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,
38 #include "SDL_rotozoom.h"
43 FreeList
* font_freelist
= NULL
;
45 static FontDescription font_desc
[] = {
47 * This is the list of fonts to be loaded. Be sure to
48 * use NULL as filename when using the same .ttf file
49 * the second time in a row - this saves memory in the
52 { "dustismo.ttf", 15, TTF_STYLE_NORMAL
},
53 { NULL
, 20, TTF_STYLE_NORMAL
},
54 { "itwasntme.ttf", 22, TTF_STYLE_NORMAL
},
55 { NULL
, 28, TTF_STYLE_NORMAL
}
58 static SDL_Surface
*buffer
;
59 static SDL_Surface
*background
;
61 static SDL_Rect
*rect_update_cache
;
62 static SDL_Rect
*rect_update_old
;
63 static int rect_update_cache_current
;
64 static int rect_update_old_count
;
66 Uint32 fading_start
= 0;
68 static const char* graphics
[] = {
90 "input_keyboard_arrows.png",
91 "input_keyboard_ol.png",
92 "input_keyboard_ws.png",
93 "input_maemo_dpad.png",
95 "input_touchscreen.png",
99 "loc_margaret_court_arena.png",
100 "loc_stade_roland_garros.png",
101 "loc_court_no_1.png",
102 "loc_arthur_ashe_stadium.png",
103 #ifdef NONFREE_LOCATIONS
104 "loc_training_camp.png",
105 "loc_austrian_open.png",
106 "loc_olympic_green_tennis.png"
110 void init_graphics() {
115 TennixArchive
*tnxar
;
116 struct SDL_RWops
* rw
;
117 char *font_data
= NULL
;
119 if (TTF_Init() == -1) {
120 fprintf(stderr
, "Cannot init TTF: %s\n", TTF_GetError());
124 rect_update_cache
= (SDL_Rect
*)calloc(RECT_UPDATE_CACHE
, sizeof(SDL_Rect
));
125 rect_update_old
= (SDL_Rect
*)calloc(RECT_UPDATE_CACHE
, sizeof(SDL_Rect
));
126 rect_update_cache_current
= 0;
127 rect_update_old_count
= 0;
129 images
= (Image
*)calloc( GR_COUNT
, sizeof( Image
));
130 fonts
= (Font
*)calloc(FONT_COUNT
, sizeof(Font
));
132 buffer
= SDL_CreateRGBSurface(SDL_SWSURFACE
, WIDTH
, HEIGHT
,
133 screen
->format
->BitsPerPixel
,
134 screen
->format
->Rmask
,
135 screen
->format
->Gmask
,
136 screen
->format
->Bmask
,
137 screen
->format
->Amask
);
139 background
= SDL_CreateRGBSurface(SDL_SWSURFACE
, WIDTH
, HEIGHT
,
140 screen
->format
->BitsPerPixel
,
141 screen
->format
->Rmask
,
142 screen
->format
->Gmask
,
143 screen
->format
->Bmask
,
144 screen
->format
->Amask
);
146 if( buffer
== NULL
) {
147 fprintf( stderr
, "Cannot create buffer surface: %s\n", SDL_GetError());
150 tnxar
= tnxar_open(ARCHIVE_FILE
);
152 /* not found in cwd - try installed... */
153 tnxar
= tnxar_open(ARCHIVE_FILE_INSTALLED
);
154 assert(tnxar
!= NULL
);
157 font_freelist
= freelist_create();
159 /* Load fonts from resource file */
160 for (i
=0; i
<FONT_COUNT
; i
++) {
161 if (font_desc
[i
].filename
!= NULL
) {
162 assert(tnxar_set_current_filename(tnxar
, font_desc
[i
].filename
) != 0);
163 font_data
= tnxar_read_current(tnxar
);
164 freelist_append(font_freelist
, font_data
);
166 assert(font_data
!= NULL
);
167 rw
= SDL_RWFromMem(font_data
, tnxar_size_current(tnxar
));
168 fonts
[i
].data
= TTF_OpenFontRW(rw
, 1, font_desc
[i
].size
);
169 assert(fonts
[i
].data
!= NULL
);
170 TTF_SetFontStyle(fonts
[i
].data
, font_desc
[i
].style
);
173 draw_button(40, (HEIGHT
-40)/2, WIDTH
-80, 40, 100, 100, 100, 1);
177 for( i
=0; i
<GR_COUNT
; i
++) {
178 if (tnxar_set_current_filename(tnxar
, graphics
[i
]) != 0) {
179 d
= tnxar_read_current(tnxar
);
180 tmp
= IMG_Load_RW(SDL_RWFromMem(d
, tnxar_size_current(tnxar
)), 1);
183 fprintf(stderr
, "Cannot find file: %s\n", graphics
[i
]);
187 fprintf( stderr
, "Error: %s\n", SDL_GetError());
191 /* Convert to RGBA in the display format */
192 data
= SDL_DisplayFormatAlpha(tmp
);
193 SDL_FreeSurface(tmp
);
196 fprintf( stderr
, "Error: %s\n", SDL_GetError());
199 images
[i
].data
= data
;
201 draw_button(40, (HEIGHT
-40)/2, (WIDTH
-80)*i
/(GR_COUNT
+SOUND_MAX
), 40, 100, 250, 100, 0);
202 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);
208 void uninit_graphics() {
211 for( i
=0; i
<GR_COUNT
; i
++) {
212 SDL_FreeSurface( images
[i
].data
);
215 if( buffer
!= NULL
) {
216 SDL_FreeSurface( buffer
);
219 if (background
!= NULL
) {
220 SDL_FreeSurface(background
);
223 free(rect_update_cache
);
224 free(rect_update_old
);
227 for (i
=0; i
<FONT_COUNT
; i
++) {
228 TTF_CloseFont(fonts
[i
].data
);
229 fonts
[i
].data
= NULL
;
233 freelist_free_all(font_freelist
);
239 FreeList
* freelist_create()
241 FreeList
* list
= (FreeList
*)malloc(sizeof(FreeList
));
242 assert(list
!= NULL
);
249 void freelist_append(FreeList
* list
, char* data
)
251 FreeListItem
* new_item
= (FreeListItem
*)malloc(sizeof(FreeListItem
));
253 assert(list
!= NULL
);
254 assert(data
!= NULL
);
256 new_item
->data
= data
;
258 /* Insert item at the beginning of list */
259 new_item
->next
= list
->head
;
260 list
->head
= new_item
;
263 void freelist_free_all(FreeList
* list
)
267 assert(list
!= NULL
);
269 while (list
->head
!= NULL
) {
270 /* Remove one item from the head of the list */
271 next
= list
->head
->next
;
272 free(list
->head
->data
);
281 int get_image_width( image_id id
) {
282 return images
[id
].data
->w
;
285 int get_image_height( image_id id
) {
286 return images
[id
].data
->h
;
289 int get_sprite_width( image_id id
, int items
) {
290 return images
[id
].data
->w
/ items
;
293 void show_sprite( image_id id
, int pos
, int items
, int x_offset
,
294 int y_offset
, int opacity
)
296 assert(id
< GR_COUNT
);
297 SDL_SetAlpha(images
[id
].data
, SDL_SRCALPHA
| SDL_RLEACCEL
, opacity
);
298 blit_surface(images
[id
].data
, x_offset
, y_offset
, pos
, items
);
301 void show_image_rotozoom(image_id id
, int x
, int y
, float rotate
, float zoom
)
306 assert(id
< GR_COUNT
);
308 tmp
= rotozoomSurface(images
[id
].data
, rotate
, zoom
, SMOOTHING_OFF
);
310 dst
.w
= src
.w
= tmp
->w
;
311 dst
.h
= src
.h
= tmp
->h
;
317 SDL_BlitSurface(tmp
, &src
, screen
, &dst
);
319 SDL_FreeSurface(tmp
);
322 void fill_image_offset( image_id id
, int x
, int y
, int w
, int h
, int offset_x
, int offset_y
) {
325 int dx
= 0, dy
= 0, cx
, cy
;
327 if( id
>= GR_COUNT
) return;
329 bitmap
= images
[id
].data
;
331 /* Make negative offsets positive */
333 offset_x
= (offset_x
%bitmap
->w
)+bitmap
->w
;
336 offset_y
= (offset_y
%bitmap
->h
)+bitmap
->h
;
339 src
.y
= offset_y
% bitmap
->h
;
341 src
.h
= dst
.h
= cy
= (h
-dy
> bitmap
->h
-src
.y
)?(bitmap
->h
-src
.y
):(h
-dy
);
345 src
.x
= offset_x
% bitmap
->w
;
347 src
.w
= dst
.w
= cx
= (w
-dx
> bitmap
->w
-src
.x
)?(bitmap
->w
-src
.x
):(w
-dx
);
350 SDL_BlitSurface( bitmap
, &src
, screen
, &dst
);
362 void line_horiz( int y
, Uint8 r
, Uint8 g
, Uint8 b
) {
363 rectangle(0, y
, screen
->w
, 1, r
, g
, b
);
366 void line_vert( int x
, Uint8 r
, Uint8 g
, Uint8 b
) {
367 rectangle(x
, 0, 1, screen
->h
, r
, g
, b
);
370 void rectangle( int x
, int y
, int w
, int h
, Uint8 r
, Uint8 g
, Uint8 b
) {
374 if (w
<= 0 || h
<= 0 || x
< 0 || y
< 0 || x
+w
> WIDTH
|| y
+h
> HEIGHT
) {
378 color
= SDL_MapRGB(screen
->format
, r
, g
, b
);
385 SDL_FillRect( screen
, &rect
, color
);
386 update_rect(x
, y
, w
, h
);
389 void rectangle_alpha(int x
, int y
, int w
, int h
, Uint8 r
, Uint8 g
, Uint8 b
, Uint8 opacity
)
393 SDL_Rect rect
, rect2
;
395 if (w
<= 0 || h
<= 0 || x
< 0 || y
< 0 || x
+w
> WIDTH
|| y
+h
> HEIGHT
) {
399 color
= SDL_MapRGB(screen
->format
, r
, g
, b
);
401 buf
= SDL_CreateRGBSurface(SDL_SWSURFACE
, w
, h
,
402 screen
->format
->BitsPerPixel
,
403 screen
->format
->Rmask
,
404 screen
->format
->Gmask
,
405 screen
->format
->Bmask
,
406 screen
->format
->Amask
);
411 rect
.w
= rect2
.w
= w
;
412 rect
.h
= rect2
.h
= h
;
414 SDL_FillRect(buf
, &rect
, color
);
415 SDL_SetAlpha(buf
, SDL_RLEACCEL
| SDL_SRCALPHA
, opacity
);
416 SDL_BlitSurface(buf
, &rect
, screen
, &rect2
);
417 update_rect(x
, y
, w
, h
);
419 SDL_FreeSurface(buf
);
422 void draw_button( int x
, int y
, int w
, int h
, Uint8 r
, Uint8 g
, Uint8 b
, char pressed
) {
423 float diff
= (pressed
?1.0-BUTTON_HIGHLIGHT
:1.0+BUTTON_HIGHLIGHT
);
424 rectangle(x
, y
, w
, h
, MIN(r
*diff
, 255), MIN(g
*diff
, 255), MIN(b
*diff
, 255));
425 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));
426 rectangle(x
+BUTTON_BORDER
, y
+BUTTON_BORDER
, w
-2*BUTTON_BORDER
, h
-2*BUTTON_BORDER
, r
, g
, b
);
429 void draw_button_text(const char* s
, int x
, int y
, int w
, int h
, Uint8 r
, Uint8 g
, Uint8 b
, char pressed
) {
432 pressed
= pressed
?1:0;
433 draw_button( x
, y
, w
, h
, r
, g
, b
, pressed
);
434 font_x
= x
+ w
/2 - font_get_string_width(FONT_SMALL
, s
)/2 + pressed
*BUTTON_BORDER
;
435 font_y
= y
+ h
/2 - font_get_height(FONT_SMALL
)/2 + pressed
*BUTTON_BORDER
;
436 font_draw_string_color(FONT_SMALL
, s
, font_x
, font_y
, (Uint8
)(r
*factor
), (Uint8
)(g
*factor
), (Uint8
)(b
*factor
));
439 void draw_button_object(MenuButton
* b
, int mx
, int my
)
441 if (b
->image_id
== GR_COUNT
) {
442 draw_button_text(b
->text
, b
->x
, b
->y
, b
->w
, b
->h
, b
->r
, b
->g
, b
->b
, M_POS_BUTTON(*b
, mx
, my
));
444 show_image_rotozoom(b
->image_id
, b
->x
+b
->w
/2, b
->y
+b
->h
/2, 0.0, 1.0+0.2*M_POS_BUTTON(*b
, mx
, my
));
456 SDL_FillRect(screen
, &rect
, SDL_MapRGB(screen
->format
, 0, 0, 0));
461 SDL_BlitSurface(screen
, NULL
, background
, NULL
);
462 rect_update_old
[0].x
= rect_update_old
[0].y
= 0;
463 rect_update_old
[0].w
= WIDTH
;
464 rect_update_old
[0].h
= HEIGHT
;
465 rect_update_old_count
= 1;
466 rect_update_cache_current
= 0;
473 SDL_BlitSurface(background
, NULL
, screen
, NULL
);
475 for (i
=0; i
<rect_update_cache_current
; i
++) {
476 SDL_BlitSurface(background
, &rect_update_cache
[i
], screen
, &rect_update_cache
[i
]);
479 /* Save rects I've just updated for redraw later */
480 tmp
= rect_update_cache
;
481 rect_update_cache
= rect_update_old
;
482 rect_update_old
= tmp
;
483 rect_update_old_count
= rect_update_cache_current
;
484 rect_update_cache_current
= 0;
487 void update_rect(Sint32 x
, Sint32 y
, Sint32 w
, Sint32 h
)
490 static int inside
= 0;
494 #ifdef DRAW_UPDATE_RECTANGLE
495 rectangle(x
, y
, w
, h
, 50+rand()%200, 50+rand()%200 ,50+rand()%200);
498 if ((x
>= WIDTH
) | (y
>= HEIGHT
) | (x
+w
<= 0) | (y
+h
<= 0) | (!w
) | (!h
)) {
503 if (rect_update_cache_current
== RECT_UPDATE_CACHE
) {
504 fprintf(stderr
, "Overflow\n");
505 rect_update_cache_current
= 0;
508 u
= &(rect_update_cache
[rect_update_cache_current
]);
510 if (x
< 0/* && x+w > 0*/) {
514 if (y
< 0/* && y+h > 0*/) {
537 rect_update_cache_current
++;
544 Uint32 ticks
= SDL_GetTicks();
545 SDL_Rect
*r_current
= NULL
, *end_current
= NULL
;
546 SDL_Rect
*r_old
= NULL
;
548 static int fading_last_time
= 0;
549 unsigned char fading_now
= ticks
< fading_start
+FADE_DURATION
;
552 SDL_SetAlpha(buffer
, SDL_SRCALPHA
| SDL_RLEACCEL
, 255-255*(ticks
-fading_start
)/FADE_DURATION
);
553 SDL_BlitSurface(buffer
, NULL
, screen
, NULL
);
554 SDL_UpdateRect(screen
, 0, 0, 0, 0);
555 } else if (fading_last_time
&& !fading_now
) {
556 SDL_UpdateRect(screen
, 0, 0, 0, 0);
558 if (rect_update_old_count
== rect_update_cache_current
) {
559 /* Merge rects into one single rect list */
560 r_old
= rect_update_old
;
561 r_current
= rect_update_cache
;
562 end_current
= rect_update_cache
+ rect_update_cache_current
;
563 while (r_current
!= end_current
) {
564 r_old
->w
= MAX(r_current
->x
+r_current
->w
, r_old
->x
+r_old
->w
);
565 r_old
->h
= MAX(r_current
->y
+r_current
->h
, r_old
->y
+r_old
->h
);
566 r_old
->x
= MIN(r_current
->x
, r_old
->x
);
567 r_old
->y
= MIN(r_current
->y
, r_old
->y
);
568 r_old
->w
-= r_old
->x
;
569 r_old
->h
-= r_old
->y
;
574 SDL_UpdateRects(screen
, rect_update_old_count
, rect_update_old
);
576 SDL_UpdateRects(screen
, rect_update_old_count
, rect_update_old
);
577 SDL_UpdateRects(screen
, rect_update_cache_current
, rect_update_cache
);
582 fading_last_time
= fading_now
;
586 SDL_BlitSurface( screen
, NULL
, buffer
, NULL
);
587 fading_start
= SDL_GetTicks();
590 SDL_Surface
* font_render_surface(font_id id
, const char* text
, Uint8 r
,
600 assert(id
< FONT_COUNT
);
602 result
= TTF_RenderText_Blended(fonts
[id
].data
, text
, color
);
604 assert(result
!= NULL
);
609 void blit_surface(SDL_Surface
* surface
, int x
, int y
, int pos
, int count
)
613 dst
.w
= src
.w
= surface
->w
/count
;
614 dst
.h
= src
.h
= surface
->h
;
620 SDL_BlitSurface(surface
, &src
, screen
, &dst
);
624 SDL_Surface
* get_surface(image_id id
)
626 assert(id
< GR_COUNT
);
627 return images
[id
].data
;
630 void font_draw_string_color(font_id id
, const char* s
, int x_offset
, int y_offset
, Uint8 r
, Uint8 g
, Uint8 b
) {
633 text
= font_render_surface(id
, s
, r
, g
, b
);
634 blit_surface_simple(text
, x_offset
, y_offset
);
635 SDL_FreeSurface(text
);
638 int font_get_string_width(font_id id
, const char* s
) {
641 assert(id
< FONT_COUNT
);
643 if (TTF_SizeText(fonts
[id
].data
, s
, &w
, &h
) != 0) {
650 int font_get_height(font_id id
) {
651 assert(id
< FONT_COUNT
);
652 return TTF_FontHeight(fonts
[id
].data
);
655 void draw_line_faded( int x1
, int y1
, int x2
, int y2
, int r
, int g
, int b
, int r2
, int g2
, int b2
) {
656 float step
, dx
, dy
, x
= x1
, y
= y1
;
658 char fade
= (r
!=r2
|| g
!=g2
|| b
!=b2
);
660 step
= (float)(abs(x2
-x1
)>abs(y2
-y1
)?abs(x2
-x1
):abs(y2
-y1
));
661 dx
= (float)(x2
-x1
) / step
;
662 dy
= (float)(y2
-y1
) / step
;
664 SDL_LockSurface( screen
);
665 for( i
=0; i
<step
; i
++) {
668 if( x
< 0.0 || x
>= WIDTH
|| y
< 0.0 || y
>= HEIGHT
) {
672 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
);
674 SET_PIXEL_RGB( screen
, (int)x
, (int)y
, r
, g
, b
);
677 SDL_UnlockSurface( screen
);