4 Commits

Author SHA1 Message Date
antopilo
993bc3ae43 Fixed latest compilation problems 2025-03-22 19:21:03 -04:00
Antoine Pilote
4d34b9978a Update FUNDING.yml 2025-02-01 01:20:58 -05:00
Antoine Pilote
4661c1f00e Update LICENSE 2024-12-06 22:14:24 -05:00
Antoine Pilote
b6721d036a Merge pull request #94 from antopilo/develop
Bumped to develop
2024-12-02 17:05:08 -05:00
2511 changed files with 42076 additions and 524356 deletions

3
.github/FUNDING.yml vendored
View File

@@ -1,9 +1,8 @@
# These are supported funding model platforms
patreon: # Replace with a single Patreon username
patreon: nuakeengine # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username
ko_fi: antopilo # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username

44
.gitmodules vendored
View File

@@ -1,33 +1,33 @@
[submodule "Nuake/Thirdparty/assimp"]
path = Nuake/Thirdparty/assimp
[submodule "Nuake/dependencies/assimp"]
path = Nuake/dependencies/assimp
url = https://github.com/assimp/assimp.git
[submodule "Nuake/Thirdparty/JoltPhysics"]
path = Nuake/Thirdparty/JoltPhysics
[submodule "Nuake/dependencies/JoltPhysics"]
path = Nuake/dependencies/JoltPhysics
url = https://github.com/antopilo/JoltPhysics.git
[submodule "Nuake/Thirdparty/soloud"]
path = Nuake/Thirdparty/soloud
[submodule "Nuake/dependencies/soloud"]
path = Nuake/dependencies/soloud
url = https://github.com/antopilo/soloud.git
[submodule "Nuake/Thirdparty/Coral"]
path = Nuake/Thirdparty/Coral
[submodule "Nuake/dependencies/Coral"]
path = Nuake/dependencies/Coral
url = https://github.com/antopilo/Coral.git
[submodule "Nuake/Thirdparty/recastnavigation"]
path = Nuake/Thirdparty/recastnavigation
[submodule "Nuake/dependencies/recastnavigation"]
path = Nuake/dependencies/recastnavigation
url = https://github.com/antopilo/recastnavigation.git
[submodule "Nuake/Thirdparty/tracy"]
path = Nuake/Thirdparty/tracy
[submodule "Nuake/dependencies/tracy"]
path = Nuake/dependencies/tracy
url = https://github.com/wolfpld/tracy.git
[submodule "Nuake/Thirdparty/msdf-atlas-gen"]
path = Nuake/Thirdparty/msdf-atlas-gen
[submodule "Nuake/dependencies/msdf-atlas-gen"]
path = Nuake/dependencies/msdf-atlas-gen
url = https://github.com/antopilo/msdf-atlas-gen.git
[submodule "Nuake/Thirdparty/yoga"]
path = Nuake/Thirdparty/yoga
[submodule "Nuake/dependencies/yoga"]
path = Nuake/dependencies/yoga
url = https://github.com/facebook/yoga.git
[submodule "Nuake/Thirdparty/freetype"]
path = Nuake/Thirdparty/freetype
[submodule "Nuake/dependencies/freetype"]
path = Nuake/dependencies/freetype
url = https://github.com/freetype/freetype.git
[submodule "Nuake/Thirdparty/entt"]
path = Nuake/Thirdparty/entt
[submodule "Nuake/dependencies/entt"]
path = Nuake/dependencies/entt
url = https://github.com/skypjack/entt.git
[submodule "Nuake/Thirdparty/glfw"]
path = Nuake/Thirdparty/glfw
[submodule "Nuake/dependencies/glfw"]
path = Nuake/dependencies/glfw
url = https://github.com/antopilo/glfw.git

View File

@@ -1,30 +0,0 @@
@echo off
REM Set default values for configuration and platform
set CONFIG=Debug
set PLATFORM=
REM Get solution file path
set SOLUTION=Nuake.sln
REM Check if Configuration is provided
if not "%~2"=="" (
set CONFIG=%~2
)
REM Check if Platform is provided
if not "%~3"=="" (
set PLATFORM=%~3
)
REM Build the solution
echo Building solution "%SOLUTION%" with Configuration=%CONFIG% and Platform=%PLATFORM%...
"C:\Program Files\Microsoft Visual Studio\2022\Community\Msbuild\Current\Bin\MSBuild.exe" "Nuake.sln" -verbosity:minimal
PAUSE
REM Check if build succeeded
if %ERRORLEVEL%==0 (
echo Build succeeded.
) else (
echo Build failed.
exit /b 1
)

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 243 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 152 KiB

View File

@@ -1,86 +0,0 @@
// Transforms
struct ModelData
{
float4x4 model;
};
[[vk::binding(0, 0)]]
StructuredBuffer<ModelData> model : register(t1);
// Vertex
struct Vertex
{
float3 position;
float uv_x;
float3 normal;
float uv_y;
float3 tangent;
float3 bitangent;
};
[[vk::binding(0, 1)]]
StructuredBuffer<Vertex> vertexBuffer : register(t2);
// Samplers
[[vk::binding(0, 2)]]
SamplerState mySampler[2] : register(s0);
// Materials
struct Material
{
bool hasAlbedo;
float3 albedo;
bool hasNormal;
bool hasMetalness;
bool hasRoughness;
bool hasAO;
float metalnessValue;
float roughnessValue;
float aoValue;
int albedoTextureId;
int normalTextureId;
int metalnessTextureId;
int roughnessTextureId;
int aoTextureId;
int samplingType;
int receiveShadow;
int castShadow;
int unlit;
int alphaScissor;
};
[[vk::binding(0, 3)]]
StructuredBuffer<Material> material;
// Textures
[[vk::binding(0, 4)]]
Texture2D textures[];
// Lights
struct Light
{
float3 position;
int type;
float4 color;
float3 direction;
float outerConeAngle;
float innerConeAngle;
bool castShadow;
int shadowMapTextureId[4];
int transformId[4];
};
[[vk::binding(0, 5)]]
StructuredBuffer<Light> lights;
// Cameras
struct CameraView {
float4x4 View;
float4x4 Projection;
float4x4 ViewProjection;
float4x4 InverseView;
float4x4 InverseProjection;
float3 Position;
float Near;
float Far;
};
[[vk::binding(0, 6)]]
StructuredBuffer<CameraView> cameras;

View File

@@ -1,28 +0,0 @@
// HLSL version for Shader Model 6.1
RWTexture2D<float4> image : register(u0);
// Define the size of a thread group
[numthreads(16, 16, 1)]
void main(
uint3 dispatchThreadID : SV_DispatchThreadID,
uint3 groupThreadID : SV_GroupThreadID,
uint3 groupID : SV_GroupID
) {
// Get the size of the image
uint2 size;
image.GetDimensions(size.x, size.y);
// Current texel coordinates
uint2 texelCoord = dispatchThreadID.xy;
if (texelCoord.x < size.x && texelCoord.y < size.y) {
float4 color = float4(0.0, 0.0, 0.0, 1.0);
if (groupThreadID.x != 0 && groupThreadID.y != 0) {
color.x = float(texelCoord.x) / float(size.x);
color.y = float(texelCoord.y) / float(size.y);
}
image[texelCoord] = color;
}
}

View File

@@ -1,44 +0,0 @@
#include "Utils/header.hlsl"
struct PSInput {
float4 Position : SV_Position;
float2 UV : TEXCOORD0;
};
struct PSOutput {
float4 oColor0 : SV_TARGET;
};
struct BlurConstant
{
int blurSourceID;
float2 sourceSize;
};
[[vk::push_constant]]
BlurConstant pushConstants;
float3 SampleTexture(int textureId, float2 uv)
{
return textures[textureId].Sample(mySampler[0], uv).rgb;
}
PSOutput main(PSInput input)
{
float2 texelSize = 1.0 / pushConstants.sourceSize;
float3 result = 0.0;
for (int x = -2; x < 2; x++)
{
for (int y = -2; y < 2; y++)
{
float2 offset = float2(x, y) * texelSize;
result += SampleTexture(pushConstants.blurSourceID, input.UV + offset);
}
}
result = result / (4.0 * 4.0);
PSOutput output;
output.oColor0 = float4(result.rgb, 1.0f);
return output;
}

View File

@@ -1,27 +0,0 @@
#include "Utils/header.hlsl"
struct BlurConstant
{
int blurSourceID;
};
[[vk::push_constant]]
BlurConstant pushConstants;
// Outputs
struct VSOutput {
float4 Position : SV_Position;
float2 UV : TEXCOORD0;
};
// Main vertex shader
VSOutput main(uint vertexIndex : SV_VertexID)
{
VSOutput output;
Vertex v = vertexBuffer[vertexIndex];
output.UV = float2(v.uv_x, v.uv_y);
output.Position = float4(v.position, 1.0f);
return output;
}

View File

@@ -1,44 +0,0 @@
#include "Utils/header.hlsl"
struct PSInput
{
float4 Position : SV_Position;
float2 UV : TEXCOORD0;
};
struct PSOutput {
float4 oColor0 : SV_TARGET;
};
struct CopyPushConstant
{
int SourceTextureID;
int Source2TextureID;
int Mode;
};
[[vk::push_constant]]
CopyPushConstant pushConstants;
PSOutput main(PSInput input)
{
PSOutput output;
int sourceTextureID = pushConstants.SourceTextureID;
int source2TextureID = pushConstants.Source2TextureID;
float2 uv = input.UV;
float4 sampleValue = textures[sourceTextureID].Sample(mySampler[0], input.UV);
float4 sampleValue2 = textures[source2TextureID].Sample(mySampler[0], input.UV);
if(pushConstants.Mode == 0)
{
output.oColor0 = lerp(sampleValue, sampleValue2, 1.0 - sampleValue.a);
}
else if(pushConstants.Mode == 1)
{
output.oColor0 = sampleValue;
output.oColor0 = sampleValue + sampleValue2;
}
return output;
}

View File

@@ -1,30 +0,0 @@
#include "Utils/header.hlsl"
struct CopyPushConstant
{
int SourceTextureID;
int Source2TextureID;
int Mode;
};
[[vk::push_constant]]
CopyPushConstant pushConstants;
// Outputs
struct VSOutput
{
float4 Position : SV_Position;
float2 UV : TEXCOORD0;
};
// Main vertex shader
VSOutput main(uint vertexIndex : SV_VertexID)
{
VSOutput output;
Vertex v = vertexBuffer[vertexIndex];
output.UV = float2(v.uv_x, v.uv_y);
output.Position = float4(v.position, 1.0f);
return output;
}

View File

@@ -1,80 +0,0 @@
#include "Utils/header.hlsl"
struct PSInput
{
float4 Position : SV_Position;
float2 UV : TEXCOORD0;
};
struct PSOutput {
float4 oColor0 : SV_TARGET;
};
struct DepthAwareBlurConstant
{
int DepthTextureID;
int VolumetricTextureID;
};
[[vk::push_constant]]
DepthAwareBlurConstant pushConstants;
float2 GetTextureSize(Texture2D tex)
{
uint width, height;
tex.GetDimensions(width, height);
return float2(width, height);
}
float PixelToUV(float2 uv, Texture2D tex)
{
float2 texSize = GetTextureSize(tex);
return uv / texSize;
}
PSOutput main(PSInput input)
{
int depthTexture = pushConstants.DepthTextureID;
float upSampledDepth = textures[depthTexture].Sample(mySampler[0], input.UV).r;
float3 upSampledColor = textures[pushConstants.VolumetricTextureID].Sample(mySampler[1], input.UV).rgb;
float3 color = 0.0f.xxx;
float totalWeight = 0.0f;
int2 screenCoordinates = int2(input.Position.xy);
int xOffset = (screenCoordinates.x % 2 == 0) ? -1 : 1;
int yOffset = (screenCoordinates.y % 2 == 0) ? -1 : 1;
int2 offsets[] = {int2(0, 0),
int2(0, yOffset),
int2(xOffset, 0),
int2(xOffset, yOffset)};
for (int i = 0; i < 4; i ++)
{
float2 uvOffset = float2(offsets[i].x * 4.0, offsets[i].y * 4.0) ;
uvOffset = PixelToUV(uvOffset, textures[pushConstants.DepthTextureID]);
float3 downscaledColor = textures[pushConstants.VolumetricTextureID].Sample(mySampler[1], input.UV + uvOffset).rgb;
float downscaledDepth = textures[pushConstants.DepthTextureID].Sample(mySampler[0], input.UV + uvOffset).r;
float currentWeight = 1.0f;
if(abs(upSampledDepth - downscaledDepth) > 0.0001)
{
//color = float3(1, 0, 0);
currentWeight *= 0.0f;
}
//currentWeight *= max(0.0f, 1.0f - abs(upSampledDepth - downscaledDepth));
color += downscaledColor * currentWeight;
totalWeight += currentWeight;
}
float3 volumetricLight;
const float epsilon = 0.0001f;
volumetricLight.xyz = color / (totalWeight + epsilon);
PSOutput output;
output.oColor0 = float4(volumetricLight.x, volumetricLight.y, volumetricLight.z, 1.0f);
//output.oColor0 = float4(upSampledColor.x, upSampledColor.y, upSampledColor.z, 1.0f);
return output;
}

View File

@@ -1,29 +0,0 @@
#include "Utils/header.hlsl"
struct DepthAwareBlurConstant
{
int DepthTextureID;
int VolumetricTextureID;
};
[[vk::push_constant]]
DepthAwareBlurConstant pushConstants;
// Outputs
struct VSOutput
{
float4 Position : SV_Position;
float2 UV : TEXCOORD0;
};
// Main vertex shader
VSOutput main(uint vertexIndex : SV_VertexID)
{
VSOutput output;
Vertex v = vertexBuffer[vertexIndex];
output.UV = float2(v.uv_x, v.uv_y);
output.Position = float4(v.position, 1.0f);
return output;
}

View File

@@ -1,66 +0,0 @@
#include "Utils/header.hlsl"
struct PSInput
{
float4 Position : SV_Position;
float2 UV : TEXCOORD0;
};
struct PSOutput
{
float4 oColor0 : SV_TARGET;
float4 oEntityID : SV_TARGET1;
};
struct DebugConstant
{
float4 Color;
float4x4 Transform;
int TextureID;
float EntityID;
};
[[vk::push_constant]]
DebugConstant pushConstants;
PSOutput main(PSInput input)
{
PSOutput output;
if(pushConstants.TextureID < 0)
{
output.oColor0 = float4(input.UV.x, input.UV.y, 0, 1);
}
else
{
float2 uv = input.UV;
float4 textureSample = textures[pushConstants.TextureID].Sample(mySampler[0], uv);
// Alpha scisorring
if(textureSample.a < 0.1)
{
//discard;
}
output.oColor0 = textureSample * pushConstants.Color;
if(pushConstants.EntityID != 0.0f)
{
float2 center = float2(0.5, 0.5);
float dist = distance(uv, center);
float radius = 0.5; // You can adjust this as needed
if (dist <= radius)
{
output.oEntityID = float4(pushConstants.EntityID, 0, 0, 1.0f);
}
else
{
output.oEntityID = float4(0, 0, 0, 0); // Or leave it unassigned if default is zero
discard;
}
}
}
return output;
}

View File

@@ -1,31 +0,0 @@
#include "Utils/header.hlsl"
struct DebugConstant
{
float4 Color;
float4x4 Transform;
int TextureID;
float EntityID;
};
[[vk::push_constant]]
DebugConstant pushConstants;
// Outputs
struct VSOutput
{
float4 Position : SV_Position;
float2 UV : TEXCOORD0;
};
// Main vertex shader
VSOutput main(uint vertexIndex : SV_VertexID)
{
VSOutput output;
Vertex v = vertexBuffer[vertexIndex];
output.UV = float2(v.uv_x, v.uv_y);
output.Position = mul(pushConstants.Transform, float4(v.position, 1.0f));
return output;
}

View File

@@ -1,30 +0,0 @@
#include "Utils/header.hlsl"
struct PSInput
{
float4 Position : SV_Position;
float2 UV : TEXCOORD0;
};
struct PSOutput
{
float4 oColor0 : SV_TARGET;
};
struct LineConstant
{
float4x4 Transform;
float4 Color;
};
[[vk::push_constant]]
LineConstant pushConstants;
PSOutput main(PSInput input)
{
PSOutput output;
output.oColor0 = pushConstants.Color;
return output;
}

View File

@@ -1,29 +0,0 @@
#include "Utils/header.hlsl"
struct LineConstant
{
float4x4 Transform;
float4 Color;
};
[[vk::push_constant]]
LineConstant pushConstants;
// Outputs
struct VSOutput
{
float4 Position : SV_Position;
float2 UV : TEXCOORD0;
};
// Main vertex shader
VSOutput main(uint vertexIndex : SV_VertexID)
{
VSOutput output;
Vertex v = vertexBuffer[vertexIndex];
output.UV = float2(v.uv_x, v.uv_y);
output.Position = mul(pushConstants.Transform, float4(v.position, 1.0f));
return output;
}

View File

@@ -1,106 +0,0 @@
#include "Utils/header.hlsl"
struct PSInput
{
float4 Position : SV_Position;
float2 UV : TEXCOORD0;
};
struct PSOutput {
float4 oColor0 : SV_TARGET;
};
struct OutlinePushConstant
{
float4 Color;
float Thickness;
int SourceTextureID;
int EntityIDTextureID;
int DepthTextureID;
float SelectedEntity;
};
[[vk::push_constant]]
OutlinePushConstant pushConstants;
float2 GetTexelSize(Texture2D tex)
{
uint width, height;
tex.GetDimensions(width, height);
return 1.0 / float2(width, height);
}
float LinearizeDepth(float depth, float nearPlane, float farPlane)
{
return (2.0 * nearPlane) / (farPlane + nearPlane - (1.0 - depth) * (farPlane - nearPlane));
}
PSOutput main(PSInput input)
{
PSOutput output;
float4 outlineColor = pushConstants.Color;
float target = pushConstants.SelectedEntity;
float radius = pushConstants.Thickness;
float2 uv = input.UV;
int entityIDTextureID = pushConstants.EntityIDTextureID;
float hasHit = 0.0f;
float sampleValue = textures[entityIDTextureID].Sample(mySampler[0], uv).r;
float depth = textures[pushConstants.DepthTextureID].Sample(mySampler[0], uv).r;
float4 fragColor = float4(0, 0, 0, 0);
const float TAU = 6.28318530;
const float steps = 64.0;
for(float i = 0.0f; i < TAU; i += TAU / steps)
{
float2 uvOffset = float2(cos(i), sin(i)) * (GetTexelSize(textures[entityIDTextureID])) * radius;
float2 sampleUV = uv + uvOffset;
sampleUV.x = clamp(sampleUV.x, 0.0, 0.999);
sampleUV.y = clamp(sampleUV.y, 0.0, 0.999);
float sample = textures[entityIDTextureID].Sample(mySampler[0], sampleUV).r;
float sampleDepth = textures[pushConstants.DepthTextureID].Sample(mySampler[0], sampleUV).r;
//sampleDepth = LinearizeDepth(sampleDepth, 0.1f, 200.0f);
//depth = LinearizeDepth(depth, 0.1f, 200.0f);
bool passDepthTest = (sampleDepth > depth);
if(sample == target && passDepthTest)
{
hasHit = 1.0f;
if(passDepthTest && sampleValue == target)
{
//hasHit = 0.0f;
}
}
float alpha = smoothstep(0.1, 0.9, hasHit);
float4 outputColor = float4(
lerp(fragColor.r, outlineColor.r, alpha),
lerp(fragColor.g, outlineColor.g, alpha),
lerp(fragColor.b, outlineColor.b, alpha),
lerp(fragColor.a, outlineColor.a, alpha)
);
fragColor = outputColor;
}
if(fragColor.a > 0.1)
{
fragColor.a = 1.0f;
}
float3 sourceTexture = textures[pushConstants.SourceTextureID].Sample(mySampler[0], uv).rgb;
float ratio = float(sampleValue != target && hasHit > 0.0f);
float4 finalColor = float4(
lerp(sourceTexture.r, fragColor.r, ratio),
lerp(sourceTexture.g, fragColor.g, ratio),
lerp(sourceTexture.b, fragColor.b, ratio),
lerp(1.0f, fragColor.a, ratio)
);
output.oColor0 = finalColor;
return output;
}

View File

@@ -1,33 +0,0 @@
#include "Utils/header.hlsl"
struct OutlinePushConstant
{
float4 Color;
float Thickness;
int SourceTextureID;
int EntityIDTextureID;
int DepthTextureID;
float SelectedEntity;
};
[[vk::push_constant]]
OutlinePushConstant pushConstants;
// Outputs
struct VSOutput
{
float4 Position : SV_Position;
float2 UV : TEXCOORD0;
};
// Main vertex shader
VSOutput main(uint vertexIndex : SV_VertexID)
{
VSOutput output;
Vertex v = vertexBuffer[vertexIndex];
output.UV = float2(v.uv_x, v.uv_y);
output.Position = float4(v.position, 1.0f);
return output;
}

View File

@@ -1,337 +0,0 @@
#include "Utils/header.hlsl"
struct PSInput
{
float4 Position : SV_Position;
float2 UV : TEXCOORD0;
};
struct PSOutput {
float4 oColor0 : SV_TARGET;
};
struct ShadingPushConstant
{
int AlbedoInputTextureId;
int DepthInputTextureId;
int NormalInputTextureId;
int MaterialInputTextureId;
int LightOffset;
int LightCount;
int CameraID;
float AmbientTerm;
float cascadeDepth[4];
int SSAOTextureId;
int EntityTextureId;
};
[[vk::push_constant]]
ShadingPushConstant pushConstants;
float3 WorldPosFromDepth(float depth, float2 uv, float4x4 invProj, float4x4 invView)
{
float z = depth;
float4 clipSpacePosition = float4(uv.x * 2.0 - 1.0, (uv.y * 2.0 - 1.0), z, 1.0f);
float4 viewSpacePosition = mul(invProj, clipSpacePosition);
viewSpacePosition /= viewSpacePosition.w;
float4 worldSpacePosition = mul(invView, viewSpacePosition);
return worldSpacePosition.xyz;
}
float LinearizeDepth(float depth, float nearPlane, float farPlane, bool reverseDepth)
{
if (reverseDepth)
{
// Reverse depth (near plane = 1.0, far plane = 0.0)
return nearPlane * farPlane / lerp(farPlane, nearPlane, depth);
}
else
{
// Standard depth (near plane = 0.0, far plane = 1.0)
return (2.0 * nearPlane * farPlane) / (farPlane + nearPlane - depth * (farPlane - nearPlane));
}
}
float DistributionGGX(float3 N, float3 H, float a)
{
float PI = 3.141592653589793f;
float a2 = a * a;
float NdotH = max(dot(N, H), 0.0);
float NdotH2 = NdotH * NdotH;
float nom = a2;
float denom = (NdotH2 * (a2 - 1.0) + 1.0);
denom = PI * denom * denom;
return nom / denom;
}
float GeometrySchlickGGX(float NdotV, float k)
{
float nom = NdotV;
float denom = NdotV * (1.0 - k) + k;
return nom / denom;
}
float GeometrySmith(float3 N, float3 V, float3 L, float k)
{
float NdotV = max(dot(N, V), 0.0);
float NdotL = max(dot(N, L), 0.0);
float ggx1 = GeometrySchlickGGX(NdotV, k);
float ggx2 = GeometrySchlickGGX(NdotL, k);
return ggx1 * ggx2;
}
float3 fresnelSchlick(float cosTheta, float3 F0)
{
return F0 + (1.0 - F0) * pow(max(1.0 - cosTheta, 0.0), 5.0);
}
float3 fresnelSchlickRoughness(float cosTheta, float3 F0, float roughness)
{
float roughnessTerm = 1.0f - roughness;
return F0 + (max(float3(roughnessTerm, roughnessTerm, roughnessTerm), F0) - F0) * pow(max(1.0 - cosTheta, 0.0), 5.0);
}
float linearDepth(float z, float near, float far) {
return near * far / (far - z * (far - near));
}
int GetCSMSplit(float depth)
{
for(int i = 0; i < 4; i++)
{
float csmSplitDepth = pushConstants.cascadeDepth[i];
if(depth < csmSplitDepth + 0.000001)
{
return i;
}
}
return 0;
}
float SampleShadowMap(int textureId, float2 coords, float compare)
{
return compare > textures[textureId].Sample(mySampler[0], coords.xy).r;
}
float SampleShadowMapLinear(int textureId, float2 coords, float compare, float2 texelSize)
{
float2 pixelPos = coords / texelSize + float2(0.5f, 0.5f);
float2 fracPart = frac(pixelPos);
float2 startTexel = (pixelPos - fracPart) * texelSize;
float blTexel = SampleShadowMap(textureId, startTexel, compare);
float brTexel = SampleShadowMap(textureId, startTexel + float2(texelSize.x, 0.0), compare);
float tlTexel = SampleShadowMap(textureId, startTexel + float2(0.0, texelSize.y), compare);
float trTexel = SampleShadowMap(textureId, startTexel + texelSize, compare);
float mixA = lerp(blTexel, tlTexel, fracPart.y);
float mixB = lerp(brTexel, trTexel, fracPart.y);
return lerp(mixA, mixB, fracPart.x);
}
float ShadowCalculation(Light light, float3 fragPos, float3 normal)
{
// Find correct CSM splits from depth
CameraView camView = cameras[pushConstants.CameraID];
float depth = length(fragPos - camView.Position);
int splitIndex = GetCSMSplit(depth);
// Calculate shadows for found split
CameraView lightView = cameras[light.transformId[splitIndex]];
int shadowMap = light.shadowMapTextureId[0];
float4 fragLightSpace = mul(lightView.Projection, mul(lightView.View, float4(fragPos, 1.0)));
float3 projCoords = fragLightSpace.xyz / fragLightSpace.w;
projCoords.xy = projCoords.xy * 0.5 + 0.5;
if (projCoords.x < 0.0 || projCoords.x > 1.0 || projCoords.y < 0.0 || projCoords.y > 1.0) {
return 1.0;
}
//projCoords.y = 1.0 - projCoords.y;
float currentDepth = projCoords.z;
float bias = max(0.005 * (1.0 - dot(normal, light.direction)), 0.0005);
if(splitIndex < 2)
{
const float NUM_SAMPLES = 4.0f;
const float SAMPLES_START = (NUM_SAMPLES - 1.0f) / 2.0f;
const float NUM_SAMPLES_SQUARED = NUM_SAMPLES * NUM_SAMPLES;
float2 texelSize = 1.0f / float2(4096, 4096);
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)
{
float2 coordsOffset = float2(x, y) * texelSize;
result += SampleShadowMapLinear(light.shadowMapTextureId[splitIndex], projCoords.xy + coordsOffset, currentDepth, texelSize);
}
}
return result /= NUM_SAMPLES_SQUARED;
}
float shadowMapDepth = textures[light.shadowMapTextureId[splitIndex]].Sample(mySampler[0], projCoords.xy).r;
return (currentDepth > shadowMapDepth);//> 0.0 ? 1.0 : 0.0;
}
PSOutput main(PSInput input)
{
PSOutput output;
CameraView camView = cameras[pushConstants.CameraID];
int depthTexture = pushConstants.DepthInputTextureId;
float depth = textures[depthTexture].Sample(mySampler[0], input.UV).r;
if(depth == 0.0f)
{
discard;
}
int albedoTextureId = pushConstants.AlbedoInputTextureId;
float3 albedo = textures[albedoTextureId].Sample(mySampler[0], input.UV).xyz;
int materialId = (int)textures[pushConstants.EntityTextureId].Sample(mySampler[0], input.UV).g;
Material inMaterial = material[materialId];
if(inMaterial.unlit)
{
output.oColor0 = float4(albedo, 1);
return output;
}
float3 worldPos = WorldPosFromDepth(depth, input.UV, camView.InverseProjection, camView.InverseView);
float3 normal = textures[pushConstants.NormalInputTextureId].Sample(mySampler[0], input.UV).rgb;
normal = normal * 2.0f - 1.0f;
float4 materialSample = textures[pushConstants.MaterialInputTextureId].Sample(mySampler[0], input.UV);
float metallic = materialSample.r;
float ao = materialSample.g;
float roughness = materialSample.b;
float ssao = textures[pushConstants.SSAOTextureId].Sample(mySampler[0], input.UV).r;
float3 N = normal;
float3 V = normalize(camView.Position - worldPos);
float3 R = reflect(-V, N);
float3 F0 = float3(0.04, 0.04, 0.04);
F0 = lerp(F0, albedo, metallic);
Light directionalLight;
bool foundDirectional = false;
for(int i = pushConstants.LightOffset; i < pushConstants.LightOffset + pushConstants.LightCount; i++)
{
Light light = lights[i];
if(light.type == 0)
{
directionalLight = light;
foundDirectional = true;
break;
}
}
const float PI = 3.141592653589793f;
float3 Lo = float3(0.0, 0.0, 0.0);
float shadow = 1.0f;
if(foundDirectional == false)
{
shadow = 1.0f;
}
//Directional
if(foundDirectional)
{
Light light = directionalLight;
float3 L = normalize(light.direction);
float attenuation = 1.0f;
if(light.castShadow == true)
{
shadow *= ShadowCalculation(light, worldPos, N);
//output.oColor0 = float4(albedo * 0.1 + float3(shadow, shadow, shadow), 1);
//return output;
}
// TODO: Shadow
float3 radiance = light.color.rgb * attenuation;
float3 H = normalize(V + L);
float NDF = DistributionGGX(N, H, roughness);
float G = GeometrySmith(N, V, L, roughness);
float3 F = fresnelSchlick(max(dot(H, V), 0.0), F0);
float3 nominator = NDF * G * F;
float denominator = 4 * max(dot(N, V), 0.0) * max(dot(N, L), 0.0) + 0.001; // 0.001 to prevent divide by zero.
float3 specular = nominator / denominator;
float3 kS = F;
float3 kD = float3(1.0, 1.0, 1.0) - kS;
kD *= 1.0 - metallic;
float NdotL = max(dot(N, L), 0.0);
if(inMaterial.receiveShadow == 0)
{
shadow = 1.0f;
}
Lo += (kD * albedo / PI + specular) * radiance * NdotL * shadow;
}
// other lights
for(int i = pushConstants.LightOffset; i < pushConstants.LightOffset + pushConstants.LightCount; i++)
{
Light light = lights[i];
float3 L = normalize(light.position - worldPos);
float distance = length(light.position - worldPos);
float attenuation = 1.0 / (distance * distance);
float3 radiance = float3(0, 0, 0);
if(light.type == 1) // point light
{
radiance = light.color * attenuation;
}
else if(light.type == 2)
{
float theta = dot(L, normalize(-light.direction));
float epsilon = light.innerConeAngle - light.outerConeAngle;
float intensity = clamp((theta - light.outerConeAngle) / epsilon, 0.0, 1.0);
radiance = light.color * intensity * attenuation;
}
float3 H = normalize(V + L);
float NDF = DistributionGGX(N, H, roughness);
float G = GeometrySmith(N, V, L, roughness);
float3 F = fresnelSchlick(max(dot(H, V), 0.0), F0);
float3 nominator = NDF * G * F;
float denominator = 4 * max(dot(N, V), 0.0) * max(dot(N, L), 0.0) + 0.001; // 0.001 to prevent divide by zero.
float3 specular = nominator / denominator;
float3 kS = F;
float3 kD = float3(1.0, 1.0, 1.0) - kS;
kD *= 1.0 - metallic;
float NdotL = max(dot(N, L), 0.0);
Lo += (kD * albedo / PI + specular) * radiance * NdotL;
}
float3 F = fresnelSchlickRoughness(max(dot(N, V), 0.0), F0, roughness);
float3 kS = F;
float3 kD = 1.0 - kS;
kD *= 1.0 - metallic;
float3 ambient = (albedo) * ao * ssao * pushConstants.AmbientTerm;
float3 color = (ambient) + Lo;
output.oColor0 = float4(color, 1);
return output;
}

View File

@@ -1,39 +0,0 @@
#include "Utils/header.hlsl"
struct ShadingPushConstant
{
int AlbedoInputTextureId;
int DepthInputTextureId;
int NormalInputTextureId;
int MaterialInputTextureId;
int LightOffset;
int LightCount;
int CameraID;
float AmbientTerm;
float cascadeDepth[4];
int SSAOTextureId;
int EntityTextureId;
};
[[vk::push_constant]]
ShadingPushConstant pushConstants;
// Outputs
struct VSOutput
{
float4 Position : SV_Position;
float2 UV : TEXCOORD0;
};
// Main vertex shader
VSOutput main(uint vertexIndex : SV_VertexID)
{
VSOutput output;
Vertex v = vertexBuffer[vertexIndex];
output.UV = float2(v.uv_x, v.uv_y);
output.Position = float4(v.position, 1.0f);
return output;
}

View File

@@ -1,31 +0,0 @@
#include "Utils/header.hlsl"
struct PSInput
{
float4 Position : SV_Position;
float2 UV : TEXCOORD0;
};
struct ModelPushConstant
{
int modelIndex; // Push constant data
int materialIndex;
int cameraID;
};
[[vk::push_constant]]
ModelPushConstant pushConstants;
void main(PSInput input)
{
Material inMaterial = material[pushConstants.materialIndex];
if(inMaterial.alphaScissor == 1)
{
SamplerState samplerr = mySampler[inMaterial.samplingType];
float albedoAlpha = textures[inMaterial.albedoTextureId].Sample(samplerr, input.UV).a;
if(albedoAlpha < 0.1f)
{
discard;
}
}
}

View File

@@ -1,51 +0,0 @@
#include "Utils/header.hlsl"
struct ModelPushConstant
{
int modelIndex; // Push constant data
int materialIndex;
int cameraID;
};
[[vk::push_constant]]
ModelPushConstant pushConstants;
// Outputs
struct VSOutput
{
float4 Position : SV_Position;
float2 UV : TEXCOORD0;
};
float LinearizeDepth(float depth, float nearPlane, float farPlane, bool reverseDepth)
{
if (reverseDepth)
{
// Reverse depth (near plane = 1.0, far plane = 0.0)
return nearPlane * farPlane / lerp(farPlane, nearPlane, depth);
}
else
{
// Standard depth (near plane = 0.0, far plane = 1.0)
return (2.0 * nearPlane * farPlane) / (farPlane + nearPlane - depth * (farPlane - nearPlane));
}
}
// Main vertex shader
VSOutput main(uint vertexIndex : SV_VertexID)
{
VSOutput output;
ModelData modelData = model[pushConstants.modelIndex];
CameraView camView = cameras[pushConstants.cameraID];
// Load vertex data from the buffer
Vertex v = vertexBuffer[vertexIndex];
// Output the position of each vertex
output.Position = mul(camView.Projection, mul(camView.View,mul(modelData.model, float4(v.position, 1.0f))));
output.UV = float2(v.uv_x, v.uv_y);
//output.Position.z = LinearizeDepth(output.Position.z, camView.Near, camView.Far, false);
return output;
}

View File

@@ -1,143 +0,0 @@
#include "Utils/header.hlsl"
[[vk::binding(0, 7)]]
StructuredBuffer<float3> ssaoKernels;
struct PSInput {
float4 Position : SV_Position;
float2 UV : TEXCOORD0;
};
struct PSOutput {
float4 oColor0 : SV_TARGET;
};
struct SSAOConstant
{
int noiseTextureID;
int normalTextureID;
int depthTextureID;
int camViewID;
float radius;
float bias;
float2 noiseScale;
float power;
};
[[vk::push_constant]]
SSAOConstant pushConstants;
float3 ViewPosFromDepth(float depth, float2 uv, float4x4 invProj)
{
float z = depth;
float4 clipSpacePosition = float4(uv.x * 2.0 - 1.0, (uv.y * 2.0 - 1.0), z, 1.0f);
float4 viewSpacePosition = mul(invProj, clipSpacePosition);
viewSpacePosition /= viewSpacePosition.w;
return viewSpacePosition.xyz;
}
float3 WorldPosFromDepth(float depth, float2 uv, CameraView camera)
{
float z = depth;
float4 clipSpacePosition = float4(uv.x * 2.0 - 1.0, (uv.y * 2.0 - 1.0), z, 1.0f);
float4 viewSpacePosition = mul(camera.InverseProjection, clipSpacePosition);
viewSpacePosition /= viewSpacePosition.w;
float4 worldSpacePosition = mul(camera.InverseView, viewSpacePosition);
worldSpacePosition /= worldSpacePosition.w;
return worldSpacePosition.xyz;
}
float3 SampleTexture(int textureId, float2 uv)
{
return textures[textureId].Sample(mySampler[0], uv).rgb;
}
float SampleDepth(float2 uv)
{
return textures[pushConstants.depthTextureID].Sample(mySampler[0], uv).r;
}
float3x3 Inverse3x3(float3x3 m)
{
float3 r0 = cross(m[1], m[2]);
float3 r1 = cross(m[2], m[0]);
float3 r2 = cross(m[0], m[1]);
float det = dot(r2, m[2]);
float invDet = 1.0 / det;
return float3x3(
r0 * invDet,
r1 * invDet,
r2 * invDet
);
}
PSOutput main(PSInput input)
{
CameraView camera = cameras[pushConstants.camViewID];
float depth = SampleDepth(input.UV);
// Discard the sky
if(depth < 0.00001)
{
discard;
}
// Calculate TBN
float3x3 normalMatrix = (float3x3)camera.View;
//normalMatrix[0] *= -1.0; // Flip the Z basis vector
float3 normal = SampleTexture(pushConstants.normalTextureID, input.UV).xyz * 2.0 - 1.0;
normal = mul(normalMatrix, normal);
float2 randomVecSample = SampleTexture(pushConstants.noiseTextureID, input.UV * pushConstants.noiseScale).xy * 2.0 - 1.0;
float3 randomVec = float3(randomVecSample.x, -randomVecSample.y, 0);
//randomVec = float3(0, 1, 0);
float3 tangent = normalize(randomVec - normal * dot(randomVec, normal));
float3 bitangent = cross(normal, tangent);
float3x3 TBN = float3x3(tangent, bitangent, normal);
float3 fragPos = ViewPosFromDepth(depth, input.UV, camera.InverseProjection);
// Fix from: https://github.com/JoeyDeVries/LearnOpenGL/issues/364
float4 fragWorldPos = mul(camera.InverseView, float4(fragPos, 1.0));
fragWorldPos.xyz /= fragWorldPos.w;
PSOutput output;
float occlusion = 0.0f;
for(int i = 0; i < 64; i++)
{
float3 samplePos = mul(ssaoKernels[i], TBN);
samplePos = fragPos + samplePos * pushConstants.radius;
//samplePos = fragWorldPos + samplePos * pushConstants.radius;
//return output;
// Fix from: https://github.com/JoeyDeVries/LearnOpenGL/issues/364
float4 worldSamplePos = mul(camera.View, float4(samplePos, 1.0));
worldSamplePos.xyz /= worldSamplePos.w;
//samplePos = worldSamplePos.xyz;
float4 offset = float4(samplePos, 1.0f);
offset = mul(camera.Projection, offset);
offset.xyz /= offset.w;
offset.xyz = offset.xyz * 0.5 + 0.5;
offset.x = clamp(offset.x, 0.00001, 0.999);
offset.y = clamp(offset.y, 0.00001, 0.999);
float sampleDepth = ViewPosFromDepth(SampleDepth(offset.xy), offset.xy, camera.InverseProjection).z;
float rangeCheck = smoothstep(0.0, 1.0, pushConstants.radius / abs(sampleDepth - fragPos.z));
occlusion += (sampleDepth - pushConstants.bias >= samplePos.z ? 1.0 : 0.0) * rangeCheck;
}
occlusion = 1.0 - (occlusion / 64.0);
occlusion = pow(occlusion, pushConstants.power);
output.oColor0 = float4(occlusion, occlusion, occlusion, 1.0f);
return output;
}

View File

@@ -1,36 +0,0 @@
#include "Utils/header.hlsl"
[[vk::binding(0, 7)]]
StructuredBuffer<float3> ssaoKernels;
struct SSAOConstant
{
int noiseTextureID;
int normalTextureID;
int depthTextureID;
float radius;
float bias;
float2 noiseScale;
float power;
};
[[vk::push_constant]]
SSAOConstant pushConstants;
// Outputs
struct VSOutput {
float4 Position : SV_Position;
float2 UV : TEXCOORD0;
};
// Main vertex shader
VSOutput main(uint vertexIndex : SV_VertexID)
{
VSOutput output;
Vertex v = vertexBuffer[vertexIndex];
output.UV = float2(v.uv_x, v.uv_y);
output.Position = float4(v.position, 1.0f);
return output;
}

View File

@@ -1,28 +0,0 @@
struct VSInput
{
[[vk::location(0)]] float3 Position : POSITION0;
[[vk::location(1)]] float3 Color : COLOR0;
};
struct UBO
{
float4x4 projectionMatrix;
float4x4 modelMatrix;
float4x4 viewMatrix;
};
cbuffer ubo : register(b0, space0) { UBO ubo; }
struct VSOutput
{
float4 Pos : SV_POSITION;
[[vk::location(0)]] float3 Color : COLOR0;
};
VSOutput main(VSInput input, uint VertexIndex : SV_VertexID)
{
VSOutput output = (VSOutput)0;
output.Color = input.Color * float(VertexIndex);
output.Pos = mul(ubo.projectionMatrix, mul(ubo.viewMatrix, mul(ubo.modelMatrix, float4(input.Position.xyz, 1.0))));
return output;
}

View File

@@ -1,52 +0,0 @@
#include "Utils/header.hlsl"
struct PSInput {
float4 Position : SV_Position;
float2 UV : TEXCOORD0;
};
struct PSOutput {
float4 oColor0 : SV_TARGET;
};
struct TonemapPushConstant
{
float Exposure;
float Gamma;
int SourceTextureID;
};
[[vk::push_constant]]
TonemapPushConstant pushConstants;
float3 PBRNeutralToneMapping(float3 color)
{
const float startCompression = 0.8 - 0.04;
const float desaturation = 0.15;
float x = min(color.r, min(color.g, color.b));
float offset = x < 0.08 ? x - 6.25 * x * x : 0.04;
color -= offset;
float peak = max(color.r, max(color.g, color.b));
if (peak < startCompression) return color;
const float d = 1. - startCompression;
float newPeak = 1. - d * d / (peak + d - startCompression);
color *= newPeak / peak;
float g = 1. - 1. / (desaturation * (peak - newPeak) + 1.);
return lerp(color, newPeak * float3(1, 1, 1), g);
}
PSOutput main(PSInput input)
{
PSOutput output;
float3 color = textures[pushConstants.SourceTextureID].Sample(mySampler[0], input.UV).rgb;
float3 mapped = float3(1.0, 1.0, 1.0) - exp(-color * pushConstants.Exposure);
color = pow(mapped, float3(pushConstants.Gamma, pushConstants.Gamma, pushConstants.Gamma));
output.oColor0 = float4(color, 1);
return output;
}

View File

@@ -1,30 +0,0 @@
#include "Utils/header.hlsl"
struct TonemapPushConstant
{
float Exposure;
float Gamma;
int SourceTextureID;
};
[[vk::push_constant]]
TonemapPushConstant pushConstants;
// Outputs
struct VSOutput {
float4 Position : SV_Position;
float2 UV : TEXCOORD0;
};
// Main vertex shader
VSOutput main(uint vertexIndex : SV_VertexID)
{
VSOutput output;
Vertex v = vertexBuffer[vertexIndex];
output.UV = float2(v.uv_x, v.uv_y);
output.Position = float4(v.position, 1.0f);
return output;
}

View File

@@ -1,111 +0,0 @@
#include "Utils/header.hlsl"
struct PSInput
{
float4 Position : SV_Position;
float3 Color : TEXCOORD0;
float2 UV : TEXCOORD1;
float3 Normal : TEXCOORD2;
float3 Tangent : TEXCOORD3;
float3 Bitangent : TEXCOORD4;
};
struct PSOutput {
float4 oColor0 : SV_TARGET;
float4 oNormal : SV_TARGET1;
float4 oMaterial : SV_TARGET2;
float4 oEntityID : SV_TARGET3;
};
struct ModelPushConstant
{
int modelIndex; // Push constant data
int materialIndex;
int cameraID;
float entityID;
};
[[vk::push_constant]]
ModelPushConstant pushConstants;
PSOutput main(PSInput input)
{
PSOutput output;
Material inMaterial = material[pushConstants.materialIndex];
SamplerState samplerr = mySampler[inMaterial.samplingType];
// ALBEDO COLOR
float4 albedoColor = float4(inMaterial.albedo.xyz, 1.0f);
if(inMaterial.hasAlbedo == 1)
{
float4 albedoSample = textures[inMaterial.albedoTextureId].Sample(samplerr, input.UV);
// Alpha cutout?
if(inMaterial.alphaScissor == 1 && albedoSample.a < 0.001f)
{
discard;
}
albedoColor.xyz = albedoSample.xyz * albedoColor.xyz;
}
output.oColor0 = albedoColor;
// NORMAL
// TODO use TBN matrix
float3 T = input.Tangent.xyz;
float3 B = input.Bitangent.xyz;
float3 N = input.Normal.xyz;
float3x3 TBN = float3x3(T, B, N);
float3 normal = float3(0.0, 0.0, 1.0);
if(inMaterial.hasNormal == 1)
{
normal = textures[inMaterial.normalTextureId].Sample(samplerr, input.UV).rgb;
normal.xyz = normal.zxy;
normal = normal * 2.0f - 1.0f;
}
else
{
normal = normal;
}
//normal = input.Normal;
normal = mul(transpose(TBN), normal);
normal = normal / 2.0f + 0.5f;
output.oNormal = float4(normal, 1.0f);
// MATERIAL
// MATERIAL PROPERTIES
float metalnessValue = inMaterial.metalnessValue;
if(inMaterial.hasMetalness == 1)
{
// TODO: Sample from metal texture
}
float aoValue = inMaterial.aoValue;
if(inMaterial.hasAO == 1)
{
// TODO: Sample from AO texture
}
float roughnessValue = inMaterial.roughnessValue;
if(inMaterial.hasRoughness == 1)
{
// TODO: Sample from roughness texture
}
float3 materialOuput = float3(inMaterial.metalnessValue, inMaterial.aoValue, inMaterial.roughnessValue);
output.oMaterial = float4(materialOuput, 1.0f);
output.oEntityID = float4(pushConstants.entityID, pushConstants.materialIndex, 0.0f, 1.0f);
return output;
}

View File

@@ -1,74 +0,0 @@
#include "Utils/header.hlsl"
struct ModelPushConstant
{
int modelIndex; // Push constant data
int materialIndex;
int cameraID;
float entityID;
};
[[vk::push_constant]]
ModelPushConstant pushConstants;
// Outputs
struct VSOutput
{
float4 Position : SV_Position;
float3 Color : TEXCOORD0;
float2 UV : TEXCOORD1;
float3 Normal : TEXCOORD2;
float3 Tangent : TEXCOORD3;
float3 Bitangent : TEXCOORD4;
};
float3x3 invert(float3x3 m)
{
float3 a = m[0];
float3 b = m[1];
float3 c = m[2];
float3 r0 = cross(b, c);
float3 r1 = cross(c, a);
float3 r2 = cross(a, b);
float det = dot(r2, c);
// Return identity if not invertible (optional fallback)
if (abs(det) < 1e-6)
return float3x3(1.0, 0.0, 0.0,
0.0, 1.0, 0.0,
0.0, 0.0, 1.0);
float invDet = 1.0 / det;
return float3x3(r0 * invDet,
r1 * invDet,
r2 * invDet);
}
// Main vertex shader
VSOutput main(uint vertexIndex : SV_VertexID)
{
VSOutput output;
CameraView camView = cameras[pushConstants.cameraID];
ModelData modelData = model[pushConstants.modelIndex];
// Load vertex data from the buffer
Vertex v = vertexBuffer[vertexIndex];
// Output the position of each vertex
output.Position = mul(camView.Projection, mul(camView.View, mul(modelData.model, float4(v.position, 1.0f))));
output.Color = normalize(float3(v.position.xyz));
output.UV = float2(v.uv_x, v.uv_y);
float3x3 upper3x3 = (float3x3)modelData.model;
float3x3 normalMatrix = transpose(invert(upper3x3));
output.Bitangent = mul(normalMatrix, normalize(v.bitangent.xyz));
output.Normal = mul(normalMatrix, normalize(v.normal.xyz));
output.Tangent = mul(normalMatrix, normalize(v.tangent.xyz));
//output.Normal = v.normal.xyz;
return output;
}

View File

@@ -1,267 +0,0 @@
#include "Utils/header.hlsl"
struct PSInput
{
float4 Position : SV_Position;
float2 UV : TEXCOORD0;
};
struct PSOutput {
float4 oColor0 : SV_TARGET;
};
struct VolumetricConstant
{
int DepthTextureID;
int StepCount;
float FogAmount;
float Exponant;
int CamViewID;
int LightCount;
float Ambient;
float Time;
float NoiseSpeed;
float NoiseScale;
float NoiseStrength;
float CSMSplits[4];
};
[[vk::push_constant]]
VolumetricConstant pushConstants;
float2 GetTexelSize(Texture2D tex)
{
uint width, height;
tex.GetDimensions(width, height);
return 1.0 / float2(width, height);
}
float LinearizeDepth(float depth, float nearPlane, float farPlane)
{
return (2.0 * nearPlane) / (farPlane + nearPlane - (1.0 - depth) * (farPlane - nearPlane));
}
float ComputeScattering(float lightDotView)
{
float PI = 3.141592653589793f;
float result = 1.0f - pushConstants.FogAmount;
result /= (4.0f * PI * pow(1.0f + pushConstants.FogAmount * pushConstants.FogAmount - (1.0f * pushConstants.FogAmount) * lightDotView, 1.5f));
return result;
}
float3 WorldPosFromDepth(float depth, float2 uv, float4x4 invProj, float4x4 invView)
{
float z = depth;
float4 clipSpacePosition = float4(uv.x * 2.0 - 1.0, (uv.y * 2.0 - 1.0), z, 1.0f);
float4 viewSpacePosition = mul(invProj, clipSpacePosition);
viewSpacePosition /= viewSpacePosition.w;
float4 worldSpacePosition = mul(invView, viewSpacePosition);
return worldSpacePosition.xyz;
}
// Simplex 3D Noise
float mod289(float x) { return x - floor(x * (1.0 / 289.0)) * 289.0; }
float3 mod289(float3 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; }
float4 mod289(float4 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; }
float4 permute(float4 x) { return mod289(((x*34.0)+1.0)*x); }
float4 taylorInvSqrt(float4 r) { return 1.79284291400159 - 0.85373472095314 * r; }
float snoise(float3 v)
{
const float2 C = float2(1.0/6.0, 1.0/3.0) ;
const float4 D = float4(0.0, 0.5, 1.0, 2.0);
// First corner
float3 i = floor(v + dot(v, C.yyy));
float3 x0 = v - i + dot(i, C.xxx);
// Other corners
float3 g = step(x0.yzx, x0.xyz);
float3 l = 1.0 - g;
float3 i1 = min(g.xyz, l.zxy);
float3 i2 = max(g.xyz, l.zxy);
// x0 = x0 - 0.0 + 0.0 * C.xxx;
float3 x1 = x0 - i1 + C.xxx;
float3 x2 = x0 - i2 + C.yyy;
float3 x3 = x0 - 1.0 + 3.0 * C.xxx;
// Permutations
i = mod289(i);
float4 p = permute(permute(permute(
i.z + float4(0.0, i1.z, i2.z, 1.0))
+ i.y + float4(0.0, i1.y, i2.y, 1.0))
+ i.x + float4(0.0, i1.x, i2.x, 1.0));
// Gradients: 7x7 points over a cube, mapped onto a unit sphere
float4 j = p - 49.0 * floor(p * (1.0 / 49.0)); // mod(p,7*7)
float4 x_ = floor(j * (1.0 / 7.0));
float4 y_ = floor(j - 7.0 * x_); // mod(j,7)
float4 x = (x_ * 2.0 + 0.5) / 7.0 - 1.0;
float4 y = (y_ * 2.0 + 0.5) / 7.0 - 1.0;
float4 h = 1.0 - abs(x) - abs(y);
float4 b0 = float4(x.xy, y.xy);
float4 b1 = float4(x.zw, y.zw);
float4 s0 = floor(b0) * 2.0 + 1.0;
float4 s1 = floor(b1) * 2.0 + 1.0;
float4 sh = -step(h, 0.0);
float4 a0 = b0.xzyw + s0.xzyw * sh.xxyy;
float4 a1 = b1.xzyw + s1.xzyw * sh.zzww;
float3 g0 = float3(a0.xy, h.x);
float3 g1 = float3(a0.zw, h.y);
float3 g2 = float3(a1.xy, h.z);
float3 g3 = float3(a1.zw, h.w);
// Normalize gradients
float4 norm = taylorInvSqrt(float4(dot(g0,g0), dot(g1,g1), dot(g2,g2), dot(g3,g3)));
g0 *= norm.x;
g1 *= norm.y;
g2 *= norm.z;
g3 *= norm.w;
// Mix final noise value
float4 m = max(0.6 - float4(dot(x0,x0), dot(x1,x1), dot(x2,x2), dot(x3,x3)), 0.0);
m = m * m;
return 42.0 * dot(m*m, float4(dot(g0,x0), dot(g1,x1), dot(g2,x2), dot(g3,x3)));
}
int GetCSMSplit(float depth)
{
for(int i = 0; i < 4; i++)
{
float csmSplitDepth = pushConstants.CSMSplits[i];
if(depth < csmSplitDepth + 0.000001)
{
return i;
}
}
return 0;
}
PSOutput main(PSInput input)
{
float ditherPattern[4][4] = { { 0.0f, 0.5f, 0.125f, 0.625f},
{ 0.75f, 0.22f, 0.875f, 0.375f},
{ 0.1875f, 0.6875f, 0.0625f, 0.5625},
{ 0.9375f, 0.4375f, 0.8125f, 0.3125} };
CameraView camView = cameras[pushConstants.CamViewID];
float3 startPosition = camView.Position;
int depthTexture = pushConstants.DepthTextureID;
float depth = textures[depthTexture].Sample(mySampler[0], input.UV).r;
float3 worldPos = WorldPosFromDepth(depth, input.UV, camView.InverseProjection, camView.InverseView);
float3 rayVector = worldPos - startPosition;
float rayLength = length(rayVector);
PSOutput output;
if(rayLength > 1000.0)
{
output.oColor0 = float4(0.0f, 0.0f, 0, 0.0f);
//return output;
}
float stepLength = rayLength / pushConstants.StepCount;
float3 rayDirection = rayVector / rayLength;
float3 step = rayDirection * stepLength;
float3 accumFog = float3(0, 0, 0);
float3 currentPosition = startPosition;
for(int i = 0; i < pushConstants.StepCount; i++)
{
for(int l = 0; l < pushConstants.LightCount; l++)
{
Light light = lights[l];
if(light.type == 0)
{
float lightDepth = length(worldPos - camView.Position);
int splitIndex = GetCSMSplit(lightDepth);
if(splitIndex == -1)
{
//accumFog += (ComputeScattering(dot(rayDirection, light.direction)).rrr * light.color.xyz) * pushConstants.Exponant;
}
else
{
CameraView lightView = cameras[light.transformId[splitIndex]];
float4 fragPosLightSpace = mul(lightView.Projection, mul(lightView.View, float4(currentPosition, 1.0)));
float3 projCoords = fragPosLightSpace.xyz / fragPosLightSpace.w;
projCoords.xy = projCoords.xy * 0.5 + 0.5;
float currentDepth = projCoords.z;
float closestDepth = textures[light.shadowMapTextureId[splitIndex]].Sample(mySampler[0], projCoords.xy).r;
float3 noiseOffset = float3(pushConstants.NoiseSpeed * pushConstants.Time, pushConstants.NoiseSpeed * pushConstants.Time, pushConstants.NoiseSpeed * pushConstants.Time);
float3 noiseSamplePos = (currentPosition + noiseOffset) * pushConstants.NoiseScale;
if(closestDepth < currentDepth)
{
accumFog += (ComputeScattering(dot(rayDirection, light.direction)).rrr * light.color.xyz) * pushConstants.Exponant * ((snoise(noiseSamplePos.xyz) + 1.0) / 2.0);
}
else
{
accumFog += (ComputeScattering(dot(rayDirection, light.direction)).rrr * light.color.xyz) * pushConstants.Ambient * ((snoise(noiseSamplePos.xyz) + 1.0) / 2.0);
}
}
}
else if(light.type == 1)
{
float3 lightToFrag = currentPosition - light.position;
float distance = length(lightToFrag);
float3 lightDir = normalize(-lightToFrag);
float attenuation = 1.0 / (distance * distance);
attenuation = 1.0 - smoothstep(0.0, 3.0f, distance);
float3 noiseOffset = float3(pushConstants.NoiseSpeed * pushConstants.Time, pushConstants.NoiseSpeed * pushConstants.Time, pushConstants.NoiseSpeed * pushConstants.Time);
float3 noiseSamplePos = (currentPosition + noiseOffset) * pushConstants.NoiseScale;
float lightScatter = (snoise(noiseSamplePos.xyz) + 1.0) * 0.5;
float3 scatterTerm = ComputeScattering(dot(rayDirection, lightDir)).rrr * light.color.xyz;
accumFog += scatterTerm * lightScatter * pushConstants.Exponant * attenuation;
}
else if(light.type == 2)
{
float3 lightToFrag = currentPosition - light.position;
float distance = length(lightToFrag);
float3 lightDir = normalize(-lightToFrag);
float attenuation = 1.0 / (distance * distance);
attenuation = 1.0 - smoothstep(0.0, 6.0f, distance);
float3 noiseOffset = float3(pushConstants.NoiseSpeed * pushConstants.Time, pushConstants.NoiseSpeed * pushConstants.Time, pushConstants.NoiseSpeed * pushConstants.Time);
float3 noiseSamplePos = (currentPosition + noiseOffset) * pushConstants.NoiseScale;
float lightScatter = (snoise(noiseSamplePos.xyz) + 1.0) * 0.5;
float theta = dot(lightDir, normalize(-light.direction));
float epsilon = light.innerConeAngle - light.outerConeAngle;
float intensity = clamp((theta - light.outerConeAngle) / epsilon, 0.0, 1.0);
float3 scatterTerm = ComputeScattering(dot(rayDirection, lightDir)).rrr * light.color.xyz;
accumFog += scatterTerm * lightScatter * pushConstants.Exponant * attenuation * intensity;
}
}
currentPosition += step ;
}
accumFog /= pushConstants.StepCount;
output.oColor0 = float4(accumFog.x, accumFog.y, accumFog.z, 1.0f);
return output;
}

View File

@@ -1,39 +0,0 @@
#include "Utils/header.hlsl"
struct VolumetricConstant
{
int DepthTextureID;
int StepCount;
float FogAmount;
float Exponant;
int CamViewID;
int LightCount;
float Ambient;
float Time;
float NoiseSpeed;
float NoiseScale;
float NoiseStrength;
float CSMSplits[4];
};
[[vk::push_constant]]
VolumetricConstant pushConstants;
// Outputs
struct VSOutput
{
float4 Position : SV_Position;
float2 UV : TEXCOORD0;
};
// Main vertex shader
VSOutput main(uint vertexIndex : SV_VertexID)
{
VSOutput output;
Vertex v = vertexBuffer[vertexIndex];
output.UV = float2(v.uv_x, v.uv_y);
output.Position = float4(v.position, 1.0f);
return output;
}

View File

@@ -1,92 +0,0 @@
#include "Utils/header.hlsl"
struct PSInput {
float4 Position : SV_Position;
float2 UV : TEXCOORD0;
};
struct PSOutput {
float4 oColor0 : SV_TARGET;
};
struct OutlinePushConstant
{
float4 Color;
float Thickness;
int SourceTextureID;
int EntityIDTextureID;
int DepthTextureID;
float SelectedEntity;
};
[[vk::push_constant]]
OutlinePushConstant pushConstants;
float2 GetTexelSize(Texture2D tex)
{
uint width, height;
tex.GetDimensions(width, height);
return 1.0 / float2(width, height);
}
PSOutput main(PSInput input)
{
PSOutput output;
float4 outlineColor = pushConstants.Color;
float target = pushConstants.SelectedEntity;
float radius = pushConstants.Thickness;
float2 uv = input.UV;
int entityIDTextureID = pushConstants.EntityIDTextureID;
float hasHit = 0.0f;
float sampleValue = textures[entityIDTextureID].Sample(mySampler[0],, uv).r;
float depth = textures[pushConstants.DepthTextureID].Sample(mySampler[0], uv).r;
float4 fragColor = float4(0, 0, 0, 0);
const float TAU = 6.28318530;
const float steps = 32.0;
for(float i = 0.0f; i < TAU; i += TAU / steps)
{
float2 uvOffset = float2(sin(i), cos(i)) * (GetTexelSize(textures[entityIDTextureID])) * radius;
float2 sampleUV = uv + uvOffset;
sampleUV.x = clamp(sampleUV.x, 0.0, 0.999);
sampleUV.y = clamp(sampleUV.y, 0.0, 0.999);
float sample = textures[entityIDTextureID].Sample(mySampler[0], sampleUV).r;
float sampleDepth = textures[pushConstants.DepthTextureID].Sample(mySampler[0], sampleUV).r;
if(sample == target && sampleDepth != 1.0f && sampleDepth > depth)
{
hasHit = 1.0f;
}
float alpha = smoothstep(0.5, 0.9, hasHit);
float4 outputColor = float4(
lerp(fragColor.r, outlineColor.r, alpha),
lerp(fragColor.g, outlineColor.g, alpha),
lerp(fragColor.b, outlineColor.b, alpha),
lerp(fragColor.a, outlineColor.a, alpha)
);
fragColor = outputColor;
}
if(fragColor.a > 0.1)
{
fragColor.a = 1.0f;
}
float3 sourceTexture = textures[pushConstants.SourceTextureID].Sample(mySampler[0], uv).rgb;
float ratio = float(sampleValue != target && hasHit > 0.0f);
float4 finalColor = float4(
lerp(sourceTexture.r, fragColor.r, ratio),
lerp(sourceTexture.g, fragColor.g, ratio),
lerp(sourceTexture.b, fragColor.b, ratio),
lerp(1.0f, fragColor.a, ratio)
);
output.oColor0 = finalColor;
return output;
}

View File

@@ -1,241 +0,0 @@
#include "Utils/header.hlsl"
struct PSInput
{
float4 Position : SV_Position;
float2 UV : TEXCOORD0;
};
struct PSOutput {
float4 oColor0 : SV_TARGET;
};
struct VolumetricConstant
{
int DepthTextureID;
int StepCount;
float FogAmount;
float Exponant;
int CamViewID;
int LightCount;
float Ambient;
float Time;
float NoiseSpeed;
float NoiseScale;
float NoiseStrength;
};
[[vk::push_constant]]
VolumetricConstant pushConstants;
float2 GetTexelSize(Texture2D tex)
{
uint width, height;
tex.GetDimensions(width, height);
return 1.0 / float2(width, height);
}
float LinearizeDepth(float depth, float nearPlane, float farPlane)
{
return (2.0 * nearPlane) / (farPlane + nearPlane - (1.0 - depth) * (farPlane - nearPlane));
}
float ComputeScattering(float lightDotView)
{
float PI = 3.141592653589793f;
float result = 1.0f - pushConstants.FogAmount;
result /= (4.0f * PI * pow(1.0f + pushConstants.FogAmount * pushConstants.FogAmount - (1.0f * pushConstants.FogAmount) * lightDotView, 1.5f));
return result;
}
float3 WorldPosFromDepth(float depth, float2 uv, float4x4 invProj, float4x4 invView)
{
float z = depth;
float4 clipSpacePosition = float4(uv.x * 2.0 - 1.0, (uv.y * 2.0 - 1.0), z, 1.0f);
float4 viewSpacePosition = mul(invProj, clipSpacePosition);
viewSpacePosition /= viewSpacePosition.w;
float4 worldSpacePosition = mul(invView, viewSpacePosition);
return worldSpacePosition.xyz;
}
// Simplex 3D Noise
float mod289(float x) { return x - floor(x * (1.0 / 289.0)) * 289.0; }
float3 mod289(float3 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; }
float4 mod289(float4 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; }
float4 permute(float4 x) { return mod289(((x*34.0)+1.0)*x); }
float4 taylorInvSqrt(float4 r) { return 1.79284291400159 - 0.85373472095314 * r; }
float snoise(float3 v)
{
const float2 C = float2(1.0/6.0, 1.0/3.0) ;
const float4 D = float4(0.0, 0.5, 1.0, 2.0);
// First corner
float3 i = floor(v + dot(v, C.yyy));
float3 x0 = v - i + dot(i, C.xxx);
// Other corners
float3 g = step(x0.yzx, x0.xyz);
float3 l = 1.0 - g;
float3 i1 = min(g.xyz, l.zxy);
float3 i2 = max(g.xyz, l.zxy);
// x0 = x0 - 0.0 + 0.0 * C.xxx;
float3 x1 = x0 - i1 + C.xxx;
float3 x2 = x0 - i2 + C.yyy;
float3 x3 = x0 - 1.0 + 3.0 * C.xxx;
// Permutations
i = mod289(i);
float4 p = permute(permute(permute(
i.z + float4(0.0, i1.z, i2.z, 1.0))
+ i.y + float4(0.0, i1.y, i2.y, 1.0))
+ i.x + float4(0.0, i1.x, i2.x, 1.0));
// Gradients: 7x7 points over a cube, mapped onto a unit sphere
float4 j = p - 49.0 * floor(p * (1.0 / 49.0)); // mod(p,7*7)
float4 x_ = floor(j * (1.0 / 7.0));
float4 y_ = floor(j - 7.0 * x_); // mod(j,7)
float4 x = (x_ * 2.0 + 0.5) / 7.0 - 1.0;
float4 y = (y_ * 2.0 + 0.5) / 7.0 - 1.0;
float4 h = 1.0 - abs(x) - abs(y);
float4 b0 = float4(x.xy, y.xy);
float4 b1 = float4(x.zw, y.zw);
float4 s0 = floor(b0) * 2.0 + 1.0;
float4 s1 = floor(b1) * 2.0 + 1.0;
float4 sh = -step(h, 0.0);
float4 a0 = b0.xzyw + s0.xzyw * sh.xxyy;
float4 a1 = b1.xzyw + s1.xzyw * sh.zzww;
float3 g0 = float3(a0.xy, h.x);
float3 g1 = float3(a0.zw, h.y);
float3 g2 = float3(a1.xy, h.z);
float3 g3 = float3(a1.zw, h.w);
// Normalize gradients
float4 norm = taylorInvSqrt(float4(dot(g0,g0), dot(g1,g1), dot(g2,g2), dot(g3,g3)));
g0 *= norm.x;
g1 *= norm.y;
g2 *= norm.z;
g3 *= norm.w;
// Mix final noise value
float4 m = max(0.6 - float4(dot(x0,x0), dot(x1,x1), dot(x2,x2), dot(x3,x3)), 0.0);
m = m * m;
return 42.0 * dot(m*m, float4(dot(g0,x0), dot(g1,x1), dot(g2,x2), dot(g3,x3)));
}
PSOutput main(PSInput input)
{
float ditherPattern[4][4] = { { 0.0f, 0.5f, 0.125f, 0.625f},
{ 0.75f, 0.22f, 0.875f, 0.375f},
{ 0.1875f, 0.6875f, 0.0625f, 0.5625},
{ 0.9375f, 0.4375f, 0.8125f, 0.3125} };
CameraView camView = cameras[pushConstants.CamViewID];
float3 startPosition = camView.Position;
int depthTexture = pushConstants.DepthTextureID;
float depth = textures[depthTexture].Sample(mySampler[0], input.UV).r;
float3 worldPos = WorldPosFromDepth(depth, input.UV, camView.InverseProjection, camView.InverseView);
float3 rayVector = worldPos - startPosition;
float rayLength = length(rayVector);
PSOutput output;
if(rayLength > 1000.0)
{
output.oColor0 = float4(0.0f, 0.0f, 0, 0.0f);
return output;
}
float stepLength = rayLength / pushConstants.StepCount;
float3 rayDirection = rayVector / rayLength;
float3 step = rayDirection * stepLength;
float3 accumFog = float3(0, 0, 0);
float3 currentPosition = startPosition;
for(int i = 0; i < pushConstants.StepCount; i++)
{
for(int l = 0; l < pushConstants.LightCount; l++)
{
Light light = lights[l];
if(light.type == 0)
{
CameraView lightView = cameras[light.transformId[0]];
float4 fragPosLightSpace = mul(lightView.Projection, mul(lightView.View, float4(currentPosition, 1.0)));
float3 projCoords = fragPosLightSpace.xyz / fragPosLightSpace.w;
projCoords.xy = projCoords.xy * 0.5 + 0.5;
float currentDepth = projCoords.z;
float closestDepth = textures[light.shadowMapTextureId[0]].Sample(mySampler[0], projCoords.xy).r;
float3 noiseOffset = float3(pushConstants.NoiseSpeed * pushConstants.Time, pushConstants.NoiseSpeed * pushConstants.Time, pushConstants.NoiseSpeed * pushConstants.Time);
float3 noiseSamplePos = (currentPosition + noiseOffset) * pushConstants.NoiseScale;
if(closestDepth < currentDepth)
{
accumFog += (ComputeScattering(dot(rayDirection, light.direction)).rrr * light.color.xyz) * pushConstants.Exponant * ((snoise(noiseSamplePos.xyz) + 1.0) / 2.0);
}
else
{
accumFog += (ComputeScattering(dot(rayDirection, light.direction)).rrr * light.color.xyz) * pushConstants.Ambient * ((snoise(noiseSamplePos.xyz) + 1.0) / 2.0);
}
}
else if(light.type == 1)
{
float3 lightToFrag = currentPosition - light.position;
float distance = length(lightToFrag);
float3 lightDir = normalize(-lightToFrag);
float attenuation = 1.0 / (distance * distance);
attenuation = 1.0 - smoothstep(0.0, 3.0f, distance);
float3 noiseOffset = float3(pushConstants.NoiseSpeed * pushConstants.Time, pushConstants.NoiseSpeed * pushConstants.Time, pushConstants.NoiseSpeed * pushConstants.Time);
float3 noiseSamplePos = (currentPosition + noiseOffset) * pushConstants.NoiseScale;
float lightScatter = (snoise(noiseSamplePos.xyz) + 1.0) * 0.5;
float3 scatterTerm = ComputeScattering(dot(rayDirection, lightDir)).rrr * light.color.xyz;
accumFog += scatterTerm * lightScatter * pushConstants.Exponant * attenuation;
}
else if(light.type == 2)
{
float3 lightToFrag = currentPosition - light.position;
float distance = length(lightToFrag);
float3 lightDir = normalize(-lightToFrag);
float attenuation = 1.0 / (distance * distance);
attenuation = 1.0 - smoothstep(0.0, 6.0f, distance);
float3 noiseOffset = float3(pushConstants.NoiseSpeed * pushConstants.Time, pushConstants.NoiseSpeed * pushConstants.Time, pushConstants.NoiseSpeed * pushConstants.Time);
float3 noiseSamplePos = (currentPosition + noiseOffset) * pushConstants.NoiseScale;
float lightScatter = (snoise(noiseSamplePos.xyz) + 1.0) * 0.5;
float theta = dot(lightDir, normalize(-light.direction));
float epsilon = light.innerConeAngle - light.outerConeAngle;
float intensity = clamp((theta - light.outerConeAngle) / epsilon, 0.0, 1.0);
float3 scatterTerm = ComputeScattering(dot(rayDirection, lightDir)).rrr * light.color.xyz;
accumFog += scatterTerm * lightScatter * pushConstants.Exponant * attenuation * intensity;
}
}
currentPosition += step ;
}
accumFog /= pushConstants.StepCount;
output.oColor0 = float4(accumFog.x, accumFog.y, accumFog.z, 1.0f);
return output;
}

69
Editor/.editorconfig Normal file
View File

@@ -0,0 +1,69 @@
# Visual Studio generated .editorconfig file with C++ settings.
root = true
[*.{c++,cc,cpp,cppm,cu,cuh,cxx,h,h++,hh,hpp,hxx,inl,ipp,ixx,tlh,tli}]
# Visual C++ Code Style settings
cpp_generate_documentation_comments = xml
# Visual C++ Formatting settings
cpp_indent_braces = false
cpp_indent_multi_line_relative_to = innermost_parenthesis
cpp_indent_within_parentheses = indent
cpp_indent_preserve_within_parentheses = true
cpp_indent_case_contents = true
cpp_indent_case_labels = false
cpp_indent_case_contents_when_block = false
cpp_indent_lambda_braces_when_parameter = true
cpp_indent_goto_labels = one_left
cpp_indent_preprocessor = leftmost_column
cpp_indent_access_specifiers = false
cpp_indent_namespace_contents = true
cpp_indent_preserve_comments = false
cpp_new_line_before_open_brace_namespace = ignore
cpp_new_line_before_open_brace_type = ignore
cpp_new_line_before_open_brace_function = ignore
cpp_new_line_before_open_brace_block = ignore
cpp_new_line_before_open_brace_lambda = ignore
cpp_new_line_scope_braces_on_separate_lines = false
cpp_new_line_close_brace_same_line_empty_type = false
cpp_new_line_close_brace_same_line_empty_function = false
cpp_new_line_before_catch = true
cpp_new_line_before_else = true
cpp_new_line_before_while_in_do_while = false
cpp_space_before_function_open_parenthesis = remove
cpp_space_within_parameter_list_parentheses = false
cpp_space_between_empty_parameter_list_parentheses = false
cpp_space_after_keywords_in_control_flow_statements = true
cpp_space_within_control_flow_statement_parentheses = false
cpp_space_before_lambda_open_parenthesis = false
cpp_space_within_cast_parentheses = false
cpp_space_after_cast_close_parenthesis = false
cpp_space_within_expression_parentheses = false
cpp_space_before_block_open_brace = true
cpp_space_between_empty_braces = false
cpp_space_before_initializer_list_open_brace = false
cpp_space_within_initializer_list_braces = true
cpp_space_preserve_in_initializer_list = true
cpp_space_before_open_square_bracket = false
cpp_space_within_square_brackets = false
cpp_space_before_empty_square_brackets = false
cpp_space_between_empty_square_brackets = false
cpp_space_group_square_brackets = true
cpp_space_within_lambda_brackets = false
cpp_space_between_empty_lambda_brackets = false
cpp_space_before_comma = false
cpp_space_after_comma = true
cpp_space_remove_around_member_operators = true
cpp_space_before_inheritance_colon = true
cpp_space_before_constructor_colon = true
cpp_space_remove_before_semicolon = true
cpp_space_after_semicolon = true
cpp_space_remove_around_unary_operator = true
cpp_space_around_binary_operator = insert
cpp_space_around_assignment_operator = insert
cpp_space_pointer_reference_alignment = ignore
cpp_space_around_ternary_operator = insert
cpp_wrap_preserve_blocks = one_liners

13
Editor/.gitignore vendored
View File

@@ -1 +1,12 @@
Build/
*.png
*.tga
*.map
*.material
*.hdr
*.obj
*.fbx
*.jpg
*.bin
*.gltf
*.bmp
*.psd

View File

@@ -0,0 +1,10 @@
{
"runtimeOptions": {
"tfm": "net8.0",
"rollForward": "LatestMinor",
"framework": {
"name": "Microsoft.NETCore.App",
"version": "8.0.0"
}
}
}

View File

@@ -1,36 +1,39 @@
#include <glad/glad.h>
#include <Engine.h>
#include <Nuake/Core/Input.h>
#include <Nuake/Scene/Scene.h>
#include <Nuake/Scene/Entities/Entity.h>
#include <Nuake/Scene/Components.h>
#include <src/Core/Input.h>
#include <src/Scene/Scene.h>
#include <src/Scene/Entities/Entity.h>
#include <src/Scene/Components.h>
#include "Editor/Windows/EditorInterface.h"
#include "src/Windows/EditorInterface.h"
#include "imgui/imgui.h"
#include <imgui/ImGuizmo.h>
#include <Nuake/Physics/PhysicsManager.h>
#include <src/Vendors/imgui/imgui.h>
#include <src/Vendors/imgui/ImGuizmo.h>
#include <src/Physics/PhysicsManager.h>
#include <glm/trigonometric.hpp>
#include <Nuake/Resource/FGD/FGDFile.h>
#include <Nuake/Rendering/Shaders/ShaderManager.h>
#include <Nuake/Rendering/Renderer.h>
#include <GLFW/glfw3.h>
#include <src/Vendors/glm/trigonometric.hpp>
#include <src/Resource/FGD/FGDFile.h>
#include <src/Rendering/Shaders/ShaderManager.h>
#include <src/Rendering/Renderer.h>
#include "Editor/Actions/EditorSelection.h"
#include "Editor/Misc/GizmoDrawer.h"
#include "Editor/Windows/FileSystemUI.h"
#include "src/Actions/EditorSelection.h"
#include "src/Misc/GizmoDrawer.h"
#include "src/Windows/FileSystemUI.h"
#include "Nuake/Core/Maths.h"
#include "Nuake/Rendering/SceneRenderer.h"
#include "src/Core/Maths.h"
#include "src/Rendering/SceneRenderer.h"
#include "Editor/Misc/WindowTheming.h"
#include "Nuake/Application/Application.h"
#include "src/Misc/WindowTheming.h"
#include "src/Application/Application.h"
#include "Nuake/Application/EntryPoint.h"
#include "src/Application/EntryPoint.h"
#include "Editor/EditorApplication.h"
#include "src/EditorApplication.h"
#include "Editor/LaunchSettings.h"
#include "LaunchSettings.h"
std::vector<std::string> ParseArguments(int argc, char* argv[])
@@ -91,11 +94,6 @@ LaunchSettings ParseLaunchSettings(const std::vector<std::string>& arguments)
launchSettings.monitor = stoi(arguments[i + 1]);
}
}
else if (arg == "--generate-bindings")
{
// Set editor window monitor
launchSettings.generateBindings = true;
}
else if (argumentSize == 2 && Nuake::FileSystem::FileExists(arg))
{
if (Nuake::String::EndsWith(arg, ".project"))

60
Editor/Editor.rc Normal file
View File

@@ -0,0 +1,60 @@
// Microsoft Visual C++ generated resource script.
//
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "winres.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// English (United States) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
LANGUAGE 9, 1
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE
BEGIN
"resource1.h\0"
END
2 TEXTINCLUDE
BEGIN
"#include ""winres.h""\r\n"
"\0"
END
3 TEXTINCLUDE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
#endif // English (United States) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED

View File

@@ -1,11 +1,10 @@
#pragma once
#include <Nuake/Core/Maths.h>
#include <src/Core/Maths.h>
#include <string>
struct LaunchSettings
{
int32_t monitor = 1;
bool generateBindings = false;
Nuake::Vector2 resolution = { 1100, 630 };
std::string windowTitle = "Nuake Editor ";
std::string projectPath;

View File

@@ -1,167 +0,0 @@
#pragma once
#include "ComponentPanel.h"
#include <Nuake/Scene/Components/CameraComponent.h>
#include "Nuake/FileSystem/FileSystem.h"
#include "Nuake/Core/Core.h"
#include "Nuake/Rendering/Vulkan/SceneViewport.h"
#include "Nuake/Rendering/Vulkan/DebugCmd.h"
class CameraPanel
{
public:
static void Draw(Nuake::Entity& entity, entt::meta_any& componentInstance)
{
using namespace Nuake;
Nuake::CameraComponent* componentPtr = componentInstance.try_cast<Nuake::CameraComponent>();
static Ref<Nuake::Viewport> previewViewport;
if (!previewViewport)
{
auto scene = entity.GetScene();
auto& vkRenderer = Nuake::VkRenderer::Get();
const UUID viewId = componentPtr->CameraInstance->ID;
previewViewport = vkRenderer.CreateViewport(viewId, { 200, 200 });
previewViewport->SetDebugName("CameraPreviewViewport");
previewViewport->GetOnDebugDraw().AddStatic([&, componentPtr](DebugCmd& cmd)
{
Matrix4 transform = Matrix4(1.0f);
auto& cam = cmd.GetScene()->m_EditorCamera;
Matrix4 initialTransform = Matrix4(1.0f);
initialTransform = glm::translate(initialTransform, cam->Translation);
Matrix4 gizmoTransform = initialTransform;
gizmoTransform = glm::inverse(componentPtr->CameraInstance->GetTransform());
gizmoTransform[3] = initialTransform[3];
auto view = componentPtr->CameraInstance->GetTransform();
auto proj = componentPtr->CameraInstance->GetPerspective();
static auto getGizmoScale = [](const Vector3& camPosition, const Nuake::Vector3& position) -> float
{
float distance = Distance(camPosition, position);
constexpr float ClosestDistance = 3.5f;
if (distance < ClosestDistance)
{
float fraction = distance / ClosestDistance;
return fraction;
}
return 1.0f;
};
Vector3 cameraPosition = componentPtr->CameraInstance->Translation;
const Vector3 gizmoSize = Vector3(Engine::GetProject()->Settings.GizmoSize);
gizmoTransform = glm::scale(gizmoTransform, gizmoSize * getGizmoScale(cameraPosition, initialTransform[3]));
cmd.DrawTexturedQuad(proj * view * gizmoTransform, TextureManager::Get()->GetTexture2("Resources/Gizmos/Camera.png"), Engine::GetProject()->Settings.PrimaryColor);
});
previewViewport->GetOnLineDraw().AddStatic([&, componentPtr](DebugLineCmd& cmd)
{
//auto& cam = cmd.GetScene()->m_EditorCamera;
//Matrix4 initialTransform = Matrix4(1.0f);
//initialTransform = glm::translate(initialTransform, cam->Translation);
//
//const float aspectRatio = cam->AspectRatio;
//const float fov = cam->Fov;
//
//Matrix4 clampedProj = glm::perspectiveFov(glm::radians(fov), 9.0f * aspectRatio, 9.0f, 0.05f, 3.0f);
//Matrix4 boxTransform = glm::translate(scene->GetCurrentCamera()->GetTransform(), Vector3(transform.GetGlobalTransform()[3])) * rotationMatrix * glm::inverse(clampedProj);
//cmd.DrawBox(proj * boxTransform, Color(1, 0, 0, 1.0f), 1.5f, false);
});
vkRenderer.RegisterSceneViewport(scene->Shared(), previewViewport->GetID());
}
if (componentPtr == nullptr)
{
return;
}
Nuake::CameraComponent& component = *componentPtr;
UIFont* boldFont = new UIFont(Fonts::Bold);
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.f, 0.f));
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0.f, 8.f));
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 0.0f);
bool removed = false;
bool headerOpened = ImGui::CollapsingHeader("CAMERA", ImGuiTreeNodeFlags_DefaultOpen);
ImGui::PopStyleVar();
if (ImGui::BeginPopupContextItem())
{
if (ImGui::Selectable("Remove")) { removed = true; }
ImGui::EndPopup();
}
if (removed)
{
entity.RemoveComponent<Nuake::CameraComponent>();
ImGui::PopStyleVar();
delete boldFont;
}
else if (headerOpened)
{
delete boldFont;
auto size = ImVec2{ ImGui::GetContentRegionAvail().x, 200 };
componentPtr->CameraInstance->OnWindowResize(size.x, size.y);
previewViewport->QueueResize({ size.x, size.y });
ImGui::BeginChild("##CameraPreview", size);
{
VkDescriptorSet textureDesc = previewViewport->GetRenderTarget()->GetImGuiDescriptorSet();
ImGui::Image(textureDesc, ImGui::GetContentRegionAvail(), { 0, 1 }, { 1, 0 });
}
ImGui::EndChild();
ImGui::PopStyleVar();
ImGui::Indent();
if (ImGui::BeginTable("Camera", 3, ImGuiTableFlags_SizingStretchProp))
{
ImGui::TableSetupColumn("name", 0, 0.25f);
ImGui::TableSetupColumn("set", 0, 0.65f);
ImGui::TableSetupColumn("reset", 0, 0.1f);
ImGui::TableNextColumn();
{
{
ImGui::Text("FOV");
ImGui::TableNextColumn();
ImGui::DragFloat("##Fov", &component.CameraInstance->Fov, 0.1f, 0.1f, 360.0f);
ImGui::TableNextColumn();
ComponentTableReset(component.CameraInstance->Fov, 88.0f);
}
ImGui::TableNextColumn();
{
ImGui::Text("Exposure");
ImGui::TableNextColumn();
ImGui::DragFloat("##Exposure", &component.CameraInstance->Exposure, 0.1f, 0.1f, 10.0f);
ImGui::TableNextColumn();
ComponentTableReset(component.CameraInstance->Fov, 1.0f);
}
ImGui::TableNextColumn();
{
ImGui::Text("Gamma");
ImGui::TableNextColumn();
ImGui::DragFloat("##Gamma", &component.CameraInstance->Gamma, 0.1f, 0.1f, 10.0f);
ImGui::TableNextColumn();
ComponentTableReset(component.CameraInstance->Fov, 2.2f);
}
}
ImGui::EndTable();
}
ImGui::Unindent();
}
else
{
ImGui::PopStyleVar();
delete boldFont;
}
ImGui::PopStyleVar();
}
};

View File

@@ -1,774 +0,0 @@
#include "MaterialEditor.h"
#include "../Misc/InterfaceFonts.h"
#include <Nuake/Resource/FontAwesome5.h>
#include <Nuake/Resource/ResourceManager.h>
#include <Nuake/FileSystem/FileDialog.h>
#include <imgui/imgui.h>
#include <imgui/imgui_internal.h>
#include <Nuake/Scene/Components/CameraComponent.h>
#include "Nuake/Rendering/Vulkan/SceneViewport.h"
#include "Nuake/Scene/Entities/Entity.h"
#include <Nuake/Scene/Components/ModelComponent.h>
#include <Engine.h>
#include "Nuake/Rendering/Vulkan/DebugCmd.h"
#include "Nuake/Resource/Project.h"
#include <Nuake/UI/ImUI.h>
Ref<Nuake::Model> sphereModel;
Ref<Nuake::Model> quadModel;
Ref<Nuake::Model> cubeModel;
enum class Shapes
{
Sphere, Cube, Quad
};
Shapes currentShape = Shapes::Sphere;
Ref<Nuake::Viewport> MaterialEditor::SceneViewport = nullptr;
Ref<Nuake::Scene> MaterialEditor::PreviewScene = nullptr;
void MaterialEditor::Enable()
{
SceneViewport->SetActive(true);
}
void MaterialEditor::Disable()
{
SceneViewport->SetActive(false);
}
MaterialEditor::MaterialEditor()
{
using namespace Nuake;
if (!SceneViewport)
{
PreviewScene = CreateRef<Nuake::Scene>();
PreviewScene->GetEnvironment()->mVolumetric->SetFogAmount(1.0f);
auto camera = PreviewScene->CreateEntity("Camera");
camera.GetComponent<Nuake::TransformComponent>().Translation = Nuake::Vector3(-2, 0, -2);
auto& camComponent = camera.AddComponent<Nuake::CameraComponent>();
camComponent.CameraInstance->Fov = 44.0f;
auto light = PreviewScene->CreateEntity("Light");
auto& lightC = light.AddComponent<LightComponent>();
auto& lightT = light.AddComponent<TransformComponent>();
lightC.CastShadows = false;
lightC.Type = LightType::Directional;
glm::vec3 forward = glm::normalize(Vector3(.33, -.33, -.33));
glm::vec3 up = glm::vec3(0, 1, 0);
// Prevent up being colinear with forward
if (glm::abs(glm::dot(forward, up)) > 0.999f)
up = glm::vec3(1, 0, 0);
glm::vec3 right = glm::normalize(glm::cross(up, forward));
up = glm::cross(forward, right);
glm::mat3 rotationMatrix(right, up, forward);
//auto& lightT = light.GetComponent<TransformComponent>();
lightT.GlobalRotation = glm::quat_cast(rotationMatrix);
auto& vkRenderer = Nuake::VkRenderer::Get();
const UUID viewId = camComponent.CameraInstance->ID;
SceneViewport = vkRenderer.CreateViewport(viewId, { 200, 200 });
SceneViewport->SetActive(false);
SceneViewport->SetDebugName("MaterialPreview");
SceneViewport->GetOnDebugDraw().AddStatic([](DebugCmd& cmd) {
Matrix4 transform = Matrix4(1.0f);
//cmd.DrawQuad(transform);
});
SceneViewport->GetOnLineDraw().AddStatic([](DebugLineCmd& cmd) {
Matrix4 transform = Matrix4(1.0f);
auto cam = cmd.GetScene()->GetEntity("Camera");
auto& camc = cam.GetComponent<CameraComponent>();
auto& cami = camc.CameraInstance;
auto proj = cami->GetPerspective();
auto view = cami->GetTransform();
//cmd.DrawSphere(proj * view * transform, { 1, 0, 0, 1 }, 2.0f, false);
});
//PreviewScene->GetEnvironment()->AmbientColor = { 0, 0, 0, 0 };
vkRenderer.RegisterSceneViewport(PreviewScene, SceneViewport->GetID());
}
auto sphere = PreviewScene->CreateEntity("Sphere");
auto& modelComponent = sphere.AddComponent<Nuake::ModelComponent>();
auto& sphereT = sphere.GetComponent<TransformComponent>();
sphereT.Translation = { 1, 0, 0 };
const std::vector<Nuake::Vertex> quadVertices
{
{ Vector3(-0.5f, 0.5f, 0.0f), 0.0f, Vector3(0, 0, 1), 1.0f, Vector4(1, 0, 0, 0), Vector4(0, 1, 0, 0) },
{ Vector3(0.5f, 0.5f, 0.0f), 1.0f, Vector3(0, 0, 1), 1.0f, Vector4(1, 0, 0, 0), Vector4(0, 1, 0, 0) },
{ Vector3(-0.5f, -0.5f, 0.0f), 0.0f, Vector3(0, 0, 1), 0.0f, Vector4(1, 0, 0, 0), Vector4(0, 1, 0, 0) },
{ Vector3(0.5f, -0.5f, 0.0f), 1.0f, Vector3(0, 0, 1), 0.0f, Vector4(1, 0, 0, 0), Vector4(0, 1, 0, 0) },
{ Vector3(-0.5f, -0.5f, 0.0f), 0.0f, Vector3(0, 0, 1), 0.0f, Vector4(1, 0, 0, 0), Vector4(0, 1, 0, 0) },
{ Vector3(0.5f, 0.5f, 0.0f), 1.0f, Vector3(0, 0, 1), 1.0f, Vector4(1, 0, 0, 0), Vector4(0, 1, 0, 0) }
};
const std::vector<uint32_t> quadIndices
{
5, 4, 3, 2, 1, 0
};
auto meshQuad = CreateRef<Mesh>();
meshQuad->AddSurface(quadVertices, quadIndices);
quadModel = CreateRef<Model>();
quadModel->AddMesh(meshQuad);
ResourceManager::RegisterResource(quadModel);
// Sphere
const int sectorCount = 32;
const int stackCount = 16;
const float radius = 0.5f;
std::vector<Nuake::Vertex> sphereVertices;
std::vector<uint32_t> sphereIndices;
for (int i = 0; i <= stackCount; ++i)
{
float stackAngle = glm::pi<float>() / 2 - i * glm::pi<float>() / stackCount;
float xy = radius * cosf(stackAngle);
float z = radius * sinf(stackAngle);
for (int j = 0; j <= sectorCount; ++j)
{
float sectorAngle = j * 2.0f * glm::pi<float>() / sectorCount;
float x = xy * cosf(sectorAngle);
float y = xy * sinf(sectorAngle);
Vector3 position = Vector3(x, y, z);
Vector3 normal = glm::normalize(position);
// Collapse seam at the poles
float u = (i == 0 || i == stackCount) ? 0.5f : (float)j / sectorCount;
float v = 1.0f - (float)i / stackCount;
Vector4 tangent = Vector4(1, 0, 0, 0);
Vector4 bitangent = Vector4(0, 1, 0, 0);
sphereVertices.push_back({ position, u, normal, v, tangent, bitangent });
}
}
for (int i = 0; i < stackCount; ++i)
{
int k1 = i * (sectorCount + 1);
int k2 = k1 + sectorCount + 1;
for (int j = 0; j < sectorCount; ++j, ++k1, ++k2)
{
if (i != 0)
{
sphereIndices.push_back(k1);
sphereIndices.push_back(k2);
sphereIndices.push_back(k1 + 1);
}
if (i != (stackCount - 1))
{
sphereIndices.push_back(k1 + 1);
sphereIndices.push_back(k2);
sphereIndices.push_back(k2 + 1);
}
}
}
auto mesh = CreateRef<Mesh>();
mesh->AddSurface(sphereVertices, sphereIndices);
sphereModel = CreateRef<Model>();
sphereModel->AddMesh(mesh);
ResourceManager::RegisterResource(sphereModel);
modelComponent.ModelResource = sphereModel->ID;
const float boxSize = 0.33f;
const std::vector<Nuake::Vertex> boxVertices =
{
// Front face
{ Vector3(-boxSize, -boxSize, boxSize), 0.0f, Vector3(0, 0, 1), 0.0f, Vector4(1, 0, 0, 0), Vector4(0, 1, 0, 0) },
{ Vector3(boxSize, -boxSize, boxSize), 1.0f, Vector3(0, 0, 1), 0.0f, Vector4(1, 0, 0, 0), Vector4(0, 1, 0, 0) },
{ Vector3(boxSize, boxSize, boxSize), 1.0f, Vector3(0, 0, 1), 1.0f, Vector4(1, 0, 0, 0), Vector4(0, 1, 0, 0) },
{ Vector3(-boxSize, boxSize, boxSize), 0.0f, Vector3(0, 0, 1), 1.0f, Vector4(1, 0, 0, 0), Vector4(0, 1, 0, 0) },
// Back face
{ Vector3(-boxSize, -boxSize, -boxSize), 1.0f, Vector3(0, 0, -1), 0.0f, Vector4(-1, 0, 0, 0), Vector4(0, 1, 0, 0) },
{ Vector3(-boxSize, boxSize, -boxSize), 1.0f, Vector3(0, 0, -1), 1.0f, Vector4(-1, 0, 0, 0), Vector4(0, 1, 0, 0) },
{ Vector3(boxSize, boxSize, -boxSize), 0.0f, Vector3(0, 0, -1), 1.0f, Vector4(-1, 0, 0, 0), Vector4(0, 1, 0, 0) },
{ Vector3(boxSize, -boxSize, -boxSize), 0.0f, Vector3(0, 0, -1), 0.0f, Vector4(-1, 0, 0, 0), Vector4(0, 1, 0, 0) },
// Left face
{ Vector3(-boxSize, -boxSize, -boxSize), 0.0f, Vector3(-1, 0, 0), 0.0f, Vector4(0, 0, 1, 0), Vector4(0, 1, 0, 0) },
{ Vector3(-boxSize, -boxSize, boxSize), 1.0f, Vector3(-1, 0, 0), 0.0f, Vector4(0, 0, 1, 0), Vector4(0, 1, 0, 0) },
{ Vector3(-boxSize, boxSize, boxSize), 1.0f, Vector3(-1, 0, 0), 1.0f, Vector4(0, 0, 1, 0), Vector4(0, 1, 0, 0) },
{ Vector3(-boxSize, boxSize, -boxSize), 0.0f, Vector3(-1, 0, 0), 1.0f, Vector4(0, 0, 1, 0), Vector4(0, 1, 0, 0) },
// Right face
{ Vector3(boxSize, -boxSize, -boxSize), 1.0f, Vector3(1, 0, 0), 0.0f, Vector4(0, 0, -1, 0), Vector4(0, 1, 0, 0) },
{ Vector3(boxSize, boxSize, -boxSize), 1.0f, Vector3(1, 0, 0), 1.0f, Vector4(0, 0, -1, 0), Vector4(0, 1, 0, 0) },
{ Vector3(boxSize, boxSize, boxSize), 0.0f, Vector3(1, 0, 0), 1.0f, Vector4(0, 0, -1, 0), Vector4(0, 1, 0, 0) },
{ Vector3(boxSize, -boxSize, boxSize), 0.0f, Vector3(1, 0, 0), 0.0f, Vector4(0, 0, -1, 0), Vector4(0, 1, 0, 0) },
// Top face
{ Vector3(-boxSize, boxSize, -boxSize), 0.0f, Vector3(0, 1, 0), 0.0f, Vector4(1, 0, 0, 0), Vector4(0, 0, -1, 0) },
{ Vector3(-boxSize, boxSize, boxSize), 0.0f, Vector3(0, 1, 0), 1.0f, Vector4(1, 0, 0, 0), Vector4(0, 0, -1, 0) },
{ Vector3(boxSize, boxSize, boxSize), 1.0f, Vector3(0, 1, 0), 1.0f, Vector4(1, 0, 0, 0), Vector4(0, 0, -1, 0) },
{ Vector3(boxSize, boxSize, -boxSize), 1.0f, Vector3(0, 1, 0), 0.0f, Vector4(1, 0, 0, 0), Vector4(0, 0, -1, 0) },
// Bottom face
{ Vector3(-boxSize, -boxSize, -boxSize), 1.0f, Vector3(0, -1, 0), 0.0f, Vector4(1, 0, 0, 0), Vector4(0, 0, 1, 0) },
{ Vector3(boxSize, -boxSize, -boxSize), 0.0f, Vector3(0, -1, 0), 0.0f, Vector4(1, 0, 0, 0), Vector4(0, 0, 1, 0) },
{ Vector3(boxSize, -boxSize, boxSize), 0.0f, Vector3(0, -1, 0), 1.0f, Vector4(1, 0, 0, 0), Vector4(0, 0, 1, 0) },
{ Vector3(-boxSize, -boxSize, boxSize), 1.0f, Vector3(0, -1, 0), 1.0f, Vector4(1, 0, 0, 0), Vector4(0, 0, 1, 0) },
};
const std::vector<uint32_t> boxIndices =
{
// Front
0, 1, 2, 2, 3, 0,
// Back
4, 5, 6, 6, 7, 4,
// Left
8, 9,10,10,11, 8,
// Right
12,13,14,14,15,12,
// Top
16,17,18,18,19,16,
// Bottom
20,21,22,22,23,20
};
auto meshBox = CreateRef<Mesh>();
meshBox->AddSurface(boxVertices, boxIndices);
cubeModel = CreateRef<Model>();
cubeModel->AddMesh(meshBox);
ResourceManager::RegisterResource(cubeModel);
modelComponent.ModelResource = cubeModel->ID;
}
void MaterialEditor::Draw(Ref<Nuake::Material> material)
{
using namespace Nuake;
auto& t = PreviewScene->GetEntity("Camera").GetComponent<CameraComponent>();
auto ent = PreviewScene->GetEntity("Sphere");
RID shape;
switch (currentShape)
{
case Shapes::Quad:
{
shape = quadModel->ID;
break;
}
case Shapes::Sphere:
{
shape = sphereModel->ID;
break;
}
case Shapes::Cube:
{
shape = cubeModel->ID;
break;
}
}
shape.Get<Model>()->GetMeshes()[0]->SetMaterial(material);
ent.GetComponent<ModelComponent>().ModelResource = shape;
auto& cam = Engine::GetCurrentScene()->m_EditorCamera;
std::string materialTitle = material->Path;
{
UIFont boldfont = UIFont(Fonts::SubTitle);
ImGui::Text(material->Path.c_str());
}
ImGui::SameLine();
{
UIFont boldfont = UIFont(Fonts::Icons);
if (ImGui::Button(ICON_FA_SAVE))
{
if (ResourceManager::IsResourceLoaded(material->ID))
{
ResourceManager::RegisterResource(material);
}
std::string fileData = material->Serialize().dump(4);
FileSystem::BeginWriteFile(material->Path);
FileSystem::WriteLine(fileData);
FileSystem::EndWriteFile();
}
}
ImVec2 previewSize = {ImGui::GetContentRegionAvail().x, 200 };
Vector2 viewportPanelSize = glm::vec2(previewSize.x, previewSize.y);
static float yaw = 0.0f; // Horizontal angle in radians
static float pitch = 0.0f; // Vertical angle in radians
static float actualYaw = 0.0f;
static float actualPitch = 0.0f;
static Vector3 actualPos = { 0, 0, 0 };
static float distance = 1.5f; // Distance from origin
const float yawSpeed = 0.01f;
const float pitchSpeed = 0.01f;
static Vector3 camPosition = Vector3(1.5, 0, 0);
t.CameraInstance->OnWindowResize(previewSize.x, previewSize.y);
SceneViewport->QueueResize({ previewSize.x, previewSize.y });
ImGui::BeginChild("MaterialPreview", previewSize);
{
auto cursorPos = ImGui::GetCursorPos();
if (ImGui::BeginPopup("shapes_popup"))
{
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(2, 2));
ImGui::PushStyleColor(ImGuiCol_Button, IM_COL32(0, 0, 0, 0));
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 100);
bool isActive = currentShape == Shapes::Sphere;
if (isActive)
{
Color color = Engine::GetProject()->Settings.PrimaryColor;
ImGui::PushStyleColor(ImGuiCol_Button, { color.r, color.g, color.b, 1.0f });
}
if (ImGui::Button((std::string(ICON_FA_CIRCLE) + " Sphere").c_str()))
{
currentShape = Shapes::Sphere;
}
Nuake::UI::Tooltip("Sphere");
if (isActive)
{
ImGui::PopStyleColor();
}
isActive = currentShape == Shapes::Cube;
if (isActive)
{
Color color = Engine::GetProject()->Settings.PrimaryColor;
ImGui::PushStyleColor(ImGuiCol_Button, { color.r, color.g, color.b, 1.0f });
}
if (ImGui::Button((std::string(ICON_FA_CUBE) + " Cube").c_str()))
{
currentShape = Shapes::Cube;
}
UI::Tooltip("Cube");
if (isActive)
{
ImGui::PopStyleColor();
}
isActive = currentShape == Shapes::Quad;
if (isActive)
{
Color color = Engine::GetProject()->Settings.PrimaryColor;
ImGui::PushStyleColor(ImGuiCol_Button, { color.r, color.g, color.b, 1.0f });
}
if (ImGui::Button((std::string(ICON_FA_SQUARE) + " Plane").c_str()))
{
currentShape = Shapes::Quad;
}
UI::Tooltip("Plane");
if (isActive)
{
ImGui::PopStyleColor();
}
ImGui::PopStyleColor();
ImGui::PopStyleVar(2);
ImGui::EndPopup();
}
if (ImGui::IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem) && ImGui::IsMouseDragging(ImGuiMouseButton_Left))
{
ImVec2 delta = ImGui::GetMouseDragDelta(ImGuiMouseButton_Left);
yaw -= delta.x * yawSpeed;
pitch += delta.y * pitchSpeed;
// Clamp pitch to prevent flipping
pitch = std::clamp(pitch, -glm::half_pi<float>() + 0.01f, glm::half_pi<float>() - 0.01f);
ImGui::ResetMouseDragDelta(ImGuiMouseButton_Left); // Prevents accumulating deltas
}
VkDescriptorSet textureDesc = SceneViewport->GetRenderTarget()->GetImGuiDescriptorSet();
ImGui::Image(textureDesc, ImGui::GetContentRegionAvail(), {0, 1}, {1, 0});
ImGui::SetCursorPos(cursorPos);
if (ImGui::Button(ICON_FA_SHAPES, ImVec2(30, 28)))
{
ImGui::OpenPopup("shapes_popup");
}
UI::Tooltip("Preview Shape");
}
ImGui::EndChild();
actualYaw = glm::mix(actualYaw, yaw, 20.0f * Engine::GetTimestep());
actualPitch = glm::mix(actualPitch, pitch, 20.0f * Engine::GetTimestep());
camPosition.x = distance * cosf(actualPitch) * sinf(actualYaw);
camPosition.y = distance * sinf(actualPitch);
camPosition.z = distance * cosf(actualPitch) * cosf(actualYaw);
actualPos = glm::mix(actualPos, camPosition, 20.0f * Engine::GetTimestep());
Vector3 target = Vector3(0, 0, 0);
Vector3 direction = glm::normalize(target - camPosition);
t.CameraInstance->Translation = { camPosition };
t.CameraInstance->SetDirection(direction);
bool flagsHeaderOpened;
{
UIFont boldfont = UIFont(Fonts::Bold);
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.f, 0.f));
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0.f, 8.f));
flagsHeaderOpened = ImGui::CollapsingHeader(" FLAGS", ImGuiTreeNodeFlags_DefaultOpen);
ImGui::PopStyleVar(2);
}
if (flagsHeaderOpened)
{
ImGui::BeginTable("##Flags", 3, ImGuiTableFlags_BordersInner | ImGuiTableFlags_SizingStretchProp);
{
ImGui::TableSetupColumn("name", 0, 0.3f);
ImGui::TableSetupColumn("set", 0, 0.6f);
ImGui::TableSetupColumn("reset", 0, 0.1f);
ImGui::TableNextColumn();
{
ImGui::Text("Culling");
ImGui::TableNextColumn();
static const char* cullingType[]{ "Back", "Front", "None"};
int selectedCulling = static_cast<int>(material->m_CullingType);
ImGui::Combo("##Culling", &selectedCulling, cullingType, IM_ARRAYSIZE(cullingType));
material->m_CullingType = static_cast<CullingType>(selectedCulling);
ImGui::TableNextColumn();
ImGui::TableNextColumn();
}
{
ImGui::Text("Sampling");
ImGui::TableNextColumn();
static const char* samplingType[]{ "Nearest", "Linear" };
int selectedSampling = static_cast<int>(material->m_SamplingType);
ImGui::Combo("##Sampling", &selectedSampling, samplingType, IM_ARRAYSIZE(samplingType));
material->m_SamplingType = static_cast<SamplingType>(selectedSampling);
ImGui::TableNextColumn();
ImGui::TableNextColumn();
}
{
ImGui::Text("Receive Shadows");
ImGui::TableNextColumn();
ImGui::Checkbox("##ReceiveShadows", &material->m_ReceiveShadows);
ImGui::TableNextColumn();
ImGui::TableNextColumn();
}
{
ImGui::Text("Cast Shadows");
ImGui::TableNextColumn();
ImGui::Checkbox("##CastShadows", &material->m_CastShadows);
ImGui::TableNextColumn();
ImGui::TableNextColumn();
}
{
ImGui::Text("Alpha Scissoring");
ImGui::TableNextColumn();
ImGui::Checkbox("##AlphaScissor", &material->m_AlphaScissor);
ImGui::TableNextColumn();
ImGui::TableNextColumn();
}
{
ImGui::Text("Unlit");
ImGui::TableNextColumn();
bool val = static_cast<bool>(material->data.u_Unlit);
ImGui::Checkbox("##Unlit", &val);
material->data.u_Unlit = static_cast<int>(val);
ImGui::TableNextColumn();
ImGui::TableNextColumn();
}
ImGui::Text("Emissive");
ImGui::TableNextColumn();
ImGui::DragFloat("##Emissiveness", &material->data.u_Emissive, 0.1f, 1.0f);
ImGui::TableNextColumn();
}
ImGui::EndTable();
}
const auto TexturePanelHeight = 100;
const ImVec2 TexturePanelSize = ImVec2(0, TexturePanelHeight);
bool AlbedoOpened;
{
UIFont boldfont = UIFont(Fonts::Bold);
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.f, 0.f));
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0.f, 8.f));
AlbedoOpened = ImGui::CollapsingHeader(" ALBEDO", ImGuiTreeNodeFlags_DefaultOpen);
ImGui::PopStyleVar(2);
}
if (AlbedoOpened)
{
ImGui::BeginTable("##Flags", 3, ImGuiTableFlags_BordersInner | ImGuiTableFlags_SizingStretchProp);
{
ImGui::TableSetupColumn("name", 0, 0.3f);
ImGui::TableSetupColumn("set", 0, 0.6f);
ImGui::TableSetupColumn("reset", 0, 0.1f);
ImGui::TableNextColumn();
{
ImGui::Text("Color");
ImGui::TableNextColumn();
Vector3 materialColor = material->data.m_AlbedoColor;
ImVec4 color = { materialColor.r, materialColor.g, materialColor.b, 1.0 };
ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x);
ImGui::ColorEdit3("##materialAlbedoColor", &material->data.m_AlbedoColor.r, ImGuiColorEditFlags_NoInputs);
ImGui::PopItemWidth();
ImGui::TableNextColumn();
// Reset
ImGui::TableNextColumn();
}
{
ImGui::Text("Texture");
ImGui::TableNextColumn();
ImTextureID textureID = 0;
if (material->HasAlbedo())
{
auto vkTexture = GPUResources::Get().GetTexture(material->AlbedoImage);
textureID = (ImTextureID)vkTexture->GetImGuiDescriptorSet();
}
if (ImGui::ImageButtonEx(ImGui::GetCurrentWindow()->GetID("#image1"), (ImTextureID)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 != "")
{
material->SetAlbedo(TextureManager::Get()->GetTexture(texture));
}
}
if (ImGui::BeginPopupContextWindow())
{
if (ImGui::MenuItem("Clear Texture"))
{
material->m_Albedo = nullptr;
}
ImGui::EndPopup();
}
ImGui::TableNextColumn();
// Reset
}
}
ImGui::EndTable();
}
if (ImGui::CollapsingHeader("Normal", ImGuiTreeNodeFlags_DefaultOpen))
{
ImGui::BeginTable("##Flags", 3, ImGuiTableFlags_BordersInner | ImGuiTableFlags_SizingStretchProp);
{
ImGui::TableSetupColumn("name", 0, 0.3f);
ImGui::TableSetupColumn("set", 0, 0.6f);
ImGui::TableSetupColumn("reset", 0, 0.1f);
ImGui::TableNextColumn();
static bool normalEnabled = true;
{
ImGui::Text("Enabled");
ImGui::TableNextColumn();
ImGui::Checkbox("##normalEnabled", &normalEnabled);
ImGui::TableNextColumn();
// Reset
ImGui::TableNextColumn();
}
if (!normalEnabled)
{
ImGui::BeginDisabled();
}
{
ImGui::Text("Texture");
ImGui::TableNextColumn();
ImTextureID textureID = 0;
if (material->HasNormal())
{
auto vkTexture = GPUResources::Get().GetTexture(material->NormalImage);
textureID = (ImTextureID)vkTexture->GetImGuiDescriptorSet();
}
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 != "")
{
material->SetNormal(TextureManager::Get()->GetTexture(texture));
}
}
if (ImGui::BeginPopupContextWindow())
{
if (ImGui::MenuItem("Clear Texture"))
{
material->m_Normal = nullptr;
}
ImGui::EndPopup();
}
}
if (!normalEnabled)
{
ImGui::EndDisabled();
}
}
ImGui::EndTable();
}
if (ImGui::CollapsingHeader("AO", ImGuiTreeNodeFlags_DefaultOpen))
{
ImGui::BeginChild("##ao", TexturePanelSize, true);
{
ImTextureID textureID = 0;
if (material->HasAO())
{
auto vkTexture = GPUResources::Get().GetTexture(material->AOImage);
textureID = (ImTextureID)vkTexture->GetImGuiDescriptorSet();
}
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 != "")
{
material->SetAO(TextureManager::Get()->GetTexture(texture));
}
}
if (ImGui::BeginPopupContextWindow())
{
if (ImGui::MenuItem("Clear Texture"))
{
material->m_AO = nullptr;
}
ImGui::EndPopup();
}
ImGui::SameLine();
ImGui::DragFloat("Value##7", &material->data.u_AOValue, 0.01f, 0.0f, 1.0f);
}
ImGui::EndChild();
}
if (ImGui::CollapsingHeader("Metalness", ImGuiTreeNodeFlags_DefaultOpen))
{
ImGui::BeginChild("##metalness", TexturePanelSize, true);
{
ImTextureID textureID = 0;
if (material->HasMetalness())
{
auto vkTexture = GPUResources::Get().GetTexture(material->MetalnessImage);
textureID = (ImTextureID)vkTexture->GetImGuiDescriptorSet();
}
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 != "")
{
material->SetMetalness(TextureManager::Get()->GetTexture(texture));
}
}
if (ImGui::BeginPopupContextWindow())
{
if (ImGui::MenuItem("Clear Texture"))
{
material->m_Metalness = nullptr;
}
ImGui::EndPopup();
}
ImGui::SameLine();
ImGui::DragFloat("Value##4", &material->data.u_MetalnessValue, 0.01f, 0.0f, 1.0f);
}
ImGui::EndChild();
}
if (ImGui::CollapsingHeader("Roughness", ImGuiTreeNodeFlags_DefaultOpen))
{
ImGui::BeginChild("##roughness", TexturePanelSize, true);
{
ImTextureID textureID = 0;
if (material->HasRoughness())
{
auto vkTexture = GPUResources::Get().GetTexture(material->RoughnessImage);
textureID = (ImTextureID)vkTexture->GetImGuiDescriptorSet();
}
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 != "")
{
material->SetRoughness(TextureManager::Get()->GetTexture(texture));
}
}
if (ImGui::BeginPopupContextWindow())
{
if (ImGui::MenuItem("Clear Texture"))
{
material->m_Roughness = nullptr;
}
ImGui::EndPopup();
}
ImGui::SameLine();
ImGui::DragFloat("Value##6", &material->data.u_RoughnessValue, 0.01f, 0.0f, 1.0f);
}
ImGui::EndChild();
}
}

View File

@@ -1,21 +0,0 @@
#pragma once
#include <Nuake/Core/Core.h>
#include <Nuake/Rendering/Textures/Material.h>
#include <Nuake/Scene/Scene.h>
#include "Nuake/Rendering/Vulkan/SceneViewport.h"
class MaterialEditor
{
private:
static Ref<Nuake::Scene> PreviewScene;
static Ref<Nuake::Viewport> SceneViewport;
public:
MaterialEditor();
~MaterialEditor() = default;
void Disable();
void Enable();
void Draw(Ref<Nuake::Material> material);
};

View File

@@ -1,108 +0,0 @@
#pragma once
#include <Nuake/Core/Core.h>
#include "ComponentPanel.h"
#include "ModelResourceInspector.h"
#include "../Misc/PopupHelper.h"
#include <Nuake/Scene/Entities/ImGuiHelper.h>
#include <Nuake/Scene/Components/ModelComponent.h>
#include <Nuake/Resource/ResourceLoader.h>
#include <Nuake/Resource/ResourceManager.h>
#include <Nuake/Core/String.h>
#include <Nuake/Resource/ModelLoader.h>
#include "Nuake/Resource/Bakers/AssetBakerManager.h"
#include "Nuake/Resource/ResourceManager.h"
class MeshPanel : ComponentPanel
{
private:
Scope<ModelResourceInspector> _modelInspector;
bool _expanded = false;
std::string _importedPathMesh;
public:
MeshPanel()
{
CreateScope<ModelResourceInspector>();
}
void Draw(Nuake::Entity& entity, entt::meta_any& componentInstance)
{
using namespace Nuake;
Nuake::ModelComponent* componentPtr = componentInstance.try_cast<Nuake::ModelComponent>();
if (componentPtr == nullptr)
{
return;
}
Nuake::ModelComponent& component = *componentPtr;
BeginComponentTable(MESH, ModelComponent);
{
ImGui::Text("Model");
ImGui::TableNextColumn();
std::string label = "None";
const bool isModelNone = component.ModelResource.Get<Model>() == nullptr;
if (!isModelNone)
{
label = std::to_string(component.ModelResource.ID);
}
if (ImGui::Button(label.c_str(), ImVec2(ImGui::GetContentRegionAvail().x, 0)))
{
if (!isModelNone)
{
if (!_expanded)
{
_modelInspector = CreateScope<ModelResourceInspector>(component.ModelResource.Get<Model>());
}
_expanded = !_expanded;
}
}
if (_expanded)
{
_modelInspector->Draw();
}
bool shouldConvert = false;
if (ImGui::BeginDragDropTarget())
{
if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("_Model"))
{
// Convert payload to relative path
std::string fullPath = std::string(static_cast<char*>(payload->Data), 256);
fullPath = Nuake::FileSystem::AbsoluteToRelative(fullPath);
auto file = Nuake::FileSystem::GetFile(fullPath);
if(file)
{
// TODO(antopilo) use file type instead of extension
if(file->GetExtension() == ".nkmesh")
{
auto modelResource = ResourceManager::GetResourceFromFile<Model>(file);
component.ModelResource = modelResource->ID;
}
else
{
// Check if we can bake this filetype
AssetBakerManager& bakerMgr = AssetBakerManager::Get();
bakerMgr.Bake(file);
}
}
}
ImGui::EndDragDropTarget();
}
ImGui::TableNextColumn();
ComponentTableReset(component.ModelPath, "");
}
EndComponentTable();
}
};

View File

@@ -1,44 +0,0 @@
#include <Nuake/Core/Core.h>
#include <Nuake/Core/MulticastDelegate.h>
#include <string>
namespace Nuake
{
class Scene;
class File;
}
// This is all the commands that the editor can receive from anywhere in the UI
class EditorRequests
{
private:
MulticastDelegate<Ref<Nuake::File>> requestLoadScene;
MulticastDelegate<std::string> requestCloseEditorWindow;
EditorRequests() = default;
~EditorRequests() = default;
public:
static EditorRequests& Get()
{
static EditorRequests instance;
return instance;
}
public:
// Broadcast requests
void RequestLoadScene(Ref<Nuake::File> sceneFile)
{
requestLoadScene.Broadcast(sceneFile);
}
void RequestCloseEditorWindow(std::string windowId)
{
requestCloseEditorWindow.Broadcast(windowId.c_str());
}
// Subcribe to requests
auto& OnRequestCloseEditorWindow() { return requestCloseEditorWindow; }
auto& OnRequestLoadScene() { return requestLoadScene; }
};

View File

@@ -1,3 +0,0 @@
#include "AnimatedValue.h"
std::vector<IAnimatedValue*> IAnimatedValue::Instances;

View File

@@ -1,62 +0,0 @@
#pragma once
#include <Nuake/Core/Maths.h>
#include <vector>
class IAnimatedValue
{
public:
static std::vector<IAnimatedValue*> Instances;
static void UpdateAll (float ts)
{
for (auto& instance : Instances)
{
instance->Update(ts);
}
}
virtual void Update(float ts) = 0;
};
template<typename T>
class AnimatedValue : public IAnimatedValue
{
public:
T Value;
T TargetValue;
float Speed = 20.0f;
AnimatedValue(T value = T(), T targetValue = T())
: Value(value), TargetValue(targetValue)
{
IAnimatedValue::Instances.push_back(this);
}
~AnimatedValue()
{
auto it = std::remove(Instances.begin(), Instances.end(), this);
IAnimatedValue::Instances.erase(it, Instances.end());
}
virtual void Update(float ts) override
{
Value = glm::mix(Value, TargetValue, glm::clamp(Speed * ts, 0.0f, 1.0f));
}
void SetValue(T value)
{
Value = value;
TargetValue = value;
}
operator T() const
{
return Value;
}
AnimatedValue<T>& operator =(T value)
{
TargetValue = value;
return *this;
}
};

View File

@@ -1,6 +0,0 @@
#pragma once
#include <string>
void ImGuiTextSTD(const std::string& label, std::string& value);
void ImGuiTextMultiline(const std::string& label, std::string& value);

View File

@@ -1,63 +0,0 @@
#pragma once
#include "InterfaceFonts.h"
#include <imgui/imgui.h>
#include <Nuake/Resource/FontAwesome5.h>
#include <Nuake/Resource/StaticResources.h>
#include <Nuake/Rendering/Vulkan/VulkanRenderer.h>
std::map<Fonts, ImFont*> FontManager::mFonts = std::map<Fonts, ImFont*>();
Ref<Nuake::VulkanImage> fontImage;
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;
using namespace Nuake::StaticResources;
mFonts[Normal] = io.Fonts->AddFontFromMemoryTTF(Data_Fonts_fa_solid_900_ttf, Data_Fonts_fa_solid_900_ttf_len, 11.f, &icons_config, icons_ranges);
ImFontConfig iconsConfigBold;
icons_config.PixelSnapH = true;
mFonts[Bold] = io.Fonts->AddFontFromMemoryTTF(Data_Fonts_FiraMono_Bold_ttf, Data_Fonts_FiraMono_Bold_ttf_len, 16.0);
iconsConfigBold.MergeMode = true;
io.Fonts->AddFontFromMemoryTTF(Data_Fonts_fa_solid_900_ttf, Data_Fonts_fa_solid_900_ttf_len, 16.f, &iconsConfigBold, icons_ranges);
iconsConfigBold.MergeMode = false;
mFonts[LargeBold] = io.Fonts->AddFontFromMemoryTTF(Data_Fonts_FiraMono_Regular_ttf, Data_Fonts_FiraMono_Regular_ttf_len, 32);
mFonts[Title] = io.Fonts->AddFontFromMemoryTTF(Data_Fonts_FiraMono_Bold_ttf, Data_Fonts_FiraMono_Bold_ttf_len, 50.0);
mFonts[SubTitle] = io.Fonts->AddFontFromMemoryTTF(Data_Fonts_FiraMono_Regular_ttf, Data_Fonts_FiraMono_Regular_ttf_len, 24.0);
ImGui::GetIO().Fonts->AddFontDefault();
mFonts[BigIcon] = io.Fonts->AddFontFromMemoryTTF(Data_Fonts_fa_solid_900_ttf, Data_Fonts_fa_solid_900_ttf_len, 42.0f, &icons_config, icons_ranges);
unsigned char* font_data = nullptr;
int width = 0, height = 0, bytes_per_pixel = 0;
// Retrieve the texture data as RGBA32
io.Fonts->GetTexDataAsRGBA32(&font_data, &width, &height, &bytes_per_pixel);
using namespace Nuake;
fontImage = CreateRef<VulkanImage>(font_data, ImageFormat::RGBA8, Vector2{width, height});
io.Fonts->SetTexID((ImTextureID)fontImage->GetImGuiDescriptorSet());
}
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

@@ -1,55 +0,0 @@
#include "LoadingSplash.h"
#include "../Misc/InterfaceFonts.h"
#include <Nuake/Core/Maths.h>
#include "Nuake/Window.h"
#include "Nuake/UI/ImUI.h"
#include <imgui/imgui.h>
#include <Nuake/Rendering/Textures/TextureManager.h>
#include <Nuake/Rendering/Vulkan/VulkanImage/VulkanImage.h>
using namespace Nuake;
LoadingSplash::LoadingSplash()
{
_NuakeLogo = Nuake::TextureManager::Get()->GetTexture2(NUAKE_LOGO_PATH);
_NuakeSplash = Nuake::TextureManager::Get()->GetTexture2(NUAKE_SPLASH_PATH);
Nuake::Window::Get()->SetDecorated(false);
Nuake::Window::Get()->SetSize({ 640, 400 });
Nuake::Window::Get()->Center();
}
void LoadingSplash::Draw(const std::string& project)
{
// 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(0.0f, 0.0f));
ImGui::Begin("Welcome Screen", 0, ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoResize);
{
const Vector2 splashSize = _NuakeSplash->GetSize();
const ImVec2 splashImguiSize = ImVec2(splashSize.x, splashSize.y);
ImGui::Image((ImTextureID)_NuakeSplash->GetImGuiDescriptorSet(), splashImguiSize, {0, 1}, {1, 0});
ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 8.0f);
ImGui::SetCursorPosX(8.0f);
{
UIFont font(Fonts::Bold);
ImGui::Text("Loading project... ");
}
ImGui::SetCursorPosX(8.0f);
ImGui::TextColored({ 1.0, 1.0, 1.0, 0.5 }, project.c_str());
}
ImGui::End();
ImGui::PopStyleVar();
ImGui::PopStyleVar();
}

View File

@@ -1,42 +0,0 @@
#pragma once
#include "Nuake/Core/Core.h"
#include "Nuake/Core/MulticastDelegate.h"
#include "../../Actions/EditorSelection.h"
namespace Nuake
{
class Scene;
}
class EditorContext
{
private:
EditorSelection selection;
Ref<Nuake::Scene> scene;
std::string windowClass;
public:
EditorContext() = default;
~EditorContext() = default;
EditorContext(Ref<Nuake::Scene> inScene, std::string inWindowClass) :
scene(inScene),
windowClass(inWindowClass)
{
}
public:
const std::string_view GetWindowClass() const { return windowClass; }
MulticastDelegate<EditorSelection> OnSelectionChanged;
const EditorSelection& GetSelection() const { return selection; }
void SetSelection(EditorSelection inSelection)
{
selection = inSelection;
OnSelectionChanged.Broadcast(selection);
}
void SetScene(Ref<Nuake::Scene> inScene) { scene = inScene; }
Ref<Nuake::Scene> GetScene() const { return scene; }
};

View File

@@ -1,152 +0,0 @@
#include "SceneEditorWindow.h"
#include "Widgets/SceneHierarchyWidget.h"
#include "Widgets/SelectionPropertyWidget.h"
#include "Widgets/LoggerWidget.h"
#include "Widgets/ViewportWidget.h"
#include "Widgets/FileBrowserWidget.h"
#include "Nuake/Scene/Scene.h"
#include "Nuake/UI/ImUI.h"
#include "../../Events/EditorRequests.h"
using namespace Nuake;
std::set<std::string> SceneEditorWindow::previouslyCreatedEditors = std::set<std::string>();
SceneEditorWindow::SceneEditorWindow(Ref<Scene> inScene) :
editorContext(inScene, inScene->Path),
layoutInitialized(false)
{
RegisterWidget<SceneHierarchyWidget>();
RegisterWidget<SelectionPropertyWidget>();
RegisterWidget<FileBrowserWidget>();
RegisterWidget<ViewportWidget>();
RegisterWidget<LoggerWidget>();
imguiId = editorContext.GetScene()->Path.empty() ? "New Scene" : editorContext.GetScene()->Path;
// This is to prevent initializing the dockspace twice, because imgui keeps a cache of the dockspace
if (previouslyCreatedEditors.find(imguiId) != previouslyCreatedEditors.end())
{
layoutInitialized = true;
}
previouslyCreatedEditors.insert(imguiId);
}
void SceneEditorWindow::Save()
{
editorContext.GetScene()->Save();
}
void SceneEditorWindow::Update(float ts)
{
for (auto& widget : widgets)
{
widget->Update(ts);
}
if (ImGui::IsKeyPressed(ImGuiKey_Escape))
{
editorContext.SetSelection(EditorSelection());
}
}
void SceneEditorWindow::Draw()
{
ImGuiID editorDockspaceId = ImGui::GetID("SceneEditorDockSpace");
// This is to prevent other windows of other scene editors to dock
ImGuiWindowClass windowClass;
windowClass.ClassId = ImHashStr("SceneEditor");
windowClass.DockingAllowUnclassed = false;
ImGui::SetNextWindowClass(&windowClass);
ImGui::SetNextWindowDockID(ImGui::GetID("SceneEditorDockSpace"));
ImGui::SetNextWindowSizeConstraints({1280, 720}, { FLT_MAX, FLT_MAX });
bool shouldStayOpen = true;
std::string windowName = std::string(ICON_FA_WINDOW_MAXIMIZE + std::string(" ") + imguiId);
if (ImGui::Begin(windowName.c_str(), &shouldStayOpen))
{
this->isFocused = true;
ImGuiWindowClass localSceneEditorClass;
localSceneEditorClass.ClassId = ImHashStr(imguiId.c_str());
std::string dockspaceName = std::string("Dockspace##" + imguiId);
ImGuiID dockspaceId = ImGui::GetID(dockspaceName.c_str());
ImGui::DockSpace(dockspaceId, ImGui::GetContentRegionAvail(), ImGuiDockNodeFlags_None, &localSceneEditorClass);
for (auto& widget : widgets)
{
widget->OnVisible();
widget->Draw();
}
// Build initial docking layout
if (!layoutInitialized)
{
auto dockbottomId = ImGui::DockBuilderSplitNode(dockspaceId, ImGuiDir_Down, 0.3f, nullptr, &dockspaceId);
auto dockLeftId = ImGui::DockBuilderSplitNode(dockspaceId, ImGuiDir_Left, 0.3f, nullptr, &dockspaceId);
auto dockRightId = ImGui::DockBuilderSplitNode(dockspaceId, ImGuiDir_Right, 0.5f, nullptr, &dockspaceId);
widgets[0]->DockTo(dockLeftId);
widgets[1]->DockTo(dockRightId);
widgets[2]->DockTo(dockbottomId);
widgets[3]->DockTo(dockspaceId);
widgets[4]->DockTo(dockbottomId);
}
}
else
{
this->isFocused = false;
for (auto& widget : widgets)
{
widget->OnHidden();
}
}
ImGui::End();
if (!layoutInitialized)
{
//ImGui::DockBuilderSplitNode(dockId, ImGuiDir_Down, 0.3f, nullptr, &dockId);
//ImGui::DockBuilderDockWindow(windowName.c_str(), dockId);
if (dockId != 0)
{
//ImGui::DockBuilderDockWindow(windowName.c_str(), dockId);
}
layoutInitialized = true;
}
if (!shouldStayOpen)
{
EditorRequests::Get().RequestCloseEditorWindow(editorContext.GetScene()->Path);
}
}
std::string SceneEditorWindow::GetWindowName() const
{
return editorContext.GetScene()->Path;
}
bool SceneEditorWindow::IsFocused() const
{
return this->isFocused;
}
void SceneEditorWindow::SetScene(Ref<Scene> scene)
{
editorContext.SetScene(scene);
for (auto& widget : widgets)
{
widget->OnSceneChanged(scene);
}
}
Ref<Scene> SceneEditorWindow::GetScene() const
{
return this->editorContext.GetScene();
}

View File

@@ -1,64 +0,0 @@
#pragma once
#include "Nuake/Core/Core.h"
#include "EditorContext.h"
#include "Widgets/IEditorWidget.h"
#include <set>
#include <string>
#include <vector>
#include <concepts>
// Forward declarations
namespace Nuake
{
class Scene;
class Entity;
}
template <typename T>
concept DerivedFromEditorWidget = std::derived_from<T, IEditorWidget>;
class SceneEditorWindow
{
private:
bool layoutInitialized;
std::string windowID; // This is used for imgui docking
EditorContext editorContext;
ImGuiID dockId = 0;
bool isFocused;
std::vector<Scope<IEditorWidget>> widgets;
// This is because imgui keeps cache of previously created dockspace, so we can reuse it.
std::string imguiId;
static std::set<std::string> previouslyCreatedEditors;
public:
SceneEditorWindow(Ref<Nuake::Scene> scene);
~SceneEditorWindow() = default;
public:
void Save();
void Update(float ts);
void Draw();
std::string GetWindowName() const;
void DockTo(ImGuiID id)
{
dockId = id;
}
bool IsFocused() const;
Ref<Nuake::Scene> GetScene() const;
void SetScene(Ref<Nuake::Scene> scene);
private:
template<DerivedFromEditorWidget T>
inline void RegisterWidget()
{
widgets.push_back(CreateScope<T>(editorContext));
}
};

View File

@@ -1,968 +0,0 @@
#include "FileBrowserWidget.h"
#include "../../../Misc/PopupHelper.h"
#include "../../../Events/EditorRequests.h"
#include <Nuake/FileSystem/Directory.h>
#include <Nuake/FileSystem/File.h>
#include <Nuake/Resource/Project.h>
#include <Nuake/Core/String.h>
#include <Nuake/UI/ImUI.h>
#include "../../../Misc/InterfaceFonts.h"
#include <Nuake/Resource/Bakers/AssetBakerManager.h>
using namespace Nuake;
FileBrowserWidget::FileBrowserWidget(EditorContext& inCtx) : IEditorWidget(inCtx)
{
SetCurrentDirectory(FileSystem::RootDirectory);
}
void FileBrowserWidget::SetCurrentDirectory(Ref<Nuake::Directory> dir)
{
queueDirectory = dir;
}
void FileBrowserWidget::Update(float ts)
{
}
void FileBrowserWidget::Draw()
{
if (BeginWidgetWindow("File Browser"))
{
if (queueDirectory != currentDirectory)
{
opacity.SetValue(0.0f);
opacity = 1.0f;
currentDirectory = queueDirectory;
}
Ref<Nuake::Directory> rootDirectory = FileSystem::GetFileTree();
auto availableSpace = ImGui::GetContentRegionAvail();
UI::Splitter(true, 4.0f, &splitterSizeLeft, &splitterSizeRight, 100, 8, availableSpace.y);
ImVec4* colors = ImGui::GetStyle().Colors;
ImGui::PushStyleColor(ImGuiCol_ChildBg, colors[ImGuiCol_TitleBgCollapsed]);
ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 8);
ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, ImVec2(0, 0));
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, { 0, 0 });
if (ImGui::BeginChild("Tree", ImVec2(splitterSizeLeft, availableSpace.y), true))
{
ImGuiTreeNodeFlags base_flags = ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_SpanAvailWidth |
ImGuiTreeNodeFlags_SpanFullWidth | ImGuiTreeNodeFlags_DefaultOpen |
ImGuiTreeNodeFlags_FramePadding;
bool isSelected = this->currentDirectory == FileSystem::RootDirectory;
if (isSelected)
{
base_flags |= ImGuiTreeNodeFlags_Selected;
}
// Header
{
UIFont boldFont = UIFont(Fonts::Bold);
bool open = ImGui::TreeNodeEx("PROJECT", base_flags);
if (ImGui::IsItemClicked())
{
SetCurrentDirectory(FileSystem::RootDirectory);
}
}
// Draw tree
for (auto& d : rootDirectory->Directories)
{
DrawFiletree(d);
}
ImGui::TreePop();
}
ImGui::PopStyleVar();
ImGui::PopStyleVar();
ImGui::PopStyleVar();
ImGui::PopStyleColor();
ImGui::EndChild();
ImGui::SameLine();
// Build file path buttons
auto paths = std::vector<Ref<Nuake::Directory>>();
{
Ref<Nuake::Directory> currentParent = currentDirectory;
paths.push_back(currentDirectory);
// Recursively build the path to the root
while (currentParent != nullptr)
{
paths.push_back(currentParent);
currentParent = currentParent->Parent;
}
}
availableSpace = ImGui::GetContentRegionAvail();
if (ImGui::BeginChild("Wrapper", availableSpace))
{
availableSpace.y = 30;
if (ImGui::BeginChild("Path", availableSpace, true))
{
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, { 2, 4 });
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0));
const auto buttonSize = ImVec2(26, 26);
// Refresh button
std::string refreshIcon = ICON_FA_SYNC_ALT;
if (ImGui::Button((refreshIcon).c_str(), buttonSize))
{
// RefreshFileBrowser();
}
ImGui::SameLine();
const auto cursorStart = ImGui::GetCursorPosX();
{ // Go back
if (ImGui::Button((std::string(ICON_FA_ANGLE_LEFT)).c_str(), buttonSize))
{
if (currentDirectory != FileSystem::RootDirectory)
{
SetCurrentDirectory(currentDirectory->Parent);
}
}
}
ImGui::SameLine();
const auto cursorEnd = ImGui::GetCursorPosX();
const auto buttonWidth = cursorEnd - cursorStart;
if (ImGui::Button((std::string(ICON_FA_ANGLE_RIGHT)).c_str(), buttonSize))
{
if (editorContext.GetSelection().Type == EditorSelectionType::Directory)
{
SetCurrentDirectory(editorContext.GetSelection().Directory);
}
}
const uint32_t numButtonAfterPathBrowser = 2;
const uint32_t searchBarSize = 6;
ImGui::SameLine();
// Draw path buttons
{
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::GetContentRegionAvail().x - (numButtonAfterPathBrowser * buttonWidth * searchBarSize)) - 4.0, 24));
for (int i = paths.size() - 1; i > 0; i--)
{
if (i != paths.size())
{
ImGui::SameLine();
}
std::string pathLabel;
if (i == paths.size() - 1)
{
pathLabel = "Project files";
}
else
{
pathLabel = paths[i]->Name;
}
if (ImGui::Button(pathLabel.c_str()))
{
SetCurrentDirectory(paths[i]);
}
ImGui::SameLine();
ImGui::Text("/");
}
ImGui::EndChild();
ImGui::PopStyleVar();
ImGui::PopStyleVar();
ImGui::PopStyleColor();
}
ImGui::SameLine();
// Search bar
ImGui::BeginChild("searchBar", ImVec2(ImGui::GetContentRegionAvail().x - (numButtonAfterPathBrowser * buttonWidth), 24));
char buffer[256];
memset(buffer, 0, sizeof(buffer));
std::strncpy(buffer, searchQuery.c_str(), sizeof(buffer));
if (ImGui::InputTextEx("##Search", "Asset search & filter ..", buffer, sizeof(buffer), ImVec2(ImGui::GetContentRegionAvail().x, 24), ImGuiInputTextFlags_EscapeClearsAll))
{
searchQuery = std::string(buffer);
}
ImGui::EndChild();
ImGui::SameLine();
if (ImGui::Button((std::string(ICON_FA_FOLDER_OPEN)).c_str(), buttonSize))
{
OS::OpenIn(currentDirectory->FullPath);
}
ImGui::PopStyleColor(); // Button color
ImGui::SameLine();
ImGui::PopStyleVar();
}
ImGui::EndChild();
ImDrawList* drawList = ImGui::GetWindowDrawList();
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));
availableSpace = ImGui::GetContentRegionAvail();
bool child = ImGui::BeginChild("Content", availableSpace);
ImGui::PopStyleVar();
ImGui::SameLine();
if (child)
{
int width = availableSpace.x;
ImVec2 buttonSize = ImVec2(60, 60);
int amount = (int)(width / 110);
if (amount <= 0) amount = 1;
int i = 1; // current amount of item per row.
if (ImGui::BeginTable("ssss", amount))
{
ImGui::PushStyleVar(ImGuiStyleVar_Alpha, opacity);
// Button to go up a level.
//if (m_CurrentDirectory && m_CurrentDirectory != FileSystem::RootDirectory && m_CurrentDirectory->Parent)
//{
// ImGui::TableNextColumn();
// if (ImGui::Button("..", buttonSize))
// m_CurrentDirectory = m_CurrentDirectory->Parent;
// i++;
//}
if (currentDirectory && currentDirectory->Directories.size() > 0)
{
for (Ref<Nuake::Directory>& d : currentDirectory->Directories)
{
if (d->GetName() == "bin" || d->GetName() == ".vs" || d->GetName() == "obj")
{
continue;
}
if (Nuake::String::Sanitize(d->Name).find(Nuake::String::Sanitize(searchQuery)) != std::string::npos)
{
if (i + 1 % amount != 0)
ImGui::TableNextColumn();
else
ImGui::TableNextRow();
DrawDirectory(d, i);
i++;
}
}
}
if (currentDirectory && currentDirectory->Files.size() > 0)
{
for (auto& f : currentDirectory->Files)
{
if (searchQuery.empty() || f->GetName().find(String::Sanitize(searchQuery)) != std::string::npos)
{
if ((f->GetFileType() == FileType::Unknown && !AssetBakerManager::Get().IsBakable(f)) || f->GetFileType() == FileType::Assembly)
{
continue;
}
if (i + 1 % amount != 0 || i == 1)
{
ImGui::TableNextColumn();
}
else
{
ImGui::TableNextRow();
}
DrawFile(f, i);
i++;
}
}
}
ImGui::PopStyleVar();
//DrawContextMenu();
//m_HasClickedOnFile = false;
ImageLoaded = 0;
ImGui::EndTable();
}
}
ImGui::EndChild();
}
ImGui::EndChild();
}
ImGui::End();
}
void FileBrowserWidget::DrawFiletree(Ref<Nuake::Directory> dir)
{
ImGuiTreeNodeFlags base_flags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick |
ImGuiTreeNodeFlags_SpanFullWidth | ImGuiTreeNodeFlags_FramePadding;
if (currentDirectory == dir)
{
base_flags |= ImGuiTreeNodeFlags_Selected;
}
if (dir->Directories.size() <= 0)
{
base_flags |= ImGuiTreeNodeFlags_Leaf;
}
std::string icon = ICON_FA_FOLDER;
bool open = ImGui::TreeNodeEx((icon + " " + dir->Name.c_str()).c_str(), base_flags);
if (ImGui::IsItemClicked())
{
SetCurrentDirectory(dir);
}
if (open)
{
for (auto& d : dir->Directories)
{
DrawFiletree(d);
}
ImGui::TreePop();
}
}
void FileBrowserWidget::DrawDirectory(Ref<Nuake::Directory> directory, uint32_t drawId)
{
ImGui::PushFont(FontManager::GetFont(Icons));
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 4.0f);
const char* icon = ICON_FA_FOLDER;
const std::string id = std::string("##") + directory->Name;
const ImVec2 size = { 80, 80 };
const ImVec2 headerSize = { size.x, 50 };
const ImVec2 totalSize = { size.x, size.y + headerSize.y };
ImVec2 prevCursor = ImGui::GetCursorPos();
ImVec2 prevScreenPos = ImGui::GetCursorScreenPos();
const bool selected = ImGui::Selectable(id.c_str(), editorContext.GetSelection().Directory == directory, ImGuiSelectableFlags_AllowOverlap | ImGuiSelectableFlags_AllowDoubleClick, totalSize);
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 (selected)
{
if (ImGui::IsMouseDoubleClicked(0))
{
SetCurrentDirectory(directory);
}
}
if (ImGui::IsItemHovered())
ImGui::SetTooltip(directory->Name.c_str());
ImGui::SetCursorPos(prevCursor);
ImGui::Image((ImTextureID)TextureManager::Get()->GetTexture2("Resources/Images/folder_icon.png")->GetImGuiDescriptorSet(), size, {0, 1}, {1, 0});
auto imguiStyle = ImGui::GetStyle();
ImVec2 startOffset = ImVec2(imguiStyle.CellPadding.x / 2.0f, 0);
ImVec2 offsetEnd = ImVec2(startOffset.x, imguiStyle.CellPadding.y / 2.0f);
ImU32 rectColor = IM_COL32(255, 255, 255, 16);
ImGui::GetWindowDrawList()->AddRectFilled(prevScreenPos + ImVec2(0, size.x) - startOffset, prevScreenPos + totalSize + offsetEnd, rectColor, 1.0f);
std::string visibleName = directory->Name;
const uint32_t MAX_CHAR_NAME = 34;
if (directory->Name.size() > MAX_CHAR_NAME)
{
visibleName = std::string(directory->Name.begin(), directory->Name.begin() + MAX_CHAR_NAME - 3) + "...";
}
ImGui::TextWrapped(visibleName.c_str());
ImGui::SetCursorPosY(prevCursor.y + totalSize.y - ImGui::GetTextLineHeight());
ImGui::TextColored({ 1, 1, 1, 0.5f }, "Folder");
ImGui::PopStyleVar();
if (ImGui::BeginPopup(hoverMenuId.c_str()))
{
if (ImGui::MenuItem("Open"))
{
SetCurrentDirectory(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::PopFont();
}
void FileBrowserWidget::DrawFile(Ref<Nuake::File> file, uint32_t drawId)
{
//ImGui::PushFont(EditorInterface::bigIconFont);
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 4.0f);
ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, { 0.f, 0.f });
std::string fileExtension = file->GetExtension();
const ImVec2 size = { 80, 80 };
const ImVec2 headerSize = { size.x, 50 };
const ImVec2 totalSize = { size.x, size.y + headerSize.y };
ImVec2 prevCursor = ImGui::GetCursorPos();
ImVec2 prevScreenPos = ImGui::GetCursorScreenPos();
std::string id = std::string("##") + file->GetAbsolutePath();
const bool selected = ImGui::Selectable(id.c_str(), editorContext.GetSelection().File == file, ImGuiSelectableFlags_AllowOverlap | ImGuiSelectableFlags_AllowDoubleClick, totalSize);
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;
}
bool shouldOpenScene = false;
if (selected)
{
if (ImGui::IsMouseDoubleClicked(0))
{
switch (file->GetFileType())
{
case FileType::Map:
OS::OpenTrenchbroomMap(file->GetAbsolutePath());
break;
case FileType::NetScript:
case FileType::UI:
case FileType::CSS:
OS::OpenIn(file->GetAbsolutePath());
break;
case FileType::Scene:
EditorRequests::Get().RequestLoadScene(file);
break;
case FileType::Solution:
OS::OpenIn(file->GetAbsolutePath());
break;
case FileType::Prefab:
//this->Editor->OpenPrefabWindow(file->GetRelativePath());
break;
}
}
editorContext.SetSelection(EditorSelection(file));
}
if (ImGui::IsItemHovered())
ImGui::SetTooltip(file->GetName().c_str());
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 == ".cs")
{
dragType = "_NetScript";
}
else if (fileExtension == ".map")
{
dragType = "_Map";
}
else if (fileExtension == ".material")
{
dragType = "_Material";
}
else if (fileExtension == ".nkmesh" || fileExtension == ".obj" || fileExtension == ".mdl" || fileExtension == ".gltf" || fileExtension == ".md3" || fileExtension == ".fbx" || fileExtension == ".glb")
{
dragType = "_Model";
}
else if (fileExtension == ".interface")
{
dragType = "_Interface";
}
else if (fileExtension == ".prefab")
{
dragType = "_Prefab";
}
else if (fileExtension == ".png" || fileExtension == ".jpg")
{
dragType = "_Image";
}
else if (fileExtension == ".wav" || fileExtension == ".ogg")
{
dragType = "_AudioFile";
}
else if (fileExtension == ".html")
{
dragType = "_UIFile";
}
else if (fileExtension == ".sky")
{
dragType = "_SkyFile";
}
else if (fileExtension == ".env")
{
dragType = "_EnvFile";
}
ImGui::SetDragDropPayload(dragType.c_str(), (void*)(pathBuffer), sizeof(pathBuffer));
ImGui::Text(file->GetName().c_str());
ImGui::EndDragDropSource();
}
Ref<VulkanImage> textureImage = TextureManager::Get()->GetTexture2("Resources/Images/file_icon.png");
const auto textureMgr = TextureManager::Get();
const auto fileType = file->GetFileType();
if (fileType == FileType::Material)
{
//auto image = ThumbnailManager::Get().GetThumbnail(file->GetRelativePath());
//if (image)
//{
// textureImage = image;
//}
}
else if (fileType == FileType::Image)
{
const std::string path = file->GetAbsolutePath();
int32_t imageNumberToLoadMax = maxImageLoaded;
if (ImGui::IsItemVisible())
{
imageNumberToLoadMax = 1;
}
if (ImageLoaded < maxImageLoaded || textureMgr->IsTextureLoaded2(path))
{
if(!textureMgr->IsTextureLoaded2(path))
ImageLoaded++;
textureImage = textureMgr->GetTexture2(path);
}
else
{
textureImage = textureMgr->GetTexture2("Resources/Images/env_file_icon.png");
}
}
else if (fileType == FileType::Project)
{
textureImage = textureMgr->GetTexture2("Resources/Images/project_icon.png");
}
else if (fileType == FileType::NetScript)
{
textureImage = textureMgr->GetTexture2("Resources/Images/csharp_icon.png");
}
else if (fileType == FileType::Scene)
{
textureImage = textureMgr->GetTexture2("Resources/Images/scene_icon.png");
}
else if (fileType == FileType::Script)
{
textureImage = textureMgr->GetTexture2("Resources/Images/script_file_icon.png");
}
else if (fileType == FileType::Audio)
{
textureImage = textureMgr->GetTexture2("Resources/Images/audio_file_icon.png");
}
else if (fileType == FileType::Prefab)
{
//auto image = ThumbnailManager::Get().GetThumbnail(file->GetRelativePath());
//if (image)
//{
// textureImage = image;
//}
}
else if (fileType == FileType::Mesh)
{
//auto image = ThumbnailManager::Get().GetThumbnail(file->GetRelativePath());
//if (image)
//{
// textureImage = image;
//}
}
else if (fileType == FileType::Solution)
{
textureImage = textureMgr->GetTexture2("Resources/Images/sln_icon.png");
}
else if (fileType == FileType::Map)
{
textureImage = textureMgr->GetTexture2("Resources/Images/trenchbroom_icon.png");
}
else if (fileType == FileType::Env)
{
textureImage = textureMgr->GetTexture2("Resources/Images/env_file_icon.png");
}
ImGui::SetCursorPos(prevCursor);
ImGui::Image(reinterpret_cast<ImTextureID>(textureImage->GetImGuiDescriptorSet()), size, { 0, 1 }, { 1, 0 });
ImGui::PopStyleVar();
auto& imguiStyle = ImGui::GetStyle();
ImVec2 startOffset = ImVec2(imguiStyle.CellPadding.x / 2.0f, 0);
ImVec2 offsetEnd = ImVec2(startOffset.x, imguiStyle.CellPadding.y / 2.0f);
ImU32 rectColor = IM_COL32(255, 255, 255, 16 * opacity);
ImGui::GetWindowDrawList()->AddRectFilled(prevScreenPos + ImVec2(0, 80) - startOffset, prevScreenPos + totalSize + offsetEnd, rectColor, 1.0f);
ImU32 rectColor2 = UI::PrimaryCol;
Color fileTypeColor = GetColorByFileType(file->GetFileType());
ImGui::GetWindowDrawList()->AddRectFilled(prevScreenPos + ImVec2(0, 80) - startOffset, prevScreenPos + ImVec2(80, 101) + offsetEnd, IM_COL32(fileTypeColor.r * 255.f, fileTypeColor.g * 255.f, fileTypeColor.b * 255.f, fileTypeColor.a * 255.f), 0.0f);
std::string visibleName = file->GetName();
const uint32_t MAX_CHAR_NAME = 32;
if (file->GetName().size() >= MAX_CHAR_NAME)
{
visibleName = std::string(visibleName.begin(), visibleName.begin() + MAX_CHAR_NAME - 3) + "...";
}
ImGui::TextWrapped(visibleName.c_str());
ImGui::SetCursorPosY(prevCursor.y + totalSize.y - ImGui::GetTextLineHeight());
ImGui::TextColored({ 1, 1, 1, 0.5f }, file->GetFileTypeAsString().c_str());
//if (fileExtension == ".png" || fileExtension == ".jpg")
//{
//
//}
//else
//{
// const char* icon = ICON_FA_FILE;
// if (fileExtension == ".shader" || fileExtension == ".wren")
// icon = ICON_FA_FILE_CODE;
// if (fileExtension == ".map")
// icon = ICON_FA_BROOM;
// if (fileExtension == ".ogg" || fileExtension == ".mp3" || fileExtension == ".wav")
// icon = ICON_FA_FILE_AUDIO;
// if (fileExtension == ".gltf" || fileExtension == ".obj")
// icon = ICON_FA_FILE_IMAGE;
//
// std::string fullName = icon + std::string("##") + file->GetAbsolutePath();
//
// bool pressed = false;
// if (fileExtension == ".material")
// {
// ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0));
// pressed = ImGui::ImageButton(fullName.c_str(), (void*)ThumbnailManager::Get().GetThumbnail(file-//>GetRelativePath())->GetID(), ImVec2(100, 100), ImVec2(0, 1), ImVec2(1, 0));
// ImGui::PopStyleVar();
// }
// else
// {
// ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0));
// pressed = ImGui::Button(fullName.c_str(), ImVec2(100, 100));
// ImGui::PopStyleVar();
// }
//
if (editorContext.GetSelection().File == file && editorContext.GetSelection().File->GetFileType() != FileType::Prefab)
{
//ThumbnailManager::Get().MarkThumbnailAsDirty(file->GetRelativePath());
}
// if(pressed)
// {
// Editor->Selection = EditorSelection(file);
// }
//
// if (ImGui::IsItemHovered() && ImGui::IsMouseDoubleClicked(0))
// {
// OS::OpenTrenchbroomMap(file->GetAbsolutePath());
// }
//}
ImGui::PopStyleVar();
const std::string openSceneId = "Open Scene" + std::string("##") + hoverMenuId;
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 (file->GetExtension() != ".scene")
{
if (ImGui::MenuItem("Open in Editor"))
{
OS::OpenIn(file->GetAbsolutePath());
}
}
else
{
if (ImGui::MenuItem("Load Scene"))
{
shouldOpenScene = true;
}
}
if (AssetBakerManager::Get().IsBakable(file))
{
if (ImGui::MenuItem("Rebake"))
{
AssetBakerManager::Get().OnNewAssetDetected(file);
}
}
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")
{
if (ImGui::MenuItem("Delete"))
{
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 (file->GetExtension() == ".wad")
{
if (ImGui::MenuItem("Convert to Materials"))
{
//Nuake::ExtractWad(file->GetAbsolutePath(), FileSystem::Root);
}
}
if (ImGui::MenuItem("Rename"))
{
shouldRename = true;
}
ImGui::Separator();
if (ImGui::MenuItem("Show in File Explorer"))
{
OS::ShowInFileExplorer(file->GetAbsolutePath());
}
ImGui::EndPopup();
}
// 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();
if (!scene->Deserialize(json::parse(FileSystem::ReadFile(projectPath, true))))
{
Logger::Log("Failed loading scene: " + projectPath, "editor", CRITICAL);
ImGui::PopFont();
return;
}
scene->Path = FileSystem::AbsoluteToRelative(projectPath);
Engine::SetCurrentScene(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::PopFont();
}
Color FileBrowserWidget::GetColorByFileType(Nuake::FileType fileType)
{
{
switch (fileType)
{
case Nuake::FileType::Unknown:
break;
case Nuake::FileType::Image:
break;
case Nuake::FileType::Material:
break;
case Nuake::FileType::Mesh:
break;
case Nuake::FileType::Script:
return { 1.0, 0.0, 0.0, 1.0 * opacity };
break;
case Nuake::FileType::NetScript:
return { 1.0, 0.0, 0.0, 1.0 * opacity };
break;
case Nuake::FileType::Project:
auto color = Engine::GetProject()->Settings.PrimaryColor ;
color.a *= opacity;
return color;
break;
case Nuake::FileType::Prefab:
break;
case Nuake::FileType::Scene:
return { 0, 1.0f, 1.0, 1.0 * opacity };
break;
case Nuake::FileType::Wad:
break;
case Nuake::FileType::Map:
return { 0.0, 1.0, 0.0, 1.0 * opacity };
break;
case Nuake::FileType::Assembly:
break;
case Nuake::FileType::Solution:
break;
case Nuake::FileType::Audio:
return { 0.0, 0.0, 1.0, 1.0 * opacity };
break;
case Nuake::FileType::UI:
return { 1.0, 1.0, 0.0, 1.0 * opacity };
break;
case Nuake::FileType::CSS:
return { 1.0, 0.0, 1.0, 1.0 * opacity };
break;
default:
break;
}
return Color(0, 0, 0, 0);
}
}

View File

@@ -1,45 +0,0 @@
#pragma once
#include "Nuake/Core/Core.h"
#include "Nuake/Core/Maths.h"
#include "Nuake/FileSystem/FileTypes.h"
#include "IEditorWidget.h"
#include "../../../misc/AnimatedValue.h"
namespace Nuake
{
class Directory;
class File;
}
class FileBrowserWidget : public IEditorWidget
{
private:
AnimatedValue<float> opacity;
float splitterSizeLeft = 300.0f;
float splitterSizeRight = 300.0f;
int maxImageLoaded = 2;
int ImageLoaded = 0;
Ref<Nuake::Directory> currentDirectory;
Ref<Nuake::Directory> queueDirectory;
std::string searchQuery;
public:
FileBrowserWidget(EditorContext& inCtx);
~FileBrowserWidget() = default;
public:
void SetCurrentDirectory(Ref<Nuake::Directory> dir);
void Update(float ts) override;
void Draw() override;
void DrawFiletree(Ref<Nuake::Directory> dir);
void DrawDirectory(Ref<Nuake::Directory> dir, uint32_t drawId);
void DrawFile(Ref<Nuake::File> file, uint32_t drawId);
Nuake::Color GetColorByFileType(Nuake::FileType fileType);
};

View File

@@ -1,54 +0,0 @@
#pragma once
#include "../EditorContext.h"
#include "Nuake/UI/ImUI.h"
class IEditorWidget
{
protected:
EditorContext& editorContext;
bool visible;
private:
std::string widgetName;
public:
IEditorWidget(EditorContext& inContext) : editorContext(inContext) {}
virtual ~IEditorWidget() {};
public:
virtual void Update(float ts) = 0;
virtual void Draw() = 0;
virtual void OnSceneChanged(Ref<Nuake::Scene> scene) {}
void SetVisible(bool isVisible)
{
visible = isVisible;
}
virtual void OnVisible() {}
virtual void OnHidden() {}
void DockTo(uint32_t dockId)
{
ImGui::DockBuilderDockWindow(widgetName.c_str(), dockId);
}
bool BeginWidgetWindow(const std::string_view& name)
{
return BeginWidgetWindow(name.data());
}
bool BeginWidgetWindow(const char* name)
{
ImGuiWindowClass windowClass;
windowClass.ClassId = ImHashStr(editorContext.GetWindowClass().data());
windowClass.DockingAllowUnclassed = false;
ImGui::SetNextWindowClass(&windowClass);
widgetName = std::string(name) + "##" + editorContext.GetScene()->Path;
return ImGui::Begin(widgetName.c_str());
}
};

View File

@@ -1,210 +0,0 @@
#include "LoggerWidget.h"
#include "Nuake/Core/Logger.h"
#include "Nuake/UI/ImUI.h"
#include "Nuake/Resource/Project.h"
#include "Engine.h"
using namespace Nuake;
void LoggerWidget::Update(float ts)
{
}
void LoggerWidget::Draw()
{
if (BeginWidgetWindow("Logger"))
{
if (ImGui::Button("Clear", ImVec2(60, 28)))
{
Logger::ClearLogs();
//SetStatusMessage("Logs cleared.");
}
ImGui::SameLine();
if (ImGui::Button(ICON_FA_FILTER, ImVec2(30, 28)))
{
ImGui::OpenPopup("filter_popup");
}
ImGui::SameLine();
bool isEnabled = LogErrors;
if (ImGui::BeginPopup("filter_popup"))
{
ImGui::SeparatorText("Filters");
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(2, 2));
ImGui::PushStyleColor(ImGuiCol_Button, IM_COL32(0, 0, 0, 0));
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 100);
if (isEnabled)
{
Color color = Engine::GetProject()->Settings.PrimaryColor;
ImGui::PushStyleColor(ImGuiCol_Button, { color.r, color.g, color.b, 1.0f });
}
if (ImGui::Button((std::string(ICON_FA_BAN) + " Error").c_str()))
{
LogErrors = !LogErrors;
}
UI::Tooltip("Display Errors");
if (isEnabled)
{
ImGui::PopStyleColor();
}
isEnabled = LogWarnings;
if (isEnabled)
{
Color color = Engine::GetProject()->Settings.PrimaryColor;
ImGui::PushStyleColor(ImGuiCol_Button, { color.r, color.g, color.b, 1.0f });
}
if (ImGui::Button((std::string(ICON_FA_EXCLAMATION_TRIANGLE) + " Warning").c_str()))
{
LogWarnings = !LogWarnings;
}
UI::Tooltip("Display Warnings");
if (isEnabled)
{
ImGui::PopStyleColor();
}
isEnabled = LogDebug;
if (isEnabled)
{
Color color = Engine::GetProject()->Settings.PrimaryColor;
ImGui::PushStyleColor(ImGuiCol_Button, { color.r, color.g, color.b, 1.0f });
}
if (ImGui::Button((std::string(ICON_FA_INFO) + " Info").c_str()))
{
LogDebug = !LogDebug;
}
UI::Tooltip("Display Verbose");
if (isEnabled)
{
ImGui::PopStyleColor();
}
ImGui::PopStyleColor();
ImGui::PopStyleVar(2);
ImGui::EndPopup();
}
ImGui::SameLine();
isEnabled = AutoScroll;
if (isEnabled)
{
Color color = Engine::GetProject()->Settings.PrimaryColor;
ImGui::PushStyleColor(ImGuiCol_Button, { color.r, color.g, color.b, 1.0f });
}
if (ImGui::Button(ICON_FA_ARROW_DOWN, ImVec2(30, 28)))
{
AutoScroll = !AutoScroll;
}
UI::Tooltip("Auto-Scroll");
if (isEnabled)
{
ImGui::PopStyleColor();
}
//ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0));
//if (ImGui::BeginChild("Log window", ImGui::GetContentRegionAvail(), false))
//{
//ImGui::PopStyleVar();
ImGuiTableFlags flags = ImGuiTableFlags_ScrollY | ImGuiTableFlags_RowBg | ImGuiTableFlags_Hideable;
if (ImGui::BeginTable("LogTable", 3, flags))
{
ImGui::TableSetupColumn("Severity", ImGuiTableColumnFlags_WidthFixed, 64.0f);
ImGui::TableSetupColumn("Time", ImGuiTableColumnFlags_WidthFixed, 64.0f);
ImGui::TableSetupColumn("Message", ImGuiTableColumnFlags_WidthStretch, 1.0f);
ImGui::TableNextColumn();
ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, ImVec2(4, 4));
for (auto& l : Logger::GetLogs())
{
if (l.type == LOG_TYPE::VERBOSE && !LogDebug)
continue;
if (l.type == LOG_TYPE::WARNING && !LogWarnings)
continue;
if (l.type == LOG_TYPE::CRITICAL && !LogErrors)
continue;
std::string severityText = "";
if (l.type == LOG_TYPE::VERBOSE)
severityText = "verbose";
else if (l.type == LOG_TYPE::WARNING)
severityText = "warning";
else
severityText = "critical";
ImVec4 redColor = ImVec4(0.6, 0.1f, 0.1f, 0.2f);
ImVec4 yellowColor = ImVec4(0.6, 0.6f, 0.1f, 0.2f);
ImVec4 colorGreen = ImVec4(0.59, 0.76, 0.47, 1.0);
ImGui::PushStyleColor(ImGuiCol_Text, colorGreen);
ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg, ImGui::GetColorU32(ImVec4(0.59, 0.76, 0.47, 0.2)), -1);
const std::string timeString = " [" + l.time + "]";
ImGui::Text(timeString.c_str());
ImGui::PopStyleColor();
ImGui::TableNextColumn();
ImVec4 colorBlue = ImVec4(98 / 255.0, 174 / 255.0, 239 / 255.0, 1.);
ImGui::PushStyleColor(ImGuiCol_Text, colorBlue);
ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg, ImGui::GetColorU32(ImVec4(98 / 255.0, 174 / 255.0, 239 / 255.0, 0.2)), -1);
ImGui::Text(l.logger.c_str());
ImGui::PopStyleColor();
ImGui::TableNextColumn();
ImVec4 color = ImVec4(1, 1, 1, 1.0);
ImGui::PushStyleColor(ImGuiCol_Text, color);
if (l.type == CRITICAL)
{
ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg, ImGui::GetColorU32(redColor), -1);
}
else if (l.type == WARNING)
{
ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg, ImGui::GetColorU32(yellowColor), -1);
}
else
{
ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg, ImGui::GetColorU32(ImVec4(1, 1, 1, 0.0)), -1);
}
std::string displayMessage = l.message;
if (l.count > 0)
{
displayMessage += "(" + std::to_string(l.count) + ")";
}
ImGui::TextWrapped(displayMessage.c_str());
ImGui::PopStyleColor();
ImGui::TableNextColumn();
}
ImGui::PopStyleVar();
if (AutoScroll && ImGui::GetScrollY() >= ImGui::GetScrollMaxY())
{
ImGui::SetScrollHereY(1.0f);
}
ImGui::EndTable();
}
}
ImGui::End();
}

View File

@@ -1,20 +0,0 @@
#pragma once
#include "IEditorWidget.h"
class LoggerWidget : public IEditorWidget
{
private:
bool LogErrors = true;
bool LogWarnings = true;
bool LogDebug = true;
bool AutoScroll = true;
public:
LoggerWidget(EditorContext& inCtx) : IEditorWidget(inCtx) {}
~LoggerWidget() = default;
public:
void Update(float ts) override;
void Draw() override;
};

View File

@@ -1,559 +0,0 @@
#include "Nuake/Core/Core.h"
#include "SceneHierarchyWidget.h"
#include "Nuake/UI/ImUI.h"
#include <imgui/imgui.h>
#include <imgui/imgui_internal.h>
#include "Nuake/Scene/Entities/Entity.h"
#include "Nuake/Scene/Components.h"
#include <Nuake/Core/Input.h>
#include <Nuake/FileSystem/FileDialog.h>
#include "Engine.h"
#include "Nuake/Resource/Project.h"
using namespace Nuake;
SceneHierarchyWidget::SceneHierarchyWidget(EditorContext& inCtx) :
IEditorWidget(inCtx),
isRenaming(false),
searchQuery("")
{
}
void SceneHierarchyWidget::Update(float ts)
{
}
void SceneHierarchyWidget::Draw()
{
if (BeginWidgetWindow("Scene Hierarchy"))
{
DrawSearchBar();
DrawCreateEntityButton();
DrawEntityTree();
}
ImGui::End();
}
void SceneHierarchyWidget::DrawSearchBar()
{
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, { 8, 8 });
ImGui::InputTextWithHint("##search", "Search entity", &searchQuery, 0, 0, 0);
ImGui::PopStyleVar();
ImGui::SameLine();
}
void SceneHierarchyWidget::DrawCreateEntityButton()
{
Ref<Scene> scene = editorContext.GetScene();
if (UI::PrimaryButton("Add Entity", { ImGui::GetContentRegionAvail().x, 0 }))
{
ImGui::OpenPopup("create_entity_popup");
}
if (ImGui::BeginPopup("create_entity_popup"))
{
Nuake::Entity entity;
if (ImGui::MenuItem("Empty"))
{
entity = scene->CreateEntity("Empty");
}
if (ImGui::BeginMenu("3D"))
{
if (ImGui::MenuItem("Camera"))
{
entity = scene->CreateEntity("Camera");
entity.AddComponent<CameraComponent>();
}
if (ImGui::MenuItem("Model"))
{
entity = scene->CreateEntity("Model");
entity.AddComponent<ModelComponent>();
}
if (ImGui::MenuItem("Skinned Model"))
{
entity = scene->CreateEntity("Skinned Model");
entity.AddComponent<SkinnedModelComponent>();
}
if (ImGui::MenuItem("Sprite"))
{
entity = scene->CreateEntity("Sprite");
entity.AddComponent<SpriteComponent>();
}
if (ImGui::MenuItem("Particle Emitter"))
{
entity = scene->CreateEntity("Particle Emitter");
entity.AddComponent<ParticleEmitterComponent>();
}
if (ImGui::MenuItem("Light"))
{
entity = scene->CreateEntity("Light");
entity.AddComponent<LightComponent>();
}
if (ImGui::MenuItem("Quake Map"))
{
entity = scene->CreateEntity("Quake Map");
entity.AddComponent<QuakeMapComponent>();
}
if (ImGui::MenuItem("NavMesh Volume"))
{
entity = scene->CreateEntity("NavMesh Volume");
entity.AddComponent<NavMeshVolumeComponent>();
}
ImGui::EndMenu();
}
if (ImGui::BeginMenu("Physics"))
{
if (ImGui::MenuItem("Character Controller"))
{
entity = scene->CreateEntity("Character Controller");
entity.AddComponent<CharacterControllerComponent>();
}
if (ImGui::MenuItem("Rigid Body"))
{
entity = scene->CreateEntity("Rigid Body");
entity.AddComponent<RigidBodyComponent>();
}
ImGui::EndMenu();
}
if (ImGui::BeginMenu("Colliders"))
{
if (ImGui::MenuItem("Box Collider"))
{
entity = scene->CreateEntity("Box Collider");
entity.AddComponent<BoxColliderComponent>();
}
if (ImGui::MenuItem("Sphere Collider"))
{
entity = scene->CreateEntity("Sphere Collider");
entity.AddComponent<SphereColliderComponent>();
}
if (ImGui::MenuItem("Capsule Collider"))
{
entity = scene->CreateEntity("Capsule Collider");
entity.AddComponent<CapsuleColliderComponent>();
}
if (ImGui::MenuItem("Cylinder Collider"))
{
entity = scene->CreateEntity("Cylinder Collider");
entity.AddComponent<CylinderColliderComponent>();
}
if (ImGui::MenuItem("Mesh Collider"))
{
entity = scene->CreateEntity("Mesh Collider");
entity.AddComponent<MeshColliderComponent>();
}
ImGui::EndMenu();
}
if (ImGui::BeginMenu("Audio"))
{
if (ImGui::MenuItem("Audio Emitter"))
{
entity = scene->CreateEntity("Audio Emitter");
entity.AddComponent<AudioEmitterComponent>();
}
ImGui::EndMenu();
}
if (entity.IsValid())
{
EditorSelection selection = editorContext.GetSelection();
if (selection.Type == EditorSelectionType::Entity && selection.Entity.IsValid())
{
selection.Entity.AddChild(entity);
}
else
{
auto& camera = editorContext.GetScene()->m_EditorCamera;
Vector3 newEntityPos = camera->Translation + camera->Direction;
entity.GetComponent<TransformComponent>().SetLocalPosition(newEntityPos);
}
editorContext.SetSelection(EditorSelection(entity));
}
ImGui::EndPopup();
}
}
void SceneHierarchyWidget::DrawEntityTree()
{
Ref<Scene> scene = editorContext.GetScene();
ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(26.f / 255.0f, 26.f / 255.0f, 26.f / 255.0f, 1));
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, { 4, 4 });
if (ImGui::BeginChild("Scene tree", ImGui::GetContentRegionAvail(), false))
{
if (ImGui::BeginTable("entity_table", 4, ImGuiTableFlags_BordersInnerV | ImGuiTableFlags_SizingStretchProp))
{
ImGui::TableSetupColumn(" Label", ImGuiTableColumnFlags_IndentEnable | ImGuiTableColumnFlags_NoResize | ImGuiTableColumnFlags_WidthStretch);
ImGui::TableSetupColumn("Type", ImGuiTableColumnFlags_IndentDisable | ImGuiTableColumnFlags_WidthFixed);
ImGui::TableSetupColumn("Script", ImGuiTableColumnFlags_NoResize | ImGuiTableColumnFlags_IndentDisable | ImGuiTableColumnFlags_WidthFixed);
ImGui::TableSetupColumn("Visibility ", ImGuiTableColumnFlags_NoResize | ImGuiTableColumnFlags_IndentDisable | ImGuiTableColumnFlags_WidthFixed);
ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, ImVec2(0, 0));
std::vector<Nuake::Entity> entitiesToDisplay;
if (searchQuery.empty())
{
entitiesToDisplay = scene->GetAllEntities();
}
else
{
auto view = scene->m_Registry.view<NameComponent>();
for (auto& e : view)
{
auto& nameComponent = view.get<NameComponent>(e);
if (String::RemoveWhiteSpace(String::ToUpper(nameComponent.Name)).find(String::RemoveWhiteSpace(String::ToUpper(searchQuery))) != std::string::npos)
{
entitiesToDisplay.push_back({ e, scene.get() });
}
}
}
// Display valid entities
for (Nuake::Entity e : entitiesToDisplay)
{
// Draw all entity without parents.
bool displayAllHierarchy = searchQuery.empty();
if ((displayAllHierarchy && !e.GetComponent<ParentComponent>().HasParent) || !displayAllHierarchy)
{
// TODO(antopilo): Add font regular font
// ImGui::PushFont(normalFont);
// Recursively draw childrens if not searching
DrawEntity(e, displayAllHierarchy);
// ImGui::PopFont();
}
}
ImGui::PopStyleVar();
}
ImGui::EndTable();
}
ImGui::EndChild();
ImGui::PopStyleVar();
ImGui::PopStyleColor();
if(ImGui::BeginDragDropTarget()) // Drag n drop new prefab file into scene tree
{
if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("_Prefab"))
{
char* file = (char*)payload->Data;
std::string fullPath = std::string(file, 256);
std::string relPath = FileSystem::AbsoluteToRelative(fullPath);
auto newPrefabInstance = Prefab::New(relPath);
newPrefabInstance->Root.GetComponent<PrefabComponent>().SetPrefab(newPrefabInstance);
newPrefabInstance->Root.GetComponent<NameComponent>().IsPrefab = true;
}
ImGui::EndDragDropTarget();
}
if (deletionQueue.GetHandle() != -1)
{
scene->DestroyEntity(deletionQueue);
// Unselect
editorContext.SetSelection(EditorSelection());
deletionQueue = Nuake::Entity{ (entt::entity)-1, scene.get() };
}
}
void SceneHierarchyWidget::DrawEntity(Nuake::Entity entity, bool drawChildrens)
{
ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, ImVec2{ 0.0f, 0.0f });
ImGuiTreeNodeFlags base_flags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_FramePadding | ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_SpanAllColumns;
NameComponent& nameComponent = entity.GetComponent<NameComponent>();
std::string name = nameComponent.Name;
ParentComponent& parent = entity.GetComponent<ParentComponent>();
ImGui::TableNextColumn();
// Draw first column Name
// Highlight if the entity is currently selected
auto selection = editorContext.GetSelection();
if (selection.Type == EditorSelectionType::Entity && selection.Entity == entity)
{
base_flags |= ImGuiTreeNodeFlags_Selected;
}
// Display arrow if it has children
bool isPrefab = entity.HasComponent<PrefabComponent>();
if (parent.Children.size() == 0 || isPrefab || !drawChildrens)
{
base_flags |= ImGuiTreeNodeFlags_Leaf;
}
// Hightlight if the entity is a prefab or BSP
if (nameComponent.IsPrefab && entity.HasComponent<PrefabComponent>())
{
ImGui::PushStyleColor(ImGuiCol_Text, IM_COL32(0, 255, 0, 255));
}
else if (entity.HasComponent<BSPBrushComponent>())
{
ImGui::PushStyleColor(ImGuiCol_Text, IM_COL32(255, 255, 255, 120));
}
// TODO(antopilo) unfolding when mouse picking
ImVec2 cursorPos = ImGui::GetCursorPos();
ImVec2 cursorPosition = ImGui::GetCursorScreenPos();
const auto& cleanName = String::RemoveWhiteSpace(String::ToUpper(name));
const size_t searchIt = cleanName.find(String::RemoveWhiteSpace(String::ToUpper(searchQuery)));
ImGui::SetNextItemAllowOverlap();
bool open = ImGui::TreeNodeEx(name.c_str(), base_flags);
if (!searchQuery.empty() && searchIt != std::string::npos)
{
int firstLetterFoundIndex = static_cast<int>(searchIt);
const auto foundStr = name.substr(0, firstLetterFoundIndex + searchQuery.size());
auto highlightBeginPos = ImGui::CalcTextSize(foundStr.c_str());
auto highlightEndPos = ImGui::CalcTextSize(searchQuery.c_str());
auto fg = ImGui::GetForegroundDrawList();
auto color = Engine::GetProject()->Settings.PrimaryColor;
auto rgbColor = IM_COL32(color.r * 255.0f, color.g * 255.0f, color.b * 255.0f, std::min(color.a, 0.2f) * 255.0f);
fg->AddRectFilled(ImVec2(cursorPosition.x + 20.0f, cursorPosition.y + 4.0f), ImVec2(cursorPosition.x + highlightEndPos.x + 26.0f, cursorPosition.y + highlightEndPos.y + 6.0f), rgbColor, 4.0f);
}
// Renaming behavior
if (isRenaming)
{
if (selection.Type == EditorSelectionType::Entity && selection.Entity == entity)
{
ImGui::SetCursorPosY(cursorPos.y);
ImGui::Indent();
ImGui::InputText("##renamingEntity", &name);
ImGui::Unindent();
if (Nuake::Input::IsKeyDown(Key::ENTER))
{
nameComponent.Name = name;
isRenaming = false;
}
}
}
// Drag and drop behavior
bool isDragging = false;
if (nameComponent.IsPrefab && entity.HasComponent<PrefabComponent>() || entity.HasComponent<BSPBrushComponent>())
{
ImGui::PopStyleColor();
}
else if (!isRenaming && ImGui::BeginDragDropSource())
{
ImGui::SetDragDropPayload("ENTITYPrefab", (void*)&entity, sizeof(Nuake::Entity));
ImGui::Text(name.c_str());
ImGui::EndDragDropSource();
}
if (ImGui::BeginDragDropTarget())
{
if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("ENTITYPrefab"))
{
Nuake::Entity payload_entity = *(const Nuake::Entity*)payload->Data;
// Check if entity is already parent.
ParentComponent& parentPayload = payload_entity.GetComponent<ParentComponent>();
if (!payload_entity.EntityContainsItself(payload_entity, entity) && parentPayload.Parent != entity && std::count(parent.Children.begin(), parent.Children.end(), payload_entity) == 0)
{
if (parentPayload.HasParent)
{
// Erase remove idiom.
ParentComponent& childOfParent = parentPayload.Parent.GetComponent<ParentComponent>();
childOfParent.Children.erase(std::remove(childOfParent.Children.begin(), childOfParent.Children.end(), payload_entity), childOfParent.Children.end());
}
parentPayload.Parent = entity;
parentPayload.HasParent = true;
parent.Children.push_back(payload_entity);
}
}
else if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("_NetScript"))
{
char* file = (char*)payload->Data;
std::string fullPath = std::string(file, 512);
std::string path = Nuake::FileSystem::AbsoluteToRelative(std::move(fullPath));
if (entity.HasComponent<NetScriptComponent>())
{
entity.GetComponent<NetScriptComponent>().ScriptPath = path;
}
else
{
entity.AddComponent<NetScriptComponent>().ScriptPath = path;
}
}
ImGui::EndDragDropTarget();
}
if (!isDragging && ImGui::IsItemHovered() && ImGui::IsMouseReleased(0))
{
// We selected another another that we werent renaming
if (selection.Entity != entity)
{
isRenaming = false;
}
editorContext.SetSelection(EditorSelection(entity));
}
if (!isDragging && (ImGui::IsItemHovered() && ImGui::IsMouseTripleClicked(0)) || Input::IsKeyPressed(Key::F2))
{
isRenaming = true;
}
if (!isDragging && (ImGui::IsItemHovered() && ImGui::IsMouseDoubleClicked(0)) || Input::IsKeyPressed(Key::F2))
{
Ref<EditorCamera> editorCam = editorContext.GetScene()->m_EditorCamera;
// Get target object's world position
glm::vec3 targetPos = glm::vec3(entity.GetComponent<TransformComponent>().GetGlobalTransform()[3]);
// Choose a direction and distance to place the camera away from the object
glm::vec3 offset = glm::vec3(2.0f, 2.0f, 2.0f); // above and behind
// Place camera at offset from the target
glm::vec3 camPos = targetPos + offset;
editorCam->Translation = camPos;
Vector3 direction = glm::normalize(targetPos - Vector3(camPos));
float yaw = glm::degrees(atan2(direction.z, direction.x));
float pitch = glm::degrees(asin(direction.y));
editorCam->TargetYaw = yaw;
editorCam->TargetPitch = pitch;
// Set the camera's transform as the inverse of the view matrix
//editorCam->SetTransform(glm::inverse(view));
}
if (!isRenaming && selection.Type == EditorSelectionType::Entity && Input::IsKeyPressed(Key::DELETE_KEY))
{
this->deletionQueue = selection.Entity;
}
if (ImGui::BeginPopupContextItem())
{
editorContext.SetSelection(EditorSelection(entity));
Nuake::Entity entity = selection.Entity;
if (entity.HasComponent<CameraComponent>())
{
// Moves the editor camera to the camera position and direction.
if (ImGui::Selectable("Focus camera"))
{
Ref<EditorCamera> editorCam = editorContext.GetScene()->m_EditorCamera;
Vector3 camDirection = entity.GetComponent<CameraComponent>().CameraInstance->GetDirection();
camDirection.z *= -1.0f;
editorCam->SetTransform(glm::inverse(entity.GetComponent<TransformComponent>().GetGlobalTransform()));
}
ImGui::Separator();
}
if (ImGui::Selectable("Remove"))
{
deletionQueue = entity;
}
if (entity.GetComponent<ParentComponent>().HasParent && ImGui::Selectable("Move to root"))
{
auto& parentComp = selection.Entity.GetComponent<ParentComponent>();
if (parentComp.HasParent)
{
auto& parentParentComp = parentComp.Parent.GetComponent<ParentComponent>();
parentParentComp.RemoveChildren(entity);
parentComp.HasParent = false;
}
}
if (ImGui::Selectable("Save entity as a new prefab"))
{
Ref<Prefab> newPrefab = Prefab::CreatePrefabFromEntity(selection.Entity);
std::string savePath = Nuake::FileDialog::SaveFile("*.prefab");
if (!String::EndsWith(savePath, ".prefab"))
{
savePath += ".prefab";
}
if (!savePath.empty())
{
newPrefab->SaveAs(savePath);
selection.Entity.AddComponent<PrefabComponent>().PrefabInstance = newPrefab;
}
}
ImGui::EndPopup();
}
ImGui::TableNextColumn();
ImGui::TextColored(ImVec4(0.5, 0.5, 0.5, 1.0), "");
ImGui::TableNextColumn();
{
bool hasScript = entity.HasComponent<NetScriptComponent>();
if (hasScript)
{
std::string scrollIcon = std::string(ICON_FA_SCROLL) + "##" + name;
ImGui::PushStyleColor(ImGuiCol_Button, { 0, 0, 0, 0 });
if (ImGui::Button(scrollIcon.c_str(), { 40, 0 }))
{
auto& scriptComponent = entity.GetComponent<NetScriptComponent>();
if (!scriptComponent.ScriptPath.empty() && FileSystem::FileExists(scriptComponent.ScriptPath))
{
OS::OpenIn(FileSystem::RelativeToAbsolute(scriptComponent.ScriptPath));
}
}
ImGui::PopStyleColor();
}
}
ImGui::TableNextColumn();
{
bool& isVisible = entity.GetComponent<VisibilityComponent>().Visible;
std::string visibilityIcon = isVisible ? ICON_FA_EYE : ICON_FA_EYE_SLASH;
ImGui::PushStyleColor(ImGuiCol_Button, { 0, 0, 0, 0 });
if (ImGui::Button(visibilityIcon.c_str(), { 40, 0 }))
{
isVisible = !isVisible;
}
ImGui::PopStyleColor();
}
if (open)
{
if (drawChildrens && !isPrefab)
{
// Caching list to prevent deletion while iterating.
std::vector<Nuake::Entity> childrens = parent.Children;
for (auto& e : childrens)
{
DrawEntity(e);
}
}
ImGui::TreePop();
}
ImGui::PopStyleVar();
}

View File

@@ -1,29 +0,0 @@
#pragma once
#include "IEditorWidget.h"
#include "Nuake/Scene/Entities/Entity.h"
class EditorContext;
class SceneHierarchyWidget : public IEditorWidget
{
public:
SceneHierarchyWidget(EditorContext& inCtx);
~SceneHierarchyWidget() = default;
public:
void Update(float ts) override;
void Draw() override;
private:
std::string searchQuery;
bool isRenaming;
Nuake::Entity deletionQueue;
void DrawSearchBar();
void DrawCreateEntityButton();
void DrawEntityTree();
void DrawEntity(Nuake::Entity entity, bool drawChildrens = true);
};

View File

@@ -1,81 +0,0 @@
#pragma once
#include "IEditorWidget.h"
#include "../../EditorSelectionPanel.h"
#include "../../../misc/AnimatedValue.h"
#include "../../../ComponentsPanel/MaterialEditor.h"
class EditorContext;
using DrawComponentTypeFn = std::function<void(Nuake::Entity& entity, entt::meta_any& componentInstance)>;
using DrawFieldTypeFn = std::function<void(entt::meta_data& fieldMeta, entt::meta_any& componentInstance)>;
class SelectionPropertyWidget : public IEditorWidget
{
private:
MaterialEditor matEditor;
TransformPanel transformPanel;
MeshPanel meshPanel;
SkinnedMeshPanel skinnedMeshPanel;
Ref<Nuake::File> currentFile;
Ref<Nuake::Resource> selectedResource;
AnimatedValue<float> opacity;
public:
SelectionPropertyWidget(EditorContext& inCtx);
~SelectionPropertyWidget() = default;
public:
void Update(float ts) override;
void Draw() override;
private:
void DrawNone();
void DrawEntity(Nuake::Entity entity);
void DrawAddComponentMenu(Nuake::Entity entity);
void DrawFile(Ref<Nuake::File> file);
void DrawResource(Nuake::Resource resource);
template<class T, auto Func>
void RegisterComponentDrawer()
{
const auto t = entt::type_id<T>();
ComponentTypeDrawers[t.hash()] = std::bind(Func, std::placeholders::_1, std::placeholders::_2);
}
template<class T, auto Func, class O>
void RegisterComponentDrawer(O* o)
{
ComponentTypeDrawers[entt::type_id<T>().hash()] = std::bind(Func, o, std::placeholders::_1, std::placeholders::_2);
}
template<class T, auto Func, class O>
void RegisterTypeDrawer(O* o)
{
FieldTypeDrawers[entt::type_id<T>().hash()] = std::bind(Func, o, std::placeholders::_1, std::placeholders::_2);
}
protected:
// Drawing functions for each component (for writing very specific inspectors for specific components)
std::unordered_map<entt::id_type, DrawComponentTypeFn> ComponentTypeDrawers;
// List of functions to call for each component field type that needs to be drawn
std::unordered_map<entt::id_type, DrawFieldTypeFn> FieldTypeDrawers;
void ResolveFile(Ref<Nuake::File> file);
void DrawMaterialPanel(Ref<Nuake::Material> material);
void DrawProjectPanel(Ref<Nuake::Project> project);
void DrawNetScriptPanel(Ref<Nuake::File> file);
void DrawComponent(Nuake::Entity& entity, entt::meta_any& component);
void DrawComponentContent(entt::meta_any& component);
void DrawFieldTypeFloat(entt::meta_data& field, entt::meta_any& component);
void DrawFieldTypeBool(entt::meta_data& field, entt::meta_any& component);
void DrawFieldTypeVector2(entt::meta_data& field, entt::meta_any& component);
void DrawFieldTypeVector3(entt::meta_data& field, entt::meta_any& component);
void DrawFieldTypeString(entt::meta_data& field, entt::meta_any& component);
void DrawFieldTypeResourceFile(entt::meta_data& field, entt::meta_any& component);
void DrawFieldTypeDynamicItemList(entt::meta_data& field, entt::meta_any& component);
};

View File

@@ -1,738 +0,0 @@
#include "ViewportWidget.h"
#include <Nuake/UI/ImUI.h>
#include "Nuake/Core/Input.h"
#include "../../EditorInterface.h"
#include "Nuake/Rendering/Vulkan/VulkanRenderer.h"
#include "Nuake/Rendering/Vulkan/SceneViewport.h"
#include "Nuake/Rendering/Vulkan/DebugCmd.h"
#include "Nuake/Rendering/Vulkan/SceneRenderPipeline.h"
#include <glm/gtc/type_ptr.hpp>
#include <Nuake/Scene/Components/AudioEmitterComponent.h>
#include <Nuake/Scene/Components/ParticleEmitterComponent.h>
#include <Nuake/Scene/Components/RigidbodyComponent.h>
#include <Nuake/Scene/Components/BoxCollider.h>
#include <Nuake/Scene/Components/SphereCollider.h>
using namespace Nuake;
ViewportWidget::ViewportWidget(EditorContext& context) :
IEditorWidget(context),
gizmoDrawingMode(GizmoDrawingModes::EditorOnly)
{
OnSceneChanged(context.GetScene());
overlayOpacity.Speed = 10.0f;
overlayOpacity = 1.0f;
outlineSize = Engine::GetProject()->Settings.OutlineRadius;
}
ViewportWidget::~ViewportWidget()
{
VkRenderer::Get().RemoveViewport(sceneViewport->GetID());
}
void ViewportWidget::Update(float ts)
{
editorContext.GetScene()->Update(ts);
if (!Engine::IsPlayMode())
{
EditorCamera& editorCam = reinterpret_cast<EditorCamera&>(*editorContext.GetScene()->GetCurrentCamera().get());
IsControllingCamera = editorCam.Update(ts, isHoveringViewport);
}
const Vector2 viewportSize = sceneViewport->GetViewportSize();
editorContext.GetScene()->GetCurrentCamera()->OnWindowResize(viewportSize.x, viewportSize.y);
if (editorContext.GetSelection().Type == EditorSelectionType::Entity)
{
sceneViewport->SetSelectedEntityID(editorContext.GetSelection().Entity.GetHandle());
}
else
{
sceneViewport->SetSelectedEntityID(-1);
}
}
void ViewportWidget::OnVisible()
{
sceneViewport->SetActive(true);
}
void ViewportWidget::OnHidden()
{
sceneViewport->SetActive(false);
}
void ViewportWidget::Draw()
{
auto oldTarget = overlayOpacity.TargetValue;
overlayOpacity.TargetValue = Engine::GetGameState() == GameState::Playing ? 0.0f : 1.0f;
if (overlayOpacity.TargetValue == oldTarget)
{
IAnimatedValue::UpdateAll(glm::clamp((float)Engine::GetTimestep(), 0.0f, Engine::GetFixedTimeStep()));
}
else
{
overlayOpacity.Value = (Engine::GetGameState() != GameState::Playing);
overlayOpacity.TargetValue = 1.0f - overlayOpacity.Value;
}
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0));
if (BeginWidgetWindow(ICON_FA_GAMEPAD + std::string("Viewport")))
{
ImGui::PopStyleVar();
{
ImGui::PushStyleVar(ImGuiStyleVar_Alpha, overlayOpacity.Value);
DrawOverlay();
ImGui::PopStyleVar();
}
ImGuizmo::BeginFrame();
ImGuizmo::SetOrthographic(false);
ImVec2 regionAvail = ImGui::GetContentRegionAvail();
Vector2 viewportPanelSize = glm::vec2(regionAvail.x, regionAvail.y);
bool needsResize = sceneViewport->QueueResize(viewportPanelSize);
editorContext.GetScene()->GetCurrentCamera()->OnWindowResize(regionAvail.x, regionAvail.y);
// This is important for make UI mouse coord relative to viewport
// Nuake::Input::SetViewportDimensions(m_ViewportPos, viewportPanelSize);
ImVec2 imagePos = ImGui::GetWindowPos() + ImGui::GetCursorPos();
ImVec2 viewportMin = ImGui::GetCursorScreenPos();
// Input::SetEditorViewportSize(m_ViewportPos, viewportPanelSize);
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0));
//m_ViewportPos = { imagePos.x, imagePos.y };
VkDescriptorSet textureDesc = sceneViewport->GetRenderTarget()->GetImGuiDescriptorSet();
if (!needsResize)
{
ImGui::Image(textureDesc, regionAvail, { 0, 1 }, { 1, 0 });
}
ImGui::PopStyleVar();
float title_bar_height = ImGui::GetFontSize() + ImGui::GetStyle().FramePadding.y * 2;
Vector2 mousePos = Input::GetMousePosition();
mousePos.y -= title_bar_height;
const ImVec2& windowPos = ImGui::GetWindowPos();
const auto windowPosNuake = Vector2(windowPos.x, windowPos.y);
const ImVec2& windowSize = ImGui::GetWindowSize();
const bool isInsideWidth = mousePos.x > windowPos.x && mousePos.x < windowPos.x + windowSize.x;
const bool isInsideHeight = mousePos.y > windowPos.y && mousePos.y < windowPos.y + windowSize.y;
this->isHoveringViewport = isInsideWidth && isInsideHeight;
auto pixelPos = (mousePos - windowPosNuake) * Engine::GetProject()->Settings.ResolutionScale;
// TODO(antopilo) drag n drop
ImGuizmo::SetDrawlist();
ImGuizmo::AllowAxisFlip(true);
ImGuizmo::SetRect(viewportMin.x, viewportMin.y, regionAvail.x, regionAvail.y);
Engine::GetProject()->Settings.OutlineRadius = outlineSize;
// TODO(grid)
auto selection = editorContext.GetSelection();
if (selection.Type == EditorSelectionType::Entity && !Engine::IsPlayMode())
{
if (!selection.Entity.IsValid())
{
editorContext.SetSelection(EditorSelection());
}
else
{
TransformComponent& tc = selection.Entity.GetComponent<TransformComponent>();
Matrix4 transform = tc.GetGlobalTransform();
auto editorCam = editorContext.GetScene()->GetCurrentCamera();
Matrix4 cameraView = editorCam->GetTransform();
// Since imguizmo doesnt support reverse-Z, we need to create a new projection matrix
// With a normal near and far plane.
Matrix4 normalZProjection = glm::perspectiveFov(glm::radians(editorCam->Fov), 9.0f * editorCam->AspectRatio, 9.0f, editorCam->Far, editorCam->Near);
static Vector3 camPreviousPos = editorContext.GetScene()->m_EditorCamera->Translation;
static Vector3 camNewPos = Vector3(0, 0, 0);
Vector3 camDelta = camNewPos - camPreviousPos;
Vector3 previousGlobalPos = transform[3];
// Imguizmo calculates the delta from the gizmo,
ImGuizmo::Manipulate(
glm::value_ptr(editorCam->GetTransform()),
glm::value_ptr(normalZProjection),
CurrentOperation, CurrentMode,
glm::value_ptr(transform), NULL,
UseSnapping ? &CurrentSnapping.x : NULL
);
if (ImGuizmo::IsUsing())
{
// Since imguizmo returns a transform in global space and we want the local transform,
// we need to multiply by the inverse of the parent's global transform in order to revert
// the changes from the parent transform.
Matrix4 localTransform = Matrix4(transform);
Vector3 newGlobalPos = transform[3];
if (ImGui::IsKeyDown(ImGuiKey_LeftShift))
{
Vector3 positionDelta = newGlobalPos - previousGlobalPos;
editorContext.GetScene()->m_EditorCamera->Translation += positionDelta;
camNewPos = editorContext.GetScene()->m_EditorCamera->Translation;
}
ParentComponent& parent = selection.Entity.GetComponent<ParentComponent>();
if (parent.HasParent)
{
const auto& parentTransformComponent = parent.Parent.GetComponent<TransformComponent>();
const Matrix4& parentTransform = parentTransformComponent.GetGlobalTransform();
localTransform = glm::inverse(parentTransform) * localTransform;
}
// Decompose local transform
float decomposedPosition[3];
float decomposedEuler[3];
float decomposedScale[3];
ImGuizmo::DecomposeMatrixToComponents(glm::value_ptr(localTransform), decomposedPosition, decomposedEuler, decomposedScale);
const auto& localPosition = Vector3(decomposedPosition[0], decomposedPosition[1], decomposedPosition[2]);
const auto& localScale = Vector3(decomposedScale[0], decomposedScale[1], decomposedScale[2]);
localTransform[0] /= localScale.x;
localTransform[1] /= localScale.y;
localTransform[2] /= localScale.z;
const auto& rotationMatrix = Matrix3(localTransform);
const Quat& localRotation = glm::normalize(Quat(rotationMatrix));
const Matrix4& rotationMatrix4 = glm::mat4_cast(localRotation);
const Matrix4& scaleMatrix = glm::scale(Matrix4(1.0f), localScale);
const Matrix4& translationMatrix = glm::translate(Matrix4(1.0f), localPosition);
const Matrix4& newLocalTransform = translationMatrix * rotationMatrix4 * scaleMatrix;
tc.Translation = localPosition;
if (CurrentOperation != ImGuizmo::SCALE)
{
tc.Rotation = localRotation;
}
tc.Scale = localScale;
tc.LocalTransform = newLocalTransform;
tc.Dirty = true;
}
}
}
if (!Engine::IsPlayMode() && !ImGuizmo::IsUsing() && ImGui::IsMouseClicked(ImGuiMouseButton_Left) && ImGui::GetIO().WantCaptureMouse && isHoveringViewport)
{
auto& sceneRenderer = VkRenderer::Get().SceneRenderers[sceneViewport->GetID()];
sceneRenderer->sceneRenderPipeline->MousePick(pixelPos, [&](uint32_t picked)
{
Logger::Log("Mouse Picked: " + std::to_string(picked));
constexpr uint32_t INVALID_PICK_ID = 3863365216;
if (picked != INVALID_PICK_ID)
{
Nuake::Entity entity = Nuake::Entity((entt::entity)picked, editorContext.GetScene().get());
if (entity.IsValid())
{
outlineSize.SetValue(0.0f);
outlineSize = 7.0f;
editorContext.SetSelection(entity);
}
}
else
{
outlineSize.SetValue(0.0f);
editorContext.SetSelection(EditorSelection());
}
});
}
}
else
{
ImGui::PopStyleVar();
}
ImGui::End();
}
void ViewportWidget::OnSceneChanged(Ref<Nuake::Scene> scene)
{
auto& vkRenderer = Nuake::VkRenderer::Get();
// Recreate new viewport with new scene with the same resolution
Vector2 currentResolution = Vector2{ 1, 1 };
if (sceneViewport)
{
currentResolution = sceneViewport->GetViewportSize();
// Remove old viewport
vkRenderer.RemoveViewport(sceneViewport->GetID());
}
// Create new viewport with same reoslution
const UUID viewId = editorContext.GetScene()->GetCurrentCamera()->ID;
auto viewport = vkRenderer.CreateViewport(viewId, currentResolution);
viewport->SetDebugName("ViewportWidget(" + scene->GetName() + ")");
vkRenderer.RegisterSceneViewport(scene, viewport->GetID());
sceneViewport = viewport;
sceneViewport->GetOnDebugDraw().AddRaw(this, &ViewportWidget::OnDebugDraw);
sceneViewport->GetOnLineDraw().AddRaw(this, &ViewportWidget::OnLineDraw);
}
float GetGizmoScale(const Vector3& camPosition, const Nuake::Vector3& position)
{
float distance = Distance(camPosition, position);
constexpr float ClosestDistance = 3.5f;
if (distance < ClosestDistance)
{
float fraction = distance / ClosestDistance;
return fraction;
}
return 1.0f;
}
template<typename T>
void DrawIconGizmo(DebugCmd& debugCmd, const std::string& icon, const EditorContext& context)
{
auto scene = debugCmd.GetScene();
auto cam = scene->GetCurrentCamera();
auto view = cam->GetTransform();
auto proj = cam->GetPerspective();
const Vector3& cameraPosition = cam->GetTranslation();
const Vector3 gizmoSize = Vector3(Engine::GetProject()->Settings.GizmoSize);
auto camView = scene->m_Registry.view<TransformComponent, T>();
for (auto e : camView)
{
auto [transform, cam] = scene->m_Registry.get<TransformComponent, T>(e);
auto selection = context.GetSelection();
bool isSelected = selection.Type == EditorSelectionType::Entity && selection.Entity.GetHandle() == (int)e;
Matrix4 initialTransform = transform.GetGlobalTransform();
Matrix4 gizmoTransform = initialTransform;
gizmoTransform = glm::inverse(scene->GetCurrentCamera()->GetTransform());
gizmoTransform[3] = initialTransform[3];
gizmoTransform = glm::scale(gizmoTransform, gizmoSize * GetGizmoScale(cameraPosition, initialTransform[3]));
debugCmd.DrawTexturedQuad(proj * view * gizmoTransform, TextureManager::Get()->GetTexture2(icon), isSelected ? Engine::GetProject()->Settings.PrimaryColor : Color(1, 1, 1, 1), (int32_t)e);
}
}
void ViewportWidget::OnLineDraw(DebugLineCmd& lineCmd)
{
GameState gamestate = Engine::GetGameState();
switch (gizmoDrawingMode)
{
case GizmoDrawingModes::EditorOnly:
{
if (gamestate == GameState::Playing)
{
return;
}
break;
}
case GizmoDrawingModes::None:
{
return;
}
}
auto scene = lineCmd.GetScene();
auto cam = scene->GetCurrentCamera();
const Vector3& cameraPosition = cam->GetTranslation();
auto view = cam->GetTransform();
auto proj = cam->GetPerspective();
auto camView = scene->m_Registry.view<TransformComponent, CameraComponent>();
for (auto e : camView)
{
auto [transform, camera] = scene->m_Registry.get<TransformComponent, CameraComponent>(e);
const Quat& globalRotation = glm::normalize(transform.GetGlobalRotation());
const Matrix4& rotationMatrix = glm::mat4_cast(globalRotation);
const float aspectRatio = camera.CameraInstance->AspectRatio;
const float fov = camera.CameraInstance->Fov;
Matrix4 clampedProj = glm::perspectiveFov(glm::radians(fov), 9.0f * aspectRatio, 9.0f, 0.05f, 3.0f);
Matrix4 boxTransform = glm::translate(scene->GetCurrentCamera()->GetTransform(), Vector3(transform.GetGlobalTransform()[3])) * rotationMatrix * glm::inverse(clampedProj);
lineCmd.DrawBox(proj * boxTransform, Color(1, 0, 0, 1.0f), 1.5f, false);
}
auto lightView = scene->m_Registry.view<TransformComponent, LightComponent>();
for (auto e : lightView)
{
auto [transformComp, lightComp] = scene->m_Registry.get<TransformComponent, LightComponent>(e);
const int32_t type = lightComp.Type;
const Quat& rotationOffset = QuatFromEuler(-90.0f, 0, 0);
const Quat& globalRotation = glm::normalize(transformComp.GetGlobalRotation()) * rotationOffset;
const Matrix4& rotationMatrix = glm::mat4_cast(globalRotation);
Matrix4 transform = Matrix4(1.0f);
transform = glm::translate(view, Vector3(transformComp.GetGlobalTransform()[3]));
transform = transform * rotationMatrix;
transform = glm::translate(transform, { 0, -1.0, 0.0 });
if (type == LightType::Spot)
{
const Quat& rotationOffset = QuatFromEuler(90.0f, 0, 0);
const Quat& globalRotation = glm::normalize(transformComp.GetGlobalRotation()) * rotationOffset;
const Matrix4& rotationMatrix = glm::mat4_cast(globalRotation);
Matrix4 transform = Matrix4(1.0f);
transform = glm::translate(view, Vector3(transformComp.GetGlobalTransform()[3]));
transform = transform * rotationMatrix;
float length = 1.0f;
float scaleDistance = glm::sqrt(lightComp.Strength);
length *= scaleDistance;
transform = glm::translate(transform, { 0, -length, 0.0 });
float radiusScale = (length) * glm::tan(Rad(lightComp.OuterCutoff)) / 0.25f;
Vector3 coneScale = Vector3(radiusScale, length, radiusScale);
transform = glm::scale(transform, coneScale);
lineCmd.DrawCone(proj * transform, Color{ lightComp.Color, 1.0f }, 1.5f, false);
}
else if (type == LightType::Directional)
{
const Quat& rotationOffset = QuatFromEuler(-90.0f, 0, 0);
const Quat& globalRotation = glm::normalize(transformComp.GetGlobalRotation()) * rotationOffset;
const Matrix4& rotationMatrix = glm::mat4_cast(globalRotation);
Matrix4 transform = Matrix4(1.0f);
transform = glm::translate(view, Vector3(transformComp.GetGlobalTransform()[3]));
transform = transform * rotationMatrix;
transform = glm::translate(transform, { 0, -1.0, 0.0 });
lineCmd.DrawCylinder(proj * transform, Color { lightComp.Color, 1.0f }, 1.5f, false);
}
}
auto boxColliderView = scene->m_Registry.view<TransformComponent, BoxColliderComponent>();
for (auto e : boxColliderView)
{
auto [transform, boxCollider] = scene->m_Registry.get<TransformComponent, BoxColliderComponent>(e);
Vector3 boxSize = boxCollider.GetSize();
Matrix4 boxTransform = Matrix4(1.0f);
boxTransform = glm::translate(boxTransform, Vector3(transform.GetGlobalTransform()[3]));
boxTransform = glm::scale(boxTransform, boxSize);
lineCmd.DrawBox(proj * view * boxTransform, Color(0, 1, 0, 1.0f), 1.5f, boxCollider.IsTrigger);
}
auto sphereColliderView = scene->m_Registry.view<TransformComponent, SphereColliderComponent>();
for (auto e : sphereColliderView)
{
auto [transformComponent, sphereCollider] = scene->m_Registry.get<TransformComponent, SphereColliderComponent>(e);
float radius = sphereCollider.GetRadius();
Matrix4 transform = Matrix4(1.0f);
transform = glm::translate(transform, Vector3(transformComponent.GetGlobalTransform()[3]));
transform = glm::scale(transform, Vector3(sphereCollider.GetRadius()));
lineCmd.DrawSphere(proj * view * transform, Color(1, 0, 0, 1.0f), 1.5f, true);
}
auto capsuleColliderView = scene->m_Registry.view<TransformComponent, CapsuleColliderComponent>();
for (auto e : capsuleColliderView)
{
auto [transformComponent, capsuleCollider] = scene->m_Registry.get<TransformComponent, CapsuleColliderComponent>(e);
Matrix4 transform = Matrix4(1.0f);
transform = glm::translate(transform, Vector3(transformComponent.GetGlobalTransform()[3]));
transform = glm::scale(transform, Vector3(capsuleCollider.Radius, capsuleCollider.Height, capsuleCollider.Radius));
lineCmd.DrawCapsule(proj * view * transform, Color(1, 0, 0, 1.0f), 1.5f, true);
}
auto cylinderColliderView = scene->m_Registry.view<TransformComponent, CylinderColliderComponent>();
for (auto e : cylinderColliderView)
{
auto [transformComponent, cylinderCollider] = scene->m_Registry.get<TransformComponent, CylinderColliderComponent>(e);
Matrix4 transform = Matrix4(1.0f);
transform = glm::translate(transform, Vector3(transformComponent.GetGlobalTransform()[3]));
transform = glm::scale(transform, Vector3(cylinderCollider.Radius, cylinderCollider.Height, cylinderCollider.Radius));
lineCmd.DrawCylinder(proj * view * transform, Color(1, 0, 0, 1.0f), 1.5f, true);
}
}
void ViewportWidget::OnDebugDraw(DebugCmd& debugCmd)
{
GameState gamestate = Engine::GetGameState();
switch (gizmoDrawingMode)
{
case GizmoDrawingModes::EditorOnly:
{
if (gamestate == GameState::Playing)
{
return;
}
break;
}
case GizmoDrawingModes::None:
{
return;
}
}
auto scene = debugCmd.GetScene();
auto cam = scene->GetCurrentCamera();
const Vector3& cameraPosition = cam->GetTranslation();
const Vector3 gizmoSize = Vector3(Engine::GetProject()->Settings.GizmoSize);
auto view = cam->GetTransform();
auto proj = cam->GetPerspective();
static auto drawGizmoIcon = [&](TransformComponent& transform, const std::string& icon, const Color& color, int32_t entityId)
{
Matrix4 initialTransform = transform.GetGlobalTransform();
Matrix4 gizmoTransform = initialTransform;
gizmoTransform = glm::inverse(scene->GetCurrentCamera()->GetTransform());
gizmoTransform[3] = initialTransform[3];
gizmoTransform = glm::scale(gizmoTransform, gizmoSize * GetGizmoScale(cameraPosition, initialTransform[3]));
debugCmd.DrawTexturedQuad(proj * view * gizmoTransform, TextureManager::Get()->GetTexture2(icon), color, entityId);
};
auto lightView = scene->m_Registry.view<TransformComponent, LightComponent>();
for (auto e : lightView)
{
auto [transform, light] = scene->m_Registry.get<TransformComponent, LightComponent>(e);
const auto& selection = editorContext.GetSelection();
bool isSelected = selection.Type == EditorSelectionType::Entity && selection.Entity.GetHandle() == (int)e;
std::string texturePath = "Resources/Gizmos/";
switch (light.Type)
{
case LightType::Point:
texturePath += "light.png";
break;
case LightType::Directional:
texturePath += "light_directional.png";
break;
case LightType::Spot:
texturePath += "light_spot.png";
break;
default:
texturePath += "light.png";
}
// Billboard + scaling logic
drawGizmoIcon(transform, texturePath, isSelected ? Engine::GetProject()->Settings.PrimaryColor : Color(1, 1, 1, 1), (int32_t)e);
}
DrawIconGizmo<CameraComponent>(debugCmd, "Resources/Gizmos/Camera.png", editorContext);
DrawIconGizmo<CharacterControllerComponent>(debugCmd, "Resources/Gizmos/player.png", editorContext);
DrawIconGizmo<BoneComponent>(debugCmd, "Resources/Gizmos/bone.png", editorContext);
DrawIconGizmo<AudioEmitterComponent>(debugCmd, "Resources/Gizmos/sound_emitter.png", editorContext);
DrawIconGizmo<RigidBodyComponent>(debugCmd, "Resources/Gizmos/rigidbody.png", editorContext);
DrawIconGizmo<ParticleEmitterComponent>(debugCmd, "Resources/Gizmos/particles.png", editorContext);
}
void ViewportWidget::DrawOverlay()
{
ImGuiIO& io = ImGui::GetIO();
const float DISTANCE = 10.0f;
int corner = 0;
ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoNav;
window_flags |= ImGuiWindowFlags_NoMove;
ImGuiViewport* viewport = ImGui::GetWindowViewport();
float title_bar_height = ImGui::GetFontSize() + ImGui::GetStyle().FramePadding.y * 2;
ImVec2 work_area_pos = ImGui::GetCurrentWindow()->Pos + ImVec2(0, title_bar_height); // Instead of using viewport->Pos we use GetWorkPos() to avoid menu bars, if any!
ImVec2 work_area_size = ImGui::GetCurrentWindow()->Size;
ImVec2 window_pos = ImVec2((corner & 1) ? (work_area_pos.x + work_area_size.x - DISTANCE) : (work_area_pos.x + DISTANCE), (corner & 2) ? (work_area_pos.y + work_area_size.y - DISTANCE) : (work_area_pos.y + DISTANCE));
ImVec2 window_pos_pivot = ImVec2((corner & 1) ? 1.0f : 0.0f, (corner & 2) ? 1.0f : 0.0f);
ImGui::SetNextWindowPos(window_pos, ImGuiCond_Always, window_pos_pivot);
ImGui::SetNextWindowViewport(viewport->ID);
ImGui::SetNextWindowBgAlpha(0.35f * overlayOpacity); // Transparent background
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 32.0f);
bool showOverlay = true;
if (ImGui::Begin("ActionBar", &showOverlay, window_flags))
{
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(2, 2));
ImGui::PushStyleColor(ImGuiCol_Button, IM_COL32(0, 0, 0, 0));
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 100);
bool selectedMode = CurrentOperation == ImGuizmo::OPERATION::TRANSLATE;
if (selectedMode)
{
Color color = Engine::GetProject()->Settings.PrimaryColor;
ImGui::PushStyleColor(ImGuiCol_Button, { color.r, color.g, color.b, 1.0 });
}
if (ImGui::Button(ICON_FA_ARROWS_ALT, ImVec2(30, 28)) || (ImGui::Shortcut(ImGuiKey_W, 0, ImGuiInputFlags_RouteGlobalLow) && !ImGui::IsAnyItemActive() && !IsControllingCamera))
{
CurrentOperation = ImGuizmo::OPERATION::TRANSLATE;
}
UI::Tooltip("Translate");
if (selectedMode)
{
ImGui::PopStyleColor();
}
ImGui::SameLine();
selectedMode = CurrentOperation == ImGuizmo::OPERATION::ROTATE;
if (selectedMode)
{
Color color = Engine::GetProject()->Settings.PrimaryColor;
ImGui::PushStyleColor(ImGuiCol_Button, { color.r, color.g, color.b, 1.0f });
}
if (ImGui::Button(ICON_FA_SYNC_ALT, ImVec2(30, 28)) || (ImGui::Shortcut(ImGuiKey_E, 0, ImGuiInputFlags_RouteGlobalLow) && !ImGui::IsAnyItemActive() && !IsControllingCamera))
{
CurrentOperation = ImGuizmo::OPERATION::ROTATE;
}
UI::Tooltip("Rotate");
if (selectedMode)
{
ImGui::PopStyleColor();
}
ImGui::SameLine();
selectedMode = CurrentOperation == ImGuizmo::OPERATION::SCALE;
if (selectedMode)
{
Color color = Engine::GetProject()->Settings.PrimaryColor;
ImGui::PushStyleColor(ImGuiCol_Button, { color.r, color.g, color.b, 1 });
}
if (ImGui::Button(ICON_FA_EXPAND_ALT, ImVec2(30, 28)) || (ImGui::Shortcut(ImGuiKey_R, 0, ImGuiInputFlags_RouteGlobalLow) && !ImGui::IsAnyItemActive() && !IsControllingCamera))
{
CurrentOperation = ImGuizmo::OPERATION::SCALE;
}
UI::Tooltip("Scale");
if (selectedMode)
{
ImGui::PopStyleColor();
}
ImGui::SameLine();
selectedMode = CurrentMode == ImGuizmo::MODE::WORLD;
if (selectedMode)
{
Color color = Engine::GetProject()->Settings.PrimaryColor;
ImGui::PushStyleColor(ImGuiCol_Button, { color.r, color.g, color.b, 1 });
}
if (ImGui::Button(ICON_FA_GLOBE, ImVec2(30, 28)))
{
CurrentMode = ImGuizmo::MODE::WORLD;
}
UI::Tooltip("Global Transformation");
if (selectedMode)
{
ImGui::PopStyleColor();
}
ImGui::SameLine();
selectedMode = CurrentMode == ImGuizmo::MODE::LOCAL;
if (selectedMode)
{
Color color = Engine::GetProject()->Settings.PrimaryColor;
ImGui::PushStyleColor(ImGuiCol_Button, { color.r, color.g, color.b, 1 });
}
if (ImGui::Button(ICON_FA_CUBE, ImVec2(30, 28)))
{
CurrentMode = ImGuizmo::MODE::LOCAL;
}
UI::Tooltip("Local Transformation");
if (selectedMode)
{
ImGui::PopStyleColor();
}
ImGui::SameLine();
ImGui::SameLine();
ImGui::PushItemWidth(75);
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, { 6, 6 });
ImGui::DragFloat("##snapping", &CurrentSnapping.x, 0.01f, 0.0f, 100.0f);
CurrentSnapping = { CurrentSnapping.x, CurrentSnapping.x, CurrentSnapping.x };
ImGui::PopStyleVar();
ImGui::PopItemWidth();
UI::Tooltip("Snapping");
ImGui::PopStyleVar();
ImGui::PopStyleVar();
ImGui::PopStyleColor();
}
ImGui::PopStyleVar();
ImGui::End();
corner = 1;
window_flags |= ImGuiWindowFlags_NoMove;
viewport = ImGui::GetWindowViewport();
work_area_pos = ImGui::GetCurrentWindow()->Pos; // Instead of using viewport->Pos we use GetWorkPos() to avoid menu bars, if any!
work_area_size = ImGui::GetCurrentWindow()->Size;
window_pos = ImVec2((corner & 1) ? (work_area_pos.x + work_area_size.x - DISTANCE) : (work_area_pos.x + DISTANCE), (corner & 2) ? (work_area_pos.y + work_area_size.y - DISTANCE) : (work_area_pos.y + DISTANCE));
window_pos_pivot = ImVec2((corner & 1) ? 1.0f : 0.0f, (corner & 2) ? 1.0f : 0.0f);
ImGui::SetNextWindowPos(window_pos, ImGuiCond_Always, window_pos_pivot);
ImGui::SetNextWindowViewport(viewport->ID);
int corner2 = 1;
work_area_pos = ImGui::GetCurrentWindow()->Pos; // Instead of using viewport->Pos we use GetWorkPos() to avoid menu bars, if any!
work_area_size = ImGui::GetCurrentWindow()->Size;
window_pos = ImVec2((corner2 & 1) ? (work_area_pos.x + work_area_size.x - DISTANCE) : (work_area_pos.x + DISTANCE), (corner2 & 2) ? (work_area_pos.y + work_area_size.y - DISTANCE) : (work_area_pos.y + DISTANCE));
window_pos_pivot = ImVec2((corner2 & 1) ? 1.0f : 0.0f, (corner2 & 2) ? 1.0f : 0.0f);
ImGui::SetNextWindowPos(window_pos + ImVec2(0, 40), ImGuiCond_Always, window_pos_pivot);
ImGui::SetNextWindowViewport(viewport->ID);
ImGui::SetNextWindowBgAlpha(0.35f); // Transparent background
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 32.0f);
ImGui::SetNextWindowSize(ImVec2(16, ImGui::GetContentRegionAvail().y - DISTANCE * 2.0 - 40.0));
if (IsControllingCamera)
{
if (ImGui::Begin("Controls", &showOverlay, window_flags))
{
const auto& editorCam = Engine::GetCurrentScene()->m_EditorCamera;
const float camSpeed = editorCam->Speed;
const float maxSpeed = 50.0f;
const float minSpeed = 0.05f;
const float normalizedSpeed = glm::clamp((camSpeed / maxSpeed), 0.0f, 1.0f);
ImVec2 start = ImGui::GetWindowPos() - ImVec2(0.0, 4.0);
ImVec2 end = start + ImGui::GetWindowSize() - ImVec2(0, 16.0);
ImVec2 startOffset = ImVec2(start.x, end.y - (normalizedSpeed * (ImGui::GetWindowHeight() - 20.0)));
ImGui::GetWindowDrawList()->AddRectFilled(startOffset + ImVec2(0, 10.0), end + ImVec2(0.0, 20.0), IM_COL32(255, 255, 255, 180 * overlayOpacity), 8.0f, ImDrawFlags_RoundCornersAll);
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 100);
ImGui::PopStyleVar();
}
ImGui::End();
}
ImGui::PopStyleVar();
}

View File

@@ -1,61 +0,0 @@
#pragma once
#include "IEditorWidget.h"
#include <imgui/ImGuizmo.h>
#include "../../../misc/AnimatedValue.h"
class EditorContext;
namespace Nuake
{
class Viewport;
class DebugCmd;
class DebugLineCmd;
}
class ViewportWidget : public IEditorWidget
{
private:
enum class GizmoDrawingModes : char16_t
{
EditorOnly,
Always,
None
};
private:
Ref<Nuake::Viewport> sceneViewport;
AnimatedValue<float> outlineSize;
AnimatedValue<float> overlayOpacity;
// Gizmo
GizmoDrawingModes gizmoDrawingMode;
ImGuizmo::OPERATION CurrentOperation = ImGuizmo::TRANSLATE;
ImGuizmo::MODE CurrentMode = ImGuizmo::WORLD;
bool UseSnapping = true;
Nuake::Vector3 CurrentSnapping = { 0.05f, 0.05f, 0.05f };
bool IsControllingCamera = false;
bool isHoveringViewport;
public:
ViewportWidget(EditorContext& context);
~ViewportWidget();
public:
void Update(float ts) override;
void Draw() override;
void OnSceneChanged(Ref<Nuake::Scene> scene) override;
void OnVisible() override;
void OnHidden() override;
void OnLineDraw(Nuake::DebugLineCmd& lineCmd);
void OnDebugDraw(Nuake::DebugCmd& debugCmd);
private:
void DrawOverlay();
};

Binary file not shown.

View File

@@ -1,129 +0,0 @@
include "Nuake/Source/Nuake/Modules/Modules.lua"
project "Editor"
targetname ("Nuake Engine")
kind "ConsoleApp"
language "C++"
cppdialect "C++20"
staticruntime "On"
dependson { "NuakeNet" }
targetdir (binaryOutputDir)
objdir (intBinaryOutputDir)
debugdir (binaryOutputDir)
defines
{
table.unpack(globalDefines)
}
files
{
"Source/**.cpp",
"Source/**.h",
-- This isn't ideal, but it works...needs a proper way of doing this, but that's for another time
"Nuake/Thirdparty/entt/natvis/entt/*.natvis"
}
includedirs
{
"../Nuake/Source",
"../Nuake/Vendors/pugixml",
"../Nuake/Vendors",
"../Nuake/Vendors/volk",
"../Nuake/Vendors/vulkan",
"../Nuake/Thirdparty/build",
"../Nuake/Thirdparty/yoga",
"../Nuake/Thirdparty/Coral/Coral.Native/Include/",
"../Nuake/Thirdparty/entt/src",
"../Nuake/Thirdparty/JoltPhysics",
"../Nuake/Thirdparty/recastnavigation/DebugUtils/Include",
"../Nuake/Thirdparty/recastnavigation/Detour/Include",
"../Nuake/Thirdparty/recastnavigation/DetourTileCache/Include",
"../Nuake/Thirdparty/vma/include",
"../Nuake/Thirdparty/msdf-atlas-gen",
"../Nuake/Thirdparty/msdf-atlas-gen/msdfgen",
"../Nuake/Thirdparty/msdf-atlas-gen/msdfgen/include",
"../Nuake/Thirdparty/yoga",
}
externalincludedirs
{
}
links
{
"Nuake",
"glad",
"GLFW",
"assimp",
"JoltPhysics",
"soloud",
"Coral.Native",
"DebugUtils",
"Detour",
"DetourCrowd",
"DetourTileCache",
"Recast",
"tracy",
"yoga",
"msdf-gen",
"msdf-atlas-gen",
"Freetype",
"vma"
}
libdirs
{
"%{cfg.debugdir}/",
}
local libCopyCmds = {}
local modules = {}
if _ACTION then
modules = loadModules("../Nuake/Source/Nuake/Modules")
print(#modules)
for _, m in ipairs(modules) do
print("m")
end
local libTargetDir = "%{cfg.debugdir}/"
local commands = getModuleLibCopy(modules, libTargetDir)
for _, command in ipairs(commands) do
table.insert(libCopyCmds, command)
print(command)
end
end
prebuildcommands {
'{ECHO} "Copying dxcompiler.dll to Working directory..."',
'{COPYFILE} "%{wks.location}Nuake/Thirdparty/dxc/bin/x64/dxcompiler.dll" "%{cfg.debugdir}/"',
'{ECHO} Copying Coral to Working directory...',
'{COPYFILE} "%{wks.location}Nuake/Thirdparty/Coral/Coral.Managed/bin/%{cfg.buildcfg}/Coral.Managed.dll" "%{cfg.debugdir}/"',
'{COPYFILE} "%{wks.location}Nuake/Thirdparty/Coral/Coral.Managed/bin/%{cfg.buildcfg}/Coral.Managed.runtimeconfig.json" "%{cfg.debugdir}/"',
'{COPYFILE} "%{wks.location}NuakeNet/Build/%{cfg.buildcfg}/Binaries/NuakeNet.dll" "%{cfg.debugdir}/"',
'xcopy /E /I /Y "%{wks.location}Data" "%{cfg.debugdir}\\Resources"',
table.unpack(libCopyCmds)
}
filter { "system:windows", "action:vs*"}
flags
{
"MultiProcessorCompile",
}
filter "configurations:Debug"
runtime "Debug"
symbols "on"
buildoptions { "/Zi" }
filter "configurations:Release"
runtime "Release"
optimize "on"

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

@@ -1,8 +1,8 @@
#pragma once
#include "Nuake/Core/Core.h"
#include "Nuake/Scene/Entities/Entity.h"
#include "Nuake/Rendering/SceneRenderer.h"
#include "Nuake/Resource/Resource.h"
#include "src/Core/Core.h"
#include "src/Scene/Entities/Entity.h"
#include "src/Rendering/SceneRenderer.h"
#include "src/Resource/Resource.h"
#include "Engine.h"

View File

@@ -1,8 +1,8 @@
#include "Commands.h"
#include "Engine.h"
#include <Engine.h>
#include "Nuake/FileSystem/FileSystem.h"
#include "src/FileSystem/FileSystem.h"
#include <filesystem>

View File

@@ -2,9 +2,9 @@
#include "../ICommand.h"
#include <Nuake/Core/Core.h>
#include <Nuake/Scene/Scene.h>
#include <Nuake/Resource/Project.h>
#include <src/Core/Core.h>
#include <src/Scene/Scene.h>
#include <src/Resource/Project.h>
#include <Engine.h>
namespace NuakeEditor {

View File

@@ -1,10 +1,10 @@
#pragma once
#include "ComponentPanel.h"
#include "Nuake/FileSystem/FileSystem.h"
#include <Nuake/Core/Maths.h>
#include <Nuake/Scene/Components/BoneComponent.h>
#include <Nuake/Scene/Entities/ImGuiHelper.h>
#include "src/FileSystem/FileSystem.h"
#include <src/Core/Maths.h>
#include <src/Scene/Components/BoneComponent.h>
#include <src/Scene/Entities/ImGuiHelper.h>
class BonePanel
{

View File

@@ -1,10 +1,10 @@
#pragma once
#include "ComponentPanel.h"
#include "Nuake/FileSystem/FileSystem.h"
#include <Nuake/Core/Maths.h>
#include <Nuake/Scene/Components/BoxCollider.h>
#include <Nuake/Scene/Entities/ImGuiHelper.h>
#include "src/FileSystem/FileSystem.h"
#include <src/Core/Maths.h>
#include <src/Scene/Components/BoxCollider.h>
#include <src/Scene/Entities/ImGuiHelper.h>
class BoxColliderPanel : ComponentPanel
{

View File

@@ -0,0 +1,51 @@
#pragma once
#include "ComponentPanel.h"
#include <src/Scene/Components/CameraComponent.h>
#include "src/FileSystem/FileSystem.h"
class CameraPanel {
public:
static void Draw(Nuake::Entity& entity, entt::meta_any& componentInstance)
{
using namespace Nuake;
Nuake::CameraComponent* componentPtr = componentInstance.try_cast<Nuake::CameraComponent>();
if (componentPtr == nullptr)
{
return;
}
Nuake::CameraComponent& component = *componentPtr;
BeginComponentTable(CAMERA, Nuake::CameraComponent);
{
{
ImGui::Text("FOV");
ImGui::TableNextColumn();
ImGui::DragFloat("##Fov", &component.CameraInstance->Fov, 0.1f, 0.1f, 360.0f);
ImGui::TableNextColumn();
ComponentTableReset(component.CameraInstance->Fov, 88.0f);
}
ImGui::TableNextColumn();
{
ImGui::Text("Exposure");
ImGui::TableNextColumn();
ImGui::DragFloat("##Exposure", &component.CameraInstance->Exposure, 0.1f, 0.1f, 10.0f);
ImGui::TableNextColumn();
ComponentTableReset(component.CameraInstance->Fov, 1.0f);
}
ImGui::TableNextColumn();
{
ImGui::Text("Gamma");
ImGui::TableNextColumn();
ImGui::DragFloat("##Gamma", &component.CameraInstance->Gamma, 0.1f, 0.1f, 10.0f);
ImGui::TableNextColumn();
ComponentTableReset(component.CameraInstance->Fov, 2.2f);
}
}
EndComponentTable();
}
};

View File

@@ -1,7 +1,7 @@
#pragma once
#include "ComponentPanel.h"
#include <Nuake/Scene/Components/CapsuleColliderComponent.h>
#include <src/Scene/Components/CapsuleColliderComponent.h>
class CapsuleColliderPanel
{

View File

@@ -1,7 +1,7 @@
#pragma once
#include "ComponentPanel.h"
#include <Nuake/Scene/Components/CharacterControllerComponent.h>
#include "Nuake/FileSystem/FileSystem.h"
#include <src/Scene/Components/CharacterControllerComponent.h>
#include "src/FileSystem/FileSystem.h"
class CharacterControllerPanel
{

View File

@@ -1,11 +1,11 @@
#pragma once
#include "Nuake/Scene/Entities/Entity.h"
#include "src/Scene/Entities/Entity.h"
#include "../Misc/InterfaceFonts.h"
#include "Nuake/UI/ImUI.h"
#include <imgui/imgui.h>
#include <Nuake/Resource/FontAwesome5.h>
#include "src/UI/ImUI.h"
#include <src/Vendors/imgui/imgui.h>
#include <src/Resource/FontAwesome5.h>
#define MenuItemComponent(label, Component) \

View File

@@ -1,7 +1,7 @@
#pragma once
#include "ComponentPanel.h"
#include <Nuake/Scene/Components/CylinderColliderComponent.h>
#include <src/Scene/Components/CylinderColliderComponent.h>
class CylinderColliderPanel
{

View File

@@ -1,6 +1,6 @@
#pragma once
#include "ComponentPanel.h"
#include "Nuake/Scene/Components/LightComponent.h"
#include "src/Scene/Components/LightComponent.h"
class LightPanel
{
@@ -58,23 +58,7 @@ public:
ImGui::TableNextColumn();
const char* lightTypes[] = { "Directional", "Point", "Spot" };
const char* current_item = lightTypes[(int)component.Type]; \
if (ImGui::BeginCombo("Type", current_item)) \
{ \
for (int n = 0; n < IM_ARRAYSIZE(lightTypes); n++) \
{ \
bool is_selected = (current_item == lightTypes[n]); \
if (ImGui::Selectable(lightTypes[n], is_selected)) \
{ \
current_item = lightTypes[n]; \
component.Type = (Nuake::LightType)n; \
} \
if (is_selected) \
ImGui::SetItemDefaultFocus(); \
} \
ImGui::EndCombo(); \
}
//ComponentDropDown(lightTypes, Nuake::LightType, component.Type)
ComponentDropDown(lightTypes, Nuake::LightType, component.Type)
ImGui::TableNextColumn();
ComponentTableReset(component.Type, Nuake::LightType::Point);

View File

@@ -0,0 +1,253 @@
#include "MaterialEditor.h"
#include "../Misc/InterfaceFonts.h"
#include <src/Resource/FontAwesome5.h>
#include <src/Resource/ResourceManager.h>
#include <src/FileSystem/FileDialog.h>
#include <imgui/imgui.h>
#include <src/Vendors/imgui/imgui_internal.h>
void MaterialEditor::Draw(Ref<Nuake::Material> material)
{
using namespace Nuake;
std::string materialTitle = material->Path;
{
UIFont boldfont = UIFont(Fonts::SubTitle);
ImGui::Text(material->Path.c_str());
}
ImGui::SameLine();
{
UIFont boldfont = UIFont(Fonts::Icons);
if (ImGui::Button(ICON_FA_SAVE))
{
if (ResourceManager::IsResourceLoaded(material->ID))
{
ResourceManager::RegisterResource(material);
}
std::string fileData = material->Serialize().dump(4);
FileSystem::BeginWriteFile(material->Path);
FileSystem::WriteLine(fileData);
FileSystem::EndWriteFile();
}
}
bool flagsHeaderOpened;
{
UIFont boldfont = UIFont(Fonts::Bold);
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.f, 0.f));
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0.f, 8.f));
flagsHeaderOpened = ImGui::CollapsingHeader(" FLAGS", ImGuiTreeNodeFlags_DefaultOpen);
ImGui::PopStyleVar(2);
}
if (flagsHeaderOpened)
{
ImGui::BeginTable("##Flags", 3, ImGuiTableFlags_BordersInner | ImGuiTableFlags_SizingStretchProp);
{
ImGui::TableSetupColumn("name", 0, 0.3f);
ImGui::TableSetupColumn("set", 0, 0.6f);
ImGui::TableSetupColumn("reset", 0, 0.1f);
ImGui::TableNextColumn();
ImGui::Text("Unlit");
ImGui::TableNextColumn();
bool unlit = material->data.u_Unlit == 1;
ImGui::Checkbox("Unlit", &unlit);
material->data.u_Unlit = (int)unlit;
ImGui::TableNextColumn();
ImGui::TableNextColumn();
ImGui::Text("Emissive");
ImGui::TableNextColumn();
ImGui::DragFloat("##Emissiveness", &material->data.u_Emissive, 0.1f, 1.0f);
ImGui::TableNextColumn();
}
ImGui::EndTable();
}
const auto TexturePanelHeight = 100;
const ImVec2 TexturePanelSize = ImVec2(0, TexturePanelHeight);
bool AlbedoOpened;
{
UIFont boldfont = UIFont(Fonts::Bold);
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.f, 0.f));
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0.f, 8.f));
AlbedoOpened = ImGui::CollapsingHeader(" ALBEDO", ImGuiTreeNodeFlags_DefaultOpen);
ImGui::PopStyleVar(2);
}
if (AlbedoOpened)
{
ImGui::BeginChild("##albedo", TexturePanelSize, true);
{
uint32_t textureID = 0;
if (material->HasAlbedo())
{
textureID = material->m_Albedo->GetID();
}
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 != "")
{
material->SetAlbedo(TextureManager::Get()->GetTexture(texture));
}
}
if (ImGui::BeginPopupContextWindow())
{
if (ImGui::MenuItem("Clear Texture"))
{
material->m_Albedo = nullptr;
}
ImGui::EndPopup();
}
ImGui::SameLine();
ImGui::ColorEdit3("Color", &material->data.m_AlbedoColor.r);
}
ImGui::EndChild();
}
if (ImGui::CollapsingHeader("Normal", ImGuiTreeNodeFlags_DefaultOpen))
{
ImGui::BeginChild("##normal", TexturePanelSize, true);
{
uint32_t textureID = 0;
if (material->HasNormal())
{
textureID = material->m_Normal->GetID();
}
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 != "")
{
material->SetNormal(TextureManager::Get()->GetTexture(texture));
}
}
if (ImGui::BeginPopupContextWindow())
{
if (ImGui::MenuItem("Clear Texture"))
{
material->m_Normal = nullptr;
}
ImGui::EndPopup();
}
}
ImGui::EndChild();
}
if (ImGui::CollapsingHeader("AO", ImGuiTreeNodeFlags_DefaultOpen))
{
ImGui::BeginChild("##ao", TexturePanelSize, true);
{
uint32_t textureID = 0;
if (material->HasAO())
{
textureID = material->m_AO->GetID();
}
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 != "")
{
material->SetAO(TextureManager::Get()->GetTexture(texture));
}
}
if (ImGui::BeginPopupContextWindow())
{
if (ImGui::MenuItem("Clear Texture"))
{
material->m_AO = nullptr;
}
ImGui::EndPopup();
}
ImGui::SameLine();
ImGui::DragFloat("Value##7", &material->data.u_AOValue, 0.01f, 0.0f, 1.0f);
}
ImGui::EndChild();
}
if (ImGui::CollapsingHeader("Metalness", ImGuiTreeNodeFlags_DefaultOpen))
{
ImGui::BeginChild("##metalness", TexturePanelSize, true);
{
uint32_t textureID = 0;
if (material->HasMetalness())
{
textureID = material->m_Metalness->GetID();
}
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 != "")
{
material->SetMetalness(TextureManager::Get()->GetTexture(texture));
}
}
if (ImGui::BeginPopupContextWindow())
{
if (ImGui::MenuItem("Clear Texture"))
{
material->m_Metalness = nullptr;
}
ImGui::EndPopup();
}
ImGui::SameLine();
ImGui::DragFloat("Value##4", &material->data.u_MetalnessValue, 0.01f, 0.0f, 1.0f);
}
ImGui::EndChild();
}
if (ImGui::CollapsingHeader("Roughness", ImGuiTreeNodeFlags_DefaultOpen))
{
ImGui::BeginChild("##roughness", TexturePanelSize, true);
{
uint32_t textureID = 0;
if (material->HasRoughness())
{
textureID = material->m_Roughness->GetID();
}
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 != "")
{
material->SetRoughness(TextureManager::Get()->GetTexture(texture));
}
}
if (ImGui::BeginPopupContextWindow())
{
if (ImGui::MenuItem("Clear Texture"))
{
material->m_Roughness = nullptr;
}
ImGui::EndPopup();
}
ImGui::SameLine();
ImGui::DragFloat("Value##6", &material->data.u_RoughnessValue, 0.01f, 0.0f, 1.0f);
}
ImGui::EndChild();
}
}

View File

@@ -0,0 +1,12 @@
#pragma once
#include <src/Core/Core.h>
#include <src/Rendering/Textures/Material.h>
class MaterialEditor
{
public:
MaterialEditor() = default;
~MaterialEditor() = default;
void Draw(Ref<Nuake::Material> material);
};

View File

@@ -1,13 +1,13 @@
#pragma once
#include <Nuake/Core/Core.h>
#include <src/Core/Core.h>
#include "ComponentPanel.h"
#include "ModelResourceInspector.h"
#include <Nuake/Scene/Entities/ImGuiHelper.h>
#include <Nuake/Scene/Components/MeshCollider.h>
#include <src/Scene/Entities/ImGuiHelper.h>
#include <src/Scene/Components/MeshCollider.h>
#include <Nuake/Resource/ResourceLoader.h>
#include <Nuake/Core/String.h>
#include <src/Resource/ResourceLoader.h>
#include <src/Core/String.h>
class MeshColliderPanel : ComponentPanel
{

View File

@@ -0,0 +1,130 @@
#pragma once
#include <src/Core/Core.h>
#include "ComponentPanel.h"
#include "ModelResourceInspector.h"
#include "../Misc/PopupHelper.h"
#include <src/Scene/Entities/ImGuiHelper.h>
#include <src/Scene/Components/ModelComponent.h>
#include <src/Resource/ResourceLoader.h>
#include <src/Resource/ResourceManager.h>
#include <src/Core/String.h>
#include <src/Resource/ModelLoader.h>
class MeshPanel : ComponentPanel
{
private:
Scope<ModelResourceInspector> _modelInspector;
bool _expanded = false;
std::string _importedPathMesh;
public:
MeshPanel()
{
CreateScope<ModelResourceInspector>();
}
void Draw(Nuake::Entity& entity, entt::meta_any& componentInstance)
{
using namespace Nuake;
Nuake::ModelComponent* componentPtr = componentInstance.try_cast<Nuake::ModelComponent>();
if (componentPtr == nullptr)
{
return;
}
Nuake::ModelComponent& component = *componentPtr;
BeginComponentTable(MESH, ModelComponent);
{
ImGui::Text("Model");
ImGui::TableNextColumn();
std::string label = "None";
const bool isModelNone = component.ModelResource == nullptr;
if (!isModelNone)
{
label = std::to_string(component.ModelResource->ID);
}
if (ImGui::Button(label.c_str(), ImVec2(ImGui::GetContentRegionAvail().x, 0)))
{
if (!isModelNone)
{
if (!_expanded)
{
_modelInspector = CreateScope<ModelResourceInspector>(component.ModelResource);
}
_expanded = !_expanded;
}
}
if (_expanded)
{
_modelInspector->Draw();
}
bool shouldConvert = false;
if (ImGui::BeginDragDropTarget())
{
if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("_Model"))
{
char* file = (char*)payload->Data;
std::string fullPath = std::string(file, 256);
fullPath = Nuake::FileSystem::AbsoluteToRelative(fullPath);
if (Nuake::String::EndsWith(fullPath, ".mesh"))
{
component.ModelPath = fullPath;
component.ModelResource = ResourceLoader::LoadModel(fullPath);
}
else
{
// Convert to .Model
component.ModelPath = fullPath;
component.LoadModel();
_importedPathMesh = fullPath;
auto loader = ModelLoader();
auto modelResource = loader.LoadModel(fullPath);
shouldConvert = true;
}
}
ImGui::EndDragDropTarget();
}
if (PopupHelper::DefineConfirmationDialog("##ConvertAsset", "Convert Asset"))
{
// Convert to disk
auto loader = ModelLoader();
Ref<Model> modelResource = loader.LoadModel(_importedPathMesh);
json serializedData = modelResource->SerializeData();
const std::string exportedMeshPath = _importedPathMesh + ".mesh";
FileSystem::BeginWriteFile(exportedMeshPath);
FileSystem::WriteLine(serializedData.dump());
FileSystem::EndWriteFile();
ResourceManager::RegisterResource(modelResource);
// Update component
component.ModelPath = exportedMeshPath;
component.ModelResource = modelResource;
}
if (shouldConvert)
{
PopupHelper::OpenPopup("##ConvertAsset");
}
ImGui::TableNextColumn();
ComponentTableReset(component.ModelPath, "");
}
EndComponentTable();
}
};

View File

@@ -5,7 +5,6 @@
ModelResourceInspector::ModelResourceInspector(Ref<Nuake::Model> model)
{
_model = model;
}
void ModelResourceInspector::Draw()
@@ -20,7 +19,7 @@ void ModelResourceInspector::Draw()
std::string childId = "materialEditor" + std::to_string(i);
ImGui::BeginChild(childId.c_str(), ImVec2(0, 0), false);
{
static MaterialEditor editor;
MaterialEditor editor;
editor.Draw(_model->GetMeshes().at(i)->GetMaterial());
}
ImGui::EndChild();

View File

@@ -1,6 +1,6 @@
#pragma once
#include <Nuake/Core/Core.h>
#include <Nuake/Resource/Model.h>
#include <src/Core/Core.h>
#include <src/Resource/Model.h>
class ModelResourceInspector
{

View File

@@ -1,12 +1,12 @@
#pragma once
#include "ComponentPanel.h"
#include <Nuake/Scene/Entities/ImGuiHelper.h>
#include <Nuake/Scene/Components/NavMeshVolumeComponent.h>
#include "Nuake/AI/NavManager.h"
#include "Nuake/Scene/Components/QuakeMap.h"
#include <Nuake/Core/Maths.h>
#include <Nuake/AI/RecastConfig.h>
#include <src/Scene/Entities/ImGuiHelper.h>
#include <src/Scene/Components/NavMeshVolumeComponent.h>
#include "src/AI/NavManager.h"
#include "src/Scene/Components/QuakeMap.h"
#include <src/Core/Maths.h>
#include <src/AI/RecastConfig.h>
class NavMeshVolumePanel
{
@@ -363,7 +363,7 @@ public:
auto& transformComponent = brush.GetComponent<TransformComponent>();
auto& modelComponent = brush.GetComponent<ModelComponent>();
for (auto& mesh : modelComponent.ModelResource.Get<Model>()->GetMeshes())
for (auto& mesh : modelComponent.ModelResource->GetMeshes())
{
Nuake::NavManager::Get().PushMesh(mesh, transformComponent.GetGlobalTransform());
}

View File

@@ -2,11 +2,11 @@
#include "../Windows/FileSystemUI.h"
#include <Nuake/FileSystem/FileDialog.h>
#include "Nuake/FileSystem/FileSystem.h"
#include <Nuake/Scripting/ScriptingEngineNet.h>
#include <Nuake/Scene/Components/NetScriptComponent.h>
#include <Nuake/Scene/Entities/ImGuiHelper.h>
#include <src/FileSystem/FileDialog.h>
#include "src/FileSystem/FileSystem.h"
#include <src/Scripting/ScriptingEngineNet.h>
#include <src/Scene/Components/NetScriptComponent.h>
#include <src/Scene/Entities/ImGuiHelper.h>
const std::string NET_TEMPLATE_SCRIPT_FIRST = R"(using Nuake.Net;

View File

@@ -1,17 +1,17 @@
#pragma once
#include <Nuake/Core/Core.h>
#include <src/Core/Core.h>
#include "ComponentPanel.h"
#include "ModelResourceInspector.h"
#include "../Misc/PopupHelper.h"
#include <Nuake/Scene/Entities/ImGuiHelper.h>
#include <Nuake/Scene/Components/SkinnedModelComponent.h>
#include <src/Scene/Entities/ImGuiHelper.h>
#include <src/Scene/Components/SkinnedModelComponent.h>
#include <Nuake/Resource/ResourceLoader.h>
#include <Nuake/Resource/ResourceManager.h>
#include <src/Resource/ResourceLoader.h>
#include <src/Resource/ResourceManager.h>
#include <Nuake/Core/String.h>
#include <Nuake/Resource/ModelLoader.h>
#include <src/Core/String.h>
#include <src/Resource/ModelLoader.h>
class SkinnedMeshPanel : ComponentPanel
{

View File

@@ -1,8 +1,8 @@
#pragma once
#include "ComponentPanel.h"
#include <Nuake/Scene/Entities/ImGuiHelper.h>
#include <Nuake/Scene/Components/TransformComponent.h>
#include <Nuake/Core/Maths.h>
#include <src/Scene/Entities/ImGuiHelper.h>
#include <src/Scene/Components/TransformComponent.h>
#include <src/Core/Maths.h>
class TransformPanel : ComponentPanel {
public:

View File

@@ -5,25 +5,18 @@
#include "Misc/GizmoDrawer.h"
#include "EditorLayer.h"
#include "Nuake/UI/NuakeUI.h"
#include "Nuake/UI/UIInputManager.h"
#include "Nuake/Modules/ModuleDB.h"
#include <glad/glad.h>
#include "src/UI/NuakeUI.h"
#include "src/UI/UIInputManager.h"
void EditorApplication::OnInit()
{
using namespace Nuake;
Engine::Init();
// Register bakers, these can convert files into nuake resources
if (m_LaunchSettings.generateBindings)
{
ModuleDB::Get().GenerateModuleAPI();
Logger::Log("Generated Bindings");
m_Window->Close();
return;
}
Engine::Init();
m_Window = Engine::GetCurrentWindow();
m_Window->SetSize({ m_Specification.WindowWidth, m_Specification.WindowHeight });
m_Window->SetTitle(m_Specification.Name);

View File

@@ -1,12 +1,12 @@
#pragma once
#include <Nuake/Application/Application.h>
#include <Nuake/Window.h>
#include <src/Application/Application.h>
#include <src/Window.h>
#include "Windows/EditorInterface.h"
#include "Misc/GizmoDrawer.h"
#include "Commands/CommandBuffer.h"
#include "LaunchSettings.h"
#include "../LaunchSettings.h"
using namespace NuakeEditor;

View File

@@ -3,10 +3,13 @@
#include "Windows/EditorInterface.h"
#include "Misc/GizmoDrawer.h"
#include "Nuake/Core/Input.h"
#include "src/Core/Input.h"
#include <glad/glad.h>
#include <glm/gtc/type_ptr.hpp>
#include "glad/glad.h"
void EditorLayer::OnAttach()
{
m_EditorInterface = new Nuake::EditorInterface(mCommandBuffer);
@@ -20,9 +23,6 @@ void EditorLayer::OnUpdate()
Nuake::Engine::Tick();
Nuake::Engine::Draw();
m_EditorInterface->Draw();
m_EditorInterface->Update(Nuake::Engine::GetTimestep());
/*
auto sceneFramebuffer = GetApplication().GetWindow()->GetFrameBuffer();
// Draw gizmos
@@ -68,13 +68,12 @@ void EditorLayer::OnUpdate()
sceneFramebuffer->Unbind();
}
*/
m_EditorInterface->Draw();
m_EditorInterface->Update(Nuake::Engine::GetTimestep());
Nuake::Engine::EndDraw();
Nuake::Input::Update();
RID::ExecuteRemaps();
Nuake::Input::Update();
}
void EditorLayer::OnDetach()

View File

@@ -1,7 +1,7 @@
#pragma once
#include <Nuake/Application/Layer.h>
#include <src/Application/Layer.h>
#include "Commands/CommandBuffer.h"
#include "Nuake/AI/NavMeshDebugDrawer.h"
#include "src/AI/NavMeshDebugDrawer.h"
namespace Nuake {

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