2 Cantaveria - action adventure platform game
3 Copyright (C) 2009 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
24 #include <SDL/SDL_opengl.h>
37 int now
= SDL_GetTicks();
38 int diff
= now
- last
;
49 int butmap
[MAX_PLAYERS
][8];
50 int joymap
[MAX_PLAYERS
];
56 int butnum(int joy
, int name
){
57 return butmap
[joy
][name
];
62 printf("sdl: quit\n");
78 while(SDL_PollEvent(&e
) != 0){
81 game
.handler
.keydown(e
.key
.keysym
.sym
);
84 game
.handler
.keyup(e
.key
.keysym
.sym
);
86 case SDL_JOYBUTTONDOWN
:
87 game
.handler
.joypress(e
.jbutton
.which
, e
.jbutton
.button
);
90 game
.handler
.joyrelease(e
.jbutton
.which
, e
.jbutton
.button
);
92 case SDL_JOYAXISMOTION
:
93 if(e
.jaxis
.axis
== 0){
94 game
.handler
.joymovex(e
.jaxis
.which
, e
.jaxis
.value
);
96 else if(e
.jaxis
.axis
== 1){
97 game
.handler
.joymovey(e
.jaxis
.which
, e
.jaxis
.value
);
107 void control(int type
, int par1
, int par2
){
111 game
.handler
.keydown(par1
);
114 game
.handler
.keyup(par1
);
117 game
.handler
.joymovex(par1
, par2
);
120 game
.handler
.joymovey(par1
, par2
);
123 game
.handler
.joypress(par1
, par2
);
126 game
.handler
.joyrelease(par1
, par2
);
146 the backend will draw the current state of the game
147 in the following way.
149 it will render a stage at a given position. a stage is
155 then it will render the sprites
158 the stage is measured in terms of screens
159 each screen is 20x15 tiles, each tile is 16 pixels square
160 each screen can have one tile set of 256 tiles
176 sprite
* sprites
[MAX_SPRITES
];
177 int sprite_count
= 0;
179 animation
* animations
[MAX_ANIMATIONS
];
182 int stage_enabled
= 0;
184 int screen_offset
= 0;
192 /********************/
193 /* drawing routines */
194 /********************/
196 void draw_sprite_sdl(sprite
* spr
){
197 int x
= spr
->x
- 0 + screen_offset
;
202 int X
= spr
->frame
.x
;
203 int Y
= spr
->frame
.y
;
205 SDL_Surface
* surf
= gfx
[spr
->gfxid
].surf
;
206 SDL_Rect r1
= {X
,Y
,w
,h
};
207 SDL_Rect r2
= {x
,y
,w
,h
};
208 SDL_BlitSurface(surf
,&r1
,video
,&r2
);
211 void draw_sprite_gl(sprite
* spr
){
212 int x
= spr
->x
- camera
.x
+ screen_offset
;
213 int y
= spr
->y
- camera
.y
;
217 glBindTexture( GL_TEXTURE_2D
, gfx
[spr
->gfxid
].texture
);
219 double X0
= spr
->frame
.x0
;
220 double Y0
= spr
->frame
.y0
;
221 double X1
= spr
->frame
.x1
;
222 double Y1
= spr
->frame
.y1
;
232 glVertex3f(x
+w
,y
+h
,0);
239 void draw_screen_sdl(zone
* z
, int si
, int sj
){
240 struct screen
* scr
= z
->screens
+si
+z
->w
*sj
;
241 SDL_Surface
* surf
= gfx
[z
->tileset
].surf
;
242 int x
= si
*20*16 - camera
.x
;
243 int y
= sj
*15*16 - camera
.y
;
245 for(int j
=0; j
< 15; j
++){
246 for(int i
=0; i
< 20; i
++){
247 if(x
> 320 || y
> 240 || x
< -16 || y
< -16) continue;
248 int gfx
= scr
->tiles
[i
][j
].gfx
;
250 SDL_Rect r1
= {gfx
&7,gfx
>>3,16,16};
251 SDL_Rect r2
= { x
, y
,16,16};
252 SDL_BlitSurface(surf
,&r1
,video
,&r2
);
264 void draw_screen_gl(zone
* z
, int si
, int sj
){
275 SDL_FillRect(video
, 0, 0xffffffff);
277 //draw walls and background
279 draw_screen_sdl(zones
[0],0,0);
283 for(int i
=0; i
< sprite_count
; i
++){
284 draw_sprite_sdl(sprites
[i
]);
287 //draw foreground tile/sprites
289 SDL_UpdateRect(video
,0,0,0,0);
293 glClearColor(1.0,1.0,1.0,0.0);
294 glClear( GL_COLOR_BUFFER_BIT
);
297 draw_screen_gl(zones
[0],0,0);
300 for(int i
=0; i
< sprite_count
; i
++){
301 draw_sprite_gl(sprites
[i
]);
304 SDL_GL_SwapBuffers();
318 void point_camera(int x
, int y
){
323 void animate_sprites(){
324 for(int i
=0; i
<sprite_count
; i
++){
325 sprite
* spr
= sprites
[i
];
327 spr
->frame_counter
+= dt
;
328 animation
* ani
= animations
[spr
->anim
];
331 while(spr
->frame_counter
> ani
->frame_lens
[spr
->current_frame
]){
332 spr
->frame_counter
-= ani
->frame_lens
[spr
->current_frame
];
333 spr
->current_frame
++;
334 if(spr
->current_frame
== ani
->frame_count
){
335 spr
->current_frame
= 0;
337 spr
->frame
= ani
->frames
[spr
->current_frame
];
340 if(spr
->update
) spr
->update(spr
, spr
->userdata
);
347 /********************/
348 /* graphics loading */
349 /********************/
351 SDL_Surface
* SDL_NewSurface(int w
, int h
){
352 char prefix
[32] = "SDL_NewSurface";
353 SDL_Surface
* tmp
= SDL_CreateRGBSurface(SDL_SRCCOLORKEY
,w
,h
,32,0,0,0,0);
355 out_of_memory(prefix
);
358 SDL_Surface
* surf
= SDL_DisplayFormat(tmp
);
360 out_of_memory(prefix
);
363 SDL_FreeSurface(tmp
);
365 SDL_FillRect(surf
,0,0x00ffffff);
372 loads a pixmap file stored in the gfx/ subdir
373 returns an SDL surface in the 24bit format RGBRGBRGB...
376 returns the gfx id of the graphics with filename
377 may or may not load a new gfx object with load_pixmap
378 in sdl mode this sets up the gfx surface for color key transparency
379 in opengl mode this converts the 24bit to 32bit texture with alpha channel
382 reads a sprite definition from from the sprites/ subdir
383 loads a new animation structure as defined the file
384 uses load_gfx to get gfx id for animation graphics
385 therefore, may or may not load new graphics
386 returns an sprite id number used to instantiate new sprites
391 SDL_Surface
* load_pixmap(char* filename
){
392 char path
[1024] = "gfx/";
393 strmcat(path
, filename
, 1024);
395 reader
* rd
= loader_open(path
);
400 unsigned char header
[18];
401 loader_read(rd
, header
, 18);
403 int w
= header
[12] + (header
[13]<<8);
404 int h
= header
[14] + (header
[15]<<8);
405 int bpp
= header
[16];
407 SDL_Surface
* surf
= SDL_CreateRGBSurface(0,w
,h
,bpp
,
408 0x00ff0000,0x0000ff00,0x000000ff,0xff000000);
410 out_of_memory("load_pixmap");
412 loader_read(rd
, surf
->pixels
, w
*(bpp
/8)*h
);
418 int load_gfx(char* filename
){
419 if(gfx_count
== MAX_GFX
){
420 fatal_error("load_gfx: cannot load any more than %d graphics\n",MAX_GFX
);
423 printf("loading %s\n",filename
);
426 for(int i
=0; i
<gfx_count
; i
++){/*check for already loaded gfx*/
427 if(strcmp(gfx
[i
].filename
, filename
)==0){
432 SDL_Surface
* src
= load_pixmap(filename
);
434 fatal_error("load_gfx: failed to load %s\n",filename
);
438 SDL_Surface
* surf
= SDL_DisplayFormatAlpha(src
);
439 SDL_SetAlpha(surf
, 0, 0);
441 Uint32 key
= SDL_MapRGB(surf
->format
, (COLOR_KEY
&0xff0000)>>16,
442 (COLOR_KEY
&0x00ff00)>>8,
443 (COLOR_KEY
&0x0000ff)>>0);
444 SDL_SetColorKey(surf
, SDL_SRCCOLORKEY
, key
);
446 SDL_FreeSurface(src
);
449 gfx
[gfx_count
].filename
= strxcpy(filename
);
450 gfx
[gfx_count
].surf
= surf
;
451 gfx
[gfx_count
].w
= surf
->w
;
452 gfx
[gfx_count
].h
= surf
->h
;
457 SDL_Surface
* conv
= SDL_CreateRGBSurface(0, src
->w
, src
->h
, 32,
458 0xff<<16,0xff<<8,0xff<<0,0);
460 SDL_BlitSurface(src
, NULL
, conv
, NULL
);
464 Uint8
* conv_bytes
= conv
->pixels
;
465 Uint32 key
= SDL_MapRGB(src
->format
,(COLOR_KEY
&0xff0000)>>16,
466 (COLOR_KEY
&0x00ff00)>>8,
467 (COLOR_KEY
&0x0000ff)>>0);
468 for(int i
=0; i
<src
->w
; i
++){
469 for(int j
=0; j
<src
->h
; j
++){
470 Uint32 pixel
= *((Uint32
*)(src
->pixels
+N
));
471 conv_bytes
[M
] = pixel
==key
? SDL_ALPHA_TRANSPARENT
: SDL_ALPHA_OPAQUE
;
472 N
+= src
->format
->BytesPerPixel
;
477 glGenTextures( 1, &texture
);
478 glBindTexture( GL_TEXTURE_2D
, texture
);
480 glTexParameteri( GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
481 glTexParameteri( GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
482 glTexParameteri( GL_TEXTURE_2D
, GL_TEXTURE_WRAP_S
, GL_REPEAT
);
483 glTexParameteri( GL_TEXTURE_2D
, GL_TEXTURE_WRAP_T
, GL_REPEAT
);
485 glTexImage2D( GL_TEXTURE_2D
, 0, 4, conv
->w
, conv
->h
, 0,
486 GL_BGRA
, GL_UNSIGNED_BYTE
, conv
->pixels
);
488 gfx
[gfx_count
].filename
= strxcpy(filename
);
489 gfx
[gfx_count
].texture
= texture
;
490 gfx
[gfx_count
].w
= src
->w
;
491 gfx
[gfx_count
].h
= src
->h
;
493 SDL_FreeSurface(conv
);
494 SDL_FreeSurface(src
);
501 int load_sprite(char* filename
, int id
){
502 printf("loading %s\n",filename
);
504 char path
[1024] = "sprites/";
505 strncat(path
, filename
, 1023 - strlen(filename
));
507 reader
* rd
= loader_open(path
);
512 animation
* ani
= xmalloc(sizeof(animation
));
519 loader_scanline(rd
,"%s",str
);
520 loader_scanline(rd
,"%d %d %d %d",&w
,&h
,&loop_mode
,&frame_count
);
522 ani
->frame_lens
= xmalloc(frame_count
*sizeof(short));
523 ani
->frames
= xmalloc(frame_count
*sizeof(struct frame
));
524 ani
->frame_count
= frame_count
;
526 int g
= load_gfx(str
);
537 for(int i
=0; i
< frame_count
; i
++){
539 loader_scanline(rd
, "%d %d %d", &l
, &x
, &y
);
540 ani
->frame_lens
[i
] = l
;
542 ani
->frames
[i
].x
= x
;
543 ani
->frames
[i
].y
= y
;
546 ani
->frames
[i
].x0
= ((double)x
)/W
;
547 ani
->frames
[i
].y0
= ((double)y
)/H
;
548 ani
->frames
[i
].x1
= ((double)(x
+w
))/W
;
549 ani
->frames
[i
].y1
= ((double)(y
+h
))/W
;
554 animations
[id
] = ani
;
559 /********************/
560 /* graphics control */
561 /********************/
563 sprite
* enable_sprite(int sprnum
){
564 if(!animations
[sprnum
]){
565 fatal_error("enable_sprite: you just tried to enable sprite with type %d, which does not exist\n",sprnum
);
567 if(sprite_count
== MAX_SPRITES
){
568 /* need a priority based way to create important sprites if full */
571 sprite
* spr
= xmalloc(sizeof(sprite
));
572 animation
* ani
= animations
[sprnum
];
574 spr
->number
= sprite_count
;
575 spr
->frame_counter
= 0;
576 spr
->current_frame
= 0;
577 spr
->frame
= ani
->frames
[0];
578 spr
->gfxid
= ani
->gfxid
;
587 spr
->userdata
= NULL
;
589 sprites
[sprite_count
++] = spr
;
593 void disable_sprite(sprite
* spr
){
594 sprite
* tmp
= sprites
[spr
->number
];
595 sprites
[spr
->number
] = sprites
[sprite_count
--];
599 sprite
* copy_sprite(sprite
* spr
){
600 if(sprite_count
== MAX_SPRITES
){
601 /* need way to make important sprites when full */
604 sprite
* copy
= xmalloc(sizeof(sprite
));
606 sprites
[sprite_count
++] = copy
;
616 extern void process_audio(short lout
[], short rout
[], int len
);
618 void audio_callback(void *userdata
, Uint8
*stream
, int len
){
619 Sint16
* out
= (Sint16
*)stream
;
621 process_audio(lout
, rout
, buffer_size
);
623 for(int i
=0; i
<buffer_size
; i
++){
625 out
[i
*2 + 1] = rout
[i
];
630 void backend_init(int argc
, char* argv
[]){
632 for(int i
=0; i
<MAX_ANIMATIONS
; i
++){
633 animations
[i
] = NULL
;
636 if(SDL_Init(SDL_INIT_VIDEO
| SDL_INIT_AUDIO
| SDL_INIT_JOYSTICK
)==-1){
637 report_error("sdl: %s\n",SDL_GetError());
644 for(int i
=0; i
<argc
; i
++){
645 if(!strcmp(argv
[i
], "-gl")){
649 if(!strcmp(argv
[i
], "-f")){
652 if(!strcmp(argv
[i
], "-h") || !strcmp(argv
[i
], "--help")){
653 printf("options:\n");
654 printf(" -gl use opengl video mode\n");
655 printf(" -f use fullscreen video mode\n");
656 printf(" -h print this help\n");
657 printf(" -v print version info\n");
660 if(!strcmp(argv
[i
], "-v")){
661 printf("cantaveria (v%d.%d)\n",VERSION_MAJOR
,VERSION_MINOR
);
662 printf("Copyright 2009 Evan Rinehart\n\n");
664 printf("This program is distributed under the terms of the GNU General\n"
665 "Public License (v2) and comes with ABSOLUTELY NO WARRANTY.\n\n");
667 printf("Send questions, comments, and bugs to evanrinehart@gmail.com\n\n");
669 printf("Send money to:\n");
670 printf("1850 Claiborne St\n");
671 printf("Mandeville, LA 70448\n");
672 printf("United States of America\n\n");
674 printf("Thanks! :)\n");
681 keymap
[ESCAPE_KEY
] = SDLK_ESCAPE
;
682 keymap
[PAUSE_KEY
] = SDLK_PAUSE
;
684 keymap
[LEFT_KEY
] = SDLK_LEFT
;
685 keymap
[RIGHT_KEY
] = SDLK_RIGHT
;
686 keymap
[UP_KEY
] = SDLK_UP
;
687 keymap
[DOWN_KEY
] = SDLK_DOWN
;
689 keymap
[FIRE_KEY
] = SDLK_z
;
690 keymap
[JUMP_KEY
] = SDLK_x
;
691 keymap
[INVENTORY_KEY
] = SDLK_a
;
692 keymap
[SPECIAL_KEY
] = SDLK_s
;
694 keymap
[L_KEY
] = SDLK_q
;
695 keymap
[R_KEY
] = SDLK_w
;
696 keymap
[START_KEY
] = SDLK_RETURN
;
697 keymap
[SELECT_KEY
] = SDLK_TAB
;
700 int N
= SDL_NumJoysticks();
701 printf("sdl: detected %d joysticks\n",N
);
702 for(int i
=0; i
<N
; i
++){
703 if(SDL_JoystickOpen(i
)){
704 printf(" joy%d: %s\n",i
,SDL_JoystickName(i
));
707 printf(" joy%d: %s (failed to open)\n",i
,SDL_JoystickName(i
));
715 SDL_WM_SetCaption("cantaveria","cantaveria");
716 SDL_ShowCursor(SDL_DISABLE
);
717 const SDL_VideoInfo
* vinfo
= SDL_GetVideoInfo();
720 if(fullscreen
&& gl_flag
){
721 W
= vinfo
->current_w
;
722 H
= vinfo
->current_h
;
741 //double aspect = vinfo->current_w*1.0 / vinfo->current_h;
742 double aspect
= ((double)W
) / H
;
746 SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER
, 1);
747 //SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1);
748 SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL
, 1);
753 flags
|= SDL_FULLSCREEN
;
754 screen_offset
= (aspect
*SCREEN_H
- SCREEN_W
)/2;
758 printf(" resolution: %d x %d %s\n",W
,H
,fullscreen
?"fullscreen":"windowed");
759 printf(" aspect ratio: %g\n",((double)W
)/H
);
760 printf(" opengl: %s\n",gl_flag
?"yes":"no");
761 printf(" x-offset: %d\n",screen_offset
);
763 video
= SDL_SetVideoMode(W
,H
,32,flags
);
765 report_error("sdl: %s\n",SDL_GetError());
769 printf(" video on\n");
773 glBlendFunc(GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
);
775 glEnable( GL_TEXTURE_2D
);
776 glClearColor( 0.0f
, 0.0f
, 0.0f
, 0.0f
);
778 glViewport( 0, 0, W
, H
);
780 glClear( GL_COLOR_BUFFER_BIT
);
782 glMatrixMode( GL_PROJECTION
);
785 glOrtho(0.0f
, 240*aspect
, 240, 0.0f
, -1.0f
, 1.0f
);
788 glOrtho(0.0f
, 320, 240, 0.0f
, -1.0f
, 1.0f
);
791 glMatrixMode( GL_MODELVIEW
);
798 audio
.freq
= SAMPLE_RATE
;
799 audio
.format
= AUDIO_S16
;
801 audio
.samples
= BUFFER_SIZE
;
802 audio
.callback
= audio_callback
;
804 SDL_AudioSpec gotten
;
806 if(SDL_OpenAudio(&audio
, &gotten
)<0){
807 report_error("sdl: cannot open audio (%s)\n", SDL_GetError());
812 printf(" sample rate = %d\n",gotten
.freq
);
813 printf(" channels = %d\n",gotten
.channels
);
814 printf(" samples = %d\n",gotten
.samples
);
815 printf(" format = %d\n",gotten
.format
);
817 if(gotten
.format
!= AUDIO_S16
){
818 printf(" WARNING: audio format not AUDIO_S16 :(\n");
821 lout
= xmalloc(gotten
.samples
*2);
822 rout
= xmalloc(gotten
.samples
*2);
823 buffer_size
= gotten
.samples
;
825 printf(" sound on\n");
834 modes = SDL_ListModes(NULL, SDL_FULLSCREEN|SDL_HWSURFACE);
836 if (modes == (SDL_Rect**)0) {
837 printf("No modes available!\n");
841 if (modes == (SDL_Rect**)-1) {
842 printf("All resolutions available.\n");
845 printf("Available Modes\n");
846 for (i=0; modes[i]; ++i)
847 printf(" %d x %d\n", modes[i]->w, modes[i]->h);