1 /* -*- Mode: C; tab-width: 4 -*- */
3 /* mirrorblob Copyright (c) 2003 Jon Dowdall <jon.dowdall@bigpond.com> */
5 * Permission to use, copy, modify, and distribute this software and its
6 * documentation for any purpose and without fee is hereby granted,
7 * provided that the above copyright notice appear in all copies and that
8 * both that copyright notice and this permission notice appear in
9 * supporting documentation.
11 * This file is provided AS IS with no warranties of any kind. The author
12 * shall have no liability with respect to the infringement of copyrights,
13 * trade secrets or any patents by this file or any part thereof. In no
14 * event will the author be liable for any lost revenue or profits or
15 * other special, indirect and consequential damages.
18 * 23-Sep-2003: jon.dowdall@bigpond.com Created module "mirrorblob"
19 * 19-Oct-2003: jon.dowdall@bigpond.com Added texturing
22 * The mirrorblob screensaver draws a pulsing blob on the screen.
23 * Options include adding a background (via screen_to_ximage),
24 * texturing the blob, making the blob semi-transparent and varying the
25 * resolution of the blob tessellation.
27 * The mirrorblob was inspired by a lavalamp is in no way a simulation.
28 * The code is just an attempt to generate some eye-candy.
30 * Much of xscreensaver code framework is taken from the pulsar module by David
31 * Konerding and the glslideshow by Mike Oliphant and Jamie Zawinski.
40 * due to a Bug/feature in VMS X11/Intrinsic.h has to be placed before xlock.
41 * otherwise caddr_t is not defined correctly
44 #include <X11/Intrinsic.h>
47 # define PROGCLASS "MirrorBlob"
48 # define HACK_INIT init_mirrorblob
49 # define HACK_DRAW draw_mirrorblob
50 # define HACK_RESHAPE reshape_mirrorblob
51 # define screensaver_opts xlockmore_opts
53 # define DEF_DELAY "10000"
54 # define DEF_FPS "False"
55 # define DEF_WIRE "False"
56 # define DEF_BLEND "False"
57 # define DEF_FOG "False"
58 # define DEF_ANTIALIAS "False"
59 # define DEF_WALLS "True"
60 # define DEF_TEXTURE "True"
61 # define DEF_COLOUR "False"
62 # define DEF_OFFSET_TEXTURE "False"
63 # define DEF_PAINT_BACKGROUND "True"
64 # define DEF_X_RES "60"
65 # define DEF_Y_RES "32"
66 # define DEF_FIELD_POINTS "5"
67 # define DEF_INCREMENTAL "0"
68 # define DEF_FADE_SPEED "1"
69 # define DEF_HOLD_FRAMES "10240"
71 #define DEFAULTS "*delay: " DEF_DELAY "\n" \
72 "*showFPS: " DEF_FPS "\n" \
73 "*wire: " DEF_WIRE "\n" \
74 "*blend: " DEF_BLEND "\n" \
75 "*fog: " DEF_FOG "\n" \
76 "*antialias: " DEF_ANTIALIAS "\n" \
77 "*walls: " DEF_WALLS "\n" \
78 "*texture: " DEF_TEXTURE "\n" \
79 "*colour: " DEF_COLOUR "\n" \
80 "*offset_texture: " DEF_OFFSET_TEXTURE "\n" \
81 "*bgimage: " DEF_PAINT_BACKGROUND "\n" \
82 "*x_resolution: " DEF_X_RES "\n" \
83 "*y_resolution: " DEF_Y_RES "\n" \
84 "*field_points: " DEF_FIELD_POINTS "\n" \
85 "*incremental: " DEF_INCREMENTAL "\n" \
86 "*fade_speed: " DEF_FADE_SPEED "\n" \
87 "*hold_frames: " DEF_HOLD_FRAMES "\n" \
89 # include "xlockmore.h" /* from the xscreensaver distribution */
90 #else /* !STANDALONE */
91 # include "xlock.h" /* from the xlockmore distribution */
92 #endif /* !STANDALONE */
94 #ifdef USE_GL /* whole file */
98 # include <X11/Xmu/Drawing.h>
100 # include <Xmu/Drawing.h>
110 /*#include <string.h>*/
111 #include "grab-ximage.h"
114 #define countof(x) (sizeof((x))/sizeof((*x)))
119 #define PI 3.1415926535897
125 static int do_antialias;
127 static int do_texture;
128 static int do_paint_background;
129 static int do_colour;
130 static int offset_texture;
131 static int x_resolution;
132 static int y_resolution;
133 static int field_points;
134 static int incremental;
135 static int fade_speed;
136 static int hold_frames;
138 static XrmOptionDescRec opts[] = {
139 {"-wire", ".mirrorblob.wire", XrmoptionNoArg, (caddr_t) "true" },
140 {"+wire", ".mirrorblob.wire", XrmoptionNoArg, (caddr_t) "false" },
141 {"-blend", ".mirrorblob.blend", XrmoptionNoArg, (caddr_t) "true" },
142 {"+blend", ".mirrorblob.blend", XrmoptionNoArg, (caddr_t) "false" },
143 {"-fog", ".mirrorblob.fog", XrmoptionNoArg, (caddr_t) "true" },
144 {"+fog", ".mirrorblob.fog", XrmoptionNoArg, (caddr_t) "false" },
145 {"-antialias", ".mirrorblob.antialias", XrmoptionNoArg, (caddr_t) "true" },
146 {"+antialias", ".mirrorblob.antialias", XrmoptionNoArg, (caddr_t) "false" },
147 {"-walls", ".mirrorblob.walls", XrmoptionNoArg, (caddr_t) "true" },
148 {"+walls", ".mirrorblob.walls", XrmoptionNoArg, (caddr_t) "false" },
149 {"-texture", ".mirrorblob.texture", XrmoptionNoArg, (caddr_t) "true" },
150 {"+texture", ".mirrorblob.texture", XrmoptionNoArg, (caddr_t) "false" },
151 {"-colour", ".mirrorblob.colour", XrmoptionNoArg, (caddr_t) "true" },
152 {"+colour", ".mirrorblob.colour", XrmoptionNoArg, (caddr_t) "false" },
153 {"-offset_texture", ".mirrorblob.offset_texture", XrmoptionNoArg, (caddr_t) "true" },
154 {"+offset_texture", ".mirrorblob.offset_texture", XrmoptionNoArg, (caddr_t) "false" },
155 {"-bgimage", ".mirrorblob.bgimage", XrmoptionNoArg, (caddr_t) "true" },
156 {"+bgimage", ".mirrorblob.bgimage", XrmoptionNoArg, (caddr_t) "false" },
157 {"-x_res", ".mirrorblob.x_res", XrmoptionSepArg, (caddr_t) NULL },
158 {"-y_res", ".mirrorblob.y_res", XrmoptionSepArg, (caddr_t) NULL },
159 {"-field_points", ".mirrorblob.field_points", XrmoptionSepArg, (caddr_t) NULL },
160 {"-incremental", ".mirrorblob.incremental", XrmoptionSepArg, (caddr_t) NULL },
161 {"-fade_speed", ".mirrorblob.fade_speed", XrmoptionSepArg, (caddr_t) NULL },
162 {"-hold_frames", ".mirrorblob.hold_frames", XrmoptionSepArg, (caddr_t) NULL },
166 static argtype vars[] = {
167 {(caddr_t *) &do_wire, "wire", "Wire", DEF_WIRE, t_Bool},
168 {(caddr_t *) &do_blend, "blend", "Blend", DEF_BLEND, t_Bool},
169 {(caddr_t *) &do_fog, "fog", "Fog", DEF_FOG, t_Bool},
170 {(caddr_t *) &do_antialias, "antialias", "Antialias", DEF_ANTIALIAS, t_Bool},
171 {(caddr_t *) &do_walls, "walls", "Walls", DEF_WALLS, t_Bool},
172 {(caddr_t *) &do_texture, "texture", "texture", DEF_TEXTURE, t_Bool},
173 {(caddr_t *) &do_colour, "colour", "colour", DEF_COLOUR, t_Bool},
174 {(caddr_t *) &offset_texture, "offset_texture","offset_texture", DEF_OFFSET_TEXTURE, t_Bool},
175 {(caddr_t *) &do_paint_background,"bgimage","bgimage", DEF_PAINT_BACKGROUND, t_Bool},
176 {(caddr_t *) &x_resolution, "x_res", "X_res", DEF_X_RES, t_Int},
177 {(caddr_t *) &y_resolution, "y_res", "Y_res", DEF_Y_RES, t_Int},
178 {(caddr_t *) &field_points, "field_points", "Field_points", DEF_FIELD_POINTS, t_Int},
179 {(caddr_t *) &incremental, "incremental", "Incremental", DEF_INCREMENTAL, t_Int},
180 {(caddr_t *) &fade_speed, "fade_speed", "fade_speed", DEF_FADE_SPEED, t_Int},
181 {(caddr_t *) &hold_frames, "hold_frames", "hold_frames", DEF_HOLD_FRAMES, t_Int},
185 static OptionStruct desc[] =
187 {"-/+ wire", "whether to do use wireframe instead of filled (faster)"},
188 {"-/+ blend", "whether to do enable blending (slower)"},
189 {"-/+ fog", "whether to do enable fog (slower)"},
190 {"-/+ antialias", "whether to do enable antialiased lines (slower)"},
191 {"-/+ walls", "whether to add walls to the blob space (slower)"},
192 {"-/+ texture", "whether to add a texture to the blob (slower)"},
193 {"-/+ colour", "whether to colour the blob"},
194 {"-/+ offset_texture", "whether to offset texture co-ordinates"},
195 {"-/+ bgimage", "whether to display a background texture (slower)"},
196 {"-x_res", "Blob resolution in x direction"},
197 {"-y_res", "Blob resolution in y direction"},
198 {"-field_points", "Number of field points used to disturb blob"},
199 {"-incremental", "Field summation method"},
200 {"-fade_speed", "speed of transistion"},
201 {"-hold_frames", "Number of frames before next image"},
204 ModeSpecOpt screensaver_opts = {countof(opts), opts, countof(vars), vars, desc};
207 ModStruct screensaver_description =
208 {"screensaver", "init_mirrorblob", "draw_mirrorblob", "release_mirrorblob",
209 "draw_mirrorblob", "init_mirrorblob", NULL, &screensaver_opts,
210 1000, 1, 2, 1, 4, 1.0, "",
211 "OpenGL screensaver", 0, NULL};
215 /* structure for holding the screensaver data */
217 int screen_width, screen_height;
218 GLXContext *glx_context;
223 static screensaverstruct *Screensaver = NULL;
225 /*****************************************************************************
226 * Types used in blob code
227 *****************************************************************************/
241 GLubyte red, green, blue, alpha;
244 /* Data used for sphere tessellation */
249 /* Number of x points at each row of the blob */
253 /* Structure to hold sphere distortion data */
256 double cx, cy, cpower;
257 double mx, my, mpower;
258 double ax, ay, apower;
259 double vx, vy, vpower;
263 /*****************************************************************************
265 *****************************************************************************/
267 static Row_Data *row_data;
269 /* Parameters controlling the position of the blob as a whole */
270 static Vector3D blob_center = {0.0, 0.0, 0.0};
271 static Vector3D blob_anchor = {0.0, 0.0, 0.0};
272 static Vector3D blob_velocity = {0.0, 0.0, 0.0};
273 static Vector3D blob_force = {0.0, 0.0, 0.0};
275 /* Count of the total number of points */
276 static int num_points;
278 static Vector3D *dots = NULL;
279 static Vector3D *normals = NULL;
280 static Colour *colours = NULL;
281 static Vector2D *tex_coords = NULL;
283 /* Pointer to the field function results */
284 static double *field = 0, *wall_field = 0;
286 Field_Data *field_data;
288 /* Use 2 textures to allow a gradualr fade between images */
289 #define NUM_TEXTURES 2
290 static int current_texture;
292 /* Ratio of used texture size to total texture size */
293 GLfloat tex_width[NUM_TEXTURES], tex_height[NUM_TEXTURES];
294 GLuint textures[NUM_TEXTURES];
296 static int holding = 1;
297 static int transitioning = 0;
298 static int colour_cycle = 0;
300 /******************************************************************************
302 * Change to the projection matrix and set our viewing volume.
306 resetProjection(int width, int height)
308 glMatrixMode( GL_PROJECTION );
310 gluPerspective( 60.0, 1.0, 1.0, 1024.0 );
311 glMatrixMode(GL_MODELVIEW);
315 /****************************************************************************
317 * Load a texture using the screen_to_ximage function.
320 grab_texture(ModeInfo *mi, int texture_index)
324 ximage = screen_to_ximage (mi->xgwa.screen, mi->window, 0);
326 glBindTexture (GL_TEXTURE_2D, textures[texture_index]);
327 glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
329 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, ximage->width, ximage->height,
330 0, GL_RGBA, GL_UNSIGNED_BYTE, ximage->data);
332 tex_width[texture_index] = mi->xgwa.width / (GLfloat)ximage->width;
333 tex_height[texture_index] = mi->xgwa.height / (GLfloat)ximage->height;
335 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
336 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
338 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
339 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
341 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
345 XDestroyImage (ximage);
348 /******************************************************************************
350 * Initialise the data used to calculate the blob shape.
353 initializeGL(ModeInfo *mi, GLsizei width, GLsizei height)
355 GLfloat fogColor[4] = { 0.1, 0.1, 0.1, 0.1 };
356 /* Lighting values */
357 GLfloat lightPos0[] = {50.0f, 10.0f, 20.0f, 1.0f };
358 GLfloat whiteLight0[] = { 0.1f, 0.1f, 0.1f, 1.0f };
359 GLfloat sourceLight0[] = { 1.0f, 1.0f, 1.0f, 1.0f };
360 GLfloat specularLight0[] = { 0.7f, 0.6f, 0.3f, 1.0f };
362 GLfloat lightPos1[] = {0.0f, -50.0f, 50.0f, 1.0f };
363 GLfloat whiteLight1[] = { 0.1f, 0.1f, 0.1f, 1.0f };
364 GLfloat sourceLight1[] = { 1.0f, 0.3f, 0.3f, 1.0f };
365 GLfloat specularLight1[] = { 0.7f, 0.6f, 0.3f, 1.0f };
367 GLfloat specref[] = { 1.0f, 1.0f, 1.0f, 1.0f };
369 /* Setup our viewport. */
370 glViewport( 0, 0, width, height );
372 glEnable(GL_DEPTH_TEST);
377 glEnable(GL_LINE_SMOOTH);
380 /* The blend function is used for trasitioning between two images even when
381 * blend is not selected.
383 glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
387 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
391 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
397 glFogi(GL_FOG_MODE, GL_LINEAR);
398 glFogfv(GL_FOG_COLOR, fogColor);
399 glFogf(GL_FOG_DENSITY, 0.35);
400 glFogf(GL_FOG_START, 2.0);
401 glFogf(GL_FOG_END, 10.0);
404 /* Our shading model--Gouraud (smooth). */
405 glShadeModel (GL_SMOOTH);
408 glCullFace (GL_BACK);
409 glEnable (GL_CULL_FACE);
410 glEnable (GL_DEPTH_TEST);
411 glFrontFace (GL_CCW);
414 /* Set the clear color. */
415 glClearColor( 0, 0, 0, 0 );
417 glViewport( 0, 0, width, height );
419 glLightfv (GL_LIGHT0, GL_AMBIENT, whiteLight0);
420 glLightfv (GL_LIGHT0, GL_DIFFUSE, sourceLight0);
421 glLightfv (GL_LIGHT0, GL_SPECULAR, specularLight0);
422 glLightfv (GL_LIGHT0, GL_POSITION, lightPos0);
423 glEnable (GL_LIGHT0);
424 glLightfv (GL_LIGHT1, GL_AMBIENT, whiteLight1);
425 glLightfv (GL_LIGHT1, GL_DIFFUSE, sourceLight1);
426 glLightfv (GL_LIGHT1, GL_SPECULAR, specularLight1);
427 glLightfv (GL_LIGHT1, GL_POSITION, lightPos1);
428 glEnable (GL_LIGHT1);
429 glEnable (GL_LIGHTING);
431 /* Enable color tracking */
432 glEnable (GL_COLOR_MATERIAL);
434 /* Set Material properties to follow glColor values */
435 glColorMaterial (GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
437 /* Set all materials to have specular reflectivity */
438 glMaterialfv (GL_FRONT, GL_SPECULAR, specref);
439 glMateriali (GL_FRONT, GL_SHININESS, 64);
441 glEnable (GL_NORMALIZE);
446 glLightModeli (GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);
448 glEnable (GL_TEXTURE_2D);
450 glGenTextures (NUM_TEXTURES, textures);
451 grab_texture (mi, current_texture);
452 grab_texture (mi, 1 - current_texture);
454 glEnableClientState (GL_TEXTURE_COORD_ARRAY);
459 glEnableClientState (GL_COLOR_ARRAY);
461 glEnableClientState (GL_NORMAL_ARRAY);
462 glEnableClientState (GL_VERTEX_ARRAY);
465 /******************************************************************************
467 * Calculate the normal vector for a plane given three points in the plane.
470 calculate_normal (Vector3D point1,
475 Vector3D vector1, vector2;
478 vector1.x = point2.x - point1.x;
479 vector1.y = point2.y - point1.y;
480 vector1.z = point2.z - point1.z;
482 vector2.x = point3.x - point2.x;
483 vector2.y = point3.y - point2.y;
484 vector2.z = point3.z - point2.z;
486 (*normal).x = vector1.y * vector2.z - vector1.z * vector2.y;
487 (*normal).y = vector1.z * vector2.x - vector1.x * vector2.z;
488 (*normal).z = vector1.x * vector2.y - vector1.y * vector2.x;
490 /* Adjust the normal to unit magnitude */
491 magnitude = sqrt ((*normal).x * (*normal).x
492 + (*normal).y * (*normal).y
493 + (*normal).z * (*normal).z);
495 /* Watch out for divide by zero/underflow */
496 if (magnitude > 1e-300)
498 (*normal).x /= magnitude;
499 (*normal).y /= magnitude;
500 (*normal).z /= magnitude;
504 /******************************************************************************
506 * Initialise the data required to draw the blob allocating the memory as
509 * Return 0 on success.
512 initialise_blob(int width,
514 int field_array_size)
522 row_data = (Row_Data *) malloc (y_resolution * sizeof (Row_Data));
525 fprintf(stderr, "Couldn't allocate row data buffer\n");
529 field_data = (Field_Data *) malloc (field_points * sizeof (Field_Data));
532 fprintf(stderr, "Couldn't allocate row data buffer\n");
536 field = (double *)malloc(field_array_size * sizeof(double));
539 fprintf(stderr, "Couldn't allocate field buffer\n");
543 wall_field = (double *)malloc(field_array_size * sizeof(double));
546 fprintf(stderr, "Couldn't allocate wall_field buffer\n");
550 dots = (Vector3D *)malloc(x_resolution * y_resolution * sizeof(Vector3D));
553 fprintf(stderr, "Couldn't allocate points buffer\n");
556 glVertexPointer (3, GL_DOUBLE, 0, (GLvoid *) dots);
558 normals = (Vector3D *)malloc(x_resolution * y_resolution * sizeof(Vector3D));
561 fprintf(stderr, "Couldn't allocate normals buffer\n");
564 glNormalPointer (GL_DOUBLE, 0, (GLvoid *) normals);
568 colours = (Colour *)malloc(x_resolution * y_resolution * sizeof(Colour));
571 fprintf(stderr, "Couldn't allocate colours buffer\n");
574 glColorPointer (4, GL_UNSIGNED_BYTE, 0, (GLvoid *) colours);
579 tex_coords = (Vector2D *)malloc(x_resolution * y_resolution
583 fprintf(stderr, "Couldn't allocate tex_coords buffer\n");
586 glTexCoordPointer (2, GL_DOUBLE, 0, (GLvoid *) tex_coords);
590 do_paint_background = False;
594 /* Generate constant row data and count of total number of points */
595 for (y = 0; y < y_resolution; y++)
597 row_data[y].cosyd = cos(PI * (double)(y * (y_resolution + 1))
598 / (double)(y_resolution * y_resolution));
599 row_data[y].sinyd = sin(PI * (double)(y * (y_resolution + 1))
600 / (double)(y_resolution * y_resolution));
601 row_data[y].num_x_points = (int)(x_resolution * row_data[y].sinyd + 1.0);
602 num_points += row_data[y].num_x_points;
605 /* Initialise field data */
606 for (i = 0; i < field_points; i++)
608 field_data[i].ax = 2.0 * (((double)random() / (double)RAND_MAX) - 0.5);
609 field_data[i].ay = 2.0 * (((double)random() / (double)RAND_MAX) - 0.5);
610 field_data[i].apower = (((double)random() / (double)RAND_MAX) - 0.5);
612 field_data[i].pos.x = 1.5 * sin(PI * field_data[i].ay)
613 * cos(PI * field_data[i].ax);
614 field_data[i].pos.y = 1.5 * cos(PI * field_data[i].ay);
615 field_data[i].pos.z = 1.5 * sin(PI * field_data[i].ay)
616 * sin(PI * field_data[i].ax);
618 field_data[i].cx = 2.0 * (((double)random() / (double)RAND_MAX) - 0.5);
619 field_data[i].cy = 2.0 * (((double)random() / (double)RAND_MAX) - 0.5);
620 field_data[i].cpower = (((double)random() / (double)RAND_MAX) - 0.5);
622 field_data[i].vx = 0.0;
623 field_data[i].vy = 0.0;
624 field_data[i].vpower = 0.0;
626 field_data[i].mx = 0.003 * ((double)random() / (double)RAND_MAX);
627 field_data[i].my = 0.003 * ((double)random() / (double)RAND_MAX);
628 field_data[i].mpower = 0.003 * ((double)random() / (double)RAND_MAX);
631 /* Initialise lookup table of field strength */
632 for (i = 0; i < field_array_size; i++)
634 xd = 2.0 * (((double)i / (double)field_array_size));
636 xd = 3.0 * xd * xd * xd * xd - 0.25 * xd * xd;
637 field[i] = 0.4 / (field_points * (xd + 0.1));
639 xd = 10.0 * (((double)i / (double)field_array_size));
640 wall_field[i] = 0.4 / (xd * xd * xd * xd + 1.0);
643 for (y = 0; y < y_resolution; y++)
645 for (x = 0; x < row_data[y].num_x_points; x++)
647 i = x + y * x_resolution;
648 xd = 2.0 * (((double)x / (double)row_data[y].num_x_points) - 0.5);
650 dots[i].x = row_data[y].sinyd * cos(PI * xd);
651 dots[i].y = row_data[y].cosyd;
652 dots[i].z = row_data[y].sinyd * sin(PI * xd);
653 normals[i].x = row_data[y].sinyd * cos(PI * xd);
654 normals[i].y = row_data[y].cosyd;
655 normals[i].z = row_data[y].sinyd * sin(PI * xd);
658 tex_coords[i].x = 2.0 - 2.0 * x / (float) row_data[y].num_x_points;
659 tex_coords[i].y = 1.0 - y / (float) y_resolution;
667 /******************************************************************************
669 * Calculate the blob shape.
674 int field_array_size,
677 static double freak = 0.0;
679 static double v_freak = 0.0007;
683 /* position of a point */
684 double xd, yd, zd, offset_x, offset_y, offset_z;
685 double strength, radius;
686 double xdist, ydist, zdist;
689 /* Color components */
696 for (y = 0; y < y_resolution; y++)
698 for (x = 0; x < row_data[y].num_x_points; x++)
700 index = x + y * x_resolution;
701 xd = 2.0 * PI * (((double)x / (double)row_data[y].num_x_points) - 0.5);
703 radius = 1.0 + 0.0 * sin (xd * 10);
705 zd = radius * row_data[y].sinyd * sin(xd);
706 xd = radius * row_data[y].sinyd * cos(xd);
707 yd = radius * row_data[y].cosyd;
713 for ( i = 0; i < field_points; i++)
715 xdist = field_data[i].pos.x - xd;
716 ydist = field_data[i].pos.y - yd;
717 zdist = field_data[i].pos.z - zd;
718 dist = field_array_size * (xdist * xdist + ydist * ydist
719 + zdist * zdist) * 0.1;
721 strength += PI * field_data[i].apower;
723 if (dist < field_array_size)
725 offset_x += xd * field_data[i].apower * field[dist];
726 offset_y += yd * field_data[i].apower * field[dist];
727 offset_z += zd * field_data[i].apower * field[dist];
729 blob_force.x += 2.0 * xd * field_data[i].apower * field[dist];
730 blob_force.y += 2.0 * yd * field_data[i].apower * field[dist];
731 blob_force.z += 2.0 * zd * field_data[i].apower * field[dist];
733 strength *= 2.0 * field[dist];
738 xd += offset_x * freak * freak;
739 yd += offset_y * freak * freak;
740 zd += offset_z * freak * freak;
742 if (incremental == 1)
762 colours[index].red = 128 + (int)(sin(strength + colour_cycle * 0.01 + 2.0 * PI * x / row_data[y].num_x_points) * 127.0);
763 colours[index].green = 128 + (int)(cos(strength + colour_cycle * 0.025) * 127.0);
764 colours[index].blue = 128 + (int)(sin(strength + colour_cycle * 0.03 + 2.0 * PI * y / y_resolution) * 127.0);
765 colours[index].alpha = 128 + (int)(cos(strength + colour_cycle * 0.015) * 63.0);
771 if (zd < -limit) zd = -limit;
772 if (zd > limit) zd = limit;
774 dist = field_array_size * (zd + limit) * (zd + limit) * 0.5;
775 if (dist < field_array_size)
777 xd += (xd - blob_center.x) * wall_field[dist];
778 yd += (yd - blob_center.y) * wall_field[dist];
779 blob_force.z += (zd + limit);
783 dist = field_array_size * (zd - limit) * (zd - limit) * 0.5;
784 if (dist < field_array_size)
786 xd += (xd - blob_center.x) * wall_field[dist];
787 yd += (yd - blob_center.y) * wall_field[dist];
788 blob_force.z -= (zd - limit);
791 if (yd < -limit) yd = -limit;
792 if (yd > limit) yd = limit;
794 dist = field_array_size * (yd + limit) * (yd + limit) * 0.5;
795 if (dist < field_array_size)
797 xd += (xd - blob_center.x) * wall_field[dist];
798 zd += (zd - blob_center.z) * wall_field[dist];
799 blob_force.y += (yd + limit);
803 dist = field_array_size * (yd - limit) * (yd - limit) * 0.5;
804 if (dist < field_array_size)
806 xd += (xd - blob_center.x) * wall_field[dist];
807 zd += (zd - blob_center.z) * wall_field[dist];
808 blob_force.y -= (yd - limit);
812 if (xd < -limit) xd = -limit;
813 if (xd > limit) xd = limit;
815 dist = field_array_size * (xd + limit) * (xd + limit) * 0.5;
816 if (dist < field_array_size)
818 yd += (yd - blob_center.y) * wall_field[dist];
819 zd += (zd - blob_center.z) * wall_field[dist];
820 blob_force.x += (xd + limit);
824 dist = field_array_size * (xd - limit) * (xd - limit) * 0.5;
825 if (dist < field_array_size)
827 yd += (yd - blob_center.y) * wall_field[dist];
828 zd += (zd - blob_center.z) * wall_field[dist];
829 blob_force.x -= (xd - limit);
833 if (yd < -limit) yd = -limit;
834 if (yd > limit) yd = limit;
844 /* Calculate the normals for each vertex and the texture mapping if required.
845 * Although the code actually calculates the normal for one of the triangles
846 * attached to a vertex rather than the vertex itself the results are not too
847 * bad for with a reasonable number of verticies.
849 for (y = 1; y < y_resolution - 1; y++)
851 int index1, index2, index3;
852 if (row_data[y - 1].num_x_points)
855 for (x = 0; x < row_data[y].num_x_points; x++)
857 if (x == row_data[y].num_x_points - 1)
859 index1 = y * x_resolution;
863 index1 = x + 1 + y * x_resolution;
865 index2 = x + y * x_resolution;
866 index3 = ((x + 0.5) * row_data[y - 1].num_x_points
867 / row_data[y].num_x_points) + (y - 1) * x_resolution;
868 calculate_normal (dots[index1], dots[index2], dots[index3],
874 tex_coords[index1].x = dots[index1].x * 0.125 + 0.5
875 * (1.0 + 0.25 * asin(normals[index1].x) / (0.5 * PI));
876 tex_coords[index1].y = dots[index1].y * 0.125 + 0.5
877 * (1.0 + 0.25 * asin(normals[index1].y) / (0.5 * PI));
881 tex_coords[index1].x = 0.5 * (1.0 + (asin(normals[index1].x)
883 tex_coords[index1].y = 0.5 * (1.0 + (asin(normals[index1].y)
886 tex_coords[index1].x *= tex_width[current_texture];
887 tex_coords[index1].y *= tex_height[current_texture];
894 v_freak += -freak / 2000000.0;
896 /* Update position and strength of points used to distort the blob */
897 for (i = 0; i < field_points; i++)
899 field_data[i].vx += field_data[i].mx*(field_data[i].cx - field_data[i].ax);
900 field_data[i].vy += field_data[i].my*(field_data[i].cy - field_data[i].ay);
901 field_data[i].vpower += field_data[i].mpower
902 * (field_data[i].cpower - field_data[i].apower);
904 field_data[i].ax += 0.1 * field_data[i].vx;
905 field_data[i].ay += 0.1 * field_data[i].vy;
906 field_data[i].apower += 0.1 * field_data[i].vpower;
908 field_data[i].pos.x = 1.5 * sin(PI * field_data[i].ay)
909 * cos(PI * field_data[i].ax);
910 field_data[i].pos.y = 1.5 * cos(PI * field_data[i].ay);
911 field_data[i].pos.z = 1.5 * sin(PI * field_data[i].ay)
912 * sin(PI * field_data[i].ax);
915 /* Update the center of the whole blob */
916 blob_velocity.x += (blob_anchor.x - blob_center.x) / 80.0
917 + 0.01 * blob_force.x / num_points;
918 blob_velocity.y += (blob_anchor.y - blob_center.y) / 80.0
919 + 0.01 * blob_force.y / num_points;
920 blob_velocity.z += (blob_anchor.z - blob_center.z) / 80.0
921 + 0.01 * blob_force.z / num_points;
923 blob_center.x += blob_velocity.x * 0.5;
924 blob_center.y += blob_velocity.y * 0.5;
925 blob_center.z += blob_velocity.z * 0.5;
927 blob_velocity.x *= 0.99;
928 blob_velocity.y *= 0.99;
929 blob_velocity.z *= 0.99;
932 /******************************************************************************
934 * Draw the blob shape.
936 * The horrendous indexing to calculate the verticies that form a particular
937 * traiangle is the result of the conversion of my first non-openGL version of
938 * blob to this openGL version. This may be tidied up when I finally playing
939 * with the more interesting bits of the code.
945 int index1, index2, index3;
948 glMatrixMode (GL_MODELVIEW);
951 /* Move down the z-axis. */
952 glTranslatef( 0.0, 0.0, -5.0 );
954 for (y = 1; y < y_resolution; y++)
956 if (row_data[y - 1].num_x_points)
958 for (x = 0; x < row_data[y].num_x_points; x++)
960 glBegin (GL_TRIANGLES);
961 if (x == row_data[y].num_x_points - 1)
963 index1 = y * x_resolution;
967 index1 = x + 1 + y * x_resolution;
969 index2 = x + y * x_resolution;
970 index3 = ((x + 0.5) * row_data[y - 1].num_x_points
971 / row_data[y].num_x_points) + (y - 1) * x_resolution;
972 glArrayElement(index1);
973 glArrayElement(index2);
974 glArrayElement(index3);
977 lower = floorf((x - 0.5) * row_data[y - 1].num_x_points
978 / (float)row_data[y].num_x_points);
979 upper = floorf((x + 0.5) * row_data[y - 1].num_x_points
980 / (float)row_data[y].num_x_points);
984 glBegin (GL_TRIANGLE_FAN);
985 index1 = x + y * x_resolution;
987 for (x2 = lower; x2 <= upper; x2++)
990 while (x3 < 0) x3 += row_data[y - 1].num_x_points;
991 while (x3 >= row_data[y - 1].num_x_points)
992 x3 -= row_data[y - 1].num_x_points;
993 index2 = x3 + (y - 1) * x_resolution;
998 while (x3 < 0) x3 += row_data[y - 1].num_x_points;
999 while (x3 >= row_data[y - 1].num_x_points)
1000 x3 -= row_data[y - 1].num_x_points;
1001 index3 = x3 + (y - 1) * x_resolution;
1004 glArrayElement(index1);
1007 glArrayElement(index2);
1016 /******************************************************************************
1018 * Draw the background image simply map a texture onto a full screen quad.
1021 draw_background (ModeInfo *mi)
1023 glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
1024 glEnable (GL_TEXTURE_2D);
1025 glDisable(GL_LIGHTING);
1027 /* Reset the projection matrix to make it easier to get the size of the quad
1030 glMatrixMode(GL_PROJECTION);
1034 glOrtho(0.0, MI_WIDTH(mi), MI_HEIGHT(mi), 0.0, -1000.0, 1000.0);
1038 glTexCoord2f (0.0, tex_height[current_texture]);
1041 glTexCoord2f (0.0, 0.0);
1042 glVertex2i (0, MI_HEIGHT(mi));
1044 glTexCoord2f (tex_width[current_texture], 0.0);
1045 glVertex2i (MI_WIDTH(mi), MI_HEIGHT(mi));
1047 glTexCoord2f (tex_width[current_texture], tex_height[current_texture]);
1048 glVertex2i (MI_WIDTH(mi), 0);
1052 glMatrixMode (GL_MODELVIEW);
1053 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
1056 /******************************************************************************
1061 drawScene(ModeInfo * mi)
1063 check_gl_error ("drawScene");
1064 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1066 glDisable (GL_BLEND);
1068 /* Ensure the background is drawn with the correct texture */
1071 glBindTexture (GL_TEXTURE_2D, textures[current_texture]);
1074 glColor4ub(255, 255, 255, 255);
1075 if (do_paint_background && !do_wire)
1077 draw_background (mi);
1079 /* When transitioning between two images paint the new image over the old
1080 * image with a varying alpha value to get a smooth fade.
1084 glDisable (GL_DEPTH_TEST);
1085 glEnable (GL_BLEND);
1086 glBindTexture (GL_TEXTURE_2D, textures[1 - current_texture]);
1087 glColor4ub (255, 255, 255, transitioning);
1089 draw_background (mi);
1091 glBindTexture (GL_TEXTURE_2D, textures[current_texture]);
1092 glEnable (GL_DEPTH_TEST);
1094 /* Clear the depth buffer bit so the backgound is behind the blob */
1095 glClear(GL_DEPTH_BUFFER_BIT);
1099 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1102 calc_blob(MI_WIDTH(mi), MI_HEIGHT(mi), 1024, 2.5);
1104 glEnable(GL_LIGHTING);
1105 glEnable(GL_LIGHT0);
1106 glEnable(GL_LIGHT1);
1110 glEnable (GL_BLEND);
1113 glColor4ub (255, 255, 255, 128 - transitioning / 2);
1117 glColor4ub (255, 255, 255, 128);
1122 glDisable (GL_BLEND);
1123 glColor4ub (255, 255, 255, 255);
1127 /* While transitioning draw the blob twice with a modified alpha channel.
1128 * The trasitioning state machine is very crude, it simply counts frames
1129 * rather than elapsed time but it works.
1135 glClear(GL_DEPTH_BUFFER_BIT);
1136 glEnable (GL_BLEND);
1137 glBindTexture (GL_TEXTURE_2D, textures[1 - current_texture]);
1140 glColor4ub (255, 255, 255, transitioning / 2);
1144 glColor4ub (255, 255, 255, transitioning);
1147 transitioning += fade_speed;
1148 if (transitioning > 255)
1151 current_texture = 1 - current_texture;
1158 if (holding > hold_frames)
1160 grab_texture (mi, 1 - current_texture);
1167 /* increment frame-counter */
1170 /* check_gl_error ("drawScene"); */
1175 draw_mirrorblob(ModeInfo * mi)
1177 screensaverstruct *gp = &Screensaver[MI_SCREEN(mi)];
1178 Display *display = MI_DISPLAY(mi);
1179 Window window = MI_WINDOW(mi);
1181 if (!gp->glx_context)
1184 glXMakeCurrent(display, window, *(gp->glx_context));
1186 if (mi->fps_p) do_fps (mi);
1187 glXSwapBuffers(display, window);
1190 /* Standard reshape function */
1192 reshape_mirrorblob(ModeInfo *mi, int width, int height)
1194 glViewport( 0, 0, MI_WIDTH(mi), MI_HEIGHT(mi) );
1195 resetProjection(width, height);
1199 init_mirrorblob(ModeInfo * mi)
1201 int screen = MI_SCREEN(mi);
1203 screensaverstruct *gp;
1205 if (Screensaver == NULL) {
1206 if ((Screensaver = (screensaverstruct *)
1207 calloc(MI_NUM_SCREENS(mi), sizeof (screensaverstruct))) == NULL)
1210 gp = &Screensaver[screen];
1212 gp->window = MI_WINDOW(mi);
1213 if ((gp->glx_context = init_GL(mi)) != NULL) {
1214 reshape_mirrorblob(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
1215 initializeGL(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
1219 /* Set the environment variable used by NVIDIA cards to control updating
1220 * during the blankning interval */
1221 setenv ("__GL_SYNC_TO_VBLANK", "1", 1);
1222 setenv ("__GL_FSAA_MODE", "1", 1);
1224 initialise_blob(MI_WIDTH(mi), MI_HEIGHT(mi), 1024);
1228 /* all sorts of nice cleanup code should go here! */
1229 void release_mirrorblob(ModeInfo * mi)
1233 if (row_data) free(row_data);
1234 if (field_data) free(field_data);
1235 if (colours) free(colours);
1236 if (tex_coords) free(tex_coords);
1237 if (dots) free(dots);
1238 if (wall_field) free(wall_field);
1239 if (field) free(field);
1241 if (Screensaver != NULL) {
1242 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
1243 /* screensaverstruct *gp = &Screensaver[screen];*/
1245 (void) free((void *) Screensaver);