1 /* vigilance, Copyright (c) 2017 Jamie Zawinski <jwz@jwz.org>
3 * Permission to use, copy, modify, distribute, and sell this software and its
4 * documentation for any purpose is hereby granted without fee, provided that
5 * the above copyright notice appear in all copies and that both that
6 * copyright notice and this permission notice appear in supporting
7 * documentation. No representations are made about the suitability of this
8 * software for any purpose. It is provided "as is" without express or
11 * Draws surveillance cameras, taking an interest in their surroundings.
14 #define DEFAULTS "*delay: 20000 \n" \
16 "*showFPS: False \n" \
17 "*wireframe: False \n" \
18 "*bodyColor: #666666" "\n" \
19 "*capColor: #FFFFFF" "\n" \
20 "*hingeColor: #444444" "\n" \
21 "*mountColor: #444444" "\n" \
22 "*lensColor: #000000" "\n" \
23 "*groundColor: #004400" "\n" \
25 # define refresh_camera 0
26 # define release_camera 0
28 #define countof(x) (sizeof((x))/sizeof((*x)))
30 #define DEF_SPEED "1.0"
31 #define DEF_CAMERA_SIZE "1.0"
33 #include "xlockmore.h"
34 #include "gltrackball.h"
35 #include "xpm-ximage.h"
40 #ifdef USE_GL /* whole file */
43 #define ABS(x) ((x)<0?-(x):(x))
45 #define MAX(A,B) ((A)>(B)?(A):(B))
47 #define MIN(A,B) ((A)<(B)?(A):(B))
49 #define BELLRAND(n) ((frand((n)) + frand((n)) + frand((n))) / 3)
53 extern const struct gllist
54 *seccam_body, *seccam_cap, *seccam_hinge, *seccam_pipe, *seccam_lens;
55 static struct gllist *ground = 0;
57 static const struct gllist * const *all_objs[] = {
58 &seccam_body, &seccam_cap, &seccam_hinge, &seccam_pipe, &seccam_lens,
59 (const struct gllist * const *) &ground
64 #define CAMERA_HINGE 2
65 #define CAMERA_MOUNT 3
69 #define BEAM_ZOFF 0.185 /* distance from origin to lens in model */
71 typedef enum { IDLE, WARM_UP, ZOT, COOL_DOWN } camera_state;
76 GLfloat facing; /* rotation around vertical axis, degrees */
77 GLfloat pitch; /* front/back tilt, degrees */
78 GLfloat velocity; /* most recent angular velocity, degrees */
79 long focus_id; /* pedestrian or camera of interest */
80 XYZ focus; /* point of interest */
85 typedef struct pedestrian pedestrian;
90 GLfloat frequency, amplitude;
97 GLXContext *glx_context;
98 trackball_state *user_trackball;
102 GLfloat component_colors[countof(all_objs)][4];
106 pedestrian *pedestrians;
107 } camera_configuration;
109 static camera_configuration *bps = NULL;
111 static GLfloat speed_arg;
116 static XrmOptionDescRec opts[] = {
117 { "-speed", ".speed", XrmoptionSepArg, 0 },
119 {"-debug", ".debug", XrmoptionNoArg, "True" },
120 {"+debug", ".debug", XrmoptionNoArg, "False" },
124 static argtype vars[] = {
125 {&speed_arg, "speed", "Speed", DEF_SPEED, t_Float},
127 {&debug_p, "debug", "Debug", "False", t_Bool},
131 ENTRYPOINT ModeSpecOpt camera_opts = {
132 countof(opts), opts, countof(vars), vars, NULL};
136 reshape_camera (ModeInfo *mi, int width, int height)
138 GLfloat h = (GLfloat) height / (GLfloat) width;
139 glViewport (0, 0, width, height);
140 glMatrixMode(GL_PROJECTION);
142 gluPerspective (30.0, 1/h, 1.0, 200);
143 glMatrixMode(GL_MODELVIEW);
149 # ifdef HAVE_MOBILE /* Keep it the same relative size when rotated. */
151 int o = (int) current_device_rotation();
152 if (o != 0 && o != 180 && o != -180)
153 glScalef (1/h, 1/h, 1/h);
157 glClear(GL_COLOR_BUFFER_BIT);
162 camera_handle_event (ModeInfo *mi, XEvent *event)
164 camera_configuration *bp = &bps[MI_SCREEN(mi)];
166 if (gltrackball_event_handler (event, bp->user_trackball,
167 MI_WIDTH (mi), MI_HEIGHT (mi),
170 else if (event->xany.type == KeyPress)
174 XLookupString (&event->xkey, &c, 1, &keysym, 0);
175 if (c == ' ' || c == '\t')
178 if (bp->cameras[0].state == IDLE && bp->pedestrians)
179 for (i = 0; i < bp->ncameras; i++)
181 bp->cameras[i].state = WARM_UP;
182 bp->cameras[i].tick = 1.0;
192 static int draw_ground (ModeInfo *, GLfloat color[4]);
195 parse_color (ModeInfo *mi, char *key, GLfloat color[4])
198 char *string = get_string_resource (mi->dpy, key, "CameraColor");
199 if (!XParseColor (mi->dpy, mi->xgwa.colormap, string, &xcolor))
201 fprintf (stderr, "%s: unparsable color in %s: %s\n", progname,
206 color[0] = xcolor.red / 65536.0;
207 color[1] = xcolor.green / 65536.0;
208 color[2] = xcolor.blue / 65536.0;
214 init_camera (ModeInfo *mi)
216 camera_configuration *bp;
217 int wire = MI_IS_WIREFRAME(mi);
219 MI_INIT (mi, bps, 0);
221 bp = &bps[MI_SCREEN(mi)];
223 bp->glx_context = init_GL(mi);
225 reshape_camera (mi, MI_WIDTH(mi), MI_HEIGHT(mi));
227 glShadeModel(GL_SMOOTH);
229 glEnable(GL_DEPTH_TEST);
230 glEnable(GL_NORMALIZE);
231 glEnable(GL_CULL_FACE);
235 GLfloat pos[4] = {0.4, 0.2, 0.4, 0.0};
236 GLfloat amb[4] = {0.2, 0.2, 0.2, 1.0};
237 GLfloat dif[4] = {1.0, 1.0, 1.0, 1.0};
238 GLfloat spc[4] = {1.0, 1.0, 1.0, 1.0};
240 glEnable(GL_LIGHTING);
242 glEnable(GL_DEPTH_TEST);
243 glEnable(GL_CULL_FACE);
245 glLightfv(GL_LIGHT0, GL_POSITION, pos);
246 glLightfv(GL_LIGHT0, GL_AMBIENT, amb);
247 glLightfv(GL_LIGHT0, GL_DIFFUSE, dif);
248 glLightfv(GL_LIGHT0, GL_SPECULAR, spc);
251 bp->user_trackball = gltrackball_init (False);
253 bp->dlists = (GLuint *) calloc (countof(all_objs)+1, sizeof(GLuint));
254 for (i = 0; i < countof(all_objs); i++)
255 bp->dlists[i] = glGenLists (1);
257 for (i = 0; i < countof(all_objs); i++)
259 const struct gllist *gll = *all_objs[i];
261 GLfloat spec1[4] = {1.00, 1.00, 1.00, 1.0};
262 GLfloat spec2[4] = {0.40, 0.40, 0.70, 1.0};
263 GLfloat *spec = spec1;
266 glNewList (bp->dlists[i], GL_COMPILE);
268 glMatrixMode(GL_MODELVIEW);
270 glMatrixMode(GL_TEXTURE);
272 glMatrixMode(GL_MODELVIEW);
274 glRotatef (-90, 1, 0, 0);
275 glRotatef (180, 0, 0, 1);
278 glBindTexture (GL_TEXTURE_2D, 0);
281 case CAMERA_BODY: key = "bodyColor"; break;
282 case CAMERA_CAP: key = "capColor"; break;
283 case CAMERA_HINGE: key = "hingeColor"; break;
284 case CAMERA_MOUNT: key = "mountColor"; break;
285 case CAMERA_LENS: key = "lensColor"; spec = spec2; break;
286 case GROUND: key = "groundColor"; spec = spec2; shiny = 128; break;
287 default: abort(); break;
290 parse_color (mi, key, bp->component_colors[i]);
292 glMaterialfv (GL_FRONT_AND_BACK, GL_SPECULAR, spec);
293 glMaterialf (GL_FRONT_AND_BACK, GL_SHININESS, shiny);
298 ground = (struct gllist *) calloc (1, sizeof(*ground));
299 ground->points = draw_ground (mi, bp->component_colors[i]);
302 renderList (gll, wire);
303 /* glColor3f (1, 1, 1); renderListNormals (gll, 100, True); */
304 /* glColor3f (1, 1, 0); renderListNormals (gll, 100, False); */
308 glMatrixMode(GL_TEXTURE);
310 glMatrixMode(GL_MODELVIEW);
316 bp->ncameras = MI_COUNT(mi);
317 if (bp->ncameras <= 0) bp->ncameras = 1;
318 bp->cameras = (camera *) calloc (bp->ncameras, sizeof (camera));
321 GLfloat range = (MI_COUNT(mi) <= 2) ? 4 : 5.5;
323 GLfloat spacing = range / bp->ncameras;
324 if (spacing < 0.7) spacing = 0.7;
325 extent = spacing * (bp->ncameras - 1);
326 for (i = 0; i < bp->ncameras; i++)
328 camera *c = &bp->cameras[i];
330 c->pos.x = i*spacing - extent/2;
333 c->pos.z = (i & 1 ? 1.1 : -0.3);
334 c->focus.x = c->pos.x;
335 c->focus.y = c->pos.y + 1;
336 c->focus.z = c->pos.z + BEAM_ZOFF;
345 /* Let's tilt the floor a little. */
346 gltrackball_reset (bp->user_trackball,
348 -0.30 + frand(0.40));
355 GLfloat d = sqrt(p.x*p.x + p.y*p.y * p.z*p.z);
370 vector_angle (XYZ a, XYZ b)
372 double La = sqrt (a.x*a.x + a.y*a.y + a.z*a.z);
373 double Lb = sqrt (b.x*b.x + b.y*b.y + b.z*b.z);
376 if (La == 0 || Lb == 0) return 0;
377 if (a.x == b.x && a.y == b.y && a.z == b.z) return 0;
379 /* dot product of two vectors is defined as:
380 La * Lb * cos(angle between vectors)
381 and is also defined as:
382 ax*bx + ay*by + az*bz
384 La * Lb * cos(angle) = ax*bx + ay*by + az*bz
385 cos(angle) = (ax*bx + ay*by + az*bz) / (La * Lb)
386 angle = acos ((ax*bx + ay*by + az*bz) / (La * Lb));
388 cc = (a.x*b.x + a.y*b.y + a.z*b.z) / (La * Lb);
389 if (cc > 1) cc = 1; /* avoid fp rounding error (1.000001 => sqrt error) */
397 draw_component (ModeInfo *mi, int i, GLfloat color[4])
399 camera_configuration *bp = &bps[MI_SCREEN(mi)];
401 color = bp->component_colors[i];
402 glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, color);
403 glCallList (bp->dlists[i]);
404 return (*all_objs[i])->points / 3;
409 draw_double_component (ModeInfo *mi, int i)
411 int count = draw_component (mi, i, 0);
415 count += draw_component (mi, i, 0);
423 draw_ray (ModeInfo *mi, camera *c)
425 int wire = MI_IS_WIREFRAME(mi);
427 GLfloat length = 10000;
428 GLfloat thickness = 0.08;
432 glTranslatef (c->pos.x, c->pos.y, c->pos.z + BEAM_ZOFF);
433 glRotatef (-c->facing, 0, 0, 1);
434 glRotatef ( c->pitch, 1, 0, 0);
435 glRotatef (frand(90), 0, 1, 0);
436 glScalef (thickness, length, thickness);
437 glDisable (GL_LIGHTING);
439 for (i = 0; i < 5; i++)
441 glColor4f (1, 0, 0, 0.1 + (i * 0.18));
442 glBegin (wire ? GL_LINE_LOOP : GL_QUADS);
443 glVertex3f (0, 0, -0.5); glVertex3f (0, 0, 0.5);
444 glVertex3f (0, 1, 0.5); glVertex3f (0, 1, -0.5);
447 glBegin (wire ? GL_LINE_LOOP : GL_QUADS);
448 glVertex3f (-0.5, 0, 0); glVertex3f ( 0.5, 0, 0);
449 glVertex3f ( 0.5, 1, 0); glVertex3f (-0.5, 1, 0);
452 glBegin (wire ? GL_LINE_LOOP : GL_QUADS);
453 glVertex3f (0, 1, -0.5); glVertex3f (0, 1, 0.5);
454 glVertex3f (0, 0, 0.5); glVertex3f (0, 0, -0.5);
457 glBegin (wire ? GL_LINE_LOOP : GL_QUADS);
458 glVertex3f (-0.5, 1, 0); glVertex3f ( 0.5, 1, 0);
459 glVertex3f ( 0.5, 0, 0); glVertex3f (-0.5, 0, 0);
462 glScalef (0.7, 1, 0.7);
464 if (!MI_IS_WIREFRAME(mi))
465 glEnable (GL_LIGHTING);
472 draw_camera_1 (ModeInfo *mi, camera *c)
475 GLfloat scale = 0.01;
476 GLfloat color[4] = { 1, 0, 0, 1 };
479 glTranslatef (c->pos.x, c->pos.y, c->pos.z);
480 glScalef (scale, scale, scale);
482 glRotatef (90, 1, 0, 0);
483 glRotatef (-90, 0, 1, 0);
485 count += draw_double_component (mi, CAMERA_MOUNT);
487 glRotatef (-c->facing, 0, 1, 0);
488 glRotatef (-c->pitch, 0, 0, 1);
490 count += draw_double_component (mi, CAMERA_HINGE);
492 if (c->state == WARM_UP)
495 glTranslatef ((0.2 - c->tick) / (scale * 3), 0, 0);
500 glTranslatef ((0.005 - frand(0.01)) / scale,
501 (0.005 - frand(0.01)) / scale,
502 (0.005 - frand(0.01)) / scale);
505 count += draw_double_component (mi, CAMERA_BODY);
509 glTranslatef ((0.005 - frand(0.01)) / scale,
510 (0.005 - frand(0.01)) / scale,
511 (0.005 - frand(0.01)) / scale);
514 count += draw_double_component (mi, CAMERA_CAP);
518 case WARM_UP: color[0] = 1.0 - c->tick; break;
519 case ZOT: color[0] = 1.0; break;
520 case COOL_DOWN: color[0] = c->tick; break;
521 default: abort(); break;
524 count += draw_component (mi, CAMERA_LENS,
525 (c->state == IDLE ? 0 : color));
528 if (debug_p && c->state != ZOT)
530 glDisable (GL_LIGHTING);
533 glVertex3f (0, BEAM_ZOFF / scale, 0);
534 glVertex3f (-100 / scale, BEAM_ZOFF / scale, 0);
536 if (!MI_IS_WIREFRAME(mi))
537 glEnable (GL_LIGHTING);
547 /* The position this pedestrian would appear at during the given ratio
548 through its life cycle.
551 pedestrian_position (pedestrian *p, GLfloat ratio)
556 pos.x += p->length * ratio;
557 pos.z += sin (M_PI * ratio * p->frequency * 2) * p->amplitude
564 draw_pedestrian (ModeInfo *mi, pedestrian *p)
571 GLfloat step = 0.001;
572 glDisable (GL_LIGHTING);
575 glBegin (GL_LINE_STRIP);
576 glVertex3f (p->pos.x, p->pos.y, p->pos.z + p->amplitude);
577 glVertex3f (p->pos.x, p->pos.y, 0);
578 glVertex3f (p->pos.x + p->length, p->pos.y, 0);
579 glVertex3f (p->pos.x + p->length, p->pos.y, p->pos.z + p->amplitude);
582 glBegin (GL_LINE_STRIP);
583 for (r = 0; r <= 1; r += step)
585 XYZ pos = pedestrian_position (p, r);
586 glVertex3f (pos.x, pos.y, pos.z);
588 if (p->ratio >= r && p->ratio < r + step)
590 glVertex3f (pos.x, pos.y, pos.z - p->amplitude);
591 glVertex3f (pos.x, pos.y, pos.z + p->amplitude);
592 glVertex3f (pos.x, pos.y, pos.z);
597 if (!MI_IS_WIREFRAME(mi))
598 glEnable (GL_LIGHTING);
605 /* Start someone walking through the scene.
608 add_pedestrian (ModeInfo *mi)
610 camera_configuration *bp = &bps[MI_SCREEN(mi)];
611 pedestrian *p = (pedestrian *) calloc (1, sizeof(*p));
616 p->pos.x = -p->length/2;
617 p->pos.y = 3 + frand(10);
618 p->pos.z = -1.5 + frand(4) + ((random() % 10) ? 0 : frand(8));
619 p->frequency = 4 + frand(4);
620 p->amplitude = 0.1 + ((random() % 10) ? BELLRAND(0.45) : BELLRAND(1.5));
622 p->speed = ((4 + frand(4) + ((random() % 10) ? 0 : frand(10)))
623 * (random() & 1 ? 1 : -1)
628 pedestrian *p2; /* add it to the end */
629 for (p2 = bp->pedestrians; p2->next; p2 = p2->next)
635 p->next = bp->pedestrians;
642 free_pedestrian (ModeInfo *mi, pedestrian *p)
644 camera_configuration *bp = &bps[MI_SCREEN(mi)];
647 if (p == bp->pedestrians)
649 bp->pedestrians = p->next;
655 for (p0 = bp->pedestrians; p0; p0 = p0->next)
658 p0->next = p0->next ? p0->next->next : 0;
670 tick_pedestrian (ModeInfo *mi, pedestrian *p)
672 p->ratio += 0.001 * (p->speed > 0 ? p->speed : -p->speed);
674 free_pedestrian (mi, p);
678 /* Extract the position of the thing this camera would like to look at.
681 set_camera_focus (ModeInfo *mi, camera *c)
683 camera_configuration *bp = &bps[MI_SCREEN(mi)];
685 if (c->focus_id > 0) /* Look at pedestrian with id N */
687 long id = c->focus_id;
689 for (p = bp->pedestrians; p; p = p->next)
693 c->focus = pedestrian_position (p, p->ratio);
695 c->focus_id = 0; /* that pedestrian has escaped */
697 else if (c->focus_id < 0) /* Look at camera -N-1 */
699 long n = -c->focus_id - 1;
700 if (bp->ncameras > n)
701 c->focus = bp->cameras[n].pos;
707 tick_camera (ModeInfo *mi, camera *c)
709 camera_configuration *bp = &bps[MI_SCREEN(mi)];
712 set_camera_focus (mi, c);
714 X = c->focus.x - c->pos.x;
715 Y = c->focus.y - c->pos.y;
716 Z = c->focus.z - c->pos.z - BEAM_ZOFF;
718 if (X != 0 || Y != 0)
720 GLfloat ofacing = c->facing;
721 GLfloat opitch = c->pitch;
723 GLfloat target_facing = atan2 (X, Y) * (180 / M_PI);
724 GLfloat target_pitch = atan2 (Z, sqrt(X*X + Y*Y)) * (180 / M_PI);
726 /* Adjust the current velocity.
727 If we are nearing the target, slow down (but don't stop).
728 Otherwise, speed up (but don't break the speed limit).
731 GLfloat accel = 0.5 * speed_arg;
732 GLfloat decel_range = 20;
733 GLfloat max_velocity = 5 * speed_arg;
734 GLfloat close_enough = 0.5 * speed_arg;
736 GLfloat dx = target_facing - c->facing;
737 GLfloat dy = target_pitch - c->pitch;
738 GLfloat angular_distance = sqrt (dx*dx + dy*dy);
740 /* Split the velocity into vx and vy components. This isn't
741 quite right since this treats them as Cartesian rather than
742 polar, but it's close enough.
744 GLfloat r = (dx == 0) ? 1 : ABS(dy) / ABS(dx);
748 if (angular_distance < decel_range) /* Nearing target, slow down */
750 c->velocity -= accel;
751 if (c->velocity <= 0)
756 c->velocity += accel;
757 if (c->velocity > max_velocity)
758 c->velocity = max_velocity;
761 /* Don't overshoot */
762 if (vx > ABS(dx)) vx = ABS(dx);
763 if (vy > ABS(dy)) vy = ABS(dy);
766 /* Rotate toward target by current angular velocity. */
767 c->facing += vx * c->velocity * (target_facing > c->facing ? 1 : -1);
768 c->pitch += vy * c->velocity * (target_pitch > c->pitch ? 1 : -1);
770 /* If we are pointed *really close* to the target, just lock on,
771 to avoid twitchy overshoot rounding errors.
773 if (angular_distance < close_enough)
775 c->facing = target_facing;
776 c->pitch = target_pitch;
779 /* Constrain to hinge's range of motion */
780 c->facing = MAX (-90, MIN (90, c->facing));
781 c->pitch = MAX (-90, MIN (55, c->pitch));
783 /* After this motion, our prevailing velocity (for next time)
784 is the angular distance we actually moved.
786 dx = c->facing - ofacing;
787 dy = c->pitch - opitch;
788 c->velocity = sqrt (dx*dx + dy*dy);
794 /* Mark the point on which this camera is focusing. */
797 glDisable (GL_LIGHTING);
798 glColor3f(0.3, 0.3, 0.3);
800 glVertex3f (c->pos.x, c->pos.y, c->pos.z + BEAM_ZOFF);
801 glVertex3f (c->focus.x, c->focus.y, c->focus.z);
805 glVertex3f (c->focus.x-0.25, c->focus.y, c->focus.z);
806 glVertex3f (c->focus.x+0.25, c->focus.y, c->focus.z);
807 glVertex3f (c->focus.x, c->focus.y-0.25, c->focus.z);
808 glVertex3f (c->focus.x, c->focus.y+0.25, c->focus.z);
809 glVertex3f (c->focus.x, c->focus.y, c->focus.z-0.25);
810 glVertex3f (c->focus.x, c->focus.y, c->focus.z+0.25);
812 if (!MI_IS_WIREFRAME(mi))
813 glEnable (GL_LIGHTING);
818 /* If this camera is looking at another camera, get shy and look away
819 if the target sees us looking.
823 camera *c2 = &bp->cameras[-1 - c->focus_id];
825 GLfloat aa = c->facing / (180 / M_PI);
826 GLfloat bb = c->pitch / (180 / M_PI);
829 a.y = cos(aa)* cos(bb);
830 a.x = sin(aa)* cos(bb);
833 aa = c2->facing / (180 / M_PI);
834 bb = c2->pitch / (180 / M_PI);
835 b.y = cos(aa)* cos(bb);
836 b.x = sin(aa)* cos(bb);
839 angle = vector_angle (normalize(a), normalize(b)) * (180 / M_PI);
844 /* Look "away" which means in the same direction. */
845 c->focus.x = c->pos.x + (c2->focus.x - c2->pos.x);
846 c->focus.y = c->pos.y + (c2->focus.y - c2->pos.y);
847 c->focus.z = c->pos.z + (c2->focus.z - c2->pos.z);
848 /* Look at either the sky or the ground.*/
849 c->focus.z = c->focus.x * (random() & 1 ? 1 : -1) * 5;
850 c->velocity = c2->velocity * 3;
855 /* Randomly pick some other things to look at.
858 if (c->state == IDLE &&
860 ? !(random() % (int) MAX (1, (50 / speed_arg)))
861 : !(random() % (int) MAX (1, (1000 / speed_arg)))))
864 /* Shiny! Start paying attention to something else. */
866 if ((bp->ncameras > 1 && !(random() % 20))) /* look at a camera */
868 int which = random() % 4;
870 for (i = 0; i < bp->ncameras; i++)
871 if (c == &bp->cameras[i])
874 /* Look at cameras 1 or 2 away in each direction, but not farther.
875 Since we arrange them in 2 staggered lines, those are the only
876 four that are in line of sight.
878 if (i >= 2 && which == 0)
880 else if (i >= 1 && which == 1)
882 else if (i < bp->ncameras-1 && which == 2)
884 else /* (i < bp->ncameras-2 && which == 3) */
887 c->focus_id = -1 - which;
889 else /* look at a pedestrian */
893 for (p = bp->pedestrians; p; p = p->next)
907 /* Run the animation */
909 if (c->state != IDLE)
911 pedestrian *p = bp->pedestrians; /* first one */
912 if (p) c->focus_id = p->id;
915 case WARM_UP: c->tick -= 0.01 * speed_arg; break;
916 case ZOT: c->tick -= 0.006 * speed_arg;
917 if (p) p->speed *= 0.995; /* target takes 1d6 HP damage */
919 case COOL_DOWN: c->tick -= 0.02 * speed_arg; break;
920 default: abort(); break;
927 case WARM_UP: c->state = ZOT; break;
928 case ZOT: c->state = COOL_DOWN;
930 if (p) p->ratio = 1.0; /* threat eliminated */
932 case COOL_DOWN: c->state = IDLE; break;
933 default: abort(); break;
938 if (bp->cameras[0].state == IDLE &&
940 bp->pedestrians[0].ratio < 0.3 &&
941 !(random() % MAX (1, (int) (50000 / speed_arg))))
943 /* CASE NIGHTMARE RED detected, engage SCORPION STARE by authority
944 of MAGINOT BLUE STARS. */
946 for (i = 0; i < bp->ncameras; i++)
948 bp->cameras[i].state = WARM_UP;
949 bp->cameras[i].tick = 1.0;
956 draw_ground (ModeInfo *mi, GLfloat color[4])
958 int wire = MI_IS_WIREFRAME(mi);
961 /* When using fog, iOS apparently doesn't like lines or quads that are
962 really long, and extend very far outside of the scene. Maybe? If the
963 length of the line (cells * cell_size) is greater than 25 or so, lines
964 that are oriented steeply away from the viewer tend to disappear
965 (whether implemented as GL_LINES or as GL_QUADS).
967 So we do a bunch of smaller grids instead of one big one.
970 GLfloat cell_size = 0.4;
979 GLfloat fog_color[4] = { 0, 0, 0, 1 };
982 glEnable (GL_LINE_SMOOTH);
983 glHint (GL_LINE_SMOOTH_HINT, GL_NICEST);
984 glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
987 glFogi (GL_FOG_MODE, GL_EXP2);
988 glFogfv (GL_FOG_COLOR, fog_color);
989 glFogf (GL_FOG_DENSITY, 0.017);
990 glFogf (GL_FOG_START, -cells/2 * cell_size * gridsh);
995 glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, color);
997 glTranslatef (-cells * gridsw * cell_size / 2, 0, 0);
998 for (h = 0; h < 2; h++)
1001 glTranslatef (0, cells * cell_size / 2, 0);
1002 for (j = 0; j < gridsh; j++)
1005 for (k = 0; k < gridsw; k++)
1008 for (i = -cells/2; i < cells/2; i++)
1010 GLfloat a = i * cell_size;
1011 GLfloat b = cells/2 * cell_size;
1012 glVertex3f (a, -b, 0); glVertex3f (a, b, 0); points++;
1013 glVertex3f (-b, a, 0); glVertex3f (b, a, 0); points++;
1016 glTranslatef (cells * cell_size, 0, 0);
1019 glTranslatef (0, cells * cell_size, 0);
1022 glRotatef (90, 1, 0, 0);
1026 glDisable (GL_LINE_SMOOTH);
1035 draw_camera (ModeInfo *mi)
1037 camera_configuration *bp = &bps[MI_SCREEN(mi)];
1038 Display *dpy = MI_DISPLAY(mi);
1039 Window window = MI_WINDOW(mi);
1040 GLfloat camera_size;
1043 if (!bp->glx_context)
1046 glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(bp->glx_context));
1048 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1053 glRotatef (current_device_rotation(), 0, 0, 1); /* right side up */
1056 gltrackball_rotate (bp->user_trackball);
1070 glRotatef (30, 0, 1, 0);
1071 glRotatef (15, 1, 0, 0);
1072 glTranslatef (0, 0, -80);
1076 mi->polygon_count = 0;
1080 if (MI_COUNT(mi) <= 2) /* re-frame the scene a little bit */
1081 glTranslatef (0, -1, 7);
1082 if (MI_COUNT(mi) >= 20)
1083 glTranslatef (0, -1.5, -5);
1084 if (MI_COUNT(mi) >= 40)
1085 glTranslatef (0, 2, -15);
1087 glScalef (camera_size, camera_size, camera_size);
1089 /* +Z is toward sky; +X is toward the right along the back wall;
1090 +Y is toward the viewer. */
1091 glRotatef (-90, 1, 0, 0);
1092 glScalef (1, -1, 1);
1095 glScalef (1/camera_size, 1/camera_size, 1/camera_size);
1096 glTranslatef (0, -2.38, -8); /* Move the ground down and back */
1097 glCallList (bp->dlists[GROUND]);
1098 mi->polygon_count += ground->points;
1104 for (p = bp->pedestrians, p2 = p ? p->next : 0;
1106 p = p2, p2 = p2 ? p2->next : 0)
1108 mi->polygon_count += draw_pedestrian (mi, p);
1109 tick_pedestrian (mi, p); /* might free p */
1112 if (!bp->pedestrians || !(random() % MAX (1, (int) (200 / speed_arg))))
1113 add_pedestrian (mi);
1116 for (i = 0; i < bp->ncameras; i++)
1118 camera *c = &bp->cameras[i];
1119 mi->polygon_count += draw_camera_1 (mi, c);
1120 tick_camera (mi, c);
1123 for (i = 0; i < bp->ncameras; i++)
1125 camera *c = &bp->cameras[i];
1126 if (c->state == ZOT) /* Do this last, for alpha blending */
1127 mi->polygon_count += draw_ray (mi, c);
1132 if (mi->fps_p) do_fps (mi);
1135 glXSwapBuffers(dpy, window);
1138 XSCREENSAVER_MODULE_2 ("Vigilance", vigilance, camera)