Merge branch 'main' into feature/NK-138-nuake-runtime

# Conflicts:
#	Editor/Runtime.cpp
This commit is contained in:
Antoine Pilote
2023-08-07 19:07:01 -04:00
146 changed files with 25057 additions and 10847 deletions

Binary file not shown.

View File

@@ -24,6 +24,8 @@ class Scene {
return Light.new(id)
} else if (component == "CharacterController") {
return CharacterController.new(id)
} else if (component == "RigidBody") {
return RigidBody.new(id)
} else if (component == "Camera") {
return Camera.new(id)
} else if (component == "Transform") {
@@ -70,6 +72,31 @@ class Scene {
foreign static IsCharacterControllerOnGround_(e)
//foreign static IsOnGround_(e)
// RigidBody
foreign static AddForce_(e, x, y, z)
// Physics
static RayCast(from, to) {
// Fetch results from physics manager, returns a list of floats
// that we need to unpack into vector3
var results = Scene.RayCast_(from.x, from.y, from.z, to.x, to.y, to.z)
var points = [] // Result array of vec3
var size = results.count / 3
var i = 0
while(i < size) {
// size is base 1 while array is base 0, offset by 1
var listIndex = i - 1
points.add(Vector3.new(results[listIndex], results[listIndex + 1], results[listIndex + 2]))
i = i + 1
}
return points
}
foreign static RayCast_(fromX, fromY, fromZ, toX, toY, toZ)
foreign static TriggerGetOverlappingBodyCount_(e)
foreign static TriggerGetOverlappingBodies_(e)
@@ -159,6 +186,16 @@ class CharacterController {
}
}
class RigidBody {
construct new(id) {
_entityId = id
}
AddForce(force) {
Scene.AddForce_(_entityId, force.x, force,y, force.z)
}
}
class Camera {
construct new(id) {
_entityId = id

View File

@@ -23,7 +23,6 @@ void main()
//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);
@@ -83,10 +82,17 @@ void main()
// Albedo
gAlbedo = vec4(m_AlbedoColor, 1.0);
if (u_HasAlbedo == 1)
gAlbedo.rgb = texture(m_Albedo, UV).rgb;
{
vec4 albedoSample = texture(m_Albedo, UV);
gAlbedo.rgb = albedoSample.rgb * m_AlbedoColor.rgb;
gAlbedo.a = albedoSample.a;
if (albedoSample.a < 0.1f)
{
discard;
}
}
gAlbedo.rgb = texture(m_Albedo, UV).rgb * m_AlbedoColor.rgb;
// Material
float finalMetalness = u_MetalnessValue;
if (u_HasMetalness == 1)

View File

@@ -8,6 +8,7 @@ out flat vec2 UV;
out mat4 v_InvView;
out mat4 v_InvProjection;
out mat4 v_View;
out mat4 v_Projection;
uniform mat4 u_View;
uniform mat4 u_Projection;
@@ -15,6 +16,7 @@ uniform mat4 u_Projection;
void main()
{
v_View = u_View;
v_Projection = u_Projection;
v_InvView = inverse(u_View);
v_InvProjection = inverse(u_Projection);
@@ -28,7 +30,6 @@ void main()
uniform sampler2D u_Depth;
uniform sampler2D u_Normal;
uniform sampler2D u_Noise;
uniform int u_KernelSize = 64;
uniform vec3 u_Samples[64];
@@ -39,13 +40,20 @@ uniform float u_Bias = 0.025f;
uniform float u_Falloff = 0.0022;
uniform float u_Area = 0.0075;
uniform float u_Strength = 2.0f;
in vec2 UV;
in mat4 v_View;
in mat4 v_InvView;
in mat4 v_InvProjection;
in mat4 v_Projection;
out vec4 FragColor;
float linearize_depth(float d, float zNear, float zFar)
{
return zNear * zFar / (zFar + d * (zNear - zFar));
}
vec3 WorldPosFromDepth(float depth)
{
float z = depth * 2.0 - 1.0;
@@ -91,46 +99,54 @@ vec3 normal_from_depth(float depth, vec2 texcoords) {
void main()
{
float depth = texture(u_Depth, UV).r ;
vec3 fragPos = ViewPosFromDepth(depth);
float normalizedRadius = u_Radius;
if(depth > 0.9999999f)
float depth = texture(u_Depth, UV).r;
if (depth > 0.9999999f)
{
FragColor = vec4(0, 0, 0, 0);
return;
}
vec3 goodNormal = normal_from_depth(depth, UV);
vec3 normal = texture(u_Normal, UV).rgb * 2.0 - 1.0;
vec4 normalT = v_View * vec4(normal, 1.0);
normalT *= -1.0f;
normal = normalT.xyz;
normal = normalize(normal);
normal = goodNormal;
vec3 randomVec = texture(u_Noise, UV * u_NoiseScale).xyz;
float radius_depth = normalizedRadius / depth;
const float SCALING_NEAR = 0.92;
float depthScaler = (depth - SCALING_NEAR) / (1.0 - SCALING_NEAR);
const float minRadius = 0.05f;
const float maxRadius = 1.2f;
const float scalerPow = 1.8f;
depthScaler = min(max(pow(depthScaler, scalerPow), minRadius), maxRadius);
float scaledRadius = u_Radius * depthScaler;
vec3 fragPos = ViewPosFromDepth(depth);
vec3 normal = texture(u_Normal, UV).xyz * 2.0 - 1.0;//normal_from_depth(depth, UV);
normal.z *= -1.0f;
// Remove translation from view;
mat4 invView = v_InvView;
invView[3] = vec4(0, 0, 0, 1);
normal = (invView * vec4(normal, 1.0f)).xyz;
vec3 randomVec = texture(u_Noise, UV * u_NoiseScale).xyz;
vec3 tangent = normalize(randomVec - normal * dot(randomVec, normal));
vec3 bitangent = cross(normal, tangent);
mat3 TBN = mat3(tangent, bitangent, normal);
float occlusion = 0.0;
vec3 position = vec3(UV, depth);
int skipped = 0;
float rangeCheckC = 0.0f;
for(int i=0; i < 64; i++)
for (int i = 0; i < 64; i++)
{
vec3 ray = u_Radius * reflect(u_Samples[i], randomVec);
vec3 hemi_ray = position + sign(dot(ray, normal)) * ray;
float sampleDepth = texture(u_Depth, hemi_ray.xy).r;
float rangeCheck = smoothstep(0.0, 1.0, u_Radius * 0.8 / abs(depth - sampleDepth));
float ao = hemi_ray.z >= sampleDepth + u_Bias ? 1.0 : 0.0;
occlusion += ao * rangeCheck;
rangeCheckC += rangeCheck;
vec3 samplePos = TBN * u_Samples[i]; // generate a random point
samplePos.z *= -1.0f;
samplePos = fragPos + samplePos * scaledRadius;
vec4 offset = vec4(samplePos, 1.0); // make it a 4-vector
offset = v_Projection * offset; // project on the near clipping plane
offset.xyz /= offset.w; // perform perspective divide
offset.xyz = offset.xyz * 0.5 + 0.5; // transform to (0,1) range
float sampleDepth = texture(u_Depth, offset.xy).r;
float rangeCheck = smoothstep(0.0, 1.0, scaledRadius / abs((samplePos.z) - sampleDepth));
occlusion += (sampleDepth <= depth - u_Bias / 100.0 ? 1.0 : 0.0) * rangeCheck;
}
float ao = 1.0 - (occlusion / 64.0);
rangeCheckC /= 64.0;
float finalAO = pow(ao, u_Strength);
float finalAO = pow(ao, u_Strength * 100.0);
FragColor = vec4(finalAO, finalAO, finalAO, 1.0);
//FragColor = vec4(rangeCheckC, rangeCheckC, rangeCheckC, 1.0);
//FragColor = vec4(1.0, 1.0, 1.0, 1.0);
}

View File

@@ -36,7 +36,7 @@
{ \
delete boldFont; \
ImGui::PopStyleVar(); \
if (ImGui::BeginTable(#name, 3, ImGuiTableFlags_BordersInner)) \
if (ImGui::BeginTable(#name, 3, ImGuiTableFlags_BordersInner | ImGuiTableFlags_SizingStretchProp)) \
{ \
ImGui::TableSetupColumn("name", 0, 0.25f); \
ImGui::TableSetupColumn("set", 0, 0.65f); \

View File

@@ -20,7 +20,7 @@ public:
ImGui::Text("Color");
ImGui::TableNextColumn();
ImGui::PushItemWidth(ImGui::GetContentRegionAvailWidth());
ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x);
ImGui::ColorEdit3("##lightcolor", &component.Color.r, ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel);
ImGui::PopItemWidth();

View File

@@ -38,7 +38,7 @@ void MaterialEditor::Draw(Ref<Nuake::Material> material)
if (flagsHeaderOpened)
{
ImGui::BeginTable("##Flags", 3, ImGuiTableFlags_BordersInner);
ImGui::BeginTable("##Flags", 3, ImGuiTableFlags_BordersInner | ImGuiTableFlags_SizingStretchProp);
{
ImGui::TableSetupColumn("name", 0, 0.3f);
ImGui::TableSetupColumn("set", 0, 0.6f);
@@ -80,7 +80,7 @@ void MaterialEditor::Draw(Ref<Nuake::Material> material)
textureID = TextureManager::Get()->GetTexture("default")->GetID();
}
if (ImGui::ImageButtonEx(ImGui::GetCurrentWindow()->GetID("#image1"), (void*)textureID, ImVec2(80, 80), ImVec2(0, 1), ImVec2(1, 0), ImVec2(2, 2), ImVec4(0, 0, 0, 0), ImVec4(1, 1, 1, 1)))
if (ImGui::ImageButtonEx(ImGui::GetCurrentWindow()->GetID("#image1"), (void*)textureID, ImVec2(80, 80), ImVec2(0, 1), ImVec2(1, 0), ImVec4(0, 0, 0, 0), ImVec4(1, 1, 1, 1)))
{
std::string texture = FileDialog::OpenFile("*.png | *.jpg");
if (texture != "")
@@ -118,7 +118,7 @@ void MaterialEditor::Draw(Ref<Nuake::Material> material)
textureID = TextureManager::Get()->GetTexture("default")->GetID();
}
if (ImGui::ImageButtonEx(ImGui::GetCurrentWindow()->GetID("#image3"), (void*)textureID, ImVec2(80, 80), ImVec2(0, 1), ImVec2(1, 0), ImVec2(2, 2), ImVec4(0, 0, 0, 1), ImVec4(1, 1, 1, 1)))
if (ImGui::ImageButtonEx(ImGui::GetCurrentWindow()->GetID("#image3"), (void*)textureID, ImVec2(80, 80), ImVec2(0, 1), ImVec2(1, 0), ImVec4(0, 0, 0, 1), ImVec4(1, 1, 1, 1)))
{
std::string texture = FileDialog::OpenFile("*.png | *.jpg");
if (texture != "")
@@ -153,7 +153,7 @@ void MaterialEditor::Draw(Ref<Nuake::Material> material)
textureID = TextureManager::Get()->GetTexture("default")->GetID();
}
if (ImGui::ImageButtonEx(ImGui::GetCurrentWindow()->GetID("#image2"), (void*)textureID, ImVec2(80, 80), ImVec2(0, 1), ImVec2(1, 0), ImVec2(2, 2), ImVec4(1, 1, 1, 1), ImVec4(1, 1, 1, 1)))
if (ImGui::ImageButtonEx(ImGui::GetCurrentWindow()->GetID("#image2"), (void*)textureID, ImVec2(80, 80), ImVec2(0, 1), ImVec2(1, 0), ImVec4(1, 1, 1, 1), ImVec4(1, 1, 1, 1)))
{
std::string texture = FileDialog::OpenFile("Image files (*.png) | *.png | Image files (*.jpg) | *.jpg");
if (texture != "")
@@ -191,7 +191,7 @@ void MaterialEditor::Draw(Ref<Nuake::Material> material)
textureID = TextureManager::Get()->GetTexture("default")->GetID();
}
if (ImGui::ImageButtonEx(ImGui::GetCurrentWindow()->GetID("#image4"), (void*)textureID, ImVec2(80, 80), ImVec2(0, 1), ImVec2(1, 0), ImVec2(2, 2), ImVec4(0, 0, 0, 1), ImVec4(1, 1, 1, 1)))
if (ImGui::ImageButtonEx(ImGui::GetCurrentWindow()->GetID("#image4"), (void*)textureID, ImVec2(80, 80), ImVec2(0, 1), ImVec2(1, 0), ImVec4(0, 0, 0, 1), ImVec4(1, 1, 1, 1)))
{
std::string texture = FileDialog::OpenFile("*.png | *.jpg");
if (texture != "")
@@ -229,7 +229,7 @@ void MaterialEditor::Draw(Ref<Nuake::Material> material)
textureID = TextureManager::Get()->GetTexture("default")->GetID();
}
if (ImGui::ImageButtonEx(ImGui::GetCurrentWindow()->GetID("#image5"), (void*)textureID, ImVec2(80, 80), ImVec2(0, 1), ImVec2(1, 0), ImVec2(2, 2), ImVec4(0, 0, 0, 0), ImVec4(1, 1, 1, 1)))
if (ImGui::ImageButtonEx(ImGui::GetCurrentWindow()->GetID("#image5"), (void*)textureID, ImVec2(80, 80), ImVec2(0, 1), ImVec2(1, 0), ImVec4(0, 0, 0, 0), ImVec4(1, 1, 1, 1)))
{
std::string texture = FileDialog::OpenFile("*.png | *.jpg");
if (texture != "")

View File

@@ -0,0 +1,88 @@
#pragma once
#include "ComponentPanel.h"
#include <src/Core/FileSystem.h>
#include <src/Core/Maths.h>
#include <src/Scene/Components/ParticleEmitterComponent.h>
#include <src/Scene/Entities/ImGuiHelper.h>
class ParticleEmitterPanel : ComponentPanel
{
public:
ParticleEmitterPanel() {}
void Draw(Nuake::Entity entity) override
{
if (!entity.HasComponent<Nuake::ParticleEmitterComponent>())
return;
auto& component = entity.GetComponent<Nuake::ParticleEmitterComponent>();
BeginComponentTable(PARTICLE EMITTER, Nuake::ParticleEmitterComponent);
{
{
ImGui::Text("Particle Color");
ImGui::TableNextColumn();
ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x);
ImGui::ColorEdit3("##lightcolor", &component.ParticleColor.r, ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel);
ImGui::PopItemWidth();
ImGui::TableNextColumn();
ComponentTableReset(component.ParticleColor, Nuake::Vector4(1, 1, 1, 1));
}
ImGui::TableNextColumn();
{
ImGui::Text("Amount");
ImGui::TableNextColumn();
ImGui::DragFloat("##ParticleAmount", &component.Amount, 0.1f, 0.0f, 500.0f);
ImGui::TableNextColumn();
ComponentTableReset(component.Amount, 10.0f);
}
ImGui::TableNextColumn();
{
ImGui::Text("Rate");
ImGui::TableNextColumn();
ImGui::DragFloat("##ParticleRate", &component.Rate, 0.1f, 0.0f, 10.0f);
ImGui::TableNextColumn();
ComponentTableReset(component.Rate, 0.0f);
}
ImGui::TableNextColumn();
{
ImGui::Text("Life");
ImGui::TableNextColumn();
ImGui::DragFloat("##ParticleLife", &component.Life, 0.1f, 0.0f, 100.0f);
ImGui::TableNextColumn();
ComponentTableReset(component.Life, 5.0f);
}
ImGui::TableNextColumn();
{
ImGui::Text("Gravity");
ImGui::TableNextColumn();
ImGuiHelper::DrawVec3("Gravity", &component.Gravity);
ImGui::TableNextColumn();
ComponentTableReset(component.Gravity, Nuake::Vector3(0, -1, 0));
}
ImGui::TableNextColumn();
{
ImGui::Text("Gravity Random");
ImGui::TableNextColumn();
ImGui::DragFloat("##GravityRandom", &component.GravityRandom, 0.01f, 0.0f, 1.0f);
ImGui::TableNextColumn();
ComponentTableReset(component.GravityRandom, 0.0f);
}
ImGui::TableNextColumn();
{
ImGui::Text("Radius");
ImGui::TableNextColumn();
ImGui::DragFloat("##ParticleRadius", &component.Radius, 0.01f, 0.0f, 10.0f);
ImGui::TableNextColumn();
ComponentTableReset(component.Radius, 1.0f);
}
}
EndComponentTable();
}
};

View File

@@ -0,0 +1,73 @@
#pragma once
#include "ComponentPanel.h"
#include <src/Core/FileSystem.h>
#include <src/Core/Maths.h>
#include <src/Scene/Components/SpriteComponent.h>
#include <src/Scene/Entities/ImGuiHelper.h>
class SpritePanel : ComponentPanel
{
public:
SpritePanel() = default;
~SpritePanel() = default;
void Draw(Nuake::Entity entity) override
{
if (!entity.HasComponent<Nuake::SpriteComponent>())
{
return;
}
auto& component = entity.GetComponent<Nuake::SpriteComponent>();
BeginComponentTable(SPRITE, Nuake::SpriteComponent);
{
{
ImGui::Text("Sprite");
ImGui::TableNextColumn();
std::string path = component.SpritePath;
ImGui::Button(path.empty() ? "Drag image" : component.SpritePath.c_str(), ImVec2(ImGui::GetContentRegionAvail().x, 0));
if (ImGui::BeginDragDropTarget())
{
if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("_Image"))
{
char* file = (char*)payload->Data;
std::string fullPath = std::string(file, 512);
path = Nuake::FileSystem::AbsoluteToRelative(std::move(fullPath));
component.SpritePath = path;
component.LoadSprite();
}
ImGui::EndDragDropTarget();
}
ImGui::TableNextColumn();
ComponentTableReset(component.LockYRotation, false);
}
ImGui::TableNextColumn();
{
ImGui::Text("Billboard");
ImGui::TableNextColumn();
ImGui::Checkbox("##billboard", &component.Billboard);
ImGui::TableNextColumn();
ComponentTableReset(component.Billboard, false);
}
ImGui::TableNextColumn();
{
ImGui::Text("Lock Y rotation");
ImGui::TableNextColumn();
ImGui::Checkbox("##lockYRotation", &component.LockYRotation);
ImGui::TableNextColumn();
ComponentTableReset(component.LockYRotation, false);
}
}
EndComponentTable();
}
};

View File

@@ -16,6 +16,7 @@
#include <src/Scene/Components/CylinderColliderComponent.h>
#include <src/Scene/Components/MeshCollider.h>
#include <src/Scene/Components/ModelComponent.h>
#include <src/Scene/Components/ParticleEmitterComponent.h>
GizmoDrawer::GizmoDrawer()
@@ -35,7 +36,7 @@ GizmoDrawer::GizmoDrawer()
GenerateSphereGizmo();
// Box
const Color cubeColor = Color(1, 0, 0, 1);
const Color cubeColor = Color(1, 0, 0, 0.5f);
std::vector<LineVertex> mBoxVertices =
{
LineVertex{Vector3(-1.f, -1.f, -1.f), cubeColor},
@@ -110,8 +111,8 @@ void GizmoDrawer::GenerateSphereGizmo()
vert2 = Vector3(x2, 0, z2);
}
circleVertices.push_back(LineVertex{ vert1, Color(1.0, 0, 0.0, 1.0) });
circleVertices.push_back(LineVertex{ vert2, Color(1.0, 0, 0.0, 1.0) });
circleVertices.push_back(LineVertex{ vert1, Color(1.0, 0, 0.0, 0.5) });
circleVertices.push_back(LineVertex{ vert2, Color(1.0, 0, 0.0, 0.5) });
}
mCircleBuffer = CreateRef<Nuake::VertexArray>();
@@ -217,6 +218,18 @@ void GizmoDrawer::DrawGizmos(Ref<Scene> scene)
Nuake::RenderCommand::DrawLines(0, 264);
}
auto particleView = scene->m_Registry.view<TransformComponent, ParticleEmitterComponent>();
for (auto e : particleView)
{
auto [transform, particle] = scene->m_Registry.get<TransformComponent, ParticleEmitterComponent>(e);
mLineShader->Bind();
mLineShader->SetUniformMat4f("u_View", glm::scale(glm::translate(scene->m_EditorCamera->GetTransform(), transform.Translation), Vector3(particle.Radius)));
mLineShader->SetUniformMat4f("u_Projection", scene->m_EditorCamera->GetPerspective());
mCircleBuffer->Bind();
Nuake::RenderCommand::DrawLines(0, 128);
}
auto meshColliderView = scene->m_Registry.view<TransformComponent, MeshColliderComponent, ModelComponent>();
for (auto e : meshColliderView)
{

View File

@@ -62,8 +62,8 @@ void CapsuleGizmo::CreateMesh()
vert2 = Vector3(x2, bottomCircleHeight, z2);
}
_CapsuleVertices.push_back(LineVertex{ vert1, Color(1.0, 0, 0.0, 1.0) });
_CapsuleVertices.push_back(LineVertex{ vert2, Color(1.0, 0, 0.0, 1.0) });
_CapsuleVertices.push_back(LineVertex{ vert1, Color(1.0, 0, 0.0, 0.5) });
_CapsuleVertices.push_back(LineVertex{ vert2, Color(1.0, 0, 0.0, 0.5) });
}
for (int i = 0; i < subDivision * 2.0; i++)
@@ -94,21 +94,21 @@ void CapsuleGizmo::CreateMesh()
vert2 = Vector3(0, z2 + heightOffset, x2);
}
_CapsuleVertices.push_back(LineVertex{ vert1, Color(1.0, 0, 0.0, 1.0) });
_CapsuleVertices.push_back(LineVertex{ vert2, Color(1.0, 0, 0.0, 1.0) });
_CapsuleVertices.push_back(LineVertex{ vert1, Color(1.0, 0, 0.0, 0.5) });
_CapsuleVertices.push_back(LineVertex{ vert2, Color(1.0, 0, 0.0, 0.5) });
}
_CapsuleVertices.push_back(LineVertex{ Vector3(radius, bottomCircleHeight, 0), Color(1.0, 0, 0.0, 1.0) });
_CapsuleVertices.push_back(LineVertex{ Vector3(radius, topCircleHeight, 0), Color(1.0, 0, 0.0, 1.0) });
_CapsuleVertices.push_back(LineVertex{ Vector3(radius, bottomCircleHeight, 0), Color(1.0, 0, 0.0, 0.5) });
_CapsuleVertices.push_back(LineVertex{ Vector3(radius, topCircleHeight, 0), Color(1.0, 0, 0.0, 0.5) });
_CapsuleVertices.push_back(LineVertex{ Vector3(-radius, bottomCircleHeight, 0), Color(1.0, 0, 0.0, 1.0) });
_CapsuleVertices.push_back(LineVertex{ Vector3(-radius, topCircleHeight, 0), Color(1.0, 0, 0.0, 1.0) });
_CapsuleVertices.push_back(LineVertex{ Vector3(-radius, bottomCircleHeight, 0), Color(1.0, 0, 0.0, 0.5) });
_CapsuleVertices.push_back(LineVertex{ Vector3(-radius, topCircleHeight, 0), Color(1.0, 0, 0.0, 0.5) });
_CapsuleVertices.push_back(LineVertex{ Vector3(0, bottomCircleHeight, radius), Color(1.0, 0, 0.0, 1.0) });
_CapsuleVertices.push_back(LineVertex{ Vector3(0, topCircleHeight, radius), Color(1.0, 0, 0.0, 1.0) });
_CapsuleVertices.push_back(LineVertex{ Vector3(0, bottomCircleHeight, radius), Color(1.0, 0, 0.0, 0.5) });
_CapsuleVertices.push_back(LineVertex{ Vector3(0, topCircleHeight, radius), Color(1.0, 0, 0.0, 0.5) });
_CapsuleVertices.push_back(LineVertex{ Vector3(0, bottomCircleHeight, -radius), Color(1.0, 0, 0.0, 1.0) });
_CapsuleVertices.push_back(LineVertex{ Vector3(0, topCircleHeight, -radius), Color(1.0, 0, 0.0, 1.0) });
_CapsuleVertices.push_back(LineVertex{ Vector3(0, bottomCircleHeight, -radius), Color(1.0, 0, 0.0, 0.5) });
_CapsuleVertices.push_back(LineVertex{ Vector3(0, topCircleHeight, -radius), Color(1.0, 0, 0.0, 0.5) });
_CapsuleBuffer = CreateRef<Nuake::VertexArray>();
_CapsuleBuffer->Bind();

View File

@@ -62,21 +62,21 @@ void CylinderGizmo::CreateMesh()
vert2 = Vector3(x2, bottomCircleHeight, z2);
}
_CylinderVertices.push_back(LineVertex{ vert1, Color(1.0, 0, 0.0, 1.0) });
_CylinderVertices.push_back(LineVertex{ vert2, Color(1.0, 0, 0.0, 1.0) });
_CylinderVertices.push_back(LineVertex{ vert1, Color(1.0, 0, 0.0, 0.5) });
_CylinderVertices.push_back(LineVertex{ vert2, Color(1.0, 0, 0.0, 0.5) });
}
_CylinderVertices.push_back(LineVertex{ Vector3(radius, bottomCircleHeight, 0), Color(1.0, 0, 0.0, 1.0) });
_CylinderVertices.push_back(LineVertex{ Vector3(radius, topCircleHeight, 0), Color(1.0, 0, 0.0, 1.0) });
_CylinderVertices.push_back(LineVertex{ Vector3(radius, bottomCircleHeight, 0), Color(1.0, 0, 0.0, 0.5) });
_CylinderVertices.push_back(LineVertex{ Vector3(radius, topCircleHeight, 0), Color(1.0, 0, 0.0, 0.5) });
_CylinderVertices.push_back(LineVertex{ Vector3(-radius, bottomCircleHeight, 0), Color(1.0, 0, 0.0, 1.0) });
_CylinderVertices.push_back(LineVertex{ Vector3(-radius, topCircleHeight, 0), Color(1.0, 0, 0.0, 1.0) });
_CylinderVertices.push_back(LineVertex{ Vector3(-radius, bottomCircleHeight, 0), Color(1.0, 0, 0.0, 0.5) });
_CylinderVertices.push_back(LineVertex{ Vector3(-radius, topCircleHeight, 0), Color(1.0, 0, 0.0, 0.5) });
_CylinderVertices.push_back(LineVertex{ Vector3(0, bottomCircleHeight, radius), Color(1.0, 0, 0.0, 1.0) });
_CylinderVertices.push_back(LineVertex{ Vector3(0, topCircleHeight, radius), Color(1.0, 0, 0.0, 1.0) });
_CylinderVertices.push_back(LineVertex{ Vector3(0, bottomCircleHeight, radius), Color(1.0, 0, 0.0, 0.5) });
_CylinderVertices.push_back(LineVertex{ Vector3(0, topCircleHeight, radius), Color(1.0, 0, 0.0, 0.5) });
_CylinderVertices.push_back(LineVertex{ Vector3(0, bottomCircleHeight, -radius), Color(1.0, 0, 0.0, 1.0) });
_CylinderVertices.push_back(LineVertex{ Vector3(0, topCircleHeight, -radius), Color(1.0, 0, 0.0, 1.0) });
_CylinderVertices.push_back(LineVertex{ Vector3(0, bottomCircleHeight, -radius), Color(1.0, 0, 0.0, 0.5) });
_CylinderVertices.push_back(LineVertex{ Vector3(0, topCircleHeight, -radius), Color(1.0, 0, 0.0, 0.5) });
_CylinderBuffer = CreateRef<Nuake::VertexArray>();
_CylinderBuffer->Bind();

View File

@@ -1,15 +1,15 @@
#include "PopupHelper.h"
#include "imgui/imgui.h"
#include "regex"
void PopupHelper::Confirmation(const std::string& id)
void PopupHelper::OpenPopup(const std::string& id)
{
ImGui::TextWrapped(id.c_str());
ImGui::OpenPopup(id.c_str());
}
bool PopupHelper::DefineDialog(const std::string& id, const std::string& text)
bool PopupHelper::DefineConfirmationDialog(const std::string& id, const std::string& text)
{
bool result = false;
@@ -30,3 +30,56 @@ bool PopupHelper::DefineDialog(const std::string& id, const std::string& text)
return result;
}
bool PopupHelper::DefineTextDialog(const std::string& id, std::string& currentText)
{
bool result = false;
ImVec2 center = ImGui::GetMainViewport()->GetCenter();
ImGui::SetNextWindowPos(center, ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
if (ImGui::BeginPopupModal(id.c_str(), NULL, ImGuiWindowFlags_AlwaysAutoResize))
{
bool isSanitized = true;
char buffer[256];
memset(buffer, 0, sizeof(buffer));
std::strncpy(buffer, currentText.c_str(), sizeof(buffer));
if (ImGui::InputText("##label", buffer, sizeof(buffer)))
{
currentText = std::string(buffer);
}
// returns false when there is a match, quirky
if (!regex_match(buffer, std::regex("[^ \\ / :*? \"<>|]+")))
{
isSanitized = false;
}
if (currentText.empty())
{
ImGui::TextColored(ImVec4(0.76, 0.45, 0.47, 1.0), "A file name can't be empty.");
}
else if (!isSanitized)
{
ImGui::TextColored(ImVec4(0.76, 0.45, 0.47, 1.0), "A file name can't contain any of the following characters: \\/:*?\"<>|");
}
ImGui::Separator();
if (ImGui::Button("OK", ImVec2(120, 0)))
{
if (isSanitized)
{
result = true;
ImGui::CloseCurrentPopup();
}
}
ImGui::SetItemDefaultFocus();
ImGui::SameLine();
if (ImGui::Button("Cancel", ImVec2(120, 0))) { ImGui::CloseCurrentPopup(); }
ImGui::EndPopup();
}
return result;
}

View File

@@ -4,6 +4,7 @@
class PopupHelper
{
public:
static void Confirmation(const std::string& id);
static bool DefineDialog(const std::string& id, const std::string& text);
static void OpenPopup(const std::string& id);
static bool DefineConfirmationDialog(const std::string& id, const std::string& text);
static bool PopupHelper::DefineTextDialog(const std::string& id, std::string& currentText);
};

View File

@@ -16,18 +16,18 @@ public:
for (int i = 0; i < numBus; i++)
{
const std::string busName = "Bus " + std::to_string(i);
ImGui::BeginTable(busName.c_str(), 1, 0, ImVec2(300, ImGui::GetContentRegionAvail().y));
ImGui::TableSetupColumn(busName.c_str(), 0, 1.0f);
ImGui::TableNextColumn ();
ImGui::TableHeader(busName.c_str());
ImGui::TableNextColumn();
const float height = ImGui::GetContentRegionAvail().y - 50;
const std::string id = "##Volume" + std::to_string(i);
ImGui::VSliderFloat(id.c_str(), ImVec2(50, height), &dummyVolume, -60.0f, 6.0f, "%.3dB", ImGuiSliderFlags_Logarithmic);
ImGui::TableNextColumn();
ImGui::EndTable();
//ImGui::BeginTable(busName.c_str(), 1, 0, ImVec2(300, ImGui::GetContentRegionAvail().y));
//
//ImGui::TableSetupColumn(busName.c_str(), 0, 1.0f);
//ImGui::TableNextColumn ();
//ImGui::TableHeader(busName.c_str());
//ImGui::TableNextColumn();
//
//const float height = ImGui::GetContentRegionAvail().y - 50;
//const std::string id = "##Volume" + std::to_string(i);
//ImGui::VSliderFloat(id.c_str(), ImVec2(50, height), &dummyVolume, -60.0f, 6.0f, "%.3dB", ImGuiSliderFlags_Logarithmic);
//ImGui::TableNextColumn();
//ImGui::EndTable();
}
}

View File

@@ -41,6 +41,8 @@
#include "../Misc/InterfaceFonts.h"
#include "WelcomeWindow.h"
#include "LoadingSplash.h"
#include "src/Rendering/SceneRenderer.h"
#include <dependencies/glfw/include/GLFW/glfw3.h>
#include <src/Rendering/Buffers/Framebuffer.h>
@@ -56,7 +58,6 @@ namespace Nuake {
filesystem = new FileSystemUI(this);
_WelcomeWindow = new WelcomeWindow(this);
_audioWindow = new AudioWindow();
m_EntitySelectionFramebuffer = CreateRef<FrameBuffer>(false, Vector2(1280, 720));
}
void EditorInterface::Init()
@@ -64,8 +65,8 @@ namespace Nuake {
ImGuiWindowFlags window_flags = ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoDocking;
static ImGuiDockNodeFlags dockspace_flags = ImGuiDockNodeFlags_AutoHideTabBar;
ImGuiViewport* viewport = ImGui::GetMainViewport();
ImGui::SetNextWindowPos(viewport->GetWorkPos());
ImGui::SetNextWindowSize(viewport->GetWorkSize());
ImGui::SetNextWindowPos(viewport->Pos);
ImGui::SetNextWindowSize(viewport->Size);
ImGui::SetNextWindowViewport(viewport->ID);
ImGuiID dockspace_id = ImGui::GetID("MyDockSpace");
@@ -86,7 +87,7 @@ namespace Nuake {
Overlay();
ImGuizmo::BeginFrame();
float availWidth = ImGui::GetContentRegionAvailWidth();
float availWidth = ImGui::GetContentRegionAvail().x;
float windowWidth = ImGui::GetWindowWidth();
float used = windowWidth - availWidth;
@@ -112,7 +113,7 @@ namespace Nuake {
ImGui::SameLine();
ImGui::Dummy(ImVec2(ImGui::GetContentRegionAvailWidth() - 120, 30));
ImGui::Dummy(ImVec2(ImGui::GetContentRegionAvail().x - 120, 30));
ImGui::SameLine();
@@ -124,7 +125,7 @@ namespace Nuake {
ImGui::BeginChild("FPS", ImVec2(60, 30), false);
std::string text = std::to_string(fps) + " fps";
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + ImGui::GetContentRegionAvailWidth() / 1.25 - ImGui::CalcTextSize(text.c_str()).x
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + ImGui::GetContentRegionAvail().x / 1.25 - ImGui::CalcTextSize(text.c_str()).x
- ImGui::GetScrollX() - 2 * ImGui::GetStyle().ItemSpacing.x);
ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 15 - (ImGui::CalcTextSize(text.c_str()).y) / 2.0);
ImGui::Text(text.c_str());
@@ -136,7 +137,7 @@ namespace Nuake {
out.precision(2);
out << std::fixed << frameTime;
text = out.str() + " ms";
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + ImGui::GetContentRegionAvailWidth() / 1.25 - ImGui::CalcTextSize(text.c_str()).x
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + ImGui::GetContentRegionAvail().x / 1.25 - ImGui::CalcTextSize(text.c_str()).x
- ImGui::GetScrollX() - 2 * ImGui::GetStyle().ItemSpacing.x);
ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 15 - (ImGui::CalcTextSize(text.c_str()).y) / 2.0);
ImGui::Text(text.c_str());
@@ -244,13 +245,17 @@ namespace Nuake {
}
}
m_IsViewportFocused = ImGui::IsWindowFocused();
if (m_IsHoveringViewport && Input::IsMouseButtonPressed(GLFW_MOUSE_BUTTON_2) && !ImGuizmo::IsUsing())
if (m_IsHoveringViewport && !m_IsViewportFocused && Input::IsMouseButtonPressed(GLFW_MOUSE_BUTTON_2))
{
ImGui::FocusWindow(ImGui::GetCurrentWindow());
}
m_IsViewportFocused = ImGui::IsWindowFocused();
if (m_IsHoveringViewport && Input::IsMouseButtonPressed(GLFW_MOUSE_BUTTON_1) && !ImGuizmo::IsUsing())
{
const auto windowPosNuake = Vector2(windowPos.x, windowPos.y);
auto& gbuffer = Engine::GetCurrentScene()->mSceneRenderer->GetGBuffer();
auto& gbuffer = Engine::GetCurrentScene()->m_SceneRenderer->GetGBuffer();
auto pixelPos = Input::GetMousePosition() - windowPosNuake;
pixelPos.y = gbuffer.GetSize().y - pixelPos.y; // imgui coords are inverted on the Y axis
@@ -258,7 +263,11 @@ namespace Nuake {
if (const int result = gbuffer.ReadPixel(3, pixelPos); result > 0)
{
Selection = EditorSelection(Entity{ (entt::entity)(result - 1), Engine::GetCurrentScene().get()});
auto& ent = Entity{ (entt::entity)(result - 1), Engine::GetCurrentScene().get() };
if (ent.IsValid())
{
Selection = EditorSelection(ent);
}
}
else
{
@@ -403,8 +412,18 @@ namespace Nuake {
{
Ref<Prefab> newPrefab = Prefab::CreatePrefabFromEntity(Selection.Entity);
std::string savePath = FileDialog::SaveFile("*.prefab");
newPrefab->SaveAs(savePath);
Selection.Entity.AddComponent<PrefabComponent>().PrefabInstance = newPrefab;
if (!String::EndsWith(savePath, ".prefab"))
{
savePath += ".prefab";
}
if (!savePath.empty())
{
newPrefab->SaveAs(savePath);
Selection.Entity.AddComponent<PrefabComponent>().PrefabInstance = newPrefab;
FileSystem::Scan();
FileSystemUI::m_CurrentDirectory = FileSystem::RootDirectory;
}
}
ImGui::EndPopup();
}
@@ -446,7 +465,7 @@ namespace Nuake {
if (ImGui::Begin("Environnement"))
{
BEGIN_COLLAPSE_HEADER(SKY);
if (ImGui::BeginTable("EnvTable", 3, ImGuiTableFlags_BordersInner))
if (ImGui::BeginTable("EnvTable", 3, ImGuiTableFlags_BordersInner | ImGuiTableFlags_SizingStretchProp))
{
ImGui::TableSetupColumn("name", 0, 0.3);
ImGui::TableSetupColumn("set", 0, 0.6);
@@ -611,7 +630,7 @@ namespace Nuake {
END_COLLAPSE_HEADER()
BEGIN_COLLAPSE_HEADER(BLOOM)
if (ImGui::BeginTable("BloomTable", 3, ImGuiTableFlags_BordersInner))
if (ImGui::BeginTable("BloomTable", 3, ImGuiTableFlags_BordersInner | ImGuiTableFlags_SizingStretchProp))
{
ImGui::TableSetupColumn("name", 0, 0.3);
ImGui::TableSetupColumn("set", 0, 0.6);
@@ -673,7 +692,7 @@ namespace Nuake {
END_COLLAPSE_HEADER()
BEGIN_COLLAPSE_HEADER(VOLUMETRIC)
if (ImGui::BeginTable("EnvTable", 3, ImGuiTableFlags_BordersInner))
if (ImGui::BeginTable("EnvTable", 3, ImGuiTableFlags_BordersInner | ImGuiTableFlags_SizingStretchProp))
{
ImGui::TableSetupColumn("name", 0, 0.3);
ImGui::TableSetupColumn("set", 0, 0.6);
@@ -737,7 +756,7 @@ namespace Nuake {
END_COLLAPSE_HEADER()
BEGIN_COLLAPSE_HEADER(SSAO)
if (ImGui::BeginTable("EnvTable", 3, ImGuiTableFlags_BordersInner))
if (ImGui::BeginTable("EnvTable", 3, ImGuiTableFlags_BordersInner | ImGuiTableFlags_SizingStretchProp))
{
ImGui::TableSetupColumn("name", 0, 0.3);
ImGui::TableSetupColumn("set", 0, 0.6);
@@ -828,7 +847,7 @@ namespace Nuake {
END_COLLAPSE_HEADER()
BEGIN_COLLAPSE_HEADER(SSR)
if (ImGui::BeginTable("EnvTable", 3, ImGuiTableFlags_BordersInner))
if (ImGui::BeginTable("EnvTable", 3, ImGuiTableFlags_BordersInner | ImGuiTableFlags_SizingStretchProp))
{
ImGui::TableSetupColumn("name", 0, 0.3);
ImGui::TableSetupColumn("set", 0, 0.6);
@@ -836,7 +855,7 @@ namespace Nuake {
ImGui::TableNextColumn();
SSR* ssr = scene->mSceneRenderer->mSSR.get();
SSR* ssr = scene->m_SceneRenderer->mSSR.get();
{
// Title
ImGui::Text("SSR RayStep");
@@ -1000,7 +1019,7 @@ namespace Nuake {
if (ImGui::Begin(title.c_str()))
{
// Buttons to add and remove entity.
if(ImGui::BeginChild("Buttons", ImVec2(ImGui::GetContentRegionAvailWidth(), 30), false))
if(ImGui::BeginChild("Buttons", ImVec2(ImGui::GetContentRegionAvail().x, 30), false))
{
// Add entity.
if (ImGui::Button(ICON_FA_PLUS, ImVec2(30, 30)))
@@ -1020,10 +1039,10 @@ namespace Nuake {
ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(26.f / 255.0f, 26.f / 255.0f, 26.f / 255.0f, 1));
if (ImGui::BeginChild("Scene tree", ImGui::GetContentRegionAvail(), false))
{
if (ImGui::BeginTable("entity_table", 2, ImGuiTableFlags_BordersInnerV | ImGuiTableFlags_NoBordersInBody))
if (ImGui::BeginTable("entity_table", 2, ImGuiTableFlags_BordersInnerV | ImGuiTableFlags_NoBordersInBody | ImGuiTableFlags_SizingStretchProp))
{
std::string icon = ICON_FA_EYE;
ImGui::TableSetupColumn((" " + icon).c_str(), ImGuiTableColumnFlags_NoResize | ImGuiTableColumnFlags_IndentDisable | ImGuiTableColumnFlags_WidthFixed, 16);
ImGui::TableSetupColumn((" " + icon).c_str(), ImGuiTableColumnFlags_NoResize | ImGuiTableColumnFlags_IndentDisable | ImGuiTableColumnFlags_WidthFixed, 32);
ImGui::TableSetupColumn("Label", ImGuiTableColumnFlags_NoResize | ImGuiTableColumnFlags_IndentEnable);
ImGui::TableHeadersRow();
ImGui::TableNextRow();
@@ -1364,7 +1383,7 @@ namespace Nuake {
Selection = EditorSelection();
}
if (ImGui::MenuItem("Open...", "CTRL+O"))
if (ImGui::MenuItem("Open..."))
{
OpenProject();
@@ -1395,7 +1414,7 @@ namespace Nuake {
Engine::LoadScene(Scene::New());
Selection = EditorSelection();
}
if (ImGui::MenuItem("Open scene...", "CTRL+SHIFT+O"))
if (ImGui::MenuItem("Open scene...", "CTRL+O"))
{
OpenScene();
Selection = EditorSelection();
@@ -1496,10 +1515,66 @@ namespace Nuake {
}
}
bool isLoadingProject = false;
bool isLoadingProjectQueue = false;
int frameCount = 2;
void EditorInterface::Draw()
{
Init();
if (isLoadingProjectQueue)
{
_WelcomeWindow->LoadQueuedProject();
isLoadingProjectQueue = false;
auto& window = Window::Get();
window->SetDecorated(true);
window->SetSize({ 1900, 1000 });
window->Center();
frameCount = 0;
return;
}
// Shortcuts
if(ImGui::IsKeyDown(ImGuiKey_LeftCtrl))
{
if(ImGui::IsKeyPressed(ImGuiKey_S))
{
Engine::GetProject()->Save();
Engine::GetCurrentScene()->Save();
Selection = EditorSelection();
}
else if(ImGui::IsKeyPressed(ImGuiKey_O))
{
OpenScene();
Selection = EditorSelection();
}
else if(ImGui::IsKeyDown(ImGuiKey_LeftShift) && ImGui::IsKeyPressed(ImGuiKey_S))
{
std::string savePath = FileDialog::SaveFile("*.project");
Engine::GetProject()->SaveAs(savePath);
Selection = EditorSelection();
}
}
if (_WelcomeWindow->IsProjectQueued() && frameCount > 0)
{
// draw splash
LoadingSplash::Get().Draw();
frameCount--;
if (frameCount == 0)
{
isLoadingProjectQueue = true;
}
return;
}
if (!Engine::GetProject())
{
_WelcomeWindow->Draw();

View File

@@ -35,7 +35,6 @@ namespace Nuake
ImGuizmo::MODE CurrentMode = ImGuizmo::WORLD;
Ref<Material> m_SelectedMaterial;
Ref<Directory> m_CurrentDirectory;
Ref<FrameBuffer> m_EntitySelectionFramebuffer;
bool m_IsMaterialSelected = false;
public:

View File

@@ -1,3 +1,5 @@
#define IMGUI_DEFINE_MATH_OPERATORS
#include "EditorSelectionPanel.h"
#include "../Misc/ImGuiTextHelper.h"
#include <src/Scene/Components/Components.h>
@@ -9,16 +11,11 @@
#include <Engine.h>
#include "src/Scene/Components/WrenScriptComponent.h"
#include "src/Scene/Components/ParticleEmitterComponent.h"
EditorSelectionPanel::EditorSelectionPanel()
{
mTransformPanel = TransformPanel();
mLightPanel = LightPanel();
mScriptPanel = ScriptPanel();
mQuakeMapPanel = QuakeMapPanel();
mCameraPanel = CameraPanel();
mRigidbodyPanel = RigidbodyPanel();
mBoxColliderPanel = BoxColliderPanel();
}
void EditorSelectionPanel::ResolveFile(Ref<Nuake::File> file)
@@ -92,12 +89,19 @@ void EditorSelectionPanel::DrawNone()
void EditorSelectionPanel::DrawEntity(Nuake::Entity entity)
{
if (!entity.IsValid())
{
return;
}
DrawAddComponentMenu(entity);
// Draw each component properties panels.
mTransformPanel.Draw(entity);
mLightPanel.Draw(entity);
mScriptPanel.Draw(entity);
mParticleEmitterPanel.Draw(entity);
mSpritePanel.Draw(entity);
mMeshPanel.Draw(entity);
mQuakeMapPanel.Draw(entity);
mCameraPanel.Draw(entity);
@@ -127,6 +131,8 @@ void EditorSelectionPanel::DrawAddComponentMenu(Nuake::Entity entity)
MenuItemComponent("Camera", Nuake::CameraComponent)
MenuItemComponent("Light", Nuake::LightComponent)
MenuItemComponent("Model", Nuake::ModelComponent)
MenuItemComponent("Sprite", Nuake::SpriteComponent)
MenuItemComponent("Particle Emitter", Nuake::ParticleEmitterComponent)
ImGui::Separator();
MenuItemComponent("Character Controller", Nuake::CharacterControllerComponent)
MenuItemComponent("Rigid body", Nuake::RigidBodyComponent)
@@ -243,7 +249,7 @@ void EditorSelectionPanel::DrawMaterialPanel(Ref<Nuake::Material> material)
textureID = TextureManager::Get()->GetTexture("default")->GetID();
}
if (ImGui::ImageButtonEx(ImGui::GetCurrentWindow()->GetID("#image1"), (void*)textureID, ImVec2(80, 80), ImVec2(0, 1), ImVec2(1, 0), ImVec2(2, 2), ImVec4(0, 0, 0, 0), ImVec4(1, 1, 1, 1)))
if (ImGui::ImageButtonEx(ImGui::GetCurrentWindow()->GetID("#image1"), (void*)textureID, ImVec2(80, 80), ImVec2(0, 1), ImVec2(1, 0), ImVec4(0, 0, 0, 0), ImVec4(1, 1, 1, 1)))
{
std::string texture = FileDialog::OpenFile("*.png | *.jpg");
if (texture != "")
@@ -281,7 +287,7 @@ void EditorSelectionPanel::DrawMaterialPanel(Ref<Nuake::Material> material)
textureID = TextureManager::Get()->GetTexture("default")->GetID();
}
if (ImGui::ImageButtonEx(ImGui::GetCurrentWindow()->GetID("#image3"), (void*)textureID, ImVec2(80, 80), ImVec2(0, 1), ImVec2(1, 0), ImVec2(2, 2), ImVec4(0, 0, 0, 1), ImVec4(1, 1, 1, 1)))
if (ImGui::ImageButtonEx(ImGui::GetCurrentWindow()->GetID("#image3"), (void*)textureID, ImVec2(80, 80), ImVec2(0, 1), ImVec2(1, 0), ImVec4(0, 0, 0, 1), ImVec4(1, 1, 1, 1)))
{
std::string texture = FileDialog::OpenFile("*.png | *.jpg");
if (texture != "")
@@ -316,7 +322,7 @@ void EditorSelectionPanel::DrawMaterialPanel(Ref<Nuake::Material> material)
textureID = TextureManager::Get()->GetTexture("default")->GetID();
}
if (ImGui::ImageButtonEx(ImGui::GetCurrentWindow()->GetID("#image2"), (void*)textureID, ImVec2(80, 80), ImVec2(0, 1), ImVec2(1, 0), ImVec2(2, 2), ImVec4(1, 1, 1, 1), ImVec4(1, 1, 1, 1)))
if (ImGui::ImageButtonEx(ImGui::GetCurrentWindow()->GetID("#image2"), (void*)textureID, ImVec2(80, 80), ImVec2(0, 1), ImVec2(1, 0), ImVec4(1, 1, 1, 1), ImVec4(1, 1, 1, 1)))
{
std::string texture = FileDialog::OpenFile("Image files (*.png) | *.png | Image files (*.jpg) | *.jpg");
if (texture != "")
@@ -351,7 +357,7 @@ void EditorSelectionPanel::DrawMaterialPanel(Ref<Nuake::Material> material)
textureID = TextureManager::Get()->GetTexture("default")->GetID();
}
if (ImGui::ImageButtonEx(ImGui::GetCurrentWindow()->GetID("#image4"), (void*)textureID, ImVec2(80, 80), ImVec2(0, 1), ImVec2(1, 0), ImVec2(2, 2), ImVec4(0, 0, 0, 1), ImVec4(1, 1, 1, 1)))
if (ImGui::ImageButtonEx(ImGui::GetCurrentWindow()->GetID("#image4"), (void*)textureID, ImVec2(80, 80), ImVec2(0, 1), ImVec2(1, 0), ImVec4(0, 0, 0, 1), ImVec4(1, 1, 1, 1)))
{
std::string texture = FileDialog::OpenFile("*.png | *.jpg");
if (texture != "")
@@ -389,7 +395,7 @@ void EditorSelectionPanel::DrawMaterialPanel(Ref<Nuake::Material> material)
textureID = TextureManager::Get()->GetTexture("default")->GetID();
}
if (ImGui::ImageButtonEx(ImGui::GetCurrentWindow()->GetID("#image5"), (void*)textureID, ImVec2(80, 80), ImVec2(0, 1), ImVec2(1, 0), ImVec2(2, 2), ImVec4(0, 0, 0, 0), ImVec4(1, 1, 1, 1)))
if (ImGui::ImageButtonEx(ImGui::GetCurrentWindow()->GetID("#image5"), (void*)textureID, ImVec2(80, 80), ImVec2(0, 1), ImVec2(1, 0), ImVec4(0, 0, 0, 0), ImVec4(1, 1, 1, 1)))
{
std::string texture = FileDialog::OpenFile("*.png | *.jpg");
if (texture != "")

View File

@@ -18,8 +18,12 @@
#include "../ComponentsPanel/SphereColliderPanel.h"
#include "../ComponentsPanel/MeshColliderPanel.h"
#include "../ComponentsPanel/CharacterControllerPanel.h"
#include "../ComponentsPanel/SpritePanel.h"
#include "../ComponentsPanel/ParticleEmitterPanel.h"
class EditorSelectionPanel {
class EditorSelectionPanel
{
private:
TransformPanel mTransformPanel;
LightPanel mLightPanel;
@@ -33,8 +37,9 @@ private:
MeshColliderPanel mMeshColliderPanel;
CapsuleColliderPanel mCapsuleColliderPanel;
CylinderColliderPanel mCylinderColliderPanel;
SpritePanel mSpritePanel;
CharacterControllerPanel mCharacterControllerPanel;
ParticleEmitterPanel mParticleEmitterPanel;
Ref<Nuake::File> currentFile;
Ref<Nuake::Resource> selectedResource;

View File

@@ -1,3 +1,4 @@
#include "FileSystemUI.h"
#include <src/Vendors/imgui/imgui.h>
@@ -30,6 +31,9 @@ namespace Nuake
{
}
std::string renameTempValue = "";
void FileSystemUI::EditorInterfaceDrawFiletree(Ref<Directory> dir)
{
ImGuiTreeNodeFlags base_flags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_SpanFullWidth | ImGuiTreeNodeFlags_FramePadding;
@@ -55,7 +59,7 @@ namespace Nuake
}
}
void FileSystemUI::DrawDirectory(Ref<Directory> directory)
void FileSystemUI::DrawDirectory(Ref<Directory> directory, uint32_t drawId)
{
ImGui::PushFont(FontManager::GetFont(Icons));
const char* icon = ICON_FA_FOLDER;
@@ -65,6 +69,98 @@ namespace Nuake
m_CurrentDirectory = directory;
}
const std::string hoverMenuId = std::string("item_hover_menu") + std::to_string(drawId);
if (ImGui::IsItemHovered() && ImGui::IsMouseReleased(1))
{
ImGui::OpenPopup(hoverMenuId.c_str());
m_hasClickedOnFile = true;
}
const std::string renameId = "Rename" + std::string("##") + hoverMenuId;
bool shouldRename = false;
const std::string deleteId = "Delete" + std::string("##") + hoverMenuId;
bool shouldDelete = false;
if (ImGui::BeginPopup(hoverMenuId.c_str()))
{
if (ImGui::MenuItem("Open"))
{
m_CurrentDirectory = directory;
}
ImGui::Separator();
if (ImGui::BeginMenu("Copy"))
{
if (ImGui::MenuItem("Full Path"))
{
OS::CopyToClipboard(directory->fullPath);
}
if (ImGui::MenuItem("Directory Name"))
{
OS::CopyToClipboard(String::Split(directory->name, '/')[0]);
}
ImGui::EndPopup();
}
if (ImGui::MenuItem("Delete"))
{
shouldDelete = true;
}
if (ImGui::MenuItem("Rename"))
{
shouldRename = true;
}
ImGui::Separator();
if (ImGui::MenuItem("Show in File Explorer"))
{
OS::OpenIn(directory->fullPath);
}
ImGui::EndPopup();
}
// Rename Popup
if (shouldRename)
{
renameTempValue = directory->name;
PopupHelper::OpenPopup(renameId);
}
if (PopupHelper::DefineTextDialog(renameId, renameTempValue))
{
if (OS::RenameDirectory(directory, renameTempValue) != 0)
{
Logger::Log("Cannot rename directory: " + renameTempValue, "editor", CRITICAL);
}
RefreshFileBrowser();
renameTempValue = "";
}
// Delete Popup
if(shouldDelete)
{
PopupHelper::OpenPopup(deleteId);
}
if(PopupHelper::DefineConfirmationDialog(deleteId, " Are you sure you want to delete the folder and all its children?\n This action cannot be undone, and all data within the folder \n will be permanently lost."))
{
if (FileSystem::DeleteFolder(directory->fullPath) != 0)
{
Logger::Log("Failed to remove directory: " + directory->name, "editor", CRITICAL);
}
RefreshFileBrowser();
}
ImGui::Text(directory->name.c_str());
ImGui::PopFont();
}
@@ -115,28 +211,42 @@ namespace Nuake
{
Editor->Selection = EditorSelection(file);
}
}
if (ImGui::BeginDragDropSource())
if (ImGui::BeginDragDropSource())
{
char pathBuffer[256];
std::strncpy(pathBuffer, file->GetAbsolutePath().c_str(), sizeof(pathBuffer));
std::string dragType;
if (fileExtension == ".wren")
{
dragType = "_Script";
}
else if (fileExtension == ".map")
{
dragType = "_Map";
}
else if (fileExtension == ".obj" || fileExtension == ".mdl" || fileExtension == ".gltf" || fileExtension == ".md3" || fileExtension == ".fbx")
{
dragType = "_Model";
}
else if (fileExtension == ".interface")
{
dragType = "_Interface";
}
else if (fileExtension == ".prefab")
{
dragType = "_Prefab";
}
else if (fileExtension == ".png" || fileExtension == ".jpg")
{
dragType = "_Image";
}
ImGui::SetDragDropPayload(dragType.c_str(), (void*)(pathBuffer), sizeof(pathBuffer));
ImGui::Text(file->GetName().c_str());
ImGui::EndDragDropSource();
}
}
const std::string hoverMenuId = std::string("item_hover_menu") + std::to_string(drawId);
if (ImGui::IsItemHovered() && ImGui::IsMouseReleased(1))
@@ -144,52 +254,100 @@ namespace Nuake
ImGui::OpenPopup(hoverMenuId.c_str());
m_hasClickedOnFile = true;
}
const std::string openSceneId = "Open Scene" + std::string("##") + hoverMenuId;
bool shouldOpenScene = false;
const std::string renameId = "Rename" + std::string("##") + hoverMenuId;
bool shouldRename = false;
const std::string deleteId = "Delete" + std::string("##") + hoverMenuId;
bool shouldDelete = false;
if (ImGui::BeginPopup(hoverMenuId.c_str()))
{
if (ImGui::MenuItem("Show in File Explorer"))
if (file->GetExtension() != ".scene")
{
OS::ShowInFileExplorer(file->GetAbsolutePath());
}
if(file->GetExtension() == ".wren")
{
ImGui::Separator();
if(ImGui::MenuItem("Open..."))
if (ImGui::MenuItem("Open in Editor"))
{
OS::OpenIn(file->GetAbsolutePath());
}
}
if(file->GetExtension() != ".project")
else
{
if (ImGui::MenuItem("Load Scene"))
{
shouldOpenScene = true;
}
}
ImGui::Separator();
if (ImGui::BeginMenu("Copy"))
{
if (ImGui::MenuItem("Full Path"))
{
OS::CopyToClipboard(file->GetAbsolutePath());
}
if (ImGui::MenuItem("File Name"))
{
OS::CopyToClipboard(file->GetName());
}
ImGui::EndPopup();
}
if (file->GetExtension() != ".project")
{
ImGui::Separator();
if (ImGui::MenuItem("Delete"))
{
if(FileSystem::RemoveFile(file->GetAbsolutePath()) != 0)
{
Logger::Log("Failed to remove file: " + file->GetRelativePath(), "editor", CRITICAL);
}
RefreshFileBrowser();
shouldDelete = true;
}
}
else
{
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1, 1, 1, 0.2f));
ImGui::MenuItem("Delete");
ImGui::PopStyleColor();
if (ImGui::IsItemHovered())
{
ImGui::BeginTooltip();
ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f);
ImGui::TextUnformatted("The file you're trying to delete is currently loaded by the game engine.");
ImGui::PopTextWrapPos();
ImGui::EndTooltip();
}
}
if (ImGui::MenuItem("Rename"))
{
shouldRename = true;
}
ImGui::Separator();
if (ImGui::MenuItem("Show in File Explorer"))
{
OS::ShowInFileExplorer(file->GetAbsolutePath());
}
ImGui::EndPopup();
}
const std::string openScene = "Open Scene" + std::string("##") + hoverMenuId;
if (ImGui::IsItemHovered() && ImGui::IsMouseDoubleClicked(0))
{
if (file->GetExtension() == ".scene")
{
PopupHelper::Confirmation(openScene);
}
shouldOpenScene = file->GetExtension() == ".scene";
}
if (PopupHelper::DefineDialog(openScene, "Open the scene? \n Changes will not be saved."))
// Open Scene Popup
if (shouldOpenScene)
{
PopupHelper::OpenPopup(openSceneId);
}
if (PopupHelper::DefineConfirmationDialog(openSceneId, " Open the scene? \n Changes will not be saved."))
{
Ref<Scene> scene = Scene::New();
const std::string projectPath = file->GetAbsolutePath();
@@ -203,6 +361,41 @@ namespace Nuake
Engine::LoadScene(scene);
}
// Rename Popup
if (shouldRename)
{
renameTempValue = file->GetName();
PopupHelper::OpenPopup(renameId);
}
if (PopupHelper::DefineTextDialog(renameId, renameTempValue))
{
if(OS::RenameFile(file, renameTempValue) != 0)
{
Logger::Log("Cannot rename file: " + renameTempValue, "editor", CRITICAL);
}
RefreshFileBrowser();
renameTempValue = "";
}
// Delete Popup
if(shouldDelete)
{
PopupHelper::OpenPopup(deleteId);
}
if(PopupHelper::DefineConfirmationDialog(deleteId, " Are you sure you want to delete the file?\n This action cannot be undone, and all data \n will be permanently lost."))
{
if (FileSystem::DeleteFileFromPath(file->GetAbsolutePath()) != 0)
{
Logger::Log("Failed to remove file: " + file->GetRelativePath(), "editor", CRITICAL);
}
RefreshFileBrowser();
}
ImGui::Text(file->GetName().c_str());
ImGui::PopFont();
}
@@ -247,7 +440,7 @@ namespace Nuake
path += ".material";
}
if (path != "")
if (!path.empty())
{
Ref<Material> material = CreateRef<Material>();
material->IsEmbedded = false;
@@ -353,8 +546,6 @@ namespace Nuake
ImGui::EndChild();
ImGui::SameLine();
avail = ImGui::GetContentRegionAvail();
std::vector<Ref<Directory>> paths = std::vector<Ref<Directory>>();
Ref<Directory> currentParent = m_CurrentDirectory;
@@ -402,12 +593,13 @@ namespace Nuake
}
const uint32_t numButtonAfterPathBrowser = 2;
const uint32_t searchBarSize = 6;
ImGui::SameLine();
ImGui::PushStyleColor(ImGuiCol_ChildBg, colors[ImGuiCol_TitleBgCollapsed]);
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0));
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(4, 4));
ImGui::BeginChild("pathBrowser", ImVec2(ImGui::GetContentRegionAvailWidth() - (numButtonAfterPathBrowser * buttonWidth) - 4.0, 24));
ImGui::BeginChild("pathBrowser", ImVec2((ImGui::GetContentRegionAvail().x - (numButtonAfterPathBrowser * buttonWidth * searchBarSize)) - 4.0, 24));
for (int i = paths.size() - 1; i > 0; i--)
{
if (i != paths.size())
@@ -431,13 +623,23 @@ namespace Nuake
ImGui::SameLine();
ImGui::Text("/");
}
ImGui::EndChild();
ImGui::PopStyleVar();
ImGui::PopStyleVar();
ImGui::PopStyleColor();
ImGui::SameLine();
ImGui::BeginChild("searchBar", ImVec2(ImGui::GetContentRegionAvail().x - (numButtonAfterPathBrowser * buttonWidth), 24));
char buffer[256];
memset(buffer, 0, sizeof(buffer));
std::strncpy(buffer, m_searchKeyWord.c_str(), sizeof(buffer));
if (ImGui::InputTextEx("##Search", "Asset search & filter ..", buffer, sizeof(buffer), ImVec2(ImGui::GetContentRegionAvail().x, 24), ImGuiInputTextFlags_EscapeClearsAll))
{
m_searchKeyWord = std::string(buffer);
}
ImGui::EndChild();
ImGui::SameLine();
@@ -454,12 +656,13 @@ namespace Nuake
}
ImGui::PopStyleColor(); // Button color
ImGui::SameLine();
}
ImGui::EndChild();
ImDrawList* drawList = ImGui::GetWindowDrawList();
ImGui::GetWindowDrawList()->AddLine(ImVec2(ImGui::GetCursorPosX(), ImGui::GetCursorPosY()), ImVec2(ImGui::GetContentRegionAvailWidth(), ImGui::GetCursorPosY()), IM_COL32(255, 0, 0, 255), 1.0f);
ImGui::GetWindowDrawList()->AddLine(ImVec2(ImGui::GetCursorPosX(), ImGui::GetCursorPosY()), ImVec2(ImGui::GetContentRegionAvail().x, ImGui::GetCursorPosY()), IM_COL32(255, 0, 0, 255), 1.0f);
ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, ImVec2(0, 0));
avail = ImGui::GetContentRegionAvail();
@@ -489,13 +692,16 @@ namespace Nuake
{
for (Ref<Directory>& d : m_CurrentDirectory->Directories)
{
if (i + 1 % amount != 0)
ImGui::TableNextColumn();
else
ImGui::TableNextRow();
if(String::Sanitize(d->name).find(String::Sanitize(m_searchKeyWord)) != std::string::npos)
{
if (i + 1 % amount != 0)
ImGui::TableNextColumn();
else
ImGui::TableNextRow();
DrawDirectory(d);
i++;
DrawDirectory(d, i);
i++;
}
}
}
@@ -503,13 +709,16 @@ namespace Nuake
{
for (auto f : m_CurrentDirectory->Files)
{
if (i - 1 % amount != 0 || i == 1)
ImGui::TableNextColumn();
else
ImGui::TableNextRow();
if(String::Sanitize(f->GetName()).find(String::Sanitize(m_searchKeyWord)) != std::string::npos)
{
if (i - 1 % amount != 0 || i == 1)
ImGui::TableNextColumn();
else
ImGui::TableNextRow();
DrawFile(f, i);
i++;
DrawFile(f, i);
i++;
}
}
}

View File

@@ -12,6 +12,7 @@ namespace Nuake {
public:
static Ref<Directory> m_CurrentDirectory;
bool m_hasClickedOnFile;
std::string m_searchKeyWord;
FileSystemUI(EditorInterface* editor)
{
@@ -24,7 +25,7 @@ namespace Nuake {
void DrawDirectoryContent();
void DrawFiletree();
void EditorInterfaceDrawFiletree(Ref<Directory> dir);
void DrawDirectory(Ref<Directory> directory);
void DrawDirectory(Ref<Directory> directory, uint32_t drawId);
bool EntityContainsItself(Entity source, Entity target);
void DrawFile(Ref<File> file, uint32_t drawId);
void DrawDirectoryExplorer();

View File

@@ -0,0 +1,51 @@
#include "LoadingSplash.h"
#include "../Misc/InterfaceFonts.h"
#include <src/Core/Maths.h>
#include "src/Window.h"
#include <src/Vendors/imgui/imgui.h>
#include <dependencies/glfw/include/GLFW/glfw3.h>
#include <src/Rendering/Textures/TextureManager.h>
LoadingSplash::LoadingSplash()
{
_NuakeLogo = Nuake::TextureManager::Get()->GetTexture(NUAKE_LOGO_PATH);
Nuake::Window::Get()->SetDecorated(false);
Nuake::Window::Get()->SetSize({ 640, 480 });
Nuake::Window::Get()->Center();
}
void LoadingSplash::Draw()
{
using namespace Nuake;
// Make viewport fullscreen
ImGuiViewport* viewport = ImGui::GetMainViewport();
ImGui::SetNextWindowPos(viewport->Pos);
ImGui::SetNextWindowSize(viewport->Size);
ImGui::SetNextWindowViewport(viewport->ID);
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(32.0f, 32.0f));
ImGui::Begin("Welcome Screen", 0, ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoResize);
{
// Draw Nuake logo
{
const Vector2 logoSize = _NuakeLogo->GetSize();
const ImVec2 imguiSize = ImVec2(logoSize.x, logoSize.y);
ImGui::Image((ImTextureID)_NuakeLogo->GetID(), imguiSize, ImVec2(0, 1), ImVec2(1, 0));
}
ImGui::Text("LOADING SCENE...");
}
ImGui::End();
ImGui::PopStyleVar();
ImGui::PopStyleVar();
}

View File

@@ -0,0 +1,29 @@
#pragma once
#include <src/Core/Core.h>
#include <src/Rendering/Textures/Texture.h>
#include <string>
namespace Nuake
{
class Texture;
}
class LoadingSplash
{
private:
const std::string NUAKE_LOGO_PATH = "resources/Images/logo_white.png";
Ref<Nuake::Texture> _NuakeLogo;
public:
static LoadingSplash& LoadingSplash::Get()
{
static LoadingSplash instance;
return instance;
}
LoadingSplash();
~LoadingSplash() = default;
void Draw();
};

View File

@@ -1,3 +1,4 @@
#define IMGUI_DEFINE_MATH_OPERATORS
#include "WelcomeWindow.h"
#include <src/Vendors/imgui/imgui.h>
@@ -59,10 +60,8 @@ namespace Nuake
END_SERIALIZE();
}
bool ProjectPreview::Deserialize(const std::string& str)
bool ProjectPreview::Deserialize(const json& j)
{
BEGIN_DESERIALIZE(str);
if (!j.contains("Path"))
return false;
@@ -81,12 +80,37 @@ namespace Nuake
_NuakeLogo = TextureManager::Get()->GetTexture(NUAKE_LOGO_PATH);
}
void WelcomeWindow::LoadQueuedProject()
{
FileSystem::SetRootDirectory(FileSystem::GetParentPath(queuedProjectPath));
auto project = Project::New();
auto projectFileData = FileSystem::ReadFile(queuedProjectPath, true);
try
{
project->Deserialize(nlohmann::json::parse(projectFileData));
project->FullPath = queuedProjectPath;
Engine::LoadProject(project);
_Editor->filesystem->m_CurrentDirectory = Nuake::FileSystem::RootDirectory;
}
catch (std::exception exception)
{
Logger::Log("Error loading project: " + queuedProjectPath, "editor", CRITICAL);
Logger::Log(exception.what());
return;
}
queuedProjectPath = "";
Engine::GetCurrentWindow()->SetTitle("Nuake Engine - Editing " + project->Name);
}
void WelcomeWindow::Draw()
{
// Make viewport fullscreen
ImGuiViewport* viewport = ImGui::GetMainViewport();
ImGui::SetNextWindowPos(viewport->GetWorkPos());
ImGui::SetNextWindowSize(viewport->GetWorkSize());
ImGui::SetNextWindowPos(viewport->Pos);
ImGui::SetNextWindowSize(viewport->Size);
ImGui::SetNextWindowViewport(viewport->ID);
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
@@ -131,7 +155,7 @@ namespace Nuake
}
const float itemHeight = 120.0f;
if (ImGui::Button("Import an existing project", ImVec2(ImGui::GetContentRegionAvailWidth(), itemHeight)))
if (ImGui::Button("Import an existing project", ImVec2(ImGui::GetContentRegionAvail().x, itemHeight)))
{
const std::string path = FileDialog::OpenFile("Project file |*.project");
if (path != "" && String::EndsWith(path, ".project"))
@@ -164,14 +188,14 @@ namespace Nuake
const std::string selectableName = "##" + std::to_string(itemIndex);
const bool isSelected = SelectedProject == itemIndex;
if (ImGui::Selectable(selectableName.c_str(), isSelected, ImGuiSelectableFlags_AllowItemOverlap, ImVec2(ImGui::GetContentRegionAvailWidth(), itemHeight)))
if (ImGui::Selectable(selectableName.c_str(), isSelected, ImGuiSelectableFlags_AllowItemOverlap, ImVec2(ImGui::GetContentRegionAvail().x, itemHeight)))
{
SelectedProject = itemIndex;
}
const ImVec2 padding = ImVec2(25.0f, 20.0f);
const ImVec2 iconSize = ImVec2(100, 100);
ImGui::SetCursorPos(padding / 2.0 + ImVec2(0, cursorYStart));
ImGui::SetCursorPos(ImVec2(padding.x / 2.0, padding.y / 2.0) + ImVec2(0, cursorYStart));
ImGui::Image((ImTextureID)project.ProjectIcon->GetID(), iconSize, ImVec2(0, 1), ImVec2(1, 0));
ImGui::SameLine();
@@ -200,7 +224,7 @@ namespace Nuake
ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(0, 0, 0, 0));
if (ImGui::BeginChild("Controls", ImGui::GetContentRegionAvail(), false))
{
const ImVec2 buttonSize = ImVec2(ImGui::GetContentRegionAvailWidth(), buttonHeight);
const ImVec2 buttonSize = ImVec2(ImGui::GetContentRegionAvail().x, buttonHeight);
if (ImGui::Button("Create a new project", buttonSize))
{
std::string selectedProject = FileDialog::SaveFile("Project file\0*.project");
@@ -249,31 +273,9 @@ namespace Nuake
{
assert(SelectedProject < std::size(_Projects));
using namespace Nuake;
SaveRecentFile();
std::string projectPath = _Projects[SelectedProject].Path;
FileSystem::SetRootDirectory(FileSystem::GetParentPath(projectPath));
auto project = Project::New();
auto projectFileData = FileSystem::ReadFile(projectPath, true);
try
{
project->Deserialize(projectFileData);
project->FullPath = projectPath;
Engine::LoadProject(project);
_Editor->filesystem->m_CurrentDirectory = Nuake::FileSystem::RootDirectory;
}
catch (std::exception exception)
{
Logger::Log("Error loading project: " + projectPath, "editor", CRITICAL);
Logger::Log(exception.what());
}
Engine::GetCurrentWindow()->SetTitle("Nuake Engine - Editing " + project->Name);
queuedProjectPath = _Projects[SelectedProject].Path;;
}
}
}
@@ -298,7 +300,7 @@ namespace Nuake
for (auto& project : j["Projects"])
{
auto projectPreview = ProjectPreview();
projectPreview.Deserialize(project.dump());
projectPreview.Deserialize(project);
_Projects.push_back(projectPreview);
}
}

View File

@@ -22,7 +22,7 @@ namespace Nuake
~ProjectPreview() = default;
json Serialize() override;
bool Deserialize(const std::string& data) override;
bool Deserialize(const json& j) override;
private:
void ReadProjectFile();
@@ -41,13 +41,15 @@ namespace Nuake
uint32_t SelectedProject = 0;
std::vector<ProjectPreview> _Projects;
std::string queuedProjectPath;
public:
WelcomeWindow(Nuake::EditorInterface* editor);
~WelcomeWindow() = default;
void Draw();
bool IsProjectQueued() const { return !queuedProjectPath.empty(); };
void LoadQueuedProject();
private:
void DrawRecentProjectsSection();
void DrawProjectItem(const uint32_t projectPreview);

View File

@@ -53,22 +53,20 @@ namespace Nuake
s_CurrentWindow->Update(s_TimeStep);
// Play mode update all the entities, Editor does not.
if (Engine::IsPlayMode())
{
s_FixedUpdateDifference += s_TimeStep;
// Fixed update
while (s_FixedUpdateDifference >= s_FixedUpdateRate)
{
s_CurrentWindow->FixedUpdate(s_FixedUpdateDifference);
s_FixedUpdateDifference -= s_FixedUpdateRate;
}
}
else
if (!Engine::IsPlayMode())
{
GetCurrentScene()->EditorUpdate(s_TimeStep);
}
s_FixedUpdateDifference += s_TimeStep;
// Fixed update
while (s_FixedUpdateDifference >= s_FixedUpdateRate)
{
s_CurrentWindow->FixedUpdate(s_FixedUpdateDifference);
s_FixedUpdateDifference -= s_FixedUpdateRate;
}
}
Input::Update();

View File

@@ -1,10 +0,0 @@
#pragma once
namespace Nuake
{
class JoltImplementation
{
};
}

View File

@@ -1,6 +0,0 @@
#include "src/Resource/Model.h"
namespace Nuake
{
}

View File

@@ -1,27 +0,0 @@
#pragma once
#include "src/Core/Core.h"
#include "src/Resource/Resource.h"
#include "src/Resource/Serializable.h"
namespace Nuake
{
class Mesh;
class Model : Resource, ISerializable
{
private:
std::vector<Ref<Mesh>> m_Meshes;
public:
Model();
~Model();
bool LoadModel(const std::string& path);
std::vector<Ref<Mesh>>& GetMeshes();
json Serialize() override;
bool Deserialize(const std::string& data) override;
};
}

View File

@@ -1,6 +0,0 @@
#include "ParticleEmitter.h"
namespace Nuake
{
}

View File

@@ -1,14 +0,0 @@
#pragma once
#include "src/Resource/Serializable.h"
namespace Nuake
{
class ParticleEmitter
{
public:
json Serialize();
bool Deserialize(const std::string& str);
};
}

View File

@@ -1,14 +0,0 @@
#pragma once
#include <vector>
#include <string>
#include "src/Scene/Entities/Entity.h"
namespace Nuake {
class PrefabComponent
{
public:
Ref<Prefab> PrefabInstance;
};
}

View File

@@ -1,2 +0,0 @@
#pragma once

View File

@@ -70,19 +70,15 @@ namespace Nuake
newDir->Parent = directory;
ScanDirectory(newDir);
directory->Directories.push_back(newDir);
}
else if (entry.is_regular_file())
{
std::string absolutePath = entry.path().string();
std::string name = entry.path().filename().string();
std::string extension = entry.path().extension().string();
std::filesystem::path currentPath = entry.path();
std::string absolutePath = currentPath.string();
std::string name = currentPath.filename().string();
std::string extension = currentPath.extension().string();
Ref<File> newFile = CreateRef<File>(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);
}
}
@@ -173,11 +169,16 @@ namespace Nuake
fileWriter.close();
}
int FileSystem::RemoveFile(const std::string& path)
int FileSystem::DeleteFileFromPath(const std::string& path)
{
return std::remove(path.c_str());
}
int FileSystem::DeleteFolder(const std::string& path)
{
return std::filesystem::remove_all(path.c_str());
}
Ref<Directory> FileSystem::GetFileTree()
{
return RootDirectory;

View File

@@ -46,7 +46,8 @@ namespace Nuake
static bool BeginWriteFile(const std::string path);
static bool WriteLine(const std::string line);
static void EndWriteFile();
static int RemoveFile(const std::string& path);
static int DeleteFileFromPath(const std::string& path);
static int DeleteFolder(const std::string& path);
};
class File

View File

@@ -1,11 +1,41 @@
#include "OS.h"
#include "src/Window.h"
#define GLFW_EXPOSE_NATIVE_WIN32
#include "GLFW/glfw3.h"
#include "GLFW/glfw3native.h"
#include <chrono>
#include <Windows.h>
#include <chrono>
#include <imgui/imgui.h>
using namespace Nuake;
int OS::GetTime()
void OS::CopyToClipboard(const std::string& value)
{
auto glob = GlobalAlloc(GMEM_FIXED, 512);
memcpy(glob, value.data(), value.size());
OpenClipboard(glfwGetWin32Window(Window::Get()->GetHandle()));
EmptyClipboard();
SetClipboardData(CF_TEXT, glob);
CloseClipboard();
}
std::string OS::GetFromClipboard()
{
OpenClipboard(nullptr);
HANDLE hData = GetClipboardData(CF_TEXT);
char* pszText = static_cast<char*>(GlobalLock(hData));
std::string text(pszText);
GlobalUnlock(hData);
CloseClipboard();
return text;
}
int OS::GetTime()
{
return static_cast<int>(std::chrono::system_clock::now().time_since_epoch().count());
}
@@ -15,6 +45,25 @@ void OS::OpenIn(const std::string& filePath)
ShellExecuteA(nullptr, "open", filePath.c_str(), nullptr, nullptr, SW_SHOWDEFAULT);
}
int OS::RenameFile(const Ref<File>& file, const std::string& newName)
{
std::string extension = !String::EndsWith(newName, file->GetExtension().c_str()) ? file->GetExtension() : "";
std::string newFilePath = file->GetParent()->fullPath + newName + extension;
std::error_code resultError;
std::filesystem::rename(file->GetAbsolutePath().c_str(), newFilePath.c_str(), resultError);
return resultError.value() == 0;
}
int OS::RenameDirectory(const Ref<Directory>& dir, const std::string& newName)
{
std::string newDirPath = dir->Parent->fullPath + newName;
std::error_code resultError;
std::filesystem::rename(dir->fullPath.c_str(), newDirPath.c_str(), resultError);
return resultError.value() == 0;
}
void OS::ShowInFileExplorer(const std::string& filePath)
{
ShellExecuteA(nullptr, "open", "explorer.exe", ("/select," + std::string(filePath)).c_str(), nullptr, SW_SHOWDEFAULT);

View File

@@ -1,14 +1,19 @@
#pragma once
#include <string>
#include "FileSystem.h"
namespace Nuake
{
class OS
{
public:
static void CopyToClipboard(const std::string& value);
static std::string GetFromClipboard();
static int GetTime();
static void OpenIn(const std::string& filePath);
static int OS::RenameFile(const Ref<File>& file, const std::string& newName);
static int OS::RenameDirectory(const Ref<Directory>& dir, const std::string& newName);
static void ShowInFileExplorer(const std::string& filePath);
};
}

View File

@@ -28,6 +28,10 @@
#include <Jolt/Physics/Body/BodyCreationSettings.h>
#include <Jolt/Physics/Body/BodyActivationListener.h>
#include <Jolt/Physics/Character/Character.h>
#include <Jolt/Physics/Collision/RayCast.h>
#include <Jolt/Physics/Collision/CastResult.h>
#include <dependencies/JoltPhysics/Jolt/Physics/Collision/CollisionCollectorImpl.h>
namespace Nuake
{
@@ -157,7 +161,7 @@ namespace Nuake
{
public:
// See: ContactListener
virtual JPH::ValidateResult OnContactValidate(const JPH::Body& inBody1, const JPH::Body& inBody2, const JPH::CollideShapeResult& inCollisionResult) override
virtual JPH::ValidateResult OnContactValidate(const JPH::Body& inBody1, const JPH::Body& inBody2, JPH::RVec3Arg inBaseOffset, const JPH::CollideShapeResult& inCollisionResult) override
{
//std::cout << "Contact validate callback" << std::endl;
@@ -187,16 +191,56 @@ namespace Nuake
public:
virtual void OnBodyActivated(const JPH::BodyID& inBodyID, JPH::uint64 inBodyUserData) override
{
std::cout << "A body got activated" << std::endl;
//std::cout << "A body got activated" << std::endl;
}
virtual void OnBodyDeactivated(const JPH::BodyID& inBodyID, JPH::uint64 inBodyUserData) override
{
std::cout << "A body went to sleep" << std::endl;
//std::cout << "A body went to sleep" << std::endl;
}
};
class ObjectVsBroadPhaseLayerFilterImpl : public JPH::ObjectVsBroadPhaseLayerFilter
{
public:
virtual bool ShouldCollide(JPH::ObjectLayer inLayer1, JPH::BroadPhaseLayer inLayer2) const override
{
switch (inLayer1)
{
case Layers::NON_MOVING:
return inLayer2 == BroadPhaseLayers::MOVING;
case Layers::MOVING:
return true;
default:
return false;
}
}
};
class ObjectLayerPairFilterImpl : public JPH::ObjectLayerPairFilter
{
public:
virtual bool ShouldCollide(JPH::ObjectLayer inObject1, JPH::ObjectLayer inObject2) const override
{
switch (inObject1)
{
case Layers::NON_MOVING:
return inObject2 == Layers::MOVING; // Non moving only collides with moving
case Layers::MOVING:
return true; // Moving collides with everything
default:
return false;
}
}
};
BPLayerInterfaceImpl JoltBroadphaseLayerInterface = BPLayerInterfaceImpl();
ObjectVsBroadPhaseLayerFilterImpl JoltObjectVSBroadphaseLayerFilter = ObjectVsBroadPhaseLayerFilterImpl();
ObjectLayerPairFilterImpl JoltObjectVSObjectLayerFilter;
namespace Physics
{
DynamicWorld::DynamicWorld() : _stepCount(0)
@@ -204,13 +248,13 @@ namespace Nuake
_registeredCharacters = std::map<uint32_t, JPH::Character*>();
// Initialize Jolt Physics
const uint32_t MaxBodies = 1024;
const uint32_t MaxBodies = 2048;
const uint32_t NumBodyMutexes = 0;
const uint32_t MaxBodyPairs = 1024;
const uint32_t MaxContactConstraints = 1024;
_JoltPhysicsSystem = CreateRef<JPH::PhysicsSystem>();
_JoltPhysicsSystem->Init(MaxBodies, NumBodyMutexes, MaxBodyPairs, MaxContactConstraints, JoltBroadphaseLayerInterface, MyBroadPhaseCanCollide, MyObjectCanCollide);
_JoltPhysicsSystem->Init(MaxBodies, NumBodyMutexes, MaxBodyPairs, MaxContactConstraints, JoltBroadphaseLayerInterface, JoltObjectVSBroadphaseLayerFilter, JoltObjectVSObjectLayerFilter);
// A body activation listener gets notified when bodies activate and go to sleep
// Note that this is called from a job so whatever you do here needs to be thread safe.
@@ -231,7 +275,7 @@ namespace Nuake
// Optional step: Before starting the physics simulation you can optimize the broad phase. This improves collision detection performance (it's pointless here because we only have 2 bodies).
// You should definitely not call this every frame or when e.g. streaming in a new level section as it is an expensive operation.
// Instead insert all new objects in batches instead of 1 at a time to keep the broad phase efficient.
//_JoltPhysicsSystem->OptimizeBroadPhase();
_JoltPhysicsSystem->OptimizeBroadPhase();
const uint32_t availableThreads = std::thread::hardware_concurrency() - 1;
_JoltJobSystem = new JPH::JobSystemThreadPool(JPH::cMaxPhysicsJobs, JPH::cMaxPhysicsBarriers, availableThreads);
}
@@ -291,6 +335,7 @@ namespace Nuake
settings->mFriction = cc->Friction;
settings->mShape = GetJoltShape(cc->Shape);
settings->mGravityFactor = 0.0f;
settings->mSupportingVolume = JPH::Plane(JPH::Vec3::sAxisY(), -0.5f);
auto& joltPosition = JPH::Vec3(cc->Position.x, cc->Position.y, cc->Position.z);
@@ -298,7 +343,7 @@ namespace Nuake
// We need to add 180 degrees because our forward is -Z.
const auto& yOffset = Vector3(0.0f, Rad(180.0), 0.0f);
bodyRotation = glm::normalize(bodyRotation * Quat(yOffset));
//bodyRotation = glm::normalize(bodyRotation * Quat(yOffset));
const auto& joltRotation = JPH::Quat(bodyRotation.x, bodyRotation.y, bodyRotation.z, bodyRotation.w);
JPH::Character* character = new JPH::Character(settings, joltPosition, joltRotation, cc->GetEntity().GetID() , _JoltPhysicsSystem.get());
@@ -316,6 +361,7 @@ namespace Nuake
{
auto& characterController = _registeredCharacters[entityHandle];
const auto groundState = characterController->GetGroundState();
return groundState == JPH::CharacterBase::EGroundState::OnGround;
}
@@ -323,20 +369,42 @@ namespace Nuake
return false;
}
RaycastResult DynamicWorld::Raycast(const Vector3& from, const Vector3& to)
std::vector<RaycastResult> DynamicWorld::Raycast(const Vector3& from, const Vector3& to)
{
Vector3 localNorm = Vector3(0,0,0);
//Logger::Log("normal: x:" + std::to_string(localNorm.x) + " y:" + std::to_string(localNorm.y )+ "z: " + std::to_string(localNorm.z));
// Create jolt ray
const auto& fromJolt = JPH::Vec3(from.x, from.y, from.z);
const auto& toDirectionJolt = JPH::Vec3(to.x - from.x, to.y - from.y, to.z - from.z);
JPH::RRayCast ray { fromJolt, toDirectionJolt };
JPH::AllHitCollisionCollector<JPH::CastRayCollector> collector;
// Map bullet result to dto.
RaycastResult result{
Vector3(0,0,0),
Vector3(0,0,0),
localNorm
};
JPH::RayCastResult result;
_JoltPhysicsSystem->GetNarrowPhaseQuery().CastRay(ray, JPH::RayCastSettings(), collector);
return result;
// Fetch results
std::vector<RaycastResult> raycastResults;
if (collector.HadHit())
{
int num_hits = (int)collector.mHits.size();
JPH::BroadPhaseCastResult* results = collector.mHits.data();
// Format result
for (int i = 0; i < num_hits; ++i)
{
const float hitFraction = results[i].mFraction;
const JPH::Vec3& hitPosition = ray.GetPointOnRay(results[i].mFraction);
RaycastResult result
{
Vector3(hitPosition.GetX(), hitPosition.GetY(), hitPosition.GetZ()),
hitFraction
};
raycastResults.push_back(std::move(result));
}
}
return raycastResults;
}
void DynamicWorld::SyncEntitiesTranforms()
@@ -415,30 +483,41 @@ namespace Nuake
// Next step
++_stepCount;
// If you take larger steps than 1 / 60th of a second you need to do multiple collision steps in order to keep the simulation stable.
// Do 1 collision step per 1 / 60th of a second (round up).
int collisionSteps = 1;
constexpr float minStepDuration = 1.0f / 90.0f;
constexpr float minStepDuration = 1.0f / 30.0f;
constexpr int maxStepCount = 32;
if(ts > minStepDuration)
{
Logger::Log("Large step detected: " + std::to_string(ts), "physics", WARNING);
collisionSteps = static_cast<float>(ts) / minStepDuration;
}
if (collisionSteps >= maxStepCount)
{
Logger::Log("Very large step detected: " + std::to_string(ts), "physics", WARNING);
}
// Prevents having too many steps and running out of jobs
collisionSteps = std::min(collisionSteps, maxStepCount);
// If you want more accurate step results you can do multiple sub steps within a collision step. Usually you would set this to 1.
constexpr int subSteps = 1;
// Step the world
_JoltPhysicsSystem->Update(ts, collisionSteps, subSteps, new JPH::TempAllocatorMalloc(), _JoltJobSystem);
for (auto& c : _registeredCharacters)
try
{
c.second->PostSimulation(0.001);
_JoltPhysicsSystem->Update(ts, collisionSteps, new JPH::TempAllocatorMalloc(), _JoltJobSystem);
for (auto& c : _registeredCharacters)
{
c.second->PostSimulation(0.05f);
}
}
catch (...)
{
Logger::Log("Failed to run simulation update", "physics", CRITICAL);
}
SyncEntitiesTranforms();
SyncCharactersTransforms();
@@ -451,20 +530,22 @@ namespace Nuake
if (!_registeredBodies.empty())
{
_JoltBodyInterface->RemoveBodies(reinterpret_cast<JPH::BodyID*>(_registeredBodies.data()), _registeredBodies.size());
_registeredBodies.clear();
}
if (!_registeredCharacters.empty())
{
for (auto& character : _registeredCharacters)
{
character.second->RemoveFromPhysicsSystem();
}
_registeredCharacters.clear();
}
}
void DynamicWorld::MoveAndSlideCharacterController(const Entity& entity, const Vector3 velocity)
void DynamicWorld::MoveAndSlideCharacterController(const Entity& entity, const Vector3& velocity)
{
const uint32_t entityHandle = entity.GetHandle();
if (_registeredCharacters.find(entityHandle) != _registeredCharacters.end())
@@ -474,6 +555,23 @@ namespace Nuake
}
}
void DynamicWorld::AddForceToRigidBody(const Entity& entity, const Vector3& force)
{
auto& bodyInterface = _JoltPhysicsSystem->GetBodyInterface();
for (const auto& body : _registeredBodies)
{
auto bodyId = static_cast<JPH::BodyID>(body);
auto entityId = static_cast<uint32_t>(bodyInterface.GetUserData(bodyId));
if (entityId == entity.GetHandle())
{
bodyInterface.AddForce(bodyId, JPH::Vec3(force.x, force.y, force.z));
return;
}
}
Logger::Log("Failed to add force to rigidbody. Body not found with id: " + std::to_string(entity.GetHandle()), "physics", WARNING);
}
JPH::Ref<JPH::Shape> DynamicWorld::GetJoltShape(const Ref<PhysicShape> shape)
{
JPH::ShapeSettings::ShapeResult result;

View File

@@ -1,8 +1,9 @@
#pragma once
#include "src/Core/Core.h"
#include "src/Core/Timestep.h"
#include <glm/ext/vector_float3.hpp>
#include "Rigibody.h"
#include "src/Core/Timestep.h"
#include "src/Core/Core.h"
#include <map>
#include "RaycastResult.h"
@@ -10,7 +11,7 @@
#include "CharacterController.h"
#include <Jolt/Jolt.h>
#include "src/Core/Core.h"
namespace JPH
{
class PhysicsSystem;
@@ -32,7 +33,8 @@ namespace Nuake
class MyContactListener;
class MyBodyActivationListener;
namespace Physics {
namespace Physics
{
class DynamicWorld
{
private:
@@ -47,6 +49,7 @@ namespace Nuake
std::vector<uint32_t> _registeredBodies;
std::map<uint32_t, JPH::Character*> _registeredCharacters;
public:
DynamicWorld();
@@ -59,10 +62,10 @@ namespace Nuake
void AddCharacterController(Ref<CharacterController> cc);
bool IsCharacterGrounded(const Entity& entity);
// This is going to be ugly. TODO: Find a better way that passing itself as a parameter
void MoveAndSlideCharacterController(const Entity& entity, const Vector3 velocity);
void MoveAndSlideCharacterController(const Entity& entity, const Vector3& velocity);
void AddForceToRigidBody(const Entity& entity, const Vector3& force);
RaycastResult Raycast(const Vector3& from, const Vector3& to);
std::vector<RaycastResult> Raycast(const Vector3& from, const Vector3& to);
void StepSimulation(Timestep ts);
void Clear();

View File

@@ -37,7 +37,7 @@ namespace Nuake
m_World->Clear();
}
RaycastResult PhysicsManager::Raycast(const Vector3& from, const Vector3& to)
std::vector<RaycastResult> PhysicsManager::Raycast(const Vector3& from, const Vector3& to)
{
return m_World->Raycast(from, to);
}

View File

@@ -45,7 +45,7 @@ namespace Nuake
void Reset();
RaycastResult Raycast(const Vector3& from, const Vector3& to);
std::vector<RaycastResult> Raycast(const Vector3& from, const Vector3& to);
void RegisterBody(Ref<Physics::RigidBody> rb);
void RegisterGhostBody(Ref<GhostObject> rb);

View File

@@ -5,16 +5,10 @@
namespace Nuake
{
namespace Physics
{
}
// result object from raycast.
struct RaycastResult {
Vector3 WorldPoint;
Vector3 LocalPoint;
Vector3 Normal;
struct RaycastResult
{
Vector3 WorldPosition;
float Fraction;
};
}

View File

@@ -37,6 +37,7 @@ namespace Nuake
void SetShape(Ref<PhysicShape> shape);
Ref<PhysicShape> GetShape() const { return _collisionShape; }
Entity GetEntity() const { return _entity; }
void AddForce(const Vector3& force);
};
}
}

View File

@@ -1,6 +1,8 @@
#include "PhysicsShapes.h"
#include "Rigibody.h"
#include "../Core.h"
#include "src/Core/Core.h"
#include "src/Core/Physics/PhysicsManager.h"
#include <glm/trigonometric.hpp>
#include <src/Scene/Entities/Entity.h>
@@ -42,5 +44,10 @@ namespace Nuake
{
_entity = ent;
}
void RigidBody::AddForce(const Vector3& force)
{
PhysicsManager::Get().GetWorld()->AddForceToRigidBody(_entity, force);
}
}
}

View File

@@ -1,5 +1,6 @@
#include "String.h"
#include <iostream>
#include <regex>
#include <sstream>
namespace Nuake
@@ -36,6 +37,19 @@ namespace Nuake
return result;
}
std::string String::Sanitize(const std::string& keyword)
{
std::string sanitizedKeyword = keyword;
// Remove spaces, underscores, and hyphens using regex
sanitizedKeyword = std::regex_replace(sanitizedKeyword, std::regex("[ _-]+"), "");
// Convert to lowercase
std::transform(sanitizedKeyword.begin(), sanitizedKeyword.end(), sanitizedKeyword.begin(), ::tolower);
return sanitizedKeyword;
}
std::vector<std::string> String::Split(const std::string& string, char delimiter)
{
std::vector<std::string> result;

View File

@@ -15,6 +15,7 @@ namespace Nuake
static bool EndsWith(const std::string& string, const std::string& end);
static bool IsDigit(const char& character);
static std::string RemoveWhiteSpace(const std::string& string);
static std::string Sanitize(const std::string& keyword);
static std::vector<std::string> Split(const std::string& string, char delimiter);
static float ToFloat(const std::string& string);

View File

@@ -111,21 +111,20 @@ namespace Nuake
END_SERIALIZE();
}
bool Camera::Deserialize(const std::string& str)
bool Camera::Deserialize(const json& j)
{
BEGIN_DESERIALIZE();
j = j["CameraInstance"];
this->m_Type = (CAMERA_TYPE)j["m_Type"];
if(j.contains("Translation"))
DESERIALIZE_VEC3(j["Translation"], Translation);
auto& camJson = j["CameraInstance"];
this->m_Type = (CAMERA_TYPE)camJson["m_Type"];
if(camJson.contains("Translation"))
DESERIALIZE_VEC3(camJson["Translation"], Translation);
//if (j.contains("Direction"))
// DESERIALIZE_VEC3(j["Direction"], Direction);
this->AspectRatio = j["AspectRatio"];
this->Fov = j["Fov"];
this->Exposure = j["Exposure"];
this->Speed = j["Speed"];
this->AspectRatio = camJson["AspectRatio"];
this->Fov = camJson["Fov"];
this->Exposure = camJson["Exposure"];
this->Speed = camJson["Speed"];
return false;
}
}

View File

@@ -59,7 +59,7 @@ namespace Nuake
bool BoxFrustumCheck(const AABB& aabb);
Frustum GetFrustum();
json Serialize() override;
bool Deserialize(const std::string& str) override;
bool Deserialize(const json& j) override;
friend EditorCamera;
};

View File

@@ -10,6 +10,8 @@
#include "src/Rendering/Buffers/VertexArray.h"
#include "src/Rendering/Buffers/VertexBufferLayout.h"
#include <future>
namespace Nuake
{
Mesh::Mesh() {}
@@ -85,7 +87,6 @@ namespace Nuake
bufferLayout.Push<float>(3); // Normal
bufferLayout.Push<float>(3); // Tangent
bufferLayout.Push<float>(3); // Bitangent
bufferLayout.Push<float>(1); // Texture
m_VertexArray->AddBuffer(*m_VertexBuffer, bufferLayout);
m_VertexArray->Unbind();
@@ -150,12 +151,10 @@ namespace Nuake
END_SERIALIZE();
}
bool Mesh::Deserialize(const std::string& str)
{
BEGIN_DESERIALIZE();
bool Mesh::Deserialize(const json& j)
{
m_Material = CreateRef<Material>();
m_Material->Deserialize(j["Material"].dump());
m_Material->Deserialize(j["Material"]);
m_Indices.reserve(j["Indices"].size());
for (auto& i : j["Indices"])
@@ -164,24 +163,26 @@ namespace Nuake
}
std::vector<Vertex> vertices;
for (auto& v : j["Vertices"])
{
Vertex vertex;
try {
DESERIALIZE_VEC2(v["UV"], vertex.uv)
std::async(std::launch::async, [&]()
{
for (auto& v : j["Vertices"])
{
Vertex vertex;
try {
DESERIALIZE_VEC2(v["UV"], vertex.uv)
}
catch (std::exception& e) {
vertex.uv = { 0.0, 0.0 };
}
DESERIALIZE_VEC3(v["Position"], vertex.position)
DESERIALIZE_VEC3(v["Normal"], vertex.normal)
DESERIALIZE_VEC3(v["Tangent"], vertex.tangent)
DESERIALIZE_VEC3(v["Bitangent"], vertex.bitangent)
vertices.push_back(vertex);
}
}
catch(std::exception& e) {
vertex.uv = { 0.0, 0.0 };
}
DESERIALIZE_VEC3(v["Position"], vertex.position)
DESERIALIZE_VEC3(v["Normal"], vertex.normal)
DESERIALIZE_VEC3(v["Tangent"], vertex.tangent)
DESERIALIZE_VEC3(v["Bitangent"], vertex.bitangent)
vertices.push_back(vertex);
}
);
m_Vertices = vertices;

View File

@@ -32,7 +32,7 @@ namespace Nuake
inline AABB GetAABB() const { return m_AABB; }
json Serialize() override;
bool Deserialize(const std::string& str) override;
bool Deserialize(const json& j) override;
private:
Ref<Material> m_Material = nullptr;
std::vector<uint32_t> m_Indices;

View File

@@ -129,14 +129,6 @@ namespace Nuake
Renderer::DrawQuad(Matrix4(1.0));
}
_ssaoBlurFramebuffer->Unbind();
/*
if (ImGui::Begin("SSAO debug"))
{
ImGui::Image((void*)(uintptr_t)(_ssaoFramebuffer->GetTexture(GL_COLOR_ATTACHMENT0)->GetID()), ImGui::GetContentRegionAvail(), ImVec2(0, 1), ImVec2(1, 0));
}
ImGui::End();
*/
}
Ref<FrameBuffer> SSAO::GetOuput() const

View File

@@ -27,11 +27,11 @@ namespace Nuake
}
public:
float Radius = 0.060f;
float Bias = 0.00125f;
float Radius = 0.997f;
float Bias = 0.045f;
float Area = 0.0075f;
float Falloff = 0.002f;
float Strength = 0.5f;
float Strength = 0.2f;
void Resize(const Vector2& size);
SSAO();
void Draw(FrameBuffer* gBuffer, const Matrix4& projection, const Matrix4& view);

View File

@@ -36,15 +36,19 @@ namespace Nuake
void Flush(Shader* shader, bool depthOnly = false)
{
shader->Bind();
const uint32_t entityIdUniformLocation = shader->FindUniformLocation("u_EntityID");
const uint32_t modelMatrixUniformLocation = shader->FindUniformLocation("u_Model");
for (auto& i : m_RenderList)
{
if(!depthOnly)
if (!depthOnly)
{
i.first->Bind(shader);
}
for (auto& m : i.second)
{
shader->SetUniformMat4f("u_Model", m.transform);
shader->SetUniform1i("u_EntityID", m.entityId + 1);
shader->SetUniformMat4f(modelMatrixUniformLocation, m.transform);
shader->SetUniform1i(entityIdUniformLocation, m.entityId + 1);
m.Mesh->Draw(shader, false);
}
}

View File

@@ -22,6 +22,7 @@ namespace Nuake
unsigned int depthFBO;
Ref<Mesh> Renderer::CubeMesh;
Ref<Mesh> Renderer::QuadMesh;
Shader* Renderer::m_Shader;
Shader* Renderer::m_SkyboxShader;
@@ -62,13 +63,14 @@ namespace Nuake
4, 5, 0, 0, 5, 1
};
float QuadVertices[] = {
-1.0f, -1.0f, 0.0f, 0.0f, 0.0f,
1.0f, 1.0f, 0.0f, 1.0f, 1.0f,
-1.0f, 1.0f, 0.0f, 0.0f, 1.0f,
1.0f, -1.0f, 0.0f, 1.0f, 0.0f,
-1.0f, -1.0f, 0.0f, 0.0f, 0.0f,
1.0f, 1.0f, 0.0f, 1.0f, 1.0f
std::vector<Vertex> QuadVertices
{
{ Vector3(-1.0f, -1.0f, 0.0f), Vector2(0, 0), Vector3(0, 0, -1) },
{ Vector3(1.0f, 1.0f, 0.0f), Vector2(1.0f, 1.0f), Vector3(0, 0, -1) },
{ Vector3(-1.0f, 1.0f, 0.0f), Vector2(0.0f, 1.0f), Vector3(0, 0, -1) },
{ Vector3(1.0f, -1.0f, 0.0f), Vector2(1.0f, 0.0f), Vector3(0, 0, -1) },
{ Vector3(-1.0f, -1.0f, 0.0f), Vector2(0.0f, 0.0f), Vector3(0, 0, -1) },
{ Vector3(1.0f, 1.0f, 0.0f), Vector2(1.0f, 1.0f), Vector3(0, 0, -1) }
};
@@ -80,28 +82,17 @@ namespace Nuake
m_LightsUniformBuffer = CreateRef<UniformBuffer>(128);
Ref<Material> material = MaterialManager::Get()->GetMaterial("default");
Ref<Material> defaultMaterial = CreateRef<Material>(Vector3{1, 1, 1});
defaultMaterial->SetName("white");
MaterialManager::Get()->RegisterMaterial(defaultMaterial);
CubeMesh = CreateRef<Mesh>();
CubeMesh->AddSurface(CubeVertices, CubeIndices);
CubeMesh->SetMaterial(material);
// Cube buffer
//CubeVertexArray = new VertexArray();
//CubeVertexArray->Bind();
//CubeVertexBuffer = new VertexBuffer(CubeVertices, sizeof(CubeVertices));
//
VertexBufferLayout vblayout = VertexBufferLayout();
vblayout.Push<float>(3);
//CubeVertexArray->AddBuffer(*CubeVertexBuffer, vblayout);
CubeMesh->SetMaterial(defaultMaterial);
// Quad buffer
QuadVertexArray = new VertexArray();
QuadVertexArray->Bind();
QuadVertexBuffer = new VertexBuffer(QuadVertices, sizeof(QuadVertices));
vblayout = VertexBufferLayout();
vblayout.Push<float>(3);
vblayout.Push<float>(2);
QuadVertexArray->AddBuffer(*QuadVertexBuffer, vblayout);
QuadMesh = CreateRef<Mesh>();
QuadMesh->AddSurface(QuadVertices, { 0, 1, 2, 3, 4, 5 });
QuadMesh->SetMaterial(defaultMaterial);
}
void Renderer::LoadShaders()
@@ -221,7 +212,7 @@ namespace Nuake
m_DebugShader->SetUniformMat4f("u_Model", transform.GetGlobalTransform());
m_DebugShader->SetUniform4f("u_Color", color.r, color.g, color.b, color.a);
CubeVertexArray->Bind();
CubeMesh->Bind();
RenderCommand::DrawArrays(0, 36);
}
@@ -233,7 +224,7 @@ namespace Nuake
void Renderer::DrawQuad(Matrix4 transform)
{
QuadVertexArray->Bind();
QuadMesh->Bind();
RenderCommand::DrawArrays(0, 6);
}
}

View File

@@ -33,6 +33,7 @@ namespace Nuake
{
private:
static RenderList m_RenderList;
public:
static VertexArray* QuadVertexArray;
static VertexBuffer* QuadVertexBuffer;
@@ -51,6 +52,7 @@ namespace Nuake
static Ref<UniformBuffer> m_LightsUniformBuffer;
static Ref<Mesh> CubeMesh;
static Ref<Mesh> QuadMesh;
static void Init();
static void LoadShaders();
@@ -65,7 +67,6 @@ namespace Nuake
// Lights
static std::vector<Light> m_Lights;
static void RegisterLight(TransformComponent transform, LightComponent light);
static void RegisterDeferredLight(TransformComponent transform, LightComponent light);
// Debug

View File

@@ -1,9 +1,13 @@
#include "SceneRenderer.h"
#include "src/Rendering/Shaders/ShaderManager.h"
#include <src/Scene/Components/BSPBrushComponent.h>
#include "src/Scene/Components/BSPBrushComponent.h"
#include "src/Scene/Components/SpriteComponent.h"
#include "src/Scene/Components/ParticleEmitterComponent.h"
#include <GL\glew.h>
namespace Nuake
{
void SceneRenderer::Init()
@@ -49,7 +53,14 @@ namespace Nuake
mGBuffer->QueueResize(framebuffer.GetSize());
GBufferPass(scene);
// SSAO
const auto& sceneEnv = scene.GetEnvironment();
sceneEnv->mSSAO->Resize(framebuffer.GetSize());
sceneEnv->mSSAO->Draw(mGBuffer.get(), mProjection, mView);
mShadingBuffer->QueueResize(framebuffer.GetSize());
ShadingPass(scene);
Ref<Texture> finalOutput = mShadingBuffer->GetTexture();
if (scene.GetEnvironment()->BloomEnabled)
{
@@ -105,9 +116,7 @@ namespace Nuake
finalOutput = framebuffer.GetTexture();
// SSAO
sceneEnv->mSSAO->Resize(framebuffer.GetSize());
sceneEnv->mSSAO->Draw(mGBuffer.get(), mProjection, mView);
// Copy final output to target framebuffer
mToneMapBuffer->QueueResize(framebuffer.GetSize());
@@ -139,11 +148,6 @@ namespace Nuake
}
framebuffer.Unbind();
mShadingBuffer->QueueResize(framebuffer.GetSize());
ShadingPass(scene);
RenderCommand::Enable(RendererEnum::DEPTH_TEST);
Renderer::EndDraw();
}
@@ -198,9 +202,40 @@ namespace Nuake
}
}
Renderer::Flush(shader, true);
}
light.m_Framebuffers[i]->Unbind();
auto spriteView = scene.m_Registry.view<TransformComponent, SpriteComponent, VisibilityComponent>();
for (auto e : spriteView)
{
auto [transform, sprite, visibility] = spriteView.get<TransformComponent, SpriteComponent, VisibilityComponent>(e);
if (!visibility.Visible || !sprite.SpriteMesh)
continue;
auto& finalQuadTransform = transform.GetGlobalTransform();
if (sprite.Billboard)
{
finalQuadTransform = glm::inverse(mView);
if (sprite.LockYRotation)
{
// This locks the pitch rotation on the billboard, useful for trees, lamps, etc.
finalQuadTransform[1] = Vector4(0, 1, 0, 0);
finalQuadTransform[2] = Vector4(finalQuadTransform[2][0], 0, finalQuadTransform[2][2], 0);
finalQuadTransform = finalQuadTransform;
}
// Translation
finalQuadTransform[3] = Vector4(transform.GetGlobalPosition(), 1.0f);
// Scale
finalQuadTransform = glm::scale(finalQuadTransform, transform.GetGlobalScale());
}
Renderer::SubmitMesh(sprite.SpriteMesh, finalQuadTransform, (uint32_t)e);
}
Renderer::Flush(shader, true);
}
}
}
}
@@ -210,16 +245,18 @@ namespace Nuake
mGBuffer->Bind();
mGBuffer->Clear();
{
// Init
RenderCommand::Enable(RendererEnum::FACE_CULL);
Shader* gBufferShader = ShaderManager::GetShader("resources/Shaders/gbuffer.shader");
gBufferShader->Bind();
gBufferShader->SetUniformMat4f("u_Projection", mProjection);
gBufferShader->SetUniformMat4f("u_View", mView);
auto view = scene.m_Registry.view<TransformComponent, ModelComponent, ParentComponent, VisibilityComponent>();
// Models
auto view = scene.m_Registry.view<TransformComponent, ModelComponent, VisibilityComponent>();
for (auto e : view)
{
auto [transform, mesh, parent, visibility] = view.get<TransformComponent, ModelComponent, ParentComponent, VisibilityComponent>(e);
auto [transform, mesh, visibility] = view.get<TransformComponent, ModelComponent, VisibilityComponent>(e);
if (mesh.ModelResource && visibility.Visible)
{
@@ -234,10 +271,11 @@ namespace Nuake
RenderCommand::Disable(RendererEnum::FACE_CULL);
Renderer::Flush(gBufferShader, false);
auto quakeView = scene.m_Registry.view<TransformComponent, BSPBrushComponent, ParentComponent, VisibilityComponent>();
// Quake BSPs
auto quakeView = scene.m_Registry.view<TransformComponent, BSPBrushComponent, VisibilityComponent>();
for (auto e : quakeView)
{
auto [transform, model, parent, visibility] = quakeView.get<TransformComponent, BSPBrushComponent, ParentComponent, VisibilityComponent>(e);
auto [transform, model, visibility] = quakeView.get<TransformComponent, BSPBrushComponent, VisibilityComponent>(e);
if (model.IsTransparent || !visibility.Visible)
continue;
@@ -248,8 +286,72 @@ namespace Nuake
}
}
Renderer::Flush(gBufferShader, false);
// Sprites
auto spriteView = scene.m_Registry.view<TransformComponent, SpriteComponent, VisibilityComponent>();
for (auto& e : spriteView)
{
auto [transform, sprite, visibility] = spriteView.get<TransformComponent, SpriteComponent, VisibilityComponent>(e);
if (!visibility.Visible || !sprite.SpriteMesh)
continue;
auto& finalQuadTransform = transform.GetGlobalTransform();
if (sprite.Billboard)
{
finalQuadTransform = glm::inverse(mView);
if (sprite.LockYRotation)
{
// This locks the pitch rotation on the billboard, useful for trees, lamps, etc.
finalQuadTransform[1] = Vector4(0, 1, 0, 0);
finalQuadTransform[2] = Vector4(finalQuadTransform[2][0], 0, finalQuadTransform[2][2], 0);
finalQuadTransform = finalQuadTransform;
}
// Translation
finalQuadTransform[3] = Vector4(transform.GetGlobalPosition(), 1.0f);
// Scale
finalQuadTransform = glm::scale(finalQuadTransform, transform.GetGlobalScale());
}
Renderer::SubmitMesh(sprite.SpriteMesh, finalQuadTransform, (uint32_t)e);
}
Renderer::Flush(gBufferShader, false);
// Particles
auto particleEmitterView = scene.m_Registry.view<TransformComponent, ParticleEmitterComponent, VisibilityComponent>();
for (auto& e : particleEmitterView)
{
auto [transform, emitterComponent, visibility] = particleEmitterView.get<TransformComponent, ParticleEmitterComponent, VisibilityComponent>(e);
if (!visibility.Visible)
continue;
Vector3 oldColor = Renderer::QuadMesh->GetMaterial()->data.m_AlbedoColor;
auto initialTransform = transform.GetGlobalTransform();
for (auto& p : emitterComponent.Emitter.Particles)
{
Matrix4 particleTransform = initialTransform;
particleTransform = glm::inverse(mView);
// Translation
const Vector3& particleGlobalPosition = transform.GetGlobalPosition() + p.Position;
particleTransform[3] = Vector4(particleGlobalPosition, 1.0f);
// Scale
particleTransform = glm::scale(particleTransform, transform.GetGlobalScale());
Renderer::QuadMesh->GetMaterial()->data.u_HasAlbedo = 0;
Renderer::QuadMesh->GetMaterial()->data.m_AlbedoColor = p.Color;
Renderer::SubmitMesh(Renderer::QuadMesh, particleTransform, (uint32_t)e);
}
Renderer::Flush(gBufferShader, false);
Renderer::QuadMesh->GetMaterial()->data.m_AlbedoColor = oldColor;
}
}
mGBuffer->Unbind();
}
void SceneRenderer::ShadingPass(Scene& scene)
@@ -308,7 +410,6 @@ namespace Nuake
Renderer::DrawQuad(Matrix4());
}
mShadingBuffer->Unbind();
}
void SceneRenderer::PostProcessPass(const Scene& scene)

View File

@@ -6,10 +6,12 @@
#include "src/Rendering/Buffers/Framebuffer.h"
#include "src/Rendering/PostFX/Bloom.h"
#include "src/Rendering/PostFX/Volumetric.h"
#include <src/Rendering/PostFX/SSR.h>
#include "src/Rendering/PostFX/SSR.h"
namespace Nuake {
class SceneRenderer {
namespace Nuake
{
class SceneRenderer
{
public:
void Init();
void Cleanup();
@@ -32,7 +34,7 @@ namespace Nuake {
Scope<FrameBuffer> mShadingBuffer;
Scope<FrameBuffer> mToneMapBuffer;
private:
void ShadowPass(Scene& scene);
void GBufferPass(Scene& scene);
void ShadingPass(Scene& scene);

View File

@@ -26,6 +26,8 @@ namespace Nuake
Source = newSource;
ProgramId = newProgramId;
return true;
}
// Bind the shader
@@ -190,7 +192,7 @@ namespace Nuake
int addr = glGetUniformLocation(ProgramId, uniform.c_str());
if (addr == -1)
return addr;//std::cout << "Warning: uniform '" << uniform << "' doesn't exists!" << std::endl;
return addr;
else
UniformCache[uniform] = addr;
@@ -250,7 +252,12 @@ namespace Nuake
//ASSERT(addr != -1);
if (addr != -1)
glUniform1i(addr, v0);
SetUniform1i(addr, v0);
}
void Shader::SetUniform1i(uint32_t location, int v0)
{
glUniform1i(location, v0);
}
void Shader::SetUniform1iv(const std::string& name, int size, int* value)
@@ -277,12 +284,19 @@ namespace Nuake
glUniformMatrix3fv(addr, 1, GL_FALSE, &mat[0][0]);
}
void Shader::SetUniformMat4f(const std::string& name, Matrix4 mat)
void Shader::SetUniformMat4f(uint32_t location, const Matrix4& mat)
{
glUniformMatrix4fv(location, 1, GL_FALSE, &mat[0][0]);
}
void Shader::SetUniformMat4f(const std::string& name, const Matrix4& mat)
{
int addr = FindUniformLocation(name);
if (addr != -1)
glUniformMatrix4fv(addr, 1, GL_FALSE, &mat[0][0]);
{
SetUniformMat4f(addr, std::move(mat));
}
}
void Shader::SetUniform1f(const std::string& name, float v0)

View File

@@ -42,16 +42,20 @@ namespace Nuake
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);
void SetUniform1i(uint32_t location, int v0);
void SetUniform1iv(const std::string& name, int size, int* value);
void SetUniform1fv(const std::string& name, int size, float* value);
void SetUniformMat3f(const std::string& name, Matrix3 mat);
void SetUniformMat4f(const std::string& name, Matrix4 mat);
void SetUniformMat4f(uint32_t name, const Matrix4& mat);
void SetUniformMat4f(const std::string& name, const Matrix4& mat);
int FindUniformLocation(std::string uniform);
private:
ShaderSource ParseShader(const std::string& filePath);
unsigned int CreateProgram(ShaderSource source);
unsigned int Compile(unsigned int type, ShaderSource source);
int FindUniformLocation(std::string uniform);
};
}

View File

@@ -68,9 +68,7 @@ namespace Nuake
data.m_AlbedoColor = Vector3{ albedoColor.r, albedoColor.g, albedoColor.b };
m_Name = "New material";
m_Albedo = m_DefaultAlbedo;
m_Name = "default";
}
Material::~Material() {}

View File

@@ -128,10 +128,8 @@ namespace Nuake
END_SERIALIZE();
}
bool Deserialize(const std::string& str) override
bool Deserialize(const json& j) override
{
BEGIN_DESERIALIZE();
if (j.contains("Path"))
{
this->Path = j["Path"];

View File

@@ -11,8 +11,6 @@ namespace Nuake
class MaterialManager
{
private:
const std::string DEFAULT_MATERIAL = "resources/Textures/default/Default.png";
static Ref<MaterialManager> s_Instance;
std::map<std::string, Ref<Material>> m_Materials;
@@ -24,12 +22,12 @@ namespace Nuake
public:
const std::string DEFAULT_MATERIAL = "resources/Textures/default/Default.png";
std::string CurrentlyBoundedMaterial = "";
MaterialManager();
void LoadMaterials();
void RegisterMaterial(Ref<Material> material);
Ref<Material> LoadMaterial(std::string path);

View File

@@ -52,9 +52,8 @@ namespace Nuake
END_SERIALIZE();
}
bool Deserialize(const std::string& str) override
bool Deserialize(const json& j) override
{
BEGIN_DESERIALIZE();
if (j.contains("Path"))
return false;

View File

@@ -3,15 +3,13 @@
namespace Nuake
{
class Vertex
struct Vertex
{
public:
Vector3 position;
Vector2 uv;
Vector3 normal;
Vector3 tangent;
Vector3 bitangent;
float texture;
};
struct LineVertex

View File

@@ -54,9 +54,8 @@ namespace Nuake {
END_SERIALIZE();
}
bool Deserialize(const std::string& str) override
bool Deserialize(const json& j) override
{
BEGIN_DESERIALIZE();
Name = j["Name"];
Description = j["Description"];
Visible = j["Visible"];
@@ -101,9 +100,8 @@ namespace Nuake {
END_SERIALIZE();
}
bool Deserialize(const std::string& str) override
bool Deserialize(const json& j) override
{
BEGIN_DESERIALIZE();
Name = j["Name"];
Description = j["Description"];
Prefab = j["Prefab"];

View File

@@ -39,15 +39,14 @@ namespace Nuake {
END_SERIALIZE();
}
bool Deserialize(const std::string& str)
bool Deserialize(const json& j)
{
BEGIN_DESERIALIZE();
if (j.contains("BrushEntities"))
{
for (auto& brush : j["BrushEntities"])
{
FGDBrushEntity brushEntity = FGDBrushEntity();
brushEntity.Deserialize(brush.dump());
brushEntity.Deserialize(brush);
BrushEntities.push_back(brushEntity);
}
}
@@ -57,7 +56,7 @@ namespace Nuake {
for (auto& point : j["PointEntities"])
{
FGDPointEntity pointEntity = FGDPointEntity();
pointEntity.Deserialize(point.dump());
pointEntity.Deserialize(point);
PointEntities.push_back(pointEntity);
}
}

View File

@@ -45,9 +45,8 @@ namespace Nuake
END_SERIALIZE();
}
bool Model::Deserialize(const std::string& str)
bool Model::Deserialize(const json& j)
{
BEGIN_DESERIALIZE();
if (j.contains("Path"))
{
this->IsEmbedded = true;
@@ -63,7 +62,7 @@ namespace Nuake
for (auto& m : j["Meshes"])
{
Ref<Mesh> mesh = CreateRef<Mesh>();
mesh->Deserialize(m.dump());
mesh->Deserialize(m);
m_Meshes.push_back(mesh);
}

View File

@@ -20,7 +20,7 @@ namespace Nuake
std::vector<Ref<Mesh>>& GetMeshes();
json Serialize() override;
bool Deserialize(const std::string& data) override;
bool Deserialize(const json& j) override;
};
}

View File

@@ -82,7 +82,6 @@ namespace Nuake
for (uint32_t i = 0; i < mesh->mNumVertices; i++)
{
Vertex vertex;
vertex.texture = 1.0f;
Vector3 current;

View File

@@ -19,7 +19,7 @@ namespace Nuake {
if (FileSystem::FileExists(path, false))
{
std::string prefabTextContent = FileSystem::ReadFile(path);
newPrefab->Deserialize(prefabTextContent);
newPrefab->Deserialize(json::parse(prefabTextContent));
}
return newPrefab;

View File

@@ -60,22 +60,28 @@ namespace Nuake {
END_SERIALIZE();
}
bool Deserialize(const std::string& str)
bool Deserialize(const json& j)
{
if (str == "")
if (j == "")
return false;
BEGIN_DESERIALIZE();
Path = j["Path"];
if (j.contains("Entities"))
{
return true;
for (json e : j["Entities"])
{
Entity entity = Entity { Engine::GetCurrentScene()->m_Registry.create(), Engine::GetCurrentScene().get() };
entity.Deserialize(e.dump());
Entity entity = Engine::GetCurrentScene()->CreateEntity("-");
auto& nameComponent = entity.GetComponent<NameComponent>();
int entityId = nameComponent.ID;
entity.Deserialize(e);
nameComponent.ID = entityId;
this->AddEntity(entity);
}
// Set reference to the parent entity to children
for (auto& e : Entities)
{
auto parentC = e.GetComponent<ParentComponent>();

View File

@@ -43,7 +43,7 @@ namespace Nuake
void Project::SaveAs(const std::string& FullPath)
{
json j = Serialize();
std::string serialized_string = j.dump();
std::string serialized_string = j.dump(4);
// TODO: Use file interface here...
// Write to file.
@@ -103,10 +103,8 @@ namespace Nuake
END_SERIALIZE();
}
bool Project::Deserialize(const std::string& str)
bool Project::Deserialize(const json& j)
{
BEGIN_DESERIALIZE();
if (!j.contains("Name") || !j.contains("Description"))
return false;
@@ -118,7 +116,7 @@ namespace Nuake
std::string path = j["EntityDefinition"];
EntityDefinitionsFile = CreateRef<FGDFile>(path);
std::string content = FileSystem::ReadFile(path, false);
EntityDefinitionsFile->Deserialize(content);
EntityDefinitionsFile->Deserialize(nlohmann::json::parse(content));
}
if (j.contains("TrenchbroomPath"))
@@ -140,7 +138,7 @@ namespace Nuake
return true;
std::string sceneContent = FileSystem::ReadFile(scenePath, false);
if (!DefaultScene->Deserialize(sceneContent))
if (!DefaultScene->Deserialize(nlohmann::json::parse(sceneContent)))
{
Logger::Log("Error loading scene: " + scenePath, "project", CRITICAL);
}

View File

@@ -33,6 +33,6 @@ namespace Nuake
static Ref<Project> Load(std::string& path);
json Serialize() override;
bool Deserialize(const std::string& str) override;
bool Deserialize(const json& j) override;
};
}

View File

@@ -49,7 +49,7 @@ namespace Nuake
Ref<Material> material = CreateRef<Material>();
material->ID = uuid;
material->Path = path;
material->Deserialize(j.dump());
material->Deserialize(j);
ResourceManager::RegisterResource(material);
return material;

View File

@@ -19,6 +19,9 @@ using json = nlohmann::json;
SERIALIZE_VEC3(v) \
j[#v]["w"] = this->v.w;
#define DESERIALIZE_VEC4(v, p) \
p = Vector4(v["x"], v["y"], v["z"], v["w"]);
#define DESERIALIZE_VEC3(v, p) \
p = Vector3(v["x"], v["y"], v["z"]);
@@ -35,11 +38,11 @@ using json = nlohmann::json;
#define BEGIN_DESERIALIZE() json j = json::parse(str);
#define DESERIALIZE_COMPONENT(c) \
if(j.contains(#c)) \
AddComponent<c>().Deserialize(j[#c].dump());
AddComponent<c>().Deserialize(j[#c]);
class ISerializable
{
public:
virtual json Serialize() = 0;
virtual bool Deserialize(const std::string& str) = 0;
virtual bool Deserialize(const json& j) = 0;
};

View File

@@ -54,10 +54,8 @@ namespace Nuake {
END_SERIALIZE();
}
bool Deserialize(const std::string& str)
bool Deserialize(const json& j)
{
BEGIN_DESERIALIZE();
if (j.contains("IsSolid"))
{
IsSolid = j["IsSolid"];

View File

@@ -12,10 +12,8 @@ struct VisibilityComponent
END_SERIALIZE();
}
bool Deserialize(std::string str)
bool Deserialize(const json& j)
{
BEGIN_DESERIALIZE();
if (j.contains("Visible"))
{
Visible = j["Visible"];

View File

@@ -12,9 +12,8 @@ namespace Nuake
END_SERIALIZE();
}
bool BoxColliderComponent::Deserialize(const std::string& str)
bool BoxColliderComponent::Deserialize(const json& j)
{
BEGIN_DESERIALIZE();
this->IsTrigger = j["IsTrigger"];
this->Size = Vector3(j["Size"]["x"], j["Size"]["y"], j["Size"]["z"]);
return true;

View File

@@ -11,7 +11,7 @@ namespace Nuake {
bool IsTrigger = false;
json Serialize();
bool Deserialize(const std::string& str);
bool Deserialize(const json& j);
};
}

View File

@@ -23,11 +23,11 @@ namespace Nuake
END_SERIALIZE();
}
bool Deserialize(std::string str)
bool Deserialize(const json& j)
{
CameraInstance = CreateRef<Camera>();
return CameraInstance->Deserialize(str);
return CameraInstance->Deserialize(j);
}
};
}

View File

@@ -13,9 +13,8 @@ namespace Nuake
END_SERIALIZE()
}
bool CapsuleColliderComponent::Deserialize(const std::string& str)
bool CapsuleColliderComponent::Deserialize(const json& j)
{
BEGIN_DESERIALIZE()
this->IsTrigger = j["IsTrigger"];
this->Radius = j["Radius"];
this->Height = j["Height"];

View File

@@ -15,6 +15,6 @@ namespace Nuake
bool IsTrigger = false;
json Serialize();
bool Deserialize(const std::string& str);
bool Deserialize(const json& str);
};
}

View File

@@ -23,10 +23,8 @@ namespace Nuake {
END_SERIALIZE();
}
bool Deserialize(const std::string str)
bool Deserialize(const json& j)
{
BEGIN_DESERIALIZE();
if (j.contains("Friction"))
{
Friction = j["Friction"];

View File

@@ -20,5 +20,4 @@
#include "ParentComponent.h"
#include "NameComponent.h"
#include "BoxCollider.h"
#include "ParticleEmitter.h"
#include "../Entities/Entity.h"

View File

@@ -13,9 +13,8 @@ namespace Nuake
END_SERIALIZE()
}
bool CylinderColliderComponent::Deserialize(const std::string& str)
bool CylinderColliderComponent::Deserialize(const json& j)
{
BEGIN_DESERIALIZE()
this->IsTrigger = j["IsTrigger"];
this->Radius = j["Radius"];
this->Height = j["Height"];

View File

@@ -15,6 +15,6 @@ namespace Nuake
bool IsTrigger = false;
json Serialize();
bool Deserialize(const std::string& str);
bool Deserialize(const json& j);
};
}

View File

@@ -17,10 +17,8 @@ namespace Nuake {
END_SERIALIZE();
}
bool Deserialize(const std::string& str)
bool Deserialize(const json& j)
{
BEGIN_DESERIALIZE();
if (j.contains("Interface"))
SetInterface(j["Interface"]);

View File

@@ -168,9 +168,8 @@ namespace Nuake
END_SERIALIZE();
}
bool Deserialize(std::string str)
bool Deserialize(const json& j)
{
BEGIN_DESERIALIZE();
if (j.contains("Type"))
Type = (LightType)j["Type"];
if (j.contains("IsVolumetric"))

View File

@@ -18,9 +18,8 @@ namespace Nuake {
END_SERIALIZE();
}
bool Deserialize(const std::string& str)
bool Deserialize(const json& j)
{
BEGIN_DESERIALIZE();
this->IsTrigger = j["IsTrigger"];
this->SubMesh = j["SubMesh"];
return true;

View File

@@ -27,16 +27,15 @@ namespace Nuake
END_SERIALIZE();
}
bool Deserialize(const std::string str)
bool Deserialize(const json& j)
{
BEGIN_DESERIALIZE();
ModelPath = j["ModelPath"];
ModelResource = CreateRef<Model>();
if (j.contains("ModelResource"))
{
auto& res = j["ModelResource"];
ModelResource->Deserialize(res.dump());
ModelResource->Deserialize(res);
}
return true;

View File

@@ -18,9 +18,8 @@ namespace Nuake {
END_SERIALIZE();
}
bool Deserialize(const std::string& str)
bool Deserialize(const json& j)
{
BEGIN_DESERIALIZE();
Name = j["Name"];
if (j.contains("ID"))

View File

@@ -41,9 +41,8 @@ namespace Nuake
END_SERIALIZE();
}
bool Deserialize(std::string str)
bool Deserialize(const json& j)
{
BEGIN_DESERIALIZE();
this->HasParent = j["HasParent"];
if (HasParent)
{

View File

@@ -0,0 +1,32 @@
#include "src/Scene/Components/ParticleEmitterComponent.h"
namespace Nuake
{
json ParticleEmitterComponent::Serialize()
{
BEGIN_SERIALIZE();
SERIALIZE_VEC4(ParticleColor);
SERIALIZE_VAL(Amount);
SERIALIZE_VAL(Life);
SERIALIZE_VAL(Rate);
SERIALIZE_VEC3(Gravity);
SERIALIZE_VAL(GravityRandom);
SERIALIZE_VAL(Radius);
END_SERIALIZE();
}
bool ParticleEmitterComponent::Deserialize(const json& j)
{
DESERIALIZE_VEC4(j["ParticleColor"], ParticleColor);
Amount = j["Amount"];
Life = j["Life"];
if (j.contains("Rate"))
{
Rate = j["Rate"];
}
DESERIALIZE_VEC3(j["Gravity"], Gravity);
GravityRandom = j["GravityRandom"];
Radius = j["Radius"];
return true;
}
}

View File

@@ -0,0 +1,34 @@
#pragma once
#include "src/Core/Core.h"
#include "src/Core/Maths.h"
#include "src/Resource/Serializable.h"
#include "src/Scene/Systems/ParticleEmitter.h"
namespace Nuake
{
class ParticleEmitterComponent
{
public:
ParticleEmitterComponent() = default;
~ParticleEmitterComponent() = default;
Color ParticleColor;
float Amount;
float Life = 1.0f;
float Rate = 0.0f;
Vector3 Gravity;
float GravityRandom;
// For now use a radius, later should use shape.
float Radius;
ParticleEmitter Emitter;
public:
json Serialize();
bool Deserialize(const json& j);
};
}

View File

@@ -30,9 +30,8 @@ namespace Nuake {
END_SERIALIZE();
}
bool Deserialize(std::string str)
bool Deserialize(const json& j)
{
BEGIN_DESERIALIZE();
if (j.contains("AutoRebuild"))
{
this->AutoRebuild = j["AutoRebuild"];

View File

@@ -13,18 +13,18 @@ namespace Nuake {
Ref<Physics::RigidBody> RigidBodyComponent::GetRigidBody() const
{
return m_Rigidbody;
return Rigidbody;
}
void RigidBodyComponent::SyncTransformComponent(TransformComponent* tc)
{
if (!m_Rigidbody)
if (!GetRigidBody())
return;
}
void RigidBodyComponent::SyncWithTransform(TransformComponent* tc)
{
if (!m_Rigidbody)
if (!GetRigidBody())
return;
}

View File

@@ -13,7 +13,7 @@ namespace Nuake {
{
public:
float Mass;
Ref<Physics::RigidBody> m_Rigidbody;
Ref<Physics::RigidBody> Rigidbody;
RigidBodyComponent();
Ref<Physics::RigidBody> GetRigidBody() const;
@@ -24,6 +24,7 @@ namespace Nuake {
void DrawShape(TransformComponent* tc);
void DrawEditor();
json Serialize()
{
BEGIN_SERIALIZE();
@@ -31,9 +32,8 @@ namespace Nuake {
END_SERIALIZE();
}
bool Deserialize(std::string str)
bool Deserialize(const json& j)
{
BEGIN_DESERIALIZE();
Mass = j["Mass"];
return true;
}

View File

@@ -19,9 +19,8 @@ namespace Nuake {
END_SERIALIZE();
}
bool Deserialize(const std::string& str)
bool Deserialize(const json& j)
{
BEGIN_DESERIALIZE();
this->Radius = j["Radius"];
this->IsTrigger = j["IsTrigger"];
return true;

View File

@@ -0,0 +1,68 @@
#include "SpriteComponent.h"
#include "src/Core/FileSystem.h"
#include "src/Rendering/Textures/TextureManager.h"
#include "src/Rendering/Textures/MaterialManager.h"
#include "src/Rendering/Vertex.h"
namespace Nuake
{
SpriteComponent::SpriteComponent() :
Billboard(false),
LockYRotation(false),
SpritePath("")
{
}
bool SpriteComponent::LoadSprite()
{
std::vector<Vertex> quadVertices =
{
{ Vector3(-1.0f, -1.0f, 0.0f), Vector2(0, 0), Vector3(0, 0, -1) },
{ Vector3(1.0f, 1.0f, 0.0f), Vector2(1.0f, 1.0f), Vector3(0, 0, -1) },
{ Vector3(-1.0f, 1.0f, 0.0f), Vector2(0.0f, 1.0f), Vector3(0, 0, -1) },
{ Vector3(1.0f, -1.0f, 0.0f), Vector2(1.0f, 0.0f), Vector3(0, 0, -1) },
{ Vector3(-1.0f, -1.0f, 0.0f), Vector2(0.0f, 0.0f), Vector3(0, 0, -1) },
{ Vector3(1.0f, 1.0f, 0.0f), Vector2(1.0f, 1.0f), Vector3(0, 0, -1) }
};
SpriteMesh = CreateRef<Mesh>();
SpriteMesh->AddSurface(quadVertices, { 0, 1, 2, 3, 4, 5 });
auto& material = MaterialManager::Get()->GetMaterial(FileSystem::Root + SpritePath);
SpriteMesh->SetMaterial(material);
return true;
}
json SpriteComponent::Serialize()
{
BEGIN_SERIALIZE();
SERIALIZE_VAL(Billboard)
SERIALIZE_VAL(LockYRotation)
SERIALIZE_VAL(SpritePath)
END_SERIALIZE();
}
bool SpriteComponent::Deserialize(const json& j)
{
if (j.contains("Billboard"))
{
Billboard = j["Billboard"];
}
if (j.contains("LockYRotation"))
{
LockYRotation = j["LockYRotation"];
}
if (j.contains("SpritePath"))
{
SpritePath = j["SpritePath"];
LoadSprite();
}
return true;
}
}

Some files were not shown because too many files have changed in this diff Show More