Merge branch 'audio'
[cantaveria.git] / video.c
blob71df5e1eb15c281d68924fe7365769bffb1e30c4
1 /*
2 Cantaveria - action adventure platform game
3 Copyright (C) 2009 2010 Evan Rinehart
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to
18 The Free Software Foundation, Inc.
19 51 Franklin Street, Fifth Floor
20 Boston, MA 02110-1301, USA
23 #include <math.h>
25 #include <SDL/SDL.h>
26 #include <SDL/SDL_opengl.h>
28 #include <list.h>
29 #include <root.h>
30 #include <util.h>
31 #include <video.h>
32 #include <loader.h>
34 SDL_Surface* video;
35 int gl_flag = 0;
36 int fullscreen = 0;
37 int W, H;
40 static int time_last; /* initialized by backend_init */
41 int since(){
42 int time_now = SDL_GetTicks();
43 int diff = time_now - time_last;
44 time_last = time_now;
45 return diff;
48 void delay(int ms){
49 SDL_Delay(ms);
59 struct {
60 char* filename;
61 SDL_Surface* surf;
62 GLuint texture;
63 int w;
64 int h;
65 } gfx[MAX_GFX];
66 int gfx_count = 0;
68 int screen_w = 320;
69 int screen_h = 240;
70 int screen_offset_x = 0;
71 int screen_offset_y = 0;
76 /********************/
77 /* drawing routines */
78 /********************/
80 void draw_gfx_raw(int gfxid, int x, int y, int X, int Y, int W, int H){
81 if(x > screen_w || y > screen_h || x+W < 0 || y+H < 0) return;
82 if(!gl_flag){
83 SDL_Surface* surf = gfx[gfxid].surf;
84 SDL_Rect r1 = {X,Y,W,H};
85 SDL_Rect r2 = {x,y,W,H};
86 SDL_BlitSurface(surf,&r1,video,&r2);
88 else{
89 double w = gfx[gfxid].w;
90 double h = gfx[gfxid].h;
91 double X0 = ((double)X)/w;
92 double X1 = X0 + ((double)W)/w;
93 double Y0 = ((double)Y)/h;
94 double Y1 = Y0 + ((double)H)/h;
96 glBindTexture( GL_TEXTURE_2D, gfx[gfxid].texture );
97 glBegin( GL_QUADS );
98 glTexCoord2d(X0,Y0);
99 glVertex3f(x,y,0);
101 glTexCoord2d(X1,Y0);
102 glVertex3f(x+W,y,0);
104 glTexCoord2d(X1,Y1);
105 glVertex3f(x+W,y+H,0);
107 glTexCoord2d(X0,Y1);
108 glVertex3f(x,y+H,0);
109 glEnd();
113 void draw_gfx(int gfxid, int x, int y, int X, int Y, int W, int H){
114 draw_gfx_raw(gfxid, x+screen_offset_x, y+screen_offset_y, X, Y, W, H);
117 void clear_video(){
118 if(!gl_flag){
119 SDL_FillRect(video, 0, 0);
121 else{
122 glClearColor(0.0,0.0,0.0,0.0);
123 glClear( GL_COLOR_BUFFER_BIT );
127 void update_video(){
128 if(!gl_flag){
129 SDL_UpdateRect(video,0,0,0,0);
131 else{
132 SDL_GL_SwapBuffers();
139 /********************/
140 /* graphics loading */
141 /********************/
143 SDL_Surface* SDL_NewSurface(int w, int h){
144 char prefix[32] = "SDL_NewSurface";
145 SDL_Surface* tmp = SDL_CreateRGBSurface(SDL_SRCCOLORKEY,w,h,32,0,0,0,0);
146 if(!tmp){
147 out_of_memory(prefix);
150 SDL_Surface* surf = SDL_DisplayFormat(tmp);
151 if(!surf){
152 out_of_memory(prefix);
155 SDL_FreeSurface(tmp);
157 SDL_FillRect(surf,0,0x00ffffff);
159 return surf;
162 SDL_Surface* load_pixmap(char* filename){
163 char path[256] = "gfx/";
164 strmcat(path, filename, 256);
166 reader* rd = loader_open(path);
167 if(!rd){
168 error_msg("load_pixmap: error opening file\n");
169 return NULL;
172 unsigned char header[18];
173 if(loader_read(rd, header, 18) < 0){
174 error_msg("load_pixmap: error reading pixmap header\n");
175 loader_close(rd);
176 return NULL;
179 int w = header[12] + (header[13]<<8);
180 int h = header[14] + (header[15]<<8);
181 int bpp = header[16];
182 //printf("load_pixmap: %s has bpp=%d\n",filename, bpp);
183 SDL_Surface* surf = SDL_CreateRGBSurface(0,w,h,bpp,
184 0x00ff0000,0x0000ff00,0x000000ff,0xff000000);
185 if(!surf){
186 out_of_memory("load_pixmap");
188 if(loader_read(rd, surf->pixels, w*(bpp/8)*h) < 0){
189 error_msg("load_pixmap: error reading pixmap data\n");
190 loader_close(rd);
191 SDL_FreeSurface(surf);
192 return NULL;
194 loader_close(rd);
196 return surf;
199 int load_gfx(char* filename){
200 int i, j;
202 if(gfx_count == MAX_GFX){
203 fatal_error(
204 "load_gfx: cannot load any more than %d graphics\n",
205 MAX_GFX
210 //printf("loading %s\n",filename);
213 for(i=0; i<gfx_count; i++){/*check for already loaded gfx*/
214 if(strcmp(gfx[i].filename, filename)==0){
215 return i;
219 SDL_Surface* src = load_pixmap(filename);
220 if(!src){
221 fatal_error("load_gfx: failed to load %s\n",filename);
224 if(!gl_flag){
225 SDL_Surface* surf = SDL_DisplayFormatAlpha(src);
226 SDL_SetAlpha(surf, 0, 0);
228 Uint32 key = SDL_MapRGB(
229 surf->format,
230 (COLOR_KEY&0xff0000)>>16,
231 (COLOR_KEY&0x00ff00)>>8,
232 (COLOR_KEY&0x0000ff)>>0
234 SDL_SetColorKey(surf, SDL_SRCCOLORKEY, key);
236 SDL_FreeSurface(src);
239 gfx[gfx_count].filename = strxcpy(filename);
240 gfx[gfx_count].surf = surf;
241 gfx[gfx_count].w = surf->w;
242 gfx[gfx_count].h = surf->h;
244 else {
245 GLuint texture;
247 //SDL_Surface* conv = SDL_CreateRGBSurface(0, pot(src->w), pot(src->h), 32,
248 //0xff<<16,0xff<<8,0xff<<0,0);
250 //SDL_Surface* tmp = SDL_
251 SDL_Surface* conv = SDL_DisplayFormatAlpha(src);
252 //SDL_SetAlpha(conv, 0, 0);
253 //SDL_BlitSurface(src, NULL, conv, NULL);
255 //printf("bpp = %d\n",conv->format->BitsPerPixel);
256 int N = 0;
257 int M = 3;
258 Uint8* conv_bytes = conv->pixels;
259 Uint32 key = SDL_MapRGB(
260 src->format,
261 (COLOR_KEY&0xff0000)>>16,
262 (COLOR_KEY&0x00ff00)>>8,
263 (COLOR_KEY&0x0000ff)>>0
265 for(i=0; i<src->w; i++){
266 for(j=0; j<src->h; j++){
268 //if(1){printf("M==%d totalbytes=%d\n",M,src->w*src->h*4);}
270 Uint32 pixel = *((Uint32*)(src->pixels+N));
271 conv_bytes[M] =
272 pixel==key ?
273 SDL_ALPHA_TRANSPARENT :
274 SDL_ALPHA_OPAQUE;
275 N += src->format->BytesPerPixel;
276 M += 4;
280 glGenTextures( 1, &texture );
281 glBindTexture( GL_TEXTURE_2D, texture );
283 glTexParameteri(
284 GL_TEXTURE_2D,
285 GL_TEXTURE_MIN_FILTER,
286 GL_NEAREST
289 glTexParameteri(
290 GL_TEXTURE_2D,
291 GL_TEXTURE_MAG_FILTER,
292 GL_NEAREST
295 glTexParameteri(
296 GL_TEXTURE_2D,
297 GL_TEXTURE_WRAP_S,
298 GL_REPEAT
301 glTexParameteri(
302 GL_TEXTURE_2D,
303 GL_TEXTURE_WRAP_T,
304 GL_REPEAT
307 glTexImage2D(
308 GL_TEXTURE_2D,
309 0, 4,
310 conv->w, conv->h,
312 GL_BGRA, GL_UNSIGNED_BYTE,
313 conv->pixels
316 gfx[gfx_count].filename = strxcpy(filename);
317 gfx[gfx_count].texture = texture;
318 gfx[gfx_count].w = src->w;
319 gfx[gfx_count].h = src->h;
321 SDL_FreeSurface(conv);
322 SDL_FreeSurface(src);
325 return gfx_count++;
328 int gfx_width(int gfxid){
329 return gfx[gfxid].w;
332 int gfx_height(int gfxid){
333 return gfx[gfxid].h;
341 /******************/
342 /* initialization */
343 /******************/
345 void sdl_init(){
346 if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK)==-1){
347 error_msg("sdl: %s\n",SDL_GetError());
348 exit(-1);
355 void print_version(){
356 char message[] =
357 "This program is distributed under the terms of the GNU General\n"
358 "Public License (v2) and comes with ABSOLUTELY NO WARRANTY.\n\n"
360 "Send questions, comments, and bugs to evanrinehart@gmail.com\n\n"
362 "Send money to:\n"
363 "1850 Claiborne St\n"
364 "Mandeville, LA 70448\n"
365 "United States of America\n\n"
367 "Thanks! :)\n"
370 printf("Cantaveria (v%d.%d)\n", VERSION_MAJOR, VERSION_MINOR);
371 printf("Copyright 2009 Evan Rinehart\n\n");
372 printf(message);
375 void print_help(){
376 printf("options:\n");
377 printf(" -gl use opengl video mode\n");
378 printf(" -f use fullscreen video mode\n");
379 printf(" -h print this help\n");
380 printf(" -v print version info\n");
383 void parse_options(int argc, char* argv[], int* fullscreen, int* gl_flag){
384 int i;
385 for(i=0; i<argc; i++){
386 if(!strcmp(argv[i], "-gl")){
387 *gl_flag = 1;
388 continue;
390 if(!strcmp(argv[i], "-f")){
391 *fullscreen = 1;
393 if(!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")){
394 print_help();
395 exit(0);
397 if(!strcmp(argv[i], "-v")){
398 print_version();
399 exit(0);
405 void setup_joysticks(){
406 int N = SDL_NumJoysticks();
407 int i;
408 boot_msg("sdl: detected %d joysticks\n", N);
409 for(i=0; i<N; i++){
410 if(SDL_JoystickOpen(i)){
411 boot_msg(" joy%d: %s\n", i, SDL_JoystickName(i));
413 else{
414 boot_msg(" joy%d: %s (failed to open)\n", i, SDL_JoystickName(i));
420 void setup_video(){
421 int flags = 0;
422 int i;
424 SDL_WM_SetCaption("cantaveria","cantaveria");
425 SDL_ShowCursor(SDL_DISABLE);
426 const SDL_VideoInfo* vinfo = SDL_GetVideoInfo();
429 if(fullscreen && gl_flag){
430 W = vinfo->current_w;
431 H = vinfo->current_h;
433 else if(gl_flag){
434 //W = 320;
435 //H = 240;
436 W = 640;
437 H = 480;
438 //W = 960;
439 //H = 720;
441 else if(fullscreen){
442 W = 320;
443 H = 240;
445 else{
446 W = 320;
447 H = 240;
450 if(gl_flag){
451 SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
452 //SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1);
453 SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, 1);
454 flags |= SDL_OPENGL;
457 if(fullscreen){
458 flags |= SDL_FULLSCREEN;
463 video = SDL_SetVideoMode(W,H,32,flags);
464 if(video == NULL){
465 fatal_error("sdl: %s\n",SDL_GetError());
468 if(gl_flag){
469 glEnable(GL_BLEND);
470 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
472 glEnable( GL_TEXTURE_2D );
473 glClearColor( 0.0f, 0.0f, 0.0f, 0.0f );
475 glViewport( 0, 0, W, H );
477 glClear( GL_COLOR_BUFFER_BIT );
479 glMatrixMode( GL_PROJECTION );
480 glLoadIdentity();
481 if(fullscreen){
482 //glOrtho(0.0f, 240*aspect, 240, 0.0f, -1.0f, 1.0f);
483 //glOrtho(0.0f, 1280.0/3, 800.0/3, 0.0f, -1.0f, 1.0f);
484 int min = 9999;
485 int n = 0;
486 for(i=1; i<10; i++){
487 if(abs(H/i - 240) < min){ min = H/i - 240; n = i; }
489 double new_w = ((double)W)/n;
490 double new_h = ((double)H)/n;
491 screen_offset_x = (new_w-320)/2;
492 screen_offset_y = (new_h-240)/2;
493 glOrtho(0.0f, new_w, new_h, 0.0f, -1.0f, 1.0f);
494 screen_w = new_w;
495 screen_h = new_h;
497 else{
498 glOrtho(0.0f, 320, 240, 0.0f, -1.0f, 1.0f);
499 screen_w = 320;
500 screen_h = 240;
503 glMatrixMode( GL_MODELVIEW );
504 glLoadIdentity();
506 else{
507 screen_w = 320;
508 screen_h = 240;
511 boot_msg("video:\n");
512 boot_msg(" resolution: %d x %d %s\n",W,H,fullscreen?"fullscreen":"windowed");
513 boot_msg(" pixel dimensions: %d x %d\n",screen_w,screen_h);
514 boot_msg(" aspect ratio: %g\n",((double)W)/H);
515 boot_msg(" opengl: %s\n",gl_flag?"yes":"no");
516 boot_msg(" x-offset: %d\n",screen_offset_x);
517 boot_msg(" y-offset: %d\n",screen_offset_y);
518 boot_msg(" video on\n");
528 void video_init(int argc, char* argv[]){
529 sdl_init();
530 parse_options(argc, argv, &fullscreen, &gl_flag);
531 setup_joysticks();
532 setup_video();
533 time_last = SDL_GetTicks();
537 void video_quit(){
538 boot_msg("sdl: quit\n");
539 SDL_Quit();
543 /* fps */
545 int fps = 0;
546 int update_count = 0;
547 int draw_count = 0;
549 void fps_update(){
550 update_count++;
551 if(update_count == 100){
552 fps = draw_count * 100 / update_count;
553 update_count = 0;
554 draw_count = 0;
558 void fps_draw(){
559 draw_count++;
562 int get_fps(){
563 return fps;