Merge remote-tracking branch 'origin/1.11'
This commit is contained in:
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/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/SelectionOutlineMaterial.flax
(Stored with Git LFS)
BIN
Content/Editor/Gizmo/SelectionOutlineMaterial.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/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/IconsMaterial.flax
(Stored with Git LFS)
BIN
Content/Editor/Icons/IconsMaterial.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.
@@ -6,6 +6,7 @@
|
||||
@3
|
||||
|
||||
#include "./Flax/Common.hlsl"
|
||||
#include "./Flax/Stencil.hlsl"
|
||||
#include "./Flax/MaterialCommon.hlsl"
|
||||
#include "./Flax/GBufferCommon.hlsl"
|
||||
@7
|
||||
@@ -14,10 +15,13 @@ 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
|
||||
@@ -200,6 +204,14 @@ 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(DepthBuffer, screenUV).r;
|
||||
|
||||
|
||||
@@ -29,6 +29,13 @@ Buffer<float4> ShadowsBuffer : register(t__SRV__);
|
||||
Texture2D<float> ShadowMap : register(t__SRV__);
|
||||
Texture3D VolumetricFogTexture : 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; }
|
||||
ProbeData GetEnvironmentProbe() { return EnvironmentProbe; }
|
||||
ExponentialHeightFogData GetExponentialHeightFog() { return ExponentialHeightFog; }
|
||||
uint GetLocalLightsCount() { return LocalLightsCount; }
|
||||
LightData GetLocalLight(uint i) { return LocalLights[i]; }
|
||||
@5// Forward Shading: Shaders
|
||||
|
||||
// Pixel Shader function for Forward Pass
|
||||
@@ -77,9 +84,8 @@ void PS_Forward(
|
||||
gBuffer.ShadingModel = MATERIAL_SHADING_MODEL;
|
||||
|
||||
// Calculate lighting from a single directional light
|
||||
float4 shadowMask = 1.0f;
|
||||
ShadowSample shadow = SampleDirectionalLightShadow(DirectionalLight, ShadowsBuffer, ShadowMap, gBuffer);
|
||||
shadowMask = GetShadowMask(shadow);
|
||||
float4 shadowMask = GetShadowMask(shadow);
|
||||
float4 light = GetLighting(ViewPos, DirectionalLight, gBuffer, shadowMask, false, false);
|
||||
|
||||
// Calculate lighting from sky light
|
||||
@@ -146,7 +152,13 @@ void PS_Forward(
|
||||
|
||||
#if USE_FOG && MATERIAL_SHADING_MODEL != SHADING_MODEL_UNLIT
|
||||
// Calculate exponential height fog
|
||||
float4 fog = GetExponentialHeightFog(ExponentialHeightFog, materialInput.WorldPosition, ViewPos, 0, gBuffer.ViewPos.z);
|
||||
#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
|
||||
float4 fog = GetExponentialHeightFog(ExponentialHeightFog, materialInput.WorldPosition, ViewPos, 0, fogSceneDistance);
|
||||
|
||||
if (ExponentialHeightFog.VolumetricFogMaxDistance > 0)
|
||||
{
|
||||
|
||||
@@ -21,7 +21,7 @@ float4 ViewInfo;
|
||||
float4 ScreenSize;
|
||||
float4 ViewSize;
|
||||
float3 ViewPadding0;
|
||||
float UnscaledTimeParam;
|
||||
float ScaledTimeParam;
|
||||
@1META_CB_END
|
||||
|
||||
// Shader resources
|
||||
|
||||
@@ -20,7 +20,7 @@ float4 ScreenSize;
|
||||
float4 TemporalAAJitter;
|
||||
float4x4 InverseViewProjectionMatrix;
|
||||
float3 ViewPadding0;
|
||||
float UnscaledTimeParam;
|
||||
float ScaledTimeParam;
|
||||
@1META_CB_END
|
||||
|
||||
// Shader resources
|
||||
|
||||
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/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/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/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/Textures/PreIntegratedGF.flax
(Stored with Git LFS)
BIN
Content/Engine/Textures/PreIntegratedGF.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Shaders/BitonicSort.flax
(Stored with Git LFS)
BIN
Content/Shaders/BitonicSort.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Shaders/GPUParticlesSorting.flax
(Stored with Git LFS)
BIN
Content/Shaders/GPUParticlesSorting.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/ProbesFilter.flax
(Stored with Git LFS)
BIN
Content/Shaders/ProbesFilter.flax
(Stored with Git LFS)
Binary file not shown.
@@ -2,9 +2,9 @@
|
||||
"Name": "Flax",
|
||||
"Version": {
|
||||
"Major": 1,
|
||||
"Minor": 10,
|
||||
"Minor": 11,
|
||||
"Revision": 0,
|
||||
"Build": 6705
|
||||
"Build": 6801
|
||||
},
|
||||
"Company": "Flax",
|
||||
"Copyright": "Copyright (c) 2012-2025 Wojciech Figat. All rights reserved.",
|
||||
|
||||
@@ -174,7 +174,9 @@ void EditorAnalytics::StartSession()
|
||||
// Bind events
|
||||
GameCooker::OnEvent.Bind<RegisterGameCookingStart>();
|
||||
ShadowsOfMordor::Builder::Instance()->OnBuildStarted.Bind<RegisterLightmapsBuildingStart>();
|
||||
#if LOG_ENABLE
|
||||
Log::Logger::OnError.Bind<RegisterError>();
|
||||
#endif
|
||||
}
|
||||
|
||||
void EditorAnalytics::EndSession()
|
||||
@@ -187,7 +189,9 @@ void EditorAnalytics::EndSession()
|
||||
// Unbind events
|
||||
GameCooker::OnEvent.Unbind<RegisterGameCookingStart>();
|
||||
ShadowsOfMordor::Builder::Instance()->OnBuildStarted.Unbind<RegisterLightmapsBuildingStart>();
|
||||
#if LOG_ENABLE
|
||||
Log::Logger::OnError.Unbind<RegisterError>();
|
||||
#endif
|
||||
|
||||
// End session
|
||||
{
|
||||
|
||||
@@ -20,13 +20,6 @@ class PlatformTools;
|
||||
#define GAME_BUILD_DOTNET_RUNTIME_MAX_VER 9
|
||||
#endif
|
||||
|
||||
#if OFFICIAL_BUILD
|
||||
// Use the fixed .NET SDK version in packaged builds for compatibility (FlaxGame is precompiled with it)
|
||||
#define GAME_BUILD_DOTNET_VER TEXT("-dotnet=" MACRO_TO_STR(GAME_BUILD_DOTNET_RUNTIME_MIN_VER))
|
||||
#else
|
||||
#define GAME_BUILD_DOTNET_VER TEXT("")
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Game building options. Used as flags.
|
||||
/// </summary>
|
||||
@@ -374,6 +367,8 @@ public:
|
||||
/// </summary>
|
||||
void GetBuildPlatformName(const Char*& platform, const Char*& architecture) const;
|
||||
|
||||
String GetDotnetCommandArg() const;
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include "Engine/Scripting/ManagedCLR/MAssembly.h"
|
||||
#include "Engine/Content/JsonAsset.h"
|
||||
#include "Engine/Content/AssetReference.h"
|
||||
#include "Engine/Profiler/ProfilerMemory.h"
|
||||
#if PLATFORM_TOOLS_WINDOWS
|
||||
#include "Platform/Windows/WindowsPlatformTools.h"
|
||||
#include "Engine/Platform/Windows/WindowsPlatformSettings.h"
|
||||
@@ -311,6 +312,14 @@ void CookingData::GetBuildPlatformName(const Char*& platform, const Char*& archi
|
||||
}
|
||||
}
|
||||
|
||||
String CookingData::GetDotnetCommandArg() const
|
||||
{
|
||||
int32 version = Tools->GetDotnetVersion();
|
||||
if (version == 0)
|
||||
return String::Empty;
|
||||
return String::Format(TEXT("-dotnet={}"), version);
|
||||
}
|
||||
|
||||
void CookingData::StepProgress(const String& info, const float stepProgress) const
|
||||
{
|
||||
const float singleStepProgress = 1.0f / (StepsCount + 1);
|
||||
@@ -380,6 +389,7 @@ bool GameCooker::IsCancelRequested()
|
||||
|
||||
PlatformTools* GameCooker::GetTools(BuildPlatform platform)
|
||||
{
|
||||
PROFILE_MEM(Editor);
|
||||
PlatformTools* result = nullptr;
|
||||
if (!Tools.TryGet(platform, result))
|
||||
{
|
||||
@@ -471,6 +481,7 @@ bool GameCooker::Build(BuildPlatform platform, BuildConfiguration configuration,
|
||||
LOG(Error, "Build platform {0} is not supported.", ::ToString(platform));
|
||||
return true;
|
||||
}
|
||||
PROFILE_MEM(Editor);
|
||||
|
||||
// Setup
|
||||
CancelFlag = 0;
|
||||
@@ -624,6 +635,7 @@ void GameCookerImpl::ReportProgress(const String& info, float totalProgress)
|
||||
|
||||
void GameCookerImpl::OnCollectAssets(HashSet<Guid>& assets)
|
||||
{
|
||||
PROFILE_MEM(Editor);
|
||||
if (Internal_OnCollectAssets == nullptr)
|
||||
{
|
||||
auto c = GameCooker::GetStaticClass();
|
||||
@@ -651,6 +663,7 @@ void GameCookerImpl::OnCollectAssets(HashSet<Guid>& assets)
|
||||
|
||||
bool GameCookerImpl::Build()
|
||||
{
|
||||
PROFILE_MEM(Editor);
|
||||
CookingData& data = *Data;
|
||||
LOG(Info, "Starting Game Cooker...");
|
||||
LOG(Info, "Platform: {0}, Configuration: {2}, Options: {1}", ::ToString(data.Platform), (int32)data.Options, ::ToString(data.Configuration));
|
||||
@@ -670,8 +683,7 @@ bool GameCookerImpl::Build()
|
||||
|
||||
MCore::Thread::Attach();
|
||||
|
||||
// Build Started
|
||||
if (!EnumHasAnyFlags(data.Options, BuildOptions::NoCook))
|
||||
// Build start
|
||||
{
|
||||
CallEvent(GameCooker::EventType::BuildStarted);
|
||||
data.Tools->OnBuildStarted(data);
|
||||
@@ -744,8 +756,8 @@ bool GameCookerImpl::Build()
|
||||
}
|
||||
IsRunning = false;
|
||||
CancelFlag = 0;
|
||||
if (!EnumHasAnyFlags(data.Options, BuildOptions::NoCook))
|
||||
{
|
||||
// Build end
|
||||
for (int32 stepIndex = 0; stepIndex < Steps.Count(); stepIndex++)
|
||||
Steps[stepIndex]->OnBuildEnded(data, failed);
|
||||
data.Tools->OnBuildEnded(data, failed);
|
||||
@@ -778,6 +790,8 @@ int32 GameCookerImpl::ThreadFunction()
|
||||
|
||||
bool GameCookerService::Init()
|
||||
{
|
||||
PROFILE_MEM(Editor);
|
||||
|
||||
auto editorAssembly = ((NativeBinaryModule*)GetBinaryModuleFlaxEngine())->Assembly;
|
||||
editorAssembly->Unloading.Bind(OnEditorAssemblyUnloading);
|
||||
GameCooker::OnCollectAssets.Bind(OnCollectAssets);
|
||||
@@ -789,6 +803,7 @@ void GameCookerService::Update()
|
||||
{
|
||||
if (IsRunning)
|
||||
{
|
||||
PROFILE_MEM(Editor);
|
||||
ScopeLock lock(ProgressLocker);
|
||||
|
||||
if (ProgressMsg.HasChars())
|
||||
|
||||
@@ -195,4 +195,9 @@ bool GDKPlatformTools::OnPostProcess(CookingData& data, GDKPlatformSettings* pla
|
||||
return false;
|
||||
}
|
||||
|
||||
int32 GDKPlatformTools::GetDotnetVersion() const
|
||||
{
|
||||
return GAME_BUILD_DOTNET_RUNTIME_MIN_VER;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -26,6 +26,7 @@ public:
|
||||
public:
|
||||
|
||||
// [PlatformTools]
|
||||
int32 GetDotnetVersion() const override;
|
||||
DotNetAOTModes UseAOT() const override;
|
||||
bool OnDeployBinaries(CookingData& data) override;
|
||||
};
|
||||
|
||||
@@ -186,7 +186,7 @@ bool MacPlatformTools::OnPostProcess(CookingData& data)
|
||||
ADD_ENTRY("CFBundlePackageType", "APPL");
|
||||
ADD_ENTRY("NSPrincipalClass", "NSApplication");
|
||||
ADD_ENTRY("LSApplicationCategoryType", "public.app-category.games");
|
||||
ADD_ENTRY("LSMinimumSystemVersion", "10.15");
|
||||
ADD_ENTRY("LSMinimumSystemVersion", "13");
|
||||
ADD_ENTRY("CFBundleIconFile", "icon.icns");
|
||||
ADD_ENTRY_STR("CFBundleExecutable", executableName);
|
||||
ADD_ENTRY_STR("CFBundleIdentifier", appIdentifier);
|
||||
@@ -231,6 +231,8 @@ bool MacPlatformTools::OnPostProcess(CookingData& data)
|
||||
LOG(Info, "Building app package...");
|
||||
{
|
||||
const String dmgPath = data.OriginalOutputPath / appName + TEXT(".dmg");
|
||||
if (FileSystem::FileExists(dmgPath))
|
||||
FileSystem::DeleteFile(dmgPath);
|
||||
CreateProcessSettings procSettings;
|
||||
procSettings.HiddenWindow = true;
|
||||
procSettings.WorkingDirectory = data.OriginalOutputPath;
|
||||
|
||||
@@ -528,6 +528,9 @@ bool WindowsPlatformTools::OnDeployBinaries(CookingData& data)
|
||||
|
||||
void WindowsPlatformTools::OnBuildStarted(CookingData& data)
|
||||
{
|
||||
if (EnumHasAllFlags(data.Options, BuildOptions::NoCook))
|
||||
return;
|
||||
|
||||
// Remove old executable
|
||||
Array<String> files;
|
||||
FileSystem::DirectoryGetFiles(files, data.NativeCodeOutputPath, TEXT("*.exe"), DirectorySearchOption::TopDirectoryOnly);
|
||||
|
||||
@@ -70,6 +70,20 @@ public:
|
||||
/// </summary>
|
||||
virtual ArchitectureType GetArchitecture() const = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the .Net version to use for the cooked game.
|
||||
/// </summary>
|
||||
virtual int32 GetDotnetVersion() const
|
||||
{
|
||||
#if OFFICIAL_BUILD
|
||||
// Use the fixed .NET SDK version in packaged builds for compatibility (FlaxGame is precompiled with it)
|
||||
return GAME_BUILD_DOTNET_RUNTIME_MIN_VER;
|
||||
#else
|
||||
// Use the highest version found on a system (Flax.Build will decide)
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the value indicating whenever platform requires AOT (needs C# assemblies to be precompiled).
|
||||
/// </summary>
|
||||
|
||||
@@ -189,7 +189,7 @@ bool CompileScriptsStep::Perform(CookingData& data)
|
||||
const String logFile = data.CacheDirectory / TEXT("CompileLog.txt");
|
||||
auto args = String::Format(
|
||||
TEXT("-log -logfile=\"{4}\" -build -mutex -buildtargets={0} -platform={1} -arch={2} -configuration={3} -aotMode={5} {6}"),
|
||||
target, platform, architecture, configuration, logFile, ToString(data.Tools->UseAOT()), GAME_BUILD_DOTNET_VER);
|
||||
target, platform, architecture, configuration, logFile, ToString(data.Tools->UseAOT()), data.GetDotnetCommandArg());
|
||||
#if PLATFORM_WINDOWS
|
||||
if (data.Platform == BuildPlatform::LinuxX64)
|
||||
#elif PLATFORM_LINUX
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
#include "Engine/Engine/Base/GameBase.h"
|
||||
#include "Engine/Engine/Globals.h"
|
||||
#include "Engine/Tools/TextureTool/TextureTool.h"
|
||||
#include "Engine/Threading/Threading.h"
|
||||
#include "Engine/Profiler/ProfilerCPU.h"
|
||||
#include "Engine/Scripting/Enums.h"
|
||||
#if PLATFORM_TOOLS_WINDOWS
|
||||
|
||||
@@ -88,7 +88,7 @@ bool DeployDataStep::Perform(CookingData& data)
|
||||
{
|
||||
// Ask Flax.Build to provide .NET SDK location for the current platform
|
||||
String sdks;
|
||||
bool failed = ScriptsBuilder::RunBuildTool(String::Format(TEXT("-log -logMessagesOnly -logFileWithConsole -logfile=SDKs.txt -printSDKs {}"), GAME_BUILD_DOTNET_VER), data.CacheDirectory);
|
||||
bool failed = ScriptsBuilder::RunBuildTool(String::Format(TEXT("-log -logMessagesOnly -logFileWithConsole -logfile=SDKs.txt -printSDKs {}"), data.GetDotnetCommandArg()), data.CacheDirectory);
|
||||
failed |= File::ReadAllText(data.CacheDirectory / TEXT("SDKs.txt"), sdks);
|
||||
int32 idx = sdks.Find(TEXT("DotNetSdk, "), StringSearchCase::CaseSensitive);
|
||||
if (idx != -1)
|
||||
@@ -200,7 +200,7 @@ bool DeployDataStep::Perform(CookingData& data)
|
||||
String sdks;
|
||||
const Char *platformName, *archName;
|
||||
data.GetBuildPlatformName(platformName, archName);
|
||||
String args = String::Format(TEXT("-log -logMessagesOnly -logFileWithConsole -logfile=SDKs.txt -printDotNetRuntime -platform={} -arch={} {}"), platformName, archName, GAME_BUILD_DOTNET_VER);
|
||||
String args = String::Format(TEXT("-log -logMessagesOnly -logFileWithConsole -logfile=SDKs.txt -printDotNetRuntime -platform={} -arch={} {}"), platformName, archName, data.GetDotnetCommandArg());
|
||||
bool failed = ScriptsBuilder::RunBuildTool(args, data.CacheDirectory);
|
||||
failed |= File::ReadAllText(data.CacheDirectory / TEXT("SDKs.txt"), sdks);
|
||||
Array<String> parts;
|
||||
@@ -244,10 +244,13 @@ bool DeployDataStep::Perform(CookingData& data)
|
||||
}
|
||||
if (version.IsEmpty())
|
||||
{
|
||||
int32 minVer = GAME_BUILD_DOTNET_RUNTIME_MIN_VER, maxVer = GAME_BUILD_DOTNET_RUNTIME_MAX_VER;
|
||||
if (srcDotnetFromEngine)
|
||||
{
|
||||
// Detect version from runtime files inside Engine Platform folder
|
||||
for (int32 i = GAME_BUILD_DOTNET_RUNTIME_MAX_VER; i >= GAME_BUILD_DOTNET_RUNTIME_MIN_VER; i--)
|
||||
if (data.Tools->GetDotnetVersion() != 0)
|
||||
minVer = maxVer = data.Tools->GetDotnetVersion();
|
||||
for (int32 i = maxVer; i >= minVer; i--)
|
||||
{
|
||||
// Check runtime files inside Engine Platform folder
|
||||
String testPath1 = srcDotnet / String::Format(TEXT("lib/net{}.0"), i);
|
||||
@@ -262,7 +265,7 @@ bool DeployDataStep::Perform(CookingData& data)
|
||||
}
|
||||
if (version.IsEmpty())
|
||||
{
|
||||
data.Error(String::Format(TEXT("Failed to find supported .NET {} version for the current host platform."), GAME_BUILD_DOTNET_RUNTIME_MIN_VER));
|
||||
data.Error(String::Format(TEXT("Failed to find supported .NET {} version (min {}) for the current host platform."), maxVer, minVer));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -364,7 +367,7 @@ bool DeployDataStep::Perform(CookingData& data)
|
||||
const String logFile = data.CacheDirectory / TEXT("StripDotnetLibs.txt");
|
||||
String args = String::Format(
|
||||
TEXT("-log -logfile=\"{}\" -runDotNetClassLibStripping -mutex -binaries=\"{}\" {}"),
|
||||
logFile, data.DataOutputPath, GAME_BUILD_DOTNET_VER);
|
||||
logFile, data.DataOutputPath, data.GetDotnetCommandArg());
|
||||
for (const String& define : data.CustomDefines)
|
||||
{
|
||||
args += TEXT(" -D");
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
void PrecompileAssembliesStep::OnBuildStarted(CookingData& data)
|
||||
{
|
||||
const DotNetAOTModes aotMode = data.Tools->UseAOT();
|
||||
if (aotMode == DotNetAOTModes::None)
|
||||
if (aotMode == DotNetAOTModes::None || EnumHasAllFlags(data.Options, BuildOptions::NoCook))
|
||||
return;
|
||||
const auto& buildSettings = *BuildSettings::Get();
|
||||
|
||||
@@ -69,7 +69,7 @@ bool PrecompileAssembliesStep::Perform(CookingData& data)
|
||||
const String logFile = data.CacheDirectory / TEXT("AOTLog.txt");
|
||||
String args = String::Format(
|
||||
TEXT("-log -logfile=\"{}\" -runDotNetAOT -mutex -platform={} -arch={} -configuration={} -aotMode={} -binaries=\"{}\" -intermediate=\"{}\" {}"),
|
||||
logFile, platform, architecture, configuration, ToString(aotMode), data.DataOutputPath, data.ManagedCodeOutputPath, GAME_BUILD_DOTNET_VER);
|
||||
logFile, platform, architecture, configuration, ToString(aotMode), data.DataOutputPath, data.ManagedCodeOutputPath, data.GetDotnetCommandArg());
|
||||
if (!buildSettings.SkipUnusedDotnetLibsPackaging)
|
||||
args += TEXT(" -skipUnusedDotnetLibs=false"); // Run AOT on whole class library (not just used libs)
|
||||
for (const String& define : data.CustomDefines)
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
#include "Engine/Core/Types/TimeSpan.h"
|
||||
#include "Engine/Core/Types/Stopwatch.h"
|
||||
#include "Engine/Core/Collections/Dictionary.h"
|
||||
#include "Engine/Profiler/ProfilerCPU.h"
|
||||
#include "Engine/Profiler/ProfilerMemory.h"
|
||||
#include "Engine/Engine/EngineService.h"
|
||||
#include "Engine/Scripting/Scripting.h"
|
||||
#include "Engine/Scripting/BinaryModule.h"
|
||||
@@ -69,6 +71,7 @@ MTypeObject* CustomEditorsUtil::GetCustomEditor(MTypeObject* refType)
|
||||
|
||||
bool CustomEditorsUtilService::Init()
|
||||
{
|
||||
PROFILE_MEM(Editor);
|
||||
TRACK_ASSEMBLY(((NativeBinaryModule*)GetBinaryModuleFlaxEngine())->Assembly);
|
||||
Scripting::BinaryModuleLoaded.Bind(&OnBinaryModuleLoaded);
|
||||
|
||||
@@ -77,6 +80,8 @@ bool CustomEditorsUtilService::Init()
|
||||
|
||||
void OnAssemblyLoaded(MAssembly* assembly)
|
||||
{
|
||||
PROFILE_CPU_NAMED("CustomEditors.OnAssemblyLoaded");
|
||||
PROFILE_MEM(Editor);
|
||||
Stopwatch stopwatch;
|
||||
|
||||
// Prepare FlaxEngine
|
||||
|
||||
@@ -22,7 +22,7 @@ internal class UIControlRefPickerControl : FlaxObjectRefPickerControl
|
||||
/// <inheritdoc />
|
||||
protected override bool IsValid(Object obj)
|
||||
{
|
||||
return obj == null || (obj is UIControl control && control.Control.GetType() == ControlType);
|
||||
return obj == null || (obj is UIControl control && ControlType.IsAssignableFrom(control.Control.GetType()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "Engine/Engine/Engine.h"
|
||||
#include "Engine/ShadowsOfMordor/Builder.h"
|
||||
#include "Engine/Profiler/ProfilerCPU.h"
|
||||
#include "Engine/Profiler/ProfilerMemory.h"
|
||||
#include "FlaxEngine.Gen.h"
|
||||
#if PLATFORM_LINUX
|
||||
#include "Engine/Tools/TextureTool/TextureTool.h"
|
||||
@@ -47,6 +48,7 @@ void Editor::CloseSplashScreen()
|
||||
|
||||
bool Editor::CheckProjectUpgrade()
|
||||
{
|
||||
PROFILE_MEM(Editor);
|
||||
const auto versionFilePath = Globals::ProjectCacheFolder / TEXT("version");
|
||||
|
||||
// Load version cache file
|
||||
@@ -366,6 +368,8 @@ bool Editor::BackupProject()
|
||||
|
||||
int32 Editor::LoadProduct()
|
||||
{
|
||||
PROFILE_MEM(Editor);
|
||||
|
||||
// Flax Editor product
|
||||
Globals::ProductName = TEXT("Flax Editor");
|
||||
Globals::CompanyName = TEXT("Flax");
|
||||
@@ -626,6 +630,7 @@ int32 Editor::LoadProduct()
|
||||
|
||||
Window* Editor::CreateMainWindow()
|
||||
{
|
||||
PROFILE_MEM(Editor);
|
||||
Window* window = Managed->GetMainWindow();
|
||||
|
||||
#if PLATFORM_LINUX
|
||||
@@ -662,6 +667,7 @@ bool Editor::Init()
|
||||
return true;
|
||||
}
|
||||
PROFILE_CPU();
|
||||
PROFILE_MEM(Editor);
|
||||
|
||||
// If during last lightmaps baking engine crashed we could try to restore the progress
|
||||
ShadowsOfMordor::Builder::Instance()->CheckIfRestoreState();
|
||||
@@ -693,11 +699,13 @@ bool Editor::Init()
|
||||
|
||||
void Editor::BeforeRun()
|
||||
{
|
||||
PROFILE_MEM(Editor);
|
||||
Managed->BeforeRun();
|
||||
}
|
||||
|
||||
void Editor::BeforeExit()
|
||||
{
|
||||
PROFILE_MEM(Editor);
|
||||
CloseSplashScreen();
|
||||
|
||||
Managed->Exit();
|
||||
@@ -708,6 +716,8 @@ void Editor::BeforeExit()
|
||||
|
||||
void EditorImpl::OnUpdate()
|
||||
{
|
||||
PROFILE_MEM(Editor);
|
||||
|
||||
// Update c# editor
|
||||
Editor::Managed->Update();
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ namespace FlaxEditor.GUI
|
||||
/// <summary>
|
||||
/// The column title horizontal text alignment
|
||||
/// </summary>
|
||||
public TextAlignment TitleAlignment = TextAlignment.Near;
|
||||
public TextAlignment TitleAlignment = TextAlignment.Center;
|
||||
|
||||
/// <summary>
|
||||
/// The column title margin.
|
||||
|
||||
@@ -114,9 +114,10 @@ namespace FlaxEditor.GUI.ContextMenu
|
||||
public ContextMenuBase()
|
||||
: base(0, 0, 120, 32)
|
||||
{
|
||||
_direction = ContextMenuDirection.RightDown;
|
||||
Visible = false;
|
||||
AutoFocus = true;
|
||||
|
||||
_direction = ContextMenuDirection.RightDown;
|
||||
_isSubMenu = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -76,6 +76,8 @@ namespace FlaxEditor.GUI.Dialogs
|
||||
public ColorSelector(float wheelSize)
|
||||
: base(0, 0, wheelSize, wheelSize)
|
||||
{
|
||||
AutoFocus = true;
|
||||
|
||||
_colorWheelSprite = Editor.Instance.Icons.ColorWheel128;
|
||||
_wheelRect = new Rectangle(0, 0, wheelSize, wheelSize);
|
||||
}
|
||||
|
||||
@@ -70,8 +70,6 @@ namespace FlaxEditor.GUI.Docking
|
||||
internal DockPanelProxy(DockPanel panel)
|
||||
: base(0, 0, 64, 64)
|
||||
{
|
||||
AutoFocus = false;
|
||||
|
||||
_panel = panel;
|
||||
AnchorPreset = AnchorPresets.StretchAll;
|
||||
Offsets = Margin.Zero;
|
||||
|
||||
@@ -368,6 +368,8 @@ namespace FlaxEditor.GUI.Input
|
||||
public SliderControl(float value, float x = 0, float y = 0, float width = 120, float min = float.MinValue, float max = float.MaxValue)
|
||||
: base(x, y, width, TextBox.DefaultHeight)
|
||||
{
|
||||
AutoFocus = true;
|
||||
|
||||
_min = min;
|
||||
_max = max;
|
||||
_value = Mathf.Clamp(value, min, max);
|
||||
|
||||
@@ -319,6 +319,8 @@ namespace FlaxEditor.GUI.Tree
|
||||
public TreeNode(bool canChangeOrder, SpriteHandle iconCollapsed, SpriteHandle iconOpened)
|
||||
: base(0, 0, 64, 16)
|
||||
{
|
||||
AutoFocus = true;
|
||||
|
||||
_canChangeOrder = canChangeOrder;
|
||||
_animationProgress = 1.0f;
|
||||
_cachedHeight = _headerHeight;
|
||||
|
||||
@@ -155,6 +155,7 @@ namespace FlaxEditor.Gizmo
|
||||
// Ensure player is not moving objects
|
||||
if (ActiveAxis != Axis.None)
|
||||
return;
|
||||
Profiler.BeginEvent("Pick");
|
||||
|
||||
// Get mouse ray and try to hit any object
|
||||
var ray = Owner.MouseRay;
|
||||
@@ -243,6 +244,8 @@ namespace FlaxEditor.Gizmo
|
||||
{
|
||||
sceneEditing.Deselect();
|
||||
}
|
||||
|
||||
Profiler.EndEvent();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "Engine/Platform/WindowsManager.h"
|
||||
#include "Engine/Content/Assets/VisualScript.h"
|
||||
#include "Engine/Content/Content.h"
|
||||
#include "Engine/Level/Actor.h"
|
||||
#include "Engine/CSG/CSGBuilder.h"
|
||||
#include "Engine/Engine/CommandLine.h"
|
||||
#include "Engine/Renderer/ProbesRenderer.h"
|
||||
@@ -75,7 +76,7 @@ void OnLightmapsBuildFinished(bool failed)
|
||||
OnLightmapsBake(ShadowsOfMordor::BuildProgressStep::GenerateLightmapCharts, 0, 0, false);
|
||||
}
|
||||
|
||||
void OnBakeEvent(bool started, const ProbesRenderer::Entry& e)
|
||||
void OnBakeEvent(bool started, Actor* e)
|
||||
{
|
||||
if (Internal_EnvProbeBake == nullptr)
|
||||
{
|
||||
@@ -83,7 +84,7 @@ void OnBakeEvent(bool started, const ProbesRenderer::Entry& e)
|
||||
ASSERT(Internal_EnvProbeBake);
|
||||
}
|
||||
|
||||
MObject* probeObj = e.Actor ? e.Actor->GetManagedInstance() : nullptr;
|
||||
MObject* probeObj = e ? e->GetManagedInstance() : nullptr;
|
||||
|
||||
MainThreadManagedInvokeAction::ParamsBuilder params;
|
||||
params.AddParam(started);
|
||||
@@ -91,12 +92,12 @@ void OnBakeEvent(bool started, const ProbesRenderer::Entry& e)
|
||||
MainThreadManagedInvokeAction::Invoke(Internal_EnvProbeBake, params);
|
||||
}
|
||||
|
||||
void OnRegisterBake(const ProbesRenderer::Entry& e)
|
||||
void OnRegisterBake(Actor* e)
|
||||
{
|
||||
OnBakeEvent(true, e);
|
||||
}
|
||||
|
||||
void OnFinishBake(const ProbesRenderer::Entry& e)
|
||||
void OnFinishBake(Actor* e)
|
||||
{
|
||||
OnBakeEvent(false, e);
|
||||
}
|
||||
@@ -157,7 +158,9 @@ ManagedEditor::ManagedEditor()
|
||||
lightmapsBuilder->OnBuildProgress.Bind<OnLightmapsBuildProgress>();
|
||||
lightmapsBuilder->OnBuildFinished.Bind<OnLightmapsBuildFinished>();
|
||||
CSG::Builder::OnBrushModified.Bind<OnBrushModified>();
|
||||
#if LOG_ENABLE
|
||||
Log::Logger::OnMessage.Bind<OnLogMessage>();
|
||||
#endif
|
||||
VisualScripting::DebugFlow.Bind<OnVisualScriptingDebugFlow>();
|
||||
}
|
||||
|
||||
@@ -173,7 +176,9 @@ ManagedEditor::~ManagedEditor()
|
||||
lightmapsBuilder->OnBuildProgress.Unbind<OnLightmapsBuildProgress>();
|
||||
lightmapsBuilder->OnBuildFinished.Unbind<OnLightmapsBuildFinished>();
|
||||
CSG::Builder::OnBrushModified.Unbind<OnBrushModified>();
|
||||
#if LOG_ENABLE
|
||||
Log::Logger::OnMessage.Unbind<OnLogMessage>();
|
||||
#endif
|
||||
VisualScripting::DebugFlow.Unbind<OnVisualScriptingDebugFlow>();
|
||||
}
|
||||
|
||||
|
||||
@@ -712,7 +712,11 @@ namespace FlaxEditor.Modules
|
||||
|
||||
private void OnActorChildNodesDispose(ActorNode node)
|
||||
{
|
||||
if (Selection.Count == 0)
|
||||
return;
|
||||
|
||||
// TODO: cache if selection contains any actor child node and skip this loop if no need to iterate
|
||||
// TODO: or build a hash set with selected nodes for quick O(1) checks (cached until selection changes)
|
||||
|
||||
// Deselect child nodes
|
||||
for (int i = 0; i < node.ChildNodes.Count; i++)
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using FlaxEditor.SceneGraph;
|
||||
using FlaxEditor.SceneGraph.Actors;
|
||||
using FlaxEngine;
|
||||
@@ -662,6 +663,48 @@ namespace FlaxEditor.Modules
|
||||
//node?.TreeNode.OnActiveChanged();
|
||||
}
|
||||
|
||||
private void OnActorDestroyChildren(Actor actor)
|
||||
{
|
||||
// Instead of doing OnActorParentChanged for every child lets remove all of them at once from that actor
|
||||
ActorNode node = GetActorNode(actor);
|
||||
if (node != null)
|
||||
{
|
||||
if (Editor.SceneEditing.HasSthSelected)
|
||||
{
|
||||
// Clear selection if one of the removed actors is selected
|
||||
var selection = new HashSet<Actor>();
|
||||
foreach (var e in Editor.SceneEditing.Selection)
|
||||
{
|
||||
if (e is ActorNode q && q.Actor)
|
||||
selection.Add(q.Actor);
|
||||
}
|
||||
var count = actor.ChildrenCount;
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
var child = actor.GetChild(i);
|
||||
if (selection.Contains(child))
|
||||
{
|
||||
Editor.SceneEditing.Deselect();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove all child nodes (upfront remove all nodes to run faster)
|
||||
for (int i = 0; i < node.ChildNodes.Count; i++)
|
||||
{
|
||||
if (node.ChildNodes[i] is ActorNode child)
|
||||
child.parentNode = null;
|
||||
}
|
||||
node.TreeNode.DisposeChildren();
|
||||
for (int i = 0; i < node.ChildNodes.Count; i++)
|
||||
{
|
||||
node.ChildNodes[i].Dispose();
|
||||
}
|
||||
node.ChildNodes.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the actor node.
|
||||
/// </summary>
|
||||
@@ -713,6 +756,7 @@ namespace FlaxEditor.Modules
|
||||
Level.ActorOrderInParentChanged += OnActorOrderInParentChanged;
|
||||
Level.ActorNameChanged += OnActorNameChanged;
|
||||
Level.ActorActiveChanged += OnActorActiveChanged;
|
||||
Level.ActorDestroyChildren += OnActorDestroyChildren;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -730,6 +774,7 @@ namespace FlaxEditor.Modules
|
||||
Level.ActorOrderInParentChanged -= OnActorOrderInParentChanged;
|
||||
Level.ActorNameChanged -= OnActorNameChanged;
|
||||
Level.ActorActiveChanged -= OnActorActiveChanged;
|
||||
Level.ActorDestroyChildren -= OnActorDestroyChildren;
|
||||
|
||||
// Cleanup graph
|
||||
Root.Dispose();
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "Engine/Core/Log.h"
|
||||
#include "Engine/Engine/Globals.h"
|
||||
#include "Engine/Core/Math/Quaternion.h"
|
||||
#include "Engine/Profiler/ProfilerMemory.h"
|
||||
#include "Engine/Serialization/JsonWriters.h"
|
||||
#include "Engine/Serialization/JsonTools.h"
|
||||
#include <ThirdParty/pugixml/pugixml.hpp>
|
||||
@@ -327,6 +328,7 @@ ProjectInfo* ProjectInfo::Load(const String& path)
|
||||
}
|
||||
|
||||
// Load
|
||||
PROFILE_MEM(Editor);
|
||||
auto project = New<ProjectInfo>();
|
||||
if (project->LoadProject(path))
|
||||
{
|
||||
|
||||
@@ -97,13 +97,16 @@ namespace FlaxEditor.SceneGraph
|
||||
/// <returns>Hit object or null if there is no intersection at all.</returns>
|
||||
public SceneGraphNode RayCast(ref Ray ray, ref Ray view, out Real distance, RayCastData.FlagTypes flags = RayCastData.FlagTypes.None)
|
||||
{
|
||||
Profiler.BeginEvent("RayCastScene");
|
||||
var data = new RayCastData
|
||||
{
|
||||
Ray = ray,
|
||||
View = view,
|
||||
Flags = flags
|
||||
};
|
||||
return RayCast(ref data, out distance, out _);
|
||||
var result = RayCast(ref data, out distance, out _);
|
||||
Profiler.EndEvent();
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -117,13 +120,16 @@ namespace FlaxEditor.SceneGraph
|
||||
/// <returns>Hit object or null if there is no intersection at all.</returns>
|
||||
public SceneGraphNode RayCast(ref Ray ray, ref Ray view, out Real distance, out Vector3 normal, RayCastData.FlagTypes flags = RayCastData.FlagTypes.None)
|
||||
{
|
||||
Profiler.BeginEvent("RayCastScene");
|
||||
var data = new RayCastData
|
||||
{
|
||||
Ray = ray,
|
||||
View = view,
|
||||
Flags = flags
|
||||
};
|
||||
return RayCast(ref data, out distance, out normal);
|
||||
var result = RayCast(ref data, out distance, out normal);
|
||||
Profiler.EndEvent();
|
||||
return result;
|
||||
}
|
||||
|
||||
internal static Quaternion RaycastNormalRotation(ref Vector3 normal)
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace FlaxEditor.SceneGraph
|
||||
/// <summary>
|
||||
/// The parent node.
|
||||
/// </summary>
|
||||
protected SceneGraphNode parentNode;
|
||||
internal SceneGraphNode parentNode;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the children list.
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "Engine/Engine/EngineService.h"
|
||||
#include "Engine/Platform/Thread.h"
|
||||
#include "Engine/Threading/IRunnable.h"
|
||||
#include "Engine/Profiler/ProfilerMemory.h"
|
||||
|
||||
void OnAsyncBegin(Thread* thread);
|
||||
void OnAsyncEnd();
|
||||
@@ -232,6 +233,8 @@ void OnAsyncEnd()
|
||||
|
||||
bool CodeEditingManagerService::Init()
|
||||
{
|
||||
PROFILE_MEM(Editor);
|
||||
|
||||
// Try get editors
|
||||
#if USE_VISUAL_STUDIO_DTE
|
||||
VisualStudioEditor::FindEditors(&CodeEditors);
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "Engine/Scripting/Scripting.h"
|
||||
#include "Engine/Scripting/Script.h"
|
||||
#include "Engine/Profiler/ProfilerCPU.h"
|
||||
#include "Engine/Profiler/ProfilerMemory.h"
|
||||
#include "Engine/Level/Level.h"
|
||||
#include "FlaxEngine.Gen.h"
|
||||
|
||||
@@ -77,7 +78,7 @@ namespace ScriptsBuilderImpl
|
||||
void onScriptsReloadEnd();
|
||||
void onScriptsLoaded();
|
||||
|
||||
void GetClassName(const StringAnsi& fullname, StringAnsi& className);
|
||||
void GetClassName(const StringAnsiView fullname, StringAnsi& className);
|
||||
|
||||
void onCodeEditorAsyncOpenBegin()
|
||||
{
|
||||
@@ -272,7 +273,7 @@ bool ScriptsBuilder::GenerateProject(const StringView& customArgs)
|
||||
return RunBuildTool(args);
|
||||
}
|
||||
|
||||
void ScriptsBuilderImpl::GetClassName(const StringAnsi& fullname, StringAnsi& className)
|
||||
void ScriptsBuilderImpl::GetClassName(const StringAnsiView fullname, StringAnsi& className)
|
||||
{
|
||||
const auto lastDotIndex = fullname.FindLast('.');
|
||||
if (lastDotIndex != -1)
|
||||
@@ -413,6 +414,7 @@ void ScriptsBuilder::GetBinariesConfiguration(const Char*& target, const Char*&
|
||||
|
||||
bool ScriptsBuilderImpl::compileGameScriptsAsyncInner()
|
||||
{
|
||||
PROFILE_MEM(Editor);
|
||||
LOG(Info, "Starting scripts compilation...");
|
||||
CallEvent(EventType::CompileStarted);
|
||||
|
||||
@@ -519,6 +521,8 @@ void ScriptsBuilderImpl::onEditorAssemblyUnloading(MAssembly* assembly)
|
||||
|
||||
bool ScriptsBuilderImpl::compileGameScriptsAsync()
|
||||
{
|
||||
PROFILE_MEM(Editor);
|
||||
|
||||
// Start
|
||||
{
|
||||
ScopeLock scopeLock(_locker);
|
||||
@@ -562,6 +566,7 @@ bool ScriptsBuilderService::Init()
|
||||
// Check flag
|
||||
if (_isInited)
|
||||
return false;
|
||||
PROFILE_MEM(Editor);
|
||||
_isInited = true;
|
||||
|
||||
// Link for Editor assembly unload event to clear cached Internal_OnCompilationEnd to prevent errors
|
||||
@@ -659,6 +664,9 @@ bool ScriptsBuilderService::Init()
|
||||
|
||||
void ScriptsBuilderService::Update()
|
||||
{
|
||||
PROFILE_CPU();
|
||||
PROFILE_MEM(Editor);
|
||||
|
||||
// Send compilation events
|
||||
{
|
||||
ScopeLock scopeLock(_compileEventsLocker);
|
||||
|
||||
@@ -233,6 +233,8 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
public BlendPointsEditor(Animation.MultiBlend node, bool is2D, float x, float y, float width, float height)
|
||||
: base(x, y, width, height)
|
||||
{
|
||||
AutoFocus = true;
|
||||
|
||||
_node = node;
|
||||
_is2D = is2D;
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ using FlaxEditor.Scripting;
|
||||
using FlaxEditor.Surface.Elements;
|
||||
using FlaxEditor.Windows.Assets;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.GUI;
|
||||
|
||||
namespace FlaxEditor.Surface.Archetypes
|
||||
{
|
||||
@@ -123,7 +124,8 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
case MaterialDomain.Particle:
|
||||
case MaterialDomain.Deformable:
|
||||
{
|
||||
bool isNotUnlit = info.ShadingModel != MaterialShadingModel.Unlit;
|
||||
bool isNotUnlit = info.ShadingModel != MaterialShadingModel.Unlit && info.ShadingModel != MaterialShadingModel.CustomLit;
|
||||
bool isOpaque = info.BlendMode == MaterialBlendMode.Opaque;
|
||||
bool withTess = info.TessellationMode != TessellationMethod.None;
|
||||
|
||||
GetBox(MaterialNodeBoxes.Color).IsActive = isNotUnlit;
|
||||
@@ -134,8 +136,8 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
GetBox(MaterialNodeBoxes.Roughness).IsActive = isNotUnlit;
|
||||
GetBox(MaterialNodeBoxes.AmbientOcclusion).IsActive = isNotUnlit;
|
||||
GetBox(MaterialNodeBoxes.Normal).IsActive = isNotUnlit;
|
||||
GetBox(MaterialNodeBoxes.Opacity).IsActive = info.ShadingModel == MaterialShadingModel.Subsurface || info.ShadingModel == MaterialShadingModel.Foliage || info.BlendMode != MaterialBlendMode.Opaque;
|
||||
GetBox(MaterialNodeBoxes.Refraction).IsActive = info.BlendMode != MaterialBlendMode.Opaque;
|
||||
GetBox(MaterialNodeBoxes.Opacity).IsActive = info.ShadingModel == MaterialShadingModel.Subsurface || info.ShadingModel == MaterialShadingModel.Foliage || !isOpaque;
|
||||
GetBox(MaterialNodeBoxes.Refraction).IsActive = !isOpaque;
|
||||
GetBox(MaterialNodeBoxes.PositionOffset).IsActive = true;
|
||||
GetBox(MaterialNodeBoxes.TessellationMultiplier).IsActive = withTess;
|
||||
GetBox(MaterialNodeBoxes.WorldDisplacement).IsActive = withTess;
|
||||
@@ -260,6 +262,211 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
}
|
||||
}
|
||||
|
||||
#if false // TODO: finish code editor based on RichTextBoxBase with text block parsing for custom styling
|
||||
internal sealed class CustomCodeTextBox : RichTextBoxBase
|
||||
{
|
||||
protected override void OnParseTextBlocks()
|
||||
{
|
||||
base.OnParseTextBlocks();
|
||||
|
||||
// Single block for a whole text
|
||||
// TODO: implement code parsing with HLSL syntax
|
||||
var font = Style.Current.FontMedium;
|
||||
var style = new TextBlockStyle
|
||||
{
|
||||
Font = new FontReference(font),
|
||||
Color = Style.Current.Foreground,
|
||||
BackgroundSelectedBrush = new SolidColorBrush(Style.Current.BackgroundSelected),
|
||||
};
|
||||
_textBlocks.Clear();
|
||||
_textBlocks.Add(new TextBlock
|
||||
{
|
||||
Range = new TextRange
|
||||
{
|
||||
StartIndex = 0,
|
||||
EndIndex = TextLength,
|
||||
},
|
||||
Style = style,
|
||||
Bounds = new Rectangle(Float2.Zero, font.MeasureText(Text)),
|
||||
});
|
||||
}
|
||||
#else
|
||||
internal sealed class CustomCodeTextBox : TextBox
|
||||
{
|
||||
#endif
|
||||
public override void Draw()
|
||||
{
|
||||
base.Draw();
|
||||
|
||||
// Draw border
|
||||
if (!IsFocused)
|
||||
Render2D.DrawRectangle(new Rectangle(Float2.Zero, Size), Style.Current.BorderNormal);
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class CustomCodeNode : SurfaceNode
|
||||
{
|
||||
private Rectangle _resizeButtonRect;
|
||||
private Float2 _startResizingSize;
|
||||
private Float2 _startResizingCornerOffset;
|
||||
private bool _isResizing;
|
||||
private CustomCodeTextBox _textBox;
|
||||
|
||||
private int SizeValueIndex => Archetype.TypeID == 8 ? 1 : 3; // Index of the Size stored in Values array
|
||||
|
||||
private Float2 SizeValue
|
||||
{
|
||||
get => (Float2)Values[SizeValueIndex];
|
||||
set => SetValue(SizeValueIndex, value, false);
|
||||
}
|
||||
|
||||
public CustomCodeNode(uint id, VisjectSurfaceContext context, NodeArchetype nodeArch, GroupArchetype groupArch)
|
||||
: base(id, context, nodeArch, groupArch)
|
||||
{
|
||||
Float2 pos = new Float2(FlaxEditor.Surface.Constants.NodeMarginX, FlaxEditor.Surface.Constants.NodeMarginY + FlaxEditor.Surface.Constants.NodeHeaderSize), size;
|
||||
if (nodeArch.TypeID == 8)
|
||||
{
|
||||
pos += new Float2(60, 0);
|
||||
size = new Float2(172, 200);
|
||||
}
|
||||
else
|
||||
{
|
||||
pos += new Float2(0, 40);
|
||||
size = new Float2(300, 200);
|
||||
}
|
||||
_textBox = new CustomCodeTextBox
|
||||
{
|
||||
IsMultiline = true,
|
||||
Location = pos,
|
||||
Size = size,
|
||||
Parent = this,
|
||||
AnchorMax = Float2.One,
|
||||
};
|
||||
_textBox.EditEnd += () => SetValue(0, _textBox.Text);
|
||||
}
|
||||
|
||||
public override bool CanSelect(ref Float2 location)
|
||||
{
|
||||
return base.CanSelect(ref location) && !_resizeButtonRect.MakeOffsetted(Location).Contains(ref location);
|
||||
}
|
||||
|
||||
public override void OnSurfaceLoaded(SurfaceNodeActions action)
|
||||
{
|
||||
base.OnSurfaceLoaded(action);
|
||||
|
||||
_textBox.Text = (string)Values[0];
|
||||
|
||||
var size = SizeValue;
|
||||
if (Surface != null && Surface.GridSnappingEnabled)
|
||||
size = Surface.SnapToGrid(size, true);
|
||||
Resize(size.X, size.Y);
|
||||
}
|
||||
|
||||
public override void OnValuesChanged()
|
||||
{
|
||||
base.OnValuesChanged();
|
||||
|
||||
var size = SizeValue;
|
||||
Resize(size.X, size.Y);
|
||||
_textBox.Text = (string)Values[0];
|
||||
}
|
||||
|
||||
protected override void UpdateRectangles()
|
||||
{
|
||||
base.UpdateRectangles();
|
||||
|
||||
const float buttonMargin = FlaxEditor.Surface.Constants.NodeCloseButtonMargin;
|
||||
const float buttonSize = FlaxEditor.Surface.Constants.NodeCloseButtonSize;
|
||||
_resizeButtonRect = new Rectangle(_closeButtonRect.Left, Height - buttonSize - buttonMargin - 4, buttonSize, buttonSize);
|
||||
}
|
||||
|
||||
public override void Draw()
|
||||
{
|
||||
base.Draw();
|
||||
|
||||
var style = Style.Current;
|
||||
if (_isResizing)
|
||||
{
|
||||
Render2D.FillRectangle(_resizeButtonRect, style.Selection);
|
||||
Render2D.DrawRectangle(_resizeButtonRect, style.SelectionBorder);
|
||||
}
|
||||
Render2D.DrawSprite(style.Scale, _resizeButtonRect, _resizeButtonRect.Contains(_mousePosition) && Surface.CanEdit ? style.Foreground : style.ForegroundGrey);
|
||||
}
|
||||
|
||||
public override void OnLostFocus()
|
||||
{
|
||||
if (_isResizing)
|
||||
EndResizing();
|
||||
|
||||
base.OnLostFocus();
|
||||
}
|
||||
|
||||
public override void OnEndMouseCapture()
|
||||
{
|
||||
if (_isResizing)
|
||||
EndResizing();
|
||||
|
||||
base.OnEndMouseCapture();
|
||||
}
|
||||
|
||||
public override bool OnMouseDown(Float2 location, MouseButton button)
|
||||
{
|
||||
if (base.OnMouseDown(location, button))
|
||||
return true;
|
||||
|
||||
if (button == MouseButton.Left && _resizeButtonRect.Contains(ref location) && Surface.CanEdit)
|
||||
{
|
||||
// Start sliding
|
||||
_isResizing = true;
|
||||
_startResizingSize = Size;
|
||||
_startResizingCornerOffset = Size - location;
|
||||
StartMouseCapture();
|
||||
Cursor = CursorType.SizeNWSE;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public override void OnMouseMove(Float2 location)
|
||||
{
|
||||
if (_isResizing)
|
||||
{
|
||||
var emptySize = CalculateNodeSize(0, 0);
|
||||
var size = Float2.Max(location - emptySize + _startResizingCornerOffset, new Float2(240, 160));
|
||||
Resize(size.X, size.Y);
|
||||
}
|
||||
else
|
||||
{
|
||||
base.OnMouseMove(location);
|
||||
}
|
||||
}
|
||||
|
||||
public override bool OnMouseUp(Float2 location, MouseButton button)
|
||||
{
|
||||
if (button == MouseButton.Left && _isResizing)
|
||||
{
|
||||
EndResizing();
|
||||
return true;
|
||||
}
|
||||
|
||||
return base.OnMouseUp(location, button);
|
||||
}
|
||||
|
||||
private void EndResizing()
|
||||
{
|
||||
Cursor = CursorType.Default;
|
||||
EndMouseCapture();
|
||||
_isResizing = false;
|
||||
if (_startResizingSize != Size)
|
||||
{
|
||||
var emptySize = CalculateNodeSize(0, 0);
|
||||
SizeValue = Size - emptySize;
|
||||
Surface.MarkAsEdited(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal enum MaterialTemplateInputsMapping
|
||||
{
|
||||
/// <summary>
|
||||
@@ -410,13 +617,15 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
new NodeArchetype
|
||||
{
|
||||
TypeID = 8,
|
||||
Create = (id, context, arch, groupArch) => new CustomCodeNode(id, context, arch, groupArch),
|
||||
Title = "Custom Code",
|
||||
Description = "Custom HLSL shader code expression",
|
||||
Flags = NodeFlags.MaterialGraph,
|
||||
Size = new Float2(300, 200),
|
||||
DefaultValues = new object[]
|
||||
{
|
||||
"// Here you can add HLSL code\nOutput0 = Input0;"
|
||||
"// Here you can add HLSL code\nOutput0 = Input0;",
|
||||
new Float2(300, 200),
|
||||
},
|
||||
Elements = new[]
|
||||
{
|
||||
@@ -433,8 +642,6 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
NodeElementArchetype.Factory.Output(1, "Output1", typeof(Float4), 9),
|
||||
NodeElementArchetype.Factory.Output(2, "Output2", typeof(Float4), 10),
|
||||
NodeElementArchetype.Factory.Output(3, "Output3", typeof(Float4), 11),
|
||||
|
||||
NodeElementArchetype.Factory.TextBox(60, 0, 175, 200, 0),
|
||||
}
|
||||
},
|
||||
new NodeArchetype
|
||||
@@ -874,6 +1081,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
new NodeArchetype
|
||||
{
|
||||
TypeID = 38,
|
||||
Create = (id, context, arch, groupArch) => new CustomCodeNode(id, context, arch, groupArch),
|
||||
Title = "Custom Global Code",
|
||||
Description = "Custom global HLSL shader code expression (placed before material shader code). Can contain includes to shader utilities or declare functions to reuse later.",
|
||||
Flags = NodeFlags.MaterialGraph,
|
||||
@@ -883,6 +1091,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
"// Here you can add HLSL code\nfloat4 GetCustomColor()\n{\n\treturn float4(1, 0, 0, 1);\n}",
|
||||
true,
|
||||
(int)MaterialTemplateInputsMapping.Utilities,
|
||||
new Float2(300, 240),
|
||||
},
|
||||
Elements = new[]
|
||||
{
|
||||
@@ -890,7 +1099,6 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
NodeElementArchetype.Factory.Text(20, 0, "Enabled"),
|
||||
NodeElementArchetype.Factory.Text(0, 20, "Location"),
|
||||
NodeElementArchetype.Factory.Enum(50, 20, 120, 2, typeof(MaterialTemplateInputsMapping)),
|
||||
NodeElementArchetype.Factory.TextBox(0, 40, 300, 200, 0),
|
||||
}
|
||||
},
|
||||
new NodeArchetype
|
||||
|
||||
@@ -1390,7 +1390,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
Elements = new[]
|
||||
{
|
||||
NodeElementArchetype.Factory.Output(0, "Time", typeof(float), 0),
|
||||
NodeElementArchetype.Factory.Output(1, "Unscaled Time", typeof(float), 1),
|
||||
NodeElementArchetype.Factory.Output(1, "Scaled Time", typeof(float), 1),
|
||||
}
|
||||
},
|
||||
new NodeArchetype
|
||||
|
||||
@@ -64,6 +64,7 @@ namespace FlaxEditor.Surface.Elements
|
||||
{
|
||||
ParentNode = parentNode;
|
||||
Archetype = archetype;
|
||||
AutoFocus = true;
|
||||
|
||||
var back = Style.Current.TextBoxBackground;
|
||||
var grayOutFactor = 0.6f;
|
||||
|
||||
@@ -59,6 +59,7 @@ namespace FlaxEditor.Surface
|
||||
protected SurfaceControl(VisjectSurfaceContext context, float width, float height)
|
||||
: base(0, 0, width, height)
|
||||
{
|
||||
AutoFocus = true;
|
||||
ClipChildren = false;
|
||||
|
||||
Surface = context.Surface;
|
||||
|
||||
@@ -120,6 +120,8 @@ namespace FlaxEditor.Surface
|
||||
|
||||
private void UpdateSelectionRectangle()
|
||||
{
|
||||
if (Root == null)
|
||||
return;
|
||||
var p1 = _rootControl.PointFromParent(ref _leftMouseDownPos);
|
||||
var p2 = _rootControl.PointFromParent(ref _mousePos);
|
||||
var selectionRect = Rectangle.FromPoints(p1, p2);
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "Engine/Content/Assets/Model.h"
|
||||
#include "Engine/Content/Assets/MaterialInstance.h"
|
||||
#include "Engine/Content/Content.h"
|
||||
#include "Engine/Profiler/ProfilerMemory.h"
|
||||
#include "Engine/Level/Level.h"
|
||||
#include "Engine/Level/Scene/Scene.h"
|
||||
#include "Engine/Level/Actors/PointLight.h"
|
||||
@@ -88,6 +89,7 @@ void ViewportIconsRenderer::DrawIcons(RenderContext& renderContext, Actor* actor
|
||||
draw.Flags = StaticFlags::Transform;
|
||||
draw.DrawModes = DrawPass::Forward;
|
||||
draw.PerInstanceRandom = 0;
|
||||
draw.StencilValue = 0;
|
||||
draw.LODBias = 0;
|
||||
draw.ForcedLOD = -1;
|
||||
draw.SortOrder = 0;
|
||||
@@ -264,6 +266,7 @@ void ViewportIconsRendererService::DrawIcons(RenderContext& renderContext, Actor
|
||||
|
||||
bool ViewportIconsRendererService::Init()
|
||||
{
|
||||
PROFILE_MEM(Editor);
|
||||
QuadModel = Content::LoadAsyncInternal<Model>(TEXT("Engine/Models/Quad"));
|
||||
#define INIT(type, path) \
|
||||
InstanceBuffers[static_cast<int32>(IconTypes::type)].Setup(1); \
|
||||
|
||||
@@ -340,6 +340,13 @@ namespace FlaxEditor.Viewport
|
||||
{
|
||||
_debugDrawData.Clear();
|
||||
|
||||
if (task is SceneRenderTask sceneRenderTask)
|
||||
{
|
||||
// Sync debug view to avoid lag on culling/LODing
|
||||
var view = sceneRenderTask.View;
|
||||
DebugDraw.SetView(ref view);
|
||||
}
|
||||
|
||||
// Collect selected objects debug shapes and visuals
|
||||
var selectedParents = TransformGizmo.SelectedParents;
|
||||
if (selectedParents.Count > 0)
|
||||
|
||||
@@ -329,7 +329,12 @@ namespace FlaxEditor.Viewport
|
||||
_tempDebugDrawContext = DebugDraw.AllocateContext();
|
||||
DebugDraw.SetContext(_tempDebugDrawContext);
|
||||
DebugDraw.UpdateContext(_tempDebugDrawContext, 1.0f);
|
||||
|
||||
if (task is SceneRenderTask sceneRenderTask)
|
||||
{
|
||||
// Sync debug view to avoid lag on culling/LODing
|
||||
var view = sceneRenderTask.View;
|
||||
DebugDraw.SetView(ref view);
|
||||
}
|
||||
for (int i = 0; i < selectedParents.Count; i++)
|
||||
{
|
||||
if (selectedParents[i].IsActiveInHierarchy)
|
||||
|
||||
@@ -264,6 +264,7 @@ namespace FlaxEditor.Viewport.Previews
|
||||
{
|
||||
DebugDraw.SetContext(_debugDrawContext);
|
||||
DebugDraw.UpdateContext(_debugDrawContext, 1.0f / Mathf.Max(Engine.FramesPerSecond, 1));
|
||||
DebugDraw.SetView(ref renderContext.View);
|
||||
CustomDebugDraw?.Invoke(context, ref renderContext);
|
||||
OnDebugDraw(context, ref renderContext);
|
||||
DebugDraw.Draw(ref renderContext, target.View(), targetDepth.View(), true);
|
||||
|
||||
@@ -181,15 +181,8 @@ namespace FlaxEditor.Windows.Assets
|
||||
|
||||
private class CollisionDataPreview : ModelBasePreview
|
||||
{
|
||||
public bool ShowCollisionData = false;
|
||||
private int _verticesCount = 0;
|
||||
private int _trianglesCount = 0;
|
||||
|
||||
public void SetVerticesAndTriangleCount(int verticesCount, int triangleCount)
|
||||
{
|
||||
_verticesCount = verticesCount;
|
||||
_trianglesCount = triangleCount;
|
||||
}
|
||||
public bool ShowInfo;
|
||||
public string Info;
|
||||
|
||||
/// <inheritdoc />
|
||||
public CollisionDataPreview(bool useWidgets)
|
||||
@@ -204,13 +197,12 @@ namespace FlaxEditor.Windows.Assets
|
||||
{
|
||||
base.Draw();
|
||||
|
||||
if (ShowCollisionData)
|
||||
if (ShowInfo)
|
||||
{
|
||||
var text = string.Format("\nTriangles: {0:N0}\nVertices: {1:N0}\nMemory Size: {2}", _trianglesCount, _verticesCount, Utilities.Utils.FormatBytesCount(Asset.MemoryUsage));
|
||||
var font = Style.Current.FontMedium;
|
||||
var pos = new Float2(10, 50);
|
||||
Render2D.DrawText(font, text, new Rectangle(pos + Float2.One, Size), Color.Black);
|
||||
Render2D.DrawText(font, text, new Rectangle(pos, Size), Color.White);
|
||||
Render2D.DrawText(font, Info, new Rectangle(pos + Float2.One, Size), Color.Black);
|
||||
Render2D.DrawText(font, Info, new Rectangle(pos, Size), Color.White);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -222,11 +214,11 @@ namespace FlaxEditor.Windows.Assets
|
||||
// Toolstrip
|
||||
_toolstrip.AddSeparator();
|
||||
_toolstrip.AddButton(editor.Icons.CenterView64, () => _preview.ResetCamera()).LinkTooltip("Show whole collision");
|
||||
var infoButton = (ToolStripButton)_toolstrip.AddButton(editor.Icons.Info64).LinkTooltip("Show Collision Data");
|
||||
var infoButton = (ToolStripButton)_toolstrip.AddButton(editor.Icons.Info64).LinkTooltip("Show Collision Data info");
|
||||
infoButton.Clicked += () =>
|
||||
{
|
||||
_preview.ShowCollisionData = !_preview.ShowCollisionData;
|
||||
infoButton.Checked = _preview.ShowCollisionData;
|
||||
_preview.ShowInfo = !_preview.ShowInfo;
|
||||
infoButton.Checked = _preview.ShowInfo;
|
||||
};
|
||||
_toolstrip.AddButton(editor.Icons.Docs64, () => Platform.OpenUrl(Utilities.Constants.DocsUrl + "manual/physics/colliders/collision-data.html")).LinkTooltip("See documentation to learn more");
|
||||
|
||||
@@ -293,7 +285,7 @@ namespace FlaxEditor.Windows.Assets
|
||||
}
|
||||
_collisionWiresShowActor.Model = _collisionWiresModel;
|
||||
_collisionWiresShowActor.SetMaterial(0, FlaxEngine.Content.LoadAsyncInternal<MaterialBase>(EditorAssets.WiresDebugMaterial));
|
||||
_preview.SetVerticesAndTriangleCount(triangleCount, indicesCount / 3);
|
||||
_preview.Info = string.Format("\nTriangles: {0:N0}\nVertices: {1:N0}\nMemory Size: {2}", triangleCount, indicesCount / 3, Utilities.Utils.FormatBytesCount(Asset.MemoryUsage));
|
||||
_preview.Asset = FlaxEngine.Content.LoadAsync<ModelBase>(_asset.Options.Model);
|
||||
}
|
||||
|
||||
|
||||
@@ -59,17 +59,11 @@ namespace FlaxEditor.Windows
|
||||
GameCookerWin = win;
|
||||
Selector = platformSelector;
|
||||
|
||||
PerPlatformOptions[PlatformType.Windows].Init("Output/Windows", "Windows");
|
||||
PerPlatformOptions[PlatformType.XboxOne].Init("Output/XboxOne", "XboxOne");
|
||||
PerPlatformOptions[PlatformType.UWP].Init("Output/UWP", "UWP");
|
||||
PerPlatformOptions[PlatformType.Linux].Init("Output/Linux", "Linux");
|
||||
PerPlatformOptions[PlatformType.PS4].Init("Output/PS4", "PS4");
|
||||
PerPlatformOptions[PlatformType.XboxScarlett].Init("Output/XboxScarlett", "XboxScarlett");
|
||||
PerPlatformOptions[PlatformType.Android].Init("Output/Android", "Android");
|
||||
PerPlatformOptions[PlatformType.Switch].Init("Output/Switch", "Switch");
|
||||
PerPlatformOptions[PlatformType.PS5].Init("Output/PS5", "PS5");
|
||||
PerPlatformOptions[PlatformType.Mac].Init("Output/Mac", "Mac");
|
||||
PerPlatformOptions[PlatformType.iOS].Init("Output/iOS", "iOS");
|
||||
foreach (var e in PerPlatformOptions)
|
||||
{
|
||||
var str = e.Key.ToString();
|
||||
e.Value.Init("Output/" + str, str);
|
||||
}
|
||||
}
|
||||
|
||||
[HideInEditor]
|
||||
@@ -196,12 +190,14 @@ namespace FlaxEditor.Windows
|
||||
var label = layout.Label(text, TextAlignment.Center);
|
||||
label.Label.AutoHeight = true;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Used to add platform specific tools if available.
|
||||
/// </summary>
|
||||
/// <param name="layout">The layout to start the tools at.</param>
|
||||
public virtual void OnCustomToolsLayout(LayoutElementsContainer layout) { }
|
||||
public virtual void OnCustomToolsLayout(LayoutElementsContainer layout)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void Build()
|
||||
{
|
||||
@@ -256,7 +252,7 @@ namespace FlaxEditor.Windows
|
||||
if (string.IsNullOrEmpty(sdkPath))
|
||||
sdkPath = Environment.GetEnvironmentVariable("ANDROID_SDK");
|
||||
emulatorGroup.Label($"SDK path: {sdkPath}");
|
||||
|
||||
|
||||
// AVD and starting emulator
|
||||
var avdGroup = emulatorGroup.Group("AVD Emulator");
|
||||
avdGroup.Label("Note: Create AVDs using Android Studio.");
|
||||
@@ -273,7 +269,7 @@ namespace FlaxEditor.Windows
|
||||
{
|
||||
if (avdListTree.Children.Count > 0)
|
||||
avdListTree.DisposeChildren();
|
||||
|
||||
|
||||
var processStartInfo = new System.Diagnostics.ProcessStartInfo
|
||||
{
|
||||
FileName = Path.Combine(sdkPath, "emulator", "emulator.exe"),
|
||||
@@ -299,7 +295,7 @@ namespace FlaxEditor.Windows
|
||||
};
|
||||
//processSettings.ShellExecute = true;
|
||||
FlaxEngine.Platform.CreateProcess(ref processSettings);
|
||||
|
||||
|
||||
var output = new string(processSettings.Output);*/
|
||||
if (output.Length == 0)
|
||||
{
|
||||
@@ -345,9 +341,9 @@ namespace FlaxEditor.Windows
|
||||
processSettings.ShellExecute = true;
|
||||
FlaxEngine.Platform.CreateProcess(ref processSettings);
|
||||
};
|
||||
|
||||
|
||||
emulatorGroup.Space(2);
|
||||
|
||||
|
||||
// Device
|
||||
var installGroup = emulatorGroup.Group("Install");
|
||||
installGroup.Panel.IsClosed = false;
|
||||
@@ -391,10 +387,10 @@ namespace FlaxEditor.Windows
|
||||
processSettings.SaveOutput = true;
|
||||
processSettings.ShellExecute = false;
|
||||
FlaxEngine.Platform.CreateProcess(ref processSettings);
|
||||
|
||||
|
||||
var output = new string(processSettings.Output);
|
||||
*/
|
||||
|
||||
|
||||
if (output.Length > 0 && !output.Equals("List of devices attached", StringComparison.Ordinal))
|
||||
{
|
||||
noDevicesLabel.Visible = false;
|
||||
@@ -403,7 +399,7 @@ namespace FlaxEditor.Windows
|
||||
{
|
||||
if (line.Trim().Equals("List of devices attached", StringComparison.Ordinal) || string.IsNullOrEmpty(line.Trim()))
|
||||
continue;
|
||||
|
||||
|
||||
var tab = line.Split("device ");
|
||||
if (tab.Length < 2)
|
||||
continue;
|
||||
@@ -430,7 +426,7 @@ namespace FlaxEditor.Windows
|
||||
{
|
||||
if (deviceListTree.Selection.Count == 0)
|
||||
return;
|
||||
|
||||
|
||||
// Get built APK at output path
|
||||
string output = StringUtils.ConvertRelativePathToAbsolute(Globals.ProjectFolder, StringUtils.NormalizePath(Output));
|
||||
if (!Directory.Exists(output))
|
||||
@@ -438,7 +434,7 @@ namespace FlaxEditor.Windows
|
||||
FlaxEditor.Editor.LogWarning("Can not copy APK because output folder does not exist.");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
var apkFiles = Directory.GetFiles(output, "*.apk");
|
||||
if (apkFiles.Length == 0)
|
||||
{
|
||||
@@ -457,7 +453,7 @@ namespace FlaxEditor.Windows
|
||||
}
|
||||
apkFilesString += $" \"{file}\"";
|
||||
}
|
||||
|
||||
|
||||
CreateProcessSettings processSettings = new CreateProcessSettings
|
||||
{
|
||||
FileName = Path.Combine(sdkPath, "platform-tools", "adb.exe"),
|
||||
|
||||
@@ -886,6 +886,12 @@ namespace FlaxEditor.Windows
|
||||
if (!_cursorVisible)
|
||||
Screen.CursorVisible = true;
|
||||
}
|
||||
|
||||
if (Editor.IsPlayMode && IsDocked && IsSelected && RootWindow.FocusedControl == null)
|
||||
{
|
||||
// Game UI cleared focus so regain it to maintain UI navigation just like game window does
|
||||
FlaxEngine.Scripting.InvokeOnUpdate(Focus);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
@@ -233,11 +233,10 @@ namespace FlaxEditor.Windows
|
||||
else
|
||||
cm.ClearItems();
|
||||
|
||||
float longestItemWidth = 0.0f;
|
||||
|
||||
// Add items
|
||||
var font = Style.Current.FontMedium;
|
||||
ItemsListContextMenu.Item lastItem = null;
|
||||
var itemFont = Style.Current.FontSmall;
|
||||
var maxWidth = 0.0f;
|
||||
foreach (var command in commands)
|
||||
{
|
||||
cm.AddItem(lastItem = new Item
|
||||
@@ -255,10 +254,7 @@ namespace FlaxEditor.Windows
|
||||
// Set command
|
||||
Set(item.Name);
|
||||
};
|
||||
|
||||
float width = font.MeasureText(command).X;
|
||||
if (width > longestItemWidth)
|
||||
longestItemWidth = width;
|
||||
maxWidth = Mathf.Max(maxWidth, itemFont.MeasureText(command).X);
|
||||
}
|
||||
cm.ItemClicked += item =>
|
||||
{
|
||||
@@ -269,13 +265,12 @@ namespace FlaxEditor.Windows
|
||||
// Setup popup
|
||||
var count = commands.Count();
|
||||
var totalHeight = count * lastItem.Height + cm.ItemsPanel.Margin.Height + cm.ItemsPanel.Spacing * (count - 1);
|
||||
|
||||
// Account for scroll bars taking up a part of the width
|
||||
longestItemWidth += 25f;
|
||||
cm.Width = longestItemWidth;
|
||||
cm.Height = 220;
|
||||
if (cm.Height > totalHeight)
|
||||
cm.Height = totalHeight; // Limit popup height if list is small
|
||||
maxWidth += 8.0f + ScrollBar.DefaultSize; // Margin
|
||||
if (cm.Width < maxWidth)
|
||||
cm.Width = maxWidth;
|
||||
if (searchText != null)
|
||||
{
|
||||
cm.SortItems();
|
||||
@@ -368,8 +363,8 @@ namespace FlaxEditor.Windows
|
||||
// Update history buffer
|
||||
if (_window._commandHistory == null)
|
||||
_window._commandHistory = new List<string>();
|
||||
else if (_window._commandHistory.Count != 0 && _window._commandHistory.Last() == command)
|
||||
_window._commandHistory.RemoveAt(_window._commandHistory.Count - 1);
|
||||
else if (_window._commandHistory.Count != 0 && _window._commandHistory.Contains(command))
|
||||
_window._commandHistory.Remove(command);
|
||||
_window._commandHistory.Add(command);
|
||||
if (_window._commandHistory.Count > CommandHistoryLimit)
|
||||
_window._commandHistory.RemoveAt(0);
|
||||
|
||||
@@ -34,6 +34,7 @@ namespace FlaxEditor.Windows.Profiler
|
||||
private List<ClickableRow> _tableRowsCache;
|
||||
private Dictionary<Guid, Resource> _resourceCache;
|
||||
private StringBuilder _stringBuilder;
|
||||
private Asset[] _assetsCache;
|
||||
|
||||
public Assets()
|
||||
: base("Assets")
|
||||
@@ -138,12 +139,12 @@ namespace FlaxEditor.Windows.Profiler
|
||||
_stringBuilder = new StringBuilder();
|
||||
|
||||
// Capture current assets usage info
|
||||
var assets = FlaxEngine.Content.Assets;
|
||||
var resources = new Resource[assets.Length];
|
||||
FlaxEngine.Content.GetAssets(ref _assetsCache, out var count);
|
||||
var resources = new Resource[count];
|
||||
ulong totalMemoryUsage = 0;
|
||||
for (int i = 0; i < resources.Length; i++)
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
var asset = assets[i];
|
||||
var asset = _assetsCache[i];
|
||||
ref var resource = ref resources[i];
|
||||
if (!asset)
|
||||
continue;
|
||||
@@ -179,6 +180,7 @@ namespace FlaxEditor.Windows.Profiler
|
||||
if (_resources == null)
|
||||
_resources = new SamplesBuffer<Resource[]>();
|
||||
_resources.Add(resources);
|
||||
Array.Clear(_assetsCache);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -200,6 +202,7 @@ namespace FlaxEditor.Windows.Profiler
|
||||
_resourceCache?.Clear();
|
||||
_tableRowsCache?.Clear();
|
||||
_stringBuilder?.Clear();
|
||||
_assetsCache = null;
|
||||
|
||||
base.OnDestroy();
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
#if USE_PROFILER
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using FlaxEditor.GUI;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.GUI;
|
||||
|
||||
@@ -13,9 +15,22 @@ namespace FlaxEditor.Windows.Profiler
|
||||
/// <seealso cref="FlaxEditor.Windows.Profiler.ProfilerMode" />
|
||||
internal sealed class Memory : ProfilerMode
|
||||
{
|
||||
private struct FrameData
|
||||
{
|
||||
public ProfilerMemory.GroupsArray Usage;
|
||||
public ProfilerMemory.GroupsArray Peek;
|
||||
public ProfilerMemory.GroupsArray Count;
|
||||
}
|
||||
|
||||
private readonly SingleChart _nativeAllocationsChart;
|
||||
private readonly SingleChart _managedAllocationsChart;
|
||||
|
||||
private readonly Table _table;
|
||||
private SamplesBuffer<FrameData> _frames;
|
||||
private List<Row> _tableRowsCache;
|
||||
private string[] _groupNames;
|
||||
private int[] _groupOrder;
|
||||
private Label _warningText;
|
||||
|
||||
public Memory()
|
||||
: base("Memory")
|
||||
{
|
||||
@@ -50,6 +65,70 @@ namespace FlaxEditor.Windows.Profiler
|
||||
Parent = layout,
|
||||
};
|
||||
_managedAllocationsChart.SelectedSampleChanged += OnSelectedSampleChanged;
|
||||
|
||||
// Warning text
|
||||
if (!ProfilerMemory.Enabled)
|
||||
{
|
||||
_warningText = new Label
|
||||
{
|
||||
Text = "Detailed memory profiling is disabled. Run with command line '-mem'",
|
||||
TextColor = Color.Red,
|
||||
Visible = false,
|
||||
Parent = layout,
|
||||
};
|
||||
}
|
||||
|
||||
// Table
|
||||
var style = Style.Current;
|
||||
var headerColor = style.LightBackground;
|
||||
var textColor = style.Foreground;
|
||||
_table = new Table
|
||||
{
|
||||
Columns = new[]
|
||||
{
|
||||
new ColumnDefinition
|
||||
{
|
||||
UseExpandCollapseMode = true,
|
||||
CellAlignment = TextAlignment.Near,
|
||||
Title = "Group",
|
||||
TitleBackgroundColor = headerColor,
|
||||
TitleColor = textColor,
|
||||
},
|
||||
new ColumnDefinition
|
||||
{
|
||||
Title = "Usage",
|
||||
TitleBackgroundColor = headerColor,
|
||||
FormatValue = FormatCellBytes,
|
||||
TitleColor = textColor,
|
||||
},
|
||||
new ColumnDefinition
|
||||
{
|
||||
Title = "Peek",
|
||||
TitleBackgroundColor = headerColor,
|
||||
FormatValue = FormatCellBytes,
|
||||
TitleColor = textColor,
|
||||
},
|
||||
new ColumnDefinition
|
||||
{
|
||||
Title = "Count",
|
||||
TitleBackgroundColor = headerColor,
|
||||
TitleColor = textColor,
|
||||
},
|
||||
},
|
||||
Parent = layout,
|
||||
};
|
||||
_table.Splits = new[]
|
||||
{
|
||||
0.5f,
|
||||
0.2f,
|
||||
0.2f,
|
||||
0.1f,
|
||||
};
|
||||
}
|
||||
|
||||
private string FormatCellBytes(object x)
|
||||
{
|
||||
return Utilities.Utils.FormatBytesCount(Convert.ToUInt64(x));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -57,6 +136,7 @@ namespace FlaxEditor.Windows.Profiler
|
||||
{
|
||||
_nativeAllocationsChart.Clear();
|
||||
_managedAllocationsChart.Clear();
|
||||
_frames?.Clear();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -84,6 +164,19 @@ namespace FlaxEditor.Windows.Profiler
|
||||
|
||||
_nativeAllocationsChart.AddSample(nativeMemoryAllocation);
|
||||
_managedAllocationsChart.AddSample(managedMemoryAllocation);
|
||||
|
||||
// Gather memory profiler stats for groups
|
||||
var frame = new FrameData
|
||||
{
|
||||
Usage = ProfilerMemory.GetGroups(0),
|
||||
Peek = ProfilerMemory.GetGroups(1),
|
||||
Count = ProfilerMemory.GetGroups(2),
|
||||
};
|
||||
if (_frames == null)
|
||||
_frames = new SamplesBuffer<FrameData>();
|
||||
if (_groupNames == null)
|
||||
_groupNames = ProfilerMemory.GetGroupNames();
|
||||
_frames.Add(frame);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -91,6 +184,112 @@ namespace FlaxEditor.Windows.Profiler
|
||||
{
|
||||
_nativeAllocationsChart.SelectedSampleIndex = selectedFrame;
|
||||
_managedAllocationsChart.SelectedSampleIndex = selectedFrame;
|
||||
|
||||
UpdateTable(selectedFrame);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnDestroy()
|
||||
{
|
||||
_tableRowsCache?.Clear();
|
||||
_groupNames = null;
|
||||
_groupOrder = null;
|
||||
|
||||
base.OnDestroy();
|
||||
}
|
||||
|
||||
private void UpdateTable(int selectedFrame)
|
||||
{
|
||||
if (_frames == null)
|
||||
return;
|
||||
if (_tableRowsCache == null)
|
||||
_tableRowsCache = new List<Row>();
|
||||
_table.IsLayoutLocked = true;
|
||||
|
||||
RecycleTableRows(_table, _tableRowsCache);
|
||||
UpdateTableInner(selectedFrame);
|
||||
|
||||
_table.UnlockChildrenRecursive();
|
||||
_table.PerformLayout();
|
||||
}
|
||||
|
||||
private unsafe void UpdateTableInner(int selectedFrame)
|
||||
{
|
||||
if (_frames.Count == 0)
|
||||
return;
|
||||
if (_warningText != null)
|
||||
_warningText.Visible = true;
|
||||
var frame = _frames.Get(selectedFrame);
|
||||
var totalUage = frame.Usage.Values0[(int)ProfilerMemory.Groups.TotalTracked];
|
||||
var totalPeek = frame.Peek.Values0[(int)ProfilerMemory.Groups.TotalTracked];
|
||||
var totalCount = frame.Count.Values0[(int)ProfilerMemory.Groups.TotalTracked];
|
||||
|
||||
// Sort by memory size
|
||||
if (_groupOrder == null)
|
||||
_groupOrder = new int[(int)ProfilerMemory.Groups.MAX];
|
||||
for (int i = 0; i < (int)ProfilerMemory.Groups.MAX; i++)
|
||||
_groupOrder[i] = i;
|
||||
Array.Sort(_groupOrder, (x, y) =>
|
||||
{
|
||||
var tmp = _frames.Get(selectedFrame);
|
||||
return tmp.Usage.Values0[y].CompareTo(tmp.Usage.Values0[x]);
|
||||
});
|
||||
|
||||
// Add rows
|
||||
var rowColor2 = Style.Current.Background * 1.4f;
|
||||
for (int i = 0; i < (int)ProfilerMemory.Groups.MAX; i++)
|
||||
{
|
||||
var group = _groupOrder[i];
|
||||
var groupUsage = frame.Usage.Values0[group];
|
||||
if (groupUsage <= 0)
|
||||
continue;
|
||||
var groupPeek = frame.Peek.Values0[group];
|
||||
var groupCount = frame.Count.Values0[group];
|
||||
|
||||
Row row;
|
||||
if (_tableRowsCache.Count != 0)
|
||||
{
|
||||
var last = _tableRowsCache.Count - 1;
|
||||
row = _tableRowsCache[last];
|
||||
_tableRowsCache.RemoveAt(last);
|
||||
}
|
||||
else
|
||||
{
|
||||
row = new Row
|
||||
{
|
||||
Values = new object[4],
|
||||
BackgroundColors = new Color[4],
|
||||
};
|
||||
}
|
||||
{
|
||||
// Group
|
||||
row.Values[0] = _groupNames[group];
|
||||
|
||||
// Usage
|
||||
row.Values[1] = groupUsage;
|
||||
row.BackgroundColors[1] = Color.Red.AlphaMultiplied(Mathf.Min(1, (float)groupUsage / totalUage) * 0.5f);
|
||||
|
||||
// Peek
|
||||
row.Values[2] = groupPeek;
|
||||
row.BackgroundColors[2] = Color.Red.AlphaMultiplied(Mathf.Min(1, (float)groupPeek / totalPeek) * 0.5f);
|
||||
|
||||
// Count
|
||||
row.Values[3] = groupCount;
|
||||
row.BackgroundColors[3] = Color.Red.AlphaMultiplied(Mathf.Min(1, (float)groupCount / totalCount) * 0.5f);
|
||||
}
|
||||
row.Width = _table.Width;
|
||||
row.BackgroundColor = i % 2 == 1 ? rowColor2 : Color.Transparent;
|
||||
row.Parent = _table;
|
||||
|
||||
var useBackground = group != (int)ProfilerMemory.Groups.Total &&
|
||||
group != (int)ProfilerMemory.Groups.TotalTracked &&
|
||||
group != (int)ProfilerMemory.Groups.Malloc;
|
||||
if (!useBackground)
|
||||
{
|
||||
for (int k = 1; k < row.BackgroundColors.Length; k++)
|
||||
row.BackgroundColors[k] = Color.Transparent;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@ namespace FlaxEditor.Windows.Profiler
|
||||
private Dictionary<string, Guid> _assetPathToId;
|
||||
private Dictionary<Guid, Resource> _resourceCache;
|
||||
private StringBuilder _stringBuilder;
|
||||
private GPUResource[] _gpuResourcesCached;
|
||||
|
||||
public MemoryGPU()
|
||||
: base("GPU Memory")
|
||||
@@ -138,13 +139,15 @@ namespace FlaxEditor.Windows.Profiler
|
||||
|
||||
// Capture current GPU resources usage info
|
||||
var contentDatabase = Editor.Instance.ContentDatabase;
|
||||
var gpuResources = GPUDevice.Instance.Resources;
|
||||
var resources = new Resource[gpuResources.Length];
|
||||
GPUDevice.Instance.GetResources(ref _gpuResourcesCached, out var count);
|
||||
var resources = new Resource[count];
|
||||
var sb = _stringBuilder;
|
||||
for (int i = 0; i < resources.Length; i++)
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
var gpuResource = gpuResources[i];
|
||||
var gpuResource = _gpuResourcesCached[i];
|
||||
ref var resource = ref resources[i];
|
||||
if (!gpuResource)
|
||||
continue;
|
||||
|
||||
// Try to reuse cached resource info
|
||||
var gpuResourceId = gpuResource.ID;
|
||||
@@ -219,6 +222,7 @@ namespace FlaxEditor.Windows.Profiler
|
||||
if (_resources == null)
|
||||
_resources = new SamplesBuffer<Resource[]>();
|
||||
_resources.Add(resources);
|
||||
Array.Clear(_gpuResourcesCached);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -255,6 +259,7 @@ namespace FlaxEditor.Windows.Profiler
|
||||
_assetPathToId?.Clear();
|
||||
_tableRowsCache?.Clear();
|
||||
_stringBuilder?.Clear();
|
||||
_gpuResourcesCached = null;
|
||||
|
||||
base.OnDestroy();
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "Engine/Engine/Time.h"
|
||||
#include "Engine/Engine/EngineService.h"
|
||||
#include "Engine/Profiler/ProfilerCPU.h"
|
||||
#include "Engine/Profiler/ProfilerMemory.h"
|
||||
#include "Engine/Threading/TaskGraph.h"
|
||||
|
||||
class BehaviorSystem : public TaskGraphSystem
|
||||
@@ -38,6 +39,7 @@ TaskGraphSystem* Behavior::System = nullptr;
|
||||
void BehaviorSystem::Job(int32 index)
|
||||
{
|
||||
PROFILE_CPU_NAMED("Behavior.Job");
|
||||
PROFILE_MEM(AI);
|
||||
Behaviors[index]->UpdateAsync();
|
||||
}
|
||||
|
||||
@@ -57,6 +59,7 @@ void BehaviorSystem::Execute(TaskGraph* graph)
|
||||
|
||||
bool BehaviorService::Init()
|
||||
{
|
||||
PROFILE_MEM(AI);
|
||||
Behavior::System = New<BehaviorSystem>();
|
||||
Engine::UpdateGraph->AddSystem(Behavior::System);
|
||||
return false;
|
||||
@@ -70,9 +73,9 @@ void BehaviorService::Dispose()
|
||||
|
||||
Behavior::Behavior(const SpawnParams& params)
|
||||
: Script(params)
|
||||
, Tree(this)
|
||||
{
|
||||
_knowledge.Behavior = this;
|
||||
Tree.Changed.Bind<Behavior, &Behavior::ResetLogic>(this);
|
||||
}
|
||||
|
||||
void Behavior::UpdateAsync()
|
||||
@@ -172,6 +175,19 @@ void Behavior::OnDisable()
|
||||
BehaviorServiceInstance.UpdateList.Remove(this);
|
||||
}
|
||||
|
||||
void Behavior::OnAssetChanged(Asset* asset, void* caller)
|
||||
{
|
||||
ResetLogic();
|
||||
}
|
||||
|
||||
void Behavior::OnAssetLoaded(Asset* asset, void* caller)
|
||||
{
|
||||
}
|
||||
|
||||
void Behavior::OnAssetUnloaded(Asset* asset, void* caller)
|
||||
{
|
||||
}
|
||||
|
||||
#if USE_EDITOR
|
||||
|
||||
bool Behavior::GetNodeDebugRelevancy(const BehaviorTreeNode* node, const Behavior* behavior)
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
/// <summary>
|
||||
/// Behavior instance script that runs Behavior Tree execution.
|
||||
/// </summary>
|
||||
API_CLASS(Attributes="Category(\"Flax Engine\")") class FLAXENGINE_API Behavior : public Script
|
||||
API_CLASS(Attributes="Category(\"Flax Engine\")") class FLAXENGINE_API Behavior : public Script, private IAssetReference
|
||||
{
|
||||
API_AUTO_SERIALIZATION();
|
||||
DECLARE_SCRIPTING_TYPE(Behavior);
|
||||
@@ -92,6 +92,11 @@ public:
|
||||
void OnDisable() override;
|
||||
|
||||
private:
|
||||
// [IAssetReference]
|
||||
void OnAssetChanged(Asset* asset, void* caller) override;
|
||||
void OnAssetLoaded(Asset* asset, void* caller) override;
|
||||
void OnAssetUnloaded(Asset* asset, void* caller) override;
|
||||
|
||||
#if USE_EDITOR
|
||||
// Editor-only utilities to debug nodes state.
|
||||
API_FUNCTION(Internal) static bool GetNodeDebugRelevancy(const BehaviorTreeNode* node, const Behavior* behavior);
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "BehaviorTree.h"
|
||||
#include "BehaviorTreeNodes.h"
|
||||
#include "BehaviorKnowledgeSelector.h"
|
||||
#include "Engine/Profiler/ProfilerMemory.h"
|
||||
#include "Engine/Scripting/Scripting.h"
|
||||
#include "Engine/Scripting/BinaryModule.h"
|
||||
#include "Engine/Scripting/ManagedCLR/MProperty.h"
|
||||
@@ -144,6 +145,7 @@ BehaviorKnowledge::~BehaviorKnowledge()
|
||||
|
||||
void BehaviorKnowledge::InitMemory(BehaviorTree* tree)
|
||||
{
|
||||
PROFILE_MEM(AI);
|
||||
if (Tree)
|
||||
FreeMemory();
|
||||
if (!tree)
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "Engine/Serialization/JsonSerializer.h"
|
||||
#include "Engine/Serialization/MemoryReadStream.h"
|
||||
#include "Engine/Threading/Threading.h"
|
||||
#include "Engine/Profiler/ProfilerMemory.h"
|
||||
#include "FlaxEngine.Gen.h"
|
||||
#if USE_EDITOR
|
||||
#include "Engine/Level/Level.h"
|
||||
@@ -275,6 +276,7 @@ Asset::LoadResult BehaviorTree::load()
|
||||
if (surfaceChunk == nullptr)
|
||||
return LoadResult::MissingDataChunk;
|
||||
MemoryReadStream surfaceStream(surfaceChunk->Get(), surfaceChunk->Size());
|
||||
PROFILE_MEM(AI);
|
||||
if (Graph.Load(&surfaceStream, true))
|
||||
{
|
||||
LOG(Warning, "Failed to load graph \'{0}\'", ToString());
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "AnimEvent.h"
|
||||
#include "Engine/Engine/Engine.h"
|
||||
#include "Engine/Profiler/ProfilerCPU.h"
|
||||
#include "Engine/Profiler/ProfilerMemory.h"
|
||||
#include "Engine/Level/Actors/AnimatedModel.h"
|
||||
#include "Engine/Engine/Time.h"
|
||||
#include "Engine/Engine/EngineService.h"
|
||||
@@ -52,7 +53,7 @@ namespace
|
||||
|
||||
AnimationsService AnimationManagerInstance;
|
||||
TaskGraphSystem* Animations::System = nullptr;
|
||||
ConcurrentSystemLocker Animations::SystemLocker;
|
||||
ReadWriteLock Animations::SystemLocker;
|
||||
#if USE_EDITOR
|
||||
Delegate<Animations::DebugFlowInfo> Animations::DebugFlow;
|
||||
#endif
|
||||
@@ -69,6 +70,7 @@ AnimContinuousEvent::AnimContinuousEvent(const SpawnParams& params)
|
||||
|
||||
bool AnimationsService::Init()
|
||||
{
|
||||
PROFILE_MEM(Animations);
|
||||
Animations::System = New<AnimationsSystem>();
|
||||
Engine::UpdateGraph->AddSystem(Animations::System);
|
||||
return false;
|
||||
@@ -83,6 +85,7 @@ void AnimationsService::Dispose()
|
||||
void AnimationsSystem::Job(int32 index)
|
||||
{
|
||||
PROFILE_CPU_NAMED("Animations.Job");
|
||||
PROFILE_MEM(Animations);
|
||||
auto animatedModel = AnimationManagerInstance.UpdateList[index];
|
||||
if (CanUpdateModel(animatedModel))
|
||||
{
|
||||
@@ -121,7 +124,7 @@ void AnimationsSystem::Execute(TaskGraph* graph)
|
||||
Active = true;
|
||||
|
||||
// Ensure no animation assets can be reloaded/modified during async update
|
||||
Animations::SystemLocker.Begin(false);
|
||||
Animations::SystemLocker.ReadLock();
|
||||
|
||||
// Setup data for async update
|
||||
const auto& tickData = Time::Update;
|
||||
@@ -147,6 +150,7 @@ void AnimationsSystem::PostExecute(TaskGraph* graph)
|
||||
if (!Active)
|
||||
return;
|
||||
PROFILE_CPU_NAMED("Animations.PostExecute");
|
||||
PROFILE_MEM(Animations);
|
||||
|
||||
// Update gameplay
|
||||
for (int32 index = 0; index < AnimationManagerInstance.UpdateList.Count(); index++)
|
||||
@@ -161,16 +165,18 @@ void AnimationsSystem::PostExecute(TaskGraph* graph)
|
||||
|
||||
// Cleanup
|
||||
AnimationManagerInstance.UpdateList.Clear();
|
||||
Animations::SystemLocker.End(false);
|
||||
Animations::SystemLocker.ReadUnlock();
|
||||
Active = false;
|
||||
}
|
||||
|
||||
void Animations::AddToUpdate(AnimatedModel* obj)
|
||||
{
|
||||
ScopeWriteLock lock(SystemLocker);
|
||||
AnimationManagerInstance.UpdateList.Add(obj);
|
||||
}
|
||||
|
||||
void Animations::RemoveFromUpdate(AnimatedModel* obj)
|
||||
{
|
||||
ScopeWriteLock lock(SystemLocker);
|
||||
AnimationManagerInstance.UpdateList.Remove(obj);
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
|
||||
#include "Engine/Scripting/ScriptingType.h"
|
||||
#include "Engine/Core/Delegate.h"
|
||||
#include "Engine/Threading/ConcurrentSystemLocker.h"
|
||||
|
||||
class TaskGraphSystem;
|
||||
class AnimatedModel;
|
||||
@@ -23,7 +22,7 @@ API_CLASS(Static) class FLAXENGINE_API Animations
|
||||
API_FIELD(ReadOnly) static TaskGraphSystem* System;
|
||||
|
||||
// Data access locker for animations data.
|
||||
static ConcurrentSystemLocker SystemLocker;
|
||||
static ReadWriteLock SystemLocker;
|
||||
|
||||
#if USE_EDITOR
|
||||
// Data wrapper for the debug flow information.
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "Engine/Content/Assets/SkinnedModel.h"
|
||||
#include "Engine/Graphics/Models/SkeletonData.h"
|
||||
#include "Engine/Scripting/Scripting.h"
|
||||
#include "Engine/Threading/Threading.h"
|
||||
|
||||
extern void RetargetSkeletonPose(const SkeletonData& sourceSkeleton, const SkeletonData& targetSkeleton, const SkinnedModel::SkeletonMapping& mapping, const Transform* sourceNodes, Transform* targetNodes);
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "Engine/Content/Content.h"
|
||||
#include "Engine/Content/Deprecated.h"
|
||||
#include "Engine/Serialization/MemoryReadStream.h"
|
||||
#include "Engine/Profiler/ProfilerMemory.h"
|
||||
#include "Engine/Audio/AudioClip.h"
|
||||
#include "Engine/Graphics/PostProcessSettings.h"
|
||||
#if USE_EDITOR
|
||||
@@ -249,6 +250,7 @@ bool SceneAnimation::Save(const StringView& path)
|
||||
Asset::LoadResult SceneAnimation::load()
|
||||
{
|
||||
TrackStatesCount = 0;
|
||||
PROFILE_MEM(AnimationsData);
|
||||
|
||||
// Get the data chunk
|
||||
if (LoadChunk(0))
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "Engine/Audio/AudioSource.h"
|
||||
#include "Engine/Graphics/RenderTask.h"
|
||||
#include "Engine/Renderer/RenderList.h"
|
||||
#include "Engine/Profiler/ProfilerMemory.h"
|
||||
#include "Engine/Scripting/Scripting.h"
|
||||
#include "Engine/Scripting/Script.h"
|
||||
#include "Engine/Scripting/ManagedCLR/MException.h"
|
||||
@@ -151,6 +152,7 @@ void SceneAnimationPlayer::Tick(float dt)
|
||||
SceneAnimation* anim = Animation.Get();
|
||||
if (!anim || !anim->IsLoaded())
|
||||
return;
|
||||
PROFILE_MEM(Animations);
|
||||
|
||||
// Setup state
|
||||
if (_tracks.Count() != anim->TrackStatesCount)
|
||||
@@ -229,6 +231,7 @@ void SceneAnimationPlayer::MapTrack(const StringView& from, const Guid& to)
|
||||
SceneAnimation* anim = Animation.Get();
|
||||
if (!anim || !anim->IsLoaded())
|
||||
return;
|
||||
PROFILE_MEM(Animations);
|
||||
for (int32 j = 0; j < anim->Tracks.Count(); j++)
|
||||
{
|
||||
const auto& track = anim->Tracks[j];
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "Engine/Scripting/BinaryModule.h"
|
||||
#include "Engine/Level/Level.h"
|
||||
#include "Engine/Profiler/ProfilerCPU.h"
|
||||
#include "Engine/Profiler/ProfilerMemory.h"
|
||||
#include "Engine/Engine/Engine.h"
|
||||
#include "Engine/Engine/CommandLine.h"
|
||||
#include "Engine/Core/Log.h"
|
||||
@@ -151,6 +152,7 @@ void Audio::SetEnableHRTF(bool value)
|
||||
bool AudioService::Init()
|
||||
{
|
||||
PROFILE_CPU_NAMED("Audio.Init");
|
||||
PROFILE_MEM(Audio);
|
||||
const auto settings = AudioSettings::Get();
|
||||
const bool mute = CommandLine::Options.Mute.IsTrue() || settings->DisableAudio;
|
||||
|
||||
@@ -211,6 +213,7 @@ bool AudioService::Init()
|
||||
void AudioService::Update()
|
||||
{
|
||||
PROFILE_CPU_NAMED("Audio.Update");
|
||||
PROFILE_MEM(Audio);
|
||||
|
||||
// Update the master volume
|
||||
float masterVolume = MasterVolume;
|
||||
|
||||
@@ -7,50 +7,67 @@
|
||||
#include "Engine/Core/Log.h"
|
||||
#include "Engine/Content/Upgraders/AudioClipUpgrader.h"
|
||||
#include "Engine/Content/Factories/BinaryAssetFactory.h"
|
||||
#include "Engine/Profiler/ProfilerCPU.h"
|
||||
#include "Engine/Scripting/ManagedCLR/MUtils.h"
|
||||
#include "Engine/Streaming/StreamingGroup.h"
|
||||
#include "Engine/Serialization/MemoryReadStream.h"
|
||||
#include "Engine/Profiler/ProfilerMemory.h"
|
||||
#include "Engine/Tools/AudioTool/OggVorbisDecoder.h"
|
||||
#include "Engine/Tools/AudioTool/AudioTool.h"
|
||||
#include "Engine/Threading/Threading.h"
|
||||
|
||||
REGISTER_BINARY_ASSET_WITH_UPGRADER(AudioClip, "FlaxEngine.AudioClip", AudioClipUpgrader, false);
|
||||
|
||||
AudioClip::StreamingTask::StreamingTask(AudioClip* asset)
|
||||
: _asset(asset)
|
||||
, _dataLock(asset->Storage->Lock())
|
||||
{
|
||||
}
|
||||
|
||||
bool AudioClip::StreamingTask::HasReference(Object* resource) const
|
||||
{
|
||||
return _asset == resource;
|
||||
}
|
||||
|
||||
bool AudioClip::StreamingTask::Run()
|
||||
{
|
||||
AssetReference<AudioClip> ref = _asset.Get();
|
||||
if (ref == nullptr || AudioBackend::Instance == nullptr)
|
||||
PROFILE_CPU_NAMED("AudioStreaming");
|
||||
PROFILE_MEM(Audio);
|
||||
AssetReference<AudioClip> clip = _asset.Get();
|
||||
if (clip == nullptr || AudioBackend::Instance == nullptr)
|
||||
return true;
|
||||
ScopeLock lock(ref->Locker);
|
||||
const auto& queue = ref->StreamingQueue;
|
||||
if (queue.Count() == 0)
|
||||
return false;
|
||||
auto clip = ref.Get();
|
||||
#if TRACY_ENABLE
|
||||
const StringView name(clip->GetPath());
|
||||
ZoneName(*name, name.Length());
|
||||
#endif
|
||||
|
||||
// Update the buffers
|
||||
// Process the loading queue (hold the asset lock)
|
||||
clip->Locker.Lock();
|
||||
const auto& queue = clip->StreamingQueue;
|
||||
Array<int32, FixedAllocation<ASSET_FILE_DATA_CHUNKS>> loadQueue;
|
||||
for (int32 i = 0; i < queue.Count(); i++)
|
||||
{
|
||||
const auto idx = queue[i];
|
||||
const int32 idx = queue[i];
|
||||
uint32& bufferID = clip->Buffers[idx];
|
||||
if (bufferID == 0)
|
||||
{
|
||||
bufferID = AudioBackend::Buffer::Create();
|
||||
// Load buffers outside the asset lock to prevent lock contention
|
||||
loadQueue.Add(idx);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Release unused data
|
||||
// Release unused buffer
|
||||
AudioBackend::Buffer::Delete(bufferID);
|
||||
bufferID = 0;
|
||||
}
|
||||
}
|
||||
clip->Locker.Unlock();
|
||||
|
||||
// Load missing buffers data (from asset chunks)
|
||||
for (int32 i = 0; i < queue.Count(); i++)
|
||||
for (int32 i = 0; i < loadQueue.Count(); i++)
|
||||
{
|
||||
if (clip->WriteBuffer(queue[i]))
|
||||
{
|
||||
if (clip->WriteBuffer(loadQueue[i]))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Update the sources
|
||||
@@ -318,6 +335,7 @@ bool AudioClip::init(AssetInitData& initData)
|
||||
|
||||
Asset::LoadResult AudioClip::load()
|
||||
{
|
||||
PROFILE_MEM(Audio);
|
||||
#if !COMPILE_WITH_OGG_VORBIS
|
||||
if (AudioHeader.Format == AudioFormat::Vorbis)
|
||||
{
|
||||
@@ -410,14 +428,11 @@ void AudioClip::unload(bool isReloading)
|
||||
|
||||
bool AudioClip::WriteBuffer(int32 chunkIndex)
|
||||
{
|
||||
// Ignore if buffer is not created
|
||||
const uint32 bufferID = Buffers[chunkIndex];
|
||||
if (bufferID == 0)
|
||||
return false;
|
||||
|
||||
// Ensure audio backend exists
|
||||
if (AudioBackend::Instance == nullptr)
|
||||
return true;
|
||||
PROFILE_CPU();
|
||||
PROFILE_MEM(Audio);
|
||||
|
||||
const auto chunk = GetChunk(chunkIndex);
|
||||
if (chunk == nullptr || chunk->IsMissing())
|
||||
@@ -429,6 +444,7 @@ bool AudioClip::WriteBuffer(int32 chunkIndex)
|
||||
Array<byte> tmp1, tmp2;
|
||||
AudioDataInfo info = AudioHeader.Info;
|
||||
const uint32 bytesPerSample = info.BitDepth / 8;
|
||||
ZoneValue(chunk->Size() / 1024); // Audio data size (in kB)
|
||||
|
||||
// Get raw data or decompress it
|
||||
switch (Format())
|
||||
@@ -436,6 +452,7 @@ bool AudioClip::WriteBuffer(int32 chunkIndex)
|
||||
case AudioFormat::Vorbis:
|
||||
{
|
||||
#if COMPILE_WITH_OGG_VORBIS
|
||||
PROFILE_CPU_NAMED("OggVorbisDecode");
|
||||
OggVorbisDecoder decoder;
|
||||
MemoryReadStream stream(chunk->Get(), chunk->Size());
|
||||
AudioDataInfo tmpInfo;
|
||||
@@ -472,7 +489,13 @@ bool AudioClip::WriteBuffer(int32 chunkIndex)
|
||||
data = Span<byte>(tmp2.Get(), tmp2.Count());
|
||||
}
|
||||
|
||||
// Write samples to the audio buffer
|
||||
// Write samples to the audio buffer (create one if missing)
|
||||
Locker.Lock(); // StreamingTask loads buffers without lock so do it here
|
||||
uint32& bufferID = Buffers[chunkIndex];
|
||||
if (bufferID == 0)
|
||||
bufferID = AudioBackend::Buffer::Create();
|
||||
AudioBackend::Buffer::Write(bufferID, data.Get(), info);
|
||||
Locker.Unlock();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -44,22 +44,11 @@ public:
|
||||
FlaxStorage::LockData _dataLock;
|
||||
|
||||
public:
|
||||
/// <summary>
|
||||
/// Init
|
||||
/// </summary>
|
||||
/// <param name="asset">Parent asset</param>
|
||||
StreamingTask(AudioClip* asset)
|
||||
: _asset(asset)
|
||||
, _dataLock(asset->Storage->Lock())
|
||||
{
|
||||
}
|
||||
StreamingTask(AudioClip* asset);
|
||||
|
||||
public:
|
||||
// [ThreadPoolTask]
|
||||
bool HasReference(Object* resource) const override
|
||||
{
|
||||
return _asset == resource;
|
||||
}
|
||||
bool HasReference(Object* resource) const override;
|
||||
|
||||
protected:
|
||||
// [ThreadPoolTask]
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "Engine/Engine/Time.h"
|
||||
#include "Engine/Level/Scene/Scene.h"
|
||||
#include "Engine/Profiler/ProfilerCPU.h"
|
||||
#include "Engine/Profiler/ProfilerMemory.h"
|
||||
#include "AudioBackend.h"
|
||||
#include "Audio.h"
|
||||
|
||||
@@ -21,9 +22,8 @@ AudioSource::AudioSource(const SpawnParams& params)
|
||||
, _playOnStart(false)
|
||||
, _startTime(0.0f)
|
||||
, _allowSpatialization(true)
|
||||
, Clip(this)
|
||||
{
|
||||
Clip.Changed.Bind<AudioSource, &AudioSource::OnClipChanged>(this);
|
||||
Clip.Loaded.Bind<AudioSource, &AudioSource::OnClipLoaded>(this);
|
||||
}
|
||||
|
||||
void AudioSource::SetVolume(float value)
|
||||
@@ -121,6 +121,7 @@ void AudioSource::Play()
|
||||
auto state = _state;
|
||||
if (state == States::Playing)
|
||||
return;
|
||||
PROFILE_CPU();
|
||||
if (Clip == nullptr || Clip->WaitForLoaded())
|
||||
{
|
||||
LOG(Warning, "Cannot play audio source without a clip ({0})", GetNamePath());
|
||||
@@ -189,6 +190,7 @@ void AudioSource::Stop()
|
||||
{
|
||||
if (_state == States::Stopped)
|
||||
return;
|
||||
PROFILE_CPU();
|
||||
|
||||
_state = States::Stopped;
|
||||
_isActuallyPlayingSth = false;
|
||||
@@ -264,7 +266,7 @@ void AudioSource::RequestStreamingBuffersUpdate()
|
||||
_needToUpdateStreamingBuffers = true;
|
||||
}
|
||||
|
||||
void AudioSource::OnClipChanged()
|
||||
void AudioSource::OnAssetChanged(Asset* asset, void* caller)
|
||||
{
|
||||
Stop();
|
||||
|
||||
@@ -276,7 +278,7 @@ void AudioSource::OnClipChanged()
|
||||
}
|
||||
}
|
||||
|
||||
void AudioSource::OnClipLoaded()
|
||||
void AudioSource::OnAssetLoaded(Asset* asset, void* caller)
|
||||
{
|
||||
if (!SourceID)
|
||||
return;
|
||||
@@ -302,6 +304,10 @@ void AudioSource::OnClipLoaded()
|
||||
}
|
||||
}
|
||||
|
||||
void AudioSource::OnAssetUnloaded(Asset* asset, void* caller)
|
||||
{
|
||||
}
|
||||
|
||||
bool AudioSource::UseStreaming() const
|
||||
{
|
||||
if (Clip == nullptr || Clip->WaitForLoaded())
|
||||
@@ -383,6 +389,7 @@ bool AudioSource::IntersectsItself(const Ray& ray, Real& distance, Vector3& norm
|
||||
void AudioSource::Update()
|
||||
{
|
||||
PROFILE_CPU();
|
||||
PROFILE_MEM(Audio);
|
||||
|
||||
// Update the velocity
|
||||
const Vector3 pos = GetPosition();
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user