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
17 #include <X11/Intrinsic.h>
21 # define PROGCLASS "FlipScreen3D"
22 # define HACK_INIT init_screenflip
23 # define HACK_DRAW draw_screenflip
24 # define HACK_RESHAPE reshape_screenflip
25 # define HACK_HANDLE_EVENT screenflip_handle_event
26 # define EVENT_MASK PointerMotionMask
27 # define screenflip_opts xlockmore_opts
28 /* insert defaults here */
30 #define DEFAULTS "*delay: 20000 \n" \
31 "*showFPS: False \n" \
33 "*wireframe: False \n" \
36 # include "xlockmore.h" /* from the xscreensaver distribution */
37 #else /* !STANDALONE */
38 # include "xlock.h" /* from the xlockmore distribution */
39 #endif /* !STANDALONE */
41 /* lifted from lament.c */
42 #define RAND(n) ((long) ((random() & 0x7fffffff) % ((long) (n))))
43 #define RANDSIGN() ((random() & 1) ? 1 : -1)
53 int tw, th; /* texture width, height */
55 GLfloat min_tx, min_ty;
56 GLfloat max_tx, max_ty;
60 GLfloat qw = QW, qh = QH; /* q? are for the quad we'll draw */
61 GLfloat qx = -6 , qy = 6;
64 #define countof(x) (sizeof((x))/sizeof((*x)))
67 static XrmOptionDescRec opts[] = {
68 {"+rotate", ".screenflip.rotate", XrmoptionNoArg, "false" },
69 {"-rotate", ".screenflip.rotate", XrmoptionNoArg, "true" },
73 static argtype vars[] = {
74 {&rotate, "rotate", "Rotate", "True", t_Bool},
79 ModeSpecOpt screenflip_opts = {countof(opts), opts, countof(vars), vars, NULL};
83 ModStruct screenflip_description =
84 {"screenflip", "init_screenflip", "draw_screenflip", "release_screenflip",
85 "draw_screenflip", "init_screenflip", NULL, &screenflip_opts,
86 1000, 1, 2, 1, 4, 1.0, "",
87 "Screenflips", 0, NULL};
93 GLXContext *glx_context;
97 static Screenflip *screenflip = NULL;
100 #include <sys/time.h>
103 #include "grab-ximage.h"
104 #include "gltrackball.h"
107 #define M_PI 3.14159265
110 static GLfloat viewer[] = {0.0, 0.0, 15.0};
113 int fadetime = 0; /* fade before regrab */
115 static trackball_state *trackball;
116 static Bool button_down_p = False;
120 screenflip_handle_event (ModeInfo *mi, XEvent *event)
122 if (event->xany.type == ButtonPress &&
123 event->xbutton.button == Button1)
125 button_down_p = True;
126 gltrackball_start (trackball,
127 event->xbutton.x, event->xbutton.y,
128 MI_WIDTH (mi), MI_HEIGHT (mi));
131 else if (event->xany.type == ButtonRelease &&
132 event->xbutton.button == Button1)
134 button_down_p = False;
137 else if (event->xany.type == ButtonPress &&
138 (event->xbutton.button == Button4 ||
139 event->xbutton.button == Button5))
141 gltrackball_mousewheel (trackball, event->xbutton.button, 10,
142 !!event->xbutton.state);
145 else if (event->xany.type == MotionNotify &&
148 gltrackball_track (trackball,
149 event->xmotion.x, event->xmotion.y,
150 MI_WIDTH (mi), MI_HEIGHT (mi));
158 /* draw the texture mapped quad (actually two back to back)*/
159 void showscreen(int frozen, int wire)
161 static GLfloat r = 1, g = 1, b = 1, a = 1;
163 /* static int stretch; */
164 static GLfloat stretch_val_x = 0, stretch_val_y = 0;
165 static GLfloat stretch_val_dx = 0, stretch_val_dy = 0;
166 /* static int stretch_x = 0, stretch_y = 0; */
169 /* r -= 0.02; g -= 0.02; b -= 0.02; */
177 stretch_val_x = stretch_val_y = stretch_val_dx = stretch_val_dy = 0;
179 if (stretch_val_dx == 0 && !frozen && !(random() % 25))
180 stretch_val_dx = (float)(random() % 100) / 5000;
181 if (stretch_val_dy == 0 && !frozen && !(random() % 25))
182 stretch_val_dy = (float)(random() % 100) / 5000;
190 w *= sin (stretch_val_x) + 1;
191 x *= sin (stretch_val_x) + 1;
192 if (!button_down_p) {
193 if (!fadetime) stretch_val_x += stretch_val_dx;
194 if (stretch_val_x > 2*M_PI && !(random() % 5))
195 stretch_val_dx = (float)(random() % 100) / 5000;
197 stretch_val_x -= 2*M_PI;
200 if (!button_down_p && !fadetime) stretch_val_y += stretch_val_dy;
201 h *= sin (stretch_val_y) / 2 + 1;
202 y *= sin (stretch_val_y) / 2 + 1;
203 if (!button_down_p) {
204 if (stretch_val_y > 2*M_PI && !(random() % 5))
205 stretch_val_dy = (float)(random() % 100) / 5000;
207 stretch_val_y -= 2*M_PI;
211 glColor4f(r, g, b, a);
215 glEnable(GL_TEXTURE_2D);
217 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
218 glDepthMask(GL_FALSE);
221 glBegin(wire ? GL_LINE_LOOP : GL_QUADS);
224 glTexCoord2f(max_tx, max_ty); glVertex3f(w, h, 0);
225 glTexCoord2f(max_tx, min_ty); glVertex3f(w, y, 0);
226 glTexCoord2f(min_tx, min_ty); glVertex3f(x, y, 0);
227 glTexCoord2f(min_tx, max_ty); glVertex3f(x, h, 0);
229 glNormal3f(0, 0, -1);
230 glTexCoord2f(min_tx, min_ty); glVertex3f(x, y, -0.05);
231 glTexCoord2f(max_tx, min_ty); glVertex3f(w, y, -0.05);
232 glTexCoord2f(max_tx, max_ty); glVertex3f(w, h, -0.05);
233 glTexCoord2f(min_tx, max_ty); glVertex3f(x, h, -0.05);
237 glDisable(GL_TEXTURE_2D);
238 glDepthMask(GL_TRUE);
240 glBegin(GL_LINE_LOOP);
250 /* This function is responsible for 'zooming back' the square after
251 * a new chunk has been grabbed with getSnapshot(), and positioning
252 * it suitably on the screen. Once positioned (where we begin to rotate),
253 * it just does a glTranslatef() and returns 1
258 static GLfloat curx, cury, curz = 0;
264 if (curx == 0) curx = qx;
265 if (cury == 0) cury = qy;
272 if (curz > -10 || curx > wx + 0.1 || curx < wx - 0.1 ||
273 cury > wy + 0.1 || cury < wy - 0.1) {
292 glTranslatef(0, 0, curz);
295 glTranslatef(0, 0, curz);
304 glColor3f(0, 0.7, 0);
306 for (i = 0 ; i <= 50; i+=2) {
307 glVertex3f( -25, -15, i-70);
308 glVertex3f( 25, -15, i-70);
309 glVertex3f( i-25, -15, -70);
310 glVertex3f( i-25, -15, -20);
315 void display(int wire)
317 static GLfloat rx=1, ry=1, rz=0;
318 static GLfloat rot = 0;
319 static GLfloat drot = 0;
320 static GLfloat odrot = 1;
321 static GLfloat ddrot = 0;
322 static float theta = 0, rho = 0, dtheta = 0, drho = 0, gamma = 0, dgamma = 0;
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(theta), 5 * sin(rho), 10 * cos(gamma) - 10);
334 /* randomly change the speed */
335 if (!button_down_p && !(random() % 300)) {
337 drho = 1/60 - (float)(random() % 100)/3000;
339 dtheta = 1/60 - (float)(random() % 100)/3000;
341 dgamma = 1/60 - (float)(random() % 100)/3000;
343 gltrackball_rotate (trackball);
344 if (rotate) glRotatef(rot, rx, ry, rz);
345 /* update variables with each frame */
346 if(!button_down_p && !fadetime) {
353 /* dont let our rotation speed get too high */
354 if (drot > 5 && ddrot > 0)
355 ddrot = 0 - (GLfloat)(random() % 100) / 1000;
356 else if (drot < -5 && ddrot < 0)
357 ddrot = (GLfloat)(random() % 100) / 1000;
358 } else { /* reset some paramaters */
359 ddrot = 0.05 - (GLfloat)(random() % 100) / 1000;
360 theta = rho = gamma = 0;
364 if (!button_down_p && !fadetime && (rot >= 360 || rot <= -360) && !(random() % 7)) { /* rotate change */
365 rx = (GLfloat)(random() % 100) / 100;
366 ry = (GLfloat)(random() % 100) / 100;
367 rz = (GLfloat)(random() % 100) / 100;
369 if (odrot * drot < 0 && tw < winw && !(random() % 10)) {
370 fadetime = 1; /* randomly fade and get new snapshot */
374 if (rot > 360 || rot < -360) /* dont overflow rotation! */
376 showscreen(frozen, wire);
381 void reshape_screenflip(ModeInfo *mi, int width, int height)
383 glViewport(0,0,(GLint)width, (GLint) height);
384 glMatrixMode(GL_PROJECTION);
386 gluPerspective(45, 1, 2.0, 85);
387 glMatrixMode(GL_MODELVIEW);
392 void getSnapshot (ModeInfo *modeinfo)
394 Bool mipmap_p = True;
398 if (MI_IS_WIREFRAME(modeinfo))
401 if (! screen_to_texture (modeinfo->xgwa.screen, modeinfo->window, 0, 0,
402 mipmap_p, NULL, &geom, &iw, &ih, &tw, &th))
405 min_tx = (GLfloat) geom.x / tw;
406 min_ty = (GLfloat) geom.y / th;
407 max_tx = (GLfloat) (geom.x + geom.width) / tw;
408 max_ty = (GLfloat) (geom.y + geom.height) / th;
410 qx = -QW/2 + ((GLfloat) geom.x * QW / iw);
411 qy = QH/2 - ((GLfloat) geom.y * QH / ih);
412 qw = QW * ((GLfloat) geom.width / iw);
413 qh = QH * ((GLfloat) geom.height / ih);
415 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
416 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
417 (mipmap_p ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR));
420 void init_screenflip(ModeInfo *mi)
422 int screen = MI_SCREEN(mi);
425 if (screenflip == NULL) {
426 if ((screenflip = (Screenflip *) calloc(MI_NUM_SCREENS(mi),
427 sizeof(Screenflip))) == NULL)
430 c = &screenflip[screen];
431 c->window = MI_WINDOW(mi);
433 trackball = gltrackball_init ();
435 if ((c->glx_context = init_GL(mi)) != NULL) {
436 reshape_screenflip(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
440 winh = MI_WIN_HEIGHT(mi);
441 winw = MI_WIN_WIDTH(mi);
442 glClearColor(0.0,0.0,0.0,0.0);
444 if (! MI_IS_WIREFRAME(mi))
446 glShadeModel(GL_SMOOTH);
447 glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
448 glEnable(GL_DEPTH_TEST);
449 glEnable(GL_CULL_FACE);
451 glDisable(GL_LIGHTING);
457 void draw_screenflip(ModeInfo *mi)
459 Screenflip *c = &screenflip[MI_SCREEN(mi)];
460 Window w = MI_WINDOW(mi);
461 Display *disp = MI_DISPLAY(mi);
466 glXMakeCurrent(disp, w, *(c->glx_context));
471 display(MI_IS_WIREFRAME(mi));
473 if(mi->fps_p) do_fps(mi);
475 glXSwapBuffers(disp, w);
478 void release_screenflip(ModeInfo *mi)
480 if (screenflip != NULL) {
481 (void) free((void *) screenflip);