From d3a98cf6cbc3bd0b9efc570f58e8812c03931c18 Mon Sep 17 00:00:00 2001 From: Simon Rettberg Date: Tue, 16 Oct 2018 10:08:48 +0200 Subject: Original 5.40 --- hacks/glx/jigglypuff.c | 1076 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1076 insertions(+) create mode 100644 hacks/glx/jigglypuff.c (limited to 'hacks/glx/jigglypuff.c') diff --git a/hacks/glx/jigglypuff.c b/hacks/glx/jigglypuff.c new file mode 100644 index 0000000..fea13fd --- /dev/null +++ b/hacks/glx/jigglypuff.c @@ -0,0 +1,1076 @@ +/* jigglypuff - a most, most, unfortunate screensaver. + * + * Copyright (c) 2003 Keith Macleod (kmacleod@primus.ca) + * + * 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 all varieties of obscene, spastic, puffy balls + * orbiting lazily about the screen. More of an accident + * than anything else. + * + * Apologies to anyone who thought they were getting a Pokemon + * out of this. + * + * Of course, if you modify it to do something interesting and/or + * funny, I'd appreciate receiving a copy. + * + * 04/06/2003 - Oops, figured out what was wrong with the sphere + * mapping. I had assumed it was done in model space, + * but of course I was totally wrong... Eye space you + * say? Yup. km + * + * 03/31/2003 - Added chrome to the color options. The mapping + * is anything but 'correct', but it's a pretty good + * effect anyways, as long as the surface is jiggling + * enough that you can't tell. Sure, it seems kind of odd + * that it's reflecting a sky that's obviously not there, + * but who has time to worry about silly details like + * that? Not me, ah rekkin'. km + * + */ + +#ifdef STANDALONE +# define DEFAULTS "*delay: 20000\n" \ + "*showFPS: False\n" \ + "*wireframe: False\n" \ + "*suppressRotationAnimation: True\n" \ + +# define free_jigglypuff 0 +# define release_jigglypuff 0 +# include "xlockmore.h" +#else +# include "xlock.h" +#endif + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "ximage-loader.h" +#include "gltrackball.h" +#include "images/gen/jigglymap_png.h" + +#ifdef USE_GL + + +#define DEF_COLOR "cycle" +#define DEF_SHININESS "100" +#define DEF_COMPLEXITY "2" +#define DEF_SPEED "500" +#define DEF_DISTANCE "100" +#define DEF_HOLD "800" +#define DEF_SPHERISM "75" +#define DEF_DAMPING "500" +#define DEF_RANDOM "True" +#define DEF_TETRA "False" +#define DEF_SPOOKY "0" + +#ifndef max +#define max(a,b) (((a)>(b))?(a):(b)) +#define min(a,b) (((a)<(b))?(a):(b)) +#endif + +/* Why isn't RAND_MAX correct in the first place? */ +#define REAL_RAND_MAX (2.0*(float)RAND_MAX) + +static int spherism; +static int hold; +static int distance; +static int damping; + +static int complexity; +static int speed; + +static int do_tetrahedron; +static int spooky; +static char *color; +static int shininess; + +static int random_parms; + +typedef struct solid solid; + +typedef struct { + float stable_distance; + float hold_strength; + float spherify_strength; + float damping_velocity; + float damping_factor; + + int do_wireframe; + int spooky; + int color_style; + GLint shininess; + GLfloat jiggly_color[4]; + GLfloat color_dir[3]; + + solid *shape; + + trackball_state *trackball; + int button_down; + + float angle; + float axis; + float speed; + + GLXContext *glx_context; +} jigglystruct; + +static jigglystruct *jss = NULL; + +static XrmOptionDescRec opts[] = { + {"-random", ".Jigglypuff.random", XrmoptionNoArg, "true"}, + {"+random", ".Jigglypuff.random", XrmoptionNoArg, "false"}, + {"-tetra", ".Jigglypuff.tetra", XrmoptionNoArg, "true"}, + {"+tetra", ".Jigglypuff.tetra", XrmoptionNoArg, "false"}, + {"-spooky", ".Jigglypuff.spooky", XrmoptionSepArg, "0"}, + {"-color", ".Jigglypuff.color", XrmoptionSepArg, DEF_COLOR}, + {"-shininess", ".Jigglypuff.shininess", XrmoptionSepArg, DEF_SHININESS}, + {"-complexity", ".Jigglypuff.complexity", XrmoptionSepArg, DEF_COMPLEXITY}, + {"-speed", ".Jigglypuff.speed", XrmoptionSepArg, DEF_SPEED}, + {"-spherism", ".Jigglypuff.spherism", XrmoptionSepArg, DEF_SPHERISM}, + {"-hold", ".Jigglypuff.hold", XrmoptionSepArg, DEF_HOLD}, + {"-distance", "Jigglypuff.distance", XrmoptionSepArg, DEF_DISTANCE}, + {"-damping", "Jigglypuff.damping", XrmoptionSepArg, DEF_DAMPING} +}; + +static argtype vars[] = { + {&random_parms, "random", "Random", DEF_RANDOM, t_Bool}, + {&do_tetrahedron, "tetra", "Tetra", DEF_TETRA, t_Bool}, + {&spooky, "spooky", "Spooky", DEF_SPOOKY, t_Int}, + {&color, "color", "Color", DEF_COLOR, t_String}, + {&shininess, "shininess", "Shininess", DEF_SHININESS, t_Int}, + {&complexity, "complexity", "Complexity", DEF_COMPLEXITY, t_Int}, + {&speed, "speed", "Speed", DEF_SPEED, t_Int}, + {&spherism, "spherism", "Spherism", DEF_SPHERISM, t_Int}, + {&hold, "hold", "Hold", DEF_HOLD, t_Int}, + {&distance, "distance", "Distance", DEF_DISTANCE, t_Int}, + {&damping, "damping", "Damping", DEF_DAMPING, t_Int} +}; + +#undef countof +#define countof(x) ((int)(sizeof(x)/sizeof(*(x)))) + +ENTRYPOINT ModeSpecOpt jigglypuff_opts = {countof(opts), opts, countof(vars), vars, NULL}; + +#define COLOR_STYLE_NORMAL 0 +#define COLOR_STYLE_CYCLE 1 +#define COLOR_STYLE_CLOWNBARF 2 +#define COLOR_STYLE_FLOWERBOX 3 +#define COLOR_STYLE_CHROME 4 + +#define CLOWNBARF_NCOLORS 5 + +static const GLfloat clownbarf_colors[CLOWNBARF_NCOLORS][4] = { + {0.7, 0.7, 0.0, 1.0}, + {0.8, 0.1, 0.1, 1.0}, + {0.1, 0.1, 0.8, 1.0}, + {0.9, 0.9, 0.9, 1.0}, + {0.0, 0.0, 0.0, 1.0} +}; + +static const GLfloat flowerbox_colors[4][4] = { + {0.7, 0.7, 0.0, 1.0}, + {0.9, 0.0, 0.0, 1.0}, + {0.0, 0.9, 0.0, 1.0}, + {0.0, 0.0, 0.9, 1.0}, +}; + +# if 0 /* I am not even going to *try* and make this bullshit compile + without warning under gcc -std=c89 -pedantic. -jwz. */ +#ifdef DEBUG +# ifdef __GNUC__ /* GCC style */ +#define _DEBUG(msg, args...) do { \ + fprintf(stderr, "%s : %d : " msg ,__FILE__,__LINE__ ,##args); \ +} while(0) +# else /* C99 standard style */ +#define _DEBUG(msg, ...) do { \ + fprintf(stderr, "%s : %d : " msg ,__FILE__,__LINE__,__VA_ARGS__); \ +} while(0) +# endif +#else +# ifdef __GNUC__ /* GCC style */ +#define _DEBUG(msg, args...) +# else /* C99 standard style */ +#define _DEBUG(msg, ...) +# endif +#endif +#endif /* 0 */ + +/* This is all the half-edge b-rep code (as well as basic geometry) */ +typedef struct face face; +typedef struct edge edge; +typedef struct hedge hedge; +typedef struct vertex vertex; +typedef GLfloat coord; +typedef coord vector[3]; + +struct solid { + face *faces; + edge *edges; + vertex *vertices; +}; + +struct face { + solid *s; + hedge *start; + const GLfloat *color; + face *next; +}; + +struct edge { + solid *s; + hedge *left; + hedge *right; + edge *next; +}; + +struct hedge { + face *f; + edge *e; + vertex *vtx; + hedge *next; + hedge *prev; +}; + +struct vertex { + solid *s; + hedge *h; + vector v; + vector n; + vector f; + vector vel; + vertex *next; +}; + +static inline void vector_init(vector v, coord x, coord y, coord z) +{ + v[0] = x; + v[1] = y; + v[2] = z; +} + +static inline void vector_copy(vector d, vector s) +{ + d[0] = s[0]; + d[1] = s[1]; + d[2] = s[2]; +} + +static inline void vector_add(vector v1, vector v2, vector v) +{ + vector_init(v, v1[0]+v2[0], v1[1]+v2[1], v1[2]+v2[2]); +} + +static inline void vector_add_to(vector v1, vector v2) +{ + v1[0] += v2[0]; + v1[1] += v2[1]; + v1[2] += v2[2]; +} + +static inline void vector_sub(vector v1, vector v2, vector v) +{ + vector_init(v, v1[0]-v2[0], v1[1]-v2[1], v1[2]-v2[2]); +} + +static inline void vector_scale(vector v, coord s) +{ + v[0] *= s; + v[1] *= s; + v[2] *= s; +} + +/* +static inline coord dot(vector v1, vector v2) +{ + return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2]; +} +*/ + +static inline void cross(vector v1, vector v2, vector v) +{ + vector_init(v, + v1[1]*v2[2] - v2[1]*v1[2], + v1[2]*v2[0] - v2[2]*v1[0], + v1[0]*v2[1] - v2[0]*v1[1]); +} + +static inline coord magnitude2(vector v) +{ + return v[0]*v[0] + v[1]*v[1] + v[2]*v[2]; +} + +static inline coord magnitude(vector v) +{ + return sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]); +} + +static inline void normalize(vector v) +{ + coord mag = 1.0/sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]); + + v[0] *= mag; + v[1] *= mag; + v[2] *= mag; +} + +static inline void normalize_to(vector v, coord m) +{ + coord mag = 1.0/sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2])/m; + + v[0] *= mag; + v[1] *= mag; + v[2] *= mag; +} + +static inline void midpoint(vector v1, vector v2, vector v) +{ + vector_init(v, + v1[0] + 0.5 * (v2[0] - v1[0]), + v1[1] + 0.5 * (v2[1] - v1[1]), + v1[2] + 0.5 * (v2[2] - v1[2])); +} + +static inline hedge *partner(hedge *h) { + if(!h->e) + return NULL; + if(h == h->e->left) { + return h->e->right; + } + else if(h == h->e->right) { + return h->e->left; + } + else { +/* _DEBUG("Inconsistent edge detected. Presumably, this is a bug. Exiting.\n", NULL); */ + exit(-1); + } +} + +static vertex *vertex_new(solid *s, vector v) +{ + vertex *vtx = (vertex*)malloc(sizeof(vertex)); + + if(!vtx) + return NULL; + vtx->s = s; + vtx->next = s->vertices; + s->vertices = vtx; + vector_copy(vtx->v, v); + vector_init(vtx->f, 0, 0, 0); + vector_init(vtx->vel, 0, 0, 0); + return vtx; +} + +/* insert a new halfedge after hafter. this is low-level, + * i.e. it is a helper for the split_* functions, which + * maintain the consistency of the solid. + */ +static hedge *hedge_new(hedge *hafter, vertex *vtx) +{ + hedge *h = (hedge*)malloc(sizeof(hedge)); + + if(!h) { +/* _DEBUG("Out of memory in hedge_new()\n",NULL); */ + return NULL; + } + h->f = hafter->f; + h->vtx = vtx; + h->e = NULL; + h->prev = hafter; + h->next = hafter->next; + hafter->next = h; + h->next->prev = h; + return h; +} + +static edge *edge_new(solid *s) +{ + edge *e = (edge*)malloc(sizeof(edge)); + if(!e) { +/* _DEBUG("Out of memory in edge_new()\n",NULL);*/ + exit(-1); + } + e->next = s->edges; + s->edges = e; + e-> s = s; + e->left = e->right = NULL; + return e; +} + +static face *face_new(solid *s, hedge *h) +{ + face *f = (face*)malloc(sizeof(face)); + if(!f) { +/* _DEBUG("Out of memory in face_new()",NULL);*/ + exit(-1); + } + f->s = s; + f->start = h; + f->next = s->faces; + s->faces = f; + return f; +} + +/* split vertex vtx, creating a new edge after v on f + * that goes to a new vertex at v, adjoining whatever + * face is on the other side of the halfedge attached to + * v on f. + * Assumptions: + * there are at least 2 faces. + * partner(h)->next->vtx == vtx + * Post-assumptions: + * the new halfedge will be inserted AFTER the indicated + * halfedge. This means that f->start is guaranteed not to + * change. + * the vertex returned will have h==. + */ + +static vertex *vertex_split(hedge *h, vector v) +{ + hedge *h2, *hn1, *hn2; + vertex *vtxn; + edge *en; + face *f1; + + f1 = h->f; + h2 = partner(h); + + vtxn = vertex_new(f1->s, v); + hn1 = hedge_new(h, vtxn); + vtxn->h = hn1; + hn2 = hedge_new(h2, vtxn); + hn2->e = h->e; + + if(h2->e->left == h2) + h2->e->left = hn2; + else + h2->e->right = hn2; + + en = edge_new(f1->s); + en->left = hn1; + en->right = h2; + hn1->e = en; + h2->e = en; + return vtxn; +} + +static face *face_split(face *f, hedge *h1, hedge *h2) +{ + hedge *hn1, *hn2, *tmp; + edge *en; + face *fn; + + if(h1->f != f || h2->f != f) { +/* _DEBUG("Whoah, cap'n, yer usin' a bad halfedge!\n",NULL);*/ + exit(-1); + } + if(h1 == h2) { +/* _DEBUG("Trying to split a face at a single vertex\n",NULL);*/ + exit(-1); + } + /* close the loops */ + h1->prev->next = h2; + h2->prev->next = h1; + tmp = h1->prev; + h1->prev = h2->prev; + h2->prev = tmp; + /* insert halfedges & create edge */ + hn1 = hedge_new(h2->prev, h1->vtx); + hn2 = hedge_new(h1->prev, h2->vtx); + en = edge_new(f->s); + en->left = hn1; + en->right = hn2; + hn1->e = en; + hn2->e = en; + + /* make the new face, first find out which hedge is contained + * in the original face, then start the new face at the other */ + tmp = f->start; + while(tmp != h1 && tmp != h2) + tmp = tmp->next; + tmp = (tmp == h1) ? h2 : h1 ; + fn = face_new(f->s, tmp); + do { + tmp->f = fn; + tmp = tmp->next; + } while(tmp != fn->start); + fn->color = f->color; + return fn; +} + +static solid *solid_new(vector where) +{ + solid *s = (solid*)malloc(sizeof(solid)); + face *f1, *f2; + edge *e; + vertex *vtx; + hedge *h1,*h2; + + s->faces = NULL; + s->edges = NULL; + s->vertices = NULL; + + h1 = (hedge*)malloc(sizeof(hedge)); + h2 = (hedge*)malloc(sizeof(hedge)); + h1->next = h1->prev = h1; + h2->next = h2->prev = h2; + + vtx = vertex_new(s, where); + vtx->h = h1; + h1->vtx = vtx; + h2->vtx = vtx; + + e = edge_new(s); + e->left = h1; + e->right = h2; + h1->e = e; + h2->e = e; + + f1 = face_new(s, h1); + f2 = face_new(s, h2); + h1->f = f1; + h2->f = f2; + + return s; +} + +/* This is all the code directly related to constructing the jigglypuff */ +static void face_tessel2(face *f) +{ + hedge *h1=f->start->prev, *h2=f->start->next; + + if(h1->next == h1) + return; + while(h2 != h1 && h2->next != h1) { + f = face_split(f, h1, h2); + h1 = f->start; + h2 = f->start->next->next; + } +} + +/* This will only work with solids composed entirely of + * triangular faces. It first add a vertex to the middle + * of each edge, then walks the faces, connecting the + * dots. + * I'm abusing the fact that new faces and edges are always + * added at the head of the list. If that ever changes, + * this is borked. + */ +static void solid_tesselate(solid *s) +{ + edge *e = s->edges; + face *f = s->faces; + + while(e) { + vector v; + midpoint(e->left->vtx->v, e->right->vtx->v, v); + vertex_split(e->left, v); + e = e->next; + } + while(f) { + face_tessel2(f); + f=f->next; + } +} + +static void solid_spherify(solid * s, coord size) +{ + vertex *vtx = s->vertices; + + while(vtx) { + normalize_to(vtx->v, size); + vtx = vtx->next; + } +} + +static solid *tetrahedron(jigglystruct *js) +{ + solid *s; + vertex *vtx; + vector v; + hedge *h; + face *f; + int i; + + vector_init(v, 1, 1, 1); + s = solid_new(v); + vector_init(v, -1, -1, 1); + h = s->faces->start; + vtx = vertex_split(h, v); + vector_init(v, -1, 1, -1); + vtx = vertex_split(vtx->h, v); + h = vtx->h; + f = face_split(s->faces, h, h->prev); + vector_init(v, 1, -1, -1); + vertex_split(f->start, v); + f = s->faces->next->next; + h = f->start; + face_split(f, h, h->next->next); + + if(js->color_style == COLOR_STYLE_FLOWERBOX) { + f = s->faces; + for(i=0; i<4; i++) { + f->color = flowerbox_colors[i]; + f = f->next; + } + } + + return s; +} + +static solid *tesselated_tetrahedron(coord size, int iter, jigglystruct *js) { + solid *s = tetrahedron(js); + int i; + + for(i=0; ifaces; + while(f) { + f->color = clownbarf_colors[random() % CLOWNBARF_NCOLORS]; + f = f->next; + } +} + +/* Here be the rendering code */ + +static inline void vertex_calcnormal(vertex *vtx, jigglystruct *js) +{ + hedge *start = vtx->h, *h=start; + + vector_init(vtx->n, 0, 0, 0); + do { + vector u, v, norm; + vector_sub(h->prev->vtx->v, vtx->v, u); + vector_sub(h->next->vtx->v, vtx->v, v); + cross(u, v, norm); + vector_add_to(vtx->n, norm); + h = partner(h)->next; + } while(h != start); + if(!js->spooky) + normalize(vtx->n); + else + vector_scale(vtx->n, js->spooky); +} + +static inline void vertex_render(vertex *vtx, jigglystruct *js) +{ + glNormal3fv(vtx->n); + glVertex3fv(vtx->v); +} + +/* This can be optimized somewhat due to the fact that all + * the faces are triangles. I haven't actually tested to + * see what the cost is of calling glBegin/glEnd for each + * triangle. + */ +static inline int face_render(face *f, jigglystruct *js) +{ + hedge *h1, *h2, *hend; + int polys = 0; + + h1 = f->start; + hend = h1->prev; + h2 = h1->next; + + if(js->color_style == COLOR_STYLE_FLOWERBOX || + js->color_style == COLOR_STYLE_CLOWNBARF) + glColor4fv(f->color); + glBegin(GL_TRIANGLES); + while(h1 != hend && h2 !=hend) { + vertex_render(h1->vtx, js); + vertex_render(h2->vtx, js); + vertex_render(hend->vtx, js); + h1 = h2; + h2 = h1->next; + polys++; + } + glEnd(); + return polys; +} + +static int jigglypuff_render(jigglystruct *js) +{ + int polys = 0; + face *f = js->shape->faces; + vertex *vtx = js->shape->vertices; + + while(vtx) { + vertex_calcnormal(vtx, js); + vtx = vtx->next; + } + while(f) { + polys += face_render(f, js); + f=f->next; + } + return polys; +} + +/* This is the jiggling code */ + +/* stable distance when subdivs == 4 */ +#define STABLE_DISTANCE 0.088388347648 + +static void update_shape(jigglystruct *js) +{ + vertex *vtx = js->shape->vertices; + edge *e = js->shape->edges; + vector zero; + + vector_init(zero, 0, 0, 0); + + /* sum all the vertex-vertex forces */ + while(e) { + vector f; + coord mag; + vector_sub(e->left->vtx->v, e->right->vtx->v, f); + mag = js->stable_distance - magnitude(f); + vector_scale(f, mag); + vector_add_to(e->left->vtx->f, f); + vector_sub(zero, f, f); + vector_add_to(e->right->vtx->f, f); + e = e->next; + } + + /* scale back the v-v force and add the spherical force + * then add the result to the vertex velocity, damping + * if necessary. Finally, move the vertex */ + while(vtx) { + coord mag; + vector to_sphere; + vector_scale(vtx->f, js->hold_strength); + vector_copy(to_sphere, vtx->v); + mag = 1 - magnitude(to_sphere); + vector_scale(to_sphere, mag * js->spherify_strength); + vector_add_to(vtx->f, to_sphere); + vector_add_to(vtx->vel, vtx->f); + vector_init(vtx->f, 0, 0, 0); + mag = magnitude2(vtx->vel); + if(mag > js->damping_velocity) + vector_scale(vtx->vel, js->damping_factor); + vector_add_to(vtx->v, vtx->vel); + vtx = vtx->next; + } +} + +/* These are the various initialization routines */ + +static void init_texture(ModeInfo *mi) +{ + XImage *img = image_data_to_ximage(mi->dpy, mi->xgwa.visual, + jigglymap_png, sizeof(jigglymap_png)); + + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, + img->width, img->height, 0, GL_RGBA, + GL_UNSIGNED_BYTE, img->data); + + XDestroyImage(img); +} + +static void setup_opengl(ModeInfo *mi, jigglystruct *js) +{ + const GLfloat lpos0[4] = {-12, 8, 12, 0}; + const GLfloat lpos1[4] = {7, -5, 0, 0}; + const GLfloat lcol0[4] = {0.7f, 0.7f, 0.65f, 1}; + const GLfloat lcol1[4] = {0.3f, 0.2f, 0.1f, 1}; + const GLfloat scolor[4]= {0.9f, 0.9f, 0.9f, 0.5f}; + + glDrawBuffer(GL_BACK); + glShadeModel(GL_SMOOTH); + glEnable(GL_DEPTH_TEST); + + if(js->do_wireframe) { + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + } + else { + glCullFace(GL_BACK); + glFrontFace(GL_CW); + glEnable(GL_CULL_FACE); + } + + if(js->color_style != COLOR_STYLE_CHROME) { + glEnable(GL_LIGHTING); + glEnable(GL_LIGHT0); + glEnable(GL_LIGHT1); + + glLightfv(GL_LIGHT0, GL_POSITION, lpos0); + glLightfv(GL_LIGHT1, GL_POSITION, lpos1); + glLightfv(GL_LIGHT0, GL_DIFFUSE, lcol0); + glLightfv(GL_LIGHT1, GL_DIFFUSE, lcol1); + + glEnable(GL_COLOR_MATERIAL); + glColor4fv(js->jiggly_color); + + glMaterialfv(GL_FRONT, GL_SPECULAR, scolor); + glMateriali(GL_FRONT, GL_SHININESS, js->shininess); + } + else { /* chrome */ + init_texture(mi); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); + glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); + glEnable(GL_TEXTURE_GEN_S); + glEnable(GL_TEXTURE_GEN_T); + glEnable(GL_TEXTURE_2D); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + } +} + +static int parse_color(jigglystruct *js) +{ + unsigned int r, g, b; + if(!strcmp(color, "clownbarf")) { + js->color_style = COLOR_STYLE_CLOWNBARF; + return 1; + } + else if(!strcmp(color, "flowerbox")) { + js->color_style = COLOR_STYLE_FLOWERBOX; + return 1; + } +# ifndef HAVE_JWZGLES /* SPHERE_MAP unimplemented */ + else if(!strcmp(color, "chrome")) { + js->color_style = COLOR_STYLE_CHROME; + return 1; + } +# endif + else if(!strcmp(color, "cycle")) { + js->color_style = COLOR_STYLE_CYCLE; + js->jiggly_color[0] = ((float)random()) / REAL_RAND_MAX * 0.7 + 0.3; + js->jiggly_color[1] = ((float)random()) / REAL_RAND_MAX * 0.7 + 0.3; + js->jiggly_color[2] = ((float)random()) / REAL_RAND_MAX * 0.7 + 0.3; + js->jiggly_color[3] = 1.0f; + js->color_dir[0] = ((float)random()) / REAL_RAND_MAX / 100.0; + js->color_dir[1] = ((float)random()) / REAL_RAND_MAX / 100.0; + js->color_dir[2] = ((float)random()) / REAL_RAND_MAX / 100.0; + return 1; + } + else + js->color_style = 0; + if(strlen(color) != 7) + return 0; + if(sscanf(color,"#%02x%02x%02x", &r, &g, &b) != 3) { + return 0; + } + js->jiggly_color[0] = ((float)r)/255; + js->jiggly_color[1] = ((float)g)/255; + js->jiggly_color[2] = ((float)b)/255; + js->jiggly_color[3] = 1.0f; + + return 1; +} + +static void randomize_parameters(jigglystruct *js) { + do_tetrahedron = random() & 1; +# ifndef HAVE_JWZGLES /* #### glPolygonMode other than GL_FILL unimplemented */ + js->do_wireframe = !(random() & 3); +# endif + js->color_style = random() % 5; +# ifdef HAVE_JWZGLES /* #### SPHERE_MAP unimplemented */ + while (js->color_style == COLOR_STYLE_CHROME) + js->color_style = random() % 5;; +# endif + if(js->color_style == COLOR_STYLE_NORMAL + || js->color_style == COLOR_STYLE_CYCLE) { + js->jiggly_color[0] = ((float)random()) / REAL_RAND_MAX * 0.5 + 0.5; + js->jiggly_color[1] = ((float)random()) / REAL_RAND_MAX * 0.5 + 0.5; + js->jiggly_color[2] = ((float)random()) / REAL_RAND_MAX * 0.5 + 0.5; + js->jiggly_color[3] = 1.0f; + if(js->color_style == COLOR_STYLE_CYCLE) { + js->color_dir[0] = ((float)random()) / REAL_RAND_MAX / 100.0; + js->color_dir[1] = ((float)random()) / REAL_RAND_MAX / 100.0; + js->color_dir[2] = ((float)random()) / REAL_RAND_MAX / 100.0; + } + } + if((js->color_style != COLOR_STYLE_CHROME) && (random() & 1)) + js->spooky = (random() % 6) + 4; + else + js->spooky = 0; + js->shininess = random() % 200; + speed = (random() % 700) + 50; + /* It' kind of dull if this is too high when it starts as a sphere */ + spherism = do_tetrahedron ? (random() % 500) + 20 : (random() % 100) + 10; + hold = (random() % 800) + 100; + distance = (random() % 500) + 100; + damping = (random() % 800) + 50; +} + +static void calculate_parameters(jigglystruct *js, int subdivs) { + /* try to compensate for the inherent instability at + * low complexity. */ + float dist_factor = (subdivs == 6) ? 2 : (subdivs == 5) ? 1 : 0.5; + + js->stable_distance = ((float)distance / 500.0) + * (STABLE_DISTANCE / dist_factor); + js->hold_strength = (float)hold / 10000.0; + js->spherify_strength = (float)spherism / 10000.0; + js->damping_velocity = (float)damping / 100000.0; + js->damping_factor = + 0.001/max(js->hold_strength, js->spherify_strength); + + js->speed = (float)speed / 1000.0; +} + +/* The screenhack related functions begin here */ + +ENTRYPOINT Bool jigglypuff_handle_event(ModeInfo *mi, XEvent *event) +{ + jigglystruct *js = &jss[MI_SCREEN(mi)]; + + if (gltrackball_event_handler (event, js->trackball, + MI_WIDTH (mi), MI_HEIGHT (mi), + &js->button_down)) + return True; + + return False; +} + +ENTRYPOINT void reshape_jigglypuff(ModeInfo *mi, int width, int height) +{ + double 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, width, height); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glFrustum(-0.5*(1/h), 0.5*(1/h), -0.5, 0.5, 1, 20); +} + +ENTRYPOINT void draw_jigglypuff(ModeInfo *mi) +{ + jigglystruct *js = &jss[MI_SCREEN(mi)]; + + glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(js->glx_context)); + + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glTranslatef(0,0,-10); + + +# ifdef HAVE_MOBILE /* Keep it the same relative size when rotated. */ + { + GLfloat h = MI_HEIGHT(mi) / (GLfloat) MI_WIDTH(mi); + int o = (int) current_device_rotation(); + if (o != 0 && o != 180 && o != -180) + glScalef (1/h, 1/h, 1/h); + } +# endif + + glRotatef(js->angle, sin(js->axis), cos(js->axis), -sin(js->axis)); + glTranslatef(0, 0, 5); + if(!(js->button_down)) { + if((js->angle += js->speed) >= 360.0f ) { + js->angle -= 360.0f; + } + if((js->axis+=0.01f) >= 2*M_PI ) { + js->axis -= 2*M_PI; + } + } + + gltrackball_rotate(js->trackball); + + if(js->color_style == COLOR_STYLE_CYCLE) { + int i; + vector_add(js->jiggly_color, js->color_dir, js->jiggly_color); + + for(i=0; i<3; i++) { + if(js->jiggly_color[i] > 1.0 || js->jiggly_color[i] < 0.3) { + js->color_dir[i] = (-js->color_dir[i]); + js->jiggly_color[i] += js->color_dir[i]; + } + } + glColor4fv(js->jiggly_color); + } + + mi->polygon_count = jigglypuff_render(js); + if(MI_IS_FPS(mi)) + do_fps(mi); + glFinish(); + update_shape(js); + glXSwapBuffers(MI_DISPLAY(mi), MI_WINDOW(mi)); +} + +ENTRYPOINT void init_jigglypuff(ModeInfo *mi) +{ + jigglystruct *js; + int subdivs; + + MI_INIT(mi, jss); + + js = &jss[MI_SCREEN(mi)]; + + js->do_wireframe = MI_IS_WIREFRAME(mi); +# ifdef HAVE_JWZGLES + js->do_wireframe = 0; /* GL_LINE unimplemented */ +# endif + + js->shininess = shininess; + + subdivs = (complexity==1) ? 4 : (complexity==2) ? 5 + : (complexity==3) ? 6 : 5; + + js->spooky = spooky << (subdivs-3); + + if(!parse_color(js)) { + fprintf(stderr, "%s: Bad color specification: '%s'.\n", progname, color); + exit(-1); + } + + if(random_parms) + randomize_parameters(js); + + js->angle = frand(180); + js->axis = frand(M_PI); + + js->shape = tesselated_tetrahedron(1, subdivs, js); + + if(!do_tetrahedron) + solid_spherify(js->shape, 1); + + if(js->color_style == COLOR_STYLE_CLOWNBARF) + clownbarf_colorize(js->shape); + + calculate_parameters(js, subdivs); + + if((js->glx_context = init_GL(mi)) != NULL) { + glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(js->glx_context)); + setup_opengl(mi, js); + reshape_jigglypuff(mi, MI_WIDTH(mi), MI_HEIGHT(mi)); + } + else { + MI_CLEARWINDOW(mi); + } + js->trackball = gltrackball_init(True); +/* _DEBUG("distance : %f\nhold : %f\nspherify : %f\ndamping : %f\ndfact : %f\n", + js->stable_distance, js->hold_strength, js->spherify_strength, + js->damping_velocity, js->damping_factor); + _DEBUG("wire : %d\nspooky : %d\nstyle : %d\nshininess : %d\n", + js->do_wireframe, js->spooky, js->color_style, js->shininess);*/ +} + +XSCREENSAVER_MODULE ("JigglyPuff", jigglypuff) + +#endif /* USE_GL */ + +/* This is the end of the file */ -- cgit v1.2.3-55-g7522