2 * flipscreen3d - takes snapshots of the screen and flips it around
4 * version 1.0 - Oct 24, 2001
6 * Copyright (C) 2001 Ben Buxton (bb@cactii.net)
8 * Permission to use, copy, modify, distribute, and sell this software and its
9 * documentation for any purpose is hereby granted without fee, provided that
10 * the above copyright notice appear in all copies and that both that
11 * copyright notice and this permission notice appear in supporting
12 * documentation. No representations are made about the suitability of this
13 * software for any purpose. It is provided "as is" without express or
18 #define DEFAULTS "*delay: 20000 \n" \
19 "*showFPS: False \n" \
20 "*wireframe: False \n" \
23 # define refresh_screenflip 0
24 # include "xlockmore.h" /* from the xscreensaver distribution */
25 # include "gltrackball.h"
26 #else /* !STANDALONE */
27 # include "xlock.h" /* from the xlockmore distribution */
28 #endif /* !STANDALONE */
30 /* lifted from lament.c */
31 #define RAND(n) ((long) ((random() & 0x7fffffff) % ((long) (n))))
32 #define RANDSIGN() ((random() & 1) ? 1 : -1)
37 /* Should be in <GL/glext.h> */
38 # ifndef GL_TEXTURE_MAX_ANISOTROPY_EXT
39 # define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE
41 # ifndef GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT
42 # define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF
45 #define DEF_ROTATE "True"
52 #define countof(x) (sizeof((x))/sizeof((*x)))
55 static XrmOptionDescRec opts[] = {
56 {"+rotate", ".screenflip.rotate", XrmoptionNoArg, "false" },
57 {"-rotate", ".screenflip.rotate", XrmoptionNoArg, "true" },
61 static argtype vars[] = {
62 {&rotate, "rotate", "Rotate", DEF_ROTATE, t_Bool},
67 ENTRYPOINT ModeSpecOpt screenflip_opts = {countof(opts), opts, countof(vars), vars, NULL};
71 ModStruct screenflip_description =
72 {"screenflip", "init_screenflip", "draw_screenflip", "release_screenflip",
73 "draw_screenflip", "init_screenflip", NULL, &screenflip_opts,
74 1000, 1, 2, 1, 4, 1.0, "",
75 "Screenflips", 0, NULL};
81 GLXContext *glx_context;
85 int tw, th; /* texture width, height */
86 GLfloat min_tx, min_ty;
87 GLfloat max_tx, max_ty;
88 GLfloat qx, qy, qw, qh; /* the quad we'll draw */
91 int fadetime; /* fade before regrab */
93 trackball_state *trackball;
96 GLfloat show_colors[4];
97 GLfloat stretch_val_x, stretch_val_y;
98 GLfloat stretch_val_dx, stretch_val_dy;
100 GLfloat curx, cury, curz;
103 GLfloat rot, drot, odrot, ddrot, orot;
104 float theta, rho, dtheta, drho, gamma, dgamma;
108 Bool waiting_for_image_p;
115 static Screenflip *screenflip = NULL;
117 #include "grab-ximage.h"
119 static const GLfloat viewer[] = {0.0, 0.0, 15.0};
123 screenflip_handle_event (ModeInfo *mi, XEvent *event)
125 Screenflip *c = &screenflip[MI_SCREEN(mi)];
127 if (event->xany.type == ButtonPress &&
128 event->xbutton.button == Button1)
130 c->button_down_p = True;
131 gltrackball_start (c->trackball,
132 event->xbutton.x, event->xbutton.y,
133 MI_WIDTH (mi), MI_HEIGHT (mi));
136 else if (event->xany.type == ButtonRelease &&
137 event->xbutton.button == Button1)
139 c->button_down_p = False;
142 else if (event->xany.type == ButtonPress &&
143 (event->xbutton.button == Button4 ||
144 event->xbutton.button == Button5 ||
145 event->xbutton.button == Button6 ||
146 event->xbutton.button == Button7))
148 gltrackball_mousewheel (c->trackball, event->xbutton.button, 10,
149 !!event->xbutton.state);
152 else if (event->xany.type == MotionNotify &&
155 gltrackball_track (c->trackball,
156 event->xmotion.x, event->xmotion.y,
157 MI_WIDTH (mi), MI_HEIGHT (mi));
165 /* draw the texture mapped quad (actually two back to back)*/
166 static void showscreen(Screenflip *c, int frozen, int wire)
171 /* r -= 0.02; g -= 0.02; b -= 0.02; */
172 c->show_colors[3] -= 0.02;
173 if (c->show_colors[3] < 0) {
177 } else if (c->show_colors[3] < 0) {
178 c->show_colors[0] = c->show_colors[1] =
179 c->show_colors[2] = c->show_colors[3] = 1;
180 c->stretch_val_x = c->stretch_val_y =
181 c->stretch_val_dx = c->stretch_val_dy = 0;
183 if (c->stretch_val_dx == 0 && !frozen && !(random() % 25))
184 c->stretch_val_dx = (float)(random() % 100) / 5000;
185 if (c->stretch_val_dy == 0 && !frozen && !(random() % 25))
186 c->stretch_val_dy = (float)(random() % 100) / 5000;
194 w *= sin (c->stretch_val_x) + 1;
195 x *= sin (c->stretch_val_x) + 1;
196 if (!c->button_down_p) {
197 if (!c->fadetime) c->stretch_val_x += c->stretch_val_dx;
198 if (c->stretch_val_x > 2*M_PI && !(random() % 5))
199 c->stretch_val_dx = (float)(random() % 100) / 5000;
201 c->stretch_val_x -= 2*M_PI;
204 if (!c->button_down_p && !c->fadetime) c->stretch_val_y += c->stretch_val_dy;
205 h *= sin (c->stretch_val_y) / 2 + 1;
206 y *= sin (c->stretch_val_y) / 2 + 1;
207 if (!c->button_down_p) {
208 if (c->stretch_val_y > 2*M_PI && !(random() % 5))
209 c->stretch_val_dy = (float)(random() % 100) / 5000;
211 c->stretch_val_y -= 2*M_PI;
215 glColor4f(c->show_colors[0], c->show_colors[1],
216 c->show_colors[2], c->show_colors[3]);
220 glEnable(GL_TEXTURE_2D);
222 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
223 glDepthMask(GL_FALSE);
226 glBegin(wire ? GL_LINE_LOOP : GL_QUADS);
229 glTexCoord2f(c->max_tx, c->max_ty); glVertex3f(w, h, 0);
230 glTexCoord2f(c->max_tx, c->min_ty); glVertex3f(w, y, 0);
231 glTexCoord2f(c->min_tx, c->min_ty); glVertex3f(x, y, 0);
232 glTexCoord2f(c->min_tx, c->max_ty); glVertex3f(x, h, 0);
234 glNormal3f(0, 0, -1);
235 glTexCoord2f(c->min_tx, c->min_ty); glVertex3f(x, y, -0.05);
236 glTexCoord2f(c->max_tx, c->min_ty); glVertex3f(w, y, -0.05);
237 glTexCoord2f(c->max_tx, c->max_ty); glVertex3f(w, h, -0.05);
238 glTexCoord2f(c->min_tx, c->max_ty); glVertex3f(x, h, -0.05);
242 glDisable(GL_TEXTURE_2D);
243 glDepthMask(GL_TRUE);
245 glBegin(GL_LINE_LOOP);
255 /* This function is responsible for 'zooming back' the square after
256 * a new chunk has been grabbed with getSnapshot(), and positioning
257 * it suitably on the screen. Once positioned (where we begin to rotate),
258 * it just does a glTranslatef() and returns 1
261 static int inposition(Screenflip *c)
268 if (c->curx == 0) c->curx = c->qx;
269 if (c->cury == 0) c->cury = c->qy;
276 if (c->curz > -10 || c->curx > wx + 0.1 || c->curx < wx - 0.1 ||
277 c->cury > wy + 0.1 || c->cury < wy - 0.1) {
296 glTranslatef(0, 0, c->curz);
299 glTranslatef(0, 0, c->curz);
305 static void drawgrid(void)
309 glColor3f(0, 0.7, 0);
311 for (i = 0 ; i <= 50; i+=2) {
312 glVertex3f( -25, -15, i-70);
313 glVertex3f( 25, -15, i-70);
314 glVertex3f( i-25, -15, -70);
315 glVertex3f( i-25, -15, -20);
322 static void display(Screenflip *c, int wire)
326 glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
328 gluLookAt(viewer[0], viewer[1], viewer[2], 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
333 glTranslatef(5 * sin(c->theta), 5 * sin(c->rho), 10 * cos(c->gamma) - 10);
334 /* randomly change the speed */
335 if (!c->button_down_p && !(random() % 300)) {
337 c->drho = 1/60 - (float)(random() % 100)/3000;
339 c->dtheta = 1/60 - (float)(random() % 100)/3000;
341 c->dgamma = 1/60 - (float)(random() % 100)/3000;
343 gltrackball_rotate (c->trackball);
344 if (rotate) glRotatef(c->rot, c->rx, c->ry, c->rz);
345 /* update variables with each frame */
346 if(!c->button_down_p && !c->fadetime) {
347 c->theta += c->dtheta;
349 c->gamma += c->dgamma;
353 /* dont let our rotation speed get too high */
354 if (c->drot > 5 && c->ddrot > 0)
355 c->ddrot = 0 - (GLfloat)(random() % 100) / 1000;
356 else if (c->drot < -5 && c->ddrot < 0)
357 c->ddrot = (GLfloat)(random() % 100) / 1000;
358 } else { /* reset some paramaters */
359 c->ddrot = 0.05 - (GLfloat)(random() % 100) / 1000;
360 c->theta = c->rho = c->gamma = 0;
364 if (!c->button_down_p && !c->fadetime && (c->rot >= 360 || c->rot <= -360) && !(random() % 7)) { /* rotate change */
365 c->rx = (GLfloat)(random() % 100) / 100;
366 c->ry = (GLfloat)(random() % 100) / 100;
367 c->rz = (GLfloat)(random() % 100) / 100;
369 if (c->odrot * c->drot < 0 && c->tw < c->winw && !(random() % 10)) {
370 c->fadetime = 1; /* randomly fade and get new snapshot */
374 if (c->rot > 360 || c->rot < -360) /* dont overflow rotation! */
376 showscreen(c, frozen, wire);
381 ENTRYPOINT void reshape_screenflip(ModeInfo *mi, int width, int height)
383 Screenflip *c = &screenflip[MI_SCREEN(mi)];
384 glViewport(0,0,(GLint)width, (GLint) height);
385 glMatrixMode(GL_PROJECTION);
387 gluPerspective(45, 1, 2.0, 85);
388 glMatrixMode(GL_MODELVIEW);
394 image_loaded_cb (const char *filename, XRectangle *geometry,
395 int image_width, int image_height,
396 int texture_width, int texture_height,
399 Screenflip *c = (Screenflip *) closure;
401 c->tw = texture_width;
402 c->th = texture_height;
403 c->min_tx = (GLfloat) geometry->x / c->tw;
404 c->min_ty = (GLfloat) geometry->y / c->th;
405 c->max_tx = (GLfloat) (geometry->x + geometry->width) / c->tw;
406 c->max_ty = (GLfloat) (geometry->y + geometry->height) / c->th;
408 c->qx = -QW/2 + ((GLfloat) geometry->x * QW / image_width);
409 c->qy = QH/2 - ((GLfloat) geometry->y * QH / image_height);
410 c->qw = QW * ((GLfloat) geometry->width / image_width);
411 c->qh = QH * ((GLfloat) geometry->height / image_height);
413 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
414 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
415 (c->mipmap_p ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR));
417 if (c->anisotropic >= 1.0)
418 glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT,
421 c->waiting_for_image_p = False;
422 c->first_image_p = False;
426 static void getSnapshot (ModeInfo *modeinfo)
428 Screenflip *c = &screenflip[MI_SCREEN(modeinfo)];
430 if (MI_IS_WIREFRAME(modeinfo))
433 c->waiting_for_image_p = True;
435 load_texture_async (modeinfo->xgwa.screen, modeinfo->window,
436 *c->glx_context, 0, 0, c->mipmap_p, c->texid,
440 ENTRYPOINT void init_screenflip(ModeInfo *mi)
442 int screen = MI_SCREEN(mi);
445 if (screenflip == NULL) {
446 if ((screenflip = (Screenflip *) calloc(MI_NUM_SCREENS(mi),
447 sizeof(Screenflip))) == NULL)
450 c = &screenflip[screen];
451 c->window = MI_WINDOW(mi);
453 c->trackball = gltrackball_init ();
455 if ((c->glx_context = init_GL(mi)) != NULL) {
456 reshape_screenflip(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
460 c->winh = MI_WIN_HEIGHT(mi);
461 c->winw = MI_WIN_WIDTH(mi);
470 c->show_colors[0] = c->show_colors[1] =
471 c->show_colors[2] = c->show_colors[3] = 1;
473 glClearColor(0.0,0.0,0.0,0.0);
475 if (! MI_IS_WIREFRAME(mi))
477 glShadeModel(GL_SMOOTH);
478 glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
479 glEnable(GL_DEPTH_TEST);
480 glEnable(GL_CULL_FACE);
482 glDisable(GL_LIGHTING);
485 if (strstr ((char *) glGetString(GL_EXTENSIONS),
486 "GL_EXT_texture_filter_anisotropic"))
487 glGetFloatv (GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &c->anisotropic);
489 c->anisotropic = 0.0;
491 glGenTextures(1, &c->texid);
493 c->first_image_p = True;
497 ENTRYPOINT void draw_screenflip(ModeInfo *mi)
499 Screenflip *c = &screenflip[MI_SCREEN(mi)];
500 Window w = MI_WINDOW(mi);
501 Display *disp = MI_DISPLAY(mi);
506 /* Wait for the first image; for subsequent images, load them in the
507 background while animating. */
508 if (c->waiting_for_image_p && c->first_image_p)
511 glXMakeCurrent(disp, w, *(c->glx_context));
513 glBindTexture(GL_TEXTURE_2D, c->texid);
518 display(c, MI_IS_WIREFRAME(mi));
520 if(mi->fps_p) do_fps(mi);
522 glXSwapBuffers(disp, w);
525 ENTRYPOINT void release_screenflip(ModeInfo *mi)
527 if (screenflip != NULL) {
528 (void) free((void *) screenflip);
534 XSCREENSAVER_MODULE_2 ("FlipScreen3D", flipscreen3d, screenflip)