fbab9df14ee2b98a3d7f7c9a74219cb955ef79b5
[shermanaquarium] / sherman-aquarium / shermans / screensaver.c
1
2 /* 
3
4    Sherman's aquarium - Screensaver part
5
6    Updated and partly rewritten for Sherman's aquarium v3.0.0 on
7    30th and 31st December 2003.
8
9    Jonas Aaberg <cja@gmx.net>
10
11 */
12
13
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <unistd.h>
17 #include <string.h>
18 #include <signal.h>
19 #include <time.h>
20 #include <glob.h>
21 #include <gdk-pixbuf/gdk-pixbuf.h>
22 #include <gdk/gdk.h>
23 #include <gdk/gdkx.h>
24 #include <SDL/SDL.h>
25 #include <X11/Xlib.h>
26
27
28
29 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
30 #define RMASK 0xff000000
31 #define GMASK 0x00ff0000
32 #define BMASK 0x0000ff00
33 #define AMASK 0x000000ff
34
35 #else
36
37 #define RMASK 0x000000ff
38 #define GMASK 0x0000ff00
39 #define BMASK 0x00ff0000
40 #define AMASK 0xff000000
41 #endif
42
43
44
45
46 typedef struct {
47     unsigned char r,g,b,alpha;
48 } GaiColor;
49
50
51 #include "aquarium.h"
52 #include "bottom.h"
53 #include "bubble.h"
54 #include "background.h"
55 #include "fish.h"
56 #include "draw.h"
57 #include "soundeffects.h"
58 #include "vroot.h"
59
60 #ifdef DARWIN
61 #include "getopt.h"
62 #else
63 #include <getopt.h>
64 #endif
65
66
67 #define ARG_SEAFLOOR 1
68 #define ARG_SOUND 2
69 #define ARG_PLANTS 3
70 #define ARG_PLANTSCALE 4
71 #define ARG_BOTTOMANIMALS 5
72 #define ARG_OGG 6
73 #define ARG_BG_SOLID 7
74 #define ARG_BG_SHADED 8
75 #define ARG_BG_WATERALIKE 9
76 #define ARG_BG_IMAGE 10
77 #define ARG_LCR 11
78 #define ARG_LCG 12
79 #define ARG_LCB 13
80 #define ARG_UCR 14
81 #define ARG_UCG 15
82 #define ARG_UCB 16
83 #define ARG_BG_IMAGE_FILE 17
84 #define ARG_RANDOM 18
85 #define ARG_SELECTED 19
86 #define ARG_RANDOM_POP 20
87 #define ARG_FISH1 21
88 #define ARG_FISH2 22
89 #define ARG_FISH3 23
90 #define ARG_FISH4 24
91 #define ARG_FISH5 25
92 #define ARG_FISH6 26
93 #define ARG_BLOWFISH 27
94 #define ARG_SWORDFISH 28
95 #define ARG_BDWELLER 29
96 #define ARG_FILLMORE 30
97 #define ARG_SHERMAN 31
98 #define ARG_MEGAN 32
99 #define ARG_HUNTER 33
100 #define ARG_PREY 34
101 #define ARG_LORI 35
102 #define ARG_ERNEST 36
103 #define ARG_SQUID 37
104 #define ARG_HAWTHORNE 38
105 #define ARG_EAT 39
106 #define ARG_EXPLODE 40
107 #define ARG_REBIRTH 41
108 #define ARG_SCALEDIFF 42
109 #define ARG_SPEED 43
110 #define ARG_SCALE 44
111 #define ARG_HUNTERA 45
112 #define ARG_SWORDA 46
113 #define ARG_SOUNDPRG 47
114 #define ARG_WINDOW_ID 48
115 #define ARG_FULLSCREEN 49
116 #define ARG_BUBBLE 50
117 #define ARG_DESKTOP 51
118 #define ARG_COMICS 52
119 #define ARG_COMICS_DIR 53
120 #define ARG_COMICS_DELAY 54
121
122 #define DEPTH 24
123
124 static int screen_width;
125 static int screen_height;
126 static gboolean comics = FALSE;
127 static char *comic_dirs[1024]; /* No more than 1024 comic dirs :-) Ugly, but... */
128 static int num_comic_dirs = 0;
129
130 static GdkWindow *window;
131 static GdkGC *gc;
132 static SDL_Surface *screen=NULL, *screen_image, *background, **thisfish;
133 static SDL_Rect *fish_dest, *fish_src, *clean_dest;
134 static int curr_dest, clean_count,  no_sdl_quit = 0, comics_delay = 50;
135 int window_id = -1, fullscreen = 0;
136 static unsigned char *original_bg;
137 static AquariumData ad;
138
139
140
141 void screensaver_draw_image(int x, int y, int idx, int rev, SA_Image *image)
142 {
143
144     fish_dest[curr_dest].x=x;
145     fish_dest[curr_dest].y=y;
146     fish_dest[curr_dest].w=image->width;
147     fish_dest[curr_dest].h=image->height;
148
149     fish_src[curr_dest].x=0;
150     fish_src[curr_dest].y=(int)((float)idx*(float)image->full_height/(float)image->frames+0.5);
151     fish_src[curr_dest].w=image->width;
152     fish_src[curr_dest].h=image->height;
153
154     if(!rev)
155         thisfish[curr_dest] = SDL_CreateRGBSurfaceFrom(image->image,
156                                                        image->width,
157                                                        (int)((float)image->full_height*(float)(idx+1) / 
158                                                              (float)image->frames + 0.5),
159                                                        32,image->rowstride,
160                                                        RMASK, GMASK, BMASK, AMASK);
161     else
162         thisfish[curr_dest] = SDL_CreateRGBSurfaceFrom(image->rev,
163                                                        image->width,
164                                                        (int)((float)image->full_height*(float)(idx+1) / 
165                                                              (float)image->frames + 0.5),
166                                                        32,image->rowstride,
167                                                        RMASK, GMASK, BMASK, AMASK);
168
169     curr_dest++;
170 }
171
172
173
174
175 void screensaver_clean(int x,int y,int w,int h)
176 {
177
178     clean_dest[clean_count].x=x-5;
179     clean_dest[clean_count].y=y-5;
180     clean_dest[clean_count].w=w+10;
181     clean_dest[clean_count].h=h+10;
182
183
184     SDL_BlitSurface(background,&clean_dest[clean_count],screen,&clean_dest[clean_count]);
185
186     clean_count++;
187 }
188
189
190 void screensaver_quit()
191 {
192     /* Resetting the term signal to the orignal so we can quit nicely.*/
193     signal(SIGTERM, SIG_DFL);
194
195     if(no_sdl_quit)
196         kill(getpid(),SIGTERM);
197     else
198         exit(0);
199
200     /* In case something is really weird */
201     kill(getpid(),SIGKILL);
202 }
203
204 void comics_clean(void)
205 {
206     int i;
207     for(i=0;i<num_comic_dirs;i++)
208         g_free(comic_dirs[i]);
209     num_comic_dirs = 0;
210     comic_dirs[0] = NULL;
211 }
212
213 void comics_prepare(char *dir)
214 {
215     comic_dirs[num_comic_dirs] = g_strdup_printf("%s/*", dir);
216     num_comic_dirs++;
217
218     /* Make sure the final one is always followed by a NULL */
219     comic_dirs[num_comic_dirs] = NULL;
220 }
221
222 char *comics_pick(void)
223 {
224     int i, flags = GLOB_NOSORT;
225     glob_t comic_files;
226     char *the_comic = NULL;
227
228
229     for(i=0;i<num_comic_dirs;i++){
230         if(i)
231             flags |= GLOB_APPEND;
232         glob(comic_dirs[i], flags, NULL, &comic_files);
233     }
234
235     if(comic_files.gl_pathc != 0)
236         the_comic = g_strdup(comic_files.gl_pathv[g_rand_int_range(ad.rnd, 0, comic_files.gl_pathc)]);
237
238     globfree(&comic_files);
239
240
241     return the_comic;
242
243 }
244
245
246 void comics_load(void)
247 {
248     int i,j, srs, ys, xs, alpha, sy, dy;
249     unsigned char *src;
250     char *comic_file = NULL;
251     GError *ferror = NULL;
252     GdkPixbuf *comic_pic, *tmp_pic;
253
254     memcpy(ad.rgb, original_bg, ad.xmax*3*ad.ymax);
255     memcpy(ad.bgr, original_bg, ad.xmax*3*ad.ymax);
256
257     comic_file = comics_pick();
258
259     if(comic_file == NULL)
260         return;
261
262     comic_pic = gdk_pixbuf_new_from_file(comic_file, &ferror);
263
264     g_free(comic_file);
265
266     if(comic_pic == NULL)
267         return;
268
269     if(screen_height < gdk_pixbuf_get_height(comic_pic) || screen_width < gdk_pixbuf_get_width(comic_pic)){
270
271         tmp_pic = gdk_pixbuf_scale_simple(comic_pic,screen_width, screen_height, GDK_INTERP_BILINEAR);
272         g_object_unref(comic_pic);
273         comic_pic = tmp_pic;
274     }
275
276
277     ys = (screen_height - gdk_pixbuf_get_height(comic_pic))/2;
278     xs = (screen_width - gdk_pixbuf_get_width(comic_pic))/2;
279
280
281     srs = gdk_pixbuf_get_rowstride(comic_pic);
282     alpha = gdk_pixbuf_get_has_alpha(comic_pic);
283     src = gdk_pixbuf_get_pixels(comic_pic);
284
285     for(i=0;i<gdk_pixbuf_get_height(comic_pic);i++){
286         sy = i * srs;
287         dy = (i+ys) * ad.xmax + xs;
288         
289         for(j=0;j<gdk_pixbuf_get_width(comic_pic);j++){
290             ad.bgr[(dy+j)*3+0] = ad.rgb[(dy+j)*3+0] = src[sy + j*(3+alpha)+0];
291             ad.bgr[(dy+j)*3+1] = ad.rgb[(dy+j)*3+1] = src[sy + j*(3+alpha)+1];
292             ad.bgr[(dy+j)*3+2] = ad.rgb[(dy+j)*3+2] = src[sy + j*(3+alpha)+2];
293         }
294     }
295     g_object_unref(comic_pic);
296
297 }
298
299
300
301 void screensaver_main_sdl(void)
302 {
303     SDL_Event event;
304     clock_t totaltime1;
305 #ifdef PERFORMACE_CHECK
306     clock_t totaltime2;
307 #endif
308     clock_t cali1, cali2;
309     int totalframes=0;
310     int num_events=0;
311     int main_loop=0;
312     int frames=0;
313     int i;
314     int delay=0;
315     int counter = 0;
316
317
318     totaltime1 = clock();
319     cali1 = clock();
320
321     while(!main_loop){
322
323
324         if(counter == 0 && comics){
325             comics_load();
326             SDL_BlitSurface(screen_image, NULL, screen, NULL);
327             SDL_UpdateRect(screen,0,0,0,0);
328             counter = 25*comics_delay;
329         }
330         counter --;
331
332
333         curr_dest=0;
334         clean_count=0;
335
336         fish_update();
337         bubble_update();
338
339         for(i=0;i<curr_dest;i++)
340             SDL_BlitSurface(thisfish[i],&fish_src[i],screen,&fish_dest[i]);
341         
342
343         /* If we get a SIGTERM from screensaver in this loop, and we later do a SDL_Quit()
344            X will get problems. So we have to avoid calling SDL_Quit if a sigterm is caught
345            in this loop.
346
347            Otherwise we get:
348            Xlib: unexpected async reply (sequence 0xf03)!
349            And sherman's starts eating processor power like mad!
350         */
351         no_sdl_quit = 1;
352         for(i=0;i<curr_dest;i++){
353             SDL_UpdateRects(screen,1,&clean_dest[i]);
354             SDL_FreeSurface(thisfish[i]);
355         }
356         no_sdl_quit = 0;
357
358         if(window_id!=-1)
359             SDL_Flip(screen);
360
361         totalframes++;
362         frames++;
363
364         if(frames==10){
365             cali2=clock();
366
367             /* Check if we're going too fast! */
368             if((float)(cali2-cali1) < (float)(0.2*CLOCKS_PER_SEC)){
369                 delay=(int)(((float)((0.2*CLOCKS_PER_SEC)-(cali2-cali1))/CLOCKS_PER_SEC)*100000);
370             }
371             else{
372                 if(delay!=0){
373                     if(delay<((int)(((float)((0.2*CLOCKS_PER_SEC)-(cali2-cali1))/CLOCKS_PER_SEC)*100000))){
374                         delay-=(int)(((float)((0.2*CLOCKS_PER_SEC)-(cali2-cali1))/CLOCKS_PER_SEC)*100000);
375                     }
376                     else
377                         delay=0;
378                 }
379             }
380             cali1=clock();
381             frames=0;
382         }
383         usleep(delay);
384         
385
386         while(SDL_PollEvent(&event)){
387             switch(event.type){
388             case SDL_QUIT:
389                 main_loop=1;
390                 break;
391             case SDL_KEYDOWN:
392                 num_events++;
393                 if(num_events==2)
394                     main_loop=1;
395                 break;
396             case SDL_MOUSEMOTION:
397                 num_events++;
398                 if(num_events==2)
399                     main_loop=1;
400                 break;
401             case  SDL_MOUSEBUTTONDOWN:
402                 num_events++;
403                 if(num_events==2)
404                     main_loop=1;
405                 break;
406             }
407         }    
408     }
409
410 #ifdef PERFORMACE_CHECK
411     totaltime2=clock();
412     printf("Frames: %d\n",totalframes);
413     printf("Seconds: %f\n",(float)(totaltime2-totaltime1)/CLOCKS_PER_SEC);
414     printf("FPS: %f\n",(float)totalframes/((float)(totaltime2-totaltime1)/CLOCKS_PER_SEC));
415 #endif
416
417 }
418
419 void screensaver_main_gdk(void)
420 {
421     GdkEvent *event;
422     int counter = 0;
423
424     while(1){
425         while(gdk_events_pending()){
426             event = gdk_event_get();
427             if(event){
428                 if(event->type == GDK_DESTROY)
429                     exit(0);
430             }
431         }
432
433         if(counter == 0 && comics){
434             comics_load();
435             counter = 25*comics_delay;
436         }
437         counter --;
438
439         memcpy(ad.rgb, ad.bgr, ad.ymax * ad.xmax * 3);
440         fish_update();
441         bubble_update();
442         gdk_draw_rgb_image(window, gc, ad.xmin, ad.ymin, ad.xmax, ad.ymax,
443                            GDK_RGB_DITHER_NONE, ad.rgb, ad.xmax * 3);
444         gdk_flush();
445         /* 25 fps */
446         usleep(1000000/25);
447     }
448
449 }
450
451 void init_sdl(int sdl_flags)
452 {
453
454     if (SDL_Init(SDL_INIT_VIDEO) < 0){
455         printf("Can't init SDL: %s\n",SDL_GetError());
456         exit(1);
457     }
458
459
460     signal(SIGTERM, screensaver_quit);
461     atexit(SDL_Quit);
462     
463
464     if(!SDL_VideoModeOK(screen_width,screen_height, DEPTH, sdl_flags)){
465         printf("Sorry, video mode %dx%d in %d bits isn't supported by hardware\n",
466                screen_width,screen_height, DEPTH);
467         exit(2);
468     }
469
470
471     screen = SDL_SetVideoMode(screen_width, screen_height, DEPTH, sdl_flags);
472
473     if(screen == NULL){
474         printf("Unable to set video mode %dx%d in %d bits.\n",
475                screen_width,screen_height,DEPTH);
476         exit(3);
477     }
478
479     SDL_WM_SetCaption("Sherman's aquarium",NULL);
480
481
482     /* Hide the mouse cursor */
483     SDL_ShowCursor(0);
484
485     /* Start with all black */
486     SDL_FillRect(screen,NULL,0x000000);
487
488     screen_image = SDL_CreateRGBSurfaceFrom(ad.rgb, ad.xmax, ad.ymax, DEPTH, ad.xmax*3, 
489                                             RMASK, GMASK, BMASK, 0);
490     background = SDL_CreateRGBSurfaceFrom(ad.bgr, ad.xmax, ad.ymax, DEPTH, ad.xmax*3, 
491                                           RMASK, GMASK, BMASK, 0);
492
493
494     SDL_BlitSurface(screen_image, NULL, screen, NULL);
495     SDL_UpdateRect(screen,0,0,0,0);
496
497 }
498
499
500 void screensaver_init()
501 {
502     char *sdl_command;
503     XWindowAttributes win_attr;
504     Display *display;
505     Fish_settings *fish_settings;
506     Bubble_settings *bubble_settings;
507     int sdl_flags = SDL_DOUBLEBUF|SDL_HWSURFACE|SDL_ANYFORMAT;
508
509     screen_height = 480;
510     screen_width = 640;
511     
512     if(window_id != -1){
513         display = XOpenDisplay(NULL);
514         XGetWindowAttributes(display, (Window)window_id, &win_attr);
515         screen_height = win_attr.height;
516         screen_width = win_attr.width;
517         fullscreen = 0;
518         ad.proximity = 1;                       /* No sound effects */
519         window = gdk_window_foreign_new((Window)window_id);
520         gdk_window_show(window);
521         gc = gdk_gc_new(window);
522     }
523
524     if(fullscreen){
525         screen_width = gdk_screen_width();
526         screen_height = gdk_screen_height();
527
528         display=XOpenDisplay(NULL);
529         sdl_command = g_strdup_printf("SDL_WINDOWID=%d",
530                                       (int)RootWindowOfScreen(ScreenOfDisplay(display, DefaultScreen(display))));
531         putenv(sdl_command);
532         ad.proximity = 0;
533         sdl_flags |= SDL_FULLSCREEN;
534     }
535
536     ad.xmax = screen_width;
537     ad.ymax = screen_height;
538   
539     ad.virtual_aquarium_x = ad.xmax + 2 * VIRTUAL_AQUARIUM_DX;
540     ad.virtual_aquarium_y = ad.ymax + 2 * VIRTUAL_AQUARIUM_DY;
541
542     ad.ymin = ad.xmin = ad.viewpoint_start_x = ad.viewpoint_start_y = 0;
543
544     ad.rgb = g_malloc0(ad.xmax*3*ad.ymax);
545     ad.bgr = g_malloc0(ad.xmax*3*ad.ymax);
546     original_bg = g_malloc0(ad.xmax*3*ad.ymax);
547
548     background_init();
549     fish_init();
550     fish_turn();
551     bottom_init();
552     bubble_init();
553
554     memcpy(ad.rgb, ad.bgr, ad.xmax*3*ad.ymax);
555     memcpy(original_bg, ad.bgr, ad.xmax*3*ad.ymax);
556
557
558     if(fullscreen || window_id == -1)
559         init_sdl(sdl_flags);
560
561
562     fish_settings = fish_get_settings_ptr();
563     bubble_settings = bubble_get_settings_ptr();
564
565     fish_dest = g_malloc0(sizeof(SDL_Rect)*(fish_settings->num_fish + 
566                                             bubble_settings->max_bubbles));
567     fish_src = g_malloc0(sizeof(SDL_Rect)*(fish_settings->num_fish +
568                                            bubble_settings->max_bubbles));
569     clean_dest = g_malloc0(sizeof(SDL_Rect)*(fish_settings->num_fish  + 
570                                              bubble_settings->max_bubbles));
571
572     thisfish = g_malloc0(sizeof(SDL_Surface*)*(fish_settings->num_fish + bubble_settings->max_bubbles));
573     
574 }
575
576 int htoi(char *str)
577 {
578   int i,sum=0,d;
579
580   if(str[0]!='0' || str[1]!='x') return -1;
581   for(i=2;i<strlen(str);i++){
582     d=0;
583     if(str[i]>='0' && str[i]<='9') d=(int)(str[i]-'0');
584     if(str[i]>='A' && str[i]<='F') d=(int)(str[i]-'A'+10);
585     if(str[i]>='a' && str[i]<='f') d=(int)(str[i]-'a'+10);
586
587     sum+=d;
588     sum=sum<<4;
589   }
590
591   return(sum>>4);
592 }
593
594 void screensaver_init_param(int argc, char **argv)
595 {
596     int i,c, numfish = 0, comic_start;
597     char *comic_buff;
598
599     Sound_settings *s, sound_settings = {0,TYPE_MP3, NULL};
600     Bubble_settings *bub, bubble_settings = {20};
601     Bottom_settings *b, bottom_settings = {0,5,1,75,2};
602     Background_settings *bg, background_settings = {NULL,NULL, 0,1, 
603                                                     (GaiColor){0, 100, 150, 0},
604                                                     (GaiColor){10,120, 250, 0},
605                                                     (GaiColor){0,0,0,0}};
606     Fish_settings *f, fish_settings = {0, 0, 75, 0, 100, 0, 15, 0, 75, 75,
607                                        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
608     struct option cmdline_options[] = {
609         {"sound", no_argument, NULL, ARG_SOUND},
610         {"soundprg", required_argument, NULL, ARG_SOUNDPRG},
611         {"ogg", no_argument, NULL, ARG_OGG},
612
613
614         {"seafloor", no_argument, NULL, ARG_SEAFLOOR},
615         {"plants", required_argument, NULL, ARG_PLANTS},
616         {"plantscale", required_argument, NULL, ARG_PLANTSCALE},
617         {"bottomanimals", required_argument, NULL, ARG_BOTTOMANIMALS},
618
619         {"bg_solid", no_argument, NULL, ARG_BG_SOLID},
620         {"bg_shaded", no_argument, NULL, ARG_BG_SHADED},
621         {"bg_wateralike", no_argument, NULL, ARG_BG_WATERALIKE},
622         {"bg_image", no_argument, NULL, ARG_BG_IMAGE},
623
624
625         {"lcr", required_argument, NULL, ARG_LCR},
626         {"lcg", required_argument, NULL, ARG_LCG},
627         {"lcb", required_argument, NULL, ARG_LCB},
628
629         {"ucr", required_argument, NULL, ARG_UCR},
630         {"ucg", required_argument, NULL, ARG_UCG},
631         {"ucb", required_argument, NULL, ARG_UCB},
632         
633         {"bg_image_file", required_argument, NULL, ARG_BG_IMAGE_FILE},
634
635         {"comics", no_argument, NULL, ARG_COMICS},
636         {"comics_dir", required_argument, NULL, ARG_COMICS_DIR},
637         {"comics_delay", required_argument, NULL, ARG_COMICS_DELAY},
638
639
640         {"random", no_argument, NULL, ARG_RANDOM},
641         {"selected", no_argument, NULL, ARG_SELECTED},
642         {"random_pop", required_argument, NULL, ARG_RANDOM_POP},
643
644         {"fish1", required_argument, NULL, ARG_FISH1},
645         {"fish2", required_argument, NULL, ARG_FISH2},
646         {"fish3", required_argument, NULL, ARG_FISH3},
647         {"fish4", required_argument, NULL, ARG_FISH4},
648         {"fish5", required_argument, NULL, ARG_FISH5},
649         {"fish6", required_argument, NULL, ARG_FISH6},
650         {"swordfish", required_argument, NULL, ARG_SWORDFISH},
651         {"blowfish", required_argument, NULL, ARG_BLOWFISH},
652         {"bdweller", required_argument, NULL, ARG_BDWELLER},
653         {"fillmore", required_argument, NULL, ARG_FILLMORE},
654         {"sherman", required_argument, NULL, ARG_SHERMAN},
655         {"megan", required_argument, NULL, ARG_MEGAN},
656         {"hunter", required_argument, NULL, ARG_HUNTER},
657         {"prey", required_argument, NULL, ARG_PREY},
658         {"lori", required_argument, NULL, ARG_LORI},
659         {"ernest", required_argument, NULL, ARG_ERNEST},
660         {"squid", required_argument, NULL, ARG_SQUID},
661         {"hawthorne", required_argument, NULL, ARG_HAWTHORNE},
662
663         {"eat", no_argument, NULL, ARG_EAT},
664         {"explode", no_argument, NULL, ARG_EXPLODE},
665         {"rebirth", no_argument, NULL, ARG_REBIRTH},
666         {"scalediff", no_argument, NULL, ARG_SCALEDIFF},
667         {"speed", required_argument, NULL, ARG_SPEED},
668         {"scale", required_argument, NULL, ARG_SCALE},
669         {"huntera", required_argument, NULL, ARG_HUNTERA},
670         {"sworda", required_argument, NULL, ARG_SWORDA},
671         {"window-id", required_argument, NULL, ARG_WINDOW_ID},
672         {"root", no_argument, NULL, ARG_FULLSCREEN},
673         {"bubble", required_argument, NULL, ARG_BUBBLE},
674         {"desktop", no_argument, NULL, ARG_DESKTOP},
675         {0,0,0,0}};
676
677
678     b = bottom_get_settings_ptr();
679     bub = bubble_get_settings_ptr();
680     bg = background_get_settings_ptr();
681     f = fish_get_settings_ptr();
682     s = sound_get_settings_ptr();
683
684     memcpy(f,&fish_settings, sizeof(Fish_settings));
685     memcpy(bg,&background_settings, sizeof(Background_settings));
686     memcpy(b,&bottom_settings, sizeof(Bottom_settings));
687     memcpy(bub, &bubble_settings, sizeof(Bubble_settings));
688     memcpy(s, &sound_settings, sizeof(Sound_settings));
689
690     while ((c =
691             getopt_long_only(argc, argv, "", cmdline_options, NULL)) != -1){
692
693         switch(c){
694
695         case ARG_SEAFLOOR:
696             b->have_sea_floor = 1;
697             break;
698         case ARG_SOUND:
699             s->on = 1;
700             break;
701         case ARG_PLANTS:
702             b->max_plants = atoi(optarg);
703             break;
704         case ARG_PLANTSCALE:
705             b->scale = atoi(optarg);
706             break;
707         case ARG_BOTTOMANIMALS:
708             b->num_bottom_animals = atoi(optarg);
709             break;
710         case ARG_OGG:
711             s->type = TYPE_OGG;
712             break;
713         case ARG_BG_SOLID:
714             bg->type = BG_SOLID;
715             bg->desktop = 0;
716             break;
717         case ARG_BG_SHADED:
718             bg->type = BG_SHADED;
719             bg->desktop = 0;
720             break;
721         case ARG_BG_WATERALIKE:
722             bg->type = BG_WATER;
723             bg->desktop = 0;
724             break;
725         case ARG_BG_IMAGE:
726             bg->type = BG_IMAGE;
727             bg->desktop = 0;
728             break;
729         case ARG_LCR:
730             bg->solid_c.r = bg->shaded_bot_c.r = atoi(optarg);
731             break;
732         case ARG_LCG:
733             bg->solid_c.g = bg->shaded_bot_c.g = atoi(optarg);
734             break;
735         case ARG_LCB:
736             bg->solid_c.b = bg->shaded_bot_c.b = atoi(optarg);
737             break;
738         case ARG_UCR:
739             bg->shaded_top_c.r = atoi(optarg);
740             break;
741         case ARG_UCG:
742             bg->shaded_top_c.g = atoi(optarg);
743             break;
744         case ARG_UCB:
745             bg->shaded_top_c.b = atoi(optarg);
746             break;
747         case ARG_BG_IMAGE_FILE:
748             bg->imagename = g_strdup_printf(optarg);
749             break;
750         case ARG_RANDOM:
751             f->type = RANDOM_FISH;
752             break;
753         case ARG_SELECTED:
754             f->type = SELECTION_FISH;
755             break;
756         case ARG_RANDOM_POP:
757             f->num_fish = atoi(optarg);
758             break;
759         case ARG_FISH1:
760             f->fish1 = atoi(optarg);
761             break;
762         case ARG_FISH2:
763             f->fish2 = atoi(optarg);
764             break;
765         case ARG_FISH3:
766             f->fish3 = atoi(optarg);
767             break;
768         case ARG_FISH4:
769             f->fish4 = atoi(optarg);
770             break;
771         case ARG_FISH5:
772             f->fish5 = atoi(optarg);
773             break;
774         case ARG_FISH6:
775             f->fish6 = atoi(optarg);
776             break;
777         case ARG_BLOWFISH:
778             f->blowfish = atoi(optarg);
779             break;
780         case ARG_SWORDFISH:
781             f->swordfish = atoi(optarg);
782             break;
783         case ARG_BDWELLER:
784             f->bdweller = atoi(optarg);
785             break;
786         case ARG_FILLMORE:
787             f->fillmore = atoi(optarg);
788             break;
789         case ARG_SHERMAN:
790             f->sherman = atoi(optarg);
791             break;
792         case ARG_MEGAN:
793             f->megan = atoi(optarg);
794             break;
795         case ARG_HUNTER:
796             f->hunter = atoi(optarg);
797             break;
798         case ARG_PREY:
799             f->prey = atoi(optarg);
800             break;
801         case ARG_LORI:
802             f->lori = atoi(optarg);
803             break;
804         case ARG_ERNEST:
805             f->ernest = atoi(optarg);
806             break;
807         case ARG_SQUID:
808             f->squid = atoi(optarg);
809             break;
810         case ARG_HAWTHORNE:
811             f->hawthorne = atoi(optarg);
812             break;
813         case ARG_EAT:
814             f->eat = 1;
815             break;
816         case ARG_EXPLODE:
817             f->explode = 1;
818             break;
819         case ARG_REBIRTH:
820             f->rebirth = 1;
821             break;
822         case ARG_SCALEDIFF:
823             f->scale_diff = 1;
824             break;
825         case ARG_SPEED:
826             f->speed = atoi(optarg);
827             break;
828         case ARG_SCALE:
829             f->scale = atoi(optarg);
830         case ARG_HUNTERA:
831             f->hunter_agr = atoi(optarg);
832             break;
833         case ARG_SWORDA:
834             f->swordfish_agr = atoi(optarg);
835             break;
836         case ARG_SOUNDPRG:
837             s->prg = g_strdup_printf(optarg);
838             break;
839         case ARG_WINDOW_ID:
840             window_id = htoi(optarg);
841             break;
842         case ARG_FULLSCREEN:
843             fullscreen = 1;
844             break;
845         case ARG_BUBBLE:
846             bub->max_bubbles = atoi(optarg);
847             break;
848         case ARG_DESKTOP:
849             bg->type = 0;
850             bg->desktop = 1;
851             break;
852         case ARG_COMICS:
853             comics = TRUE;
854             comics_prepare(IMAGE_PATH "/strips");
855             break;
856         case ARG_COMICS_DELAY:
857             comics_delay = atoi(optarg);
858             break;
859         case ARG_COMICS_DIR:
860             comics_clean();
861             comic_start = 0;
862             comic_buff = g_strdup(optarg);
863             for(i=0;i<strlen(optarg);i++){
864                 if(comic_buff[i] == ';'){
865                     comic_buff[i] = '\0';
866                     comics_prepare(comic_buff+comic_start);
867                     comic_start = i+1;
868                 }
869             }
870             comics_prepare(comic_buff+comic_start);
871             g_free(comic_buff);
872
873             break;
874         default:
875             break;
876         }
877     }
878
879     numfish += f->fish1;
880     numfish += f->fish2;
881     numfish += f->fish3;
882     numfish += f->fish4;
883     numfish += f->fish5;
884     numfish += f->fish6;
885     numfish += f->swordfish;
886     numfish += f->blowfish;
887     numfish += f->fillmore;
888     numfish += f->sherman;
889     numfish += f->prey;
890     numfish += f->hunter;
891     numfish += f->lori;
892     numfish += f->ernest;
893     numfish += f->squid;
894     numfish += f->megan;
895     numfish += f->bdweller;
896     numfish += f->hawthorne;
897
898     if(f->type == SELECTION_FISH)
899         f->num_fish = numfish;
900
901 }
902
903 int main(int argc, char **argv)
904 {
905     gdk_init(&argc, &argv);
906
907     ad.rnd = g_rand_new();
908
909     screensaver_init_param(argc, argv);
910     screensaver_init(0);
911
912     if(window_id==-1)
913         screensaver_main_sdl();
914     else
915         screensaver_main_gdk();
916     return 0;
917 }
918
919
920 AquariumData *aquarium_get_settings_ptr(void)
921 {
922     return &ad;
923 }
924
925 unsigned char *aquarium_install_path(void)
926 {
927     return IMAGE_PATH;
928 }
929
930
931 void aquarium_draw_image(int x, int y, int idx, int rev, SA_Image *image)
932 {
933     if(window_id==-1)
934         screensaver_draw_image(x, y, idx, rev, image);
935     else
936         draw_image(x, y, idx, rev, image);
937 }
938
939 void aquarium_draw_pic_alpha(SA_Image *image, int w, int h, int x, int y, int idx, int alpha)
940 {
941     if(window_id==-1)
942         screensaver_draw_image(x, y, idx, 0, image);
943     else
944         draw_pic_alpha(image->image, w, h, x, y, idx,alpha);
945
946
947
948 void aquarium_clean_image(int x, int y, int w, int h)
949 {
950     if(window_id==-1)
951         screensaver_clean(x, y, w, h);
952 }
953
954 GdkPixbuf *gai_load_image(char *fname)
955 {
956     GError *msg = NULL;
957     GdkPixbuf *pix;
958     char *full_name;
959
960     full_name = g_strdup_printf("%s/%s",IMAGE_PATH,fname);
961     pix = gdk_pixbuf_new_from_file(full_name, &msg);
962     if(!pix){
963         printf("%s\n",msg->message);
964         exit(1);
965     }
966     g_free(full_name);
967
968     return pix;
969     
970 }
971 void gai_display_error_continue(char *msg)
972 {
973     printf(" *** Error: %s\n",msg);
974 }