Chunk loading example
This commit is contained in:
@@ -22,8 +22,8 @@ find_package_handle_standard_args(
|
|||||||
_libzip_pkgcfg
|
_libzip_pkgcfg
|
||||||
)
|
)
|
||||||
|
|
||||||
if (LIBZIP_FOUND)
|
if(LIBZIP_FOUND)
|
||||||
if (NOT TARGET libzip::zip)
|
if(NOT TARGET libzip::zip)
|
||||||
add_library(libzip::zip UNKNOWN IMPORTED)
|
add_library(libzip::zip UNKNOWN IMPORTED)
|
||||||
set_target_properties(libzip::zip
|
set_target_properties(libzip::zip
|
||||||
PROPERTIES
|
PROPERTIES
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ void textureInit(
|
|||||||
const palette_t *pal = PALETTE_LIST[data.palette.palette];
|
const palette_t *pal = PALETTE_LIST[data.palette.palette];
|
||||||
assertNotNull(pal, "Palette cannot be NULL");
|
assertNotNull(pal, "Palette cannot be NULL");
|
||||||
GLenum err = glGetError();
|
GLenum err = glGetError();
|
||||||
if (err != GL_NO_ERROR) {
|
if(err != GL_NO_ERROR) {
|
||||||
assertUnreachable("GL Error before setting color table");
|
assertUnreachable("GL Error before setting color table");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,9 +82,9 @@ void textureInit(
|
|||||||
glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &mask);
|
glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &mask);
|
||||||
if(mask & GL_CONTEXT_CORE_PROFILE_BIT) {
|
if(mask & GL_CONTEXT_CORE_PROFILE_BIT) {
|
||||||
GLint n=0; glGetIntegerv(GL_NUM_EXTENSIONS, &n);
|
GLint n=0; glGetIntegerv(GL_NUM_EXTENSIONS, &n);
|
||||||
for (GLint i=0; i<n; ++i) {
|
for(GLint i=0; i<n; ++i) {
|
||||||
const char* e = (const char*)glGetStringi(GL_EXTENSIONS, i);
|
const char* e = (const char*)glGetStringi(GL_EXTENSIONS, i);
|
||||||
if (e && strcmp(e, "GL_EXT_paletted_texture")==0) { havePalTex = true; break; }
|
if(e && strcmp(e, "GL_EXT_paletted_texture")==0) { havePalTex = true; break; }
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const char* ext = (const char*)glGetString(GL_EXTENSIONS);
|
const char* ext = (const char*)glGetString(GL_EXTENSIONS);
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ errorret_t errorChainImpl(
|
|||||||
const char_t *function,
|
const char_t *function,
|
||||||
const int32_t line
|
const int32_t line
|
||||||
) {
|
) {
|
||||||
if (retval.code == ERROR_OK) return retval;
|
if(retval.code == ERROR_OK) return retval;
|
||||||
|
|
||||||
assertNotNull(retval.state, "Error state NULL (Likely missing errorOk)");
|
assertNotNull(retval.state, "Error state NULL (Likely missing errorOk)");
|
||||||
assertNotNull(retval.state->message, "Message cannot be NULL");
|
assertNotNull(retval.state->message, "Message cannot be NULL");
|
||||||
@@ -106,7 +106,7 @@ errorret_t errorChainImpl(
|
|||||||
}
|
}
|
||||||
|
|
||||||
void errorCatch(const errorret_t retval) {
|
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, "Error state cannot be NULL");
|
||||||
assertNotNull(retval.state->message, "Message 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) {
|
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, "Error state cannot be NULL");
|
||||||
assertNotNull(retval.state->message, "Message cannot be NULL");
|
assertNotNull(retval.state->message, "Message cannot be NULL");
|
||||||
|
|||||||
@@ -152,7 +152,7 @@ errorret_t errorPrint(const errorret_t retval);
|
|||||||
*/
|
*/
|
||||||
#define errorChain(retval) { \
|
#define errorChain(retval) { \
|
||||||
errorret_t errorChainRetval = (retval); \
|
errorret_t errorChainRetval = (retval); \
|
||||||
if (errorChainRetval.code != ERROR_OK) { \
|
if(errorChainRetval.code != ERROR_OK) { \
|
||||||
return errorChainImpl(errorChainRetval, __FILE__, __func__, __LINE__); \
|
return errorChainImpl(errorChainRetval, __FILE__, __func__, __LINE__); \
|
||||||
} \
|
} \
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
#include "time/time.h"
|
#include "time/time.h"
|
||||||
#include "util/math.h"
|
#include "util/math.h"
|
||||||
#include "rpg/cutscene/cutscenemode.h"
|
#include "rpg/cutscene/cutscenemode.h"
|
||||||
|
#include "rpg/world/map.h"
|
||||||
|
|
||||||
entity_t ENTITIES[ENTITY_COUNT];
|
entity_t ENTITIES[ENTITY_COUNT];
|
||||||
|
|
||||||
|
|||||||
@@ -45,7 +45,6 @@ void rpgUpdate(void) {
|
|||||||
if(!TIME.fixedUpdate) return;
|
if(!TIME.fixedUpdate) return;
|
||||||
|
|
||||||
// TODO: Do not update if the scene is not the map scene?
|
// TODO: Do not update if the scene is not the map scene?
|
||||||
|
|
||||||
mapUpdate();
|
mapUpdate();
|
||||||
|
|
||||||
// Update overworld ents.
|
// Update overworld ents.
|
||||||
@@ -55,8 +54,8 @@ void rpgUpdate(void) {
|
|||||||
entityUpdate(ent);
|
entityUpdate(ent);
|
||||||
} while(++ent < &ENTITIES[ENTITY_COUNT]);
|
} while(++ent < &ENTITIES[ENTITY_COUNT]);
|
||||||
|
|
||||||
// Tick the cutscene system.
|
|
||||||
cutsceneSystemUpdate();
|
cutsceneSystemUpdate();
|
||||||
|
rpgCameraUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
void rpgDispose(void) {
|
void rpgDispose(void) {
|
||||||
|
|||||||
@@ -8,9 +8,35 @@
|
|||||||
#include "rpgcamera.h"
|
#include "rpgcamera.h"
|
||||||
#include "util/memory.h"
|
#include "util/memory.h"
|
||||||
#include "rpg/entity/entity.h"
|
#include "rpg/entity/entity.h"
|
||||||
|
#include "rpg/world/map.h"
|
||||||
|
|
||||||
rpgcamera_t RPG_CAMERA;
|
rpgcamera_t RPG_CAMERA;
|
||||||
|
|
||||||
void rpgCameraInit(void) {
|
void rpgCameraInit(void) {
|
||||||
memoryZero(&RPG_CAMERA, sizeof(rpgcamera_t));
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -29,4 +29,9 @@ extern rpgcamera_t RPG_CAMERA;
|
|||||||
/**
|
/**
|
||||||
* Initializes the RPG camera.
|
* Initializes the RPG camera.
|
||||||
*/
|
*/
|
||||||
void rpgCameraInit(void);
|
void rpgCameraInit(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the RPG camera.
|
||||||
|
*/
|
||||||
|
void rpgCameraUpdate(void);
|
||||||
@@ -7,17 +7,119 @@
|
|||||||
|
|
||||||
#include "map.h"
|
#include "map.h"
|
||||||
#include "util/memory.h"
|
#include "util/memory.h"
|
||||||
|
#include <stdio.h> // For printf
|
||||||
|
|
||||||
map_t MAP;
|
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() {
|
void mapInit() {
|
||||||
memoryZero(&MAP, sizeof(map_t));
|
memoryZero(&MAP, sizeof(map_t));
|
||||||
|
|
||||||
for(uint32_t i = 0; i < MAP_CHUNK_COUNT; i++) {
|
uint32_t index = 0;
|
||||||
MAP.chunkOrder[i] = &MAP.chunks[i];
|
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() {
|
void mapUpdate() {
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -29,4 +29,19 @@ void mapInit();
|
|||||||
/**
|
/**
|
||||||
* Updates the map.
|
* Updates the map.
|
||||||
*/
|
*/
|
||||||
void mapUpdate();
|
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);
|
||||||
@@ -8,7 +8,7 @@
|
|||||||
#include "math.h"
|
#include "math.h"
|
||||||
|
|
||||||
uint32_t mathNextPowTwo(uint32_t value) {
|
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 |= value >> 1;
|
value |= value >> 1;
|
||||||
value |= value >> 2;
|
value |= value >> 2;
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ void stringTrim(char_t *str) {
|
|||||||
*(end + 1) = '\0';
|
*(end + 1) = '\0';
|
||||||
|
|
||||||
// Move trimmed string to the original buffer
|
// 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) {
|
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;
|
char_t *endptr;
|
||||||
errno = 0;
|
errno = 0;
|
||||||
long int result = strtol(str, &endptr, 10);
|
long int result = strtol(str, &endptr, 10);
|
||||||
if (errno != 0 || *endptr != '\0') {
|
if(errno != 0 || *endptr != '\0') {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
*out = (int32_t)result;
|
*out = (int32_t)result;
|
||||||
@@ -112,7 +112,7 @@ bool_t stringToI64(const char_t *str, int64_t *out) {
|
|||||||
char_t *endptr;
|
char_t *endptr;
|
||||||
errno = 0;
|
errno = 0;
|
||||||
long long int result = strtoll(str, &endptr, 10);
|
long long int result = strtoll(str, &endptr, 10);
|
||||||
if (errno != 0 || *endptr != '\0') {
|
if(errno != 0 || *endptr != '\0') {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
*out = (int64_t)result;
|
*out = (int64_t)result;
|
||||||
@@ -126,7 +126,7 @@ bool_t stringToU16(const char_t *str, uint16_t *out) {
|
|||||||
char_t *endptr;
|
char_t *endptr;
|
||||||
errno = 0;
|
errno = 0;
|
||||||
unsigned long int result = strtoul(str, &endptr, 10);
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
*out = (uint16_t)result;
|
*out = (uint16_t)result;
|
||||||
@@ -140,7 +140,7 @@ bool_t stringToF32(const char_t *str, float_t *out) {
|
|||||||
char_t *endptr;
|
char_t *endptr;
|
||||||
errno = 0;
|
errno = 0;
|
||||||
float_t result = strtof(str, &endptr);
|
float_t result = strtof(str, &endptr);
|
||||||
if (errno != 0 || *endptr != '\0') {
|
if(errno != 0 || *endptr != '\0') {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
*out = result;
|
*out = result;
|
||||||
|
|||||||
Reference in New Issue
Block a user