Files
dusk/archive/rpg/overworld/sceneoverworld.c
2025-10-06 19:14:52 -05:00

146 lines
4.1 KiB
C

/**
* Copyright (c) 2025 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "sceneoverworld.h"
#include "rpg/entity/entity.h"
#include "display/spritebatch.h"
#include "display/framebuffer.h"
#include "display/scene/scenemanager.h"
#include "display/mesh/quad.h"
#include "asset/assetmanager.h"
#include "assert/assert.h"
#include "display/tileset/tileset_entities.h"
sceneoverworld_t SCENE_OVERWORLD;
asset_t *testAsset;
ref_t testAssetRef;
errorret_t sceneOverworldInit(void) {
cameraInit(&SCENE_OVERWORLD.camera);
glm_vec3_copy((vec3){ 0.0f, 1.0f, 0.0f }, SCENE_OVERWORLD.camera.lookat.up);
SCENE_OVERWORLD.camera.perspective.fov = 45;
SCENE_OVERWORLD.camera.farClip = 10000.0f;
scene_t *scene = &SCENE_MANAGER_SCENES[SCENE_TYPE_OVERWORLD];
scene->flags |= SCENE_FLAG_ACTIVE | SCENE_FLAG_VISIBLE;
errorChain(assetManagerLoadAsset(
TILESET_ENTITIES.image, &testAsset, &testAssetRef
));
errorOk();
}
void sceneOverworldUpdate(void) {
if(RPG.map == NULL) return;
// Move camera to player.
const entity_t *start = &RPG.map->entities[0];
const entity_t *end = &RPG.map->entities[RPG.map->entityCount];
while(start < end) {
if(start->type == ENTITY_TYPE_PLAYER) {
SCENE_OVERWORLD.camera.lookat.target[0] = start->position[0];
SCENE_OVERWORLD.camera.lookat.target[1] = start->position[1];
break;
}
start++;
}
}
void sceneOverworldRender(void) {
const float_t camOffset = 12.0f;
const float_t fbWidth = frameBufferGetWidth(FRAMEBUFFER_BOUND);
const float_t fbHeight = frameBufferGetHeight(FRAMEBUFFER_BOUND);
const float_t aspect = fbWidth / fbHeight;
const float_t pixelPerfectOffset = tanf(
(glm_rad(180) - SCENE_OVERWORLD.camera.perspective.fov) / 2.0f
) * (fbHeight/ 2.0f);
// glm_vec3_copy((vec3){
// -100.0f, -100.0f, 0.0f
// }, SCENE_OVERWORLD.camera.lookat.target);
glm_vec3_copy((vec3){
SCENE_OVERWORLD.camera.lookat.target[0],
SCENE_OVERWORLD.camera.lookat.target[1] + camOffset,
SCENE_OVERWORLD.camera.lookat.target[2] + pixelPerfectOffset
}, SCENE_OVERWORLD.camera.lookat.position);
cameraPushMatrix(&SCENE_OVERWORLD.camera);
if(RPG.map != NULL) sceneOverworldRenderMap(RPG.map);
spriteBatchFlush();
cameraPopMatrix();
}
void sceneOverworldRenderMap(const map_t *map) {
assertNotNull(map, "Map pointer cannot be NULL");
// Draw base layer
sceneOverworldRenderMapLayer(map, &map->base);
// Draw entities
const entity_t *start = &map->entities[0];
const entity_t *end = &map->entities[map->entityCount];
while(start < end) {
// Render entity here.
sceneOverworldRenderEntity(start);
start++;
}
spriteBatchFlush();
// Draw overlay layer.
sceneOverworldRenderMapLayer(map, &map->overlay);
}
void sceneOverworldRenderEntity(const entity_t *entity) {
assertNotNull(entity, "Entity pointer cannot be NULL");
assertTrue(entity->type < ENTITY_TYPE_COUNT, "Invalid entity type");
assertTrue(entity->type != ENTITY_TYPE_NULL, "Cannot have NULL entity type");
vec4 uv;
tilesetPositionGetUV(&TILESET_ENTITIES, entity->direction, 0, uv);
// For now, just draw a placeholder quad.
spriteBatchPush(
&testAsset->paletteImage.texture,
entity->position[0], entity->position[1],
entity->position[0] + TILESET_ENTITIES.tileWidth,
entity->position[1] + TILESET_ENTITIES.tileHeight,
COLOR_WHITE,
uv[0], uv[1], uv[2], uv[3]
);
}
void sceneOverworldRenderMapLayer(const map_t *map, const maplayer_t *layer) {
assertNotNull(layer, "Map layer pointer cannot be NULL");
for(uint32_t y = 0; y < map->height; y++) {
for(uint32_t x = 0; x < map->width; x++) {
const tile_t *tile = &layer->tiles[y * map->width + x];
if(tile->id == 0) continue;
spriteBatchPush(
NULL,
x * TILESET_ENTITIES.tileWidth,
y * TILESET_ENTITIES.tileHeight,
(x + 1) * TILESET_ENTITIES.tileWidth,
(y + 1) * TILESET_ENTITIES.tileHeight,
COLOR_RED,
0, 0, 1, 1
);
}
}
spriteBatchFlush();
}
void sceneOverworldDispose(void) {
// Dispose of the overworld scene.
if(testAsset) assetUnlock(testAsset, testAssetRef);
}