From http://www.jwz.org/xscreensaver/xscreensaver-5.30.tar.gz
[xscreensaver] / hacks / glx / mirrorblob.c
1 /* mirrorblob  Copyright (c) 2003 Jon Dowdall <jon.dowdall@bigpond.com> */
2 /*
3  * Permission to use, copy, modify, and distribute this software and its
4  * documentation for any purpose and without fee is hereby granted,
5  * provided that the above copyright notice appear in all copies and that
6  * both that copyright notice and this permission notice appear in
7  * supporting documentation.
8  *
9  * This file is provided AS IS with no warranties of any kind.  The author
10  * shall have no liability with respect to the infringement of copyrights,
11  * trade secrets or any patents by this file or any part thereof.  In no
12  * event will the author be liable for any lost revenue or profits or
13  * other special, indirect and consequential damages.
14  *
15  * Revision History:
16  * 23-Sep-2003:  jon.dowdall@bigpond.com  Created module "blob"
17  * 19-Oct-2003:  jon.dowdall@bigpond.com  Added texturing
18  * 21-Oct-2003:                           Renamed to mirrorblob
19  * 10-Feb-2004:  jon.dowdall@bigpond.com  Added motion blur
20  * 28-Jan-2006:  jon.dowdall@bigpond.com  Big clean up and bug fixes
21  * 13-Apr-2009:  jon.dowdall@gmail.com    Fixed Mac version
22  *
23  * The mirrorblob screensaver draws a pulsing blob on the screen.  Options
24  * include adding a background (via screen_to_texture), texturing the blob,
25  * making the blob semi-transparent and varying the resolution of the blob
26  * tessellation.
27  *
28  * The blob was inspired by a lavalamp is in no way a simulation.  The code is
29  * just an attempt to generate some eye-candy.
30  *
31  * Much of xmirrorblob code framework is taken from the pulsar module by David
32  * Konerding and the glslideshow by Mike Oliphant and Jamie Zawinski.
33  *
34  */
35
36 #include <math.h>
37
38 #ifdef STANDALONE
39 #define DEFAULTS "*delay:             " DEF_DELAY "\n"                      \
40                  "*showFPS:           " DEF_FPS   "\n"                      \
41                  "*useSHM:              True       \n"                      \
42                  "*desktopGrabber:  xscreensaver-getimage -no-desktop %s\n" \
43                  "*grabDesktopImages:   True  \n"                           \
44                  "*chooseRandomImages:  True  \n"
45
46 # define refresh_mirrorblob 0
47 # include "xlockmore.h"
48 #else /* !STANDALONE */
49 # include "xlock.h"        /* from the xlockmore distribution */
50 #endif /* !STANDALONE */
51
52 #ifdef USE_GL /* whole file */
53
54
55 #define DEF_DELAY            "10000"
56 #define DEF_FPS              "False"
57 #define DEF_WIRE             "False"
58 #define DEF_BLEND            "1.0"
59 #define DEF_FOG              "False"
60 #define DEF_ANTIALIAS        "False"
61 #define DEF_WALLS            "False"
62 #define DEF_COLOUR           "False"
63 #define DEF_ASYNC            "True"
64 #define DEF_TEXTURE          "True"
65 #define DEF_OFFSET_TEXTURE   "False"
66 #define DEF_PAINT_BACKGROUND "True"
67 #define DEF_RESOLUTION       "30"
68 #define DEF_BUMPS            "10"
69 #define DEF_MOTION_BLUR      "0.0"
70 #define DEF_INCREMENTAL      "0"
71 #define DEF_HOLD_TIME        "30.0"
72 #define DEF_FADE_TIME        "5.0"
73 #define DEF_ZOOM             "1.0"
74
75 #ifdef HAVE_XMU
76 # ifndef VMS
77 #  include <X11/Xmu/Drawing.h>
78 #else  /* VMS */
79 #  include <Xmu/Drawing.h>
80 # endif /* VMS */
81 #endif
82
83 #include "gltrackball.h"
84 #include "grab-ximage.h"
85
86 #undef countof
87 #define countof(x) (sizeof((x)) / sizeof((*x)))
88
89 #define PI  3.1415926535897
90
91 /* Options from command line */
92 static GLfloat blend;
93 static Bool wireframe;
94 static Bool do_fog;
95 static Bool do_antialias;
96 static Bool do_walls;
97 static Bool do_texture;
98 static Bool do_paint_background;
99 static Bool do_colour;
100 static Bool offset_texture;
101 static int resolution;
102 static int bumps;
103 static float motion_blur;
104 static float fade_time;
105 static float hold_time;
106 static float zoom;
107
108 /* Internal parameters based on supplied options */
109 static Bool culling;
110 static Bool load_textures;
111
112 static XrmOptionDescRec opts[] = {
113     {"-wire",             ".blob.wire",             XrmoptionNoArg, "true" },
114     {"+wire",             ".blob.wire",             XrmoptionNoArg, "false" },
115     {"-blend",            ".blob.blend",            XrmoptionSepArg, 0 },
116     {"-fog",              ".blob.fog",              XrmoptionNoArg, "true" },
117     {"+fog",              ".blob.fog",              XrmoptionNoArg, "false" },
118     {"-antialias",        ".blob.antialias",        XrmoptionNoArg, "true" },
119     {"+antialias",        ".blob.antialias",        XrmoptionNoArg, "false" },
120     {"-walls",            ".blob.walls",            XrmoptionNoArg, "true" },
121     {"+walls",            ".blob.walls",            XrmoptionNoArg, "false" },
122     {"-texture",          ".blob.texture",          XrmoptionNoArg, "true" },
123     {"+texture",          ".blob.texture",          XrmoptionNoArg, "false" },
124     {"-colour",           ".blob.colour",           XrmoptionNoArg, "true" },
125     {"+colour",           ".blob.colour",           XrmoptionNoArg, "false" },
126     {"-offset-texture",   ".blob.offsetTexture",    XrmoptionNoArg, "true" },
127     {"+offset-texture",   ".blob.offsetTexture",    XrmoptionNoArg, "false" },
128     {"-paint-background", ".blob.paintBackground",  XrmoptionNoArg, "true" },
129     {"+paint-background", ".blob.paintBackground",  XrmoptionNoArg, "false" },
130     {"-resolution",       ".blob.resolution",       XrmoptionSepArg, NULL },
131     {"-bumps",            ".blob.bumps",            XrmoptionSepArg, NULL },
132     {"-motion-blur",      ".blob.motionBlur",       XrmoptionSepArg, 0 },
133     {"-fade-time",        ".blob.fadeTime",         XrmoptionSepArg, 0 },
134     {"-hold-time",        ".blob.holdTime",         XrmoptionSepArg, 0 },
135     {"-zoom",             ".blob.zoom",             XrmoptionSepArg, 0 },
136 };
137
138 static argtype vars[] = {
139     {&wireframe,    "wire",         "Wire",      DEF_WIRE,      t_Bool},
140     {&blend,        "blend",        "Blend",     DEF_BLEND,     t_Float},
141     {&do_fog,       "fog",          "Fog",       DEF_FOG,       t_Bool},
142     {&do_antialias, "antialias",    "Antialias", DEF_ANTIALIAS, t_Bool},
143     {&do_walls,     "walls",        "Walls",     DEF_WALLS,     t_Bool},
144     {&do_texture,   "texture",      "Texture",   DEF_TEXTURE,   t_Bool},
145     {&do_colour,    "colour",       "Colour",    DEF_COLOUR,   t_Bool},
146     {&offset_texture, "offsetTexture","OffsetTexture", DEF_OFFSET_TEXTURE, t_Bool},
147     {&do_paint_background,"paintBackground","PaintBackground", DEF_PAINT_BACKGROUND, t_Bool},
148     {&resolution,   "resolution",   "Resolution",   DEF_RESOLUTION,   t_Int},
149     {&bumps,        "bumps",        "Bump",         DEF_BUMPS, t_Int},
150     {&motion_blur,  "motionBlur",   "MotionBlur",   DEF_MOTION_BLUR,  t_Float},
151     {&fade_time,    "fadeTime",     "FadeTime",     DEF_FADE_TIME,    t_Float},
152     {&hold_time,    "holdTime",     "HoldTime",     DEF_HOLD_TIME,    t_Float},
153     {&zoom,         "zoom",         "Zoom",         DEF_ZOOM,         t_Float},
154 };
155
156
157 static OptionStruct desc[] =
158 {
159     {"-/+ wire", "whether to do use wireframe instead of filled (faster)"},
160     {"-/+ blend", "whether to do enable blending (slower)"},
161     {"-/+ fog", "whether to do enable fog (slower)"},
162     {"-/+ antialias", "whether to do enable antialiased lines (slower)"},
163     {"-/+ walls", "whether to add walls to the blob space (slower)"},
164     {"-/+ texture", "whether to add a texture to the blob (slower)"},
165     {"-/+ colour", "whether to colour the blob"},
166     {"-/+ offset_texture", "whether to offset texture co-ordinates"},
167     {"-/+ paint_background", "whether to display a background texture (slower)"},
168     {"-resolution", "Resolution of blob tesselation"},
169     {"-bumps", "Number of bumps used to disturb blob"},
170     {"-motion_blur", "Fade blob images (higher number = faster fade)"},
171     {"-fade_time", "Number of frames to transistion to next image"},
172     {"-hold_time", "Number of frames before next image"},
173 };
174
175 ENTRYPOINT ModeSpecOpt mirrorblob_opts = {countof(opts), opts, countof(vars), vars, desc};
176
177 #ifdef USE_MODULES
178 ModStruct   mirrorblob_description =
179 {"mirrorblob", "init_mirrorblob", "draw_mirrorblob", "release_mirrorblob",
180  "draw_mirrorblob", "init_mirrorblob", "handle_event", &mirrorblob_opts,
181  1000, 1, 2, 1, 4, 1.0, "",
182  "OpenGL mirrorblob", 0, NULL};
183 #endif
184
185 /*****************************************************************************
186  * Types used in blob code
187  *****************************************************************************/
188
189 typedef struct
190 {
191   GLfloat x, y;
192 } Vector2D;
193
194 typedef struct
195 {
196   GLfloat x, y, z;
197 } Vector3D;
198
199 typedef struct
200 {
201   GLfloat w;
202   GLfloat x;
203   GLfloat y;
204   GLfloat z;
205 } Quaternion;
206
207 typedef struct
208 {
209   GLubyte red, green, blue, alpha;
210 } Colour;
211
212 typedef struct
213 {
214   Vector3D initial_position;
215   Vector3D position;
216   Vector3D normal;
217 } Node_Data;
218
219 typedef struct
220 {
221   int node1, node2, node3;
222   Vector3D normal;
223   double length1, length2, length3;
224 } Face_Data;
225
226 /* Structure to hold data about bumps used to distortion sphere */
227 typedef struct
228 {
229   double cx, cy, cpower, csize;
230   double ax, ay, power, size;
231   double mx, my, mpower, msize;
232   double vx, vy, vpower, vsize;
233   Vector3D pos;
234 } Bump_Data;
235
236 /* Vertices of a tetrahedron */
237 #define sqrt_3 0.5773502692
238 /*#undef sqrt_3
239 #define sqrt_3 1.0*/
240 #define PPP {  sqrt_3,  sqrt_3,  sqrt_3 }       /* +X, +Y, +Z */
241 #define MMP { -sqrt_3, -sqrt_3,  sqrt_3 }       /* -X, -Y, +Z */
242 #define MPM { -sqrt_3,  sqrt_3, -sqrt_3 }       /* -X, +Y, -Z */
243 #define PMM {  sqrt_3, -sqrt_3, -sqrt_3 }       /* +X, -Y, -Z */
244
245 /* Structure describing a tetrahedron */
246 static Vector3D tetrahedron[4][3] = {
247     {PPP, MMP, MPM},
248     {PMM, MPM, MMP},
249     {PPP, MPM, PMM},
250     {PPP, PMM, MMP}
251 };
252
253 /*****************************************************************************
254  * Static blob data
255  *****************************************************************************/
256
257 static const Vector3D zero_vector = { 0.0, 0.0, 0.0 };
258
259 /* Use 2 textures to allow a gradual fade between images */
260 #define NUM_TEXTURES 2
261 #define BUMP_ARRAY_SIZE 1024
262
263 typedef enum
264 {
265   INITIALISING,
266   HOLDING,
267   LOADING,
268   TRANSITIONING
269 } Frame_State;
270
271 /* structure for holding the mirrorblob data */
272 typedef struct {
273   int screen_width, screen_height;
274   GLXContext *glx_context;
275   Window window;
276   XColor fg, bg;
277
278   /* Parameters controlling the position of the blob as a whole */
279   Vector3D blob_center;
280   Vector3D blob_anchor;
281   Vector3D blob_velocity;
282   Vector3D blob_force;
283
284   /* Count of the total number of nodes and faces used to tesselate the blob */
285   int num_nodes;
286   int num_faces;
287
288   Node_Data *nodes;
289   Face_Data *faces;
290   
291   Vector3D *dots;
292   Vector3D *normals;
293   Colour   *colours;
294   Vector2D *tex_coords;
295
296   /* Pointer to the bump function results */
297   double *bump_shape, *wall_shape;
298
299   Bump_Data *bump_data;
300
301   /* Use 2 textures to allow a gradual fade between images */
302   int current_texture;
303
304   /* Ratio of used texture size to total texture size */
305   GLfloat tex_width[NUM_TEXTURES], tex_height[NUM_TEXTURES];
306   GLuint textures[NUM_TEXTURES];
307
308   Frame_State state;
309   double state_start_time;
310
311   int colour_cycle;
312
313   Bool mipmap_p;
314   Bool waiting_for_image_p;
315   Bool first_image_p;
316
317   trackball_state *trackball;
318   int button_down;
319
320 } mirrorblobstruct;
321
322 static mirrorblobstruct *Mirrorblob = NULL;
323
324 /******************************************************************************
325  *
326  * Returns the current time in seconds as a double.  Shamelessly borrowed from
327  * glslideshow.
328  *
329  */
330 static double
331 double_time (void)
332 {
333   struct timeval now;
334 # ifdef GETTIMEOFDAY_TWO_ARGS
335   struct timezone tzp;
336   gettimeofday(&now, &tzp);
337 # else
338   gettimeofday(&now);
339 # endif
340
341   return (now.tv_sec + ((double) now.tv_usec * 0.000001));
342 }
343
344 /******************************************************************************
345  *
346  * Change to the projection matrix and set our viewing volume.
347  *
348  */
349 static void
350 reset_projection(int width, int height)
351 {
352   glMatrixMode (GL_PROJECTION);
353   glLoadIdentity ();
354   gluPerspective (60.0, 1.0, 1.0, 1024.0 );
355   glMatrixMode (GL_MODELVIEW);
356   glLoadIdentity ();
357 }
358
359 /******************************************************************************
360  *
361  * Calculate the dot product of two vectors u and v
362  * Dot product u.v = |u||v|cos(theta)
363  * Where theta = angle between u and v
364  */
365 static inline double
366 dot (const Vector3D u, const Vector3D v)
367 {
368   return (u.x * v.x) + (u.y * v.y) + (u.z * v.z);
369 }
370
371 /******************************************************************************
372  *
373  * Calculate the cross product of two vectors.
374  * Gives a vector perpendicular to u and v with magnitude |u||v|sin(theta)
375  * Where theta = angle between u and v
376  */
377 static inline Vector3D
378 cross (const Vector3D u, const Vector3D v)
379 {
380   Vector3D result;
381
382   result.x = (u.y * v.z - u.z * v.y);
383   result.y = (u.z * v.x - u.x * v.z);
384   result.z = (u.x * v.y - u.y * v.x);
385
386   return result;
387 }
388
389 /******************************************************************************
390  *
391  * Add vector v to vector u
392  */
393 static inline void
394 add (Vector3D *u, const Vector3D v)
395 {
396   u->x = u->x + v.x;
397   u->y = u->y + v.y;
398   u->z = u->z + v.z;
399 }
400
401 /******************************************************************************
402  *
403  * Subtract vector v from vector u
404  */
405 static inline Vector3D
406 subtract (const Vector3D u, const Vector3D v)
407 {
408   Vector3D result;
409
410   result.x = u.x - v.x;
411   result.y = u.y - v.y;
412   result.z = u.z - v.z;
413
414   return result;
415 }
416
417 /******************************************************************************
418  *
419  * multiply vector v by scalar s
420  */
421 static inline Vector3D
422 scale (const Vector3D v, const double s)
423 {
424   Vector3D result;
425     
426   result.x = v.x * s;
427   result.y = v.y * s;
428   result.z = v.z * s;
429   return result;
430 }
431
432 /******************************************************************************
433  *
434  * normalise vector v
435  */
436 static inline Vector3D
437 normalise (const Vector3D v)
438 {
439   Vector3D result;
440   double magnitude;
441
442   magnitude = sqrt (dot(v, v));
443
444   if (magnitude > 1e-300)
445     {
446       result = scale (v, 1.0 / magnitude);
447     }
448   else
449     {
450       printf("zero\n");
451       result = zero_vector;
452     }
453   return result;
454 }
455
456 /******************************************************************************
457  *
458  * Calculate the transform matrix for the given quaternion
459  */
460 static void
461 quaternion_transform (Quaternion q, GLfloat * transform)
462 {
463   GLfloat x, y, z, w;
464   x = q.x;
465   y = q.y;
466   z = q.z;
467   w = q.w;
468
469   transform[0] = (w * w) + (x * x) - (y * y) - (z * z);
470   transform[1] = (2.0 * x * y) + (2.0 * w * z);
471   transform[2] = (2.0 * x * z) - (2.0 * w * y);
472   transform[3] = 0.0;
473
474   transform[4] = (2.0 * x * y) - (2.0 * w * z);
475   transform[5] = (w * w) - (x * x) + (y * y) - (z * z);
476   transform[6] = (2.0 * y * z) + (2.0 * w * x);
477   transform[7] = 0.0;
478
479   transform[8] = (2.0 * x * z) + (2.0 * w * y);
480   transform[9] = (2.0 * y * z) - (2.0 * w * x);
481   transform[10] = (w * w) - (x * x) - (y * y) + (z * z);
482   transform[11] = 0.0;
483
484   transform[12] = 0.0;
485   transform[13] = 0.0;
486   transform[14] = 0.0;
487   transform[15] = (w * w) + (x * x) + (y * y) + (z * z);
488 }
489
490 /******************************************************************************
491  *
492  * Apply a matrix transform to the given vector
493  */
494 static inline Vector3D
495 vector_transform (Vector3D u, GLfloat * t)
496 {
497   Vector3D result;
498
499   result.x = (u.x * t[0] + u.y * t[4] + u.z * t[8] + 1.0 * t[12]);
500   result.y = (u.x * t[1] + u.y * t[5] + u.z * t[9] + 1.0 * t[13]);
501   result.z = (u.x * t[2] + u.y * t[6] + u.z * t[10] + 1.0 * t[14]);
502
503   return result;
504 }
505
506 /******************************************************************************
507  *
508  * Return a node that is on an arc between node1 and node2, where distance
509  * is the proportion of the distance from node1 to the total arc.
510  */
511 static Vector3D
512 partial (Vector3D node1, Vector3D node2, double distance)
513 {
514   Vector3D result;
515   Vector3D rotation_axis;
516   GLfloat transformation[16];
517   double angle;
518   Quaternion rotation;
519
520   rotation_axis = normalise (cross (node1, node2));
521   angle = acos (dot (node1, node2)) * distance;
522
523   rotation.x = rotation_axis.x * sin (angle / 2.0);
524   rotation.y = rotation_axis.y * sin (angle / 2.0);
525   rotation.z = rotation_axis.z * sin (angle / 2.0);
526   rotation.w = cos (angle / 2.0);
527
528   quaternion_transform (rotation, transformation);
529
530   result = vector_transform (node1, transformation);
531
532   return result;
533 }
534
535 /****************************************************************************
536  *
537  * Callback indicating a texture has loaded
538  */
539 static void
540 image_loaded_cb (const char *filename, XRectangle *geometry,
541                  int image_width, int image_height, 
542                  int texture_width, int texture_height,
543                  void *closure)
544 {
545   mirrorblobstruct *mp = (mirrorblobstruct *) closure;
546   GLint texid = -1;
547   int texture_index = -1;
548   int i;
549
550   glGetIntegerv (GL_TEXTURE_BINDING_2D, &texid);
551   if (texid < 0) abort();
552
553   for (i = 0; i < NUM_TEXTURES; i++) {
554     if (mp->textures[i] == texid) {
555       texture_index = i;
556       break;
557     }
558   }
559   if (texture_index < 0) abort();
560
561   mp->tex_width [texture_index] =  (GLfloat) image_width  / texture_width;
562   mp->tex_height[texture_index] = -(GLfloat) image_height / texture_height;
563
564   glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
565   glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
566                    (mp->mipmap_p ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR));
567   glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
568   glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
569   glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
570
571   mp->waiting_for_image_p = False;
572   mp->first_image_p = True;
573 }
574
575 /* Load a new file into a texture
576  */
577 static void
578 grab_texture(ModeInfo *mi, int texture_index)
579 {
580   mirrorblobstruct *mp = &Mirrorblob[MI_SCREEN(mi)];
581         
582   {
583     int w = (MI_WIDTH(mi)  / 2) - 1;
584     int h = (MI_HEIGHT(mi) / 2) - 1;
585     if (w <= 10) w = 10;
586     if (h <= 10) h = 10;
587         
588     mp->waiting_for_image_p = True;
589     mp->mipmap_p = True;
590     load_texture_async (mi->xgwa.screen, mi->window,
591                         *mp->glx_context, w, h, mp->mipmap_p, 
592                         mp->textures[texture_index],
593                         image_loaded_cb, mp);
594   }
595 }
596
597 /******************************************************************************
598  *
599  * Generate internal parameters based on supplied options the parameters to
600  * ensure they are consistant.
601  */
602 static void
603 set_parameters(void)
604 {
605 # ifdef HAVE_JWZGLES /* #### glPolygonMode other than GL_FILL unimplemented */
606   wireframe = 0;
607 # endif
608
609   /* In wire frame mode do not draw a texture */
610   if (wireframe)
611     {
612       do_texture = False;
613       blend = 1.0;
614     }
615     
616   /* Need to load textures if either the blob or the backgound has an image */
617   if (do_texture || do_paint_background)
618     {
619       load_textures = True;
620     }
621   else
622     {
623       load_textures = False;
624     }
625     
626   /* If theres no texture don't calculate co-ordinates. */
627   if (!do_texture)
628     {
629       offset_texture = False;
630     }
631     
632   culling = True;
633 }
634
635 /******************************************************************************
636  *
637  * Initialise the openGL state data.
638  */
639 static void
640 initialize_gl(ModeInfo *mi, GLsizei width, GLsizei height)
641 {
642   mirrorblobstruct *gp = &Mirrorblob[MI_SCREEN(mi)];
643     
644   /* Lighting values */
645   GLfloat ambientLight[] = { 0.2f, 0.2f, 0.2f, 1.0f };
646
647   GLfloat lightPos0[] = {500.0f, 100.0f, 200.0f, 1.0f };
648   GLfloat whiteLight0[] = { 0.0f, 0.0f, 0.0f, 1.0f };
649   GLfloat sourceLight0[] = { 0.6f, 0.6f, 0.6f, 1.0f };
650   GLfloat specularLight0[] = { 0.8f, 0.8f, 0.9f, 1.0f };
651
652   GLfloat lightPos1[] = {-50.0f, -100.0f, 2500.0f, 1.0f };
653   GLfloat whiteLight1[] = { 0.0f, 0.0f, 0.0f, 1.0f };
654   GLfloat sourceLight1[] = { 0.6f, 0.6f, 0.6f, 1.0f };
655   GLfloat specularLight1[] = { 0.7f, 0.7f, 0.7f, 1.0f };
656
657   GLfloat specref[] = { 1.0f, 1.0f, 1.0f, 1.0f };
658
659   GLfloat fogColor[4] = { 0.4, 0.4, 0.5, 0.1 };
660
661   /* Set the internal parameters based on the configuration settings */
662   set_parameters();
663
664   /* Set the viewport to the width and heigh of the window */
665   glViewport (0, 0, width, height ); 
666
667   if (do_antialias)
668     {
669       blend = 1.0;
670       glEnable(GL_LINE_SMOOTH);
671       glEnable(GL_POLYGON_SMOOTH);
672     }
673
674   /* The blend function is used for trasitioning between two images even when
675    * blend is not selected.
676    */
677   glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
678  
679   if (do_fog)
680     {
681       glEnable(GL_FOG);
682       glFogfv(GL_FOG_COLOR, fogColor);
683       glFogf(GL_FOG_DENSITY, 0.50);
684       glFogf(GL_FOG_START, 15.0);
685       glFogf(GL_FOG_END, 30.0);
686     }
687
688   /* Set the shading model to smooth (Gouraud shading). */
689   glShadeModel (GL_SMOOTH);
690
691   glLightModelfv (GL_LIGHT_MODEL_AMBIENT, ambientLight);
692   glLightfv (GL_LIGHT0, GL_AMBIENT, whiteLight0);
693   glLightfv (GL_LIGHT0, GL_DIFFUSE, sourceLight0);
694   glLightfv (GL_LIGHT0, GL_SPECULAR, specularLight0);
695   glLightfv (GL_LIGHT0, GL_POSITION, lightPos0);
696   glEnable (GL_LIGHT0);
697   glLightfv (GL_LIGHT1, GL_AMBIENT, whiteLight1);
698   glLightfv (GL_LIGHT1, GL_DIFFUSE, sourceLight1);
699   glLightfv (GL_LIGHT1, GL_SPECULAR, specularLight1);
700   glLightfv (GL_LIGHT1, GL_POSITION, lightPos1);
701   glEnable (GL_LIGHT1);
702   glEnable (GL_LIGHTING);
703
704   /* Enable color tracking */
705   glEnable (GL_COLOR_MATERIAL);
706
707   /* Set Material properties to follow glColor values */
708   glColorMaterial (GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
709
710   /* Set all materials to have specular reflectivity */
711   glMaterialfv (GL_FRONT, GL_SPECULAR, specref);
712   glMateriali (GL_FRONT, GL_SHININESS, 32);
713
714   /* Let GL implementation scale normal vectors. */
715   glEnable (GL_NORMALIZE);
716
717   /* Enable Arrays */
718   if (load_textures)
719     {
720       glLightModeli (GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);
721       glEnable (GL_TEXTURE_2D);
722
723       gp->current_texture = 0;
724       glGenTextures(NUM_TEXTURES, gp->textures);
725       grab_texture(mi, gp->current_texture);
726
727       glMatrixMode (GL_TEXTURE);
728       glRotated (180.0, 1.0, 0.0, 0.0);
729       glMatrixMode (GL_MODELVIEW);
730     }
731
732   /* Clear the buffer since this is not done during a draw with motion blur */
733   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
734 }
735
736 /******************************************************************************
737  *
738  * Initialise the openGL state data.
739  */
740 static void
741 set_blob_gl_state(GLfloat alpha)
742 {
743   if (do_antialias)
744     {
745       glEnable(GL_LINE_SMOOTH);
746       glEnable(GL_POLYGON_SMOOTH);
747     }
748
749   if (wireframe)
750     {
751       glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
752     }
753   else
754     {
755       glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
756     }
757
758   /* The blend function is used for trasitioning between two images even when
759    * blend is not selected.
760    */
761   glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
762  
763   /* Culling. */
764   if (culling)
765     {
766       glCullFace (GL_BACK);
767       glEnable (GL_CULL_FACE);
768       glFrontFace (GL_CCW);
769     }
770   else
771     {
772       glDisable (GL_CULL_FACE);
773     }
774     
775   if (blend < 1.0)
776     {
777       glEnable (GL_BLEND);
778       glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
779       /* Set the default blob colour to off-white. */
780       glColor4f (0.9, 0.9, 1.0, alpha);
781     }
782   else
783     {
784       glDisable(GL_BLEND);
785       glColor4f (0.9, 0.9, 1.0, 1.0);
786     }
787     
788   glEnable(GL_DEPTH_TEST);
789   glEnable(GL_LIGHTING);
790 }
791
792 /******************************************************************************
793  *
794  * Initialise the data required to draw the blob allocating the memory as
795  * necessary.
796  *
797  * Return 0 on success.
798  */
799 static int
800 initialise_blob(mirrorblobstruct *gp,
801                 int width,
802                 int height,
803                 int bump_array_size)
804 {
805   /* Loop variables */    
806   int i, u, v, node, side, face, base, base2 = 0;
807   int nodes_on_edge = resolution;
808   Vector3D node1, node2, result;
809
810   if (nodes_on_edge < 2)
811     return -1;
812
813   gp->num_nodes = 2 * nodes_on_edge * nodes_on_edge - 4 * nodes_on_edge + 4;
814   gp->num_faces = 4 * (nodes_on_edge - 1) * (nodes_on_edge - 1);
815  
816   gp->nodes = (Node_Data *) malloc (gp->num_nodes * sizeof (Node_Data));
817   if (!gp->nodes)
818     {
819       fprintf (stderr, "Couldn't allocate gp->nodes buffer\n");
820       return -1;
821     }
822
823   gp->faces = (Face_Data *) malloc (gp->num_faces * sizeof (Face_Data));
824   if (!gp->faces)
825     {
826       fprintf (stderr, "Couldn't allocate faces data buffer\n");
827       return -1;
828     }
829
830   gp->bump_data = (Bump_Data *) malloc (bumps * sizeof (Bump_Data));
831   if (!gp->bump_data)
832     {
833       fprintf(stderr, "Couldn't allocate bump data buffer\n");
834       return -1;
835     }
836
837   gp->bump_shape = (double *)malloc(bump_array_size * sizeof(double));
838   if (!gp->bump_shape)
839     {
840       fprintf(stderr, "Couldn't allocate bump buffer\n");
841       return -1;
842     }
843
844   gp->wall_shape = (double *)malloc(bump_array_size * sizeof(double));
845   if (!gp->wall_shape)
846     {
847       fprintf(stderr, "Couldn't allocate wall bump buffer\n");
848       return -1;
849     }
850
851         
852   gp->dots = (Vector3D *)malloc(gp->num_nodes * sizeof(Vector3D));
853   if (!gp->dots)
854     {
855       fprintf(stderr, "Couldn't allocate nodes buffer\n");
856       return -1;
857     }
858
859   gp->normals = (Vector3D *)malloc(gp->num_nodes * sizeof(Vector3D));
860   if (!gp->normals)
861     {
862       fprintf(stderr, "Couldn't allocate normals buffer\n");
863       return -1;
864     }
865
866   gp->colours = (Colour *)malloc(gp->num_nodes * sizeof(Colour));
867   if (!gp->colours)
868     {
869       fprintf(stderr, "Couldn't allocate colours buffer\n");
870       return -1;
871     }
872
873   gp->tex_coords = (Vector2D *)malloc(gp->num_nodes * sizeof(Vector2D));
874   if (!gp->tex_coords)
875     {
876       fprintf(stderr, "Couldn't allocate gp->tex_coords buffer\n");
877       return -1;
878     }
879
880         
881   /* Initialise bump data */
882   for (i = 0; i < bumps; i++)
883     {
884       gp->bump_data[i].ax = 2.0 * (((double)random() / (double)RAND_MAX) - 0.5);
885       gp->bump_data[i].ay = 2.0 * (((double)random() / (double)RAND_MAX) - 0.5);
886       gp->bump_data[i].power = (5.0 / pow(bumps, 0.75)) * (((double)random() / (double)RAND_MAX) - 0.5);
887       gp->bump_data[i].size = 0.1 + 0.5 * (((double)random() / (double)RAND_MAX));
888
889       gp->bump_data[i].pos.x = 1.5 * sin(PI * gp->bump_data[i].ay)
890         * cos(PI *  gp->bump_data[i].ax);
891       gp->bump_data[i].pos.y = 1.5 * cos(PI * gp->bump_data[i].ay);
892       gp->bump_data[i].pos.z = 1.5 * sin(PI * gp->bump_data[i].ay)
893         * sin(PI *  gp->bump_data[i].ax);
894
895       gp->bump_data[i].cx = 2.0 * (((double)random() / (double)RAND_MAX) - 0.5);
896       gp->bump_data[i].cy = 2.0 * (((double)random() / (double)RAND_MAX) - 0.5);
897       gp->bump_data[i].cpower = (5.0 / pow(bumps, 0.75)) * (((double)random() / (double)RAND_MAX) - 0.5);
898       gp->bump_data[i].csize = 0.35; /*0.1 + 0.25 * (((double)random() / (double)RAND_MAX));*/
899
900       gp->bump_data[i].vx = 0.0;
901       gp->bump_data[i].vy = 0.0;
902       gp->bump_data[i].vpower = 0.0;
903       gp->bump_data[i].vsize = 0.0;
904
905       gp->bump_data[i].mx = 0.003 * ((double)random() / (double)RAND_MAX);
906       gp->bump_data[i].my = 0.003 * ((double)random() / (double)RAND_MAX);
907       gp->bump_data[i].mpower = 0.003 * ((double)random() / (double)RAND_MAX);
908       gp->bump_data[i].msize = 0.003 * ((double)random() / (double)RAND_MAX);
909     }
910
911   /* Initialise lookup table of bump strength */
912   for (i = 0; i < bump_array_size; i++)
913     {
914       double xd, xd2;
915       xd = i / (double)bump_array_size;
916
917       xd2 = 48.0 * xd * xd;
918       gp->bump_shape[i] = 0.1 / (xd2 + 0.1);
919
920       xd2 = 40.0 * xd * xd * xd * xd;
921       gp->wall_shape[i] = 0.4 / (xd2 + 0.1);
922     }
923
924   node = 0;
925   face = 0;
926   for (side = 0; side < 4; side++)
927     {
928       base = node;
929       if (side == 2) 
930         {
931           base2 = node;
932         }
933       /*
934        * The start and end of the for loops below are modified based on the 
935        * side of the tetrahedron that is being calculated to avoid duplication
936        * of the gp->nodes that are on the edges of the tetrahedron. 
937        */
938       for (u = (side > 1); u < (nodes_on_edge - (side > 0)); u++)
939         {
940           node1 = partial (normalise (tetrahedron[side][0]),
941                            normalise (tetrahedron[side][1]),
942                            u / (double) (nodes_on_edge - 1));
943           node2 = partial (normalise (tetrahedron[side][0]),
944                            normalise (tetrahedron[side][2]),
945                            u / (double) (nodes_on_edge - 1));
946
947           for (v = (side > 1); v <= (u - (side > 2)); v++)
948             {
949               if (u > 0)
950                 result = partial (node1, node2, v / (double) u);
951               else
952                 result = node1;
953
954               gp->nodes[node].position = normalise (result);
955               gp->nodes[node].initial_position = gp->nodes[node].position;
956               gp->nodes[node].normal = zero_vector;
957               node++;
958             }
959         }
960  
961       /*
962        * Determine which nodes make up each face.  The complexity is caused 
963        * by having to determine the correct nodes for the edges of the
964        * tetrahedron since the common nodes on the edges are only calculated
965        * once (see above).
966        */
967       for (u = 0; u < (nodes_on_edge - 1); u++)
968         {
969           for (v = 0; v <= u; v++)
970             {
971               {
972                 if (side < 2)
973                   {
974                     gp->faces[face].node1 = base + ((u * (u + 1)) / 2) + v;
975                     gp->faces[face].node2 =
976                       base + ((u + 1) * (u + 2)) / 2 + v + 1;
977                     gp->faces[face].node3 =
978                       base + ((u + 1) * (u + 2)) / 2 + v;
979
980                     if ((side == 1) && (u == (nodes_on_edge - 2)))
981                       {
982                         gp->faces[face].node3 =
983                           ((u + 1) * (u + 2)) / 2 +
984                           nodes_on_edge - v - 1;
985                         gp->faces[face].node2 =
986                           ((u + 1) * (u + 2)) / 2 +
987                           nodes_on_edge - v - 2;
988                       }
989                   }
990                 else if (side < 3)
991                   {
992                     gp->faces[face].node1 =
993                       base + (((u - 1) * u) / 2) + v - 1;
994                     gp->faces[face].node2 = base + ((u) * (u + 1)) / 2 + v;
995                     gp->faces[face].node3 =
996                       base + ((u) * (u + 1)) / 2 + v - 1;
997
998                     if (u == (nodes_on_edge - 2))
999                       {
1000                         int n = nodes_on_edge - v - 1;
1001                         gp->faces[face].node2 =
1002                           ((nodes_on_edge *
1003                             (nodes_on_edge + 1)) / 2) +
1004                           ((n - 1) * (n + 0)) / 2;
1005                         gp->faces[face].node3 =
1006                           ((nodes_on_edge *
1007                             (nodes_on_edge + 1)) / 2) +
1008                           ((n + 0) * (n + 1)) / 2;
1009                       }
1010                     if (v == 0)
1011                       {
1012                         gp->faces[face].node1 = (((u + 1) * (u + 2)) / 2) - 1;
1013                         gp->faces[face].node3 = (((u + 2) * (u + 3)) / 2) - 1;
1014                       }
1015                   }
1016                 else
1017                   {
1018                     gp->faces[face].node1 =
1019                       base + (((u - 2) * (u - 1)) / 2) + v - 1;
1020                     gp->faces[face].node2 = base + ((u - 1) * u) / 2 + v;
1021                     gp->faces[face].node3 = base + ((u - 1) * u) / 2 + v - 1;
1022
1023                     if (v == 0)
1024                       {
1025                         gp->faces[face].node1 =
1026                           base2 + ((u * (u + 1)) / 2) - 1;
1027                         gp->faces[face].node3 =
1028                           base2 + ((u + 1) * (u + 2)) / 2 - 1;
1029                       }
1030                     if (u == (nodes_on_edge - 2))
1031                       {
1032                         gp->faces[face].node3 =
1033                           ((nodes_on_edge *
1034                             (nodes_on_edge + 1)) / 2) +
1035                           ((v + 1) * (v + 2)) / 2 - 1;
1036                         gp->faces[face].node2 =
1037                           ((nodes_on_edge *
1038                             (nodes_on_edge + 1)) / 2) +
1039                           ((v + 2) * (v + 3)) / 2 - 1;
1040                       }
1041                     if (v == u)
1042                       {
1043                         gp->faces[face].node1 = (u * (u + 1)) / 2;
1044                         gp->faces[face].node2 = ((u + 1) * (u + 2)) / 2;
1045                       }
1046                   }
1047                 face++;
1048               }
1049
1050               if (v < u)
1051                 {
1052                   if (side < 2)
1053                     {
1054                       gp->faces[face].node1 = base + ((u * (u + 1)) / 2) + v;
1055                       gp->faces[face].node2 =
1056                         base + ((u * (u + 1)) / 2) + v + 1;
1057                       gp->faces[face].node3 =
1058                         base + (((u + 1) * (u + 2)) / 2) + v + 1;
1059
1060                       if ((side == 1) && (u == (nodes_on_edge - 2)))
1061                         {
1062                           gp->faces[face].node3 =
1063                             ((u + 1) * (u + 2)) / 2 +
1064                             nodes_on_edge - v - 2;
1065                         }
1066                     }
1067                   else if (side < 3)
1068                     {
1069                       gp->faces[face].node1 =
1070                         base + ((u * (u - 1)) / 2) + v - 1;
1071                       gp->faces[face].node2 = base + ((u * (u - 1)) / 2) + v;
1072                       gp->faces[face].node3 = base + ((u * (u + 1)) / 2) + v;
1073
1074                       if (u == (nodes_on_edge - 2))
1075                         {
1076                           int n = nodes_on_edge - v - 1;
1077                           gp->faces[face].node3 =
1078                             ((nodes_on_edge *
1079                               (nodes_on_edge + 1)) / 2) +
1080                             ((n + 0) * (n - 1)) / 2;
1081                         }
1082                       if (v == 0)
1083                         {
1084                           gp->faces[face].node1 = (((u + 1) * (u + 2)) / 2) - 1;
1085                         }
1086                     }
1087                   else
1088                     {
1089                       gp->faces[face].node1 =
1090                         base + (((u - 2) * (u - 1)) / 2) + v - 1;
1091                       gp->faces[face].node2 =
1092                         base + (((u - 2) * (u - 1)) / 2) + v;
1093                       gp->faces[face].node3 = base + (((u - 1) * u) / 2) + v;
1094
1095                       if (v == 0)
1096                         {
1097                           gp->faces[face].node1 = base2 + (u * (u + 1)) / 2 - 1;
1098                         }
1099                       if (u == (nodes_on_edge - 2))
1100                         {
1101                           gp->faces[face].node3 =
1102                             ((nodes_on_edge * (nodes_on_edge + 1)) / 2) +
1103                             ((v + 2) * (v + 3)) / 2 - 1;
1104                         }
1105                       if (v == (u - 1))
1106                         {
1107                           gp->faces[face].node2 = (u * (u + 1)) / 2;
1108                         }
1109                     }
1110                   face++;
1111                 }
1112             }
1113         }
1114     }
1115
1116   return 0;
1117 }
1118
1119 /******************************************************************************
1120  *
1121  * Return the magnitude of the given vector
1122  */
1123 #if 0
1124 static inline double
1125 length (Vector3D u)
1126 {
1127   return sqrt (u.x * u.x + u.y * u.y + u.z * u.z);
1128 }
1129 #endif
1130
1131 /******************************************************************************
1132  *
1133  * Calculate the blob shape.
1134  */
1135 static void
1136 calc_blob(mirrorblobstruct *gp,
1137           int width,
1138           int height,
1139           int bump_array_size,
1140           float limit,
1141           double fade)
1142 {
1143   /* Loop variables */
1144   int i, index, face;
1145   /* position of a node */
1146   Vector3D node;
1147   Vector3D offset;
1148   Vector3D bump_vector;
1149   int dist;
1150
1151   /* Update position and strength of bumps used to distort the blob */
1152   for (i = 0; i < bumps; i++)
1153     {
1154       gp->bump_data[i].vx += gp->bump_data[i].mx*(gp->bump_data[i].cx - gp->bump_data[i].ax);
1155       gp->bump_data[i].vy += gp->bump_data[i].my*(gp->bump_data[i].cy - gp->bump_data[i].ay);
1156       gp->bump_data[i].vpower += gp->bump_data[i].mpower
1157         * (gp->bump_data[i].cpower - gp->bump_data[i].power);
1158       gp->bump_data[i].vsize += gp->bump_data[i].msize
1159         * (gp->bump_data[i].csize - gp->bump_data[i].size);
1160
1161       gp->bump_data[i].ax += 0.1 * gp->bump_data[i].vx;
1162       gp->bump_data[i].ay += 0.1 * gp->bump_data[i].vy;
1163       gp->bump_data[i].power += 0.1 * gp->bump_data[i].vpower;
1164       gp->bump_data[i].size += 0.1 * gp->bump_data[i].vsize;
1165
1166       gp->bump_data[i].pos.x = 1.0 * sin(PI * gp->bump_data[i].ay)
1167         * cos(PI * gp->bump_data[i].ax);
1168       gp->bump_data[i].pos.y = 1.0 * cos(PI * gp->bump_data[i].ay);
1169       gp->bump_data[i].pos.z = 1.0 * sin(PI * gp->bump_data[i].ay)
1170         * sin(PI * gp->bump_data[i].ax);
1171     }
1172
1173   /* Update calculate new position for each vertex based on an offset from
1174    * the initial position
1175    */
1176   gp->blob_force = zero_vector;
1177   for (index = 0; index < gp->num_nodes; ++index)
1178     {
1179       node = gp->nodes[index].initial_position;
1180       gp->nodes[index].normal = node;
1181
1182       offset = zero_vector;
1183       for ( i = 0; i < bumps; i++)
1184         {
1185           bump_vector = subtract(gp->bump_data[i].pos, node);
1186
1187           dist = bump_array_size * dot(bump_vector, bump_vector) * gp->bump_data[i].size;
1188
1189           if (dist < bump_array_size)
1190             {
1191               add(&offset, scale(node, gp->bump_data[i].power * gp->bump_shape[dist]));
1192               add(&gp->blob_force, scale(node, gp->bump_data[i].power * gp->bump_shape[dist]));
1193             }
1194         }
1195
1196       add(&node, offset);
1197       node = scale(node, zoom);
1198       add(&node, gp->blob_center);
1199
1200       if (do_walls)
1201         {
1202           if (node.z < -limit) node.z = -limit;
1203           if (node.z > limit) node.z = limit;
1204
1205           dist = bump_array_size * (node.z + limit) * (node.z + limit) * 0.5;
1206           if (dist < bump_array_size)
1207             {
1208               node.x += (node.x - gp->blob_center.x) * gp->wall_shape[dist];
1209               node.y += (node.y - gp->blob_center.y) * gp->wall_shape[dist];
1210               gp->blob_force.z += (node.z + limit);
1211             }
1212           else
1213             {
1214               dist = bump_array_size * (node.z - limit) * (node.z - limit) * 0.5;
1215               if (dist < bump_array_size)
1216                 {
1217                   node.x += (node.x - gp->blob_center.x) * gp->wall_shape[dist];
1218                   node.y += (node.y - gp->blob_center.y) * gp->wall_shape[dist];
1219                   gp->blob_force.z -= (node.z - limit);
1220                 }
1221
1222               if (node.y < -limit) node.y = -limit;
1223               if (node.y > limit) node.y = limit;
1224
1225               dist = bump_array_size * (node.y + limit) * (node.y + limit) * 0.5;
1226               if (dist < bump_array_size)
1227                 {
1228                   node.x += (node.x - gp->blob_center.x) * gp->wall_shape[dist];
1229                   node.z += (node.z - gp->blob_center.z) * gp->wall_shape[dist];
1230                   gp->blob_force.y += (node.y + limit);
1231                 }
1232               else
1233                 {
1234                   dist = bump_array_size * (node.y - limit) * (node.y - limit) * 0.5;
1235                   if (dist < bump_array_size)
1236                     {
1237                       node.x += (node.x - gp->blob_center.x) * gp->wall_shape[dist];
1238                       node.z += (node.z - gp->blob_center.z) * gp->wall_shape[dist];
1239                       gp->blob_force.y -= (node.y - limit);
1240                     }
1241                 }
1242
1243               if (node.x < -limit) node.x = -limit;
1244               if (node.x > limit) node.x = limit;
1245
1246               dist = bump_array_size * (node.x + limit) * (node.x + limit) * 0.5;
1247               if (dist < bump_array_size)
1248                 {
1249                   node.y += (node.y - gp->blob_center.y) * gp->wall_shape[dist];
1250                   node.z += (node.z - gp->blob_center.z) * gp->wall_shape[dist];
1251                   gp->blob_force.x += (node.x + limit);
1252                 }
1253               else
1254                 {
1255                   dist = bump_array_size * (node.x - limit) * (node.x - limit) * 0.5;
1256                   if (dist < bump_array_size)
1257                     {
1258                       node.y += (node.y - gp->blob_center.y) * gp->wall_shape[dist];
1259                       node.z += (node.z - gp->blob_center.z) * gp->wall_shape[dist];
1260                       gp->blob_force.x -= (node.x - limit);
1261                     }
1262                 }
1263
1264               if (node.y < -limit) node.y = -limit;
1265               if (node.y > limit) node.y = limit;
1266             }
1267         }
1268       gp->dots[index] = node;
1269     }
1270
1271   /* Determine the normal for each face */
1272   for (face = 0; face < gp->num_faces; face++)
1273     {
1274       /* Use pointers to indexed nodes to help readability */
1275       int index1 = gp->faces[face].node1;
1276       int index2 = gp->faces[face].node2;
1277       int index3 = gp->faces[face].node3;
1278
1279       gp->faces[face].normal = cross(subtract(gp->dots[index2], gp->dots[index1]),
1280                                      subtract(gp->dots[index3], gp->dots[index1]));
1281             
1282       /* Add the normal for the face onto the normal for the verticies of
1283          the face */
1284       add(&gp->nodes[index1].normal, gp->faces[face].normal);
1285       add(&gp->nodes[index2].normal, gp->faces[face].normal);
1286       add(&gp->nodes[index3].normal, gp->faces[face].normal);
1287     }
1288
1289   /* Use the normal to set the colour and texture */
1290   if (do_colour || do_texture)
1291     {
1292       for (index = 0; index < gp->num_nodes; ++index)
1293         {
1294           gp->normals[index] = normalise(gp->nodes[index].normal);
1295    
1296           if (do_colour)
1297             {
1298               gp->colours[index].red = (int)(255.0 * fabs(gp->normals[index].x));
1299               gp->colours[index].green = (int)(255.0 * fabs(gp->normals[index].y));
1300               gp->colours[index].blue = (int)(255.0 * fabs(gp->normals[index].z));
1301               gp->colours[index].alpha = (int)(255.0 * fade);
1302             }
1303           if (do_texture)
1304             {
1305               if (offset_texture)
1306                 {
1307                   const float cube_size = 100.0;
1308                   Vector3D eye = {0.0, 0.0, 50.0};
1309                   Vector3D eye_r = normalise(subtract(gp->dots[index], eye));
1310                   Vector3D reference = subtract(eye_r, scale(gp->normals[index], 2.0 * dot(eye_r, gp->normals[index])));
1311                   double x = 0.0;
1312                   double y = 0.0;
1313                   double n, n_min = 10000.0, sign = 1.0;
1314                   if (fabs(reference.z) > 1e-9)
1315                     {
1316                       n = (cube_size - gp->dots[index].z) / reference.z;
1317                       if (n < 0.0)
1318                         {
1319                           n = (-cube_size - gp->dots[index].z) / reference.z;
1320                           sign = 3.0;
1321                         }
1322                       if (n > 0.0)
1323                         {
1324                           x = sign * (gp->dots[index].x + n * reference.x);
1325                           y = sign * (gp->dots[index].y + n * reference.y);
1326                           n_min = n;
1327                         }
1328                     }
1329                   if (fabs(reference.x) > 1e-9)
1330                     {
1331                       n = (cube_size - gp->dots[index].x) / reference.x;
1332                       sign = 1.0;
1333                       if (n < 0.0)
1334                         {
1335                           n = (-cube_size - gp->dots[index].x) / reference.x;
1336                           sign = -1.0;
1337                         }
1338                       if ((n > 0.0) && (n < n_min))
1339                         {
1340                           x = sign * (2.0 * cube_size - (gp->dots[index].z + n * reference.z));
1341                           y = sign * x * (gp->dots[index].y + n * reference.y) / cube_size;
1342                           n_min = n;
1343                         }
1344                     }
1345                   if (fabs(reference.y) > 1e-9)
1346                     {
1347                       n = (cube_size - gp->dots[index].y) / reference.y;
1348                       sign = 1.0;
1349                       if (n < 0.0)
1350                         {
1351                           n = (-cube_size - gp->dots[index].y) / reference.y;
1352                           sign = -1.0;
1353                         }
1354                       if ((n > 0.0) && (n < n_min))
1355                         {
1356                           y = sign * (2.0 * cube_size -( gp->dots[index].z + n * reference.z));
1357                           x = sign * y * (gp->dots[index].x + n * reference.x) / cube_size;
1358                         }
1359                     }
1360                                         
1361                   gp->tex_coords[index].x = 0.5 + x / (cube_size * 6.0);
1362                   gp->tex_coords[index].y = 0.5 - y / (cube_size * 6.0);
1363                 }
1364               else
1365                 {
1366                   gp->tex_coords[index].x = 0.5
1367                     * (1.0 + asin(gp->normals[index].x) / (0.5 * PI));
1368                   gp->tex_coords[index].y = -0.5
1369                     * (1.0 + asin(gp->normals[index].y) / (0.5 * PI));
1370                 }
1371               /* Adjust the texture co-ordinates to from range 0..1 to
1372                * 0..width or 0..height as appropriate
1373                */
1374               gp->tex_coords[index].x *= gp->tex_width[gp->current_texture];
1375               gp->tex_coords[index].y *= gp->tex_height[gp->current_texture];
1376             }
1377         }
1378     }
1379     
1380   /* Update the center of the whole blob */
1381   add(&gp->blob_velocity, scale (subtract (gp->blob_anchor, gp->blob_center), 1.0 / 80.0));
1382   add(&gp->blob_velocity, scale (gp->blob_force, 0.01 / gp->num_nodes));
1383
1384   add(&gp->blob_center, scale(gp->blob_velocity, 0.5));
1385
1386   gp->blob_velocity = scale(gp->blob_velocity, 0.999);
1387 }
1388
1389 static void
1390 draw_vertex(mirrorblobstruct *gp, int index)
1391 {
1392   if (do_colour)
1393     {
1394       glColor3ub(gp->colours[index].red,
1395                  gp->colours[index].green,
1396                  gp->colours[index].blue);
1397     }
1398   if (load_textures)
1399     {
1400       glTexCoord2fv(&gp->tex_coords[index].x);
1401     }
1402   glNormal3fv(&gp->normals[index].x);
1403   glVertex3fv(&gp->dots[index].x);
1404 }
1405
1406 /******************************************************************************
1407  *
1408  * Draw the blob shape.
1409  *
1410  */
1411 static void
1412 draw_blob (mirrorblobstruct *gp)
1413 {
1414   int face;
1415
1416   glMatrixMode(GL_MODELVIEW);
1417   glLoadIdentity();
1418   glRotatef(current_device_rotation(), 0, 0, 1);
1419
1420   /* Move down the z-axis. */
1421   glTranslatef (0.0, 0.0, -4.0);
1422
1423   gltrackball_rotate (gp->trackball);
1424
1425   /* glColor4ub (255, 0, 0, 128); */
1426   glBegin(GL_TRIANGLES);
1427   for (face = 0; face < gp->num_faces; face++)
1428     {
1429       draw_vertex(gp, gp->faces[face].node1);
1430       draw_vertex(gp, gp->faces[face].node2);
1431       draw_vertex(gp, gp->faces[face].node3);
1432     }
1433   glEnd();
1434
1435 #if 0
1436   glBegin(GL_LINES);
1437   for (face = 0; face < gp->num_faces; face++)
1438     {
1439       if (gp->normals[gp->faces[face].node1].z > 0.0)
1440         {
1441           Vector3D end = gp->dots[gp->faces[face].node1];
1442           glVertex3dv(&end);
1443           add(&end, scale(gp->normals[gp->faces[face].node1], 0.25));
1444           glVertex3dv(&end);
1445         }
1446     }
1447   glEnd();
1448 #endif
1449         
1450   glLoadIdentity();
1451 }
1452
1453 /******************************************************************************
1454  *
1455  * Draw the background image simply map a texture onto a full screen quad.
1456  */
1457 static void
1458 draw_background (ModeInfo *mi)
1459 {
1460   mirrorblobstruct *gp = &Mirrorblob[MI_SCREEN(mi)];
1461   GLfloat rot = current_device_rotation();
1462     
1463   glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
1464   glEnable (GL_TEXTURE_2D);
1465   glDisable(GL_LIGHTING);
1466   glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
1467
1468   /* Reset the projection matrix to make it easier to get the size of the quad
1469    * correct
1470    */
1471   glMatrixMode(GL_PROJECTION);
1472   glPushMatrix();
1473   glLoadIdentity();
1474
1475   glRotatef (rot, 0, 0, 1);
1476   if ((rot >  45 && rot <  135) ||
1477       (rot < -45 && rot > -135))
1478     {
1479       GLfloat s = MI_WIDTH(mi) / (GLfloat) MI_HEIGHT(mi);
1480       glScalef (s, 1/s, 1);
1481     }
1482
1483   glOrtho(0.0, MI_WIDTH(mi), MI_HEIGHT(mi), 0.0, -1000.0, 1000.0);
1484
1485   glBegin (GL_QUADS);
1486     
1487   glTexCoord2f (0.0, 0.0);
1488   glVertex2i (0, 0);
1489     
1490   glTexCoord2f (0.0, gp->tex_height[gp->current_texture]);
1491   glVertex2i (0, MI_HEIGHT(mi));
1492
1493   glTexCoord2f (gp->tex_width[gp->current_texture], gp->tex_height[gp->current_texture]);
1494   glVertex2i (MI_WIDTH(mi), MI_HEIGHT(mi));
1495
1496   glTexCoord2f (gp->tex_width[gp->current_texture], 0.0);
1497   glVertex2i (MI_WIDTH(mi), 0);
1498   glEnd();
1499
1500   glPopMatrix ();
1501   glMatrixMode (GL_MODELVIEW);
1502   glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
1503 }
1504
1505 /******************************************************************************
1506  *
1507  * Update the scene.
1508  */
1509 static GLvoid
1510 draw_scene(ModeInfo * mi)
1511 {
1512   mirrorblobstruct *gp = &Mirrorblob[MI_SCREEN(mi)];
1513     
1514   double fade = 0.0;
1515   double current_time;
1516   check_gl_error ("draw_scene");
1517
1518   mi->polygon_count = 0;
1519   glColor4f (1.0, 1.0, 1.0, 1.0);
1520
1521   current_time = double_time();
1522   switch (gp->state)
1523     {
1524     case INITIALISING:
1525       glColor4f (0.0, 0.0, 0.0, 1.0);
1526       fade = 1.0;
1527       break;
1528
1529     case TRANSITIONING:
1530       fade = 1.0 - (current_time - gp->state_start_time) / fade_time;
1531       break;
1532
1533     case LOADING: /* FALL-THROUGH */
1534     case HOLDING:
1535       fade = 1.0;
1536       break;
1537     }
1538
1539   /* Set the correct texture, when transitioning this ensures that the first draw
1540    * is the original texture (which has the new texture drawn over it with decreasing
1541    * transparency)
1542    */
1543   if (load_textures)
1544     {
1545       glBindTexture(GL_TEXTURE_2D, gp->textures[gp->current_texture]);
1546     }
1547
1548   glDisable (GL_DEPTH_TEST);
1549   if (do_paint_background)
1550     {
1551       glEnable (GL_TEXTURE_2D);
1552       if (motion_blur > 0.0)
1553         {
1554           glClear(GL_DEPTH_BUFFER_BIT);
1555           glEnable (GL_BLEND);
1556           glColor4f (1.0, 1.0, 1.0, motion_blur);
1557         }
1558       else
1559         {
1560           glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1561         }
1562       draw_background (mi);
1563       mi->polygon_count++;
1564
1565       /* When transitioning between two images paint the new image over the old
1566        * image with a varying alpha value to get a smooth fade.
1567        */
1568       if (gp->state == TRANSITIONING)
1569         {
1570           glEnable (GL_BLEND);
1571           /* Select the texture to transition to */
1572           glBindTexture (GL_TEXTURE_2D, gp->textures[1 - gp->current_texture]);
1573           glColor4f (1.0, 1.0, 1.0, 1.0 - fade);
1574
1575           draw_background (mi);
1576           mi->polygon_count++;
1577
1578           /* Select the original texture to draw the blob */
1579           glBindTexture (GL_TEXTURE_2D, gp->textures[gp->current_texture]);
1580         }
1581       /* Clear the depth buffer bit so the backgound is behind the blob */
1582       glClear(GL_DEPTH_BUFFER_BIT);
1583     }
1584   else if (motion_blur > 0.0)
1585     {
1586       glEnable (GL_BLEND);
1587       glColor4f (0.0, 0.0, 0.0, motion_blur);
1588       glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
1589       glTranslatef (0.0, 0.0, -4.0);
1590       glRectd (-10.0, -10.0, 10.0, 10.0);
1591       if (wireframe)
1592         {
1593           glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
1594         }
1595       glClear(GL_DEPTH_BUFFER_BIT);
1596     }
1597   else
1598     {
1599       glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1600     }
1601
1602   if (!do_texture)
1603     {
1604       fade = 1.0;
1605       glDisable (GL_TEXTURE_2D);
1606     }
1607
1608   calc_blob(gp, MI_WIDTH(mi), MI_HEIGHT(mi), BUMP_ARRAY_SIZE, 2.5, fade * blend);
1609
1610   set_blob_gl_state(fade * blend);
1611
1612   if (blend < 1.0)
1613     {
1614       /* Disable the colour chanels so that only the depth buffer is updated */
1615       glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
1616       draw_blob(gp);
1617       mi->polygon_count += gp->num_faces;
1618       glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
1619     }
1620         
1621   glDepthFunc(GL_LEQUAL);
1622   draw_blob(gp);
1623   mi->polygon_count += gp->num_faces;
1624
1625   /* While transitioning between images draw a second blob with a modified
1626    * alpha value.
1627    */
1628   if (load_textures && (hold_time > 0))
1629     {
1630       switch (gp->state)
1631         {
1632         case INITIALISING:
1633           if (!gp->waiting_for_image_p)
1634             {
1635               gp->state = HOLDING;
1636             }
1637           break;
1638                 
1639         case HOLDING:
1640           if ((current_time - gp->state_start_time) > hold_time)
1641             {
1642               grab_texture(mi, 1 - gp->current_texture);
1643               gp->state = LOADING;
1644             }
1645           break;
1646
1647         case LOADING:
1648           /* Once the image has loaded move to the TRANSITIONING STATE */
1649           if (!gp->waiting_for_image_p)
1650             {
1651               gp->state = TRANSITIONING;
1652               /* Get the time again rather than using the current time so
1653                * that the time taken by the grab_texture function is not part
1654                * of the fade time
1655                */
1656               gp->state_start_time = double_time();
1657             }
1658           break;        
1659
1660         case TRANSITIONING:
1661
1662           /* If the blob is textured draw over existing blob to fade between
1663            * images
1664            */
1665           if (do_texture)
1666             {
1667               /* Select the texture to transition to */
1668               glBindTexture (GL_TEXTURE_2D, gp->textures[1 - gp->current_texture]);
1669               glEnable (GL_BLEND);
1670                 
1671               /* If colour is enabled update the alpha data in the buffer and
1672                * use that in the blending since the alpha of the incomming
1673                * verticies will not be correct
1674                */
1675               if (do_colour)
1676                 {
1677                   glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE);
1678                   glClearColor(0.0, 0.0, 0.0, (1.0 - fade) * blend);
1679                   glClear(GL_COLOR_BUFFER_BIT);
1680                   glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);                    
1681                   glBlendFunc(GL_DST_ALPHA, GL_ONE_MINUS_DST_ALPHA);
1682                 }
1683               else
1684                 {
1685                   glColor4f (0.9, 0.9, 1.0, (1.0 - fade) * blend);
1686                 }
1687
1688               draw_blob (gp);
1689               mi->polygon_count += gp->num_faces;
1690
1691               if (do_colour)
1692                 {
1693                   /* Restore the 'standard' blend functions. */
1694                   glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1695                 }
1696             }
1697             
1698           if ((current_time - gp->state_start_time) > fade_time)
1699             {
1700               gp->state = HOLDING;
1701               gp->state_start_time = current_time;
1702               gp->current_texture = 1 - gp->current_texture;
1703             }
1704           break;
1705
1706         }
1707     }
1708 }
1709
1710 /******************************************************************************
1711  *
1712  * XMirrorblob screen update entry
1713  */
1714 ENTRYPOINT void
1715 draw_mirrorblob(ModeInfo * mi)
1716 {
1717   mirrorblobstruct *gp = &Mirrorblob[MI_SCREEN(mi)];
1718   Display    *display = MI_DISPLAY(mi);
1719   Window      window = MI_WINDOW(mi);
1720
1721   if (!gp->glx_context)
1722     return;
1723
1724   /* Wait for the first image; for subsequent images, load them in the
1725      background while animating. */
1726   if (gp->waiting_for_image_p && gp->first_image_p)
1727     return;
1728
1729   glXMakeCurrent(display, window, *(gp->glx_context));
1730   draw_scene(mi);
1731   if (mi->fps_p) do_fps (mi);
1732   glFinish();
1733   glXSwapBuffers(display, window);
1734 }
1735
1736 /******************************************************************************
1737  *
1738  * XMirrorblob screen resize entry
1739  */
1740 ENTRYPOINT void
1741 reshape_mirrorblob(ModeInfo *mi, int width, int height)
1742 {
1743   glViewport( 0, 0, MI_WIDTH(mi), MI_HEIGHT(mi) );
1744   reset_projection(width, height);
1745 }
1746
1747 /****************************************************************************
1748  *
1749  * Handle Mouse events
1750  */
1751 ENTRYPOINT Bool
1752 mirrorblob_handle_event (ModeInfo * mi, XEvent * event)
1753 {
1754   mirrorblobstruct *gp = &Mirrorblob[MI_SCREEN (mi)];
1755
1756   if (event->xany.type == ButtonPress &&
1757       event->xbutton.button == Button4)
1758     {
1759       zoom *= 1.1;
1760       return True;
1761     }
1762   else if (event->xany.type == ButtonPress &&
1763            event->xbutton.button == Button5)
1764     {
1765
1766       zoom *= 0.9;
1767       return True;
1768     }
1769   else if (gltrackball_event_handler (event, gp->trackball,
1770                                  MI_WIDTH (mi), MI_HEIGHT (mi),
1771                                  &gp->button_down))
1772     {
1773       return True;
1774     }
1775   else if (screenhack_event_helper (MI_DISPLAY(mi), MI_WINDOW(mi), event))
1776     {
1777       gp->state_start_time = 0;
1778       gp->state = HOLDING;
1779       return True;
1780     }
1781
1782   return False;
1783 }
1784
1785 /******************************************************************************
1786  *
1787  * XMirrorblob initialise entry
1788  */
1789 ENTRYPOINT void
1790 init_mirrorblob(ModeInfo * mi)
1791 {
1792   int screen = MI_SCREEN(mi);
1793
1794   mirrorblobstruct *gp;
1795
1796   if (Mirrorblob == NULL)
1797     {
1798       if ((Mirrorblob = (mirrorblobstruct *)
1799            calloc(MI_NUM_SCREENS(mi), sizeof (mirrorblobstruct))) == NULL)
1800         {
1801           return;
1802         }
1803     }
1804   gp = &Mirrorblob[screen];
1805
1806   gp->window = MI_WINDOW(mi);
1807   if ((gp->glx_context = init_GL(mi)) != NULL)
1808     {
1809       reshape_mirrorblob(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
1810       initialize_gl(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
1811     }
1812   else
1813     {
1814       MI_CLEARWINDOW(mi);
1815     }
1816   gp->trackball = gltrackball_init(False);
1817     
1818   initialise_blob(gp, MI_WIDTH(mi), MI_HEIGHT(mi), BUMP_ARRAY_SIZE);
1819   gp->state = INITIALISING;
1820   gp->state_start_time = double_time();
1821
1822   gp->first_image_p = True;
1823 }
1824
1825 /******************************************************************************
1826  *
1827  * XMirrorblob cleanup entry
1828  */
1829 ENTRYPOINT void
1830 release_mirrorblob(ModeInfo * mi)
1831 {
1832   if (Mirrorblob != NULL) {
1833     int i;
1834     for (i = 0; i < MI_NUM_SCREENS(mi); i++) {
1835       mirrorblobstruct *gp = &Mirrorblob[i];
1836       if (gp->nodes) free(gp->nodes);
1837       if (gp->faces) free(gp->faces);
1838       if (gp->bump_data) free(gp->bump_data);
1839       if (gp->colours) free(gp->colours);
1840       if (gp->tex_coords) free(gp->tex_coords);
1841       if (gp->dots) free(gp->dots);
1842       if (gp->wall_shape) free(gp->wall_shape);
1843       if (gp->bump_shape) free(gp->bump_shape);
1844     }
1845
1846     free(Mirrorblob);
1847     Mirrorblob = NULL;
1848   }
1849   FreeAllGL(mi);
1850 }
1851
1852 XSCREENSAVER_MODULE ("MirrorBlob", mirrorblob)
1853
1854 #endif