1 /*
2  * Copyright (C) 2003 Alex Zolotov <nightradio@knoppix.ru>
3  * Mucked with by Tugrul Galatali <tugrul@galatali.com>
4  *
5  * MatrixView is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation.
8  *
9  * MatrixView is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17  */
18 
19 // MatrixView screen saver
20 
21 #include <math.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <time.h>
26 #include <GL/gl.h>
27 #include <GL/glu.h>
28 #include <sys/time.h>
29 
30 #include "driver.h"
31 #include "loadTexture.h"
32 #include "matrixview_textures.h"
33 #include "rsDefines.h"
34 #include "rsRand.h"
35 
36 const char *hack_name = "MatrixView";
37 
38 int cycleScene = 5;
39 int cycleMatrix = 5;
40 float contrast = -1;
41 
42 // Settings for our light.  Try playing with these (or add more lights).
43 float Light_Ambient[] = { 0.1f, 0.1f, 0.1f, 1.0f };
44 float Light_Diffuse[] = { 1.2f, 1.2f, 1.2f, 1.0f };
45 float Light_Position[] = { 2.0f, 2.0f, 0.0f, 1.0f };
46 
47 unsigned char *font;
48 unsigned char *pics;
49 
50 unsigned char flare[16] = { 0, 0, 0, 0,
51 	0, 180, 0, 0,
52 	0, 0, 0, 0,
53 	0, 0, 0, 0
54 };
55 
56 #define MAX_TEXT_X 320
57 #define MAX_TEXT_Y 240
58 int text_x = 90;
59 int text_y = 70;
60 #define _text_x text_x/2
61 #define _text_y text_y/2
62 
63 // Scene position
64 #define Z_Off -128.0f
65 #define Z_Depth 8
66 
67 unsigned char speed[MAX_TEXT_X];
68 unsigned char text[MAX_TEXT_X * MAX_TEXT_Y + MAX_TEXT_X];
69 unsigned char text_light[MAX_TEXT_X * MAX_TEXT_Y + MAX_TEXT_X];	//255 - white; 254 - none;
70 float text_depth[MAX_TEXT_X * MAX_TEXT_Y + MAX_TEXT_X];
71 
72 unsigned char *pic = NULL;
73 float bump_pic[MAX_TEXT_X * MAX_TEXT_Y + MAX_TEXT_X];
74 int exit_mode = 0;		//0 - none; 1 - exit mode (explode main text);
75 float r1 = 0.2, r2 = 1, r3 = 0.4;
76 float texture_add = 0;
77 float exit_angle = 0;
78 long one_frame = 60;
79 
80 int pic_mode = 0;		//0 - none; 1 - pic fade in; 2 - pic fade out;
81 int pic_fade = 0;
82 
83 float *pts;
84 float *texcoords;
85 unsigned char *colors;
86 
87 #include <magick/api.h>
88 #include <wand/magick-wand.h>
89 #include <dirent.h>
90 #include <sys/types.h>
91 #include <sys/stat.h>
92 #include <unistd.h>
93 
94 char *dirName = NULL;
95 DIR *imageDir;
96 
97 unsigned char *next_pic = NULL;
98 
99 // Directory scanning + image loading code in a separate function callable either from loadNextImage or another thread if pthreads is available.
loadNextImageFromDisk()100 void loadNextImageFromDisk() {
101 	MagickWand *magick_wand = NewMagickWand();
102 	ExceptionInfo exception;
103 	int dirLoop = 0;
104 
105 	GetExceptionInfo (&exception);
106 
107 	int imageLoaded = 0;
108 	do {
109 		struct dirent *file;
110 
111 		if (!imageDir) {
112 			if (dirLoop) {
113 				dirName = NULL;
114 				return;
115 			}
116 
117 			imageDir = opendir (dirName);
118 			dirLoop = 1;
119 		}
120 
121 		file = readdir (imageDir);
122 		if (file) {
123 			struct stat fileStat;
124 			char *full_path_and_name = (char *)malloc(strlen(dirName) + 1 + strlen(file->d_name) + 1);
125 
126 			if (full_path_and_name) {
127 				sprintf(full_path_and_name, "%s/%s", dirName, file->d_name);
128 
129 				if (!stat(full_path_and_name, (struct stat *)&fileStat)) {
130 					if (S_ISREG(fileStat.st_mode)) {
131 						if (MagickReadImage(magick_wand, full_path_and_name) == MagickFalse) {
132 							char *description;
133 							ExceptionType severity;
134 
135 							description = MagickGetException (magick_wand, &severity);
136 							fprintf (stderr, "Error loading %s: %s\n", full_path_and_name, description);
137 							description = (char *)MagickRelinquishMemory (description);
138 						} else {
139 							imageLoaded = 1;
140 						}
141 					}
142 				}
143 
144 				free(full_path_and_name);
145 			} else {
146 				fprintf (stderr, "Out of memory\n");
147 			}
148 		} else {
149 			closedir(imageDir);
150 			imageDir = NULL;
151 		}
152 	} while (!imageLoaded);
153 
154 	MagickScaleImage (magick_wand, text_x, text_y);
155 	MagickNormalizeImage (magick_wand);
156 	MagickContrastImage (magick_wand, MagickTrue);
157 	MagickNegateImage (magick_wand, MagickFalse);
158 
159 	if (!next_pic)
160 		next_pic = (unsigned char *)malloc (text_x * text_y);
161 
162 	ExportImagePixels (GetImageFromMagickWand(magick_wand), 0, 0, text_x, text_y, "I", CharPixel, next_pic, &exception);
163 
164 	magick_wand = DestroyMagickWand (magick_wand);
165 }
166 
167 #include <pthread.h>
168 pthread_t *imageLoadingThread = NULL;
169 pthread_mutex_t *next_pic_mutex;
170 pthread_cond_t *next_pic_cond;
171 volatile int exiting = 0;
172 
imageLoadingThreadMain(void * arg)173 void *imageLoadingThreadMain(void *arg) {
174 	do {
175 		loadNextImageFromDisk();
176 
177 		pthread_cond_wait(next_pic_cond, next_pic_mutex);
178 	} while (!exiting);
179 
180 	pthread_exit(NULL);
181 
182 	return NULL;
183 }
184 
loadNextImage()185 void loadNextImage ()
186 {
187 	if (dirName) {
188 		if (!imageLoadingThread) {
189 			next_pic_mutex = (pthread_mutex_t *)malloc(sizeof(pthread_mutex_t));
190 			pthread_mutex_init(next_pic_mutex, NULL);
191 
192 			pthread_mutex_lock(next_pic_mutex);
193 
194 			next_pic_cond = (pthread_cond_t *)malloc(sizeof(pthread_cond_t));
195 			pthread_cond_init(next_pic_cond, NULL);
196 
197 			imageLoadingThread = (pthread_t *)malloc(sizeof(pthread_t));
198 			pthread_create(imageLoadingThread, NULL, imageLoadingThreadMain, NULL);
199 		} else {
200 			pthread_mutex_lock(next_pic_mutex);
201 			if (pic) {
202 				unsigned char *tmp = next_pic;
203 				next_pic = pic;
204 				pic = tmp;
205 			} else {
206 				pic = next_pic;
207 				next_pic = NULL;
208 			}
209 			pthread_mutex_unlock(next_pic_mutex);
210 
211 			pthread_cond_signal(next_pic_cond);
212 		}
213 	} else {
214 		ExceptionInfo exception;
215 		Image *image = NULL, *scaled_image;
216 		ImageInfo *image_info;
217 
218 		GetExceptionInfo (&exception);
219 
220 		if (!pics)
221 			LOAD_TEXTURE (pics, cpics, cpics_compressedsize, cpics_size)
222 
223 		if ((text_x != 90) || (text_y != 70)) {
224 			if (!pic)
225 				pic = (unsigned char *)malloc (text_x * text_y);
226 
227 			image_info = CloneImageInfo ((ImageInfo *) NULL);
228 			image_info->size = AcquireMagickMemory(sizeof("90x70"));
229 			strcpy(image_info->size, "90x70");
230 			image = AcquireImage(image_info);
231 
232 			ImportImagePixels(image, 0, 0, 90, 70, "I", CharPixel, (unsigned char *)(pics + ((random () & 15) * (90 * 70))));
233 
234 			scaled_image = ScaleImage (image, text_x, text_y, &exception);
235 
236 			ExportImagePixels (scaled_image, 0, 0, text_x, text_y, "I", CharPixel, pic, &exception);
237 
238 			DestroyImage (image);
239 			DestroyImage (scaled_image);
240 		} else {
241 			if (!pics)
242 				LOAD_TEXTURE (pics, cpics, cpics_compressedsize, cpics_size)
243 
244 			pic = (unsigned char *)(pics + ((random () & 15) * (text_x * text_y)));
245 		}
246 	}
247 }
248 
draw_illuminatedchar(long num,float x,float y,float z)249 void draw_illuminatedchar (long num, float x, float y, float z)
250 {
251 	float tx, ty;
252 	long num2, num3;
253 
254 	num2 = num / 10;
255 	num3 = num - (num2 * 10);
256 	ty = (float)num2 / 7;
257 	tx = (float)num3 / 10;
258 	glNormal3f (0.0f, 0.0f, 1.0f);	// Needed for lighting
259 	glColor4f (0.9, 0.4, 0.3, .5);	// Basic polygon color
260 
261 	glTexCoord2f (tx, ty);
262 	glVertex3f (x, y, z);
263 	glTexCoord2f (tx + 0.1, ty);
264 	glVertex3f (x + 1, y, z);
265 	glTexCoord2f (tx + 0.1, ty + 0.166);
266 	glVertex3f (x + 1, y - 1, z);
267 	glTexCoord2f (tx, ty + 0.166);
268 	glVertex3f (x, y - 1, z);
269 }
270 
draw_flare(float x,float y,float z)271 void draw_flare (float x, float y, float z)	//flare
272 {
273 	glNormal3f (0.0f, 0.0f, 1.0f);	// Needed for lighting
274 	glColor4f (0.9, 0.4, 0.3, .8);	// Basic polygon color
275 
276 	glTexCoord2f (0, 0);
277 	glVertex3f (x - 1, y + 1, z);
278 	glTexCoord2f (0.75, 0);
279 	glVertex3f (x + 2, y + 1, z);
280 	glTexCoord2f (0.75, 0.75);
281 	glVertex3f (x + 2, y - 2, z);
282 	glTexCoord2f (0, 0.75);
283 	glVertex3f (x - 1, y - 2, z);
284 }
285 
draw_text()286 void draw_text ()
287 {
288 	int x, y;
289 	long p = 0;
290 	int c, c_pic;
291 
292 	if (pic_mode == 1)
293 		if (pic_fade < 255)
294 			pic_fade++;
295 
296 	if (pic_mode == 2)
297 		if (pic_fade > 0)
298 			pic_fade--;
299 
300 	int vp = 0, tp = 0, cp = 0;
301 	for (y = _text_y; y > -_text_y; y--) {
302 		for (x = -_text_x; x < _text_x; x++) {
303 			c = text_light[p] - (text[p] >> 1);
304 			c += pic_fade;
305 			if (c > 255)
306 				c = 255;
307 
308 			if (pic) {
309 				c_pic = pic[p] * contrast - (255 - pic_fade);
310 
311 				if (c_pic < 0)
312 					c_pic = 0;
313 
314 				c -= c_pic;
315 
316 				if (c < 0)
317 					c = 0;
318 
319 				bump_pic[p] = (255.0f - c_pic) / (256 / Z_Depth);
320 			} else {
321 				bump_pic[p] = Z_Depth;
322 			}
323 
324 			if (c > 10)
325 				if (text[p]) {
326 					long num = text[p] + 1;
327 					float light = c;
328 					const float z = text_depth[p] + bump_pic[p];
329 					float tx, ty;
330 					long num2, num3;
331 
332 					num &= 63;
333 					light = light / 255;	//light=7-light;num+=(light*60);
334 					num2 = num / 10;
335 					num3 = num - (num2 * 10);
336 					ty = (float)num2 / 7;
337 					tx = (float)num3 / 10;
338 
339 #define VA(tx, ty, x, y, z, light) \
340 	colors[cp++] = 0.9 * 255; colors[cp++] = 0.4 * 255; colors[cp++] = 0.3 * 255; colors[cp++] = light * 255; \
341 	texcoords[tp++] = tx; texcoords[tp++] = ty; \
342 	pts[vp++] = x; pts[vp++] = y; pts[vp++] = z;
343 
344 					VA(tx, ty, x, y, z, light);
345 					VA(tx + 0.1, ty, x + 1, y, z, light);
346 					VA(tx + 0.1, ty + 0.166, x + 1, y - 1, z, light);
347 					VA(tx, ty + 0.166, x, y - 1, z, light);
348 				}
349 
350 			if (exit_mode)
351 				text_depth[p] += (((float)text[p] - 128) / 2000);
352 			else if (text_depth[p] < 0.1)
353 				text_depth[p] = 0;
354 			else
355 				text_depth[p] /= 1.1;
356 
357 			p++;
358 		}
359 	}
360 
361 	glNormal3f (0.0f, 0.0f, 1.0f);	// Needed for lighting
362 
363 	glDrawArrays(GL_QUADS, 0, tp >> 1);
364 }
365 
draw_illuminatedtext(void)366 void draw_illuminatedtext (void)
367 {
368 	float x, y;
369 	long p = 0;
370 
371 	for (y = _text_y; y > -_text_y; y--) {
372 		for (x = -_text_x; x < _text_x; x++) {
373 			if (text_light[p] > 128)
374 				if (text_light[p + text_x] < 10)
375 					draw_illuminatedchar (text[p] + 1, x, y, text_depth[p] + bump_pic[p]);
376 			p++;
377 		}
378 	}
379 }
380 
draw_flares(void)381 void draw_flares (void)
382 {
383 	float x, y;
384 	long p = 0;
385 
386 	for (y = _text_y; y > -_text_y; y--) {
387 		for (x = -_text_x; x < _text_x; x++) {
388 			if (text_light[p] > 128)
389 				if (text_light[p + text_x] < 10)
390 					draw_flare (x, y, text_depth[p] + bump_pic[p]);
391 			p++;
392 		}
393 	}
394 }
395 
scroll(double dCurrentTime)396 void scroll (double dCurrentTime)
397 {
398 	unsigned int a, s, polovina;
399 	static double dLastCycle = -1;
400 	static double dLastMove = -1;
401 
402 	//====== CHANGING SCENE ======
403 	if (cycleScene > 0) {
404 		if (pic_mode == 1)
405 			if (dCurrentTime - dLastCycle > cycleScene) {
406 				pic_mode = 2;
407 
408 				if ((random () & 63) == 63)
409 					exit_mode = 1;
410 			}
411 
412 		if (dCurrentTime - dLastCycle > cycleScene + cycleMatrix)
413 			dLastCycle = dCurrentTime;
414 
415 		if (dCurrentTime == dLastCycle) {
416 			loadNextImage ();
417 
418 			// If a picture isn't available, don't switch modes and skip the cycleScene interval.
419 			if (pic)
420 				pic_mode = 1;
421 			else
422 				dLastCycle -= cycleScene;
423 
424 			if ((random () & 3) == 3)
425 				exit_mode = 0;
426 		}
427 	}
428 
429 	if (dCurrentTime - dLastMove > 1.0 / (text_y / 1.5)) {
430 		dLastMove = dCurrentTime;
431 
432 		polovina = (text_x * text_y) / 2;
433 		s = 0;
434 		for (a = (text_x * text_y) + text_x - 1; a > text_x; a--) {
435 			if (speed[s]) {
436 				text_light[a] = text_light[a - text_x];	//scroll light table down
437 			}
438 			s++;
439 			if (s >= text_x)
440 				s = 0;
441 		}
442 
443 		//============================
444 		//for (a = (text_x * text_y) + text_x - 1; a > text_x; a--) {
445 		//      text_light[a] = text_light[a - text_x]; //scroll light table down
446 		//}
447 		memmove ((void *)(&text_light[0] + text_x), (void *)&text_light, (text_x * text_y) - 1);
448 
449 		//for (a = 0; a < text_x; a++)
450 		//      text_light[a] = 253;    //clear top line (in light table)
451 		memset ((void *)&text_light, 253, text_x);
452 
453 		s = 0;
454 		for (a = polovina; a < (text_x * text_y); a++) {
455 			if (text_light[a] == 255)
456 				text_light[s] = text_light[s + text_x] >> 1;	//make black bugs in top line
457 
458 			s++;
459 
460 			if (s >= text_x)
461 				s = 0;
462 		}
463 	}
464 }
465 
make_change(double dCurrentTime)466 void make_change (double dCurrentTime)
467 {
468 	unsigned int r = random () & 0xFFFF;
469 
470 	r >>= 3;
471 	if (r < (text_x * text_y))
472 		text[r] += 133;	//random bugs
473 
474 	r = random () & 0xFFFF;
475 	r >>= 7;
476 	if (r < text_x)
477 		if (text_light[r] != 0)
478 			text_light[r] = 255;	//white bugs
479 
480 	scroll (dCurrentTime);
481 }
482 
hack_reshape(xstuff_t * XStuff)483 void hack_reshape (xstuff_t * XStuff)
484 {
485 	glViewport (0, 0, XStuff->windowWidth, XStuff->windowHeight);
486 
487 	glMatrixMode (GL_PROJECTION);
488 	glLoadIdentity ();
489 	//gluPerspective (45.0f, (GLfloat) XStuff->windowWidth / (GLfloat) XStuff->windowHeight, 0.1f, 150.0f);
490 	glFrustum(-_text_x, _text_x, -_text_y, _text_y, -Z_Off - Z_Depth, -Z_Off);
491 
492 	glMatrixMode (GL_MODELVIEW);
493 }
494 
load_texture()495 void load_texture ()
496 {
497 	long a;
498 
499 	LOAD_TEXTURE (font, cfont, cfont_compressedsize, cfont_size)
500 
501 	for (a = 0; a < 131072; a++) {
502 		if ((a >> 9) & 2)
503 			font[a] = font[a];
504 		else
505 			font[a] = font[a] >> 1;
506 	}
507 }
508 
make_text()509 void make_text ()
510 {
511 	long a;
512 	unsigned int r;
513 
514 	for (a = 0; a < (text_x * text_y); a++) {
515 		r = random () & 0xFFFF;
516 		text[a] = r;
517 	}
518 
519 	for (a = 0; a < text_x; a++)
520 		speed[a] = random () & 1;
521 }
522 
ourBuildTextures()523 void ourBuildTextures ()
524 {
525 	GLenum gluerr;
526 
527 	glBindTexture (GL_TEXTURE_2D, 1);
528 
529 	if ((gluerr = gluBuild2DMipmaps (GL_TEXTURE_2D, GL_RGBA8, 512, 256, GL_GREEN, GL_UNSIGNED_BYTE, (void *)font))) {
530 		fprintf (stderr, "GLULib%s\n", gluErrorString (gluerr));
531 		exit (-1);
532 	}
533 
534 	glBindTexture (GL_TEXTURE_2D, 2);
535 
536 	if ((gluerr = gluBuild2DMipmaps (GL_TEXTURE_2D, GL_RGBA8, 512, 256, GL_LUMINANCE, GL_UNSIGNED_BYTE, (void *)font))) {
537 		fprintf (stderr, "GLULib%s\n", gluErrorString (gluerr));
538 		exit (-1);
539 	}
540 
541 	FREE_TEXTURE (font)
542 
543 	glBindTexture (GL_TEXTURE_2D, 3);
544 
545 	if ((gluerr = gluBuild2DMipmaps (GL_TEXTURE_2D, GL_RGBA8, 4, 4, GL_LUMINANCE, GL_UNSIGNED_BYTE, (void *)flare))) {
546 		fprintf (stderr, "GLULib%s\n", gluErrorString (gluerr));
547 		exit (-1);
548 	}
549 
550 	// Some pretty standard settings for wrapping and filtering.
551 	glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
552 	glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
553 
554 	// We start with GL_DECAL mode.
555 	glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
556 }
557 
hack_init(xstuff_t * XStuff)558 void hack_init (xstuff_t * XStuff)	// Called right after the window is created, and OpenGL is initialized.
559 {
560 	load_texture ();
561 	make_text ();
562 
563 	MagickWandGenesis ();
564 
565 	ourBuildTextures ();
566 
567 	// Buffers for drawing the bulk of the characters using arrays
568 	pts = (float *)malloc(text_y * text_x * 3 * 4 * sizeof(float));
569 	texcoords = (float *)malloc(text_y * text_x * 2 * 4 * sizeof(float));
570 	colors = (unsigned char *)malloc(text_y * text_x * 4 * 4 * sizeof(unsigned char));
571 
572 	glVertexPointer(3, GL_FLOAT, 0, pts);
573 	glEnableClientState(GL_VERTEX_ARRAY);
574 
575 	glColorPointer(4, GL_UNSIGNED_BYTE, 0, colors);
576 	glEnableClientState(GL_COLOR_ARRAY);
577 
578 	glTexCoordPointer(2, GL_FLOAT, 0, texcoords);
579 	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
580 
581 	// Color to clear color buffer to.
582 	glClearColor (0.0f, 0.0f, 0.0f, 0.0f);
583 
584 	// Depth to clear depth buffer to; type of test.
585 	glClearDepth (1.0);
586 	glDepthFunc (GL_LESS);
587 
588 	// Enables Smooth Color Shading; try GL_FLAT for (lack of) fun.
589 	glShadeModel (GL_SMOOTH);
590 
591 	// Set up a light, turn it on.
592 	glLightfv (GL_LIGHT1, GL_POSITION, Light_Position);
593 	glLightfv (GL_LIGHT1, GL_AMBIENT, Light_Ambient);
594 	glLightfv (GL_LIGHT1, GL_DIFFUSE, Light_Diffuse);
595 	glEnable (GL_LIGHT1);
596 
597 	// A handy trick -- have surface material mirror the color.
598 	glColorMaterial (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
599 	glEnable (GL_COLOR_MATERIAL);
600 
601 	hack_reshape (XStuff);
602 }
603 
hack_cleanup(xstuff_t * XStuff)604 void hack_cleanup (xstuff_t * XStuff)
605 {
606 	if (imageLoadingThread) {
607 		// Try acquiring the lock first to make sure the thread is asleep and signallable. Otherwise the signal will miss the other thread and the pthread_join will hang.
608 		pthread_mutex_lock(next_pic_mutex);
609 
610 		exiting = 1;
611 		pthread_cond_signal(next_pic_cond);
612 
613 		pthread_mutex_unlock(next_pic_mutex);
614 
615 		pthread_join(*imageLoadingThread, NULL);
616 	}
617 
618 	free(pts);
619 	free(texcoords);
620 	free(colors);
621 }
622 
hack_draw(xstuff_t * XStuff,double currentTime,float frameTime)623 void hack_draw (xstuff_t * XStuff, double currentTime, float frameTime)
624 {
625 	glBindTexture (GL_TEXTURE_2D, 1);
626 	glEnable (GL_BLEND);
627 	glEnable (GL_TEXTURE_2D);
628 
629 	glDisable (GL_LIGHTING);
630 	glBlendFunc (GL_SRC_ALPHA, GL_ONE);
631 	glDisable (GL_DEPTH_TEST);
632 	glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR);
633 	glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
634 	glMatrixMode (GL_MODELVIEW);
635 	glLoadIdentity ();
636 	glTranslatef (0.0f, 0.0f, Z_Off);
637 
638 	// Clear the color and depth buffers.
639 	glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
640 
641 	if (exit_mode)
642 		exit_angle += 0.08;
643 	else
644 		exit_angle /= 1.1;
645 
646 	if (texture_add > 0)
647 		texture_add /= 1.05;
648 
649 	glRotatef (exit_angle, r1, r2, r3);
650 
651 	// OK, let's start drawing our planer quads.
652 	draw_text ();
653 
654 	glBindTexture (GL_TEXTURE_2D, 2);
655 	glBegin (GL_QUADS);
656 	draw_illuminatedtext ();
657 	glEnd ();
658 
659 	glBindTexture (GL_TEXTURE_2D, 3);
660 	glBegin (GL_QUADS);
661 	draw_flares ();
662 	glEnd ();
663 
664 	make_change (currentTime);
665 
666 	glLoadIdentity ();
667 	glMatrixMode (GL_PROJECTION);
668 }
669 
hack_handle_opts(int argc,char ** argv)670 void hack_handle_opts (int argc, char **argv)
671 {
672 	while (1) {
673 		int c;
674 
675 #ifdef HAVE_GETOPT_H
676 		static struct option long_options[] = {
677 			{"help", 0, 0, 'h'},
678 			DRIVER_OPTIONS_LONG
679 			{"images", 1, 0, 'i'},
680 			{"scene_interval", 1, 0, 's'},
681 			{"matrix_interval", 1, 0, 'm'},
682 			{"matrix_width", 1, 0, 'X'},
683 			{"matrix_height", 1, 0, 'Y'},
684 			{"contrast", 1, 0, 'c'},
685 			{0, 0, 0, 0}
686 		};
687 
688 		c = getopt_long (argc, argv, DRIVER_OPTIONS_SHORT "hs:m:X:Y:c:i:", long_options, NULL);
689 #else
690 		c = getopt (argc, argv, DRIVER_OPTIONS_SHORT "hs:m:X:Y:c:i:");
691 #endif
692 		if (c == -1)
693 			break;
694 
695 		switch (c) {
696 			DRIVER_OPTIONS_CASES case 'h':printf ("%s:"
697 #ifndef HAVE_GETOPT_H
698 							      " Not built with GNU getopt.h, long options *NOT* enabled."
699 #endif
700 							      "\n" DRIVER_OPTIONS_HELP "\t--images/-i <arg>\n\t--scene_interval/-s <arg>\n" "\t--matrix_interval/-m <arg>\n"
701 								  "\t--matrix_width/-X <arg>\n" "\t--matrix_height/-Y <arg>\n" "\t--contrast/-c <arg>\n", argv[0]);
702 
703 			exit (1);
704 
705 		case 'i':
706 			{
707 				struct stat fileStat;
708 
709 				if (!stat(optarg, (struct stat *)&fileStat)) {
710 					if (S_ISDIR(fileStat.st_mode)) {
711 						imageDir = opendir (optarg);
712 						if (imageDir) {
713 							dirName = (char *)malloc (strlen (optarg) + 1);
714 							strcpy (dirName, optarg);
715 						} else {
716 							fprintf (stderr, "--images: Could not open %s\n", optarg);
717 						}
718 					} else {
719 						fprintf(stderr, "--images: %s is not a directory\n", optarg);
720 					}
721 				} else {
722 					fprintf(stderr, "--images: Could not stat %s\n", optarg);
723 				}
724 			}
725 
726 			break;
727 		case 's':
728 			cycleScene = strtol_minmaxdef (optarg, 10, 0, 120, 1, 5, "--scene_interval: ");
729 			break;
730 		case 'm':
731 			cycleMatrix = strtol_minmaxdef (optarg, 10, 3, 120, 1, 5, "--matrix_interval: ");
732 			break;
733 		case 'X':
734 			text_x = strtol_minmaxdef (optarg, 10, 40, MAX_TEXT_X, 1, 90, "--matrix_width: ");
735 			break;
736 		case 'Y':
737 			text_y = strtol_minmaxdef (optarg, 10, 30, MAX_TEXT_Y, 1, 70, "--matrix_height: ");
738 			break;
739 		case 'c':
740 			contrast = strtol_minmaxdef (optarg, 10, 0, 100, 1, 75, "--contrast: ") / 100.0f;
741 			break;
742 		}
743 	}
744 
745 #ifdef HAVE_IMAGEMAGICK
746 	// If contrast is unset, set it to 0.75 for external images, 1 for internal.
747 	if (contrast == -1) {
748 		if (dirName)
749 			contrast = 0.75;
750 		else
751 			contrast = 1;
752 	}
753 #else
754 	// If contrast is unset, set it to 1.
755 	if (contrast == -1)
756 		contrast = 1;
757 
758 	if (cycleScene > 0) {
759 		if ((text_x != 90) || (text_y != 70)) {
760 			printf("%s: Not built with ImageMagick, can not scale images. Resetting matrix resolution to 90x70.\n", argv[0]);
761 
762 			text_x = 90;
763 			text_y = 70;
764 		}
765 	}
766 #endif
767 }
768 
769