http://ftp.nluug.nl/pub/os/Linux/distr/pardusrepo/sources/xscreensaver-5.02.tar.gz
[xscreensaver] / hacks / glx / crackberg.c
1 /***************************
2  ** crackberg; Matus Telgarsky [ catachresis@cmu.edu ] 2005 
3  ** */
4 #define XK_MISCELLANY
5 #include <X11/keysymdef.h>
6
7 #define DEFAULTS    "*delay:        20000       \n" \
8                     "*showFPS:      False       \n" \
9                     "*wireframe:    False       \n" \
10
11 # define refresh_crackberg 0
12 #undef countof
13 #define countof(x) (sizeof((x))/sizeof((*x)))
14
15 #include "xlockmore.h"
16 #ifdef USE_GL /* whole file */
17
18 #define DEF_NSUBDIVS   "4"
19 #define DEF_BORING     "False"
20 #define DEF_CRACK      "True"
21 #define DEF_WATER      "True"
22 #define DEF_FLAT       "True"
23 #define DEF_COLOR      "plain"
24 #define DEF_LIT        "True"
25 #define DEF_VISIBILITY "0.6"
26 #define DEF_LETTERBOX  "False"
27
28
29 /***************************
30  ** macros
31  ** */
32
33 #define M_RAD7_4        0.661437827766148
34 #define M_SQRT3_2       0.866025403784439
35 #define M_PI_180        0.0174532925199433
36 #define M_180_PI        57.2957795130823
37 #define MSPEED_SCALE    1.1
38 #define AVE3(a,b,c)     ( ((a) + (b) + (c)) / 3.0 )
39 #define MAX_ZDELTA      0.35
40 #define DISPLACE(h,d)   (h+(random()/(double)RAND_MAX-0.5)*2*MAX_ZDELTA/(1<<d))
41 #define MEAN(x,y)       ( ((x) + (y)) / 2.0 )
42 #define TCOORD(x,y)     (cberg->heights[(cberg->epoints * (y) - ((y)-1)*(y)/2 + (x))])
43 #define sNCOORD(x,y,p)  (cberg->norms[3 * (cberg->epoints * (y) - ((y)-1)*(y)/2 + (x)) + (p)])
44 #define SET_sNCOORD(x,y, down, a,b,c,d,e,f)   \
45     sNCOORD(x,y,0) = AVE3(a-d, 0.5 * (b-e), -0.5 * (c-f)); \
46     sNCOORD(x,y,1) = ((down) ? -1 : +1) * AVE3(0.0, M_SQRT3_2 * (b-e), M_SQRT3_2 * (c-f)); \
47     sNCOORD(x,y,2) = (2*dx)
48 #define fNCOORD(x,y,w,p)  \
49     (cberg->norms[3 * (2*(y)*cberg->epoints-((y)+1)*((y)+1) + 1 + 2 * ((x)-1) + (w)) + (p)])
50 #define SET_fNCOORDa(x,y, down, dz00,dz01) \
51     fNCOORD(x,y,0,0) = (down) * (dy) * (dz01); \
52     fNCOORD(x,y,0,1) = (down) * ((dz01) * (dx) / 2 - (dx) * (dz00)); \
53     fNCOORD(x,y,0,2) = (down) * (dx) * (dy)
54 #define SET_fNCOORDb(x,y, down, dz10,dz11) \
55     fNCOORD(x,y,1,0) = (down) * (dy) * (dz10); \
56     fNCOORD(x,y,1,1) = (down) * ((dz11) * (dx) - (dx) * (dz10) / 2); \
57     fNCOORD(x,y,1,2) = (down) * (dx) * (dy)
58
59
60 /***************************
61  ** types
62  ** */
63
64
65 typedef struct _cberg_state cberg_state;
66 typedef struct _Trile Trile;
67
68 typedef struct {
69     void (*init)(Trile *);
70     void (*free)(Trile *);
71     void (*draw)(Trile *);
72     void (*init_iter)(Trile *, cberg_state *);
73     void (*dying_iter)(Trile *, cberg_state *);
74 } Morph;
75
76 typedef struct {
77     char *id;
78     void (*land)(cberg_state *, double);
79     void (*water)(cberg_state *, double);
80     double bg[4];
81 } Color;
82
83 enum { TRILE_NEW, TRILE_INIT, TRILE_STABLE, TRILE_DYING, TRILE_DELETE };
84
85 struct _Trile {
86     int x,y; /*center coords; points up if (x+y)%2 == 0, else down*/
87     short state;
88     short visible;
89     double *l,*r,*v; /*only edges need saving*/
90     GLuint call_list;
91
92     void *morph_data;
93     const Morph *morph;
94
95     struct _Trile *left, *right, *parent; /* for bst, NOT spatial */
96     struct _Trile *next_free; /* for memory allocation */
97 };
98
99 enum { MOTION_AUTO = 0, MOTION_MANUAL = 1, MOTION_LROT= 2,    MOTION_RROT = 4,
100        MOTION_FORW = 8,   MOTION_BACK = 16,  MOTION_DEC = 32, MOTION_INC = 64,
101        MOTION_LEFT = 128, MOTION_RIGHT = 256 };
102
103 struct _cberg_state {
104     GLXContext *glx_context;
105     Trile *trile_head;
106     
107     double x,y,z, yaw,roll,pitch, dx,dy,dz, dyaw,droll,dpitch, elapsed;
108     double prev_frame;
109     int motion_state;
110     double mspeed;
111
112     double fovy, aspect, zNear, zFar;
113
114     const Color *color;
115
116     int count;
117
118     unsigned int epoints, /*number of points to one edge*/
119                  tpoints, /*number points total*/
120                  ntris,   /*number triangles per trile*/
121                  tnorms;  /*number of normals*/
122
123     double *heights, *norms;
124     Trile *free_head; /* for trile_[alloc|free] */
125
126     double draw_elapsed;
127
128     double dx0;
129
130     double vs0r,vs0g,vs0b, vs1r, vs1g, vs1b,
131            vf0r,vf0g,vf0b, vf1r, vf1g, vf1b;
132 };
133
134
135
136 /***************************
137  ** globals
138  ** */
139
140 static unsigned int nsubdivs;
141 static Bool crack, boring, do_water, flat, lit, letterbox;
142 static float visibility;
143 static char *color;
144
145 static cberg_state *cbergs = NULL;
146
147 static XrmOptionDescRec opts[] = {
148   {"-nsubdivs",   ".nsubdivs",   XrmoptionSepArg, 0},
149   {"-boring",     ".boring",     XrmoptionNoArg,  "True"},
150   {"-crack",      ".crack",      XrmoptionNoArg,  "True"},
151   {"-no-crack",   ".crack",      XrmoptionNoArg,  "False"},
152   {"-water",      ".water",      XrmoptionNoArg,  "True"},
153   {"-no-water",   ".water",      XrmoptionNoArg,  "False"},
154   {"-flat",       ".flat",       XrmoptionNoArg,  "True"},
155   {"-no-flat",    ".flat",       XrmoptionNoArg,  "False"},
156   {"-color",      ".color",      XrmoptionSepArg, 0},
157   {"-lit",        ".lit",        XrmoptionNoArg,  "True"},
158   {"-no-lit",     ".lit",        XrmoptionNoArg,  "False"},
159   {"-visibility", ".visibility", XrmoptionSepArg, 0},
160   {"-letterbox",  ".letterbox",  XrmoptionNoArg,  "True"}
161 };
162
163 static argtype vars[] = {
164   {&nsubdivs,   "nsubdivs",   "nsubdivs",   DEF_NSUBDIVS,   t_Int},
165   {&boring,     "boring",     "boring",     DEF_BORING,     t_Bool},
166   {&crack,      "crack",      "crack",      DEF_CRACK,      t_Bool},
167   {&do_water,   "water",      "water",      DEF_WATER,      t_Bool},
168   {&flat,       "flat",       "flat",       DEF_FLAT,       t_Bool},
169   {&color,      "color",      "color",      DEF_COLOR,      t_String},
170   {&lit,        "lit",        "lit",        DEF_LIT,        t_Bool},
171   {&visibility, "visibility", "visibility", DEF_VISIBILITY, t_Float},
172   {&letterbox,  "letterbox",  "letterbox",  DEF_LETTERBOX,  t_Bool}
173 };
174
175 ENTRYPOINT ModeSpecOpt crackberg_opts = {countof(opts), opts, countof(vars), vars, NULL};
176
177
178 /***************************
179  ** Trile functions. 
180  **  first come all are regular trile functions 
181  ** */
182
183
184 /* forward decls for trile_new */
185 static Trile *triles_find(Trile *tr, int x, int y);
186 static Trile *trile_alloc(cberg_state *cberg);
187 static const Morph *select_morph(void);
188 static const Color *select_color(cberg_state *);
189
190 static void trile_calc_sides(cberg_state *cberg, 
191                              Trile *new, int x, int y, Trile *root)
192 {
193     unsigned int i,j,k; 
194     int dv = ( (x + y) % 2 ? +1 : -1); /* we are pointing down or up*/
195     Trile *l, *r, *v; /* v_ertical */
196
197
198     if (root) {
199         l = triles_find(root, x-1, y);
200         r = triles_find(root, x+1, y);  
201         v = triles_find(root, x,y+dv); 
202     } else
203         l = r = v = NULL;
204
205     if (v) {
206         for (i = 0; i != cberg->epoints; ++i)
207             new->v[i] = v->v[i];
208     } else {
209         if (l)          new->v[0] = l->l[0];
210         else if (!root) new->v[0] = DISPLACE(0,0);
211         else { 
212             Trile *tr; /* all of these tests needed.. */
213             if ( (tr = triles_find(root, x-1, y + dv)) )
214                 new->v[0] = tr->l[0];
215             else if ( (tr = triles_find(root, x-2, y)) )
216                 new->v[0] = tr->r[0];
217             else if ( (tr = triles_find(root, x-2, y + dv)) )
218                 new->v[0] = tr->r[0];
219             else
220                 new->v[0] = DISPLACE(0,0);
221         }
222
223         if (r)          new->v[cberg->epoints-1] = r->l[0];
224         else if (!root) new->v[cberg->epoints-1] = DISPLACE(0,0);
225         else {
226             Trile *tr;
227             if ( (tr = triles_find(root, x+1, y + dv)) )
228                 new->v[cberg->epoints-1] = tr->l[0];
229             else if ( (tr = triles_find(root, x+2, y)) )
230                 new->v[cberg->epoints-1] = tr->v[0];
231             else if ( (tr = triles_find(root, x+2, y + dv)) )
232                 new->v[cberg->epoints-1] = tr->v[0];
233             else
234                 new->v[cberg->epoints-1] = DISPLACE(0,0);
235         }
236
237         for (i = ((1 << nsubdivs) >> 1), k =1; i; i >>= 1, ++k)
238             for (j = i; j < cberg->epoints; j += i * 2)
239                 new->v[j] = DISPLACE(MEAN(new->v[j-i], new->v[j+i]), k);
240     }
241         
242     if (l) {
243         for (i = 0; i != cberg->epoints; ++i)
244             new->l[i] = l->r[i];
245     } else {
246         if (r)          new->l[0] = r->v[0];
247         else if (!root) new->l[0] = DISPLACE(0,0);
248         else {
249             Trile *tr;
250             if ( (tr = triles_find(root, x-1, y-dv)) )
251                 new->l[0] = tr->r[0];
252             else if ( (tr = triles_find(root, x+1, y-dv)) )
253                 new->l[0] = tr->v[0];
254             else if ( (tr = triles_find(root, x, y-dv)) )
255                 new->l[0] = tr->l[0];
256             else 
257                 new->l[0] = DISPLACE(0,0);
258         }
259
260         new->l[cberg->epoints - 1] = new->v[0];
261
262         for (i = ((1 << nsubdivs) >> 1), k =1; i; i >>= 1, ++k)
263             for (j = i; j < cberg->epoints; j += i * 2)
264                 new->l[j] = DISPLACE(MEAN(new->l[j-i], new->l[j+i]), k);
265     }
266
267     if (r) {
268         for (i = 0; i != cberg->epoints; ++i)
269             new->r[i] = r->l[i];
270     } else {
271         new->r[0] = new->v[cberg->epoints - 1];
272         new->r[cberg->epoints - 1] = new->l[0];
273
274         for (i = ((1 << nsubdivs) >> 1), k =1; i; i >>= 1, ++k)
275             for (j = i; j < cberg->epoints; j += i * 2)
276                 new->r[j] = DISPLACE(MEAN(new->r[j-i], new->r[j+i]), k);
277     }
278 }
279
280 static void trile_calc_heights(cberg_state *cberg, Trile *new)
281 {
282     unsigned int i, j, k, h;
283
284     for (i = 0; i < cberg->epoints - 1; ++i) { /* copy in sides */
285         TCOORD(i,0) = new->v[i];
286         TCOORD(cberg->epoints - 1 - i, i) = new->r[i];
287         TCOORD(0, cberg->epoints - 1 - i) = new->l[i];
288     }
289
290     for (i = ((1 << nsubdivs) >> 2), k =1; i; i >>= 1, ++k)
291         for (j = 1; j < (1 << k); ++j)
292             for (h = 1; h <= (1<<k) - j; ++h) {
293                 TCOORD( i*(2*h - 1), i*(2*j - 1) ) = /*rights*/
294                   DISPLACE(MEAN(TCOORD( i*(2*h - 2), i*(2*j + 0) ),
295                                 TCOORD( i*(2*h + 0), i*(2*j - 2) )), k);
296
297                 TCOORD( i*(2*h + 0), i*(2*j - 1) ) = /*lefts*/
298                   DISPLACE(MEAN(TCOORD( i*(2*h + 0), i*(2*j - 2) ),
299                                 TCOORD( i*(2*h + 0), i*(2*j + 0) )), k);
300
301                 TCOORD( i*(2*h - 1), i*(2*j + 0) ) = /*verts*/
302                   DISPLACE(MEAN(TCOORD( i*(2*h - 2), i*(2*j + 0) ),
303                                 TCOORD( i*(2*h + 0), i*(2*j + 0) )), k);
304             }
305 }
306
307 static void trile_calc_flat_norms(cberg_state *cberg, Trile *new)
308 {
309     unsigned int x, y;
310     int down = (((new->x + new->y) % 2) ? -1 : +1);
311     double dz00,dz01,dz10,dz11, a,b,c,d;
312     double dy = down * M_SQRT3_2 / (1 << nsubdivs);
313     double dx = cberg->dx0;
314
315     for (y = 0; y < cberg->epoints - 1; ++y) {
316         a = TCOORD(0,y);
317         b = TCOORD(0,y+1);
318         for (x = 1; x < cberg->epoints - 1 - y; ++x) {
319             c = TCOORD(x,y);
320             d = TCOORD(x,y+1);
321
322             dz00 = b-c;
323             dz01 = a-c;
324             dz10 = b-d;
325             dz11 = c-d;
326             
327             SET_fNCOORDa(x,y, down, dz00,dz01);
328             SET_fNCOORDb(x,y, down, dz10,dz11);
329
330             a = c;
331             b = d;
332         }
333
334         c = TCOORD(x,y);
335         dz00 = b-c;
336         dz01 = a-c;
337         SET_fNCOORDa(x,y, down, dz00, dz01);
338     }
339 }
340
341 static void trile_calc_smooth_norms(cberg_state *cberg, Trile *new)
342 {
343     unsigned int i,j, down = (new->x + new->y) % 2;
344     double prev, cur, next;
345     double dx = cberg->dx0;
346
347     /** corners -- assume level (bah) **/
348     cur = TCOORD(0,0);
349     SET_sNCOORD(0,0, down,
350         cur,cur,TCOORD(0,1),TCOORD(1,0),cur,cur);
351     cur = TCOORD(cberg->epoints-1,0);
352     SET_sNCOORD(cberg->epoints-1,0, down,
353         TCOORD(cberg->epoints-2,0),TCOORD(cberg->epoints-2,1),cur,cur,cur,cur);
354     cur = TCOORD(0,cberg->epoints-1);
355     SET_sNCOORD(0,cberg->epoints-1, down,
356         cur,cur,cur,cur,TCOORD(1,cberg->epoints-2),TCOORD(0,cberg->epoints-2));
357
358
359     /** sides **/
360     /* vert */
361     prev = TCOORD(0,0);
362     cur = TCOORD(1,0);
363     for (i = 1; i < cberg->epoints - 1; ++i) {
364         next = TCOORD(i+1,0);
365         SET_sNCOORD(i,0, down, prev,TCOORD(i-1,1),TCOORD(i,1), next,cur,cur);
366         prev = cur;
367         cur = next;
368     }
369
370     /* right */
371     prev = TCOORD(cberg->epoints-1,0);
372     cur = TCOORD(cberg->epoints-2,0);
373     for (i = 1; i < cberg->epoints - 1; ++i) {
374         next = TCOORD(cberg->epoints-i-2,i+1);
375         SET_sNCOORD(cberg->epoints-i-1,i, down, TCOORD(cberg->epoints-i-2,i),next,cur,
376                                         cur,prev,TCOORD(cberg->epoints-i-1,i-1));
377         prev = cur;
378         cur = next;
379     }
380         
381     /* left */
382     prev = TCOORD(0,0);
383     cur = TCOORD(0,1);
384     for (i = 1; i < cberg->epoints - 1; ++i) {
385         next = TCOORD(0,i+1);
386         SET_sNCOORD(0,i, down, cur,cur,next,TCOORD(1,i),TCOORD(1,i-1),prev);
387         prev = cur;
388         cur = next;
389     }
390
391
392     /** fill in **/
393     for (i = 1; i < cberg->epoints - 2; ++i) {
394         prev = TCOORD(0,i);
395         cur = TCOORD(1,i);
396         for (j = 1; j < cberg->epoints - i - 1; ++j) {
397             next = TCOORD(j+1,i);
398             SET_sNCOORD(j,i, down, prev,TCOORD(j-1,i+1),TCOORD(j,i+1),
399                             next,TCOORD(j+1,i-1),TCOORD(j,i-1));
400             prev = cur;
401             cur = next;
402         }
403     }
404 }
405
406 static inline void trile_light(cberg_state *cberg, 
407                                unsigned int x, unsigned int y, 
408                                unsigned int which)
409 {
410     if (flat) {
411         if (x) {
412             glNormal3d(fNCOORD(x,y,which,0),
413                        fNCOORD(x,y,which,1),
414                        fNCOORD(x,y,which,2));
415         } else { /* I get mesa errors and bizarre glitches without this!! */
416             glNormal3d(fNCOORD(1,y,0,0),
417                        fNCOORD(1,y,0,1),
418                        fNCOORD(1,y,0,2));
419         }
420     } else {
421         glNormal3d(sNCOORD(x,y+which,0),
422                    sNCOORD(x,y+which,1),
423                    sNCOORD(x,y+which,2));
424     }
425 }
426
427 static inline void trile_draw_vertex(cberg_state *cberg, unsigned int ix,
428     unsigned int iy, unsigned int which, double x,double y,
429     double zcur, double z1, double z2)
430 {
431     glColor3d(0.0, 0.0, 0.0); /* don't ask. my card breaks otherwise. */
432     
433     if (do_water && zcur <= 0.0) {
434         cberg->color->water(cberg, zcur); /* XXX use average-of-3 for color when flat?*/
435         if (lit) glNormal3d(0.0,0.0,1.0);
436         glVertex3d(x, y, 0.0); 
437     } else {
438         cberg->color->land(cberg, zcur);
439         if (lit) trile_light(cberg,ix,iy,which);
440         glVertex3d(x, y, zcur);
441     }
442 }
443
444 static void trile_render(cberg_state *cberg, Trile *new)
445 {
446     double cornerx = 0.5 * new->x - 0.5, cornery;
447     double dy = M_SQRT3_2 / (1 << nsubdivs);
448     double z0,z1,z2;
449     int x,y;
450
451     new->call_list = glGenLists(1);
452     glNewList(new->call_list, GL_COMPILE);
453
454         if ((new->x + new->y) % 2) { /*point down*/
455             cornery = (new->y + 0.5)*M_SQRT3_2;
456             glFrontFace(GL_CW);
457             dy = -dy;
458         } else
459             cornery = (new->y - 0.5) * M_SQRT3_2;
460
461         for (y = 0; y < cberg->epoints - 1; ++y) {
462             double dx = cberg->dx0;
463             glBegin(GL_TRIANGLE_STRIP);
464                 /* first three points all part of the same triangle.. */
465                 z0 = TCOORD(0,y);
466                 z1 = TCOORD(0,y+1);
467                 z2 = TCOORD(1,y);
468                 trile_draw_vertex(cberg, 0,y,0,
469                   cornerx,cornery, z0, z1, z2);
470                 trile_draw_vertex(cberg, 0,y,1,
471                   cornerx+0.5*dx,cornery+dy, z1, z0, z2);
472
473                 for (x = 1; x < cberg->epoints - 1 - y; ++x) {
474                     trile_draw_vertex(cberg, x,y,0,
475                       cornerx+x*dx,cornery, z2, z1, z0);
476
477                     z0 = TCOORD(x, y+1);
478
479                     trile_draw_vertex(cberg, x,y,1,
480                       cornerx+(x+0.5)*dx,cornery+dy, z0, z2, z1);
481
482                     z1 = z0;
483                     z0 = z2;
484                     z2 = TCOORD(x+1,y);
485                 }
486                 trile_draw_vertex(cberg, x,y,0,
487                   cornerx + x*dx, cornery, z2, z1, z0);
488             glEnd();
489
490             cornerx += dx/2;
491             cornery += dy;
492         }
493
494         if ((new->x + new->y) % 2) /*point down*/
495             glFrontFace(GL_CCW);
496     glEndList();
497 }
498
499 static Trile *trile_new(cberg_state *cberg, int x,int y,Trile *parent,Trile *root)
500 {
501     Trile *new;
502
503     new = trile_alloc(cberg);
504
505     new->x = x;
506     new->y = y;
507     new->state = TRILE_NEW;
508     new->parent = parent;
509     new->left = new->right = NULL;
510     new->visible = 1;
511
512     new->morph = select_morph();
513     new->morph->init(new);
514
515     trile_calc_sides(cberg, new, x, y, root);
516     trile_calc_heights(cberg, new);
517
518     if (lit) {
519         if (flat)   trile_calc_flat_norms(cberg, new);
520         else        trile_calc_smooth_norms(cberg, new);
521     }
522
523     trile_render(cberg, new);
524     return new;
525 }
526
527 static Trile *trile_alloc(cberg_state *cberg)
528 {
529     Trile *new;
530
531     if (cberg->free_head) {
532         new = cberg->free_head;
533         cberg->free_head = cberg->free_head->next_free;
534     } else {
535         ++cberg->count;
536         if (!(new = malloc(sizeof(Trile)))
537          || !(new->l = (double *) malloc(sizeof(double) * cberg->epoints * 3))) {
538             perror(progname);
539             exit(1);
540         }
541         new->r = new->l + cberg->epoints;
542         new->v = new->r + cberg->epoints;
543 #ifdef DEBUG
544         printf("needed to alloc; [%d]\n", cberg->count);
545 #endif
546     }
547     return new;
548 }
549
550 static void trile_free(cberg_state *cberg, Trile *tr)
551 {
552     glDeleteLists(tr->call_list, 1);
553     tr->morph->free(tr);
554     tr->next_free = cberg->free_head;
555     cberg->free_head = tr;
556 }
557
558
559 static void trile_draw_vanilla(Trile *tr)
560 { glCallList(tr->call_list); }
561
562 static void trile_draw(Trile *tr, void *ignore)
563 {
564     if (tr->state == TRILE_STABLE)
565         trile_draw_vanilla(tr);
566     else
567         tr->morph->draw(tr);
568 }
569
570
571 /***************************
572  ** Trile morph functions. 
573  **  select function at bottom (forward decls sucls) 
574  ** */
575
576
577 /*** first the basic growing morph */
578
579 static void grow_init(Trile *tr)
580 {
581     tr->morph_data = (void *) malloc(sizeof(double));
582     *((double *)tr->morph_data) = 0.02; /* not 0; avoid normals crapping */
583 }
584
585 static void grow_free(Trile *tr)
586 {
587     free(tr->morph_data);
588 }
589
590 static void grow_draw(Trile *tr)
591 {
592     glPushMatrix();
593         glScaled(1.0,1.0, *((double *)tr->morph_data));
594         trile_draw_vanilla(tr);
595     glPopMatrix();
596 }
597
598 static void grow_init_iter(Trile *tr, cberg_state *cberg)
599 {
600     *((double *)(tr->morph_data)) = *((double *)tr->morph_data) + cberg->elapsed;
601     if (*((double *)tr->morph_data) >= 1.0)
602         tr->state = TRILE_STABLE;
603 }
604
605 static void grow_dying_iter(Trile *tr, cberg_state *cberg)
606 {
607     *((double *)tr->morph_data) = *((double *)tr->morph_data) - cberg->elapsed;
608     if (*((double *)tr->morph_data) <= 0.02) /* XXX avoid fast del/cons? */
609         tr->state = TRILE_DELETE;
610 }
611
612 /**** falling morph ****/
613
614 static void fall_init(Trile *tr)
615 {
616     tr->morph_data = (void *) malloc(sizeof(double));
617     *((double *)tr->morph_data) = 0.0;
618 }
619
620 static void fall_free(Trile *tr)
621 {
622     free(tr->morph_data);
623 }
624
625 static void fall_draw(Trile *tr)
626 {
627     glPushMatrix();
628         glTranslated(0.0,0.0,(0.5 - *((double *)tr->morph_data)) * 8);
629         trile_draw_vanilla(tr);
630     glPopMatrix();
631 }
632
633 static void fall_init_iter(Trile *tr, cberg_state *cberg)
634 {
635     *((double *)(tr->morph_data)) = *((double *)tr->morph_data) + cberg->elapsed;
636     if (*((double *)tr->morph_data) >= 0.5)
637         tr->state = TRILE_STABLE;
638 }
639
640 static void fall_dying_iter(Trile *tr, cberg_state *cberg)
641 {
642     *((double *)tr->morph_data) = *((double *)tr->morph_data) - cberg->elapsed;
643     if (*((double *)tr->morph_data) <= 0.0) /* XXX avoid fast del/cons? */
644         tr->state = TRILE_DELETE;
645 }
646
647 /**** yeast morph ****/
648
649 static void yeast_init(Trile *tr)
650 {
651     tr->morph_data = (void *) malloc(sizeof(double));
652     *((double *)tr->morph_data) = 0.02;
653 }
654
655 static void yeast_free(Trile *tr)
656 {
657     free(tr->morph_data);
658 }
659
660 static void yeast_draw(Trile *tr)
661 {
662     double x = tr->x * 0.5,
663            y = tr->y * M_SQRT3_2,
664            z = *((double *)tr->morph_data);
665
666     glPushMatrix();
667         glTranslated(x, y, 0);
668         glRotated(z*360, 0,0,1);
669         glScaled(z,z,z);
670         glTranslated(-x, -y, 0);
671         trile_draw_vanilla(tr);
672     glPopMatrix();
673 }
674
675 static void yeast_init_iter(Trile *tr, cberg_state *cberg)
676 {
677     *((double *)(tr->morph_data)) = *((double *)tr->morph_data) + cberg->elapsed;
678     if (*((double *)tr->morph_data) >= 1.0)
679         tr->state = TRILE_STABLE;
680 }
681
682 static void yeast_dying_iter(Trile *tr, cberg_state *cberg)
683 {
684     *((double *)tr->morph_data) = *((double *)tr->morph_data) - cberg->elapsed;
685     if (*((double *)tr->morph_data) <= 0.02) /* XXX avoid fast del/cons? */
686         tr->state = TRILE_DELETE;
687 }
688
689 /**** identity morph ****/
690
691 static void identity_init(Trile *tr)
692 { tr->state = TRILE_STABLE; }
693
694 static void identity_free(Trile *tr)
695 {}
696
697 static void identity_draw(Trile *tr)
698 { trile_draw_vanilla(tr); }
699
700 static void identity_init_iter(Trile *tr, cberg_state *cberg)
701 {}
702
703 static void identity_dying_iter(Trile *tr, cberg_state *cberg)
704 { tr->state = TRILE_DELETE; }
705
706 /** now to handle selection **/
707
708 static const Morph morphs[] = {
709     {grow_init, grow_free, grow_draw, grow_init_iter, grow_dying_iter},
710     {fall_init, fall_free, fall_draw, fall_init_iter, fall_dying_iter},
711     {yeast_init, yeast_free, yeast_draw, yeast_init_iter, yeast_dying_iter},
712     {identity_init,  /*always put identity last to skip it..*/
713         identity_free, identity_draw, identity_init_iter, identity_dying_iter}
714 };    
715
716 static const Morph *select_morph()
717
718     int nmorphs = countof(morphs);
719     if (crack)
720         return &morphs[random() % (nmorphs-1)]; 
721     else if (boring)
722         return &morphs[nmorphs-1]; 
723     else
724         return morphs;
725 }
726
727
728 /***************************
729  ** Trile superstructure functions. 
730  **  */
731
732
733 static void triles_set_visible(cberg_state *cberg, Trile **root, int x, int y)
734 {
735     Trile *parent = NULL, 
736           *iter = *root;
737     int goleft=0;
738
739     while (iter != NULL) {
740         parent = iter;
741         goleft = (iter->x > x || (iter->x == x && iter->y > y));
742         if (goleft)
743             iter = iter->left;
744         else if (iter->x == x && iter->y == y) {
745             iter->visible = 1;
746             return;
747         } else
748             iter = iter->right;
749     }
750
751     if (parent == NULL)
752         *root = trile_new(cberg, x,y, NULL, NULL);
753     else if (goleft)
754         parent->left = trile_new(cberg, x,y, parent, *root);
755     else
756         parent->right = trile_new(cberg, x,y, parent, *root);
757 }
758
759 static unsigned int triles_foreach(Trile *root, void (*f)(Trile *, void *), 
760   void *data)
761 {
762     if (root == NULL) 
763         return 0;
764     
765     f(root, data);
766     return 1 + triles_foreach(root->left, f, data) 
767       + triles_foreach(root->right, f, data);
768 }
769
770 static void triles_update_state(Trile **root, cberg_state *cberg)
771 {
772     int process_current = 1;
773     if (*root == NULL)
774         return;
775
776     while (process_current) {
777         if ( (*root)->visible ) {
778             if ( (*root)->state == TRILE_INIT )
779                 (*root)->morph->init_iter(*root, cberg);
780             else if ( (*root)->state == TRILE_DYING ) {
781                 (*root)->state = TRILE_INIT;
782                 (*root)->morph->init_iter(*root, cberg);
783             } else if ( (*root)->state == TRILE_NEW ) 
784                 (*root)->state = TRILE_INIT;
785
786             (*root)->visible = 0;
787         } else {
788             if ( (*root)->state == TRILE_STABLE )
789                 (*root)->state = TRILE_DYING;
790             else if ( (*root)->state == TRILE_INIT ) {
791                 (*root)->state = TRILE_DYING;
792                 (*root)->morph->dying_iter(*root, cberg);
793             } else if ( (*root)->state == TRILE_DYING )
794                 (*root)->morph->dying_iter(*root, cberg);
795         }
796
797         if ( (*root)->state == TRILE_DELETE ) {
798             Trile *splice_me;
799             process_current = 1;
800
801             if ((*root)->left == NULL) {
802                 splice_me = (*root)->right;
803                 if (splice_me)
804                     splice_me->parent = (*root)->parent;
805                 else 
806                     process_current = 0;
807             } else if ((*root)->right == NULL) {
808                 splice_me = (*root)->left;
809                 splice_me->parent = (*root)->parent;
810             } else {
811                 Trile *tmp;
812                 for (splice_me = (*root)->right; splice_me->left != NULL; )
813                     splice_me = splice_me->left;
814                 tmp = splice_me->right;
815
816                 if (tmp) tmp->parent = splice_me->parent;
817
818                 if (splice_me == splice_me->parent->left)
819                     splice_me->parent->left = tmp;
820                 else
821                     splice_me->parent->right = tmp;
822
823                 splice_me->parent = (*root)->parent;
824                 splice_me->left = (*root)->left;
825                 (*root)->left->parent = splice_me;
826                 splice_me->right = (*root)->right;
827                 if ((*root)->right)
828                     (*root)->right->parent = splice_me;
829             }
830             trile_free(cberg, *root);
831             *root = splice_me;
832         } else
833             process_current = 0;
834     }
835
836     if (*root) {
837         triles_update_state(&((*root)->left), cberg);
838         triles_update_state(&((*root)->right), cberg);
839     } 
840 }
841
842 static Trile *triles_find(Trile *tr, int x, int y)
843 {
844     while (tr && !(tr->x == x && tr->y == y))
845         if (x < tr->x || (x == tr->x && y < tr->y))
846             tr = tr->left;
847         else
848             tr = tr->right;
849     return tr;
850 }
851
852
853 /***************************
854  ** Trile superstructure visibility functions. 
855  **  strategy fine, implementation lazy&retarded =/
856  **  */
857
858 #ifdef DEBUG
859 static double x_shit, y_shit;
860 #endif
861
862 static void calc_points(cberg_state *cberg, double *x1,double *y1, 
863         double *x2,double *y2, double *x3,double *y3, double *x4,double *y4)
864 {
865     double zNear, x_nearcenter, y_nearcenter, nhalfwidth, x_center, y_center;
866
867
868     /* could cache these.. bahhhhhhhhhhhhhh */
869     double halfheight = tan(cberg->fovy / 2 * M_PI_180) * cberg->zNear;
870     double fovx_2 = atan(halfheight * cberg->aspect / cberg->zNear) * M_180_PI; 
871     double zFar = cberg->zFar + M_RAD7_4;
872     double fhalfwidth = zFar * tan(fovx_2 * M_PI_180)
873                       + M_RAD7_4 / cos(fovx_2 * M_PI_180);
874     double x_farcenter = cberg->x + zFar * cos(cberg->yaw * M_PI_180);
875     double y_farcenter = cberg->y + zFar * sin(cberg->yaw * M_PI_180);
876     *x1 = x_farcenter + fhalfwidth * cos((cberg->yaw - 90) * M_PI_180);
877     *y1 = y_farcenter + fhalfwidth * sin((cberg->yaw - 90) * M_PI_180);
878     *x2 = x_farcenter - fhalfwidth * cos((cberg->yaw - 90) * M_PI_180);
879     *y2 = y_farcenter - fhalfwidth * sin((cberg->yaw - 90) * M_PI_180);
880
881 #ifdef DEBUG
882     printf("pos (%.3f,%.3f) @ %.3f || fovx: %f || fovy: %f\n", 
883             cberg->x, cberg->y, cberg->yaw, fovx_2 * 2, cberg->fovy);
884     printf("\tfarcenter: (%.3f,%.3f) || fhalfwidth: %.3f \n"
885            "\tp1: (%.3f,%.3f) || p2: (%.3f,%.3f)\n",
886             x_farcenter, y_farcenter, fhalfwidth, *x1, *y1, *x2, *y2);
887 #endif
888
889     if (cberg->z - halfheight <= 0) /* near view plane hits xy */
890         zNear = cberg->zNear - M_RAD7_4;
891     else /* use bottom of frustum */
892         zNear = cberg->z / tan(cberg->fovy / 2 * M_PI_180) - M_RAD7_4;
893     nhalfwidth = zNear * tan(fovx_2 * M_PI_180)
894                + M_RAD7_4 / cos(fovx_2 * M_PI_180);
895     x_nearcenter = cberg->x + zNear * cos(cberg->yaw * M_PI_180);
896     y_nearcenter = cberg->y + zNear * sin(cberg->yaw * M_PI_180);
897     *x3 = x_nearcenter - nhalfwidth * cos((cberg->yaw - 90) * M_PI_180);
898     *y3 = y_nearcenter - nhalfwidth * sin((cberg->yaw - 90) * M_PI_180);
899     *x4 = x_nearcenter + nhalfwidth * cos((cberg->yaw - 90) * M_PI_180);
900     *y4 = y_nearcenter + nhalfwidth * sin((cberg->yaw - 90) * M_PI_180);
901
902 #ifdef DEBUG
903     printf("\tnearcenter: (%.3f,%.3f) || nhalfwidth: %.3f\n"
904            "\tp3: (%.3f,%.3f) || p4: (%.3f,%.3f)\n",
905             x_nearcenter, y_nearcenter, nhalfwidth, *x3, *y3, *x4, *y4);
906 #endif
907
908
909     /* center can be average or the intersection of diagonals.. */
910 #if 0
911     {
912         double c = nhalfwidth * (zFar -zNear) / (fhalfwidth + nhalfwidth);
913         x_center = x_nearcenter + c * cos(cberg->yaw * M_PI_180);
914         y_center = y_nearcenter + c * sin(cberg->yaw * M_PI_180);
915     }
916 #else
917     x_center = (x_nearcenter + x_farcenter) / 2;
918     y_center = (y_nearcenter + y_farcenter) / 2;
919 #endif
920 #ifdef DEBUG
921     x_shit = x_center;
922     y_shit = y_center;
923 #endif
924     
925 #define VSCALE(p)   *x##p = visibility * *x##p + (1-visibility) * x_center; \
926                     *y##p = visibility * *y##p + (1-visibility) * y_center
927
928     VSCALE(1);
929     VSCALE(2);
930     VSCALE(3);
931     VSCALE(4);
932 #undef VSCALE
933 }
934
935 /* this is pretty stupid.. */
936 static inline void minmax4(double a, double b, double c, double d, 
937   double *min, double *max)
938 {
939     *min = *max = a;
940
941     if (b > *max)       *max = b;
942     else if (b < *min)  *min = b;
943     if (c > *max)       *max = c;
944     else if (c < *min)  *min = c;
945     if (d > *max)       *max = d;
946     else if (d < *min)  *min = d;
947 }
948
949 typedef struct {
950     double min, max, start, dx;
951 } LS;
952
953 #define check_line(a, b)                     \
954     if (fabs(y##a-y##b) > 0.001) {                    \
955         ls[count].dx = (x##b-x##a)/(y##b-y##a);               \
956         if (y##b > y##a) {                            \
957             ls[count].start = x##a;                     \
958             ls[count].min = y##a;                       \
959             ls[count].max = y##b;                       \
960         } else {                                  \
961             ls[count].start = x##b;                     \
962             ls[count].min = y##b;                       \
963             ls[count].max = y##a;                       \
964         }                                         \
965         ++count;                                    \
966     }
967
968 static unsigned int build_ls(cberg_state *cberg, 
969                       double x1, double y1, double x2, double y2, 
970                       double x3, double y3, double x4, double y4, LS *ls,
971                       double *trough, double *peak)
972 {
973     unsigned int count = 0;
974
975     check_line(1, 2);
976     check_line(2, 3);
977     check_line(3, 4);
978     check_line(4, 1);
979
980     minmax4(y1, y2, y3, y4, trough, peak);
981     return count;
982 }
983
984 #undef check_line
985
986 /*needs bullshit to avoid double counts on corners.*/
987 static void find_bounds(double y, double *left, double *right, LS *ls,
988         unsigned int nls)
989 {
990     double x;
991     unsigned int i, set = 0;
992
993     for (i = 0; i != nls; ++i)
994         if (ls[i].min <= y && ls[i].max >= y) {
995             x = (y - ls[i].min) * ls[i].dx + ls[i].start;
996             if (!set) {
997                 *left = x;
998                 ++set;
999             } else if (fabs(x - *left) > 0.001) {
1000                 if (*left < x)
1001                     *right = x;
1002                 else {
1003                     *right = *left;
1004                     *left = x;
1005                 }
1006                 return;
1007             }
1008         }
1009
1010     /* just in case we somehow blew up */
1011     *left = 3.0;
1012     *right = -3.0;
1013 }
1014
1015 static void mark_visible(cberg_state *cberg)
1016 {
1017     double trough, peak, yval, left=0, right=0;
1018     double x1,y1, x2,y2, x3,y3, x4,y4;
1019     int start, stop, x, y;
1020     LS ls[4];
1021     unsigned int nls;
1022
1023     calc_points(cberg, &x1,&y1, &x2,&y2, &x3,&y3, &x4,&y4);
1024     nls = build_ls(cberg, x1,y1, x2,y2, x3,y3, x4,y4, ls, &trough, &peak);
1025
1026     start = (int) ceil(trough / M_SQRT3_2);
1027     stop = (int) floor(peak / M_SQRT3_2);
1028     
1029     for (y = start; y <= stop; ++y) {
1030         yval = y * M_SQRT3_2;
1031         find_bounds(yval, &left, &right, ls, nls);
1032         for (x = (int) ceil(left*2-1); x <= (int) floor(right*2); ++x) 
1033             triles_set_visible(cberg, &(cberg->trile_head), x, y);
1034     }
1035 }
1036
1037
1038 /***************************
1039  ** color schemes
1040  ** */
1041
1042 static void plain_land(cberg_state *cberg, double z)
1043 { glColor3f(pow((z/0.35),4),  z/0.35, pow((z/0.35),4)); }
1044 static void plain_water(cberg_state *cberg, double z)
1045 { glColor3f(0.0, (z+0.35)*1.6, 0.8); }
1046
1047 static void ice_land(cberg_state *cberg, double z)
1048 { glColor3f((0.35 - z)/0.35, (0.35 - z)/0.35, 1.0); }
1049 static void ice_water(cberg_state *cberg, double z)
1050 { glColor3f(0.0, (z+0.35)*1.6, 0.8); }
1051
1052
1053 static void magma_land(cberg_state *cberg, double z)
1054 { glColor3f(z/0.35, z/0.2,0); }
1055 static void magma_lava(cberg_state *cberg, double z)
1056 { glColor3f((z+0.35)*1.6, (z+0.35), 0.0); }
1057
1058 static void vomit_solid(cberg_state *cberg, double z)
1059 {
1060     double norm = fabs(z) / 0.35;
1061     glColor3f( 
1062       (1-norm) * cberg->vs0r + norm * cberg->vs1r, 
1063       (1-norm) * cberg->vs0g + norm * cberg->vs1g, 
1064       (1-norm) * cberg->vs0b + norm * cberg->vs1b 
1065     );
1066 }
1067 static void vomit_fluid(cberg_state *cberg, double z)
1068 {
1069     double norm = z / -0.35;
1070     glColor3f( 
1071       (1-norm) * cberg->vf0r + norm * cberg->vf1r, 
1072       (1-norm) * cberg->vf0g + norm * cberg->vf1g, 
1073       (1-norm) * cberg->vf0b + norm * cberg->vf1b 
1074     );
1075 }
1076
1077
1078 static const Color colors[] = {
1079     {"plain", plain_land, plain_water, {0.0, 0.0, 0.0, 1.0}},
1080     {"ice", ice_land, ice_water, {0.0, 0.0, 0.0, 1.0}},
1081     {"magma", magma_land, magma_lava, {0.3, 0.3, 0.0, 1.0}},
1082     {"vomit", vomit_solid, vomit_fluid, {0.3, 0.3, 0.0, 1.0}}, /* no error! */
1083 };
1084
1085 static const Color *select_color(cberg_state *cberg)
1086 {
1087     unsigned int ncolors = countof(colors);
1088     int idx = -1;
1089     if ( ! strcmp(color, "random") )
1090         idx = random() % ncolors;
1091     else {
1092         unsigned int i;
1093         for (i = 0; i != ncolors; ++i)
1094             if ( ! strcmp(colors[i].id, color) ) {
1095                 idx = i;
1096                 break;
1097             }
1098
1099         if (idx == -1) {
1100             printf("invalid color scheme selected; valid choices are:\n");
1101             for (i = 0; i != ncolors; ++i)
1102                 printf("\t%s\n", colors[i].id);
1103             printf("\t%s\n", "random");
1104             idx = 0;
1105         }
1106     }
1107
1108     if ( ! strcmp(colors[idx].id, "vomit") ) { /* need to create it (ghetto) */
1109         cberg->vs0r = random()/(double)RAND_MAX;
1110         cberg->vs0g = random()/(double)RAND_MAX;
1111         cberg->vs0b = random()/(double)RAND_MAX; 
1112         cberg->vs1r = random()/(double)RAND_MAX; 
1113         cberg->vs1g = random()/(double)RAND_MAX;
1114         cberg->vs1b = random()/(double)RAND_MAX;
1115         cberg->vf0r = random()/(double)RAND_MAX;
1116         cberg->vf0g = random()/(double)RAND_MAX;
1117         cberg->vf0b = random()/(double)RAND_MAX; 
1118         cberg->vf1r = random()/(double)RAND_MAX; 
1119         cberg->vf1g = random()/(double)RAND_MAX; 
1120         cberg->vf1b = random()/(double)RAND_MAX; 
1121  
1122         glClearColor(random()/(double)RAND_MAX,
1123                      random()/(double)RAND_MAX,
1124                      random()/(double)RAND_MAX,
1125                      1.0);
1126     } else {
1127         glClearColor(colors[idx].bg[0],
1128                      colors[idx].bg[1],
1129                      colors[idx].bg[2],
1130                      colors[idx].bg[3]);
1131     }
1132     return colors + idx;
1133 }
1134
1135
1136 /***************************
1137  ** misc helper functions
1138  ** */
1139
1140
1141 /* simple one for now.. */
1142 static inline double drunken_rando(double cur_val, double max, double width)
1143 {
1144     double r = random() / (double) RAND_MAX * 2;
1145     if (cur_val > 0)
1146         if (r >= 1)
1147             return cur_val + (r-1) * width * (1-cur_val/max);
1148         else
1149             return cur_val - r * width; 
1150     else
1151         if (r >= 1)
1152             return cur_val - (r-1) * width * (1+cur_val/max);
1153         else
1154             return cur_val + r * width; 
1155 }
1156
1157
1158 /***************************
1159  ** core crackberg routines
1160  ** */
1161
1162 ENTRYPOINT void reshape_crackberg (ModeInfo *mi, int w, int h);
1163
1164 ENTRYPOINT void init_crackberg (ModeInfo *mi)
1165 {
1166     cberg_state *cberg;
1167
1168     if (!cbergs) {
1169         nsubdivs %= 16; /* just in case.. */
1170
1171         if ( !(cbergs = calloc(MI_NUM_SCREENS(mi), sizeof(cberg_state)))) {
1172             perror(progname);
1173             exit(1);
1174         }
1175
1176         if (visibility > 1.0 || visibility < 0.2) {
1177             printf("visibility must be in range [0.2 .. 1.0]\n");
1178             visibility = 1.0;
1179         }
1180     }
1181
1182     cberg = &cbergs[MI_SCREEN(mi)];
1183     
1184     cberg->epoints = 1 + (1 << nsubdivs);
1185     cberg->tpoints = cberg->epoints * (cberg->epoints + 1) / 2;
1186     cberg->ntris = (1 << (nsubdivs << 1));
1187     cberg->tnorms = ( (flat) ? cberg->ntris : cberg->tpoints);
1188     cberg->dx0 = 1.0 / (1 << nsubdivs);
1189
1190     cberg->heights = malloc(cberg->tpoints * sizeof(double));
1191     cberg->norms = malloc(3 * cberg->tnorms * sizeof(double));
1192
1193     cberg->glx_context = init_GL(mi);
1194     cberg->motion_state = MOTION_AUTO;
1195     cberg->mspeed = 1.0;
1196     cberg->z = 0.5;
1197
1198     cberg->fovy = 60.0;
1199     cberg->zNear = 0.5;
1200     cberg->zFar = 5.0;
1201
1202     cberg->draw_elapsed = 1.0;
1203
1204     glEnable(GL_DEPTH_TEST);
1205     glEnable(GL_BLEND);
1206     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1207     glShadeModel((flat) ? GL_FLAT : GL_SMOOTH);
1208     glPolygonMode(GL_FRONT_AND_BACK, (MI_IS_WIREFRAME(mi)) ? GL_LINE : GL_FILL);
1209
1210     if (lit) {
1211         glEnable(GL_LIGHTING);
1212         glEnable(GL_LIGHT0);
1213         glEnable(GL_COLOR_MATERIAL);
1214         glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
1215         glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
1216         glEnable(GL_NORMALIZE);
1217         glEnable(GL_RESCALE_NORMAL); 
1218     }
1219
1220     cberg->color = select_color(cberg);
1221
1222     reshape_crackberg(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
1223 }
1224
1225 ENTRYPOINT void reshape_crackberg (ModeInfo *mi, int w, int h)
1226 {
1227     int h2;
1228     cberg_state *cberg = &cbergs[MI_SCREEN(mi)];
1229
1230     if (letterbox && (h2 = w * 9 / 16) < h) {
1231         glViewport(0, (h-h2)/2, w, h2);
1232         cberg->aspect = w/(double)h2;
1233     } else {
1234         glViewport (0, 0, w, h);
1235         cberg->aspect = w/(double)h;
1236     }
1237
1238     glMatrixMode(GL_PROJECTION);
1239     glLoadIdentity();
1240     gluPerspective(cberg->fovy, cberg->aspect, cberg->zNear, cberg->zFar);
1241     glMatrixMode(GL_MODELVIEW);
1242 }
1243
1244 ENTRYPOINT Bool crackberg_handle_event (ModeInfo *mi, XEvent *ev)
1245 {
1246     cberg_state *cberg = &cbergs[MI_SCREEN(mi)];
1247
1248     if (ev->xany.type == KeyPress) {
1249         switch (XKeycodeToKeysym(mi->dpy, ev->xkey.keycode, 0)) {
1250             case XK_Left:   cberg->motion_state |= MOTION_LROT;  break;
1251             case XK_Right:  cberg->motion_state |= MOTION_RROT;  break;
1252             case '1':       cberg->motion_state |= MOTION_DEC;   break; 
1253             case '2':       cberg->motion_state |= MOTION_INC;   break;
1254             case 'a':       cberg->motion_state |= MOTION_LEFT;  break;
1255             case 'd':       cberg->motion_state |= MOTION_RIGHT; break;
1256             case 's':       cberg->motion_state |= MOTION_BACK;  break;
1257             case 'w':       cberg->motion_state |= MOTION_FORW;  break;
1258             default:        return False;
1259         }
1260         cberg->motion_state |= MOTION_MANUAL;
1261     } else if (ev->xany.type == KeyRelease) { 
1262 #if 0
1263         XEvent peek_ev;
1264         if (XPending(mi->dpy)) {
1265             XPeekEvent(mi->dpy, &peek_ev);
1266             if (peek_ev.type == KeyPress
1267              && peek_ev.xkey.keycode == ev->xkey.keycode       
1268              && peek_ev.xkey.time - ev->xkey.time < 2) {
1269                 XNextEvent(mi->dpy, &peek_ev); /* drop bullshit repeat events */
1270                 return False;
1271             }
1272         }
1273 #endif
1274
1275         switch (XKeycodeToKeysym(mi->dpy, ev->xkey.keycode, 0)) {
1276             case XK_Left:   cberg->motion_state &= ~MOTION_LROT;  break;
1277             case XK_Right:  cberg->motion_state &= ~MOTION_RROT;  break;
1278             case '1':       cberg->motion_state &= ~MOTION_DEC;   break; 
1279             case '2':       cberg->motion_state &= ~MOTION_INC;   break;
1280             case 'a':       cberg->motion_state &= ~MOTION_LEFT;  break;
1281             case 'd':       cberg->motion_state &= ~MOTION_RIGHT; break;
1282             case 's':       cberg->motion_state &= ~MOTION_BACK;  break;
1283             case 'w':       cberg->motion_state &= ~MOTION_FORW;  break;
1284             case ' ':       
1285                 if (cberg->motion_state == MOTION_MANUAL)
1286                     cberg->motion_state = MOTION_AUTO;     
1287                 break;
1288             default:            return False;
1289         }
1290     } else
1291         return False;
1292     return True;
1293 }   
1294  
1295 ENTRYPOINT void draw_crackberg (ModeInfo *mi)
1296 {
1297     cberg_state *cberg = &cbergs[MI_SCREEN(mi)];
1298     struct timeval cur_frame_t;
1299     double cur_frame;
1300     static const float lpos[] = {2.0,0.0,-0.3,0.0};
1301
1302     if (!cberg->glx_context) /*XXX does this get externally tweaked? it kinda*/
1303         return;               /*XXX can't.. check it in crackberg_init*/
1304
1305     glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(cberg->glx_context));
1306
1307     gettimeofday(&cur_frame_t, NULL);
1308     cur_frame = cur_frame_t.tv_sec + cur_frame_t.tv_usec / 1.0E6;
1309     if ( cberg->prev_frame ) { /*not first run */
1310
1311         cberg->elapsed = cur_frame - cberg->prev_frame;
1312
1313         if (cberg->motion_state == MOTION_AUTO) {
1314             cberg->x += cberg->dx * cberg->elapsed;
1315             cberg->y += cberg->dy * cberg->elapsed;
1316             /* cberg->z */
1317             /* cberg->pitch */
1318             /* cberg->roll */
1319             cberg->yaw += cberg->dyaw * cberg->elapsed;
1320
1321             cberg->draw_elapsed += cberg->elapsed;
1322             if (cberg->draw_elapsed >= 0.8) {
1323                 cberg->draw_elapsed = 0.0;
1324                 cberg->dx = drunken_rando(cberg->dx, 2.5, 0.8);
1325                 cberg->dy = drunken_rando(cberg->dy, 2.5, 0.8);
1326                 /* cberg->dz */
1327                 /* cberg->dpitch */
1328                 /* cberg->droll */
1329                 cberg->dyaw = drunken_rando(cberg->dyaw, 40.0,  8.0);
1330             }
1331         } else {
1332             double scale = cberg->elapsed * cberg->mspeed;
1333             if (cberg->motion_state & MOTION_BACK) {
1334                 cberg->x -= cos(cberg->yaw * M_PI_180) * scale;
1335                 cberg->y -= sin(cberg->yaw * M_PI_180) * scale;
1336             }
1337             if (cberg->motion_state & MOTION_FORW) {
1338                 cberg->x += cos(cberg->yaw * M_PI_180) * scale;
1339                 cberg->y += sin(cberg->yaw * M_PI_180) * scale;
1340             }
1341
1342             if (cberg->motion_state & MOTION_LEFT) {
1343                 cberg->x -= sin(cberg->yaw * M_PI_180) * scale;
1344                 cberg->y += cos(cberg->yaw * M_PI_180) * scale;
1345             }
1346             if (cberg->motion_state & MOTION_RIGHT) {
1347                 cberg->x += sin(cberg->yaw * M_PI_180) * scale;
1348                 cberg->y -= cos(cberg->yaw * M_PI_180) * scale;
1349             }
1350
1351             if (cberg->motion_state & MOTION_LROT)
1352                 cberg->yaw += 45 * scale;
1353             if (cberg->motion_state & MOTION_RROT)
1354                 cberg->yaw -= 45 * scale;
1355
1356             if (cberg->motion_state & MOTION_DEC)
1357                 cberg->mspeed /= pow(MSPEED_SCALE, cberg->draw_elapsed);
1358             if (cberg->motion_state & MOTION_INC)
1359                 cberg->mspeed *= pow(MSPEED_SCALE, cberg->draw_elapsed);
1360
1361         }
1362     }
1363     cberg->prev_frame = cur_frame;
1364
1365     mark_visible(cberg);
1366     triles_update_state(&(cberg->trile_head), cberg);
1367         
1368     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1369     glLoadIdentity();
1370     gluLookAt(0,0,0, 1,0,0, 0,0,1);
1371     glLightfv(GL_LIGHT0, GL_POSITION, lpos);
1372     /*glRotated(cberg->roll, 1,0,0); / * XXX blah broken and unused for now..* /
1373     glRotated(cberg->pitch, 0,1,0); */
1374     glRotated(-cberg->yaw, 0,0,1); /* camera sees ->yaw over */
1375     glTranslated(-cberg->x, -cberg->y, -cberg->z);
1376
1377     mi->polygon_count = cberg->ntris * 
1378       triles_foreach(cberg->trile_head, trile_draw,(void *) cberg);
1379     
1380     if (mi->fps_p)  
1381         do_fps(mi);
1382
1383 #ifdef DEBUG
1384     glBegin(GL_LINES);
1385         glColor3f(1.0,0.0,0.0);
1386         glVertex3d(x_shit, y_shit, 0.0);
1387         glVertex3d(x_shit, y_shit, 1.0);
1388     glEnd();
1389 #endif
1390
1391     glFinish();
1392     glXSwapBuffers(MI_DISPLAY(mi), MI_WINDOW(mi));
1393 }
1394
1395 /* uh */
1396 ENTRYPOINT void release_crackberg (ModeInfo *mi)
1397 {
1398   if (cbergs) {
1399     int screen;
1400     for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
1401       cberg_state *cberg = &cbergs[screen];
1402       if (cberg->norms)
1403         free(cberg->norms);
1404       free(cberg->heights);
1405     }
1406     free (cbergs);
1407     cbergs = 0;
1408   }
1409 }
1410
1411 XSCREENSAVER_MODULE ("Crackberg", crackberg)
1412
1413 #endif /* USE_GL */