├── INSTALL.TXT
├── LICENCE.txt
├── Makefile
├── README.rst
├── SDL2
└── updatesdl.sh
├── assets
├── calvin.ttf
├── character.png
├── ground.png
├── heroic.ogg
├── map1.tmx
├── shot.png
├── splash.png
├── swish-2.ogg
├── swish.ogg
├── tiles.png
└── yoster.ttf
├── common.c
├── list.c
├── main.c
├── mxml
└── update.sh
├── sprite.c
└── tmx.c
/INSTALL.TXT:
--------------------------------------------------------------------------------
1 | Before compiling SDL2 it is necessary/better to have some dev libraries and headers installed:
2 |
3 | $ apt-get install libvorbis-dev libsmpeg-dev libasound2-dev libpulse-dev libpng-dev libfreetype6-dev autoconf
4 |
5 | Then
6 |
7 | $ cd SDL2
8 | $ ./updatesdl.sh
9 | $ cd ..
10 | $ cd mxml
11 | $ ./update.sh
12 |
13 | To test main.c
14 |
15 | $ make && ./glapp
16 |
17 |
--------------------------------------------------------------------------------
/LICENCE.txt:
--------------------------------------------------------------------------------
1 | Copyright (c) 2015, Batiste Bieler
2 | All rights reserved.
3 |
4 | Redistribution and use in source and binary forms, with or without
5 | modification, are permitted provided that the following conditions are met:
6 | * Redistributions of source code must retain the above copyright
7 | notice, this list of conditions and the following disclaimer.
8 | * Redistributions in binary form must reproduce the above copyright
9 | notice, this list of conditions and the following disclaimer in the
10 | documentation and/or other materials provided with the distribution.
11 | * The names of its contributors cannot be used to endorse or promote products
12 | derived from this software without specific prior written permission.
13 |
14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
15 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 | DISCLAIMED. IN NO EVENT SHALL BATISTE BIELER BE LIABLE FOR ANY
18 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
21 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
23 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | CFLAGS =
2 | SDLFLAGS = $(shell SDL2/sdl2-x86/bin/sdl2-config --libs --cflags) -lSDL2_image -lSDL2_ttf -lSDL2_mixer
3 | MXMLFLAGS = -L$(shell pwd)/mxml/mxml-bin/lib/ -Wl,-rpath,$(shell pwd)/mxml/mxml-bin/lib/ -I$(shell pwd)/mxml/mxml-bin/include/ -lmxml
4 | CC=gcc -Wall
5 |
6 | # -lXi -lXmu
7 |
8 | all: glbuild
9 |
10 | glbuild:
11 | $(CC) $(CFLAGS) -o glapp main.c $(SDLFLAGS) $(MXMLFLAGS)
12 |
13 | eglbuild:
14 | $(CC) $(CFLAGS) -o glapp main.c -lGLESv2 $(SDLFLAGS) $(MXMLFLAGS)
15 |
16 | debug:
17 | $(CC) $(CFLAGS) -o glapp main.c $(SDLFLAGS) $(MXMLFLAGS) -g -O0
18 |
19 | clean:
20 | rm glapp eglapp debugapp
21 |
--------------------------------------------------------------------------------
/README.rst:
--------------------------------------------------------------------------------
1 | ===============
2 | Game skeleton
3 | ===============
4 |
5 | This program can read and display TMX Map created with the Tiled editor.
6 |
7 | .. image:: https://raw.github.com/batiste/sdl2-game-loop/master/assets/shot.png
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/SDL2/updatesdl.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | prefixDir=`pwd`/sdl2-x86
4 |
5 | # ------------------------------ Functions Start ------------------------------
6 | function cloneSdlRepo {
7 | (hg clone http://hg.libsdl.org/$1 && cd $1 && hg co default && hg pull -u)
8 | }
9 |
10 | function pullAndBuildSdlRepo {
11 | echo "
12 | ------------------------------------------------------------
13 | Building $1
14 | ------------------------------------------------------------"
15 | sleep 1
16 | echo "Updating $1 from repo"
17 | cd $1
18 | hg co default
19 | hg pull -u
20 | ./autogen.sh
21 | #rm -rf build
22 | mkdir build
23 | cd build
24 | ../configure --prefix=$prefixDir || exit 1
25 | make || exit 1
26 | make install
27 | cd ../..
28 | echo "
29 | ------------------------------------------------------------
30 | Finished Building $1
31 | ------------------------------------------------------------"
32 | }
33 | # ------------------------------ Functions End ------------------------------
34 |
35 |
36 |
37 | # ------------------------------ Script Start ------------------------------
38 |
39 | echo "Performing update of sdl2
40 | "
41 | #echo -n "Removing current library..."
42 | #rm -rf sdl2-x86
43 | mkdir sdl2-x86
44 | #echo " done"
45 |
46 | if [ ! -e SDL ] # Just simply check for SDL since all other depend on it
47 | then
48 | echo "SDL Repo not found. Checking out all repositories"
49 | rm -rf SDL SDL_image SDL_mixer SDL_net SDL_ttf
50 | cloneSdlRepo "SDL" &
51 | cloneSdlRepo "SDL_image" &
52 | cloneSdlRepo "SDL_mixer" &
53 | cloneSdlRepo "SDL_ttf" &
54 | cloneSdlRepo "SDL_net"
55 | echo "
56 | # ------------------------------------------------------------
57 | # Waiting for Repo Checkout
58 | # ------------------------------------------------------------"
59 | wait $(jobs -p)
60 | echo "
61 | ------------------------------------------------------------
62 | Finished checking out repositories
63 | ------------------------------------------------------------"
64 | sleep 1
65 | fi
66 |
67 | # SDL BUILD
68 | pullAndBuildSdlRepo "SDL"
69 | export SDL_CONFIG=$prefixDir/bin/sdl2-config
70 | if [ ! -f $SDL_CONFIG ]
71 | then
72 | echo "Did not find sdl2-config"
73 | exit
74 | fi
75 |
76 | # Build the rest
77 | pullAndBuildSdlRepo "SDL_image"
78 | pullAndBuildSdlRepo "SDL_mixer"
79 | pullAndBuildSdlRepo "SDL_ttf"
80 | pullAndBuildSdlRepo "SDL_net"
81 |
82 |
83 | wait $(jobs -p)
84 | echo "
85 | ------------------------------------------------------------
86 | Finished Rebuild All Repositories!
87 | ------------------------------------------------------------"
88 |
--------------------------------------------------------------------------------
/assets/calvin.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/batiste/sdl2-game-loop/e19a0b2979fe4ccad0c27325e193082a3855f688/assets/calvin.ttf
--------------------------------------------------------------------------------
/assets/character.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/batiste/sdl2-game-loop/e19a0b2979fe4ccad0c27325e193082a3855f688/assets/character.png
--------------------------------------------------------------------------------
/assets/ground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/batiste/sdl2-game-loop/e19a0b2979fe4ccad0c27325e193082a3855f688/assets/ground.png
--------------------------------------------------------------------------------
/assets/heroic.ogg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/batiste/sdl2-game-loop/e19a0b2979fe4ccad0c27325e193082a3855f688/assets/heroic.ogg
--------------------------------------------------------------------------------
/assets/map1.tmx:
--------------------------------------------------------------------------------
1 |
2 |
5072 |
--------------------------------------------------------------------------------
/assets/shot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/batiste/sdl2-game-loop/e19a0b2979fe4ccad0c27325e193082a3855f688/assets/shot.png
--------------------------------------------------------------------------------
/assets/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/batiste/sdl2-game-loop/e19a0b2979fe4ccad0c27325e193082a3855f688/assets/splash.png
--------------------------------------------------------------------------------
/assets/swish-2.ogg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/batiste/sdl2-game-loop/e19a0b2979fe4ccad0c27325e193082a3855f688/assets/swish-2.ogg
--------------------------------------------------------------------------------
/assets/swish.ogg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/batiste/sdl2-game-loop/e19a0b2979fe4ccad0c27325e193082a3855f688/assets/swish.ogg
--------------------------------------------------------------------------------
/assets/tiles.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/batiste/sdl2-game-loop/e19a0b2979fe4ccad0c27325e193082a3855f688/assets/tiles.png
--------------------------------------------------------------------------------
/assets/yoster.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/batiste/sdl2-game-loop/e19a0b2979fe4ccad0c27325e193082a3855f688/assets/yoster.ttf
--------------------------------------------------------------------------------
/common.c:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (C) 2013 batiste.bieler@gmail.com
3 |
4 | Common function and globals,
5 | Abstract away what is not central to the game logic
6 | */
7 |
8 | #ifndef GAME_LOOP_COMMON
9 | #define GAME_LOOP_COMMON 1
10 |
11 | #include
12 | #include
13 | #include
14 | #include
15 |
16 | #include "list.c"
17 |
18 | #include "SDL.h"
19 | #include "SDL_image.h"
20 | #include "SDL_ttf.h"
21 | #include "SDL_audio.h"
22 | #include "SDL_mixer.h"
23 | #define TICK_INTERVAL 20
24 |
25 | // this seems necessary to do this: SDL_Texture->w
26 | // use SDL_QueryTexture(img, NULL, NULL, &w, &h); to get the size
27 | // #include "SDL2/SDL/src/render/SDL_sysrender.h"
28 |
29 | #define MIN(a,b) (((a)<(b))?(a):(b))
30 | #define MAX(a,b) (((a)>(b))?(a):(b))
31 |
32 |
33 | // globals
34 | SDL_Window * window = NULL;
35 | SDL_Renderer * renderer = NULL;
36 | SDL_DisplayMode displaymode;
37 | SDL_Rect viewport;
38 | int channels[4] = {0, 0, 0, 0};
39 |
40 | GenericList * texturesList;
41 | GenericList * musicList;
42 | GenericList * fontList;
43 |
44 | SDL_Color black;
45 | SDL_Color white;
46 |
47 | // 0: full FPS, 1: cap the framerate
48 | int draw_mode = 1;
49 | static Uint32 next_time;
50 |
51 |
52 | inline int mod(a, b) {
53 | int c = a % b;
54 | return (c < 0) ? c + b : c;
55 | }
56 |
57 | Uint32
58 | timeLeft(void) {
59 | Uint32 now;
60 | now = SDL_GetTicks();
61 | if(next_time <= now)
62 | return 0;
63 | else
64 | return next_time - now;
65 | }
66 |
67 | void
68 | capFramerate(void) {
69 | SDL_Delay(timeLeft());
70 | next_time += TICK_INTERVAL;
71 | }
72 |
73 | // Call this instead of exit(), so we can clean up SDL
74 | static void
75 | quit(int rc) {
76 |
77 | printf("Cleanup\n");
78 |
79 | ListElement *el;
80 |
81 | for(el = texturesList->first; el != NULL; el=el->next) {
82 | printf("Destroy texture\n");
83 | SDL_DestroyTexture((SDL_Texture *)el->data);
84 | }
85 | destroyList(texturesList);
86 |
87 | for(el = musicList->first; el != NULL; el=el->next) {
88 | printf("Destroy music\n");
89 | Mix_FreeMusic((Mix_Music *)el->data);
90 | }
91 | destroyList(musicList);
92 |
93 | for(el = fontList->first; el != NULL; el=el->next) {
94 | printf("Destroy font\n");
95 | TTF_CloseFont((TTF_Font *)el->data);
96 | }
97 | destroyList(fontList);
98 |
99 | if(renderer) {
100 | SDL_DestroyRenderer(renderer);
101 | //printf("%s\n", SDL_GetError());
102 | }
103 | if(window) {
104 | SDL_DestroyWindow(window);
105 | //printf("%s\n", SDL_GetError());
106 | }
107 | Mix_CloseAudio();
108 | SDL_Quit();
109 | printf("Bye!\n");
110 | exit(0);
111 | }
112 |
113 |
114 |
115 | void init(void) {
116 |
117 | texturesList = createList();
118 | musicList = createList();
119 | fontList = createList();
120 | black.r = 0; black.g = 0; black.b = 0;
121 | white.r = 255; white.g = 255; white.b = 255;
122 |
123 | // Initialize SDL2
124 | if( SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) < 0) {
125 | fprintf(stderr, "Unable to initialize SDL: %s \n", SDL_GetError());
126 | quit(1);
127 | }
128 |
129 | // Display available audio device
130 | int count = SDL_GetNumAudioDevices(0), i;
131 | for (i = 0; i < count; ++i ) {
132 | fprintf(stderr, "Audio device %d: %s\n", i, SDL_GetAudioDeviceName(i, 0));
133 | }
134 |
135 | // init sound
136 | int audio_rate = 22050;
137 | Uint16 audio_format = AUDIO_S16SYS;
138 | int nb_audio_channels = 4;
139 | int audio_buffers = 4096;
140 |
141 | if(Mix_OpenAudio(audio_rate, audio_format, nb_audio_channels, audio_buffers) != 0) {
142 | fprintf(stderr, "Unable to initialize audio: %s\n", Mix_GetError());
143 | quit(1);
144 | }
145 |
146 | // Get desktop information
147 | if (SDL_GetDesktopDisplayMode(0, &displaymode) < 0) {
148 | fprintf(stderr, "Could not get display mode: %s\n", SDL_GetError());
149 | quit(1);
150 | }
151 |
152 | viewport.x = 0;
153 | viewport.y = 0;
154 | viewport.w = MIN(displaymode.w, 800);
155 | viewport.h = MIN(displaymode.h, 600);
156 |
157 | // Create an application window with the following settings:
158 | window = SDL_CreateWindow(
159 | "Game example", // window title
160 | SDL_WINDOWPOS_UNDEFINED, // initial x destination
161 | SDL_WINDOWPOS_UNDEFINED, // initial y destination
162 | viewport.w, // width, in pixels
163 | viewport.h, // height, in pixels
164 | SDL_WINDOW_SHOWN // flags
165 | );
166 |
167 | // Check that the window was successfully made
168 | if(window==NULL){
169 | // In the event that the window could not be made...
170 | fprintf(stderr, "Could not create window: %s\n", SDL_GetError());
171 | quit(1);
172 | }
173 |
174 | renderer = SDL_CreateRenderer(window, -1, 0); // SDL_RENDERER_PRESENTVSYNC
175 | if (renderer < 0) {
176 | fprintf(stderr, "Could not create renderer: %s\n", SDL_GetError());
177 | quit(1);
178 | }
179 |
180 | SDL_RenderGetViewport(renderer, &viewport);
181 |
182 | if (TTF_Init() == -1) {
183 | fprintf(stderr, "Unable to initialize SDL_ttf: %s \n", TTF_GetError());
184 | quit(1);
185 | }
186 |
187 | }
188 |
189 |
190 | SDL_Texture * renderFontToTexture(TTF_Font * font, char * text) {
191 | // Create a text texture with a shadow effect
192 | SDL_Surface * textb = TTF_RenderText_Solid(font, text, black);
193 | SDL_Surface * textw = TTF_RenderText_Solid(font, text, white);
194 |
195 | /* Create a 32-bit surface with the bytes of each pixel in R,G,B,A order,
196 | as expected by OpenGL for textures */
197 | SDL_Surface *surface;
198 | Uint32 rmask, gmask, bmask, amask;
199 |
200 | /* SDL interprets each pixel as a 32-bit number, so our masks must depend
201 | on the endianness (byte order) of the machine */
202 | #if SDL_BYTEORDER == SDL_BIG_ENDIAN
203 | rmask = 0xff000000;
204 | gmask = 0x00ff0000;
205 | bmask = 0x0000ff00;
206 | amask = 0x000000ff;
207 | #else
208 | rmask = 0x000000ff;
209 | gmask = 0x0000ff00;
210 | bmask = 0x00ff0000;
211 | amask = 0xff000000;
212 | #endif
213 |
214 | // with amask = 0, I see the image, with amask = 0xff000000, I see nothing
215 | surface = SDL_CreateRGBSurface(0, textw->w + 8, textw->h + 8, 32,
216 | rmask, gmask, bmask, amask);
217 |
218 | SDL_Rect text_rect;
219 | text_rect.x = 2;
220 | text_rect.y = 1;
221 | text_rect.w = textw->w;
222 | text_rect.h = textw->h;
223 |
224 | SDL_BlitSurface(textw, NULL, surface, &text_rect);
225 | text_rect.x = 0;
226 | text_rect.y = 0;
227 | SDL_BlitSurface(textb, NULL, surface, &text_rect);
228 |
229 | SDL_Texture * texture = SDL_CreateTextureFromSurface(renderer, surface);
230 |
231 | // This important to free the surface to avoid leaks
232 | SDL_FreeSurface(textw);
233 | SDL_FreeSurface(textb);
234 | SDL_FreeSurface(surface);
235 | return texture;
236 | }
237 |
238 |
239 |
240 | // Helper fonction to load assets
241 |
242 | SDL_Texture * getTexture(char * filename) {
243 | SDL_Texture * texture = IMG_LoadTexture(renderer, filename);
244 | if (texture == NULL) {
245 | fprintf(stderr, "Couldn't load %s: %s\n", filename, SDL_GetError());
246 | quit(1);
247 | }
248 | addToList(texturesList, texture);
249 | return texture;
250 | }
251 |
252 | Mix_Music * getMusic(char * filename) {
253 | Mix_Music * music = Mix_LoadMUS(filename);
254 | if(music == NULL) {
255 | fprintf(stderr, "Unable to load sound file: %s\n", Mix_GetError());
256 | quit(1);
257 | }
258 | addToList(musicList, music);
259 | return music;
260 | }
261 |
262 | TTF_Font * getFont(char * filename, int size) {
263 | TTF_Font * font = TTF_OpenFont(filename, size);
264 | if(font == NULL) {
265 | fprintf(stderr, "Unable to load ttf file: %s\n", SDL_GetError());
266 | quit(1);
267 | }
268 | addToList(fontList, font);
269 | return font;
270 | }
271 |
272 |
273 |
274 |
275 | #endif
276 |
--------------------------------------------------------------------------------
/list.c:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (C) 2013 batiste.bieler@gmail.com
3 |
4 | Generic double linked list implementation
5 | */
6 | #ifndef LINKED_LIST
7 | #define LINKED_LIST 1
8 |
9 | #include
10 | #include
11 |
12 | void assert(int value) {
13 | if(value)
14 | return;
15 | printf("List assert fail, quick exit\n");
16 | exit(1);
17 | }
18 |
19 | //Generic list Element
20 | struct ListElement {
21 | struct ListElement *next;
22 | struct ListElement *prev;
23 | int refcount;
24 | void *data;
25 | };
26 | typedef struct ListElement ListElement;
27 |
28 | //Generic List Structure
29 | struct GenericList {
30 | int length; //Number of elements in list
31 | struct ListElement *first; //Ptr to first element in list
32 | struct ListElement *last; //Ptr to last element in list
33 | };
34 | typedef struct GenericList GenericList;
35 |
36 | void initList(GenericList *list) {
37 | list->length = 0;
38 | list->first = NULL;
39 | list->last = NULL;
40 | }
41 |
42 | GenericList * createList() {
43 | GenericList * list = (GenericList *)malloc(sizeof(GenericList));
44 | initList(list);
45 | return list;
46 | }
47 |
48 | ListElement *
49 | getFromList(GenericList *list, int n) {
50 | assert(list!=NULL);
51 | ListElement *el = NULL;
52 | int i = 0;
53 | for(el = list->first; el != NULL; el=el->next) {
54 | if(i==n) {
55 | return el;
56 | }
57 | i = i + 1;
58 | }
59 | // last will be returned
60 | return el;
61 | }
62 |
63 | ListElement *
64 | addToList(GenericList *list, void *item) {
65 | //check inputs
66 | assert(item!=NULL);
67 | assert(list!=NULL);
68 | //Create generic element to hold item ptr
69 | ListElement *newElement = (ListElement *)malloc(sizeof(ListElement));
70 | assert(newElement != NULL);
71 | newElement->refcount = 1;
72 | list->length = list->length + 1;
73 | newElement->data = item;
74 | if (list->length == 1)
75 | {
76 | list->first = newElement;
77 | list->last = newElement;
78 | newElement->prev = NULL;
79 | newElement->next = NULL;
80 | }
81 | else
82 | {
83 | newElement->prev = list->last;
84 | newElement->next = NULL;
85 | list->last->next = newElement;
86 | list->last = newElement;
87 | }
88 | return newElement;
89 | }
90 |
91 | int
92 | removeFromList(GenericList *list, ListElement *toRemove) {
93 | // TODO: find a mechanisms to free deleted items
94 |
95 | //check inputs
96 | if(toRemove==NULL) {
97 | return 0;
98 | }
99 | assert(list!=NULL);
100 | ListElement *el;
101 | if (list->length == 0) {
102 | return 0;
103 | }
104 |
105 | if (list->length == 1) {
106 | if(toRemove == list->first) {
107 | list->length = 0;
108 | list->first = NULL;
109 | list->last = NULL;
110 | return 1;
111 | }
112 | return 0;
113 | }
114 |
115 | // there is at least 2 items in the list
116 | for(el = list->first; el != NULL; el=el->next) {
117 | // found a matching item
118 | if(el == toRemove) {
119 | // this is the first item
120 | if(el == list->first) {
121 | list->first = el->next;
122 | list->first->prev = NULL;
123 | // this is the last item
124 | } else if (el == list->last) {
125 | list->last = el->prev;
126 | list->last->next = NULL;
127 | } else {
128 | el->prev->next = el->next;
129 | el->next->prev = el->prev;
130 | }
131 | list->length = list->length - 1;
132 | return 1;
133 | }
134 | }
135 | return 0;
136 | }
137 |
138 | int
139 | emptyList(GenericList *list) {
140 |
141 | assert(list!=NULL);
142 | ListElement *el;
143 | ListElement *el2;
144 |
145 | for(el = list->first; el != NULL; el = el2) {
146 | el2 = el->next;
147 | free(el);
148 | }
149 |
150 | initList(list);
151 | return 0;
152 | }
153 |
154 | int
155 | destroyList(GenericList *list) {
156 | emptyList(list);
157 | free(list);
158 | return 0;
159 | }
160 |
161 | void
162 | displayList(GenericList *list) {
163 | ListElement *el;
164 | printf("List length %d\n", list->length);
165 | int i = 1;
166 | for(el = list->first; el != NULL; el=el->next, i=i+1) {
167 | printf("Item %d address %p\n", i, el->data);
168 | }
169 | }
170 |
171 | #endif
172 |
--------------------------------------------------------------------------------
/main.c:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (C) 2013 batiste.bieler@gmail.com
3 |
4 | SDL game loop
5 | */
6 |
7 | #include "common.c"
8 | #include "sprite.c"
9 | #include "tmx.c"
10 |
11 | // Keyboard variables and functions
12 |
13 | int wasd[4] = {0, 0, 0, 0};
14 | int controls[1] = {0};
15 |
16 | void handleKeyboard(int key, int down_or_up) {
17 |
18 | // down
19 | if(down_or_up) {
20 | switch(key)
21 | {
22 | case SDLK_c:
23 | if(draw_mode == 1) {
24 | draw_mode = 0;
25 | } else {
26 | draw_mode = 1;
27 | }
28 | break;
29 | }
30 | }
31 |
32 | // down and up
33 | switch(key)
34 | {
35 | case SDLK_w:
36 | wasd[0] = down_or_up;
37 | break;
38 | case SDLK_a:
39 | wasd[1] = down_or_up;
40 | break;
41 | case SDLK_s:
42 | wasd[2] = down_or_up;
43 | break;
44 | case SDLK_d:
45 | wasd[3] = down_or_up;
46 | break;
47 | case SDLK_SPACE:
48 | controls[0] = down_or_up;
49 | break;
50 | }
51 | //printf("Keyboard event wasd %d, %d, %d, %d\n", wasd[0], wasd[1], wasd[2], wasd[3]);
52 | }
53 |
54 | void showSplashScreen(void) {
55 |
56 | SDL_Rect rect;
57 | SDL_Texture * splashTexture = getTexture("assets/splash.png");
58 | int w, h;
59 | SDL_QueryTexture(splashTexture, NULL, NULL, &w, &h);
60 | rect.w = w;
61 | rect.h = h;
62 | rect.x = viewport.w / 2 - w / 2;
63 | rect.y = viewport.h / 2 - h / 2;
64 |
65 | SDL_RendererInfo info;
66 | SDL_GetRendererInfo(renderer, &info);
67 |
68 | SDL_Delay(100);
69 | int alpha = 1;
70 | while(alpha < 255) {
71 | if(SDL_SetTextureAlphaMod(splashTexture, alpha) != 0) {
72 | quit(1);
73 | }
74 |
75 | SDL_RenderClear(renderer);
76 | SDL_RenderCopy(renderer, splashTexture, NULL, &rect);
77 | SDL_RenderPresent(renderer);
78 |
79 | SDL_Delay(TICK_INTERVAL);
80 | alpha = alpha + 6;
81 | }
82 | }
83 |
84 | int hasCollision(TmxMap * map, int x, int y) {
85 | int i, j;
86 | for(i=0; inumObjectGroups; i++) {
87 | TmxObjectGroup * group = &map->objectGroups[i];
88 | //printf("%s\n", group->name);
89 | if(strcmp(group->name, "collisions") == 0) {
90 | for(j=0; jnumObjects; j++) {
91 | TmxObject object = group->objects[j];
92 | // shorcuts
93 | if(x >= object.x && y >= object.y && x <= object.xw && y <= object.yw) {
94 | //printf("collision\n");
95 | //quit(1);
96 | return 1;
97 | }
98 | }
99 | }
100 | }
101 | return 0;
102 | }
103 |
104 |
105 | int
106 | main(int argc, char *argv[])
107 | {
108 |
109 | int i, j, k, done;
110 | SDL_Event event;
111 |
112 | init();
113 |
114 | SDL_SetRenderDrawColor(renderer, 0xff, 0xff, 0xff, 0xff);
115 | SDL_RenderClear(renderer);
116 | SDL_RenderPresent(renderer);
117 |
118 | // Load assets
119 | // Mix_Music * music = getMusic("assets/heroic.ogg");
120 | // Mix_Music * swish = getMusic("assets/swish.ogg");
121 | Mix_Chunk * chunk = Mix_LoadWAV("assets/swish-2.ogg");
122 | TTF_Font * font = getFont("assets/yoster.ttf", 26);
123 | SDL_Texture * groundTexture = getTexture("assets/ground.png");
124 | SDL_Texture * characterTexture = getTexture("assets/character.png");
125 |
126 | TmxMap * map = TMX_LoadFile("assets/map1.tmx");
127 |
128 | SDL_Texture ** texturestable = malloc(map->numTilesets * sizeof(SDL_Texture *));
129 | Sprite * sprites = malloc((map->numTiles + 1) * sizeof(Sprite));
130 | for(i=0; inumTilesets; i++) {
131 | TmxTileset * set = &map->tilesets[i];
132 | char str[80];
133 | strcpy(str, "assets/");
134 | strcat(str, set->source);
135 | k = set->firstgid;
136 | texturestable[i] = getTexture(str);
137 | for(j=0; jnumTiles; j++) {
138 | Sprite * sp = &sprites[k];
139 | sp->source.w = sp->destination.w = set->tilewidth;
140 | sp->source.h = sp->destination.h = set->tileheight;
141 | sp->destination.x = sp->destination.y = 0;
142 | sp->texture = texturestable[i];
143 | sp->source.x = (j * set->tilewidth) % set->width;
144 | sp->source.y = set->tileheight * ((j * set->tilewidth) / set->width);
145 | k++;
146 | }
147 | }
148 |
149 | // a simple channel_finished function
150 | void channelDone(int channelNum) {
151 | printf("Channel %d finished\n", channelNum);
152 | channels[channelNum] = 0;
153 | }
154 | Mix_ChannelFinished(channelDone);
155 |
156 | //quit(1);
157 |
158 | /*Mix_PlayMusic(music, -1);
159 | if(Mix_PlayMusic(music, -1)) {
160 | fprintf(stderr, "Unable to play ogg file: %s\n", Mix_GetError());
161 | quit(1);
162 | }*/
163 |
164 | // Table of sprites, ready to use
165 | SpriteTable * groundTable = splitTextureTable(groundTexture, 48, 48);
166 | // SpriteTable * characterTable = splitTextureTable(characterTexture, 48, 48);
167 |
168 | // Animations of the character
169 | SDL_Rect rect;
170 | rect.x = 0;
171 | rect.y = 0;
172 | rect.w = 48;
173 | rect.h = 48;
174 |
175 | // Stand up
176 | Animation * stand = createAnimation(characterTexture, &rect, 4, 1);
177 |
178 | // Move
179 | Animation * goDown = createAnimation(characterTexture, &rect, 4, 4);
180 | rect.y = 48;
181 | Animation * goRight = createAnimation(characterTexture, &rect, 4, 4);
182 | rect.y = 2 * 48;
183 | Animation * goUp = createAnimation(characterTexture, &rect, 4, 4);
184 | rect.y = 3 * 48;
185 | Animation * goLeft = createAnimation(characterTexture, &rect, 4, 4);
186 |
187 | // Sword
188 | rect.y = 4 * 48;
189 | Animation * swordRight = createAnimation(characterTexture, &rect, 2, 6);
190 | rect.y = 5 * 48;
191 | Animation * swordLeft = createAnimation(characterTexture, &rect, 2, 6);
192 |
193 | // All sorts of variable for the game loop
194 | done = 0;
195 |
196 | // the current sprite respresenting the character
197 | Sprite * characterSprite = getSpriteFromAnimation(goUp, 0);
198 |
199 | int scroll_x = 0, scroll_y = 0;
200 |
201 | SDL_Texture * text_texture1 = NULL;
202 |
203 | // number of the current frame
204 | int frameNum = SDL_GetTicks() / TICK_INTERVAL;
205 | // amount of rendered frames
206 | int renderedFrames = 0;
207 |
208 | // desired frames by second
209 | int framesBySecond = 1000 / TICK_INTERVAL;
210 |
211 | // indicate if the current frame is a "real" frame
212 | int physical_frame = 1;
213 |
214 | printf("Desired fps %d\n", framesBySecond);
215 | printf("Start the game loop\n");
216 |
217 | SDL_Delay(50);
218 | showSplashScreen();
219 | SDL_Delay(1000);
220 | SDL_SetRenderDrawColor(renderer, 0x70, 0xc8, 0x40, 0xff);
221 |
222 | int charx = viewport.w / 2;
223 | int chary = viewport.h / 2;
224 |
225 | // The game loop
226 | while (!done) {
227 |
228 | // slow down the physical stuff by being sure it runs
229 | // only once every TICK_INTERVAL, or physical frame
230 | if(SDL_GetTicks() / TICK_INTERVAL > frameNum) {
231 | frameNum = SDL_GetTicks() / TICK_INTERVAL;
232 | physical_frame = 1;
233 | } else {
234 | // no physical simulation should happen in this frame
235 | physical_frame = 0;
236 | }
237 |
238 | // ---- Physic and events
239 |
240 | // this is a "real" frame where we responde to events and apply physic
241 | if(physical_frame) {
242 |
243 | // Check for events
244 | while (SDL_PollEvent(&event)) {
245 | // printf("Event type: %d\n", event.type);
246 | if (event.type == SDL_QUIT || event.type == SDL_WINDOWEVENT_CLOSE) {
247 | done = 1;
248 | }
249 |
250 | if (event.type == SDL_KEYDOWN) {
251 | handleKeyboard(event.key.keysym.sym, 1);
252 | }
253 |
254 | if (event.type == SDL_KEYUP) {
255 | handleKeyboard(event.key.keysym.sym, 0);
256 | }
257 | }
258 |
259 | // apply events to the world
260 | int speed = 5;
261 | if(wasd[0] && hasCollision(map, charx+24, chary - speed+40) == 0) {
262 | chary = chary - speed;
263 | scroll_y = scroll_y + speed;
264 | }
265 | if(wasd[1] && hasCollision(map, charx+24 -speed, chary+40) == 0) {
266 | charx = charx - speed;
267 | scroll_x = scroll_x + speed;
268 | }
269 | if(wasd[2] && hasCollision(map, charx+24, chary + speed+40) == 0) {
270 | chary = chary + speed;
271 | scroll_y = scroll_y - speed;
272 | }
273 | if(wasd[3] && hasCollision(map, charx+24 + speed, chary+40) == 0) {
274 | charx = charx + speed;
275 | scroll_x = scroll_x - speed;
276 | }
277 |
278 | }
279 |
280 |
281 | // ---- Graphic rendering
282 |
283 | // this is not free
284 | SDL_RenderClear(renderer);
285 |
286 | // rendering the grid
287 | for(i=0; inumLayers; i++) {
288 | TmxLayer * layer = &map->layers[i];
289 | for(j=0; jnumTiles; j++) {
290 | int gid = layer->tiles[j];
291 | if(gid > 0) {
292 | int x = (j % map->width) * map->tilewidth + scroll_x;
293 | int y = (j / map->width) * map->tileheight + scroll_y;
294 | drawSpriteAt(renderer, &sprites[gid], x, y);
295 | }
296 | }
297 | }
298 |
299 | // render the character
300 | characterSprite = getSpriteFromAnimation(stand, frameNum);
301 |
302 | if(wasd[0]) {
303 | characterSprite = getSpriteFromAnimation(goUp, frameNum);
304 | }
305 | if(wasd[1]) {
306 | characterSprite = getSpriteFromAnimation(goLeft, frameNum);
307 | }
308 | if(wasd[2]) {
309 | characterSprite = getSpriteFromAnimation(goDown, frameNum);
310 | }
311 | if(wasd[3]) {
312 | characterSprite = getSpriteFromAnimation(goRight, frameNum);
313 | }
314 |
315 | if(controls[0]) {
316 | characterSprite = getSpriteFromAnimation(swordRight, frameNum);
317 | if(wasd[3])
318 | characterSprite = getSpriteFromAnimation(swordRight, frameNum);
319 | if(wasd[1])
320 | characterSprite = getSpriteFromAnimation(swordLeft, frameNum);
321 |
322 |
323 | if( !Mix_Playing(0) && Mix_PlayChannel( 0, chunk, 0 ) == -1 ) {
324 | fprintf(stderr, "Unable to play WAV file: %s\n", Mix_GetError());
325 | }
326 |
327 | }
328 |
329 | drawSpriteAt(renderer, characterSprite, charx + scroll_x, chary + scroll_y);
330 |
331 |
332 | // do this every second on a physical frame
333 | if(frameNum % framesBySecond == 0 && physical_frame) {
334 |
335 | if(text_texture1) {
336 | SDL_DestroyTexture(text_texture1);
337 | }
338 |
339 | char buffer[50];
340 | if(draw_mode == 1) {
341 | sprintf(buffer, "Press c to maximize FPS. Current FPS: %d", renderedFrames);
342 | } else {
343 | sprintf(buffer, "Press c to cap to 50FPS. Current FPS: %d", renderedFrames);
344 | }
345 |
346 | text_texture1 = renderFontToTexture(font, buffer);
347 |
348 | renderedFrames = 0;
349 | }
350 |
351 | if(text_texture1) {
352 | SDL_Rect text_rect;
353 | text_rect.x = 15;
354 | text_rect.y = 10;
355 | SDL_QueryTexture(text_texture1, NULL, NULL, &text_rect.w, &text_rect.h);
356 | SDL_RenderCopy(renderer, text_texture1, NULL, &text_rect);
357 | }
358 |
359 | // Update the screen
360 | SDL_RenderPresent(renderer);
361 |
362 | // Cap to ~ 50 fps
363 | if(draw_mode == 1) {
364 | capFramerate();
365 | }
366 |
367 | renderedFrames++;
368 |
369 | }
370 |
371 | // cleanup
372 | // TODO: free the structure that need to be
373 |
374 | // seems to create more problems with valgrind
375 | destroyAnimation(stand);
376 | destroyAnimation(goUp);
377 | destroyAnimation(goDown);
378 | destroyAnimation(goLeft);
379 | destroyAnimation(goRight);
380 | destroyAnimation(swordRight);
381 | destroyAnimation(swordLeft);
382 | destroySpriteTable(groundTable);
383 | SDL_DestroyTexture(text_texture1);
384 | free(sprites);
385 | free(texturestable);
386 |
387 | quit(0);
388 |
389 | // to prevent compiler warning
390 | return 0;
391 | }
392 |
393 |
--------------------------------------------------------------------------------
/mxml/update.sh:
--------------------------------------------------------------------------------
1 | svn checkout http://svn.msweet.org/mxml/trunk/
2 | cd trunk
3 | ./configure --prefix=`pwd`/../mxml-bin
4 | make
5 | make install
6 |
--------------------------------------------------------------------------------
/sprite.c:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (C) 2013 batiste.bieler@gmail.com
3 |
4 | Sprite functions
5 | */
6 |
7 | #include "common.c"
8 |
9 | struct Sprite {
10 | SDL_Texture * texture;
11 | struct SDL_Rect source;
12 | struct SDL_Rect destination;
13 | };
14 | typedef struct Sprite Sprite;
15 |
16 | struct SpriteTable {
17 | // a table of pointer of sprite
18 | Sprite ** table;
19 | int length;
20 | };
21 | typedef struct SpriteTable SpriteTable;
22 |
23 | struct Animation {
24 | // a table of sprites used for animation
25 | SpriteTable * sprites;
26 | //Uint32 startTick;
27 | //Uint32 currentTick;
28 | int ticksByFrame;
29 | int duration;
30 | };
31 | typedef struct Animation Animation;
32 |
33 | struct AnimationInstance {
34 | Animation * animation;
35 | int startFrame;
36 | int currentTick;
37 | };
38 |
39 | Sprite *
40 | createSprite(SDL_Texture * texture, int w, int h) {
41 | Sprite * sp = (Sprite *)malloc(sizeof(Sprite));
42 | sp->texture = texture;
43 | sp->source.x = 0;
44 | sp->source.y = 0;
45 | sp->source.w = w;
46 | sp->source.h = h;
47 |
48 | sp->destination.x = 0;
49 | sp->destination.y = 0;
50 | sp->destination.w = w;
51 | sp->destination.h = h;
52 | return sp;
53 | }
54 |
55 | Animation * createAnimation(SDL_Texture * texture, SDL_Rect * sprites_start, int ticksByFrame, int numberSprite) {
56 |
57 | Sprite * sprite;
58 | int j, w, h;
59 | SDL_QueryTexture(texture, NULL, NULL, &w, &h);
60 | int columns = (w - sprites_start->x) / sprites_start->w;
61 | if(numberSprite != 0) {
62 | columns = MIN(numberSprite, columns);
63 | }
64 |
65 | Sprite ** table = (Sprite **) malloc(columns * sizeof(Sprite *));
66 |
67 | for(j=0; jw, sprites_start->h);
69 | sprite->source.x = j * sprites_start->w + sprites_start->x;
70 | sprite->source.y = sprites_start->y;
71 | table[j] = sprite;
72 | }
73 |
74 | SpriteTable * spritetable = (SpriteTable *) malloc(sizeof(SpriteTable));
75 | spritetable->table = table;
76 | spritetable->length = columns;
77 |
78 | Animation * anim = (Animation *) malloc(sizeof(Animation));
79 | anim->sprites = spritetable;
80 | anim->ticksByFrame = ticksByFrame;
81 | anim->duration = ticksByFrame * numberSprite;
82 |
83 | //anim->startTick = 0;
84 | //anim->currentTick = 0;
85 |
86 | return anim;
87 | }
88 |
89 | void destroyAnimation(Animation * anim) {
90 | free(anim->sprites->table);
91 | free(anim->sprites);
92 | free(anim);
93 | }
94 |
95 | Sprite *
96 | getSpriteFromAnimation(Animation * anim, int frame) {
97 | int spriteIndex = (frame / anim->ticksByFrame) % anim->sprites->length;
98 | return anim->sprites->table[spriteIndex];
99 | }
100 |
101 | void
102 | drawSprite(SDL_Renderer * renderer, Sprite * sp) {
103 | SDL_RenderCopy(renderer, sp->texture, &sp->source, &sp->destination);
104 | }
105 |
106 | void
107 | drawSpriteAt(SDL_Renderer * renderer, Sprite * sp, int x, int y) {
108 | SDL_Rect _rect;
109 | _rect.x = x;
110 | _rect.y = y;
111 | _rect.w = sp->destination.w;
112 | _rect.h = sp->destination.h;
113 | SDL_RenderCopy(renderer, sp->texture, &sp->source, &_rect);
114 | }
115 |
116 | SpriteTable *
117 | splitTextureTable(SDL_Texture * texture, int w, int h) {
118 | Sprite * sprite;
119 | int i, j, tex_w, tex_h;
120 | SDL_QueryTexture(texture, NULL, NULL, &tex_w, &tex_h);
121 | int columns = tex_w / w;
122 | int lines = tex_h / h;
123 |
124 | Sprite ** table = (Sprite **) malloc(columns * lines * sizeof(Sprite *));
125 |
126 | printf("Texture has lines %d and columns %d\n", lines, columns);
127 |
128 | for(i=0; isource.x = j * w;
132 | sprite->source.y = i * h;
133 | table[i * columns + j] = sprite;
134 | }
135 | }
136 |
137 | SpriteTable * spritetable = (SpriteTable *) malloc(sizeof(SpriteTable));
138 | spritetable->table = table;
139 | spritetable->length = lines * columns;
140 |
141 | return spritetable;
142 | }
143 |
144 | void destroySpriteTable(SpriteTable * table) {
145 | free(table->table);
146 | free(table);
147 | }
148 |
149 |
150 |
--------------------------------------------------------------------------------
/tmx.c:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (C) 2013 batiste.bieler@gmail.com
3 |
4 | TMX map reader in C using mxml
5 | */
6 |
7 | #include "mxml.h"
8 | #include "string.h"
9 | #include
10 | #ifndef WIN32
11 | # include
12 | #endif /* !WIN32 */
13 | #include
14 | #ifndef O_BINARY
15 | # define O_BINARY 0
16 | #endif /* !O_BINARY */
17 |
18 | // TMX Format documentation : https://github.com/bjorn/tiled/wiki/TMX-Map-Format
19 |
20 | struct TmxTileset {
21 | int tilewidth;
22 | int tileheight;
23 | char name[50];
24 | int firstgid;
25 | char source[50];
26 | int width;
27 | int height;
28 | int numTiles;
29 | int spacing;
30 | int margin;
31 | };
32 | typedef struct TmxTileset TmxTileset;
33 |
34 | struct TmxLayer {
35 | int width;
36 | int height;
37 | int numTiles;
38 | int * tiles;
39 | char name[50];
40 | };
41 | typedef struct TmxLayer TmxLayer;
42 |
43 | struct TmxProperty {
44 | char * name;
45 | char * value;
46 | };
47 | typedef struct TmxProperty TmxProperty;
48 |
49 | struct TmxObject {
50 | int width;
51 | int height;
52 | int x;
53 | int y;
54 | int xw;
55 | int yw;
56 | int numProperties;
57 | TmxProperty * properties;
58 | };
59 | typedef struct TmxObject TmxObject;
60 |
61 | struct TmxObjectGroup {
62 | int width;
63 | int height;
64 | int numObjects;
65 | TmxObject * objects;
66 | char name[50];
67 | };
68 | typedef struct TmxObjectGroup TmxObjectGroup;
69 |
70 | struct TmxMap {
71 | int width;
72 | int height;
73 | int tilewidth;
74 | int tileheight;
75 | // "orthogonal", "isometric" and "staggered"
76 | char orientation[15];
77 |
78 | TmxTileset * tilesets;
79 | int numTilesets;
80 |
81 | TmxObjectGroup * objectGroups;
82 | int numObjectGroups;
83 |
84 | TmxLayer * layers;
85 | int numLayers;
86 |
87 | int numTiles;
88 | };
89 | typedef struct TmxMap TmxMap;
90 |
91 | /*TmxTileset * createTileset(mxml_node_t * node) {
92 |
93 | }*/
94 |
95 |
96 | // mxmlLoadString
97 | TmxMap * TMX_LoadFile(char * filename) {
98 | FILE *fp;
99 | mxml_node_t * tree;
100 |
101 | fp = fopen(filename, "r");
102 | tree = mxmlLoadFile(NULL, fp, MXML_TEXT_CALLBACK);
103 | fclose(fp);
104 |
105 | mxml_node_t * node;
106 | mxml_node_t * mapNode;
107 |
108 | /* Find the first "map" element */
109 | mapNode = mxmlFindElement(tree, tree, "map",
110 | NULL, NULL,
111 | MXML_DESCEND);
112 |
113 |
114 |
115 | // create and fillup the map
116 | TmxMap * map = malloc(sizeof(TmxMap));
117 | map->width = atoi(mxmlElementGetAttr(mapNode, "width"));
118 | map->height = atoi(mxmlElementGetAttr(mapNode, "height"));
119 | map->tilewidth = atoi(mxmlElementGetAttr(mapNode, "tilewidth"));
120 | map->tileheight = atoi(mxmlElementGetAttr(mapNode, "tileheight"));
121 | strncpy(map->orientation, mxmlElementGetAttr(mapNode, "orientation"), 12);
122 | map->numTilesets = 0;
123 | map->numObjectGroups = 0;
124 | map->numLayers = 0;
125 | map->tilesets = NULL;
126 | map->objectGroups = NULL;
127 | map->layers = NULL;
128 | map->numTiles = 0;
129 |
130 | node = mxmlFindElement(tree, tree, "tileset",
131 | NULL, NULL,
132 | MXML_DESCEND);
133 |
134 | if(node == NULL) {
135 | printf("Cannot go further without at least one tileset");
136 | mxmlDelete(tree);
137 | return map;
138 | }
139 |
140 | const char * name;
141 |
142 | // First pass we count the tilesets, layers and object groups
143 | while(node != NULL) {
144 | name = mxmlGetElement(node);
145 | if(name) {
146 | if(strcmp(name, "tileset") == 0) {
147 | map->numTilesets += 1;
148 | }
149 | if(strcmp(name, "layer") == 0) {
150 | map->numLayers += 1;
151 | }
152 | if(strcmp(name, "objectgroup") == 0) {
153 | map->numObjectGroups += 1;
154 | }
155 | }
156 | node = mxmlWalkNext(node, mapNode,
157 | MXML_NO_DESCEND);
158 | }
159 |
160 | // create the map object in memory
161 | map->tilesets = malloc(map->numTilesets * sizeof(TmxTileset));
162 | map->layers = malloc(map->numLayers * sizeof(TmxLayer));
163 | map->objectGroups = malloc(map->numObjectGroups * sizeof(TmxObjectGroup));
164 |
165 | node = mxmlFindElement(tree, tree, "tileset",
166 | NULL, NULL,
167 | MXML_DESCEND);
168 |
169 | int i = 0, j = 0, k = 0, l = 0, m=0;
170 | // Second pass we fill the tilesets, layers and object groups
171 | while(node != NULL) {
172 | name = mxmlGetElement(node);
173 | if(name) {
174 | if(strcmp(name, "tileset") == 0) {
175 | TmxTileset * set = &map->tilesets[i];
176 | set->firstgid = atoi(mxmlElementGetAttr(node, "firstgid"));
177 | set->tilewidth = atoi(mxmlElementGetAttr(node, "tilewidth"));
178 | set->tileheight = atoi(mxmlElementGetAttr(node, "tileheight"));
179 | strncpy(set->name, mxmlElementGetAttr(node, "name"), 50);
180 | mxml_node_t * image = mxmlFindElement(node, node, "image",
181 | NULL, NULL,
182 | MXML_DESCEND);
183 | set->width = (atoi(mxmlElementGetAttr(image, "width")) / set->tilewidth) * set->tilewidth;
184 | set->height = (atoi(mxmlElementGetAttr(image, "height")) / set->tileheight) * set->tileheight;
185 | strncpy(set->source, mxmlElementGetAttr(image, "source"), 50);
186 |
187 | set->numTiles = (set->width / set->tilewidth) * (set->height / set->tileheight);
188 |
189 | i++;
190 | }
191 |
192 | if(strcmp(name, "layer") == 0) {
193 | TmxLayer * layer = &map->layers[j];
194 | layer->width = atoi(mxmlElementGetAttr(node, "width"));
195 | layer->height = atoi(mxmlElementGetAttr(node, "height"));
196 | strncpy(layer->name, mxmlElementGetAttr(node, "name"), 50);
197 | layer->numTiles = layer->width * layer->height;
198 | map->numTiles = map->numTiles + layer->numTiles;
199 |
200 | // create the tiles
201 | layer->tiles = malloc(layer->numTiles * sizeof(int));
202 |
203 |
204 | // filling up all the tiles
205 | mxml_node_t * tile = mxmlFindElement(node, node, "tile",
206 | NULL, NULL,
207 | MXML_DESCEND);
208 | mxml_node_t * data = mxmlFindElement(node, node, "data",
209 | NULL, NULL,
210 | MXML_DESCEND);
211 | l = 0;
212 | while(tile != NULL) {
213 | if(mxmlGetElement(tile)) {
214 | layer->tiles[l] = atoi(mxmlElementGetAttr(tile, "gid"));
215 | l++;
216 | }
217 | tile = mxmlWalkNext(tile, data, MXML_NO_DESCEND);
218 | }
219 |
220 | j++;
221 |
222 | }
223 | if(strcmp(name, "objectgroup") == 0) {
224 | TmxObjectGroup * group = &map->objectGroups[k];
225 | group->width = atoi(mxmlElementGetAttr(node, "width"));
226 | group->height = atoi(mxmlElementGetAttr(node, "height"));
227 | strncpy(group->name, mxmlElementGetAttr(node, "name"), 50);
228 |
229 | // count the objects
230 | mxml_node_t * object = mxmlFindElement(node, node, "object",
231 | NULL, NULL,
232 | MXML_DESCEND);
233 | l = 0;
234 | while(object != NULL) {
235 | if(mxmlGetElement(object)) {
236 | l++;
237 | }
238 | object = mxmlWalkNext(object, node, MXML_NO_DESCEND);
239 | }
240 | // create the objects
241 | group->objects = malloc(l * sizeof(TmxObject));
242 | group->numObjects = l;
243 | // fillup the objects
244 | object = mxmlFindElement(node, node, "object",
245 | NULL, NULL,
246 | MXML_DESCEND);
247 | l = 0;
248 | while(object != NULL) {
249 |
250 | if(mxmlGetElement(object)) {
251 | TmxObject * tobject = &group->objects[l];
252 | // it seems that some object might have no height...
253 | tobject->width = atoi(mxmlElementGetAttr(object, "width"));
254 | tobject->height = atoi(mxmlElementGetAttr(object, "height"));
255 | tobject->x = atoi(mxmlElementGetAttr(object, "x"));
256 | tobject->y = atoi(mxmlElementGetAttr(object, "y"));
257 | tobject->xw = tobject->x + tobject->width;
258 | tobject->yw = tobject->y + tobject->height;
259 | tobject->numProperties = 0;
260 | // count the properties
261 | mxml_node_t * prop = mxmlFindElement(object, object, "property",
262 | NULL, NULL,
263 | MXML_DESCEND);
264 |
265 | while(prop != NULL) {
266 | if(mxmlGetElement(prop)) {
267 | tobject->numProperties = tobject->numProperties + 1;
268 | }
269 | prop = mxmlWalkNext(prop, object, MXML_NO_DESCEND);
270 | }
271 | tobject->properties = malloc(tobject->numProperties * sizeof(TmxProperty));
272 |
273 | // fill the properties
274 | prop = mxmlFindElement(object, object, "property",
275 | NULL, NULL,
276 | MXML_DESCEND);
277 | m = 0;
278 | while(prop != NULL) {
279 | if(mxmlGetElement(prop)) {
280 | const char * name = mxmlElementGetAttr(prop, "name");
281 | const char * value = mxmlElementGetAttr(prop, "name");
282 | tobject->properties[m].name = malloc(sizeof(name));
283 | strncpy(tobject->properties[m].name, name, sizeof(name));
284 | tobject->properties[m].value = malloc(sizeof(value));
285 | strncpy(tobject->properties[m].value, name, sizeof(value));
286 | }
287 | prop = mxmlWalkNext(prop, object, MXML_NO_DESCEND);
288 | m = m + 1;
289 | }
290 | l++;
291 | }
292 |
293 | // next object
294 | object = mxmlWalkNext(object, node, MXML_NO_DESCEND);
295 | }
296 |
297 |
298 | k++;
299 | }
300 | }
301 | node = mxmlWalkNext(node, mapNode,
302 | MXML_NO_DESCEND);
303 | }
304 |
305 |
306 | mxmlDelete(tree);
307 | return map;
308 | }
309 |
310 |
311 |
312 |
313 |
--------------------------------------------------------------------------------