1 /* jigglypuff - a most, most, unfortunate screensaver.
3 * Copyright (c) 2003 Keith Macleod (kmacleod@primus.ca)
5 * Permission to use, copy, modify, distribute, and sell this software and its
6 * documentation for any purpose is hereby granted without fee, provided that
7 * the above copyright notice appear in all copies and that both that
8 * copyright notice and this permission notice appear in supporting
9 * documentation. No representations are made about the suitability of this
10 * software for any purpose. It is provided "as is" without express or
13 * Draws all varieties of obscene, spastic, puffy balls
14 * orbiting lazily about the screen. More of an accident
17 * Apologies to anyone who thought they were getting a Pokemon
20 * Of course, if you modify it to do something interesting and/or
21 * funny, I'd appreciate receiving a copy.
23 * 04/06/2003 - Oops, figured out what was wrong with the sphere
24 * mapping. I had assumed it was done in model space,
25 * but of course I was totally wrong... Eye space you
28 * 03/31/2003 - Added chrome to the color options. The mapping
29 * is anything but 'correct', but it's a pretty good
30 * effect anyways, as long as the surface is jiggling
31 * enough that you can't tell. Sure, it seems kind of odd
32 * that it's reflecting a sky that's obviously not there,
33 * but who has time to worry about silly details like
34 * that? Not me, ah rekkin'. km
39 # define DEFAULTS "*delay: 20000\n" \
41 "*wireframe: False\n" \
43 # define refresh_jigglypuff 0
44 # define release_jigglypuff 0
45 # include "xlockmore.h"
54 #include "xpm-ximage.h"
55 #include "gltrackball.h"
56 #include "../images/jigglymap.xpm"
61 #define DEF_COLOR "cycle"
62 #define DEF_SHININESS "100"
63 #define DEF_COMPLEXITY "2"
64 #define DEF_SPEED "500"
65 #define DEF_DISTANCE "100"
66 #define DEF_HOLD "800"
67 #define DEF_SPHERISM "75"
68 #define DEF_DAMPING "500"
69 #define DEF_RANDOM "True"
70 #define DEF_TETRA "False"
71 #define DEF_SPOOKY "0"
74 #define max(a,b) (((a)>(b))?(a):(b))
75 #define min(a,b) (((a)<(b))?(a):(b))
78 /* Why isn't RAND_MAX correct in the first place? */
79 #define REAL_RAND_MAX (2.0*(float)RAND_MAX)
86 static int complexity;
89 static int do_tetrahedron;
94 static int random_parms;
96 typedef struct solid solid;
99 float stable_distance;
101 float spherify_strength;
102 float damping_velocity;
103 float damping_factor;
109 GLfloat jiggly_color[4];
110 GLfloat color_dir[3];
114 trackball_state *trackball;
121 GLXContext *glx_context;
124 static jigglystruct *jss = NULL;
126 static XrmOptionDescRec opts[] = {
127 {"-random", ".Jigglypuff.random", XrmoptionNoArg, "true"},
128 {"+random", ".Jigglypuff.random", XrmoptionNoArg, "false"},
129 {"-tetra", ".Jigglypuff.tetra", XrmoptionNoArg, "true"},
130 {"+tetra", ".Jigglypuff.tetra", XrmoptionNoArg, "false"},
131 {"-spooky", ".Jigglypuff.spooky", XrmoptionSepArg, "0"},
132 {"-color", ".Jigglypuff.color", XrmoptionSepArg, DEF_COLOR},
133 {"-shininess", ".Jigglypuff.shininess", XrmoptionSepArg, DEF_SHININESS},
134 {"-complexity", ".Jigglypuff.complexity", XrmoptionSepArg, DEF_COMPLEXITY},
135 {"-speed", ".Jigglypuff.speed", XrmoptionSepArg, DEF_SPEED},
136 {"-spherism", ".Jigglypuff.spherism", XrmoptionSepArg, DEF_SPHERISM},
137 {"-hold", ".Jigglypuff.hold", XrmoptionSepArg, DEF_HOLD},
138 {"-distance", "Jigglypuff.distance", XrmoptionSepArg, DEF_DISTANCE},
139 {"-damping", "Jigglypuff.damping", XrmoptionSepArg, DEF_DAMPING}
142 static argtype vars[] = {
143 {&random_parms, "random", "Random", DEF_RANDOM, t_Bool},
144 {&do_tetrahedron, "tetra", "Tetra", DEF_TETRA, t_Bool},
145 {&spooky, "spooky", "Spooky", DEF_SPOOKY, t_Int},
146 {&color, "color", "Color", DEF_COLOR, t_String},
147 {&shininess, "shininess", "Shininess", DEF_SHININESS, t_Int},
148 {&complexity, "complexity", "Complexity", DEF_COMPLEXITY, t_Int},
149 {&speed, "speed", "Speed", DEF_SPEED, t_Int},
150 {&spherism, "spherism", "Spherism", DEF_SPHERISM, t_Int},
151 {&hold, "hold", "Hold", DEF_HOLD, t_Int},
152 {&distance, "distance", "Distance", DEF_DISTANCE, t_Int},
153 {&damping, "damping", "Damping", DEF_DAMPING, t_Int}
157 #define countof(x) ((int)(sizeof(x)/sizeof(*(x))))
159 ENTRYPOINT ModeSpecOpt jigglypuff_opts = {countof(opts), opts, countof(vars), vars, NULL};
161 #define COLOR_STYLE_NORMAL 0
162 #define COLOR_STYLE_CYCLE 1
163 #define COLOR_STYLE_CLOWNBARF 2
164 #define COLOR_STYLE_FLOWERBOX 3
165 #define COLOR_STYLE_CHROME 4
167 #define CLOWNBARF_NCOLORS 5
169 static const GLfloat clownbarf_colors[CLOWNBARF_NCOLORS][4] = {
170 {0.7, 0.7, 0.0, 1.0},
171 {0.8, 0.1, 0.1, 1.0},
172 {0.1, 0.1, 0.8, 1.0},
173 {0.9, 0.9, 0.9, 1.0},
177 static const GLfloat flowerbox_colors[4][4] = {
178 {0.7, 0.7, 0.0, 1.0},
179 {0.9, 0.0, 0.0, 1.0},
180 {0.0, 0.9, 0.0, 1.0},
181 {0.0, 0.0, 0.9, 1.0},
184 # if 0 /* I am not even going to *try* and make this bullshit compile
185 without warning under gcc -std=c89 -pedantic. -jwz. */
187 # ifdef __GNUC__ /* GCC style */
188 #define _DEBUG(msg, args...) do { \
189 fprintf(stderr, "%s : %d : " msg ,__FILE__,__LINE__ ,##args); \
191 # else /* C99 standard style */
192 #define _DEBUG(msg, ...) do { \
193 fprintf(stderr, "%s : %d : " msg ,__FILE__,__LINE__,__VA_ARGS__); \
197 # ifdef __GNUC__ /* GCC style */
198 #define _DEBUG(msg, args...)
199 # else /* C99 standard style */
200 #define _DEBUG(msg, ...)
205 /* This is all the half-edge b-rep code (as well as basic geometry) */
206 typedef struct face face;
207 typedef struct edge edge;
208 typedef struct hedge hedge;
209 typedef struct vertex vertex;
210 typedef GLfloat coord;
211 typedef coord vector[3];
222 const GLfloat *color;
251 static inline void vector_init(vector v, coord x, coord y, coord z)
258 static inline void vector_copy(vector d, vector s)
265 static inline void vector_add(vector v1, vector v2, vector v)
267 vector_init(v, v1[0]+v2[0], v1[1]+v2[1], v1[2]+v2[2]);
270 static inline void vector_add_to(vector v1, vector v2)
277 static inline void vector_sub(vector v1, vector v2, vector v)
279 vector_init(v, v1[0]-v2[0], v1[1]-v2[1], v1[2]-v2[2]);
282 static inline void vector_scale(vector v, coord s)
290 static inline coord dot(vector v1, vector v2)
292 return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2];
296 static inline void cross(vector v1, vector v2, vector v)
299 v1[1]*v2[2] - v2[1]*v1[2],
300 v1[2]*v2[0] - v2[2]*v1[0],
301 v1[0]*v2[1] - v2[0]*v1[1]);
304 static inline coord magnitude2(vector v)
306 return v[0]*v[0] + v[1]*v[1] + v[2]*v[2];
309 static inline coord magnitude(vector v)
311 return sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]);
314 static inline void normalize(vector v)
316 coord mag = 1.0/sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]);
323 static inline void normalize_to(vector v, coord m)
325 coord mag = 1.0/sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2])/m;
332 static inline void midpoint(vector v1, vector v2, vector v)
335 v1[0] + 0.5 * (v2[0] - v1[0]),
336 v1[1] + 0.5 * (v2[1] - v1[1]),
337 v1[2] + 0.5 * (v2[2] - v1[2]));
340 static inline hedge *partner(hedge *h) {
343 if(h == h->e->left) {
346 else if(h == h->e->right) {
350 /* _DEBUG("Inconsistent edge detected. Presumably, this is a bug. Exiting.\n", NULL); */
355 static vertex *vertex_new(solid *s, vector v)
357 vertex *vtx = (vertex*)malloc(sizeof(vertex));
362 vtx->next = s->vertices;
364 vector_copy(vtx->v, v);
365 vector_init(vtx->f, 0, 0, 0);
366 vector_init(vtx->vel, 0, 0, 0);
370 /* insert a new halfedge after hafter. this is low-level,
371 * i.e. it is a helper for the split_* functions, which
372 * maintain the consistency of the solid.
374 static hedge *hedge_new(hedge *hafter, vertex *vtx)
376 hedge *h = (hedge*)malloc(sizeof(hedge));
379 /* _DEBUG("Out of memory in hedge_new()\n",NULL); */
386 h->next = hafter->next;
392 static edge *edge_new(solid *s)
394 edge *e = (edge*)malloc(sizeof(edge));
396 /* _DEBUG("Out of memory in edge_new()\n",NULL);*/
402 e->left = e->right = NULL;
406 static face *face_new(solid *s, hedge *h)
408 face *f = (face*)malloc(sizeof(face));
410 /* _DEBUG("Out of memory in face_new()",NULL);*/
420 /* split vertex vtx, creating a new edge after v on f
421 * that goes to a new vertex at v, adjoining whatever
422 * face is on the other side of the halfedge attached to
425 * there are at least 2 faces.
426 * partner(h)->next->vtx == vtx
428 * the new halfedge will be inserted AFTER the indicated
429 * halfedge. This means that f->start is guaranteed not to
431 * the vertex returned will have h==<the new halfedge>.
434 static vertex *vertex_split(hedge *h, vector v)
436 hedge *h2, *hn1, *hn2;
444 vtxn = vertex_new(f1->s, v);
445 hn1 = hedge_new(h, vtxn);
447 hn2 = hedge_new(h2, vtxn);
450 if(h2->e->left == h2)
455 en = edge_new(f1->s);
463 static face *face_split(face *f, hedge *h1, hedge *h2)
465 hedge *hn1, *hn2, *tmp;
469 if(h1->f != f || h2->f != f) {
470 /* _DEBUG("Whoah, cap'n, yer usin' a bad halfedge!\n",NULL);*/
474 /* _DEBUG("Trying to split a face at a single vertex\n",NULL);*/
477 /* close the loops */
483 /* insert halfedges & create edge */
484 hn1 = hedge_new(h2->prev, h1->vtx);
485 hn2 = hedge_new(h1->prev, h2->vtx);
492 /* make the new face, first find out which hedge is contained
493 * in the original face, then start the new face at the other */
495 while(tmp != h1 && tmp != h2)
497 tmp = (tmp == h1) ? h2 : h1 ;
498 fn = face_new(f->s, tmp);
502 } while(tmp != fn->start);
503 fn->color = f->color;
507 static solid *solid_new(vector where)
509 solid *s = (solid*)malloc(sizeof(solid));
519 h1 = (hedge*)malloc(sizeof(hedge));
520 h2 = (hedge*)malloc(sizeof(hedge));
521 h1->next = h1->prev = h1;
522 h2->next = h2->prev = h2;
524 vtx = vertex_new(s, where);
535 f1 = face_new(s, h1);
536 f2 = face_new(s, h2);
543 /* This is all the code directly related to constructing the jigglypuff */
544 static void face_tessel2(face *f)
546 hedge *h1=f->start->prev, *h2=f->start->next;
550 while(h2 != h1 && h2->next != h1) {
551 f = face_split(f, h1, h2);
553 h2 = f->start->next->next;
557 /* This will only work with solids composed entirely of
558 * triangular faces. It first add a vertex to the middle
559 * of each edge, then walks the faces, connecting the
561 * I'm abusing the fact that new faces and edges are always
562 * added at the head of the list. If that ever changes,
565 static void solid_tesselate(solid *s)
572 midpoint(e->left->vtx->v, e->right->vtx->v, v);
573 vertex_split(e->left, v);
582 static void solid_spherify(solid * s, coord size)
584 vertex *vtx = s->vertices;
587 normalize_to(vtx->v, size);
592 static solid *tetrahedron(jigglystruct *js)
601 vector_init(v, 1, 1, 1);
603 vector_init(v, -1, -1, 1);
605 vtx = vertex_split(h, v);
606 vector_init(v, -1, 1, -1);
607 vtx = vertex_split(vtx->h, v);
609 f = face_split(s->faces, h, h->prev);
610 vector_init(v, 1, -1, -1);
611 vertex_split(f->start, v);
612 f = s->faces->next->next;
614 face_split(f, h, h->next->next);
616 if(js->color_style == COLOR_STYLE_FLOWERBOX) {
619 f->color = flowerbox_colors[i];
627 static solid *tesselated_tetrahedron(coord size, int iter, jigglystruct *js) {
628 solid *s = tetrahedron(js);
631 for(i=0; i<iter; i++) {
637 static void clownbarf_colorize(solid *s) {
640 f->color = clownbarf_colors[random() % CLOWNBARF_NCOLORS];
645 /* Here be the rendering code */
647 static inline void vertex_calcnormal(vertex *vtx, jigglystruct *js)
649 hedge *start = vtx->h, *h=start;
651 vector_init(vtx->n, 0, 0, 0);
654 vector_sub(h->prev->vtx->v, vtx->v, u);
655 vector_sub(h->next->vtx->v, vtx->v, v);
657 vector_add_to(vtx->n, norm);
658 h = partner(h)->next;
663 vector_scale(vtx->n, js->spooky);
666 static inline void vertex_render(vertex *vtx, jigglystruct *js)
672 /* This can be optimized somewhat due to the fact that all
673 * the faces are triangles. I haven't actually tested to
674 * see what the cost is of calling glBegin/glEnd for each
677 static inline int face_render(face *f, jigglystruct *js)
679 hedge *h1, *h2, *hend;
686 if(js->color_style == COLOR_STYLE_FLOWERBOX ||
687 js->color_style == COLOR_STYLE_CLOWNBARF)
688 glColor4fv(f->color);
689 glBegin(GL_TRIANGLES);
690 while(h1 != hend && h2 !=hend) {
691 vertex_render(h1->vtx, js);
692 vertex_render(h2->vtx, js);
693 vertex_render(hend->vtx, js);
702 static int jigglypuff_render(jigglystruct *js)
705 face *f = js->shape->faces;
706 vertex *vtx = js->shape->vertices;
709 vertex_calcnormal(vtx, js);
713 polys += face_render(f, js);
719 /* This is the jiggling code */
721 /* stable distance when subdivs == 4 */
722 #define STABLE_DISTANCE 0.088388347648
724 static void update_shape(jigglystruct *js)
726 vertex *vtx = js->shape->vertices;
727 edge *e = js->shape->edges;
730 vector_init(zero, 0, 0, 0);
732 /* sum all the vertex-vertex forces */
736 vector_sub(e->left->vtx->v, e->right->vtx->v, f);
737 mag = js->stable_distance - magnitude(f);
738 vector_scale(f, mag);
739 vector_add_to(e->left->vtx->f, f);
740 vector_sub(zero, f, f);
741 vector_add_to(e->right->vtx->f, f);
745 /* scale back the v-v force and add the spherical force
746 * then add the result to the vertex velocity, damping
747 * if necessary. Finally, move the vertex */
751 vector_scale(vtx->f, js->hold_strength);
752 vector_copy(to_sphere, vtx->v);
753 mag = 1 - magnitude(to_sphere);
754 vector_scale(to_sphere, mag * js->spherify_strength);
755 vector_add_to(vtx->f, to_sphere);
756 vector_add_to(vtx->vel, vtx->f);
757 vector_init(vtx->f, 0, 0, 0);
758 mag = magnitude2(vtx->vel);
759 if(mag > js->damping_velocity)
760 vector_scale(vtx->vel, js->damping_factor);
761 vector_add_to(vtx->v, vtx->vel);
766 /* These are the various initialization routines */
768 static void init_texture(ModeInfo *mi)
770 XImage *img = xpm_to_ximage(mi->dpy, mi->xgwa.visual,
771 mi->xgwa.colormap, jigglymap_xpm);
773 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB,
774 img->width, img->height, 0, GL_RGBA,
775 GL_UNSIGNED_BYTE, img->data);
780 static void setup_opengl(ModeInfo *mi, jigglystruct *js)
782 const GLfloat lpos0[4] = {-12, 8, 12, 0};
783 const GLfloat lpos1[4] = {7, -5, 0, 0};
784 const GLfloat lcol0[4] = {0.7f, 0.7f, 0.65f, 1};
785 const GLfloat lcol1[4] = {0.3f, 0.2f, 0.1f, 1};
786 const GLfloat scolor[4]= {0.9f, 0.9f, 0.9f, 0.5f};
788 glDrawBuffer(GL_BACK);
789 glShadeModel(GL_SMOOTH);
790 glEnable(GL_DEPTH_TEST);
792 if(js->do_wireframe) {
793 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
798 glEnable(GL_CULL_FACE);
801 if(js->color_style != COLOR_STYLE_CHROME) {
802 glEnable(GL_LIGHTING);
806 glLightfv(GL_LIGHT0, GL_POSITION, lpos0);
807 glLightfv(GL_LIGHT1, GL_POSITION, lpos1);
808 glLightfv(GL_LIGHT0, GL_DIFFUSE, lcol0);
809 glLightfv(GL_LIGHT1, GL_DIFFUSE, lcol1);
811 glEnable(GL_COLOR_MATERIAL);
812 glColor4fv(js->jiggly_color);
814 glMaterialfv(GL_FRONT, GL_SPECULAR, scolor);
815 glMateriali(GL_FRONT, GL_SHININESS, js->shininess);
819 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
820 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
821 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
822 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
823 glEnable(GL_TEXTURE_GEN_S);
824 glEnable(GL_TEXTURE_GEN_T);
825 glEnable(GL_TEXTURE_2D);
826 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
827 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
828 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
832 static int parse_color(jigglystruct *js)
834 unsigned int r, g, b;
835 if(!strcmp(color, "clownbarf")) {
836 js->color_style = COLOR_STYLE_CLOWNBARF;
839 else if(!strcmp(color, "flowerbox")) {
840 js->color_style = COLOR_STYLE_FLOWERBOX;
843 # ifndef HAVE_JWZGLES /* SPHERE_MAP unimplemented */
844 else if(!strcmp(color, "chrome")) {
845 js->color_style = COLOR_STYLE_CHROME;
849 else if(!strcmp(color, "cycle")) {
850 js->color_style = COLOR_STYLE_CYCLE;
851 js->jiggly_color[0] = ((float)random()) / REAL_RAND_MAX * 0.7 + 0.3;
852 js->jiggly_color[1] = ((float)random()) / REAL_RAND_MAX * 0.7 + 0.3;
853 js->jiggly_color[2] = ((float)random()) / REAL_RAND_MAX * 0.7 + 0.3;
854 js->jiggly_color[3] = 1.0f;
855 js->color_dir[0] = ((float)random()) / REAL_RAND_MAX / 100.0;
856 js->color_dir[1] = ((float)random()) / REAL_RAND_MAX / 100.0;
857 js->color_dir[2] = ((float)random()) / REAL_RAND_MAX / 100.0;
862 if(strlen(color) != 7)
864 if(sscanf(color,"#%02x%02x%02x", &r, &g, &b) != 3) {
867 js->jiggly_color[0] = ((float)r)/255;
868 js->jiggly_color[1] = ((float)g)/255;
869 js->jiggly_color[2] = ((float)b)/255;
870 js->jiggly_color[3] = 1.0f;
875 static void randomize_parameters(jigglystruct *js) {
876 do_tetrahedron = random() & 1;
877 # ifndef HAVE_JWZGLES /* #### glPolygonMode other than GL_FILL unimplemented */
878 js->do_wireframe = !(random() & 3);
880 js->color_style = random() % 5;
881 # ifdef HAVE_JWZGLES /* #### SPHERE_MAP unimplemented */
882 while (js->color_style == COLOR_STYLE_CHROME)
883 js->color_style = random() % 5;;
885 if(js->color_style == COLOR_STYLE_NORMAL
886 || js->color_style == COLOR_STYLE_CYCLE) {
887 js->jiggly_color[0] = ((float)random()) / REAL_RAND_MAX * 0.5 + 0.5;
888 js->jiggly_color[1] = ((float)random()) / REAL_RAND_MAX * 0.5 + 0.5;
889 js->jiggly_color[2] = ((float)random()) / REAL_RAND_MAX * 0.5 + 0.5;
890 js->jiggly_color[3] = 1.0f;
891 if(js->color_style == COLOR_STYLE_CYCLE) {
892 js->color_dir[0] = ((float)random()) / REAL_RAND_MAX / 100.0;
893 js->color_dir[1] = ((float)random()) / REAL_RAND_MAX / 100.0;
894 js->color_dir[2] = ((float)random()) / REAL_RAND_MAX / 100.0;
897 if((js->color_style != COLOR_STYLE_CHROME) && (random() & 1))
898 js->spooky = (random() % 6) + 4;
901 js->shininess = random() % 200;
902 speed = (random() % 700) + 50;
903 /* It' kind of dull if this is too high when it starts as a sphere */
904 spherism = do_tetrahedron ? (random() % 500) + 20 : (random() % 100) + 10;
905 hold = (random() % 800) + 100;
906 distance = (random() % 500) + 100;
907 damping = (random() % 800) + 50;
910 static void calculate_parameters(jigglystruct *js, int subdivs) {
911 /* try to compensate for the inherent instability at
913 float dist_factor = (subdivs == 6) ? 2 : (subdivs == 5) ? 1 : 0.5;
915 js->stable_distance = ((float)distance / 500.0)
916 * (STABLE_DISTANCE / dist_factor);
917 js->hold_strength = (float)hold / 10000.0;
918 js->spherify_strength = (float)spherism / 10000.0;
919 js->damping_velocity = (float)damping / 100000.0;
921 0.001/max(js->hold_strength, js->spherify_strength);
923 js->speed = (float)speed / 1000.0;
926 /* The screenhack related functions begin here */
928 ENTRYPOINT Bool jigglypuff_handle_event(ModeInfo *mi, XEvent *event)
930 jigglystruct *js = &jss[MI_SCREEN(mi)];
932 if(event->xany.type == ButtonPress &&
933 event->xbutton.button == Button1) {
935 gltrackball_start(js->trackball, event->xbutton.x, event->xbutton.y,
936 MI_WIDTH(mi), MI_HEIGHT(mi));
939 else if(event->xany.type == ButtonRelease &&
940 event->xbutton.button == Button1) {
944 else if (event->xany.type == ButtonPress &&
945 (event->xbutton.button == Button4 ||
946 event->xbutton.button == Button5 ||
947 event->xbutton.button == Button6 ||
948 event->xbutton.button == Button7))
950 gltrackball_mousewheel (js->trackball, event->xbutton.button, 10,
951 !!event->xbutton.state);
954 else if(event->xany.type == MotionNotify && js->button_down) {
955 gltrackball_track(js->trackball, event->xmotion.x, event->xmotion.y,
956 MI_WIDTH(mi), MI_HEIGHT(mi));
962 ENTRYPOINT void reshape_jigglypuff(ModeInfo *mi, int width, int height)
964 GLfloat aspect = (GLfloat)width / (GLfloat)height;
966 glViewport(0, 0, width, height);
967 glMatrixMode(GL_PROJECTION);
969 glFrustum(-0.5*aspect, 0.5*aspect, -0.5, 0.5, 1, 20);
970 /* glTranslatef(0, 0, -10);*/
973 ENTRYPOINT void draw_jigglypuff(ModeInfo *mi)
975 jigglystruct *js = &jss[MI_SCREEN(mi)];
977 glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(js->glx_context));
979 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
981 glMatrixMode(GL_MODELVIEW);
983 glTranslatef(0,0,-10);
985 glRotatef(js->angle, sin(js->axis), cos(js->axis), -sin(js->axis));
986 glTranslatef(0, 0, 5);
987 if(!(js->button_down)) {
988 if((js->angle += js->speed) >= 360.0f ) {
991 if((js->axis+=0.01f) >= 2*M_PI ) {
996 /* Do it twice because we don't track the device's orientation. */
997 glRotatef( current_device_rotation(), 0, 0, 1);
998 gltrackball_rotate(js->trackball);
999 glRotatef(-current_device_rotation(), 0, 0, 1);
1001 if(js->color_style == COLOR_STYLE_CYCLE) {
1003 vector_add(js->jiggly_color, js->color_dir, js->jiggly_color);
1005 for(i=0; i<3; i++) {
1006 if(js->jiggly_color[i] > 1.0 || js->jiggly_color[i] < 0.3) {
1007 js->color_dir[i] = (-js->color_dir[i]);
1008 js->jiggly_color[i] += js->color_dir[i];
1011 glColor4fv(js->jiggly_color);
1014 mi->polygon_count = jigglypuff_render(js);
1019 glXSwapBuffers(MI_DISPLAY(mi), MI_WINDOW(mi));
1022 ENTRYPOINT void init_jigglypuff(ModeInfo *mi)
1028 jss = (jigglystruct*)
1029 calloc(MI_NUM_SCREENS(mi), sizeof(jigglystruct));
1031 fprintf(stderr, "%s: No..memory...must...abort..\n", progname);
1036 js = &jss[MI_SCREEN(mi)];
1038 js->do_wireframe = MI_IS_WIREFRAME(mi);
1039 # ifdef HAVE_JWZGLES
1040 js->do_wireframe = 0; /* GL_LINE unimplemented */
1043 js->shininess = shininess;
1045 subdivs = (complexity==1) ? 4 : (complexity==2) ? 5
1046 : (complexity==3) ? 6 : 5;
1048 js->spooky = spooky << (subdivs-3);
1050 if(!parse_color(js)) {
1051 fprintf(stderr, "%s: Bad color specification: '%s'.\n", progname, color);
1056 randomize_parameters(js);
1058 js->angle = frand(180);
1059 js->axis = frand(M_PI);
1061 js->shape = tesselated_tetrahedron(1, subdivs, js);
1064 solid_spherify(js->shape, 1);
1066 if(js->color_style == COLOR_STYLE_CLOWNBARF)
1067 clownbarf_colorize(js->shape);
1069 calculate_parameters(js, subdivs);
1071 if((js->glx_context = init_GL(mi)) != NULL) {
1072 glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(js->glx_context));
1073 setup_opengl(mi, js);
1074 reshape_jigglypuff(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
1079 js->trackball = gltrackball_init();
1080 /* _DEBUG("distance : %f\nhold : %f\nspherify : %f\ndamping : %f\ndfact : %f\n",
1081 js->stable_distance, js->hold_strength, js->spherify_strength,
1082 js->damping_velocity, js->damping_factor);
1083 _DEBUG("wire : %d\nspooky : %d\nstyle : %d\nshininess : %d\n",
1084 js->do_wireframe, js->spooky, js->color_style, js->shininess);*/
1087 XSCREENSAVER_MODULE ("JigglyPuff", jigglypuff)
1091 /* This is the end of the file */