diff --git a/CMakeLists.txt b/CMakeLists.txt index d80a62b..2fd1a1c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -199,7 +199,7 @@ target_include_directories(${PROJECT_NAME} SYSTEM PUBLIC dependencies/glm) # spdlog set(SPDLOG_BUILD_SHARED OFF CACHE INTERNAL "" FORCE) +set(SPDLOG_SYSTEM_INCLUDES ON CACHE INTERNAL "" FORCE) set(BUILD_SHARED_LIBS OFF) -add_subdirectory(dependencies/spdlog) +add_subdirectory(dependencies/spdlog) # automatically calls target_include_directories target_link_libraries(${PROJECT_NAME} PUBLIC spdlog) -target_include_directories(${PROJECT_NAME} SYSTEM PUBLIC dependencies/spdlog/include) diff --git a/include/components/mesh_renderable.h b/include/components/mesh_renderable.h index 509f224..8dadf18 100644 --- a/include/components/mesh_renderable.h +++ b/include/components/mesh_renderable.h @@ -9,8 +9,8 @@ namespace engine { struct MeshRenderableComponent { - std::shared_ptr mesh; - std::shared_ptr material; + std::shared_ptr mesh; + std::shared_ptr material; }; } // namespace engine diff --git a/include/renderer.h b/include/renderer.h index c96493f..487e9b2 100644 --- a/include/renderer.h +++ b/include/renderer.h @@ -33,7 +33,7 @@ class Renderer { void PreRender(bool window_is_resized, glm::mat4 camera_transform); // staticList can be nullptr to render nothing - void Render(const RenderList& static_list, const RenderList& dynamic_list); + void Render(const RenderList* static_list, const RenderList* dynamic_list); // getters @@ -78,7 +78,10 @@ class Renderer { */ // ALL fragment shaders must begin with: /* - layout(set = 2, binding = 0) uniform sampler2D materialSetSampler; + layout(set = 2, binding = 0) uniform sampler2D materialSetAlbedoSampler; + layout(set = 2, binding = 1) uniform sampler2D materialSetNormalSampler; + layout(set = 2, binding = 2) uniform sampler2D materialSetOcclusionSampler; + layout(set = 2, binding = 3) uniform sampler2D materialSetMetallicRoughnessSampler; */ // in vertex shader diff --git a/include/resources/font.h b/include/resources/font.h index 82bf736..f6321f1 100644 --- a/include/resources/font.h +++ b/include/resources/font.h @@ -9,7 +9,6 @@ #include namespace engine { -namespace resources { class Font { public: @@ -31,7 +30,6 @@ class Font { int GetGlyphIndex(int unicode_codepoint); }; -} // namespace resources } // namespace engine #endif \ No newline at end of file diff --git a/include/resources/material.h b/include/resources/material.h index 723b6c4..5336509 100644 --- a/include/resources/material.h +++ b/include/resources/material.h @@ -6,26 +6,37 @@ #include "resources/shader.h" #include "resources/texture.h" +// a material is just a shader with assigned textures/parameters + namespace engine { -namespace resources { // copyable class Material { - public: - Material(std::shared_ptr shader); - ~Material() = default; - Material(const Material&); - Material& operator=(const Material&) = delete; + public: + Material(Renderer* renderer, std::shared_ptr shader); + ~Material(); + Material& operator=(const Material&) = delete; - auto GetShader() { return shader_.get(); } + void SetAlbedoTexture(std::shared_ptr texture); + void SetNormalTexture(std::shared_ptr texture); + void SetOcclusionTexture(std::shared_ptr texture); + void SetMetallicRoughnessTexture(std::shared_ptr texture); - std::shared_ptr texture_; + const gfx::DescriptorSet* GetDescriptorSet() { return material_set_; } + Shader* GetShader() { return shader_.get(); } - private: - const std::shared_ptr shader_; + private: + const std::shared_ptr shader_; + std::shared_ptr texture_albedo_; + std::shared_ptr texture_normal_; + std::shared_ptr texture_occlusion_; + std::shared_ptr texture_metallic_roughness_; + + const gfx::DescriptorSet* material_set_ = nullptr; + + Renderer* const renderer_; }; -} // namespace resources -} // namespace engine +} // namespace engine #endif \ No newline at end of file diff --git a/include/resources/mesh.h b/include/resources/mesh.h index d05d6ae..449b717 100644 --- a/include/resources/mesh.h +++ b/include/resources/mesh.h @@ -3,6 +3,7 @@ #include #include +#include #include #include "gfx.h" @@ -13,13 +14,13 @@ namespace engine { struct Vertex { glm::vec3 pos; glm::vec3 norm; + glm::vec4 tangent; // w component flips binormal if -1. w should be 1 or -1 glm::vec2 uv; }; } // namespace engine namespace engine { -namespace resources { class Mesh { public: @@ -48,7 +49,6 @@ class Mesh { const std::vector& indices); }; -} // namespace resources } // namespace engine #endif \ No newline at end of file diff --git a/include/resources/shader.h b/include/resources/shader.h index 136bb44..e44d5d7 100644 --- a/include/resources/shader.h +++ b/include/resources/shader.h @@ -1,12 +1,10 @@ -#ifndef ENGINE_INCLUDE_RESOURCES_SHADER_H_ -#define ENGINE_INCLUDE_RESOURCES_SHADER_H_ +#pragma once #include "application.h" #include "gfx.h" #include "gfx_device.h" namespace engine { -namespace resources { class Shader { public: @@ -43,7 +41,4 @@ class Shader { const int render_order_; }; -} // namespace resources -} // namespace engine - -#endif \ No newline at end of file +} // namespace engine \ No newline at end of file diff --git a/include/resources/texture.h b/include/resources/texture.h index 3c4555b..64fc8dc 100644 --- a/include/resources/texture.h +++ b/include/resources/texture.h @@ -7,36 +7,33 @@ #include "gfx_device.h" namespace engine { -namespace resources { class Texture { - public: - enum class Filtering { - kOff, - kBilinear, - kTrilinear, - kAnisotropic, - }; + public: + enum class Filtering { + kOff, + kBilinear, + kTrilinear, + kAnisotropic, + }; - Texture(Renderer* renderer, const std::string& path, - Filtering filtering); - Texture(Renderer* renderer, const uint8_t* bitmap, int width, int height, - Filtering filtering); + Texture(Renderer* renderer, const uint8_t* bitmap, int width, int height, Filtering filtering); - ~Texture(); - Texture(const Texture&) = delete; - Texture& operator=(const Texture&) = delete; + ~Texture(); + Texture(const Texture&) = delete; + Texture& operator=(const Texture&) = delete; - const gfx::Image* GetImage() { return image_; } - const gfx::DescriptorSet* GetDescriptorSet() { return descriptor_set_; } + const gfx::Image* GetImage() { return image_; } + const gfx::Sampler* GetSampler() { return sampler_; } - private: - GFXDevice* gfx_; - const gfx::Image* image_; - const gfx::DescriptorSet* descriptor_set_; + private: + GFXDevice* gfx_; + const gfx::Image* image_; + const gfx::Sampler* sampler_; // not owned by Texture, owned by Renderer }; -} // namespace resources -} // namespace engine +std::unique_ptr LoadTextureFromFile(const std::string& path, Texture::Filtering filtering, Renderer* renderer); + +} // namespace engine #endif \ No newline at end of file diff --git a/include/scene_manager.h b/include/scene_manager.h index e86ad78..4c484b2 100644 --- a/include/scene_manager.h +++ b/include/scene_manager.h @@ -12,26 +12,50 @@ namespace engine { class Application; class SceneManager { - public: - SceneManager(Application* app); - ~SceneManager(); - SceneManager(const SceneManager&) = delete; - SceneManager& operator=(const SceneManager&) = delete; + public: + SceneManager(Application* app); + ~SceneManager(); + SceneManager(const SceneManager&) = delete; + SceneManager& operator=(const SceneManager&) = delete; - // creates an empty scene and sets it as active - Scene* CreateEmptyScene(); + // creates an empty scene and sets it as active + Scene* CreateEmptyScene(); -// returns active scene, nullptr if no scene active - Scene* UpdateActiveScene(float ts); - Scene* GetActiveScene() { return scenes_.at(active_scene_index_).get(); } + // nullptr deactivates the active scene + void SetActiveScene(Scene* scene) + { + if (scene == nullptr) { + active_scene_index_ = -1; + } + else { + // linear search for scene + int index = 0; + for (const auto& unique_scene : scenes_) { + if (unique_scene.get() == scene) { + break; + } + ++index; + } + if (index >= scenes_.size()) { + throw std::runtime_error("Failed to find active scene!"); + } + else { + active_scene_index_ = index; + } + } + } - private: - Application* const app_; + // returns active scene, nullptr if no scene active + Scene* UpdateActiveScene(float ts); + Scene* GetActiveScene() { return scenes_.at(active_scene_index_).get(); } - std::vector> scenes_; - int active_scene_index_ = -1; + private: + Application* const app_; + + std::vector> scenes_; + int active_scene_index_ = -1; }; -} // namespace engine +} // namespace engine #endif \ No newline at end of file diff --git a/include/systems/mesh_render_system.h b/include/systems/mesh_render_system.h index 925c812..3728b6d 100644 --- a/include/systems/mesh_render_system.h +++ b/include/systems/mesh_render_system.h @@ -1,5 +1,4 @@ -#ifndef ENGINE_INCLUDE_SYSTEMS_MESH_RENDER_SYSTEM_H_ -#define ENGINE_INCLUDE_SYSTEMS_MESH_RENDER_SYSTEM_H_ +#pragma once #include @@ -13,7 +12,7 @@ struct RenderListEntry { const gfx::Pipeline* pipeline; const gfx::Buffer* vertex_buffer; const gfx::Buffer* index_buffer; - const gfx::DescriptorSet* base_colour_texture; + const gfx::DescriptorSet* material_set; glm::mat4 model_matrix; uint32_t index_count; }; @@ -43,6 +42,4 @@ class MeshRenderSystem : public System { }; -} // namespace engine - -#endif \ No newline at end of file +} // namespace engine \ No newline at end of file diff --git a/include/util/files.h b/include/util/files.h index 18d714a..d6a49f7 100644 --- a/include/util/files.h +++ b/include/util/files.h @@ -14,7 +14,7 @@ std::unique_ptr> ReadBinaryFile(const std::string& path); // Read an image file into a vector byte buffer. PNG and JPG support at a // minimum. Output format is R8G8B8A8_UINT std::unique_ptr> ReadImageFile(const std::string& path, - int* width, int* height); + int& width, int& height); } // namespace util } // namespace engine diff --git a/res/engine/shaders/fancy.frag b/res/engine/shaders/fancy.frag new file mode 100644 index 0000000..aced458 --- /dev/null +++ b/res/engine/shaders/fancy.frag @@ -0,0 +1,42 @@ +#version 450 + +layout(set = 2, binding = 0) uniform sampler2D materialSetAlbedoSampler; +layout(set = 2, binding = 1) uniform sampler2D materialSetNormalSampler; +layout(set = 2, binding = 2) uniform sampler2D materialSetOcclusionSampler; +layout(set = 2, binding = 3) uniform sampler2D materialSetMetallicRoughnessSampler; + +layout(location = 0) in vec3 fragPos; +layout(location = 1) in vec3 fragNorm; +layout(location = 2) in vec2 fragUV; +layout(location = 3) in vec3 fragViewPos; +layout(location = 4) in vec3 fragLightPos; +layout(location = 5) in mat3 fragTBN; + +layout(location = 0) out vec4 outColor; + +void main() { + + // constants + vec3 lightColor = vec3(1.0, 1.0, 1.0); + vec3 ambientColor = vec3(1.0, 1.0, 1.0); + float ambientStrength = 0.05; + vec3 emission = vec3(0.0, 0.0, 0.0); + + vec3 baseColor = vec3(texture(materialSetAlbedoSampler, fragUV)); + + vec3 norm = vec3(texture(materialSetNormalSampler, fragUV)); + norm = normalize(norm * 2.0 - 1.0); + + vec3 lightDir = fragTBN * normalize(fragLightPos - fragPos); + vec3 viewDir = fragTBN * normalize(fragViewPos - fragPos); + + vec3 diffuse = max(dot(norm, lightDir), 0.0) * lightColor; + vec3 ambient = ambientColor * ambientStrength; + vec3 halfwayDir = normalize(lightDir + viewDir); + float spec = pow(max(dot(norm, halfwayDir), 0.0), 32.0); + vec3 specular = spec * lightColor; + + vec3 lighting = min(diffuse + ambient + specular, 1.0); + outColor = min( ( vec4(baseColor, 1.0) ) * vec4(lighting + emission, 1.0), vec4(1.0)); +} + diff --git a/res/engine/shaders/fancy.vert b/res/engine/shaders/fancy.vert new file mode 100644 index 0000000..11e1093 --- /dev/null +++ b/res/engine/shaders/fancy.vert @@ -0,0 +1,43 @@ +#version 450 + +layout(set = 0, binding = 0) uniform GlobalSetUniformBuffer { + mat4 proj; +} globalSetUniformBuffer; + +layout(set = 1, binding = 0) uniform FrameSetUniformBuffer { + mat4 view; +} frameSetUniformBuffer; + +layout( push_constant ) uniform Constants { + mat4 model; +} constants; + +layout(location = 0) in vec3 inPosition; +layout(location = 1) in vec3 inNorm; +layout(location = 2) in vec4 inTangent; +layout(location = 3) in vec2 inUV; + +layout(location = 0) out vec3 fragPos; +layout(location = 1) out vec3 fragNorm; +layout(location = 2) out vec2 fragUV; +layout(location = 3) out vec3 fragViewPos; +layout(location = 4) out vec3 fragLightPos; +layout(location = 5) out mat3 fragTBN; + +void main() { + gl_Position = globalSetUniformBuffer.proj * frameSetUniformBuffer.view * constants.model * vec4(inPosition, 1.0); + + mat3 normalMatrix = mat3(transpose(inverse(constants.model))); + + fragPos = vec3(constants.model * vec4(inPosition, 1.0)); + fragNorm = normalize(normalMatrix * inNorm); + fragUV = inUV; + fragViewPos = vec3(inverse(frameSetUniformBuffer.view) * vec4(0.0, 0.0, 0.0, 1.0)); + fragLightPos = vec3(2000.0, -2000.0, 2000.0); + + vec3 T = normalize(normalMatrix * inTangent.xyz); + vec3 B = cross(fragNorm, T) * inTangent.w; // from unity docs, w flips the binormal + fragTBN = transpose(mat3(T, B, fragNorm)); + + gl_Position.y *= -1.0; +} diff --git a/res/engine/shaders/quad.vert b/res/engine/shaders/quad.vert index d20efd2..36e5f72 100644 --- a/res/engine/shaders/quad.vert +++ b/res/engine/shaders/quad.vert @@ -14,7 +14,8 @@ layout( push_constant ) uniform Constants { layout(location = 0) in vec3 inPosition; layout(location = 1) in vec3 inNorm; -layout(location = 2) in vec2 inUV; +layout(location = 2) in vec4 inTangent; +layout(location = 3) in vec2 inUV; layout(location = 0) out vec2 fragUV; diff --git a/res/engine/shaders/showNormals.vert b/res/engine/shaders/showNormals.vert index 40542ae..b468b5f 100644 --- a/res/engine/shaders/showNormals.vert +++ b/res/engine/shaders/showNormals.vert @@ -12,7 +12,8 @@ layout(set = 0, binding = 0) uniform SetZeroBuffer { layout(location = 0) in vec3 inPosition; layout(location = 1) in vec3 inNorm; -layout(location = 2) in vec2 inUV; +layout(location = 2) in vec4 inTangent; +layout(location = 3) in vec2 inUV; layout(location = 0) out vec3 fragNorm; diff --git a/res/engine/shaders/showUVs.vert b/res/engine/shaders/showUVs.vert index 429bda6..f166abb 100644 --- a/res/engine/shaders/showUVs.vert +++ b/res/engine/shaders/showUVs.vert @@ -12,7 +12,8 @@ layout(set = 0, binding = 0) uniform SetZeroBuffer { layout(location = 0) in vec3 inPosition; layout(location = 1) in vec3 inNorm; -layout(location = 2) in vec2 inUV; +layout(location = 2) in vec4 inTangent; +layout(location = 3) in vec2 inUV; layout(location = 0) out vec2 fragUV; diff --git a/res/engine/shaders/skybox.frag b/res/engine/shaders/skybox.frag index 8e5a402..f5f448c 100644 --- a/res/engine/shaders/skybox.frag +++ b/res/engine/shaders/skybox.frag @@ -1,11 +1,14 @@ #version 450 -layout(set = 2, binding = 0) uniform sampler2D materialSetSampler; +layout(set = 2, binding = 0) uniform sampler2D materialSetAlbedoSampler; +layout(set = 2, binding = 1) uniform sampler2D materialSetNormalSampler; +layout(set = 2, binding = 2) uniform sampler2D materialSetOcclusionSampler; +layout(set = 2, binding = 3) uniform sampler2D materialSetMetallicRoughnessSampler; layout(location = 0) in vec2 fragUV; layout(location = 0) out vec4 outColor; void main() { - outColor = texture(materialSetSampler, fragUV); + outColor = texture(materialSetAlbedoSampler, fragUV); } \ No newline at end of file diff --git a/res/engine/shaders/skybox.vert b/res/engine/shaders/skybox.vert index 7b7eb51..fd6b003 100644 --- a/res/engine/shaders/skybox.vert +++ b/res/engine/shaders/skybox.vert @@ -13,7 +13,9 @@ layout( push_constant ) uniform Constants { } constants; layout(location = 0) in vec3 inPosition; -layout(location = 2) in vec2 inUV; +layout(location = 1) in vec3 inNorm; +layout(location = 2) in vec4 inTangent; +layout(location = 3) in vec2 inUV; layout(location = 0) out vec2 fragUV; diff --git a/res/engine/shaders/standard.frag b/res/engine/shaders/standard.frag index c750561..bc8acd4 100644 --- a/res/engine/shaders/standard.frag +++ b/res/engine/shaders/standard.frag @@ -1,6 +1,9 @@ #version 450 -layout(set = 2, binding = 0) uniform sampler2D materialSetSampler; +layout(set = 2, binding = 0) uniform sampler2D materialSetAlbedoSampler; +layout(set = 2, binding = 1) uniform sampler2D materialSetNormalSampler; +layout(set = 2, binding = 2) uniform sampler2D materialSetOcclusionSampler; +layout(set = 2, binding = 3) uniform sampler2D materialSetMetallicRoughnessSampler; layout(location = 0) in vec3 fragPos; layout(location = 1) in vec3 fragNorm; @@ -15,7 +18,7 @@ void main() { vec3 lightColor = vec3(1.0, 1.0, 1.0); vec3 ambientColor = vec3(1.0, 1.0, 1.0); float ambientStrength = 0.05; - vec3 baseColor = vec3(texture(materialSetSampler, fragUV)); + vec3 baseColor = vec3(texture(materialSetAlbedoSampler, fragUV)); vec3 emission = vec3(0.0, 0.0, 0.0); // code diff --git a/res/engine/shaders/standard.vert b/res/engine/shaders/standard.vert index 0b00905..3d57327 100644 --- a/res/engine/shaders/standard.vert +++ b/res/engine/shaders/standard.vert @@ -14,7 +14,8 @@ layout( push_constant ) uniform Constants { layout(location = 0) in vec3 inPosition; layout(location = 1) in vec3 inNorm; -layout(location = 2) in vec2 inUV; +layout(location = 2) in vec4 inTangent; +layout(location = 3) in vec2 inUV; layout(location = 0) out vec3 fragPos; layout(location = 1) out vec3 fragNorm; diff --git a/src/application.cpp b/src/application.cpp index 51d085a..8c3dbae 100644 --- a/src/application.cpp +++ b/src/application.cpp @@ -83,11 +83,11 @@ Application::Application(const char* appName, const char* appVersion, gfx::Graph resources_path_ = getResourcesPath(); // register resource managers - RegisterResourceManager(); - RegisterResourceManager(); - RegisterResourceManager(); - RegisterResourceManager(); - RegisterResourceManager(); + RegisterResourceManager(); + RegisterResourceManager(); + RegisterResourceManager(); + RegisterResourceManager(); + RegisterResourceManager(); im_gui_things.context = ImGui::CreateContext(); // ImGuiIO& io = ImGui::GetIO() @@ -97,58 +97,78 @@ Application::Application(const char* appName, const char* appVersion, gfx::Graph /* default fonts */ { - auto monoFont = std::make_unique(GetResourcePath("engine/fonts/mono.ttf")); - GetResourceManager()->AddPersistent("builtin.mono", std::move(monoFont)); + auto monoFont = std::make_unique(GetResourcePath("engine/fonts/mono.ttf")); + GetResourceManager()->AddPersistent("builtin.mono", std::move(monoFont)); } /* default shaders */ { - resources::Shader::VertexParams vertParams{}; + Shader::VertexParams vertParams{}; vertParams.has_normal = true; + vertParams.has_tangent = true; vertParams.has_uv0 = true; - resources::Shader::ShaderSettings shaderSettings{}; + Shader::ShaderSettings shaderSettings{}; shaderSettings.vertexParams = vertParams; shaderSettings.alpha_blending = false; shaderSettings.cull_backface = true; shaderSettings.write_z = true; shaderSettings.render_order = 0; - auto texturedShader = std::make_unique(renderer(), GetResourcePath("engine/shaders/standard.vert").c_str(), + auto texturedShader = std::make_unique(renderer(), GetResourcePath("engine/shaders/standard.vert").c_str(), GetResourcePath("engine/shaders/standard.frag").c_str(), shaderSettings); - GetResourceManager()->AddPersistent("builtin.standard", std::move(texturedShader)); + GetResourceManager()->AddPersistent("builtin.standard", std::move(texturedShader)); } { - resources::Shader::VertexParams vertParams{}; + Shader::VertexParams vertParams{}; vertParams.has_normal = true; + vertParams.has_tangent = true; vertParams.has_uv0 = true; - resources::Shader::ShaderSettings shaderSettings{}; + Shader::ShaderSettings shaderSettings{}; shaderSettings.vertexParams = vertParams; shaderSettings.alpha_blending = false; shaderSettings.cull_backface = true; shaderSettings.write_z = true; shaderSettings.render_order = 0; - auto skyboxShader = std::make_unique(renderer(), GetResourcePath("engine/shaders/skybox.vert").c_str(), - GetResourcePath("engine/shaders/skybox.frag").c_str(), shaderSettings); - GetResourceManager()->AddPersistent("builtin.skybox", std::move(skyboxShader)); + auto fancyShader = std::make_unique(renderer(), GetResourcePath("engine/shaders/fancy.vert").c_str(), + GetResourcePath("engine/shaders/fancy.frag").c_str(), shaderSettings); + GetResourceManager()->AddPersistent("builtin.fancy", std::move(fancyShader)); } - if (0) { - resources::Shader::VertexParams vertParams{}; + { + Shader::VertexParams vertParams{}; vertParams.has_normal = true; + vertParams.has_tangent = true; vertParams.has_uv0 = true; - resources::Shader::ShaderSettings shaderSettings{}; + Shader::ShaderSettings shaderSettings{}; + shaderSettings.vertexParams = vertParams; + shaderSettings.alpha_blending = false; + shaderSettings.cull_backface = true; + shaderSettings.write_z = true; + shaderSettings.render_order = 0; + auto skyboxShader = std::make_unique(renderer(), GetResourcePath("engine/shaders/skybox.vert").c_str(), + GetResourcePath("engine/shaders/skybox.frag").c_str(), shaderSettings); + GetResourceManager()->AddPersistent("builtin.skybox", std::move(skyboxShader)); + } +#if 0 + { + Shader::VertexParams vertParams{}; + vertParams.has_normal = true; + vertParams.has_tangent = true; + vertParams.has_uv0 = true; + Shader::ShaderSettings shaderSettings{}; shaderSettings.vertexParams = vertParams; shaderSettings.alpha_blending = true; shaderSettings.cull_backface = true; shaderSettings.write_z = false; shaderSettings.render_order = 1; - auto quadShader = std::make_unique(renderer(), GetResourcePath("engine/shaders/quad.vert").c_str(), + auto quadShader = std::make_unique(renderer(), GetResourcePath("engine/shaders/quad.vert").c_str(), GetResourcePath("engine/shaders/quad.frag").c_str(), shaderSettings); - GetResourceManager()->AddPersistent("builtin.quad", std::move(quadShader)); + GetResourceManager()->AddPersistent("builtin.quad", std::move(quadShader)); } +#endif /* default textures */ { - auto whiteTexture = std::make_unique(renderer(), GetResourcePath("engine/textures/white.png"), resources::Texture::Filtering::kOff); - GetResourceManager()->AddPersistent("builtin.white", std::move(whiteTexture)); + auto whiteTexture = LoadTextureFromFile(GetResourcePath("engine/textures/white.png"), Texture::Filtering::kOff, renderer()); + GetResourceManager()->AddPersistent("builtin.white", std::move(whiteTexture)); } } @@ -228,6 +248,7 @@ void Application::GameLoop() return find_depth(parent, current_depth + 1); } }; + if (scene) { for (Entity i = 1; i < scene->next_entity_id_; ++i) { auto t = scene->GetComponent(i); @@ -235,8 +256,12 @@ void Application::GameLoop() int depth = find_depth(i, 0); for (int j = 0; j < depth; ++j) tabs += std::string{" "}; ImGui::Text("%s%s", tabs.c_str(), t->tag.c_str()); + ImGui::Text("%.1f %.1f %.1f", t->position.x, t->position.y, t->position.z); } } + else { + ImGui::Text("No scene active!"); + } } ImGui::End(); } @@ -253,7 +278,7 @@ void Application::GameLoop() dynamic_list = mesh_render_system->GetDynamicRenderList(); } renderer_->PreRender(window()->GetWindowResized(), camera_transform); - renderer_->Render(*static_list, *dynamic_list); + renderer_->Render(static_list, dynamic_list); /* poll events */ window_->GetInputAndEvents(); diff --git a/src/renderer.cpp b/src/renderer.cpp index 91f4c44..9df9a3d 100644 --- a/src/renderer.cpp +++ b/src/renderer.cpp @@ -6,157 +6,146 @@ #include "imgui/imgui.h" -[[maybe_unused]] static glm::mat4 GenPerspectiveMatrix(float vertical_fov_radians, - float aspect_ratio, float znear, - float zfar) { - float g = 1.0f / tanf(vertical_fov_radians * 0.5f); - float k1 = zfar / (zfar - znear); - float k2 = -(zfar * znear) / (znear - zfar); - glm::mat4 m{1.0f}; +[[maybe_unused]] static glm::mat4 GenPerspectiveMatrix(float vertical_fov_radians, float aspect_ratio, float znear, float zfar) +{ + float g = 1.0f / tanf(vertical_fov_radians * 0.5f); + float k1 = zfar / (zfar - znear); + float k2 = -(zfar * znear) / (znear - zfar); + glm::mat4 m{1.0f}; - m[0][0] = g / aspect_ratio; - m[1][1] = g; - m[2][2] = k1; - m[2][3] = -1.0f; - m[3][2] = k2; - m[3][3] = 0.0f; + m[0][0] = g / aspect_ratio; + m[1][1] = g; + m[2][2] = k1; + m[2][3] = -1.0f; + m[3][2] = k2; + m[3][3] = 0.0f; - return m; + return m; } namespace engine { -Renderer::Renderer(const char* app_name, const char* app_version, - SDL_Window* window, gfx::GraphicsSettings settings) { - device_ = - std::make_unique(app_name, app_version, window, settings); +Renderer::Renderer(const char* app_name, const char* app_version, SDL_Window* window, gfx::GraphicsSettings settings) +{ + device_ = std::make_unique(app_name, app_version, window, settings); - // sort out descriptor set layouts: - std::vector globalSetBindings; - { - auto& binding0 = globalSetBindings.emplace_back(); - binding0.descriptor_type = gfx::DescriptorType::kUniformBuffer; - binding0.stage_flags = gfx::ShaderStageFlags::kVertex; - } - global_uniform.layout = device_->CreateDescriptorSetLayout(globalSetBindings); - global_uniform.set = device_->AllocateDescriptorSet(global_uniform.layout); - global_uniform.uniform_buffer_data.data = glm::mat4{1.0f}; - global_uniform.uniform_buffer = - device_->CreateUniformBuffer(sizeof(global_uniform.uniform_buffer_data), - &global_uniform.uniform_buffer_data); - device_->UpdateDescriptorUniformBuffer( - global_uniform.set, 0, global_uniform.uniform_buffer, 0, - sizeof(global_uniform.uniform_buffer_data)); + // sort out descriptor set layouts: + std::vector globalSetBindings; + { + auto& binding0 = globalSetBindings.emplace_back(); + binding0.descriptor_type = gfx::DescriptorType::kUniformBuffer; + binding0.stage_flags = gfx::ShaderStageFlags::kVertex; + } + global_uniform.layout = device_->CreateDescriptorSetLayout(globalSetBindings); + global_uniform.set = device_->AllocateDescriptorSet(global_uniform.layout); + global_uniform.uniform_buffer_data.data = glm::mat4{1.0f}; + global_uniform.uniform_buffer = device_->CreateUniformBuffer(sizeof(global_uniform.uniform_buffer_data), &global_uniform.uniform_buffer_data); + device_->UpdateDescriptorUniformBuffer(global_uniform.set, 0, global_uniform.uniform_buffer, 0, sizeof(global_uniform.uniform_buffer_data)); - std::vector frameSetBindings; - { - auto& binding0 = frameSetBindings.emplace_back(); - binding0.descriptor_type = gfx::DescriptorType::kUniformBuffer; - binding0.stage_flags = gfx::ShaderStageFlags::kVertex; - } - frame_uniform.layout = device_->CreateDescriptorSetLayout(frameSetBindings); - frame_uniform.set = device_->AllocateDescriptorSet(frame_uniform.layout); - frame_uniform.uniform_buffer_data.data = glm::mat4{1.0f}; - frame_uniform.uniform_buffer = - device_->CreateUniformBuffer(sizeof(frame_uniform.uniform_buffer_data), - &frame_uniform.uniform_buffer_data); - device_->UpdateDescriptorUniformBuffer( - frame_uniform.set, 0, frame_uniform.uniform_buffer, 0, - sizeof(frame_uniform.uniform_buffer_data)); + std::vector frameSetBindings; + { + auto& binding0 = frameSetBindings.emplace_back(); + binding0.descriptor_type = gfx::DescriptorType::kUniformBuffer; + binding0.stage_flags = gfx::ShaderStageFlags::kVertex; + } + frame_uniform.layout = device_->CreateDescriptorSetLayout(frameSetBindings); + frame_uniform.set = device_->AllocateDescriptorSet(frame_uniform.layout); + frame_uniform.uniform_buffer_data.data = glm::mat4{1.0f}; + frame_uniform.uniform_buffer = device_->CreateUniformBuffer(sizeof(frame_uniform.uniform_buffer_data), &frame_uniform.uniform_buffer_data); + device_->UpdateDescriptorUniformBuffer(frame_uniform.set, 0, frame_uniform.uniform_buffer, 0, sizeof(frame_uniform.uniform_buffer_data)); - std::vector materialSetBindings; - { - auto& binding0 = materialSetBindings.emplace_back(); - binding0.descriptor_type = gfx::DescriptorType::kCombinedImageSampler; - binding0.stage_flags = gfx::ShaderStageFlags::kFragment; - } - material_set_layout = device_->CreateDescriptorSetLayout(materialSetBindings); + std::vector materialSetBindings; + gfx::DescriptorSetLayoutBinding materialSetBinding{}; + materialSetBinding.descriptor_type = gfx::DescriptorType::kCombinedImageSampler; + materialSetBinding.stage_flags = gfx::ShaderStageFlags::kFragment; + materialSetBindings.push_back(materialSetBinding); // albedo + materialSetBindings.push_back(materialSetBinding); // normal + materialSetBindings.push_back(materialSetBinding); // occlusion + materialSetBindings.push_back(materialSetBinding); // metallic-roughness + material_set_layout = device_->CreateDescriptorSetLayout(materialSetBindings); - device_->SetupImguiBackend(); + device_->SetupImguiBackend(); }; -Renderer::~Renderer() { - for (const auto& [info, sampler] : samplers) { - device_->DestroySampler(sampler); - } - device_->DestroyDescriptorSetLayout(material_set_layout); - - device_->DestroyUniformBuffer(frame_uniform.uniform_buffer); - device_->DestroyDescriptorSetLayout(frame_uniform.layout); - - device_->DestroyUniformBuffer(global_uniform.uniform_buffer); - device_->DestroyDescriptorSetLayout(global_uniform.layout); -} - -void Renderer::PreRender(bool window_is_resized, glm::mat4 camera_transform) { - if (window_is_resized) { - uint32_t w, h; - device_->GetViewportSize(&w, &h); - viewport_aspect_ratio_ = (float)w / (float)h; - const glm::mat4 proj_matrix = glm::perspectiveRH_ZO( - camera_settings_.vertical_fov_radians, viewport_aspect_ratio_, - camera_settings_.clip_near, camera_settings_.clip_far); - /* update SET 0 (rarely changing uniforms)*/ - global_uniform.uniform_buffer_data.data = proj_matrix; - device_->WriteUniformBuffer(global_uniform.uniform_buffer, 0, - sizeof(global_uniform.uniform_buffer_data), - &global_uniform.uniform_buffer_data); - } - - // set camera view matrix uniform - /* update SET 1 (per frame uniforms) */ - const glm::mat4 view_matrix = glm::inverse(camera_transform); - frame_uniform.uniform_buffer_data.data = view_matrix; - device_->WriteUniformBuffer(frame_uniform.uniform_buffer, 0, - sizeof(frame_uniform.uniform_buffer_data), - &frame_uniform.uniform_buffer_data); -} - -void Renderer::Render(const RenderList& static_list, - const RenderList& dynamic_list) { - last_bound_pipeline_ = nullptr; - - gfx::DrawBuffer* draw_buffer = device_->BeginRender(); - - if (!static_list.empty()) { - DrawRenderList(draw_buffer, static_list); - } - if (!dynamic_list.empty()) { - DrawRenderList(draw_buffer, dynamic_list); - } - - device_->CmdRenderImguiDrawData(draw_buffer, ImGui::GetDrawData()); - - device_->FinishRender(draw_buffer); -} - -void Renderer::DrawRenderList(gfx::DrawBuffer* draw_buffer, - const RenderList& render_list) { - // if a pipeline hasn't been bound yet at all - if (last_bound_pipeline_ == nullptr) { - const gfx::Pipeline* first_pipeline = render_list.begin()->pipeline; - // these bindings persist between all pipelines - device_->CmdBindDescriptorSet(draw_buffer, first_pipeline, - global_uniform.set, 0); - device_->CmdBindDescriptorSet(draw_buffer, first_pipeline, - frame_uniform.set, 1); - device_->CmdBindPipeline(draw_buffer, first_pipeline); - last_bound_pipeline_ = first_pipeline; - } - - for (const auto& entry : render_list) { - if (entry.pipeline != last_bound_pipeline_) { - device_->CmdBindPipeline(draw_buffer, entry.pipeline); - last_bound_pipeline_ = entry.pipeline; +Renderer::~Renderer() +{ + for (const auto& [info, sampler] : samplers) { + device_->DestroySampler(sampler); } - device_->CmdBindDescriptorSet(draw_buffer, entry.pipeline, - entry.base_colour_texture, 2); - device_->CmdPushConstants(draw_buffer, entry.pipeline, 0, - sizeof(entry.model_matrix), &entry.model_matrix); - device_->CmdBindVertexBuffer(draw_buffer, 0, entry.vertex_buffer); - device_->CmdBindIndexBuffer(draw_buffer, entry.index_buffer); - device_->CmdDrawIndexed(draw_buffer, entry.index_count, 1, 0, 0, 0); - } + device_->DestroyDescriptorSetLayout(material_set_layout); + + device_->DestroyUniformBuffer(frame_uniform.uniform_buffer); + device_->DestroyDescriptorSetLayout(frame_uniform.layout); + + device_->DestroyUniformBuffer(global_uniform.uniform_buffer); + device_->DestroyDescriptorSetLayout(global_uniform.layout); } -} // namespace engine +void Renderer::PreRender(bool window_is_resized, glm::mat4 camera_transform) +{ + if (window_is_resized) { + uint32_t w, h; + device_->GetViewportSize(&w, &h); + viewport_aspect_ratio_ = (float)w / (float)h; + const glm::mat4 proj_matrix = + glm::perspectiveRH_ZO(camera_settings_.vertical_fov_radians, viewport_aspect_ratio_, camera_settings_.clip_near, camera_settings_.clip_far); + /* update SET 0 (rarely changing uniforms)*/ + global_uniform.uniform_buffer_data.data = proj_matrix; + device_->WriteUniformBuffer(global_uniform.uniform_buffer, 0, sizeof(global_uniform.uniform_buffer_data), &global_uniform.uniform_buffer_data); + } + + // set camera view matrix uniform + /* update SET 1 (per frame uniforms) */ + const glm::mat4 view_matrix = glm::inverse(camera_transform); + frame_uniform.uniform_buffer_data.data = view_matrix; + device_->WriteUniformBuffer(frame_uniform.uniform_buffer, 0, sizeof(frame_uniform.uniform_buffer_data), &frame_uniform.uniform_buffer_data); +} + +void Renderer::Render(const RenderList* static_list, const RenderList* dynamic_list) +{ + last_bound_pipeline_ = nullptr; + + gfx::DrawBuffer* draw_buffer = device_->BeginRender(); + + if (static_list) { + if (!static_list->empty()) { + DrawRenderList(draw_buffer, *static_list); + } + } + if (dynamic_list) { + if (!dynamic_list->empty()) { + DrawRenderList(draw_buffer, *dynamic_list); + } + } + + device_->CmdRenderImguiDrawData(draw_buffer, ImGui::GetDrawData()); + + device_->FinishRender(draw_buffer); +} + +void Renderer::DrawRenderList(gfx::DrawBuffer* draw_buffer, const RenderList& render_list) +{ + // if a pipeline hasn't been bound yet at all + if (last_bound_pipeline_ == nullptr) { + const gfx::Pipeline* first_pipeline = render_list.begin()->pipeline; + // these bindings persist between all pipelines + device_->CmdBindDescriptorSet(draw_buffer, first_pipeline, global_uniform.set, 0); + device_->CmdBindDescriptorSet(draw_buffer, first_pipeline, frame_uniform.set, 1); + device_->CmdBindPipeline(draw_buffer, first_pipeline); + last_bound_pipeline_ = first_pipeline; + } + + for (const auto& entry : render_list) { + if (entry.pipeline != last_bound_pipeline_) { + device_->CmdBindPipeline(draw_buffer, entry.pipeline); + last_bound_pipeline_ = entry.pipeline; + } + device_->CmdBindDescriptorSet(draw_buffer, entry.pipeline, entry.material_set, 2); + device_->CmdPushConstants(draw_buffer, entry.pipeline, 0, sizeof(entry.model_matrix), &entry.model_matrix); + device_->CmdBindVertexBuffer(draw_buffer, 0, entry.vertex_buffer); + device_->CmdBindIndexBuffer(draw_buffer, entry.index_buffer); + device_->CmdDrawIndexed(draw_buffer, entry.index_count, 1, 0, 0, 0); + } +} + +} // namespace engine diff --git a/src/resources/font.cpp b/src/resources/font.cpp index 2a5a11c..6d55f00 100644 --- a/src/resources/font.cpp +++ b/src/resources/font.cpp @@ -8,7 +8,7 @@ #include "log.h" #include "util/files.h" -namespace engine::resources { +namespace engine { Font::Font(const std::string& path) { font_buffer_ = util::ReadBinaryFile(path); @@ -131,4 +131,4 @@ int Font::GetGlyphIndex(int unicode_codepoint) { } } -} // namespace engine::resources +} // namespace engine diff --git a/src/resources/material.cpp b/src/resources/material.cpp index a747ff3..a77dc4b 100644 --- a/src/resources/material.cpp +++ b/src/resources/material.cpp @@ -2,18 +2,37 @@ #include "resources/shader.h" -namespace engine::resources { - - Material::Material(std::shared_ptr shader) - : shader_(shader) - { - - } - - Material::Material(const Material& original) - : texture_(original.texture_), shader_(original.shader_) - { - - } +namespace engine { +Material::Material(Renderer* renderer, std::shared_ptr shader) : shader_(shader), renderer_(renderer) +{ + material_set_ = renderer->GetDevice()->AllocateDescriptorSet(renderer->GetMaterialSetLayout()); } + +Material::~Material() { renderer_->GetDevice()->FreeDescriptorSet(material_set_); } + +void Material::SetAlbedoTexture(std::shared_ptr texture) +{ + renderer_->GetDevice()->UpdateDescriptorCombinedImageSampler(material_set_, 0, texture->GetImage(), texture->GetSampler()); + texture_albedo_ = texture; +} + +void Material::SetNormalTexture(std::shared_ptr texture) +{ + renderer_->GetDevice()->UpdateDescriptorCombinedImageSampler(material_set_, 1, texture->GetImage(), texture->GetSampler()); + texture_normal_ = texture; +} + +void Material::SetOcclusionTexture(std::shared_ptr texture) +{ + renderer_->GetDevice()->UpdateDescriptorCombinedImageSampler(material_set_, 2, texture->GetImage(), texture->GetSampler()); + texture_occlusion_ = texture; +} + +void Material::SetMetallicRoughnessTexture(std::shared_ptr texture) +{ + renderer_->GetDevice()->UpdateDescriptorCombinedImageSampler(material_set_, 3, texture->GetImage(), texture->GetSampler()); + texture_metallic_roughness_ = texture; +} + +} // namespace engine diff --git a/src/resources/mesh.cpp b/src/resources/mesh.cpp index 741b9fb..fc31573 100644 --- a/src/resources/mesh.cpp +++ b/src/resources/mesh.cpp @@ -3,7 +3,7 @@ #include "log.h" #include "gfx_device.h" -namespace engine::resources { +namespace engine { Mesh::Mesh(GFXDevice* gfx, const std::vector& vertices) : gfx_(gfx) { std::vector indices(vertices.size()); @@ -36,4 +36,4 @@ void Mesh::InitMesh(const std::vector& vertices, indices.size()); } -} // namespace engine::resources +} // namespace engine diff --git a/src/resources/shader.cpp b/src/resources/shader.cpp index 63ae8b9..2449f2b 100644 --- a/src/resources/shader.cpp +++ b/src/resources/shader.cpp @@ -6,7 +6,7 @@ #include -namespace engine::resources { +namespace engine { Shader::Shader(Renderer* renderer, const char* vertPath, const char* fragPath, const ShaderSettings& settings) @@ -67,4 +67,4 @@ Shader::~Shader() { const gfx::Pipeline* Shader::GetPipeline() { return pipeline_; } -} // namespace engine::resources +} // namespace engine diff --git a/src/resources/texture.cpp b/src/resources/texture.cpp index c394adf..52c8f8b 100644 --- a/src/resources/texture.cpp +++ b/src/resources/texture.cpp @@ -6,102 +6,57 @@ #include -namespace engine::resources { +namespace engine { -Texture::Texture(Renderer* renderer, const std::string& path, - Filtering filtering) - : gfx_(renderer->GetDevice()) { - int width, height; - std::unique_ptr> texbuf = - util::ReadImageFile(path, &width, &height); +Texture::Texture(Renderer* renderer, const uint8_t* bitmap, int width, int height, Filtering filtering) : gfx_(renderer->GetDevice()) +{ + gfx::SamplerInfo samplerInfo{}; - gfx::SamplerInfo samplerInfo{}; + samplerInfo.magnify = gfx::Filter::kLinear; - samplerInfo.magnify = gfx::Filter::kLinear; + switch (filtering) { + case Filtering::kOff: + samplerInfo.minify = gfx::Filter::kNearest; + samplerInfo.mipmap = gfx::Filter::kNearest; + samplerInfo.anisotropic_filtering = false; + break; + case Filtering::kBilinear: + samplerInfo.minify = gfx::Filter::kLinear; + samplerInfo.mipmap = gfx::Filter::kNearest; + samplerInfo.anisotropic_filtering = false; + break; + case Filtering::kTrilinear: + samplerInfo.minify = gfx::Filter::kLinear; + samplerInfo.mipmap = gfx::Filter::kLinear; + samplerInfo.anisotropic_filtering = false; + break; + case Filtering::kAnisotropic: + samplerInfo.minify = gfx::Filter::kLinear; + samplerInfo.mipmap = gfx::Filter::kLinear; + samplerInfo.anisotropic_filtering = true; + } - switch (filtering) { - case Filtering::kOff: - samplerInfo.minify = gfx::Filter::kNearest; - samplerInfo.mipmap = gfx::Filter::kNearest; - samplerInfo.anisotropic_filtering = false; - break; - case Filtering::kBilinear: - samplerInfo.minify = gfx::Filter::kLinear; - samplerInfo.mipmap = gfx::Filter::kNearest; - samplerInfo.anisotropic_filtering = false; - break; - case Filtering::kTrilinear: - samplerInfo.minify = gfx::Filter::kLinear; - samplerInfo.mipmap = gfx::Filter::kLinear; - samplerInfo.anisotropic_filtering = false; - break; - case Filtering::kAnisotropic: - samplerInfo.minify = gfx::Filter::kLinear; - samplerInfo.mipmap = gfx::Filter::kLinear; - samplerInfo.anisotropic_filtering = true; - } + if (renderer->samplers.contains(samplerInfo) == false) { + renderer->samplers.insert(std::make_pair(samplerInfo, gfx_->CreateSampler(samplerInfo))); + } - if (renderer->samplers.contains(samplerInfo) == false) { - renderer->samplers.insert( - std::make_pair(samplerInfo, gfx_->CreateSampler(samplerInfo))); - } + image_ = gfx_->CreateImage(width, height, bitmap); + sampler_ = renderer->samplers.at(samplerInfo); - image_ = gfx_->CreateImage(width, height, texbuf->data()); - descriptor_set_ = - gfx_->AllocateDescriptorSet(renderer->GetMaterialSetLayout()); - gfx_->UpdateDescriptorCombinedImageSampler( - descriptor_set_, 0, image_, renderer->samplers.at(samplerInfo)); - - LOG_DEBUG("Created texture: {}, width: {} height: {}", path, width, height); + LOG_DEBUG("Created texture: width: {}, height: {}", width, height); } -Texture::Texture(Renderer* renderer, const uint8_t* bitmap, int width, - int height, Filtering filtering) - : gfx_(renderer->GetDevice()) { - gfx::SamplerInfo samplerInfo{}; - - samplerInfo.magnify = gfx::Filter::kLinear; - - switch (filtering) { - case Filtering::kOff: - samplerInfo.minify = gfx::Filter::kNearest; - samplerInfo.mipmap = gfx::Filter::kNearest; - samplerInfo.anisotropic_filtering = false; - break; - case Filtering::kBilinear: - samplerInfo.minify = gfx::Filter::kLinear; - samplerInfo.mipmap = gfx::Filter::kNearest; - samplerInfo.anisotropic_filtering = false; - break; - case Filtering::kTrilinear: - samplerInfo.minify = gfx::Filter::kLinear; - samplerInfo.mipmap = gfx::Filter::kLinear; - samplerInfo.anisotropic_filtering = false; - break; - case Filtering::kAnisotropic: - samplerInfo.minify = gfx::Filter::kLinear; - samplerInfo.mipmap = gfx::Filter::kLinear; - samplerInfo.anisotropic_filtering = true; - } - - if (renderer->samplers.contains(samplerInfo) == false) { - renderer->samplers.insert( - std::make_pair(samplerInfo, gfx_->CreateSampler(samplerInfo))); - } - - image_ = gfx_->CreateImage(width, height, bitmap); - descriptor_set_ = - gfx_->AllocateDescriptorSet(renderer->GetMaterialSetLayout()); - gfx_->UpdateDescriptorCombinedImageSampler( - descriptor_set_, 0, image_, renderer->samplers.at(samplerInfo)); - - LOG_DEBUG("Created texture: BITMAP, width: {} height: {}", width, height); +Texture::~Texture() +{ + LOG_DEBUG("Destroying texture..."); + gfx_->DestroyImage(image_); } -Texture::~Texture() { - LOG_DEBUG("Destroying texture..."); - gfx_->FreeDescriptorSet(descriptor_set_); - gfx_->DestroyImage(image_); +std::unique_ptr LoadTextureFromFile(const std::string& path, Texture::Filtering filtering, Renderer* renderer) +{ + int width, height; + auto bitmap = util::ReadImageFile(path, width, height); + return std::make_unique(renderer, bitmap->data(), width, height, filtering); } -} // namespace engine::resources +} // namespace engine \ No newline at end of file diff --git a/src/scene_manager.cpp b/src/scene_manager.cpp index 6672f9a..d926995 100644 --- a/src/scene_manager.cpp +++ b/src/scene_manager.cpp @@ -7,31 +7,28 @@ namespace engine { - SceneManager::SceneManager(Application* app) - : app_(app) - { - } +SceneManager::SceneManager(Application* app) : app_(app) {} - SceneManager::~SceneManager() {} - - Scene* SceneManager::CreateEmptyScene() - { - auto scene = std::make_unique(app_); - scenes_.emplace_back(std::move(scene)); - active_scene_index_ = (int)scenes_.size() - 1; - return scenes_.back().get(); - } - - Scene* SceneManager::UpdateActiveScene(float ts) - { - if (active_scene_index_ >= 0) [[likely]] { - assert((size_t)active_scene_index_ < scenes_.size()); - Scene* activeScene = scenes_[active_scene_index_].get(); - activeScene->Update(ts); - return activeScene; - } else { - return nullptr; - } - } +SceneManager::~SceneManager() {} +Scene* SceneManager::CreateEmptyScene() +{ + auto scene = std::make_unique(app_); + scenes_.emplace_back(std::move(scene)); + return scenes_.back().get(); } + +Scene* SceneManager::UpdateActiveScene(float ts) +{ + if (active_scene_index_ >= 0) [[likely]] { + assert((size_t)active_scene_index_ < scenes_.size()); + Scene* activeScene = scenes_[active_scene_index_].get(); + activeScene->Update(ts); + return activeScene; + } + else { + return nullptr; + } +} + +} // namespace engine diff --git a/src/systems/mesh_render_system.cpp b/src/systems/mesh_render_system.cpp index 965ec05..f102c07 100644 --- a/src/systems/mesh_render_system.cpp +++ b/src/systems/mesh_render_system.cpp @@ -8,72 +8,68 @@ namespace engine { -MeshRenderSystem::MeshRenderSystem(Scene* scene) - : System(scene, {typeid(TransformComponent).hash_code(), - typeid(MeshRenderableComponent).hash_code()}) {} +MeshRenderSystem::MeshRenderSystem(Scene* scene) : System(scene, {typeid(TransformComponent).hash_code(), typeid(MeshRenderableComponent).hash_code()}) {} MeshRenderSystem::~MeshRenderSystem() {} -void MeshRenderSystem::RebuildStaticRenderList() { - BuildRenderList(static_render_list_, true); - list_needs_rebuild_ = false; +void MeshRenderSystem::RebuildStaticRenderList() +{ + BuildRenderList(static_render_list_, true); + list_needs_rebuild_ = false; } -void MeshRenderSystem::OnComponentInsert(Entity entity) { - (void)entity; - list_needs_rebuild_ = true; +void MeshRenderSystem::OnComponentInsert(Entity entity) +{ + (void)entity; + list_needs_rebuild_ = true; } -void MeshRenderSystem::OnUpdate(float ts) { - // do stuff - (void)ts; - // update the static render list only if it needs updating - if (list_needs_rebuild_) { - RebuildStaticRenderList(); - } - // update the dynamic render list always - BuildRenderList(dynamic_render_list_, false); -} - -void MeshRenderSystem::BuildRenderList(RenderList& render_list, - bool with_static_entities) { - render_list.clear(); - render_list.reserve(entities_.size()); - - std::unordered_map render_orders; - - for (Entity entity : entities_) { - auto transform = scene_->GetComponent(entity); - - if (transform->is_static != with_static_entities) continue; - - auto renderable = scene_->GetComponent(entity); - - const gfx::Pipeline* pipeline = - renderable->material->GetShader()->GetPipeline(); - - render_list.emplace_back( - RenderListEntry{.pipeline = pipeline, - .vertex_buffer = renderable->mesh->GetVB(), - .index_buffer = renderable->mesh->GetIB(), - .base_colour_texture = - renderable->material->texture_->GetDescriptorSet(), - .model_matrix = transform->world_matrix, - .index_count = renderable->mesh->GetCount()}); - - if (render_orders.contains(pipeline) == false) { - render_orders.emplace( - pipeline, renderable->material->GetShader()->GetRenderOrder()); +void MeshRenderSystem::OnUpdate(float ts) +{ + // do stuff + (void)ts; + // update the static render list only if it needs updating + if (list_needs_rebuild_) { + RebuildStaticRenderList(); } - } + // update the dynamic render list always + BuildRenderList(dynamic_render_list_, false); +} - // sort the meshes by pipeline - auto sort_by_pipeline = [&render_orders](const RenderListEntry& e1, - const RenderListEntry& e2) -> bool { - return (render_orders.at(e1.pipeline) < render_orders.at(e2.pipeline)); - }; +void MeshRenderSystem::BuildRenderList(RenderList& render_list, bool with_static_entities) +{ + render_list.clear(); + render_list.reserve(entities_.size()); - std::sort(render_list.begin(), render_list.end(), sort_by_pipeline); + std::unordered_map render_orders; + + for (Entity entity : entities_) { + auto transform = scene_->GetComponent(entity); + + if (transform->is_static != with_static_entities) continue; + + auto renderable = scene_->GetComponent(entity); + + const gfx::Pipeline* pipeline = renderable->material->GetShader()->GetPipeline(); + + render_list.emplace_back(RenderListEntry{.pipeline = pipeline, + .vertex_buffer = renderable->mesh->GetVB(), + .index_buffer = renderable->mesh->GetIB(), + .material_set = renderable->material->GetDescriptorSet(), + .model_matrix = transform->world_matrix, + .index_count = renderable->mesh->GetCount()}); + + if (render_orders.contains(pipeline) == false) { + render_orders.emplace(pipeline, renderable->material->GetShader()->GetRenderOrder()); + } + } + + // sort the meshes by pipeline + auto sort_by_pipeline = [&render_orders](const RenderListEntry& e1, const RenderListEntry& e2) -> bool { + return (render_orders.at(e1.pipeline) < render_orders.at(e2.pipeline)); + }; + + std::sort(render_list.begin(), render_list.end(), sort_by_pipeline); #if 0 LOG_TRACE("\nPRINTING RENDER LIST ({})\n", with_static_entities ? "STATIC" : "DYNAMIC"); @@ -91,4 +87,4 @@ void MeshRenderSystem::BuildRenderList(RenderList& render_list, #endif } -} // namespace engine +} // namespace engine diff --git a/src/util/files.cpp b/src/util/files.cpp index 3859ccb..5129035 100644 --- a/src/util/files.cpp +++ b/src/util/files.cpp @@ -54,7 +54,7 @@ std::unique_ptr> ReadBinaryFile(const std::string& path) { } std::unique_ptr> ReadImageFile(const std::string& path, - int* width, int* height) { + int& width, int& height) { int x, y, n; unsigned char* data = stbi_load(path.c_str(), &x, &y, &n, STBI_rgb_alpha); // Image is 4 bpp @@ -68,8 +68,8 @@ std::unique_ptr> ReadImageFile(const std::string& path, auto buffer = std::make_unique>(size); memcpy(buffer->data(), data, buffer->size()); - *width = x; - *height = y; + width = x; + height = y; stbi_image_free(data); diff --git a/src/util/model_loader.cpp b/src/util/model_loader.cpp index 691e2f5..ea9ac39 100644 --- a/src/util/model_loader.cpp +++ b/src/util/model_loader.cpp @@ -27,226 +27,198 @@ namespace engine::util { - static void buildGraph( - const std::map>& textures, - const std::vector>& meshes, - const std::vector& meshTextureIndices, - aiNode* parentNode, Scene* scene, Entity parentObj, bool is_static) - { +static void buildGraph(const std::map>& textures, const std::vector>& meshes, + const std::vector& meshTextureIndices, aiNode* parentNode, Scene* scene, Entity parentObj, bool is_static) +{ - // convert to glm column major - glm::mat4 transform{}; - for (int i = 0; i < 4; i++) { - for (int j = 0; j < 4; j++) { - transform[i][j] = parentNode->mTransformation[j][i]; - } - } - - // get position - glm::vec3 position{ transform[3][0], transform[3][1], transform[3][2] }; + // convert to glm column major + glm::mat4 transform{}; + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 4; j++) { + transform[i][j] = parentNode->mTransformation[j][i]; + } + } - // remove position from matrix - transform[3][0] = 0.0f; - transform[3][1] = 0.0f; - transform[3][2] = 0.0f; + // get position + glm::vec3 position{transform[3][0], transform[3][1], transform[3][2]}; - // get scale - glm::vec3 scale{}; - scale.x = sqrt(transform[0][0] * transform[0][0] + transform[0][1] * transform[0][1] + transform[0][2] * transform[0][2]); - scale.y = sqrt(transform[1][0] * transform[1][0] + transform[1][1] * transform[1][1] + transform[1][2] * transform[1][2]); - scale.z = sqrt(transform[2][0] * transform[2][0] + transform[2][1] * transform[2][1] + transform[2][2] * transform[2][2]); + // remove position from matrix + transform[3][0] = 0.0f; + transform[3][1] = 0.0f; + transform[3][2] = 0.0f; - // remove scaling from matrix - for (int row = 0; row < 3; row++) { - transform[0][row] /= scale.x; - transform[1][row] /= scale.y; - transform[2][row] /= scale.z; - } + // get scale + glm::vec3 scale{}; + scale.x = sqrt(transform[0][0] * transform[0][0] + transform[0][1] * transform[0][1] + transform[0][2] * transform[0][2]); + scale.y = sqrt(transform[1][0] * transform[1][0] + transform[1][1] * transform[1][1] + transform[1][2] * transform[1][2]); + scale.z = sqrt(transform[2][0] * transform[2][0] + transform[2][1] * transform[2][1] + transform[2][2] * transform[2][2]); - // get rotation - glm::quat rotation = glm::quat_cast(transform); + // remove scaling from matrix + for (int row = 0; row < 3; row++) { + transform[0][row] /= scale.x; + transform[1][row] /= scale.y; + transform[2][row] /= scale.z; + } - // ASSIMP always makes the root node Y-up - // We want Z-up - if (parentNode->mParent == nullptr) { - // if this is the root node - rotation *= glm::angleAxis(glm::half_pi(), glm::vec3{1.0f, 0.0f, 0.0f}); - } + // get rotation + glm::quat rotation = glm::quat_cast(transform); - // update position, scale, rotation - auto parentTransform = scene->GetComponent(parentObj); - parentTransform->position = position; - parentTransform->scale = scale; - parentTransform->rotation = rotation; + // ASSIMP always makes the root node Y-up + // We want Z-up + if (parentNode->mParent == nullptr) { + // if this is the root node + rotation *= glm::angleAxis(glm::half_pi(), glm::vec3{1.0f, 0.0f, 0.0f}); + } + + // update position, scale, rotation + auto parentTransform = scene->GetComponent(parentObj); + parentTransform->position = position; + parentTransform->scale = scale; + parentTransform->rotation = rotation; parentTransform->is_static = is_static; - for (uint32_t i = 0; i < parentNode->mNumMeshes; i++) { - // create child node for each mesh - auto child = scene->CreateEntity("_mesh" + std::to_string(i), parentObj); - scene->GetComponent(child)->is_static = is_static; - auto childRenderer = scene->AddComponent(child); - childRenderer->mesh = meshes[parentNode->mMeshes[i]]; - childRenderer->material = std::make_shared(scene->app()->GetResource("builtin.standard")); - if (textures.contains(meshTextureIndices[parentNode->mMeshes[i]])) { - childRenderer->material->texture_ = textures.at(meshTextureIndices[parentNode->mMeshes[i]]); - } else { - childRenderer->material->texture_ = scene->app()->GetResource("builtin.white"); - } - } - - for (uint32_t i = 0; i < parentNode->mNumChildren; i++) { - buildGraph( - textures, - meshes, - meshTextureIndices, - parentNode->mChildren[i], - scene, - scene->CreateEntity("child" + std::to_string(i), parentObj), is_static - ); - } - } - - Entity LoadMeshFromFile(Scene* parent, const std::string& path, bool is_static) - { - - Assimp::Importer importer; - - class myStream : public Assimp::LogStream { - public: - void write(const char* message) override { - (void)message; - LOG_TRACE("ASSIMP: {}", message); - } - }; - - const unsigned int severity = Assimp::Logger::Debugging | Assimp::Logger::Info | Assimp::Logger::Err | Assimp::Logger::Warn; - Assimp::DefaultLogger::get()->attachStream(new myStream, severity); - - // remove everything but texcoords, normals, meshes, materials - importer.SetPropertyInteger(AI_CONFIG_PP_RVC_FLAGS, - aiComponent_ANIMATIONS | - aiComponent_BONEWEIGHTS | - aiComponent_CAMERAS | - aiComponent_COLORS | - aiComponent_LIGHTS | - aiComponent_TANGENTS_AND_BITANGENTS | - aiComponent_TEXTURES | - 0 - ); - importer.SetPropertyInteger(AI_CONFIG_PP_SBP_REMOVE, - aiPrimitiveType_POINT | - aiPrimitiveType_LINE | - aiPrimitiveType_POLYGON - ); - - const aiScene* scene = importer.ReadFile(path, - aiProcess_JoinIdenticalVertices | - aiProcess_Triangulate | - aiProcess_SortByPType | - aiProcess_RemoveComponent | - aiProcess_SplitLargeMeshes | // leave at default maximum - aiProcess_ValidateDataStructure | // make sure to log the output - aiProcess_ImproveCacheLocality | - aiProcess_RemoveRedundantMaterials | - aiProcess_FindInvalidData | - aiProcess_GenSmoothNormals | - aiProcess_GenUVCoords | - aiProcess_TransformUVCoords | - aiProcess_FlipUVs | // Collada uses bottom-left origin - 0 - ); - - const char* errString = importer.GetErrorString(); - if (errString[0] != '\0' || scene == nullptr) { - throw std::runtime_error("assimp error: " + std::string(errString)); - } - - if (scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE) { - throw std::runtime_error("assimp error (incomplete): " + std::string(errString)); - } - - assert(scene->HasAnimations() == false); - assert(scene->HasCameras() == false); - assert(scene->HasLights() == false); - assert(scene->hasSkeletons() == false); - - LOG_TRACE("material count: {}, mesh count: {}", scene->mNumMaterials, scene->mNumMeshes); - - std::map> textures{}; - - for (uint32_t i = 0; i < scene->mNumMaterials; i++) { - const aiMaterial* m = scene->mMaterials[i]; - LOG_TRACE("Material {}:", i); - LOG_TRACE(" Name: {}", m->GetName().C_Str()); - for (uint32_t j = 0; j < m->mNumProperties; j++) { - [[maybe_unused]] const aiMaterialProperty* p = m->mProperties[j]; - LOG_TRACE(" prop {}, key: {}", j, p->mKey.C_Str()); - } - - if (aiGetMaterialTextureCount(m, aiTextureType_DIFFUSE) >= 1) { - aiString texPath{}; - aiGetMaterialTexture(m, aiTextureType_DIFFUSE, 0, &texPath); - LOG_TRACE(" Diffuse tex: {}", texPath.C_Str()); - std::filesystem::path absPath = path; - absPath = absPath.parent_path(); - absPath /= texPath.C_Str(); - try { - textures[i] = std::make_shared( - parent->app()->renderer(), - absPath.string(), - resources::Texture::Filtering::kTrilinear); - } catch (const std::runtime_error&) { - textures[i] = parent->app()->GetResource("builtin.white"); - } - } - } - - std::vector> meshes{}; - std::vector meshMaterialIndices{}; - for (uint32_t i = 0; i < scene->mNumMeshes; i++) { - const aiMesh* m = scene->mMeshes[i]; - meshMaterialIndices.push_back(m->mMaterialIndex); - std::vector vertices(m->mNumVertices); - std::vector indices((size_t)m->mNumFaces * 3); - LOG_TRACE("Mesh {}: vertex count {}", i, vertices.size()); - LOG_TRACE("Mesh {}: index count {}", i, indices.size()); - - for (uint32_t j = 0; j < vertices.size(); j++) { - Vertex v{}; - v.pos.x = m->mVertices[j].x; - v.pos.y = m->mVertices[j].y; - v.pos.z = m->mVertices[j].z; - v.norm.x = m->mNormals[j].x; - v.norm.y = m->mNormals[j].y; - v.norm.z = m->mNormals[j].z; - vertices[j] = v; - } - if (m->mNumUVComponents[0] >= 2) { - for (uint32_t j = 0; j < vertices.size(); j++) { - vertices[j].uv.x = m->mTextureCoords[0][j].x; - vertices[j].uv.y = m->mTextureCoords[0][j].y; - - } - } - - for (uint32_t j = 0; j < indices.size() / 3; j++) { - indices[(size_t)j * 3 + 0] = m->mFaces[j].mIndices[0]; - indices[(size_t)j * 3 + 1] = m->mFaces[j].mIndices[1]; - indices[(size_t)j * 3 + 2] = m->mFaces[j].mIndices[2]; - } - meshes.push_back(std::make_shared( - parent->app()->renderer()->GetDevice(), vertices, - indices)); - } - - Entity obj = parent->CreateEntity(scene->GetShortFilename(path.c_str())); - - buildGraph(textures, meshes, meshMaterialIndices, scene->mRootNode, parent, obj, is_static); - - LOG_INFO("Loaded model: {}, meshes: {}, textures: {}", scene->GetShortFilename(path.c_str()), meshes.size(), textures.size()); - - Assimp::DefaultLogger::kill(); - return obj; - } + for (uint32_t i = 0; i < parentNode->mNumMeshes; i++) { + // create child node for each mesh + auto child = scene->CreateEntity("_mesh" + std::to_string(i), parentObj); + scene->GetComponent(child)->is_static = is_static; + auto childRenderer = scene->AddComponent(child); + childRenderer->mesh = meshes[parentNode->mMeshes[i]]; + childRenderer->material = std::make_shared(scene->app()->renderer(), scene->app()->GetResource("builtin.standard")); + if (textures.contains(meshTextureIndices[parentNode->mMeshes[i]])) { + childRenderer->material->SetAlbedoTexture(textures.at(meshTextureIndices[parentNode->mMeshes[i]])); + } + else { + childRenderer->material->SetAlbedoTexture(scene->app()->GetResource("builtin.white")); + } + } + for (uint32_t i = 0; i < parentNode->mNumChildren; i++) { + buildGraph(textures, meshes, meshTextureIndices, parentNode->mChildren[i], scene, scene->CreateEntity("child" + std::to_string(i), parentObj), + is_static); + } } + +Entity LoadMeshFromFile(Scene* parent, const std::string& path, bool is_static) +{ + + Assimp::Importer importer; + + class myStream : public Assimp::LogStream { + public: + void write(const char* message) override + { + (void)message; + LOG_TRACE("ASSIMP: {}", message); + } + }; + + const unsigned int severity = Assimp::Logger::Debugging | Assimp::Logger::Info | Assimp::Logger::Err | Assimp::Logger::Warn; + Assimp::DefaultLogger::get()->attachStream(new myStream, severity); + + // remove everything but texcoords, normals, meshes, materials + importer.SetPropertyInteger(AI_CONFIG_PP_RVC_FLAGS, aiComponent_ANIMATIONS | aiComponent_BONEWEIGHTS | aiComponent_CAMERAS | aiComponent_COLORS | + aiComponent_LIGHTS | aiComponent_TANGENTS_AND_BITANGENTS | aiComponent_TEXTURES | 0); + importer.SetPropertyInteger(AI_CONFIG_PP_SBP_REMOVE, aiPrimitiveType_POINT | aiPrimitiveType_LINE | aiPrimitiveType_POLYGON); + + const aiScene* scene = + importer.ReadFile(path, + aiProcess_JoinIdenticalVertices | aiProcess_Triangulate | aiProcess_SortByPType | aiProcess_RemoveComponent | + aiProcess_SplitLargeMeshes | // leave at default maximum + aiProcess_ValidateDataStructure | // make sure to log the output + aiProcess_ImproveCacheLocality | aiProcess_RemoveRedundantMaterials | aiProcess_FindInvalidData | aiProcess_GenSmoothNormals | + aiProcess_GenUVCoords | aiProcess_TransformUVCoords | aiProcess_FlipUVs | // Collada uses bottom-left origin + aiProcess_CalcTangentSpace | 0); + + const char* errString = importer.GetErrorString(); + if (errString[0] != '\0' || scene == nullptr) { + throw std::runtime_error("assimp error: " + std::string(errString)); + } + + if (scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE) { + throw std::runtime_error("assimp error (incomplete): " + std::string(errString)); + } + + assert(scene->HasAnimations() == false); + assert(scene->HasCameras() == false); + assert(scene->HasLights() == false); + assert(scene->hasSkeletons() == false); + + LOG_TRACE("material count: {}, mesh count: {}", scene->mNumMaterials, scene->mNumMeshes); + + std::map> textures{}; + + for (uint32_t i = 0; i < scene->mNumMaterials; i++) { + const aiMaterial* m = scene->mMaterials[i]; + LOG_TRACE("Material {}:", i); + LOG_TRACE(" Name: {}", m->GetName().C_Str()); + for (uint32_t j = 0; j < m->mNumProperties; j++) { + [[maybe_unused]] const aiMaterialProperty* p = m->mProperties[j]; + LOG_TRACE(" prop {}, key: {}", j, p->mKey.C_Str()); + } + + if (aiGetMaterialTextureCount(m, aiTextureType_DIFFUSE) >= 1) { + aiString texPath{}; + aiGetMaterialTexture(m, aiTextureType_DIFFUSE, 0, &texPath); + LOG_TRACE(" Diffuse tex: {}", texPath.C_Str()); + std::filesystem::path absPath = path; + absPath = absPath.parent_path(); + absPath /= texPath.C_Str(); + try { + textures[i] = LoadTextureFromFile(absPath.string(), Texture::Filtering::kTrilinear, parent->app()->renderer()); + } + catch (const std::runtime_error&) { + textures[i] = parent->app()->GetResource("builtin.white"); + } + } + } + + std::vector> meshes{}; + std::vector meshMaterialIndices{}; + for (uint32_t i = 0; i < scene->mNumMeshes; i++) { + const aiMesh* m = scene->mMeshes[i]; + meshMaterialIndices.push_back(m->mMaterialIndex); + std::vector vertices(m->mNumVertices); + std::vector indices((size_t)m->mNumFaces * 3); + LOG_TRACE("Mesh {}: vertex count {}", i, vertices.size()); + LOG_TRACE("Mesh {}: index count {}", i, indices.size()); + + if (m->mTangents == nullptr) { + throw std::runtime_error("No tangents array found!"); + } + + for (uint32_t j = 0; j < vertices.size(); j++) { + Vertex v{}; + v.pos.x = m->mVertices[j].x; + v.pos.y = m->mVertices[j].y; + v.pos.z = m->mVertices[j].z; + v.norm.x = m->mNormals[j].x; + v.norm.y = m->mNormals[j].y; + v.norm.z = m->mNormals[j].z; + v.tangent.x = m->mTangents[j].x; + v.tangent.y = m->mTangents[j].y; + v.tangent.z = m->mTangents[j].z; + v.tangent.w = 1.0f; + v.uv.x = m->mTextureCoords[0][j].x; + v.uv.y = m->mTextureCoords[0][j].y; + vertices[j] = v; + } + + for (uint32_t j = 0; j < indices.size() / 3; j++) { + indices[(size_t)j * 3 + 0] = m->mFaces[j].mIndices[0]; + indices[(size_t)j * 3 + 1] = m->mFaces[j].mIndices[1]; + indices[(size_t)j * 3 + 2] = m->mFaces[j].mIndices[2]; + } + meshes.push_back(std::make_shared(parent->app()->renderer()->GetDevice(), vertices, indices)); + } + + Entity obj = parent->CreateEntity(scene->GetShortFilename(path.c_str())); + + buildGraph(textures, meshes, meshMaterialIndices, scene->mRootNode, parent, obj, is_static); + + LOG_INFO("Loaded model: {}, meshes: {}, textures: {}", scene->GetShortFilename(path.c_str()), meshes.size(), textures.size()); + + Assimp::DefaultLogger::kill(); + return obj; +} + +} // namespace engine::util diff --git a/src/window.cpp b/src/window.cpp index 707928b..4a0c6c9 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -167,8 +167,8 @@ namespace engine { { const ImGuiIO& io = ImGui::GetIO(); if (io.WantCaptureMouse) { - mouse_.dx = 0.0f; - mouse_.dy = 0.0f; + mouse_.dx = 0; + mouse_.dy = 0; } else { mouse_.x = e.x; diff --git a/test/res/textures/bricks_normal.png b/test/res/textures/bricks_normal.png new file mode 100644 index 0000000..a00970d Binary files /dev/null and b/test/res/textures/bricks_normal.png differ diff --git a/test/res/textures/brickwall_albedo.jpg b/test/res/textures/brickwall_albedo.jpg new file mode 100644 index 0000000..39478d3 Binary files /dev/null and b/test/res/textures/brickwall_albedo.jpg differ diff --git a/test/res/textures/brickwall_normal.jpg b/test/res/textures/brickwall_normal.jpg new file mode 100644 index 0000000..a0a5fb6 Binary files /dev/null and b/test/res/textures/brickwall_normal.jpg differ diff --git a/test/res/textures/testnormal.png b/test/res/textures/testnormal.png new file mode 100644 index 0000000..e7d1986 Binary files /dev/null and b/test/res/textures/testnormal.png differ diff --git a/test/src/camera_controller.cpp b/test/src/camera_controller.cpp index 85cbe12..7312903 100644 --- a/test/src/camera_controller.cpp +++ b/test/src/camera_controller.cpp @@ -105,6 +105,7 @@ void CameraControllerSystem::OnUpdate(float ts) { } if (scene_->app()->input_manager()->GetButtonPress("exit")) { - scene_->app()->window()->SetCloseFlag(); + //scene_->app()->window()->SetCloseFlag(); + scene_->app()->scene_manager()->SetActiveScene(next_scene_); } } \ No newline at end of file diff --git a/test/src/camera_controller.hpp b/test/src/camera_controller.hpp index 23dd4d0..83ed69e 100644 --- a/test/src/camera_controller.hpp +++ b/test/src/camera_controller.hpp @@ -23,6 +23,8 @@ class CameraControllerSystem engine::TransformComponent* t = nullptr; CameraControllerComponent* c = nullptr; + + engine::Scene* next_scene_ = nullptr; }; #endif \ No newline at end of file diff --git a/test/src/game.cpp b/test/src/game.cpp index 5846636..3a6f1f9 100644 --- a/test/src/game.cpp +++ b/test/src/game.cpp @@ -56,12 +56,11 @@ void PlayGame(GameSettings settings) app.window()->SetRelativeMouseMode(true); ConfigureInputs(app.input_manager()); + engine::Scene* my_scene = app.scene_manager()->CreateEmptyScene(); { - static auto my_scene = app.scene_manager()->CreateEmptyScene(); - /* create camera */ - { - auto camera = my_scene->CreateEntity("camera"); + { /* create camera */ + engine::Entity camera = my_scene->CreateEntity("camera"); /* as of right now, the entity with tag 'camera' is used to build the view * matrix */ @@ -74,19 +73,23 @@ void PlayGame(GameSettings settings) my_scene->AddComponent(camera); } - /* shared resources */ - auto grass_texture = std::make_shared(app.renderer(), app.GetResourcePath("textures/grass.png"), - engine::resources::Texture::Filtering::kAnisotropic); + { /* floor */ + engine::Entity floor = engine::util::LoadMeshFromFile(my_scene, app.GetResourcePath("models/terrain.dae"), true); + } - auto sky_texture = std::make_shared(app.renderer(), app.GetResourcePath("textures/sky.jpg"), - engine::resources::Texture::Filtering::kAnisotropic); +#if 0 + + /* shared resources */ + auto grass_texture = engine::LoadTextureFromFile(app.GetResourcePath("textures/grass.png"), engine::Texture::Filtering::kAnisotropic, app.renderer()); + + std::shared_ptr sky_texture = engine::LoadTextureFromFile(app.GetResourcePath("textures/sky.jpg"), engine::Texture::Filtering::kAnisotropic, app.renderer()); /* skybox */ { engine::Entity skybox = my_scene->CreateEntity("skybox"); auto skybox_renderable = my_scene->AddComponent(skybox); - skybox_renderable->material = std::make_unique(app.GetResource("builtin.skybox")); + skybox_renderable->material = std::make_unique(app.GetResource("builtin.skybox")); skybox_renderable->material->texture_ = sky_texture; skybox_renderable->mesh = GenCuboidMesh(app.renderer()->GetDevice(), 10.0f, 10.0f, 10.0f, 1.0f, true); @@ -95,14 +98,6 @@ void PlayGame(GameSettings settings) skybox_transform->position = {-5.0f, -5.0f, -5.0f}; } - /* floor */ - { - engine::Entity floor = engine::util::LoadMeshFromFile(my_scene, app.GetResourcePath("models/terrain.dae"), true); - - auto floor_transform = my_scene->GetComponent(floor); - floor_transform->is_static = true; - } - /* building */ { auto cobbleHouse = engine::util::LoadMeshFromFile(my_scene, app.GetResourcePath("models/cobble_house/cobble_house.dae"), false); @@ -119,9 +114,9 @@ void PlayGame(GameSettings settings) engine::Entity cube = my_scene->CreateEntity("cube", 0, glm::vec3{40.0f, 10.0f, 5.0f}); auto cubeRenderable = my_scene->AddComponent(cube); cubeRenderable->mesh = GenCuboidMesh(app.renderer()->GetDevice(), 1.0f, 1.0f, 1.0f); - cubeRenderable->material = std::make_unique(app.GetResource("builtin.standard")); - cubeRenderable->material->texture_ = std::make_unique(app.renderer(), app.GetResourcePath("textures/uvcheck.png"), - engine::resources::Texture::Filtering::kAnisotropic); + cubeRenderable->material = std::make_unique(app.GetResource("builtin.standard")); + cubeRenderable->material->texture_ = + engine::LoadTextureFromFile(app.GetResourcePath("textures/uvcheck.png"), engine::Texture::Filtering::kAnisotropic, app.renderer()); } /* some text */ @@ -147,8 +142,61 @@ void PlayGame(GameSettings settings) my_scene->GetComponent(engine::util::LoadMeshFromFile(my_scene, app.GetResourcePath("models/teapot.dae"), true)) ->position += glm::vec3{10.0f, 10.0f, 10.0f}; - //engine::util::LoadGLTF(*my_scene, app.GetResourcePath("engine/models/test/test.gltf")); + // engine::util::LoadGLTF(*my_scene, app.GetResourcePath("engine/models/test/test.gltf")); - app.GameLoop(); +#endif } + + engine::Scene* scene2 = app.scene_manager()->CreateEmptyScene(); + { + + { /* create camera */ + engine::Entity camera = scene2->CreateEntity("camera"); + + /* as of right now, the entity with tag 'camera' is used to build the view + * matrix */ + + auto camera_transform = scene2->GetComponent(camera); + camera_transform->position = {0.0f, 0.0f, 10.0f}; + + scene2->RegisterComponent(); + scene2->RegisterSystem(); + scene2->AddComponent(camera); + } + + { /* house */ + engine::Entity floor = engine::util::LoadMeshFromFile(scene2, app.GetResourcePath("models/cobble_house/cobble_house.dae"), true); + } + + { /* axes */ + engine::util::LoadMeshFromFile(scene2, app.GetResourcePath("models/MY_AXES.dae"), true); + } + + { /* a wall */ + engine::Entity wall = scene2->CreateEntity("wall", 0, glm::vec3{50.0f, 0.0f, 0.0f}); + auto wall_renderable = scene2->AddComponent(wall); + wall_renderable->mesh = GenCuboidMesh(app.renderer()->GetDevice(), 8.0f, 8.0f, 8.0f); + wall_renderable->material = std::make_unique(app.renderer(), app.GetResource("builtin.fancy")); + + std::shared_ptr albedo_texture = + engine::LoadTextureFromFile(app.GetResourcePath("textures/brickwall_albedo.jpg"), engine::Texture::Filtering::kTrilinear, app.renderer()); + std::shared_ptr normal_texture = + engine::LoadTextureFromFile(app.GetResourcePath("textures/testnormal.png"), engine::Texture::Filtering::kTrilinear, app.renderer()); + + wall_renderable->material->SetAlbedoTexture(app.GetResource("builtin.white")); + wall_renderable->material->SetNormalTexture(normal_texture); + + auto custom = scene2->AddComponent(wall); + custom->onInit = []() {}; + custom->onUpdate = [&](float dt) { + //scene2->GetComponent(wall)->rotation *= glm::angleAxis(dt, glm::normalize(glm::vec3{2.0f, 1.0f, 1.0f})); + }; + } + } + + my_scene->GetSystem()->next_scene_ = scene2; + scene2->GetSystem()->next_scene_ = my_scene; + + app.scene_manager()->SetActiveScene(my_scene); + app.GameLoop(); } diff --git a/test/src/meshgen.cpp b/test/src/meshgen.cpp index 9280036..f5f8200 100644 --- a/test/src/meshgen.cpp +++ b/test/src/meshgen.cpp @@ -8,7 +8,7 @@ #include "resources/mesh.h" -std::unique_ptr GenSphereMesh(engine::GFXDevice* gfx, float r, int detail, bool wind_inside, bool flip_normals) +std::unique_ptr GenSphereMesh(engine::GFXDevice* gfx, float r, int detail, bool wind_inside, bool flip_normals) { using namespace glm; @@ -34,26 +34,26 @@ std::unique_ptr GenSphereMesh(engine::GFXDevice* gfx, f // tris are visible from outside the sphere // triangle 1 - vertices.push_back({top_left, {}, {0.0f, 0.0f}}); - vertices.push_back({bottom_left, {}, {0.0f, 1.0f}}); - vertices.push_back({bottom_right, {}, {1.0f, 1.0f}}); + vertices.push_back({top_left, {}, {}, {0.0f, 0.0f}}); + vertices.push_back({bottom_left, {}, {}, {0.0f, 1.0f}}); + vertices.push_back({bottom_right, {}, {}, {1.0f, 1.0f}}); // triangle 2 - vertices.push_back({top_right, {}, {1.0f, 0.0f}}); - vertices.push_back({top_left, {}, {0.0f, 0.0f}}); - vertices.push_back({bottom_right, {}, {1.0f, 1.0f}}); + vertices.push_back({top_right, {}, {}, {1.0f, 0.0f}}); + vertices.push_back({top_left, {}, {}, {0.0f, 0.0f}}); + vertices.push_back({bottom_right, {}, {}, {1.0f, 1.0f}}); } else { // tris are visible from inside the sphere // triangle 1 - vertices.push_back({bottom_right, {}, {1.0f, 1.0f}}); - vertices.push_back({bottom_left, {}, {0.0f, 1.0f}}); - vertices.push_back({top_left, {}, {0.0f, 0.0f}}); + vertices.push_back({bottom_right, {}, {}, {1.0f, 1.0f}}); + vertices.push_back({bottom_left, {}, {}, {0.0f, 1.0f}}); + vertices.push_back({top_left, {}, {}, {0.0f, 0.0f}}); // triangle 2 - vertices.push_back({bottom_right, {}, {1.0f, 1.0f}}); - vertices.push_back({top_left, {}, {0.0f, 0.0f}}); - vertices.push_back({top_right, {}, {1.0f, 0.0f}}); + vertices.push_back({bottom_right, {}, {}, {1.0f, 1.0f}}); + vertices.push_back({top_left, {}, {}, {0.0f, 0.0f}}); + vertices.push_back({top_right, {}, {}, {1.0f, 0.0f}}); } vec3 vector1 = (vertices.end() - 1)->pos - (vertices.end() - 2)->pos; @@ -72,10 +72,10 @@ std::unique_ptr GenSphereMesh(engine::GFXDevice* gfx, f } } - return std::make_unique(gfx, vertices); + return std::make_unique(gfx, vertices); } -std::unique_ptr GenCuboidMesh(engine::GFXDevice* gfx, float x, float y, float z, float tiling, bool wind_inside) +std::unique_ptr GenCuboidMesh(engine::GFXDevice* gfx, float x, float y, float z, float tiling, bool wind_inside) { // x goes -> // y goes ^ @@ -86,47 +86,47 @@ std::unique_ptr GenCuboidMesh(engine::GFXDevice* gfx, f std::vector v{}; // front - v.push_back({ {0.0f, 0.0f, z}, {0.0f, -1.0f, 0.0f}, {0.0f, 0.0f} }); - v.push_back({ {0.0f, 0.0f, 0.0f}, {0.0f, -1.0f, 0.0f}, {0.0f, tiling} }); - v.push_back({ {x, 0.0f, 0.0f}, {0.0f, -1.0f, 0.0f}, {tiling, tiling} }); - v.push_back({ {x, 0.0f, 0.0f}, {0.0f, -1.0f, 0.0f}, {tiling, tiling} }); - v.push_back({ {x, 0.0f, z}, {0.0f, -1.0f, 0.0f}, {tiling, 0.0f} }); - v.push_back({ {0.0f, 0.0f, z}, {0.0f, -1.0f, 0.0f}, {0.0f, 0.0f} }); + v.push_back({{0.0f, 0.0f, z}, {0.0f, -1.0f, 0.0f}, {1.0f, 0.0f, 0.0f, 1.0f}, {0.0f, 0.0f}}); + v.push_back({{0.0f, 0.0f, 0.0f}, {0.0f, -1.0f, 0.0f}, {1.0f, 0.0f, 0.0f, 1.0f}, {0.0f, tiling}}); + v.push_back({{x, 0.0f, 0.0f}, {0.0f, -1.0f, 0.0f}, {1.0f, 0.0f, 0.0f, 1.0f}, {tiling, tiling}}); + v.push_back({{x, 0.0f, 0.0f}, {0.0f, -1.0f, 0.0f}, {1.0f, 0.0f, 0.0f, 1.0f}, {tiling, tiling}}); + v.push_back({{x, 0.0f, z}, {0.0f, -1.0f, 0.0f}, {1.0f, 0.0f, 0.0f, 1.0f}, {tiling, 0.0f}}); + v.push_back({{0.0f, 0.0f, z}, {0.0f, -1.0f, 0.0f}, {1.0f, 0.0f, 0.0f, 1.0f}, {0.0f, 0.0f}}); // back - v.push_back({ {x, y, z}, {0.0f, 1.0f, 0.0f}, {0.0f, 0.0f} }); - v.push_back({ {x, y, 0.0f}, {0.0f, 1.0f, 0.0f}, {0.0f, tiling} }); - v.push_back({ {0.0f, y, 0.0f}, {0.0f, 1.0f, 0.0f}, {tiling, tiling} }); - v.push_back({ {0.0f, y, 0.0f}, {0.0f, 1.0f, 0.0f}, {tiling, tiling} }); - v.push_back({ {0.0f, y, z}, {0.0f, 1.0f, 0.0f}, {tiling, 0.0f} }); - v.push_back({ {x, y, z}, {0.0f, 1.0f, 0.0f}, {0.0f, 0.0f} }); + v.push_back({{x, y, z}, {0.0f, 1.0f, 0.0f}, {}, {0.0f, 0.0f}}); + v.push_back({{x, y, 0.0f}, {0.0f, 1.0f, 0.0f}, {}, {0.0f, tiling}}); + v.push_back({{0.0f, y, 0.0f}, {0.0f, 1.0f, 0.0f}, {}, {tiling, tiling}}); + v.push_back({{0.0f, y, 0.0f}, {0.0f, 1.0f, 0.0f}, {}, {tiling, tiling}}); + v.push_back({{0.0f, y, z}, {0.0f, 1.0f, 0.0f}, {}, {tiling, 0.0f}}); + v.push_back({{x, y, z}, {0.0f, 1.0f, 0.0f}, {}, {0.0f, 0.0f}}); // left - v.push_back({ {0.0f, y, z}, {-1.0f, 0.0f, 0.0f}, {0.0f, 0.0f} }); - v.push_back({ {0.0f, y, 0.0f}, {-1.0f, 0.0f, 0.0f}, {0.0f, tiling} }); - v.push_back({ {0.0f, 0.0f, 0.0f}, {-1.0f, 0.0f, 0.0f}, {tiling, tiling} }); - v.push_back({ {0.0f, 0.0f, 0.0f}, {-1.0f, 0.0f, 0.0f}, {tiling, tiling} }); - v.push_back({ {0.0f, 0.0f, z}, {-1.0f, 0.0f, 0.0f}, {tiling, 0.0f} }); - v.push_back({ {0.0f, y, z}, {-1.0f, 0.0f, 0.0f}, {0.0f, 0.0f} }); + v.push_back({{0.0f, y, z}, {-1.0f, 0.0f, 0.0f}, {}, {0.0f, 0.0f}}); + v.push_back({{0.0f, y, 0.0f}, {-1.0f, 0.0f, 0.0f}, {}, {0.0f, tiling}}); + v.push_back({{0.0f, 0.0f, 0.0f}, {-1.0f, 0.0f, 0.0f}, {}, {tiling, tiling}}); + v.push_back({{0.0f, 0.0f, 0.0f}, {-1.0f, 0.0f, 0.0f}, {}, {tiling, tiling}}); + v.push_back({{0.0f, 0.0f, z}, {-1.0f, 0.0f, 0.0f}, {}, {tiling, 0.0f}}); + v.push_back({{0.0f, y, z}, {-1.0f, 0.0f, 0.0f}, {}, {0.0f, 0.0f}}); // right - v.push_back({ {x, 0.0f, z}, {1.0f, 0.0f, 0.0f}, {0.0f, 0.0f} }); - v.push_back({ {x, 0.0f, 0.0f}, {1.0f, 0.0f, 0.0f}, {0.0f, tiling} }); - v.push_back({ {x, y, 0.0f}, {1.0f, 0.0f, 0.0f}, {tiling, tiling} }); - v.push_back({ {x, y, 0.0f}, {1.0f, 0.0f, 0.0f}, {tiling, tiling} }); - v.push_back({ {x, y, z}, {1.0f, 0.0f, 0.0f}, {tiling, 0.0f} }); - v.push_back({ {x, 0.0f, z}, {1.0f, 0.0f, 0.0f}, {0.0f, 0.0f} }); + v.push_back({{x, 0.0f, z}, {1.0f, 0.0f, 0.0f}, {}, {0.0f, 0.0f}}); + v.push_back({{x, 0.0f, 0.0f}, {1.0f, 0.0f, 0.0f}, {}, {0.0f, tiling}}); + v.push_back({{x, y, 0.0f}, {1.0f, 0.0f, 0.0f}, {}, {tiling, tiling}}); + v.push_back({{x, y, 0.0f}, {1.0f, 0.0f, 0.0f}, {}, {tiling, tiling}}); + v.push_back({{x, y, z}, {1.0f, 0.0f, 0.0f}, {}, {tiling, 0.0f}}); + v.push_back({{x, 0.0f, z}, {1.0f, 0.0f, 0.0f}, {}, {0.0f, 0.0f}}); // top - v.push_back({ {0.0f, y, z}, {0.0f, 0.0f, 1.0f}, {0.0f, 0.0f} }); - v.push_back({ {0.0f, 0.0f, z}, {0.0f, 0.0f, 1.0f}, {0.0f, tiling} }); - v.push_back({ {x, 0.0f, z}, {0.0f, 0.0f, 1.0f}, {tiling, tiling} }); - v.push_back({ {x, 0.0f, z}, {0.0f, 0.0f, 1.0f}, {tiling, tiling} }); - v.push_back({ {x, y, z}, {0.0f, 0.0f, 1.0f}, {tiling, 0.0f} }); - v.push_back({ {0.0f, y, z}, {0.0f, 0.0f, 1.0f}, {0.0f, 0.0f} }); + v.push_back({{0.0f, y, z}, {0.0f, 0.0f, 1.0f}, {1.0f, 0.0f, 0.0f, 1.0f}, {0.0f, 0.0f}}); + v.push_back({{0.0f, 0.0f, z}, {0.0f, 0.0f, 1.0f}, {1.0f, 0.0f, 0.0f, 1.0f}, {0.0f, tiling}}); + v.push_back({{x, 0.0f, z}, {0.0f, 0.0f, 1.0f}, {1.0f, 0.0f, 0.0f, 1.0f}, {tiling, tiling}}); + v.push_back({{x, 0.0f, z}, {0.0f, 0.0f, 1.0f}, {1.0f, 0.0f, 0.0f, 1.0f}, {tiling, tiling}}); + v.push_back({{x, y, z}, {0.0f, 0.0f, 1.0f}, {1.0f, 0.0f, 0.0f, 1.0f}, {tiling, 0.0f}}); + v.push_back({{0.0f, y, z}, {0.0f, 0.0f, 1.0f}, {1.0f, 0.0f, 0.0f, 1.0f}, {0.0f, 0.0f}}); // bottom - v.push_back({ {x, y, 0.0f}, {0.0f, 0.0f, -1.0f}, {0.0f, 0.0f} }); - v.push_back({ {x, 0.0f, 0.0f}, {0.0f, 0.0f, -1.0f}, {0.0f, tiling} }); - v.push_back({ {0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, -1.0f}, {tiling, tiling} }); - v.push_back({ {0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, -1.0f}, {tiling, tiling} }); - v.push_back({ {0.0f, y, 0.0f}, {0.0f, 0.0f, -1.0f}, {tiling, 0.0f} }); - v.push_back({ {x, y, 0.0f}, {0.0f, 0.0f, -1.0f}, {0.0f, 0.0f} }); + v.push_back({{x, y, 0.0f}, {0.0f, 0.0f, -1.0f}, {}, {0.0f, 0.0f}}); + v.push_back({{x, 0.0f, 0.0f}, {0.0f, 0.0f, -1.0f}, {}, {0.0f, tiling}}); + v.push_back({{0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, -1.0f}, {}, {tiling, tiling}}); + v.push_back({{0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, -1.0f}, {}, {tiling, tiling}}); + v.push_back({{0.0f, y, 0.0f}, {0.0f, 0.0f, -1.0f}, {}, {tiling, 0.0f}}); + v.push_back({{x, y, 0.0f}, {0.0f, 0.0f, -1.0f}, {}, {0.0f, 0.0f}}); if (wind_inside) { for (size_t i = 0; i < v.size(); i += 3) { @@ -134,5 +134,5 @@ std::unique_ptr GenCuboidMesh(engine::GFXDevice* gfx, f } } - return std::make_unique(gfx, v); + return std::make_unique(gfx, v); } diff --git a/test/src/meshgen.hpp b/test/src/meshgen.hpp index 888d3a9..4e53e4b 100644 --- a/test/src/meshgen.hpp +++ b/test/src/meshgen.hpp @@ -5,11 +5,11 @@ #include "resources/mesh.h" -std::unique_ptr GenSphereMesh( +std::unique_ptr GenSphereMesh( engine::GFXDevice* gfx, float r, int detail, bool wind_inside = false, bool flip_normals = false); -std::unique_ptr GenCuboidMesh( +std::unique_ptr GenCuboidMesh( engine::GFXDevice* gfx, float x, float y, float z, float tiling = 1.0f, bool wind_inside = false);