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();
310 /*******************/
311 /* message control */
312 /*******************/
321 struct treenode
* chartree
= NULL
;
325 int ptrcomp(void* k1
, void* k2
){
329 void set_message(char* str
){
333 N
+= unicode_getc(str
+N
, &u
);
334 vwchar
* C
= tree_search(chartree
, ptrcomp
, (void*)u
);
335 printf("%04lx[%p] ",u
, C
);
340 void advance_message(){
344 void clear_message(){
348 void complete_message(){
354 vwchar
* C
= xmalloc(sizeof(vwchar
));
362 chartree
= xmalloc(sizeof(treenode
));
366 chartree
->key
= (void*)' ';
374 vwchar
* load_vwchar(reader
* rd
, int gfx
){
378 int ret
= loader_scanline(rd
, "%256s %d %d %d %d %d\n",str
,&x
,&y
,&w
,&k1
,&k2
);
382 unicode_getc(str
,&u
);
383 vwchar
* C
= xmalloc(sizeof(vwchar
));
394 void print_tree(treenode
* node
){
395 printf("(%lx,",(utf32
)node
->key
);
413 void randomly_insert(vwchar
* C
[], int count
){
414 for(int i
=0; i
<count
-1; i
++){
415 int j
= randint(0,count
-i
-1);
416 tree_insert(chartree
, ptrcomp
, (void*)C
[j
]->u
, C
[j
]);
423 int load_font(char* filename
){
424 printf("load_font: loading %s\n",filename
);
425 char buf
[256] = "fonts/";
426 strmcat(buf
, filename
, 256);
427 reader
* rd
= loader_open(buf
);
429 fatal_error("load_font: cannot open %s\n",filename
);
433 loader_scanline(rd
, "%256s", str
);
434 int gfx
= load_gfx(str
);
436 /* we read 64 characters at a time and insert them
437 randomly into the binary search tree. this is supposed
438 to help produce a more balanced tree. */
442 C
[ptr
] = load_vwchar(rd
, gfx
);
445 randomly_insert(C
, 64);
449 C
[++ptr
] = load_vwchar(rd
, gfx
);
453 randomly_insert(C
, ptr
);
455 printf("load_font: character tree is the following\n");
456 print_tree(chartree
);
468 void point_camera(int x
, int y
){
473 void animate_sprites(){
474 for(int i
=0; i
<sprite_count
; i
++){
475 sprite
* spr
= sprites
[i
];
477 spr
->frame_counter
+= dt
;
478 animation
* ani
= animations
[spr
->anim
];
481 while(spr
->frame_counter
> ani
->frame_lens
[spr
->current_frame
]){
482 spr
->frame_counter
-= ani
->frame_lens
[spr
->current_frame
];
483 spr
->current_frame
++;
484 if(spr
->current_frame
== ani
->frame_count
){
485 spr
->current_frame
= 0;
487 spr
->frame
= ani
->frames
[spr
->current_frame
];
490 if(spr
->update
) spr
->update(spr
, spr
->userdata
);
497 /********************/
498 /* graphics loading */
499 /********************/
501 SDL_Surface
* SDL_NewSurface(int w
, int h
){
502 char prefix
[32] = "SDL_NewSurface";
503 SDL_Surface
* tmp
= SDL_CreateRGBSurface(SDL_SRCCOLORKEY
,w
,h
,32,0,0,0,0);
505 out_of_memory(prefix
);
508 SDL_Surface
* surf
= SDL_DisplayFormat(tmp
);
510 out_of_memory(prefix
);
513 SDL_FreeSurface(tmp
);
515 SDL_FillRect(surf
,0,0x00ffffff);
522 loads a pixmap file stored in the gfx/ subdir
523 returns an SDL surface in the 24bit format RGBRGBRGB...
526 returns the gfx id of the graphics with filename
527 may or may not load a new gfx object with load_pixmap
528 in sdl mode this sets up the gfx surface for color key transparency
529 in opengl mode this converts the 24bit to 32bit texture with alpha channel
532 reads a sprite definition from from the sprites/ subdir
533 loads a new animation structure as defined the file
534 uses load_gfx to get gfx id for animation graphics
535 therefore, may or may not load new graphics
536 returns an sprite id number used to instantiate new sprites
541 SDL_Surface
* load_pixmap(char* filename
){
542 char path
[256] = "gfx/";
543 strmcat(path
, filename
, 256);
545 reader
* rd
= loader_open(path
);
550 unsigned char header
[18];
551 loader_read(rd
, header
, 18);
553 int w
= header
[12] + (header
[13]<<8);
554 int h
= header
[14] + (header
[15]<<8);
555 int bpp
= header
[16];
557 SDL_Surface
* surf
= SDL_CreateRGBSurface(0,w
,h
,bpp
,
558 0x00ff0000,0x0000ff00,0x000000ff,0xff000000);
560 out_of_memory("load_pixmap");
562 loader_read(rd
, surf
->pixels
, w
*(bpp
/8)*h
);
568 int load_gfx(char* filename
){
569 if(gfx_count
== MAX_GFX
){
570 fatal_error("load_gfx: cannot load any more than %d graphics\n",MAX_GFX
);
573 printf("loading %s\n",filename
);
576 for(int i
=0; i
<gfx_count
; i
++){/*check for already loaded gfx*/
577 if(strcmp(gfx
[i
].filename
, filename
)==0){
582 SDL_Surface
* src
= load_pixmap(filename
);
584 fatal_error("load_gfx: failed to load %s\n",filename
);
588 SDL_Surface
* surf
= SDL_DisplayFormatAlpha(src
);
589 SDL_SetAlpha(surf
, 0, 0);
591 Uint32 key
= SDL_MapRGB(surf
->format
, (COLOR_KEY
&0xff0000)>>16,
592 (COLOR_KEY
&0x00ff00)>>8,
593 (COLOR_KEY
&0x0000ff)>>0);
594 SDL_SetColorKey(surf
, SDL_SRCCOLORKEY
, key
);
596 SDL_FreeSurface(src
);
599 gfx
[gfx_count
].filename
= strxcpy(filename
);
600 gfx
[gfx_count
].surf
= surf
;
601 gfx
[gfx_count
].w
= surf
->w
;
602 gfx
[gfx_count
].h
= surf
->h
;
607 SDL_Surface
* conv
= SDL_CreateRGBSurface(0, src
->w
, src
->h
, 32,
608 0xff<<16,0xff<<8,0xff<<0,0);
610 SDL_BlitSurface(src
, NULL
, conv
, NULL
);
614 Uint8
* conv_bytes
= conv
->pixels
;
615 Uint32 key
= SDL_MapRGB(src
->format
,(COLOR_KEY
&0xff0000)>>16,
616 (COLOR_KEY
&0x00ff00)>>8,
617 (COLOR_KEY
&0x0000ff)>>0);
618 for(int i
=0; i
<src
->w
; i
++){
619 for(int j
=0; j
<src
->h
; j
++){
620 Uint32 pixel
= *((Uint32
*)(src
->pixels
+N
));
621 conv_bytes
[M
] = pixel
==key
? SDL_ALPHA_TRANSPARENT
: SDL_ALPHA_OPAQUE
;
622 N
+= src
->format
->BytesPerPixel
;
627 glGenTextures( 1, &texture
);
628 glBindTexture( GL_TEXTURE_2D
, texture
);
630 glTexParameteri( GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
631 glTexParameteri( GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
632 glTexParameteri( GL_TEXTURE_2D
, GL_TEXTURE_WRAP_S
, GL_REPEAT
);
633 glTexParameteri( GL_TEXTURE_2D
, GL_TEXTURE_WRAP_T
, GL_REPEAT
);
635 glTexImage2D( GL_TEXTURE_2D
, 0, 4, conv
->w
, conv
->h
, 0,
636 GL_BGRA
, GL_UNSIGNED_BYTE
, conv
->pixels
);
638 gfx
[gfx_count
].filename
= strxcpy(filename
);
639 gfx
[gfx_count
].texture
= texture
;
640 gfx
[gfx_count
].w
= src
->w
;
641 gfx
[gfx_count
].h
= src
->h
;
643 SDL_FreeSurface(conv
);
644 SDL_FreeSurface(src
);
651 int load_sprite(char* filename
, int id
){
652 printf("loading %s\n",filename
);
654 char path
[1024] = "sprites/";
655 strncat(path
, filename
, 1023 - strlen(filename
));
657 reader
* rd
= loader_open(path
);
662 animation
* ani
= xmalloc(sizeof(animation
));
669 loader_scanline(rd
,"%256s",str
);
670 loader_scanline(rd
,"%d %d %d %d",&w
,&h
,&loop_mode
,&frame_count
);
672 ani
->frame_lens
= xmalloc(frame_count
*sizeof(short));
673 ani
->frames
= xmalloc(frame_count
*sizeof(struct frame
));
674 ani
->frame_count
= frame_count
;
676 int g
= load_gfx(str
);
687 for(int i
=0; i
< frame_count
; i
++){
689 loader_scanline(rd
, "%d %d %d", &l
, &x
, &y
);
690 ani
->frame_lens
[i
] = l
;
692 ani
->frames
[i
].x
= x
;
693 ani
->frames
[i
].y
= y
;
696 ani
->frames
[i
].x0
= ((double)x
)/W
;
697 ani
->frames
[i
].y0
= ((double)y
)/H
;
698 ani
->frames
[i
].x1
= ((double)(x
+w
))/W
;
699 ani
->frames
[i
].y1
= ((double)(y
+h
))/W
;
704 animations
[id
] = ani
;
711 /********************/
712 /* graphics control */
713 /********************/
715 sprite
* enable_sprite(int sprnum
){
716 if(!animations
[sprnum
]){
717 fatal_error("enable_sprite: you just tried to enable sprite with type %d, which does not exist\n",sprnum
);
719 if(sprite_count
== MAX_SPRITES
){
720 /* need a priority based way to create important sprites if full */
723 sprite
* spr
= xmalloc(sizeof(sprite
));
724 animation
* ani
= animations
[sprnum
];
726 spr
->number
= sprite_count
;
727 spr
->frame_counter
= 0;
728 spr
->current_frame
= 0;
729 spr
->frame
= ani
->frames
[0];
730 spr
->gfxid
= ani
->gfxid
;
739 spr
->userdata
= NULL
;
741 sprites
[sprite_count
++] = spr
;
745 void disable_sprite(sprite
* spr
){
746 sprite
* tmp
= sprites
[spr
->number
];
747 sprites
[spr
->number
] = sprites
[sprite_count
--];
751 sprite
* copy_sprite(sprite
* spr
){
752 if(sprite_count
== MAX_SPRITES
){
753 /* need way to make important sprites when full */
756 sprite
* copy
= xmalloc(sizeof(sprite
));
758 sprites
[sprite_count
++] = copy
;
768 extern void process_audio(short lout
[], short rout
[], int len
);
770 void audio_callback(void *userdata
, Uint8
*stream
, int len
){
771 Sint16
* out
= (Sint16
*)stream
;
773 process_audio(lout
, rout
, buffer_size
);
775 for(int i
=0; i
<buffer_size
; i
++){
777 out
[i
*2 + 1] = rout
[i
];
788 void backend_init(int argc
, char* argv
[]){
794 for(int i
=0; i
<MAX_ANIMATIONS
; i
++){
795 animations
[i
] = NULL
;
798 if(SDL_Init(SDL_INIT_VIDEO
| SDL_INIT_AUDIO
| SDL_INIT_JOYSTICK
)==-1){
799 report_error("sdl: %s\n",SDL_GetError());
806 for(int i
=0; i
<argc
; i
++){
807 if(!strcmp(argv
[i
], "-gl")){
811 if(!strcmp(argv
[i
], "-f")){
814 if(!strcmp(argv
[i
], "-h") || !strcmp(argv
[i
], "--help")){
815 printf("options:\n");
816 printf(" -gl use opengl video mode\n");
817 printf(" -f use fullscreen video mode\n");
818 printf(" -h print this help\n");
819 printf(" -v print version info\n");
822 if(!strcmp(argv
[i
], "-v")){
823 printf("cantaveria (v%d.%d)\n",VERSION_MAJOR
,VERSION_MINOR
);
824 printf("Copyright 2009 Evan Rinehart\n\n");
826 printf("This program is distributed under the terms of the GNU General\n"
827 "Public License (v2) and comes with ABSOLUTELY NO WARRANTY.\n\n");
829 printf("Send questions, comments, and bugs to evanrinehart@gmail.com\n\n");
831 printf("Send money to:\n");
832 printf("1850 Claiborne St\n");
833 printf("Mandeville, LA 70448\n");
834 printf("United States of America\n\n");
836 printf("Thanks! :)\n");
843 keymap
[ESCAPE_KEY
] = SDLK_ESCAPE
;
844 keymap
[PAUSE_KEY
] = SDLK_PAUSE
;
846 keymap
[LEFT_KEY
] = SDLK_LEFT
;
847 keymap
[RIGHT_KEY
] = SDLK_RIGHT
;
848 keymap
[UP_KEY
] = SDLK_UP
;
849 keymap
[DOWN_KEY
] = SDLK_DOWN
;
851 keymap
[FIRE_KEY
] = SDLK_z
;
852 keymap
[JUMP_KEY
] = SDLK_x
;
853 keymap
[INVENTORY_KEY
] = SDLK_a
;
854 keymap
[SPECIAL_KEY
] = SDLK_s
;
856 keymap
[L_KEY
] = SDLK_q
;
857 keymap
[R_KEY
] = SDLK_w
;
858 keymap
[START_KEY
] = SDLK_RETURN
;
859 keymap
[SELECT_KEY
] = SDLK_TAB
;
862 int N
= SDL_NumJoysticks();
863 printf("sdl: detected %d joysticks\n",N
);
864 for(int i
=0; i
<N
; i
++){
865 if(SDL_JoystickOpen(i
)){
866 printf(" joy%d: %s\n",i
,SDL_JoystickName(i
));
869 printf(" joy%d: %s (failed to open)\n",i
,SDL_JoystickName(i
));
877 SDL_WM_SetCaption("cantaveria","cantaveria");
878 SDL_ShowCursor(SDL_DISABLE
);
879 const SDL_VideoInfo
* vinfo
= SDL_GetVideoInfo();
882 if(fullscreen
&& gl_flag
){
883 W
= vinfo
->current_w
;
884 H
= vinfo
->current_h
;
903 //double aspect = vinfo->current_w*1.0 / vinfo->current_h;
904 double aspect
= ((double)W
) / H
;
908 SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER
, 1);
909 //SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1);
910 SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL
, 1);
915 flags
|= SDL_FULLSCREEN
;
916 screen_offset
= (aspect
*SCREEN_H
- SCREEN_W
)/2;
920 printf(" resolution: %d x %d %s\n",W
,H
,fullscreen
?"fullscreen":"windowed");
921 printf(" aspect ratio: %g\n",((double)W
)/H
);
922 printf(" opengl: %s\n",gl_flag
?"yes":"no");
923 printf(" x-offset: %d\n",screen_offset
);
925 video
= SDL_SetVideoMode(W
,H
,32,flags
);
927 report_error("sdl: %s\n",SDL_GetError());
931 printf(" video on\n");
935 glBlendFunc(GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
);
937 glEnable( GL_TEXTURE_2D
);
938 glClearColor( 0.0f
, 0.0f
, 0.0f
, 0.0f
);
940 glViewport( 0, 0, W
, H
);
942 glClear( GL_COLOR_BUFFER_BIT
);
944 glMatrixMode( GL_PROJECTION
);
947 glOrtho(0.0f
, 240*aspect
, 240, 0.0f
, -1.0f
, 1.0f
);
950 glOrtho(0.0f
, 320, 240, 0.0f
, -1.0f
, 1.0f
);
953 glMatrixMode( GL_MODELVIEW
);
960 audio
.freq
= SAMPLE_RATE
;
961 audio
.format
= AUDIO_S16
;
963 audio
.samples
= BUFFER_SIZE
;
964 audio
.callback
= audio_callback
;
966 SDL_AudioSpec gotten
;
968 if(SDL_OpenAudio(&audio
, &gotten
)<0){
969 report_error("sdl: cannot open audio (%s)\n", SDL_GetError());
974 printf(" sample rate = %d\n",gotten
.freq
);
975 printf(" channels = %d\n",gotten
.channels
);
976 printf(" samples = %d\n",gotten
.samples
);
977 printf(" format = %d\n",gotten
.format
);
979 if(gotten
.format
!= AUDIO_S16
){
980 printf(" WARNING: audio format not AUDIO_S16 :(\n");
983 lout
= xmalloc(gotten
.samples
*2);
984 rout
= xmalloc(gotten
.samples
*2);
985 buffer_size
= gotten
.samples
;
987 printf(" sound on\n");
996 modes = SDL_ListModes(NULL, SDL_FULLSCREEN|SDL_HWSURFACE);
998 if (modes == (SDL_Rect**)0) {
999 printf("No modes available!\n");
1003 if (modes == (SDL_Rect**)-1) {
1004 printf("All resolutions available.\n");
1007 printf("Available Modes\n");
1008 for (i=0; modes[i]; ++i)
1009 printf(" %d x %d\n", modes[i]->w, modes[i]->h);