http://ftp.nluug.nl/pub/os/Linux/distr/pardusrepo/sources/xscreensaver-5.02.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  *
22  * The mirrorblob screensaver draws a pulsing blob on the screen.  Options
23  * include adding a background (via screen_to_texture), texturing the blob,
24  * making the blob semi-transparent and varying the resolution of the blob
25  * tessellation.
26  *
27  * The blob was inspired by a lavalamp is in no way a simulation.  The code is
28  * just an attempt to generate some eye-candy.
29  *
30  * Much of xmirrorblob code framework is taken from the pulsar module by David
31  * Konerding and the glslideshow by Mike Oliphant and Jamie Zawinski.
32  *
33  */
34
35 #include <math.h>
36
37 #ifdef STANDALONE
38 #define DEFAULTS \
39     "*delay:             " DEF_DELAY "\n" \
40     "*showFPS:           " DEF_FPS   "\n" \
41     "*useSHM:              True      \n"
42
43 # define refresh_mirrorblob 0
44 /*
45 # define mirrorblob_handle_event 0
46 */
47 # include "xlockmore.h"    /* from the xmirrorblob distribution */
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.offset_texture",   XrmoptionNoArg, "true" },
127     {"+offset-texture",   ".blob.offset_texture",   XrmoptionNoArg, "false" },
128     {"-paint-background", ".blob.paint_background", XrmoptionNoArg, "true" },
129     {"+paint-background", ".blob.paint_background", XrmoptionNoArg, "false" },
130     {"-resolution",       ".blob.resolution",       XrmoptionSepArg, NULL },
131     {"-bumps",            ".blob.bumps",            XrmoptionSepArg, NULL },
132     {"-motion-blur",      ".blob.motion_blur",      XrmoptionSepArg, 0 },
133     {"-fade-time",        ".blob.fade_time",        XrmoptionSepArg, 0 },
134     {"-hold-time",        ".blob.hold_time",        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, "offset_texture","Offset_Texture", DEF_OFFSET_TEXTURE, t_Bool},
147     {&do_paint_background,"paint_background","Paint_Background", DEF_PAINT_BACKGROUND, t_Bool},
148     {&resolution,   "resolution",   "Resolution",   DEF_RESOLUTION,   t_Int},
149     {&bumps,        "bumps",        "Bump",         DEF_BUMPS, t_Int},
150     {&motion_blur,  "motion_blur",  "Motion_Blur",  DEF_MOTION_BLUR,  t_Float},
151     {&fade_time,    "fade_time",    "Fade_Time",    DEF_FADE_TIME,    t_Float},
152     {&hold_time,    "hold_time",    "Hold_Time",    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 /*****************************************************************************
187  * Types used in blob code
188  *****************************************************************************/
189
190 typedef struct
191 {
192     GLdouble x, y;
193 } Vector2D;
194
195 typedef struct
196 {
197     GLdouble x, y, z;
198 } Vector3D;
199
200 typedef struct
201 {
202     GLdouble w;
203     GLdouble x;
204     GLdouble y;
205     GLdouble z;
206 } Quaternion;
207
208 typedef struct
209 {
210     GLubyte red, green, blue, alpha;
211 } Colour;
212
213 typedef struct
214 {
215     Vector3D initial_position;
216     Vector3D position;
217     Vector3D normal;
218 } Node_Data;
219
220 typedef struct
221 {
222     int node1, node2, node3;
223     Vector3D normal;
224     double length1, length2, length3;
225 } Face_Data;
226
227 /* Structure to hold data about bumps used to distortion sphere */
228 typedef struct
229 {
230     double cx, cy, cpower, csize;
231     double ax, ay, power, size;
232     double mx, my, mpower, msize;
233     double vx, vy, vpower, vsize;
234     Vector3D pos;
235 } Bump_Data;
236
237 /* Vertices of a tetrahedron */
238 #define sqrt_3 0.5773502692
239 /*#undef sqrt_3
240 #define sqrt_3 1.0*/
241 #define PPP {  sqrt_3,  sqrt_3,  sqrt_3 }       /* +X, +Y, +Z */
242 #define MMP { -sqrt_3, -sqrt_3,  sqrt_3 }       /* -X, -Y, +Z */
243 #define MPM { -sqrt_3,  sqrt_3, -sqrt_3 }       /* -X, +Y, -Z */
244 #define PMM {  sqrt_3, -sqrt_3, -sqrt_3 }       /* +X, -Y, -Z */
245
246 /* Structure describing a tetrahedron */
247 Vector3D tetrahedron[4][3] = {
248     {PPP, MMP, MPM},
249     {PMM, MPM, MMP},
250     {PPP, MPM, PMM},
251     {PPP, PMM, MMP}
252 };
253
254 /*****************************************************************************
255  * Static blob data
256  *****************************************************************************/
257
258 const Vector3D zero_vector = { 0.0, 0.0, 0.0 };
259
260 /* Use 2 textures to allow a gradual fade between images */
261 #define NUM_TEXTURES 2
262 #define BUMP_ARRAY_SIZE 1024
263
264 typedef enum
265 {
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, GLdouble * transform)
462 {
463     GLdouble 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, GLdouble * 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     GLdouble 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  * Load a texture.
538  */
539
540 static void
541 image_loaded_cb (const char *filename, XRectangle *geometry,
542                  int image_width, int image_height, 
543                  int texture_width, int texture_height,
544                  void *closure)
545 {
546   mirrorblobstruct *mp = (mirrorblobstruct *) closure;
547   GLint texid = -1;
548   int texture_index = -1;
549   int i;
550
551   glGetIntegerv (GL_TEXTURE_BINDING_2D, &texid);
552   if (texid < 0) abort();
553
554   for (i = 0; i < NUM_TEXTURES; i++) {
555     if (mp->textures[i] == texid) {
556       texture_index = i;
557       break;
558     }
559   }
560   if (texture_index < 0) abort();
561
562   mp->tex_width [texture_index] =  (GLfloat) image_width  / texture_width;
563   mp->tex_height[texture_index] = -(GLfloat) image_height / texture_height;
564
565   glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
566   glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
567                    (mp->mipmap_p ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR));
568   glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
569   glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
570   glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
571
572   mp->waiting_for_image_p = False;
573   mp->first_image_p = True;
574 }
575
576
577 static void
578 grab_texture(ModeInfo *mi, int texture_index)
579 {
580   mirrorblobstruct *mp = &Mirrorblob[MI_SCREEN(mi)];
581
582   mp->waiting_for_image_p = True;
583   mp->mipmap_p = True;
584   load_texture_async (mi->xgwa.screen, mi->window,
585                       *mp->glx_context, 0, 0, mp->mipmap_p, 
586                       mp->textures[texture_index],
587                       image_loaded_cb, mp);
588 }
589
590 /******************************************************************************
591  *
592  * Generate internal parameters based on supplied options the parameters to
593  * ensure they are consistant.
594  */
595 static void
596 set_parameters(void)
597 {
598     /* In wire frame mode do not draw a texture */
599     if (wireframe)
600     {
601         do_texture = False;
602         blend = 1.0;
603     }
604     
605     /* Need to load textures if either the blob or the backgound has an image */
606     if (do_texture || do_paint_background)
607     {
608         load_textures = True;
609     }
610     else
611     {
612         load_textures = False;
613     }
614     
615     /* If theres no texture don't calculate co-ordinates. */
616     if (!do_texture)
617     {
618         offset_texture = False;
619     }
620     
621     culling = True;
622 }
623
624 /******************************************************************************
625  *
626  * Initialise the openGL state data.
627  */
628 static void
629 initialize_gl(ModeInfo *mi, GLsizei width, GLsizei height)
630 {
631     mirrorblobstruct *gp = &Mirrorblob[MI_SCREEN(mi)];
632     
633     /* Lighting values */
634     GLfloat ambientLight[] = { 0.2f, 0.2f, 0.2f, 1.0f };
635
636     GLfloat lightPos0[] = {500.0f, 100.0f, 200.0f, 1.0f };
637     GLfloat whiteLight0[] = { 0.0f, 0.0f, 0.0f, 1.0f };
638     GLfloat sourceLight0[] = { 0.6f, 0.6f, 0.6f, 1.0f };
639     GLfloat specularLight0[] = { 0.8f, 0.8f, 0.9f, 1.0f };
640
641     GLfloat lightPos1[] = {0.0f, -500.0f, 500.0f, 1.0f };
642     GLfloat whiteLight1[] = { 0.0f, 0.0f, 0.0f, 1.0f };
643     GLfloat sourceLight1[] = { 0.6f, 0.6f, 0.6f, 1.0f };
644     GLfloat specularLight1[] = { 0.7f, 0.7f, 0.7f, 1.0f };
645
646     GLfloat specref[] = { 1.0f, 1.0f, 1.0f, 1.0f };
647
648     GLfloat fogColor[4] = { 0.4, 0.4, 0.5, 0.1 };
649
650     /* Set the internal parameters based on the configuration settings */
651     set_parameters();
652
653     /* Set the viewport to the width and heigh of the window */
654     glViewport (0, 0, width, height ); 
655
656     if (do_antialias)
657     {
658         blend = 1.0;
659         glEnable(GL_LINE_SMOOTH);
660         glEnable(GL_POLYGON_SMOOTH);
661     }
662
663     /* The blend function is used for trasitioning between two images even when
664      * blend is not selected.
665      */
666     glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
667  
668     if (do_fog)
669     {
670         glEnable(GL_FOG);
671         glFogfv(GL_FOG_COLOR, fogColor);
672         glFogf(GL_FOG_DENSITY, 0.50);
673         glFogf(GL_FOG_START, 15.0);
674         glFogf(GL_FOG_END, 30.0);
675     }
676
677     /* Set the shading model to smooth (Gouraud shading). */
678     glShadeModel (GL_SMOOTH);
679
680     /* Set the clear color. */
681     glClearColor( 0, 0, 0, 0 );
682
683     glLightModelfv (GL_LIGHT_MODEL_AMBIENT, ambientLight);
684     glLightfv (GL_LIGHT0, GL_AMBIENT, whiteLight0);
685     glLightfv (GL_LIGHT0, GL_DIFFUSE, sourceLight0);
686     glLightfv (GL_LIGHT0, GL_SPECULAR, specularLight0);
687     glLightfv (GL_LIGHT0, GL_POSITION, lightPos0);
688     glEnable (GL_LIGHT0);
689     glLightfv (GL_LIGHT1, GL_AMBIENT, whiteLight1);
690     glLightfv (GL_LIGHT1, GL_DIFFUSE, sourceLight1);
691     glLightfv (GL_LIGHT1, GL_SPECULAR, specularLight1);
692     glLightfv (GL_LIGHT1, GL_POSITION, lightPos1);
693     glEnable (GL_LIGHT1);
694     glEnable (GL_LIGHTING);
695
696     /* Enable color tracking */
697     glEnable (GL_COLOR_MATERIAL);
698
699     /* Set Material properties to follow glColor values */
700     glColorMaterial (GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
701
702     /* Set all materials to have specular reflectivity */
703     glMaterialfv (GL_FRONT, GL_SPECULAR, specref);
704     glMateriali (GL_FRONT, GL_SHININESS, 32);
705
706     /* Let GL implementation scale normal vectors. */
707     glEnable (GL_NORMALIZE);
708
709     /* Enable Arrays */
710     if (load_textures)
711     {
712         glLightModeli (GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);
713         glEnable (GL_TEXTURE_2D);
714
715         gp->current_texture = 0;
716         glGenTextures (NUM_TEXTURES, gp->textures);
717         grab_texture (mi, gp->current_texture);
718
719         if (do_texture)
720         {
721             glEnableClientState (GL_TEXTURE_COORD_ARRAY);
722         }
723         glMatrixMode (GL_TEXTURE);
724         glRotated (180.0, 1.0, 0.0, 0.0);
725         glMatrixMode (GL_MODELVIEW);
726     }
727
728     if (do_colour)
729     {
730         glEnableClientState (GL_COLOR_ARRAY);
731     }
732     glEnableClientState (GL_NORMAL_ARRAY);
733     glEnableClientState (GL_VERTEX_ARRAY);
734
735     /* Clear the buffer since this is not done during a draw with motion blur */
736     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
737 }
738
739 /******************************************************************************
740  *
741  * Initialise the openGL state data.
742  */
743 static void
744 set_blob_gl_state(GLdouble alpha)
745 {
746     if (do_antialias)
747     {
748         glEnable(GL_LINE_SMOOTH);
749         glEnable(GL_POLYGON_SMOOTH);
750     }
751
752     if (wireframe)
753     {
754         glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
755     }
756     else
757     {
758         glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
759     }
760
761     /* The blend function is used for trasitioning between two images even when
762      * blend is not selected.
763      */
764     glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
765  
766     /* Culling. */
767     if (culling)
768     {
769         glCullFace (GL_BACK);
770         glEnable (GL_CULL_FACE);
771         glFrontFace (GL_CCW);
772     }
773     else
774     {
775         glDisable (GL_CULL_FACE);
776     }
777     
778     if (blend < 1.0)
779     {
780         glEnable (GL_BLEND);
781         glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
782         /* Set the default blob colour to off-white. */
783         glColor4d (0.9, 0.9, 1.0, alpha);
784     }
785     else
786     {
787         glDisable(GL_BLEND);
788         glColor4d (0.9, 0.9, 1.0, 1.0);
789     }
790     
791     glEnable(GL_DEPTH_TEST);
792     glEnable(GL_LIGHTING);
793 }
794
795 /******************************************************************************
796  *
797  * Initialise the data required to draw the blob allocating the memory as
798  * necessary.
799  *
800  * Return 0 on success.
801  */
802 static int
803 initialise_blob(mirrorblobstruct *gp,
804                 int width,
805                 int height,
806                 int bump_array_size)
807 {
808      /* Loop variables */    
809     int i, u, v, node, side, face, base, base2 = 0;
810     int nodes_on_edge = resolution;
811     Vector3D node1, node2, result;
812
813     if (nodes_on_edge < 2)
814         return -1;
815
816     gp->num_nodes = 2 * nodes_on_edge * nodes_on_edge - 4 * nodes_on_edge + 4;
817     gp->num_faces = 4 * (nodes_on_edge - 1) * (nodes_on_edge - 1);
818  
819     gp->nodes = (Node_Data *) malloc (gp->num_nodes * sizeof (Node_Data));
820     if (!gp->nodes)
821     {
822         fprintf (stderr, "Couldn't allocate gp->nodes buffer\n");
823         return -1;
824     }
825
826     gp->faces = (Face_Data *) malloc (gp->num_faces * sizeof (Face_Data));
827     if (!gp->faces)
828     {
829         fprintf (stderr, "Couldn't allocate faces data buffer\n");
830         return -1;
831     }
832
833     gp->bump_data = (Bump_Data *) malloc (bumps * sizeof (Bump_Data));
834     if (!gp->bump_data)
835     {
836         fprintf(stderr, "Couldn't allocate bump data buffer\n");
837         return -1;
838     }
839
840     gp->bump_shape = (double *)malloc(bump_array_size * sizeof(double));
841     if (!gp->bump_shape)
842     {
843         fprintf(stderr, "Couldn't allocate bump buffer\n");
844         return -1;
845     }
846
847     gp->wall_shape = (double *)malloc(bump_array_size * sizeof(double));
848     if (!gp->wall_shape)
849     {
850         fprintf(stderr, "Couldn't allocate wall bump buffer\n");
851         return -1;
852     }
853
854     gp->dots = (Vector3D *)malloc(gp->num_nodes * sizeof(Vector3D));
855     if (!gp->dots)
856     {
857         fprintf(stderr, "Couldn't allocate nodes buffer\n");
858         return -1;
859     }
860     glVertexPointer (3, GL_DOUBLE, 0, (GLvoid *) gp->dots);
861
862     gp->normals = (Vector3D *)malloc(gp->num_nodes * sizeof(Vector3D));
863     if (!gp->normals)
864     {
865         fprintf(stderr, "Couldn't allocate normals buffer\n");
866         return -1;
867     }
868     glNormalPointer (GL_DOUBLE, 0, (GLvoid *) gp->normals);
869
870     if (do_colour)
871     {
872         gp->colours = (Colour *)malloc(gp->num_nodes * sizeof(Colour));
873         if (!gp->colours)
874         {
875             fprintf(stderr, "Couldn't allocate colours buffer\n");
876             return -1;
877         }
878         glColorPointer (4, GL_UNSIGNED_BYTE, 0, (GLvoid *) gp->colours);
879     }
880
881     if (do_texture)
882     {
883         gp->tex_coords = (Vector2D *)malloc(gp->num_nodes * sizeof(Vector2D));
884         if (!gp->tex_coords)
885         {
886             fprintf(stderr, "Couldn't allocate gp->tex_coords buffer\n");
887             return -1;
888         }
889         glTexCoordPointer (2, GL_DOUBLE, 0, (GLvoid *) gp->tex_coords);
890     }
891
892     /* Initialise bump data */
893     for (i = 0; i < bumps; i++)
894     {
895         gp->bump_data[i].ax = 2.0 * (((double)random() / (double)RAND_MAX) - 0.5);
896         gp->bump_data[i].ay = 2.0 * (((double)random() / (double)RAND_MAX) - 0.5);
897         gp->bump_data[i].power = (5.0 / pow(bumps, 0.75)) * (((double)random() / (double)RAND_MAX) - 0.5);
898         gp->bump_data[i].size = 0.1 + 0.5 * (((double)random() / (double)RAND_MAX));
899
900         gp->bump_data[i].pos.x = 1.5 * sin(PI * gp->bump_data[i].ay)
901             * cos(PI *  gp->bump_data[i].ax);
902         gp->bump_data[i].pos.y = 1.5 * cos(PI * gp->bump_data[i].ay);
903         gp->bump_data[i].pos.z = 1.5 * sin(PI * gp->bump_data[i].ay)
904             * sin(PI *  gp->bump_data[i].ax);
905
906         gp->bump_data[i].cx = 2.0 * (((double)random() / (double)RAND_MAX) - 0.5);
907         gp->bump_data[i].cy = 2.0 * (((double)random() / (double)RAND_MAX) - 0.5);
908         gp->bump_data[i].cpower = (5.0 / pow(bumps, 0.75)) * (((double)random() / (double)RAND_MAX) - 0.5);
909         gp->bump_data[i].csize = 0.35; /*0.1 + 0.25 * (((double)random() / (double)RAND_MAX));*/
910
911         gp->bump_data[i].vx = 0.0;
912         gp->bump_data[i].vy = 0.0;
913         gp->bump_data[i].vpower = 0.0;
914         gp->bump_data[i].vsize = 0.0;
915
916         gp->bump_data[i].mx = 0.003 * ((double)random() / (double)RAND_MAX);
917         gp->bump_data[i].my = 0.003 * ((double)random() / (double)RAND_MAX);
918         gp->bump_data[i].mpower = 0.003 * ((double)random() / (double)RAND_MAX);
919         gp->bump_data[i].msize = 0.003 * ((double)random() / (double)RAND_MAX);
920     }
921
922     /* Initialise lookup table of bump strength */
923     for (i = 0; i < bump_array_size; i++)
924     {
925         double xd, xd2;
926         xd = i / (double)bump_array_size;
927
928         xd2 = 48.0 * xd * xd;
929         gp->bump_shape[i] = 0.1 / (xd2 + 0.1);
930
931         xd2 = 40.0 * xd * xd * xd * xd;
932         gp->wall_shape[i] = 0.4 / (xd2 + 0.1);
933     }
934
935     node = 0;
936     face = 0;
937     for (side = 0; side < 4; side++)
938     {
939         base = node;
940         if (side == 2) 
941         {
942             base2 = node;
943         }
944         /*
945          * The start and end of the for loops below are modified based on the 
946          * side of the tetrahedron that is being calculated to avoid duplication
947          * of the gp->nodes that are on the edges of the tetrahedron. 
948          */
949         for (u = (side > 1); u < (nodes_on_edge - (side > 0)); u++)
950         {
951             node1 = partial (normalise (tetrahedron[side][0]),
952                               normalise (tetrahedron[side][1]),
953                               u / (double) (nodes_on_edge - 1));
954             node2 = partial (normalise (tetrahedron[side][0]),
955                               normalise (tetrahedron[side][2]),
956                               u / (double) (nodes_on_edge - 1));
957
958             for (v = (side > 1); v <= (u - (side > 2)); v++)
959             {
960                 if (u > 0)
961                     result = partial (node1, node2, v / (double) u);
962                 else
963                     result = node1;
964
965                 gp->nodes[node].position = normalise (result);
966                 gp->nodes[node].initial_position = gp->nodes[node].position;
967                 gp->nodes[node].normal = zero_vector;
968                 node++;
969             }
970         }
971  
972         /*
973          * Determine which nodes make up each face.  The complexity is caused 
974          * by having to determine the correct nodes for the edges of the
975          * tetrahedron since the common nodes on the edges are only calculated
976          * once (see above).
977          */
978         for (u = 0; u < (nodes_on_edge - 1); u++)
979         {
980             for (v = 0; v <= u; v++)
981             {
982                 {
983                     if (side < 2)
984                     {
985                         gp->faces[face].node1 = base + ((u * (u + 1)) / 2) + v;
986                         gp->faces[face].node2 =
987                             base + ((u + 1) * (u + 2)) / 2 + v + 1;
988                         gp->faces[face].node3 =
989                             base + ((u + 1) * (u + 2)) / 2 + v;
990
991                         if ((side == 1) && (u == (nodes_on_edge - 2)))
992                         {
993                             gp->faces[face].node3 =
994                                 ((u + 1) * (u + 2)) / 2 +
995                                 nodes_on_edge - v - 1;
996                             gp->faces[face].node2 =
997                                 ((u + 1) * (u + 2)) / 2 +
998                                 nodes_on_edge - v - 2;
999                         }
1000                     }
1001                     else if (side < 3)
1002                     {
1003                         gp->faces[face].node1 =
1004                             base + (((u - 1) * u) / 2) + v - 1;
1005                         gp->faces[face].node2 = base + ((u) * (u + 1)) / 2 + v;
1006                         gp->faces[face].node3 =
1007                             base + ((u) * (u + 1)) / 2 + v - 1;
1008
1009                         if (u == (nodes_on_edge - 2))
1010                         {
1011                             int n = nodes_on_edge - v - 1;
1012                             gp->faces[face].node2 =
1013                                 ((nodes_on_edge *
1014                                   (nodes_on_edge + 1)) / 2) +
1015                                 ((n - 1) * (n + 0)) / 2;
1016                             gp->faces[face].node3 =
1017                                 ((nodes_on_edge *
1018                                   (nodes_on_edge + 1)) / 2) +
1019                                 ((n + 0) * (n + 1)) / 2;
1020                         }
1021                         if (v == 0)
1022                         {
1023                             gp->faces[face].node1 = (((u + 1) * (u + 2)) / 2) - 1;
1024                             gp->faces[face].node3 = (((u + 2) * (u + 3)) / 2) - 1;
1025                         }
1026                     }
1027                     else
1028                     {
1029                         gp->faces[face].node1 =
1030                             base + (((u - 2) * (u - 1)) / 2) + v - 1;
1031                         gp->faces[face].node2 = base + ((u - 1) * u) / 2 + v;
1032                         gp->faces[face].node3 = base + ((u - 1) * u) / 2 + v - 1;
1033
1034                         if (v == 0)
1035                         {
1036                             gp->faces[face].node1 =
1037                                 base2 + ((u * (u + 1)) / 2) - 1;
1038                             gp->faces[face].node3 =
1039                                 base2 + ((u + 1) * (u + 2)) / 2 - 1;
1040                         }
1041                         if (u == (nodes_on_edge - 2))
1042                         {
1043                             gp->faces[face].node3 =
1044                                 ((nodes_on_edge *
1045                                   (nodes_on_edge + 1)) / 2) +
1046                                 ((v + 1) * (v + 2)) / 2 - 1;
1047                             gp->faces[face].node2 =
1048                                 ((nodes_on_edge *
1049                                   (nodes_on_edge + 1)) / 2) +
1050                                 ((v + 2) * (v + 3)) / 2 - 1;
1051                         }
1052                         if (v == u)
1053                         {
1054                             gp->faces[face].node1 = (u * (u + 1)) / 2;
1055                             gp->faces[face].node2 = ((u + 1) * (u + 2)) / 2;
1056                         }
1057                     }
1058                     face++;
1059                 }
1060
1061                 if (v < u)
1062                 {
1063                     if (side < 2)
1064                     {
1065                         gp->faces[face].node1 = base + ((u * (u + 1)) / 2) + v;
1066                         gp->faces[face].node2 =
1067                             base + ((u * (u + 1)) / 2) + v + 1;
1068                         gp->faces[face].node3 =
1069                             base + (((u + 1) * (u + 2)) / 2) + v + 1;
1070
1071                         if ((side == 1) && (u == (nodes_on_edge - 2)))
1072                         {
1073                             gp->faces[face].node3 =
1074                                 ((u + 1) * (u + 2)) / 2 +
1075                                 nodes_on_edge - v - 2;
1076                         }
1077                     }
1078                     else if (side < 3)
1079                     {
1080                         gp->faces[face].node1 =
1081                             base + ((u * (u - 1)) / 2) + v - 1;
1082                         gp->faces[face].node2 = base + ((u * (u - 1)) / 2) + v;
1083                         gp->faces[face].node3 = base + ((u * (u + 1)) / 2) + v;
1084
1085                         if (u == (nodes_on_edge - 2))
1086                         {
1087                             int n = nodes_on_edge - v - 1;
1088                             gp->faces[face].node3 =
1089                                 ((nodes_on_edge *
1090                                   (nodes_on_edge + 1)) / 2) +
1091                                 ((n + 0) * (n - 1)) / 2;
1092                         }
1093                         if (v == 0)
1094                         {
1095                             gp->faces[face].node1 = (((u + 1) * (u + 2)) / 2) - 1;
1096                         }
1097                     }
1098                     else
1099                     {
1100                         gp->faces[face].node1 =
1101                             base + (((u - 2) * (u - 1)) / 2) + v - 1;
1102                         gp->faces[face].node2 =
1103                             base + (((u - 2) * (u - 1)) / 2) + v;
1104                         gp->faces[face].node3 = base + (((u - 1) * u) / 2) + v;
1105
1106                         if (v == 0)
1107                         {
1108                             gp->faces[face].node1 = base2 + (u * (u + 1)) / 2 - 1;
1109                         }
1110                         if (u == (nodes_on_edge - 2))
1111                         {
1112                             gp->faces[face].node3 =
1113                                 ((nodes_on_edge * (nodes_on_edge + 1)) / 2) +
1114                                 ((v + 2) * (v + 3)) / 2 - 1;
1115                         }
1116                         if (v == (u - 1))
1117                         {
1118                             gp->faces[face].node2 = (u * (u + 1)) / 2;
1119                         }
1120                     }
1121                     face++;
1122                 }
1123             }
1124         }
1125     }
1126
1127     return 0;
1128 }
1129
1130 /******************************************************************************
1131  *
1132  * Return the magnitude of the given vector
1133  */
1134 static inline double
1135 length (Vector3D u)
1136 {
1137     return sqrt (u.x * u.x + u.y * u.y + u.z * u.z);
1138 }
1139
1140 /******************************************************************************
1141  *
1142  * Calculate the blob shape.
1143  */
1144 static void
1145 calc_blob(mirrorblobstruct *gp,
1146           int width,
1147           int height,
1148           int bump_array_size,
1149           float limit,
1150           double fade)
1151 {
1152     /* Loop variables */
1153     int i, index, face;
1154     /* position of a node */
1155     Vector3D node;
1156     Vector3D offset;
1157     Vector3D bump_vector;
1158     int dist;
1159
1160     /* Update position and strength of bumps used to distort the blob */
1161     for (i = 0; i < bumps; i++)
1162     {
1163         gp->bump_data[i].vx += gp->bump_data[i].mx*(gp->bump_data[i].cx - gp->bump_data[i].ax);
1164         gp->bump_data[i].vy += gp->bump_data[i].my*(gp->bump_data[i].cy - gp->bump_data[i].ay);
1165         gp->bump_data[i].vpower += gp->bump_data[i].mpower
1166             * (gp->bump_data[i].cpower - gp->bump_data[i].power);
1167         gp->bump_data[i].vsize += gp->bump_data[i].msize
1168             * (gp->bump_data[i].csize - gp->bump_data[i].size);
1169
1170         gp->bump_data[i].ax += 0.1 * gp->bump_data[i].vx;
1171         gp->bump_data[i].ay += 0.1 * gp->bump_data[i].vy;
1172         gp->bump_data[i].power += 0.1 * gp->bump_data[i].vpower;
1173         gp->bump_data[i].size += 0.1 * gp->bump_data[i].vsize;
1174
1175         gp->bump_data[i].pos.x = 1.0 * sin(PI * gp->bump_data[i].ay)
1176             * cos(PI * gp->bump_data[i].ax);
1177         gp->bump_data[i].pos.y = 1.0 * cos(PI * gp->bump_data[i].ay);
1178         gp->bump_data[i].pos.z = 1.0 * sin(PI * gp->bump_data[i].ay)
1179             * sin(PI * gp->bump_data[i].ax);
1180     }
1181
1182     /* Update calculate new position for each vertex based on an offset from
1183      * the initial position
1184      */
1185     gp->blob_force = zero_vector;
1186     for (index = 0; index < gp->num_nodes; ++index)
1187     {
1188         node = gp->nodes[index].initial_position;
1189         gp->nodes[index].normal = zero_vector;
1190
1191         offset = zero_vector;
1192         for ( i = 0; i < bumps; i++)
1193         {
1194             bump_vector = subtract(gp->bump_data[i].pos, node);
1195
1196             dist = bump_array_size * dot(bump_vector, bump_vector) * gp->bump_data[i].size;
1197
1198             if (dist < bump_array_size)
1199             {
1200                 add(&offset, scale(node, gp->bump_data[i].power * gp->bump_shape[dist]));
1201                 add(&gp->blob_force, scale(node, gp->bump_data[i].power * gp->bump_shape[dist]));
1202             }
1203         }
1204
1205         add(&node, offset);
1206         node = scale(node, zoom);
1207         add(&node, gp->blob_center);
1208
1209         if (do_walls)
1210         {
1211             if (node.z < -limit) node.z = -limit;
1212             if (node.z > limit) node.z = limit;
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             else
1222             {
1223                 dist = bump_array_size * (node.z - limit) * (node.z - limit) * 0.5;
1224                 if (dist < bump_array_size)
1225                 {
1226                     node.x += (node.x - gp->blob_center.x) * gp->wall_shape[dist];
1227                     node.y += (node.y - gp->blob_center.y) * gp->wall_shape[dist];
1228                     gp->blob_force.z -= (node.z - limit);
1229                 }
1230
1231                 if (node.y < -limit) node.y = -limit;
1232                 if (node.y > limit) node.y = limit;
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                 else
1242                 {
1243                     dist = bump_array_size * (node.y - limit) * (node.y - limit) * 0.5;
1244                     if (dist < bump_array_size)
1245                     {
1246                         node.x += (node.x - gp->blob_center.x) * gp->wall_shape[dist];
1247                         node.z += (node.z - gp->blob_center.z) * gp->wall_shape[dist];
1248                         gp->blob_force.y -= (node.y - limit);
1249                     }
1250                 }
1251
1252                 if (node.x < -limit) node.x = -limit;
1253                 if (node.x > limit) node.x = limit;
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                 else
1263                 {
1264                     dist = bump_array_size * (node.x - limit) * (node.x - limit) * 0.5;
1265                     if (dist < bump_array_size)
1266                     {
1267                         node.y += (node.y - gp->blob_center.y) * gp->wall_shape[dist];
1268                         node.z += (node.z - gp->blob_center.z) * gp->wall_shape[dist];
1269                         gp->blob_force.x -= (node.x - limit);
1270                     }
1271                 }
1272
1273                 if (node.y < -limit) node.y = -limit;
1274                 if (node.y > limit) node.y = limit;
1275             }
1276         }
1277         gp->dots[index] = node;
1278     }
1279
1280     /* Determine the normal for each face */
1281     for (face = 0; face < gp->num_faces; face++)
1282     {
1283         /* Use nodeers to indexed nodes to help readability */
1284         Node_Data *node1 = &gp->nodes[gp->faces[face].node1];
1285         Node_Data *node2 = &gp->nodes[gp->faces[face].node2];
1286         Node_Data *node3 = &gp->nodes[gp->faces[face].node3];
1287
1288         gp->faces[face].normal = cross(subtract(node2->position, node1->position),
1289                                        subtract(node3->position, node1->position));
1290             
1291         /* Add the normal for the face onto the normal for the verticies of
1292            the face */
1293         add(&node1->normal, gp->faces[face].normal);
1294         add(&node2->normal, gp->faces[face].normal);
1295         add(&node3->normal, gp->faces[face].normal);
1296     }
1297
1298     /* Use the normal to set the colour and texture */
1299     if (do_colour || do_texture)
1300     {
1301         for (index = 0; index < gp->num_nodes; ++index)
1302         {
1303             gp->normals[index] = normalise(gp->nodes[index].normal);
1304    
1305             if (do_colour)
1306             {
1307                 gp->colours[index].red = (int)(255.0 * fabs(gp->normals[index].x));
1308                 gp->colours[index].green = (int)(255.0 * fabs(gp->normals[index].y));
1309                 gp->colours[index].blue = (int)(255.0 * fabs(gp->normals[index].z));
1310                 gp->colours[index].alpha = (int)(255.0 * fade);
1311             }
1312             if (do_texture)
1313             {
1314                 if (offset_texture)
1315                 {
1316                     gp->tex_coords[index].x = gp->dots[index].x * 0.125 + 0.5
1317                         * (1.0 + 0.25 * asin(gp->normals[index].x) / (0.5 * PI));
1318                     gp->tex_coords[index].y = -gp->dots[index].y * 0.125 - 0.5
1319                         * (1.0 + 0.25 * asin(gp->normals[index].y) / (0.5 * PI));
1320                 }
1321                 else
1322                 {
1323                     gp->tex_coords[index].x = 0.5
1324                         * (1.0 + asin(gp->normals[index].x) / (0.5 * PI));
1325                     gp->tex_coords[index].y = -0.5
1326                         * (1.0 + asin(gp->normals[index].y) / (0.5 * PI));
1327                 }
1328                 /* Adjust the texture co-ordinates to from range 0..1 to
1329                  * 0..width or 0..height as appropriate
1330                  */
1331                 gp->tex_coords[index].x *= gp->tex_width[gp->current_texture];
1332                 gp->tex_coords[index].y *= gp->tex_height[gp->current_texture];
1333             }
1334         }
1335     }
1336     
1337     /* Update the center of the whole blob */
1338     add(&gp->blob_velocity, scale (subtract (gp->blob_anchor, gp->blob_center), 1.0 / 80.0));
1339     add(&gp->blob_velocity, scale (gp->blob_force, 0.01 / gp->num_nodes));
1340
1341     add(&gp->blob_center, scale(gp->blob_velocity, 0.5));
1342
1343     gp->blob_velocity = scale(gp->blob_velocity, 0.999);
1344 }
1345
1346 /******************************************************************************
1347  *
1348  * Draw the blob shape.
1349  *
1350  */
1351 static void
1352 draw_blob (mirrorblobstruct *gp)
1353 {
1354     int face;
1355
1356     glMatrixMode (GL_MODELVIEW);
1357     glLoadIdentity ();
1358
1359     /* Move down the z-axis. */
1360     glTranslatef (0.0, 0.0, -4.0);
1361
1362     gltrackball_rotate (gp->trackball);
1363
1364     /* glColor4ub (255, 0, 0, 128); */
1365     glBegin (GL_TRIANGLES);
1366     for (face = 0; face < gp->num_faces; face++)
1367     {
1368         glArrayElement (gp->faces[face].node1);
1369         glArrayElement (gp->faces[face].node2);
1370         glArrayElement (gp->faces[face].node3);
1371     }
1372     glEnd ();
1373     glLoadIdentity ();
1374 }
1375
1376 /******************************************************************************
1377  *
1378  * Draw the background image simply map a texture onto a full screen quad.
1379  */
1380 static void
1381 draw_background (ModeInfo *mi)
1382 {
1383     mirrorblobstruct *gp = &Mirrorblob[MI_SCREEN(mi)];
1384     
1385     glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
1386     glEnable (GL_TEXTURE_2D);
1387     glDisable(GL_LIGHTING);
1388     glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
1389
1390     /* Reset the projection matrix to make it easier to get the size of the quad
1391      * correct
1392      */
1393     glMatrixMode(GL_PROJECTION);
1394     glPushMatrix();
1395     glLoadIdentity();
1396
1397     glOrtho(0.0, MI_WIDTH(mi), MI_HEIGHT(mi), 0.0, -1000.0, 1000.0);
1398
1399     glBegin (GL_QUADS);
1400     
1401     glTexCoord2f (0.0, 0.0);
1402     glVertex2i (0, 0);
1403     
1404     glTexCoord2f (0.0, gp->tex_height[gp->current_texture]);
1405     glVertex2i (0, MI_HEIGHT(mi));
1406
1407     glTexCoord2f (gp->tex_width[gp->current_texture], gp->tex_height[gp->current_texture]);
1408     glVertex2i (MI_WIDTH(mi), MI_HEIGHT(mi));
1409
1410     glTexCoord2f (gp->tex_width[gp->current_texture], 0.0);
1411     glVertex2i (MI_WIDTH(mi), 0);
1412     glEnd();
1413
1414     glPopMatrix ();
1415     glMatrixMode (GL_MODELVIEW);
1416     glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
1417 }
1418
1419 /******************************************************************************
1420  *
1421  * Update the scene.
1422  */
1423 static GLvoid
1424 draw_scene(ModeInfo * mi)
1425 {
1426     mirrorblobstruct *gp = &Mirrorblob[MI_SCREEN(mi)];
1427     
1428     double fade = 0.0;
1429     double current_time;
1430     check_gl_error ("draw_scene");
1431
1432     glColor4d(1.0, 1.0, 1.0, 1.0);
1433
1434     current_time = double_time();
1435     switch (gp->state)
1436     {
1437     case TRANSITIONING:
1438         fade = 1.0 - (current_time - gp->state_start_time) / fade_time;
1439         break;
1440
1441     case LOADING: /* FALL-THROUGH */
1442     case HOLDING:
1443         fade = 1.0;
1444         break;
1445     }
1446
1447     /* Set the correct texture, when transitioning this ensures that the first draw
1448      * is the original texture (which has the new texture drawn over it with decreasing
1449      * transparency)
1450      */
1451     if (load_textures)
1452     {
1453         glBindTexture (GL_TEXTURE_2D, gp->textures[gp->current_texture]);
1454     }
1455
1456     glDisable (GL_DEPTH_TEST);
1457     if (do_paint_background)
1458     {
1459         glEnable (GL_TEXTURE_2D);
1460         if (motion_blur > 0.0)
1461         {
1462             glClear(GL_DEPTH_BUFFER_BIT);
1463             glEnable (GL_BLEND);
1464             glColor4d (1.0, 1.0, 1.0, motion_blur);
1465         }
1466         else
1467         {
1468             glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1469         }
1470         draw_background (mi);
1471
1472         /* When transitioning between two images paint the new image over the old
1473          * image with a varying alpha value to get a smooth fade.
1474          */
1475         if (gp->state == TRANSITIONING)
1476         {
1477             glEnable (GL_BLEND);
1478             /* Select the texture to transition to */
1479             glBindTexture (GL_TEXTURE_2D, gp->textures[1 - gp->current_texture]);
1480             glColor4d (1.0, 1.0, 1.0, 1.0 - fade);
1481
1482             draw_background (mi);
1483
1484             /* Select the original texture to draw the blob */
1485             glBindTexture (GL_TEXTURE_2D, gp->textures[gp->current_texture]);
1486         }
1487         /* Clear the depth buffer bit so the backgound is behind the blob */
1488         glClear(GL_DEPTH_BUFFER_BIT);
1489     }
1490     else if (motion_blur > 0.0)
1491     {
1492         glEnable (GL_BLEND);
1493         glColor4d (0.0, 0.0, 0.0, motion_blur);
1494         glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
1495         glTranslatef (0.0, 0.0, -4.0);
1496         glRectd (-10.0, -10.0, 10.0, 10.0);
1497         if (wireframe)
1498         {
1499             glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
1500         }
1501         glClear (GL_DEPTH_BUFFER_BIT);
1502     }
1503     else
1504     {
1505         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1506     }
1507
1508     if (!do_texture)
1509     {
1510         fade = 1.0;
1511         glDisable (GL_TEXTURE_2D);
1512     }
1513
1514     calc_blob(gp, MI_WIDTH(mi), MI_HEIGHT(mi), BUMP_ARRAY_SIZE, 2.5, fade * blend);
1515
1516     set_blob_gl_state(fade * blend);
1517
1518     if (blend < 1.0)
1519     {
1520         /* Disable the three colour chanels so that only the depth buffer is updated */
1521         glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
1522         draw_blob(gp);
1523         glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
1524         glDepthFunc(GL_LEQUAL);
1525     }
1526     glDepthFunc(GL_LEQUAL);
1527     draw_blob(gp);
1528
1529     /* While transitioning between images draw a second blob with a modified
1530      * alpha value.
1531      */
1532     if (load_textures && (hold_time > 0))
1533     {
1534         switch (gp->state)
1535         {
1536         case HOLDING:
1537             if ((current_time - gp->state_start_time) > hold_time)
1538             {
1539                 grab_texture(mi, 1 - gp->current_texture);
1540                 gp->state = LOADING;
1541             }
1542             break;
1543
1544         case LOADING:
1545             /* Once the image has loaded move to the TRANSITIONING STATE */
1546             if (!gp->waiting_for_image_p)
1547             {
1548                 gp->state = TRANSITIONING;
1549                 /* Get the time again rather than using the current time so
1550                  * that the time taken by the grab_texture function is not part
1551                  * of the fade time
1552                  */
1553                 gp->state_start_time = double_time();
1554             }
1555             break;        
1556
1557         case TRANSITIONING:
1558
1559             /* If the blob is textured draw over existing blob to fade between
1560              * images
1561              */
1562             if (do_texture)
1563             {
1564                 /* Select the texture to transition to */
1565                 glBindTexture (GL_TEXTURE_2D, gp->textures[1 - gp->current_texture]);
1566                 glEnable (GL_BLEND);
1567                 
1568                 /* If colour is enabled update the alpha data in the buffer and
1569                  * use that in the blending since the alpha of the incomming
1570                  * verticies will not be correct
1571                  */
1572                 if (do_colour)
1573                 {
1574                     glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE);
1575                     glClearColor(0.0, 0.0, 0.0, (1.0 - fade) * blend);
1576                     glClear(GL_COLOR_BUFFER_BIT);
1577                     glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);                    
1578                     glBlendFunc(GL_DST_ALPHA, GL_ONE_MINUS_DST_ALPHA);
1579                 }
1580                 else
1581                 {
1582                     glColor4d(0.9, 0.9, 1.0, (1.0 - fade) * blend);
1583                 }
1584
1585                 draw_blob (gp);
1586
1587                 if (do_colour)
1588                 {
1589                     /* Restore the 'standard' blend functions. */
1590                     glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1591                 }
1592             }
1593             
1594             if ((current_time - gp->state_start_time) > fade_time)
1595             {
1596                 gp->state = HOLDING;
1597                 gp->state_start_time = current_time;
1598                 gp->current_texture = 1 - gp->current_texture;
1599             }
1600             break;
1601
1602         }
1603     }
1604 }
1605
1606 /******************************************************************************
1607  *
1608  * XMirrorblob screen update entry
1609  */
1610 ENTRYPOINT void
1611 draw_mirrorblob(ModeInfo * mi)
1612 {
1613     mirrorblobstruct *gp = &Mirrorblob[MI_SCREEN(mi)];
1614     Display    *display = MI_DISPLAY(mi);
1615     Window      window = MI_WINDOW(mi);
1616
1617     if (!gp->glx_context)
1618         return;
1619
1620     /* Wait for the first image; for subsequent images, load them in the
1621        background while animating. */
1622     if (gp->waiting_for_image_p && gp->first_image_p)
1623       return;
1624
1625     glXMakeCurrent(display, window, *(gp->glx_context));
1626     draw_scene(mi);
1627     if (mi->fps_p) do_fps (mi);
1628     glXSwapBuffers(display, window);
1629 }
1630
1631 /******************************************************************************
1632  *
1633  * XMirrorblob screen resize entry
1634  */
1635 ENTRYPOINT void
1636 reshape_mirrorblob(ModeInfo *mi, int width, int height)
1637 {
1638     glViewport( 0, 0, MI_WIDTH(mi), MI_HEIGHT(mi) );
1639     reset_projection(width, height);
1640 }
1641
1642 /****************************************************************************
1643  *
1644  * Handle Mouse events
1645  */
1646 ENTRYPOINT Bool
1647 mirrorblob_handle_event (ModeInfo * mi, XEvent * event)
1648 {
1649     mirrorblobstruct *gp = &Mirrorblob[MI_SCREEN (mi)];
1650
1651     if (event->xany.type == ButtonPress &&
1652         event->xbutton.button == Button1)
1653     {
1654         gp->button_down = 1;
1655         gltrackball_start (gp->trackball, event->xbutton.x,
1656                            event->xbutton.y, MI_WIDTH (mi), MI_HEIGHT (mi));
1657         return True;
1658     }
1659     else if (event->xany.type == ButtonRelease &&
1660              event->xbutton.button == Button1)
1661     {
1662         gp->button_down = 0;
1663         return True;
1664     }
1665     else if (event->xany.type == ButtonPress &&
1666              event->xbutton.button == Button4)
1667     {
1668         zoom *= 1.1;
1669         return True;
1670     }
1671     else if (event->xany.type == ButtonPress &&
1672              event->xbutton.button == Button5)
1673     {
1674
1675         zoom *= 0.9;
1676         return True;
1677     }
1678     else if (event->xany.type == MotionNotify && gp->button_down)
1679     {
1680         gltrackball_track (gp->trackball, event->xmotion.x,
1681                            event->xmotion.y, MI_WIDTH (mi), MI_HEIGHT (mi));
1682         return True;
1683     }
1684     return False;
1685 }
1686
1687 /******************************************************************************
1688  *
1689  * XMirrorblob initialise entry
1690  */
1691 ENTRYPOINT void
1692 init_mirrorblob(ModeInfo * mi)
1693 {
1694     int screen = MI_SCREEN(mi);
1695
1696     mirrorblobstruct *gp;
1697
1698     if (Mirrorblob == NULL)
1699     {
1700         if ((Mirrorblob = (mirrorblobstruct *)
1701              calloc(MI_NUM_SCREENS(mi), sizeof (mirrorblobstruct))) == NULL)
1702         {
1703             return;
1704         }
1705     }
1706     gp = &Mirrorblob[screen];
1707
1708     gp->window = MI_WINDOW(mi);
1709     if ((gp->glx_context = init_GL(mi)) != NULL)
1710     {
1711         reshape_mirrorblob(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
1712         initialize_gl(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
1713     }
1714     else
1715     {
1716         MI_CLEARWINDOW(mi);
1717     }
1718     gp->trackball = gltrackball_init ();
1719     
1720     initialise_blob(gp, MI_WIDTH(mi), MI_HEIGHT(mi), BUMP_ARRAY_SIZE);
1721     gp->state_start_time = double_time();
1722
1723     gp->first_image_p = True;
1724 }
1725
1726 /******************************************************************************
1727  *
1728  * XMirrorblob cleanup entry
1729  */
1730 ENTRYPOINT void
1731 release_mirrorblob(ModeInfo * mi)
1732 {
1733   if (Mirrorblob != NULL) {
1734     int i;
1735     for (i = 0; i < MI_NUM_SCREENS(mi); i++) {
1736       mirrorblobstruct *gp = &Mirrorblob[i];
1737       if (gp->nodes) free(gp->nodes);
1738       if (gp->faces) free(gp->faces);
1739       if (gp->bump_data) free(gp->bump_data);
1740       if (gp->colours) free(gp->colours);
1741       if (gp->tex_coords) free(gp->tex_coords);
1742       if (gp->dots) free(gp->dots);
1743       if (gp->wall_shape) free(gp->wall_shape);
1744       if (gp->bump_shape) free(gp->bump_shape);
1745     }
1746
1747     free(Mirrorblob);
1748     Mirrorblob = NULL;
1749   }
1750   FreeAllGL(mi);
1751 }
1752
1753 XSCREENSAVER_MODULE ("MirrorBlob", mirrorblob)
1754
1755 #endif