Rewrite of the stage module.
[cantaveria.git] / video.c
blob8034cdef88ce0dc26bcc767bd7c9d7802a81bbee
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
25 video module is the low level interface to video output.
26 it has several low level functions.
27 * initialize the video system for a certain video mode
28 * load graphics data into the abstract graphics pool
29 * draw a portion of some graphics somewhere on screen
30 * millisecond time delta generator
31 * screen clear
32 * screen flip
33 * process suspend
39 #include <math.h>
41 #include <SDL/SDL.h>
42 #include <SDL/SDL_opengl.h>
44 #include <list.h>
45 #include <root.h>
46 #include <util.h>
47 #include <video.h>
48 #include <loader.h>
50 SDL_Surface* video;
51 int gl_flag = 0;
52 int fullscreen = 0;
53 int W, H;
56 static int time_last; /* initialized by backend_init */
57 int since(){
58 int time_now = SDL_GetTicks();
59 int diff = time_now - time_last;
60 time_last = time_now;
61 return diff;
64 void delay(int ms){
65 SDL_Delay(ms);
75 struct {
76 char* filename;
77 SDL_Surface* surf;
78 GLuint texture;
79 int w;
80 int h;
81 } gfx[MAX_GFX];
82 int gfx_count = 0;
84 int screen_w = 320;
85 int screen_h = 240;
86 int screen_offset_x = 0;
87 int screen_offset_y = 0;
92 /********************/
93 /* drawing routines */
94 /********************/
96 void draw_gfx_raw(int gfxid, int x, int y, int X, int Y, int W, int H){
97 if(x > screen_w || y > screen_h || x+W < 0 || y+H < 0) return;
98 if(!gl_flag){
99 SDL_Surface* surf = gfx[gfxid].surf;
100 SDL_Rect r1 = {X,Y,W,H};
101 SDL_Rect r2 = {x,y,W,H};
102 SDL_BlitSurface(surf,&r1,video,&r2);
104 else{
105 double w = gfx[gfxid].w;
106 double h = gfx[gfxid].h;
107 double X0 = ((double)X)/w;
108 double X1 = X0 + ((double)W)/w;
109 double Y0 = ((double)Y)/h;
110 double Y1 = Y0 + ((double)H)/h;
112 glBindTexture( GL_TEXTURE_2D, gfx[gfxid].texture );
113 glBegin( GL_QUADS );
114 glTexCoord2d(X0,Y0);
115 glVertex3f(x,y,0);
117 glTexCoord2d(X1,Y0);
118 glVertex3f(x+W,y,0);
120 glTexCoord2d(X1,Y1);
121 glVertex3f(x+W,y+H,0);
123 glTexCoord2d(X0,Y1);
124 glVertex3f(x,y+H,0);
125 glEnd();
129 void draw_gfx(int gfxid, int x, int y, int X, int Y, int W, int H){
130 draw_gfx_raw(gfxid, x+screen_offset_x, y+screen_offset_y, X, Y, W, H);
133 void clear_video(){
134 if(!gl_flag){
135 SDL_FillRect(video, 0, 0);
137 else{
138 glClearColor(0.0,0.0,0.0,0.0);
139 glClear( GL_COLOR_BUFFER_BIT );
143 void update_video(){
144 if(!gl_flag){
145 SDL_UpdateRect(video,0,0,0,0);
147 else{
148 SDL_GL_SwapBuffers();
155 /********************/
156 /* graphics loading */
157 /********************/
159 SDL_Surface* SDL_NewSurface(int w, int h){
160 char prefix[32] = "SDL_NewSurface";
161 SDL_Surface* tmp = SDL_CreateRGBSurface(SDL_SRCCOLORKEY,w,h,32,0,0,0,0);
162 if(!tmp){
163 out_of_memory(prefix);
166 SDL_Surface* surf = SDL_DisplayFormat(tmp);
167 if(!surf){
168 out_of_memory(prefix);
171 SDL_FreeSurface(tmp);
173 SDL_FillRect(surf,0,0x00ffffff);
175 return surf;
178 SDL_Surface* load_pixmap(char* filename){
179 char path[256] = "gfx/";
180 strmcat(path, filename, 256);
182 reader* rd = loader_open(path);
183 if(!rd){
184 error_msg("load_pixmap: error opening file\n");
185 return NULL;
188 unsigned char header[18];
189 if(loader_read(rd, header, 18) < 0){
190 error_msg("load_pixmap: error reading pixmap header\n");
191 loader_close(rd);
192 return NULL;
195 int w = header[12] + (header[13]<<8);
196 int h = header[14] + (header[15]<<8);
197 int bpp = header[16];
198 //printf("load_pixmap: %s has bpp=%d\n",filename, bpp);
199 SDL_Surface* surf = SDL_CreateRGBSurface(0,w,h,bpp,
200 0x00ff0000,0x0000ff00,0x000000ff,0xff000000);
201 if(!surf){
202 out_of_memory("load_pixmap");
204 if(loader_read(rd, surf->pixels, w*(bpp/8)*h) < 0){
205 error_msg("load_pixmap: error reading pixmap data\n");
206 loader_close(rd);
207 SDL_FreeSurface(surf);
208 return NULL;
210 loader_close(rd);
212 return surf;
215 int load_gfx(char* filename){
216 int i, j;
218 if(gfx_count == MAX_GFX){
219 fatal_error(
220 "load_gfx: cannot load any more than %d graphics\n",
221 MAX_GFX
226 //printf("loading %s\n",filename);
229 for(i=0; i<gfx_count; i++){/*check for already loaded gfx*/
230 if(strcmp(gfx[i].filename, filename)==0){
231 return i;
235 SDL_Surface* src = load_pixmap(filename);
236 if(!src){
237 fatal_error("load_gfx: failed to load %s\n",filename);
240 if(!gl_flag){
241 SDL_Surface* surf = SDL_DisplayFormatAlpha(src);
242 SDL_SetAlpha(surf, 0, 0);
244 Uint32 key = SDL_MapRGB(
245 surf->format,
246 (COLOR_KEY&0xff0000)>>16,
247 (COLOR_KEY&0x00ff00)>>8,
248 (COLOR_KEY&0x0000ff)>>0
250 SDL_SetColorKey(surf, SDL_SRCCOLORKEY, key);
252 SDL_FreeSurface(src);
255 gfx[gfx_count].filename = strxcpy(filename);
256 gfx[gfx_count].surf = surf;
257 gfx[gfx_count].w = surf->w;
258 gfx[gfx_count].h = surf->h;
260 else {
261 GLuint texture;
263 //SDL_Surface* conv = SDL_CreateRGBSurface(0, pot(src->w), pot(src->h), 32,
264 //0xff<<16,0xff<<8,0xff<<0,0);
266 //SDL_Surface* tmp = SDL_
267 SDL_Surface* conv = SDL_DisplayFormatAlpha(src);
268 //SDL_SetAlpha(conv, 0, 0);
269 //SDL_BlitSurface(src, NULL, conv, NULL);
271 //printf("bpp = %d\n",conv->format->BitsPerPixel);
272 int N = 0;
273 int M = 3;
274 Uint8* conv_bytes = conv->pixels;
275 Uint32 key = SDL_MapRGB(
276 src->format,
277 (COLOR_KEY&0xff0000)>>16,
278 (COLOR_KEY&0x00ff00)>>8,
279 (COLOR_KEY&0x0000ff)>>0
281 for(i=0; i<src->w; i++){
282 for(j=0; j<src->h; j++){
284 //if(1){printf("M==%d totalbytes=%d\n",M,src->w*src->h*4);}
286 Uint32 pixel = *((Uint32*)(src->pixels+N));
287 conv_bytes[M] =
288 pixel==key ?
289 SDL_ALPHA_TRANSPARENT :
290 SDL_ALPHA_OPAQUE;
291 N += src->format->BytesPerPixel;
292 M += 4;
296 glGenTextures( 1, &texture );
297 glBindTexture( GL_TEXTURE_2D, texture );
299 glTexParameteri(
300 GL_TEXTURE_2D,
301 GL_TEXTURE_MIN_FILTER,
302 GL_NEAREST
305 glTexParameteri(
306 GL_TEXTURE_2D,
307 GL_TEXTURE_MAG_FILTER,
308 GL_NEAREST
311 glTexParameteri(
312 GL_TEXTURE_2D,
313 GL_TEXTURE_WRAP_S,
314 GL_REPEAT
317 glTexParameteri(
318 GL_TEXTURE_2D,
319 GL_TEXTURE_WRAP_T,
320 GL_REPEAT
323 glTexImage2D(
324 GL_TEXTURE_2D,
325 0, 4,
326 conv->w, conv->h,
328 GL_BGRA, GL_UNSIGNED_BYTE,
329 conv->pixels
332 gfx[gfx_count].filename = strxcpy(filename);
333 gfx[gfx_count].texture = texture;
334 gfx[gfx_count].w = src->w;
335 gfx[gfx_count].h = src->h;
337 SDL_FreeSurface(conv);
338 SDL_FreeSurface(src);
341 return gfx_count++;
344 int gfx_width(int gfxid){
345 return gfx[gfxid].w;
348 int gfx_height(int gfxid){
349 return gfx[gfxid].h;
357 /******************/
358 /* initialization */
359 /******************/
361 void sdl_init(){
362 if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK)==-1){
363 error_msg("sdl: %s\n",SDL_GetError());
364 exit(-1);
371 void print_version(){
372 char message[] =
373 "This program is distributed under the terms of the GNU General\n"
374 "Public License (v2) and comes with ABSOLUTELY NO WARRANTY.\n\n"
376 "Send questions, comments, and bugs to evanrinehart@gmail.com\n\n"
378 "Send money to:\n"
379 "1850 Claiborne St\n"
380 "Mandeville, LA 70448\n"
381 "United States of America\n\n"
383 "Thanks! :)\n"
386 printf("Cantaveria (v%d.%d)\n", VERSION_MAJOR, VERSION_MINOR);
387 printf("Copyright 2009 Evan Rinehart\n\n");
388 printf(message);
391 void print_help(){
392 printf("options:\n");
393 printf(" -gl use opengl video mode\n");
394 printf(" -f use fullscreen video mode\n");
395 printf(" -h print this help\n");
396 printf(" -v print version info\n");
399 void parse_options(int argc, char* argv[], int* fullscreen, int* gl_flag){
400 int i;
401 for(i=0; i<argc; i++){
402 if(!strcmp(argv[i], "-gl")){
403 *gl_flag = 1;
404 continue;
406 if(!strcmp(argv[i], "-f")){
407 *fullscreen = 1;
409 if(!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")){
410 print_help();
411 exit(0);
413 if(!strcmp(argv[i], "-v")){
414 print_version();
415 exit(0);
421 void setup_joysticks(){
422 int N = SDL_NumJoysticks();
423 int i;
424 boot_msg("sdl: detected %d joysticks\n", N);
425 for(i=0; i<N; i++){
426 if(SDL_JoystickOpen(i)){
427 boot_msg(" joy%d: %s\n", i, SDL_JoystickName(i));
429 else{
430 boot_msg(" joy%d: %s (failed to open)\n", i, SDL_JoystickName(i));
436 void setup_video(){
437 int flags = 0;
438 int i;
440 SDL_WM_SetCaption("cantaveria","cantaveria");
441 SDL_ShowCursor(SDL_DISABLE);
442 const SDL_VideoInfo* vinfo = SDL_GetVideoInfo();
445 if(fullscreen && gl_flag){
446 W = vinfo->current_w;
447 H = vinfo->current_h;
449 else if(gl_flag){
450 //W = 320;
451 //H = 240;
452 W = 640;
453 H = 480;
454 //W = 960;
455 //H = 720;
457 else if(fullscreen){
458 W = 320;
459 H = 240;
461 else{
462 W = 320;
463 H = 240;
466 if(gl_flag){
467 SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
468 //SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1);
469 SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, 1);
470 flags |= SDL_OPENGL;
473 if(fullscreen){
474 flags |= SDL_FULLSCREEN;
479 video = SDL_SetVideoMode(W,H,32,flags);
480 if(video == NULL){
481 fatal_error("sdl: %s\n",SDL_GetError());
484 if(gl_flag){
485 glEnable(GL_BLEND);
486 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
488 glEnable( GL_TEXTURE_2D );
489 glClearColor( 0.0f, 0.0f, 0.0f, 0.0f );
491 glViewport( 0, 0, W, H );
493 glClear( GL_COLOR_BUFFER_BIT );
495 glMatrixMode( GL_PROJECTION );
496 glLoadIdentity();
497 if(fullscreen){
498 //glOrtho(0.0f, 240*aspect, 240, 0.0f, -1.0f, 1.0f);
499 //glOrtho(0.0f, 1280.0/3, 800.0/3, 0.0f, -1.0f, 1.0f);
500 int min = 9999;
501 int n = 0;
502 for(i=1; i<10; i++){
503 if(abs(H/i - 240) < min){ min = H/i - 240; n = i; }
505 double new_w = ((double)W)/n;
506 double new_h = ((double)H)/n;
507 screen_offset_x = (new_w-320)/2;
508 screen_offset_y = (new_h-240)/2;
509 glOrtho(0.0f, new_w, new_h, 0.0f, -1.0f, 1.0f);
510 screen_w = new_w;
511 screen_h = new_h;
513 else{
514 glOrtho(0.0f, 320, 240, 0.0f, -1.0f, 1.0f);
515 screen_w = 320;
516 screen_h = 240;
519 glMatrixMode( GL_MODELVIEW );
520 glLoadIdentity();
522 else{
523 screen_w = 320;
524 screen_h = 240;
527 boot_msg("video:\n");
528 boot_msg(" resolution: %d x %d %s\n",W,H,fullscreen?"fullscreen":"windowed");
529 boot_msg(" pixel dimensions: %d x %d\n",screen_w,screen_h);
530 boot_msg(" aspect ratio: %g\n",((double)W)/H);
531 boot_msg(" opengl: %s\n",gl_flag?"yes":"no");
532 boot_msg(" x-offset: %d\n",screen_offset_x);
533 boot_msg(" y-offset: %d\n",screen_offset_y);
534 boot_msg(" video on\n");
544 void video_init(int argc, char* argv[]){
545 sdl_init();
546 parse_options(argc, argv, &fullscreen, &gl_flag);
547 setup_joysticks();
548 setup_video();
549 time_last = SDL_GetTicks();
553 void video_quit(){
554 boot_msg("sdl: quit\n");
555 SDL_Quit();
559 /* fps */
561 int fps = 0;
562 int update_count = 0;
563 int draw_count = 0;
565 void fps_update(){
566 update_count++;
567 if(update_count == 100){
568 fps = draw_count * 100 / update_count;
569 update_count = 0;
570 draw_count = 0;
574 void fps_draw(){
575 draw_count++;
578 int get_fps(){
579 return fps;