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