Compare commits
5 Commits
memorymana
...
nomoreexcl
| Author | SHA1 | Date | |
|---|---|---|---|
| a1a243b2b2 | |||
| 1e0d22d4e1 | |||
| ab51822caf | |||
| e860c84bd1 | |||
| 29cc3c341d |
2
Makefile
2
Makefile
@@ -35,4 +35,4 @@ src/%.o: src/%.c
|
||||
$(CC) -c -o $@ $(CFLAGS) $(SDLFLAGS_CC) $?
|
||||
|
||||
$(DISTFILE): $(OBJFILES)
|
||||
$(CC) -o $@ $^ -lexc -lbox2d -ljansson -lhashmap -lm $(SDLFLAGS_LD)
|
||||
$(CC) -o $@ $^ -lbox2d -ljansson -lhashmap -lm $(SDLFLAGS_LD)
|
||||
|
||||
62
src/assets.c
62
src/assets.c
@@ -1,45 +1,53 @@
|
||||
#include <SDL3/SDL.h>
|
||||
#include <SDL3_image/SDL_image.h>
|
||||
#include <SDL3_mixer/SDL_mixer.h>
|
||||
#include <SDL3/SDL_stdinc.h>
|
||||
#include <aklabs/exclib.h>
|
||||
#include "game.h"
|
||||
#include "error.h"
|
||||
#include "string.h"
|
||||
#include "heap.h"
|
||||
|
||||
void load_frame_from_image(char *fname, GAME_frame *frame)
|
||||
ErrorContext *load_frame_from_image(char *fname, GAME_frame *frame)
|
||||
{
|
||||
char *asset_path = NULL;
|
||||
PREPARE_ERROR(errctx);
|
||||
string *tmpstr = NULL;
|
||||
SDL_Texture *tex = NULL;
|
||||
|
||||
THROW_ZERO(frame, EXC_NULLPOINTER, "load_frame_from_image received NULL frame");
|
||||
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;
|
||||
FAIL_ZERO_RETURN(errctx, frame, ERR_NULLPOINTER, "load_frame_from_image received NULL frame");
|
||||
FAIL_ZERO_RETURN(errctx, frame, ERR_NULLPOINTER, "load_frame_from_image received NULL filename");
|
||||
errctx = heap_next_string(&tmpstr);
|
||||
FAIL_ZERO_RETURN(errctx, tmpstr, ERR_NULLPOINTER, "%s", errctx->message);
|
||||
string_initialize(tmpstr, NULL);
|
||||
|
||||
SDL_snprintf((char *)&tmpstr->data, MAX_STRING_LENGTH, "%s%s", SDL_GetBasePath(), fname);
|
||||
tex = IMG_LoadTexture(renderer, (char *)&tmpstr->data);
|
||||
|
||||
FAIL_ZERO_RETURN(errctx, tex, ERR_NULLPOINTER, "Failed loading asset");
|
||||
|
||||
frame->texture = tex;
|
||||
SDL_GetTextureSize(tex, &frame->w, &frame->h);
|
||||
heap_release_string(tmpstr);
|
||||
RELEASE_ERROR(errctx);
|
||||
}
|
||||
|
||||
void load_start_bgm(char *fname)
|
||||
ErrorContext *load_start_bgm(char *fname)
|
||||
{
|
||||
PREPARE_ERROR(errctx);
|
||||
char *asset_path = NULL;
|
||||
string *tmpstr = NULL;
|
||||
|
||||
THROW_ZERO(fname, EXC_NULLPOINTER, "load_start_bgm received NULL filename");
|
||||
FAIL_ZERO_RETURN(errctx, fname, ERR_NULLPOINTER, "load_start_bgm received NULL filename");
|
||||
errctx = heap_next_string(&tmpstr);
|
||||
FAIL_ZERO_RETURN(errctx, tmpstr, ERR_NULLPOINTER, "%s", errctx->message);
|
||||
string_initialize(tmpstr, NULL);
|
||||
|
||||
TRY {
|
||||
SDL_asprintf(&asset_path, "%s%s", SDL_GetBasePath(), fname);
|
||||
SDL_Log("Loading music asset from %s", asset_path);
|
||||
bgm = Mix_LoadMUS(asset_path);
|
||||
THROW_ZERO(bgm, EXC_NULLPOINTER, "Failed to load music asset");
|
||||
if (!Mix_PlayMusic(bgm, 0)) {
|
||||
THROW(EXC_SDL_MUSICMIXER, "Failed to play music asset");
|
||||
}
|
||||
} FINALLY {
|
||||
SDL_free(asset_path);
|
||||
} ETRY;
|
||||
SDL_snprintf((char *)&tmpstr->data, MAX_STRING_LENGTH, "%s%s", SDL_GetBasePath(), fname);
|
||||
SDL_Log("Loading music asset from %s", (char *)&tmpstr->data);
|
||||
bgm = Mix_LoadMUS(asset_path);
|
||||
FAIL_ZERO_RETURN(errctx, bgm, ERR_NULLPOINTER, "Failed to load music asset");
|
||||
|
||||
if (!Mix_PlayMusic(bgm, 0)) {
|
||||
FAIL_RETURN(errctx, ERR_SDL, "Failed to play music asset %s", fname);
|
||||
}
|
||||
heap_release_string(tmpstr);
|
||||
RELEASE_ERROR(errctx);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
#ifndef _ASSETS_H_
|
||||
#define _ASSETS_H_
|
||||
|
||||
void load_frame_from_image(char *fname, GAME_frame *frame);
|
||||
void load_start_bgm(char *fname);
|
||||
#include "error.h"
|
||||
|
||||
ErrorContext *load_frame_from_image(char *fname, GAME_frame *frame);
|
||||
ErrorContext *load_start_bgm(char *fname);
|
||||
|
||||
#endif //_ASSETS_H_
|
||||
|
||||
@@ -2,18 +2,24 @@
|
||||
#include <SDL3_image/SDL_image.h>
|
||||
#include <SDL3_mixer/SDL_mixer.h>
|
||||
#include <box2d/box2d.h>
|
||||
#include <stdio.h>
|
||||
#include "game.h"
|
||||
#include "physics.h"
|
||||
#include "tilemap.h"
|
||||
#include "sprite.h"
|
||||
|
||||
#include "heap.h"
|
||||
#include "registry.h"
|
||||
#include "string.h"
|
||||
#include "error.h"
|
||||
|
||||
SDL_Window *window = NULL;
|
||||
SDL_Renderer *renderer = NULL;
|
||||
GAME_frame ball;
|
||||
GAME_frame paddle1;
|
||||
GAME_frame paddle2;
|
||||
GAME_frame table;
|
||||
tilemap gamemap;
|
||||
volatile tilemap gamemap;
|
||||
Mix_Music *bgm = NULL;
|
||||
SDL_FRect camera;
|
||||
|
||||
|
||||
16
src/game.h
16
src/game.h
@@ -3,26 +3,16 @@
|
||||
|
||||
#include <SDL3_mixer/SDL_mixer.h>
|
||||
#include "tilemap.h"
|
||||
#include <aklabs/exclib.h>
|
||||
|
||||
#define EXC_SDL_INIT (EXC_PREDEFINED_EXCEPTIONS + 1)
|
||||
#define EXC_SDL_MUSICMIXER (EXC_PREDEFINED_EXCEPTIONS + 2)
|
||||
#define EXC_GAME_UNDEFINED (EXC_PREDEFINED_EXCEPTIONS + 3)
|
||||
#define EXC_ATTRIBUTEERROR (EXC_PREDEFINED_EXCEPTIONS + 4)
|
||||
#define EXC_TYPEERROR (EXC_PREDEFINED_EXCEPTIONS + 5)
|
||||
#define EXC_KEYERROR (EXC_PREDEFINED_EXCEPTIONS + 6)
|
||||
#define EXC_HEAPERROR (EXC_PREDEFINED_EXCEPTIONS + 7)
|
||||
#define EXC_INDEXERROR (EXC_PREDEFINED_EXCEPTIONS + 8)
|
||||
|
||||
/* ==================== GAME STATE VARIABLES =================== */
|
||||
|
||||
typedef struct GAME_frame {
|
||||
typedef struct {
|
||||
float w;
|
||||
float h;
|
||||
SDL_Texture *texture;
|
||||
} GAME_frame;
|
||||
|
||||
typedef struct iterator {
|
||||
typedef struct {
|
||||
int flags;
|
||||
int layerid;
|
||||
} iterator;
|
||||
@@ -71,7 +61,7 @@ extern GAME_frame ball;
|
||||
extern GAME_frame paddle1;
|
||||
extern GAME_frame paddle2;
|
||||
extern GAME_frame table;
|
||||
extern tilemap gamemap;
|
||||
extern volatile tilemap gamemap;
|
||||
extern Mix_Music *bgm;
|
||||
extern SDL_FRect camera;
|
||||
|
||||
|
||||
139
src/heap.c
139
src/heap.c
@@ -1,10 +1,13 @@
|
||||
#include <stdlib.h>
|
||||
#include <aklabs/exclib.h>
|
||||
|
||||
#include "game.h"
|
||||
#include "sprite.h"
|
||||
#include "heap.h"
|
||||
#include "registry.h"
|
||||
#include "string.h"
|
||||
#include "error.h"
|
||||
|
||||
/* The error heap is not here - it is in error.c and error.h to prevent a circular dependency between these two headers */
|
||||
|
||||
actor HEAP_ACTOR[MAX_HEAP_ACTOR];
|
||||
sprite HEAP_SPRITE[MAX_HEAP_SPRITE];
|
||||
@@ -12,141 +15,175 @@ spritesheet HEAP_SPRITESHEET[MAX_HEAP_SPRITESHEET];
|
||||
character HEAP_CHARACTER[MAX_HEAP_CHARACTER];
|
||||
string HEAP_STRING[MAX_HEAP_STRING];
|
||||
|
||||
void heap_init()
|
||||
ErrorContext *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));
|
||||
}
|
||||
PREPARE_ERROR(errctx);
|
||||
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));
|
||||
}
|
||||
for ( i = 0; i < MAX_HEAP_ERROR; i++) {
|
||||
memset(&HEAP_ERROR[i], 0x00, sizeof(ErrorContext));
|
||||
}
|
||||
SUCCEED_RETURN(errctx);
|
||||
}
|
||||
|
||||
actor *heap_next_actor()
|
||||
ErrorContext *heap_next_actor(actor **dest)
|
||||
{
|
||||
PREPARE_ERROR(errctx);
|
||||
for (int i = 0; i < MAX_HEAP_ACTOR; i++ ) {
|
||||
if ( HEAP_ACTOR[i].refcount != 0 ) {
|
||||
continue;
|
||||
}
|
||||
return &HEAP_ACTOR[i];
|
||||
*dest = &HEAP_ACTOR[i];
|
||||
SUCCEED_RETURN(errctx);
|
||||
}
|
||||
THROW(EXC_HEAPERROR, "Unable to find unused actor on the heap");
|
||||
FAIL_RETURN(errctx, ERR_HEAP, "Unable to find unused actor on the heap");
|
||||
}
|
||||
|
||||
sprite *heap_next_sprite()
|
||||
ErrorContext *heap_next_sprite(sprite **dest)
|
||||
{
|
||||
PREPARE_ERROR(errctx);
|
||||
for (int i = 0; i < MAX_HEAP_SPRITE; i++ ) {
|
||||
if ( HEAP_SPRITE[i].refcount != 0 ) {
|
||||
continue;
|
||||
}
|
||||
return &HEAP_SPRITE[i];
|
||||
*dest = &HEAP_SPRITE[i];
|
||||
SUCCEED_RETURN(errctx);
|
||||
}
|
||||
THROW(EXC_HEAPERROR, "Unable to find unused sprite on the heap");
|
||||
FAIL_RETURN(errctx, ERR_HEAP, "Unable to find unused sprite on the heap");
|
||||
}
|
||||
|
||||
spritesheet *heap_next_spritesheet()
|
||||
ErrorContext *heap_next_spritesheet(spritesheet **dest)
|
||||
{
|
||||
PREPARE_ERROR(errctx);
|
||||
for (int i = 0; i < MAX_HEAP_SPRITESHEET; i++ ) {
|
||||
if ( HEAP_SPRITESHEET[i].refcount != 0 ) {
|
||||
continue;
|
||||
}
|
||||
return &HEAP_SPRITESHEET[i];
|
||||
*dest = &HEAP_SPRITESHEET[i];
|
||||
SUCCEED_RETURN(errctx);
|
||||
}
|
||||
THROW(EXC_HEAPERROR, "Unable to find unused spritesheet on the heap");
|
||||
FAIL_RETURN(errctx, ERR_HEAP, "Unable to find unused spritesheet on the heap");
|
||||
}
|
||||
|
||||
character *heap_next_character()
|
||||
ErrorContext *heap_next_character(character **dest)
|
||||
{
|
||||
PREPARE_ERROR(errctx);
|
||||
for (int i = 0; i < MAX_HEAP_CHARACTER; i++ ) {
|
||||
if ( HEAP_CHARACTER[i].refcount != 0 ) {
|
||||
continue;
|
||||
}
|
||||
return &HEAP_CHARACTER[i];
|
||||
*dest = &HEAP_CHARACTER[i];
|
||||
SUCCEED_RETURN(errctx);
|
||||
}
|
||||
THROW(EXC_HEAPERROR, "Unable to find unused character on the heap");
|
||||
FAIL_RETURN(errctx, ERR_HEAP, "Unable to find unused character on the heap");
|
||||
}
|
||||
|
||||
string *heap_next_string()
|
||||
ErrorContext *heap_next_string(string **dest)
|
||||
{
|
||||
PREPARE_ERROR(errctx);
|
||||
for (int i = 0; i < MAX_HEAP_STRING; i++ ) {
|
||||
if ( HEAP_STRING[i].refcount != 0 ) {
|
||||
continue;
|
||||
}
|
||||
return &HEAP_STRING[i];
|
||||
*dest = &HEAP_STRING[i];
|
||||
SUCCEED_RETURN(errctx);
|
||||
}
|
||||
THROW(EXC_HEAPERROR, "Unable to find unused string on the heap");
|
||||
FAIL_RETURN(errctx, ERR_HEAP, "Unable to find unused string on the heap");
|
||||
}
|
||||
|
||||
void heap_release_actor(actor *ptr)
|
||||
ErrorContext *heap_release_actor(actor *ptr)
|
||||
{
|
||||
THROW_ZERO(ptr, EXC_NULLPOINTER, "NULL character reference");
|
||||
PREPARE_ERROR(errctx);
|
||||
FAIL_ZERO_RETURN(errctx, ptr, ERR_NULLPOINTER, "NULL actor reference");
|
||||
if ( ptr->refcount > 0 ) {
|
||||
ptr->refcount -= 1;
|
||||
ptr->refcount -= 1;
|
||||
}
|
||||
if ( ptr->refcount == 0 ) {
|
||||
heap_release_character(ptr->basechar);
|
||||
SDL_ClearProperty(REGISTRY_ACTOR, (char *)&ptr->name);
|
||||
}
|
||||
SUCCEED_RETURN(errctx);
|
||||
}
|
||||
|
||||
void heap_release_character(character *basechar)
|
||||
ErrorContext *heap_release_character(character *basechar)
|
||||
{
|
||||
PREPARE_ERROR(errctx);
|
||||
iterator opflags;
|
||||
THROW_ZERO(basechar, EXC_NULLPOINTER, "NULL character reference");
|
||||
FAIL_ZERO_RETURN(errctx, basechar, ERR_NULLPOINTER, "NULL character reference");
|
||||
BITMASK_CLEAR(opflags.flags);
|
||||
BITMASK_ADD(opflags.flags, ITERATOR_OP_RELEASE);
|
||||
|
||||
if ( basechar->refcount > 0 ) {
|
||||
basechar->refcount -= 1;
|
||||
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);
|
||||
}
|
||||
SUCCEED_RETURN(errctx);
|
||||
}
|
||||
|
||||
void heap_release_sprite(sprite *ptr)
|
||||
ErrorContext *heap_release_sprite(sprite *ptr)
|
||||
{
|
||||
THROW_ZERO(ptr, EXC_NULLPOINTER, "Received NULL sprite reference");
|
||||
PREPARE_ERROR(errctx);
|
||||
FAIL_ZERO_RETURN(errctx, ptr, ERR_NULLPOINTER, "Received NULL sprite reference");
|
||||
if ( ptr->refcount > 0 ) {
|
||||
ptr->refcount -= 1;
|
||||
ptr->refcount -= 1;
|
||||
}
|
||||
if ( ptr->refcount == 0 ) {
|
||||
heap_release_spritesheet(ptr->sheet);
|
||||
ATTEMPT {
|
||||
CATCH(errctx, heap_release_spritesheet(ptr->sheet));
|
||||
} CLEANUP {
|
||||
} PROCESS(errctx) {
|
||||
} HANDLE(errctx, ERR_NULLPOINTER) {
|
||||
// This just means the spritesheet inside the sprite was null. It's odd,
|
||||
// but since we're releasing this and not using it, we don't care.
|
||||
// This is a noop, we do nothing.
|
||||
} FINISH(errctx, true);
|
||||
SDL_ClearProperty(REGISTRY_SPRITE, (char *)&ptr->name);
|
||||
}
|
||||
SUCCEED_RETURN(errctx);
|
||||
}
|
||||
|
||||
void heap_release_spritesheet(spritesheet *ptr)
|
||||
ErrorContext *heap_release_spritesheet(spritesheet *ptr)
|
||||
{
|
||||
THROW_ZERO(ptr, EXC_NULLPOINTER, "Received NULL spritesheet reference");
|
||||
PREPARE_ERROR(errctx);
|
||||
FAIL_ZERO_RETURN(errctx, ptr, ERR_NULLPOINTER, "Received NULL spritesheet reference");
|
||||
if ( ptr->refcount > 0 ) {
|
||||
ptr->refcount -= 1;
|
||||
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);
|
||||
}
|
||||
SUCCEED_RETURN(errctx);
|
||||
}
|
||||
|
||||
void heap_release_string(string *ptr)
|
||||
ErrorContext *heap_release_string(string *ptr)
|
||||
{
|
||||
THROW_ZERO(ptr, EXC_NULLPOINTER, "Received NULL spritesheet reference");
|
||||
PREPARE_ERROR(errctx);
|
||||
FAIL_ZERO_RETURN(errctx, ptr, ERR_NULLPOINTER, "Received NULL string reference");
|
||||
if ( ptr->refcount > 0 ) {
|
||||
ptr->refcount -= 1;
|
||||
ptr->refcount -= 1;
|
||||
}
|
||||
if ( ptr->refcount == 0 ) {
|
||||
memset(ptr->data, 0x00, MAX_STRING_LENGTH);
|
||||
}
|
||||
memset(&ptr->data, 0x00, MAX_STRING_LENGTH);
|
||||
}
|
||||
SUCCEED_RETURN(errctx);
|
||||
}
|
||||
|
||||
|
||||
24
src/heap.h
24
src/heap.h
@@ -3,6 +3,7 @@
|
||||
|
||||
#include "sprite.h"
|
||||
#include "string.h"
|
||||
#include "error.h"
|
||||
|
||||
#define MAX_HEAP_ACTOR 64
|
||||
#define MAX_HEAP_SPRITE (MAX_HEAP_ACTOR * 16)
|
||||
@@ -16,16 +17,17 @@ 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);
|
||||
ErrorContext *heap_init();
|
||||
ErrorContext *heap_next_actor(actor **dest);
|
||||
ErrorContext *heap_next_sprite(sprite **dest);
|
||||
ErrorContext *heap_next_spritesheet(spritesheet **dest);
|
||||
ErrorContext *heap_next_character(character **dest);
|
||||
ErrorContext *heap_next_string(string **dest);
|
||||
|
||||
ErrorContext *heap_release_actor(actor *ptr);
|
||||
ErrorContext *heap_release_sprite(sprite *ptr);
|
||||
ErrorContext *heap_release_spritesheet(spritesheet *ptr);
|
||||
ErrorContext *heap_release_character(character *ptr);
|
||||
ErrorContext *heap_release_string(string *ptr);
|
||||
|
||||
#endif //_HEAP_H_
|
||||
|
||||
@@ -1,82 +1,104 @@
|
||||
#include <jansson.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "json_helpers.h"
|
||||
#include "game.h"
|
||||
#include "string.h"
|
||||
#include "heap.h"
|
||||
#include "string.h"
|
||||
#include "registry.h"
|
||||
#include "error.h"
|
||||
|
||||
json_t *get_json_object_value(json_t *obj, char *key)
|
||||
ErrorContext *get_json_object_value(json_t *obj, char *key, json_t **dest)
|
||||
{
|
||||
PREPARE_ERROR(errctx);
|
||||
json_t *value = json_object_get(obj, key);
|
||||
THROW_ZERO(value, EXC_KEYERROR, "");
|
||||
THROW_ZERO(json_is_object(value), EXC_ATTRIBUTEERROR, "");
|
||||
return value;
|
||||
FAIL_ZERO_RETURN(errctx, value, ERR_KEY, "Key %s not found in object", key);
|
||||
FAIL_ZERO_RETURN(errctx, (json_is_object(value)), ERR_TYPE, "Key %s in object has incorrect type", key);
|
||||
*dest = value;
|
||||
SUCCEED_RETURN(errctx);
|
||||
}
|
||||
|
||||
bool get_json_boolean_value(json_t *obj, char *key)
|
||||
ErrorContext *get_json_boolean_value(json_t *obj, char *key, bool *dest)
|
||||
{
|
||||
PREPARE_ERROR(errctx);
|
||||
json_t *value = json_object_get(obj, key);
|
||||
THROW_ZERO(value, EXC_KEYERROR, "");
|
||||
THROW_ZERO(json_is_boolean(value), EXC_ATTRIBUTEERROR, "");
|
||||
bool i = json_boolean_value(value);
|
||||
json_decref(value);
|
||||
return i;
|
||||
FAIL_ZERO_RETURN(errctx, value, ERR_KEY, "Key %s not found in object", key);
|
||||
FAIL_ZERO_RETURN(errctx, (json_is_boolean(value)), ERR_TYPE, "Key %s in object has incorrect type", key);
|
||||
*dest = json_boolean_value(value);
|
||||
SUCCEED_RETURN(errctx);
|
||||
}
|
||||
|
||||
int get_json_integer_value(json_t *obj, char *key)
|
||||
ErrorContext *get_json_integer_value(json_t *obj, char *key, int *dest)
|
||||
{
|
||||
PREPARE_ERROR(errctx);
|
||||
json_t *value = json_object_get(obj, key);
|
||||
THROW_ZERO(value, EXC_KEYERROR, "");
|
||||
THROW_ZERO(json_is_integer(value), EXC_ATTRIBUTEERROR, "");
|
||||
int i = json_integer_value(value);
|
||||
json_decref(value);
|
||||
return i;
|
||||
FAIL_ZERO_RETURN(errctx, value, ERR_KEY, "Key %s not found in object", key);
|
||||
FAIL_ZERO_RETURN(errctx, (json_is_integer(value)), ERR_TYPE, "Key %s in object has incorrect type", key);
|
||||
*dest = json_integer_value(value);
|
||||
SUCCEED_RETURN(errctx);
|
||||
}
|
||||
|
||||
float get_json_number_value(json_t *obj, char *key)
|
||||
ErrorContext *get_json_number_value(json_t *obj, char *key, float *dest)
|
||||
{
|
||||
PREPARE_ERROR(errctx);
|
||||
FAIL_ZERO_RETURN(errctx, obj, ERR_NULLPOINTER, "NULL pointer reference");
|
||||
json_t *value = json_object_get(obj, key);
|
||||
float f;
|
||||
THROW_ZERO(value, EXC_KEYERROR, "");
|
||||
THROW_ZERO(json_is_number(value), EXC_ATTRIBUTEERROR, "");
|
||||
f = json_number_value(value);
|
||||
json_decref(value);
|
||||
return f;
|
||||
FAIL_ZERO_RETURN(errctx, value, ERR_KEY, "Key %s not found in object", key);
|
||||
FAIL_ZERO_RETURN(errctx, (json_is_number(value)), ERR_TYPE, "Key %s in object has incorrect type", key);
|
||||
*dest = json_number_value(value);
|
||||
SUCCEED_RETURN(errctx);
|
||||
}
|
||||
|
||||
string *get_json_string_value(json_t *obj, char *key)
|
||||
ErrorContext *get_json_string_value(json_t *obj, char *key, string **dest)
|
||||
{
|
||||
string *s = heap_next_string();
|
||||
PREPARE_ERROR(errctx);
|
||||
FAIL_ZERO_RETURN(errctx, obj, ERR_NULLPOINTER, "NULL pointer reference");
|
||||
json_t *value = json_object_get(obj, key);
|
||||
THROW_ZERO(value, EXC_KEYERROR, key);
|
||||
THROW_ZERO(json_is_string(value), EXC_ATTRIBUTEERROR, key);
|
||||
strncpy(s->data, (char *)json_string_value(value), MAX_STRING_LENGTH);
|
||||
json_decref(value);
|
||||
return s;
|
||||
FAIL_ZERO_RETURN(errctx, value, ERR_KEY, "Key %s not found in object", key);
|
||||
FAIL_ZERO_RETURN(errctx, (json_is_string(value)), ERR_TYPE, "Key %s in object has incorrect type", key);
|
||||
|
||||
ATTEMPT {
|
||||
if ( *dest == NULL ) {
|
||||
CATCH(errctx, heap_next_string(dest));
|
||||
CATCH(errctx, string_initialize(*dest, NULL));
|
||||
}
|
||||
} CLEANUP {
|
||||
} PROCESS(errctx) {
|
||||
} FINISH(errctx, false);
|
||||
|
||||
strncpy((char *)&(*dest)->data, json_string_value(value), MAX_STRING_LENGTH);
|
||||
SUCCEED_RETURN(errctx);
|
||||
}
|
||||
|
||||
json_t *get_json_array_value(json_t *obj, char *key)
|
||||
ErrorContext *get_json_array_value(json_t *obj, char *key, json_t **dest)
|
||||
{
|
||||
PREPARE_ERROR(errctx);
|
||||
FAIL_ZERO_RETURN(errctx, obj, ERR_NULLPOINTER, "NULL pointer reference");
|
||||
json_t *value = json_object_get(obj, key);
|
||||
THROW_ZERO(value, EXC_KEYERROR, key);
|
||||
THROW_ZERO(json_is_array(value), EXC_ATTRIBUTEERROR, key);
|
||||
return value;
|
||||
FAIL_ZERO_RETURN(errctx, value, ERR_KEY, "Key %s not found in object", key);
|
||||
FAIL_ZERO_RETURN(errctx, (json_is_array(value)), ERR_TYPE, "Key %s in object has incorrect type", key);
|
||||
*dest = value;
|
||||
SUCCEED_RETURN(errctx);
|
||||
}
|
||||
|
||||
json_t *get_json_array_index_object(json_t *array, int index)
|
||||
ErrorContext *get_json_array_index_object(json_t *array, int index, json_t **dest)
|
||||
{
|
||||
PREPARE_ERROR(errctx);
|
||||
FAIL_ZERO_RETURN(errctx, array, ERR_NULLPOINTER, "NULL pointer reference");
|
||||
json_t *value = json_array_get(array, index);
|
||||
THROW_ZERO(value, EXC_INDEXERROR, "");
|
||||
THROW_ZERO(json_is_object(value), EXC_ATTRIBUTEERROR, "");
|
||||
return value;
|
||||
FAIL_ZERO_RETURN(errctx, value, ERR_OUTOFBOUNDS, "Index %d out of bounds for array", index);
|
||||
FAIL_ZERO_RETURN(errctx, (json_is_object(value)), ERR_TYPE, "Index %d in object has incorrect type", index);
|
||||
*dest = value;
|
||||
SUCCEED_RETURN(errctx);
|
||||
}
|
||||
|
||||
int get_json_array_index_integer(json_t *array, int index)
|
||||
ErrorContext *get_json_array_index_integer(json_t *array, int index, int *dest)
|
||||
{
|
||||
int i;
|
||||
PREPARE_ERROR(errctx);
|
||||
FAIL_ZERO_RETURN(errctx, array, ERR_NULLPOINTER, "NULL pointer reference");
|
||||
json_t *value = json_array_get(array, index);
|
||||
THROW_ZERO(value, EXC_INDEXERROR, "");
|
||||
THROW_ZERO(json_is_integer(value), EXC_ATTRIBUTEERROR, "");
|
||||
i = json_integer_value(value);
|
||||
json_decref(value);
|
||||
return i;
|
||||
FAIL_ZERO_RETURN(errctx, value, ERR_OUTOFBOUNDS, "Index %d out of bounds for array", index);
|
||||
FAIL_ZERO_RETURN(errctx, (json_is_integer(value)), ERR_TYPE, "Index %d in object has incorrect type", index);
|
||||
*dest = json_integer_value(value);
|
||||
SUCCEED_RETURN(errctx);
|
||||
}
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
#ifndef _JSON_HELPERS_H_
|
||||
#define _JSON_HELPERS_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "error.h"
|
||||
#include "string.h"
|
||||
|
||||
json_t *get_json_object_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);
|
||||
float get_json_number_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_index_object(json_t *array, int index);
|
||||
int get_json_array_index_integer(json_t *array, int index);
|
||||
ErrorContext *get_json_object_value(json_t *obj, char *key, json_t **dest);
|
||||
ErrorContext *get_json_boolean_value(json_t *obj, char *key, bool *dest);
|
||||
ErrorContext *get_json_integer_value(json_t *obj, char *key, int *dest);
|
||||
ErrorContext *get_json_number_value(json_t *obj, char *key, float *dest);
|
||||
ErrorContext *get_json_string_value(json_t *obj, char *key, string **dest);
|
||||
ErrorContext *get_json_array_value(json_t *obj, char *key, json_t **dest);
|
||||
ErrorContext *get_json_array_index_object(json_t *array, int index, json_t **dest);
|
||||
ErrorContext *get_json_array_index_integer(json_t *array, int index, int *dest);
|
||||
|
||||
#endif // _JSON_HELPERS_H_
|
||||
|
||||
@@ -1,32 +1,70 @@
|
||||
#include <aklabs/exclib.h>
|
||||
#include <SDL3/SDL.h>
|
||||
#include "sprite.h"
|
||||
#include "registry.h"
|
||||
#include "game.h"
|
||||
#include "error.h"
|
||||
|
||||
SDL_PropertiesID REGISTRY_ACTOR;
|
||||
SDL_PropertiesID REGISTRY_SPRITE;
|
||||
SDL_PropertiesID REGISTRY_SPRITESHEET;
|
||||
SDL_PropertiesID REGISTRY_CHARACTER;
|
||||
|
||||
void registry_init_actor()
|
||||
ErrorContext *registry_init_actor()
|
||||
{
|
||||
PREPARE_ERROR(errctx);
|
||||
REGISTRY_ACTOR = SDL_CreateProperties();
|
||||
THROW_ZERO(REGISTRY_ACTOR, EXC_NULLPOINTER, "Error initializing actor registry");
|
||||
FAIL_ZERO_RETURN(errctx, REGISTRY_ACTOR, ERR_NULLPOINTER, "Error initializing actor registry");
|
||||
SUCCEED_RETURN(errctx);
|
||||
}
|
||||
|
||||
void registry_init_sprite()
|
||||
ErrorContext *registry_init_sprite()
|
||||
{
|
||||
PREPARE_ERROR(errctx);
|
||||
REGISTRY_SPRITE = SDL_CreateProperties();
|
||||
THROW_ZERO(REGISTRY_SPRITE, EXC_NULLPOINTER, "Error initializing sprite registry");
|
||||
FAIL_ZERO_RETURN(errctx, REGISTRY_SPRITE, ERR_NULLPOINTER, "Error initializing sprite registry");
|
||||
SUCCEED_RETURN(errctx);
|
||||
}
|
||||
|
||||
void registry_init_spritesheet()
|
||||
ErrorContext *registry_init_spritesheet()
|
||||
{
|
||||
PREPARE_ERROR(errctx);
|
||||
REGISTRY_SPRITESHEET = SDL_CreateProperties();
|
||||
THROW_ZERO(REGISTRY_SPRITESHEET, EXC_NULLPOINTER, "Error initializing spritesheet registry");
|
||||
FAIL_ZERO_RETURN(errctx, REGISTRY_SPRITESHEET, ERR_NULLPOINTER, "Error initializing spritesheet registry");
|
||||
SUCCEED_RETURN(errctx);
|
||||
}
|
||||
|
||||
void registry_init_character()
|
||||
ErrorContext *registry_init_character()
|
||||
{
|
||||
PREPARE_ERROR(errctx);
|
||||
REGISTRY_CHARACTER = SDL_CreateProperties();
|
||||
THROW_ZERO(REGISTRY_CHARACTER, EXC_NULLPOINTER, "Error initializing character registry");
|
||||
FAIL_ZERO_RETURN(errctx, REGISTRY_CHARACTER, ERR_NULLPOINTER, "Error initializing character registry");
|
||||
SUCCEED_RETURN(errctx);
|
||||
}
|
||||
|
||||
// SDL iterator so we can't return error information here, void only
|
||||
// this means we don't have anywhere to send exceptions up to, so if we hit an error, we log and exit(1) here
|
||||
void registry_iterate_actor(void *userdata, SDL_PropertiesID registry, const char *name)
|
||||
{
|
||||
PREPARE_ERROR(errctx);
|
||||
iterator *opflags = (iterator *)userdata;
|
||||
|
||||
ATTEMPT {
|
||||
FAIL_ZERO_BREAK(errctx, name, ERR_NULLPOINTER, "registry_iterate_actor received NULL property name");
|
||||
FAIL_ZERO_BREAK(errctx, opflags, ERR_NULLPOINTER, "received NULL iterator flags");
|
||||
actor *obj = (actor *)SDL_GetPointerProperty(registry, name, NULL);
|
||||
FAIL_ZERO_BREAK(errctx, obj, ERR_NULLPOINTER, "registry_iterate_actor received property name that was not in the registry");
|
||||
if ( BITMASK_HAS(opflags->flags, ITERATOR_OP_LAYERMASK) ) {
|
||||
if ( obj->layer != opflags->layerid ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( BITMASK_HAS(opflags->flags, ITERATOR_OP_UPDATE) ) {
|
||||
CATCH(errctx, actor_update(obj));
|
||||
}
|
||||
if ( BITMASK_HAS(opflags->flags, ITERATOR_OP_RENDER) ) {
|
||||
CATCH(errctx, actor_render(obj, renderer));
|
||||
}
|
||||
} CLEANUP {
|
||||
} PROCESS(errctx) {
|
||||
} FINISH_NORETURN(errctx);
|
||||
}
|
||||
|
||||
@@ -1,16 +1,18 @@
|
||||
#ifndef _REGISTRY_H_
|
||||
#define _REGISTRY_H_
|
||||
|
||||
#include "error.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();
|
||||
ErrorContext *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();
|
||||
ErrorContext *registry_init_sprite();
|
||||
ErrorContext *registry_init_spritesheet();
|
||||
ErrorContext *registry_init_character();
|
||||
|
||||
|
||||
#endif //_REGISTRY_H_
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
#include <SDL3/SDL_properties.h>
|
||||
#include <SDL3_image/SDL_image.h>
|
||||
#include <SDL3_mixer/SDL_mixer.h>
|
||||
#include <aklabs/exclib.h>
|
||||
#include <box2d/box2d.h>
|
||||
|
||||
#include "tilemap.h"
|
||||
@@ -13,24 +12,15 @@
|
||||
#include "draw.h"
|
||||
#include "assets.h"
|
||||
#include "sprite.h"
|
||||
#include "heap.h"
|
||||
#include "error.h"
|
||||
#include "registry.h"
|
||||
|
||||
SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[])
|
||||
{
|
||||
spritesheet *spritesheetptr = NULL;
|
||||
sprite *spriteptr = NULL;
|
||||
actor *actorptr = NULL;
|
||||
character *characterptr = NULL;
|
||||
|
||||
PREPARE_ERROR(errctx);
|
||||
|
||||
SDL_AudioSpec spec;
|
||||
exclib_init();
|
||||
exclib_name_exception(EXC_SDL_INIT, "SDL Initialization Failure");
|
||||
exclib_name_exception(EXC_SDL_MUSICMIXER, "SDL Music Mixer Failure");
|
||||
exclib_name_exception(EXC_GAME_UNDEFINED, "Undefined method or value");
|
||||
exclib_name_exception(EXC_ATTRIBUTEERROR, "Attribute Error");
|
||||
exclib_name_exception(EXC_TYPEERROR, "Type Error");
|
||||
exclib_name_exception(EXC_KEYERROR, "Key Error");
|
||||
|
||||
heap_init();
|
||||
registry_init_actor();
|
||||
@@ -50,6 +40,40 @@ SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[])
|
||||
return SDL_APP_FAILURE;
|
||||
}
|
||||
|
||||
ATTEMPT {
|
||||
spritesheet *sheet;
|
||||
sprite *spr;
|
||||
character *basechar;
|
||||
CATCH(errctx, heap_next_spritesheet(&sheet));
|
||||
CATCH(errctx, spritesheet_initialize(sheet, 48, 48, "../assets/Actor1.png"));
|
||||
|
||||
CATCH(errctx, heap_next_sprite(&spr));
|
||||
CATCH(errctx, sprite_initialize(spr, "tester", sheet));
|
||||
spr->frameids[0] = 13;
|
||||
spr->speed = 100;
|
||||
spr->loop = false;
|
||||
spr->loopReverse = false;
|
||||
spr->width = 48;
|
||||
spr->height = 48;
|
||||
|
||||
CATCH(errctx, heap_next_character(&basechar));
|
||||
CATCH(errctx, character_initialize(basechar, "tester"));
|
||||
CATCH(errctx, character_sprite_add(basechar, spr, (ACTOR_STATE_ALIVE | ACTOR_STATE_FACE_LEFT)));
|
||||
|
||||
CATCH(errctx, heap_next_actor(&actorptr));
|
||||
CATCH(errctx, actor_initialize((actor *)actorptr, "player"));
|
||||
actorptr->basechar = basechar;
|
||||
actorptr->visible = true;
|
||||
actorptr->x = 120;
|
||||
actorptr->y = 120;
|
||||
actorptr->layer = 0;
|
||||
actorptr->state = (ACTOR_STATE_ALIVE | ACTOR_STATE_FACE_LEFT);
|
||||
|
||||
} CLEANUP {
|
||||
} PROCESS(errctx) {
|
||||
} FINISH_NORETURN(errctx);
|
||||
|
||||
/*
|
||||
GAME_init_physics();
|
||||
|
||||
spec.freq = MIX_DEFAULT_FREQUENCY;
|
||||
@@ -66,42 +90,54 @@ SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[])
|
||||
(spec.channels > 2) ? "surround" : (spec.channels > 1) ? "stereo" : "mono");
|
||||
}
|
||||
|
||||
TRY {
|
||||
sprite_load_json("../assets/sprites/little_guy_walking_left.json");
|
||||
sprite_load_json("../assets/sprites/little_guy_facing_left.json");
|
||||
character_load_json("../assets/characters/littleguy.json");
|
||||
|
||||
actorptr = heap_next_actor();
|
||||
actor_initialize(actorptr, "player");
|
||||
actorptr->basechar = SDL_GetPointerProperty(
|
||||
REGISTRY_CHARACTER,
|
||||
"little guy",
|
||||
NULL);
|
||||
actorptr->state = (ACTOR_STATE_ALIVE | ACTOR_STATE_FACE_LEFT);
|
||||
} CATCH(EXC_NULLPOINTER) {
|
||||
SDL_Log("Attempting to load asset: %s (%s)", EXCLIB_EXCEPTION->description, SDL_GetError());
|
||||
return SDL_APP_FAILURE;
|
||||
} ETRY;
|
||||
ATTEMPT {
|
||||
CATCH(errctx, sprite_load_json("../assets/sprites/little_guy_walking_left.json"));
|
||||
CATCH(errctx, sprite_load_json("../assets/sprites/little_guy_facing_left.json"));
|
||||
CATCH(errctx, character_load_json("../assets/characters/littleguy.json"));
|
||||
CATCH(errctx, heap_next_actor(&actorptr));
|
||||
CATCH(errctx, actor_initialize((actor *)actorptr, "player"));
|
||||
actorptr->basechar = SDL_GetPointerProperty(
|
||||
REGISTRY_CHARACTER,
|
||||
"little guy",
|
||||
NULL);
|
||||
FAIL_ZERO_BREAK(errctx, actorptr->basechar, ERR_REGISTRY, "Can't load character 'little guy' from the registry");
|
||||
} CLEANUP {
|
||||
} PROCESS(errctx) {
|
||||
} HANDLE(errctx, ERR_NULLPOINTER) {
|
||||
SDL_Log("Attempting to load asset: %s (%s)", errctx->message, SDL_GetError());
|
||||
return SDL_APP_FAILURE;
|
||||
} FINISH_NORETURN(errctx);
|
||||
|
||||
actorptr->state = (ACTOR_STATE_ALIVE | ACTOR_STATE_FACE_LEFT | ACTOR_STATE_MOVING_LEFT);
|
||||
actorptr->x = 320;
|
||||
actorptr->y = 240;
|
||||
actorptr->visible = true;
|
||||
*/
|
||||
/*
|
||||
TRY {
|
||||
//load_start_bgm("../assets/nutcracker.mid");
|
||||
load_start_bgm("../assets/memories.mp3");
|
||||
} EXCEPT {
|
||||
} 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;
|
||||
} FINALLY {
|
||||
} ETRY;
|
||||
*/
|
||||
|
||||
TRY {
|
||||
tilemap_load("../assets/tilemap.tmj", &gamemap);
|
||||
} DEFAULT {
|
||||
SDL_Log("Exception while loading tilemap: %s (%s)", EXCLIB_EXCEPTION->description, SDL_GetError());
|
||||
return SDL_APP_FAILURE;
|
||||
} ETRY;
|
||||
*/
|
||||
|
||||
|
||||
ATTEMPT {
|
||||
CATCH(errctx, tilemap_load("../assets/tilemap.tmj", (tilemap *)&gamemap));
|
||||
} CLEANUP {
|
||||
} PROCESS(errctx) {
|
||||
} HANDLE_DEFAULT(errctx) {
|
||||
SDL_Log("Error while loading tilemap: %s (%s)", errctx->message, SDL_GetError());
|
||||
return SDL_APP_FAILURE;
|
||||
} FINISH_NORETURN(errctx);
|
||||
|
||||
|
||||
camera.x = 0;
|
||||
camera.y = 0;
|
||||
camera.w = 640;
|
||||
@@ -135,10 +171,10 @@ SDL_AppResult SDL_AppIterate(void *appstate)
|
||||
BITMASK_ADD(opflags.flags, ITERATOR_OP_UPDATE);
|
||||
BITMASK_ADD(opflags.flags, ITERATOR_OP_RENDER);
|
||||
|
||||
for ( i = 0; i < gamemap.numlayers; i++ ) {
|
||||
opflags.layerid = i;
|
||||
tilemap_draw(renderer, &gamemap, &camera, i);
|
||||
SDL_EnumerateProperties(REGISTRY_ACTOR, ®istry_iterate_actor, (void *)&opflags);
|
||||
for ( i = 0; i < TILEMAP_MAX_LAYERS; i++ ) {
|
||||
opflags.layerid = i;
|
||||
tilemap_draw(renderer, (tilemap *)&gamemap, &camera, i);
|
||||
SDL_EnumerateProperties(REGISTRY_ACTOR, ®istry_iterate_actor, (void *)&opflags);
|
||||
}
|
||||
SDL_RenderPresent(renderer);
|
||||
return SDL_APP_CONTINUE;
|
||||
|
||||
561
src/sprite.c
561
src/sprite.c
@@ -1,56 +1,70 @@
|
||||
#include <SDL3/SDL.h>
|
||||
#include <SDL3/SDL_stdinc.h>
|
||||
#include <SDL3_image/SDL_image.h>
|
||||
#include <box2d/box2d.h>
|
||||
#include <aklabs/exclib.h>
|
||||
#include <string.h>
|
||||
#include <jansson.h>
|
||||
#include "string.h"
|
||||
|
||||
#include "game.h"
|
||||
#include "sprite.h"
|
||||
#include "json_helpers.h"
|
||||
#include "heap.h"
|
||||
#include "registry.h"
|
||||
#include "error.h"
|
||||
|
||||
void actor_initialize(actor *obj, char *name)
|
||||
ErrorContext *actor_initialize(actor *obj, char *name)
|
||||
{
|
||||
THROW_ZERO(obj, EXC_NULLPOINTER, "actor_initialize received null actor pointer");
|
||||
THROW_ZERO(name, EXC_NULLPOINTER, "actor_initialize received null name string pointer");
|
||||
PREPARE_ERROR(errctx);
|
||||
FAIL_ZERO_RETURN(errctx, obj, ERR_NULLPOINTER, "actor_initialize received null actor pointer");
|
||||
FAIL_ZERO_RETURN(errctx, name, ERR_NULLPOINTER, "actor_initialize received null name string pointer");
|
||||
|
||||
memset(obj, sizeof(actor), 0x00);
|
||||
strncpy((char *)obj->name, name, SPRITE_MAX_ACTOR_NAME_LENGTH);
|
||||
obj->curSpriteReversing = false;
|
||||
THROW_ZERO(SDL_SetPointerProperty(REGISTRY_ACTOR, name, (void *)obj),
|
||||
EXC_KEYERROR,
|
||||
"Unable to add actor to registry");
|
||||
|
||||
FAIL_ZERO_RETURN(
|
||||
errctx,
|
||||
SDL_SetPointerProperty(REGISTRY_ACTOR, name, (void *)obj),
|
||||
ERR_KEY,
|
||||
"Unable to add actor to registry"
|
||||
);
|
||||
obj->refcount += 1;
|
||||
SDL_Log("Actor %s initialized and added to the registry", (char *)obj->name);
|
||||
SUCCEED_RETURN(errctx);
|
||||
}
|
||||
|
||||
void actor_set_character(actor *obj, char *basecharname)
|
||||
ErrorContext *actor_set_character(actor *obj, char *basecharname)
|
||||
{
|
||||
PREPARE_ERROR(errctx);
|
||||
character *basechar;
|
||||
THROW_ZERO(obj, EXC_NULLPOINTER, "Null actor reference");
|
||||
THROW_ZERO(basecharname, EXC_NULLPOINTER, "Null character reference");
|
||||
FAIL_ZERO_RETURN(errctx, obj, ERR_NULLPOINTER, "Null actor reference");
|
||||
FAIL_ZERO_RETURN(errctx, basecharname, ERR_NULLPOINTER, "Null character reference");
|
||||
|
||||
obj->basechar = SDL_GetPointerProperty(REGISTRY_CHARACTER, basecharname, NULL);
|
||||
THROW_ZERO(obj->basechar, EXC_NULLPOINTER, "Character not found in the registry");
|
||||
|
||||
FAIL_ZERO_RETURN(errctx, obj->basechar, ERR_NULLPOINTER, "Character not found in the registry");
|
||||
SUCCEED_RETURN(errctx);
|
||||
}
|
||||
|
||||
void actor_update(actor *obj)
|
||||
ErrorContext *actor_update(actor *obj)
|
||||
{
|
||||
PREPARE_ERROR(errctx);
|
||||
size_t iter = 0;
|
||||
SDL_Time curtime = 0;
|
||||
SDL_Time curtimems = 0;
|
||||
sprite *curSprite = NULL;
|
||||
|
||||
THROW_ZERO(obj, EXC_NULLPOINTER, "NULL actor reference");
|
||||
THROW_ZERO(obj->basechar, EXC_NULLPOINTER, "Actor has NULL base character reference");
|
||||
|
||||
curSprite = character_sprite_get(obj->basechar, obj->state);
|
||||
if ( curSprite == NULL ) {
|
||||
FAIL_ZERO_RETURN(errctx, obj, ERR_NULLPOINTER, "NULL actor reference");
|
||||
FAIL_ZERO_RETURN(errctx, obj->basechar, ERR_NULLPOINTER, "Actor has NULL base character reference");
|
||||
|
||||
ATTEMPT {
|
||||
CATCH(errctx, character_sprite_get(obj->basechar, obj->state, &curSprite));
|
||||
} CLEANUP {
|
||||
} PROCESS(errctx) {
|
||||
} HANDLE(errctx, ERR_KEY) {
|
||||
// TODO: Actor has no sprite matching the current state. Should we treat this as an error and throw?
|
||||
return;
|
||||
}
|
||||
SUCCEED_RETURN(errctx);
|
||||
} FINISH(errctx, true);
|
||||
|
||||
SDL_GetCurrentTime(&curtime);
|
||||
curtimems = curtime / 1000000;
|
||||
// is it time to change frames?
|
||||
@@ -80,46 +94,62 @@ void actor_update(actor *obj)
|
||||
}
|
||||
obj->curSpriteFrameTimer = curtimems;
|
||||
}
|
||||
SUCCEED_RETURN(errctx);
|
||||
}
|
||||
|
||||
bool actor_visible(actor *obj, SDL_FRect *camera)
|
||||
static ErrorContext *actor_visible(actor *obj, SDL_FRect *camera, bool *visible)
|
||||
{
|
||||
PREPARE_ERROR(errctx);
|
||||
sprite *curSprite = NULL;
|
||||
|
||||
THROW_ZERO(obj, EXC_NULLPOINTER, "NULL actor");
|
||||
THROW_ZERO(renderer, EXC_NULLPOINTER, "NULL renderer");
|
||||
THROW_ZERO(obj->basechar, EXC_NULLPOINTER, "Actor has NULL base character reference");
|
||||
FAIL_ZERO_RETURN(errctx, obj, ERR_NULLPOINTER, "NULL actor");
|
||||
FAIL_ZERO_RETURN(errctx, renderer, ERR_NULLPOINTER, "NULL renderer");
|
||||
FAIL_ZERO_RETURN(errctx, obj->basechar, ERR_NULLPOINTER, "Actor has NULL base character reference");
|
||||
|
||||
curSprite = character_sprite_get(obj->basechar, obj->state);
|
||||
if ( obj->visible == false || curSprite == NULL ) {
|
||||
ATTEMPT {
|
||||
CATCH(errctx, character_sprite_get(obj->basechar, obj->state, &curSprite));
|
||||
} CLEANUP {
|
||||
} PROCESS(errctx) {
|
||||
} HANDLE(errctx, ERR_KEY) {
|
||||
// TODO: Actor has no sprite matching the current state. Should we treat this as an error and throw?
|
||||
return false;
|
||||
}
|
||||
*visible = false;
|
||||
SUCCEED_RETURN(errctx);
|
||||
} FINISH(errctx, true);
|
||||
|
||||
if ( (obj->x < (camera->x - curSprite->width)) ||
|
||||
(obj->x > (camera->x + camera->w)) ||
|
||||
(obj->y < (camera->y - curSprite->height)) ||
|
||||
(obj->y > (camera->y + camera->h)) ) {
|
||||
SDL_Log("Actor %s is not within the visible camera", obj->name);
|
||||
return false;
|
||||
*visible = false;
|
||||
} else {
|
||||
*visible = obj->visible;
|
||||
}
|
||||
return true;
|
||||
SUCCEED_RETURN(errctx);
|
||||
}
|
||||
|
||||
void actor_render(actor *obj, SDL_Renderer *renderer)
|
||||
ErrorContext *actor_render(actor *obj, SDL_Renderer *renderer)
|
||||
{
|
||||
PREPARE_ERROR(errctx);
|
||||
sprite *curSprite = NULL;
|
||||
|
||||
THROW_ZERO(obj, EXC_NULLPOINTER, "NULL actor");
|
||||
THROW_ZERO(renderer, EXC_NULLPOINTER, "NULL renderer");
|
||||
THROW_ZERO(obj->basechar, EXC_NULLPOINTER, "Actor has NULL base character reference");
|
||||
|
||||
curSprite = character_sprite_get(obj->basechar, obj->state);
|
||||
if ( ! actor_visible(obj, &camera) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool visible;
|
||||
SDL_FRect src;
|
||||
SDL_FRect dest;
|
||||
|
||||
FAIL_ZERO_RETURN(errctx, obj, ERR_NULLPOINTER, "NULL actor");
|
||||
FAIL_ZERO_RETURN(errctx, renderer, ERR_NULLPOINTER, "NULL renderer");
|
||||
FAIL_ZERO_RETURN(errctx, obj->basechar, ERR_NULLPOINTER, "Actor has NULL base character reference");
|
||||
|
||||
ATTEMPT {
|
||||
CATCH(errctx, character_sprite_get(obj->basechar, obj->state, &curSprite));
|
||||
CATCH(errctx, actor_visible(obj, &camera, &visible));
|
||||
} CLEANUP {
|
||||
} PROCESS(errctx) {
|
||||
} FINISH(errctx, true);
|
||||
|
||||
if ( ! visible ) {
|
||||
SUCCEED_RETURN(errctx);
|
||||
}
|
||||
|
||||
src.x = curSprite->width * curSprite->frameids[obj->curSpriteFrameId];
|
||||
if ( src.x >= curSprite->sheet->texture->w ) {
|
||||
src.y = ((int)src.x / curSprite->sheet->texture->w) * curSprite->height;
|
||||
@@ -135,240 +165,283 @@ void actor_render(actor *obj, SDL_Renderer *renderer)
|
||||
dest.h = curSprite->width;
|
||||
|
||||
SDL_RenderTexture(renderer, curSprite->sheet->texture, &src, &dest);
|
||||
SUCCEED_RETURN(errctx);
|
||||
}
|
||||
|
||||
void character_load_json(char *filename)
|
||||
ErrorContext *character_initialize(character *obj, char *name)
|
||||
{
|
||||
json_t *json;
|
||||
PREPARE_ERROR(errctx);
|
||||
FAIL_ZERO_RETURN(errctx, obj, ERR_NULLPOINTER, "NULL character reference");
|
||||
FAIL_ZERO_RETURN(errctx, name, ERR_NULLPOINTER, "NULL name string pointer");
|
||||
memset(obj, sizeof(character), 0x00);
|
||||
strncpy(obj->name, name, SPRITE_MAX_CHARACTER_NAME_LENGTH);
|
||||
obj->state_sprites = SDL_CreateProperties();
|
||||
FAIL_ZERO_RETURN(errctx, obj->state_sprites, ERR_NULLPOINTER, "Unable to initialize SDL_PropertiesID for character state map");
|
||||
FAIL_ZERO_RETURN(errctx, SDL_SetPointerProperty(REGISTRY_CHARACTER, name, (void *)obj),
|
||||
ERR_KEY,
|
||||
"Unable to add character to registry");
|
||||
obj->refcount += 1;
|
||||
SUCCEED_RETURN(errctx);
|
||||
}
|
||||
|
||||
ErrorContext *character_sprite_add(character *basechar, sprite *ref, int state)
|
||||
{
|
||||
PREPARE_ERROR(errctx);
|
||||
char stateval[32];
|
||||
FAIL_ZERO_RETURN(errctx, basechar, ERR_NULLPOINTER, "NULL character reference");
|
||||
FAIL_ZERO_RETURN(errctx, ref, ERR_NULLPOINTER, "NULL sprite reference");
|
||||
memset(&stateval, 0x00, 32);
|
||||
SDL_itoa(state, (char *)&stateval, 10);
|
||||
SDL_SetPointerProperty(basechar->state_sprites, (char *)&stateval, ref);
|
||||
SUCCEED_RETURN(errctx);
|
||||
}
|
||||
|
||||
ErrorContext *character_sprite_get(character *basechar, int state, sprite **dest)
|
||||
{
|
||||
PREPARE_ERROR(errctx);
|
||||
char stateval[32];
|
||||
FAIL_ZERO_RETURN(errctx, dest, ERR_NULLPOINTER, "NULL pointer to sprite pointer (**dest)");
|
||||
FAIL_ZERO_RETURN(errctx, basechar, ERR_NULLPOINTER, "NULL character reference");
|
||||
memset(&stateval, 0x00, 32);
|
||||
SDL_itoa(state, (char *)&stateval, 10);
|
||||
*dest = (sprite *)SDL_GetPointerProperty(basechar->state_sprites, (char *)&stateval, NULL);
|
||||
FAIL_ZERO_RETURN(errctx, *dest, ERR_KEY, "Sprite for state %d not found in the registry", state);
|
||||
SUCCEED_RETURN(errctx);
|
||||
}
|
||||
|
||||
// SDL iterator so we can't return error information here, void only
|
||||
// this means we don't have anywhere to send exceptions up to, so if we hit an error, we log and exit(1) here
|
||||
void character_state_sprites_iterate(void *userdata, SDL_PropertiesID registry, const char *name)
|
||||
{
|
||||
PREPARE_ERROR(errctx);
|
||||
sprite *spriteptr;
|
||||
iterator *opflags = (iterator *)userdata;
|
||||
ATTEMPT {
|
||||
FAIL_ZERO_BREAK(errctx, opflags, ERR_NULLPOINTER, "Character state sprite iterator received null iterator op pointer");
|
||||
FAIL_ZERO_BREAK(errctx, name, ERR_NULLPOINTER, "Character state sprite iterator received null sprite name");
|
||||
spriteptr = (sprite *)SDL_GetPointerProperty(registry, name, NULL);
|
||||
FAIL_ZERO_BREAK(errctx, spriteptr, ERR_NULLPOINTER, "Character state sprite for %s not found", name);
|
||||
if ( BITMASK_HAS(opflags->flags, ITERATOR_OP_RELEASE) ) {
|
||||
CATCH(errctx, heap_release_sprite(spriteptr));
|
||||
}
|
||||
} CLEANUP {
|
||||
} PROCESS(errctx) {
|
||||
} FINISH_NORETURN(errctx);
|
||||
}
|
||||
|
||||
static ErrorContext *character_load_json_inner(json_t *json, character *obj)
|
||||
{
|
||||
PREPARE_ERROR(errctx);
|
||||
json_t *mappings;
|
||||
json_t *curmapping;
|
||||
json_error_t error;
|
||||
string *s;
|
||||
sprite *spriteptr = NULL;
|
||||
char *asset_path = NULL;
|
||||
character *obj = NULL;
|
||||
int i = 0;
|
||||
char *nameptr;
|
||||
char *spritenameptr;
|
||||
string *tmpstr;
|
||||
string *tmpstr2;
|
||||
int stateval;
|
||||
|
||||
THROW_ZERO(filename, EXC_NULLPOINTER, "Received null filename");
|
||||
obj = heap_next_character();
|
||||
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");
|
||||
ATTEMPT {
|
||||
CATCH(errctx, get_json_string_value((json_t *)json, "name", &tmpstr));
|
||||
CATCH(errctx, character_initialize((character *)obj, tmpstr->data));
|
||||
CATCH(errctx, get_json_array_value((json_t *)json, "sprite_mappings", &mappings));
|
||||
for ( i = 0; i < json_array_size((json_t *)mappings) ; i++ ) {
|
||||
CATCH(errctx, get_json_array_index_object((json_t *)mappings, i, &curmapping));
|
||||
CATCH(errctx, get_json_string_value((json_t *)curmapping, "sprite", &tmpstr));
|
||||
spriteptr = (sprite *)SDL_GetPointerProperty(
|
||||
REGISTRY_SPRITE,
|
||||
tmpstr->data,
|
||||
NULL
|
||||
);
|
||||
CATCH(errctx, get_json_string_value((json_t *)json, "name", &tmpstr2));
|
||||
CATCH(errctx, get_json_integer_value((json_t *)curmapping, "state", &stateval));
|
||||
CATCH(errctx, get_json_string_value((json_t *)curmapping, "sprite", &tmpstr));
|
||||
FAIL_ZERO_BREAK(
|
||||
errctx,
|
||||
spriteptr,
|
||||
ERR_NULLPOINTER,
|
||||
"Character %s for state %d references sprite %s but not found in the registry",
|
||||
tmpstr2->data,
|
||||
stateval,
|
||||
tmpstr->data
|
||||
);
|
||||
character_sprite_add((character *)obj, (sprite *)spriteptr, stateval);
|
||||
}
|
||||
} 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");
|
||||
TRY {
|
||||
for ( i = 0; i < json_array_size(mappings) ; i++ ) {
|
||||
curmapping = get_json_array_index_object(mappings, i);
|
||||
s = get_json_string_value(curmapping, "sprite");
|
||||
spriteptr = SDL_GetPointerProperty(
|
||||
REGISTRY_SPRITE,
|
||||
s->data,
|
||||
NULL
|
||||
);
|
||||
heap_release_string(s);
|
||||
THROW_ZERO(spriteptr, EXC_NULLPOINTER, "Character references sprite that does not exist");
|
||||
character_sprite_add(
|
||||
obj,
|
||||
spriteptr,
|
||||
get_json_integer_value(curmapping, "state")
|
||||
);
|
||||
}
|
||||
} FINALLY {
|
||||
json_decref(curmapping);
|
||||
} ETRY;
|
||||
} FINALLY {
|
||||
json_decref(mappings);
|
||||
json_decref(json);
|
||||
} ETRY;
|
||||
} CLEANUP {
|
||||
if ( tmpstr != NULL )
|
||||
heap_release_string(tmpstr);
|
||||
if ( tmpstr2 != NULL )
|
||||
heap_release_string(tmpstr2);
|
||||
} PROCESS(errctx) {
|
||||
} FINISH(errctx, true);
|
||||
}
|
||||
|
||||
void sprite_load_json(char *filename)
|
||||
ErrorContext *character_load_json(char *filename)
|
||||
{
|
||||
PREPARE_ERROR(errctx);
|
||||
json_t *json;
|
||||
json_t *spritesheet_json;
|
||||
json_t *frames;
|
||||
json_error_t error;
|
||||
string *s;
|
||||
spritesheet *sheet = NULL;
|
||||
character *obj = NULL;
|
||||
string *tmpstr = NULL;
|
||||
char *asset_path = NULL;
|
||||
sprite *obj = NULL;
|
||||
int i = 0;
|
||||
|
||||
THROW_ZERO(filename, EXC_NULLPOINTER, "Received null filename");
|
||||
obj = heap_next_sprite();
|
||||
FAIL_ZERO_RETURN(errctx, filename, ERR_NULLPOINTER, "Received null filename");
|
||||
ATTEMPT {
|
||||
CATCH(errctx, heap_next_character(&obj));
|
||||
CATCH(errctx, heap_next_string(&tmpstr));
|
||||
CATCH(errctx, string_initialize(tmpstr, NULL));
|
||||
SDL_snprintf((char *)&tmpstr->data, MAX_STRING_LENGTH, "%s%s", SDL_GetBasePath(), filename);
|
||||
json = (json_t *)json_load_file((char *)&tmpstr->data, 0, &error);
|
||||
FAIL_ZERO_BREAK(
|
||||
errctx,
|
||||
json,
|
||||
ERR_NULLPOINTER,
|
||||
"Error while loading character from %s on line %d: %s", asset_path, error.line, error.text
|
||||
);
|
||||
CATCH(errctx, character_load_json_inner(json, obj));
|
||||
} CLEANUP {
|
||||
heap_release_string(tmpstr);
|
||||
heap_release_character(obj);
|
||||
} PROCESS(errctx) {
|
||||
} FINISH(errctx, true);
|
||||
}
|
||||
|
||||
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 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 {
|
||||
spritesheet_json = get_json_object_value(json, "spritesheet");
|
||||
s = get_json_string_value(spritesheet_json, "filename");
|
||||
sheet = SDL_GetPointerProperty(
|
||||
static ErrorContext *sprite_load_json_spritesheet(json_t *json, spritesheet **sheet)
|
||||
{
|
||||
PREPARE_ERROR(errctx);
|
||||
json_t *spritesheet_json = NULL;
|
||||
int ss_frame_width = 0;
|
||||
int ss_frame_height = 0;
|
||||
string *ss_filename = NULL;
|
||||
|
||||
ATTEMPT {
|
||||
CATCH(errctx, get_json_object_value((json_t *)json, "spritesheet", &spritesheet_json));
|
||||
CATCH(errctx, get_json_string_value((json_t *)spritesheet_json, "filename", &ss_filename));
|
||||
*sheet = SDL_GetPointerProperty(
|
||||
REGISTRY_SPRITESHEET,
|
||||
s->data,
|
||||
ss_filename->data,
|
||||
NULL
|
||||
);
|
||||
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(
|
||||
obj,
|
||||
s->data,
|
||||
sheet);
|
||||
heap_release_string(s);
|
||||
} FINALLY {
|
||||
json_decref(spritesheet_json);
|
||||
} ETRY;
|
||||
if ( *sheet == NULL ) {
|
||||
CATCH(errctx, heap_next_spritesheet(sheet));
|
||||
CATCH(errctx, get_json_integer_value((json_t *)spritesheet_json, "frame_width", &ss_frame_width));
|
||||
CATCH(errctx, get_json_integer_value((json_t *)spritesheet_json, "frame_height", &ss_frame_width));
|
||||
CATCH(errctx,
|
||||
spritesheet_initialize(
|
||||
(spritesheet *)sheet,
|
||||
ss_frame_width,
|
||||
ss_frame_height,
|
||||
ss_filename->data)
|
||||
);
|
||||
}
|
||||
} CLEANUP {
|
||||
heap_release_string(ss_filename);
|
||||
} PROCESS(errctx) {
|
||||
} FINISH(errctx, true);
|
||||
|
||||
SUCCEED_RETURN(errctx);
|
||||
}
|
||||
|
||||
ErrorContext *sprite_load_json(char *filename)
|
||||
{
|
||||
PREPARE_ERROR(errctx);
|
||||
json_t *json = NULL;
|
||||
json_t *frames = NULL;
|
||||
json_error_t error;
|
||||
char *asset_path = NULL;
|
||||
sprite *obj = NULL;
|
||||
spritesheet *sheet = NULL;
|
||||
string *spritename = NULL;
|
||||
string *tmpstr = NULL;
|
||||
int i = 0;
|
||||
|
||||
FAIL_ZERO_RETURN(errctx, filename, ERR_NULLPOINTER, "Received null filename");
|
||||
ATTEMPT {
|
||||
CATCH(errctx, heap_next_sprite(&obj));
|
||||
CATCH(errctx, heap_next_string(&tmpstr));
|
||||
CATCH(errctx, string_initialize(tmpstr, NULL));
|
||||
SDL_snprintf((char *)&tmpstr->data, MAX_STRING_LENGTH, "%s%s", SDL_GetBasePath(), filename);
|
||||
json = (json_t *)json_load_file(tmpstr->data, 0, &error);
|
||||
FAIL_ZERO_BREAK(
|
||||
errctx,
|
||||
json,
|
||||
ERR_NULLPOINTER,
|
||||
"Error while loading sprite from %s on line %d: %s", tmpstr->data, error.line, error.text
|
||||
);
|
||||
|
||||
CATCH(errctx, sprite_load_json_spritesheet(json, &sheet));
|
||||
CATCH(errctx, get_json_string_value((json_t *)json, "name", &spritename));
|
||||
CATCH(errctx,
|
||||
sprite_initialize(
|
||||
(sprite *)obj,
|
||||
spritename->data,
|
||||
(spritesheet *)sheet)
|
||||
);
|
||||
|
||||
CATCH(errctx, get_json_integer_value((json_t *)json, "width", &obj->width));
|
||||
CATCH(errctx, get_json_integer_value((json_t *)json, "height", &obj->height));
|
||||
CATCH(errctx, get_json_integer_value((json_t *)json, "speed", &obj->speed));
|
||||
CATCH(errctx, get_json_boolean_value((json_t *)json, "loop", &obj->loop));
|
||||
CATCH(errctx, get_json_boolean_value((json_t *)json, "loopReverse", &obj->loopReverse));
|
||||
|
||||
obj->width = get_json_integer_value(json, "width");
|
||||
obj->height = get_json_integer_value(json, "height");
|
||||
obj->speed = get_json_integer_value(json, "speed");
|
||||
obj->loop = get_json_boolean_value(json, "loop");
|
||||
obj->loopReverse = get_json_boolean_value(json, "loopReverse");
|
||||
|
||||
frames = get_json_array_value(json, "frames");
|
||||
TRY {
|
||||
obj->frames = json_array_size(frames);
|
||||
for ( i = 0 ; i < obj->frames; i++ ) {
|
||||
obj->frameids[i] = get_json_array_index_integer(frames, i);
|
||||
}
|
||||
} FINALLY {
|
||||
json_decref(frames);
|
||||
} ETRY;
|
||||
} FINALLY {
|
||||
json_decref(json);
|
||||
} ETRY;
|
||||
CATCH(errctx, get_json_array_value((json_t *)json, "frames", &frames));
|
||||
obj->frames = json_array_size((json_t *)frames);
|
||||
for ( i = 0 ; i < obj->frames; i++ ) {
|
||||
CATCH(errctx, get_json_array_index_integer((json_t *)frames, i, &obj->frameids[i]));
|
||||
}
|
||||
} CLEANUP {
|
||||
heap_release_string(spritename);
|
||||
heap_release_string(tmpstr);
|
||||
} PROCESS(errctx) {
|
||||
} FINISH(errctx, true);
|
||||
SUCCEED_RETURN(errctx);
|
||||
}
|
||||
|
||||
void sprite_initialize(sprite *spr, char *name, spritesheet *sheet)
|
||||
ErrorContext *sprite_initialize(sprite *spr, char *name, spritesheet *sheet)
|
||||
{
|
||||
THROW_ZERO(spr, EXC_NULLPOINTER, "Null sprite reference");
|
||||
THROW_ZERO(name, EXC_NULLPOINTER, "Empty sprite name");
|
||||
THROW_ZERO(sheet, EXC_NULLPOINTER, "Null spritesheet reference");
|
||||
PREPARE_ERROR(errctx);
|
||||
FAIL_ZERO_RETURN(errctx, spr, ERR_NULLPOINTER, "Null sprite reference");
|
||||
FAIL_ZERO_RETURN(errctx, name, ERR_NULLPOINTER, "Empty sprite name");
|
||||
FAIL_ZERO_RETURN(errctx, sheet, ERR_NULLPOINTER, "Null spritesheet reference");
|
||||
|
||||
memset(spr, 0x00, sizeof(sprite));
|
||||
memcpy(spr->name, name, SPRITE_MAX_NAME_LENGTH);
|
||||
spr->sheet = sheet;
|
||||
THROW_ZERO(SDL_SetPointerProperty(REGISTRY_SPRITE, (char *)&spr->name, (void *)spr),
|
||||
EXC_KEYERROR,
|
||||
"Unable to add sprite to registry");
|
||||
FAIL_ZERO_RETURN(
|
||||
errctx,
|
||||
SDL_SetPointerProperty(REGISTRY_SPRITE, (char *)&spr->name, (void *)spr),
|
||||
ERR_KEY,
|
||||
"Unable to add sprite to registry");
|
||||
spr->refcount += 1;
|
||||
SUCCEED_RETURN(errctx);
|
||||
}
|
||||
|
||||
void spritesheet_initialize(spritesheet *sheet, short sprite_w, short sprite_h, char *filename)
|
||||
ErrorContext *spritesheet_initialize(spritesheet *sheet, int sprite_w, int sprite_h, char *filename)
|
||||
{
|
||||
char *asset_path;
|
||||
THROW_ZERO(sheet, EXC_NULLPOINTER, "Null spritesheet pointer");
|
||||
THROW_ZERO(filename, EXC_NULLPOINTER, "Null filename pointer");
|
||||
PREPARE_ERROR(errctx);
|
||||
string *tmpstr = NULL;
|
||||
FAIL_ZERO_RETURN(errctx, sheet, ERR_NULLPOINTER, "Null spritesheet pointer");
|
||||
FAIL_ZERO_RETURN(errctx, filename, ERR_NULLPOINTER, "Null filename pointer");
|
||||
errctx = heap_next_string(&tmpstr);
|
||||
FAIL_ZERO_RETURN(errctx, tmpstr, ERR_NULLPOINTER, "%s", errctx->message);
|
||||
|
||||
TRY {
|
||||
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);
|
||||
|
||||
THROW_ZERO(sheet->texture, EXC_NULLPOINTER, "Failed loading asset");
|
||||
THROW_ZERO(SDL_SetPointerProperty(REGISTRY_SPRITESHEET, sheet->name, (void *)sheet),
|
||||
EXC_KEYERROR,
|
||||
"Unable to add spritesheet to registry");
|
||||
string_initialize(tmpstr, NULL);
|
||||
memset(sheet, 0x00, sizeof(sheet));
|
||||
|
||||
snprintf((char *)&tmpstr->data, MAX_STRING_LENGTH, "%s%s", SDL_GetBasePath(), filename);
|
||||
sheet->texture = IMG_LoadTexture(renderer, (char *)&tmpstr->data);
|
||||
heap_release_string(tmpstr);
|
||||
strncpy((char *)&sheet->name, filename, SPRITE_SHEET_MAX_FILENAME_LENGTH);
|
||||
|
||||
FAIL_ZERO_RETURN(errctx, sheet->texture, ERR_NULLPOINTER, "Failed loading asset");
|
||||
FAIL_ZERO_RETURN(
|
||||
errctx,
|
||||
SDL_SetPointerProperty(REGISTRY_SPRITESHEET, (char *)sheet->name, (void *)sheet),
|
||||
ERR_KEY,
|
||||
"Unable to add spritesheet to registry: %s",
|
||||
SDL_GetError());
|
||||
sheet->refcount += 1;
|
||||
SUCCEED_RETURN(errctx);
|
||||
}
|
||||
|
||||
void registry_iterate_actor(void *userdata, SDL_PropertiesID registry, const char *name)
|
||||
{
|
||||
iterator *opflags = (iterator *)userdata;
|
||||
THROW_ZERO(name, EXC_NULLPOINTER, "registry_iterate_actor received NULL property name");
|
||||
THROW_ZERO(opflags, EXC_NULLPOINTER, "received NULL iterator flags");
|
||||
actor *obj = (actor *)SDL_GetPointerProperty(registry, name, NULL);
|
||||
THROW_ZERO(obj, EXC_NULLPOINTER, "registry_iterate_actor received property name that was not in the registry");
|
||||
if ( BITMASK_HAS(opflags->flags, ITERATOR_OP_LAYERMASK) ) {
|
||||
if ( obj->layer != opflags->layerid ) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if ( BITMASK_HAS(opflags->flags, ITERATOR_OP_UPDATE) ) {
|
||||
actor_update(obj);
|
||||
}
|
||||
if ( BITMASK_HAS(opflags->flags, ITERATOR_OP_RENDER) ) {
|
||||
actor_render(obj, renderer);
|
||||
}
|
||||
}
|
||||
|
||||
void character_initialize(character *obj, char *name)
|
||||
{
|
||||
THROW_ZERO(obj, EXC_NULLPOINTER, "NULL character reference");
|
||||
THROW_ZERO(name, EXC_NULLPOINTER, "NULL name string pointer");
|
||||
memset(obj, sizeof(character), 0x00);
|
||||
strncpy(obj->name, name, SPRITE_MAX_CHARACTER_NAME_LENGTH);
|
||||
obj->state_sprites = SDL_CreateProperties();
|
||||
THROW_ZERO(obj->state_sprites, EXC_NULLPOINTER, "Unable to initialize SDL_PropertiesID for character state map");
|
||||
THROW_ZERO(SDL_SetPointerProperty(REGISTRY_CHARACTER, name, (void *)obj),
|
||||
EXC_KEYERROR,
|
||||
"Unable to add character to registry");
|
||||
obj->refcount += 1;
|
||||
}
|
||||
|
||||
void character_sprite_add(character *basechar, sprite *ref, int state)
|
||||
{
|
||||
char stateval[32];
|
||||
THROW_ZERO(basechar, EXC_NULLPOINTER, "NULL character reference");
|
||||
THROW_ZERO(ref, EXC_NULLPOINTER, "NULL sprite reference");
|
||||
memset(&stateval, 0x00, 32);
|
||||
snprintf((char *)&stateval, 32, "%d", state);
|
||||
SDL_SetPointerProperty(basechar->state_sprites, (char *)&stateval, ref);
|
||||
}
|
||||
|
||||
sprite *character_sprite_get(character *basechar, int state)
|
||||
{
|
||||
char stateval[32];
|
||||
THROW_ZERO(basechar, EXC_NULLPOINTER, "NULL character reference");
|
||||
memset(&stateval, 0x00, 32);
|
||||
snprintf((char *)&stateval, 32, "%d", state);
|
||||
return (sprite *)SDL_GetPointerProperty(basechar->state_sprites, (char *)&stateval, NULL);
|
||||
}
|
||||
|
||||
void character_state_sprites_iterate(void *userdata, SDL_PropertiesID registry, const char *name)
|
||||
{
|
||||
sprite *spriteptr;
|
||||
iterator *opflags = (iterator *)userdata;
|
||||
THROW_ZERO(opflags, EXC_NULLPOINTER, "Iterator received NULL iterator flags");
|
||||
THROW_ZERO(name, EXC_NULLPOINTER, "Iterator received NULL property name");
|
||||
spriteptr = (sprite *)SDL_GetPointerProperty(registry, name, NULL);
|
||||
THROW_ZERO(spriteptr, EXC_NULLPOINTER, "Iterator received property name that was not in the registry");
|
||||
if ( BITMASK_HAS(opflags->flags, ITERATOR_OP_RELEASE) ) {
|
||||
heap_release_sprite(spriteptr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
66
src/sprite.h
66
src/sprite.h
@@ -3,7 +3,7 @@
|
||||
|
||||
#include <box2d/box2d.h>
|
||||
#include <SDL3/SDL_properties.h>
|
||||
#include <SDL3/SDL.h>
|
||||
#include "error.h"
|
||||
|
||||
#define ACTOR_STATE_FACE_DOWN 1 // 1
|
||||
#define ACTOR_STATE_FACE_LEFT 1 << 1 // 2
|
||||
@@ -45,22 +45,27 @@
|
||||
#define SPRITE_MAX_ACTOR_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 {
|
||||
int refcount;
|
||||
SDL_Texture *texture;
|
||||
char name[SPRITE_SHEET_MAX_FILENAME_LENGTH];
|
||||
short sprite_w;
|
||||
short sprite_h;
|
||||
int sprite_w;
|
||||
int sprite_h;
|
||||
} spritesheet;
|
||||
|
||||
typedef struct {
|
||||
int refcount;
|
||||
spritesheet *sheet;
|
||||
short frameids[SPRITE_MAX_FRAMES]; // which IDs on the spritesheet belong to our frames
|
||||
short frames; // how many frames are in this animation
|
||||
short width;
|
||||
short height;
|
||||
short speed; // how many milliseconds a given sprite frame should be visible before cycling
|
||||
int frameids[SPRITE_MAX_FRAMES]; // which IDs on the spritesheet belong to our frames
|
||||
int frames; // how many frames are in this animation
|
||||
int width;
|
||||
int height;
|
||||
int speed; // how many milliseconds a given sprite frame should be visible before cycling
|
||||
bool loop; // when this sprite is done playing, it should immediately start again
|
||||
bool loopReverse; // when this sprite is done playing, it should go in reverse order through its frames
|
||||
char name[SPRITE_MAX_NAME_LENGTH];
|
||||
@@ -76,10 +81,10 @@ typedef struct {
|
||||
int refcount;
|
||||
char name[SPRITE_MAX_ACTOR_NAME_LENGTH];
|
||||
character *basechar;
|
||||
short curSpriteFrameId;
|
||||
int curSpriteFrameId;
|
||||
SDL_Time curSpriteFrameTimer;
|
||||
bool curSpriteReversing;
|
||||
short layer;
|
||||
int layer;
|
||||
b2BodyId physicsId;
|
||||
b2Polygon physicsBox;
|
||||
int state;
|
||||
@@ -89,21 +94,40 @@ typedef struct {
|
||||
int y;
|
||||
} actor;
|
||||
|
||||
void actor_initialize(actor *obj, char *name);
|
||||
void actor_set_character(actor *obj, char *basecharname);
|
||||
void actor_render(actor *obj, SDL_Renderer *renderer);
|
||||
void actor_update(actor *obj);
|
||||
ErrorContext *actor_initialize(actor *obj, char *name);
|
||||
ErrorContext *actor_set_character(actor *obj, char *basecharname);
|
||||
ErrorContext *actor_render(actor *obj, SDL_Renderer *renderer);
|
||||
ErrorContext *actor_update(actor *obj);
|
||||
|
||||
void character_initialize(character *basechar, char *name);
|
||||
void character_sprite_add(character *basechar, sprite *ref, int state);
|
||||
sprite *character_sprite_get(character *basechar, int state);
|
||||
ErrorContext *character_initialize(character *basechar, char *name);
|
||||
ErrorContext *character_sprite_add(character *basechar, sprite *ref, int state);
|
||||
ErrorContext *character_sprite_get(character *basechar, int state, sprite **dest);
|
||||
|
||||
// This is an SDL iterator so we can't return our error state from it.
|
||||
void character_state_sprites_iterate(void *userdata, SDL_PropertiesID props, const char *name);
|
||||
void character_load_json(char *filename);
|
||||
|
||||
ErrorContext *character_load_json(char *filename);
|
||||
|
||||
// initializes a new sprite to use the given sheet and otherwise sets to zero
|
||||
void sprite_initialize(sprite *spr, char *name, spritesheet *sheet);
|
||||
ErrorContext *sprite_initialize(sprite *spr, char *name, spritesheet *sheet);
|
||||
// loads a given image file into a new spritesheet
|
||||
void spritesheet_initialize(spritesheet *sheet, short sprite_w, short sprite_h, char *filename);
|
||||
void sprite_load_json(char *filename);
|
||||
ErrorContext *spritesheet_initialize(spritesheet *sheet, int sprite_w, int sprite_h, char *filename);
|
||||
ErrorContext *sprite_load_json(char *filename);
|
||||
|
||||
ErrorContext *registry_init_actor();
|
||||
ErrorContext *registry_init_sprite();
|
||||
ErrorContext *registry_init_spritesheet();
|
||||
ErrorContext *registry_init_character();
|
||||
|
||||
ErrorContext *heap_init();
|
||||
ErrorContext *heap_next_actor(actor **dest);
|
||||
ErrorContext *heap_next_sprite(sprite **dest);
|
||||
ErrorContext *heap_next_spritesheet(spritesheet **dest);
|
||||
ErrorContext *heap_next_character(character **dest);
|
||||
|
||||
ErrorContext *heap_release_actor(actor *ptr);
|
||||
ErrorContext *heap_release_sprite(sprite *ptr);
|
||||
ErrorContext *heap_release_spritesheet(spritesheet *ptr);
|
||||
ErrorContext *heap_release_character(character *ptr);
|
||||
|
||||
#endif //_SPRITE_H_
|
||||
|
||||
13
src/string.c
13
src/string.c
@@ -1,12 +1,15 @@
|
||||
#include "string.h"
|
||||
#include <aklabs/exclib.h>
|
||||
#include "error.h"
|
||||
|
||||
void string_initialize(string *obj, char *init)
|
||||
ErrorContext *string_initialize(string *obj, char *init)
|
||||
{
|
||||
THROW_ZERO(obj, EXC_NULLPOINTER, "Attempted to initialize NULL string reference");
|
||||
PREPARE_ERROR(errctx);
|
||||
FAIL_ZERO_RETURN(errctx, obj, ERR_NULLPOINTER, "Attempted to initialize NULL string reference");
|
||||
if ( init != NULL ) {
|
||||
strncpy(obj->data, init, MAX_STRING_LENGTH);
|
||||
strncpy((char *)&obj->data, init, MAX_STRING_LENGTH);
|
||||
} else {
|
||||
memset(obj->data, 0x00, sizeof(string));
|
||||
memset(&obj->data, 0x00, sizeof(string));
|
||||
}
|
||||
obj->refcount = 1;
|
||||
SUCCEED_RETURN(errctx);
|
||||
}
|
||||
|
||||
@@ -1,14 +1,17 @@
|
||||
#ifndef _STRING_H_
|
||||
#define _STRING_H_
|
||||
|
||||
#include "string.h"
|
||||
#include "error.h"
|
||||
|
||||
#define MAX_STRING_LENGTH 256
|
||||
|
||||
typedef struct string
|
||||
typedef struct
|
||||
{
|
||||
int refcount;
|
||||
char data[MAX_STRING_LENGTH];
|
||||
} string;
|
||||
|
||||
void string_initialize(string *obj, char *init);
|
||||
ErrorContext *string_initialize(string *obj, char *init);
|
||||
|
||||
#endif //_STRING_H_
|
||||
|
||||
929
src/tilemap.c
929
src/tilemap.c
File diff suppressed because it is too large
Load Diff
@@ -19,15 +19,15 @@
|
||||
#define TILEMAP_LAYER_TYPE_OBJECTS 2
|
||||
|
||||
typedef struct {
|
||||
int x;
|
||||
int y;
|
||||
float x;
|
||||
float y;
|
||||
int gid;
|
||||
int id;
|
||||
int height;
|
||||
int width;
|
||||
int rotation;
|
||||
int type;
|
||||
int visible;
|
||||
bool visible;
|
||||
actor *actorptr;
|
||||
char name[TILEMAP_MAX_OBJECT_NAME_SIZE];
|
||||
} tilemap_object;
|
||||
@@ -49,8 +49,8 @@ typedef struct {
|
||||
int columns;
|
||||
int firstgid;
|
||||
char imagefilename[TILEMAP_MAX_TILESET_FILENAME_SIZE];
|
||||
char imageheight;
|
||||
char imagewidth;
|
||||
int imageheight;
|
||||
int imagewidth;
|
||||
char name[TILEMAP_MAX_TILESET_NAME_SIZE];
|
||||
SDL_Texture *texture;
|
||||
// Use this as a lookup table instead of storing tiles
|
||||
@@ -67,7 +67,7 @@ typedef struct {
|
||||
// lead to premature exhaustion of TILEMAP_MAX_TILES_PER_IMAGE
|
||||
// because set D or E may only have 64 tiles but they may be
|
||||
// at the upper end of the array bound already because of this.
|
||||
short tile_offsets[TILEMAP_MAX_TILES_PER_IMAGE][2];
|
||||
int tile_offsets[TILEMAP_MAX_TILES_PER_IMAGE][2];
|
||||
int tilecount;
|
||||
int tileheight;
|
||||
int tilewidth;
|
||||
@@ -87,9 +87,9 @@ typedef struct {
|
||||
tilemap_layer layers[TILEMAP_MAX_LAYERS];
|
||||
} tilemap;
|
||||
|
||||
void tilemap_load(char *fname, tilemap *dest);
|
||||
void tilemap_draw(SDL_Renderer *renderer, tilemap *dest, SDL_FRect *viewport, int layeridx);
|
||||
void tilemap_draw_tileset(SDL_Renderer *renderer, tilemap *dest, int tilesetidx);
|
||||
ErrorContext *tilemap_load(char *fname, tilemap *dest);
|
||||
ErrorContext *tilemap_draw(SDL_Renderer *renderer, tilemap *dest, SDL_FRect *viewport, int layeridx);
|
||||
ErrorContext *tilemap_draw_tileset(SDL_Renderer *renderer, tilemap *dest, int tilesetidx);
|
||||
|
||||
|
||||
#endif //_TILEMAP_H_
|
||||
|
||||
89
src/util.c
89
src/util.c
@@ -1,11 +1,12 @@
|
||||
#include <SDL3/SDL.h>
|
||||
#include <aklabs/exclib.h>
|
||||
#include "util.h"
|
||||
#include "error.h"
|
||||
|
||||
void rectangle_points(RectanglePoints *dest, SDL_FRect *rect)
|
||||
ErrorContext *rectangle_points(RectanglePoints *dest, SDL_FRect *rect)
|
||||
{
|
||||
THROW_ZERO(dest, EXC_NULLPOINTER, "NULL RectanglePoints reference");
|
||||
THROW_ZERO(rect, EXC_NULLPOINTER, "NULL Rectangle reference");
|
||||
PREPARE_ERROR(errctx);
|
||||
FAIL_ZERO_RETURN(errctx, dest, ERR_NULLPOINTER, "NULL RectanglePoints reference");
|
||||
FAIL_ZERO_RETURN(errctx, rect, ERR_NULLPOINTER, "NULL Rectangle reference");
|
||||
dest->topleft.x = rect->x;
|
||||
dest->topleft.y = rect->y;
|
||||
dest->bottomleft.x = rect->x;
|
||||
@@ -14,62 +15,68 @@ void rectangle_points(RectanglePoints *dest, SDL_FRect *rect)
|
||||
dest->topright.y = rect->y;
|
||||
dest->bottomright.x = rect->x + rect->w;
|
||||
dest->bottomright.y = rect->y + rect->h;
|
||||
SUCCEED_RETURN(errctx);
|
||||
}
|
||||
|
||||
bool collide_point_rectangle(point *p, RectanglePoints *rp)
|
||||
ErrorContext *collide_point_rectangle(point *p, RectanglePoints *rp, bool *collide)
|
||||
{
|
||||
THROW_ZERO(p, EXC_NULLPOINTER, "NULL Point reference");
|
||||
THROW_ZERO(rp, EXC_NULLPOINTER, "NULL RectanglePoints reference");
|
||||
PREPARE_ERROR(errctx);
|
||||
FAIL_ZERO_RETURN(errctx, p, ERR_NULLPOINTER, "NULL Point reference");
|
||||
FAIL_ZERO_RETURN(errctx, rp, ERR_NULLPOINTER, "NULL RectanglePoints reference");
|
||||
if ( (p->x >= rp->topleft.x) && (p->y <= rp->topleft.y) &&
|
||||
(p->x <= rp->bottomright.x) && (p->y <= rp->bottomright.y) ) {
|
||||
return true;
|
||||
*collide = true;
|
||||
}
|
||||
return false;
|
||||
*collide = false;
|
||||
SUCCEED_RETURN(errctx);
|
||||
}
|
||||
|
||||
bool collide_rectangles(SDL_FRect *r1, SDL_FRect *r2)
|
||||
ErrorContext *collide_rectangles(SDL_FRect *r1, SDL_FRect *r2, bool *collide)
|
||||
{
|
||||
RectanglePoints r1p;
|
||||
RectanglePoints r2p;
|
||||
THROW_ZERO(r1, EXC_NULLPOINTER, "NULL rectangle reference");
|
||||
THROW_ZERO(r1, EXC_NULLPOINTER, "NULL rectangle reference");
|
||||
rectangle_points(&r1p, r1);
|
||||
PREPARE_ERROR(errctx);
|
||||
FAIL_ZERO_RETURN(errctx, r1, ERR_NULLPOINTER, "NULL rectangle reference");
|
||||
FAIL_ZERO_RETURN(errctx, r2, ERR_NULLPOINTER, "NULL rectangle reference");
|
||||
|
||||
ATTEMPT {
|
||||
CATCH(errctx, rectangle_points(&r1p, r1));
|
||||
} CLEANUP {
|
||||
} PROCESS(errctx) {
|
||||
} FINISH(errctx, true);
|
||||
|
||||
// is the upper left corner of r1 contacting r2?
|
||||
if ( collide_point_rectangle(&r1p.topleft, &r2p) ) {
|
||||
return true;
|
||||
}
|
||||
collide_point_rectangle(&r1p.topleft, &r2p, collide);
|
||||
if ( *collide == true ) { SUCCEED_RETURN(errctx); }
|
||||
|
||||
// is the upper left corner of r2 contacting r1?
|
||||
if ( collide_point_rectangle(&r2p.topleft, &r1p) ) {
|
||||
return true;
|
||||
}
|
||||
collide_point_rectangle(&r2p.topleft, &r1p, collide);
|
||||
if ( *collide == true ) { SUCCEED_RETURN(errctx); }
|
||||
|
||||
// is the top right corner of r1 contacting r2?
|
||||
if ( collide_point_rectangle(&r1p.topright, &r2p) ) {
|
||||
return true;
|
||||
}
|
||||
collide_point_rectangle(&r1p.topright, &r2p, collide);
|
||||
if ( *collide == true ) { SUCCEED_RETURN(errctx); }
|
||||
|
||||
// is the top right corner of r2 contacting r1?
|
||||
if ( collide_point_rectangle(&r2p.topright, &r1p) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
collide_point_rectangle(&r2p.topright, &r1p, collide);
|
||||
if ( *collide == true ) { SUCCEED_RETURN(errctx); }
|
||||
|
||||
// is the bottom left corner of r1 contacting r2?
|
||||
if ( collide_point_rectangle(&r1p.bottomleft, &r2p) ) {
|
||||
return true;
|
||||
}
|
||||
collide_point_rectangle(&r1p.bottomleft, &r2p, collide);
|
||||
if ( *collide == true ) { SUCCEED_RETURN(errctx); }
|
||||
|
||||
// is the bottom left corner of r2 contacting r1?
|
||||
if ( collide_point_rectangle(&r2p.bottomleft, &r1p) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
collide_point_rectangle(&r2p.bottomleft, &r1p, collide);
|
||||
if ( *collide == true ) { SUCCEED_RETURN(errctx); }
|
||||
|
||||
// is the bottom right corner of r1 contacting r2?
|
||||
if ( collide_point_rectangle(&r1p.bottomright, &r2p) ) {
|
||||
return true;
|
||||
}
|
||||
collide_point_rectangle(&r1p.bottomright, &r2p, collide);
|
||||
if ( *collide == true ) { SUCCEED_RETURN(errctx); }
|
||||
|
||||
// is the bottom right corner of r2 contacting r1?
|
||||
if ( collide_point_rectangle(&r2p.bottomright, &r1p) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
collide_point_rectangle(&r2p.bottomright, &r1p, collide);
|
||||
if ( *collide == true ) { SUCCEED_RETURN(errctx); }
|
||||
|
||||
*collide = false;
|
||||
SUCCEED_RETURN(errctx);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#ifndef _UTIL_H_
|
||||
#define _UTIL_H_
|
||||
|
||||
#include "error.h"
|
||||
|
||||
typedef struct point {
|
||||
int x;
|
||||
int y;
|
||||
@@ -16,8 +18,8 @@ typedef struct RectanglePoints {
|
||||
|
||||
#define COLLIDE_RECTANGLES(r1x, r1y, r1w, r1h, r2x, r2y, r2w, r2h) ((r1x < (r2x + r2w)) || ((r1x + r1w) > r2x)
|
||||
|
||||
void rectangle_points(RectanglePoints *dest, SDL_FRect *rect);
|
||||
bool collide_point_rectangle(point *p, RectanglePoints *r);
|
||||
bool collide_rectangles(SDL_FRect *r1, SDL_FRect *r2);
|
||||
ErrorContext *rectangle_points(RectanglePoints *dest, SDL_FRect *rect);
|
||||
ErrorContext *collide_point_rectangle(point *p, RectanglePoints *r, bool *collide);
|
||||
ErrorContext *collide_rectangles(SDL_FRect *r1, SDL_FRect *r2, bool *collide);
|
||||
|
||||
#endif // _UTIL_H_
|
||||
|
||||
Reference in New Issue
Block a user