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.
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.
14 * Copyright 2003 Blair Tennessy
17 #include <X11/Intrinsic.h>
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" \
31 #include "xlockmore.h"
38 #include "gltrackball.h"
40 ModeSpecOpt antspotlight_opts = {
41 0, NULL, 0, NULL, NULL
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
53 #define Scale4Window 0.3
54 #define Scale4Iconic 0.4
56 #define sqr(A) ((A)*(A))
62 GLfloat max_tx, max_ty;
63 int mono = 0, wire = 0, ticks = 0;
67 GLXContext *glx_context;
69 trackball_state *trackball;
74 #include "grab-ximage.h"
76 static antspotlightstruct *antspotlight = (antspotlightstruct *) NULL;
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))
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);
92 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mono ? MaterialGray5 : Material);
93 glEnable(GL_CULL_FACE);
96 if(!((*sphere)(0.18)))
98 glScalef(1, 1 / 1.3, 1);
99 glTranslatef(0.00, 0.30, 0.00);
100 if(!((*sphere)(0.2)))
103 glTranslatef(-0.05, 0.17, 0.05);
104 glRotatef(-90, 1, 0, 0);
105 glRotatef(-25, 0, 1, 0);
108 glTranslatef(0.00, 0.10, 0.00);
111 glRotatef(25, 0, 1, 0);
112 glRotatef(90, 1, 0, 0);
115 glTranslatef(0.15, -0.65, 0.05);
116 if(!((*sphere)(0.25)))
118 glScalef(1, 1 / 1.3, 1);
120 glDisable(GL_CULL_FACE);
122 glDisable(GL_LIGHTING);
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);
138 glColor3fv(mono ? MaterialGray6 : MaterialGray5);
139 glVertex3f(0.40, 0.70, 0.40);
140 glVertex3f(0.40, 0.70, -0.40);
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);
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);
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);
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);
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);
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);
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);
210 glEnable(GL_LIGHTING);
216 static Bool mySphere(float radius)
218 GLUquadricObj *quadObj;
220 if((quadObj = gluNewQuadric()) == 0)
223 gluQuadricDrawStyle(quadObj, (GLenum) GLU_FILL);
224 gluSphere(quadObj, radius, 16, 16);
225 gluDeleteQuadric(quadObj);
230 /* silhouette sphere */
231 static Bool mySphere2(float radius)
233 GLUquadricObj *quadObj;
235 if((quadObj = gluNewQuadric()) == 0)
237 gluQuadricDrawStyle(quadObj, (GLenum) GLU_LINE);
238 gluSphere(quadObj, radius, 16, 8);
239 gluDeleteQuadric(quadObj);
245 static Bool myCone2(float radius) { return True; }
249 double boardsize = 8.0;
252 GLfloat spot_direction[3];
254 void draw_board(void)
257 double cutoff = Pi/3.0;
261 glEnable(GL_TEXTURE_2D);
262 glBindTexture(GL_TEXTURE_2D, screentexture);
263 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialGray6);
267 /* center is roughly spotlight position */
268 center[0] = ant->position[0];/* + cos(ant->direction); */
270 center[2] = ant->position[2];/* - 0.7*sin(ant->direction);*/
272 centertex[0] = (boardsize/2.0+center[0]) * max_tx / boardsize;
273 centertex[1] = max_ty - ((boardsize/2.0+center[2]) * max_ty / boardsize);
275 /* glPolygonMode(GL_FRONT, GL_LINE); */
276 /* glDisable(GL_TEXTURE_2D); */
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.
283 i should be finding the intersection of the cone of light and
286 for(i = -8; i < 8; ++i) {
288 double theta1, theta2;
290 glBegin(GL_TRIANGLE_STRIP);
291 glNormal3f(0.0, 1.0, 0.0);
293 glTexCoord2f(centertex[0], centertex[1]);
294 glVertex3f(center[0], 0.01, center[2]);
296 /* watch those constants */
297 theta1 = ant->direction + i*(cutoff/8);
298 theta2 = ant->direction + (i+1)*(cutoff/8);
300 for(j = 1; j <= 40; ++j) {
301 double point[3], tex[2];
302 /* double fj = pow(1.05, j) - 1.0;*/
304 point[0] = center[0] + fj*cos(theta1);
306 point[2] = center[2] - fj*sin(theta1);
308 tex[0] = (boardsize/2.0+point[0]) * max_tx / boardsize;
309 tex[1] = (boardsize/2.0+point[2]) * max_ty / boardsize;
311 glTexCoord2f(tex[0], tex[1]);
312 glVertex3f(point[0], point[1], point[2]);
314 point[0] = center[0] + fj*cos(theta2);
316 point[2] = center[2] - fj*sin(theta2);
318 tex[0] = (boardsize/2.0+point[0]) * max_tx / boardsize;
319 tex[1] = (boardsize/2.0+point[2]) * max_ty / boardsize;
321 glTexCoord2f(tex[0], tex[1]);
322 glVertex3f(point[0], point[1], point[2]);
328 glDisable(GL_TEXTURE_2D);
331 /* return euclidean distance between two points */
332 double distance(double x[3], double y[3])
334 double dx = x[0] - y[0];
335 double dz = x[2] - y[2];
336 return sqrt(dx*dx + dz*dz);
339 /* determine a new goal */
343 ant->goal[0] = random()%((int)(boardsize+0.5)-2) - boardsize/2.0 + 1.0;
345 ant->goal[2] = random()%((int)(boardsize+0.5)-2) - boardsize/2.0 + 1.0;
347 while(distance(ant->position, ant->goal) < 2.0);
350 /* construct our ant */
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;
366 double sign(double d)
368 return d < 0.0 ? -1.0 : 1.0;
371 double min(double a, double b)
373 return a < b ? a : b;
376 double max(double a, double b)
378 return a > b ? a : b;
381 /* find a new goal and reset steps */
387 /* draw ant composed of skeleton and glass */
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);
399 draw_ant(ant->material, mono, 0, ant->step, mySphere2, myCone2);
404 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialGrayB);
405 glColor4fv(MaterialGrayB);
406 draw_ant(MaterialGrayB, mono, 0, ant->step, mySphere, myCone2);
413 void draw_antspotlight_strip(ModeInfo *mi)
416 /* compute spotlight position and direction */
417 GLfloat light1_position[4];
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;
424 spot_direction[0] = cos(ant->direction);
425 spot_direction[1] = -0.5;
426 spot_direction[2] = -sin(ant->direction);
428 glLightfv(GL_LIGHT2, GL_POSITION, light1_position);
429 glLightfv(GL_LIGHT2, GL_SPOT_DIRECTION, spot_direction);
432 glDisable(GL_LIGHT0);
433 glDisable(GL_LIGHT1);
440 /* glCallList(BOARDLIST); */
442 glDisable(GL_LIGHT2);
449 /* near goal, bend path towards next step */
450 if(distance(ant->position, ant->goal) < 0.2) {
454 /* move toward goal, correct ant direction if required */
458 double dx = ant->goal[0] - ant->position[0];
459 double dz = -(ant->goal[2] - ant->position[2]);
460 double theta, ideal, dt;
462 if(fabs(dx) > EPSILON) {
468 theta = dz > 0.0 ? (1.0/2.0)*Pi : (3.0/2.0)*Pi;
473 ideal = theta - ant->direction;
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;
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)
493 void reshape_antspotlight(ModeInfo * mi, int width, int height)
495 double h = (GLfloat) height / (GLfloat) width;
497 glViewport(0, 0, width, height);
498 glMatrixMode(GL_PROJECTION);
501 gluPerspective(45, 1/h, 1.0, 25.0);
503 glMatrixMode(GL_MODELVIEW);
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 };
521 static void pinit(void)
524 glClearColor(0.0, 0.0, 0.0, 1.0);
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);
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);
548 glEnable(GL_NORMALIZE);
552 /* setup material properties */
553 glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, front_shininess);
554 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, front_specular);
556 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
557 glShadeModel(GL_SMOOTH);
558 /* glShadeModel(GL_FLAT); */
559 glEnable(GL_DEPTH_TEST);
562 /* cleanup routine */
563 void release_antspotlight(ModeInfo * mi)
567 free((void *) antspotlight);
568 antspotlight = (antspotlightstruct *) NULL;
575 #define MAX_MAGNIFICATION 10
576 #define max(a, b) a < b ? b : a
577 #define min(a, b) a < b ? a : b
580 Bool antspotlight_handle_event(ModeInfo *mi, XEvent *event)
582 antspotlightstruct *mp = &antspotlight[MI_SCREEN(mi)];
584 switch(event->xany.type) {
587 switch(event->xbutton.button) {
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));
601 mag = min(mag+1, MAX_MAGNIFICATION);
609 switch(event->xbutton.button) {
611 mp->button_down_p = False;
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));
632 void get_snapshot(ModeInfo *modeinfo)
634 Bool mipmap_p = True;
637 if (MI_IS_WIREFRAME(modeinfo))
640 if (! screen_to_texture (modeinfo->xgwa.screen, modeinfo->window, 0, 0,
641 mipmap_p, NULL, NULL, &iw, &ih, &tw, &th))
644 max_tx = (GLfloat) iw / tw;
645 max_ty = (GLfloat) ih / th;
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));
652 void init_antspotlight(ModeInfo *mi)
654 double rot_speed = 0.3;
656 antspotlightstruct *mp;
659 if((antspotlight = (antspotlightstruct *)
660 calloc(MI_NUM_SCREENS(mi), sizeof (antspotlightstruct))) == NULL)
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 ();
667 if((mp->glx_context = init_GL(mi)) != NULL) {
668 reshape_antspotlight(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
669 glDrawBuffer(GL_BACK);
675 glGenTextures(1, &screentexture);
676 glBindTexture(GL_TEXTURE_2D, screentexture);
680 mono = MI_IS_MONO(mi);
681 wire = MI_IS_WIREFRAME(mi);
683 /* glNewList(BOARDLIST, GL_COMPILE); */
688 void draw_antspotlight(ModeInfo * mi)
690 antspotlightstruct *mp;
692 Display *display = MI_DISPLAY(mi);
693 Window window = MI_WINDOW(mi);
697 mp = &antspotlight[MI_SCREEN(mi)];
699 MI_IS_DRAWN(mi) = True;
704 glXMakeCurrent(display, window, *(mp->glx_context));
706 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
710 /* position camera */
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]);
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); */
724 draw_antspotlight_strip(mi);
730 if (MI_IS_FPS(mi)) do_fps (mi);
733 glXSwapBuffers(display, window);
736 void change_antspotlight(ModeInfo * mi)
738 antspotlightstruct *mp = &antspotlight[MI_SCREEN(mi)];
740 if (!mp->glx_context)
743 glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(mp->glx_context));