From http://www.jwz.org/xscreensaver/xscreensaver-5.35.tar.gz
[xscreensaver] / hacks / glx / atunnel.c
1 /* -*- Mode: C; tab-width: 4 -*- */
2 /* atunnel --- OpenGL Advanced Tunnel Screensaver */
3
4 #if 0
5 static const char sccsid[] = "@(#)atunnel.c     5.13 2004/05/25 xlockmore";
6 #endif
7
8 /* Copyright (c) E. Lassauge, 2003-2004. */
9
10 /*
11  * Permission to use, copy, modify, and distribute this software and its
12  * documentation for any purpose and without fee is hereby granted,
13  * provided that the above copyright notice appear in all copies and that
14  * both that copyright notice and this permission notice appear in
15  * supporting documentation.
16  *
17  * This file is provided AS IS with no warranties of any kind.  The author
18  * shall have no liability with respect to the infringement of copyrights,
19  * trade secrets or any patents by this file or any part thereof.  In no
20  * event will the author be liable for any lost revenue or profits or
21  * other special, indirect and consequential damages.
22  *
23  * The original code for this mode was written by Roman Podobedov
24  * Email: romka@ut.ee
25  * WEB: http://romka.demonews.com
26  *
27  * Eric Lassauge  (May-25-2004) <lassauge@users.sourceforge.net>
28  *                                  http://lassauge.free.fr/linux.html
29  *
30  * REVISION HISTORY:
31  *
32  * E.Lassauge - 25-May-2004:
33  *      - added more texture !
34  * E.Lassauge - 16-Mar-2002:
35  *      - created based on the Roman demo.
36  *      - deleted all external file stuff to use xpm textures and
37  *        hardcoded path point values.
38  *
39  */
40
41 #ifdef STANDALONE               /* xscreensaver mode */
42 #define DEFAULTS                "*delay:        10000   \n" \
43                                 "*showFPS:  False   \n" \
44                                                                 "*suppressRotationAnimation: True\n" \
45
46 # define refresh_atunnel 0
47 # define atunnel_handle_event 0
48 #define MODE_atunnel
49 # include "xlockmore.h"         /* from the xscreensaver distribution */
50 #else                           /* !STANDALONE */
51 # include "xlock.h"             /* from the xlockmore distribution */
52 #endif                          /* !STANDALONE */
53
54 #ifdef MODE_atunnel /* whole file */
55
56 #include <stdio.h>
57 #include <stdlib.h>
58 #include <math.h>
59 #include "tunnel_draw.h"
60
61 #if defined( USE_XPM ) || defined( USE_XPMINC ) || defined(STANDALONE)
62 /* USE_XPM & USE_XPMINC in xlock mode ; STANDALONE in xscreensaver mode */
63 #include "xpm-ximage.h"
64 #define I_HAVE_XPM
65
66 #ifdef STANDALONE
67 #include "../images/tunnel0.xpm"
68 #include "../images/tunnel1.xpm"
69 #include "../images/tunnel2.xpm"
70 #include "../images/tunnel3.xpm"
71 #include "../images/tunnel4.xpm"
72 #include "../images/tunnel5.xpm"
73 #else /* !STANDALONE */
74 #include "pixmaps/tunnel0.xpm"
75 #include "pixmaps/tunnel1.xpm"
76 #include "pixmaps/tunnel2.xpm"
77 #include "pixmaps/tunnel3.xpm"
78 #include "pixmaps/tunnel4.xpm"
79 #include "pixmaps/tunnel5.xpm"
80 #endif /* !STANDALONE */
81 #endif /* HAVE_XPM */
82
83
84 #undef countof
85 #define countof(x) (sizeof((x))/sizeof((*x)))
86
87 #define DEF_LIGHT       "True"
88 #define DEF_WIRE    "False"
89 #define DEF_TEXTURE     "True"
90
91 static Bool do_light;
92 static Bool do_wire;
93 static Bool do_texture;
94
95 static XrmOptionDescRec opts[] = {
96   {"-light",   ".atunnel.light",      XrmoptionNoArg, "true" },
97   {"+light",   ".atunnel.light",      XrmoptionNoArg, "false" },
98   {"-wireframe",".atunnel.wire",       XrmoptionNoArg, "true" },
99   {"+wireframe",".atunnel.wire",       XrmoptionNoArg, "false" },
100   {"-texture", ".atunnel.texture",    XrmoptionNoArg, "true" },
101   {"+texture", ".atunnel.texture",    XrmoptionNoArg, "false" },
102 };
103
104 static argtype vars[] = {
105   {&do_light,   "light",   "Light",   DEF_LIGHT,   t_Bool},
106   {&do_wire,    "wire",    "Wire",    DEF_WIRE,    t_Bool},
107   {&do_texture, "texture", "Texture", DEF_TEXTURE, t_Bool},
108 };
109
110 static OptionStruct desc[] =
111 {
112   {"-/+ light",   "whether to do enable lighting (slower)"},
113   {"-/+ wire",    "whether to do use wireframe instead of filled (faster)"},
114   {"-/+ texture", "whether to apply a texture (slower)"},
115 };
116
117 ENTRYPOINT ModeSpecOpt atunnel_opts = {countof(opts), opts, countof(vars), vars, desc};
118
119 #ifdef USE_MODULES
120 ModStruct   atunnel_description =
121 {"atunnel", "init_atunnel", "draw_atunnel", "release_atunnel",
122  "draw_atunnel", "init_atunnel", NULL, &atunnel_opts,
123  1000, 1, 2, 1, 4, 1.0, "",
124  "OpenGL advanced tunnel screensaver", 0, NULL};
125 #endif
126
127 /* structure for holding the screensaver data */
128 typedef struct {
129   int screen_width, screen_height;
130   GLXContext *glx_context;
131   Window window;
132   struct tunnel_state *ts;
133   GLuint texture[MAX_TEXTURE]; /* texture id: GL world */
134 } atunnelstruct;
135
136 static atunnelstruct *Atunnel = NULL;
137
138 /*=================== Load Texture =========================================*/
139 static void LoadTexture(ModeInfo * mi, char **fn, int t_num)
140 {
141 #if defined( I_HAVE_XPM )
142         atunnelstruct *sa = &Atunnel[MI_SCREEN(mi)];
143         XImage *teximage;    /* Texture data */
144  
145         if ((teximage = xpm_to_ximage(MI_DISPLAY(mi), MI_VISUAL(mi),
146                          MI_COLORMAP(mi), fn)) == None) {
147             (void) fprintf(stderr, "Error reading the texture.\n");
148             glDeleteTextures(1, &sa->texture[t_num]);
149             do_texture = False;
150 #ifdef STANDALONE
151             exit(0);
152 #else
153             return;
154 #endif
155         }
156
157 #ifdef HAVE_GLBINDTEXTURE
158         glBindTexture(GL_TEXTURE_2D, sa->texture[t_num]);
159 #endif /* HAVE_GLBINDTEXTURE */
160         glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
161         clear_gl_error();
162         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, teximage->width, teximage->height, 
163                         0, GL_RGBA,
164                  /* GL_UNSIGNED_BYTE, */
165                  GL_UNSIGNED_INT_8_8_8_8_REV,
166                  teximage->data);
167         check_gl_error("texture");
168
169         /* Texture parameters, LINEAR scaling for better texture quality */
170         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 
171         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 
172
173         XDestroyImage(teximage);
174 #else /* !I_HAVE_XPM */
175         do_texture = False;
176 #endif /* !I_HAVE_XPM */
177
178
179 /*=================== Main Initialization ==================================*/
180 static void Init(ModeInfo * mi)
181 {
182         atunnelstruct *sa = &Atunnel[MI_SCREEN(mi)];
183         GLfloat light_ambient[] = {1.0, 1.0, 1.0, 1.0};
184         GLfloat light_diffuse[] = {1.0, 1.0, 1.0, 1.0};
185         GLfloat light_specular[] = {1.0, 1.0, 1.0, 1.0};
186         GLfloat light_position[] = {0.0, 0.0, 1.0, 0.0};
187         GLfloat fogColor[4] = {0.8, 0.8, 0.8, 1.0};
188
189         if (do_texture)
190         {
191                 glGenTextures(MAX_TEXTURE, sa->texture);
192                 LoadTexture(mi, texture0,0);
193                 LoadTexture(mi, texture1,1);
194                 LoadTexture(mi, texture2,2);
195                 LoadTexture(mi, texture3,3);
196                 LoadTexture(mi, texture4,4);
197                 LoadTexture(mi, texture5,5);
198                 glEnable(GL_TEXTURE_2D);
199         }
200         sa->ts = atunnel_InitTunnel();
201         
202         /* Set lighting parameters */
203         if (do_light)
204         {
205                 glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient);
206                 glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse);
207                 glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular);
208                 glLightfv(GL_LIGHT0, GL_POSITION, light_position);
209
210                 /* Enable light 0 */
211                 glEnable(GL_LIGHT0);
212                 glDepthFunc(GL_LESS);
213         
214                 glEnable(GL_LIGHTING);
215         }
216
217 # ifdef HAVE_JWZGLES /* #### glPolygonMode other than GL_FILL unimplemented */
218     do_wire = 0;
219 # endif
220
221         if (do_wire) {
222                 glDisable(GL_NORMALIZE);
223                 glDisable(GL_CULL_FACE);
224                 glDisable(GL_DEPTH_TEST);
225                 glDisable(GL_TEXTURE_2D);
226                 glPolygonMode(GL_FRONT,GL_LINE);
227                 glPolygonMode(GL_BACK,GL_LINE);
228         }
229         else
230         {
231                 glEnable(GL_DEPTH_TEST);
232                 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
233
234                 /* Enable fog */
235                 glFogi(GL_FOG_MODE, GL_EXP);
236                 glFogfv(GL_FOG_COLOR, fogColor);
237                 glFogf(GL_FOG_DENSITY, 0.3);
238                 glEnable(GL_FOG);
239         
240                 /* Cull face */
241                 glCullFace(GL_FRONT);
242                 glEnable(GL_CULL_FACE);
243         }
244         
245         glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
246 }
247
248
249 /* Standard reshape function */
250 ENTRYPOINT void
251 reshape_atunnel(ModeInfo *mi, int width, int height)
252 {
253         float a;
254
255         glViewport(0, 0, width, height);
256         glMatrixMode(GL_PROJECTION);
257         glLoadIdentity();
258         a = (float)width/(float)height;
259         glFrustum(-0.1*a, 0.1*a, -0.1, 0.1, 0.1, 10);
260         glMatrixMode(GL_MODELVIEW);
261 }
262
263 /* draw the screensaver once */
264 ENTRYPOINT void draw_atunnel(ModeInfo * mi)
265 {
266         atunnelstruct *sa = &Atunnel[MI_SCREEN(mi)];
267         Display    *display = MI_DISPLAY(mi);
268         Window      window = MI_WINDOW(mi);
269
270         if (!sa->glx_context)
271                 return;
272
273         glXMakeCurrent(display, window, *(sa->glx_context));
274
275         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
276
277         glLoadIdentity();
278
279         atunnel_DrawTunnel(sa->ts, do_texture, do_light, sa->texture);
280         atunnel_SplashScreen(sa->ts, do_wire, do_texture, do_light);
281
282         glFlush();  
283         /* manage framerate display */
284         if (MI_IS_FPS(mi)) do_fps (mi);
285         glXSwapBuffers(display, window);
286
287 }
288
289
290 /* xscreensaver initialization routine */
291 ENTRYPOINT void init_atunnel(ModeInfo * mi)
292 {
293   int screen = MI_SCREEN(mi);
294   atunnelstruct *sa;
295
296   if (Atunnel == NULL) {
297         if ((Atunnel = (atunnelstruct *) calloc(MI_NUM_SCREENS(mi), sizeof (atunnelstruct))) == NULL)
298           return;
299   }
300   sa = &Atunnel[screen];
301
302   sa->window = MI_WINDOW(mi);
303   if ((sa->glx_context = init_GL(mi)) != NULL) {
304         reshape_atunnel(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
305         Init(mi);
306   } else {
307         MI_CLEARWINDOW(mi);
308   }
309
310 }
311
312 /* all sorts of nice cleanup code should go here! */
313 ENTRYPOINT void release_atunnel(ModeInfo * mi)
314 {
315 #if 0
316   int screen;
317   if (Atunnel != NULL) {
318         for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
319       atunnelstruct *sa = &Atunnel[screen];
320       FreeTunnel(sa->ts);
321         }
322         (void) free((void *) Atunnel);
323         Atunnel = NULL;
324   }
325   FreeAllGL(mi);
326 #endif
327 }
328
329 XSCREENSAVER_MODULE ("Atunnel", atunnel)
330
331 #endif