X-Git-Url: http://git.hungrycats.org/cgi-bin/gitweb.cgi?p=xscreensaver;a=blobdiff_plain;f=hacks%2Fglx%2Fhexstrut.c;fp=hacks%2Fglx%2Fhexstrut.c;h=f2646099cd79f8603ff761228d38e78afb670e08;hp=0000000000000000000000000000000000000000;hb=d6b0217f2417bd19187f0ebc389d6c5c2233b11c;hpb=aa75c7476aeaa84cf3abc192b376a8b03c325213 diff --git a/hacks/glx/hexstrut.c b/hacks/glx/hexstrut.c new file mode 100644 index 00000000..f2646099 --- /dev/null +++ b/hacks/glx/hexstrut.c @@ -0,0 +1,512 @@ +/* hexstrut, Copyright (c) 2016 Jamie Zawinski + * + * 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. + */ + +#define DEFAULTS "*delay: 30000 \n" \ + "*showFPS: False \n" \ + "*wireframe: False \n" \ + "*count: 20 \n" \ + "*suppressRotationAnimation: True\n" \ + +# define refresh_hexstrut 0 +#undef countof +#define countof(x) (sizeof((x))/sizeof((*x))) + +#include "xlockmore.h" +#include "colors.h" +#include "normals.h" +#include "rotator.h" +#include "gltrackball.h" +#include + +#ifdef USE_GL /* whole file */ + + +#define DEF_SPIN "True" +#define DEF_WANDER "True" +#define DEF_SPEED "1.0" +#define DEF_THICKNESS "0.2" + +#define BELLRAND(n) ((frand((n)) + frand((n)) + frand((n))) / 3) + +typedef struct { double a, o; } LL; /* latitude + longitude */ + +typedef struct triangle triangle; +struct triangle { + XYZ p[3]; + triangle *next; + triangle *neighbors[6]; + GLfloat orot, rot; + int delay, odelay; + int ccolor; +}; + +typedef struct { + GLXContext *glx_context; + rotator *rot; + trackball_state *trackball; + Bool button_down_p; + + int count; + triangle *triangles; + + int ncolors; + XColor *colors; + +} hexstrut_configuration; + +static hexstrut_configuration *bps = NULL; + +static Bool do_spin; +static GLfloat speed; +static Bool do_wander; +static GLfloat thickness; + +static XrmOptionDescRec opts[] = { + { "-spin", ".spin", XrmoptionNoArg, "True" }, + { "+spin", ".spin", XrmoptionNoArg, "False" }, + { "-speed", ".speed", XrmoptionSepArg, 0 }, + { "-wander", ".wander", XrmoptionNoArg, "True" }, + { "+wander", ".wander", XrmoptionNoArg, "False" }, + { "-thickness", ".thickness", 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}, + {&thickness, "thickness", "Thickness", DEF_THICKNESS, t_Float}, +}; + +ENTRYPOINT ModeSpecOpt hexstrut_opts = {countof(opts), opts, countof(vars), vars, NULL}; + + + +/* Add t1 to the neighbor list of t0. */ +static void +link_neighbor (triangle *t0, triangle *t1) +{ + int k; + if (t0 == t1) + return; + for (k = 0; k < countof(t0->neighbors); k++) + { + if (t0->neighbors[k] == t1 || + t0->neighbors[k] == 0) + { + t0->neighbors[k] = t1; + return; + } + } + fprintf (stderr, "too many neighbors\n"); + abort(); +} + + +static void +make_plane (ModeInfo *mi) +{ + hexstrut_configuration *bp = &bps[MI_SCREEN(mi)]; + int n = MI_COUNT(mi) * 2; + GLfloat size = 2.0 / n; + int x, y; + GLfloat w = size; + GLfloat h = size * sqrt(3) / 2; + triangle **grid = (triangle **) calloc (n * n, sizeof(*grid)); + + for (y = 0; y < n; y++) + for (x = 0; x < n; x++) + { + triangle *t; + + t = (triangle *) calloc (1, sizeof(*t)); + t->p[0].x = (x - n/2) * w; + t->p[0].y = (y - n/2) * h; + + if (y & 1) + t->p[0].x += w / 2; + + t->p[1].x = t->p[0].x - w/2; + t->p[2].x = t->p[0].x + w/2; + t->p[1].y = t->p[0].y + h; + t->p[2].y = t->p[0].y + h; + + if (x > 0) + { + triangle *t2 = grid[y * n + (x-1)]; + link_neighbor (t, t2); + link_neighbor (t2, t); + } + if (y > 0) + { + triangle *t2 = grid[(y-1) * n + x]; + link_neighbor (t, t2); + link_neighbor (t2, t); + + if (x < n-1) + { + t2 = grid[(y-1) * n + (x+1)]; + link_neighbor (t, t2); + link_neighbor (t2, t); + } + } + + t->next = bp->triangles; + bp->triangles = t; + grid[y * n + x] = t; + bp->count++; + } + + free (grid); +} + + +static void +tick_triangles (ModeInfo *mi) +{ + hexstrut_configuration *bp = &bps[MI_SCREEN(mi)]; + triangle *t; + GLfloat step = 0.01 + (0.04 * speed); + + if (! (random() % 80)) + { + int n = random() % bp->count; + int i; + for (i = 0, t = bp->triangles; t && i < n; t = t->next, i++) + ; + if (! t->rot) + { + t->rot += step * ((random() & 1) ? 1 : -1); + t->odelay = t->delay = 4; + } + } + + for (t = bp->triangles; t; t = t->next) + { + /* If this triangle is rotating, continue until done. */ + if (t->rot) + { + t->rot += step * (t->rot > 0 ? 1 : -1); + + t->ccolor++; + if (t->ccolor > bp->ncolors) + t->ccolor = 0; + + if (t->rot > 1 || t->rot < -1) + { + t->orot += (t->rot > 1 ? 1 : -1); + t->rot = 0; + } + } + + /* If this triangle's propagation delay hasn't hit zero, decrement it. + When it does, start its neighbors rotating. + */ + if (t->delay) + { + int i; + t->delay--; + if (t->delay == 0) + for (i = 0; i < countof(t->neighbors); i++) + { + if (t->neighbors[i] && + t->neighbors[i]->rot == 0) + { + t->neighbors[i]->rot += step * (t->rot > 0 ? 1 : -1); + t->neighbors[i]->delay = + t->neighbors[i]->odelay = t->odelay; + } + } + } + } +} + + +static void +draw_triangles (ModeInfo *mi) +{ + hexstrut_configuration *bp = &bps[MI_SCREEN(mi)]; + int wire = MI_IS_WIREFRAME(mi); + triangle *t; + GLfloat length = sqrt(3) / 3; + GLfloat t2 = length * thickness / 2; + GLfloat scale; + + { + triangle *t = bp->triangles; + GLfloat X = t->p[0].x - t->p[1].x; + GLfloat Y = t->p[0].y - t->p[1].y; + GLfloat Z = t->p[0].z - t->p[1].z; + scale = sqrt(X*X + Y*Y + Z*Z); + } + + glFrontFace (GL_CCW); + + glBegin (wire ? GL_LINES : GL_QUADS); + + glNormal3f (0, 0, 1); + for (t = bp->triangles; t; t = t->next) + { + int i; + XYZ c; + GLfloat color[4]; + + GLfloat angle = (M_PI * 2 / 3) * t->rot; + GLfloat cr = cos(angle), sr = sin(angle); + + c.x = (t->p[0].x + t->p[1].x + t->p[2].x) / 3; + c.y = (t->p[0].y + t->p[1].y + t->p[2].y) / 3; + c.z = (t->p[0].z + t->p[1].z + t->p[2].z) / 3; + + /* Actually we don't need normals at all, since no lighting. + do_normal (t->p[0].x, t->p[0].y, t->p[0].z, + t->p[1].x, t->p[1].y, t->p[1].z, + t->p[2].x, t->p[2].y, t->p[2].z); + */ + + color[0] = bp->colors[t->ccolor].red / 65535.0; + color[1] = bp->colors[t->ccolor].green / 65535.0; + color[2] = bp->colors[t->ccolor].blue / 65535.0; + color[3] = 1; + + /* Brighter */ + color[0] = color[0] * 0.75 + 0.25; + color[1] = color[1] * 0.75 + 0.25; + color[2] = color[2] * 0.75 + 0.25; + + glColor4fv (color); + glMaterialfv (GL_FRONT, GL_AMBIENT_AND_DIFFUSE, color); + + for (i = 0; i < 3; i++) + { + /* Orient to direction of corner. */ + GLfloat x = t->p[i].x - c.x; + GLfloat y = t->p[i].y - c.y; + GLfloat z = t->p[i].z - c.z; + + GLfloat smc = sr * y - cr * x; + GLfloat spc = cr * y + sr * x; + + GLfloat st2 = t2 * scale / sqrt(x*x + y*y); + GLfloat slength = length * scale / sqrt(x*x + y*y + z*z); + + GLfloat xt2 = spc * st2; + GLfloat yt2 = smc * st2; + GLfloat xlength = c.x - slength * smc; + GLfloat ylength = c.y + slength * spc; + GLfloat zlength = c.z + slength * z; + + if (! wire) + glVertex3f (c.x - xt2, c.y - yt2, c.z); + + glVertex3f (c.x + xt2, c.y + yt2, c.z); + if (wire) + glVertex3f (xlength + xt2, ylength + yt2, zlength); + + if (! wire) + glVertex3f (xlength + xt2, ylength + yt2, zlength); + + glVertex3f (xlength - xt2, ylength - yt2, zlength); + + if (wire) + glVertex3f (c.x - xt2, c.y - yt2, c.z); + + mi->polygon_count++; + } + } + + glEnd(); +} + + +/* Window management, etc + */ +ENTRYPOINT void +reshape_hexstrut (ModeInfo *mi, int width, int height) +{ + GLfloat h = (GLfloat) height / (GLfloat) width; + + glViewport (0, 0, (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); + +# 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 (1/h, 1/h, 1/h); + } +# endif + + glClear(GL_COLOR_BUFFER_BIT); +} + + +ENTRYPOINT Bool +hexstrut_handle_event (ModeInfo *mi, XEvent *event) +{ + hexstrut_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 == '\t') + { + bp->ncolors = 64; + make_smooth_colormap (0, 0, 0, + bp->colors, &bp->ncolors, + False, 0, False); + return True; + } + } + + return False; +} + + +ENTRYPOINT void +init_hexstrut (ModeInfo *mi) +{ + hexstrut_configuration *bp; + + if (!bps) { + bps = (hexstrut_configuration *) + calloc (MI_NUM_SCREENS(mi), sizeof (hexstrut_configuration)); + if (!bps) { + fprintf(stderr, "%s: out of memory\n", progname); + exit(1); + } + } + + bp = &bps[MI_SCREEN(mi)]; + + bp->glx_context = init_GL(mi); + + reshape_hexstrut (mi, MI_WIDTH(mi), MI_HEIGHT(mi)); + + { + double spin_speed = 0.002; + double wander_speed = 0.003; + double spin_accel = 1.0; + + 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, + False); + bp->trackball = gltrackball_init (True); + } + + + /* Let's tilt the scene a little. */ + gltrackball_start (bp->trackball, 500, 500, 1000, 1000); + gltrackball_track (bp->trackball, + 350 + (random() % 300), + 350 + (random() % 300), + 1000, 1000); + + + if (thickness < 0.05) thickness = 0.05; + if (thickness < 0.05) MI_IS_WIREFRAME(mi) = True; + if (thickness > 1.7) thickness = 1.7; + if (speed > 2) speed = 2; + + bp->ncolors = 64; + bp->colors = (XColor *) calloc(bp->ncolors, sizeof(XColor)); + make_smooth_colormap (0, 0, 0, + bp->colors, &bp->ncolors, + False, 0, False); + + make_plane (mi); +} + + +ENTRYPOINT void +draw_hexstrut (ModeInfo *mi) +{ + hexstrut_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)); + + glShadeModel(GL_SMOOTH); + + glDisable(GL_DEPTH_TEST); + glEnable(GL_NORMALIZE); + glDisable(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) * 6, + (y - 0.5) * 6, + (z - 0.5) * 12); + + gltrackball_rotate (bp->trackball); + + get_rotation (bp->rot, &x, &y, &z, !bp->button_down_p); + glRotatef (z * 360, 0.0, 0.0, 1.0); + } + + mi->polygon_count = 0; + + glScalef (30, 30, 30); + + if (! bp->button_down_p) + tick_triangles (mi); + draw_triangles (mi); + + glPopMatrix (); + + if (mi->fps_p) do_fps (mi); + glFinish(); + + glXSwapBuffers(dpy, window); +} + + +ENTRYPOINT void +release_hexstrut (ModeInfo *mi) +{ + hexstrut_configuration *bp = &bps[MI_SCREEN(mi)]; + while (bp->triangles) + { + triangle *t = bp->triangles->next; + free (bp->triangles); + bp->triangles = t; + } +} + +XSCREENSAVER_MODULE ("Hexstrut", hexstrut) + +#endif /* USE_GL */