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