diff --git a/Editor/resources/Shaders/combine.shader b/Editor/resources/Shaders/combine.shader index df932b51..4e42e6ac 100644 --- a/Editor/resources/Shaders/combine.shader +++ b/Editor/resources/Shaders/combine.shader @@ -27,5 +27,5 @@ void main() vec4 a = texture(u_Source, UV); vec4 b = texture(u_Source2, UV); - FragColor = vec4(vec3(a.rgb + b.rgb / 2.0), a.a * b.a); + FragColor = vec4(vec3(a.rgb + (b.rgb) / 2.0), a.a); } \ No newline at end of file diff --git a/Editor/resources/Shaders/deferred.shader b/Editor/resources/Shaders/deferred.shader index c9d14654..39b4c5a0 100644 --- a/Editor/resources/Shaders/deferred.shader +++ b/Editor/resources/Shaders/deferred.shader @@ -180,7 +180,7 @@ float ShadowCalculation(Light light, vec3 FragPos, vec3 normal) float bias = max(0.005 * (1.0 - dot(normal, light.Direction)), 0.0005); //float pcfDepth = texture(ShadowMaps[shadowmap], vec3(projCoords.xy, currentDepth), bias); - if (shadowmap <= 3) + if (shadowmap <= 4) { const float NUM_SAMPLES = 4.f; const float SAMPLES_START = (NUM_SAMPLES - 1.0f) / 2.0f; @@ -272,7 +272,7 @@ void main() // scale light by NdotL float NdotL = max(dot(N, L), 0.0); - Lo += (kD * albedo / PI) * radiance * NdotL;// note that we already multiplied the BRDF by the Fresnel (kS) so we won't multiply by kS again + Lo += (kD * albedo / PI + specular) * radiance * NdotL;// note that we already multiplied the BRDF by the Fresnel (kS) so we won't multiply by kS again } /// ambient lighting (we now use IBL as the ambient term) @@ -282,7 +282,7 @@ void main() vec3 kD = 1.0 - kS; kD *= 1.0 - metallic; - vec3 ambient = (kD * albedo) * (ao) * ssao; + vec3 ambient = (vec3(0.5) * albedo) * (ao)*ssao; vec3 color = (ambient) + Lo; // Display CSM splits.. diff --git a/Editor/resources/Shaders/shadowMap_skinned.shader b/Editor/resources/Shaders/shadowMap_skinned.shader new file mode 100644 index 00000000..9e91acee --- /dev/null +++ b/Editor/resources/Shaders/shadowMap_skinned.shader @@ -0,0 +1,45 @@ +#shader vertex +#version 460 core + +layout(location = 0) in vec3 Position; +layout(location = 1) in vec2 UVPosition; +layout(location = 2) in vec3 Normal; +layout(location = 3) in vec3 Tangent; +layout(location = 4) in vec3 Bitangent; +layout(location = 5) in ivec4 BoneIDs; +layout(location = 6) in vec4 Weights; + +uniform mat4 u_LightTransform; + +const int MAX_BONES = 200; +const int MAX_BONES_INFLUENCE = 4; +uniform mat4 u_FinalBonesMatrice[MAX_BONES]; + +void main() +{ + vec4 totalPosition = vec4(0.0f); + for (int i = 0; i < MAX_BONES_INFLUENCE; i++) + { + if (BoneIDs[i] == -1) + { + continue; + } + + if (BoneIDs[i] >= MAX_BONES) + { + totalPosition = vec4(Position, 1.0f); + break; + } + + vec4 localPosition = u_FinalBonesMatrice[BoneIDs[i]] * vec4(Position, 1.0f); + totalPosition += localPosition * Weights[i]; + // vec3 localNormal = mat3(u_FinalBonesMatrice[BoneIDs[i]]) * Normal; + } + + gl_Position = u_LightTransform * totalPosition; +} + +#shader fragment +#version 460 core + +void main() { } \ No newline at end of file diff --git a/Editor/src/Windows/EditorInterface.cpp b/Editor/src/Windows/EditorInterface.cpp index 0196ef75..112b14de 100644 --- a/Editor/src/Windows/EditorInterface.cpp +++ b/Editor/src/Windows/EditorInterface.cpp @@ -46,6 +46,7 @@ #include "src/Rendering/SceneRenderer.h" #include #include +#include "UIDemoWindow.h" namespace Nuake { Ref userInterface; @@ -1544,6 +1545,7 @@ namespace Nuake { bool isLoadingProject = false; bool isLoadingProjectQueue = false; + UIDemoWindow m_DemoWindow; int frameCount = 2; void EditorInterface::Draw() @@ -1610,6 +1612,8 @@ namespace Nuake { pInterface.m_CurrentProject = Engine::GetProject(); + m_DemoWindow.Draw(); + _audioWindow->Draw(); DrawMenuBar(); diff --git a/Editor/src/Windows/FileSystemUI.cpp b/Editor/src/Windows/FileSystemUI.cpp index ab952c97..7c2fb4a1 100644 --- a/Editor/src/Windows/FileSystemUI.cpp +++ b/Editor/src/Windows/FileSystemUI.cpp @@ -62,9 +62,9 @@ namespace Nuake void FileSystemUI::DrawDirectory(Ref directory, uint32_t drawId) { ImGui::PushFont(FontManager::GetFont(Icons)); + ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 4.0f); const char* icon = ICON_FA_FOLDER; const std::string id = ICON_FA_FOLDER + std::string("##") + directory->name; - ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 4.0f); if (ImGui::Button(id.c_str(), ImVec2(100, 100))) { m_CurrentDirectory = directory; diff --git a/Editor/src/Windows/UIDemoWindow.cpp b/Editor/src/Windows/UIDemoWindow.cpp new file mode 100644 index 00000000..39ec1513 --- /dev/null +++ b/Editor/src/Windows/UIDemoWindow.cpp @@ -0,0 +1,20 @@ +#include "UIDemoWindow.h" + +#include "src/UI/ImUI.h" + +float floatSlider = 0.6f; +bool checkbox = false; + +void UIDemoWindow::Draw() +{ + using namespace Nuake; + + UI::BeginWindow("UI Demo"); + { + UI::PrimaryButton("Primary Button"); + UI::SecondaryButton("Secondary Button"); + UI::FloatSlider("Float slider", floatSlider); + UI::CheckBox("Checkbox", checkbox); + } + UI::EndWindow(); +} \ No newline at end of file diff --git a/Editor/src/Windows/UIDemoWindow.h b/Editor/src/Windows/UIDemoWindow.h new file mode 100644 index 00000000..af0d9859 --- /dev/null +++ b/Editor/src/Windows/UIDemoWindow.h @@ -0,0 +1,13 @@ +#pragma once + + +class UIDemoWindow +{ +public: + UIDemoWindow() = default; + ~UIDemoWindow() = default; + + void Draw(); +}; + + \ No newline at end of file diff --git a/Nuake/src/Core/FileSystem.cpp b/Nuake/src/Core/FileSystem.cpp index c7d15487..a7b1c642 100644 --- a/Nuake/src/Core/FileSystem.cpp +++ b/Nuake/src/Core/FileSystem.cpp @@ -174,12 +174,12 @@ namespace Nuake fileWriter.close(); } - int FileSystem::DeleteFileFromPath(const std::string& path) + uintmax_t FileSystem::DeleteFileFromPath(const std::string& path) { return std::remove(path.c_str()); } - int FileSystem::DeleteFolder(const std::string& path) + uintmax_t FileSystem::DeleteFolder(const std::string& path) { return std::filesystem::remove_all(path.c_str()); } diff --git a/Nuake/src/Core/FileSystem.h b/Nuake/src/Core/FileSystem.h index 8327e343..98ff2f74 100644 --- a/Nuake/src/Core/FileSystem.h +++ b/Nuake/src/Core/FileSystem.h @@ -47,8 +47,8 @@ namespace Nuake static bool BeginWriteFile(const std::string path); static bool WriteLine(const std::string line); static void EndWriteFile(); - static int DeleteFileFromPath(const std::string& path); - static int DeleteFolder(const std::string& path); + static uintmax_t DeleteFileFromPath(const std::string& path); + static uintmax_t DeleteFolder(const std::string& path); }; class File diff --git a/Nuake/src/Rendering/RenderList.h b/Nuake/src/Rendering/RenderList.h index 619477a3..b1bf3562 100644 --- a/Nuake/src/Rendering/RenderList.h +++ b/Nuake/src/Rendering/RenderList.h @@ -49,8 +49,12 @@ namespace Nuake for (auto& m : i.second) { + if (!depthOnly) + { + shader->SetUniform1i(entityIdUniformLocation, m.entityId + 1); + } + shader->SetUniformMat4f(modelMatrixUniformLocation, m.transform); - shader->SetUniform1i(entityIdUniformLocation, m.entityId + 1); m.Mesh->Draw(shader, false); } } diff --git a/Nuake/src/Rendering/SceneRenderer.cpp b/Nuake/src/Rendering/SceneRenderer.cpp index 0dddd99a..60dad487 100644 --- a/Nuake/src/Rendering/SceneRenderer.cpp +++ b/Nuake/src/Rendering/SceneRenderer.cpp @@ -262,6 +262,43 @@ namespace Nuake } } } + + Shader* gBufferSkinnedMeshShader = ShaderManager::GetShader("resources/Shaders/shadowMap_skinned.shader"); + gBufferSkinnedMeshShader->Bind(); + const uint32_t modelMatrixUniformLocation = gBufferSkinnedMeshShader->FindUniformLocation("u_Model"); + gBufferSkinnedMeshShader->SetUniformMat4f(modelMatrixUniformLocation, Matrix4(1.0f)); + + auto skinnedView = scene.m_Registry.view(); + for (auto l : view) + { + auto [lightTransform, light, visibility] = view.get(l); + if (light.Type != LightType::Directional || !light.CastShadows || !visibility.Visible) + { + continue; + } + + for (int i = 0; i < CSM_AMOUNT; i++) + { + light.m_Framebuffers[i]->Bind(); + { + gBufferSkinnedMeshShader->SetUniformMat4f("u_LightTransform", light.mViewProjections[i]); + for (auto e : skinnedView) + { + auto [transform, mesh, visibility] = skinnedView.get(e); + if (mesh.ModelResource != nullptr && visibility.Visible) + { + auto& rootBoneNode = mesh.ModelResource->GetSkeletonRootNode(); + SetSkeletonBoneTransformRecursive(rootBoneNode, gBufferSkinnedMeshShader); + + for (auto& m : mesh.ModelResource->GetMeshes()) + { + m->Draw(gBufferSkinnedMeshShader, false); + } + } + } + } + } + } } void SceneRenderer::GBufferPass(Scene& scene) @@ -293,10 +330,8 @@ namespace Nuake } } } - Renderer::Flush(gBufferShader, false); - // Quake BSPs auto quakeView = scene.m_Registry.view(); for (auto e : quakeView) @@ -311,9 +346,9 @@ namespace Nuake Renderer::SubmitMesh(b, transform.GetGlobalTransform(), (uint32_t)e); } } - Renderer::Flush(gBufferShader, false); + RenderCommand::Disable(RendererEnum::FACE_CULL); // Sprites auto spriteView = scene.m_Registry.view(); for (auto& e : spriteView) @@ -399,7 +434,6 @@ namespace Nuake if (meshResource && visibility.Visible) { auto& rootBoneNode = meshResource->GetSkeletonRootNode(); - SetSkeletonBoneTransformRecursive(rootBoneNode, gBufferSkinnedMeshShader); for (auto& m : mesh.ModelResource->GetMeshes()) diff --git a/Nuake/src/Rendering/Textures/Texture.cpp b/Nuake/src/Rendering/Textures/Texture.cpp index 217e740a..06b06bd1 100644 --- a/Nuake/src/Rendering/Textures/Texture.cpp +++ b/Nuake/src/Rendering/Textures/Texture.cpp @@ -41,7 +41,7 @@ namespace Nuake } } - Texture::Texture(glm::vec2 size, GLenum format, GLenum format2, GLenum format3, void* data) + Texture::Texture(Vector2 size, GLenum format, GLenum format2, GLenum format3, void* data) { m_RendererId = 0; m_Format = format; @@ -67,24 +67,20 @@ namespace Nuake //glGenerateMipmap(GL_TEXTURE_2D); } - Texture::Texture(Vector2 size, unsigned char* data, int len) + Texture::Texture(unsigned char* data, int len) { m_RendererId = 0; - m_Width = size.x; - m_Height = size.y; int channels = 0; m_LocalBuffer = stbi_load_from_memory(data, len, &m_Width, &m_Height, &channels, 0); glGenTextures(1, &m_RendererId); glBindTexture(GL_TEXTURE_2D, m_RendererId); glGenerateMipmap(GL_TEXTURE_2D); - //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, -1.0f); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, m_Width, m_Height, 0, GL_RGB, GL_UNSIGNED_BYTE, m_LocalBuffer); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_Width, m_Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, m_LocalBuffer); glGenerateMipmap(GL_TEXTURE_2D); if (m_LocalBuffer) @@ -93,12 +89,12 @@ namespace Nuake } else { - const std::string msg = "failed to load texture buffer"; + const std::string msg = "Failed to load texture from buffer"; Logger::Log(msg, "texture", WARNING); } } - Texture::Texture(glm::vec2 size, msdfgen::BitmapConstRef& bitmap, bool t) + Texture::Texture(Vector2 size, msdfgen::BitmapConstRef& bitmap, bool t) { m_RendererId = 0; m_Width = size.x; @@ -110,7 +106,6 @@ namespace Nuake glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - auto pixel = bitmap(0, bitmap.height - 0 - 1); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, m_Width, m_Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (unsigned char*)bitmap.pixels); } diff --git a/Nuake/src/Rendering/Textures/Texture.h b/Nuake/src/Rendering/Textures/Texture.h index 5654da0b..8654ca4e 100644 --- a/Nuake/src/Rendering/Textures/Texture.h +++ b/Nuake/src/Rendering/Textures/Texture.h @@ -28,10 +28,11 @@ namespace Nuake int m_BPP; // byte per pixel. public: - Texture(const std::string& path); - Texture(glm::vec2 size, msdfgen::BitmapConstRef& bitmap, bool t); - Texture(glm::vec2 size, GLenum format, GLenum format2 = 0, GLenum format3 = 0, void* data = NULL); - Texture(Vector2 size, unsigned char* data, int len); + Texture(const std::string& path); // Load texture from file + Texture(unsigned char* data, int len); // Used to load texture from a memory buffer + + Texture(Vector2 size, GLenum format, GLenum format2 = 0, GLenum format3 = 0, void* data = 0); // Used to load texture from memeory with known size + Texture(Vector2 size, msdfgen::BitmapConstRef& bitmap, bool t); // Used internally for MSDF fonts ~Texture(); void Resize(glm::vec2 size); diff --git a/Nuake/src/Resource/ModelLoader.cpp b/Nuake/src/Resource/ModelLoader.cpp index d9ab3048..7aece8b2 100644 --- a/Nuake/src/Resource/ModelLoader.cpp +++ b/Nuake/src/Resource/ModelLoader.cpp @@ -522,9 +522,19 @@ namespace Nuake uint32_t textureIndex = std::atoi(String::Split(path, '*')[1].c_str()); const aiTexture* aitexture = scene->GetEmbeddedTexture(path.c_str()); - Vector2 textureSize = Vector2(aitexture->mWidth, aitexture->mHeight); - auto texture = CreateRef(textureSize, (unsigned char*)aitexture->pcData, textureSize.x); - return texture; + Ref nuakeTexture; + if (aitexture->mHeight == 0) + { + // We are using a compression like jpeg, where width is the size of the buffer in bytes. + nuakeTexture = CreateRef((unsigned char*)aitexture->pcData, aitexture->mWidth); + } + else + { + Vector2 textureSize = Vector2(aitexture->mWidth, aitexture->mHeight); + nuakeTexture = CreateRef((unsigned char*)aitexture->pcData, textureSize.x); + } + + return nuakeTexture; } std::string texturePath = modelDir + path; diff --git a/Nuake/src/Resource/Serializable.h b/Nuake/src/Resource/Serializable.h index 17a22834..5d243f59 100644 --- a/Nuake/src/Resource/Serializable.h +++ b/Nuake/src/Resource/Serializable.h @@ -34,6 +34,27 @@ p = j[#p]; \ #define DESERIALIZE_VEC2(v, p) \ p = Vector2(v["x"], v["y"]); +#define SERIALIZE_MAT4(lbl, m) \ +{ \ + int i = 0; \ + for (int l = 0; l < 4; l++) { \ + for (int k = 0; k < 4; k++) { \ + j[lbl][i] = m[l][k]; \ + i++; \ + } \ + } \ +} + +#define DESERIALIZE_MAT4(lbl, m) \ +{ \ + int i = 0; \ + for(int l = 0; l < 4; l++) { \ + for(int k = 0; k < 4; k++) { \ + m[l][k] = j[lbl][i];\ + i++; \ + } \ + } \ +} #define SERIALIZE_OBJECT(v) j[#v] = v->Serialize(); #define SERIALIZE_OBJECT_REF(v) j[#v] = v.Serialize(); diff --git a/Nuake/src/Resource/SkeletalAnimation.cpp b/Nuake/src/Resource/SkeletalAnimation.cpp index 80e5d180..46d73a82 100644 --- a/Nuake/src/Resource/SkeletalAnimation.cpp +++ b/Nuake/src/Resource/SkeletalAnimation.cpp @@ -11,6 +11,11 @@ namespace Nuake m_PositionTimestamps = std::vector(); m_RotationTimestamps = std::vector(); m_ScaleTimestamps = std::vector(); + + m_PositionTransform = Matrix4(1.0f); + m_RotationTransform = Matrix4(1.0f); + m_ScaleTransform = Matrix4(1.0f); + m_FinalTransform = Matrix4(1.0f); } float BoneTransformTrack::GetScaleFactor(float lastTime, float nextTime, float animationTime) @@ -22,7 +27,7 @@ namespace Nuake return scaleFactor; } - Nuake::Matrix4 BoneTransformTrack::InterpolatePosition(float time) + Matrix4 BoneTransformTrack::InterpolatePosition(float time) { if (m_Positions.size() == 0) { @@ -34,14 +39,20 @@ namespace Nuake return glm::translate(Matrix4(1.0f), m_Positions[0]); } + // This returns the last position when we are at the last keyframe int p0Index = GetPositionIndex(time); + if (p0Index == m_Positions.size() - 1) + { + return glm::translate(Matrix4(1.0f), m_Positions[p0Index]); + } + int p1Index = p0Index + 1; float scaleFactor = GetScaleFactor(m_PositionTimestamps[p0Index], m_PositionTimestamps[p1Index], time); - glm::vec3 finalPosition = glm::mix(m_Positions[p0Index], m_Positions[p1Index], scaleFactor); + Vector3 finalPosition = glm::mix(m_Positions[p0Index], m_Positions[p1Index], scaleFactor); return glm::translate(Matrix4(1.0f), finalPosition); } - Nuake::Matrix4 BoneTransformTrack::InterpolateRotation(float time) + Matrix4 BoneTransformTrack::InterpolateRotation(float time) { if (m_Rotations.size() == 0) { @@ -54,17 +65,21 @@ namespace Nuake return glm::toMat4(rotation); } + // This returns the last rotation when we are at the last keyframe int p0Index = GetRotationIndex(time); + if (p0Index == m_Rotations.size() - 1) + { + return glm::toMat4(m_Rotations[p0Index]); + } + int p1Index = p0Index + 1; - float scaleFactor = GetScaleFactor(m_RotationTimestamps[p0Index], - m_RotationTimestamps[p1Index], time); - glm::quat finalRotation = glm::slerp(m_Rotations[p0Index], - m_Rotations[p1Index], scaleFactor); + float scaleFactor = GetScaleFactor(m_RotationTimestamps[p0Index], m_RotationTimestamps[p1Index], time); + Quat finalRotation = glm::slerp(m_Rotations[p0Index],m_Rotations[p1Index], scaleFactor); finalRotation = glm::normalize(finalRotation); return glm::toMat4(finalRotation); } - Nuake::Matrix4 BoneTransformTrack::InterpolateScale(float time) + Matrix4 BoneTransformTrack::InterpolateScale(float time) { if (m_Scales.size() == 0) { @@ -72,14 +87,21 @@ namespace Nuake } if (1 == m_Scales.size()) + { return glm::scale(glm::mat4(1.0f), m_Scales[0]); + } + // This returns the last rotation when we are at the last keyframe int p0Index = GetScaleIndex(time); + if (p0Index == m_Scales.size() - 1) + { + return glm::scale(Matrix4(1.0f), m_Scales[p0Index]); + } + int p1Index = p0Index + 1; - float scaleFactor = GetScaleFactor(m_ScaleTimestamps[p0Index], - m_ScaleTimestamps[p1Index], time); - glm::vec3 finalScale = glm::mix(m_Scales[p0Index], m_Scales[p1Index], scaleFactor); - return glm::scale(glm::mat4(1.0f), finalScale); + float scaleFactor = GetScaleFactor(m_ScaleTimestamps[p0Index], m_ScaleTimestamps[p1Index], time); + Vector3 finalScale = glm::mix(m_Scales[p0Index], m_Scales[p1Index], scaleFactor); + return glm::scale(Matrix4(1.0f), finalScale); } json BoneTransformTrack::Serialize() diff --git a/Nuake/src/Resource/SkeletalAnimation.h b/Nuake/src/Resource/SkeletalAnimation.h index 15824a9f..cab1a2bc 100644 --- a/Nuake/src/Resource/SkeletalAnimation.h +++ b/Nuake/src/Resource/SkeletalAnimation.h @@ -59,25 +59,11 @@ namespace Nuake m_Scales.push_back(scale); } - int GetPositionIndex(float animationTime) - { - if (m_Positions.size() == 0) - { - return 0; - } - - for (int index = 0; index < m_Positions.size() - 1; index++) - { - if (animationTime < m_PositionTimestamps[index + 1]) - { - return index; - } - } - assert(0); - } - void Update(float time) { + // We cannot use const reference here because we would compare the reference to previous pos + // to the m_PositionTransform and previous pos always equale. + // Making the hasChanged always false. We would end up comparing the same values always. const Matrix4 previousPos = m_PositionTransform; const Matrix4 previousRot = m_RotationTransform; const Matrix4 previousSca = m_ScaleTransform; @@ -97,6 +83,24 @@ namespace Nuake return m_FinalTransform; } + int GetPositionIndex(float animationTime) + { + if (m_Positions.size() == 0) + { + return 0; + } + + for (int index = 0; index < m_Positions.size() - 1; index++) + { + if (animationTime < m_PositionTimestamps[index + 1]) + { + return index; + } + } + + return static_cast(m_Positions.size()) - 1; + } + /* Gets the current index on mKeyRotations to interpolate to based on the current animation time*/ int GetRotationIndex(float animationTime) @@ -108,7 +112,8 @@ namespace Nuake return index; } } - assert(0); + + return static_cast(m_Rotations.size()) - 1; } /* Gets the current index on mKeyScalings to interpolate to based on the @@ -122,7 +127,8 @@ namespace Nuake return index; } } - assert(0); + + return static_cast(m_Scales.size()) - 1; } float GetScaleFactor(float lastTime, float nextTime, float animationTime); @@ -158,7 +164,7 @@ namespace Nuake } else { - m_CurrentTime = time; + m_CurrentTime = std::max(time, m_Duration); } } diff --git a/Nuake/src/Resource/SkeletonNode.h b/Nuake/src/Resource/SkeletonNode.h index 32b54a3b..e5c22555 100644 --- a/Nuake/src/Resource/SkeletonNode.h +++ b/Nuake/src/Resource/SkeletonNode.h @@ -1,6 +1,7 @@ #pragma once #include "src/Core/Core.h" #include "src/Core/Maths.h" +#include "src/Resource/Serializable.h" namespace Nuake { @@ -14,5 +15,47 @@ namespace Nuake Matrix4 FinalTransform = Matrix4(1.0f); int32_t Id = -1; int32_t EntityHandle = 0; + + json Serialize() + { + BEGIN_SERIALIZE(); + SERIALIZE_MAT4("Transform", Transform); + SERIALIZE_MAT4("Offset", Offset); + SERIALIZE_VAL(Name); + SERIALIZE_VAL(ChildrenCount); + SERIALIZE_VAL(Id); + SERIALIZE_VAL(EntityHandle); + + uint32_t i = 0; + for (auto& c : Children) + { + j["Children"][i] = c.Serialize(); + i++; + } + + END_SERIALIZE(); + } + + bool Deserialize(json j) + { + DESERIALIZE_MAT4("Transform", Transform); + DESERIALIZE_MAT4("Offset", Offset); + DESERIALIZE_VAL(Name); + DESERIALIZE_VAL(ChildrenCount); + DESERIALIZE_VAL(Id); + DESERIALIZE_VAL(EntityHandle); + + if (j.contains("Children")) + { + for (uint32_t i = 0; i < ChildrenCount; i++) + { + SkeletonNode newChildren; + newChildren.Deserialize(j["Children"][i]); + Children.push_back(std::move(newChildren)); + } + } + + return true; + } }; } \ No newline at end of file diff --git a/Nuake/src/Resource/SkinnedModel.cpp b/Nuake/src/Resource/SkinnedModel.cpp index ac71f490..39f4187a 100644 --- a/Nuake/src/Resource/SkinnedModel.cpp +++ b/Nuake/src/Resource/SkinnedModel.cpp @@ -71,6 +71,7 @@ namespace Nuake if (this->Path != "") { j["Path"] = this->Path; + j["SkeletonNode"] = m_SkeletonRoot.Serialize(); } else { @@ -86,10 +87,9 @@ namespace Nuake for (auto& animation : m_Animations) { j["m_Animations"][a] = animation->Serialize(); + a++; } - } - END_SERIALIZE(); } @@ -108,6 +108,13 @@ namespace Nuake m_NumAnimation = m_Animations.size(); m_CurrentAnimation = 0; + if (j.contains("SkeletonNode")) + { + SkeletonNode skeletonNode; + skeletonNode.Deserialize(j["SkeletonNode"]); + m_SkeletonRoot = std::move(skeletonNode); + } + this->Path = j["Path"]; } else diff --git a/Nuake/src/Scene/Components/SkinnedModelComponent.h b/Nuake/src/Scene/Components/SkinnedModelComponent.h index 0e6bdb53..b0abed18 100644 --- a/Nuake/src/Scene/Components/SkinnedModelComponent.h +++ b/Nuake/src/Scene/Components/SkinnedModelComponent.h @@ -35,6 +35,7 @@ namespace Nuake bool Deserialize(const json& j) { ModelPath = j["ModelPath"]; + ModelResource = CreateRef(); if (j.contains("ModelResource")) diff --git a/Nuake/src/Scene/Scene.cpp b/Nuake/src/Scene/Scene.cpp index 52e11da7..6fcf724d 100644 --- a/Nuake/src/Scene/Scene.cpp +++ b/Nuake/src/Scene/Scene.cpp @@ -486,7 +486,6 @@ namespace Nuake skeletonRoot.EntityHandle = skeletonRootEntity.GetID(); entity.AddChild(skeletonRootEntity); - Vector3 bonePosition; Quat boneRotation; Vector3 boneScale; diff --git a/Nuake/src/Scene/Systems/AnimationSystem.cpp b/Nuake/src/Scene/Systems/AnimationSystem.cpp index 9aa7fdd2..f384d495 100644 --- a/Nuake/src/Scene/Systems/AnimationSystem.cpp +++ b/Nuake/src/Scene/Systems/AnimationSystem.cpp @@ -36,28 +36,24 @@ namespace Nuake { float newAnimationTime = animation->GetCurrentTime() + (ts * animation->GetTicksPerSecond()); animation->SetCurrentTime(newAnimationTime); - - auto& rootBone = model->GetSkeletonRootNode(); - UpdateBonePositionTraversal(rootBone, animation, animation->GetCurrentTime()); } + + auto& rootBone = model->GetSkeletonRootNode(); + UpdateBonePositionTraversal(rootBone, animation, animation->GetCurrentTime(), model->IsPlaying); } } - void AnimationSystem::UpdateBonePositionTraversal(SkeletonNode& bone, Ref animation, float time) + void AnimationSystem::UpdateBonePositionTraversal(SkeletonNode& bone, Ref animation, float time, bool isPlaying) { - const std::string& boneName = bone.Name; - - auto& animationTrack = animation->GetTrack(boneName); + auto& animationTrack = animation->GetTrack(bone.Name); - Entity& boneEntity = m_Scene->GetEntity(boneName); Entity& boneEnt = m_Scene->GetEntityByID(bone.EntityHandle); - ///assert(boneEnt.GetHandle() == boneEntity.GetHandle()); if (boneEnt.IsValid()) { auto& transformComponent = boneEnt.GetComponent(); bone.FinalTransform = transformComponent.GetGlobalTransform() * bone.Offset; - //if (!animationTrack.IsEmpty()) + if (!animationTrack.IsEmpty() && isPlaying) { // Get Update transform animationTrack.Update(time); @@ -76,10 +72,10 @@ namespace Nuake transformComponent.Dirty = false; } } - + for (auto& childBone : bone.Children) { - UpdateBonePositionTraversal(childBone, animation, time); + UpdateBonePositionTraversal(childBone, animation, time, isPlaying); } } diff --git a/Nuake/src/Scene/Systems/AnimationSystem.h b/Nuake/src/Scene/Systems/AnimationSystem.h index 57361dad..604a77b5 100644 --- a/Nuake/src/Scene/Systems/AnimationSystem.h +++ b/Nuake/src/Scene/Systems/AnimationSystem.h @@ -19,6 +19,6 @@ namespace Nuake void Exit() override; private: - void UpdateBonePositionTraversal(SkeletonNode& bone, Ref animation, float time); + void UpdateBonePositionTraversal(SkeletonNode& bone, Ref animation, float time, bool isPlaying); }; } diff --git a/Nuake/src/Scene/Systems/TransformSystem.cpp b/Nuake/src/Scene/Systems/TransformSystem.cpp index 9986e892..e9ee86f3 100644 --- a/Nuake/src/Scene/Systems/TransformSystem.cpp +++ b/Nuake/src/Scene/Systems/TransformSystem.cpp @@ -78,8 +78,9 @@ namespace Nuake Quat globalOrientation = transform.GetLocalRotation(); Vector3 globalScale = transform.GetLocalScale(); -#ifndef FRAME_PERFECT_TRANSFORM ParentComponent parentComponent = currentParent.GetComponent(); +#define FRAME_PERFECT_TRANSFORM +#ifndef FRAME_PERFECT_TRANSFORM if (parentComponent.HasParent) { TransformComponent& transformComponent = parentComponent.Parent.GetComponent(); diff --git a/Nuake/src/UI/ImUI.h b/Nuake/src/UI/ImUI.h new file mode 100644 index 00000000..b65a4f24 --- /dev/null +++ b/Nuake/src/UI/ImUI.h @@ -0,0 +1,154 @@ +#pragma once +#include "src/Core/Core.h" +#include "src/Core/Maths.h" + +#include "imgui/imgui.h" +#include "../../../Editor/src/Misc/InterfaceFonts.h" + +#include "src/Resource/FontAwesome5.h" + +namespace Nuake +{ + namespace UI + { + static uint32_t PrimaryCol = IM_COL32(97, 0, 255, 255); + static uint32_t GrabCol = IM_COL32(97, 0, 255, 255); + + static ImVec2 ButtonPadding = ImVec2(16.0f, 8.0f); + static ImVec2 IconButtonPadding = ImVec2(8.0f, 8.0f); + + void BeginWindow(const std::string& name) + { + ImGui::Begin(name.c_str()); + } + + void EndWindow() + { + ImGui::End(); + } + + bool PrimaryButton(const std::string& name) + { + ImGui::PushStyleColor(ImGuiCol_Button, IM_COL32(97, 0, 255, 255)); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, IM_COL32(97, 0, 255, 200)); + ImGui::PushStyleColor(ImGuiCol_ButtonActive, IM_COL32(97, 0, 255, 255)); + + ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 4.0f); + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ButtonPadding); + + UIFont boldFont(Bold); + const bool buttonPressed = ImGui::Button(name.c_str()); + + ImGui::PopStyleColor(3); + + ImGui::PopStyleVar(2); + + return buttonPressed; + } + + bool SecondaryButton(const std::string& name) + { + ImGui::PushStyleColor(ImGuiCol_Button, IM_COL32(0, 0, 0, 0)); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, IM_COL32(97, 0, 255, 200)); + ImGui::PushStyleColor(ImGuiCol_ButtonActive, IM_COL32(97, 0, 255, 255)); + ImGui::PushStyleColor(ImGuiCol_Border, PrimaryCol); + + ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 2.0f); + ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 4.0f); + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ButtonPadding); + + UIFont boldFont(Bold); + const bool buttonPressed = ImGui::Button(name.c_str()); + + ImGui::PopStyleVar(3); + + ImGui::PopStyleColor(4); + + return buttonPressed; + } + + bool IconButton(const std::string& icon) + { + ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 4.0f); + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, IconButtonPadding); + + const float height = ImGui::GetTextLineHeight() + ButtonPadding.y * 2.0; + const bool isPressed = ImGui::Button(icon.c_str(), ImVec2(height, height)); + + ImGui::PopStyleVar(2); + + return isPressed; + } + + bool FloatSlider(const std::string& name, float& input, float min = 0.0f, float max = 1.0f, float speed = 0.01f) + { + //ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, { 0, ImGui::GetStyle().ItemSpacing.y }); + //IconButton(ICON_FA_ANGLE_UP); + // + //ImGui::SameLine(); + + ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 4.0f); + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ButtonPadding); + + const bool isUsing = ImGui::DragFloat(("##" + name).c_str(), &input, speed, min, max); + + ImGui::PopStyleVar(2); + + //ImGui::PopStyleColor(); + + return isUsing; + } + + bool CheckBox(const std::string& name, bool& value) + { + const float height = ImGui::GetTextLineHeight() + ButtonPadding.y * 2.0; + + if (value) + { + ImGui::PushStyleColor(ImGuiCol_Button, IM_COL32(0, 0, 0, 0)); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, IM_COL32(97, 0, 255, 200)); + ImGui::PushStyleColor(ImGuiCol_ButtonActive, PrimaryCol); + ImGui::PushStyleColor(ImGuiCol_Border, PrimaryCol); + + ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 2.0f); + ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 4.0f); + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ButtonPadding); + + const bool buttonPressed = ImGui::Button(("##" + name).c_str(), ImVec2(height, height)); + + ImGui::PopStyleVar(3); + + ImGui::PopStyleColor(4); + + if (buttonPressed) + { + value = false; + } + } + else + { + ImGui::PushStyleColor(ImGuiCol_Button, PrimaryCol); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, PrimaryCol); + ImGui::PushStyleColor(ImGuiCol_ButtonActive, PrimaryCol); + ImGui::PushStyleColor(ImGuiCol_Border, IM_COL32(97, 0, 255, 200)); + + ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 2.0f); + ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 4.0f); + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ButtonPadding); + + const bool buttonPressed = ImGui::Button(("##" + name).c_str(), ImVec2(height, height)); + + ImGui::PopStyleVar(3); + + ImGui::PopStyleColor(4); + + if (buttonPressed) + { + value = true; + } + } + + return value; + } + } +} \ No newline at end of file