diff --git a/build.sh b/build.sh index 9530b5d70bc35277b9659b6d2f95f93f9e674b4b..183ef6d175ae05155b3fd8482126998afdc96c31 100755 --- a/build.sh +++ b/build.sh @@ -2,7 +2,7 @@ CACHE=/tmp/fggl/ LOG=$CACHE/demo.log -EXE="../builds/cli/demo/FgglDemo" +EXE="../builds/cli/bin/FgglDemo" # check build directory exists if [[ ! -d "builds/cli/" ]] diff --git a/demo/main.cpp b/demo/main.cpp index 067388dbbd7b75da63568df5dc3917b30763ade5..90a71da6b1f60f589672b1ba40361dc5836195e7 100644 --- a/demo/main.cpp +++ b/demo/main.cpp @@ -292,9 +292,13 @@ public: void render(fggl::gfx::Paint& paint) override { //debugInspector(); - fggl::gfx::renderMeshes(glModule, *m_world, m_sceneTime->delta()); + //fggl::gfx::renderMeshes(glModule, *m_world, m_sceneTime->delta()); } + fggl::ecs3::World* world() override { + return m_world.get(); + } + // entity inspector void debugInspector() { auto types = m_world->types(); diff --git a/fggl/app.cpp b/fggl/app.cpp index c74cea5a3c356ee3f41eb52f6689eb76acf32561..5ca623b73d3db732cd8d9d3a6938916b83193989 100644 --- a/fggl/app.cpp +++ b/fggl/app.cpp @@ -48,6 +48,11 @@ namespace fggl { auto& graphics = m_window->graphics(); graphics.draw2D( paint ); + ecs3::World* world = state.world(); + if ( world != nullptr ) { + graphics.drawScene(*world); + } + m_window->frameEnd(); m_modules->onFrameEnd(); diff --git a/fggl/gfx/ogl/renderer.cpp b/fggl/gfx/ogl/renderer.cpp index fea729595b907ee814b66416a428775e41cb5fa2..a889a96cbfe1ee21d106754ab3f0732993d4ee78 100644 --- a/fggl/gfx/ogl/renderer.cpp +++ b/fggl/gfx/ogl/renderer.cpp @@ -173,10 +173,12 @@ namespace fggl::gfx { // setup 2D rendering system ShaderConfig shader2DConfig = ShaderFromName("shader2D"); m_cache->load(shader2DConfig); + ShaderConfig shader3DConfig = ShaderFromName("phong"); + m_cache->load(shader3DConfig); // rendering helpers m_canvasRenderer = std::make_unique<ogl4::CanvasRenderer>(); - m_modelRenderer = std::make_unique<ogl4::StaticModelRenderer>(); + m_modelRenderer = std::make_unique<ogl4::StaticModelRenderer>(m_cache.get()); }; void OpenGL4Backend::clear() { @@ -193,6 +195,12 @@ namespace fggl::gfx { m_canvasRenderer->render(shader2D, paint); } + void OpenGL4Backend::drawScene(ecs3::World &world) { + if ( m_modelRenderer ) { + m_modelRenderer->render(world); + } + } + void OpenGL4Backend::resize(int width, int height) { glViewport(0, 0, width, height); } @@ -305,7 +313,6 @@ namespace fggl::gfx { glEnable(GL_PRIMITIVE_RESTART); glPrimitiveRestartIndex(mesh->restartVertex); } - glDrawElements(mesh->renderType, mesh->idxSize, GL_UNSIGNED_INT, reinterpret_cast<void *>(mesh->idxOffset)); if (mesh->renderType == GlRenderType::triangle_strip) { diff --git a/fggl/gfx/ogl4/CMakeLists.txt b/fggl/gfx/ogl4/CMakeLists.txt index b66df9424352f3ff782db0bf27e3622ee99fdb16..0b9e81784f74f840f0b28ac7a9c609bc346aba38 100644 --- a/fggl/gfx/ogl4/CMakeLists.txt +++ b/fggl/gfx/ogl4/CMakeLists.txt @@ -3,4 +3,5 @@ target_sources(fggl PRIVATE canvas.cpp + models.cpp ) diff --git a/fggl/gfx/ogl4/canvas.cpp b/fggl/gfx/ogl4/canvas.cpp index 8a51333b2de1780fec04a61abbe8777f54e07372..548dc152acf8f239f8d3c410d3ac858acf383b6a 100644 --- a/fggl/gfx/ogl4/canvas.cpp +++ b/fggl/gfx/ogl4/canvas.cpp @@ -109,6 +109,11 @@ namespace fggl::gfx::ogl4 { data::Mesh2D mesh; convert_to_mesh(paint, mesh); + // nothing to render? give up + if ( mesh.indexList.empty() ){ + return; + } + // update data m_vao.bind(); m_vertexList.replace(mesh.vertexList.size(), mesh.vertexList.data()); diff --git a/fggl/gfx/ogl4/models.cpp b/fggl/gfx/ogl4/models.cpp index b752d307728816dc5a89496e3328c159b96e56e8..177d95d7343b557cd55535dd98cabced7cc7be17 100644 --- a/fggl/gfx/ogl4/models.cpp +++ b/fggl/gfx/ogl4/models.cpp @@ -23,6 +23,8 @@ // #include "fggl/gfx/ogl4/models.hpp" +#include "fggl/data/heightmap.h" + #include "fggl/gfx/camera.hpp" #include <spdlog/spdlog.h> @@ -30,15 +32,97 @@ namespace fggl::gfx::ogl4 { void StaticModelRenderer::resolveModels(ecs3::World &world) { // FIXME: this needs something reactive or performance will suck. - auto renderables = world.findMatching<StaticModel>(); - + auto renderables = world.findMatching<gfx::StaticMesh>(); for (auto& renderable : renderables){ auto currModel = world.get<StaticModel>( renderable ); if ( currModel != nullptr ){ continue; } + auto* meshComp = world.get<gfx::StaticMesh>(renderable); + + // create a vao to store the mesh + auto vao = std::make_shared< ogl::VertexArray >(); + vao->bind(); + + // setup the mesh buffer stuff + auto meshToUpload = meshComp->mesh; + auto meshBuffer = std::make_shared<ogl::ArrayBuffer>(); + + spdlog::info("mesh data to upload: {}", meshToUpload.vertexCount()); + meshBuffer->write(meshToUpload.vertexCount() * sizeof(data::Vertex), meshToUpload.vertexList().data(), ogl::BufUsage::STATIC_DRAW); + + // set up the vertex attributes + auto posAttr = ogl::attribute<data::Vertex, math::vec3>(offsetof(data::Vertex, posititon)); + auto normalAttr = ogl::attribute<data::Vertex, math::vec3>(offsetof(data::Vertex, normal)); + auto colAttr = ogl::attribute<data::Vertex, math::vec3>(offsetof(data::Vertex, colour)); + + vao->setAttribute( *meshBuffer.get(), 0, posAttr ); + vao->setAttribute( *meshBuffer.get(), 1, normalAttr ); + vao->setAttribute( *meshBuffer.get(), 3, colAttr ); + + // set up the element attributes + auto elementBuffer = std::make_shared<ogl::ElementBuffer>(); + elementBuffer->write(meshToUpload.indexCount() * sizeof(uint32_t), meshToUpload.indexList().data(), ogl::BufUsage::STATIC_DRAW); + + auto* modelComp = world.add<StaticModel>(renderable); + modelComp->vao = vao; + modelComp->vertexData = meshBuffer; + modelComp->elements = elementBuffer; + modelComp->pipeline = m_phong; + modelComp->elementCount = meshToUpload.indexCount(); + modelComp->drawType = ogl::Primative::TRIANGLE; + + // no active model, we need to resolve/load one. + spdlog::info("looks like {} needs a static mesh", renderable); + } + + // terrain + auto terrain = world.findMatching<data::HeightMap>(); + for (auto& renderable : terrain){ + auto currModel = world.get<StaticModel>( renderable ); + if ( currModel != nullptr ){ + continue; + } + + auto* heightmap = world.get<data::HeightMap>(renderable); + + // create a vao to store the mesh + auto vao = std::make_shared< ogl::VertexArray >(); + vao->bind(); + + // setup the mesh buffer stuff + data::Mesh meshToUpload{}; + data::generateHeightMesh(heightmap, meshToUpload); + auto meshBuffer = std::make_shared<ogl::ArrayBuffer>(); + + spdlog::info("mesh data to upload: {}", meshToUpload.vertexCount()); + meshBuffer->write(meshToUpload.vertexCount() * sizeof(data::Vertex), meshToUpload.vertexList().data(), ogl::BufUsage::STATIC_DRAW); + + // set up the vertex attributes + auto posAttr = ogl::attribute<data::Vertex, math::vec3>(offsetof(data::Vertex, posititon)); + auto normalAttr = ogl::attribute<data::Vertex, math::vec3>(offsetof(data::Vertex, normal)); + auto colAttr = ogl::attribute<data::Vertex, math::vec3>(offsetof(data::Vertex, colour)); + + vao->setAttribute( *meshBuffer.get(), 0, posAttr ); + vao->setAttribute( *meshBuffer.get(), 1, normalAttr ); + vao->setAttribute( *meshBuffer.get(), 3, colAttr ); + + // set up the element attributes + auto elementBuffer = std::make_shared<ogl::ElementBuffer>(); + elementBuffer->write(meshToUpload.indexCount() * sizeof(uint32_t), meshToUpload.indexList().data(), ogl::BufUsage::STATIC_DRAW); + + auto* modelComp = world.add<StaticModel>(renderable); + modelComp->vao = vao; + modelComp->vertexData = meshBuffer; + modelComp->elements = elementBuffer; + modelComp->pipeline = m_phong; + modelComp->elementCount = meshToUpload.indexCount(); + modelComp->drawType = ogl::Primative::TRIANGLE_STRIP; + modelComp->restartIndex = meshToUpload.restartVertex; + // no active model, we need to resolve/load one. + spdlog::info("looks like heightmap, {} needs a static mesh", renderable); } } @@ -57,7 +141,6 @@ namespace fggl::gfx::ogl4 { // perform a rendering pass for each camera (will usually only be one...) for ( auto& cameraEnt : cameras ){ - //TODO should be cliping this to only visible objects // enable required OpenGL state @@ -75,8 +158,7 @@ namespace fggl::gfx::ogl4 { math::mat4 viewMatrix = glm::lookAt( camTransform->origin(), camComp->target, camTransform->up() ); // TODO lighting needs to not be this... - math::vec3 lightPos{1.0f, 1.0f, 1.0f}; - math::mat4 modelMatrix(1.0f); + math::vec3 lightPos{20.0f, 20.0f, 15.0f}; auto renderables = world.findMatching<StaticModel>(); for ( const auto& entity : renderables ){ @@ -86,16 +168,35 @@ namespace fggl::gfx::ogl4 { // grouping by shader would mean we only need to send the model matrix... // TODO clean shader API auto shader = model->pipeline; + if ( shader == nullptr ) { + spdlog::warn("shader was null, aborting render"); + return; + } + shader->use(); - shader->setUniformMtx(shader->uniform("model"), &modelMatrix, 1); - shader->setUniformMtx(shader->uniform("view"), &viewMatrix, 1); - shader->setUniformMtx(shader->uniform("projection"), &projectionMatrix, 1); + shader->setUniformMtx(shader->uniform("model"), transform->model()); + shader->setUniformMtx(shader->uniform("view"), viewMatrix); + shader->setUniformMtx(shader->uniform("projection"), projectionMatrix); + + auto lightPosIdx = shader->uniform("lightPos"); + if ( lightPosIdx != -1 ) { + shader->setUniformF(lightPosIdx, lightPos); + } auto vao = model->vao; + vao->bind(); + + model->vertexData->bind(); - // TODO support primitive restart/fans/etc... + if ( model->restartIndex != 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) { + glDisable(GL_PRIMITIVE_RESTART); + } } } diff --git a/include/fggl/app.hpp b/include/fggl/app.hpp index b3f15053612ede7dfee60ad6a8fb67e7f064ed2f..a73989c137bc70e0a103cc204650ffe881731e8e 100644 --- a/include/fggl/app.hpp +++ b/include/fggl/app.hpp @@ -82,6 +82,10 @@ namespace fggl { virtual void deactivate() {} + inline virtual ecs3::World* world() { + return nullptr; + } + protected: App &m_owner; }; diff --git a/include/fggl/gfx/ogl/renderer.hpp b/include/fggl/gfx/ogl/renderer.hpp index 24c0ab1824c2ae3acbf198a7090b917354192950..a07cbaba16a59fe0e07f11103fed8af9f1cba288 100644 --- a/include/fggl/gfx/ogl/renderer.hpp +++ b/include/fggl/gfx/ogl/renderer.hpp @@ -57,6 +57,7 @@ namespace fggl::gfx { void resize(int width, int height) override; void draw2D(const Paint &paint) override; + void drawScene(ecs3::World& world) override; private: std::unique_ptr<ogl4::StaticModelRenderer> m_modelRenderer; diff --git a/include/fggl/gfx/ogl/types.hpp b/include/fggl/gfx/ogl/types.hpp index e878cf0f3adb06f685ac0ea0d719e3922e51d0b9..f84e46573100e530e9cd0b78cb6a1b9fd99767ef 100644 --- a/include/fggl/gfx/ogl/types.hpp +++ b/include/fggl/gfx/ogl/types.hpp @@ -29,6 +29,7 @@ #include <cassert> #include <string_view> #include <iostream> +#include <glm/gtc/type_ptr.hpp> #include "fggl/gfx/ogl/common.hpp" #include "fggl/math/types.hpp" @@ -49,6 +50,9 @@ namespace fggl::gfx::ogl { void release(); public: + Shader() = default; + inline Shader(GLuint obj) : m_obj(obj) {} + // copy constructor bad Shader(const Shader&) = delete; Shader& operator=(const Shader&) = delete; @@ -57,35 +61,64 @@ namespace fggl::gfx::ogl { Shader(Shader&& other); Shader& operator=(Shader&& other); - void use(); + void use() { + glUseProgram( m_obj ); + } - Location uniform(const std::string_view& name) const; + inline Location uniform(const std::string_view& name) const { + return glGetUniformLocation( m_obj, name.data() ); + } // primatives - void setUniformF(Location name, GLfloat value); - void setUniformI(Location name, GLint value); - void setUniformU(Location name, GLuint value); + inline void setUniformF(Location name, GLfloat value) { + glProgramUniform1f(m_obj, name, value); + } + inline void setUniformI(Location name, GLint value) { + glProgramUniform1i(m_obj, name, value); + } + + inline void setUniformU(Location name, GLuint value) { + glProgramUniform1ui(m_obj, name, value); + } // vector versions (float) - void setUniformF(Location name, math::vec2f value); - void setUniformF(Location name, math::vec3f value); - void setUniformF(Location name, math::vec4f value); - void setUniformF(Location name, const math::vec2f* value, GLsizei size); - void setUniformF(Location name, const math::vec3f* value, GLsizei size); - void setUniformF(Location name, const math::vec4f* value, GLsizei size); + inline void setUniformF(Location name, math::vec2f value) { + glProgramUniform2f(m_obj, name, value.x, value.y); + } + + inline void setUniformF(Location name, math::vec3f value) { + glProgramUniform3f(m_obj, name, value.x, value.y, value.z); + } + + inline void setUniformF(Location name, math::vec4f value) { + glProgramUniform4f(m_obj, name, value.x, value.y, value.z, value.w); + } // vector versions (int) - void setUniformI(Location name, math::vec2i value); - void setUniformI(Location name, math::vec3i value); - void setUniformI(Location name, math::vec4i value); - void setUniformI(Location name, const math::vec2i* value, GLsizei size); - void setUniformI(Location name, const math::vec3i* value, GLsizei size); - void setUniformI(Location name, const math::vec4i* value, GLsizei size); + inline void setUniformI(Location name, math::vec2i value) { + glProgramUniform2i(m_obj, name, value.x, value.y); + } + + inline void setUniformI(Location name, math::vec3i value) { + glProgramUniform3i(m_obj, name, value.x, value.y, value.z); + } + + inline void setUniformI(Location name, math::vec4i value) { + glProgramUniform4i(m_obj, name, value.x, value.y, value.z, value.w); + } // matrix versions - void setUniformMtx(Location name, const math::mat2*, GLsizei count); - void setUniformMtx(Location name, const math::mat3*, GLsizei count); - void setUniformMtx(Location name, const math::mat4*, GLsizei count); + inline void setUniformMtx(Location name, const math::mat2& mtx) { + glProgramUniformMatrix2fv(m_obj, name, 1, GL_FALSE, glm::value_ptr(mtx)); + } + + void setUniformMtx(Location name, const math::mat3& mtx) { + glProgramUniformMatrix3fv(m_obj, name, 1, GL_FALSE, glm::value_ptr(mtx)); + } + + void setUniformMtx(Location name, const math::mat4& mtx) { + glProgramUniformMatrix4fv(m_obj, name, 1, GL_FALSE, glm::value_ptr(mtx)); + } }; enum class BuffAttrF { diff --git a/include/fggl/gfx/ogl4/models.hpp b/include/fggl/gfx/ogl4/models.hpp index 8ae6fa1c37966adcaf9e59c1ac2e65f7d1777edd..1f5a9c0160f46212445f8a5c489f60e028320c5e 100644 --- a/include/fggl/gfx/ogl4/models.hpp +++ b/include/fggl/gfx/ogl4/models.hpp @@ -8,27 +8,35 @@ #include <string> #include <unordered_map> +#include "fggl/gfx/ogl/shader.hpp" #include "fggl/gfx/ogl/backend.hpp" #include "fggl/gfx/ogl/types.hpp" #include "fggl/ecs3/ecs.hpp" namespace fggl::gfx::ogl4 { + const std::size_t NO_RESTART_IDX = 0; + struct StaticModel { - constexpr static const char name[] = "StaticModel"; + constexpr static auto name = "StaticModel"; std::shared_ptr<ogl::Shader> pipeline; - std::shared_ptr<ogl::VertexArray> vao; // element data + std::shared_ptr<ogl::VertexArray> vao; std::shared_ptr<ogl::ElementBuffer> elements; - ogl::Primative drawType; + std::shared_ptr<ogl::ArrayBuffer> vertexData; std::size_t elementCount; + + ogl::Primative drawType; + std::size_t restartIndex = NO_RESTART_IDX; }; class StaticModelRenderer { public: - StaticModelRenderer() = default; + inline StaticModelRenderer(gfx::ShaderCache* cache) : m_shaders(cache), m_phong(nullptr), m_vao(), m_vertexList(), m_indexList() { + m_phong = std::make_shared<ogl::Shader>( cache->get("phong") ); + } ~StaticModelRenderer() = default; StaticModelRenderer(const StaticModelRenderer& other) = delete; @@ -53,6 +61,8 @@ namespace fggl::gfx::ogl4 { */ void renderModelsForward(const ecs3::World& world); + gfx::ShaderCache* m_shaders; + std::shared_ptr< ogl::Shader > m_phong; ogl::VertexArray m_vao; ogl::ArrayBuffer m_vertexList; ogl::ElementBuffer m_indexList; diff --git a/include/fggl/gfx/windowing.hpp b/include/fggl/gfx/windowing.hpp index a307896d9dafc7e2db6650f53d2d4fb23e6a8e0e..45866bc46edb4e8b867d9fbfe35e59cc1b6a7524 100644 --- a/include/fggl/gfx/windowing.hpp +++ b/include/fggl/gfx/windowing.hpp @@ -4,6 +4,7 @@ #include <memory> #include <fggl/gfx/paint.hpp> +#include "fggl/ecs3/ecs.hpp" namespace fggl::gfx { @@ -14,6 +15,7 @@ namespace fggl::gfx { virtual void resize(int width, int height) = 0; virtual void draw2D(const Paint &paint) = 0; + virtual void drawScene(ecs3::World&) = 0; }; class Window {