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/geodesicgears.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/geodesicgears.c')
| -rw-r--r-- | hacks/glx/geodesicgears.c | 1801 |
1 files changed, 0 insertions, 1801 deletions
diff --git a/hacks/glx/geodesicgears.c b/hacks/glx/geodesicgears.c deleted file mode 100644 index 146b835..0000000 --- a/hacks/glx/geodesicgears.c +++ /dev/null @@ -1,1801 +0,0 @@ -/* geodesicgears, Copyright (c) 2014-2015 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. - * - * Inspired by http://bugman123.com/Gears/ - * and by http://kennethsnelson.net/PortraitOfAnAtom.pdf - */ - -#define DEFAULTS "*delay: 30000 \n" \ - "*count: 4 \n" \ - "*wireframe: False \n" \ - "*showFPS: False \n" \ - "*texFontCacheSize: 100 \n" \ - "*suppressRotationAnimation: True\n" \ - "*font: sans-serif 16\n" \ - -# define release_geodesic 0 - -#include "xlockmore.h" -#include "involute.h" -#include "colors.h" -#include "normals.h" -#include "rotator.h" -#include "gltrackball.h" -#include <ctype.h> -#include "texfont.h" - - -#ifdef USE_GL /* whole file */ - -#include "gllist.h" - -#define DEF_SPIN "True" -#define DEF_WANDER "True" -#define DEF_SPEED "1.0" -#define DEF_LABELS "False" -#define DEF_NUMBERS "False" -#define DEF_TIMEOUT "20" - -typedef struct { double a, o; } LL; /* latitude + longitude */ - -/* 10:6 is a mismesh. */ - -static const struct { - enum { PRISM, OCTO, DECA, G14, G18, G32, G92, G182 } type; - const GLfloat args[5]; -} gear_templates[] = { - { PRISM }, - { OCTO }, - { DECA }, - { G14 }, - { G18 }, - { G32, { 15, 6, 0.4535 }}, /* teeth1, teeth2, radius1 */ - { G32, { 15, 12, 0.3560 }}, - { G32, { 20, 6, 0.4850 }}, - { G32, { 20, 12, 0.3995 }}, /* double of 10:6 */ - { G32, { 20, 18, 0.3375 }}, - { G32, { 25, 6, 0.5065 }}, - { G32, { 25, 12, 0.4300 }}, - { G32, { 25, 18, 0.3725 }}, - { G32, { 25, 24, 0.3270 }}, - { G32, { 30, 12, 0.4535 }}, /* double of 15:6 */ - { G32, { 30, 18, 0.3995 }}, - { G32, { 30, 24, 0.3560 }}, /* double of 15:12 */ - { G32, { 30, 30, 0.3205 }}, - { G32, { 35, 12, 0.4710 }}, - { G32, { 35, 18, 0.4208 }}, - { G32, { 35, 24, 0.3800 }}, - { G32, { 35, 30, 0.3450 }}, - { G32, { 35, 36, 0.3160 }}, - { G32, { 40, 12, 0.4850 }}, /* double of 20:6 */ - { G32, { 40, 24, 0.3995 }}, /* double of 10:6, 20:12 */ -/*{ G32, { 40, 36, 0.3375 }},*/ /* double of 20:18 */ - { G32, { 50, 12, 0.5065 }}, /* double of 25:6 */ - { G32, { 50, 24, 0.4300 }}, /* double of 25:12 */ - - /* These all have phase errors and don't always mesh properly. - Maybe we should just omit them? */ - - { G92, { 35, 36, 16, 0.2660, 0.366 }}, /* teeth1, 2, 3, r1, pitch3 */ - { G92, { 25, 36, 11, 0.2270, 0.315 }}, -/*{ G92, { 15, 15, 8, 0.2650, 0.356 }},*/ -/*{ G92, { 20, 21, 8, 0.2760, 0.355 }},*/ - { G92, { 25, 27, 16, 0.2320, 0.359 }}, - { G92, { 20, 36, 11, 0.1875, 0.283 }}, - { G92, { 30, 30, 16, 0.2585, 0.374 }}, /* double of 15:15:8 */ - { G92, { 20, 33, 11, 0.1970, 0.293 }}, -/*{ G92, { 10, 12, 8, 0.2030, 0.345 }},*/ - { G92, { 30, 33, 16, 0.2455, 0.354 }}, -/*{ G92, { 25, 24, 8, 0.3050, 0.375 }},*/ - { G92, { 20, 24, 16, 0.2030, 0.346 }}, -}; - - -typedef struct sphere_gear sphere_gear; -struct sphere_gear { - int id; /* name, for debugging */ - XYZ axis; /* the vector on which this gear's axis lies */ - int direction; /* rotation, +1 or -1 */ - GLfloat offset; /* rotational degrees from parent gear */ - sphere_gear *parent; /* gear driving this one, or 0 for root */ - sphere_gear **children; /* gears driven by this one (no loops) */ - sphere_gear **neighbors; /* gears touching this one (circular!) */ - int nchildren, children_size; - int nneighbors, neighbors_size; - const gear *g; /* shape of this gear (shared) */ -}; - - -typedef struct { - GLXContext *glx_context; - rotator *rot; - trackball_state *trackball; - Bool button_down_p; - int ncolors; - XColor *colors; - GLfloat color1[4], color2[4]; - texture_font_data *font; - - int nshapes, shapes_size; /* how many 'gear' objects there are */ - int ngears, gears_size; /* how many 'sphere_gear' objects there are */ - gear *shapes; - sphere_gear *gears; - - int which; - int mode; /* 0 = normal, 1 = out, 2 = in */ - int mode_tick; - int next; /* 0 = random, -1 = back, 1 = forward */ - time_t draw_time; - int draw_tick; - char *desc; - - GLfloat th; /* rotation of the root sphere_gear in degrees. */ - -} geodesic_configuration; - -static geodesic_configuration *bps = NULL; - -static int timeout; -static Bool do_spin; -static GLfloat speed; -static Bool do_wander; -static Bool do_labels; -static Bool do_numbers; - -static XrmOptionDescRec opts[] = { - { "-spin", ".spin", XrmoptionNoArg, "True" }, - { "+spin", ".spin", XrmoptionNoArg, "False" }, - { "-speed", ".speed", XrmoptionSepArg, 0 }, - { "-wander", ".wander", XrmoptionNoArg, "True" }, - { "+wander", ".wander", XrmoptionNoArg, "False" }, - { "-labels", ".labels", XrmoptionNoArg, "True" }, - { "+labels", ".labels", XrmoptionNoArg, "False" }, - { "-numbers", ".numbers",XrmoptionNoArg, "True" }, - { "+numbers", ".numbers",XrmoptionNoArg, "False" }, - { "-timeout", ".timeout",XrmoptionSepArg, 0 }, -}; - -static argtype vars[] = { - {&do_spin, "spin", "Spin", DEF_SPIN, t_Bool}, - {&do_wander, "wander", "Wander", DEF_WANDER, t_Bool}, - {&speed, "speed", "Speed", DEF_SPEED, t_Float}, - {&do_labels, "labels", "Labels", DEF_LABELS, t_Bool}, - {&do_numbers,"numbers","Numbers",DEF_NUMBERS,t_Bool}, - {&timeout, "timeout","Seconds",DEF_TIMEOUT,t_Int}, -}; - -ENTRYPOINT ModeSpecOpt geodesic_opts = { - countof(opts), opts, countof(vars), vars, NULL}; - - -#undef BELLRAND -#define BELLRAND(n) ((frand((n)) + frand((n)) + frand((n))) / 3) - - - -static XYZ -cross_product (XYZ a, XYZ b) -{ - XYZ c; - c.x = (a.y * b.z) - (a.z * b.y); - c.y = (a.z * b.x) - (a.x * b.z); - c.z = (a.x * b.y) - (a.y * b.x); - return c; -} - - -static GLfloat -dot_product (XYZ a, XYZ b) -{ - return (a.x * b.x) + (a.y * b.y) + (a.z * b.z); -} - - -static XYZ -normalize (XYZ v) -{ - GLfloat d = sqrt ((v.x * v.x) + (v.y * v.y) + (v.z * v.z)); - if (d == 0) - v.x = v.y = v.z = 0; - else - { - v.x /= d; - v.y /= d; - v.z /= d; - } - return v; -} - - -static XYZ -polar_to_cartesian (LL v) -{ - XYZ p; - p.x = cos (v.a) * cos (v.o); - p.y = cos (v.a) * sin (v.o); - p.z = sin (v.a); - return p; -} - - - - -static gear * -add_gear_shape (ModeInfo *mi, GLfloat radius, int teeth) -{ - geodesic_configuration *bp = &bps[MI_SCREEN(mi)]; - int wire = MI_IS_WIREFRAME(mi); - gear *g; - int i; - - if (bp->nshapes >= bp->shapes_size - 1) - { - bp->shapes_size = bp->shapes_size * 1.2 + 4; - bp->shapes = (gear *) - realloc (bp->shapes, bp->shapes_size * sizeof(*bp->shapes)); - } - g = &bp->shapes[bp->nshapes++]; - - memset (g, 0, sizeof(*g)); - - g->r = radius; - g->nteeth = teeth; - g->ratio = 1; - - g->tooth_h = g->r / (teeth * 0.4); - - if (g->tooth_h > 0.06) /* stubbier teeth when small tooth count. */ - g->tooth_h *= 0.6; - - g->thickness = 0.05 + BELLRAND(0.15); - g->thickness2 = g->thickness / 4; - g->thickness3 = g->thickness; - g->size = wire ? INVOLUTE_SMALL : INVOLUTE_LARGE; - - /* Move the disc's origin inward to make the edge of the disc be tangent - to the unit sphere. */ - g->z = 1 - sqrt (1 - (g->r * g->r)); - - /* #### This isn't quite right */ - g->tooth_slope = 1 + ((g->z * 2) / g->r); - - - /* Decide on shape of gear interior: - - just a ring with teeth; - - that, plus a thinner in-set "plate" in the middle; - - that, plus a thin raised "lip" on the inner plate; - - or, a wide lip (really, a thicker third inner plate.) - */ - if (wire) - ; - else if ((random() % 10) == 0) - { - /* inner_r can go all the way in; there's no inset disc. */ - g->inner_r = (g->r * 0.3) + frand((g->r - g->tooth_h/2) * 0.6); - g->inner_r2 = 0; - g->inner_r3 = 0; - } - else - { - /* inner_r doesn't go in very far; inner_r2 is an inset disc. */ - g->inner_r = (g->r * 0.5) + frand((g->r - g->tooth_h) * 0.4); - g->inner_r2 = (g->r * 0.1) + frand(g->inner_r * 0.5); - g->inner_r3 = 0; - - if (g->inner_r2 > (g->r * 0.2)) - { - int nn = (random() % 10); - if (nn <= 2) - g->inner_r3 = (g->r * 0.1) + frand(g->inner_r2 * 0.2); - else if (nn <= 7 && g->inner_r2 >= 0.1) - g->inner_r3 = g->inner_r2 - 0.01; - } - } - - /* If we have three discs, sometimes make the middle disc be spokes. - */ - if (g->inner_r3 && ((random() % 5) == 0)) - { - g->spokes = 2 + BELLRAND (5); - g->spoke_thickness = 1 + frand(7.0); - if (g->spokes == 2 && g->spoke_thickness < 2) - g->spoke_thickness += 1; - } - - /* Sometimes add little nubbly bits, if there is room. - */ - if (!wire && g->nteeth > 5) - { - double size = 0; - involute_biggest_ring (g, 0, &size, 0); - if (size > g->r * 0.2 && (random() % 5) == 0) - { - g->nubs = 1 + (random() % 16); - if (g->nubs > 8) g->nubs = 1; - } - } - - /* Decide how complex the polygon model should be. - */ - { - double pix = g->tooth_h * MI_HEIGHT(mi); /* approx. tooth size in pixels */ - if (pix <= 4) g->size = INVOLUTE_SMALL; - else if (pix <= 8) g->size = INVOLUTE_MEDIUM; - else if (pix <= 30) g->size = INVOLUTE_LARGE; - else g->size = INVOLUTE_HUGE; - } - - if (g->inner_r3 > g->inner_r2) abort(); - if (g->inner_r2 > g->inner_r) abort(); - if (g->inner_r > g->r) abort(); - - i = random() % bp->ncolors; - g->color[0] = bp->colors[i].red / 65536.0; - g->color[1] = bp->colors[i].green / 65536.0; - g->color[2] = bp->colors[i].blue / 65536.0; - g->color[3] = 1; - - i = (i + bp->ncolors / 2) % bp->ncolors; - g->color2[0] = bp->colors[i].red / 65536.0; - g->color2[1] = bp->colors[i].green / 65536.0; - g->color2[2] = bp->colors[i].blue / 65536.0; - g->color2[3] = 1; - - g->dlist = glGenLists (1); - glNewList (g->dlist, GL_COMPILE); - -#if 1 - { - gear G, *g2 = &G; - *g2 = *g; - - /* Move the gear inward so that its outer edge is on the disc, instead - of its midpoint. */ - g2->z += g2->thickness/2; - - /* 'radius' is at the surface but 'g->r' is at the center, so we need - to reverse the slope computation that involute.c does. */ - g2->r /= (1 + (g2->thickness * g2->tooth_slope / 2)); - - glPushMatrix(); - glTranslatef(g2->x, g2->y, -g2->z); - - /* Line up the center of the point of tooth 0 with "up". */ - glRotatef (90, 0, 0, 1); - glRotatef (180, 0, 1, 0); - glRotatef (-360.0 / g2->nteeth / 4, 0, 0, 1); - - g->polygons = draw_involute_gear (g2, wire); - glPopMatrix(); - } -# else /* draw discs */ - { - glPushMatrix(); - glTranslatef(g->x, g->y, -g->z); - glLineWidth (2); - glFrontFace (GL_CCW); - glNormal3f(0, 0, 1); - glColor3f(0, 0, 0); - glDisable (GL_LIGHTING); - - glBegin(GL_LINES); - glVertex3f (0, 0, 0); - glVertex3f (0, radius, 0); - glEnd(); - - glColor3f(0.5, 0.5, 0.5); - glBegin(wire ? GL_LINE_LOOP : GL_TRIANGLE_FAN); - { - GLfloat th; - GLfloat step = M_PI * 2 / 128; - /* radius *= 1.005; */ - glVertex3f (0, 0, 0); - for (th = 0; th < M_PI * 2 + step; th += step) - { - GLfloat x = cos(th) * radius; - GLfloat y = sin(th) * radius; - glVertex3f (x, y, 0); - } - } - glEnd(); - if (!wire) glEnable(GL_LIGHTING); - glPopMatrix(); - } -# endif /* 0 */ - - glEndList (); - - return g; -} - - -static void -add_sphere_gear (ModeInfo *mi, gear *g, XYZ axis) -{ - geodesic_configuration *bp = &bps[MI_SCREEN(mi)]; - sphere_gear *gg; - int i; - - axis = normalize (axis); - - /* If there's already a gear on this axis, don't duplicate it. */ - for (i = 0; i < bp->ngears; i++) - { - XYZ o = bp->gears[i].axis; - if (o.x == axis.x && o.y == axis.y && o.z == axis.z) - return; - } - - if (bp->ngears >= bp->gears_size - 1) - { - bp->gears_size = bp->gears_size * 1.2 + 10; - bp->gears = (sphere_gear *) - realloc (bp->gears, bp->gears_size * sizeof(*bp->gears)); - } - - gg = &bp->gears[bp->ngears]; - memset (gg, 0, sizeof(*gg)); - gg->id = bp->ngears; - gg->axis = axis; - gg->direction = 0; - gg->g = g; - bp->ngears++; -} - - -static void -free_sphere_gears (ModeInfo *mi) -{ - geodesic_configuration *bp = &bps[MI_SCREEN(mi)]; - int i; - for (i = 0; i < bp->nshapes; i++) - { - if (bp->shapes[i].dlist) - glDeleteLists (bp->shapes[i].dlist, 1); - } - free (bp->shapes); - bp->nshapes = 0; - bp->shapes_size = 0; - bp->shapes = 0; - - for (i = 0; i < bp->ngears; i++) - { - sphere_gear *g = &bp->gears[i]; - if (g->children) - free (g->children); - if (g->neighbors) - free (g->neighbors); - } - free (bp->gears); - bp->ngears = 0; - bp->gears_size = 0; - bp->gears = 0; -} - - - -/* Is the gear a member of the list? - */ -static Bool -gear_list_member (sphere_gear *g, sphere_gear **list, int count) -{ - int i; - for (i = 0; i < count; i++) - if (list[i] == g) return True; - return False; -} - - -/* Add the gear to the list, resizing it as needed. - */ -static void -gear_list_push (sphere_gear *g, - sphere_gear ***listP, - int *countP, int *sizeP) -{ - if (*countP >= (*sizeP) - 1) - { - *sizeP = (*sizeP) * 1.2 + 4; - *listP = (sphere_gear **) realloc (*listP, (*sizeP) * sizeof(**listP)); - } - (*listP)[*countP] = g; - (*countP)++; -} - - -/* Mark child and parent as being mutual neighbors. - */ -static void -link_neighbors (sphere_gear *parent, sphere_gear *child) -{ - if (child == parent) abort(); - - /* Add child to parent's list of neighbors */ - if (! gear_list_member (child, parent->neighbors, parent->nneighbors)) - { - gear_list_push (child, - &parent->neighbors, - &parent->nneighbors, - &parent->neighbors_size); - /* fprintf(stderr, "neighbor %2d -> %2d (%d)\n", parent->id, child->id, - parent->nneighbors); */ - } - - /* Add parent to child's list of neighbors */ - if (! gear_list_member (parent, child->neighbors, child->nneighbors)) - { - gear_list_push (parent, - &child->neighbors, - &child->nneighbors, - &child->neighbors_size); - /* fprintf(stderr, "neighbor %2d <- %2d\n", parent->id, child->id); */ - } -} - -/* Mark child as having parent, and vice versa. - */ -static void -link_child (sphere_gear *parent, sphere_gear *child) -{ - if (child == parent) abort(); - if (child->parent) return; - - gear_list_push (child, - &parent->children, - &parent->nchildren, - &parent->children_size); - child->parent = parent; - /* fprintf(stderr, "child %2d -> %2d (%d)\n", parent->id, child->id, - parent->nchildren); */ -} - - - -static void link_children (sphere_gear *); - -static void -link_children (sphere_gear *parent) -{ - int i; -# if 1 /* depth first */ - for (i = 0; i < parent->nneighbors; i++) - { - sphere_gear *child = parent->neighbors[i]; - if (! child->parent) - { - link_child (parent, child); - link_children (child); - } - } -# else /* breadth first */ - for (i = 0; i < parent->nneighbors; i++) - { - sphere_gear *child = parent->neighbors[i]; - if (! child->parent) - link_child (parent, child); - } - for (i = 0; i < parent->nchildren; i++) - { - sphere_gear *child = parent->children[i]; - link_children (child); - } -# endif -} - - - -/* Whether the two gears touch. - */ -static Bool -gears_touch_p (ModeInfo *mi, sphere_gear *a, sphere_gear *b) -{ - /* We need to know if the two discs on the surface overlap. - - Find the angle between the axis of each disc, and a point on its edge: - the axis between the hypotenuse and adjacent of a right triangle between - the disc's radius and the origin. - - R - _____ - |_| / - | / - 1 | / - |t/ t = asin(R) - |/ - - Find the angle between the axes of the two discs. - - | - | / angle = acos (v1 dot v2) - 1 | / axis = v1 cross v2 - | / 1 - | / - |/ - - If the sum of the first two angles is less than the third angle, - they touch. - */ - XYZ p1 = a->axis; - XYZ p2 = b->axis; - double t1 = asin (a->g->r); - double t2 = asin (b->g->r); - double th = acos (dot_product (p1, p2)); - - return (t1 + t2 >= th); -} - - -/* Set the rotation direction for the gear and its kids. - */ -static void -orient_gears (ModeInfo *mi, sphere_gear *g) -{ - int i; - if (g->parent) - g->direction = -g->parent->direction; - for (i = 0; i < g->nchildren; i++) - orient_gears (mi, g->children[i]); -} - - -/* Returns the global model coordinates of the given tooth of a gear. - */ -static XYZ -tooth_coords (const sphere_gear *s, int tooth) -{ - const gear *g = s->g; - GLfloat off = s->offset * (M_PI / 180) * g->ratio * s->direction; - GLfloat th = (tooth * M_PI * 2 / g->nteeth) - off; - XYZ axis; - GLfloat angle; - XYZ from = { 0, 1, 0 }; - XYZ to = s->axis; - XYZ p0, p1, p2; - GLfloat x, y, z, C, S, m[4][4]; - - axis = cross_product (from, to); - angle = acos (dot_product (from, to)); - - p0 = normalize (axis); - x = p0.x; - y = p0.y; - z = p0.z; - C = cos(angle); - S = sin(angle); - - /* this is what glRotatef does */ - m[0][0] = x*x * (1 - C) + C; - m[1][0] = x*y * (1 - C) - z*S; - m[2][0] = x*z * (1 - C) + y*S; - m[3][0] = 0; - - m[0][1] = y*x * (1 - C) + z*S; - m[1][1] = y*y * (1 - C) + C; - m[2][1] = y*z * (1 - C) - x*S; - m[3][1] = 0; - - m[0][2] = x*z * (1 - C) - y*S; - m[1][2] = y*z * (1 - C) + x*S; - m[2][2] = z*z * (1 - C) + C; - m[3][2] = 0; - - m[0][3] = 0; - m[1][3] = 0; - m[2][3] = 0; - m[3][3] = 1; - - /* The point to transform */ - p1.x = g->r * sin (th); - p1.z = g->r * cos (th); - p1.y = 1 - g->z; - p1 = normalize (p1); - - /* transformation result */ - p2.x = p1.x * m[0][0] + p1.y * m[1][0] + p1.z * m[2][0] + m[3][0]; - p2.y = p1.x * m[0][1] + p1.y * m[1][1] + p1.z * m[2][1] + m[3][1]; - p2.z = p1.x * m[0][2] + p1.y * m[1][2] + p1.z * m[2][2] + m[3][2]; - - return p2; -} - - -/* Returns the number of the tooth of the first gear that is closest - to any tooth of its parent. Also the position of the parent tooth. - */ -static int -parent_tooth (const sphere_gear *s, XYZ *parent) -{ - const sphere_gear *s2 = s->parent; - int i, j; - GLfloat min_dist = 99999; - int min_tooth = 0; - XYZ min_parent = { 0, 0, 0 }; - - if (s2) - for (i = 0; i < s->g->nteeth; i++) - { - XYZ p1 = tooth_coords (s, i); - for (j = 0; j < s2->g->nteeth; j++) - { - XYZ p2 = tooth_coords (s2, j); - XYZ d; - GLfloat dist; - d.x = p1.x - p2.x; - d.y = p1.y - p2.y; - d.z = p1.z - p2.z; - - dist = sqrt (d.x*d.x + d.y*d.y + d.z*d.z); - if (dist < min_dist) - { - min_dist = dist; - min_parent = p2; - min_tooth = i; - } - } - } - *parent = min_parent; - return min_tooth; -} - - -/* Make all of the gear's children's teeth mesh properly. - */ -static void align_gear_teeth (sphere_gear *s); -static void -align_gear_teeth (sphere_gear *s) -{ - int i; - XYZ pc; - - if (s->parent) - { - /* Iterate this gear's offset until we find a value for it that - minimizes the distance between this gear's parent-pointing - tooth, and the corresponding tooth on the parent. - */ - int pt = parent_tooth (s, &pc); - GLfloat range = 360 / s->g->nteeth; - GLfloat steps = 64; - GLfloat min_dist = 999999; - GLfloat min_off = 0; - GLfloat off; - - for (off = -range/2; off < range/2; off += range/steps) - { - XYZ tc, d; - GLfloat dist; - s->offset = off; - tc = tooth_coords (s, pt); - d.x = pc.x - tc.x; - d.y = pc.y - tc.y; - d.z = pc.z - tc.z; - dist = sqrt (d.x*d.x + d.y*d.y + d.z*d.z); - if (dist < min_dist) - { - min_dist = dist; - min_off = off; - } - } - - s->offset = min_off; - } - - /* Now do the children. We have to do it in parent/child order because - the offset we just computed for the parent affects everyone downstream. - */ - for (i = 0; i < s->nchildren; i++) - align_gear_teeth (s->children[i]); -} - - - -static void -describe_gears (ModeInfo *mi) -{ - geodesic_configuration *bp = &bps[MI_SCREEN(mi)]; - int gears_per_teeth[1000]; - int i; - int lines = 0; - memset (gears_per_teeth, 0, sizeof(gears_per_teeth)); - for (i = 0; i < bp->ngears; i++) - gears_per_teeth[bp->gears[i].g->nteeth]++; - if (bp->desc) free (bp->desc); - bp->desc = (char *) malloc (80 * bp->ngears); - *bp->desc = 0; - for (i = 0; i < countof(gears_per_teeth); i++) - if (gears_per_teeth[i]) - { - sprintf (bp->desc + strlen(bp->desc), - "%s%d gears with %d teeth", - (lines > 0 ? ",\n" : ""), - gears_per_teeth[i], i); - lines++; - } - if (lines > 1) - sprintf (bp->desc + strlen(bp->desc), ",\n%d gears total", bp->ngears); - strcat (bp->desc, "."); -} - - -/* Takes the gears and makes an arbitrary DAG of them in order to compute - direction and gear ratios. - */ -static void -sort_gears (ModeInfo *mi) -{ - geodesic_configuration *bp = &bps[MI_SCREEN(mi)]; - sphere_gear *root = 0; - int i, j; - - /* For each gear, compare it against every other gear. - If they touch, mark them as being each others' neighbors. - */ - for (i = 0; i < bp->ngears; i++) - { - sphere_gear *a = &bp->gears[i]; - for (j = 0; j < bp->ngears; j++) - { - sphere_gear *b = &bp->gears[j]; - if (a == b) continue; - if (gears_touch_p (mi, a, b)) - link_neighbors (a, b); - } - } - - bp->gears[0].parent = &bp->gears[0]; /* don't give this one a parent */ - link_children (&bp->gears[0]); - bp->gears[0].parent = 0; - - -# if 0 - for (i = 0; i < bp->ngears; i++) - { - fprintf (stderr, "%2d: p = %2d; k(%d, %d) = ", - i, - bp->gears[i].parent ? bp->gears[i].parent->id : -1, - bp->gears[i].nneighbors, - bp->gears[i].nchildren); - for (j = 0; j < bp->gears[i].nneighbors; j++) - fprintf (stderr, "%2d ", (int) bp->gears[i].neighbors[j]->id); - fprintf (stderr, "\t\t"); - if (j < 5) fprintf (stderr, "\t"); - for (j = 0; j < bp->gears[i].nchildren; j++) - fprintf (stderr, "%2d ", (int) bp->gears[i].children[j]->id); - fprintf (stderr,"\n"); - } - fprintf (stderr,"\n"); -# endif /* 0 */ - - - /* If there is more than one gear with no parent, we fucked up. */ - - root = 0; - for (i = 0; i < bp->ngears; i++) - { - sphere_gear *g = &bp->gears[i]; - if (!g->parent) - root = g; - } - - if (! root) abort(); - - root->direction = 1; - orient_gears (mi, root); - - /* If there are any gears with no direction, they aren't reachable. */ - for (i = 0; i < bp->ngears; i++) - { - sphere_gear *g = &bp->gears[i]; - if (g->direction == 0) - fprintf(stderr,"INTERNAL ERROR: unreachable: %d\n", g->id); - } - - align_gear_teeth (root); - describe_gears (mi); -} - - -/* Create 5 identical gears arranged on the faces of a uniform - triangular prism. - */ -static void -make_prism (ModeInfo *mi) -{ - geodesic_configuration *bp = &bps[MI_SCREEN(mi)]; - gear *g; - XYZ a; - int i; - int teeth = 4 * (4 + (int) (BELLRAND(20))); - if (teeth % 4) abort(); /* must be a multiple of 4 */ - - g = add_gear_shape (mi, 0.7075, teeth); - - a.x = 0; a.y = 0; a.z = 1; - add_sphere_gear (mi, g, a); - a.z = -1; - add_sphere_gear (mi, g, a); - - a.z = 0; - for (i = 0; i < 3; i++) - { - GLfloat th = i * M_PI * 2 / 3; - a.x = cos (th); - a.y = sin (th); - add_sphere_gear (mi, g, a); - } - - if (bp->ngears != 5) abort(); -} - - -/* Create 8 identical gears arranged on the faces of an octohedron - (or alternately, arranged on the diagonals of a cube.) - */ -static void -make_octo (ModeInfo *mi) -{ - geodesic_configuration *bp = &bps[MI_SCREEN(mi)]; - static const XYZ verts[] = {{ -1, -1, -1 }, - { -1, -1, 1 }, - { -1, 1, 1 }, - { -1, 1, -1 }, - { 1, -1, 1 }, - { 1, -1, -1 }, - { 1, 1, -1 }, - { 1, 1, 1 }}; - gear *g; - int i; - int teeth = 4 * (4 + (int) (BELLRAND(20))); - if (teeth % 4) abort(); /* must be a multiple of 4 */ - - g = add_gear_shape (mi, 0.578, teeth); - for (i = 0; i < countof(verts); i++) - add_sphere_gear (mi, g, verts[i]); - - if (bp->ngears != 8) abort(); -} - - -/* Create 10 identical gears arranged on the faces of ... something. - I'm not sure what polyhedron is the basis of this. - */ -static void -make_deca (ModeInfo *mi) -{ - geodesic_configuration *bp = &bps[MI_SCREEN(mi)]; - gear *g; - XYZ a; - int i, j; - int teeth = 4 * (4 + (int) (BELLRAND(15))); - if (teeth % 4) abort(); /* must be a multiple of 4 */ - - g = add_gear_shape (mi, 0.5415, teeth); - - a.x = 0; a.y = 0; a.z = 1; - add_sphere_gear (mi, g, a); - a.z = -1; - add_sphere_gear (mi, g, a); - - for (j = -1; j <= 1; j += 2) - { - GLfloat off = (j < 0 ? 0 : M_PI / 4); - LL v; - v.a = j * M_PI * 0.136; /* #### Empirical. What is this? */ - for (i = 0; i < 4; i++) - { - v.o = i * M_PI / 2 + off; - a = polar_to_cartesian (v); - add_sphere_gear (mi, g, a); - } - } - if (bp->ngears != 10) abort(); -} - - -/* Create 14 identical gears arranged on the faces of ... something. - I'm not sure what polyhedron is the basis of this. - */ -static void -make_14 (ModeInfo *mi) -{ - geodesic_configuration *bp = &bps[MI_SCREEN(mi)]; - gear *g; - XYZ a; - int i; - GLfloat r = 0.4610; - int teeth = 6 * (2 + (int) (BELLRAND(4))); - if (teeth % 6) abort(); /* must be a multiple of 6. I think? */ - /* mismeshes: 24 30 34 36 42 48 54 60 */ - - /* North, south */ - g = add_gear_shape (mi, r, teeth); - a.x = 0; a.y = 0; a.z = 1; - add_sphere_gear (mi, g, a); - a.z = -1; - add_sphere_gear (mi, g, a); - - /* Equator */ - a.z = 0; - for (i = 0; i < 4; i++) - { - GLfloat th = i * M_PI * 2 / 4 + (M_PI / 4); - a.x = cos(th); - a.y = sin(th); - add_sphere_gear (mi, g, a); - } - - /* The other 8 */ - g = add_gear_shape (mi, r, teeth); - - for (i = 0; i < 4; i++) - { - LL v; - v.a = M_PI * 0.197; /* #### Empirical. Also, wrong. What is this? */ - v.o = i * M_PI * 2 / 4; - a = polar_to_cartesian (v); - add_sphere_gear (mi, g, a); - v.a = -v.a; - a = polar_to_cartesian (v); - add_sphere_gear (mi, g, a); - } - - if (bp->ngears != 14) abort(); -} - - -/* Create 18 identical gears arranged on the faces of ... something. - I'm not sure what polyhedron is the basis of this. - */ -static void -make_18 (ModeInfo *mi) -{ - geodesic_configuration *bp = &bps[MI_SCREEN(mi)]; - gear *g, *g2; - XYZ a; - int i; - GLfloat r = 0.3830; - int sizes[] = { 8, 12, 16, 20 }; /* 10, 14, 18, 26 and 34 don't work */ - int teeth = sizes[random() % countof(sizes)] * (1 + (random() % 4)); - - /* North, south */ - g = add_gear_shape (mi, r, teeth); - a.x = 0; a.y = 0; a.z = 1; - add_sphere_gear (mi, g, a); - a.z = -1; - add_sphere_gear (mi, g, a); - - /* Equator */ - g2 = add_gear_shape (mi, r, teeth); - a.z = 0; - for (i = 0; i < 8; i++) - { - GLfloat th = i * M_PI * 2 / 8 + (M_PI / 4); - a.x = cos(th); - a.y = sin(th); - add_sphere_gear (mi, (i & 1 ? g : g2), a); - } - - /* The other 16 */ - g = add_gear_shape (mi, r, teeth); - - for (i = 0; i < 4; i++) - { - LL v; - v.a = M_PI * 0.25; - v.o = i * M_PI * 2 / 4; - a = polar_to_cartesian (v); - add_sphere_gear (mi, g, a); - v.a = -v.a; - a = polar_to_cartesian (v); - add_sphere_gear (mi, g, a); - } - - if (bp->ngears != 18) abort(); -} - - -/* Create 32 gears arranged along a truncated icosahedron: - One gear on each of the 20 faces, and one on each of the 12 vertices. - */ -static void -make_32 (ModeInfo *mi, const GLfloat *args) -{ - /* http://bugman123.com/Gears/32GearSpheres/ */ - geodesic_configuration *bp = &bps[MI_SCREEN(mi)]; - GLfloat th0 = atan (0.5); /* lat division: 26.57 deg */ - GLfloat s = M_PI / 5; /* lon division: 72 deg */ - int i; - - int teeth1 = args[0]; - int teeth2 = args[1]; - GLfloat r1 = args[2]; - GLfloat ratio = teeth2 / (GLfloat) teeth1; - GLfloat r2 = r1 * ratio; - - gear *gear1, *gear2; - - if (teeth1 % 5) abort(); - if (teeth2 % 6) abort(); - - gear1 = add_gear_shape (mi, r1, teeth1); - gear2 = add_gear_shape (mi, r2, teeth2); - gear2->ratio = 1 / ratio; - - { - XYZ a = { 0, 0, 1 }; - XYZ b = { 0, 0, -1 }; - add_sphere_gear (mi, gear1, a); - add_sphere_gear (mi, gear1, b); - } - - 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; - XYZ p1, p2, p3, pc, pc2; - 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)) /* southern hemisphere */ - { - v1.a = -v1.a; - v2.a = -v2.a; - v3.a = -v3.a; - vc.a = -vc.a; - } - - p1 = polar_to_cartesian (v1); - p2 = polar_to_cartesian (v2); - p3 = polar_to_cartesian (v3); - pc = polar_to_cartesian (vc); - - /* Two faces: 123 and 12c. */ - - add_sphere_gear (mi, gear1, p1); /* left shared point of 2 triangles */ - - pc2.x = (p1.x + p2.x + p3.x) / 3; /* center of bottom triangle */ - pc2.y = (p1.y + p2.y + p3.y) / 3; - pc2.z = (p1.z + p2.z + p3.z) / 3; - add_sphere_gear (mi, gear2, pc2); - - pc2.x = (p1.x + p2.x + pc.x) / 3; /* center of top triangle */ - pc2.y = (p1.y + p2.y + pc.y) / 3; - pc2.z = (p1.z + p2.z + pc.z) / 3; - add_sphere_gear (mi, gear2, pc2); - } - - if (bp->ngears != 32) abort(); -} - - -/* Create 92 gears arranged along a geodesic sphere: 20 + 12 + 60. - (frequency 3v, class-I geodesic tessellation of an icosahedron) - */ -static void -make_92 (ModeInfo *mi, const GLfloat *args) -{ - /* http://bugman123.com/Gears/92GearSpheres/ */ - geodesic_configuration *bp = &bps[MI_SCREEN(mi)]; - GLfloat th0 = atan (0.5); /* lat division: 26.57 deg */ - GLfloat s = M_PI / 5; /* lon division: 72 deg */ - int i; - - int tscale = 2; /* These don't mesh properly, so let's increase the - number of teeth so that it's not so obvious. */ - - int teeth1 = args[0] * tscale; - int teeth2 = args[1] * tscale; - int teeth3 = args[2] * tscale; - GLfloat r1 = args[3]; - GLfloat ratio2 = teeth2 / (GLfloat) teeth1; - GLfloat ratio3 = teeth3 / (GLfloat) teeth2; - GLfloat r2 = r1 * ratio2; - GLfloat r3 = r2 * ratio3; - - GLfloat r4 = args[4]; /* #### Empirical. Not sure what its basis is. */ - GLfloat r5 = 1 - r4; - - gear *gear1, *gear2, *gear3; - - gear1 = add_gear_shape (mi, r1, teeth1); - gear2 = add_gear_shape (mi, r2, teeth2); - gear3 = add_gear_shape (mi, r3, teeth3); - gear2->ratio = 1 / ratio2; - gear3->ratio = 1 / ratio3; - - { - XYZ a = { 0, 0, 1 }; - XYZ b = { 0, 0, -1 }; - add_sphere_gear (mi, gear1, a); - add_sphere_gear (mi, gear1, b); - } - - 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; - XYZ p1, p2, p3, pc, pc2; - 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)) /* southern hemisphere */ - { - v1.a = -v1.a; - v2.a = -v2.a; - v3.a = -v3.a; - vc.a = -vc.a; - } - - p1 = polar_to_cartesian (v1); - p2 = polar_to_cartesian (v2); - p3 = polar_to_cartesian (v3); - pc = polar_to_cartesian (vc); - - /* Two faces: 123 and 12c. */ - - add_sphere_gear (mi, gear1, p1); /* left shared point of 2 triangles */ - - pc2.x = (p1.x + p2.x + p3.x) / 3; /* center of bottom triangle */ - pc2.y = (p1.y + p2.y + p3.y) / 3; - pc2.z = (p1.z + p2.z + p3.z) / 3; - add_sphere_gear (mi, gear2, pc2); - - pc2.x = (p1.x + p2.x + pc.x) / 3; /* center of top triangle */ - pc2.y = (p1.y + p2.y + pc.y) / 3; - pc2.z = (p1.z + p2.z + pc.z) / 3; - add_sphere_gear (mi, gear2, pc2); - - /* left edge of bottom triangle, 1/3 in */ - pc2.x = p1.x + (p3.x - p1.x) * r4; - pc2.y = p1.y + (p3.y - p1.y) * r4; - pc2.z = p1.z + (p3.z - p1.z) * r4; - add_sphere_gear (mi, gear3, pc2); - - /* left edge of bottom triangle, 2/3 in */ - pc2.x = p1.x + (p3.x - p1.x) * r5; - pc2.y = p1.y + (p3.y - p1.y) * r5; - pc2.z = p1.z + (p3.z - p1.z) * r5; - add_sphere_gear (mi, gear3, pc2); - - /* left edge of top triangle, 1/3 in */ - pc2.x = p1.x + (pc.x - p1.x) * r4; - pc2.y = p1.y + (pc.y - p1.y) * r4; - pc2.z = p1.z + (pc.z - p1.z) * r4; - add_sphere_gear (mi, gear3, pc2); - - /* left edge of top triangle, 2/3 in */ - pc2.x = p1.x + (pc.x - p1.x) * r5; - pc2.y = p1.y + (pc.y - p1.y) * r5; - pc2.z = p1.z + (pc.z - p1.z) * r5; - add_sphere_gear (mi, gear3, pc2); - - /* center of shared edge, 1/3 in */ - pc2.x = p1.x + (p2.x - p1.x) * r4; - pc2.y = p1.y + (p2.y - p1.y) * r4; - pc2.z = p1.z + (p2.z - p1.z) * r4; - add_sphere_gear (mi, gear3, pc2); - - /* center of shared edge, 2/3 in */ - pc2.x = p1.x + (p2.x - p1.x) * r5; - pc2.y = p1.y + (p2.y - p1.y) * r5; - pc2.z = p1.z + (p2.z - p1.z) * r5; - add_sphere_gear (mi, gear3, pc2); - } - - if (bp->ngears != 92) abort(); -} - -static void -make_182 (ModeInfo *mi, const GLfloat *args) -{ - /* #### TODO: http://bugman123.com/Gears/182GearSpheres/ */ - abort(); -} - - -/* Window management, etc - */ -ENTRYPOINT void -reshape_geodesic (ModeInfo *mi, int width, int height) -{ - geodesic_configuration *bp = &bps[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), *bp->glx_context); - - glViewport (0, y, (GLint) width, (GLint) height); - - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - gluPerspective (30.0, 1/h, 1.0, 100.0); - - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - gluLookAt( 0.0, 0.0, 30.0, - 0.0, 0.0, 0.0, - 0.0, 1.0, 0.0); - - { - GLfloat s = (MI_WIDTH(mi) < MI_HEIGHT(mi) - ? (MI_WIDTH(mi) / (GLfloat) MI_HEIGHT(mi)) - : 1); - glScalef (s, s, s); - } - - glClear(GL_COLOR_BUFFER_BIT); -} - - -static void -pick_shape (ModeInfo *mi, time_t last) -{ - geodesic_configuration *bp = &bps[MI_SCREEN(mi)]; - int count = countof (gear_templates); - - if (bp->colors) - free (bp->colors); - - bp->ncolors = 1024; - bp->colors = (XColor *) calloc(bp->ncolors, sizeof(XColor)); - make_smooth_colormap (0, 0, 0, - bp->colors, &bp->ncolors, - False, 0, False); - - free_sphere_gears (mi); - - if (last == 0) - { - bp->which = random() % count; - } - else if (bp->next < 0) - { - bp->which--; - if (bp->which < 0) bp->which = count-1; - bp->next = 0; - } - else if (bp->next > 0) - { - bp->which++; - if (bp->which >= count) bp->which = 0; - bp->next = 0; - } - else - { - int n = bp->which; - while (n == bp->which) - n = random() % count; - bp->which = n; - } - - switch (gear_templates[bp->which].type) { - case PRISM: make_prism (mi); break; - case OCTO: make_octo (mi); break; - case DECA: make_deca (mi); break; - case G14: make_14 (mi); break; - case G18: make_18 (mi); break; - case G32: make_32 (mi, gear_templates[bp->which].args); break; - case G92: make_92 (mi, gear_templates[bp->which].args); break; - case G182: make_182(mi, gear_templates[bp->which].args); break; - default: abort(); break; - } - - sort_gears (mi); -} - - - -ENTRYPOINT void -init_geodesic (ModeInfo *mi) -{ - geodesic_configuration *bp; - - MI_INIT (mi, bps); - - bp = &bps[MI_SCREEN(mi)]; - - bp->glx_context = init_GL(mi); - - reshape_geodesic (mi, MI_WIDTH(mi), MI_HEIGHT(mi)); - - { - static GLfloat cspec[4] = {1.0, 1.0, 1.0, 1.0}; - static const GLfloat shiny = 128.0; - - static GLfloat pos[4] = {1.0, 1.0, 1.0, 0.0}; - static GLfloat amb[4] = {0.0, 0.0, 0.0, 1.0}; - static GLfloat dif[4] = {1.0, 1.0, 1.0, 1.0}; - static GLfloat spc[4] = {0.0, 1.0, 1.0, 1.0}; - - glLightfv(GL_LIGHT0, GL_POSITION, pos); - glLightfv(GL_LIGHT0, GL_AMBIENT, amb); - glLightfv(GL_LIGHT0, GL_DIFFUSE, dif); - glLightfv(GL_LIGHT0, GL_SPECULAR, spc); - - glMaterialfv (GL_FRONT, GL_SPECULAR, cspec); - glMateriali (GL_FRONT, GL_SHININESS, shiny); - } - - if (! bp->rot) - { - double spin_speed = 0.25 * speed; - double wander_speed = 0.01 * speed; - double spin_accel = 0.2; - - bp->rot = make_rotator (do_spin ? spin_speed : 0, - do_spin ? spin_speed : 0, - do_spin ? spin_speed : 0, - spin_accel, - do_wander ? wander_speed : 0, - True); - bp->trackball = gltrackball_init (True); - } - - bp->font = load_texture_font (MI_DISPLAY(mi), "font"); - - pick_shape (mi, 0); -} - - -ENTRYPOINT Bool -geodesic_handle_event (ModeInfo *mi, XEvent *event) -{ - geodesic_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; - else - { - if (event->xany.type == KeyPress) - { - KeySym keysym; - char c = 0; - XLookupString (&event->xkey, &c, 1, &keysym, 0); - if (c == '<' || c == ',' || c == '-' || c == '_' || - keysym == XK_Left || keysym == XK_Up || keysym == XK_Prior) - { - bp->next = -1; - goto SWITCH; - } - else if (c == '>' || c == '.' || c == '=' || c == '+' || - keysym == XK_Right || keysym == XK_Down || - keysym == XK_Next) - { - bp->next = 1; - goto SWITCH; - } - } - - if (screenhack_event_helper (MI_DISPLAY(mi), MI_WINDOW(mi), event)) - { - SWITCH: - bp->mode = 1; - bp->mode_tick = 4; - return True; - } - } - - return False; -} - - -ENTRYPOINT void -draw_geodesic (ModeInfo *mi) -{ - time_t now = time ((time_t *) 0); - int wire = MI_IS_WIREFRAME(mi); - geodesic_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); - - if (! wire) - { - glEnable (GL_DEPTH_TEST); - glEnable (GL_BLEND); - glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glEnable (GL_LIGHTING); - glEnable (GL_LIGHT0); - } - - - if (bp->draw_time == 0) - { - pick_shape (mi, bp->draw_time); - bp->draw_time = now; - } - else if (bp->mode == 0) - { - if (bp->draw_tick++ > 10) - { - if (bp->draw_time == 0) bp->draw_time = now; - bp->draw_tick = 0; - - if (!bp->button_down_p && - bp->draw_time + timeout <= now) - { - /* randomize every -timeout seconds */ - bp->mode = 1; /* go out */ - bp->mode_tick = 10 / speed; - bp->draw_time = now; - } - } - } - else if (bp->mode == 1) /* out */ - { - if (--bp->mode_tick <= 0) - { - bp->mode_tick = 10 / speed; - bp->mode = 2; /* go in */ - pick_shape (mi, bp->draw_time); - bp->draw_time = now; - } - } - else if (bp->mode == 2) /* in */ - { - if (--bp->mode_tick <= 0) - bp->mode = 0; /* normal */ - } - else - abort(); - - - if (! wire) - glShadeModel(GL_SMOOTH); - - glEnable(GL_DEPTH_TEST); - glEnable(GL_NORMALIZE); - glEnable(GL_CULL_FACE); - - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - glPushMatrix (); - - { - 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) * 17); - - gltrackball_rotate (bp->trackball); - - get_rotation (bp->rot, &x, &y, &z, !bp->button_down_p); - glRotatef (x * 360, 1.0, 0.0, 0.0); - glRotatef (y * 360, 0.0, 1.0, 0.0); - glRotatef (z * 360, 0.0, 0.0, 1.0); - } - - mi->polygon_count = 0; - - glScalef (6, 6, 6); - - if (bp->ngears < 14) - glScalef (0.8, 0.8, 0.8); /* make these a little easier to see */ - - if (bp->mode != 0) - { - GLfloat s = (bp->mode == 1 - ? bp->mode_tick / (10 / speed) - : ((10 / speed) - bp->mode_tick + 1) / (10 / speed)); - glScalef (s, s, s); - } - - - { - int i; - for (i = 0; i < bp->ngears; i++) - { - const sphere_gear *s = &bp->gears[i]; - const gear *g = s->g; - - XYZ axis; - XYZ from = { 0, 1, 0 }; - XYZ to = s->axis; - GLfloat angle; - GLfloat off = s->offset; - - /* If an even number of teeth, offset by 1/2 tooth width. */ - if (s->direction > 0 && !(g->nteeth & 1)) - off += 360 / g->nteeth / 2; - - axis = cross_product (from, to); - angle = acos (dot_product (from, to)); - - glPushMatrix(); - glTranslatef (to.x, to.y, to.z); - glRotatef (angle / M_PI * 180, axis.x, axis.y, axis.z); - glRotatef (-90, 1, 0, 0); - glRotatef(180, 0, 0, 1); - glRotatef ((bp->th - off) * g->ratio * s->direction, - 0, 0, 1); - - glCallList (g->dlist); - mi->polygon_count += g->polygons; - glPopMatrix(); - -#if 0 - { /* Draw tooth vectors */ - GLfloat r = 1 - g->z; - XYZ pc; - int pt = parent_tooth (s, &pc); - int t; - glDisable(GL_LIGHTING); - glLineWidth (8); - for (t = 0; t < g->nteeth; t++) - { - XYZ p = tooth_coords (s, t); - XYZ p2; - p2.x = (r * s->axis.x + p.x) / 2; - p2.y = (r * s->axis.y + p.y) / 2; - p2.z = (r * s->axis.z + p.z) / 2; - - if (t == pt) - glColor3f(1,0,1); - else - glColor3f(0,1,1); - glBegin(GL_LINES); - glVertex3f (p.x, p.y, p.z); - glVertex3f (p2.x, p2.y, p2.z); - glEnd(); - } - if (!wire) glEnable(GL_LIGHTING); - glLineWidth (1); - } -#endif - -#if 0 - { /* Draw the parent/child DAG */ - GLfloat s1 = 1.1; - GLfloat s2 = s->parent ? s1 : 1.5; - GLfloat s3 = 1.0; - XYZ p1 = s->axis; - XYZ p2 = s->parent ? s->parent->axis : p1; - glDisable(GL_LIGHTING); - glColor3f(0,0,1); - glBegin(GL_LINES); - glVertex3f (s1 * p1.x, s1 * p1.y, s1 * p1.z); - glVertex3f (s2 * p2.x, s2 * p2.y, s2 * p2.z); - glVertex3f (s1 * p1.x, s1 * p1.y, s1 * p1.z); - glVertex3f (s3 * p1.x, s3 * p1.y, s3 * p1.z); - glEnd(); - if (!wire) glEnable(GL_LIGHTING); - } -#endif - } - - /* We need to draw the fonts in a second pass in order to make - transparency (as a result of anti-aliasing) work properly. - */ - if (do_numbers && bp->mode == 0) - for (i = 0; i < bp->ngears; i++) - { - const sphere_gear *s = &bp->gears[i]; - const gear *g = s->g; - - XYZ axis; - XYZ from = { 0, 1, 0 }; - XYZ to = s->axis; - GLfloat angle; - GLfloat off = s->offset; - - int w, h, j; - char buf[100]; - XCharStruct e; - - /* If an even number of teeth, offset by 1/2 tooth width. */ - if (s->direction > 0 /* && !(g->nteeth & 1) */) - off += 360 / g->nteeth / 2; - - axis = cross_product (from, to); - angle = acos (dot_product (from, to)); - - glPushMatrix(); - glTranslatef(to.x, to.y, to.z); - glRotatef (angle / M_PI * 180, axis.x, axis.y, axis.z); - glRotatef (-90, 1, 0, 0); - glRotatef(180, 0, 0, 1); - glRotatef ((bp->th - off) * g->ratio * s->direction, - 0, 0, 1); - - glDisable (GL_LIGHTING); - glColor3f(1, 1, 0); - glPushMatrix(); - glScalef(0.005, 0.005, 0.005); - sprintf (buf, "%d", i); - texture_string_metrics (bp->font, buf, &e, 0, 0); - w = e.width; - h = e.ascent + e.descent; - glTranslatef (-w/2, -h/2, 0); - print_texture_string (bp->font, buf); - glPopMatrix(); - -# if 1 - for (j = 0; j < g->nteeth; j++) /* Number the teeth */ - { - GLfloat ss = 0.08 * g->r / g->nteeth; - GLfloat r = g->r * 0.88; - GLfloat th = M_PI - (j * M_PI * 2 / g->nteeth + M_PI/2); - - - glPushMatrix(); - glTranslatef (r * cos(th), r * sin(th), -g->z + 0.01); - glScalef(ss, ss, ss); - sprintf (buf, "%d", j + 1); - texture_string_metrics (bp->font, buf, &e, 0, 0); - w = e.width; - h = e.ascent + e.descent; - glTranslatef (-w/2, -h/2, 0); - print_texture_string (bp->font, buf); - glPopMatrix(); - } -# endif - glPopMatrix(); - if (!wire) glEnable(GL_LIGHTING); - } - - bp->th += 0.7 * speed; /* Don't mod this to 360 - causes glitches. */ - } - - if (do_labels && bp->mode == 0) - { - glColor3f (1, 1, 0); - print_texture_label (mi->dpy, bp->font, - mi->xgwa.width, mi->xgwa.height, - 1, bp->desc); - } - - glPopMatrix (); - - if (mi->fps_p) do_fps (mi); - glFinish(); - - glXSwapBuffers(dpy, window); -} - -ENTRYPOINT void -free_geodesic (ModeInfo *mi) -{ - geodesic_configuration *bp = &bps[MI_SCREEN(mi)]; - if (!bp->glx_context) - return; - glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *bp->glx_context); - if (bp->font) free_texture_font (bp->font); - if (bp->colors) free (bp->colors); - if (mi) free_sphere_gears (mi); - if (bp->desc) free (bp->desc); - if (bp->trackball) gltrackball_free (bp->trackball); - if (bp->rot) free_rotator (bp->rot); -} - - -XSCREENSAVER_MODULE_2 ("GeodesicGears", geodesicgears, geodesic) - -#endif /* USE_GL */ |
