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