1 /* mirrorblob Copyright (c) 2003 Jon Dowdall <jon.dowdall@bigpond.com> */
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.
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.
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
21 * The mirrorblob screensaver draws a pulsing blob on the screen. Options
22 * include adding a background (via screen_to_ximage), texturing the blob,
23 * making the blob semi-transparent and varying the resolution of the blob
26 * The blob was inspired by a lavalamp is in no way a simulation. The code is
27 * just an attempt to generate some eye-candy.
29 * Much of xscreensaver code framework is taken from the pulsar module by David
30 * 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 "Screensaver"
48 # define HACK_INIT init_screensaver
49 # define HACK_DRAW draw_screensaver
50 # define HACK_RESHAPE reshape_screensaver
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_COLOUR "False"
61 #define DEF_TEXTURE "True"
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_MOTION_BLUR "0"
68 #define DEF_INCREMENTAL "0"
69 #define DEF_HOLD_TIME "30"
70 #define DEF_FADE_TIME "5"
73 "*delay: " DEF_DELAY "\n" \
74 "*showFPS: " DEF_FPS "\n" \
75 "*wire: " DEF_WIRE "\n" \
76 "*blend: " DEF_BLEND "\n" \
77 "*fog: " DEF_FOG "\n" \
78 "*antialias: " DEF_ANTIALIAS "\n" \
79 "*walls: " DEF_WALLS "\n" \
80 "*colour : " DEF_COLOUR "\n" \
81 "*texture: " DEF_TEXTURE "\n" \
82 "*offset_texture: " DEF_OFFSET_TEXTURE "\n" \
83 "*paint_background: " DEF_PAINT_BACKGROUND "\n" \
84 "*x_resolution: " DEF_X_RES "\n" \
85 "*y_resolution: " DEF_Y_RES "\n" \
86 "*field_points: " DEF_FIELD_POINTS "\n" \
87 "*motion_blur: " DEF_MOTION_BLUR "\n" \
88 "*incremental: " DEF_INCREMENTAL "\n" \
89 "*hold_time: " DEF_HOLD_TIME "\n" \
90 "*fade_time: " DEF_FADE_TIME "\n"
92 # include "xlockmore.h" /* from the xscreensaver distribution */
93 #else /* !STANDALONE */
94 # include "xlock.h" /* from the xlockmore distribution */
95 #endif /* !STANDALONE */
97 #ifdef USE_GL /* whole file */
101 # include <X11/Xmu/Drawing.h>
103 # include <Xmu/Drawing.h>
113 /*#include <string.h>*/
114 #include "grab-ximage.h"
117 #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 motion_blur;
135 static int incremental;
136 static int fade_time;
137 static int hold_time;
139 static XrmOptionDescRec opts[] = {
140 {"-wire", ".blob.wire", XrmoptionNoArg, "true" },
141 {"+wire", ".blob.wire", XrmoptionNoArg, "false" },
142 {"-blend", ".blob.blend", XrmoptionNoArg, "true" },
143 {"+blend", ".blob.blend", XrmoptionNoArg, "false" },
144 {"-fog", ".blob.fog", XrmoptionNoArg, "true" },
145 {"+fog", ".blob.fog", XrmoptionNoArg, "false" },
146 {"-antialias", ".blob.antialias", XrmoptionNoArg, "true" },
147 {"+antialias", ".blob.antialias", XrmoptionNoArg, "false" },
148 {"-walls", ".blob.walls", XrmoptionNoArg, "true" },
149 {"+walls", ".blob.walls", XrmoptionNoArg, "false" },
150 {"-texture", ".blob.texture", XrmoptionNoArg, "true" },
151 {"+texture", ".blob.texture", XrmoptionNoArg, "false" },
152 {"-colour", ".blob.colour", XrmoptionNoArg, "true" },
153 {"+colour", ".blob.colour", XrmoptionNoArg, "false" },
154 {"-offset_texture", ".blob.offset_texture", XrmoptionNoArg, "true" },
155 {"+offset_texture", ".blob.offset_texture", XrmoptionNoArg, "false" },
156 {"-paint_background", ".blob.paint_background", XrmoptionNoArg, "true" },
157 {"+paint_background", ".blob.paint_background", XrmoptionNoArg, "false" },
158 {"-x_res", ".blob.x_res", XrmoptionSepArg, NULL },
159 {"-y_res", ".blob.y_res", XrmoptionSepArg, NULL },
160 {"-field_points", ".blob.field_points", XrmoptionSepArg, NULL },
161 {"-motion_blur", ".blob.motion_blur", XrmoptionSepArg, NULL },
162 {"-incremental", ".blob.incremental", XrmoptionSepArg, NULL },
163 {"-fade_time", ".blob.fade_time", XrmoptionSepArg, NULL },
164 {"-hold_time", ".blob.hold_time", XrmoptionSepArg, NULL },
167 static argtype vars[] = {
168 {&do_wire, "wire", "Wire", DEF_WIRE, t_Bool},
169 {&do_blend, "blend", "Blend", DEF_BLEND, t_Bool},
170 {&do_fog, "fog", "Fog", DEF_FOG, t_Bool},
171 {&do_antialias, "antialias", "Antialias", DEF_ANTIALIAS, t_Bool},
172 {&do_walls, "walls", "Walls", DEF_WALLS, t_Bool},
173 {&do_texture, "texture", "Texture", DEF_TEXTURE, t_Bool},
174 {&do_colour, "colour", "Colour", DEF_COLOUR, t_Bool},
175 {&offset_texture, "offset_texture","Offset_Texture", DEF_OFFSET_TEXTURE, t_Bool},
176 {&do_paint_background,"paint_background","Paint_Background", DEF_PAINT_BACKGROUND, t_Bool},
177 {&x_resolution, "x_res", "X_Res", DEF_X_RES, t_Int},
178 {&y_resolution, "y_res", "Y_Res", DEF_Y_RES, t_Int},
179 {&field_points, "field_points", "Field_Points", DEF_FIELD_POINTS, t_Int},
180 {&motion_blur, "motion_blur", "Motion_Blur", DEF_MOTION_BLUR, t_Int},
181 {&incremental, "incremental", "Incremental", DEF_INCREMENTAL, t_Int},
182 {&fade_time, "fade_time", "Fade_Time", DEF_FADE_TIME, t_Int},
183 {&hold_time, "hold_time", "Hold_Time", DEF_HOLD_TIME, t_Int},
187 static OptionStruct desc[] =
189 {"-/+ wire", "whether to do use wireframe instead of filled (faster)"},
190 {"-/+ blend", "whether to do enable blending (slower)"},
191 {"-/+ fog", "whether to do enable fog (slower)"},
192 {"-/+ antialias", "whether to do enable antialiased lines (slower)"},
193 {"-/+ walls", "whether to add walls to the blob space (slower)"},
194 {"-/+ texture", "whether to add a texture to the blob (slower)"},
195 {"-/+ colour", "whether to colour the blob"},
196 {"-/+ offset_texture", "whether to offset texture co-ordinates"},
197 {"-/+ paint_background", "whether to display a background texture (slower)"},
198 {"-x_res", "Blob resolution in x direction"},
199 {"-y_res", "Blob resolution in y direction"},
200 {"-field_points", "Number of field points used to disturb blob"},
201 {"-motion_blur", "Fade blob images (higher number = faster fade)"},
202 {"-incremental", "Field summation method"},
203 {"-fade_time", "Number of frames to transistion to next image"},
204 {"-hold_time", "Number of frames before next image"},
207 ModeSpecOpt screensaver_opts = {countof(opts), opts, countof(vars), vars, desc};
210 ModStruct screensaver_description =
211 {"screensaver", "init_screensaver", "draw_screensaver", "release_screensaver",
212 "draw_screensaver", "init_screensaver", NULL, &screensaver_opts,
213 1000, 1, 2, 1, 4, 1.0, "",
214 "OpenGL screensaver", 0, NULL};
217 /* structure for holding the screensaver data */
219 int screen_width, screen_height;
220 GLXContext *glx_context;
225 static screensaverstruct *Screensaver = NULL;
227 /*****************************************************************************
228 * Types used in blob code
229 *****************************************************************************/
243 GLubyte red, green, blue, alpha;
246 /* Data used for sphere tessellation */
251 /* Number of x points at each row of the blob */
255 /* Structure to hold sphere distortion data */
258 double cx, cy, cpower;
259 double mx, my, mpower;
260 double ax, ay, apower;
261 double vx, vy, vpower;
265 /*****************************************************************************
267 *****************************************************************************/
269 static Row_Data *row_data;
271 /* Parameters controlling the position of the blob as a whole */
272 static Vector3D blob_center = {0.0, 0.0, 0.0};
273 static Vector3D blob_anchor = {0.0, 0.0, 0.0};
274 static Vector3D blob_velocity = {0.0, 0.0, 0.0};
275 static Vector3D blob_force = {0.0, 0.0, 0.0};
277 /* Count of the total number of points */
278 static int num_points;
280 static Vector3D *dots = NULL;
281 static Vector3D *normals = NULL;
282 static Colour *colours = NULL;
283 static Vector2D *tex_coords = NULL;
285 /* Pointer to the field function results */
286 static double *field = 0, *wall_field = 0;
288 Field_Data *field_data;
290 /* Use 2 textures to allow a gradual fade between images */
291 #define NUM_TEXTURES 2
292 static int current_texture;
294 /* Ratio of used texture size to total texture size */
295 GLfloat tex_width[NUM_TEXTURES], tex_height[NUM_TEXTURES];
296 GLuint textures[NUM_TEXTURES];
304 static Frame_State state = HOLDING;
305 static double state_start_time = 0;
307 static int colour_cycle = 0;
309 /******************************************************************************
311 * Returns the current time in seconds as a double. Shamelessly borrowed from
319 # ifdef GETTIMEOFDAY_TWO_ARGS
321 gettimeofday(&now, &tzp);
326 return (now.tv_sec + ((double) now.tv_usec * 0.000001));
329 /******************************************************************************
331 * Change to the projection matrix and set our viewing volume.
335 reset_projection(int width, int height)
337 glMatrixMode (GL_PROJECTION);
339 gluPerspective (60.0, 1.0, 1.0, 1024.0 );
340 glMatrixMode (GL_MODELVIEW);
344 /****************************************************************************
346 * Load a texture using the screen_to_ximage function.
349 grab_texture(ModeInfo *mi, int texture_index)
353 ximage = screen_to_ximage (mi->xgwa.screen, mi->window, 0);
355 glBindTexture (GL_TEXTURE_2D, textures[texture_index]);
356 glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
358 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, ximage->width, ximage->height,
359 0, GL_RGBA, GL_UNSIGNED_BYTE, ximage->data);
361 tex_width[texture_index] = (mi->xgwa.width - 1) / (GLfloat)ximage->width;
362 tex_height[texture_index] = (mi->xgwa.height - 1) / (GLfloat)ximage->height;
364 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
365 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
367 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
368 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
370 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
374 XDestroyImage (ximage);
377 /******************************************************************************
379 * Initialise the data used to calculate the blob shape.
382 initialize_gl(ModeInfo *mi, GLsizei width, GLsizei height)
384 GLfloat fogColor[4] = { 0.1, 0.1, 0.1, 0.1 };
385 /* Lighting values */
386 GLfloat lightPos0[] = {500.0f, 100.0f, 200.0f, 1.0f };
387 GLfloat whiteLight0[] = { 0.1f, 0.1f, 0.1f, 1.0f };
388 GLfloat sourceLight0[] = { 1.0f, 1.0f, 1.0f, 1.0f };
389 GLfloat specularLight0[] = { 0.7f, 0.6f, 0.3f, 1.0f };
391 GLfloat lightPos1[] = {0.0f, -500.0f, 500.0f, 1.0f };
392 GLfloat whiteLight1[] = { 0.1f, 0.1f, 0.1f, 1.0f };
393 GLfloat sourceLight1[] = { 1.0f, 0.3f, 0.3f, 1.0f };
394 GLfloat specularLight1[] = { 0.7f, 0.6f, 0.3f, 1.0f };
396 GLfloat specref[] = { 1.0f, 1.0f, 1.0f, 1.0f };
398 /* Setup our viewport. */
399 glViewport (0, 0, width, height );
401 glEnable(GL_DEPTH_TEST);
406 glEnable(GL_LINE_SMOOTH);
409 /* The blend function is used for trasitioning between two images even when
410 * blend is not selected.
412 glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
416 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
420 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
426 glFogi(GL_FOG_MODE, GL_LINEAR);
427 glFogfv(GL_FOG_COLOR, fogColor);
428 glFogf(GL_FOG_DENSITY, 0.35);
429 glFogf(GL_FOG_START, 2.0);
430 glFogf(GL_FOG_END, 10.0);
433 /* Our shading model--Gouraud (smooth). */
434 glShadeModel (GL_SMOOTH);
437 glCullFace (GL_BACK);
438 glEnable (GL_CULL_FACE);
439 glEnable (GL_DEPTH_TEST);
440 glFrontFace (GL_CCW);
442 /* Set the clear color. */
443 glClearColor( 0, 0, 0, 0 );
445 glViewport( 0, 0, width, height );
447 glLightfv (GL_LIGHT0, GL_AMBIENT, whiteLight0);
448 glLightfv (GL_LIGHT0, GL_DIFFUSE, sourceLight0);
449 glLightfv (GL_LIGHT0, GL_SPECULAR, specularLight0);
450 glLightfv (GL_LIGHT0, GL_POSITION, lightPos0);
451 glEnable (GL_LIGHT0);
452 glLightfv (GL_LIGHT1, GL_AMBIENT, whiteLight1);
453 glLightfv (GL_LIGHT1, GL_DIFFUSE, sourceLight1);
454 glLightfv (GL_LIGHT1, GL_SPECULAR, specularLight1);
455 glLightfv (GL_LIGHT1, GL_POSITION, lightPos1);
456 glEnable (GL_LIGHT1);
457 glEnable (GL_LIGHTING);
459 /* Enable color tracking */
460 glEnable (GL_COLOR_MATERIAL);
462 /* Set Material properties to follow glColor values */
463 glColorMaterial (GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
465 /* Set all materials to have specular reflectivity */
466 glMaterialfv (GL_FRONT, GL_SPECULAR, specref);
467 glMateriali (GL_FRONT, GL_SHININESS, 64);
469 glEnable (GL_NORMALIZE);
474 glLightModeli (GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);
476 glEnable (GL_TEXTURE_2D);
478 glGenTextures (NUM_TEXTURES, textures);
479 grab_texture (mi, current_texture);
481 glEnableClientState (GL_TEXTURE_COORD_ARRAY);
486 glEnableClientState (GL_COLOR_ARRAY);
488 glEnableClientState (GL_NORMAL_ARRAY);
489 glEnableClientState (GL_VERTEX_ARRAY);
491 /* Clear the buffer since this is not done during a draw with motion blur */
492 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
495 /******************************************************************************
497 * Calculate the normal vector for a plane given three points in the plane.
500 calculate_normal (Vector3D point1,
505 Vector3D vector1, vector2;
508 vector1.x = point2.x - point1.x;
509 vector1.y = point2.y - point1.y;
510 vector1.z = point2.z - point1.z;
512 vector2.x = point3.x - point2.x;
513 vector2.y = point3.y - point2.y;
514 vector2.z = point3.z - point2.z;
516 (*normal).x = vector1.y * vector2.z - vector1.z * vector2.y;
517 (*normal).y = vector1.z * vector2.x - vector1.x * vector2.z;
518 (*normal).z = vector1.x * vector2.y - vector1.y * vector2.x;
520 /* Adjust the normal to unit magnitude */
521 magnitude = sqrt ((*normal).x * (*normal).x
522 + (*normal).y * (*normal).y
523 + (*normal).z * (*normal).z);
525 /* Watch out for divide by zero/underflow */
526 if (magnitude > 1e-300)
528 (*normal).x /= magnitude;
529 (*normal).y /= magnitude;
530 (*normal).z /= magnitude;
534 /******************************************************************************
536 * Initialise the data required to draw the blob allocating the memory as
539 * Return 0 on success.
542 initialise_blob(int width,
544 int field_array_size)
552 row_data = (Row_Data *) malloc (y_resolution * sizeof (Row_Data));
555 fprintf(stderr, "Couldn't allocate row data buffer\n");
559 field_data = (Field_Data *) malloc (field_points * sizeof (Field_Data));
562 fprintf(stderr, "Couldn't allocate field data buffer\n");
566 field = (double *)malloc(field_array_size * sizeof(double));
569 fprintf(stderr, "Couldn't allocate field buffer\n");
573 wall_field = (double *)malloc(field_array_size * sizeof(double));
576 fprintf(stderr, "Couldn't allocate wall field buffer\n");
580 dots = (Vector3D *)malloc(x_resolution * y_resolution * sizeof(Vector3D));
583 fprintf(stderr, "Couldn't allocate points buffer\n");
586 glVertexPointer (3, GL_DOUBLE, 0, (GLvoid *) dots);
588 normals = (Vector3D *)malloc(x_resolution * y_resolution * sizeof(Vector3D));
591 fprintf(stderr, "Couldn't allocate normals buffer\n");
594 glNormalPointer (GL_DOUBLE, 0, (GLvoid *) normals);
598 colours = (Colour *)malloc(x_resolution * y_resolution * sizeof(Colour));
601 fprintf(stderr, "Couldn't allocate colours buffer\n");
604 glColorPointer (4, GL_UNSIGNED_BYTE, 0, (GLvoid *) colours);
609 tex_coords = (Vector2D *)malloc(x_resolution * y_resolution
613 fprintf(stderr, "Couldn't allocate tex_coords buffer\n");
616 glTexCoordPointer (2, GL_DOUBLE, 0, (GLvoid *) tex_coords);
620 /* Generate constant row data and count of total number of points */
621 for (y = 0; y < y_resolution; y++)
623 row_data[y].cosyd = cos(PI * (double)(y * (y_resolution + 1))
624 / (double)(y_resolution * y_resolution));
625 row_data[y].sinyd = sin(PI * (double)(y * (y_resolution + 1))
626 / (double)(y_resolution * y_resolution));
627 row_data[y].num_x_points = (int)(x_resolution * row_data[y].sinyd + 1.0);
628 num_points += row_data[y].num_x_points;
631 /* Initialise field data */
632 for (i = 0; i < field_points; i++)
634 field_data[i].ax = 2.0 * (((double)random() / (double)RAND_MAX) - 0.5);
635 field_data[i].ay = 2.0 * (((double)random() / (double)RAND_MAX) - 0.5);
636 field_data[i].apower = (((double)random() / (double)RAND_MAX) - 0.5);
638 field_data[i].pos.x = 1.5 * sin(PI * field_data[i].ay)
639 * cos(PI * field_data[i].ax);
640 field_data[i].pos.y = 1.5 * cos(PI * field_data[i].ay);
641 field_data[i].pos.z = 1.5 * sin(PI * field_data[i].ay)
642 * sin(PI * field_data[i].ax);
644 field_data[i].cx = 2.0 * (((double)random() / (double)RAND_MAX) - 0.5);
645 field_data[i].cy = 2.0 * (((double)random() / (double)RAND_MAX) - 0.5);
646 field_data[i].cpower = (((double)random() / (double)RAND_MAX) - 0.5);
648 field_data[i].vx = 0.0;
649 field_data[i].vy = 0.0;
650 field_data[i].vpower = 0.0;
652 field_data[i].mx = 0.003 * ((double)random() / (double)RAND_MAX);
653 field_data[i].my = 0.003 * ((double)random() / (double)RAND_MAX);
654 field_data[i].mpower = 0.003 * ((double)random() / (double)RAND_MAX);
657 /* Initialise lookup table of field strength */
658 for (i = 0; i < field_array_size; i++)
660 xd = 2.0 * (((double)i / (double)field_array_size));
662 xd = 3.0 * xd * xd * xd * xd;
663 field[i] = 0.4 / (field_points * (xd + 0.1));
665 xd = 10.0 * (((double)i / (double)field_array_size));
666 wall_field[i] = 0.4 / (xd * xd * xd * xd + 1.0);
669 for (y = 0; y < y_resolution; y++)
671 for (x = 0; x < row_data[y].num_x_points; x++)
673 i = x + y * x_resolution;
674 xd = 2.0 * (((double)x / (double)row_data[y].num_x_points) - 0.5);
676 dots[i].x = row_data[y].sinyd * cos(PI * xd);
677 dots[i].y = row_data[y].cosyd;
678 dots[i].z = row_data[y].sinyd * sin(PI * xd);
679 normals[i].x = row_data[y].sinyd * cos(PI * xd);
680 normals[i].y = row_data[y].cosyd;
681 normals[i].z = row_data[y].sinyd * sin(PI * xd);
684 tex_coords[i].x = 2.0 - 2.0 * x / (float) row_data[y].num_x_points;
685 tex_coords[i].y = 1.0 - y / (float) y_resolution;
693 /******************************************************************************
695 * Calculate the blob shape.
700 int field_array_size,
704 static double freak = 0.0;
706 static double v_freak = 0.0007;
709 int x, y, i, index, index1, index2, index3;
710 /* position of a point */
711 double xd, yd, zd, offset_x, offset_y, offset_z;
712 double strength, radius;
713 double xdist, ydist, zdist;
716 /* Color components */
720 /* Update position and strength of points used to distort the blob */
721 for (i = 0; i < field_points; i++)
723 field_data[i].vx += field_data[i].mx*(field_data[i].cx - field_data[i].ax);
724 field_data[i].vy += field_data[i].my*(field_data[i].cy - field_data[i].ay);
725 field_data[i].vpower += field_data[i].mpower
726 * (field_data[i].cpower - field_data[i].apower);
728 field_data[i].ax += 0.1 * field_data[i].vx;
729 field_data[i].ay += 0.1 * field_data[i].vy;
730 field_data[i].apower += 0.1 * field_data[i].vpower;
732 field_data[i].pos.x = 1.0 * sin(PI * field_data[i].ay)
733 * cos(PI * field_data[i].ax);
734 field_data[i].pos.y = 1.0 * cos(PI * field_data[i].ay);
735 field_data[i].pos.z = 1.0 * sin(PI * field_data[i].ay)
736 * sin(PI * field_data[i].ax);
742 for (y = 0; y < y_resolution; y++)
744 for (x = 0; x < row_data[y].num_x_points; x++)
746 index = x + y * x_resolution;
747 xd = 2.0 * PI * (((double)x / (double)row_data[y].num_x_points) - 0.5);
749 radius = 1.0 + 0.0 * sin (xd * 10);
751 zd = radius * row_data[y].sinyd * sin(xd);
752 xd = radius * row_data[y].sinyd * cos(xd);
753 yd = radius * row_data[y].cosyd;
755 normals[index].x = xd;
756 normals[index].y = yd;
757 normals[index].z = zd;
763 for ( i = 0; i < field_points; i++)
765 xdist = field_data[i].pos.x - xd;
766 ydist = field_data[i].pos.y - yd;
767 zdist = field_data[i].pos.z - zd;
768 dist = field_array_size * (xdist * xdist + ydist * ydist
769 + zdist * zdist) * 0.1;
771 strength += PI * field_data[i].apower;
773 if (dist < field_array_size)
775 offset_x += xd * field_data[i].apower * field[dist];
776 offset_y += yd * field_data[i].apower * field[dist];
777 offset_z += zd * field_data[i].apower * field[dist];
779 blob_force.x += 1.0 * xd * field_data[i].apower * field[dist];
780 blob_force.y += 1.0 * yd * field_data[i].apower * field[dist];
781 blob_force.z += 1.0 * zd * field_data[i].apower * field[dist];
783 strength *= 2.0 * field[dist];
788 xd += offset_x * freak * freak;
789 yd += offset_y * freak * freak;
790 zd += offset_z * freak * freak;
792 if (incremental == 1)
812 colours[index].red = 128 + (int)(sin(strength + colour_cycle * 0.01 + 2.0 * PI * x / row_data[y].num_x_points) * 127.0);
813 colours[index].green = 128 + (int)(cos(strength + colour_cycle * 0.025) * 127.0);
814 colours[index].blue = 128 + (int)(sin(strength + colour_cycle * 0.03 + 2.0 * PI * y / y_resolution) * 127.0);
815 colours[index].alpha = (int)(255.0 * fade);
821 if (zd < -limit) zd = -limit;
822 if (zd > limit) zd = limit;
824 dist = field_array_size * (zd + limit) * (zd + limit) * 0.5;
825 if (dist < field_array_size)
827 xd += (xd - blob_center.x) * wall_field[dist];
828 yd += (yd - blob_center.y) * wall_field[dist];
829 blob_force.z += (zd + limit);
833 dist = field_array_size * (zd - limit) * (zd - limit) * 0.5;
834 if (dist < field_array_size)
836 xd += (xd - blob_center.x) * wall_field[dist];
837 yd += (yd - blob_center.y) * wall_field[dist];
838 blob_force.z -= (zd - limit);
841 if (yd < -limit) yd = -limit;
842 if (yd > limit) yd = limit;
844 dist = field_array_size * (yd + limit) * (yd + limit) * 0.5;
845 if (dist < field_array_size)
847 xd += (xd - blob_center.x) * wall_field[dist];
848 zd += (zd - blob_center.z) * wall_field[dist];
849 blob_force.y += (yd + limit);
853 dist = field_array_size * (yd - limit) * (yd - limit) * 0.5;
854 if (dist < field_array_size)
856 xd += (xd - blob_center.x) * wall_field[dist];
857 zd += (zd - blob_center.z) * wall_field[dist];
858 blob_force.y -= (yd - limit);
862 if (xd < -limit) xd = -limit;
863 if (xd > limit) xd = limit;
865 dist = field_array_size * (xd + limit) * (xd + limit) * 0.5;
866 if (dist < field_array_size)
868 yd += (yd - blob_center.y) * wall_field[dist];
869 zd += (zd - blob_center.z) * wall_field[dist];
870 blob_force.x += (xd + limit);
874 dist = field_array_size * (xd - limit) * (xd - limit) * 0.5;
875 if (dist < field_array_size)
877 yd += (yd - blob_center.y) * wall_field[dist];
878 zd += (zd - blob_center.z) * wall_field[dist];
879 blob_force.x -= (xd - limit);
883 if (yd < -limit) yd = -limit;
884 if (yd > limit) yd = limit;
894 /* Calculate the normals for each vertex and the texture mapping if required.
895 * Although the code actually calculates the normal for one of the triangles
896 * attached to a vertex rather than the vertex itself the results are not too
897 * bad for with a reasonable number of verticies.
900 /* The first point is treated as a special case since the loop expects to use
901 * points in the previous row to form the triangle.
904 index2 = y * x_resolution;
905 index3 = 1 + y * x_resolution;
906 calculate_normal (dots[index1], dots[index2], dots[index3], &normals[index1]);
911 tex_coords[index1].x = dots[index1].x * 0.125 + 0.5
912 * (1.0 + 0.25 * asin(normals[index1].x) / (0.5 * PI));
913 tex_coords[index1].y = dots[index1].y * 0.125 + 0.5
914 * (1.0 + 0.25 * asin(normals[index1].y) / (0.5 * PI));
918 tex_coords[index1].x = 0.5 * (1.0 + (asin(normals[index1].x)
920 tex_coords[index1].y = 0.5 * (1.0 + (asin(normals[index1].y)
923 tex_coords[index1].x *= tex_width[current_texture];
924 tex_coords[index1].y *= tex_height[current_texture];
927 for (y = 1; y < y_resolution - 1; y++)
929 if (row_data[y - 1].num_x_points)
931 for (x = 0; x < row_data[y].num_x_points; x++)
933 if (x == row_data[y].num_x_points - 1)
935 index1 = y * x_resolution;
939 index1 = x + 1 + y * x_resolution;
941 index2 = x + y * x_resolution;
942 index3 = ((x + 0.5) * row_data[y - 1].num_x_points
943 / row_data[y].num_x_points) + (y - 1) * x_resolution;
944 calculate_normal (dots[index1], dots[index2], dots[index3],
950 tex_coords[index1].x = dots[index1].x * 0.125 + 0.5
951 * (1.0 + 0.25 * asin(normals[index1].x) / (0.5 * PI));
952 tex_coords[index1].y = dots[index1].y * 0.125 + 0.5
953 * (1.0 + 0.25 * asin(normals[index1].y) / (0.5 * PI));
957 tex_coords[index1].x = 0.5 * (1.0 + (asin(normals[index1].x)
959 tex_coords[index1].y = 0.5 * (1.0 + (asin(normals[index1].y)
962 tex_coords[index1].x *= tex_width[current_texture];
963 tex_coords[index1].y *= tex_height[current_texture];
968 index1 = (y_resolution - 1) * x_resolution;
969 index2 = (y_resolution - 2) * x_resolution;
970 index3 = 1 + (y_resolution - 2) * x_resolution;
971 calculate_normal (dots[index1], dots[index2], dots[index3], &normals[index1]);
976 tex_coords[index1].x = dots[index1].x * 0.125 + 0.5
977 * (1.0 + 0.25 * asin(normals[index1].x) / (0.5 * PI));
978 tex_coords[index1].y = dots[index1].y * 0.125 + 0.5
979 * (1.0 + 0.25 * asin(normals[index1].y) / (0.5 * PI));
983 tex_coords[index1].x = 0.5 * (1.0 + (asin(normals[index1].x)
985 tex_coords[index1].y = 0.5 * (1.0 + (asin(normals[index1].y)
988 tex_coords[index1].x *= tex_width[current_texture];
989 tex_coords[index1].y *= tex_height[current_texture];
994 v_freak += -freak / 2000000.0;
996 /* Update the center of the whole blob */
997 blob_velocity.x += (blob_anchor.x - blob_center.x) / 80.0
998 + 0.01 * blob_force.x / num_points;
999 blob_velocity.y += (blob_anchor.y - blob_center.y) / 80.0
1000 + 0.01 * blob_force.y / num_points;
1001 blob_velocity.z += (blob_anchor.z - blob_center.z) / 80.0
1002 + 0.01 * blob_force.z / num_points;
1004 blob_center.x += blob_velocity.x * 0.5;
1005 blob_center.y += blob_velocity.y * 0.5;
1006 blob_center.z += blob_velocity.z * 0.5;
1008 blob_velocity.x *= 0.99;
1009 blob_velocity.y *= 0.99;
1010 blob_velocity.z *= 0.99;
1013 /******************************************************************************
1015 * Draw the blob shape.
1017 * The horrendous indexing to calculate the verticies that form a particular
1018 * traiangle is the result of the conversion of my first non-openGL version of
1019 * blob to this openGL version. This may be tidied up when I finally playing
1020 * with the more interesting bits of the code.
1026 int index1, index2, index3;
1029 glMatrixMode (GL_MODELVIEW);
1032 /* Move down the z-axis. */
1033 glTranslatef (0.0, 0.0, -5.0 );
1035 for (y = 1; y < y_resolution; y++)
1037 if (row_data[y - 1].num_x_points)
1039 for (x = 0; x < row_data[y].num_x_points; x++)
1041 glBegin (GL_TRIANGLES);
1042 if (x == row_data[y].num_x_points - 1)
1044 index1 = y * x_resolution;
1048 index1 = x + 1 + y * x_resolution;
1050 index2 = x + y * x_resolution;
1051 index3 = ((x + 0.5) * row_data[y - 1].num_x_points
1052 / row_data[y].num_x_points) + (y - 1) * x_resolution;
1053 glArrayElement(index1);
1054 glArrayElement(index2);
1055 glArrayElement(index3);
1058 lower = floorf((x - 0.5) * row_data[y - 1].num_x_points
1059 / (float)row_data[y].num_x_points);
1060 upper = floorf((x + 0.5) * row_data[y - 1].num_x_points
1061 / (float)row_data[y].num_x_points);
1065 glBegin (GL_TRIANGLE_FAN);
1066 index1 = x + y * x_resolution;
1068 for (x2 = lower; x2 <= upper; x2++)
1071 while (x3 < 0) x3 += row_data[y - 1].num_x_points;
1072 while (x3 >= row_data[y - 1].num_x_points)
1073 x3 -= row_data[y - 1].num_x_points;
1074 index2 = x3 + (y - 1) * x_resolution;
1079 while (x3 < 0) x3 += row_data[y - 1].num_x_points;
1080 while (x3 >= row_data[y - 1].num_x_points)
1081 x3 -= row_data[y - 1].num_x_points;
1082 index3 = x3 + (y - 1) * x_resolution;
1085 glArrayElement(index1);
1088 glArrayElement(index2);
1097 /******************************************************************************
1099 * Draw the background image simply map a texture onto a full screen quad.
1102 draw_background (ModeInfo *mi)
1104 glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
1105 glEnable (GL_TEXTURE_2D);
1106 glDisable(GL_LIGHTING);
1108 /* Reset the projection matrix to make it easier to get the size of the quad
1111 glMatrixMode(GL_PROJECTION);
1115 glOrtho(0.0, MI_WIDTH(mi), MI_HEIGHT(mi), 0.0, -1000.0, 1000.0);
1119 glTexCoord2f (0.0, tex_height[current_texture]);
1122 glTexCoord2f (0.0, 0.0);
1123 glVertex2i (0, MI_HEIGHT(mi));
1125 glTexCoord2f (tex_width[current_texture], 0.0);
1126 glVertex2i (MI_WIDTH(mi), MI_HEIGHT(mi));
1128 glTexCoord2f (tex_width[current_texture], tex_height[current_texture]);
1129 glVertex2i (MI_WIDTH(mi), 0);
1133 glMatrixMode (GL_MODELVIEW);
1134 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
1137 /******************************************************************************
1142 draw_scene(ModeInfo * mi)
1145 double current_time;
1146 check_gl_error ("draw_scene");
1148 glColor4d(1.0, 1.0, 1.0, 1.0);
1150 current_time = double_time();
1154 fade = (current_time - state_start_time) / fade_time;
1163 /* Set the correct texture, when transitioning this ensures that the first draw
1164 * is the original texture (which has the new texture drawn over it with decreasing
1169 glBindTexture (GL_TEXTURE_2D, textures[current_texture]);
1172 if (do_paint_background && !do_wire)
1174 glClear(GL_DEPTH_BUFFER_BIT);
1177 glEnable (GL_BLEND);
1178 glColor4ub (255, 255, 255, motion_blur);
1180 draw_background (mi);
1182 /* When transitioning between two images paint the new image over the old
1183 * image with a varying alpha value to get a smooth fade.
1185 if (state == TRANSITIONING)
1187 glDisable (GL_DEPTH_TEST);
1188 glEnable (GL_BLEND);
1189 /* Select the texture to transition to */
1190 glBindTexture (GL_TEXTURE_2D, textures[1 - current_texture]);
1191 glColor4d (1.0, 1.0, 1.0, fade);
1193 draw_background (mi);
1195 /* Select the original texture to draw the blob */
1196 glBindTexture (GL_TEXTURE_2D, textures[current_texture]);
1197 glEnable (GL_DEPTH_TEST);
1199 /* Clear the depth buffer bit so the backgound is behind the blob */
1200 glClear(GL_DEPTH_BUFFER_BIT);
1202 else if (motion_blur)
1204 glDisable (GL_DEPTH_TEST);
1205 glEnable (GL_BLEND);
1206 glColor4ub (0, 0, 0, motion_blur);
1207 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
1208 glRectd (-10.0, -10.0, 10.0, 10.0);
1211 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
1213 glEnable (GL_DEPTH_TEST);
1214 glClear (GL_DEPTH_BUFFER_BIT);
1218 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1226 calc_blob(MI_WIDTH(mi), MI_HEIGHT(mi), 1024, 2.5, fade);
1228 glEnable(GL_LIGHTING);
1229 glEnable(GL_LIGHT0);
1230 glEnable(GL_LIGHT1);
1234 glEnable (GL_BLEND);
1237 glBlendFunc (GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA);
1241 glColor4d (1.0, 1.0, 1.0, 0.5 - fade);
1246 glDisable (GL_BLEND);
1247 glColor4d (1.0, 1.0, 1.0, 1.0);
1251 if (do_blend && do_colour)
1253 glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1256 /* While transitioning draw a second blob twice with a modified alpha channel.
1257 * The trasitioning state machine is very crude, it simply counts frames
1258 * rather than elapsed time but it works.
1260 if (do_texture && (hold_time > 0))
1265 glClear(GL_DEPTH_BUFFER_BIT);
1266 glEnable (GL_BLEND);
1267 /* Select the texture to transition to */
1268 glBindTexture (GL_TEXTURE_2D, textures[1 - current_texture]);
1269 glColor4d (1.0, 1.0, 1.0, fade);
1272 if ((current_time - state_start_time) > fade_time)
1275 state_start_time = current_time;
1276 current_texture = 1 - current_texture;
1281 if ((current_time - state_start_time) > hold_time)
1283 grab_texture (mi, 1 - current_texture);
1284 state = TRANSITIONING;
1285 /* Get the time again rather than using the current time so
1286 * that the time taken by the grab_texture function is not part
1289 state_start_time = double_time();
1296 /******************************************************************************
1298 * XScreensaver screen update entry
1301 draw_screensaver(ModeInfo * mi)
1303 screensaverstruct *gp = &Screensaver[MI_SCREEN(mi)];
1304 Display *display = MI_DISPLAY(mi);
1305 Window window = MI_WINDOW(mi);
1307 if (!gp->glx_context)
1310 glXMakeCurrent(display, window, *(gp->glx_context));
1312 if (mi->fps_p) do_fps (mi);
1313 glXSwapBuffers(display, window);
1316 /******************************************************************************
1318 * XScreensaver screen resize entry
1321 reshape_screensaver(ModeInfo *mi, int width, int height)
1323 glViewport( 0, 0, MI_WIDTH(mi), MI_HEIGHT(mi) );
1324 reset_projection(width, height);
1327 /******************************************************************************
1329 * XScreensaver initialise entry
1332 init_screensaver(ModeInfo * mi)
1334 int screen = MI_SCREEN(mi);
1336 screensaverstruct *gp;
1338 if (Screensaver == NULL)
1340 if ((Screensaver = (screensaverstruct *)
1341 calloc(MI_NUM_SCREENS(mi), sizeof (screensaverstruct))) == NULL)
1346 gp = &Screensaver[screen];
1348 gp->window = MI_WINDOW(mi);
1349 if ((gp->glx_context = init_GL(mi)) != NULL)
1351 reshape_screensaver(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
1352 initialize_gl(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
1359 initialise_blob(MI_WIDTH(mi), MI_HEIGHT(mi), 1024);
1360 state_start_time = double_time();
1363 /******************************************************************************
1365 * XScreensaver cleanup entry
1368 release_screensaver(ModeInfo * mi)
1370 if (row_data) free(row_data);
1371 if (field_data) free(field_data);
1372 if (colours) free(colours);
1373 if (tex_coords) free(tex_coords);
1374 if (dots) free(dots);
1375 if (wall_field) free(wall_field);
1376 if (field) free(field);
1378 if (Screensaver != NULL)
1380 (void) free((void *) Screensaver);