Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added asset/texture/brown_photostudio_02_2k.hdr
Binary file not shown.
5 changes: 3 additions & 2 deletions source/paimon/app/application.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,11 @@ Application::Application(const ApplicationConfig& config) {
// Create window
m_window = Window::create(config.windowConfig, config.contextFormat);

m_scene = ecs::Scene::create();

// Load shaders
m_shaderManager.load(PAIMON_SHADER_DIR);

m_scene = ecs::Scene::create();

m_imguiLayer = pushLayer(std::make_unique<ImGuiLayer>());

pushLayer(std::make_unique<EditorLayer>());
Expand Down
2 changes: 1 addition & 1 deletion source/paimon/app/panel/menu_panel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ void MenuPanel::showFileMenu() {
if (result == NFD_OKAY) {
auto& scene = Application::getInstance().getScene();
LOG_INFO("Loading model: {}", outPath);
scene.load(outPath);
scene.loadModel(outPath);
NFD_FreePathU8(outPath);
} else if (result == NFD_ERROR) {
LOG_ERROR("Error opening file dialog: {}", NFD_GetError());
Expand Down
60 changes: 52 additions & 8 deletions source/paimon/core/ecs/scene.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
#include "paimon/core/ecs/scene.h"

#include "paimon/core/ecs/components.h"
#include "paimon/core/ecs/entity.h"
#include "paimon/core/io/gltf.h"
#include "paimon/core/io/ibl.h"
#include "paimon/config.h"
#include <algorithm>
#include <filesystem>

namespace paimon {
namespace ecs {
Expand All @@ -22,9 +27,44 @@ Entity Scene::createEntity(const std::string &name) {
}

void Scene::destroyEntity(Entity entity) {
if (entity.isValid() && entity.getScene() == this) {
m_registry.destroy(entity.getHandle());
if (!entity.isValid() || entity.getScene() != this) {
return;
}

// Destroy all descendants first to avoid leaving orphan entities.
std::vector<Entity> childrenSnapshot;
if (entity.hasComponent<Children>()) {
childrenSnapshot = entity.getComponent<Children>().children;
}

for (auto child : childrenSnapshot) {
if (child.isValid() && child.getScene() == this && child != entity) {
destroyEntity(child);
}
}

// Remove this entity from its parent's children list.
if (entity.hasComponent<Parent>()) {
auto parent = entity.getComponent<Parent>().parent;
if (parent.isValid() && parent.getScene() == this &&
parent.hasComponent<Children>()) {
auto &siblings = parent.getComponent<Children>().children;
siblings.erase(std::remove(siblings.begin(), siblings.end(), entity),
siblings.end());
}
}

if (m_mainCamera == entity) {
m_mainCamera = Entity{};
}
if (m_directionalLight == entity) {
m_directionalLight = Entity{};
}
if (m_environment == entity) {
m_environment = Entity{};
}

m_registry.destroy(entity.getHandle());
}

entt::registry &Scene::getRegistry() { return m_registry; }
Expand All @@ -37,10 +77,14 @@ bool Scene::valid(entt::entity entity) const {
return m_registry.valid(entity);
}

Entity Scene::load(const std::filesystem::path &filepath) {
void Scene::loadModel(const std::filesystem::path &filepath) {
GltfLoader loader(filepath);
loader.load(*this);
return loader.getRootEntity();
}

void Scene::loadEnvironment(const std::filesystem::path &filepath) {
IBLLoader loader(filepath);
loader.load(*this);
}

std::unique_ptr<Scene> Scene::create() {
Expand Down Expand Up @@ -70,11 +114,11 @@ std::unique_ptr<Scene> Scene::create() {
}

{
// Initialize environment entity
auto environment = scene->createEntity("Environment");
environment.addComponent<Environment>();
auto envEntity = scene->createEntity("Environment");
envEntity.addComponent<ecs::Environment>();
scene->setEnvironment(envEntity);

scene->setEnvironment(environment);
scene->loadEnvironment(std::filesystem::path(PAIMON_TEXTURE_DIR) / "belfast_sunset_puresky_2k.hdr");
}

return scene;
Expand Down
4 changes: 3 additions & 1 deletion source/paimon/core/ecs/scene.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,9 @@ class Scene {
// Check if entity is valid
bool valid(entt::entity entity) const;

Entity load(const std::filesystem::path &filepath);
void loadModel(const std::filesystem::path &filepath);

void loadEnvironment(const std::filesystem::path &filepath);

static std::unique_ptr<Scene> create();

Expand Down
19 changes: 9 additions & 10 deletions source/paimon/core/io/gltf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,8 @@ glm::mat4 parseMat4(const std::vector<double> data) {

GltfLoader::GltfLoader(const std::filesystem::path &filepath) {

m_filepath = filepath;

tinygltf::TinyGLTF loader;
std::string errorMessage;
std::string warningMessage;
Expand Down Expand Up @@ -230,8 +232,14 @@ void GltfLoader::load(ecs::Scene &scene) {
parseMaterials();
parseMeshes(); // Step 4: mesh primitives reference accessor Buffers

auto entityName = m_filepath.stem().string();
auto rootEntity = scene.createEntity(entityName);

int sceneIndex = m_model.defaultScene >= 0 ? m_model.defaultScene : 0;
parseScene(m_model.scenes[sceneIndex], scene);
for (const auto nodeIndex : m_model.scenes[sceneIndex].nodes) {
const auto &node = m_model.nodes[nodeIndex];
parseNode(node, rootEntity, scene);
}
}

// ============================================================================
Expand Down Expand Up @@ -468,12 +476,3 @@ void GltfLoader::parseNode(const tinygltf::Node &node, ecs::Entity parent, ecs::
parseNode(childNode, nodeEntity, scene);
}
}

void GltfLoader::parseScene(const tinygltf::Scene &scene, ecs::Scene &ecs_scene) {
// Implementation for parsing a glTF scene into an ECS scene
m_rootEntity = ecs_scene.createEntity("RootNode");
for (const auto nodeIndex : scene.nodes) {
const auto &node = m_model.nodes[nodeIndex];
parseNode(node, m_rootEntity, ecs_scene);
}
}
9 changes: 2 additions & 7 deletions source/paimon/core/io/gltf.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,6 @@ class GltfLoader {

void load(ecs::Scene &scene);

const ecs::Entity &getRootEntity() const { return m_rootEntity; }

ecs::Entity getRootEntity() { return m_rootEntity; }

private:
void parseBuffers();
void parseBufferViews();
Expand All @@ -44,12 +40,11 @@ class GltfLoader {
void parseMeshes();

void parseNode(const tinygltf::Node &node, ecs::Entity parent, ecs::Scene &scene);
void parseScene(const tinygltf::Scene &scene, ecs::Scene &ecs_scene);

private:
tinygltf::Model m_model;
std::filesystem::path m_filepath;

ecs::Entity m_rootEntity;
tinygltf::Model m_model;

std::vector<std::shared_ptr<Sampler>> m_samplers;
std::vector<std::shared_ptr<Texture>> m_images;
Expand Down
12 changes: 4 additions & 8 deletions source/paimon/core/io/ibl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <stb_image_write.h>

#include "paimon/core/ecs/components.h"
#include "paimon/core/ecs/entity.h"
#include "paimon/core/log_system.h"
#include "paimon/rendering/render_context.h"
#include "paimon/utility/brdf_lut_pass.h"
Expand Down Expand Up @@ -48,14 +49,9 @@ void IBLLoader::load(ecs::Scene &scene) {

// Get the existing Environment entity, or create a new one.
auto envEntity = scene.getEnvironment();
if (!envEntity) {
envEntity = scene.createEntity("Environment");
envEntity.addComponent<ecs::Environment>();
scene.setEnvironment(envEntity);
LOG_INFO("IBLLoader: created new Environment entity");
}
envEntity.removeComponent<ecs::Environment>();

auto &envComp = envEntity.getOrAddComponent<ecs::Environment>();
auto &envComp = envEntity.addComponent<ecs::Environment>();
envComp.equirectangularMap = m_equirectangularTexture;
envComp.irradianceMap = m_irradianceMapPass->getIrradianceMap();
envComp.prefilteredMap = m_prefilteredMapPass->getPrefilteredMap();
Expand All @@ -65,7 +61,7 @@ void IBLLoader::load(ecs::Scene &scene) {
m_filepath.string());

#ifdef PAIMON_DEBUG
// save((std::filesystem::path(PAIMON_TEXTURE_DIR) / "ibl_output"));
save((std::filesystem::path(PAIMON_TEXTURE_DIR) / "ibl_output"));
#endif
}

Expand Down
4 changes: 3 additions & 1 deletion source/paimon/core/io/ibl.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include <filesystem>
#include <memory>

#include "paimon/core/ecs/entity.h"
#include "paimon/core/ecs/scene.h"
#include "paimon/opengl/texture.h"

Expand Down Expand Up @@ -31,7 +32,6 @@ class IBLLoader {
IBLLoader &operator=(const IBLLoader &) = delete;

void load(ecs::Scene &scene);
void save(const std::filesystem::path &directory);

private:
void loadHDRTexture();
Expand All @@ -41,6 +41,8 @@ class IBLLoader {
void save2DTexture(const Texture &texture, const std::filesystem::path &filepath,
int width, int height);

void save(const std::filesystem::path &directory);

private:
std::filesystem::path m_filepath;

Expand Down
12 changes: 12 additions & 0 deletions source/paimon/core/macro.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,15 @@
#if defined linux || defined __linux || defined __linux__
#define PAIMON_OS_UNIX
#endif

#ifdef PAIMON_OS_WINDOWS
#if defined (DEBUG) || defined (_DEBUG)
#define PAIMON_DEBUG
#endif
#endif

#ifdef PAIMON_OS_UNIX
#if !defined (NDEBUG)
#define PAIMON_DEBUG
#endif
#endif
40 changes: 22 additions & 18 deletions source/paimon/rendering/render_pass/color_pass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,13 @@ ColorPass::ColorPass(RenderContext &renderContext)
m_color_texture = std::make_unique<Texture>(GL_TEXTURE_2D);
m_depth_texture = std::make_unique<Texture>(GL_TEXTURE_2D);

// 1x1 white fallback texture: ensures ao=1.0 when occlusion texture is absent,
// and correct defaults for other missing material textures.
m_default_white_texture = std::make_unique<Texture>(GL_TEXTURE_2D);
m_default_white_texture->set_storage_2d(1, GL_RGBA8, 1, 1);
const uint8_t white[4] = {255, 255, 255, 255};
m_default_white_texture->set_sub_image_2d(0, 0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, white);

// Create uniform buffers and storage buffers
m_transform_ubo.set_storage(sizeof(TransformUBO), nullptr,
GL_DYNAMIC_STORAGE_BIT);
Expand Down Expand Up @@ -278,24 +285,21 @@ void ColorPass::draw(RenderContext &ctx, const glm::ivec2 &resolution,
materialData.roughnessFactor = pbr.roughnessFactor;
m_material_ubo.set_sub_data(0, sizeof(MaterialUBO), &materialData);

// Bind textures with sampler
if (pbr.baseColorTexture && pbr.baseColorTexture->image) {
ctx.bindTexture(0, *pbr.baseColorTexture->image, *m_sampler);
}
if (pbr.metallicRoughnessTexture &&
pbr.metallicRoughnessTexture->image) {
ctx.bindTexture(1, *pbr.metallicRoughnessTexture->image,
*m_sampler);
}
if (mat->normalTexture && mat->normalTexture->image) {
ctx.bindTexture(2, *mat->normalTexture->image, *m_sampler);
}
if (mat->emissiveTexture && mat->emissiveTexture->image) {
ctx.bindTexture(3, *mat->emissiveTexture->image, *m_sampler);
}
if (mat->occlusionTexture && mat->occlusionTexture->image) {
ctx.bindTexture(4, *mat->occlusionTexture->image, *m_sampler);
}
// Bind textures with sampler; fall back to white 1x1 so that
// missing textures don't leave stale bindings from previous draws.
// Critically: occlusion (slot 4) must default to white (ao=1.0),
// otherwise the entire IBL contribution is zeroed out.
auto& white = *m_default_white_texture;
ctx.bindTexture(0, (pbr.baseColorTexture && pbr.baseColorTexture->image)
? *pbr.baseColorTexture->image : white, *m_sampler);
ctx.bindTexture(1, (pbr.metallicRoughnessTexture && pbr.metallicRoughnessTexture->image)
? *pbr.metallicRoughnessTexture->image : white, *m_sampler);
ctx.bindTexture(2, (mat->normalTexture && mat->normalTexture->image)
? *mat->normalTexture->image : white, *m_sampler);
ctx.bindTexture(3, (mat->emissiveTexture && mat->emissiveTexture->image)
? *mat->emissiveTexture->image : white, *m_sampler);
ctx.bindTexture(4, (mat->occlusionTexture && mat->occlusionTexture->image)
? *mat->occlusionTexture->image : white, *m_sampler);
}

// Bind IBL textures (bindings 5/6/7 match shader layout)
Expand Down
1 change: 1 addition & 0 deletions source/paimon/rendering/render_pass/color_pass.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ class ColorPass {

std::unique_ptr<Texture> m_color_texture;
std::unique_ptr<Texture> m_depth_texture;
std::unique_ptr<Texture> m_default_white_texture; // fallback for missing material textures (ao=1)

std::unique_ptr<Sampler> m_sampler;
std::unique_ptr<Sampler> m_ibl_sampler; // Cubemap sampler for IBL textures
Expand Down
Loading