diff options
| author | Simon Rettberg | 2024-09-06 14:42:37 +0200 |
|---|---|---|
| committer | Simon Rettberg | 2024-09-06 14:42:37 +0200 |
| commit | badef32037f52f79abc1f1440b786cd71afdf270 (patch) | |
| tree | 412b792d4cab4a7a110db82fcf74fe8a1ac55ec1 /hacks/glx/peepers.c | |
| parent | Delete pre-6.00 files (diff) | |
| download | xscreensaver-master.tar.gz xscreensaver-master.tar.xz xscreensaver-master.zip | |
Diffstat (limited to 'hacks/glx/peepers.c')
| -rw-r--r-- | hacks/glx/peepers.c | 1471 |
1 files changed, 0 insertions, 1471 deletions
diff --git a/hacks/glx/peepers.c b/hacks/glx/peepers.c deleted file mode 100644 index 1554616..0000000 --- a/hacks/glx/peepers.c +++ /dev/null @@ -1,1471 +0,0 @@ -/* peepers, Copyright (c) 2018-2019 Jamie Zawinski <jwz@jwz.org> - * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that - * copyright notice and this permission notice appear in supporting - * documentation. No representations are made about the suitability of this - * software for any purpose. It is provided "as is" without express or - * implied warranty. - * - * Created: 14 Feb 2018, jwz. - * - * Floating eyeballs! - * - * Inspired by @PaintYourDragon's Adafruit Snake Eyes Raspberry Pi Bonnet - * https://learn.adafruit.com/animated-snake-eyes-bonnet-for-raspberry-pi/ - * which is excellent. - */ - -#define DEFAULTS "*delay: 30000 \n" \ - "*count: 0 \n" \ - "*showFPS: False \n" \ - "*wireframe: False \n" \ - -# define release_peepers 0 - -#define DEF_SPEED "1.0" -#define DEF_MODE "random" - -#undef BELLRAND -#define BELLRAND(n) ((frand((n)) + frand((n)) + frand((n))) / 3) -#undef RANDSIGN -#define RANDSIGN() ((random() & 1) ? 1 : -1) - -#include "xlockmore.h" -#include "normals.h" -#include "rotator.h" -#include "gltrackball.h" -#include "ximage-loader.h" -#include <ctype.h> - -#ifndef HAVE_JWXYZ -# include <X11/Xatom.h> -#endif - -#include "images/gen/sclera_png.h" -#include "images/gen/iris_png.h" - -#ifdef USE_GL /* whole file */ - -typedef struct { double a, o; } LL; /* latitude + longitude */ - -typedef struct { - int idx; - GLfloat x, y, z; - GLfloat dx, dy, dz; - GLfloat ddx, ddy, ddz; - rotator *rot; - struct { GLfloat from, to, current, tick; } dilation; - enum { ROTATE, SPIN, TRACK } focus; - XYZ track; - GLfloat tilt, roll; - GLfloat scale; - GLfloat color[4]; - int jaundice; -} floater; - -typedef enum { RETINA, IRIS, SCLERA, LENS, TICK } component; - -typedef struct { - GLXContext *glx_context; - trackball_state *trackball; - - Bool button_down_p; - XYZ mouse, last_mouse, fake_mouse; - time_t last_mouse_time; - int mouse_dx, mouse_dy; - - GLuint retina_list, sclera_list, lens_list, iris_list; - GLuint sclera_texture, iris_texture; - int eye_polys; - - int nfloaters; - floater *floaters; - enum { BOUNCE, SCROLL_LEFT, SCROLL_RIGHT, XEYES, BEHOLDER } mode; - -} peepers_configuration; - -static peepers_configuration *bps = NULL; - -static GLfloat speed; -const char *mode_opt; - -static XrmOptionDescRec opts[] = { - { "-speed", ".speed", XrmoptionSepArg, 0 }, - { "-mode", ".mode", XrmoptionSepArg, 0 }, -}; - -static argtype vars[] = { - {&speed, "speed", "Speed", DEF_SPEED, t_Float}, - {&mode_opt, "mode", "Mode", DEF_MODE, t_String}, -}; - -ENTRYPOINT ModeSpecOpt peepers_opts = {countof(opts), opts, countof(vars), vars, NULL}; - - -/* Bottom edge of screen is -0.5; left and right scale by aspect. */ -#define BOTTOM (-1.6) -#define LEFT (BOTTOM * MI_WIDTH(mi) / (GLfloat) MI_HEIGHT(mi)) - -static void -reset_floater (ModeInfo *mi, floater *f) -{ - peepers_configuration *bp = &bps[MI_SCREEN(mi)]; - GLfloat r = ((bp->mode == BOUNCE ? LEFT : BOTTOM) * - (bp->nfloaters < 10 ? 0.3: 0.6)); - GLfloat x, y; - - if (bp->nfloaters <= 2) - { - x = frand(LEFT) * RANDSIGN() * 0.3; - y = 0; - } - else - { - /* Position them off screen in a circle */ - GLfloat th = f->idx * (M_PI + (M_PI/6)) * 2 / bp->nfloaters; - x = r * cos (th); - y = r * sin (th) * 1.5; /* Oval */ - } - - switch (bp->mode) { - case BOUNCE: - f->x = x; - f->y = BOTTOM; - f->z = y; - - /* Yes, I know I'm varying the force of gravity instead of varying the - launch velocity. That's intentional: empirical studies indicate - that it's way, way funnier that way. */ - - f->dy = 0.1; - f->dx = 0; - f->dz = 0; - - { - GLfloat min = -0.004; - GLfloat max = -0.0019; - f->ddy = min + frand (max - min); - f->ddx = 0; - f->ddz = 0; - } - - if (! (random() % (10 * bp->nfloaters))) - { - f->dx = BELLRAND(0.03) * RANDSIGN(); - f->dz = BELLRAND(0.03) * RANDSIGN(); - } - break; - - case SCROLL_LEFT: - case SCROLL_RIGHT: - - f->x = (bp->mode == SCROLL_LEFT ? -LEFT : LEFT); - f->y = x; - f->z = y; - - f->dx = (1.0 + frand(2.0)) * 0.020 * (bp->mode == SCROLL_LEFT ? -1 : 1); - f->dy = (1.0 + frand(2.0)) * 0.002 * RANDSIGN(); - f->dz = (1.0 + frand(2.0)) * 0.002 * RANDSIGN(); - f->ddy = 0; - f->ddz = 0; - break; - - case XEYES: /* This happens in layout_grid() */ - break; - case BEHOLDER: /* This happens in layout_geodesic() */ - break; - - default: - abort(); - } - - f->focus = ((random() % 8) ? ROTATE : - (random() % 4) ? TRACK : SPIN); - f->track.x = 8 - frand(16); - f->track.y = 8 - frand(16); - f->track.z = 8 + frand(16); - - f->tilt = 45 - BELLRAND(90); - f->roll = frand(180); - f->dilation.to = f->dilation.from = f->dilation.current = frand(1.0); - f->dilation.tick = 1; - - f->scale = 0.8 + BELLRAND(0.2); - - if (bp->nfloaters == 1) f->scale *= 0.5; - else if (bp->nfloaters <= 3) f->scale *= 0.4; - else if (bp->nfloaters <= 9) f->scale *= 0.3; - else if (bp->nfloaters <= 15) f->scale *= 0.2; - else if (bp->nfloaters <= 25) f->scale *= 0.15; - else if (bp->nfloaters <= 90) f->scale *= 0.12; - else f->scale *= 0.07; - - if (MI_WIDTH(mi) < MI_HEIGHT(mi)) - { - f->scale /= MI_HEIGHT(mi) / (GLfloat) MI_WIDTH(mi) * 1.2; - } - - { - static const struct { GLfloat pct; unsigned long c; } c[] = { - /* All of the articles that I found with percentages in them only - added up to around 70%, so who knows what that means. */ -# if 0 - { 55, 0x985A07 }, /* brown -- supposedly real global percentage */ -# else - { 20, 0x985A07 }, /* brown -- but that's a lot of brown... */ -# endif - { 8, 0xD5AD68 }, /* hazel */ - { 8, 0x777F92 }, /* blue */ - { 2, 0x6B7249 }, /* green */ - { 1, 0x7F7775 }, /* gray */ - { 0.5, 0x9E8042 }, /* amber */ - { 0.1, 0xFFAA88 }, /* red */ - }; - GLfloat p = 0, t = 0; - GLfloat s = 1 - frand(0.3); - int i; - for (i = 0; i < countof(c); i++) - p += c[i].pct; - p = frand(p); - - for (i = 0; i < countof(c) - 1; i++) - { - t += c[i].pct; - if (t > p) break; - } - - if (c[i].c == 0xFFAA88) f->jaundice = 2; - else if (!(random() % 20)) f->jaundice = 1; - - f->color[0] = ((c[i].c >> 16) & 0xFF) / 255.0 * s; - f->color[1] = ((c[i].c >> 8) & 0xFF) / 255.0 * s; - f->color[2] = ((c[i].c >> 0) & 0xFF) / 255.0 * s; - f->color[3] = 1; - } -} - - -/* Place a grid of eyeballs on the screen, maximizing use of space. - */ -static void -layout_grid (ModeInfo *mi) -{ - peepers_configuration *bp = &bps[MI_SCREEN(mi)]; - - /* Distribute the eyes into a rectangular grid that fills the window. - There may be some empty cells. N items in a W x H rectangle: - N = W * H - N = W * W * R - N/R = W*W - W = sqrt(N/R) - */ - GLfloat aspect = MI_WIDTH(mi) / (GLfloat) MI_HEIGHT(mi); - int nlines = sqrt (bp->nfloaters / aspect) + 0.5; - int *cols = (int *) calloc (nlines, sizeof(*cols)); - int i, x, y, max = 0; - GLfloat scale, spacing; - - for (i = 0; i < bp->nfloaters; i++) - { - cols[i % nlines]++; - if (cols[i % nlines] > max) max = cols[i % nlines]; - } - - /* That gave us, e.g. 7777666. Redistribute to 6767767. */ - for (i = 0; i < nlines / 2; i += 2) - { - int j = nlines-i-1; - int swap = cols[i]; - cols[i] = cols[j]; - cols[j] = swap; - } - - scale = 1.0 / nlines; /* Scale for height */ - if (scale * max > aspect) /* Shrink if overshot width */ - scale *= aspect / (scale * max); - - scale *= 0.9; /* Add padding */ - spacing = scale * 2.2; - - if (bp->nfloaters == 1) spacing = 0; - - i = 0; - for (y = 0; y < nlines; y++) - for (x = 0; x < cols[y]; x++) - { - floater *f = &bp->floaters[i]; - f->scale = scale; - f->x = spacing * (x - cols[y] / 2.0) + spacing/2; - f->y = spacing * (y - nlines / 2.0) + spacing/2; - f->z = 0; - i++; - } - free (cols); -} - - -/* Computes the midpoint of a line between two polar coords. - */ -static void -midpoint2 (LL v1, LL v2, LL *vm_ret, - XYZ *p1_ret, XYZ *p2_ret, XYZ *pm_ret) -{ - XYZ p1, p2, pm; - LL vm; - GLfloat hyp; - - p1.x = cos (v1.a) * cos (v1.o); - p1.y = cos (v1.a) * sin (v1.o); - p1.z = sin (v1.a); - - p2.x = cos (v2.a) * cos (v2.o); - p2.y = cos (v2.a) * sin (v2.o); - p2.z = sin (v2.a); - - pm.x = (p1.x + p2.x) / 2; - pm.y = (p1.y + p2.y) / 2; - pm.z = (p1.z + p2.z) / 2; - - vm.o = atan2 (pm.y, pm.x); - hyp = sqrt (pm.x * pm.x + pm.y * pm.y); - vm.a = atan2 (pm.z, hyp); - - *p1_ret = p1; - *p2_ret = p2; - *pm_ret = pm; - *vm_ret = vm; -} - - -/* Computes the midpoint of a triangle specified in polar coords. - */ -static void -midpoint3 (LL v1, LL v2, LL v3, LL *vm_ret, - XYZ *p1_ret, XYZ *p2_ret, XYZ *p3_ret, XYZ *pm_ret) -{ - XYZ p1, p2, p3, pm; - LL vm; - GLfloat hyp; - - p1.x = cos (v1.a) * cos (v1.o); - p1.y = cos (v1.a) * sin (v1.o); - p1.z = sin (v1.a); - - p2.x = cos (v2.a) * cos (v2.o); - p2.y = cos (v2.a) * sin (v2.o); - p2.z = sin (v2.a); - - p3.x = cos (v3.a) * cos (v3.o); - p3.y = cos (v3.a) * sin (v3.o); - p3.z = sin (v3.a); - - pm.x = (p1.x + p2.x + p3.x) / 3; - pm.y = (p1.y + p2.y + p3.y) / 3; - pm.z = (p1.z + p2.z + p3.z) / 3; - - vm.o = atan2 (pm.y, pm.x); - hyp = sqrt (pm.x * pm.x + pm.y * pm.y); - vm.a = atan2 (pm.z, hyp); - - *p1_ret = p1; - *p2_ret = p2; - *p3_ret = p3; - *pm_ret = pm; - *vm_ret = vm; -} - - -/* Place the eyeballs on a sphere (geodesic) - */ -static void -layout_geodesic_triangle (ModeInfo *mi, LL v1, LL v2, LL v3, int depth, - int *i) -{ - peepers_configuration *bp = &bps[MI_SCREEN(mi)]; - - if (depth <= 0) - { - floater *f = &bp->floaters[*i]; - GLfloat s2 = 0.7; - LL vc; - XYZ p1, p2, p3, pc; - if (*i >= bp->nfloaters) abort(); - - midpoint3 (v1, v2, v3, &vc, &p1, &p2, &p3, &pc); - - switch (bp->nfloaters) { /* This is lame. */ - case 20: f->scale = 0.26; break; - case 80: f->scale = 0.13; break; - case 320: f->scale = 0.065; break; - case 1280: f->scale = 0.0325; break; - default: abort(); - } - - f->z = s2 * cos (vc.a) * cos (vc.o); - f->x = s2 * cos (vc.a) * sin (vc.o); - f->y = s2 * sin (vc.a); - (*i)++; - } - else - { - LL v12, v23, v13; - XYZ p1, p2, p3, p12, p23, p13; - - midpoint2 (v1, v2, &v12, &p1, &p2, &p12); - midpoint2 (v2, v3, &v23, &p2, &p3, &p23); - midpoint2 (v1, v3, &v13, &p1, &p3, &p13); - depth--; - - layout_geodesic_triangle (mi, v1, v12, v13, depth, i); - layout_geodesic_triangle (mi, v12, v2, v23, depth, i); - layout_geodesic_triangle (mi, v13, v23, v3, depth, i); - layout_geodesic_triangle (mi, v12, v23, v13, depth, i); - } -} - - -/* Creates triangles of a geodesic to the given depth (frequency). - */ -static void -layout_geodesic (ModeInfo *mi) -{ - peepers_configuration *bp = &bps[MI_SCREEN(mi)]; - int depth; - GLfloat th0 = atan (0.5); /* lat division: 26.57 deg */ - GLfloat s = M_PI / 5; /* lon division: 72 deg */ - int i; - int ii = 0; - - switch (bp->nfloaters) { /* This is lame. */ - case 20: depth = 0; break; - case 80: depth = 1; break; - case 320: depth = 2; break; - case 1280: depth = 3; break; - default: abort(); - } - - for (i = 0; i < 10; i++) - { - GLfloat th1 = s * i; - GLfloat th2 = s * (i+1); - GLfloat th3 = s * (i+2); - LL v1, v2, v3, vc; - v1.a = th0; v1.o = th1; - v2.a = th0; v2.o = th3; - v3.a = -th0; v3.o = th2; - vc.a = M_PI/2; vc.o = th2; - - if (i & 1) /* north */ - { - layout_geodesic_triangle (mi, v1, v2, vc, depth, &ii); - layout_geodesic_triangle (mi, v2, v1, v3, depth, &ii); - } - else /* south */ - { - v1.a = -v1.a; - v2.a = -v2.a; - v3.a = -v3.a; - vc.a = -vc.a; - layout_geodesic_triangle (mi, v2, v1, vc, depth, &ii); - layout_geodesic_triangle (mi, v1, v2, v3, depth, &ii); - } - } - - bp->floaters[0].dx = BELLRAND(0.01) * RANDSIGN(); -} - - -/* Advance the animation by one step. - */ -static void -tick_floater (ModeInfo *mi, floater *f) -{ - peepers_configuration *bp = &bps[MI_SCREEN(mi)]; - - /* if (bp->button_down_p) return;*/ - - f->dx += f->ddx * speed * 0.5; - f->dy += f->ddy * speed * 0.5; - f->dz += f->ddz * speed * 0.5; - - if (bp->mode != BEHOLDER) - { - f->x += f->dx * speed * 0.5; - f->y += f->dy * speed * 0.5; - f->z += f->dz * speed * 0.5; - } - - f->dilation.tick += 0.1 * speed; - if (f->dilation.tick > 1) f->dilation.tick = 1; - if (f->dilation.tick < 0) f->dilation.tick = 0; - - f->dilation.current = (f->dilation.from + - ((f->dilation.to - f->dilation.from) * - f->dilation.tick)); - - if (f->dilation.tick == 1 && !(random() % 20)) - { - f->dilation.from = f->dilation.to; - f->dilation.to = frand(1.0); - f->dilation.tick = 0; - } - - switch (bp->mode) { - case BOUNCE: - if (f->y < BOTTOM || - f->x < LEFT || f->x > -LEFT) - reset_floater (mi, f); - break; - case SCROLL_LEFT: - if (f->x < LEFT) - reset_floater (mi, f); - break; - case SCROLL_RIGHT: - if (f->x > -LEFT) - reset_floater (mi, f); - break; - case XEYES: - break; - case BEHOLDER: - { - GLfloat x = f->x; - GLfloat y = f->z; - GLfloat th = atan2 (y, x); - GLfloat r = sqrt(x*x + y*y); - th += bp->floaters[0].dx; - f->x = r*cos(th); - f->z = r*sin(th); - - if (! (random() % 100)) - bp->floaters[0].dx += frand(0.0001) * RANDSIGN(); - } - break; - default: - abort(); - } -} - - -/* Make sure none of the eyeballs overlap. - */ -static void -de_collide (ModeInfo *mi) -{ - peepers_configuration *bp = &bps[MI_SCREEN(mi)]; - int i, j; - for (i = 0; i < bp->nfloaters; i++) - { - floater *f0 = &bp->floaters[i]; - for (j = i+1; j < bp->nfloaters; j++) - { - floater *f1 = &bp->floaters[j]; - GLfloat X = f1->x - f0->x; - GLfloat Y = f1->y - f0->y; - GLfloat Z = f1->z - f0->z; - GLfloat min = (f0->scale + f1->scale); - GLfloat d2 = X*X + Y*Y + Z*Z; - if (d2 < min*min) - { - GLfloat d = sqrt (d2); - GLfloat dd = 0.5 * (min - d) / 2; - GLfloat dx = X * dd; - GLfloat dy = Y * dd; - GLfloat dz = Z * dd; - f0->x -= dx; f0->y -= dy; f0->z -= dz; - f1->x += dx; f1->y += dy; f1->z += dz; - } - } - } -} - - -/* Window management, etc - */ -ENTRYPOINT void -reshape_peepers (ModeInfo *mi, int width, int height) -{ - peepers_configuration *bp = &bps[MI_SCREEN(mi)]; - GLfloat h = (GLfloat) height / (GLfloat) width; - int y = 0; - - glViewport (0, y, (GLint) width, (GLint) height); - - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - gluPerspective (30.0, 1/h, 1.0, 100); - - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - gluLookAt( 0.0, 0.0, 30.0, - 0.0, 0.0, 0.0, - 0.0, 1.0, 0.0); - - glClear(GL_COLOR_BUFFER_BIT); - - if (bp->mode == XEYES) - layout_grid (mi); -} - - -/* Find the mouse pointer on the screen and note its position in the scene. - */ -static void -track_mouse (ModeInfo *mi) -{ - peepers_configuration *bp = &bps[MI_SCREEN(mi)]; - Window r, c; - int x, y, rx, ry; - unsigned int m; - int w = MI_WIDTH(mi); - int h = MI_HEIGHT(mi); - int rot = (int) current_device_rotation(); - int swap; - GLfloat ys = 2.0; - GLfloat xs = ys * w / h; - time_t now = time ((time_t *) 0); - - XQueryPointer (MI_DISPLAY (mi), MI_WINDOW (mi), - &r, &c, &rx, &ry, &x, &y, &m); - - if (x != bp->last_mouse.x && y != bp->last_mouse.y) - { - bp->last_mouse_time = now; - bp->fake_mouse.x = x; - bp->fake_mouse.y = y; - bp->mouse_dx = 0; - bp->mouse_dy = 0; - bp->last_mouse.x = x; - bp->last_mouse.y = y; - } - else if (now > bp->last_mouse_time + 10) - { - /* Mouse isn't moving. Bored now. */ - if (! (random() % 20)) bp->mouse_dx += (random() % 2) * RANDSIGN(); - if (! (random() % 20)) bp->mouse_dy += (random() % 2) * RANDSIGN(); - bp->fake_mouse.x += bp->mouse_dx; - bp->fake_mouse.y += bp->mouse_dy; - x = bp->fake_mouse.x; - y = bp->fake_mouse.y; - } - - while (rot <= -180) rot += 360; - while (rot > 180) rot -= 360; - - if (rot > 135 || rot < -135) /* 180 */ - { - x = w - x; - y = h - y; - } - else if (rot > 45) /* 90 */ - { - swap = x; x = y; y = swap; - swap = w; w = h; h = swap; - xs = ys; - ys = xs * w / h; - x = w - x; - } - else if (rot < -45) /* 270 */ - { - swap = x; x = y; y = swap; - swap = w; w = h; h = swap; - xs = ys; - ys = xs * w / h; - y = h - y; - } - - /* Put the mouse directly on the glass. */ - x = x - w / 2; - y = h / 2 - y; - bp->mouse.x = xs * x / w; - bp->mouse.y = ys * y / h; - bp->mouse.z = 0; - -# if 0 - glPushMatrix(); - glTranslatef (bp->mouse.x, bp->mouse.y, bp->mouse.z); - if (!MI_IS_WIREFRAME(mi)) glDisable(GL_LIGHTING); - glColor3f(1,1,1); - glBegin(GL_LINES); - glVertex3f(-1,0,0); glVertex3f(1,0,0); - glVertex3f(0,-1,0); glVertex3f(0,1,0); - glVertex3f(0,0,-1); glVertex3f(0,0,1); - glEnd(); - glPopMatrix(); - if (!MI_IS_WIREFRAME(mi)) glEnable(GL_LIGHTING); -# endif - - /* Move it farther into the scene: on the glass is too far away. - But keep it farther away the farther outside the window the - mouse is, so the eyes don''t turn 90 degrees sideways. - */ - bp->mouse.x *= 0.8; - bp->mouse.y *= 0.8; - bp->mouse.z += 0.7; - - bp->mouse.z = MAX (0.7, - sqrt (bp->mouse.x * bp->mouse.x + - bp->mouse.y * bp->mouse.y)); - - if (bp->mode == BEHOLDER) - bp->mouse.z += 0.25; - - -# if 0 - glPushMatrix(); - glTranslatef (bp->mouse.x, bp->mouse.y, bp->mouse.z); - if (!MI_IS_WIREFRAME(mi)) glDisable(GL_LIGHTING); - glColor3f(1,0,1); - glBegin(GL_LINES); - glVertex3f(-1,0,0); glVertex3f(1,0,0); - glVertex3f(0,-1,0); glVertex3f(0,1,0); - glVertex3f(0,0,-1); glVertex3f(0,0,1); - glEnd(); - glPopMatrix(); - if (!MI_IS_WIREFRAME(mi)) glEnable(GL_LIGHTING); -# endif -} - - -ENTRYPOINT Bool -peepers_handle_event (ModeInfo *mi, XEvent *event) -{ - peepers_configuration *bp = &bps[MI_SCREEN(mi)]; - - if (gltrackball_event_handler (event, bp->trackball, - MI_WIDTH (mi), MI_HEIGHT (mi), - &bp->button_down_p)) - { - if (bp->button_down_p) /* Aim each eyeball at the mouse. */ - { - int i; - track_mouse (mi); - for (i = 0; i < bp->nfloaters; i++) - { - floater *f = &bp->floaters[i]; - f->track = bp->mouse; - f->focus = TRACK; - } - } - - return True; - } - - return False; -} - - -/* Generate the polygons for the display lists. - This routine generates the various styles of sphere-oid we use. - */ -static int -draw_ball (ModeInfo *mi, component which) -{ - peepers_configuration *bp = &bps[MI_SCREEN(mi)]; - int wire = MI_IS_WIREFRAME(mi); - int polys = 0; - - GLfloat iris_ratio = 0.42; /* Size of the iris. */ - /* The lens bulges out, but the iris bulges in, sorta. */ - GLfloat lens_bulge = (which == IRIS ? -0.50 : 0.32); - - GLfloat xstep = 32; /* Facets on the sphere */ - GLfloat ystep = 32; - XYZ *stacks, *normals; - GLfloat x, y, z; - int i, j; - int xstart, xstop; - - if (bp->nfloaters > 16 || wire) - xstep = ystep = 16; - - if (bp->nfloaters > 96 && which == LENS) - return 0; - - switch (which) { - case LENS: xstart = 0; xstop = xstep; break; - case SCLERA: xstart = 0; xstop = xstep * (1 - iris_ratio/2); break; - case IRIS: xstart = xstep * (1 - iris_ratio/2 * 1.2); xstop = xstep; break; - case RETINA: xstart = xstep * (1 - iris_ratio/2 * 1.2); xstop = 0; break; - default: abort(); break; - } - - stacks = (XYZ *) calloc (sizeof(*stacks), xstep + 1); - normals = (XYZ *) calloc (sizeof(*stacks), xstep + 1); - - if (which == RETINA) - { - GLfloat c1[4] = { 0, 0, 0, 1 }; - GLfloat c2[4] = { 0.15, 0, 0, 1 }; - GLfloat th = M_PI * (1.0 - iris_ratio/2); - GLfloat z1 = cos(th); - GLfloat z2 = 0.9; - GLfloat r1 = sin(th); - GLfloat r2 = r1 * 0.3; - - if (!wire) - { - glColor4fv (c1); - glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, c1); - glMaterialfv (GL_FRONT_AND_BACK, GL_SPECULAR, c1); - } - - /* Draw a black cone to occlude the interior of the eye. */ - - glBegin (wire ? GL_LINES : GL_QUAD_STRIP); - for (i = 0; i <= xstep; i++) - { - GLfloat th2 = i * M_PI * 2 / xstep; - GLfloat x = cos(th2); - GLfloat y = sin(th2); - glNormal3f (0, 0, 1); - glVertex3f (z1, r1 * x, r1 * y); - glNormal3f (0, 0, 1); - glVertex3f (z2, r2 * x, r2 * y); - polys++; - } - glEnd(); - - if (!wire) - { - glColor4fv (c2); - glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, c2); - glMaterialfv (GL_FRONT_AND_BACK, GL_SPECULAR, c2); - } - - /* Draw a small red circle at the base of the cone. */ - - glBegin (wire ? GL_LINES : GL_TRIANGLE_FAN); - glVertex3f (z2, 0, 0); - glNormal3f (0, 0, 1); - for (i = xstep; i >= 0; i--) - { - GLfloat th2 = i * M_PI * 2 / xstep; - GLfloat x = cos(th2); - GLfloat y = sin(th2); - glVertex3f (z2, r2 * x, r2 * y); - polys++; - } - glEnd(); - goto DONE; - } - - for (i = xstart; i <= xstop; i++) - { - GLfloat th = i * M_PI / xstep; - GLfloat x = cos(th); - GLfloat y = sin(th); - - /* Bulge the lens, or dimple the iris. */ - if (th > M_PI * (1.0 - iris_ratio/2) && - th < M_PI * (1.0 + iris_ratio/2)) - { - GLfloat r = (1 - th / M_PI) / iris_ratio * 2; - r = cos (M_PI * r / 2); - r *= lens_bulge; - r = r * r * (lens_bulge < 0 ? -1 : 1); - x *= 1+r; - y *= 1+r; - } - - stacks[i].x = x; - stacks[i].y = y; - stacks[i].z = 0; - } - - /* Fill normals with the normal at the center of each face. */ - for (i = xstart; i < xstop; i++) - { - GLfloat dx = stacks[i+1].x - stacks[i].x; - GLfloat dy = stacks[i+1].y - stacks[i].y; - y = dy/dx; - z = sqrt (1 + y*y); - normals[i].x = -y/z; - normals[i].y = 1/z; - normals[i].z = 0; - - if (lens_bulge < 0 && i > xstep * (1 - iris_ratio/2) + 1) - { - normals[i].x *= -1; - normals[i].y *= -1; - } - } - - if (!wire) - glBegin (GL_QUADS); - - for (i = xstart; i < xstop; i++) - { - GLfloat x0 = stacks[i].x; - GLfloat x1 = stacks[i+1].x; - GLfloat r0 = stacks[i].y; - GLfloat r1 = stacks[i+1].y; - - for (j = 0; j < ystep*2; j++) - { - GLfloat tha = j * M_PI / ystep; - GLfloat thb = (j+1) * M_PI / ystep; - GLfloat xa = cos (tha); - GLfloat ya = sin (tha); - GLfloat xb = cos (thb); - GLfloat yb = sin (thb); - - /* Each vertex normal is average of adjacent face normals. */ - - XYZ p1, p2, p3, p4; - XYZ n1, n2, n3, n4; - p1.x = x0; p1.y = r0 * ya; p1.z = r0 * xa; - p2.x = x1; p2.y = r1 * ya; p2.z = r1 * xa; - p3.x = x1; p3.y = r1 * yb; p3.z = r1 * xb; - p4.x = x0; p4.y = r0 * yb; p4.z = r0 * xb; - - if (i == 0) - { - n1.x = 1; n1.y = 0; n1.z = 0; - n4.x = 1; n4.y = 0; n4.z = 0; - } - else - { - x = (normals[i-1].x + normals[i].x) / 2; - y = (normals[i-1].y + normals[i].y) / 2; - n1.x = x; n1.z = y * xa; n1.y = y * ya; - n4.x = x; n4.z = y * xb; n4.y = y * yb; - } - - if (i == xstep-1) - { - n2.x = -1; n2.y = 0; n2.z = 0; - n3.x = -1; n3.y = 0; n3.z = 0; - } - else - { - x = (normals[i+1].x + normals[i].x) / 2; - y = (normals[i+1].y + normals[i].y) / 2; - n2.x = x; n2.z = y * xa; n2.y = y * ya; - n3.x = x; n3.z = y * xb; n3.y = y * yb; - } - -#if 0 - /* Render normals as lines for debugging */ - glBegin(GL_LINES); - glVertex3f(p1.x, p1.y, p1.z); - glVertex3f(p1.x + n1.x * 0.3, p1.y + n1.y * 0.3, p1.z + n1.z * 0.3); - glEnd(); - - glBegin(GL_LINES); - glVertex3f(p2.x, p2.y, p2.z); - glVertex3f(p2.x + n2.x * 0.3, p2.y + n2.y * 0.3, p2.z + n2.z * 0.3); - glEnd(); - - glBegin(GL_LINES); - glVertex3f(p3.x, p3.y, p3.z); - glVertex3f(p3.x + n3.x * 0.3, p3.y + n3.y * 0.3, p3.z + n3.z * 0.3); - glEnd(); - - glBegin(GL_LINES); - glVertex3f(p4.x, p4.y, p4.z); - glVertex3f(p4.x + n4.x * 0.3, p4.y + n4.y * 0.3, p4.z + n4.z * 0.3); - glEnd(); -#endif - - if (wire) - glBegin (GL_LINE_LOOP); - - glTexCoord2f ((j+1) / (GLfloat) ystep / 2, - (i - xstart) / (GLfloat) (xstop - xstart)); - - glNormal3f (n4.x, n4.y, n4.z); - glVertex3f (p4.x, p4.y, p4.z); - - glTexCoord2f ((j+1) / (GLfloat) ystep / 2, - ((i+1) - xstart) / (GLfloat) (xstop - xstart)); - - glNormal3f (n3.x, n3.y, n3.z); - glVertex3f (p3.x, p3.y, p3.z); - - glTexCoord2f (j / (GLfloat) ystep / 2, - ((i+1) - xstart) / (GLfloat) (xstop - xstart)); - - glNormal3f (n2.x, n2.y, n2.z); - glVertex3f (p2.x, p2.y, p2.z); - - glTexCoord2f (j / (GLfloat) ystep / 2, - (i - xstart) / (GLfloat) (xstop - xstart)); - - glNormal3f (n1.x, n1.y, n1.z); - glVertex3f (p1.x, p1.y, p1.z); - - polys++; - - if (wire) - glEnd(); - } - } - - if (!wire) - glEnd(); - - DONE: - free (stacks); - free (normals); - - return polys; -} - - -ENTRYPOINT void -init_peepers (ModeInfo *mi) -{ - peepers_configuration *bp; - int wire = MI_IS_WIREFRAME(mi); - int i; - - MI_INIT (mi, bps); - - bp = &bps[MI_SCREEN(mi)]; - - bp->glx_context = init_GL(mi); - - reshape_peepers (mi, MI_WIDTH(mi), MI_HEIGHT(mi)); - - glShadeModel(GL_SMOOTH); - - glEnable(GL_DEPTH_TEST); - glEnable(GL_NORMALIZE); - - if (!wire) - { - XImage *xi; - GLfloat pos[4] = {0.4, 0.2, 0.4, 0.0}; - GLfloat amb[4] = {0.1, 0.1, 0.1, 1.0}; - - glLightfv(GL_LIGHT0, GL_POSITION, pos); - glLightfv(GL_LIGHT0, GL_AMBIENT, amb); - - glEnable (GL_LIGHTING); - glEnable (GL_LIGHT0); - glEnable (GL_DEPTH_TEST); - glEnable (GL_CULL_FACE); - glEnable (GL_BLEND); - - glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - glLightfv(GL_LIGHT0, GL_POSITION, pos); - glLightfv(GL_LIGHT0, GL_AMBIENT, amb); - - glPixelStorei (GL_UNPACK_ALIGNMENT, 1); - - xi = image_data_to_ximage (mi->dpy, mi->xgwa.visual, - sclera_png, sizeof(sclera_png)); - glGenTextures (1, &bp->sclera_texture); - glBindTexture (GL_TEXTURE_2D, bp->sclera_texture); - - glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, - xi->width, xi->height, 0, - GL_RGBA, GL_UNSIGNED_BYTE, xi->data); - check_gl_error("texture"); - XDestroyImage (xi); - - xi = image_data_to_ximage (mi->dpy, mi->xgwa.visual, - iris_png, sizeof(iris_png)); - - glGenTextures (1, &bp->iris_texture); - glBindTexture (GL_TEXTURE_2D, bp->iris_texture); - - glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, - xi->width, xi->height, 0, - GL_RGBA, GL_UNSIGNED_BYTE, xi->data); - check_gl_error("texture"); - XDestroyImage (xi); - - - } - - bp->lens_list = glGenLists (1); - glNewList (bp->lens_list, GL_COMPILE); - bp->eye_polys += draw_ball (mi, LENS); - glEndList (); - - bp->sclera_list = glGenLists (1); - glNewList (bp->sclera_list, GL_COMPILE); - bp->eye_polys += draw_ball (mi, SCLERA); - glEndList (); - - bp->iris_list = glGenLists (1); - glNewList (bp->iris_list, GL_COMPILE); - bp->eye_polys += draw_ball (mi, IRIS); - glEndList (); - - bp->retina_list = glGenLists (1); - glNewList (bp->retina_list, GL_COMPILE); - bp->eye_polys += draw_ball (mi, RETINA); - glEndList (); - - bp->trackball = gltrackball_init (False); - - if (!mode_opt || !*mode_opt || !strcasecmp (mode_opt, "random")) - bp->mode = ((random() & 1) ? BOUNCE : - ((random() & 1) ? SCROLL_LEFT : SCROLL_RIGHT)); - else if (!strcasecmp (mode_opt, "bounce")) - bp->mode = BOUNCE; - else if (!strcasecmp (mode_opt, "scroll")) - bp->mode = (random() & 1) ? SCROLL_LEFT : SCROLL_RIGHT; - else if (!strcasecmp (mode_opt, "xeyes")) - bp->mode = XEYES; - else if (!strcasecmp (mode_opt, "beholder") || - !strcasecmp (mode_opt, "ball")) - bp->mode = BEHOLDER; - else - { - fprintf (stderr, - "%s: mode must be bounce, scroll, random, xeyes or beholder," - " not \"%s\"\n", - progname, mode_opt); - exit (1); - } - - bp->nfloaters = MI_COUNT (mi); - - if (bp->nfloaters <= 0) - { - if (bp->mode == XEYES) - bp->nfloaters = 2 + (random() % 30); - else if (bp->mode == BEHOLDER) - bp->nfloaters = 20 * pow (4, (random() % 4)); - else - bp->nfloaters = 2 + (random() % 6); - } - - if (bp->mode == BEHOLDER) - { - if (bp->nfloaters <= 20) bp->nfloaters = 20; /* This is lame */ - else if (bp->nfloaters <= 80) bp->nfloaters = 80; - else if (bp->nfloaters <= 320) bp->nfloaters = 320; - else bp->nfloaters = 1280; - } - - bp->floaters = (floater *) calloc (bp->nfloaters, sizeof (floater)); - - for (i = 0; i < bp->nfloaters; i++) - { - floater *f = &bp->floaters[i]; - f->idx = i; - f->rot = make_rotator (10.0, 0, 0, - 4, 0.05 * speed, - True); - if (bp->nfloaters == 2) - { - f->x = 10 * (i ? 1 : -1); - } - else if (i != 0) - { - double th = (i - 1) * M_PI*2 / (bp->nfloaters-1); - double r = LEFT * 0.3; - f->x = r * cos(th); - f->z = r * sin(th); - } - - if (bp->mode == SCROLL_LEFT || bp->mode == SCROLL_RIGHT) - { - f->y = f->x; - f->x = 0; - } - - reset_floater (mi, f); - } - - if (bp->mode == XEYES) - layout_grid (mi); - else if (bp->mode == BEHOLDER) - layout_geodesic (mi); - -# ifndef HAVE_JWXYZ /* Real X11 */ -# if 0 /* I wonder if this works? */ - if (bp->mode == XEYES && MI_WIN_IS_INWINDOW (mi)) - { - uint32_t ca = 0; - glClearColor (0, 0, 0, 0); - XChangeProperty (MI_DISPLAY(mi), MI_WINDOW(mi), - XInternAtom (MI_DISPLAY(mi), - "_NET_WM_WINDOW_OPACITY", 0), - XA_CARDINAL, 32, PropModeReplace, - (uint8_t *) &ca, 1); - } -# endif -# endif -} - - -static void -draw_floater (ModeInfo *mi, floater *f, component which) -{ - peepers_configuration *bp = &bps[MI_SCREEN(mi)]; - int wire = MI_IS_WIREFRAME(mi); - double x, y, z; - - GLfloat spc[4] = { 1.0, 1.0, 1.0, 1.0 }; - GLfloat c2[4] = { 1.0, 1.0, 1.0, 1.0 }; - GLfloat c2b[4] = { 1.0, 0.6, 0.6, 1.0 }; - GLfloat c2c[4] = { 1.0, 1.0, 0.65, 1.0 }; - GLfloat c3[4] = { 0.6, 0.6, 0.6, 0.25 }; - - get_position (f->rot, &x, &y, &z, - which == LENS && !bp->button_down_p); - - if (bp->nfloaters == 2 && - f != &bp->floaters[0] && - (bp->mode == BOUNCE || bp->mode == XEYES)) - { - /* When there are exactly two eyes, track them together. */ - floater *f0 = &bp->floaters[0]; - double x0, y0, z0; - get_position (f0->rot, &x0, &y0, &z0, 0); - x = x0; - y = 1-y0; /* This is rotation: what the eye is looking at */ - z = z0; - if (bp->mode != XEYES) - { - f->x = f0->x + f0->scale * 3; - f->y = f0->y; - f->z = f0->z; - } - f->dilation = f0->dilation; - f->focus = f0->focus; - f->track = f0->track; - f->tilt = f0->tilt; - f->scale = f0->scale; - f->jaundice = f0->jaundice; - if (f->focus == ROTATE) - f->focus = f0->focus = TRACK; - memcpy (f->color, f0->color, sizeof(f0->color)); - } - - glPushMatrix(); - glTranslatef (f->x, f->y, f->z); - - /* gltrackball_rotate (bp->trackball); */ - - switch (f->focus) { - case ROTATE: - glRotatef (y * 180, 0, 1, 0); - glRotatef (f->tilt, 0, 0, 1); - break; - case SPIN: - glRotatef (y * 360 + 90, 0, 1, 0); - glRotatef (x * 360, 1.0, 0.0, 0.0); - glRotatef (z * 360, 0.0, 0.0, 1.0); - break; - case TRACK: - { - GLfloat X, Y, Z; - X = f->track.x - f->x; - Y = f->track.z - f->z; - Z = f->track.y - f->y; - if (X != 0 || Y != 0) - { - GLfloat facing = atan2 (X, Y) * (180 / M_PI); - GLfloat pitch = atan2 (Z, sqrt(X*X + Y*Y)) * (180 / M_PI); - glRotatef (90, 0, 1, 0); - glRotatef (facing, 0, 1, 0); - glRotatef (-pitch, 0, 0, 1); - } - } - - break; - default: - abort(); - } - - glRotatef (f->roll, 1, 0, 0); - glScalef (f->scale, f->scale, f->scale); - - if (! wire) - glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - - switch (which) { - case RETINA: - if (!wire) - { - glScalef (0.96, 0.96, 0.96); - glCallList (bp->retina_list); - } - break; - - case IRIS: - glColor4fv (f->color); - if (! wire) - { - glMaterialfv (GL_FRONT_AND_BACK, GL_SPECULAR, spc); - glMaterialf (GL_FRONT_AND_BACK, GL_SHININESS, 10); - - glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, f->color); - glMaterialf (GL_FRONT_AND_BACK, GL_SHININESS, 20); - - glEnable (GL_TEXTURE_2D); - glBindTexture (GL_TEXTURE_2D, bp->iris_texture); - glMatrixMode (GL_TEXTURE); - glLoadIdentity(); - glScalef (1, 1.25 + f->dilation.current * 0.3, 1); - glMatrixMode (GL_MODELVIEW); - } - glScalef (0.96, 0.96, 0.96); - glCallList (bp->iris_list); - - if (! wire) - { - glMatrixMode (GL_TEXTURE); - glLoadIdentity(); - glMatrixMode (GL_MODELVIEW); - } - break; - - case SCLERA: - if (! wire) - { - GLfloat *c = (f->jaundice == 2 ? c2b : f->jaundice == 1 ? c2c : c2); - glColor4fv (c); - glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, c); - glBindTexture (GL_TEXTURE_2D, bp->sclera_texture); - - glScalef (0.98, 0.98, 0.98); - glCallList (bp->sclera_list); - } - break; - - case LENS: - glColor4fv (c3); - if (! wire) - { - glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, c3); - glDisable (GL_TEXTURE_2D); - } - glCallList (bp->lens_list); - break; - - default: - abort(); - break; - } - - glPopMatrix(); -} - - -ENTRYPOINT void -draw_peepers (ModeInfo *mi) -{ - peepers_configuration *bp = &bps[MI_SCREEN(mi)]; - Display *dpy = MI_DISPLAY(mi); - Window window = MI_WINDOW(mi); - - if (!bp->glx_context) - return; - - glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *bp->glx_context); - - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - glPushMatrix (); - - glRotatef (current_device_rotation(), 0, 0, 1); - - - /* Scale so that screen is 1 high and w/h wide. */ - glScalef (8, 8, 8); - - mi->polygon_count = 0; - - if (bp->mode == XEYES || bp->mode == BEHOLDER) - { - int i; - track_mouse (mi); - for (i = 0; i < bp->nfloaters; i++) - { - floater *f = &bp->floaters[i]; - f->track = bp->mouse; - f->focus = TRACK; - } - } - -# if 0 - { - /* Draw just one */ - component j; - floater F; - reset_floater(mi, &F); - F.x = F.y = F.z = 0; - F.dx = F.dy = F.dz = 0; - F.ddx = F.ddy = F.ddz = 0; - F.scale = 1; - F.focus = TRACK; - F.dilation.current = 0; - F.track.x = F.track.y = F.track.z = 0; - F.rot = make_rotator (0, 0, 0, 1, 0, False); - glRotatef(180,0,1,0); - glRotatef(15,1,0,0); - for (j = RETINA; j <= LENS; j++) - draw_floater (mi, &F, j); - mi->polygon_count += bp->eye_polys; - } -# else - { - component j; - int i; - for (j = RETINA; j <= TICK; j++) - for (i = 0; i < bp->nfloaters; i++) - { - floater *f = &bp->floaters[i]; - if (j == TICK) - tick_floater (mi, f); - else - draw_floater (mi, f, j); - } - - if (bp->mode != BEHOLDER) - de_collide (mi); - - mi->polygon_count += bp->eye_polys * bp->nfloaters; - } -# endif - - glPopMatrix (); - - if (mi->fps_p) do_fps (mi); - glFinish(); - - glXSwapBuffers(dpy, window); -} - - -ENTRYPOINT void -free_peepers (ModeInfo *mi) -{ - peepers_configuration *bp = &bps[MI_SCREEN(mi)]; - int i; - if (!bp->glx_context) return; - glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *bp->glx_context); - for (i = 0; i < bp->nfloaters; i++) - free_rotator (bp->floaters[i].rot); - if (bp->floaters) free (bp->floaters); - if (glIsList(bp->lens_list)) glDeleteLists(bp->lens_list, 1); - if (glIsList(bp->sclera_list)) glDeleteLists(bp->sclera_list, 1); - if (glIsList(bp->iris_list)) glDeleteLists(bp->iris_list, 1); - if (glIsList(bp->retina_list)) glDeleteLists(bp->retina_list, 1); - if (bp->sclera_texture) glDeleteTextures (1, &bp->sclera_texture); - if (bp->iris_texture) glDeleteTextures (1, &bp->iris_texture); -} - -XSCREENSAVER_MODULE ("Peepers", peepers) - -#endif /* USE_GL */ |
