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" \
30 #include "xlockmore.h"
37 #include "gltrackball.h"
39 ModeSpecOpt antspotlight_opts = {
40 0, NULL, 0, NULL, NULL
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
52 #define Scale4Window 0.3
53 #define Scale4Iconic 0.4
55 #define sqr(A) ((A)*(A))
62 int tw, th; /* texture width, height */
64 GLfloat max_tx, max_ty;
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;
74 GLXContext *glx_context;
76 trackball_state *trackball;
81 #include "grab-ximage.h"
83 static antspotlightstruct *antspotlight = (antspotlightstruct *) NULL;
87 /* draw method for ant */
88 Bool draw_ant(GLfloat *Material, int mono, int shadow,
89 float ant_step, Bool (*sphere)(float), Bool (*cone)(float)) {
91 float cos1 = cos(ant_step);
92 float cos2 = cos(ant_step + 2 * Pi / 3);
93 float cos3 = cos(ant_step + 4 * Pi / 3);
94 float sin1 = sin(ant_step);
95 float sin2 = sin(ant_step + 2 * Pi / 3);
96 float sin3 = sin(ant_step + 4 * Pi / 3);
98 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mono ? MaterialGray5 : Material);
99 glEnable(GL_CULL_FACE);
102 if(!((*sphere)(0.18)))
104 glScalef(1, 1 / 1.3, 1);
105 glTranslatef(0.00, 0.30, 0.00);
106 if(!((*sphere)(0.2)))
109 glTranslatef(-0.05, 0.17, 0.05);
110 glRotatef(-90, 1, 0, 0);
111 glRotatef(-25, 0, 1, 0);
114 glTranslatef(0.00, 0.10, 0.00);
117 glRotatef(25, 0, 1, 0);
118 glRotatef(90, 1, 0, 0);
121 glTranslatef(0.15, -0.65, 0.05);
122 if(!((*sphere)(0.25)))
124 glScalef(1, 1 / 1.3, 1);
126 glDisable(GL_CULL_FACE);
128 glDisable(GL_LIGHTING);
132 glColor3fv(mono ? MaterialGray5 : Material);
133 glVertex3f(0.00, 0.30, 0.00);
134 glColor3fv(MaterialGray);
135 glVertex3f(0.40, 0.70, 0.40);
136 glColor3fv(mono ? MaterialGray5 : Material);
137 glVertex3f(0.00, 0.30, 0.00);
138 glColor3fv(MaterialGray);
139 glVertex3f(0.40, 0.70, -0.40);
144 glColor3fv(mono ? MaterialGray6 : MaterialGray5);
145 glVertex3f(0.40, 0.70, 0.40);
146 glVertex3f(0.40, 0.70, -0.40);
151 glBegin(GL_LINE_STRIP);
152 glColor3fv(mono ? MaterialGray5 : Material);
153 glVertex3f(0.00, 0.05, 0.18);
154 glVertex3f(0.35 + 0.05 * cos1, 0.15, 0.25);
155 glColor3fv(MaterialGray);
156 glVertex3f(-0.20 + 0.05 * cos1, 0.25 + 0.1 * sin1, 0.45);
159 /* LEFT-CENTER ARM */
160 glBegin(GL_LINE_STRIP);
161 glColor3fv(mono ? MaterialGray5 : Material);
162 glVertex3f(0.00, 0.00, 0.18);
163 glVertex3f(0.35 + 0.05 * cos2, 0.00, 0.25);
164 glColor3fv(MaterialGray);
165 glVertex3f(-0.20 + 0.05 * cos2, 0.00 + 0.1 * sin2, 0.45);
169 glBegin(GL_LINE_STRIP);
170 glColor3fv(mono ? MaterialGray5 : Material);
171 glVertex3f(0.00, -0.05, 0.18);
172 glVertex3f(0.35 + 0.05 * cos3, -0.15, 0.25);
173 glColor3fv(MaterialGray);
174 glVertex3f(-0.20 + 0.05 * cos3, -0.25 + 0.1 * sin3, 0.45);
177 /* RIGHT-FRONT ARM */
178 glBegin(GL_LINE_STRIP);
179 glColor3fv(mono ? MaterialGray5 : Material);
180 glVertex3f(0.00, 0.05, -0.18);
181 glVertex3f(0.35 - 0.05 * sin1, 0.15, -0.25);
182 glColor3fv(MaterialGray);
183 glVertex3f(-0.20 - 0.05 * sin1, 0.25 + 0.1 * cos1, -0.45);
186 /* RIGHT-CENTER ARM */
187 glBegin(GL_LINE_STRIP);
188 glColor3fv(mono ? MaterialGray5 : Material);
189 glVertex3f(0.00, 0.00, -0.18);
190 glVertex3f(0.35 - 0.05 * sin2, 0.00, -0.25);
191 glColor3fv(MaterialGray);
192 glVertex3f(-0.20 - 0.05 * sin2, 0.00 + 0.1 * cos2, -0.45);
196 glBegin(GL_LINE_STRIP);
197 glColor3fv(mono ? MaterialGray5 : Material);
198 glVertex3f(0.00, -0.05, -0.18);
199 glVertex3f(0.35 - 0.05 * sin3, -0.15, -0.25);
200 glColor3fv(MaterialGray);
201 glVertex3f(-0.20 - 0.05 * sin3, -0.25 + 0.1 * cos3, -0.45);
206 glColor3fv(MaterialGray5);
207 glVertex3f(-0.20 + 0.05 * cos1, 0.25 + 0.1 * sin1, 0.45);
208 glVertex3f(-0.20 + 0.05 * cos2, 0.00 + 0.1 * sin2, 0.45);
209 glVertex3f(-0.20 + 0.05 * cos3, -0.25 + 0.1 * sin3, 0.45);
210 glVertex3f(-0.20 - 0.05 * sin1, 0.25 + 0.1 * cos1, -0.45);
211 glVertex3f(-0.20 - 0.05 * sin2, 0.00 + 0.1 * cos2, -0.45);
212 glVertex3f(-0.20 - 0.05 * sin3, -0.25 + 0.1 * cos3, -0.45);
216 glEnable(GL_LIGHTING);
222 static Bool mySphere(float radius) {
223 GLUquadricObj *quadObj;
225 if((quadObj = gluNewQuadric()) == 0)
228 gluQuadricDrawStyle(quadObj, (GLenum) GLU_FILL);
229 gluSphere(quadObj, radius, 16, 16);
230 gluDeleteQuadric(quadObj);
235 /* silhouette sphere */
236 static Bool mySphere2(float radius) {
237 GLUquadricObj *quadObj;
239 if((quadObj = gluNewQuadric()) == 0)
241 gluQuadricDrawStyle(quadObj, (GLenum) GLU_LINE);
242 gluSphere(quadObj, radius, 16, 8);
243 gluDeleteQuadric(quadObj);
249 static Bool myCone2(float radius) { return True; }
253 double boardsize = 8.0;
256 GLfloat spot_direction[3];
258 void draw_board(void) {
260 double cutoff = Pi/3.0;
264 glEnable(GL_TEXTURE_2D);
265 glBindTexture(GL_TEXTURE_2D, screentexture);
266 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialGray6);
270 /* center is roughly spotlight position */
271 center[0] = ant->position[0];/* + cos(ant->direction); */
273 center[2] = ant->position[2];/* - 0.7*sin(ant->direction);*/
275 centertex[0] = (boardsize/2.0+center[0]) * max_tx / boardsize;
276 centertex[1] = max_ty - ((boardsize/2.0+center[2]) * max_ty / boardsize);
278 /* glPolygonMode(GL_FRONT, GL_LINE); */
279 /* glDisable(GL_TEXTURE_2D); */
282 the vertices determined here should correspond to the illuminated
283 board. ideally the code adapts vertex distribution to the
284 intensity and shape of the light.
286 i should be finding the intersection of the cone of light and
289 for(i = -8; i < 8; ++i) {
291 double theta1, theta2;
293 glBegin(GL_TRIANGLE_STRIP);
294 glNormal3f(0.0, 1.0, 0.0);
295 glTexCoord2f(centertex[0], centertex[1]);
296 glVertex3f(center[0], 0.01, center[2]);
298 /* watch those constants */
299 theta1 = ant->direction + i*(cutoff/8);
300 theta2 = ant->direction + (i+1)*(cutoff/8);
302 for(j = 1; j <= 40; ++j) {
303 double point[3], tex[2];
304 /* double fj = pow(1.05, j) - 1.0;*/
306 point[0] = center[0] + fj*cos(theta1);
308 point[2] = center[2] - fj*sin(theta1);
310 tex[0] = (boardsize/2.0+point[0]) * max_tx / boardsize;
311 tex[1] = max_ty - ((boardsize/2.0+point[2]) * max_ty / boardsize);
313 glTexCoord2f(tex[0], tex[1]);
314 glVertex3f(point[0], point[1], point[2]);
316 point[0] = center[0] + fj*cos(theta2);
318 point[2] = center[2] - fj*sin(theta2);
320 tex[0] = (boardsize/2.0+point[0]) * max_tx / boardsize;
321 tex[1] = max_ty - ((boardsize/2.0+point[2]) * max_ty / boardsize);
323 glTexCoord2f(tex[0], tex[1]);
324 glVertex3f(point[0], point[1], point[2]);
330 glDisable(GL_TEXTURE_2D);
333 /* return euclidean distance between two points */
334 double distance(double x[3], double y[3]) {
335 double dx = x[0] - y[0];
336 double dz = x[2] - y[2];
337 return sqrt(dx*dx + dz*dz);
340 /* determine a new goal */
341 void find_goal(void) {
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 */
351 void build_ant(void) {
352 ant = (Ant *) malloc(sizeof (Ant));
353 ant->position[0] = 0.0;
354 ant->position[1] = 0.0;
355 ant->position[2] = 0.0;
356 ant->direction = 0.0;
357 ant->velocity = 0.02;
358 ant->material = MaterialGray5;
365 double sign(double d) {
366 return d < 0.0 ? -1.0 : 1.0;
369 double min(double a, double b) {
370 return a < b ? a : b;
373 double max(double a, double b) {
374 return a > b ? a : b;
377 /* find a new goal and reset steps */
378 void reset_ant(void) {
382 /* draw ant composed of skeleton and glass */
383 void show_ant(void) {
387 /* move into position */
388 glTranslatef(ant->position[0], 0.33, ant->position[2]);
389 glRotatef(180.0 + ant->direction*180.0/Pi, 0.0, 1.0, 0.0);
390 glRotatef(90.0, 0.0, 0.0, 1.0);
393 draw_ant(ant->material, mono, 0, ant->step, mySphere2, myCone2);
398 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialGrayB);
399 glColor4fv(MaterialGrayB);
400 draw_ant(MaterialGrayB, mono, 0, ant->step, mySphere, myCone2);
407 void draw_antspotlight_strip(ModeInfo *mi) {
409 /* compute spotlight position and direction */
410 GLfloat light1_position[4];
412 light1_position[0] = ant->position[0] + 0.7*cos(ant->direction);
413 light1_position[1] = 0.5;
414 light1_position[2] = ant->position[2] - 0.7*sin(ant->direction);
415 light1_position[3] = 1.0;
417 spot_direction[0] = cos(ant->direction);
418 spot_direction[1] = -0.5;
419 spot_direction[2] = -sin(ant->direction);
421 glLightfv(GL_LIGHT2, GL_POSITION, light1_position);
422 glLightfv(GL_LIGHT2, GL_SPOT_DIRECTION, spot_direction);
425 glDisable(GL_LIGHT0);
426 glDisable(GL_LIGHT1);
433 /* glCallList(BOARDLIST); */
435 glDisable(GL_LIGHT2);
442 /* near goal, bend path towards next step */
443 if(distance(ant->position, ant->goal) < 0.2) {
447 /* move toward goal, correct ant direction if required */
451 double dx = ant->goal[0] - ant->position[0];
452 double dz = -(ant->goal[2] - ant->position[2]);
453 double theta, ideal, dt;
455 if(fabs(dx) > EPSILON) {
461 theta = dz > 0.0 ? (1.0/2.0)*Pi : (3.0/2.0)*Pi;
466 ideal = theta - ant->direction;
470 /* compute correction */
471 dt = sign(ideal) * min(fabs(ideal), Pi/100.0);
472 ant->direction += dt;
473 while(ant->direction < 0.0)
474 ant->direction += 2*Pi;
475 while(ant->direction > 2*Pi)
476 ant->direction -= 2*Pi;
479 ant->position[0] += ant->velocity * cos(ant->direction);
480 ant->position[2] += ant->velocity * sin(-ant->direction);
481 ant->step += 10*ant->velocity;
482 while(ant->step > 2*Pi)
486 void reshape_antspotlight(ModeInfo * mi, int width, int height) {
487 double h = (GLfloat) height / (GLfloat) width;
489 antspotlightstruct *mp = &antspotlight[MI_SCREEN(mi)];
491 glViewport(0, 0, mp->WindW = (GLint) width, mp->WindH = (GLint) height);
492 glMatrixMode(GL_PROJECTION);
495 gluPerspective(45, 1/h, 1.0, 25.0);
497 glMatrixMode(GL_MODELVIEW);
502 /* lighting variables */
503 GLfloat front_shininess[] = {60.0};
504 GLfloat front_specular[] = {0.8, 0.8, 0.8, 1.0};
505 GLfloat ambient[] = {0.4, 0.4, 0.4, 1.0};
506 GLfloat ambient2[] = {0.0, 0.0, 0.0, 0.0};
507 GLfloat diffuse[] = {1.0, 1.0, 1.0, 1.0};
508 GLfloat position0[] = {1.0, 5.0, 1.0, 0.0};
509 GLfloat position1[] = {-1.0, -5.0, 1.0, 0.0};
510 GLfloat lmodel_ambient[] = {0.8, 0.8, 0.8, 1.0};
511 GLfloat lmodel_twoside[] = {GL_TRUE};
512 GLfloat spotlight_ambient[] = { 0.0, 0.0, 0.0, 1.0 };
513 GLfloat spotlight_diffuse[] = { 1.0, 1.0, 1.0, 1.0 };
515 static void pinit(void) {
517 glClearColor(0.0, 0.0, 0.0, 1.0);
519 /* setup twoside lighting */
520 glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
521 glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
522 glLightfv(GL_LIGHT0, GL_POSITION, position0);
523 glLightfv(GL_LIGHT1, GL_AMBIENT, ambient);
524 glLightfv(GL_LIGHT1, GL_DIFFUSE, diffuse);
525 glLightfv(GL_LIGHT1, GL_POSITION, position1);
526 /* glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient); */
527 glLightModelfv(GL_LIGHT_MODEL_TWO_SIDE, lmodel_twoside);
528 glEnable(GL_LIGHTING);
532 /* setup spotlight */
533 glLightfv(GL_LIGHT2, GL_AMBIENT, spotlight_ambient);
534 glLightfv(GL_LIGHT2, GL_DIFFUSE, spotlight_diffuse);
535 glLightf(GL_LIGHT2, GL_CONSTANT_ATTENUATION, 0.1);
536 glLightf(GL_LIGHT2, GL_LINEAR_ATTENUATION, 0.05);
537 glLightf(GL_LIGHT2, GL_QUADRATIC_ATTENUATION, 0.0);
538 glLightf(GL_LIGHT2, GL_SPOT_CUTOFF, 60.0);
539 glLightf(GL_LIGHT2, GL_SPOT_EXPONENT, 3.0);
541 glEnable(GL_NORMALIZE);
545 /* setup material properties */
546 glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, front_shininess);
547 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, front_specular);
549 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
550 glShadeModel(GL_SMOOTH);
551 /* glShadeModel(GL_FLAT); */
552 glEnable(GL_DEPTH_TEST);
555 /* cleanup routine */
556 void release_antspotlight(ModeInfo * mi) {
559 free((void *) antspotlight);
560 antspotlight = (antspotlightstruct *) NULL;
567 #define MAX_MAGNIFICATION 10
568 #define max(a, b) a < b ? b : a
569 #define min(a, b) a < b ? a : b
572 Bool antspotlight_handle_event(ModeInfo *mi, XEvent *event) {
573 antspotlightstruct *mp = &antspotlight[MI_SCREEN(mi)];
575 switch(event->xany.type) {
578 switch(event->xbutton.button) {
581 mp->button_down_p = True;
582 gltrackball_start(mp->trackball,
583 event->xbutton.x, event->xbutton.y,
584 MI_WIDTH (mi), MI_HEIGHT (mi));
592 mag = min(mag+1, MAX_MAGNIFICATION);
600 switch(event->xbutton.button) {
602 mp->button_down_p = False;
609 if(mp->button_down_p)
610 gltrackball_track(mp->trackball,
611 event->xmotion.x, event->xmotion.y,
612 MI_WIDTH (mi), MI_HEIGHT (mi));
623 void get_snapshot(ModeInfo *modeinfo) {
627 if(MI_IS_WIREFRAME(modeinfo))
630 ximage = screen_to_ximage(modeinfo->xgwa.screen, modeinfo->window, NULL);
633 tw = modeinfo->xgwa.width;
634 th = modeinfo->xgwa.height;
636 #if 0 /* jwz: this makes the image start off the bottom right of the screen */
641 qw *= (GLfloat)tw/winw;
642 qh *= (GLfloat)th/winh;
644 max_tx = (GLfloat) tw / (GLfloat) ximage->width;
645 max_ty = (GLfloat) th / (GLfloat) ximage->height;
647 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
648 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
649 GL_LINEAR_MIPMAP_LINEAR);
652 status = gluBuild2DMipmaps(GL_TEXTURE_2D, 3,
653 ximage->width, ximage->height,
654 GL_RGBA, GL_UNSIGNED_BYTE, ximage->data);
656 if (!status && glGetError())
657 /* Some implementations of gluBuild2DMipmaps(), but set a GL error anyway.
658 We could just call check_gl_error(), but that would exit. */
662 const unsigned char *s = gluErrorString(status);
663 fprintf(stderr, "%s: error mipmapping %dx%d texture: %s\n",
664 progname, ximage->width, ximage->height,
665 (s ? s : (unsigned char *) "(unknown)"));
666 fprintf(stderr, "%s: turning on -wireframe.\n", progname);
667 MI_IS_WIREFRAME(modeinfo) = 1;
670 check_gl_error("mipmapping"); /* should get a return code instead of a
671 GL error, but just in case... */
675 XDestroyImage (ximage);
678 void init_antspotlight(ModeInfo *mi) {
679 double rot_speed = 0.3;
681 antspotlightstruct *mp;
684 if((antspotlight = (antspotlightstruct *)
685 calloc(MI_NUM_SCREENS(mi), sizeof (antspotlightstruct))) == NULL)
688 mp = &antspotlight[MI_SCREEN(mi)];
689 mp->rot = make_rotator (rot_speed, rot_speed, rot_speed, 1, 0, True);
690 mp->trackball = gltrackball_init ();
692 if((mp->glx_context = init_GL(mi)) != NULL) {
693 reshape_antspotlight(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
694 glDrawBuffer(GL_BACK);
700 glGenTextures(1, &screentexture);
701 glBindTexture(GL_TEXTURE_2D, screentexture);
705 mono = MI_IS_MONO(mi);
706 wire = MI_IS_WIREFRAME(mi);
708 /* glNewList(BOARDLIST, GL_COMPILE); */
713 void draw_antspotlight(ModeInfo * mi) {
714 antspotlightstruct *mp;
716 Display *display = MI_DISPLAY(mi);
717 Window window = MI_WINDOW(mi);
721 mp = &antspotlight[MI_SCREEN(mi)];
723 MI_IS_DRAWN(mi) = True;
728 glXMakeCurrent(display, window, *(mp->glx_context));
730 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
734 /* position camera */
736 /* follow focused ant */
737 glTranslatef(0.0, 0.0, -6.0 - mag);
738 glRotatef(35.0, 1.0, 0.0, 0.0);
739 gltrackball_rotate(mp->trackball);
740 glTranslatef(-ant->position[0], ant->position[1], -ant->position[2]);
742 /* stable position */
743 /* glTranslatef(0.0, 0.0, -10.0 - mag); */
744 /* gltrackball_rotate(mp->trackball); */
745 /* glRotatef(40.0, 1.0, 0.0, 0.0); */
746 /* glRotatef(20.0, 0.0, 1.0, 0.0); */
748 draw_antspotlight_strip(mi);
754 if (MI_IS_FPS(mi)) do_fps (mi);
757 glXSwapBuffers(display, window);
760 void change_antspotlight(ModeInfo * mi) {
761 antspotlightstruct *mp = &antspotlight[MI_SCREEN(mi)];
763 if (!mp->glx_context)
766 glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(mp->glx_context));