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