diff --git a/Assets/Meshes/cube.obj b/Assets/Models/cube.obj similarity index 100% rename from Assets/Meshes/cube.obj rename to Assets/Models/cube.obj diff --git a/Assets/Meshes/sphere.obj b/Assets/Models/sphere.obj similarity index 100% rename from Assets/Meshes/sphere.obj rename to Assets/Models/sphere.obj diff --git a/Assets/Shaders/phong.fs b/Assets/Shaders/phong.fs index 6468e838..dfb6fc00 100644 --- a/Assets/Shaders/phong.fs +++ b/Assets/Shaders/phong.fs @@ -1,5 +1,5 @@ #version 330 core -#define ICE_MAX_LIGHTS (256) +#define ICE_MAX_LIGHTS (16) out vec4 frag_color; @@ -7,12 +7,13 @@ struct Light { vec3 position; vec3 rotation; vec3 color; + int type; //0 = Point, 1 = Directional, 2 = Spot }; struct Material { - vec3 albedo; - vec3 specular; - vec3 ambient; + vec4 albedo; + vec4 specular; + vec4 ambient; float alpha; bool use_diffuse_map; sampler2D diffuse_map; @@ -36,33 +37,43 @@ in vec2 ftex_coords; vec3 normal; -vec3 pointLight(Light light) { - vec3 rcolor = vec3(0.0); +vec4 computeLightEffect(Light light, vec3 light_direction) { + vec4 rcolor = vec4(0.0); //diffuse vec3 n = normalize(normal); - vec3 light_direction = normalize(light.position - fposition); float diff = max(dot(n, light_direction), 0.0); - vec3 diffuse_color = material.albedo; + vec4 diffuse_color = material.albedo; if(material.use_diffuse_map) { - diffuse_color *= texture(material.diffuse_map, ftex_coords).xyz; + diffuse_color *= texture(material.diffuse_map, ftex_coords); } - rcolor += light.color * (diff * diffuse_color); + rcolor += vec4(light.color, 1.0) * (diff * diffuse_color); if(diff > 0) { //specular vec3 view_direction = normalize(fview - fposition); vec3 reflection_direction = reflect(-light_direction, n); float spec = pow(max(dot(view_direction, reflection_direction), 0.0), material.alpha); - vec3 specular_color = material.specular; + vec4 specular_color = material.specular; if(material.use_specular_map) { - specular_color *= texture(material.specular_map, ftex_coords).xyz; + specular_color *= texture(material.specular_map, ftex_coords); } - rcolor += light.color * (spec * specular_color); + rcolor += vec4(light.color, 1.0) * (spec * specular_color); } return rcolor; } +vec4 applyLight(Light light) { + if(light.type == 0) { + vec3 light_direction = normalize(light.position - fposition); + float distance = length(light.position - fposition); + return computeLightEffect(light, light_direction); + } else if(light.type == 1) { + return computeLightEffect(light, -normalize(light.rotation)); + } else if(light.type == 2) { + //TODO: Spot lights + } +} vec3 colorToNormal(vec3 color) { return normalize(vec3(color.x * 2 - 1, color.y * 2 - 1, color.z * 2 - 1)); @@ -76,19 +87,19 @@ void main() { normal = fnormal; } //ambient - vec3 color_accumulator = vec3(material.ambient*ambient_light); + vec4 color_accumulator = material.ambient * vec4(ambient_light, 1.0); if(material.use_ambient_map) { - color_accumulator *= texture(material.ambient_map, ftex_coords).xyz; + color_accumulator *= texture(material.ambient_map, ftex_coords); } for(int i = 0; i < light_count; i++) { - color_accumulator += pointLight(lights[i]); + color_accumulator += applyLight(lights[i]); } if(light_count == 0) { - frag_color = vec4(material.albedo, 1.0); + frag_color = material.albedo; if(material.use_diffuse_map) { frag_color *= texture(material.diffuse_map, ftex_coords); } } else { - frag_color = vec4(color_accumulator, 1.0); + frag_color = color_accumulator; } } \ No newline at end of file diff --git a/ICE/Assets/include/Asset.h b/ICE/Assets/include/Asset.h index b47de8d8..1dae6038 100644 --- a/ICE/Assets/include/Asset.h +++ b/ICE/Assets/include/Asset.h @@ -14,14 +14,12 @@ namespace ICE { typedef unsigned long long AssetUID; -enum class AssetType { ETex2D, ETexCube, EShader, EMesh, EMaterial }; +enum class AssetType { ETex2D, ETexCube, EShader, EMesh, EModel, EMaterial }; class Asset : public Resource { public: Asset() : Resource({}) {} virtual AssetType getType() const = 0; virtual std::string getTypeName() const = 0; - virtual void load() = 0; - virtual void unload() = 0; }; } // namespace ICE diff --git a/ICE/Assets/include/AssetBank.h b/ICE/Assets/include/AssetBank.h index 5ad30f0f..54600e16 100644 --- a/ICE/Assets/include/AssetBank.h +++ b/ICE/Assets/include/AssetBank.h @@ -86,6 +86,16 @@ class AssetBank { return false; } + bool addAssetWithSpecificUID(const AssetPath& name, const std::shared_ptr& asset, AssetUID id) { + if (resources.find(id) == resources.end() && nameMapping.find(name) == nameMapping.end()) { + resources.try_emplace(id, AssetBankEntry{name, asset}); + nameMapping.try_emplace(name, id); + nextUID = nextUID > id ? nextUID : id + 1; + return true; + } + return false; + } + bool renameAsset(const AssetPath& oldName, const AssetPath& newName) { if (oldName.toString() == newName.toString()) { return true; @@ -108,7 +118,7 @@ class AssetBank { if (nameMapping.find(name) != nameMapping.end()) { AssetUID id = getUID(name); nameMapping.erase(name); - resources[id].asset->unload(); + //TODO: Check resources[id].asset->unload(); resources.erase(id); return true; } diff --git a/ICE/Assets/include/AssetLoader.h b/ICE/Assets/include/AssetLoader.h index 4fafc6f6..75d25cc2 100644 --- a/ICE/Assets/include/AssetLoader.h +++ b/ICE/Assets/include/AssetLoader.h @@ -12,6 +12,7 @@ #include "Asset.h" #include "IAssetLoader.h" +#include "Model.h" namespace ICE { class AssetLoader { @@ -32,9 +33,10 @@ class AssetLoader { } private: - std::unordered_map>, std::shared_ptr>, std::shared_ptr>, - std::shared_ptr>, std::shared_ptr>>> + std::unordered_map< + std::type_index, + std::variant>, std::shared_ptr>, std::shared_ptr>, + std::shared_ptr>, std::shared_ptr>>> loaders; }; } // namespace ICE diff --git a/ICE/Assets/src/AssetBank.cpp b/ICE/Assets/src/AssetBank.cpp index 669e54b1..3ac81f18 100644 --- a/ICE/Assets/src/AssetBank.cpp +++ b/ICE/Assets/src/AssetBank.cpp @@ -5,10 +5,10 @@ #include "AssetBank.h" #include -#include +#include #include "MaterialLoader.h" -#include "MeshLoader.h" +#include "ModelLoader.h" #include "ShaderLoader.h" #include "TextureLoader.h" @@ -17,7 +17,7 @@ namespace ICE { AssetBank::AssetBank(const std::shared_ptr &factory) : graphics_factory(factory) { loader.AddLoader(std::make_shared(factory)); loader.AddLoader(std::make_shared(factory)); - loader.AddLoader(std::make_shared(factory)); + loader.AddLoader(std::make_shared(factory, *this)); loader.AddLoader(std::make_shared(factory)); loader.AddLoader(std::make_shared()); } diff --git a/ICE/Assets/src/AssetPath.cpp b/ICE/Assets/src/AssetPath.cpp index 070d4952..2460372e 100644 --- a/ICE/Assets/src/AssetPath.cpp +++ b/ICE/Assets/src/AssetPath.cpp @@ -2,56 +2,56 @@ // Created by Thomas Ibanez on 03.08.21. // -#include -#include +#include "AssetPath.h" + #include +#include #include -#include "AssetPath.h" +#include namespace ICE { - std::unordered_map AssetPath::typenames = { - {typeid(Texture2D), "Textures"}, - {typeid(TextureCube), "CubeMaps"}, - {typeid(Mesh), "Meshes"}, - {typeid(Material), "Materials"}, - {typeid(Shader), "Shaders"} - }; - - AssetPath::AssetPath(std::string path) { - size_t last = 0; - for(size_t i = 0; i < path.length(); i++) { - if(path[i] == ASSET_PATH_SEPARATOR) { - this->path.push_back(path.substr(last, i-last)); - last = i + 1; - } +std::unordered_map AssetPath::typenames = {{typeid(Texture2D), "Textures"}, + {typeid(TextureCube), "CubeMaps"}, + {typeid(Model), "Models"}, + {typeid(Material), "Materials"}, + {typeid(Shader), "Shaders"}}; + +AssetPath::AssetPath(std::string path) { + size_t last = 0; + for (size_t i = 0; i < path.length(); i++) { + if (path[i] == ASSET_PATH_SEPARATOR) { + this->path.push_back(path.substr(last, i - last)); + last = i + 1; } - name = path.substr(last, path.length()-last); } + name = path.substr(last, path.length() - last); +} - std::string AssetPath::toString() const { - return (prefix() + name); - } +std::string AssetPath::toString() const { + return (prefix() + name); +} - std::vector AssetPath::getPath() const { - return path; - } +std::vector AssetPath::getPath() const { + return path; +} - std::string AssetPath::getName() const { - return name; - } +std::string AssetPath::getName() const { + return name; +} - void AssetPath::setName(const std::string &name) { - AssetPath::name = name; - } +void AssetPath::setName(const std::string &name) { + AssetPath::name = name; +} - AssetPath::AssetPath(const AssetPath& cpy) : AssetPath(cpy.toString()) {} +AssetPath::AssetPath(const AssetPath &cpy) : AssetPath(cpy.toString()) { +} - std::string AssetPath::prefix() const { - auto str = std::string(); - for(auto &p : path) { - str += p+ASSET_PATH_SEPARATOR; - } - return str; +std::string AssetPath::prefix() const { + auto str = std::string(); + for (auto &p : path) { + str += p + ASSET_PATH_SEPARATOR; } -} \ No newline at end of file + return str; +} +} // namespace ICE \ No newline at end of file diff --git a/ICE/Assets/test/AssetBankTest.cpp b/ICE/Assets/test/AssetBankTest.cpp index 1fafecfe..28c789e2 100644 --- a/ICE/Assets/test/AssetBankTest.cpp +++ b/ICE/Assets/test/AssetBankTest.cpp @@ -1,6 +1,7 @@ // // Created by Thomas Ibanez on 24.02.21. // +#define STB_IMAGE_IMPLEMENTATION #include #include "AssetBank.h" @@ -8,6 +9,7 @@ using namespace ICE; + TEST(AssetBankTest, AddedAssetsCanBeRetrieved) { NoneGraphicsFactory g_fac; AssetBank ab(std::make_shared(g_fac)); diff --git a/ICE/Assets/test/AssetPathTest.cpp b/ICE/Assets/test/AssetPathTest.cpp index 2a090ed1..e560eff5 100644 --- a/ICE/Assets/test/AssetPathTest.cpp +++ b/ICE/Assets/test/AssetPathTest.cpp @@ -2,7 +2,7 @@ // Created by Thomas Ibanez on 24.02.21. // #include -#include +#include #include #include #include @@ -32,7 +32,7 @@ TEST(AssetPathTest, setNameOk) { TEST(AssetPathTest, TypePrefixOk) { EXPECT_EQ(AssetPath::WithTypePrefix("a").toString(), "Materials/a"); - EXPECT_EQ(AssetPath::WithTypePrefix("a").toString(), "Meshes/a"); + EXPECT_EQ(AssetPath::WithTypePrefix("a").toString(), "Models/a"); EXPECT_EQ(AssetPath::WithTypePrefix("a").toString(), "Shaders/a"); EXPECT_EQ(AssetPath::WithTypePrefix("a").toString(), "Textures/a"); EXPECT_EQ(AssetPath::WithTypePrefix("a").toString(), "CubeMaps/a"); diff --git a/ICE/CMakeLists.txt b/ICE/CMakeLists.txt index ad50cd66..294fb2be 100644 --- a/ICE/CMakeLists.txt +++ b/ICE/CMakeLists.txt @@ -3,6 +3,8 @@ project(ICE) message(STATUS "Building ${PROJECT_NAME}") +add_compile_definitions(NOMINMAX) + add_subdirectory(Assets) add_subdirectory(Components) add_subdirectory(Core) diff --git a/ICE/Components/include/RenderComponent.h b/ICE/Components/include/RenderComponent.h index e5e44d36..f44bb4b9 100644 --- a/ICE/Components/include/RenderComponent.h +++ b/ICE/Components/include/RenderComponent.h @@ -11,9 +11,8 @@ namespace ICE { struct RenderComponent : public Component { - RenderComponent(AssetUID mesh_id, AssetUID material_id) : mesh(mesh_id), material(material_id) {} - AssetUID mesh; - AssetUID material; + RenderComponent(AssetUID model_id) : model(model_id) {} + AssetUID model; }; } // namespace ICE diff --git a/ICE/Core/src/ICEEngine.cpp b/ICE/Core/src/ICEEngine.cpp index dc1464ad..2d901755 100644 --- a/ICE/Core/src/ICEEngine.cpp +++ b/ICE/Core/src/ICEEngine.cpp @@ -1,4 +1,5 @@ #define STB_IMAGE_IMPLEMENTATION + #include "ICEEngine.h" #include diff --git a/ICE/Graphics/CMakeLists.txt b/ICE/Graphics/CMakeLists.txt index dc528bba..d1e42010 100644 --- a/ICE/Graphics/CMakeLists.txt +++ b/ICE/Graphics/CMakeLists.txt @@ -11,7 +11,8 @@ target_sources(${PROJECT_NAME} PRIVATE src/ForwardRenderer.cpp src/Material.cpp src/Mesh.cpp - src/GeometryPass.cpp "include/RenderData.h") + src/Model.cpp + src/GeometryPass.cpp) target_link_libraries(${PROJECT_NAME} PUBLIC diff --git a/ICE/Graphics/include/GraphicsFactory.h b/ICE/Graphics/include/GraphicsFactory.h index ef11a962..329684c9 100644 --- a/ICE/Graphics/include/GraphicsFactory.h +++ b/ICE/Graphics/include/GraphicsFactory.h @@ -33,6 +33,7 @@ class GraphicsFactory { const std::string& fragmentFile) const = 0; virtual std::shared_ptr createTexture2D(const std::string& file) const = 0; + virtual std::shared_ptr createTexture2D(const void* data, size_t w, size_t h, TextureFormat fmt) const = 0; virtual std::shared_ptr createTextureCube(const std::string& file) const = 0; }; diff --git a/ICE/Graphics/include/Material.h b/ICE/Graphics/include/Material.h index e3675501..e4ade123 100644 --- a/ICE/Graphics/include/Material.h +++ b/ICE/Graphics/include/Material.h @@ -44,8 +44,6 @@ class Material : public Asset { //Asset interface std::string getTypeName() const override; AssetType getType() const override; - void load() override; - void unload() override; private: AssetUID m_shader = NO_ASSET_ID; diff --git a/ICE/Graphics/include/Mesh.h b/ICE/Graphics/include/Mesh.h index 68fbea86..b1881ca3 100644 --- a/ICE/Graphics/include/Mesh.h +++ b/ICE/Graphics/include/Mesh.h @@ -35,8 +35,6 @@ class Mesh : public Asset { std::string getTypeName() const override; AssetType getType() const override; - void load() override; - void unload() override; private: std::vector vertices, normals; diff --git a/ICE/Graphics/include/Model.h b/ICE/Graphics/include/Model.h new file mode 100644 index 00000000..653c7bfe --- /dev/null +++ b/ICE/Graphics/include/Model.h @@ -0,0 +1,23 @@ +#pragma once + +#include "Asset.h" +#include "Mesh.h" + +namespace ICE { +class Model : public Asset { + public: + Model(const std::vector> &meshes, const std::vector &materials); + + std::vector> getMeshes() const { return m_meshes; } + std::vector getMaterialsIDs() const { return m_materials; } + AABB getBoundingBox() const { return m_boundingbox; } + + AssetType getType() const override { return AssetType::EModel; } + std::string getTypeName() const override { return "Model"; } + + private: + std::vector> m_meshes; + std::vector m_materials; + AABB m_boundingbox{{0, 0, 0}, {0, 0, 0}}; +}; +} // namespace ICE \ No newline at end of file diff --git a/ICE/Graphics/include/Shader.h b/ICE/Graphics/include/Shader.h index 8e3c4e80..bc839067 100644 --- a/ICE/Graphics/include/Shader.h +++ b/ICE/Graphics/include/Shader.h @@ -5,35 +5,31 @@ #ifndef ICE_SHADER_H #define ICE_SHADER_H -#include -#include #include -namespace ICE { - class Shader : public Asset { - public: - virtual void bind() const = 0; - virtual void unbind() const = 0; +#include +#include - virtual void loadInt(const std::string &name, int v) = 0; - virtual void loadInts(const std::string &name, int* array, uint32_t size) = 0; +namespace ICE { +class Shader : public Asset { + public: + virtual void bind() const = 0; + virtual void unbind() const = 0; - virtual void loadFloat(const std::string &name, float v) = 0; - virtual void loadFloat2(const std::string &name, Eigen::Vector2f vec) = 0; - virtual void loadFloat3(const std::string &name, Eigen::Vector3f vec) = 0; - virtual void loadFloat4(const std::string &name, Eigen::Vector4f vec) = 0; + virtual void loadInt(const std::string &name, int v) = 0; + virtual void loadInts(const std::string &name, int *array, uint32_t size) = 0; - virtual void loadMat4(const std::string &name, Eigen::Matrix4f mat) = 0; + virtual void loadFloat(const std::string &name, float v) = 0; + virtual void loadFloat2(const std::string &name, Eigen::Vector2f vec) = 0; + virtual void loadFloat3(const std::string &name, Eigen::Vector3f vec) = 0; + virtual void loadFloat4(const std::string &name, Eigen::Vector4f vec) = 0; - std::string getTypeName() const override { - return "Shader"; - }; + virtual void loadMat4(const std::string &name, Eigen::Matrix4f mat) = 0; - AssetType getType() const override { - return AssetType::EShader; - }; + std::string getTypeName() const override { return "Shader"; }; - }; -} + AssetType getType() const override { return AssetType::EShader; }; +}; +} // namespace ICE -#endif //ICE_SHADER_H +#endif //ICE_SHADER_H diff --git a/ICE/Graphics/include/Texture.h b/ICE/Graphics/include/Texture.h index 682ba6df..0ecbf37d 100644 --- a/ICE/Graphics/include/Texture.h +++ b/ICE/Graphics/include/Texture.h @@ -4,10 +4,10 @@ #ifndef ICE_TEXTURE_H #define ICE_TEXTURE_H +#include #include #include -#include #include #include @@ -34,7 +34,6 @@ class Texture : public Asset { virtual TextureType getTextureType() const = 0; static void* getDataFromFile(const std::string file, int* width, int* height, int* channels, int force = STBI_default) { - stbi_set_flip_vertically_on_load(1); stbi_uc* data = stbi_load(file.c_str(), width, height, channels, force); if(data == nullptr) { Logger::Log(Logger::ERROR, "Graphics", "Texture %s could not load: %s", file.c_str(), stbi_failure_reason()); @@ -50,8 +49,6 @@ class Texture2D : public Texture { virtual AssetType getType() const override { return AssetType::ETex2D; } virtual std::string getTypeName() const override { return "Texture2D"; } - virtual void load() override = 0; - virtual void unload() override = 0; }; class TextureCube : public Texture { @@ -61,8 +58,6 @@ class TextureCube : public Texture { virtual AssetType getType() const override { return AssetType::ETexCube; } virtual std::string getTypeName() const override { return "TextureCube"; } - virtual void load() override = 0; - virtual void unload() override = 0; }; } // namespace ICE diff --git a/ICE/Graphics/src/ForwardRenderer.cpp b/ICE/Graphics/src/ForwardRenderer.cpp index 11746728..80eec167 100644 --- a/ICE/Graphics/src/ForwardRenderer.cpp +++ b/ICE/Graphics/src/ForwardRenderer.cpp @@ -66,21 +66,6 @@ void ForwardRenderer::remove(Entity e) { void ForwardRenderer::prepareFrame(Camera& camera) { //TODO: Sort entities, make shader list, batch, make instances, set uniforms, etc.. - std::sort(m_render_queue.begin(), m_render_queue.end(), [this](Entity a, Entity b) { - auto rc_a = m_registry->getComponent(a); - auto material_a = m_asset_bank->getAsset(rc_a->material); - auto rc_b = m_registry->getComponent(b); - auto material_b = m_asset_bank->getAsset(rc_b->material); - - bool a_transparent = material_a ? material_a->isTransparent() : false; - bool b_transparent = material_b ? material_b->isTransparent() : false; - - if (!a_transparent && b_transparent) { - return true; - } else { - return false; - } - }); if (m_skybox != NO_ASSET_ID) { auto shader = m_asset_bank->getAsset("__ice_skybox_shader"); @@ -106,64 +91,90 @@ void ForwardRenderer::prepareFrame(Camera& camera) { std::unordered_set prepared_shaders; auto view_mat = camera.lookThrough(); + auto frustum = extractFrustumPlanes(camera.getProjection() * view_mat); for (const auto& e : m_render_queue) { auto rc = m_registry->getComponent(e); auto tc = m_registry->getComponent(e); - auto material = m_asset_bank->getAsset(rc->material); - if (!material) { + auto model = m_asset_bank->getAsset(rc->model); + if (!model) continue; - } - auto shader = m_asset_bank->getAsset(material->getShader()); - if (!shader) { + + auto aabb = model->getBoundingBox(); + Eigen::Vector3f min = (tc->getModelMatrix() * Eigen::Vector4f(aabb.getMin().x(), aabb.getMin().y(), aabb.getMin().z(), 1.0)).head<3>(); + Eigen::Vector3f max = (tc->getModelMatrix() * Eigen::Vector4f(aabb.getMax().x(), aabb.getMax().y(), aabb.getMax().z(), 1.0)).head<3>(); + aabb = AABB(std::vector{min, max}); + if (!isAABBInFrustum(frustum, aabb)) { continue; } - if (!prepared_shaders.contains(material->getShader())) { - shader->bind(); - - shader->loadMat4("projection", camera.getProjection()); - shader->loadMat4("view", view_mat); - - shader->loadFloat3("ambient_light", Eigen::Vector3f(0.1f, 0.1f, 0.1f)); - int i = 0; - for (const auto& e : m_lights) { - auto light = m_registry->getComponent(e); - auto transform = m_registry->getComponent(e); - std::string light_name = (std::string("lights[") + std::to_string(i) + std::string("].")); - shader->loadFloat3((light_name + std::string("position")).c_str(), transform->getPosition()); - shader->loadFloat3((light_name + std::string("rotation")).c_str(), transform->getRotation()); - shader->loadFloat3((light_name + std::string("color")).c_str(), light->color); - shader->loadInt((light_name + std::string("type")).c_str(), static_cast(light->type)); - i++; + for (int i = 0; i < model->getMeshes().size(); i++) { + auto mtl_id = model->getMaterialsIDs().at(i); + auto mesh = model->getMeshes().at(i); + auto material = m_asset_bank->getAsset(mtl_id); + if (!material) { + continue; + } + auto shader = m_asset_bank->getAsset(material->getShader()); + if (!shader) { + continue; } - shader->loadInt("light_count", i); - prepared_shaders.emplace(material->getShader()); - } - auto mesh = m_asset_bank->getAsset(rc->mesh); - if (!mesh) { - return; - } + if (!prepared_shaders.contains(material->getShader())) { + shader->bind(); + + shader->loadMat4("projection", camera.getProjection()); + shader->loadMat4("view", view_mat); + + shader->loadFloat3("ambient_light", Eigen::Vector3f(0.1f, 0.1f, 0.1f)); + int i = 0; + for (const auto& e : m_lights) { + auto light = m_registry->getComponent(e); + auto transform = m_registry->getComponent(e); + std::string light_name = (std::string("lights[") + std::to_string(i) + std::string("].")); + shader->loadFloat3((light_name + std::string("position")).c_str(), transform->getPosition()); + shader->loadFloat3((light_name + std::string("rotation")).c_str(), transform->getRotation()); + shader->loadFloat3((light_name + std::string("color")).c_str(), light->color); + shader->loadInt((light_name + std::string("type")).c_str(), static_cast(light->type)); + i++; + } + shader->loadInt("light_count", i); + prepared_shaders.emplace(material->getShader()); + } + + if (!mesh) { + return; + } - std::unordered_map> texs; - for (const auto& [name, value] : material->getAllUniforms()) { - if (std::holds_alternative(value)) { - auto v = std::get(value); - if (auto tex = m_asset_bank->getAsset(v); tex) { - texs.try_emplace(v, tex); + std::unordered_map> texs; + for (const auto& [name, value] : material->getAllUniforms()) { + if (std::holds_alternative(value)) { + auto v = std::get(value); + if (auto tex = m_asset_bank->getAsset(v); tex) { + texs.try_emplace(v, tex); + } } } - } - m_render_commands.push_back(RenderCommand{.mesh = mesh, - .material = material, - .shader = shader, - .textures = texs, - .model_matrix = tc->getModelMatrix(), - .faceCulling = true, - .depthTest = true}); + m_render_commands.push_back(RenderCommand{.mesh = mesh, + .material = material, + .shader = shader, + .textures = texs, + .model_matrix = tc->getModelMatrix(), + .faceCulling = true, + .depthTest = true}); + } } + std::sort(m_render_commands.begin(), m_render_commands.end(), [this](const RenderCommand &a, const RenderCommand &b) { + bool a_transparent = a.material->isTransparent(); + bool b_transparent = b.material->isTransparent(); + + if (!a_transparent && b_transparent) { + return true; + } else { + return false; + } + }); m_geometry_pass.submit(&m_render_commands); } diff --git a/ICE/Graphics/src/GeometryPass.cpp b/ICE/Graphics/src/GeometryPass.cpp index 2bb8b771..36ad1f6e 100644 --- a/ICE/Graphics/src/GeometryPass.cpp +++ b/ICE/Graphics/src/GeometryPass.cpp @@ -13,6 +13,7 @@ void GeometryPass::execute() { std::shared_ptr current_shader; std::shared_ptr current_material; std::shared_ptr current_mesh; + for (const auto& command : *m_render_queue) { auto& shader = command.shader; auto& material = command.material; diff --git a/ICE/Graphics/src/Material.cpp b/ICE/Graphics/src/Material.cpp index 8415e16d..19a5cc84 100644 --- a/ICE/Graphics/src/Material.cpp +++ b/ICE/Graphics/src/Material.cpp @@ -32,8 +32,4 @@ std::string Material::getTypeName() const { AssetType Material::getType() const { return AssetType::EMaterial; } -void Material::load() { -} -void Material::unload() { -} } // namespace ICE \ No newline at end of file diff --git a/ICE/Graphics/src/Mesh.cpp b/ICE/Graphics/src/Mesh.cpp index 921a4c79..ae1b2265 100644 --- a/ICE/Graphics/src/Mesh.cpp +++ b/ICE/Graphics/src/Mesh.cpp @@ -60,8 +60,4 @@ std::string Mesh::getTypeName() const { AssetType Mesh::getType() const { return AssetType::EMesh; } -void Mesh::load() { -} -void Mesh::unload() { -} } // namespace ICE \ No newline at end of file diff --git a/ICE/Graphics/src/Model.cpp b/ICE/Graphics/src/Model.cpp new file mode 100644 index 00000000..0a9ad74f --- /dev/null +++ b/ICE/Graphics/src/Model.cpp @@ -0,0 +1,12 @@ +#include "Model.h" + +namespace ICE { +Model::Model(const std::vector> &meshes, const std::vector &materials) + : m_meshes(meshes), + m_materials(materials) { + for (const auto &mesh : meshes) { + m_boundingbox = m_boundingbox.unionWith(mesh->getBoundingBox()); + } +} + +} // namespace ICE \ No newline at end of file diff --git a/ICE/GraphicsAPI/None/NoneGraphics.h b/ICE/GraphicsAPI/None/NoneGraphics.h index d9ff1e7e..685c2ec7 100644 --- a/ICE/GraphicsAPI/None/NoneGraphics.h +++ b/ICE/GraphicsAPI/None/NoneGraphics.h @@ -75,8 +75,6 @@ class NoneShader : public Shader { void loadMat4(const std::string &name, Eigen::Matrix4f mat) override {} virtual AssetType getType() const override { return AssetType::EShader; } virtual std::string getTypeName() const override { return "Shader"; } - virtual void load() override {} - virtual void unload() override {} }; class NoneTexture2D : public Texture2D { @@ -89,9 +87,6 @@ class NoneTexture2D : public Texture2D { void setData(void *data, uint32_t size) override {} void *getTexture() const override { return nullptr; } TextureType getTextureType() const override { return TextureType::Tex2D; } - - virtual void load() override {} - virtual void unload() override {} }; class NoneTextureCube : public TextureCube { @@ -104,9 +99,6 @@ class NoneTextureCube : public TextureCube { void setData(void *data, uint32_t size) override {} void *getTexture() const override { return nullptr; } TextureType getTextureType() const override { return TextureType::CubeMap; } - - virtual void load() override {} - virtual void unload() override {} }; class NoneVertexArray : public VertexArray { diff --git a/ICE/GraphicsAPI/None/NoneGraphicsFactory.h b/ICE/GraphicsAPI/None/NoneGraphicsFactory.h index 2f940027..2baeac67 100644 --- a/ICE/GraphicsAPI/None/NoneGraphicsFactory.h +++ b/ICE/GraphicsAPI/None/NoneGraphicsFactory.h @@ -36,6 +36,9 @@ class NoneGraphicsFactory : public GraphicsFactory { } std::shared_ptr createTexture2D(const std::string& file) const override { return std::make_shared(); } + std::shared_ptr createTexture2D(const void* data, size_t w, size_t h, TextureFormat fmt) const override { + return std::make_shared(); + } std::shared_ptr createTextureCube(const std::string& file) const override { return std::make_shared(); } }; diff --git a/ICE/GraphicsAPI/OpenGL/include/OpenGLFactory.h b/ICE/GraphicsAPI/OpenGL/include/OpenGLFactory.h index ba4198e7..a7861794 100644 --- a/ICE/GraphicsAPI/OpenGL/include/OpenGLFactory.h +++ b/ICE/GraphicsAPI/OpenGL/include/OpenGLFactory.h @@ -44,6 +44,7 @@ class OpenGLFactory : public GraphicsFactory { } std::shared_ptr createTexture2D(const std::string& file) const override { return std::make_shared(file); } + std::shared_ptr createTexture2D(const void* data, size_t w, size_t h, TextureFormat fmt) const override { return std::make_shared(data, w, h, fmt); } std::shared_ptr createTextureCube(const std::string& file) const override { return std::make_shared(file); } }; diff --git a/ICE/GraphicsAPI/OpenGL/include/OpenGLShader.h b/ICE/GraphicsAPI/OpenGL/include/OpenGLShader.h index dbde0dd2..476605d0 100644 --- a/ICE/GraphicsAPI/OpenGL/include/OpenGLShader.h +++ b/ICE/GraphicsAPI/OpenGL/include/OpenGLShader.h @@ -36,10 +36,6 @@ namespace ICE { OpenGLShader(const std::string &vertexFile, const std::string &fragmentFile); - void load() override {} - - void unload() override {} - private: GLint getLocation(const std::string &name); diff --git a/ICE/GraphicsAPI/OpenGL/include/OpenGLTexture.h b/ICE/GraphicsAPI/OpenGL/include/OpenGLTexture.h index 64142d3c..8753aef4 100644 --- a/ICE/GraphicsAPI/OpenGL/include/OpenGLTexture.h +++ b/ICE/GraphicsAPI/OpenGL/include/OpenGLTexture.h @@ -5,73 +5,72 @@ #ifndef ICE_OPENGLTEXTURE_H #define ICE_OPENGLTEXTURE_H - +#include #include + #include -#include namespace ICE { - class OpenGLTexture2D : public Texture2D { - public: - OpenGLTexture2D(const std::string &file); +class OpenGLTexture2D : public Texture2D { + public: + OpenGLTexture2D(const std::string &file); + OpenGLTexture2D(const void *data, size_t w, size_t h, TextureFormat fmt); + + void bind(uint32_t slot) const override; - void bind(uint32_t slot) const override; + TextureFormat getFormat() const override; - TextureFormat getFormat() const override; + uint32_t getWidth() const override; + uint32_t getHeight() const override; - uint32_t getWidth() const override; - uint32_t getHeight() const override; + TextureWrap getWrap() const override; - TextureWrap getWrap() const override; + void setData(void *data, uint32_t size) override; - void setData(void *data, uint32_t size) override; + void *getTexture() const override; - void *getTexture() const override; + TextureType getTextureType() const override; - TextureType getTextureType() const override; - void load() override {} - void unload() override {} + private: + void loadData(const void *data, size_t w, size_t h, TextureFormat fmt); - private: - std::string file; - uint32_t id; - uint32_t width, height; - TextureFormat format; - TextureWrap wrap; - GLenum storageFormat; - GLenum dataFormat; - }; + std::string file; + uint32_t id; + uint32_t width, height; + TextureFormat format; + TextureWrap wrap; + GLenum storageFormat; + GLenum dataFormat; +}; - class OpenGLTextureCube : public TextureCube { - public: - OpenGLTextureCube(const std::string &file); +class OpenGLTextureCube : public TextureCube { + public: + OpenGLTextureCube(const std::string &file); - void bind(uint32_t slot) const override; + void bind(uint32_t slot) const override; - TextureFormat getFormat() const override; + TextureFormat getFormat() const override; - uint32_t getWidth() const override; - uint32_t getHeight() const override; + uint32_t getWidth() const override; + uint32_t getHeight() const override; - TextureWrap getWrap() const override; + TextureWrap getWrap() const override; - void setData(void *data, uint32_t size) override; + void setData(void *data, uint32_t size) override; - void *getTexture() const override; + void *getTexture() const override; - TextureType getTextureType() const override; - void load() override {} - void unload() override {} - private: - std::string file; - uint32_t id; - uint32_t width, height; - TextureFormat format; - TextureWrap wrap; - GLenum storageFormat; - GLenum dataFormat; - }; -} + TextureType getTextureType() const override; + private: + std::string file; + uint32_t id; + uint32_t width, height; + TextureFormat format; + TextureWrap wrap; + GLenum storageFormat; + GLenum dataFormat; +}; +} // namespace ICE -#endif //ICE_OPENGLTEXTURE_H +#endif //ICE_OPENGLTEXTURE_H diff --git a/ICE/GraphicsAPI/OpenGL/src/OpenGLTexture2D.cpp b/ICE/GraphicsAPI/OpenGL/src/OpenGLTexture2D.cpp index dc6a091e..f121663d 100644 --- a/ICE/GraphicsAPI/OpenGL/src/OpenGLTexture2D.cpp +++ b/ICE/GraphicsAPI/OpenGL/src/OpenGLTexture2D.cpp @@ -2,75 +2,83 @@ // Created by Thomas Ibanez on 22.12.20. // -#include "OpenGLTexture.h" #include #include -namespace ICE { - - OpenGLTexture2D::OpenGLTexture2D(const std::string &file) : file(file) { - int channels, w, h; - void* data = Texture::getDataFromFile(file, &w, &h, &channels); - width = w; - height = h; - storageFormat = GL_RGBA; - dataFormat = GL_RGBA; - if(channels == 4) { - format = TextureFormat::RGBA; - } else if(channels == 3) { - storageFormat = dataFormat = GL_RGB; - format = TextureFormat::RGB; - } - - glGenTextures(1, &id); - glBindTexture(GL_TEXTURE_2D, id); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - - wrap = TextureWrap::Repeat; - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - - glTexImage2D(GL_TEXTURE_2D, 0, storageFormat, width, height, 0, dataFormat, GL_UNSIGNED_BYTE, data); - - stbi_image_free(data); - } - - void OpenGLTexture2D::setData(void *data, uint32_t size) { - uint32_t bpp = (format == TextureFormat::RGBA) ? 4 : 3; - if(size != bpp * width * height) { - throw ICEException("Texture size corrupted"); - } - glTextureSubImage2D(id, 0,0,0, width, height, dataFormat, GL_UNSIGNED_BYTE, data); - } +#include "OpenGLTexture.h" - void OpenGLTexture2D::bind(uint32_t slot) const { - glActiveTexture(GL_TEXTURE0 + slot); - glBindTexture(GL_TEXTURE_2D, id); - } +namespace ICE { - TextureWrap OpenGLTexture2D::getWrap() const { - return wrap; +OpenGLTexture2D::OpenGLTexture2D(const std::string &file) : file(file) { + int channels, w, h; + void *data = Texture::getDataFromFile(file, &w, &h, &channels); + loadData(data, w, h, channels == 4 ? TextureFormat::RGBA : TextureFormat::RGB); + stbi_image_free(data); +} + +OpenGLTexture2D::OpenGLTexture2D(const void *data, size_t w, size_t h, TextureFormat fmt) { + loadData(data, w, h, fmt); +} + +void OpenGLTexture2D::loadData(const void *data, size_t w, size_t h, TextureFormat fmt) { + width = w; + height = h; + storageFormat = GL_RGBA; + dataFormat = GL_RGBA; + if (fmt == TextureFormat::RGBA) { + format = TextureFormat::RGBA; + } else if (fmt == TextureFormat::RGB) { + storageFormat = dataFormat = GL_RGB; + format = TextureFormat::RGB; } - TextureFormat OpenGLTexture2D::getFormat() const { - return format; - } + glGenTextures(1, &id); + glBindTexture(GL_TEXTURE_2D, id); - uint32_t OpenGLTexture2D::getWidth() const { - return width; - } + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - uint32_t OpenGLTexture2D::getHeight() const { - return height; - } + wrap = TextureWrap::Repeat; + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - void *OpenGLTexture2D::getTexture() const { - return static_cast(0)+id; - } + glTexImage2D(GL_TEXTURE_2D, 0, storageFormat, width, height, 0, dataFormat, GL_UNSIGNED_BYTE, data); +} - TextureType OpenGLTexture2D::getTextureType() const { - return TextureType::Tex2D; +void OpenGLTexture2D::setData(void *data, uint32_t size) { + uint32_t bpp = (format == TextureFormat::RGBA) ? 4 : 3; + if (size != bpp * width * height) { + throw ICEException("Texture size corrupted"); } -} \ No newline at end of file + glTextureSubImage2D(id, 0, 0, 0, width, height, dataFormat, GL_UNSIGNED_BYTE, data); +} + +void OpenGLTexture2D::bind(uint32_t slot) const { + glActiveTexture(GL_TEXTURE0 + slot); + glBindTexture(GL_TEXTURE_2D, id); +} + +TextureWrap OpenGLTexture2D::getWrap() const { + return wrap; +} + +TextureFormat OpenGLTexture2D::getFormat() const { + return format; +} + +uint32_t OpenGLTexture2D::getWidth() const { + return width; +} + +uint32_t OpenGLTexture2D::getHeight() const { + return height; +} + +void *OpenGLTexture2D::getTexture() const { + return static_cast(0) + id; +} + +TextureType OpenGLTexture2D::getTextureType() const { + return TextureType::Tex2D; +} +} // namespace ICE \ No newline at end of file diff --git a/ICE/GraphicsAPI/OpenGL/src/OpenGLTextureCube.cpp b/ICE/GraphicsAPI/OpenGL/src/OpenGLTextureCube.cpp index a9ed4f62..faeba6c4 100644 --- a/ICE/GraphicsAPI/OpenGL/src/OpenGLTextureCube.cpp +++ b/ICE/GraphicsAPI/OpenGL/src/OpenGLTextureCube.cpp @@ -1,66 +1,67 @@ // // Created by Thomas Ibanez on 29.12.20. // -#include -#include "OpenGLTexture.h" -#include #include -namespace ICE { +#include - OpenGLTextureCube::OpenGLTextureCube(const std::string &file) { - int channels, w, h; - void* data = Texture::getDataFromFile(file, &w, &h, &channels, STBI_rgb); - width = w; - height = h; +#include "OpenGLTexture.h" - glGenTextures(1, &id); - glBindTexture(GL_TEXTURE_CUBE_MAP, id); +namespace ICE { - auto faces = equirectangularToCubemap((uint8_t*)data, width, height); - for(int i = 0; i < 6; i++) { - glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB, width/4, width/4, 0, GL_RGB, GL_UNSIGNED_BYTE, faces[i]); - } +OpenGLTextureCube::OpenGLTextureCube(const std::string &file) { + int channels, w, h; + void *data = Texture::getDataFromFile(file, &w, &h, &channels, STBI_rgb); + width = w; + height = h; - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); + glGenTextures(1, &id); + glBindTexture(GL_TEXTURE_CUBE_MAP, id); - stbi_image_free(data); + auto faces = equirectangularToCubemap((uint8_t *) data, width, height); + for (int i = 0; i < 6; i++) { + glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB, width / 4, width / 4, 0, GL_RGB, GL_UNSIGNED_BYTE, faces[i]); } - void OpenGLTextureCube::bind(uint32_t slot) const { - glActiveTexture(GL_TEXTURE0 + slot); - glBindTexture(GL_TEXTURE_CUBE_MAP, id); - } + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); - TextureFormat OpenGLTextureCube::getFormat() const { - return TextureFormat::RGB; - } + stbi_image_free(data); +} - uint32_t OpenGLTextureCube::getWidth() const { - return width; - } +void OpenGLTextureCube::bind(uint32_t slot) const { + glActiveTexture(GL_TEXTURE0 + slot); + glBindTexture(GL_TEXTURE_CUBE_MAP, id); +} - uint32_t OpenGLTextureCube::getHeight() const { - return height; - } +TextureFormat OpenGLTextureCube::getFormat() const { + return TextureFormat::RGB; +} - TextureWrap OpenGLTextureCube::getWrap() const { - return TextureWrap::Clamp; - } +uint32_t OpenGLTextureCube::getWidth() const { + return width; +} - void OpenGLTextureCube::setData(void *data, uint32_t size) { - //TODO - } +uint32_t OpenGLTextureCube::getHeight() const { + return height; +} - void *OpenGLTextureCube::getTexture() const { - return static_cast(0)+id; - } +TextureWrap OpenGLTextureCube::getWrap() const { + return TextureWrap::Clamp; +} - TextureType OpenGLTextureCube::getTextureType() const { - return TextureType::CubeMap; - } -} \ No newline at end of file +void OpenGLTextureCube::setData(void *data, uint32_t size) { + //TODO +} + +void *OpenGLTextureCube::getTexture() const { + return static_cast(0) + id; +} + +TextureType OpenGLTextureCube::getTextureType() const { + return TextureType::CubeMap; +} +} // namespace ICE \ No newline at end of file diff --git a/ICE/IO/CMakeLists.txt b/ICE/IO/CMakeLists.txt index e59e2794..0c68baa4 100644 --- a/ICE/IO/CMakeLists.txt +++ b/ICE/IO/CMakeLists.txt @@ -10,7 +10,7 @@ target_sources(${PROJECT_NAME} PRIVATE src/Project.cpp src/MaterialExporter.cpp src/TextureLoader.cpp - src/MeshLoader.cpp + src/ModelLoader.cpp src/ShaderLoader.cpp src/MaterialLoader.cpp ) diff --git a/ICE/IO/include/MeshLoader.h b/ICE/IO/include/MeshLoader.h deleted file mode 100644 index 4983b1ac..00000000 --- a/ICE/IO/include/MeshLoader.h +++ /dev/null @@ -1,19 +0,0 @@ -// -// Created by Thomas Ibanez on 31.07.21. -// - -#pragma once - -#include - -#include "Asset.h" -#include "IAssetLoader.h" -#include "Mesh.h" - -namespace ICE { -class MeshLoader : public IAssetLoader { - public: - MeshLoader(const std::shared_ptr &factory) : IAssetLoader(factory) {} - std::shared_ptr load(const std::vector &file) override; -}; -} // namespace ICE diff --git a/ICE/IO/include/ModelLoader.h b/ICE/IO/include/ModelLoader.h new file mode 100644 index 00000000..5dfd1af9 --- /dev/null +++ b/ICE/IO/include/ModelLoader.h @@ -0,0 +1,35 @@ +// +// Created by Thomas Ibanez on 31.07.21. +// + +#pragma once + +#include +#include + +#include + +#include "Asset.h" +#include "IAssetLoader.h" +#include "Model.h" + +namespace ICE { +class AssetBank; + +class ModelLoader : public IAssetLoader { + public: + ModelLoader(const std::shared_ptr &factory, AssetBank &bank) + : ref_bank(bank), + m_graphics_factory(factory), + IAssetLoader(factory) {} + std::shared_ptr load(const std::vector &file) override; + AssetUID extractMaterial(const aiMaterial *material, const std::string &model_name, const aiScene *scene); + AssetUID extractTexture(const aiMaterial *material, const std::string &tex_path, const aiScene *scene, aiTextureType type); + + private: + Eigen::Vector4f colorToVec(aiColor4D *color); + + AssetBank &ref_bank; + std::shared_ptr m_graphics_factory; +}; +} // namespace ICE diff --git a/ICE/IO/src/MeshLoader.cpp b/ICE/IO/src/MeshLoader.cpp deleted file mode 100644 index bbcb0cf5..00000000 --- a/ICE/IO/src/MeshLoader.cpp +++ /dev/null @@ -1,72 +0,0 @@ -// -// Created by Thomas Ibanez on 31.07.21. -// - -#include "MeshLoader.h" - -#include -#include -#include - -#include -#include - -namespace ICE { -std::shared_ptr MeshLoader::load(const std::vector &file) { - Assimp::Importer importer; - - const aiScene *scene = importer.ReadFile( - file[0].string(), - aiProcess_CalcTangentSpace | aiProcess_Triangulate | aiProcess_JoinIdenticalVertices); - - auto vertices = std::vector(); - auto normals = std::vector(); - auto uvs = std::vector(); - auto indices = std::vector(); - // Loop over faces(polygon) - auto mesh0 = scene->mMeshes[0]; - for (int i = 0; i < mesh0->mNumVertices; i++) { - auto v = mesh0->mVertices[i]; - auto n = mesh0->mNormals[i]; - Eigen::Vector2f uv(0, 0); - if (mesh0->mTextureCoords[0] != nullptr) { - auto uv_file = mesh0->mTextureCoords[0][i]; - uv.x() = uv_file.x; - uv.y() = uv_file.y; - } - vertices.emplace_back(v.x, v.y, v.z); - normals.emplace_back(n.x, n.y, n.z); - uvs.push_back(uv); - } - for (int i = 0; i < mesh0->mNumFaces; i++) { - auto f = mesh0->mFaces[i]; - assert(f.mNumIndices == 3); - indices.emplace_back(f.mIndices[0], f.mIndices[1], f.mIndices[2]); - } - - auto mesh = std::make_shared(vertices, normals, uvs, indices); - - mesh->setSources(file); - - auto vertexArray = graphics_factory->createVertexArray(); - - auto vertexBuffer = graphics_factory->createVertexBuffer(); - auto normalsBuffer = graphics_factory->createVertexBuffer(); - auto uvBuffer = graphics_factory->createVertexBuffer(); - auto indexBuffer = graphics_factory->createIndexBuffer(); - - vertexBuffer->putData(BufferUtils::CreateFloatBuffer(mesh->getVertices()), 3 * mesh->getVertices().size() * sizeof(float)); - normalsBuffer->putData(BufferUtils::CreateFloatBuffer(mesh->getNormals()), 3 * mesh->getNormals().size() * sizeof(float)); - uvBuffer->putData(BufferUtils::CreateFloatBuffer(mesh->getUVCoords()), 2 * mesh->getUVCoords().size() * sizeof(float)); - indexBuffer->putData(BufferUtils::CreateIntBuffer(mesh->getIndices()), 3 * mesh->getIndices().size() * sizeof(int)); - - vertexArray->pushVertexBuffer(vertexBuffer, 3); - vertexArray->pushVertexBuffer(normalsBuffer, 3); - vertexArray->pushVertexBuffer(uvBuffer, 2); - vertexArray->setIndexBuffer(indexBuffer); - - mesh->setVertexArray(vertexArray); - - return mesh; -} -} // namespace ICE diff --git a/ICE/IO/src/ModelLoader.cpp b/ICE/IO/src/ModelLoader.cpp new file mode 100644 index 00000000..b78dd350 --- /dev/null +++ b/ICE/IO/src/ModelLoader.cpp @@ -0,0 +1,177 @@ +// +// Created by Thomas Ibanez on 31.07.21. +// + +#include "ModelLoader.h" + +#include +#include +#include +#include +#include + +#include +#include + +namespace ICE { +std::shared_ptr ModelLoader::load(const std::vector &file) { + Assimp::Importer importer; + + const aiScene *scene = importer.ReadFile(file[0].string(), + aiProcess_PreTransformVertices | aiProcess_FlipUVs | aiProcess_ValidateDataStructure | aiProcess_SortByPType | aiProcess_GenSmoothNormals + | aiProcess_CalcTangentSpace | aiProcess_Triangulate); + + std::vector> meshes; + std::vector materials; + + for (int m = 0; m < scene->mNumMeshes; m++) { + auto vertices = std::vector(); + auto normals = std::vector(); + auto uvs = std::vector(); + auto indices = std::vector(); + // Loop over faces(polygon) + auto mesh = scene->mMeshes[m]; + auto material = scene->mMaterials[mesh->mMaterialIndex]; + + materials.push_back(extractMaterial(material, file[0].filename().stem().string(), scene)); + + for (int i = 0; i < mesh->mNumVertices; i++) { + auto v = mesh->mVertices[i]; + auto n = mesh->mNormals ? mesh->mNormals[i] : aiVector3D{0, 0, 0}; + Eigen::Vector2f uv(0, 0); + if (mesh->mTextureCoords[0] != nullptr) { + auto uv_file = mesh->mTextureCoords[0][i]; + uv.x() = uv_file.x; + uv.y() = uv_file.y; + } + vertices.emplace_back(v.x, v.y, v.z); + normals.emplace_back(n.x, n.y, n.z); + uvs.push_back(uv); + } + for (int i = 0; i < mesh->mNumFaces; i++) { + auto f = mesh->mFaces[i]; + assert(f.mNumIndices == 3); + indices.emplace_back(f.mIndices[0], f.mIndices[1], f.mIndices[2]); + } + + meshes.push_back(std::make_shared(vertices, normals, uvs, indices)); + + meshes.back()->setSources(file); + + auto vertexArray = graphics_factory->createVertexArray(); + + auto vertexBuffer = graphics_factory->createVertexBuffer(); + auto normalsBuffer = graphics_factory->createVertexBuffer(); + auto uvBuffer = graphics_factory->createVertexBuffer(); + auto indexBuffer = graphics_factory->createIndexBuffer(); + + vertexBuffer->putData(BufferUtils::CreateFloatBuffer(meshes.back()->getVertices()), 3 * meshes.back()->getVertices().size() * sizeof(float)); + normalsBuffer->putData(BufferUtils::CreateFloatBuffer(meshes.back()->getNormals()), 3 * meshes.back()->getNormals().size() * sizeof(float)); + uvBuffer->putData(BufferUtils::CreateFloatBuffer(meshes.back()->getUVCoords()), 2 * meshes.back()->getUVCoords().size() * sizeof(float)); + indexBuffer->putData(BufferUtils::CreateIntBuffer(meshes.back()->getIndices()), 3 * meshes.back()->getIndices().size() * sizeof(int)); + + vertexArray->pushVertexBuffer(vertexBuffer, 3); + vertexArray->pushVertexBuffer(normalsBuffer, 3); + vertexArray->pushVertexBuffer(uvBuffer, 2); + vertexArray->setIndexBuffer(indexBuffer); + + meshes.back()->setVertexArray(vertexArray); + } + auto model = std::make_shared(meshes, materials); + model->setSources(file); + return model; +} + +AssetUID ModelLoader::extractMaterial(const aiMaterial *material, const std::string &model_name, const aiScene *scene) { + auto mtl_name = material->GetName(); + if (mtl_name.length == 0) { + mtl_name = "DefaultMat"; + } + auto bank_name = model_name + "/" + mtl_name.C_Str(); + auto mtl = std::make_shared(); + mtl->setUniform("material.use_diffuse_map", false); + mtl->setUniform("material.use_ambient_map", false); + mtl->setUniform("material.use_specular_map", false); + mtl->setUniform("material.use_normal_map", false); + if (auto ambient_map = extractTexture(material, bank_name + "/ambient_map", scene, aiTextureType_AMBIENT); ambient_map != 0) { + mtl->setUniform("material.ambient_map", ambient_map); + mtl->setUniform("material.use_ambient_map", true); + } + if (auto diffuse_tex = extractTexture(material, bank_name + "/diffuse_map", scene, aiTextureType_DIFFUSE); diffuse_tex != 0) { + mtl->setUniform("material.diffuse_map", diffuse_tex); + mtl->setUniform("material.use_diffuse_map", true); + } + if (auto specular_tex = extractTexture(material, bank_name + "/specular_map", scene, aiTextureType_SPECULAR); specular_tex != 0) { + mtl->setUniform("material.specular_map", specular_tex); + mtl->setUniform("material.use_specular_map", true); + } + if (auto normal_tex = extractTexture(material, bank_name + "/normal_map", scene, aiTextureType_NORMALS); normal_tex != 0) { + mtl->setUniform("material.normal_map", normal_tex); + mtl->setUniform("material.use_normal_map", true); + } + + if (ref_bank.getUID(AssetPath::WithTypePrefix(bank_name)) != 0) { + return ref_bank.getUID(AssetPath::WithTypePrefix(bank_name)); + } + mtl->setShader(ref_bank.getUID(AssetPath::WithTypePrefix("phong"))); + + aiColor4D diffuse; + aiColor4D specular; + aiColor4D ambient; + ai_real alpha = 1.0; + + if (aiGetMaterialColor(material, AI_MATKEY_COLOR_DIFFUSE, &diffuse) == aiReturn_SUCCESS) + mtl->setUniform("material.albedo", colorToVec(&diffuse)); + if (aiGetMaterialColor(material, AI_MATKEY_COLOR_SPECULAR, &specular) == aiReturn_SUCCESS) + mtl->setUniform("material.specular", colorToVec(&specular)); + if (aiGetMaterialColor(material, AI_MATKEY_COLOR_AMBIENT, &ambient) == aiReturn_SUCCESS) + mtl->setUniform("material.ambient", colorToVec(&ambient)); + if (aiGetMaterialFloat(material, AI_MATKEY_SHININESS, &alpha) == aiReturn_SUCCESS) + mtl->setUniform("material.alpha", std::max(alpha, 1.0f)); + + ref_bank.addAsset(bank_name, mtl); + return ref_bank.getUID(AssetPath::WithTypePrefix(bank_name)); +} + +AssetUID ModelLoader::extractTexture(const aiMaterial *material, const std::string &tex_path, const aiScene *scene, aiTextureType type) { + AssetUID tex_id = 0; + aiString texture_file; + if (material->Get(AI_MATKEY_TEXTURE(type, 0), texture_file) == aiReturn_SUCCESS) { + if (auto texture = scene->GetEmbeddedTexture(texture_file.C_Str())) { + unsigned char *data = reinterpret_cast(texture->pcData); + void *data2 = nullptr; + int width = texture->mWidth; + int height = texture->mHeight; + int channels = 0; + if (height == 0) { + //Compressed memory, use stbi to load + data2 = stbi_load_from_memory(data, texture->mWidth, &width, &height, &channels, 4); + } else { + data2 = data; + } + auto texture_ice = m_graphics_factory->createTexture2D(data2, width, height, TextureFormat::RGBA); + if (tex_id = ref_bank.getUID(AssetPath::WithTypePrefix(tex_path)); tex_id != 0) { + ref_bank.removeAsset(AssetPath::WithTypePrefix(tex_path)); + ref_bank.addAssetWithSpecificUID(AssetPath::WithTypePrefix(tex_path), texture_ice, tex_id); + } else { + ref_bank.addAsset(tex_path, texture_ice); + tex_id = ref_bank.getUID(AssetPath::WithTypePrefix(tex_path)); + } + } else { + //regular file, check if it exists and read it + //TODO :) + } + } + return tex_id; +} + +Eigen::Vector4f ModelLoader::colorToVec(aiColor4D *color) { + Eigen::Vector4f v; + v.x() = color->r; + v.y() = color->g; + v.z() = color->b; + v.w() = color->a; + return v; +} + +} // namespace ICE diff --git a/ICE/IO/src/Project.cpp b/ICE/IO/src/Project.cpp index 71c9c2a3..397fb3dc 100644 --- a/ICE/IO/src/Project.cpp +++ b/ICE/IO/src/Project.cpp @@ -29,7 +29,7 @@ Project::Project(const fs::path &base_directory, const std::string &name) m_shaders_directory = m_base_directory / assets_folder / "Shaders"; m_textures_directory = m_base_directory / assets_folder / "Textures"; m_cubemaps_directory = m_base_directory / assets_folder / "Cubemaps"; - m_meshes_directory = m_base_directory / assets_folder / "Meshes"; + m_meshes_directory = m_base_directory / assets_folder / "Models"; m_scenes_directory = m_base_directory / "Scenes"; } @@ -41,8 +41,8 @@ bool Project::CreateDirectories() { fs::create_directories(m_meshes_directory); fs::create_directories(m_scenes_directory); - copyAssetFile("Meshes", "cube", "Assets/Meshes/cube.obj"); - copyAssetFile("Meshes", "sphere", "Assets/Meshes/sphere.obj"); + copyAssetFile("Models", "cube", "Assets/Models/cube.obj"); + copyAssetFile("Models", "sphere", "Assets/Models/sphere.obj"); copyAssetFile("Shaders", "phong", "Assets/Shaders/phong.vs"); copyAssetFile("Shaders", "phong", "Assets/Shaders/phong.fs"); copyAssetFile("Shaders", "solid", "Assets/Shaders/solid.vs"); @@ -56,16 +56,19 @@ bool Project::CreateDirectories() { copyAssetFile("Cubemaps", "skybox", "Assets/Textures/skybox.png"); copyAssetFile("Materials", "base_mat", "Assets/Materials/base_mat.icm"); - assetBank->addAsset("cube", {m_meshes_directory / "cube.obj"}); - assetBank->addAsset("sphere", {m_meshes_directory / "sphere.obj"}); assetBank->addAsset("solid", {m_shaders_directory / "solid.vs", m_shaders_directory / "solid.fs"}); assetBank->addAsset("phong", {m_shaders_directory / "phong.vs", m_shaders_directory / "phong.fs"}); assetBank->addAsset("normal", {m_shaders_directory / "normal.vs", m_shaders_directory / "normal.fs"}); assetBank->addAsset("lastpass", {m_shaders_directory / "lastpass.vs", m_shaders_directory / "lastpass.fs"}); assetBank->addAsset("__ice__picking_shader", {m_shaders_directory / "picking.vs", m_shaders_directory / "picking.fs"}); + assetBank->addAsset("skybox", {m_cubemaps_directory / "skybox.png"}); + assetBank->addAsset("base_mat", {m_materials_directory / "base_mat.icm"}); + assetBank->addAsset("cube", {m_meshes_directory / "cube.obj"}); + assetBank->addAsset("sphere", {m_meshes_directory / "sphere.obj"}); + scenes.push_back(std::make_shared("MainScene")); setCurrentScene(getScenes()[0]); return true; @@ -94,15 +97,17 @@ void Project::writeToFile(const std::shared_ptr &editorCamera) { j["scenes"] = vec; vec.clear(); - for (const auto &[asset_id, mesh] : assetBank->getAll()) { + for (const auto &[asset_id, mesh] : assetBank->getAll()) { vec.push_back(dumpAsset(asset_id, mesh)); } - j["meshes"] = vec; + j["models"] = vec; vec.clear(); for (const auto &[asset_id, material] : assetBank->getAll()) { auto mtlName = assetBank->getName(asset_id).getName(); - fs::path path = m_materials_directory / (mtlName + ".icm"); + + fs::path path = m_materials_directory.parent_path() / (assetBank->getName(asset_id).prefix() + mtlName + ".icm"); + fs::create_directories(path.parent_path()); MaterialExporter().writeToJson(path, *material); material->setSources({path}); @@ -147,8 +152,7 @@ void Project::writeToFile(const std::shared_ptr &editorCamera) { if (s->getRegistry()->entityHasComponent(e)) { RenderComponent rc = *s->getRegistry()->getComponent(e); json renderjson; - renderjson["mesh"] = rc.mesh; - renderjson["material"] = rc.material; + renderjson["model"] = rc.model; entity["renderComponent"] = renderjson; } if (s->getRegistry()->entityHasComponent(e)) { @@ -196,7 +200,7 @@ void Project::loadFromFile() { infile.close(); std::vector sceneNames = j["scenes"]; - json meshes = j["meshes"]; + json meshes = j["models"]; json material = j["materials"]; json shader = j["shaders"]; json texture = j["textures2D"]; @@ -205,11 +209,11 @@ void Project::loadFromFile() { cameraPosition = JsonParser::parseVec3(j["camera_position"]); cameraRotation = JsonParser::parseVec3(j["camera_rotation"]); + loadAssetsOfType(shader); loadAssetsOfType(texture); loadAssetsOfType(cubeMap); - loadAssetsOfType(meshes); loadAssetsOfType(material); - loadAssetsOfType(shader); + loadAssetsOfType(meshes); for (const auto &s : sceneNames) { infile = std::ifstream(m_scenes_directory / (s + ".ics")); @@ -234,12 +238,12 @@ void Project::loadFromFile() { } if (!jentity["renderComponent"].is_null()) { json rj = jentity["renderComponent"]; - RenderComponent rc(rj["mesh"], rj["material"]); + RenderComponent rc(rj["model"]); scene.getRegistry()->addComponent(e, rc); } if (!jentity["lightComponent"].is_null()) { json lj = jentity["lightComponent"]; - LightComponent lc(static_cast((int)lj["type"]), JsonParser::parseVec3(lj["color"])); + LightComponent lc(static_cast((int) lj["type"]), JsonParser::parseVec3(lj["color"])); scene.getRegistry()->addComponent(e, lc); } } diff --git a/ICE/IO/src/TextureLoader.cpp b/ICE/IO/src/TextureLoader.cpp index 33ca33e5..c8296322 100644 --- a/ICE/IO/src/TextureLoader.cpp +++ b/ICE/IO/src/TextureLoader.cpp @@ -4,12 +4,15 @@ #include "TextureLoader.h" -#include #include +#include namespace ICE { std::shared_ptr Texture2DLoader::load(const std::vector &file) { Logger::Log(Logger::VERBOSE, "IO", "Loading texture..."); + if (file.empty()) { + return nullptr; + } auto texture = graphics_factory->createTexture2D(file[0].string()); texture->setSources(file); return texture; diff --git a/ICE/IO/test/CMakeLists.txt b/ICE/IO/test/CMakeLists.txt index 7a439130..e7b0bb2e 100644 --- a/ICE/IO/test/CMakeLists.txt +++ b/ICE/IO/test/CMakeLists.txt @@ -18,23 +18,23 @@ target_link_libraries(MaterialsTestSuite gtest_main io) -add_executable(MeshLoaderTestSuite - MeshLoaderTest.cpp +add_executable(ModelLoaderTestSuite + ModelLoaderTest.cpp ) -add_test(NAME MeshLoaderTestSuite - COMMAND MeshLoaderTestSuite - WORKING_DIRECTORY $) +add_test(NAME ModelLoaderTestSuite + COMMAND ModelLoaderTestSuite + WORKING_DIRECTORY $) -target_link_libraries(MeshLoaderTestSuite +target_link_libraries(ModelLoaderTestSuite PRIVATE gtest_main io) add_custom_command( - TARGET MeshLoaderTestSuite POST_BUILD + TARGET ModelLoaderTestSuite POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/cube.obj" - $ + $ ) diff --git a/ICE/IO/test/MeshLoaderTest.cpp b/ICE/IO/test/MeshLoaderTest.cpp deleted file mode 100644 index 5fe47926..00000000 --- a/ICE/IO/test/MeshLoaderTest.cpp +++ /dev/null @@ -1,13 +0,0 @@ -#include -#include - -#include "MeshLoader.h" - -using namespace ICE; - -TEST(MeshLoaderTest, LoadFromObj) { - auto gr_f = std::make_shared(); - auto mesh = MeshLoader(gr_f).load({"cube.obj"}); - EXPECT_EQ(mesh->getVertices().size(), 24); - EXPECT_EQ(mesh->getIndices().size(), 12); -} \ No newline at end of file diff --git a/ICE/IO/test/ModelLoaderTest.cpp b/ICE/IO/test/ModelLoaderTest.cpp new file mode 100644 index 00000000..6316aa42 --- /dev/null +++ b/ICE/IO/test/ModelLoaderTest.cpp @@ -0,0 +1,17 @@ +#define STB_IMAGE_IMPLEMENTATION + +#include +#include +#include + +#include "ModelLoader.h" + +using namespace ICE; + +TEST(ModelLoaderTest, LoadFromObj) { + auto gr_f = std::make_shared(); + AssetBank bank(gr_f); + auto mesh = ModelLoader(gr_f, bank).load({"cube.obj"}); + EXPECT_EQ(mesh->getMeshes().at(0)->getVertices().size(), 36); + EXPECT_EQ(mesh->getMeshes().at(0)->getIndices().size(), 12); +} \ No newline at end of file diff --git a/ICE/Math/include/AABB.h b/ICE/Math/include/AABB.h index d7405e03..8f44ec29 100644 --- a/ICE/Math/include/AABB.h +++ b/ICE/Math/include/AABB.h @@ -14,6 +14,8 @@ namespace ICE { AABB(const Eigen::Vector3f& min, const Eigen::Vector3f& max); AABB(const std::vector& points); + AABB scaledBy(const Eigen::Vector3f& scale) const; + AABB translatedBy(const Eigen::Vector3f& tr) const; float getVolume() const; bool overlaps(const AABB& other) const; bool contains(const Eigen::Vector3f& point) const; diff --git a/ICE/Math/include/ICEMath.h b/ICE/Math/include/ICEMath.h index bf829c7a..aef5a91e 100644 --- a/ICE/Math/include/ICEMath.h +++ b/ICE/Math/include/ICEMath.h @@ -10,6 +10,8 @@ #include #include +#include "AABB.h" + #define DEG_TO_RAD(x) ((x) * M_PI / 180.0) #define RAD_TO_DEG(x) ((x) * 180.0 / M_PI) @@ -30,6 +32,8 @@ Eigen::Matrix4f transformationMatrix(const Eigen::Vector3f &translation, const E Eigen::Vector3f orientation(int face, float x, float y); int clamp(int x, int a, int b); std::array equirectangularToCubemap(uint8_t *inputPixels, int width, int height, float rotation = 180); +std::array extractFrustumPlanes(const Eigen::Matrix4f &PV); +bool isAABBInFrustum(const std::array &frustum, const AABB &aabb); } // namespace ICE #endif //ICE_ICEMATH_H diff --git a/ICE/Math/src/AABB.cpp b/ICE/Math/src/AABB.cpp index f486b8d2..c2c93f3e 100644 --- a/ICE/Math/src/AABB.cpp +++ b/ICE/Math/src/AABB.cpp @@ -6,47 +6,52 @@ namespace ICE { - AABB::AABB(const Eigen::Vector3f &min, const Eigen::Vector3f &max) : min(min), max(max) {} - AABB::AABB(const std::vector& points) : AABB(points[0], points[0]) { - for(auto v : points) { - min = min.cwiseMin(v); - max = max.cwiseMax(v); - } - } - - float AABB::getVolume() const { - return (max.x() - min.x()) * (max.y() - min.y()) * (max.z() - min.z()); - } - - bool AABB::overlaps(const AABB &other) const { - return (min.x() <= other.max.x() && max.x() >= other.min.x()) && - (min.y() <= other.max.y() && max.y() >= other.min.y()) && - (min.z() <= other.max.z() && max.z() >= other.min.z()); - } - - bool AABB::contains(const Eigen::Vector3f &point) const { - return (point.x() >= min.x() && point.x() <= max.x()) && - (point.y() >= min.y() && point.y() <= max.y()) && - (point.z() >= min.z() && point.z() <= max.z()); - } - - AABB AABB::operator+(const AABB &other) const { - return unionWith(other); - } - - AABB AABB::unionWith(const AABB &other) const { - return AABB(min.cwiseMin(other.min), max.cwiseMax(other.max)); - } - - Eigen::Vector3f AABB::getCenter() const { - return (min + max) / 2; - } - - const Eigen::Vector3f &AABB::getMin() const { - return min; - } - - const Eigen::Vector3f &AABB::getMax() const { - return max; - } -} \ No newline at end of file +AABB::AABB(const Eigen::Vector3f &min, const Eigen::Vector3f &max) : min(min), max(max) { +} +AABB::AABB(const std::vector &points) : AABB(points[0], points[0]) { + for (auto v : points) { + min = min.cwiseMin(v); + max = max.cwiseMax(v); + } +} + +AABB AABB::scaledBy(const Eigen::Vector3f &scale) const { + return AABB(min.cwiseProduct(scale), max.cwiseProduct(scale)); +} +AABB AABB::translatedBy(const Eigen::Vector3f &tr) const { + return AABB(min + tr, max + tr); +} +float AABB::getVolume() const { + return (max.x() - min.x()) * (max.y() - min.y()) * (max.z() - min.z()); +} + +bool AABB::overlaps(const AABB &other) const { + return (min.x() <= other.max.x() && max.x() >= other.min.x()) && (min.y() <= other.max.y() && max.y() >= other.min.y()) + && (min.z() <= other.max.z() && max.z() >= other.min.z()); +} + +bool AABB::contains(const Eigen::Vector3f &point) const { + return (point.x() >= min.x() && point.x() <= max.x()) && (point.y() >= min.y() && point.y() <= max.y()) + && (point.z() >= min.z() && point.z() <= max.z()); +} + +AABB AABB::operator+(const AABB &other) const { + return unionWith(other); +} + +AABB AABB::unionWith(const AABB &other) const { + return AABB(min.cwiseMin(other.min), max.cwiseMax(other.max)); +} + +Eigen::Vector3f AABB::getCenter() const { + return (min + max) / 2; +} + +const Eigen::Vector3f &AABB::getMin() const { + return min; +} + +const Eigen::Vector3f &AABB::getMax() const { + return max; +} +} // namespace ICE \ No newline at end of file diff --git a/ICE/Math/src/ICEMath.cpp b/ICE/Math/src/ICEMath.cpp index ae47648a..13fd4a1c 100644 --- a/ICE/Math/src/ICEMath.cpp +++ b/ICE/Math/src/ICEMath.cpp @@ -29,7 +29,7 @@ Eigen::Matrix4f rotationMatrix(Eigen::Vector3f angles, bool yaw_first) { mz(1, 0) = sinf(rz); mz(1, 1) = cosf(rz); - if(yaw_first) { + if (yaw_first) { return my * mx * mz; } else { return mx * my * mz; @@ -125,4 +125,42 @@ std::array equirectangularToCubemap(uint8_t *inputPixels, int widt } return outputPixels; } + +std::array extractFrustumPlanes(const Eigen::Matrix4f &PV) { + std::array planes; + // Left + planes[0] = {PV(3, 0) + PV(0, 0), PV(3, 1) + PV(0, 1), PV(3, 2) + PV(0, 2), PV(3, 3) + PV(0, 3)}; + // Right + planes[1] = {PV(3, 0) - PV(0, 0), PV(3, 1) - PV(0, 1), PV(3, 2) - PV(0, 2), PV(3, 3) - PV(0, 3)}; + // Bottom + planes[2] = {PV(3, 0) + PV(1, 0), PV(3, 1) + PV(1, 1), PV(3, 2) + PV(1, 2), PV(3, 3) + PV(1, 3)}; + // Top + planes[3] = {PV(3, 0) - PV(1, 0), PV(3, 1) - PV(1, 1), PV(3, 2) - PV(1, 2), PV(3, 3) - PV(1, 3)}; + // Near + planes[4] = {PV(3, 0) + PV(2, 0), PV(3, 1) + PV(2, 1), PV(3, 2) + PV(2, 2), PV(3, 3) + PV(2, 3)}; + // Far + planes[5] = {PV(3, 0) - PV(2, 0), PV(3, 1) - PV(2, 1), PV(3, 2) - PV(2, 2), PV(3, 3) - PV(2, 3)}; + // Normalize planes + for (int i = 0; i < 6; i++) { + float length = sqrt(planes[i](0) * planes[i](0) + planes[i](1) * planes[i](1) + planes[i](2) * planes[i](2)); + planes[i](0) /= length; + planes[i](1) /= length; + planes[i](2) /= length; + planes[i](3) /= length; + } + return planes; +} + +bool isAABBInFrustum(const std::array &frustum, const AABB &aabb) { + for (int i = 0; i < 6; i++) { + Eigen::Vector3f positive(frustum[i](0) >= 0 ? aabb.getMax().x() : aabb.getMin().x(), + frustum[i](1) >= 0 ? aabb.getMax().y() : aabb.getMin().y(), + frustum[i](2) >= 0 ? aabb.getMax().z() : aabb.getMin().z()); + + if (frustum[i](0) * positive.x() + frustum[i](1) * positive.y() + frustum[i](2) * positive.z() + frustum[i](3) < 0) { + return false; + } + } + return true; +} } // namespace ICE diff --git a/ICEBERG/UI/AddComponentPopup.h b/ICEBERG/UI/AddComponentPopup.h index 48e55742..92b85627 100644 --- a/ICEBERG/UI/AddComponentPopup.h +++ b/ICEBERG/UI/AddComponentPopup.h @@ -35,7 +35,7 @@ class AddComponentPopup { m_components_combo.render(); if (ImGui::Button("Add")) { if(m_components_combo.getSelectedItem() == "Render Component") - m_registry->addComponent(m_entity, ICE::RenderComponent(0, 0)); + m_registry->addComponent(m_entity, ICE::RenderComponent(0)); if(m_components_combo.getSelectedItem() == "Light Component") m_registry->addComponent(m_entity, ICE::LightComponent(ICE::PointLight, Eigen::Vector3f(1, 1, 1))); diff --git a/ICEBERG/UI/AssetsWidget.h b/ICEBERG/UI/AssetsWidget.h index 9474c3f3..ab500c93 100644 --- a/ICEBERG/UI/AssetsWidget.h +++ b/ICEBERG/UI/AssetsWidget.h @@ -37,6 +37,7 @@ class AssetsWidget : public Widget { if (ImGui::Selectable(asset->folder_name.c_str(), i == m_selected_index)) { m_selected_index = i; m_current_view = m_assets[i]; + m_prefix = ""; } } ImGui::EndTable(); @@ -51,6 +52,7 @@ class AssetsWidget : public Widget { ImGui::Text(folder->folder_name.c_str()); if (ImGui::IsItemHovered() && ImGui::IsMouseDoubleClicked(0)) { m_current_view = folder; + m_prefix += folder->folder_name+"/"; } } @@ -64,7 +66,7 @@ class AssetsWidget : public Widget { ImGui::EndGroup(); if (m_assets[m_selected_index]->folder_name == "Materials") { if (ImGui::IsItemHovered() && ImGui::IsMouseDoubleClicked(0)) { - callback("material_edit", name); + callback("material_edit", m_prefix+name); } } if (ImGui::BeginPopupContextItem((name + "_material_context").c_str())) { @@ -106,10 +108,12 @@ class AssetsWidget : public Widget { m_assets.clear(); m_current_view = nullptr; m_selected_index = 0; + m_prefix = ""; } private: std::vector> m_assets; int m_selected_index = 0; std::shared_ptr m_current_view = nullptr; + std::string m_prefix; }; diff --git a/ICEBERG/UI/InspectorWidget.h b/ICEBERG/UI/InspectorWidget.h index 24379213..902d27ae 100644 --- a/ICEBERG/UI/InspectorWidget.h +++ b/ICEBERG/UI/InspectorWidget.h @@ -85,21 +85,15 @@ class InspectorWidget : public Widget { } } - void setRenderComponent(ICE::RenderComponent* rc, const std::vector& meshes_paths, const std::vector& meshes_ids, - const std::vector& materials_paths, const std::vector& materials_ids) { + void setRenderComponent(ICE::RenderComponent* rc, const std::vector& meshes_paths, const std::vector& meshes_ids) { m_rc = rc; m_rc_inputs.clear(); if (rc) { m_rc_inputs.reserve(2); - UniformInputs in_mesh("Mesh", rc->mesh); - in_mesh.onValueChanged([this](const ICE::UniformValue& v) { m_rc->mesh = std::get(v); }); + UniformInputs in_mesh("Mesh", rc->model); + in_mesh.onValueChanged([this](const ICE::UniformValue& v) { m_rc->model = std::get(v); }); in_mesh.setAssetComboList(meshes_paths, meshes_ids); m_rc_inputs.push_back(in_mesh); - - UniformInputs in_mat("Material", rc->material); - in_mat.onValueChanged([this](const ICE::UniformValue& v) { m_rc->material = std::get(v); }); - in_mat.setAssetComboList(materials_paths, materials_ids); - m_rc_inputs.push_back(in_mat); } } diff --git a/ICEBERG/UI/NewMaterialWidget.h b/ICEBERG/UI/NewMaterialWidget.h index a04b930c..ece39eaa 100644 --- a/ICEBERG/UI/NewMaterialWidget.h +++ b/ICEBERG/UI/NewMaterialWidget.h @@ -62,8 +62,8 @@ class NewMaterialWidget : public Widget { } ImGui::SameLine(); if (ImGui::Button("Apply")) { - auto rename_ok = m_engine->getAssetBank()->renameAsset(m_engine->getAssetBank()->getName(m_id), - ICE::AssetPath::WithTypePrefix(m_name)); + auto new_name = m_engine->getAssetBank()->getName(m_id).prefix() + m_name; + auto rename_ok = m_engine->getAssetBank()->renameAsset(m_engine->getAssetBank()->getName(m_id), new_name); if (rename_ok) { m_accepted = true; ImGui::CloseCurrentPopup(); @@ -168,31 +168,40 @@ class NewMaterialWidget : public Widget { } void* renderPreview() { - auto preview_framebuffer = m_engine->getGraphicsFactory()->createFramebuffer({256, 256, 1}); - ICE::Scene s("preview_scene"); + auto model_uid = m_engine->getAssetBank()->getUID(ICE::AssetPath::WithTypePrefix("sphere")); - auto render_system = std::make_shared(); - render_system->setRenderer( - std::make_shared(m_engine->getApi(), m_engine->getGraphicsFactory(), s.getRegistry(), m_engine->getAssetBank())); + auto model = m_engine->getAssetBank()->getAsset(model_uid); + auto shader = m_engine->getAssetBank()->getAsset(m_material->getShader()); auto camera = std::make_shared(60.0, 1.0, 0.01, 10000.0); camera->backward(2); camera->up(1); camera->pitch(-30); - render_system->setCamera(camera); - render_system->setViewport(0, 0, 256, 256); - s.getRegistry()->addSystem(render_system); - - auto entity = s.createEntity(); - auto mesh_uid = m_engine->getAssetBank()->getUID(ICE::AssetPath("Meshes/sphere")); - - s.getRegistry()->addComponent(entity, ICE::RenderComponent(mesh_uid, m_id)); - s.getRegistry()->addComponent(entity, ICE::TransformComponent({0, 0, 0}, {0, 45, 0}, {1, 1, 1})); - render_system->setTarget(preview_framebuffer); - render_system->update(1.0f); + shader->bind(); + shader->loadMat4("projection", camera->getProjection()); + shader->loadMat4("view", camera->lookThrough()); + + ICE::GeometryPass pass(m_engine->getApi(), m_engine->getGraphicsFactory(), {256, 256, 1}); + std::vector cmds; + std::unordered_map> textures; + for (const auto& [k, v] : m_material->getAllUniforms()) { + if (std::holds_alternative(v)) { + auto id = std::get(v); + textures.try_emplace(id, m_engine->getAssetBank()->getAsset(id)); + } + } + for (const auto& mesh : model->getMeshes()) { + cmds.push_back(ICE::RenderCommand{.mesh = mesh, + .material = m_material, + .shader = shader, + .textures = textures, + .model_matrix = Eigen::Matrix4f::Identity()}); + } + pass.submit(&cmds); + pass.execute(); - return static_cast(0) + preview_framebuffer->getTexture(); + return static_cast(0) + pass.getResult()->getTexture(); } bool accepted() { diff --git a/ICEBERG/src/Assets.cpp b/ICEBERG/src/Assets.cpp index cf302c80..45a3653e 100644 --- a/ICEBERG/src/Assets.cpp +++ b/ICEBERG/src/Assets.cpp @@ -27,40 +27,52 @@ void* Assets::createThumbnail(const ICE::AssetBankEntry& entry) { if (auto m = std::dynamic_pointer_cast(asset); m) { return m->getTexture(); } - auto preview_framebuffer = m_g_factory->createFramebuffer({256, 256, 1}); - ICE::Scene s("preview_scene"); - auto render_system = std::make_shared(); - render_system->setRenderer(std::make_shared(m_engine->getApi(), m_g_factory, s.getRegistry(), m_engine->getAssetBank())); - - auto camera = std::make_shared(60.0, 1.0, 0.01, 10000.0); - camera->backward(2); - camera->up(1); - camera->pitch(-30); - render_system->setCamera(camera); - render_system->setViewport(0, 0, 256, 256); - s.getRegistry()->addSystem(render_system); - - auto entity = s.createEntity(); - auto mesh_uid = m_engine->getAssetBank()->getUID(ICE::AssetPath("Meshes/sphere")); + auto model_uid = m_engine->getAssetBank()->getUID(ICE::AssetPath::WithTypePrefix("sphere")); auto material_uid = m_engine->getAssetBank()->getUID(ICE::AssetPath("Materials/base_mat")); auto self_uid = m_engine->getAssetBank()->getUID(entry.path); - if (auto m = std::dynamic_pointer_cast(asset); m) { - mesh_uid = self_uid; + if (auto m = std::dynamic_pointer_cast(asset); m) { + model_uid = self_uid; } else if (auto m = std::dynamic_pointer_cast(asset); m) { material_uid = self_uid; } else { //TODO return default icons return nullptr; } + auto model = m_engine->getAssetBank()->getAsset(model_uid); + auto material = m_engine->getAssetBank()->getAsset(material_uid); + auto shader = m_engine->getAssetBank()->getAsset(material->getShader()); - s.getRegistry()->addComponent(entity, ICE::RenderComponent(mesh_uid, material_uid)); - s.getRegistry()->addComponent(entity, ICE::TransformComponent({0, 0, 0}, {0, 45, 0}, {1, 1, 1})); - render_system->setTarget(preview_framebuffer); - render_system->update(1.0f); + auto camera = std::make_shared(60.0, 1.0, 0.01, 10000.0); + camera->backward(2); + camera->up(1); + camera->pitch(-30); + + shader->bind(); + shader->loadMat4("projection", camera->getProjection()); + shader->loadMat4("view", camera->lookThrough()); + + ICE::GeometryPass pass(m_engine->getApi(), m_engine->getGraphicsFactory(), {256, 256, 1}); + std::vector cmds; + std::unordered_map> textures; + for (const auto& [k, v] : material->getAllUniforms()) { + if (std::holds_alternative(v)) { + auto id = std::get(v); + textures.try_emplace(id, m_engine->getAssetBank()->getAsset(id)); + } + } + for (const auto& mesh : model->getMeshes()) { + cmds.push_back(ICE::RenderCommand{.mesh = mesh, + .material = material, + .shader = shader, + .textures = textures, + .model_matrix = Eigen::Matrix4f::Identity()}); + } + pass.submit(&cmds); + pass.execute(); - return static_cast(0) + preview_framebuffer->getTexture(); + return static_cast(0) + pass.getResult()->getTexture(); } void Assets::rebuildViewer() { diff --git a/ICEBERG/src/Editor.cpp b/ICEBERG/src/Editor.cpp index 5564b082..02266736 100644 --- a/ICEBERG/src/Editor.cpp +++ b/ICEBERG/src/Editor.cpp @@ -40,9 +40,9 @@ Editor::Editor(const std::shared_ptr& engine, const std::shared_ import_name + std::to_string(++i); } while (m_engine->getAssetBank()->nameInUse(ICE::AssetPath::WithTypePrefix(import_name + std::to_string(i)))); import_name = import_name + std::to_string(i); - m_engine->getProject()->copyAssetFile("Meshes", import_name, file); - m_engine->getAssetBank()->addAsset( - import_name, {m_engine->getProject()->getBaseDirectory() / "Assets" / "Meshes" / (import_name + file.extension().string())}); + m_engine->getProject()->copyAssetFile("Models", import_name, file); + m_engine->getAssetBank()->addAsset( + import_name, {m_engine->getProject()->getBaseDirectory() / "Assets" / "Models" / (import_name + file.extension().string())}); m_assets->rebuildViewer(); } }); diff --git a/ICEBERG/src/Hierarchy.cpp b/ICEBERG/src/Hierarchy.cpp index c33594b4..a1ff313d 100644 --- a/ICEBERG/src/Hierarchy.cpp +++ b/ICEBERG/src/Hierarchy.cpp @@ -14,9 +14,8 @@ Hierarchy::Hierarchy(const std::shared_ptr &engine) : m_engine(e scene->getRegistry()->addComponent( entity, ICE::TransformComponent(Eigen::Vector3f::Zero(), Eigen::Vector3f::Zero(), Eigen::Vector3f(1, 1, 1))); - auto cube_id = m_engine->getAssetBank()->getUID(ICE::AssetPath::WithTypePrefix("cube")); - auto mat_id = m_engine->getAssetBank()->getUID(ICE::AssetPath::WithTypePrefix("base_mat")); - scene->getRegistry()->addComponent(entity, ICE::RenderComponent(cube_id, mat_id)); + auto cube_id = m_engine->getAssetBank()->getUID(ICE::AssetPath::WithTypePrefix("cube")); + scene->getRegistry()->addComponent(entity, ICE::RenderComponent(cube_id)); scene->getGraph()->setParent(entity, parent, false); m_need_rebuild_tree = true; diff --git a/ICEBERG/src/Inspector.cpp b/ICEBERG/src/Inspector.cpp index c3b94a3c..71e8e8f2 100644 --- a/ICEBERG/src/Inspector.cpp +++ b/ICEBERG/src/Inspector.cpp @@ -46,7 +46,7 @@ void Inspector::setSelectedEntity(ICE::Entity e, bool force_refesh) { auto registry = m_engine->getProject()->getCurrentScene()->getRegistry(); ui.setEntityName(m_engine->getProject()->getCurrentScene()->getAlias(e)); ui.setLightComponent(nullptr); - ui.setRenderComponent(nullptr, {}, {}, {}, {}); + ui.setRenderComponent(nullptr, {}, {}); if (registry->entityHasComponent(e)) { auto tc = registry->getComponent(e); @@ -55,23 +55,17 @@ void Inspector::setSelectedEntity(ICE::Entity e, bool force_refesh) { if (registry->entityHasComponent(e)) { auto rc = registry->getComponent(e); - auto meshes = m_engine->getAssetBank()->getAll(); - auto materials = m_engine->getAssetBank()->getAll(); + auto meshes = m_engine->getAssetBank()->getAll(); - std::vector meshes_paths, materials_paths; - std::vector meshes_ids, materials_ids; + std::vector meshes_paths; + std::vector meshes_ids; for (const auto& [id, m] : meshes) { meshes_ids.push_back(id); meshes_paths.push_back(m_engine->getAssetBank()->getName(id).toString()); } - for (const auto& [id, m] : materials) { - materials_ids.push_back(id); - materials_paths.push_back(m_engine->getAssetBank()->getName(id).toString()); - } - - ui.setRenderComponent(rc, meshes_paths, meshes_ids, materials_paths, materials_ids); + ui.setRenderComponent(rc, meshes_paths, meshes_ids); } if (registry->entityHasComponent(e)) { auto lc = registry->getComponent(e); diff --git a/ICEBERG/src/Viewport.cpp b/ICEBERG/src/Viewport.cpp index 1b40a01f..0830af5f 100644 --- a/ICEBERG/src/Viewport.cpp +++ b/ICEBERG/src/Viewport.cpp @@ -45,10 +45,12 @@ Viewport::Viewport(const std::shared_ptr &engine, const std::fun auto rc = registry->getComponent(e); m_engine->getAssetBank()->getAsset("__ice__picking_shader")->loadMat4("model", tc->getModelMatrix()); m_engine->getAssetBank()->getAsset("__ice__picking_shader")->loadInt("objectID", e); - auto mesh = m_engine->getAssetBank()->getAsset(rc->mesh); - mesh->getVertexArray()->bind(); - mesh->getVertexArray()->getIndexBuffer()->bind(); - m_engine->getApi()->renderVertexArray(mesh->getVertexArray()); + auto model = m_engine->getAssetBank()->getAsset(rc->model); + for (const auto &mesh : model->getMeshes()) { + mesh->getVertexArray()->bind(); + mesh->getVertexArray()->getIndexBuffer()->bind(); + m_engine->getApi()->renderVertexArray(mesh->getVertexArray()); + } } } auto color = m_picking_frambuffer->readPixel(x, y); diff --git a/ICEFIELD/icefield.cpp b/ICEFIELD/icefield.cpp index 5ad9c940..a2d3851b 100644 --- a/ICEFIELD/icefield.cpp +++ b/ICEFIELD/icefield.cpp @@ -23,7 +23,7 @@ int main(void) { engine.setProject(project); - engine.getAssetBank()->addAsset("cube", {"Assets/cube.obj"}); + engine.getAssetBank()->addAsset("cube", {"Assets/cube.obj"}); engine.getAssetBank()->addAsset("solid", {"Assets/solid.vs", "Assets/solid.fs"}); auto shader_id = engine.getAssetBank()->getUID(std::string("Shaders/solid")); @@ -33,12 +33,12 @@ int main(void) { mat->setUniform("uAlbedo", Eigen::Vector3f(0.2, 0.5, 1)); engine.getAssetBank()->addAsset("mat", mat); - auto mesh_id = engine.getAssetBank()->getUID(std::string("Meshes/cube")); + auto mesh_id = engine.getAssetBank()->getUID(std::string("Models/cube")); auto material_id = engine.getAssetBank()->getUID(std::string("Materials/mat")); auto entity = scene->createEntity(); scene->getRegistry()->addComponent(entity, TransformComponent(Eigen::Vector3f::Zero(), Eigen::Vector3f::Zero(), Eigen::Vector3f(1, 1, 1))); - scene->getRegistry()->addComponent(entity, RenderComponent(mesh_id, material_id)); + scene->getRegistry()->addComponent(entity, RenderComponent(mesh_id)); auto camera = std::make_shared(60.0, 16.0 / 9.0, 0.01, 10000.0); camera->backward(2);