Merge remote-tracking branch 'origin/1.10' into sdl_platform
# Conflicts: # Source/Editor/GUI/ContextMenu/ContextMenuBase.cs # Source/Engine/Platform/Linux/LinuxPlatform.cpp
This commit is contained in:
3
.github/workflows/tests.yml
vendored
3
.github/workflows/tests.yml
vendored
@@ -73,8 +73,11 @@ jobs:
|
||||
.\Development\Scripts\Windows\CallBuildTool.bat -build -log -dotnet=8 -arch=x64 -platform=Windows -configuration=Development -buildtargets=FlaxTestsTarget
|
||||
dotnet msbuild Source\Tools\Flax.Build.Tests\Flax.Build.Tests.csproj /m /t:Restore,Build /p:Configuration=Debug /p:Platform=AnyCPU /nologo
|
||||
- name: Test
|
||||
shell: pwsh
|
||||
run: |
|
||||
$ErrorActionPreference = "Stop"
|
||||
.\Binaries\Editor\Win64\Development\FlaxTests.exe
|
||||
if(!$?) { Write-Host "Tests failed with exit code $LastExitCode" -ForegroundColor Red; Exit $LastExitCode }
|
||||
dotnet test -f net8.0 Binaries\Tests\Flax.Build.Tests.dll
|
||||
xcopy /y Binaries\Editor\Win64\Development\FlaxEngine.CSharp.dll Binaries\Tests
|
||||
xcopy /y Binaries\Editor\Win64\Development\FlaxEngine.CSharp.runtimeconfig.json Binaries\Tests
|
||||
|
||||
BIN
Content/Editor/Camera/M_Camera.flax
(Stored with Git LFS)
BIN
Content/Editor/Camera/M_Camera.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Editor/Camera/O_Camera.flax
(Stored with Git LFS)
BIN
Content/Editor/Camera/O_Camera.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Editor/CubeTexturePreviewMaterial.flax
(Stored with Git LFS)
BIN
Content/Editor/CubeTexturePreviewMaterial.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Editor/DebugMaterials/DDGIDebugProbes.flax
(Stored with Git LFS)
BIN
Content/Editor/DebugMaterials/DDGIDebugProbes.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Editor/DebugMaterials/SingleColor/Decal.flax
(Stored with Git LFS)
BIN
Content/Editor/DebugMaterials/SingleColor/Decal.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Editor/DebugMaterials/SingleColor/Particle.flax
(Stored with Git LFS)
BIN
Content/Editor/DebugMaterials/SingleColor/Particle.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Editor/DebugMaterials/SingleColor/Surface.flax
(Stored with Git LFS)
BIN
Content/Editor/DebugMaterials/SingleColor/Surface.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Editor/DebugMaterials/SingleColor/SurfaceAdditive.flax
(Stored with Git LFS)
BIN
Content/Editor/DebugMaterials/SingleColor/SurfaceAdditive.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Editor/DebugMaterials/SingleColor/Terrain.flax
(Stored with Git LFS)
BIN
Content/Editor/DebugMaterials/SingleColor/Terrain.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Editor/DefaultFontMaterial.flax
(Stored with Git LFS)
BIN
Content/Editor/DefaultFontMaterial.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Editor/Gizmo/FoliageBrushMaterial.flax
(Stored with Git LFS)
BIN
Content/Editor/Gizmo/FoliageBrushMaterial.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Editor/Gizmo/Material.flax
(Stored with Git LFS)
BIN
Content/Editor/Gizmo/Material.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Editor/Gizmo/MaterialWire.flax
(Stored with Git LFS)
BIN
Content/Editor/Gizmo/MaterialWire.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Editor/Gizmo/MaterialWireFocus.flax
(Stored with Git LFS)
BIN
Content/Editor/Gizmo/MaterialWireFocus.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Editor/Gizmo/RotationAxis.flax
(Stored with Git LFS)
BIN
Content/Editor/Gizmo/RotationAxis.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Editor/Gizmo/ScaleAxis.flax
(Stored with Git LFS)
BIN
Content/Editor/Gizmo/ScaleAxis.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Editor/Gizmo/SelectionOutlineMaterial.flax
(Stored with Git LFS)
BIN
Content/Editor/Gizmo/SelectionOutlineMaterial.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Editor/Gizmo/TranslationAxis.flax
(Stored with Git LFS)
BIN
Content/Editor/Gizmo/TranslationAxis.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Editor/Gizmo/VertexColorsPreviewMaterial.flax
(Stored with Git LFS)
BIN
Content/Editor/Gizmo/VertexColorsPreviewMaterial.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Editor/Gizmo/WireBox.flax
(Stored with Git LFS)
BIN
Content/Editor/Gizmo/WireBox.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Editor/Highlight Material.flax
(Stored with Git LFS)
BIN
Content/Editor/Highlight Material.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Editor/Icons/AudioListener.flax
(Stored with Git LFS)
BIN
Content/Editor/Icons/AudioListener.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Editor/Icons/AudioSource.flax
(Stored with Git LFS)
BIN
Content/Editor/Icons/AudioSource.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Editor/Icons/Decal.flax
(Stored with Git LFS)
BIN
Content/Editor/Icons/Decal.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Editor/Icons/DirectionalLight.flax
(Stored with Git LFS)
BIN
Content/Editor/Icons/DirectionalLight.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Editor/Icons/EnvironmentProbe.flax
(Stored with Git LFS)
BIN
Content/Editor/Icons/EnvironmentProbe.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Editor/Icons/IconsMaterial.flax
(Stored with Git LFS)
BIN
Content/Editor/Icons/IconsMaterial.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Editor/Icons/ParticleEffect.flax
(Stored with Git LFS)
BIN
Content/Editor/Icons/ParticleEffect.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Editor/Icons/PointLight.flax
(Stored with Git LFS)
BIN
Content/Editor/Icons/PointLight.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Editor/Icons/SceneAnimationPlayer.flax
(Stored with Git LFS)
BIN
Content/Editor/Icons/SceneAnimationPlayer.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Editor/Icons/SkyLight.flax
(Stored with Git LFS)
BIN
Content/Editor/Icons/SkyLight.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Editor/Icons/Skybox.flax
(Stored with Git LFS)
BIN
Content/Editor/Icons/Skybox.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Editor/IesProfilePreviewMaterial.flax
(Stored with Git LFS)
BIN
Content/Editor/IesProfilePreviewMaterial.flax
(Stored with Git LFS)
Binary file not shown.
@@ -83,6 +83,12 @@ float3 GetObjectSize(MaterialInput input)
|
||||
return float3(1, 1, 1);
|
||||
}
|
||||
|
||||
// Gets the current object scale (supports instancing)
|
||||
float3 GetObjectScale(MaterialInput input)
|
||||
{
|
||||
return float3(1, 1, 1);
|
||||
}
|
||||
|
||||
// Get the current object random value supports instancing)
|
||||
float GetPerInstanceRandom(MaterialInput input)
|
||||
{
|
||||
|
||||
@@ -207,6 +207,20 @@ float3 GetObjectSize(MaterialInput input)
|
||||
return GeometrySize * float3(world._m00, world._m11, world._m22);
|
||||
}
|
||||
|
||||
// Gets the current object scale (supports instancing)
|
||||
float3 GetObjectScale(MaterialInput input)
|
||||
{
|
||||
float4x4 world = WorldMatrix;
|
||||
|
||||
// Extract scale from the world matrix
|
||||
float3 scale;
|
||||
scale.x = length(float3(world._11, world._12, world._13));
|
||||
scale.y = length(float3(world._21, world._22, world._23));
|
||||
scale.z = length(float3(world._31, world._32, world._33));
|
||||
|
||||
return scale;
|
||||
}
|
||||
|
||||
// Get the current object random value
|
||||
float GetPerInstanceRandom(MaterialInput input)
|
||||
{
|
||||
@@ -297,7 +311,7 @@ VertexOutput VS_SplineModel(ModelInput input)
|
||||
output.Position = mul(float4(output.Geometry.WorldPosition, 1), ViewProjectionMatrix);
|
||||
|
||||
// Pass vertex attributes
|
||||
output.Geometry.TexCoord = input.TexCoord;
|
||||
output.Geometry.TexCoord = input.TexCoord0;
|
||||
#if USE_VERTEX_COLOR
|
||||
output.Geometry.VertexColor = input.Color;
|
||||
#endif
|
||||
|
||||
@@ -163,6 +163,12 @@ float3 GetObjectSize(MaterialInput input)
|
||||
return float3(1, 1, 1);
|
||||
}
|
||||
|
||||
// Gets the current object scale (supports instancing)
|
||||
float3 GetObjectScale(MaterialInput input)
|
||||
{
|
||||
return float3(1, 1, 1);
|
||||
}
|
||||
|
||||
// Get the current object random value supports instancing)
|
||||
float GetPerInstanceRandom(MaterialInput input)
|
||||
{
|
||||
|
||||
@@ -299,24 +299,22 @@ half3x3 CalcTangentToLocal(ModelInput input)
|
||||
float3 normal = input.Normal.xyz * 2.0 - 1.0;
|
||||
float3 tangent = input.Tangent.xyz * 2.0 - 1.0;
|
||||
float3 bitangent = cross(normal, tangent) * bitangentSign;
|
||||
return float3x3(tangent, bitangent, normal);
|
||||
return (half3x3)float3x3(tangent, bitangent, normal);
|
||||
}
|
||||
|
||||
half3x3 CalcTangentToWorld(in float4x4 world, in half3x3 tangentToLocal)
|
||||
{
|
||||
half3x3 localToWorld = RemoveScaleFromLocalToWorld((float3x3)world);
|
||||
half3x3 localToWorld = (half3x3)RemoveScaleFromLocalToWorld((float3x3)world);
|
||||
return mul(tangentToLocal, localToWorld);
|
||||
}
|
||||
|
||||
float3 GetParticlePosition(uint ParticleIndex)
|
||||
float3 GetParticlePosition(uint particleIndex)
|
||||
{
|
||||
return TransformParticlePosition(GetParticleVec3(ParticleIndex, PositionOffset));
|
||||
return TransformParticlePosition(GetParticleVec3(particleIndex, PositionOffset));
|
||||
}
|
||||
|
||||
// Vertex Shader function for Sprite Rendering
|
||||
META_VS(true, FEATURE_LEVEL_ES2)
|
||||
META_VS_IN_ELEMENT(POSITION, 0, R32G32_FLOAT, 0, 0, PER_VERTEX, 0, true)
|
||||
META_VS_IN_ELEMENT(TEXCOORD, 0, R32G32_FLOAT, 0, ALIGN, PER_VERTEX, 0, true)
|
||||
VertexOutput VS_Sprite(SpriteInput input, uint particleIndex : SV_InstanceID)
|
||||
{
|
||||
VertexOutput output;
|
||||
@@ -407,7 +405,7 @@ VertexOutput VS_Sprite(SpriteInput input, uint particleIndex : SV_InstanceID)
|
||||
output.InstanceParams = PerInstanceRandom;
|
||||
|
||||
// Calculate tanget space to world space transformation matrix for unit vectors
|
||||
half3x3 tangentToLocal = float3x3(axisX, axisY, axisZ);
|
||||
half3x3 tangentToLocal = half3x3(axisX, axisY, axisZ);
|
||||
half3x3 tangentToWorld = CalcTangentToWorld(world, tangentToLocal);
|
||||
output.TBN = tangentToWorld;
|
||||
|
||||
@@ -516,7 +514,7 @@ VertexOutput VS_Model(ModelInput input, uint particleIndex : SV_InstanceID)
|
||||
output.Position = mul(float4(output.WorldPosition, 1), ViewProjectionMatrix);
|
||||
|
||||
// Pass vertex attributes
|
||||
output.TexCoord = input.TexCoord;
|
||||
output.TexCoord = input.TexCoord0;
|
||||
output.ParticleIndex = particleIndex;
|
||||
#if USE_VERTEX_COLOR
|
||||
output.VertexColor = input.Color;
|
||||
@@ -612,7 +610,7 @@ VertexOutput VS_Ribbon(RibbonInput input, uint vertexIndex : SV_VertexID)
|
||||
{
|
||||
output.TexCoord.x = (float)input.Order / (float)RibbonSegmentCount;
|
||||
}
|
||||
output.TexCoord.y = (vertexIndex + 1) & 0x1;
|
||||
output.TexCoord.y = (float)((vertexIndex + 1) & 0x1);
|
||||
output.TexCoord = output.TexCoord * RibbonUVScale + RibbonUVOffset;
|
||||
|
||||
// Compute world space vertex position
|
||||
@@ -631,7 +629,7 @@ VertexOutput VS_Ribbon(RibbonInput input, uint vertexIndex : SV_VertexID)
|
||||
output.InstanceParams = PerInstanceRandom;
|
||||
|
||||
// Calculate tanget space to world space transformation matrix for unit vectors
|
||||
half3x3 tangentToLocal = float3x3(tangentRight, tangentUp, cross(tangentRight, tangentUp));
|
||||
half3x3 tangentToLocal = half3x3(tangentRight, tangentUp, cross(tangentRight, tangentUp));
|
||||
half3x3 tangentToWorld = CalcTangentToWorld(world, tangentToLocal);
|
||||
output.TBN = tangentToWorld;
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// Version: @0
|
||||
|
||||
#define MATERIAL 1
|
||||
#define MATERIAL_TEXCOORDS 4
|
||||
#define USE_PER_VIEW_CONSTANTS 1
|
||||
#define USE_PER_DRAW_CONSTANTS 1
|
||||
@3
|
||||
@@ -24,21 +25,29 @@ Buffer<float4> BoneMatrices : register(t1);
|
||||
Buffer<float4> PrevBoneMatrices : register(t2);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Geometry data passed though the graphics rendering stages up to the pixel shader
|
||||
struct GeometryData
|
||||
{
|
||||
float3 WorldPosition : TEXCOORD0;
|
||||
float2 TexCoord : TEXCOORD1;
|
||||
float2 LightmapUV : TEXCOORD2;
|
||||
float4 TexCoords01 : TEXCOORD1;
|
||||
float4 TexCoords23 : TEXCOORD2;
|
||||
float2 LightmapUV : TEXCOORD3;
|
||||
#if USE_VERTEX_COLOR
|
||||
half4 VertexColor : COLOR;
|
||||
#endif
|
||||
float3 WorldNormal : TEXCOORD3;
|
||||
float4 WorldTangent : TEXCOORD4;
|
||||
float3 WorldNormal : TEXCOORD4;
|
||||
float4 WorldTangent : TEXCOORD5;
|
||||
float3 PrevWorldPosition : TEXCOORD7;
|
||||
nointerpolation uint ObjectIndex : TEXCOORD8;
|
||||
};
|
||||
|
||||
float3 DecodeNormal(float4 normalMap)
|
||||
{
|
||||
float2 xy = normalMap.rg * 2.0 - 1.0;
|
||||
return float3(xy, sqrt(1.0 - saturate(dot(xy, xy))));
|
||||
}
|
||||
|
||||
// Interpolants passed from the vertex shader
|
||||
struct VertexOutput
|
||||
{
|
||||
@@ -68,7 +77,7 @@ struct MaterialInput
|
||||
{
|
||||
float3 WorldPosition;
|
||||
float TwoSidedSign;
|
||||
float2 TexCoord;
|
||||
float2 TexCoords[MATERIAL_TEXCOORDS];
|
||||
#if USE_LIGHTMAP
|
||||
float2 LightmapUV;
|
||||
#endif
|
||||
@@ -86,12 +95,18 @@ struct MaterialInput
|
||||
#endif
|
||||
};
|
||||
|
||||
// Map access to the main texure coordinate channel as UV0
|
||||
#define TexCoord TexCoords[0]
|
||||
|
||||
// Extracts geometry data to the material input
|
||||
MaterialInput GetGeometryMaterialInput(GeometryData geometry)
|
||||
{
|
||||
MaterialInput output = (MaterialInput)0;
|
||||
output.WorldPosition = geometry.WorldPosition;
|
||||
output.TexCoord = geometry.TexCoord;
|
||||
output.TexCoords[0] = geometry.TexCoords01.xy;
|
||||
output.TexCoords[1] = geometry.TexCoords01.zw;
|
||||
output.TexCoords[2] = geometry.TexCoords23.xy;
|
||||
output.TexCoords[3] = geometry.TexCoords23.zw;
|
||||
#if USE_LIGHTMAP
|
||||
output.LightmapUV = geometry.LightmapUV;
|
||||
#endif
|
||||
@@ -126,8 +141,8 @@ MaterialInput GetGeometryMaterialInput(GeometryData geometry)
|
||||
GeometryData InterpolateGeometry(GeometryData p0, float w0, GeometryData p1, float w1, GeometryData p2, float w2)
|
||||
{
|
||||
GeometryData output = (GeometryData)0;
|
||||
output.TexCoord = p0.TexCoord * w0 + p1.TexCoord * w1 + p2.TexCoord * w2;
|
||||
output.LightmapUV = p0.LightmapUV * w0 + p1.LightmapUV * w1 + p2.LightmapUV * w2;
|
||||
output.TexCoords01 = p0.TexCoords01 * w0 + p1.TexCoords01 * w1 + p2.TexCoords01 * w2;
|
||||
output.TexCoords23 = p0.TexCoords23 * w0 + p1.TexCoords23 * w1 + p2.TexCoords23 * w2;
|
||||
#if USE_VERTEX_COLOR
|
||||
output.VertexColor = p0.VertexColor * w0 + p1.VertexColor * w1 + p2.VertexColor * w2;
|
||||
#endif
|
||||
@@ -223,6 +238,24 @@ float3 GetObjectSize(MaterialInput input)
|
||||
return input.Object.GeometrySize * float3(world._m00, world._m11, world._m22);
|
||||
}
|
||||
|
||||
// Gets the current object scale (supports instancing)
|
||||
float3 GetObjectScale(MaterialInput input)
|
||||
{
|
||||
float4x4 world = input.Object.WorldMatrix;
|
||||
|
||||
// Get the squares of the scale factors
|
||||
float scaleXSquared = dot(world[0].xyz, world[0].xyz);
|
||||
float scaleYSquared = dot(world[1].xyz, world[1].xyz);
|
||||
float scaleZSquared = dot(world[2].xyz, world[2].xyz);
|
||||
|
||||
// Take square root to get actual scales
|
||||
return float3(
|
||||
sqrt(scaleXSquared),
|
||||
sqrt(scaleYSquared),
|
||||
sqrt(scaleZSquared)
|
||||
);
|
||||
}
|
||||
|
||||
// Get the current object random value (supports instancing)
|
||||
float GetPerInstanceRandom(MaterialInput input)
|
||||
{
|
||||
@@ -312,14 +345,15 @@ VertexOutput VS(ModelInput input)
|
||||
output.Position = mul(float4(output.Geometry.WorldPosition, 1), ViewProjectionMatrix);
|
||||
|
||||
// Pass vertex attributes
|
||||
output.Geometry.TexCoord = input.TexCoord;
|
||||
output.Geometry.TexCoords01 = float4(input.TexCoord0, input.TexCoord1);
|
||||
output.Geometry.TexCoords23 = float4(input.TexCoord2, input.TexCoord3);
|
||||
#if USE_VERTEX_COLOR
|
||||
output.Geometry.VertexColor = input.Color;
|
||||
#endif
|
||||
#if CAN_USE_LIGHTMAP
|
||||
output.Geometry.LightmapUV = input.LightmapUV * object.LightmapArea.zw + object.LightmapArea.xy;
|
||||
#else
|
||||
output.Geometry.LightmapUV = input.LightmapUV;
|
||||
output.Geometry.LightmapUV = float2(0, 0);
|
||||
#endif
|
||||
|
||||
// Calculate tanget space to world space transformation matrix for unit vectors
|
||||
@@ -459,7 +493,7 @@ META_VS_IN_ELEMENT(TEXCOORD, 0, R16G16_FLOAT, 0, ALIGN, PER_VERTEX, 0,
|
||||
META_VS_IN_ELEMENT(NORMAL, 0, R10G10B10A2_UNORM, 0, ALIGN, PER_VERTEX, 0, true)
|
||||
META_VS_IN_ELEMENT(TANGENT, 0, R10G10B10A2_UNORM, 0, ALIGN, PER_VERTEX, 0, true)
|
||||
META_VS_IN_ELEMENT(BLENDINDICES, 0, R8G8B8A8_UINT, 0, ALIGN, PER_VERTEX, 0, true)
|
||||
META_VS_IN_ELEMENT(BLENDWEIGHT, 0, R16G16B16A16_FLOAT,0, ALIGN, PER_VERTEX, 0, true)
|
||||
META_VS_IN_ELEMENT(BLENDWEIGHTS, 0, R16G16B16A16_FLOAT,0, ALIGN, PER_VERTEX, 0, true)
|
||||
VertexOutput VS_Skinned(ModelInput_Skinned input)
|
||||
{
|
||||
VertexOutput output;
|
||||
@@ -486,9 +520,10 @@ VertexOutput VS_Skinned(ModelInput_Skinned input)
|
||||
output.Position = mul(float4(output.Geometry.WorldPosition, 1), ViewProjectionMatrix);
|
||||
|
||||
// Pass vertex attributes
|
||||
output.Geometry.TexCoord = input.TexCoord;
|
||||
output.Geometry.TexCoords01 = float4(input.TexCoord0, input.TexCoord1);
|
||||
output.Geometry.TexCoords23 = float4(input.TexCoord2, input.TexCoord3);
|
||||
#if USE_VERTEX_COLOR
|
||||
output.Geometry.VertexColor = float4(0, 0, 0, 1);
|
||||
output.Geometry.VertexColor = input.Color;
|
||||
#endif
|
||||
output.Geometry.LightmapUV = float2(0, 0);
|
||||
|
||||
|
||||
@@ -236,6 +236,12 @@ float3 GetObjectSize(MaterialInput input)
|
||||
return float3(1, 1, 1);
|
||||
}
|
||||
|
||||
// Gets the current object scale (supports instancing)
|
||||
float3 GetObjectScale(MaterialInput input)
|
||||
{
|
||||
return float3(1, 1, 1);
|
||||
}
|
||||
|
||||
// Get the current object random value
|
||||
float GetPerInstanceRandom(MaterialInput input)
|
||||
{
|
||||
@@ -319,8 +325,6 @@ struct TerrainVertexInput
|
||||
|
||||
// Vertex Shader function for terrain rendering
|
||||
META_VS(true, FEATURE_LEVEL_ES2)
|
||||
META_VS_IN_ELEMENT(TEXCOORD, 0, R32G32_FLOAT, 0, ALIGN, PER_VERTEX, 0, true)
|
||||
META_VS_IN_ELEMENT(TEXCOORD, 1, R8G8B8A8_UNORM, 0, ALIGN, PER_VERTEX, 0, true)
|
||||
VertexOutput VS(TerrainVertexInput input)
|
||||
{
|
||||
VertexOutput output;
|
||||
|
||||
BIN
Content/Editor/Particles/Particle Material Color.flax
(Stored with Git LFS)
BIN
Content/Editor/Particles/Particle Material Color.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Editor/Particles/Particle Material Preview.flax
(Stored with Git LFS)
BIN
Content/Editor/Particles/Particle Material Preview.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Editor/Particles/Smoke Material.flax
(Stored with Git LFS)
BIN
Content/Editor/Particles/Smoke Material.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Editor/Primitives/Capsule.flax
(Stored with Git LFS)
BIN
Content/Editor/Primitives/Capsule.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Editor/Primitives/Cone.flax
(Stored with Git LFS)
BIN
Content/Editor/Primitives/Cone.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Editor/Primitives/Cube.flax
(Stored with Git LFS)
BIN
Content/Editor/Primitives/Cube.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Editor/Primitives/Cylinder.flax
(Stored with Git LFS)
BIN
Content/Editor/Primitives/Cylinder.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Editor/Primitives/Plane.flax
(Stored with Git LFS)
BIN
Content/Editor/Primitives/Plane.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Editor/Primitives/Sphere.flax
(Stored with Git LFS)
BIN
Content/Editor/Primitives/Sphere.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Editor/SpriteMaterial.flax
(Stored with Git LFS)
BIN
Content/Editor/SpriteMaterial.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Editor/Terrain/Circle Brush Material.flax
(Stored with Git LFS)
BIN
Content/Editor/Terrain/Circle Brush Material.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Editor/Terrain/Highlight Terrain Material.flax
(Stored with Git LFS)
BIN
Content/Editor/Terrain/Highlight Terrain Material.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Editor/TexturePreviewMaterial.flax
(Stored with Git LFS)
BIN
Content/Editor/TexturePreviewMaterial.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Editor/Wires Debug Material.flax
(Stored with Git LFS)
BIN
Content/Editor/Wires Debug Material.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Engine/DefaultDeformableMaterial.flax
(Stored with Git LFS)
BIN
Content/Engine/DefaultDeformableMaterial.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Engine/DefaultMaterial.flax
(Stored with Git LFS)
BIN
Content/Engine/DefaultMaterial.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Engine/DefaultRadialMenu.flax
(Stored with Git LFS)
BIN
Content/Engine/DefaultRadialMenu.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Engine/DefaultTerrainMaterial.flax
(Stored with Git LFS)
BIN
Content/Engine/DefaultTerrainMaterial.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Engine/Models/Box.flax
(Stored with Git LFS)
BIN
Content/Engine/Models/Box.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Engine/Models/Quad.flax
(Stored with Git LFS)
BIN
Content/Engine/Models/Quad.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Engine/Models/SimpleBox.flax
(Stored with Git LFS)
BIN
Content/Engine/Models/SimpleBox.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Engine/Models/Sphere.flax
(Stored with Git LFS)
BIN
Content/Engine/Models/Sphere.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Engine/Models/SphereLowPoly.flax
(Stored with Git LFS)
BIN
Content/Engine/Models/SphereLowPoly.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Engine/SingleColorMaterial.flax
(Stored with Git LFS)
BIN
Content/Engine/SingleColorMaterial.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Engine/SkyboxMaterial.flax
(Stored with Git LFS)
BIN
Content/Engine/SkyboxMaterial.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Engine/WhiteMaterial.flax
(Stored with Git LFS)
BIN
Content/Engine/WhiteMaterial.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Shaders/BakeLightmap.flax
(Stored with Git LFS)
BIN
Content/Shaders/BakeLightmap.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Shaders/Editor/LightmapUVsDensity.flax
(Stored with Git LFS)
BIN
Content/Shaders/Editor/LightmapUVsDensity.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Shaders/PostProcessing.flax
(Stored with Git LFS)
BIN
Content/Shaders/PostProcessing.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Shaders/Shadows.flax
(Stored with Git LFS)
BIN
Content/Shaders/Shadows.flax
(Stored with Git LFS)
Binary file not shown.
@@ -2,9 +2,9 @@
|
||||
"Name": "Flax",
|
||||
"Version": {
|
||||
"Major": 1,
|
||||
"Minor": 9,
|
||||
"Minor": 10,
|
||||
"Revision": 0,
|
||||
"Build": 6606
|
||||
"Build": 6702
|
||||
},
|
||||
"Company": "Flax",
|
||||
"Copyright": "Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.",
|
||||
|
||||
@@ -237,6 +237,7 @@
|
||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002ECSharpPlaceAttributeOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateBlankLinesAroundFieldToBlankLinesAroundProperty/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateThisQualifierSettings/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/GrammarAndSpelling/GrammarChecking/Exceptions/=Try_0020to_0020scripting/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:String x:Key="/Default/GrammarAndSpelling/GrammarChecking/RulesStates/=LanguageTool_002EEN_002EE_005FG/@EntryIndexedValue">DisabledByUser</s:String>
|
||||
<s:Boolean x:Key="/Default/PatternsAndTemplates/Todo/TodoPatterns/=EEA05B0ED8200E4BA9D2D3F1052EBFFD/@KeyIndexDefined">True</s:Boolean>
|
||||
<s:String x:Key="/Default/PatternsAndTemplates/Todo/TodoPatterns/=EEA05B0ED8200E4BA9D2D3F1052EBFFD/Color/@EntryValue">Blue</s:String>
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "Engine/Core/Math/Color32.h"
|
||||
#include "Engine/Core/Config/GameSettings.h"
|
||||
#include "Editor/Utilities/EditorUtilities.h"
|
||||
#include "Engine/Graphics/PixelFormatSampler.h"
|
||||
#include "Engine/Graphics/Textures/TextureData.h"
|
||||
#include "Engine/Tools/TextureTool/TextureTool.h"
|
||||
#include "Engine/Content/Content.h"
|
||||
@@ -240,7 +241,7 @@ void UpdateIconData(uint8* iconData, const TextureData* icon)
|
||||
const TextureMipData* srcPixels = icon->GetData(0, srcPixelsMip);
|
||||
const Color32* srcPixelsData = (Color32*)srcPixels->Data.Get();
|
||||
const Int2 srcPixelsSize(Math::Max(1, icon->Width >> srcPixelsMip), Math::Max(1, icon->Height >> srcPixelsMip));
|
||||
const auto sampler = TextureTool::GetSampler(icon->Format);
|
||||
const auto sampler = PixelFormatSampler::Get(icon->Format);
|
||||
ASSERT_LOW_LAYER(sampler);
|
||||
|
||||
// Write colors
|
||||
@@ -252,7 +253,7 @@ void UpdateIconData(uint8* iconData, const TextureData* icon)
|
||||
for (uint32 x = 0; x < width; x++)
|
||||
{
|
||||
float u = (float)x / width;
|
||||
const Color c = TextureTool::SampleLinear(sampler, Float2(u, v), srcPixelsData, srcPixelsSize, srcPixels->RowPitch);
|
||||
const Color c = sampler->SampleLinear(srcPixelsData, Float2(u, v), srcPixelsSize, srcPixels->RowPitch);
|
||||
colorData[idx++] = Color32(c).GetAsBGRA();
|
||||
}
|
||||
}
|
||||
@@ -271,7 +272,7 @@ void UpdateIconData(uint8* iconData, const TextureData* icon)
|
||||
{
|
||||
uint32 x = packedX * 8 + pixelIdx;
|
||||
float u = (float)x / width;
|
||||
const Color c = TextureTool::SampleLinear(sampler, Float2(u, v), srcPixelsData, srcPixelsSize, srcPixels->RowPitch);
|
||||
const Color c = sampler->SampleLinear(srcPixelsData, Float2(u, v), srcPixelsSize, srcPixels->RowPitch);
|
||||
if (c.A < 0.25f)
|
||||
mask |= 1 << (7 - pixelIdx);
|
||||
}
|
||||
@@ -322,7 +323,7 @@ bool UpdateExeIcon(const String& path, const TextureData& icon)
|
||||
const TextureData* iconRGBA8 = &icon;
|
||||
TextureData tmpData1;
|
||||
//if (icon.Format != PixelFormat::R8G8B8A8_UNorm)
|
||||
if (TextureTool::GetSampler(icon.Format) == nullptr)
|
||||
if (PixelFormatSampler::Get(icon.Format) == nullptr)
|
||||
{
|
||||
if (TextureTool::Convert(tmpData1, *iconRGBA8, PixelFormat::R8G8B8A8_UNorm))
|
||||
{
|
||||
|
||||
@@ -137,10 +137,7 @@ void CookAssetsStep::CacheData::Load(CookingData& data)
|
||||
if (!FileSystem::DirectoryExists(CacheFolder))
|
||||
FileSystem::CreateDirectory(CacheFolder);
|
||||
if (!FileSystem::FileExists(HeaderFilePath))
|
||||
{
|
||||
LOG(Warning, "Missing incremental build cooking assets cache.");
|
||||
return;
|
||||
}
|
||||
|
||||
auto file = FileReadStream::Open(HeaderFilePath);
|
||||
if (file == nullptr)
|
||||
@@ -158,7 +155,7 @@ void CookAssetsStep::CacheData::Load(CookingData& data)
|
||||
|
||||
LOG(Info, "Loading incremental build cooking cache (entries count: {0})", entriesCount);
|
||||
file->ReadBytes(&Settings, sizeof(Settings));
|
||||
Entries.EnsureCapacity(Math::RoundUpToPowerOf2(static_cast<int32>(entriesCount * 3.0f)));
|
||||
Entries.EnsureCapacity(entriesCount);
|
||||
|
||||
Array<Pair<String, DateTime>> fileDependencies;
|
||||
for (int32 i = 0; i < entriesCount; i++)
|
||||
@@ -166,7 +163,7 @@ void CookAssetsStep::CacheData::Load(CookingData& data)
|
||||
Guid id;
|
||||
file->Read(id);
|
||||
String typeName;
|
||||
file->ReadString(&typeName);
|
||||
file->Read(typeName);
|
||||
DateTime fileModified;
|
||||
file->Read(fileModified);
|
||||
int32 fileDependenciesCount;
|
||||
@@ -176,7 +173,7 @@ void CookAssetsStep::CacheData::Load(CookingData& data)
|
||||
for (int32 j = 0; j < fileDependenciesCount; j++)
|
||||
{
|
||||
Pair<String, DateTime>& f = fileDependencies[j];
|
||||
file->ReadString(&f.First, 10);
|
||||
file->Read(f.First, 10);
|
||||
file->Read(f.Second);
|
||||
}
|
||||
|
||||
@@ -311,9 +308,9 @@ void CookAssetsStep::CacheData::Save(CookingData& data)
|
||||
{
|
||||
auto& e = i->Value;
|
||||
file->Write(e.ID);
|
||||
file->WriteString(e.TypeName);
|
||||
file->Write(e.TypeName);
|
||||
file->Write(e.FileModified);
|
||||
file->WriteInt32(e.FileDependencies.Count());
|
||||
file->Write(e.FileDependencies.Count());
|
||||
for (auto& f : e.FileDependencies)
|
||||
{
|
||||
file->Write(f.First, 10);
|
||||
@@ -365,17 +362,27 @@ bool CookAssetsStep::ProcessDefaultAsset(AssetCookData& options)
|
||||
|
||||
bool CookAssetsStep::Process(CookingData& data, CacheData& cache, Asset* asset)
|
||||
{
|
||||
// Validate asset
|
||||
PROFILE_CPU_ASSET(asset);
|
||||
if (asset->IsVirtual())
|
||||
{
|
||||
// Virtual assets are not included into the build
|
||||
return false;
|
||||
}
|
||||
const bool wasLoaded = asset->IsLoaded();
|
||||
if (asset->WaitForLoaded())
|
||||
{
|
||||
LOG(Error, "Failed to load asset \'{0}\'", asset->ToString());
|
||||
return true;
|
||||
}
|
||||
if (!wasLoaded)
|
||||
{
|
||||
// HACK: give some time to resave any old assets in Asset::onLoad after it's loaded
|
||||
// This assumes that if Load Thread enters Asset::Save then it will get asset lock and hold it until asset is saved
|
||||
// So we can take the same lock to wait for save end but first we need to wait for it to get that lock
|
||||
// (in future try to handle it in a better way)
|
||||
Platform::Sleep(5);
|
||||
}
|
||||
ScopeLock lock(asset->Locker);
|
||||
|
||||
// Switch based on an asset type
|
||||
const auto asBinaryAsset = dynamic_cast<BinaryAsset*>(asset);
|
||||
@@ -793,7 +800,10 @@ bool CookAssetsStep::Process(CookingData& data, CacheData& cache, BinaryAsset* a
|
||||
// Prepare asset data
|
||||
AssetInitData initData;
|
||||
if (asset->Storage->LoadAssetHeader(asset->GetID(), initData))
|
||||
{
|
||||
LOG(Warning, "Failed to load asset {} header from storage '{}'", asset->GetID(), asset->Storage->GetPath());
|
||||
return true;
|
||||
}
|
||||
initData.Header.UnlinkChunks();
|
||||
initData.Metadata.Release();
|
||||
for (auto& e : initData.Dependencies)
|
||||
@@ -1165,7 +1175,7 @@ bool CookAssetsStep::Perform(CookingData& data)
|
||||
assetRef = Content::LoadAsync<Asset>(assetId);
|
||||
if (assetRef == nullptr)
|
||||
{
|
||||
data.Error(TEXT("Failed to load asset included in build."));
|
||||
LOG(Error, "Failed to load asset {} included in build", assetId);
|
||||
return true;
|
||||
}
|
||||
e.Info.TypeName = assetRef->GetTypeName();
|
||||
@@ -1173,6 +1183,7 @@ bool CookAssetsStep::Perform(CookingData& data)
|
||||
// Cook asset
|
||||
if (Process(data, cache, assetRef.Get()))
|
||||
{
|
||||
LOG(Error, "Failed to process asset {}", assetRef->ToString());
|
||||
cache.Save(data);
|
||||
return true;
|
||||
}
|
||||
@@ -1205,10 +1216,17 @@ bool CookAssetsStep::Perform(CookingData& data)
|
||||
// Copy file
|
||||
if (!FileSystem::FileExists(cookedPath) || FileSystem::GetFileLastEditTime(cookedPath) >= FileSystem::GetFileLastEditTime(filePath))
|
||||
{
|
||||
if (FileSystem::CreateDirectory(StringUtils::GetDirectoryName(cookedPath)))
|
||||
const String cookedFolder = StringUtils::GetDirectoryName(cookedPath);
|
||||
if (FileSystem::CreateDirectory(cookedFolder))
|
||||
{
|
||||
LOG(Error, "Failed to create directory '{}'", cookedFolder);
|
||||
return true;
|
||||
}
|
||||
if (FileSystem::CopyFile(cookedPath, filePath))
|
||||
{
|
||||
LOG(Error, "Failed to copy file from '{}' to '{}'", filePath, cookedPath);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Count stats of file extension
|
||||
@@ -1249,7 +1267,7 @@ bool CookAssetsStep::Perform(CookingData& data)
|
||||
*(int32*)(bytes.Get() + 804) = contentKey;
|
||||
*(Guid*)(bytes.Get() + 808) = gameSettings->SplashScreen;
|
||||
Encryption::EncryptBytes(bytes.Get(), bytes.Count());
|
||||
stream->WriteArray(bytes);
|
||||
stream->Write(bytes);
|
||||
|
||||
Delete(stream);
|
||||
}
|
||||
|
||||
@@ -39,14 +39,9 @@ CustomEditorsUtilService CustomEditorsUtilServiceInstance;
|
||||
|
||||
struct Entry
|
||||
{
|
||||
MClass* DefaultEditor;
|
||||
MClass* CustomEditor;
|
||||
|
||||
Entry()
|
||||
{
|
||||
DefaultEditor = nullptr;
|
||||
CustomEditor = nullptr;
|
||||
}
|
||||
MClass* DefaultEditor = nullptr;
|
||||
MClass* CustomEditor = nullptr;
|
||||
MType* CustomEditorType = nullptr;
|
||||
};
|
||||
|
||||
Dictionary<MType*, Entry> Cache(512);
|
||||
@@ -63,11 +58,11 @@ MTypeObject* CustomEditorsUtil::GetCustomEditor(MTypeObject* refType)
|
||||
Entry result;
|
||||
if (Cache.TryGet(type, result))
|
||||
{
|
||||
if (result.CustomEditorType)
|
||||
return INTERNAL_TYPE_GET_OBJECT(result.CustomEditorType);
|
||||
MClass* editor = result.CustomEditor ? result.CustomEditor : result.DefaultEditor;
|
||||
if (editor)
|
||||
{
|
||||
return MUtils::GetType(editor);
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
@@ -157,7 +152,7 @@ void OnAssemblyLoaded(MAssembly* assembly)
|
||||
else if (typeClass)
|
||||
{
|
||||
auto& entry = Cache[mclass->GetType()];
|
||||
entry.CustomEditor = typeClass;
|
||||
entry.CustomEditorType = type;
|
||||
|
||||
//LOG(Info, "Custom Editor {0} for type {1}", String(typeClass->GetFullName()), String(mclass->GetFullName()));
|
||||
}
|
||||
|
||||
@@ -405,20 +405,9 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
|
||||
// Select object
|
||||
if (_value is Actor actor)
|
||||
{
|
||||
if (PresenterContext is PropertiesWindow)
|
||||
Editor.Instance.SceneEditing.Select(actor);
|
||||
else if (PresenterContext is PrefabWindow prefabWindow)
|
||||
prefabWindow.Select(prefabWindow.Graph.Root.Find(actor));
|
||||
}
|
||||
Select(actor);
|
||||
else if (_value is Script script && script.Actor)
|
||||
{
|
||||
var a = script.Actor;
|
||||
if (PresenterContext is PropertiesWindow)
|
||||
Editor.Instance.SceneEditing.Select(a);
|
||||
else if (PresenterContext is PrefabWindow prefabWindow)
|
||||
prefabWindow.Select(prefabWindow.Graph.Root.Find(a));
|
||||
}
|
||||
Select(script.Actor);
|
||||
else if (_value is Asset asset)
|
||||
Editor.Instance.Windows.ContentWin.Select(asset);
|
||||
}
|
||||
@@ -436,6 +425,14 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
ShowDropDownMenu();
|
||||
}
|
||||
|
||||
private void Select(Actor actor)
|
||||
{
|
||||
if (PresenterContext is PropertiesWindow)
|
||||
Editor.Instance.SceneEditing.Select(actor);
|
||||
else if (PresenterContext is PrefabWindow prefabWindow)
|
||||
prefabWindow.Select(prefabWindow.Graph.Root.Find(actor));
|
||||
}
|
||||
|
||||
private void DoDrag()
|
||||
{
|
||||
// Do the drag drop operation if has selected element
|
||||
|
||||
@@ -42,6 +42,8 @@ public class Editor : EditorModule
|
||||
options.ScriptingAPI.SystemReferences.Add("System.Text.RegularExpressions");
|
||||
options.ScriptingAPI.SystemReferences.Add("System.IO.Compression.ZipFile");
|
||||
options.ScriptingAPI.SystemReferences.Add("System.Diagnostics.Process");
|
||||
if (Profiler.Use(options))
|
||||
options.ScriptingAPI.Defines.Add("USE_PROFILER");
|
||||
|
||||
// Enable optimizations for Editor, disable this for debugging the editor
|
||||
if (options.Configuration == TargetConfiguration.Development)
|
||||
|
||||
@@ -79,10 +79,6 @@ bool Editor::CheckProjectUpgrade()
|
||||
Delete(file);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(Warning, "Missing version cache file");
|
||||
}
|
||||
|
||||
// Check if project is in the old, deprecated layout
|
||||
if (EditorImpl::IsOldProjectXmlFormat)
|
||||
@@ -403,7 +399,7 @@ int32 Editor::LoadProduct()
|
||||
}
|
||||
|
||||
// Create new project option
|
||||
if (CommandLine::Options.NewProject)
|
||||
if (CommandLine::Options.NewProject.IsTrue())
|
||||
{
|
||||
Array<String> projectFiles;
|
||||
FileSystem::DirectoryGetFiles(projectFiles, projectPath, TEXT("*.flaxproj"), DirectorySearchOption::TopDirectoryOnly);
|
||||
@@ -428,7 +424,7 @@ int32 Editor::LoadProduct()
|
||||
}
|
||||
}
|
||||
}
|
||||
if (CommandLine::Options.NewProject)
|
||||
if (CommandLine::Options.NewProject.IsTrue())
|
||||
{
|
||||
if (projectPath.IsEmpty())
|
||||
projectPath = Platform::GetWorkingDirectory();
|
||||
@@ -529,7 +525,7 @@ int32 Editor::LoadProduct()
|
||||
if (projectPath.IsEmpty())
|
||||
{
|
||||
#if PLATFORM_HAS_HEADLESS_MODE
|
||||
if (CommandLine::Options.Headless)
|
||||
if (CommandLine::Options.Headless.IsTrue())
|
||||
{
|
||||
Platform::Fatal(TEXT("Missing project path."));
|
||||
return -1;
|
||||
@@ -612,7 +608,7 @@ int32 Editor::LoadProduct()
|
||||
// Validate project min supported version (older engine may try to load newer project)
|
||||
// Special check if project specifies only build number, then major/minor fields are set to 0
|
||||
const auto engineVersion = FLAXENGINE_VERSION;
|
||||
for (auto e : projects)
|
||||
for (const auto& e : projects)
|
||||
{
|
||||
const auto project = e.Item;
|
||||
if (project->MinEngineVersion > engineVersion ||
|
||||
@@ -657,7 +653,7 @@ Window* Editor::CreateMainWindow()
|
||||
bool Editor::Init()
|
||||
{
|
||||
// Scripts project files generation from command line
|
||||
if (CommandLine::Options.GenProjectFiles)
|
||||
if (CommandLine::Options.GenProjectFiles.IsTrue())
|
||||
{
|
||||
const String customArgs = TEXT("-verbose -log -logfile=\"Cache/Intermediate/ProjectFileLog.txt\"");
|
||||
const bool failed = ScriptsBuilder::GenerateProject(customArgs);
|
||||
|
||||
@@ -355,14 +355,14 @@ namespace FlaxEditor.GUI.ContextMenu
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Show(Control parent, Float2 location)
|
||||
public override void Show(Control parent, Float2 location, ContextMenuDirection? direction = null)
|
||||
{
|
||||
// Remove last separator to make context menu look better
|
||||
int lastIndex = _panel.Children.Count - 1;
|
||||
if (lastIndex >= 0 && _panel.Children[lastIndex] is ContextMenuSeparator separator)
|
||||
separator.Dispose();
|
||||
|
||||
base.Show(parent, location);
|
||||
base.Show(parent, location, direction);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
@@ -101,6 +101,16 @@ namespace FlaxEditor.GUI.ContextMenu
|
||||
/// </summary>
|
||||
public List<Window> ExternalPopups = new List<Window>();
|
||||
|
||||
/// <summary>
|
||||
/// Optional flag that can disable popup visibility based on window focus and use external control via Hide.
|
||||
/// </summary>
|
||||
public bool UseVisibilityControl = true;
|
||||
|
||||
/// <summary>
|
||||
/// Optional flag that can disable popup input capturing. Useful for transparent or visual-only popups.
|
||||
/// </summary>
|
||||
public bool UseInput = true;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ContextMenuBase"/> class.
|
||||
/// </summary>
|
||||
@@ -137,21 +147,26 @@ namespace FlaxEditor.GUI.ContextMenu
|
||||
/// </summary>
|
||||
/// <param name="parent">Parent control to attach to it.</param>
|
||||
/// <param name="location">Popup menu origin location in parent control coordinates.</param>
|
||||
public virtual void Show(Control parent, Float2 location)
|
||||
/// <param name="direction">The custom popup direction. Null to use automatic direction.</param>
|
||||
public virtual void Show(Control parent, Float2 location, ContextMenuDirection? direction = null)
|
||||
{
|
||||
Assert.IsNotNull(parent);
|
||||
|
||||
// Ensure to be closed
|
||||
Hide();
|
||||
bool isAlreadyVisible = Visible && _window;
|
||||
if (!isAlreadyVisible)
|
||||
Hide();
|
||||
|
||||
// Peek parent control window
|
||||
var parentWin = parent.RootWindow;
|
||||
if (parentWin == null)
|
||||
{
|
||||
Hide();
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if show menu inside the other menu - then link as a child to prevent closing the calling menu window on lost focus
|
||||
if (_parentCM == null && parentWin.ChildrenCount == 1 && parentWin.Children[0] is ContextMenuBase parentCM)
|
||||
{
|
||||
Hide();
|
||||
parentCM.ShowChild(this, parentCM.PointFromScreen(parent.PointToScreen(location)), false);
|
||||
return;
|
||||
}
|
||||
@@ -169,7 +184,7 @@ namespace FlaxEditor.GUI.ContextMenu
|
||||
var monitorBounds = Platform.GetMonitorBounds(locationSS);
|
||||
var rightBottomLocationSS = locationSS + dpiSize;
|
||||
bool isUp = false, isLeft = false;
|
||||
if (UseAutomaticDirectionFix)
|
||||
if (UseAutomaticDirectionFix && direction == null)
|
||||
{
|
||||
var parentMenu = parent as ContextMenu;
|
||||
if (monitorBounds.Bottom < rightBottomLocationSS.Y)
|
||||
@@ -196,6 +211,26 @@ namespace FlaxEditor.GUI.ContextMenu
|
||||
locationSS.X -= dpiSize.X;
|
||||
}
|
||||
}
|
||||
else if (direction.HasValue)
|
||||
{
|
||||
switch (direction.Value)
|
||||
{
|
||||
case ContextMenuDirection.RightUp:
|
||||
isUp = true;
|
||||
break;
|
||||
case ContextMenuDirection.LeftDown:
|
||||
isLeft = true;
|
||||
break;
|
||||
case ContextMenuDirection.LeftUp:
|
||||
isLeft = true;
|
||||
isUp = true;
|
||||
break;
|
||||
}
|
||||
if (isLeft)
|
||||
locationSS.X -= dpiSize.X;
|
||||
if (isUp)
|
||||
locationSS.Y -= dpiSize.Y;
|
||||
}
|
||||
|
||||
// Update direction flag
|
||||
if (isUp)
|
||||
@@ -203,47 +238,62 @@ namespace FlaxEditor.GUI.ContextMenu
|
||||
else
|
||||
_direction = isLeft ? ContextMenuDirection.LeftDown : ContextMenuDirection.RightDown;
|
||||
|
||||
// Create window
|
||||
var desc = CreateWindowSettings.Default;
|
||||
desc.Position = locationSS;
|
||||
desc.StartPosition = WindowStartPosition.Manual;
|
||||
desc.Size = dpiSize;
|
||||
desc.Fullscreen = false;
|
||||
desc.HasBorder = false;
|
||||
desc.SupportsTransparency = false;
|
||||
desc.ShowInTaskbar = false;
|
||||
desc.ActivateWhenFirstShown = true;
|
||||
desc.AllowInput = true;
|
||||
desc.AllowMinimize = false;
|
||||
desc.AllowMaximize = false;
|
||||
desc.AllowDragAndDrop = false;
|
||||
desc.IsTopmost = true;
|
||||
desc.Type = WindowType.Popup;
|
||||
desc.Parent = parentWin.Window;
|
||||
desc.Title = "ContextMenu";
|
||||
desc.HasSizingFrame = false;
|
||||
OnWindowCreating(ref desc);
|
||||
_window = Platform.CreateWindow(ref desc);
|
||||
_window.GotFocus += OnWindowGotFocus;
|
||||
_window.LostFocus += OnWindowLostFocus;
|
||||
if (isAlreadyVisible)
|
||||
{
|
||||
_window.ClientBounds = new Rectangle(locationSS, dpiSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Create window
|
||||
var desc = CreateWindowSettings.Default;
|
||||
desc.Position = locationSS;
|
||||
desc.StartPosition = WindowStartPosition.Manual;
|
||||
desc.Size = dpiSize;
|
||||
desc.Fullscreen = false;
|
||||
desc.HasBorder = false;
|
||||
desc.SupportsTransparency = false;
|
||||
desc.ShowInTaskbar = false;
|
||||
desc.ActivateWhenFirstShown = UseInput;
|
||||
desc.AllowInput = UseInput;
|
||||
desc.AllowMinimize = false;
|
||||
desc.AllowMaximize = false;
|
||||
desc.AllowDragAndDrop = false;
|
||||
desc.IsTopmost = true;
|
||||
desc.Type = WindowType.Popup;
|
||||
desc.Parent = parentWin.Window;
|
||||
desc.Title = "ContextMenu";
|
||||
desc.HasSizingFrame = false;
|
||||
OnWindowCreating(ref desc);
|
||||
_window = Platform.CreateWindow(ref desc);
|
||||
if (UseVisibilityControl)
|
||||
{
|
||||
_window.GotFocus += OnWindowGotFocus;
|
||||
_window.LostFocus += OnWindowLostFocus;
|
||||
}
|
||||
|
||||
#if USE_IS_FOREGROUND && USE_SDL_WORKAROUNDS
|
||||
// The focus between popup and parent windows doesn't change, force hide the popup when clicked on parent
|
||||
parentWin.Window.MouseDown += OnWindowMouseDown;
|
||||
_window.Closed += () => parentWin.Window.MouseDown -= OnWindowMouseDown;
|
||||
// The focus between popup and parent windows doesn't change, force hide the popup when clicked on parent
|
||||
parentWin.Window.MouseDown += OnWindowMouseDown;
|
||||
_window.Closed += () => parentWin.Window.MouseDown -= OnWindowMouseDown;
|
||||
#endif
|
||||
|
||||
// Attach to the window
|
||||
_parentCM = parent as ContextMenuBase;
|
||||
Parent = _window.GUI;
|
||||
// Attach to the window
|
||||
_parentCM = parent as ContextMenuBase;
|
||||
Parent = _window.GUI;
|
||||
}
|
||||
|
||||
// Show
|
||||
Visible = true;
|
||||
if (_window == null)
|
||||
return;
|
||||
_window.Show();
|
||||
PerformLayout();
|
||||
_previouslyFocused = parentWin.FocusedControl;
|
||||
Focus();
|
||||
OnShow();
|
||||
if (UseVisibilityControl)
|
||||
{
|
||||
_previouslyFocused = parentWin.FocusedControl;
|
||||
Focus();
|
||||
OnShow();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -508,7 +558,7 @@ namespace FlaxEditor.GUI.ContextMenu
|
||||
base.Update(deltaTime);
|
||||
|
||||
// Let root context menu to check if none of the popup windows
|
||||
if (_parentCM == null && !IsForeground)
|
||||
if (_parentCM == null && UseVisibilityControl && !IsForeground)
|
||||
{
|
||||
#if USE_SDL_WORKAROUNDS
|
||||
if (!IsMouseOver)
|
||||
|
||||
@@ -56,6 +56,11 @@ namespace FlaxEditor.GUI
|
||||
/// </summary>
|
||||
public event Action<Item> Clicked;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when items gets focused.
|
||||
/// </summary>
|
||||
public event Action<Item> Focused;
|
||||
|
||||
/// <summary>
|
||||
/// The tint color of the text.
|
||||
/// </summary>
|
||||
@@ -141,6 +146,10 @@ namespace FlaxEditor.GUI
|
||||
protected virtual void GetTextRect(out Rectangle rect)
|
||||
{
|
||||
rect = new Rectangle(2, 0, Width - 4, Height);
|
||||
|
||||
// Indent for drop panel items is handled by drop panel margin
|
||||
if (Parent is not DropPanel)
|
||||
rect.Location += new Float2(Editor.Instance.Icons.ArrowRight12.Size.X + 2, 0);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -155,10 +164,6 @@ namespace FlaxEditor.GUI
|
||||
if (IsMouseOver || IsFocused)
|
||||
Render2D.FillRectangle(new Rectangle(Float2.Zero, Size), style.BackgroundHighlighted);
|
||||
|
||||
// Indent for drop panel items is handled by drop panel margin
|
||||
if (Parent is not DropPanel)
|
||||
textRect.Location += new Float2(Editor.Instance.Icons.ArrowRight12.Size.X + 2, 0);
|
||||
|
||||
// Draw all highlights
|
||||
if (_highlights != null)
|
||||
{
|
||||
@@ -207,6 +212,14 @@ namespace FlaxEditor.GUI
|
||||
base.OnMouseLeave();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnGotFocus()
|
||||
{
|
||||
base.OnGotFocus();
|
||||
|
||||
Focused?.Invoke(this);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override int Compare(Control other)
|
||||
{
|
||||
@@ -227,6 +240,7 @@ namespace FlaxEditor.GUI
|
||||
private readonly Panel _scrollPanel;
|
||||
private List<DropPanel> _categoryPanels;
|
||||
private bool _waitingForInput;
|
||||
private string _customSearch;
|
||||
|
||||
/// <summary>
|
||||
/// Event fired when any item in this popup menu gets clicked.
|
||||
@@ -248,26 +262,30 @@ namespace FlaxEditor.GUI
|
||||
/// </summary>
|
||||
/// <param name="width">The control width.</param>
|
||||
/// <param name="height">The control height.</param>
|
||||
public ItemsListContextMenu(float width = 320, float height = 220)
|
||||
/// <param name="withSearch">Enables search field.</param>
|
||||
public ItemsListContextMenu(float width = 320, float height = 220, bool withSearch = true)
|
||||
{
|
||||
// Context menu dimensions
|
||||
Size = new Float2(width, height);
|
||||
|
||||
// Search box
|
||||
_searchBox = new SearchBox(false, 1, 1)
|
||||
if (withSearch)
|
||||
{
|
||||
Parent = this,
|
||||
Width = Width - 3,
|
||||
};
|
||||
_searchBox.TextChanged += OnSearchFilterChanged;
|
||||
_searchBox.ClearSearchButton.Clicked += () => PerformLayout();
|
||||
// Search box
|
||||
_searchBox = new SearchBox(false, 1, 1)
|
||||
{
|
||||
Parent = this,
|
||||
Width = Width - 3,
|
||||
};
|
||||
_searchBox.TextChanged += OnSearchFilterChanged;
|
||||
_searchBox.ClearSearchButton.Clicked += () => PerformLayout();
|
||||
}
|
||||
|
||||
// Panel with scrollbar
|
||||
_scrollPanel = new Panel(ScrollBars.Vertical)
|
||||
{
|
||||
Parent = this,
|
||||
AnchorPreset = AnchorPresets.StretchAll,
|
||||
Bounds = new Rectangle(0, _searchBox.Bottom + 1, Width, Height - _searchBox.Bottom - 2),
|
||||
Bounds = withSearch ? new Rectangle(0, _searchBox.Bottom + 1, Width, Height - _searchBox.Bottom - 2) : new Rectangle(Float2.Zero, Size),
|
||||
};
|
||||
|
||||
// Items list panel
|
||||
@@ -286,12 +304,13 @@ namespace FlaxEditor.GUI
|
||||
|
||||
LockChildrenRecursive();
|
||||
|
||||
var searchText = _searchBox?.Text ?? _customSearch;
|
||||
var items = ItemsPanel.Children;
|
||||
for (int i = 0; i < items.Count; i++)
|
||||
{
|
||||
if (items[i] is Item item)
|
||||
{
|
||||
item.UpdateFilter(_searchBox.Text);
|
||||
item.UpdateFilter(searchText);
|
||||
item.UpdateScore();
|
||||
}
|
||||
}
|
||||
@@ -305,13 +324,13 @@ namespace FlaxEditor.GUI
|
||||
{
|
||||
if (category.Children[j] is Item item2)
|
||||
{
|
||||
item2.UpdateFilter(_searchBox.Text);
|
||||
item2.UpdateFilter(searchText);
|
||||
item2.UpdateScore();
|
||||
anyVisible |= item2.Visible;
|
||||
}
|
||||
}
|
||||
category.Visible = anyVisible;
|
||||
if (string.IsNullOrEmpty(_searchBox.Text))
|
||||
if (string.IsNullOrEmpty(searchText))
|
||||
category.Close(false);
|
||||
else
|
||||
category.Open(false);
|
||||
@@ -322,8 +341,8 @@ namespace FlaxEditor.GUI
|
||||
|
||||
UnlockChildrenRecursive();
|
||||
PerformLayout(true);
|
||||
_searchBox.Focus();
|
||||
TextChanged?.Invoke(_searchBox.Text);
|
||||
_searchBox?.Focus();
|
||||
TextChanged?.Invoke(searchText);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -355,6 +374,14 @@ namespace FlaxEditor.GUI
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes all added items.
|
||||
/// </summary>
|
||||
public void ClearItems()
|
||||
{
|
||||
ItemsPanel.DisposeChildren();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sorts the items list (by item name by default).
|
||||
/// </summary>
|
||||
@@ -368,6 +395,34 @@ namespace FlaxEditor.GUI
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Focuses and scroll to the given item to be selected.
|
||||
/// </summary>
|
||||
/// <param name="item">The item to select.</param>
|
||||
public void SelectItem(Item item)
|
||||
{
|
||||
item.Focus();
|
||||
ScrollViewTo(item);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Applies custom search text query on the items list. Works even if search field is disabled
|
||||
/// </summary>
|
||||
/// <param name="text">The custom search text. Null to clear search.</param>
|
||||
public void Search(string text)
|
||||
{
|
||||
if (_searchBox != null)
|
||||
{
|
||||
_searchBox.SetText(text);
|
||||
}
|
||||
else
|
||||
{
|
||||
_customSearch = text;
|
||||
if (VisibleInHierarchy)
|
||||
OnSearchFilterChanged();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the item to the view and registers for the click event.
|
||||
/// </summary>
|
||||
@@ -446,9 +501,11 @@ namespace FlaxEditor.GUI
|
||||
}
|
||||
}
|
||||
|
||||
_searchBox.Clear();
|
||||
_searchBox?.Clear();
|
||||
UnlockChildrenRecursive();
|
||||
PerformLayout(true);
|
||||
if (_customSearch != null)
|
||||
OnSearchFilterChanged();
|
||||
}
|
||||
|
||||
private List<Item> GetVisibleItems()
|
||||
@@ -510,7 +567,7 @@ namespace FlaxEditor.GUI
|
||||
if (RootWindow.FocusedControl == null)
|
||||
{
|
||||
// Focus search box if nothing is focused
|
||||
_searchBox.Focus();
|
||||
_searchBox?.Focus();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -536,7 +593,7 @@ namespace FlaxEditor.GUI
|
||||
var focusedIndex = items.IndexOf(focusedItem);
|
||||
if (focusedIndex == 0)
|
||||
{
|
||||
_searchBox.Focus();
|
||||
_searchBox?.Focus();
|
||||
}
|
||||
else if (focusedIndex > 0)
|
||||
{
|
||||
@@ -556,7 +613,7 @@ namespace FlaxEditor.GUI
|
||||
break;
|
||||
}
|
||||
|
||||
if (_waitingForInput)
|
||||
if (_waitingForInput && _searchBox != null)
|
||||
{
|
||||
_waitingForInput = false;
|
||||
_searchBox.Focus();
|
||||
|
||||
@@ -68,7 +68,8 @@ namespace FlaxEditor.Gizmo
|
||||
if (_vertexBuffer == null)
|
||||
{
|
||||
_vertexBuffer = new GPUBuffer();
|
||||
var desc = GPUBufferDescription.Vertex(sizeof(Float3), 4);
|
||||
var layout = GPUVertexLayout.Get([new VertexElement(VertexElement.Types.Position, 0, 0, false, PixelFormat.R32G32B32_Float)]);
|
||||
var desc = GPUBufferDescription.Vertex(layout, sizeof(Float3), 4);
|
||||
_vertexBuffer.Init(ref desc);
|
||||
}
|
||||
if (_indexBuffer == null)
|
||||
|
||||
@@ -192,7 +192,7 @@ namespace FlaxEditor.Modules
|
||||
/// Removes a quick action by name.
|
||||
/// </summary>
|
||||
/// <param name="name">The action's name.</param>
|
||||
/// <returns>True when it succeed, false if there is no Quick Action with this name.</returns>
|
||||
/// <returns>True when it succeeds, false if there is no Quick Action with this name.</returns>
|
||||
public bool RemoveQuickAction(string name)
|
||||
{
|
||||
if (_quickActions == null)
|
||||
@@ -288,6 +288,16 @@ namespace FlaxEditor.Modules
|
||||
Profiler.EndEvent();
|
||||
}
|
||||
|
||||
// Editor window
|
||||
foreach (var window in Editor.Windows.Windows)
|
||||
{
|
||||
if (window is Windows.Assets.AssetEditorWindow)
|
||||
continue;
|
||||
var windowName = window.Title + " (window)";
|
||||
if (nameRegex.Match(windowName).Success)
|
||||
matches.Add(new SearchResult { Name = windowName, Type = "Window", Item = window });
|
||||
}
|
||||
|
||||
Profiler.EndEvent();
|
||||
return matches;
|
||||
}
|
||||
@@ -407,6 +417,9 @@ namespace FlaxEditor.Modules
|
||||
Editor.Instance.Windows.EditWin.Viewport.FocusSelection();
|
||||
}
|
||||
break;
|
||||
case Windows.EditorWindow window:
|
||||
window.FocusOrShow();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -56,6 +56,11 @@ namespace FlaxEditor.Modules
|
||||
/// </summary>
|
||||
public readonly GenerateScriptsProjectFilesProgress GenerateScriptsProjectFiles = new GenerateScriptsProjectFilesProgress();
|
||||
|
||||
/// <summary>
|
||||
/// The assets loading progress handler.
|
||||
/// </summary>
|
||||
public readonly LoadAssetsProgress LoadAssets = new LoadAssetsProgress();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the first active handler.
|
||||
/// </summary>
|
||||
@@ -80,6 +85,7 @@ namespace FlaxEditor.Modules
|
||||
RegisterHandler(CodeEditorOpen);
|
||||
RegisterHandler(NavMeshBuilding);
|
||||
RegisterHandler(GenerateScriptsProjectFiles);
|
||||
RegisterHandler(LoadAssets);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -447,6 +447,8 @@ namespace FlaxEditor.Modules
|
||||
|
||||
private void StateMachineOnStateChanged()
|
||||
{
|
||||
if (Editor.StateMachine.CurrentState is States.ClosingState)
|
||||
return;
|
||||
UpdateToolstrip();
|
||||
UpdateStatusBar();
|
||||
}
|
||||
|
||||
40
Source/Editor/Progress/Handlers/LoadAssetsProgress.cs
Normal file
40
Source/Editor/Progress/Handlers/LoadAssetsProgress.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
|
||||
|
||||
namespace FlaxEditor.Progress.Handlers
|
||||
{
|
||||
/// <summary>
|
||||
/// Loading assets progress reporting handler.
|
||||
/// </summary>
|
||||
/// <seealso cref="FlaxEditor.Progress.ProgressHandler" />
|
||||
public sealed class LoadAssetsProgress : ProgressHandler
|
||||
{
|
||||
private int _loadingAssetsCount;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="LoadAssetsProgress"/> class.
|
||||
/// </summary>
|
||||
public LoadAssetsProgress()
|
||||
{
|
||||
Editor.Instance.EditorUpdate += OnEditorUpdate;
|
||||
}
|
||||
|
||||
private void OnEditorUpdate()
|
||||
{
|
||||
var contentStats = FlaxEngine.Content.Stats;
|
||||
if (_loadingAssetsCount == contentStats.LoadingAssetsCount)
|
||||
return;
|
||||
|
||||
if (contentStats.LoadingAssetsCount == 0)
|
||||
OnEnd();
|
||||
else if (_loadingAssetsCount == 0)
|
||||
OnStart();
|
||||
if (contentStats.LoadingAssetsCount > 0)
|
||||
{
|
||||
var progress = (float)contentStats.LoadedAssetsCount / contentStats.AssetsCount;
|
||||
var text = contentStats.LoadingAssetsCount == 1 ? "Loading 1 asset..." : $"Loading {contentStats.LoadingAssetsCount} assets...";
|
||||
OnUpdate(progress, text);
|
||||
}
|
||||
_loadingAssetsCount = contentStats.LoadingAssetsCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -80,19 +80,23 @@ namespace FlaxEditor.SceneGraph.Actors
|
||||
|
||||
// Get vertex data for each mesh
|
||||
var meshes = model.LODs[0].Meshes;
|
||||
var meshesData = new SkinnedMesh.Vertex0[meshes.Length][];
|
||||
var bonesVertices = new List<SkinnedMesh.Vertex0>[bones.Length];
|
||||
var bonesVertices = new List<Float3>[bones.Length];
|
||||
var indicesLimit = new Int4(bones.Length - 1);
|
||||
for (int i = 0; i < meshes.Length; i++)
|
||||
{
|
||||
meshesData[i] = meshes[i].DownloadVertexBuffer0();
|
||||
|
||||
var meshData = meshes[i].DownloadVertexBuffer0();
|
||||
for (int j = 0; j < meshData.Length; j++)
|
||||
var assessor = new MeshAccessor();
|
||||
if (assessor.LoadMesh(meshes[i]))
|
||||
return;
|
||||
var positionStream = assessor.Position();
|
||||
var blendIndicesStream = assessor.BlendIndices();
|
||||
var blendWeightsStream = assessor.BlendWeights();
|
||||
if (!positionStream.IsValid || !blendIndicesStream.IsValid || !blendWeightsStream.IsValid)
|
||||
continue;
|
||||
var count = positionStream.Count;
|
||||
for (int j = 0; j < count; j++)
|
||||
{
|
||||
ref var v = ref meshData[j];
|
||||
var weights = (Float4)v.BlendWeights;
|
||||
var indices = Int4.Min((Int4)v.BlendIndices, indicesLimit);
|
||||
var weights = blendWeightsStream.GetFloat4(j);
|
||||
var indices = Int4.Min((Int4)blendIndicesStream.GetFloat4(j), indicesLimit);
|
||||
|
||||
// Find the bone with the highest influence on the vertex
|
||||
var maxWeightIndex = 0;
|
||||
@@ -104,17 +108,18 @@ namespace FlaxEditor.SceneGraph.Actors
|
||||
var maxWeightBone = indices[maxWeightIndex];
|
||||
|
||||
// Skin vertex position with the current pose
|
||||
Float3.Transform(ref v.Position, ref skinningMatrices[indices[0]], out Float3 pos0);
|
||||
Float3.Transform(ref v.Position, ref skinningMatrices[indices[1]], out Float3 pos1);
|
||||
Float3.Transform(ref v.Position, ref skinningMatrices[indices[2]], out Float3 pos2);
|
||||
Float3.Transform(ref v.Position, ref skinningMatrices[indices[3]], out Float3 pos3);
|
||||
v.Position = pos0 * weights[0] + pos1 * weights[1] + pos2 * weights[2] + pos3 * weights[3];
|
||||
var position = positionStream.GetFloat3(j);
|
||||
Float3.Transform(ref position, ref skinningMatrices[indices[0]], out Float3 pos0);
|
||||
Float3.Transform(ref position, ref skinningMatrices[indices[1]], out Float3 pos1);
|
||||
Float3.Transform(ref position, ref skinningMatrices[indices[2]], out Float3 pos2);
|
||||
Float3.Transform(ref position, ref skinningMatrices[indices[3]], out Float3 pos3);
|
||||
position = pos0 * weights[0] + pos1 * weights[1] + pos2 * weights[2] + pos3 * weights[3];
|
||||
|
||||
// Add vertex to the bone list
|
||||
ref var boneVertices = ref bonesVertices[maxWeightBone];
|
||||
if (boneVertices == null)
|
||||
boneVertices = new List<SkinnedMesh.Vertex0>();
|
||||
boneVertices.Add(v);
|
||||
boneVertices = new List<Float3>();
|
||||
boneVertices.Add(position);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -128,10 +133,10 @@ namespace FlaxEditor.SceneGraph.Actors
|
||||
continue; // Skip not used bones
|
||||
|
||||
// Compute bounds of the vertices using this bone (in local space of the actor)
|
||||
Float3 boneBoundsMin = boneVertices[0].Position, boneBoundsMax = boneVertices[0].Position;
|
||||
Float3 boneBoundsMin = boneVertices[0], boneBoundsMax = boneVertices[0];
|
||||
for (int i = 1; i < boneVertices.Count; i++)
|
||||
{
|
||||
var pos = boneVertices[i].Position;
|
||||
var pos = boneVertices[i];
|
||||
boneBoundsMin = Float3.Min(boneBoundsMin, pos);
|
||||
boneBoundsMax = Float3.Max(boneBoundsMax, pos);
|
||||
}
|
||||
@@ -165,10 +170,10 @@ namespace FlaxEditor.SceneGraph.Actors
|
||||
var boneBounds = BoundingBox.Zero;
|
||||
if (boneVertices != null)
|
||||
{
|
||||
boneBounds = new BoundingBox(boneVertices[0].Position, boneVertices[0].Position);
|
||||
boneBounds = new BoundingBox(boneVertices[0], boneVertices[0]);
|
||||
for (int i = 1; i < boneVertices.Count; i++)
|
||||
{
|
||||
var pos = boneVertices[i].Position;
|
||||
var pos = boneVertices[i];
|
||||
boneBounds.Minimum = Float3.Min(boneBounds.Minimum, pos);
|
||||
boneBounds.Minimum = Float3.Max(boneBounds.Maximum, pos);
|
||||
}
|
||||
@@ -263,7 +268,7 @@ namespace FlaxEditor.SceneGraph.Actors
|
||||
var boneLocalBounds = BoundingBox.Zero;
|
||||
for (int i = 0; i < boneVertices.Count; i++)
|
||||
{
|
||||
var pos = boneTransform.WorldToLocal(boneVertices[i].Position);
|
||||
var pos = boneTransform.WorldToLocal(boneVertices[i]);
|
||||
Vector3.Min(ref boneLocalBounds.Minimum, ref pos, out boneLocalBounds.Minimum);
|
||||
Vector3.Max(ref boneLocalBounds.Maximum, ref pos, out boneLocalBounds.Maximum);
|
||||
}
|
||||
@@ -360,20 +365,20 @@ namespace FlaxEditor.SceneGraph.Actors
|
||||
Editor.Instance.Scene.MarkSceneEdited(actor.Scene);
|
||||
}
|
||||
|
||||
private static unsafe Matrix CalculateCovarianceMatrix(List<SkinnedMesh.Vertex0> vertices)
|
||||
private static unsafe Matrix CalculateCovarianceMatrix(List<Float3> vertices)
|
||||
{
|
||||
// [Reference: https://en.wikipedia.org/wiki/Covariance_matrix]
|
||||
|
||||
// Calculate average point
|
||||
var avg = Float3.Zero;
|
||||
for (int i = 0; i < vertices.Count; i++)
|
||||
avg += vertices[i].Position;
|
||||
avg += vertices[i];
|
||||
avg /= vertices.Count;
|
||||
|
||||
// Calculate distance to average for every point
|
||||
var errors = new Float3[vertices.Count];
|
||||
for (int i = 0; i < vertices.Count; i++)
|
||||
errors[i] = vertices[i].Position - avg;
|
||||
errors[i] = vertices[i] - avg;
|
||||
|
||||
var covariance = Matrix.Identity;
|
||||
var cj = stackalloc float[3];
|
||||
@@ -393,15 +398,9 @@ namespace FlaxEditor.SceneGraph.Actors
|
||||
var row = new Float4(cj[0], cj[1], cj[2], 0.0f);
|
||||
switch (j)
|
||||
{
|
||||
case 0:
|
||||
covariance.Row1 = row;
|
||||
break;
|
||||
case 1:
|
||||
covariance.Row2 = row;
|
||||
break;
|
||||
case 2:
|
||||
covariance.Row3 = row;
|
||||
break;
|
||||
case 0: covariance.Row1 = row; break;
|
||||
case 1: covariance.Row2 = row; break;
|
||||
case 2: covariance.Row3 = row; break;
|
||||
}
|
||||
}
|
||||
return covariance;
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace FlaxEditor.SceneGraph.Actors
|
||||
[HideInEditor]
|
||||
public sealed class StaticModelNode : ActorNode
|
||||
{
|
||||
private Dictionary<IntPtr, Mesh.Vertex[]> _vertices;
|
||||
private Dictionary<IntPtr, Float3[]> _vertices;
|
||||
|
||||
/// <inheritdoc />
|
||||
public StaticModelNode(Actor actor)
|
||||
@@ -53,14 +53,17 @@ namespace FlaxEditor.SceneGraph.Actors
|
||||
var key = FlaxEngine.Object.GetUnmanagedPtr(mesh);
|
||||
if (!_vertices.TryGetValue(key, out var verts))
|
||||
{
|
||||
verts = mesh.DownloadVertexBuffer();
|
||||
var accessor = new MeshAccessor();
|
||||
if (accessor.LoadMesh(mesh))
|
||||
continue;
|
||||
verts = accessor.Positions;
|
||||
if (verts == null)
|
||||
continue;
|
||||
_vertices.Add(key, verts);
|
||||
}
|
||||
for (int i = 0; i < verts.Length; i++)
|
||||
{
|
||||
var v = verts[i].Position;
|
||||
ref var v = ref verts[i];
|
||||
var distance = Float3.DistanceSquared(ref pointLocal, ref v);
|
||||
if (distance <= minDistance)
|
||||
{
|
||||
|
||||
@@ -586,7 +586,7 @@ bool ScriptsBuilderService::Init()
|
||||
auto project = Editor::Project;
|
||||
HashSet<ProjectInfo*> projects;
|
||||
project->GetAllProjects(projects);
|
||||
for (auto e : projects)
|
||||
for (const auto& e : projects)
|
||||
{
|
||||
ProjectInfo* project = e.Item;
|
||||
if (project->Name == TEXT("Flax"))
|
||||
|
||||
@@ -919,6 +919,17 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
_selectedAnimation.SelectedIndex = 0;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void SetValuesPaste(object[] values)
|
||||
{
|
||||
// Fix Guids pasted as string
|
||||
// TODO: let copy/paste system in Visject handle value types to be strongly typed
|
||||
for (int i = 5; i < values.Length; i += 2)
|
||||
values[i] = Guid.Parse((string)values[i]);
|
||||
|
||||
base.SetValuesPaste(values);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnValuesChanged()
|
||||
{
|
||||
|
||||
@@ -225,8 +225,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
/// <inheritdoc />
|
||||
public override void OnDestroy()
|
||||
{
|
||||
if (Surface != null)
|
||||
Surface.RemoveContext(this);
|
||||
Surface?.RemoveContext(this);
|
||||
|
||||
_maxTransitionsPerUpdate = null;
|
||||
_reinitializeOnBecomingRelevant = null;
|
||||
@@ -717,9 +716,12 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
|
||||
LoadTransitions();
|
||||
|
||||
// Register for surface mouse events to handle transition arrows interactions
|
||||
Surface.CustomMouseUp += OnSurfaceMouseUp;
|
||||
Surface.CustomMouseDoubleClick += OnSurfaceMouseDoubleClick;
|
||||
if (Surface != null)
|
||||
{
|
||||
// Register for surface mouse events to handle transition arrows interactions
|
||||
Surface.CustomMouseUp += OnSurfaceMouseUp;
|
||||
Surface.CustomMouseDoubleClick += OnSurfaceMouseDoubleClick;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnSurfaceMouseUp(ref Float2 mouse, MouseButton buttons, ref bool handled)
|
||||
@@ -1398,7 +1400,8 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
if (context.FindNode(9, 21) == null)
|
||||
{
|
||||
var wasEnabled = true;
|
||||
if (Surface.Undo != null)
|
||||
var undo = Surface?.Undo;
|
||||
if (undo != null)
|
||||
{
|
||||
wasEnabled = Surface.Undo.Enabled;
|
||||
Surface.Undo.Enabled = false;
|
||||
@@ -1406,7 +1409,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
|
||||
context.SpawnNode(9, 21, new Float2(100.0f));
|
||||
|
||||
if (Surface.Undo != null)
|
||||
if (undo != null)
|
||||
{
|
||||
Surface.Undo.Enabled = wasEnabled;
|
||||
}
|
||||
@@ -1492,7 +1495,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
/// <inheritdoc />
|
||||
public override void OnDestroy()
|
||||
{
|
||||
Surface.RemoveContext(this);
|
||||
Surface?.RemoveContext(this);
|
||||
|
||||
base.OnDestroy();
|
||||
}
|
||||
@@ -1886,7 +1889,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
if (context.FindNode(9, 22) == null)
|
||||
{
|
||||
var wasEnabled = true;
|
||||
var undo = SourceState.Surface.Undo;
|
||||
var undo = SourceState.Surface?.Undo;
|
||||
if (undo != null)
|
||||
{
|
||||
wasEnabled = undo.Enabled;
|
||||
|
||||
@@ -15,6 +15,29 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
[HideInEditor]
|
||||
public static class Material
|
||||
{
|
||||
/// <summary>
|
||||
/// Blend modes (each enum item value maps to box ID).
|
||||
/// </summary>
|
||||
internal enum BlendMode
|
||||
{
|
||||
Normal,
|
||||
Add,
|
||||
Subtract,
|
||||
Multiply,
|
||||
Screen,
|
||||
Overlay,
|
||||
LinearBurn,
|
||||
LinearLight,
|
||||
Darken,
|
||||
Lighten,
|
||||
Difference,
|
||||
Exclusion,
|
||||
Divide,
|
||||
HardLight,
|
||||
PinLight,
|
||||
HardMix
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Customized <see cref="SurfaceNode"/> for main material node.
|
||||
/// </summary>
|
||||
@@ -1073,6 +1096,49 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
NodeElementArchetype.Factory.Output(0, string.Empty, typeof(Float3), 4),
|
||||
]
|
||||
},
|
||||
new NodeArchetype
|
||||
{
|
||||
TypeID = 50,
|
||||
Title = "Shift HSV",
|
||||
Description = "Modifies the HSV of a color, values are from -1:1, preserves alpha",
|
||||
Flags = NodeFlags.MaterialGraph,
|
||||
Size = new Float2(175, 80),
|
||||
DefaultValues =
|
||||
[
|
||||
0.0f, // For Hue (index 0)
|
||||
0.0f, // For Sat (index 1)
|
||||
0.0f, // For Val (index 2)
|
||||
],
|
||||
Elements =
|
||||
[
|
||||
NodeElementArchetype.Factory.Input(0, "RGBA", true, typeof(Float4), 0), // No default
|
||||
NodeElementArchetype.Factory.Input(1, "Hue", true, typeof(float), 1, 0), // Uses DefaultValues[0]
|
||||
NodeElementArchetype.Factory.Input(2, "Sat", true, typeof(float), 2, 1), // Uses DefaultValues[1]
|
||||
NodeElementArchetype.Factory.Input(3, "Val", true, typeof(float), 3, 2), // Uses DefaultValues[2]
|
||||
NodeElementArchetype.Factory.Output(0, "RGBA", typeof(Float4), 4),
|
||||
]
|
||||
},
|
||||
new NodeArchetype
|
||||
{
|
||||
TypeID = 51,
|
||||
Title = "Color Blend",
|
||||
Description = "Blends two colors using various blend modes. Passes base alpha through.",
|
||||
Flags = NodeFlags.MaterialGraph,
|
||||
Size = new Float2(180, 80),
|
||||
DefaultValues = new object[]
|
||||
{
|
||||
BlendMode.Normal, // Default blend mode
|
||||
1.0f, // Default blend amount
|
||||
},
|
||||
Elements = new[]
|
||||
{
|
||||
NodeElementArchetype.Factory.Input(1, "Base Color", true, typeof(Float4), 0),
|
||||
NodeElementArchetype.Factory.Input(2, "Blend Color", true, typeof(Float4), 1),
|
||||
NodeElementArchetype.Factory.Input(3, "Intensity", true, typeof(float), 2, 1),
|
||||
NodeElementArchetype.Factory.Enum(0, 0, 120, 0, typeof(BlendMode)), // Blend mode selector
|
||||
NodeElementArchetype.Factory.Output(0, "Result", typeof(Float4), 3),
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,9 +123,15 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
AlternativeTitles = new string[] { "UV", "UVs" },
|
||||
Description = "Texture coordinates",
|
||||
Flags = NodeFlags.MaterialGraph,
|
||||
Size = new Float2(110, 30),
|
||||
Size = new Float2(150, 30),
|
||||
DefaultValues = new object[]
|
||||
{
|
||||
0u
|
||||
},
|
||||
Elements = new[]
|
||||
{
|
||||
NodeElementArchetype.Factory.Text(0, 1, "Channel:"),
|
||||
NodeElementArchetype.Factory.UnsignedInteger(50, 0, 0, -1, 0, 3),
|
||||
NodeElementArchetype.Factory.Output(0, "UVs", typeof(Float2), 0)
|
||||
}
|
||||
},
|
||||
@@ -396,21 +402,29 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
new NodeArchetype
|
||||
{
|
||||
TypeID = 16,
|
||||
Title = "World Triplanar Texture",
|
||||
Description = "Projects a texture using world-space coordinates instead of UVs.",
|
||||
Title = "Triplanar Texture",
|
||||
Description = "Projects a texture using world-space coordinates with triplanar mapping.",
|
||||
Flags = NodeFlags.MaterialGraph,
|
||||
Size = new Float2(240, 60),
|
||||
Size = new Float2(280, 100),
|
||||
DefaultValues = new object[]
|
||||
{
|
||||
1.0f,
|
||||
1.0f
|
||||
1.0f, // Scale
|
||||
1.0f, // Blend
|
||||
Float2.Zero, // Offset
|
||||
2, // Sampler
|
||||
false, // Local
|
||||
},
|
||||
Elements = new[]
|
||||
{
|
||||
NodeElementArchetype.Factory.Input(0, "Texture", true, typeof(FlaxEngine.Object), 0),
|
||||
NodeElementArchetype.Factory.Input(1, "Scale", true, typeof(Float4), 1, 0),
|
||||
NodeElementArchetype.Factory.Input(1, "Scale", true, typeof(float), 1, 0),
|
||||
NodeElementArchetype.Factory.Input(2, "Blend", true, typeof(float), 2, 1),
|
||||
NodeElementArchetype.Factory.Output(0, "Color", typeof(Float4), 3)
|
||||
NodeElementArchetype.Factory.Input(3, "Offset", true, typeof(Float2), 3, 2),
|
||||
NodeElementArchetype.Factory.Output(0, "Color", typeof(Float4), 5),
|
||||
NodeElementArchetype.Factory.Text(0, Surface.Constants.LayoutOffsetY * 4, "Sampler"),
|
||||
NodeElementArchetype.Factory.ComboBox(50, Surface.Constants.LayoutOffsetY * 4 - 1, 100, 3, typeof(CommonSamplerType)),
|
||||
NodeElementArchetype.Factory.Text(155, Surface.Constants.LayoutOffsetY * 4, "Local"),
|
||||
NodeElementArchetype.Factory.Bool(190, Surface.Constants.LayoutOffsetY * 4, 4),
|
||||
}
|
||||
},
|
||||
new NodeArchetype
|
||||
@@ -450,7 +464,35 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
{
|
||||
NodeElementArchetype.Factory.Output(0, "UVs", typeof(Float2), 0)
|
||||
}
|
||||
}
|
||||
},
|
||||
new NodeArchetype
|
||||
{
|
||||
TypeID = 23,
|
||||
Title = "Triplanar Normal Map",
|
||||
Description = "Projects a normal map texture using world-space coordinates with triplanar mapping.",
|
||||
Flags = NodeFlags.MaterialGraph,
|
||||
Size = new Float2(280, 100),
|
||||
DefaultValues = new object[]
|
||||
{
|
||||
1.0f, // Scale
|
||||
1.0f, // Blend
|
||||
Float2.Zero, // Offset
|
||||
2, // Sampler
|
||||
false, // Local
|
||||
},
|
||||
Elements = new[]
|
||||
{
|
||||
NodeElementArchetype.Factory.Input(0, "Texture", true, typeof(FlaxEngine.Object), 0),
|
||||
NodeElementArchetype.Factory.Input(1, "Scale", true, typeof(float), 1, 0),
|
||||
NodeElementArchetype.Factory.Input(2, "Blend", true, typeof(float), 2, 1),
|
||||
NodeElementArchetype.Factory.Input(3, "Offset", true, typeof(Float2), 3, 2),
|
||||
NodeElementArchetype.Factory.Output(0, "Vector", typeof(Float3), 5),
|
||||
NodeElementArchetype.Factory.Text(0, Surface.Constants.LayoutOffsetY * 4, "Sampler"),
|
||||
NodeElementArchetype.Factory.ComboBox(50, Surface.Constants.LayoutOffsetY * 4 - 1, 100, 3, typeof(CommonSamplerType)),
|
||||
NodeElementArchetype.Factory.Text(155, Surface.Constants.LayoutOffsetY * 4, "Local"),
|
||||
NodeElementArchetype.Factory.Bool(190, Surface.Constants.LayoutOffsetY * 4, 4),
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1499,12 +1499,12 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
2,
|
||||
|
||||
// Stop 0
|
||||
0.1f,
|
||||
Color.CornflowerBlue,
|
||||
0.05f,
|
||||
Color.Black,
|
||||
|
||||
// Stop 1
|
||||
0.9f,
|
||||
Color.GreenYellow,
|
||||
0.95f,
|
||||
Color.White,
|
||||
|
||||
// Empty stops 2-7
|
||||
0.0f, Color.Black,
|
||||
|
||||
@@ -759,7 +759,7 @@ namespace FlaxEditor.Surface.ContextMenu
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Show(Control parent, Float2 location)
|
||||
public override void Show(Control parent, Float2 location, ContextMenuDirection? direction = null)
|
||||
{
|
||||
Show(parent, location, null);
|
||||
}
|
||||
|
||||
@@ -147,6 +147,11 @@ namespace FlaxEditor.Surface.Elements
|
||||
{
|
||||
value = (double)toSet;
|
||||
}
|
||||
else if (parentNode.GroupArchetype.GroupID != 2)
|
||||
{
|
||||
// Per-component editing is used only by nodes from Constant group, otherwise use float
|
||||
value = toSet;
|
||||
}
|
||||
else if (value is Vector2 asVector2)
|
||||
{
|
||||
if (arch.BoxID == 0)
|
||||
|
||||
@@ -87,7 +87,7 @@ namespace FlaxEditor.Surface
|
||||
Title = TitleValue;
|
||||
Color = ColorValue;
|
||||
var size = SizeValue;
|
||||
if (Surface.GridSnappingEnabled)
|
||||
if (Surface != null && Surface.GridSnappingEnabled)
|
||||
size = Surface.SnapToGrid(size, true);
|
||||
Size = size;
|
||||
|
||||
|
||||
@@ -1001,6 +1001,15 @@ namespace FlaxEditor.Surface
|
||||
_isDuringValuesEditing = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets teh node values from the given pasted source. Can be overriden to perform validation or custom values processing.
|
||||
/// </summary>
|
||||
/// <param name="values">The input values array.</param>
|
||||
public virtual void SetValuesPaste(object[] values)
|
||||
{
|
||||
Values = values;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when node values set gets changed.
|
||||
/// </summary>
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using FlaxEditor.Surface.Undo;
|
||||
using FlaxEngine;
|
||||
|
||||
namespace FlaxEditor.Surface
|
||||
{
|
||||
@@ -57,6 +57,28 @@ namespace FlaxEditor.Surface
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Opens the surface context with the given owning nodes IDs path.
|
||||
/// </summary>
|
||||
/// <param name="nodePath">The node ids path.</param>
|
||||
/// <returns>Found context or null if cannot.</returns>
|
||||
public VisjectSurfaceContext OpenContext(Span<uint> nodePath)
|
||||
{
|
||||
OpenContext(RootContext.Context);
|
||||
if (nodePath != null && nodePath.Length != 0)
|
||||
{
|
||||
for (int i = 0; i < nodePath.Length; i++)
|
||||
{
|
||||
var node = Context.FindNode(nodePath[i]);
|
||||
if (node is ISurfaceContext context)
|
||||
OpenContext(context);
|
||||
else
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return Context;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the Visject surface context for the given surface data source context.
|
||||
/// </summary>
|
||||
@@ -101,7 +123,12 @@ namespace FlaxEditor.Surface
|
||||
if (_root == null)
|
||||
_root = surfaceContext;
|
||||
else if (ContextStack.Contains(surfaceContext))
|
||||
throw new ArgumentException("Context has been already added to the stack.");
|
||||
{
|
||||
// Go up until the given context
|
||||
while (ContextStack.First() != surfaceContext)
|
||||
CloseContext();
|
||||
return;
|
||||
}
|
||||
|
||||
// Change stack
|
||||
ContextStack.Push(surfaceContext);
|
||||
|
||||
@@ -286,13 +286,14 @@ namespace FlaxEditor.Surface
|
||||
// Initialize
|
||||
if (nodeData.Values != null && node.Values.Length > 0)
|
||||
{
|
||||
if (node.Values != null && node.Values.Length == nodeData.Values.Length)
|
||||
var nodeValues = (object[])node.Values?.Clone();
|
||||
if (nodeValues != null && nodeValues.Length == nodeData.Values.Length)
|
||||
{
|
||||
// Copy and fix values (Json deserializes may output them in a different format)
|
||||
for (int l = 0; l < node.Values.Length; l++)
|
||||
for (int l = 0; l < nodeData.Values.Length; l++)
|
||||
{
|
||||
var src = nodeData.Values[l].Value;
|
||||
var dst = node.Values[l];
|
||||
var dst = nodeValues[l];
|
||||
|
||||
try
|
||||
{
|
||||
@@ -364,13 +365,24 @@ namespace FlaxEditor.Surface
|
||||
Editor.LogWarning(ex);
|
||||
}
|
||||
|
||||
node.Values[l] = src;
|
||||
nodeValues[l] = src;
|
||||
}
|
||||
}
|
||||
else if (node.Archetype.Flags.HasFlag(NodeFlags.VariableValuesSize))
|
||||
{
|
||||
// Copy values
|
||||
nodeValues = new object[nodeData.Values.Length];
|
||||
for (int l = 0; l < nodeData.Values.Length; l++)
|
||||
{
|
||||
nodeValues[l] = nodeData.Values[l].Value;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Editor.LogWarning("Invalid node custom values.");
|
||||
}
|
||||
if (nodeValues != null)
|
||||
node.SetValuesPaste(nodeValues);
|
||||
}
|
||||
|
||||
Context.OnControlLoaded(node, SurfaceNodeActions.Paste);
|
||||
@@ -445,7 +457,8 @@ namespace FlaxEditor.Surface
|
||||
// Select those nodes
|
||||
Select(nodes.Values);
|
||||
|
||||
MarkAsEdited();
|
||||
if (nodes.Count > 0)
|
||||
MarkAsEdited();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user