5 * Copyright (C) 2003, 2007, 2008, 2009 Thomas Perl <thp@thpinfo.com>
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
39 static SDL_Surface
*buffer
;
40 static SDL_Surface
*background
;
42 static SDL_Rect
*rect_update_cache
;
43 static SDL_Rect
*rect_update_old
;
44 static int rect_update_cache_current
;
45 static int rect_update_old_count
;
47 Uint32 fading_start
= 0;
49 static const char* graphics
[] = {
71 "loc_margaret_court_arena.png",
72 "loc_stade_roland_garros.png",
74 "loc_arthur_ashe_stadium.png"
77 void init_graphics() {
84 rect_update_cache
= (SDL_Rect
*)calloc(RECT_UPDATE_CACHE
, sizeof(SDL_Rect
));
85 rect_update_old
= (SDL_Rect
*)calloc(RECT_UPDATE_CACHE
, sizeof(SDL_Rect
));
86 rect_update_cache_current
= 0;
87 rect_update_old_count
= 0;
89 images
= (Image
*)calloc( GR_COUNT
, sizeof( Image
));
91 buffer
= SDL_CreateRGBSurface(SDL_SWSURFACE
, WIDTH
, HEIGHT
,
92 screen
->format
->BitsPerPixel
,
93 screen
->format
->Rmask
,
94 screen
->format
->Gmask
,
95 screen
->format
->Bmask
,
96 screen
->format
->Amask
);
98 background
= SDL_CreateRGBSurface(SDL_SWSURFACE
, WIDTH
, HEIGHT
,
99 screen
->format
->BitsPerPixel
,
100 screen
->format
->Rmask
,
101 screen
->format
->Gmask
,
102 screen
->format
->Bmask
,
103 screen
->format
->Amask
);
105 if( buffer
== NULL
) {
106 fprintf( stderr
, "Cannot create buffer surface: %s\n", SDL_GetError());
109 tnxar
= tnxar_open(ARCHIVE_FILE
);
111 /* not found in cwd - try installed... */
112 tnxar
= tnxar_open(ARCHIVE_FILE_INSTALLED
);
113 assert(tnxar
!= NULL
);
116 draw_button(40, (HEIGHT
-40)/2, WIDTH
-80, 40, 100, 100, 100, 1);
120 for( i
=0; i
<GR_COUNT
; i
++) {
121 if (tnxar_set_current_filename(tnxar
, graphics
[i
]) != 0) {
122 d
= tnxar_read_current(tnxar
);
123 tmp
= IMG_Load_RW(SDL_RWFromMem(d
, tnxar_size_current(tnxar
)), 0);
126 fprintf(stderr
, "Cannot find file: %s\n", graphics
[i
]);
130 fprintf( stderr
, "Error: %s\n", SDL_GetError());
134 if( GRAPHICS_IS_FONT(i
)) {
135 /* Convert to RGB w/ colorkey=black for opacity support */
136 SDL_SetColorKey( tmp
, SDL_SRCCOLORKEY
| SDL_RLEACCEL
, SDL_MapRGB( tmp
->format
, 0, 0, 0));
137 data
= SDL_ConvertSurface( tmp
, screen
->format
, SDL_SRCCOLORKEY
| SDL_RLEACCEL
);
139 /* Convert to RGBA for alpha channel from PNG */
140 data
= SDL_DisplayFormatAlpha( tmp
);
142 SDL_FreeSurface( tmp
);
145 fprintf( stderr
, "Error: %s\n", SDL_GetError());
148 images
[i
].data
= data
;
150 draw_button(40, (HEIGHT
-40)/2, (WIDTH
-80)*i
/(GR_COUNT
+SOUND_MAX
), 40, 100, 250, 100, 0);
151 rectangle(40+BUTTON_BORDER
*2, (HEIGHT
-40)/2+20+BUTTON_BORDER
, (WIDTH
-80)*i
/(GR_COUNT
+SOUND_MAX
)-BUTTON_BORDER
*2, 10, 170, 250, 170);
157 void uninit_graphics() {
160 for( i
=0; i
<GR_COUNT
; i
++) {
161 SDL_FreeSurface( images
[i
].data
);
164 if( buffer
!= NULL
) {
165 SDL_FreeSurface( buffer
);
168 if (background
!= NULL
) {
169 SDL_FreeSurface(background
);
172 free(rect_update_cache
);
173 free(rect_update_old
);
177 int get_image_width( image_id id
) {
178 return images
[id
].data
->w
;
181 int get_image_height( image_id id
) {
182 return images
[id
].data
->h
;
185 int get_sprite_width( image_id id
, int items
) {
186 return images
[id
].data
->w
/ items
;
189 void show_sprite( image_id id
, int pos
, int items
, int x_offset
, int y_offset
, int opacity
) {
193 bitmap
= images
[id
].data
;
197 SDL_SetAlpha( bitmap
, SDL_SRCALPHA
| SDL_RLEACCEL
, opacity
);
199 dst
.w
= src
.w
= bitmap
->w
/items
;
200 dst
.h
= src
.h
= bitmap
->h
;
206 SDL_BlitSurface( bitmap
, &src
, screen
, &dst
);
210 void fill_image_offset( image_id id
, int x
, int y
, int w
, int h
, int offset_x
, int offset_y
) {
213 int dx
= 0, dy
= 0, cx
, cy
;
215 if( id
>= GR_COUNT
) return;
217 bitmap
= images
[id
].data
;
219 /* Make negative offsets positive */
221 offset_x
= (offset_x
%bitmap
->w
)+bitmap
->w
;
224 offset_y
= (offset_y
%bitmap
->h
)+bitmap
->h
;
227 src
.y
= offset_y
% bitmap
->h
;
229 src
.h
= dst
.h
= cy
= (h
-dy
> bitmap
->h
-src
.y
)?(bitmap
->h
-src
.y
):(h
-dy
);
233 src
.x
= offset_x
% bitmap
->w
;
235 src
.w
= dst
.w
= cx
= (w
-dx
> bitmap
->w
-src
.x
)?(bitmap
->w
-src
.x
):(w
-dx
);
238 SDL_BlitSurface( bitmap
, &src
, screen
, &dst
);
250 void line_horiz( int y
, Uint8 r
, Uint8 g
, Uint8 b
) {
251 rectangle(0, y
, screen
->w
, 1, r
, g
, b
);
254 void line_vert( int x
, Uint8 r
, Uint8 g
, Uint8 b
) {
255 rectangle(x
, 0, 1, screen
->h
, r
, g
, b
);
258 void rectangle( int x
, int y
, int w
, int h
, Uint8 r
, Uint8 g
, Uint8 b
) {
259 Uint32 color
= SDL_MapRGB( screen
->format
, r
, g
, b
);
267 SDL_FillRect( screen
, &rect
, color
);
268 update_rect(x
, y
, w
, h
);
271 void draw_button( int x
, int y
, int w
, int h
, Uint8 r
, Uint8 g
, Uint8 b
, char pressed
) {
272 float diff
= (pressed
?1.0-BUTTON_HIGHLIGHT
:1.0+BUTTON_HIGHLIGHT
);
273 rectangle(x
, y
, w
, h
, MIN(r
*diff
, 255), MIN(g
*diff
, 255), MIN(b
*diff
, 255));
274 rectangle(x
+BUTTON_BORDER
, y
+BUTTON_BORDER
, w
-BUTTON_BORDER
, h
-BUTTON_BORDER
, MIN(r
/diff
, 255), MIN(g
/diff
, 255), MIN(b
/diff
, 255));
275 rectangle(x
+BUTTON_BORDER
, y
+BUTTON_BORDER
, w
-2*BUTTON_BORDER
, h
-2*BUTTON_BORDER
, r
, g
, b
);
278 void draw_button_text(const char* s
, int x
, int y
, int w
, int h
, Uint8 r
, Uint8 g
, Uint8 b
, char pressed
) {
280 pressed
= pressed
?1:0;
281 draw_button( x
, y
, w
, h
, r
, g
, b
, pressed
);
282 font_x
= x
+ w
/2 - font_get_string_width( GR_SMALLISH_FONT
, s
)/2 + pressed
*BUTTON_BORDER
;
283 font_y
= y
+ h
/2 - get_image_height( GR_SMALLISH_FONT
)/2 + pressed
*BUTTON_BORDER
;
284 font_draw_string( GR_SMALLISH_FONT
, s
, font_x
, font_y
, 0, 0);
295 SDL_FillRect(screen
, &rect
, SDL_MapRGB(screen
->format
, 0, 0, 0));
300 SDL_BlitSurface(screen
, NULL
, background
, NULL
);
301 rect_update_old
[0].x
= rect_update_old
[0].y
= 0;
302 rect_update_old
[0].w
= WIDTH
;
303 rect_update_old
[0].h
= HEIGHT
;
304 rect_update_old_count
= 1;
305 rect_update_cache_current
= 0;
312 SDL_BlitSurface(background
, NULL
, screen
, NULL
);
314 for (i
=0; i
<rect_update_cache_current
; i
++) {
315 SDL_BlitSurface(background
, &rect_update_cache
[i
], screen
, &rect_update_cache
[i
]);
318 /* Save rects I've just updated for redraw later */
319 tmp
= rect_update_cache
;
320 rect_update_cache
= rect_update_old
;
321 rect_update_old
= tmp
;
322 rect_update_old_count
= rect_update_cache_current
;
323 rect_update_cache_current
= 0;
326 void update_rect(Sint32 x
, Sint32 y
, Sint32 w
, Sint32 h
)
329 static int inside
= 0;
333 #ifdef DRAW_UPDATE_RECTANGLE
334 rectangle(x
, y
, w
, h
, 50+rand()%200, 50+rand()%200 ,50+rand()%200);
337 if ((x
>= WIDTH
) | (y
>= HEIGHT
) | (x
+w
<= 0) | (y
+h
<= 0) | (!w
) | (!h
)) {
342 if (rect_update_cache_current
== RECT_UPDATE_CACHE
) {
343 fprintf(stderr
, "Overflow\n");
344 rect_update_cache_current
= 0;
347 u
= &(rect_update_cache
[rect_update_cache_current
]);
349 if (x
< 0/* && x+w > 0*/) {
353 if (y
< 0/* && y+h > 0*/) {
376 rect_update_cache_current
++;
383 Uint32 ticks
= SDL_GetTicks();
384 SDL_Rect
*r_current
= NULL
, *end_current
= NULL
;
385 SDL_Rect
*r_old
= NULL
;
387 static int fading_last_time
= 0;
388 unsigned char fading_now
= ticks
< fading_start
+FADE_DURATION
;
391 SDL_SetAlpha(buffer
, SDL_SRCALPHA
| SDL_RLEACCEL
, 255-255*(ticks
-fading_start
)/FADE_DURATION
);
392 SDL_BlitSurface(buffer
, NULL
, screen
, NULL
);
393 SDL_UpdateRect(screen
, 0, 0, 0, 0);
394 } else if (fading_last_time
&& !fading_now
) {
395 SDL_UpdateRect(screen
, 0, 0, 0, 0);
397 if (rect_update_old_count
== rect_update_cache_current
) {
398 /* Merge rects into one single rect list */
399 r_old
= rect_update_old
;
400 r_current
= rect_update_cache
;
401 end_current
= rect_update_cache
+ rect_update_cache_current
;
402 while (r_current
!= end_current
) {
403 r_old
->w
= MAX(r_current
->x
+r_current
->w
, r_old
->x
+r_old
->w
);
404 r_old
->h
= MAX(r_current
->y
+r_current
->h
, r_old
->y
+r_old
->h
);
405 r_old
->x
= MIN(r_current
->x
, r_old
->x
);
406 r_old
->y
= MIN(r_current
->y
, r_old
->y
);
407 r_old
->w
-= r_old
->x
;
408 r_old
->h
-= r_old
->y
;
413 SDL_UpdateRects(screen
, rect_update_old_count
, rect_update_old
);
415 SDL_UpdateRects(screen
, rect_update_old_count
, rect_update_old
);
416 SDL_UpdateRects(screen
, rect_update_cache_current
, rect_update_cache
);
421 fading_last_time
= fading_now
;
425 SDL_BlitSurface( screen
, NULL
, buffer
, NULL
);
426 fading_start
= SDL_GetTicks();
429 int font_get_metrics(image_id id
, unsigned char ch
, int* xp
, int* wp
) {
430 /* Caching of x and width values for faster calculation */
431 static int xcache
[0xFF][GRAPHICS_FONT_COUNT
],
432 wcache
[0xFF][GRAPHICS_FONT_COUNT
];
433 static unsigned char cacheflag
[0xFF][GRAPHICS_FONT_COUNT
];
436 int pos
, x
= -1, w
= 0;
437 int search_pos
= 0, search_x
= 0;
438 unsigned char font_index
= id
-GRAPHICS_FONT_FIRST
;
439 Uint8 red
, green
, blue
;
441 if(!GRAPHICS_IS_FONT(id
)) return 0;
443 if (cacheflag
[ch
][font_index
]) {
445 if (xp
!= NULL
) *xp
= xcache
[ch
][font_index
];
446 if (wp
!= NULL
) *wp
= wcache
[ch
][font_index
];
447 return wcache
[ch
][font_index
];
450 pos
= toupper( ch
) - ' '; /* ' ' = first character in font bitmap */
452 bitmap
= images
[id
].data
;
454 SDL_LockSurface( bitmap
);
455 while( search_x
< bitmap
->w
) {
456 GET_PIXEL_RGB( bitmap
, search_x
, 0, &red
, &green
, &blue
);
458 /* Increase pos counter if we have a "marker" pixel (255,0,255) */
459 if( red
> 250 && green
< 10 && blue
> 250) {
461 if( search_pos
== pos
) {
463 } else if( search_pos
== pos
+ 1) {
471 SDL_UnlockSurface( bitmap
);
473 if( wp
!= NULL
) (*wp
) = w
;
474 if( xp
!= NULL
) (*xp
) = x
;
476 cacheflag
[ch
][font_index
]++;
477 xcache
[ch
][font_index
] = x
;
478 wcache
[ch
][font_index
] = w
;
483 int font_draw_char( image_id id
, char ch
, int x_offset
, int y_offset
) {
488 font_get_metrics( id
, ch
, &x
, &w
);
489 if( x
== -1) return w
;
491 bitmap
= images
[id
].data
;
494 dst
.h
= src
.h
= bitmap
->h
- 1;
500 SDL_BlitSurface( bitmap
, &src
, screen
, &dst
);
505 void font_draw_string_alpha( image_id id
, const char* s
, int x_offset
, int y_offset
, int start
, int animation
, int opacity
) {
508 int additional_x
= 0, additional_y
= 0;
509 float xw
= 0.0, xw_diff
= 0.0;
513 if( id
> GR_COUNT
) return;
515 bitmap
= images
[id
].data
;
516 SDL_SetAlpha( bitmap
, SDL_SRCALPHA
| SDL_RLEACCEL
, opacity
);
518 if( animation
& ANIMATION_BUNGEE
) {
519 xw
= (25.0*sinf( start
/10.0));
523 if( animation
& ANIMATION_PENDULUM
) {
524 x
-= (int)(20.0*sinf( start
/20.0));
528 for( i
=0; i
<strlen(s
); i
++) {
529 if( animation
& ANIMATION_WAVE
) {
530 y
= y_offset
+ (int)(3.0*sinf( start
/10.0 + x
/30.0));
532 x
+= font_draw_char( id
, s
[i
], x
, y
);
533 if( animation
& ANIMATION_BUNGEE
) {
534 xw_diff
+= xw
/strlen(s
);
535 if( xw_diff
> 1.0 || xw_diff
< -1.0) {
545 if (animation
& ANIMATION_WAVE
) {
548 if (animation
& ANIMATION_BUNGEE
) {
551 update_rect(x_offset
-additional_x
, y_offset
-additional_y
, x
-x_offset
+additional_x
*2, get_image_height(id
)+additional_y
*2);
554 int font_get_string_width( image_id id
, const char* s
) {
558 for( i
=0; i
<strlen(s
); i
++) {
559 w
+= font_get_metrics( id
, s
[i
], NULL
, NULL
);
565 void draw_line_faded( int x1
, int y1
, int x2
, int y2
, int r
, int g
, int b
, int r2
, int g2
, int b2
) {
566 float step
, dx
, dy
, x
= x1
, y
= y1
;
568 char fade
= (r
!=r2
|| g
!=g2
|| b
!=b2
);
570 step
= (float)(abs(x2
-x1
)>abs(y2
-y1
)?abs(x2
-x1
):abs(y2
-y1
));
571 dx
= (float)(x2
-x1
) / step
;
572 dy
= (float)(y2
-y1
) / step
;
574 SDL_LockSurface( screen
);
575 for( i
=0; i
<step
; i
++) {
578 if( x
< 0.0 || x
>= WIDTH
|| y
< 0.0 || y
>= HEIGHT
) {
582 SET_PIXEL_RGB( screen
, (int)x
, (int)y
, (r
*(step
-i
)+r2
*i
)/step
, (g
*(step
-i
)+g2
*i
)/step
, (b
*(step
-i
)+b2
*i
)/step
);
584 SET_PIXEL_RGB( screen
, (int)x
, (int)y
, r
, g
, b
);
587 SDL_UnlockSurface( screen
);