1 /* -*- Mode: C; tab-width: 4 -*- */
2 /* pulsar --- pulsar module for xscreensaver */
4 * Permission to use, copy, modify, and distribute this software and its
5 * documentation for any purpose and without fee is hereby granted,
6 * provided that the above copyright notice appear in all copies and that
7 * both that copyright notice and this permission notice appear in
8 * supporting documentation.
10 * This file is provided AS IS with no warranties of any kind. The author
11 * shall have no liability with respect to the infringement of copyrights,
12 * trade secrets or any patents by this file or any part thereof. In no
13 * event will the author be liable for any lost revenue or profits or
14 * other special, indirect and consequential damages.
17 * 4-Apr-1999: dek@cgl.ucsf.edu Created module "pulsar"
26 * due to a Bug/feature in VMS X11/Intrinsic.h has to be placed before xlock.
27 * otherwise caddr_t is not defined correctly
30 #include <X11/Intrinsic.h>
33 # define PROGCLASS "Screensaver"
34 # define HACK_INIT init_screensaver
35 # define HACK_DRAW draw_screensaver
36 # define screensaver_opts xlockmore_opts
37 #define DEFAULTS "*light: False \n" \
41 "*antialias: False \n" \
42 "*texture: False \n" \
43 "*texture_quality: False \n" \
46 "*doDepth: False \n" \
48 # include "xlockmore.h" /* from the xscreensaver distribution */
49 #else /* !STANDALONE */
50 # include "xlock.h" /* from the xlockmore distribution */
51 #endif /* !STANDALONE */
53 #ifdef USE_GL /* whole file */
57 # ifndef PIXEL_ALREADY_TYPEDEFED
58 # define PIXEL_ALREADY_TYPEDEFED /* Sigh, Xmu/Drawing.h needs this... */
64 # include <X11/Xmu/Drawing.h>
66 # include <Xmu/Drawing.h>
78 /* Functions for loading and storing textures */
80 #define checkImageWidth 64
81 #define checkImageHeight 64
92 /* Functions for handling the frames per second timer */
96 #define SAMPLE_FRAMES 10
100 static int FrameCounter = 0;
101 static double oldtime=-1., newtime=-1.;
102 static char FPSstring[1024]="FPS: NONE";
104 static float x_pos=0, y_pos=0;
106 #define FONT "-*-courier-medium-r-normal-*-240-*"
110 #define NUM_TRIANGLES 5
111 static float scale_x=1, scale_y=1, scale_z=1;
112 static int frame = 0;
118 GLfloat dtx, dty, dtz;
119 GLfloat drx, dry, drz;
122 struct triangle triangles[NUM_TRIANGLES];
127 #define countof(x) (sizeof((x))/sizeof((*x)))
132 int global_width=WIDTH, global_height=HEIGHT;
135 static XrmOptionDescRec opts[] = {
136 {"-light", ".pulsar.light", XrmoptionNoArg, (caddr_t) "true" },
137 {"+light", ".pulsar.light", XrmoptionNoArg, (caddr_t) "false" },
138 {"-wire", ".pulsar.wire", XrmoptionNoArg, (caddr_t) "true" },
139 {"+wire", ".pulsar.wire", XrmoptionNoArg, (caddr_t) "false" },
140 {"-blend", ".pulsar.blend", XrmoptionNoArg, (caddr_t) "true" },
141 {"+blend", ".pulsar.blend", XrmoptionNoArg, (caddr_t) "false" },
142 {"-fog", ".pulsar.fog", XrmoptionNoArg, (caddr_t) "true" },
143 {"+fog", ".pulsar.fog", XrmoptionNoArg, (caddr_t) "false" },
144 {"-antialias", ".pulsar.antialias", XrmoptionNoArg, (caddr_t) "true" },
145 {"+antialias", ".pulsar.antialias", XrmoptionNoArg, (caddr_t) "false" },
146 {"-texture", ".pulsar.texture", XrmoptionNoArg, (caddr_t) "true" },
147 {"+texture", ".pulsar.texture", XrmoptionNoArg, (caddr_t) "false" },
148 {"-texture_quality", ".pulsar.texture_quality", XrmoptionNoArg, (caddr_t) "true" },
149 {"+texture_quality", ".pulsar.texture_quality", XrmoptionNoArg, (caddr_t) "false" },
150 {"-mipmap", ".pulsar.mipmap", XrmoptionNoArg, (caddr_t) "true" },
151 {"+mipmap", ".pulsar.mipmap", XrmoptionNoArg, (caddr_t) "false" },
152 {"-fps", ".pulsar.fps", XrmoptionNoArg, (caddr_t) "true" },
153 {"+fps", ".pulsar.fps", XrmoptionNoArg, (caddr_t) "false" },
154 {"-do_depth", ".pulsar.doDepth", XrmoptionNoArg, (caddr_t) "true" },
155 {"+do_depth", ".pulsar.doDepth", XrmoptionNoArg, (caddr_t) "false" },
158 #define DEF_LIGHT "False"
159 #define DEF_WIRE "False"
160 #define DEF_BLEND "True"
161 #define DEF_FOG "False"
162 #define DEF_ANTIALIAS "False"
163 #define DEF_TEXTURE "False"
164 #define DEF_TEXTURE_QUALITY "False"
165 #define DEF_MIPMAP "False"
166 #define DEF_FPS "False"
167 #define DEF_DO_DEPTH "False"
173 static int do_antialias;
174 static int do_texture;
175 static int do_texture_quality;
176 static int do_mipmap;
180 static argtype vars[] = {
181 {(caddr_t *) &do_light, "light", "Light", DEF_LIGHT, t_Bool},
182 {(caddr_t *) &do_wire, "wire", "Wire", DEF_WIRE, t_Bool},
183 {(caddr_t *) &do_blend, "blend", "Blend", DEF_BLEND, t_Bool},
184 {(caddr_t *) &do_fog, "fog", "Fog", DEF_FOG, t_Bool},
185 {(caddr_t *) &do_antialias, "antialias", "Antialias", DEF_ANTIALIAS, t_Bool},
186 {(caddr_t *) &do_texture, "texture", "Texture", DEF_TEXTURE, t_Bool},
187 {(caddr_t *) &do_texture_quality, "texture_quality", "Texture_quality", DEF_TEXTURE_QUALITY, t_Bool},
188 {(caddr_t *) &do_mipmap, "mipmap", "Mipmap", DEF_MIPMAP, t_Bool},
189 {(caddr_t *) &do_fps, "fps", "fps", DEF_FPS, t_Bool},
190 {(caddr_t *) &do_depth, "doDepth", "DoDepth", DEF_DO_DEPTH, t_Bool},
194 ModeSpecOpt screensaver_opts = {countof(opts), opts, countof(vars), vars, NULL};
197 ModStruct screensaver_description =
198 {"screensaver", "init_screensaver", "draw_screensaver", "release_screensaver",
199 "draw_screensaver", "init_screensaver", NULL, &screensaver_opts,
200 1000, 1, 2, 1, 4, 1.0, "",
201 "OpenGL screensaver", 0, NULL};
205 /* structure for holding the screensaver data */
207 int screen_width, screen_height;
208 GLXContext *glx_context;
213 static screensaverstruct *Screensaver = NULL;
219 XFontStruct *fontInfo;
221 int first=0, last=255;
223 Dpy = XOpenDisplay(NULL);
224 fontInfo = XLoadQueryFont(Dpy, FONT);
225 if (fontInfo == NULL)
227 fprintf(stderr, "Failed to load font %s\n", FONT);
232 first = fontInfo->min_char_or_byte2;
233 last = fontInfo->max_char_or_byte2;
235 base = glGenLists((GLuint) last+1);
237 fprintf (stderr, "out of display lists\n");
240 glXUseXFont(id, first, last-first+1, base+first);
244 void PrintString(float x, float y, char *string)
248 /* save the current state */
249 /* note: could be expensive! */
250 glPushAttrib(GL_ALL_ATTRIB_BITS);
251 glMatrixMode(GL_PROJECTION);
253 gluOrtho2D(0, global_width, 0, global_height);
254 glMatrixMode(GL_MODELVIEW);
257 /* disable lighting and texturing when drawing bitmaps! */
258 glDisable(GL_TEXTURE_2D);
259 glDisable(GL_LIGHTING);
262 /* draw a black background */
266 glRasterPos2f( x, y);
267 len = (int) strlen(string);
268 for (i = 0; i < len; i++) {
269 glCallList(base+string[i]);
272 /* clean up after our state changes */
279 #ifdef GETTIMEOFDAY_TWO_ARGS
281 gettimeofday(&now, &tzp);
285 return (double) (now.tv_sec + (((double) now.tv_usec) * 0.000001));
290 /* every SAMPLE_FRAMES frames, get the time and use it to get the
292 if (!(FrameCounter % SAMPLE_FRAMES)) {
295 sprintf(FPSstring, "FPS: %.02f", SAMPLE_FRAMES/(newtime-oldtime));
298 PrintString(x_pos,y_pos,FPSstring);
303 GLubyte *Generate_Image(int *width, int *height, int *format)
309 *width = checkImageWidth;
310 *height = checkImageHeight;
311 result = (GLubyte *)malloc(4 * *width * *height);
314 for (i = 0; i < checkImageWidth; i++) {
315 for (j = 0; j < checkImageHeight; j++) {
316 c = (((((i&0x8)==0))^(((j&0x8))==0)))*255;
317 result[counter++] = (GLubyte) c;
318 result[counter++] = (GLubyte) c;
319 result[counter++] = (GLubyte) c;
320 result[counter++] = (GLubyte) 255;
332 /* Load a TIFF texture: requires libtiff */
333 uint32 *LoadTIFF(char *filename, int *width, int *height, int *format)
341 tif = TIFFOpen(filename, "r");
343 fprintf(stderr, "Problem showing %s\n", filename);
344 return Generate_Image(&width, &height, &format);
346 if (TIFFRGBAImageBegin(&img, tif, 0, emsg)) {
347 npixels = (tsize_t) (img.width * img.height);
348 raster = (uint32 *) _TIFFmalloc(npixels * (tsize_t) sizeof(uint32));
349 if (raster != NULL) {
350 if (TIFFRGBAImageGet(&img, raster, img.width, img.height) == 0) {
351 TIFFError(filename, emsg);
352 return Generate_Image(&width, &height, &format);
355 TIFFRGBAImageEnd(&img);
357 TIFFError(filename, emsg);
358 return Generate_Image(&width, &height, &format);
362 *height = img.height;
371 /* Load a modified version of PPM format with an extra byte for alpha */
372 GLubyte *LoadPPM4(const char *filename, int *width, int *height, int *format)
379 fp = fopen(filename, "rb");
382 fprintf(stderr, "Unable to open file '%s'\n", filename);
383 return Generate_Image(width, height, format);
386 if (!fgets(buff, sizeof(buff), fp))
389 return Generate_Image(width, height, format);
392 if (buff[0] != '6' || buff[1] != 'P')
394 fprintf(stderr, "Invalid image format (must be `6P')\n");
395 return Generate_Image(width, height, format);
398 result = malloc(sizeof(PPMImage));
401 fprintf(stderr, "Unable to allocate memory\n");
402 return Generate_Image(width, height, format);
407 fgets(buff, sizeof(buff), fp);
409 while (buff[0] == '#');
411 if (sscanf(buff, "%d %d", &result->sizeX, &result->sizeY) != 2)
413 fprintf(stderr, "Error loading image `%s'\n", filename);
414 return Generate_Image(width, height, format);
417 if (fscanf(fp, "%d", &maxval) != 1)
419 fprintf(stderr, "Error loading image `%s'\n", filename);
420 return Generate_Image(width, height, format);
423 while (fgetc(fp) != '\n')
426 result->data = (GLubyte *)malloc(4 * result->sizeX * result->sizeY);
429 fprintf(stderr, "Unable to allocate memory\n");
433 if (fread(result->data, 4 * result->sizeX, result->sizeY, fp) != result->sizeY)
435 fprintf(stderr, "Error loading image `%s'\n", filename);
436 return Generate_Image(width, height, format);
441 *width = result->sizeX;
442 *height = result->sizeY;
447 /* Load a plain PPM image */
448 GLubyte *LoadPPM(const char *filename, int *width, int *height, int *format)
455 fp = fopen(filename, "rb");
458 fprintf(stderr, "Unable to open file '%s'\n", filename);
459 return Generate_Image(width, height, format);
462 if (!fgets(buff, sizeof(buff), fp))
465 return Generate_Image(width, height, format);
468 if (buff[0] != 'P' || buff[1] != '6')
470 fprintf(stderr, "Invalid image format (must be `P6')\n");
471 return Generate_Image(width, height, format);
474 result = malloc(sizeof(PPMImage));
477 fprintf(stderr, "Unable to allocate memory\n");
478 return Generate_Image(width, height, format);
483 fgets(buff, sizeof(buff), fp);
485 while (buff[0] == '#');
487 if (sscanf(buff, "%d %d", &result->sizeX, &result->sizeY) != 2)
489 fprintf(stderr, "Error loading image `%s'\n", filename);
490 return Generate_Image(width, height, format);
493 if (fscanf(fp, "%d", &maxval) != 1)
495 fprintf(stderr, "Error loading image `%s'\n", filename);
496 return Generate_Image(width, height, format);
499 while (fgetc(fp) != '\n')
502 result->data = (GLubyte *)malloc(3 * result->sizeX * result->sizeY);
505 fprintf(stderr, "Unable to allocate memory\n");
506 return Generate_Image(width, height, format);
509 if (fread(result->data, 3 * result->sizeX, result->sizeY, fp) != result->sizeY)
511 fprintf(stderr, "Error loading image `%s'\n", filename);
512 return Generate_Image(width, height, format);
517 *width = result->sizeX;
518 *height = result->sizeY;
523 /* Create a texture in OpenGL. First an image is loaded
524 and stored in a raster buffer, then it's */
525 void Create_Texture(char *filename)
532 fprintf(stdout, "Loading texture '%s'\n", filename);
534 if ( !strncmp((filename+strlen(filename)-3), "ppm", 3))
535 image = LoadPPM(filename, &width, &height, &format);
536 else if ( !strncmp((filename+strlen(filename)-4), "ppm4", 4))
537 image = LoadPPM4(filename, &width, &height, &format);
539 else if ( !strncmp((filename+strlen(filename)-4), "tiff", 4))
540 image = (GLubyte *)LoadTIFF(filename, &width, &height, &format);
543 fprintf(stderr, "Unknown file format extension: '%s'\n", filename);
544 image = Generate_Image(&width, &height, &format);
547 /* GL_MODULATE or GL_DECAL depending on what you want */
548 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
549 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
550 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
551 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
553 if (do_texture_quality) {
554 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
555 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
556 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
559 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
560 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
561 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
565 a=gluBuild2DMipmaps(GL_TEXTURE_2D, format, width, height, format, GL_UNSIGNED_BYTE, image);
567 glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0,
568 format, GL_UNSIGNED_BYTE, image);
573 void resetProjection(void) {
574 glMatrixMode(GL_PROJECTION);
576 glFrustum(-1, 1, -1, 1, 1, 100);
577 glMatrixMode(GL_MODELVIEW);
582 void GenerateTriangle(void)
586 tri_list = glGenLists(1);
587 glNewList(tri_list,GL_COMPILE);
588 /* glBegin(GL_TRIANGLES); */
590 glColor4f(1,0,0,.4); glNormal3f(0,0,1); glTexCoord2f(0,0); glVertex2f(-1, -1);
591 glColor4f(0,1,0,.4); glNormal3f(0,0,1); glTexCoord2f(0,1); glVertex2f(-1, 1);
592 glColor4f(0,0,1,.4); glNormal3f(0,0,1); glTexCoord2f(1,1); glVertex2f( 1, 1);
593 glColor4f(1,1,1,1); glNormal3f(0,0,1); glTexCoord2f(1,0); glVertex2f( 1, -1);
597 for (i=0; i < NUM_TRIANGLES; i++)
599 triangles[i].rx = 0.;
600 triangles[i].ry = 0.;
601 triangles[i].rz = 0.;
602 triangles[i].tx = 0.;
603 triangles[i].ty = 0.;
604 triangles[i].tz = -10;
606 triangles[i].drx = drand48() * 5.;
607 triangles[i].dry = drand48() * 5.;
608 triangles[i].drz = 0;
612 void initializeGL(GLsizei width, GLsizei height)
614 GLfloat fogColor[4] = { 0.1, 0.1, 0.1, 0.1 };
617 global_height=height;
619 glViewport( 0, 0, width, height );
623 glEnable(GL_DEPTH_TEST);
630 glEnable(GL_LINE_SMOOTH);
635 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
640 glShadeModel(GL_SMOOTH);
641 glEnable(GL_COLOR_MATERIAL);
642 glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
646 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
648 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
652 glFogi(GL_FOG_MODE, GL_LINEAR);
653 glFogfv(GL_FOG_COLOR, fogColor);
654 glFogf(GL_FOG_DENSITY, 0.35);
655 /* glHint(GL_FOG_HINT, GL_FASTEST); */
656 glFogf(GL_FOG_START, 50.0);
657 glFogf(GL_FOG_END, 100.0);
663 Create_Texture(Textures[0]);
668 void drawTriangles(void) {
670 for (i=0; i < NUM_TRIANGLES; i++)
673 glTranslatef(triangles[i].tx,0,0);
674 glTranslatef(0,triangles[i].ty,0);
675 glTranslatef(0,0,triangles[i].tz);
676 glRotatef(triangles[i].rx, 1,0,0);
677 glRotatef(triangles[i].ry, 0,1,0);
678 glRotatef(triangles[i].rz, 0,0,1);
679 glCallList(tri_list);
682 triangles[i].rx += triangles[i].drx;
683 triangles[i].ry += triangles[i].dry;
684 triangles[i].rz += triangles[i].drz;
689 GLvoid drawScene(GLvoid)
692 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
694 /* we have to do this here because the FPS meter turns these 3 features off!! */
697 glEnable(GL_LIGHTING);
702 glEnable(GL_TEXTURE_2D);
707 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
712 glScalef(scale_x, scale_y, scale_z);
715 scale_x = cos(frame/360.)*10.;
716 scale_y = sin(frame/360.)*10.;
724 void draw_screensaver(ModeInfo * mi)
726 screensaverstruct *gp = &Screensaver[MI_SCREEN(mi)];
727 Display *display = MI_DISPLAY(mi);
728 Window window = MI_WINDOW(mi);
730 if (!gp->glx_context)
733 glXMakeCurrent(display, window, *(gp->glx_context));
735 glXSwapBuffers(display, window);
738 /* Standard reshape function */
740 reshape(int width, int height)
742 glViewport( 0, 0, global_width, global_height );
747 init_screensaver(ModeInfo * mi)
749 int screen = MI_SCREEN(mi);
751 screensaverstruct *gp;
753 if (Screensaver == NULL) {
754 if ((Screensaver = (screensaverstruct *) calloc(MI_NUM_SCREENS(mi), sizeof (screensaverstruct))) == NULL)
757 gp = &Screensaver[screen];
759 gp->window = MI_WINDOW(mi);
760 if ((gp->glx_context = init_GL(mi)) != NULL) {
761 reshape(MI_WIDTH(mi), MI_HEIGHT(mi));
762 initializeGL(MI_WIDTH(mi), MI_HEIGHT(mi));
769 /* all sorts of nice cleanup code should go here! */
770 void release_screensaver(ModeInfo * mi)
773 if (Screensaver != NULL) {
774 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
775 /* screensaverstruct *gp = &Screensaver[screen];*/
777 (void) free((void *) Screensaver);