http://www.tienza.es/crux/src/www.jwz.org/xscreensaver/xscreensaver-5.05.tar.gz
[xscreensaver] / hacks / glx / antspotlight.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 2003 Blair Tennessy
15  */
16
17 #ifdef STANDALONE
18 #define DEFAULTS            "*delay:   20000   \n" \
19                             "*showFPS: False   \n" \
20                             "*useSHM:  True    \n"
21
22 # define refresh_antspotlight 0
23 #include "xlockmore.h"
24 #else
25 #include "xlock.h"
26 #endif
27
28 #include "rotator.h"
29 #include "gltrackball.h"
30
31 ENTRYPOINT ModeSpecOpt antspotlight_opts = {
32   0, NULL, 0, NULL, NULL
33 };
34
35 #ifdef USE_MODULES
36 ModStruct   antspotlight_description = {
37   "antspotlight", "init_antspotlight", "draw_antspotlight", 
38   "release_antspotlight", "draw_antspotlight", "change_antspotlight", 
39   (char *) NULL, &antspotlight_opts, 1000, 1, 1, 1, 4, 1.0, "",
40   "draws an ant scoping the screen", 0, NULL
41 };
42 #endif
43
44 #define Scale4Window               0.3
45 #define Scale4Iconic               0.4
46
47 #define sqr(A)                     ((A)*(A))
48
49 #ifndef Pi
50 #define Pi M_PI
51 #endif
52
53 #include "ants.h"
54 #include "grab-ximage.h"
55
56 typedef struct {
57   GLXContext *glx_context;
58   rotator    *rot;
59   trackball_state *trackball;
60   Bool        button_down_p;
61
62   GLfloat max_tx, max_ty;
63   int mono, wire, ticks;
64   GLuint screentexture;
65
66   Ant *ant;
67   double boardsize;
68   GLfloat spot_direction[3];
69   int mag;
70
71   Bool mipmap_p;
72   Bool waiting_for_image_p;
73
74 } antspotlightstruct;
75
76 static antspotlightstruct *antspotlight = (antspotlightstruct *) NULL;
77
78 #define NUM_SCENES      2
79
80 /* draw method for ant */
81 static Bool draw_ant(antspotlightstruct *mp,
82                      const GLfloat *Material, int mono, int shadow, 
83               float ant_step, Bool (*sphere)(float), Bool (*cone)(float))
84 {
85   
86   float cos1 = cos(ant_step);
87   float cos2 = cos(ant_step + 2 * Pi / 3);
88   float cos3 = cos(ant_step + 4 * Pi / 3);
89   float sin1 = sin(ant_step);
90   float sin2 = sin(ant_step + 2 * Pi / 3);
91   float sin3 = sin(ant_step + 4 * Pi / 3);
92   
93 /* Apparently this is a performance killer on many systems...
94    glEnable(GL_POLYGON_SMOOTH);
95  */
96   glEnable(GL_BLEND);
97   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
98
99   glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->mono ? MaterialGray5 : Material);
100   glEnable(GL_CULL_FACE);
101   glPushMatrix();
102   glScalef(1, 1.3, 1);
103   if(!((*sphere)(0.18)))
104     return False;
105   glScalef(1, 1 / 1.3, 1);
106   glTranslatef(0.00, 0.30, 0.00);
107   if(!((*sphere)(0.2)))
108     return False;
109   
110   glTranslatef(-0.05, 0.17, 0.05);
111   glRotatef(-90, 1, 0, 0);
112   glRotatef(-25, 0, 1, 0);
113   if(!((*cone)(0.05)))
114     return False;
115   glTranslatef(0.00, 0.10, 0.00);
116   if(!((*cone)(0.05)))
117     return False;
118   glRotatef(25, 0, 1, 0);
119   glRotatef(90, 1, 0, 0);
120   
121   glScalef(1, 1.3, 1);
122   glTranslatef(0.15, -0.65, 0.05);
123   if(!((*sphere)(0.25)))
124     return False;
125   glScalef(1, 1 / 1.3, 1);
126   glPopMatrix();
127   glDisable(GL_CULL_FACE);
128   
129   glDisable(GL_LIGHTING);
130   
131   /* ANTENNAS */
132   glEnable(GL_LINE_SMOOTH);
133   glEnable(GL_BLEND);
134   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
135    
136   glBegin(GL_LINES);
137   glColor3fv(mp->mono ? MaterialGray5 : Material);
138   glVertex3f(0.00, 0.30, 0.00);
139   glColor3fv(MaterialGray);
140   glVertex3f(0.40, 0.70, 0.40);
141   glColor3fv(mp->mono ? MaterialGray5 : Material);
142   glVertex3f(0.00, 0.30, 0.00);
143   glColor3fv(MaterialGray);
144   glVertex3f(0.40, 0.70, -0.40);
145   glEnd();
146
147   if(!shadow) {
148     glBegin(GL_POINTS);
149     glColor3fv(mp->mono ? MaterialGray6 : MaterialGray5);
150     glVertex3f(0.40, 0.70, 0.40);
151     glVertex3f(0.40, 0.70, -0.40);
152     glEnd();
153   }
154
155   /* LEFT-FRONT ARM */
156   glBegin(GL_LINE_STRIP);
157   glColor3fv(mp->mono ? MaterialGray5 : Material);
158   glVertex3f(0.00, 0.05, 0.18);
159   glVertex3f(0.35 + 0.05 * cos1, 0.15, 0.25);
160   glColor3fv(MaterialGray);
161   glVertex3f(-0.20 + 0.05 * cos1, 0.25 + 0.1 * sin1, 0.45);
162   glEnd();
163
164   /* LEFT-CENTER ARM */
165   glBegin(GL_LINE_STRIP);
166   glColor3fv(mp->mono ? MaterialGray5 : Material);
167   glVertex3f(0.00, 0.00, 0.18);
168   glVertex3f(0.35 + 0.05 * cos2, 0.00, 0.25);
169   glColor3fv(MaterialGray);
170   glVertex3f(-0.20 + 0.05 * cos2, 0.00 + 0.1 * sin2, 0.45);
171   glEnd();
172
173   /* LEFT-BACK ARM */
174   glBegin(GL_LINE_STRIP);
175   glColor3fv(mp->mono ? MaterialGray5 : Material);
176   glVertex3f(0.00, -0.05, 0.18);
177   glVertex3f(0.35 + 0.05 * cos3, -0.15, 0.25);
178   glColor3fv(MaterialGray);
179   glVertex3f(-0.20 + 0.05 * cos3, -0.25 + 0.1 * sin3, 0.45);
180   glEnd();
181
182   /* RIGHT-FRONT ARM */
183   glBegin(GL_LINE_STRIP);
184   glColor3fv(mp->mono ? MaterialGray5 : Material);
185   glVertex3f(0.00, 0.05, -0.18);
186   glVertex3f(0.35 - 0.05 * sin1, 0.15, -0.25);
187   glColor3fv(MaterialGray);
188   glVertex3f(-0.20 - 0.05 * sin1, 0.25 + 0.1 * cos1, -0.45);
189   glEnd();
190
191   /* RIGHT-CENTER ARM */
192   glBegin(GL_LINE_STRIP);
193   glColor3fv(mp->mono ? MaterialGray5 : Material);
194   glVertex3f(0.00, 0.00, -0.18);
195   glVertex3f(0.35 - 0.05 * sin2, 0.00, -0.25);
196   glColor3fv(MaterialGray);
197   glVertex3f(-0.20 - 0.05 * sin2, 0.00 + 0.1 * cos2, -0.45);
198   glEnd();
199
200   /* RIGHT-BACK ARM */
201   glBegin(GL_LINE_STRIP);
202   glColor3fv(mp->mono ? MaterialGray5 : Material);
203   glVertex3f(0.00, -0.05, -0.18);
204   glVertex3f(0.35 - 0.05 * sin3, -0.15, -0.25);
205   glColor3fv(MaterialGray);
206   glVertex3f(-0.20 - 0.05 * sin3, -0.25 + 0.1 * cos3, -0.45);
207   glEnd();
208
209   if(!shadow) {
210     glBegin(GL_POINTS);
211     glColor3fv(MaterialGray5);
212     glVertex3f(-0.20 + 0.05 * cos1, 0.25 + 0.1 * sin1, 0.45);
213     glVertex3f(-0.20 + 0.05 * cos2, 0.00 + 0.1 * sin2, 0.45);
214     glVertex3f(-0.20 + 0.05 * cos3, -0.25 + 0.1 * sin3, 0.45);
215     glVertex3f(-0.20 - 0.05 * sin1, 0.25 + 0.1 * cos1, -0.45);
216     glVertex3f(-0.20 - 0.05 * sin2, 0.00 + 0.1 * cos2, -0.45);
217     glVertex3f(-0.20 - 0.05 * sin3, -0.25 + 0.1 * cos3, -0.45);
218     glEnd();
219   }
220
221   glEnable(GL_LIGHTING);
222
223   return True;
224 }
225
226 /* filled sphere */
227 static Bool mySphere(float radius)
228 {
229   GLUquadricObj *quadObj;
230   
231   if((quadObj = gluNewQuadric()) == 0)
232     return False;
233
234   gluQuadricDrawStyle(quadObj, (GLenum) GLU_FILL);
235   gluSphere(quadObj, radius, 16, 16);
236   gluDeleteQuadric(quadObj);
237
238   return True;
239 }
240
241 /* silhouette sphere */
242 static Bool mySphere2(float radius)
243 {
244   GLUquadricObj *quadObj;
245
246   if((quadObj = gluNewQuadric()) == 0)
247         return False;
248   gluQuadricDrawStyle(quadObj, (GLenum) GLU_LINE);
249   gluSphere(quadObj, radius, 16, 8);
250   gluDeleteQuadric(quadObj);
251
252   return True;
253 }
254
255 /* no cone */
256 static Bool myCone2(float radius) { return True; }
257
258 static void draw_board(antspotlightstruct *mp)
259 {
260   int i, j;
261   double cutoff = Pi/3.0;
262   double center[3];
263   double centertex[2];
264
265   glEnable(GL_TEXTURE_2D);
266   glBindTexture(GL_TEXTURE_2D, mp->screentexture);
267   glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialGray6);
268
269   /* draw mesh */
270
271   /* center is roughly spotlight position */
272   center[0] = mp->ant->position[0];/* + cos(ant->direction); */
273   center[1] = 0.0;
274   center[2] = mp->ant->position[2];/* - 0.7*sin(ant->direction);*/
275
276   centertex[0] = (mp->boardsize/2.0+center[0]) * mp->max_tx / mp->boardsize;
277   centertex[1] = mp->max_ty - ((mp->boardsize/2.0+center[2]) * mp->max_ty / mp->boardsize);
278
279 /*   glPolygonMode(GL_FRONT, GL_LINE); */
280 /*   glDisable(GL_TEXTURE_2D); */
281
282   /* 
283      the vertices determined here should correspond to the illuminated
284      board.  ideally the code adapts vertex distribution to the
285      intensity and shape of the light.
286      
287      i should be finding the intersection of the cone of light and
288      the board-plane.
289   */
290   for(i = -12; i < 12; ++i) {
291
292     double theta1, theta2;
293
294     glBegin(GL_TRIANGLE_STRIP);
295     glNormal3f(0.0, 1.0, 0.0);
296
297     glTexCoord2f(centertex[0], centertex[1]);
298     glVertex3f(center[0], 0.01, center[2]);
299
300     /* watch those constants */
301     theta1 = mp->ant->direction + i*(cutoff/8);
302     theta2 = mp->ant->direction + (i+1)*(cutoff/8);
303
304     for(j = 1; j <= 64; ++j) {
305       double point[3], tex[2];
306       /* double fj = pow(1.05, j) - 1.0;*/
307       double fj = j / 6.0;
308       point[0] = center[0] + fj*cos(theta1);
309       point[1] = 0.0;
310       point[2] = center[2] - fj*sin(theta1);
311
312       tex[0] = (mp->boardsize/2.0+point[0]) * mp->max_tx / mp->boardsize;
313       tex[1] = (mp->boardsize/2.0+point[2]) * mp->max_ty / mp->boardsize;
314
315       glTexCoord2f(tex[0], tex[1]);
316       glVertex3f(point[0], point[1], point[2]);
317
318       point[0] = center[0] + fj*cos(theta2);
319       point[1] = 0.0;
320       point[2] = center[2] - fj*sin(theta2);
321
322       tex[0] = (mp->boardsize/2.0+point[0]) * mp->max_tx / mp->boardsize;
323       tex[1] = (mp->boardsize/2.0+point[2]) * mp->max_ty / mp->boardsize;
324
325       glTexCoord2f(tex[0], tex[1]);
326       glVertex3f(point[0], point[1], point[2]);
327     }
328
329     glEnd();
330   }
331
332   glDisable(GL_TEXTURE_2D);
333 }
334
335 /* return euclidean distance between two points */
336 static double distance(double x[3], double y[3])
337 {
338   double dx = x[0] - y[0];
339   double dz = x[2] - y[2];
340   return sqrt(dx*dx + dz*dz);
341 }
342
343 /* determine a new goal */
344 static void find_goal(antspotlightstruct *mp)
345 {
346   do {
347     mp->ant->goal[0] = random()%((int)(mp->boardsize+0.5)-2) - mp->boardsize/2.0 + 1.0;
348     mp->ant->goal[1] = 0.0;
349     mp->ant->goal[2] = random()%((int)(mp->boardsize+0.5)-2) - mp->boardsize/2.0 + 1.0;
350   }
351   while(distance(mp->ant->position, mp->ant->goal) < 2.0);
352 }
353
354 /* construct our ant */
355 static void build_ant(antspotlightstruct *mp)
356 {
357   mp->ant = (Ant *) malloc(sizeof (Ant));
358   mp->ant->position[0] = 0.0;
359   mp->ant->position[1] = 0.0;
360   mp->ant->position[2] = 0.0;
361   mp->ant->direction = 0.0;
362   mp->ant->velocity = 0.02;
363   mp->ant->material = MaterialGray5;
364   mp->ant->step = 0;
365   find_goal(mp);
366 }
367
368 #define EPSILON 0.01
369
370 static double sign(double d)
371 {
372   return d < 0.0 ? -1.0 : 1.0;
373 }
374
375 static double min(double a, double b)
376 {
377   return a < b ? a : b;
378 }
379
380 /*
381 static double max(double a, double b)
382 {
383   return a > b ? a : b;
384 }
385 */
386
387 /* find a new goal and reset steps */
388 static void reset_ant(antspotlightstruct *mp)
389 {
390   find_goal(mp);
391 }
392
393 /* draw ant composed of skeleton and glass */
394 static void show_ant(antspotlightstruct *mp)
395 {
396
397   glPushMatrix();
398
399   /* move into position */
400   glTranslatef(mp->ant->position[0], 0.33, mp->ant->position[2]);
401   glRotatef(180.0 + mp->ant->direction*180.0/Pi, 0.0, 1.0, 0.0);
402   glRotatef(90.0, 0.0, 0.0, 1.0);
403
404   /* draw skeleton */
405   draw_ant(mp, mp->ant->material, mp->mono, 0, mp->ant->step, mySphere2, myCone2);
406
407   /* draw glass */
408   if(!mp->wire && !mp->mono) {
409     glEnable(GL_BLEND);
410     glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialGrayB);
411     glColor4fv(MaterialGrayB);
412     draw_ant(mp, MaterialGrayB, mp->mono, 0, mp->ant->step, mySphere, myCone2);
413     glDisable(GL_BLEND);
414   }
415
416   glPopMatrix();
417 }
418
419 static void draw_antspotlight_strip(ModeInfo *mi)
420 {
421   antspotlightstruct *mp = &antspotlight[MI_SCREEN(mi)];
422
423   /* compute spotlight position and direction */
424   GLfloat light1_position[4];
425
426   light1_position[0] = mp->ant->position[0] + 0.7*cos(mp->ant->direction);
427   light1_position[1] = 0.5;
428   light1_position[2] = mp->ant->position[2] - 0.7*sin(mp->ant->direction);
429   light1_position[3] = 1.0;
430
431   mp->spot_direction[0] = cos(mp->ant->direction);
432   mp->spot_direction[1] = -0.5;
433   mp->spot_direction[2] = -sin(mp->ant->direction);
434
435   glLightfv(GL_LIGHT2, GL_POSITION, light1_position);
436   glLightfv(GL_LIGHT2, GL_SPOT_DIRECTION, mp->spot_direction);
437   
438   glEnable(GL_LIGHT2);
439   glDisable(GL_LIGHT0);
440   glDisable(GL_LIGHT1);
441
442   /* draw board */
443   if(mp->wire)
444     ;
445   else
446     draw_board(mp);
447
448   glDisable(GL_LIGHT2);
449   glEnable(GL_LIGHT0);
450   glEnable(GL_LIGHT1);
451   
452   /* now modify ant */
453   show_ant(mp);
454
455   /* near goal, bend path towards next step */
456   if(distance(mp->ant->position, mp->ant->goal) < 0.2) {
457     reset_ant(mp);
458   }
459
460   if(random()%100 == 0) {
461     reset_ant(mp);
462   }
463
464
465   /* move toward goal, correct ant direction if required */
466   else {
467     
468     /* difference */
469     double dx = mp->ant->goal[0] - mp->ant->position[0];
470     double dz = -(mp->ant->goal[2] - mp->ant->position[2]);
471     double theta, ideal, dt;
472     
473     if(fabs(dx) > EPSILON) {
474       theta = atan(dz/dx);
475       if(dx < 0.0)
476         theta += Pi;
477     }
478     else
479       theta = dz > 0.0 ? (1.0/2.0)*Pi : (3.0/2.0)*Pi;
480     
481     if(theta < 0.0)
482       theta += 2*Pi;
483     
484     ideal = theta - mp->ant->direction;
485     if(ideal > Pi)
486       ideal -= 2*Pi;
487     
488     /* compute correction */
489     dt = sign(ideal) * min(fabs(ideal), Pi/100.0);
490     mp->ant->direction += dt;
491     while(mp->ant->direction < 0.0)
492       mp->ant->direction += 2*Pi;
493     while(mp->ant->direction > 2*Pi)
494       mp->ant->direction -= 2*Pi;
495   }
496
497   mp->ant->position[0] += mp->ant->velocity * cos(mp->ant->direction);
498   mp->ant->position[2] += mp->ant->velocity * sin(-mp->ant->direction);
499   mp->ant->step += 10*mp->ant->velocity;
500   while(mp->ant->step > 2*Pi)
501     mp->ant->step -= 2*Pi;
502 }
503
504 ENTRYPOINT void reshape_antspotlight(ModeInfo * mi, int width, int height)
505 {
506   double h = (GLfloat) height / (GLfloat) width;  
507   int size = 2;
508   glViewport(0, 0, width, height);
509   glMatrixMode(GL_PROJECTION);
510   glLoadIdentity();
511
512   gluPerspective(45, 1/h, 1.0, 25.0);
513
514   glMatrixMode(GL_MODELVIEW);
515   glLineWidth(size);
516   glPointSize(size);
517 }
518
519 /* lighting variables */
520 static const GLfloat front_shininess[] = {60.0};
521 static const GLfloat front_specular[] = {0.8, 0.8, 0.8, 1.0};
522 static const GLfloat ambient[] = {0.4, 0.4, 0.4, 1.0};
523 /*static const GLfloat ambient2[] = {0.0, 0.0, 0.0, 0.0};*/
524 static const GLfloat diffuse[] = {1.0, 1.0, 1.0, 1.0};
525 static const GLfloat position0[] = {1.0, 5.0, 1.0, 0.0};
526 static const GLfloat position1[] = {-1.0, -5.0, 1.0, 0.0};
527 /*static const GLfloat lmodel_ambient[] = {0.8, 0.8, 0.8, 1.0};*/
528 static const GLfloat lmodel_twoside[] = {GL_TRUE};
529 static const GLfloat spotlight_ambient[] = { 0.0, 0.0, 0.0, 1.0 };
530 static const GLfloat spotlight_diffuse[] = { 1.0, 1.0, 1.0, 1.0 };
531
532 static void pinit(void)
533 {
534   glClearDepth(1.0);
535   glClearColor(0.0, 0.0, 0.0, 1.0);
536   
537   /* setup twoside lighting */
538   glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
539   glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
540   glLightfv(GL_LIGHT0, GL_POSITION, position0);
541   glLightfv(GL_LIGHT1, GL_AMBIENT, ambient);
542   glLightfv(GL_LIGHT1, GL_DIFFUSE, diffuse);
543   glLightfv(GL_LIGHT1, GL_POSITION, position1);
544
545   glLightModelfv(GL_LIGHT_MODEL_AMBIENT, spotlight_ambient);
546   glLightModelfv(GL_LIGHT_MODEL_TWO_SIDE, lmodel_twoside);
547   glEnable(GL_LIGHTING);
548   glEnable(GL_LIGHT0);
549   glEnable(GL_LIGHT1);
550
551   /* setup spotlight */
552   glLightfv(GL_LIGHT2, GL_AMBIENT, spotlight_ambient);
553   glLightfv(GL_LIGHT2, GL_DIFFUSE, spotlight_diffuse);
554   glLightf(GL_LIGHT2, GL_CONSTANT_ATTENUATION, 0.1);
555   glLightf(GL_LIGHT2, GL_LINEAR_ATTENUATION, 0.05);
556   glLightf(GL_LIGHT2, GL_QUADRATIC_ATTENUATION, 0.0);
557   glLightf(GL_LIGHT2, GL_SPOT_CUTOFF, 60.0);
558   glLightf(GL_LIGHT2, GL_SPOT_EXPONENT, 3.0);
559
560   glEnable(GL_NORMALIZE);
561   glFrontFace(GL_CCW);
562   glCullFace(GL_BACK);
563
564   /* setup material properties */
565   glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, front_shininess);
566   glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, front_specular);
567
568   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
569   glShadeModel(GL_SMOOTH);
570 /*   glShadeModel(GL_FLAT); */
571   glEnable(GL_DEPTH_TEST);
572 }
573
574 /* cleanup routine */
575 ENTRYPOINT void release_antspotlight(ModeInfo * mi)
576 {
577
578   if(antspotlight) {
579     free((void *) antspotlight);
580     antspotlight = (antspotlightstruct *) NULL;
581   }
582
583   FreeAllGL(mi);
584 }
585
586 #define MAX_MAGNIFICATION 10
587 #define max(a, b) a < b ? b : a
588 #define min(a, b) a < b ? a : b
589
590 /* event handling */
591 ENTRYPOINT Bool antspotlight_handle_event(ModeInfo *mi, XEvent *event)
592 {
593   antspotlightstruct *mp = &antspotlight[MI_SCREEN(mi)];
594
595   switch(event->xany.type) {
596   case ButtonPress:
597
598     switch(event->xbutton.button) {
599
600     case Button1:
601       mp->button_down_p = True;
602       gltrackball_start(mp->trackball, 
603                         event->xbutton.x, event->xbutton.y,
604                         MI_WIDTH (mi), MI_HEIGHT (mi));
605       break;
606       
607     case Button4:
608       mp->mag = max(mp->mag-1, 1);
609       break;
610
611     case Button5:
612       mp->mag = min(mp->mag+1, MAX_MAGNIFICATION);
613       break;
614     }
615
616     break;
617     
618   case ButtonRelease:
619
620     switch(event->xbutton.button) {
621     case Button1:
622       mp->button_down_p = False;
623       break;
624     }
625
626     break;
627
628   case MotionNotify:
629     if(mp->button_down_p)
630       gltrackball_track(mp->trackball,
631                         event->xmotion.x, event->xmotion.y,
632                         MI_WIDTH (mi), MI_HEIGHT (mi));
633     break;
634     
635   default:
636     return False;
637   }
638
639   return True;
640 }
641
642 static void
643 image_loaded_cb (const char *filename, XRectangle *geometry,
644                  int image_width, int image_height, 
645                  int texture_width, int texture_height,
646                  void *closure)
647 {
648   antspotlightstruct *mp = (antspotlightstruct *) closure;
649
650   mp->max_tx = (GLfloat) image_width  / texture_width;
651   mp->max_ty = (GLfloat) image_height / texture_height;
652
653   glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
654   glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
655                    (mp->mipmap_p ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR));
656
657   mp->waiting_for_image_p = False;
658 }
659
660
661 /* get screenshot */
662 static void get_snapshot(ModeInfo *modeinfo)
663 {
664   antspotlightstruct *mp = &antspotlight[MI_SCREEN(modeinfo)];
665
666   if (MI_IS_WIREFRAME(modeinfo))
667     return;
668
669   mp->waiting_for_image_p = True;
670   mp->mipmap_p = True;
671   load_texture_async (modeinfo->xgwa.screen, modeinfo->window,
672                       *mp->glx_context, 0, 0, mp->mipmap_p, 
673                       mp->screentexture, image_loaded_cb, mp);
674 }
675
676
677 ENTRYPOINT void init_antspotlight(ModeInfo *mi)
678 {
679   double rot_speed = 0.3;
680
681   antspotlightstruct *mp;
682   
683   if(!antspotlight) {
684     if((antspotlight = (antspotlightstruct *) 
685         calloc(MI_NUM_SCREENS(mi), sizeof (antspotlightstruct))) == NULL)
686       return;
687   }
688   mp = &antspotlight[MI_SCREEN(mi)];
689   mp->rot = make_rotator (rot_speed, rot_speed, rot_speed, 1, 0, True);
690   mp->trackball = gltrackball_init ();
691
692   if((mp->glx_context = init_GL(mi)) != NULL) {
693     reshape_antspotlight(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
694     glDrawBuffer(GL_BACK);
695     pinit();
696   }
697   else
698     MI_CLEARWINDOW(mi);
699
700   glGenTextures(1, &mp->screentexture);
701   glBindTexture(GL_TEXTURE_2D, mp->screentexture);
702   get_snapshot(mi);
703
704   build_ant(mp);
705   mp->mono = MI_IS_MONO(mi);
706   mp->wire = MI_IS_WIREFRAME(mi);
707   mp->boardsize = 8.0;
708   mp->mag = 1;
709 }
710
711 ENTRYPOINT void draw_antspotlight(ModeInfo * mi)
712 {
713   antspotlightstruct *mp;
714   
715   Display    *display = MI_DISPLAY(mi);
716   Window      window = MI_WINDOW(mi);
717   
718   if(!antspotlight)
719         return;
720   mp = &antspotlight[MI_SCREEN(mi)];
721   
722   MI_IS_DRAWN(mi) = True;
723   
724   if(!mp->glx_context)
725         return;
726   
727   /* Just keep running before the texture has come in. */
728   /* if (mp->waiting_for_image_p) return; */
729
730   glXMakeCurrent(display, window, *(mp->glx_context));
731   
732   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
733   
734   glPushMatrix();
735
736   /* position camera */
737
738   /* follow focused ant */
739   glTranslatef(0.0, 0.0, -6.0 - mp->mag);
740   glRotatef(35.0, 1.0, 0.0, 0.0);
741   gltrackball_rotate(mp->trackball);
742   glTranslatef(-mp->ant->position[0], mp->ant->position[1], -mp->ant->position[2]);
743
744   /* stable position */
745 /*   glTranslatef(0.0, 0.0, -10.0 - mag); */
746 /*   gltrackball_rotate(mp->trackball); */
747 /*   glRotatef(40.0, 1.0, 0.0, 0.0); */
748 /*   glRotatef(20.0, 0.0, 1.0, 0.0); */
749
750   draw_antspotlight_strip(mi);
751
752   ++mp->ticks;
753   
754   glPopMatrix();
755   
756   if (MI_IS_FPS(mi)) do_fps (mi);
757   glFlush();
758   
759   glXSwapBuffers(display, window);
760 }
761
762 #ifndef STANDALONE
763 ENTRYPOINT void change_antspotlight(ModeInfo * mi)
764 {
765   antspotlightstruct *mp = &antspotlight[MI_SCREEN(mi)];
766   
767   if (!mp->glx_context)
768         return;
769   
770   glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(mp->glx_context));
771   pinit();
772 }
773 #endif /* !STANDALONE */
774
775 XSCREENSAVER_MODULE ("AntSpotlight", antspotlight)