82a1862b258db5734a445fa4c8b8f793e22a5194
[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 #include "xlockmore.h"
29
30 #ifdef USE_GL
31
32 #define DEF_SPEED   "1.0"
33 #define DEF_DIV     "30"
34 #define DEF_ZOOM    "20"
35 #define DEF_BIGDOTS "True"
36
37 #undef countof
38 #define countof(x) (sizeof((x))/sizeof((*x)))
39
40 #include "rotator.h"
41 #include "gltrackball.h"
42
43 /*************************************************************************/
44
45 static int ticks;
46 static float size;
47 static float speed;
48 static Bool bigdots;
49
50 static argtype vars[] = {
51   { &speed,   "speed",   "Speed",   DEF_SPEED,   t_Float },
52   { &size,    "zoom",    "Zoom",    DEF_ZOOM,    t_Float },
53   { &ticks,   "ticks",   "Ticks",   DEF_DIV,     t_Int },
54   { &bigdots, "bigdots", "BigDots", DEF_BIGDOTS, t_Bool },
55 };
56
57 static XrmOptionDescRec opts[] = {
58   { "-speed",   ".speed",   XrmoptionSepArg, 0 },
59   { "-zoom",    ".zoom",    XrmoptionSepArg, 0 },
60   { "-ticks",   ".ticks",   XrmoptionSepArg, 0 },
61   { "-bigdots", ".bigdots", XrmoptionNoArg,  "True" },
62   { "+bigdots", ".bigdots", XrmoptionNoArg,  "False" },
63 };
64
65 ENTRYPOINT ModeSpecOpt cubicgrid_opts = {countof(opts), opts, countof(vars), vars, NULL};
66
67 #ifdef USE_MODULES
68 ModStruct   cubicgrid_description =
69 { "cubicgrid", "init_cubicgrid", "draw_cubicgrid", "release_cubicgrid",
70   "draw_cubicgrid", "change_cubicgrid", NULL, &cubicgrid_opts,
71   25000, 1, 1, 1, 1.0, 4, "",
72   "Shows a rotating 3D lattice from inside", 0, NULL
73 };
74 #endif
75
76 typedef struct {
77   GLXContext    *glx_context;
78   GLfloat       ratio;
79   GLint         list;
80
81   rotator *rot;
82   trackball_state *trackball;
83   Bool button_down_p;
84   int npoints;
85 } cubicgrid_conf;
86
87 static cubicgrid_conf *cubicgrid = NULL;
88
89 static const GLfloat zpos = -18.0;
90
91 /*************************************************************************/
92
93 ENTRYPOINT Bool
94 cubicgrid_handle_event (ModeInfo *mi, XEvent *event)
95 {
96   cubicgrid_conf *cp = &cubicgrid[MI_SCREEN(mi)];
97
98   if (gltrackball_event_handler (event, cp->trackball,
99                                  MI_WIDTH (mi), MI_HEIGHT (mi),
100                                  &cp->button_down_p))
101     return True;
102
103   return False;
104 }
105
106
107 static Bool draw_main(ModeInfo *mi)
108 {
109   cubicgrid_conf *cp = &cubicgrid[MI_SCREEN(mi)];
110   double x, y, z;
111
112   glClear(GL_COLOR_BUFFER_BIT);
113   glLoadIdentity();
114
115   glRotatef (180, 1, 0, 0);  /* Make trackball track the right way */
116   glRotatef (180, 0, 1, 0);
117
118   glTranslatef(0, 0, zpos);
119
120   glScalef(size/ticks, size/ticks, size/ticks);
121
122
123 # ifdef HAVE_MOBILE     /* Keep it the same relative size when rotated. */
124   {
125     GLfloat h = MI_HEIGHT(mi) / (GLfloat) MI_WIDTH(mi);
126     int o = (int) current_device_rotation();
127     if (o != 0 && o != 180 && o != -180)
128       glScalef (1/h, 1/h, 1);
129   }
130 # endif
131
132   gltrackball_rotate (cp->trackball);
133
134   get_rotation (cp->rot, &x, &y, &z, !cp->button_down_p);
135   glRotatef (-x * 360, 1.0, 0.0, 0.0);
136   glRotatef (-y * 360, 0.0, 1.0, 0.0);
137   glRotatef (-z * 360, 0.0, 0.0, 1.0);
138
139   glTranslatef(-ticks/2.0, -ticks/2.0, -ticks/2.0);
140   glCallList(cp->list);
141   return True;
142 }
143
144 static void init_gl(ModeInfo *mi) 
145 {
146   cubicgrid_conf *cp = &cubicgrid[MI_SCREEN(mi)];
147   int x, y, z;
148   float tf = ticks;
149
150   glDrawBuffer(GL_BACK);
151   if(bigdots) {
152     glPointSize(2.0);
153   }
154   glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
155   glShadeModel(GL_FLAT);
156
157   cp->list = glGenLists(1);
158   glNewList(cp->list, GL_COMPILE);
159   if(MI_IS_MONO(mi)) {
160     glColor3f(1.0, 1.0, 1.0);
161     glBegin(GL_POINTS);
162     for(x = 0; x < ticks; x++) {
163       for(y = 0; y < ticks; y++) {
164         for(z = 0; z < ticks; z++) {
165           glVertex3f(x, y, z);
166           cp->npoints++;
167         }
168       }
169     }
170     glEnd();
171   }
172   else
173   {
174     glBegin(GL_POINTS);
175     for(x = 0; x < ticks; x++) {
176       for(y = 0; y < ticks; y++) {
177         for(z = 0; z < ticks; z++) {
178           glColor3f(x/tf, y/tf, z/tf);
179           glVertex3f(x, y, z);
180           cp->npoints++;
181         }
182       }
183     }
184     glEnd();
185   }
186   glEndList();
187 }
188
189 /*************************************************************************/
190
191 ENTRYPOINT void reshape_cubicgrid(ModeInfo *mi, int width, int height) 
192 {
193   cubicgrid_conf *cp = &cubicgrid[MI_SCREEN(mi)];
194   if(!height) height = 1;
195   cp->ratio = (GLfloat)width/(GLfloat)height;
196   glViewport(0, 0, (GLint) width, (GLint) height);
197   glMatrixMode(GL_PROJECTION);
198   glLoadIdentity();
199   gluPerspective(30.0, cp->ratio, 1.0, 100.0);
200   glMatrixMode(GL_MODELVIEW);
201   glClear(GL_COLOR_BUFFER_BIT);
202 }
203
204 ENTRYPOINT void release_cubicgrid(ModeInfo *mi) 
205 {
206   if (cubicgrid != NULL) {
207     int screen;
208     for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
209       cubicgrid_conf *cp = &cubicgrid[screen];
210       if (cp->glx_context) {
211         cp->glx_context = NULL;
212       }
213     }
214     free((void *)cubicgrid);
215     cubicgrid = NULL;
216   }
217   FreeAllGL(mi);
218 }
219
220 ENTRYPOINT void init_cubicgrid(ModeInfo *mi) 
221 {
222   cubicgrid_conf *cp;
223   if(!cubicgrid) {
224     cubicgrid = (cubicgrid_conf *)calloc(MI_NUM_SCREENS(mi), sizeof(cubicgrid_conf));
225     if(!cubicgrid) return;
226   }
227   cp = &cubicgrid[MI_SCREEN(mi)];
228
229   if ((cp->glx_context = init_GL(mi)) != NULL) {
230     init_gl(mi);
231     reshape_cubicgrid(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
232   } else {
233     MI_CLEARWINDOW(mi);
234   }
235
236   {
237     double spin_speed = 0.045 * speed;
238     double spin_accel = 0.005 * speed;
239
240     cp->rot = make_rotator (spin_speed, spin_speed, spin_speed,
241                             spin_accel, 0, True);
242     cp->trackball = gltrackball_init (True);
243   }
244 }
245
246 ENTRYPOINT void draw_cubicgrid(ModeInfo * mi) 
247 {
248   Display *display = MI_DISPLAY(mi);
249   Window window = MI_WINDOW(mi);
250   cubicgrid_conf *cp;
251   if (!cubicgrid) return;
252   cp = &cubicgrid[MI_SCREEN(mi)];
253   MI_IS_DRAWN(mi) = True;
254   if (!cp->glx_context) return;
255   glXMakeCurrent(display, window, *(cp->glx_context));
256   if (!draw_main(mi)) {
257     release_cubicgrid(mi);
258     return;
259   }
260   mi->polygon_count = cp->npoints;
261   if (MI_IS_FPS(mi)) do_fps (mi);
262   glFlush();
263   glXSwapBuffers(display, window);
264 }
265
266 #ifndef STANDALONE
267 ENTRYPOINT void change_cubicgrid(ModeInfo * mi) 
268 {
269   cubicgrid_conf *cp = &cubicgrid[MI_SCREEN(mi)];
270   if (!cp->glx_context) return;
271   glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(cp->glx_context));
272   init_gl(mi);
273 }
274 #endif /* !STANDALONE */
275
276
277 XSCREENSAVER_MODULE ("CubicGrid", cubicgrid)
278
279 #endif