21bb1be90f4ee5bf3384caa4162176cfa7dbe602
[xscreensaver] / hacks / glx / antinspect.c
1 /*
2  * Permission to use, copy, modify, and distribute this software and its
3  * documentation for any purpose and without fee is hereby granted,
4  * provided that the above copyright notice appear in all copies and that
5  * both that copyright notice and this permission notice appear in
6  * supporting documentation.
7  *
8  * This file is provided AS IS with no warranties of any kind.  The author
9  * shall have no liability with respect to the infringement of copyrights,
10  * trade secrets or any patents by this file or any part thereof.  In no
11  * event will the author be liable for any lost revenue or profits or
12  * other special, indirect and consequential damages.
13  *
14  * Copyright 2004 Blair Tennessy
15  * tennessy@cs.ubc.ca
16  */
17
18 #ifdef STANDALONE
19 #define DEFAULTS            "*delay:   20000   \n" \
20                             "*showFPS: False   \n"
21
22 # define refresh_antinspect 0
23 #include "xlockmore.h"
24 #else
25 #include "xlock.h"
26 #endif
27
28 #include "gltrackball.h"
29
30 #define DEF_SHADOWS  "True"
31
32 static int shadows;
33
34 static XrmOptionDescRec opts[] = {
35   {"-shadows", ".antinspect.shadows", XrmoptionNoArg, "on"},
36   {"+shadows", ".antinspect.shadows", XrmoptionNoArg, "off"}
37 };
38
39 static argtype vars[] = {
40   {&shadows, "shadows", "Shadows", DEF_SHADOWS, t_Bool}
41 };
42
43 static OptionStruct desc[] = {
44   {"-/+shadows", "turn on/off ant shadows"}
45 };
46
47 ENTRYPOINT ModeSpecOpt antinspect_opts = {sizeof opts / sizeof opts[0], 
48                             opts, 
49                             sizeof vars / sizeof vars[0], 
50                             vars, 
51                             desc};
52
53 #ifdef USE_MODULES
54 ModStruct   antinspect_description =
55   {"antinspect", "init_antinspect", "draw_antinspect", "release_antinspect",
56    "draw_antinspect", "change_antinspect", (char *) NULL, &antinspect_opts,
57    1000, 1, 1, 1, 4, 1.0, "",
58    "draws some ants", 0, NULL};
59 #endif
60
61 #define Scale4Window               0.3
62 #define Scale4Iconic               0.4
63
64 #define sqr(A)                     ((A)*(A))
65
66 #ifndef Pi
67 #define Pi                         M_PI
68 #endif
69
70 #define ObjAntinspectStrip 0
71 #define ObjAntBody      1
72 #define MaxObj          2
73
74 /*************************************************************************/
75
76 typedef struct {
77   GLint       WindH, WindW;
78   GLfloat     step;
79   GLfloat     ant_position;
80   GLXContext *glx_context;
81   trackball_state *trackball;
82   Bool        button_down_p;
83   int linewidth;
84   float ant_step;
85
86 } antinspectstruct;
87
88 static const float front_shininess[] = {60.0};
89 static const float front_specular[] =  {0.7, 0.7, 0.7, 1.0};
90 static const float ambient[] = {0.0, 0.0, 0.0, 1.0};
91 static const float diffuse[] = {1.0, 1.0, 1.0, 1.0};
92 static float position0[] = {0.0, 3.0, 0.0, 1.0};
93 static const float position1[] = {-1.0, -3.0, 1.0, 0.0};
94 static const float lmodel_ambient[] = {0.5, 0.5, 0.5, 1.0};
95 static const float lmodel_twoside[] = {GL_TRUE};
96
97 static const float MaterialRed[] =     {0.6, 0.0, 0.0, 1.0};
98 static const float MaterialOrange[] =  {1.0, 0.69, 0.00, 1.0};
99 static const float MaterialGray[] =    {0.2, 0.2, 0.2, 1.0};
100 static const float MaterialBlack[] =   {0.1, 0.1, 0.1, 0.4};
101 static const float MaterialShadow[] =   {0.3, 0.3, 0.3, 0.3};
102 static const float MaterialGray5[] =   {0.5, 0.5, 0.5, 0.3};
103 static const float MaterialGray6[] =   {0.6, 0.6, 0.6, 1.0};
104
105 static antinspectstruct *antinspect = (antinspectstruct *) NULL;
106
107 #define NUM_SCENES      2
108
109 enum {X, Y, Z, W};
110 enum {A, B, C, D};
111
112 /* create a matrix that will project the desired shadow */
113 static void shadowmatrix(GLfloat shadowMat[4][4],
114                          const GLfloat groundplane[4],
115                          const GLfloat lightpos[4]) 
116 {
117   GLfloat dot;
118
119   /* find dot product between light position vector and ground plane normal */
120   dot = groundplane[X] * lightpos[X] +
121         groundplane[Y] * lightpos[Y] +
122         groundplane[Z] * lightpos[Z] +
123         groundplane[W] * lightpos[W];
124
125   shadowMat[0][0] = dot - lightpos[X] * groundplane[X];
126   shadowMat[1][0] = 0.f - lightpos[X] * groundplane[Y];
127   shadowMat[2][0] = 0.f - lightpos[X] * groundplane[Z];
128   shadowMat[3][0] = 0.f - lightpos[X] * groundplane[W];
129
130   shadowMat[X][1] = 0.f - lightpos[Y] * groundplane[X];
131   shadowMat[1][1] = dot - lightpos[Y] * groundplane[Y];
132   shadowMat[2][1] = 0.f - lightpos[Y] * groundplane[Z];
133   shadowMat[3][1] = 0.f - lightpos[Y] * groundplane[W];
134
135   shadowMat[X][2] = 0.f - lightpos[Z] * groundplane[X];
136   shadowMat[1][2] = 0.f - lightpos[Z] * groundplane[Y];
137   shadowMat[2][2] = dot - lightpos[Z] * groundplane[Z];
138   shadowMat[3][2] = 0.f - lightpos[Z] * groundplane[W];
139
140   shadowMat[X][3] = 0.f - lightpos[W] * groundplane[X];
141   shadowMat[1][3] = 0.f - lightpos[W] * groundplane[Y];
142   shadowMat[2][3] = 0.f - lightpos[W] * groundplane[Z];
143   shadowMat[3][3] = dot - lightpos[W] * groundplane[W];
144 }
145
146 static const GLfloat ground[4] = {0.0, 1.0, 0.0, -0.00001};
147
148 /* simple filled sphere */
149 static Bool mySphere(float radius) 
150 {
151   GLUquadricObj *quadObj;
152
153   if((quadObj = gluNewQuadric()) == 0)
154     return False;
155   gluQuadricDrawStyle(quadObj, (GLenum) GLU_FILL);
156   gluSphere(quadObj, radius, 16, 16);
157   gluDeleteQuadric(quadObj);
158
159   return True;
160 }
161
162 /* caged sphere */
163 static Bool mySphere2(float radius) 
164 {
165   GLUquadricObj *quadObj;
166
167   if((quadObj = gluNewQuadric()) == 0)
168     return False;
169   gluQuadricDrawStyle(quadObj, (GLenum) GLU_LINE);/*GLU_SILHOUETTE);*/
170   gluSphere(quadObj, radius, 16, 8);
171   gluDeleteQuadric(quadObj);
172
173   return True;
174 }
175
176 /* null cone */
177 static Bool myCone2(float radius) 
178
179   return True; 
180 }
181
182 /* draw an ant */
183 static Bool draw_antinspect_ant(ModeInfo *mi, antinspectstruct * mp, 
184                                 const float *Material, int mono,
185                                 Bool (*sphere)(float), Bool (*cone)(float)) 
186 {
187   float       cos1 = cos(mp->ant_step);
188   float       cos2 = cos(mp->ant_step + 2 * Pi / 3);
189   float       cos3 = cos(mp->ant_step + 4 * Pi / 3);
190   float       sin1 = sin(mp->ant_step);
191   float       sin2 = sin(mp->ant_step + 2 * Pi / 3);
192   float       sin3 = sin(mp->ant_step + 4 * Pi / 3);
193   
194   if (mono)
195     glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialGray5);
196   else
197     glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, Material);
198   glEnable(GL_CULL_FACE);
199   glPushMatrix();
200   glScalef(1, 1.3, 1);
201   if (!((*sphere)(0.18)))
202     return False;
203   glScalef(1, 1 / 1.3, 1);
204   glTranslatef(0.00, 0.30, 0.00);
205   if (!((*sphere)(0.2)))
206     return False;
207   
208   glTranslatef(-0.05, 0.17, 0.05);
209   glRotatef(-90, 1, 0, 0);
210   glRotatef(-25, 0, 1, 0);
211   if (!((*cone)(0.05)))
212     return False;
213   glTranslatef(0.00, 0.10, 0.00);
214   if (!((*cone)(0.05)))
215     return False;
216   glRotatef(25, 0, 1, 0);
217   glRotatef(90, 1, 0, 0);
218   
219   glScalef(1, 1.3, 1);
220   glTranslatef(0.15, -0.65, 0.05);
221   if (!((*sphere)(0.25)))
222     return False;
223   glScalef(1, 1 / 1.3, 1);
224   glPopMatrix();
225   glDisable(GL_CULL_FACE);
226   
227   glDisable(GL_LIGHTING);
228   
229   /* ANTENNAS */
230   glBegin(GL_LINES);
231   if (mono)
232     glColor3fv(MaterialGray5);
233   else
234     glColor3fv(Material);
235   glVertex3f(0.00, 0.30, 0.00);
236   glColor3fv(MaterialGray);
237   glVertex3f(0.40, 0.70, 0.40);
238   mi->polygon_count++;
239   if (mono)
240     glColor3fv(MaterialGray5);
241   else
242     glColor3fv(Material);
243   glVertex3f(0.00, 0.30, 0.00);
244   glColor3fv(MaterialGray);
245   glVertex3f(0.40, 0.70, -0.40);
246   mi->polygon_count++;
247   glEnd();
248   glBegin(GL_POINTS);
249   if (mono)
250     glColor3fv(MaterialGray6);
251   else
252     glColor3fv(Material);
253   glVertex3f(0.40, 0.70, 0.40);
254   mi->polygon_count++;
255   glVertex3f(0.40, 0.70, -0.40);
256   mi->polygon_count++;
257   glEnd();
258   
259   /* LEFT-FRONT ARM */
260   glBegin(GL_LINE_STRIP);
261   if (mono)
262     glColor3fv(MaterialGray5);
263   else
264     glColor3fv(Material);
265   glVertex3f(0.00, 0.05, 0.18);
266   glVertex3f(0.35 + 0.05 * cos1, 0.15, 0.25);
267   mi->polygon_count++;
268   glColor3fv(MaterialGray);
269   glVertex3f(-0.20 + 0.05 * cos1, 0.25 + 0.1 * sin1, 0.45);
270   mi->polygon_count++;
271   glEnd();
272   
273   /* LEFT-CENTER ARM */
274   glBegin(GL_LINE_STRIP);
275   if (mono)
276     glColor3fv(MaterialGray5);
277   else
278     glColor3fv(Material);
279   glVertex3f(0.00, 0.00, 0.18);
280   glVertex3f(0.35 + 0.05 * cos2, 0.00, 0.25);
281   mi->polygon_count++;
282   glColor3fv(MaterialGray);
283   glVertex3f(-0.20 + 0.05 * cos2, 0.00 + 0.1 * sin2, 0.45);
284   mi->polygon_count++;
285   glEnd();
286   mi->polygon_count++;
287   
288   /* LEFT-BACK ARM */
289   glBegin(GL_LINE_STRIP);
290   if (mono)
291     glColor3fv(MaterialGray5);
292   else
293     glColor3fv(Material);
294   glVertex3f(0.00, -0.05, 0.18);
295   glVertex3f(0.35 + 0.05 * cos3, -0.15, 0.25);
296   mi->polygon_count++;
297   glColor3fv(MaterialGray);
298   glVertex3f(-0.20 + 0.05 * cos3, -0.25 + 0.1 * sin3, 0.45);
299   mi->polygon_count++;
300   glEnd();
301   
302   /* RIGHT-FRONT ARM */
303   glBegin(GL_LINE_STRIP);
304   if (mono)
305     glColor3fv(MaterialGray5);
306   else
307     glColor3fv(Material);
308   glVertex3f(0.00, 0.05, -0.18);
309   glVertex3f(0.35 - 0.05 * sin1, 0.15, -0.25);
310   mi->polygon_count++;
311   glColor3fv(MaterialGray);
312   glVertex3f(-0.20 - 0.05 * sin1, 0.25 + 0.1 * cos1, -0.45);
313   mi->polygon_count++;
314   glEnd();
315   
316   /* RIGHT-CENTER ARM */
317   glBegin(GL_LINE_STRIP);
318   if (mono)
319     glColor3fv(MaterialGray5);
320   else
321     glColor3fv(Material);
322   glVertex3f(0.00, 0.00, -0.18);
323   glVertex3f(0.35 - 0.05 * sin2, 0.00, -0.25);
324   mi->polygon_count++;
325   glColor3fv(MaterialGray);
326   glVertex3f(-0.20 - 0.05 * sin2, 0.00 + 0.1 * cos2, -0.45);
327   mi->polygon_count++;
328   glEnd();
329   
330   /* RIGHT-BACK ARM */
331   glBegin(GL_LINE_STRIP);
332   if (mono)
333     glColor3fv(MaterialGray5);
334   else
335     glColor3fv(Material);
336   glVertex3f(0.00, -0.05, -0.18);
337   glVertex3f(0.35 - 0.05 * sin3, -0.15, -0.25);
338   mi->polygon_count++;
339   glColor3fv(MaterialGray);
340   glVertex3f(-0.20 - 0.05 * sin3, -0.25 + 0.1 * cos3, -0.45);
341   mi->polygon_count++;
342   glEnd();
343     
344   glEnable(GL_LIGHTING);
345   
346   return True;
347 }
348
349 /* only works with 3 right now */
350 #define ANTCOUNT 3
351
352 static const float MaterialBen[4] = {0.25, 0.30, 0.46, 1.0};
353
354 static const float* antmaterial[ANTCOUNT] = 
355   {MaterialRed, MaterialBen, MaterialOrange};
356 static double antposition[ANTCOUNT] = {0.0, 120.0, 240.0};
357 static const double antvelocity[ANTCOUNT] = {0.3, 0.3, 0.3};
358 static const double antsphere[ANTCOUNT] = {1.2, 1.2, 1.2};
359
360 /* permutations */
361 static const double antorder[6][ANTCOUNT] = {{0, 1, 2},
362                                        {0, 2, 1},
363                                        {2, 0, 1},
364                                        {2, 1, 0},
365                                        {1, 2, 0},
366                                        {1, 0, 2}};
367
368 /* draw the scene */
369 static Bool draw_antinspect_strip(ModeInfo * mi) 
370 {
371   antinspectstruct *mp = &antinspect[MI_SCREEN(mi)];
372   int         i, j;
373   int         mono = MI_IS_MONO(mi);
374
375   int ro = (((int)antposition[1])/(360/(2*ANTCOUNT))) % (2*ANTCOUNT);
376
377   glEnable(GL_TEXTURE_2D);
378   position0[1] = 9.6;
379   glLightfv(GL_LIGHT0, GL_POSITION, position0);
380
381   glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialGray5);
382   glRotatef(-30.0, 0.0, 1.0, 0.0);
383
384   glDisable(GL_TEXTURE_2D);
385   glDisable(GL_BLEND);
386
387   /* render ground plane */
388   glBegin(GL_TRIANGLES);
389   glColor4fv(MaterialShadow);
390   glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialBlack);
391   glNormal3f(0.0, 1.0, 0.0);
392
393   /* middle tri */
394   glVertex3f(0.0, 0.0, -1.0);
395   glVertex3f(-sqrt(3.0)/2.0, 0.0, 0.5);
396   glVertex3f(sqrt(3.0)/2.0, 0.0, 0.5);
397   mi->polygon_count++;
398   glEnd();
399
400   /* rotate */
401   for(i = 0; i < 3; ++i) {
402     glRotatef(120.0, 0.0, 1.0, 0.0);
403     glBegin(GL_TRIANGLES);
404     glVertex3f(0.0, 0.0, 1.0 + 3.0);
405     glVertex3f(sqrt(3.0)/2.0, 0.0, -0.5 + 3.0);
406     glVertex3f(-sqrt(3.0)/2.0, 0.0, -0.5 + 3.0);
407     mi->polygon_count++;
408     glEnd();
409   }
410
411   /* first render shadows -- no depth required */
412   if(shadows) {
413     GLfloat m[4][4];
414     shadowmatrix(m, ground, position0);
415     
416     glColor4fv(MaterialShadow);
417     glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialShadow);
418     
419     glDisable(GL_BLEND);
420     glDisable(GL_LIGHTING);
421     
422     /* display ant shadow */
423     glPushMatrix();
424     glTranslatef(0.0, 0.001, 0.0);
425     glMultMatrixf(m[0]);
426
427     for(i = 0; i < ANTCOUNT; ++i) {
428
429       /* draw ant */
430       glPushMatrix();
431
432       /* center */
433       glRotatef(antposition[i], 0.0, 1.0, 0.0);
434       glTranslatef(2.4, 0.0, 0.0);
435       glTranslatef(0.0, antsphere[i], 0.0);
436       glRotatef(90.0, 0.0, 1.0, 0.0);
437
438       /* orient ant */
439       glRotatef(10.0, 0.0, 1.0, 0.0);
440       glRotatef(40.0, 0.0, 0.0, 1.0);
441       glTranslatef(0.0, -0.8, 0.0);
442       glRotatef(180.0, 0.0, 1.0, 0.0);
443       glRotatef(90.0, 0.0, 0.0, 1.0);
444
445       /* set colour */
446       glColor4fv(MaterialShadow);
447       glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialShadow);
448
449       if(antposition[i] > 360.0)
450         antposition[i] = 0.0;
451       draw_antinspect_ant(mi, mp, MaterialShadow, mono, mySphere2, myCone2);
452
453       glDisable(GL_BLEND);
454       glDisable(GL_LIGHTING);
455
456       /* draw sphere */
457       glRotatef(-20.0, 1.0, 0.0, 0.0);
458       glRotatef(-mp->ant_step*2, 0.0, 0.0, 1.0);
459       glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialShadow);
460       mySphere2(1.2);
461
462       glPopMatrix();
463     }
464   
465     glPopMatrix();
466   }
467
468   glEnable(GL_LIGHTING);
469
470   /* truants */
471   for(j = 0; j < ANTCOUNT; ++j) {
472     /* determine rendering order */
473     i = antorder[ro][j];
474
475     glPushMatrix();
476     
477     /* center */
478     glRotatef(antposition[i], 0.0, 1.0, 0.0);
479     glTranslatef(2.4, 0.0, 0.0);
480     glTranslatef(0.0, antsphere[i], 0.0);    
481     glRotatef(90.0, 0.0, 1.0, 0.0);
482
483     /* draw ant */
484     glPushMatrix();
485     glRotatef(10.0, 0.0, 1.0, 0.0);
486     glRotatef(40.0, 0.0, 0.0, 1.0);
487     glTranslatef(0.0, -0.8, 0.0);
488     glRotatef(180.0, 0.0, 1.0, 0.0);
489     glRotatef(90.0, 0.0, 0.0, 1.0);
490     if(antposition[i] > 360.0)
491       antposition[i] = 0.0;
492     glEnable(GL_BLEND);
493     draw_antinspect_ant(mi, mp, antmaterial[i], mono, mySphere2, myCone2);
494     glDisable(GL_BLEND);
495     glPopMatrix();
496
497     /* draw sphere */
498     glRotatef(-20.0, 1.0, 0.0, 0.0);
499     glRotatef(-mp->ant_step*2, 0.0, 0.0, 1.0);
500     glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mono ? MaterialGray5 : antmaterial[i]);
501     mySphere2(1.2);
502     glEnable(GL_BLEND);
503     glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialBlack);
504     mySphere(1.16);
505     glDisable(GL_BLEND);
506         
507     glPopMatrix();
508
509     /* finally, evolve */
510     antposition[i] += antvelocity[i];
511   }
512
513   /* but the step size is the same! */
514   mp->ant_step += 0.2;
515   
516   mp->ant_position += 1;
517   return True;
518 }
519
520 ENTRYPOINT void reshape_antinspect(ModeInfo * mi, int width, int height) 
521 {
522   double h = (GLfloat) height / (GLfloat) width;  
523   antinspectstruct *mp = &antinspect[MI_SCREEN(mi)];
524   mp->linewidth = (width / 512) + 1;
525
526   glViewport(0, 0, mp->WindW = (GLint) width, mp->WindH = (GLint) height);
527   glMatrixMode(GL_PROJECTION);
528   glLoadIdentity();
529
530   gluPerspective(45, 1/h, 7.0, 20.0);
531
532   glMatrixMode(GL_MODELVIEW);
533   glLineWidth(mp->linewidth);
534   glPointSize(mp->linewidth);
535 }
536
537 static void pinit(void) 
538 {
539   glClearDepth(1.0);
540   glClearColor(0.0, 0.0, 0.0, 1.0);
541   
542   glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
543   glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
544   glLightfv(GL_LIGHT0, GL_POSITION, position0);
545   glLightfv(GL_LIGHT1, GL_AMBIENT, ambient);
546   glLightfv(GL_LIGHT1, GL_DIFFUSE, diffuse);
547   glLightfv(GL_LIGHT1, GL_POSITION, position1);
548   glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);
549   glLightModelfv(GL_LIGHT_MODEL_TWO_SIDE, lmodel_twoside);
550   glEnable(GL_LIGHTING);
551   glEnable(GL_LIGHT0);
552   glEnable(GL_LIGHT1);
553   glEnable(GL_NORMALIZE);
554   glFrontFace(GL_CCW);
555   
556   /* antinspect */
557   glShadeModel(GL_SMOOTH);
558   glEnable(GL_DEPTH_TEST);
559   glDisable(GL_TEXTURE_2D);
560
561   glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, front_shininess);
562   glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, front_specular);
563 }
564
565 ENTRYPOINT void release_antinspect(ModeInfo * mi) 
566 {
567   if(antinspect) {
568         free((void *) antinspect);
569         antinspect = (antinspectstruct *) NULL;
570   }
571   FreeAllGL(mi);
572 }
573
574 ENTRYPOINT Bool antinspect_handle_event (ModeInfo *mi, XEvent *event) 
575 {
576   antinspectstruct *mp = &antinspect[MI_SCREEN(mi)];
577   
578   if(event->xany.type == ButtonPress && event->xbutton.button == Button1) {
579         mp->button_down_p = True;
580         gltrackball_start(mp->trackball,
581                                           event->xbutton.x, event->xbutton.y,
582                                           MI_WIDTH (mi), MI_HEIGHT (mi));
583         return True;
584   }
585   else if(event->xany.type == ButtonRelease && 
586                   event->xbutton.button == Button1) {
587         mp->button_down_p = False;
588         return True;
589   }
590   else if (event->xany.type == ButtonPress &&
591            (event->xbutton.button == Button4 ||
592             event->xbutton.button == Button5 ||
593             event->xbutton.button == Button6 ||
594             event->xbutton.button == Button7))
595     {
596       gltrackball_mousewheel (mp->trackball, event->xbutton.button, 5,
597                               !event->xbutton.state);
598       return True;
599     }
600   else if(event->xany.type == MotionNotify && mp->button_down_p) {
601         gltrackball_track (mp->trackball,
602                                            event->xmotion.x, event->xmotion.y,
603                                            MI_WIDTH (mi), MI_HEIGHT (mi));
604         return True;
605   }
606   
607   return False;
608 }
609
610 ENTRYPOINT void init_antinspect(ModeInfo * mi) 
611 {
612   antinspectstruct *mp;
613   
614   if(antinspect == NULL) {
615     if((antinspect = (antinspectstruct *) calloc(MI_NUM_SCREENS(mi),
616                                                  sizeof (antinspectstruct))) == NULL)
617       return;
618   }
619   mp = &antinspect[MI_SCREEN(mi)];
620   mp->step = NRAND(90);
621   mp->ant_position = NRAND(90);
622   mp->trackball = gltrackball_init ();
623   
624   if ((mp->glx_context = init_GL(mi)) != NULL) {
625     reshape_antinspect(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
626     glDrawBuffer(GL_BACK);
627     pinit();
628   } 
629   else
630     MI_CLEARWINDOW(mi);
631
632   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
633 }
634
635 ENTRYPOINT void draw_antinspect(ModeInfo * mi) 
636 {
637   antinspectstruct *mp;
638   
639   Display    *display = MI_DISPLAY(mi);
640   Window      window = MI_WINDOW(mi);
641   
642   if(!antinspect)
643     return;
644   mp = &antinspect[MI_SCREEN(mi)];
645   
646   MI_IS_DRAWN(mi) = True;
647   
648   if(!mp->glx_context)
649         return;
650   
651   glXMakeCurrent(display, window, *(mp->glx_context));
652   
653   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
654
655   glPushMatrix();
656
657   mi->polygon_count = 0;
658
659   /* position camera --- this works well, we can peer inside 
660      the antbubble */
661   glTranslatef(0.0, 0.0, -10.0);
662   gltrackball_rotate(mp->trackball);
663   glRotatef((15.0/2.0 + 15.0*sin(mp->ant_step/100.0)), 1.0, 0.0, 0.0);
664   glRotatef(30.0, 1.0, 0.0, 0.0);
665   glRotatef(180.0, 0.0, 1.0, 0.0);
666   
667   if (!draw_antinspect_strip(mi)) {
668         release_antinspect(mi);
669         return;
670   }
671   
672   glPopMatrix();
673   
674   if (MI_IS_FPS(mi)) do_fps (mi);
675   glFlush();
676   
677   glXSwapBuffers(display, window);
678   
679   mp->step += 0.025;
680 }
681
682 #ifndef STANDALONE
683 ENTRYPOINT void change_antinspect(ModeInfo * mi) 
684 {
685   antinspectstruct *mp = &antinspect[MI_SCREEN(mi)];
686   
687   if (!mp->glx_context)
688         return;
689   
690   glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(mp->glx_context));
691   pinit();
692 }
693 #endif /* !STANDALONE */
694
695
696 XSCREENSAVER_MODULE ("AntInspect", antinspect)