Compare commits
4 Commits
vulkan-dev
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
993bc3ae43 | ||
|
|
4d34b9978a | ||
|
|
4661c1f00e | ||
|
|
b6721d036a |
3
.github/FUNDING.yml
vendored
3
.github/FUNDING.yml
vendored
@@ -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
44
.gitmodules
vendored
@@ -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
|
||||
|
||||
@@ -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 |
@@ -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;
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
69
Editor/.editorconfig
Normal 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
13
Editor/.gitignore
vendored
@@ -1 +1,12 @@
|
||||
Build/
|
||||
*.png
|
||||
*.tga
|
||||
*.map
|
||||
*.material
|
||||
*.hdr
|
||||
*.obj
|
||||
*.fbx
|
||||
*.jpg
|
||||
*.bin
|
||||
*.gltf
|
||||
*.bmp
|
||||
*.psd
|
||||
10
Editor/Coral.Managed.runtimeconfig.json
Normal file
10
Editor/Coral.Managed.runtimeconfig.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"runtimeOptions": {
|
||||
"tfm": "net8.0",
|
||||
"rollForward": "LatestMinor",
|
||||
"framework": {
|
||||
"name": "Microsoft.NETCore.App",
|
||||
"version": "8.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
60
Editor/Editor.rc
Normal 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
|
||||
@@ -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;
|
||||
@@ -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();
|
||||
}
|
||||
};
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
};
|
||||
@@ -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();
|
||||
}
|
||||
};
|
||||
@@ -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; }
|
||||
};
|
||||
@@ -1,3 +0,0 @@
|
||||
#include "AnimatedValue.h"
|
||||
|
||||
std::vector<IAnimatedValue*> IAnimatedValue::Instances;
|
||||
@@ -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;
|
||||
}
|
||||
};
|
||||
@@ -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);
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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; }
|
||||
};
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
};
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
};
|
||||
@@ -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());
|
||||
}
|
||||
};
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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);
|
||||
};
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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);
|
||||
};
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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();
|
||||
};
|
||||
BIN
Editor/SourceSansPro-Regular.ttf
Normal file
BIN
Editor/SourceSansPro-Regular.ttf
Normal file
Binary file not shown.
@@ -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
16
Editor/resource.h
Normal 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
|
||||
@@ -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"
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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 {
|
||||
@@ -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
|
||||
{
|
||||
@@ -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
|
||||
{
|
||||
51
Editor/src/ComponentsPanel/CameraPanel.h
Normal file
51
Editor/src/ComponentsPanel/CameraPanel.h
Normal 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();
|
||||
}
|
||||
};
|
||||
@@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
#include "ComponentPanel.h"
|
||||
|
||||
#include <Nuake/Scene/Components/CapsuleColliderComponent.h>
|
||||
#include <src/Scene/Components/CapsuleColliderComponent.h>
|
||||
|
||||
class CapsuleColliderPanel
|
||||
{
|
||||
@@ -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
|
||||
{
|
||||
@@ -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) \
|
||||
@@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
#include "ComponentPanel.h"
|
||||
|
||||
#include <Nuake/Scene/Components/CylinderColliderComponent.h>
|
||||
#include <src/Scene/Components/CylinderColliderComponent.h>
|
||||
|
||||
class CylinderColliderPanel
|
||||
{
|
||||
@@ -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);
|
||||
253
Editor/src/ComponentsPanel/MaterialEditor.cpp
Normal file
253
Editor/src/ComponentsPanel/MaterialEditor.cpp
Normal 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();
|
||||
}
|
||||
}
|
||||
12
Editor/src/ComponentsPanel/MaterialEditor.h
Normal file
12
Editor/src/ComponentsPanel/MaterialEditor.h
Normal 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);
|
||||
};
|
||||
@@ -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
|
||||
{
|
||||
130
Editor/src/ComponentsPanel/MeshPanel.h
Normal file
130
Editor/src/ComponentsPanel/MeshPanel.h
Normal 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();
|
||||
}
|
||||
};
|
||||
@@ -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();
|
||||
@@ -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
|
||||
{
|
||||
@@ -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());
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
{
|
||||
@@ -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:
|
||||
@@ -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);
|
||||
@@ -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;
|
||||
|
||||
@@ -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()
|
||||
@@ -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
Reference in New Issue
Block a user