From 307f3a9dec1f03bfa79c0ef70a69d3c8cb0b2e21 Mon Sep 17 00:00:00 2001 From: Dominic Masters Date: Sun, 9 Nov 2025 12:50:15 -0600 Subject: [PATCH] Chunk loading example --- cmake/modules/Findlibzip.cmake | 4 +- src/display/texture.c | 6 +- src/error/error.c | 6 +- src/error/error.h | 2 +- src/rpg/entity/entity.c | 1 + src/rpg/rpg.c | 3 +- src/rpg/rpgcamera.c | 26 ++++++++ src/rpg/rpgcamera.h | 7 ++- src/rpg/world/map.c | 106 ++++++++++++++++++++++++++++++++- src/rpg/world/map.h | 17 +++++- src/util/math.c | 2 +- src/util/string.c | 10 ++-- 12 files changed, 169 insertions(+), 21 deletions(-) diff --git a/cmake/modules/Findlibzip.cmake b/cmake/modules/Findlibzip.cmake index bf43e18..2254ae2 100644 --- a/cmake/modules/Findlibzip.cmake +++ b/cmake/modules/Findlibzip.cmake @@ -22,8 +22,8 @@ find_package_handle_standard_args( _libzip_pkgcfg ) -if (LIBZIP_FOUND) - if (NOT TARGET libzip::zip) +if(LIBZIP_FOUND) + if(NOT TARGET libzip::zip) add_library(libzip::zip UNKNOWN IMPORTED) set_target_properties(libzip::zip PROPERTIES diff --git a/src/display/texture.c b/src/display/texture.c index 7ad2e6d..0f4dc26 100644 --- a/src/display/texture.c +++ b/src/display/texture.c @@ -68,7 +68,7 @@ void textureInit( const palette_t *pal = PALETTE_LIST[data.palette.palette]; assertNotNull(pal, "Palette cannot be NULL"); GLenum err = glGetError(); - if (err != GL_NO_ERROR) { + if(err != GL_NO_ERROR) { assertUnreachable("GL Error before setting color table"); } @@ -82,9 +82,9 @@ void textureInit( glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &mask); if(mask & GL_CONTEXT_CORE_PROFILE_BIT) { GLint n=0; glGetIntegerv(GL_NUM_EXTENSIONS, &n); - for (GLint i=0; imessage, "Message cannot be NULL"); @@ -106,7 +106,7 @@ errorret_t errorChainImpl( } void errorCatch(const errorret_t retval) { - if (retval.code == ERROR_OK) return; + if(retval.code == ERROR_OK) return; assertNotNull(retval.state, "Error state cannot be NULL"); assertNotNull(retval.state->message, "Message cannot be NULL"); @@ -115,7 +115,7 @@ void errorCatch(const errorret_t retval) { } errorret_t errorPrint(const errorret_t retval) { - if (retval.code == ERROR_OK) return retval; + if(retval.code == ERROR_OK) return retval; assertNotNull(retval.state, "Error state cannot be NULL"); assertNotNull(retval.state->message, "Message cannot be NULL"); diff --git a/src/error/error.h b/src/error/error.h index 85e60fb..5155eca 100644 --- a/src/error/error.h +++ b/src/error/error.h @@ -152,7 +152,7 @@ errorret_t errorPrint(const errorret_t retval); */ #define errorChain(retval) { \ errorret_t errorChainRetval = (retval); \ - if (errorChainRetval.code != ERROR_OK) { \ + if(errorChainRetval.code != ERROR_OK) { \ return errorChainImpl(errorChainRetval, __FILE__, __func__, __LINE__); \ } \ } diff --git a/src/rpg/entity/entity.c b/src/rpg/entity/entity.c index 09fe998..e74dc17 100644 --- a/src/rpg/entity/entity.c +++ b/src/rpg/entity/entity.c @@ -11,6 +11,7 @@ #include "time/time.h" #include "util/math.h" #include "rpg/cutscene/cutscenemode.h" +#include "rpg/world/map.h" entity_t ENTITIES[ENTITY_COUNT]; diff --git a/src/rpg/rpg.c b/src/rpg/rpg.c index 081cac4..dfffbf6 100644 --- a/src/rpg/rpg.c +++ b/src/rpg/rpg.c @@ -45,7 +45,6 @@ void rpgUpdate(void) { if(!TIME.fixedUpdate) return; // TODO: Do not update if the scene is not the map scene? - mapUpdate(); // Update overworld ents. @@ -55,8 +54,8 @@ void rpgUpdate(void) { entityUpdate(ent); } while(++ent < &ENTITIES[ENTITY_COUNT]); - // Tick the cutscene system. cutsceneSystemUpdate(); + rpgCameraUpdate(); } void rpgDispose(void) { diff --git a/src/rpg/rpgcamera.c b/src/rpg/rpgcamera.c index 1963796..afb8c81 100644 --- a/src/rpg/rpgcamera.c +++ b/src/rpg/rpgcamera.c @@ -8,9 +8,35 @@ #include "rpgcamera.h" #include "util/memory.h" #include "rpg/entity/entity.h" +#include "rpg/world/map.h" rpgcamera_t RPG_CAMERA; void rpgCameraInit(void) { memoryZero(&RPG_CAMERA, sizeof(rpgcamera_t)); +} + +void rpgCameraUpdate(void) { + switch(RPG_CAMERA.mode) { + case RPG_CAMERA_MODE_FREE: + // Free camera mode; nothing to do. + break; + + case RPG_CAMERA_MODE_FOLLOW_ENTITY: { + entity_t *entity = &ENTITIES[RPG_CAMERA.followEntity.followEntityId]; + if(entity->type == ENTITY_TYPE_NULL) return; + + // Update map position to match camera. + mapPositionSet( + (int16_t)(entity->position.x / CHUNK_WIDTH), + (int16_t)(entity->position.y / CHUNK_HEIGHT), + (int16_t)(entity->position.z / CHUNK_DEPTH) + ); + break; + } + + default: + // Unknown camera mode; do nothing. + break; + } } \ No newline at end of file diff --git a/src/rpg/rpgcamera.h b/src/rpg/rpgcamera.h index cf45add..4338d03 100644 --- a/src/rpg/rpgcamera.h +++ b/src/rpg/rpgcamera.h @@ -29,4 +29,9 @@ extern rpgcamera_t RPG_CAMERA; /** * Initializes the RPG camera. */ -void rpgCameraInit(void); \ No newline at end of file +void rpgCameraInit(void); + +/** + * Updates the RPG camera. + */ +void rpgCameraUpdate(void); \ No newline at end of file diff --git a/src/rpg/world/map.c b/src/rpg/world/map.c index 9e292ac..907d147 100644 --- a/src/rpg/world/map.c +++ b/src/rpg/world/map.c @@ -7,17 +7,119 @@ #include "map.h" #include "util/memory.h" +#include // For printf map_t MAP; +// Dummy functions for chunk loading/unloading +void mapChunkUnload(chunk_t* chunk) { + // Placeholder for unloading logic + printf("Unloading chunk at (%d, %d, %d)\n", chunk->x, chunk->y, chunk->z); +} + +void mapChunkLoad(chunk_t* chunk) { + // Placeholder for loading logic + printf("Loading chunk at (%d, %d, %d)\n", chunk->x, chunk->y, chunk->z); +} + void mapInit() { memoryZero(&MAP, sizeof(map_t)); - for(uint32_t i = 0; i < MAP_CHUNK_COUNT; i++) { - MAP.chunkOrder[i] = &MAP.chunks[i]; + uint32_t index = 0; + for(uint32_t z = 0; z < MAP_CHUNK_DEPTH; z++) { + for(uint32_t y = 0; y < MAP_CHUNK_HEIGHT; y++) { + for(uint32_t x = 0; x < MAP_CHUNK_WIDTH; x++) { + chunk_t *chunk = &MAP.chunks[index]; + chunk->x = x; + chunk->y = y; + chunk->z = z; + MAP.chunkOrder[index] = chunk; + mapChunkLoad(chunk); + index++; + } + } } } +void mapPositionSet(const int16_t x, const int16_t y, const int16_t z) { + const int16_t curX = MAP.x; + const int16_t curY = MAP.y; + const int16_t curZ = MAP.z; + if(curX == x && curY == y && curZ == z) return; + + // Determine which chunks remain loaded + int32_t chunksRemaining[MAP_CHUNK_COUNT] = {0}; + int32_t chunksFreed[MAP_CHUNK_COUNT] = {0}; + + uint32_t remainingCount = 0; + uint32_t freedCount = 0; + + for(uint32_t i = 0; i < MAP_CHUNK_COUNT; i++) { + // Will this chunk remain loaded? + chunk_t *chunk = &MAP.chunks[i]; + if( + chunk->x >= x && chunk->x < x + MAP_CHUNK_WIDTH && + chunk->y >= y && chunk->y < y + MAP_CHUNK_HEIGHT && + chunk->z >= z && chunk->z < z + MAP_CHUNK_DEPTH + ) { + // Stays loaded + chunksRemaining[remainingCount++] = i; + continue; + } + + // Not remaining loaded + chunksFreed[freedCount++] = i; + } + + // Unload the freed chunks + for(uint32_t i = 0; i < freedCount; i++) { + chunk_t *chunk = &MAP.chunks[chunksFreed[i]]; + mapChunkUnload(chunk); + } + + // This can probably be optimized later, for now we check each chunk and see + // if it needs loading or not, and update the chunk order + uint32_t orderIndex = 0; + for(uint32_t zOff = 0; zOff < MAP_CHUNK_DEPTH; zOff++) { + for(uint32_t yOff = 0; yOff < MAP_CHUNK_HEIGHT; yOff++) { + for(uint32_t xOff = 0; xOff < MAP_CHUNK_WIDTH; xOff++) { + const int16_t chunkX = x + xOff; + const int16_t chunkY = y + yOff; + const int16_t chunkZ = z + zOff; + + // Is this chunk already loaded (was not unloaded earlier)? + int32_t chunkIndex = -1; + for(uint32_t i = 0; i < remainingCount; i++) { + chunk_t *chunk = &MAP.chunks[chunksRemaining[i]]; + if(chunk->x != chunkX) continue; + if(chunk->y != chunkY) continue; + if(chunk->z != chunkZ) continue; + chunkIndex = chunksRemaining[i]; + break; + } + + // Need to load this chunk + if(chunkIndex == -1) { + // Find a freed chunk to reuse + chunkIndex = chunksFreed[--freedCount]; + chunk_t *chunk = &MAP.chunks[chunkIndex]; + chunk->x = chunkX; + chunk->y = chunkY; + chunk->z = chunkZ; + mapChunkLoad(chunk); + } + + MAP.chunkOrder[orderIndex++] = &MAP.chunks[chunkIndex]; + } + } + } + + // Update map position + MAP.x = x; + MAP.y = y; + MAP.z = z; +} + void mapUpdate() { } \ No newline at end of file diff --git a/src/rpg/world/map.h b/src/rpg/world/map.h index fd07d71..e20b1f1 100644 --- a/src/rpg/world/map.h +++ b/src/rpg/world/map.h @@ -29,4 +29,19 @@ void mapInit(); /** * Updates the map. */ -void mapUpdate(); \ No newline at end of file +void mapUpdate(); + +/** + * Sets the map position and updates chunks accordingly. + */ +void mapPositionSet(const int16_t x, const int16_t y, const int16_t z); + +/** + * Dummy: Unloads a chunk. + */ +void mapChunkUnload(chunk_t* chunk); + +/** + * Dummy: Loads a chunk. + */ +void mapChunkLoad(chunk_t* chunk); \ No newline at end of file diff --git a/src/util/math.c b/src/util/math.c index ac538d1..55f8f7a 100644 --- a/src/util/math.c +++ b/src/util/math.c @@ -8,7 +8,7 @@ #include "math.h" uint32_t mathNextPowTwo(uint32_t value) { - if (value == 0) return 1; // Handle zero case + if(value == 0) return 1; // Handle zero case value--; value |= value >> 1; value |= value >> 2; diff --git a/src/util/string.c b/src/util/string.c index f06b116..8b7b668 100644 --- a/src/util/string.c +++ b/src/util/string.c @@ -48,7 +48,7 @@ void stringTrim(char_t *str) { *(end + 1) = '\0'; // Move trimmed string to the original buffer - if (start != str) memmove(str, start, end - start + 2); + if(start != str) memmove(str, start, end - start + 2); } char_t * stringToken(char_t *str, const char_t *delim) { @@ -98,7 +98,7 @@ bool_t stringToI32(const char_t *str, int32_t *out) { char_t *endptr; errno = 0; long int result = strtol(str, &endptr, 10); - if (errno != 0 || *endptr != '\0') { + if(errno != 0 || *endptr != '\0') { return false; } *out = (int32_t)result; @@ -112,7 +112,7 @@ bool_t stringToI64(const char_t *str, int64_t *out) { char_t *endptr; errno = 0; long long int result = strtoll(str, &endptr, 10); - if (errno != 0 || *endptr != '\0') { + if(errno != 0 || *endptr != '\0') { return false; } *out = (int64_t)result; @@ -126,7 +126,7 @@ bool_t stringToU16(const char_t *str, uint16_t *out) { char_t *endptr; errno = 0; unsigned long int result = strtoul(str, &endptr, 10); - if (errno != 0 || *endptr != '\0' || result > UINT16_MAX) { + if(errno != 0 || *endptr != '\0' || result > UINT16_MAX) { return false; } *out = (uint16_t)result; @@ -140,7 +140,7 @@ bool_t stringToF32(const char_t *str, float_t *out) { char_t *endptr; errno = 0; float_t result = strtof(str, &endptr); - if (errno != 0 || *endptr != '\0') { + if(errno != 0 || *endptr != '\0') { return false; } *out = result;