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