Chunk load skin
This commit is contained in:
@@ -19,23 +19,30 @@ map_t MAP;
|
|||||||
|
|
||||||
errorret_t mapInit() {
|
errorret_t mapInit() {
|
||||||
memoryZero(&MAP, sizeof(map_t));
|
memoryZero(&MAP, sizeof(map_t));
|
||||||
|
|
||||||
MAP.loaded = true;
|
MAP.loaded = true;
|
||||||
int32_t i = 0;
|
|
||||||
for(chunkunit_t z = 0; z < MAP_CHUNK_DEPTH; z++) {
|
MAP.loadPosition = (chunkpos_t){
|
||||||
for(chunkunit_t y = 0; y < MAP_CHUNK_HEIGHT; y++) {
|
-(MAP_CHUNK_SKIN),
|
||||||
for(chunkunit_t x = 0; x < MAP_CHUNK_WIDTH; x++) {
|
-(MAP_CHUNK_SKIN),
|
||||||
chunk_t *chunk = &MAP.chunks[i];
|
-(MAP_CHUNK_SKIN)
|
||||||
chunk->position.x = x + MAP.chunkPosition.x;
|
};
|
||||||
chunk->position.y = y + MAP.chunkPosition.y;
|
|
||||||
chunk->position.z = z + MAP.chunkPosition.z;
|
chunkindex_t i = 0;
|
||||||
MAP.chunkOrder[i] = chunk;
|
for(chunkunit_t z = 0; z < MAP_LOADED_CHUNK_DEPTH; z++) {
|
||||||
|
for(chunkunit_t y = 0; y < MAP_LOADED_CHUNK_HEIGHT; y++) {
|
||||||
|
for(chunkunit_t x = 0; x < MAP_LOADED_CHUNK_WIDTH; x++) {
|
||||||
|
chunk_t *chunk = &MAP.chunks[i++];
|
||||||
|
chunk->position = (chunkpos_t){
|
||||||
|
MAP.loadPosition.x + (chunkunit_t)x,
|
||||||
|
MAP.loadPosition.y + (chunkunit_t)y,
|
||||||
|
MAP.loadPosition.z + (chunkunit_t)z
|
||||||
|
};
|
||||||
errorChain(mapChunkLoad(chunk));
|
errorChain(mapChunkLoad(chunk));
|
||||||
i++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mapRebuildChunkOrder();
|
||||||
errorOk();
|
errorOk();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,72 +52,77 @@ bool_t mapIsLoaded() {
|
|||||||
|
|
||||||
errorret_t mapPositionSet(const chunkpos_t newPos) {
|
errorret_t mapPositionSet(const chunkpos_t newPos) {
|
||||||
if(!mapIsLoaded()) errorThrow("No map loaded");
|
if(!mapIsLoaded()) errorThrow("No map loaded");
|
||||||
|
if(chunkPositionIsEqual(newPos, MAP.chunkPosition)) errorOk();
|
||||||
|
|
||||||
const chunkpos_t curPos = MAP.chunkPosition;
|
// If the new render window still fits inside the current loaded area,
|
||||||
if(chunkPositionIsEqual(curPos, newPos)) {
|
// just remap chunkOrder — no asset I/O needed.
|
||||||
|
const chunkpos_t lp = MAP.loadPosition;
|
||||||
|
if(
|
||||||
|
newPos.x >= lp.x &&
|
||||||
|
newPos.y >= lp.y &&
|
||||||
|
newPos.z >= lp.z &&
|
||||||
|
newPos.x + MAP_CHUNK_WIDTH <= lp.x + MAP_LOADED_CHUNK_WIDTH &&
|
||||||
|
newPos.y + MAP_CHUNK_HEIGHT <= lp.y + MAP_LOADED_CHUNK_HEIGHT &&
|
||||||
|
newPos.z + MAP_CHUNK_DEPTH <= lp.z + MAP_LOADED_CHUNK_DEPTH
|
||||||
|
) {
|
||||||
|
MAP.chunkPosition = newPos;
|
||||||
|
mapRebuildChunkOrder();
|
||||||
errorOk();
|
errorOk();
|
||||||
}
|
}
|
||||||
|
|
||||||
chunkindex_t chunksRemaining[MAP_CHUNK_COUNT] = {0};
|
// Render window fell outside the loaded area — re-centre the load
|
||||||
chunkindex_t chunksFreed[MAP_CHUNK_COUNT] = {0};
|
// window on the new render position (skin buffer on every side).
|
||||||
|
const chunkpos_t newLoadPos = {
|
||||||
uint32_t remainingCount = 0;
|
newPos.x - MAP_CHUNK_SKIN,
|
||||||
uint32_t freedCount = 0;
|
newPos.y - MAP_CHUNK_SKIN,
|
||||||
|
newPos.z - MAP_CHUNK_SKIN
|
||||||
for(chunkindex_t i = 0; i < MAP_CHUNK_COUNT; i++) {
|
|
||||||
chunk_t *chunk = &MAP.chunks[i];
|
|
||||||
if(
|
|
||||||
chunk->position.x >= newPos.x &&
|
|
||||||
chunk->position.x < newPos.x + MAP_CHUNK_WIDTH &&
|
|
||||||
|
|
||||||
chunk->position.y >= newPos.y &&
|
|
||||||
chunk->position.y < newPos.y + MAP_CHUNK_HEIGHT &&
|
|
||||||
|
|
||||||
chunk->position.z >= newPos.z &&
|
|
||||||
chunk->position.z < newPos.z + MAP_CHUNK_DEPTH
|
|
||||||
) {
|
|
||||||
chunksRemaining[remainingCount++] = i;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
chunksFreed[freedCount++] = i;
|
|
||||||
}
|
|
||||||
|
|
||||||
for(chunkindex_t i = 0; i < freedCount; i++) {
|
|
||||||
chunk_t *chunk = &MAP.chunks[chunksFreed[i]];
|
|
||||||
mapChunkUnload(chunk);
|
|
||||||
}
|
|
||||||
|
|
||||||
chunkindex_t orderIndex = 0;
|
|
||||||
for(chunkunit_t zOff = 0; zOff < MAP_CHUNK_DEPTH; zOff++) {
|
|
||||||
for(chunkunit_t yOff = 0; yOff < MAP_CHUNK_HEIGHT; yOff++) {
|
|
||||||
for(chunkunit_t xOff = 0; xOff < MAP_CHUNK_WIDTH; xOff++) {
|
|
||||||
const chunkpos_t newChunkPos = {
|
|
||||||
newPos.x + xOff, newPos.y + yOff, newPos.z + zOff
|
|
||||||
};
|
};
|
||||||
|
|
||||||
chunkindex_t chunkIndex = -1;
|
// Separate loaded chunks into "keep" and "free" buckets.
|
||||||
for(chunkindex_t i = 0; i < remainingCount; i++) {
|
chunkindex_t chunksFreed[MAP_LOADED_CHUNK_COUNT];
|
||||||
chunk_t *chunk = &MAP.chunks[chunksRemaining[i]];
|
uint32_t freedCount = 0;
|
||||||
if(!chunkPositionIsEqual(chunk->position, newChunkPos)) continue;
|
|
||||||
chunkIndex = chunksRemaining[i];
|
// Use a boolean grid so the inner load loop can check O(1).
|
||||||
break;
|
bool_t posLoaded[MAP_LOADED_CHUNK_WIDTH][MAP_LOADED_CHUNK_HEIGHT]
|
||||||
|
[MAP_LOADED_CHUNK_DEPTH];
|
||||||
|
memoryZero(posLoaded, sizeof(posLoaded));
|
||||||
|
|
||||||
|
for(chunkindex_t i = 0; i < MAP_LOADED_CHUNK_COUNT; i++) {
|
||||||
|
chunk_t *chunk = &MAP.chunks[i];
|
||||||
|
chunkunit_t rx = chunk->position.x - newLoadPos.x;
|
||||||
|
chunkunit_t ry = chunk->position.y - newLoadPos.y;
|
||||||
|
chunkunit_t rz = chunk->position.z - newLoadPos.z;
|
||||||
|
if(
|
||||||
|
rx >= 0 && rx < MAP_LOADED_CHUNK_WIDTH &&
|
||||||
|
ry >= 0 && ry < MAP_LOADED_CHUNK_HEIGHT &&
|
||||||
|
rz >= 0 && rz < MAP_LOADED_CHUNK_DEPTH
|
||||||
|
) {
|
||||||
|
posLoaded[rx][ry][rz] = true;
|
||||||
|
} else {
|
||||||
|
mapChunkUnload(chunk);
|
||||||
|
chunksFreed[freedCount++] = i;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(chunkIndex == -1) {
|
for(chunkunit_t z = 0; z < MAP_LOADED_CHUNK_DEPTH; z++) {
|
||||||
chunkIndex = chunksFreed[--freedCount];
|
for(chunkunit_t y = 0; y < MAP_LOADED_CHUNK_HEIGHT; y++) {
|
||||||
chunk_t *chunk = &MAP.chunks[chunkIndex];
|
for(chunkunit_t x = 0; x < MAP_LOADED_CHUNK_WIDTH; x++) {
|
||||||
chunk->position = newChunkPos;
|
if(posLoaded[x][y][z]) continue;
|
||||||
|
assertTrue(freedCount > 0, "No free chunk slot available.");
|
||||||
|
chunk_t *chunk = &MAP.chunks[chunksFreed[--freedCount]];
|
||||||
|
chunk->position = (chunkpos_t){
|
||||||
|
newLoadPos.x + (chunkunit_t)x,
|
||||||
|
newLoadPos.y + (chunkunit_t)y,
|
||||||
|
newLoadPos.z + (chunkunit_t)z
|
||||||
|
};
|
||||||
errorChain(mapChunkLoad(chunk));
|
errorChain(mapChunkLoad(chunk));
|
||||||
}
|
}
|
||||||
|
|
||||||
MAP.chunkOrder[orderIndex++] = &MAP.chunks[chunkIndex];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MAP.loadPosition = newLoadPos;
|
||||||
MAP.chunkPosition = newPos;
|
MAP.chunkPosition = newPos;
|
||||||
|
mapRebuildChunkOrder();
|
||||||
errorOk();
|
errorOk();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,21 +131,16 @@ errorret_t mapUpdate() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
errorret_t mapDispose() {
|
errorret_t mapDispose() {
|
||||||
for(chunkindex_t i = 0; i < MAP_CHUNK_COUNT; i++) {
|
for(chunkindex_t i = 0; i < MAP_LOADED_CHUNK_COUNT; i++) {
|
||||||
mapChunkUnload(&MAP.chunks[i]);
|
mapChunkUnload(&MAP.chunks[i]);
|
||||||
}
|
}
|
||||||
errorOk();
|
errorOk();
|
||||||
}
|
}
|
||||||
|
|
||||||
void mapChunkUnload(chunk_t *chunk) {
|
void mapChunkUnload(chunk_t *chunk) {
|
||||||
uint8_t chunkIndex = (uint8_t)(chunk - MAP.chunks);
|
|
||||||
for(uint8_t i = 0; i < CHUNK_ENTITY_COUNT_MAX; i++) {
|
for(uint8_t i = 0; i < CHUNK_ENTITY_COUNT_MAX; i++) {
|
||||||
if(chunk->entities[i] == 0xFF) continue;
|
if(chunk->entities[i] == 0xFF) continue;
|
||||||
entity_t *entity = &ENTITIES[chunk->entities[i]];
|
entity_t *entity = &ENTITIES[chunk->entities[i]];
|
||||||
assertTrue(
|
|
||||||
entity->chunkIndex == chunkIndex,
|
|
||||||
"Entity chunk index does not match chunk"
|
|
||||||
);
|
|
||||||
if(entity->type == ENTITY_TYPE_PLAYER) {
|
if(entity->type == ENTITY_TYPE_PLAYER) {
|
||||||
entitySetChunk(entity, 0xFF);
|
entitySetChunk(entity, 0xFF);
|
||||||
} else {
|
} else {
|
||||||
@@ -235,6 +242,24 @@ tile_t mapGetTile(const worldpos_t position) {
|
|||||||
return chunk->tiles[tileIndex];
|
return chunk->tiles[tileIndex];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void mapRebuildChunkOrder() {
|
||||||
|
memoryZero(MAP.chunkOrder, sizeof(MAP.chunkOrder));
|
||||||
|
for(chunkindex_t i = 0; i < MAP_LOADED_CHUNK_COUNT; i++) {
|
||||||
|
chunk_t *chunk = &MAP.chunks[i];
|
||||||
|
const chunkpos_t rel = {
|
||||||
|
chunk->position.x - MAP.chunkPosition.x,
|
||||||
|
chunk->position.y - MAP.chunkPosition.y,
|
||||||
|
chunk->position.z - MAP.chunkPosition.z
|
||||||
|
};
|
||||||
|
if(
|
||||||
|
rel.x < 0 || rel.x >= MAP_CHUNK_WIDTH ||
|
||||||
|
rel.y < 0 || rel.y >= MAP_CHUNK_HEIGHT ||
|
||||||
|
rel.z < 0 || rel.z >= MAP_CHUNK_DEPTH
|
||||||
|
) continue;
|
||||||
|
MAP.chunkOrder[chunkPosToIndex(&rel)] = chunk;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void mapChunkLoadError(void *params, void *user) {
|
void mapChunkLoadError(void *params, void *user) {
|
||||||
assertNotNull(params, "mapChunkLoadError: params cannot be NULL");
|
assertNotNull(params, "mapChunkLoadError: params cannot be NULL");
|
||||||
assertNotNull(user, "mapChunkLoadError: user cannot be NULL");
|
assertNotNull(user, "mapChunkLoadError: user cannot be NULL");
|
||||||
|
|||||||
@@ -12,14 +12,12 @@
|
|||||||
#define MAP_FILE_PATH_MAX 128
|
#define MAP_FILE_PATH_MAX 128
|
||||||
|
|
||||||
typedef struct map_s {
|
typedef struct map_s {
|
||||||
// char_t filePath[MAP_FILE_PATH_MAX];
|
|
||||||
// char_t dirPath[MAP_FILE_PATH_MAX];
|
|
||||||
// char_t fileName[MAP_FILE_PATH_MAX];
|
|
||||||
bool_t loaded;
|
bool_t loaded;
|
||||||
|
|
||||||
chunk_t chunks[MAP_CHUNK_COUNT];
|
chunk_t chunks[MAP_LOADED_CHUNK_COUNT];
|
||||||
chunk_t *chunkOrder[MAP_CHUNK_COUNT];
|
chunk_t *chunkOrder[MAP_CHUNK_COUNT];
|
||||||
chunkpos_t chunkPosition;
|
chunkpos_t chunkPosition;
|
||||||
|
chunkpos_t loadPosition;
|
||||||
} map_t;
|
} map_t;
|
||||||
|
|
||||||
extern map_t MAP;
|
extern map_t MAP;
|
||||||
@@ -106,6 +104,12 @@ void mapChunkLoadError(void *params, void *user);
|
|||||||
*/
|
*/
|
||||||
void mapChunkLoaded(void *params, void *user);
|
void mapChunkLoaded(void *params, void *user);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rebuilds chunkOrder from the loaded chunks that fall within the
|
||||||
|
* current render window. Called whenever chunkPosition changes.
|
||||||
|
*/
|
||||||
|
void mapRebuildChunkOrder();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the index of a chunk, within the world, at the given position.
|
* Gets the index of a chunk, within the world, at the given position.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -22,6 +22,16 @@
|
|||||||
#define MAP_CHUNK_DEPTH 4
|
#define MAP_CHUNK_DEPTH 4
|
||||||
#define MAP_CHUNK_COUNT (MAP_CHUNK_WIDTH * MAP_CHUNK_HEIGHT * MAP_CHUNK_DEPTH)
|
#define MAP_CHUNK_COUNT (MAP_CHUNK_WIDTH * MAP_CHUNK_HEIGHT * MAP_CHUNK_DEPTH)
|
||||||
|
|
||||||
|
// Extra chunks loaded on every side beyond the render window.
|
||||||
|
// The render window can drift MAP_CHUNK_SKIN chunks in any direction
|
||||||
|
// before a load/unload cycle is triggered.
|
||||||
|
#define MAP_CHUNK_SKIN 1
|
||||||
|
#define MAP_LOADED_CHUNK_WIDTH (MAP_CHUNK_WIDTH + MAP_CHUNK_SKIN)
|
||||||
|
#define MAP_LOADED_CHUNK_HEIGHT (MAP_CHUNK_HEIGHT + MAP_CHUNK_SKIN)
|
||||||
|
#define MAP_LOADED_CHUNK_DEPTH (MAP_CHUNK_DEPTH + MAP_CHUNK_SKIN)
|
||||||
|
#define MAP_LOADED_CHUNK_COUNT \
|
||||||
|
(MAP_LOADED_CHUNK_WIDTH * MAP_LOADED_CHUNK_HEIGHT * MAP_LOADED_CHUNK_DEPTH)
|
||||||
|
|
||||||
#define ENTITY_COUNT 32
|
#define ENTITY_COUNT 32
|
||||||
|
|
||||||
typedef int16_t worldunit_t;
|
typedef int16_t worldunit_t;
|
||||||
|
|||||||
@@ -120,7 +120,8 @@ errorret_t sceneOverworldRender(scenedata_t *sceneData) {
|
|||||||
|
|
||||||
errorret_t sceneOverworldDrawChunks() {
|
errorret_t sceneOverworldDrawChunks() {
|
||||||
for(chunkindex_t i = 0; i < MAP_CHUNK_COUNT; i++) {
|
for(chunkindex_t i = 0; i < MAP_CHUNK_COUNT; i++) {
|
||||||
chunk_t *chunk = &MAP.chunks[i];
|
chunk_t *chunk = MAP.chunkOrder[i];
|
||||||
|
if(chunk == NULL) continue;
|
||||||
if(chunk->meshCount == 0) continue;
|
if(chunk->meshCount == 0) continue;
|
||||||
|
|
||||||
for(uint8_t m = 0; m < chunk->meshCount; m++) {
|
for(uint8_t m = 0; m < chunk->meshCount; m++) {
|
||||||
|
|||||||
Reference in New Issue
Block a user