Merge branch 'io'
[cantaveria.git] / video.c
bloba55ef2174c535b010f0683a33cd947db73350591
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 <input.h>
32 #include <video.h>
33 #include <loader.h>
35 SDL_Surface* video;
36 int gl_flag = 0;
37 int fullscreen = 0;
38 int W, H;
41 static int time_last; /* initialized by backend_init */
42 int since(){
43 int time_now = SDL_GetTicks();
44 int diff = time_now - time_last;
45 time_last = time_now;
46 return diff;
49 void delay(int ms){
50 SDL_Delay(ms);
60 struct {
61 char* filename;
62 SDL_Surface* surf;
63 GLuint texture;
64 int w;
65 int h;
66 } gfx[MAX_GFX];
67 int gfx_count = 0;
69 int screen_w = 320;
70 int screen_h = 240;
71 int screen_offset_x = 0;
72 int screen_offset_y = 0;
77 /********************/
78 /* drawing routines */
79 /********************/
81 void draw_gfx_raw(int gfxid, int x, int y, int X, int Y, int W, int H){
82 if(x > screen_w || y > screen_h || x+W < 0 || y+H < 0) return;
83 if(!gl_flag){
84 SDL_Surface* surf = gfx[gfxid].surf;
85 SDL_Rect r1 = {X,Y,W,H};
86 SDL_Rect r2 = {x,y,W,H};
87 SDL_BlitSurface(surf,&r1,video,&r2);
89 else{
90 double w = gfx[gfxid].w;
91 double h = gfx[gfxid].h;
92 double X0 = ((double)X)/w;
93 double X1 = X0 + ((double)W)/w;
94 double Y0 = ((double)Y)/h;
95 double Y1 = Y0 + ((double)H)/h;
97 glBindTexture( GL_TEXTURE_2D, gfx[gfxid].texture );
98 glBegin( GL_QUADS );
99 glTexCoord2d(X0,Y0);
100 glVertex3f(x,y,0);
102 glTexCoord2d(X1,Y0);
103 glVertex3f(x+W,y,0);
105 glTexCoord2d(X1,Y1);
106 glVertex3f(x+W,y+H,0);
108 glTexCoord2d(X0,Y1);
109 glVertex3f(x,y+H,0);
110 glEnd();
114 void draw_gfx(int gfxid, int x, int y, int X, int Y, int W, int H){
115 draw_gfx_raw(gfxid, x+screen_offset_x, y+screen_offset_y, X, Y, W, H);
118 void clear_video(){
119 if(!gl_flag){
120 SDL_FillRect(video, 0, 0);
122 else{
123 glClearColor(0.0,0.0,0.0,0.0);
124 glClear( GL_COLOR_BUFFER_BIT );
128 void update_video(){
129 if(!gl_flag){
130 SDL_UpdateRect(video,0,0,0,0);
132 else{
133 SDL_GL_SwapBuffers();
140 /********************/
141 /* graphics loading */
142 /********************/
144 SDL_Surface* SDL_NewSurface(int w, int h){
145 char prefix[32] = "SDL_NewSurface";
146 SDL_Surface* tmp = SDL_CreateRGBSurface(SDL_SRCCOLORKEY,w,h,32,0,0,0,0);
147 if(!tmp){
148 out_of_memory(prefix);
151 SDL_Surface* surf = SDL_DisplayFormat(tmp);
152 if(!surf){
153 out_of_memory(prefix);
156 SDL_FreeSurface(tmp);
158 SDL_FillRect(surf,0,0x00ffffff);
160 return surf;
163 SDL_Surface* load_pixmap(char* filename){
164 char path[256] = "gfx/";
165 strmcat(path, filename, 256);
167 reader* rd = loader_open(path);
168 if(!rd){
169 error_msg("load_pixmap: error opening file\n");
170 return NULL;
173 unsigned char header[18];
174 if(loader_read(rd, header, 18) < 0){
175 error_msg("load_pixmap: error reading pixmap header\n");
176 loader_close(rd);
177 return NULL;
180 int w = header[12] + (header[13]<<8);
181 int h = header[14] + (header[15]<<8);
182 int bpp = header[16];
183 //printf("load_pixmap: %s has bpp=%d\n",filename, bpp);
184 SDL_Surface* surf = SDL_CreateRGBSurface(0,w,h,bpp,
185 0x00ff0000,0x0000ff00,0x000000ff,0xff000000);
186 if(!surf){
187 out_of_memory("load_pixmap");
189 if(loader_read(rd, surf->pixels, w*(bpp/8)*h) < 0){
190 error_msg("load_pixmap: error reading pixmap data\n");
191 loader_close(rd);
192 SDL_FreeSurface(surf);
193 return NULL;
195 loader_close(rd);
197 return surf;
200 int load_gfx(char* filename){
201 int i, j;
203 if(gfx_count == MAX_GFX){
204 fatal_error(
205 "load_gfx: cannot load any more than %d graphics\n",
206 MAX_GFX
211 //printf("loading %s\n",filename);
214 for(i=0; i<gfx_count; i++){/*check for already loaded gfx*/
215 if(strcmp(gfx[i].filename, filename)==0){
216 return i;
220 SDL_Surface* src = load_pixmap(filename);
221 if(!src){
222 fatal_error("load_gfx: failed to load %s\n",filename);
225 if(!gl_flag){
226 SDL_Surface* surf = SDL_DisplayFormatAlpha(src);
227 SDL_SetAlpha(surf, 0, 0);
229 Uint32 key = SDL_MapRGB(
230 surf->format,
231 (COLOR_KEY&0xff0000)>>16,
232 (COLOR_KEY&0x00ff00)>>8,
233 (COLOR_KEY&0x0000ff)>>0
235 SDL_SetColorKey(surf, SDL_SRCCOLORKEY, key);
237 SDL_FreeSurface(src);
240 gfx[gfx_count].filename = strxcpy(filename);
241 gfx[gfx_count].surf = surf;
242 gfx[gfx_count].w = surf->w;
243 gfx[gfx_count].h = surf->h;
245 else {
246 GLuint texture;
248 //SDL_Surface* conv = SDL_CreateRGBSurface(0, pot(src->w), pot(src->h), 32,
249 //0xff<<16,0xff<<8,0xff<<0,0);
251 //SDL_Surface* tmp = SDL_
252 SDL_Surface* conv = SDL_DisplayFormatAlpha(src);
253 //SDL_SetAlpha(conv, 0, 0);
254 //SDL_BlitSurface(src, NULL, conv, NULL);
256 //printf("bpp = %d\n",conv->format->BitsPerPixel);
257 int N = 0;
258 int M = 3;
259 Uint8* conv_bytes = conv->pixels;
260 Uint32 key = SDL_MapRGB(
261 src->format,
262 (COLOR_KEY&0xff0000)>>16,
263 (COLOR_KEY&0x00ff00)>>8,
264 (COLOR_KEY&0x0000ff)>>0
266 for(i=0; i<src->w; i++){
267 for(j=0; j<src->h; j++){
269 //if(1){printf("M==%d totalbytes=%d\n",M,src->w*src->h*4);}
271 Uint32 pixel = *((Uint32*)(src->pixels+N));
272 conv_bytes[M] =
273 pixel==key ?
274 SDL_ALPHA_TRANSPARENT :
275 SDL_ALPHA_OPAQUE;
276 N += src->format->BytesPerPixel;
277 M += 4;
281 glGenTextures( 1, &texture );
282 glBindTexture( GL_TEXTURE_2D, texture );
284 glTexParameteri(
285 GL_TEXTURE_2D,
286 GL_TEXTURE_MIN_FILTER,
287 GL_NEAREST
290 glTexParameteri(
291 GL_TEXTURE_2D,
292 GL_TEXTURE_MAG_FILTER,
293 GL_NEAREST
296 glTexParameteri(
297 GL_TEXTURE_2D,
298 GL_TEXTURE_WRAP_S,
299 GL_REPEAT
302 glTexParameteri(
303 GL_TEXTURE_2D,
304 GL_TEXTURE_WRAP_T,
305 GL_REPEAT
308 glTexImage2D(
309 GL_TEXTURE_2D,
310 0, 4,
311 conv->w, conv->h,
313 GL_BGRA, GL_UNSIGNED_BYTE,
314 conv->pixels
317 gfx[gfx_count].filename = strxcpy(filename);
318 gfx[gfx_count].texture = texture;
319 gfx[gfx_count].w = src->w;
320 gfx[gfx_count].h = src->h;
322 SDL_FreeSurface(conv);
323 SDL_FreeSurface(src);
326 return gfx_count++;
329 int gfx_width(int gfxid){
330 return gfx[gfxid].w;
333 int gfx_height(int gfxid){
334 return gfx[gfxid].h;
342 /******************/
343 /* initialization */
344 /******************/
346 void sdl_init(){
347 if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK)==-1){
348 error_msg("sdl: %s\n",SDL_GetError());
349 exit(-1);
356 void print_version(){
357 char message[] =
358 "This program is distributed under the terms of the GNU General\n"
359 "Public License (v2) and comes with ABSOLUTELY NO WARRANTY.\n\n"
361 "Send questions, comments, and bugs to evanrinehart@gmail.com\n\n"
363 "Send money to:\n"
364 "1850 Claiborne St\n"
365 "Mandeville, LA 70448\n"
366 "United States of America\n\n"
368 "Thanks! :)\n"
371 printf("Cantaveria (v%d.%d)\n", VERSION_MAJOR, VERSION_MINOR);
372 printf("Copyright 2009 Evan Rinehart\n\n");
373 printf(message);
376 void print_help(){
377 printf("options:\n");
378 printf(" -gl use opengl video mode\n");
379 printf(" -f use fullscreen video mode\n");
380 printf(" -h print this help\n");
381 printf(" -v print version info\n");
384 void parse_options(int argc, char* argv[], int* fullscreen, int* gl_flag){
385 int i;
386 for(i=0; i<argc; i++){
387 if(!strcmp(argv[i], "-gl")){
388 *gl_flag = 1;
389 continue;
391 if(!strcmp(argv[i], "-f")){
392 *fullscreen = 1;
394 if(!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")){
395 print_help();
396 exit(0);
398 if(!strcmp(argv[i], "-v")){
399 print_version();
400 exit(0);
406 void setup_joysticks(){
407 int N = SDL_NumJoysticks();
408 int i;
409 boot_msg("sdl: detected %d joysticks\n", N);
410 for(i=0; i<N; i++){
411 if(SDL_JoystickOpen(i)){
412 boot_msg(" joy%d: %s\n", i, SDL_JoystickName(i));
414 else{
415 boot_msg(" joy%d: %s (failed to open)\n", i, SDL_JoystickName(i));
421 void setup_video(){
422 int flags = 0;
423 int i;
425 SDL_WM_SetCaption("cantaveria","cantaveria");
426 SDL_ShowCursor(SDL_DISABLE);
427 const SDL_VideoInfo* vinfo = SDL_GetVideoInfo();
430 if(fullscreen && gl_flag){
431 W = vinfo->current_w;
432 H = vinfo->current_h;
434 else if(gl_flag){
435 //W = 320;
436 //H = 240;
437 W = 640;
438 H = 480;
439 //W = 960;
440 //H = 720;
442 else if(fullscreen){
443 W = 320;
444 H = 240;
446 else{
447 W = 320;
448 H = 240;
451 if(gl_flag){
452 SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
453 //SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1);
454 SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, 1);
455 flags |= SDL_OPENGL;
458 if(fullscreen){
459 flags |= SDL_FULLSCREEN;
464 video = SDL_SetVideoMode(W,H,32,flags);
465 if(video == NULL){
466 fatal_error("sdl: %s\n",SDL_GetError());
469 if(gl_flag){
470 glEnable(GL_BLEND);
471 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
473 glEnable( GL_TEXTURE_2D );
474 glClearColor( 0.0f, 0.0f, 0.0f, 0.0f );
476 glViewport( 0, 0, W, H );
478 glClear( GL_COLOR_BUFFER_BIT );
480 glMatrixMode( GL_PROJECTION );
481 glLoadIdentity();
482 if(fullscreen){
483 //glOrtho(0.0f, 240*aspect, 240, 0.0f, -1.0f, 1.0f);
484 //glOrtho(0.0f, 1280.0/3, 800.0/3, 0.0f, -1.0f, 1.0f);
485 int min = 9999;
486 int n = 0;
487 for(i=1; i<10; i++){
488 if(abs(H/i - 240) < min){ min = H/i - 240; n = i; }
490 double new_w = ((double)W)/n;
491 double new_h = ((double)H)/n;
492 screen_offset_x = (new_w-320)/2;
493 screen_offset_y = (new_h-240)/2;
494 glOrtho(0.0f, new_w, new_h, 0.0f, -1.0f, 1.0f);
495 screen_w = new_w;
496 screen_h = new_h;
498 else{
499 glOrtho(0.0f, 320, 240, 0.0f, -1.0f, 1.0f);
500 screen_w = 320;
501 screen_h = 240;
504 glMatrixMode( GL_MODELVIEW );
505 glLoadIdentity();
507 else{
508 screen_w = 320;
509 screen_h = 240;
512 boot_msg("video:\n");
513 boot_msg(" resolution: %d x %d %s\n",W,H,fullscreen?"fullscreen":"windowed");
514 boot_msg(" pixel dimensions: %d x %d\n",screen_w,screen_h);
515 boot_msg(" aspect ratio: %g\n",((double)W)/H);
516 boot_msg(" opengl: %s\n",gl_flag?"yes":"no");
517 boot_msg(" x-offset: %d\n",screen_offset_x);
518 boot_msg(" y-offset: %d\n",screen_offset_y);
519 boot_msg(" video on\n");
529 void video_init(int argc, char* argv[]){
530 sdl_init();
531 parse_options(argc, argv, &fullscreen, &gl_flag);
532 setup_joysticks();
533 setup_video();
534 time_last = SDL_GetTicks();
538 void video_quit(){
539 boot_msg("sdl: quit\n");
540 SDL_Quit();
544 /* fps */
546 int fps = 0;
547 int update_count = 0;
548 int draw_count = 0;
550 void fps_update(){
551 update_count++;
552 if(update_count == 100){
553 fps = draw_count * 100 / update_count;
554 update_count = 0;
555 draw_count = 0;
559 void fps_draw(){
560 draw_count++;
563 int get_fps(){
564 return fps;