1 /*
2 XBubble - init.c
3
4 Copyright (C) 2002 Ivan Djelic <ivan@savannah.gnu.org>
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <limits.h>
24 #include <string.h>
25 #include <ctype.h>
26 #include <math.h>
27 #include <X11/Xlib.h>
28 #include <dirent.h>
29
30 #include "setting.h"
31 #include "cell.h"
32 #include "rgba.h"
33 #include "dialog.h"
34 #include "frame.h"
35 #include "bubble.h"
36 #include "board.h"
37 #include "gettext.h"
38
39 extern Display *display;
40 extern Visual *visual;
41 extern Window root;
42 extern Window win;
43 extern int screen;
44 extern int depth;
45
46 extern Colormap colormap;
47
48 extern char * data_dir;
49 extern char * theme;
50 extern int scale;
51 extern int win_width;
52 extern int win_height;
53
54 extern int nb_levels;
55 extern int level[MAX_NB_LEVELS][NB_CELLS];
56
57 XFontStruct *title_font;
58 XFontStruct *dialog_font;
59 XFontStruct *menu_font;
60 GC dialog_gc;
61 GC dialog_text_gc;
62 GC menu_gc;
63 GC selected_gc;
64 Pixmap win_bg;
65 Pixmap board_decoration;
66 Pixmap board_decoration_mask;
67 Pixmap cup_on;
68 Pixmap cup_off;
69 Pixmap cup_on_mask;
70 Pixmap cup_off_mask;
71
72 Set alert_animation;
73 Set canon_animation;
74 Set countdown_animation;
75 Set bubble_animation[NB_COLORS][NB_BUBBLE_STATES];
76 char *game_fonts[] = FONTS;
77
78 int titlefont_color[3] = TITLEFONT_COLOR;
79 int menufont_color[3] = MENUFONT_COLOR;
80 int menufont_selected_color[3] = MENUFONT_SELECTED_COLOR;
81 int notitle = 0;
82
data_file(char * file,int themed)83 char * data_file( char * file, int themed ) {
84 int path_max;
85 int theme_len;
86 char * abs_data_dir;
87 static int offset = 0;
88 static char buffer[1024];
89 if ( ! offset ) {
90 #ifdef PATH_MAX
91 path_max = PATH_MAX;
92 #else
93 path_max = pathconf (path, _PC_PATH_MAX);
94 if (path_max <= 0)
95 path_max = 4096;
96 #endif
97 abs_data_dir = (char *) xmalloc( path_max * sizeof(char));
98 realpath( data_dir, abs_data_dir );
99 offset = strlen(abs_data_dir);
100 if ( offset > 1024-128 )
101 offset = 1024-128;
102 strncpy( buffer, abs_data_dir, offset );
103 buffer[offset++] = '/';
104 buffer[1023] = '\0';
105 free( abs_data_dir );
106 }
107 if (themed) {
108 theme_len=strlen(theme);
109 strncpy( buffer + offset, "themes/", 126);
110 strncpy( buffer + offset + 7, theme, 119);
111 strncpy( buffer + offset + theme_len + 7, "/", 119 - theme_len);
112 strncpy( buffer + offset + theme_len + 8, file, 118 - theme_len);
113 } else {
114 strncpy( buffer + offset, file, 126);
115 }
116 return buffer;
117 }
118
119
load_levels(char * file)120 void load_levels( char * file ) {
121 FILE *fd;
122 char line[128];
123 unsigned char r[8];
124 int i, cell = 0;
125 int line_counter = 0;
126 int long_row = 1;
127 int color, parse_error = 0;
128
129 nb_levels = 0;
130 file = data_file(file, 0);
131
132 fd = fopen( file, "r" );
133 if ( fd == NULL ) {
134 warn( _("cannot open levels file %s."), file);
135 return;
136 }
137 while (( fgets( line, 128, fd ) != NULL )&&( ! parse_error )) {
138 line_counter++;
139 if (( isalnum(line[0]) )||( line[0] == '-' )||( line[0] == ' ' )) {
140 /* parse row */
141 if ( long_row )
142 parse_error = ( sscanf( line, "%c %c %c %c %c %c %c %c",
143 r, r+1, r+2, r+3, r+4, r+5, r+6, r+7 ) != 8);
144 else
145 parse_error = ( sscanf( line, " %c %c %c %c %c %c %c",
146 r+1, r+2, r+3, r+4, r+5, r+6, r+7 ) != 7 );
147 if ( ! parse_error ) {
148 for ( i = 0; i < 8; i++ ) {
149 switch( r[i] ) {
150 default:
151 /* the shift in values read and stored comes from the compatibility with fb */
152 case '-': color = 0; break;
153 case '0': color = 1; break;
154 case '1': color = 2; break;
155 case '2': color = 3; break;
156 case '3': color = 4; break;
157 case '4': color = 5; break;
158 case '5': color = 6; break;
159 case '6': color = 7; break;
160 case '7': color = 8; break;
161 }
162 level[nb_levels][cell++] = color;
163 }
164 long_row = 1 - long_row;
165 }
166 else
167 warn( _("parse error in file %s at line %d."), file, line_counter );
168 }
169 if ( cell >= (ROWS-1)*8 ) {
170 nb_levels++;
171 cell = 0;
172 long_row = 1;
173 }
174 if ( nb_levels >= MAX_NB_LEVELS ) {
175 warn( _("too many levels in file %s."), file );
176 break;
177 }
178 }
179 }
180
init_display(char * display_name)181 void init_display( char * display_name ) {
182 int i;
183 XColor colors[256];
184 display = XOpenDisplay( display_name );
185 if ( display == NULL )
186 fail( _("cannot open display.") );
187 screen = DefaultScreen( display);
188 visual = DefaultVisual( display, screen);
189 root = RootWindow( display, screen);
190 depth = DefaultDepth( display, screen);
191 if ( depth < 8 ) {
192 XCloseDisplay(display);
193 fail( _("sorry, your display color depth is not supported.") );
194 }
195 if ( depth == 8 ) { /* allocate our own RRRGGGBB palette */
196 for ( i = 0; i < 256; i++ ) {
197 colors[i].pixel = i;
198 colors[i].red = (( i & 0xe0 ) << 8 );
199 colors[i].green = (( i & 0x1c ) << 11 );
200 colors[i].blue = (( i & 0x03 ) << 14 );
201 colors[i].flags = DoRed | DoGreen | DoBlue;
202 }
203 colormap = XCreateColormap( display, root, visual, AllocAll );
204 XStoreColors( display, colormap, colors, 256 );
205 }
206 }
207
add_font_path(char * path)208 void add_font_path( char * path ) {
209 int i;
210 int npaths;
211 char ** fontpath;
212 char ** new_fontpath;
213
214 fontpath = XGetFontPath( display, &npaths );
215 if ( fontpath != NULL ) {
216 /* check if path is already present */
217 for ( i = 0; i < npaths; i++ )
218 if ( strncmp( path, fontpath[i], strlen(path) ) == 0 ) {
219 XFreeFontPath(fontpath);
220 return;
221 }
222 new_fontpath = (char **) xmalloc( sizeof(char *)*( npaths + 1 ));
223 memcpy( new_fontpath, fontpath, npaths*sizeof(char *));
224 new_fontpath[npaths] = path;
225 XSetFontPath( display, new_fontpath, npaths+1 );
226 XFreeFontPath(fontpath);
227 free(new_fontpath);
228 }
229 }
230
load_font(int pixel_size)231 XFontStruct * load_font( int pixel_size ) {
232 XFontStruct * xfont;
233 char name[128];
234 int i;
235 static int added_font_path = 0;
236
237 /* try to load each font in turn */
238 for ( i = 0; game_fonts[i] != NULL; i++ ) {
239 sprintf( name, game_fonts[i], pixel_size );
240 xfont = XLoadQueryFont( display, name );
241 if ( xfont != NULL )
242 return xfont;
243 }
244 /* let's see if we can supply a font */
245 if ( ! added_font_path ) {
246 add_font_path(data_file("",0));
247 added_font_path = 1;
248 }
249 sprintf( name, SUPPLIED_FONT, pixel_size );
250 xfont = XLoadQueryFont( display, name );
251 if ( xfont != NULL )
252 return xfont;
253
254 /* at least we should have the "fixed" font ... uurgh */
255 xfont = XLoadQueryFont( display, "fixed" );
256 if ( xfont == NULL )
257 fail( _("couldn't load any font !") );
258 return xfont;
259 }
260
create_copy_gc()261 static GC create_copy_gc() {
262 XGCValues gcv;
263 unsigned long gcm;
264 gcm = GCFunction | GCGraphicsExposures;
265 gcv.graphics_exposures = False;
266 gcv.function = GXcopy;
267 return XCreateGC( display, root, gcm, &gcv );
268 }
269
load_frame(char * file,double zoom)270 Frame load_frame( char *file, double zoom ) {
271 Pixmap pixmap;
272 Pixmap mask;
273 Pixmap *pmask;
274 RgbaImage ri1;
275 RgbaImage ri2;
276 Frame frame = (Frame) xmalloc( sizeof( struct _Frame ));
277
278 ri1 = create_rgba_image_from_png_file(data_file(file,1));
279 /* ri2 = ( zoom < 1.0 )? scale_rgba_image( ri1, zoom, zoom ) : ri1; */
280 ri2 = scale_rgba_image( ri1, zoom, zoom ) ;
281 pmask = ( ri2->has_alpha )? &mask : NULL;
282 create_pixmaps_from_rgba_image( ri2, &pixmap, pmask );
283
284 frame->width = ri2->width;
285 frame->height = ri2->height;
286 /* center sprite */
287 frame->cx = ri2->width/2;
288 frame->cy = ri2->height/2;
289 /* default frame duration = 40 ms */
290 frame->delay = 40;
291 frame->has_mask = ri2->has_alpha;
292 frame->pixmap = pixmap;
293 if ( frame->has_mask ) {
294 frame->gc = create_copy_gc();
295 /* precompute clipmask */
296 XSetClipMask( display, frame->gc, mask );
297 XFreePixmap( display, mask );
298 }
299 if ( ri1 != ri2 )
300 delete_rgba_image(ri1);
301 delete_rgba_image(ri2);
302 return frame;
303 }
304
delete_frame(Frame frame)305 void delete_frame( Frame frame ) {
306 XFreePixmap( display, frame->pixmap);
307 if ( frame->has_mask )
308 XFreeGC( display, frame->gc );
309 free(frame);
310 }
311
load_animation(char * filename,double zoom)312 Set load_animation( char *filename, double zoom ) {
313 Frame frame;
314 Set animation = NULL;
315 int cx;
316 int cy;
317 int delay;
318 int max_nb_frames = 0;
319 int lc = 0;
320 char line[128];
321 char framename[128];
322 FILE *fd;
323
324 /* open animation description file */
325 fd = fopen( data_file(filename,1), "r" );
326 if ( fd == NULL )
327 fail( _("cannot open animation file %s."), data_file(filename,1) );
328
329 /* count frames */
330 while ( fgets( line, 128, fd ) != NULL ) {
331 if ( isalnum(line[0]))
332 max_nb_frames++;
333 }
334 rewind(fd);
335 /* load frames */
336 if ( max_nb_frames > 0 ) {
337 animation = set_new(max_nb_frames);
338 while ( fgets( line, 128, fd ) != NULL ) {
339 lc++;
340 /* parse line */
341 if ( isalnum(line[0])) {
342 if ( sscanf( line, "%127s%d%d%d", framename, &cx, &cy, &delay) == 4 ) {
343 frame = load_frame( framename, zoom );
344 set_add( animation, frame );
345 frame->cx = cx*zoom;
346 frame->cy = cy*zoom;
347 frame->delay = delay;
348 }
349 else
350 warn( _("error parsing line %d of file %s."), lc, filename );
351 }
352 }
353 if ( animation->size == 0 )
354 fail( _("animation %s has no valid frames."), filename );
355 }
356 fclose(fd);
357 return animation;
358 }
359
load_scaled_image(char * file,Pixmap * pix,Pixmap * mask,double zoom)360 void load_scaled_image( char *file, Pixmap *pix, Pixmap *mask, double zoom ) {
361 RgbaImage ri1;
362 RgbaImage ri2;
363 ri1 = create_rgba_image_from_png_file(data_file(file,1));
364 ri2 = ( zoom < 1.0 )? scale_rgba_image( ri1, zoom, zoom ) : ri1;
365 create_pixmaps_from_rgba_image( ri2, pix, mask );
366 delete_rgba_image(ri1);
367 if ( ri2 != ri1 )
368 delete_rgba_image(ri2);
369 }
370
delete_animation(Set animation)371 void delete_animation( Set animation ) {
372 int i;
373 if (animation) {
374 for ( i = 0; i < animation->size; i++ )
375 delete_frame( animation->element[i] );
376 set_free( animation );
377 }
378 }
379
make_canon_animation(double zoom)380 void make_canon_animation( double zoom ) {
381 RgbaImage ri;
382 RgbaImage ri2;
383 Pixmap mask;
384 Frame frame;
385 int i;
386
387 ri2 = create_rgba_image_from_png_file(data_file("canon.png",1));
388 ri2->hotx = CANON_CX;
389 ri2->hoty = CANON_CY;
390 ri = scale_rgba_image( ri2, zoom, zoom );
391 delete_rgba_image(ri2);
392
393 canon_animation = set_new( NB_ANGLES );
394
395 for ( i = -CANON_ANGLE_MAX; i <= CANON_ANGLE_MAX; i++ ) {
396 frame = (Frame) xmalloc( sizeof( struct _Frame ));
397 ri2 = rotate_rgba_image( ri, -i*ANGLE_STEP, True );
398 create_pixmaps_from_rgba_image( ri2, &frame->pixmap, &mask );
399 frame->width = ri2->width;
400 frame->height = ri2->height;
401 frame->cx = ri2->hotx;
402 frame->cy = ri2->hoty;
403 frame->delay = 0;
404 frame->has_mask = ri2->has_alpha;
405 if ( frame->has_mask ) {
406 frame->gc = create_copy_gc();
407 /* precompute clipmask */
408 XSetClipMask( display, frame->gc, mask );
409 XFreePixmap( display, mask );
410 }
411 delete_rgba_image(ri2);
412 set_add( canon_animation, frame );
413 }
414 delete_rgba_image(ri);
415 }
416
417 /* Determine whether it is a valid bubble name or not.
418 The following Naming convention is used :
419 Bubble_<COLOR>_<STATE>_<num>.png
420 */
parse_bubble_name(const char * name,int * color_val,int * state_val)421 int parse_bubble_name(const char *name,int *color_val, int *state_val)
422 {
423 char *copy = NULL, *copy_orig = NULL;
424 char *token = NULL;
425 int color,state;
426 int return_val = 0;
427
428 copy = copy_orig = calloc(strlen(name) + 1, sizeof(char));
429 strcpy(copy,name);
430 token = strtok(copy,"_");
431
432 if(strcmp(token,"Bubble")==0) { /* Let's determine the color */
433 token = strtok(NULL,"_");
434
435 for ( color = 0; color < NB_COLORS; color++ ) {
436 if(strcmp(name_color_get(color),token)==0) {
437 break;
438 }
439 }
440 if(color==NB_COLORS) {
441 warn( _("%s : %s is not a valid color."), name, token );
442 } else { /* Let's determine the state now */
443 *color_val = color;
444
445 token = strtok(NULL,"_");
446 for ( state = 0; state < NB_BUBBLE_STATES; state++ ) {
447 if(strcmp(name_state_get(state),token)==0) {
448 break;
449 }
450 }
451 if((state == NB_BUBBLE_STATES) && (strcmp(DEFAULT_STATE_NAME,token)!=0)) {
452 warn( _("%s : %s is not a valid state."), name, token );
453 } else {
454 return_val = 1;
455 *state_val = ((state==NB_BUBBLE_STATES)?DEFAULT_STATE:state);
456 }
457 }
458 }
459 free(copy_orig);
460 return return_val;
461 }
462
diren_select_bubbles(struct dirent * d)463 int diren_select_bubbles (struct dirent *d) {
464 int color;
465 int state;
466
467 /* Check whether this is a .png file or not */
468 if(strcmp(d->d_name + strlen(d->d_name) - 4,".png")!=0) {
469 return 0;
470 }
471 return(parse_bubble_name(d->d_name,&color,&state));
472 }
473
load_animations(double zoom)474 void load_animations( double zoom ) {
475 int color=-1;
476 int state=-1;
477 int bubble_animation_size[NB_COLORS][NB_BUBBLE_STATES];
478 Set default_animation[NB_COLORS];
479 int default_animation_size[NB_COLORS];
480
481 struct dirent **namelist = NULL;
482 int n = 0;
483 int i;
484 char *dir = NULL;
485
486 alert_animation = load_animation( "frame_light.txt", zoom );
487 countdown_animation = load_animation( "countdown.txt", zoom );
488
489 for ( color = 0; color < NB_COLORS; color++ ) {
490 for ( state = 0; state < NB_BUBBLE_STATES; state++ ) {
491 bubble_animation[color][state] = NULL;
492 bubble_animation_size[color][state] = 0;
493 }
494 }
495
496 for ( color = 0; color < NB_COLORS; color++ ) {
497 default_animation[color] = NULL;
498 default_animation_size[color] = 0;
499 }
500
501 color=state=-1;
502
503 /* bubble animation */
504 dir = data_file("./",1);
505
506 n = scandir(dir, &namelist, diren_select_bubbles , alphasort);
507 if (n < 0) fail(_("Error while scanning %s"),dir);
508 for(i=0; i<n; i++) {
509 parse_bubble_name(namelist[i]->d_name,&color,&state);
510 if(state!=DEFAULT_STATE) {
511 bubble_animation_size[color][state]++;
512 } else {
513 default_animation_size[color]++;
514 }
515 }
516
517 for ( color = 0; color < NB_COLORS; color++ ) {
518 if(default_animation_size[color]) {
519 default_animation[color]= set_new(default_animation_size[color]);
520 }
521 for ( state = 0; state < NB_BUBBLE_STATES; state++ ) {
522 if(bubble_animation_size[color][state]==0) {
523 bubble_animation[color][state] = default_animation[color];
524 } else {
525 bubble_animation[color][state] = set_new(bubble_animation_size[color][state]);
526 }
527 }
528 }
529
530 for(i=0; i<n; i++) {
531 color = -1;
532 state = -1;
533 parse_bubble_name(namelist[i]->d_name,&color,&state);
534 if(state!=DEFAULT_STATE) {
535 set_add( bubble_animation[color][state],
536 load_frame(namelist[i]->d_name, zoom));
537 } else {
538 set_add( default_animation[color],
539 load_frame(namelist[i]->d_name, zoom));
540 }
541 }
542
543 for ( color = 0; color < NB_COLORS; color++ ) {
544 for ( state = 0; state < NB_BUBBLE_STATES; state++ ) {
545 if(bubble_animation[color][state]==NULL) {
546 fail(_("Badly formed theme : no image for %s bubbles in state %s"),
547 name_color_get(color),name_state_get(state));
548 }
549 }
550 }
551 for(i=0; i<n; i++)
552 free(namelist[i]);
553 free(namelist);
554 }
555
put_pixmap(Pixmap dest_pixmap,Pixmap dest_mask,Pixmap src_pixmap,Pixmap src_mask,int x,int y,int w,int h,int dx,int dy)556 void put_pixmap( Pixmap dest_pixmap,
557 Pixmap dest_mask,
558 Pixmap src_pixmap,
559 Pixmap src_mask,
560 int x, int y, int w, int h, int dx, int dy ) {
561 GC gc;
562 GC gc_mask;
563 XGCValues gcv;
564 unsigned long gcm;
565 gcm = GCFunction | GCGraphicsExposures;
566 gcv.graphics_exposures = False;
567 gcv.function = GXcopy;
568 gc = XCreateGC( display, root, gcm, &gcv );
569 gcv.function = GXor;
570 gc_mask = XCreateGC( display, dest_mask, gcm, &gcv );
571 XSetClipMask( display, gc, src_mask );
572 XSetClipOrigin( display, gc, dx, dy );
573 XCopyArea( display, src_pixmap, dest_pixmap, gc, x, y, w, h, dx, dy );
574 if ( src_mask != None )
575 XCopyArea( display, src_mask, dest_mask, gc_mask, x, y, w, h, dx, dy );
576 else {
577 XSetFillStyle( display, gc_mask, FillSolid );
578 XFillRectangle( display, dest_mask, gc_mask, dx, dy, w, h );
579 }
580 XFreeGC( display, gc );
581 XFreeGC( display, gc_mask );
582 }
583
load_images(double zoom)584 void load_images( double zoom ) {
585 GC gc;
586 GC gc_mask;
587 int x;
588 int y;
589 unsigned int width;
590 unsigned int height;
591 unsigned int d;
592 Window w;
593 Frame frame;
594 Pixmap tile;
595 Pixmap tile_mask;
596 Pixmap side;
597 Pixmap side_mask;
598 Pixmap tee;
599 Pixmap tee_mask;
600 Pixmap bottom;
601 Pixmap bottom_mask;
602 Pixmap bar;
603 XGCValues gcv;
604 unsigned long gcm;
605 gcm = GCFunction | GCGraphicsExposures;
606 gcv.graphics_exposures = False;
607 gcv.function = GXcopy;
608
609 load_scaled_image( "blue_bg.png", &tile, &tile_mask, zoom );
610 load_scaled_image( "side.png", &side, &side_mask, zoom );
611 load_scaled_image( "bar.png", &bar, NULL, zoom );
612 load_scaled_image( "tee.png", &tee, &tee_mask, zoom );
613 load_scaled_image( "bottom.png", &bottom, &bottom_mask, zoom );
614 load_scaled_image( "cup_on.png", &cup_on, &cup_on_mask, zoom);
615 load_scaled_image( "cup_off.png", &cup_off, &cup_off_mask, zoom);
616
617 width = board_win_width(scale);
618 height = board_win_height(scale);
619
620 /* make board background decoration */
621 board_decoration = XCreatePixmap( display, root, width, height, depth );
622 board_decoration_mask = XCreatePixmap( display, root, width, height, 1);
623 gc = XCreateGC( display, root, gcm, &gcv );
624 gc_mask = XCreateGC( display, board_decoration_mask, gcm, &gcv );
625
626 /* draw background tile */
627 XSetFillStyle( display, gc, FillTiled );
628 XSetTile( display, gc, tile );
629 XFillRectangle( display, board_decoration, gc, 0, 0, width, height);
630 XSetFillStyle( display, gc_mask, FillTiled );
631 XSetTile( display, gc_mask, tile_mask );
632 XFillRectangle( display, board_decoration_mask, gc_mask, 0, 0, width,height);
633
634 /* left side */
635 put_pixmap( board_decoration, board_decoration_mask, side, side_mask,
636 0, 0, scale_x( 0, scale), height, 0, 0 );
637 /* right side */
638 put_pixmap( board_decoration, board_decoration_mask, side, side_mask,
639 0, 0, scale_x( 0, scale), height, width - scale_x(0,scale), 0 );
640
641 /* bar */
642 x = scale_x( 0, scale );
643 y = scale_y( (ROWS-1)*ROW_HEIGHT, scale );
644 width = scale_x( BOARD_WIDTH, scale ) - x;
645 height = 20*scale/MAX_SCALE;
646 XSetTile( display, gc, bar );
647 XSetForeground( display, gc_mask, WhitePixel(display, root));
648 XSetFillStyle( display, gc_mask, FillSolid );
649 XSetClipMask( display, gc, None );
650 XSetClipOrigin( display, gc, 0, 0 );
651 XFillRectangle( display, board_decoration, gc, x, y, width, height );
652 XFillRectangle( display, board_decoration_mask, gc_mask, x, y, width,height);
653
654 /* add bottom */
655 XGetGeometry( display, bottom, &w, &x, &y, &width, &height, &d, &d );
656 x = ( board_win_width(scale) - width )/2;
657 y = board_win_height(scale) - height;
658 put_pixmap( board_decoration, board_decoration_mask, bottom, bottom_mask,
659 0, 0, width, height, x, y );
660 /* add tee */
661 XGetGeometry( display, tee, &w, &x, &y, &width, &height, &d, &d );
662 x = scale_x( 1.0, scale ) - width/2;
663 y = board_win_height(scale) - height;
664 put_pixmap( board_decoration, board_decoration_mask, tee, tee_mask,
665 0, 0, width, height, x, y );
666 /* add top */
667 frame = alert_animation->element[0];
668 XGetGeometry( display, frame->pixmap, &w, &x, &y, &width, &height, &d, &d );
669 x = ( board_win_width(scale) - width )/2;
670 put_pixmap( board_decoration, board_decoration_mask,
671 frame->pixmap, None,
672 0, 0, frame->width, frame->height, x, 0 );
673
674 /* cleanup */
675 XFreeGC( display, gc );
676 XFreeGC( display, gc_mask );
677 XFreePixmap( display, bar );
678 XFreePixmap( display, tile );
679 XFreePixmap( display, tile_mask );
680 XFreePixmap( display, side );
681 XFreePixmap( display, side_mask );
682 XFreePixmap( display, bottom );
683 XFreePixmap( display, bottom_mask );
684 XFreePixmap( display, tee );
685 XFreePixmap( display, tee_mask );
686 }
687
init_gcs()688 void init_gcs() {
689 /* load dialog font */
690 dialog_font = load_font( 3*scale/2 );
691 /* yellow for hilighting menu selection */
692 selected_gc = create_copy_gc();
693 XSetFont( display, selected_gc, menu_font->fid );
694 XSetForeground( display, selected_gc, get_pixel( menufont_selected_color[0],
695 menufont_selected_color[1],
696 menufont_selected_color[2] ));
697 /* grey for menu items */
698 menu_gc = create_copy_gc();
699 XSetFont( display, menu_gc, menu_font->fid );
700 XSetForeground( display, menu_gc, get_pixel( menufont_color[0], menufont_color[1],
701 menufont_color[2] ));
702 }
703
cleanup_graphics()704 void cleanup_graphics() {
705 int color;
706 delete_animation( alert_animation );
707 delete_animation( canon_animation );
708 delete_animation( countdown_animation );
709 /* FIXME: cleanup animations properly !
710 delete_frame( bubble_animation[0][DEAD]->element[1] );
711 */
712 for ( color = 0; color < NB_COLORS; color++ ) {
713 delete_animation( bubble_animation[color][STUCK] );
714 delete_animation( bubble_animation[color][EXPLODING] );
715 delete_animation( bubble_animation[color][DEAD] );
716 }
717 XFreeGC( display, dialog_gc );
718 XFreeGC( display, dialog_text_gc );
719 XFreeGC( display, menu_gc );
720 XFreeGC( display, selected_gc );
721 XFreePixmap( display, win_bg );
722 XFreePixmap( display, board_decoration );
723 XFreePixmap( display, board_decoration_mask );
724 XFreePixmap( display, cup_on );
725 XFreePixmap( display, cup_off );
726 XFreePixmap( display, cup_on_mask );
727 XFreePixmap( display, cup_off_mask );
728 XFreeFont( display, title_font );
729 XFreeFont( display, dialog_font );
730 XFreeFont( display, menu_font );
731 }
732
splash_screen(double zoom)733 void splash_screen( double zoom ) {
734 Window splash1=(Window)NULL;
735 Window splash2;
736 int height1;
737 int height2;
738 char * title = "XBubble";
739 char * subtitle = _("Loading graphics ...");
740
741 char *config_file = "config.txt";
742 FILE *fd = NULL ;
743 char line[128];
744 char *copy = NULL;
745 char *copy_orig = NULL;
746 char *token = NULL;
747 int lc=0;
748 int value = 0;
749 int *font_color = NULL;
750 int font_nb=0;
751 double newzoom = zoom;
752 int i;
753
754 fd = fopen( data_file(config_file,1), "r" );
755 if(fd) { /* time to change default values... */
756 while ( fgets( line, 128, fd ) != NULL ) {
757 lc++;
758 copy = copy_orig = calloc(strlen(line) + 1, sizeof(char));
759 strcpy(copy,line);
760 copy[strlen(line)-1]=' ';
761 token = strtok(copy," :");
762 if(token==NULL) continue;
763 if(strcmp(token,"BUBBLE_SIZE")==0) { /* We need to scale */
764 token = strtok(NULL," :");
765 if(sscanf(token,"%d",&value)!=1)
766 warn( _("error parsing line %d of file %s."), lc, config_file );
767 else
768 newzoom = zoom * MAX_SCALE / value;
769 } else if (((strcmp(token,"TITLE_COLOR")==0)&&((font_nb=1))) ||
770 ((strcmp(token,"MENU_COLOR")==0)&&((font_nb=2))) ||
771 ((strcmp(token,"MENU_SELECTED_COLOR")==0)&&((font_nb=3)))) {
772 switch (font_nb) {
773 case 1: font_color = titlefont_color; break;
774 case 2: font_color = menufont_color; break;
775 case 3: font_color = menufont_selected_color; break;
776 default: break;
777 }
778 for(i=0; i<3; i++) {
779 token = strtok(NULL," :");
780 if(sscanf(token,"%d",&font_color[i])!=1) {
781 warn( _("error parsing line %d of file %s."), lc, config_file );
782 break;
783 }
784 }
785 } else if (strcmp(token,"NO_TITLE")==0) {
786 notitle = 1;
787 } else
788 warn( _("error parsing line %d of file %s."), lc, config_file );
789 free(copy_orig);
790 }
791 fclose(fd);
792 }
793
794 load_scaled_image( "xbubble_bg.png", &win_bg, NULL, zoom);
795 XSetWindowBackgroundPixmap( display, win, win_bg );
796 XMapWindow( display, win );
797
798 /* load title & menu fonts */
799 title_font = load_font( 3*scale );
800 menu_font = load_font( scale );
801 height1 = title_font->ascent + title_font->descent;
802 height2 = menu_font->ascent + menu_font->descent;
803
804 /* make GCs */
805 dialog_gc = create_copy_gc();
806 dialog_text_gc = create_copy_gc();
807
808 /* GC for tiling dialogs background */
809 XSetFillStyle( display, dialog_gc, FillTiled );
810 XSetTile( display, dialog_gc, win_bg );
811 if (!notitle)
812 splash1 = create_dialog( win_width/2, ( win_height - height2 )/2, gettext(title),
813 title_font, get_pixel( titlefont_color[0], titlefont_color[1],
814 titlefont_color[2] ), 0, 1.0 );
815 splash2 = create_dialog( win_width/2, ( win_height + height1 )/2, gettext(subtitle),
816 menu_font, get_pixel( menufont_color[0], menufont_color[1],
817 menufont_color[2] ), 0, 1.0 );
818 load_levels( "levels.txt" );
819 load_animations(newzoom);
820 make_canon_animation(zoom);
821 load_images(zoom);
822 init_gcs();
823
824 if(!notitle)
825 XDestroyWindow( display, splash1 );
826 XDestroyWindow( display, splash2 );
827 }
828