Fixed a unused result warning.
[cantaveria.git] / video.c
blob4cd651fab30c79e2029df0df36c7086a5d7155b2
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;
55 static int time_last; /* initialized by backend_init */
56 int since(){
57 int time_now = SDL_GetTicks();
58 int diff = time_now - time_last;
59 time_last = time_now;
60 return diff;
63 void delay(int ms){
64 SDL_Delay(ms);
74 struct {
75 char* filename;
76 SDL_Surface* surf;
77 GLuint texture;
78 int w;
79 int h;
80 } gfx[MAX_GFX];
81 int gfx_count = 0;
83 int screen_w = 320;
84 int screen_h = 240;
85 int screen_offset_x = 0;
86 int screen_offset_y = 0;
87 int screen_w_phys;
88 int screen_h_phys;
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(!gl_flag){
98 SDL_Surface* surf = gfx[gfxid].surf;
99 SDL_Rect r1 = {X,Y,W,H};
100 SDL_Rect r2 = {x,y,W,H};
101 SDL_BlitSurface(surf,&r1,video,&r2);
103 else{
104 double w = gfx[gfxid].w;
105 double h = gfx[gfxid].h;
106 double X0 = ((double)X)/w;
107 double X1 = X0 + ((double)W)/w;
108 double Y0 = ((double)Y)/h;
109 double Y1 = Y0 + ((double)H)/h;
111 glBindTexture( GL_TEXTURE_2D, gfx[gfxid].texture );
112 glBegin( GL_QUADS );
113 glTexCoord2d(X0,Y0);
114 glVertex3f(x,y,0);
116 glTexCoord2d(X1,Y0);
117 glVertex3f(x+W,y,0);
119 glTexCoord2d(X1,Y1);
120 glVertex3f(x+W,y+H,0);
122 glTexCoord2d(X0,Y1);
123 glVertex3f(x,y+H,0);
124 glEnd();
128 void draw_test_rect(int x, int y, int w, int h){
129 if(!gl_flag){
130 SDL_Rect dst = {x, y, w, h};
131 SDL_FillRect(video, &dst, 0x00ff00ff);
133 else{
134 glColor3f(1.0, 0.0, 1.0);
135 glBegin( GL_QUADS );
136 glVertex3f(x, y, 0);
137 glVertex3f(x+w, y, 0);
138 glVertex3f(x+w, y+h, 0);
139 glVertex3f(x, y+h, 0);
140 glEnd();
141 glColor3f(1.0,1.0,1.0);
145 void draw_gfx(int gfxid, int x, int y, int X, int Y, int W, int H){
146 draw_gfx_raw(gfxid, x+screen_offset_x, y+screen_offset_y, X, Y, W, H);
149 void clear_video(){
150 if(!gl_flag){
151 SDL_FillRect(video, 0, 0);
153 else{
154 glClearColor(0.0,0.0,0.0,0.0);
155 glClear( GL_COLOR_BUFFER_BIT );
159 void update_video(){
160 if(!gl_flag){
161 SDL_UpdateRect(video,0,0,0,0);
163 else{
164 SDL_GL_SwapBuffers();
169 /********************/
170 /* graphics loading */
171 /********************/
173 SDL_Surface* SDL_NewSurface(int w, int h){
174 char prefix[32] = "SDL_NewSurface";
175 SDL_Surface* tmp = SDL_CreateRGBSurface(SDL_SRCCOLORKEY,w,h,32,0,0,0,0);
176 if(!tmp){
177 out_of_memory(prefix);
180 SDL_Surface* surf = SDL_DisplayFormat(tmp);
181 if(!surf){
182 out_of_memory(prefix);
185 SDL_FreeSurface(tmp);
187 SDL_FillRect(surf,0,0x00ffffff);
189 return surf;
192 void debug_surf(char* msg, SDL_Surface* surf){
193 printf("%s\n", msg);
194 int i;
195 unsigned char* ptr = surf->pixels;
196 int bpp = surf->format->BytesPerPixel;
198 for(i=0; i<500; i+=bpp){
199 printf("%2x %2x %2x %2x\n", ptr[i], ptr[i+1], ptr[i+2], ptr[i+3]);
205 SDL_Surface* load_tga(const char* path){
206 unsigned char header[18];
207 reader* rd = loader_open(path);
208 int w, h, bpp;
209 int mask;
210 unsigned char parts[4];
211 int key = 0;
212 int i;
213 int npix;
214 Uint32* pixels;
216 if(!rd){
217 error_msg("load_pixmap: error opening file\n");
218 return NULL;
221 if(loader_read(rd, header, 18) < 0){
222 error_msg("load_pixmap: error reading pixmap header\n");
223 loader_close(rd);
224 return NULL;
227 w = header[12] + (header[13]<<8);
228 h = header[14] + (header[15]<<8);
229 bpp = header[16];
231 npix = w*h;
233 SDL_Surface* surf = SDL_CreateRGBSurface(0,w,h,32,
234 0x00ff0000,0x0000ff00,0x000000ff,0xff000000);
235 if(!surf){
236 out_of_memory("load_pixmap");
239 pixels = surf->pixels;
240 mask = surf->format->Amask;
242 for(i=0; i<npix; i++){
243 if(loader_read(rd, parts, bpp/8) < 0){
244 error_msg("load_pixmap: error reading pixmap data\n");
245 loader_close(rd);
246 SDL_FreeSurface(surf);
247 return NULL;
250 if(bpp == 24){
251 if(parts[0] == 0 && parts[1] == 0 && parts[2] == 0){
252 pixels[i] = 0;
254 else{
255 pixels[i] = parts[0] | (parts[1]<<8) | (parts[2]<<16);
256 pixels[i] |= mask;
259 else if(bpp == 32){
260 if(parts[0] == 0 && parts[1] == 0 && parts[2] == 0){
261 pixels[i] = 0;
263 else{
264 pixels[i] = parts[0] | (parts[1]<<8) | (parts[2]<<16);
265 pixels[i] |= mask;
270 loader_close(rd);
272 SDL_SetAlpha(surf, 0, 0);
273 SDL_SetColorKey(surf, SDL_SRCCOLORKEY, key);
274 //debug_surf(filename, surf);
276 return surf;
280 int load_gfx(const char* filename){
281 int i;
282 SDL_Surface* src;
284 if(filename[0] == '\0'){
285 printf("load_gfx: empty path\n");
286 return 0;
289 if(gfx_count == MAX_GFX){
290 printf("this error can easily be fixed\n");
291 fatal_error(
292 "load_gfx: cannot load any more than %d graphics\n",
293 MAX_GFX
297 for(i=0; i<gfx_count; i++){/*check for already loaded gfx*/
298 if(strcmp(gfx[i].filename, filename)==0){
299 return i;
303 src = load_tga(filename);
304 if(!src){
305 //fatal_error("load_gfx: failed to load %s\n",filename);
306 return 0;
309 if(!gl_flag){
310 gfx[gfx_count].filename = strxcpy(filename);
311 gfx[gfx_count].surf = src;
312 gfx[gfx_count].w = src->w;
313 gfx[gfx_count].h = src->h;
315 else {
316 GLuint texture;
318 glGenTextures( 1, &texture );
319 glBindTexture( GL_TEXTURE_2D, texture );
321 glTexParameteri(
322 GL_TEXTURE_2D,
323 GL_TEXTURE_MIN_FILTER,
324 GL_NEAREST
327 glTexParameteri(
328 GL_TEXTURE_2D,
329 GL_TEXTURE_MAG_FILTER,
330 GL_NEAREST
333 glTexParameteri(
334 GL_TEXTURE_2D,
335 GL_TEXTURE_WRAP_S,
336 GL_REPEAT
339 glTexParameteri(
340 GL_TEXTURE_2D,
341 GL_TEXTURE_WRAP_T,
342 GL_REPEAT
345 glTexImage2D(
346 GL_TEXTURE_2D,
347 0, 4,
348 src->w, src->h,
350 GL_BGRA, GL_UNSIGNED_BYTE,
351 src->pixels
354 gfx[gfx_count].filename = strxcpy(filename);
355 gfx[gfx_count].texture = texture;
356 gfx[gfx_count].w = src->w;
357 gfx[gfx_count].h = src->h;
359 SDL_FreeSurface(src);
362 return gfx_count++;
365 void clear_gfx(){
366 int i;
367 for(i=2; i<gfx_count; i++){
368 if(!gl_flag){
369 SDL_FreeSurface(gfx[i].surf);
371 else{
372 glDeleteTextures(1, &(gfx[i].texture));
376 gfx_count = 2;
379 void load_panic_gfx(){
380 if(gfx_count > 0){
381 printf("load_panic_gfx: must call this before loading graphics\n");
383 else{
384 load_gfx("gfx/panic.tga");
385 load_gfx("gfx/smallfont.tga");
387 gfx[0].filename[0] = 0;
388 gfx[1].filename[1] = 0;
397 /******************/
398 /* initialization */
399 /******************/
401 void sdl_init(){
402 if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK)==-1){
403 error_msg("sdl: %s\n",SDL_GetError());
404 exit(-1);
412 void print_version(){
413 char message[] =
414 "This program is distributed under the terms of the GNU General\n"
415 "Public License (v2) and comes with ABSOLUTELY NO WARRANTY.\n\n"
417 "Send questions, comments, and bugs to evanrinehart@gmail.com\n\n"
419 "Send money to:\n"
420 "1850 Claiborne St\n"
421 "Mandeville, LA 70448\n"
422 "United States of America\n\n"
424 "Thanks! :)\n"
427 printf("Cantaveria (v%d.%d)\n", VERSION_MAJOR, VERSION_MINOR);
428 printf("Copyright 2009 Evan Rinehart\n\n");
429 printf("%s\n", message);
432 void print_help(){
433 printf("options:\n");
434 printf(" -gl use opengl video mode\n");
435 printf(" -f use fullscreen video mode\n");
436 printf(" -h print this help\n");
437 printf(" -v print version info\n");
440 void parse_options(int argc, char* argv[], int* _fullscreen, int* _gl_flag){
441 int i;
442 for(i=0; i<argc; i++){
443 if(!strcmp(argv[i], "-gl")){
444 *_gl_flag = 1;
445 continue;
447 if(!strcmp(argv[i], "-f")){
448 *_fullscreen = 1;
450 if(!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")){
451 print_help();
452 exit(0);
454 if(!strcmp(argv[i], "-v")){
455 print_version();
456 exit(0);
462 void setup_joysticks(){
463 int N = SDL_NumJoysticks();
464 int i;
465 boot_msg("sdl: detected %d joysticks\n", N);
466 for(i=0; i<N; i++){
467 if(SDL_JoystickOpen(i)){
468 boot_msg(" joy%d: %s\n", i, SDL_JoystickName(i));
470 else{
471 boot_msg(" joy%d: %s (failed to open)\n", i, SDL_JoystickName(i));
477 void setup_video(){
478 int flags = 0;
479 int i;
481 SDL_WM_SetCaption("cantaveria","cantaveria");
482 SDL_ShowCursor(SDL_DISABLE);
483 const SDL_VideoInfo* vinfo = SDL_GetVideoInfo();
486 if(fullscreen && gl_flag){
487 screen_w_phys = vinfo->current_w;
488 screen_h_phys = vinfo->current_h;
490 else if(gl_flag){
491 //W = 320;
492 //H = 240;
493 screen_w_phys = 640;
494 screen_h_phys = 480;
495 //W = 960;
496 //H = 720;
498 else if(fullscreen){
499 screen_w_phys = 320;
500 screen_h_phys = 240;
502 else{
503 screen_w_phys = 320;
504 screen_h_phys = 240;
507 if(gl_flag){
508 SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
509 //SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1);
510 //SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, 1);
511 flags |= SDL_OPENGL;
514 if(fullscreen){
515 flags |= SDL_FULLSCREEN;
520 video = SDL_SetVideoMode(screen_w_phys,screen_h_phys,32,flags);
521 if(video == NULL){
522 fatal_error("sdl: %s\n",SDL_GetError());
525 if(gl_flag){
526 glEnable(GL_BLEND);
527 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
529 glEnable( GL_TEXTURE_2D );
530 glClearColor( 0.0f, 0.0f, 0.0f, 0.0f );
532 glViewport( 0, 0, screen_w_phys, screen_h_phys );
534 glClear( GL_COLOR_BUFFER_BIT );
536 glMatrixMode( GL_PROJECTION );
537 glLoadIdentity();
538 if(fullscreen){
539 //glOrtho(0.0f, 240*aspect, 240, 0.0f, -1.0f, 1.0f);
540 //glOrtho(0.0f, 1280.0/3, 800.0/3, 0.0f, -1.0f, 1.0f);
541 int min = 9999;
542 int n = 0;
543 for(i=1; i<10; i++){
544 if(abs(screen_h_phys/i - 240) < min){
545 min = screen_h_phys/i - 240; n = i;
548 double new_w = ((double)screen_w_phys)/n;
549 double new_h = ((double)screen_h_phys)/n;
550 screen_offset_x = (new_w-320)/2;
551 screen_offset_y = (new_h-240)/2;
552 glOrtho(0.0f, new_w, new_h, 0.0f, -1.0f, 1.0f);
553 screen_w = new_w;
554 screen_h = new_h;
556 else{
557 glOrtho(0.0f, 320, 240, 0.0f, -1.0f, 1.0f);
558 screen_w = 320;
559 screen_h = 240;
562 glMatrixMode( GL_MODELVIEW );
563 glLoadIdentity();
565 else{
566 screen_w = 320;
567 screen_h = 240;
570 boot_msg("video:\n");
571 boot_msg(" resolution: %d x %d %s\n",screen_w_phys,screen_h_phys,fullscreen?"fullscreen":"windowed");
572 boot_msg(" pixel dimensions: %d x %d\n",screen_w,screen_h);
573 boot_msg(" aspect ratio: %g\n",((double)screen_w_phys)/screen_h_phys);
574 boot_msg(" opengl: %s\n",gl_flag?"yes":"no");
575 boot_msg(" x-offset: %d\n",screen_offset_x);
576 boot_msg(" y-offset: %d\n",screen_offset_y);
577 boot_msg(" video on\n");
581 void map_pixel(int mx, int my, int *x, int *y){
582 *x = mx*screen_w/screen_w_phys;
583 *y = my*screen_h/screen_h_phys;
590 void video_init(int argc, char* argv[]){
591 sdl_init();
592 parse_options(argc, argv, &fullscreen, &gl_flag);
593 setup_joysticks();
594 setup_video();
595 time_last = SDL_GetTicks();
598 void video_quit(){
599 boot_msg("sdl: quit\n");
600 SDL_Quit();
604 /* fps */
606 int fps = 0;
607 int update_count = 0;
608 int draw_count = 0;
610 void fps_update(){
611 update_count++;
612 if(update_count == 100){
613 fps = draw_count * 100 / update_count;
614 update_count = 0;
615 draw_count = 0;
619 void fps_draw(){
620 draw_count++;
623 int get_fps(){
624 return fps;
628 void draw_black_rect(int x, int y, int w, int h){
629 if(!gl_flag){
630 SDL_Rect r = {x, y, w, h};
631 SDL_FillRect(video, &r, 0);
633 else{
634 glBegin( GL_QUADS );
635 glColor3f(0.0, 0.0, 0.0);
636 glVertex3f(x, y, 0);
637 glVertex3f(x+w, y, 0);
638 glVertex3f(x+w, y+h, 0);
639 glVertex3f(x, y+h, 0);
640 glColor3f(1.0,1.0,1.0);
641 glEnd();
646 void screen_dimensions(int* w, int * h){
647 *w = screen_w;
648 *h = screen_h;
654 void gfx_dimensions(int gfxid, int* w, int* h){
655 *w = gfx[gfxid].w;
656 *h = gfx[gfxid].h;