use new intro module
[rdex:client.git] / src / rdex.c
1 /* =====================================================================
2 rdex -- reaction-diffusion explorer
3 Copyright (C) 2008,2009,2010  Claude Heiland-Allen <claudiusmaximus@goto10.org>
4 ------------------------------------------------------------------------
5 Main Module
6 ===================================================================== */
7 #define _BSD_SOURCE
8
9 #include <math.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <unistd.h>
14 #include "rdex.h"
15
16 //======================================================================
17 // main module global mutable state
18 static struct rdex rdex;
19
20 //======================================================================
21 // main module initialization
22 int rdex_init() {
23   int nrt = 0 != getenv("RDEX_RENDER");
24   memset(&rdex, 0, sizeof(rdex));
25   glGenFramebuffersEXT(1, &rdex.fbo);
26   if (! reactiondiffusion_init(&rdex.reactiondiffusion)) { return 0; }
27   if (! copysquare_init       (&rdex.copysquare       )) { return 0; }
28   if (! arithmeticmean_init   (&rdex.arithmeticmean   )) { return 0; }
29   if (! numericerror_init     (&rdex.numericerror     )) { return 0; }
30   if (! difference_init       (&rdex.difference       )) { return 0; }
31   if (! falsecolour_init      (&rdex.falsecolour      )) { return 0; }
32   if (! library_init          (&rdex.library, rdex.fbo)) { return 0; }
33   if (! screenshot_init       (&rdex.screenshot, nrt  )) { return 0; }
34   if (! audio_init            (&rdex.audio, nrt       )) { return 0; }
35   if (! sequence_init         (&rdex.sequence         )) { return 0; }
36   if (! intro_init            (&rdex.intro            )) { return 0; }
37   rdex.starttime = 0;
38   rdex.fullscreen = 0;
39 //  reactiondiffusion_spawn(&rdex.reactiondiffusion);
40   rdex.done = 0;
41   rdex.behaviour = "none";
42   rdex.mode = mode_random;
43   rdex.nrt = nrt;
44   return 1;
45 }
46
47 //======================================================================
48 // main module reshape callback
49 void rdex_reshape(int w, int h) {
50   reactiondiffusion_reshape(&rdex.reactiondiffusion, rdex_tex_size, rdex_tex_size);
51   copysquare_reshape       (&rdex.copysquare,        rdex_tex_size, rdex_tex_size);
52   arithmeticmean_reshape   (&rdex.arithmeticmean,    rdex_tex_size, rdex_tex_size);
53   numericerror_reshape     (&rdex.numericerror,      rdex_tex_size, rdex_tex_size);
54   difference_reshape       (&rdex.difference,        rdex_tex_size, rdex_tex_size);
55   falsecolour_reshape      (&rdex.falsecolour,       rdex_tex_size, rdex_tex_size);
56   library_reshape          (&rdex.library,           w, h);
57   screenshot_reshape       (&rdex.screenshot,        w, h);
58   sequence_reshape         (&rdex.sequence,          w, h);
59   intro_reshape            (&rdex.intro,             w, h);
60 }
61
62 //======================================================================
63 // main module display callback
64 void rdex_display() {
65   glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, rdex.fbo);
66   screenshot_display1      (&rdex.screenshot);
67   for (int g = 0; g < rdex_overdrive; ++g) {
68     reactiondiffusion_display(&rdex.reactiondiffusion, rdex.fbo);
69     if (g % 2 == 0) {
70       audio_display1       (&rdex.audio,             rdex.fbo, rdex.reactiondiffusion.texture, g / 2);
71     }
72   }
73   copysquare_display       (&rdex.copysquare,        rdex.fbo, rdex.reactiondiffusion.texture);
74   arithmeticmean_display   (&rdex.arithmeticmean,    rdex.fbo, rdex.copysquare       .texture);
75   numericerror_display     (&rdex.numericerror,      rdex.fbo, rdex.reactiondiffusion.texture);
76   difference_display       (&rdex.difference,        rdex.fbo, rdex.reactiondiffusion.texture);
77   falsecolour_display      (&rdex.falsecolour,       rdex.fbo, rdex.reactiondiffusion.texture);
78   library_display_save(
79     &rdex.library,
80     rdex.fbo,
81     rdex.falsecolour.texture,
82     rdex.reactiondiffusion.texture,
83     rdex.reactiondiffusion.value.ru,
84     rdex.reactiondiffusion.value.rv,
85     rdex.reactiondiffusion.value.f,
86     rdex.reactiondiffusion.value.k,
87     (rdex.reactiondiffusion.frame / (double) (1 << 14)) *
88     (rdex.reactiondiffusion.frame / (double) (1 << 14)),
89     rdex.behaviour
90   );
91   library_display          (&rdex.library,           rdex.fbo, rdex.falsecolour.texture);
92   sequence_display         (&rdex.sequence, &rdex.library, &rdex.reactiondiffusion, &rdex.audio);
93   intro_display            (&rdex.intro, 0.04); /* FIXME hardcoded frame rate */
94   glutSwapBuffers();
95   audio_display2           (&rdex.audio);
96   screenshot_display2      (&rdex.screenshot);
97   rdex.frame += 1;
98   int reseed = rdex.done;
99   if (rdex.done) {
100     float ru = 0, rv = 0, f = 0, k = 0, ru2, rv2, f2, k2;
101     switch (rdex.mode) {
102     case mode_random: {
103       int i = 0;
104       float randomness = 1e6; //16.0;
105       while (! library_pick(&rdex.library, &ru2, &rv2, &f2, &k2, randomness)) {
106         ru += ru2;
107         rv += rv2;
108         f  += f2;
109         k  += k2;
110         i  += 1;
111 //      randomness = 2.0;
112       }
113       if (i == 0) {
114         reactiondiffusion_randomize(&rdex.reactiondiffusion);
115       } else {
116         ru /= i;
117         rv /= i;
118         f  /= i;
119         k  /= i;
120         reactiondiffusion_near(&rdex.reactiondiffusion, ru, rv, f, k, 0.01);
121       }
122       fprintf(stderr, "%d\t", i);
123     } break;
124     case mode_sequence: {
125       if (reseed) { rdex.reactiondiffusion.frame = 0; }
126     /*
127       if (reseed) {
128       float randomness = 1.1;
129       if (! library_pick(&rdex.library, &ru, &rv, &f, &k, randomness)) {
130         rdex.loop[rdex.loopindex].v[0] = ru;
131         rdex.loop[rdex.loopindex].v[1] = rv;
132         rdex.loop[rdex.loopindex].v[2] = f;
133         rdex.loop[rdex.loopindex].v[3] = k;
134       } else { //if (randomness * rand() / (double) RAND_MAX < 1.0) {
135         rdex.loop[rdex.loopindex].v[0] = 0.3 * rand() / (double) RAND_MAX;
136         rdex.loop[rdex.loopindex].v[1] = 0.3 * rand() / (double) RAND_MAX;
137         rdex.loop[rdex.loopindex].v[2] = 0.1 * rand() / (double) RAND_MAX;
138         rdex.loop[rdex.loopindex].v[3] = 0.1 * rand() / (double) RAND_MAX;
139       }
140     }
141       ru = rdex.loop[rdex.loopindex].v[0];
142       rv = rdex.loop[rdex.loopindex].v[1];
143       f  = rdex.loop[rdex.loopindex].v[2];
144       k  = rdex.loop[rdex.loopindex].v[3];
145       if (reseed) {
146         reactiondiffusion_near(&rdex.reactiondiffusion, ru, rv, f, k, 0.001);
147       } else {
148         rdex.reactiondiffusion.value.ru = ru;
149         rdex.reactiondiffusion.value.rv = rv;
150         rdex.reactiondiffusion.value.f  = f;
151         rdex.reactiondiffusion.value.k  = k;
152       }
153       fprintf(stderr, "L\t");
154     */
155     } break;
156     }
157     rdex.library.worldsphere.delta[0] = (rand() / (double) RAND_MAX - 0.5) / 64.0;
158     rdex.library.worldsphere.delta[1] = (rand() / (double) RAND_MAX - 0.5) / 64.0;
159     rdex.done = 0;
160   }
161 }
162
163 //======================================================================
164 // main module exit callback
165 void rdex_atexit(void) {
166 // /* not safe to call at exit it seems... */
167 //  if (glutGameModeGet(GLUT_GAME_MODE_ACTIVE)) {
168 //    glutLeaveGameMode();
169 //  }
170   audio_atexit(&rdex.audio);
171   double timeelapsed = (double) time(NULL) - (double) rdex.starttime;
172   fprintf(stderr, "\n\n--------------------------------------------------------------------------\n");
173   fprintf(stderr, "------------------------------- statistics -------------------------------\n");
174   fprintf(stderr, "--------------------------------------------------------------------------\n");
175   fprintf(stderr, "%10d seconds elapsed (+/- 1)\n", (int) timeelapsed);
176   fprintf(stderr, "%10d frames rendered (%f fps)\n", rdex.frame, rdex.frame / timeelapsed);
177   fprintf(stderr, "%10d frames dropped\n", rdex.framedrops);
178   fprintf(stderr, "%10d species analyzed (%f sps)\n", rdex.species, rdex.species / timeelapsed);
179   fprintf(stderr, "        %6.2f%% uniform (%d)\n", 100.0 * rdex.uniform / (double) rdex.species, rdex.uniform);
180   fprintf(stderr, "        %6.2f%% stable  (%d)\n", 100.0 * rdex.stable  / (double) rdex.species, rdex.stable);
181   fprintf(stderr, "        %6.2f%% dynamic (%d)\n", 100.0 * rdex.dynamic / (double) rdex.species, rdex.dynamic);
182   fprintf(stderr, "        %6.2f%% erratic (%d)\n", 100.0 * rdex.erratic / (double) rdex.species, rdex.erratic);
183   fprintf(stderr, "--------------------------------------------------------------------------\n");
184   fprintf(stderr, "average frame time: %f seconds\n", rdex.sumdt / rdex.sum1);
185   fprintf(stderr, "standard deviation: %f\n", sqrt( rdex.sumdt2 / rdex.sum1 - pow(rdex.sumdt / rdex.sum1, 2) ));
186   fprintf(stderr, "--------------------------------------------------------------------------\n");
187 }
188
189 //======================================================================
190 // main module timer callback
191 //void rdex_idle() {
192 void rdex_timer(int v) {
193   
194   // initialize
195   if (rdex.starttime == 0) {
196     rdex.starttime = time(NULL);
197     rdex.frame = 0;
198     rdex.sum1 = 0;
199     rdex.sumdt = 0;
200     rdex.sumdt2 = 0;
201     atexit(rdex_atexit);
202     clock_gettime(CLOCK_REALTIME, &rdex.clock0);
203   }
204
205   // check if there are enough free buffers to render a frame
206   int r = audio_read;
207   int w = audio_write;
208   if (rdex.nrt || (w < r && w + AUDIO_COUNT < r) || ( r < w && w + AUDIO_COUNT < r + AUDIO_BUFFERS)) {
209
210   for (int g = 0; g < rdex_overdrive; ++g) {
211     reactiondiffusion_idle(&rdex.reactiondiffusion);
212   }
213   copysquare_idle       (&rdex.copysquare);
214   arithmeticmean_idle   (&rdex.arithmeticmean);
215   numericerror_idle     (&rdex.numericerror);
216   difference_idle       (&rdex.difference);
217   falsecolour_idle      (&rdex.falsecolour);
218   library_idle          (&rdex.library);
219   screenshot_idle       (&rdex.screenshot);
220   if (rdex.reactiondiffusion.frame > (rdex_count*1) && rdex.arithmeticmean.stddev < 0.01) {
221 //    if (rdex.species % 32 == 0) {
222 //      if (rdex.species) { fputc('|', stderr); }
223 //      fprintf(stderr, "\n%08x|", rdex.species);
224 //    }
225     rdex.done = 1; //(rdex.mode == mode_random);
226     rdex.species += 1;
227     rdex.uniform += 1;
228     rdex.behaviour = "uniform";
229 //    rdex.library.snap = 1;
230     //fprintf(stderr, "_\t%d", rdex.reactiondiffusion.frame);
231 //    reactiondiffusion_randomize(&rdex.reactiondiffusion);
232   } else if (rdex.reactiondiffusion.frame % (rdex_count*2) == (rdex_count*1)) {
233     rdex.numericerror.calc = 1;
234   } else if (rdex.reactiondiffusion.frame % (rdex_count*2) == (rdex_count*1) + rdex_overdrive) {
235     if (rdex.numericerror.mean > 0.2) {
236 //      if (rdex.species % 32 == 0) {
237 //        if (rdex.species) { fputc('|', stderr); }
238 //        fprintf(stderr, "\n%08x|", rdex.species);
239 //      }
240       rdex.done = 1;
241       rdex.species += 1;
242       rdex.erratic += 1;
243       //fprintf(stderr, ".\t%d", rdex.reactiondiffusion.frame);
244       //reactiondiffusion_randomize(&rdex.reactiondiffusion);
245     }
246   } else if (rdex.reactiondiffusion.frame % (rdex_count*3) == (rdex_count*1)) {
247     rdex.difference.snap = 1;
248   } else if (rdex.reactiondiffusion.frame % (rdex_count*3) == (rdex_count*2)) {
249     rdex.difference.calc = 1;
250   } else if (rdex.reactiondiffusion.frame % (rdex_count*3) == (rdex_count*2) + rdex_overdrive) {
251     if (rdex.difference.mean < 0.011) {
252       rdex.done = (rdex.mode == mode_random);
253       rdex.species += 1;
254       rdex.stable += 1;
255       rdex.behaviour = "stable";
256       rdex.library.snap = (rdex.mode == mode_random);
257       //fprintf(stderr, "o\t%d", rdex.reactiondiffusion.frame);
258     } else if (rdex.reactiondiffusion.frame > 16000 && rdex.mode == mode_random) {
259       rdex.done = 1;
260       rdex.species += 1;
261       rdex.dynamic += 1;
262       rdex.behaviour = "dynamic";
263       rdex.library.snap = (rdex.mode == mode_random);
264       //fprintf(stderr, "*\t%d", rdex.reactiondiffusion.frame);
265     }
266   }
267 /* else if (rdex.reactiondiffusion.frame == 14400) {
268     if (rdex.species % 32 == 0) {
269       if (rdex.species) { fputc('|', stderr); }
270       fprintf(stderr, "\n%08x|", rdex.species);
271     }
272     rdex.species += 1;
273     int which = rdex.difference.mean < 0.01;
274     if (which) { rdex.stable += 1; } else { rdex.dynamic += 1; }
275     fputc(which ? 'o' : '*', stderr);
276     //reactiondiffusion_perturb(&rdex.reactiondiffusion);
277     reactiondiffusion_randomize(&rdex.reactiondiffusion);
278   }
279 */
280   glutPostRedisplay();
281
282
283   // gather timing statistics
284   clock_gettime(CLOCK_REALTIME, &rdex.clock1);
285   double dt = (rdex.clock1.tv_sec - rdex.clock0.tv_sec) + 1.0e-9 * (rdex.clock1.tv_nsec - rdex.clock0.tv_nsec);
286   rdex.sum1 += 1;
287   rdex.sumdt += dt;
288   rdex.sumdt2 += dt*dt;
289   clock_gettime(CLOCK_REALTIME, &rdex.clock0);
290
291   }
292
293   // sleep for 1ms and check again if jack is ready
294   glutTimerFunc(1, rdex_timer, v + 1);
295
296 }
297
298 void rdex_pmotion(int x, int y) {
299   library_pmotion(&rdex.library, x, y);
300 }
301
302 void rdex_amotion(int x, int y) {
303   library_amotion(&rdex.library, x, y);
304 }
305
306 void rdex_keynormal(unsigned char key, int x, int y) {
307   if (! sequence_keynormal(&rdex.sequence, &rdex.library, key, x, y)) {
308           switch (key) {
309                   case 27: // escape
310                                 exit(0);
311                     break;
312                   case 9: // tab
313                     audio_start(&rdex.audio);
314         intro_start(&rdex.intro);
315                     break;
316                   case 127: // delete
317                     audio_stop(&rdex.audio);
318         //outro_start(&rdex.outro);
319                     break;
320                   default:
321                     break;
322           }
323   }
324 }
325
326 void rdex_keyspecial(int key, int x, int y) {
327   if (! sequence_keyspecial(&rdex.sequence, &rdex.library, key, x, y)) {
328     switch (key) {
329             default:
330               break;
331     }
332   }
333 }
334
335 // EOF