From http://www.jwz.org/xscreensaver/xscreensaver-5.39.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 release_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 "ximage-loader.h"
64 #define I_HAVE_XPM
65
66 #include "images/gen/tunnel0_png.h"
67 #include "images/gen/tunnel1_png.h"
68 #include "images/gen/tunnel2_png.h"
69 #include "images/gen/tunnel3_png.h"
70 #include "images/gen/tunnel4_png.h"
71 #include "images/gen/tunnel5_png.h"
72 #endif /* HAVE_XPM */
73
74
75 #undef countof
76 #define countof(x) (sizeof((x))/sizeof((*x)))
77
78 #define DEF_LIGHT       "True"
79 #define DEF_WIRE    "False"
80 #define DEF_TEXTURE     "True"
81
82 static Bool do_light;
83 static Bool do_wire;
84 static Bool do_texture;
85
86 static XrmOptionDescRec opts[] = {
87   {"-light",   ".atunnel.light",      XrmoptionNoArg, "true" },
88   {"+light",   ".atunnel.light",      XrmoptionNoArg, "false" },
89   {"-wireframe",".atunnel.wire",       XrmoptionNoArg, "true" },
90   {"+wireframe",".atunnel.wire",       XrmoptionNoArg, "false" },
91   {"-texture", ".atunnel.texture",    XrmoptionNoArg, "true" },
92   {"+texture", ".atunnel.texture",    XrmoptionNoArg, "false" },
93 };
94
95 static argtype vars[] = {
96   {&do_light,   "light",   "Light",   DEF_LIGHT,   t_Bool},
97   {&do_wire,    "wire",    "Wire",    DEF_WIRE,    t_Bool},
98   {&do_texture, "texture", "Texture", DEF_TEXTURE, t_Bool},
99 };
100
101 static OptionStruct desc[] =
102 {
103   {"-/+ light",   "whether to do enable lighting (slower)"},
104   {"-/+ wire",    "whether to do use wireframe instead of filled (faster)"},
105   {"-/+ texture", "whether to apply a texture (slower)"},
106 };
107
108 ENTRYPOINT ModeSpecOpt atunnel_opts = {countof(opts), opts, countof(vars), vars, desc};
109
110 #ifdef USE_MODULES
111 ModStruct   atunnel_description =
112 {"atunnel", "init_atunnel", "draw_atunnel", NULL,
113  "draw_atunnel", "init_atunnel", "free_atunnel", &atunnel_opts,
114  1000, 1, 2, 1, 4, 1.0, "",
115  "OpenGL advanced tunnel screensaver", 0, NULL};
116 #endif
117
118 /* structure for holding the screensaver data */
119 typedef struct {
120   int screen_width, screen_height;
121   GLXContext *glx_context;
122   Window window;
123   struct tunnel_state *ts;
124   GLuint texture[MAX_TEXTURE]; /* texture id: GL world */
125 } atunnelstruct;
126
127 static atunnelstruct *Atunnel = NULL;
128
129 /*=================== Load Texture =========================================*/
130 static void LoadTexture(ModeInfo * mi,
131                         const unsigned char *data, unsigned long size,
132                         int t_num)
133 {
134 #if defined( I_HAVE_XPM )
135         atunnelstruct *sa = &Atunnel[MI_SCREEN(mi)];
136         XImage *teximage;    /* Texture data */
137  
138         if ((teximage = image_data_to_ximage(MI_DISPLAY(mi), MI_VISUAL(mi),
139                                              data, size))
140             == None) {
141             (void) fprintf(stderr, "Error reading the texture.\n");
142             glDeleteTextures(1, &sa->texture[t_num]);
143             do_texture = False;
144 #ifdef STANDALONE
145             exit(0);
146 #else
147             return;
148 #endif
149         }
150
151 #ifdef HAVE_GLBINDTEXTURE
152         glBindTexture(GL_TEXTURE_2D, sa->texture[t_num]);
153 #endif /* HAVE_GLBINDTEXTURE */
154         glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
155         clear_gl_error();
156         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, teximage->width, teximage->height, 
157                  0, GL_RGBA, GL_UNSIGNED_BYTE, teximage->data);
158         check_gl_error("texture");
159
160         /* Texture parameters, LINEAR scaling for better texture quality */
161         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 
162         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 
163
164         XDestroyImage(teximage);
165 #else /* !I_HAVE_XPM */
166         do_texture = False;
167 #endif /* !I_HAVE_XPM */
168
169
170 /*=================== Main Initialization ==================================*/
171 static void Init(ModeInfo * mi)
172 {
173         atunnelstruct *sa = &Atunnel[MI_SCREEN(mi)];
174         GLfloat light_ambient[] = {1.0, 1.0, 1.0, 1.0};
175         GLfloat light_diffuse[] = {1.0, 1.0, 1.0, 1.0};
176         GLfloat light_specular[] = {1.0, 1.0, 1.0, 1.0};
177         GLfloat light_position[] = {0.0, 0.0, 1.0, 0.0};
178         GLfloat fogColor[4] = {0.8, 0.8, 0.8, 1.0};
179
180         if (do_texture)
181         {
182                 glGenTextures(MAX_TEXTURE, sa->texture);
183                 LoadTexture(mi, tunnel0_png, sizeof(tunnel0_png),0);
184                 LoadTexture(mi, tunnel1_png, sizeof(tunnel1_png),1);
185                 LoadTexture(mi, tunnel2_png, sizeof(tunnel2_png),2);
186                 LoadTexture(mi, tunnel3_png, sizeof(tunnel3_png),3);
187                 LoadTexture(mi, tunnel4_png, sizeof(tunnel4_png),4);
188                 LoadTexture(mi, tunnel5_png, sizeof(tunnel5_png),5);
189                 glEnable(GL_TEXTURE_2D);
190         }
191         sa->ts = atunnel_InitTunnel();
192         
193         /* Set lighting parameters */
194         if (do_light)
195         {
196                 glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient);
197                 glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse);
198                 glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular);
199                 glLightfv(GL_LIGHT0, GL_POSITION, light_position);
200
201                 /* Enable light 0 */
202                 glEnable(GL_LIGHT0);
203                 glDepthFunc(GL_LESS);
204         
205                 glEnable(GL_LIGHTING);
206         }
207
208 # ifdef HAVE_JWZGLES /* #### glPolygonMode other than GL_FILL unimplemented */
209     do_wire = 0;
210 # endif
211
212         if (do_wire) {
213                 glDisable(GL_NORMALIZE);
214                 glDisable(GL_CULL_FACE);
215                 glDisable(GL_DEPTH_TEST);
216                 glDisable(GL_TEXTURE_2D);
217                 glPolygonMode(GL_FRONT,GL_LINE);
218                 glPolygonMode(GL_BACK,GL_LINE);
219         }
220         else
221         {
222                 glEnable(GL_DEPTH_TEST);
223                 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
224
225                 /* Enable fog */
226                 glFogi(GL_FOG_MODE, GL_EXP);
227                 glFogfv(GL_FOG_COLOR, fogColor);
228                 glFogf(GL_FOG_DENSITY, 0.3);
229                 glEnable(GL_FOG);
230         
231                 /* Cull face */
232                 glCullFace(GL_FRONT);
233                 glEnable(GL_CULL_FACE);
234         }
235         
236         glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
237 }
238
239
240 /* Standard reshape function */
241 ENTRYPOINT void
242 reshape_atunnel(ModeInfo *mi, int width, int height)
243 {
244   double h = (GLfloat) height / (GLfloat) width;  
245   int y = 0;
246
247   if (width > height * 2) {   /* tiny window: show middle */
248     height = width;
249     y = -height/2;
250     h = height / (GLfloat) width;
251   }
252
253   glViewport(0, y, width, height);
254   glMatrixMode(GL_PROJECTION);
255   glLoadIdentity();
256   glFrustum(-0.1*(1/h), 0.1*(1/h), -0.1, 0.1, 0.1, 10);
257   glMatrixMode(GL_MODELVIEW);
258 }
259
260 /* draw the screensaver once */
261 ENTRYPOINT void draw_atunnel(ModeInfo * mi)
262 {
263         atunnelstruct *sa = &Atunnel[MI_SCREEN(mi)];
264         Display    *display = MI_DISPLAY(mi);
265         Window      window = MI_WINDOW(mi);
266
267         if (!sa->glx_context)
268                 return;
269
270         glXMakeCurrent(display, window, *(sa->glx_context));
271
272         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
273
274         glLoadIdentity();
275
276         atunnel_DrawTunnel(sa->ts, do_texture, do_light, sa->texture);
277         atunnel_SplashScreen(sa->ts, do_wire, do_texture, do_light);
278
279         glFlush();  
280         /* manage framerate display */
281         if (MI_IS_FPS(mi)) do_fps (mi);
282         glXSwapBuffers(display, window);
283
284 }
285
286
287 /* xscreensaver initialization routine */
288 ENTRYPOINT void init_atunnel(ModeInfo * mi)
289 {
290   int screen = MI_SCREEN(mi);
291   atunnelstruct *sa;
292
293   MI_INIT(mi, Atunnel);
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 free_atunnel(ModeInfo * mi)
308 {
309 #if 0
310   atunnelstruct *sa = &Atunnel[MI_SCREEN(mi)];
311   FreeTunnel(sa->ts);
312 #endif
313 }
314
315 XSCREENSAVER_MODULE ("Atunnel", atunnel)
316
317 #endif