diff --git a/src/examples/demo/DemoApp.h b/src/examples/demo/DemoApp.h index 622fac9..e05323c 100644 --- a/src/examples/demo/DemoApp.h +++ b/src/examples/demo/DemoApp.h @@ -31,7 +31,7 @@ namespace DemoAppGLFWCallbacks void cursorPos(GLFWwindow* window, double xpos, double ypos); void scroll(GLFWwindow* window, double xoffset, double yoffset); -} +} // namespace DemoAppGLFWCallbacks class DemoApp : public system::BaseApp { @@ -42,254 +42,263 @@ class DemoApp : public system::BaseApp struct { - double lastX, lastY; + double lastX, lastY; } m_MouseState; lepus::gfx::Camera m_Camera; - virtual void Init(void callback()) {}; + virtual void Init(void callback()){}; struct KeyboardState { - bool w = false, a = false, s = false, d = false, e = false; + bool w = false, a = false, s = false, d = false, e = false; }; struct { - lepus::math::Matrix4x4 projMatrix, viewMatrix; + lepus::math::Matrix4x4 projMatrix, viewMatrix; } m_UniformState; public: DemoApp() { - m_FOV = 0.f; + m_FOV = 0.f; - m_MouseState = - { - -1.0, -1.0 - }; + m_MouseState = + { + -1.0, -1.0}; - m_Camera = lepus::gfx::Camera(); + m_Camera = lepus::gfx::Camera(); - Init(); + Init(); } inline void Init() { - assert(!m_Initialised); + assert(!m_Initialised); - // Enable logging - engine::ConsoleLogger::Global().Enabled = true; + // Enable logging + engine::ConsoleLogger::Global().Enabled = true; - m_Initialised = true; + m_Initialised = true; - DemoAppGLFWCallbacks::_demoApp = this; + DemoAppGLFWCallbacks::_demoApp = this; } inline void OnMouseMove(double xpos, double ypos) { - float deltaX = (xpos - m_MouseState.lastX) / 300.0; - float deltaY = (ypos - m_MouseState.lastY) / 300.0; - lepus::types::Quaternion rotationYaw = lepus::types::Quaternion(0.f, 1.f, 0.f, -deltaX); - - auto combined = rotationYaw; - float angle = combined.Angle(); - if (abs(angle) > 0.001f) - { - m_Camera.Transform().Rotate(rotationYaw); - } - lepus::types::Quaternion rotationPitch = lepus::types::Quaternion(m_Camera.Transform().Right(), -deltaY); - angle = rotationPitch.Angle(); - if (abs(angle) > 0.001f) - { - m_Camera.Transform().Rotate(rotationPitch); - } - - m_MouseState.lastX = xpos; - m_MouseState.lastY = ypos; + float deltaX = (xpos - m_MouseState.lastX) / 300.0; + float deltaY = (ypos - m_MouseState.lastY) / 300.0; + lepus::types::Quaternion rotationYaw = lepus::types::Quaternion(0.f, 1.f, 0.f, -deltaX); + + auto combined = rotationYaw; + float angle = combined.Angle(); + if (abs(angle) > 0.001f) + { + m_Camera.Transform().Rotate(rotationYaw); + } + lepus::types::Quaternion rotationPitch = lepus::types::Quaternion(m_Camera.Transform().Right(), -deltaY); + angle = rotationPitch.Angle(); + if (abs(angle) > 0.001f) + { + m_Camera.Transform().Rotate(rotationPitch); + } + + m_MouseState.lastX = xpos; + m_MouseState.lastY = ypos; } inline void OnScroll(double xoffset, float yoffset) { - m_FOV = fmax(1.f, fmin(179.f, m_FOV + (float)yoffset)); - engine::ConsoleLogger::Global().LogInfo("", "scrollCallback", "yoffset", std::to_string(xoffset).append(", ").append(std::to_string(yoffset)).append("FOV: ").append(std::to_string(m_FOV)).c_str()); + m_FOV = fmax(1.f, fmin(179.f, m_FOV + (float)yoffset)); + engine::ConsoleLogger::Global().LogInfo("", "scrollCallback", "yoffset", std::to_string(xoffset).append(", ").append(std::to_string(yoffset)).append("FOV: ").append(std::to_string(m_FOV)).c_str()); } inline int Run() override { - std::shared_ptr windowing = std::make_shared(800, 600); - - // Create new graphics engine instance - gfx::GraphicsApiGLOptions options = {}; - options.mainViewport = { 800, 600 }; - gfx::GraphicsEngine engine(&options, windowing); - - // Termination condition for main loop - bool isRunning = true; - - // Set the window as the current OpenGL context. - windowing->SetAsCurrentContext(); - - // Output start message to console - engine::ConsoleLogger::Global().LogInfo("", "main", "Demo starting!"); - - // Load & compile shaders. - std::string vertShaderSrc = system::FileSystem::Read("../../Content/GLSL/Unlit/RGBVertex.vert"), fragShaderSrc = system::FileSystem::Read("../../Content/GLSL/Unlit/RGBVertex.frag"); - gfx::ShaderCompiledResult - vertShader = gfx::ShaderCompilerGLSL::Singleton().CompileShader(vertShaderSrc.c_str(), vertShaderSrc.length(), gfx::VertexShader), - fragShader = gfx::ShaderCompilerGLSL::Singleton().CompileShader(fragShaderSrc.c_str(), fragShaderSrc.length(), gfx::FragmentShader); - - // Register shader with the API. - auto& api = engine.GetApi(); - api.GetOptions().RegisterShader(&vertShader, &fragShader); - - // Set up engine for drawing. - engine.Setup(); - m_Camera.Transform().Origin(m_Camera.Transform().Forward() * -2.f); - - // Instantiate two Renderables in the scene graph, each with its own transform, using the same cube mesh data. - auto cubeMesh = lepus::gfx::GLMesh(lepus::utility::Primitives::Cube()); - auto cube = lepus::gfx::Renderable(&cubeMesh, lepus::math::Transform()); - auto cube2 = lepus::gfx::Renderable(&cubeMesh, lepus::math::Transform()); - auto cubeX = lepus::gfx::Renderable(&cubeMesh, lepus::math::Transform()); - auto cubeY = lepus::gfx::Renderable(&cubeMesh, lepus::math::Transform()); - auto cubeZ = lepus::gfx::Renderable(&cubeMesh, lepus::math::Transform()); - api.GetSceneGraph().AddChild(&cube); - api.GetSceneGraph().AddChild(&cube2); - api.GetSceneGraph().AddChild(&cubeX); - api.GetSceneGraph().AddChild(&cubeY); - api.GetSceneGraph().AddChild(&cubeZ); - - cubeX.GetTransform().SetPosition(-1.5f, 2.f, 0.f); - cubeY.GetTransform().SetPosition(0.f, 2.f, 0.f); - cubeZ.GetTransform().SetPosition(1.5f, 2.f, 0.f); - - // Update projection and view matrices with data from the camera object. - m_UniformState.projMatrix = m_Camera.BuildPerspectiveMatrix(); - ((lepus::gfx::GLMatrixUniformBinding*)api.GetUniform(LEPUS_GFX_UNIFORMS_GLOBAL_PROJECTION_MATRIX))->Value((float*)m_UniformState.projMatrix.data()); - m_UniformState.viewMatrix = m_Camera.BuildViewMatrix(); - ((lepus::gfx::GLMatrixUniformBinding*)api.GetUniform(LEPUS_GFX_UNIFORMS_GLOBAL_VIEW_MATRIX))->Value((float*)m_UniformState.viewMatrix.data()); - - // Initialise the FOV variable and set up a callback so we can let the user adjust it with the mouse scroll wheel. - m_FOV = m_Camera.FOV(); - glfwSetScrollCallback(reinterpret_cast(windowing->GetWindowPtr()), DemoAppGLFWCallbacks::scroll); - - float runningTime = glfwGetTime(); - - GLFWwindow* window = reinterpret_cast(windowing->GetWindowPtr()); - - // Set up mouse input for camera freelook. - glfwGetCursorPos(window, &m_MouseState.lastX, &m_MouseState.lastY); - glfwSetCursorPosCallback(reinterpret_cast(windowing->GetWindowPtr()), DemoAppGLFWCallbacks::cursorPos); - glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); - glfwSetInputMode(window, GLFW_RAW_MOUSE_MOTION, 1); - - // Initialise all keys as released. - KeyboardState keys = { false, false, false, false, false }; - - float deltaTime = 0.f; - // cube2.GetTransform().Rotate(lepus::types::Quaternion(lepus::types::Vector3(0.f, 0.f, 1.f), PI * 0.25f)); - - while (isRunning) - { - // lepus::engine::ConsoleLogger::Global().LogInfo("DemoApp", "Run", std::to_string(cube2.GetTransform().Rotation().w()).c_str()); - // lepus::engine::ConsoleLogger::Global().LogInfo("DemoApp", "Run", cube2.GetTransform().Rotation().Axis().ToString().c_str()); - cube2.GetTransform().SetPosition(1.f * sinf(runningTime), 1.f * cosf(runningTime), -1.f); - windowing->Update(); // Update window before drawing - - bool eKeyPressedLastFrame = keys.e; - UpdateInput(keys, windowing); - // cube.GetTransform().Rotate(lepus::types::Quaternion(lepus::types::Vector3(0.f, 1.f, 0.f), deltaTime)); - lepus::engine::ConsoleLogger::Global().LogInfo("DemoApp", "Tick", std::to_string(cube2.GetTransform().Rotation().w()).c_str()); - // lepus::engine::ConsoleLogger::Global().LogInfo("DemoApp", "Tick", std::to_string(cube2.GetTransform().Rotation().Angle()).c_str()); - cube2.GetTransform().Rotate(lepus::types::Quaternion(lepus::types::Vector3(1.f, 1.f, 1.f), deltaTime)); - cubeX.GetTransform().Rotate(lepus::types::Quaternion(lepus::types::Vector3(1.f, 0.f, 0.f), deltaTime)); - cubeY.GetTransform().Rotate(lepus::types::Quaternion(lepus::types::Vector3(0.f, 1.f, 0.f), deltaTime)); - cubeZ.GetTransform().Rotate(lepus::types::Quaternion(lepus::types::Vector3(0.f, 0.f, 1.f), deltaTime)); - if (!eKeyPressedLastFrame && keys.e) - { - // cube2.GetTransform().Rotate(lepus::types::Quaternion(lepus::types::Vector3(0.f, 0.f, 1.f), PI / 4.f)); - lepus::engine::ConsoleLogger::Global().LogInfo("DemoApp", "Run", std::to_string(cube2.GetTransform().Rotation().Angle() * (1.f / PI) * 180.f).c_str()); - } - Tick(deltaTime, keys); - UpdateUniforms(&api); - - engine.Render(100, 149, 237); - - float newRunningTime = glfwGetTime(); - deltaTime = newRunningTime - runningTime; - runningTime = newRunningTime; - - isRunning = windowing->Update(); - } - - Shutdown(windowing); - - return 0; + std::shared_ptr windowing = std::make_shared(800, 600); + + // Create new graphics engine instance + gfx::GraphicsApiGLOptions options = {}; + options.mainViewport = {800, 600}; + gfx::GraphicsEngine engine(&options, windowing); + + // Termination condition for main loop + bool isRunning = true; + + // Set the window as the current OpenGL context. + windowing->SetAsCurrentContext(); + + // Output start message to console + engine::ConsoleLogger::Global().LogInfo("", "main", "Demo starting!"); + + // Load & compile shaders. + std::string vertShaderSrc = system::FileSystem::Read("../../Content/GLSL/Unlit/RGBVertex.vert"), fragShaderSrc = system::FileSystem::Read("../../Content/GLSL/Unlit/RGBVertex.frag"); + gfx::ShaderCompiledResult + vertShader = gfx::ShaderCompilerGLSL::Singleton().CompileShader(vertShaderSrc.c_str(), vertShaderSrc.length(), gfx::VertexShader), + fragShader = gfx::ShaderCompilerGLSL::Singleton().CompileShader(fragShaderSrc.c_str(), fragShaderSrc.length(), gfx::FragmentShader); + + // Register shader with the API. + auto& api = engine.GetApi(); + api.GetOptions().RegisterShader(&vertShader, &fragShader); + + // Set up engine for drawing. + engine.Setup(); + m_Camera.Transform().Origin(m_Camera.Transform().Forward() * -2.f); + + // Instantiate two Renderables in the scene graph, each with its own transform, using the same cube mesh data. + auto cubeMesh = lepus::gfx::GLMesh(lepus::utility::Primitives::Cube()); + auto cube = lepus::gfx::Renderable(&cubeMesh, lepus::math::Transform()); + auto cube2 = lepus::gfx::Renderable(&cubeMesh, lepus::math::Transform()); + + // Also a cube to test each X-axis (pitch), Y-axis (yaw) and Z-axis (roll) rotation. + auto cubeX = lepus::gfx::Renderable(&cubeMesh, lepus::math::Transform()); + auto cubeY = lepus::gfx::Renderable(&cubeMesh, lepus::math::Transform()); + auto cubeZ = lepus::gfx::Renderable(&cubeMesh, lepus::math::Transform()); + // api.GetSceneGraph().AddChild(&cube); + api.GetSceneGraph().AddChild(&cube2); + api.GetSceneGraph().AddChild(&cubeX); + api.GetSceneGraph().AddChild(&cubeY); + api.GetSceneGraph().AddChild(&cubeZ); + + cubeX.GetTransform().SetPosition(-1.5f, 2.f, 0.f); + cubeY.GetTransform().SetPosition(0.f, 2.f, 0.f); + cubeZ.GetTransform().SetPosition(1.5f, 2.f, 0.f); + + // Update projection and view matrices with data from the camera object. + m_UniformState.projMatrix = m_Camera.BuildPerspectiveMatrix(); + ((lepus::gfx::GLMatrixUniformBinding*)api.GetUniform(LEPUS_GFX_UNIFORMS_GLOBAL_PROJECTION_MATRIX))->Value((float*)m_UniformState.projMatrix.data()); + m_UniformState.viewMatrix = m_Camera.BuildViewMatrix(); + ((lepus::gfx::GLMatrixUniformBinding*)api.GetUniform(LEPUS_GFX_UNIFORMS_GLOBAL_VIEW_MATRIX))->Value((float*)m_UniformState.viewMatrix.data()); + + // Initialise the FOV variable and set up a callback so we can let the user adjust it with the mouse scroll wheel. + m_FOV = m_Camera.FOV(); + glfwSetScrollCallback(reinterpret_cast(windowing->GetWindowPtr()), DemoAppGLFWCallbacks::scroll); + + float runningTime = glfwGetTime(); + + GLFWwindow* window = reinterpret_cast(windowing->GetWindowPtr()); + + // Set up mouse input for camera freelook. + glfwGetCursorPos(window, &m_MouseState.lastX, &m_MouseState.lastY); + glfwSetCursorPosCallback(reinterpret_cast(windowing->GetWindowPtr()), DemoAppGLFWCallbacks::cursorPos); + glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); + glfwSetInputMode(window, GLFW_RAW_MOUSE_MOTION, 1); + + // Initialise all keys as released. + KeyboardState keys = {false, false, false, false, false}; + + float deltaTime = 0.f; + // cube2.GetTransform().Rotate(lepus::types::Quaternion(lepus::types::Vector3(0.f, 0.f, 1.f), PI * 0.25f)); + + while (isRunning) + { + // lepus::engine::ConsoleLogger::Global().LogInfo("DemoApp", "Run", std::to_string(cube2.GetTransform().Rotation().w()).c_str()); + // lepus::engine::ConsoleLogger::Global().LogInfo("DemoApp", "Run", cube2.GetTransform().Rotation().Axis().ToString().c_str()); + cube2.GetTransform().SetPosition(1.f * sinf(runningTime), 1.f * cosf(runningTime), -1.f); + windowing->Update(); // Update window before drawing + + bool eKeyPressedLastFrame = keys.e; + UpdateInput(keys, windowing); + // cube.GetTransform().Rotate(lepus::types::Quaternion(lepus::types::Vector3(0.f, 1.f, 0.f), deltaTime)); + lepus::engine::ConsoleLogger::Global().LogInfo("DemoApp", "Tick", std::to_string(cube2.GetTransform().Rotation().w()).c_str()); + // lepus::engine::ConsoleLogger::Global().LogInfo("DemoApp", "Tick", std::to_string(cube2.GetTransform().Rotation().Angle()).c_str()); + // cube2.GetTransform().Rotate(lepus::types::Quaternion(lepus::types::Vector3(1.f, 1.f, 1.f), deltaTime)); + cubeX.GetTransform().Rotate(lepus::types::Quaternion(lepus::types::Vector3(1.f, 0.f, 0.f), deltaTime)); + cubeY.GetTransform().Rotate(lepus::types::Quaternion(lepus::types::Vector3(0.f, 1.f, 0.f), deltaTime)); + cubeZ.GetTransform().Rotate(lepus::types::Quaternion(lepus::types::Vector3(0.f, 0.f, 1.f), deltaTime)); + + cube2.GetTransform().SetScale(fabs(cosf(runningTime))); + // cube.GetTransform().SetScale(fabs(cosf(runningTime))); + + // cubeX.GetTransform().SetScale(fabs(cosf(runningTime))); + // cubeY.GetTransform().SetScale(fabs(cosf(runningTime))); + // cubeZ.GetTransform().SetScale(fabs(cosf(runningTime))); + + if (!eKeyPressedLastFrame && keys.e) + { + // cube2.GetTransform().Rotate(lepus::types::Quaternion(lepus::types::Vector3(0.f, 0.f, 1.f), PI / 4.f)); + lepus::engine::ConsoleLogger::Global().LogInfo("DemoApp", "Run", std::to_string(cube2.GetTransform().Rotation().Angle() * (1.f / PI) * 180.f).c_str()); + } + Tick(deltaTime, keys); + UpdateUniforms(&api); + + engine.Render(100, 149, 237); + + float newRunningTime = glfwGetTime(); + deltaTime = newRunningTime - runningTime; + runningTime = newRunningTime; + + isRunning = windowing->Update(); + } + + Shutdown(windowing); + + return 0; } inline void UpdateInput(KeyboardState& keys, std::shared_ptr windowing) { - GLFWwindow* window = (GLFWwindow*)windowing->GetWindowPtr(); + GLFWwindow* window = (GLFWwindow*)windowing->GetWindowPtr(); - keys.w = glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS; - keys.a = glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS; - keys.s = glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS; - keys.d = glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS; - keys.e = glfwGetKey(window, GLFW_KEY_E) == GLFW_RELEASE; + keys.w = glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS; + keys.a = glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS; + keys.s = glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS; + keys.d = glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS; + keys.e = glfwGetKey(window, GLFW_KEY_E) == GLFW_RELEASE; } inline void UpdateUniforms(gfx::GraphicsApi* api) { - m_UniformState.projMatrix = m_Camera.BuildPerspectiveMatrix(); - m_UniformState.viewMatrix = m_Camera.BuildViewMatrix(); + m_UniformState.projMatrix = m_Camera.BuildPerspectiveMatrix(); + m_UniformState.viewMatrix = m_Camera.BuildViewMatrix(); - ((lepus::gfx::GLMatrixUniformBinding*)api->GetUniform(LEPUS_GFX_UNIFORMS_GLOBAL_PROJECTION_MATRIX))->Value((float*)m_UniformState.projMatrix.data()); - ((lepus::gfx::GLMatrixUniformBinding*)api->GetUniform(LEPUS_GFX_UNIFORMS_GLOBAL_VIEW_MATRIX))->Value((float*)m_UniformState.viewMatrix.data()); + ((lepus::gfx::GLMatrixUniformBinding*)api->GetUniform(LEPUS_GFX_UNIFORMS_GLOBAL_PROJECTION_MATRIX))->Value((float*)m_UniformState.projMatrix.data()); + ((lepus::gfx::GLMatrixUniformBinding*)api->GetUniform(LEPUS_GFX_UNIFORMS_GLOBAL_VIEW_MATRIX))->Value((float*)m_UniformState.viewMatrix.data()); } inline void Tick(float deltaTime, const KeyboardState& keys) { - m_Camera.FOV(m_FOV); - - lepus::types::Vector3 forwardDelta, rightDelta; - - // Process camera movement input based on keyboard state. - if (keys.s) - { - forwardDelta = forwardDelta - (m_Camera.Transform().Forward() * deltaTime * _camSpeed); - } - if (keys.w) - { - forwardDelta = forwardDelta + (m_Camera.Transform().Forward() * deltaTime * _camSpeed); - } - if (keys.d) - { - rightDelta = rightDelta + (m_Camera.Transform().Right() * deltaTime * _camSpeed); - } - if (keys.a) - { - rightDelta = rightDelta - (m_Camera.Transform().Right() * deltaTime * _camSpeed); - } - - // lepus::engine::ConsoleLogger::Global().LogInfo("DemoApp", "Tick", m_Camera.Transform().Rotation().Axis().ToString().c_str()); - // lepus::engine::ConsoleLogger::Global().LogInfo("DemoApp", "Tick", std::to_string(m_Camera.Transform().Rotation().Angle() * (1.f / PI) * 180.f).c_str()); - - m_Camera.Transform().Origin(m_Camera.Transform().Origin() + forwardDelta + rightDelta); + m_Camera.FOV(m_FOV); + + lepus::types::Vector3 forwardDelta, rightDelta; + + // Process camera movement input based on keyboard state. + if (keys.s) + { + forwardDelta = forwardDelta - (m_Camera.Transform().Forward() * deltaTime * _camSpeed); + } + if (keys.w) + { + forwardDelta = forwardDelta + (m_Camera.Transform().Forward() * deltaTime * _camSpeed); + } + if (keys.d) + { + rightDelta = rightDelta + (m_Camera.Transform().Right() * deltaTime * _camSpeed); + } + if (keys.a) + { + rightDelta = rightDelta - (m_Camera.Transform().Right() * deltaTime * _camSpeed); + } + + // lepus::engine::ConsoleLogger::Global().LogInfo("DemoApp", "Tick", m_Camera.Transform().Rotation().Axis().ToString().c_str()); + // lepus::engine::ConsoleLogger::Global().LogInfo("DemoApp", "Tick", std::to_string(m_Camera.Transform().Rotation().Angle() * (1.f / PI) * 180.f).c_str()); + + m_Camera.Transform().Origin(m_Camera.Transform().Origin() + forwardDelta + rightDelta); } inline void Shutdown(std::shared_ptr windowing) { - // Output shutdown message to console - engine::ConsoleLogger::Global().LogInfo("", "main", "Demo shutting down!"); + // Output shutdown message to console + engine::ConsoleLogger::Global().LogInfo("", "main", "Demo shutting down!"); - windowing->Shutdown(); + windowing->Shutdown(); - system::WindowingGLFW::Terminate(); + system::WindowingGLFW::Terminate(); - engine::ConsoleLogger::Shutdown(); + engine::ConsoleLogger::Shutdown(); - m_Initialised = false; + m_Initialised = false; } }; diff --git a/src/lepus/gfx/GraphicsEngine/Apis/ApiGL.h b/src/lepus/gfx/GraphicsEngine/Apis/ApiGL.h index 17a9499..a7a316e 100644 --- a/src/lepus/gfx/GraphicsEngine/Apis/ApiGL.h +++ b/src/lepus/gfx/GraphicsEngine/Apis/ApiGL.h @@ -14,134 +14,143 @@ namespace lepus { - namespace gfx + namespace gfx + { + class GraphicsApiGLOptions : public GraphicsApiOptions { - class GraphicsApiGLOptions : public GraphicsApiOptions + public: + static const size_t ProgramCount = 8; + + private: + GLuint m_FragmentShaders[ProgramCount]; + GLuint m_VertexShaders[ProgramCount]; + size_t m_ShaderCount = 0; + + public: + GraphicsApiType GetType() override { return GraphicsApiOpenGL; } + + GraphicsApiGLOptions() + : GraphicsApiOptions() + { + // Zero the shader arrays. + memset(m_FragmentShaders, 0, ProgramCount * sizeof(GLuint)); + memset(m_VertexShaders, 0, ProgramCount * sizeof(GLuint)); + } + + inline GLuint const GetFragmentShader(size_t index) { return m_FragmentShaders[index]; } + inline GLuint const GetVertexShader(size_t index) { return m_VertexShaders[index]; } + + const size_t RegisterShader(GLShaderCompiledResult const* vertexShader = nullptr, GLShaderCompiledResult const* fragShader = nullptr, GLShaderCompiledResult const* geomShader = nullptr) + { + assert(m_ShaderCount < ProgramCount); + + if (vertexShader) { - public: - static const size_t ProgramCount = 8; - private: - GLuint m_FragmentShaders[ProgramCount]; - GLuint m_VertexShaders[ProgramCount]; - size_t m_ShaderCount = 0; - public: - GraphicsApiType GetType() override { return GraphicsApiOpenGL; } - - GraphicsApiGLOptions() : GraphicsApiOptions() - { - // Zero the shader arrays. - memset(m_FragmentShaders, 0, ProgramCount * sizeof(GLuint)); - memset(m_VertexShaders, 0, ProgramCount * sizeof(GLuint)); - } - - inline GLuint const GetFragmentShader(size_t index) { return m_FragmentShaders[index]; } - inline GLuint const GetVertexShader(size_t index) { return m_VertexShaders[index]; } - - const size_t RegisterShader(GLShaderCompiledResult const* vertexShader = nullptr, GLShaderCompiledResult const* fragShader = nullptr, GLShaderCompiledResult const* geomShader = nullptr) - { - assert(m_ShaderCount < ProgramCount); - - if (vertexShader) - { - m_VertexShaders[m_ShaderCount] = vertexShader->ShaderHandle; - } - - if (fragShader) - { - m_FragmentShaders[m_ShaderCount] = fragShader->ShaderHandle; - } - - if (geomShader) - { - // TODO - } - - return m_ShaderCount++; - } - }; - - typedef lepus::gfx::SceneGraph> GLSceneGraph; - - template GraphicsApiGLOptions& GraphicsApi::GetOptions(); - - class GraphicsApiGL : public GraphicsApi + m_VertexShaders[m_ShaderCount] = vertexShader->ShaderHandle; + } + + if (fragShader) { - friend class GraphicsApiGLOptions; - private: - static const uint8_t _meshCount = 2; - struct - { - /// @brief Handle to the vertex array objects. - GLuint vao; + m_FragmentShaders[m_ShaderCount] = fragShader->ShaderHandle; + } - /// @brief List with all uniforms used by the API. - // TODO: Change to array - might get better cache/locality to improve access times. - std::forward_list*> uniforms; + if (geomShader) + { + // TODO + } - /// @brief Uniform map to update the values. - // TODO: Move to a Material class? - std::unordered_map*> uniformMap; - } m_Pipeline; + return m_ShaderCount++; + } + }; - GLuint m_Programs[GraphicsApiGLOptions::ProgramCount]; + typedef lepus::gfx::SceneGraph> GLSceneGraph; - GLSceneGraph m_Scene; + template GraphicsApiGLOptions& GraphicsApi::GetOptions(); - private: - void SetupVertexArrays(); - void SetupBuffers(); - void SetupShaders(); - void SetupUniforms(); + class GraphicsApiGL : public GraphicsApi + { + friend class GraphicsApiGLOptions; - private: - inline void* GetUniformInternal(char* name) override - { - size_t targetKeyLength = strlen(name); + private: + static const uint8_t _meshCount = 2; + struct + { + /// @brief Handle to the vertex array objects. + GLuint vao; + + /// @brief List with all uniforms used by the API. + // TODO: Change to array - might get better cache/locality to improve access times. + std::forward_list*> uniforms; + + /// @brief Uniform map to update the values. + // TODO: Move to a Material class? + std::unordered_map*> uniformMap; + } m_Pipeline; + + GLuint m_Programs[GraphicsApiGLOptions::ProgramCount]; + + GLSceneGraph m_Scene; + + private: + void SetupVertexArrays(); + void SetupBuffers(); + void SetupShaders(); + void SetupUniforms(); + + private: + inline void* GetUniformInternal(char* name) override + { + size_t targetKeyLength = strlen(name); + + // TODO: unordered_map doesn't really work with string keys... add actual hashing! + for (auto it = m_Pipeline.uniformMap.begin(); it != m_Pipeline.uniformMap.end(); it++) + { + size_t keyLength = strlen(it->first); + if (targetKeyLength == keyLength && !strcmp(name, it->first)) + { + return it->second; + } + } - // TODO: unordered_map doesn't really work with string keys... add actual hashing! - for (auto it = m_Pipeline.uniformMap.begin(); it != m_Pipeline.uniformMap.end(); it++) - { - size_t keyLength = strlen(it->first); - if (targetKeyLength == keyLength && !strcmp(name, it->first)) - { - return it->second; - } - } + return nullptr; + } - return nullptr; - } + public: + GraphicsApiGL(GraphicsApiGLOptions options) + { + GraphicsApiGL::Init(&options); + } - public: - GraphicsApiGL(GraphicsApiGLOptions options) - { - Init(&options); - } + GraphicsApiGL(GraphicsApiGLOptions* options) + { + GraphicsApiGL::Init(options); + } - void Init(GraphicsApiOptions* options) override; + void Init(GraphicsApiOptions* options) override; - void CreatePipeline() override; + void CreatePipeline() override; - void UpdateUniforms() override; + void UpdateUniforms() override; - inline GLSceneGraph& GetSceneGraph() - { - return m_Scene; - } + inline GLSceneGraph& GetSceneGraph() + { + return m_Scene; + } - void Draw() override; + void Draw() override; - void ClearFrameBuffer(float r, float g, float b) override; + void ClearFrameBuffer(float r, float g, float b) override; - /// @brief Dummy method as OpenGL itself doesn't need to do anything for the swap chain to work. - void SwapBuffers() override {} + /// @brief Dummy method as OpenGL itself doesn't need to do anything for the swap chain to work. + void SwapBuffers() override {} - void Shutdown() override; - }; + void Shutdown() override; + }; - template const lepus::gfx::GLUniformBinding* GraphicsApi::GetUniform*>(char* name); + template const lepus::gfx::GLUniformBinding* GraphicsApi::GetUniform*>(char* name); - template GraphicsApiGL& GraphicsEngine::GetApi(); - } -} + template GraphicsApiGL& GraphicsEngine::GetApi(); + } // namespace gfx +} // namespace lepus #endif \ No newline at end of file diff --git a/src/lepus/gfx/GraphicsEngine/GraphicsApi.h b/src/lepus/gfx/GraphicsEngine/GraphicsApi.h index 410dc99..57b317c 100644 --- a/src/lepus/gfx/GraphicsEngine/GraphicsApi.h +++ b/src/lepus/gfx/GraphicsEngine/GraphicsApi.h @@ -38,10 +38,7 @@ namespace lepus /// @brief Main viewport used by the application. lepus::types::Viewport mainViewport = {}; - virtual ~GraphicsApiOptions() - { - - } + virtual ~GraphicsApiOptions() {} }; /// @brief API wrapper to be used by GraphicsEngine. @@ -84,15 +81,25 @@ namespace lepus GraphicsApi(GraphicsApiOptions* options) { - Init(options); - m_ShutdownCalled = false; + m_Options = nullptr; + GraphicsApi::Init(options); } - /// @brief Initialises the API with the provided options. - /// @param options An options object using a GraphicsApiOptions type for the requested API. - /// Make sure you don't pass a pointer to a new object here. Implementations of this class must copy the options, - /// not reference a pointer, so there's a potential risk of a memory leak there. - virtual void Init(GraphicsApiOptions* options) = 0; + /// @brief Initialises the API with the provided + /// options. + /// @param options An options object using a + /// GraphicsApiOptions type for the requested API. Make + /// sure you don't pass a pointer to a new object here. + /// Implementations of this class must copy the options, + /// not reference a pointer, so there's a potential risk + /// of a memory leak there. + virtual inline void Init(GraphicsApiOptions* options) + { + assert(options == nullptr); + + InitInternal(options); + m_ShutdownCalled = false; + } /// @brief Obtains the options object this GraphicsApi was initialised with. /// @@ -149,7 +156,7 @@ namespace lepus Shutdown(); } }; - } -} + } // namespace gfx +} // namespace lepus #endif \ No newline at end of file diff --git a/src/lepus/gfx/GraphicsEngine/GraphicsEngine.cpp b/src/lepus/gfx/GraphicsEngine/GraphicsEngine.cpp index 64ebed4..d8f7996 100644 --- a/src/lepus/gfx/GraphicsEngine/GraphicsEngine.cpp +++ b/src/lepus/gfx/GraphicsEngine/GraphicsEngine.cpp @@ -22,12 +22,14 @@ void GraphicsEngine::InitApi(GraphicsApiOptions* options) switch (options->GetType()) { case GraphicsApiType::GraphicsApiOpenGL: - m_Api = new GraphicsApiGL(*(GraphicsApiGLOptions*)options); + m_Api = new GraphicsApiGL(*dynamic_cast(options)); break; case GraphicsApiType::GraphicsApiVulkan: // TODO + break; case GraphicsApiType::GraphicsApiTest: // Ignore test/mock APIs. + break; case GraphicsApiType::GraphicsApiUnknown: default: // Assert if the API type is not part of the enum. @@ -41,7 +43,7 @@ void GraphicsEngine::Setup() m_Api->CreatePipeline(); } -void GraphicsEngine::Render(float r, float g, float b) +void GraphicsEngine::Render(const float r, const float g, const float b) { m_Api->ClearFrameBuffer(r, g, b); diff --git a/src/lepus/utility/types/Transform.h b/src/lepus/utility/types/Transform.h index f088165..91e30ba 100644 --- a/src/lepus/utility/types/Transform.h +++ b/src/lepus/utility/types/Transform.h @@ -8,153 +8,180 @@ namespace lepus { namespace math { - class Transform - { - private: - lepus::types::Vector3 m_Origin, m_Forward, m_Right, m_Up; - // axis-angle - lepus::types::Quaternion m_Rotation; - - public: - Transform() - { - m_Origin = lepus::types::Vector3(); - - m_Forward = lepus::types::Vector3(0.f, 0.f, 1.f); - m_Right = lepus::types::Vector3(1.f, 0.f, 0.f); - m_Up = lepus::types::Vector3(0.f, 1.f, 0.f); - - m_Rotation = lepus::types::Quaternion(); - } - - Transform(Transform&& transform) - { - m_Origin = transform.Origin(); - m_Forward = transform.Forward(); - m_Up = transform.Up(); - m_Right = transform.Right(); - m_Rotation = transform.Rotation(); - } - - Transform(const Transform& transform) - { - m_Origin = transform.Origin(); - m_Forward = transform.Forward(); - m_Up = transform.Up(); - m_Right = transform.Right(); - m_Rotation = transform.Rotation(); - } - - Transform& operator=(const Transform& transform) - { - m_Origin = transform.Origin(); - m_Forward = transform.Forward(); - m_Up = transform.Up(); - m_Right = transform.Right(); - m_Rotation = transform.Rotation(); - - return *this; - } - - inline lepus::types::Vector3 Origin() const { return m_Origin; } - inline void Origin(const lepus::types::Vector3& vec) - { - m_Origin.x(vec.x()); - m_Origin.y(vec.y()); - m_Origin.z(vec.z()); - } - - inline lepus::types::Vector3 Forward() const { return lepus::types::Vector3(m_Forward); } - inline lepus::types::Vector3 Right() const { return lepus::types::Vector3(m_Right); } - inline lepus::types::Vector3 Up() const { return lepus::types::Vector3(m_Up); } - - inline lepus::types::Quaternion Rotation() const { return m_Rotation; } - inline void Rotation(const lepus::types::Quaternion& newRotation) - { - m_Rotation.x(newRotation.x()); - m_Rotation.y(newRotation.y()); - m_Rotation.z(newRotation.z()); - m_Rotation.w(newRotation.w()); - } - - inline void Rotate(const lepus::types::Quaternion& quat) - { - m_Rotation = m_Rotation * quat; - - // Rotate the basis vectors - auto newForward = quat.Rotate(m_Forward); - auto newRight = quat.Rotate(m_Right); - auto newUp = quat.Rotate(m_Up); - - // Set basis vectors to rotated - m_Forward.x(newForward.x());m_Forward.y(newForward.y());m_Forward.z(newForward.z()); - m_Right.x(newRight.x());m_Right.y(newRight.y());m_Right.z(newRight.z()); - m_Up.x(newUp.x());m_Up.y(newUp.y());m_Up.z(newUp.z()); - } - - static inline lepus::math::Matrix4x4 AxisAngle(lepus::types::Vector3& axis, float angle) - { - lepus::math::Matrix4x4 ret = lepus::math::Matrix4x4::Identity(); - - lepus::types::Vector3 unitAxis = axis * (1.f / axis.Magnitude()); - - float c = cosf(angle); - float s = sinf(angle); - - ret.set<0, 0>(c + (unitAxis.x() * unitAxis.x() * (1.f - c))); - ret.set<1, 0>((unitAxis.y() * unitAxis.x() * (1.f - c)) + (unitAxis.z() * s)); - ret.set<2, 0>((unitAxis.z() * unitAxis.x() * (1.f - c)) - (unitAxis.y() * s)); - - ret.set<0, 1>((unitAxis.y() * unitAxis.x() * (1.f - c)) - (unitAxis.z() * s)); - ret.set<1, 1>(c + (unitAxis.y() * unitAxis.y() * (1.f - c))); - ret.set<2, 1>((unitAxis.z() * unitAxis.y() * (1.f - c)) + (unitAxis.x() * s)); - - ret.set<0, 2>((unitAxis.z() * unitAxis.x() * (1.f - c)) + (unitAxis.y() * s)); - ret.set<1, 2>((unitAxis.z() * unitAxis.y() * (1.f - c)) - (unitAxis.x() * s)); - ret.set<2, 2>(c + (unitAxis.z() * unitAxis.z() * (1.f - c))); - - return ret; - } - - inline void SetPosition(float x, float y, float z) - { - m_Origin.x(x); - m_Origin.y(y); - m_Origin.z(z); - } - - inline lepus::math::Matrix4x4 BuildMatrix() const - { - lepus::math::Matrix4x4 model = lepus::math::Matrix4x4::Identity(); - - // Translation - model.set<0, 3>(m_Origin.x()); - model.set<1, 3>(m_Origin.y()); - model.set<2, 3>(m_Origin.z()); - - // TODO: add scaling and rotation - lepus::types::Quaternion normRot = m_Rotation.Normalised(); - lepus::types::Vector3 axis = normRot.Axis(); - //axis = axis * (1.f / axis.Magnitude()); - float angle = normRot.Angle(); - - float cosTheta = cosf(angle); - float invCosTheta = 1.f - cosTheta; - float sinTheta = sinf(angle); - model.set<0, 0>(axis.x() * axis.x() * invCosTheta + cosTheta); - model.set<0, 1>(axis.x() * axis.y() * invCosTheta + axis.z() * sinTheta); - model.set<1, 1>(axis.y() * axis.y() * invCosTheta + cosTheta); - model.set<1, 0>(axis.y() * axis.x() * invCosTheta - axis.z() * sinTheta); - model.set<2, 0>(axis.z() * axis.x() * invCosTheta + axis.y() * sinTheta); - model.set<2, 1>(axis.z() * axis.y() * invCosTheta - axis.x() * sinTheta); - model.set<0, 2>(axis.x() * axis.z() * invCosTheta - axis.y() * sinTheta); - model.set<1, 2>(axis.y() * axis.z() * invCosTheta + axis.x() * sinTheta); - model.set<2, 2>(axis.z() * axis.z() * invCosTheta + cosTheta); - - return model; - } - }; - } -} + class Transform + { + private: + lepus::types::Vector3 m_Origin, m_Forward, m_Right, m_Up; + // axis-angle + lepus::types::Quaternion m_Rotation; + + lepus::types::Vector3 m_Scale; + + public: + Transform() + { + m_Origin = lepus::types::Vector3(); + + m_Forward = lepus::types::Vector3(0.f, 0.f, 1.f); + m_Right = lepus::types::Vector3(1.f, 0.f, 0.f); + m_Up = lepus::types::Vector3(0.f, 1.f, 0.f); + + m_Rotation = lepus::types::Quaternion(); + + m_Scale = lepus::types::Vector3(1.f, 1.f, 1.f); + } + + Transform(Transform&& transform) + { + m_Origin = transform.Origin(); + m_Forward = transform.Forward(); + m_Up = transform.Up(); + m_Right = transform.Right(); + m_Rotation = transform.Rotation(); + m_Scale = transform.Scale(); + } + + Transform(const Transform& transform) + { + m_Origin = transform.Origin(); + m_Forward = transform.Forward(); + m_Up = transform.Up(); + m_Right = transform.Right(); + m_Rotation = transform.Rotation(); + m_Scale = transform.Scale(); + } + + Transform& operator=(const Transform& transform) + { + m_Origin = transform.Origin(); + m_Forward = transform.Forward(); + m_Up = transform.Up(); + m_Right = transform.Right(); + m_Rotation = transform.Rotation(); + m_Scale = transform.Scale(); + + return *this; + } + + inline lepus::types::Vector3 Origin() const { return m_Origin; } + inline void Origin(const lepus::types::Vector3& vec) + { + m_Origin.x(vec.x()); + m_Origin.y(vec.y()); + m_Origin.z(vec.z()); + } + + inline lepus::types::Vector3 Forward() const { return lepus::types::Vector3(m_Forward); } + inline lepus::types::Vector3 Right() const { return lepus::types::Vector3(m_Right); } + inline lepus::types::Vector3 Up() const { return lepus::types::Vector3(m_Up); } + + inline lepus::types::Quaternion Rotation() const { return m_Rotation; } + inline void Rotation(const lepus::types::Quaternion& newRotation) + { + m_Rotation.x(newRotation.x()); + m_Rotation.y(newRotation.y()); + m_Rotation.z(newRotation.z()); + m_Rotation.w(newRotation.w()); + } + + inline void Rotate(const lepus::types::Quaternion& quat) + { + m_Rotation = m_Rotation * quat; + + // Rotate the basis vectors + auto newForward = quat.Rotate(m_Forward); + auto newRight = quat.Rotate(m_Right); + auto newUp = quat.Rotate(m_Up); + + // Set basis vectors to rotated + m_Forward.x(newForward.x()); + m_Forward.y(newForward.y()); + m_Forward.z(newForward.z()); + m_Right.x(newRight.x()); + m_Right.y(newRight.y()); + m_Right.z(newRight.z()); + m_Up.x(newUp.x()); + m_Up.y(newUp.y()); + m_Up.z(newUp.z()); + } + + static inline lepus::math::Matrix4x4 AxisAngle(lepus::types::Vector3& axis, float angle) + { + lepus::math::Matrix4x4 ret = lepus::math::Matrix4x4::Identity(); + + lepus::types::Vector3 unitAxis = axis * (1.f / axis.Magnitude()); + + float c = cosf(angle); + float s = sinf(angle); + + ret.set<0, 0>(c + (unitAxis.x() * unitAxis.x() * (1.f - c))); + ret.set<1, 0>((unitAxis.y() * unitAxis.x() * (1.f - c)) + (unitAxis.z() * s)); + ret.set<2, 0>((unitAxis.z() * unitAxis.x() * (1.f - c)) - (unitAxis.y() * s)); + + ret.set<0, 1>((unitAxis.y() * unitAxis.x() * (1.f - c)) - (unitAxis.z() * s)); + ret.set<1, 1>(c + (unitAxis.y() * unitAxis.y() * (1.f - c))); + ret.set<2, 1>((unitAxis.z() * unitAxis.y() * (1.f - c)) + (unitAxis.x() * s)); + + ret.set<0, 2>((unitAxis.z() * unitAxis.x() * (1.f - c)) + (unitAxis.y() * s)); + ret.set<1, 2>((unitAxis.z() * unitAxis.y() * (1.f - c)) - (unitAxis.x() * s)); + ret.set<2, 2>(c + (unitAxis.z() * unitAxis.z() * (1.f - c))); + + return ret; + } + + inline lepus::types::Vector3 Scale() const { return m_Scale; } + + inline void SetPosition(float x, float y, float z) + { + m_Origin.x(x); + m_Origin.y(y); + m_Origin.z(z); + } + + inline void SetScale(float scale) + { + this->SetScale(scale, scale, scale); + } + + inline void SetScale(float x, float y, float z) + { + m_Scale.x(x); + m_Scale.y(y); + m_Scale.z(z); + } + + inline lepus::math::Matrix4x4 BuildMatrix() const + { + lepus::math::Matrix4x4 model = lepus::math::Matrix4x4::Identity(); + + // Translation + model.set<0, 3>(m_Origin.x()); + model.set<1, 3>(m_Origin.y()); + model.set<2, 3>(m_Origin.z()); + + // TODO: add scaling and rotation + lepus::types::Quaternion normRot = m_Rotation.Normalised(); + lepus::types::Vector3 axis = normRot.Axis(); + // axis = axis * (1.f / axis.Magnitude()); + float angle = normRot.Angle(); + + float cosTheta = cosf(angle); + float invCosTheta = 1.f - cosTheta; + float sinTheta = sinf(angle); + model.set<0, 0>(m_Scale.x() * ((axis.x() * axis.x()) * invCosTheta + cosTheta)); + model.set<0, 1>(m_Scale.y() * (axis.x() * axis.y() * invCosTheta + axis.z() * sinTheta)); + model.set<1, 1>(m_Scale.y() * ((axis.y() * axis.y()) * invCosTheta + cosTheta)); + model.set<1, 0>(m_Scale.x() * (axis.y() * axis.x() * invCosTheta - axis.z() * sinTheta)); + model.set<2, 0>(m_Scale.x() * (axis.z() * axis.x() * invCosTheta + axis.y() * sinTheta)); + model.set<2, 1>(m_Scale.y() * (axis.z() * axis.y() * invCosTheta - axis.x() * sinTheta)); + model.set<0, 2>(m_Scale.z() * (axis.x() * axis.z() * invCosTheta - axis.y() * sinTheta)); + model.set<1, 2>(m_Scale.z() * (axis.y() * axis.z() * invCosTheta + axis.x() * sinTheta)); + model.set<2, 2>(m_Scale.z() * ((axis.z() * axis.z()) * invCosTheta + cosTheta)); + + return model; + } + }; + } // namespace math +} // namespace lepus #endif