1 /***************************
2 ** crackberg; Matus Telgarsky [ catachresis@cmu.edu ] 2005
4 #include <X11/Intrinsic.h>
6 #include <X11/keysymdef.h>
8 extern XtAppContext app;
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
19 #define DEFAULTS "*delay: 20000 \n" \
20 "*showFPS: False \n" \
23 #define countof(x) (sizeof((x))/sizeof((*x)))
25 #include "xlockmore.h"
26 #ifdef USE_GL /* whole file */
31 /***************************
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)
62 /***************************
67 typedef struct _cberg_state cberg_state;
68 typedef struct _Trile Trile;
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 *);
81 void (*water)(double);
85 enum { TRILE_NEW, TRILE_INIT, TRILE_STABLE, TRILE_DYING, TRILE_DELETE };
88 int x,y; /*center coords; points up if (x+y)%2 == 0, else down*/
91 double *l,*r,*v; /*only edges need saving*/
97 struct _Trile *left, *right, *parent; /* for bst, NOT spatial */
98 struct _Trile *next_free; /* for memory allocation */
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 };
105 struct _cberg_state {
106 GLXContext *glx_context;
109 double x,y,z, yaw,roll,pitch, dx,dy,dz, dyaw,droll,dpitch, elapsed;
114 double fovy, aspect, zNear, zFar;
120 /***************************
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;
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] */
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"}
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}
164 ModeSpecOpt sws_opts = {countof(opts), opts, countof(vars), vars, NULL};
167 /***************************
169 ** first come all are regular trile functions
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);
179 static void trile_calc_sides(Trile *new, int x, int y, Trile *root)
182 int dv = ( (x + y) % 2 ? +1 : -1); /* we are pointing down or up*/
183 Trile *l, *r, *v; /* v_ertical */
187 l = triles_find(root, x-1, y);
188 r = triles_find(root, x+1, y);
189 v = triles_find(root, x,y+dv);
194 for (i = 0; i != epoints; ++i)
197 if (l) new->v[0] = l->l[0];
198 else if (!root) new->v[0] = DISPLACE(0,0);
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];
208 new->v[0] = DISPLACE(0,0);
211 if (r) new->v[epoints-1] = r->l[0];
212 else if (!root) new->v[epoints-1] = DISPLACE(0,0);
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];
222 new->v[epoints-1] = DISPLACE(0,0);
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);
231 for (i = 0; i != epoints; ++i)
234 if (r) new->l[0] = r->v[0];
235 else if (!root) new->l[0] = DISPLACE(0,0);
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];
245 new->l[0] = DISPLACE(0,0);
248 new->l[epoints - 1] = new->v[0];
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);
256 for (i = 0; i != epoints; ++i)
259 new->r[0] = new->v[epoints - 1];
260 new->r[epoints - 1] = new->l[0];
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);
268 static void trile_calc_heights(Trile *new)
270 unsigned int i, j, k, h;
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];
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);
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);
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);
295 static void trile_calc_flat_norms(Trile *new)
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);
302 for (y = 0; y < epoints - 1; ++y) {
305 for (x = 1; x < epoints - 1 - y; ++x) {
314 SET_fNCOORDa(x,y, down, dz00,dz01);
315 SET_fNCOORDb(x,y, down, dz10,dz11);
324 SET_fNCOORDa(x,y, down, dz00, dz01);
328 static void trile_calc_smooth_norms(Trile *new)
330 unsigned int i,j, down = (new->x + new->y) % 2;
331 double prev, cur, next;
333 /** corners -- assume level (bah) **/
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));
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);
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));
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);
379 for (i = 1; i < epoints - 2; ++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));
392 static inline void trile_light(unsigned int x, unsigned int y,
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),
406 glNormal3d(sNCOORD(x,y+which,0),
407 sNCOORD(x,y+which,1),
408 sNCOORD(x,y+which,2));
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)
416 glColor3d(0.0, 0.0, 0.0); /* don't ask. my card breaks otherwise. */
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);
423 cberg->color->land(zcur);
424 if (lit) trile_light(ix,iy,which);
425 glVertex3d(x, y, zcur);
429 static void trile_render(cberg_state *cberg, Trile *new)
431 double cornerx = 0.5 * new->x - 0.5, cornery;
432 double dy = M_SQRT3_2 / (1 << nsubdivs);
436 new->call_list = glGenLists(1);
437 glNewList(new->call_list, GL_COMPILE);
439 if ((new->x + new->y) % 2) { /*point down*/
440 cornery = (new->y + 0.5)*M_SQRT3_2;
444 cornery = (new->y - 0.5) * M_SQRT3_2;
446 for (y = 0; y < epoints - 1; ++y) {
447 glBegin(GL_TRIANGLE_STRIP);
448 /* first three points all part of the same triangle.. */
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);
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);
463 trile_draw_vertex(cberg, x,y,1,
464 cornerx+(x+0.5)*dx,cornery+dy, z0, z2, z1);
470 trile_draw_vertex(cberg, x,y,0,
471 cornerx + x*dx, cornery, z2, z1, z0);
478 if ((new->x + new->y) % 2) /*point down*/
483 static Trile *trile_new(cberg_state *cberg, int x,int y,Trile *parent,Trile *root)
491 new->state = TRILE_NEW;
492 new->parent = parent;
493 new->left = new->right = NULL;
496 new->morph = select_morph();
497 new->morph->init(new);
499 trile_calc_sides(new, x, y, root);
500 trile_calc_heights(new);
503 if (flat) trile_calc_flat_norms(new);
504 else trile_calc_smooth_norms(new);
507 trile_render(cberg, new);
511 static Trile *trile_alloc(void)
514 static unsigned int count = 0;
518 free_head = free_head->next_free;
521 if (!(new = malloc(sizeof(Trile)))
522 || !(new->l = (double *) malloc(sizeof(double) * epoints * 3))) {
526 new->r = new->l + epoints;
527 new->v = new->r + epoints;
529 printf("needed to alloc; [%d]\n", count);
535 static void trile_free(Trile *tr)
537 glDeleteLists(tr->call_list, 1);
539 tr->next_free = free_head;
544 static void trile_draw_vanilla(Trile *tr)
545 { glCallList(tr->call_list); }
547 static void trile_draw(Trile *tr, void *ignore)
549 if (tr->state == TRILE_STABLE)
550 trile_draw_vanilla(tr);
556 /***************************
557 ** Trile morph functions.
558 ** select function at bottom (forward decls sucls)
562 /*** first the basic growing morph */
564 static void grow_init(Trile *tr)
566 tr->morph_data = (void *) malloc(sizeof(double));
567 *((double *)tr->morph_data) = 0.02; /* not 0; avoid normals crapping */
570 static void grow_free(Trile *tr)
572 free(tr->morph_data);
575 static void grow_draw(Trile *tr)
578 glScaled(1.0,1.0, *((double *)tr->morph_data));
579 trile_draw_vanilla(tr);
583 static void grow_init_iter(Trile *tr, cberg_state *cberg)
585 *((double *)(tr->morph_data)) = *((double *)tr->morph_data) + cberg->elapsed;
586 if (*((double *)tr->morph_data) >= 1.0)
587 tr->state = TRILE_STABLE;
590 static void grow_dying_iter(Trile *tr, cberg_state *cberg)
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;
597 /**** falling morph ****/
599 static void fall_init(Trile *tr)
601 tr->morph_data = (void *) malloc(sizeof(double));
602 *((double *)tr->morph_data) = 0.0;
605 static void fall_free(Trile *tr)
607 free(tr->morph_data);
610 static void fall_draw(Trile *tr)
613 glTranslated(0.0,0.0,(0.5 - *((double *)tr->morph_data)) * 8);
614 trile_draw_vanilla(tr);
618 static void fall_init_iter(Trile *tr, cberg_state *cberg)
620 *((double *)(tr->morph_data)) = *((double *)tr->morph_data) + cberg->elapsed;
621 if (*((double *)tr->morph_data) >= 0.5)
622 tr->state = TRILE_STABLE;
625 static void fall_dying_iter(Trile *tr, cberg_state *cberg)
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;
632 /**** yeast morph ****/
634 static void yeast_init(Trile *tr)
636 tr->morph_data = (void *) malloc(sizeof(double));
637 *((double *)tr->morph_data) = 0.02;
640 static void yeast_free(Trile *tr)
642 free(tr->morph_data);
645 static void yeast_draw(Trile *tr)
647 double x = tr->x * 0.5,
648 y = tr->y * M_SQRT3_2,
649 z = *((double *)tr->morph_data);
652 glTranslated(x, y, 0);
653 glRotated(z*360, 0,0,1);
655 glTranslated(-x, -y, 0);
656 trile_draw_vanilla(tr);
660 static void yeast_init_iter(Trile *tr, cberg_state *cberg)
662 *((double *)(tr->morph_data)) = *((double *)tr->morph_data) + cberg->elapsed;
663 if (*((double *)tr->morph_data) >= 1.0)
664 tr->state = TRILE_STABLE;
667 static void yeast_dying_iter(Trile *tr, cberg_state *cberg)
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;
674 /**** identity morph ****/
676 static void identity_init(Trile *tr)
677 { tr->state = TRILE_STABLE; }
679 static void identity_free(Trile *tr)
682 static void identity_draw(Trile *tr)
683 { trile_draw_vanilla(tr); }
685 static void identity_init_iter(Trile *tr, cberg_state *cberg)
688 static void identity_dying_iter(Trile *tr, cberg_state *cberg)
689 { tr->state = TRILE_DELETE; }
691 /** now to handle selection **/
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}
700 static unsigned int nmorphs = countof(morphs);
702 static Morph *select_morph()
705 return &morphs[random() % (nmorphs-1)];
707 return &morphs[nmorphs-1];
713 /***************************
714 ** Trile superstructure functions.
718 static void triles_set_visible(cberg_state *cberg, Trile **root, int x, int y)
720 Trile *parent = NULL,
724 while (iter != NULL) {
726 goleft = (iter->x > x || (iter->x == x && iter->y > y));
729 else if (iter->x == x && iter->y == y) {
737 *root = trile_new(cberg, x,y, NULL, NULL);
739 parent->left = trile_new(cberg, x,y, parent, *root);
741 parent->right = trile_new(cberg, x,y, parent, *root);
744 static unsigned int triles_foreach(Trile *root, void (*f)(Trile *, void *),
751 return 1 + triles_foreach(root->left, f, data)
752 + triles_foreach(root->right, f, data);
755 static void triles_update_state(Trile **root, cberg_state *cberg)
757 int process_current = 1;
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;
771 (*root)->visible = 0;
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);
782 if ( (*root)->state == TRILE_DELETE ) {
786 if ((*root)->left == NULL) {
787 splice_me = (*root)->right;
789 splice_me->parent = (*root)->parent;
792 } else if ((*root)->right == NULL) {
793 splice_me = (*root)->left;
794 splice_me->parent = (*root)->parent;
797 for (splice_me = (*root)->right; splice_me->left != NULL; )
798 splice_me = splice_me->left;
799 tmp = splice_me->right;
801 if (tmp) tmp->parent = splice_me->parent;
803 if (splice_me == splice_me->parent->left)
804 splice_me->parent->left = tmp;
806 splice_me->parent->right = tmp;
808 splice_me->parent = (*root)->parent;
809 splice_me->left = (*root)->left;
810 (*root)->left->parent = splice_me;
811 splice_me->right = (*root)->right;
813 (*root)->right->parent = splice_me;
822 triles_update_state(&((*root)->left), cberg);
823 triles_update_state(&((*root)->right), cberg);
827 static Trile *triles_find(Trile *tr, int x, int y)
829 while (tr && !(tr->x == x && tr->y == y))
830 if (x < tr->x || (x == tr->x && y < tr->y))
838 /***************************
839 ** Trile superstructure visibility functions.
840 ** strategy fine, implementation lazy&retarded =/
844 static double x_shit, y_shit;
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)
850 double zNear, x_nearcenter, y_nearcenter, nhalfwidth, x_center, y_center;
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);
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);
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);
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);
894 /* center can be average or the intersection of diagonals.. */
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);
902 x_center = (x_nearcenter + x_farcenter) / 2;
903 y_center = (y_nearcenter + y_farcenter) / 2;
910 #define VSCALE(p) *x##p = visibility * *x##p + (1-visibility) * x_center; \
911 *y##p = visibility * *y##p + (1-visibility) * y_center
920 /* this is pretty stupid.. */
921 static inline void minmax4(double a, double b, double c, double d,
922 double *min, double *max)
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;
935 double min, max, start, dx;
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); \
942 ls[count].start = x##a; \
943 ls[count].min = y##a; \
944 ls[count].max = y##b; \
946 ls[count].start = x##b; \
947 ls[count].min = y##b; \
948 ls[count].max = y##a; \
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)
958 unsigned int count = 0;
965 minmax4(y1, y2, y3, y4, trough, peak);
971 /*needs bullshit to avoid double counts on corners.*/
972 static void find_bounds(double y, double *left, double *right, LS *ls,
976 unsigned int i, set = 0;
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;
984 } else if (fabs(x - *left) > 0.001) {
995 /* just in case we somehow blew up */
1000 static void mark_visible(cberg_state *cberg)
1002 double trough, peak, yval, left, right;
1003 double x1,y1, x2,y2, x3,y3, x4,y4;
1004 int start, stop, x, y;
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);
1011 start = (int) ceil(trough / M_SQRT3_2);
1012 stop = (int) floor(peak / M_SQRT3_2);
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);
1023 /***************************
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); }
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); }
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); }
1043 static double vs0r,vs0g,vs0b, vs1r, vs1g, vs1b,
1044 vf0r,vf0g,vf0b, vf1r, vf1g, vf1b;
1045 static void vomit_solid(double z)
1047 double norm = fabs(z) / 0.35;
1049 (1-norm) * vs0r + norm * vs1r,
1050 (1-norm) * vs0g + norm * vs1g,
1051 (1-norm) * vs0b + norm * vs1b
1054 static void vomit_fluid(double z)
1056 double norm = z / -0.35;
1058 (1-norm) * vf0r + norm * vf1r,
1059 (1-norm) * vf0g + norm * vf1g,
1060 (1-norm) * vf0b + norm * vf1b
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! */
1071 static unsigned int ncolors = countof(colors);
1073 static Color *select_color()
1076 if ( ! strcmp(color, "random") )
1077 idx = random() % ncolors;
1080 for (i = 0; i != ncolors; ++i)
1081 if ( ! strcmp(colors[i].id, color) ) {
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");
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;
1109 glClearColor(random()/(double)RAND_MAX,
1110 random()/(double)RAND_MAX,
1111 random()/(double)RAND_MAX,
1114 glClearColor(colors[idx].bg[0],
1119 return colors + idx;
1123 /***************************
1124 ** misc helper functions
1128 /* simple one for now.. */
1129 static inline double drunken_rando(double cur_val, double max, double width)
1131 double r = random() / (double) RAND_MAX * 2;
1134 return cur_val + (r-1) * width * (1-cur_val/max);
1136 return cur_val - r * width;
1139 return cur_val - (r-1) * width * (1+cur_val/max);
1141 return cur_val + r * width;
1145 /***************************
1146 ** core crackberg routines
1150 void crackberg_init(ModeInfo *mi)
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);
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)))) ) {
1169 if (visibility > 1.0 || visibility < 0.2) {
1170 printf("visibility must be in range [0.2 .. 1.0]\n");
1175 cberg = cbergs + MI_SCREEN(mi);
1177 cberg->glx_context = init_GL(mi);
1178 cberg->motion_state = MOTION_AUTO;
1179 cberg->mspeed = 1.0;
1186 glEnable(GL_DEPTH_TEST);
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);
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);
1202 cberg->color = select_color();
1204 crackberg_reshape(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
1207 void crackberg_reshape(ModeInfo *mi, int w, int h)
1210 cberg_state *cberg = cbergs + MI_SCREEN(mi);
1212 if (letterbox && (h2 = w * 9 / 16) < h) {
1213 glViewport(0, (h-h2)/2, w, h2);
1214 cberg->aspect = w/(double)h2;
1216 glViewport (0, 0, w, h);
1217 cberg->aspect = w/(double)h;
1220 glMatrixMode(GL_PROJECTION);
1222 gluPerspective(cberg->fovy, cberg->aspect, cberg->zNear, cberg->zFar);
1223 glMatrixMode(GL_MODELVIEW);
1226 Bool crackberg_handle_ev(ModeInfo *mi, XEvent *ev)
1228 cberg_state *cberg = cbergs + MI_SCREEN(mi);
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;
1242 cberg->motion_state |= MOTION_MANUAL;
1243 } else if (ev->xany.type == KeyRelease) {
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 */
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;
1265 if (cberg->motion_state == MOTION_MANUAL)
1266 cberg->motion_state = MOTION_AUTO;
1268 default: return False;
1275 void crackberg_draw(ModeInfo *mi)
1277 cberg_state *cberg = cbergs + MI_SCREEN(mi);
1278 struct timeval cur_frame_t;
1280 static float lpos[] = {2.0,0.0,-0.3,0.0};
1282 if (!cberg->glx_context) /*XXX does this get externally tweaked? it kinda*/
1283 return; /*XXX can't.. check it in crackberg_init*/
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;
1290 cberg->elapsed = cur_frame - cberg->prev_frame;
1292 if (cberg->motion_state == MOTION_AUTO) {
1293 cberg->x += cberg->dx * cberg->elapsed;
1294 cberg->y += cberg->dy * cberg->elapsed;
1298 cberg->yaw += cberg->dyaw * cberg->elapsed;
1300 elapsed += cberg->elapsed;
1301 if (elapsed >= 0.8) {
1303 cberg->dx = drunken_rando(cberg->dx, 2.5, 0.8);
1304 cberg->dy = drunken_rando(cberg->dy, 2.5, 0.8);
1308 cberg->dyaw = drunken_rando(cberg->dyaw, 40.0, 8.0);
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;
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;
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;
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;
1330 if (cberg->motion_state & MOTION_LROT)
1331 cberg->yaw += 45 * scale;
1332 if (cberg->motion_state & MOTION_RROT)
1333 cberg->yaw -= 45 * scale;
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);
1342 cberg->prev_frame = cur_frame;
1344 mark_visible(cberg);
1345 triles_update_state(&(cberg->trile_head), cberg);
1347 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
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);
1356 mi->polygon_count = ntris *
1357 triles_foreach(cberg->trile_head, trile_draw,(void *) cberg);
1364 glColor3f(1.0,0.0,0.0);
1365 glVertex3d(x_shit, y_shit, 0.0);
1366 glVertex3d(x_shit, y_shit, 1.0);
1371 glXSwapBuffers(MI_DISPLAY(mi), MI_WINDOW(mi));
1375 void crackberg_free(ModeInfo *mi)