diff --git a/data/Shaders/Mesh/Mesh.frag b/data/Shaders/Mesh/Mesh.frag index a2370ad598b6832cf73018e518818ae4a4d93a8d..73cf64c48bfea1072e3ad200e44164ce17349848 100644 --- a/data/Shaders/Mesh/Mesh.frag +++ b/data/Shaders/Mesh/Mesh.frag @@ -36,14 +36,17 @@ void main() vec3 pointToCamera = cameraData.wsPosition - fragData.wsPosition; vec3 pointToCameraDir = normalize(pointToCamera); + vec3 ambient; vec3 diffuse; vec3 specular; for (int i = 0; i < lightData.pointLightCount; i++) { vec3 pointToLight = lightData.pointLightPos[i].xyz - fragData.wsPosition; - float distance = length(pointToLight); float attenuation = 1.0 / (constant + linear * distance + quadratic * (distance * distance)); + + ambient += attenuation * lightData.pointLightIntensity[i].xyz * 0.1f; + vec3 pointToLightDir = normalize(pointToLight); @@ -58,7 +61,7 @@ void main() specular += vec3(pow(max(dot(pointToCameraDir, reflectDir), 0.0), coefficient) * lightData.pointLightIntensity[i] * attenuation); } - vec3 resultIntensity = diffuse * color + specular; + vec3 resultIntensity = (ambient + diffuse) * color + specular; vec3 resultColor = resultIntensity; frag_color = vec4(resultColor, 1.0); } diff --git a/data/Shaders/Sprite/sprite.frag b/data/Shaders/Sprite/sprite.frag deleted file mode 100644 index 8ecd5b08931a1221a6325cae49917999fff8b721..0000000000000000000000000000000000000000 --- a/data/Shaders/Sprite/sprite.frag +++ /dev/null @@ -1,10 +0,0 @@ -#version 330 - -in vec2 fragUV; - -uniform sampler2D sampler; - -void main() -{ - gl_FragColor = texture(sampler, fragUV); -} diff --git a/data/Shaders/Sprite/sprite.vert b/data/Shaders/Sprite/sprite.vert deleted file mode 100644 index bb53e55963954626ae17c024ea2b0af29af91166..0000000000000000000000000000000000000000 --- a/data/Shaders/Sprite/sprite.vert +++ /dev/null @@ -1,17 +0,0 @@ -#version 330 - -in vec3 position; -in vec2 texCoord; -in vec3 normal; - -out vec2 fragUV; - -uniform mat4 model; -uniform mat4 viewProjection; - -void main() -{ - gl_Position = viewProjection * model * vec4(position, 1.0); - - fragUV = texCoord; -} diff --git a/external/DMath b/external/DMath index 221eadc75e3ec0dfd0a244084a234fac24062312..30717a477868d3dcc8ce82f55c2f4d78236d4227 160000 --- a/external/DMath +++ b/external/DMath @@ -1 +1 @@ -Subproject commit 221eadc75e3ec0dfd0a244084a234fac24062312 +Subproject commit 30717a477868d3dcc8ce82f55c2f4d78236d4227 diff --git a/include/DEngine/AssetManager/AssetManager.hpp b/include/DEngine/AssetManager/AssetManager.hpp index 7103c16d9d2763ff689db0cd51a91fbcbd44c45a..576b2b1c6fe8626bc4be03c2c46c403d4058d15a 100644 --- a/include/DEngine/AssetManager/AssetManager.hpp +++ b/include/DEngine/AssetManager/AssetManager.hpp @@ -15,8 +15,8 @@ namespace Engine struct MeshInfo { std::string path; - size_t meshIndex; - size_t primitiveIndex; + size_t meshIndex = 0; + size_t primitiveIndex = 0; bool operator==(const MeshInfo& right) const; }; diff --git a/include/DEngine/Components/Camera.hpp b/include/DEngine/Components/Camera.hpp index 1e62bd200b36320a44c7fc4c2a53eebd6395a46c..232ee03e1cdc154a051d02d9aa291f4bd5dbebb2 100644 --- a/include/DEngine/Components/Camera.hpp +++ b/include/DEngine/Components/Camera.hpp @@ -25,7 +25,7 @@ namespace Engine static constexpr float defaultFovY = 50.f; static constexpr float defaultOrtographicWidth = 10.f; static constexpr float defaultZNear = 0.1f; - static constexpr float defaultZFar = 100.f; + static constexpr float defaultZFar = 10000.f; static constexpr ProjectionMode defaultProjectionMode = ProjectionMode::Perspective; explicit Camera(SceneObject& owningObject); diff --git a/include/DEngine/Components/PointLight.hpp b/include/DEngine/Components/PointLight.hpp index 4495e75f7616046ae0fce8542f9733f89377ede1..e529d7952da9daf47d7da4b26981dec662b1d446 100644 --- a/include/DEngine/Components/PointLight.hpp +++ b/include/DEngine/Components/PointLight.hpp @@ -26,6 +26,7 @@ namespace Engine [[nodiscard]] Math::Matrix<4, 3> GetModel_Reduced(Space space) const; [[nodiscard]] Math::Matrix4x4 GetModel(Space space) const; + [[nodiscard]] Math::Vector<3, float> GetPosition(Space space) const; }; } } \ No newline at end of file diff --git a/include/DEngine/SceneObject.hpp b/include/DEngine/SceneObject.hpp index b02983d864eb5ae62eea210258ee5b0829871fe6..8bd21bbcefa763411542b4f80a5ae9331b99edd9 100644 --- a/include/DEngine/SceneObject.hpp +++ b/include/DEngine/SceneObject.hpp @@ -43,6 +43,7 @@ namespace Engine [[nodiscard]] Scene& GetScene(); [[nodiscard]] SceneObject* GetParent() const; + void SetParent(SceneObject* newParent); template<typename T> decltype(auto) AddComponent(); @@ -71,7 +72,7 @@ namespace Engine private: std::reference_wrapper<Scene> sceneRef; SceneObject* parent = nullptr; - std::vector<SceneObject*> children; + std::vector<std::reference_wrapper<SceneObject>> children; std::unordered_map<std::type_index, std::vector<size_t>> components; std::unordered_map<std::type_index, size_t> singletonComponents; }; diff --git a/include/InputRotate.hpp b/include/InputRotate.hpp new file mode 100644 index 0000000000000000000000000000000000000000..91eb9ec00b444346915bfba0d08dfdca00faf55f --- /dev/null +++ b/include/InputRotate.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include "DEngine/Components/ScriptBase.hpp" + +#include "DMath/Vector/Vector.hpp" + +namespace Assignment02 +{ + class InputRotate : public Engine::Components::ScriptBase + { + public: + using ParentType = ScriptBase; + + explicit InputRotate(Engine::SceneObject& owningObject); + + protected: + void SceneStart() override; + + void Tick() override; + }; +} \ No newline at end of file diff --git a/include/SinusMovement.hpp b/include/SinusMovement.hpp index aace0dc2839b3dd5bf190b4e9f39f33af95058ad..724025a3dcacf0cf63cbf2406ea4910415d8057a 100644 --- a/include/SinusMovement.hpp +++ b/include/SinusMovement.hpp @@ -14,6 +14,8 @@ namespace Assignment02 explicit SinusMovement(Engine::SceneObject& owningObject); Math::Vector3D startPos{}; + float movementMultiplier = 7.5f; + float timeMultiplier = 25.f; protected: void SceneStart() override; diff --git a/src/Engine/Components/Camera.cpp b/src/Engine/Components/Camera.cpp index 254f6da19d8ca3680fe9f68096b3a3fbc3bf9fcc..0cb2c19a36a190e2e68a5e3089f5f18902602a96 100644 --- a/src/Engine/Components/Camera.cpp +++ b/src/Engine/Components/Camera.cpp @@ -81,9 +81,7 @@ namespace Engine if (space == Space::Local) return localPos; else if (space == Space::World) - { - return GetSceneObject().GetPosition(space); - } + return Multiply_Reduced(GetSceneObject().GetModel_Reduced(space), localPos); else { assert(false && "Invalid enum value."); diff --git a/src/Engine/Components/PointLight.cpp b/src/Engine/Components/PointLight.cpp index 31630598d6a7979ed3ff64abb5a07965ad235174..952b3fd452b93f252a8c347857eb6f9de015a958 100644 --- a/src/Engine/Components/PointLight.cpp +++ b/src/Engine/Components/PointLight.cpp @@ -33,5 +33,10 @@ namespace Engine using namespace Math::LinTran3D; return AsMat4(GetModel_Reduced(space)); } + + Math::Vector<3, float> PointLight::GetPosition(Space space) const + { + return Math::LinTran3D::GetTranslation(GetModel_Reduced(space)); + } } } \ No newline at end of file diff --git a/src/Engine/Engine.cpp b/src/Engine/Engine.cpp index 710e49eb524988c7bf0ff6bb210abf472a5ef967..bf800321b77303e39f55e206772af0a4b53ba7fd 100644 --- a/src/Engine/Engine.cpp +++ b/src/Engine/Engine.cpp @@ -15,6 +15,7 @@ #include "DEngine/Components/PointLight.hpp" #include "SinusMovement.hpp" +#include "InputRotate.hpp" #include "Systems/RenderSystem.hpp" @@ -41,16 +42,22 @@ namespace Engine rendererInitInfo.preferredAPI = Renderer::API::OpenGL; // Debug info + // Whether we want to enable debugging in the rendering system + // And the error callback method we want to use. rendererInitInfo.debugInitInfo.useDebugging = true; rendererInitInfo.debugInitInfo.errorMessageCallback = rendererDebugCallback; + // Dimensions and handle to a surface we have generated to render onto. rendererInitInfo.surfaceDimensions = Application::GetWindowSize(); rendererInitInfo.surfaceHandle = Application::Core::GetMainWindowHandle(); + // Set function pointer to our decoupled asset loaders. rendererInitInfo.assetLoadCreateInfo.meshLoader = &AssMan::GetRendererMeshDoc; rendererInitInfo.assetLoadCreateInfo.assetLoadEnd = &AssMan::Renderer_AssetLoadEndEvent; rendererInitInfo.assetLoadCreateInfo.textureLoader = &LoadTexture; + // Function pointer to the Application systems GL_SwapBuffer function. + // This one goes to GLFW3's swap buffer function. rendererInitInfo.openGLInitInfo.glSwapBuffers = &Application::Core::GL_SwapWindow; Renderer::Core::Initialize(rendererInitInfo); } @@ -69,46 +76,102 @@ void Engine::Core::Run() Scene& scene1 = Engine::NewScene(); Renderer::GetViewport(0).SetSceneRef(&scene1); + // Add our cube model to the asset manager + AssMan::MeshInfo meshInfo; + meshInfo.path = "data/Meshes/Cube/Cube.gltf"; + size_t cubeMesh = AssMan::AddMesh(std::move(meshInfo)); + + // Create camera Object + // SceneObjects are guaranteed to be in the same place in memory always. No need for soft-references. auto& objCamera = scene1.NewSceneObject(); objCamera.localPosition.z = -5.f; + // Add a component to our SceneObject (similiar to Unity's GameObject) + // This function returns a soft-reference to the component (.first) and a hard-reference (.second.get()). + // We use hard-references, but components may move in memory over the lifetime of the program + // so soft-references are usually preferred. auto& camera = objCamera.AddComponent<Components::Camera>().second.get(); - camera.zFar = 10000.f; + camera.rotation = camera.rotation; objCamera.AddComponent<Components::FreeLook>(); + // Light object 1 auto& lightObj = scene1.NewSceneObject(); lightObj.localPosition = { 0.f, 1.f, 0.f }; + lightObj.localScale = { 0.1f, 0.1f, 0.1f }; Components::PointLight& light1 = lightObj.AddComponent<Components::PointLight>().second.get(); - light1.color = { 1.f, 1.f, 1.f }; - light1.intensity = 2.f; - lightObj.AddComponent<Assignment02::SinusMovement>(); - - auto& obj4 = scene1.NewSceneObject(); - obj4.localPosition = { 0.f, -7.5f, -10.f }; - //Components::PointLight& light3 = obj4.AddComponent<Components::PointLight>().second.get(); - - - LoadGLTFScene(scene1, "Data/Sponza2/Sponza.gltf"); - - const auto& meshCompVector = scene1.GetAllComponents<Components::MeshRenderer>(); - + light1.color = { 1.f, 0.5f, 0.5f }; + light1.intensity = 0.5f; + auto& sinus1 = lightObj.AddComponent<Assignment02::SinusMovement>(); + auto& mesh1 = lightObj.AddComponent<Components::MeshRenderer>().second.get(); + mesh1.mesh = cubeMesh; + mesh1.texture = 0; + + + // Light object 2 + auto& lightObj2 = scene1.NewSceneObject(); + lightObj2.localPosition = { 0.f, 5.f, 3.f }; + lightObj2.localScale = { 0.1f, 0.1f, 0.1f }; + auto& mesh2 = lightObj2.AddComponent<Components::MeshRenderer>().second.get(); + mesh2.mesh = cubeMesh; + mesh2.texture = 0; + auto& sinus2 = lightObj2.AddComponent<Assignment02::SinusMovement>(); + sinus2.timeMultiplier = 15.f; + sinus2.movementMultiplier = -sinus2.movementMultiplier; + Components::PointLight& light2 = lightObj2.AddComponent<Components::PointLight>().second.get(); + light2.color = { 0.5f, 1.f, 0.5f }; + light2.intensity = 0.5f; + + + // Light object 3 + auto& lightObj3 = scene1.NewSceneObject(); + lightObj3.localPosition = { 0.f, 5.f, -3.5f }; + lightObj3.localScale = { 0.1f, 0.1f, 0.1f }; + auto& mesh3 = lightObj3.AddComponent<Components::MeshRenderer>().second.get(); + mesh3.mesh = cubeMesh; + mesh3.texture = 0; + auto& sinus3 = lightObj3.AddComponent<Assignment02::SinusMovement>(); + sinus3.timeMultiplier = 15.f; + Components::PointLight& light3 = lightObj3.AddComponent<Components::PointLight>().second.get(); + light3.color = { 0.5f, 0.5f, 1.f }; + light3.intensity = 0.5f; + + // Load the GLTF scene, with a reference to the SceneObject we want to add it to + auto& rootObj = scene1.NewSceneObject(); + rootObj.AddComponent<Assignment02::InputRotate>(); + LoadGLTFScene(rootObj, "data/Sponza2/Sponza.gltf"); + + lightObj.SetParent(&rootObj); + lightObj2.SetParent(&rootObj); + lightObj3.SetParent(&rootObj); + + // Not optimal solution. These are the RenderGraph struct we can work with. + // Ideally they should belong to Rendering system Renderer::RenderGraph graph; Renderer::RenderGraphTransform graphTransform; scene1.Scripts_SceneStart(); + // Checks for any window events, like input etc and updates the Input system. while (Application::Core::UpdateEvents(), Application::IsRunning()) { + // Calls all the custom script components' Tick function. scene1.ScriptTick(); + // Build the RenderGraph we want to submit to the rendering system RenderSystem::BuildRenderGraph(scene1, graph); + // Submit built RenderGraph Renderer::Core::PrepareRenderingEarly(graph); + // Update camera-info in the renderer by using the Camera-component we have made. Renderer::Core::SetCameraInfo(GetRendererCameraInfo(camera)); + // Build the positional data for the RenderGraph. RenderSystem::BuildRenderGraphTransform(scene1, graphTransform); + // Submit the positional data for the RenderGraph Renderer::Core::PrepareRenderingLate(graphTransform); + // Draw the most recently submitted RenderGraph Renderer::Core::Draw(); + // Various End-of-Tick events Input::Core::ClearValues(); Time::Core::TickEnd(scene1.GetTimeData()); } diff --git a/src/Engine/LoadGLTFScene.cpp b/src/Engine/LoadGLTFScene.cpp index 4ee83f98cbedb8c41168430992e31cf0558d612d..8d636faa4daa2d7b80d50c7844e36a4143c73e77 100644 --- a/src/Engine/LoadGLTFScene.cpp +++ b/src/Engine/LoadGLTFScene.cpp @@ -10,39 +10,48 @@ namespace Engine { - bool LoadGLTFScene(Scene& scene, std::filesystem::path path) + bool LoadGLTFScene(SceneObject& obj, std::filesystem::path path) { auto gltfDoc = fx::gltf::LoadFromText(path.string()); + Scene& scene = obj.GetScene(); + + // Generate one sceneObject for all our primitives to be attached to. auto& sceneObj = scene.NewSceneObject(); + sceneObj.SetParent(&obj); + + // Software currently only supports one node with several primitives attached. + // Found no sample files to test with multiple nodes. + // Multiple nodes would mean multiple SceneObjects. sceneObj.localScale = { gltfDoc.nodes[0].scale[0], gltfDoc.nodes[0].scale[1], gltfDoc.nodes[0].scale[2], }; - for (size_t meshIndex = 0; meshIndex < gltfDoc.meshes.size(); meshIndex++) - { - const auto& mesh = gltfDoc.meshes[meshIndex]; + // Grabs the GLTF mesh node 0 uses. + const auto& mesh = gltfDoc.meshes[gltfDoc.nodes[0].mesh]; - for (size_t primitiveIndex = 0; primitiveIndex < mesh.primitives.size(); primitiveIndex++) - { - const auto& primitive = mesh.primitives[primitiveIndex]; - - auto& compRef = sceneObj.AddComponent<Components::MeshRenderer>().second.get(); - - AssetManager::MeshInfo meshInfo{}; - meshInfo.path = path.string(); - meshInfo.meshIndex = meshIndex; - meshInfo.primitiveIndex = primitiveIndex; - - size_t meshID = AssetManager::AddMesh(std::move(meshInfo)); - compRef.SetMesh(meshID); - - size_t baseColorTexIndex = gltfDoc.materials[primitive.material].pbrMetallicRoughness.baseColorTexture.index; - AssetManager::TextureInfo textureInfo{}; - textureInfo.path = path.parent_path().string() + '/' + gltfDoc.images[baseColorTexIndex].uri; - - size_t textureID = AssetManager::AddTexture(std::move(textureInfo)); - compRef.texture = textureID; - } + // Iterates through the primitives in this mesh and adds it to the AssetManager, then adds it as a component on the SceneObject + for (size_t primitiveIndex = 0; primitiveIndex < mesh.primitives.size(); primitiveIndex++) + { + const auto& primitive = mesh.primitives[primitiveIndex]; + + auto& compRef = sceneObj.AddComponent<Components::MeshRenderer>().second.get(); + + AssetManager::MeshInfo meshInfo{}; + meshInfo.path = path.string(); + meshInfo.meshIndex = gltfDoc.nodes[0].mesh; + meshInfo.primitiveIndex = primitiveIndex; + + size_t meshID = AssetManager::AddMesh(std::move(meshInfo)); + compRef.SetMesh(meshID); + + // Adds the BaseColor (Diffuse) texture associated with this primitive, to the AssetManager + // and then references it in the MeshRenderer component. + size_t baseColorTexIndex = gltfDoc.materials[primitive.material].pbrMetallicRoughness.baseColorTexture.index; + AssetManager::TextureInfo textureInfo{}; + textureInfo.path = path.parent_path().string() + '/' + gltfDoc.images[baseColorTexIndex].uri; + + size_t textureID = AssetManager::AddTexture(std::move(textureInfo)); + compRef.texture = textureID; } return true; diff --git a/src/Engine/LoadGLTFScene.hpp b/src/Engine/LoadGLTFScene.hpp index 3a4371c02de47ce8371a5c31a4bf6e46a4506087..bd1dedcc7b9439eed30f738f6b7e60ace1794721 100644 --- a/src/Engine/LoadGLTFScene.hpp +++ b/src/Engine/LoadGLTFScene.hpp @@ -5,7 +5,7 @@ namespace Engine { - class Scene; + class SceneObject; - bool LoadGLTFScene(Scene& scene, std::filesystem::path path); + bool LoadGLTFScene(SceneObject& scene, std::filesystem::path path); } \ No newline at end of file diff --git a/src/Engine/Renderer/OpenGL.cpp b/src/Engine/Renderer/OpenGL.cpp index d8a93cb014f7cd6f554951ea1ac7bceb68117d1c..7c2fada645070a2bf34bb258f2bf72517faf8cf5 100644 --- a/src/Engine/Renderer/OpenGL.cpp +++ b/src/Engine/Renderer/OpenGL.cpp @@ -215,11 +215,12 @@ namespace Engine data.spriteSamplerUniform = glGetUniformLocation(data.spriteProgram, "sampler"); } - void Renderer::OpenGL::LoadMeshShader(Engine::Renderer::OpenGL::Data &data) + void Renderer::OpenGL::LoadMeshShader(Data &data) { // Create shader data.meshProgram = glCreateProgram(); + // Links the shader files to the shader program. std::array<GLuint, 2> shader{}; shader[0] = CreateShader(LoadShader("Data/Shaders/Mesh/Mesh.vert"), GL_VERTEX_SHADER); shader[1] = CreateShader(LoadShader("Data/Shaders/Mesh/Mesh.frag"), GL_FRAGMENT_SHADER); @@ -239,9 +240,6 @@ namespace Engine // Grab uniforms data.meshModelUniform = glGetUniformLocation(data.meshProgram, "model"); data.meshTextureUniform = glGetUniformLocation(data.meshProgram, "texture"); - - - glUniformBlockBinding(data.meshProgram, 1, 1); } void Renderer::OpenGL::CreateStandardUBOs(Data& data) @@ -249,15 +247,14 @@ namespace Engine std::array<GLuint, 2> buffers; glGenBuffers(2, buffers.data()); + // Make camera ubo, bind it to 0 data.cameraDataUBO = buffers[0]; - data.lightDataUBO = buffers[1]; - - // Make camera ubo glBindBuffer(GL_UNIFORM_BUFFER, data.cameraDataUBO); glNamedBufferData(data.cameraDataUBO, sizeof(CameraDataUBO), nullptr, GL_DYNAMIC_DRAW); glBindBufferRange(GL_UNIFORM_BUFFER, 0, data.cameraDataUBO, 0, sizeof(CameraDataUBO)); - // Make light ubo + // Make light ubo, bind it to 1 + data.lightDataUBO = buffers[1]; glBindBuffer(GL_UNIFORM_BUFFER, data.lightDataUBO); glNamedBufferData(data.lightDataUBO, sizeof(LightDataUBO), nullptr, GL_DYNAMIC_DRAW); glBindBufferRange(GL_UNIFORM_BUFFER, 1, data.lightDataUBO, 0, sizeof(LightDataUBO)); @@ -270,9 +267,11 @@ namespace Engine void Renderer::OpenGL::Initialize(std::any& apiData, const InitInfo& createInfo) { + // Initializes GLEW auto glInitResult = glewInit(); assert(glInitResult == 0); + // Allocates the memory associated with the OpenGL rendering. apiData = std::make_any<Data>(); Data& data = std::any_cast<Data&>(apiData); @@ -298,9 +297,10 @@ namespace Engine } } + // Creates UBO buffers for camera and lighting data. CreateStandardUBOs(data); - // Gen sampler + // We only use 1 Sampler Object in this project. We generate it here and set its parameters. glGenSamplers(1, &data.samplerObject); glSamplerParameteri(data.samplerObject, GL_TEXTURE_WRAP_S, GL_REPEAT); glSamplerParameteri(data.samplerObject, GL_TEXTURE_WRAP_T, GL_REPEAT); @@ -311,20 +311,21 @@ namespace Engine glSamplerParameteri(data.samplerObject, GL_TEXTURE_LOD_BIAS, 0); glBindSampler(0, data.samplerObject); + // Basic OpenGL settings. glEnable(GL_DEPTH_TEST); - glEnable(GL_CULL_FACE); glCullFace(GL_BACK); //glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - // Load default texture + // Load default texture, this texture will ordinarily be used if the renderer can't find the one it's supposed to use. auto loadResult = DTex::LoadFromFile(std::string{ Setup::assetPath } + "/DRenderer/Textures/02.ktx"); assert(loadResult.GetResultInfo() == DTex::ResultInfo::Success && "Couldn't load the default texture for DRenderer."); data.testIBO = GetIBOFromTexDoc(loadResult.GetValue()).value(); //LoadSpriteShader(data); + // Loads the mesh shader and initializes it. LoadMeshShader(data); } @@ -350,12 +351,18 @@ namespace Engine { Data& data = GetAPIData(); + // Loads any needed texture into the unordered_map of IBOs in Data. UpdateIBODatabase(data, spriteLoadQueue); + // Loads any needed meshes into the unordered_map of VBOs in Data. UpdateVBODatabase(data, meshLoadQueue); + // Sends signal that the renderer is done loading assets to render this frame. + // This helps the AssetManager know when it can discard loaded assets in CPU memory. Core::GetData().assetLoadData.assetLoadEnd(); const auto& renderGraph = Core::GetRenderGraph(); + // Below we load all light intensities, colors etc. onto our Camera UBO. + // Update ambient light constexpr GLintptr ambientLightOffset = offsetof(LightDataUBO, LightDataUBO::ambientLight); glNamedBufferSubData(data.lightDataUBO, ambientLightOffset, sizeof(renderGraph.ambientLight), renderGraph.ambientLight.data()); @@ -385,6 +392,8 @@ namespace Engine const auto& renderGraphTransform = Core::GetRenderGraphTransform(); + // Below we load all non-drawcall positional data onto OpenGL. This includes light- and camera positional data. + // Update lights positions const size_t elements = Math::Min(10, renderGraphTransform.pointLights.size()); std::array<std::array<float, 4>, 10> posData; @@ -423,11 +432,13 @@ namespace Engine const auto& renderGraph = Core::GetRenderGraph(); const auto& renderGraphTransform = Core::GetRenderGraphTransform(); - Draw_SpritePass(data, renderGraph.sprites, renderGraphTransform.sprites); + //Draw_SpritePass(data, renderGraph.sprites, renderGraphTransform.sprites); + // Here our Mesh rendering-pass begins and ends. Draw_MeshPass(data, renderGraph.meshes, renderGraphTransform.meshes); auto& viewport = Renderer::GetViewport(0); + // At the end of the drawing process, we grab the surface handle we drew on and swap the GL Buffers. data.glSwapBuffers(viewport.GetSurfaceHandle()); } @@ -473,13 +484,18 @@ namespace Engine glProgramUniform1ui(data.meshProgram, data.meshTextureUniform, 0); + // Iterates over all Mesh-components to be drawn for (size_t i = 0; i < meshes.size(); i++) { + // Updates the model matrix glProgramUniformMatrix4fv(data.meshProgram, data.meshModelUniform, 1, GL_FALSE, transforms[i].data()); + // Find the correct vertex array object and binds it. const VBO& vbo = data.vboDatabase.at(meshes[i].meshID); glBindVertexArray(vbo.vertexArrayObject); + // Finds the correct texture object and binds it. If we couldn't find it, + // then we bind the default texture for the renderer. And log an error output. glActiveTexture(GL_TEXTURE0); auto iboIterator = data.iboDatabase.find(meshes[i].diffuseID); if (iboIterator == data.iboDatabase.end()) @@ -493,6 +509,7 @@ namespace Engine else glBindTexture(GL_TEXTURE_2D, iboIterator->second.texture); + // We draw elements using information we got from our VBO glDrawElements(GL_TRIANGLES, vbo.numIndices, vbo.indexType, nullptr); } } @@ -531,9 +548,11 @@ namespace Engine { IBO ibo; + // Grabs the OpenGL data from the DTex::TexDoc structure. GLenum target = DTex::ToGLTarget(input.GetTextureType()); GLint format = DTex::ToGLFormat(input.GetPixelFormat()); GLenum type = DTex::ToGLType(input.GetPixelFormat()); + if (target == 0 || format == 0) { LogDebugMessage("Error. Texture can not be used in OpenGL."); @@ -544,9 +563,11 @@ namespace Engine glBindTexture(target, ibo.texture); + // Sets mipmapping parameters. glTexParameteri(target, GL_TEXTURE_BASE_LEVEL, 0); glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, GLint(input.GetMipLevels() - 1)); + // Iterates over mipmap-levels and loads all image data onto OpenGL. for (GLint level = 0; level < GLint(input.GetMipLevels()); level++) { GLsizei width = GLsizei(input.GetDimensions(level).width); @@ -584,6 +605,8 @@ namespace Engine VBO vbo; + // Here we load the metadata from our Renderer::MeshDocument struct + vbo.indexType = ToGLType(meshDocument.GetIndexType()); vbo.numIndices = meshDocument.GetIndexCount(); @@ -592,6 +615,8 @@ namespace Engine glGenBuffers(GLint(vbo.attributeBuffers.size()), vbo.attributeBuffers.data()); + // Below we move all the mesh-data onto the GPU on a per-attribute basis. + glBindBuffer(GL_ARRAY_BUFFER, vbo.attributeBuffers[size_t(VBO::Attribute::Position)]); glBufferData(GL_ARRAY_BUFFER, meshDocument.GetByteLength(MeshDocument::Attribute::Position), meshDocument.GetDataPtr(MeshDocument::Attribute::Position), GL_STATIC_DRAW); glEnableVertexAttribArray(size_t(VBO::Attribute::Position)); diff --git a/src/Engine/Renderer/Renderer.cpp b/src/Engine/Renderer/Renderer.cpp index bb2692409c065f89157fb8a9349ea775037edc26..c9c797c0a7cd8abee1d4fea491a55d6070e59c3e 100644 --- a/src/Engine/Renderer/Renderer.cpp +++ b/src/Engine/Renderer/Renderer.cpp @@ -125,6 +125,9 @@ namespace Engine bool Renderer::Core::Initialize(const InitInfo& createInfo) { + // Checks if the supplies InitInfo struct provides all the necessary info. + // This only happens if debugging is enabled. + // This doesn't happen at all when compiling in release mode. if constexpr (Setup::enableDebugging) { if (createInfo.debugInitInfo.useDebugging) @@ -149,15 +152,17 @@ namespace Engine data.assetLoadData = createInfo.assetLoadCreateInfo; + // Creates a new viewport NewViewport(createInfo.surfaceDimensions, createInfo.surfaceHandle); + // Initializes correct function pointers based on the preferred 3D API switch (data.activeAPI) { case API::OpenGL: OpenGL::Initialize(data.apiData, createInfo.openGLInitInfo); - data.Draw = OpenGL::Draw; - data.PrepareRenderingEarly = OpenGL::PrepareRenderingEarly; - data.PrepareRenderingLate = OpenGL::PrepareRenderingLate; + data.Draw = &OpenGL::Draw; + data.PrepareRenderingEarly = &OpenGL::PrepareRenderingEarly; + data.PrepareRenderingLate = &OpenGL::PrepareRenderingLate; break; default: break; @@ -186,14 +191,21 @@ namespace Engine auto& renderGraph = data.renderGraph; + // Moves through the RenderGraph and tracks what assets are referenced + // to know which assets need to be loaded and which can be unloaded. + // Assets to be loaded/unloaded are stored in the data.load* queues. UpdateAssetReferences(data, renderGraph, &renderGraphInput); + // Swaps the resources of the user's rendergraph and the one the renderer owns. + // This allows you to reuse allocated memory. std::swap(renderGraph, renderGraphInput); + // Logs a message whenever textures or mesh assets need to be loaded. if (!data.loadTextureQueue.empty() || !data.loadMeshQueue.empty()) LogDebugMessage("Loading sprite/mesh resource(s)..."); data.PrepareRenderingEarly(data.loadTextureQueue, data.loadMeshQueue); + // Clears all the load-asset queues. data.loadTextureQueue.clear(); data.unloadTextureQueue.clear(); data.loadMeshQueue.clear(); diff --git a/src/Engine/SceneObject.cpp b/src/Engine/SceneObject.cpp index f8fb6ad6737b52580cd8aa916a86eb2c94c05306..c97575bc4e4b73886760ec9681c2c212b24c5b72 100644 --- a/src/Engine/SceneObject.cpp +++ b/src/Engine/SceneObject.cpp @@ -5,128 +5,201 @@ #include "DMath/LinearTransform2D.hpp" #include "DMath/LinearTransform3D.hpp" -Engine::SceneObject::SceneObject(Scene& owningScene, size_t indexInScene) : - sceneRef(owningScene) +namespace Engine { -} + SceneObject::SceneObject(Scene& owningScene, size_t indexInScene) : + sceneRef(owningScene) + { + } -Engine::SceneObject::~SceneObject() -{ - -} + SceneObject::~SceneObject() + { -Engine::Scene& Engine::SceneObject::GetScene() -{ - return sceneRef.get(); -} + } -Engine::SceneObject* Engine::SceneObject::GetParent() const { return parent; } + Scene& SceneObject::GetScene() + { + return sceneRef.get(); + } -Math::Vector3D Engine::SceneObject::GetPosition(Space space) const -{ - if (space == Space::Local) - return localPosition; - else + SceneObject* SceneObject::GetParent() const { return parent; } + + void SceneObject::SetParent(SceneObject* newParent) { - if (parent == nullptr) + if (parent == newParent) + return; + + // Clean up old parent + if (parent != nullptr) + { + auto& parentChildVector = parent->children; + for (size_t i = 0; i < parentChildVector.size(); i++) + { + if (this == &parentChildVector[i].get()) + { + parentChildVector[i] = parentChildVector.back(); + parentChildVector.pop_back(); + break; + } + } + } + + parent = newParent; + + // Add reference to new parent + if (parent != nullptr) + parent->children.emplace_back(*this); + } + + Math::Vector3D SceneObject::GetPosition(Space space) const + { + using namespace Math::LinTran3D; + + if (space == Space::Local) return localPosition; else { - assert(false); + if (parent == nullptr) + return localPosition; + else + return Multiply_Reduced(parent->GetModel_Reduced(space), localPosition); + } + } + + Math::Matrix<4, 3> SceneObject::GetModel_Reduced(Space space) const + { + using namespace Math::LinTran3D; + + auto localModel = Multiply_Reduced(Rotate_Reduced(localRotation), Scale_Reduced(localScale)); + Math::LinTran3D::AddTranslation(localModel, localPosition); + + if (space == Space::Local || parent == nullptr) + return localModel; + else if (space == Space::World) + return Multiply_Reduced(parent->GetModel_Reduced(space), localModel); + else + { + assert(false && "Error. Undefined enum value."); return {}; } } -} -Math::Matrix<4, 3> Engine::SceneObject::GetModel_Reduced(Space space) const -{ - const auto& scaleModel = Math::LinTran3D::Scale_Reduced(localScale); - const auto& rotateModel = Math::LinTran3D::Rotate_Reduced(localRotation); - auto localModel = Math::LinTran3D::Multiply_Reduced(scaleModel, rotateModel); - Math::LinTran3D::AddTranslation(localModel, localPosition); - return localModel; -} - -Math::Matrix<3, 2> Engine::SceneObject::GetModel2D_Reduced(Space space) const -{ - const auto& scaleModel = Math::LinTran2D::Scale_Reduced(localScale.x, localScale.y); - const auto& rotate = Math::LinTran2D::Rotate_Reduced(localRotation); - auto localModel = Math::LinTran2D::Multiply_Reduced(scaleModel, rotate); - Math::LinTran2D::AddTranslation(localModel, localPosition.x, localPosition.y); - return localModel; -} - -Math::Matrix2x2 Engine::SceneObject::GetRotationModel2D(Space space) const -{ - return Math::Matrix2x2(); -} + Math::Matrix<3, 2> SceneObject::GetModel2D_Reduced(Space space) const + { + using namespace Math::LinTran2D; -Math::Matrix<3, 3, float> Engine::SceneObject::GetRotationModel(Space space) const -{ - using namespace Math::LinearTransform3D; + auto localModel = Multiply_Reduced(Scale_Reduced(localScale.AsVec2()), Rotate_Reduced(localRotation)); + AddTranslation(localModel, localPosition.AsVec2()); - auto localModel = Rotate(localRotation); - if (space == Space::Local || parent == nullptr) - return localModel; - else - return parent->GetRotationModel(space) * localModel; -} + if (space == Space::Local || parent == nullptr) + return localModel; + else if (space == Space::World) + return Multiply_Reduced(parent->GetModel2D_Reduced(space), localModel); + else + { + assert(false && "Error. Undefined enum value."); + return {}; + } + } -Math::Vector<3, float> Engine::SceneObject::GetForwardVector(Space space) const -{ - Math::UnitQuaternion<float> quat = localRotation; + Math::Matrix2x2 SceneObject::GetRotationModel2D(Space space) const + { + return Math::Matrix2x2(); + } + + Math::Matrix<3, 3, float> SceneObject::GetRotationModel(Space space) const + { + using namespace Math::LinTran3D; - const auto & s = quat.GetS(); - const auto & x = quat.GetX(); - const auto & y = quat.GetY(); - const auto & z = quat.GetZ(); + auto localModel = Rotate(localRotation); + if (space == Space::Local || parent == nullptr) + return localModel; + else if (space == Space::World) + return parent->GetRotationModel(space) * localModel; + else + { + assert(false && "Error. Undefined enum value."); + return {}; + } + } - return - Math::Vector<3, float> + Math::Vector<3, float> SceneObject::GetForwardVector(Space space) const { - 2 * x* z + 2 * y * s, - 2 * y* z - 2 * x * s, - 1 - 2 * Math::Sqrd(x) - 2 * Math::Sqrd(y) - }; -} + const auto& s = localRotation.GetS(); + const auto& x = localRotation.GetX(); + const auto& y = localRotation.GetY(); + const auto& z = localRotation.GetZ(); -Math::Vector<3, float> Engine::SceneObject::GetUpVector(Space space) const -{ - Math::UnitQuaternion<float> quat = localRotation; + Math::Vector<3, float> localForwardVector + { + 2 * x * z + 2 * y * s, + 2 * y * z - 2 * x * s, + 1 - 2 * Math::Sqrd(x) - 2 * Math::Sqrd(y) + }; + + if (space == Space::Local || parent == nullptr) + return localForwardVector; + else if (space == Space::World) + return parent->GetRotationModel(space) * localForwardVector; + else + { + assert(false && "Error. Undefined enum value."); + return {}; + } + } + + Math::Vector<3, float> SceneObject::GetUpVector(Space space) const + { + const auto& s = localRotation.GetS(); + const auto& x = localRotation.GetX(); + const auto& y = localRotation.GetY(); + const auto& z = localRotation.GetZ(); - const auto & s = quat.GetS(); - const auto & x = quat.GetX(); - const auto & y = quat.GetY(); - const auto & z = quat.GetZ(); + Math::Vector<3, float> localUpVector + { + 2 * x * y - 2 * z * s, + 1 - 2 * Math::Sqrd(x) - 2 * Math::Sqrd(z), + 2 * y * z + 2 * x * s + }; + + if (space == Space::Local || parent == nullptr) + return localUpVector; + else if (space == Space::World) + return parent->GetRotationModel(space) * localUpVector; + else + { + assert(false && "Error. Undefined enum value."); + return {}; + } + } - return - Math::Vector<3, float> + Math::Vector<3, float> SceneObject::GetRightVector(Space space) const { - 2 * x* y - 2 * z * s, - 1 - 2 * Math::Sqrd(x) - 2 * Math::Sqrd(z), - 2 * y* z + 2 * x * s - }; -} + const auto& s = localRotation.GetS(); + const auto& x = localRotation.GetX(); + const auto& y = localRotation.GetY(); + const auto& z = localRotation.GetZ(); -Math::Vector<3, float> Engine::SceneObject::GetRightVector(Space space) const -{ - Math::UnitQuaternion<float> quat = localRotation; - - const auto& s = quat.GetS(); - const auto& x = quat.GetX(); - const auto& y = quat.GetY(); - const auto& z = quat.GetZ(); - - return - Math::Vector<3, float> - { - 1 - 2 * Math::Sqrd(y) - 2 * Math::Sqrd(z), - 2 * x * y + 2 * z * s, - 2 * x * z - 2 * y * s - }; -} - -void Engine::Destroy(SceneObject& sceneObject) -{ - Core::Destroy(sceneObject); + Math::Vector<3, float> localRightVector + { + 1 - 2 * Math::Sqrd(y) - 2 * Math::Sqrd(z), + 2 * x * y + 2 * z * s, + 2 * x * z - 2 * y * s + }; + + if (space == Space::Local || parent == nullptr) + return localRightVector; + else if (space == Space::World) + return parent->GetRotationModel(space) * localRightVector; + else + { + assert(false && "Error. Undefined enum value."); + return {}; + } + } + + void Engine::Destroy(SceneObject & sceneObject) + { + Core::Destroy(sceneObject); + } } \ No newline at end of file diff --git a/src/Engine/Systems/RenderSystem.cpp b/src/Engine/Systems/RenderSystem.cpp index 5afbc6e99e26da3e84c796cf1d80ec646b6f1472..8cfd17be4ba7849608069ba643b4ae573b97246b 100644 --- a/src/Engine/Systems/RenderSystem.cpp +++ b/src/Engine/Systems/RenderSystem.cpp @@ -12,19 +12,7 @@ namespace Engine { void RenderSystem::BuildRenderGraph(const Scene& scene, Renderer::RenderGraph& graph) { - auto spriteComponentsPtr = scene.GetAllComponents<Components::SpriteRenderer>(); - if (spriteComponentsPtr == nullptr) - graph.sprites.clear(); - else - { - const auto& spriteComponents = *spriteComponentsPtr; - graph.sprites.resize(spriteComponents.size()); - for (size_t i = 0; i < spriteComponents.size(); i++) - { - const auto& spriteComponent = spriteComponents[i]; - } - } - + // Copies all the MeshID and TextureID data (no positional data) from the components into the RenderGraph auto meshComponentsPtr = scene.GetAllComponents<Components::MeshRenderer>(); if (meshComponentsPtr == nullptr) graph.meshes.clear(); @@ -44,6 +32,7 @@ namespace Engine } } + // Loads all PointLight data (no positional data) onto the RenderGraph struct. auto pointLightComponentsPtr = scene.GetAllComponents<Components::PointLight>(); if (pointLightComponentsPtr == nullptr) graph.pointLightIntensities.clear(); @@ -63,17 +52,9 @@ namespace Engine void RenderSystem::BuildRenderGraphTransform(const Scene& scene, Renderer::RenderGraphTransform& transforms) { - auto spriteComponentsPtr = scene.GetAllComponents<Components::SpriteRenderer>(); - if (spriteComponentsPtr == nullptr) - transforms.sprites.clear(); - else - { - const auto& spriteComponents = *spriteComponentsPtr; - transforms.sprites.resize(spriteComponents.size()); - for (size_t i = 0; i < spriteComponents.size(); i++) - transforms.sprites[i] = spriteComponents[i].GetModel(Space::World).data; - } - + // Copies all the Mesh-components' positional data onto the RenderGraphTransform struct. + // This copies a full 4x4 matrix, it's faster because everything has + // to be converted to that format to move up the parent SceneObject chain anyways auto meshComponentsPtr = scene.GetAllComponents<Components::MeshRenderer>(); if (meshComponentsPtr == nullptr) transforms.meshes.clear(); @@ -85,6 +66,7 @@ namespace Engine transforms.meshes[i] = meshComponents[i].GetModel(Space::World).data; } + // Loads all the PointLight components' positional data over to the RenderGraphTransform auto pointLightComponentsPtr = scene.GetAllComponents<Components::PointLight>(); if (pointLightComponentsPtr == nullptr) transforms.pointLights.clear(); @@ -94,8 +76,7 @@ namespace Engine transforms.pointLights.resize(pointLightComponents.size()); for (size_t i = 0; i < pointLightComponents.size(); i++) { - const auto& model = pointLightComponents[i].GetModel_Reduced(Space::World); - const Math::Vector3D& position = Math::LinTran3D::GetTranslation(model); + const auto& position = pointLightComponents[i].GetPosition(Space::World); transforms.pointLights[i] = { position.x, position.y, position.z }; } } diff --git a/src/InputRotate.cpp b/src/InputRotate.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d4770245febadc1051762589fc567288707550f4 --- /dev/null +++ b/src/InputRotate.cpp @@ -0,0 +1,35 @@ +#include "InputRotate.hpp" + +#include "DEngine/SceneObject.hpp" +#include "DEngine/Scene.hpp" + +#include "DMath/Trigonometric.hpp" + +#include "DEngine/Input/InputRaw.hpp" + +namespace Assignment02 +{ + InputRotate::InputRotate(Engine::SceneObject& owner) : + ParentType(owner) + { + + } + + void InputRotate::SceneStart() + { + ParentType::SceneStart(); + } + + void InputRotate::Tick() + { + ParentType::Tick(); + + const auto& scene = GetSceneObject().GetScene(); + float deltaTime = scene.GetTimeData().GetDeltaTime(); + + if (Engine::Input::Raw::GetValue(Engine::Input::Raw::Button::Up)) + GetSceneObject().localRotation = Math::UnitQuaternion<float>({ 0.f, 0.f, 10.f * deltaTime }) * GetSceneObject().localRotation; + if (Engine::Input::Raw::GetValue(Engine::Input::Raw::Button::Down)) + GetSceneObject().localRotation = Math::UnitQuaternion<float>({ 0.f, 0.f, -10.f * deltaTime }) * GetSceneObject().localRotation; + } +} \ No newline at end of file diff --git a/src/SinusMovement.cpp b/src/SinusMovement.cpp index 3d69eab9fb1962decd17a5185b10fcbd4e914e98..852062eee9133c37daccb402c1766210318f051b 100644 --- a/src/SinusMovement.cpp +++ b/src/SinusMovement.cpp @@ -30,8 +30,6 @@ namespace Assignment02 float time = scene.GetTimeData().GetTimeSinceSceneStart(); - float timeMultiplier = 25.f; - float moveMagnitudeMultipler = 7.5f; - GetSceneObject().localPosition.x = startPos.x + Math::Sin(time * timeMultiplier) * moveMagnitudeMultipler; + GetSceneObject().localPosition.x = startPos.x + Math::Sin(time * timeMultiplier) * movementMultiplier; } } \ No newline at end of file