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