diff options
author | Simon Rettberg | 2018-10-16 10:08:48 +0200 |
---|---|---|
committer | Simon Rettberg | 2018-10-16 10:08:48 +0200 |
commit | d3a98cf6cbc3bd0b9efc570f58e8812c03931c18 (patch) | |
tree | cbddf8e50f35a9c6e878a5bfe3c6d625d99e12ba /hacks/glx/glknots.c | |
download | xscreensaver-d3a98cf6cbc3bd0b9efc570f58e8812c03931c18.tar.gz xscreensaver-d3a98cf6cbc3bd0b9efc570f58e8812c03931c18.tar.xz xscreensaver-d3a98cf6cbc3bd0b9efc570f58e8812c03931c18.zip |
Original 5.40
Diffstat (limited to 'hacks/glx/glknots.c')
-rw-r--r-- | hacks/glx/glknots.c | 445 |
1 files changed, 445 insertions, 0 deletions
diff --git a/hacks/glx/glknots.c b/hacks/glx/glknots.c new file mode 100644 index 0000000..730cadb --- /dev/null +++ b/hacks/glx/glknots.c @@ -0,0 +1,445 @@ +/* glknots, Copyright (c) 2003-2014 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. + * + * Generates some 3D knots (closed loops). + * Inspired by Paul Bourke <pbourke@swin.edu.au> at + * http://astronomy.swin.edu.au/~pbourke/curves/knot/ + */ + +#define DEFAULTS "*delay: 30000 \n" \ + "*showFPS: False \n" \ + "*wireframe: False \n" \ + "*suppressRotationAnimation: True\n" \ + +# define free_knot 0 +# define release_knot 0 +#undef countof +#define countof(x) (sizeof((x))/sizeof((*x))) + +#include "xlockmore.h" +#include "colors.h" +#include "tube.h" +#include "rotator.h" +#include "gltrackball.h" +#include <ctype.h> + +#ifdef USE_GL /* whole file */ + +#define DEF_SPIN "XYZ" +#define DEF_WANDER "True" +#define DEF_SPEED "1.0" +#define DEF_THICKNESS "0.3" +#define DEF_SEGMENTS "800" +#define DEF_DURATION "8" + +typedef struct { + GLXContext *glx_context; + rotator *rot; + trackball_state *trackball; + Bool button_down_p; + + GLuint knot_list; + + int ncolors; + XColor *colors; + int ccolor; + + int mode; /* 0 = normal, 1 = out, 2 = in */ + int mode_tick; + Bool clear_p; + + time_t last_time; + int draw_tick; + +} knot_configuration; + +static knot_configuration *bps = NULL; + +static char *do_spin; +static GLfloat speed; +static Bool do_wander; +static GLfloat thickness; +static unsigned int segments; +static int duration; + +static XrmOptionDescRec opts[] = { + { "-spin", ".spin", XrmoptionSepArg, 0 }, + { "+spin", ".spin", XrmoptionNoArg, "" }, + { "-wander", ".wander", XrmoptionNoArg, "True" }, + { "+wander", ".wander", XrmoptionNoArg, "False" }, + { "-speed", ".speed", XrmoptionSepArg, 0 }, + { "-thickness", ".thickness", XrmoptionSepArg, 0 }, + { "-segments", ".segments", XrmoptionSepArg, 0 }, + { "-duration", ".duration", XrmoptionSepArg, 0 }, +}; + +static argtype vars[] = { + {&do_spin, "spin", "Spin", DEF_SPIN, t_String}, + {&do_wander, "wander", "Wander", DEF_WANDER, t_Bool}, + {&speed, "speed", "Speed", DEF_SPEED, t_Float}, + {&thickness, "thickness", "Thickness", DEF_THICKNESS, t_Float}, + {&segments, "segments", "Segments", DEF_SEGMENTS, t_Int}, + {&duration, "duration", "Duration", DEF_DURATION, t_Int}, +}; + +ENTRYPOINT ModeSpecOpt knot_opts = {countof(opts), opts, countof(vars), vars, NULL}; + + +static void +make_knot (ModeInfo *mi) +{ + int wire = MI_IS_WIREFRAME(mi); + + GLfloat diam = (4 * thickness); + int faces = (wire ? 3 : 6); + + unsigned int i; + double x, y, z, ox=0, oy=0, oz=0; + double mu; + + double p[9]; + + Bool blobby_p = (0 == (random() % 5)); + Bool type = (random() % 2); + + for (i = 0; i < countof(p); i++) + { + p[i] = 1 + (random() % 4); + if (! (random() % 3)) + p[i] += (random() % 5); + } + + if (type == 1) + { + p[0] += 4; + p[1] *= ((p[0] + p[0]) / 10); + blobby_p = False; + } + + mi->polygon_count = 0; + + for (i = 0; i <= segments; i++) + { + if (type == 0) + { + mu = i * (M_PI * 2) / segments; + x = 10 * (cos(mu) + cos(p[0]*mu)) + cos(p[1]*mu) + cos(p[2]*mu); + y = 6 * sin(mu) + 10 * sin(p[3]*mu); + z = 16 * sin(p[4]*mu) * sin(p[5]*mu/2) + p[6]*sin(p[7]*mu) - + 2 * sin(p[8]*mu); + } + else if (type == 1) + { + mu = i * (M_PI * 2) * p[0] / (double) segments; + x = 10 * cos(mu) * (1 + cos(p[1] * mu/ p[0]) / 2.0); + y = 25 * sin(p[1] * mu / p[0]) / 2.0; + z = 10 * sin(mu) * (1 + cos(p[1] * mu/ p[0]) / 2.0); + } + else + abort(); + + if (i != 0) + { + GLfloat dist = sqrt ((x-ox)*(x-ox) + + (y-oy)*(y-oy) + + (z-oz)*(z-oz)); + GLfloat di; + if (!blobby_p) + di = diam; + else + { + di = dist * (segments / 500.0); + di = (di * di * 3); + } + + mi->polygon_count += tube (ox, oy, oz, + x, y, z, + di, dist/3, + faces, True, wire, wire); + } + + ox = x; + oy = y; + oz = z; + } +} + + +/* Window management, etc + */ +ENTRYPOINT void +reshape_knot (ModeInfo *mi, int width, int height) +{ + 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; + } + + 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); + +# 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); +} + + +static void +new_knot (ModeInfo *mi) +{ + knot_configuration *bp = &bps[MI_SCREEN(mi)]; + int i; + + bp->clear_p = !!(random() % 15); + + bp->ncolors = 128; + bp->colors = (XColor *) calloc(bp->ncolors, sizeof(XColor)); + make_smooth_colormap (0, 0, 0, + bp->colors, &bp->ncolors, + False, 0, False); + + for (i = 0; i < bp->ncolors; i++) + { + /* make colors twice as bright */ + bp->colors[i].red = (bp->colors[i].red >> 2) + 0x7FFF; + bp->colors[i].green = (bp->colors[i].green >> 2) + 0x7FFF; + bp->colors[i].blue = (bp->colors[i].blue >> 2) + 0x7FFF; + } + + glNewList (bp->knot_list, GL_COMPILE); + make_knot (mi); + glEndList (); +} + + +ENTRYPOINT Bool +knot_handle_event (ModeInfo *mi, XEvent *event) +{ + knot_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 (screenhack_event_helper (MI_DISPLAY(mi), MI_WINDOW(mi), event)) + { + bp->last_time = 1; + return True; + } + + return False; +} + + + +ENTRYPOINT void +init_knot (ModeInfo *mi) +{ + knot_configuration *bp; + int wire = MI_IS_WIREFRAME(mi); + + MI_INIT (mi, bps); + + bp = &bps[MI_SCREEN(mi)]; + + bp->glx_context = init_GL(mi); + + if (thickness <= 0) thickness = 0.001; + else if (thickness > 1) thickness = 1; + + if (segments < 10) segments = 10; + + reshape_knot (mi, MI_WIDTH(mi), MI_HEIGHT(mi)); + + if (!wire) + { + GLfloat pos[4] = {1.0, 1.0, 1.0, 0.0}; + GLfloat amb[4] = {0.0, 0.0, 0.0, 1.0}; + GLfloat dif[4] = {1.0, 1.0, 1.0, 1.0}; + GLfloat spc[4] = {0.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); + } + + { + Bool spinx=False, spiny=False, spinz=False; + double spin_speed = 2.0; + double wander_speed = 0.05; + double spin_accel = 0.2; + + char *s = do_spin; + while (*s) + { + if (*s == 'x' || *s == 'X') spinx = True; + else if (*s == 'y' || *s == 'Y') spiny = True; + else if (*s == 'z' || *s == 'Z') 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 (spinx ? spin_speed : 0, + spiny ? spin_speed : 0, + spinz ? spin_speed : 0, + spin_accel, + do_wander ? wander_speed : 0, + (spinx && spiny && spinz)); + bp->trackball = gltrackball_init (True); + } + + bp->knot_list = glGenLists (1); + new_knot(mi); + + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); +} + + +ENTRYPOINT void +draw_knot (ModeInfo *mi) +{ + knot_configuration *bp = &bps[MI_SCREEN(mi)]; + Display *dpy = MI_DISPLAY(mi); + Window window = MI_WINDOW(mi); + + GLfloat bcolor[4] = {0.0, 0.0, 0.0, 1.0}; + GLfloat bspec[4] = {1.0, 1.0, 1.0, 1.0}; + GLfloat bshiny = 128.0; + + if (!bp->glx_context) + return; + + glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(bp->glx_context)); + + if (bp->mode == 0) + { + if (bp->draw_tick++ > 10) + { + time_t now = time((time_t *) 0); + if (bp->last_time == 0) bp->last_time = now; + bp->draw_tick = 0; + if (!bp->button_down_p && + now - bp->last_time >= duration) + { + bp->mode = 1; /* go out */ + bp->mode_tick = 10 / speed; + bp->last_time = now; + } + } + } + else if (bp->mode == 1) /* out */ + { + if (--bp->mode_tick <= 0) + { + new_knot (mi); + bp->mode_tick = 10 / speed; + bp->mode = 2; /* go in */ + } + } + else if (bp->mode == 2) /* in */ + { + if (--bp->mode_tick <= 0) + bp->mode = 0; /* normal */ + } + else + abort(); + + glShadeModel(GL_SMOOTH); + + glEnable(GL_DEPTH_TEST); + glEnable(GL_NORMALIZE); + glEnable(GL_CULL_FACE); + + if (bp->clear_p) + 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) * 15); + + 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); + } + + bcolor[0] = bp->colors[bp->ccolor].red / 65536.0; + bcolor[1] = bp->colors[bp->ccolor].green / 65536.0; + bcolor[2] = bp->colors[bp->ccolor].blue / 65536.0; + bp->ccolor++; + if (bp->ccolor >= bp->ncolors) bp->ccolor = 0; + + glMaterialfv (GL_FRONT, GL_SPECULAR, bspec); + glMateriali (GL_FRONT, GL_SHININESS, bshiny); + glMaterialfv (GL_FRONT, GL_AMBIENT_AND_DIFFUSE, bcolor); + + glScalef(0.25, 0.25, 0.25); + + 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); + } + + glCallList (bp->knot_list); + + glPopMatrix (); + + if (mi->fps_p) do_fps (mi); + glFinish(); + + glXSwapBuffers(dpy, window); +} + +XSCREENSAVER_MODULE_2 ("GLKnots", glknots, knot) + +#endif /* USE_GL */ |