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