]> git.hungrycats.org Git - xscreensaver/blob - hacks/glx/blinkbox.c
From https://www.jwz.org/xscreensaver/xscreensaver-6.09.tar.gz
[xscreensaver] / hacks / glx / blinkbox.c
1 /* blinkbox, Copyright (c) 2003 Jeremy English <jenglish@myself.com>
2  *
3  * Permission to use, copy, modify, distribute, and sell this software and its
4  * documentation for any purpose is hereby granted without fee, provided that
5  * the above copyright notice appear in all copies and that both that
6  * copyright notice and this permission notice appear in supporting
7  * documentation.  No representations are made about the suitability of this
8  * software for any purpose.  It is provided "as is" without express or
9  * implied warranty.
10  */
11
12 /* motion blur added March 2005 by John Boero <jlboero@cs.uwm.edu>
13  */
14
15 #define DEFAULTS        "*delay:        30000            \n" \
16                         "*wireframe:    False            \n" \
17                         "*suppressRotationAnimation: True\n" \
18
19 # define release_ball 0
20 # define ball_handle_event xlockmore_no_events
21
22 #include "xlockmore.h"
23 #include "sphere.h"
24 #include <ctype.h>
25
26 #ifdef USE_GL /* whole file */
27
28 #define MAX_COUNT 20
29 #define ALPHA_AMT 0.05
30
31 /* this should be between 1 and 8 */
32 #define DEF_BOXSIZE  "2"
33 #define DEF_DISSOLVE "False"
34 #define DEF_FADE     "True"
35 #define DEF_BLUR     "True"
36
37
38 typedef struct{
39   GLfloat x,y,z;
40 } Tdpos;
41
42 typedef struct{
43   int hit;
44   Tdpos pos;
45   int counter;
46   GLfloat color[3];
47   GLfloat rot[4];
48   int des_count;
49   int alpha_count;
50 }Side;
51
52 struct Bounding_box {
53   Tdpos top;
54   Tdpos bottom;
55 };
56
57 struct Ball {
58   GLfloat x;
59   GLfloat y;
60   GLfloat z;
61   int d;
62 };
63
64 struct bscale {
65   GLfloat wh; /*width Height*/
66   GLfloat d; /*depth*/
67 };
68
69 static const struct Bounding_box bbox = {{14,14,20},{-14,-14,-20}};
70
71 typedef struct {
72   GLXContext *glx_context;
73
74   struct Ball ball;
75
76   struct bscale bscale;
77
78   Tdpos mo;  /*motion*/
79   Tdpos moh; /*hold motion value*/
80
81   Tdpos bpos;
82
83   GLuint ballList;
84   GLuint boxList;
85   GLfloat des_amt;
86
87   /*sides*/
88   Side lside;/*Red*/
89   Side rside;/*Green*/
90   Side tside;/*Blue*/
91   Side bside;/*Orange*/
92   Side fside;/*Yellow*/
93   Side aside;/*Purple*/
94   Side *sp;
95
96 } blinkboxstruct;
97
98 static blinkboxstruct *blinkbox = (blinkboxstruct *) NULL;
99
100
101 /* lights */
102 static const float LightDiffuse[]=   { 1.0f, 1.0f, 1.0f, 1.0f };
103 static const float LightPosition[]=  { 20.0f, 100.0f, 20.0f, 1.0f };
104
105 static Bool do_dissolve;
106 static Bool do_fade;
107 static Bool do_blur;
108 static float bscale_wh;
109
110 static XrmOptionDescRec opts[] = {
111   { "-boxsize",  ".boxsize",  XrmoptionSepArg, 0      },
112   { "-dissolve", ".dissolve", XrmoptionNoArg, "True"  },
113   { "+dissolve", ".dissolve", XrmoptionNoArg, "False" },
114   { "-fade",     ".fade",     XrmoptionNoArg, "True"  },
115   { "+fade",     ".fade",     XrmoptionNoArg, "False" },
116   { "-blur",     ".blur",     XrmoptionNoArg, "True"  },
117   { "+blur",     ".blur",     XrmoptionNoArg, "False" }
118
119 };
120
121 static argtype vars[] = {
122   {&bscale_wh,   "boxsize",   "Boxsize",  DEF_BOXSIZE,  t_Float},
123   {&do_dissolve, "dissolve",  "Dissolve", DEF_DISSOLVE, t_Bool},
124   {&do_fade,     "fade",      "Fade",     DEF_FADE,     t_Bool},
125   {&do_blur,     "blur",      "Blur",     DEF_BLUR,     t_Bool},
126 };
127
128 ENTRYPOINT ModeSpecOpt ball_opts = {countof(opts), opts, countof(vars), vars, NULL};
129
130 static void
131 swap(GLfloat *a, GLfloat *b)
132 {
133   GLfloat t = *a;
134   *a = *b;
135   *b = t;
136 }
137
138 static float
139 get_rand(void)
140 {
141   GLfloat j = 1+(random() % 2);
142   return (j);
143 }
144
145 static void
146 swap_mov(GLfloat *a, GLfloat *b)
147 {
148   int j;
149   swap(a,b);
150   j = get_rand();
151   if (*a < 0)
152     *a = j * -1;
153   else
154     *a = j;
155 }
156
157 static void
158 cp_b_pos(blinkboxstruct *bp, Tdpos *s_pos)
159 {
160   s_pos->x = bp->ball.x;
161   s_pos->y = bp->ball.y;
162   s_pos->z = bp->ball.z;
163 }
164
165 static void
166 hit_side(blinkboxstruct *bp)
167 {
168   if ((bp->ball.x - bp->ball.d) <= bbox.bottom.x){
169     bp->lside.hit = 1;
170     bp->lside.counter   = MAX_COUNT;
171     bp->lside.des_count = 1;
172     bp->lside.alpha_count = 0;
173     cp_b_pos(bp, &bp->lside.pos);
174     swap_mov(&bp->mo.x,&bp->moh.x);
175   }else
176   if ((bp->ball.x + bp->ball.d) >= bbox.top.x){
177     bp->rside.hit = 1;
178     bp->rside.counter = MAX_COUNT;
179     bp->rside.des_count = 1;
180     bp->rside.alpha_count = 0;
181     cp_b_pos(bp, &bp->rside.pos);
182     swap_mov(&bp->mo.x,&bp->moh.x);
183   }
184 }
185
186 static void
187 hit_top_bottom(blinkboxstruct *bp)
188 {
189   if ((bp->ball.y - bp->ball.d) <= bbox.bottom.y){
190     bp->bside.hit = 1;
191     bp->bside.counter = MAX_COUNT;
192     bp->bside.des_count = 1;
193     bp->bside.alpha_count = 0;
194     cp_b_pos(bp, &bp->bside.pos);
195     swap_mov(&bp->mo.y,&bp->moh.y);
196   }else
197   if ((bp->ball.y + bp->ball.d) >= bbox.top.y){
198     bp->tside.hit = 1;
199     bp->tside.counter = MAX_COUNT;
200     bp->tside.des_count = 1;
201     bp->tside.alpha_count = 0;
202     cp_b_pos(bp, &bp->tside.pos);
203     swap_mov(&bp->mo.y,&bp->moh.y);
204   }
205 }
206
207 static void
208 hit_front_back(blinkboxstruct *bp)
209 {
210   if ((bp->ball.z - bp->ball.d) <= bbox.bottom.z){
211     bp->aside.hit = 1;
212     bp->aside.counter = MAX_COUNT;
213     bp->aside.des_count = 1;
214     bp->aside.alpha_count = 0;
215     cp_b_pos(bp, &bp->aside.pos);
216     swap_mov(&bp->mo.z,&bp->moh.z);
217   }else
218   if((bp->ball.z + bp->ball.d) >= bbox.top.z){
219     bp->fside.hit = 1;
220     bp->fside.counter = MAX_COUNT;
221     bp->fside.des_count = 1;
222     bp->fside.alpha_count = 0;
223     cp_b_pos(bp, &bp->fside.pos);
224     swap_mov(&bp->mo.z,&bp->moh.z);
225   }
226 }
227
228 ENTRYPOINT void
229 reshape_ball (ModeInfo *mi, int width, int height)
230 {
231   GLfloat h = (GLfloat) height / (GLfloat) width;
232   int y = 0;
233
234   if (width > height * 5) {   /* tiny window: show middle */
235     height = width * 9/16;
236     y = -height/2;
237     h = height / (GLfloat) width;
238   }
239
240   glViewport (0, y, (GLint) width, (GLint) height);
241   glMatrixMode(GL_PROJECTION);
242   glLoadIdentity();
243   gluPerspective (30.0, 1/h, 1.0, 100.0);
244
245   glMatrixMode(GL_MODELVIEW);
246   glLoadIdentity();
247   gluLookAt( 0.0, 0.0, 40.0,
248              0.0, 0.0, 0.0,
249              0.0, 2.0,  10.0);
250 }
251
252 static void
253 unit_cube(int wire)
254 {
255   glBegin((wire)?GL_LINE_LOOP:GL_QUADS);
256   glNormal3f( 0.0f, -1.0f, 0.0f);
257   glVertex3f(-1.0f, -1.0f, -1.0f);
258   glVertex3f( 1.0f, -1.0f, -1.0f);
259   glVertex3f( 1.0f, -1.0f,  1.0f);
260   glVertex3f(-1.0f, -1.0f,  1.0f);
261   glNormal3f( 0.0f,  0.0f,  1.0f);
262   glVertex3f(-1.0f, -1.0f,  1.0f);
263   glVertex3f( 1.0f, -1.0f,  1.0f);
264   glVertex3f( 1.0f,  1.0f,  1.0f);
265   glVertex3f(-1.0f,  1.0f,  1.0f);
266   glNormal3f( 0.0f,  0.0f, -1.0f);
267   glVertex3f(-1.0f, -1.0f, -1.0f);
268   glVertex3f(-1.0f,  1.0f, -1.0f);
269   glVertex3f( 1.0f,  1.0f, -1.0f);
270   glVertex3f( 1.0f, -1.0f, -1.0f);
271   glNormal3f( 1.0f,  0.0f,  0.0f);
272   glVertex3f( 1.0f, -1.0f, -1.0f);
273   glVertex3f( 1.0f,  1.0f, -1.0f);
274   glVertex3f( 1.0f,  1.0f,  1.0f);
275   glVertex3f( 1.0f, -1.0f,  1.0f);
276   glNormal3f( -1.0f, 0.0f,  0.0f);
277   glVertex3f(-1.0f, -1.0f, -1.0f);
278   glVertex3f(-1.0f, -1.0f,  1.0f);
279   glVertex3f(-1.0f,  1.0f,  1.0f);
280   glVertex3f(-1.0f,  1.0f, -1.0f);
281   glNormal3f( 1.0f,  1.0f,  0.0f);
282   glVertex3f(-1.0f,  1.0f, -1.0f);
283   glVertex3f(-1.0f,  1.0f,  1.0f);
284   glVertex3f( 1.0f,  1.0f,  1.0f);
285   glVertex3f( 1.0f,  1.0f, -1.0f);
286   glEnd();
287 }
288
289 ENTRYPOINT void
290 init_ball (ModeInfo *mi)
291 {
292   int wire = MI_IS_WIREFRAME(mi);
293   blinkboxstruct *bp;
294   
295   MI_INIT (mi, blinkbox);
296   bp = &blinkbox[MI_SCREEN(mi)];
297
298   if ((bp->glx_context = init_GL(mi)) != NULL) {
299     reshape_ball(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
300     glDrawBuffer(GL_BACK);
301   }
302   else
303     MI_CLEARWINDOW(mi);
304
305   bp->ball.d = 1;
306   bp->bscale.wh = bscale_wh;
307   bp->bscale.d = 0.25;
308
309   bp->mo.x = 1;
310   bp->mo.y = 1;
311   bp->mo.z = 1;
312
313   bp->moh.x = -1.0;
314   bp->moh.y = -1.5;
315   bp->moh.z = -1.5;
316
317   bp->bpos.x = 1;
318   bp->bpos.y = 1;
319   bp->bpos.z = 1;
320
321   bp->des_amt = 1;
322
323   bp->lside.counter = MAX_COUNT;
324   bp->rside.counter = MAX_COUNT;
325   bp->tside.counter = MAX_COUNT;
326   bp->bside.counter = MAX_COUNT;
327   bp->fside.counter = MAX_COUNT;
328   bp->aside.counter = MAX_COUNT;
329
330   bp->lside.color[0] = 1;
331   bp->rside.color[1] = 1;
332   bp->tside.color[2] = 1;
333
334   bp->bside.color[0] = 1;
335   bp->bside.color[1] = 0.5;
336
337   bp->fside.color[0] = 1;
338   bp->fside.color[1] = 1;
339
340   bp->aside.color[0] = 0.5;
341   bp->aside.color[2] = 1;
342
343   bp->lside.rot[0] = 90;
344   bp->rside.rot[0] = 90;
345   bp->tside.rot[0] = 90;
346   bp->bside.rot[0] = 90;
347   bp->fside.rot[0] = 90;
348   bp->aside.rot[0] = 90;
349
350   bp->lside.rot[2] = 1;
351   bp->rside.rot[2] = 1;
352   bp->tside.rot[1] = 1;
353   bp->bside.rot[1] = 1;
354   bp->fside.rot[3] = 1;
355   bp->aside.rot[3] = 1;
356
357   bp->lside.des_count = 1;
358   bp->rside.des_count = 1;
359   bp->tside.des_count = 1;
360   bp->bside.des_count = 1;
361   bp->fside.des_count = 1;
362   bp->aside.des_count = 1;
363
364   bp->lside.alpha_count = 1;
365   bp->rside.alpha_count = 1;
366   bp->tside.alpha_count = 1;
367   bp->bside.alpha_count = 1;
368   bp->fside.alpha_count = 1;
369   bp->aside.alpha_count = 1;
370
371
372 #define SPHERE_SLICES 12  /* how densely to render spheres */
373 #define SPHERE_STACKS 16
374
375 /*  bp->sp = malloc(sizeof(*bp->sp));
376   if(bp->sp == NULL){
377     fprintf(stderr,"Could not allocate memory\n");
378     exit(1);
379   }*/
380   if( (bp->bscale.wh < 1) ||
381       (bp->bscale.wh > 8) ) {
382     fprintf(stderr,"Boxsize out of range. Using default\n");
383     bp->bscale.wh = 2;
384   }
385   if (do_dissolve){
386     bp->des_amt = bp->bscale.wh / MAX_COUNT;
387   }
388
389   reshape_ball(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
390   bp->ballList = glGenLists(1);
391   glNewList(bp->ballList, GL_COMPILE);
392   unit_sphere (SPHERE_STACKS, SPHERE_SLICES, wire);
393   glEndList ();
394
395   bp->boxList = glGenLists(1);
396   glNewList(bp->boxList, GL_COMPILE);
397   unit_cube(wire);
398   glEndList();
399
400   if (wire) return;
401
402   glEnable(GL_COLOR_MATERIAL);
403   glShadeModel(GL_SMOOTH);
404   glClearDepth(1.0f);
405   glEnable(GL_DEPTH_TEST);
406   glDepthFunc(GL_LEQUAL);
407   glEnable(GL_LIGHTING);
408   glClearDepth(1);
409   glLightfv(GL_LIGHT1, GL_DIFFUSE, LightDiffuse);
410   glLightfv(GL_LIGHT1, GL_POSITION,LightPosition);
411   glEnable(GL_LIGHT1);
412   if (do_fade || do_blur) {
413     glEnable(GL_BLEND);
414     glDisable(GL_DEPTH_TEST);
415   }
416 }
417
418 static void
419 CheckBoxPos(blinkboxstruct *bp, 
420             GLfloat bot_x, GLfloat top_x, GLfloat bot_y, GLfloat top_y)
421 {
422   /*Make sure it's inside of the bounding box*/
423   bp->bpos.x = ((bp->bpos.x - bp->bscale.wh) < bot_x) ? bot_x + bp->bscale.wh : bp->bpos.x;
424   bp->bpos.x = ((bp->bpos.x + bp->bscale.wh) > top_x) ? top_x - bp->bscale.wh : bp->bpos.x;
425   bp->bpos.y = ((bp->bpos.y - bp->bscale.wh) < bot_y) ? bot_y + bp->bscale.wh : bp->bpos.y;
426   bp->bpos.y = ((bp->bpos.y + bp->bscale.wh) > top_y) ? top_y - bp->bscale.wh : bp->bpos.y;
427 }
428
429 ENTRYPOINT void
430 draw_ball (ModeInfo *mi)
431 {
432    blinkboxstruct *bp = &blinkbox[MI_SCREEN(mi)];
433
434    Display *dpy = MI_DISPLAY(mi);
435    Window window = MI_WINDOW(mi);
436    int i = 0;
437
438    if (! bp->glx_context)
439      return;
440    mi->polygon_count = 0;
441    glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *bp->glx_context);
442
443    glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
444
445    hit_top_bottom(bp);
446    hit_front_back(bp);
447    hit_side(bp);
448
449    glRotated(0.25,0,0,1);
450    glRotated(0.25,0,1,0);
451    glRotated(0.25,1,0,0);
452
453
454    glPushMatrix();
455
456    {
457      GLfloat s = (MI_WIDTH(mi) < MI_HEIGHT(mi)
458                   ? MI_WIDTH(mi) / (GLfloat) MI_HEIGHT(mi)
459                   : 1);
460      s *= 0.5;
461      glScalef (s, s, s);
462    }
463
464    glColor3f(1,1,1);
465    glPushMatrix();
466
467    if (!do_blur || MI_IS_WIREFRAME(mi)) {
468      glTranslatef(bp->ball.x += bp->mo.x,
469                   bp->ball.y += bp->mo.y,
470                   bp->ball.z += bp->mo.z);
471
472      glScalef(2,2,2);
473      glCallList(bp->ballList);
474      mi->polygon_count += SPHERE_SLICES*SPHERE_STACKS;
475
476    } else {
477
478 #    define blur_detail 24.0
479      float ball_alpha = 1 / blur_detail;
480
481      glBlendFunc(GL_SRC_ALPHA,GL_ONE);
482      glTranslatef(bp->ball.x, bp->ball.y, bp->ball.z);
483    
484      for (i = 0; i < blur_detail; ++i) {
485        glTranslatef(bp->mo.x / blur_detail,
486                     bp->mo.y / blur_detail,
487                     bp->mo.z / blur_detail);
488
489        /* comment the following line for quick but boring linear blur */
490        ball_alpha = sin((M_PI / blur_detail) * i) / blur_detail;
491      
492        glColor4f(1, 1, 1, ball_alpha);
493
494        glScalef(2, 2, 2);
495        glCallList(bp->ballList);
496        mi->polygon_count += SPHERE_SLICES*SPHERE_STACKS;
497        glScalef(.5, .5, .5);
498      }
499      i = 0;
500    
501      bp->ball.x += bp->mo.x;
502      bp->ball.y += bp->mo.y;
503      bp->ball.z += bp->mo.z;
504    }
505    
506    glPopMatrix();
507
508    while(i < 6){
509     switch(i){
510       case 0:{
511                bp->sp = &bp->lside;
512                bp->bpos.x = bp->lside.pos.z*-1;
513                bp->bpos.y = bp->lside.pos.y;
514                bp->bpos.z = bbox.bottom.x - bp->bscale.d;
515                if (bp->sp->hit)
516                 CheckBoxPos(bp, bbox.bottom.z,bbox.top.z,bbox.bottom.y,bbox.top.y);
517                break;
518              }
519       case 1:{
520                bp->sp = &bp->rside;
521                bp->bpos.x = bp->rside.pos.z*-1;
522                bp->bpos.y = bp->rside.pos.y;
523                bp->bpos.z = bbox.top.x + bp->bscale.d;
524                if (bp->sp->hit)
525                 CheckBoxPos(bp, bbox.bottom.z,bbox.top.z,bbox.bottom.y,bbox.top.y);
526                break;
527              }
528       case 2:{
529                bp->sp = &bp->tside;
530                bp->bpos.x = bp->tside.pos.x;
531                bp->bpos.y = bp->tside.pos.z;
532                bp->bpos.z = bbox.bottom.y - bp->bscale.d;
533                if (bp->sp->hit)
534                 CheckBoxPos(bp, bbox.bottom.x,bbox.top.x,bbox.bottom.z,bbox.top.z);
535                break;
536              }
537       case 3:{
538                bp->sp = &bp->bside;
539                bp->bpos.x = bp->bside.pos.x;
540                bp->bpos.y = bp->bside.pos.z;
541                bp->bpos.z = bbox.top.y + bp->bscale.d;
542                if (bp->sp->hit)
543                 CheckBoxPos(bp, bbox.bottom.x,bbox.top.x,bbox.bottom.z,bbox.top.z);
544                break;
545              }
546       case 4:{
547                bp->sp = &bp->fside;
548                bp->bpos.x = bp->fside.pos.y;
549                bp->bpos.y = bp->fside.pos.x*-1;
550                bp->bpos.z = bbox.top.z + bp->bscale.d;
551                if (bp->sp->hit)
552                 CheckBoxPos(bp, bbox.bottom.y,bbox.top.y,bbox.bottom.x,bbox.top.x);
553                break;
554              }
555       case 5:{
556                bp->sp = &bp->aside;
557                bp->bpos.x = bp->aside.pos.y;
558                bp->bpos.y = bp->aside.pos.x*-1;
559                bp->bpos.z = bbox.bottom.z + bp->bscale.d;
560                if (bp->sp->hit)
561                 CheckBoxPos(bp, bbox.bottom.y,bbox.top.y,bbox.bottom.x,bbox.top.x);
562                break;
563              }
564     }
565     if(bp->sp->hit){
566       if(do_fade){
567         glColor4f(bp->sp->color[0],bp->sp->color[1],bp->sp->color[2],1-(ALPHA_AMT * bp->sp->alpha_count));
568       }else{
569         glColor3fv(bp->sp->color);
570       }
571       glBlendFunc(GL_SRC_ALPHA,GL_ONE);
572       glPushMatrix();
573       glRotatef(bp->sp->rot[0],bp->sp->rot[1],bp->sp->rot[2],bp->sp->rot[3]);
574       glTranslatef(bp->bpos.x,bp->bpos.y,bp->bpos.z);
575       if (do_dissolve) {
576          glScalef(bp->bscale.wh-(bp->des_amt*bp->sp->des_count),bp->bscale.wh-(bp->des_amt*bp->sp->des_count),bp->bscale.d);
577       }else{
578         glScalef(bp->bscale.wh,bp->bscale.wh,bp->bscale.d);
579       }
580       glCallList(bp->boxList);
581       mi->polygon_count += 6;
582       glPopMatrix();
583       bp->sp->counter--;
584       bp->sp->des_count++;
585       bp->sp->alpha_count++;
586       if(!bp->sp->counter)
587       {
588         bp->sp->hit = 0;
589       }
590     }
591     i++;
592   }
593
594
595    glPopMatrix();
596   if (mi->fps_p) do_fps (mi);
597    glFinish();
598    glXSwapBuffers(dpy, window);
599
600 }
601
602 ENTRYPOINT void
603 free_ball (ModeInfo *mi)
604 {
605    blinkboxstruct *bp = &blinkbox[MI_SCREEN(mi)];
606    if (!bp->glx_context) return;
607    glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *bp->glx_context);
608    if (glIsList(bp->ballList)) glDeleteLists(bp->ballList, 1);
609    if (glIsList(bp->boxList))  glDeleteLists(bp->boxList, 1);
610 }
611
612 XSCREENSAVER_MODULE_2 ("BlinkBox", blinkbox, ball)
613
614 #endif /* USE_GL */