summaryrefslogtreecommitdiffstats
path: root/hacks/glx/splitflap.c
diff options
context:
space:
mode:
Diffstat (limited to 'hacks/glx/splitflap.c')
-rw-r--r--hacks/glx/splitflap.c1426
1 files changed, 0 insertions, 1426 deletions
diff --git a/hacks/glx/splitflap.c b/hacks/glx/splitflap.c
deleted file mode 100644
index 0706cc8..0000000
--- a/hacks/glx/splitflap.c
+++ /dev/null
@@ -1,1426 +0,0 @@
-/* splitflap, Copyright (c) 2015-2021 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.
- *
- * Draws a split-flap text display.
- */
-
-#define FLAP_FONT "sans-serif bold 144"
-
-#define DEFAULTS "*delay: 20000 \n" \
- "*showFPS: False \n" \
- "*wireframe: False \n" \
- "*flapFont: " FLAP_FONT "\n" \
- "*frameColor: #444444" "\n" \
- "*caseColor: #666666" "\n" \
- "*discColor: #888888" "\n" \
- "*finColor: #222222" "\n" \
- "*textColor: #FFFF00" "\n" \
- "*multiSample: True \n" \
- "*program: xscreensaver-text\n" \
- "*usePty: False\n"
-
-# define release_splitflap 0
-
-#define DEF_SPEED "1.0"
-#define DEF_WIDTH "22"
-#define DEF_HEIGHT "8"
-#define DEF_SPIN "XYZ"
-#define DEF_WANDER "True"
-#define DEF_FACE_FRONT "True"
-#define DEF_MODE "Text"
-
-#include "xlockmore.h"
-
-#include <ctype.h>
-
-#ifdef USE_GL /* whole file */
-
-#include "gltrackball.h"
-#include "rotator.h"
-#include "ximage-loader.h"
-#include "utf8wc.h"
-#include "textclient.h"
-#include "texfont.h"
-#include "gllist.h"
-
-extern const struct gllist
- *splitflap_obj_box_quarter_frame, *splitflap_obj_disc_quarter,
- *splitflap_obj_fin_edge_half, *splitflap_obj_fin_face_half;
-static struct gllist *splitflap_obj_outer_frame = 0;
-
-static const struct gllist * const *all_objs[] = {
- &splitflap_obj_box_quarter_frame, &splitflap_obj_disc_quarter,
- &splitflap_obj_fin_edge_half, &splitflap_obj_fin_face_half,
- (const struct gllist * const *) &splitflap_obj_outer_frame
-};
-
-#define SPLITFLAP_QUARTER_FRAME 0
-#define SPLITFLAP_DISC_QUARTER 1
-#define SPLITFLAP_FIN_EDGE_HALF 2
-#define SPLITFLAP_FIN_FACE_HALF 3
-#define SPLITFLAP_OUTER_FRAME 4
-
-#define COLON_WIDTH 0.5
-
-typedef struct {
- int target_index; /* desired character */
- double current_index; /* currently displayed, fractional */
- GLfloat sticky; /* bottom fin doesn't fall all the way */
- int missing; /* which fin has snapped off, or -1 */
- const char * const *spool; /* chars available for display */
- int spool_size; /* how many fins on the spool */
-} flapper;
-
-typedef struct {
- const char *text;
- GLuint texid;
- XCharStruct metrics;
- int tex_width, tex_height;
-} texinfo;
-
-typedef struct {
- GLXContext *glx_context;
- rotator *rot, *rot2;
- trackball_state *trackball;
- Bool button_down_p;
- Bool spinx, spiny, spinz;
-
- texinfo *texinfo;
- int texinfo_size;
-
- GLuint *dlists;
- GLfloat component_colors[countof(all_objs)][4];
- GLfloat text_color[4];
-
- flapper *flappers; /* grid_width * grid_height */
-
- texture_font_data *font_data;
- int ascent, descent;
-
- text_data *tc;
- unsigned char text[5];
- int linger;
- int clock_p;
- Bool first_time_p;
-
-} splitflap_configuration;
-
-static const char * const digit_s1_spool[] = { " ", "1" };
-static const char * const digit_01_spool[] = { "0", "1" };
-static const char * const ap_spool[] = { "A", "P" };
-static const char * const m_spool[] = { "M" };
-static const char * const digit_05_spool[] = { "0", "1", "2", "3", "4", "5" };
-static const char * const digit_spool[] = {
- "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"
-};
-
-static const char * const ascii_spool[] = {
- " ", "!", "\"", "#", "$", "%", "&", "'",
- "(", ")", "*", "+", ",", "-", ".", "/",
- "0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
- ":", ";", "<", "=", ">", "?", "@",
- "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M",
- "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z",
- "[", "\\", "]", "^", "_", "`", "{", "|", "}", "~",
-};
-
-
-/* If we include these, the flappers just take too long. It's boring. */
-static const char * const latin1_spool[] = {
- " ", "!", "\"", "#", "$", "%", "&", "'",
- "(", ")", "*", "+", ",", "-", ".", "/",
- "0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
- ":", ";", "<", "=", ">", "?", "@",
- "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M",
- "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z",
- "[", "\\", "]", "^", "_", "`", "{", "|", "}", "~",
-
- "\302\241", "\302\242", "\302\243", "\302\245",
- "\302\247", "\302\251", "\302\265", "\302\266",
-
- "\303\200", "\303\201", "\303\202", "\303\203",
- "\303\204", "\303\205", "\303\206", "\303\207",
- "\303\210", "\303\211", "\303\212", "\303\213",
- "\303\214", "\303\215", "\303\216", "\303\217",
- "\303\220", "\303\221", "\303\222", "\303\223",
- "\303\224", "\303\225", "\303\226", "\303\230",
- "\303\231", "\303\232", "\303\233", "\303\234",
- "\303\235", "\303\236", "\303\237", "\303\267",
-};
-
-
-static splitflap_configuration *bps = NULL;
-
-static GLfloat speed;
-static int grid_width, grid_height;
-static char *do_spin;
-static Bool do_wander;
-static Bool face_front_p;
-static char *mode_str;
-
-static XrmOptionDescRec opts[] = {
- { "-speed", ".speed", XrmoptionSepArg, 0 },
- { "-width", ".width", XrmoptionSepArg, 0 },
- { "-height", ".height", XrmoptionSepArg, 0 },
- { "-spin", ".spin", XrmoptionSepArg, 0 },
- { "+spin", ".spin", XrmoptionNoArg, "" },
- { "-wander", ".wander", XrmoptionNoArg, "True" },
- { "+wander", ".wander", XrmoptionNoArg, "False" },
- { "-front", ".faceFront", XrmoptionNoArg, "True" },
- { "+front", ".faceFront", XrmoptionNoArg, "False" },
- { "-mode", ".mode", XrmoptionSepArg, 0 },
-};
-
-static argtype vars[] = {
- {&speed, "speed", "Speed", DEF_SPEED, t_Float},
- {&grid_width, "width", "Width", DEF_WIDTH, t_Int},
- {&grid_height, "height", "Height", DEF_HEIGHT, t_Int},
- {&do_spin, "spin", "Spin", DEF_SPIN, t_String},
- {&do_wander, "wander", "Wander", DEF_WANDER, t_Bool},
- {&face_front_p, "faceFront", "FaceFront", DEF_FACE_FRONT, t_Bool},
- {&mode_str, "mode", "Mode", DEF_MODE, t_String},
-};
-
-ENTRYPOINT ModeSpecOpt splitflap_opts = {
- countof(opts), opts, countof(vars), vars, NULL};
-
-
-/* Window management, etc
- */
-ENTRYPOINT void
-reshape_splitflap (ModeInfo *mi, int width, int height)
-{
- GLfloat h = (GLfloat) height / (GLfloat) width;
-
- glViewport (0, 0, (GLint) width, (GLint) height);
-
- glMatrixMode(GL_PROJECTION);
- glLoadIdentity();
- gluPerspective (40.0, 1/h, 0.5, 25);
-
- glMatrixMode(GL_MODELVIEW);
- glLoadIdentity();
- gluLookAt( 0, 0, 3, /* 10x lower than traditional, for better depth rez */
- 0, 0, 0,
- 0, 1, 0);
-
-# ifdef HAVE_MOBILE /* Keep it the same relative size when rotated. */
- {
- int o = (int) current_device_rotation();
- if (o != 0 && o != 180 && o != -180)
- glScalef (h, h, h);
- }
-# endif
-
- glClear(GL_COLOR_BUFFER_BIT);
-}
-
-
-ENTRYPOINT Bool
-splitflap_handle_event (ModeInfo *mi, XEvent *event)
-{
- splitflap_configuration *bp = &bps[MI_SCREEN(mi)];
-
- if (gltrackball_event_handler (event, bp->trackball,
- MI_WIDTH (mi), MI_HEIGHT (mi),
- &bp->button_down_p))
- return True;
-
- return False;
-}
-
-
-static void
-init_textures (ModeInfo *mi)
-{
- splitflap_configuration *bp = &bps[MI_SCREEN(mi)];
- int i;
- const char * const *spool = latin1_spool;
- int max = countof(latin1_spool);
-
- bp->texinfo = (texinfo *) calloc (max+1, sizeof(*bp->texinfo));
- texture_string_metrics (bp->font_data, "", 0, &bp->ascent, &bp->descent);
-
- for (i = 0; i < max; i++)
- {
- texinfo *ti = &bp->texinfo[i];
- glGenTextures (1, &ti->texid);
- glBindTexture (GL_TEXTURE_2D, ti->texid);
-
- ti->text = spool[i];
-
- /* fprintf(stderr, "%d \\%03o\\%03o %s\n", i,
- (unsigned char) ti->text[0],
- (unsigned char) ti->text[1],
- ti->text); */
-
- string_to_texture (bp->font_data, ti->text, &ti->metrics,
- &ti->tex_width, &ti->tex_height);
- }
- bp->texinfo_size = i;
-
- glBindTexture (GL_TEXTURE_2D, 0);
-}
-
-
-static void
-parse_color (ModeInfo *mi, char *key, GLfloat color[4])
-{
- XColor xcolor;
- char *string = get_string_resource (mi->dpy, key, "Color");
- if (!XParseColor (mi->dpy, mi->xgwa.colormap, string, &xcolor))
- {
- fprintf (stderr, "%s: unparsable color in %s: %s\n", progname,
- key, string);
- exit (1);
- }
- free (string);
-
- color[0] = xcolor.red / 65536.0;
- color[1] = xcolor.green / 65536.0;
- color[2] = xcolor.blue / 65536.0;
- color[3] = 1;
-}
-
-
-static int draw_outer_frame (ModeInfo *mi);
-
-ENTRYPOINT void
-init_splitflap (ModeInfo *mi)
-{
- splitflap_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_splitflap (mi, MI_WIDTH(mi), MI_HEIGHT(mi));
-
- bp->first_time_p = True;
-
- if (!mode_str || !*mode_str || !strcasecmp(mode_str, "text"))
- {
- bp->clock_p = 0;
- }
- else if (!strcasecmp (mode_str, "clock") ||
- !strcasecmp (mode_str, "clock12"))
- {
- bp->clock_p = 12;
- grid_width = 8;
- grid_height = 1;
- }
- else if (!strcasecmp (mode_str, "clock24"))
- {
- bp->clock_p = 24;
- grid_width = 6;
- grid_height = 1;
- }
- else
- {
- fprintf (stderr,
- "%s: `mode' must be text, clock12 or clock24: not `%s'\n",
- progname, mode_str);
- exit (1);
- }
-
- if (! bp->clock_p)
- {
- bp->tc = textclient_open (MI_DISPLAY (mi));
- bp->text[0] = 0;
-
- if (grid_width > 10)
- textclient_reshape (bp->tc,
- grid_width, grid_height,
- grid_width, grid_height,
- 0);
- }
-
- if (bp->clock_p)
- speed /= 4;
-
- {
- double spin_speed = 0.5;
- double wander_speed = 0.005;
- double tilt_speed = 0.001;
- double spin_accel = 0.5;
-
- char *s = do_spin;
- while (*s)
- {
- if (*s == 'x' || *s == 'X') bp->spinx = True;
- else if (*s == 'y' || *s == 'Y') bp->spiny = True;
- else if (*s == 'z' || *s == 'Z') bp->spinz = True;
- else if (*s == '0') ;
- else
- {
- fprintf (stderr,
- "%s: spin must contain only the characters X, Y, or Z (not \"%s\")\n",
- progname, do_spin);
- exit (1);
- }
- s++;
- }
-
- bp->rot = make_rotator (bp->spinx ? spin_speed : 0,
- bp->spiny ? spin_speed : 0,
- bp->spinz ? spin_speed : 0,
- spin_accel,
- do_wander ? wander_speed : 0,
- False);
- bp->rot2 = (face_front_p
- ? make_rotator (0, 0, 0, 0, tilt_speed, True)
- : 0);
- bp->trackball = gltrackball_init (False);
- }
-
- bp->dlists = (GLuint *) calloc (countof(all_objs)+1, sizeof(GLuint));
- for (i = 0; i < countof(all_objs); i++)
- bp->dlists[i] = glGenLists (1);
-
- parse_color (mi, "textColor", bp->text_color);
- for (i = 0; i < countof(all_objs); i++)
- {
- const struct gllist *gll = *all_objs[i];
- char *key = 0;
- GLfloat spec[4] = {0.4, 0.4, 0.4, 1.0};
- GLfloat shiny = 80; /* 0-128 */
-
- glNewList (bp->dlists[i], GL_COMPILE);
-
- glMatrixMode(GL_MODELVIEW);
- glPushMatrix();
- glMatrixMode(GL_TEXTURE);
- glPushMatrix();
- glMatrixMode(GL_MODELVIEW);
-
- glRotatef (-90, 1, 0, 0);
-
- glBindTexture (GL_TEXTURE_2D, 0);
-
- switch (i) {
- case SPLITFLAP_QUARTER_FRAME:
- key = "frameColor";
- break;
- case SPLITFLAP_OUTER_FRAME:
- key = "caseColor";
- break;
- case SPLITFLAP_DISC_QUARTER:
- key = (wire ? "frameColor" : "discColor");
- break;
- case SPLITFLAP_FIN_EDGE_HALF:
- case SPLITFLAP_FIN_FACE_HALF:
- key = "finColor";
- break;
- default:
- abort();
- }
-
- parse_color (mi, key, bp->component_colors[i]);
-
- if (wire && i == SPLITFLAP_FIN_EDGE_HALF)
- bp->component_colors[i][0] =
- bp->component_colors[i][1] =
- bp->component_colors[i][2] = 0.7;
-
- glMaterialfv (GL_FRONT_AND_BACK, GL_SPECULAR, spec);
- glMaterialf (GL_FRONT_AND_BACK, GL_SHININESS, shiny);
-
- switch (i) {
- case SPLITFLAP_OUTER_FRAME:
- if (! splitflap_obj_outer_frame)
- splitflap_obj_outer_frame =
- (struct gllist *) calloc (1, sizeof(*splitflap_obj_outer_frame));
- splitflap_obj_outer_frame->points = draw_outer_frame(mi);
- break;
- default:
- renderList (gll, wire);
- break;
- }
-
- glMatrixMode(GL_TEXTURE);
- glPopMatrix();
- glMatrixMode(GL_MODELVIEW);
- glPopMatrix();
-
- glEndList ();
- }
-
- if (grid_width < 1) grid_width = 1;
- if (grid_height < 1) grid_height = 1;
- bp->flappers = (flapper *) calloc (grid_width * grid_height,
- sizeof (flapper));
-
- for (i = 0; i < grid_width * grid_height; i++)
- {
- flapper *f = &bp->flappers[i];
-
- if (!bp->clock_p)
- {
- f->spool = ascii_spool;
- f->spool_size = countof (ascii_spool);
- }
- else
- {
- switch (i) {
- case 0:
- if (bp->clock_p == 12)
- {
- f->spool = digit_s1_spool;
- f->spool_size = countof (digit_s1_spool);
- }
- else
- {
- f->spool = digit_01_spool;
- f->spool_size = countof (digit_01_spool);
- }
- break;
- case 1: case 3: case 5:
- f->spool = digit_spool;
- f->spool_size = countof (digit_spool);
- break;
- case 2: case 4:
- f->spool = digit_05_spool;
- f->spool_size = countof (digit_05_spool);
- break;
- case 6:
- f->spool = ap_spool;
- f->spool_size = countof (ap_spool);
- break;
- case 7:
- f->spool = m_spool;
- f->spool_size = countof (m_spool);
- break;
- default:
- abort();
- }
- }
-
- f->target_index = random() % f->spool_size;
- /* f->target_index = 0; */
- f->current_index = f->target_index;
- f->missing = (((random() % 10) == 0)
- ? (random() % f->spool_size)
- : -1);
- }
-
- bp->font_data = load_texture_font (mi->dpy, "flapFont");
- init_textures (mi);
-
- reshape_splitflap (mi, MI_WIDTH(mi), MI_HEIGHT(mi));
-}
-
-
-static int
-draw_component (ModeInfo *mi, int i)
-{
- splitflap_configuration *bp = &bps[MI_SCREEN(mi)];
- glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE,
- bp->component_colors[i]);
- glCallList (bp->dlists[i]);
- return (*all_objs[i])->points / 3;
-}
-
-
-static int
-draw_frame_quarter (ModeInfo *mi, flapper *f)
-{
- int count = 0;
- glPushMatrix();
- count += draw_component (mi, SPLITFLAP_QUARTER_FRAME);
- glPopMatrix();
- return count;
-}
-
-static int
-draw_disc_quarter (ModeInfo *mi, flapper *f)
-{
- int count = 0;
- glPushMatrix();
- count += draw_component (mi, SPLITFLAP_DISC_QUARTER);
- glPopMatrix();
- return count;
-}
-
-static int
-draw_fin_edge_half (ModeInfo *mi, flapper *f)
-{
- int count = 0;
- glPushMatrix();
- count += draw_component (mi, SPLITFLAP_FIN_EDGE_HALF);
- glPopMatrix();
- return count;
-}
-
-static int
-draw_fin_face_half (ModeInfo *mi, flapper *f)
-{
- int count = 0;
- if (MI_IS_WIREFRAME(mi)) return 0;
- glPushMatrix();
- count += draw_component (mi, SPLITFLAP_FIN_FACE_HALF);
- glPopMatrix();
- return count;
-}
-
-
-static int
-draw_frame (ModeInfo *mi, flapper *f)
-{
- int count = 0;
-
- glPushMatrix();
-
- glFrontFace (GL_CCW);
- count += draw_frame_quarter (mi, f);
- count += draw_disc_quarter (mi, f);
-
- glScalef (-1, 1, 1);
- glFrontFace (GL_CW);
- count += draw_frame_quarter (mi, f);
- count += draw_disc_quarter (mi, f);
-
- glScalef ( 1, -1, 1);
- glFrontFace (GL_CCW);
- count += draw_frame_quarter (mi, f);
- count += draw_disc_quarter (mi, f);
-
- glScalef (-1, 1, 1);
- glFrontFace (GL_CW);
- count += draw_frame_quarter (mi, f);
- count += draw_disc_quarter (mi, f);
-
- glPopMatrix();
- return count;
-}
-
-
-static void
-draw_fin_text_quad (ModeInfo *mi, flapper *f, int index, Bool top_p)
-{
- int wire = MI_IS_WIREFRAME(mi);
- splitflap_configuration *bp = &bps[MI_SCREEN(mi)];
-
- /* 15 / is weird
- 27 ; descends too far
- 32 @ is too wide
- 59 [ descends too far
- 79 A^ is taller than the font
- 89 I` is weird
- */
-
- GLfloat z = 0.035; /* Lifted off the surface by this distance */
- GLfloat bot = 0.013; /* Distance away from the mid gutter */
- GLfloat scale = 1.8; /* Scale to fill the panel */
-
- int lh = bp->ascent + bp->descent;
- texinfo *ti;
- GLfloat qx0, qy0, qx1, qy1;
- GLfloat tx0, ty0, tx1, ty1;
- XCharStruct overall;
- int tex_width, tex_height;
- int i;
-
- if (bp->texinfo_size <= 0) abort();
- for (i = 0; i < bp->texinfo_size; i++)
- {
- ti = &bp->texinfo[i];
- if (!strcmp (f->spool[index], ti->text))
- break;
- }
- if (i >= bp->texinfo_size) abort();
-
- overall = ti->metrics;
- tex_width = ti->tex_width;
- tex_height = ti->tex_height;
-
- if (bp->ascent < overall.ascent)
- /* WTF! &Aacute; has a higher ascent than the font itself!
- Scale it down so that it doesn't overlap the fin. */
- scale *= bp->ascent / (GLfloat) overall.ascent * 0.98;
-
- glPushMatrix();
-
- glNormal3f (0, 0, 1);
- glFrontFace (top_p ? GL_CCW : GL_CW);
-
- if (! wire)
- {
- glBindTexture (GL_TEXTURE_2D, ti->texid);
- enable_texture_string_parameters (bp->font_data);
- }
-
- glTranslatef (0, 0, z); /* Move to just above the surface */
- glScalef (1.0 / lh, 1.0 / lh, 1); /* Scale to font pixel coordinates */
- glScalef (scale, scale, 1); /* Fill the panel with the font */
-
- if (!top_p)
- {
- glRotatef (180, 0, 0, 1);
- }
-
- /* Position the XCharStruct origin at 0,0 in the scene. */
- qx0 = -overall.lbearing;
- qy0 = -overall.descent;
- qx1 = overall.rbearing;
- qy1 = overall.ascent;
-
- /* Center horizontally. */
- qx0 -= (overall.rbearing - overall.lbearing) / 2.0;
- qx1 -= (overall.rbearing - overall.lbearing) / 2.0;
-
-
- /* Move origin to below font descenders. */
- qy0 += bp->descent;
- qy1 += bp->descent;
-
- /* Center vertically. */
- qy0 -= (bp->ascent + bp->descent) / 2.0;
- qy1 -= (bp->ascent + bp->descent) / 2.0;
-
- /* Move the descenders down a bit, if there's room.
- This means that weirdos like [ and $ might not be on the baseline.
- #### This looks good with X11 fonts but bad with MacOS fonts. WTF?
- */
-#ifndef HAVE_COCOA
- {
- GLfloat off = bp->descent / 3.0;
- GLfloat max = bp->descent - off;
- if (overall.descent > max)
- off = max - overall.descent;
- if (off < 0)
- off = 0;
- qy0 -= off;
- qy1 -= off;
- }
-# endif /* !HAVE_COCOA */
-
- /* Attach the texture to the quad. */
- tx0 = 0;
- ty1 = 0;
- tx1 = (overall.rbearing - overall.lbearing) / (GLfloat) tex_width;
- ty0 = (overall.ascent + overall.descent) / (GLfloat) tex_height;
-
- /* Convert from font ascent/descent to character ascent/descent. */
-
- /* Flip texture horizontally on bottom panel. */
- if (!top_p)
- {
- GLfloat s = tx0;
- tx0 = tx1;
- tx1 = s;
- }
-
-
- /* Cut the character in half, truncating just above the split line. */
- {
- GLfloat oqy0 = qy0;
- GLfloat oqy1 = qy1;
- GLfloat r0, r1;
-
- bot *= lh * scale;
-
- if (top_p)
- {
- if (qy0 < bot)
- qy0 = bot;
- }
- else
- {
- if (qy1 > -bot)
- qy1 = -bot;
- }
-
- r0 = (qy0 - oqy0) / (oqy1 - oqy0);
- r1 = (qy1 - oqy1) / (oqy1 - oqy0);
- ty0 -= r0 * (ty0 - ty1);
- ty1 -= r1 * (ty0 - ty1);
- }
-
- glColor4fv (bp->text_color);
- glBegin (wire ? GL_LINE_LOOP : GL_QUADS);
- glTexCoord2f (tx0, ty0); glVertex3f (qx0, qy0, 0);
- glTexCoord2f (tx1, ty0); glVertex3f (qx1, qy0, 0);
- glTexCoord2f (tx1, ty1); glVertex3f (qx1, qy1, 0);
- glTexCoord2f (tx0, ty1); glVertex3f (qx0, qy1, 0);
- glEnd();
-
- glPopMatrix();
-
- if (! wire)
- {
- glDisable (GL_BLEND);
- glEnable (GL_LIGHTING);
- glDisable (GL_TEXTURE_2D);
- }
-}
-
-
-static int
-draw_fin (ModeInfo *mi, flapper *f, int front_index, int back_index,
- Bool text_p)
-{
- int count = 0;
-
- glPushMatrix();
-
- glFrontFace (GL_CCW);
-
- if (! text_p)
- count += draw_fin_edge_half (mi, f);
-
- if (front_index >= 0)
- {
- if (text_p)
- {
- draw_fin_text_quad (mi, f, front_index, True);
- count++;
- }
- else
- count += draw_fin_face_half (mi, f);
- }
-
- glScalef (-1, 1, 1);
- if (! text_p)
- {
- glFrontFace (GL_CW);
- count += draw_fin_edge_half (mi, f);
- if (front_index >= 0)
- count += draw_fin_face_half (mi, f);
- }
-
- if (back_index >= 0)
- {
- glRotatef (180, 0, 1, 0);
- if (text_p)
- {
- draw_fin_text_quad (mi, f, back_index, False);
- count++;
- }
- else
- {
- count += draw_fin_face_half (mi, f);
- glScalef (-1, 1, 1);
- glFrontFace (GL_CCW);
- count += draw_fin_face_half (mi, f);
- }
- }
-
- glPopMatrix();
- return count;
-}
-
-
-/* The case holding the grid of flappers.
- */
-static int
-draw_outer_frame (ModeInfo *mi)
-{
- splitflap_configuration *bp = &bps[MI_SCREEN(mi)];
- int count = 0;
- GLfloat w = grid_width;
- GLfloat h = grid_height;
- GLfloat d = 1;
-
- if (bp->clock_p == 12)
- w += COLON_WIDTH * 3;
- else if (bp->clock_p == 24)
- w += COLON_WIDTH * 2;
-
- w += 0.2;
- h += 0.2;
-
- if (bp->clock_p) w += 0.25;
- if (w > 3) w += 0.5;
- if (h > 3) h += 0.5;
-
- if (MI_IS_WIREFRAME(mi))
- return 0;
-
- glFrontFace (GL_CCW);
- glPushMatrix();
- glTranslatef (0, 1.03, 0);
-
- glBegin (GL_QUADS);
-
- glNormal3f ( 0, 1, 0); /* back */
- glVertex3f (-w, d, h);
- glVertex3f ( w, d, h);
- glVertex3f ( w, d, -h);
- glVertex3f (-w, d, -h);
- count++;
-
- glNormal3f ( 0, -1, 0); /* front */
- glVertex3f (-w, -d, -h);
- glVertex3f ( w, -d, -h);
- glVertex3f ( w, -d, h);
- glVertex3f (-w, -d, h);
- count++;
-
- glNormal3f ( 0, 0, 1); /* top */
- glVertex3f (-w, -d, h);
- glVertex3f ( w, -d, h);
- glVertex3f ( w, d, h);
- glVertex3f (-w, d, h);
- count++;
-
- glNormal3f ( 0, 0, -1); /* bottom */
- glVertex3f (-w, d, -h);
- glVertex3f ( w, d, -h);
- glVertex3f ( w, -d, -h);
- glVertex3f (-w, -d, -h);
- count++;
-
- glNormal3f ( 1, 0, 0); /* left */
- glVertex3f ( w, -d, h);
- glVertex3f ( w, -d, -h);
- glVertex3f ( w, d, -h);
- glVertex3f ( w, d, h);
- count++;
-
- glNormal3f (-1, 0, 0); /* right */
- glVertex3f (-w, -d, -h);
- glVertex3f (-w, -d, h);
- glVertex3f (-w, d, h);
- glVertex3f (-w, d, -h);
- count++;
-
- glEnd();
- glPopMatrix();
-
- return count;
-}
-
-
-static void
-tick_flapper (ModeInfo *mi, flapper *f)
-{
- splitflap_configuration *bp = &bps[MI_SCREEN(mi)];
- double prev = f->current_index;
- Bool wrapped_p = False;
-
- if (bp->button_down_p) return;
- if (f->current_index == f->target_index)
- return;
-
- f->current_index += speed * 0.35; /* turn the crank */
-
- while (f->current_index > f->spool_size)
- {
- f->current_index -= f->spool_size;
- wrapped_p = True;
- }
-
- if (f->current_index < 0) abort();
-
- if ((prev < f->target_index || wrapped_p) &&
- f->current_index > f->target_index) /* just overshot */
- f->current_index = f->target_index;
-}
-
-
-#define MOD(M,N) (((M)+(N)) % (N)) /* Works with negatives */
-
-static int
-draw_flapper (ModeInfo *mi, flapper *f, Bool text_p)
-{
- int prev_index = floor (f->current_index);
- int next_index = MOD (prev_index+1, f->spool_size);
- int count = 0;
- GLfloat epsilon = 0.02;
- GLfloat r = f->current_index - prev_index;
- Bool moving_p = (r > 0 && r < 1);
- GLfloat sticky = f->sticky;
-
- if (f->missing >= 0)
- sticky = 0;
-
- if (f->missing >= 0 &&
- MOD (prev_index, f->spool_size) == f->missing)
- {
- moving_p = False;
- sticky = 0;
- }
-
- if (!moving_p)
- next_index = prev_index;
-
- if (! text_p)
- count += draw_frame (mi, f);
-
- /* Top flap, flat: top half of target char */
- if (!moving_p || !text_p || r > epsilon)
- {
- int p2 = next_index;
-
- if (p2 == f->missing)
- p2 = MOD (p2+1, f->spool_size);
-
- count += draw_fin (mi, f, p2, -1, text_p);
- }
-
- /* Bottom flap, flat: bottom half of prev char */
- if (!moving_p || !text_p || r < 1 - epsilon)
- {
- int p2 = prev_index;
-
- if (!moving_p && sticky)
- p2 = MOD (p2-1, f->spool_size);
-
- if (f->missing >= 0 &&
- p2 == MOD (f->missing+1, f->spool_size))
- p2 = MOD (p2-1, f->spool_size);
-
- glPushMatrix();
- glRotatef (180, 1, 0, 0);
- count += draw_fin (mi, f, -1, p2, text_p);
- glPopMatrix();
- }
-
- /* Moving flap, front: top half of prev char */
- /* Moving flap, back: bottom half of target char */
- if (moving_p || sticky)
- {
- if (!moving_p)
- r = 1.0;
- if (sticky && r > 1 - sticky)
- r = 1 - sticky;
- glPushMatrix();
- glRotatef (r * 180, 1, 0, 0);
- count += draw_fin (mi, f, prev_index, next_index, text_p);
- glPopMatrix();
- }
-
- return count;
-}
-
-
-static int
-draw_colon (ModeInfo *mi)
-{
- splitflap_configuration *bp = &bps[MI_SCREEN(mi)];
- GLfloat s = 1.0 / (bp->ascent + bp->descent);
- GLfloat z = 0.01;
- int count = 0;
- XCharStruct m;
-
- texture_string_metrics (bp->font_data, ":", &m, 0, 0);
-
- s *= 2;
-
- glPushMatrix();
-
- glTranslatef (-(1 + COLON_WIDTH), 0, 0);
- glScalef (s, s, 1);
-
- glTranslatef (-m.lbearing - (m.rbearing - m.lbearing)/2,
- -(m.ascent + m.descent) / 2,
- 0);
-
- glEnable (GL_TEXTURE_2D);
-
- /* draw the text five times, to give it a border. */
- {
- const XPoint offsets[] = {{ -1, -1 },
- { -1, 1 },
- { 1, 1 },
- { 1, -1 },
- { 0, 0 }};
- int i;
- GLfloat n = 1.5;
-
- glColor3f (0, 0, 0);
- for (i = 0; i < countof(offsets); i++)
- {
- glPushMatrix();
- if (offsets[i].x == 0)
- {
- glColor4fv (bp->text_color);
- glTranslatef (0, 0, z * 2);
- }
- glTranslatef (n * offsets[i].x, n * offsets[i].y, 0);
- print_texture_string (bp->font_data, ":");
- count++;
- glPopMatrix();
- }
- }
-
- glPopMatrix();
-
- return count;
-}
-
-
-/* Reads and returns a single Unicode character from the text client.
- */
-static unsigned long
-read_unicode (ModeInfo *mi)
-{
- splitflap_configuration *bp = &bps[MI_SCREEN(mi)];
- const unsigned char *end = bp->text + sizeof(bp->text) - 1; /* 4 bytes */
- unsigned long uc = 0;
- long L;
- int i;
-
- if (bp->clock_p || !bp->tc) abort();
-
- /* Fill the buffer with available input.
- */
- i = strlen ((char *) bp->text);
- while (i < (end - bp->text))
- {
- int c = textclient_getc (bp->tc);
- if (c <= 0) break;
- bp->text[i++] = (char) c;
- bp->text[i] = 0;
- }
-
- /* Pop 1-4 bytes from the front of the buffer and extract a UTF8 character.
- */
- L = utf8_decode (bp->text, i, &uc);
- if (L)
- {
- int j = end - bp->text - L;
- memmove (bp->text, bp->text + L, j);
- bp->text[j] = 0;
- }
- else
- uc = 0;
-
- return uc;
-}
-
-
-/* Given a Unicode character, finds the corresponding index on the spool,
- if any. Returns 0 if not found.
- */
-static int
-find_index (ModeInfo *mi, flapper *f, long uc)
-{
- char string[5];
- int L = utf8_encode (uc, string, sizeof(string) - 1);
- int i;
- if (L <= 0) return 0;
- string[L] = 0;
- for (i = 0; i < f->spool_size; i++)
- {
- if (!strcmp (string, f->spool[i]))
- return i;
- }
- return 0;
-}
-
-
-/* Read input from the text client and populate the spool with it.
- */
-static void
-fill_targets (ModeInfo *mi)
-{
- splitflap_configuration *bp = &bps[MI_SCREEN(mi)];
- int x, y;
- Bool cls_p = False;
-
- if (bp->clock_p)
- {
- char buf[80];
- time_t now = time ((time_t *) 0);
- struct tm *tm = localtime (&now);
- const char *fmt = (bp->clock_p == 24
- ? "%H%M%S"
- : "%I%M%S%p");
- int i;
- strftime (buf, sizeof(buf)-1, fmt, tm);
- if (bp->clock_p == 12 && buf[0] == '0')
- buf[0] = ' ';
-
- for (i = 0; i < strlen(buf); i++)
- {
- flapper *f = &bp->flappers[i];
- f->target_index = find_index (mi, f, buf[i]);
- }
- for (; i < grid_width * grid_height; i++)
- {
- flapper *f = &bp->flappers[i];
- f->target_index = find_index (mi, f, ' ');
- }
- return;
- }
-
- for (y = 0; y < grid_height; y++)
- {
- Bool nl_p = False;
- for (x = 0; x < grid_width; x++)
- {
- int i = y * grid_width + x;
- flapper *f = &bp->flappers[i];
- unsigned long uc = ((nl_p || cls_p) ? ' ' : read_unicode (mi));
- if (uc == '\r' || uc == '\n')
- nl_p = True;
- else if (uc == 12) /* ^L */
- cls_p = True;
-
- /* Convert Unicode to the closest Latin1 equivalent. */
- if (uc > 127)
- {
- Bool ascii_p = (f->spool != latin1_spool);
- unsigned char s[5], *s2;
- int L = utf8_encode (uc, (char *) s, sizeof(s));
- s[L] = 0;
- s2 = (unsigned char *) utf8_to_latin1 ((char *) s, ascii_p);
-
- if (s2[0] < 128) /* ASCII */
- uc = s2[0];
- else /* Latin1 -> UTF8 -> Unicode */
- {
- s[0] = (s2[0] > 0xBF ? 0xC3 : 0xC2);
- s[1] = s2[0] & (s2[0] > 0xBF ? 0xBF : 0xFF);
- s[2] = 0;
- utf8_decode (s, 2, &uc);
- }
-
- free (s2);
- }
-
- /* Upcase ASCII. Upcasing Unicrud would be rocket surgery. */
- if (uc >= 'a' && uc <= 'z') uc += ('A'-'a');
-
- f->target_index = find_index (mi, f, uc);
-
- f->sticky = (((random() % 20) == 0)
- ? 0.05 + frand(0.1) + frand(0.1)
- : 0);
- }
- }
-
-# if 0
- for (y = 0; y < grid_height; y++)
- {
- fprintf (stderr, "# ");
- for (x = 0; x < grid_width; x++)
- {
- int i = y * grid_width + x;
- flapper *f = &bp->flappers[i];
- fprintf(stderr, "%s", bp->spool[f->target_index]);
- }
- fprintf (stderr, " #\n");
- }
- fprintf (stderr, "\n");
-# endif
-}
-
-
-static void
-draw_flappers (ModeInfo *mi, Bool text_p)
-{
- splitflap_configuration *bp = &bps[MI_SCREEN(mi)];
- int x, y;
- int running = 0;
-
- for (y = 0; y < grid_height; y++)
- for (x = 0; x < grid_width; x++)
- {
- int i = (grid_height - y - 1) * grid_width + x;
- flapper *f = &bp->flappers[i];
- GLfloat xx = x;
- GLfloat yy = y;
-
- if (bp->clock_p)
- {
- if (x >= 2) xx += COLON_WIDTH;
- if (x >= 4) xx += COLON_WIDTH;
- if (x >= 6) xx += COLON_WIDTH;
- }
-
- xx *= 2.01;
- yy *= 1.98;
-
- glPushMatrix();
- glTranslatef (xx, yy, 0);
- mi->polygon_count += draw_flapper (mi, f, text_p);
-
- if (text_p && bp->clock_p && (x == 2 || x == 4))
- mi->polygon_count += draw_colon (mi);
-
- glPopMatrix();
-
- if (text_p)
- {
- tick_flapper (mi, f);
- if (f->current_index != f->target_index)
- running++;
- }
- }
-
- if (text_p && !running)
- {
- if (bp->clock_p)
- fill_targets (mi);
- else if (bp->linger)
- {
- bp->linger--;
- if (!bp->linger)
- fill_targets (mi);
- }
- else
- {
- /* Base of 1 second, plus 1 second for every 25 characters.
- Also multiply by speed? */
- bp->linger = 30;
- if (!bp->first_time_p)
- bp->linger += (grid_width * grid_height * 1.2);
- bp->first_time_p = False;
- }
- }
-}
-
-
-ENTRYPOINT void
-draw_splitflap (ModeInfo *mi)
-{
- splitflap_configuration *bp = &bps[MI_SCREEN(mi)];
- Display *dpy = MI_DISPLAY(mi);
- Window window = MI_WINDOW(mi);
- int wire = MI_IS_WIREFRAME(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);
-
- glShadeModel(GL_SMOOTH);
-
- glEnable(GL_DEPTH_TEST);
- glEnable(GL_NORMALIZE);
- glEnable(GL_CULL_FACE);
-
- if (!wire)
- {
- GLfloat pos[4] = {0.4, 0.2, 0.4, 0.0};
-/* GLfloat amb[4] = {0.0, 0.0, 0.0, 1.0};*/
- GLfloat amb[4] = {0.2, 0.2, 0.2, 1.0};
- GLfloat dif[4] = {1.0, 1.0, 1.0, 1.0};
- GLfloat spc[4] = {1.0, 1.0, 1.0, 1.0};
-
- glEnable(GL_LIGHTING);
- glEnable(GL_LIGHT0);
- glEnable(GL_DEPTH_TEST);
- glEnable(GL_CULL_FACE);
-
- glLightfv(GL_LIGHT0, GL_POSITION, pos);
- glLightfv(GL_LIGHT0, GL_AMBIENT, amb);
- glLightfv(GL_LIGHT0, GL_DIFFUSE, dif);
- glLightfv(GL_LIGHT0, GL_SPECULAR, spc);
-
- glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- }
-
-
- glPushMatrix ();
- glRotatef(current_device_rotation(), 0, 0, 1);
-
- glScalef (0.1, 0.1, 0.1); /* because of gluLookAt */
-
- {
- double x, y, z;
- get_position (bp->rot, &x, &y, &z, !bp->button_down_p);
- glTranslatef((x - 0.5) * 8,
- (y - 0.5) * 8,
- (z - 0.5) * 8);
-
- gltrackball_rotate (bp->trackball);
-
- if (face_front_p)
- {
- double maxx = 120;
- double maxy = 60;
- double maxz = 45;
- get_position (bp->rot2, &x, &y, &z, !bp->button_down_p);
- if (bp->spinx) glRotatef (maxy/2 - x*maxy, 1, 0, 0);
- if (bp->spiny) glRotatef (maxx/2 - y*maxx, 0, 1, 0);
- if (bp->spinz) glRotatef (maxz/2 - z*maxz, 0, 0, 1);
- }
- else
- {
- get_rotation (bp->rot, &x, &y, &z, !bp->button_down_p);
- glRotatef (x * 360, 1, 0, 0);
- glRotatef (y * 360, 0, 1, 0);
- glRotatef (z * 360, 0, 0, 1);
- }
- }
-
- /* Fit the whole grid on the screen */
- {
- GLfloat r = MI_HEIGHT(mi) / (GLfloat) MI_WIDTH(mi);
- int cells = (grid_width > grid_height
- ? grid_width * r
- : grid_height);
- GLfloat s = 8;
-# ifdef HAVE_MOBILE
- s *= 2; /* #### What. Why is this necessary? */
-#endif
- s /= cells;
- glScalef (s, s, s);
- }
-
- mi->polygon_count = 0;
- mi->polygon_count += draw_component (mi, SPLITFLAP_OUTER_FRAME);
-
- {
- GLfloat xoff = (bp->clock_p == 12 ? COLON_WIDTH * 3 :
- bp->clock_p == 24 ? COLON_WIDTH * 2 :
- 0);
- glTranslatef (1 - (grid_width + xoff), 1 - grid_height, 0);
- }
-
- /* We must render all text after all polygons, or alpha blending
- doesn't work right. */
- draw_flappers (mi, False);
- draw_flappers (mi, True);
-
- glPopMatrix ();
-
- if (mi->fps_p) do_fps (mi);
- glFinish();
-
- glXSwapBuffers(dpy, window);
-}
-
-ENTRYPOINT void
-free_splitflap (ModeInfo *mi)
-{
- splitflap_configuration *bp = &bps[MI_SCREEN(mi)];
- int i;
-
- if (!bp->glx_context) return;
- glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *bp->glx_context);
-
- if (bp->flappers) free (bp->flappers);
- if (bp->tc) textclient_close (bp->tc);
- if (bp->trackball) gltrackball_free (bp->trackball);
- if (bp->rot) free_rotator (bp->rot);
- if (bp->rot2) free_rotator (bp->rot2);
- if (bp->font_data) free_texture_font (bp->font_data);
- if (bp->dlists) {
- for (i = 0; i < countof(all_objs); i++)
- if (glIsList(bp->dlists[i])) glDeleteLists(bp->dlists[i], 1);
- free (bp->dlists);
- }
- if (bp->texinfo) {
- for (i = 0; i < bp->texinfo_size; i++)
- if (bp->texinfo[i].texid) glDeleteTextures (1, &bp->texinfo[i].texid);
- free (bp->texinfo);
- }
-}
-
-XSCREENSAVER_MODULE ("SplitFlap", splitflap)
-
-#endif /* USE_GL */