From 462fb12bd56695f01a62788b9f088740d93ced6a Mon Sep 17 00:00:00 2001 From: Andrew Kesterson Date: Sat, 27 Jun 2026 13:16:28 -0400 Subject: [PATCH] WIP on physics/stage BSP stuff --- include/akgl/SDL_GameControllerDB.h | 6 +- include/akgl/actor.h | 7 +- include/akgl/game.h | 11 ++- include/akgl/heap.h | 1 + include/akgl/stage.h | 28 ++++--- src/actor.c | 2 + src/game.c | 3 + src/heap.c | 19 +++-- src/physics.c | 9 +++ src/stage.c | 110 +++++++++++++++++----------- 10 files changed, 130 insertions(+), 66 deletions(-) diff --git a/include/akgl/SDL_GameControllerDB.h b/include/akgl/SDL_GameControllerDB.h index ca04f60..36bb36f 100644 --- a/include/akgl/SDL_GameControllerDB.h +++ b/include/akgl/SDL_GameControllerDB.h @@ -1,9 +1,9 @@ #ifndef _SDL_GAMECONTROLLERDB_H_ #define _SDL_GAMECONTROLLERDB_H_ -// Taken from https://raw.githubusercontent.com/mdqinc/SDL_GameControllerDB/refs/heads/master/gamecontrollerdb.txt on Sun Jun 21 04:37:50 PM EDT 2026 +// Taken from https://raw.githubusercontent.com/mdqinc/SDL_GameControllerDB/refs/heads/master/gamecontrollerdb.txt on Sat Jun 27 08:22:48 AM EDT 2026 -#define AKGL_SDL_GAMECONTROLLER_DB_LEN 2241 +#define AKGL_SDL_GAMECONTROLLER_DB_LEN 2243 const char *SDL_GAMECONTROLLER_DB[] = { "03000000300f00000a01000000000000,3 In 1 Conversion Box,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b8,x:b3,y:b0,platform:Windows", @@ -1262,6 +1262,7 @@ const char *SDL_GAMECONTROLLER_DB[] = { "03000000c82d00001530000011010000,8BitDo Ultimate C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux", "03000000c82d00001630000011010000,8BitDo Ultimate C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux", "03000000c82d00001730000011010000,8BitDo Ultimate C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux", + "06000000c82d00000320000007010000,8BitDo Ultimate Wired Controller for Xbox,a:b0,b:b1,x:b2,y:b3,back:b6,guide:b8,start:b7,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux", "03000000c82d00000121000011010000,8BitDo Xbox One SN30 Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux", "05000000c82d00000121000000010000,8BitDo Xbox One SN30 Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux", "05000000a00500003232000001000000,8BitDo Zero,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Linux", @@ -2026,6 +2027,7 @@ const char *SDL_GAMECONTROLLER_DB[] = { "5553422c322d6178697320382d627574,iBuffalo Super Famicom Controller,a:b1,b:b0,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b17,rightshoulder:b18,start:b10,x:b3,y:b2,platform:Android", "64306137363261396266353433303531,InterAct GoPad,a:b24,b:b25,leftshoulder:b23,lefttrigger:b27,leftx:a0,lefty:a1,rightshoulder:b26,righttrigger:b28,x:b21,y:b22,platform:Android", "532e542e442e20496e74657261637420,InterAct HammerHead FX,a:b23,b:b24,back:b30,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b26,leftstick:b22,lefttrigger:b28,leftx:a0,lefty:a1,rightshoulder:b27,rightstick:b25,righttrigger:b29,rightx:a2,righty:a3,start:b31,x:b20,y:b21,platform:Android", + "05000000300f00001201000000780f00,Jess Tech Dual Analog Pad,a:b22,b:b23,back:b28,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b24,leftstick:b30,lefttrigger:b25,leftx:a0,lefty:a1,rightshoulder:b26,rightstick:b31,righttrigger:b27,rightx:a3,righty:a2,start:b29,x:b20,y:b21,platform:Android", "65346535636333663931613264643164,Joy-Con,a:b21,b:b22,back:b29,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b25,lefttrigger:b27,leftx:a0,lefty:a1,rightshoulder:b26,righttrigger:b28,rightx:a2,righty:a3,start:b30,x:b23,y:b24,platform:Android", "33346566643039343630376565326335,Joy-Con (L),a:b0,b:b1,back:b7,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,rightshoulder:b20,start:b17,x:b19,y:b2,platform:Android", "35313531613435623366313835326238,Joy-Con (L),a:b0,b:b1,back:b7,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,rightshoulder:b20,start:b17,x:b19,y:b2,platform:Android", diff --git a/include/akgl/actor.h b/include/akgl/actor.h index d4008ca..4b1f87f 100644 --- a/include/akgl/actor.h +++ b/include/akgl/actor.h @@ -2,8 +2,11 @@ #define _AKGL_ACTOR_H_ #include -#include "types.h" -#include "character.h" + +#include + +#include +#include // ---- LOW WORD STATUSES ---- diff --git a/include/akgl/game.h b/include/akgl/game.h index e67c65d..d0c53a0 100644 --- a/include/akgl/game.h +++ b/include/akgl/game.h @@ -3,10 +3,11 @@ #include #include -#include "types.h" -#include "tilemap.h" -#include "renderer.h" -#include "physics.h" +#include +#include +#include +#include +#include #define AKGL_VERSION "0.1.0" @@ -49,10 +50,12 @@ extern MIX_Mixer *akgl_mixer; extern MIX_Track *akgl_tracks[AKGL_GAME_AUDIO_MAX_TRACKS]; extern SDL_FRect _akgl_camera; extern akgl_Game game; +extern akgl_Stage _stage; extern akgl_RenderBackend _akgl_renderer; extern akgl_PhysicsBackend _akgl_physics; extern akgl_Tilemap _akgl_gamemap; +extern akgl_Stage *stage; extern akgl_Tilemap *gamemap; extern akgl_RenderBackend *renderer; extern akgl_PhysicsBackend *physics; diff --git a/include/akgl/heap.h b/include/akgl/heap.h index eb434be..8bdf39c 100644 --- a/include/akgl/heap.h +++ b/include/akgl/heap.h @@ -5,6 +5,7 @@ #include #include #include +#include #include #include diff --git a/include/akgl/stage.h b/include/akgl/stage.h index 10a8d94..8924d88 100644 --- a/include/akgl/stage.h +++ b/include/akgl/stage.h @@ -4,18 +4,12 @@ #include #include +#include + #define AKGL_STAGE_PARTITION_HORIZONTAL 0 #define AKGL_STAGE_PARTITION_VERTICAL 1 #define AKGL_STAGE_PARTITION_MAXDEPTH 4 -// Stages are collections of lights and cameras in a 2D or 3D space wherein actors -// and backgrounds are placed and directed for action. -typedef struct akgl_Stage { - aksl_TreeNode bsp; - akerr_ErrorContext AKERR_NOIGNORE *(*partition)(struct akgl_Stage *self); - akerr_ErrorContext AKERR_NOIGNORE *(*partition_actor)(struct akgl_Stage *self, akgl_Actor *actor); -} akgl_Stage; - typedef struct akgl_BSPContext { aksl_TreeNode *left; aksl_TreeNode *right; @@ -25,11 +19,27 @@ typedef struct akgl_BSPContext { typedef struct akgl_BSPLeaf { SDL_FRect extent; aksl_ListNode *actors; -} +} akgl_BSPLeaf; + +// Stages are collections of lights and cameras in a 2D or 3D space wherein actors +// and backgrounds are placed and directed for action. +typedef struct akgl_Stage { + aksl_TreeNode bsp; + akgl_BSPLeaf _rootleaf; + akerr_ErrorContext AKERR_NOIGNORE *(*partition)(struct akgl_Stage *self); + akerr_ErrorContext AKERR_NOIGNORE *(*partition_actor)(struct akgl_Stage *self, akgl_Actor *actor); +} akgl_Stage; + akerr_ErrorContext AKERR_NOIGNORE *akgl_stage_2d(akgl_Stage *self); // A function to divide the stage into a binary space partition tree with lists of actors in each partition akerr_ErrorContext AKERR_NOIGNORE *akgl_stage_2d_partition(akgl_Stage *self); +akerr_ErrorContext AKERR_NOIGNORE *akgl_stage_2d_partition_switchdirection(uint8_t direction, uint8_t *dest); +akerr_ErrorContext AKERR_NOIGNORE *akgl_stage_2d_bsp_actoriter(aksl_ListNode *node, void *data); +akerr_ErrorContext AKERR_NOIGNORE *akgl_stage_2d_bsp(aksl_TreeNode *root, aksl_ListNode *actors, SDL_FRect extents, uint8_t direction, uint8_t depth, uint8_t maxdepth); +akerr_ErrorContext AKERR_NOIGNORE *akgl_stage_2d_bspfree(akgl_Stage *self); +akerr_ErrorContext AKERR_NOIGNORE *akgl_stage_2d_partition(akgl_Stage *self); +akerr_ErrorContext AKERR_NOIGNORE *akgl_stage_2d_bsp_move(akgl_Stage *self, akgl_Actor *actor); #endif // _STAGE_H_ diff --git a/src/actor.c b/src/actor.c index 10e26aa..6403320 100644 --- a/src/actor.c +++ b/src/actor.c @@ -1,7 +1,9 @@ #include #include #include + #include +#include #include #include diff --git a/src/game.c b/src/game.c index d3baf78..0b03add 100644 --- a/src/game.c +++ b/src/game.c @@ -25,12 +25,14 @@ akgl_RenderBackend *renderer; akgl_PhysicsBackend *physics; SDL_FRect *camera; akgl_Tilemap *gamemap; +akgl_Stage *stage; // Default objects akgl_RenderBackend _akgl_renderer; akgl_PhysicsBackend _akgl_physics; SDL_FRect _akgl_camera; akgl_Tilemap _akgl_gamemap; +akgl_Stage _akgl_stage; MIX_Audio *bgm = NULL; MIX_Mixer *akgl_mixer = NULL; @@ -124,6 +126,7 @@ akerr_ErrorContext AKERR_NOIGNORE *akgl_game_init() renderer = &_akgl_renderer; physics = &_akgl_physics; gamemap = &_akgl_gamemap; + stage = &_akgl_stage; PASS(e, akgl_game_state_unlock()); SUCCEED_RETURN(e); diff --git a/src/heap.c b/src/heap.c index c06f7ff..78321ff 100644 --- a/src/heap.c +++ b/src/heap.c @@ -10,6 +10,7 @@ #include #include #include +#include akgl_Actor HEAP_ACTOR[AKGL_MAX_HEAP_ACTOR]; akgl_Sprite HEAP_SPRITE[AKGL_MAX_HEAP_SPRITE]; @@ -18,7 +19,7 @@ akgl_Character HEAP_CHARACTER[AKGL_MAX_HEAP_CHARACTER]; akgl_String HEAP_STRING[AKGL_MAX_HEAP_STRING]; aksl_ListNode HEAP_LIST[AKGL_MAX_HEAP_LIST]; aksl_TreeNode HEAP_TREE[AKGL_MAX_HEAP_TREE]; -aksl_ListNode HEAP_TREE_LEAVES[AKGL_MAX_HEAP_TREE]; +akgl_BSPLeaf HEAP_TREE_LEAVES[AKGL_MAX_HEAP_TREE]; void *AKGL_LIST_SENTINEL = (void *)1; /** Sentinel value used for aksl_ListNode objects to determine if they are available */ @@ -28,6 +29,8 @@ akerr_ErrorContext *akgl_heap_init() int i = 0; akerr_name_for_status(AKGL_ERR_SDL, "SDL Error"); PASS(errctx, akgl_heap_init_actor()); + PASS(errctx, akgl_heap_init_list()); + PASS(errctx, akgl_heap_init_tree()); for ( i = 0; i < AKGL_MAX_HEAP_SPRITE; i++) { memset(&HEAP_SPRITE[i], 0x00, sizeof(akgl_Sprite)); } @@ -59,6 +62,7 @@ akerr_ErrorContext *akgl_heap_init_tree(void) for ( int i = 0; i < AKGL_MAX_HEAP_TREE; i++) { memset(&HEAP_TREE[i], 0x00, sizeof(aksl_TreeNode)); HEAP_TREE[i].leaf = AKGL_LIST_SENTINEL; + memset(&HEAP_TREE_LEAVES[i], 0x00, sizeof(akgl_BSPLeaf)); } SUCCEED_RETURN(e); } @@ -108,7 +112,7 @@ akerr_ErrorContext *akgl_heap_next_tree(aksl_TreeNode **dest) { PREPARE_ERROR(errctx); for (int i = 0; i < AKGL_MAX_HEAP_TREE; i++ ) { - if ( HEAP_TREE[i].leaf != &AKGL_LIST_SENTINEL ) { + if ( HEAP_TREE[i].leaf != AKGL_LIST_SENTINEL ) { continue; } *dest = &HEAP_TREE[i]; @@ -132,7 +136,7 @@ akerr_ErrorContext *akgl_heap_release_list(aksl_ListNode *list) FAIL_ZERO_RETURN(e, list, AKERR_NULLPOINTER, "list"); list->next = NULL; list->prev = NULL; - list->data = (void *)&AKGL_LIST_SENTINEL; + list->data = (void *)AKGL_LIST_SENTINEL; SUCCEED_RETURN(e); } @@ -149,10 +153,13 @@ akerr_ErrorContext *akgl_heap_release_tree(aksl_TreeNode *tree) { PREPARE_ERROR(e); FAIL_ZERO_RETURN(e, tree, AKERR_NULLPOINTER, "tree"); + akgl_BSPLeaf *leaf = NULL; tree->left = NULL; tree->right = NULL; - if ( tree->leaf != NULL && tree->leaf->actors != NULL ) { - FAIL_RETURN(e, AKERR_VALUE, "Can't release tree node %p until its leaf actors %p is released and leaf->actors == NULL", tree, tree->leaf->actors); + tree->parent = NULL; + leaf = (akgl_BSPLeaf *)tree->leaf; + if ( tree->leaf != NULL && leaf->actors != NULL ) { + FAIL_RETURN(e, AKERR_VALUE, "Can't release tree node %p until its leaf actors %p is released and leaf->actors == NULL", tree, leaf->actors); } else if ( tree->leaf != NULL ) { memset((void *)tree->leaf, 0x00, sizeof(akgl_BSPLeaf)); } @@ -192,7 +199,7 @@ akerr_ErrorContext AKERR_NOIGNORE *akgl_heap_iter_tree_release(aksl_TreeNode *pt FAIL_ZERO_RETURN(e, ptr, AKERR_NULLPOINTER, "ptr"); if ( ptr->leaf != AKGL_LIST_SENTINEL && ptr->leaf != NULL ) { PASS(e, akgl_heap_release_list(ptr->leaf)); - ptr->leaf = NULL; + //ptr->leaf = NULL; } PASS(e, akgl_heap_release_tree(ptr)); SUCCEED_RETURN(e); diff --git a/src/physics.c b/src/physics.c index 12c22c4..46833a9 100644 --- a/src/physics.c +++ b/src/physics.c @@ -6,6 +6,7 @@ #include #include #include +#include akerr_ErrorContext AKERR_NOIGNORE *akgl_physics_null_gravity(akgl_PhysicsBackend *self, akgl_Actor *actor, float32_t dt) { @@ -91,9 +92,17 @@ akerr_ErrorContext AKERR_NOIGNORE *akgl_physics_arcade_move(struct akgl_PhysicsB PREPARE_ERROR(e); FAIL_ZERO_RETURN(e, self, AKERR_NULLPOINTER, "self"); FAIL_ZERO_RETURN(e, actor, AKERR_NULLPOINTER, "actor"); + akgl_Sprite *curspr = NULL; actor->x += actor->vx * dt; actor->y += actor->vy * dt; actor->z += actor->vz * dt; + // Set the actor's bounding box for physics + if ( actor->basechar != NULL ) { + PASS(e, actor->basechar->sprite_get(actor->basechar, actor->state, &curspr)); + actor->bbox = (SDL_FRect){actor->x, actor->y, curspr->width, curspr->height}; + } else { + actor->bbox = (SDL_FRect){actor->x, actor->y, 0, 0}; + } SUCCEED_RETURN(e); } diff --git a/src/stage.c b/src/stage.c index 2feef3b..97bb86a 100644 --- a/src/stage.c +++ b/src/stage.c @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -19,6 +20,9 @@ akerr_ErrorContext AKERR_NOIGNORE *akgl_stage_2d(akgl_Stage *self) memset((void *)self, 0x00, sizeof(akgl_Stage)); self->partition = akgl_stage_2d_partition; self->partition_actor = akgl_stage_2d_bsp_move; + memset((void *)&self->bsp, 0x00, sizeof(aksl_TreeNode)); + self->bsp.leaf = &self->_rootleaf; + memset((void *)&self->_rootleaf, 0x00, sizeof(akgl_BSPLeaf)); SUCCEED_RETURN(e); } @@ -43,6 +47,7 @@ akerr_ErrorContext AKERR_NOIGNORE *akgl_stage_2d_partition_switchdirection(uint8 } else { FAIL_RETURN(e, AKERR_VALUE, "Unknown partition direction %d", direction); } + SUCCEED_RETURN(e); } /** @@ -67,25 +72,29 @@ akerr_ErrorContext AKERR_NOIGNORE *akgl_stage_2d_bsp_actoriter(aksl_ListNode *no bool e2intersect; akgl_BSPContext *context = NULL; akgl_Actor *actor = NULL; - aksl_ListNode *dest = NULL; + aksl_TreeNode *dest = NULL; aksl_ListNode *newnode = NULL; + akgl_BSPLeaf *leaf = NULL; PREPARE_ERROR(e); FAIL_ZERO_RETURN(e, node, AKERR_NULLPOINTER, "node"); FAIL_ZERO_RETURN(e, data, AKERR_NULLPOINTER, "data"); FAIL_ZERO_RETURN(e, node->data, AKERR_NULLPOINTER, "node->data"); - FAIL_ZERO_RETURN(e, context->left, AKERR_NULLPOINTER, "left"); - FAIL_ZERO_RETURN(e, context->right, AKERR_NULLPOINTER, "right"); - FAIL_ZERO_RETURN(e, context->parent, AKERR_NULLPOINTER, "parent"); - FAIL_ZERO_RETURN(e, context->left->leaf.actors, AKERR_NULLPOINTER, "left->leaf"); - FAIL_ZERO_RETURN(e, context->right->leaf.actors, AKERR_NULLPOINTER, "right->leaf"); - FAIL_ZERO_RETURN(e, context->parent->leaf.actors, AKERR_NULLPOINTER, "parent->leaf"); - context = (akgl_BSPContext *)data; actor = (akgl_Actor *)node->data; - e1intersect = SDL_HasRectIntersectionFloat(&context->left.extent, &actor->bbox); - e2intersect = SDL_HasRectIntersectionFloat(&context->right.extent, &actor->bbox); + FAIL_ZERO_RETURN(e, context->left, AKERR_NULLPOINTER, "left"); + FAIL_ZERO_RETURN(e, context->right, AKERR_NULLPOINTER, "right"); + FAIL_ZERO_RETURN(e, context->parent, AKERR_NULLPOINTER, "parent"); + FAIL_ZERO_RETURN(e, ((akgl_BSPLeaf *)context->left->leaf)->actors, AKERR_NULLPOINTER, "left->leaf"); + FAIL_ZERO_RETURN(e, ((akgl_BSPLeaf *)context->right->leaf)->actors, AKERR_NULLPOINTER, "right->leaf"); + FAIL_ZERO_RETURN(e, ((akgl_BSPLeaf *)context->parent->leaf)->actors, AKERR_NULLPOINTER, "parent->leaf"); + + + leaf = (akgl_BSPLeaf *)context->left->leaf; + e1intersect = SDL_HasRectIntersectionFloat(&leaf->extent, &actor->bbox); + leaf = (akgl_BSPLeaf *)context->right->leaf; + e2intersect = SDL_HasRectIntersectionFloat(&leaf->extent, &actor->bbox); if ( e1intersect && e2intersect ) { // Actors who cross left/right boundaries get left in the context of their parent, so both @@ -100,7 +109,8 @@ akerr_ErrorContext AKERR_NOIGNORE *akgl_stage_2d_bsp_actoriter(aksl_ListNode *no if ( dest != NULL ) { PASS(e, akgl_heap_next_list(&newnode)); newnode->data = node->data; - PASS(e, aksl_list_push(dest->leaf.actors, newnode)); + leaf = (akgl_BSPLeaf *)dest->leaf; + PASS(e, aksl_list_push(leaf->actors, newnode)); actor->bsphome = dest; actor->bsplistnode = newnode; } @@ -129,7 +139,8 @@ akerr_ErrorContext AKERR_NOIGNORE *akgl_stage_2d_bsp_actoriter(aksl_ListNode *no */ akerr_ErrorContext AKERR_NOIGNORE *akgl_stage_2d_bsp(aksl_TreeNode *root, aksl_ListNode *actors, SDL_FRect extents, uint8_t direction, uint8_t depth, uint8_t maxdepth) { - akgl_BSPContext context; + akgl_BSPContext context = {0, 0, 0}; + akgl_BSPLeaf *leaf = NULL; // Until we have reached maxdepth levels of depth PREPARE_ERROR(e); @@ -143,58 +154,67 @@ akerr_ErrorContext AKERR_NOIGNORE *akgl_stage_2d_bsp(aksl_TreeNode *root, aksl_L // (the top half of a vertical division is "left", bottom half is "right") if ( root->left == NULL ) { PASS(e, akgl_heap_next_tree((aksl_TreeNode **)&root->left)); - PASS(e, akgl_heap_next_list((aksl_ListNode **)&root->left->leaf->actors)); - context.left = root->left; + PASS(e, akgl_heap_next_list((aksl_ListNode **)&((akgl_BSPLeaf *)root->left->leaf)->actors)); root->left->parent = root; + leaf = root->left->leaf; if ( direction == AKGL_STAGE_PARTITION_HORIZONTAL ) { - context.left.extent.x = extents.x; - context.left.extent.y = extents.y; - context.left.extent.w = extents.w; - context.left.extent.h = (extents.h / 2); + leaf->extent.x = extents.x; + leaf->extent.y = extents.y; + leaf->extent.w = extents.w; + leaf->extent.h = (extents.h / 2); } else if ( direction == AKGL_STAGE_PARTITION_VERTICAL ) { - context.left.extent.x = extents.x; - context.left.extent.y = extents.y; - context.left.extent.w = (extents.w / 2); - context.left.extent.h = extents.h; + leaf->extent.x = extents.x; + leaf->extent.y = extents.y; + leaf->extent.w = (extents.w / 2); + leaf->extent.h = extents.h; } else { FAIL_RETURN(e, AKERR_VALUE, "Invalid partition direction %d", direction); } } if ( root->right == NULL ) { PASS(e, akgl_heap_next_tree((aksl_TreeNode **)&root->right)); - PASS(e, akgl_heap_next_list((aksl_ListNode **)&root->right->leaf->actors)); - context.right = root->right; + PASS(e, akgl_heap_next_list((aksl_ListNode **)&((akgl_BSPLeaf *)root->right->leaf)->actors)); root->right->parent = root; + leaf = root->right->leaf; if ( direction == AKGL_STAGE_PARTITION_HORIZONTAL ) { - context.right.extent.x = extents.x; - context.right.extent.y = extents.y + (extents.h / 2); - context.right.extent.w = extents.w; - context.right.extent.h = (extents.h / 2); + leaf->extent.x = extents.x; + leaf->extent.y = extents.y + (extents.h / 2); + leaf->extent.w = extents.w; + leaf->extent.h = (extents.h / 2); } else if ( direction == AKGL_STAGE_PARTITION_VERTICAL ) { - context.right.extent.x = extents.x + (extents.w / 2); - context.right.extent.y = extents.y; - context.right.extent.w = (extents.w / 2); - context.right.extent.h = extents.h; + leaf->extent.x = extents.x + (extents.w / 2); + leaf->extent.y = extents.y; + leaf->extent.w = (extents.w / 2); + leaf->extent.h = extents.h; } else { FAIL_RETURN(e, AKERR_VALUE, "Invalid partition direction %d", direction); } } - if ( root->leaf->actors == NULL ) { - PASS(e, akgl_heap_next_list((aksl_ListNode **)&root->leaf->actors)); - context.parent = root; + if ( ((akgl_BSPLeaf *)root->leaf)->actors == NULL ) { + PASS(e, akgl_heap_next_list((aksl_ListNode **)&((akgl_BSPLeaf *)root->leaf)->actors)); } + context.left = root->left; + context.right = root->right; + context.parent = root; // - Test (SDL_HasIntersection) all actor objects in the current working space // against the SDL_Frects for both halves. If they intersect, push the actors // down into the leaf linked lists for each half - PASS(e, aksl_list_iterate(actors, &akgl_stage_2d_bsp_actoriter, &context)); + ATTEMPT { + CATCH(e, aksl_list_iterate(actors, &akgl_stage_2d_bsp_actoriter, &context)); + } CLEANUP { + } PROCESS(e) { + } HANDLE(e, AKERR_NULLPOINTER) { + SDL_Log("Empty actor list"); + } FINISH(e, true); + PASS(e, akgl_stage_2d_partition_switchdirection(direction, &direction)); // - Recurse down into the left BSP node, changing our partitioning // (vertical->horizontal, horizontal->vertical etc) - PASS(e, akgl_stage_2d_bsp(root->left, root->left->leaf->actors, context.left.extent, direction, depth + 1, maxdepth)); + PASS(e, akgl_stage_2d_bsp(root->left, ((akgl_BSPLeaf *)root->left->leaf)->actors, ((akgl_BSPLeaf *)context.left->leaf)->extent, direction, depth + 1, maxdepth)); // - Recurse down into the right BSP node // (vertical->horizontal, horizontal->vertical etc) - PASS(e, akgl_stage_2d_bsp(root->right, root->right->leaf->actors, context.right.extent, direction, depth + 1, maxdepth)); + PASS(e, akgl_stage_2d_bsp(root->right, ((akgl_BSPLeaf *)root->right->leaf)->actors, ((akgl_BSPLeaf *)context.right->leaf)->extent, direction, depth + 1, maxdepth)); SUCCEED_RETURN(e); } @@ -234,7 +254,10 @@ akerr_ErrorContext AKERR_NOIGNORE *akgl_stage_2d_partition(akgl_Stage *self) FAIL_ZERO_RETURN(e, self, AKERR_NULLPOINTER, "self"); PASS(e, akgl_stage_2d_bspfree(self)); - + + self->bsp.leaf = &self->_rootleaf; + memset((void *)&self->_rootleaf, 0x00, sizeof(akgl_BSPLeaf)); + // Build a linked list of all actors currently initialized PASS(e, akgl_heap_next_list(&actors)); curnode = actors; @@ -255,6 +278,7 @@ akerr_ErrorContext AKERR_NOIGNORE *akgl_stage_2d_partition(akgl_Stage *self) * a simple Mario style sidescroller or even a JRPG, but for something like * a bullet hell, it will be essential. */ + ((akgl_BSPLeaf *)self->bsp.leaf)->extent = (SDL_FRect){0, 0, camera->w, camera->h}; ATTEMPT { CATCH(e, akgl_stage_2d_bsp( &self->bsp, @@ -318,7 +342,7 @@ akerr_ErrorContext AKERR_NOIGNORE *akgl_stage_2d_bsp_move(akgl_Stage *self, akgl } else { // Actor already exists somewhere in the BSP tree // 1. Is it still in the extents for its bsphome? If so, do nothing. - if ( SDL_HasRectIntersectionFloat(&actor->bsphome->leaf->extent, &actor->bbox) ) { + if ( SDL_HasRectIntersectionFloat(&((akgl_BSPLeaf *)actor->bsphome->leaf)->extent, &actor->bbox) ) { SUCCEED_RETURN(e); } // 2. If not, pop the actor out of its current BSP actor list, and start walking up. @@ -327,20 +351,20 @@ akerr_ErrorContext AKERR_NOIGNORE *akgl_stage_2d_bsp_move(akgl_Stage *self, akgl tmp = actor->bsplistnode; while ( curnode != NULL ) { // 3. Is it within the current BSP node's extents? If not, walk up and repeat. - if ( SDL_HasRectIntersectionFloat(&curnode->leaf->extent, &actor->bbox) ) { + if ( SDL_HasRectIntersectionFloat(&((akgl_BSPLeaf *)curnode->leaf)->extent, &actor->bbox) ) { // 4. Find which extent it matches. // FIXME : akgl_BSPContext should be replaced with aksl_TreeNode at this point, it's fully redundant context.left = curnode->left; context.right = curnode->right; context.parent = curnode->parent; - PASS(e, akgl_stage_2d_bsp_actoriter(tmp, actor->bsplistnode, &context)); + PASS(e, akgl_stage_2d_bsp_actoriter(actor->bsplistnode, &context)); } curnode = curnode->parent; } // Release the old actor node, it will have been moved to a new one by now if ( tmp == actor->bsplistnode ) { // Odd ... - SDL_Log("Expected actor %d to be moved to a different BSP node after moving, but it still has the same list node...\n", actor); + SDL_Log("Expected actor %p to be moved to a different BSP node after moving, but it still has the same list node...\n", actor); } else { PASS(e, akgl_heap_release_list(tmp)); }