Joystick support (via command line); better keyboard controls
[tennix.git] / graphics.c
blob4e460ed4ee9abd3a6b4cac78da69306b01f12f49
2 /**
4 * Tennix! SDL Port
5 * Copyright (C) 2003, 2007 Thomas Perl <thp@perli.net>
6 *
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,
20 * MA 02110-1301, USA.
22 **/
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <math.h>
28 #include "tennix.h"
29 #include "graphics.h"
31 static Image* images;
33 static SDL_Surface *buffer;
35 static Uint32 fading_start = 0;
37 #include "data/graphics_data.c"
38 static const ResourceData graphics[] = {
39 RESOURCE(court),
40 RESOURCE(shadow),
41 RESOURCE(player_racket),
42 RESOURCE(ground),
43 RESOURCE(ball),
44 RESOURCE(menu),
45 RESOURCE(smallish_font),
46 RESOURCE(dkc2),
47 RESOURCE(referee),
48 RESOURCE(ctt_hard),
49 RESOURCE(ctt_clay),
50 RESOURCE(ctt_grass)
53 void init_graphics() {
54 int i;
55 SDL_Surface* data;
56 SDL_Surface* tmp;
58 #ifndef MACOSX
59 tmp = IMG_Load_RW( SDL_RWFromConstMem( icon, sizeof(icon)), 1);
60 if( tmp != NULL) {
61 SDL_WM_SetIcon( tmp, NULL);
62 SDL_FreeSurface( tmp);
64 #endif
66 images = (Image*)calloc( GR_COUNT, sizeof( Image));
68 for( i=0; i<GR_COUNT; i++) {
69 tmp = IMG_Load_RW( SDL_RWFromConstMem( graphics[i].data, graphics[i].size), 1);
70 if( !tmp) {
71 fprintf( stderr, "Error: %s\n", SDL_GetError());
72 continue;
75 if( GRAPHICS_IS_FONT(i)) {
76 /* Convert to RGB w/ colorkey=black for opacity support */
77 SDL_SetColorKey( tmp, SDL_SRCCOLORKEY | SDL_RLEACCEL, SDL_MapRGB( tmp->format, 0, 0, 0));
78 data = SDL_ConvertSurface( tmp, screen->format, SDL_SRCCOLORKEY | SDL_RLEACCEL);
79 } else {
80 /* Convert to RGBA for alpha channel from PNG */
81 data = SDL_DisplayFormatAlpha( tmp);
83 SDL_FreeSurface( tmp);
85 if( !data) {
86 fprintf( stderr, "Error: %s\n", SDL_GetError());
87 continue;
89 images[i].data = data;
92 buffer = SDL_CreateRGBSurface( SDL_HWSURFACE, WIDTH, HEIGHT, screen->format->BitsPerPixel, screen->format->Rmask, screen->format->Gmask, screen->format->Bmask, screen->format->Amask);
94 if( buffer == NULL) {
95 fprintf( stderr, "Cannot create buffer surface: %s\n", SDL_GetError());
99 void uninit_graphics() {
100 int i;
102 for( i=0; i<GR_COUNT; i++) {
103 SDL_FreeSurface( images[i].data);
106 if( buffer != NULL) {
107 SDL_FreeSurface( buffer);
110 free( images);
113 int get_image_width( image_id id) {
114 return images[id].data->w;
117 int get_image_height( image_id id) {
118 return images[id].data->h;
121 int get_sprite_width( image_id id, int items) {
122 return images[id].data->w / items;
125 void show_sprite( image_id id, int pos, int items, int x_offset, int y_offset, int opacity) {
126 SDL_Surface *bitmap;
127 SDL_Rect src, dst;
129 bitmap = images[id].data;
131 if( !bitmap) return;
133 SDL_SetAlpha( bitmap, SDL_SRCALPHA | SDL_RLEACCEL, opacity);
135 dst.w = src.w = bitmap->w/items;
136 dst.h = src.h = bitmap->h;
137 src.x = src.w*pos;
138 src.y = 0;
139 dst.x = x_offset;
140 dst.y = y_offset;
142 SDL_BlitSurface( bitmap, &src, screen, &dst);
145 void fill_image( image_id id, int x, int y, int w, int h) {
146 SDL_Surface *bitmap;
147 SDL_Rect src, dst;
148 int dx = 0, dy = 0, cx, cy;
150 if( id >= GR_COUNT) return;
152 bitmap = images[id].data;
153 src.x = src.y = 0;
155 while( dy < h) {
156 src.h = dst.h = cy = (h-dy > bitmap->h)?(bitmap->h):(h-dy);
157 dst.y = y+dy;
159 dx = 0;
160 while( dx < w) {
161 src.w = dst.w = cx = (w-dx > bitmap->w)?(bitmap->w):(w-dx);
162 dst.x = x+dx;
164 SDL_BlitSurface( bitmap, &src, screen, &dst);
166 dx += cx;
169 dy += cy;
173 void line_horiz( int y, Uint8 r, Uint8 g, Uint8 b) {
174 Uint32 color = SDL_MapRGB( screen->format, r, g, b);
175 SDL_Rect rect;
177 rect.x = 0;
178 rect.w = screen->w;
179 rect.y = y;
180 rect.h = 1;
182 SDL_FillRect( screen, &rect, color);
185 void line_vert( int x, Uint8 r, Uint8 g, Uint8 b) {
186 Uint32 color = SDL_MapRGB( screen->format, r, g, b);
187 SDL_Rect rect;
189 rect.x = x;
190 rect.w = 1;
191 rect.y = 0;
192 rect.h = screen->h;
194 SDL_FillRect( screen, &rect, color);
197 void rectangle( int x, int y, int w, int h, Uint8 r, Uint8 g, Uint8 b) {
198 Uint32 color = SDL_MapRGB( screen->format, r, g, b);
199 SDL_Rect rect;
201 rect.x = x;
202 rect.y = y;
203 rect.w = w;
204 rect.h = h;
206 SDL_FillRect( screen, &rect, color);
209 void draw_button( int x, int y, int w, int h, Uint8 r, Uint8 g, Uint8 b, char pressed) {
210 float diff = (pressed?1.0-BUTTON_HIGHLIGHT:1.0+BUTTON_HIGHLIGHT);
211 int border = BUTTON_BORDER;
212 rectangle( x, y, w, h, r*diff, g*diff, b*diff);
213 rectangle( x+border, y+border, w-border, h-border, r/diff, g/diff, b/diff);
214 rectangle( x+border, y+border, w-2*border, h-2*border, r, g, b);
217 void draw_button_text( char* s, int x, int y, int w, int h, Uint8 r, Uint8 g, Uint8 b, char pressed) {
218 int font_x, font_y;
219 pressed = pressed?1:0;
220 draw_button( x, y, w, h, r, g, b, pressed);
221 font_x = x + w/2 - font_get_string_width( GR_SMALLISH_FONT, s)/2 + pressed*BUTTON_BORDER;
222 font_y = y + h/2 - get_image_height( GR_SMALLISH_FONT)/2 + pressed*BUTTON_BORDER;
223 font_draw_string( GR_SMALLISH_FONT, s, font_x, font_y, 0, 0);
226 void show_image( image_id id, int x_offset, int y_offset, int opacity) {
227 show_sprite( id, 0, 1, x_offset, y_offset, opacity);
230 void clearscr() {
231 SDL_Rect rect;
233 rect.x = 0;
234 rect.y = 0;
235 rect.w = WIDTH;
236 rect.h = HEIGHT;
238 SDL_FillRect( screen, &rect, SDL_MapRGB( screen->format, 0, 0, 0));
241 void updatescr() {
242 int ticks = SDL_GetTicks();
244 if( ticks < fading_start+FADE_DURATION) {
245 SDL_SetAlpha( buffer, SDL_SRCALPHA | SDL_RLEACCEL, 255-255*(ticks-fading_start)/FADE_DURATION);
246 SDL_BlitSurface( buffer, NULL, screen, NULL);
249 SDL_UpdateRect( screen, 0, 0, 0, 0);
250 SDL_Flip( screen);
253 void start_fade() {
254 SDL_BlitSurface( screen, NULL, buffer, NULL);
255 fading_start = SDL_GetTicks();
258 int is_fading() {
259 return SDL_GetTicks() < fading_start+FADE_DURATION;
262 int font_get_metrics( image_id id, char ch, int* xp, int* wp) {
263 SDL_Surface *bitmap;
264 int pos, x = -1, w = 0;
265 int search_pos = 0, search_x = 0;
266 Uint8 red, green, blue;
268 if( id >= GR_COUNT) return 0;
270 pos = toupper( ch) - ' '; /* ' ' = first character in font bitmap */
272 bitmap = images[id].data;
274 SDL_LockSurface( bitmap);
275 while( search_x < bitmap->w) {
276 GET_PIXEL_RGB( bitmap, search_x, 0, &red, &green, &blue);
278 /* Increase pos counter if we have a "marker" pixel (255,0,255) */
279 if( red > 250 && green < 10 && blue > 250) {
280 search_pos++;
281 if( search_pos == pos) {
282 x = search_x;
283 } else if( search_pos == pos + 1) {
284 w = search_x - x;
285 break;
289 search_x++;
291 SDL_UnlockSurface( bitmap);
293 if( wp != NULL) (*wp) = w;
294 if( xp != NULL) (*xp) = x;
296 return w;
299 int font_draw_char( image_id id, char ch, int x_offset, int y_offset) {
300 SDL_Surface *bitmap;
301 SDL_Rect src, dst;
302 int x = -1, w = 0;
304 font_get_metrics( id, ch, &x, &w);
305 if( x == -1) return w;
307 bitmap = images[id].data;
309 dst.w = src.w = w;
310 dst.h = src.h = bitmap->h - 1;
311 src.x = x;
312 src.y = 1;
313 dst.x = x_offset;
314 dst.y = y_offset;
316 SDL_BlitSurface( bitmap, &src, screen, &dst);
318 return src.w;
321 void font_draw_string_alpha( image_id id, const char* s, int x_offset, int y_offset, int start, int animation, int opacity) {
322 int y = y_offset;
323 int x = x_offset;
324 int i;
325 float xw = 0.0, xw_diff;
326 SDL_Surface *bitmap;
328 if( id > GR_COUNT) return;
330 bitmap = images[id].data;
331 SDL_SetAlpha( bitmap, SDL_SRCALPHA | SDL_RLEACCEL, opacity);
333 if( animation & ANIMATION_BUNGEE) {
334 xw = (25.0*sinf( start/10.0));
335 xw_diff = 0.0;
336 x -= xw / 2;
339 if( animation & ANIMATION_PENDULUM) {
340 x -= (int)(20.0*sinf( start/20.0));
343 for( i=0; i<strlen(s); i++) {
344 if( animation & ANIMATION_WAVE) {
345 y = y_offset + (int)(3.0*sinf( start/10.0 + x/30.0));
347 x += font_draw_char( id, s[i], x, y);
348 if( animation & ANIMATION_BUNGEE) {
349 xw_diff += xw/strlen(s);
350 if( xw_diff > 1.0 || xw_diff < -1.0) {
351 x += (int)(xw_diff);
352 if( xw_diff > 1.0) {
353 xw_diff -= 1.0;
354 } else {
355 xw_diff += 1.0;
362 int font_get_string_width( image_id id, const char* s) {
363 int w = 0, i;
365 for( i=0; i<strlen(s); i++) {
366 w += font_get_metrics( id, s[i], NULL, NULL);
369 return w;
372 void draw_line_faded( int x1, int y1, int x2, int y2, int r, int g, int b, int r2, int g2, int b2) {
373 float step, dx, dy, x = x1, y = y1;
374 int i;
375 char fade = (r!=r2 || g!=g2 || b!=b2);
377 step = (float)(abs(x2-x1)>abs(y2-y1)?abs(x2-x1):abs(y2-y1));
378 dx = (float)(x2-x1) / step;
379 dy = (float)(y2-y1) / step;
381 SDL_LockSurface( screen);
382 for( i=0; i<step; i++) {
383 x += dx;
384 y += dy;
385 if( x < 0.0 || x >= WIDTH || y < 0.0 || y >= HEIGHT) {
386 continue;
388 if( fade) {
389 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);
390 } else {
391 SET_PIXEL_RGB( screen, (int)x, (int)y, r, g, b);
394 SDL_UnlockSurface( screen);