From http://www.jwz.org/xscreensaver/xscreensaver-5.35.tar.gz
[xscreensaver] / hacks / glx / stonerview.c
1 /* StonerView: An eccentric visual toy.
2    Copyright 1998-2001 by Andrew Plotkin (erkyrath@eblong.com)
3
4    For the latest version, source code, and links to more of my stuff, see:
5    http://www.eblong.com/zarf/stonerview.html
6
7    Permission to use, copy, modify, distribute, and sell this software and its
8    documentation for any purpose is hereby granted without fee, provided that
9    the above copyright notice appear in all copies and that both that
10    copyright notice and this permission notice appear in supporting
11    documentation.  No representations are made about the suitability of this
12    software for any purpose.  It is provided "as is" without express or 
13    implied warranty.
14 */
15
16 /* Ported away from GLUT (so that it can do `-root' and work with xscreensaver)
17    by Jamie Zawinski <jwz@jwz.org>, 22-Jan-2001.
18
19    Revamped to work in the xlockmore framework so that it will also work
20    with the MacOS X port of xscreensaver by jwz, 21-Feb-2006.
21  */
22
23 #define DEFAULTS        "*delay:        20000       \n" \
24                         "*showFPS:      False       \n" \
25                         "*wireframe:    False       \n"
26
27 # define refresh_stonerview 0
28 #undef countof
29 #define countof(x) (sizeof((x))/sizeof((*x)))
30
31 #include "xlockmore.h"
32
33 #ifdef USE_GL /* whole file */
34
35 #include "stonerview.h"
36 #include "gltrackball.h"
37
38 #define DEF_TRANSPARENT "True"
39
40 typedef struct {
41   GLXContext *glx_context;
42   stonerview_state *st;
43   trackball_state *trackball;
44   Bool button_down_p;
45 } stonerview_configuration;
46
47 static stonerview_configuration *bps = NULL;
48
49 static Bool transparent_p;
50
51
52 static XrmOptionDescRec opts[] = {
53   { "-transparent",   ".transparent",   XrmoptionNoArg, "True" },
54   { "+transparent",   ".transparent",   XrmoptionNoArg, "False" },
55 };
56
57 static argtype vars[] = {
58   {&transparent_p, "transparent", "Transparent", DEF_TRANSPARENT, t_Bool},
59 };
60
61 ENTRYPOINT ModeSpecOpt stonerview_opts = {countof(opts), opts, countof(vars), vars, NULL};
62
63
64 ENTRYPOINT void
65 reshape_stonerview (ModeInfo *mi, int width, int height)
66 {
67   GLfloat h = (GLfloat) height / (GLfloat) width;
68
69   glViewport(0, 0, (GLint) width, (GLint) height);
70   glMatrixMode(GL_PROJECTION);
71   glLoadIdentity();
72   glFrustum(-1.0, 1.0, -h, h, 5.0, 60.0);
73   glMatrixMode(GL_MODELVIEW);
74   glLoadIdentity();
75   glTranslatef(0.0, 0.0, -40.0);
76 }
77
78
79 ENTRYPOINT void 
80 init_stonerview (ModeInfo *mi)
81 {
82   stonerview_configuration *bp;
83
84   if (!bps) {
85     bps = (stonerview_configuration *)
86       calloc (MI_NUM_SCREENS(mi), sizeof (stonerview_configuration));
87     if (!bps) {
88       fprintf(stderr, "%s: out of memory\n", progname);
89       exit(1);
90     }
91   }
92
93   bp = &bps[MI_SCREEN(mi)];
94
95   bp->glx_context = init_GL(mi);
96
97   bp->trackball = gltrackball_init (False);
98   bp->st = stonerview_init_view(MI_IS_WIREFRAME(mi), transparent_p);
99   stonerview_init_move(bp->st);
100
101   reshape_stonerview (mi, MI_WIDTH(mi), MI_HEIGHT(mi));
102   clear_gl_error(); /* WTF? sometimes "invalid op" from glViewport! */
103 }
104
105
106 ENTRYPOINT void
107 draw_stonerview (ModeInfo *mi)
108 {
109   stonerview_configuration *bp = &bps[MI_SCREEN(mi)];
110
111   glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(bp->glx_context));
112
113   glPushMatrix ();
114   glRotatef( current_device_rotation(), 0, 0, 1);
115   gltrackball_rotate (bp->trackball);
116
117 # ifdef HAVE_MOBILE     /* Keep it the same relative size when rotated. */
118   {
119     GLfloat h = MI_HEIGHT(mi) / (GLfloat) MI_WIDTH(mi);
120     int o = (int) current_device_rotation();
121     if (o != 0 && o != 180 && o != -180)
122       glScalef (h, h, h);
123   }
124 # endif
125
126   stonerview_win_draw(bp->st);
127   if (! bp->button_down_p)
128     stonerview_move_increment(bp->st);
129   glPopMatrix ();
130
131   mi->polygon_count = NUM_ELS;
132   if (mi->fps_p) do_fps (mi);
133   glFinish();
134
135   glXSwapBuffers(MI_DISPLAY (mi), MI_WINDOW(mi));
136 }
137
138 ENTRYPOINT void
139 release_stonerview (ModeInfo *mi)
140 {
141   if (bps) {
142     int screen;
143     for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
144       stonerview_configuration *bp = &bps[screen];
145       if (bp->st)
146         stonerview_win_release (bp->st);
147     }
148     free (bps);
149     bps = 0;
150   }
151   FreeAllGL(mi);
152 }
153
154 ENTRYPOINT Bool
155 stonerview_handle_event (ModeInfo *mi, XEvent *event)
156 {
157   stonerview_configuration *bp = &bps[MI_SCREEN(mi)];
158
159   if (gltrackball_event_handler (event, bp->trackball,
160                                  MI_WIDTH (mi), MI_HEIGHT (mi),
161                                  &bp->button_down_p))
162     return True;
163
164   return False;
165 }
166
167 XSCREENSAVER_MODULE ("StonerView", stonerview)
168
169 #endif /* USE_GL */