ftp://ftp.krokus.ru/pub/OpenBSD/distfiles/xscreensaver-4.22.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 #include <X11/Intrinsic.h>
16
17 extern XtAppContext app;
18
19 #define PROGCLASS         "BlinkBox"
20 #define HACK_INIT         init_ball
21 #define HACK_DRAW         draw_ball
22 #define HACK_RESHAPE  reshape_ball
23 #define sws_opts          xlockmore_opts
24 #define MAX_COUNT 20
25 #define ALPHA_AMT 0.05
26
27 /* this should be between 1 and 8 */
28 #define DEF_WH       "2"
29 #define DEF_DISSOLVE "False"
30 #define DEF_FADE     "True"
31 #define DEF_BLUR     "True"
32
33 #define DEFAULTS        "*delay:        30000            \n" \
34                         "*wireframe:    False            \n" \
35
36 #undef countof
37 #define countof(x) (sizeof((x))/sizeof((*x)))
38
39 #include "xlockmore.h"
40 #include "sphere.h"
41 #include <ctype.h>
42
43 #ifdef USE_GL /* whole file */
44
45
46 #include <GL/glu.h>
47
48 typedef struct{
49   GLfloat x,y,z;
50 } Tdpos;
51
52 typedef struct{
53   int hit;
54   Tdpos pos;
55   int counter;
56   GLfloat color[3];
57   GLfloat rot[4];
58   int des_count;
59   int alpha_count;
60 }Side;
61
62 struct Bounding_box {
63   Tdpos top;
64   Tdpos bottom;
65 } bbox = {{14,14,20},{-14,-14,-20}};
66
67 struct Ball {
68   GLfloat x;
69   GLfloat y;
70   GLfloat z;
71   int d;
72 } ball = {0,0,0,1};
73
74 struct {
75   GLfloat wh; /*width Height*/
76   GLfloat d; /*depth*/
77 } bscale = {1, 0.25};
78
79 static GLuint ballList;
80 static GLuint boxList;
81 Tdpos mo = { 1.0, 1.0, 1.0};  /*motion*/
82 Tdpos moh= {-1.0,-1.5,-1.5}; /*hold motion value*/
83
84 Tdpos bpos= {1.0, 1.0, 1.0};
85
86 /*sides*/
87 static Side lside = {0, {0, 0, 0,}, MAX_COUNT,  {1.0, 0.0, 0.0},{90,0,1,0},1,1};/*Red*/
88 static Side rside = {0, {0, 0, 0,}, MAX_COUNT,  {0.0, 1.0, 0.0},{90,0,1,0},1,1};/*Green*/
89 static Side tside = {0, {0, 0, 0,}, MAX_COUNT,  {0.0, 0.0, 1.0},{90,1,0,0},1,1};/*Blue*/
90 static Side bside = {0, {0, 0, 0,}, MAX_COUNT,  {1.0, 0.5, 0.0},{90,1,0,0},1,1};/*Orange*/
91 static Side fside = {0, {0, 0, 0,}, MAX_COUNT,  {1.0, 1.0, 0.0},{90,0,0,1},1,1};/*Yellow*/
92 static Side aside = {0, {0, 0, 0,}, MAX_COUNT,  {0.5, 0.0, 1.0},{90,0,0,1},1,1};/*Purple*/
93 Side *sp;
94
95 /* lights */
96 static float LightDiffuse[]=   { 1.0f, 1.0f, 1.0f, 1.0f };
97 static float LightPosition[]=  { 20.0f, 100.0f, 20.0f, 1.0f };
98
99 static Bool do_dissolve;
100 static Bool do_fade;
101 static Bool do_blur;
102 static GLfloat des_amt   = 1;
103
104 static XrmOptionDescRec opts[] = {
105   { "-boxsize",  ".boxsize",  XrmoptionSepArg, 0      },
106   { "-dissolve", ".dissolve", XrmoptionNoArg, "True"  },
107   { "+dissolve", ".dissolve", XrmoptionNoArg, "False" },
108   { "-fade",     ".fade",     XrmoptionNoArg, "True"  },
109   { "+fade",     ".fade",     XrmoptionNoArg, "False" },
110   { "-blur",     ".blur",     XrmoptionNoArg, "True"  },
111   { "+blur",     ".blur",     XrmoptionNoArg, "False" }
112
113 };
114
115 static argtype vars[] = {
116   {&bscale.wh,   "boxsize",   "Boxsize",  DEF_WH,       t_Float},
117   {&do_dissolve, "dissolve",  "Dissolve", DEF_DISSOLVE, t_Bool},
118   {&do_fade,     "fade",      "Fade",     DEF_FADE,     t_Bool},
119   {&do_blur,     "blur",      "Blur",     DEF_BLUR,     t_Bool},
120 };
121
122 ModeSpecOpt sws_opts = {countof(opts), opts, countof(vars), vars, NULL};
123
124 void
125 swap(GLfloat *a, GLfloat *b)
126 {
127   GLfloat t = *a;
128   *a = *b;
129   *b = t;
130 }
131
132 float
133 get_rand(void)
134 {
135   GLfloat j = 1+(random() % 2);
136   return (j);
137 }
138
139 void
140 swap_mov(GLfloat *a, GLfloat *b)
141 {
142   int j;
143   swap(a,b);
144   j = get_rand();
145   if (*a < 0)
146     *a = (j *= -1);
147   else
148     *a = j;
149 }
150
151 void
152 cp_b_pos(Tdpos *s_pos){
153   s_pos->x = ball.x;
154   s_pos->y = ball.y;
155   s_pos->z = ball.z;
156 }
157
158 void
159 hit_side(void)
160 {
161   if ((ball.x - ball.d) <= bbox.bottom.x){
162     lside.hit = 1;
163     lside.counter   = MAX_COUNT;
164     lside.des_count = 1;
165     lside.alpha_count = 0;
166     cp_b_pos(&lside.pos);
167     swap_mov(&mo.x,&moh.x);
168   }else
169   if ((ball.x + ball.d) >= bbox.top.x){
170     rside.hit = 1;
171     rside.counter = MAX_COUNT;
172     rside.des_count = 1;
173     rside.alpha_count = 0;
174     cp_b_pos(&rside.pos);
175     swap_mov(&mo.x,&moh.x);
176   }
177 }
178
179 void
180 hit_top_bottom(void)
181 {
182   if ((ball.y - ball.d) <= bbox.bottom.y){
183     bside.hit = 1;
184     bside.counter = MAX_COUNT;
185     bside.des_count = 1;
186     bside.alpha_count = 0;
187     cp_b_pos(&bside.pos);
188     swap_mov(&mo.y,&moh.y);
189   }else
190   if ((ball.y + ball.d) >= bbox.top.y){
191     tside.hit = 1;
192     tside.counter = MAX_COUNT;
193     tside.des_count = 1;
194     tside.alpha_count = 0;
195     cp_b_pos(&tside.pos);
196     swap_mov(&mo.y,&moh.y);
197   }
198 }
199
200 void
201 hit_front_back(void)
202 {
203   if ((ball.z - ball.d) <= bbox.bottom.z){
204     aside.hit = 1;
205     aside.counter = MAX_COUNT;
206     aside.des_count = 1;
207     aside.alpha_count = 0;
208     cp_b_pos(&aside.pos);
209     swap_mov(&mo.z,&moh.z);
210   }else
211   if((ball.z + ball.d) >= bbox.top.z){
212     fside.hit = 1;
213     fside.counter = MAX_COUNT;
214     fside.des_count = 1;
215     fside.alpha_count = 0;
216     cp_b_pos(&fside.pos);
217     swap_mov(&mo.z,&moh.z);
218   }
219 }
220
221 void
222 reshape_ball (ModeInfo *mi, int width, int height)
223 {
224   GLfloat h = (GLfloat) height / (GLfloat) width;
225
226   glViewport (0, 0, (GLint) width, (GLint) height);
227   glMatrixMode(GL_PROJECTION);
228   glLoadIdentity();
229   gluPerspective (30.0, 1/h, 1.0, 100.0);
230
231   glMatrixMode(GL_MODELVIEW);
232   glLoadIdentity();
233   gluLookAt( 0.0, 0.0, 40.0,
234              0.0, 0.0, 0.0,
235              0.0, 2.0,  10.0);
236
237 }
238
239 void
240 unit_cube(int wire)
241 {
242   glBegin((wire)?GL_LINE_LOOP:GL_QUADS);
243   glNormal3f( 0.0f, -1.0f, 0.0f);
244   glVertex3f(-1.0f, -1.0f, -1.0f);
245   glVertex3f( 1.0f, -1.0f, -1.0f);
246   glVertex3f( 1.0f, -1.0f,  1.0f);
247   glVertex3f(-1.0f, -1.0f,  1.0f);
248   glNormal3f( 0.0f,  0.0f,  1.0f);
249   glVertex3f(-1.0f, -1.0f,  1.0f);
250   glVertex3f( 1.0f, -1.0f,  1.0f);
251   glVertex3f( 1.0f,  1.0f,  1.0f);
252   glVertex3f(-1.0f,  1.0f,  1.0f);
253   glNormal3f( 0.0f,  0.0f, -1.0f);
254   glVertex3f(-1.0f, -1.0f, -1.0f);
255   glVertex3f(-1.0f,  1.0f, -1.0f);
256   glVertex3f( 1.0f,  1.0f, -1.0f);
257   glVertex3f( 1.0f, -1.0f, -1.0f);
258   glNormal3f( 1.0f,  0.0f,  0.0f);
259   glVertex3f( 1.0f, -1.0f, -1.0f);
260   glVertex3f( 1.0f,  1.0f, -1.0f);
261   glVertex3f( 1.0f,  1.0f,  1.0f);
262   glVertex3f( 1.0f, -1.0f,  1.0f);
263   glNormal3f( -1.0f, 0.0f,  0.0f);
264   glVertex3f(-1.0f, -1.0f, -1.0f);
265   glVertex3f(-1.0f, -1.0f,  1.0f);
266   glVertex3f(-1.0f,  1.0f,  1.0f);
267   glVertex3f(-1.0f,  1.0f, -1.0f);
268   glNormal3f( 1.0f,  1.0f,  0.0f);
269   glVertex3f(-1.0f,  1.0f, -1.0f);
270   glVertex3f(-1.0f,  1.0f,  1.0f);
271   glVertex3f( 1.0f,  1.0f,  1.0f);
272   glVertex3f( 1.0f,  1.0f, -1.0f);
273   glEnd();
274 }
275
276 void
277 init_ball (ModeInfo *mi)
278 {
279   #define SPHERE_SLICES 12  /* how densely to render spheres */
280   #define SPHERE_STACKS 16
281   int wire = MI_IS_WIREFRAME(mi);
282
283   sp = malloc(sizeof(*sp));
284   if(sp == NULL){
285     fprintf(stderr,"Could not allocate memory\n");
286     exit(1);
287   }
288   if( (bscale.wh < 1) ||
289       (bscale.wh > 8) ) {
290     fprintf(stderr,"Boxsize out of range. Using default\n");
291     bscale.wh = 2;
292   }
293   if (do_dissolve){
294     des_amt = bscale.wh / MAX_COUNT;
295   }
296   init_GL(mi);
297   reshape_ball(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
298   ballList = glGenLists(1);
299   glNewList(ballList, GL_COMPILE);
300   unit_sphere (SPHERE_STACKS, SPHERE_SLICES, wire);
301   glEndList ();
302
303   boxList = glGenLists(1);
304   glNewList(boxList, GL_COMPILE);
305   unit_cube(wire);
306   glEndList();
307
308   if (wire) return;
309
310   glEnable(GL_COLOR_MATERIAL);
311   glShadeModel(GL_SMOOTH);
312   glClearColor(0.0f, 0.0f, 0.0f, 0.5f);
313   glClearDepth(1.0f);
314   glEnable(GL_DEPTH_TEST);
315   glDepthFunc(GL_LEQUAL);
316   glEnable(GL_LIGHTING);
317   glClearDepth(1);
318   glLightfv(GL_LIGHT1, GL_DIFFUSE, LightDiffuse);
319   glLightfv(GL_LIGHT1, GL_POSITION,LightPosition);
320   glEnable(GL_LIGHT1);
321   if (do_fade || do_blur) {
322     glEnable(GL_BLEND);
323     glDisable(GL_DEPTH_TEST);
324   }
325 }
326
327 void
328 CheckBoxPos(GLfloat bot_x, GLfloat top_x, GLfloat bot_y, GLfloat top_y)
329 {
330   /*Make sure it's inside of the bounding box*/
331   bpos.x = ((bpos.x - bscale.wh) < bot_x) ? bot_x + bscale.wh : bpos.x;
332   bpos.x = ((bpos.x + bscale.wh) > top_x) ? top_x - bscale.wh : bpos.x;
333   bpos.y = ((bpos.y - bscale.wh) < bot_y) ? bot_y + bscale.wh : bpos.y;
334   bpos.y = ((bpos.y + bscale.wh) > top_y) ? top_y - bscale.wh : bpos.y;
335 }
336
337 void
338 draw_ball (ModeInfo *mi)
339 {
340    Display *dpy = MI_DISPLAY(mi);
341    Window window = MI_WINDOW(mi);
342    int i = 0;
343    glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
344
345    hit_top_bottom();
346    hit_front_back();
347    hit_side();
348
349    glRotated(0.25,0,0,1);
350    glRotated(0.25,0,1,0);
351    glRotated(0.25,1,0,0);
352
353
354    glPushMatrix();
355    glScalef(0.5,0.5,0.5);
356
357    glColor3f(1,1,1);
358    glPushMatrix();
359
360    if (!do_blur || MI_IS_WIREFRAME(mi)) {
361      glTranslatef(ball.x += mo.x,
362                   ball.y += mo.y,
363                   ball.z += mo.z);
364
365      glScalef(2,2,2);
366      glCallList(ballList);
367
368    } else {
369
370 #    define blur_detail 24.0
371      float ball_alpha = 1 / blur_detail;
372
373      glBlendFunc(GL_SRC_ALPHA,GL_ONE);
374      glTranslatef(ball.x, ball.y, ball.z);
375    
376      for (i = 0; i < blur_detail; ++i) {
377        glTranslatef(mo.x / blur_detail,
378                     mo.y / blur_detail,
379                     mo.z / blur_detail);
380
381        /* comment the following line for quick but boring linear blur */
382        ball_alpha = sin((M_PI / blur_detail) * i) / blur_detail;
383      
384        glColor4f(1, 1, 1, ball_alpha);
385
386        glScalef(2, 2, 2);
387        glCallList(ballList);
388        glScalef(.5, .5, .5);
389      }
390      i = 0;
391    
392      ball.x += mo.x;
393      ball.y += mo.y;
394      ball.z += mo.z;
395    }
396    
397    glPopMatrix();
398
399    while(i < 6){
400     switch(i){
401       case 0:{
402                sp = &lside;
403                bpos.x = lside.pos.z*-1;
404                bpos.y = lside.pos.y;
405                bpos.z = bbox.bottom.x - bscale.d;
406                if (sp->hit)
407                 CheckBoxPos(bbox.bottom.z,bbox.top.z,bbox.bottom.y,bbox.top.y);
408                break;
409              }
410       case 1:{
411                sp = &rside;
412                bpos.x = rside.pos.z*-1;
413                bpos.y = rside.pos.y;
414                bpos.z = bbox.top.x + bscale.d;
415                if (sp->hit)
416                 CheckBoxPos(bbox.bottom.z,bbox.top.z,bbox.bottom.y,bbox.top.y);
417                break;
418              }
419       case 2:{
420                sp = &tside;
421                bpos.x = tside.pos.x;
422                bpos.y = tside.pos.z;
423                bpos.z = bbox.bottom.y - bscale.d;
424                if (sp->hit)
425                 CheckBoxPos(bbox.bottom.x,bbox.top.x,bbox.bottom.z,bbox.top.z);
426                break;
427              }
428       case 3:{
429                sp = &bside;
430                bpos.x = bside.pos.x;
431                bpos.y = bside.pos.z;
432                bpos.z = bbox.top.y + bscale.d;
433                if (sp->hit)
434                 CheckBoxPos(bbox.bottom.x,bbox.top.x,bbox.bottom.z,bbox.top.z);
435                break;
436              }
437       case 4:{
438                sp = &fside;
439                bpos.x = fside.pos.y;
440                bpos.y = fside.pos.x*-1;
441                bpos.z = bbox.top.z + bscale.d;
442                if (sp->hit)
443                 CheckBoxPos(bbox.bottom.y,bbox.top.y,bbox.bottom.x,bbox.top.x);
444                break;
445              }
446       case 5:{
447                sp = &aside;
448                bpos.x = aside.pos.y;
449                bpos.y = aside.pos.x*-1;
450                bpos.z = bbox.bottom.z + bscale.d;
451                if (sp->hit)
452                 CheckBoxPos(bbox.bottom.y,bbox.top.y,bbox.bottom.x,bbox.top.x);
453                break;
454              }
455     }
456     if(sp->hit){
457       if(do_fade){
458         glColor4f(sp->color[0],sp->color[1],sp->color[2],1-(ALPHA_AMT * sp->alpha_count));
459       }else{
460         glColor3fv(sp->color);
461       }
462       glBlendFunc(GL_SRC_ALPHA,GL_ONE);
463       glPushMatrix();
464       glRotatef(sp->rot[0],sp->rot[1],sp->rot[2],sp->rot[3]);
465       glTranslatef(bpos.x,bpos.y,bpos.z);
466       if (do_dissolve) {
467          glScalef(bscale.wh-(des_amt*sp->des_count),bscale.wh-(des_amt*sp->des_count),bscale.d);
468       }else{
469         glScalef(bscale.wh,bscale.wh,bscale.d);
470       }
471       glCallList(boxList);
472       glPopMatrix();
473       sp->counter--;
474       sp->des_count++;
475       sp->alpha_count++;
476       if(!sp->counter)
477       {
478         sp->hit = 0;
479       }
480     }
481     i++;
482   }
483
484
485    glPopMatrix();
486    glFinish();
487    glXSwapBuffers(dpy, window);
488
489 }
490
491 #endif /* USE_GL */