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
18 #define DEFAULTS "*delay: 20000 \n" \
19 "*showFPS: False \n" \
22 # define refresh_antspotlight 0
23 # define release_antspotlight 0
24 #include "xlockmore.h"
32 # include <X11/Xlib.h>
39 #endif /* HAVE_JWZGLES */
44 #include "gltrackball.h"
46 ENTRYPOINT ModeSpecOpt antspotlight_opts = {
47 0, NULL, 0, NULL, NULL
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
59 #define Scale4Window 0.3
60 #define Scale4Iconic 0.4
62 #define sqr(A) ((A)*(A))
69 #include "grab-ximage.h"
72 GLXContext *glx_context;
74 trackball_state *trackball;
77 GLfloat max_tx, max_ty;
78 int mono, wire, ticks;
83 GLfloat spot_direction[3];
87 Bool waiting_for_image_p;
91 static antspotlightstruct *antspotlight = (antspotlightstruct *) NULL;
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))
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);
108 /* Apparently this is a performance killer on many systems...
109 glEnable(GL_POLYGON_SMOOTH);
112 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
114 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->mono ? MaterialGray5 : Material);
115 glEnable(GL_CULL_FACE);
118 if(!((*sphere)(0.18)))
120 glScalef(1, 1 / 1.3, 1);
121 glTranslatef(0.00, 0.30, 0.00);
122 if(!((*sphere)(0.2)))
125 glTranslatef(-0.05, 0.17, 0.05);
126 glRotatef(-90, 1, 0, 0);
127 glRotatef(-25, 0, 1, 0);
130 glTranslatef(0.00, 0.10, 0.00);
133 glRotatef(25, 0, 1, 0);
134 glRotatef(90, 1, 0, 0);
137 glTranslatef(0.15, -0.65, 0.05);
138 if(!((*sphere)(0.25)))
140 glScalef(1, 1 / 1.3, 1);
142 glDisable(GL_CULL_FACE);
144 glDisable(GL_LIGHTING);
147 glEnable(GL_LINE_SMOOTH);
149 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
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);
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);
166 glColor3fv(mp->mono ? MaterialGray6 : MaterialGray5);
167 glVertex3f(0.40, 0.70, 0.40);
169 glVertex3f(0.40, 0.70, -0.40);
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);
180 glColor3fv(MaterialGray);
181 glVertex3f(-0.20 + 0.05 * cos1, 0.25 + 0.1 * sin1, 0.45);
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);
191 glColor3fv(MaterialGray);
192 glVertex3f(-0.20 + 0.05 * cos2, 0.00 + 0.1 * sin2, 0.45);
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);
202 glColor3fv(MaterialGray);
203 glVertex3f(-0.20 + 0.05 * cos3, -0.25 + 0.1 * sin3, 0.45);
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);
213 glColor3fv(MaterialGray);
214 glVertex3f(-0.20 - 0.05 * sin1, 0.25 + 0.1 * cos1, -0.45);
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);
224 glColor3fv(MaterialGray);
225 glVertex3f(-0.20 - 0.05 * sin2, 0.00 + 0.1 * cos2, -0.45);
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);
235 glColor3fv(MaterialGray);
236 glVertex3f(-0.20 - 0.05 * sin3, -0.25 + 0.1 * cos3, -0.45);
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;
253 glEnable(GL_LIGHTING);
259 static Bool mySphere(float radius)
262 GLUquadricObj *quadObj;
264 if((quadObj = gluNewQuadric()) == 0)
267 gluQuadricDrawStyle(quadObj, (GLenum) GLU_FILL);
268 gluSphere(quadObj, radius, 16, 16);
269 gluDeleteQuadric(quadObj);
272 glScalef (radius, radius, radius);
273 glRotatef (90, 1, 0, 0);
274 unit_sphere (16, 16, False);
280 /* silhouette sphere */
281 static Bool mySphere2(float radius)
284 GLUquadricObj *quadObj;
286 if((quadObj = gluNewQuadric()) == 0)
288 gluQuadricDrawStyle(quadObj, (GLenum) GLU_LINE);
289 gluSphere(quadObj, radius, 16, 8);
290 gluDeleteQuadric(quadObj);
292 /* #### no GLU_LINE */
294 glScalef (radius, radius, radius);
295 glRotatef (90, 1, 0, 0);
296 unit_sphere (16, 16, True);
303 static Bool myCone2(float radius) { return True; }
305 static void draw_board(ModeInfo *mi, antspotlightstruct *mp)
308 double cutoff = Pi/3.0;
312 glEnable(GL_TEXTURE_2D);
313 glBindTexture(GL_TEXTURE_2D, mp->screentexture);
314 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialGray6);
318 /* center is roughly spotlight position */
319 center[0] = mp->ant->position[0];/* + cos(ant->direction); */
321 center[2] = mp->ant->position[2];/* - 0.7*sin(ant->direction);*/
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);
326 /* glPolygonMode(GL_FRONT, GL_LINE); */
327 /* glDisable(GL_TEXTURE_2D); */
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.
334 i should be finding the intersection of the cone of light and
337 for(i = -12; i < 12; ++i) {
339 double theta1, theta2;
341 glBegin(GL_TRIANGLE_STRIP);
342 glNormal3f(0.0, 1.0, 0.0);
344 glTexCoord2f(centertex[0], centertex[1]);
345 glVertex3f(center[0], 0.01, center[2]);
347 /* watch those constants */
348 theta1 = mp->ant->direction + i*(cutoff/8);
349 theta2 = mp->ant->direction + (i+1)*(cutoff/8);
351 for(j = 1; j <= 64; ++j) {
352 double point[3], tex[2];
353 /* double fj = pow(1.05, j) - 1.0;*/
355 point[0] = center[0] + fj*cos(theta1);
357 point[2] = center[2] - fj*sin(theta1);
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;
362 glTexCoord2f(tex[0], tex[1]);
363 glVertex3f(point[0], point[1], point[2]);
365 point[0] = center[0] + fj*cos(theta2);
367 point[2] = center[2] - fj*sin(theta2);
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;
372 glTexCoord2f(tex[0], tex[1]);
373 glVertex3f(point[0], point[1], point[2]);
380 glDisable(GL_TEXTURE_2D);
383 /* return euclidean distance between two points */
384 static double distance(double x[3], double y[3])
386 double dx = x[0] - y[0];
387 double dz = x[2] - y[2];
388 return sqrt(dx*dx + dz*dz);
391 /* determine a new goal */
392 static void find_goal(antspotlightstruct *mp)
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;
399 while(distance(mp->ant->position, mp->ant->goal) < 2.0);
402 /* construct our ant */
403 static void build_ant(antspotlightstruct *mp)
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;
418 static double sign(double d)
420 return d < 0.0 ? -1.0 : 1.0;
423 static double min(double a, double b)
425 return a < b ? a : b;
429 static double max(double a, double b)
431 return a > b ? a : b;
435 /* find a new goal and reset steps */
436 static void reset_ant(antspotlightstruct *mp)
441 /* draw ant composed of skeleton and glass */
442 static void show_ant(ModeInfo *mi, antspotlightstruct *mp)
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);
453 draw_ant(mi, mp, mp->ant->material, mp->mono, 0, mp->ant->step, mySphere2, myCone2);
456 if(!mp->wire && !mp->mono) {
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);
467 static void draw_antspotlight_strip(ModeInfo *mi)
469 antspotlightstruct *mp = &antspotlight[MI_SCREEN(mi)];
471 /* compute spotlight position and direction */
472 GLfloat light1_position[4];
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;
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);
483 glLightfv(GL_LIGHT2, GL_POSITION, light1_position);
484 glLightfv(GL_LIGHT2, GL_SPOT_DIRECTION, mp->spot_direction);
487 glDisable(GL_LIGHT0);
488 glDisable(GL_LIGHT1);
496 glDisable(GL_LIGHT2);
503 /* near goal, bend path towards next step */
504 if(distance(mp->ant->position, mp->ant->goal) < 0.2) {
508 if(random()%100 == 0) {
513 /* move toward goal, correct ant direction if required */
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;
521 if(fabs(dx) > EPSILON) {
527 theta = dz > 0.0 ? (1.0/2.0)*Pi : (3.0/2.0)*Pi;
532 ideal = theta - mp->ant->direction;
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;
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;
552 ENTRYPOINT void reshape_antspotlight(ModeInfo * mi, int width, int height)
554 double h = (GLfloat) height / (GLfloat) width;
556 glViewport(0, 0, width, height);
557 glMatrixMode(GL_PROJECTION);
560 gluPerspective(45, 1/h, 1.0, 25.0);
562 glMatrixMode(GL_MODELVIEW);
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 };
580 static void pinit(void)
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);
592 glLightModelfv(GL_LIGHT_MODEL_AMBIENT, spotlight_ambient);
593 glLightModelfv(GL_LIGHT_MODEL_TWO_SIDE, lmodel_twoside);
594 glEnable(GL_LIGHTING);
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);
607 glEnable(GL_NORMALIZE);
611 /* setup material properties */
612 glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, front_shininess);
613 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, front_specular);
615 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
616 glShadeModel(GL_SMOOTH);
617 /* glShadeModel(GL_FLAT); */
618 glEnable(GL_DEPTH_TEST);
621 #define MAX_MAGNIFICATION 10
622 #define max(a, b) a < b ? b : a
623 #define min(a, b) a < b ? a : b
626 ENTRYPOINT Bool antspotlight_handle_event(ModeInfo *mi, XEvent *event)
628 antspotlightstruct *mp = &antspotlight[MI_SCREEN(mi)];
630 if (gltrackball_event_handler (event, mp->trackball,
631 MI_WIDTH (mi), MI_HEIGHT (mi),
635 if (event->xany.type == ButtonPress)
637 switch(event->xbutton.button) {
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));
647 mp->mag = max(mp->mag-1, 1);
651 mp->mag = min(mp->mag+1, MAX_MAGNIFICATION);
660 image_loaded_cb (const char *filename, XRectangle *geometry,
661 int image_width, int image_height,
662 int texture_width, int texture_height,
665 antspotlightstruct *mp = (antspotlightstruct *) closure;
667 mp->max_tx = (GLfloat) image_width / texture_width;
668 mp->max_ty = (GLfloat) image_height / texture_height;
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));
674 mp->waiting_for_image_p = False;
679 static void get_snapshot(ModeInfo *modeinfo)
681 antspotlightstruct *mp = &antspotlight[MI_SCREEN(modeinfo)];
683 if (MI_IS_WIREFRAME(modeinfo))
686 mp->waiting_for_image_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);
694 ENTRYPOINT void init_antspotlight(ModeInfo *mi)
696 double rot_speed = 0.3;
698 antspotlightstruct *mp;
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);
705 if((mp->glx_context = init_GL(mi)) != NULL) {
706 reshape_antspotlight(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
707 glDrawBuffer(GL_BACK);
713 glGenTextures(1, &mp->screentexture);
714 glBindTexture(GL_TEXTURE_2D, mp->screentexture);
718 mp->mono = MI_IS_MONO(mi);
719 mp->wire = MI_IS_WIREFRAME(mi);
724 ENTRYPOINT void draw_antspotlight(ModeInfo * mi)
726 antspotlightstruct *mp;
728 Display *display = MI_DISPLAY(mi);
729 Window window = MI_WINDOW(mi);
733 mp = &antspotlight[MI_SCREEN(mi)];
735 MI_IS_DRAWN(mi) = True;
740 mi->polygon_count = 0;
742 /* Just keep running before the texture has come in. */
743 /* if (mp->waiting_for_image_p) return; */
745 glXMakeCurrent(display, window, *(mp->glx_context));
747 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
750 glRotatef(current_device_rotation(), 0, 0, 1);
752 /* position camera */
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]);
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); */
766 draw_antspotlight_strip(mi);
772 if (MI_IS_FPS(mi)) do_fps (mi);
775 glXSwapBuffers(display, window);
779 ENTRYPOINT void change_antspotlight(ModeInfo * mi)
781 antspotlightstruct *mp = &antspotlight[MI_SCREEN(mi)];
783 if (!mp->glx_context)
786 glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(mp->glx_context));
789 #endif /* !STANDALONE */
791 XSCREENSAVER_MODULE ("AntSpotlight", antspotlight)