Merge branch 'list' into io
[cantaveria.git] / video.c
blob1b7d58b7acc45e78f35bc412adf0c36353069263
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 return NULL;
172 unsigned char header[18];
173 loader_read(rd, header, 18);
175 int w = header[12] + (header[13]<<8);
176 int h = header[14] + (header[15]<<8);
177 int bpp = header[16];
178 //printf("load_pixmap: %s has bpp=%d\n",filename, bpp);
179 SDL_Surface* surf = SDL_CreateRGBSurface(0,w,h,bpp,
180 0x00ff0000,0x0000ff00,0x000000ff,0xff000000);
181 if(!surf){
182 out_of_memory("load_pixmap");
184 loader_read(rd, surf->pixels, w*(bpp/8)*h);
185 loader_close(rd);
187 return surf;
190 int load_gfx(char* filename){
191 int i, j;
193 if(gfx_count == MAX_GFX){
194 fatal_error(
195 "load_gfx: cannot load any more than %d graphics\n",
196 MAX_GFX
201 //printf("loading %s\n",filename);
204 for(i=0; i<gfx_count; i++){/*check for already loaded gfx*/
205 if(strcmp(gfx[i].filename, filename)==0){
206 return i;
210 SDL_Surface* src = load_pixmap(filename);
211 if(!src){
212 fatal_error("load_gfx: failed to load %s\n",filename);
215 if(!gl_flag){
216 SDL_Surface* surf = SDL_DisplayFormatAlpha(src);
217 SDL_SetAlpha(surf, 0, 0);
219 Uint32 key = SDL_MapRGB(
220 surf->format,
221 (COLOR_KEY&0xff0000)>>16,
222 (COLOR_KEY&0x00ff00)>>8,
223 (COLOR_KEY&0x0000ff)>>0
225 SDL_SetColorKey(surf, SDL_SRCCOLORKEY, key);
227 SDL_FreeSurface(src);
230 gfx[gfx_count].filename = strxcpy(filename);
231 gfx[gfx_count].surf = surf;
232 gfx[gfx_count].w = surf->w;
233 gfx[gfx_count].h = surf->h;
235 else {
236 GLuint texture;
238 //SDL_Surface* conv = SDL_CreateRGBSurface(0, pot(src->w), pot(src->h), 32,
239 //0xff<<16,0xff<<8,0xff<<0,0);
241 //SDL_Surface* tmp = SDL_
242 SDL_Surface* conv = SDL_DisplayFormatAlpha(src);
243 //SDL_SetAlpha(conv, 0, 0);
244 //SDL_BlitSurface(src, NULL, conv, NULL);
246 //printf("bpp = %d\n",conv->format->BitsPerPixel);
247 int N = 0;
248 int M = 3;
249 Uint8* conv_bytes = conv->pixels;
250 Uint32 key = SDL_MapRGB(
251 src->format,
252 (COLOR_KEY&0xff0000)>>16,
253 (COLOR_KEY&0x00ff00)>>8,
254 (COLOR_KEY&0x0000ff)>>0
256 for(i=0; i<src->w; i++){
257 for(j=0; j<src->h; j++){
259 //if(1){printf("M==%d totalbytes=%d\n",M,src->w*src->h*4);}
261 Uint32 pixel = *((Uint32*)(src->pixels+N));
262 conv_bytes[M] =
263 pixel==key ?
264 SDL_ALPHA_TRANSPARENT :
265 SDL_ALPHA_OPAQUE;
266 N += src->format->BytesPerPixel;
267 M += 4;
271 glGenTextures( 1, &texture );
272 glBindTexture( GL_TEXTURE_2D, texture );
274 glTexParameteri(
275 GL_TEXTURE_2D,
276 GL_TEXTURE_MIN_FILTER,
277 GL_NEAREST
280 glTexParameteri(
281 GL_TEXTURE_2D,
282 GL_TEXTURE_MAG_FILTER,
283 GL_NEAREST
286 glTexParameteri(
287 GL_TEXTURE_2D,
288 GL_TEXTURE_WRAP_S,
289 GL_REPEAT
292 glTexParameteri(
293 GL_TEXTURE_2D,
294 GL_TEXTURE_WRAP_T,
295 GL_REPEAT
298 glTexImage2D(
299 GL_TEXTURE_2D,
300 0, 4,
301 conv->w, conv->h,
303 GL_BGRA, GL_UNSIGNED_BYTE,
304 conv->pixels
307 gfx[gfx_count].filename = strxcpy(filename);
308 gfx[gfx_count].texture = texture;
309 gfx[gfx_count].w = src->w;
310 gfx[gfx_count].h = src->h;
312 SDL_FreeSurface(conv);
313 SDL_FreeSurface(src);
316 return gfx_count++;
319 int gfx_width(int gfxid){
320 return gfx[gfxid].w;
323 int gfx_height(int gfxid){
324 return gfx[gfxid].h;
332 /******************/
333 /* initialization */
334 /******************/
336 void sdl_init(){
337 if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK)==-1){
338 error_msg("sdl: %s\n",SDL_GetError());
339 exit(-1);
346 void print_version(){
347 char message[] =
348 "This program is distributed under the terms of the GNU General\n"
349 "Public License (v2) and comes with ABSOLUTELY NO WARRANTY.\n\n"
351 "Send questions, comments, and bugs to evanrinehart@gmail.com\n\n"
353 "Send money to:\n"
354 "1850 Claiborne St\n"
355 "Mandeville, LA 70448\n"
356 "United States of America\n\n"
358 "Thanks! :)\n"
361 printf("Cantaveria (v%d.%d)\n", VERSION_MAJOR, VERSION_MINOR);
362 printf("Copyright 2009 Evan Rinehart\n\n");
363 printf(message);
366 void print_help(){
367 printf("options:\n");
368 printf(" -gl use opengl video mode\n");
369 printf(" -f use fullscreen video mode\n");
370 printf(" -h print this help\n");
371 printf(" -v print version info\n");
374 void parse_options(int argc, char* argv[], int* fullscreen, int* gl_flag){
375 int i;
376 for(i=0; i<argc; i++){
377 if(!strcmp(argv[i], "-gl")){
378 *gl_flag = 1;
379 continue;
381 if(!strcmp(argv[i], "-f")){
382 *fullscreen = 1;
384 if(!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")){
385 print_help();
386 exit(0);
388 if(!strcmp(argv[i], "-v")){
389 print_version();
390 exit(0);
396 void setup_joysticks(){
397 int N = SDL_NumJoysticks();
398 int i;
399 boot_msg("sdl: detected %d joysticks\n", N);
400 for(i=0; i<N; i++){
401 if(SDL_JoystickOpen(i)){
402 boot_msg(" joy%d: %s\n", i, SDL_JoystickName(i));
404 else{
405 boot_msg(" joy%d: %s (failed to open)\n", i, SDL_JoystickName(i));
411 void setup_video(){
412 int flags = 0;
413 int i;
415 SDL_WM_SetCaption("cantaveria","cantaveria");
416 SDL_ShowCursor(SDL_DISABLE);
417 const SDL_VideoInfo* vinfo = SDL_GetVideoInfo();
420 if(fullscreen && gl_flag){
421 W = vinfo->current_w;
422 H = vinfo->current_h;
424 else if(gl_flag){
425 //W = 320;
426 //H = 240;
427 W = 640;
428 H = 480;
429 //W = 960;
430 //H = 720;
432 else if(fullscreen){
433 W = 320;
434 H = 240;
436 else{
437 W = 320;
438 H = 240;
441 if(gl_flag){
442 SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
443 //SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1);
444 SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, 1);
445 flags |= SDL_OPENGL;
448 if(fullscreen){
449 flags |= SDL_FULLSCREEN;
454 video = SDL_SetVideoMode(W,H,32,flags);
455 if(video == NULL){
456 fatal_error("sdl: %s\n",SDL_GetError());
459 if(gl_flag){
460 glEnable(GL_BLEND);
461 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
463 glEnable( GL_TEXTURE_2D );
464 glClearColor( 0.0f, 0.0f, 0.0f, 0.0f );
466 glViewport( 0, 0, W, H );
468 glClear( GL_COLOR_BUFFER_BIT );
470 glMatrixMode( GL_PROJECTION );
471 glLoadIdentity();
472 if(fullscreen){
473 //glOrtho(0.0f, 240*aspect, 240, 0.0f, -1.0f, 1.0f);
474 //glOrtho(0.0f, 1280.0/3, 800.0/3, 0.0f, -1.0f, 1.0f);
475 int min = 9999;
476 int n = 0;
477 for(i=1; i<10; i++){
478 if(abs(H/i - 240) < min){ min = H/i - 240; n = i; }
480 double new_w = ((double)W)/n;
481 double new_h = ((double)H)/n;
482 screen_offset_x = (new_w-320)/2;
483 screen_offset_y = (new_h-240)/2;
484 glOrtho(0.0f, new_w, new_h, 0.0f, -1.0f, 1.0f);
485 screen_w = new_w;
486 screen_h = new_h;
488 else{
489 glOrtho(0.0f, 320, 240, 0.0f, -1.0f, 1.0f);
490 screen_w = 320;
491 screen_h = 240;
494 glMatrixMode( GL_MODELVIEW );
495 glLoadIdentity();
497 else{
498 screen_w = 320;
499 screen_h = 240;
502 boot_msg("video:\n");
503 boot_msg(" resolution: %d x %d %s\n",W,H,fullscreen?"fullscreen":"windowed");
504 boot_msg(" pixel dimensions: %d x %d\n",screen_w,screen_h);
505 boot_msg(" aspect ratio: %g\n",((double)W)/H);
506 boot_msg(" opengl: %s\n",gl_flag?"yes":"no");
507 boot_msg(" x-offset: %d\n",screen_offset_x);
508 boot_msg(" y-offset: %d\n",screen_offset_y);
509 boot_msg(" video on\n");
519 void video_init(int argc, char* argv[]){
520 sdl_init();
521 parse_options(argc, argv, &fullscreen, &gl_flag);
522 setup_joysticks();
523 setup_video();
524 time_last = SDL_GetTicks();
528 void video_quit(){
529 boot_msg("sdl: quit\n");
530 SDL_Quit();
534 /* fps */
536 int fps = 0;
537 int update_count = 0;
538 int draw_count = 0;
540 void fps_update(){
541 update_count++;
542 if(update_count == 100){
543 fps = draw_count * 100 / update_count;
544 update_count = 0;
545 draw_count = 0;
549 void fps_draw(){
550 draw_count++;
553 int get_fps(){
554 return fps;