diff options
| author | Simon Rettberg | 2024-09-06 14:42:37 +0200 |
|---|---|---|
| committer | Simon Rettberg | 2024-09-06 14:42:37 +0200 |
| commit | badef32037f52f79abc1f1440b786cd71afdf270 (patch) | |
| tree | 412b792d4cab4a7a110db82fcf74fe8a1ac55ec1 /hacks/glx/mirrorblob.c | |
| parent | Delete pre-6.00 files (diff) | |
| download | xscreensaver-master.tar.gz xscreensaver-master.tar.xz xscreensaver-master.zip | |
Diffstat (limited to 'hacks/glx/mirrorblob.c')
| -rw-r--r-- | hacks/glx/mirrorblob.c | 1840 |
1 files changed, 0 insertions, 1840 deletions
diff --git a/hacks/glx/mirrorblob.c b/hacks/glx/mirrorblob.c deleted file mode 100644 index 4e754bb..0000000 --- a/hacks/glx/mirrorblob.c +++ /dev/null @@ -1,1840 +0,0 @@ -/* mirrorblob Copyright (c) 2003 Jon Dowdall <jon.dowdall@bigpond.com> */ -/* - * Permission to use, copy, modify, and distribute this software and its - * documentation for any purpose and without fee is hereby granted, - * provided that the above copyright notice appear in all copies and that - * both that copyright notice and this permission notice appear in - * supporting documentation. - * - * This file is provided AS IS with no warranties of any kind. The author - * shall have no liability with respect to the infringement of copyrights, - * trade secrets or any patents by this file or any part thereof. In no - * event will the author be liable for any lost revenue or profits or - * other special, indirect and consequential damages. - * - * Revision History: - * 23-Sep-2003: jon.dowdall@bigpond.com Created module "blob" - * 19-Oct-2003: jon.dowdall@bigpond.com Added texturing - * 21-Oct-2003: Renamed to mirrorblob - * 10-Feb-2004: jon.dowdall@bigpond.com Added motion blur - * 28-Jan-2006: jon.dowdall@bigpond.com Big clean up and bug fixes - * 13-Apr-2009: jon.dowdall@gmail.com Fixed Mac version - * - * The mirrorblob screensaver draws a pulsing blob on the screen. Options - * include adding a background (via screen_to_texture), texturing the blob, - * making the blob semi-transparent and varying the resolution of the blob - * tessellation. - * - * The blob was inspired by a lavalamp is in no way a simulation. The code is - * just an attempt to generate some eye-candy. - * - * Much of xmirrorblob code framework is taken from the pulsar module by David - * Konerding and the glslideshow by Mike Oliphant and Jamie Zawinski. - * - */ - -#include <math.h> - -#ifdef STANDALONE -#define DEFAULTS "*delay: " DEF_DELAY "\n" \ - "*showFPS: " DEF_FPS "\n" \ - "*useSHM: True \n" \ - "*desktopGrabber: xscreensaver-getimage -no-desktop %s\n" \ - "*grabDesktopImages: True \n" \ - "*chooseRandomImages: True \n" \ - "*suppressRotationAnimation: True\n" \ - -# define release_mirrorblob 0 -# include "xlockmore.h" -#else /* !STANDALONE */ -# include "xlock.h" /* from the xlockmore distribution */ -#endif /* !STANDALONE */ - -#ifdef USE_GL /* whole file */ - - -#define DEF_DELAY "10000" -#define DEF_FPS "False" -#define DEF_WIRE "False" -#define DEF_BLEND "1.0" -#define DEF_FOG "False" -#define DEF_ANTIALIAS "False" -#define DEF_WALLS "False" -#define DEF_COLOUR "False" -#define DEF_ASYNC "True" -#define DEF_TEXTURE "True" -#define DEF_OFFSET_TEXTURE "False" -#define DEF_PAINT_BACKGROUND "True" -#define DEF_RESOLUTION "30" -#define DEF_BUMPS "10" -#define DEF_MOTION_BLUR "0.0" -#define DEF_INCREMENTAL "0" -#define DEF_HOLD_TIME "30.0" -#define DEF_FADE_TIME "5.0" -#define DEF_ZOOM "1.0" - -#include "gltrackball.h" -#include "grab-ximage.h" - -#define PI M_PI - -/* Options from command line */ -static GLfloat blend; -static Bool wireframe; -static Bool do_fog; -static Bool do_antialias; -static Bool do_walls; -static Bool do_texture; -static Bool do_paint_background; -static Bool do_colour; -static Bool offset_texture; -static int resolution; -static int bumps; -static float motion_blur; -static float fade_time; -static float hold_time; -static float zoom; - -/* Internal parameters based on supplied options */ -static Bool culling; -static Bool load_textures; - -static XrmOptionDescRec opts[] = { - {"-wire", ".blob.wire", XrmoptionNoArg, "true" }, - {"+wire", ".blob.wire", XrmoptionNoArg, "false" }, - {"-blend", ".blob.blend", XrmoptionSepArg, 0 }, - {"-fog", ".blob.fog", XrmoptionNoArg, "true" }, - {"+fog", ".blob.fog", XrmoptionNoArg, "false" }, - {"-antialias", ".blob.antialias", XrmoptionNoArg, "true" }, - {"+antialias", ".blob.antialias", XrmoptionNoArg, "false" }, - {"-walls", ".blob.walls", XrmoptionNoArg, "true" }, - {"+walls", ".blob.walls", XrmoptionNoArg, "false" }, - {"-texture", ".blob.texture", XrmoptionNoArg, "true" }, - {"+texture", ".blob.texture", XrmoptionNoArg, "false" }, - {"-colour", ".blob.colour", XrmoptionNoArg, "true" }, - {"+colour", ".blob.colour", XrmoptionNoArg, "false" }, - {"-offset-texture", ".blob.offsetTexture", XrmoptionNoArg, "true" }, - {"+offset-texture", ".blob.offsetTexture", XrmoptionNoArg, "false" }, - {"-paint-background", ".blob.paintBackground", XrmoptionNoArg, "true" }, - {"+paint-background", ".blob.paintBackground", XrmoptionNoArg, "false" }, - {"-resolution", ".blob.resolution", XrmoptionSepArg, NULL }, - {"-bumps", ".blob.bumps", XrmoptionSepArg, NULL }, - {"-motion-blur", ".blob.motionBlur", XrmoptionSepArg, 0 }, - {"-fade-time", ".blob.fadeTime", XrmoptionSepArg, 0 }, - {"-hold-time", ".blob.holdTime", XrmoptionSepArg, 0 }, - {"-zoom", ".blob.zoom", XrmoptionSepArg, 0 }, -}; - -static argtype vars[] = { - {&wireframe, "wire", "Wire", DEF_WIRE, t_Bool}, - {&blend, "blend", "Blend", DEF_BLEND, t_Float}, - {&do_fog, "fog", "Fog", DEF_FOG, t_Bool}, - {&do_antialias, "antialias", "Antialias", DEF_ANTIALIAS, t_Bool}, - {&do_walls, "walls", "Walls", DEF_WALLS, t_Bool}, - {&do_texture, "texture", "Texture", DEF_TEXTURE, t_Bool}, - {&do_colour, "colour", "Colour", DEF_COLOUR, t_Bool}, - {&offset_texture, "offsetTexture","OffsetTexture", DEF_OFFSET_TEXTURE, t_Bool}, - {&do_paint_background,"paintBackground","PaintBackground", DEF_PAINT_BACKGROUND, t_Bool}, - {&resolution, "resolution", "Resolution", DEF_RESOLUTION, t_Int}, - {&bumps, "bumps", "Bump", DEF_BUMPS, t_Int}, - {&motion_blur, "motionBlur", "MotionBlur", DEF_MOTION_BLUR, t_Float}, - {&fade_time, "fadeTime", "FadeTime", DEF_FADE_TIME, t_Float}, - {&hold_time, "holdTime", "HoldTime", DEF_HOLD_TIME, t_Float}, - {&zoom, "zoom", "Zoom", DEF_ZOOM, t_Float}, -}; - - -static OptionStruct desc[] = -{ - {"-/+ wire", "whether to do use wireframe instead of filled (faster)"}, - {"-/+ blend", "whether to do enable blending (slower)"}, - {"-/+ fog", "whether to do enable fog (slower)"}, - {"-/+ antialias", "whether to do enable antialiased lines (slower)"}, - {"-/+ walls", "whether to add walls to the blob space (slower)"}, - {"-/+ texture", "whether to add a texture to the blob (slower)"}, - {"-/+ colour", "whether to colour the blob"}, - {"-/+ offset_texture", "whether to offset texture co-ordinates"}, - {"-/+ paint_background", "whether to display a background texture (slower)"}, - {"-resolution", "Resolution of blob tesselation"}, - {"-bumps", "Number of bumps used to disturb blob"}, - {"-motion_blur", "Fade blob images (higher number = faster fade)"}, - {"-fade_time", "Number of frames to transition to next image"}, - {"-hold_time", "Number of frames before next image"}, -}; - -ENTRYPOINT ModeSpecOpt mirrorblob_opts = {countof(opts), opts, countof(vars), vars, desc}; - -#ifdef USE_MODULES -ModStruct mirrorblob_description = -{"mirrorblob", "init_mirrorblob", "draw_mirrorblob", NULL, - "draw_mirrorblob", "init_mirrorblob", "free_mirrorblob", &mirrorblob_opts, - 1000, 1, 2, 1, 4, 1.0, "", - "OpenGL mirrorblob", 0, NULL}; -#endif - -/***************************************************************************** - * Types used in blob code - *****************************************************************************/ - -typedef struct -{ - GLfloat x, y; -} Vector2D; - -typedef struct -{ - GLfloat x, y, z; -} Vector3D; - -typedef struct -{ - GLfloat w; - GLfloat x; - GLfloat y; - GLfloat z; -} Quaternion; - -typedef struct -{ - GLubyte red, green, blue, alpha; -} Colour; - -typedef struct -{ - Vector3D initial_position; - Vector3D position; - Vector3D normal; -} Node_Data; - -typedef struct -{ - int node1, node2, node3; - Vector3D normal; - double length1, length2, length3; -} Face_Data; - -/* Structure to hold data about bumps used to distortion sphere */ -typedef struct -{ - double cx, cy, cpower, csize; - double ax, ay, power, size; - double mx, my, mpower, msize; - double vx, vy, vpower, vsize; - Vector3D pos; -} Bump_Data; - -/* Vertices of a tetrahedron */ -#define sqrt_3 0.5773502692 -/*#undef sqrt_3 -#define sqrt_3 1.0*/ -#define PPP { sqrt_3, sqrt_3, sqrt_3 } /* +X, +Y, +Z */ -#define MMP { -sqrt_3, -sqrt_3, sqrt_3 } /* -X, -Y, +Z */ -#define MPM { -sqrt_3, sqrt_3, -sqrt_3 } /* -X, +Y, -Z */ -#define PMM { sqrt_3, -sqrt_3, -sqrt_3 } /* +X, -Y, -Z */ - -/* Structure describing a tetrahedron */ -static Vector3D tetrahedron[4][3] = { - {PPP, MMP, MPM}, - {PMM, MPM, MMP}, - {PPP, MPM, PMM}, - {PPP, PMM, MMP} -}; - -/***************************************************************************** - * Static blob data - *****************************************************************************/ - -static const Vector3D zero_vector = { 0.0, 0.0, 0.0 }; - -/* Use 2 textures to allow a gradual fade between images */ -#define NUM_TEXTURES 2 -#define BUMP_ARRAY_SIZE 1024 - -typedef enum -{ - INITIALISING, - HOLDING, - LOADING, - TRANSITIONING -} Frame_State; - -/* structure for holding the mirrorblob data */ -typedef struct { - int screen_width, screen_height; - GLXContext *glx_context; - Window window; - XColor fg, bg; - - /* Parameters controlling the position of the blob as a whole */ - Vector3D blob_center; - Vector3D blob_anchor; - Vector3D blob_velocity; - Vector3D blob_force; - - /* Count of the total number of nodes and faces used to tesselate the blob */ - int num_nodes; - int num_faces; - - Node_Data *nodes; - Face_Data *faces; - - Vector3D *dots; - Vector3D *normals; - Colour *colours; - Vector2D *tex_coords; - - /* Pointer to the bump function results */ - double *bump_shape, *wall_shape; - - Bump_Data *bump_data; - - /* Use 2 textures to allow a gradual fade between images */ - int current_texture; - - /* Ratio of used texture size to total texture size */ - GLfloat tex_width[NUM_TEXTURES], tex_height[NUM_TEXTURES]; - GLuint textures[NUM_TEXTURES]; - - Frame_State state; - double state_start_time; - - int colour_cycle; - - Bool mipmap_p; - Bool waiting_for_image_p; - Bool first_image_p; - - trackball_state *trackball; - int button_down; - -} mirrorblobstruct; - -static mirrorblobstruct *Mirrorblob = NULL; - -/****************************************************************************** - * - * Returns the current time in seconds as a double. Shamelessly borrowed from - * glslideshow. - * - */ -static double -double_time (void) -{ - struct timeval now; -# ifdef GETTIMEOFDAY_TWO_ARGS - struct timezone tzp; - gettimeofday(&now, &tzp); -# else - gettimeofday(&now); -# endif - - return (now.tv_sec + ((double) now.tv_usec * 0.000001)); -} - -/****************************************************************************** - * - * Change to the projection matrix and set our viewing volume. - * - */ -static void -reset_projection(int width, int height) -{ - glMatrixMode (GL_PROJECTION); - glLoadIdentity (); - gluPerspective (60.0, 1.0, 1.0, 1024.0 ); - glMatrixMode (GL_MODELVIEW); - glLoadIdentity (); -} - -/****************************************************************************** - * - * Calculate the dot product of two vectors u and v - * Dot product u.v = |u||v|cos(theta) - * Where theta = angle between u and v - */ -static inline double -dot (const Vector3D u, const Vector3D v) -{ - return (u.x * v.x) + (u.y * v.y) + (u.z * v.z); -} - -/****************************************************************************** - * - * Calculate the cross product of two vectors. - * Gives a vector perpendicular to u and v with magnitude |u||v|sin(theta) - * Where theta = angle between u and v - */ -static inline Vector3D -cross (const Vector3D u, const Vector3D v) -{ - Vector3D result; - - result.x = (u.y * v.z - u.z * v.y); - result.y = (u.z * v.x - u.x * v.z); - result.z = (u.x * v.y - u.y * v.x); - - return result; -} - -/****************************************************************************** - * - * Add vector v to vector u - */ -static inline void -add (Vector3D *u, const Vector3D v) -{ - u->x = u->x + v.x; - u->y = u->y + v.y; - u->z = u->z + v.z; -} - -/****************************************************************************** - * - * Subtract vector v from vector u - */ -static inline Vector3D -subtract (const Vector3D u, const Vector3D v) -{ - Vector3D result; - - result.x = u.x - v.x; - result.y = u.y - v.y; - result.z = u.z - v.z; - - return result; -} - -/****************************************************************************** - * - * multiply vector v by scalar s - */ -static inline Vector3D -scale (const Vector3D v, const double s) -{ - Vector3D result; - - result.x = v.x * s; - result.y = v.y * s; - result.z = v.z * s; - return result; -} - -/****************************************************************************** - * - * normalise vector v - */ -static inline Vector3D -normalise (const Vector3D v) -{ - Vector3D result; - double magnitude; - - magnitude = sqrt (dot(v, v)); - - if (magnitude > 1e-300) - { - result = scale (v, 1.0 / magnitude); - } - else - { - printf("zero\n"); - result = zero_vector; - } - return result; -} - -/****************************************************************************** - * - * Calculate the transform matrix for the given quaternion - */ -static void -quaternion_transform (Quaternion q, GLfloat * transform) -{ - GLfloat x, y, z, w; - x = q.x; - y = q.y; - z = q.z; - w = q.w; - - transform[0] = (w * w) + (x * x) - (y * y) - (z * z); - transform[1] = (2.0 * x * y) + (2.0 * w * z); - transform[2] = (2.0 * x * z) - (2.0 * w * y); - transform[3] = 0.0; - - transform[4] = (2.0 * x * y) - (2.0 * w * z); - transform[5] = (w * w) - (x * x) + (y * y) - (z * z); - transform[6] = (2.0 * y * z) + (2.0 * w * x); - transform[7] = 0.0; - - transform[8] = (2.0 * x * z) + (2.0 * w * y); - transform[9] = (2.0 * y * z) - (2.0 * w * x); - transform[10] = (w * w) - (x * x) - (y * y) + (z * z); - transform[11] = 0.0; - - transform[12] = 0.0; - transform[13] = 0.0; - transform[14] = 0.0; - transform[15] = (w * w) + (x * x) + (y * y) + (z * z); -} - -/****************************************************************************** - * - * Apply a matrix transform to the given vector - */ -static inline Vector3D -vector_transform (Vector3D u, GLfloat * t) -{ - Vector3D result; - - result.x = (u.x * t[0] + u.y * t[4] + u.z * t[8] + 1.0 * t[12]); - result.y = (u.x * t[1] + u.y * t[5] + u.z * t[9] + 1.0 * t[13]); - result.z = (u.x * t[2] + u.y * t[6] + u.z * t[10] + 1.0 * t[14]); - - return result; -} - -/****************************************************************************** - * - * Return a node that is on an arc between node1 and node2, where distance - * is the proportion of the distance from node1 to the total arc. - */ -static Vector3D -partial (Vector3D node1, Vector3D node2, double distance) -{ - Vector3D result; - Vector3D rotation_axis; - GLfloat transformation[16]; - double angle; - Quaternion rotation; - - rotation_axis = normalise (cross (node1, node2)); - angle = acos (dot (node1, node2)) * distance; - - rotation.x = rotation_axis.x * sin (angle / 2.0); - rotation.y = rotation_axis.y * sin (angle / 2.0); - rotation.z = rotation_axis.z * sin (angle / 2.0); - rotation.w = cos (angle / 2.0); - - quaternion_transform (rotation, transformation); - - result = vector_transform (node1, transformation); - - return result; -} - -/**************************************************************************** - * - * Callback indicating a texture has loaded - */ -static void -image_loaded_cb (const char *filename, XRectangle *geometry, - int image_width, int image_height, - int texture_width, int texture_height, - void *closure) -{ - mirrorblobstruct *mp = (mirrorblobstruct *) closure; - GLint texid = -1; - int texture_index = -1; - int i; - - glGetIntegerv (GL_TEXTURE_BINDING_2D, &texid); - if (texid < 0) abort(); - - for (i = 0; i < NUM_TEXTURES; i++) { - if (mp->textures[i] == texid) { - texture_index = i; - break; - } - } - if (texture_index < 0) abort(); - - mp->tex_width [texture_index] = (GLfloat) image_width / texture_width; - mp->tex_height[texture_index] = -(GLfloat) image_height / texture_height; - - glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, - (mp->mipmap_p ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR)); - glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - - mp->waiting_for_image_p = False; - mp->first_image_p = True; -} - -/* Load a new file into a texture - */ -static void -grab_texture(ModeInfo *mi, int texture_index) -{ - mirrorblobstruct *mp = &Mirrorblob[MI_SCREEN(mi)]; - - { - int w = (MI_WIDTH(mi) / 2) - 1; - int h = (MI_HEIGHT(mi) / 2) - 1; - if (w <= 10) w = 10; - if (h <= 10) h = 10; - - mp->waiting_for_image_p = True; - mp->mipmap_p = True; - load_texture_async (mi->xgwa.screen, mi->window, - *mp->glx_context, w, h, mp->mipmap_p, - mp->textures[texture_index], - image_loaded_cb, mp); - } -} - -/****************************************************************************** - * - * Generate internal parameters based on supplied options the parameters to - * ensure they are consistant. - */ -static void -set_parameters(void) -{ -# ifdef HAVE_JWZGLES /* #### glPolygonMode other than GL_FILL unimplemented */ - wireframe = 0; -# endif - - /* In wire frame mode do not draw a texture */ - if (wireframe) - { - do_texture = False; - blend = 1.0; - } - - /* Need to load textures if either the blob or the backgound has an image */ - if (do_texture || do_paint_background) - { - load_textures = True; - } - else - { - load_textures = False; - } - - /* If theres no texture don't calculate co-ordinates. */ - if (!do_texture) - { - offset_texture = False; - } - - culling = True; -} - -/****************************************************************************** - * - * Initialise the openGL state data. - */ -static void -initialize_gl(ModeInfo *mi, GLsizei width, GLsizei height) -{ - mirrorblobstruct *gp = &Mirrorblob[MI_SCREEN(mi)]; - - /* Lighting values */ - GLfloat ambientLight[] = { 0.2f, 0.2f, 0.2f, 1.0f }; - - GLfloat lightPos0[] = {500.0f, 100.0f, 200.0f, 1.0f }; - GLfloat whiteLight0[] = { 0.0f, 0.0f, 0.0f, 1.0f }; - GLfloat sourceLight0[] = { 0.6f, 0.6f, 0.6f, 1.0f }; - GLfloat specularLight0[] = { 0.8f, 0.8f, 0.9f, 1.0f }; - - GLfloat lightPos1[] = {-50.0f, -100.0f, 2500.0f, 1.0f }; - GLfloat whiteLight1[] = { 0.0f, 0.0f, 0.0f, 1.0f }; - GLfloat sourceLight1[] = { 0.6f, 0.6f, 0.6f, 1.0f }; - GLfloat specularLight1[] = { 0.7f, 0.7f, 0.7f, 1.0f }; - - GLfloat specref[] = { 1.0f, 1.0f, 1.0f, 1.0f }; - - GLfloat fogColor[4] = { 0.4, 0.4, 0.5, 0.1 }; - - /* Set the internal parameters based on the configuration settings */ - set_parameters(); - - /* Set the viewport to the width and heigh of the window */ - glViewport (0, 0, width, height ); - - if (do_antialias) - { - blend = 1.0; - glEnable(GL_LINE_SMOOTH); - glEnable(GL_POLYGON_SMOOTH); - } - - /* The blend function is used for trasitioning between two images even when - * blend is not selected. - */ - glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - if (do_fog) - { - glEnable(GL_FOG); - glFogfv(GL_FOG_COLOR, fogColor); - glFogf(GL_FOG_DENSITY, 0.50); - glFogf(GL_FOG_START, 15.0); - glFogf(GL_FOG_END, 30.0); - } - - /* Set the shading model to smooth (Gouraud shading). */ - glShadeModel (GL_SMOOTH); - - glLightModelfv (GL_LIGHT_MODEL_AMBIENT, ambientLight); - glLightfv (GL_LIGHT0, GL_AMBIENT, whiteLight0); - glLightfv (GL_LIGHT0, GL_DIFFUSE, sourceLight0); - glLightfv (GL_LIGHT0, GL_SPECULAR, specularLight0); - glLightfv (GL_LIGHT0, GL_POSITION, lightPos0); - glEnable (GL_LIGHT0); - glLightfv (GL_LIGHT1, GL_AMBIENT, whiteLight1); - glLightfv (GL_LIGHT1, GL_DIFFUSE, sourceLight1); - glLightfv (GL_LIGHT1, GL_SPECULAR, specularLight1); - glLightfv (GL_LIGHT1, GL_POSITION, lightPos1); - glEnable (GL_LIGHT1); - glEnable (GL_LIGHTING); - - /* Enable color tracking */ - glEnable (GL_COLOR_MATERIAL); - - /* Set Material properties to follow glColor values */ - glColorMaterial (GL_FRONT, GL_AMBIENT_AND_DIFFUSE); - - /* Set all materials to have specular reflectivity */ - glMaterialfv (GL_FRONT, GL_SPECULAR, specref); - glMateriali (GL_FRONT, GL_SHININESS, 32); - - /* Let GL implementation scale normal vectors. */ - glEnable (GL_NORMALIZE); - - /* Enable Arrays */ - if (load_textures) - { - glLightModeli (GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR); - glEnable (GL_TEXTURE_2D); - - gp->current_texture = 0; - glGenTextures(NUM_TEXTURES, gp->textures); - grab_texture(mi, gp->current_texture); - - glMatrixMode (GL_TEXTURE); - glRotated (180.0, 1.0, 0.0, 0.0); - glMatrixMode (GL_MODELVIEW); - } - - /* Clear the buffer since this is not done during a draw with motion blur */ - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); -} - -/****************************************************************************** - * - * Initialise the openGL state data. - */ -static void -set_blob_gl_state(GLfloat alpha) -{ - if (do_antialias) - { - glEnable(GL_LINE_SMOOTH); - glEnable(GL_POLYGON_SMOOTH); - } - - if (wireframe) - { - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - } - else - { - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - } - - /* The blend function is used for trasitioning between two images even when - * blend is not selected. - */ - glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - /* Culling. */ - if (culling) - { - glCullFace (GL_BACK); - glEnable (GL_CULL_FACE); - glFrontFace (GL_CCW); - } - else - { - glDisable (GL_CULL_FACE); - } - - if (blend < 1.0) - { - glEnable (GL_BLEND); - glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - /* Set the default blob colour to off-white. */ - glColor4f (0.9, 0.9, 1.0, alpha); - } - else - { - glDisable(GL_BLEND); - glColor4f (0.9, 0.9, 1.0, 1.0); - } - - glEnable(GL_DEPTH_TEST); - glEnable(GL_LIGHTING); -} - -/****************************************************************************** - * - * Initialise the data required to draw the blob allocating the memory as - * necessary. - * - * Return 0 on success. - */ -static int -initialise_blob(mirrorblobstruct *gp, - int width, - int height, - int bump_array_size) -{ - /* Loop variables */ - int i, u, v, node, side, face, base, base2 = 0; - int nodes_on_edge = resolution; - Vector3D node1, node2, result; - - if (nodes_on_edge < 2) - return -1; - - gp->num_nodes = 2 * nodes_on_edge * nodes_on_edge - 4 * nodes_on_edge + 4; - gp->num_faces = 4 * (nodes_on_edge - 1) * (nodes_on_edge - 1); - - gp->nodes = (Node_Data *) malloc (gp->num_nodes * sizeof (Node_Data)); - if (!gp->nodes) - { - fprintf (stderr, "Couldn't allocate gp->nodes buffer\n"); - return -1; - } - - gp->faces = (Face_Data *) malloc (gp->num_faces * sizeof (Face_Data)); - if (!gp->faces) - { - fprintf (stderr, "Couldn't allocate faces data buffer\n"); - return -1; - } - - gp->bump_data = (Bump_Data *) malloc (bumps * sizeof (Bump_Data)); - if (!gp->bump_data) - { - fprintf(stderr, "Couldn't allocate bump data buffer\n"); - return -1; - } - - gp->bump_shape = (double *)malloc(bump_array_size * sizeof(double)); - if (!gp->bump_shape) - { - fprintf(stderr, "Couldn't allocate bump buffer\n"); - return -1; - } - - gp->wall_shape = (double *)malloc(bump_array_size * sizeof(double)); - if (!gp->wall_shape) - { - fprintf(stderr, "Couldn't allocate wall bump buffer\n"); - return -1; - } - - - gp->dots = (Vector3D *)malloc(gp->num_nodes * sizeof(Vector3D)); - if (!gp->dots) - { - fprintf(stderr, "Couldn't allocate nodes buffer\n"); - return -1; - } - - gp->normals = (Vector3D *)malloc(gp->num_nodes * sizeof(Vector3D)); - if (!gp->normals) - { - fprintf(stderr, "Couldn't allocate normals buffer\n"); - return -1; - } - - gp->colours = (Colour *)malloc(gp->num_nodes * sizeof(Colour)); - if (!gp->colours) - { - fprintf(stderr, "Couldn't allocate colours buffer\n"); - return -1; - } - - gp->tex_coords = (Vector2D *)malloc(gp->num_nodes * sizeof(Vector2D)); - if (!gp->tex_coords) - { - fprintf(stderr, "Couldn't allocate gp->tex_coords buffer\n"); - return -1; - } - - - /* Initialise bump data */ - for (i = 0; i < bumps; i++) - { - gp->bump_data[i].ax = 2.0 * (((double)random() / (double)RAND_MAX) - 0.5); - gp->bump_data[i].ay = 2.0 * (((double)random() / (double)RAND_MAX) - 0.5); - gp->bump_data[i].power = (5.0 / pow(bumps, 0.75)) * (((double)random() / (double)RAND_MAX) - 0.5); - gp->bump_data[i].size = 0.1 + 0.5 * (((double)random() / (double)RAND_MAX)); - - gp->bump_data[i].pos.x = 1.5 * sin(PI * gp->bump_data[i].ay) - * cos(PI * gp->bump_data[i].ax); - gp->bump_data[i].pos.y = 1.5 * cos(PI * gp->bump_data[i].ay); - gp->bump_data[i].pos.z = 1.5 * sin(PI * gp->bump_data[i].ay) - * sin(PI * gp->bump_data[i].ax); - - gp->bump_data[i].cx = 2.0 * (((double)random() / (double)RAND_MAX) - 0.5); - gp->bump_data[i].cy = 2.0 * (((double)random() / (double)RAND_MAX) - 0.5); - gp->bump_data[i].cpower = (5.0 / pow(bumps, 0.75)) * (((double)random() / (double)RAND_MAX) - 0.5); - gp->bump_data[i].csize = 0.35; /*0.1 + 0.25 * (((double)random() / (double)RAND_MAX));*/ - - gp->bump_data[i].vx = 0.0; - gp->bump_data[i].vy = 0.0; - gp->bump_data[i].vpower = 0.0; - gp->bump_data[i].vsize = 0.0; - - gp->bump_data[i].mx = 0.003 * ((double)random() / (double)RAND_MAX); - gp->bump_data[i].my = 0.003 * ((double)random() / (double)RAND_MAX); - gp->bump_data[i].mpower = 0.003 * ((double)random() / (double)RAND_MAX); - gp->bump_data[i].msize = 0.003 * ((double)random() / (double)RAND_MAX); - } - - /* Initialise lookup table of bump strength */ - for (i = 0; i < bump_array_size; i++) - { - double xd, xd2; - xd = i / (double)bump_array_size; - - xd2 = 48.0 * xd * xd; - gp->bump_shape[i] = 0.1 / (xd2 + 0.1); - - xd2 = 40.0 * xd * xd * xd * xd; - gp->wall_shape[i] = 0.4 / (xd2 + 0.1); - } - - node = 0; - face = 0; - for (side = 0; side < 4; side++) - { - base = node; - if (side == 2) - { - base2 = node; - } - /* - * The start and end of the for loops below are modified based on the - * side of the tetrahedron that is being calculated to avoid duplication - * of the gp->nodes that are on the edges of the tetrahedron. - */ - for (u = (side > 1); u < (nodes_on_edge - (side > 0)); u++) - { - node1 = partial (normalise (tetrahedron[side][0]), - normalise (tetrahedron[side][1]), - u / (double) (nodes_on_edge - 1)); - node2 = partial (normalise (tetrahedron[side][0]), - normalise (tetrahedron[side][2]), - u / (double) (nodes_on_edge - 1)); - - for (v = (side > 1); v <= (u - (side > 2)); v++) - { - if (u > 0) - result = partial (node1, node2, v / (double) u); - else - result = node1; - - gp->nodes[node].position = normalise (result); - gp->nodes[node].initial_position = gp->nodes[node].position; - gp->nodes[node].normal = zero_vector; - node++; - } - } - - /* - * Determine which nodes make up each face. The complexity is caused - * by having to determine the correct nodes for the edges of the - * tetrahedron since the common nodes on the edges are only calculated - * once (see above). - */ - for (u = 0; u < (nodes_on_edge - 1); u++) - { - for (v = 0; v <= u; v++) - { - { - if (side < 2) - { - gp->faces[face].node1 = base + ((u * (u + 1)) / 2) + v; - gp->faces[face].node2 = - base + ((u + 1) * (u + 2)) / 2 + v + 1; - gp->faces[face].node3 = - base + ((u + 1) * (u + 2)) / 2 + v; - - if ((side == 1) && (u == (nodes_on_edge - 2))) - { - gp->faces[face].node3 = - ((u + 1) * (u + 2)) / 2 + - nodes_on_edge - v - 1; - gp->faces[face].node2 = - ((u + 1) * (u + 2)) / 2 + - nodes_on_edge - v - 2; - } - } - else if (side < 3) - { - gp->faces[face].node1 = - base + (((u - 1) * u) / 2) + v - 1; - gp->faces[face].node2 = base + ((u) * (u + 1)) / 2 + v; - gp->faces[face].node3 = - base + ((u) * (u + 1)) / 2 + v - 1; - - if (u == (nodes_on_edge - 2)) - { - int n = nodes_on_edge - v - 1; - gp->faces[face].node2 = - ((nodes_on_edge * - (nodes_on_edge + 1)) / 2) + - ((n - 1) * (n + 0)) / 2; - gp->faces[face].node3 = - ((nodes_on_edge * - (nodes_on_edge + 1)) / 2) + - ((n + 0) * (n + 1)) / 2; - } - if (v == 0) - { - gp->faces[face].node1 = (((u + 1) * (u + 2)) / 2) - 1; - gp->faces[face].node3 = (((u + 2) * (u + 3)) / 2) - 1; - } - } - else - { - gp->faces[face].node1 = - base + (((u - 2) * (u - 1)) / 2) + v - 1; - gp->faces[face].node2 = base + ((u - 1) * u) / 2 + v; - gp->faces[face].node3 = base + ((u - 1) * u) / 2 + v - 1; - - if (v == 0) - { - gp->faces[face].node1 = - base2 + ((u * (u + 1)) / 2) - 1; - gp->faces[face].node3 = - base2 + ((u + 1) * (u + 2)) / 2 - 1; - } - if (u == (nodes_on_edge - 2)) - { - gp->faces[face].node3 = - ((nodes_on_edge * - (nodes_on_edge + 1)) / 2) + - ((v + 1) * (v + 2)) / 2 - 1; - gp->faces[face].node2 = - ((nodes_on_edge * - (nodes_on_edge + 1)) / 2) + - ((v + 2) * (v + 3)) / 2 - 1; - } - if (v == u) - { - gp->faces[face].node1 = (u * (u + 1)) / 2; - gp->faces[face].node2 = ((u + 1) * (u + 2)) / 2; - } - } - face++; - } - - if (v < u) - { - if (side < 2) - { - gp->faces[face].node1 = base + ((u * (u + 1)) / 2) + v; - gp->faces[face].node2 = - base + ((u * (u + 1)) / 2) + v + 1; - gp->faces[face].node3 = - base + (((u + 1) * (u + 2)) / 2) + v + 1; - - if ((side == 1) && (u == (nodes_on_edge - 2))) - { - gp->faces[face].node3 = - ((u + 1) * (u + 2)) / 2 + - nodes_on_edge - v - 2; - } - } - else if (side < 3) - { - gp->faces[face].node1 = - base + ((u * (u - 1)) / 2) + v - 1; - gp->faces[face].node2 = base + ((u * (u - 1)) / 2) + v; - gp->faces[face].node3 = base + ((u * (u + 1)) / 2) + v; - - if (u == (nodes_on_edge - 2)) - { - int n = nodes_on_edge - v - 1; - gp->faces[face].node3 = - ((nodes_on_edge * - (nodes_on_edge + 1)) / 2) + - ((n + 0) * (n - 1)) / 2; - } - if (v == 0) - { - gp->faces[face].node1 = (((u + 1) * (u + 2)) / 2) - 1; - } - } - else - { - gp->faces[face].node1 = - base + (((u - 2) * (u - 1)) / 2) + v - 1; - gp->faces[face].node2 = - base + (((u - 2) * (u - 1)) / 2) + v; - gp->faces[face].node3 = base + (((u - 1) * u) / 2) + v; - - if (v == 0) - { - gp->faces[face].node1 = base2 + (u * (u + 1)) / 2 - 1; - } - if (u == (nodes_on_edge - 2)) - { - gp->faces[face].node3 = - ((nodes_on_edge * (nodes_on_edge + 1)) / 2) + - ((v + 2) * (v + 3)) / 2 - 1; - } - if (v == (u - 1)) - { - gp->faces[face].node2 = (u * (u + 1)) / 2; - } - } - face++; - } - } - } - } - - return 0; -} - -/****************************************************************************** - * - * Return the magnitude of the given vector - */ -#if 0 -static inline double -length (Vector3D u) -{ - return sqrt (u.x * u.x + u.y * u.y + u.z * u.z); -} -#endif - -/****************************************************************************** - * - * Calculate the blob shape. - */ -static void -calc_blob(mirrorblobstruct *gp, - int width, - int height, - int bump_array_size, - float limit, - double fade) -{ - /* Loop variables */ - int i, index, face; - /* position of a node */ - Vector3D node; - Vector3D offset; - Vector3D bump_vector; - int dist; - - /* Update position and strength of bumps used to distort the blob */ - for (i = 0; i < bumps; i++) - { - gp->bump_data[i].vx += gp->bump_data[i].mx*(gp->bump_data[i].cx - gp->bump_data[i].ax); - gp->bump_data[i].vy += gp->bump_data[i].my*(gp->bump_data[i].cy - gp->bump_data[i].ay); - gp->bump_data[i].vpower += gp->bump_data[i].mpower - * (gp->bump_data[i].cpower - gp->bump_data[i].power); - gp->bump_data[i].vsize += gp->bump_data[i].msize - * (gp->bump_data[i].csize - gp->bump_data[i].size); - - gp->bump_data[i].ax += 0.1 * gp->bump_data[i].vx; - gp->bump_data[i].ay += 0.1 * gp->bump_data[i].vy; - gp->bump_data[i].power += 0.1 * gp->bump_data[i].vpower; - gp->bump_data[i].size += 0.1 * gp->bump_data[i].vsize; - - gp->bump_data[i].pos.x = 1.0 * sin(PI * gp->bump_data[i].ay) - * cos(PI * gp->bump_data[i].ax); - gp->bump_data[i].pos.y = 1.0 * cos(PI * gp->bump_data[i].ay); - gp->bump_data[i].pos.z = 1.0 * sin(PI * gp->bump_data[i].ay) - * sin(PI * gp->bump_data[i].ax); - } - - /* Update calculate new position for each vertex based on an offset from - * the initial position - */ - gp->blob_force = zero_vector; - for (index = 0; index < gp->num_nodes; ++index) - { - node = gp->nodes[index].initial_position; - gp->nodes[index].normal = node; - - offset = zero_vector; - for ( i = 0; i < bumps; i++) - { - bump_vector = subtract(gp->bump_data[i].pos, node); - - dist = bump_array_size * dot(bump_vector, bump_vector) * gp->bump_data[i].size; - - if (dist < bump_array_size) - { - add(&offset, scale(node, gp->bump_data[i].power * gp->bump_shape[dist])); - add(&gp->blob_force, scale(node, gp->bump_data[i].power * gp->bump_shape[dist])); - } - } - - add(&node, offset); - node = scale(node, zoom); - add(&node, gp->blob_center); - - if (do_walls) - { - if (node.z < -limit) node.z = -limit; - if (node.z > limit) node.z = limit; - - dist = bump_array_size * (node.z + limit) * (node.z + limit) * 0.5; - if (dist < bump_array_size) - { - node.x += (node.x - gp->blob_center.x) * gp->wall_shape[dist]; - node.y += (node.y - gp->blob_center.y) * gp->wall_shape[dist]; - gp->blob_force.z += (node.z + limit); - } - else - { - dist = bump_array_size * (node.z - limit) * (node.z - limit) * 0.5; - if (dist < bump_array_size) - { - node.x += (node.x - gp->blob_center.x) * gp->wall_shape[dist]; - node.y += (node.y - gp->blob_center.y) * gp->wall_shape[dist]; - gp->blob_force.z -= (node.z - limit); - } - - if (node.y < -limit) node.y = -limit; - if (node.y > limit) node.y = limit; - - dist = bump_array_size * (node.y + limit) * (node.y + limit) * 0.5; - if (dist < bump_array_size) - { - node.x += (node.x - gp->blob_center.x) * gp->wall_shape[dist]; - node.z += (node.z - gp->blob_center.z) * gp->wall_shape[dist]; - gp->blob_force.y += (node.y + limit); - } - else - { - dist = bump_array_size * (node.y - limit) * (node.y - limit) * 0.5; - if (dist < bump_array_size) - { - node.x += (node.x - gp->blob_center.x) * gp->wall_shape[dist]; - node.z += (node.z - gp->blob_center.z) * gp->wall_shape[dist]; - gp->blob_force.y -= (node.y - limit); - } - } - - if (node.x < -limit) node.x = -limit; - if (node.x > limit) node.x = limit; - - dist = bump_array_size * (node.x + limit) * (node.x + limit) * 0.5; - if (dist < bump_array_size) - { - node.y += (node.y - gp->blob_center.y) * gp->wall_shape[dist]; - node.z += (node.z - gp->blob_center.z) * gp->wall_shape[dist]; - gp->blob_force.x += (node.x + limit); - } - else - { - dist = bump_array_size * (node.x - limit) * (node.x - limit) * 0.5; - if (dist < bump_array_size) - { - node.y += (node.y - gp->blob_center.y) * gp->wall_shape[dist]; - node.z += (node.z - gp->blob_center.z) * gp->wall_shape[dist]; - gp->blob_force.x -= (node.x - limit); - } - } - - if (node.y < -limit) node.y = -limit; - if (node.y > limit) node.y = limit; - } - } - gp->dots[index] = node; - } - - /* Determine the normal for each face */ - for (face = 0; face < gp->num_faces; face++) - { - /* Use pointers to indexed nodes to help readability */ - int index1 = gp->faces[face].node1; - int index2 = gp->faces[face].node2; - int index3 = gp->faces[face].node3; - - gp->faces[face].normal = cross(subtract(gp->dots[index2], gp->dots[index1]), - subtract(gp->dots[index3], gp->dots[index1])); - - /* Add the normal for the face onto the normal for the verticies of - the face */ - add(&gp->nodes[index1].normal, gp->faces[face].normal); - add(&gp->nodes[index2].normal, gp->faces[face].normal); - add(&gp->nodes[index3].normal, gp->faces[face].normal); - } - - /* Use the normal to set the colour and texture */ - if (do_colour || do_texture) - { - for (index = 0; index < gp->num_nodes; ++index) - { - gp->normals[index] = normalise(gp->nodes[index].normal); - - if (do_colour) - { - gp->colours[index].red = (int)(255.0 * fabs(gp->normals[index].x)); - gp->colours[index].green = (int)(255.0 * fabs(gp->normals[index].y)); - gp->colours[index].blue = (int)(255.0 * fabs(gp->normals[index].z)); - gp->colours[index].alpha = (int)(255.0 * fade); - } - if (do_texture) - { - if (offset_texture) - { - const float cube_size = 100.0; - Vector3D eye = {0.0, 0.0, 50.0}; - Vector3D eye_r = normalise(subtract(gp->dots[index], eye)); - Vector3D reference = subtract(eye_r, scale(gp->normals[index], 2.0 * dot(eye_r, gp->normals[index]))); - double x = 0.0; - double y = 0.0; - double n, n_min = 10000.0, sign = 1.0; - if (fabs(reference.z) > 1e-9) - { - n = (cube_size - gp->dots[index].z) / reference.z; - if (n < 0.0) - { - n = (-cube_size - gp->dots[index].z) / reference.z; - sign = 3.0; - } - if (n > 0.0) - { - x = sign * (gp->dots[index].x + n * reference.x); - y = sign * (gp->dots[index].y + n * reference.y); - n_min = n; - } - } - if (fabs(reference.x) > 1e-9) - { - n = (cube_size - gp->dots[index].x) / reference.x; - sign = 1.0; - if (n < 0.0) - { - n = (-cube_size - gp->dots[index].x) / reference.x; - sign = -1.0; - } - if ((n > 0.0) && (n < n_min)) - { - x = sign * (2.0 * cube_size - (gp->dots[index].z + n * reference.z)); - y = sign * x * (gp->dots[index].y + n * reference.y) / cube_size; - n_min = n; - } - } - if (fabs(reference.y) > 1e-9) - { - n = (cube_size - gp->dots[index].y) / reference.y; - sign = 1.0; - if (n < 0.0) - { - n = (-cube_size - gp->dots[index].y) / reference.y; - sign = -1.0; - } - if ((n > 0.0) && (n < n_min)) - { - y = sign * (2.0 * cube_size -( gp->dots[index].z + n * reference.z)); - x = sign * y * (gp->dots[index].x + n * reference.x) / cube_size; - } - } - - gp->tex_coords[index].x = 0.5 + x / (cube_size * 6.0); - gp->tex_coords[index].y = 0.5 - y / (cube_size * 6.0); - } - else - { - gp->tex_coords[index].x = 0.5 - * (1.0 + asin(gp->normals[index].x) / (0.5 * PI)); - gp->tex_coords[index].y = -0.5 - * (1.0 + asin(gp->normals[index].y) / (0.5 * PI)); - } - /* Adjust the texture co-ordinates to from range 0..1 to - * 0..width or 0..height as appropriate - */ - gp->tex_coords[index].x *= gp->tex_width[gp->current_texture]; - gp->tex_coords[index].y *= gp->tex_height[gp->current_texture]; - } - } - } - - /* Update the center of the whole blob */ - add(&gp->blob_velocity, scale (subtract (gp->blob_anchor, gp->blob_center), 1.0 / 80.0)); - add(&gp->blob_velocity, scale (gp->blob_force, 0.01 / gp->num_nodes)); - - add(&gp->blob_center, scale(gp->blob_velocity, 0.5)); - - gp->blob_velocity = scale(gp->blob_velocity, 0.999); -} - -static void -draw_vertex(mirrorblobstruct *gp, int index) -{ - if (do_colour) - { - glColor3ub(gp->colours[index].red, - gp->colours[index].green, - gp->colours[index].blue); - } - if (load_textures) - { - glTexCoord2fv(&gp->tex_coords[index].x); - } - glNormal3fv(&gp->normals[index].x); - glVertex3fv(&gp->dots[index].x); -} - -/****************************************************************************** - * - * Draw the blob shape. - * - */ -static void -draw_blob (mirrorblobstruct *gp) -{ - int face; - - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); -/* glRotatef(current_device_rotation(), 0, 0, 1); */ - - /* Move down the z-axis. */ - glTranslatef (0.0, 0.0, -4.0); - - gltrackball_rotate (gp->trackball); - - /* glColor4ub (255, 0, 0, 128); */ - glBegin(GL_TRIANGLES); - for (face = 0; face < gp->num_faces; face++) - { - draw_vertex(gp, gp->faces[face].node1); - draw_vertex(gp, gp->faces[face].node2); - draw_vertex(gp, gp->faces[face].node3); - } - glEnd(); - -#if 0 - glBegin(GL_LINES); - for (face = 0; face < gp->num_faces; face++) - { - if (gp->normals[gp->faces[face].node1].z > 0.0) - { - Vector3D end = gp->dots[gp->faces[face].node1]; - glVertex3dv(&end); - add(&end, scale(gp->normals[gp->faces[face].node1], 0.25)); - glVertex3dv(&end); - } - } - glEnd(); -#endif - - glLoadIdentity(); -} - -/****************************************************************************** - * - * Draw the background image simply map a texture onto a full screen quad. - */ -static void -draw_background (ModeInfo *mi) -{ - mirrorblobstruct *gp = &Mirrorblob[MI_SCREEN(mi)]; - GLfloat rot = current_device_rotation(); - - glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL); - glEnable (GL_TEXTURE_2D); - glDisable(GL_LIGHTING); - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - - /* Reset the projection matrix to make it easier to get the size of the quad - * correct - */ - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glLoadIdentity(); - - glRotatef (-rot, 0, 0, 1); -/* - if ((rot > 45 && rot < 135) || - (rot < -45 && rot > -135)) - { - GLfloat s = MI_WIDTH(mi) / (GLfloat) MI_HEIGHT(mi); - glScalef (s, 1/s, 1); - } -*/ - - glOrtho(0.0, MI_WIDTH(mi), MI_HEIGHT(mi), 0.0, -1000.0, 1000.0); - - glBegin (GL_QUADS); - - glTexCoord2f (0.0, 0.0); - glVertex2i (0, 0); - - glTexCoord2f (0.0, gp->tex_height[gp->current_texture]); - glVertex2i (0, MI_HEIGHT(mi)); - - glTexCoord2f (gp->tex_width[gp->current_texture], gp->tex_height[gp->current_texture]); - glVertex2i (MI_WIDTH(mi), MI_HEIGHT(mi)); - - glTexCoord2f (gp->tex_width[gp->current_texture], 0.0); - glVertex2i (MI_WIDTH(mi), 0); - glEnd(); - - glPopMatrix (); - glMatrixMode (GL_MODELVIEW); - glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); -} - -/****************************************************************************** - * - * Update the scene. - */ -static GLvoid -draw_scene(ModeInfo * mi) -{ - mirrorblobstruct *gp = &Mirrorblob[MI_SCREEN(mi)]; - - double fade = 0.0; - double current_time; - check_gl_error ("draw_scene"); - - mi->polygon_count = 0; - glColor4f (1.0, 1.0, 1.0, 1.0); - - current_time = double_time(); - switch (gp->state) - { - case INITIALISING: - glColor4f (0.0, 0.0, 0.0, 1.0); - fade = 1.0; - break; - - case TRANSITIONING: - fade = 1.0 - (current_time - gp->state_start_time) / fade_time; - break; - - case LOADING: /* FALL-THROUGH */ - case HOLDING: - fade = 1.0; - break; - } - - /* Set the correct texture, when transitioning this ensures that the first draw - * is the original texture (which has the new texture drawn over it with decreasing - * transparency) - */ - if (load_textures) - { - glBindTexture(GL_TEXTURE_2D, gp->textures[gp->current_texture]); - } - - glDisable (GL_DEPTH_TEST); - if (do_paint_background) - { - glEnable (GL_TEXTURE_2D); - if (motion_blur > 0.0) - { - glClear(GL_DEPTH_BUFFER_BIT); - glEnable (GL_BLEND); - glColor4f (1.0, 1.0, 1.0, motion_blur); - } - else - { - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - } - draw_background (mi); - mi->polygon_count++; - - /* When transitioning between two images paint the new image over the old - * image with a varying alpha value to get a smooth fade. - */ - if (gp->state == TRANSITIONING) - { - glEnable (GL_BLEND); - /* Select the texture to transition to */ - glBindTexture (GL_TEXTURE_2D, gp->textures[1 - gp->current_texture]); - glColor4f (1.0, 1.0, 1.0, 1.0 - fade); - - draw_background (mi); - mi->polygon_count++; - - /* Select the original texture to draw the blob */ - glBindTexture (GL_TEXTURE_2D, gp->textures[gp->current_texture]); - } - /* Clear the depth buffer bit so the backgound is behind the blob */ - glClear(GL_DEPTH_BUFFER_BIT); - } - else if (motion_blur > 0.0) - { - glEnable (GL_BLEND); - glColor4f (0.0, 0.0, 0.0, motion_blur); - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - glTranslatef (0.0, 0.0, -4.0); - glRectd (-10.0, -10.0, 10.0, 10.0); - if (wireframe) - { - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - } - glClear(GL_DEPTH_BUFFER_BIT); - } - else - { - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - } - - if (!do_texture) - { - fade = 1.0; - glDisable (GL_TEXTURE_2D); - } - - calc_blob(gp, MI_WIDTH(mi), MI_HEIGHT(mi), BUMP_ARRAY_SIZE, 2.5, fade * blend); - - set_blob_gl_state(fade * blend); - - if (blend < 1.0) - { - /* Disable the colour chanels so that only the depth buffer is updated */ - glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); - draw_blob(gp); - mi->polygon_count += gp->num_faces; - glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); - } - - glDepthFunc(GL_LEQUAL); - draw_blob(gp); - mi->polygon_count += gp->num_faces; - - /* While transitioning between images draw a second blob with a modified - * alpha value. - */ - if (load_textures && (hold_time > 0)) - { - switch (gp->state) - { - case INITIALISING: - if (!gp->waiting_for_image_p) - { - gp->state = HOLDING; - } - break; - - case HOLDING: - if ((current_time - gp->state_start_time) > hold_time) - { - grab_texture(mi, 1 - gp->current_texture); - gp->state = LOADING; - } - break; - - case LOADING: - /* Once the image has loaded move to the TRANSITIONING STATE */ - if (!gp->waiting_for_image_p) - { - gp->state = TRANSITIONING; - /* Get the time again rather than using the current time so - * that the time taken by the grab_texture function is not part - * of the fade time - */ - gp->state_start_time = double_time(); - } - break; - - case TRANSITIONING: - - /* If the blob is textured draw over existing blob to fade between - * images - */ - if (do_texture) - { - /* Select the texture to transition to */ - glBindTexture (GL_TEXTURE_2D, gp->textures[1 - gp->current_texture]); - glEnable (GL_BLEND); - - /* If colour is enabled update the alpha data in the buffer and - * use that in the blending since the alpha of the incomming - * verticies will not be correct - */ - if (do_colour) - { - glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE); - glClearColor(0.0, 0.0, 0.0, (1.0 - fade) * blend); - glClear(GL_COLOR_BUFFER_BIT); - glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); - glBlendFunc(GL_DST_ALPHA, GL_ONE_MINUS_DST_ALPHA); - } - else - { - glColor4f (0.9, 0.9, 1.0, (1.0 - fade) * blend); - } - - draw_blob (gp); - mi->polygon_count += gp->num_faces; - - if (do_colour) - { - /* Restore the 'standard' blend functions. */ - glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - } - } - - if ((current_time - gp->state_start_time) > fade_time) - { - gp->state = HOLDING; - gp->state_start_time = current_time; - gp->current_texture = 1 - gp->current_texture; - } - break; - - } - } -} - -/****************************************************************************** - * - * XMirrorblob screen update entry - */ -ENTRYPOINT void -draw_mirrorblob(ModeInfo * mi) -{ - mirrorblobstruct *gp = &Mirrorblob[MI_SCREEN(mi)]; - Display *display = MI_DISPLAY(mi); - Window window = MI_WINDOW(mi); - - if (!gp->glx_context) - return; - - /* Wait for the first image; for subsequent images, load them in the - background while animating. */ - if (gp->waiting_for_image_p && gp->first_image_p) - return; - - glXMakeCurrent(display, window, *gp->glx_context); - draw_scene(mi); - if (mi->fps_p) do_fps (mi); - glFinish(); - glXSwapBuffers(display, window); -} - -/****************************************************************************** - * - * XMirrorblob screen resize entry - */ -ENTRYPOINT void -reshape_mirrorblob(ModeInfo *mi, int width, int height) -{ - glViewport( 0, 0, MI_WIDTH(mi), MI_HEIGHT(mi) ); - reset_projection(width, height); -} - -/**************************************************************************** - * - * Handle Mouse events - */ -ENTRYPOINT Bool -mirrorblob_handle_event (ModeInfo * mi, XEvent * event) -{ - mirrorblobstruct *gp = &Mirrorblob[MI_SCREEN (mi)]; - - if (event->xany.type == ButtonPress && - event->xbutton.button == Button4) - { - zoom *= 1.1; - return True; - } - else if (event->xany.type == ButtonPress && - event->xbutton.button == Button5) - { - - zoom *= 0.9; - return True; - } - else if (gltrackball_event_handler (event, gp->trackball, - MI_WIDTH (mi), MI_HEIGHT (mi), - &gp->button_down)) - { - return True; - } - else if (screenhack_event_helper (MI_DISPLAY(mi), MI_WINDOW(mi), event)) - { - gp->state_start_time = 0; - gp->state = HOLDING; - return True; - } - - return False; -} - -/****************************************************************************** - * - * XMirrorblob initialise entry - */ -ENTRYPOINT void -init_mirrorblob(ModeInfo * mi) -{ - int screen = MI_SCREEN(mi); - - mirrorblobstruct *gp; - - MI_INIT(mi, Mirrorblob); - gp = &Mirrorblob[screen]; - - gp->window = MI_WINDOW(mi); - if ((gp->glx_context = init_GL(mi)) != NULL) - { - reshape_mirrorblob(mi, MI_WIDTH(mi), MI_HEIGHT(mi)); - initialize_gl(mi, MI_WIDTH(mi), MI_HEIGHT(mi)); - } - else - { - MI_CLEARWINDOW(mi); - } - gp->trackball = gltrackball_init(False); - - initialise_blob(gp, MI_WIDTH(mi), MI_HEIGHT(mi), BUMP_ARRAY_SIZE); - gp->state = INITIALISING; - gp->state_start_time = double_time(); - - gp->first_image_p = True; -} - -/****************************************************************************** - * - * XMirrorblob cleanup entry - */ -ENTRYPOINT void -free_mirrorblob(ModeInfo * mi) -{ - mirrorblobstruct *gp = &Mirrorblob[MI_SCREEN(mi)]; - int i; - - if (!gp->glx_context) return; - glXMakeCurrent (MI_DISPLAY(mi), MI_WINDOW(mi), *gp->glx_context); - - if (gp->nodes) free(gp->nodes); - if (gp->faces) free(gp->faces); - if (gp->bump_data) free(gp->bump_data); - if (gp->colours) free(gp->colours); - if (gp->tex_coords) free(gp->tex_coords); - if (gp->dots) free(gp->dots); - if (gp->normals) free(gp->normals); - if (gp->wall_shape) free(gp->wall_shape); - if (gp->bump_shape) free(gp->bump_shape); - if (gp->trackball) gltrackball_free (gp->trackball); - - for (i = 0; i < NUM_TEXTURES; i++) - if (gp->textures[i]) glDeleteTextures(1, &gp->textures[i]); -} - -XSCREENSAVER_MODULE ("MirrorBlob", mirrorblob) - -#endif |
