X-Git-Url: http://git.hungrycats.org/cgi-bin/gitweb.cgi?p=xscreensaver;a=blobdiff_plain;f=hacks%2Fglx%2Fjigglypuff.c;h=bc20c44279c57bca3af7e2bdb2d6a25dc3507f12;hp=ba36ecf893d5ef27d085ce2a9b5fdce2ddcfd6cf;hb=6cee540bdbb571485cd5e519f89f389faebd0495;hpb=40eacb5812ef7c0e3374fb139afbb4f5bc8bbfb5 diff --git a/hacks/glx/jigglypuff.c b/hacks/glx/jigglypuff.c index ba36ecf8..bc20c442 100644 --- a/hacks/glx/jigglypuff.c +++ b/hacks/glx/jigglypuff.c @@ -1,4 +1,4 @@ -/* jigglypuff - the least colorful screensaver you'll ever see +/* jigglypuff - a most, most, unfortunate screensaver. * * Copyright (c) 2003 Keith Macleod (kmacleod@primus.ca) * @@ -14,28 +14,59 @@ * orbiting lazily about the screen. More of an accident * than anything else. * - * This could either use more options, or less options and - * more randomness. - * * 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 + * */ #include #ifdef STANDALONE -# define PROGCLASS "Jigglypuff" -# define HACK_INIT init_jigglypuff -# define HACK_DRAW draw_jigglypuff -# define HACK_RESHAPE reshape_jigglypuff -# define jigglypuff_opts xlockmore_opts -# define DEFAULTS "*random: True\n" \ - "*delay: 20000\n" \ - "*showFPS: False\n" \ - "wireframe: False\n" +# define PROGCLASS "Jigglypuff" +# define HACK_INIT init_jigglypuff +# define HACK_DRAW draw_jigglypuff +# define HACK_RESHAPE reshape_jigglypuff +# define HACK_HANDLE_EVENT jigglypuff_handle_event +# define EVENT_MASK PointerMotionMask +# define jigglypuff_opts xlockmore_opts + +#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 DEFAULTS "*delay: 20000\n" \ + "*showFPS: False\n" \ + "*wireframe: False\n" \ + "*color: cycle\n" \ + "*shininess: 100\n" \ + "*complexity: 2\n" \ + "*speed: 500\n" \ + "*distance: 100\n" \ + "*hold: 800\n" \ + "*spherism: 200\n" \ + "*damping: 500\n" + # include "xlockmore.h" #else @@ -46,6 +77,10 @@ # include "config.h" #endif +#include "xpm-ximage.h" +#include "gltrackball.h" +#include "../images/jigglymap.xpm" + #ifdef USE_GL #include @@ -54,14 +89,22 @@ #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 do_wireframe; +static int complexity; +static int speed; + static int do_tetrahedron; -static int do_spooky; +static int spooky; +static char *color; +static int shininess; + static int random_parms; typedef struct solid solid; @@ -74,14 +117,23 @@ typedef struct { float damping_factor; int do_wireframe; - int do_spooky; + 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; +} jigglystruct; static jigglystruct *jss = NULL; @@ -90,22 +142,29 @@ static XrmOptionDescRec opts[] = { {"+random", ".Jigglypuff.random", XrmoptionNoArg, (caddr_t)"false"}, {"-tetra", ".Jigglypuff.tetra", XrmoptionNoArg, (caddr_t)"true"}, {"+tetra", ".Jigglypuff.tetra", XrmoptionNoArg, (caddr_t)"false"}, - {"-spooky", ".Jigglypuff.spooky", XrmoptionNoArg, (caddr_t)"true"}, - {"+spooky", ".Jigglypuff.spooky", XrmoptionNoArg, (caddr_t)"false"}, - {"-spherism", ".Jigglypuff.spherism", XrmoptionSepArg, "500"}, - {"-hold", ".Jigglypuff.hold", XrmoptionSepArg, "500"}, - {"-distance", "Jigglypuff.distance", XrmoptionSepArg, "500"}, - {"-damping", "Jigglypuff.damping", XrmoptionSepArg, "50"} + {"-spooky", ".Jigglypuff.spooky", XrmoptionSepArg, (caddr_t)"0"}, + {"-color", ".Jigglypuff.color", XrmoptionSepArg, (caddr_t)DEF_COLOR}, + {"-shininess", ".Jigglypuff.shininess", XrmoptionSepArg, (caddr_t)DEF_SHININESS}, + {"-complexity", ".Jigglypuff.complexity", XrmoptionSepArg, (caddr_t)DEF_COMPLEXITY}, + {"-speed", ".Jigglypuff.speed", XrmoptionSepArg, (caddr_t)DEF_SPEED}, + {"-spherism", ".Jigglypuff.spherism", XrmoptionSepArg, (caddr_t)DEF_SPHERISM}, + {"-hold", ".Jigglypuff.hold", XrmoptionSepArg, (caddr_t)DEF_HOLD}, + {"-distance", "Jigglypuff.distance", XrmoptionSepArg, (caddr_t)DEF_DISTANCE}, + {"-damping", "Jigglypuff.damping", XrmoptionSepArg, (caddr_t)DEF_DAMPING} }; static argtype vars[] = { {(caddr_t*)&random_parms, "random", "Random", "False", t_Bool}, - {(caddr_t*)&do_tetrahedron, "tetra", "Tetra", "True", t_Bool}, - {(caddr_t*)&do_spooky, "spooky", "Spooky", "False", t_Bool}, - {(caddr_t*)&spherism, "spherism", "Spherism", "100", t_Int}, - {(caddr_t*)&hold, "hold", "Hold", "600", t_Int}, - {(caddr_t*)&distance, "distance", "Distance", "500", t_Int}, - {(caddr_t*)&damping, "damping", "Damping", "50", t_Int} + {(caddr_t*)&do_tetrahedron, "tetra", "Tetra", "False", t_Bool}, + {(caddr_t*)&spooky, "spooky", "Spooky", "0", t_Int}, + {(caddr_t*)&color, "color", "Color", DEF_COLOR, t_String}, + {(caddr_t*)&shininess, "shininess", "Shininess", DEF_SHININESS, t_Int}, + {(caddr_t*)&complexity, "complexity", "Complexity", DEF_COMPLEXITY, t_Int}, + {(caddr_t*)&speed, "speed", "Speed", DEF_SPEED, t_Int}, + {(caddr_t*)&spherism, "spherism", "Spherism", DEF_SPHERISM, t_Int}, + {(caddr_t*)&hold, "hold", "Hold", DEF_HOLD, t_Int}, + {(caddr_t*)&distance, "distance", "Distance", DEF_DISTANCE, t_Int}, + {(caddr_t*)&damping, "damping", "Damping", DEF_DAMPING, t_Int} }; #undef countof @@ -113,6 +172,29 @@ static argtype vars[] = { 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 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 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}, +}; + #ifdef DEBUG #define _DEBUG(msg, args...) do { \ fprintf(stderr, "%s : %d : " msg ,__FILE__,__LINE__ ,##args); \ @@ -121,6 +203,7 @@ ModeSpecOpt jigglypuff_opts = {countof(opts), opts, countof(vars), vars, NULL}; #define _DEBUG(msg, args...) #endif +/* 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; @@ -137,6 +220,7 @@ struct solid { struct face { solid *s; hedge *start; + GLfloat *color; face *next; }; @@ -165,54 +249,50 @@ struct vertex { vertex *next; }; -static void vector_init(vector v, coord x, coord y, coord z) +static inline void vector_init(vector v, coord x, coord y, coord z) { v[0] = x; v[1] = y; v[2] = z; } -static void vector_copy(vector d, vector s) +static inline void vector_copy(vector d, vector s) { d[0] = s[0]; d[1] = s[1]; d[2] = s[2]; } -#if 0 -static void vector_add(vector v1, vector v2, vector v) +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]); } -#endif -static void vector_add_to(vector v1, vector v2) +static inline void vector_add_to(vector v1, vector v2) { v1[0] += v2[0]; v1[1] += v2[1]; v1[2] += v2[2]; } -static void vector_sub(vector v1, vector v2, vector v) +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 void vector_scale(vector v, coord s) +static inline void vector_scale(vector v, coord s) { v[0] *= s; v[1] *= s; v[2] *= s; } -#if 0 -static coord dot(vector v1, vector v2) +static inline coord dot(vector v1, vector v2) { return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2]; } -#endif -static void cross(vector v1, vector v2, vector v) +static inline void cross(vector v1, vector v2, vector v) { vector_init(v, v1[1]*v2[2] - v2[1]*v1[2], @@ -220,17 +300,17 @@ static void cross(vector v1, vector v2, vector v) v1[0]*v2[1] - v2[0]*v1[1]); } -static coord magnitude2(vector v) +static inline coord magnitude2(vector v) { return v[0]*v[0] + v[1]*v[1] + v[2]*v[2]; } -static coord magnitude(vector v) +static inline coord magnitude(vector v) { return sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]); } -static void normalize(vector v) +static inline void normalize(vector v) { coord mag = 1.0/sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]); @@ -239,7 +319,7 @@ static void normalize(vector v) v[2] *= mag; } -static void normalize_to(vector v, coord m) +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; @@ -248,7 +328,7 @@ static void normalize_to(vector v, coord m) v[2] *= mag; } -static void midpoint(vector v1, vector v2, vector v) +static inline void midpoint(vector v1, vector v2, vector v) { vector_init(v, v1[0] + 0.5 * (v2[0] - v1[0]), @@ -256,7 +336,7 @@ static void midpoint(vector v1, vector v2, vector v) v1[2] + 0.5 * (v2[2] - v1[2])); } -static hedge *partner(hedge *h) { +static inline hedge *partner(hedge *h) { if(!h->e) return NULL; if(h == h->e->left) { @@ -266,12 +346,12 @@ static hedge *partner(hedge *h) { return h->e->left; } else { - _DEBUG("Holy shit Batman! this edge is fucked up!\n"); + _DEBUG("Inconsistent edge detected. Presumably, this is a bug. Exiting.\n"); exit(-1); } } -static vertex *vertex_new(solid *s, vector v) +vertex *vertex_new(solid *s, vector v) { vertex *vtx = (vertex*)malloc(sizeof(vertex)); @@ -290,7 +370,7 @@ static vertex *vertex_new(solid *s, vector v) * 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 *hedge_new(hedge *hafter, vertex *vtx) { hedge *h = (hedge*)malloc(sizeof(hedge)); @@ -308,7 +388,7 @@ static hedge *hedge_new(hedge *hafter, vertex *vtx) return h; } -static edge *edge_new(solid *s) +edge *edge_new(solid *s) { edge *e = (edge*)malloc(sizeof(edge)); if(!e) { @@ -322,7 +402,7 @@ static edge *edge_new(solid *s) return e; } -static face *face_new(solid *s, hedge *h) +face *face_new(solid *s, hedge *h) { face *f = (face*)malloc(sizeof(face)); if(!f) { @@ -344,17 +424,13 @@ static face *face_new(solid *s, hedge *h) * there are at least 2 faces. * partner(h)->next->vtx == vtx * Post-assumptions: - * the new halfedge will be inserted _before_ the - * halfedge owning vtx in f. - * THIS IS WRONG. FIX ME!!! - * New Deal - the Invariants * the new halfedge will be inserted AFTER the indicated * halfedge. This means that f->start is guaranteed not to * change. - * Also, the vertex returned will have h==. + * the vertex returned will have h==. */ -static vertex *vertex_split(hedge *h, vector v) +vertex *vertex_split(hedge *h, vector v) { hedge *h2, *hn1, *hn2; vertex *vtxn; @@ -364,7 +440,7 @@ static vertex *vertex_split(hedge *h, vector v) f1 = h->f; h2 = partner(h); f2 = h2->f; - + vtxn = vertex_new(f1->s, v); hn1 = hedge_new(h, vtxn); vtxn->h = hn1; @@ -384,7 +460,7 @@ static vertex *vertex_split(hedge *h, vector v) return vtxn; } -static face *face_split(face *f, hedge *h1, hedge *h2) +face *face_split(face *f, hedge *h1, hedge *h2) { hedge *hn1, *hn2, *tmp; edge *en; @@ -424,10 +500,11 @@ static face *face_split(face *f, hedge *h1, hedge *h2) tmp->f = fn; tmp = tmp->next; } while(tmp != fn->start); + fn->color = f->color; return fn; } -static solid *solid_new(vector where) +solid *solid_new(vector where) { solid *s = (solid*)malloc(sizeof(solid)); face *f1, *f2; @@ -463,33 +540,8 @@ static solid *solid_new(vector where) return s; } -static solid *tetra(void) -{ - solid *s; - vertex *vtx; - vector v; - hedge *h; - face *f; - - 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); - - return s; -} - -static void face_tessel2(face *f) +/* This is all the code directly related to constructing the jigglypuff */ +void face_tessel2(face *f) { hedge *h1=f->start->prev, *h2=f->start->next; @@ -510,7 +562,7 @@ static void face_tessel2(face *f) * added at the head of the list. If that ever changes, * this is borked. */ -static void solid_tesselate(solid *s) +void solid_tesselate(solid *s) { edge *e = s->edges; face *f = s->faces; @@ -527,7 +579,7 @@ static void solid_tesselate(solid *s) } } -static void solid_spherify(solid * s, coord size) +void solid_spherify(solid * s, coord size) { vertex *vtx = s->vertices; @@ -537,9 +589,43 @@ static void solid_spherify(solid * s, coord size) } } -static solid *tesselated_tetrahedron(coord size, int iter) +solid *tetrahedron(jigglystruct *js) { - solid *s = tetra(); + 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; +} + +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; @@ -561,19 +657,24 @@ static void vertex_calcnormal(vertex *vtx, int spooky) vector_add_to(vtx->n, norm); h = partner(h)->next; } while(h != start); - if(!spooky) + if(!js->spooky) normalize(vtx->n); else - vector_scale(vtx->n, 15); + vector_scale(vtx->n, js->spooky); } -static void vertex_render(vertex *vtx) +static inline void vertex_render(vertex *vtx, jigglystruct *js) { glNormal3fv(vtx->n); glVertex3fv(vtx->v); } -static void face_render(face *f) +/* 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 void face_render(face *f, jigglystruct *js) { hedge *h1, *h2, *hend; @@ -581,58 +682,49 @@ static void face_render(face *f) 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); - vertex_render(h2->vtx); - vertex_render(hend->vtx); + vertex_render(h1->vtx, js); + vertex_render(h2->vtx, js); + vertex_render(hend->vtx, js); h1 = h2; h2 = h1->next; } glEnd(); } -static void jigglypuff_render(jigglystruct *js) +void jigglypuff_render(jigglystruct *js) { face *f = js->shape->faces; vertex *vtx = js->shape->vertices; while(vtx) { - vertex_calcnormal(vtx, js->do_spooky); + vertex_calcnormal(vtx, js); vtx = vtx->next; } while(f) { - face_render(f); + face_render(f, js); f=f->next; } } -void calculate_parameters(jigglystruct *js) { - js->stable_distance = (float)distance / 10000.0; - js->hold_strength = (float)hold / 1000.0; - js->spherify_strength = (float)spherism / 10000.0; - js->damping_velocity = (float)damping / 100000.0; - js->damping_factor = - min(0.1, 1.0/max(js->hold_strength, js->spherify_strength)); -} +/* This is the jiggling code */ -void randomize_parameters(void) { - do_tetrahedron = !(random() & 1); - do_spooky = !(random() & 3); - do_wireframe = !(random() & 3); - spherism = random() % 1000; - hold = random() % 1000; - distance = random() % 1000; - damping = random() % 1000; -} +/* stable distance when subdivs == 4 */ +#define STABLE_DISTANCE 0.088388347648 -void update_shape(jigglystruct *js) { +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; @@ -644,6 +736,10 @@ void update_shape(jigglystruct *js) { 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; @@ -662,56 +758,32 @@ void update_shape(jigglystruct *js) { } } -void draw_jigglypuff(ModeInfo *mi) -{ - jigglystruct *js = &jss[MI_SCREEN(mi)]; - - glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(js->glx_context)); - - glDrawBuffer(GL_BACK); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); +/* These are the various initialization routines */ - glRotatef(js->angle, sin(js->axis), cos(js->axis), -sin(js->axis)); - glTranslatef(0,0,5); - - if((js->angle+=0.1) >= 360.0f ) { - js->angle -= 360.0f; - } - if((js->axis+=0.01f) >= 2*M_PI ) { - js->axis -= 2*M_PI; - } - jigglypuff_render(js); - if(mi->fps_p) - do_fps(mi); - glFinish(); - update_shape(js); - glXSwapBuffers(MI_DISPLAY(mi), MI_WINDOW(mi)); -} - -void reshape_jigglypuff(ModeInfo *mi, int width, int height) +void init_texture(ModeInfo *mi) { - GLfloat aspect = (GLfloat)width / (GLfloat)height; + XImage *img = xpm_to_ximage(mi->dpy, mi->xgwa.visual, + mi->xgwa.colormap, jigglymap_xpm); - glViewport(0, 0, width, height); - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glFrustum(-0.5*aspect, 0.5*aspect, -0.5, 0.5, 1, 20); - glTranslatef(0,0,-10); + 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) +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.7, 0.7, 0.65, 1}; const GLfloat lcol1[4] = {0.3, 0.2, 0.1, 1}; - const GLfloat color1[4]={1, 1, 1, 0.5}; - const GLfloat color2[4]={0.9, 0.9, 0.9, 0.5}; + const GLfloat scolor[4]= {0.9, 0.9, 0.9, 0.5}; + glDrawBuffer(GL_BACK); + glClearColor(0, 0, 0, 0); glShadeModel(GL_SMOOTH); + glEnable(GL_DEPTH_TEST); if(js->do_wireframe) { glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); @@ -722,27 +794,209 @@ static void setup_opengl(ModeInfo *mi, jigglystruct *js) glEnable(GL_CULL_FACE); } - glEnable(GL_DEPTH_TEST); + 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); + } +} - glEnable(GL_LIGHTING); - glEnable(GL_LIGHT0); - glEnable(GL_LIGHT1); +int parse_color(jigglystruct *js) +{ + 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; + } + else if(!strcmp(color, "chrome")) { + js->color_style = COLOR_STYLE_CHROME; + return 1; + } + 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; - glLightfv(GL_LIGHT0, GL_POSITION, lpos0); - glLightfv(GL_LIGHT1, GL_POSITION, lpos1); - glLightfv(GL_LIGHT0, GL_DIFFUSE, lcol0); - glLightfv(GL_LIGHT1, GL_DIFFUSE, lcol1); + return 1; +} - glClearColor(0, 0, 0, 0); +void randomize_parameters(jigglystruct *js) { + do_tetrahedron = random() & 1; + js->do_wireframe = !(random() & 3); + js->color_style = random() % 5; + 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; +} + +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 */ + +Bool jigglypuff_handle_event(ModeInfo *mi, XEvent *event) +{ + jigglystruct *js = &jss[MI_SCREEN(mi)]; + + if(event->xany.type == ButtonPress && + event->xbutton.button & Button1) { + js->button_down = 1; + gltrackball_start(js->trackball, event->xbutton.x, event->xbutton.y, + MI_WIDTH(mi), MI_HEIGHT(mi)); + return True; + } + else if(event->xany.type == ButtonRelease && + event->xbutton.button & Button1) { + js->button_down = 0; + return True; + } + else if(event->xany.type == MotionNotify && js->button_down) { + gltrackball_track(js->trackball, event->xmotion.x, event->xmotion.y, + MI_WIDTH(mi), MI_HEIGHT(mi)); + return True; + } + return False; +} + +void reshape_jigglypuff(ModeInfo *mi, int width, int height) +{ + GLfloat aspect = (GLfloat)width / (GLfloat)height; + + glViewport(0, 0, width, height); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glFrustum(-0.5*aspect, 0.5*aspect, -0.5, 0.5, 1, 20); +/* glTranslatef(0, 0, -10);*/ +} + +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); - glMaterialfv(GL_FRONT, GL_DIFFUSE, color1); - glMaterialfv(GL_FRONT, GL_SPECULAR, color2); - glMateriali(GL_FRONT, GL_SHININESS, 100); + 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); + } + + jigglypuff_render(js); + if(MI_IS_FPS(mi)) + do_fps(mi); + glFinish(); + update_shape(js); + glXSwapBuffers(MI_DISPLAY(mi), MI_WINDOW(mi)); } void init_jigglypuff(ModeInfo *mi) { jigglystruct *js; + int subdivs; if(!jss) { jss = (jigglystruct*) @@ -752,20 +1006,59 @@ void init_jigglypuff(ModeInfo *mi) exit(1); } } + js = &jss[MI_SCREEN(mi)]; + js->do_wireframe = MI_IS_WIREFRAME(mi); + + 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(); + randomize_parameters(js); + + 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)); } - js->shape = tesselated_tetrahedron(1, 5); - if(!do_tetrahedron) - solid_spherify(js->shape, 1); - calculate_parameters(js); - js->do_spooky = do_spooky; + else { + MI_CLEARWINDOW(mi); + } + js->trackball = gltrackball_init(); + _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); } +/* This is the end of the file */ + #endif /* USE_GL */ + + + + + + +