Work on music, midi, and seq interfaces.
[cantaveria.git] / video.c
bloba4e246c8ef32a2c5887c803e0ef507455f553c96
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 <root.h>
29 #include <util.h>
30 #include <input.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 return NULL;
171 unsigned char header[18];
172 loader_read(rd, header, 18);
174 int w = header[12] + (header[13]<<8);
175 int h = header[14] + (header[15]<<8);
176 int bpp = header[16];
177 printf("load_pixmap: %s has bpp=%d\n",filename, bpp);
178 SDL_Surface* surf = SDL_CreateRGBSurface(0,w,h,bpp,
179 0x00ff0000,0x0000ff00,0x000000ff,0xff000000);
180 if(!surf){
181 out_of_memory("load_pixmap");
183 loader_read(rd, surf->pixels, w*(bpp/8)*h);
184 loader_close(rd);
186 return surf;
189 int load_gfx(char* filename){
190 int i, j;
192 if(gfx_count == MAX_GFX){
193 fatal_error(
194 "load_gfx: cannot load any more than %d graphics\n",
195 MAX_GFX
200 printf("loading %s\n",filename);
203 for(i=0; i<gfx_count; i++){/*check for already loaded gfx*/
204 if(strcmp(gfx[i].filename, filename)==0){
205 return i;
209 SDL_Surface* src = load_pixmap(filename);
210 if(!src){
211 fatal_error("load_gfx: failed to load %s\n",filename);
214 if(!gl_flag){
215 SDL_Surface* surf = SDL_DisplayFormatAlpha(src);
216 SDL_SetAlpha(surf, 0, 0);
218 Uint32 key = SDL_MapRGB(
219 surf->format,
220 (COLOR_KEY&0xff0000)>>16,
221 (COLOR_KEY&0x00ff00)>>8,
222 (COLOR_KEY&0x0000ff)>>0
224 SDL_SetColorKey(surf, SDL_SRCCOLORKEY, key);
226 SDL_FreeSurface(src);
229 gfx[gfx_count].filename = strxcpy(filename);
230 gfx[gfx_count].surf = surf;
231 gfx[gfx_count].w = surf->w;
232 gfx[gfx_count].h = surf->h;
234 else {
235 GLuint texture;
237 //SDL_Surface* conv = SDL_CreateRGBSurface(0, pot(src->w), pot(src->h), 32,
238 //0xff<<16,0xff<<8,0xff<<0,0);
240 //SDL_Surface* tmp = SDL_
241 SDL_Surface* conv = SDL_DisplayFormatAlpha(src);
242 //SDL_SetAlpha(conv, 0, 0);
243 //SDL_BlitSurface(src, NULL, conv, NULL);
245 //printf("bpp = %d\n",conv->format->BitsPerPixel);
246 int N = 0;
247 int M = 3;
248 Uint8* conv_bytes = conv->pixels;
249 Uint32 key = SDL_MapRGB(
250 src->format,
251 (COLOR_KEY&0xff0000)>>16,
252 (COLOR_KEY&0x00ff00)>>8,
253 (COLOR_KEY&0x0000ff)>>0
255 for(i=0; i<src->w; i++){
256 for(j=0; j<src->h; j++){
258 //if(1){printf("M==%d totalbytes=%d\n",M,src->w*src->h*4);}
260 Uint32 pixel = *((Uint32*)(src->pixels+N));
261 conv_bytes[M] =
262 pixel==key ?
263 SDL_ALPHA_TRANSPARENT :
264 SDL_ALPHA_OPAQUE;
265 N += src->format->BytesPerPixel;
266 M += 4;
270 glGenTextures( 1, &texture );
271 glBindTexture( GL_TEXTURE_2D, texture );
273 glTexParameteri(
274 GL_TEXTURE_2D,
275 GL_TEXTURE_MIN_FILTER,
276 GL_NEAREST
279 glTexParameteri(
280 GL_TEXTURE_2D,
281 GL_TEXTURE_MAG_FILTER,
282 GL_NEAREST
285 glTexParameteri(
286 GL_TEXTURE_2D,
287 GL_TEXTURE_WRAP_S,
288 GL_REPEAT
291 glTexParameteri(
292 GL_TEXTURE_2D,
293 GL_TEXTURE_WRAP_T,
294 GL_REPEAT
297 glTexImage2D(
298 GL_TEXTURE_2D,
299 0, 4,
300 conv->w, conv->h,
302 GL_BGRA, GL_UNSIGNED_BYTE,
303 conv->pixels
306 gfx[gfx_count].filename = strxcpy(filename);
307 gfx[gfx_count].texture = texture;
308 gfx[gfx_count].w = src->w;
309 gfx[gfx_count].h = src->h;
311 SDL_FreeSurface(conv);
312 SDL_FreeSurface(src);
315 return gfx_count++;
318 int gfx_width(int gfxid){
319 return gfx[gfxid].w;
322 int gfx_height(int gfxid){
323 return gfx[gfxid].h;
331 /******************/
332 /* initialization */
333 /******************/
335 void sdl_init(){
336 if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK)==-1){
337 report_error("sdl: %s\n",SDL_GetError());
338 exit(-1);
345 void print_version(){
346 char message[] =
347 "This program is distributed under the terms of the GNU General\n"
348 "Public License (v2) and comes with ABSOLUTELY NO WARRANTY.\n\n"
350 "Send questions, comments, and bugs to evanrinehart@gmail.com\n\n"
352 "Send money to:\n"
353 "1850 Claiborne St\n"
354 "Mandeville, LA 70448\n"
355 "United States of America\n\n"
357 "Thanks! :)\n"
360 printf("Cantaveria (v%d.%d)\n", VERSION_MAJOR, VERSION_MINOR);
361 puts("Copyright 2009 Evan Rinehart\n\n");
362 puts(message);
365 void print_help(){
366 printf("options:\n");
367 printf(" -gl use opengl video mode\n");
368 printf(" -f use fullscreen video mode\n");
369 printf(" -h print this help\n");
370 printf(" -v print version info\n");
373 void parse_options(int argc, char* argv[], int* fullscreen, int* gl_flag){
374 int i;
375 for(i=0; i<argc; i++){
376 if(!strcmp(argv[i], "-gl")){
377 *gl_flag = 1;
378 continue;
380 if(!strcmp(argv[i], "-f")){
381 *fullscreen = 1;
383 if(!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")){
384 print_help();
385 exit(0);
387 if(!strcmp(argv[i], "-v")){
388 print_version();
389 exit(0);
395 void setup_joysticks(){
396 int N = SDL_NumJoysticks();
397 int i;
398 printf("sdl: detected %d joysticks\n",N);
399 for(i=0; i<N; i++){
400 if(SDL_JoystickOpen(i)){
401 printf(" joy%d: %s\n", i, SDL_JoystickName(i));
403 else{
404 printf(
405 " joy%d: %s (failed to open)\n",
406 i, SDL_JoystickName(i)
413 void setup_video(){
414 int flags = 0;
415 int i;
417 SDL_WM_SetCaption("cantaveria","cantaveria");
418 SDL_ShowCursor(SDL_DISABLE);
419 const SDL_VideoInfo* vinfo = SDL_GetVideoInfo();
422 if(fullscreen && gl_flag){
423 W = vinfo->current_w;
424 H = vinfo->current_h;
426 else if(gl_flag){
427 //W = 320;
428 //H = 240;
429 W = 640;
430 H = 480;
431 //W = 960;
432 //H = 720;
434 else if(fullscreen){
435 W = 320;
436 H = 240;
438 else{
439 W = 320;
440 H = 240;
443 if(gl_flag){
444 SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
445 //SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1);
446 SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, 1);
447 flags |= SDL_OPENGL;
450 if(fullscreen){
451 flags |= SDL_FULLSCREEN;
456 video = SDL_SetVideoMode(W,H,32,flags);
457 if(video == NULL){
458 report_error("sdl: %s\n",SDL_GetError());
459 exit(-1);
462 if(gl_flag){
463 glEnable(GL_BLEND);
464 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
466 glEnable( GL_TEXTURE_2D );
467 glClearColor( 0.0f, 0.0f, 0.0f, 0.0f );
469 glViewport( 0, 0, W, H );
471 glClear( GL_COLOR_BUFFER_BIT );
473 glMatrixMode( GL_PROJECTION );
474 glLoadIdentity();
475 if(fullscreen){
476 //glOrtho(0.0f, 240*aspect, 240, 0.0f, -1.0f, 1.0f);
477 //glOrtho(0.0f, 1280.0/3, 800.0/3, 0.0f, -1.0f, 1.0f);
478 int min = 9999;
479 int n = 0;
480 for(i=1; i<10; i++){
481 if(abs(H/i - 240) < min){ min = H/i - 240; n = i; }
483 double new_w = ((double)W)/n;
484 double new_h = ((double)H)/n;
485 screen_offset_x = (new_w-320)/2;
486 screen_offset_y = (new_h-240)/2;
487 glOrtho(0.0f, new_w, new_h, 0.0f, -1.0f, 1.0f);
488 screen_w = new_w;
489 screen_h = new_h;
491 else{
492 glOrtho(0.0f, 320, 240, 0.0f, -1.0f, 1.0f);
493 screen_w = 320;
494 screen_h = 240;
497 glMatrixMode( GL_MODELVIEW );
498 glLoadIdentity();
500 else{
501 screen_w = 320;
502 screen_h = 240;
505 printf("video:\n");
506 printf(" resolution: %d x %d %s\n",W,H,fullscreen?"fullscreen":"windowed");
507 printf(" pixel dimensions: %d x %d\n",screen_w,screen_h);
508 printf(" aspect ratio: %g\n",((double)W)/H);
509 printf(" opengl: %s\n",gl_flag?"yes":"no");
510 printf(" x-offset: %d\n",screen_offset_x);
511 printf(" y-offset: %d\n",screen_offset_y);
512 printf(" video on\n");
522 void video_init(int argc, char* argv[]){
523 sdl_init();
524 parse_options(argc, argv, &fullscreen, &gl_flag);
525 setup_joysticks();
526 setup_video();
527 time_last = SDL_GetTicks();
531 void video_quit(){
532 printf("sdl: quit\n");
533 SDL_Quit();
537 /* fps */
539 int fps = 0;
540 int update_count = 0;
541 int draw_count = 0;
543 void fps_update(){
544 update_count++;
545 if(update_count == 100){
546 fps = draw_count * 100 / update_count;
547 update_count = 0;
548 draw_count = 0;
552 void fps_draw(){
553 draw_count++;
556 int get_fps(){
557 return fps;