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