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