diff --git a/demo/main.cpp b/demo/main.cpp index 07cb316a8d693122d1903cd0676ac795d802b9c6..0fc4475731a419efc5c4305dc7ab709917bc1378 100644 --- a/demo/main.cpp +++ b/demo/main.cpp @@ -5,10 +5,9 @@ #include <iostream> #include <fggl/gfx/window.hpp> -#include <fggl/gfx/ogl.hpp> -#include <fggl/gfx/renderer.hpp> -#include <fggl/gfx/shader.hpp> #include <fggl/gfx/camera.hpp> +#include <fggl/gfx/ogl/compat.hpp> + #include <fggl/data/procedural.hpp> #include <fggl/ecs/ecs.hpp> #include <fggl/debug/debug.h> @@ -178,45 +177,24 @@ int main(int argc, char* argv[]) { win.title("FGGL Demo"); win.fullscreen( true ); - // opengl time - fggl::gfx::Graphics ogl(win); - fggl::gfx::MeshRenderer meshRenderer; - - // debug layer - fggl::debug::DebugUI debug(win); - debug.visible(true); + // setup ECS + fggl::ecs::ECS ecs; // storage API fggl::data::Storage storage; discover( storage.resolvePath(fggl::data::Data, "res") ); - fggl::gfx::ShaderCache cache(storage); - - fggl::gfx::ShaderConfig config; - config.name = "unlit"; - config.vertex = "unlit_vert.glsl"; - config.fragment = "unlit_frag.glsl"; - auto shader = cache.load(config); - - fggl::gfx::ShaderConfig configPhong; - configPhong.name = "phong"; - configPhong.vertex = configPhong.name + "_vert.glsl"; - configPhong.fragment = configPhong.name + "_frag.glsl"; -// configPhong.fragment = configPhong.name + "_normals_frag.glsl"; - auto shaderPhong = cache.load(configPhong); - - fggl::gfx::ShaderConfig configNormals; - configNormals.name = "normals"; - configNormals.hasGeom = true; - configNormals.vertex = configNormals.name + "_vert.glsl"; - configNormals.geometry = configNormals.name + "_geom.glsl"; - configNormals.fragment = configNormals.name + "_frag.glsl"; - auto shaderNormals = cache.load( configNormals ); + // Opengl APIs + auto glModule = fggl::gfx::ecsInitOpenGL(ecs, win, storage); + fggl::gfx::loadPipeline(glModule, "unlit", false); + fggl::gfx::loadPipeline(glModule, "phong", false); + fggl::gfx::loadPipeline(glModule, "normals", false); + + // debug layer + fggl::debug::DebugUI debug(win); + debug.visible(true); // create ECS - fggl::ecs::ECS ecs; - ecs.registerComponent<fggl::gfx::MeshToken>(); - ecs.registerComponent<fggl::gfx::Camera>(); ecs.registerComponent<fggl::math::Transform>(); // make camera @@ -231,11 +209,10 @@ int main(int argc, char* argv[]) { auto floorEnt = ecs.createEntity(); { ecs.addComponent<fggl::math::Transform>( floorEnt ); - fggl::data::Mesh mesh = fggl::data::make_quad_xz(); - auto token = meshRenderer.upload( mesh ); - auto bounds = ecs.addComponent<fggl::gfx::MeshToken>(floorEnt, token); + ecs.addComponent<fggl::gfx::StaticMesh>(floorEnt, mesh, "phong"); + fggl::gfx::onStaticMeshAdded(ecs, floorEnt, glModule); } int nCubes = 3; @@ -266,11 +243,11 @@ int main(int argc, char* argv[]) { fggl::data::make_slope( mesh, leftSlope ); fggl::data::make_slope( mesh, rightSlope ); } - mesh.removeDups(); - auto token = meshRenderer.upload( mesh ); - token.pipeline = shaderPhong; - ecs.addComponent<fggl::gfx::MeshToken>(entity, token); + ecs.addComponent<fggl::gfx::StaticMesh>(entity, mesh, "phong"); + + // pretend we have callbacks + fggl::gfx::onStaticMeshAdded(ecs, entity, glModule); } fggl::gfx::Input& input = fggl::gfx::Input::instance(); @@ -404,26 +381,14 @@ int main(int argc, char* argv[]) { }*/ // render step - ogl.clear(); - - // render using real shader - auto renderables = ecs.getEntityWith<fggl::gfx::MeshToken>(); - for ( auto renderable : renderables ) { - auto token = ecs.getComponent<fggl::gfx::MeshToken>(renderable); - token->pipeline = shaderPhong; - } - meshRenderer.render(win, ecs, camEnt, 16.0f); - - // render using normals shader - if ( showNormals ) { - for ( auto renderable : renderables ) { - auto token = ecs.getComponent<fggl::gfx::MeshToken>(renderable); - token->pipeline = shaderNormals; - } - meshRenderer.render(win, ecs, camEnt, 16.0f); - } + win.activate(); + glModule->ogl.clear(); + // model rendering system + fggl::gfx::renderMeshes(glModule, ecs, dt); debug.draw(); + + // swap the windows - frame rendering over win.swap(); } diff --git a/fggl/gfx/CMakeLists.txt b/fggl/gfx/CMakeLists.txt index 961857887e88901d4ec059d044e0f45ce0aaa1d2..0e81d51759fe6378d716ecc34227bf8d50db6fc7 100644 --- a/fggl/gfx/CMakeLists.txt +++ b/fggl/gfx/CMakeLists.txt @@ -3,19 +3,9 @@ target_sources(fggl PRIVATE window.cpp - renderer.cpp input.cpp - shader.cpp - ogl.cpp ) -# OpenGL Backend -find_package( OpenGL REQUIRED ) -include_directories( ${OPENGL_INCLUDE_DIR} ) -target_link_libraries(fggl OpenGL::OpenGL GLEW) +# OpenGL backend +add_subdirectory(ogl) -# GLEW -find_package( GLEW REQUIRED ) -include_directories( ${GLEW_INCLUDE_DIRS} ) - -find_package( glm REQUIRED ) diff --git a/fggl/gfx/common.hpp b/fggl/gfx/common.hpp new file mode 100644 index 0000000000000000000000000000000000000000..1192659b66c748eb1cbcc42f431d14e91f4fd28d --- /dev/null +++ b/fggl/gfx/common.hpp @@ -0,0 +1,25 @@ +#ifndef FGGL_GFX_COMMON_H +#define FGGL_GFX_COMMON_H + +// load the correct rendering backend (only opengl for now) +#include <fggl/gfx/ogl/common.hpp> + +// now it's safe to load the windowing system +#include <GLFW/glfw3.h> + +#include <fggl/data/model.hpp> +#include <string> + +namespace fggl::gfx { + + struct StaticMesh { + data::Mesh mesh; + std::string pipeline; + + inline StaticMesh(const data::Mesh& aMesh, const std::string& aPipeline) : + mesh(aMesh), pipeline(aPipeline) {} + }; + +} + +#endif diff --git a/fggl/gfx/ogl/CMakeLists.txt b/fggl/gfx/ogl/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..d746aebf88144248bb17bc9be0335717d56ebb84 --- /dev/null +++ b/fggl/gfx/ogl/CMakeLists.txt @@ -0,0 +1,19 @@ + +# Sources +target_sources(fggl + PRIVATE + backend.cpp + shader.cpp + renderer.cpp +) + +# OpenGL Backend +find_package( OpenGL REQUIRED ) +include_directories( ${OPENGL_INCLUDE_DIR} ) +target_link_libraries(fggl OpenGL::OpenGL GLEW) + +# GLEW +find_package( GLEW REQUIRED ) +include_directories( ${GLEW_INCLUDE_DIRS} ) + +find_package( glm REQUIRED ) diff --git a/fggl/gfx/ogl.cpp b/fggl/gfx/ogl/backend.cpp similarity index 92% rename from fggl/gfx/ogl.cpp rename to fggl/gfx/ogl/backend.cpp index 706420976ec6127f46b15038e4d6138111d26345..3585d91b3424dde33bf9ad9aa5bd1f85a1e50b17 100644 --- a/fggl/gfx/ogl.cpp +++ b/fggl/gfx/ogl/backend.cpp @@ -1,4 +1,4 @@ -#include <fggl/gfx/ogl.hpp> +#include <fggl/gfx/ogl/backend.hpp> #include <stdexcept> diff --git a/fggl/gfx/ogl.hpp b/fggl/gfx/ogl/backend.hpp similarity index 92% rename from fggl/gfx/ogl.hpp rename to fggl/gfx/ogl/backend.hpp index 0cc71387046c28988a34759825d3d140ffd49cf5..13075a1b78d1cf84c6ce03400638b1bca5fe4d55 100644 --- a/fggl/gfx/ogl.hpp +++ b/fggl/gfx/ogl/backend.hpp @@ -1,8 +1,8 @@ -#ifndef FGGL_GFX_OGL_H -#define FGGL_GFX_OGL_H +#ifndef FGGL_GFX_OGL_BACKEND_H +#define FGGL_GFX_OGL_BACKEND_H -#include "window.hpp" -#include "rendering.hpp" +#include <fggl/gfx/ogl/common.hpp> +#include <fggl/gfx/window.hpp> #include <stdexcept> diff --git a/fggl/gfx/rendering.cpp b/fggl/gfx/ogl/common.hpp similarity index 52% rename from fggl/gfx/rendering.cpp rename to fggl/gfx/ogl/common.hpp index 4577c57c8a6573d564f2a16af3e693143fc6b148..28786f54456740ddc12c6bdb53fb97b39e4b5417 100644 --- a/fggl/gfx/rendering.cpp +++ b/fggl/gfx/ogl/common.hpp @@ -1,11 +1,10 @@ -#ifndef FGGL_GFX_RENDERING_H -#define FGGL_GFX_RENDERING_H +#ifndef FGGL_GFX_OGL_COMMON_H +#define FGGL_GFX_OGL_COMMON_H /** * Ensure Graphics libraries are in the right order. */ #include <GL/glew.h> -#include <GLFW/glfw3.h> #endif diff --git a/fggl/gfx/ogl/compat.hpp b/fggl/gfx/ogl/compat.hpp new file mode 100644 index 0000000000000000000000000000000000000000..0cc905df047fd66ef6d4649a465bd1b8c36f2447 --- /dev/null +++ b/fggl/gfx/ogl/compat.hpp @@ -0,0 +1,98 @@ +#ifndef FGGL_GFX_OGL_COMPAT_H +#define FGGL_GFX_OGL_COMPAT_H +/** + * Legacy/Direct OpenGL calls. + * + * This shouldn't be exposed to the demo app, but the ECS we're using isn't smart enouph to allow us to + * abstract this yet. It's next thing on the list, but this branch is about cleaning up OpenGL not about + * extending our ECS. + * + * Should be removed when the engine has suitable abstractions in place. + */ + +#include <fggl/gfx/ogl/shader.hpp> +#include <fggl/gfx/ogl/renderer.hpp> + +#include <fggl/gfx/common.hpp> +#include <fggl/gfx/camera.hpp> +#include <fggl/ecs/ecs.hpp> + +namespace fggl::gfx { + + // + // fake module support - allows us to still RAII + // + struct ecsOpenGLModule { + fggl::gfx::Graphics ogl; + fggl::gfx::MeshRenderer renderer; + fggl::gfx::ShaderCache cache; + + inline ecsOpenGLModule(Window& window, fggl::data::Storage& storage) : + ogl(window), renderer(), cache(storage) { + } + }; + using OglModule = std::shared_ptr<ecsOpenGLModule>; + + // + // Loading related functions - should be handled in modules/data-driven + // + inline void loadPipeline(OglModule& mod, const std::string& name, bool hasGeom) { + fggl::gfx::ShaderConfig config; + config.name = name; + config.vertex = name+"_vert.glsl"; + config.fragment = name+"_frag.glsl"; + if ( hasGeom ) { + config.geometry = name+"_geom.glsl"; + } + mod->cache.load(config); + } + + inline void loadBasicPipeline(OglModule& mod, const std::string &name) { + loadPipeline(mod, name, false); + } + + // + // fake module/callbacks - our ECS doesn't have module/callback support yet. + // + inline void onStaticMeshAdded(ecs::ECS& ecs, ecs::entity_t entity, OglModule& mod) { + auto meshData = ecs.getComponent<gfx::StaticMesh>(entity); + auto pipeline = mod->cache.get(meshData->pipeline); + + auto glMesh = mod->renderer.upload(meshData->mesh); + glMesh.pipeline = pipeline; + + ecs.addComponent<fggl::gfx::GlRenderToken>(entity, glMesh); + } + + inline void renderMeshes(OglModule& mod, ecs::ECS& ecs, float dt) { + // get the camera + auto cameras = ecs.getEntityWith<fggl::gfx::Camera>(); + if ( cameras.empty() ) { + return; + } + auto camera = cameras[0]; + + // get the models + auto renderables = ecs.getEntityWith<fggl::gfx::GlRenderToken>(); + for ( auto renderable : renderables ) { + mod->renderer.render(ecs, camera, dt); + } + } + + inline void ecsInitGraphics(ecs::ECS& ecs) { + ecs.registerComponent<fggl::gfx::StaticMesh>(); + ecs.registerComponent<fggl::gfx::Camera>(); + } + + inline std::shared_ptr<ecsOpenGLModule> ecsInitOpenGL(ecs::ECS& ecs, Window& window, data::Storage& storage) { + ecsInitGraphics(ecs); + + auto mod = std::make_shared<ecsOpenGLModule>(window, storage); + ecs.registerComponent<fggl::gfx::GlRenderToken>(); + return mod; + } + +} + + +#endif diff --git a/fggl/gfx/renderer.cpp b/fggl/gfx/ogl/renderer.cpp similarity index 93% rename from fggl/gfx/renderer.cpp rename to fggl/gfx/ogl/renderer.cpp index a3febd7582606128fcb4d077c2e50b577d59f786..5c70dfd565b8608f3cafa65ad294526b24e7b669 100644 --- a/fggl/gfx/renderer.cpp +++ b/fggl/gfx/ogl/renderer.cpp @@ -1,9 +1,8 @@ -#include <fggl/gfx/renderer.hpp> -#include <fggl/gfx/rendering.hpp> -#include <fggl/gfx/camera.hpp> +#include <fggl/gfx/ogl/renderer.hpp> #include <fggl/data/model.hpp> +#include <fggl/gfx/camera.hpp> #include <glm/ext/matrix_transform.hpp> #include <glm/glm.hpp> #include <glm/gtc/type_ptr.hpp> @@ -67,7 +66,7 @@ GlRenderToken MeshRenderer::upload(fggl::data::Mesh& mesh) { return token; } -void MeshRenderer::render(const Window& window, const fggl::ecs::ECS& ecs, const ecs::entity_t camera, float dt) { +void MeshRenderer::render(const fggl::ecs::ECS& ecs, const ecs::entity_t camera, float dt) { if ( camera == ecs::NULL_ENTITY ) return; auto entities = ecs.getEntityWith<GlRenderToken>(); @@ -75,9 +74,6 @@ void MeshRenderer::render(const Window& window, const fggl::ecs::ECS& ecs, const total += dt; - // make sure the correct rendering context is active - window.activate(); - glEnable(GL_CULL_FACE); glCullFace(GL_BACK); diff --git a/fggl/gfx/renderer.hpp b/fggl/gfx/ogl/renderer.hpp similarity index 76% rename from fggl/gfx/renderer.hpp rename to fggl/gfx/ogl/renderer.hpp index 1772e2f4e6ad4d8a00c121399896be08ab9c29e1..cac965a67f4e041caf9b7ce28d84748a14d94bcf 100644 --- a/fggl/gfx/renderer.hpp +++ b/fggl/gfx/ogl/renderer.hpp @@ -5,7 +5,7 @@ #include <fggl/data/model.hpp> #include <fggl/ecs/ecs.hpp> -#include <fggl/gfx/ogl.hpp> +#include <fggl/gfx/ogl/backend.hpp> namespace fggl::gfx { @@ -23,8 +23,7 @@ namespace fggl::gfx { token_t upload(fggl::data::Mesh& mesh); - // are VAO safe across opengl contexts? :S - void render(const Window& window, const ecs::ECS& ecs, const ecs::entity_t camera, float dt); + void render(const ecs::ECS& ecs, const ecs::entity_t camera, float dt); float total; }; diff --git a/fggl/gfx/shader.cpp b/fggl/gfx/ogl/shader.cpp similarity index 99% rename from fggl/gfx/shader.cpp rename to fggl/gfx/ogl/shader.cpp index 144bfa7cefa884cb9bf3da669822545e7c04a9a1..59a10e57f19d1182fb4e616b834f0c0defa5de3a 100644 --- a/fggl/gfx/shader.cpp +++ b/fggl/gfx/ogl/shader.cpp @@ -1,5 +1,5 @@ -#include <fggl/gfx/shader.hpp> +#include <fggl/gfx/ogl/shader.hpp> #include <iostream> #include <vector> diff --git a/fggl/gfx/shader.hpp b/fggl/gfx/ogl/shader.hpp similarity index 97% rename from fggl/gfx/shader.hpp rename to fggl/gfx/ogl/shader.hpp index e66f9399fdee09e03648e43f9279d5c691d97a7b..4e06dbd41399b6d79ac4ba1b2e3820f2acd07675 100644 --- a/fggl/gfx/shader.hpp +++ b/fggl/gfx/ogl/shader.hpp @@ -2,7 +2,7 @@ #define FGGL_GFX_SHADER_H #include <cstdio> -#include <fggl/gfx/ogl.hpp> +#include <fggl/gfx/ogl/backend.hpp> #include <fggl/data/storage.hpp> #include <filesystem> diff --git a/fggl/gfx/rendering.hpp b/fggl/gfx/rendering.hpp deleted file mode 100644 index 4577c57c8a6573d564f2a16af3e693143fc6b148..0000000000000000000000000000000000000000 --- a/fggl/gfx/rendering.hpp +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef FGGL_GFX_RENDERING_H -#define FGGL_GFX_RENDERING_H - -/** - * Ensure Graphics libraries are in the right order. - */ - -#include <GL/glew.h> -#include <GLFW/glfw3.h> - -#endif diff --git a/fggl/gfx/window.hpp b/fggl/gfx/window.hpp index eaff91042567c14716556f0769a34d487af0382b..eaa80386f58b30273ec0d024f7e67c4efe802b4a 100644 --- a/fggl/gfx/window.hpp +++ b/fggl/gfx/window.hpp @@ -4,8 +4,8 @@ #include <cassert> #include <string> +#include <fggl/gfx/common.hpp> #include <fggl/math/types.hpp> -#include <fggl/gfx/rendering.hpp> #include <fggl/gfx/input.hpp> namespace fggl::gfx {