http://www.jwz.org/xscreensaver/xscreensaver-5.13.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 ();
98   bp->st = init_view(MI_IS_WIREFRAME(mi), transparent_p);
99   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   gltrackball_rotate (bp->trackball);
115   win_draw(bp->st);
116   if (! bp->button_down_p)
117     move_increment(bp->st);
118   glPopMatrix ();
119
120   mi->polygon_count = NUM_ELS;
121   if (mi->fps_p) do_fps (mi);
122   glFinish();
123
124   glXSwapBuffers(MI_DISPLAY (mi), MI_WINDOW(mi));
125 }
126
127 ENTRYPOINT void
128 release_stonerview (ModeInfo *mi)
129 {
130   if (bps) {
131     int screen;
132     for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
133       stonerview_configuration *bp = &bps[screen];
134       if (bp->st)
135         win_release (bp->st);
136     }
137     free (bps);
138     bps = 0;
139   }
140   FreeAllGL(mi);
141 }
142
143 ENTRYPOINT Bool
144 stonerview_handle_event (ModeInfo *mi, XEvent *event)
145 {
146   stonerview_configuration *bp = &bps[MI_SCREEN(mi)];
147
148   if (event->xany.type == ButtonPress &&
149       event->xbutton.button == Button1)
150     {
151       bp->button_down_p = True;
152       gltrackball_start (bp->trackball,
153                          event->xbutton.x, event->xbutton.y,
154                          MI_WIDTH (mi), MI_HEIGHT (mi));
155       return True;
156     }
157   else if (event->xany.type == ButtonRelease &&
158            event->xbutton.button == Button1)
159     {
160       bp->button_down_p = False;
161       return True;
162     }
163   else if (event->xany.type == ButtonPress &&
164            (event->xbutton.button == Button4 ||
165             event->xbutton.button == Button5 ||
166             event->xbutton.button == Button6 ||
167             event->xbutton.button == Button7))
168     {
169       gltrackball_mousewheel (bp->trackball, event->xbutton.button, 10,
170                               !!event->xbutton.state);
171       return True;
172     }
173   else if (event->xany.type == MotionNotify &&
174            bp->button_down_p)
175     {
176       gltrackball_track (bp->trackball,
177                          event->xmotion.x, event->xmotion.y,
178                          MI_WIDTH (mi), MI_HEIGHT (mi));
179       return True;
180     }
181
182   return False;
183 }
184
185 XSCREENSAVER_MODULE ("StonerView", stonerview)
186
187 #endif /* USE_GL */