From 3188e3052238a6bfe723ed4bd7ed85d44114807b Mon Sep 17 00:00:00 2001 From: Joseph Walton-Rivers <joseph@walton-rivers.uk> Date: Sat, 22 Oct 2022 18:18:03 +0100 Subject: [PATCH] new rendering pipeline with multi-mesh support --- .gitattributes | 4 + demo/CMakeLists.txt | 1 + demo/data/backpack/ao.jpg | 3 + demo/data/backpack/backpack.mtl | 3 + demo/data/backpack/backpack.obj | 3 + demo/data/backpack/diffuse.jpg | 3 + demo/data/backpack/normal.png | 3 + demo/data/backpack/roughness.jpg | 3 + demo/data/backpack/source_attribution.txt | 3 + demo/data/backpack/specular.jpg | 3 + demo/demo/main.cpp | 14 +- demo/demo/models/viewer.cpp | 132 ++++++++++++++ demo/include/models/viewer.hpp | 43 +++++ fggl/CMakeLists.txt | 7 +- fggl/data/assimp/CMakeLists.txt | 11 ++ fggl/data/assimp/module.cpp | 116 ++++++++++++ fggl/gfx/ogl4/CMakeLists.txt | 1 + fggl/gfx/ogl4/meshes.cpp | 213 ++++++++++++++++++++++ fggl/gfx/ogl4/models.cpp | 97 +++++++++- include/fggl/assets/manager.hpp | 5 + include/fggl/data/assimp/module.hpp | 48 +++++ include/fggl/entity/entity.hpp | 5 +- include/fggl/gfx/camera.hpp | 4 + include/fggl/gfx/ogl/backend.hpp | 1 - include/fggl/gfx/ogl/types.hpp | 2 + include/fggl/gfx/ogl4/meshes.hpp | 177 ++++++++++++++++++ include/fggl/gfx/ogl4/models.hpp | 7 +- include/fggl/math/types.hpp | 8 +- include/fggl/mesh/components.hpp | 55 ++++++ include/fggl/mesh/mesh.hpp | 61 +++++++ 30 files changed, 1010 insertions(+), 26 deletions(-) create mode 100644 demo/data/backpack/ao.jpg create mode 100644 demo/data/backpack/backpack.mtl create mode 100644 demo/data/backpack/backpack.obj create mode 100644 demo/data/backpack/diffuse.jpg create mode 100644 demo/data/backpack/normal.png create mode 100644 demo/data/backpack/roughness.jpg create mode 100644 demo/data/backpack/source_attribution.txt create mode 100644 demo/data/backpack/specular.jpg create mode 100644 demo/demo/models/viewer.cpp create mode 100644 demo/include/models/viewer.hpp create mode 100644 fggl/data/assimp/CMakeLists.txt create mode 100644 fggl/data/assimp/module.cpp create mode 100644 fggl/gfx/ogl4/meshes.cpp create mode 100644 include/fggl/data/assimp/module.hpp create mode 100644 include/fggl/gfx/ogl4/meshes.hpp create mode 100644 include/fggl/mesh/components.hpp create mode 100644 include/fggl/mesh/mesh.hpp diff --git a/.gitattributes b/.gitattributes index 1b9fa98..1e2d898 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1 +1,5 @@ *,ogg filter=lfs diff=lfs merge=lfs -text +*.mtl filter=lfs diff=lfs merge=lfs -text +*.jpg filter=lfs diff=lfs merge=lfs -text +*.obj filter=lfs diff=lfs merge=lfs -text +*.png filter=lfs diff=lfs merge=lfs -text diff --git a/demo/CMakeLists.txt b/demo/CMakeLists.txt index facfd04..f634304 100644 --- a/demo/CMakeLists.txt +++ b/demo/CMakeLists.txt @@ -9,6 +9,7 @@ add_executable(demo demo/topdown.cpp demo/grid.cpp demo/robot/programmer.cpp + demo/models/viewer.cpp ) target_include_directories(demo diff --git a/demo/data/backpack/ao.jpg b/demo/data/backpack/ao.jpg new file mode 100644 index 0000000..0b28edb --- /dev/null +++ b/demo/data/backpack/ao.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d7b0855da6e4f621546b5bbf8a41bc0963a898c44ccce578c89e6bf929cdcfd7 +size 1895126 diff --git a/demo/data/backpack/backpack.mtl b/demo/data/backpack/backpack.mtl new file mode 100644 index 0000000..868905e --- /dev/null +++ b/demo/data/backpack/backpack.mtl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f9aaffb7ce3f968c01c3ab0e2de60fa38dff9695993c79d082c2e0a10c115cb5 +size 278 diff --git a/demo/data/backpack/backpack.obj b/demo/data/backpack/backpack.obj new file mode 100644 index 0000000..9c18219 --- /dev/null +++ b/demo/data/backpack/backpack.obj @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8d3253f4032314c72353b79cbe589ec5751f50c294668cfd55fe70988e1d64ea +size 6998040 diff --git a/demo/data/backpack/diffuse.jpg b/demo/data/backpack/diffuse.jpg new file mode 100644 index 0000000..cc28b9f --- /dev/null +++ b/demo/data/backpack/diffuse.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bbac15f06974d2ff27ea3aa3c4c555025b4d90bef533a23bd6c89630efc8f582 +size 6108855 diff --git a/demo/data/backpack/normal.png b/demo/data/backpack/normal.png new file mode 100644 index 0000000..0f1e060 --- /dev/null +++ b/demo/data/backpack/normal.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d4a2f93658af8c4881cfa6ac329993879adfb7b3ce48000a3928f20593a9908d +size 15214871 diff --git a/demo/data/backpack/roughness.jpg b/demo/data/backpack/roughness.jpg new file mode 100644 index 0000000..2668d92 --- /dev/null +++ b/demo/data/backpack/roughness.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8e6d31f76cd1cc19694c99f4c2d05dc75baf5f09580439ddf5f3cb934779df08 +size 4388250 diff --git a/demo/data/backpack/source_attribution.txt b/demo/data/backpack/source_attribution.txt new file mode 100644 index 0000000..31bb948 --- /dev/null +++ b/demo/data/backpack/source_attribution.txt @@ -0,0 +1,3 @@ +Model by Berk Gedik, from: https://sketchfab.com/3d-models/survival-guitar-backpack-low-poly-799f8c4511f84fab8c3f12887f7e6b36 + +Modified material assignment (Joey de Vries) for easier load in OpenGL model loading chapter, and renamed albedo to diffuse and metallic to specular to match non-PBR lighting setup. \ No newline at end of file diff --git a/demo/data/backpack/specular.jpg b/demo/data/backpack/specular.jpg new file mode 100644 index 0000000..08395c7 --- /dev/null +++ b/demo/data/backpack/specular.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:dfc3fac4a52b709caa998aec8699ae2421f59ae8c353c7e05779cd93cff8153b +size 6722296 diff --git a/demo/demo/main.cpp b/demo/demo/main.cpp index d9c0587..3228169 100644 --- a/demo/demo/main.cpp +++ b/demo/demo/main.cpp @@ -31,14 +31,13 @@ #include "fggl/entity/module.hpp" #include "fggl/audio/openal/audio.hpp" - -#include "fggl/gfx/atlas.hpp" #include "fggl/display/glfw/window.hpp" -#include "fggl/platform/paths.hpp" #include "fggl/scenes/menu.hpp" #include "fggl/modules/manager.hpp" + +#include "fggl/data/assimp/module.hpp" #include "fggl/assets/module.hpp" #include "fggl/script/lua/module.hpp" @@ -46,13 +45,14 @@ #include "rollball.hpp" #include "topdown.hpp" #include "grid.hpp" +#include "models/viewer.hpp" static void setup_menu(fggl::App& app) { auto *menu = app.addState<fggl::scenes::BasicMenu>("menu"); // add some menu items for the game states - const std::array labels = {"terrain", "rollball", "Top Down", "Grid World"}; - const std::array scenes = {"game", "rollball", "topdown", "gridworld"}; + const std::array labels = {"terrain", "rollball", "Top Down", "Grid World", "Viewer"}; + const std::array scenes = {"game", "rollball", "topdown", "gridworld", "viewer"}; for (std::size_t i = 0; i < labels.size(); ++i) { std::string sceneName = scenes.at(i); @@ -85,6 +85,9 @@ int main(int argc, const char* argv[]) { moduleManager.use<fggl::entity::ECS>(); moduleManager.use<fggl::script::Lua>(); + // debug/testing use + moduleManager.use<fggl::data::AssimpLoader>(); + #ifdef FGGL_MODULE_BULLET moduleManager.use<fggl::phys::Bullet3>(); #else @@ -109,6 +112,7 @@ int main(int argc, const char* argv[]) { app.addState<demo::RollBall>("rollball"); app.addState<demo::TopDown>("topdown"); app.addState<demo::GridScene>("gridworld"); + app.addState<demo::Viewer>("viewer"); return app.run(argc, argv); } diff --git a/demo/demo/models/viewer.cpp b/demo/demo/models/viewer.cpp new file mode 100644 index 0000000..048b8e5 --- /dev/null +++ b/demo/demo/models/viewer.cpp @@ -0,0 +1,132 @@ +/* + * This file is part of FGGL. + * + * FGGL is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * FGGL is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License along with FGGL. + * If not, see <https://www.gnu.org/licenses/>. + */ + +// +// Created by webpigeon on 18/10/22. +// + +#include "models/viewer.hpp" + +#include "fggl/assets/module.hpp" +#include "fggl/data/assimp/module.hpp" + +#include "fggl/mesh/mesh.hpp" +#include "fggl/mesh/components.hpp" + +#include "fggl/input/camera_input.hpp" + +#include "fggl/gfx/phong.hpp" +#include "fggl/gfx/camera.hpp" + +namespace demo { + + static fggl::entity::EntityID build_model(fggl::entity::EntityManager& manager, fggl::assets::AssetManager *assets){ + auto model = manager.create(); + + manager.add<fggl::math::Transform>(model); + auto& mesh = manager.add<fggl::mesh::StaticMultiMesh3D>(model); + + auto* meshData = assets->get<fggl::mesh::MultiMesh3D>("backpack/backpack.obj"); + if ( meshData == nullptr ) { + fggl::debug::warning("loading model did not work!"); + } else { + mesh.mesh = *meshData; + mesh.pipeline = "redbook/debug"; + } + + auto& material = manager.add<fggl::gfx::PhongMaterial>(model); + + return model; + } + + static void process_camera(fggl::entity::EntityManager& ecs, const fggl::input::Input& input) { + auto cameras = ecs.find<fggl::gfx::Camera>(); + auto cam = cameras[0]; + + auto camTransform = ecs.get<fggl::math::Transform>(cam); + auto camComp = ecs.get<fggl::gfx::Camera>(cam); + + const glm::vec3 dir = ( camTransform.origin() - camComp.target ); + const glm::vec3 forward = glm::normalize( dir ); + + // scroll wheel + glm::vec3 motion(0.0f); + float delta = input.mouse.axis( fggl::input::MouseAxis::SCROLL_Y ); + if ( (glm::length( dir ) < 25.0f && delta < 0.0f) || (glm::length( dir ) > 2.5f && delta > 0.0f) ) + motion -= (forward * delta); + camTransform.origin( camTransform.origin() + motion ); + + fggl::input::process_arcball(ecs, input, cam); + } + + static void setup_camera(fggl::entity::EntityManager& world) { + auto prototype = world.create(); + + // setup camera position/transform + auto& transform = world.add<fggl::math::Transform>(prototype); + transform.origin(glm::vec3(10.0f, 3.0f, 10.0f)); + + // setup camera components + world.add<fggl::gfx::Camera>(prototype); + + // interactive camera + auto& cameraKeys = world.add<fggl::input::FreeCamKeys>(prototype); + cameraKeys.forward = glfwGetKeyScancode(GLFW_KEY_W); + cameraKeys.backward = glfwGetKeyScancode(GLFW_KEY_S); + cameraKeys.left = glfwGetKeyScancode(GLFW_KEY_A); + cameraKeys.right = glfwGetKeyScancode(GLFW_KEY_D); + cameraKeys.rotate_cw = glfwGetKeyScancode(GLFW_KEY_Q); + cameraKeys.rotate_ccw = glfwGetKeyScancode(GLFW_KEY_E); + } + + Viewer::Viewer(fggl::App &app) : fggl::scenes::Game(app), m_model(fggl::entity::INVALID) { + + } + + void Viewer::activate() { + Game::activate(); + + // force load required data + auto *loader = owner().service<fggl::assets::Loader>(); + auto *manager = owner().service<fggl::assets::AssetManager>(); + + loader->load("backpack/backpack.obj", fggl::data::models::ASSIMP_MODEL, manager); + + // create camera + setup_camera(world()); + + // setup model + m_model = build_model(world(), manager); + + // asset loader + + //loader-> + } + + void Viewer::deactivate() { + Game::deactivate(); + } + + void Viewer::update(float dt) { + Game::update(dt); + process_camera(world(), input()); + } + + void Viewer::render(fggl::gfx::Graphics &gfx) { + Game::render(gfx); + + gfx.drawScene(world()); + } + +} diff --git a/demo/include/models/viewer.hpp b/demo/include/models/viewer.hpp new file mode 100644 index 0000000..7e29623 --- /dev/null +++ b/demo/include/models/viewer.hpp @@ -0,0 +1,43 @@ +/* + * This file is part of FGGL. + * + * FGGL is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * FGGL is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License along with FGGL. + * If not, see <https://www.gnu.org/licenses/>. + */ + +// +// Created by webpigeon on 18/10/22. +// + +#ifndef FGGL_DEMO_INCLUDE_MODELS_VIEWER_HPP +#define FGGL_DEMO_INCLUDE_MODELS_VIEWER_HPP + +#include "fggl/scenes/game.hpp" + +namespace demo { + + class Viewer : public fggl::scenes::Game { + + public: + explicit Viewer(fggl::App& app); + + void activate() override; + void deactivate() override; + + void update(float dt) override; + void render(fggl::gfx::Graphics& gfx) override; + + private: + fggl::entity::EntityID m_model; + + }; +} + +#endif //FGGL_DEMO_INCLUDE_MODELS_VIEWER_HPP diff --git a/fggl/CMakeLists.txt b/fggl/CMakeLists.txt index a62f5fc..d054dc3 100644 --- a/fggl/CMakeLists.txt +++ b/fggl/CMakeLists.txt @@ -65,12 +65,7 @@ find_package(yaml-cpp) target_link_libraries(fggl PUBLIC yaml-cpp) # model loading -find_package(assimp CONFIG) -if (MSVC) - target_link_libraries(${PROJECT_NAME} PUBLIC assimp::assimp) -else () - target_link_libraries(${PROJECT_NAME} PUBLIC assimp) -endif () +add_subdirectory(data/assimp) find_package(Freetype) target_link_libraries(${PROJECT_NAME} PUBLIC Freetype::Freetype) diff --git a/fggl/data/assimp/CMakeLists.txt b/fggl/data/assimp/CMakeLists.txt new file mode 100644 index 0000000..1daab2b --- /dev/null +++ b/fggl/data/assimp/CMakeLists.txt @@ -0,0 +1,11 @@ +find_package(assimp CONFIG) +if (MSVC) + target_link_libraries(${PROJECT_NAME} PUBLIC assimp::assimp) +else () + target_link_libraries(${PROJECT_NAME} PUBLIC assimp) +endif () + +target_sources(fggl + PRIVATE + module.cpp +) \ No newline at end of file diff --git a/fggl/data/assimp/module.cpp b/fggl/data/assimp/module.cpp new file mode 100644 index 0000000..99d2a63 --- /dev/null +++ b/fggl/data/assimp/module.cpp @@ -0,0 +1,116 @@ +/* + * This file is part of FGGL. + * + * FGGL is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * FGGL is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License along with FGGL. + * If not, see <https://www.gnu.org/licenses/>. + */ + +// +// Created by webpigeon on 18/10/22. +// + +#include "fggl/data/assimp/module.hpp" +#include "fggl/data/model.hpp" +#include "fggl/debug/logging.hpp" +#include "fggl/assets/manager.hpp" +#include "fggl/mesh/mesh.hpp" + +#include <assimp/Importer.hpp> +#include <assimp/scene.h> +#include <assimp/postprocess.h> + +namespace fggl::data::models { + + constexpr math::vec3 convert(aiVector3D& vec) { + return {vec.x, vec.y, vec.z}; + } + + constexpr math::vec2 convert(aiVector2D& vec) { + return {vec.x, vec.y}; + } + + static void process_mesh(mesh::Mesh3D& mesh, aiMesh* assimpMesh, const aiScene* scene) { + assert( assimpMesh != nullptr ); + assert( scene != nullptr ); + + for ( auto idx = 0U; idx < assimpMesh->mNumVertices; ++idx ) { + mesh::Vertex3D vertex{ + .position = convert(assimpMesh->mVertices[idx]), + .normal = convert(assimpMesh->mNormals[idx]) + }; + + if ( assimpMesh->mTextureCoords[0] != nullptr ) { + vertex.texPos = convert( assimpMesh->mTextureCoords[0][idx] ); + } + + mesh.data.push_back(vertex); + } + + for ( auto idx = 0U; idx < assimpMesh->mNumFaces; ++idx ) { + auto face = assimpMesh->mFaces[idx]; + assert( face.mNumIndices == 3); + + for ( auto vid = 0U; vid < face.mNumIndices; ++vid) { + mesh.indices.push_back( face.mIndices[vid] ); + } + } + } + + static void process_node(mesh::MultiMesh3D& mesh, aiNode* node, const aiScene* scene) { + for ( auto idx = 0U; idx < node->mNumMeshes; ++idx ) { + auto *assimpMesh = scene->mMeshes[ node->mMeshes[idx] ]; + + // process assimp submesh + mesh::Mesh3D meshData; + process_mesh(meshData, assimpMesh, scene); + + mesh.meshes.push_back(meshData); + } + + for ( auto idx = 0U; idx < node->mNumChildren; ++idx) { + process_node(mesh, node->mChildren[idx], scene); + } + } + + + static assets::AssetRefRaw load_assimp_model(assets::Loader* loader, const assets::AssetGUID& guid, const assets::AssetData& data, void* userPtr) { + auto *filePath = std::get<assets::AssetPath *>(data); + + // assimp stuff + Assimp::Importer importer; + + // import the scene from disk + const aiScene *scene = importer.ReadFile(filePath->c_str(), aiProcess_Triangulate | aiProcess_FlipUVs); + if ( !scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode ) { + debug::warning("unable to load required model asset"); + return nullptr; + } + + debug::debug("Processing assimp mesh, {} meshes", scene->mNumMeshes); + + // now we can try importing the mesh data + mesh::MultiMesh3D* packedMesh = new mesh::MultiMesh3D(); + process_node( *packedMesh, scene->mRootNode, scene); + + // FIXME asset loading system needs rework, this is bonkers. + assets::AssetManager* manager = (assets::AssetManager*)userPtr; + manager->set(guid, packedMesh); + + return nullptr; + } + + bool AssimpModule::factory(modules::ModuleService service, modules::Services &serviceManager) { + if ( service == MODEL_PROVIDER ) { + auto assetLoader = serviceManager.get<assets::Loader>(); + assetLoader->setFactory( ASSIMP_MODEL, load_assimp_model, assets::LoadType::PATH ); + } + } + +} // namespace fggl::data diff --git a/fggl/gfx/ogl4/CMakeLists.txt b/fggl/gfx/ogl4/CMakeLists.txt index e000470..fee95dc 100644 --- a/fggl/gfx/ogl4/CMakeLists.txt +++ b/fggl/gfx/ogl4/CMakeLists.txt @@ -6,5 +6,6 @@ target_sources(fggl canvas.cpp models.cpp debug.cpp + meshes.cpp module.cpp ) diff --git a/fggl/gfx/ogl4/meshes.cpp b/fggl/gfx/ogl4/meshes.cpp new file mode 100644 index 0000000..6f8fc86 --- /dev/null +++ b/fggl/gfx/ogl4/meshes.cpp @@ -0,0 +1,213 @@ +/* + * This file is part of FGGL. + * + * FGGL is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * FGGL is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License along with FGGL. + * If not, see <https://www.gnu.org/licenses/>. + */ + +#include "fggl/gfx/ogl4/meshes.hpp" + + +// +// Created by webpigeon on 22/10/22. +// + +namespace fggl::gfx::ogl4 { + + static std::shared_ptr<ogl::ArrayBuffer> setup_array_buffer(std::shared_ptr<ogl::VertexArray> &vao, + const std::vector<mesh::Vertex3D> &data) { + // upload the data to the GPU + auto buff = std::make_shared<ogl::ArrayBuffer>(); + buff->write(data.size() * sizeof(mesh::Vertex3D), data.data(), ogl::BufUsage::STATIC_DRAW); + + // set up the vertex attributes + auto posAttr = ogl::attribute<mesh::Vertex3D, math::vec3>(offsetof(mesh::Vertex3D, position)); + auto normalAttr = ogl::attribute<mesh::Vertex3D, math::vec3>(offsetof(mesh::Vertex3D, normal)); + auto colAttr = ogl::attribute<mesh::Vertex3D, math::vec3>(offsetof(mesh::Vertex3D, colour)); + auto texAttr = ogl::attribute<mesh::Vertex3D, math::vec3>(offsetof(mesh::Vertex3D, colour)); + + vao->setAttribute(*buff, 0, posAttr); + vao->setAttribute(*buff, 1, normalAttr); + vao->setAttribute(*buff, 2, colAttr); + vao->setAttribute(*buff, 3, texAttr); + + return buff; + } + + static std::shared_ptr<ogl::ElementBuffer> setup_index_buffer(const std::vector<uint32_t>& data) { + auto elementBuffer = std::make_shared<ogl::ElementBuffer>(); + elementBuffer->write(data.size() * sizeof(uint32_t), + data.data(), ogl::BufUsage::STATIC_DRAW); + return elementBuffer; + } + + void MeshData::draw() const { + vao->bind(); + vertexData->bind(); + + if ( drawInfo.restartIndex != ogl::NO_RESTART_IDX) { + glEnable(GL_PRIMITIVE_RESTART); + glPrimitiveRestartIndex( drawInfo.restartIndex ); + } + + vao->drawElements(*elements, drawInfo.mode, elementCount); + + if ( drawInfo.restartIndex != ogl::NO_RESTART_IDX ) { + glDisable(GL_PRIMITIVE_RESTART); + } + } + + void StaticMultiMesh::draw() const { + for ( const auto& mesh : meshes ) { + mesh.draw(); + } + } + + void setup_material(const std::shared_ptr<ogl::Shader>& shader, const PhongMaterial* material) { + if ( !shader->hasUniform("materials[0].ambient") ) { + return; + } + + // setup material block + shader->setUniformF(shader->uniform("materials[0].emission"), material->emission); + shader->setUniformF(shader->uniform("materials[0].ambient"), material->ambient); + shader->setUniformF(shader->uniform("materials[0].diffuse"), material->diffuse); + shader->setUniformF(shader->uniform("materials[0].specular"), material->specular); + shader->setUniformF(shader->uniform("materials[0].shininess"), material->shininess); + } + + void setup_lighting(const std::shared_ptr<ogl::Shader>& shader, const math::mat4& viewMatrix, const math::Transform& camTransform, const math::Transform& transform, math::vec3 lightPos) { + if (shader->hasUniform("lightPos")) { + shader->setUniformF(shader->uniform("lightPos"), lightPos); + } + + if ( !shader->hasUniform("lights[0].isEnabled") ) { + return; + } + + bool local = true; + + shader->setUniformI(shader->uniform("lights[0].isEnabled"), 1); + shader->setUniformI(shader->uniform("lights[0].isLocal"), local); + shader->setUniformI(shader->uniform("lights[0].isSpot"), 0); + + shader->setUniformF(shader->uniform("lights[0].constantAttenuation"), 5.0f); + shader->setUniformF(shader->uniform("lights[0].linearAttenuation"), 0.0f); + shader->setUniformF(shader->uniform("lights[0].quadraticAttenuation"), 0.0f); + + shader->setUniformF(shader->uniform("Strength"), 0.6F); + + if (!local) { + lightPos = glm::normalize(lightPos); + auto viewDir = glm::normalize(camTransform.origin() - transform.origin()); + auto halfVector = glm::normalize(lightPos + viewDir); + shader->setUniformF(shader->uniform("lights[0].halfVector"), halfVector); + shader->setUniformF(shader->uniform("EyeDirection"), viewDir); + shader->setUniformF(shader->uniform("lights[0].position"), lightPos); + } else { + auto camModelView = (viewMatrix * camTransform.model() * math::vec4(0.0f, 0.0f, 0.0f, 1.0f)); + auto modelModelView = (viewMatrix * transform.model() * math::vec4(0.0f, 0.0f, 0.0f, 1.0f)); + math::vec3 viewDir = glm::normalize(camModelView - modelModelView); + shader->setUniformF(shader->uniform("EyeDirection"), viewDir); + + shader->setUniformF(shader->uniform("lights[0].position"), + math::vec3(viewMatrix * math::vec4(lightPos, 1.0f))); + } + + shader->setUniformF(shader->uniform("lights[0].ambient"), {0.0f, 0.5f, 0.0f}); + shader->setUniformF(shader->uniform("lights[0].colour"), {0.5f, 0.5f, 0.5f}); + } + + + void forward_pass_multi_mesh(const entity::EntityID& camera, const fggl::entity::EntityManager& world) { + + // enable required OpenGL state + glEnable(GL_CULL_FACE); + glCullFace(GL_BACK); + + // enable depth testing + glEnable(GL_DEPTH_TEST); + + // set-up camera matrices + const auto &camTransform = world.get<fggl::math::Transform>(camera); + const auto &camComp = world.get<fggl::gfx::Camera>(camera); + + const math::mat4 projectionMatrix = + glm::perspective(camComp.fov, camComp.aspectRatio, camComp.nearPlane, camComp.farPlane); + const math::mat4 viewMatrix = glm::lookAt(camTransform.origin(), camComp.target, camTransform.up()); + + // TODO lighting needs to not be this... + math::vec3 lightPos{0.0f, 10.0f, 0.0f}; + + std::shared_ptr<ogl::Shader> shader = nullptr; + ogl::Location mvpMatrixUniform = 0; + ogl::Location mvMatrixUniform = 0; + + auto entityView = world.find<StaticMultiMesh>(); + for (const auto &entity : entityView) { + debug::trace("Multi-mesh happened!"); + + // ensure that the model pipeline actually exists... + const auto &model = world.get<StaticMultiMesh>(entity); + if (model.pipeline == nullptr) { + debug::warning("shader was null, aborting render"); + continue; + } + + // check if we switched shaders + if (shader == nullptr || shader->shaderID() != model.pipeline->shaderID()) { + // new shader - need to re-send the view and projection matrices + shader = model.pipeline; + shader->use(); + if (shader->hasUniform("projection")) { + shader->setUniformMtx(shader->uniform("view"), viewMatrix); + shader->setUniformMtx(shader->uniform("projection"), projectionMatrix); + } + mvpMatrixUniform = shader->uniform("MVPMatrix"); + mvMatrixUniform = shader->uniform("MVMatrix"); + } + + // set model transform + const auto &transform = world.get<math::Transform>(entity); + shader->setUniformMtx(mvpMatrixUniform, projectionMatrix * viewMatrix * transform.model()); + shader->setUniformMtx(mvMatrixUniform, viewMatrix * transform.model()); + + auto normalMatrix = glm::mat3(glm::transpose(inverse(transform.model()))); + shader->setUniformMtx(shader->uniform("NormalMatrix"), normalMatrix); + + // setup lighting mode + setup_lighting(shader, viewMatrix, camTransform, transform, lightPos); + setup_material(shader, world.tryGet<PhongMaterial>(entity, &DEFAULT_MATERIAL)); + + model.draw(); + + } + } + + MeshData upload_mesh(const mesh::Mesh3D& rawMesh) { + auto vao = std::make_shared<ogl::VertexArray>(); + return { + .vao = vao, + .elements = setup_index_buffer( rawMesh.indices ), + .vertexData = setup_array_buffer(vao, rawMesh.data ), + .elementCount = rawMesh.indices.size(), + .drawInfo = { .mode = ogl::Primitive::TRIANGLE } + }; + } + + std::vector<MeshData> upload_multi_mesh(const mesh::MultiMesh3D& rawMesh) { + std::vector<MeshData> gpuMeshes; + for (const auto& mesh : rawMesh.meshes) { + gpuMeshes.push_back( upload_mesh(mesh) ); + } + return gpuMeshes; + } + +} diff --git a/fggl/gfx/ogl4/models.cpp b/fggl/gfx/ogl4/models.cpp index b70131b..99a2384 100644 --- a/fggl/gfx/ogl4/models.cpp +++ b/fggl/gfx/ogl4/models.cpp @@ -17,6 +17,8 @@ // #include "fggl/gfx/ogl4/models.hpp" +#include "fggl/gfx/ogl4/meshes.hpp" + #include "fggl/data/heightmap.hpp" #include "fggl/debug/logging.hpp" @@ -41,6 +43,7 @@ namespace fggl::gfx::ogl4 { return buff; } + static std::shared_ptr<ogl::ElementBuffer> setupIndexBuffer(std::shared_ptr<ogl::VertexArray> &vao, const std::vector<uint32_t> &data) { auto elementBuffer = std::make_shared<ogl::ElementBuffer>(); @@ -88,6 +91,31 @@ namespace fggl::gfx::ogl4 { return modelAsset; } + /*MeshData* StaticModelRenderer::uploadMesh(assets::AssetGUID guid, const mesh::Mesh3D &mesh, bool allowCache) { + assert( m_assets != nullptr ); + + // if the asset has already been uploaded, we don't need to do anything + if ( allowCache && m_assets->has(guid) ) { + m_assets->require(guid); + return m_assets->get<MeshData>(guid); + } + + // the asset does not exist, we need to upload it + auto* modelAsset = new MeshData(); + modelAsset->vao = std::make_shared<ogl::VertexArray>(); + modelAsset->vertexData = setupArrayBuffer(modelAsset->vao, mesh.data); + modelAsset->elements = setupIndexBuffer(modelAsset->vao, mesh.indices); + modelAsset->elementCount = mesh.indices.size(); + modelAsset->drawInfo.mode = ogl::Primitive::TRIANGLE; + + // if caching is enabled, then use the cache + if ( allowCache ) { + m_assets->set(guid, modelAsset); + } + + return modelAsset; + }*/ + StaticModelGPU* StaticModelRenderer::uploadMesh2(const assets::AssetGUID& meshName, const data::Mesh &mesh) { assert( m_assets != nullptr ); @@ -107,6 +135,52 @@ namespace fggl::gfx::ogl4 { } #ifdef FGGL_ALLOW_DEFERRED_UPLOAD + static void setup_meshes(entity::EntityManager& world, ShaderCache* shaders) { + auto entsWithModels = world.find<mesh::StaticMesh3D>(); + for ( const auto& mesher : entsWithModels ) { + + // check if this entity already has a mesh... + const auto* currModel = world.tryGet<StaticMesh>(mesher); + if ( currModel != nullptr ) { + continue; + } + + // figure out the requirements + auto& rawMesh = world.get<mesh::StaticMesh3D>(mesher); + if ( rawMesh.guid != util::make_guid("__NO_CACHE__") ){ + // TODO support fetching of loaded meshes + debug::warning("multiple entities sharing a mesh has not been implemented yet..."); + } + + auto& entityMesh = world.add<StaticMesh>(mesher); + entityMesh.pipeline = shaders->get( rawMesh.pipeline ); + entityMesh.mesh = upload_mesh( rawMesh.mesh ); + } + } + + static void setup_multi_meshes(entity::EntityManager& world, ShaderCache* shaders) { + auto entsWithModels = world.find<mesh::StaticMultiMesh3D>(); + for ( const auto& mesher : entsWithModels ) { + + // check if this entity already has a mesh... + const auto* currModel = world.tryGet<StaticMultiMesh>(mesher); + if ( currModel != nullptr ) { + continue; + } + + // figure out the requirements + auto& multiMesh = world.get<mesh::StaticMultiMesh3D>(mesher); + if ( multiMesh.guid != util::make_guid("__NO_CACHE__") ){ + // TODO support fetching of loaded meshes + debug::warning("multiple entities sharing a mesh has not been implemented yet..."); + } + + auto& entityMesh = world.add<StaticMultiMesh>(mesher); + entityMesh.pipeline = shaders->get( multiMesh.pipeline ); + entityMesh.meshes = upload_multi_mesh(multiMesh.mesh); + } + } + void StaticModelRenderer::resolveModels(entity::EntityManager &world) { // FIXME: this needs something reactive or performance will suck. auto renderableEnts = world.find<data::StaticMesh>(); @@ -131,6 +205,10 @@ namespace fggl::gfx::ogl4 { debug::log(debug::Level::info, "Added static mesh to {}, pipeline was: {}", (uint64_t) renderable, meshComp.pipeline); } + // multi-meshes + setup_meshes(world, m_shaders); + setup_multi_meshes(world, m_shaders); + // terrain auto terrain = world.find<data::HeightMap>(); for (auto &renderable : terrain) { @@ -268,14 +346,14 @@ namespace fggl::gfx::ogl4 { vao->bind(); model.vertexData->bind(); - if (model.restartIndex != NO_RESTART_IDX) { + if (model.restartIndex != ogl::NO_RESTART_IDX) { glEnable(GL_PRIMITIVE_RESTART); glPrimitiveRestartIndex(model.restartIndex); } auto *elements = model.elements.get(); vao->drawElements(*elements, model.drawType, model.elementCount); - if (model.restartIndex != NO_RESTART_IDX) { + if (model.restartIndex != ogl::NO_RESTART_IDX) { glDisable(GL_PRIMITIVE_RESTART); } } @@ -293,8 +371,7 @@ namespace fggl::gfx::ogl4 { const auto &camTransform = world.get<fggl::math::Transform>(camera); const auto &camComp = world.get<fggl::gfx::Camera>(camera); - const math::mat4 projectionMatrix = - glm::perspective(camComp.fov, camComp.aspectRatio, camComp.nearPlane, camComp.farPlane); + const math::mat4 projectionMatrix = camComp.perspective(); const math::mat4 viewMatrix = glm::lookAt(camTransform.origin(), camComp.target, camTransform.up()); ogl::Location modelUniform = shader->uniform("model"); @@ -320,14 +397,14 @@ namespace fggl::gfx::ogl4 { vao->bind(); model.vertexData->bind(); - if (model.restartIndex != NO_RESTART_IDX) { + if (model.restartIndex != ogl::NO_RESTART_IDX) { glEnable(GL_PRIMITIVE_RESTART); glPrimitiveRestartIndex(model.restartIndex); } auto *elements = model.elements.get(); vao->drawElements(*elements, model.drawType, model.elementCount); - if (model.restartIndex != NO_RESTART_IDX) { + if (model.restartIndex != ogl::NO_RESTART_IDX) { glDisable(GL_PRIMITIVE_RESTART); } } @@ -349,9 +426,15 @@ namespace fggl::gfx::ogl4 { //TODO should be clipping this to only visible objects forward_camera_pass(cameraEnt, world); + forward_pass<ogl4::StaticMesh>(cameraEnt, world); + forward_pass<ogl4::StaticMultiMesh>(cameraEnt, world); + // enable rendering normals if ( m_renderNormals ) { - forward_normal_pass(cameraEnt, world, m_shaders->get("normals")); + auto normalShader = m_shaders->get("normals"); + forward_pass_normals<StaticMesh>(cameraEnt, world, normalShader); + forward_pass_normals<StaticMultiMesh>(cameraEnt, world, normalShader); + forward_normal_pass(cameraEnt, world, normalShader); } } } diff --git a/include/fggl/assets/manager.hpp b/include/fggl/assets/manager.hpp index fef3c4e..27a9fc9 100644 --- a/include/fggl/assets/manager.hpp +++ b/include/fggl/assets/manager.hpp @@ -24,6 +24,7 @@ #include <functional> #include <memory> +#include "fggl/debug/logging.hpp" #include "fggl/assets/types.hpp" #include "fggl/util/safety.hpp" @@ -61,6 +62,10 @@ namespace fggl::assets { try { const auto &assetRecord = m_registry.at(guid); std::shared_ptr<AssetBoxT<T>> casted = std::dynamic_pointer_cast<AssetBoxT<T>>(assetRecord); + if ( casted == nullptr ) { + debug::error("Asset type requested did not match loaded asset type!"); + return nullptr; + } return casted->asset; } catch (std::out_of_range& e) { return nullptr; diff --git a/include/fggl/data/assimp/module.hpp b/include/fggl/data/assimp/module.hpp new file mode 100644 index 0000000..3c4a186 --- /dev/null +++ b/include/fggl/data/assimp/module.hpp @@ -0,0 +1,48 @@ +/* + * This file is part of FGGL. + * + * FGGL is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * FGGL is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License along with FGGL. + * If not, see <https://www.gnu.org/licenses/>. + */ + +// +// Created by webpigeon on 18/10/22. +// + +#ifndef FGGL_DATA_ASSIMP_MODULE_HPP +#define FGGL_DATA_ASSIMP_MODULE_HPP + +#include "fggl/modules/module.hpp" +#include "fggl/assets/loader.hpp" + + +namespace fggl::data::models { + + constexpr auto MODEL_PROVIDER = modules::make_service("fggl::data::Model"); + constexpr auto ASSIMP_MODEL = assets::AssetType::make("model::assimp"); + + struct AssimpModule { + constexpr static const char *name = "fggl::data::Assimp"; + constexpr static const std::array<modules::ModuleService, 1> provides = { + MODEL_PROVIDER + }; + constexpr static const std::array<modules::ModuleService, 1> depends = { + assets::Loader::service + }; + static bool factory(modules::ModuleService service, modules::Services &serviceManager); + }; + +} + +namespace fggl::data { + using AssimpLoader = models::AssimpModule; +} + +#endif //FGGL_DATA_ASSIMP_MODULE_HPP diff --git a/include/fggl/entity/entity.hpp b/include/fggl/entity/entity.hpp index cb1527e..04f5f96 100644 --- a/include/fggl/entity/entity.hpp +++ b/include/fggl/entity/entity.hpp @@ -68,8 +68,9 @@ namespace fggl::entity { } template<typename Component> - const Component *tryGet(EntityID entity) const { - return m_registry.try_get<Component>(entity); + const Component *tryGet(EntityID entity, const Component* defaultValue = nullptr) const { + auto* comp = m_registry.try_get<Component>(entity); + return comp == nullptr ? defaultValue : comp; } template<typename ...Components> diff --git a/include/fggl/gfx/camera.hpp b/include/fggl/gfx/camera.hpp index 8a14da3..adf9831 100644 --- a/include/fggl/gfx/camera.hpp +++ b/include/fggl/gfx/camera.hpp @@ -27,6 +27,10 @@ namespace fggl::gfx { float fov = glm::radians(45.0f); float nearPlane = 0.1f; float farPlane = 100.0f; + + inline math::mat4 perspective() const { + return glm::perspective(fov, aspectRatio, nearPlane, farPlane); + } }; inline math::mat4 calc_proj_matrix(const Camera &camera) { diff --git a/include/fggl/gfx/ogl/backend.hpp b/include/fggl/gfx/ogl/backend.hpp index 5116f0d..034f878 100644 --- a/include/fggl/gfx/ogl/backend.hpp +++ b/include/fggl/gfx/ogl/backend.hpp @@ -24,7 +24,6 @@ * FGGL OpenGL 4.x rendering backend. */ namespace fggl::gfx { - } #endif diff --git a/include/fggl/gfx/ogl/types.hpp b/include/fggl/gfx/ogl/types.hpp index 6e237b2..6f070c7 100644 --- a/include/fggl/gfx/ogl/types.hpp +++ b/include/fggl/gfx/ogl/types.hpp @@ -306,6 +306,8 @@ namespace fggl::gfx::ogl { void release(); }; + constexpr std::size_t NO_RESTART_IDX = 0; + enum class BuffAttrF { HALF_FLOAT = GL_HALF_FLOAT, FLOAT = GL_FLOAT, diff --git a/include/fggl/gfx/ogl4/meshes.hpp b/include/fggl/gfx/ogl4/meshes.hpp new file mode 100644 index 0000000..6061fa4 --- /dev/null +++ b/include/fggl/gfx/ogl4/meshes.hpp @@ -0,0 +1,177 @@ +/* + * This file is part of FGGL. + * + * FGGL is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * FGGL is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License along with FGGL. + * If not, see <https://www.gnu.org/licenses/>. + */ + +// +// Created by webpigeon on 22/10/22. +// + +#ifndef FGGL_GFX_OGL4_MESHES_HPP +#define FGGL_GFX_OGL4_MESHES_HPP + +#include "fggl/mesh/components.hpp" +#include "fggl/entity/entity.hpp" + +#include "fggl/gfx/ogl/types.hpp" +#include "fggl/gfx/camera.hpp" +#include "fggl/gfx/phong.hpp" + +namespace fggl::gfx::ogl4 { + + struct DrawType { + ogl::Primitive mode; + std::size_t restartIndex = ogl::NO_RESTART_IDX; + }; + + struct MeshData { + std::shared_ptr<ogl::VertexArray> vao; + std::shared_ptr<ogl::ElementBuffer> elements; + std::shared_ptr<ogl::ArrayBuffer> vertexData; + std::size_t elementCount; + DrawType drawInfo; + + void draw() const; + }; + + struct StaticMesh { + constexpr static auto name = "StaticMultiMesh"; + + std::shared_ptr<ogl::Shader> pipeline; + MeshData mesh; + + inline void draw() const { + mesh.draw(); + } + }; + + struct StaticMultiMesh { + constexpr static auto name = "StaticMultiMesh"; + + std::shared_ptr<ogl::Shader> pipeline; + std::vector<MeshData> meshes; + + void draw() const; + }; + + void setup_material(const std::shared_ptr<ogl::Shader>& shader, const PhongMaterial* material); + void setup_lighting(const std::shared_ptr<ogl::Shader>& shader, const math::mat4& viewMatrix, const math::Transform& camTransform, const math::Transform& transform, math::vec3 lightPos); + + template<typename T> + void forward_pass(const entity::EntityID& camera, const fggl::entity::EntityManager& world) { + + // enable required OpenGL state + glEnable(GL_CULL_FACE); + glCullFace(GL_BACK); + + // enable depth testing + glEnable(GL_DEPTH_TEST); + + // set-up camera matrices + const auto &camTransform = world.get<fggl::math::Transform>(camera); + const auto &camComp = world.get<fggl::gfx::Camera>(camera); + + const math::mat4 projectionMatrix = camComp.perspective(); + const math::mat4 viewMatrix = glm::lookAt(camTransform.origin(), camComp.target, camTransform.up()); + + // TODO lighting needs to not be this... + math::vec3 lightPos{0.0F, 10.0F, 0.0F}; + + std::shared_ptr<ogl::Shader> shader = nullptr; + ogl::Location mvpMatrixUniform = 0; + ogl::Location mvMatrixUniform = 0; + + auto entityView = world.find<T>(); + debug::info("Triggering rendering pass for {} entities", entityView.size()); + + for (const auto &entity : entityView) { + // ensure that the model pipeline actually exists... + const auto &model = world.get<T>(entity); + if (model.pipeline == nullptr) { + debug::warning("shader was null, aborting render"); + continue; + } + + // check if we switched shaders + if (shader == nullptr || shader->shaderID() != model.pipeline->shaderID()) { + // new shader - need to re-send the view and projection matrices + shader = model.pipeline; + shader->use(); + if (shader->hasUniform("projection")) { + shader->setUniformMtx(shader->uniform("view"), viewMatrix); + shader->setUniformMtx(shader->uniform("projection"), projectionMatrix); + } + mvpMatrixUniform = shader->uniform("MVPMatrix"); + mvMatrixUniform = shader->uniform("MVMatrix"); + } + + // set model transform + const auto &transform = world.get<math::Transform>(entity); + shader->setUniformMtx(mvpMatrixUniform, projectionMatrix * viewMatrix * transform.model()); + shader->setUniformMtx(mvMatrixUniform, viewMatrix * transform.model()); + + auto normalMatrix = glm::mat3(glm::transpose(inverse(transform.model()))); + shader->setUniformMtx(shader->uniform("NormalMatrix"), normalMatrix); + + // setup lighting mode + setup_lighting(shader, viewMatrix, camTransform, transform, lightPos); + setup_material(shader, world.tryGet<PhongMaterial>(entity, &DEFAULT_MATERIAL)); + + model.draw(); + } + } + + template<typename T> + void forward_pass_normals(const entity::EntityID& camera, const fggl::entity::EntityManager& world, const std::shared_ptr<ogl::Shader>& shader) { + // enable required OpenGL state + glEnable(GL_CULL_FACE); + glCullFace(GL_BACK); + + // enable depth testing + glEnable(GL_DEPTH_TEST); + + // set-up camera matrices + const auto &camTransform = world.get<fggl::math::Transform>(camera); + const auto &camComp = world.get<fggl::gfx::Camera>(camera); + + const math::mat4 projectionMatrix = camComp.perspective(); + const math::mat4 viewMatrix = glm::lookAt(camTransform.origin(), camComp.target, camTransform.up()); + + ogl::Location modelUniform = shader->uniform("model"); + ogl::Location viewUniform = shader->uniform("view"); + ogl::Location projUniform = shader->uniform("projection"); + + shader->use(); + shader->setUniformMtx(projUniform, projectionMatrix); + shader->setUniformMtx(viewUniform, viewMatrix); + + auto entities = world.find<T>(); + for (const auto &entity : entities) { + + // ensure that the model pipeline actually exists... + const auto &model = world.get<T>(entity); + + // set model transform + const auto &transform = world.get<math::Transform>(entity); + shader->setUniformMtx(modelUniform, transform.model()); + + // render model + model.draw(); + } + } + + MeshData upload_mesh(const mesh::Mesh3D& meshComponent); + std::vector<MeshData> upload_multi_mesh(const mesh::MultiMesh3D& meshComponent); + +} // namespace fggl::gfx::ogl4 + +#endif //FGGL_GFX_OGL4_MESHES_HPP diff --git a/include/fggl/gfx/ogl4/models.hpp b/include/fggl/gfx/ogl4/models.hpp index 6a8beb1..bf58fdd 100644 --- a/include/fggl/gfx/ogl4/models.hpp +++ b/include/fggl/gfx/ogl4/models.hpp @@ -27,13 +27,14 @@ #include "fggl/gfx/ogl/types.hpp" #include "fggl/data/model.hpp" +#include "fggl/mesh/mesh.hpp" + #include "fggl/assets/manager.hpp" #define FGGL_ALLOW_DEFERRED_UPLOAD namespace fggl::gfx::ogl4 { - const std::size_t NO_RESTART_IDX = 0; struct StaticModelGPU { std::shared_ptr<ogl::VertexArray> vao; @@ -41,7 +42,7 @@ namespace fggl::gfx::ogl4 { std::shared_ptr<ogl::ArrayBuffer> vertices; std::size_t elementCount; ogl::Primitive drawType = ogl::Primitive::TRIANGLE; - std::size_t restartIndex = NO_RESTART_IDX; + std::size_t restartIndex = ogl::NO_RESTART_IDX; }; struct StaticModelInstance { @@ -63,7 +64,7 @@ namespace fggl::gfx::ogl4 { std::size_t elementCount; ogl::Primitive drawType; - std::size_t restartIndex = NO_RESTART_IDX; + std::size_t restartIndex = ogl::NO_RESTART_IDX; }; class StaticModelRenderer { diff --git a/include/fggl/math/types.hpp b/include/fggl/math/types.hpp index b6c790d..795e665 100644 --- a/include/fggl/math/types.hpp +++ b/include/fggl/math/types.hpp @@ -61,7 +61,7 @@ namespace fggl::math { /** * A 4D unsigned integer vector. */ - using vec4ui = glm::ivec4; + using vec4ui = glm::uvec4; /** * A 3D floating-point vector. @@ -76,7 +76,7 @@ namespace fggl::math { /** * A 3D unsigned integer vector. */ - using vec3ui = glm::ivec3; + using vec3ui = glm::uvec3; /** * A 2D floating-point vector @@ -93,6 +93,10 @@ namespace fggl::math { */ using vec2ui = glm::uvec2; + using vec2b = glm::bvec2; + using vec3b = glm::bvec3; + using vec4b = glm::bvec4; + /** * A 2x2 floating-point matrix. */ diff --git a/include/fggl/mesh/components.hpp b/include/fggl/mesh/components.hpp new file mode 100644 index 0000000..ea1630a --- /dev/null +++ b/include/fggl/mesh/components.hpp @@ -0,0 +1,55 @@ +/* + * This file is part of FGGL. + * + * FGGL is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * FGGL is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License along with FGGL. + * If not, see <https://www.gnu.org/licenses/>. + */ + +// +// Created by webpigeon on 22/10/22. +// FIXME HACKY IMPLEMENTATION DETAIL BECAUSE THE ASSET LOADING PIPELINE IS BAD +// + +#include "fggl/mesh/mesh.hpp" + +#ifndef FGGL_MESH_COMPONENTS_HPP +#define FGGL_MESH_COMPONENTS_HPP + +namespace fggl::mesh { + + struct StaticMesh3D { + constexpr static const char name[] = "StaticMesh3D"; + constexpr static const util::GUID guid = util::make_guid(name); + + util::GUID meshReference; + Mesh3D mesh; + std::string pipeline; + + inline StaticMesh3D() = default; + inline StaticMesh3D(const Mesh3D &aMesh, std::string aPipeline) : + mesh(aMesh), pipeline(std::move(aPipeline)) {} + }; + + struct StaticMultiMesh3D { + constexpr static const char name[] = "StaticMultiMesh3D"; + constexpr static const util::GUID guid = util::make_guid(name); + + util::GUID meshReference; + MultiMesh3D mesh; + std::string pipeline; + + inline StaticMultiMesh3D() = default; + inline StaticMultiMesh3D(const MultiMesh3D &aMesh, std::string aPipeline) : + mesh(aMesh), pipeline(std::move(aPipeline)) {} + }; + +} + +#endif //FGGL_MESH_COMPONENTS// _HPP diff --git a/include/fggl/mesh/mesh.hpp b/include/fggl/mesh/mesh.hpp new file mode 100644 index 0000000..8f0f898 --- /dev/null +++ b/include/fggl/mesh/mesh.hpp @@ -0,0 +1,61 @@ +/* + * This file is part of FGGL. + * + * FGGL is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * FGGL is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License along with FGGL. + * If not, see <https://www.gnu.org/licenses/>. + */ + +// +// Created by webpigeon on 18/10/22. +// + +#ifndef FGGL_MESH_MESH_HPP +#define FGGL_MESH_MESH_HPP + +#include "fggl/math/types.hpp" + +#include <vector> +#include <span> + +namespace fggl::mesh { + + struct Vertex3D { + math::vec3 position; + math::vec3 normal; + math::vec3 colour{ 1.0F, 1.0F, 1.0f }; + math::vec2 texPos{ 0.0F, 0.0F }; + }; + + struct Vertex2D { + math::vec2 position; + math::vec2 colour; + math::vec2 texPos; + }; + + template<typename VertexFormat> + struct Mesh { + std::vector<VertexFormat> data; + std::vector<uint32_t> indices; + }; + + template<typename MeshFormat> + struct MultiMesh { + std::vector<MeshFormat> meshes; + }; + + using Mesh2D = Mesh<Vertex2D>; + using MultiMesh2D = MultiMesh<Mesh2D>; + + using Mesh3D = Mesh<Vertex3D>; + using MultiMesh3D = MultiMesh<Mesh3D>; + +} + +#endif //FGGL_MESH_MESH_HPP -- GitLab