1 /* vigilance, Copyright (c) 2017-2018 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 free_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 "ximage-loader.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;
141 if (width > height * 5) { /* tiny window: show middle */
142 height = width * 9/16;
144 h = height / (GLfloat) width;
147 glViewport (0, y, width, height);
148 glMatrixMode(GL_PROJECTION);
150 gluPerspective (30.0, 1/h, 1.0, 200);
151 glMatrixMode(GL_MODELVIEW);
157 # ifdef HAVE_MOBILE /* Keep it the same relative size when rotated. */
159 int o = (int) current_device_rotation();
160 if (o != 0 && o != 180 && o != -180)
161 glScalef (1/h, 1/h, 1/h);
165 glClear(GL_COLOR_BUFFER_BIT);
170 camera_handle_event (ModeInfo *mi, XEvent *event)
172 camera_configuration *bp = &bps[MI_SCREEN(mi)];
174 if (gltrackball_event_handler (event, bp->user_trackball,
175 MI_WIDTH (mi), MI_HEIGHT (mi),
178 else if (event->xany.type == KeyPress)
182 XLookupString (&event->xkey, &c, 1, &keysym, 0);
183 if (c == ' ' || c == '\t')
186 if (bp->cameras[0].state == IDLE && bp->pedestrians)
187 for (i = 0; i < bp->ncameras; i++)
189 bp->cameras[i].state = WARM_UP;
190 bp->cameras[i].tick = 1.0;
200 static int draw_ground (ModeInfo *, GLfloat color[4]);
203 parse_color (ModeInfo *mi, char *key, GLfloat color[4])
206 char *string = get_string_resource (mi->dpy, key, "CameraColor");
207 if (!XParseColor (mi->dpy, mi->xgwa.colormap, string, &xcolor))
209 fprintf (stderr, "%s: unparsable color in %s: %s\n", progname,
214 color[0] = xcolor.red / 65536.0;
215 color[1] = xcolor.green / 65536.0;
216 color[2] = xcolor.blue / 65536.0;
222 init_camera (ModeInfo *mi)
224 camera_configuration *bp;
225 int wire = MI_IS_WIREFRAME(mi);
229 bp = &bps[MI_SCREEN(mi)];
231 bp->glx_context = init_GL(mi);
233 reshape_camera (mi, MI_WIDTH(mi), MI_HEIGHT(mi));
235 glShadeModel(GL_SMOOTH);
237 glEnable(GL_DEPTH_TEST);
238 glEnable(GL_NORMALIZE);
239 glEnable(GL_CULL_FACE);
243 GLfloat pos[4] = {0.4, 0.2, 0.4, 0.0};
244 GLfloat amb[4] = {0.2, 0.2, 0.2, 1.0};
245 GLfloat dif[4] = {1.0, 1.0, 1.0, 1.0};
246 GLfloat spc[4] = {1.0, 1.0, 1.0, 1.0};
248 glEnable(GL_LIGHTING);
250 glEnable(GL_DEPTH_TEST);
251 glEnable(GL_CULL_FACE);
253 glLightfv(GL_LIGHT0, GL_POSITION, pos);
254 glLightfv(GL_LIGHT0, GL_AMBIENT, amb);
255 glLightfv(GL_LIGHT0, GL_DIFFUSE, dif);
256 glLightfv(GL_LIGHT0, GL_SPECULAR, spc);
259 bp->user_trackball = gltrackball_init (False);
261 bp->dlists = (GLuint *) calloc (countof(all_objs)+1, sizeof(GLuint));
262 for (i = 0; i < countof(all_objs); i++)
263 bp->dlists[i] = glGenLists (1);
265 for (i = 0; i < countof(all_objs); i++)
267 const struct gllist *gll = *all_objs[i];
269 GLfloat spec1[4] = {1.00, 1.00, 1.00, 1.0};
270 GLfloat spec2[4] = {0.40, 0.40, 0.70, 1.0};
271 GLfloat *spec = spec1;
274 glNewList (bp->dlists[i], GL_COMPILE);
276 glMatrixMode(GL_MODELVIEW);
278 glMatrixMode(GL_TEXTURE);
280 glMatrixMode(GL_MODELVIEW);
282 glRotatef (-90, 1, 0, 0);
283 glRotatef (180, 0, 0, 1);
286 glBindTexture (GL_TEXTURE_2D, 0);
289 case CAMERA_BODY: key = "bodyColor"; break;
290 case CAMERA_CAP: key = "capColor"; break;
291 case CAMERA_HINGE: key = "hingeColor"; break;
292 case CAMERA_MOUNT: key = "mountColor"; break;
293 case CAMERA_LENS: key = "lensColor"; spec = spec2; break;
294 case GROUND: key = "groundColor"; spec = spec2; shiny = 128; break;
295 default: abort(); break;
298 parse_color (mi, key, bp->component_colors[i]);
300 glMaterialfv (GL_FRONT_AND_BACK, GL_SPECULAR, spec);
301 glMaterialf (GL_FRONT_AND_BACK, GL_SHININESS, shiny);
306 ground = (struct gllist *) calloc (1, sizeof(*ground));
307 ground->points = draw_ground (mi, bp->component_colors[i]);
310 renderList (gll, wire);
311 /* glColor3f (1, 1, 1); renderListNormals (gll, 100, True); */
312 /* glColor3f (1, 1, 0); renderListNormals (gll, 100, False); */
316 glMatrixMode(GL_TEXTURE);
318 glMatrixMode(GL_MODELVIEW);
324 bp->ncameras = MI_COUNT(mi);
325 if (bp->ncameras <= 0) bp->ncameras = 1;
326 bp->cameras = (camera *) calloc (bp->ncameras, sizeof (camera));
329 GLfloat range = (MI_COUNT(mi) <= 2) ? 4 : 5.5;
331 GLfloat spacing = range / bp->ncameras;
332 if (spacing < 0.7) spacing = 0.7;
333 extent = spacing * (bp->ncameras - 1);
334 for (i = 0; i < bp->ncameras; i++)
336 camera *c = &bp->cameras[i];
338 c->pos.x = i*spacing - extent/2;
341 c->pos.z = (i & 1 ? 1.1 : -0.3);
342 c->focus.x = c->pos.x;
343 c->focus.y = c->pos.y + 1;
344 c->focus.z = c->pos.z + BEAM_ZOFF;
353 /* Let's tilt the floor a little. */
354 gltrackball_reset (bp->user_trackball,
356 -0.30 + frand(0.40));
363 GLfloat d = sqrt(p.x*p.x + p.y*p.y * p.z*p.z);
378 vector_angle (XYZ a, XYZ b)
380 double La = sqrt (a.x*a.x + a.y*a.y + a.z*a.z);
381 double Lb = sqrt (b.x*b.x + b.y*b.y + b.z*b.z);
384 if (La == 0 || Lb == 0) return 0;
385 if (a.x == b.x && a.y == b.y && a.z == b.z) return 0;
387 /* dot product of two vectors is defined as:
388 La * Lb * cos(angle between vectors)
389 and is also defined as:
390 ax*bx + ay*by + az*bz
392 La * Lb * cos(angle) = ax*bx + ay*by + az*bz
393 cos(angle) = (ax*bx + ay*by + az*bz) / (La * Lb)
394 angle = acos ((ax*bx + ay*by + az*bz) / (La * Lb));
396 cc = (a.x*b.x + a.y*b.y + a.z*b.z) / (La * Lb);
397 if (cc > 1) cc = 1; /* avoid fp rounding error (1.000001 => sqrt error) */
405 draw_component (ModeInfo *mi, int i, GLfloat color[4])
407 camera_configuration *bp = &bps[MI_SCREEN(mi)];
409 color = bp->component_colors[i];
410 glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, color);
411 glCallList (bp->dlists[i]);
412 return (*all_objs[i])->points / 3;
417 draw_double_component (ModeInfo *mi, int i)
419 int count = draw_component (mi, i, 0);
423 count += draw_component (mi, i, 0);
431 draw_ray (ModeInfo *mi, camera *c)
433 int wire = MI_IS_WIREFRAME(mi);
435 GLfloat length = 10000;
436 GLfloat thickness = 0.08;
440 glTranslatef (c->pos.x, c->pos.y, c->pos.z + BEAM_ZOFF);
441 glRotatef (-c->facing, 0, 0, 1);
442 glRotatef ( c->pitch, 1, 0, 0);
443 glRotatef (frand(90), 0, 1, 0);
444 glScalef (thickness, length, thickness);
445 glDisable (GL_LIGHTING);
447 for (i = 0; i < 5; i++)
449 glColor4f (1, 0, 0, 0.1 + (i * 0.18));
450 glBegin (wire ? GL_LINE_LOOP : GL_QUADS);
451 glVertex3f (0, 0, -0.5); glVertex3f (0, 0, 0.5);
452 glVertex3f (0, 1, 0.5); glVertex3f (0, 1, -0.5);
455 glBegin (wire ? GL_LINE_LOOP : GL_QUADS);
456 glVertex3f (-0.5, 0, 0); glVertex3f ( 0.5, 0, 0);
457 glVertex3f ( 0.5, 1, 0); glVertex3f (-0.5, 1, 0);
460 glBegin (wire ? GL_LINE_LOOP : GL_QUADS);
461 glVertex3f (0, 1, -0.5); glVertex3f (0, 1, 0.5);
462 glVertex3f (0, 0, 0.5); glVertex3f (0, 0, -0.5);
465 glBegin (wire ? GL_LINE_LOOP : GL_QUADS);
466 glVertex3f (-0.5, 1, 0); glVertex3f ( 0.5, 1, 0);
467 glVertex3f ( 0.5, 0, 0); glVertex3f (-0.5, 0, 0);
470 glScalef (0.7, 1, 0.7);
472 if (!MI_IS_WIREFRAME(mi))
473 glEnable (GL_LIGHTING);
480 draw_camera_1 (ModeInfo *mi, camera *c)
483 GLfloat scale = 0.01;
484 GLfloat color[4] = { 1, 0, 0, 1 };
487 glTranslatef (c->pos.x, c->pos.y, c->pos.z);
488 glScalef (scale, scale, scale);
490 glRotatef (90, 1, 0, 0);
491 glRotatef (-90, 0, 1, 0);
493 count += draw_double_component (mi, CAMERA_MOUNT);
495 glRotatef (-c->facing, 0, 1, 0);
496 glRotatef (-c->pitch, 0, 0, 1);
498 count += draw_double_component (mi, CAMERA_HINGE);
500 if (c->state == WARM_UP)
503 glTranslatef ((0.2 - c->tick) / (scale * 3), 0, 0);
508 glTranslatef ((0.005 - frand(0.01)) / scale,
509 (0.005 - frand(0.01)) / scale,
510 (0.005 - frand(0.01)) / scale);
513 count += draw_double_component (mi, CAMERA_BODY);
517 glTranslatef ((0.005 - frand(0.01)) / scale,
518 (0.005 - frand(0.01)) / scale,
519 (0.005 - frand(0.01)) / scale);
522 count += draw_double_component (mi, CAMERA_CAP);
526 case WARM_UP: color[0] = 1.0 - c->tick; break;
527 case ZOT: color[0] = 1.0; break;
528 case COOL_DOWN: color[0] = c->tick; break;
529 default: abort(); break;
532 count += draw_component (mi, CAMERA_LENS,
533 (c->state == IDLE ? 0 : color));
536 if (debug_p && c->state != ZOT)
538 glDisable (GL_LIGHTING);
541 glVertex3f (0, BEAM_ZOFF / scale, 0);
542 glVertex3f (-100 / scale, BEAM_ZOFF / scale, 0);
544 if (!MI_IS_WIREFRAME(mi))
545 glEnable (GL_LIGHTING);
555 /* The position this pedestrian would appear at during the given ratio
556 through its life cycle.
559 pedestrian_position (pedestrian *p, GLfloat ratio)
564 pos.x += p->length * ratio;
565 pos.z += sin (M_PI * ratio * p->frequency * 2) * p->amplitude
572 draw_pedestrian (ModeInfo *mi, pedestrian *p)
579 GLfloat step = 0.001;
580 glDisable (GL_LIGHTING);
583 glBegin (GL_LINE_STRIP);
584 glVertex3f (p->pos.x, p->pos.y, p->pos.z + p->amplitude);
585 glVertex3f (p->pos.x, p->pos.y, 0);
586 glVertex3f (p->pos.x + p->length, p->pos.y, 0);
587 glVertex3f (p->pos.x + p->length, p->pos.y, p->pos.z + p->amplitude);
590 glBegin (GL_LINE_STRIP);
591 for (r = 0; r <= 1; r += step)
593 XYZ pos = pedestrian_position (p, r);
594 glVertex3f (pos.x, pos.y, pos.z);
596 if (p->ratio >= r && p->ratio < r + step)
598 glVertex3f (pos.x, pos.y, pos.z - p->amplitude);
599 glVertex3f (pos.x, pos.y, pos.z + p->amplitude);
600 glVertex3f (pos.x, pos.y, pos.z);
605 if (!MI_IS_WIREFRAME(mi))
606 glEnable (GL_LIGHTING);
613 /* Start someone walking through the scene.
616 add_pedestrian (ModeInfo *mi)
618 camera_configuration *bp = &bps[MI_SCREEN(mi)];
619 pedestrian *p = (pedestrian *) calloc (1, sizeof(*p));
624 p->pos.x = -p->length/2;
625 p->pos.y = 3 + frand(10);
626 p->pos.z = -1.5 + frand(4) + ((random() % 10) ? 0 : frand(8));
627 p->frequency = 4 + frand(4);
628 p->amplitude = 0.1 + ((random() % 10) ? BELLRAND(0.45) : BELLRAND(1.5));
630 p->speed = ((4 + frand(4) + ((random() % 10) ? 0 : frand(10)))
631 * (random() & 1 ? 1 : -1)
636 pedestrian *p2; /* add it to the end */
637 for (p2 = bp->pedestrians; p2->next; p2 = p2->next)
643 p->next = bp->pedestrians;
650 free_pedestrian (ModeInfo *mi, pedestrian *p)
652 camera_configuration *bp = &bps[MI_SCREEN(mi)];
655 if (p == bp->pedestrians)
657 bp->pedestrians = p->next;
663 for (p0 = bp->pedestrians; p0; p0 = p0->next)
666 p0->next = p0->next ? p0->next->next : 0;
678 tick_pedestrian (ModeInfo *mi, pedestrian *p)
680 p->ratio += 0.001 * (p->speed > 0 ? p->speed : -p->speed);
682 free_pedestrian (mi, p);
686 /* Extract the position of the thing this camera would like to look at.
689 set_camera_focus (ModeInfo *mi, camera *c)
691 camera_configuration *bp = &bps[MI_SCREEN(mi)];
693 if (c->focus_id > 0) /* Look at pedestrian with id N */
695 long id = c->focus_id;
697 for (p = bp->pedestrians; p; p = p->next)
701 c->focus = pedestrian_position (p, p->ratio);
703 c->focus_id = 0; /* that pedestrian has escaped */
705 else if (c->focus_id < 0) /* Look at camera -N-1 */
707 long n = -c->focus_id - 1;
708 if (bp->ncameras > n)
709 c->focus = bp->cameras[n].pos;
715 tick_camera (ModeInfo *mi, camera *c)
717 camera_configuration *bp = &bps[MI_SCREEN(mi)];
720 set_camera_focus (mi, c);
722 X = c->focus.x - c->pos.x;
723 Y = c->focus.y - c->pos.y;
724 Z = c->focus.z - c->pos.z - BEAM_ZOFF;
726 if (X != 0 || Y != 0)
728 GLfloat ofacing = c->facing;
729 GLfloat opitch = c->pitch;
731 GLfloat target_facing = atan2 (X, Y) * (180 / M_PI);
732 GLfloat target_pitch = atan2 (Z, sqrt(X*X + Y*Y)) * (180 / M_PI);
734 /* Adjust the current velocity.
735 If we are nearing the target, slow down (but don't stop).
736 Otherwise, speed up (but don't break the speed limit).
739 GLfloat accel = 0.5 * speed_arg;
740 GLfloat decel_range = 20;
741 GLfloat max_velocity = 5 * speed_arg;
742 GLfloat close_enough = 0.5 * speed_arg;
744 GLfloat dx = target_facing - c->facing;
745 GLfloat dy = target_pitch - c->pitch;
746 GLfloat angular_distance = sqrt (dx*dx + dy*dy);
748 /* Split the velocity into vx and vy components. This isn't
749 quite right since this treats them as Cartesian rather than
750 polar, but it's close enough.
752 GLfloat r = (dx == 0) ? 1 : ABS(dy) / ABS(dx);
756 if (angular_distance < decel_range) /* Nearing target, slow down */
758 c->velocity -= accel;
759 if (c->velocity <= 0)
764 c->velocity += accel;
765 if (c->velocity > max_velocity)
766 c->velocity = max_velocity;
769 /* Don't overshoot */
770 if (vx > ABS(dx)) vx = ABS(dx);
771 if (vy > ABS(dy)) vy = ABS(dy);
774 /* Rotate toward target by current angular velocity. */
775 c->facing += vx * c->velocity * (target_facing > c->facing ? 1 : -1);
776 c->pitch += vy * c->velocity * (target_pitch > c->pitch ? 1 : -1);
778 /* If we are pointed *really close* to the target, just lock on,
779 to avoid twitchy overshoot rounding errors.
781 if (angular_distance < close_enough)
783 c->facing = target_facing;
784 c->pitch = target_pitch;
787 /* Constrain to hinge's range of motion */
788 c->facing = MAX (-90, MIN (90, c->facing));
789 c->pitch = MAX (-90, MIN (55, c->pitch));
791 /* After this motion, our prevailing velocity (for next time)
792 is the angular distance we actually moved.
794 dx = c->facing - ofacing;
795 dy = c->pitch - opitch;
796 c->velocity = sqrt (dx*dx + dy*dy);
802 /* Mark the point on which this camera is focusing. */
805 glDisable (GL_LIGHTING);
806 glColor3f(0.3, 0.3, 0.3);
808 glVertex3f (c->pos.x, c->pos.y, c->pos.z + BEAM_ZOFF);
809 glVertex3f (c->focus.x, c->focus.y, c->focus.z);
813 glVertex3f (c->focus.x-0.25, c->focus.y, c->focus.z);
814 glVertex3f (c->focus.x+0.25, c->focus.y, c->focus.z);
815 glVertex3f (c->focus.x, c->focus.y-0.25, c->focus.z);
816 glVertex3f (c->focus.x, c->focus.y+0.25, c->focus.z);
817 glVertex3f (c->focus.x, c->focus.y, c->focus.z-0.25);
818 glVertex3f (c->focus.x, c->focus.y, c->focus.z+0.25);
820 if (!MI_IS_WIREFRAME(mi))
821 glEnable (GL_LIGHTING);
826 /* If this camera is looking at another camera, get shy and look away
827 if the target sees us looking.
831 camera *c2 = &bp->cameras[-1 - c->focus_id];
833 GLfloat aa = c->facing / (180 / M_PI);
834 GLfloat bb = c->pitch / (180 / M_PI);
837 a.y = cos(aa)* cos(bb);
838 a.x = sin(aa)* cos(bb);
841 aa = c2->facing / (180 / M_PI);
842 bb = c2->pitch / (180 / M_PI);
843 b.y = cos(aa)* cos(bb);
844 b.x = sin(aa)* cos(bb);
847 angle = vector_angle (normalize(a), normalize(b)) * (180 / M_PI);
852 /* Look "away" which means in the same direction. */
853 c->focus.x = c->pos.x + (c2->focus.x - c2->pos.x);
854 c->focus.y = c->pos.y + (c2->focus.y - c2->pos.y);
855 c->focus.z = c->pos.z + (c2->focus.z - c2->pos.z);
856 /* Look at either the sky or the ground.*/
857 c->focus.z = c->focus.x * (random() & 1 ? 1 : -1) * 5;
858 c->velocity = c2->velocity * 3;
863 /* Randomly pick some other things to look at.
866 if (c->state == IDLE &&
868 ? !(random() % (int) MAX (1, (50 / speed_arg)))
869 : !(random() % (int) MAX (1, (1000 / speed_arg)))))
872 /* Shiny! Start paying attention to something else. */
874 if ((bp->ncameras > 1 && !(random() % 20))) /* look at a camera */
876 int which = random() % 4;
878 for (i = 0; i < bp->ncameras; i++)
879 if (c == &bp->cameras[i])
882 /* Look at cameras 1 or 2 away in each direction, but not farther.
883 Since we arrange them in 2 staggered lines, those are the only
884 four that are in line of sight.
886 if (i >= 2 && which == 0)
888 else if (i >= 1 && which == 1)
890 else if (i < bp->ncameras-2 && which == 2)
892 else if (i == bp->ncameras-1)
894 else /* (i < bp->ncameras-2 && which == 3) */
897 c->focus_id = -1 - which;
899 else /* look at a pedestrian */
903 for (p = bp->pedestrians; p; p = p->next)
917 /* Run the animation */
919 if (c->state != IDLE)
921 pedestrian *p = bp->pedestrians; /* first one */
922 if (p) c->focus_id = p->id;
925 case WARM_UP: c->tick -= 0.01 * speed_arg; break;
926 case ZOT: c->tick -= 0.006 * speed_arg;
927 if (p) p->speed *= 0.995; /* target takes 1d6 HP damage */
929 case COOL_DOWN: c->tick -= 0.02 * speed_arg; break;
930 default: abort(); break;
937 case WARM_UP: c->state = ZOT; break;
938 case ZOT: c->state = COOL_DOWN;
940 if (p) p->ratio = 1.0; /* threat eliminated */
942 case COOL_DOWN: c->state = IDLE; break;
943 default: abort(); break;
948 if (bp->cameras[0].state == IDLE &&
950 bp->pedestrians[0].ratio < 0.3 &&
951 !(random() % MAX (1, (int) (50000 / speed_arg))))
953 /* CASE NIGHTMARE RED detected, engage SCORPION STARE by authority
954 of MAGINOT BLUE STARS. */
956 for (i = 0; i < bp->ncameras; i++)
958 bp->cameras[i].state = WARM_UP;
959 bp->cameras[i].tick = 1.0;
966 draw_ground (ModeInfo *mi, GLfloat color[4])
968 int wire = MI_IS_WIREFRAME(mi);
971 /* When using fog, iOS apparently doesn't like lines or quads that are
972 really long, and extend very far outside of the scene. Maybe? If the
973 length of the line (cells * cell_size) is greater than 25 or so, lines
974 that are oriented steeply away from the viewer tend to disappear
975 (whether implemented as GL_LINES or as GL_QUADS).
977 So we do a bunch of smaller grids instead of one big one.
980 GLfloat cell_size = 0.4;
989 GLfloat fog_color[4] = { 0, 0, 0, 1 };
992 glEnable (GL_LINE_SMOOTH);
993 glHint (GL_LINE_SMOOTH_HINT, GL_NICEST);
994 glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
997 glFogi (GL_FOG_MODE, GL_EXP2);
998 glFogfv (GL_FOG_COLOR, fog_color);
999 glFogf (GL_FOG_DENSITY, 0.017);
1000 glFogf (GL_FOG_START, -cells/2 * cell_size * gridsh);
1005 glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, color);
1007 glTranslatef (-cells * gridsw * cell_size / 2, 0, 0);
1008 for (h = 0; h < 2; h++)
1011 glTranslatef (0, cells * cell_size / 2, 0);
1012 for (j = 0; j < gridsh; j++)
1015 for (k = 0; k < gridsw; k++)
1018 for (i = -cells/2; i < cells/2; i++)
1020 GLfloat a = i * cell_size;
1021 GLfloat b = cells/2 * cell_size;
1022 glVertex3f (a, -b, 0); glVertex3f (a, b, 0); points++;
1023 glVertex3f (-b, a, 0); glVertex3f (b, a, 0); points++;
1026 glTranslatef (cells * cell_size, 0, 0);
1029 glTranslatef (0, cells * cell_size, 0);
1032 glRotatef (90, 1, 0, 0);
1036 glDisable (GL_LINE_SMOOTH);
1045 draw_camera (ModeInfo *mi)
1047 camera_configuration *bp = &bps[MI_SCREEN(mi)];
1048 Display *dpy = MI_DISPLAY(mi);
1049 Window window = MI_WINDOW(mi);
1050 GLfloat camera_size;
1053 if (!bp->glx_context)
1056 glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(bp->glx_context));
1058 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1063 glRotatef (current_device_rotation(), 0, 0, 1); /* right side up */
1066 gltrackball_rotate (bp->user_trackball);
1080 glRotatef (30, 0, 1, 0);
1081 glRotatef (15, 1, 0, 0);
1082 glTranslatef (0, 0, -80);
1086 mi->polygon_count = 0;
1090 if (MI_COUNT(mi) <= 2) /* re-frame the scene a little bit */
1091 glTranslatef (0, -1, 7);
1092 if (MI_COUNT(mi) >= 20)
1093 glTranslatef (0, -1.5, -5);
1094 if (MI_COUNT(mi) >= 40)
1095 glTranslatef (0, 2, -15);
1097 glScalef (camera_size, camera_size, camera_size);
1099 /* +Z is toward sky; +X is toward the right along the back wall;
1100 +Y is toward the viewer. */
1101 glRotatef (-90, 1, 0, 0);
1102 glScalef (1, -1, 1);
1105 glScalef (1/camera_size, 1/camera_size, 1/camera_size);
1106 glTranslatef (0, -2.38, -8); /* Move the ground down and back */
1107 glCallList (bp->dlists[GROUND]);
1108 mi->polygon_count += ground->points;
1114 for (p = bp->pedestrians, p2 = p ? p->next : 0;
1116 p = p2, p2 = p2 ? p2->next : 0)
1118 mi->polygon_count += draw_pedestrian (mi, p);
1119 tick_pedestrian (mi, p); /* might free p */
1122 if (!bp->pedestrians || !(random() % MAX (1, (int) (200 / speed_arg))))
1123 add_pedestrian (mi);
1126 for (i = 0; i < bp->ncameras; i++)
1128 camera *c = &bp->cameras[i];
1129 mi->polygon_count += draw_camera_1 (mi, c);
1130 tick_camera (mi, c);
1133 for (i = 0; i < bp->ncameras; i++)
1135 camera *c = &bp->cameras[i];
1136 if (c->state == ZOT) /* Do this last, for alpha blending */
1137 mi->polygon_count += draw_ray (mi, c);
1142 if (mi->fps_p) do_fps (mi);
1145 glXSwapBuffers(dpy, window);
1148 XSCREENSAVER_MODULE_2 ("Vigilance", vigilance, camera)