/* * lockward.c: First attempt at an Xscreensaver. * * Leo L. Schwab 2007.08.17 **** * Copyright (c) 2007 Leo L. Schwab * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to permit * persons to whom the Software is furnished to do so, subject to the * following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE * USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include #include #include "xlockmore.h" #include "colors.h" /*************************************************************************** * #defines */ #ifdef USE_GL /* whole file */ #define DEFAULTS "*delay: 20000 \n"\ "*showFPS: False \n" #define release_lockward 0 #define NUMOF(x) (sizeof ((x)) / sizeof ((*x))) #define NBLADES 12 #define NSPINNERS 4 #define NRADII 8 #define COLORIDX_SHF 4 #define SUBDIV 6 #undef countof #define countof(x) (sizeof((x))/sizeof((*x))) /*************************************************************************** * Structure definitions. */ struct lockward_context; /* Forward declaration. */ #define int8_t char #define int16_t short #define int32_t int #define uint8_t unsigned char #define uint16_t unsigned short #define uint32_t unsigned int typedef struct bladestate { uint8_t outer, inner; /* Radii */ } bladestate; typedef struct spinnerstate { GLfloat rot; /* Terminal rotation after count expires */ GLfloat rotinc; /* Per-frame increment to rot. */ XColor *colors; bladestate *bladeidx; int ncolors; /* n.4 fixed-point */ int ccolor; /* n.4 fixed-point */ int colorinc; /* n.4 fixed-point */ int rotcount; uint8_t nblades; } spinnerstate; typedef struct blinkstate { int (*drawfunc) (struct lockward_context *ctx, struct blinkstate *bs); uint32_t *noise; /* For draw_blink_segment_scatter() */ GLfloat color[4]; uint32_t val; int16_t dwell; /* <0: sharp >0: decay */ int16_t dwellcnt; uint8_t type; int8_t counter; int8_t direction; int8_t radius; } blinkstate; enum blinktype { BTYPE_RADIAL_SINGLE = 0, BTYPE_RADIAL_RANDOM, BTYPE_RADIAL_SEQ, BTYPE_RADIAL_DOUBLESEQ, BTYPE_SEGMENT_SINGLE, BTYPE_SEGMENT_RANDOM, BTYPE_CONCENTRIC_SINGLE, BTYPE_CONCENTRIC_RANDOM, BTYPE_CONCENTRIC_SEQ, BTYPE_SEGMENT_SCATTER, MAX_BTYPE }; typedef struct { GLfloat x,y,z; } XYZ; typedef struct lockward_context { GLXContext *glx_context; spinnerstate spinners[NSPINNERS]; blinkstate blink; /* This used to put vertexes into lists without putting begin/end into the same list! I didn't even know that worked. Well, it doesn't work with jwzgles, so I changed it to not do that. */ /* GLuint blades_outer, blades_inner; */ XYZ points_outer[NRADII][SUBDIV+1]; XYZ points_inner[NRADII][SUBDIV+1]; GLuint rings; Bool blendmode; int nextblink; int fps; } lockward_context; /*************************************************************************** * Prototypes. */ ENTRYPOINT void free_lockward (ModeInfo *mi); /*************************************************************************** * Global variables. */ static lockward_context *g_ctx = NULL; static Bool g_blink_p = True; static int g_blades = NBLADES; static int g_rotateidle_min, g_rotateidle_max; static int g_blinkidle_min, g_blinkidle_max; static int g_blinkdwell_min, g_blinkdwell_max; #define DEF_BLINK "True" #define DEF_ROTATEIDLEMIN "1000" #define DEF_ROTATEIDLEMAX "6000" #define DEF_BLINKIDLEMIN "1000" #define DEF_BLINKIDLEMAX "9000" #define DEF_BLINKDWELLMIN "100" #define DEF_BLINKDWELLMAX "600" static XrmOptionDescRec opts[] = { { "-blink", ".blink", XrmoptionNoArg, "on" }, { "+blink", ".blink", XrmoptionNoArg, "off" }, { "-rotateidle-min", ".rotateidlemin", XrmoptionSepArg, 0 }, { "-rotateidle-max", ".rotateidlemax", XrmoptionSepArg, 0 }, { "-blinkidle-min", ".blinkidlemin", XrmoptionSepArg, 0 }, { "-blinkidle-max", ".blinkidlemax", XrmoptionSepArg, 0 }, { "-blinkdwell-min", ".blinkdwellmin", XrmoptionSepArg, 0 }, { "-blinkdwell-max", ".blinkdwellmax", XrmoptionSepArg, 0 }, }; static argtype vars[] = { { &g_blink_p, "blink", "Blink", DEF_BLINK, t_Bool }, { &g_rotateidle_min, "rotateidlemin", "Rotateidlemin", DEF_ROTATEIDLEMIN, t_Int }, { &g_rotateidle_max, "rotateidlemax", "Rotateidlemax", DEF_ROTATEIDLEMAX, t_Int }, { &g_blinkidle_min, "blinkidlemin", "Blinkidlemin", DEF_BLINKIDLEMIN, t_Int }, { &g_blinkidle_max, "blinkidlemax", "Blinkidlemax", DEF_BLINKIDLEMAX, t_Int }, { &g_blinkdwell_min, "blinkdwellmin", "Blinkdwellmin", DEF_BLINKDWELLMIN, t_Int }, { &g_blinkdwell_max, "blinkdwellmax", "Blinkdwellmax", DEF_BLINKDWELLMAX, t_Int }, }; static OptionStruct desc[] = { { "-/+blink", "Turn on/off blinking effects." }, { "-rotateidle-min", "Minimum idle time for rotators, in milliseconds." }, { "-rotateidle-max", "Maximum idle time for rotators, in milliseconds." }, { "-blinkidle-min", "Minimum idle time between blink effects, in milliseconds." }, { "-blinkidle-max", "Maximum idle time between blink effects, in milliseconds." }, { "-blinkdwell-min", "Minimum dwell time for blink effects, in milliseconds." }, { "-blinkdwell-max", "Maximum dwell time for blink effects, in milliseconds." }, }; ENTRYPOINT ModeSpecOpt lockward_opts = { NUMOF(opts), opts, NUMOF(vars), vars, desc }; /*************************************************************************** * Window management. */ ENTRYPOINT void reshape_lockward (ModeInfo *mi, int width, int height) { lockward_context *ctx = &g_ctx[MI_SCREEN (mi)]; GLfloat h = (GLfloat) height / (GLfloat) width; int y = 0; if (width > height * 5) { /* tiny window: show middle */ height = width * 9/16; y = -height/2; h = height / (GLfloat) width; } glXMakeCurrent (MI_DISPLAY (mi), MI_WINDOW (mi), *ctx->glx_context); glViewport (0, y, (GLint) width, (GLint) height); glMatrixMode (GL_PROJECTION); glLoadIdentity (); if (height > width) glOrtho (-8.0, 8.0, -8.0 * h, 8.0 * h, -1, 1); else glOrtho (-8.0 / h, 8.0 / h, -8.0, 8.0, -1, 1); glMatrixMode (GL_MODELVIEW); } ENTRYPOINT Bool lockward_handle_event (ModeInfo *mi, XEvent *event) { lockward_context *ctx = &g_ctx[MI_SCREEN (mi)]; if (event->xany.type == KeyPress) { KeySym keysym; char c = 0; XLookupString (&event->xkey, &c, 1, &keysym, 0); if (c == ' ' || c == '\t') { ctx->blendmode ^= 1; return True; } } return False; } /*************************************************************************** * "Blade" routines. */ static void random_blade_rot (lockward_context *ctx, struct spinnerstate *ss) { /* * The circle is divided up in to g_blades divisions. The idea here * is to rotate to an exact division point. * * The target rotation is computed via random numbers. * * The time it takes to get there is a maximum of six seconds per * division, and a minimum of one second (no matter how far away it * is), and is selected by random numbers. * * The time value is converted into frames, and a per-frame rotation * is computed. * * During rendering, we approach the target rotation by subtracting * from it the per-frame rotation times the number of outstanding * ticks. Doing it this way means we'll hit the target rotation * exactly, without low-order errors creeping in to the values (at * least not nearly as quickly). */ GLfloat d; int dist; dist = random() % g_blades + 1; ss->rotcount = random() % (6 * dist * ctx->fps - ctx->fps) + ctx->fps; if (random() & 4) dist = -dist; d = dist * 360.0 / (GLfloat) g_blades; ss->rot += d; ss->rotinc = d / (GLfloat) ss->rotcount; } /* * A "blade" is pie-wedge shaped flat thing that is rotated around where the * apex is/would be. Initially envisioned as 1/12th of a circle, but that * could be configurable. The inner and outer edges are rounded off using * six subdivisions so that, when multiple blades are assembled, it looks * more like a circle and less like a polygon. * * The blade is assembled as a tri-fan. It is oriented centered at 3 * o'clock. The blade is composed of two display lists -- arcs, essentially * -- the outer and the inner one. The outer one *must* be called before * the inner one, or the blade clockwise-ness will be wrong, and become * invisible. Arcs of various radii are compiled. */ static void gen_blade_arcs (lockward_context *ctx) { GLfloat here, there, step; int i, n; here = 0; there = M_PI * 2.0 / g_blades; step = there / SUBDIV; here -= SUBDIV * step / 2.0; /* * Build outer blade arcs. * Start at left side of outer radius. Strike all its vertices. */ for (n = 0; n < NRADII; ++n) { /* glNewList (ctx->blades_outer + n, GL_COMPILE); */ XYZ *a = ctx->points_outer[n]; int j = 0; for (i = SUBDIV; i >= 0; --i) { /* glVertex3f (cos (here + step * i) * (n + 1.0), sin (here + step * i) * (n + 1.0), 0); */ a[j].x = cos (here + step * i) * (n + 1.0); a[j].y = sin (here + step * i) * (n + 1.0); a[j].z = 0; j++; } if (j != SUBDIV+1) abort(); /* glEndList (); */ } /* * Build inner blade arcs. * Move to inner radius, strike all vertices in opposite order. */ for (n = 0; n < NRADII; ++n) { /* glNewList (ctx->blades_inner + n, GL_COMPILE); */ XYZ *a = ctx->points_inner[n]; int j = 0; for (i = 0; i <= SUBDIV; ++i) { /* glVertex3f (cos (here + step * i) * (n + 1.0), sin (here + step * i) * (n + 1.0), 0); */ a[j].x = cos (here + step * i) * (n + 1.0); a[j].y = sin (here + step * i) * (n + 1.0); a[j].z = 0; j++; } if (j != SUBDIV+1) abort(); /* glEndList (); */ } } static void gen_rings (lockward_context *ctx) { GLfloat step; int i, n; step = M_PI * 2.0 / (g_blades * SUBDIV); for (n = 0; n < NRADII - 1; ++n) { glNewList (ctx->rings + n, GL_COMPILE); glBegin (GL_TRIANGLE_STRIP); for (i = g_blades * SUBDIV; i >= 0; --i) { glVertex3f (cos (step * i) * (n + 1.0), sin (step * i) * (n + 1.0), 0); glVertex3f (cos (step * i) * (n + 2.0), sin (step * i) * (n + 2.0), 0); } glEnd(); glEndList (); } } /*************************************************************************** * "Blink" routines. */ static int calc_interval_frames (lockward_context *ctx, int min, int max) { /* * Compute random interval between min and max milliseconds. * Returned value is in frames. */ register int i; i = min; if (max > min) i += random() % (max - min); return i * ctx->fps / 1000; } static void set_alpha_by_dwell (struct blinkstate *bs) { if (bs->dwell > 0) bs->color[3] = (GLfloat) bs->dwellcnt / (GLfloat) bs->dwell; else bs->color[3] = bs->dwellcnt > (-bs->dwell >> 2) ? 1.0 : 0.0; } static void draw_blink_blade (lockward_context *ctx, int inner, int outer, Bool begin_p) { int i; if (begin_p) glBegin (GL_TRIANGLE_FAN); /* glCallList (ctx->blades_outer + outer); */ for (i = 0; i < countof(*ctx->points_outer); i++) glVertex3f(ctx->points_outer[outer][i].x, ctx->points_outer[outer][i].y, ctx->points_outer[outer][i].z); /* glCallList (ctx->blades_inner + inner); */ for (i = 0; i < countof(*ctx->points_inner); i++) glVertex3f(ctx->points_inner[inner][i].x, ctx->points_inner[inner][i].y, ctx->points_inner[inner][i].z); if (begin_p) glEnd(); } static int draw_blink_radial_random (lockward_context *ctx, struct blinkstate *bs) { int i; /* * There is no sense of direction in a random sweep, so re-use the * 'direction' field to hold the current blade we're messing with. */ if (bs->dwellcnt < 0) { if (bs->counter <= 0) { bs->drawfunc = NULL; return 0; } /* * Find available blade. Potentially very slow, depending on * how unlucky we are. */ do { i = random() % g_blades; } while (bs->val & (1 << i)); bs->val |= (1 << i); /* Mark as used. */ bs->direction = i; if ((bs->dwellcnt = bs->dwell) < 0) bs->dwellcnt = -bs->dwellcnt; if ( bs->type == BTYPE_SEGMENT_SINGLE || bs->type == BTYPE_SEGMENT_RANDOM) bs->radius = random() % (NRADII - 1); --bs->counter; } set_alpha_by_dwell (bs); glBlendFunc (GL_DST_COLOR, GL_SRC_ALPHA); glColor4fv (bs->color); glRotatef (bs->direction * 360.0 / (GLfloat) g_blades, 0, 0, 1); if (bs->radius >= 0) draw_blink_blade (ctx, bs->radius, bs->radius + 1, True); else draw_blink_blade (ctx, 0, NRADII - 1, True); --bs->dwellcnt; return SUBDIV + SUBDIV; } static int draw_blink_radial_sequential (lockward_context *ctx, struct blinkstate *bs) { if (bs->dwellcnt < 0) { if (bs->counter <= 0) { bs->drawfunc = NULL; return 0; } if ((bs->dwellcnt = bs->dwell) < 0) bs->dwellcnt = -bs->dwellcnt; --bs->counter; } set_alpha_by_dwell (bs); glBlendFunc (GL_DST_COLOR, GL_SRC_ALPHA); glColor4fv (bs->color); glRotatef ((bs->counter * bs->direction + (int) bs->val) * 360.0 / (GLfloat) g_blades, 0, 0, 1); draw_blink_blade (ctx, 0, NRADII - 1, True); --bs->dwellcnt; return SUBDIV + SUBDIV; } static int draw_blink_radial_doubleseq (lockward_context *ctx, struct blinkstate *bs) { int polys; if (bs->dwellcnt < 0) { if (bs->counter <= 0) { bs->drawfunc = NULL; return 0; } if ((bs->dwellcnt = bs->dwell) < 0) bs->dwellcnt = -bs->dwellcnt; --bs->counter; } set_alpha_by_dwell (bs); glBlendFunc (GL_DST_COLOR, GL_SRC_ALPHA); glColor4fv (bs->color); glPushMatrix (); glRotatef (((int) bs->val + bs->counter) * 360.0 / (GLfloat) g_blades, 0, 0, 1); draw_blink_blade (ctx, 0, NRADII - 1, True); glPopMatrix (); polys = SUBDIV + SUBDIV; if (bs->counter && bs->counter < g_blades / 2) { glRotatef (((int) bs->val - bs->counter) * 360.0 / (GLfloat) g_blades, 0, 0, 1); draw_blink_blade (ctx, 0, NRADII - 1, True); polys += SUBDIV + SUBDIV; } --bs->dwellcnt; return polys; } static int draw_blink_concentric_random (lockward_context *ctx, struct blinkstate *bs) { int i; if (bs->dwellcnt < 0) { if (bs->counter <= 0) { bs->drawfunc = NULL; return 0; } do { i = random() % (NRADII - 1); } while (bs->val & (1 << i)); bs->val |= (1 << i); bs->direction = i; if ((bs->dwellcnt = bs->dwell) < 0) bs->dwellcnt = -bs->dwellcnt; --bs->counter; } set_alpha_by_dwell (bs); glBlendFunc (GL_DST_COLOR, GL_SRC_ALPHA); glColor4fv (bs->color); glCallList (ctx->rings + bs->direction); --bs->dwellcnt; return g_blades * SUBDIV * 2; } static int draw_blink_concentric_sequential (lockward_context *ctx, struct blinkstate *bs) { if (bs->dwellcnt < 0) { if (bs->counter <= 0) { bs->drawfunc = NULL; return 0; } if ((bs->dwellcnt = bs->dwell) < 0) bs->dwellcnt = -bs->dwellcnt; --bs->counter; } set_alpha_by_dwell (bs); glBlendFunc (GL_DST_COLOR, GL_SRC_ALPHA); glColor4fv (bs->color); if (bs->direction > 0) glCallList (ctx->rings + (NRADII - 2) - bs->counter); else glCallList (ctx->rings + bs->counter); --bs->dwellcnt; return g_blades * SUBDIV * 2; } static int draw_blink_segment_scatter (lockward_context *ctx, struct blinkstate *bs) { int i, polys = 0; if (bs->dwellcnt < 0) { if (bs->counter <= 0) { bs->drawfunc = NULL; return 0; } /* * Init random noise array. On average, 1/4 of the bits will * be set, which should look nice. (1/2 looks too busy.) */ for (i = g_blades; --i >= 0; ) bs->noise[i] = random() & random() & ((1 << (NRADII - 1)) - 1); if ((bs->dwellcnt = bs->dwell) < 0) bs->dwellcnt = -bs->dwellcnt; --bs->counter; } set_alpha_by_dwell (bs); glBlendFunc (GL_DST_COLOR, GL_SRC_ALPHA); glColor4fv (bs->color); for (i = g_blades; --i >= 0; ) { register uint32_t bits; int inner, outer; /* * Find consecutive runs of 1 bits. Keep going until we run * out of them. */ for (bits = bs->noise[i]; bits; ) { inner = ffs (bits) - 1; bits = ~bits & ~((1 << inner) - 1); outer = ffs (bits) - 1; bits = ~bits & ~((1 << outer) - 1); glPushMatrix (); glRotatef (i * 360.0 / (GLfloat) g_blades, 0, 0, 1); draw_blink_blade (ctx, inner, outer, True); glPopMatrix (); polys += SUBDIV + SUBDIV; } } --bs->dwellcnt; return polys; } static void random_blink (lockward_context *ctx, struct blinkstate *bs) { bs->color[0] = bs->color[1] = bs->color[2] = bs->color[3] = 1.0; bs->dwellcnt = -1; bs->radius = -1; bs->dwell = calc_interval_frames (ctx, g_blinkdwell_min, g_blinkdwell_max); if (random() & 2) bs->dwell = -bs->dwell; bs->type = random() % MAX_BTYPE; switch (bs->type) { case BTYPE_RADIAL_SINGLE: case BTYPE_SEGMENT_SINGLE: bs->drawfunc = draw_blink_radial_random; bs->val = 0; bs->counter = 1; break; case BTYPE_RADIAL_RANDOM: case BTYPE_SEGMENT_RANDOM: bs->drawfunc = draw_blink_radial_random; bs->val = 0; bs->counter = g_blades; break; case BTYPE_RADIAL_SEQ: bs->drawfunc = draw_blink_radial_sequential; bs->val = random() % g_blades; /* Initial offset */ bs->direction = random() & 8 ? 1 : -1; bs->counter = g_blades; break; case BTYPE_RADIAL_DOUBLESEQ: bs->drawfunc = draw_blink_radial_doubleseq; bs->val = random() % g_blades; /* Initial offset */ bs->counter = g_blades / 2 + 1; break; case BTYPE_CONCENTRIC_SINGLE: bs->drawfunc = draw_blink_concentric_random; bs->val = 0; bs->counter = 1; break; case BTYPE_CONCENTRIC_RANDOM: bs->drawfunc = draw_blink_concentric_random; bs->val = 0; bs->counter = NRADII - 1; break; case BTYPE_CONCENTRIC_SEQ: bs->drawfunc = draw_blink_concentric_sequential; bs->direction = random() & 8 ? 1 : -1; bs->counter = NRADII - 1; break; case BTYPE_SEGMENT_SCATTER: bs->drawfunc = draw_blink_segment_scatter; bs->counter = random() % (g_blades / 2) + (g_blades / 2) + 1; break; } } /*************************************************************************** * Main rendering routine. */ ENTRYPOINT void draw_lockward (ModeInfo *mi) { lockward_context *ctx = &g_ctx[MI_SCREEN (mi)]; spinnerstate *ss; Display *dpy = MI_DISPLAY(mi); Window window = MI_WINDOW(mi); int i, n; GLfloat scolor[4] = {0.0, 0.0, 0.0, 0.5}; if (!ctx->glx_context) return; glXMakeCurrent (MI_DISPLAY (mi), MI_WINDOW (mi), *ctx->glx_context); glClear (GL_COLOR_BUFFER_BIT); if (ctx->blendmode) glBlendFunc (GL_ONE, GL_ONE); else glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glPushMatrix (); glLoadIdentity (); mi->polygon_count = 0; for (n = NSPINNERS; --n >= 0; ) { ss = &ctx->spinners[n]; /* Set color. */ i = ss->ccolor >> COLORIDX_SHF; scolor[0] = ss->colors[i].red / 65535.0; scolor[1] = ss->colors[i].green / 65535.0; scolor[2] = ss->colors[i].blue / 65535.0; glColor4fv (scolor); glPushMatrix (); glRotatef (ss->rot - ss->rotcount * ss->rotinc, 0, 0, 1); for (i = ss->nblades; --i >= 0; ) { glPushMatrix (); glRotatef (360.0 * i / ss->nblades, 0, 0, 1); glBegin (GL_TRIANGLE_FAN); /* glCallList (ctx->blades_outer + ss->bladeidx[i].outer); */ /* glCallList (ctx->blades_inner + ss->bladeidx[i].inner); */ draw_blink_blade (ctx, ss->bladeidx[i].inner, ss->bladeidx[i].outer, False); glEnd (); glPopMatrix (); mi->polygon_count += SUBDIV + SUBDIV; } glPopMatrix (); /* Advance rotation. */ if (ss->rotcount) { if (ss->rotcount > 0) --ss->rotcount; } else { if (ss->rotinc == 0.0) random_blade_rot (ctx, ss); else { /* Compute # of ticks to sit idle. */ ss->rotinc = 0.0; ss->rotcount = calc_interval_frames (ctx, g_rotateidle_min, g_rotateidle_max); } } /* Advance colors. */ if ((ss->ccolor += ss->colorinc) >= ss->ncolors) ss->ccolor -= ss->ncolors; else if (ss->ccolor < 0) ss->ccolor += ss->ncolors; } if (g_blink_p) { if (ctx->blink.drawfunc) { mi->polygon_count += ctx->blink.drawfunc (ctx, &ctx->blink); } else { if (ctx->nextblink > 0) --ctx->nextblink; else { /* Compute # of frames for blink idle time. */ ctx->nextblink = calc_interval_frames (ctx, g_blinkidle_min, g_blinkidle_max); random_blink (ctx, &ctx->blink); } } } glPopMatrix (); if (MI_IS_FPS (mi)) do_fps (mi); glFinish(); glXSwapBuffers (dpy, window); } /*************************************************************************** * Initialization/teardown. */ ENTRYPOINT void init_lockward (ModeInfo *mi) { lockward_context *ctx; int i, n; MI_INIT (mi, g_ctx); ctx = &g_ctx[MI_SCREEN (mi)]; ctx->glx_context = init_GL (mi); reshape_lockward (mi, MI_WIDTH (mi), MI_HEIGHT (mi)); glEnable (GL_CULL_FACE); glEnable (GL_BLEND); glDisable (GL_DEPTH_TEST); glShadeModel (GL_FLAT); glFrontFace (GL_CW); /* ctx->blades_outer = glGenLists (NRADII); */ /* ctx->blades_inner = glGenLists (NRADII); */ ctx->rings = glGenLists (NRADII - 1); ctx->blendmode = 0; /* WTF? ctx->fps = 1000000 / MI_DELAY (mi); */ ctx->fps = 60; ctx->nextblink = calc_interval_frames (ctx, g_blinkidle_min, g_blinkidle_max); ctx->blink.drawfunc = NULL; ctx->blink.noise = malloc (sizeof (uint32_t) * g_blades); if (!ctx->blink.noise) { fprintf (stderr, "Can't allocate noise array.\n"); exit (1); } gen_blade_arcs (ctx); gen_rings (ctx); for (i = NSPINNERS; --i >= 0; ) { spinnerstate *ss = &ctx->spinners[i]; ss->rot = 0.0; ss->rotcount = -1; /* Establish rotation */ random_blade_rot (ctx, ss); /* * Establish color cycling path and rate. Rate avoids zero. */ ss->ncolors = 128; ss->colorinc = (random() & ((2 << COLORIDX_SHF) - 1)) - (1 << COLORIDX_SHF); if (ss->colorinc >= 0) ++ss->colorinc; ss->colors = (XColor *) calloc (ss->ncolors, sizeof (XColor)); if (!ss->colors) { fprintf (stderr, "Can't allocate XColors for spinner %d.\n", i); exit (1); } make_smooth_colormap (0, 0, 0, ss->colors, &ss->ncolors, False, 0, False); ss->ncolors <<= COLORIDX_SHF; /* * Create blades. */ ss->nblades = g_blades; ss->bladeidx = malloc (sizeof (bladestate) * g_blades); if (!ss->bladeidx) { fprintf (stderr, "Can't allocate blades.\n"); exit (1); } for (n = g_blades; --n >= 0; ) { /* * Establish blade radii. Can't be equal. Ensure * outer > inner. */ do { ss->bladeidx[n].outer = random() & 7; ss->bladeidx[n].inner = random() & 7; } while (ss->bladeidx[n].outer == ss->bladeidx[n].inner); if (ss->bladeidx[n].outer < ss->bladeidx[n].inner) { uint8_t tmp; tmp = ss->bladeidx[n].outer; ss->bladeidx[n].outer = ss->bladeidx[n].inner; ss->bladeidx[n].inner = tmp; } } } } ENTRYPOINT void free_lockward (ModeInfo *mi) { lockward_context *ctx = &g_ctx[MI_SCREEN (mi)]; int i; if (!ctx->glx_context) return; glXMakeCurrent (MI_DISPLAY (mi), MI_WINDOW (mi), *ctx->glx_context); if (ctx->blink.noise) free (ctx->blink.noise); if (glIsList (ctx->rings)) glDeleteLists (ctx->rings, NRADII - 1); /* if (glIsList (ctx->blades_outer)) glDeleteLists (ctx->blades_outer, NRADII); if (glIsList (ctx->blades_inner)) glDeleteLists (ctx->blades_inner, NRADII); */ for (i = NSPINNERS; --i >= 0; ) { spinnerstate *ss = &ctx->spinners[i]; if (ss->colors) free (ss->colors); if (ss->bladeidx) free (ss->bladeidx); } } XSCREENSAVER_MODULE ("Lockward", lockward) #endif /* USE_GL */ /* vim:se ts=8 sts=8 sw=8: */