ee244ea5c137b38fe7bdd95d488ef9258c2cb090
[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
45 # define refresh_atunnel 0
46 # define atunnel_handle_event 0
47 #define MODE_atunnel
48 # include "xlockmore.h"         /* from the xscreensaver distribution */
49 #else                           /* !STANDALONE */
50 # include "xlock.h"             /* from the xlockmore distribution */
51 #endif                          /* !STANDALONE */
52
53 #ifdef MODE_atunnel /* whole file */
54
55 #include <stdio.h>
56 #include <stdlib.h>
57 #include <math.h>
58 #include "tunnel_draw.h"
59
60 #if defined( USE_XPM ) || defined( USE_XPMINC ) || defined(STANDALONE)
61 /* USE_XPM & USE_XPMINC in xlock mode ; STANDALONE in xscreensaver mode */
62 #include "xpm-ximage.h"
63 #define I_HAVE_XPM
64
65 #ifdef STANDALONE
66 #include "../images/tunnel0.xpm"
67 #include "../images/tunnel1.xpm"
68 #include "../images/tunnel2.xpm"
69 #include "../images/tunnel3.xpm"
70 #include "../images/tunnel4.xpm"
71 #include "../images/tunnel5.xpm"
72 #else /* !STANDALONE */
73 #include "pixmaps/tunnel0.xpm"
74 #include "pixmaps/tunnel1.xpm"
75 #include "pixmaps/tunnel2.xpm"
76 #include "pixmaps/tunnel3.xpm"
77 #include "pixmaps/tunnel4.xpm"
78 #include "pixmaps/tunnel5.xpm"
79 #endif /* !STANDALONE */
80 #endif /* HAVE_XPM */
81
82
83 #undef countof
84 #define countof(x) (sizeof((x))/sizeof((*x)))
85
86 #define DEF_LIGHT       "True"
87 #define DEF_WIRE    "False"
88 #define DEF_TEXTURE     "True"
89
90 static Bool do_light;
91 static Bool do_wire;
92 static Bool do_texture;
93
94 static XrmOptionDescRec opts[] = {
95   {"-light",   ".atunnel.light",      XrmoptionNoArg, "true" },
96   {"+light",   ".atunnel.light",      XrmoptionNoArg, "false" },
97   {"-wireframe",".atunnel.wire",       XrmoptionNoArg, "true" },
98   {"+wireframe",".atunnel.wire",       XrmoptionNoArg, "false" },
99   {"-texture", ".atunnel.texture",    XrmoptionNoArg, "true" },
100   {"+texture", ".atunnel.texture",    XrmoptionNoArg, "false" },
101 };
102
103 static argtype vars[] = {
104   {&do_light,   "light",   "Light",   DEF_LIGHT,   t_Bool},
105   {&do_wire,    "wire",    "Wire",    DEF_WIRE,    t_Bool},
106   {&do_texture, "texture", "Texture", DEF_TEXTURE, t_Bool},
107 };
108
109 static OptionStruct desc[] =
110 {
111   {"-/+ light",   "whether to do enable lighting (slower)"},
112   {"-/+ wire",    "whether to do use wireframe instead of filled (faster)"},
113   {"-/+ texture", "whether to apply a texture (slower)"},
114 };
115
116 ENTRYPOINT ModeSpecOpt atunnel_opts = {countof(opts), opts, countof(vars), vars, desc};
117
118 #ifdef USE_MODULES
119 ModStruct   atunnel_description =
120 {"atunnel", "init_atunnel", "draw_atunnel", "release_atunnel",
121  "draw_atunnel", "init_atunnel", NULL, &atunnel_opts,
122  1000, 1, 2, 1, 4, 1.0, "",
123  "OpenGL advanced tunnel screensaver", 0, NULL};
124 #endif
125
126 /* structure for holding the screensaver data */
127 typedef struct {
128   int screen_width, screen_height;
129   GLXContext *glx_context;
130   Window window;
131   struct tunnel_state *ts;
132   GLuint texture[MAX_TEXTURE]; /* texture id: GL world */
133 } atunnelstruct;
134
135 static atunnelstruct *Atunnel = NULL;
136
137 /*=================== Load Texture =========================================*/
138 static void LoadTexture(ModeInfo * mi, char **fn, int t_num)
139 {
140 #if defined( I_HAVE_XPM )
141         atunnelstruct *sa = &Atunnel[MI_SCREEN(mi)];
142         XImage *teximage;    /* Texture data */
143  
144         if ((teximage = xpm_to_ximage(MI_DISPLAY(mi), MI_VISUAL(mi),
145                          MI_COLORMAP(mi), fn)) == None) {
146             (void) fprintf(stderr, "Error reading the texture.\n");
147             glDeleteTextures(1, &sa->texture[t_num]);
148             do_texture = False;
149 #ifdef STANDALONE
150             exit(0);
151 #else
152             return;
153 #endif
154         }
155
156 #ifdef HAVE_GLBINDTEXTURE
157         glBindTexture(GL_TEXTURE_2D, sa->texture[t_num]);
158 #endif /* HAVE_GLBINDTEXTURE */
159         glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
160         clear_gl_error();
161         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, teximage->width, teximage->height, 
162                         0, GL_RGBA,
163                  /* GL_UNSIGNED_BYTE, */
164                  GL_UNSIGNED_INT_8_8_8_8_REV,
165                  teximage->data);
166         check_gl_error("texture");
167
168         /* Texture parameters, LINEAR scaling for better texture quality */
169         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 
170         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 
171
172         XDestroyImage(teximage);
173 #else /* !I_HAVE_XPM */
174         do_texture = False;
175 #endif /* !I_HAVE_XPM */
176
177
178 /*=================== Main Initialization ==================================*/
179 static void Init(ModeInfo * mi)
180 {
181         atunnelstruct *sa = &Atunnel[MI_SCREEN(mi)];
182         GLfloat light_ambient[] = {1.0, 1.0, 1.0, 1.0};
183         GLfloat light_diffuse[] = {1.0, 1.0, 1.0, 1.0};
184         GLfloat light_specular[] = {1.0, 1.0, 1.0, 1.0};
185         GLfloat light_position[] = {0.0, 0.0, 1.0, 0.0};
186         GLfloat fogColor[4] = {0.8, 0.8, 0.8, 1.0};
187
188         if (do_texture)
189         {
190                 glGenTextures(MAX_TEXTURE, sa->texture);
191                 LoadTexture(mi, texture0,0);
192                 LoadTexture(mi, texture1,1);
193                 LoadTexture(mi, texture2,2);
194                 LoadTexture(mi, texture3,3);
195                 LoadTexture(mi, texture4,4);
196                 LoadTexture(mi, texture5,5);
197                 glEnable(GL_TEXTURE_2D);
198         }
199         sa->ts = InitTunnel();
200         
201         /* Set lighting parameters */
202         if (do_light)
203         {
204                 glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient);
205                 glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse);
206                 glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular);
207                 glLightfv(GL_LIGHT0, GL_POSITION, light_position);
208
209                 /* Enable light 0 */
210                 glEnable(GL_LIGHT0);
211                 glDepthFunc(GL_LESS);
212         
213                 glEnable(GL_LIGHTING);
214         }
215         if (do_wire) {
216                 glDisable(GL_NORMALIZE);
217                 glDisable(GL_CULL_FACE);
218                 glDisable(GL_DEPTH_TEST);
219                 glDisable(GL_TEXTURE_2D);
220                 glPolygonMode(GL_FRONT,GL_LINE);
221                 glPolygonMode(GL_BACK,GL_LINE);
222         }
223         else
224         {
225                 glEnable(GL_DEPTH_TEST);
226                 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
227
228                 /* Enable fog */
229                 glFogi(GL_FOG_MODE, GL_EXP);
230                 glFogfv(GL_FOG_COLOR, fogColor);
231                 glFogf(GL_FOG_DENSITY, 0.3);
232                 glEnable(GL_FOG);
233         
234                 /* Cull face */
235                 glCullFace(GL_FRONT);
236                 glEnable(GL_CULL_FACE);
237         }
238         
239         glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
240 }
241
242
243 /* Standard reshape function */
244 ENTRYPOINT void
245 reshape_atunnel(ModeInfo *mi, int width, int height)
246 {
247         float a;
248
249         glViewport(0, 0, width, height);
250         glMatrixMode(GL_PROJECTION);
251         glLoadIdentity();
252         a = (float)width/(float)height;
253         glFrustum(-0.1*a, 0.1*a, -0.1, 0.1, 0.1, 10);
254         glMatrixMode(GL_MODELVIEW);
255 }
256
257 /* draw the screensaver once */
258 ENTRYPOINT void draw_atunnel(ModeInfo * mi)
259 {
260         atunnelstruct *sa = &Atunnel[MI_SCREEN(mi)];
261         Display    *display = MI_DISPLAY(mi);
262         Window      window = MI_WINDOW(mi);
263
264         if (!sa->glx_context)
265                 return;
266
267         glXMakeCurrent(display, window, *(sa->glx_context));
268
269         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
270
271         glLoadIdentity();
272
273         DrawTunnel(sa->ts, do_texture, do_light, sa->texture);
274         SplashScreen(sa->ts, do_wire, do_texture, do_light);
275
276         glFlush();  
277         /* manage framerate display */
278         if (MI_IS_FPS(mi)) do_fps (mi);
279         glXSwapBuffers(display, window);
280
281 }
282
283
284 /* xscreensaver initialization routine */
285 ENTRYPOINT void init_atunnel(ModeInfo * mi)
286 {
287   int screen = MI_SCREEN(mi);
288   atunnelstruct *sa;
289
290   if (Atunnel == NULL) {
291         if ((Atunnel = (atunnelstruct *) calloc(MI_NUM_SCREENS(mi), sizeof (atunnelstruct))) == NULL)
292           return;
293   }
294   sa = &Atunnel[screen];
295
296   sa->window = MI_WINDOW(mi);
297   if ((sa->glx_context = init_GL(mi)) != NULL) {
298         reshape_atunnel(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
299         Init(mi);
300   } else {
301         MI_CLEARWINDOW(mi);
302   }
303
304 }
305
306 /* all sorts of nice cleanup code should go here! */
307 ENTRYPOINT void release_atunnel(ModeInfo * mi)
308 {
309 #if 0
310   int screen;
311   if (Atunnel != NULL) {
312         for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
313       atunnelstruct *sa = &Atunnel[screen];
314       FreeTunnel(sa->ts);
315         }
316         (void) free((void *) Atunnel);
317         Atunnel = NULL;
318   }
319   FreeAllGL(mi);
320 #endif
321 }
322
323 XSCREENSAVER_MODULE ("Atunnel", atunnel)
324
325 #endif