diff --git a/Editor/Editor.cpp b/Editor/Editor.cpp index d425ef17..f4ed8f47 100644 --- a/Editor/Editor.cpp +++ b/Editor/Editor.cpp @@ -1,16 +1,21 @@ #include -#include "src/Core/Maths.h" -#include +#include +#include "src/Core/Input.h" #include +#include +#include + +#include "src/Windows/EditorInterface.h" + + + #include #include #include -#include #include #include "src/Scene/Components/BoxCollider.h" -#include "src/EditorInterface.h" -#include "src/Core/Input.h" + #include #include #include @@ -20,6 +25,7 @@ #include "src/UI/UserInterface.h" #include "src/NewEditor.h" #include +#include "src/Actions/EditorSelection.h" std::string WindowTitle = "Nuake Engine"; @@ -38,13 +44,6 @@ void OpenProject() project->FullPath = projectPath; Nuake::Engine::LoadProject(project); - - // Create new interface named test. - //userInterface = UI::UserInterface::New("test"); - - - // Set current interface running. - //Engine::GetCurrentScene()->AddInterface(userInterface); } std::vector vertices @@ -168,10 +167,10 @@ int main() ditherShader->SetUniform1f("u_Time", Nuake::Engine::GetTime()); ditherShader->SetUniform4f("u_Color", 252.0 / 255.0, 3.0 / 255.0, 65.0 / 255.0, 1.0); - if (editor.m_IsEntitySelected && editor.m_SelectedEntity.HasComponent()) + if (editor.Selection.Type == EditorSelectionType::Entity && editor.Selection.Entity.HasComponent()) { - for (auto& m : editor.m_SelectedEntity.GetComponent().Meshes) - Nuake::Renderer::SubmitMesh(m, editor.m_SelectedEntity.GetComponent().GetGlobalTransform()); + for (auto& m : editor.Selection.Entity.GetComponent().Meshes) + Nuake::Renderer::SubmitMesh(m, editor.Selection.Entity.GetComponent().GetGlobalTransform()); Nuake::Renderer::Flush(ditherShader, true); } @@ -179,10 +178,10 @@ int main() ditherShader->SetUniform1f("u_Time", Nuake::Engine::GetTime() / 10.0f); ditherShader->SetUniform4f("u_Color", 52.f / 255.f, 235.f / 255.f, 88.f / 255.f, 1); auto cubeCollidersView = currentScene->m_Registry.view(); - if (editor.m_IsEntitySelected && editor.m_SelectedEntity.HasComponent()) + if (editor.Selection.Type == EditorSelectionType::Entity && editor.Selection.Entity.HasComponent()) { - auto transformComponent = editor.m_SelectedEntity.GetComponent(); - auto colliderComponent = editor.m_SelectedEntity.GetComponent(); + auto transformComponent = editor.Selection.Entity.GetComponent(); + auto colliderComponent = editor.Selection.Entity.GetComponent(); Nuake::Matrix4 transform = transformComponent.GetGlobalTransform(); transform = glm::scale(transform, colliderComponent.Size); Nuake::Renderer::SubmitCube(transform); @@ -194,9 +193,9 @@ int main() sceneFramebuffer->Unbind(); editor.Draw(); + Nuake::Engine::EndDraw(); } Nuake::Engine::Close(); -} - +} \ No newline at end of file diff --git a/Editor/resource.h b/Editor/resource.h new file mode 100644 index 00000000..be5b9788 --- /dev/null +++ b/Editor/resource.h @@ -0,0 +1,16 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by Editor.rc +// +#define IDI_ICON1 101 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 102 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/Editor/resources/Shaders/combine.shader b/Editor/resources/Shaders/combine.shader new file mode 100644 index 00000000..df932b51 --- /dev/null +++ b/Editor/resources/Shaders/combine.shader @@ -0,0 +1,31 @@ +#shader vertex +#version 460 core + +layout(location = 0) in vec3 VertexPosition; +layout(location = 1) in vec2 UVPosition; + +out flat vec2 UV; + +void main() +{ + UV = UVPosition; + gl_Position = vec4(VertexPosition, 1.0f); +} + +#shader fragment +#version 460 core + +uniform sampler2D u_Source; +uniform sampler2D u_Source2; + +in vec2 UV; + +out vec4 FragColor; + +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); +} \ No newline at end of file diff --git a/Editor/resources/Shaders/deferred.shader b/Editor/resources/Shaders/deferred.shader index abed9efd..b3b823a4 100644 --- a/Editor/resources/Shaders/deferred.shader +++ b/Editor/resources/Shaders/deferred.shader @@ -117,25 +117,51 @@ vec3 fresnelSchlickRoughness(float cosTheta, vec3 F0, float roughness) return F0 + (max(vec3(1.0 - roughness), F0) - F0) * pow(max(1.0 - cosTheta, 0.0), 5.0); } - -float ShadowCalculation(Light light, vec3 FragPos, vec3 normal) +int GetCSMDepth(float depth, Light light) { - // Get Depth - float depth = length(FragPos - u_EyePosition); - int shadowmap = 0; - + int shadowmap = -1; // Get CSM depth for (int i = 0; i < 4; i++) { float CSMDepth = light.CascadeDepth[i]; - - if (depth < CSMDepth + 0.0001) + + if (depth < CSMDepth + 0.0001f) { shadowmap = i; break; } } - + + return shadowmap; +} + +float SampleShadowMap(sampler2D shadowMap, vec2 coords, float compare) +{ + return step(compare, texture(shadowMap, coords.xy).r); +} + +float SampleShadowMapLinear(sampler2D shadowMap, vec2 coords, float compare, vec2 texelSize) +{ + vec2 pixelPos = coords / texelSize + vec2(0.5); + vec2 fracPart = fract(pixelPos); + vec2 startTexel = (pixelPos - fracPart) * texelSize; + + float blTexel = SampleShadowMap(shadowMap, startTexel, compare); + float brTexel = SampleShadowMap(shadowMap, startTexel + vec2(texelSize.x, 0.0), compare); + float tlTexel = SampleShadowMap(shadowMap, startTexel + vec2(0.0, texelSize.y), compare); + float trTexel = SampleShadowMap(shadowMap, startTexel + texelSize, compare); + + float mixA = mix(blTexel, tlTexel, fracPart.y); + float mixB = mix(brTexel, trTexel, fracPart.y); + + return mix(mixA, mixB, fracPart.x); +} + +float ShadowCalculation(Light light, vec3 FragPos, vec3 normal) +{ + // Get Depth + float depth = length(FragPos - u_EyePosition); + int shadowmap = GetCSMDepth(depth, light); if (shadowmap == -1) return 1.0; @@ -149,18 +175,40 @@ float ShadowCalculation(Light light, vec3 FragPos, vec3 normal) // get depth of current fragment from light's perspective float currentDepth = projCoords.z; // check whether current frag pos is in shadow - float bias = max(0.005 * (1.0 - dot(normal, light.Direction)), 0.0005); - float shadow = 0.0; + float bias = max(0.005 * (1.0 - dot(normal, light.Direction)), 0.0005); + //float pcfDepth = texture(ShadowMaps[shadowmap], vec3(projCoords.xy, currentDepth), bias); - float pcfDepth = texture(ShadowMaps[shadowmap], projCoords.xy).r; - return currentDepth - bias > pcfDepth ? 1.0 : 0.0; + if (shadowmap <= 3) + { + const float NUM_SAMPLES = 4.f; + const float SAMPLES_START = (NUM_SAMPLES - 1.0f) / 2.0f; + const float NUM_SAMPLES_SQUARED = NUM_SAMPLES * NUM_SAMPLES; + vec2 texelSize = 1.0 / vec2(2048, 2048); + + float result = 0.0f; + for (float y = -SAMPLES_START; y <= SAMPLES_START; y += 1.0f) + { + for (float x = -SAMPLES_START; x <= SAMPLES_START; x += 1.0f) + { + vec2 coordsOffset = vec2(x, y) * texelSize; + result += SampleShadowMapLinear(ShadowMaps[shadowmap], projCoords.xy + coordsOffset, currentDepth - bias, texelSize); + } + } + + return result / NUM_SAMPLES_SQUARED; + } + + else + { + return SampleShadowMap(ShadowMaps[shadowmap], projCoords.xy, currentDepth - bias); + } + } void main() { vec3 worldPos = WorldPosFromDepth(texture(m_Depth, UV).r); - if (texture(m_Depth, UV).r == 1) { FragColor = vec4(0, 0, 0, 0); @@ -202,7 +250,7 @@ void main() vec3 radiance = Lights[i].Color * attenuation ; if (Lights[i].Type == 0) { - radiance *= 1.0f - shadow; + radiance *= shadow; } // Cook-Torrance BRDF @@ -235,5 +283,18 @@ void main() vec3 ambient = (kD * albedo) * ao; vec3 color = ambient + Lo; + // Display CSM splits.. + /*float depth = length(worldPos - u_EyePosition); + int cascade = GetCSMDepth(depth, Lights[0]); + if (cascade == 0) + color *= vec3(1.0, 0.0, 0.0); + if (cascade == 1) + color *= vec3(0.0, 1.0, 0.0); + if (cascade == 2) + color *= vec3(0.0, 0.0, 1.0); + if (cascade == 3) + color *= vec3(0.0, 1.0, 1.0); + */ + FragColor = vec4(color, 1.0); } \ No newline at end of file diff --git a/Editor/resources/Shaders/dither.shader b/Editor/resources/Shaders/dither.shader index d44edb35..07718726 100644 --- a/Editor/resources/Shaders/dither.shader +++ b/Editor/resources/Shaders/dither.shader @@ -25,7 +25,6 @@ void main() discard; vec4 finalColor = u_Color; - finalColor.a = (sin(u_Time * 4.0) + 1.0) / 4.0 + 0.1; FragColor = finalColor; } \ No newline at end of file diff --git a/Editor/resources/Shaders/gbuffer.shader b/Editor/resources/Shaders/gbuffer.shader index 5475d15e..c08d14cf 100644 --- a/Editor/resources/Shaders/gbuffer.shader +++ b/Editor/resources/Shaders/gbuffer.shader @@ -17,8 +17,15 @@ out vec2 UV; void main() { - vec3 N = normalize((u_Model * vec4(Normal, 0.0f)).xyz); + //mat3 normalMatrix = transpose(inverse(mat3(u_Model))); + //vec3 T = normalize(normalMatrix * Tangent); + //vec3 N = normalize(normalMatrix * Normal); + //T = normalize(T - dot(T, N) * N); + //vec3 B = cross(N, T); + + vec3 T = normalize((u_Model * vec4(Tangent, 0.0f)).xyz); + vec3 N = normalize((u_Model * vec4(Normal, 0.0f)).xyz); vec3 B = normalize((u_Model * vec4(Bitangent, 0.0f)).xyz); TBN = mat3(T, B, N); @@ -68,10 +75,8 @@ void main() if (u_HasNormal == 1) normal = texture(m_Normal, UV).rgb; normal = normal * 2.0 - 1.0; - normal = TBN * normalize(normal); - - gNormal = vec4(normal, 1.0) / 2.0 + 0.5; + gNormal = vec4(normal / 2.0 + 0.5, 1.0); // Albedo gAlbedo = vec4(m_AlbedoColor, 1.0); diff --git a/Editor/resources/Shaders/pbr.shader b/Editor/resources/Shaders/pbr.shader index caad26d2..15f307db 100644 --- a/Editor/resources/Shaders/pbr.shader +++ b/Editor/resources/Shaders/pbr.shader @@ -1,5 +1,6 @@ #shader vertex #version 460 core + layout(location = 0) in vec3 VertexPosition; layout(location = 1) in vec2 UVPosition; layout(location = 2) in vec3 Normal; diff --git a/Editor/resources/Shaders/ssr.shader b/Editor/resources/Shaders/ssr.shader new file mode 100644 index 00000000..12bd89d9 --- /dev/null +++ b/Editor/resources/Shaders/ssr.shader @@ -0,0 +1,189 @@ +#shader vertex +#version 460 core + +layout(location = 0) in vec3 VertexPosition; +layout(location = 1) in vec2 UVPosition; + +out flat vec2 UV; + +void main() +{ + UV = UVPosition; + gl_Position = vec4(VertexPosition, 1.0f); +} + +#shader fragment +#version 420 core + +in vec2 UV; +out vec4 outColor; + +uniform sampler2D textureFrame; +uniform sampler2D textureDepth; +uniform sampler2D textureNorm; +uniform sampler2D textureMetallic; +uniform sampler2D textureAlbedo; + +uniform mat4 proj; +uniform mat4 invProj; +uniform mat4 view; +uniform mat4 invView; + +uniform float rayStep = 0.2f; +uniform int iterationCount = 100; +uniform float distanceBias = 0.05f; +uniform bool enableSSR = true; +uniform int sampleCount = 4; +uniform bool isSamplingEnabled = true; +uniform bool isExponentialStepEnabled = false; +uniform bool isAdaptiveStepEnabled = true; +uniform bool isBinarySearchEnabled = true; +uniform bool debugDraw = false; +uniform float samplingCoefficient = 0.001f; + +vec3 ReflectedVector; +float Metallic; +const float reflectionSpecularFalloffExponent = 3.0; +float random(vec2 uv) { + return fract(sin(dot(uv, vec2(12.9898, 78.233))) * 43758.5453123); //simple random function +} + +vec3 generatePositionFromDepth(vec2 texturePos, float depth) { + vec4 ndc = vec4((texturePos - 0.5) * 2, depth, 1.f); + vec4 inversed = invProj * ndc;// going back from projected + inversed /= inversed.w; + return inversed.xyz; +} + +vec2 generateProjectedPosition(vec3 pos) { + vec4 samplePosition = proj * vec4(pos, 1.f); + samplePosition.xy = (samplePosition.xy / samplePosition.w) * 0.5 + 0.5; + return samplePosition.xy; +} + +vec3 SSR(vec3 position, vec3 reflection) { + vec3 step = rayStep * reflection; + vec3 marchingPosition = position + step; + float delta; + float depthFromScreen; + vec2 screenPosition; + + int i = 0; + for (; i < iterationCount; i++) { + screenPosition = generateProjectedPosition(marchingPosition); + depthFromScreen = abs(generatePositionFromDepth(screenPosition, textureLod(textureDepth, screenPosition, 2).x).z); + delta = abs(marchingPosition.z) - depthFromScreen; + + float depth = textureLod(textureDepth, screenPosition, 2).r; + + if (abs(delta) < distanceBias || depthFromScreen > 1000.0f) { + vec3 color = vec3(1); + if (debugDraw) + color = vec3(0.5 + sign(delta) / 2, 0.3, 0.5 - sign(delta) / 2); + vec2 dCoords = smoothstep(0.2, 0.6, abs(vec2(0.5, 0.5) - screenPosition.xy)); + float screenEdgefactor = clamp(1.0 - (dCoords.x + dCoords.y), 0.0, 1.0); + float ReflectionMultiplier = pow(Metallic, 3.0) * + screenEdgefactor * + -ReflectedVector.z; + + return texture(textureFrame, screenPosition).xyz * color * clamp(ReflectionMultiplier, 0.0, 0.9); + } + if (isBinarySearchEnabled && delta > 0) { + break; + } + if (isAdaptiveStepEnabled) { + float directionSign = sign(abs(marchingPosition.z) - depthFromScreen); + //this is sort of adapting step, should prevent lining reflection by doing sort of iterative converging + //some implementation doing it by binary search, but I found this idea more cheaty and way easier to implement + step = step * (1.0 - rayStep * max(directionSign, 0.0)); + marchingPosition += step * (-directionSign); + } + else { + marchingPosition += step; + } + if (isExponentialStepEnabled) { + step *= 1.05; + } + } + if (isBinarySearchEnabled) { + for (; i < iterationCount; i++) { + + step *= 0.5; + marchingPosition = marchingPosition - step * sign(delta); + + screenPosition = generateProjectedPosition(marchingPosition); + depthFromScreen = abs(generatePositionFromDepth(screenPosition, textureLod(textureDepth, screenPosition, 2).x).z); + delta = abs(marchingPosition.z) - depthFromScreen; + + vec2 dCoords = smoothstep(0.2, 0.6, abs(vec2(0.5, 0.5) - screenPosition.xy)); + float screenEdgefactor = clamp(1.0 - (dCoords.x + dCoords.y), 0.0, 1.0); + float ReflectionMultiplier = pow(Metallic, 3.0) * screenEdgefactor * + -ReflectedVector.z; + + if (abs(delta) < distanceBias) { + return texture(textureFrame, screenPosition).xyz * clamp(ReflectionMultiplier, 0.0, 0.9); + } + } + } + + return vec3(0.0); +} + +vec3 fresnelSchlick(float cosTheta, vec3 F0) +{ + return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0); +} + +void main() { + vec3 position = generatePositionFromDepth(UV, textureLod(textureDepth, UV, 2).x); + vec4 normal = view * vec4(texture(textureNorm, UV).xyz * 2.0 - 1.0, 0.0); + + float metallic = texture(textureMetallic, UV).r; + Metallic = metallic; + vec3 albedo = texture(textureAlbedo, UV).rgb; + vec3 F0 = vec3(0.04); + F0 = mix(F0, albedo, metallic); + vec3 Fresnel = fresnelSchlick(max(dot(normalize(normal.rgb), normalize(position)), 0.0), F0); + + if (!enableSSR || metallic < 0.01) { + discard;// outColor = mix(texture(textureFrame, UV), normal, 0.9); + } + else { + vec3 reflectionDirection = normalize(reflect(position, normalize(normal.xyz))); + + ReflectedVector = reflectionDirection; + if (isSamplingEnabled) { + vec3 firstBasis = normalize(cross(vec3(0.f, 0.f, 1.f), reflectionDirection)); + vec3 secondBasis = normalize(cross(reflectionDirection, firstBasis)); + vec4 resultingColor = vec4(0.f); + for (int i = 0; i < sampleCount; i++) { + vec2 coeffs = vec2(random(UV + vec2(0, i)) + random(UV + vec2(i, 0))) * samplingCoefficient; + vec3 reflectionDirectionRandomized = reflectionDirection + firstBasis * coeffs.x + secondBasis * coeffs.y; + vec3 tempColor = SSR(position, normalize(reflectionDirectionRandomized)); + + if(tempColor != vec3(0)) + resultingColor += vec4(tempColor, 1.0f); + } + + if(resultingColor.w != 0) + resultingColor /= resultingColor.w; + + if (resultingColor.xyz == vec3(0.0f)) + { + outColor = vec4(1, 0, 0, 0); + + return; + } + + + outColor = vec4(resultingColor.xyz * Fresnel, metallic) ; + + } + else { + outColor = vec4(SSR(position, normalize(reflectionDirection)) * Fresnel, metallic); + if (outColor.xyz == vec3(0.f)) { + outColor = texture(textureFrame, UV); + } + } + } +} diff --git a/Editor/resources/Shaders/volumetric.shader b/Editor/resources/Shaders/volumetric.shader index 6d6fde46..53790de8 100644 --- a/Editor/resources/Shaders/volumetric.shader +++ b/Editor/resources/Shaders/volumetric.shader @@ -37,11 +37,12 @@ struct Light { mat4 transform; vec3 color; vec3 direction; - sampler2D shadowmap; + int shadowmap; }; uniform Light u_Lights[MAX_LIGHT]; +uniform sampler2D lightShadowmap; in vec2 UV; out vec4 FragColor; @@ -57,7 +58,8 @@ float ComputeScattering(float lightDotView) vec3 ComputeVolumetric(vec3 FragPos, Light light) { - vec3 rayVector = FragPos - u_CamPosition; // Ray Direction + vec3 startPosition = u_CamPosition; // Camera Position + vec3 rayVector = FragPos - startPosition; // Ray Direction float rayLength = length(rayVector); // Length of the raymarched @@ -68,7 +70,7 @@ vec3 ComputeVolumetric(vec3 FragPos, Light light) vec3 accumFog = vec3(0.0f, 0.0f, 0.0f); // accumulative color // Raymarching - vec3 currentPosition = u_CamPosition; + vec3 currentPosition = startPosition; for (int i = 0; i < u_StepCount; i++) { vec4 fragPosLightSpace = light.transform * vec4(currentPosition, 1.0f); @@ -78,7 +80,7 @@ vec3 ComputeVolumetric(vec3 FragPos, Light light) projCoords = projCoords * 0.5 + 0.5; float currentDepth = projCoords.z; - float closestDepth = texture(light.shadowmap, projCoords.xy).r; + float closestDepth = texture(lightShadowmap, projCoords.xy).r; if (closestDepth > currentDepth) accumFog += (ComputeScattering(dot(rayDirection, normalize(light.direction))).xxx * light.color); @@ -110,11 +112,10 @@ void main() vec3 globalFragmentPosition = WorldPosFromDepth(depth); vec3 fog = vec3(0, 0, 0); - for (int i = 0; i < u_LightCount; i++) { fog += ComputeVolumetric(globalFragmentPosition, u_Lights[i]); } - - FragColor = vec4(mix(fog, vec3(depth), 0.01), 1.0); + + FragColor = vec4(mix(fog, ComputeVolumetric(globalFragmentPosition, u_Lights[0]), 0.9f), 1.0); } \ No newline at end of file diff --git a/Editor/src/Actions/EditorSelection.h b/Editor/src/Actions/EditorSelection.h new file mode 100644 index 00000000..b71e9b7c --- /dev/null +++ b/Editor/src/Actions/EditorSelection.h @@ -0,0 +1,49 @@ +#pragma once +#include "src/Core/Core.h" +#include "src/Scene/Entities/Entity.h" +#include "src/Resource/Resource.h" + +enum EditorSelectionType { + None, + Entity, + File, + Resource, +}; + +class EditorSelection { +public: + + EditorSelectionType Type = EditorSelectionType::None; + + Nuake::Entity Entity; + Ref File; + Nuake::Resource Resource; + + EditorSelection() + { + Type = None; + } + + EditorSelection(const Nuake::Entity& entity) + { + Type = EditorSelectionType::Entity; + Entity = entity; + } + + EditorSelection(const Ref& file) + { + Type = EditorSelectionType::File; + File = file; + } + + EditorSelection(const Nuake::Resource& resource) + { + Type = EditorSelectionType::Resource; + Resource = resource; + } + + operator bool() + { + return Type != None; + } +}; \ No newline at end of file diff --git a/Editor/src/ComponentsPanel/ComponentPanel.h b/Editor/src/ComponentsPanel/ComponentPanel.h new file mode 100644 index 00000000..781c9a4c --- /dev/null +++ b/Editor/src/ComponentsPanel/ComponentPanel.h @@ -0,0 +1,89 @@ +#pragma once +#include "src/Scene/Entities/Entity.h" + +#include "../Misc/InterfaceFonts.h" + +#include +#include + + +#define MenuItemComponent(label, Component) \ + if(entity.HasComponent()) \ + ImGui::Text(label); \ + else if (ImGui::MenuItem(label)) \ + entity.AddComponent(); + + +#define BeginComponentTable(name, component) \ + UIFont* boldFont = new UIFont(Fonts::Bold); \ + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.f, 0.f)); \ + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0.f, 8.f)); \ + bool removed = false; \ + bool headerOpened = ImGui::CollapsingHeader(#name, ImGuiTreeNodeFlags_DefaultOpen); \ + if (#name != "TRANSFORM" && ImGui::BeginPopupContextItem()) \ + { \ + if (ImGui::Selectable("Remove")) { removed = true; } \ + ImGui::EndPopup(); \ + } \ + \ + if(removed) \ + { \ + entity.RemoveComponent(); \ + ImGui::PopStyleVar(); \ + delete boldFont; \ + } \ + else if (headerOpened) \ + { \ + delete boldFont; \ + ImGui::PopStyleVar(); \ + if (ImGui::BeginTable(#name, 3, ImGuiTableFlags_BordersInner)) \ + { \ + ImGui::TableSetupColumn("name", 0, 0.3f); \ + ImGui::TableSetupColumn("set", 0, 0.6f); \ + ImGui::TableSetupColumn("reset", 0, 0.1f); \ + \ + ImGui::TableNextColumn(); + + +#define EndComponentTable() \ + ImGui::EndTable(); \ + } \ + } \ + else \ + { \ + ImGui::PopStyleVar(); \ + delete boldFont; \ + } \ + ImGui::PopStyleVar(); + + +#define ComponentTableReset(setting, value) \ + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1, 1, 1, 0)); \ + std::string resetLabel = std::string(ICON_FA_UNDO) + "##Reset" + #setting; \ + if (ImGui::Button(resetLabel.c_str())) setting = value; \ + ImGui::PopStyleColor(); + + +#define ComponentDropDown(arrayData, enumData, value) \ + const char* current_item = arrayData[(int)value]; \ + if (ImGui::BeginCombo("Type", current_item)) \ + { \ + for (int n = 0; n < IM_ARRAYSIZE(arrayData); n++) \ + { \ + bool is_selected = (current_item == arrayData[n]); \ + if (ImGui::Selectable(arrayData[n], is_selected)) \ + { \ + current_item = arrayData[n]; \ + value = (enumData)n; \ + } \ + if (is_selected) \ + ImGui::SetItemDefaultFocus(); \ + } \ + ImGui::EndCombo(); \ + } + + +class ComponentPanel { +public: + virtual void Draw(Nuake::Entity entity) = 0; +}; \ No newline at end of file diff --git a/Editor/src/ComponentsPanel/LightPanel.h b/Editor/src/ComponentsPanel/LightPanel.h new file mode 100644 index 00000000..27cc1736 --- /dev/null +++ b/Editor/src/ComponentsPanel/LightPanel.h @@ -0,0 +1,106 @@ +#pragma once +#include "ComponentPanel.h" +#include "src/Scene/Components/LightComponent.h" + +class LightPanel :ComponentPanel { + +public: + LightPanel() { } + + void Draw(Nuake::Entity entity) override + { + if (!entity.HasComponent()) + return; + + Nuake::LightComponent& component = entity.GetComponent(); + + BeginComponentTable(LIGHT, Nuake::LightComponent); + { + { + ImGui::Text("Color"); + + ImGui::TableNextColumn(); + ImGui::PushItemWidth(ImGui::GetContentRegionAvailWidth()); + ImGui::ColorEdit3("##lightcolor", &component.Color.r, ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel); + ImGui::PopItemWidth(); + + ImGui::TableNextColumn(); + ComponentTableReset(component.Color, Nuake::Vector3(1, 1, 1)); + } + ImGui::TableNextColumn(); + { + ImGui::Text("Strength"); + + ImGui::TableNextColumn(); + ImGui::SliderFloat("Strength", &component.Strength, 0.0f, 100.0f); + + ImGui::TableNextColumn(); + ComponentTableReset(component.Strength, 10.f); + } + ImGui::TableNextColumn(); + { + ImGui::Text("Cast Shadows"); + ImGui::TableNextColumn(); + + // Using the SetCastShadows allows to create Framebuffers. + bool castShadows = component.CastShadows; + ImGui::Checkbox("##CastShadows", &castShadows); + if (castShadows != component.CastShadows) + component.SetCastShadows(castShadows); + + ImGui::TableNextColumn(); + ComponentTableReset(component.CastShadows, false); + } + ImGui::TableNextColumn(); + { + ImGui::Text("Type"); + ImGui::TableNextColumn(); + + const char* lightTypes[] = { "Directional", "Point", "Spot" }; + ComponentDropDown(lightTypes, Nuake::LightType, component.Type) + + ImGui::TableNextColumn(); + ComponentTableReset(component.Type, Nuake::LightType::Point); + } + ImGui::TableNextColumn(); + if (component.Type == Nuake::LightType::Directional) + { + { + ImGui::Text("Is Volumetric"); + + ImGui::TableNextColumn(); + ImGui::Checkbox("##Volumetric", &component.IsVolumetric); + + ImGui::TableNextColumn(); + ComponentTableReset(component.IsVolumetric, false); + } + ImGui::TableNextColumn(); + { + ImGui::Text("Sync Direction with sky"); + + ImGui::TableNextColumn(); + ImGui::Checkbox("##SyncSky", &component.SyncDirectionWithSky); + + ImGui::TableNextColumn(); + ComponentTableReset(component.SyncDirectionWithSky, false); + + // Light direction is only useful if it is not overriden by the procedural sky direction + if (!component.SyncDirectionWithSky) + { + ImGui::TableNextColumn(); + { + ImGui::Text("Direction"); + + ImGui::TableNextColumn(); + ImGuiHelper::DrawVec3("Direction", &component.Direction); + + ImGui::TableNextColumn(); + ComponentTableReset(component.Direction, Nuake::Vector3(0, -1, 0)); + } + } + } + } + } + EndComponentTable(); + } +}; \ No newline at end of file diff --git a/Editor/src/ComponentsPanel/MeshPanel.h b/Editor/src/ComponentsPanel/MeshPanel.h new file mode 100644 index 00000000..30c8ed81 --- /dev/null +++ b/Editor/src/ComponentsPanel/MeshPanel.h @@ -0,0 +1,43 @@ +#pragma once +#include "ComponentPanel.h" +#include +#include + +class MeshPanel : ComponentPanel { + +public: + MeshPanel() {} + + void Draw(Nuake::Entity entity) override + { + if (!entity.HasComponent()) + return; + + Nuake::MeshComponent& component = entity.GetComponent(); + BeginComponentTable(MESH, Nuake::MeshComponent); + { + ImGui::Text("Mesh"); + ImGui::TableNextColumn(); + + std::string path = component.ModelPath; + ImGui::Button(component.ModelPath.c_str(), ImVec2(ImGui::GetContentRegionAvail().x, 0)); + if (ImGui::BeginDragDropTarget()) + { + if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("_Model")) + { + char* file = (char*)payload->Data; + std::string fullPath = std::string(file, 256); + path = Nuake::FileSystem::AbsoluteToRelative(fullPath); + + component.ModelPath = path; + component.LoadModel(); + } + ImGui::EndDragDropTarget(); + } + + ImGui::TableNextColumn(); + ComponentTableReset(component.ModelPath, ""); + } + EndComponentTable(); + } +}; \ No newline at end of file diff --git a/Editor/src/ComponentsPanel/QuakeMapPanel.h b/Editor/src/ComponentsPanel/QuakeMapPanel.h new file mode 100644 index 00000000..bf9c235d --- /dev/null +++ b/Editor/src/ComponentsPanel/QuakeMapPanel.h @@ -0,0 +1,70 @@ +#pragma once +#include "ComponentPanel.h" +#include +#include "src/Scene/Systems/QuakeMapBuilder.h" +#include + +class QuakeMapPanel : ComponentPanel { + +public: + QuakeMapPanel() {} + + void Draw(Nuake::Entity entity) override + { + if (!entity.HasComponent()) + return; + + Nuake::QuakeMapComponent& component = entity.GetComponent(); + BeginComponentTable(QUAKEMAP, Nuake::QuakeMapComponent); + { + { + ImGui::Text("Map"); + ImGui::TableNextColumn(); + + std::string path = component.Path; + ImGui::Button(component.Path.c_str(), ImVec2(ImGui::GetContentRegionAvail().x, 0)); + if (ImGui::BeginDragDropTarget()) + { + if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("_Map")) + { + char* file = (char*)payload->Data; + std::string fullPath = std::string(file, 256); + path = Nuake::FileSystem::AbsoluteToRelative(fullPath); + + component.Path = path; + } + ImGui::EndDragDropTarget(); + } + + ImGui::TableNextColumn(); + + ComponentTableReset(component.Path, ""); + } + ImGui::TableNextColumn(); + { + ImGui::Text("Collision"); + ImGui::TableNextColumn(); + + ImGui::Checkbox("#Collison", &component.HasCollisions); + ImGui::TableNextColumn(); + ComponentTableReset(component.HasCollisions, true); + } + ImGui::TableNextColumn(); + { + ImGui::Text("Build"); + ImGui::TableNextColumn(); + + if (ImGui::Button("Build")) + { + Nuake::QuakeMapBuilder builder; + builder.BuildQuakeMap(entity, component.HasCollisions); + } + + ImGui::TableNextColumn(); + + //ComponentTableReset(component.Class, ""); + } + } + EndComponentTable(); + } +}; \ No newline at end of file diff --git a/Editor/src/ComponentsPanel/ScriptPanel.h b/Editor/src/ComponentsPanel/ScriptPanel.h new file mode 100644 index 00000000..48511286 --- /dev/null +++ b/Editor/src/ComponentsPanel/ScriptPanel.h @@ -0,0 +1,65 @@ +#pragma once +#include "ComponentPanel.h" +#include +#include + +class ScriptPanel : ComponentPanel { + +public: + ScriptPanel() {} + + void Draw(Nuake::Entity entity) override + { + if (!entity.HasComponent()) + return; + + Nuake::WrenScriptComponent& component = entity.GetComponent(); + BeginComponentTable(SCRIPT, Nuake::WrenScriptComponent); + { + { + ImGui::Text("Script"); + ImGui::TableNextColumn(); + + std::string path = component.Script; + ImGui::Button(component.Script.c_str(), ImVec2(ImGui::GetContentRegionAvail().x, 0)); + if (ImGui::BeginDragDropTarget()) + { + if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("_Script")) + { + char* file = (char*)payload->Data; + std::string fullPath = std::string(file, 256); + path = Nuake::FileSystem::AbsoluteToRelative(fullPath); + + Ref nuakeFile = Nuake::FileSystem::GetFile(path); + component.mWrenScript = CreateRef(nuakeFile, true); + auto& modules = component.mWrenScript->GetModules(); + } + ImGui::EndDragDropTarget(); + } + + component.Script = path; + + + // + //ImGuiHelper::DrawVec3("Translation", &component.Translation); + ImGui::TableNextColumn(); + + ComponentTableReset(component.Script, ""); + } + ImGui::TableNextColumn(); + { + ImGui::Text("Module"); + ImGui::TableNextColumn(); + + // Todo: Automatically parse available modules. and offer a dropdown + //ImGuiHelper::DrawVec3("Rotation", &component.Rotation); + ImGui::TableNextColumn(); + + + + //ComponentTableReset(component.Class, ""); + } + } + EndComponentTable(); + } +}; \ No newline at end of file diff --git a/Editor/src/ComponentsPanel/TransformPanel.h b/Editor/src/ComponentsPanel/TransformPanel.h new file mode 100644 index 00000000..8e36944f --- /dev/null +++ b/Editor/src/ComponentsPanel/TransformPanel.h @@ -0,0 +1,48 @@ +#pragma once +#include "ComponentPanel.h" +#include +#include + +class TransformPanel : ComponentPanel { + +public: + TransformPanel() {} + + void Draw(Nuake::Entity entity) override + { + Nuake::TransformComponent& component = entity.GetComponent(); + BeginComponentTable(TRANSFORM, Nuake::TransformComponent); + { + { + ImGui::Text("Translation"); + ImGui::TableNextColumn(); + + ImGuiHelper::DrawVec3("Translation", &component.Translation); + ImGui::TableNextColumn(); + + ComponentTableReset(component.Translation, Nuake::Vector3(0, 0, 0)); + } + ImGui::TableNextColumn(); + { + ImGui::Text("Rotation"); + ImGui::TableNextColumn(); + + ImGuiHelper::DrawVec3("Rotation", &component.Rotation); + ImGui::TableNextColumn(); + + ComponentTableReset(component.Rotation, Nuake::Vector3(0, 0, 0)); + } + ImGui::TableNextColumn(); + { + ImGui::Text("Scale"); + ImGui::TableNextColumn(); + + ImGuiHelper::DrawVec3("Scale", &component.Scale); + ImGui::TableNextColumn(); + + ComponentTableReset(component.Scale, Nuake::Vector3(1, 1, 1)); + } + } + EndComponentTable(); + } +}; \ No newline at end of file diff --git a/Editor/src/GizmoDrawer.h b/Editor/src/GizmoDrawer.h deleted file mode 100644 index b9bf1a9c..00000000 --- a/Editor/src/GizmoDrawer.h +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once - -class GizmoDrawer -{ - void Draw(); - - -}; \ No newline at end of file diff --git a/Editor/src/ImGuiTextHelper.h b/Editor/src/Misc/ImGuiTextHelper.h similarity index 95% rename from Editor/src/ImGuiTextHelper.h rename to Editor/src/Misc/ImGuiTextHelper.h index 4525cf79..87dde8df 100644 --- a/Editor/src/ImGuiTextHelper.h +++ b/Editor/src/Misc/ImGuiTextHelper.h @@ -1,9 +1,7 @@ #pragma once -#include #include #include - void ImGuiTextSTD(const std::string& label, std::string& value) { char buffer[256]; diff --git a/Editor/src/Misc/InterfaceFonts.cpp b/Editor/src/Misc/InterfaceFonts.cpp new file mode 100644 index 00000000..85699d3d --- /dev/null +++ b/Editor/src/Misc/InterfaceFonts.cpp @@ -0,0 +1,38 @@ +#pragma once +#include "InterfaceFonts.h" +#include +#include + +std::map FontManager::mFonts = std::map(); + +void FontManager::LoadFonts() +{ + ImGuiIO& io = ImGui::GetIO(); (void)io; + static const ImWchar icons_ranges[] = { ICON_MIN_FA, ICON_MAX_FA, 0 }; + ImFontConfig icons_config; icons_config.MergeMode = true; icons_config.PixelSnapH = true; + + mFonts[Normal] = io.Fonts->AddFontFromFileTTF("resources/Fonts/fa-solid-900.ttf", 11.0f, &icons_config, icons_ranges); + mFonts[Bold] = io.Fonts->AddFontFromFileTTF("resources/Fonts/OpenSans-Bold.ttf", 16.0); + mFonts[LargeBold] = io.Fonts->AddFontFromFileTTF("resources/Fonts/OpenSans-Regular.ttf", 32); + mFonts[Title] = io.Fonts->AddFontFromFileTTF("resources/Fonts/OpenSans-Bold.ttf", 50.0); + mFonts[SubTitle] = io.Fonts->AddFontFromFileTTF("resources/Fonts/OpenSans-Regular.ttf", 24.0); + ImGui::GetIO().Fonts->AddFontDefault(); + icons_config.MergeMode = true; + mFonts[BigIcon] = io.Fonts->AddFontFromFileTTF("resources/Fonts/fa-solid-900.ttf", 42.0f, &icons_config, icons_ranges); +} + +ImFont* FontManager::GetFont(Fonts font) +{ + return mFonts[font]; +} + +UIFont::UIFont(Fonts font) +{ + ImGuiFont = FontManager::GetFont(font); + ImGui::PushFont(ImGuiFont); +} + +UIFont::~UIFont() +{ + ImGui::PopFont(); +} diff --git a/Editor/src/Misc/InterfaceFonts.h b/Editor/src/Misc/InterfaceFonts.h new file mode 100644 index 00000000..ae107492 --- /dev/null +++ b/Editor/src/Misc/InterfaceFonts.h @@ -0,0 +1,28 @@ +#pragma once + +#include + +enum Fonts { + Normal, Bold, LargeBold, Icons, BigIcon, Title, SubTitle +}; + +class ImFont; + +// Help class that automatically push and pops itself when +// Reaching end of scope +class UIFont { +private: + ImFont* ImGuiFont; +public: + UIFont(Fonts font); + ~UIFont(); +}; + +class FontManager { +private: + static std::map < Fonts, ImFont*> mFonts; + +public: + static void LoadFonts(); + static ImFont* GetFont(Fonts font); +}; \ No newline at end of file diff --git a/Editor/src/SceneTree.h b/Editor/src/SceneTree.h deleted file mode 100644 index 6f70f09b..00000000 --- a/Editor/src/SceneTree.h +++ /dev/null @@ -1 +0,0 @@ -#pragma once diff --git a/Editor/src/Toolbar.h b/Editor/src/Toolbar.h deleted file mode 100644 index 6f70f09b..00000000 --- a/Editor/src/Toolbar.h +++ /dev/null @@ -1 +0,0 @@ -#pragma once diff --git a/Editor/src/EditorInterface.cpp b/Editor/src/Windows/EditorInterface.cpp similarity index 68% rename from Editor/src/EditorInterface.cpp rename to Editor/src/Windows/EditorInterface.cpp index e28db125..f08e7d5e 100644 --- a/Editor/src/EditorInterface.cpp +++ b/Editor/src/Windows/EditorInterface.cpp @@ -25,11 +25,9 @@ #include "src/Scene/Scene.h" #include "src/Scene/Components/Components.h" #include "src/Scene/Components/BoxCollider.h" -#include "src/Scene/Components/LuaScriptComponent.h" -#include "src/Scene/Components/WrenScriptComponent.h" #include "src/Scene/Systems/QuakeMapBuilder.h" #include "src/Scene/Components/LightComponent.h" -#include "UIComponents/Viewport.h" +#include "../UIComponents/Viewport.h" #include #include #include @@ -37,11 +35,25 @@ #include #include "src/Core/Input.h" +#include "../Actions/EditorSelection.h" +#include "FileSystemUI.h" + +#include "../Misc/InterfaceFonts.h" + +#include "WelcomeWindow.h" +#include "src/Rendering/SceneRenderer.h" + namespace Nuake { Ref userInterface; ImFont* normalFont; ImFont* boldFont; ImFont* EditorInterface::bigIconFont; + + EditorInterface::EditorInterface() + { + filesystem = new FileSystemUI(this); + } + void EditorInterface::Init() { ImGuiWindowFlags window_flags = ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoDocking; @@ -64,8 +76,6 @@ namespace Nuake { std::string name = ICON_FA_GAMEPAD + std::string(" Scene"); if (ImGui::Begin(name.c_str())) { - - ImGui::PopStyleVar(); Overlay(); ImGuizmo::BeginFrame(); @@ -91,10 +101,10 @@ namespace Nuake { glm::value_ptr(glm::identity()), 100.f); } - if (m_IsEntitySelected && !Engine::IsPlayMode) + if (Selection.Type == EditorSelectionType::Entity && !Engine::IsPlayMode) { - TransformComponent& tc = m_SelectedEntity.GetComponent(); - ParentComponent& parent = m_SelectedEntity.GetComponent(); + TransformComponent& tc = Selection.Entity.GetComponent(); + ParentComponent& parent = Selection.Entity.GetComponent(); Matrix4 oldTransform = tc.GetGlobalTransform(); Vector3 oldRotation = tc.Rotation; ImGuizmo::Manipulate( @@ -103,10 +113,11 @@ namespace Nuake { CurrentOperation, CurrentMode, glm::value_ptr(oldTransform), 0, 0 ); + if (ImGuizmo::IsUsing()) if (ImGuizmo::IsUsing()) { Vector3 globalPos = Vector3(); - Entity currentParent = m_SelectedEntity; + Entity currentParent = Selection.Entity; if (parent.HasParent) { Matrix4 inverseParent = glm::inverse(parent.Parent.GetComponent().GlobalTransform); @@ -161,7 +172,7 @@ namespace Nuake { std::string name = nameComponent.Name; ParentComponent& parent = e.GetComponent(); - if (m_SelectedEntity == e) + if (Selection.Type == EditorSelectionType::Entity && Selection.Entity == e) base_flags |= ImGuiTreeNodeFlags_Selected; ImGui::TableNextColumn(); @@ -218,57 +229,57 @@ namespace Nuake { } if (ImGui::IsItemClicked()) - { - m_SelectedEntity = e; - m_IsEntitySelected = true; - } + Selection = EditorSelection(e); - if (m_IsEntitySelected) + if (ImGui::BeginPopupContextItem()) { - if (ImGui::BeginPopupContextItem()) + Selection = EditorSelection(e); + + Entity entity = Selection.Entity; + if (entity.HasComponent()) { - if (m_SelectedEntity.HasComponent()) + // Moves the editor camera to the camera position and direction. + if (ImGui::Selectable("Focus camera")) { - if (ImGui::Selectable("Focus camera")) - { - Engine::GetCurrentScene()->m_EditorCamera->Translation = m_SelectedEntity.GetComponent().Translation; - Engine::GetCurrentScene()->m_EditorCamera->SetDirection(m_SelectedEntity.GetComponent().CameraInstance->GetDirection()); - } - ImGui::Separator(); + Ref editorCam = Engine::GetCurrentScene()->m_EditorCamera; + editorCam->Translation = entity.GetComponent().Translation; + Vector3 camDirection = entity.GetComponent().CameraInstance->GetDirection(); + editorCam->SetDirection(camDirection); } - - if (ImGui::Selectable("Remove")) - { - QueueDeletion = e; - } - - - if (ImGui::Selectable("Move to root")) - { - auto& p = m_SelectedEntity.GetComponent(); - if (p.HasParent) - { - auto& pp = p.Parent.GetComponent(); - pp.RemoveChildren(m_SelectedEntity); - p.HasParent = false; - } - } - if (ImGui::Selectable("Save as new prefab")) - { - Ref newPrefab = Prefab::CreatePrefabFromEntity(m_SelectedEntity); - std::string savePath = FileDialog::SaveFile("*.prefab"); - newPrefab->SaveAs(savePath); - m_SelectedEntity.AddComponent().PrefabInstance = newPrefab; - } - ImGui::EndPopup(); + ImGui::Separator(); } + + if (ImGui::Selectable("Remove")) + { + QueueDeletion = e; + } + + if (entity.GetComponent().HasParent && ImGui::Selectable("Move to root")) + { + auto& parentComp = Selection.Entity.GetComponent(); + if (parentComp.HasParent) + { + auto& parentParentComp = parentComp.Parent.GetComponent(); + parentParentComp.RemoveChildren(entity); + parentComp.HasParent = false; + } + } + + if (ImGui::Selectable("Save entity as a new prefab")) + { + Ref newPrefab = Prefab::CreatePrefabFromEntity(Selection.Entity); + std::string savePath = FileDialog::SaveFile("*.prefab"); + newPrefab->SaveAs(savePath); + Selection.Entity.AddComponent().PrefabInstance = newPrefab; + } + ImGui::EndPopup(); } + if (open) { - // Caching list to prevent deletion while iterating. std::vector childrens = parent.Children; - for (auto c : childrens) + for (auto& c : childrens) DrawEntityTree(c); ImGui::TreePop(); @@ -334,7 +345,6 @@ namespace Nuake { else if (env->CurrentSkyType == SkyType::ProceduralSky) { - { // Sun Intensity ImGui::Text("Sun Intensity"); ImGui::TableNextColumn(); @@ -477,8 +487,6 @@ namespace Nuake { ImGui::EndTable(); } - - if (ImGui::CollapsingHeader("Post processing", ImGuiTreeNodeFlags_DefaultOpen)) { if (ImGui::BeginTable("EnvTable", 3, ImGuiTableFlags_BordersInner)) @@ -593,6 +601,195 @@ namespace Nuake { } } + SSR* ssr = scene->mSceneRenderer->mSSR.get(); + ImGui::TableNextColumn(); + { + // Title + ImGui::Text("SSR RayStep"); + ImGui::TableNextColumn(); + ImGui::DragFloat("##SSRRS", &ssr->RayStep, 0.01f, 0.0f); + ImGui::TableNextColumn(); + + // Reset button + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1, 1, 1, 0)); + std::string resetVolumetric = ICON_FA_UNDO + std::string("##resetVolumetric"); + if (ImGui::Button(resetVolumetric.c_str())) env->VolumetricEnabled = false; + ImGui::PopStyleColor(); + } + + ImGui::TableNextColumn(); + { + // Title + ImGui::Text("iterationCount"); + ImGui::TableNextColumn(); + ImGui::DragInt("##SSRRSi", &ssr->IterationCount, 1, 1); + ImGui::TableNextColumn(); + + // Reset button + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1, 1, 1, 0)); + std::string resetVolumetric = ICON_FA_UNDO + std::string("##resetVolumetric"); + if (ImGui::Button(resetVolumetric.c_str())) env->VolumetricEnabled = false; + ImGui::PopStyleColor(); + } + + ImGui::TableNextColumn(); + { + // Title + ImGui::Text("distanceBias"); + ImGui::TableNextColumn(); + ImGui::DragFloat("##SSRRSid", &ssr->DistanceBias, 0.01f, 0.f); + ImGui::TableNextColumn(); + + // Reset button + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1, 1, 1, 0)); + std::string resetVolumetric = ICON_FA_UNDO + std::string("##resetVolumetric"); + if (ImGui::Button(resetVolumetric.c_str())) env->VolumetricEnabled = false; + ImGui::PopStyleColor(); + } + + ImGui::TableNextColumn(); + { + // Title + ImGui::Text("sampleCount"); + ImGui::TableNextColumn(); + ImGui::DragInt("##SSRRSids", &ssr->SampleCount, 1, 0); + ImGui::TableNextColumn(); + + // Reset button + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1, 1, 1, 0)); + std::string resetVolumetric = ICON_FA_UNDO + std::string("##resetVolumetric"); + if (ImGui::Button(resetVolumetric.c_str())) env->VolumetricEnabled = false; + ImGui::PopStyleColor(); + } + + ImGui::TableNextColumn(); + { + // Title + ImGui::Text("Sampling Enabled"); + ImGui::TableNextColumn(); + ImGui::Checkbox("##SSRRSidss", &ssr->SamplingEnabled); + ImGui::TableNextColumn(); + + // Reset button + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1, 1, 1, 0)); + std::string resetVolumetric = ICON_FA_UNDO + std::string("##resetVolumetric"); + if (ImGui::Button(resetVolumetric.c_str())) env->VolumetricEnabled = false; + ImGui::PopStyleColor(); + } + + + ImGui::TableNextColumn(); + { + // Title + ImGui::Text("Expo"); + ImGui::TableNextColumn(); + ImGui::Checkbox("##SSRRSidsse", &ssr->ExpoStep); + ImGui::TableNextColumn(); + + // Reset button + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1, 1, 1, 0)); + std::string resetVolumetric = ICON_FA_UNDO + std::string("##resetVolumetric"); + if (ImGui::Button(resetVolumetric.c_str())) env->VolumetricEnabled = false; + ImGui::PopStyleColor(); + } + + ImGui::TableNextColumn(); + { + // Title + ImGui::Text("Adaptive Steps"); + ImGui::TableNextColumn(); + ImGui::Checkbox("##SSRRSidssse", &ssr->AdaptiveStep); + ImGui::TableNextColumn(); + + // Reset button + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1, 1, 1, 0)); + std::string resetVolumetric = ICON_FA_UNDO + std::string("##resetVolumetric"); + if (ImGui::Button(resetVolumetric.c_str())) env->VolumetricEnabled = false; + ImGui::PopStyleColor(); + } + + ImGui::TableNextColumn(); + { + // Title + ImGui::Text("Binary Searcg"); + ImGui::TableNextColumn(); + ImGui::Checkbox("##SSRRSidsssbe", &ssr->BinarySearch); + ImGui::TableNextColumn(); + + // Reset button + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1, 1, 1, 0)); + std::string resetVolumetric = ICON_FA_UNDO + std::string("##resetVolumetric"); + if (ImGui::Button(resetVolumetric.c_str())) env->VolumetricEnabled = false; + ImGui::PopStyleColor(); + } + + + ImGui::TableNextColumn(); + { + // Title + ImGui::Text("Debug"); + ImGui::TableNextColumn(); + ImGui::Checkbox("##SSRRSidsssbed", &ssr->DebugDraw); + ImGui::TableNextColumn(); + + // Reset button + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1, 1, 1, 0)); + std::string resetVolumetric = ICON_FA_UNDO + std::string("##resetVolumetric"); + if (ImGui::Button(resetVolumetric.c_str())) env->VolumetricEnabled = false; + ImGui::PopStyleColor(); + } + + + ImGui::TableNextColumn(); + { + // Title + ImGui::Text("samplingCoefficient"); + ImGui::TableNextColumn(); + ImGui::DragFloat("##samplingCoefficient", &ssr->SampleingCoefficient, 0.001f, 0.0f); + ImGui::TableNextColumn(); + + // Reset button + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1, 1, 1, 0)); + std::string resetVolumetric = ICON_FA_UNDO + std::string("##resetVolumetric"); + if (ImGui::Button(resetVolumetric.c_str())) env->VolumetricEnabled = false; + ImGui::PopStyleColor(); + } + + if (env->VolumetricEnabled) + { + ImGui::TableNextColumn(); + { + // Title + ImGui::Text("Volumetric Scattering"); + ImGui::TableNextColumn(); + + ImGui::DragFloat("##Volumetric Scattering", &env->VolumetricFog, .01f, 0.0f, 1.0f); + ImGui::TableNextColumn(); + + // Reset button + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1, 1, 1, 0)); + std::string resetBloomThreshold = ICON_FA_UNDO + std::string("##resetBloomThreshold"); + if (ImGui::Button(resetBloomThreshold.c_str())) env->mBloom->SetThreshold(2.4f); + ImGui::PopStyleColor(); + } + + ImGui::TableNextColumn(); + { + // Title + ImGui::Text("Step count"); + ImGui::TableNextColumn(); + + ImGui::DragFloat("##Volumetric Step Count", &env->VolumetricStepCount, 1.f, 0.0f); + ImGui::TableNextColumn(); + + // Reset button + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1, 1, 1, 0)); + std::string resetQuality = ICON_FA_UNDO + std::string("##resetQuality"); + if (ImGui::Button(resetQuality.c_str())) env->VolumetricStepCount = 50.f; + ImGui::PopStyleColor(); + } + } + } ImGui::EndTable(); @@ -610,7 +807,7 @@ namespace Nuake { if (ImGui::Begin(title.c_str())) { // Buttons to add and remove entity. - if(ImGui::BeginChild("Buttons", ImVec2(300, 30), false)) + if(ImGui::BeginChild("Buttons", ImVec2(ImGui::GetContentRegionAvailWidth(), 30), false)) { // Add entity. if (ImGui::Button(ICON_FA_PLUS)) @@ -646,7 +843,7 @@ namespace Nuake { ImGuiTreeNodeFlags base_flags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_SpanAvailWidth; std::string name = e.GetComponent().Name; // If selected add selected flag. - if (m_SelectedEntity == e) + if (Selection.Type == EditorSelectionType::Entity && Selection.Entity == e) base_flags |= ImGuiTreeNodeFlags_Selected; // Write in normal font. @@ -696,8 +893,8 @@ namespace Nuake { { Engine::GetCurrentScene()->DestroyEntity(QueueDeletion); - if (m_SelectedEntity == QueueDeletion) - m_IsEntitySelected = false; + // Clear Selection + Selection = EditorSelection(); QueueDeletion = Entity{ (entt::entity)-1, scene.get() }; } @@ -709,596 +906,15 @@ namespace Nuake { void EditorInterface::DrawEntityPropreties() { - if (ImGui::Begin("Propreties")) - { - if (!m_IsEntitySelected) - { - std::string text = "No entity selected"; - auto windowWidth = ImGui::GetWindowSize().x; - auto windowHeight = ImGui::GetWindowSize().y; - - auto textWidth = ImGui::CalcTextSize(text.c_str()).x; - auto textHeight = ImGui::CalcTextSize(text.c_str()).y; - ImGui::SetCursorPosX((windowWidth - textWidth) * 0.5f); - ImGui::SetCursorPosY((windowHeight - textHeight) * 0.5f); - - ImGui::PushFont(boldFont); - ImGui::Text(text.c_str()); - ImGui::PopFont(); - ImGui::End(); - return; - } - - if (m_SelectedEntity.HasComponent()) { - auto& name = m_SelectedEntity.GetComponent().Name; - - char buffer[256]; - memset(buffer, 0, sizeof(buffer)); - std::strncpy(buffer, name.c_str(), sizeof(buffer)); - ImGui::Text("Name: "); - ImGui::SameLine(); - if (ImGui::InputText("##Name", buffer, sizeof(buffer))) - { - name = std::string(buffer); - } - ImGui::SameLine(); - if (ImGui::Button("Add component")) - { - ImGui::OpenPopup("add_component_popup"); - - } - if (ImGui::BeginPopup("add_component_popup")) - { - if (ImGui::MenuItem("Wren Script") && !m_SelectedEntity.HasComponent()) - m_SelectedEntity.AddComponent(); - ImGui::Separator(); - if (ImGui::MenuItem("Camera Component") && !m_SelectedEntity.HasComponent()) - m_SelectedEntity.AddComponent(); - ImGui::Separator(); - if (ImGui::MenuItem("Light Component") && !m_SelectedEntity.HasComponent()) - m_SelectedEntity.AddComponent(); - ImGui::Separator(); - if (ImGui::MenuItem("Mesh Component") && !m_SelectedEntity.HasComponent()) - m_SelectedEntity.AddComponent(); - if (ImGui::MenuItem("Quake map Component") && !m_SelectedEntity.HasComponent()) - m_SelectedEntity.AddComponent(); - ImGui::Separator(); - if (ImGui::MenuItem("Character controller") && !m_SelectedEntity.HasComponent()) - m_SelectedEntity.AddComponent(); - if (ImGui::MenuItem("Rigidbody Component") && !m_SelectedEntity.HasComponent()) - { - m_SelectedEntity.AddComponent(); - auto transformComponent = m_SelectedEntity.GetComponent(); - } - if (ImGui::MenuItem("Box collider Component") && !m_SelectedEntity.HasComponent()) - { - m_SelectedEntity.AddComponent(); - } - if (ImGui::MenuItem("Sphere collider Component") && !m_SelectedEntity.HasComponent()) - { - m_SelectedEntity.AddComponent(); - } - if (ImGui::MenuItem("Mesh collider Component") && !m_SelectedEntity.HasComponent()) - { - m_SelectedEntity.AddComponent(); - } - ImGui::Separator(); - if (ImGui::MenuItem("Interface Component") && !m_SelectedEntity.HasComponent()) - { - m_SelectedEntity.AddComponent< InterfaceComponent>(); - } - - // your popup code - ImGui::EndPopup(); - } - ImGui::Separator(); - } - - - std::string iconTransform = ICON_FA_MAP_MARKER; - - ImGui::PushFont(boldFont); - ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0)); - ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 8)); - bool headerOpened = ImGui::CollapsingHeader(" TRANSFORM", ImGuiTreeNodeFlags_DefaultOpen); - if (headerOpened) - { - ImGui::PopFont(); - ImGui::PopStyleVar(); - if (ImGui::BeginTable("TransformTable", 3, ImGuiTableFlags_BordersInner)) - { - TransformComponent& component = m_SelectedEntity.GetComponent(); - - ImGui::TableSetupColumn("name", 0, 0.3); - ImGui::TableSetupColumn("set", 0, 0.6); - ImGui::TableSetupColumn("reset", 0, 0.1); - - ImGui::TableNextColumn(); - ImGui::Text("Translation"); - ImGui::TableNextColumn(); - ImGuiHelper::DrawVec3("Translation", &component.Translation); - ImGui::TableNextColumn(); - - ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1, 1, 1, 0)); - std::string resetTranslation = ICON_FA_UNDO + std::string("##ResetTranslation"); - if (ImGui::Button(resetTranslation.c_str())) component.Translation = Vector3(0, 0, 0); - ImGui::PopStyleColor(); - - ImGui::TableNextColumn(); - ImGui::Text("Rotation"); - - ImGui::TableNextColumn(); - ImGuiHelper::DrawVec3("Rotation", &component.Rotation); - - ImGui::TableNextColumn(); - ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1, 1, 1, 0)); - std::string resetRotation = ICON_FA_UNDO + std::string("##ResetRotation"); - if (ImGui::Button(resetRotation.c_str())) component.Rotation = Vector3(0, 0, 0); - ImGui::PopStyleColor(); - - ImGui::TableNextColumn(); - ImGui::Text("Scale"); - - ImGui::TableNextColumn(); - ImGuiHelper::DrawVec3("Scale", &component.Scale); - - ImGui::TableNextColumn(); - std::string resetScale = ICON_FA_UNDO + std::string("##ResetScale"); - ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1, 1, 1, 0)); - if (ImGui::Button(resetScale.c_str())) component.Scale = Vector3(1, 1, 1); - ImGui::PopStyleColor(); - - ImGui::EndTable(); - } - //ImGui::InputText("Name:", selectedEntity->m_Name.data(), 12); - - } - else - { - ImGui::PopStyleVar(); - ImGui::PopFont(); - } - - ImGui::PopStyleVar(); - - if (m_SelectedEntity.HasComponent()) - { - ImGui::PushFont(boldFont); - ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0)); - ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 8)); - - headerOpened = ImGui::CollapsingHeader("Interface", ImGuiTreeNodeFlags_DefaultOpen); - if (headerOpened) - { - ImGui::PopFont(); - ImGui::PopStyleVar(); - InterfaceComponent& component = m_SelectedEntity.GetComponent(); - std::string& path = component.Path; - char pathBuffer[256]; - memset(pathBuffer, 0, sizeof(pathBuffer)); - std::strncpy(pathBuffer, path.c_str(), sizeof(pathBuffer)); - - ImGui::Text("Interface: "); - ImGui::SameLine(); - - if (ImGui::InputText("##InterfacePath", pathBuffer, sizeof(pathBuffer))) - path = FileSystem::AbsoluteToRelative(std::string(pathBuffer)); - - if (ImGui::BeginDragDropTarget()) - { - if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("_Interface")) - { - char* file = (char*)payload->Data; - std::string fullPath = std::string(file, 256); - path = FileSystem::AbsoluteToRelative(fullPath); - component.SetInterface(path); - } - ImGui::EndDragDropTarget(); - } - } - else - { - ImGui::PopStyleVar(); - ImGui::PopFont(); - } - - ImGui::PopStyleVar(); - } - - if (m_SelectedEntity.HasComponent()) - { - std::string icon = ICON_FA_MALE; - if (ImGui::CollapsingHeader((icon + " " + "Mesh").c_str(), ImGuiTreeNodeFlags_DefaultOpen)) - { - ImGui::TextColored(ImGui::GetStyleColorVec4(1), "Mesh properties"); - auto& component = m_SelectedEntity.GetComponent(); - // Path - std::string path = component.ModelPath; - char pathBuffer[256]; - - memset(pathBuffer, 0, sizeof(pathBuffer)); - std::strncpy(pathBuffer, path.c_str(), sizeof(pathBuffer)); - - std::string oldPath = component.ModelPath; - ImGui::Text("Model: "); - ImGui::SameLine(); - if (ImGui::InputText("##ModelPath", pathBuffer, sizeof(pathBuffer))) - path = FileSystem::AbsoluteToRelative(std::string(pathBuffer)); - if (ImGui::BeginDragDropTarget()) - { - if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("_Model")) - { - char* file = (char*)payload->Data; - std::string fullPath = std::string(file, 256); - path = FileSystem::AbsoluteToRelative(fullPath); - } - ImGui::EndDragDropTarget(); - } - - if (component.ModelPath != path) - { - component.ModelPath = path; - component.LoadModel(); - } - - ImGui::SameLine(); - - if (ImGui::Button("Reimport")) - { - component.LoadModel(); - } - - ImGui::Indent(16.0f); - if (ImGui::CollapsingHeader("Meshes")) - { - ImGui::Indent(16.0f); - uint16_t index = 0; - for (auto& m : component.meshes) - { - if (ImGui::CollapsingHeader(std::to_string(index).c_str())) - { - std::string materialName = "No material"; - if (m->m_Material) - materialName = m->m_Material->GetName(); - - ImGui::Indent(16.0f); - if (ImGui::CollapsingHeader(materialName.c_str())) - { - //if (ImGui::BeginChild("Material child", ImVec2(0, 0), true, ImGuiWindowFlags_AlwaysAutoResize)) - //{ - ImGui::Indent(16.0f); - DrawMaterialEditor(m->m_Material); - //} - //ImGui::EndChild(); - } - - if (ImGui::BeginDragDropTarget()) - { - if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("_Material")) - { - char* file = (char*)payload->Data; - std::string fullPath = std::string(file, 256); - path = FileSystem::AbsoluteToRelative(fullPath); - } - ImGui::EndDragDropTarget(); - } - } - - index++; - } - - } - - ImGui::Separator(); - } - - } - - if (m_SelectedEntity.HasComponent()) - { - ImGui::PushFont(boldFont); - ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0)); - ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 8)); - - bool headerOpened = ImGui::CollapsingHeader(" LIGHT", ImGuiTreeNodeFlags_DefaultOpen); - if (headerOpened) - { - ImGui::PopFont(); - ImGui::PopStyleVar(); - if (ImGui::BeginTable("TransformTable", 3, ImGuiTableFlags_BordersInner)) - { - LightComponent& component = m_SelectedEntity.GetComponent(); - - ImGui::TableSetupColumn("name", 0, 0.3); - ImGui::TableSetupColumn("set", 0, 0.6); - ImGui::TableSetupColumn("reset", 0, 0.1); - - ImGui::TableNextColumn(); - ImGui::Text("Color"); - ImGui::TableNextColumn(); - ImGui::PushItemWidth(ImGui::GetContentRegionAvailWidth()); - ImGui::ColorEdit3("##lightcolor", &component.Color.r, ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel); - ImGui::PopItemWidth(); - ImGui::TableNextColumn(); - - ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1, 1, 1, 0)); - std::string resetColor = ICON_FA_UNDO + std::string("##ResetTranslation"); - if (ImGui::Button(resetColor.c_str())) component.Color = Vector3(1, 1, 1); - ImGui::PopStyleColor(); - - ImGui::TableNextColumn(); - ImGui::Text("Strength"); - - ImGui::TableNextColumn(); - ImGui::SliderFloat("Strength", &component.Strength, 0.0f, 100.0f); - - ImGui::TableNextColumn(); - ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1, 1, 1, 0)); - std::string resetStrength = ICON_FA_UNDO + std::string("##resetStrength"); - if (ImGui::Button(resetStrength.c_str())) component.Strength = 10.0f; - ImGui::PopStyleColor(); - - ImGui::TableNextColumn(); - ImGui::Text("Cast Shadows"); - - ImGui::TableNextColumn(); - - // This will create framebuffers and textures. - bool castShadows = component.CastShadows; - ImGui::Checkbox("##CastShadows", &component.CastShadows); - if (castShadows != component.CastShadows) - component.SetCastShadows(castShadows); - - - ImGui::TableNextColumn(); - std::string resetShadow = ICON_FA_UNDO + std::string("##resetShadow"); - ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1, 1, 1, 0)); - if (ImGui::Button(resetShadow.c_str())) component.CastShadows = false; - ImGui::PopStyleColor(); - - ImGui::TableNextColumn(); - ImGui::Text("Type"); - ImGui::TableNextColumn(); - const char* types[] = { "Directional", "Point", "Spot" }; - static const char* current_item = types[component.Type]; - - if (ImGui::BeginCombo("Type", current_item)) // The second parameter is the label previewed before opening the combo. - { - for (int n = 0; n < IM_ARRAYSIZE(types); n++) - { - bool is_selected = (current_item == types[n]); // You can store your selection however you want, outside or inside your objects - if (ImGui::Selectable(types[n], is_selected)) - { - current_item = types[n]; - component.Type = (LightType)n; - } - if (is_selected) - ImGui::SetItemDefaultFocus(); // You may set the initial focus when opening the combo (scrolling + for keyboard navigation support) - } - ImGui::EndCombo(); - } - - ImGui::TableNextColumn(); - std::string resetType = ICON_FA_UNDO + std::string("##resetType"); - ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1, 1, 1, 0)); - if (ImGui::Button(resetShadow.c_str())) component.Type = Point; - ImGui::PopStyleColor(); - - - if (component.Type == Directional) - { - ImGui::TableNextColumn(); - ImGui::Text("Is Volumetric"); - - ImGui::TableNextColumn(); - ImGui::Checkbox("##Volumetric", &component.IsVolumetric); - - ImGui::TableNextColumn(); - std::string resetIsVolumetric = ICON_FA_UNDO + std::string("##IsVolumetric"); - ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1, 1, 1, 0)); - if (ImGui::Button(resetIsVolumetric.c_str())) component.IsVolumetric = false; - ImGui::PopStyleColor(); - - ImGui::TableNextColumn(); - ImGui::Text("Sync Sky Direction"); - - ImGui::TableNextColumn(); - ImGui::Checkbox("##SyncSky", &component.SyncDirectionWithSky); - - ImGui::TableNextColumn(); - std::string resetSyncDirectionWithSky = ICON_FA_UNDO + std::string("##resetSyncDirectionWithSky"); - ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1, 1, 1, 0)); - if (ImGui::Button(resetSyncDirectionWithSky.c_str())) component.SyncDirectionWithSky = false; - ImGui::PopStyleColor(); - - ImGui::TableNextColumn(); - ImGui::Text("Direction"); - ImGui::TableNextColumn(); - ImGuiHelper::DrawVec3("Direction", &component.Direction); - ImGui::TableNextColumn(); - - ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1, 1, 1, 0)); - std::string resetDirection = ICON_FA_UNDO + std::string("##resetDirection"); - if (ImGui::Button(resetDirection.c_str())) component.Direction = Vector3(0, -1, 0); - ImGui::PopStyleColor(); - } - ImGui::EndTable(); - } - } - else - { - ImGui::PopStyleVar(); - ImGui::PopFont(); - } - ImGui::PopStyleVar(); - } - - if (m_SelectedEntity.HasComponent()) { - std::string icon = ICON_FA_FILE; - if (ImGui::CollapsingHeader((icon + " " + "Wren Script").c_str(), ImGuiTreeNodeFlags_DefaultOpen)) - { - ImGui::TextColored(ImGui::GetStyleColorVec4(1), "Script properties"); - auto& component = m_SelectedEntity.GetComponent(); - - // Path - std::string path = component.Script; - char pathBuffer[256]; - - memset(pathBuffer, 0, sizeof(pathBuffer)); - std::strncpy(pathBuffer, path.c_str(), sizeof(pathBuffer)); - - ImGui::Text("Script: "); - ImGui::SameLine(); - if (ImGui::InputText("##ScriptPath", pathBuffer, sizeof(pathBuffer))) - path = FileSystem::AbsoluteToRelative(std::string(pathBuffer)); - if (ImGui::BeginDragDropTarget()) - { - if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("_Script")) - { - char* file = (char*)payload->Data; - std::string fullPath = std::string(file, 256); - path = FileSystem::AbsoluteToRelative(fullPath); - } - ImGui::EndDragDropTarget(); - } - - - component.Script = path; - - // Class - std::string module = component.Class; - - char classBuffer[256]; - - memset(classBuffer, 0, sizeof(classBuffer)); - std::strncpy(classBuffer, module.c_str(), sizeof(classBuffer)); - - ImGui::Text("Class: "); - ImGui::SameLine(); - if (ImGui::InputText("##ScriptModule", classBuffer, sizeof(classBuffer))) - module = std::string(classBuffer); - - component.Class = module; - ImGui::Separator(); - } - } - - if (m_SelectedEntity.HasComponent()) { - - std::string icon = ICON_FA_LIGHTBULB; - if (ImGui::CollapsingHeader((icon + " " + "Camera").c_str(), ImGuiTreeNodeFlags_DefaultOpen)) - { - ImGui::TextColored(ImGui::GetStyleColorVec4(1), "Camera properties"); - m_SelectedEntity.GetComponent().DrawEditor(); - ImGui::Separator(); - } - - } - - if (m_SelectedEntity.HasComponent()) - { - if (ImGui::CollapsingHeader("Character controller", ImGuiTreeNodeFlags_DefaultOpen)) - { - ImGui::TextColored(ImGui::GetStyleColorVec4(1), "Character controller properties"); - auto& c = m_SelectedEntity.GetComponent(); - ImGui::InputFloat("Height", &c.Height); - ImGui::InputFloat("Radius", &c.Radius); - ImGui::InputFloat("Mass", &c.Mass); - ImGui::Separator(); - } - } - if (m_SelectedEntity.HasComponent()) - { - std::string icon = ICON_FA_BOWLING_BALL; - if (ImGui::CollapsingHeader((icon + " Rigidbody").c_str(), ImGuiTreeNodeFlags_DefaultOpen)) - { - ImGui::TextColored(ImGui::GetStyleColorVec4(1), "Rigidbody properties"); - RigidBodyComponent& rbComponent = m_SelectedEntity.GetComponent(); - ImGui::DragFloat("Mass", &rbComponent.mass, 0.1, 0.0); - ImGui::Separator(); - } - } - if (m_SelectedEntity.HasComponent()) - { - std::string icon = ICON_FA_BOX; - if (ImGui::CollapsingHeader((icon + " Box collider").c_str(), ImGuiTreeNodeFlags_DefaultOpen)) - { - ImGui::TextColored(ImGui::GetStyleColorVec4(1), "Box collider properties"); - BoxColliderComponent& component = m_SelectedEntity.GetComponent(); - ImGuiHelper::DrawVec3("Size", &component.Size); - ImGui::Checkbox("Is trigger", &component.IsTrigger); - - ImGui::Separator(); - } - } - if (m_SelectedEntity.HasComponent()) - { - std::string icon = ICON_FA_CIRCLE; - if (ImGui::CollapsingHeader((icon + " Sphere collider").c_str(), ImGuiTreeNodeFlags_DefaultOpen)) - { - ImGui::TextColored(ImGui::GetStyleColorVec4(1), "Sphere properties"); - SphereColliderComponent& component = m_SelectedEntity.GetComponent(); - ImGui::DragFloat("Radius", &component.Radius, 0.1f, 0.0f, 100.0f); - ImGui::Checkbox("Is trigger", &component.IsTrigger); - - ImGui::Separator(); - } - } - if (m_SelectedEntity.HasComponent()) - { - - std::string icon = ICON_FA_BROOM; - if (ImGui::CollapsingHeader((icon + " " + "Quake map").c_str(), ImGuiTreeNodeFlags_DefaultOpen)) - { - ImGui::TextColored(ImGui::GetStyleColorVec4(1), "Quake map properties"); - auto& component = m_SelectedEntity.GetComponent(); - std::string path = component.Path; - - - char pathBuffer[256]; - memset(pathBuffer, 0, sizeof(pathBuffer)); - std::strncpy(pathBuffer, path.c_str(), sizeof(pathBuffer)); - ImGui::Text("Map file: "); - ImGui::SameLine(); - if (ImGui::InputText("##MapPath", pathBuffer, sizeof(pathBuffer))) - { - path = std::string(pathBuffer); - } - - if (ImGui::BeginDragDropTarget()) - { - if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("_Map")) - { - char* file = (char*)payload->Data; - std::string fullPath = std::string(file, 256); - path = FileSystem::AbsoluteToRelative(fullPath); - } - ImGui::EndDragDropTarget(); - } - - component.Path = path; - - ImGui::InputFloat("Scale factor", &component.ScaleFactor, 0.01f, 0.1f); - - ImGui::Checkbox("Build collisions", &component.HasCollisions); - if (ImGui::Button("Build Geometry")) - { - QuakeMapBuilder mapBuilder; - mapBuilder.BuildQuakeMap(m_SelectedEntity); - } - ImGui::Separator(); - } - } - - } - ImGui::End(); + SelectionPanel.Draw(Selection); + } void EditorInterface::DrawGizmos() { Ref scene = Engine::GetCurrentScene(); - if (!m_IsEntitySelected) + if (!Selection.Type == EditorSelectionType::Entity) return; } @@ -1372,23 +988,23 @@ namespace Nuake { void EditorInterface::DrawFile(Ref file) { ImGui::PushFont(bigIconFont); - if (file->Type == ".png" || file->Type == ".jpg") + + std::string fileExtenstion = file->GetExtension(); + if (fileExtenstion == ".png" || fileExtenstion == ".jpg") { - Ref texture = TextureManager::Get()->GetTexture(file->fullPath); + Ref texture = TextureManager::Get()->GetTexture(file->GetAbsolutePath()); ImGui::ImageButton((void*)texture->GetID(), ImVec2(100, 100), ImVec2(0, 1), ImVec2(1, 0)); } else { const char* icon = ICON_FA_FILE; - if (file->Type == ".shader") + if (fileExtenstion == ".shader" || fileExtenstion == ".wren") icon = ICON_FA_FILE_CODE; - else if (file->Type == ".map") + else if (fileExtenstion == ".map") icon = ICON_FA_BROOM; - else if (file->Type == ".ogg" || file->Type == ".mp3" || file->Type == ".wav" || file->Type == ".flac") + else if (fileExtenstion == ".ogg" || fileExtenstion == ".mp3" || fileExtenstion == ".wav") icon = ICON_FA_FILE_AUDIO; - else if (file->Type == ".cpp" || file->Type == ".h" || file->Type == ".cs" || file->Type == ".py" || file->Type == ".lua") - icon = ICON_FA_FILE_CODE; if (ImGui::Button(icon, ImVec2(100, 100))) { @@ -1400,7 +1016,7 @@ namespace Nuake { } } } - ImGui::Text(file->name.c_str()); + ImGui::Text(file->GetName().c_str()); ImGui::PopFont(); } @@ -1884,12 +1500,17 @@ namespace Nuake { } - json SceneSnapshot; + + Ref SceneSnapshot; + WelcomeWindow window = WelcomeWindow(); void EditorInterface::Draw() { Init(); auto flags = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize; + + + if (ImGui::BeginPopupModal("Welcome", NULL, flags)) { ImGui::Text("Welcome to Nuake Engine"); @@ -1903,7 +1524,7 @@ namespace Nuake { if (ImGui::Button("Open Project")) { OpenProject(); - filesystem.m_CurrentDirectory = FileSystem::RootDirectory; + filesystem->m_CurrentDirectory = FileSystem::RootDirectory; } @@ -1924,27 +1545,27 @@ namespace Nuake { { NewProject(); - m_IsEntitySelected = false; + Selection = EditorSelection(); } if (ImGui::MenuItem("Open...", "CTRL+O")) { OpenProject(); - m_IsEntitySelected = false; + Selection = EditorSelection(); } if (ImGui::MenuItem("Save", "CTRL+S")) { Engine::GetProject()->Save(); Engine::GetCurrentScene()->Save(); - m_IsEntitySelected = false; + Selection = EditorSelection(); } if (ImGui::MenuItem("Save as...", "CTRL+SHIFT+S")) { std::string savePath = FileDialog::SaveFile("*.project"); Engine::GetProject()->SaveAs(savePath); - m_IsEntitySelected = false; + Selection = EditorSelection(); } ImGui::Separator(); if (ImGui::MenuItem("Set current scene as default")) @@ -1955,24 +1576,24 @@ namespace Nuake { if (ImGui::MenuItem("New scene")) { Engine::LoadScene(Scene::New()); - m_IsEntitySelected = false; + Selection = EditorSelection(); } if (ImGui::MenuItem("Open scene...", "CTRL+SHIFT+O")) { OpenScene(); - m_IsEntitySelected = false; + Selection = EditorSelection(); } if (ImGui::MenuItem("Save scene", "CTR+SHIFT+L+S")) { Engine::GetCurrentScene()->Save(); - m_IsEntitySelected = false; + Selection = EditorSelection(); } if (ImGui::MenuItem("Save scene as...", "CTRL+SHIFT+S")) { std::string savePath = FileDialog::SaveFile("*.scene"); Engine::GetCurrentScene()->SaveAs(savePath); - m_IsEntitySelected = false; + Selection = EditorSelection(); } ImGui::EndMenu(); @@ -2044,6 +1665,12 @@ namespace Nuake { if (ImGui::BeginMenu("Debug")) { if (ImGui::MenuItem("Show ImGui demo", NULL, m_ShowImGuiDemo)) m_ShowImGuiDemo = !m_ShowImGuiDemo; + if (ImGui::MenuItem("Rebuild Shaders", NULL)) + { + Nuake::Logger::Log("Rebuilding Shaders..."); + Nuake::ShaderManager::RebuildShaders(); + Nuake::Logger::Log("Shaders Rebuilt."); + } ImGui::EndMenu(); } if (ImGui::BeginMenu("Quit")) ImGui::EndMenu(); @@ -2062,8 +1689,8 @@ namespace Nuake { DrawLogger(); // new stuff - filesystem.Draw(); - filesystem.DrawDirectoryExplorer(); + filesystem->Draw(); + filesystem->DrawDirectoryExplorer(); if (m_ShowImGuiDemo) ImGui::ShowDemoWindow(); @@ -2089,7 +1716,7 @@ namespace Nuake { ImGui::SameLine(); if (ImGui::Button(ICON_FA_PLAY)) { - SceneSnapshot = Engine::GetCurrentScene()->Serialize(); + SceneSnapshot = Engine::GetCurrentScene()->Copy(); Engine::EnterPlayMode(); } ImGui::SameLine(); @@ -2097,8 +1724,8 @@ namespace Nuake { { Engine::ExitPlayMode(); - Engine::GetCurrentScene()->Deserialize(SceneSnapshot.dump()); - m_IsEntitySelected = false; + Engine::LoadScene(SceneSnapshot); + Selection = EditorSelection(); } } ImGui::End(); @@ -2107,14 +1734,7 @@ namespace Nuake { void EditorInterface::BuildFonts() { - ImGuiIO& io = ImGui::GetIO(); (void)io; - static const ImWchar icons_ranges[] = { ICON_MIN_FA, ICON_MAX_FA, 0 }; - ImFontConfig icons_config; icons_config.MergeMode = true; icons_config.PixelSnapH = true; - normalFont = io.Fonts->AddFontFromFileTTF("resources/Fonts/fa-solid-900.ttf", 11.0f, &icons_config, icons_ranges); - boldFont = io.Fonts->AddFontFromFileTTF("resources/Fonts/OpenSans-Bold.ttf", 16.0); ImGui::PushStyleVar(ImGuiStyleVar_ButtonTextAlign, ImVec2(0.5f, 0.5f)); - ImGui::GetIO().Fonts->AddFontDefault(); - icons_config.MergeMode = true; - bigIconFont = io.Fonts->AddFontFromFileTTF("resources/Fonts/fa-solid-900.ttf", 42.0f, &icons_config, icons_ranges); + FontManager::LoadFonts(); } } diff --git a/Editor/src/EditorInterface.h b/Editor/src/Windows/EditorInterface.h similarity index 84% rename from Editor/src/EditorInterface.h rename to Editor/src/Windows/EditorInterface.h index ee1bcc25..d93afb2b 100644 --- a/Editor/src/EditorInterface.h +++ b/Editor/src/Windows/EditorInterface.h @@ -3,18 +3,20 @@ #include "src/Vendors/imgui/imgui.h" #include #include "src/Core/FileSystem.h" -#include "FileSystemUI.h" - +#include "../Actions/EditorSelection.h" +#include "EditorSelectionPanel.h" namespace Nuake { class Material; + class FileSystemUI; class EditorInterface { private: - FileSystemUI filesystem = FileSystemUI(); + FileSystemUI* filesystem; + bool m_DrawGrid = false; bool m_ShowImGuiDemo = false; bool m_DebugCollisions = false; @@ -27,8 +29,11 @@ namespace Nuake { bool m_IsMaterialSelected = false; public: - bool m_IsEntitySelected = false; - Entity m_SelectedEntity; + EditorSelection Selection; + EditorSelectionPanel SelectionPanel; + + EditorInterface(); + static ImFont* bigIconFont; void BuildFonts(); void Init(); diff --git a/Editor/src/Windows/EditorSelectionPanel.cpp b/Editor/src/Windows/EditorSelectionPanel.cpp new file mode 100644 index 00000000..d4097946 --- /dev/null +++ b/Editor/src/Windows/EditorSelectionPanel.cpp @@ -0,0 +1,357 @@ +#include "EditorSelectionPanel.h" +#include "src/Scene/Components/ImportComponents.h" +#include "../Misc/ImGuiTextHelper.h" + +EditorSelectionPanel::EditorSelectionPanel() +{ + mTransformPanel = TransformPanel(); + mLightPanel = LightPanel(); + mScriptPanel = ScriptPanel(); + mQuakeMapPanel = QuakeMapPanel(); +} + +void EditorSelectionPanel::Draw(EditorSelection selection) +{ + if (ImGui::Begin("Propreties")) + { + switch (selection.Type) + { + case EditorSelectionType::None: + { + DrawNone(); + break; + } + + case EditorSelectionType::Entity: + { + DrawEntity(selection.Entity); + break; + } + case EditorSelectionType::File: + { + DrawFile(selection.File.get()); + break; + } + case EditorSelectionType::Resource: + { + DrawResource(selection.Resource); + break; + } + } + } + ImGui::End(); +} + +void EditorSelectionPanel::DrawNone() +{ + std::string text = "No selection"; + auto windowWidth = ImGui::GetWindowSize().x; + auto windowHeight = ImGui::GetWindowSize().y; + + auto textWidth = ImGui::CalcTextSize(text.c_str()).x; + auto textHeight = ImGui::CalcTextSize(text.c_str()).y; + ImGui::SetCursorPosX((windowWidth - textWidth) * 0.5f); + ImGui::SetCursorPosY((windowHeight - textHeight) * 0.5f); + + ImGui::Text(text.c_str()); +} + +void EditorSelectionPanel::DrawEntity(Nuake::Entity entity) +{ + DrawAddComponentMenu(entity); + + // Draw each component properties panels. + mTransformPanel.Draw(entity); + mLightPanel.Draw(entity); + mScriptPanel.Draw(entity); + mMeshPanel.Draw(entity); + mQuakeMapPanel.Draw(entity); + /* + if (Selection.Entity.HasComponent()) + { + std::string icon = ICON_FA_MALE; + if (ImGui::CollapsingHeader((icon + " " + "Mesh").c_str(), ImGuiTreeNodeFlags_DefaultOpen)) + { + ImGui::TextColored(ImGui::GetStyleColorVec4(1), "Mesh properties"); + auto& component = Selection.Entity.GetComponent(); + // Path + std::string path = component.ModelPath; + char pathBuffer[256]; + + memset(pathBuffer, 0, sizeof(pathBuffer)); + std::strncpy(pathBuffer, path.c_str(), sizeof(pathBuffer)); + + std::string oldPath = component.ModelPath; + ImGui::Text("Model: "); + ImGui::SameLine(); + if (ImGui::InputText("##ModelPath", pathBuffer, sizeof(pathBuffer))) + path = FileSystem::AbsoluteToRelative(std::string(pathBuffer)); + if (ImGui::BeginDragDropTarget()) + { + if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("_Model")) + { + char* file = (char*)payload->Data; + std::string fullPath = std::string(file, 256); + path = FileSystem::AbsoluteToRelative(fullPath); + } + ImGui::EndDragDropTarget(); + } + + if (component.ModelPath != path) + { + component.ModelPath = path; + component.LoadModel(); + } + + ImGui::SameLine(); + + if (ImGui::Button("Reimport")) + { + component.LoadModel(); + } + + ImGui::Indent(16.0f); + if (ImGui::CollapsingHeader("Meshes")) + { + ImGui::Indent(16.0f); + uint16_t index = 0; + for (auto& m : component.meshes) + { + if (ImGui::CollapsingHeader(std::to_string(index).c_str())) + { + std::string materialName = "No material"; + if (m->m_Material) + materialName = m->m_Material->GetName(); + + ImGui::Indent(16.0f); + if (ImGui::CollapsingHeader(materialName.c_str())) + { + //if (ImGui::BeginChild("Material child", ImVec2(0, 0), true, ImGuiWindowFlags_AlwaysAutoResize)) + //{ + ImGui::Indent(16.0f); + DrawMaterialEditor(m->m_Material); + //} + //ImGui::EndChild(); + } + + if (ImGui::BeginDragDropTarget()) + { + if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("_Material")) + { + char* file = (char*)payload->Data; + std::string fullPath = std::string(file, 256); + path = FileSystem::AbsoluteToRelative(fullPath); + } + ImGui::EndDragDropTarget(); + } + } + + index++; + } + + } + + ImGui::Separator(); + } + + } + + + + if (Selection.Entity.HasComponent()) { + std::string icon = ICON_FA_FILE; + if (ImGui::CollapsingHeader((icon + " " + "Wren Script").c_str(), ImGuiTreeNodeFlags_DefaultOpen)) + { + ImGui::TextColored(ImGui::GetStyleColorVec4(1), "Script properties"); + auto& component = Selection.Entity.GetComponent(); + + // Path + std::string path = component.Script; + char pathBuffer[256]; + + memset(pathBuffer, 0, sizeof(pathBuffer)); + std::strncpy(pathBuffer, path.c_str(), sizeof(pathBuffer)); + + ImGui::Text("Script: "); + ImGui::SameLine(); + if (ImGui::InputText("##ScriptPath", pathBuffer, sizeof(pathBuffer))) + path = FileSystem::AbsoluteToRelative(std::string(pathBuffer)); + if (ImGui::BeginDragDropTarget()) + { + if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("_Script")) + { + char* file = (char*)payload->Data; + std::string fullPath = std::string(file, 256); + path = FileSystem::AbsoluteToRelative(fullPath); + } + ImGui::EndDragDropTarget(); + } + + + component.Script = path; + + // Class + std::string module = component.Class; + + char classBuffer[256]; + + memset(classBuffer, 0, sizeof(classBuffer)); + std::strncpy(classBuffer, module.c_str(), sizeof(classBuffer)); + + ImGui::Text("Class: "); + ImGui::SameLine(); + if (ImGui::InputText("##ScriptModule", classBuffer, sizeof(classBuffer))) + module = std::string(classBuffer); + + component.Class = module; + ImGui::Separator(); + } + } + + if (Selection.Entity.HasComponent()) { + + std::string icon = ICON_FA_LIGHTBULB; + if (ImGui::CollapsingHeader((icon + " " + "Camera").c_str(), ImGuiTreeNodeFlags_DefaultOpen)) + { + ImGui::TextColored(ImGui::GetStyleColorVec4(1), "Camera properties"); + Selection.Entity.GetComponent().DrawEditor(); + ImGui::Separator(); + } + + } + + if (Selection.Entity.HasComponent()) + { + if (ImGui::CollapsingHeader("Character controller", ImGuiTreeNodeFlags_DefaultOpen)) + { + ImGui::TextColored(ImGui::GetStyleColorVec4(1), "Character controller properties"); + auto& c = Selection.Entity.GetComponent(); + ImGui::InputFloat("Height", &c.Height); + ImGui::InputFloat("Radius", &c.Radius); + ImGui::InputFloat("Mass", &c.Mass); + ImGui::Separator(); + } + } + if (Selection.Entity.HasComponent()) + { + std::string icon = ICON_FA_BOWLING_BALL; + if (ImGui::CollapsingHeader((icon + " Rigidbody").c_str(), ImGuiTreeNodeFlags_DefaultOpen)) + { + ImGui::TextColored(ImGui::GetStyleColorVec4(1), "Rigidbody properties"); + RigidBodyComponent& rbComponent = Selection.Entity.GetComponent(); + ImGui::DragFloat("Mass", &rbComponent.mass, 0.1, 0.0); + ImGui::Separator(); + } + } + if (Selection.Entity.HasComponent()) + { + std::string icon = ICON_FA_BOX; + if (ImGui::CollapsingHeader((icon + " Box collider").c_str(), ImGuiTreeNodeFlags_DefaultOpen)) + { + ImGui::TextColored(ImGui::GetStyleColorVec4(1), "Box collider properties"); + BoxColliderComponent& component = Selection.Entity.GetComponent(); + ImGuiHelper::DrawVec3("Size", &component.Size); + ImGui::Checkbox("Is trigger", &component.IsTrigger); + + ImGui::Separator(); + } + } + if (Selection.Entity.HasComponent()) + { + std::string icon = ICON_FA_CIRCLE; + if (ImGui::CollapsingHeader((icon + " Sphere collider").c_str(), ImGuiTreeNodeFlags_DefaultOpen)) + { + ImGui::TextColored(ImGui::GetStyleColorVec4(1), "Sphere properties"); + SphereColliderComponent& component = Selection.Entity.GetComponent(); + ImGui::DragFloat("Radius", &component.Radius, 0.1f, 0.0f, 100.0f); + ImGui::Checkbox("Is trigger", &component.IsTrigger); + + ImGui::Separator(); + } + } + if (Selection.Entity.HasComponent()) + { + + std::string icon = ICON_FA_BROOM; + if (ImGui::CollapsingHeader((icon + " " + "Quake map").c_str(), ImGuiTreeNodeFlags_DefaultOpen)) + { + ImGui::TextColored(ImGui::GetStyleColorVec4(1), "Quake map properties"); + auto& component = Selection.Entity.GetComponent(); + std::string path = component.Path; + + + char pathBuffer[256]; + memset(pathBuffer, 0, sizeof(pathBuffer)); + std::strncpy(pathBuffer, path.c_str(), sizeof(pathBuffer)); + ImGui::Text("Map file: "); + ImGui::SameLine(); + if (ImGui::InputText("##MapPath", pathBuffer, sizeof(pathBuffer))) + { + path = std::string(pathBuffer); + } + + if (ImGui::BeginDragDropTarget()) + { + if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("_Map")) + { + char* file = (char*)payload->Data; + std::string fullPath = std::string(file, 256); + path = FileSystem::AbsoluteToRelative(fullPath); + } + ImGui::EndDragDropTarget(); + } + + component.Path = path; + + ImGui::InputFloat("Scale factor", &component.ScaleFactor, 0.01f, 0.1f); + + ImGui::Checkbox("Build collisions", &component.HasCollisions); + if (ImGui::Button("Build Geometry")) + { + QuakeMapBuilder mapBuilder; + mapBuilder.BuildQuakeMap(Selection.Entity); + } + ImGui::Separator(); + } + }*/ +} + +void EditorSelectionPanel::DrawAddComponentMenu(Nuake::Entity entity) +{ + if (entity.HasComponent()) + { + auto& entityName = entity.GetComponent().Name; + ImGuiTextSTD("##Name", entityName); + ImGui::SameLine(); + + if (ImGui::Button("Add Component")) + ImGui::OpenPopup("ComponentPopup"); + + if (ImGui::BeginPopup("ComponentPopup")) + { + MenuItemComponent("Wren Script", Nuake::WrenScriptComponent); + MenuItemComponent("Camera", Nuake::CameraComponent); + MenuItemComponent("Light", Nuake::LightComponent); + MenuItemComponent("Mesh", Nuake::MeshComponent); + MenuItemComponent("Rigid body", Nuake::RigidBodyComponent); + MenuItemComponent("Box collider", Nuake::BoxColliderComponent); + MenuItemComponent("Sphere collider", Nuake::SphereColliderComponent); + MenuItemComponent("Mesh collider", Nuake::MeshColliderComponent); + MenuItemComponent("Quake map", Nuake::QuakeMapComponent); + ImGui::EndPopup(); + } + ImGui::Separator(); + } + +} + +void EditorSelectionPanel::DrawFile(Nuake::File* file) +{ + +} + +void EditorSelectionPanel::DrawResource(Nuake::Resource resource) +{ + +} + diff --git a/Editor/src/Windows/EditorSelectionPanel.h b/Editor/src/Windows/EditorSelectionPanel.h new file mode 100644 index 00000000..0a2c332e --- /dev/null +++ b/Editor/src/Windows/EditorSelectionPanel.h @@ -0,0 +1,30 @@ +#pragma once +#include "../Actions/EditorSelection.h" +#include "src/Scene/Entities/Entity.h" +#include "src/Core/FileSystem.h" + +#include "../ComponentsPanel/TransformPanel.h" +#include "../ComponentsPanel/LightPanel.h" +#include "../ComponentsPanel/ScriptPanel.h" +#include "../ComponentsPanel/MeshPanel.h" +#include "../ComponentsPanel/QuakeMapPanel.h" + +class EditorSelectionPanel { +private: + TransformPanel mTransformPanel; + LightPanel mLightPanel; + ScriptPanel mScriptPanel; + MeshPanel mMeshPanel; + QuakeMapPanel mQuakeMapPanel; +public: + EditorSelectionPanel(); + + void Draw(EditorSelection selection); + + void DrawNone(); + void DrawEntity(Nuake::Entity entity); + void DrawAddComponentMenu(Nuake::Entity entity); + + void DrawFile(Nuake::File* file); + void DrawResource(Nuake::Resource resource); +}; \ No newline at end of file diff --git a/Editor/src/FileSystemUI.cpp b/Editor/src/Windows/FileSystemUI.cpp similarity index 91% rename from Editor/src/FileSystemUI.cpp rename to Editor/src/Windows/FileSystemUI.cpp index 5ca91e76..88019809 100644 --- a/Editor/src/FileSystemUI.cpp +++ b/Editor/src/Windows/FileSystemUI.cpp @@ -114,54 +114,53 @@ namespace Nuake { void FileSystemUI::DrawFile(Ref file) { ImGui::PushFont(EditorInterface::bigIconFont); - if (file->Type == ".png" || file->Type == ".jpg") + std::string fileExtension = file->GetExtension(); + if (fileExtension == ".png" || fileExtension == ".jpg") { - Ref texture = TextureManager::Get()->GetTexture(file->fullPath); + Ref texture = TextureManager::Get()->GetTexture(file->GetAbsolutePath()); ImGui::ImageButton((void*)texture->GetID(), ImVec2(100, 100), ImVec2(0, 1), ImVec2(1, 0)); } else { const char* icon = ICON_FA_FILE; - if (file->Type == ".shader") + if (fileExtension == ".shader" || fileExtension == ".wren") icon = ICON_FA_FILE_CODE; - if (file->Type == ".map") + if (fileExtension == ".map") icon = ICON_FA_BROOM; - if (file->Type == ".ogg" || file->Type == ".mp3" || file->Type == ".wav" || file->Type == ".flac") + if (fileExtension == ".ogg" || fileExtension == ".mp3" || fileExtension == ".wav") icon = ICON_FA_FILE_AUDIO; - if (file->Type == ".wren") - icon = ICON_FA_FILE_CODE; - if (file->Type == ".md3" || file->Type == ".obj") + if (fileExtension == ".md3" || fileExtension == ".obj") icon = ICON_FA_FILE_IMAGE; - std::string fullName = icon + std::string("##") + file->fullPath; + std::string fullName = icon + std::string("##") + file->GetAbsolutePath(); if (ImGui::Button(fullName.c_str(), ImVec2(100, 100))) { - + Editor->Selection = EditorSelection(file); } if (ImGui::BeginDragDropSource()) { char pathBuffer[256]; - std::strncpy(pathBuffer, file->fullPath.c_str(), sizeof(pathBuffer)); + std::strncpy(pathBuffer, file->GetAbsolutePath().c_str(), sizeof(pathBuffer)); std::string dragType; - if (file->Type == ".wren") + if (fileExtension == ".wren") dragType = "_Script"; - else if (file->Type == ".map") + else if (fileExtension == ".map") dragType = "_Map"; - else if (file->Type == ".obj" || file->Type == ".mdl" || file->Type == ".gltf" || file->Type == ".md3" || file->Type == ".fbx") + else if (fileExtension == ".obj" || fileExtension == ".mdl" || fileExtension == ".gltf" || fileExtension == ".md3" || fileExtension == ".fbx") dragType = "_Model"; - else if (file->Type == ".interface") + else if (fileExtension == ".interface") dragType = "_Interface"; - else if (file->Type == ".prefab") + else if (fileExtension == ".prefab") dragType = "_Prefab"; ImGui::SetDragDropPayload(dragType.c_str(), (void*)(pathBuffer), sizeof(pathBuffer)); - ImGui::Text(file->name.c_str()); + ImGui::Text(file->GetName().c_str()); ImGui::EndDragDropSource(); } } - ImGui::Text(file->name.c_str()); + ImGui::Text(file->GetName().c_str()); ImGui::PopFont(); } @@ -266,7 +265,7 @@ namespace Nuake { { int width = avail.x; ImVec2 buttonSize = ImVec2(80, 80); - int amount = (int)(width / 200); + int amount = (int)(width / 100); if (amount <= 0) amount = 1; int i = 1; // current amount of item per row. diff --git a/Editor/src/FileSystemUI.h b/Editor/src/Windows/FileSystemUI.h similarity index 82% rename from Editor/src/FileSystemUI.h rename to Editor/src/Windows/FileSystemUI.h index 03a7acee..6ce45ae0 100644 --- a/Editor/src/FileSystemUI.h +++ b/Editor/src/Windows/FileSystemUI.h @@ -1,18 +1,22 @@ #pragma once #include #include +#include "EditorInterface.h" namespace Nuake { class FileSystemUI { private: - + EditorInterface* Editor; public: Ref m_CurrentDirectory; - FileSystemUI() { + + FileSystemUI(EditorInterface* editor) { m_CurrentDirectory = FileSystem::RootDirectory; + Editor = editor; } + void Draw(); void DrawDirectoryContent(); void DrawFiletree(); diff --git a/Editor/src/ProjectInterface.cpp b/Editor/src/Windows/ProjectInterface.cpp similarity index 90% rename from Editor/src/ProjectInterface.cpp rename to Editor/src/Windows/ProjectInterface.cpp index 726e4a66..5d2a88c0 100644 --- a/Editor/src/ProjectInterface.cpp +++ b/Editor/src/Windows/ProjectInterface.cpp @@ -1,7 +1,7 @@ #include "ProjectInterface.h" #include #include "Engine.h" -#include "ImGuiTextHelper.h" +//#include "ImGuiTextHelper.h" namespace Nuake { void ProjectInterface::DrawProjectSettings() @@ -45,7 +45,7 @@ namespace Nuake { ImGui::Text("Trenchbroom path:"); ImGui::SameLine(); - ImGuiTextSTD("", m_CurrentProject->TrenchbroomPath); + //ImGuiTextSTD("", m_CurrentProject->TrenchbroomPath); ImGui::SameLine(); if (ImGui::Button("Browse")) { @@ -62,8 +62,8 @@ namespace Nuake { auto flags = ImGuiWindowFlags_NoTitleBar; if (ImGui::BeginPopupModal("Create new point entity", NULL, flags)) { - ImGuiTextSTD("Name", newEntity.Name); - ImGuiTextMultiline("Description", newEntity.Description); + //ImGuiTextSTD("Name", newEntity.Name); + //ImGuiTextMultiline("Description", newEntity.Description); if (ImGui::BeginTable("DictCreate", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable)) { @@ -75,7 +75,7 @@ namespace Nuake { int idx = 0; for (auto& p : newEntity.Properties) { - ImGuiTextSTD("Name", p.name); + //ImGuiTextSTD("Name", p.name); ImGui::TableNextColumn(); std::string current_item = NULL; if (ImGui::BeginCombo(("TypeSelection" + std::to_string(idx)).c_str(), current_item.c_str())) @@ -146,18 +146,18 @@ namespace Nuake { int i = 0; for (auto& pE : file->PointEntities) { - ImGuiTextSTD("##PName" + std::to_string(i), pE.Name); + //ImGuiTextSTD("##PName" + std::to_string(i), pE.Name); for (int i = 0; i < pE.Name.size(); i++) { if (pE.Name[i] == ' ') pE.Name[i] = '_'; } ImGui::TableNextColumn(); - ImGuiTextSTD("Desc" + std::to_string(i), pE.Description); + //ImGuiTextSTD("Desc" + std::to_string(i), pE.Description); ImGui::TableNextColumn(); ImGui::Button("Edit"); ImGui::TableNextColumn(); - ImGuiTextSTD("Prefab##" + std::to_string(i), pE.Prefab); + //ImGuiTextSTD("Prefab##" + std::to_string(i), pE.Prefab); if (ImGui::BeginDragDropTarget()) { if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("_Prefab")) @@ -201,10 +201,10 @@ namespace Nuake { int i = 0; for (auto& pE : file->BrushEntities) { - ImGuiTextSTD("##Name" + std::to_string(i), pE.Name); + //ImGuiTextSTD("##Name" + std::to_string(i), pE.Name); ImGui::TableNextColumn(); - ImGuiTextSTD("Desc" + std::to_string(i), pE.Description); + //ImGuiTextSTD("Desc" + std::to_string(i), pE.Description); ImGui::TableNextColumn(); ImGui::Checkbox(std::string("Visible##" + std::to_string(i)).c_str(), &pE.Visible); @@ -215,7 +215,7 @@ namespace Nuake { ImGui::TableNextColumn(); - ImGuiTextSTD("Script##" + std::to_string(i), pE.Script); + //ImGuiTextSTD("Script##" + std::to_string(i), pE.Script); if (ImGui::BeginDragDropTarget()) { if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("_Script")) @@ -227,7 +227,7 @@ namespace Nuake { ImGui::EndDragDropTarget(); } - ImGuiTextSTD("Class##" + std::to_string(i), pE.Class); + //ImGuiTextSTD("Class##" + std::to_string(i), pE.Class); ImGui::TableNextColumn(); i++; @@ -238,8 +238,8 @@ namespace Nuake { if (ImGui::BeginPopupModal("CreateBrush", NULL, flags)) { - ImGuiTextSTD("Name", newEntity.Name); - ImGuiTextMultiline("Description", newEntity.Description); + //ImGuiTextSTD("Name", newEntity.Name); + //ImGuiTextMultiline("Description", newEntity.Description); bool isSolid = true; bool isTrigger = false; diff --git a/Editor/src/ProjectInterface.h b/Editor/src/Windows/ProjectInterface.h similarity index 100% rename from Editor/src/ProjectInterface.h rename to Editor/src/Windows/ProjectInterface.h diff --git a/Editor/src/Windows/WelcomeWindow.cpp b/Editor/src/Windows/WelcomeWindow.cpp new file mode 100644 index 00000000..f8530fec --- /dev/null +++ b/Editor/src/Windows/WelcomeWindow.cpp @@ -0,0 +1,83 @@ +#include "WelcomeWindow.h" +#include + +#include "../Misc/InterfaceFonts.h" +#include +#include + +void WelcomeWindow::Draw() +{ + std::vector projects = { + "C:/Dev/Nuake-DemoProject/test.project" + }; + + ImGuiViewport* viewport = ImGui::GetMainViewport(); + ImGui::SetNextWindowPos(viewport->GetWorkPos()); + ImGui::SetNextWindowSize(viewport->GetWorkSize()); + ImGui::SetNextWindowViewport(viewport->ID); + + ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f); + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(32.0f, 32.0f)); + ImGui::Begin("AL:SDAL:SKd", 0, ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoResize); + { + { + UIFont boldfont = UIFont(Fonts::Title); + + std::string text = "Nuake Engine"; + auto windowWidth = ImGui::GetWindowSize().x; + auto textWidth = ImGui::CalcTextSize(text.c_str()).x; + + ImGui::SetCursorPosX((windowWidth - textWidth) * 0.5f); + ImGui::Text(text.c_str()); + } + { + UIFont boldfont = UIFont(Fonts::SubTitle); + std::string text = "An IdTech inspired game engine"; + auto windowWidth = ImGui::GetWindowSize().x; + auto textWidth = ImGui::CalcTextSize(text.c_str()).x; + + ImGui::SetCursorPosX((windowWidth - textWidth) * 0.5f); + ImGui::Text(text.c_str()); + } + ImGui::Separator(); + { + UIFont boldfont = UIFont(Fonts::SubTitle); + ImGui::Text("Projects recently opened"); + } + + ImVec2 projectsWindowSize = ImGui::GetContentRegionAvail(); + projectsWindowSize.x *= 0.6f; + + int idx = 0; + ImGui::BeginChild("Projects", projectsWindowSize, true); + { + for (int i = 0; i < 6; i++) + { + float cursorY = ImGui::GetCursorPosY(); + std::string selectableName = "##My new project" + std::to_string(i); + ImGui::Selectable(selectableName.c_str(), false, 0, ImVec2(ImGui::GetContentRegionAvailWidth(), 100)); + ImGui::SetCursorPosY(cursorY); + { + UIFont boldfont = UIFont(Fonts::LargeBold); + ImGui::Text("Name of project"); + } + + { + UIFont boldfont = UIFont(Fonts::Bold); + ImGui::Text("last modified on 10/20/2022"); + } + { + UIFont boldfont = UIFont(Fonts::Normal); + ImGui::TextWrapped("Description lajsflkahjfklashklashgkASDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDlashglkashlkghalskghaslghaslkghaklsg"); + //ImGui::Text("Description lajsflkahjfklashklashgklashglkashlkghalskghaslghaslkghaklsg"); + } + ImGui::SetCursorPosY(cursorY + 100); + } + } + ImGui::EndChild(); + } + + ImGui::End(); + ImGui::PopStyleVar(); + ImGui::PopStyleVar(); +} \ No newline at end of file diff --git a/Editor/src/Windows/WelcomeWindow.h b/Editor/src/Windows/WelcomeWindow.h new file mode 100644 index 00000000..d95bebdb --- /dev/null +++ b/Editor/src/Windows/WelcomeWindow.h @@ -0,0 +1,9 @@ +#pragma once + + +class WelcomeWindow { +public: + int SelectedProject = 0; + + void Draw(); +}; \ No newline at end of file diff --git a/Nuake/Engine.cpp b/Nuake/Engine.cpp index 0e13b3ce..2ed011cf 100644 --- a/Nuake/Engine.cpp +++ b/Nuake/Engine.cpp @@ -85,10 +85,7 @@ namespace Nuake { // Dont trigger exit if already not in play mode. if (IsPlayMode) - { GetCurrentScene()->OnExit(); - Input::ShowMouse(); - } Input::ShowMouse(); IsPlayMode = false; diff --git a/Nuake/src/Core/FileSystem.cpp b/Nuake/src/Core/FileSystem.cpp index 71a0c455..f5176395 100644 --- a/Nuake/src/Core/FileSystem.cpp +++ b/Nuake/src/Core/FileSystem.cpp @@ -75,11 +75,14 @@ namespace Nuake } else if (entry.is_regular_file()) { - Ref newFile = CreateRef(); - newFile->Type = entry.path().extension().string(); - newFile->name = entry.path().filename().string(); - newFile->Parent = directory; - newFile->fullPath = entry.path().string(); + std::string absolutePath = entry.path().string(); + std::string name = entry.path().filename().string(); + std::string extension = entry.path().extension().string(); + Ref newFile = CreateRef(directory, absolutePath, name, extension); + //newFile->Type = entry.path().extension().string(); + //newFile->name = entry.path().filename().string(); + //newFile->Parent = directory; + //newFile->fullPath = entry.path().string(); directory->Files.push_back(newFile); } } @@ -166,4 +169,38 @@ namespace Nuake return RootDirectory; } + Ref FileSystem::GetFile(const std::string& path) + { + // Note, Might be broken on other platforms. + auto& splits = String::Split(path, '/'); + + int currentDepth = -1; + std::string currentDirName = "."; + Ref currentDirComparator = RootDirectory; + while (currentDirName == currentDirComparator->name) + { + currentDepth++; + currentDirName = splits[currentDepth]; + + // Find next directory + for (auto& d : currentDirComparator->Directories) + { + if (d->name == currentDirName) + { + currentDirComparator = d; + } + } + + // Find in files if can't find in directories. + for (auto& f : currentDirComparator->Files) + { + if (f->GetName() == currentDirName) + { + return f; + } + } + } + + } + } diff --git a/Nuake/src/Core/FileSystem.h b/Nuake/src/Core/FileSystem.h index 4826a627..413773b7 100644 --- a/Nuake/src/Core/FileSystem.h +++ b/Nuake/src/Core/FileSystem.h @@ -4,6 +4,7 @@ #include "Core.h" #include #include +#include "String.h" namespace Nuake { @@ -14,24 +15,8 @@ namespace Nuake static std::string SaveFile(const char* filter); }; - struct Directory; - struct File - { - std::string Type; - std::string name; - - std::string fullPath; - Ref Parent; - }; - - struct Directory - { - std::string name; - std::string fullPath; - Ref Parent; - std::vector> Directories; - std::vector> Files; - }; + class Directory; + class File; class FileSystem { @@ -45,6 +30,7 @@ namespace Nuake static void Scan(); static std::string AbsoluteToRelative(const std::string& path); static Ref GetFileTree(); + static Ref GetFile(const std::string& path); static void ScanDirectory(Ref directory); static void GetDirectories(); @@ -58,4 +44,40 @@ namespace Nuake static bool WriteLine(const std::string line); static void EndWriteFile(); }; + + class File + { + private: + std::string Type; + std::string Name; + std::string RelativePath; + std::string AbsolutePath; + Ref Parent; + public: + + std::string GetExtension() { return Type; } + std::string GetName() { return Name; } + std::string GetRelativePath() { return RelativePath; } + std::string GetAbsolutePath() { return AbsolutePath; } + Ref GetParent() { return Parent; } + + File(Ref parentDir, const std::string& absolutePath, const std::string& name, const std::string& type) + { + AbsolutePath = absolutePath; + Parent = parentDir; + RelativePath = FileSystem::AbsoluteToRelative(absolutePath); + Name = name; + Type = type; + } + }; + + class Directory + { + public: + std::string name; + std::string fullPath; + Ref Parent; + std::vector> Directories; + std::vector> Files; + }; } diff --git a/Nuake/src/Core/ResourceManager.h b/Nuake/src/Core/ResourceManager.h new file mode 100644 index 00000000..b177ae00 --- /dev/null +++ b/Nuake/src/Core/ResourceManager.h @@ -0,0 +1,8 @@ +#pragma once + +namespace Nuake { + class ResourceManager + { + + }; +} \ No newline at end of file diff --git a/Nuake/src/Rendering/Camera.cpp b/Nuake/src/Rendering/Camera.cpp index 6f202c7e..6dbe6600 100644 --- a/Nuake/src/Rendering/Camera.cpp +++ b/Nuake/src/Rendering/Camera.cpp @@ -52,7 +52,7 @@ namespace Nuake //cam->cameraRight = glm::normalize(glm::cross(cam->up, cam->cameraFront)); Direction = glm::normalize(direction); Right = glm::normalize(glm::cross(Vector3(0, 1, 0), Direction)); - + //Up = glm::normalize(glm::cross(Direction, Right)) } Vector3 Camera::GetTranslation() { @@ -72,7 +72,7 @@ namespace Nuake Matrix4 Camera::GetTransform() { - glm::mat4 tr = lookAt(Translation, Translation + Direction, Up); + glm::mat4 tr = lookAt(Translation, Translation + Direction, Vector3(0, 1, 0)); return tr; } diff --git a/Nuake/src/Rendering/Light.cpp b/Nuake/src/Rendering/Light.cpp index c116a17c..84643404 100644 --- a/Nuake/src/Rendering/Light.cpp +++ b/Nuake/src/Rendering/Light.cpp @@ -18,7 +18,7 @@ namespace Nuake } } - DirectionalLight::~DirectionalLight() + DirectionalLight::~DirectionalLight() { for (int i = 0; i < CSM_SPLIT_AMOUNT; i++) { @@ -43,10 +43,6 @@ namespace Nuake m_CascadeSplits[i] = (d - CSM_NEAR_CLIP) / CSM_CLIP_RANGE; } - //mCascadeSplits[0] = 0.2f; - //mCascadeSplits[1] = 0.45f; - //mCascadeSplits[2] = 1.0f; - float lastSplitDist = 0.0f; // Calculate Orthographic Projection matrix for each cascade for (int cascade = 0; cascade < CSM_SPLIT_AMOUNT; cascade++) @@ -113,6 +109,9 @@ namespace Nuake roundOffset = roundOffset * 2.0f / ShadowMapResolution; roundOffset.z = 0.0f; roundOffset.w = 0.0f; + lightProjectionMatrix[0] += roundOffset; + lightProjectionMatrix[1] += roundOffset; + lightProjectionMatrix[2] += roundOffset; lightProjectionMatrix[3] += roundOffset; // Store SplitDistance and ViewProjection-Matrix diff --git a/Nuake/src/Rendering/Light.h b/Nuake/src/Rendering/Light.h index 76fd6435..efda82b6 100644 --- a/Nuake/src/Rendering/Light.h +++ b/Nuake/src/Rendering/Light.h @@ -42,8 +42,8 @@ namespace Nuake { inline Matrix4 GetCascadeViewProjection(const int i) { return m_CascadeViewProjections[i]; } private: static const int CSM_SPLIT_AMOUNT = 4; - const float CSM_NEAR_CLIP = 0.01f; - const float CSM_FAR_CLIP = 1000.0f; + const float CSM_NEAR_CLIP = 0.001f; + const float CSM_FAR_CLIP = 500.0f; const float CSM_CLIP_RANGE = CSM_FAR_CLIP - CSM_NEAR_CLIP; const float mCascadeNearPlaneOffset = 0.0; diff --git a/Nuake/src/Rendering/PostFX/SSAO.cpp b/Nuake/src/Rendering/PostFX/SSAO.cpp new file mode 100644 index 00000000..b568bb35 --- /dev/null +++ b/Nuake/src/Rendering/PostFX/SSAO.cpp @@ -0,0 +1,5 @@ +#include "SSAO.h" + +namespace Nuake { + +} \ No newline at end of file diff --git a/Nuake/src/Rendering/PostFX/SSAO.h b/Nuake/src/Rendering/PostFX/SSAO.h new file mode 100644 index 00000000..20dc525d --- /dev/null +++ b/Nuake/src/Rendering/PostFX/SSAO.h @@ -0,0 +1,8 @@ +#pragma once + + +namespace Nuake { + class SSAO { + + }; +} \ No newline at end of file diff --git a/Nuake/src/Rendering/PostFX/SSR.cpp b/Nuake/src/Rendering/PostFX/SSR.cpp new file mode 100644 index 00000000..5da64eb6 --- /dev/null +++ b/Nuake/src/Rendering/PostFX/SSR.cpp @@ -0,0 +1,65 @@ +#include "SSR.h" +#include +#include "src/Rendering/RenderCommand.h" +#include "src/Rendering/Renderer.h" +#include + +namespace Nuake { + SSR::SSR() + { + mSize = Vector2(1280, 720); + mShader = ShaderManager::GetShader("resources/Shaders/ssr.shader"); + } + + void SSR::Init() + { + OutputFramebuffer = CreateRef(false, mSize); + OutputFramebuffer->SetTexture(CreateRef(mSize, GL_RGBA, GL_RGBA16F, GL_FLOAT)); + } + + void SSR::Resize(Vector2 size) + { + if (mSize == size) + return; + + mSize = size * 0.5f; + Init(); + } + + void SSR::Draw(FrameBuffer* gBuffer, Ref previousFrame, Matrix4 view, Matrix4 projection, Ref cam) + { + OutputFramebuffer->Bind(); + { + RenderCommand::Clear(); + + mShader->Bind(); + + mShader->SetUniform1f("rayStep", RayStep); + mShader->SetUniform1i("iterationCount", IterationCount); + mShader->SetUniform1f("distanceBias", DistanceBias); + mShader->SetUniform1i("enableSSR", (int)1); + mShader->SetUniform1i("sampleCount", SampleCount); + mShader->SetUniform1i("isSamplingEnabled", SamplingEnabled); + mShader->SetUniform1i("isExponentialStepEnabled", ExpoStep); + mShader->SetUniform1i("isAdaptiveStepEnabled", AdaptiveStep); + mShader->SetUniform1i("isBinarySearchEnabled", BinarySearch); + mShader->SetUniform1i("debugDraw", DebugDraw); + mShader->SetUniform1f("samplingCoefficient", SampleingCoefficient); + mShader->SetUniformMat4f("view", view); + mShader->SetUniformMat4f("invView", glm::inverse(view)); + mShader->SetUniformMat4f("proj", projection); + mShader->SetUniformMat4f("invProj", glm::inverse(projection)); + + mShader->SetUniformTex("textureDepth", gBuffer->GetTexture(GL_DEPTH_ATTACHMENT).get(), 1); + mShader->SetUniformTex("textureNorm", gBuffer->GetTexture(GL_COLOR_ATTACHMENT1).get(), 2); + mShader->SetUniformTex("textureMetallic", gBuffer->GetTexture(GL_COLOR_ATTACHMENT2).get(), 3); + + mShader->SetUniformTex("textureAlbedo", gBuffer->GetTexture(GL_COLOR_ATTACHMENT0).get(), 5); + mShader->SetUniformTex("textureFrame", previousFrame.get(), 7); + + Renderer::DrawQuad(Matrix4()); + } + OutputFramebuffer->Unbind(); + } + +} diff --git a/Nuake/src/Rendering/PostFX/SSR.h b/Nuake/src/Rendering/PostFX/SSR.h new file mode 100644 index 00000000..79bec0ab --- /dev/null +++ b/Nuake/src/Rendering/PostFX/SSR.h @@ -0,0 +1,31 @@ +#pragma once +#include "src/Core/Core.h" +#include "src/Rendering/Buffers/Framebuffer.h" +#include "src/Rendering/Shaders/ShaderManager.h" +#include "src/Rendering/Camera.h" + +namespace Nuake { + class SSR { + private: + Vector2 mSize; + Shader* mShader; + public: + Ref OutputFramebuffer; + + float RayStep = 0.2f; + int IterationCount = 100; + float DistanceBias = 0.05f; + int SampleCount = 1; + bool SamplingEnabled = true; + bool ExpoStep = true; + bool AdaptiveStep = true; + bool BinarySearch = true; + bool DebugDraw = false; + float SampleingCoefficient = 0.000f; + + SSR(); + void Init(); + void Resize(Vector2 size); + void Draw(FrameBuffer* gBuffer, Ref previousFrame, Matrix4 view, Matrix4 projection, Ref cam); + }; +} \ No newline at end of file diff --git a/Nuake/src/Rendering/PostFX/Volumetric.cpp b/Nuake/src/Rendering/PostFX/Volumetric.cpp index 9d099aed..d2270844 100644 --- a/Nuake/src/Rendering/PostFX/Volumetric.cpp +++ b/Nuake/src/Rendering/PostFX/Volumetric.cpp @@ -18,7 +18,7 @@ namespace Nuake { void Volumetric::Init() { - mFinalFramebuffer = CreateScope(false, mSize); + mFinalFramebuffer = CreateScope(true, mSize); mFinalFramebuffer->SetTexture(CreateRef(mSize, GL_RGBA, GL_RGBA16F, GL_FLOAT)); } @@ -35,18 +35,19 @@ namespace Nuake { { mFinalFramebuffer->Bind(); mFinalFramebuffer->Clear(); - RenderCommand::Disable(RendererEnum::DEPTH_TEST); RenderCommand::Disable(RendererEnum::FACE_CULL); + + Vector3 cameraPosition = view[3]; Shader* volumetricShader = ShaderManager::GetShader("resources/Shaders/volumetric.shader"); volumetricShader->Bind(); volumetricShader->SetUniformMat4f("u_Projection", projection); volumetricShader->SetUniformMat4f("u_View", view); - volumetricShader->SetUniformTex("u_Depth", mDepth, 0); - volumetricShader->SetUniformVec3("u_CamPosition", view[3]); + volumetricShader->SetUniformTex("u_Depth", mDepth, 1); + volumetricShader->SetUniformVec3("u_CamPosition", cameraPosition); volumetricShader->SetUniform1i("u_StepCount", mStepCount); volumetricShader->SetUniform1f("u_FogAmount", mFogAmount); - volumetricShader->SetUniform1i("u_LightCount", lights.size()); + volumetricShader->SetUniform1i("u_LightCount", 1); for (uint16_t i = 0; i < lights.size(); i++) { @@ -57,10 +58,18 @@ namespace Nuake { volumetricShader->SetUniformVec3(u_light + "color", light.Color); volumetricShader->SetUniformVec3(u_light + "direction", light.GetDirection()); - volumetricShader->SetUniformTex(u_light + "shadowmap", light.m_Framebuffers[0]->GetTexture(GL_DEPTH_ATTACHMENT).get(), 1 + i); + volumetricShader->SetUniformTex("lightShadowmap", light.m_Framebuffers[0]->GetTexture(GL_DEPTH_ATTACHMENT).get(), 2 + i); } + + Renderer::DrawQuad(); mFinalFramebuffer->Unbind(); + + if (ImGui::Begin("Volumetric debug")) + { + ImGui::Image((void*)mFinalFramebuffer->GetTexture()->GetID(), ImGui::GetContentRegionAvail(), ImVec2(0, 1), ImVec2(1, 0)); + } + ImGui::End(); } } \ No newline at end of file diff --git a/Nuake/src/Rendering/SceneRenderer.cpp b/Nuake/src/Rendering/SceneRenderer.cpp index 627cbfc7..bcfe8d4a 100644 --- a/Nuake/src/Rendering/SceneRenderer.cpp +++ b/Nuake/src/Rendering/SceneRenderer.cpp @@ -20,8 +20,14 @@ namespace Nuake { mBloom = CreateScope(4); mBloom->SetSource(shadedTexture); - + mVolumetric = CreateScope(); + + mSSR = CreateScope(); + + mToneMapBuffer = CreateScope(false, Vector2(1920, 1080)); + mToneMapBuffer->SetTexture(CreateRef(Vector2(1920, 1080), GL_RGB), GL_COLOR_ATTACHMENT0); + } void SceneRenderer::Cleanup() @@ -70,12 +76,15 @@ namespace Nuake { mVolumetric->SetDepth(mGBuffer->GetTexture(GL_DEPTH_ATTACHMENT).get()); mVolumetric->Draw(mProjection , mView, lightList); + finalOutput = mVolumetric->GetFinalOutput(); } // Copy final output to target framebuffer - framebuffer.Bind(); + mToneMapBuffer->QueueResize(framebuffer.GetSize()); + mToneMapBuffer->Bind(); { + RenderCommand::Clear(); Shader* shader = ShaderManager::GetShader("resources/Shaders/tonemap.shader"); shader->Bind(); @@ -84,8 +93,24 @@ namespace Nuake { shader->SetUniformTex("u_Source", finalOutput); Renderer::DrawQuad(); } + mToneMapBuffer->Unbind(); + + mSSR->Resize(framebuffer.GetSize()); + mSSR->Draw(mGBuffer.get(), framebuffer.GetTexture(), mView, mProjection, scene.GetCurrentCamera()); + + framebuffer.Bind(); + { + RenderCommand::Clear(); + Shader* shader = ShaderManager::GetShader("resources/Shaders/combine.shader"); + shader->Bind(); + + shader->SetUniformTex("u_Source", mToneMapBuffer->GetTexture().get(), 0); + shader->SetUniformTex("u_Source2", mSSR->OutputFramebuffer->GetTexture().get(), 1); + Renderer::DrawQuad(); + } framebuffer.Unbind(); + RenderCommand::Enable(RendererEnum::DEPTH_TEST); Renderer::EndDraw(); } @@ -97,6 +122,7 @@ namespace Nuake { Shader* shader = ShaderManager::GetShader("resources/Shaders/shadowMap.shader"); shader->Bind(); + RenderCommand::Disable(RendererEnum::FACE_CULL); glCullFace(GL_BACK); auto meshView = scene.m_Registry.view(); diff --git a/Nuake/src/Rendering/SceneRenderer.h b/Nuake/src/Rendering/SceneRenderer.h index 467bacd5..6e6600df 100644 --- a/Nuake/src/Rendering/SceneRenderer.h +++ b/Nuake/src/Rendering/SceneRenderer.h @@ -6,6 +6,7 @@ #include "src/Rendering/Buffers/Framebuffer.h" #include "src/Rendering/PostFX/Bloom.h" #include "src/Rendering/PostFX/Volumetric.h" +#include namespace Nuake { class SceneRenderer { @@ -15,11 +16,15 @@ namespace Nuake { void BeginRenderScene(const Matrix4& projection, const Matrix4& view); void RenderScene(Scene& scene, FrameBuffer& framebuffer); + + + Scope mSSR; private: Matrix4 mProjection, mView; Scope mGBuffer; Scope mShadingBuffer; + Scope mToneMapBuffer; Scope mBloom; Scope mVolumetric; diff --git a/Nuake/src/Rendering/Shaders/Shader.cpp b/Nuake/src/Rendering/Shaders/Shader.cpp index 85158916..1ee00048 100644 --- a/Nuake/src/Rendering/Shaders/Shader.cpp +++ b/Nuake/src/Rendering/Shaders/Shader.cpp @@ -10,9 +10,22 @@ namespace Nuake // TODO: Register all uniform when creating shader. Shader::Shader(const std::string& filePath) { - Source = ParseShader(filePath); + Path = filePath; - ProgramId = CreateProgram(); + Source = ParseShader(this->Path); + ProgramId = CreateProgram(Source); + } + + bool Shader::Rebuild() + { + ShaderSource newSource = ParseShader(this->Path); + unsigned int newProgramId = CreateProgram(newSource); + + if(newProgramId == 0) + return false; + + Source = newSource; + ProgramId = newProgramId; } // Bind the shader @@ -78,24 +91,30 @@ namespace Nuake // Parse both source and creates a shader program. // This returns the program id. - unsigned int Shader::CreateProgram() + unsigned int Shader::CreateProgram(ShaderSource source) { unsigned int program = glCreateProgram(); - unsigned int vs = Compile(GL_VERTEX_SHADER); - unsigned int fs = Compile(GL_FRAGMENT_SHADER); + unsigned int vs = Compile(GL_VERTEX_SHADER, source); + unsigned int fs = Compile(GL_FRAGMENT_SHADER, source); unsigned int gs = 0; unsigned int cs = 0; + if (vs == 0) + return 0; + + if (fs == 0) + return 0; + if (Source.GeometryShader != "") { - gs = Compile(GL_GEOMETRY_SHADER); + gs = Compile(GL_GEOMETRY_SHADER, source); glAttachShader(program, gs); } if (Source.ComputeShader != "") { - cs = Compile(GL_COMPUTE_SHADER); + cs = Compile(GL_COMPUTE_SHADER, source); glAttachShader(program, cs); } @@ -116,14 +135,14 @@ namespace Nuake } // Compile a single shader and checks for error. - unsigned int Shader::Compile(unsigned int type) + unsigned int Shader::Compile(unsigned int type, ShaderSource source) { unsigned int id = glCreateShader(type); const char* src; - if (type == GL_FRAGMENT_SHADER) src = Source.FragmentShader.c_str(); - if (type == GL_VERTEX_SHADER) src = Source.VertexShader.c_str(); - if (type == GL_GEOMETRY_SHADER) src = Source.GeometryShader.c_str(); + if (type == GL_FRAGMENT_SHADER) src = source.FragmentShader.c_str(); + if (type == GL_VERTEX_SHADER) src = source.VertexShader.c_str(); + if (type == GL_GEOMETRY_SHADER) src = source.GeometryShader.c_str(); if (type == GL_COMPUTE_SHADER) src = Source.ComputeShader.c_str(); glShaderSource(id, 1, &src, nullptr); @@ -171,7 +190,7 @@ namespace Nuake int addr = glGetUniformLocation(ProgramId, uniform.c_str()); if (addr == -1) - std::cout << "Warning: uniform '" << uniform << "' doesn't exists!" << std::endl; + return addr;//std::cout << "Warning: uniform '" << uniform << "' doesn't exists!" << std::endl; else UniformCache[uniform] = addr; @@ -201,62 +220,77 @@ namespace Nuake void Shader::SetUniform4f(const std::string& name, float v0, float v1, float v2, float v3) { int addr = FindUniformLocation(name); - ASSERT(addr != -1); - glUniform4f(addr, v0, v1, v2, v3); + //ASSERT(addr != -1); + + if (addr != -1) + glUniform4f(addr, v0, v1, v2, v3); } void Shader::SetUniform3f(const std::string& name, float v0, float v1, float v2) { int addr = FindUniformLocation(name); - ASSERT(addr != -1); - glUniform3f(addr, v0, v1, v2); + //ASSERT(addr != -1); + + if (addr != -1) + glUniform3f(addr, v0, v1, v2); } void Shader::SetUniform2f(const std::string& name, float v0, float v1) { int addr = FindUniformLocation(name); - ASSERT(addr != -1); - glUniform2f(addr, v0, v1); + //ASSERT(addr != -1); + + if (addr != -1) + glUniform2f(addr, v0, v1); } void Shader::SetUniform1i(const std::string& name, int v0) { int addr = FindUniformLocation(name); - ASSERT(addr != -1); - glUniform1i(addr, v0); + //ASSERT(addr != -1); + + if (addr != -1) + glUniform1i(addr, v0); } void Shader::SetUniform1iv(const std::string& name, int size, int* value) { int addr = FindUniformLocation(name); - ASSERT(addr != -1); - glUniform1iv(addr, size, value); + //ASSERT(addr != -1); + if (addr != -1) + glUniform1iv(addr, size, value); } void Shader::SetUniformMat3f(const std::string& name, Matrix3 mat) { int addr = FindUniformLocation(name); - ASSERT(addr != -1); - glUniformMatrix3fv(addr, 1, GL_FALSE, &mat[0][0]); + //ASSERT(addr != -1); + if(addr != -1) + glUniformMatrix3fv(addr, 1, GL_FALSE, &mat[0][0]); } void Shader::SetUniformMat4f(const std::string& name, Matrix4 mat) { int addr = FindUniformLocation(name); - ASSERT(addr != -1); - glUniformMatrix4fv(addr, 1, GL_FALSE, &mat[0][0]); + + if (addr != -1) + glUniformMatrix4fv(addr, 1, GL_FALSE, &mat[0][0]); } void Shader::SetUniform1f(const std::string& name, float v0) { int addr = FindUniformLocation(name); - ASSERT(addr != -1); - glUniform1f(addr, v0); + //ASSERT(addr != -1); + + if (addr != -1) + glUniform1f(addr, v0); } + void Shader::SetUniformTex(const std::string& name, Texture* texture, unsigned int slot) { - ASSERT(texture != nullptr); + //ASSERT(texture != nullptr); + SetUniform1i(name, slot); texture->Bind(slot); } diff --git a/Nuake/src/Rendering/Shaders/Shader.h b/Nuake/src/Rendering/Shaders/Shader.h index fdf45238..4b7923e0 100644 --- a/Nuake/src/Rendering/Shaders/Shader.h +++ b/Nuake/src/Rendering/Shaders/Shader.h @@ -20,6 +20,7 @@ namespace Nuake class Shader { public: + std::string Path; ShaderSource Source; unsigned int ProgramId; @@ -27,6 +28,7 @@ namespace Nuake Shader(const std::string& filePath); + bool Rebuild(); void Bind() const; void Unbind() const; @@ -37,6 +39,7 @@ namespace Nuake void SetUniform3f(const std::string& name, float v0, float v1, float v2); void SetUniform2f(const std::string& name, float v0, float v1); void SetUniform1f(const std::string& name, float v0); + void SetUniform1b(const std::string& name, bool v0); void SetUniformTex(const std::string& name, Texture* texture, unsigned int slot = 0); void SetUniform1i(const std::string& name, int v0); @@ -46,8 +49,8 @@ namespace Nuake private: ShaderSource ParseShader(const std::string& filePath); - unsigned int CreateProgram(); - unsigned int Compile(unsigned int type); + unsigned int CreateProgram(ShaderSource source); + unsigned int Compile(unsigned int type, ShaderSource source); int FindUniformLocation(std::string uniform); }; } diff --git a/Nuake/src/Rendering/Shaders/ShaderManager.cpp b/Nuake/src/Rendering/Shaders/ShaderManager.cpp index 3ba354a4..bd2f2b24 100644 --- a/Nuake/src/Rendering/Shaders/ShaderManager.cpp +++ b/Nuake/src/Rendering/Shaders/ShaderManager.cpp @@ -1,5 +1,6 @@ #pragma once #include "ShaderManager.h" +#include "src/Core/Logger.h" namespace Nuake { @@ -14,4 +15,15 @@ namespace Nuake return m_Shaders[path].get(); } + + void ShaderManager::RebuildShaders() + { + for (auto& s : m_Shaders) + { + if (!s.second->Rebuild()) + { + Logger::Log("Failed to rebuild shader: " + s.first, Nuake::CRITICAL); + } + } + } } diff --git a/Nuake/src/Rendering/Shaders/ShaderManager.h b/Nuake/src/Rendering/Shaders/ShaderManager.h index 6db5a02e..6f987dc9 100644 --- a/Nuake/src/Rendering/Shaders/ShaderManager.h +++ b/Nuake/src/Rendering/Shaders/ShaderManager.h @@ -14,5 +14,6 @@ namespace Nuake public: static Shader* GetShader(const std::string& path); + static void RebuildShaders(); }; } diff --git a/Nuake/src/Rendering/Textures/Material.cpp b/Nuake/src/Rendering/Textures/Material.cpp index 02d2cfb3..55cf1b56 100644 --- a/Nuake/src/Rendering/Textures/Material.cpp +++ b/Nuake/src/Rendering/Textures/Material.cpp @@ -94,45 +94,54 @@ namespace Nuake // return; MaterialManager::Get()->CurrentlyBoundedMaterial = m_Name; - glBindBuffer(GL_UNIFORM_BUFFER, UBO); - - glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(UBOStructure), &data); - glBindBuffer(GL_UNIFORM_BUFFER, 0); - glBindBufferBase(GL_UNIFORM_BUFFER, 32, UBO); + // Albedo if (m_Albedo != nullptr) + { + data.u_HasAlbedo = 1; m_Albedo->Bind(4); + } else m_DefaultAlbedo->Bind(4); shader->SetUniform1i("m_Albedo", 4); // AO if (m_AO != nullptr) + { + data.u_HasAO = 1; m_AO->Bind(5); + } else m_DefaultAO->Bind(5); shader->SetUniform1i("m_AO", 5); // Metallic - if (m_Metalness != nullptr) + if (m_Metalness != nullptr) { + data.u_HasMetalness = 1; m_Metalness->Bind(6); + } else m_DefaultMetalness->Bind(6); shader->SetUniform1i("m_Metalness", 6); // Roughness - if (m_Roughness != nullptr) + if (m_Roughness != nullptr) { + data.u_HasRoughness = 1; m_Roughness->Bind(7); + } else m_DefaultRoughness->Bind(7); shader->SetUniform1i("m_Roughness", 7); // Normal - if (m_Normal != nullptr) + if (m_Normal != nullptr) { + data.u_HasNormal = 1; m_Normal->Bind(8); + } else m_DefaultNormal->Bind(8); + shader->SetUniform1i("m_Normal", 8); // Displacement @@ -140,6 +149,12 @@ namespace Nuake m_Displacement->Bind(9); else m_DefaultDisplacement->Bind(9); + + glBindBuffer(GL_UNIFORM_BUFFER, UBO); + + glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(UBOStructure), &data); + glBindBuffer(GL_UNIFORM_BUFFER, 0); + glBindBufferBase(GL_UNIFORM_BUFFER, 32, UBO); //Renderer::m_Shader->SetUniform1i("m_Displacement", 9); //Renderer::m_Shader->SetUniform1i("m_Displacement", 9); } diff --git a/Nuake/src/Rendering/Textures/Material.h b/Nuake/src/Rendering/Textures/Material.h index 4b23aa57..eadbaa58 100644 --- a/Nuake/src/Rendering/Textures/Material.h +++ b/Nuake/src/Rendering/Textures/Material.h @@ -44,9 +44,9 @@ namespace Nuake 0, // Has metalness 0.f, // Metalness value 0, // u_HasRoughness - 1.f, // u_RoughnessValue + 0.f, // u_RoughnessValue 0, // u_HasAO - 0.5f, // u_AOValue + 1.f, // u_AOValue 0, // u_HasNormal 0, // u_HasDisplacement 0 diff --git a/Nuake/src/Rendering/Textures/MaterialManager.cpp b/Nuake/src/Rendering/Textures/MaterialManager.cpp index 8da4a0b7..cb5a627b 100644 --- a/Nuake/src/Rendering/Textures/MaterialManager.cpp +++ b/Nuake/src/Rendering/Textures/MaterialManager.cpp @@ -25,12 +25,6 @@ namespace Nuake Ref MaterialManager::GetMaterial(std::string name) { - if (!FileSystem::FileExists(name)) - { - Logger::Log("Couldn't load material: " + name + " - File doesn't exists", Nuake::LOG_TYPE::CRITICAL); - name = DEFAULT_MATERIAL; - } - if (!IsMaterialLoaded(name)) { Ref newMaterial = CreateRef(name); diff --git a/Nuake/src/Resource/Resource.h b/Nuake/src/Resource/Resource.h index 86c90a86..b2c05523 100644 --- a/Nuake/src/Resource/Resource.h +++ b/Nuake/src/Resource/Resource.h @@ -1,5 +1,47 @@ #pragma once +#include +#include +#include "src/Rendering/Mesh/Mesh.h" -class Ressource -{ -}; \ No newline at end of file +namespace Nuake { + enum class ResourceType + { + Texture, + Prefab, + Map, + Mesh, + Shader + }; + + + class Resource + { + public: + unsigned int Id; + ResourceType Type; + + bool IsEmbedded; + std::string Path; // Only if embedded + + void MakeExternal(); + void Duplicate(); + void MakeEmbedded(); + }; + + class TextureResource : Resource + { + public: + std::string TexturePath; + // texture flags + }; + + + class ModelResource : Resource + { + public: + std::vector SubMeshes; + + ModelResource(); + bool Load(const std::string& path); + }; +} diff --git a/Nuake/src/Resource/ResourceManager.h b/Nuake/src/Resource/ResourceManager.h new file mode 100644 index 00000000..68290ca0 --- /dev/null +++ b/Nuake/src/Resource/ResourceManager.h @@ -0,0 +1,16 @@ +#pragma once +#include "src/Core/Core.h" +#include "src/Resource/Resource.h" +#include "src/Resource/UUID.h" + +#include + +namespace Nuake { + class ResourceManager { + private: + static std::unordered_map> m_Resources; + + public: + static Ref GetResource(const UUID& uuid); + }; +} \ No newline at end of file diff --git a/Nuake/src/Resource/UUID.cpp b/Nuake/src/Resource/UUID.cpp new file mode 100644 index 00000000..2136fdb7 --- /dev/null +++ b/Nuake/src/Resource/UUID.cpp @@ -0,0 +1,18 @@ +#include "UUID.h" +#include + +namespace Nuake { + static std::random_device s_RandomDevice; + static std::mt19937_64 s_Engine(s_RandomDevice()); + static std::uniform_int_distribution s_UniformDistribution; + + UUID::UUID() : m_UUID(s_UniformDistribution(s_Engine)) + { + + } + + UUID::UUID(uint64_t uuid) : m_UUID(uuid) + { + + } +} diff --git a/Nuake/src/Resource/UUID.h b/Nuake/src/Resource/UUID.h new file mode 100644 index 00000000..67482900 --- /dev/null +++ b/Nuake/src/Resource/UUID.h @@ -0,0 +1,30 @@ +#pragma once +#include +#include + +namespace Nuake { + + class UUID + { + public: + UUID(); + UUID(uint64_t uuid); + UUID(const UUID&) = default; + + operator uint64_t() const { return m_UUID; } + private: + uint64_t m_UUID; + }; +} + + +namespace std { + template<> + struct hash + { + std::size_t operator()(const Nuake::UUID& uuid) const + { + return hash()((uint64_t)uuid); + } + }; +} \ No newline at end of file diff --git a/Nuake/src/Scene/Components/BoxCollider.h b/Nuake/src/Scene/Components/BoxCollider.h index 1fbafef8..125452b3 100644 --- a/Nuake/src/Scene/Components/BoxCollider.h +++ b/Nuake/src/Scene/Components/BoxCollider.h @@ -1,6 +1,7 @@ #pragma once #include "src/Core/Physics/PhysicsShapes.h" #include "src/Core/Core.h" + namespace Nuake { class BoxColliderComponent { diff --git a/Nuake/src/Scene/Components/ImportComponents.h b/Nuake/src/Scene/Components/ImportComponents.h new file mode 100644 index 00000000..f110bf1d --- /dev/null +++ b/Nuake/src/Scene/Components/ImportComponents.h @@ -0,0 +1,22 @@ +#pragma once + +// Base +#include "NameComponent.h" +#include "ParentComponent.h" +#include "TransformComponent.h" +#include "PrefabComponent.h" + +#include "CameraComponent.h" +#include "LightComponent.h" +#include "MeshComponent.h" +#include "QuakeMap.h" + +// Physics +#include "RigidbodyComponent.h" +#include "BoxCollider.h" +#include "SphereCollider.h" +#include "MeshCollider.h" + +// Behaviour +#include "WrenScriptComponent.h" + diff --git a/Nuake/src/Scene/Components/LightComponent.cpp b/Nuake/src/Scene/Components/LightComponent.cpp index 6384d4ca..9cd8a776 100644 --- a/Nuake/src/Scene/Components/LightComponent.cpp +++ b/Nuake/src/Scene/Components/LightComponent.cpp @@ -36,7 +36,10 @@ namespace Nuake { for (int i = 0; i < CSM_AMOUNT; i++) { m_Framebuffers[i] = CreateRef(false, glm::vec2(4096, 4096)); - m_Framebuffers[i]->SetTexture(CreateRef(glm::vec2(4096, 4096), GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT, GL_FLOAT), GL_DEPTH_ATTACHMENT); + auto texture = CreateRef(glm::vec2(4096, 4096), GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT, GL_FLOAT); + texture->SetParameter(GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE); + m_Framebuffers[i]->SetTexture(texture, GL_DEPTH_ATTACHMENT); + } } else { diff --git a/Nuake/src/Scene/Components/LightComponent.h b/Nuake/src/Scene/Components/LightComponent.h index 2eec9598..ac6d92cc 100644 --- a/Nuake/src/Scene/Components/LightComponent.h +++ b/Nuake/src/Scene/Components/LightComponent.h @@ -63,11 +63,11 @@ namespace Nuake glm::mat4 inverseViewProjection = glm::inverse(viewProjection); // TODO: Automate this - const float nearClip = 0.01f; - const float farClip = 1000.0f; + const float nearClip = 0.0001f; + const float farClip = 800.0f; const float clipRange = farClip - nearClip; - const float mCascadeNearPlaneOffset = 0.0; + const float mCascadeNearPlaneOffset = -100.0f; const float mCascadeFarPlaneOffset = 0.0; // Calculate the optimal cascade distances diff --git a/Nuake/src/Scene/Components/MeshComponent.cpp b/Nuake/src/Scene/Components/MeshComponent.cpp index a6c11577..0a8854a6 100644 --- a/Nuake/src/Scene/Components/MeshComponent.cpp +++ b/Nuake/src/Scene/Components/MeshComponent.cpp @@ -73,15 +73,22 @@ namespace Nuake { vector.z = mesh->mNormals[i].z; vertex.normal = vector; - vector.x = mesh->mTangents[i].x; - vector.y = mesh->mTangents[i].y; - vector.z = mesh->mTangents[i].z; - vertex.tangent = vector; + if (mesh->mTangents) + { + vector.x = mesh->mTangents[i].x; + vector.y = mesh->mTangents[i].y; + vector.z = mesh->mTangents[i].z; + vertex.tangent = vector; + } + + if (mesh->mBitangents) + { + vector.x = mesh->mBitangents[i].x; + vector.y = mesh->mBitangents[i].y; + vector.z = mesh->mBitangents[i].z; + vertex.bitangent = vector; + } - vector.x = mesh->mBitangents[i].x; - vector.y = mesh->mBitangents[i].y; - vector.z = mesh->mBitangents[i].z; - vertex.bitangent = vector; if (mesh->mTextureCoords[0]) // does the mesh contain texture coordinates? { diff --git a/Nuake/src/Scene/Components/PrefabComponent.h b/Nuake/src/Scene/Components/PrefabComponent.h index 182704eb..5bc62f6f 100644 --- a/Nuake/src/Scene/Components/PrefabComponent.h +++ b/Nuake/src/Scene/Components/PrefabComponent.h @@ -11,8 +11,6 @@ namespace Nuake { void SetPrefab(Ref prefab) { PrefabInstance = prefab; - - } }; } \ No newline at end of file diff --git a/Nuake/src/Scene/Components/WrenScriptComponent.h b/Nuake/src/Scene/Components/WrenScriptComponent.h index f80155f7..ba098273 100644 --- a/Nuake/src/Scene/Components/WrenScriptComponent.h +++ b/Nuake/src/Scene/Components/WrenScriptComponent.h @@ -7,15 +7,14 @@ namespace Nuake { { public: std::string Script; - std::string Class; + unsigned int mModule = 0; Ref mWrenScript; json Serialize() { BEGIN_SERIALIZE(); SERIALIZE_VAL(Script); - SERIALIZE_VAL(Class); END_SERIALIZE(); } @@ -24,8 +23,6 @@ namespace Nuake { BEGIN_DESERIALIZE(); if (j.contains("Script")) Script = j["Script"]; - if (j.contains("Class")) - Class = j["Class"]; return true; diff --git a/Nuake/src/Scene/EditorCamera.cpp b/Nuake/src/Scene/EditorCamera.cpp index c69c3101..4d38dff1 100644 --- a/Nuake/src/Scene/EditorCamera.cpp +++ b/Nuake/src/Scene/EditorCamera.cpp @@ -2,6 +2,7 @@ #include "../Core/Input.h" #include #include +#include "src/Core/Logger.h" namespace Nuake { @@ -99,4 +100,13 @@ namespace Nuake Direction = glm::normalize(Direction); Right = glm::normalize(glm::cross(Up, Direction)); } + Ref EditorCamera::Copy() + { + Ref copy = CreateRef(); + copy->Translation = this->Translation; + copy->Yaw = this->Yaw; + copy->Pitch = this->Pitch; + + return copy; + } } diff --git a/Nuake/src/Scene/EditorCamera.h b/Nuake/src/Scene/EditorCamera.h index a4033ba9..44a797a9 100644 --- a/Nuake/src/Scene/EditorCamera.h +++ b/Nuake/src/Scene/EditorCamera.h @@ -1,6 +1,7 @@ #pragma once #include "../Core/Timestep.h" #include "../Rendering/Camera.h" +#include "src/Core/Core.h" namespace Nuake { @@ -14,6 +15,9 @@ namespace Nuake } void Update(Timestep ts); + + + Ref Copy(); private: bool controlled = false; bool firstMouse = false; @@ -21,7 +25,7 @@ namespace Nuake float mouseLastX; float mouseLastY; - float Yaw = 0.f; - float Pitch = 0.f; + float Yaw = -135.f; + float Pitch = -45.f; }; } diff --git a/Nuake/src/Scene/Environment/ProceduralSky.cpp b/Nuake/src/Scene/Environment/ProceduralSky.cpp index 356a650d..72f9cd94 100644 --- a/Nuake/src/Scene/Environment/ProceduralSky.cpp +++ b/Nuake/src/Scene/Environment/ProceduralSky.cpp @@ -85,6 +85,20 @@ namespace Nuake return SunDirection; } + Ref ProceduralSky::Copy() + { + auto copy = CreateRef(); + copy->SurfaceRadius = this->SurfaceRadius; + copy->AtmosphereRadius = this->AtmosphereRadius; + copy->RayleighScattering = this->RayleighScattering; + copy->MieScattering = this->MieScattering; + copy->SunIntensity = this->SunIntensity; + copy->CenterPoint = this->CenterPoint; + copy->SunDirection = this->SunDirection; + + return copy; + } + json ProceduralSky::Serialize() { BEGIN_SERIALIZE() diff --git a/Nuake/src/Scene/Environment/ProceduralSky.h b/Nuake/src/Scene/Environment/ProceduralSky.h index af5a396e..bbe5bf32 100644 --- a/Nuake/src/Scene/Environment/ProceduralSky.h +++ b/Nuake/src/Scene/Environment/ProceduralSky.h @@ -25,6 +25,8 @@ namespace Nuake Vector3 GetSunDirection(); + Ref Copy(); + json Serialize() override; bool Deserialize(const std::string& str) override; }; diff --git a/Nuake/src/Scene/Lighting/Environment.cpp b/Nuake/src/Scene/Lighting/Environment.cpp index e79bab26..c92bbc5a 100644 --- a/Nuake/src/Scene/Lighting/Environment.cpp +++ b/Nuake/src/Scene/Lighting/Environment.cpp @@ -27,6 +27,25 @@ namespace Nuake { Renderer::m_Shader->SetUniform1f("u_FogStepCount", VolumetricStepCount); } + Ref Environment::Copy() + { + Ref copy = CreateRef(); + copy->CurrentSkyType = this->CurrentSkyType; + copy->ProceduralSkybox = this->ProceduralSkybox->Copy(); + copy->VolumetricEnabled = this->VolumetricEnabled; + copy->VolumetricFog = this->VolumetricFog; + copy->VolumetricStepCount = this->VolumetricStepCount; + + copy->Exposure = this->Exposure; + copy->Gamma = this->Gamma; + + copy->BloomEnabled = this->BloomEnabled; + copy->ClearColor = this->ClearColor; + copy->AmbientColor = this->AmbientColor; + + return copy; + } + json Environment::Serialize() { BEGIN_SERIALIZE(); diff --git a/Nuake/src/Scene/Lighting/Environment.h b/Nuake/src/Scene/Lighting/Environment.h index d17519a2..bb939313 100644 --- a/Nuake/src/Scene/Lighting/Environment.h +++ b/Nuake/src/Scene/Lighting/Environment.h @@ -42,6 +42,8 @@ namespace Nuake void Push(); + Ref Copy(); + json Serialize() override; bool Deserialize(const std::string& str) override; }; diff --git a/Nuake/src/Scene/Scene.cpp b/Nuake/src/Scene/Scene.cpp index a15ee1a7..57cc3bcc 100644 --- a/Nuake/src/Scene/Scene.cpp +++ b/Nuake/src/Scene/Scene.cpp @@ -83,6 +83,8 @@ namespace Nuake { } } + + bool Scene::OnInit() { for (auto& system : m_Systems) @@ -139,7 +141,7 @@ namespace Nuake { void Scene::Draw(FrameBuffer& framebuffer, const Matrix4& projection, const Matrix4& view) { - mSceneRenderer->BeginRenderScene(projection, view); + mSceneRenderer->BeginRenderScene(m_EditorCamera->GetPerspective(), m_EditorCamera->GetTransform()); mSceneRenderer->RenderScene(*this, framebuffer); } @@ -170,13 +172,18 @@ namespace Nuake { } Entity Scene::CreateEntity(const std::string& name) + { + return CreateEntity(name, (int)OS::GetTime()); + } + + Entity Scene::CreateEntity(const std::string& name, int id) { Entity entity = { m_Registry.create(), this }; entity.AddComponent(); NameComponent& nameComponent = entity.AddComponent(); nameComponent.Name = name; - nameComponent.ID = (int)OS::GetTime(); + nameComponent.ID = id; ParentComponent& parentComponent = entity.AddComponent(); @@ -233,6 +240,11 @@ namespace Nuake { return m_Environement; } + void Scene::SetEnvironment(Ref env) + { + m_Environement = env; + } + bool Scene::Save() { if (Path == "") @@ -252,12 +264,53 @@ namespace Nuake { return true; } - Scene* Scene::Copy() + template + void Scene::CopyComponent(entt::registry& dst, entt::registry& src) { - Scene* sceneCopy = new Scene(); + auto view = src.view(); + for (auto e : view) + { + int id = src.get(e).ID; + auto& component = src.get(e); + + auto idView = dst.view(); + for (auto de : idView) + { + if (idView.get(de).ID == src.get(e).ID) + { + dst.emplace_or_replace(de, component); + } + } + } + + } + + Ref Scene::Copy() + { + Ref sceneCopy = CreateRef(); sceneCopy->Path = this->Path; sceneCopy->Name = this->Name; + sceneCopy->m_EditorCamera = this->m_EditorCamera->Copy(); + + sceneCopy->SetEnvironment(this->GetEnvironment()->Copy()); + + auto& srcRegistry = this->m_Registry; + auto& dstRegistry = sceneCopy->m_Registry; + auto idView = srcRegistry.view(); + for (auto e : idView) + { + NameComponent& nameComponent = srcRegistry.get(e); + int id = nameComponent.ID; + std::string& name = nameComponent.Name; + sceneCopy->CreateEntity(name, id); + } + + CopyComponent(sceneCopy->m_Registry, this->m_Registry); + CopyComponent(sceneCopy->m_Registry, this->m_Registry); + CopyComponent(sceneCopy->m_Registry, this->m_Registry); + CopyComponent(sceneCopy->m_Registry, this->m_Registry); + return sceneCopy; } diff --git a/Nuake/src/Scene/Scene.h b/Nuake/src/Scene/Scene.h index a228e89c..471b69aa 100644 --- a/Nuake/src/Scene/Scene.h +++ b/Nuake/src/Scene/Scene.h @@ -21,7 +21,7 @@ namespace Nuake { { friend Entity; private: - std::string Name; // Name of the scene + std::string Name; bool has_changed = true; // The systems are what updates the components. @@ -29,22 +29,16 @@ namespace Nuake { // In the scene constructor. std::vector> m_Systems; Ref m_Environement; - SceneRenderer* mSceneRenderer; public: Ref m_EditorCamera; entt::registry m_Registry; std::string Path = ""; + SceneRenderer* mSceneRenderer; static Ref New(); Scene(); ~Scene(); - std::string GetName(); - bool SetName(std::string& newName); - - Entity GetEntity(int handle); - Entity GetEntityByID(int id); - bool OnInit(); void OnExit(); void Update(Timestep ts); @@ -54,23 +48,31 @@ namespace Nuake { void Draw(FrameBuffer& framebuffer); void Draw(FrameBuffer& framebuffer, const Matrix4& projection, const Matrix4& view); - std::vector GetAllEntities(); - Entity GetEntity(const std::string& name); - - Entity CreateEntity(const std::string& name); - void DestroyEntity(Entity entity); // TODO: Could return bool + std::string GetName(); + bool SetName(std::string& newName); Ref GetCurrentCamera(); + + Entity CreateEntity(const std::string& name); + Entity CreateEntity(const std::string& name, int id); + void DestroyEntity(Entity entity); + + std::vector GetAllEntities(); + Entity GetEntity(const std::string& name); + Entity GetEntity(int handle); + Entity GetEntityByID(int id); + + template + static void CopyComponent(entt::registry& dst, entt::registry& src); + Ref GetEnvironment() const; + void SetEnvironment(Ref env); bool Save(); bool SaveAs(const std::string& path); - - void AddInterface(Ref interface); + Ref Copy(); json Serialize() override; - - Scene* Copy(); bool Deserialize(const std::string& str) override; }; } diff --git a/Nuake/src/Scene/Systems/QuakeMapBuilder.cpp b/Nuake/src/Scene/Systems/QuakeMapBuilder.cpp index b04daf3c..3778462f 100644 --- a/Nuake/src/Scene/Systems/QuakeMapBuilder.cpp +++ b/Nuake/src/Scene/Systems/QuakeMapBuilder.cpp @@ -214,7 +214,7 @@ namespace Nuake { { auto& wrenScript = brushEntity.AddComponent(); wrenScript.Script = fgdBrush.Script; - wrenScript.Class = fgdBrush.Class; + wrenScript.mModule = 0; // TODO } if (bsp.IsTrigger) diff --git a/Nuake/src/Scene/Systems/ScriptingSystem.cpp b/Nuake/src/Scene/Systems/ScriptingSystem.cpp index 1266013e..78e52ada 100644 --- a/Nuake/src/Scene/Systems/ScriptingSystem.cpp +++ b/Nuake/src/Scene/Systems/ScriptingSystem.cpp @@ -13,22 +13,17 @@ namespace Nuake { { ScriptingEngine::Init(); - auto entities = m_Scene->m_Registry.view(); - for (auto e : entities) + auto& entities = m_Scene->m_Registry.view(); + for (auto& e : entities) { WrenScriptComponent& wren = entities.get(e); - if (wren.Script != "" && wren.Class != "") - { - wren.mWrenScript = CreateRef(wren.Script, wren.Class, true); - if (!wren.mWrenScript->CompiledSuccesfully) - return false; - } + wren.mWrenScript->Build(wren.mModule, true); + + if (!wren.mWrenScript->HasCompiledSuccesfully()) + return false; - if (wren.mWrenScript != nullptr) - { - wren.mWrenScript->SetScriptableEntityID((int)e); - wren.mWrenScript->CallInit(); - } + wren.mWrenScript->SetScriptableEntityID((int)e); + wren.mWrenScript->CallInit(); } return true; diff --git a/Nuake/src/Scripting/Modules/EngineModule.h b/Nuake/src/Scripting/Modules/EngineModule.h index b6f082d6..f2fd480e 100644 --- a/Nuake/src/Scripting/Modules/EngineModule.h +++ b/Nuake/src/Scripting/Modules/EngineModule.h @@ -5,17 +5,18 @@ #include "ScriptModule.h" #include #include + namespace Nuake { namespace ScriptAPI { class EngineModule : public ScriptModule { - std::string ModuleName = "Engine"; + const std::string ModuleName = "Engine"; std::string GetModuleName() override { - return "Engine"; + return ModuleName; } void RegisterModule(WrenVM* vm) override diff --git a/Nuake/src/Scripting/ScriptingEngine.cpp b/Nuake/src/Scripting/ScriptingEngine.cpp index 59916bdf..7d69a124 100644 --- a/Nuake/src/Scripting/ScriptingEngine.cpp +++ b/Nuake/src/Scripting/ScriptingEngine.cpp @@ -88,18 +88,18 @@ namespace Nuake { return result; } - Ref ScriptingEngine::RegisterScript(const std::string& path, const std::string& mod) - { - // Check if scripts has already been loaded. - // You can't import the same module twice, otherwise, compile error. - if (m_Scripts.find(path) == m_Scripts.end()) - { - std::string query = "import \"" + path + "\" for " + mod; - wrenInterpret(m_WrenVM, "main", query.c_str()); - } - - return CreateRef(path, mod); - } + //Ref ScriptingEngine::RegisterScript(const std::string& path, const std::string& mod) + //{ + // //// Check if scripts has already been loaded. + // //// You can't import the same module twice, otherwise, compile error. + // //if (m_Scripts.find(path) == m_Scripts.end()) + // //{ + // // std::string query = "import \"" + path + "\" for " + mod; + // // wrenInterpret(m_WrenVM, "main", query.c_str()); + // //} + // // + // //return CreateRef(path, mod); + //} // Useful to check if a script has been imported, importing a script // twice gives a compile error. @@ -120,8 +120,6 @@ namespace Nuake { m_LoadedScripts.push_back(path); } - - void ScriptingEngine::RegisterModule(Ref scriptModule) { Modules[scriptModule->GetModuleName()] = scriptModule; diff --git a/Nuake/src/Scripting/WrenScript.cpp b/Nuake/src/Scripting/WrenScript.cpp index ffffdbc6..1d5bfec1 100644 --- a/Nuake/src/Scripting/WrenScript.cpp +++ b/Nuake/src/Scripting/WrenScript.cpp @@ -1,18 +1,57 @@ #include "WrenScript.h" -#include "../Core/FileSystem.h" +#include "src/Core/String.h" + #include namespace Nuake { - WrenScript::WrenScript(const std::string& path, const std::string& mod, bool isEntity) + WrenScript::WrenScript(Ref file, bool isEntity) + { + mFile = file; + IsEntity = isEntity; + + ParseModules(); + } + + void WrenScript::ParseModules() + { + std::ifstream MyReadFile(mFile->GetAbsolutePath()); + std::string fileContent = ""; + + while (getline(MyReadFile, fileContent)) + { + bool hasFoundModule = false; + + auto& splits = String::Split(fileContent, ' '); + for (unsigned int i = 0; i < splits.size(); i++) + { + std::string s = splits[i]; + if (s == "class" && i + 1 < splits.size() && !hasFoundModule) + { + std::string moduleFound = splits[i + 1]; + mModules.push_back(moduleFound); + hasFoundModule = true; + } + } + } + + // Close the file + MyReadFile.close(); + } + + std::vector WrenScript::GetModules() + { + return mModules; + } + + void WrenScript::Build(unsigned int moduleId, bool isEntity) { WrenVM* vm = ScriptingEngine::GetWrenVM(); - CompiledSuccesfully = true; - + std::string relativePath = mFile->GetRelativePath(); // Can't import twice the same script, otherwise gives a compile error. - if (!ScriptingEngine::IsScriptImported(path)) + if (!ScriptingEngine::IsScriptImported(relativePath)) { - std::string source = "import \"" + path + "\" for " + mod; + std::string source = "import \"" + relativePath + "\" for " + GetModules()[moduleId]; WrenInterpretResult result = wrenInterpret(vm, "main", source.c_str()); if (result != WREN_RESULT_SUCCESS) @@ -21,12 +60,12 @@ namespace Nuake { if (!CompiledSuccesfully) return; - ScriptingEngine::ImportScript(path); + ScriptingEngine::ImportScript(relativePath); } // Get handle to class wrenEnsureSlots(vm, 1); - wrenGetVariable(vm, "main", mod.c_str(), 0); + wrenGetVariable(vm, "main", GetModules()[moduleId].c_str(), 0); WrenHandle* classHandle = wrenGetSlotHandle(vm, 0); // Call the constructor @@ -44,10 +83,14 @@ namespace Nuake { if (isEntity) this->m_SetEntityIDHandle = wrenMakeCallHandle(vm, "SetEntityId(_)"); + + CompiledSuccesfully = true; } void WrenScript::CallInit() { + if (!CompiledSuccesfully) return; + WrenVM* vm = ScriptingEngine::GetWrenVM(); wrenSetSlotHandle(vm, 0, this->m_Instance); WrenInterpretResult result = wrenCall(vm, this->m_OnInitHandle); @@ -55,6 +98,8 @@ namespace Nuake { void WrenScript::CallUpdate(float timestep) { + if (!CompiledSuccesfully) return; + WrenVM* vm = ScriptingEngine::GetWrenVM(); wrenEnsureSlots(vm, 2); wrenSetSlotHandle(vm, 0, this->m_Instance); @@ -64,6 +109,8 @@ namespace Nuake { void WrenScript::CallFixedUpdate(float timestep) { + if (!CompiledSuccesfully) return; + WrenVM* vm = ScriptingEngine::GetWrenVM(); wrenEnsureSlots(vm, 2); wrenSetSlotHandle(vm, 0, this->m_Instance); @@ -84,6 +131,9 @@ namespace Nuake { void WrenScript::RegisterMethod(const std::string& signature) { + if (!CompiledSuccesfully) + return; + WrenVM* vm = ScriptingEngine::GetWrenVM(); WrenHandle* handle = wrenMakeCallHandle(vm, signature.c_str()); methods.emplace(signature, handle); @@ -91,8 +141,10 @@ namespace Nuake { void WrenScript::CallMethod(const std::string& signature) { - WrenVM* vm = ScriptingEngine::GetWrenVM(); + if (!CompiledSuccesfully) + return; + WrenVM* vm = ScriptingEngine::GetWrenVM(); // Not found. maybe try to register it? if (methods.find(signature) == methods.end()) @@ -105,6 +157,9 @@ namespace Nuake { void WrenScript::SetScriptableEntityID(int id) { + if (!CompiledSuccesfully) + return; + WrenVM* vm = ScriptingEngine::GetWrenVM(); wrenSetSlotHandle(vm, 0, this->m_Instance); wrenSetSlotDouble(vm, 1, id); diff --git a/Nuake/src/Scripting/WrenScript.h b/Nuake/src/Scripting/WrenScript.h index e714b5c2..7ce5b98b 100644 --- a/Nuake/src/Scripting/WrenScript.h +++ b/Nuake/src/Scripting/WrenScript.h @@ -1,5 +1,7 @@ #pragma once #include "ScriptingEngine.h" + +#include "src/Core/FileSystem.h" #include #include @@ -8,7 +10,14 @@ class WrenHandle; namespace Nuake { class WrenScript { + private: + bool CompiledSuccesfully; + bool IsEntity = false; + std::vector mModules; + public: + Ref mFile; + std::map methods; WrenHandle* m_Instance; WrenHandle* m_OnInitHandle; @@ -17,10 +26,14 @@ namespace Nuake { WrenHandle* m_OnExitHandle; WrenHandle* m_SetEntityIDHandle; - bool CompiledSuccesfully; + // Building + WrenScript(Ref file, bool isEntity); - WrenScript(const std::string& path, const std::string& mod, bool isEntity = false); + void ParseModules(); + std::vector GetModules(); + void Build(unsigned int moduleId, bool isEntity = false); + // Method calls void CallInit(); void CallUpdate(float timestep); void CallFixedUpdate(float timestep); @@ -30,5 +43,7 @@ namespace Nuake { void CallMethod(const std::string& signature); void SetScriptableEntityID(int id); + + bool HasCompiledSuccesfully() { return CompiledSuccesfully; } }; }