rdex: depth sorting of library points (now stored in regrown array instead of linked...
[rdex:client.git] / src / library.c
1 /* =====================================================================
2 rdex -- reaction-diffusion explorer
3 Copyright (C) 2008  Claude Heiland-Allen <claudiusmaximus@goto10.org>
4 ------------------------------------------------------------------------
5 Library Module
6 ===================================================================== */
7
8 #include <assert.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <wordexp.h>
13 #include <math.h>
14 #include "library.h"
15
16 //======================================================================
17 // prototypes
18
19 struct library *library_init(struct library *library) {
20   if (!library) { return 0; }
21   library->count = 0;
22   library->arraysize = 256;
23   library->array = malloc(sizeof(struct libelem) * library->arraysize);
24   for (int i = 0; i < 4; ++i) { library->vmin[i] =  1.0e6; }
25   for (int i = 0; i < 4; ++i) { library->vmax[i] = -1.0e6; }
26   for (int i = 0; i < 4; ++i) { library->vsub[i] = 0; }
27   for (int i = 0; i < 4; ++i) { library->vmul[i] = 0; }
28   const GLfloat m0[16] = {1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1};
29   for (int i = 0; i < 16; ++i) { library->m[i] = m0[i]; }
30   library->d = 4;
31   library->X = 0;
32   library->Y = 0;
33   library->Z = 0;
34   library->width = 1;
35   library->height = 1;
36   library->snap = 0;
37   library->buffersize = library_tex_size * library_tex_size * 3;
38   library->buffer = malloc(library->buffersize);
39   library->session = getenv("RDEX_SESSION");
40   if (! library->session) { library->session = "."; }
41   library_load(library);
42   return library;
43 }
44
45 void library_grow(struct library *library) {
46   int newarraysize = library->arraysize * 2;
47   struct libelem *newarray = malloc(sizeof(struct libelem) * newarraysize);
48   memcpy(newarray, library->array, sizeof(struct libelem) * library->count);
49   free(library->array);
50   library->arraysize = newarraysize;
51   library->array = newarray;
52 }
53
54 void library_append(
55   struct library *library,
56   GLfloat ru, GLfloat rv, GLfloat f, GLfloat k, GLuint t
57 ) {
58   assert(library->count < library->arraysize);
59   library->vmin[0] = fmin(library->vmin[0], ru);
60   library->vmin[1] = fmin(library->vmin[1], rv);
61   library->vmin[2] = fmin(library->vmin[2], f);
62   library->vmin[3] = fmin(library->vmin[3], k);
63   library->vmax[0] = fmax(library->vmax[0], ru);
64   library->vmax[1] = fmax(library->vmax[1], rv);
65   library->vmax[2] = fmax(library->vmax[2], f);
66   library->vmax[3] = fmax(library->vmax[3], k);
67   library->array[library->count].v[0] = ru;
68   library->array[library->count].v[1] = rv;
69   library->array[library->count].v[2] = f;
70   library->array[library->count].v[3] = k;
71   library->array[library->count].t = t;
72   library->count += 1;
73   if (library->count == library->arraysize) {
74     library_grow(library);
75   }
76 }
77
78 void library_rerange(struct library *library) {
79   for (int i = 0; i < 4; ++i) {
80     library->vmul[i] = library->vmax[i] - library->vmin[i];
81     library->vsub[i] = library->vmin[i] + library->vmul[i]/2;
82     if (library->vmul[i] > 0) { library->vmul[i] = 1.0/library->vmul[i]; }
83   }
84 }
85
86 int library_load(struct library *library) {
87   glEnable(GL_TEXTURE_2D);
88   wordexp_t p;
89   if (0 == wordexp("$RDEX_SESSION/ru_*__rv_*__f_*__k_*.ppm", &p, WRDE_NOCMD | WRDE_SHOWERR | WRDE_UNDEF)) { // FIXME: use library->session stuff..
90   char sru[9]; char srv[9]; char sf[9]; char sk[9];
91   for (int i = 0; i < p.we_wordc; ++i) {
92    int l = strlen(p.we_wordv[i]);
93    if (l >= 52 && 4 == sscanf(p.we_wordv[i] + l - 52, "ru_%8c__rv_%8c__f_%8c__k_%8c.ppm", sru, srv, sf, sk)) {
94     sru[8] = '\0'; srv[8] = '\0'; sf[8] = '\0'; sk[8] = '\0';
95     double ru, rv, f, k;
96     if (1 != sscanf(sru, "%lg", &ru)) { break; }
97     if (1 != sscanf(srv, "%lg", &rv)) { break; }
98     if (1 != sscanf(sf,  "%lg", &f))  { break; }
99     if (1 != sscanf(sk,  "%lg", &k))  { break; }
100     FILE *image = fopen(p.we_wordv[i], "rb");
101     if (!image) { break; }
102     fseek(image, -library->buffersize, SEEK_END);
103     fread(library->buffer, library->buffersize, 1, image);
104     fclose(image);
105     GLuint t;
106     glGenTextures(1, &t);
107     glBindTexture(GL_TEXTURE_2D, t);
108     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
109     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
110     glTexImage2D(
111       GL_TEXTURE_2D, 0, GL_RGB,
112       library_tex_size, library_tex_size, 0,
113       GL_RGB, GL_UNSIGNED_BYTE, library->buffer
114     );
115     library_append(library, ru, rv, f, k, t);
116    }
117   }
118   wordfree(&p);
119   }
120   library_rerange(library);
121   glDisable(GL_TEXTURE_2D);
122   return 1;
123 }
124
125 void library_display_save(
126   struct library *library, GLuint fbo, GLuint texture,
127   double ru, double rv, double f, double k
128 ) {
129   if (! library->snap) { return; }
130   library->snap = 0;
131   GLuint t;
132   glGenTextures(1, &t);
133   glEnable(GL_TEXTURE_2D);
134   glBindTexture(GL_TEXTURE_2D, t);
135   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
136   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
137   glTexImage2D(
138     GL_TEXTURE_2D, 0, GL_RGBA,
139     library_tex_size, library_tex_size, 0,
140     GL_RGBA, GL_UNSIGNED_BYTE, 0
141   );
142   glMatrixMode(GL_PROJECTION);
143   glLoadIdentity();
144   glViewport(0, 0, library_tex_size, library_tex_size);
145   gluOrtho2D(0, 1, 0, 1);
146   glMatrixMode(GL_MODELVIEW);
147   glLoadIdentity();
148   glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);
149   glFramebufferTexture2DEXT(
150     GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D,
151     t, 0
152   );
153   glBindTexture(GL_TEXTURE_2D, texture);
154   glBegin(GL_QUADS); { glColor4f(1,1,1,1);
155     glTexCoord2f(0, 0); glVertex2f(0, 0);
156     glTexCoord2f(1, 0); glVertex2f(1, 0);
157     glTexCoord2f(1, 1); glVertex2f(1, 1);
158     glTexCoord2f(0, 1); glVertex2f(0, 1);
159   } glEnd();
160   glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
161   char filename[1024];
162   snprintf(
163     filename, 1000,
164     "%s/ru_%f__rv_%f__f_%f__k_%f.ppm",
165     library->session, ru, rv, f, k
166   );
167   FILE *imgfile = fopen(filename, "wb");
168   if (imgfile) {
169     glBindTexture(GL_TEXTURE_2D, t);
170     glGetTexImage(
171       GL_TEXTURE_2D, 0, GL_RGB, GL_UNSIGNED_BYTE, library->buffer
172     );
173     fprintf(imgfile, "P6\n%d %d 255\n", library_tex_size, library_tex_size);
174     for (int y = library_tex_size - 1; y >= 0; --y) {
175       fwrite(
176         library->buffer + y * library_tex_size * 3,
177         library_tex_size * 3, 1, imgfile
178       );
179     }
180     fclose(imgfile);
181   }
182   library_append(library, ru, rv, f, k, t);
183   library_rerange(library);
184   glDisable(GL_TEXTURE_2D);
185 }
186
187 void library_reshape(struct library *library, int w, int h) {
188   library->width = w;
189   library->height = h;
190 }
191
192 void library_project(struct library *library) {
193   for (int i = 0; i < library->count; ++i) {
194     GLfloat x0 = (library->array[i].v[0] - library->vsub[0]) * library->vmul[0];
195     GLfloat x1 = (library->array[i].v[1] - library->vsub[1]) * library->vmul[1];
196     GLfloat x2 = (library->array[i].v[2] - library->vsub[2]) * library->vmul[2];
197     GLfloat x3 = (library->array[i].v[3] - library->vsub[3]) * library->vmul[3];
198     GLfloat y0 = library->m[ 0] * x0 + library->m[ 1]*x1 + library->m[ 2]*x2 + library->m[ 3]*x3;
199     GLfloat y1 = library->m[ 4] * x0 + library->m[ 5]*x1 + library->m[ 6]*x2 + library->m[ 7]*x3;
200     GLfloat y2 = library->m[ 8] * x0 + library->m[ 9]*x1 + library->m[10]*x2 + library->m[11]*x3;
201     GLfloat y3 = library->m[12] * x0 + library->m[13]*x1 + library->m[14]*x2 + library->m[15]*x3;
202     GLfloat k = 3 * library->d / (library->d + y3);
203     y0 *= k;
204     y1 *= k;
205     y2 *= k;
206     library->array[i].w[0] = y0;
207     library->array[i].w[1] = y1;
208     library->array[i].w[2] = y2;
209   }
210 }
211
212 int library_cmpz(struct libelem *a, struct libelem *b) {
213   if (a->w[2] < b->w[2]) return -1;
214   if (a->w[2] > b->w[2]) return  1;
215   return 0;
216 }
217
218 void library_sort(struct library *library) {
219   qsort(library->array, library->count, sizeof(struct libelem), library_cmpz);
220 }
221
222 void library_display(struct library *library, GLuint texture) {
223   glClearColor(0,0,0,1);
224   glClear(GL_COLOR_BUFFER_BIT);
225   int width, height;
226   glDisable(GL_DEPTH_TEST);
227   glEnable(GL_TEXTURE_2D);
228   glBindTexture(GL_TEXTURE_2D, texture);
229   glMatrixMode(GL_PROJECTION);
230   glLoadIdentity();
231   gluOrtho2D(0, 1, 0, 1);
232   glMatrixMode(GL_MODELVIEW);
233   glLoadIdentity();
234   glViewport(0, 0, library->width, library->height);
235   glGetTexLevelParameteriv(
236     GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &width
237   );
238   glGetTexLevelParameteriv(
239     GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &height
240   );
241   glBegin(GL_QUADS); {
242     float x = 0.5 * library->width/width;
243     float y = 0.5 * library->height/height;
244     glColor4f(1,1,1,1);
245     glTexCoord2f(0.5 - x, 0.5 - y); glVertex2f(0, 0);
246     glTexCoord2f(0.5 + x, 0.5 - y); glVertex2f(1, 0);
247     glTexCoord2f(0.5 + x, 0.5 + y); glVertex2f(1, 1);
248     glTexCoord2f(0.5 - x, 0.5 + y); glVertex2f(0, 1);
249   } glEnd();
250   glMatrixMode(GL_PROJECTION);
251   glLoadIdentity();
252   float v = (float) library->width / (float) library->height;
253   glFrustum(-v*v, v*v, -v, v, 4, 12);
254   glMatrixMode(GL_MODELVIEW);
255   glViewport(0, 0, library->width, library->height);
256   glLoadIdentity();
257   // { 4D rolling ball
258     float R = 15;
259     float r = sqrt(library->X * library->X + library->Y * library->Y + library->Z * library->Z);
260     float D = sqrt(R*R+r*r);
261     float c = R / D;
262     float s = r / D;
263     float x, y, z;
264     if (r > 0.00001) {
265       x = library->X / r;
266       y = library->Y / r;
267       z = library->Z / r;
268     } else {
269       x = 0;
270       y = 0;
271       z = 0;
272     }
273     GLfloat m[16] = {
274       1-x*x*(1-c), -(1-c)*x*y,  -(1-c)*x*z,  s*x,
275       -(1-c)*x*y,  1-y*y*(1-c), -(1-c)*y*z,  s*y,
276       -(1-c)*x*z,  -(1-c)*y*z,  1-z*z*(1-c), s*z,
277       -s*x,        -s*y,        -s*z,        c
278     };
279     glMultMatrixf(m);
280     glMultMatrixf(library->m);
281     glGetFloatv(GL_MODELVIEW_MATRIX , library->m);
282   // } rolling ball
283   glLoadIdentity();
284   glTranslatef(0,0,-8);
285   library_project(library);
286   library_sort(library);
287   for (int i = 0; i < library->count; ++i) {
288     glBindTexture(GL_TEXTURE_2D, library->array[i].t);
289     GLfloat y0 = library->array[i].w[0];
290     GLfloat y1 = library->array[i].w[1];
291     GLfloat y2 = library->array[i].w[2];
292     glBegin(GL_QUADS); {
293       glColor4f(0, 0, 0, 1);
294       glTexCoord2f(0, 0); glVertex3f(y0 - 0.15, y1 - 0.15, y2);
295       glTexCoord2f(1, 0); glVertex3f(y0 + 0.15, y1 - 0.15, y2);
296       glTexCoord2f(1, 1); glVertex3f(y0 + 0.15, y1 + 0.15, y2);
297       glTexCoord2f(0, 1); glVertex3f(y0 - 0.15, y1 + 0.15, y2);
298       glColor4f(1, 1, 1, 1);
299       glTexCoord2f(0, 0); glVertex3f(y0 - 0.125, y1 - 0.125, y2);
300       glTexCoord2f(1, 0); glVertex3f(y0 + 0.125, y1 - 0.125, y2);
301       glTexCoord2f(1, 1); glVertex3f(y0 + 0.125, y1 + 0.125, y2);
302       glTexCoord2f(0, 1); glVertex3f(y0 - 0.125, y1 + 0.125, y2);
303     } glEnd();
304   }
305   glDisable(GL_TEXTURE_2D);
306   glEnable(GL_DEPTH_TEST);
307 }
308
309 void library_pmotion(struct library *library, int x, int y) {
310   library->X =  (x - library->width/2.0)  / (float) library->width;
311   library->Y = -(y - library->height/2.0) / (float) library->height;
312   library->Z = 0;
313 }
314
315 void library_amotion(struct library *library, int x, int y) {
316   library->X = (x - library->width/2.0)  / (float) library->width;
317   library->Y = 0;
318   library->Z = (y - library->height/2.0) / (float) library->height;
319 }
320
321 void library_idle(struct library *library) { }
322
323 // EOF