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