http://packetstormsecurity.org/UNIX/admin/xscreensaver-4.01.tar.gz
[xscreensaver] / hacks / glx / flipscreen3d.c
1 /*
2  * screenflip - takes snapshots of the screen and flips it around
3  *
4  * version 1.0 - Oct 24, 2001
5  *
6  * Copyright (C) 2001 Ben Buxton (bb@cactii.net)
7  *
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
14  * implied warranty.
15  */
16
17 #include <X11/Intrinsic.h>
18
19
20 #ifdef STANDALONE
21 # define PROGCLASS                                      "Screenflip"
22 # define HACK_INIT                                      init_screenflip
23 # define HACK_DRAW                                      draw_screenflip
24 # define HACK_RESHAPE                           reshape_screenflip
25 # define screenflip_opts                                     xlockmore_opts
26 /* insert defaults here */
27
28 #define DEFAULTS       "*delay:       20000       \n" \
29                         "*showFPS:       False       \n" \
30                         "*rotate:       True       \n" \
31                         "*wireframe:    False   \n"     \
32
33 # include "xlockmore.h"                         /* from the xscreensaver distribution */
34 #else  /* !STANDALONE */
35 # include "xlock.h"                                     /* from the xlockmore distribution */
36 #endif /* !STANDALONE */
37
38 /* lifted from lament.c */
39 #define RAND(n) ((long) ((random() & 0x7fffffff) % ((long) (n))))
40 #define RANDSIGN() ((random() & 1) ? 1 : -1)
41
42
43 #ifdef USE_GL
44
45 #include <GL/glu.h>
46
47 int rotate;
48
49 int winw, winh;
50 int tw, th; /* texture width, height */
51 int tx, ty;
52 GLfloat max_tx, max_ty;
53
54 #define QW 12
55 #define QH 12
56 GLfloat qw = QW, qh = QH; /* q? are for the quad we'll draw */
57 GLfloat qx = -6 , qy = 6;
58
59 #undef countof
60 #define countof(x) (sizeof((x))/sizeof((*x)))
61
62
63 static XrmOptionDescRec opts[] = {
64   {"+rotate", ".screenflip.rotate", XrmoptionNoArg, (caddr_t) "false" },
65   {"-rotate", ".screenflip.rotate", XrmoptionNoArg, (caddr_t) "true" },
66 };
67
68
69 static argtype vars[] = {
70   {(caddr_t *) &rotate, "rotate", "Rotate", "True", t_Bool},
71 };
72
73
74
75 ModeSpecOpt screenflip_opts = {countof(opts), opts, countof(vars), vars, NULL};
76
77
78 #ifdef USE_MODULES
79 ModStruct   screenflip_description =
80 {"screenflip", "init_screenflip", "draw_screenflip", "release_screenflip",
81  "draw_screenflip", "init_screenflip", NULL, &screenflip_opts,
82  1000, 1, 2, 1, 4, 1.0, "",
83  "Screenflips", 0, NULL};
84
85 #endif
86
87
88 typedef struct {
89   GLXContext *glx_context;
90   Window window;
91 } Screenflip;
92
93 static Screenflip *screenflip = NULL;
94
95 #include <math.h>
96 #include <sys/time.h>
97 #include <stdio.h>
98 #include <stdlib.h>
99 #include "grab-ximage.h"
100
101 #ifndef M_PI
102 #define M_PI 3.14159265
103 #endif
104
105 static GLfloat viewer[] = {0.0, 0.0, 15.0};
106
107 int regrab = 0;
108 int fadetime = 0; /* fade before regrab */
109
110
111 /* draw the texture mapped quad (actually two back to back)*/
112 void showscreen(int frozen, int wire)
113 {
114   static GLfloat r = 1, g = 1, b = 1, a = 1;
115   GLfloat qxw, qyh;
116   GLfloat x, y, w, h;
117   /* static int stretch; */
118   static GLfloat stretch_val_x = 0, stretch_val_y = 0;
119   static GLfloat stretch_val_dx = 0, stretch_val_dy = 0;
120   /* static int stretch_x = 0, stretch_y = 0; */
121
122   if (fadetime) {
123 /*    r -= 0.02; g -= 0.02; b -= 0.02; */
124     a -= 0.02;
125     if (a < 0) {
126       regrab = 1;
127       fadetime = 0;
128     }
129   } else if (a < 0) {
130     r = g = b = a = 1;
131     stretch_val_x = stretch_val_y = stretch_val_dx = stretch_val_dy = 0;
132   }
133   if (stretch_val_dx == 0 && !frozen && !(random() % 25))
134     stretch_val_dx = (float)(random() % 100) / 5000;
135   if (stretch_val_dy == 0 && !frozen && !(random() % 25))
136     stretch_val_dy = (float)(random() % 100) / 5000;
137     
138   qxw = qx+qw;
139   qyh = qy-qh;
140   x = qx; y = qy;
141   w = qxw; h = qyh;
142
143   if (!frozen) {
144      w *= sin (stretch_val_x) + 1;
145      x *= sin (stretch_val_x) + 1;
146      if (!fadetime) stretch_val_x += stretch_val_dx;
147      if (stretch_val_x > 2*M_PI && !(random() % 5))
148        stretch_val_dx = (float)(random() % 100) / 5000;
149      else
150        stretch_val_x -= 2*M_PI;
151
152      if (!fadetime) stretch_val_y += stretch_val_dy;
153      h *= sin (stretch_val_y) / 2 + 1;
154      y *= sin (stretch_val_y) / 2 + 1;
155      if (stretch_val_y > 2*M_PI && !(random() % 5))
156        stretch_val_dy = (float)(random() % 100) / 5000;
157      else
158        stretch_val_y -= 2*M_PI;
159   }
160
161   glColor4f(r, g, b, a);
162
163   if (!wire)
164     {
165       glEnable(GL_TEXTURE_2D);
166       glEnable(GL_BLEND);
167       glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
168       glDepthMask(GL_FALSE);
169     }
170
171   glBegin(wire ? GL_LINE_LOOP : GL_QUADS);
172
173   glNormal3f(0, 0, 1);
174
175   glTexCoord2f(0, max_ty);
176   glVertex3f(x, y, 0);
177
178   glTexCoord2f(max_tx, max_ty);
179   glVertex3f(w, y, 0);
180
181   glTexCoord2f(max_tx, 0);
182   glVertex3f(w, h, 0);
183
184   glTexCoord2f(0, 0);
185   glVertex3f(x, h, 0);
186
187   glNormal3f(0, 0, -1);
188
189   glTexCoord2f(0, max_ty);
190   glVertex3f(x, y, -0.05);
191
192   glTexCoord2f(0, 0);
193   glVertex3f(x, h, -0.05);
194
195   glTexCoord2f(max_tx, 0);
196   glVertex3f(w, h, -0.05);
197
198   glTexCoord2f(max_tx, max_ty);
199   glVertex3f(w, y, -0.05);
200
201   glEnd();
202
203
204   glDisable(GL_TEXTURE_2D);
205   glDepthMask(GL_TRUE);
206
207   glBegin(GL_LINE_LOOP);
208    glVertex3f(x, y, 0);
209    glVertex3f(x, h, 0);
210    glVertex3f(w, h, 0);
211    glVertex3f(w, y, 0);
212  glEnd();
213   glDisable(GL_BLEND);
214
215 }
216
217 /* This function is responsible for 'zooming back' the square after
218  * a new chunk has been grabbed with getSnapshot(), and positioning
219  * it suitably on the screen. Once positioned (where we begin to rotate),
220  * it just does a glTranslatef() and returns 1
221  */
222
223 int inposition(void)
224 {
225   static GLfloat curx, cury, curz = 0;
226   GLfloat wx;
227   GLfloat wy;
228   wx = 0 - (qw/2);
229   wy = (qh/2);
230
231   if (curx == 0) curx = qx;
232   if (cury == 0) cury = qy;
233   if (regrab) {
234      curz = 0;
235      curx = qx;
236      cury = qy;
237      regrab = 0;
238   }
239   if (curz > -10 || curx > wx + 0.1 || curx < wx - 0.1 ||
240          cury > wy + 0.1 || cury < wy - 0.1) {
241     if (curz > -10)
242       curz -= 0.05;
243     if (curx > wx) {
244        qx -= 0.02;
245        curx -= 0.02;
246     }
247     if (curx < wx) {
248        qx += 0.02;
249        curx += 0.02;
250     }
251     if (cury > wy) {
252        qy -= 0.02;
253        cury -= 0.02;
254     }
255     if (cury < wy) {
256        qy += 0.02;
257        cury += 0.02;
258     }
259     glTranslatef(0, 0, curz);
260     return 0;
261   }
262   glTranslatef(0, 0, curz);
263   return 1;
264
265 }
266
267 void drawgrid(void)
268 {
269   int i;
270
271   glColor3f(0, 0.7, 0);
272   glBegin(GL_LINES);
273   for (i = 0 ; i <= 50; i+=2) {
274       glVertex3f( -25, -15, i-70);
275       glVertex3f( 25, -15, i-70);
276       glVertex3f( i-25, -15, -70);
277       glVertex3f( i-25, -15, -20);
278   }
279   glEnd();
280 }
281
282 void display(int wire)
283 {
284   static GLfloat rx=1, ry=1, rz=0;
285   static GLfloat rot = 0;
286   static GLfloat drot = 0;
287   static GLfloat odrot = 1;
288   static GLfloat ddrot = 0;
289   static float theta = 0, rho = 0, dtheta = 0, drho = 0, gamma = 0, dgamma = 0;
290   static GLfloat orot;
291   int frozen;
292
293   glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
294   glLoadIdentity();
295   gluLookAt(viewer[0], viewer[1], viewer[2], 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
296   glPushMatrix();
297
298   if (inposition()) {
299     frozen = 0;
300     glTranslatef(5 * sin(theta), 5 * sin(rho), 10 * cos(gamma) - 10);
301 /* randomly change the speed */
302     if (!(random() % 300)) {
303       if (random() % 2)
304         drho = 1/60 - (float)(random() % 100)/3000;
305       if (random() % 2)
306         dtheta = 1/60 - (float)(random() % 100)/3000;
307       if (random() % 2)
308         dgamma = 1/60 - (float)(random() % 100)/3000;
309     }
310     if (rotate) glRotatef(rot, rx, ry, rz);
311 /* update variables with each frame */
312     if (!fadetime) {
313       theta += dtheta;
314       rho += drho;
315       gamma += dgamma;
316       rot += drot;
317       drot += ddrot;
318     }
319 /* dont let our rotation speed get too high */
320     if (drot > 5 && ddrot > 0)
321         ddrot = 0 - (GLfloat)(random() % 100) / 1000;
322     else if (drot < -5 && ddrot < 0)
323         ddrot = (GLfloat)(random() % 100) / 1000;
324   } else { /* reset some paramaters */
325     ddrot = 0.05 - (GLfloat)(random() % 100) / 1000;
326     theta = rho = gamma = 0;
327     rot = 0;
328     frozen = 1;
329   }
330   if (!fadetime && (rot >= 360 || rot <= -360) && !(random() % 7)) { /* rotate  change */
331     rx = (GLfloat)(random() % 100) / 100;
332     ry = (GLfloat)(random() % 100) / 100;
333     rz = (GLfloat)(random() % 100) / 100;
334   }
335   if (odrot * drot < 0 && tw < winw && !(random() % 10)) {
336     fadetime = 1;                /* randomly fade and get new snapshot */
337   }
338   orot = rot;
339   odrot = drot;
340   if (rot > 360 || rot < -360) /* dont overflow rotation! */
341     rot -= rot;
342   showscreen(frozen, wire);
343   glPopMatrix();
344   glFlush();
345 }
346
347 void reshape_screenflip(ModeInfo *mi, int width, int height)
348 {
349  glViewport(0,0,(GLint)width, (GLint) height);
350  glMatrixMode(GL_PROJECTION);
351  glLoadIdentity();
352  gluPerspective(45, 1, 2.0, 85);
353  glMatrixMode(GL_MODELVIEW);
354  winw = width;
355  winh = height;
356 }
357
358 void getSnapshot (ModeInfo *modeinfo)
359 {
360   XImage *ximage;
361   int status;
362
363   if (MI_IS_WIREFRAME(modeinfo))
364     return;
365
366  ximage = screen_to_ximage (modeinfo->xgwa.screen, modeinfo->window);
367
368   qw = QW; qh = QH;
369   tw = modeinfo->xgwa.width;
370   th = modeinfo->xgwa.height;
371
372 #if 0  /* jwz: this makes the image start off the bottom right of the screen */
373   qx += (qw*tw/winw);
374   qy -= (qh*th/winh);
375 #endif
376
377   qw *= (GLfloat)tw/winw;
378   qh *= (GLfloat)th/winh;
379
380   max_tx = (GLfloat) tw / (GLfloat) ximage->width;
381   max_ty = (GLfloat) th / (GLfloat) ximage->height;
382
383
384  glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
385  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
386                   GL_LINEAR_MIPMAP_LINEAR);
387
388  clear_gl_error();
389  status = gluBuild2DMipmaps(GL_TEXTURE_2D, 3,
390                             ximage->width, ximage->height,
391                             GL_RGBA, GL_UNSIGNED_BYTE, ximage->data);
392  if (status)
393    {
394      const char *s = gluErrorString (status);
395      fprintf (stderr, "%s: error mipmapping %dx%d texture: %s\n",
396               progname, ximage->width, ximage->height,
397               (s ? s : "(unknown)"));
398      fprintf (stderr, "%s: turning on -wireframe.\n", progname);
399      MI_IS_WIREFRAME(modeinfo) = 1;
400      clear_gl_error();
401    }
402  check_gl_error("mipmapping");  /* should get a return code instead of a
403                                    GL error, but just in case... */
404
405  free(ximage->data);
406  ximage->data = 0;
407  XDestroyImage (ximage);
408 }
409
410 void init_screenflip(ModeInfo *mi)
411 {
412   int screen = MI_SCREEN(mi);
413   Screenflip *c;
414
415  if (screenflip == NULL) {
416    if ((screenflip = (Screenflip *) calloc(MI_NUM_SCREENS(mi),
417                                         sizeof(Screenflip))) == NULL)
418           return;
419  }
420  c = &screenflip[screen];
421  c->window = MI_WINDOW(mi);
422
423  if ((c->glx_context = init_GL(mi)) != NULL) {
424       reshape_screenflip(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
425  } else {
426      MI_CLEARWINDOW(mi);
427  }
428  winh = MI_WIN_HEIGHT(mi);
429  winw = MI_WIN_WIDTH(mi);
430  glClearColor(0.0,0.0,0.0,0.0);
431
432  if (! MI_IS_WIREFRAME(mi))
433    {
434      glShadeModel(GL_SMOOTH);
435      glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
436      glEnable(GL_DEPTH_TEST);
437      glEnable(GL_CULL_FACE);
438      glCullFace(GL_FRONT);
439      glDisable(GL_LIGHTING);
440    }
441
442  getSnapshot(mi);
443 }
444
445 void draw_screenflip(ModeInfo *mi)
446 {
447   Screenflip *c = &screenflip[MI_SCREEN(mi)];
448   Window w = MI_WINDOW(mi);
449   Display *disp = MI_DISPLAY(mi);
450
451   if (!c->glx_context)
452       return;
453
454  glXMakeCurrent(disp, w, *(c->glx_context));
455
456   if (regrab)
457     getSnapshot(mi);
458
459   display(MI_IS_WIREFRAME(mi));
460
461   if(mi->fps_p) do_fps(mi);
462   glFinish(); 
463   glXSwapBuffers(disp, w);
464 }
465
466 void release_screenflip(ModeInfo *mi)
467 {
468   if (screenflip != NULL) {
469    (void) free((void *) screenflip);
470    screenflip = NULL;
471   }
472   FreeAllGL(MI);
473 }
474
475 #endif