Added Screen space reflections and Editor UI refactoring

This commit is contained in:
antopilo
2022-01-31 13:54:58 -05:00
parent e216686272
commit b273a2fb8a
78 changed files with 2454 additions and 946 deletions

View File

@@ -1,16 +1,21 @@
#include <Engine.h>
#include "src/Core/Maths.h"
#include <src/Scene/Entities/Entity.h>
#include <src/Core/Maths.h>
#include "src/Core/Input.h"
#include <src/Scene/Scene.h>
#include <src/Scene/Entities/Entity.h>
#include <src/Scene/Components/Components.h>
#include "src/Windows/EditorInterface.h"
#include <src/Scene/Components/QuakeMap.h>
#include <src/Vendors/imgui/imgui.h>
#include <src/Vendors/imgui/ImGuizmo.h>
#include <src/Scene/Components/Components.h>
#include <src/Core/Physics/PhysicsManager.h>
#include "src/Scene/Components/BoxCollider.h"
#include "src/EditorInterface.h"
#include "src/Core/Input.h"
#include <GLFW/glfw3.h>
#include <src/Vendors/glm/trigonometric.hpp>
#include <src/Scripting/ScriptingEngine.h>
@@ -20,6 +25,7 @@
#include "src/UI/UserInterface.h"
#include "src/NewEditor.h"
#include <src/Scene/Components/BSPBrushComponent.h>
#include "src/Actions/EditorSelection.h"
std::string WindowTitle = "Nuake Engine";
@@ -38,13 +44,6 @@ void OpenProject()
project->FullPath = projectPath;
Nuake::Engine::LoadProject(project);
// Create new interface named test.
//userInterface = UI::UserInterface::New("test");
// Set current interface running.
//Engine::GetCurrentScene()->AddInterface(userInterface);
}
std::vector<Nuake::LineVertex> vertices
@@ -168,10 +167,10 @@ int main()
ditherShader->SetUniform1f("u_Time", Nuake::Engine::GetTime());
ditherShader->SetUniform4f("u_Color", 252.0 / 255.0, 3.0 / 255.0, 65.0 / 255.0, 1.0);
if (editor.m_IsEntitySelected && editor.m_SelectedEntity.HasComponent<Nuake::BSPBrushComponent>())
if (editor.Selection.Type == EditorSelectionType::Entity && editor.Selection.Entity.HasComponent<Nuake::BSPBrushComponent>())
{
for (auto& m : editor.m_SelectedEntity.GetComponent<Nuake::BSPBrushComponent>().Meshes)
Nuake::Renderer::SubmitMesh(m, editor.m_SelectedEntity.GetComponent<Nuake::TransformComponent>().GetGlobalTransform());
for (auto& m : editor.Selection.Entity.GetComponent<Nuake::BSPBrushComponent>().Meshes)
Nuake::Renderer::SubmitMesh(m, editor.Selection.Entity.GetComponent<Nuake::TransformComponent>().GetGlobalTransform());
Nuake::Renderer::Flush(ditherShader, true);
}
@@ -179,10 +178,10 @@ int main()
ditherShader->SetUniform1f("u_Time", Nuake::Engine::GetTime() / 10.0f);
ditherShader->SetUniform4f("u_Color", 52.f / 255.f, 235.f / 255.f, 88.f / 255.f, 1);
auto cubeCollidersView = currentScene->m_Registry.view<Nuake::TransformComponent, Nuake::BoxColliderComponent>();
if (editor.m_IsEntitySelected && editor.m_SelectedEntity.HasComponent<Nuake::BoxColliderComponent>())
if (editor.Selection.Type == EditorSelectionType::Entity && editor.Selection.Entity.HasComponent<Nuake::BoxColliderComponent>())
{
auto transformComponent = editor.m_SelectedEntity.GetComponent<Nuake::TransformComponent>();
auto colliderComponent = editor.m_SelectedEntity.GetComponent<Nuake::BoxColliderComponent>();
auto transformComponent = editor.Selection.Entity.GetComponent<Nuake::TransformComponent>();
auto colliderComponent = editor.Selection.Entity.GetComponent<Nuake::BoxColliderComponent>();
Nuake::Matrix4 transform = transformComponent.GetGlobalTransform();
transform = glm::scale(transform, colliderComponent.Size);
Nuake::Renderer::SubmitCube(transform);
@@ -194,9 +193,9 @@ int main()
sceneFramebuffer->Unbind();
editor.Draw();
Nuake::Engine::EndDraw();
}
Nuake::Engine::Close();
}
}

16
Editor/resource.h Normal file
View File

@@ -0,0 +1,16 @@
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by Editor.rc
//
#define IDI_ICON1 101
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 102
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1001
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif

View File

@@ -0,0 +1,31 @@
#shader vertex
#version 460 core
layout(location = 0) in vec3 VertexPosition;
layout(location = 1) in vec2 UVPosition;
out flat vec2 UV;
void main()
{
UV = UVPosition;
gl_Position = vec4(VertexPosition, 1.0f);
}
#shader fragment
#version 460 core
uniform sampler2D u_Source;
uniform sampler2D u_Source2;
in vec2 UV;
out vec4 FragColor;
void main()
{
vec4 a = texture(u_Source, UV);
vec4 b = texture(u_Source2, UV);
FragColor = vec4(vec3(a.rgb + b.rgb / 2.0), a.a * b.a);
}

View File

@@ -117,25 +117,51 @@ vec3 fresnelSchlickRoughness(float cosTheta, vec3 F0, float roughness)
return F0 + (max(vec3(1.0 - roughness), F0) - F0) * pow(max(1.0 - cosTheta, 0.0), 5.0);
}
float ShadowCalculation(Light light, vec3 FragPos, vec3 normal)
int GetCSMDepth(float depth, Light light)
{
// Get Depth
float depth = length(FragPos - u_EyePosition);
int shadowmap = 0;
int shadowmap = -1;
// Get CSM depth
for (int i = 0; i < 4; i++)
{
float CSMDepth = light.CascadeDepth[i];
if (depth < CSMDepth + 0.0001)
if (depth < CSMDepth + 0.0001f)
{
shadowmap = i;
break;
}
}
return shadowmap;
}
float SampleShadowMap(sampler2D shadowMap, vec2 coords, float compare)
{
return step(compare, texture(shadowMap, coords.xy).r);
}
float SampleShadowMapLinear(sampler2D shadowMap, vec2 coords, float compare, vec2 texelSize)
{
vec2 pixelPos = coords / texelSize + vec2(0.5);
vec2 fracPart = fract(pixelPos);
vec2 startTexel = (pixelPos - fracPart) * texelSize;
float blTexel = SampleShadowMap(shadowMap, startTexel, compare);
float brTexel = SampleShadowMap(shadowMap, startTexel + vec2(texelSize.x, 0.0), compare);
float tlTexel = SampleShadowMap(shadowMap, startTexel + vec2(0.0, texelSize.y), compare);
float trTexel = SampleShadowMap(shadowMap, startTexel + texelSize, compare);
float mixA = mix(blTexel, tlTexel, fracPart.y);
float mixB = mix(brTexel, trTexel, fracPart.y);
return mix(mixA, mixB, fracPart.x);
}
float ShadowCalculation(Light light, vec3 FragPos, vec3 normal)
{
// Get Depth
float depth = length(FragPos - u_EyePosition);
int shadowmap = GetCSMDepth(depth, light);
if (shadowmap == -1)
return 1.0;
@@ -149,18 +175,40 @@ float ShadowCalculation(Light light, vec3 FragPos, vec3 normal)
// get depth of current fragment from light's perspective
float currentDepth = projCoords.z;
// check whether current frag pos is in shadow
float bias = max(0.005 * (1.0 - dot(normal, light.Direction)), 0.0005);
float shadow = 0.0;
float bias = max(0.005 * (1.0 - dot(normal, light.Direction)), 0.0005);
//float pcfDepth = texture(ShadowMaps[shadowmap], vec3(projCoords.xy, currentDepth), bias);
float pcfDepth = texture(ShadowMaps[shadowmap], projCoords.xy).r;
return currentDepth - bias > pcfDepth ? 1.0 : 0.0;
if (shadowmap <= 3)
{
const float NUM_SAMPLES = 4.f;
const float SAMPLES_START = (NUM_SAMPLES - 1.0f) / 2.0f;
const float NUM_SAMPLES_SQUARED = NUM_SAMPLES * NUM_SAMPLES;
vec2 texelSize = 1.0 / vec2(2048, 2048);
float result = 0.0f;
for (float y = -SAMPLES_START; y <= SAMPLES_START; y += 1.0f)
{
for (float x = -SAMPLES_START; x <= SAMPLES_START; x += 1.0f)
{
vec2 coordsOffset = vec2(x, y) * texelSize;
result += SampleShadowMapLinear(ShadowMaps[shadowmap], projCoords.xy + coordsOffset, currentDepth - bias, texelSize);
}
}
return result / NUM_SAMPLES_SQUARED;
}
else
{
return SampleShadowMap(ShadowMaps[shadowmap], projCoords.xy, currentDepth - bias);
}
}
void main()
{
vec3 worldPos = WorldPosFromDepth(texture(m_Depth, UV).r);
if (texture(m_Depth, UV).r == 1)
{
FragColor = vec4(0, 0, 0, 0);
@@ -202,7 +250,7 @@ void main()
vec3 radiance = Lights[i].Color * attenuation ;
if (Lights[i].Type == 0) {
radiance *= 1.0f - shadow;
radiance *= shadow;
}
// Cook-Torrance BRDF
@@ -235,5 +283,18 @@ void main()
vec3 ambient = (kD * albedo) * ao;
vec3 color = ambient + Lo;
// Display CSM splits..
/*float depth = length(worldPos - u_EyePosition);
int cascade = GetCSMDepth(depth, Lights[0]);
if (cascade == 0)
color *= vec3(1.0, 0.0, 0.0);
if (cascade == 1)
color *= vec3(0.0, 1.0, 0.0);
if (cascade == 2)
color *= vec3(0.0, 0.0, 1.0);
if (cascade == 3)
color *= vec3(0.0, 1.0, 1.0);
*/
FragColor = vec4(color, 1.0);
}

View File

@@ -25,7 +25,6 @@ void main()
discard;
vec4 finalColor = u_Color;
finalColor.a = (sin(u_Time * 4.0) + 1.0) / 4.0 + 0.1;
FragColor = finalColor;
}

View File

@@ -17,8 +17,15 @@ out vec2 UV;
void main()
{
vec3 N = normalize((u_Model * vec4(Normal, 0.0f)).xyz);
//mat3 normalMatrix = transpose(inverse(mat3(u_Model)));
//vec3 T = normalize(normalMatrix * Tangent);
//vec3 N = normalize(normalMatrix * Normal);
//T = normalize(T - dot(T, N) * N);
//vec3 B = cross(N, T);
vec3 T = normalize((u_Model * vec4(Tangent, 0.0f)).xyz);
vec3 N = normalize((u_Model * vec4(Normal, 0.0f)).xyz);
vec3 B = normalize((u_Model * vec4(Bitangent, 0.0f)).xyz);
TBN = mat3(T, B, N);
@@ -68,10 +75,8 @@ void main()
if (u_HasNormal == 1)
normal = texture(m_Normal, UV).rgb;
normal = normal * 2.0 - 1.0;
normal = TBN * normalize(normal);
gNormal = vec4(normal, 1.0) / 2.0 + 0.5;
gNormal = vec4(normal / 2.0 + 0.5, 1.0);
// Albedo
gAlbedo = vec4(m_AlbedoColor, 1.0);

View File

@@ -1,5 +1,6 @@
#shader vertex
#version 460 core
layout(location = 0) in vec3 VertexPosition;
layout(location = 1) in vec2 UVPosition;
layout(location = 2) in vec3 Normal;

View File

@@ -0,0 +1,189 @@
#shader vertex
#version 460 core
layout(location = 0) in vec3 VertexPosition;
layout(location = 1) in vec2 UVPosition;
out flat vec2 UV;
void main()
{
UV = UVPosition;
gl_Position = vec4(VertexPosition, 1.0f);
}
#shader fragment
#version 420 core
in vec2 UV;
out vec4 outColor;
uniform sampler2D textureFrame;
uniform sampler2D textureDepth;
uniform sampler2D textureNorm;
uniform sampler2D textureMetallic;
uniform sampler2D textureAlbedo;
uniform mat4 proj;
uniform mat4 invProj;
uniform mat4 view;
uniform mat4 invView;
uniform float rayStep = 0.2f;
uniform int iterationCount = 100;
uniform float distanceBias = 0.05f;
uniform bool enableSSR = true;
uniform int sampleCount = 4;
uniform bool isSamplingEnabled = true;
uniform bool isExponentialStepEnabled = false;
uniform bool isAdaptiveStepEnabled = true;
uniform bool isBinarySearchEnabled = true;
uniform bool debugDraw = false;
uniform float samplingCoefficient = 0.001f;
vec3 ReflectedVector;
float Metallic;
const float reflectionSpecularFalloffExponent = 3.0;
float random(vec2 uv) {
return fract(sin(dot(uv, vec2(12.9898, 78.233))) * 43758.5453123); //simple random function
}
vec3 generatePositionFromDepth(vec2 texturePos, float depth) {
vec4 ndc = vec4((texturePos - 0.5) * 2, depth, 1.f);
vec4 inversed = invProj * ndc;// going back from projected
inversed /= inversed.w;
return inversed.xyz;
}
vec2 generateProjectedPosition(vec3 pos) {
vec4 samplePosition = proj * vec4(pos, 1.f);
samplePosition.xy = (samplePosition.xy / samplePosition.w) * 0.5 + 0.5;
return samplePosition.xy;
}
vec3 SSR(vec3 position, vec3 reflection) {
vec3 step = rayStep * reflection;
vec3 marchingPosition = position + step;
float delta;
float depthFromScreen;
vec2 screenPosition;
int i = 0;
for (; i < iterationCount; i++) {
screenPosition = generateProjectedPosition(marchingPosition);
depthFromScreen = abs(generatePositionFromDepth(screenPosition, textureLod(textureDepth, screenPosition, 2).x).z);
delta = abs(marchingPosition.z) - depthFromScreen;
float depth = textureLod(textureDepth, screenPosition, 2).r;
if (abs(delta) < distanceBias || depthFromScreen > 1000.0f) {
vec3 color = vec3(1);
if (debugDraw)
color = vec3(0.5 + sign(delta) / 2, 0.3, 0.5 - sign(delta) / 2);
vec2 dCoords = smoothstep(0.2, 0.6, abs(vec2(0.5, 0.5) - screenPosition.xy));
float screenEdgefactor = clamp(1.0 - (dCoords.x + dCoords.y), 0.0, 1.0);
float ReflectionMultiplier = pow(Metallic, 3.0) *
screenEdgefactor *
-ReflectedVector.z;
return texture(textureFrame, screenPosition).xyz * color * clamp(ReflectionMultiplier, 0.0, 0.9);
}
if (isBinarySearchEnabled && delta > 0) {
break;
}
if (isAdaptiveStepEnabled) {
float directionSign = sign(abs(marchingPosition.z) - depthFromScreen);
//this is sort of adapting step, should prevent lining reflection by doing sort of iterative converging
//some implementation doing it by binary search, but I found this idea more cheaty and way easier to implement
step = step * (1.0 - rayStep * max(directionSign, 0.0));
marchingPosition += step * (-directionSign);
}
else {
marchingPosition += step;
}
if (isExponentialStepEnabled) {
step *= 1.05;
}
}
if (isBinarySearchEnabled) {
for (; i < iterationCount; i++) {
step *= 0.5;
marchingPosition = marchingPosition - step * sign(delta);
screenPosition = generateProjectedPosition(marchingPosition);
depthFromScreen = abs(generatePositionFromDepth(screenPosition, textureLod(textureDepth, screenPosition, 2).x).z);
delta = abs(marchingPosition.z) - depthFromScreen;
vec2 dCoords = smoothstep(0.2, 0.6, abs(vec2(0.5, 0.5) - screenPosition.xy));
float screenEdgefactor = clamp(1.0 - (dCoords.x + dCoords.y), 0.0, 1.0);
float ReflectionMultiplier = pow(Metallic, 3.0) * screenEdgefactor *
-ReflectedVector.z;
if (abs(delta) < distanceBias) {
return texture(textureFrame, screenPosition).xyz * clamp(ReflectionMultiplier, 0.0, 0.9);
}
}
}
return vec3(0.0);
}
vec3 fresnelSchlick(float cosTheta, vec3 F0)
{
return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0);
}
void main() {
vec3 position = generatePositionFromDepth(UV, textureLod(textureDepth, UV, 2).x);
vec4 normal = view * vec4(texture(textureNorm, UV).xyz * 2.0 - 1.0, 0.0);
float metallic = texture(textureMetallic, UV).r;
Metallic = metallic;
vec3 albedo = texture(textureAlbedo, UV).rgb;
vec3 F0 = vec3(0.04);
F0 = mix(F0, albedo, metallic);
vec3 Fresnel = fresnelSchlick(max(dot(normalize(normal.rgb), normalize(position)), 0.0), F0);
if (!enableSSR || metallic < 0.01) {
discard;// outColor = mix(texture(textureFrame, UV), normal, 0.9);
}
else {
vec3 reflectionDirection = normalize(reflect(position, normalize(normal.xyz)));
ReflectedVector = reflectionDirection;
if (isSamplingEnabled) {
vec3 firstBasis = normalize(cross(vec3(0.f, 0.f, 1.f), reflectionDirection));
vec3 secondBasis = normalize(cross(reflectionDirection, firstBasis));
vec4 resultingColor = vec4(0.f);
for (int i = 0; i < sampleCount; i++) {
vec2 coeffs = vec2(random(UV + vec2(0, i)) + random(UV + vec2(i, 0))) * samplingCoefficient;
vec3 reflectionDirectionRandomized = reflectionDirection + firstBasis * coeffs.x + secondBasis * coeffs.y;
vec3 tempColor = SSR(position, normalize(reflectionDirectionRandomized));
if(tempColor != vec3(0))
resultingColor += vec4(tempColor, 1.0f);
}
if(resultingColor.w != 0)
resultingColor /= resultingColor.w;
if (resultingColor.xyz == vec3(0.0f))
{
outColor = vec4(1, 0, 0, 0);
return;
}
outColor = vec4(resultingColor.xyz * Fresnel, metallic) ;
}
else {
outColor = vec4(SSR(position, normalize(reflectionDirection)) * Fresnel, metallic);
if (outColor.xyz == vec3(0.f)) {
outColor = texture(textureFrame, UV);
}
}
}
}

View File

@@ -37,11 +37,12 @@ struct Light {
mat4 transform;
vec3 color;
vec3 direction;
sampler2D shadowmap;
int shadowmap;
};
uniform Light u_Lights[MAX_LIGHT];
uniform sampler2D lightShadowmap;
in vec2 UV;
out vec4 FragColor;
@@ -57,7 +58,8 @@ float ComputeScattering(float lightDotView)
vec3 ComputeVolumetric(vec3 FragPos, Light light)
{
vec3 rayVector = FragPos - u_CamPosition; // Ray Direction
vec3 startPosition = u_CamPosition; // Camera Position
vec3 rayVector = FragPos - startPosition; // Ray Direction
float rayLength = length(rayVector); // Length of the raymarched
@@ -68,7 +70,7 @@ vec3 ComputeVolumetric(vec3 FragPos, Light light)
vec3 accumFog = vec3(0.0f, 0.0f, 0.0f); // accumulative color
// Raymarching
vec3 currentPosition = u_CamPosition;
vec3 currentPosition = startPosition;
for (int i = 0; i < u_StepCount; i++)
{
vec4 fragPosLightSpace = light.transform * vec4(currentPosition, 1.0f);
@@ -78,7 +80,7 @@ vec3 ComputeVolumetric(vec3 FragPos, Light light)
projCoords = projCoords * 0.5 + 0.5;
float currentDepth = projCoords.z;
float closestDepth = texture(light.shadowmap, projCoords.xy).r;
float closestDepth = texture(lightShadowmap, projCoords.xy).r;
if (closestDepth > currentDepth)
accumFog += (ComputeScattering(dot(rayDirection, normalize(light.direction))).xxx * light.color);
@@ -110,11 +112,10 @@ void main()
vec3 globalFragmentPosition = WorldPosFromDepth(depth);
vec3 fog = vec3(0, 0, 0);
for (int i = 0; i < u_LightCount; i++)
{
fog += ComputeVolumetric(globalFragmentPosition, u_Lights[i]);
}
FragColor = vec4(mix(fog, vec3(depth), 0.01), 1.0);
FragColor = vec4(mix(fog, ComputeVolumetric(globalFragmentPosition, u_Lights[0]), 0.9f), 1.0);
}

View File

@@ -0,0 +1,49 @@
#pragma once
#include "src/Core/Core.h"
#include "src/Scene/Entities/Entity.h"
#include "src/Resource/Resource.h"
enum EditorSelectionType {
None,
Entity,
File,
Resource,
};
class EditorSelection {
public:
EditorSelectionType Type = EditorSelectionType::None;
Nuake::Entity Entity;
Ref<Nuake::File> File;
Nuake::Resource Resource;
EditorSelection()
{
Type = None;
}
EditorSelection(const Nuake::Entity& entity)
{
Type = EditorSelectionType::Entity;
Entity = entity;
}
EditorSelection(const Ref<Nuake::File>& file)
{
Type = EditorSelectionType::File;
File = file;
}
EditorSelection(const Nuake::Resource& resource)
{
Type = EditorSelectionType::Resource;
Resource = resource;
}
operator bool()
{
return Type != None;
}
};

View File

@@ -0,0 +1,89 @@
#pragma once
#include "src/Scene/Entities/Entity.h"
#include "../Misc/InterfaceFonts.h"
#include <src/Vendors/imgui/imgui.h>
#include <src/Resource/FontAwesome5.h>
#define MenuItemComponent(label, Component) \
if(entity.HasComponent<Component>()) \
ImGui::Text(label); \
else if (ImGui::MenuItem(label)) \
entity.AddComponent<Component>();
#define BeginComponentTable(name, component) \
UIFont* boldFont = new UIFont(Fonts::Bold); \
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.f, 0.f)); \
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0.f, 8.f)); \
bool removed = false; \
bool headerOpened = ImGui::CollapsingHeader(#name, ImGuiTreeNodeFlags_DefaultOpen); \
if (#name != "TRANSFORM" && ImGui::BeginPopupContextItem()) \
{ \
if (ImGui::Selectable("Remove")) { removed = true; } \
ImGui::EndPopup(); \
} \
\
if(removed) \
{ \
entity.RemoveComponent<component>(); \
ImGui::PopStyleVar(); \
delete boldFont; \
} \
else if (headerOpened) \
{ \
delete boldFont; \
ImGui::PopStyleVar(); \
if (ImGui::BeginTable(#name, 3, ImGuiTableFlags_BordersInner)) \
{ \
ImGui::TableSetupColumn("name", 0, 0.3f); \
ImGui::TableSetupColumn("set", 0, 0.6f); \
ImGui::TableSetupColumn("reset", 0, 0.1f); \
\
ImGui::TableNextColumn();
#define EndComponentTable() \
ImGui::EndTable(); \
} \
} \
else \
{ \
ImGui::PopStyleVar(); \
delete boldFont; \
} \
ImGui::PopStyleVar();
#define ComponentTableReset(setting, value) \
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1, 1, 1, 0)); \
std::string resetLabel = std::string(ICON_FA_UNDO) + "##Reset" + #setting; \
if (ImGui::Button(resetLabel.c_str())) setting = value; \
ImGui::PopStyleColor();
#define ComponentDropDown(arrayData, enumData, value) \
const char* current_item = arrayData[(int)value]; \
if (ImGui::BeginCombo("Type", current_item)) \
{ \
for (int n = 0; n < IM_ARRAYSIZE(arrayData); n++) \
{ \
bool is_selected = (current_item == arrayData[n]); \
if (ImGui::Selectable(arrayData[n], is_selected)) \
{ \
current_item = arrayData[n]; \
value = (enumData)n; \
} \
if (is_selected) \
ImGui::SetItemDefaultFocus(); \
} \
ImGui::EndCombo(); \
}
class ComponentPanel {
public:
virtual void Draw(Nuake::Entity entity) = 0;
};

View File

@@ -0,0 +1,106 @@
#pragma once
#include "ComponentPanel.h"
#include "src/Scene/Components/LightComponent.h"
class LightPanel :ComponentPanel {
public:
LightPanel() { }
void Draw(Nuake::Entity entity) override
{
if (!entity.HasComponent<Nuake::LightComponent>())
return;
Nuake::LightComponent& component = entity.GetComponent<Nuake::LightComponent>();
BeginComponentTable(LIGHT, Nuake::LightComponent);
{
{
ImGui::Text("Color");
ImGui::TableNextColumn();
ImGui::PushItemWidth(ImGui::GetContentRegionAvailWidth());
ImGui::ColorEdit3("##lightcolor", &component.Color.r, ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel);
ImGui::PopItemWidth();
ImGui::TableNextColumn();
ComponentTableReset(component.Color, Nuake::Vector3(1, 1, 1));
}
ImGui::TableNextColumn();
{
ImGui::Text("Strength");
ImGui::TableNextColumn();
ImGui::SliderFloat("Strength", &component.Strength, 0.0f, 100.0f);
ImGui::TableNextColumn();
ComponentTableReset(component.Strength, 10.f);
}
ImGui::TableNextColumn();
{
ImGui::Text("Cast Shadows");
ImGui::TableNextColumn();
// Using the SetCastShadows allows to create Framebuffers.
bool castShadows = component.CastShadows;
ImGui::Checkbox("##CastShadows", &castShadows);
if (castShadows != component.CastShadows)
component.SetCastShadows(castShadows);
ImGui::TableNextColumn();
ComponentTableReset(component.CastShadows, false);
}
ImGui::TableNextColumn();
{
ImGui::Text("Type");
ImGui::TableNextColumn();
const char* lightTypes[] = { "Directional", "Point", "Spot" };
ComponentDropDown(lightTypes, Nuake::LightType, component.Type)
ImGui::TableNextColumn();
ComponentTableReset(component.Type, Nuake::LightType::Point);
}
ImGui::TableNextColumn();
if (component.Type == Nuake::LightType::Directional)
{
{
ImGui::Text("Is Volumetric");
ImGui::TableNextColumn();
ImGui::Checkbox("##Volumetric", &component.IsVolumetric);
ImGui::TableNextColumn();
ComponentTableReset(component.IsVolumetric, false);
}
ImGui::TableNextColumn();
{
ImGui::Text("Sync Direction with sky");
ImGui::TableNextColumn();
ImGui::Checkbox("##SyncSky", &component.SyncDirectionWithSky);
ImGui::TableNextColumn();
ComponentTableReset(component.SyncDirectionWithSky, false);
// Light direction is only useful if it is not overriden by the procedural sky direction
if (!component.SyncDirectionWithSky)
{
ImGui::TableNextColumn();
{
ImGui::Text("Direction");
ImGui::TableNextColumn();
ImGuiHelper::DrawVec3("Direction", &component.Direction);
ImGui::TableNextColumn();
ComponentTableReset(component.Direction, Nuake::Vector3(0, -1, 0));
}
}
}
}
}
EndComponentTable();
}
};

View File

@@ -0,0 +1,43 @@
#pragma once
#include "ComponentPanel.h"
#include <src/Scene/Entities/ImGuiHelper.h>
#include <src/Scene/Components/MeshComponent.h>
class MeshPanel : ComponentPanel {
public:
MeshPanel() {}
void Draw(Nuake::Entity entity) override
{
if (!entity.HasComponent<Nuake::MeshComponent>())
return;
Nuake::MeshComponent& component = entity.GetComponent<Nuake::MeshComponent>();
BeginComponentTable(MESH, Nuake::MeshComponent);
{
ImGui::Text("Mesh");
ImGui::TableNextColumn();
std::string path = component.ModelPath;
ImGui::Button(component.ModelPath.c_str(), ImVec2(ImGui::GetContentRegionAvail().x, 0));
if (ImGui::BeginDragDropTarget())
{
if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("_Model"))
{
char* file = (char*)payload->Data;
std::string fullPath = std::string(file, 256);
path = Nuake::FileSystem::AbsoluteToRelative(fullPath);
component.ModelPath = path;
component.LoadModel();
}
ImGui::EndDragDropTarget();
}
ImGui::TableNextColumn();
ComponentTableReset(component.ModelPath, "");
}
EndComponentTable();
}
};

View File

@@ -0,0 +1,70 @@
#pragma once
#include "ComponentPanel.h"
#include <src/Scene/Components/QuakeMap.h>
#include "src/Scene/Systems/QuakeMapBuilder.h"
#include <src/Core/FileSystem.h>
class QuakeMapPanel : ComponentPanel {
public:
QuakeMapPanel() {}
void Draw(Nuake::Entity entity) override
{
if (!entity.HasComponent<Nuake::QuakeMapComponent>())
return;
Nuake::QuakeMapComponent& component = entity.GetComponent<Nuake::QuakeMapComponent>();
BeginComponentTable(QUAKEMAP, Nuake::QuakeMapComponent);
{
{
ImGui::Text("Map");
ImGui::TableNextColumn();
std::string path = component.Path;
ImGui::Button(component.Path.c_str(), ImVec2(ImGui::GetContentRegionAvail().x, 0));
if (ImGui::BeginDragDropTarget())
{
if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("_Map"))
{
char* file = (char*)payload->Data;
std::string fullPath = std::string(file, 256);
path = Nuake::FileSystem::AbsoluteToRelative(fullPath);
component.Path = path;
}
ImGui::EndDragDropTarget();
}
ImGui::TableNextColumn();
ComponentTableReset(component.Path, "");
}
ImGui::TableNextColumn();
{
ImGui::Text("Collision");
ImGui::TableNextColumn();
ImGui::Checkbox("#Collison", &component.HasCollisions);
ImGui::TableNextColumn();
ComponentTableReset(component.HasCollisions, true);
}
ImGui::TableNextColumn();
{
ImGui::Text("Build");
ImGui::TableNextColumn();
if (ImGui::Button("Build"))
{
Nuake::QuakeMapBuilder builder;
builder.BuildQuakeMap(entity, component.HasCollisions);
}
ImGui::TableNextColumn();
//ComponentTableReset(component.Class, "");
}
}
EndComponentTable();
}
};

View File

@@ -0,0 +1,65 @@
#pragma once
#include "ComponentPanel.h"
#include <src/Scene/Components/WrenScriptComponent.h>
#include <src/Core/FileSystem.h>
class ScriptPanel : ComponentPanel {
public:
ScriptPanel() {}
void Draw(Nuake::Entity entity) override
{
if (!entity.HasComponent<Nuake::WrenScriptComponent>())
return;
Nuake::WrenScriptComponent& component = entity.GetComponent<Nuake::WrenScriptComponent>();
BeginComponentTable(SCRIPT, Nuake::WrenScriptComponent);
{
{
ImGui::Text("Script");
ImGui::TableNextColumn();
std::string path = component.Script;
ImGui::Button(component.Script.c_str(), ImVec2(ImGui::GetContentRegionAvail().x, 0));
if (ImGui::BeginDragDropTarget())
{
if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("_Script"))
{
char* file = (char*)payload->Data;
std::string fullPath = std::string(file, 256);
path = Nuake::FileSystem::AbsoluteToRelative(fullPath);
Ref<Nuake::File> nuakeFile = Nuake::FileSystem::GetFile(path);
component.mWrenScript = CreateRef<Nuake::WrenScript>(nuakeFile, true);
auto& modules = component.mWrenScript->GetModules();
}
ImGui::EndDragDropTarget();
}
component.Script = path;
//
//ImGuiHelper::DrawVec3("Translation", &component.Translation);
ImGui::TableNextColumn();
ComponentTableReset(component.Script, "");
}
ImGui::TableNextColumn();
{
ImGui::Text("Module");
ImGui::TableNextColumn();
// Todo: Automatically parse available modules. and offer a dropdown
//ImGuiHelper::DrawVec3("Rotation", &component.Rotation);
ImGui::TableNextColumn();
//ComponentTableReset(component.Class, "");
}
}
EndComponentTable();
}
};

View File

@@ -0,0 +1,48 @@
#pragma once
#include "ComponentPanel.h"
#include <src/Scene/Entities/ImGuiHelper.h>
#include <src/Scene/Components/TransformComponent.h>
class TransformPanel : ComponentPanel {
public:
TransformPanel() {}
void Draw(Nuake::Entity entity) override
{
Nuake::TransformComponent& component = entity.GetComponent<Nuake::TransformComponent>();
BeginComponentTable(TRANSFORM, Nuake::TransformComponent);
{
{
ImGui::Text("Translation");
ImGui::TableNextColumn();
ImGuiHelper::DrawVec3("Translation", &component.Translation);
ImGui::TableNextColumn();
ComponentTableReset(component.Translation, Nuake::Vector3(0, 0, 0));
}
ImGui::TableNextColumn();
{
ImGui::Text("Rotation");
ImGui::TableNextColumn();
ImGuiHelper::DrawVec3("Rotation", &component.Rotation);
ImGui::TableNextColumn();
ComponentTableReset(component.Rotation, Nuake::Vector3(0, 0, 0));
}
ImGui::TableNextColumn();
{
ImGui::Text("Scale");
ImGui::TableNextColumn();
ImGuiHelper::DrawVec3("Scale", &component.Scale);
ImGui::TableNextColumn();
ComponentTableReset(component.Scale, Nuake::Vector3(1, 1, 1));
}
}
EndComponentTable();
}
};

View File

@@ -1,8 +0,0 @@
#pragma once
class GizmoDrawer
{
void Draw();
};

View File

@@ -1,9 +1,7 @@
#pragma once
#include <vcruntime_string.h>
#include <string>
#include <src/Vendors/imgui/imgui.h>
void ImGuiTextSTD(const std::string& label, std::string& value)
{
char buffer[256];

View File

@@ -0,0 +1,38 @@
#pragma once
#include "InterfaceFonts.h"
#include <src/Vendors/imgui/imgui.h>
#include <src/Resource/FontAwesome5.h>
std::map<Fonts, ImFont*> FontManager::mFonts = std::map<Fonts, ImFont*>();
void FontManager::LoadFonts()
{
ImGuiIO& io = ImGui::GetIO(); (void)io;
static const ImWchar icons_ranges[] = { ICON_MIN_FA, ICON_MAX_FA, 0 };
ImFontConfig icons_config; icons_config.MergeMode = true; icons_config.PixelSnapH = true;
mFonts[Normal] = io.Fonts->AddFontFromFileTTF("resources/Fonts/fa-solid-900.ttf", 11.0f, &icons_config, icons_ranges);
mFonts[Bold] = io.Fonts->AddFontFromFileTTF("resources/Fonts/OpenSans-Bold.ttf", 16.0);
mFonts[LargeBold] = io.Fonts->AddFontFromFileTTF("resources/Fonts/OpenSans-Regular.ttf", 32);
mFonts[Title] = io.Fonts->AddFontFromFileTTF("resources/Fonts/OpenSans-Bold.ttf", 50.0);
mFonts[SubTitle] = io.Fonts->AddFontFromFileTTF("resources/Fonts/OpenSans-Regular.ttf", 24.0);
ImGui::GetIO().Fonts->AddFontDefault();
icons_config.MergeMode = true;
mFonts[BigIcon] = io.Fonts->AddFontFromFileTTF("resources/Fonts/fa-solid-900.ttf", 42.0f, &icons_config, icons_ranges);
}
ImFont* FontManager::GetFont(Fonts font)
{
return mFonts[font];
}
UIFont::UIFont(Fonts font)
{
ImGuiFont = FontManager::GetFont(font);
ImGui::PushFont(ImGuiFont);
}
UIFont::~UIFont()
{
ImGui::PopFont();
}

View File

@@ -0,0 +1,28 @@
#pragma once
#include <map>
enum Fonts {
Normal, Bold, LargeBold, Icons, BigIcon, Title, SubTitle
};
class ImFont;
// Help class that automatically push and pops itself when
// Reaching end of scope
class UIFont {
private:
ImFont* ImGuiFont;
public:
UIFont(Fonts font);
~UIFont();
};
class FontManager {
private:
static std::map < Fonts, ImFont*> mFonts;
public:
static void LoadFonts();
static ImFont* GetFont(Fonts font);
};

View File

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

View File

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

View File

@@ -3,18 +3,20 @@
#include "src/Vendors/imgui/imgui.h"
#include <src/Vendors/imgui/ImGuizmo.h>
#include "src/Core/FileSystem.h"
#include "FileSystemUI.h"
#include "../Actions/EditorSelection.h"
#include "EditorSelectionPanel.h"
namespace Nuake {
class Material;
class FileSystemUI;
class EditorInterface
{
private:
FileSystemUI filesystem = FileSystemUI();
FileSystemUI* filesystem;
bool m_DrawGrid = false;
bool m_ShowImGuiDemo = false;
bool m_DebugCollisions = false;
@@ -27,8 +29,11 @@ namespace Nuake {
bool m_IsMaterialSelected = false;
public:
bool m_IsEntitySelected = false;
Entity m_SelectedEntity;
EditorSelection Selection;
EditorSelectionPanel SelectionPanel;
EditorInterface();
static ImFont* bigIconFont;
void BuildFonts();
void Init();

View File

@@ -0,0 +1,357 @@
#include "EditorSelectionPanel.h"
#include "src/Scene/Components/ImportComponents.h"
#include "../Misc/ImGuiTextHelper.h"
EditorSelectionPanel::EditorSelectionPanel()
{
mTransformPanel = TransformPanel();
mLightPanel = LightPanel();
mScriptPanel = ScriptPanel();
mQuakeMapPanel = QuakeMapPanel();
}
void EditorSelectionPanel::Draw(EditorSelection selection)
{
if (ImGui::Begin("Propreties"))
{
switch (selection.Type)
{
case EditorSelectionType::None:
{
DrawNone();
break;
}
case EditorSelectionType::Entity:
{
DrawEntity(selection.Entity);
break;
}
case EditorSelectionType::File:
{
DrawFile(selection.File.get());
break;
}
case EditorSelectionType::Resource:
{
DrawResource(selection.Resource);
break;
}
}
}
ImGui::End();
}
void EditorSelectionPanel::DrawNone()
{
std::string text = "No selection";
auto windowWidth = ImGui::GetWindowSize().x;
auto windowHeight = ImGui::GetWindowSize().y;
auto textWidth = ImGui::CalcTextSize(text.c_str()).x;
auto textHeight = ImGui::CalcTextSize(text.c_str()).y;
ImGui::SetCursorPosX((windowWidth - textWidth) * 0.5f);
ImGui::SetCursorPosY((windowHeight - textHeight) * 0.5f);
ImGui::Text(text.c_str());
}
void EditorSelectionPanel::DrawEntity(Nuake::Entity entity)
{
DrawAddComponentMenu(entity);
// Draw each component properties panels.
mTransformPanel.Draw(entity);
mLightPanel.Draw(entity);
mScriptPanel.Draw(entity);
mMeshPanel.Draw(entity);
mQuakeMapPanel.Draw(entity);
/*
if (Selection.Entity.HasComponent<MeshComponent>())
{
std::string icon = ICON_FA_MALE;
if (ImGui::CollapsingHeader((icon + " " + "Mesh").c_str(), ImGuiTreeNodeFlags_DefaultOpen))
{
ImGui::TextColored(ImGui::GetStyleColorVec4(1), "Mesh properties");
auto& component = Selection.Entity.GetComponent<MeshComponent>();
// Path
std::string path = component.ModelPath;
char pathBuffer[256];
memset(pathBuffer, 0, sizeof(pathBuffer));
std::strncpy(pathBuffer, path.c_str(), sizeof(pathBuffer));
std::string oldPath = component.ModelPath;
ImGui::Text("Model: ");
ImGui::SameLine();
if (ImGui::InputText("##ModelPath", pathBuffer, sizeof(pathBuffer)))
path = FileSystem::AbsoluteToRelative(std::string(pathBuffer));
if (ImGui::BeginDragDropTarget())
{
if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("_Model"))
{
char* file = (char*)payload->Data;
std::string fullPath = std::string(file, 256);
path = FileSystem::AbsoluteToRelative(fullPath);
}
ImGui::EndDragDropTarget();
}
if (component.ModelPath != path)
{
component.ModelPath = path;
component.LoadModel();
}
ImGui::SameLine();
if (ImGui::Button("Reimport"))
{
component.LoadModel();
}
ImGui::Indent(16.0f);
if (ImGui::CollapsingHeader("Meshes"))
{
ImGui::Indent(16.0f);
uint16_t index = 0;
for (auto& m : component.meshes)
{
if (ImGui::CollapsingHeader(std::to_string(index).c_str()))
{
std::string materialName = "No material";
if (m->m_Material)
materialName = m->m_Material->GetName();
ImGui::Indent(16.0f);
if (ImGui::CollapsingHeader(materialName.c_str()))
{
//if (ImGui::BeginChild("Material child", ImVec2(0, 0), true, ImGuiWindowFlags_AlwaysAutoResize))
//{
ImGui::Indent(16.0f);
DrawMaterialEditor(m->m_Material);
//}
//ImGui::EndChild();
}
if (ImGui::BeginDragDropTarget())
{
if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("_Material"))
{
char* file = (char*)payload->Data;
std::string fullPath = std::string(file, 256);
path = FileSystem::AbsoluteToRelative(fullPath);
}
ImGui::EndDragDropTarget();
}
}
index++;
}
}
ImGui::Separator();
}
}
if (Selection.Entity.HasComponent<WrenScriptComponent>()) {
std::string icon = ICON_FA_FILE;
if (ImGui::CollapsingHeader((icon + " " + "Wren Script").c_str(), ImGuiTreeNodeFlags_DefaultOpen))
{
ImGui::TextColored(ImGui::GetStyleColorVec4(1), "Script properties");
auto& component = Selection.Entity.GetComponent<WrenScriptComponent>();
// Path
std::string path = component.Script;
char pathBuffer[256];
memset(pathBuffer, 0, sizeof(pathBuffer));
std::strncpy(pathBuffer, path.c_str(), sizeof(pathBuffer));
ImGui::Text("Script: ");
ImGui::SameLine();
if (ImGui::InputText("##ScriptPath", pathBuffer, sizeof(pathBuffer)))
path = FileSystem::AbsoluteToRelative(std::string(pathBuffer));
if (ImGui::BeginDragDropTarget())
{
if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("_Script"))
{
char* file = (char*)payload->Data;
std::string fullPath = std::string(file, 256);
path = FileSystem::AbsoluteToRelative(fullPath);
}
ImGui::EndDragDropTarget();
}
component.Script = path;
// Class
std::string module = component.Class;
char classBuffer[256];
memset(classBuffer, 0, sizeof(classBuffer));
std::strncpy(classBuffer, module.c_str(), sizeof(classBuffer));
ImGui::Text("Class: ");
ImGui::SameLine();
if (ImGui::InputText("##ScriptModule", classBuffer, sizeof(classBuffer)))
module = std::string(classBuffer);
component.Class = module;
ImGui::Separator();
}
}
if (Selection.Entity.HasComponent<CameraComponent>()) {
std::string icon = ICON_FA_LIGHTBULB;
if (ImGui::CollapsingHeader((icon + " " + "Camera").c_str(), ImGuiTreeNodeFlags_DefaultOpen))
{
ImGui::TextColored(ImGui::GetStyleColorVec4(1), "Camera properties");
Selection.Entity.GetComponent<CameraComponent>().DrawEditor();
ImGui::Separator();
}
}
if (Selection.Entity.HasComponent<CharacterControllerComponent>())
{
if (ImGui::CollapsingHeader("Character controller", ImGuiTreeNodeFlags_DefaultOpen))
{
ImGui::TextColored(ImGui::GetStyleColorVec4(1), "Character controller properties");
auto& c = Selection.Entity.GetComponent<CharacterControllerComponent>();
ImGui::InputFloat("Height", &c.Height);
ImGui::InputFloat("Radius", &c.Radius);
ImGui::InputFloat("Mass", &c.Mass);
ImGui::Separator();
}
}
if (Selection.Entity.HasComponent<RigidBodyComponent>())
{
std::string icon = ICON_FA_BOWLING_BALL;
if (ImGui::CollapsingHeader((icon + " Rigidbody").c_str(), ImGuiTreeNodeFlags_DefaultOpen))
{
ImGui::TextColored(ImGui::GetStyleColorVec4(1), "Rigidbody properties");
RigidBodyComponent& rbComponent = Selection.Entity.GetComponent<RigidBodyComponent>();
ImGui::DragFloat("Mass", &rbComponent.mass, 0.1, 0.0);
ImGui::Separator();
}
}
if (Selection.Entity.HasComponent<BoxColliderComponent>())
{
std::string icon = ICON_FA_BOX;
if (ImGui::CollapsingHeader((icon + " Box collider").c_str(), ImGuiTreeNodeFlags_DefaultOpen))
{
ImGui::TextColored(ImGui::GetStyleColorVec4(1), "Box collider properties");
BoxColliderComponent& component = Selection.Entity.GetComponent<BoxColliderComponent>();
ImGuiHelper::DrawVec3("Size", &component.Size);
ImGui::Checkbox("Is trigger", &component.IsTrigger);
ImGui::Separator();
}
}
if (Selection.Entity.HasComponent<SphereColliderComponent>())
{
std::string icon = ICON_FA_CIRCLE;
if (ImGui::CollapsingHeader((icon + " Sphere collider").c_str(), ImGuiTreeNodeFlags_DefaultOpen))
{
ImGui::TextColored(ImGui::GetStyleColorVec4(1), "Sphere properties");
SphereColliderComponent& component = Selection.Entity.GetComponent<SphereColliderComponent>();
ImGui::DragFloat("Radius", &component.Radius, 0.1f, 0.0f, 100.0f);
ImGui::Checkbox("Is trigger", &component.IsTrigger);
ImGui::Separator();
}
}
if (Selection.Entity.HasComponent<QuakeMapComponent>())
{
std::string icon = ICON_FA_BROOM;
if (ImGui::CollapsingHeader((icon + " " + "Quake map").c_str(), ImGuiTreeNodeFlags_DefaultOpen))
{
ImGui::TextColored(ImGui::GetStyleColorVec4(1), "Quake map properties");
auto& component = Selection.Entity.GetComponent<QuakeMapComponent>();
std::string path = component.Path;
char pathBuffer[256];
memset(pathBuffer, 0, sizeof(pathBuffer));
std::strncpy(pathBuffer, path.c_str(), sizeof(pathBuffer));
ImGui::Text("Map file: ");
ImGui::SameLine();
if (ImGui::InputText("##MapPath", pathBuffer, sizeof(pathBuffer)))
{
path = std::string(pathBuffer);
}
if (ImGui::BeginDragDropTarget())
{
if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("_Map"))
{
char* file = (char*)payload->Data;
std::string fullPath = std::string(file, 256);
path = FileSystem::AbsoluteToRelative(fullPath);
}
ImGui::EndDragDropTarget();
}
component.Path = path;
ImGui::InputFloat("Scale factor", &component.ScaleFactor, 0.01f, 0.1f);
ImGui::Checkbox("Build collisions", &component.HasCollisions);
if (ImGui::Button("Build Geometry"))
{
QuakeMapBuilder mapBuilder;
mapBuilder.BuildQuakeMap(Selection.Entity);
}
ImGui::Separator();
}
}*/
}
void EditorSelectionPanel::DrawAddComponentMenu(Nuake::Entity entity)
{
if (entity.HasComponent<Nuake::NameComponent>())
{
auto& entityName = entity.GetComponent<Nuake::NameComponent>().Name;
ImGuiTextSTD("##Name", entityName);
ImGui::SameLine();
if (ImGui::Button("Add Component"))
ImGui::OpenPopup("ComponentPopup");
if (ImGui::BeginPopup("ComponentPopup"))
{
MenuItemComponent("Wren Script", Nuake::WrenScriptComponent);
MenuItemComponent("Camera", Nuake::CameraComponent);
MenuItemComponent("Light", Nuake::LightComponent);
MenuItemComponent("Mesh", Nuake::MeshComponent);
MenuItemComponent("Rigid body", Nuake::RigidBodyComponent);
MenuItemComponent("Box collider", Nuake::BoxColliderComponent);
MenuItemComponent("Sphere collider", Nuake::SphereColliderComponent);
MenuItemComponent("Mesh collider", Nuake::MeshColliderComponent);
MenuItemComponent("Quake map", Nuake::QuakeMapComponent);
ImGui::EndPopup();
}
ImGui::Separator();
}
}
void EditorSelectionPanel::DrawFile(Nuake::File* file)
{
}
void EditorSelectionPanel::DrawResource(Nuake::Resource resource)
{
}

View File

@@ -0,0 +1,30 @@
#pragma once
#include "../Actions/EditorSelection.h"
#include "src/Scene/Entities/Entity.h"
#include "src/Core/FileSystem.h"
#include "../ComponentsPanel/TransformPanel.h"
#include "../ComponentsPanel/LightPanel.h"
#include "../ComponentsPanel/ScriptPanel.h"
#include "../ComponentsPanel/MeshPanel.h"
#include "../ComponentsPanel/QuakeMapPanel.h"
class EditorSelectionPanel {
private:
TransformPanel mTransformPanel;
LightPanel mLightPanel;
ScriptPanel mScriptPanel;
MeshPanel mMeshPanel;
QuakeMapPanel mQuakeMapPanel;
public:
EditorSelectionPanel();
void Draw(EditorSelection selection);
void DrawNone();
void DrawEntity(Nuake::Entity entity);
void DrawAddComponentMenu(Nuake::Entity entity);
void DrawFile(Nuake::File* file);
void DrawResource(Nuake::Resource resource);
};

View File

@@ -114,54 +114,53 @@ namespace Nuake {
void FileSystemUI::DrawFile(Ref<File> file)
{
ImGui::PushFont(EditorInterface::bigIconFont);
if (file->Type == ".png" || file->Type == ".jpg")
std::string fileExtension = file->GetExtension();
if (fileExtension == ".png" || fileExtension == ".jpg")
{
Ref<Texture> texture = TextureManager::Get()->GetTexture(file->fullPath);
Ref<Texture> texture = TextureManager::Get()->GetTexture(file->GetAbsolutePath());
ImGui::ImageButton((void*)texture->GetID(), ImVec2(100, 100), ImVec2(0, 1), ImVec2(1, 0));
}
else
{
const char* icon = ICON_FA_FILE;
if (file->Type == ".shader")
if (fileExtension == ".shader" || fileExtension == ".wren")
icon = ICON_FA_FILE_CODE;
if (file->Type == ".map")
if (fileExtension == ".map")
icon = ICON_FA_BROOM;
if (file->Type == ".ogg" || file->Type == ".mp3" || file->Type == ".wav" || file->Type == ".flac")
if (fileExtension == ".ogg" || fileExtension == ".mp3" || fileExtension == ".wav")
icon = ICON_FA_FILE_AUDIO;
if (file->Type == ".wren")
icon = ICON_FA_FILE_CODE;
if (file->Type == ".md3" || file->Type == ".obj")
if (fileExtension == ".md3" || fileExtension == ".obj")
icon = ICON_FA_FILE_IMAGE;
std::string fullName = icon + std::string("##") + file->fullPath;
std::string fullName = icon + std::string("##") + file->GetAbsolutePath();
if (ImGui::Button(fullName.c_str(), ImVec2(100, 100)))
{
Editor->Selection = EditorSelection(file);
}
if (ImGui::BeginDragDropSource())
{
char pathBuffer[256];
std::strncpy(pathBuffer, file->fullPath.c_str(), sizeof(pathBuffer));
std::strncpy(pathBuffer, file->GetAbsolutePath().c_str(), sizeof(pathBuffer));
std::string dragType;
if (file->Type == ".wren")
if (fileExtension == ".wren")
dragType = "_Script";
else if (file->Type == ".map")
else if (fileExtension == ".map")
dragType = "_Map";
else if (file->Type == ".obj" || file->Type == ".mdl" || file->Type == ".gltf" || file->Type == ".md3" || file->Type == ".fbx")
else if (fileExtension == ".obj" || fileExtension == ".mdl" || fileExtension == ".gltf" || fileExtension == ".md3" || fileExtension == ".fbx")
dragType = "_Model";
else if (file->Type == ".interface")
else if (fileExtension == ".interface")
dragType = "_Interface";
else if (file->Type == ".prefab")
else if (fileExtension == ".prefab")
dragType = "_Prefab";
ImGui::SetDragDropPayload(dragType.c_str(), (void*)(pathBuffer), sizeof(pathBuffer));
ImGui::Text(file->name.c_str());
ImGui::Text(file->GetName().c_str());
ImGui::EndDragDropSource();
}
}
ImGui::Text(file->name.c_str());
ImGui::Text(file->GetName().c_str());
ImGui::PopFont();
}
@@ -266,7 +265,7 @@ namespace Nuake {
{
int width = avail.x;
ImVec2 buttonSize = ImVec2(80, 80);
int amount = (int)(width / 200);
int amount = (int)(width / 100);
if (amount <= 0) amount = 1;
int i = 1; // current amount of item per row.

View File

@@ -1,18 +1,22 @@
#pragma once
#include <src/Core/FileSystem.h>
#include <src/Scene/Entities/Entity.h>
#include "EditorInterface.h"
namespace Nuake {
class FileSystemUI
{
private:
EditorInterface* Editor;
public:
Ref<Directory> m_CurrentDirectory;
FileSystemUI() {
FileSystemUI(EditorInterface* editor) {
m_CurrentDirectory = FileSystem::RootDirectory;
Editor = editor;
}
void Draw();
void DrawDirectoryContent();
void DrawFiletree();

View File

@@ -1,7 +1,7 @@
#include "ProjectInterface.h"
#include <src/Vendors/imgui/imgui.h>
#include "Engine.h"
#include "ImGuiTextHelper.h"
//#include "ImGuiTextHelper.h"
namespace Nuake {
void ProjectInterface::DrawProjectSettings()
@@ -45,7 +45,7 @@ namespace Nuake {
ImGui::Text("Trenchbroom path:");
ImGui::SameLine();
ImGuiTextSTD("", m_CurrentProject->TrenchbroomPath);
//ImGuiTextSTD("", m_CurrentProject->TrenchbroomPath);
ImGui::SameLine();
if (ImGui::Button("Browse"))
{
@@ -62,8 +62,8 @@ namespace Nuake {
auto flags = ImGuiWindowFlags_NoTitleBar;
if (ImGui::BeginPopupModal("Create new point entity", NULL, flags))
{
ImGuiTextSTD("Name", newEntity.Name);
ImGuiTextMultiline("Description", newEntity.Description);
//ImGuiTextSTD("Name", newEntity.Name);
//ImGuiTextMultiline("Description", newEntity.Description);
if (ImGui::BeginTable("DictCreate", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable))
{
@@ -75,7 +75,7 @@ namespace Nuake {
int idx = 0;
for (auto& p : newEntity.Properties)
{
ImGuiTextSTD("Name", p.name);
//ImGuiTextSTD("Name", p.name);
ImGui::TableNextColumn();
std::string current_item = NULL;
if (ImGui::BeginCombo(("TypeSelection" + std::to_string(idx)).c_str(), current_item.c_str()))
@@ -146,18 +146,18 @@ namespace Nuake {
int i = 0;
for (auto& pE : file->PointEntities)
{
ImGuiTextSTD("##PName" + std::to_string(i), pE.Name);
//ImGuiTextSTD("##PName" + std::to_string(i), pE.Name);
for (int i = 0; i < pE.Name.size(); i++)
{
if (pE.Name[i] == ' ')
pE.Name[i] = '_';
}
ImGui::TableNextColumn();
ImGuiTextSTD("Desc" + std::to_string(i), pE.Description);
//ImGuiTextSTD("Desc" + std::to_string(i), pE.Description);
ImGui::TableNextColumn();
ImGui::Button("Edit");
ImGui::TableNextColumn();
ImGuiTextSTD("Prefab##" + std::to_string(i), pE.Prefab);
//ImGuiTextSTD("Prefab##" + std::to_string(i), pE.Prefab);
if (ImGui::BeginDragDropTarget())
{
if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("_Prefab"))
@@ -201,10 +201,10 @@ namespace Nuake {
int i = 0;
for (auto& pE : file->BrushEntities)
{
ImGuiTextSTD("##Name" + std::to_string(i), pE.Name);
//ImGuiTextSTD("##Name" + std::to_string(i), pE.Name);
ImGui::TableNextColumn();
ImGuiTextSTD("Desc" + std::to_string(i), pE.Description);
//ImGuiTextSTD("Desc" + std::to_string(i), pE.Description);
ImGui::TableNextColumn();
ImGui::Checkbox(std::string("Visible##" + std::to_string(i)).c_str(), &pE.Visible);
@@ -215,7 +215,7 @@ namespace Nuake {
ImGui::TableNextColumn();
ImGuiTextSTD("Script##" + std::to_string(i), pE.Script);
//ImGuiTextSTD("Script##" + std::to_string(i), pE.Script);
if (ImGui::BeginDragDropTarget())
{
if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("_Script"))
@@ -227,7 +227,7 @@ namespace Nuake {
ImGui::EndDragDropTarget();
}
ImGuiTextSTD("Class##" + std::to_string(i), pE.Class);
//ImGuiTextSTD("Class##" + std::to_string(i), pE.Class);
ImGui::TableNextColumn();
i++;
@@ -238,8 +238,8 @@ namespace Nuake {
if (ImGui::BeginPopupModal("CreateBrush", NULL, flags))
{
ImGuiTextSTD("Name", newEntity.Name);
ImGuiTextMultiline("Description", newEntity.Description);
//ImGuiTextSTD("Name", newEntity.Name);
//ImGuiTextMultiline("Description", newEntity.Description);
bool isSolid = true;
bool isTrigger = false;

View File

@@ -0,0 +1,83 @@
#include "WelcomeWindow.h"
#include <src/Vendors/imgui/imgui.h>
#include "../Misc/InterfaceFonts.h"
#include <string>
#include <vector>
void WelcomeWindow::Draw()
{
std::vector<std::string> projects = {
"C:/Dev/Nuake-DemoProject/test.project"
};
ImGuiViewport* viewport = ImGui::GetMainViewport();
ImGui::SetNextWindowPos(viewport->GetWorkPos());
ImGui::SetNextWindowSize(viewport->GetWorkSize());
ImGui::SetNextWindowViewport(viewport->ID);
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(32.0f, 32.0f));
ImGui::Begin("AL:SDAL:SKd", 0, ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoResize);
{
{
UIFont boldfont = UIFont(Fonts::Title);
std::string text = "Nuake Engine";
auto windowWidth = ImGui::GetWindowSize().x;
auto textWidth = ImGui::CalcTextSize(text.c_str()).x;
ImGui::SetCursorPosX((windowWidth - textWidth) * 0.5f);
ImGui::Text(text.c_str());
}
{
UIFont boldfont = UIFont(Fonts::SubTitle);
std::string text = "An IdTech inspired game engine";
auto windowWidth = ImGui::GetWindowSize().x;
auto textWidth = ImGui::CalcTextSize(text.c_str()).x;
ImGui::SetCursorPosX((windowWidth - textWidth) * 0.5f);
ImGui::Text(text.c_str());
}
ImGui::Separator();
{
UIFont boldfont = UIFont(Fonts::SubTitle);
ImGui::Text("Projects recently opened");
}
ImVec2 projectsWindowSize = ImGui::GetContentRegionAvail();
projectsWindowSize.x *= 0.6f;
int idx = 0;
ImGui::BeginChild("Projects", projectsWindowSize, true);
{
for (int i = 0; i < 6; i++)
{
float cursorY = ImGui::GetCursorPosY();
std::string selectableName = "##My new project" + std::to_string(i);
ImGui::Selectable(selectableName.c_str(), false, 0, ImVec2(ImGui::GetContentRegionAvailWidth(), 100));
ImGui::SetCursorPosY(cursorY);
{
UIFont boldfont = UIFont(Fonts::LargeBold);
ImGui::Text("Name of project");
}
{
UIFont boldfont = UIFont(Fonts::Bold);
ImGui::Text("last modified on 10/20/2022");
}
{
UIFont boldfont = UIFont(Fonts::Normal);
ImGui::TextWrapped("Description lajsflkahjfklashklashgkASDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDlashglkashlkghalskghaslghaslkghaklsg");
//ImGui::Text("Description lajsflkahjfklashklashgklashglkashlkghalskghaslghaslkghaklsg");
}
ImGui::SetCursorPosY(cursorY + 100);
}
}
ImGui::EndChild();
}
ImGui::End();
ImGui::PopStyleVar();
ImGui::PopStyleVar();
}

View File

@@ -0,0 +1,9 @@
#pragma once
class WelcomeWindow {
public:
int SelectedProject = 0;
void Draw();
};

View File

@@ -85,10 +85,7 @@ namespace Nuake
{
// Dont trigger exit if already not in play mode.
if (IsPlayMode)
{
GetCurrentScene()->OnExit();
Input::ShowMouse();
}
Input::ShowMouse();
IsPlayMode = false;

View File

@@ -75,11 +75,14 @@ namespace Nuake
}
else if (entry.is_regular_file())
{
Ref<File> newFile = CreateRef<File>();
newFile->Type = entry.path().extension().string();
newFile->name = entry.path().filename().string();
newFile->Parent = directory;
newFile->fullPath = entry.path().string();
std::string absolutePath = entry.path().string();
std::string name = entry.path().filename().string();
std::string extension = entry.path().extension().string();
Ref<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);
}
}
@@ -166,4 +169,38 @@ namespace Nuake
return RootDirectory;
}
Ref<File> FileSystem::GetFile(const std::string& path)
{
// Note, Might be broken on other platforms.
auto& splits = String::Split(path, '/');
int currentDepth = -1;
std::string currentDirName = ".";
Ref<Directory> currentDirComparator = RootDirectory;
while (currentDirName == currentDirComparator->name)
{
currentDepth++;
currentDirName = splits[currentDepth];
// Find next directory
for (auto& d : currentDirComparator->Directories)
{
if (d->name == currentDirName)
{
currentDirComparator = d;
}
}
// Find in files if can't find in directories.
for (auto& f : currentDirComparator->Files)
{
if (f->GetName() == currentDirName)
{
return f;
}
}
}
}
}

View File

@@ -4,6 +4,7 @@
#include "Core.h"
#include <iostream>
#include <fstream>
#include "String.h"
namespace Nuake
{
@@ -14,24 +15,8 @@ namespace Nuake
static std::string SaveFile(const char* filter);
};
struct Directory;
struct File
{
std::string Type;
std::string name;
std::string fullPath;
Ref<Directory> Parent;
};
struct Directory
{
std::string name;
std::string fullPath;
Ref<Directory> Parent;
std::vector<Ref<Directory>> Directories;
std::vector<Ref<File>> Files;
};
class Directory;
class File;
class FileSystem
{
@@ -45,6 +30,7 @@ namespace Nuake
static void Scan();
static std::string AbsoluteToRelative(const std::string& path);
static Ref<Directory> GetFileTree();
static Ref<File> GetFile(const std::string& path);
static void ScanDirectory(Ref<Directory> directory);
static void GetDirectories();
@@ -58,4 +44,40 @@ namespace Nuake
static bool WriteLine(const std::string line);
static void EndWriteFile();
};
class File
{
private:
std::string Type;
std::string Name;
std::string RelativePath;
std::string AbsolutePath;
Ref<Directory> Parent;
public:
std::string GetExtension() { return Type; }
std::string GetName() { return Name; }
std::string GetRelativePath() { return RelativePath; }
std::string GetAbsolutePath() { return AbsolutePath; }
Ref<Directory> GetParent() { return Parent; }
File(Ref<Directory> parentDir, const std::string& absolutePath, const std::string& name, const std::string& type)
{
AbsolutePath = absolutePath;
Parent = parentDir;
RelativePath = FileSystem::AbsoluteToRelative(absolutePath);
Name = name;
Type = type;
}
};
class Directory
{
public:
std::string name;
std::string fullPath;
Ref<Directory> Parent;
std::vector<Ref<Directory>> Directories;
std::vector<Ref<File>> Files;
};
}

View File

@@ -0,0 +1,8 @@
#pragma once
namespace Nuake {
class ResourceManager
{
};
}

View File

@@ -52,7 +52,7 @@ namespace Nuake
//cam->cameraRight = glm::normalize(glm::cross(cam->up, cam->cameraFront));
Direction = glm::normalize(direction);
Right = glm::normalize(glm::cross(Vector3(0, 1, 0), Direction));
//Up = glm::normalize(glm::cross(Direction, Right))
}
Vector3 Camera::GetTranslation() {
@@ -72,7 +72,7 @@ namespace Nuake
Matrix4 Camera::GetTransform()
{
glm::mat4 tr = lookAt(Translation, Translation + Direction, Up);
glm::mat4 tr = lookAt(Translation, Translation + Direction, Vector3(0, 1, 0));
return tr;
}

View File

@@ -18,7 +18,7 @@ namespace Nuake
}
}
DirectionalLight::~DirectionalLight()
DirectionalLight::~DirectionalLight()
{
for (int i = 0; i < CSM_SPLIT_AMOUNT; i++)
{
@@ -43,10 +43,6 @@ namespace Nuake
m_CascadeSplits[i] = (d - CSM_NEAR_CLIP) / CSM_CLIP_RANGE;
}
//mCascadeSplits[0] = 0.2f;
//mCascadeSplits[1] = 0.45f;
//mCascadeSplits[2] = 1.0f;
float lastSplitDist = 0.0f;
// Calculate Orthographic Projection matrix for each cascade
for (int cascade = 0; cascade < CSM_SPLIT_AMOUNT; cascade++)
@@ -113,6 +109,9 @@ namespace Nuake
roundOffset = roundOffset * 2.0f / ShadowMapResolution;
roundOffset.z = 0.0f;
roundOffset.w = 0.0f;
lightProjectionMatrix[0] += roundOffset;
lightProjectionMatrix[1] += roundOffset;
lightProjectionMatrix[2] += roundOffset;
lightProjectionMatrix[3] += roundOffset;
// Store SplitDistance and ViewProjection-Matrix

View File

@@ -42,8 +42,8 @@ namespace Nuake {
inline Matrix4 GetCascadeViewProjection(const int i) { return m_CascadeViewProjections[i]; }
private:
static const int CSM_SPLIT_AMOUNT = 4;
const float CSM_NEAR_CLIP = 0.01f;
const float CSM_FAR_CLIP = 1000.0f;
const float CSM_NEAR_CLIP = 0.001f;
const float CSM_FAR_CLIP = 500.0f;
const float CSM_CLIP_RANGE = CSM_FAR_CLIP - CSM_NEAR_CLIP;
const float mCascadeNearPlaneOffset = 0.0;

View File

@@ -0,0 +1,5 @@
#include "SSAO.h"
namespace Nuake {
}

View File

@@ -0,0 +1,8 @@
#pragma once
namespace Nuake {
class SSAO {
};
}

View File

@@ -0,0 +1,65 @@
#include "SSR.h"
#include <dependencies/GLEW/include/GL/glew.h>
#include "src/Rendering/RenderCommand.h"
#include "src/Rendering/Renderer.h"
#include <src/Vendors/imgui/imgui.h>
namespace Nuake {
SSR::SSR()
{
mSize = Vector2(1280, 720);
mShader = ShaderManager::GetShader("resources/Shaders/ssr.shader");
}
void SSR::Init()
{
OutputFramebuffer = CreateRef<FrameBuffer>(false, mSize);
OutputFramebuffer->SetTexture(CreateRef<Texture>(mSize, GL_RGBA, GL_RGBA16F, GL_FLOAT));
}
void SSR::Resize(Vector2 size)
{
if (mSize == size)
return;
mSize = size * 0.5f;
Init();
}
void SSR::Draw(FrameBuffer* gBuffer, Ref<Texture> previousFrame, Matrix4 view, Matrix4 projection, Ref<Camera> cam)
{
OutputFramebuffer->Bind();
{
RenderCommand::Clear();
mShader->Bind();
mShader->SetUniform1f("rayStep", RayStep);
mShader->SetUniform1i("iterationCount", IterationCount);
mShader->SetUniform1f("distanceBias", DistanceBias);
mShader->SetUniform1i("enableSSR", (int)1);
mShader->SetUniform1i("sampleCount", SampleCount);
mShader->SetUniform1i("isSamplingEnabled", SamplingEnabled);
mShader->SetUniform1i("isExponentialStepEnabled", ExpoStep);
mShader->SetUniform1i("isAdaptiveStepEnabled", AdaptiveStep);
mShader->SetUniform1i("isBinarySearchEnabled", BinarySearch);
mShader->SetUniform1i("debugDraw", DebugDraw);
mShader->SetUniform1f("samplingCoefficient", SampleingCoefficient);
mShader->SetUniformMat4f("view", view);
mShader->SetUniformMat4f("invView", glm::inverse(view));
mShader->SetUniformMat4f("proj", projection);
mShader->SetUniformMat4f("invProj", glm::inverse(projection));
mShader->SetUniformTex("textureDepth", gBuffer->GetTexture(GL_DEPTH_ATTACHMENT).get(), 1);
mShader->SetUniformTex("textureNorm", gBuffer->GetTexture(GL_COLOR_ATTACHMENT1).get(), 2);
mShader->SetUniformTex("textureMetallic", gBuffer->GetTexture(GL_COLOR_ATTACHMENT2).get(), 3);
mShader->SetUniformTex("textureAlbedo", gBuffer->GetTexture(GL_COLOR_ATTACHMENT0).get(), 5);
mShader->SetUniformTex("textureFrame", previousFrame.get(), 7);
Renderer::DrawQuad(Matrix4());
}
OutputFramebuffer->Unbind();
}
}

View File

@@ -0,0 +1,31 @@
#pragma once
#include "src/Core/Core.h"
#include "src/Rendering/Buffers/Framebuffer.h"
#include "src/Rendering/Shaders/ShaderManager.h"
#include "src/Rendering/Camera.h"
namespace Nuake {
class SSR {
private:
Vector2 mSize;
Shader* mShader;
public:
Ref<FrameBuffer> OutputFramebuffer;
float RayStep = 0.2f;
int IterationCount = 100;
float DistanceBias = 0.05f;
int SampleCount = 1;
bool SamplingEnabled = true;
bool ExpoStep = true;
bool AdaptiveStep = true;
bool BinarySearch = true;
bool DebugDraw = false;
float SampleingCoefficient = 0.000f;
SSR();
void Init();
void Resize(Vector2 size);
void Draw(FrameBuffer* gBuffer, Ref<Texture> previousFrame, Matrix4 view, Matrix4 projection, Ref<Camera> cam);
};
}

View File

@@ -18,7 +18,7 @@ namespace Nuake {
void Volumetric::Init()
{
mFinalFramebuffer = CreateScope<FrameBuffer>(false, mSize);
mFinalFramebuffer = CreateScope<FrameBuffer>(true, mSize);
mFinalFramebuffer->SetTexture(CreateRef<Texture>(mSize, GL_RGBA, GL_RGBA16F, GL_FLOAT));
}
@@ -35,18 +35,19 @@ namespace Nuake {
{
mFinalFramebuffer->Bind();
mFinalFramebuffer->Clear();
RenderCommand::Disable(RendererEnum::DEPTH_TEST);
RenderCommand::Disable(RendererEnum::FACE_CULL);
Vector3 cameraPosition = view[3];
Shader* volumetricShader = ShaderManager::GetShader("resources/Shaders/volumetric.shader");
volumetricShader->Bind();
volumetricShader->SetUniformMat4f("u_Projection", projection);
volumetricShader->SetUniformMat4f("u_View", view);
volumetricShader->SetUniformTex("u_Depth", mDepth, 0);
volumetricShader->SetUniformVec3("u_CamPosition", view[3]);
volumetricShader->SetUniformTex("u_Depth", mDepth, 1);
volumetricShader->SetUniformVec3("u_CamPosition", cameraPosition);
volumetricShader->SetUniform1i("u_StepCount", mStepCount);
volumetricShader->SetUniform1f("u_FogAmount", mFogAmount);
volumetricShader->SetUniform1i("u_LightCount", lights.size());
volumetricShader->SetUniform1i("u_LightCount", 1);
for (uint16_t i = 0; i < lights.size(); i++)
{
@@ -57,10 +58,18 @@ namespace Nuake {
volumetricShader->SetUniformVec3(u_light + "color", light.Color);
volumetricShader->SetUniformVec3(u_light + "direction", light.GetDirection());
volumetricShader->SetUniformTex(u_light + "shadowmap", light.m_Framebuffers[0]->GetTexture(GL_DEPTH_ATTACHMENT).get(), 1 + i);
volumetricShader->SetUniformTex("lightShadowmap", light.m_Framebuffers[0]->GetTexture(GL_DEPTH_ATTACHMENT).get(), 2 + i);
}
Renderer::DrawQuad();
mFinalFramebuffer->Unbind();
if (ImGui::Begin("Volumetric debug"))
{
ImGui::Image((void*)mFinalFramebuffer->GetTexture()->GetID(), ImGui::GetContentRegionAvail(), ImVec2(0, 1), ImVec2(1, 0));
}
ImGui::End();
}
}

View File

@@ -20,8 +20,14 @@ namespace Nuake {
mBloom = CreateScope<Bloom>(4);
mBloom->SetSource(shadedTexture);
mVolumetric = CreateScope<Volumetric>();
mSSR = CreateScope<SSR>();
mToneMapBuffer = CreateScope<FrameBuffer>(false, Vector2(1920, 1080));
mToneMapBuffer->SetTexture(CreateRef<Texture>(Vector2(1920, 1080), GL_RGB), GL_COLOR_ATTACHMENT0);
}
void SceneRenderer::Cleanup()
@@ -70,12 +76,15 @@ namespace Nuake {
mVolumetric->SetDepth(mGBuffer->GetTexture(GL_DEPTH_ATTACHMENT).get());
mVolumetric->Draw(mProjection , mView, lightList);
finalOutput = mVolumetric->GetFinalOutput();
}
// Copy final output to target framebuffer
framebuffer.Bind();
mToneMapBuffer->QueueResize(framebuffer.GetSize());
mToneMapBuffer->Bind();
{
RenderCommand::Clear();
Shader* shader = ShaderManager::GetShader("resources/Shaders/tonemap.shader");
shader->Bind();
@@ -84,8 +93,24 @@ namespace Nuake {
shader->SetUniformTex("u_Source", finalOutput);
Renderer::DrawQuad();
}
mToneMapBuffer->Unbind();
mSSR->Resize(framebuffer.GetSize());
mSSR->Draw(mGBuffer.get(), framebuffer.GetTexture(), mView, mProjection, scene.GetCurrentCamera());
framebuffer.Bind();
{
RenderCommand::Clear();
Shader* shader = ShaderManager::GetShader("resources/Shaders/combine.shader");
shader->Bind();
shader->SetUniformTex("u_Source", mToneMapBuffer->GetTexture().get(), 0);
shader->SetUniformTex("u_Source2", mSSR->OutputFramebuffer->GetTexture().get(), 1);
Renderer::DrawQuad();
}
framebuffer.Unbind();
RenderCommand::Enable(RendererEnum::DEPTH_TEST);
Renderer::EndDraw();
}
@@ -97,6 +122,7 @@ namespace Nuake {
Shader* shader = ShaderManager::GetShader("resources/Shaders/shadowMap.shader");
shader->Bind();
RenderCommand::Disable(RendererEnum::FACE_CULL);
glCullFace(GL_BACK);
auto meshView = scene.m_Registry.view<TransformComponent, MeshComponent>();

View File

@@ -6,6 +6,7 @@
#include "src/Rendering/Buffers/Framebuffer.h"
#include "src/Rendering/PostFX/Bloom.h"
#include "src/Rendering/PostFX/Volumetric.h"
#include <src/Rendering/PostFX/SSR.h>
namespace Nuake {
class SceneRenderer {
@@ -15,11 +16,15 @@ namespace Nuake {
void BeginRenderScene(const Matrix4& projection, const Matrix4& view);
void RenderScene(Scene& scene, FrameBuffer& framebuffer);
Scope<SSR> mSSR;
private:
Matrix4 mProjection, mView;
Scope<FrameBuffer> mGBuffer;
Scope<FrameBuffer> mShadingBuffer;
Scope<FrameBuffer> mToneMapBuffer;
Scope<Bloom> mBloom;
Scope<Volumetric> mVolumetric;

View File

@@ -10,9 +10,22 @@ namespace Nuake
// TODO: Register all uniform when creating shader.
Shader::Shader(const std::string& filePath)
{
Source = ParseShader(filePath);
Path = filePath;
ProgramId = CreateProgram();
Source = ParseShader(this->Path);
ProgramId = CreateProgram(Source);
}
bool Shader::Rebuild()
{
ShaderSource newSource = ParseShader(this->Path);
unsigned int newProgramId = CreateProgram(newSource);
if(newProgramId == 0)
return false;
Source = newSource;
ProgramId = newProgramId;
}
// Bind the shader
@@ -78,24 +91,30 @@ namespace Nuake
// Parse both source and creates a shader program.
// This returns the program id.
unsigned int Shader::CreateProgram()
unsigned int Shader::CreateProgram(ShaderSource source)
{
unsigned int program = glCreateProgram();
unsigned int vs = Compile(GL_VERTEX_SHADER);
unsigned int fs = Compile(GL_FRAGMENT_SHADER);
unsigned int vs = Compile(GL_VERTEX_SHADER, source);
unsigned int fs = Compile(GL_FRAGMENT_SHADER, source);
unsigned int gs = 0;
unsigned int cs = 0;
if (vs == 0)
return 0;
if (fs == 0)
return 0;
if (Source.GeometryShader != "")
{
gs = Compile(GL_GEOMETRY_SHADER);
gs = Compile(GL_GEOMETRY_SHADER, source);
glAttachShader(program, gs);
}
if (Source.ComputeShader != "")
{
cs = Compile(GL_COMPUTE_SHADER);
cs = Compile(GL_COMPUTE_SHADER, source);
glAttachShader(program, cs);
}
@@ -116,14 +135,14 @@ namespace Nuake
}
// Compile a single shader and checks for error.
unsigned int Shader::Compile(unsigned int type)
unsigned int Shader::Compile(unsigned int type, ShaderSource source)
{
unsigned int id = glCreateShader(type);
const char* src;
if (type == GL_FRAGMENT_SHADER) src = Source.FragmentShader.c_str();
if (type == GL_VERTEX_SHADER) src = Source.VertexShader.c_str();
if (type == GL_GEOMETRY_SHADER) src = Source.GeometryShader.c_str();
if (type == GL_FRAGMENT_SHADER) src = source.FragmentShader.c_str();
if (type == GL_VERTEX_SHADER) src = source.VertexShader.c_str();
if (type == GL_GEOMETRY_SHADER) src = source.GeometryShader.c_str();
if (type == GL_COMPUTE_SHADER) src = Source.ComputeShader.c_str();
glShaderSource(id, 1, &src, nullptr);
@@ -171,7 +190,7 @@ namespace Nuake
int addr = glGetUniformLocation(ProgramId, uniform.c_str());
if (addr == -1)
std::cout << "Warning: uniform '" << uniform << "' doesn't exists!" << std::endl;
return addr;//std::cout << "Warning: uniform '" << uniform << "' doesn't exists!" << std::endl;
else
UniformCache[uniform] = addr;
@@ -201,62 +220,77 @@ namespace Nuake
void Shader::SetUniform4f(const std::string& name, float v0, float v1, float v2, float v3)
{
int addr = FindUniformLocation(name);
ASSERT(addr != -1);
glUniform4f(addr, v0, v1, v2, v3);
//ASSERT(addr != -1);
if (addr != -1)
glUniform4f(addr, v0, v1, v2, v3);
}
void Shader::SetUniform3f(const std::string& name, float v0, float v1, float v2)
{
int addr = FindUniformLocation(name);
ASSERT(addr != -1);
glUniform3f(addr, v0, v1, v2);
//ASSERT(addr != -1);
if (addr != -1)
glUniform3f(addr, v0, v1, v2);
}
void Shader::SetUniform2f(const std::string& name, float v0, float v1)
{
int addr = FindUniformLocation(name);
ASSERT(addr != -1);
glUniform2f(addr, v0, v1);
//ASSERT(addr != -1);
if (addr != -1)
glUniform2f(addr, v0, v1);
}
void Shader::SetUniform1i(const std::string& name, int v0)
{
int addr = FindUniformLocation(name);
ASSERT(addr != -1);
glUniform1i(addr, v0);
//ASSERT(addr != -1);
if (addr != -1)
glUniform1i(addr, v0);
}
void Shader::SetUniform1iv(const std::string& name, int size, int* value)
{
int addr = FindUniformLocation(name);
ASSERT(addr != -1);
glUniform1iv(addr, size, value);
//ASSERT(addr != -1);
if (addr != -1)
glUniform1iv(addr, size, value);
}
void Shader::SetUniformMat3f(const std::string& name, Matrix3 mat)
{
int addr = FindUniformLocation(name);
ASSERT(addr != -1);
glUniformMatrix3fv(addr, 1, GL_FALSE, &mat[0][0]);
//ASSERT(addr != -1);
if(addr != -1)
glUniformMatrix3fv(addr, 1, GL_FALSE, &mat[0][0]);
}
void Shader::SetUniformMat4f(const std::string& name, Matrix4 mat)
{
int addr = FindUniformLocation(name);
ASSERT(addr != -1);
glUniformMatrix4fv(addr, 1, GL_FALSE, &mat[0][0]);
if (addr != -1)
glUniformMatrix4fv(addr, 1, GL_FALSE, &mat[0][0]);
}
void Shader::SetUniform1f(const std::string& name, float v0)
{
int addr = FindUniformLocation(name);
ASSERT(addr != -1);
glUniform1f(addr, v0);
//ASSERT(addr != -1);
if (addr != -1)
glUniform1f(addr, v0);
}
void Shader::SetUniformTex(const std::string& name, Texture* texture, unsigned int slot)
{
ASSERT(texture != nullptr);
//ASSERT(texture != nullptr);
SetUniform1i(name, slot);
texture->Bind(slot);
}

View File

@@ -20,6 +20,7 @@ namespace Nuake
class Shader
{
public:
std::string Path;
ShaderSource Source;
unsigned int ProgramId;
@@ -27,6 +28,7 @@ namespace Nuake
Shader(const std::string& filePath);
bool Rebuild();
void Bind() const;
void Unbind() const;
@@ -37,6 +39,7 @@ namespace Nuake
void SetUniform3f(const std::string& name, float v0, float v1, float v2);
void SetUniform2f(const std::string& name, float v0, float v1);
void SetUniform1f(const std::string& name, float v0);
void SetUniform1b(const std::string& name, bool v0);
void SetUniformTex(const std::string& name, Texture* texture, unsigned int slot = 0);
void SetUniform1i(const std::string& name, int v0);
@@ -46,8 +49,8 @@ namespace Nuake
private:
ShaderSource ParseShader(const std::string& filePath);
unsigned int CreateProgram();
unsigned int Compile(unsigned int type);
unsigned int CreateProgram(ShaderSource source);
unsigned int Compile(unsigned int type, ShaderSource source);
int FindUniformLocation(std::string uniform);
};
}

View File

@@ -1,5 +1,6 @@
#pragma once
#include "ShaderManager.h"
#include "src/Core/Logger.h"
namespace Nuake
{
@@ -14,4 +15,15 @@ namespace Nuake
return m_Shaders[path].get();
}
void ShaderManager::RebuildShaders()
{
for (auto& s : m_Shaders)
{
if (!s.second->Rebuild())
{
Logger::Log("Failed to rebuild shader: " + s.first, Nuake::CRITICAL);
}
}
}
}

View File

@@ -14,5 +14,6 @@ namespace Nuake
public:
static Shader* GetShader(const std::string& path);
static void RebuildShaders();
};
}

View File

@@ -94,45 +94,54 @@ namespace Nuake
// return;
MaterialManager::Get()->CurrentlyBoundedMaterial = m_Name;
glBindBuffer(GL_UNIFORM_BUFFER, UBO);
glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(UBOStructure), &data);
glBindBuffer(GL_UNIFORM_BUFFER, 0);
glBindBufferBase(GL_UNIFORM_BUFFER, 32, UBO);
// Albedo
if (m_Albedo != nullptr)
{
data.u_HasAlbedo = 1;
m_Albedo->Bind(4);
}
else
m_DefaultAlbedo->Bind(4);
shader->SetUniform1i("m_Albedo", 4);
// AO
if (m_AO != nullptr)
{
data.u_HasAO = 1;
m_AO->Bind(5);
}
else
m_DefaultAO->Bind(5);
shader->SetUniform1i("m_AO", 5);
// Metallic
if (m_Metalness != nullptr)
if (m_Metalness != nullptr) {
data.u_HasMetalness = 1;
m_Metalness->Bind(6);
}
else
m_DefaultMetalness->Bind(6);
shader->SetUniform1i("m_Metalness", 6);
// Roughness
if (m_Roughness != nullptr)
if (m_Roughness != nullptr) {
data.u_HasRoughness = 1;
m_Roughness->Bind(7);
}
else
m_DefaultRoughness->Bind(7);
shader->SetUniform1i("m_Roughness", 7);
// Normal
if (m_Normal != nullptr)
if (m_Normal != nullptr) {
data.u_HasNormal = 1;
m_Normal->Bind(8);
}
else
m_DefaultNormal->Bind(8);
shader->SetUniform1i("m_Normal", 8);
// Displacement
@@ -140,6 +149,12 @@ namespace Nuake
m_Displacement->Bind(9);
else
m_DefaultDisplacement->Bind(9);
glBindBuffer(GL_UNIFORM_BUFFER, UBO);
glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(UBOStructure), &data);
glBindBuffer(GL_UNIFORM_BUFFER, 0);
glBindBufferBase(GL_UNIFORM_BUFFER, 32, UBO);
//Renderer::m_Shader->SetUniform1i("m_Displacement", 9);
//Renderer::m_Shader->SetUniform1i("m_Displacement", 9);
}

View File

@@ -44,9 +44,9 @@ namespace Nuake
0, // Has metalness
0.f, // Metalness value
0, // u_HasRoughness
1.f, // u_RoughnessValue
0.f, // u_RoughnessValue
0, // u_HasAO
0.5f, // u_AOValue
1.f, // u_AOValue
0, // u_HasNormal
0, // u_HasDisplacement
0

View File

@@ -25,12 +25,6 @@ namespace Nuake
Ref<Material> MaterialManager::GetMaterial(std::string name)
{
if (!FileSystem::FileExists(name))
{
Logger::Log("Couldn't load material: " + name + " - File doesn't exists", Nuake::LOG_TYPE::CRITICAL);
name = DEFAULT_MATERIAL;
}
if (!IsMaterialLoaded(name))
{
Ref<Material> newMaterial = CreateRef<Material>(name);

View File

@@ -1,5 +1,47 @@
#pragma once
#include <string>
#include <vector>
#include "src/Rendering/Mesh/Mesh.h"
class Ressource
{
};
namespace Nuake {
enum class ResourceType
{
Texture,
Prefab,
Map,
Mesh,
Shader
};
class Resource
{
public:
unsigned int Id;
ResourceType Type;
bool IsEmbedded;
std::string Path; // Only if embedded
void MakeExternal();
void Duplicate();
void MakeEmbedded();
};
class TextureResource : Resource
{
public:
std::string TexturePath;
// texture flags
};
class ModelResource : Resource
{
public:
std::vector<Mesh*> SubMeshes;
ModelResource();
bool Load(const std::string& path);
};
}

View File

@@ -0,0 +1,16 @@
#pragma once
#include "src/Core/Core.h"
#include "src/Resource/Resource.h"
#include "src/Resource/UUID.h"
#include <map>
namespace Nuake {
class ResourceManager {
private:
static std::unordered_map<UUID, Ref<Resource>> m_Resources;
public:
static Ref<Resource> GetResource(const UUID& uuid);
};
}

View File

@@ -0,0 +1,18 @@
#include "UUID.h"
#include <random>
namespace Nuake {
static std::random_device s_RandomDevice;
static std::mt19937_64 s_Engine(s_RandomDevice());
static std::uniform_int_distribution<uint64_t> s_UniformDistribution;
UUID::UUID() : m_UUID(s_UniformDistribution(s_Engine))
{
}
UUID::UUID(uint64_t uuid) : m_UUID(uuid)
{
}
}

30
Nuake/src/Resource/UUID.h Normal file
View File

@@ -0,0 +1,30 @@
#pragma once
#include <cstdint>
#include <xhash>
namespace Nuake {
class UUID
{
public:
UUID();
UUID(uint64_t uuid);
UUID(const UUID&) = default;
operator uint64_t() const { return m_UUID; }
private:
uint64_t m_UUID;
};
}
namespace std {
template<>
struct hash<Nuake::UUID>
{
std::size_t operator()(const Nuake::UUID& uuid) const
{
return hash<uint64_t>()((uint64_t)uuid);
}
};
}

View File

@@ -1,6 +1,7 @@
#pragma once
#include "src/Core/Physics/PhysicsShapes.h"
#include "src/Core/Core.h"
namespace Nuake {
class BoxColliderComponent
{

View File

@@ -0,0 +1,22 @@
#pragma once
// Base
#include "NameComponent.h"
#include "ParentComponent.h"
#include "TransformComponent.h"
#include "PrefabComponent.h"
#include "CameraComponent.h"
#include "LightComponent.h"
#include "MeshComponent.h"
#include "QuakeMap.h"
// Physics
#include "RigidbodyComponent.h"
#include "BoxCollider.h"
#include "SphereCollider.h"
#include "MeshCollider.h"
// Behaviour
#include "WrenScriptComponent.h"

View File

@@ -36,7 +36,10 @@ namespace Nuake {
for (int i = 0; i < CSM_AMOUNT; i++)
{
m_Framebuffers[i] = CreateRef<FrameBuffer>(false, glm::vec2(4096, 4096));
m_Framebuffers[i]->SetTexture(CreateRef<Texture>(glm::vec2(4096, 4096), GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT, GL_FLOAT), GL_DEPTH_ATTACHMENT);
auto texture = CreateRef<Texture>(glm::vec2(4096, 4096), GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT, GL_FLOAT);
texture->SetParameter(GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
m_Framebuffers[i]->SetTexture(texture, GL_DEPTH_ATTACHMENT);
}
}
else {

View File

@@ -63,11 +63,11 @@ namespace Nuake
glm::mat4 inverseViewProjection = glm::inverse(viewProjection);
// TODO: Automate this
const float nearClip = 0.01f;
const float farClip = 1000.0f;
const float nearClip = 0.0001f;
const float farClip = 800.0f;
const float clipRange = farClip - nearClip;
const float mCascadeNearPlaneOffset = 0.0;
const float mCascadeNearPlaneOffset = -100.0f;
const float mCascadeFarPlaneOffset = 0.0;
// Calculate the optimal cascade distances

View File

@@ -73,15 +73,22 @@ namespace Nuake {
vector.z = mesh->mNormals[i].z;
vertex.normal = vector;
vector.x = mesh->mTangents[i].x;
vector.y = mesh->mTangents[i].y;
vector.z = mesh->mTangents[i].z;
vertex.tangent = vector;
if (mesh->mTangents)
{
vector.x = mesh->mTangents[i].x;
vector.y = mesh->mTangents[i].y;
vector.z = mesh->mTangents[i].z;
vertex.tangent = vector;
}
if (mesh->mBitangents)
{
vector.x = mesh->mBitangents[i].x;
vector.y = mesh->mBitangents[i].y;
vector.z = mesh->mBitangents[i].z;
vertex.bitangent = vector;
}
vector.x = mesh->mBitangents[i].x;
vector.y = mesh->mBitangents[i].y;
vector.z = mesh->mBitangents[i].z;
vertex.bitangent = vector;
if (mesh->mTextureCoords[0]) // does the mesh contain texture coordinates?
{

View File

@@ -11,8 +11,6 @@ namespace Nuake {
void SetPrefab(Ref<Prefab> prefab)
{
PrefabInstance = prefab;
}
};
}

View File

@@ -7,15 +7,14 @@ namespace Nuake {
{
public:
std::string Script;
std::string Class;
unsigned int mModule = 0;
Ref<WrenScript> mWrenScript;
json Serialize()
{
BEGIN_SERIALIZE();
SERIALIZE_VAL(Script);
SERIALIZE_VAL(Class);
END_SERIALIZE();
}
@@ -24,8 +23,6 @@ namespace Nuake {
BEGIN_DESERIALIZE();
if (j.contains("Script"))
Script = j["Script"];
if (j.contains("Class"))
Class = j["Class"];
return true;

View File

@@ -2,6 +2,7 @@
#include "../Core/Input.h"
#include <GLFW/glfw3.h>
#include <glm/trigonometric.hpp>
#include "src/Core/Logger.h"
namespace Nuake
{
@@ -99,4 +100,13 @@ namespace Nuake
Direction = glm::normalize(Direction);
Right = glm::normalize(glm::cross(Up, Direction));
}
Ref<EditorCamera> EditorCamera::Copy()
{
Ref<EditorCamera> copy = CreateRef<EditorCamera>();
copy->Translation = this->Translation;
copy->Yaw = this->Yaw;
copy->Pitch = this->Pitch;
return copy;
}
}

View File

@@ -1,6 +1,7 @@
#pragma once
#include "../Core/Timestep.h"
#include "../Rendering/Camera.h"
#include "src/Core/Core.h"
namespace Nuake
{
@@ -14,6 +15,9 @@ namespace Nuake
}
void Update(Timestep ts);
Ref<EditorCamera> Copy();
private:
bool controlled = false;
bool firstMouse = false;
@@ -21,7 +25,7 @@ namespace Nuake
float mouseLastX;
float mouseLastY;
float Yaw = 0.f;
float Pitch = 0.f;
float Yaw = -135.f;
float Pitch = -45.f;
};
}

View File

@@ -85,6 +85,20 @@ namespace Nuake
return SunDirection;
}
Ref<ProceduralSky> ProceduralSky::Copy()
{
auto copy = CreateRef<ProceduralSky>();
copy->SurfaceRadius = this->SurfaceRadius;
copy->AtmosphereRadius = this->AtmosphereRadius;
copy->RayleighScattering = this->RayleighScattering;
copy->MieScattering = this->MieScattering;
copy->SunIntensity = this->SunIntensity;
copy->CenterPoint = this->CenterPoint;
copy->SunDirection = this->SunDirection;
return copy;
}
json ProceduralSky::Serialize()
{
BEGIN_SERIALIZE()

View File

@@ -25,6 +25,8 @@ namespace Nuake
Vector3 GetSunDirection();
Ref<ProceduralSky> Copy();
json Serialize() override;
bool Deserialize(const std::string& str) override;
};

View File

@@ -27,6 +27,25 @@ namespace Nuake {
Renderer::m_Shader->SetUniform1f("u_FogStepCount", VolumetricStepCount);
}
Ref<Environment> Environment::Copy()
{
Ref<Environment> copy = CreateRef<Environment>();
copy->CurrentSkyType = this->CurrentSkyType;
copy->ProceduralSkybox = this->ProceduralSkybox->Copy();
copy->VolumetricEnabled = this->VolumetricEnabled;
copy->VolumetricFog = this->VolumetricFog;
copy->VolumetricStepCount = this->VolumetricStepCount;
copy->Exposure = this->Exposure;
copy->Gamma = this->Gamma;
copy->BloomEnabled = this->BloomEnabled;
copy->ClearColor = this->ClearColor;
copy->AmbientColor = this->AmbientColor;
return copy;
}
json Environment::Serialize()
{
BEGIN_SERIALIZE();

View File

@@ -42,6 +42,8 @@ namespace Nuake
void Push();
Ref<Environment> Copy();
json Serialize() override;
bool Deserialize(const std::string& str) override;
};

View File

@@ -83,6 +83,8 @@ namespace Nuake {
}
}
bool Scene::OnInit()
{
for (auto& system : m_Systems)
@@ -139,7 +141,7 @@ namespace Nuake {
void Scene::Draw(FrameBuffer& framebuffer, const Matrix4& projection, const Matrix4& view)
{
mSceneRenderer->BeginRenderScene(projection, view);
mSceneRenderer->BeginRenderScene(m_EditorCamera->GetPerspective(), m_EditorCamera->GetTransform());
mSceneRenderer->RenderScene(*this, framebuffer);
}
@@ -170,13 +172,18 @@ namespace Nuake {
}
Entity Scene::CreateEntity(const std::string& name)
{
return CreateEntity(name, (int)OS::GetTime());
}
Entity Scene::CreateEntity(const std::string& name, int id)
{
Entity entity = { m_Registry.create(), this };
entity.AddComponent<TransformComponent>();
NameComponent& nameComponent = entity.AddComponent<NameComponent>();
nameComponent.Name = name;
nameComponent.ID = (int)OS::GetTime();
nameComponent.ID = id;
ParentComponent& parentComponent = entity.AddComponent<ParentComponent>();
@@ -233,6 +240,11 @@ namespace Nuake {
return m_Environement;
}
void Scene::SetEnvironment(Ref<Environment> env)
{
m_Environement = env;
}
bool Scene::Save()
{
if (Path == "")
@@ -252,12 +264,53 @@ namespace Nuake {
return true;
}
Scene* Scene::Copy()
template<typename Component>
void Scene::CopyComponent(entt::registry& dst, entt::registry& src)
{
Scene* sceneCopy = new Scene();
auto view = src.view<Component>();
for (auto e : view)
{
int id = src.get<NameComponent>(e).ID;
auto& component = src.get<Component>(e);
auto idView = dst.view<NameComponent>();
for (auto de : idView)
{
if (idView.get<NameComponent>(de).ID == src.get<NameComponent>(e).ID)
{
dst.emplace_or_replace<Component>(de, component);
}
}
}
}
Ref<Scene> Scene::Copy()
{
Ref<Scene> sceneCopy = CreateRef<Scene>();
sceneCopy->Path = this->Path;
sceneCopy->Name = this->Name;
sceneCopy->m_EditorCamera = this->m_EditorCamera->Copy();
sceneCopy->SetEnvironment(this->GetEnvironment()->Copy());
auto& srcRegistry = this->m_Registry;
auto& dstRegistry = sceneCopy->m_Registry;
auto idView = srcRegistry.view<NameComponent>();
for (auto e : idView)
{
NameComponent& nameComponent = srcRegistry.get<NameComponent>(e);
int id = nameComponent.ID;
std::string& name = nameComponent.Name;
sceneCopy->CreateEntity(name, id);
}
CopyComponent<TransformComponent>(sceneCopy->m_Registry, this->m_Registry);
CopyComponent<LightComponent>(sceneCopy->m_Registry, this->m_Registry);
CopyComponent<MeshComponent>(sceneCopy->m_Registry, this->m_Registry);
CopyComponent<CameraComponent>(sceneCopy->m_Registry, this->m_Registry);
return sceneCopy;
}

View File

@@ -21,7 +21,7 @@ namespace Nuake {
{
friend Entity;
private:
std::string Name; // Name of the scene
std::string Name;
bool has_changed = true;
// The systems are what updates the components.
@@ -29,22 +29,16 @@ namespace Nuake {
// In the scene constructor.
std::vector<Ref<System>> m_Systems;
Ref<Environment> m_Environement;
SceneRenderer* mSceneRenderer;
public:
Ref<EditorCamera> m_EditorCamera;
entt::registry m_Registry;
std::string Path = "";
SceneRenderer* mSceneRenderer;
static Ref<Scene> New();
Scene();
~Scene();
std::string GetName();
bool SetName(std::string& newName);
Entity GetEntity(int handle);
Entity GetEntityByID(int id);
bool OnInit();
void OnExit();
void Update(Timestep ts);
@@ -54,23 +48,31 @@ namespace Nuake {
void Draw(FrameBuffer& framebuffer);
void Draw(FrameBuffer& framebuffer, const Matrix4& projection, const Matrix4& view);
std::vector<Entity> GetAllEntities();
Entity GetEntity(const std::string& name);
Entity CreateEntity(const std::string& name);
void DestroyEntity(Entity entity); // TODO: Could return bool
std::string GetName();
bool SetName(std::string& newName);
Ref<Camera> GetCurrentCamera();
Entity CreateEntity(const std::string& name);
Entity CreateEntity(const std::string& name, int id);
void DestroyEntity(Entity entity);
std::vector<Entity> GetAllEntities();
Entity GetEntity(const std::string& name);
Entity GetEntity(int handle);
Entity GetEntityByID(int id);
template<typename Component>
static void CopyComponent(entt::registry& dst, entt::registry& src);
Ref<Environment> GetEnvironment() const;
void SetEnvironment(Ref<Environment> env);
bool Save();
bool SaveAs(const std::string& path);
void AddInterface(Ref<UI::UserInterface> interface);
Ref<Scene> Copy();
json Serialize() override;
Scene* Copy();
bool Deserialize(const std::string& str) override;
};
}

View File

@@ -214,7 +214,7 @@ namespace Nuake {
{
auto& wrenScript = brushEntity.AddComponent<WrenScriptComponent>();
wrenScript.Script = fgdBrush.Script;
wrenScript.Class = fgdBrush.Class;
wrenScript.mModule = 0; // TODO
}
if (bsp.IsTrigger)

View File

@@ -13,22 +13,17 @@ namespace Nuake {
{
ScriptingEngine::Init();
auto entities = m_Scene->m_Registry.view<WrenScriptComponent>();
for (auto e : entities)
auto& entities = m_Scene->m_Registry.view<WrenScriptComponent>();
for (auto& e : entities)
{
WrenScriptComponent& wren = entities.get<WrenScriptComponent>(e);
if (wren.Script != "" && wren.Class != "")
{
wren.mWrenScript = CreateRef<WrenScript>(wren.Script, wren.Class, true);
if (!wren.mWrenScript->CompiledSuccesfully)
return false;
}
wren.mWrenScript->Build(wren.mModule, true);
if (!wren.mWrenScript->HasCompiledSuccesfully())
return false;
if (wren.mWrenScript != nullptr)
{
wren.mWrenScript->SetScriptableEntityID((int)e);
wren.mWrenScript->CallInit();
}
wren.mWrenScript->SetScriptableEntityID((int)e);
wren.mWrenScript->CallInit();
}
return true;

View File

@@ -5,17 +5,18 @@
#include "ScriptModule.h"
#include <iostream>
#include <wren.h>
namespace Nuake
{
namespace ScriptAPI
{
class EngineModule : public ScriptModule
{
std::string ModuleName = "Engine";
const std::string ModuleName = "Engine";
std::string GetModuleName() override
{
return "Engine";
return ModuleName;
}
void RegisterModule(WrenVM* vm) override

View File

@@ -88,18 +88,18 @@ namespace Nuake {
return result;
}
Ref<WrenScript> ScriptingEngine::RegisterScript(const std::string& path, const std::string& mod)
{
// Check if scripts has already been loaded.
// You can't import the same module twice, otherwise, compile error.
if (m_Scripts.find(path) == m_Scripts.end())
{
std::string query = "import \"" + path + "\" for " + mod;
wrenInterpret(m_WrenVM, "main", query.c_str());
}
return CreateRef<WrenScript>(path, mod);
}
//Ref<WrenScript> ScriptingEngine::RegisterScript(const std::string& path, const std::string& mod)
//{
// //// Check if scripts has already been loaded.
// //// You can't import the same module twice, otherwise, compile error.
// //if (m_Scripts.find(path) == m_Scripts.end())
// //{
// // std::string query = "import \"" + path + "\" for " + mod;
// // wrenInterpret(m_WrenVM, "main", query.c_str());
// //}
// //
// //return CreateRef<WrenScript>(path, mod);
//}
// Useful to check if a script has been imported, importing a script
// twice gives a compile error.
@@ -120,8 +120,6 @@ namespace Nuake {
m_LoadedScripts.push_back(path);
}
void ScriptingEngine::RegisterModule(Ref<ScriptModule> scriptModule)
{
Modules[scriptModule->GetModuleName()] = scriptModule;

View File

@@ -1,18 +1,57 @@
#include "WrenScript.h"
#include "../Core/FileSystem.h"
#include "src/Core/String.h"
#include <src/Vendors/wren/src/include/wren.h>
namespace Nuake {
WrenScript::WrenScript(const std::string& path, const std::string& mod, bool isEntity)
WrenScript::WrenScript(Ref<File> file, bool isEntity)
{
mFile = file;
IsEntity = isEntity;
ParseModules();
}
void WrenScript::ParseModules()
{
std::ifstream MyReadFile(mFile->GetAbsolutePath());
std::string fileContent = "";
while (getline(MyReadFile, fileContent))
{
bool hasFoundModule = false;
auto& splits = String::Split(fileContent, ' ');
for (unsigned int i = 0; i < splits.size(); i++)
{
std::string s = splits[i];
if (s == "class" && i + 1 < splits.size() && !hasFoundModule)
{
std::string moduleFound = splits[i + 1];
mModules.push_back(moduleFound);
hasFoundModule = true;
}
}
}
// Close the file
MyReadFile.close();
}
std::vector<std::string> WrenScript::GetModules()
{
return mModules;
}
void WrenScript::Build(unsigned int moduleId, bool isEntity)
{
WrenVM* vm = ScriptingEngine::GetWrenVM();
CompiledSuccesfully = true;
std::string relativePath = mFile->GetRelativePath();
// Can't import twice the same script, otherwise gives a compile error.
if (!ScriptingEngine::IsScriptImported(path))
if (!ScriptingEngine::IsScriptImported(relativePath))
{
std::string source = "import \"" + path + "\" for " + mod;
std::string source = "import \"" + relativePath + "\" for " + GetModules()[moduleId];
WrenInterpretResult result = wrenInterpret(vm, "main", source.c_str());
if (result != WREN_RESULT_SUCCESS)
@@ -21,12 +60,12 @@ namespace Nuake {
if (!CompiledSuccesfully)
return;
ScriptingEngine::ImportScript(path);
ScriptingEngine::ImportScript(relativePath);
}
// Get handle to class
wrenEnsureSlots(vm, 1);
wrenGetVariable(vm, "main", mod.c_str(), 0);
wrenGetVariable(vm, "main", GetModules()[moduleId].c_str(), 0);
WrenHandle* classHandle = wrenGetSlotHandle(vm, 0);
// Call the constructor
@@ -44,10 +83,14 @@ namespace Nuake {
if (isEntity)
this->m_SetEntityIDHandle = wrenMakeCallHandle(vm, "SetEntityId(_)");
CompiledSuccesfully = true;
}
void WrenScript::CallInit()
{
if (!CompiledSuccesfully) return;
WrenVM* vm = ScriptingEngine::GetWrenVM();
wrenSetSlotHandle(vm, 0, this->m_Instance);
WrenInterpretResult result = wrenCall(vm, this->m_OnInitHandle);
@@ -55,6 +98,8 @@ namespace Nuake {
void WrenScript::CallUpdate(float timestep)
{
if (!CompiledSuccesfully) return;
WrenVM* vm = ScriptingEngine::GetWrenVM();
wrenEnsureSlots(vm, 2);
wrenSetSlotHandle(vm, 0, this->m_Instance);
@@ -64,6 +109,8 @@ namespace Nuake {
void WrenScript::CallFixedUpdate(float timestep)
{
if (!CompiledSuccesfully) return;
WrenVM* vm = ScriptingEngine::GetWrenVM();
wrenEnsureSlots(vm, 2);
wrenSetSlotHandle(vm, 0, this->m_Instance);
@@ -84,6 +131,9 @@ namespace Nuake {
void WrenScript::RegisterMethod(const std::string& signature)
{
if (!CompiledSuccesfully)
return;
WrenVM* vm = ScriptingEngine::GetWrenVM();
WrenHandle* handle = wrenMakeCallHandle(vm, signature.c_str());
methods.emplace(signature, handle);
@@ -91,8 +141,10 @@ namespace Nuake {
void WrenScript::CallMethod(const std::string& signature)
{
WrenVM* vm = ScriptingEngine::GetWrenVM();
if (!CompiledSuccesfully)
return;
WrenVM* vm = ScriptingEngine::GetWrenVM();
// Not found. maybe try to register it?
if (methods.find(signature) == methods.end())
@@ -105,6 +157,9 @@ namespace Nuake {
void WrenScript::SetScriptableEntityID(int id)
{
if (!CompiledSuccesfully)
return;
WrenVM* vm = ScriptingEngine::GetWrenVM();
wrenSetSlotHandle(vm, 0, this->m_Instance);
wrenSetSlotDouble(vm, 1, id);

View File

@@ -1,5 +1,7 @@
#pragma once
#include "ScriptingEngine.h"
#include "src/Core/FileSystem.h"
#include <map>
#include <string>
@@ -8,7 +10,14 @@ class WrenHandle;
namespace Nuake {
class WrenScript
{
private:
bool CompiledSuccesfully;
bool IsEntity = false;
std::vector<std::string> mModules;
public:
Ref<File> mFile;
std::map <std::string, WrenHandle*> methods;
WrenHandle* m_Instance;
WrenHandle* m_OnInitHandle;
@@ -17,10 +26,14 @@ namespace Nuake {
WrenHandle* m_OnExitHandle;
WrenHandle* m_SetEntityIDHandle;
bool CompiledSuccesfully;
// Building
WrenScript(Ref<File> file, bool isEntity);
WrenScript(const std::string& path, const std::string& mod, bool isEntity = false);
void ParseModules();
std::vector<std::string> GetModules();
void Build(unsigned int moduleId, bool isEntity = false);
// Method calls
void CallInit();
void CallUpdate(float timestep);
void CallFixedUpdate(float timestep);
@@ -30,5 +43,7 @@ namespace Nuake {
void CallMethod(const std::string& signature);
void SetScriptableEntityID(int id);
bool HasCompiledSuccesfully() { return CompiledSuccesfully; }
};
}