diff options
author | Simon Rettberg | 2018-10-16 10:08:48 +0200 |
---|---|---|
committer | Simon Rettberg | 2018-10-16 10:08:48 +0200 |
commit | d3a98cf6cbc3bd0b9efc570f58e8812c03931c18 (patch) | |
tree | cbddf8e50f35a9c6e878a5bfe3c6d625d99e12ba /hacks/glx/gleidescope.c | |
download | xscreensaver-d3a98cf6cbc3bd0b9efc570f58e8812c03931c18.tar.gz xscreensaver-d3a98cf6cbc3bd0b9efc570f58e8812c03931c18.tar.xz xscreensaver-d3a98cf6cbc3bd0b9efc570f58e8812c03931c18.zip |
Original 5.40
Diffstat (limited to 'hacks/glx/gleidescope.c')
-rw-r--r-- | hacks/glx/gleidescope.c | 1624 |
1 files changed, 1624 insertions, 0 deletions
diff --git a/hacks/glx/gleidescope.c b/hacks/glx/gleidescope.c new file mode 100644 index 0000000..ec33388 --- /dev/null +++ b/hacks/glx/gleidescope.c @@ -0,0 +1,1624 @@ +/* -*- Mode: C; tab-width: 4 -*- */ +/* vim: set ai ts=4 sw=4: */ + +#if 0 +/*static const char sccsid[] = "@(#)gleidescope.c 1.0 03/06/27 xlockmore";*/ +#endif + +/* enable -grab switch for animations */ +#undef GRAB + +#undef DISPLAY_TEXTURE + +/*- + * 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: + * + * 20030627 1.0 acd First Release. + * Texture loading code from 'glplanet' + * by Jamie Zawinski <jwz@jwz.org> + * 20030810 1.1 acd Added size flag. + * Now grabs screen / video / picture + * (uses code from 'glslideshow' by + * Mike Oliphant, Ben Buxton, Jamie Zawinski). + * Added -duration. + * Added mouse code. + * Added fade code (also from glslideshow). + * 20031013 1.2 acd Migrated to compile without warnings under + * xscreensaver 4.13. + * 20031023 1.3 acd Better code to limit twisting speeds. + * Tweaked initial rotation values. + * Move, Rotate, Zoom now chosen at random if + * no preference is given. + * Made grid slightly bigger so you can't see + * the edge when zooming and moving. + * 20061226 1.4 acd Now uses GL Display Lists. + * 20070318 1.5 acd Generates textures. + * Fixed texture size problem (and introduced another). + * 20070412 1.6 acd Textures now have independant sizes. + * 20070413 1.7 acd Added Lissajous movement pattern. + * 20070414 1.8 acd Added corners movement pattern. + * 20080319 1.9 acd Changes to arguments for saner gleidescope.xml. + * + * TODO + * generate textures myself - render random shapes to 256x256 texture. (done) + * lower res for checks and random - use 256 and 4x4 or 8x8 pixels. (disabled for now) + * gnome-saver doesn't let you specify source directory so add that to this. + * image loading routine is too slow - rotation grinds to a halt - stop using it. (better in version 5) + * image loading also looks bad for non-square images - edges are black. (fixed) + * possible to see edge of the world on widescreen terminals - use larger grid and hidden hex removal? + * fading textures may have different max_tx - use two sets. (done) + * choice of movement patterns. (3 implemented, chooseable at compile time) + * look into rangle and tangle. + */ + +/* +**---------------------------------------------------------------------------- +** Defines +**---------------------------------------------------------------------------- +*/ + +#ifdef STANDALONE +# define DEFAULTS \ + "*delay: 20000 \n" \ + "*showFPS: False \n" \ + "*size: 0 \n" \ + "*useSHM: True \n" \ + "*suppressRotationAnimation: True\n" \ + +# define release_gleidescope 0 +# include "xlockmore.h" /* from the xscreensaver distribution */ +#else /* !STANDALONE */ +# include "xlock.h" /* from the xlockmore distribution */ +#endif /* !STANDALONE */ + +#ifdef USE_GL + +#include "colors.h" +#include "ximage-loader.h" +#include "grab-ximage.h" + +#ifdef GRAB +void grab_frame(Display *display, Window window); +#endif + +/* acd TODO should all these be in gleidestruct? */ +/* they can't be, because of the idiotic way the xlockmore "argtype vars" + interface works. -jwz */ +#ifdef GRAB +static Bool grab; /* grab images */ +#endif +static Bool move; /* moving camera */ +static Bool nomove; /* no moving camera */ +static Bool rotate; /* rotate in place */ +static Bool norotate; /* no rotate in place */ +static Bool zoom; /* zooming camera */ +static Bool nozoom; /* no zooming camera */ +static char *image_str; /* name of texture to load */ +static int duration; /* length of time to display grabbed image */ + +#define MAX_CAM_SPEED 1.0 +#define MAX_ANGLE_VEL 1.0 +#define INITIAL_ANGLE_VEL 0.2 +#define INITIAL_ANGLE_ACC 0.001 +#define TWISTING_PROBABILITY 1000 /* 1 in ... of change of acceleration */ + +#define RADIANS (M_PI / 180) +#define ANGLE_120 (M_PI * 2 / 3) +#define ANGLE_240 (M_PI * 4 / 3) + +#define DEF_GRAB "False" +#define DEF_MOVE "False" +#define DEF_NOMOVE "False" +#define DEF_ROTATE "False" +#define DEF_NOROTATE "False" +#define DEF_ZOOM "False" +#define DEF_NOZOOM "False" +#define DEF_IMAGE "DEFAULT" +#define DEF_DURATION "30" + + +static XrmOptionDescRec opts[] = +{ +#ifdef GRAB + {"-grab", ".gleidescope.grab", XrmoptionNoArg, "true"}, +#endif + {"-move", ".gleidescope.move", XrmoptionNoArg, "true"}, + {"-no-move", ".gleidescope.nomove", XrmoptionNoArg, "true"}, + {"-rotate", ".gleidescope.rotate", XrmoptionNoArg, "true"}, + {"-no-rotate", ".gleidescope.norotate", XrmoptionNoArg, "true"}, + {"-zoom", ".gleidescope.zoom", XrmoptionNoArg, "true"}, + {"-no-zoom", ".gleidescope.nozoom", XrmoptionNoArg, "true"}, + {"-image", ".gleidescope.image", XrmoptionSepArg, "DEFAULT"}, + {"-duration", ".gleidescope.duration", XrmoptionSepArg, "30"}, +}; + + +static argtype vars[] = { +#ifdef GRAB + {&grab, "grab", "Grab", DEF_GRAB, t_Bool}, +#endif + {&move, "move", "Move", DEF_MOVE, t_Bool}, + {&nomove, "nomove", "noMove", DEF_NOMOVE, t_Bool}, + {&rotate, "rotate", "Rotate", DEF_ROTATE, t_Bool}, + {&norotate, "norotate", "noRotate", DEF_NOROTATE, t_Bool}, + {&zoom, "zoom", "Zoom", DEF_ZOOM, t_Bool}, + {&nozoom, "nozoom", "noZoom", DEF_NOZOOM, t_Bool}, + {&image_str, "image", "Image", DEF_IMAGE, t_String}, + {&duration, "duration", "Duration", DEF_DURATION, t_Int}, +}; + +static OptionStruct desc[] = { +#ifdef GRAB + {"-grab", "grab images to create animation"}, +#endif + {"-move", "camera will move"}, + {"-no-move", "camera won't move"}, + {"-rotate", "camera will rotate"}, + {"-no-rotate", "camera won't rotate"}, + {"-zoom", "camera will zoom"}, + {"-no-zoom", "camera won't zoom"}, + {"-image", "xpm / xbm image file to use for texture"}, + {"-duration", "length of time texture will be used"}, +}; + +ENTRYPOINT ModeSpecOpt gleidescope_opts = { + sizeof opts / sizeof opts[0], opts, + sizeof vars / sizeof vars[0], vars, + desc +}; + +#ifdef USE_MODULES +ModStruct gleidescope_description = { + "gleidescope", "init_gleidescope", "draw_gleidescope", NULL, + "draw_gleidescope", "init_gleidescope", "free_gleidescope", + &gleidescope_opts, 1000, 1, 2, 1, 4, 1.0, "", + "GL Kaleidescope", 0, NULL}; +#endif + +/* +**----------------------------------------------------------------------------- +** Typedefs +**----------------------------------------------------------------------------- +*/ + +typedef struct hex_s { + GLfloat x, y, z; /* position */ +} hex_t; + +typedef struct { + GLfloat x; + GLfloat y; + GLfloat z; +} vectorf; + +typedef struct { + GLfloat x; + GLfloat y; +} vector2f; + +typedef struct { + GLuint id; /* opengl texture id */ + GLfloat width, height; /* texture width and height */ + GLfloat min_tx, min_ty; /* minimum texture sizes */ + GLfloat max_tx, max_ty; /* maximum texture sizes */ + time_t start_time; + Bool button_down_p; + Bool mipmap_p; + Bool waiting_for_image_p; + /* r_phase is for triangle rotation speed */ + GLfloat x_period, y_period, r_period; + GLfloat x_phase, y_phase, r_phase; +} texture; + +#define MAX_FADE 500 /* number of fade cycles */ + +typedef struct { + float cam_x_speed, cam_z_speed, cam_y_speed; + int cam_x_phase, cam_z_phase, cam_y_phase; + float tic; + GLXContext *glx_context; + Window window; + texture textures[2]; /* texture handles */ + GLuint visible; /* index for current texture */ + GLint fade; + time_t start_time; + Bool button_down_p; + + int size; + int list; + + float tangle; /* texture angle (degrees) */ + float tangle_vel; /* texture velocity */ + float tangle_acc; /* texture acceleration */ + + float rangle; /* rotate angle */ + float rangle_vel; /* rotate velocity */ + float rangle_acc; /* rotate acceleration */ + + /* mouse */ + int xstart; + int ystart; + double xmouse; + double ymouse; + + Bool mipmap_p; + Bool waiting_for_image_p; + +} gleidestruct; + +#define frandrange(x, y) (x + frand(y - x)) + +#define XOFFSET (0.8660254f) /* sin 60' */ +#define YOFFSET (1.5000000f) /* cos 60' + 1 */ + +#if 0 + +#define SIZE 3 + +/* generates a grid with edges of given size */ +/* acd TODO - replace hex[] with this and allow size and distance as parameters */ + +int +generate_grid(int size) + + int i, x, y; + + gp->size--; + + i = gp->size; + for (y = -size ; y <= size ; y++) { + for (x = -i ; x <= i ; x += 2) { + printf("{XOFFSET * %d, YOFFSET * %d, 0},\n", x, y); + } + printf("\n"); + if (y < 0) { + i++; + } else { + i--; + } + } + return 0; +} +#endif + +/* acd - this is terrible - 120+ hexes */ +static const hex_t hex[] = { + /* edges of size 7 */ + /* number of hexagons required to cover screen depends on camera distance */ + /* at a distance of 10 this is just about enough. */ + {XOFFSET * -6, YOFFSET * -6, 0}, + {XOFFSET * -4, YOFFSET * -6, 0}, + {XOFFSET * -2, YOFFSET * -6, 0}, + {XOFFSET * 0, YOFFSET * -6, 0}, + {XOFFSET * 2, YOFFSET * -6, 0}, + {XOFFSET * 4, YOFFSET * -6, 0}, + {XOFFSET * 6, YOFFSET * -6, 0}, + + {XOFFSET * -7, YOFFSET * -5, 0}, + {XOFFSET * -5, YOFFSET * -5, 0}, + {XOFFSET * -3, YOFFSET * -5, 0}, + {XOFFSET * -1, YOFFSET * -5, 0}, + {XOFFSET * 1, YOFFSET * -5, 0}, + {XOFFSET * 3, YOFFSET * -5, 0}, + {XOFFSET * 5, YOFFSET * -5, 0}, + {XOFFSET * 7, YOFFSET * -5, 0}, + + {XOFFSET * -8, YOFFSET * -4, 0}, + {XOFFSET * -6, YOFFSET * -4, 0}, + {XOFFSET * -4, YOFFSET * -4, 0}, + {XOFFSET * -2, YOFFSET * -4, 0}, + {XOFFSET * 0, YOFFSET * -4, 0}, + {XOFFSET * 2, YOFFSET * -4, 0}, + {XOFFSET * 4, YOFFSET * -4, 0}, + {XOFFSET * 6, YOFFSET * -4, 0}, + {XOFFSET * 8, YOFFSET * -4, 0}, + + {XOFFSET * -9, YOFFSET * -3, 0}, + {XOFFSET * -7, YOFFSET * -3, 0}, + {XOFFSET * -5, YOFFSET * -3, 0}, + {XOFFSET * -3, YOFFSET * -3, 0}, + {XOFFSET * -1, YOFFSET * -3, 0}, + {XOFFSET * 1, YOFFSET * -3, 0}, + {XOFFSET * 3, YOFFSET * -3, 0}, + {XOFFSET * 5, YOFFSET * -3, 0}, + {XOFFSET * 7, YOFFSET * -3, 0}, + {XOFFSET * 9, YOFFSET * -3, 0}, + + {XOFFSET * -10, YOFFSET * -2, 0}, + {XOFFSET * -8, YOFFSET * -2, 0}, + {XOFFSET * -6, YOFFSET * -2, 0}, + {XOFFSET * -4, YOFFSET * -2, 0}, + {XOFFSET * -2, YOFFSET * -2, 0}, + {XOFFSET * 0, YOFFSET * -2, 0}, + {XOFFSET * 2, YOFFSET * -2, 0}, + {XOFFSET * 4, YOFFSET * -2, 0}, + {XOFFSET * 6, YOFFSET * -2, 0}, + {XOFFSET * 8, YOFFSET * -2, 0}, + {XOFFSET * 10, YOFFSET * -2, 0}, + + {XOFFSET * -11, YOFFSET * -1, 0}, + {XOFFSET * -9, YOFFSET * -1, 0}, + {XOFFSET * -7, YOFFSET * -1, 0}, + {XOFFSET * -5, YOFFSET * -1, 0}, + {XOFFSET * -3, YOFFSET * -1, 0}, + {XOFFSET * -1, YOFFSET * -1, 0}, + {XOFFSET * 1, YOFFSET * -1, 0}, + {XOFFSET * 3, YOFFSET * -1, 0}, + {XOFFSET * 5, YOFFSET * -1, 0}, + {XOFFSET * 7, YOFFSET * -1, 0}, + {XOFFSET * 9, YOFFSET * -1, 0}, + {XOFFSET * 11, YOFFSET * -1, 0}, + + {XOFFSET * -12, YOFFSET * 0, 0}, + {XOFFSET * -10, YOFFSET * 0, 0}, + {XOFFSET * -8, YOFFSET * 0, 0}, + {XOFFSET * -6, YOFFSET * 0, 0}, + {XOFFSET * -4, YOFFSET * 0, 0}, + {XOFFSET * -2, YOFFSET * 0, 0}, + {XOFFSET * 0, YOFFSET * 0, 0}, + {XOFFSET * 2, YOFFSET * 0, 0}, + {XOFFSET * 4, YOFFSET * 0, 0}, + {XOFFSET * 6, YOFFSET * 0, 0}, + {XOFFSET * 8, YOFFSET * 0, 0}, + {XOFFSET * 10, YOFFSET * 0, 0}, + {XOFFSET * 12, YOFFSET * 0, 0}, + + {XOFFSET * -11, YOFFSET * 1, 0}, + {XOFFSET * -9, YOFFSET * 1, 0}, + {XOFFSET * -7, YOFFSET * 1, 0}, + {XOFFSET * -5, YOFFSET * 1, 0}, + {XOFFSET * -3, YOFFSET * 1, 0}, + {XOFFSET * -1, YOFFSET * 1, 0}, + {XOFFSET * 1, YOFFSET * 1, 0}, + {XOFFSET * 3, YOFFSET * 1, 0}, + {XOFFSET * 5, YOFFSET * 1, 0}, + {XOFFSET * 7, YOFFSET * 1, 0}, + {XOFFSET * 9, YOFFSET * 1, 0}, + {XOFFSET * 11, YOFFSET * 1, 0}, + + {XOFFSET * -10, YOFFSET * 2, 0}, + {XOFFSET * -8, YOFFSET * 2, 0}, + {XOFFSET * -6, YOFFSET * 2, 0}, + {XOFFSET * -4, YOFFSET * 2, 0}, + {XOFFSET * -2, YOFFSET * 2, 0}, + {XOFFSET * 0, YOFFSET * 2, 0}, + {XOFFSET * 2, YOFFSET * 2, 0}, + {XOFFSET * 4, YOFFSET * 2, 0}, + {XOFFSET * 6, YOFFSET * 2, 0}, + {XOFFSET * 8, YOFFSET * 2, 0}, + {XOFFSET * 10, YOFFSET * 2, 0}, + + {XOFFSET * -9, YOFFSET * 3, 0}, + {XOFFSET * -7, YOFFSET * 3, 0}, + {XOFFSET * -5, YOFFSET * 3, 0}, + {XOFFSET * -3, YOFFSET * 3, 0}, + {XOFFSET * -1, YOFFSET * 3, 0}, + {XOFFSET * 1, YOFFSET * 3, 0}, + {XOFFSET * 3, YOFFSET * 3, 0}, + {XOFFSET * 5, YOFFSET * 3, 0}, + {XOFFSET * 7, YOFFSET * 3, 0}, + {XOFFSET * 9, YOFFSET * 3, 0}, + + {XOFFSET * -8, YOFFSET * 4, 0}, + {XOFFSET * -6, YOFFSET * 4, 0}, + {XOFFSET * -4, YOFFSET * 4, 0}, + {XOFFSET * -2, YOFFSET * 4, 0}, + {XOFFSET * 0, YOFFSET * 4, 0}, + {XOFFSET * 2, YOFFSET * 4, 0}, + {XOFFSET * 4, YOFFSET * 4, 0}, + {XOFFSET * 6, YOFFSET * 4, 0}, + {XOFFSET * 8, YOFFSET * 4, 0}, + + {XOFFSET * -7, YOFFSET * 5, 0}, + {XOFFSET * -5, YOFFSET * 5, 0}, + {XOFFSET * -3, YOFFSET * 5, 0}, + {XOFFSET * -1, YOFFSET * 5, 0}, + {XOFFSET * 1, YOFFSET * 5, 0}, + {XOFFSET * 3, YOFFSET * 5, 0}, + {XOFFSET * 5, YOFFSET * 5, 0}, + {XOFFSET * 7, YOFFSET * 5, 0}, + + {XOFFSET * -6, YOFFSET * 6, 0}, + {XOFFSET * -4, YOFFSET * 6, 0}, + {XOFFSET * -2, YOFFSET * 6, 0}, + {XOFFSET * 0, YOFFSET * 6, 0}, + {XOFFSET * 2, YOFFSET * 6, 0}, + {XOFFSET * 4, YOFFSET * 6, 0}, + {XOFFSET * 6, YOFFSET * 6, 0}, +}; + +/* +**---------------------------------------------------------------------------- +** Local Variables +**---------------------------------------------------------------------------- +*/ + +static gleidestruct *gleidescope = NULL; + +#if 0 +/* + *load defaults in config structure + */ +static void setdefaultconfig(void) +{ +#ifdef GRAB + grab = False; +#endif + move = False; + rotate = False; + zoom = False; + image = NULL; +} +#endif + +ENTRYPOINT Bool +gleidescope_handle_event(ModeInfo *mi, XEvent *event) +{ + gleidestruct *gp = &gleidescope[MI_SCREEN(mi)]; + + /* + printf("event:%d\n", event->xany.type); + printf("button:%d\n", event->xbutton.button); + */ + if (event->xany.type == ButtonPress) + { + if (event->xbutton.button == Button1 || + event->xbutton.button == Button3) + { + /* store initial values of mouse */ + gp->xstart = event->xbutton.x; + gp->ystart = event->xbutton.y; + + /* button is down */ + gp->button_down_p = True; + return True; + } +#if 0 /* TODO */ + else if (event->xbutton.button == Button4) + { + /* zoom in */ + return True; + } + else if (event->xbutton.button == Button5) + { + /* zoom out */ + return True; + } +#endif + } else if (event->xany.type == ButtonRelease) + { + if (event->xbutton.button == Button1 || + event->xbutton.button == Button3) + { + /* button is up */ + gp->button_down_p = False; + return True; + } + } else if (event->xany.type == MotionNotify) + { + if (gp->button_down_p) + { + /* update mouse position */ + gp->xmouse += (double)(event->xmotion.x - gp->xstart) / MI_WIDTH(mi); + gp->ymouse += (double)(event->xmotion.y - gp->ystart) / MI_HEIGHT(mi); + gp->xstart = event->xmotion.x; + gp->ystart = event->xmotion.y; + + return True; + } + } + else if (screenhack_event_helper (MI_DISPLAY(mi), MI_WINDOW(mi), event)) + { + gp->start_time = -1; + gp->fade = 0; + return True; + } + + return False; +} + + +static void +image_loaded_cb (const char *filename, XRectangle *geometry, + int image_width, int image_height, + int texture_width, int texture_height, + void *closure) +{ + texture *tp = (texture *) closure; + +#if 0 + gp->max_tx = (GLfloat) image_width / texture_width; + gp->max_ty = (GLfloat) image_height / texture_height; +#endif + + /* new - taken from flipscreen */ + tp->width = texture_width; + tp->height = texture_height; + tp->min_tx = (GLfloat) geometry->x / tp->width; + tp->min_ty = (GLfloat) geometry->y / tp->height; + tp->max_tx = (GLfloat) (geometry->x + geometry->width) / tp->width; + tp->max_ty = (GLfloat) (geometry->y + geometry->height) / tp->height; + +#ifdef DEBUG + printf("Image w,h: (%d, %d)\n", image_width, image_height); + printf("Texture w,h: (%d, %d)\n", texture_width, texture_height); + printf("Geom x,y: (%d, %d)\n", geometry->x, geometry->y); + printf("Geom w,h: (%d, %d)\n", geometry->width, geometry->height); + printf("Max Tx,Ty: (%f, %f)\n", tp->max_tx, tp->max_ty); +#endif + + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, + (tp->mipmap_p ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR)); + + tp->waiting_for_image_p = False; + tp->start_time = time ((time_t *) 0); +} + +static void +getSnapshot(ModeInfo *mi, texture *texture) +{ + gleidestruct *gp = &gleidescope[MI_SCREEN(mi)]; + +#ifdef DEBUG + printf("getSnapshot"); +#endif + + if (MI_IS_WIREFRAME(mi)) + return; + + gp->mipmap_p = True; + load_texture_async (mi->xgwa.screen, mi->window, + *gp->glx_context, 0, 0, gp->mipmap_p, + texture->id, image_loaded_cb, texture); + texture->start_time = time((time_t *)0); +} + +#define TEXTURE_SIZE 256 + +static void +plot(unsigned char *buffer, int x, int y, int r, int g, int b, int a) { + int c; + if (x < 0 || x >= TEXTURE_SIZE || y < 0 || y >= TEXTURE_SIZE) { + return; + } + c = ((x * TEXTURE_SIZE) + y) * 4; + /*printf("(%d,%d)[%d]\n", x, y, c);*/ + buffer[c + 0] = r; + buffer[c + 1] = g; + buffer[c + 2] = b; + buffer[c + 3] = a; +} + +#if 0 +static void +plot2(unsigned char *buffer, int x, int y, int r, int g, int b, int a) { + int c; + if (x < 0 || x >= TEXTURE_SIZE || y < 0 || y >= TEXTURE_SIZE) { + return; + } + c = ((x * TEXTURE_SIZE) + y) * 4; + /*printf("(%d,%d)[%d]\n", x, y, c);*/ + buffer[c + 0] = r; + buffer[c + 1] = g; + buffer[c + 2] = b; + buffer[c + 3] = a; + + if (y + 1 < TEXTURE_SIZE) { + buffer[c + 4] = r; + buffer[c + 5] = g; + buffer[c + 6] = b; + buffer[c + 7] = a; + } + + if (x + 1 < TEXTURE_SIZE) { + c += (TEXTURE_SIZE * 4); + buffer[c + 0] = r; + buffer[c + 1] = g; + buffer[c + 2] = b; + buffer[c + 3] = a; + if (y + 1 < TEXTURE_SIZE) { + buffer[c + 4] = r; + buffer[c + 5] = g; + buffer[c + 6] = b; + buffer[c + 7] = a; + } + } +} +#endif + +/* draw geometric shapes to texture */ +/* modifies passed in buffer */ +static void +draw_shapes (unsigned char *buffer) { + int a = 0xff; + int x, y, w, h; + int i, j; + int s; + float left, right; + + for (i = 0 ; i < TEXTURE_SIZE * TEXTURE_SIZE * 4 ; i += 4) { + buffer[i + 0] = 0x00; + buffer[i + 1] = 0x00; + buffer[i + 2] = 0x00; + buffer[i + 3] = 0xff; + } + + for (s = 0 ; s < 25 ; s++) { + int shape = random() % 3; + + /* 8 bits */ + int r = (random() & 0xff); + int g = (random() & 0xff); + int b = (random() & 0xff); + + switch (shape) { + case 0: + /* rectangle */ + x = (random() % TEXTURE_SIZE) - (TEXTURE_SIZE / 4); /* top left */ + y = (random() % TEXTURE_SIZE) - (TEXTURE_SIZE / 4); + w = 10 + random() % (TEXTURE_SIZE / 4); /* size */ + h = 10 + random() % (TEXTURE_SIZE / 4); +#ifdef DEBUG + printf("Rectangle: (%d, %d)(%d, %d)\n", x, y, w, h); +#endif + if (x < 0) { + x = 0; + } + if (y < 0) { + y = 0; + } + for (i = x ; i < x + w && i < TEXTURE_SIZE; i++) { + for (j = y ; j < y + h && j < TEXTURE_SIZE; j++) { + plot(buffer, i, j, r, g, b, a); + } + } + break; + + case 1: + /* circle */ + x = random() % TEXTURE_SIZE; /* centre */ + y = random() % TEXTURE_SIZE; + h = 10 + random() % (TEXTURE_SIZE / 8); /* radius */ +#ifdef DEBUG + printf("Circle: %d, %d, %d\n", x, y, h); +#endif + for (i = 0 ; i < h ; i++) { + int xdist = i * i; + for (j = 0 ; j < h ; j++) { + int ydist = j * j; + /* + printf("xdist: %d\n", xdist); + printf("ydist: %d\n", ydist); + printf("radius: %d\n", h * h); + */ + if ((xdist + ydist) < (h * h)) { + plot(buffer, x + i, y + j, r, b, g, a); + /* check we haven't already done these */ + if (j != 0) { + plot(buffer, x + i, y - j, r, b, g, a); + } + if (i != 0) { + plot(buffer, x - i, y + j, r, b, g, a); + if (j != 0) { + plot(buffer, x - i, y - j, r, b, g, a); + } + } + } + } + } + break; + + case 2: + /* triangle */ + x = random() % TEXTURE_SIZE; /* top */ + y = random() % TEXTURE_SIZE; + h = 10 + random() % (TEXTURE_SIZE / 4); /* height */ +#ifdef DEBUG + printf("Triangle: %d, %d, %d\n", x, y, h); +#endif + left = x; + right = x; + for (i = 0 ; i < h ; i++) { + for (j = left ; j < right ; j++) { + plot(buffer, j, y + i, r, g, b, a); + } + left -= .5; + right += .5; + } + break; + } + } +} + +static void +setup_random_texture (ModeInfo *mi, texture *texture) +{ + int width = 0, height = 0; + char buf[1024]; + unsigned char *my_data = NULL; +#if 0 + int i, j, c; + int style; + int r0, g0, b0, a0, r1, g1, b1, a1; +#endif + +#ifdef DEBUG + printf("RandomTexture\n"); +#endif + + /* use this texture */ + glBindTexture(GL_TEXTURE_2D, texture->id); + + clear_gl_error(); + + /* + * code for various generated patterns - noise, stripes, checks etc. + * random geometric shapes looked the best. + */ + +#if 0 + style = random() & 0x3; + r0 = random() & 0xff; + g0 = random() & 0xff; + b0 = random() & 0xff; + a0 = 0xff; + r1 = random() & 0xff; + g1 = random() & 0xff; + b1 = random() & 0xff; + a1 = 0xff; + + switch (style) { + case 0: /* random */ + printf("Random0\n"); + height = width = TEXTURE_SIZE; + my_data = (void *)malloc(width * height * 4); + for (i = 0 ; i < width ; i += 2) { + for (j = 0 ; j < height ; j += 2) { + r0 = random() & 0xff; + g0 = random() & 0xff; + b0 = random() & 0xff; + a0 = 0xff; + plot2(my_data, i, j, r0, g0, b0, a0); + } + } + break; + + case 1: /* shapes */ +#endif +#ifdef DEBUG + printf("Shapes\n"); +#endif + height = width = TEXTURE_SIZE; + my_data = (void *)malloc(width * height * 4); + draw_shapes(my_data); +#if 0 + break; + + case 2: /* check */ + printf("Check\n"); + height = width = TEXTURE_SIZE; + my_data = (void *)malloc(width * height * 4); + for (i = 0 ; i < height ; i += 2) { + for (j = 0 ; j < width ; j += 2) { + if (((i + j) & 0x3) == 0) { + plot2(my_data, i, j, r0, g0, b0, a0); + } else { + plot2(my_data, i, j, r1, g1, b1, a1); + } + } + } + break; + + case 3: /* random stripes */ + printf("Stripes 2\n"); + height = width = TEXTURE_SIZE; + my_data = (void *)malloc(width * height * 4); + for (i = 0 ; i < height ; i += 2) { + r0 = random() & 0xff; + g0 = random() & 0xff; + b0 = random() & 0xff; + a0 = 0xff; + for (j = 0 ; j < width ; j += 2) { + plot2(my_data, i, j, r0, g0, b0, a0); + } + } + break; + } +#endif + + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, + width, height, 0, + GL_RGBA, GL_UNSIGNED_BYTE, my_data); + sprintf (buf, "random texture: (%dx%d)", + width, height); + check_gl_error(buf); + + /* setup parameters for texturing */ + glPixelStorei(GL_UNPACK_ALIGNMENT, 4); + glPixelStorei(GL_UNPACK_ROW_LENGTH, width); + + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + if (random() & 0x1) { + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + } else { + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + } + + if (my_data != NULL) { + free(my_data); + my_data = NULL; + } + + /* use full texture */ + /* acd - was 1.0 */ + texture->min_tx = 0.0; + texture->max_tx = 2.0; + texture->min_ty = 0.0; + texture->max_ty = 2.0; + texture->start_time = time((time_t *)0); +} + +static Bool +setup_file_texture (ModeInfo *mi, char *filename, texture *texture) +{ + Display *dpy = mi->dpy; + Visual *visual = mi->xgwa.visual; + char buf[1024]; + + XImage *image = file_to_ximage (dpy, visual, filename); + if (!image) return False; + +#ifdef DEBUG + printf("FileTexture\n"); +#endif + + /* use this texture */ + glBindTexture(GL_TEXTURE_2D, texture->id); + + clear_gl_error(); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, + image->width, image->height, 0, + GL_RGBA, GL_UNSIGNED_BYTE, image->data); + sprintf (buf, "texture: %.100s (%dx%d)", + filename, image->width, image->height); + check_gl_error(buf); + + /* setup parameters for texturing */ + glPixelStorei(GL_UNPACK_ALIGNMENT, 4); + glPixelStorei(GL_UNPACK_ROW_LENGTH, image->width); + + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + + /* use full texture */ + texture->min_tx = 0.0; + texture->max_tx = 1.0; + texture->min_ty = 0.0; + texture->max_ty = 1.0; + texture->start_time = time((time_t *)0); + return True; +} + +static void +setup_texture(ModeInfo * mi, texture *texture) +{ + gleidestruct *gp = &gleidescope[MI_SCREEN(mi)]; + + if (!image_str || !*image_str || !strcmp(image_str, "DEFAULT")) { + BUILTIN: + /* no image specified - use system settings */ +#ifdef DEBUG + printf("SetupTexture: get_snapshot\n"); +#endif + getSnapshot(mi, texture); + } else { + if (strcmp(image_str, "GENERATE") == 0) { +#ifdef DEBUG + printf("SetupTexture: random_texture\n"); +#endif + setup_random_texture(mi, texture); + } else { + /* use supplied image file */ +#ifdef DEBUG + printf("SetupTexture: file_texture\n"); +#endif + if (! setup_file_texture(mi, image_str, texture)) + goto BUILTIN; + } + } + /* copy start time from texture */ + gp->start_time = texture->start_time; + + check_gl_error("texture initialization"); + + /* acd + * resultant loaded image is upside down BUT + * it's a kaledescope and half of the hexagon is backwards anyway... + */ + + /* TODO: values for lissajous movement */ + texture->x_period = frandrange(-2.0, 2.0); + texture->y_period = frandrange(-2.0, 2.0); + texture->r_period = frandrange(-2.0, 2.0); + texture->x_phase = frand(M_PI * 2); + texture->y_phase = frand(M_PI * 2); + texture->r_phase = frand(M_PI * 2); +#ifdef DEBUG + printf("XPeriod %f XPhase %f\n", texture->x_period, texture->x_phase); + printf("YPeriod %f YPhase %f\n", texture->y_period, texture->y_phase); + printf("RPeriod %f RPhase %f\n", texture->r_period, texture->r_phase); +#endif +} + +#define VERTEX0 glVertex3f( 0.0000f, 0.000f, 0.0f); +#define VERTEX1 glVertex3f( 0.0000f, 1.000f, 0.0f); +#define VERTEX2 glVertex3f( XOFFSET, 0.500f, 0.0f); +#define VERTEX3 glVertex3f( XOFFSET, -0.500f, 0.0f); +#define VERTEX4 glVertex3f( 0.0000f, -1.000f, 0.0f); +#define VERTEX5 glVertex3f(-XOFFSET, -0.500f, 0.0f); +#define VERTEX6 glVertex3f(-XOFFSET, 0.500f, 0.0f); + +/* +** Three different functions for calculating texture coordinates +** which modify how the texture triangle moves over the source image. +** Choose one. +*/ + +#if 0 +/* the classic equilateral triangle rotating around centre */ +static void +calculate_texture_coords(ModeInfo *mi, texture *texture, vector2f t[3]) { + + gleidestruct *gp = &gleidescope[MI_SCREEN(mi)]; + GLfloat centre_x = 0.5; + GLfloat centre_y = 0.5; + GLfloat radius_x = (texture->max_tx - texture->min_tx) / 2; + GLfloat radius_y = (texture->max_ty - texture->min_ty) / 2; + GLfloat tangle2; + t[0].x = centre_x; + t[0].y = centre_y; + + /* t[1] */ + t[1].x = centre_x + .95 * radius_x * cos((gp->ymouse * 2 * M_PI) + (gp->tangle * RADIANS)); + t[1].y = centre_y + .95 * radius_y * sin((gp->ymouse * 2 * M_PI) + (gp->tangle * RADIANS)); + + /* t[2] is always 60' further around than t2 */ + tangle2 = (gp->ymouse * 2 * M_PI) + (gp->tangle * RADIANS) + (M_PI * 2 / 6); + t[2].x = centre_x + .95 * radius_x * cos(tangle2); + t[2].y = centre_y + .95 * radius_y * sin(tangle2); +#if 0 + printf("texcoords:[%f,%f]->[%f,%f](%f,%f)\n", t[0].x, t[0].y, t[1].x, t[1].y, texture->max_tx, texture->max_ty); +#endif +} +#endif + +#if 1 +/* new lissajous movement pattern */ +static void +calculate_texture_coords(ModeInfo *mi, texture *texture, vector2f t[3]) { + + /* equilateral triangle rotating around centre */ + gleidestruct *gp = &gleidescope[MI_SCREEN(mi)]; + GLfloat width = texture->max_tx - texture->min_tx; + GLfloat height = texture->max_ty - texture->min_ty; + /* centre */ + GLfloat centre_x = texture->min_tx + (width * .5); + GLfloat centre_y = texture->min_ty + (height * .5); + /* m radius and t radius should be = .5 */ + /* triangle radius is 30% available space */ + GLfloat t_radius_x = width * .3; + GLfloat t_radius_y = height * .3; + /* movement radius is 30% available space */ + GLfloat m_radius_x = width * .2; + GLfloat m_radius_y = height * .2; + GLfloat angle2; + + /* centre of triangle */ + GLfloat angle = (gp->ymouse * 2 * M_PI) + (gp->tangle * RADIANS); /* to radians */ + GLfloat t_centre_x = centre_x + m_radius_x * cos(texture->x_period * angle + texture->x_phase); + GLfloat t_centre_y = centre_y + m_radius_y * sin(texture->y_period * angle + texture->y_phase); + +#if 0 + printf("WH: %f, %f - tWH: %f, %f\n", width, height, texture->width, texture->height); + printf("size: (%f, %f)\n", width, height); + printf("centre: (%f, %f)\n", centre_x, centre_y); +#endif + + angle2 = texture->r_period * angle + texture->r_phase; + t[0].x = t_centre_x + t_radius_x * cos(angle2); + t[0].y = t_centre_y + t_radius_y * sin(angle2); + t[1].x = t_centre_x + t_radius_x * cos(angle2 + ANGLE_120); + t[1].y = t_centre_y + t_radius_y * sin(angle2 + ANGLE_120); + t[2].x = t_centre_x + t_radius_x * cos(angle2 + ANGLE_240); + t[2].y = t_centre_y + t_radius_y * sin(angle2 + ANGLE_240); + +#if 0 + printf("texcoords:[%f,%f]->[%f,%f](%f,%f)\n", t[0].x, t[0].y, t[1].x, t[1].y, texture->max_tx, texture->max_ty); +#endif +} +#endif + +#if 0 +/* corners into corners - meant to maximise coverage */ +static void +calculate_texture_coords(ModeInfo *mi, texture *texture, vector2f t[3]) { + + /* equilateral triangle rotating around centre */ + gleidestruct *gp = &gleidescope[MI_SCREEN(mi)]; + GLfloat width = texture->max_tx - texture->min_tx; + GLfloat height = texture->max_ty - texture->min_ty; + /* centre */ + GLfloat centre_x = texture->min_tx + (width * .5); + GLfloat centre_y = texture->min_ty + (height * .5); + /* m radius and t radius should be = .5 */ + /* triangle radius calculated using maths 8) */ +#define TRADIUS (M_SQRT2 - 1.0) +#define MRADIUS (1.0 - (M_SQRT2 / 2.0)) + GLfloat t_radius_x = width * TRADIUS * .95; + GLfloat t_radius_y = height * TRADIUS * .95; + /* movement radius also calculated using maths */ + GLfloat m_radius_x = width * MRADIUS * .95; + GLfloat m_radius_y = height * MRADIUS * .95; + GLfloat angle, angle2; + GLfloat t_centre_x, t_centre_y; + + /* centre of triangle */ + angle = gp->tangle * RADIANS; /* to radians */ + t_centre_x = centre_x + m_radius_x * cos(angle); + t_centre_y = centre_y + m_radius_y * sin(angle); +#if 0 + printf("angle: %f, %f\n", angle, gp->tangle); + printf("tcentre: %f,%f\n", t_centre_x, t_centre_y); + printf("tradius: %f,%f\n", t_radius_x, t_radius_y); + + printf("size: (%f, %f)\n", width, height); + printf("centre: (%f, %f)\n", centre_x, centre_y); + printf("centre: (%f, %f)\n", centre_x, centre_y); + printf("TRADIUS: %f\n", TRADIUS); + printf("MRADIUS: %f\n", MRADIUS); +#endif + + /* angle2 is tied to tangle */ + angle2 = (180.0 - ((30.0 / 90.0) * gp->tangle)) * RADIANS; +#if 0 + printf("Angle1: %f\tAngle2: %f\n", angle / RADIANS, angle2 / RADIANS); +#endif + t[0].x = t_centre_x + t_radius_x * cos(angle2); + t[0].y = t_centre_y + t_radius_y * sin(angle2); + t[1].x = t_centre_x + t_radius_x * cos(angle2 + ANGLE_120); + t[1].y = t_centre_y + t_radius_y * sin(angle2 + ANGLE_120); + t[2].x = t_centre_x + t_radius_x * cos(angle2 + ANGLE_240); + t[2].y = t_centre_y + t_radius_y * sin(angle2 + ANGLE_240); + +#if 0 + printf("texcoords:[%f,%f][%f,%f][%f,%f]\n", t[0].x, t[0].y, t[1].x, t[1].y, t[2].x, t[2].y); +#endif +} +#endif + +static int +draw_hexagons(ModeInfo *mi, int translucency, texture *texture) +{ + int polys = 0; + int i; + vector2f t[3]; + gleidestruct *gp = &gleidescope[MI_SCREEN(mi)]; + + calculate_texture_coords(mi, texture, t); + + glColor4f(1.0, 1.0, 1.0, (float)translucency / MAX_FADE); + glEnable(GL_TEXTURE_2D); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glDepthMask(GL_FALSE); + glBindTexture(GL_TEXTURE_2D, texture->id); + + if (gp->list == -1) { + gp->list = glGenLists(1); + } + + /* compile new list */ + glNewList(gp->list, GL_COMPILE); + glBegin(GL_TRIANGLES); + + /* + ** six triangles to each hexagon + */ + + glTexCoord2f(t[0].x, t[0].y); + VERTEX0; + glTexCoord2f(t[1].x, t[1].y); + VERTEX1; + glTexCoord2f(t[2].x, t[2].y); + VERTEX6; + + glTexCoord2f(t[0].x, t[0].y); + VERTEX0; + glTexCoord2f(t[2].x, t[2].y); + VERTEX6; + glTexCoord2f(t[1].x, t[1].y); + VERTEX5; + + glTexCoord2f(t[0].x, t[0].y); + VERTEX0; + glTexCoord2f(t[1].x, t[1].y); + VERTEX5; + glTexCoord2f(t[2].x, t[2].y); + VERTEX4; + + glTexCoord2f(t[0].x, t[0].y); + VERTEX0; + glTexCoord2f(t[2].x, t[2].y); + VERTEX4; + glTexCoord2f(t[1].x, t[1].y); + VERTEX3; + + glTexCoord2f(t[0].x, t[0].y); + VERTEX0; + glTexCoord2f(t[1].x, t[1].y); + VERTEX3; + glTexCoord2f(t[2].x, t[2].y); + VERTEX2; + + glTexCoord2f(t[0].x, t[0].y); + VERTEX0; + glTexCoord2f(t[2].x, t[2].y); + VERTEX2; + glTexCoord2f(t[1].x, t[1].y); + VERTEX1; + + glEnd(); + glEndList(); + + /* call the list n times */ + for (i = 0 ; i < sizeof(hex) / sizeof(hex[0]) ; i++) { + + glPushMatrix(); + + glTranslatef(hex[i].x, hex[i].y, 0.0); + glCallList(gp->list); + polys += 6; + + glPopMatrix(); + } + +#ifdef DISPLAY_TEXTURE + glPushMatrix(); + /* acd debug - display (bigger, centred) texture */ + glScalef(2.0, 2.0, 2.0); + glTranslatef(-0.5, -0.5, 0.0); + glBegin(GL_QUADS); + glTexCoord2f(0.0, 0.0); + glVertex3f(0.0, 0.0, -0.1); + glTexCoord2f(1.0, 0.0); + glVertex3f(1.0, 0.0, -0.1); + glTexCoord2f(1.0, 1.0); + glVertex3f(1.0, 1.0, -0.1); + glTexCoord2f(0.0, 1.0); + glVertex3f(0.0, 1.0, -0.1); + polys++; + glEnd(); + /* acd debug - display texture triangle */ + glColor4f(1.0, 0.5, 1.0, 1.0); + glBegin(GL_LINE_LOOP); + glVertex3f(t[0].x, t[0].y, -0.11); + glVertex3f(t[1].x, t[1].y, -0.11); + glVertex3f(t[2].x, t[2].y, -0.11); + polys++; + glEnd(); + glPopMatrix(); +#endif + + glDisable(GL_TEXTURE_2D); + glDepthMask(GL_TRUE); + glDisable(GL_BLEND); + return polys; +} + +/* + * main rendering loop + */ +static void +draw(ModeInfo * mi) +{ + GLfloat x_angle, y_angle, z_angle; + gleidestruct *gp = &gleidescope[MI_SCREEN(mi)]; + vectorf v1; + + mi->polygon_count = 0; + + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glLoadIdentity(); + + gp->tic += 0.005f; + + x_angle = gp->cam_x_phase + gp->tic * gp->cam_x_speed; + y_angle = gp->cam_y_phase + gp->tic * gp->cam_y_speed; + z_angle = gp->cam_z_phase + gp->tic * gp->cam_z_speed; + + if (move) { + v1.x = 1 * sin(x_angle); + v1.y = 1 * sin(y_angle); + } else { + v1.x = 0; + v1.y = 0; + } + + /* size is changed in pinit() to be distance from plane */ + gp->size = MI_SIZE(mi); + if (gp->size > 10) { + gp->size = 10; + } + if (gp->size <= 0) { + gp->size = 0; + } + if (gp->size > 0) { + /* user defined size */ + v1.z = gp->size; + } else if (zoom) { + /* max distance given by adding the constant and the multiplier */ + v1.z = 5.0 + 3.0 * sin(z_angle); + } else { + /* default */ + v1.z = 7.0; + } + + /* update rotation angle (but not if mouse button down) */ + if (rotate && !gp->button_down_p) + { + float new_rangle_vel = 0.0; + + /* update camera rotation angle and velocity */ + gp->rangle += gp->rangle_vel; + new_rangle_vel = gp->rangle_vel + gp->rangle_acc; + if (new_rangle_vel > -MAX_ANGLE_VEL && new_rangle_vel < MAX_ANGLE_VEL) + { + /* new velocity is within limits */ + gp->rangle_vel = new_rangle_vel; + } + + /* randomly change twisting speed - 3ff = 1024 */ + if ((random() % TWISTING_PROBABILITY) < 1.0) { + gp->rangle_acc = INITIAL_ANGLE_ACC * frand(1.0); + if (gp->rangle_vel > 0.0) { + gp->rangle_acc = -gp->rangle_acc; + } + } + } +#if 0 + printf("Rangle: %f : %f : %f\n", gp->rangle, gp->rangle_vel, gp->rangle_acc); + printf("Tangle: %f : %f : %f\n", gp->tangle, gp->tangle_vel, gp->tangle_acc); +#endif + +#ifdef WOBBLE + /* this makes the image wobble - requires -move and a larger grid */ + gluLookAt(0, 0, v1.z, v1.x, v1.y, 0.0, 0.0, 1.0, 0.0); +#else + /* no wobble - camera always perpendicular to grid */ + + /* rotating camera rather than entire space - smoother */ + gluLookAt( + v1.x, v1.y, v1.z, + v1.x, v1.y, 0.0, + sin((gp->xmouse * M_PI * 2) + gp->rangle * RADIANS), + cos((gp->xmouse * M_PI * 2) + gp->rangle * RADIANS), + 0.0); +#endif + +# ifdef HAVE_MOBILE /* Keep it the same relative size when rotated. */ + { + GLfloat h = MI_HEIGHT(mi) / (GLfloat) MI_WIDTH(mi); + int o = (int) current_device_rotation(); + if (o != 0 && o != 180 && o != -180) + glScalef (1/h, 1/h, 1/h); + } +# endif + + if (gp->fade == 0) + { + /* not fading */ + mi->polygon_count += + draw_hexagons(mi, MAX_FADE, &gp->textures[gp->visible]); + } + else + { + /* fading - show both textures with alpha + NB first is always max alpha */ + mi->polygon_count += + draw_hexagons(mi, MAX_FADE, &gp->textures[1 - gp->visible]); + mi->polygon_count += + draw_hexagons(mi, MAX_FADE - gp->fade, &gp->textures[gp->visible]); + + /* fade some more */ + gp->fade++; + + /* have we faded enough? */ + if (gp->fade > MAX_FADE) + { + /* stop fading */ + gp->fade = 0; + gp->visible = 1 - gp->visible; + } + } + + /* increment texture angle based on time, velocity etc */ + /* but only if button is not down */ + if (!gp->button_down_p) + { + float new_tangle_vel = 0.0; + + gp->tangle += gp->tangle_vel; + + /* work out new texture angle velocity */ + new_tangle_vel = gp->tangle_vel + gp->tangle_acc; + if (new_tangle_vel > -MAX_ANGLE_VEL && new_tangle_vel < MAX_ANGLE_VEL) + { + /* new velocity is inside limits */ + gp->tangle_vel = new_tangle_vel; + } + + /* randomly change twisting speed - 3ff = 1024 */ + if ((random() % TWISTING_PROBABILITY) < 1.0) { + gp->tangle_acc = INITIAL_ANGLE_ACC * frand(1.0); + if (gp->tangle_vel > 0.0) { + gp->tangle_acc = -gp->tangle_acc; + } + } + } + + glFlush(); +} + +/* + * new window size or exposure + */ +ENTRYPOINT void reshape_gleidescope(ModeInfo *mi, int width, int height) +{ + gleidestruct *gp = &gleidescope[MI_SCREEN(mi)]; + GLfloat h = (GLfloat) height / (GLfloat) width; + + int y = 0; + + if (width > height * 5) { /* tiny window: show middle */ + height = width * 9/16; + y = -height/2; + h = height / (GLfloat) width; + } + + glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(gp->glx_context)); + + glViewport(0, y, (GLint) width, (GLint) height); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + gluPerspective(50.0, 1/h, 0.1, 2000.0); + glMatrixMode (GL_MODELVIEW); + glLineWidth(1); + glPointSize(1); +} + +static void +pinit(ModeInfo * mi) +{ + gleidestruct *gp = &gleidescope[MI_SCREEN(mi)]; + + /* set start time - star_time = 0 implies non-dynamic texture */ + gp->start_time = (time_t)0; + + /* set the texture size to default */ + /* + gp->max_tx = 1.0; + gp->max_ty = 1.0; + */ + + /* no fading */ + gp->fade = 0; + + glShadeModel(GL_SMOOTH); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + glEnable(GL_DEPTH_TEST); + glEnable(GL_CULL_FACE); + glDisable(GL_LIGHTING); + + /* space for textures */ + glGenTextures(1, &gp->textures[0].id); + glGenTextures(1, &gp->textures[1].id); + gp->visible = 0; + + setup_texture(mi, &gp->textures[gp->visible]); + + /* + ** want to choose a value for arg randomly if neither -arg nor -no-arg + ** is specified. xscreensaver libraries don't seem to let you do this - + ** if something isn't true then it is false (pesky two-state boolean values). + ** so, i've defined both -arg and -no-arg to arguments and added the + ** following logic. + ** (btw if both -arg and -no-arg are defined then arg is set to False) + */ + if (zoom == False && nozoom == False) + { + /* no zoom preference - randomise */ + zoom = (((random() & 0x1) == 0x1) ? True : False); + } + else if (nozoom == True) + { + /* definately no zoom */ + zoom = False; + } + + if (move == False && nomove == False) + { + /* no move preference - randomise */ + move = (((random() & 0x1) == 0x1) ? True : False); + } + else if (nomove == True) + { + /* definately no move */ + move = False; + } + + if (rotate == False && norotate == False) + { + /* no rotate preference - randomise */ + rotate = (((random() & 0x1) == 0x1) ? True : False); + } + else if (norotate == True) + { + /* definately no rotate */ + rotate = False; + } + + /* define cam variables */ + gp->cam_x_speed = MAX_CAM_SPEED * frandrange(-.5, 0.5); + gp->cam_x_phase = random() % 360; + gp->cam_y_speed = MAX_CAM_SPEED * frandrange(-.5, 0.5); + gp->cam_y_phase = random() % 360; + gp->cam_z_speed = MAX_CAM_SPEED * frandrange(-.5, 0.5); + gp->cam_z_phase = random() % 360; + + /* initial angular speeds */ + gp->rangle_vel = INITIAL_ANGLE_VEL * frandrange(-.5, 0.5); + gp->tangle_vel = INITIAL_ANGLE_VEL * frandrange(-.5, 0.5); + gp->rangle_acc = INITIAL_ANGLE_ACC * frandrange(-.5, 0.5); + gp->tangle_acc = INITIAL_ANGLE_ACC * frandrange(-.5, 0.5); + + /* jwz */ +#if 0 + { + GLfloat speed = 15; + gp->rangle_vel *= speed; + gp->tangle_vel *= speed; + gp->rangle_acc *= speed; + gp->tangle_acc *= speed; + } +#endif + + /* distance is 11 - size */ + if (gp->size != -1) { + if (zoom) { + fprintf(stderr, "-size given. ignoring -zoom.\n"); + zoom = False; + } + if (gp->size < 1) { + gp->size = 1; + } else if (gp->size >= 10) { + gp->size = 10; + } + gp->size = 11 - gp->size; + } + +#ifdef DEBUG +printf("phases [%d, %d, %d]\n", gp->cam_x_phase, gp->cam_y_phase, gp->cam_z_phase); +#endif +} + +ENTRYPOINT void +init_gleidescope(ModeInfo * mi) +{ + gleidestruct *gp; + int screen = MI_SCREEN(mi); + + MI_INIT(mi, gleidescope); + gp = &gleidescope[screen]; + gp->window = MI_WINDOW(mi); + gp->size = -1; + gp->list = -1; + + if ((gp->glx_context = init_GL(mi)) != NULL) { + + reshape_gleidescope(mi, MI_WIDTH(mi), MI_HEIGHT(mi)); + clear_gl_error(); /* WTF? sometimes "invalid op" from glViewport! */ + + glDrawBuffer(GL_BACK); + + /* do initialisation */ + pinit(mi); + + } else { + MI_CLEARWINDOW(mi); + } +} + +ENTRYPOINT void +draw_gleidescope(ModeInfo * mi) +{ + gleidestruct *gp = &gleidescope[MI_SCREEN(mi)]; + Display *display = MI_DISPLAY(mi); + Window window = MI_WINDOW(mi); + + + if (!gp->glx_context) + return; + + /* Just keep running before the texture has come in. */ + /* if (gp->waiting_for_image_p) return; */ + + glDrawBuffer(GL_BACK); + + glXMakeCurrent(display, window, *(gp->glx_context)); + draw(mi); + + if (mi->fps_p) { + do_fps (mi); + } + + glFinish(); + glXSwapBuffers(display, window); + +#ifdef GRAB + if (grab) { + grab_frame(display, window); + } +#endif + + /* need to change texture? */ + if ((gp->start_time != 0) && (duration != -1) && gp->fade == 0) { + if (gp->start_time + duration <= time((time_t *)0)) { +#ifdef DEBUG + printf("Start Time: %lu - Current Time: %lu\n", (unsigned long)gp->start_time, (unsigned long)time((time_t *)0)); + printf("Changing Texture\n"); +#endif + /* get new snapshot (into back buffer) and start fade count */ + setup_texture(mi, &gp->textures[1 - gp->visible]); + /* restart fading */ + gp->fade = 1; + } + } +} + +ENTRYPOINT void +free_gleidescope(ModeInfo * mi) +{ + gleidestruct *gp = &gleidescope[MI_SCREEN(mi)]; + + /* acd - is this needed? */ + if (gp->glx_context) { + /* Display lists MUST be freed while their glXContext is current. */ + glXMakeCurrent(MI_DISPLAY(mi), gp->window, *(gp->glx_context)); + + /* acd - was code here for freeing things that are no longer in struct */ + } +} + +XSCREENSAVER_MODULE ("Gleidescope", gleidescope) + +#endif |