2015年9月24日木曜日

古き良きteapot


3D的なことをしたくなったのでデバッグ用にいろいろOpenGLを調べていたのですが今はOpenGL3.1ごろやらで必須になったCore Profileとかいうのが主流らしいです。 ただデバッグ用に確認したいだけで高速化を求めなければGLUTで十分だなあと思った次第です。 teapotを回転するだけですが時代を感じてよいですね。
#include <stdio.h>
#include <stdlib.h>
#ifdef __APPLE__
#include <GLUT/glut.h>
#else
#include <GL/glut.h>
#endif
typedef struct {
int width;
int height;
char* title;
float field_of_view_angle;
float z_near;
float z_far;
} glutWindow;
typedef struct {
int down;
int pos[2];
float angle[2];
} glutMouse;
glutWindow win;
glutMouse m;
float g_rotation = 0;
float g_rotation_speed = 0.2f;
void display() {
// Clear Screen and Depth Buffer
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
// Define a viewing transformation
gluLookAt(4, 2, 0, 0, 0, 0, 0, 1, 0);
// Push and pop the current matrix stack.
// This causes that translations and rotations on this matrix wont influence
// others.
glPushMatrix();
glColor3f(1, 0, 0);
// Rotate the teapot
glRotated(90, 0.0, 1.0, 0.0);
glRotated(m.angle[0], 0.0, 1.0, 0.0);
glRotated(m.angle[1], 1.0, 0.0, 0.0);
// Draw the teapot
glutSolidTeapot(1);
glPopMatrix();
g_rotation += g_rotation_speed;
glutSwapBuffers();
}
void initialize() {
// select projection matrix
glMatrixMode(GL_PROJECTION);
// set the viewport
glViewport(0, 0, win.width, win.height);
// set matrix mode
glMatrixMode(GL_PROJECTION);
// reset projection matrix
glLoadIdentity();
GLfloat aspect = (GLfloat)win.width / win.height;
// set up a perspective projection matrix
gluPerspective(win.field_of_view_angle, aspect, win.z_near, win.z_far);
// specify which matrix is the current matrix
glMatrixMode(GL_MODELVIEW);
glShadeModel(GL_SMOOTH);
// specify the clear value for the depth buffer
glClearDepth(1.0f);
glDepthFunc(GL_LEQUAL);
glEnable(GL_DEPTH_TEST);
// specify implementation-specific hints
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
GLfloat amb_light[] = {0.1, 0.1, 0.1, 1.0};
GLfloat diffuse[] = {0.6, 0.6, 0.6, 1};
GLfloat specular[] = {0.7, 0.7, 0.3, 1};
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, amb_light);
glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
glLightfv(GL_LIGHT0, GL_SPECULAR, specular);
glEnable(GL_LIGHT0);
glEnable(GL_COLOR_MATERIAL);
glShadeModel(GL_SMOOTH);
glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE);
glEnable(GL_LIGHTING);
glClearColor(0.0, 0.0, 0.0, 1.0);
}
void keyboard(unsigned char key, int mousePositionX, int mousePositionY) {
switch (key) {
case 'q':
exit(0);
break;
default:
break;
}
}
void mouse(int button, int state, int x, int y) {
if (button == GLUT_LEFT_BUTTON) {
if (state == GLUT_DOWN) {
m.pos[0] = x;
m.pos[1] = y;
m.down = 1;
}
if (state == GLUT_UP) {
m.down = 0;
}
}
}
void motion(int x, int y) {
int mx, my;
if (m.down) {
mx = (double)(x - m.pos[0]);
my = (double)(y - m.pos[1]);
m.pos[0] = x;
m.pos[1] = y;
m.angle[0] += mx;
m.angle[1] += my;
glutPostRedisplay();
}
}
int main(int argc, char** argv) {
// set window values
win.width = 640;
win.height = 480;
win.title = "teapot";
win.field_of_view_angle = 45;
win.z_near = 1.0f;
win.z_far = 500.0f;
// set mouse values;
m.down = 0;
m.angle[0] = m.angle[1] = 0.0;
// initialize and run program
glutInit(&argc, argv); // GLUT initialization
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH); // Display Mode
glutInitWindowSize(win.width, win.height); // set window size
glutCreateWindow(win.title); // create Window
glutDisplayFunc(display); // register Display Function
glutIdleFunc(display); // register Idle Function
glutKeyboardFunc(keyboard); // register Keyboard Handler
glutMouseFunc(mouse);
glutMotionFunc(motion);
initialize();
glutMainLoop(); // run GLUT mainloop
return 0;
}
view raw teapot.c hosted with ❤ by GitHub

2015年9月19日土曜日

C++からCを呼んでみる

かなり使い古されていると思うけどC++からCを呼んでみました。 数値計算や簡単なロジックだけであればC言語だけで十分なのでC++の闇に触れないでC言語で作って他の言語から呼ぶのが、 今から性能を求めるシステムを作る場合はよいのではないかと思います。
#include "c.h"
#include <stdio.h>
char* hello(){
return "hello";
}
view raw c.c hosted with ❤ by GitHub
#ifdef __cplusplus
extern "C" {
char* hello();
}
#endif
view raw c.h hosted with ❤ by GitHub
#include "c.h"
#include <iostream>
using namespace std;
int main(){
cout<<hello()<<endl;
return 0;
}
view raw cpp.cpp hosted with ❤ by GitHub
build:
gcc -c c.c -o c.o
g++ -c cpp.cpp -o cpp.o
g++ -o c+cpp cpp.o c.o
view raw Makefile hosted with ❤ by GitHub

2015年9月15日火曜日

iPhoneでOpenGLを使って四角を書く

iPhoneで四角だけを書くものを作りました。 OpenGL ESがわからない上にObjective-Cはしんどいです。 これ正方形を書いたつもりなんだけど長くなっているということは 解像度によって調整しないといけないということなんやろうか。。 ただこの前作った流体シミュレーションと組み合わせると面白いことができそうです。
#import "GameViewController.h"
#import <OpenGLES/ES2/glext.h>
typedef struct
{
float Position[3];
}Vertex;
typedef struct
{
float Color[4];
}Color;
const Vertex gVertices[]={
{-0.5,-0.5,0},
{0.5,-0.5,0},
{-0.5,0.5,0},
{0.5,0.5,0}
};
const GLubyte gIndices[]={
0,1,2,3
};
Color gColors[] = {
{1,0,0,1},
{0,1,0,1},
{0,0,1,1},
{1,1,1,1}
};
@interface GameViewController () {
}
@property (strong,nonatomic) EAGLContext *context;
@property (strong,nonatomic) GLKBaseEffect *effect;
@property (nonatomic) GLuint vertexBuffer;
@property (nonatomic) GLuint indexBuffer;
@property (nonatomic) GLuint colorBuffer;
@end
@implementation GameViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
if (!self.context) {
NSLog(@"Failed to create ES context");
}
GLKView *view = (GLKView *)self.view;
view.context = self.context;
view.drawableDepthFormat = GLKViewDrawableDepthFormat24;
[self setupGL];
}
- (void)dealloc
{
[self tearDownGL];
if ([EAGLContext currentContext] == self.context) {
[EAGLContext setCurrentContext:nil];
}
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
if ([self isViewLoaded] && ([[self view] window] == nil)) {
self.view = nil;
[self tearDownGL];
if ([EAGLContext currentContext] == self.context) {
[EAGLContext setCurrentContext:nil];
}
self.context = nil;
}
}
- (void)setupGL
{
[EAGLContext setCurrentContext:self.context];
self.effect =[[GLKBaseEffect alloc] init];
self.effect.colorMaterialEnabled = YES;
glEnable(GL_DEPTH_TEST);
glGenBuffers(1, &_vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(gVertices), gVertices, GL_STATIC_DRAW);
glEnableVertexAttribArray(GLKVertexAttribPosition);
glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void *)NULL);
glGenBuffers(1, &_colorBuffer);
glBindBuffer(GL_ARRAY_BUFFER, _colorBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(gColors), gColors, GL_STATIC_DRAW);
glEnableVertexAttribArray(GLKVertexAttribColor);
glVertexAttribPointer(GLKVertexAttribColor, 4, GL_FLOAT, GL_FALSE, sizeof(Color), (void *)NULL);
glGenBuffers(1, &_indexBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(gIndices), gIndices, GL_STATIC_DRAW);
}
- (void)tearDownGL
{
[EAGLContext setCurrentContext:self.context];
}
#pragma mark - GLKView and GLKViewController delegate methods
- (void)update
{
return;
}
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect
{
glClearColor(0.65f, 0.65f, 0.65f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Render the object with GLKit
[self.effect prepareToDraw];
glDrawElements(GL_TRIANGLE_STRIP, 6,GL_UNSIGNED_BYTE, 0);
}
#pragma mark - OpenGL ES 2 shader compilation
@end

2015年9月13日日曜日

もくもくする何か

もくもくする何かを作ってみました。 ナビエストークス方程式的な流体をスタガード格子でコンパクトに書いているサンプルがないので作ってみました。 もともと同じようなものがあったのでほとんど佐野ってきています。 時間ができたらiPhoneアプリみたいにしたいですね。
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#ifdef __APPLE__
#include <GLUT/glut.h>
#else
#include <GL/glut.h>
#endif
#define START_FOR(X,Y) for(int j=0;j<Y;j++){for(int i=0;i<X;i++){
#define END_FOR }}
#define SWAP(i,j) {double ** tmp=i;i=j;j=tmp;}
#define MIN(i,j) (i>j?j:i)
#define MAX(i,j) (i<j?j:i)
#define CLIP(src,min,max) MAX(min,MIN(max,src))
#define DT 0.1 //Time Step
#define M 1.0 //Grid Size
#define N 64 //Cell Numbers
#define W 512 //Window Size
#define T 200 //Iteration Numbers
#define V 0.01 //Viscocity
const double H = M/N; //Cell Size
int mx_prev,my_prev,mstat; //Mouse
double **s,**s_swap; //Steam
double **f[2]; //Force (0:x,1:y)
double **u, **v, **u_swap, **v_swap; //Velocity
double **d, **p, **o; //Divergence,Pressure,Vorticity
int show_v,show_g; //Show Flag(Velocity,Grid)
double ** alloc2d(int n, int m) {
double ** ptr = (double **)malloc(sizeof(double *) * n);
for(int i = 0; i < n; i++){
ptr[i] = (double *)malloc(sizeof(double) * m);
}
return ptr;
}
void free2d(double **ptr, int n){
for(int i=0; i < n; i++){
free(ptr[i]);
}
free(ptr);
}
void init(){
if(!s) s = alloc2d(N,N);
if(!s_swap) s_swap = alloc2d(N,N);
if(!f[0]) f[0] = alloc2d(N,N);
if(!f[1]) f[1] = alloc2d(N,N);
if(!u) u = alloc2d(N+1,N);
if(!v) v = alloc2d(N,N+1);
if(!u_swap) u_swap = alloc2d(N+1,N);
if(!v_swap) v_swap = alloc2d(N,N+1);
if(!d) d = alloc2d(N,N);
if(!p) p = alloc2d(N,N);
if(!o) o = alloc2d(N,N);
START_FOR(N+1,N)
u[i][j] = 0.0;
u_swap[i][j] = 0.0;
END_FOR
START_FOR(N,N+1)
v[i][j] = 0.0;
v_swap[i][j] = 0.0;
END_FOR
START_FOR(N,N)
d[i][j] = 0.0;
p[i][j] = 0.0;
o[i][j] = 0.0;
s[i][j] = 0.0;
s_swap[i][j] = 0.0;
f[0][i][j] = 0.0;
f[1][i][j] = 0.0;
END_FOR
show_v = show_g = 0;
}
void final(){
if(u)free(u);u=NULL;
if(v)free(v);v=NULL;
if(u_swap)free(u_swap);u_swap=NULL;
if(v_swap)free(v_swap);v_swap=NULL;
if(p)free(p);p=NULL;
if(d)free(d);d=NULL;
if(o)free(o);o=NULL;
if(s)free(s);s=NULL;
if(s_swap)free(s_swap);s_swap=NULL;
if(f[0])free(f[0]);f[0]=NULL;
if(f[1])free(f[1]);f[1]=NULL;
}
double u_ref(int i, int j){
return u[CLIP(i,0,N)][CLIP(j,0,N-1)];
}
double v_ref(int i, int j){
return v[CLIP(i,0,N-1)][CLIP(j,0,N)];
}
double s_ref(int i, int j){
return s[CLIP(i,0,N-1)][CLIP(j,0,N-1)];
}
double p_ref(int i, int j){
return p[CLIP(i,0,N-1)][CLIP(j,0,N-1)];
}
void enforce_boundary(){
START_FOR(N+1,N)
if(i==0 || i==N) u[i][j] = 0;
END_FOR
START_FOR(N,N+1)
if(j==0 || j==N) v[i][j] = 0;
END_FOR
}
void vorticity_confinement(){
//Compute Vorticity
START_FOR(N, N)
o[i][j] = ((v_ref(i+1,j)-v_ref(i-1,j))-(u_ref(i,j+1)-u_ref(i,j-1))) * 0.5 * H;
END_FOR
START_FOR(N, N)
if(i==0 || i==N-1 || j==0 || j==N-1) continue;
//Compute Gradient of Vorticity Length
double h[2]= {
(fabs(o[i+1][j])-fabs(o[i-1][j])) * 0.5 * H,
(fabs(o[i][j+1])-fabs(o[i][j-1])) * 0.5 * H
};
double h_len = hypot(h[0],h[1]);
if(h_len > 0){
double e = 10;
double n[2] = { h[0]/h_len, h[1]/h_len};
f[0][i][j] += e * H * (n[1] * o[i][j]);
f[1][i][j] += e * H * -(n[0] * o[i][j]);
}
END_FOR
}
void compute_force(){
START_FOR(N,N)
if(i==0)continue;
u[i][j] += f[0][i][j] + f[0][i-1][j];
END_FOR
START_FOR(N,N)
if(j==0)continue;
v[i][j] += f[1][i][j] + f[1][i][j-1];
END_FOR
}
double interpolation(double **src, double x, double y, int width, int height){
x = CLIP(x,0.0,width);
y = CLIP(y,0.0,height);
int i = MIN(x,width-2);
int j = MIN(y,height-2);
return ((i+1-x)*src[i][j]+(x-i)*src[i+1][j])*(j+1-y)+
((i+1-x)*src[i][j+1]+(x-i)*src[i+1][j+1])*(y-j);
}
void semiLagragian(double **src, double **u, double **v,int width, int height, double **out){
START_FOR(width,height)
out[i][j]=interpolation(src, i-N*u[i][j]*DT, j-N*v[i][j]*DT, width, height);
END_FOR
}
void compute_advection(){
//Compute Fluid Velocity At Each Staggerd Faces And Cell Centers
double **uy = alloc2d(N+1,N);
double **vx = alloc2d(N,N+1);
double **cx = alloc2d(N,N);
double **cy = alloc2d(N,N);
START_FOR(N+1,N)
uy[i][j] = (v_ref(i-1,j) + v_ref(i-1,j+1) + v_ref(i,j+1) + v_ref(i,j)) * 0.25;
END_FOR
START_FOR(N,N+1)
vx[i][j] = (u_ref(i,j-1) + u_ref(i,j) + u_ref(i+1, j) + u_ref(i+1,j-1)) * 0.25;
END_FOR
START_FOR(N,N)
cx[i][j] = (u[i][j] + u[i+1][j]) * 0.5;
cy[i][j] = (v[i][j] + v[i][j+1]) * 0.5;
END_FOR
semiLagragian(u,u,uy,N+1,N,u_swap);
semiLagragian(v,vx,v,N,N+1,v_swap);
semiLagragian(s,cx,cy,N,N,s_swap);
free2d(uy,N+1);
free2d(vx,N);
free2d(cx,N);
free2d(cy,N);
SWAP(u,u_swap);
SWAP(v,v_swap);
SWAP(s,s_swap);
}
void compute_diffuse(){
double a = DT * V;
START_FOR(N+1,N)
u_swap[i][j] = u_ref(i,j) + a * (u_ref(i-1,j) + u_ref(i+1,j) + u_ref(i,j-1) + u_ref(i,j+1) - 4 * u_ref(i,j));
END_FOR
START_FOR(N,N+1)
v_swap[i][j] = v_ref(i,j) + a * (v_ref(i-1,j) + v_ref(i+1,j) + v_ref(i,j-1) + v_ref(i,j+1) - 4 * v_ref(i,j));
END_FOR
START_FOR(N,N)
s_swap[i][j] = s_ref(i,j) + a * (s_ref(i-1,j) + s_ref(i+1,j) + s_ref(i,j-1) + s_ref(i,j+1) - 4 * s_ref(i,j));
END_FOR
SWAP(u,u_swap);
SWAP(v,v_swap);
SWAP(s,s_swap);
}
void compute_divergence(){
START_FOR(N, N)
d[i][j] = ((u[i+1][j]-u[i][j])+(v[i][j+1]-v[i][j]))/H;
END_FOR
}
void compute_pressure(){
double h2 = H * H;
for(int k=0; k < T; k++){
START_FOR(N,N)
p[i][j] = ((p_ref(i+1,j)+p_ref(i-1,j)+p_ref(i,j+1)+p_ref(i, j-1))-h2*d[i][j])/4;
END_FOR
}
}
void subtract_pressure(){
START_FOR(N+1,N)
if(i>0 && i<N) u[i][j] -= (p[i][j]-p[i-1][j])/H;
END_FOR
START_FOR(N,N+1)
if(j>0 && j<N) v[i][j] -= (p[i][j]-p[i][j-1])/H;
END_FOR
}
void computeStep(){
enforce_boundary();
vorticity_confinement();
compute_force();
compute_advection();
compute_diffuse();
compute_divergence();
compute_pressure();
subtract_pressure();
}
void computePostDisplay(){
START_FOR(N,N)
f[0][i][j]=0;
f[1][i][j]=0;
END_FOR
}
void idle(){
computeStep();
glutPostRedisplay();
}
void keyboard(unsigned char key, int x, int y){
switch(key){
case 'q':final();exit(0);break;
case 'v':show_v = !show_v;break;
case 'g':show_g = !show_g;break;
}
}
void mouse(int button, int state, int x, int y){
mx_prev = x;
my_prev = y;
mstat = state;
}
void motion(int x, int y){
if(mstat == GLUT_DOWN){
double cx = x/(double)W;
double cy = M-y/(double)W;
double dx = (x-mx_prev)/(double)W;
double dy = -(y-my_prev)/(double)W;
int i = CLIP(cx*N, 0, N-1);
int j = CLIP(cy*N, 0, N-1);
f[0][i][j]+=CLIP(M*N*dx, -M/N/DT,M/N/DT);
f[1][i][j]+=CLIP(M*N*dy, -M/N/DT,M/N/DT);
int r = N/64;
for(int u=-r; u<=r; u++){
for(int v=-r; v<=r; v++){
if(hypot(u,v)<=r){
s[i+u][j+v] = 2.0;
}
}
}
}
mx_prev = x;
my_prev = y;
}
void drawBitmapString(const char *string){
while(*string){
glutBitmapCharacter(GLUT_BITMAP_HELVETICA_12, *string++);
}
}
void displayText(){
glColor4f(1.0,1.0,1.0,1.0);
glRasterPos2d(0.05,0.95);
drawBitmapString("Press \"q\" to close window");
}
void displayConcentration(double **c){
START_FOR(N-1,N-1)
double pos[2]={i*H+H*0.5,j*H+H*0.5};
double s = 2000;
glBegin(GL_QUADS);
glColor4d(c[i][j]>0,0,c[i][j]<0,fabs(c[i][j]*s));
glVertex2d(pos[0],pos[1]);
glColor4d(c[i+1][j]>0,0,c[i+1][j]<0,fabs(c[i+1][j]*s));
glVertex2d(pos[0]+H,pos[1]);
glColor4d(c[i+1][j+1]>0,0,c[i+1][j+1]<0,fabs(c[i+1][j+1]*s));
glVertex2d(pos[0]+H,pos[1]+H);
glColor4d(c[i][j+1]>0,0,c[i][j+1]<0,fabs(c[i][j+1]*s));
glVertex2d(pos[0],pos[1]+H);
glEnd();
END_FOR
}
void displaySteam(){
START_FOR(N-1,N-1)
double pos[2]={i*H+H*0.5,j*H+H*0.5};
glBegin(GL_QUADS);
glColor4d(s[i][j],s[i][j],s[i][j],s[i][j]);
glVertex2d(pos[0],pos[1]);
glColor4d(s[i+1][j],s[i+1][j],s[i+1][j],s[i+1][j]);
glVertex2d(pos[0]+H,pos[1]);
glColor4d(s[i+1][j+1],s[i+1][j+1],s[i+1][j+1],s[i+1][j+1]);
glVertex2d(pos[0]+H,pos[1]+H);
glColor4d(s[i][j+1],s[i][j+1],s[i][j+1],s[i][j+1]);
glVertex2d(pos[0],pos[1]+H);
glEnd();
END_FOR
}
void displayGrid(){
glColor4d(0.4,0.4,0.4,0.5);
for (int i=0; i<N+1; i++){
glBegin(GL_LINES);
glVertex2d(0.0, H*i);
glVertex2d(1.0, H*i);
glEnd();
}
for (int i=0; i<N+1; i++){
glBegin(GL_LINES);
glVertex2d(H*i, 0.0);
glVertex2d(H*i, 1.0);
glEnd();
}
}
void displayVelocity(){
glColor4d(1.0,1.0,0.0,1.0);
START_FOR(N, N)
double pos[2]={i*H+H*0.5,j*H+H*0.5};
double vel[2]={(u[i][j]+u[i+1][j])*0.5,(v[i][j]+v[i][j+1])*0.5};
glBegin(GL_LINES);
glVertex2d(pos[0],pos[1]);
glVertex2d(pos[0]+vel[0],pos[1]+vel[1]);
glEnd();
END_FOR
}
void display(){
glClearColor(0.0, 0.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
if(show_g)displayGrid();
if(show_v)displayVelocity();
displaySteam();
displayText();
glutSwapBuffers();
computePostDisplay();
}
void reshape(int w, int h){
glViewport(0,0,w,h);
glLoadIdentity();
glOrtho(0.0,M,0.0,M,-1.0,1.0);
}
int main(int argc, char * argv[]){
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);
glutInitWindowPosition(100,100);
glutInitWindowSize(W,W);
glutCreateWindow("steam2d");
glutIdleFunc(idle);
glutKeyboardFunc(keyboard);
glutMouseFunc(mouse);
glutMotionFunc(motion);
glutDisplayFunc(display);
glutReshapeFunc(reshape);
init();
glutMainLoop();
return 0;
}
view raw fluid2d.c hosted with ❤ by GitHub