rdex: new concept, library of points visualized over searching
[rdex:client.git] / rdex_map.c
1 /* =====================================================================
2 rdex -- reaction-diffusion explorer
3 Copyright (C) 2008  Claude Heiland-Allen <claudiusmaximus@goto10.org>
4 ===================================================================== */
5
6 #include <math.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <GL/glew.h>
10 #include <GL/glut.h>
11 #include "rdex2c_data.h"
12
13
14 //======================================================================
15 // load a file into memory as a string (watch out for embedded '\0')
16 char *loadfile(const char *filename) {
17   char *result = 0;
18         int size = 0;
19         FILE *f = fopen(filename, "rb");
20         if (! f) return 0;
21         fseek(f, 0, SEEK_END);
22         size = ftell(f);
23         fseek(f, 0, SEEK_SET);
24         result = (char *)malloc(size+1);
25         if (size != fread(result, sizeof(char), size, f)) {
26     free(result);
27     fclose(f);
28     return 0;
29         }
30         fclose(f);
31         result[size] = 0;
32         return result;
33 }
34
35 //======================================================================
36 // print a shader object's debug log
37 void shader_debug(GLhandleARB obj) {
38   int infologLength = 0;
39   int maxLength;
40   if (glIsShader(obj)) {
41     glGetShaderiv(obj,GL_INFO_LOG_LENGTH,&maxLength);
42   } else {
43     glGetProgramiv(obj, GL_INFO_LOG_LENGTH, &maxLength);
44   }
45   char *infoLog = malloc(maxLength);
46   if (!infoLog) {
47     return;
48   }
49   if (glIsShader(obj)) {
50     glGetShaderInfoLog(obj, maxLength, &infologLength, infoLog);
51   } else {
52     glGetProgramInfoLog(obj, maxLength, &infologLength, infoLog);
53   }
54   if (infologLength > 0) {
55     fprintf(stderr, "%s\n", infoLog);
56   }
57   free(infoLog);
58 }
59
60 //######################################################################
61 //####                                                    Generic Shader
62 //######################################################################
63
64 //======================================================================
65 // generic shader data
66 struct shader {
67   GLint linkStatus;
68   GLhandleARB program;
69   GLhandleARB fragment;
70   GLhandleARB vertex;
71   GLcharARB *fragmentSource;
72   GLcharARB *vertexSource;
73 };
74
75 //======================================================================
76 // generic shader uniform location access macro
77 #define shader_uniform(self,name) \
78   (self)->uniform.name = \
79      glGetUniformLocationARB((self)->shader.program, #name)
80
81 //======================================================================
82 // generic shader uniform update access macro (integer)
83 #define shader_updatei(self,name) \
84   glUniform1iARB((self)->uniform.name, (self)->value.name)
85
86 //======================================================================
87 // generic shader uniform update access macro (float)
88 #define shader_updatef(self,name) \
89   glUniform1fARB((self)->uniform.name, (self)->value.name)
90
91 //======================================================================
92 // generic shader initialization
93 struct shader *shader_init(
94   struct shader *shader, const char *vert, const char *frag
95 ) {
96   if (! shader) { return 0; }
97   shader->linkStatus     = 0;
98   shader->vertexSource   = 0;
99   shader->fragmentSource = 0;
100   if (vert) {
101     if (!(shader->vertexSource   = loadfile(vert))) { return 0; }
102   }
103   if (frag) {
104     if (!(shader->fragmentSource = loadfile(frag))) { return 0; }
105   }
106   if (shader->vertexSource || shader->fragmentSource) {
107     shader->program = glCreateProgramObjectARB();
108     if (shader->vertexSource) {
109       shader->vertex =
110         glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB);
111       glShaderSourceARB(shader->vertex,
112         1, (const GLcharARB **) &shader->vertexSource, 0
113       );
114       glCompileShaderARB(shader->vertex);
115       shader_debug(shader->vertex);
116       glAttachObjectARB(shader->program, shader->vertex);
117     }
118     if (shader->fragmentSource) {
119       shader->fragment =
120         glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);
121       glShaderSourceARB(shader->fragment,
122         1, (const GLcharARB **) &shader->fragmentSource, 0
123       );
124       glCompileShaderARB(shader->fragment);
125       shader_debug(shader->fragment);
126       glAttachObjectARB(shader->program, shader->fragment);
127     }
128     glLinkProgramARB(shader->program);
129     shader_debug(shader->program);
130     glGetObjectParameterivARB(shader->program,
131       GL_OBJECT_LINK_STATUS_ARB, &shader->linkStatus
132     );
133     if (! shader->linkStatus) { return 0; }
134   } else { return 0; }
135   return shader;
136 }
137
138 //######################################################################
139 //####                                             Hyperspace Projection
140 //######################################################################
141
142 //======================================================================
143 // copysquare shader data
144 struct hyperproject { struct shader shader;
145   struct { GLint w; } uniform;
146   struct { float w; } value;
147 };
148
149 //======================================================================
150 // copysquare shader initialization
151 struct hyperproject *hyperproject_init(struct hyperproject *hyperproject) {
152   if (! hyperproject) { return 0; }
153   if (! shader_init(&hyperproject->shader, "hyperproject.vert", 0)) {
154     return 0;
155   }
156   shader_uniform(hyperproject, w);
157   hyperproject->value.w = 5;
158   return hyperproject;
159 }
160
161 void hyperproject_begin(struct hyperproject *hyperproject) {
162   glUseProgramObjectARB(hyperproject->shader.program);
163   shader_updatef(hyperproject, w);
164 }
165
166 void hyperproject_end(struct hyperproject *hyperproject) {
167   glUseProgramObjectARB(0);
168 }
169
170
171 struct map {
172   struct hyperproject *hyperproject;
173   int width, height;
174   GLfloat X, Y, Z, dx, dy, dz;
175   GLfloat color[4][3];
176   GLfloat m[16];
177 };
178
179 struct map map = {
180   0,0,0,0,0,0,0,0,0,
181   { {0.1,0.1,0.1}, {0,0,0.2}, {0,0.2,0}, {0.2,0,0} },
182   {1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1}
183 };
184
185 int map_init() {
186   map.hyperproject = malloc(sizeof(struct hyperproject));
187   return hyperproject_init(map.hyperproject);
188 }
189
190 void map_reshape(int w, int h) {
191   map.width = w;
192   map.height = h;
193 }
194
195 void map_display() {
196 hyperproject_begin(map.hyperproject);
197   {int status = glGetError();
198   if (status) fprintf(stderr, "gl1: %d\n", status);}
199
200   glClearColor(0,0,0,1);
201   glClear(GL_COLOR_BUFFER_BIT);
202   glMatrixMode(GL_PROJECTION);
203   glLoadIdentity();
204   float v = (float) map.width / (float) map.height;
205   glFrustum(-v*v, v*v, -v, v, 4, 12);
206   glMatrixMode(GL_MODELVIEW);
207   glLoadIdentity();
208   {
209     // 4D rolling ball
210     float R = 15;
211     float r = sqrt(map.X * map.X + map.Y * map.Y + map.Z * map.Z);
212     float D = sqrt(R*R+r*r);
213     float c = R / D;
214     float s = r / D;
215     float x, y, z;
216     if (r > 0.00001) {
217       x = map.X / r;
218       y = map.Y / r;
219       z = map.Z / r;
220     } else {
221       x = 0;
222       y = 0;
223       z = 0;
224     }
225     GLfloat m[16] = {
226       1-x*x*(1-c), -(1-c)*x*y,  -(1-c)*x*z,  s*x,
227       -(1-c)*x*y,  1-y*y*(1-c), -(1-c)*y*z,  s*y,
228       -(1-c)*x*z,  -(1-c)*y*z,  1-z*z*(1-c), s*z,
229       -s*x,        -s*y,        -s*z,        c
230     };
231     glMultMatrixf(m);
232     glMultMatrixf(map.m);
233     glGetFloatv(GL_MODELVIEW_MATRIX , map.m);
234   }
235   glLoadIdentity();
236   glViewport(0, 0, map.width, map.height);
237   glTranslatef(0,0,-8);
238   glMultMatrixf(map.m);
239   glDisable(GL_DEPTH_TEST);
240   glEnable(GL_BLEND);
241   glBlendFunc(GL_SRC_ALPHA,GL_ONE);
242   glPointSize(8);
243   glEnable(GL_POINT_SMOOTH);
244   glBegin(GL_POINTS); {
245     for (int i = 0; rdex2c_data[i].c >= 0; ++i) {
246       glColor3fv(map.color[rdex2c_data[i].c]);
247       glVertex4f((rdex2c_data[i].f  - 0.05)/0.05, (rdex2c_data[i].k  - 0.05)/0.05,
248                  (rdex2c_data[i].ru - 0.15)/0.15, (rdex2c_data[i].rv - 0.15)/0.15);
249     }
250   } glEnd();
251   glPointSize(8);
252   glDisable(GL_POINT_SMOOTH);
253 /*
254   glBegin(GL_LINES); {
255     const int N = 4;
256     glColor3f(0.1,0.1,0.1);
257     for (int i = 0; i < N; ++i) { float x = 2.0*i/(N-1.0)-1.0;
258     for (int j = 0; j < N; ++j) { float y = 2.0*j/(N-1.0)-1.0;
259     for (int k = 0; k < N; ++k) { float z = 2.0*k/(N-1.0)-1.0;
260     for (int l = 0; l < N; ++l) { float w = 2.0*l/(N-1.0)-1.0;
261     for (int m = 0; m < 4; ++m) {
262       glVertex4f(x+(0==m)/(2*N-1.0),y+(1==m)/(2*N-1.0),z+(2==m)/(2*N-1.0),w+(3==m)/(2*N-1.0));
263       glVertex4f(x-(0==m)/(2*N-1.0),y-(1==m)/(2*N-1.0),z-(2==m)/(2*N-1.0),w-(3==m)/(2*N-1.0));
264     }}}}}
265   } glEnd();
266 */
267   glFlush();
268 hyperproject_end(map.hyperproject);  
269   glutSwapBuffers();
270   int status = glGetError();
271   if (status) fprintf(stderr, "gl: %d\n", status);
272 }
273
274 void map_idle() {
275   map.X = map.dx;
276   map.Y = map.dy;
277   map.Z = map.dz;
278   glutPostRedisplay();
279 }
280
281 void map_pmotion(int x, int y) {
282   map.dx = (x - map.width/2.0)  / (float) map.width;
283   map.dy = -(y - map.height/2.0) / (float) map.height;
284   map.dz = 0;
285 }
286
287 void map_amotion(int x, int y) {
288   map.dx = (x - map.width/2.0)  / (float) map.width;
289   map.dy = 0;
290   map.dz = (y - map.height/2.0) / (float) map.height;
291 }
292
293 int main(int argc, char **argv) {
294   glutInit(&argc, argv);
295   glutInitWindowSize(788,576);
296   glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);
297   glutCreateWindow("rdex map");
298   glewInit();
299   if (map_init()) {
300     glutDisplayFunc(map_display);
301     glutReshapeFunc(map_reshape);
302     glutPassiveMotionFunc(map_pmotion);
303     glutMotionFunc(map_amotion);
304     glutIdleFunc(map_idle);
305     glutMainLoop();
306     return 0; // never reached
307   } else {
308     return 1;
309   }
310 }