WIP : feature/physics_bsptree #1

Open
andrew wants to merge 5 commits from feature/physics_bsptree into main
10 changed files with 130 additions and 66 deletions
Showing only changes of commit 462fb12bd5 - Show all commits

View File

@@ -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",

View File

@@ -2,8 +2,11 @@
#define _AKGL_ACTOR_H_
#include <stdint.h>
#include "types.h"
#include "character.h"
#include <akstdlib.h>
#include <akgl/types.h>
#include <akgl/character.h>
// ---- LOW WORD STATUSES ----

View File

@@ -3,10 +3,11 @@
#include <stdint.h>
#include <SDL3_mixer/SDL_mixer.h>
#include "types.h"
#include "tilemap.h"
#include "renderer.h"
#include "physics.h"
#include <akgl/types.h>
#include <akgl/tilemap.h>
#include <akgl/renderer.h>
#include <akgl/physics.h>
#include <akgl/stage.h>
#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;

View File

@@ -5,6 +5,7 @@
#include <akgl/actor.h>
#include <akgl/character.h>
#include <akgl/staticstring.h>
#include <akgl/stage.h>
#include <akerror.h>
#include <akstdlib.h>

View File

@@ -4,18 +4,12 @@
#include <SDL3/SDL.h>
#include <akstdlib.h>
#include <akgl/actor.h>
#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_

View File

@@ -1,7 +1,9 @@
#include <SDL3/SDL.h>
#include <SDL3_image/SDL_image.h>
#include <string.h>
#include <akerror.h>
#include <akstdlib.h>
#include <akgl/physics.h>
#include <akgl/game.h>

View File

@@ -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);

View File

@@ -10,6 +10,7 @@
#include <akgl/staticstring.h>
#include <akgl/iterator.h>
#include <akgl/error.h>
#include <akgl/stage.h>
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);

View File

@@ -6,6 +6,7 @@
#include <akgl/error.h>
#include <akgl/heap.h>
#include <akgl/registry.h>
#include <akgl/stage.h>
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);
}

View File

@@ -1,4 +1,5 @@
#include <SDL3/SDL.h>
#include <akstdlib.h>
#include <akgl/stage.h>
#include <akgl/actor.h>
#include <akgl/heap.h>
@@ -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);
}
@@ -235,6 +255,9 @@ akerr_ErrorContext AKERR_NOIGNORE *akgl_stage_2d_partition(akgl_Stage *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));
}