2 Commits

Author SHA1 Message Date
c6bc90a82a _lagdriver fixes
Some checks failed
Build Android / Game (Android, Release ARM64) (push) Has been cancelled
Build iOS / Game (iOS, Release ARM64) (push) Has been cancelled
Build Linux / Editor (Linux, Development x64) (push) Has been cancelled
Build Linux / Game (Linux, Release x64) (push) Has been cancelled
Build macOS / Editor (Mac, Development ARM64) (push) Has been cancelled
Build macOS / Game (Mac, Release ARM64) (push) Has been cancelled
Build Windows / Editor (Windows, Development x64) (push) Has been cancelled
Build Windows / Game (Windows, Release x64) (push) Has been cancelled
Cooker / Cook (Mac) (push) Has been cancelled
Tests / Tests (Linux) (push) Has been cancelled
Tests / Tests (Windows) (push) Has been cancelled
2025-09-12 13:52:55 +03:00
43b576d961 Add support for Visual Studio 2026 and v145 MSVC toolset
Some checks failed
Build Android / Game (Android, Release ARM64) (push) Has been cancelled
Build iOS / Game (iOS, Release ARM64) (push) Has been cancelled
Build Linux / Editor (Linux, Development x64) (push) Has been cancelled
Build Linux / Game (Linux, Release x64) (push) Has been cancelled
Build macOS / Editor (Mac, Development ARM64) (push) Has been cancelled
Build macOS / Game (Mac, Release ARM64) (push) Has been cancelled
Build Windows / Editor (Windows, Development x64) (push) Has been cancelled
Build Windows / Game (Windows, Release x64) (push) Has been cancelled
Cooker / Cook (Mac) (push) Has been cancelled
Tests / Tests (Linux) (push) Has been cancelled
Tests / Tests (Windows) (push) Has been cancelled
2025-09-10 20:05:28 +03:00
1440 changed files with 16609 additions and 158146 deletions

View File

@@ -1,42 +0,0 @@
name: Bug Report
description: File a bug report.
title: "[Bug]: "
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to fill out this bug report! Please attach a minimal reproduction project if available!
- type: textarea
id: description-area
attributes:
label: Description
description: Please provide a description of the bug and what you expected to happen.
validations:
required: true
- type: textarea
id: steps-area
attributes:
label: Steps to reproduce
description: Please provide reproduction steps if available.
validations:
required: true
- type: dropdown
id: version
attributes:
label: Version
description: What version of Flax did you experience the bug in?
options:
- '1.9'
- '1.10'
- '1.11'
- '1.12'
- master branch
default: 3
validations:
required: true
- type: textarea
id: logs
attributes:
label: Relevant logs
description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks.
render: shell

View File

@@ -1,22 +0,0 @@
name: Feature Request
description: File a feature request.
title: "[Request]: "
body:
- type: markdown
attributes:
value: |
Thank you for taking the time to submit this feature request!
- type: textarea
id: description-area
attributes:
label: Description
description: Please provide a description of the feature!
validations:
required: true
- type: textarea
id: benefits-area
attributes:
label: Benefits
description: Please list what benefits this feature would provide to the engine!
validations:
required: true

18
.github/data/bt.sh vendored
View File

@@ -1,18 +0,0 @@
#!/bin/sh
# https://gist.github.com/ongardie/aa15f1f0d0e6b59890a9
gdb -q --batch \
-ex 'handle SIGHUP nostop pass' \
-ex 'handle SIGQUIT nostop pass' \
-ex 'handle SIGPIPE nostop pass' \
-ex 'handle SIGALRM nostop pass' \
-ex 'handle SIGTERM nostop pass' \
-ex 'handle SIGUSR1 nostop pass' \
-ex 'handle SIGUSR2 nostop pass' \
-ex 'handle SIGCHLD nostop pass' \
-ex 'handle SIG34 nostop pass' \
-ex 'set print thread-events off' \
-return-child-result \
-ex 'run' \
-ex 'thread apply all bt' \
--tty=/dev/stdout \
--args $*

View File

@@ -4,7 +4,6 @@ on: [push, pull_request]
env:
DOTNET_NOLOGO: true
DOTNET_CLI_TELEMETRY_OPTOUT: false
DOTNET_ROLL_FORWARD: 'minor'
jobs:
@@ -20,7 +19,7 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v3
with:
dotnet-version: 8.0.419
dotnet-version: 8.0.x
- name: Setup .NET Workload
run: |
dotnet workload install android
@@ -34,7 +33,4 @@ jobs:
git lfs pull
- name: Build
run: |
PowerShell "(Get-Content global.json).Replace('latestMajor', 'minor') | Set-Content global.json"
PowerShell "(Get-Content Source/Tools/Flax.Build/global.json).Replace('latestMajor', 'minor') | Set-Content Source/Tools/Flax.Build/global.json"
PowerShell "(Get-Content Source/Tools/Flax.Build/Flax.Build.csproj).Replace('LatestMajor', 'Minor') | Set-Content Source/Tools/Flax.Build/Flax.Build.csproj"
.\Development\Scripts\Windows\CallBuildTool.bat -build -log -printSDKs -dotnet=8 -arch=ARM64 -platform=Android -configuration=Release -buildtargets=FlaxGame

View File

@@ -19,7 +19,7 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v3
with:
dotnet-version: 9.0.x
dotnet-version: 8.0.x
- name: Setup .NET Workload
run: |
dotnet workload install ios
@@ -33,4 +33,4 @@ jobs:
git lfs pull
- name: Build
run: |
./Development/Scripts/Mac/CallBuildTool.sh -build -log -dotnet=9 -arch=ARM64 -platform=iOS -configuration=Release -buildtargets=FlaxGame
./Development/Scripts/Mac/CallBuildTool.sh -build -log -dotnet=8 -arch=ARM64 -platform=iOS -configuration=Release -buildtargets=FlaxGame

View File

@@ -16,8 +16,7 @@ jobs:
uses: actions/checkout@v3
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y --fix-missing libx11-dev libxcursor-dev libxinerama-dev build-essential gettext libtool libtool-bin libpulse-dev libasound2-dev libjack-dev portaudio19-dev libwayland-dev
sudo apt-get install libx11-dev libxcursor-dev libxinerama-dev build-essential gettext libtool libtool-bin libpulse-dev libasound2-dev libjack-dev portaudio19-dev libwayland-dev
- name: Setup Vulkan
uses: ./.github/actions/vulkan
- name: Setup .NET
@@ -45,8 +44,7 @@ jobs:
uses: actions/checkout@v3
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y --fix-missing libx11-dev libxcursor-dev libxinerama-dev build-essential gettext libtool libtool-bin libpulse-dev libasound2-dev libjack-dev portaudio19-dev libwayland-dev
sudo apt-get install libx11-dev libxcursor-dev libxinerama-dev libwayland-dev
- name: Setup Vulkan
uses: ./.github/actions/vulkan
- name: Setup .NET

View File

@@ -4,7 +4,6 @@ on: [push, pull_request]
env:
DOTNET_NOLOGO: true
DOTNET_CLI_TELEMETRY_OPTOUT: false
DOTNET_ROLL_FORWARD: 'minor'
jobs:
@@ -20,7 +19,7 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v3
with:
dotnet-version: 8.0.419
dotnet-version: 8.0.x
- name: Print .NET info
run: |
dotnet --info
@@ -31,9 +30,6 @@ jobs:
git lfs pull
- name: Build
run: |
PowerShell "(Get-Content global.json).Replace('latestMajor', 'minor') | Set-Content global.json"
PowerShell "(Get-Content Source/Tools/Flax.Build/global.json).Replace('latestMajor', 'minor') | Set-Content Source/Tools/Flax.Build/global.json"
PowerShell "(Get-Content Source/Tools/Flax.Build/Flax.Build.csproj).Replace('LatestMajor', 'Minor') | Set-Content Source/Tools/Flax.Build/Flax.Build.csproj"
.\Development\Scripts\Windows\CallBuildTool.bat -build -log -printSDKs -dotnet=8 -arch=x64 -platform=Windows -configuration=Development -buildtargets=FlaxEditor
# Game
@@ -48,7 +44,7 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v3
with:
dotnet-version: 8.0.419
dotnet-version: 8.0.x
- name: Print .NET info
run: |
dotnet --info
@@ -59,7 +55,4 @@ jobs:
git lfs pull
- name: Build
run: |
PowerShell "(Get-Content global.json).Replace('latestMajor', 'minor') | Set-Content global.json"
PowerShell "(Get-Content Source/Tools/Flax.Build/global.json).Replace('latestMajor', 'minor') | Set-Content Source/Tools/Flax.Build/global.json"
PowerShell "(Get-Content Source/Tools/Flax.Build/Flax.Build.csproj).Replace('LatestMajor', 'Minor') | Set-Content Source/Tools/Flax.Build/Flax.Build.csproj"
.\Development\Scripts\Windows\CallBuildTool.bat -build -log -printSDKs -dotnet=8 -arch=x64 -platform=Windows -configuration=Release -buildtargets=FlaxGame

View File

@@ -7,7 +7,6 @@ on:
env:
DOTNET_NOLOGO: true
DOTNET_CLI_TELEMETRY_OPTOUT: false
DOTNET_ROLL_FORWARD: 'minor'
GIT_LFS_PULL_OPTIONS: '-c lfs.concurrenttransfers=1 -c lfs.transfer.maxretries=2 -c http.version="HTTP/1.1" -c lfs.activitytimeout=60'
jobs:
@@ -28,16 +27,13 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v3
with:
dotnet-version: 8.0.419
dotnet-version: 8.0.x
- name: Print .NET info
run: |
dotnet --info
dotnet workload --info
- name: Build
run: |
PowerShell "(Get-Content global.json).Replace('latestMajor', 'minor') | Set-Content global.json"
PowerShell "(Get-Content Source/Tools/Flax.Build/global.json).Replace('latestMajor', 'minor') | Set-Content Source/Tools/Flax.Build/global.json"
PowerShell "(Get-Content Source/Tools/Flax.Build/Flax.Build.csproj).Replace('LatestMajor', 'Minor') | Set-Content Source/Tools/Flax.Build/Flax.Build.csproj"
.\PackageEditor.bat -arch=x64 -platform=Windows -deployOutput=Output -dotnet=8
- name: Upload
uses: actions/upload-artifact@v4
@@ -64,16 +60,13 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v3
with:
dotnet-version: 8.0.419
dotnet-version: 8.0.x
- name: Print .NET info
run: |
dotnet --info
dotnet workload --info
- name: Build
run: |
PowerShell "(Get-Content global.json).Replace('latestMajor', 'minor') | Set-Content global.json"
PowerShell "(Get-Content Source/Tools/Flax.Build/global.json).Replace('latestMajor', 'minor') | Set-Content Source/Tools/Flax.Build/global.json"
PowerShell "(Get-Content Source/Tools/Flax.Build/Flax.Build.csproj).Replace('LatestMajor', 'Minor') | Set-Content Source/Tools/Flax.Build/Flax.Build.csproj"
.\PackagePlatforms.bat -arch=x64 -platform=Windows -deployOutput=Output -dotnet=8
- name: Upload
uses: actions/upload-artifact@v4
@@ -94,8 +87,7 @@ jobs:
git ${{ env.GIT_LFS_PULL_OPTIONS }} lfs pull
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y --fix-missing libx11-dev libxcursor-dev libxinerama-dev build-essential gettext libtool libtool-bin libpulse-dev libasound2-dev libjack-dev portaudio19-dev libwayland-dev
sudo apt-get install libx11-dev libxcursor-dev libxinerama-dev build-essential gettext libtool libtool-bin libpulse-dev libasound2-dev libjack-dev portaudio19-dev
- name: Setup Vulkan
uses: ./.github/actions/vulkan
- name: Setup .NET
@@ -126,8 +118,7 @@ jobs:
git ${{ env.GIT_LFS_PULL_OPTIONS }} lfs pull
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y --fix-missing libx11-dev libxcursor-dev libxinerama-dev build-essential gettext libtool libtool-bin libpulse-dev libasound2-dev libjack-dev portaudio19-dev libwayland-dev
sudo apt-get install libx11-dev libxcursor-dev libxinerama-dev build-essential gettext libtool libtool-bin libpulse-dev libasound2-dev libjack-dev portaudio19-dev
- name: Setup Vulkan
uses: ./.github/actions/vulkan
- name: Setup .NET

View File

@@ -4,7 +4,6 @@ on: [push, pull_request]
env:
DOTNET_NOLOGO: true
DOTNET_CLI_TELEMETRY_OPTOUT: false
DOTNET_ROLL_FORWARD: 'minor'
jobs:
@@ -29,23 +28,25 @@ jobs:
git lfs pull
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y --fix-missing libx11-dev libxcursor-dev libxinerama-dev build-essential gettext libtool libtool-bin libpulse-dev libasound2-dev libjack-dev portaudio19-dev libwayland-dev gdb
chmod +x .github/data/bt.sh
sudo apt-get install libx11-dev libxcursor-dev libxinerama-dev build-essential gettext libtool libtool-bin libpulse-dev libasound2-dev libjack-dev portaudio19-dev libwayland-dev
- name: Build
run: |
./GenerateProjectFiles.sh -vs2022 -log -verbose -printSDKs -dotnet=8
./Development/Scripts/Linux/CallBuildTool.sh -build -log -dotnet=8 -arch=x64 -platform=Linux -configuration=Development -buildtargets=FlaxTestsTarget -UseLargeWorlds=true
./Development/Scripts/Linux/CallBuildTool.sh -build -log -dotnet=8 -arch=x64 -platform=Linux -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
dotnet msbuild Source/Tools/Flax.Build.Tests/Flax.Build.Tests.csproj /m /t:Restore,Build /p:Configuration=Debug /p:Platform=AnyCPU /nologo
- name: Test
run: |
${GITHUB_WORKSPACE}/.github/data/bt.sh ./Binaries/Editor/Linux/Development/FlaxTests -headless
${GITHUB_WORKSPACE}/Binaries/Editor/Linux/Development/FlaxTests
dotnet test -f net8.0 Binaries/Tests/Flax.Build.Tests.dll
cp Binaries/Editor/Linux/Development/FlaxEngine.CSharp.dll Binaries/Tests
cp Binaries/Editor/Linux/Development/FlaxEngine.CSharp.runtimeconfig.json Binaries/Tests
cp Binaries/Editor/Linux/Development/Newtonsoft.Json.dll Binaries/Tests
dotnet test -f net8.0 Binaries/Tests/FlaxEngine.CSharp.dll
- name: Test UseLargeWorlds
run: |
./Development/Scripts/Linux/CallBuildTool.sh -build -log -dotnet=8 -arch=x64 -platform=Linux -configuration=Development -buildtargets=FlaxTestsTarget -UseLargeWorlds=true
${GITHUB_WORKSPACE}/Binaries/Editor/Linux/Development/FlaxTests
# Tests on Windows
tests-windows:
@@ -57,7 +58,7 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v3
with:
dotnet-version: 8.0.419
dotnet-version: 8.0.x
- name: Print .NET info
run: |
dotnet --info
@@ -68,9 +69,6 @@ jobs:
git lfs pull
- name: Build
run: |
PowerShell "(Get-Content global.json).Replace('latestMajor', 'minor') | Set-Content global.json"
PowerShell "(Get-Content Source/Tools/Flax.Build/global.json).Replace('latestMajor', 'minor') | Set-Content Source/Tools/Flax.Build/global.json"
PowerShell "(Get-Content Source/Tools/Flax.Build/Flax.Build.csproj).Replace('LatestMajor', 'Minor') | Set-Content Source/Tools/Flax.Build/Flax.Build.csproj"
.\GenerateProjectFiles.bat -vs2022 -log -verbose -printSDKs -dotnet=8
.\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
@@ -78,7 +76,7 @@ jobs:
shell: pwsh
run: |
$ErrorActionPreference = "Stop"
.\Binaries\Editor\Win64\Development\FlaxTests.exe -headless
.\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

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -6,7 +6,6 @@
@3
#include "./Flax/Common.hlsl"
#include "./Flax/Stencil.hlsl"
#include "./Flax/MaterialCommon.hlsl"
#include "./Flax/GBufferCommon.hlsl"
@7
@@ -15,13 +14,10 @@ META_CB_BEGIN(0, Data)
float4x4 WorldMatrix;
float4x4 InvWorld;
float4x4 SvPositionToWorld;
float3 Padding0;
uint RenderLayersMask;
@1META_CB_END
// Use depth buffer for per-pixel decal layering
Texture2D DepthBuffer : register(t0);
Texture2D<uint2> StencilBuffer : register(t1);
// Material shader resources
@2
@@ -42,10 +38,10 @@ struct MaterialInput
float2 SvPositionToDecalUV(float4 svPosition)
{
float2 screenUV = svPosition.xy * ScreenSize.zw;
svPosition.z = SAMPLE_RT_DEPTH(DepthBuffer, screenUV);
float4 positionHS = PROJECT_POINT(float4(svPosition.xyz, 1), SvPositionToWorld);
svPosition.z = SAMPLE_RT(DepthBuffer, screenUV).r;
float4 positionHS = mul(float4(svPosition.xyz, 1), SvPositionToWorld);
float3 positionWS = positionHS.xyz / positionHS.w;
float3 positionOS = PROJECT_POINT(float4(positionWS, 1), InvWorld).xyz;
float3 positionOS = mul(float4(positionWS, 1), InvWorld).xyz;
return positionOS.xz + 0.5f;
}
@@ -182,10 +178,10 @@ META_VS_IN_ELEMENT(POSITION, 0, R32G32B32_FLOAT, 0, 0, PER_VERTEX, 0, true)
void VS_Decal(in float3 Position : POSITION0, out float4 SvPosition : SV_Position)
{
// Compute world space vertex position
float3 worldPosition = PROJECT_POINT(float4(Position.xyz, 1), WorldMatrix).xyz;
float3 worldPosition = mul(float4(Position.xyz, 1), WorldMatrix).xyz;
// Compute clip space position
SvPosition = PROJECT_POINT(float4(worldPosition.xyz, 1), ViewProjectionMatrix);
SvPosition = mul(float4(worldPosition.xyz, 1), ViewProjectionMatrix);
}
// Pixel Shader function for decals rendering
@@ -204,20 +200,12 @@ void PS_Decal(
#endif
)
{
// Stencil masking
uint stencilObjectLayer = STENCIL_BUFFER_OBJECT_LAYER(STENCIL_BUFFER_LOAD(StencilBuffer, SvPosition.xy));
if ((RenderLayersMask & (1 << stencilObjectLayer)) == 0)
{
clip(-1);
return;
}
float2 screenUV = SvPosition.xy * ScreenSize.zw;
SvPosition.z = SAMPLE_RT_DEPTH(DepthBuffer, screenUV);
SvPosition.z = SAMPLE_RT(DepthBuffer, screenUV).r;
float4 positionHS = PROJECT_POINT(float4(SvPosition.xyz, 1), SvPositionToWorld);
float4 positionHS = mul(float4(SvPosition.xyz, 1), SvPositionToWorld);
float3 positionWS = positionHS.xyz / positionHS.w;
float3 positionOS = PROJECT_POINT(float4(positionWS, 1), InvWorld).xyz;
float3 positionOS = mul(float4(positionWS, 1), InvWorld).xyz;
clip(0.5 - abs(positionOS.xyz));
float2 decalUVs = positionOS.xz + 0.5f;

View File

@@ -308,7 +308,7 @@ VertexOutput VS_SplineModel(ModelInput input)
world = mul(world, WorldMatrix);
// Compute clip space position
output.Position = PROJECT_POINT(float4(output.Geometry.WorldPosition, 1), ViewProjectionMatrix);
output.Position = mul(float4(output.Geometry.WorldPosition, 1), ViewProjectionMatrix);
// Pass vertex attributes
output.Geometry.TexCoord = input.TexCoord0;
@@ -337,7 +337,8 @@ VertexOutput VS_SplineModel(ModelInput input)
// Apply world position offset per-vertex
#if USE_POSITION_OFFSET
output.Geometry.WorldPosition += material.PositionOffset;
output.Position = PROJECT_POINT(float4(output.Geometry.WorldPosition, 1), ViewProjectionMatrix);
output.Geometry.PrevWorldPosition += material.PositionOffset;
output.Position = mul(float4(output.Geometry.WorldPosition, 1), ViewProjectionMatrix);
#endif
// Get tessalation multiplier (per vertex)

View File

@@ -4,8 +4,8 @@
#define MAX_LOCAL_LIGHTS 4
@1// Forward Shading: Includes
#include "./Flax/LightingCommon.hlsl"
#include "./Flax/ReflectionsCommon.hlsl"
#if USE_REFLECTIONS
#include "./Flax/ReflectionsCommon.hlsl"
#define MATERIAL_REFLECTIONS_SSR 1
#if MATERIAL_REFLECTIONS == MATERIAL_REFLECTIONS_SSR
#include "./Flax/SSR.hlsl"
@@ -14,13 +14,11 @@
#include "./Flax/Lighting.hlsl"
#include "./Flax/ShadowsSampling.hlsl"
#include "./Flax/ExponentialHeightFog.hlsl"
#include "./Flax/VolumetricFog.hlsl"
@2// Forward Shading: Constants
LightData DirectionalLight;
LightData SkyLight;
EnvProbeData EnvironmentProbe;
ProbeData EnvironmentProbe;
ExponentialHeightFogData ExponentialHeightFog;
VolumetricFogData VolumetricFog;
float3 Dummy2;
uint LocalLightsCount;
LightData LocalLights[MAX_LOCAL_LIGHTS];
@@ -29,15 +27,12 @@ TextureCube EnvProbe : register(t__SRV__);
TextureCube SkyLightTexture : register(t__SRV__);
Buffer<float4> ShadowsBuffer : register(t__SRV__);
Texture2D<float> ShadowMap : register(t__SRV__);
Texture3D VolumetricFogTexture : register(t__SRV__);
Texture2D PreIntegratedGF : register(t__SRV__);
@4// Forward Shading: Utilities
// Public accessors for lighting data, use them as data binding might change but those methods will remain.
LightData GetDirectionalLight() { return DirectionalLight; }
LightData GetSkyLight() { return SkyLight; }
EnvProbeData GetEnvironmentProbe() { return EnvironmentProbe; }
ProbeData GetEnvironmentProbe() { return EnvironmentProbe; }
ExponentialHeightFogData GetExponentialHeightFog() { return ExponentialHeightFog; }
VolumetricFogData GetVolumetricFog() { return VolumetricFog; }
uint GetLocalLightsCount() { return LocalLightsCount; }
LightData GetLocalLight(uint i) { return LocalLights[i]; }
@5// Forward Shading: Shaders
@@ -112,8 +107,7 @@ void PS_Forward(
// Calculate reflections
#if USE_REFLECTIONS
float4 reflections = SampleReflectionProbe(ViewPos, EnvProbe, EnvironmentProbe, gBuffer.WorldPos, gBuffer.Normal, gBuffer.Roughness);
reflections.rgb *= reflections.a;
float3 reflections = SampleReflectionProbe(ViewPos, EnvProbe, EnvironmentProbe, gBuffer.WorldPos, gBuffer.Normal, gBuffer.Roughness).rgb;
#if MATERIAL_REFLECTIONS == MATERIAL_REFLECTIONS_SSR
// Screen Space Reflections
@@ -121,7 +115,7 @@ void PS_Forward(
Texture2D sceneColorTexture = MATERIAL_REFLECTIONS_SSR_COLOR;
float2 screenUV = materialInput.SvPosition.xy * ScreenSize.zw;
float stepSize = ScreenSize.z; // 1 / screenWidth
float maxSamples = 50;
float maxSamples = 48;
float worldAntiSelfOcclusionBias = 0.1f;
float brdfBias = 0.82f;
float drawDistance = 5000.0f;
@@ -129,7 +123,7 @@ void PS_Forward(
if (hit.z > 0)
{
float3 screenColor = sceneColorTexture.SampleLevel(SamplerPointClamp, hit.xy, 0).rgb;
reflections.rgb = lerp(reflections.rgb, screenColor, hit.z);
reflections = lerp(reflections, screenColor, hit.z);
}
// Fallback to software tracing if possible
@@ -141,37 +135,23 @@ void PS_Forward(
if (TraceSDFSoftwareReflections(gBuffer, reflectWS, surfaceAtlas))
{
float3 screenColor = sceneColorTexture.SampleLevel(SamplerPointClamp, hit.xy, 0).rgb;
reflections.rgb = lerp(surfaceAtlas, float4(screenColor, 1), hit.z);
reflections = lerp(surfaceAtlas, float4(screenColor, 1), hit.z);
}
}
#endif
#endif
light.rgb += reflections.rgb * GetReflectionSpecularLighting(PreIntegratedGF, ViewPos, gBuffer);
light.rgb += reflections * GetReflectionSpecularLighting(ViewPos, gBuffer) * light.a;
#endif
// Add lighting
output.rgb += light.rgb;
// Add lighting (apply ambient occlusion)
output.rgb += light.rgb * gBuffer.AO;
#endif
#if USE_FOG && MATERIAL_SHADING_MODEL != SHADING_MODEL_UNLIT
// Calculate exponential height fog
#if DIRECTX && FEATURE_LEVEL < FEATURE_LEVEL_SM6
// TODO: fix D3D11/D3D10 bug with incorrect distance
float fogSceneDistance = distance(materialInput.WorldPosition, ViewPos);
#else
float fogSceneDistance = gBuffer.ViewPos.z;
#endif
float fogSkipDistance = max(ExponentialHeightFog.VolumetricFogMaxDistance - 100, 0);
float4 fog = GetExponentialHeightFog(ExponentialHeightFog, materialInput.WorldPosition, ViewPos, fogSkipDistance, fogSceneDistance);
if (ExponentialHeightFog.VolumetricFogMaxDistance > 0)
{
// Sample volumetric fog and mix it in
float2 screenUV = materialInput.SvPosition.xy * ScreenSize.zw;
float4 volumetricFog = SampleVolumetricFog(VolumetricFogTexture, VolumetricFog, materialInput.WorldPosition - ViewPos, screenUV, TemporalAAJitter);
fog = CombineVolumetricFog(fog, volumetricFog);
}
float4 fog = GetExponentialHeightFog(ExponentialHeightFog, materialInput.WorldPosition, ViewPos, 0, gBuffer.ViewPos.z);
// Apply fog to the output color
#if MATERIAL_BLEND == MATERIAL_BLEND_OPAQUE

View File

@@ -67,7 +67,7 @@ float Rand(inout uint seed)
float3 ReprojectPosition(float2 uv, float rawDepth)
{
uv = uv * float2(2.0, -2.0) + float2(-1.0, 1.0);
float4 pos = PROJECT_POINT(float4(uv.x, uv.y, rawDepth, 1.0f), InvViewProjectionMatrix);
float4 pos = mul(float4(uv.x, uv.y, rawDepth, 1.0f), InvViewProjectionMatrix);
return pos.xyz / pos.w;
}
@@ -158,7 +158,7 @@ void SpawnParticle(Context context)
@4}
// Main entry point for the particles simulation and spawning
META_CS(true, AUTO)
META_CS(true, FEATURE_LEVEL_SM5)
[numthreads(THREAD_GROUP_SIZE, 1, 1)]
void CS_Main(uint3 dispatchThreadId : SV_DispatchThreadID)
{

View File

@@ -21,7 +21,7 @@ float4 ViewInfo;
float4 ScreenSize;
float4 ViewSize;
float3 ViewPadding0;
float ScaledTimeParam;
float UnscaledTimeParam;
@1META_CB_END
// Shader resources
@@ -38,7 +38,6 @@ struct VertexOutput
#endif
float4 ClipExtents : TEXCOORD3;
float2 ClipOrigin : TEXCOORD4;
float2 CustomData : TEXCOORD5; // x-per-geometry type, y-features mask
#if USE_CUSTOM_VERTEX_INTERPOLATORS
float4 CustomVSToPS[CUSTOM_VERTEX_INTERPOLATORS_COUNT] : TEXCOORD9;
#endif
@@ -56,7 +55,6 @@ struct PixelInput
#endif
float4 ClipExtents : TEXCOORD3;
float2 ClipOrigin : TEXCOORD4;
float2 CustomData : TEXCOORD5; // x-per-geometry type, y-features mask
#if USE_CUSTOM_VERTEX_INTERPOLATORS
float4 CustomVSToPS[CUSTOM_VERTEX_INTERPOLATORS_COUNT] : TEXCOORD9;
#endif
@@ -69,7 +67,6 @@ struct MaterialInput
float3 WorldPosition;
float TwoSidedSign;
float2 TexCoord;
float2 CustomData; // x-per-geometry type, y-features mask
#if USE_VERTEX_COLOR
half4 VertexColor;
#endif
@@ -87,7 +84,6 @@ MaterialInput GetMaterialInput(Render2DVertex input, VertexOutput output)
MaterialInput result;
result.WorldPosition = output.WorldPosition;
result.TexCoord = output.TexCoord;
result.CustomData = input.CustomDataAndClipOrigin.xy;
#if USE_VERTEX_COLOR
result.VertexColor = output.VertexColor;
#endif
@@ -107,7 +103,6 @@ MaterialInput GetMaterialInput(PixelInput input)
MaterialInput result;
result.WorldPosition = input.WorldPosition;
result.TexCoord = input.TexCoord;
result.CustomData = input.CustomData;
#if USE_VERTEX_COLOR
result.VertexColor = input.VertexColor;
#endif
@@ -227,14 +222,13 @@ VertexOutput VS_GUI(Render2DVertex input)
if ((int)input.CustomDataAndClipOrigin.y & 1)
input.Position = (int2)input.Position;
output.Position = PROJECT_POINT(float4(input.Position, 0, 1), ViewProjectionMatrix);
output.Position = mul(float4(input.Position, 0, 1), ViewProjectionMatrix);
output.WorldPosition = mul(float4(input.Position, 0, 1), WorldMatrix).xyz;
output.TexCoord = input.TexCoord;
output.WindowPos = input.Position;
#if USE_VERTEX_COLOR
output.VertexColor = input.Color;
#endif
output.CustomData = input.CustomDataAndClipOrigin.xy;
output.ClipOrigin = input.CustomDataAndClipOrigin.zw;
output.ClipExtents = input.ClipExtents;

View File

@@ -393,7 +393,7 @@ VertexOutput VS_Sprite(SpriteInput input, uint particleIndex : SV_InstanceID)
output.WorldPosition = position + spriteVertexPosition;
// Compute clip space position
output.Position = PROJECT_POINT(float4(output.WorldPosition.xyz, 1), ViewProjectionMatrix);
output.Position = mul(float4(output.WorldPosition.xyz, 1), ViewProjectionMatrix);
// Pass vertex attributes
output.TexCoord = input.TexCoord;
@@ -431,7 +431,7 @@ VertexOutput VS_Sprite(SpriteInput input, uint particleIndex : SV_InstanceID)
// Apply world position offset per-vertex
#if USE_POSITION_OFFSET
output.WorldPosition += material.PositionOffset;
output.Position = PROJECT_POINT(float4(output.WorldPosition.xyz, 1), ViewProjectionMatrix);
output.Position = mul(float4(output.WorldPosition.xyz, 1), ViewProjectionMatrix);
#endif
// Copy interpolants for other shader stages
@@ -511,7 +511,7 @@ VertexOutput VS_Model(ModelInput input, uint particleIndex : SV_InstanceID)
output.WorldPosition = mul(float4(input.Position, 1), world).xyz;
// Compute clip space position
output.Position = PROJECT_POINT(float4(output.WorldPosition, 1), ViewProjectionMatrix);
output.Position = mul(float4(output.WorldPosition, 1), ViewProjectionMatrix);
// Pass vertex attributes
output.TexCoord = input.TexCoord0;
@@ -549,7 +549,7 @@ VertexOutput VS_Model(ModelInput input, uint particleIndex : SV_InstanceID)
// Apply world position offset per-vertex
#if USE_POSITION_OFFSET
output.WorldPosition += material.PositionOffset;
output.Position = PROJECT_POINT(float4(output.WorldPosition.xyz, 1), ViewProjectionMatrix);
output.Position = mul(float4(output.WorldPosition.xyz, 1), ViewProjectionMatrix);
#endif
// Copy interpolants for other shader stages
@@ -617,7 +617,7 @@ VertexOutput VS_Ribbon(RibbonInput input, uint vertexIndex : SV_VertexID)
output.WorldPosition = position + tangentRight * vertexSign * (ribbonWidth.xxx * 0.5f);
// Compute clip space position
output.Position = PROJECT_POINT(float4(output.WorldPosition.xyz, 1), ViewProjectionMatrix);
output.Position = mul(float4(output.WorldPosition.xyz, 1), ViewProjectionMatrix);
// Pass vertex attributes
output.ParticleIndex = particleIndex;
@@ -645,7 +645,7 @@ VertexOutput VS_Ribbon(RibbonInput input, uint vertexIndex : SV_VertexID)
materialInput.TBN = output.TBN;
materialInput.TwoSidedSign = 1;
materialInput.SvPosition = output.Position;
materialInput.PreSkinnedPosition = position;
materialInput.PreSkinnedPosition = Position;
materialInput.PreSkinnedNormal = tangentToLocal[2].xyz;
materialInput.InstanceOrigin = output.InstanceOrigin;
materialInput.InstanceParams = output.InstanceParams;
@@ -655,7 +655,7 @@ VertexOutput VS_Ribbon(RibbonInput input, uint vertexIndex : SV_VertexID)
// Apply world position offset per-vertex
#if USE_POSITION_OFFSET
output.WorldPosition += material.PositionOffset;
output.Position = PROJECT_POINT(float4(output.WorldPosition.xyz, 1), ViewProjectionMatrix);
output.Position = mul(float4(output.WorldPosition.xyz, 1), ViewProjectionMatrix);
#endif
// Copy interpolants for other shader stages

View File

@@ -20,7 +20,7 @@ float4 ScreenSize;
float4 TemporalAAJitter;
float4x4 InverseViewProjectionMatrix;
float3 ViewPadding0;
float ScaledTimeParam;
float UnscaledTimeParam;
@1META_CB_END
// Shader resources

View File

@@ -342,7 +342,7 @@ VertexOutput VS(ModelInput input)
output.Geometry.PrevWorldPosition = mul(float4(input.Position.xyz, 1), object.PrevWorldMatrix).xyz;
// Compute clip space position
output.Position = PROJECT_POINT(float4(output.Geometry.WorldPosition, 1), ViewProjectionMatrix);
output.Position = mul(float4(output.Geometry.WorldPosition, 1), ViewProjectionMatrix);
// Pass vertex attributes
output.Geometry.TexCoords01 = float4(input.TexCoord0, input.TexCoord1);
@@ -378,7 +378,7 @@ VertexOutput VS(ModelInput input)
#if USE_POSITION_OFFSET
output.Geometry.WorldPosition += material.PositionOffset;
output.Geometry.PrevWorldPosition += material.PositionOffset;
output.Position = PROJECT_POINT(float4(output.Geometry.WorldPosition, 1), ViewProjectionMatrix);
output.Position = mul(float4(output.Geometry.WorldPosition, 1), ViewProjectionMatrix);
#endif
// Get tessalation multiplier (per vertex)
@@ -412,7 +412,7 @@ float4 VS_Depth(ModelInput_PosOnly input) : SV_Position
// Transform vertex position into the screen
float3 worldPosition = mul(float4(input.Position.xyz, 1), object.WorldMatrix).xyz;
float4 position = PROJECT_POINT(float4(worldPosition, 1), ViewProjectionMatrix);
float4 position = mul(float4(worldPosition, 1), ViewProjectionMatrix);
return position;
}
@@ -518,7 +518,7 @@ VertexOutput VS_Skinned(ModelInput_Skinned input)
#endif
// Compute clip space position
output.Position = PROJECT_POINT(float4(output.Geometry.WorldPosition, 1), ViewProjectionMatrix);
output.Position = mul(float4(output.Geometry.WorldPosition, 1), ViewProjectionMatrix);
// Pass vertex attributes
output.Geometry.TexCoords01 = float4(input.TexCoord0, input.TexCoord1);
@@ -549,7 +549,7 @@ VertexOutput VS_Skinned(ModelInput_Skinned input)
#if USE_POSITION_OFFSET
output.Geometry.WorldPosition += material.PositionOffset;
output.Geometry.PrevWorldPosition += material.PositionOffset;
output.Position = PROJECT_POINT(float4(output.Geometry.WorldPosition, 1), ViewProjectionMatrix);
output.Position = mul(float4(output.Geometry.WorldPosition, 1), ViewProjectionMatrix);
#endif
// Get tessalation multiplier (per vertex)

View File

@@ -388,7 +388,7 @@ VertexOutput VS(TerrainVertexInput input)
output.Geometry.WorldPosition = mul(float4(position, 1), worldMatrix).xyz;
// Compute clip space position
output.Position = PROJECT_POINT(float4(output.Geometry.WorldPosition, 1), ViewProjectionMatrix);
output.Position = mul(float4(output.Geometry.WorldPosition, 1), ViewProjectionMatrix);
// Pass vertex attributes
#if USE_SMOOTH_LOD_TRANSITION
@@ -436,7 +436,7 @@ VertexOutput VS(TerrainVertexInput input)
// Apply world position offset per-vertex
#if USE_POSITION_OFFSET
output.Geometry.WorldPosition += material.PositionOffset;
output.Position = PROJECT_POINT(float4(output.Geometry.WorldPosition, 1), ViewProjectionMatrix);
output.Position = mul(float4(output.Geometry.WorldPosition, 1), ViewProjectionMatrix);
#endif
// Get tessalation multiplier (per vertex)

View File

@@ -8,7 +8,6 @@
#include "./Flax/Common.hlsl"
#include "./Flax/MaterialCommon.hlsl"
#include "./Flax/GBufferCommon.hlsl"
#include "./Flax/VolumetricFog.hlsl"
@7
// Primary constant buffer (with additional material parameters)
@@ -22,7 +21,6 @@ float Dummy0;
float VolumetricFogMaxDistance;
int ParticleStride;
int ParticleIndex;
float4 GridSliceParameters;
@1META_CB_END
// Particles attributes buffer
@@ -204,19 +202,19 @@ Material GetMaterialPS(MaterialInput input)
META_PS(true, FEATURE_LEVEL_SM5)
void PS_VolumetricFog(Quad_GS2PS input, out float4 VBufferA : SV_Target0, out float4 VBufferB : SV_Target1)
{
// Reproject grid position back to the screen and world space
uint3 gridCoordinate = uint3(input.Vertex.Position.xy, input.LayerIndex);
float3 cellOffset = 0.5f;
float2 volumeUV = (gridCoordinate.xy + cellOffset.xy) / GridSize.xy;
float sceneDepth = GetDepthFromSlice(GridSliceParameters, gridCoordinate.z + cellOffset.z) / ViewFar;
float zSlice = gridCoordinate.z + cellOffset.z;
float sceneDepth = (zSlice / GridSize.z) * VolumetricFogMaxDistance / ViewFar;
float deviceDepth = (ViewInfo.w / sceneDepth) + ViewInfo.z;
float4 clipPos = float4(volumeUV * float2(2.0, -2.0) + float2(-1.0, 1.0), deviceDepth, 1.0);
float4 wsPos = mul(clipPos, InverseViewProjectionMatrix);
wsPos.xyz /= wsPos.w;
float3 positionWS = wsPos.xyz / wsPos.w;
// Get material parameters
MaterialInput materialInput = (MaterialInput)0;
materialInput.WorldPosition = wsPos.xyz;
materialInput.WorldPosition = positionWS;
materialInput.TexCoord = input.Vertex.TexCoord;
materialInput.ParticleIndex = ParticleIndex;
materialInput.TBN = float3x3(float3(1, 0, 0), float3(0, 1, 0), float3(0, 0, 1));
@@ -227,10 +225,9 @@ void PS_VolumetricFog(Quad_GS2PS input, out float4 VBufferA : SV_Target0, out fl
Material material = GetMaterialPS(materialInput);
// Compute fog properties
material.Opacity *= material.Mask;
float3 albedo = material.Color;
float extinction = material.Opacity * 0.001f;
float3 emission = material.Emissive * material.Opacity;
float extinction = material.Opacity * material.Mask * 0.001f;
float3 emission = material.Emissive;
float3 scattering = albedo * extinction;
float absorption = max(0.0f, extinction - Luminance(scattering));

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -2,26 +2,18 @@
"Name": "Flax",
"Version": {
"Major": 1,
"Minor": 12,
"Minor": 11,
"Revision": 0,
"Build": 6910
"Build": 6800
},
"Company": "Flax",
"Copyright": "Copyright (c) 2012-2026 Wojciech Figat. All rights reserved.",
"Copyright": "Copyright (c) 2012-2025 Wojciech Figat. All rights reserved.",
"GameTarget": "FlaxGame",
"EditorTarget": "FlaxEditor",
"Configuration": {
"UseCSharp": true,
"UseLargeWorlds": false,
"UseDotNet": true,
"Windows": {
"UseSDL": false,
},
"Mac": {
"UseSDL": false,
},
"Linux": {
"UseSDL": true,
},
"UseSDL": true
}
}
}

View File

@@ -188,7 +188,7 @@
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_FIELD_ATTRIBUTE_ON_SAME_LINE/@EntryValue">False</s:Boolean>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_FIELD_ATTRIBUTE_ON_SAME_LINE_EX/@EntryValue">NEVER</s:String>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_SIMPLE_ACCESSOR_ATTRIBUTE_ON_SAME_LINE/@EntryValue">False</s:Boolean>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_SIMPLE_CASE_STATEMENT_ON_SAME_LINE/@EntryValue">ALWAYS</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_SIMPLE_EMBEDDED_STATEMENT_ON_SAME_LINE/@EntryValue">NEVER</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/SIMPLE_CASE_STATEMENT_STYLE/@EntryValue">ON_SINGLE_LINE</s:String>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/SPACE_AFTER_TYPECAST_PARENTHESES/@EntryValue">False</s:Boolean>

19
ISSUE_TEMPLATE.md Normal file
View File

@@ -0,0 +1,19 @@
<!-- Please search existing issues for potential duplicates before filing yours:
https://github.com/flaxengine/FlaxEngine/issues?q=is%3Aissue
-->
**Issue description:**
<!-- What happened, and what was expected. -->
<!-- Log file, can be found in the project directory's `Logs` folder (optional) -->
**Steps to reproduce:**
<!-- Enter minimal reproduction steps if available. -->
**Minimal reproduction project:**
<!-- Recommended as it greatly speeds up debugging. Drag and drop a zip archive to upload it. -->
**Flax version:**
<!-- Specify version number. -->

View File

@@ -49,7 +49,7 @@ Follow the instructions below to compile and run the engine from source.
* Fedora: `sudo dnf install dotnet-sdk-8.0`
* Arch: `sudo pacman -S dotnet-sdk-8.0 dotnet-runtime-8.0 dotnet-targeting-pack-8.0 dotnet-host`
* Install Vulkan SDK ([https://vulkan.lunarg.com/](https://vulkan.lunarg.com/))
* Ubuntu: `sudo apt install vulkan-sdk` (deprecated, follow official docs)
* Ubuntu: `sudo apt install vulkan-sdk`
* Fedora: `sudo dnf install vulkan-headers vulkan-tools vulkan-validation-layers`
* Arch: `sudo pacman -S vulkan-headers vulkan-tools vulkan-validation-layers`
* Install Git with LFS
@@ -60,7 +60,7 @@ Follow the instructions below to compile and run the engine from source.
* Ubuntu: `sudo apt-get install libx11-dev libxcursor-dev libxinerama-dev zlib1g-dev`
* Fedora: `sudo dnf install libX11-devel libXcursor-devel libXinerama-devel ghc-zlib-devel`
* Arch: `sudo pacman -S base-devel libx11 libxcursor libxinerama zlib`
* Install Clang compiler (version 14 or later):
* Install Clang compiler (version 6 or later):
* Ubuntu: `sudo apt-get install clang lldb lld`
* Fedora: `sudo dnf install clang llvm lldb lld`
* Arch: `sudo pacman -S clang lldb lld`

View File

@@ -117,8 +117,7 @@ namespace FlaxEditor.Content.Create
private static bool IsValid(Type type)
{
var controlTypes = Editor.Instance.CodeEditing.Controls.Get();
return (type.IsPublic || type.IsNestedPublic) && !type.IsAbstract && !type.IsGenericType && controlTypes.Contains(new ScriptType(type));
return (type.IsPublic || type.IsNestedPublic) && !type.IsAbstract && !type.IsGenericType;
}
}

View File

@@ -19,7 +19,7 @@ namespace FlaxEditor.Content.GUI
/// <summary>
/// Gets the target node.
/// </summary>
public ContentFolderTreeNode TargetNode { get; }
public ContentTreeNode TargetNode { get; }
/// <summary>
/// Initializes a new instance of the <see cref="ContentNavigationButton"/> class.
@@ -28,7 +28,7 @@ namespace FlaxEditor.Content.GUI
/// <param name="x">The x position.</param>
/// <param name="y">The y position.</param>
/// <param name="height">The height.</param>
public ContentNavigationButton(ContentFolderTreeNode targetNode, float x, float y, float height)
public ContentNavigationButton(ContentTreeNode targetNode, float x, float y, float height)
: base(x, y, height)
{
TargetNode = targetNode;
@@ -147,7 +147,7 @@ namespace FlaxEditor.Content.GUI
ClearItems();
foreach (var child in Target.TargetNode.Children)
{
if (child is ContentFolderTreeNode node)
if (child is ContentTreeNode node)
{
if (node.Folder.VisibleInHierarchy) // Respect the filter set by ContentFilterConfig.Filter(...)
AddItem(node.Folder.ShortName);
@@ -180,7 +180,7 @@ namespace FlaxEditor.Content.GUI
var item = _items[index];
foreach (var child in Target.TargetNode.Children)
{
if (child is ContentFolderTreeNode node && node.Folder.ShortName == item)
if (child is ContentTreeNode node && node.Folder.ShortName == item)
{
Editor.Instance.Windows.ContentWin.Navigate(node);
return;

View File

@@ -187,11 +187,6 @@ namespace FlaxEditor.Content.Import
// Glossiness, metalness, ambient occlusion, displacement, height, cavity or specular
_settings.Settings.Type = TextureFormatType.GrayScale;
}
else if (_settings.Settings.Type == TextureFormatType.ColorRGB)
{
// Blind guess that common color texture is sRGB
_settings.Settings.sRGB = true;
}
// Try to restore target asset texture import options (useful for fast reimport)
Editor.TryRestoreImportOptions(ref _settings.Settings, ResultUrl);

View File

@@ -59,7 +59,7 @@ namespace FlaxEditor.Content
/// <summary>
/// Gets the content node.
/// </summary>
public ContentFolderTreeNode Node { get; }
public ContentTreeNode Node { get; }
/// <summary>
/// The subitems of this folder.
@@ -72,7 +72,7 @@ namespace FlaxEditor.Content
/// <param name="type">The folder type.</param>
/// <param name="path">The path to the item.</param>
/// <param name="node">The folder parent node.</param>
internal ContentFolder(ContentFolderType type, string path, ContentFolderTreeNode node)
internal ContentFolder(ContentFolderType type, string path, ContentTreeNode node)
: base(path)
{
FolderType = type;
@@ -118,7 +118,7 @@ namespace FlaxEditor.Content
get
{
var hasParentFolder = ParentFolder != null;
var isContentFolder = Node is MainContentFolderTreeNode;
var isContentFolder = Node is MainContentTreeNode;
return hasParentFolder && !isContentFolder;
}
}

View File

@@ -281,13 +281,6 @@ namespace FlaxEditor.Content
private void CacheData()
{
if (!_asset)
{
_parameters = Utils.GetEmptyArray<ScriptMemberInfo>();
_methods = Utils.GetEmptyArray<ScriptMemberInfo>();
_attributes = Utils.GetEmptyArray<Attribute>();
return;
}
if (_parameters != null)
return;
if (_asset.WaitForLoaded())
@@ -351,13 +344,13 @@ namespace FlaxEditor.Content
}
/// <inheritdoc />
public string Name => _asset ? Path.GetFileNameWithoutExtension(_asset.Path) : null;
public string Name => Path.GetFileNameWithoutExtension(_asset.Path);
/// <inheritdoc />
public string Namespace => string.Empty;
/// <inheritdoc />
public string TypeName => _asset ? JsonSerializer.GetStringID(_asset.ID) : null;
public string TypeName => JsonSerializer.GetStringID(_asset.ID);
/// <inheritdoc />
public bool IsPublic => true;

View File

@@ -130,11 +130,6 @@ namespace FlaxEditor.Content
eyeAdaptation.Mode = EyeAdaptationMode.None;
eyeAdaptation.OverrideFlags |= EyeAdaptationSettingsOverride.Mode;
preview.PostFxVolume.EyeAdaptation = eyeAdaptation;
var antiAliasing = preview.PostFxVolume.AntiAliasing;
antiAliasing.Mode = AntialiasingMode.FastApproximateAntialiasing;
antiAliasing.OverrideFlags |= AntiAliasingSettingsOverride.Mode;
preview.PostFxVolume.AntiAliasing = antiAliasing;
}
}
}

View File

@@ -45,8 +45,6 @@ namespace FlaxEditor.Content.Thumbnails
{
if (item == null)
throw new ArgumentNullException();
if (_task == null)
return;
// Check if use default icon
var defaultThumbnail = item.DefaultThumbnail;
@@ -225,12 +223,11 @@ namespace FlaxEditor.Content.Thumbnails
/// <inheritdoc />
public override void OnInit()
{
if (Editor.IsHeadlessMode || (GPUDevice.Instance != null && GPUDevice.Instance.RendererType == RendererType.Null))
return;
// Create cache folder
if (!Directory.Exists(_cacheFolder))
{
Directory.CreateDirectory(_cacheFolder);
}
// Find atlases in a Editor cache directory
var files = Directory.GetFiles(_cacheFolder, "cache_*.flax", SearchOption.TopDirectoryOnly);
@@ -485,7 +482,7 @@ namespace FlaxEditor.Content.Thumbnails
public override void OnUpdate()
{
// Wait some frames before start generating previews (late init feature)
if (Time.TimeSinceStartup < 1.0f || HasAllAtlasesLoaded() == false || _task == null)
if (Time.TimeSinceStartup < 1.0f || HasAllAtlasesLoaded() == false)
return;
lock (_requests)

View File

@@ -1,433 +0,0 @@
// Copyright (c) Wojciech Figat. All rights reserved.
using System;
using System.Collections.Generic;
using FlaxEditor.GUI;
using FlaxEditor.GUI.Drag;
using FlaxEditor.GUI.Tree;
using FlaxEditor.SceneGraph;
using FlaxEditor.Utilities;
using FlaxEngine;
using FlaxEngine.GUI;
namespace FlaxEditor.Content;
/// <summary>
/// Content folder tree node.
/// </summary>
/// <seealso cref="TreeNode" />
public class ContentFolderTreeNode : TreeNode
{
private DragItems _dragOverItems;
private DragActors _dragActors;
private List<Rectangle> _highlights;
/// <summary>
/// The folder.
/// </summary>
protected ContentFolder _folder;
/// <summary>
/// Whether this node can be deleted.
/// </summary>
public virtual bool CanDelete => true;
/// <summary>
/// Whether this node can be duplicated.
/// </summary>
public virtual bool CanDuplicate => true;
/// <summary>
/// Gets the content folder item.
/// </summary>
public ContentFolder Folder => _folder;
/// <summary>
/// Gets the type of the folder.
/// </summary>
public ContentFolderType FolderType => _folder.FolderType;
/// <summary>
/// Returns true if that folder can import/manage scripts.
/// </summary>
public bool CanHaveScripts => _folder.CanHaveScripts;
/// <summary>
/// Returns true if that folder can import/manage assets.
/// </summary>
/// <returns>True if can contain assets for project, otherwise false</returns>
public bool CanHaveAssets => _folder.CanHaveAssets;
/// <summary>
/// Gets the parent node.
/// </summary>
public ContentFolderTreeNode ParentNode => Parent as ContentFolderTreeNode;
/// <summary>
/// Gets the folder path.
/// </summary>
public string Path => _folder.Path;
/// <summary>
/// Gets the navigation button label.
/// </summary>
public virtual string NavButtonLabel => _folder.ShortName;
/// <summary>
/// Initializes a new instance of the <see cref="ContentFolderTreeNode"/> class.
/// </summary>
/// <param name="parent">The parent node.</param>
/// <param name="path">The folder path.</param>
public ContentFolderTreeNode(ContentFolderTreeNode parent, string path)
: this(parent, parent?.FolderType ?? ContentFolderType.Other, path)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="ContentFolderTreeNode"/> class.
/// </summary>
/// <param name="parent">The parent node.</param>
/// <param name="type">The folder type.</param>
/// <param name="path">The folder path.</param>
protected ContentFolderTreeNode(ContentFolderTreeNode parent, ContentFolderType type, string path)
: base(false, Editor.Instance.Icons.FolderClosed32, Editor.Instance.Icons.FolderOpen32)
{
_folder = new ContentFolder(type, path, this);
Text = _folder.ShortName;
if (parent != null)
{
Folder.ParentFolder = parent.Folder;
Parent = parent;
}
IconColor = Color.Transparent; // Hide default icon, we draw scaled icon manually
UpdateCustomArrowRect();
Editor.Instance?.Windows?.ContentWin?.TryAutoExpandContentNode(this);
}
/// <summary>
/// Updates the custom arrow rectangle so it stays aligned with the current layout.
/// </summary>
private void UpdateCustomArrowRect()
{
var contentWindow = Editor.Instance?.Windows?.ContentWin;
var scale = contentWindow != null && contentWindow.IsTreeOnlyMode ? contentWindow.View.ViewScale : 1.0f;
var arrowSize = Mathf.Clamp(12.0f * scale, 10.0f, 20.0f);
var iconSize = Mathf.Clamp(16.0f * scale, 12.0f, 28.0f);
// Use the current text layout, not just cached values.
var textRect = TextRect;
var iconLeft = textRect.Left - iconSize - 2.0f;
var x = Mathf.Max(iconLeft - arrowSize - 2.0f, 0.0f);
var y = Mathf.Max((HeaderHeight - arrowSize) * 0.5f, 0.0f);
CustomArrowRect = new Rectangle(x, y, arrowSize, arrowSize);
}
/// <inheritdoc />
public override void PerformLayout(bool force = false)
{
base.PerformLayout(force);
UpdateCustomArrowRect();
}
/// <summary>
/// Shows the rename popup for the item.
/// </summary>
public void StartRenaming()
{
if (!_folder.CanRename)
return;
// Start renaming the folder
Editor.Instance.Windows.ContentWin.ScrollingOnTreeView(false);
var dialog = RenamePopup.Show(this, TextRect, _folder.ShortName, false);
dialog.Tag = _folder;
dialog.Renamed += popup =>
{
Editor.Instance.Windows.ContentWin.Rename((ContentFolder)popup.Tag, popup.Text);
Editor.Instance.Windows.ContentWin.ScrollingOnTreeView(true);
};
dialog.Closed += popup => { Editor.Instance.Windows.ContentWin.ScrollingOnTreeView(true); };
}
/// <summary>
/// Updates the query search filter.
/// </summary>
/// <param name="filterText">The filter text.</param>
public void UpdateFilter(string filterText)
{
bool noFilter = string.IsNullOrWhiteSpace(filterText);
// Update itself
bool isThisVisible;
if (noFilter)
{
// Clear filter
_highlights?.Clear();
isThisVisible = true;
}
else
{
var text = Text;
if (QueryFilterHelper.Match(filterText, text, out QueryFilterHelper.Range[] ranges))
{
// Update highlights
if (_highlights == null)
_highlights = new List<Rectangle>(ranges.Length);
else
_highlights.Clear();
var style = Style.Current;
var font = style.FontSmall;
var textRect = TextRect;
for (int i = 0; i < ranges.Length; i++)
{
var start = font.GetCharPosition(text, ranges[i].StartIndex);
var end = font.GetCharPosition(text, ranges[i].EndIndex);
_highlights.Add(new Rectangle(start.X + textRect.X, textRect.Y, end.X - start.X, textRect.Height));
}
isThisVisible = true;
}
else
{
// Hide
_highlights?.Clear();
isThisVisible = false;
}
}
// Update children
bool isAnyChildVisible = false;
for (int i = 0; i < _children.Count; i++)
{
if (_children[i] is ContentFolderTreeNode child)
{
child.UpdateFilter(filterText);
isAnyChildVisible |= child.Visible;
}
else if (_children[i] is ContentItemTreeNode itemNode)
{
itemNode.UpdateFilter(filterText);
isAnyChildVisible |= itemNode.Visible;
}
}
if (!noFilter)
{
bool isExpanded = isAnyChildVisible;
if (isExpanded)
Expand(true);
else
Collapse(true);
}
Visible = isThisVisible | isAnyChildVisible;
}
/// <inheritdoc />
public override int Compare(Control other)
{
if (other is ContentItemTreeNode)
return -1;
if (other is ContentFolderTreeNode otherNode)
return string.Compare(Text, otherNode.Text, StringComparison.Ordinal);
return base.Compare(other);
}
/// <inheritdoc />
public override void Draw()
{
base.Draw();
// Draw all highlights
if (_highlights != null)
{
var style = Style.Current;
var color = style.ProgressNormal * 0.6f;
for (int i = 0; i < _highlights.Count; i++)
Render2D.FillRectangle(_highlights[i], color);
}
var contentWindow = Editor.Instance.Windows.ContentWin;
var scale = contentWindow != null && contentWindow.IsTreeOnlyMode ? contentWindow.View.ViewScale : 1.0f;
var icon = IsExpanded ? Editor.Instance.Icons.FolderOpen32 : Editor.Instance.Icons.FolderClosed32;
var iconSize = Mathf.Clamp(16.0f * scale, 12.0f, 28.0f);
var iconRect = new Rectangle(TextRect.Left - iconSize - 2.0f, (HeaderHeight - iconSize) * 0.5f, iconSize, iconSize);
Render2D.DrawSprite(icon, iconRect);
}
/// <inheritdoc />
public override void OnDestroy()
{
// Delete folder item
_folder.Dispose();
base.OnDestroy();
}
/// <inheritdoc />
protected override void OnExpandedChanged()
{
base.OnExpandedChanged();
Editor.Instance?.Windows?.ContentWin?.OnContentTreeNodeExpandedChanged(this, IsExpanded);
}
private DragDropEffect GetDragEffect(DragData data)
{
if (_dragActors != null && _dragActors.HasValidDrag)
return DragDropEffect.Move;
if (data is DragDataFiles)
{
if (_folder.CanHaveAssets)
return DragDropEffect.Copy;
}
else
{
if (_dragOverItems != null && _dragOverItems.HasValidDrag)
return DragDropEffect.Move;
}
return DragDropEffect.None;
}
private bool ValidateDragItem(ContentItem item)
{
// Reject itself and any parent
return item != _folder && !item.Find(_folder);
}
private bool ValidateDragActors(ActorNode actor)
{
return actor.CanCreatePrefab && _folder.CanHaveAssets;
}
private void ImportActors(DragActors actors)
{
Select();
foreach (var actorNode in actors.Objects)
{
var actor = actorNode.Actor;
if (actors.Objects.Contains(actorNode.ParentNode as ActorNode))
continue;
Editor.Instance.Prefabs.CreatePrefab(actor, false);
}
Editor.Instance.Windows.ContentWin.RefreshView();
}
/// <inheritdoc />
protected override DragDropEffect OnDragEnterHeader(DragData data)
{
if (data is DragDataFiles)
return _folder.CanHaveAssets ? DragDropEffect.Copy : DragDropEffect.None;
if (_dragActors == null)
_dragActors = new DragActors(ValidateDragActors);
if (_dragActors.OnDragEnter(data))
return DragDropEffect.Move;
if (_dragOverItems == null)
_dragOverItems = new DragItems(ValidateDragItem);
_dragOverItems.OnDragEnter(data);
return GetDragEffect(data);
}
/// <inheritdoc />
protected override DragDropEffect OnDragMoveHeader(DragData data)
{
if (data is DragDataFiles)
return _folder.CanHaveAssets ? DragDropEffect.Copy : DragDropEffect.None;
if (_dragActors != null && _dragActors.HasValidDrag)
return DragDropEffect.Move;
return GetDragEffect(data);
}
/// <inheritdoc />
protected override void OnDragLeaveHeader()
{
_dragOverItems?.OnDragLeave();
_dragActors?.OnDragLeave();
base.OnDragLeaveHeader();
}
/// <inheritdoc />
protected override DragDropEffect OnDragDropHeader(DragData data)
{
var result = DragDropEffect.None;
// Check if drop element or files
if (data is DragDataFiles files)
{
// Import files
Editor.Instance.ContentImporting.Import(files.Files, _folder);
result = DragDropEffect.Copy;
Expand();
}
else if (_dragActors != null && _dragActors.HasValidDrag)
{
ImportActors(_dragActors);
_dragActors.OnDragDrop();
result = DragDropEffect.Move;
Expand();
}
else if (_dragOverItems != null && _dragOverItems.HasValidDrag)
{
// Move items
Editor.Instance.ContentDatabase.Move(_dragOverItems.Objects, _folder);
result = DragDropEffect.Move;
Expand();
}
_dragOverItems?.OnDragDrop();
return result;
}
/// <inheritdoc />
protected override void DoDragDrop()
{
DoDragDrop(DragItems.GetDragData(_folder));
}
/// <inheritdoc />
protected override void OnLongPress()
{
Select();
StartRenaming();
}
/// <inheritdoc />
public override bool OnKeyDown(KeyboardKeys key)
{
if (IsFocused)
{
switch (key)
{
case KeyboardKeys.F2:
StartRenaming();
return true;
case KeyboardKeys.Delete:
if (Folder.Exists && CanDelete)
Editor.Instance.Windows.ContentWin.Delete(Folder);
return true;
}
if (RootWindow.GetKey(KeyboardKeys.Control))
{
switch (key)
{
case KeyboardKeys.D:
if (Folder.Exists && CanDuplicate)
Editor.Instance.Windows.ContentWin.Duplicate(Folder);
return true;
}
}
}
return base.OnKeyDown(key);
}
}

View File

@@ -1,224 +0,0 @@
// Copyright (c) Wojciech Figat. All rights reserved.
using System;
using System.Collections.Generic;
using FlaxEditor.Content.GUI;
using FlaxEditor.GUI.Drag;
using FlaxEditor.GUI.Tree;
using FlaxEditor.Utilities;
using FlaxEngine;
using FlaxEngine.GUI;
namespace FlaxEditor.Content;
/// <summary>
/// Tree node for non-folder content items.
/// </summary>
public sealed class ContentItemTreeNode : TreeNode, IContentItemOwner
{
private List<Rectangle> _highlights;
/// <summary>
/// The content item.
/// </summary>
public ContentItem Item { get; }
/// <summary>
/// Initializes a new instance of the <see cref="ContentItemTreeNode"/> class.
/// </summary>
/// <param name="item">The content item.</param>
public ContentItemTreeNode(ContentItem item)
: base(false, Editor.Instance.Icons.Document128, Editor.Instance.Icons.Document128)
{
Item = item ?? throw new ArgumentNullException(nameof(item));
UpdateDisplayedName();
IconColor = Color.Transparent; // Reserve icon space but draw custom thumbnail.
Item.AddReference(this);
}
private static SpriteHandle GetIcon(ContentItem item)
{
if (item == null)
return SpriteHandle.Invalid;
var icon = item.Thumbnail;
if (!icon.IsValid)
icon = item.DefaultThumbnail;
if (!icon.IsValid)
icon = Editor.Instance.Icons.Document128;
return icon;
}
/// <summary>
/// Updates the query search filter.
/// </summary>
/// <param name="filterText">The filter text.</param>
public void UpdateFilter(string filterText)
{
bool noFilter = string.IsNullOrWhiteSpace(filterText);
bool isVisible;
if (noFilter)
{
_highlights?.Clear();
isVisible = true;
}
else
{
var text = Text;
if (QueryFilterHelper.Match(filterText, text, out QueryFilterHelper.Range[] ranges))
{
if (_highlights == null)
_highlights = new List<Rectangle>(ranges.Length);
else
_highlights.Clear();
var style = Style.Current;
var font = style.FontSmall;
var textRect = TextRect;
for (int i = 0; i < ranges.Length; i++)
{
var start = font.GetCharPosition(text, ranges[i].StartIndex);
var end = font.GetCharPosition(text, ranges[i].EndIndex);
_highlights.Add(new Rectangle(start.X + textRect.X, textRect.Y, end.X - start.X, textRect.Height));
}
isVisible = true;
}
else
{
_highlights?.Clear();
isVisible = false;
}
}
Visible = isVisible;
}
/// <inheritdoc />
public override void Draw()
{
base.Draw();
var icon = GetIcon(Item);
if (icon.IsValid)
{
var contentWindow = Editor.Instance.Windows.ContentWin;
var scale = contentWindow != null && contentWindow.IsTreeOnlyMode ? contentWindow.View.ViewScale : 1.0f;
var iconSize = Mathf.Clamp(16.0f * scale, 12.0f, 28.0f);
var textRect = TextRect;
var iconRect = new Rectangle(textRect.Left - iconSize - 2.0f, (HeaderHeight - iconSize) * 0.5f, iconSize, iconSize);
Render2D.DrawSprite(icon, iconRect);
}
if (_highlights != null)
{
var style = Style.Current;
var color = style.ProgressNormal * 0.6f;
for (int i = 0; i < _highlights.Count; i++)
Render2D.FillRectangle(_highlights[i], color);
}
}
/// <inheritdoc />
protected override bool OnMouseDoubleClickHeader(ref Float2 location, MouseButton button)
{
if (button == MouseButton.Left)
{
Editor.Instance.Windows.ContentWin.Open(Item);
return true;
}
return base.OnMouseDoubleClickHeader(ref location, button);
}
/// <inheritdoc />
public override bool OnKeyDown(KeyboardKeys key)
{
if (IsFocused)
{
switch (key)
{
case KeyboardKeys.Return:
Editor.Instance.Windows.ContentWin.Open(Item);
return true;
case KeyboardKeys.F2:
Editor.Instance.Windows.ContentWin.Rename(Item);
return true;
case KeyboardKeys.Delete:
Editor.Instance.Windows.ContentWin.Delete(Item);
return true;
}
}
return base.OnKeyDown(key);
}
/// <inheritdoc />
protected override void DoDragDrop()
{
DoDragDrop(DragItems.GetDragData(Item));
}
/// <inheritdoc />
public override bool OnShowTooltip(out string text, out Float2 location, out Rectangle area)
{
Item.UpdateTooltipText();
TooltipText = Item.TooltipText;
return base.OnShowTooltip(out text, out location, out area);
}
/// <inheritdoc />
void IContentItemOwner.OnItemDeleted(ContentItem item)
{
}
/// <inheritdoc />
void IContentItemOwner.OnItemRenamed(ContentItem item)
{
UpdateDisplayedName();
}
/// <inheritdoc />
void IContentItemOwner.OnItemReimported(ContentItem item)
{
}
/// <inheritdoc />
void IContentItemOwner.OnItemDispose(ContentItem item)
{
}
/// <inheritdoc />
public override int Compare(Control other)
{
if (other is ContentFolderTreeNode)
return 1;
if (other is ContentItemTreeNode otherItem)
return ApplySortOrder(string.Compare(Text, otherItem.Text, StringComparison.InvariantCulture));
return base.Compare(other);
}
/// <inheritdoc />
public override void OnDestroy()
{
Item.RemoveReference(this);
base.OnDestroy();
}
/// <summary>
/// Updates the text of the node.
/// </summary>
public void UpdateDisplayedName()
{
var contentWindow = Editor.Instance?.Windows?.ContentWin;
var showExtensions = contentWindow?.View?.ShowFileExtensions ?? true;
Text = Item.ShowFileExtension || showExtensions ? Item.FileName : Item.ShortName;
}
private static SortType GetSortType()
{
return Editor.Instance?.Windows?.ContentWin?.CurrentSortType ?? SortType.AlphabeticOrder;
}
private static int ApplySortOrder(int result)
{
return GetSortType() == SortType.AlphabeticReverse ? -result : result;
}
}

View File

@@ -0,0 +1,333 @@
// Copyright (c) Wojciech Figat. All rights reserved.
using System.Collections.Generic;
using FlaxEditor.GUI;
using FlaxEditor.GUI.Drag;
using FlaxEditor.GUI.Tree;
using FlaxEditor.Utilities;
using FlaxEngine;
using FlaxEngine.GUI;
namespace FlaxEditor.Content
{
/// <summary>
/// Content folder tree node.
/// </summary>
/// <seealso cref="TreeNode" />
public class ContentTreeNode : TreeNode
{
private DragItems _dragOverItems;
private List<Rectangle> _highlights;
/// <summary>
/// The folder.
/// </summary>
protected ContentFolder _folder;
/// <summary>
/// Whether this node can be deleted.
/// </summary>
public virtual bool CanDelete => true;
/// <summary>
/// Whether this node can be duplicated.
/// </summary>
public virtual bool CanDuplicate => true;
/// <summary>
/// Gets the content folder item.
/// </summary>
public ContentFolder Folder => _folder;
/// <summary>
/// Gets the type of the folder.
/// </summary>
public ContentFolderType FolderType => _folder.FolderType;
/// <summary>
/// Returns true if that folder can import/manage scripts.
/// </summary>
public bool CanHaveScripts => _folder.CanHaveScripts;
/// <summary>
/// Returns true if that folder can import/manage assets.
/// </summary>
/// <returns>True if can contain assets for project, otherwise false</returns>
public bool CanHaveAssets => _folder.CanHaveAssets;
/// <summary>
/// Gets the parent node.
/// </summary>
public ContentTreeNode ParentNode => Parent as ContentTreeNode;
/// <summary>
/// Gets the folder path.
/// </summary>
public string Path => _folder.Path;
/// <summary>
/// Gets the navigation button label.
/// </summary>
public virtual string NavButtonLabel => _folder.ShortName;
/// <summary>
/// Initializes a new instance of the <see cref="ContentTreeNode"/> class.
/// </summary>
/// <param name="parent">The parent node.</param>
/// <param name="path">The folder path.</param>
public ContentTreeNode(ContentTreeNode parent, string path)
: this(parent, parent?.FolderType ?? ContentFolderType.Other, path)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="ContentTreeNode"/> class.
/// </summary>
/// <param name="parent">The parent node.</param>
/// <param name="type">The folder type.</param>
/// <param name="path">The folder path.</param>
protected ContentTreeNode(ContentTreeNode parent, ContentFolderType type, string path)
: base(false, Editor.Instance.Icons.FolderClosed32, Editor.Instance.Icons.FolderOpen32)
{
_folder = new ContentFolder(type, path, this);
Text = _folder.ShortName;
if (parent != null)
{
Folder.ParentFolder = parent.Folder;
Parent = parent;
}
IconColor = Style.Current.Foreground;
}
/// <summary>
/// Shows the rename popup for the item.
/// </summary>
public void StartRenaming()
{
if (!_folder.CanRename)
return;
// Start renaming the folder
Editor.Instance.Windows.ContentWin.ScrollingOnTreeView(false);
var dialog = RenamePopup.Show(this, TextRect, _folder.ShortName, false);
dialog.Tag = _folder;
dialog.Renamed += popup =>
{
Editor.Instance.Windows.ContentWin.Rename((ContentFolder)popup.Tag, popup.Text);
Editor.Instance.Windows.ContentWin.ScrollingOnTreeView(true);
};
dialog.Closed += popup => { Editor.Instance.Windows.ContentWin.ScrollingOnTreeView(true); };
}
/// <summary>
/// Updates the query search filter.
/// </summary>
/// <param name="filterText">The filter text.</param>
public void UpdateFilter(string filterText)
{
bool noFilter = string.IsNullOrWhiteSpace(filterText);
// Update itself
bool isThisVisible;
if (noFilter)
{
// Clear filter
_highlights?.Clear();
isThisVisible = true;
}
else
{
var text = Text;
if (QueryFilterHelper.Match(filterText, text, out QueryFilterHelper.Range[] ranges))
{
// Update highlights
if (_highlights == null)
_highlights = new List<Rectangle>(ranges.Length);
else
_highlights.Clear();
var style = Style.Current;
var font = style.FontSmall;
var textRect = TextRect;
for (int i = 0; i < ranges.Length; i++)
{
var start = font.GetCharPosition(text, ranges[i].StartIndex);
var end = font.GetCharPosition(text, ranges[i].EndIndex);
_highlights.Add(new Rectangle(start.X + textRect.X, textRect.Y, end.X - start.X, textRect.Height));
}
isThisVisible = true;
}
else
{
// Hide
_highlights?.Clear();
isThisVisible = false;
}
}
// Update children
bool isAnyChildVisible = false;
for (int i = 0; i < _children.Count; i++)
{
if (_children[i] is ContentTreeNode child)
{
child.UpdateFilter(filterText);
isAnyChildVisible |= child.Visible;
}
}
bool isExpanded = isAnyChildVisible;
if (isExpanded)
{
Expand(true);
}
else
{
Collapse(true);
}
Visible = isThisVisible | isAnyChildVisible;
}
/// <inheritdoc />
public override void Draw()
{
base.Draw();
// Draw all highlights
if (_highlights != null)
{
var style = Style.Current;
var color = style.ProgressNormal * 0.6f;
for (int i = 0; i < _highlights.Count; i++)
Render2D.FillRectangle(_highlights[i], color);
}
}
/// <inheritdoc />
public override void OnDestroy()
{
// Delete folder item
_folder.Dispose();
base.OnDestroy();
}
private DragDropEffect GetDragEffect(DragData data)
{
if (data is DragDataFiles)
{
if (_folder.CanHaveAssets)
return DragDropEffect.Copy;
}
else
{
if (_dragOverItems.HasValidDrag)
return DragDropEffect.Move;
}
return DragDropEffect.None;
}
private bool ValidateDragItem(ContentItem item)
{
// Reject itself and any parent
return item != _folder && !item.Find(_folder);
}
/// <inheritdoc />
protected override DragDropEffect OnDragEnterHeader(DragData data)
{
if (_dragOverItems == null)
_dragOverItems = new DragItems(ValidateDragItem);
_dragOverItems.OnDragEnter(data);
return GetDragEffect(data);
}
/// <inheritdoc />
protected override DragDropEffect OnDragMoveHeader(DragData data)
{
return GetDragEffect(data);
}
/// <inheritdoc />
protected override void OnDragLeaveHeader()
{
_dragOverItems.OnDragLeave();
base.OnDragLeaveHeader();
}
/// <inheritdoc />
protected override DragDropEffect OnDragDropHeader(DragData data)
{
var result = DragDropEffect.None;
// Check if drop element or files
if (data is DragDataFiles files)
{
// Import files
Editor.Instance.ContentImporting.Import(files.Files, _folder);
result = DragDropEffect.Copy;
Expand();
}
else if (_dragOverItems.HasValidDrag)
{
// Move items
Editor.Instance.ContentDatabase.Move(_dragOverItems.Objects, _folder);
result = DragDropEffect.Move;
Expand();
}
_dragOverItems.OnDragDrop();
return result;
}
/// <inheritdoc />
protected override void DoDragDrop()
{
DoDragDrop(DragItems.GetDragData(_folder));
}
/// <inheritdoc />
protected override void OnLongPress()
{
Select();
StartRenaming();
}
/// <inheritdoc />
public override bool OnKeyDown(KeyboardKeys key)
{
if (IsFocused)
{
switch (key)
{
case KeyboardKeys.F2:
StartRenaming();
return true;
case KeyboardKeys.Delete:
if (Folder.Exists && CanDelete)
Editor.Instance.Windows.ContentWin.Delete(Folder);
return true;
}
if (RootWindow.GetKey(KeyboardKeys.Control))
{
switch (key)
{
case KeyboardKeys.D:
if (Folder.Exists && CanDuplicate)
Editor.Instance.Windows.ContentWin.Duplicate(Folder);
return true;
}
}
}
return base.OnKeyDown(key);
}
}
}

View File

@@ -7,8 +7,8 @@ namespace FlaxEditor.Content
/// <summary>
/// Content tree node used for main directories.
/// </summary>
/// <seealso cref="ContentFolderTreeNode" />
public class MainContentFolderTreeNode : ContentFolderTreeNode
/// <seealso cref="FlaxEditor.Content.ContentTreeNode" />
public class MainContentTreeNode : ContentTreeNode
{
private FileSystemWatcher _watcher;
@@ -19,12 +19,12 @@ namespace FlaxEditor.Content
public override bool CanDuplicate => false;
/// <summary>
/// Initializes a new instance of the <see cref="MainContentFolderTreeNode"/> class.
/// Initializes a new instance of the <see cref="MainContentTreeNode"/> class.
/// </summary>
/// <param name="parent">The parent project.</param>
/// <param name="type">The folder type.</param>
/// <param name="path">The folder path.</param>
public MainContentFolderTreeNode(ProjectFolderTreeNode parent, ContentFolderType type, string path)
public MainContentTreeNode(ProjectTreeNode parent, ContentFolderType type, string path)
: base(parent, type, path)
{
_watcher = new FileSystemWatcher(path)

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