2 Commits

15 changed files with 490 additions and 437 deletions

View File

@@ -2,21 +2,37 @@ SDLFLAGS_CC:=$(shell PKG_CONFIG_PATH=~/local/lib/pkgconfig pkg-config sdl3 --cfl
SDLFLAGS_LD:=$(shell PKG_CONFIG_PATH=~/local/lib/pkgconfig pkg-config sdl3 --libs) -lSDL3_image -lSDL3_mixer SDLFLAGS_LD:=$(shell PKG_CONFIG_PATH=~/local/lib/pkgconfig pkg-config sdl3 --libs) -lSDL3_image -lSDL3_mixer
CC:=$(shell which gcc) CC:=$(shell which gcc)
LD:=$(shell which ld) LD:=$(shell which ld)
SRCFILES:=$(shell find src -type f -name '*.c')
OBJFILES:=$(patsubst %.c,%.o,$(SRCFILES))
PREPFILES:=$(patsubst %.c,%.E,$(SRCFILES))
ASMFILES:=$(patsubst %.c,%.S,$(SRCFILES))
CFLAGS:=-ggdb -gstabs CFLAGS:=-ggdb -gstabs
OBJECTS:=src/util.o src/assets.o src/draw.o src/game.o src/physics.o src/json_helpers.o src/tilemap.o src/sprite.o src/sdl3-gametest.o
DISTFILE:=dist/sdl3-gametest DISTFILE:=dist/sdl3-gametest
.PHONY: clean .PHONY: clean
.PHONY: preprocessor
.PHONY: assembler
all: $(DISTFILE) all: $(DISTFILE)
preprocessor: $(PREPFILES)
assembler: $(ASMFILES)
clean: clean:
rm -f src/*.o ${DISTFILE} rm -f $(OBJFILES) $(PREPFILES) $(ASMFILES) ${DISTFILE}
src/%.S: src/%.c
$(CC) -S -o $@ $(CFLAGS) $(SDLFLAGS_CC) $?
src/%.E: src/%.c
$(CC) -E -o $@ $(CFLAGS) $(SDLFLAGS_CC) $?
src/%.o: src/%.c src/%.o: src/%.c
$(CC) -c -o $@ $(CFLAGS) $(SDLFLAGS_CC) $? $(CC) -c -o $@ $(CFLAGS) $(SDLFLAGS_CC) $?
$(DISTFILE): $(OBJECTS) $(DISTFILE): $(OBJFILES)
$(CC) -o $@ $^ -lexc -lbox2d -ljansson -lhashmap -lm $(SDLFLAGS_LD) $(CC) -o $@ $^ -lexc -lbox2d -ljansson -lhashmap -lm $(SDLFLAGS_LD)

View File

@@ -1,6 +1,7 @@
#include <SDL3/SDL.h> #include <SDL3/SDL.h>
#include <SDL3_image/SDL_image.h> #include <SDL3_image/SDL_image.h>
#include <SDL3_mixer/SDL_mixer.h> #include <SDL3_mixer/SDL_mixer.h>
#include <SDL3/SDL_stdinc.h>
#include <aklabs/exclib.h> #include <aklabs/exclib.h>
#include "game.h" #include "game.h"
@@ -11,12 +12,15 @@ void load_frame_from_image(char *fname, GAME_frame *frame)
THROW_ZERO(frame, EXC_NULLPOINTER, "load_frame_from_image received NULL frame"); THROW_ZERO(frame, EXC_NULLPOINTER, "load_frame_from_image received NULL frame");
THROW_ZERO(fname, EXC_NULLPOINTER, "load_frame_from_image received NULL filename"); THROW_ZERO(fname, EXC_NULLPOINTER, "load_frame_from_image received NULL filename");
TRY {
SDL_asprintf(&asset_path, "%s%s", SDL_GetBasePath(), fname);
tex = IMG_LoadTexture(renderer, asset_path);
THROW_ZERO(tex, EXC_NULLPOINTER, "Failed loading asset");
} FINALLY {
SDL_free(asset_path);
} ETRY;
SDL_asprintf(&asset_path, "%s%s", SDL_GetBasePath(), fname);
tex = IMG_LoadTexture(renderer, asset_path);
THROW_ZERO(tex, EXC_NULLPOINTER, "Failed loading asset");
frame->texture = tex; frame->texture = tex;
SDL_GetTextureSize(tex, &frame->w, &frame->h); SDL_GetTextureSize(tex, &frame->w, &frame->h);
} }
@@ -27,12 +31,15 @@ void load_start_bgm(char *fname)
THROW_ZERO(fname, EXC_NULLPOINTER, "load_start_bgm received NULL filename"); THROW_ZERO(fname, EXC_NULLPOINTER, "load_start_bgm received NULL filename");
SDL_asprintf(&asset_path, "%s%s", SDL_GetBasePath(), fname); TRY {
SDL_Log("Loading music asset from %s", asset_path); SDL_asprintf(&asset_path, "%s%s", SDL_GetBasePath(), fname);
bgm = Mix_LoadMUS(asset_path); SDL_Log("Loading music asset from %s", asset_path);
THROW_ZERO(bgm, EXC_NULLPOINTER, "Failed to load music asset"); bgm = Mix_LoadMUS(asset_path);
THROW_ZERO(bgm, EXC_NULLPOINTER, "Failed to load music asset");
if (!Mix_PlayMusic(bgm, 0)) { if (!Mix_PlayMusic(bgm, 0)) {
THROW(EXC_SDL_MUSICMIXER, "Failed to play music asset"); THROW(EXC_SDL_MUSICMIXER, "Failed to play music asset");
} }
} FINALLY {
SDL_free(asset_path);
} ETRY;
} }

152
src/heap.c Normal file
View File

@@ -0,0 +1,152 @@
#include <stdlib.h>
#include <aklabs/exclib.h>
#include "game.h"
#include "sprite.h"
#include "heap.h"
#include "registry.h"
actor HEAP_ACTOR[MAX_HEAP_ACTOR];
sprite HEAP_SPRITE[MAX_HEAP_SPRITE];
spritesheet HEAP_SPRITESHEET[MAX_HEAP_SPRITESHEET];
character HEAP_CHARACTER[MAX_HEAP_CHARACTER];
string HEAP_STRING[MAX_HEAP_STRING];
void heap_init()
{
int i = 0;
for ( i = 0; i < MAX_HEAP_ACTOR; i++) {
memset(&HEAP_ACTOR[i], 0x00, sizeof(actor));
}
for ( i = 0; i < MAX_HEAP_SPRITE; i++) {
memset(&HEAP_SPRITE[i], 0x00, sizeof(sprite));
}
for ( i = 0; i < MAX_HEAP_SPRITESHEET; i++) {
memset(&HEAP_SPRITESHEET[i], 0x00, sizeof(spritesheet));
}
for ( i = 0; i < MAX_HEAP_CHARACTER; i++) {
memset(&HEAP_CHARACTER[i], 0x00, sizeof(character));
}
for ( i = 0; i < MAX_HEAP_STRING; i++) {
memset(&HEAP_STRING[i], 0x00, sizeof(string));
}
}
actor *heap_next_actor()
{
for (int i = 0; i < MAX_HEAP_ACTOR; i++ ) {
if ( HEAP_ACTOR[i].refcount != 0 ) {
continue;
}
return &HEAP_ACTOR[i];
}
THROW(EXC_HEAPERROR, "Unable to find unused actor on the heap");
}
sprite *heap_next_sprite()
{
for (int i = 0; i < MAX_HEAP_SPRITE; i++ ) {
if ( HEAP_SPRITE[i].refcount != 0 ) {
continue;
}
return &HEAP_SPRITE[i];
}
THROW(EXC_HEAPERROR, "Unable to find unused sprite on the heap");
}
spritesheet *heap_next_spritesheet()
{
for (int i = 0; i < MAX_HEAP_SPRITESHEET; i++ ) {
if ( HEAP_SPRITESHEET[i].refcount != 0 ) {
continue;
}
return &HEAP_SPRITESHEET[i];
}
THROW(EXC_HEAPERROR, "Unable to find unused spritesheet on the heap");
}
character *heap_next_character()
{
for (int i = 0; i < MAX_HEAP_CHARACTER; i++ ) {
if ( HEAP_CHARACTER[i].refcount != 0 ) {
continue;
}
return &HEAP_CHARACTER[i];
}
THROW(EXC_HEAPERROR, "Unable to find unused character on the heap");
}
string *heap_next_string()
{
for (int i = 0; i < MAX_HEAP_STRING; i++ ) {
if ( HEAP_STRING[i].refcount != 0 ) {
continue;
}
return &HEAP_STRING[i];
}
THROW(EXC_HEAPERROR, "Unable to find unused string on the heap");
}
void heap_release_actor(actor *ptr)
{
THROW_ZERO(ptr, EXC_NULLPOINTER, "NULL character reference");
if ( ptr->refcount > 0 ) {
ptr->refcount -= 1;
}
if ( ptr->refcount == 0 ) {
heap_release_character(ptr->basechar);
SDL_ClearProperty(REGISTRY_ACTOR, (char *)&ptr->name);
}
}
void heap_release_character(character *basechar)
{
iterator opflags;
THROW_ZERO(basechar, EXC_NULLPOINTER, "NULL character reference");
BITMASK_CLEAR(opflags.flags);
BITMASK_ADD(opflags.flags, ITERATOR_OP_RELEASE);
if ( basechar->refcount > 0 ) {
basechar->refcount -= 1;
}
if ( basechar->refcount == 0 ) {
SDL_EnumerateProperties(basechar->state_sprites, &character_state_sprites_iterate, (void *)&opflags);
SDL_ClearProperty(REGISTRY_CHARACTER, (char *)&basechar->name);
}
}
void heap_release_sprite(sprite *ptr)
{
THROW_ZERO(ptr, EXC_NULLPOINTER, "Received NULL sprite reference");
if ( ptr->refcount > 0 ) {
ptr->refcount -= 1;
}
if ( ptr->refcount == 0 ) {
heap_release_spritesheet(ptr->sheet);
SDL_ClearProperty(REGISTRY_SPRITE, (char *)&ptr->name);
}
}
void heap_release_spritesheet(spritesheet *ptr)
{
THROW_ZERO(ptr, EXC_NULLPOINTER, "Received NULL spritesheet reference");
if ( ptr->refcount > 0 ) {
ptr->refcount -= 1;
}
if ( ptr->refcount == 0 ) {
// TODO : If we go threaded, make sure this is only happening on the main thread
SDL_DestroyTexture(ptr->texture);
SDL_ClearProperty(REGISTRY_CHARACTER, (char *)&ptr->name);
}
}
void heap_release_string(string *ptr)
{
THROW_ZERO(ptr, EXC_NULLPOINTER, "Received NULL spritesheet reference");
if ( ptr->refcount > 0 ) {
ptr->refcount -= 1;
}
if ( ptr->refcount == 0 ) {
memset(ptr->data, 0x00, MAX_STRING_LENGTH);
}
}

31
src/heap.h Normal file
View File

@@ -0,0 +1,31 @@
#ifndef _HEAP_H_
#define _HEAP_H_
#include "sprite.h"
#include "string.h"
#define MAX_HEAP_ACTOR 64
#define MAX_HEAP_SPRITE (MAX_HEAP_ACTOR * 16)
#define MAX_HEAP_SPRITESHEET MAX_HEAP_SPRITE
#define MAX_HEAP_CHARACTER 256
#define MAX_HEAP_STRING 256
extern actor HEAP_ACTOR[MAX_HEAP_ACTOR];
extern sprite HEAP_SPRITE[MAX_HEAP_SPRITE];
extern spritesheet HEAP_SPRITESHEET[MAX_HEAP_SPRITESHEET];
extern character HEAP_CHARACTER[MAX_HEAP_CHARACTER];
extern string HEAP_STRING[MAX_HEAP_STRING];
void heap_init();
actor *heap_next_actor();
sprite *heap_next_sprite();
spritesheet *heap_next_spritesheet();
character *heap_next_character();
string *heap_next_string();
void heap_release_actor(actor *ptr);
void heap_release_sprite(sprite *ptr);
void heap_release_spritesheet(spritesheet *ptr);
void heap_release_character(character *ptr);
void heap_release_string(string *ptr);
#endif //_HEAP_H_

View File

@@ -1,6 +1,8 @@
#include <jansson.h> #include <jansson.h>
#include "json_helpers.h" #include "json_helpers.h"
#include "game.h" #include "game.h"
#include "string.h"
#include "heap.h"
json_t *get_json_object_value(json_t *obj, char *key) json_t *get_json_object_value(json_t *obj, char *key)
{ {
@@ -10,12 +12,14 @@ json_t *get_json_object_value(json_t *obj, char *key)
return value; return value;
} }
int get_json_boolean_value(json_t *obj, char *key) bool get_json_boolean_value(json_t *obj, char *key)
{ {
json_t *value = json_object_get(obj, key); json_t *value = json_object_get(obj, key);
THROW_ZERO(value, EXC_KEYERROR, ""); THROW_ZERO(value, EXC_KEYERROR, "");
THROW_ZERO(json_is_boolean(value), EXC_ATTRIBUTEERROR, ""); THROW_ZERO(json_is_boolean(value), EXC_ATTRIBUTEERROR, "");
return json_boolean_value(value); bool i = json_boolean_value(value);
json_decref(value);
return i;
} }
int get_json_integer_value(json_t *obj, char *key) int get_json_integer_value(json_t *obj, char *key)
@@ -23,30 +27,38 @@ int get_json_integer_value(json_t *obj, char *key)
json_t *value = json_object_get(obj, key); json_t *value = json_object_get(obj, key);
THROW_ZERO(value, EXC_KEYERROR, ""); THROW_ZERO(value, EXC_KEYERROR, "");
THROW_ZERO(json_is_integer(value), EXC_ATTRIBUTEERROR, ""); THROW_ZERO(json_is_integer(value), EXC_ATTRIBUTEERROR, "");
return json_integer_value(value); int i = json_integer_value(value);
json_decref(value);
return i;
} }
float get_json_number_value(json_t *obj, char *key) float get_json_number_value(json_t *obj, char *key)
{ {
json_t *value = json_object_get(obj, key); json_t *value = json_object_get(obj, key);
float f;
THROW_ZERO(value, EXC_KEYERROR, ""); THROW_ZERO(value, EXC_KEYERROR, "");
THROW_ZERO(json_is_number(value), EXC_ATTRIBUTEERROR, ""); THROW_ZERO(json_is_number(value), EXC_ATTRIBUTEERROR, "");
return json_number_value(value); f = json_number_value(value);
json_decref(value);
return f;
} }
const char *get_json_string_value(json_t *obj, char *key) string *get_json_string_value(json_t *obj, char *key)
{ {
string *s = heap_next_string();
json_t *value = json_object_get(obj, key); json_t *value = json_object_get(obj, key);
THROW_ZERO(value, EXC_KEYERROR, ""); THROW_ZERO(value, EXC_KEYERROR, key);
THROW_ZERO(json_is_string(value), EXC_ATTRIBUTEERROR, ""); THROW_ZERO(json_is_string(value), EXC_ATTRIBUTEERROR, key);
return json_string_value(value); strncpy(s->data, (char *)json_string_value(value), MAX_STRING_LENGTH);
json_decref(value);
return s;
} }
json_t *get_json_array_value(json_t *obj, char *key) json_t *get_json_array_value(json_t *obj, char *key)
{ {
json_t *value = json_object_get(obj, key); json_t *value = json_object_get(obj, key);
THROW_ZERO(value, EXC_KEYERROR, ""); THROW_ZERO(value, EXC_KEYERROR, key);
THROW_ZERO(json_is_array(value), EXC_ATTRIBUTEERROR, ""); THROW_ZERO(json_is_array(value), EXC_ATTRIBUTEERROR, key);
return value; return value;
} }
@@ -60,8 +72,11 @@ json_t *get_json_array_index_object(json_t *array, int index)
int get_json_array_index_integer(json_t *array, int index) int get_json_array_index_integer(json_t *array, int index)
{ {
int i;
json_t *value = json_array_get(array, index); json_t *value = json_array_get(array, index);
THROW_ZERO(value, EXC_INDEXERROR, ""); THROW_ZERO(value, EXC_INDEXERROR, "");
THROW_ZERO(json_is_integer(value), EXC_ATTRIBUTEERROR, ""); THROW_ZERO(json_is_integer(value), EXC_ATTRIBUTEERROR, "");
return json_integer_value(value); i = json_integer_value(value);
json_decref(value);
return i;
} }

View File

@@ -1,11 +1,14 @@
#ifndef _JSON_HELPERS_H_ #ifndef _JSON_HELPERS_H_
#define _JSON_HELPERS_H_ #define _JSON_HELPERS_H_
#include <stdbool.h>
#include "string.h"
json_t *get_json_object_value(json_t *obj, char *key); json_t *get_json_object_value(json_t *obj, char *key);
int get_json_boolean_value(json_t *obj, char *key); bool get_json_boolean_value(json_t *obj, char *key);
int get_json_integer_value(json_t *obj, char *key); int get_json_integer_value(json_t *obj, char *key);
float get_json_number_value(json_t *obj, char *key); float get_json_number_value(json_t *obj, char *key);
const char *get_json_string_value(json_t *obj, char *key); string *get_json_string_value(json_t *obj, char *key);
json_t *get_json_array_value(json_t *obj, char *key); json_t *get_json_array_value(json_t *obj, char *key);
json_t *get_json_array_index_object(json_t *array, int index); json_t *get_json_array_index_object(json_t *array, int index);
int get_json_array_index_integer(json_t *array, int index); int get_json_array_index_integer(json_t *array, int index);

32
src/registry.c Normal file
View File

@@ -0,0 +1,32 @@
#include <aklabs/exclib.h>
#include "sprite.h"
#include "registry.h"
SDL_PropertiesID REGISTRY_ACTOR;
SDL_PropertiesID REGISTRY_SPRITE;
SDL_PropertiesID REGISTRY_SPRITESHEET;
SDL_PropertiesID REGISTRY_CHARACTER;
void registry_init_actor()
{
REGISTRY_ACTOR = SDL_CreateProperties();
THROW_ZERO(REGISTRY_ACTOR, EXC_NULLPOINTER, "Error initializing actor registry");
}
void registry_init_sprite()
{
REGISTRY_SPRITE = SDL_CreateProperties();
THROW_ZERO(REGISTRY_SPRITE, EXC_NULLPOINTER, "Error initializing sprite registry");
}
void registry_init_spritesheet()
{
REGISTRY_SPRITESHEET = SDL_CreateProperties();
THROW_ZERO(REGISTRY_SPRITESHEET, EXC_NULLPOINTER, "Error initializing spritesheet registry");
}
void registry_init_character()
{
REGISTRY_CHARACTER = SDL_CreateProperties();
THROW_ZERO(REGISTRY_CHARACTER, EXC_NULLPOINTER, "Error initializing character registry");
}

16
src/registry.h Normal file
View File

@@ -0,0 +1,16 @@
#ifndef _REGISTRY_H_
#define _REGISTRY_H_
extern SDL_PropertiesID REGISTRY_ACTOR;
extern SDL_PropertiesID REGISTRY_SPRITE;
extern SDL_PropertiesID REGISTRY_SPRITESHEET;
extern SDL_PropertiesID REGISTRY_CHARACTER;
void registry_init_actor();
void registry_iterate_actor(void *userdata, SDL_PropertiesID registry, const char *name);
void registry_init_sprite();
void registry_init_spritesheet();
void registry_init_character();
#endif //_REGISTRY_H_

View File

@@ -13,6 +13,8 @@
#include "draw.h" #include "draw.h"
#include "assets.h" #include "assets.h"
#include "sprite.h" #include "sprite.h"
#include "heap.h"
#include "registry.h"
SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[]) SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[])
{ {
@@ -81,18 +83,6 @@ SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[])
return SDL_APP_FAILURE; return SDL_APP_FAILURE;
} ETRY; } ETRY;
/*TRY {
actorptr = heap_next_actor();
actor_initialize(actorptr, "npc");
actorptr->basechar = characterptr;
actorptr->x = 0;
actorptr->y = 0;
actorptr->state = (ACTOR_STATE_ALIVE | ACTOR_STATE_FACE_LEFT | ACTOR_STATE_MOVING_LEFT);
} CATCH(EXC_NULLPOINTER) {
SDL_Log("Attempting to setup npc: %s (%s)", EXCLIB_EXCEPTION->description, SDL_GetError());
return SDL_APP_FAILURE;
} ETRY;*/
/* /*
TRY { TRY {
//load_start_bgm("../assets/nutcracker.mid"); //load_start_bgm("../assets/nutcracker.mid");

View File

@@ -1,139 +0,0 @@
#define SDL_MAIN_USE_CALLBACKS
#include <SDL3/SDL.h>
#include <SDL3/SDL_main.h>
#include <SDL3_image/SDL_image.h>
#include <SDL3_mixer/SDL_mixer.h>
#include <aklabs/exclib.h>
#include <box2d/box2d.h>
#include "game.h"
#include "physics.h"
#include "draw.h"
#include "assets.h"
SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[])
{
SDL_AudioSpec spec;
/* Initialize variables */
spec.freq = MIX_DEFAULT_FREQUENCY;
spec.format = MIX_DEFAULT_FORMAT;
spec.channels = MIX_DEFAULT_CHANNELS;
exclib_name_exception(EXC_SDL_INIT, "SDL Initialization Failure");
exclib_name_exception(EXC_SDL_MUSICMIXER, "SDL Music Mixer Failure");
SDL_SetAppMetadata("SDL3-Pong", "0.1", "net.aklabs.sdl3-pong");
if (!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK | SDL_INIT_AUDIO )) {
SDL_Log("Couldn't initialize SDL: %s", SDL_GetError());
return SDL_APP_FAILURE;
}
if (!SDL_CreateWindowAndRenderer("net/aklabs/sdl3-pong", 640, 480, 0, &window, &renderer)) {
SDL_Log("Couldn't create window/renderer: %s", SDL_GetError());
return SDL_APP_FAILURE;
}
GAME_init_physics();
if (!Mix_OpenAudio(0, &spec)) {
SDL_Log("Couldn't initialize the audio subsystem: %s", SDL_GetError());
return SDL_APP_FAILURE;
} else {
Mix_QuerySpec(&spec.freq, &spec.format, &spec.channels);
SDL_Log("Opened audio at %d Hz %d bit%s %s audio buffer\n", spec.freq,
(spec.format&0xFF),
(SDL_AUDIO_ISFLOAT(spec.format) ? " (float)" : ""),
(spec.channels > 2) ? "surround" : (spec.channels > 1) ? "stereo" : "mono");
}
TRY {
load_frame_from_image("../assets/ball.png", &ball);
load_frame_from_image("../assets/paddle-green.png", &paddle1);
load_frame_from_image("../assets/paddle-red.png", &paddle2);
load_frame_from_image("../assets/table.jpg", &table);
} CATCH(EXC_NULLPOINTER) {
SDL_Log("Attempting to load asset: %s", EXCLIB_EXCEPTION->description);
return SDL_APP_FAILURE;
} ETRY;
/*
TRY {
//load_start_bgm("../assets/nutcracker.mid");
load_start_bgm("../assets/memories.mp3");
} CATCH(EXC_NULLPOINTER) {
} CATCH_GROUP(EXC_SDL_INIT) {
} CATCH_GROUP(EXC_SDL_MUSICMIXER) {
SDL_Log("Attempting to load and play background music: %s (%s)", EXCLIB_EXCEPTION->description, SDL_GetError());
return SDL_APP_FAILURE;
} ETRY;
*/
return SDL_APP_CONTINUE;
}
SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event)
{
if (event->type == SDL_EVENT_QUIT) {
return SDL_APP_SUCCESS; /* end the program, reporting success to the OS. */
} else if (event->type == SDL_EVENT_JOYSTICK_BUTTON_UP) {
GAME_handle_joystick_button_up(appstate, event);
} else if (event->type == SDL_EVENT_JOYSTICK_ADDED) {
GAME_handle_joystick_added(appstate, event);
} else if (event->type == SDL_EVENT_JOYSTICK_REMOVED) {
GAME_handle_joystick_removed(appstate, event);
}
return SDL_APP_CONTINUE; /* carry on with the program! */
}
SDL_AppResult SDL_AppIterate(void *appstate)
{
SDL_FRect dest;
b2Vec2 position;
GAME_draw_background(640, 480);
b2World_Step(physicsWorldId, physicsTimeStep, physicsSubStepCount);
dest.x = 0;
dest.y = 0;
dest.w = table.w;
dest.h = table.h;
SDL_RenderTexture(renderer, table.texture, NULL, &dest);
dest.x = 16;
dest.y = 200;
dest.w = paddle1.w;
dest.h = paddle1.h;
SDL_RenderTexture(renderer, paddle1.texture, NULL, &dest);
dest.x = (640-32);
dest.y = 200;
dest.w = paddle1.w;
dest.h = paddle1.h;
SDL_RenderTexture(renderer, paddle2.texture, NULL, &dest);
position = b2Body_GetPosition(physicsBallBodyId);
dest.x = (int)SCREEN_PHYSICS_SCALE(position.x);
dest.y = (int)SCREEN_PHYSICS_SCALE(position.y);
dest.w = 16;
dest.h = 16;
SDL_RenderTexture(renderer, ball.texture, NULL, &dest);
SDL_RenderPresent(renderer);
return SDL_APP_CONTINUE;
}
void SDL_AppQuit(void *appstate, SDL_AppResult result)
{
/* SDL will clean up the window/renderer for us. */
SDL_DestroyTexture(ball.texture);
b2DestroyWorld(physicsWorldId);
SDL_Log("Freeing music resources");
if ( bgm != NULL ) {
Mix_FreeMusic(bgm);
}
SDL_Log("Quitting mixer");
Mix_Quit();
}

View File

@@ -1,108 +1,16 @@
#include <SDL3/SDL.h> #include <SDL3/SDL.h>
#include <SDL3/SDL_stdinc.h>
#include <SDL3_image/SDL_image.h> #include <SDL3_image/SDL_image.h>
#include <box2d/box2d.h> #include <box2d/box2d.h>
#include <aklabs/exclib.h> #include <aklabs/exclib.h>
#include <string.h> #include <string.h>
#include <jansson.h> #include <jansson.h>
#include "string.h"
#include "game.h" #include "game.h"
#include "sprite.h" #include "sprite.h"
#include "json_helpers.h" #include "json_helpers.h"
#include "heap.h"
SDL_PropertiesID REGISTRY_ACTOR; #include "registry.h"
SDL_PropertiesID REGISTRY_SPRITE;
SDL_PropertiesID REGISTRY_SPRITESHEET;
SDL_PropertiesID REGISTRY_CHARACTER;
actor HEAP_ACTOR[MAX_HEAP_ACTOR];
sprite HEAP_SPRITE[MAX_HEAP_SPRITE];
spritesheet HEAP_SPRITESHEET[MAX_HEAP_SPRITESHEET];
character HEAP_CHARACTER[MAX_HEAP_CHARACTER];
void heap_init()
{
int i = 0;
for ( i = 0; i < MAX_HEAP_ACTOR; i++) {
memset(&HEAP_ACTOR[i], 0x00, sizeof(actor));
}
for ( i = 0; i < MAX_HEAP_SPRITE; i++) {
memset(&HEAP_SPRITE[i], 0x00, sizeof(sprite));
}
for ( i = 0; i < MAX_HEAP_SPRITESHEET; i++) {
memset(&HEAP_SPRITESHEET[i], 0x00, sizeof(spritesheet));
}
for ( i = 0; i < MAX_HEAP_CHARACTER; i++) {
memset(&HEAP_CHARACTER[i], 0x00, sizeof(character));
}
}
actor *heap_next_actor()
{
for (int i = 0; i < MAX_HEAP_ACTOR; i++ ) {
if ( HEAP_ACTOR[i].refcount != 0 ) {
continue;
}
return &HEAP_ACTOR[i];
}
THROW(EXC_HEAPERROR, "Unable to find unused actor on the heap");
}
sprite *heap_next_sprite()
{
for (int i = 0; i < MAX_HEAP_SPRITE; i++ ) {
if ( HEAP_SPRITE[i].refcount != 0 ) {
continue;
}
return &HEAP_SPRITE[i];
}
THROW(EXC_HEAPERROR, "Unable to find unused sprite on the heap");
}
spritesheet *heap_next_spritesheet()
{
for (int i = 0; i < MAX_HEAP_SPRITESHEET; i++ ) {
if ( HEAP_SPRITESHEET[i].refcount != 0 ) {
continue;
}
return &HEAP_SPRITESHEET[i];
}
THROW(EXC_HEAPERROR, "Unable to find unused spritesheet on the heap");
}
character *heap_next_character()
{
for (int i = 0; i < MAX_HEAP_CHARACTER; i++ ) {
if ( HEAP_CHARACTER[i].refcount != 0 ) {
continue;
}
return &HEAP_CHARACTER[i];
}
THROW(EXC_HEAPERROR, "Unable to find unused character on the heap");
}
void registry_init_actor()
{
REGISTRY_ACTOR = SDL_CreateProperties();
THROW_ZERO(REGISTRY_ACTOR, EXC_NULLPOINTER, "Error initializing actor registry");
}
void registry_init_sprite()
{
REGISTRY_SPRITE = SDL_CreateProperties();
THROW_ZERO(REGISTRY_SPRITE, EXC_NULLPOINTER, "Error initializing sprite registry");
}
void registry_init_spritesheet()
{
REGISTRY_SPRITESHEET = SDL_CreateProperties();
THROW_ZERO(REGISTRY_SPRITESHEET, EXC_NULLPOINTER, "Error initializing spritesheet registry");
}
void registry_init_character()
{
REGISTRY_CHARACTER = SDL_CreateProperties();
THROW_ZERO(REGISTRY_CHARACTER, EXC_NULLPOINTER, "Error initializing character registry");
}
void actor_initialize(actor *obj, char *name) void actor_initialize(actor *obj, char *name)
{ {
@@ -235,6 +143,7 @@ void character_load_json(char *filename)
json_t *mappings; json_t *mappings;
json_t *curmapping; json_t *curmapping;
json_error_t error; json_error_t error;
string *s;
sprite *spriteptr = NULL; sprite *spriteptr = NULL;
char *asset_path = NULL; char *asset_path = NULL;
character *obj = NULL; character *obj = NULL;
@@ -242,29 +151,32 @@ void character_load_json(char *filename)
THROW_ZERO(filename, EXC_NULLPOINTER, "Received null filename"); THROW_ZERO(filename, EXC_NULLPOINTER, "Received null filename");
obj = heap_next_character(); obj = heap_next_character();
SDL_asprintf(&asset_path, "%s%s", SDL_GetBasePath(), filename);
json = json_load_file(asset_path, 0, &error);
if (!json) {
SDL_Log("Error while loading character from %s on line %d: %s", asset_path, error.line, error.text);
THROW(EXC_NULLPOINTER, "Loading JSON sprite failed");
}
character_initialize(obj, (char *)get_json_string_value(json, "name"));
TRY { TRY {
SDL_asprintf(&asset_path, "%s%s", SDL_GetBasePath(), filename);
json = json_load_file(asset_path, 0, &error);
if (!json) {
SDL_Log("Error while loading character from %s on line %d: %s", asset_path, error.line, error.text);
THROW(EXC_NULLPOINTER, "Loading JSON sprite failed");
}
} FINALLY {
SDL_free(asset_path);
} ETRY;
TRY {
s = get_json_string_value(json, "name");
character_initialize(obj, s->data);
heap_release_string(s);
mappings = get_json_array_value(json, "sprite_mappings"); mappings = get_json_array_value(json, "sprite_mappings");
TRY { TRY {
for ( i = 0; i < json_array_size(mappings) ; i++ ) { for ( i = 0; i < json_array_size(mappings) ; i++ ) {
curmapping = get_json_array_index_object(mappings, i); curmapping = get_json_array_index_object(mappings, i);
s = get_json_string_value(curmapping, "sprite");
spriteptr = SDL_GetPointerProperty( spriteptr = SDL_GetPointerProperty(
REGISTRY_SPRITE, REGISTRY_SPRITE,
get_json_string_value(curmapping, "sprite"), s->data,
NULL NULL
); );
SDL_Log("Character %s for state %d references sprite %s", heap_release_string(s);
(char *)get_json_string_value(json, "name"),
get_json_integer_value(curmapping, "state"),
(char *)get_json_string_value(curmapping, "sprite")
);
THROW_ZERO(spriteptr, EXC_NULLPOINTER, "Character references sprite that does not exist"); THROW_ZERO(spriteptr, EXC_NULLPOINTER, "Character references sprite that does not exist");
character_sprite_add( character_sprite_add(
obj, obj,
@@ -274,9 +186,9 @@ void character_load_json(char *filename)
} }
} FINALLY { } FINALLY {
json_decref(curmapping); json_decref(curmapping);
json_decref(mappings);
} ETRY; } ETRY;
} FINALLY { } FINALLY {
json_decref(mappings);
json_decref(json); json_decref(json);
} ETRY; } ETRY;
} }
@@ -287,6 +199,7 @@ void sprite_load_json(char *filename)
json_t *spritesheet_json; json_t *spritesheet_json;
json_t *frames; json_t *frames;
json_error_t error; json_error_t error;
string *s;
spritesheet *sheet = NULL; spritesheet *sheet = NULL;
char *asset_path = NULL; char *asset_path = NULL;
sprite *obj = NULL; sprite *obj = NULL;
@@ -294,34 +207,43 @@ void sprite_load_json(char *filename)
THROW_ZERO(filename, EXC_NULLPOINTER, "Received null filename"); THROW_ZERO(filename, EXC_NULLPOINTER, "Received null filename");
obj = heap_next_sprite(); obj = heap_next_sprite();
SDL_asprintf(&asset_path, "%s%s", SDL_GetBasePath(), filename);
json = json_load_file(asset_path, 0, &error); TRY {
if (!json) { SDL_asprintf(&asset_path, "%s%s", SDL_GetBasePath(), filename);
SDL_Log("Error while loading sprite from %s on line %d: %s", asset_path, error.line, error.text); json = json_load_file(asset_path, 0, &error);
THROW(EXC_NULLPOINTER, "Loading JSON sprite failed"); if (!json) {
} SDL_Log("Error while loading sprite from %s on line %d: %s", asset_path, error.line, error.text);
THROW(EXC_NULLPOINTER, "Loading JSON sprite failed");
}
} FINALLY {
SDL_free(asset_path);
} ETRY;
TRY { TRY {
spritesheet_json = get_json_object_value(json, "spritesheet"); spritesheet_json = get_json_object_value(json, "spritesheet");
s = get_json_string_value(spritesheet_json, "filename");
sheet = SDL_GetPointerProperty( sheet = SDL_GetPointerProperty(
REGISTRY_SPRITESHEET, REGISTRY_SPRITESHEET,
get_json_string_value(spritesheet_json, "filename"), s->data,
NULL NULL
); );
if ( sheet == NULL ) {
sheet = heap_next_spritesheet();
spritesheet_initialize(
sheet,
get_json_integer_value(spritesheet_json, "frame_width"),
get_json_integer_value(spritesheet_json, "frame_height"),
(char *)get_json_string_value(spritesheet_json, "filename")
);
}
TRY { TRY {
if ( sheet == NULL ) {
sheet = heap_next_spritesheet();
spritesheet_initialize(
sheet,
get_json_integer_value(spritesheet_json, "frame_width"),
get_json_integer_value(spritesheet_json, "frame_height"),
s->data
);
}
heap_release_string(s);
s = get_json_string_value(json, "name");
sprite_initialize( sprite_initialize(
obj, obj,
(char *)get_json_string_value(json, "name"), s->data,
sheet); sheet);
heap_release_string(s);
} FINALLY { } FINALLY {
json_decref(spritesheet_json); json_decref(spritesheet_json);
} ETRY; } ETRY;
@@ -367,8 +289,13 @@ void spritesheet_initialize(spritesheet *sheet, short sprite_w, short sprite_h,
THROW_ZERO(sheet, EXC_NULLPOINTER, "Null spritesheet pointer"); THROW_ZERO(sheet, EXC_NULLPOINTER, "Null spritesheet pointer");
THROW_ZERO(filename, EXC_NULLPOINTER, "Null filename pointer"); THROW_ZERO(filename, EXC_NULLPOINTER, "Null filename pointer");
SDL_asprintf(&asset_path, "%s%s", SDL_GetBasePath(), filename); TRY {
sheet->texture = IMG_LoadTexture(renderer, asset_path); SDL_asprintf(&asset_path, "%s%s", SDL_GetBasePath(), filename);
sheet->texture = IMG_LoadTexture(renderer, asset_path);
} FINALLY {
SDL_free(asset_path);
} ETRY;
strncpy(sheet->name, filename, SPRITE_SHEET_MAX_FILENAME_LENGTH); strncpy(sheet->name, filename, SPRITE_SHEET_MAX_FILENAME_LENGTH);
THROW_ZERO(sheet->texture, EXC_NULLPOINTER, "Failed loading asset"); THROW_ZERO(sheet->texture, EXC_NULLPOINTER, "Failed loading asset");
@@ -444,48 +371,4 @@ void character_state_sprites_iterate(void *userdata, SDL_PropertiesID registry,
} }
} }
void heap_release_actor(actor *ptr)
{
THROW_ZERO(ptr, EXC_NULLPOINTER, "NULL character reference");
ptr->refcount -= 1;
if ( ptr->refcount == 0 ) {
heap_release_character(ptr->basechar);
SDL_ClearProperty(REGISTRY_ACTOR, (char *)&ptr->name);
}
}
void heap_release_character(character *basechar)
{
iterator opflags;
THROW_ZERO(basechar, EXC_NULLPOINTER, "NULL character reference");
BITMASK_CLEAR(opflags.flags);
BITMASK_ADD(opflags.flags, ITERATOR_OP_RELEASE);
basechar->refcount -= 1;
if ( basechar->refcount == 0 ) {
SDL_EnumerateProperties(basechar->state_sprites, &character_state_sprites_iterate, (void *)&opflags);
SDL_ClearProperty(REGISTRY_CHARACTER, (char *)&basechar->name);
}
}
void heap_release_sprite(sprite *ptr)
{
THROW_ZERO(ptr, EXC_NULLPOINTER, "Received NULL sprite reference");
ptr->refcount -= 1;
if ( ptr->refcount == 0 ) {
heap_release_spritesheet(ptr->sheet);
SDL_ClearProperty(REGISTRY_SPRITE, (char *)&ptr->name);
}
}
void heap_release_spritesheet(spritesheet *ptr)
{
THROW_ZERO(ptr, EXC_NULLPOINTER, "Received NULL spritesheet reference");
ptr->refcount -= 1;
if ( ptr->refcount == 0 ) {
// TODO : If we go threaded, make sure this is only happening on the main thread
SDL_DestroyTexture(ptr->texture);
SDL_ClearProperty(REGISTRY_CHARACTER, (char *)&ptr->name);
}
}

View File

@@ -3,6 +3,7 @@
#include <box2d/box2d.h> #include <box2d/box2d.h>
#include <SDL3/SDL_properties.h> #include <SDL3/SDL_properties.h>
#include <SDL3/SDL.h>
#define ACTOR_STATE_FACE_DOWN 1 // 1 #define ACTOR_STATE_FACE_DOWN 1 // 1
#define ACTOR_STATE_FACE_LEFT 1 << 1 // 2 #define ACTOR_STATE_FACE_LEFT 1 << 1 // 2
@@ -44,11 +45,6 @@
#define SPRITE_MAX_ACTOR_NAME_LENGTH 128 #define SPRITE_MAX_ACTOR_NAME_LENGTH 128
#define SPRITE_MAX_CHARACTER_NAME_LENGTH 128 #define SPRITE_MAX_CHARACTER_NAME_LENGTH 128
#define MAX_HEAP_ACTOR 64
#define MAX_HEAP_SPRITE (MAX_HEAP_ACTOR * 16)
#define MAX_HEAP_SPRITESHEET MAX_HEAP_SPRITE
#define MAX_HEAP_CHARACTER 256
typedef struct { typedef struct {
int refcount; int refcount;
SDL_Texture *texture; SDL_Texture *texture;
@@ -93,16 +89,6 @@ typedef struct {
int y; int y;
} actor; } actor;
extern SDL_PropertiesID REGISTRY_ACTOR;
extern SDL_PropertiesID REGISTRY_SPRITE;
extern SDL_PropertiesID REGISTRY_SPRITESHEET;
extern SDL_PropertiesID REGISTRY_CHARACTER;
extern actor HEAP_ACTOR[MAX_HEAP_ACTOR];
extern sprite HEAP_SPRITE[MAX_HEAP_SPRITE];
extern spritesheet HEAP_SPRITESHEET[MAX_HEAP_SPRITESHEET];
extern character HEAP_CHARACTER[MAX_HEAP_CHARACTER];
void actor_initialize(actor *obj, char *name); void actor_initialize(actor *obj, char *name);
void actor_set_character(actor *obj, char *basecharname); void actor_set_character(actor *obj, char *basecharname);
void actor_render(actor *obj, SDL_Renderer *renderer); void actor_render(actor *obj, SDL_Renderer *renderer);
@@ -120,20 +106,4 @@ void sprite_initialize(sprite *spr, char *name, spritesheet *sheet);
void spritesheet_initialize(spritesheet *sheet, short sprite_w, short sprite_h, char *filename); void spritesheet_initialize(spritesheet *sheet, short sprite_w, short sprite_h, char *filename);
void sprite_load_json(char *filename); void sprite_load_json(char *filename);
void registry_init_actor();
void registry_iterate_actor(void *userdata, SDL_PropertiesID registry, const char *name);
void registry_init_sprite();
void registry_init_spritesheet();
void registry_init_character();
void heap_init();
actor *heap_next_actor();
sprite *heap_next_sprite();
spritesheet *heap_next_spritesheet();
character *heap_next_character();
void heap_release_actor(actor *ptr);
void heap_release_sprite(sprite *ptr);
void heap_release_spritesheet(spritesheet *ptr);
void heap_release_character(character *ptr);
#endif //_SPRITE_H_ #endif //_SPRITE_H_

12
src/string.c Normal file
View File

@@ -0,0 +1,12 @@
#include "string.h"
#include <aklabs/exclib.h>
void string_initialize(string *obj, char *init)
{
THROW_ZERO(obj, EXC_NULLPOINTER, "Attempted to initialize NULL string reference");
if ( init != NULL ) {
strncpy(obj->data, init, MAX_STRING_LENGTH);
} else {
memset(obj->data, 0x00, sizeof(string));
}
}

14
src/string.h Normal file
View File

@@ -0,0 +1,14 @@
#ifndef _STRING_H_
#define _STRING_H_
#define MAX_STRING_LENGTH 256
typedef struct string
{
int refcount;
char data[MAX_STRING_LENGTH];
} string;
void string_initialize(string *obj, char *init);
#endif //_STRING_H_

View File

@@ -5,6 +5,9 @@
#include "tilemap.h" #include "tilemap.h"
#include "game.h" #include "game.h"
#include "sprite.h" #include "sprite.h"
#include "heap.h"
#include "registry.h"
#include "string.h"
#include <string.h> #include <string.h>
#include <jansson.h> #include <jansson.h>
#include "json_helpers.h" #include "json_helpers.h"
@@ -13,36 +16,53 @@ static json_t *get_json_tilemap_property(json_t *obj, char *key, char *type)
{ {
json_t *properties; json_t *properties;
json_t *property; json_t *property;
string *s;
int i = 0; int i = 0;
// This is not a generic JSON helper. It assumes we are receiving an object with a 'properties' key // This is not a generic JSON helper. It assumes we are receiving an object with a 'properties' key
// inside of it. That key is an array of objects, and each object has a name, type, and value. // inside of it. That key is an array of objects, and each object has a name, type, and value.
THROW_ZERO(obj, EXC_NULLPOINTER, "NULL json obj reference"); THROW_ZERO(obj, EXC_NULLPOINTER, "NULL json obj reference");
THROW_ZERO(key, EXC_NULLPOINTER, "NULL key string"); THROW_ZERO(key, EXC_NULLPOINTER, "NULL key string");
properties = get_json_array_value(obj, "properties"); properties = get_json_array_value(obj, "properties");
for (i = 0; i < json_array_size(properties); i++) { TRY {
property = get_json_array_index_object(properties, i); for (i = 0; i < json_array_size(properties); i++) {
if ( strcmp(get_json_string_value(property, "name"), key) != 0 ) { property = get_json_array_index_object(properties, i);
continue; s = get_json_string_value(property, "name");
if ( strcmp(s->data, key) != 0 ) {
heap_release_string(s);
continue;
}
heap_release_string(s);
s = get_json_string_value(property, "type");
if ( strcmp(s->data, type) != 0 ) {
THROW(EXC_ATTRIBUTEERROR, "Character property is present but is incorrect type");
}
heap_release_string(s);
json_decref(properties);
return property;
} }
if ( strcmp(get_json_string_value(property, "type"), type) != 0 ) { } FINALLY {
THROW(EXC_ATTRIBUTEERROR, "Character property is present but is incorrect type"); heap_release_string(s);
} json_decref(properties);
return property; } ETRY;
}
THROW(EXC_KEYERROR, "Property not found in properties map"); THROW(EXC_KEYERROR, "Property not found in properties map");
} }
static const char *get_json_properties_string(json_t *obj, char *key) static string *get_json_properties_string(json_t *obj, char *key)
{ {
json_t *property = get_json_tilemap_property(obj, key, "string"); json_t *property = get_json_tilemap_property(obj, key, "string");
return get_json_string_value(property, "value"); string *s = get_json_string_value(property, "value");;
json_decref(property);
return s;
} }
static int get_json_properties_integer(json_t *obj, char *key) static int get_json_properties_integer(json_t *obj, char *key)
{ {
json_t *property = get_json_tilemap_property(obj, key, "int"); json_t *property = get_json_tilemap_property(obj, key, "int");
return get_json_integer_value(property, "value"); int i = get_json_integer_value(property, "value");
json_decref(property);
return i;
} }
static void tilemap_load_tilesets(tilemap *dest, json_t *root) static void tilemap_load_tilesets(tilemap *dest, json_t *root)
@@ -50,6 +70,7 @@ static void tilemap_load_tilesets(tilemap *dest, json_t *root)
THROW_ZERO(dest, EXC_NULLPOINTER, "Received NULL tilemap pointer"); THROW_ZERO(dest, EXC_NULLPOINTER, "Received NULL tilemap pointer");
THROW_ZERO(root, EXC_NULLPOINTER, "Received NULL json object pointer"); THROW_ZERO(root, EXC_NULLPOINTER, "Received NULL json object pointer");
char *asset_path; char *asset_path;
string *s;
json_t *tilesets = get_json_array_value(root, "tilesets"); json_t *tilesets = get_json_array_value(root, "tilesets");
json_t *tileset; json_t *tileset;
int i; int i;
@@ -71,18 +92,22 @@ static void tilemap_load_tilesets(tilemap *dest, json_t *root)
dest->tilesets[i].tilecount = get_json_integer_value(tileset, "tilecount"); dest->tilesets[i].tilecount = get_json_integer_value(tileset, "tilecount");
dest->tilesets[i].tileheight = get_json_integer_value(tileset, "tileheight"); dest->tilesets[i].tileheight = get_json_integer_value(tileset, "tileheight");
dest->tilesets[i].tilewidth = get_json_integer_value(tileset, "tilewidth"); dest->tilesets[i].tilewidth = get_json_integer_value(tileset, "tilewidth");
s = get_json_string_value(tileset, "name");
strncpy((char *)&dest->tilesets[i].name, strncpy((char *)&dest->tilesets[i].name,
get_json_string_value(tileset, "name"), s->data,
TILEMAP_MAX_TILESET_NAME_SIZE TILEMAP_MAX_TILESET_NAME_SIZE
); );
heap_release_string(s);
s = get_json_string_value(tileset, "image");
snprintf((char *)&dest->tilesets[i].imagefilename, snprintf((char *)&dest->tilesets[i].imagefilename,
TILEMAP_MAX_TILESET_FILENAME_SIZE, TILEMAP_MAX_TILESET_FILENAME_SIZE,
"%s%s", "%s%s",
SDL_GetBasePath(), SDL_GetBasePath(),
get_json_string_value(tileset, "image") s->data
); );
heap_release_string(s);
dest->tilesets[i].texture = IMG_LoadTexture(renderer, (char *)&dest->tilesets[i].imagefilename); dest->tilesets[i].texture = IMG_LoadTexture(renderer, (char *)&dest->tilesets[i].imagefilename);
THROW_ZERO(dest->tilesets[i].texture, EXC_NULLPOINTER, "Failed loading tileset image"); THROW_ZERO(dest->tilesets[i].texture, EXC_NULLPOINTER, "Failed loading tileset image");
@@ -130,8 +155,10 @@ static void tilemap_load_tilesets(tilemap *dest, json_t *root)
y_offset);*/ y_offset);*/
} }
// SDL_Log("Processed %d total tiles for tileset", j); // SDL_Log("Processed %d total tiles for tileset", j);
json_decref(tileset);
dest->numtilesets += 1; dest->numtilesets += 1;
} }
json_decref(tilesets);
} }
static void tilemap_load_layer_objects(tilemap *dest, json_t *root, int layerid) static void tilemap_load_layer_objects(tilemap *dest, json_t *root, int layerid)
@@ -141,6 +168,8 @@ static void tilemap_load_layer_objects(tilemap *dest, json_t *root, int layerid)
int j; int j;
int len; int len;
actor *actorobj; actor *actorobj;
string *s;
string *sc;
tilemap_layer *curlayer; tilemap_layer *curlayer;
tilemap_object *curobj; tilemap_object *curobj;
const char *charptr; const char *charptr;
@@ -155,11 +184,14 @@ static void tilemap_load_layer_objects(tilemap *dest, json_t *root, int layerid)
for ( j = 0; j < len; j++ ) { for ( j = 0; j < len; j++ ) {
layerdatavalue = get_json_array_index_object(layerdata, j); layerdatavalue = get_json_array_index_object(layerdata, j);
curobj = &curlayer->objects[j]; curobj = &curlayer->objects[j];
strncpy(curobj->name, get_json_string_value(layerdatavalue, "name"), SPRITE_MAX_ACTOR_NAME_LENGTH); s = get_json_string_value(layerdatavalue, "name");
strncpy(curobj->name, s->data, SPRITE_MAX_ACTOR_NAME_LENGTH);
heap_release_string(s);
curobj->x = (int) get_json_number_value(layerdatavalue, "x"); curobj->x = (int) get_json_number_value(layerdatavalue, "x");
curobj->y = (int) get_json_number_value(layerdatavalue, "y"); curobj->y = (int) get_json_number_value(layerdatavalue, "y");
curobj->visible = get_json_boolean_value(layerdatavalue, "visible"); curobj->visible = get_json_boolean_value(layerdatavalue, "visible");
if ( strcmp((char *)get_json_string_value(layerdatavalue, "type"), "actor") == 0 ) { s = get_json_string_value(layerdatavalue, "type");
if ( strcmp(s->data, "actor") == 0 ) {
curobj->type = TILEMAP_OBJECT_TYPE_ACTOR; curobj->type = TILEMAP_OBJECT_TYPE_ACTOR;
if ( strlen((char *)&curobj->name) == 0 ) { if ( strlen((char *)&curobj->name) == 0 ) {
THROW(EXC_KEYERROR, "Actor in tile object layer cannot have empty name"); THROW(EXC_KEYERROR, "Actor in tile object layer cannot have empty name");
@@ -167,8 +199,10 @@ static void tilemap_load_layer_objects(tilemap *dest, json_t *root, int layerid)
actorobj = SDL_GetPointerProperty(REGISTRY_ACTOR, (char *)&curobj->name, NULL); actorobj = SDL_GetPointerProperty(REGISTRY_ACTOR, (char *)&curobj->name, NULL);
if ( actorobj == NULL ) { if ( actorobj == NULL ) {
actorobj = heap_next_actor(); actorobj = heap_next_actor();
sc = get_json_properties_string(layerdatavalue, "character");
actor_initialize(actorobj, (char *)&curobj->name); actor_initialize(actorobj, (char *)&curobj->name);
actor_set_character(actorobj, (char *)get_json_properties_string(layerdatavalue, "character")); actor_set_character(actorobj, sc->data);
heap_release_string(sc);
} else { } else {
actorobj->refcount += 1; actorobj->refcount += 1;
} }
@@ -182,6 +216,7 @@ static void tilemap_load_layer_objects(tilemap *dest, json_t *root, int layerid)
json_decref(layerdatavalue); json_decref(layerdatavalue);
} }
} FINALLY { } FINALLY {
heap_release_string(s);
if ( layerdatavalue != NULL ) { if ( layerdatavalue != NULL ) {
json_decref(layerdatavalue); json_decref(layerdatavalue);
} }
@@ -208,6 +243,7 @@ static void tilemap_load_layer_tile(tilemap *dest, json_t *root, int layerid)
json_decref(layerdata); json_decref(layerdata);
THROW(EXC_OUTOFBOUNDS, "Map layer exceeds the maximum size"); THROW(EXC_OUTOFBOUNDS, "Map layer exceeds the maximum size");
} }
TRY {
for ( j = 0; j < layerdatalen; j++ ) { for ( j = 0; j < layerdatalen; j++ ) {
layerdatavalue = json_array_get(layerdata, j); layerdatavalue = json_array_get(layerdata, j);
if (!json_is_integer(layerdatavalue)) { if (!json_is_integer(layerdatavalue)) {
@@ -218,7 +254,12 @@ static void tilemap_load_layer_tile(tilemap *dest, json_t *root, int layerid)
dest->layers[layerid].data[j] = json_integer_value(layerdatavalue); dest->layers[layerid].data[j] = json_integer_value(layerdatavalue);
json_decref(layerdatavalue); json_decref(layerdatavalue);
} }
json_decref(layerdata); } FINALLY {
if ( layerdatavalue != NULL ) {
json_decref(layerdatavalue);
json_decref(layerdata);
}
} ETRY;
} }
static void tilemap_load_layers(tilemap *dest, json_t *root) static void tilemap_load_layers(tilemap *dest, json_t *root)
@@ -227,41 +268,47 @@ static void tilemap_load_layers(tilemap *dest, json_t *root)
THROW_ZERO(root, EXC_NULLPOINTER, "tilemap_load_layers received NULL json object pointer"); THROW_ZERO(root, EXC_NULLPOINTER, "tilemap_load_layers received NULL json object pointer");
json_t *layers = get_json_array_value(root, "layers"); json_t *layers = get_json_array_value(root, "layers");
json_t *layer; json_t *layer;
string *s;
const char *layertype = NULL; const char *layertype = NULL;
int i; int i;
dest->numlayers = json_array_size(layers); dest->numlayers = json_array_size(layers);
for ( i = 0; i < dest->numlayers; i++) { TRY {
if ( i >= TILEMAP_MAX_LAYERS ) { for ( i = 0; i < dest->numlayers; i++) {
json_decref(layers); if ( i >= TILEMAP_MAX_LAYERS ) {
THROW(EXC_OUTOFBOUNDS, "Map exceeds the maximum number of layers"); THROW(EXC_OUTOFBOUNDS, "Map exceeds the maximum number of layers");
} }
layer = get_json_array_index_object(layers, i); layer = get_json_array_index_object(layers, i);
if ( (get_json_integer_value(layer, "id") - 1) != i ) { if ( (get_json_integer_value(layer, "id") - 1) != i ) {
// TileD's map layer IDs start at 1, not 0, and are sequential but not necessarily contiguous. We may have a gap in IDs. // TileD's map layer IDs start at 1, not 0, and are sequential but not necessarily contiguous. We may have a gap in IDs.
continue; json_decref(layer);
} continue;
}
dest->layers[i].opacity = get_json_number_value(layer, "opacity");
dest->layers[i].visible = get_json_boolean_value(layer, "visible"); dest->layers[i].opacity = get_json_number_value(layer, "opacity");
dest->layers[i].id = get_json_integer_value(layer, "id"); dest->layers[i].visible = get_json_boolean_value(layer, "visible");
dest->layers[i].x = get_json_integer_value(layer, "x"); dest->layers[i].id = get_json_integer_value(layer, "id");
dest->layers[i].y = get_json_integer_value(layer, "y"); dest->layers[i].x = get_json_integer_value(layer, "x");
dest->layers[i].y = get_json_integer_value(layer, "y");
TRY {
layertype = get_json_string_value(layer, "type"); TRY {
if ( strncmp(layertype, "objectgroup", strlen(layertype)) == 0 ) { s = get_json_string_value(layer, "type");
if ( strncmp(s->data, "objectgroup", strlen(s->data)) == 0 ) {
dest->layers[i].type = TILEMAP_LAYER_TYPE_OBJECTS; dest->layers[i].type = TILEMAP_LAYER_TYPE_OBJECTS;
tilemap_load_layer_objects(dest, layer, i); tilemap_load_layer_objects(dest, layer, i);
} else if ( strncmp(layertype, "tilelayer", strlen(layertype)) == 0 ) { } else if ( strncmp(s->data, "tilelayer", strlen(s->data)) == 0 ) {
dest->layers[i].type = TILEMAP_LAYER_TYPE_TILES; dest->layers[i].type = TILEMAP_LAYER_TYPE_TILES;
tilemap_load_layer_tile(dest, layer, i); tilemap_load_layer_tile(dest, layer, i);
} }
} FINALLY { } FINALLY {
heap_release_string(s);
json_decref(layer); json_decref(layer);
json_decref(layers); } ETRY;
} ETRY; }
} } FINALLY {
json_decref(layers);
} ETRY;
} }
void tilemap_load(char *fname, tilemap *dest) void tilemap_load(char *fname, tilemap *dest)
@@ -274,13 +321,17 @@ void tilemap_load(char *fname, tilemap *dest)
THROW_ZERO(dest, EXC_NULLPOINTER, "load_tilemap received null tilemap"); THROW_ZERO(dest, EXC_NULLPOINTER, "load_tilemap received null tilemap");
memset(dest, 0x00, sizeof(tilemap)); memset(dest, 0x00, sizeof(tilemap));
SDL_asprintf(&asset_path, "%s%s", SDL_GetBasePath(), fname); TRY {
json = json_load_file(asset_path, 0, &error); SDL_asprintf(&asset_path, "%s%s", SDL_GetBasePath(), fname);
if (!json) { json = json_load_file(asset_path, 0, &error);
SDL_Log("Error while loading tilemap from %s on line %d: %s", asset_path, error.line, error.text); if (!json) {
THROW(EXC_NULLPOINTER, "Loading JSON tilemap failed"); SDL_Log("Error while loading tilemap from %s on line %d: %s", asset_path, error.line, error.text);
} THROW(EXC_NULLPOINTER, "Loading JSON tilemap failed");
}
} FINALLY {
SDL_free(asset_path);
} ETRY;
TRY { TRY {
dest->tileheight = get_json_integer_value(json, "tileheight"); dest->tileheight = get_json_integer_value(json, "tileheight");