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