From http://www.jwz.org/xscreensaver/xscreensaver-5.37.tar.gz
[xscreensaver] / hacks / glx / cubicgrid.c
1 /*-
2  * Permission to use, copy, modify, and distribute this software and its
3  * documentation for any purpose and without fee is hereby granted,
4  * provided that the above copyright notice appear in all copies and that
5  * both that copyright notice and this permission notice appear in
6  * supporting documentation.
7  *
8  * This file is provided AS IS with no warranties of any kind.  The author
9  * shall have no liability with respect to the infringement of copyrights,
10  * trade secrets or any patents by this file or any part thereof.  In no
11  * event will the author be liable for any lost revenue or profits or
12  * other special, indirect and consequential damages.
13  *
14  * Cubic Grid - a 3D lattice. The observer is located in the centre of 
15  * a spinning finite lattice. As it rotates, various view-throughs appear and 
16  * evolve. A simple idea with interesting results.
17  * 
18  * Vasek Potocek (Dec-28-2007)
19  * vasek.potocek@post.cz
20  */
21
22 #define DEFAULTS   "*delay:         20000         \n" \
23                    "*showFPS:       False         \n" \
24                    "*wireframe:     False         \n" \
25                    "*suppressRotationAnimation: True\n" \
26
27 # define refresh_cubicgrid 0
28 # define release_cubicgrid 0
29 #include "xlockmore.h"
30
31 #ifdef USE_GL
32
33 #define DEF_SPEED   "1.0"
34 #define DEF_DIV     "30"
35 #define DEF_ZOOM    "20"
36 #define DEF_BIGDOTS "True"
37
38 #undef countof
39 #define countof(x) (sizeof((x))/sizeof((*x)))
40
41 #include "rotator.h"
42 #include "gltrackball.h"
43
44 /*************************************************************************/
45
46 static int ticks;
47 static float size;
48 static float speed;
49 static Bool bigdots;
50
51 static argtype vars[] = {
52   { &speed,   "speed",   "Speed",   DEF_SPEED,   t_Float },
53   { &size,    "zoom",    "Zoom",    DEF_ZOOM,    t_Float },
54   { &ticks,   "ticks",   "Ticks",   DEF_DIV,     t_Int },
55   { &bigdots, "bigdots", "BigDots", DEF_BIGDOTS, t_Bool },
56 };
57
58 static XrmOptionDescRec opts[] = {
59   { "-speed",   ".speed",   XrmoptionSepArg, 0 },
60   { "-zoom",    ".zoom",    XrmoptionSepArg, 0 },
61   { "-ticks",   ".ticks",   XrmoptionSepArg, 0 },
62   { "-bigdots", ".bigdots", XrmoptionNoArg,  "True" },
63   { "+bigdots", ".bigdots", XrmoptionNoArg,  "False" },
64 };
65
66 ENTRYPOINT ModeSpecOpt cubicgrid_opts = {countof(opts), opts, countof(vars), vars, NULL};
67
68 #ifdef USE_MODULES
69 ModStruct   cubicgrid_description =
70 { "cubicgrid", "init_cubicgrid", "draw_cubicgrid", NULL,
71   "draw_cubicgrid", "change_cubicgrid", NULL, &cubicgrid_opts,
72   25000, 1, 1, 1, 1.0, 4, "",
73   "Shows a rotating 3D lattice from inside", 0, NULL
74 };
75 #endif
76
77 typedef struct {
78   GLXContext    *glx_context;
79   GLfloat       ratio;
80   GLint         list;
81
82   rotator *rot;
83   trackball_state *trackball;
84   Bool button_down_p;
85   int npoints;
86 } cubicgrid_conf;
87
88 static cubicgrid_conf *cubicgrid = NULL;
89
90 static const GLfloat zpos = -18.0;
91
92 /*************************************************************************/
93
94 ENTRYPOINT Bool
95 cubicgrid_handle_event (ModeInfo *mi, XEvent *event)
96 {
97   cubicgrid_conf *cp = &cubicgrid[MI_SCREEN(mi)];
98
99   if (gltrackball_event_handler (event, cp->trackball,
100                                  MI_WIDTH (mi), MI_HEIGHT (mi),
101                                  &cp->button_down_p))
102     return True;
103
104   return False;
105 }
106
107
108 static Bool draw_main(ModeInfo *mi)
109 {
110   cubicgrid_conf *cp = &cubicgrid[MI_SCREEN(mi)];
111   double x, y, z;
112
113   glClear(GL_COLOR_BUFFER_BIT);
114   glLoadIdentity();
115
116   glRotatef (180, 1, 0, 0);  /* Make trackball track the right way */
117   glRotatef (180, 0, 1, 0);
118
119   glTranslatef(0, 0, zpos);
120
121   glScalef(size/ticks, size/ticks, size/ticks);
122
123
124 # ifdef HAVE_MOBILE     /* Keep it the same relative size when rotated. */
125   {
126     GLfloat h = MI_HEIGHT(mi) / (GLfloat) MI_WIDTH(mi);
127     int o = (int) current_device_rotation();
128     if (o != 0 && o != 180 && o != -180)
129       glScalef (1/h, 1/h, 1);
130   }
131 # endif
132
133   gltrackball_rotate (cp->trackball);
134
135   get_rotation (cp->rot, &x, &y, &z, !cp->button_down_p);
136   glRotatef (-x * 360, 1.0, 0.0, 0.0);
137   glRotatef (-y * 360, 0.0, 1.0, 0.0);
138   glRotatef (-z * 360, 0.0, 0.0, 1.0);
139
140   glTranslatef(-ticks/2.0, -ticks/2.0, -ticks/2.0);
141   glCallList(cp->list);
142   return True;
143 }
144
145 static void init_gl(ModeInfo *mi) 
146 {
147   cubicgrid_conf *cp = &cubicgrid[MI_SCREEN(mi)];
148   int x, y, z;
149   float tf = ticks;
150
151   glDrawBuffer(GL_BACK);
152   if(bigdots) {
153     glPointSize(2.0);
154   }
155   glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
156   glShadeModel(GL_FLAT);
157
158   cp->list = glGenLists(1);
159   glNewList(cp->list, GL_COMPILE);
160   if(MI_IS_MONO(mi)) {
161     glColor3f(1.0, 1.0, 1.0);
162     glBegin(GL_POINTS);
163     for(x = 0; x < ticks; x++) {
164       for(y = 0; y < ticks; y++) {
165         for(z = 0; z < ticks; z++) {
166           glVertex3f(x, y, z);
167           cp->npoints++;
168         }
169       }
170     }
171     glEnd();
172   }
173   else
174   {
175     glBegin(GL_POINTS);
176     for(x = 0; x < ticks; x++) {
177       for(y = 0; y < ticks; y++) {
178         for(z = 0; z < ticks; z++) {
179           glColor3f(x/tf, y/tf, z/tf);
180           glVertex3f(x, y, z);
181           cp->npoints++;
182         }
183       }
184     }
185     glEnd();
186   }
187   glEndList();
188 }
189
190 /*************************************************************************/
191
192 ENTRYPOINT void reshape_cubicgrid(ModeInfo *mi, int width, int height) 
193 {
194   cubicgrid_conf *cp = &cubicgrid[MI_SCREEN(mi)];
195   if(!height) height = 1;
196   cp->ratio = (GLfloat)width/(GLfloat)height;
197   glViewport(0, 0, (GLint) width, (GLint) height);
198   glMatrixMode(GL_PROJECTION);
199   glLoadIdentity();
200   gluPerspective(30.0, cp->ratio, 1.0, 100.0);
201   glMatrixMode(GL_MODELVIEW);
202   glClear(GL_COLOR_BUFFER_BIT);
203 }
204
205 ENTRYPOINT void init_cubicgrid(ModeInfo *mi) 
206 {
207   cubicgrid_conf *cp;
208   MI_INIT(mi, cubicgrid, NULL);
209   cp = &cubicgrid[MI_SCREEN(mi)];
210
211   if ((cp->glx_context = init_GL(mi)) != NULL) {
212     init_gl(mi);
213     reshape_cubicgrid(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
214   } else {
215     MI_CLEARWINDOW(mi);
216   }
217
218   {
219     double spin_speed = 0.045 * speed;
220     double spin_accel = 0.005 * speed;
221
222     cp->rot = make_rotator (spin_speed, spin_speed, spin_speed,
223                             spin_accel, 0, True);
224     cp->trackball = gltrackball_init (True);
225   }
226 }
227
228 ENTRYPOINT void draw_cubicgrid(ModeInfo * mi) 
229 {
230   Display *display = MI_DISPLAY(mi);
231   Window window = MI_WINDOW(mi);
232   cubicgrid_conf *cp;
233   if (!cubicgrid) return;
234   cp = &cubicgrid[MI_SCREEN(mi)];
235   MI_IS_DRAWN(mi) = True;
236   if (!cp->glx_context) return;
237   glXMakeCurrent(display, window, *(cp->glx_context));
238   if (!draw_main(mi)) {
239     MI_ABORT(mi);
240     return;
241   }
242   mi->polygon_count = cp->npoints;
243   if (MI_IS_FPS(mi)) do_fps (mi);
244   glFlush();
245   glXSwapBuffers(display, window);
246 }
247
248 #ifndef STANDALONE
249 ENTRYPOINT void change_cubicgrid(ModeInfo * mi) 
250 {
251   cubicgrid_conf *cp = &cubicgrid[MI_SCREEN(mi)];
252   if (!cp->glx_context) return;
253   glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(cp->glx_context));
254   init_gl(mi);
255 }
256 #endif /* !STANDALONE */
257
258
259 XSCREENSAVER_MODULE ("CubicGrid", cubicgrid)
260
261 #endif