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