Merge branch 'master' of https://github.com/Menotdan/FlaxEngine into material_import

Merge Upstream Changes.
This commit is contained in:
Menotdan
2023-09-25 23:51:34 -04:00
130 changed files with 2757 additions and 1736 deletions

View File

@@ -205,8 +205,6 @@ void MaterialInstance::Bind(BindParameters& params)
Asset::LoadResult MaterialInstance::load()
{
ASSERT(_baseMaterial == nullptr);
// Get main chunk
auto chunk0 = GetChunk(0);
if (chunk0 == nullptr || chunk0->IsMissing())
@@ -229,6 +227,7 @@ Asset::LoadResult MaterialInstance::load()
else
{
// Clear parameters if has no material loaded
_baseMaterial = nullptr;
Params.Dispose();
ParamsChanged();
}

View File

@@ -32,14 +32,21 @@ CreateAssetResult ImportShader::Import(CreateAssetContext& context)
LOG(Warning, "Empty shader source file.");
return CreateAssetResult::Error;
}
// Ensure the source code has an empty line at the end (expected by glslang)
auto sourceCodeChunkSize = sourceCodeSize + 1;
if (sourceCodeText[sourceCodeSize - 1] != '\n')
sourceCodeChunkSize++;
const auto& sourceCodeChunk = context.Data.Header.Chunks[SourceCodeChunk];
sourceCodeChunk->Data.Allocate(sourceCodeSize + 1);
sourceCodeChunk->Data.Allocate(sourceCodeChunkSize);
const auto sourceCode = sourceCodeChunk->Get();
Platform::MemoryCopy(sourceCode, sourceCodeText.Get(), sourceCodeSize);
sourceCode[sourceCodeChunkSize - 2] = '\n';
// Encrypt source code
Encryption::EncryptBytes(sourceCode, sourceCodeSize);
sourceCode[sourceCodeSize] = 0;
Encryption::EncryptBytes(sourceCode, sourceCodeChunkSize - 1);
sourceCode[sourceCodeChunkSize - 1] = 0;
// Set Custom Data with Header
ShaderStorage::Header20 shaderHeader;

View File

@@ -223,10 +223,10 @@ void Log::Logger::ProcessLogMessage(LogType type, const StringView& msg, fmt_fla
else
{
//w.append(msg.Get(), msg.Get() + msg.Length());
fmt_flax::format(w, TEXT("{}"), (const Char*)msg.Get());
fmt_flax::format(w, TEXT("{}"), msg);
}
#else
fmt_flax::format(w, TEXT("{}"), (const Char*)msg.Get());
fmt_flax::format(w, TEXT("{}"), msg);
#endif
}

View File

@@ -72,7 +72,7 @@ void String::Set(const char* chars, int32 length)
}
_length = length;
}
if (chars)
if (chars && length)
StringUtils::ConvertANSI2UTF16(chars, _data, length, _length);
}
@@ -298,8 +298,10 @@ String String::TrimTrailing() const
end--;
}
ASSERT_LOW_LAYER(end >= start);
return Substring(start, end - start + 1);
const int32 count = end - start + 1;
if (start >= 0 && start + count <= Length() && count >= 0)
return String(_data + start, count);
return Empty;
}
String& String::operator/=(const Char* str)

View File

@@ -32,6 +32,7 @@ namespace FlaxEngine.Interop
public static class NativeToManaged
{
public static object ConvertToManaged(IntPtr unmanaged) => unmanaged == IntPtr.Zero ? null : ManagedHandle.FromIntPtr(unmanaged).Target;
public static IntPtr ConvertToUnmanaged(object managed) => managed != null ? ManagedHandle.ToIntPtr(managed, GCHandleType.Weak) : IntPtr.Zero;
public static void Free(IntPtr unmanaged)
{
@@ -44,6 +45,7 @@ namespace FlaxEngine.Interop
#endif
public static class ManagedToNative
{
public static object ConvertToManaged(IntPtr unmanaged) => unmanaged == IntPtr.Zero ? null : ManagedHandle.FromIntPtr(unmanaged).Target;
public static IntPtr ConvertToUnmanaged(object managed) => managed != null ? ManagedHandle.ToIntPtr(managed, GCHandleType.Weak) : IntPtr.Zero;
public static void Free(IntPtr unmanaged)
@@ -147,29 +149,16 @@ namespace FlaxEngine.Interop
#if FLAX_EDITOR
[HideInEditor]
#endif
[CustomMarshaller(typeof(FlaxEngine.Object), MarshalMode.ManagedToUnmanagedIn, typeof(ObjectMarshaller.ManagedToNative))]
[CustomMarshaller(typeof(FlaxEngine.Object), MarshalMode.UnmanagedToManagedOut, typeof(ObjectMarshaller.ManagedToNative))]
[CustomMarshaller(typeof(FlaxEngine.Object), MarshalMode.ElementIn, typeof(ObjectMarshaller.ManagedToNative))]
[CustomMarshaller(typeof(FlaxEngine.Object), MarshalMode.ManagedToUnmanagedOut, typeof(ObjectMarshaller.NativeToManaged))]
[CustomMarshaller(typeof(FlaxEngine.Object), MarshalMode.UnmanagedToManagedIn, typeof(ObjectMarshaller.NativeToManaged))]
[CustomMarshaller(typeof(FlaxEngine.Object), MarshalMode.ElementOut, typeof(ObjectMarshaller.NativeToManaged))]
[CustomMarshaller(typeof(FlaxEngine.Object), MarshalMode.ManagedToUnmanagedIn, typeof(ObjectMarshaller))]
[CustomMarshaller(typeof(FlaxEngine.Object), MarshalMode.UnmanagedToManagedOut, typeof(ObjectMarshaller))]
[CustomMarshaller(typeof(FlaxEngine.Object), MarshalMode.ElementIn, typeof(ObjectMarshaller))]
[CustomMarshaller(typeof(FlaxEngine.Object), MarshalMode.ManagedToUnmanagedOut, typeof(ObjectMarshaller))]
[CustomMarshaller(typeof(FlaxEngine.Object), MarshalMode.UnmanagedToManagedIn, typeof(ObjectMarshaller))]
[CustomMarshaller(typeof(FlaxEngine.Object), MarshalMode.ElementOut, typeof(ObjectMarshaller))]
public static class ObjectMarshaller
{
#if FLAX_EDITOR
[HideInEditor]
#endif
public static class NativeToManaged
{
public static FlaxEngine.Object ConvertToManaged(IntPtr unmanaged) => unmanaged != IntPtr.Zero ? Unsafe.As<FlaxEngine.Object>(ManagedHandle.FromIntPtr(unmanaged).Target) : null;
}
#if FLAX_EDITOR
[HideInEditor]
#endif
public static class ManagedToNative
{
public static IntPtr ConvertToUnmanaged(FlaxEngine.Object managed) => Unsafe.As<object>(managed) != null ? ManagedHandle.ToIntPtr(managed) : IntPtr.Zero;
}
public static FlaxEngine.Object ConvertToManaged(IntPtr unmanaged) => unmanaged != IntPtr.Zero ? Unsafe.As<FlaxEngine.Object>(ManagedHandle.FromIntPtr(unmanaged).Target) : null;
public static IntPtr ConvertToUnmanaged(FlaxEngine.Object managed) => Unsafe.As<object>(managed) != null ? ManagedHandle.ToIntPtr(managed) : IntPtr.Zero;
}
#if FLAX_EDITOR
@@ -342,6 +331,7 @@ namespace FlaxEngine.Interop
public static class NativeToManaged
{
public static Dictionary<T, U> ConvertToManaged(IntPtr unmanaged) => DictionaryMarshaller<T, U>.ToManaged(unmanaged);
public static IntPtr ConvertToUnmanaged(Dictionary<T, U> managed) => DictionaryMarshaller<T, U>.ToNative(managed, GCHandleType.Weak);
public static void Free(IntPtr unmanaged) => DictionaryMarshaller<T, U>.Free(unmanaged);
}
@@ -350,8 +340,8 @@ namespace FlaxEngine.Interop
#endif
public static class ManagedToNative
{
public static Dictionary<T, U> ConvertToManaged(IntPtr unmanaged) => DictionaryMarshaller<T, U>.ToManaged(unmanaged);
public static IntPtr ConvertToUnmanaged(Dictionary<T, U> managed) => DictionaryMarshaller<T, U>.ToNative(managed, GCHandleType.Weak);
public static void Free(IntPtr unmanaged)
{
//DictionaryMarshaller<T, U>.Free(unmanaged); // No need to free weak handles
@@ -425,6 +415,28 @@ namespace FlaxEngine.Interop
return new T[numElements];
}
public static TUnmanagedElement* AllocateContainerForUnmanagedElements(T[] managed, out int numElements)
{
if (managed is null)
{
numElements = 0;
return null;
}
numElements = managed.Length;
(ManagedHandle managedArrayHandle, _) = ManagedArray.AllocatePooledArray<TUnmanagedElement>(managed.Length);
return (TUnmanagedElement*)ManagedHandle.ToIntPtr(managedArrayHandle);
}
public static ReadOnlySpan<T> GetManagedValuesSource(T[] managed) => managed;
public static Span<TUnmanagedElement> GetUnmanagedValuesDestination(TUnmanagedElement* unmanaged)
{
if (unmanaged == null)
return Span<TUnmanagedElement>.Empty;
ManagedArray managedArray = Unsafe.As<ManagedArray>(ManagedHandle.FromIntPtr(new IntPtr(unmanaged)).Target);
return managedArray.ToSpan<TUnmanagedElement>();
}
public static Span<T> GetManagedValuesDestination(T[] managed) => managed;
public static ReadOnlySpan<TUnmanagedElement> GetUnmanagedValuesSource(TUnmanagedElement* unmanaged, int numElements)
@@ -591,6 +603,7 @@ namespace FlaxEngine.Interop
public static class NativeToManaged
{
public static string ConvertToManaged(IntPtr unmanaged) => ManagedString.ToManaged(unmanaged);
public static unsafe IntPtr ConvertToUnmanaged(string managed) => managed == null ? IntPtr.Zero : ManagedHandle.ToIntPtr(managed, GCHandleType.Weak);
public static void Free(IntPtr unmanaged) => ManagedString.Free(unmanaged);
}
@@ -599,11 +612,8 @@ namespace FlaxEngine.Interop
#endif
public static class ManagedToNative
{
public static unsafe IntPtr ConvertToUnmanaged(string managed)
{
return managed == null ? IntPtr.Zero : ManagedHandle.ToIntPtr(managed, GCHandleType.Weak);
}
public static string ConvertToManaged(IntPtr unmanaged) => ManagedString.ToManaged(unmanaged);
public static unsafe IntPtr ConvertToUnmanaged(string managed) => managed == null ? IntPtr.Zero : ManagedHandle.ToIntPtr(managed, GCHandleType.Weak);
public static void Free(IntPtr unmanaged)
{
//ManagedString.Free(unmanaged); // No need to free weak handles

View File

@@ -184,7 +184,7 @@ namespace FlaxEngine.Interop
{
string moduleName = Marshal.PtrToStringAnsi(moduleNamePtr);
string modulePath = Marshal.PtrToStringAnsi(modulePathPtr);
nativeLibraryPaths[moduleName] = modulePath;
libraryPaths[moduleName] = modulePath;
}
[UnmanagedCallersOnly]
@@ -297,7 +297,7 @@ namespace FlaxEngine.Interop
internal static void GetClassFields(ManagedHandle typeHandle, NativeFieldDefinitions** classFields, int* classFieldsCount)
{
Type type = Unsafe.As<Type>(typeHandle.Target);
var fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
var fields = type.GetFields(BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
NativeFieldDefinitions* arr = (NativeFieldDefinitions*)NativeAlloc(fields.Length, Unsafe.SizeOf<NativeFieldDefinitions>());
for (int i = 0; i < fields.Length; i++)
@@ -331,7 +331,7 @@ namespace FlaxEngine.Interop
internal static void GetClassProperties(ManagedHandle typeHandle, NativePropertyDefinitions** classProperties, int* classPropertiesCount)
{
Type type = Unsafe.As<Type>(typeHandle.Target);
var properties = type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
var properties = type.GetProperties(BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
var arr = (NativePropertyDefinitions*)NativeAlloc(properties.Length, Unsafe.SizeOf<NativePropertyDefinitions>());
for (int i = 0; i < properties.Length; i++)
@@ -559,6 +559,19 @@ namespace FlaxEngine.Interop
return managedArray.Pointer;
}
[UnmanagedCallersOnly]
internal static IntPtr GetArray(ManagedHandle handle)
{
if (!handle.IsAllocated)
return IntPtr.Zero;
object value = handle.Target;
if (value is ManagedArray)
return (IntPtr)handle;
if (value is Array)
return Invoker.MarshalReturnValueGeneric(value.GetType(), value);
return IntPtr.Zero;
}
[UnmanagedCallersOnly]
internal static int GetArrayLength(ManagedHandle arrayHandle)
{
@@ -804,8 +817,8 @@ namespace FlaxEngine.Interop
[UnmanagedCallersOnly]
internal static IntPtr FieldGetValueBoxed(ManagedHandle fieldOwnerHandle, ManagedHandle fieldHandle)
{
object fieldOwner = fieldOwnerHandle.Target;
FieldHolder field = Unsafe.As<FieldHolder>(fieldHandle.Target);
object fieldOwner = field.field.IsStatic ? null : fieldOwnerHandle.Target;
object fieldValue = field.field.GetValue(fieldOwner);
return Invoker.MarshalReturnValueGeneric(field.field.FieldType, fieldValue);
}
@@ -838,39 +851,46 @@ namespace FlaxEngine.Interop
*assemblyFullName = NativeAllocStringAnsi(flaxEngineAssembly.FullName);
return GetAssemblyHandle(flaxEngineAssembly);
}
try
{
string assemblyPath = Marshal.PtrToStringUni(assemblyPathPtr);
string assemblyPath = Marshal.PtrToStringAnsi(assemblyPathPtr);
Assembly assembly;
Assembly assembly;
#if FLAX_EDITOR
// Load assembly from loaded bytes to prevent file locking in Editor
var assemblyBytes = File.ReadAllBytes(assemblyPath);
using MemoryStream stream = new MemoryStream(assemblyBytes);
var pdbPath = Path.ChangeExtension(assemblyPath, "pdb");
if (File.Exists(pdbPath))
{
// Load including debug symbols
using FileStream pdbStream = new FileStream(Path.ChangeExtension(assemblyPath, "pdb"), FileMode.Open);
assembly = scriptingAssemblyLoadContext.LoadFromStream(stream, pdbStream);
}
else
{
assembly = scriptingAssemblyLoadContext.LoadFromStream(stream);
}
// Load assembly from loaded bytes to prevent file locking in Editor
var assemblyBytes = File.ReadAllBytes(assemblyPath);
using MemoryStream stream = new MemoryStream(assemblyBytes);
var pdbPath = Path.ChangeExtension(assemblyPath, "pdb");
if (File.Exists(pdbPath))
{
// Load including debug symbols
using FileStream pdbStream = new FileStream(Path.ChangeExtension(assemblyPath, "pdb"), FileMode.Open);
assembly = scriptingAssemblyLoadContext.LoadFromStream(stream, pdbStream);
}
else
{
assembly = scriptingAssemblyLoadContext.LoadFromStream(stream);
}
#else
// Load assembly from file
assembly = scriptingAssemblyLoadContext.LoadFromAssemblyPath(assemblyPath);
// Load assembly from file
assembly = scriptingAssemblyLoadContext.LoadFromAssemblyPath(assemblyPath);
#endif
if (assembly == null)
return new ManagedHandle();
NativeLibrary.SetDllImportResolver(assembly, NativeLibraryImportResolver);
if (assembly == null)
return new ManagedHandle();
NativeLibrary.SetDllImportResolver(assembly, NativeLibraryImportResolver);
// Assemblies loaded via streams have no Location: https://github.com/dotnet/runtime/issues/12822
AssemblyLocations.Add(assembly.FullName, assemblyPath);
// Assemblies loaded via streams have no Location: https://github.com/dotnet/runtime/issues/12822
AssemblyLocations.Add(assembly.FullName, assemblyPath);
*assemblyName = NativeAllocStringAnsi(assembly.GetName().Name);
*assemblyFullName = NativeAllocStringAnsi(assembly.FullName);
return GetAssemblyHandle(assembly);
*assemblyName = NativeAllocStringAnsi(assembly.GetName().Name);
*assemblyFullName = NativeAllocStringAnsi(assembly.FullName);
return GetAssemblyHandle(assembly);
}
catch (Exception ex)
{
Debug.LogException(ex);
}
return new ManagedHandle();
}
[UnmanagedCallersOnly]
@@ -909,7 +929,7 @@ namespace FlaxEngine.Interop
loadedNativeLibraries.Remove(nativeLibraryName);
}
if (nativeLibraryName != null)
nativeLibraryPaths.Remove(nativeLibraryName);
libraryPaths.Remove(nativeLibraryName);
}
[UnmanagedCallersOnly]

View File

@@ -24,7 +24,8 @@ namespace FlaxEngine.Interop
/// <summary>
/// Provides a Mono-like API for native code to access managed runtime.
/// </summary>
internal static unsafe partial class NativeInterop
[HideInEditor]
public static unsafe partial class NativeInterop
{
internal static Dictionary<string, string> AssemblyLocations = new();
@@ -50,7 +51,7 @@ namespace FlaxEngine.Interop
private static Dictionary<Type, int> _typeSizeCache = new();
private static Dictionary<string, IntPtr> loadedNativeLibraries = new();
internal static Dictionary<string, string> nativeLibraryPaths = new();
internal static Dictionary<string, string> libraryPaths = new();
private static Dictionary<Assembly, string> assemblyOwnedNativeLibraries = new();
internal static AssemblyLoadContext scriptingAssemblyLoadContext;
@@ -59,7 +60,7 @@ namespace FlaxEngine.Interop
{
if (!loadedNativeLibraries.TryGetValue(libraryName, out IntPtr nativeLibrary))
{
if (!nativeLibraryPaths.TryGetValue(libraryName, out var nativeLibraryPath))
if (!libraryPaths.TryGetValue(libraryName, out var nativeLibraryPath))
nativeLibraryPath = libraryName;
nativeLibrary = NativeLibrary.Load(nativeLibraryPath, assembly, dllImportSearchPath);
@@ -101,9 +102,9 @@ namespace FlaxEngine.Interop
private static Assembly OnScriptingAssemblyLoadContextResolving(AssemblyLoadContext assemblyLoadContext, AssemblyName assemblyName)
{
// FIXME: There should be a better way to resolve the path to EditorTargetPath where the dependencies are stored
foreach (string nativeLibraryPath in nativeLibraryPaths.Values)
foreach (string libraryPath in libraryPaths.Values)
{
string editorTargetPath = Path.GetDirectoryName(nativeLibraryPath);
string editorTargetPath = Path.GetDirectoryName(libraryPath);
var assemblyPath = Path.Combine(editorTargetPath, assemblyName.Name + ".dll");
if (File.Exists(assemblyPath))
@@ -147,7 +148,27 @@ namespace FlaxEngine.Interop
NativeMemory.AlignedFree(ptr);
}
internal static T[] GCHandleArrayToManagedArray<T>(ManagedArray ptrArray) where T : class
/// <summary>
/// Converts a delegate into a function pointer that is callable from unmanaged code via <see cref="Marshal.GetFunctionPointerForDelegate{TDelegate}"/> but cached <paramref name="d"/> delegate to prevent collecting it by GC.
/// </summary>
/// <typeparam name="TDelegate">The type of delegate to convert.</typeparam>
/// <param name="d">The delegate to be passed to unmanaged code.</param>
/// <returns>A value that can be passed to unmanaged code, which, in turn, can use it to call the underlying managed delegate.</returns>
public static IntPtr GetFunctionPointerForDelegate<TDelegate>(TDelegate d) where TDelegate : notnull
{
// Example use-case: C# script runs actions via JobSystem.Dispatch which causes crash due to GC collecting Delegate object
ManagedHandle.Alloc(d, GCHandleType.Weak);
return Marshal.GetFunctionPointerForDelegate<TDelegate>(d);
}
/// <summary>
/// Converts array of GC Handles from native runtime to managed array.
/// </summary>
/// <typeparam name="T">Array element type.</typeparam>
/// <param name="ptrArray">Input array.</param>
/// <returns>Output array.</returns>
public static T[] GCHandleArrayToManagedArray<T>(ManagedArray ptrArray) where T : class
{
Span<IntPtr> span = ptrArray.ToSpan<IntPtr>();
T[] managedArray = new T[ptrArray.Length];
@@ -156,7 +177,12 @@ namespace FlaxEngine.Interop
return managedArray;
}
internal static IntPtr[] ManagedArrayToGCHandleArray(Array array)
/// <summary>
/// Converts managed array wrapper into array of GC Handles for native runtime.
/// </summary>
/// <param name="array">Input array.</param>
/// <returns>Output array.</returns>
public static IntPtr[] ManagedArrayToGCHandleArray(Array array)
{
if (array.Length == 0)
return Array.Empty<IntPtr>();
@@ -170,13 +196,26 @@ namespace FlaxEngine.Interop
return pointerArray;
}
internal static ManagedArray ManagedArrayToGCHandleWrappedArray(Array array)
/// <summary>
/// Converts managed array wrapper into array of GC Handles for native runtime.
/// </summary>
/// <param name="array">Input array.</param>
/// <returns>Output array.</returns>
public static ManagedArray ManagedArrayToGCHandleWrappedArray(Array array)
{
IntPtr[] pointerArray = ManagedArrayToGCHandleArray(array);
return ManagedArray.WrapNewArray(pointerArray, array.GetType());
}
internal static TDst[] ConvertArray<TSrc, TDst>(Span<TSrc> src, Func<TSrc, TDst> convertFunc)
/// <summary>
/// Converts array with a custom converter function for each element.
/// </summary>
/// <typeparam name="TSrc">Input data type.</typeparam>
/// <typeparam name="TDst">Output data type.</typeparam>
/// <param name="src">The input array.</param>
/// <param name="convertFunc">Converter callback.</param>
/// <returns>The output array.</returns>
public static TDst[] ConvertArray<TSrc, TDst>(Span<TSrc> src, Func<TSrc, TDst> convertFunc)
{
TDst[] dst = new TDst[src.Length];
for (int i = 0; i < src.Length; i++)
@@ -184,7 +223,15 @@ namespace FlaxEngine.Interop
return dst;
}
internal static TDst[] ConvertArray<TSrc, TDst>(TSrc[] src, Func<TSrc, TDst> convertFunc)
/// <summary>
/// Converts array with a custom converter function for each element.
/// </summary>
/// <typeparam name="TSrc">Input data type.</typeparam>
/// <typeparam name="TDst">Output data type.</typeparam>
/// <param name="src">The input array.</param>
/// <param name="convertFunc">Converter callback.</param>
/// <returns>The output array.</returns>
public static TDst[] ConvertArray<TSrc, TDst>(TSrc[] src, Func<TSrc, TDst> convertFunc)
{
TDst[] dst = new TDst[src.Length];
for (int i = 0; i < src.Length; i++)
@@ -1024,11 +1071,12 @@ namespace FlaxEngine.Interop
private static uint pinnedBoxedValuesPointer = 0;
private static (IntPtr ptr, int size)[] pinnedAllocations = new (IntPtr ptr, int size)[256];
private static uint pinnedAllocationsPointer = 0;
private delegate TInternal ToNativeDelegate<T, TInternal>(T value);
private delegate IntPtr UnboxerDelegate(object value, object converter);
private static ConcurrentDictionary<Type, (UnboxerDelegate deleg, object toNativeDeleg)> unboxers = new (1, 3);
private static ConcurrentDictionary<Type, (UnboxerDelegate deleg, object toNativeDeleg)> unboxers = new(1, 3);
private static MethodInfo unboxerMethod = typeof(ValueTypeUnboxer).GetMethod(nameof(ValueTypeUnboxer.UnboxPointer), BindingFlags.Static | BindingFlags.NonPublic);
private static MethodInfo unboxerToNativeMethod = typeof(ValueTypeUnboxer).GetMethod(nameof(ValueTypeUnboxer.UnboxPointerWithConverter), BindingFlags.Static | BindingFlags.NonPublic);
@@ -1089,7 +1137,8 @@ namespace FlaxEngine.Interop
return new IntPtr(Unsafe.AsPointer(ref Unsafe.Unbox<T>(value)));
}
private static IntPtr UnboxPointerWithConverter<T, TInternal>(object value, object converter) where T : struct where TInternal : struct
private static IntPtr UnboxPointerWithConverter<T, TInternal>(object value, object converter) where T : struct
where TInternal : struct
{
ToNativeDelegate<T, TInternal> toNative = Unsafe.As<ToNativeDelegate<T, TInternal>>(converter);
return PinValue<TInternal>(toNative(Unsafe.Unbox<T>(value)));
@@ -1099,12 +1148,12 @@ namespace FlaxEngine.Interop
private delegate IntPtr InvokeThunkDelegate(ManagedHandle instanceHandle, IntPtr param1, IntPtr param2, IntPtr param3, IntPtr param4, IntPtr param5, IntPtr param6, IntPtr param7);
/// <summary>
/// Returns all types that that owned by this assembly.
/// Returns all types owned by this assembly.
/// </summary>
private static Type[] GetAssemblyTypes(Assembly assembly)
{
var referencedAssemblies = assembly.GetReferencedAssemblies();
var allAssemblies = AppDomain.CurrentDomain.GetAssemblies();
var allAssemblies = Utils.GetAssemblies();
var referencedTypes = new List<string>();
foreach (var assemblyName in referencedAssemblies)
{

View File

@@ -76,11 +76,11 @@ void ForwardShadingFeature::Bind(MaterialShader::BindParameters& params, Span<by
// Set reflection probe data
EnvironmentProbe* probe = nullptr;
// TODO: optimize env probe searching for a transparent material - use spatial cache for renderer to find it
const Vector3 drawCallOrigin = drawCall.ObjectPosition + view.Origin;
const BoundingSphere objectBoundsWorld(drawCall.ObjectPosition + view.Origin, drawCall.ObjectRadius);
for (int32 i = 0; i < cache->EnvironmentProbes.Count(); i++)
{
const auto p = cache->EnvironmentProbes[i];
if (p->GetSphere().Contains(drawCallOrigin) != ContainmentType::Disjoint)
if (CollisionsHelper::SphereIntersectsSphere(objectBoundsWorld, p->GetSphere()))
{
probe = p;
break;
@@ -99,10 +99,12 @@ void ForwardShadingFeature::Bind(MaterialShader::BindParameters& params, Span<by
// Set local lights
data.LocalLightsCount = 0;
const BoundingSphere objectBounds(drawCall.ObjectPosition, drawCall.ObjectRadius);
// TODO: optimize lights searching for a transparent material - use spatial cache for renderer to find it
for (int32 i = 0; i < cache->PointLights.Count() && data.LocalLightsCount < MaxLocalLights; i++)
{
const auto& light = cache->PointLights[i];
if (BoundingSphere(light.Position, light.Radius).Contains(drawCall.ObjectPosition) != ContainmentType::Disjoint)
if (CollisionsHelper::SphereIntersectsSphere(objectBounds, BoundingSphere(light.Position, light.Radius)))
{
light.SetupLightData(&data.LocalLights[data.LocalLightsCount], false);
data.LocalLightsCount++;
@@ -111,7 +113,7 @@ void ForwardShadingFeature::Bind(MaterialShader::BindParameters& params, Span<by
for (int32 i = 0; i < cache->SpotLights.Count() && data.LocalLightsCount < MaxLocalLights; i++)
{
const auto& light = cache->SpotLights[i];
if (BoundingSphere(light.Position, light.Radius).Contains(drawCall.ObjectPosition) != ContainmentType::Disjoint)
if (CollisionsHelper::SphereIntersectsSphere(objectBounds, BoundingSphere(light.Position, light.Radius)))
{
light.SetupLightData(&data.LocalLights[data.LocalLightsCount], false);
data.LocalLightsCount++;

View File

@@ -429,6 +429,7 @@ void Mesh::Draw(const RenderContext& renderContext, MaterialBase* material, cons
drawCall.Material = material;
drawCall.World = world;
drawCall.ObjectPosition = drawCall.World.GetTranslation();
drawCall.ObjectRadius = _sphere.Radius * drawCall.World.GetScaleVector().GetAbsolute().MaxValue();
drawCall.Surface.GeometrySize = _box.GetSize();
drawCall.Surface.PrevWorld = world;
drawCall.Surface.Lightmap = nullptr;
@@ -495,6 +496,7 @@ void Mesh::Draw(const RenderContext& renderContext, const DrawInfo& info, float
drawCall.Material = material;
drawCall.World = *info.World;
drawCall.ObjectPosition = drawCall.World.GetTranslation();
drawCall.ObjectRadius = info.Bounds.Radius; // TODO: should it be kept in sync with ObjectPosition?
drawCall.Surface.GeometrySize = _box.GetSize();
drawCall.Surface.PrevWorld = info.DrawState->PrevWorld;
drawCall.Surface.Lightmap = (info.Flags & StaticFlags::Lightmap) != StaticFlags::None ? info.Lightmap : nullptr;
@@ -555,6 +557,7 @@ void Mesh::Draw(const RenderContextBatch& renderContextBatch, const DrawInfo& in
drawCall.Material = material;
drawCall.World = *info.World;
drawCall.ObjectPosition = drawCall.World.GetTranslation();
drawCall.ObjectRadius = info.Bounds.Radius; // TODO: should it be kept in sync with ObjectPosition?
drawCall.Surface.GeometrySize = _box.GetSize();
drawCall.Surface.PrevWorld = info.DrawState->PrevWorld;
drawCall.Surface.Lightmap = (info.Flags & StaticFlags::Lightmap) != StaticFlags::None ? info.Lightmap : nullptr;

View File

@@ -198,6 +198,7 @@ void SkinnedMesh::Draw(const RenderContext& renderContext, const DrawInfo& info,
drawCall.Material = material;
drawCall.World = *info.World;
drawCall.ObjectPosition = drawCall.World.GetTranslation();
drawCall.ObjectRadius = info.Bounds.Radius; // TODO: should it be kept in sync with ObjectPosition?
drawCall.Surface.GeometrySize = _box.GetSize();
drawCall.Surface.PrevWorld = info.DrawState->PrevWorld;
drawCall.Surface.Lightmap = nullptr;
@@ -258,6 +259,7 @@ void SkinnedMesh::Draw(const RenderContextBatch& renderContextBatch, const DrawI
drawCall.Material = material;
drawCall.World = *info.World;
drawCall.ObjectPosition = drawCall.World.GetTranslation();
drawCall.ObjectRadius = info.Bounds.Radius; // TODO: should it be kept in sync with ObjectPosition?
drawCall.Surface.GeometrySize = _box.GetSize();
drawCall.Surface.PrevWorld = info.DrawState->PrevWorld;
drawCall.Surface.Lightmap = nullptr;

View File

@@ -120,7 +120,7 @@ bool GPUShader::Create(MemoryReadStream& stream)
GPUShaderProgram* shader = CreateGPUShaderProgram(type, initializer, cache, cacheSize, stream);
if (shader == nullptr)
{
LOG(Warning, "Failed to create shader program.");
LOG(Error, "Failed to create {} Shader program '{}'.", ::ToString(type), String(initializer.Name));
return true;
}

View File

@@ -105,7 +105,7 @@ bool GPUBufferDX11::OnInit()
data.SysMemPitch = bufferDesc.ByteWidth;
data.SysMemSlicePitch = 0;
}
VALIDATE_DIRECTX_RESULT(_device->GetDevice()->CreateBuffer(&bufferDesc, _desc.InitData ? &data : nullptr, &_resource));
VALIDATE_DIRECTX_CALL(_device->GetDevice()->CreateBuffer(&bufferDesc, _desc.InitData ? &data : nullptr, &_resource));
// Set state
DX_SET_DEBUG_NAME(_resource, GetName());
@@ -135,7 +135,7 @@ bool GPUBufferDX11::OnInit()
srvDesc.Buffer.NumElements = numElements;
}
ID3D11ShaderResourceView* srv;
VALIDATE_DIRECTX_RESULT(_device->GetDevice()->CreateShaderResourceView(_resource, &srvDesc, &srv));
VALIDATE_DIRECTX_CALL(_device->GetDevice()->CreateShaderResourceView(_resource, &srvDesc, &srv));
_view.SetSRV(srv);
}
if (useUAV)
@@ -156,7 +156,7 @@ bool GPUBufferDX11::OnInit()
else
uavDesc.Format = RenderToolsDX::ToDxgiFormat(PixelFormatExtensions::FindUnorderedAccessFormat(_desc.Format));
ID3D11UnorderedAccessView* uav;
VALIDATE_DIRECTX_RESULT(_device->GetDevice()->CreateUnorderedAccessView(_resource, &uavDesc, &uav));
VALIDATE_DIRECTX_CALL(_device->GetDevice()->CreateUnorderedAccessView(_resource, &uavDesc, &uav));
_view.SetUAV(uav);
}

View File

@@ -143,7 +143,7 @@ GPUDevice* GPUDeviceDX11::Create()
if (tempAdapter && TryCreateDevice(tempAdapter, maxAllowedFeatureLevel, &adapter.MaxFeatureLevel))
{
adapter.Index = index;
VALIDATE_DIRECTX_RESULT(tempAdapter->GetDesc(&adapter.Description));
VALIDATE_DIRECTX_CALL(tempAdapter->GetDesc(&adapter.Description));
uint32 outputs = RenderToolsDX::CountAdapterOutputs(tempAdapter);
LOG(Info, "Adapter {1}: '{0}', DirectX {2}", adapter.Description.Description, index, RenderToolsDX::GetFeatureLevelString(adapter.MaxFeatureLevel));
@@ -163,7 +163,7 @@ GPUDevice* GPUDeviceDX11::Create()
if (tempAdapter && TryCreateDevice(tempAdapter, maxAllowedFeatureLevel, &adapter.MaxFeatureLevel))
{
DXGI_ADAPTER_DESC desc;
VALIDATE_DIRECTX_RESULT(tempAdapter->GetDesc(&desc));
VALIDATE_DIRECTX_CALL(tempAdapter->GetDesc(&desc));
for (int i = 0; i < adapters.Count(); i++)
{
if (adapters[i].Description.AdapterLuid.LowPart == desc.AdapterLuid.LowPart &&
@@ -274,7 +274,7 @@ ID3D11BlendState* GPUDeviceDX11::GetBlendState(const BlendingMode& blending)
#endif
// Create object
VALIDATE_DIRECTX_RESULT(_device->CreateBlendState(&desc, &blendState));
VALIDATE_DIRECTX_CALL(_device->CreateBlendState(&desc, &blendState));
// Cache blend state
BlendStates.Add(blending, blendState);
@@ -333,7 +333,7 @@ bool GPUDeviceDX11::Init()
// Create DirectX device
D3D_FEATURE_LEVEL createdFeatureLevel = static_cast<D3D_FEATURE_LEVEL>(0);
auto targetFeatureLevel = GetD3DFeatureLevel();
VALIDATE_DIRECTX_RESULT(D3D11CreateDevice(adapter, D3D_DRIVER_TYPE_UNKNOWN, NULL, flags, &targetFeatureLevel, 1, D3D11_SDK_VERSION, &_device, &createdFeatureLevel, &_imContext));
VALIDATE_DIRECTX_CALL(D3D11CreateDevice(adapter, D3D_DRIVER_TYPE_UNKNOWN, NULL, flags, &targetFeatureLevel, 1, D3D11_SDK_VERSION, &_device, &createdFeatureLevel, &_imContext));
// Validate result
ASSERT(_device);
@@ -409,7 +409,7 @@ bool GPUDeviceDX11::Init()
// Init debug layer
#if GPU_ENABLE_DIAGNOSTICS
ComPtr<ID3D11InfoQueue> infoQueue;
VALIDATE_DIRECTX_RESULT(_device->QueryInterface(IID_PPV_ARGS(&infoQueue)));
VALIDATE_DIRECTX_CALL(_device->QueryInterface(IID_PPV_ARGS(&infoQueue)));
if (infoQueue)
{
D3D11_INFO_QUEUE_FILTER filter;
@@ -457,7 +457,7 @@ bool GPUDeviceDX11::Init()
samplerDesc.MinLOD = 0;
samplerDesc.MaxLOD = D3D11_FLOAT32_MAX;
result = _device->CreateSamplerState(&samplerDesc, &_samplerLinearClamp);
LOG_DIRECTX_RESULT_WITH_RETURN(result);
LOG_DIRECTX_RESULT_WITH_RETURN(result, true);
// Point Clamp
samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT;
@@ -467,7 +467,7 @@ bool GPUDeviceDX11::Init()
samplerDesc.MinLOD = 0;
samplerDesc.MaxLOD = D3D11_FLOAT32_MAX;
result = _device->CreateSamplerState(&samplerDesc, &_samplerPointClamp);
LOG_DIRECTX_RESULT_WITH_RETURN(result);
LOG_DIRECTX_RESULT_WITH_RETURN(result, true);
// Linear Wrap
samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
@@ -477,7 +477,7 @@ bool GPUDeviceDX11::Init()
samplerDesc.MinLOD = 0;
samplerDesc.MaxLOD = D3D11_FLOAT32_MAX;
result = _device->CreateSamplerState(&samplerDesc, &_samplerLinearWrap);
LOG_DIRECTX_RESULT_WITH_RETURN(result);
LOG_DIRECTX_RESULT_WITH_RETURN(result, true);
// Point Wrap
samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT;
@@ -487,7 +487,7 @@ bool GPUDeviceDX11::Init()
samplerDesc.MinLOD = 0;
samplerDesc.MaxLOD = D3D11_FLOAT32_MAX;
result = _device->CreateSamplerState(&samplerDesc, &_samplerPointWrap);
LOG_DIRECTX_RESULT_WITH_RETURN(result);
LOG_DIRECTX_RESULT_WITH_RETURN(result, true);
// Shadow
samplerDesc.Filter = D3D11_FILTER_COMPARISON_MIN_MAG_MIP_POINT;
@@ -500,7 +500,7 @@ bool GPUDeviceDX11::Init()
samplerDesc.MinLOD = 0;
samplerDesc.MaxLOD = D3D11_FLOAT32_MAX;
result = _device->CreateSamplerState(&samplerDesc, &_samplerShadow);
LOG_DIRECTX_RESULT_WITH_RETURN(result);
LOG_DIRECTX_RESULT_WITH_RETURN(result, true);
// Shadow PCF
samplerDesc.Filter = D3D11_FILTER_COMPARISON_MIN_MAG_MIP_LINEAR;
@@ -514,7 +514,7 @@ bool GPUDeviceDX11::Init()
samplerDesc.MinLOD = 0;
samplerDesc.MaxLOD = D3D11_FLOAT32_MAX;
result = _device->CreateSamplerState(&samplerDesc, &_samplerShadowPCF);
LOG_DIRECTX_RESULT_WITH_RETURN(result);
LOG_DIRECTX_RESULT_WITH_RETURN(result, true);
}
// Rasterizer States
@@ -534,7 +534,7 @@ bool GPUDeviceDX11::Init()
rDesc.AntialiasedLineEnable = !!wireframe; \
rDesc.DepthClipEnable = !!depthClip; \
result = _device->CreateRasterizerState(&rDesc, &RasterizerStates[index]); \
LOG_DIRECTX_RESULT_WITH_RETURN(result)
LOG_DIRECTX_RESULT_WITH_RETURN(result, true)
CREATE_RASTERIZER_STATE(CullMode::Normal, D3D11_CULL_BACK, false, false);
CREATE_RASTERIZER_STATE(CullMode::Inverted, D3D11_CULL_FRONT, false, false);
CREATE_RASTERIZER_STATE(CullMode::TwoSided, D3D11_CULL_NONE, false, false);
@@ -568,7 +568,7 @@ bool GPUDeviceDX11::Init()
dsDesc.DepthFunc = (D3D11_COMPARISON_FUNC)depthFunc; \
index = (int32)depthFunc + (depthEnable ? 0 : 9) + (depthWrite ? 0 : 18); \
HRESULT result = _device->CreateDepthStencilState(&dsDesc, &DepthStencilStates[index]); \
LOG_DIRECTX_RESULT_WITH_RETURN(result); }
LOG_DIRECTX_RESULT_WITH_RETURN(result, true); }
CREATE_DEPTH_STENCIL_STATE(false, false);
CREATE_DEPTH_STENCIL_STATE(false, true);
CREATE_DEPTH_STENCIL_STATE(true, true);
@@ -666,7 +666,7 @@ void GPUDeviceDX11::DrawEnd()
#if GPU_ENABLE_DIAGNOSTICS
// Flush debug messages queue
ComPtr<ID3D11InfoQueue> infoQueue;
VALIDATE_DIRECTX_RESULT(_device->QueryInterface(IID_PPV_ARGS(&infoQueue)));
VALIDATE_DIRECTX_CALL(_device->QueryInterface(IID_PPV_ARGS(&infoQueue)));
if (infoQueue)
{
Array<uint8> data;

View File

@@ -106,7 +106,7 @@ bool GPUSamplerDX11::OnInit()
samplerDesc.MinLOD = _desc.MinMipLevel;
samplerDesc.MaxLOD = _desc.MaxMipLevel;
HRESULT result = _device->GetDevice()->CreateSamplerState(&samplerDesc, &SamplerState);
LOG_DIRECTX_RESULT_WITH_RETURN(result);
LOG_DIRECTX_RESULT_WITH_RETURN(result, true);
ASSERT(SamplerState != nullptr);
_memoryUsage = sizeof(D3D11_SAMPLER_DESC);

View File

@@ -10,6 +10,7 @@
GPUShaderProgram* GPUShaderDX11::CreateGPUShaderProgram(ShaderStage type, const GPUShaderProgramInitializer& initializer, byte* cacheBytes, uint32 cacheSize, MemoryReadStream& stream)
{
GPUShaderProgram* shader = nullptr;
HRESULT result;
switch (type)
{
case ShaderStage::Vertex:
@@ -90,12 +91,13 @@ GPUShaderProgram* GPUShaderDX11::CreateGPUShaderProgram(ShaderStage type, const
if (inputLayoutSize > 0)
{
// Create input layout
VALIDATE_DIRECTX_RESULT(_device->GetDevice()->CreateInputLayout(inputLayoutDesc, inputLayoutSize, cacheBytes, cacheSize, &inputLayout));
VALIDATE_DIRECTX_CALL(_device->GetDevice()->CreateInputLayout(inputLayoutDesc, inputLayoutSize, cacheBytes, cacheSize, &inputLayout));
}
// Create shader
ID3D11VertexShader* buffer = nullptr;
VALIDATE_DIRECTX_RESULT(_device->GetDevice()->CreateVertexShader(cacheBytes, cacheSize, nullptr, &buffer));
result = _device->GetDevice()->CreateVertexShader(cacheBytes, cacheSize, nullptr, &buffer);
LOG_DIRECTX_RESULT_WITH_RETURN(result, nullptr);
// Create object
shader = New<GPUShaderProgramVSDX11>(initializer, buffer, inputLayout, inputLayoutSize);
@@ -109,7 +111,8 @@ GPUShaderProgram* GPUShaderDX11::CreateGPUShaderProgram(ShaderStage type, const
// Create shader
ID3D11HullShader* buffer = nullptr;
VALIDATE_DIRECTX_RESULT(_device->GetDevice()->CreateHullShader(cacheBytes, cacheSize, nullptr, &buffer));
result = _device->GetDevice()->CreateHullShader(cacheBytes, cacheSize, nullptr, &buffer);
LOG_DIRECTX_RESULT_WITH_RETURN(result, nullptr);
// Create object
shader = New<GPUShaderProgramHSDX11>(initializer, buffer, controlPointsCount);
@@ -119,7 +122,8 @@ GPUShaderProgram* GPUShaderDX11::CreateGPUShaderProgram(ShaderStage type, const
{
// Create shader
ID3D11DomainShader* buffer = nullptr;
VALIDATE_DIRECTX_RESULT(_device->GetDevice()->CreateDomainShader(cacheBytes, cacheSize, nullptr, &buffer));
result = _device->GetDevice()->CreateDomainShader(cacheBytes, cacheSize, nullptr, &buffer);
LOG_DIRECTX_RESULT_WITH_RETURN(result, nullptr);
// Create object
shader = New<GPUShaderProgramDSDX11>(initializer, buffer);
@@ -129,7 +133,8 @@ GPUShaderProgram* GPUShaderDX11::CreateGPUShaderProgram(ShaderStage type, const
{
// Create shader
ID3D11GeometryShader* buffer = nullptr;
VALIDATE_DIRECTX_RESULT(_device->GetDevice()->CreateGeometryShader(cacheBytes, cacheSize, nullptr, &buffer));
result = _device->GetDevice()->CreateGeometryShader(cacheBytes, cacheSize, nullptr, &buffer);
LOG_DIRECTX_RESULT_WITH_RETURN(result, nullptr);
// Create object
shader = New<GPUShaderProgramGSDX11>(initializer, buffer);
@@ -139,7 +144,8 @@ GPUShaderProgram* GPUShaderDX11::CreateGPUShaderProgram(ShaderStage type, const
{
// Create shader
ID3D11PixelShader* buffer = nullptr;
VALIDATE_DIRECTX_RESULT(_device->GetDevice()->CreatePixelShader(cacheBytes, cacheSize, nullptr, &buffer));
result = _device->GetDevice()->CreatePixelShader(cacheBytes, cacheSize, nullptr, &buffer);
LOG_DIRECTX_RESULT_WITH_RETURN(result, nullptr);
// Create object
shader = New<GPUShaderProgramPSDX11>(initializer, buffer);
@@ -149,7 +155,8 @@ GPUShaderProgram* GPUShaderDX11::CreateGPUShaderProgram(ShaderStage type, const
{
// Create shader
ID3D11ComputeShader* buffer = nullptr;
VALIDATE_DIRECTX_RESULT(_device->GetDevice()->CreateComputeShader(cacheBytes, cacheSize, nullptr, &buffer));
result = _device->GetDevice()->CreateComputeShader(cacheBytes, cacheSize, nullptr, &buffer);
LOG_DIRECTX_RESULT_WITH_RETURN(result, nullptr);
// Create object
shader = New<GPUShaderProgramCSDX11>(initializer, buffer);

View File

@@ -28,13 +28,13 @@ GPUSwapChainDX11::GPUSwapChainDX11(GPUDeviceDX11* device, Window* window)
void GPUSwapChainDX11::getBackBuffer()
{
VALIDATE_DIRECTX_RESULT(_swapChain->GetBuffer(0, __uuidof(_backBuffer), reinterpret_cast<void**>(&_backBuffer)));
VALIDATE_DIRECTX_CALL(_swapChain->GetBuffer(0, __uuidof(_backBuffer), reinterpret_cast<void**>(&_backBuffer)));
ID3D11RenderTargetView* rtv;
ID3D11ShaderResourceView* srv;
VALIDATE_DIRECTX_RESULT(_device->GetDevice()->CreateRenderTargetView(_backBuffer, nullptr, &rtv));
VALIDATE_DIRECTX_CALL(_device->GetDevice()->CreateRenderTargetView(_backBuffer, nullptr, &rtv));
#if GPU_USE_WINDOW_SRV
VALIDATE_DIRECTX_RESULT(_device->GetDevice()->CreateShaderResourceView(_backBuffer, nullptr, &srv));
VALIDATE_DIRECTX_CALL(_device->GetDevice()->CreateShaderResourceView(_backBuffer, nullptr, &srv));
#else
srv = nullptr;
#endif
@@ -55,7 +55,7 @@ void GPUSwapChainDX11::OnReleaseGPU()
// Disable fullscreen mode
if (_swapChain)
{
VALIDATE_DIRECTX_RESULT(_swapChain->SetFullscreenState(false, nullptr));
VALIDATE_DIRECTX_CALL(_swapChain->SetFullscreenState(false, nullptr));
}
#endif
@@ -78,7 +78,7 @@ bool GPUSwapChainDX11::IsFullscreen()
// Get state
BOOL state;
VALIDATE_DIRECTX_RESULT(_swapChain->GetFullscreenState(&state, nullptr));
VALIDATE_DIRECTX_CALL(_swapChain->GetFullscreenState(&state, nullptr));
return state == TRUE;
}
@@ -229,21 +229,21 @@ bool GPUSwapChainDX11::Resize(int32 width, int32 height)
// Create swap chain
#if PLATFORM_WINDOWS
auto dxgi = _device->GetDXGIFactory();
VALIDATE_DIRECTX_RESULT(dxgi->CreateSwapChain(_device->GetDevice(), &swapChainDesc, &_swapChain));
VALIDATE_DIRECTX_CALL(dxgi->CreateSwapChain(_device->GetDevice(), &swapChainDesc, &_swapChain));
ASSERT(_swapChain);
// Disable DXGI changes to the window
VALIDATE_DIRECTX_RESULT(dxgi->MakeWindowAssociation(_windowHandle, DXGI_MWA_NO_ALT_ENTER));
VALIDATE_DIRECTX_CALL(dxgi->MakeWindowAssociation(_windowHandle, DXGI_MWA_NO_ALT_ENTER));
#else
auto dxgiFactory = (IDXGIFactory2*)_device->GetDXGIFactory();
VALIDATE_DIRECTX_RESULT(dxgiFactory->CreateSwapChainForCoreWindow(_device->GetDevice(), static_cast<IUnknown*>(_windowHandle), &swapChainDesc, nullptr, &_swapChain));
VALIDATE_DIRECTX_CALL(dxgiFactory->CreateSwapChainForCoreWindow(_device->GetDevice(), static_cast<IUnknown*>(_windowHandle), &swapChainDesc, nullptr, &_swapChain));
ASSERT(_swapChain);
// Ensure that DXGI does not queue more than one frame at a time. This both reduces latency and
// ensures that the application will only render after each VSync, minimizing power consumption.
ComPtr<IDXGIDevice2> dxgiDevice;
VALIDATE_DIRECTX_RESULT(_device->GetDevice()->QueryInterface(IID_PPV_ARGS(&dxgiDevice)));
VALIDATE_DIRECTX_RESULT(dxgiDevice->SetMaximumFrameLatency(1));
VALIDATE_DIRECTX_CALL(_device->GetDevice()->QueryInterface(IID_PPV_ARGS(&dxgiDevice)));
VALIDATE_DIRECTX_CALL(dxgiDevice->SetMaximumFrameLatency(1));
#endif
}
else
@@ -252,10 +252,10 @@ bool GPUSwapChainDX11::Resize(int32 width, int32 height)
#if PLATFORM_WINDOWS
_swapChain->GetDesc(&swapChainDesc);
VALIDATE_DIRECTX_RESULT(_swapChain->ResizeBuffers(swapChainDesc.BufferCount, width, height, swapChainDesc.BufferDesc.Format, swapChainDesc.Flags));
VALIDATE_DIRECTX_CALL(_swapChain->ResizeBuffers(swapChainDesc.BufferCount, width, height, swapChainDesc.BufferDesc.Format, swapChainDesc.Flags));
#else
_swapChain->GetDesc1(&swapChainDesc);
VALIDATE_DIRECTX_RESULT(_swapChain->ResizeBuffers(swapChainDesc.BufferCount, width, height, swapChainDesc.Format, swapChainDesc.Flags));
VALIDATE_DIRECTX_CALL(_swapChain->ResizeBuffers(swapChainDesc.BufferCount, width, height, swapChainDesc.Format, swapChainDesc.Flags));
#endif
}

View File

@@ -87,7 +87,7 @@ bool GPUTextureDX11::OnInit()
result = device->CreateTexture2D(&textureDesc, nullptr, &texture);
_resource = texture;
}
LOG_DIRECTX_RESULT_WITH_RETURN(result);
LOG_DIRECTX_RESULT_WITH_RETURN(result, true);
ASSERT(_resource != nullptr);
DX_SET_DEBUG_NAME(_resource, GetName());
@@ -135,7 +135,7 @@ void GPUTextureDX11::OnResidentMipsChanged()
}
ID3D11ShaderResourceView* srView = nullptr;
if (mipLevels != 0)
VALIDATE_DIRECTX_RESULT(_device->GetDevice()->CreateShaderResourceView(_resource, &srDesc, &srView));
VALIDATE_DIRECTX_CALL(_device->GetDevice()->CreateShaderResourceView(_resource, &srDesc, &srView));
GPUTextureViewDX11& view = IsVolume() ? _handleVolume : _handlesPerSlice[0];
if (view.GetParent() == nullptr)
view.Init(this, nullptr, srView, nullptr, nullptr, Format(), MultiSampleLevel());
@@ -201,7 +201,7 @@ void GPUTextureDX11::initHandles()
srDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE3D;
srDesc.Texture3D.MostDetailedMip = 0;
srDesc.Texture3D.MipLevels = mipLevels;
VALIDATE_DIRECTX_RESULT(device->CreateShaderResourceView(_resource, &srDesc, &srView));
VALIDATE_DIRECTX_CALL(device->CreateShaderResourceView(_resource, &srDesc, &srView));
}
if (useRTV)
{
@@ -209,7 +209,7 @@ void GPUTextureDX11::initHandles()
rtDesc.Texture3D.MipSlice = 0;
rtDesc.Texture3D.FirstWSlice = 0;
rtDesc.Texture3D.WSize = Depth();
VALIDATE_DIRECTX_RESULT(device->CreateRenderTargetView(_resource, &rtDesc, &rtView));
VALIDATE_DIRECTX_CALL(device->CreateRenderTargetView(_resource, &rtDesc, &rtView));
}
if (useUAV)
{
@@ -217,7 +217,7 @@ void GPUTextureDX11::initHandles()
uaDesc.Texture3D.MipSlice = 0;
uaDesc.Texture3D.WSize = Depth();
uaDesc.Texture3D.FirstWSlice = 0;
VALIDATE_DIRECTX_RESULT(device->CreateUnorderedAccessView(_resource, &uaDesc, &uaView));
VALIDATE_DIRECTX_CALL(device->CreateUnorderedAccessView(_resource, &uaDesc, &uaView));
}
_handleVolume.Init(this, rtView, srView, nullptr, uaView, format, msaa);
@@ -232,7 +232,7 @@ void GPUTextureDX11::initHandles()
for (int32 sliceIndex = 0; sliceIndex < Depth(); sliceIndex++)
{
rtDesc.Texture3D.FirstWSlice = sliceIndex;
VALIDATE_DIRECTX_RESULT(device->CreateRenderTargetView(_resource, &rtDesc, &rtView));
VALIDATE_DIRECTX_CALL(device->CreateRenderTargetView(_resource, &rtDesc, &rtView));
_handlesPerSlice[sliceIndex].Init(this, rtView, nullptr, nullptr, nullptr, format, msaa);
}
}
@@ -263,7 +263,7 @@ void GPUTextureDX11::initHandles()
dsDesc.Texture2DArray.FirstArraySlice = arrayIndex;
dsDesc.Texture2DArray.MipSlice = 0;
}
VALIDATE_DIRECTX_RESULT(device->CreateDepthStencilView(_resource, &dsDesc, &dsView));
VALIDATE_DIRECTX_CALL(device->CreateDepthStencilView(_resource, &dsDesc, &dsView));
}
if (useRTV)
{
@@ -281,7 +281,7 @@ void GPUTextureDX11::initHandles()
rtDesc.Texture2DArray.FirstArraySlice = arrayIndex;
rtDesc.Texture2DArray.MipSlice = 0;
}
VALIDATE_DIRECTX_RESULT(device->CreateRenderTargetView(_resource, &rtDesc, &rtView));
VALIDATE_DIRECTX_CALL(device->CreateRenderTargetView(_resource, &rtDesc, &rtView));
}
if (useSRV)
{
@@ -305,7 +305,7 @@ void GPUTextureDX11::initHandles()
srDesc.Texture2DArray.MipLevels = mipLevels;
srDesc.Texture2DArray.MostDetailedMip = 0;
}
VALIDATE_DIRECTX_RESULT(device->CreateShaderResourceView(_resource, &srDesc, &srView));
VALIDATE_DIRECTX_CALL(device->CreateShaderResourceView(_resource, &srDesc, &srView));
}
}
@@ -322,7 +322,7 @@ void GPUTextureDX11::initHandles()
dsDesc.Texture2DArray.ArraySize = arraySize;
dsDesc.Texture2DArray.FirstArraySlice = 0;
dsDesc.Texture2DArray.MipSlice = 0;
VALIDATE_DIRECTX_RESULT(device->CreateDepthStencilView(_resource, &dsDesc, &dsView));
VALIDATE_DIRECTX_CALL(device->CreateDepthStencilView(_resource, &dsDesc, &dsView));
}
if (useRTV)
{
@@ -330,7 +330,7 @@ void GPUTextureDX11::initHandles()
rtDesc.Texture2DArray.ArraySize = arraySize;
rtDesc.Texture2DArray.FirstArraySlice = 0;
rtDesc.Texture2DArray.MipSlice = 0;
VALIDATE_DIRECTX_RESULT(device->CreateRenderTargetView(_resource, &rtDesc, &rtView));
VALIDATE_DIRECTX_CALL(device->CreateRenderTargetView(_resource, &rtDesc, &rtView));
}
if (useSRV)
{
@@ -348,7 +348,7 @@ void GPUTextureDX11::initHandles()
srDesc.Texture2DArray.MipLevels = mipLevels;
srDesc.Texture2DArray.MostDetailedMip = 0;
}
VALIDATE_DIRECTX_RESULT(device->CreateShaderResourceView(_resource, &srDesc, &srView));
VALIDATE_DIRECTX_CALL(device->CreateShaderResourceView(_resource, &srDesc, &srView));
}
if (useUAV)
{
@@ -356,7 +356,7 @@ void GPUTextureDX11::initHandles()
uaDesc.Texture2DArray.MipSlice = 0;
uaDesc.Texture2DArray.ArraySize = arraySize;
uaDesc.Texture2DArray.FirstArraySlice = 0;
VALIDATE_DIRECTX_RESULT(device->CreateUnorderedAccessView(_resource, &uaDesc, &uaView));
VALIDATE_DIRECTX_CALL(device->CreateUnorderedAccessView(_resource, &uaDesc, &uaView));
}
_handleArray.Init(this, rtView, srView, dsView, uaView, format, msaa);
}
@@ -386,7 +386,7 @@ void GPUTextureDX11::initHandles()
dsDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
dsDesc.Texture2D.MipSlice = 0;
}
VALIDATE_DIRECTX_RESULT(device->CreateDepthStencilView(_resource, &dsDesc, &dsView));
VALIDATE_DIRECTX_CALL(device->CreateDepthStencilView(_resource, &dsDesc, &dsView));
}
if (useRTV)
{
@@ -406,7 +406,7 @@ void GPUTextureDX11::initHandles()
rtDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
rtDesc.Texture2D.MipSlice = 0;
}
VALIDATE_DIRECTX_RESULT(device->CreateRenderTargetView(_resource, &rtDesc, &rtView));
VALIDATE_DIRECTX_CALL(device->CreateRenderTargetView(_resource, &rtDesc, &rtView));
}
if (useSRV)
{
@@ -426,13 +426,13 @@ void GPUTextureDX11::initHandles()
srDesc.Texture2D.MostDetailedMip = 0;
srDesc.Texture2D.MipLevels = mipLevels;
}
VALIDATE_DIRECTX_RESULT(device->CreateShaderResourceView(_resource, &srDesc, &srView));
VALIDATE_DIRECTX_CALL(device->CreateShaderResourceView(_resource, &srDesc, &srView));
}
if (useUAV)
{
uaDesc.ViewDimension = D3D11_UAV_DIMENSION_TEXTURE2D;
uaDesc.Texture2D.MipSlice = 0;
VALIDATE_DIRECTX_RESULT(device->CreateUnorderedAccessView(_resource, &uaDesc, &uaView));
VALIDATE_DIRECTX_CALL(device->CreateUnorderedAccessView(_resource, &uaDesc, &uaView));
}
_handlesPerSlice[0].Init(this, rtView, srView, dsView, uaView, format, msaa);
}
@@ -521,7 +521,7 @@ void GPUTextureDX11::initHandles()
dsDesc.Flags = D3D11_DSV_READ_ONLY_DEPTH;
if (PixelFormatExtensions::HasStencil(format))
dsDesc.Flags |= D3D11_DSV_READ_ONLY_STENCIL;
VALIDATE_DIRECTX_RESULT(device->CreateDepthStencilView(_resource, &dsDesc, &dsView));
VALIDATE_DIRECTX_CALL(device->CreateDepthStencilView(_resource, &dsDesc, &dsView));
}
ASSERT(!useRTV);
rtView = nullptr;
@@ -543,7 +543,7 @@ void GPUTextureDX11::initHandles()
srDesc.Texture2D.MostDetailedMip = 0;
srDesc.Texture2D.MipLevels = mipLevels;
}
VALIDATE_DIRECTX_RESULT(device->CreateShaderResourceView(_resource, &srDesc, &srView));
VALIDATE_DIRECTX_CALL(device->CreateShaderResourceView(_resource, &srDesc, &srView));
}
_handleReadOnlyDepth.Init(this, rtView, srView, dsView, nullptr, format, msaa);
}

View File

@@ -31,7 +31,7 @@ ID3D12CommandAllocator* CommandAllocatorPoolDX12::RequestAllocator(uint64 comple
if (firstPair.First <= completedFenceValue)
{
allocator = firstPair.Second;
VALIDATE_DIRECTX_RESULT(allocator->Reset());
VALIDATE_DIRECTX_CALL(allocator->Reset());
_ready.RemoveAtKeepOrder(0);
}
}
@@ -39,7 +39,7 @@ ID3D12CommandAllocator* CommandAllocatorPoolDX12::RequestAllocator(uint64 comple
// If no allocators were ready to be reused, create a new one
if (allocator == nullptr)
{
VALIDATE_DIRECTX_RESULT(_device->GetDevice()->CreateCommandAllocator(_type, IID_PPV_ARGS(&allocator)));
VALIDATE_DIRECTX_CALL(_device->GetDevice()->CreateCommandAllocator(_type, IID_PPV_ARGS(&allocator)));
#if GPU_ENABLE_RESOURCE_NAMING
Char name[32];
swprintf(name, 32, L"CommandAllocator %u", _pool.Count());

View File

@@ -111,7 +111,7 @@ bool CommandQueueDX12::Init()
desc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
desc.NodeMask = 0;
HRESULT result = _device->GetDevice()->CreateCommandQueue(&desc, IID_PPV_ARGS(&_commandQueue));
LOG_DIRECTX_RESULT_WITH_RETURN(result);
LOG_DIRECTX_RESULT_WITH_RETURN(result, true);
#if GPU_ENABLE_RESOURCE_NAMING
_commandQueue->SetName(TEXT("CommandQueueDX12::CommandQueue"));
#endif
@@ -148,7 +148,7 @@ void CommandQueueDX12::WaitForGPU()
uint64 CommandQueueDX12::ExecuteCommandList(ID3D12CommandList* list)
{
VALIDATE_DIRECTX_RESULT((static_cast<ID3D12GraphicsCommandList*>(list))->Close());
VALIDATE_DIRECTX_CALL((static_cast<ID3D12GraphicsCommandList*>(list))->Close());
_commandQueue->ExecuteCommandLists(1, &list);

View File

@@ -73,7 +73,7 @@ bool DescriptorHeapWithSlotsDX12::Create(D3D12_DESCRIPTOR_HEAP_TYPE type, uint32
// Create heap
const HRESULT result = _device->GetDevice()->CreateDescriptorHeap(&desc, __uuidof(ID3D12DescriptorHeap), reinterpret_cast<void**>(&_heap));
LOG_DIRECTX_RESULT_WITH_RETURN(result);
LOG_DIRECTX_RESULT_WITH_RETURN(result, true);
// Setup
_type = type;
@@ -196,7 +196,7 @@ bool DescriptorHeapRingBufferDX12::Init()
desc.Flags = _shaderVisible ? D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE : D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
desc.NodeMask = 0;
const HRESULT result = _device->GetDevice()->CreateDescriptorHeap(&desc, IID_PPV_ARGS(&_heap));
LOG_DIRECTX_RESULT_WITH_RETURN(result);
LOG_DIRECTX_RESULT_WITH_RETURN(result, true);
// Setup
_firstFree = 0;

View File

@@ -136,7 +136,7 @@ bool GPUBufferDX12::OnInit()
// Create resource
ID3D12Resource* resource;
D3D12_RESOURCE_STATES initialState = D3D12_RESOURCE_STATE_COPY_DEST;
VALIDATE_DIRECTX_RESULT(_device->GetDevice()->CreateCommittedResource(&heapProperties, D3D12_HEAP_FLAG_NONE, &resourceDesc, initialState, nullptr, IID_PPV_ARGS(&resource)));
VALIDATE_DIRECTX_CALL(_device->GetDevice()->CreateCommittedResource(&heapProperties, D3D12_HEAP_FLAG_NONE, &resourceDesc, initialState, nullptr, IID_PPV_ARGS(&resource)));
// Set state
initResource(resource, initialState, 1);

View File

@@ -83,7 +83,7 @@ GPUContextDX12::GPUContextDX12(GPUDeviceDX12* device, D3D12_COMMAND_LIST_TYPE ty
FrameFenceValues[0] = 0;
FrameFenceValues[1] = 0;
_currentAllocator = _device->GetCommandQueue()->RequestAllocator();
VALIDATE_DIRECTX_RESULT(device->GetDevice()->CreateCommandList(0, type, _currentAllocator, nullptr, IID_PPV_ARGS(&_commandList)));
VALIDATE_DIRECTX_CALL(device->GetDevice()->CreateCommandList(0, type, _currentAllocator, nullptr, IID_PPV_ARGS(&_commandList)));
#if GPU_ENABLE_RESOURCE_NAMING
_commandList->SetName(TEXT("GPUContextDX12::CommandList"));
#endif

View File

@@ -77,7 +77,7 @@ GPUDevice* GPUDeviceDX12::Create()
#endif
#ifdef __ID3D12DeviceRemovedExtendedDataSettings_FWD_DEFINED__
ComPtr<ID3D12DeviceRemovedExtendedDataSettings> dredSettings;
VALIDATE_DIRECTX_RESULT(D3D12GetDebugInterface(IID_PPV_ARGS(&dredSettings)));
VALIDATE_DIRECTX_CALL(D3D12GetDebugInterface(IID_PPV_ARGS(&dredSettings)));
if (dredSettings)
{
// Turn on AutoBreadcrumbs and Page Fault reporting
@@ -116,7 +116,7 @@ GPUDevice* GPUDeviceDX12::Create()
{
adapter.Index = index;
adapter.MaxFeatureLevel = D3D_FEATURE_LEVEL_12_0;
VALIDATE_DIRECTX_RESULT(tempAdapter->GetDesc(&adapter.Description));
VALIDATE_DIRECTX_CALL(tempAdapter->GetDesc(&adapter.Description));
uint32 outputs = RenderToolsDX::CountAdapterOutputs(tempAdapter);
// Send that info to the log
@@ -137,7 +137,7 @@ GPUDevice* GPUDeviceDX12::Create()
if (tempAdapter && CheckDX12Support(tempAdapter))
{
DXGI_ADAPTER_DESC desc;
VALIDATE_DIRECTX_RESULT(tempAdapter->GetDesc(&desc));
VALIDATE_DIRECTX_CALL(tempAdapter->GetDesc(&desc));
for (int i = 0; i < adapters.Count(); i++)
{
if (adapters[i].Description.AdapterLuid.LowPart == desc.AdapterLuid.LowPart &&
@@ -254,7 +254,7 @@ bool GPUDeviceDX12::Init()
#if PLATFORM_XBOX_SCARLETT
params.DisableDXR = TRUE;
#endif
VALIDATE_DIRECTX_RESULT(D3D12XboxCreateDevice(nullptr, &params, IID_GRAPHICS_PPV_ARGS(&_device)));
VALIDATE_DIRECTX_CALL(D3D12XboxCreateDevice(nullptr, &params, IID_GRAPHICS_PPV_ARGS(&_device)));
// Setup adapter
D3D12XBOX_GPU_HARDWARE_CONFIGURATION hwConfig = {};
@@ -319,12 +319,12 @@ bool GPUDeviceDX12::Init()
}
// Create DirectX device
VALIDATE_DIRECTX_RESULT(D3D12CreateDevice(adapter, D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&_device)));
VALIDATE_DIRECTX_CALL(D3D12CreateDevice(adapter, D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&_device)));
// Debug Layer
#if GPU_ENABLE_DIAGNOSTICS
ComPtr<ID3D12InfoQueue> infoQueue;
VALIDATE_DIRECTX_RESULT(_device->QueryInterface(IID_PPV_ARGS(&infoQueue)));
VALIDATE_DIRECTX_CALL(_device->QueryInterface(IID_PPV_ARGS(&infoQueue)));
if (infoQueue)
{
D3D12_INFO_QUEUE_FILTER filter;
@@ -363,7 +363,7 @@ bool GPUDeviceDX12::Init()
// Spawn some info about the hardware
D3D12_FEATURE_DATA_D3D12_OPTIONS options;
VALIDATE_DIRECTX_RESULT(_device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS, &options, sizeof(options)));
VALIDATE_DIRECTX_CALL(_device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS, &options, sizeof(options)));
LOG(Info, "Tiled Resources Tier: {0}", (int32)options.TiledResourcesTier);
LOG(Info, "Resource Binding Tier: {0}", (int32)options.ResourceBindingTier);
LOG(Info, "Conservative Rasterization Tier: {0}", (int32)options.ConservativeRasterizationTier);
@@ -662,10 +662,10 @@ bool GPUDeviceDX12::Init()
// Serialize
ComPtr<ID3DBlob> signature;
ComPtr<ID3DBlob> error;
VALIDATE_DIRECTX_RESULT(D3D12SerializeRootSignature(&rootSignatureDesc, D3D_ROOT_SIGNATURE_VERSION_1, &signature, &error));
VALIDATE_DIRECTX_CALL(D3D12SerializeRootSignature(&rootSignatureDesc, D3D_ROOT_SIGNATURE_VERSION_1, &signature, &error));
// Create
VALIDATE_DIRECTX_RESULT(_device->CreateRootSignature(0, signature->GetBufferPointer(), signature->GetBufferSize(), IID_PPV_ARGS(&_rootSignature)));
VALIDATE_DIRECTX_CALL(_device->CreateRootSignature(0, signature->GetBufferPointer(), signature->GetBufferSize(), IID_PPV_ARGS(&_rootSignature)));
}
// Upload buffer
@@ -896,14 +896,14 @@ void GPUDeviceDX12::OnResumed()
void GPUDeviceDX12::updateFrameEvents()
{
ComPtr<IDXGIDevice1> dxgiDevice;
VALIDATE_DIRECTX_RESULT(_device->QueryInterface(IID_GRAPHICS_PPV_ARGS(&dxgiDevice)));
VALIDATE_DIRECTX_CALL(_device->QueryInterface(IID_GRAPHICS_PPV_ARGS(&dxgiDevice)));
ComPtr<IDXGIAdapter> dxgiAdapter;
VALIDATE_DIRECTX_RESULT(dxgiDevice->GetAdapter(dxgiAdapter.GetAddressOf()));
VALIDATE_DIRECTX_CALL(dxgiDevice->GetAdapter(dxgiAdapter.GetAddressOf()));
dxgiAdapter->GetDesc(&_adapter->Description);
ComPtr<IDXGIOutput> dxgiOutput;
VALIDATE_DIRECTX_RESULT(dxgiAdapter->EnumOutputs(0, dxgiOutput.GetAddressOf()));
VALIDATE_DIRECTX_RESULT(_device->SetFrameIntervalX(dxgiOutput.Get(), D3D12XBOX_FRAME_INTERVAL_60_HZ, DX12_BACK_BUFFER_COUNT - 1u, D3D12XBOX_FRAME_INTERVAL_FLAG_NONE));
VALIDATE_DIRECTX_RESULT(_device->ScheduleFrameEventX(D3D12XBOX_FRAME_EVENT_ORIGIN, 0U, nullptr, D3D12XBOX_SCHEDULE_FRAME_EVENT_FLAG_NONE));
VALIDATE_DIRECTX_CALL(dxgiAdapter->EnumOutputs(0, dxgiOutput.GetAddressOf()));
VALIDATE_DIRECTX_CALL(_device->SetFrameIntervalX(dxgiOutput.Get(), D3D12XBOX_FRAME_INTERVAL_60_HZ, DX12_BACK_BUFFER_COUNT - 1u, D3D12XBOX_FRAME_INTERVAL_FLAG_NONE));
VALIDATE_DIRECTX_CALL(_device->ScheduleFrameEventX(D3D12XBOX_FRAME_EVENT_ORIGIN, 0U, nullptr, D3D12XBOX_SCHEDULE_FRAME_EVENT_FLAG_NONE));
}
#endif

View File

@@ -66,7 +66,7 @@ void GPUSwapChainDX12::OnReleaseGPU()
// Disable fullscreen mode
if (_swapChain)
{
VALIDATE_DIRECTX_RESULT(_swapChain->SetFullscreenState(false, nullptr));
VALIDATE_DIRECTX_CALL(_swapChain->SetFullscreenState(false, nullptr));
}
#endif
@@ -100,7 +100,7 @@ bool GPUSwapChainDX12::IsFullscreen()
// Get state
BOOL state;
VALIDATE_DIRECTX_RESULT(_swapChain->GetFullscreenState(&state, nullptr));
VALIDATE_DIRECTX_CALL(_swapChain->GetFullscreenState(&state, nullptr));
return state == TRUE;
#endif
}
@@ -221,7 +221,7 @@ bool GPUSwapChainDX12::Resize(int32 width, int32 height)
// Create swap chain (it needs the queue so that it can force a flush on it)
IDXGISwapChain1* swapChain;
auto dxgiFactory = _device->GetDXGIFactory();
VALIDATE_DIRECTX_RESULT(dxgiFactory->CreateSwapChainForHwnd(_device->GetCommandQueueDX12(), _windowHandle, &swapChainDesc, &fullscreenDesc, nullptr, &swapChain));
VALIDATE_DIRECTX_CALL(dxgiFactory->CreateSwapChainForHwnd(_device->GetCommandQueueDX12(), _windowHandle, &swapChainDesc, &fullscreenDesc, nullptr, &swapChain));
_swapChain = static_cast<IDXGISwapChain3*>(swapChain);
ASSERT(_swapChain);
DX_SET_DEBUG_NAME_EX(_swapChain, TEXT("RenderOutput"), TEXT("SwapChain"), TEXT(""));
@@ -229,7 +229,7 @@ bool GPUSwapChainDX12::Resize(int32 width, int32 height)
_backBuffers.Resize(swapChainDesc.BufferCount);
// Disable DXGI changes to the window
VALIDATE_DIRECTX_RESULT(dxgiFactory->MakeWindowAssociation(_windowHandle, DXGI_MWA_NO_ALT_ENTER));
VALIDATE_DIRECTX_CALL(dxgiFactory->MakeWindowAssociation(_windowHandle, DXGI_MWA_NO_ALT_ENTER));
}
else
{
@@ -237,7 +237,7 @@ bool GPUSwapChainDX12::Resize(int32 width, int32 height)
_swapChain->GetDesc1(&swapChainDesc);
VALIDATE_DIRECTX_RESULT(_swapChain->ResizeBuffers(swapChainDesc.BufferCount, width, height, swapChainDesc.Format, swapChainDesc.Flags));
VALIDATE_DIRECTX_CALL(_swapChain->ResizeBuffers(swapChainDesc.BufferCount, width, height, swapChainDesc.Format, swapChainDesc.Flags));
}
_currentFrameIndex = _swapChain->GetCurrentBackBufferIndex();
@@ -316,7 +316,7 @@ void GPUSwapChainDX12::getBackBuffer()
swapChainBufferDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
D3D12_CLEAR_VALUE swapChainOptimizedClearValue = {};
swapChainOptimizedClearValue.Format = swapChainBufferDesc.Format;
VALIDATE_DIRECTX_RESULT(_device->GetDevice()->CreateCommittedResource(
VALIDATE_DIRECTX_CALL(_device->GetDevice()->CreateCommittedResource(
&swapChainHeapProperties,
D3D12_HEAP_FLAG_ALLOW_DISPLAY,
&swapChainBufferDesc,
@@ -324,7 +324,7 @@ void GPUSwapChainDX12::getBackBuffer()
&swapChainOptimizedClearValue,
IID_GRAPHICS_PPV_ARGS(&backbuffer)));
#else
VALIDATE_DIRECTX_RESULT(_swapChain->GetBuffer(i, IID_PPV_ARGS(&backbuffer)));
VALIDATE_DIRECTX_CALL(_swapChain->GetBuffer(i, IID_PPV_ARGS(&backbuffer)));
#endif
DX_SET_DEBUG_NAME_EX(backbuffer, TEXT("RenderOutput"), TEXT("BackBuffer"), i);
_backBuffers[i].Setup(this, backbuffer);
@@ -337,7 +337,7 @@ void GPUSwapChainDX12::Begin(RenderTask* task)
{
// Wait until frame start is signaled
_framePipelineToken = D3D12XBOX_FRAME_PIPELINE_TOKEN_NULL;
VALIDATE_DIRECTX_RESULT(_device->GetDevice()->WaitFrameEventX(D3D12XBOX_FRAME_EVENT_ORIGIN, INFINITE, nullptr, D3D12XBOX_WAIT_FRAME_EVENT_FLAG_NONE, &_framePipelineToken));
VALIDATE_DIRECTX_CALL(_device->GetDevice()->WaitFrameEventX(D3D12XBOX_FRAME_EVENT_ORIGIN, INFINITE, nullptr, D3D12XBOX_WAIT_FRAME_EVENT_FLAG_NONE, &_framePipelineToken));
GPUSwapChain::Begin(task);
}
@@ -366,7 +366,7 @@ void GPUSwapChainDX12::Present(bool vsync)
planeParameters.Token = _framePipelineToken;
planeParameters.ResourceCount = 1;
planeParameters.ppResources = &backBuffer;
VALIDATE_DIRECTX_RESULT(_device->GetCommandQueueDX12()->PresentX(1, &planeParameters, nullptr));
VALIDATE_DIRECTX_CALL(_device->GetCommandQueueDX12()->PresentX(1, &planeParameters, nullptr));
// Base
GPUSwapChain::Present(vsync);

View File

@@ -113,7 +113,7 @@ bool GPUTextureDX12::OnInit()
resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
resourceDesc.Flags = D3D12_RESOURCE_FLAG_NONE;
auto result = device->CreateCommittedResource(&heapProperties, D3D12_HEAP_FLAG_NONE, &resourceDesc, D3D12_RESOURCE_STATE_COPY_DEST, nullptr, IID_PPV_ARGS(&resource));
LOG_DIRECTX_RESULT_WITH_RETURN(result);
LOG_DIRECTX_RESULT_WITH_RETURN(result, true);
initResource(resource, D3D12_RESOURCE_STATE_COPY_DEST, 1);
DX_SET_DEBUG_NAME(_resource, GetName());
_memoryUsage = totalSize;
@@ -184,7 +184,7 @@ bool GPUTextureDX12::OnInit()
// Create texture
auto result = device->CreateCommittedResource(&heapProperties, D3D12_HEAP_FLAG_NONE, &resourceDesc, initialState, clearValuePtr, IID_PPV_ARGS(&resource));
LOG_DIRECTX_RESULT_WITH_RETURN(result);
LOG_DIRECTX_RESULT_WITH_RETURN(result, true);
// Set state
bool isRead = useSRV || useUAV;

View File

@@ -37,7 +37,7 @@ void GPUTimerQueryDX12::End()
heap.EndQuery(context, _end);
const auto queue = _device->GetCommandQueue()->GetCommandQueue();
VALIDATE_DIRECTX_RESULT(queue->GetTimestampFrequency(&_gpuFrequency));
VALIDATE_DIRECTX_CALL(queue->GetTimestampFrequency(&_gpuFrequency));
_endCalled = true;
}

View File

@@ -41,7 +41,7 @@ bool QueryHeapDX12::Init()
heapDesc.Count = _queryHeapCount;
heapDesc.NodeMask = 0;
HRESULT result = _device->GetDevice()->CreateQueryHeap(&heapDesc, IID_PPV_ARGS(&_queryHeap));
LOG_DIRECTX_RESULT_WITH_RETURN(result);
LOG_DIRECTX_RESULT_WITH_RETURN(result, true);
DX_SET_DEBUG_NAME(_queryHeap, "Query Heap");
// Create the result buffer
@@ -64,7 +64,7 @@ bool QueryHeapDX12::Init()
resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
resourceDesc.Flags = D3D12_RESOURCE_FLAG_NONE;
result = _device->GetDevice()->CreateCommittedResource(&heapProperties, D3D12_HEAP_FLAG_NONE, &resourceDesc, D3D12_RESOURCE_STATE_COPY_DEST, nullptr, IID_PPV_ARGS(&_resultBuffer));
LOG_DIRECTX_RESULT_WITH_RETURN(result);
LOG_DIRECTX_RESULT_WITH_RETURN(result, true);
DX_SET_DEBUG_NAME(_resultBuffer, "Query Heap Result Buffer");
// Start out with an open query batch
@@ -181,7 +181,7 @@ void* QueryHeapDX12::ResolveQuery(ElementHandle& handle)
range.Begin = batch.Start * _resultSize;
range.End = range.Begin + batch.Count * _resultSize;
void* mapped = nullptr;
VALIDATE_DIRECTX_RESULT(_resultBuffer->Map(0, &range, &mapped));
VALIDATE_DIRECTX_CALL(_resultBuffer->Map(0, &range, &mapped));
// Copy the results data
Platform::MemoryCopy(_resultData.Get() + range.Begin, (byte*)mapped + range.Begin, batch.Count * _resultSize);

View File

@@ -229,7 +229,7 @@ UploadBufferPageDX12::UploadBufferPageDX12(GPUDeviceDX12* device, uint64 size)
resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
resourceDesc.Flags = D3D12_RESOURCE_FLAG_NONE;
ID3D12Resource* resource;
VALIDATE_DIRECTX_RESULT(_device->GetDevice()->CreateCommittedResource(&heapProperties, D3D12_HEAP_FLAG_NONE, &resourceDesc, D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&resource)));
VALIDATE_DIRECTX_CALL(_device->GetDevice()->CreateCommittedResource(&heapProperties, D3D12_HEAP_FLAG_NONE, &resourceDesc, D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&resource)));
// Set state
initResource(resource, D3D12_RESOURCE_STATE_GENERIC_READ, 1);
@@ -238,7 +238,7 @@ UploadBufferPageDX12::UploadBufferPageDX12(GPUDeviceDX12* device, uint64 size)
GPUAddress = _resource->GetGPUVirtualAddress();
// Map buffer
VALIDATE_DIRECTX_RESULT(_resource->Map(0, nullptr, &CPUAddress));
VALIDATE_DIRECTX_CALL(_resource->Map(0, nullptr, &CPUAddress));
}
void UploadBufferPageDX12::OnReleaseGPU()

View File

@@ -272,15 +272,15 @@ namespace RenderToolsDX
#if GPU_ENABLE_ASSERTION
// DirectX results validation
#define VALIDATE_DIRECTX_RESULT(x) { HRESULT result = x; if (FAILED(result)) RenderToolsDX::ValidateD3DResult(result, __FILE__, __LINE__); }
#define VALIDATE_DIRECTX_CALL(x) { HRESULT result = x; if (FAILED(result)) RenderToolsDX::ValidateD3DResult(result, __FILE__, __LINE__); }
#define LOG_DIRECTX_RESULT(result) if (FAILED(result)) RenderToolsDX::LogD3DResult(result, __FILE__, __LINE__)
#define LOG_DIRECTX_RESULT_WITH_RETURN(result) if (FAILED(result)) { RenderToolsDX::LogD3DResult(result, __FILE__, __LINE__); return true; }
#define LOG_DIRECTX_RESULT_WITH_RETURN(result, returnValue) if (FAILED(result)) { RenderToolsDX::LogD3DResult(result, __FILE__, __LINE__); return returnValue; }
#else
#define VALIDATE_DIRECTX_RESULT(x) x
#define VALIDATE_DIRECTX_CALL(x) x
#define LOG_DIRECTX_RESULT(result) if(FAILED(result)) RenderToolsDX::LogD3DResult(result)
#define LOG_DIRECTX_RESULT_WITH_RETURN(result) if(FAILED(result)) { RenderToolsDX::LogD3DResult(result); return true; }
#define LOG_DIRECTX_RESULT_WITH_RETURN(result, returnValue) if(FAILED(result)) { RenderToolsDX::LogD3DResult(result); return returnValue; }
#endif

View File

@@ -100,6 +100,7 @@ void Skybox::ApplySky(GPUContext* context, RenderContext& renderContext, const M
Platform::MemoryClear(&drawCall, sizeof(DrawCall));
drawCall.World = world;
drawCall.ObjectPosition = drawCall.World.GetTranslation();
drawCall.ObjectRadius = _sphere.Radius;
drawCall.Surface.GeometrySize = _box.GetSize();
drawCall.WorldDeterminantSign = Math::FloatSelect(world.RotDeterminant(), 1, -1);
drawCall.PerInstanceRandom = GetPerInstanceRandom();

View File

@@ -405,6 +405,7 @@ void SplineModel::Draw(RenderContext& renderContext)
const Transform splineTransform = GetTransform();
renderContext.View.GetWorldMatrix(splineTransform, drawCall.World);
drawCall.ObjectPosition = drawCall.World.GetTranslation() + drawCall.Deformable.LocalMatrix.GetTranslation();
drawCall.ObjectRadius = _sphere.Radius; // TODO: use radius for the spline chunk rather than whole spline
const float worldDeterminantSign = drawCall.World.RotDeterminant() * drawCall.Deformable.LocalMatrix.RotDeterminant();
for (int32 segment = 0; segment < _instances.Count(); segment++)
{

View File

@@ -32,7 +32,7 @@ void SceneTicking::TickData::RemoveTick(void* callee)
{
for (int32 i = 0; i < Ticks.Count(); i++)
{
if (Ticks[i].Callee == callee)
if (Ticks.Get()[i].Callee == callee)
{
Ticks.RemoveAt(i);
break;
@@ -45,7 +45,7 @@ void SceneTicking::TickData::Tick()
TickScripts(Scripts);
for (int32 i = 0; i < Ticks.Count(); i++)
Ticks[i].Call();
Ticks.Get()[i].Call();
}
#if USE_EDITOR
@@ -54,7 +54,7 @@ void SceneTicking::TickData::RemoveTickExecuteInEditor(void* callee)
{
for (int32 i = 0; i < TicksExecuteInEditor.Count(); i++)
{
if (TicksExecuteInEditor[i].Callee == callee)
if (TicksExecuteInEditor.Get()[i].Callee == callee)
{
TicksExecuteInEditor.RemoveAt(i);
break;
@@ -67,7 +67,7 @@ void SceneTicking::TickData::TickExecuteInEditor()
TickScripts(ScriptsExecuteInEditor);
for (int32 i = 0; i < TicksExecuteInEditor.Count(); i++)
TicksExecuteInEditor[i].Call();
TicksExecuteInEditor.Get()[i].Call();
}
#endif

View File

@@ -21,6 +21,7 @@ namespace
FORCE_INLINE void InitFilter(dtQueryFilter& filter)
{
Platform::MemoryCopy(filter.m_areaCost, NavMeshRuntime::NavAreasCosts, sizeof(NavMeshRuntime::NavAreasCosts));
static_assert(sizeof(dtQueryFilter::m_areaCost) == sizeof(NavMeshRuntime::NavAreasCosts), "Invalid navmesh area cost list.");
}
}

View File

@@ -938,7 +938,8 @@ void Particles::DrawParticles(RenderContext& renderContext, ParticleEffect* effe
// Setup a draw call common data
DrawCall drawCall;
drawCall.PerInstanceRandom = effect->GetPerInstanceRandom();
drawCall.ObjectPosition = effect->GetPosition();
drawCall.ObjectPosition = effect->GetSphere().Center - view.Origin;
drawCall.ObjectRadius = effect->GetSphere().Radius;
// Draw all emitters
for (int32 emitterIndex = 0; emitterIndex < effect->Instance.Emitters.Count(); emitterIndex++)

View File

@@ -70,6 +70,53 @@ CFStringRef AppleUtils::ToString(const StringView& str)
return CFStringCreateWithBytes(nullptr, (const UInt8*)str.GetText(), str.Length() * sizeof(Char), kCFStringEncodingUTF16LE, false);
}
NSString* AppleUtils::ToNSString(const StringView& str)
{
NSString* ret = !str.IsEmpty() ? [[NSString alloc] initWithBytes: (const UInt8*)str.Get() length: str.Length() * sizeof(Char) encoding: NSUTF16LittleEndianStringEncoding] : nil;
return ret ? ret : @"";
}
NSString* AppleUtils::ToNSString(const char* string)
{
NSString* ret = string ? [NSString stringWithUTF8String: string] : nil;
return ret ? ret : @"";
}
NSArray* AppleUtils::ParseArguments(NSString* argsString) {
NSMutableArray *argsArray = [NSMutableArray array];
NSMutableString *currentArg = [NSMutableString string];
BOOL insideQuotes = NO;
for (NSInteger i = 0; i < argsString.length; ++i) {
unichar c = [argsString characterAtIndex:i];
if (c == '\"') {
if (insideQuotes) {
[argsArray addObject:[currentArg copy]];
[currentArg setString:@""];
insideQuotes = NO;
} else {
insideQuotes = YES;
}
} else if (c == ' ' && !insideQuotes) {
if (currentArg.length > 0) {
[argsArray addObject:[currentArg copy]];
[currentArg setString:@""];
}
} else {
[currentArg appendFormat:@"%C", c];
}
}
if (currentArg.length > 0) {
[argsArray addObject:[currentArg copy]];
}
return [argsArray copy];
}
typedef uint16_t offset_t;
#define align_mem_up(num, align) (((num) + ((align) - 1)) & ~((align) - 1))

View File

@@ -13,6 +13,9 @@ class AppleUtils
public:
static String ToString(CFStringRef str);
static CFStringRef ToString(const StringView& str);
static NSString* ToNSString(const StringView& str);
static NSString* ToNSString(const char* string);
static NSArray* ParseArguments(NSString* argsString);
#if PLATFORM_MAC
static Float2 PosToCoca(const Float2& pos);
static Float2 CocaToPos(const Float2& pos);

View File

@@ -23,6 +23,7 @@ namespace FlaxEngine
AllowDragAndDrop = true,
IsRegularWindow = true,
HasSizingFrame = true,
ShowAfterFirstPaint = true,
};
}
}

View File

@@ -131,7 +131,7 @@ DECLARE_SCRIPTING_TYPE_MINIMAL(CreateWindowSettings);
/// <summary>
/// Enable/disable window auto-show after the first paint.
/// </summary>
API_FIELD() bool ShowAfterFirstPaint = false;
API_FIELD() bool ShowAfterFirstPaint = true;
/// <summary>
/// The custom data (platform dependant).

View File

@@ -6,6 +6,8 @@
#include "Windows/WindowsFileSystemWatcher.h"
#elif PLATFORM_LINUX
#include "Linux/LinuxFileSystemWatcher.h"
#elif PLATFORM_MAC
#include "Mac/MacFileSystemWatcher.h"
#else
#include "Base/FileSystemWatcherBase.h"
#endif

View File

@@ -136,7 +136,7 @@ bool LinuxFileSystem::ShowFileExplorer(const StringView& path)
{
const StringAsANSI<> pathAnsi(*path, path.Length());
char cmd[2048];
sprintf(cmd, "nautilus %s &", pathAnsi.Get());
sprintf(cmd, "xdg-open %s &", pathAnsi.Get());
system(cmd);
return false;
}

View File

@@ -132,7 +132,7 @@ bool MacFileSystem::ShowBrowseFolderDialog(Window* parentWindow, const StringVie
bool MacFileSystem::ShowFileExplorer(const StringView& path)
{
return Platform::StartProcess(TEXT("open"), String::Format(TEXT("\"{0}\""), path), StringView::Empty) != 0;
return [[NSWorkspace sharedWorkspace] selectFile: AppleUtils::ToNSString(FileSystem::ConvertRelativePathToAbsolute(path)) inFileViewerRootedAtPath: @""];
}
#endif

View File

@@ -0,0 +1,100 @@
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
#if PLATFORM_MAC
#include "MacFileSystemWatcher.h"
#include "Engine/Platform/Apple/AppleUtils.h"
#include "Engine/Platform/CriticalSection.h"
#include "Engine/Platform/Thread.h"
#include "Engine/Threading/ThreadSpawner.h"
#include "Engine/Core/Collections/Array.h"
#include "Engine/Core/Types/StringView.h"
void DirectoryWatchCallback( ConstFSEventStreamRef StreamRef, void* FileWatcherPtr, size_t EventCount, void* EventPaths, const FSEventStreamEventFlags EventFlags[], const FSEventStreamEventId EventIDs[] )
{
MacFileSystemWatcher* macFileSystemWatcher = (MacFileSystemWatcher*)FileWatcherPtr;
if (macFileSystemWatcher)
{
CFArrayRef EventPathArray = (CFArrayRef)EventPaths;
for( size_t EventIndex = 0; EventIndex < EventCount; ++EventIndex )
{
const FSEventStreamEventFlags Flags = EventFlags[EventIndex];
if( !(Flags & kFSEventStreamEventFlagItemIsFile) && !(Flags & kFSEventStreamEventFlagItemIsDir) )
{
// events about symlinks don't concern us
continue;
}
auto action = FileSystemAction::Unknown;
const bool added = ( Flags & kFSEventStreamEventFlagItemCreated );
const bool renamed = ( Flags & kFSEventStreamEventFlagItemRenamed );
const bool modified = ( Flags & kFSEventStreamEventFlagItemModified );
const bool removed = ( Flags & kFSEventStreamEventFlagItemRemoved );
if (added)
{
action = FileSystemAction::Create;
}
if (renamed || modified)
{
action = FileSystemAction::Delete;
}
if (removed)
{
action = FileSystemAction::Modify;
}
const String resolvedPath = AppleUtils::ToString((CFStringRef)CFArrayGetValueAtIndex(EventPathArray,EventIndex));
macFileSystemWatcher->OnEvent(resolvedPath, action);
}
}
}
MacFileSystemWatcher::MacFileSystemWatcher(const String& directory, bool withSubDirs)
: FileSystemWatcherBase(directory, withSubDirs)
{
CFStringRef FullPathMac = AppleUtils::ToString(StringView(directory));
CFArrayRef PathsToWatch = CFArrayCreate(NULL, (const void**)&FullPathMac, 1, NULL);
CFAbsoluteTime Latency = 0.2;
FSEventStreamContext Context;
Context.version = 0;
Context.info = this;
Context.retain = NULL;
Context.release = NULL;
Context.copyDescription = NULL;
EventStream = FSEventStreamCreate( NULL,
&DirectoryWatchCallback,
&Context,
PathsToWatch,
kFSEventStreamEventIdSinceNow,
Latency,
kFSEventStreamCreateFlagUseCFTypes | kFSEventStreamCreateFlagNoDefer | kFSEventStreamCreateFlagFileEvents
);
CFRelease(PathsToWatch);
CFRelease(FullPathMac);
FSEventStreamScheduleWithRunLoop( EventStream, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode );
FSEventStreamStart( EventStream );
IsRunning = true;
}
MacFileSystemWatcher::~MacFileSystemWatcher()
{
if (IsRunning)
{
FSEventStreamStop(EventStream);
FSEventStreamUnscheduleFromRunLoop(EventStream, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
FSEventStreamInvalidate(EventStream);
FSEventStreamRelease(EventStream);
}
}
#endif

View File

@@ -0,0 +1,39 @@
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
#pragma once
#if PLATFORM_MAC
#include "Engine/Platform/Base/FileSystemWatcherBase.h"
#include <CoreServices/CoreServices.h>
/// <summary>
/// Mac platform implementation of the file system watching object.
/// </summary>
class FLAXENGINE_API MacFileSystemWatcher : public FileSystemWatcherBase
{
public:
/// <summary>
/// Initializes a new instance of the <see cref="MacFileSystemWatcher"/> class.
/// </summary>
/// <param name="directory">The directory to watch.</param>
/// <param name="withSubDirs">True if monitor the directory tree rooted at the specified directory or just a given directory.</param>
MacFileSystemWatcher(const String& directory, bool withSubDirs);
/// <summary>
/// Finalizes an instance of the <see cref="MacFileSystemWatcher"/> class.
/// </summary>
~MacFileSystemWatcher();
public:
private:
FSEventStreamRef EventStream;
bool IsRunning;
};
#endif

View File

@@ -324,13 +324,16 @@ void MacPlatform::BeforeRun()
void MacPlatform::Tick()
{
// Process system events
while (true)
NSEvent* event = nil;
do
{
NSEvent* event = [NSApp nextEventMatchingMask:NSEventMaskAny untilDate:[NSDate distantPast] inMode:NSDefaultRunLoopMode dequeue:YES];
if (event == nil)
break;
[NSApp sendEvent:event];
}
event = [NSApp nextEventMatchingMask: NSEventMaskAny untilDate: nil inMode: NSDefaultRunLoopMode dequeue: YES];
if (event)
{
[NSApp sendEvent:event];
}
} while(event);
ApplePlatform::Tick();
}
@@ -429,13 +432,6 @@ Window* MacPlatform::CreateWindow(const CreateWindowSettings& settings)
int32 MacPlatform::CreateProcess(CreateProcessSettings& settings)
{
LOG(Info, "Command: {0} {1}", settings.FileName, settings.Arguments);
String cwd;
if (settings.WorkingDirectory.HasChars())
{
LOG(Info, "Working directory: {0}", settings.WorkingDirectory);
cwd = Platform::GetWorkingDirectory();
Platform::SetWorkingDirectory(settings.WorkingDirectory);
}
const bool captureStdOut = settings.LogOutput || settings.SaveOutput;
// Special case if filename points to the app package (use actual executable)
@@ -462,44 +458,81 @@ int32 MacPlatform::CreateProcess(CreateProcessSettings& settings)
}
}
const String cmdLine = exePath + TEXT(" ") + settings.Arguments;
const StringAsANSI<> cmdLineAnsi(*cmdLine, cmdLine.Length());
FILE* pipe = popen(cmdLineAnsi.Get(), "r");
if (cwd.Length() != 0)
{
Platform::SetWorkingDirectory(cwd);
}
if (!pipe)
{
LOG(Warning, "Failed to start process, errno={}", errno);
return -1;
}
// TODO: environment
NSTask *task = [[NSTask alloc] init];
task.launchPath = AppleUtils::ToNSString(exePath);
task.arguments = AppleUtils::ParseArguments(AppleUtils::ToNSString(settings.Arguments));
if (settings.WorkingDirectory.HasChars())
task.currentDirectoryPath = AppleUtils::ToNSString(settings.WorkingDirectory);
int32 returnCode = 0;
if (settings.WaitForEnd)
{
id<NSObject> outputObserver = nil;
if (captureStdOut)
{
char lineBuffer[1024];
while (fgets(lineBuffer, sizeof(lineBuffer), pipe) != NULL)
NSPipe *stdoutPipe = [NSPipe pipe];
[task setStandardOutput:stdoutPipe];
outputObserver = [[NSNotificationCenter defaultCenter]
addObserverForName: NSFileHandleDataAvailableNotification
object: [stdoutPipe fileHandleForReading]
queue: nil
usingBlock:^(NSNotification* notification)
{
char* p = lineBuffer + strlen(lineBuffer) - 1;
if (*p == '\n') *p = 0;
String line(lineBuffer);
if (settings.SaveOutput)
settings.Output.Add(line.Get(), line.Length());
if (settings.LogOutput)
Log::Logger::Write(LogType::Info, line);
NSData* data = [stdoutPipe fileHandleForReading].availableData;
if (data.length)
{
String line((const char*)data.bytes, data.length);
if (settings.SaveOutput)
settings.Output.Add(line.Get(), line.Length());
if (settings.LogOutput)
{
StringView lineView(line);
if (line[line.Length() - 1] == '\n')
lineView = StringView(line.Get(), line.Length() - 1);
Log::Logger::Write(LogType::Info, lineView);
}
[[stdoutPipe fileHandleForReading] waitForDataInBackgroundAndNotify];
}
}
];
[[stdoutPipe fileHandleForReading] waitForDataInBackgroundAndNotify];
}
else
String exception;
@try
{
while (!feof(pipe))
{
sleep(1);
}
[task launch];
[task waitUntilExit];
returnCode = [task terminationStatus];
}
@catch (NSException* e)
{
exception = e.reason.UTF8String;
}
if (!exception.IsEmpty())
{
LOG(Error, "Failed to run command {0} {1} with error {2}", settings.FileName, settings.Arguments, exception);
returnCode = -1;
}
}
else
{
String exception;
@try
{
[task launch];
}
@catch (NSException* e)
{
exception = e.reason.UTF8String;
}
if (!exception.IsEmpty())
{
LOG(Error, "Failed to run command {0} {1} with error {2}", settings.FileName, settings.Arguments, exception);
returnCode = -1;
}
}

View File

@@ -237,8 +237,8 @@ class UnixConditionVariable;
typedef UnixConditionVariable ConditionVariable;
class MacFileSystem;
typedef MacFileSystem FileSystem;
class FileSystemWatcherBase;
typedef FileSystemWatcherBase FileSystemWatcher;
class MacFileSystemWatcher;
typedef MacFileSystemWatcher FileSystemWatcher;
class UnixFile;
typedef UnixFile File;
class MacPlatform;

View File

@@ -258,6 +258,11 @@ struct DrawCall
/// </summary>
Float3 ObjectPosition;
/// <summary>
/// Object bounding sphere radius that contains it whole (sphere at ObjectPosition).
/// </summary>
float ObjectRadius;
/// <summary>
/// The world matrix determinant sign (used for geometry that is two sided or has inverse scale - needs to flip normal vectors and change triangles culling).
/// </summary>

View File

@@ -464,6 +464,7 @@ void GBufferPass::DrawDecals(RenderContext& renderContext, GPUTextureView* light
transform.Scale *= decal->GetSize();
renderContext.View.GetWorldMatrix(transform, drawCall.World);
drawCall.ObjectPosition = drawCall.World.GetTranslation();
drawCall.ObjectRadius = decal->GetSphere().Radius;
context->ResetRenderTarget();

View File

@@ -26,7 +26,7 @@ PACK_STRUCT(struct HistogramData {
GPUBuffer* HistogramPass::Render(RenderContext& renderContext, GPUTexture* colorBuffer)
{
auto device = GPUDevice::Instance;
auto context = device->GetMainContext();;
auto context = device->GetMainContext();
if (checkIfSkipPass() || !_isSupported)
return nullptr;

View File

@@ -855,6 +855,7 @@ DRAW:
{
auto& batch = BatchedDrawCalls.Get()[list.PreBatchedDrawCalls.Get()[i]];
auto drawCall = batch.DrawCall;
drawCall.ObjectRadius = 0.0f;
bindParams.FirstDrawCall = &drawCall;
const auto* instancesData = batch.Instances.Get();

View File

@@ -1009,12 +1009,36 @@ void ManagedBinaryModule::InitType(MClass* mclass)
}
if (baseType.Module == this)
InitType(baseClass); // Ensure base is initialized before
baseType.Module->TypeNameToTypeIndex.TryGet(baseClass->GetFullName(), *(int32*)&baseType.TypeIndex);
// So we must special case this flow of a generic class of which its possible the generic base class is not in the same module
if (baseType.TypeIndex == -1 && baseClass->IsGeneric())
{
auto genericNameIndex = baseClass->GetFullName().FindLast('`');
// we add 2 because of the way generic names work its `N
auto genericClassName = baseClass->GetFullName().Substring(0, genericNameIndex + 2);
// We check for the generic class name instead of the baseclass fullname
baseType.Module->TypeNameToTypeIndex.TryGet(genericClassName, *(int32*)&baseType.TypeIndex);
}
if (!baseType)
{
LOG(Error, "Missing base class for managed class {0} from assembly {1}.", String(typeName), Assembly->ToString());
return;
}
if (baseType.TypeIndex == -1)
{
if (baseType.Module)
LOG(Error, "Missing base class for managed class {0} from assembly {1}.", String(baseClass->GetFullName()), baseType.Module->GetName().ToString());
else
// Not sure this can happen but never hurts to account for it
LOG(Error, "Missing base class for managed class {0} from unknown assembly.", String(baseClass->GetFullName()));
return;
}
ScriptingTypeHandle nativeType = baseType;
while (true)
{

View File

@@ -85,6 +85,7 @@ public:
static MClass* GetClass(MClass* elementKlass);
static int32 GetLength(const MArray* obj);
static void* GetAddress(const MArray* obj);
static MArray* Unbox(MObject* obj);
template<typename T>
FORCE_INLINE static T* GetAddress(const MArray* obj)

View File

@@ -363,11 +363,12 @@ struct MConverter<Array<T>>
void Unbox(Array<T>& result, MObject* data)
{
const int32 length = data ? MCore::Array::GetLength((MArray*)data) : 0;
MArray* array = MCore::Array::Unbox(data);
const int32 length = array ? MCore::Array::GetLength(array) : 0;
result.Resize(length);
MConverter<T> converter;
Span<T> resultSpan(result.Get(), length);
converter.ToNativeArray(resultSpan, (MArray*)data);
converter.ToNativeArray(resultSpan, array);
}
};

View File

@@ -408,6 +408,12 @@ void* MCore::Array::GetAddress(const MArray* obj)
return CallStaticMethod<void*, void*>(GetArrayPointerPtr, (void*)obj);
}
MArray* MCore::Array::Unbox(MObject* obj)
{
static void* GetArrayPtr = GetStaticMethodPointer(TEXT("GetArray"));
return (MArray*)CallStaticMethod<void*, void*>(GetArrayPtr, (void*)obj);
}
MGCHandle MCore::GCHandle::New(MObject* obj, bool pinned)
{
ASSERT(obj);
@@ -697,13 +703,10 @@ bool MAssembly::LoadImage(const String& assemblyPath, const StringView& nativePa
{
// TODO: Use new hostfxr delegate load_assembly_bytes? (.NET 8+)
// Open .Net assembly
const StringAnsi assemblyPathAnsi = assemblyPath.ToStringAnsi();
const char* name;
const char* fullname;
const char* name = nullptr;
const char* fullname = nullptr;
static void* LoadAssemblyImagePtr = GetStaticMethodPointer(TEXT("LoadAssemblyImage"));
_handle = CallStaticMethod<void*, const char*, const char**, const char**>(LoadAssemblyImagePtr, assemblyPathAnsi.Get(), &name, &fullname);
_name = name;
_fullname = fullname;
_handle = CallStaticMethod<void*, const Char*, const char**, const char**>(LoadAssemblyImagePtr, assemblyPath.Get(), &name, &fullname);
MCore::GC::FreeMemory((void*)name);
MCore::GC::FreeMemory((void*)fullname);
if (_handle == nullptr)
@@ -711,6 +714,8 @@ bool MAssembly::LoadImage(const String& assemblyPath, const StringView& nativePa
Log::CLRInnerException(TEXT(".NET assembly image is invalid at ") + assemblyPath);
return true;
}
_name = name;
_fullname = fullname;
CachedAssemblyHandles.Add(_handle, this);
// Provide new path of hot-reloaded native library path for managed DllImport
@@ -719,6 +724,13 @@ bool MAssembly::LoadImage(const String& assemblyPath, const StringView& nativePa
StringAnsi nativeName = _name.EndsWith(".CSharp") ? StringAnsi(_name.Get(), _name.Length() - 7) : StringAnsi(_name);
RegisterNativeLibrary(nativeName.Get(), StringAnsi(nativePath).Get());
}
#if USE_EDITOR
// Register the editor module location for Assembly resolver
else
{
RegisterNativeLibrary(_name.Get(), StringAnsi(assemblyPath).Get());
}
#endif
_hasCachedClasses = false;
_assemblyPath = assemblyPath;
@@ -898,7 +910,6 @@ const Array<MMethod*>& MClass::GetMethods() const
NativeMethodDefinitions& definition = methods[i];
MMethod* method = New<MMethod>(const_cast<MClass*>(this), StringAnsi(definition.name), definition.handle, definition.numParameters, definition.methodAttributes);
_methods.Add(method);
MCore::GC::FreeMemory((void*)definition.name);
}
MCore::GC::FreeMemory(methods);
@@ -932,7 +943,6 @@ const Array<MField*>& MClass::GetFields() const
NativeFieldDefinitions& definition = fields[i];
MField* field = New<MField>(const_cast<MClass*>(this), definition.fieldHandle, definition.name, definition.fieldType, definition.fieldAttributes);
_fields.Add(field);
MCore::GC::FreeMemory((void*)definition.name);
}
MCore::GC::FreeMemory(fields);
@@ -977,7 +987,6 @@ const Array<MProperty*>& MClass::GetProperties() const
const NativePropertyDefinitions& definition = foundProperties[i];
MProperty* property = New<MProperty>(const_cast<MClass*>(this), definition.name, definition.getterHandle, definition.setterHandle, definition.getterAttributes, definition.setterAttributes);
_properties.Add(property);
MCore::GC::FreeMemory((void*)definition.name);
}
MCore::GC::FreeMemory(foundProperties);
@@ -1541,7 +1550,16 @@ bool InitHostfxr()
get_hostfxr_params.size = sizeof(hostfxr_initialize_parameters);
get_hostfxr_params.assembly_path = libraryPath.Get();
#if PLATFORM_MAC
get_hostfxr_params.dotnet_root = "/usr/local/share/dotnet";
::String macOSDotnetRoot = TEXT("/usr/local/share/dotnet");
#if defined(__x86_64) || defined(__x86_64__) || defined(__amd64__) || defined(_M_X64)
// When emulating x64 on arm
const ::String dotnetRootEmulated = macOSDotnetRoot / TEXT("x64");
if (FileSystem::FileExists(dotnetRootEmulated / TEXT("dotnet"))) {
macOSDotnetRoot = dotnetRootEmulated;
}
#endif
const FLAX_CORECLR_STRING& finalDotnetRootPath = FLAX_CORECLR_STRING(macOSDotnetRoot);
get_hostfxr_params.dotnet_root = finalDotnetRootPath.Get();
#else
get_hostfxr_params.dotnet_root = nullptr;
#endif
@@ -1588,7 +1606,10 @@ bool InitHostfxr()
void* hostfxr = Platform::LoadLibrary(path.Get());
if (hostfxr == nullptr)
{
LOG(Fatal, "Failed to load hostfxr library ({0})", path);
if (FileSystem::FileExists(path))
LOG(Fatal, "Failed to load hostfxr library, possible platform/architecture mismatch with the library. See log for more information. ({0})", path);
else
LOG(Fatal, "Failed to load hostfxr library ({0})", path);
return true;
}
hostfxr_initialize_for_runtime_config = (hostfxr_initialize_for_runtime_config_fn)Platform::GetProcAddress(hostfxr, "hostfxr_initialize_for_runtime_config");
@@ -1627,7 +1648,28 @@ bool InitHostfxr()
if (rc != 0 || handle == nullptr)
{
hostfxr_close(handle);
LOG(Fatal, "Failed to initialize hostfxr: {0:x} ({1})", (unsigned int)rc, String(init_params.dotnet_root));
if (rc == 0x80008096) // FrameworkMissingFailure
{
String platformStr;
switch (PLATFORM_TYPE)
{
case PlatformType::Windows:
case PlatformType::UWP:
platformStr = PLATFORM_64BITS ? "Windows x64" : "Windows x86";
break;
case PlatformType::Linux:
platformStr = PLATFORM_ARCH_ARM64 ? "Linux Arm64" : PLATFORM_ARCH_ARM ? "Linux Arm32" : PLATFORM_64BITS ? "Linux x64" : "Linux x86";
break;
case PlatformType::Mac:
platformStr = PLATFORM_ARCH_ARM || PLATFORM_ARCH_ARM64 ? "macOS Arm64" : PLATFORM_64BITS ? "macOS x64" : "macOS x86";
break;
default:;
platformStr = "";
}
LOG(Fatal, "Failed to resolve compatible .NET runtime version in '{0}'. Make sure the correct platform version for runtime is installed ({1})", platformStr, String(init_params.dotnet_root));
}
else
LOG(Fatal, "Failed to initialize hostfxr: {0:x} ({1})", (unsigned int)rc, String(init_params.dotnet_root));
return true;
}

View File

@@ -804,6 +804,11 @@ void* MCore::Array::GetAddress(const MArray* obj)
return mono_array_addr_with_size((MonoArray*)obj, 0, 0);
}
MArray* MCore::Array::Unbox(MObject* obj)
{
return (MArray*)obj;
}
MGCHandle MCore::GCHandle::New(MObject* obj, bool pinned)
{
return mono_gchandle_new(obj, pinned);

View File

@@ -141,6 +141,11 @@ void* MCore::Array::GetAddress(const MArray* obj)
return nullptr;
}
MArray* MCore::Array::Unbox(MObject* obj)
{
return nullptr;
}
MGCHandle MCore::GCHandle::New(MObject* obj, bool pinned)
{
return (MGCHandle)(uintptr)obj;

View File

@@ -45,7 +45,7 @@ bool TerrainChunk::PrepareDraw(const RenderContext& renderContext)
// Calculate chunk distance to view
const auto lodView = (renderContext.LodProxyView ? renderContext.LodProxyView : &renderContext.View);
const float distance = Float3::Distance(_boundsCenter - lodView->Origin, lodView->Position);
const float distance = Float3::Distance(_sphere.Center - lodView->Origin, lodView->Position);
lod = (int32)Math::Pow(distance / chunkEdgeSize, lodDistribution);
lod += lodBias;
@@ -88,6 +88,7 @@ void TerrainChunk::Draw(const RenderContext& renderContext) const
drawCall.Material = _cachedDrawMaterial;
renderContext.View.GetWorldMatrix(_transform, drawCall.World);
drawCall.ObjectPosition = drawCall.World.GetTranslation();
drawCall.ObjectRadius = _sphere.Radius;
drawCall.Terrain.Patch = _patch;
drawCall.Terrain.HeightmapUVScaleBias = _heightmapUVScaleBias;
drawCall.Terrain.OffsetUV = Vector2((float)(_patch->_x * TerrainPatch::CHUNKS_COUNT_EDGE + _x), (float)(_patch->_z * TerrainPatch::CHUNKS_COUNT_EDGE + _z));
@@ -145,6 +146,7 @@ void TerrainChunk::Draw(const RenderContext& renderContext, MaterialBase* materi
drawCall.Material = material;
renderContext.View.GetWorldMatrix(_transform, drawCall.World);
drawCall.ObjectPosition = drawCall.World.GetTranslation();
drawCall.ObjectRadius = _sphere.Radius;
drawCall.Terrain.Patch = _patch;
drawCall.Terrain.HeightmapUVScaleBias = _heightmapUVScaleBias;
drawCall.Terrain.OffsetUV = Vector2((float)(_patch->_x * TerrainPatch::CHUNKS_COUNT_EDGE + _x), (float)(_patch->_z * TerrainPatch::CHUNKS_COUNT_EDGE + _z));
@@ -202,7 +204,7 @@ void TerrainChunk::UpdateBounds()
OrientedBoundingBox obb(Vector3::Zero, Vector3::One);
obb.Transform(localTransform);
obb.GetBoundingBox(_bounds);
_boundsCenter = _bounds.GetCenter();
BoundingSphere::FromBox(_bounds, _sphere);
_bounds.Minimum -= boundsExtent;
_bounds.Maximum += boundsExtent;

View File

@@ -3,6 +3,7 @@
#pragma once
#include "Engine/Core/Math/BoundingBox.h"
#include "Engine/Core/Math/BoundingSphere.h"
#include "Engine/Core/Math/Matrix.h"
#include "Engine/Core/Math/Transform.h"
#include "Engine/Core/ISerializable.h"
@@ -29,7 +30,7 @@ private:
Float4 _heightmapUVScaleBias;
Transform _transform;
BoundingBox _bounds;
Vector3 _boundsCenter;
BoundingSphere _sphere;
float _perInstanceRandom;
float _yOffset, _yHeight;

View File

@@ -19,7 +19,7 @@ namespace FlaxEngine.Tests
{
var result = 0;
var libraryName = "FlaxEngine";
var library = NativeLibrary.Load(Interop.NativeInterop.nativeLibraryPaths[libraryName]);
var library = NativeLibrary.Load(Interop.NativeInterop.libraryPaths[libraryName]);
if (library == IntPtr.Zero)
return -1;
var types = typeof(FlaxEngine.Object).Assembly.GetTypes();

View File

@@ -42,7 +42,16 @@ public:
void write(const char* message) override
{
String s(message);
s.Replace('\n', ' ');
if (s.Length() <= 0)
return;
for (int32 i = 0; i < s.Length(); i++)
{
Char& c = s[i];
if (c == '\n')
c = ' ';
else if (c >= 255)
c = '?';
}
LOG(Info, "[Assimp]: {0}", s);
}
};
@@ -557,12 +566,17 @@ bool ImportMaterials(ImportedModelData& result, AssimpImporterData& data, String
return false;
}
bool IsMeshInvalid(const aiMesh* aMesh)
{
return aMesh->mPrimitiveTypes != aiPrimitiveType_TRIANGLE || aMesh->mNumVertices == 0 || aMesh->mNumFaces == 0 || aMesh->mFaces[0].mNumIndices != 3;
}
bool ImportMesh(int32 i, ImportedModelData& result, AssimpImporterData& data, String& errorMsg)
{
const auto aMesh = data.Scene->mMeshes[i];
// Skip invalid meshes
if (aMesh->mPrimitiveTypes != aiPrimitiveType_TRIANGLE || aMesh->mNumVertices == 0 || aMesh->mNumFaces == 0 || aMesh->mFaces[0].mNumIndices != 3)
if (IsMeshInvalid(aMesh))
return false;
// Skip unused meshes
@@ -707,13 +721,13 @@ bool ModelTool::ImportDataAssimp(const char* path, ImportedModelData& data, Opti
if (EnumHasAnyFlags(data.Types, ImportDataTypes::Geometry) && context->Scene->HasMeshes())
{
const int meshCount = context->Scene->mNumMeshes;
if (options.SplitObjects && options.ObjectIndex == -1)
if (options.SplitObjects && options.ObjectIndex == -1 && meshCount > 1)
{
// Import the first object within this call
options.SplitObjects = false;
options.ObjectIndex = 0;
if (meshCount > 1 && options.OnSplitImport.IsBinded())
if (options.OnSplitImport.IsBinded())
{
// Split all animations into separate assets
LOG(Info, "Splitting imported {0} meshes", meshCount);
@@ -780,13 +794,13 @@ bool ModelTool::ImportDataAssimp(const char* path, ImportedModelData& data, Opti
if (EnumHasAnyFlags(data.Types, ImportDataTypes::Animations) && context->Scene->HasAnimations())
{
const int32 animCount = (int32)context->Scene->mNumAnimations;
if (options.SplitObjects && options.ObjectIndex == -1)
if (options.SplitObjects && options.ObjectIndex == -1 && animCount > 1)
{
// Import the first object within this call
options.SplitObjects = false;
options.ObjectIndex = 0;
if (animCount > 1 && options.OnSplitImport.IsBinded())
if (options.OnSplitImport.IsBinded())
{
// Split all animations into separate assets
LOG(Info, "Splitting imported {0} animations", animCount);

View File

@@ -924,8 +924,6 @@ bool ImportMesh(int32 index, ImportedModelData& result, OpenFbxImporterData& dat
const auto aMesh = data.Scene->getMesh(index);
const auto aGeometry = aMesh->getGeometry();
const auto trianglesCount = aGeometry->getVertexCount() / 3;
// Skip invalid meshes
if (IsMeshInvalid(aMesh))
return false;
@@ -1246,13 +1244,13 @@ bool ModelTool::ImportDataOpenFBX(const char* path, ImportedModelData& data, Opt
if (EnumHasAnyFlags(data.Types, ImportDataTypes::Geometry) && context->Scene->getMeshCount() > 0)
{
const int meshCount = context->Scene->getMeshCount();
if (options.SplitObjects && options.ObjectIndex == -1)
if (options.SplitObjects && options.ObjectIndex == -1 && meshCount > 1)
{
// Import the first object within this call
options.SplitObjects = false;
options.ObjectIndex = 0;
if (meshCount > 1 && options.OnSplitImport.IsBinded())
if (options.OnSplitImport.IsBinded())
{
// Split all animations into separate assets
LOG(Info, "Splitting imported {0} meshes", meshCount);
@@ -1273,6 +1271,22 @@ bool ModelTool::ImportDataOpenFBX(const char* path, ImportedModelData& data, Opt
const auto meshIndex = Math::Clamp<int32>(options.ObjectIndex, 0, meshCount - 1);
if (ImportMesh(meshIndex, data, *context, errorMsg))
return true;
// Let the firstly imported mesh import all materials from all meshes (index 0 is importing all following ones before itself during splitting - see code above)
if (options.ObjectIndex == 1)
{
for (int32 i = 0; i < meshCount; i++)
{
const auto aMesh = context->Scene->getMesh(i);
if (i == 1 || IsMeshInvalid(aMesh))
continue;
for (int32 j = 0; j < aMesh->getMaterialCount(); j++)
{
const ofbx::Material* aMaterial = aMesh->getMaterial(j);
context->AddMaterial(data, aMaterial);
}
}
}
}
else
{
@@ -1329,13 +1343,13 @@ bool ModelTool::ImportDataOpenFBX(const char* path, ImportedModelData& data, Opt
if (EnumHasAnyFlags(data.Types, ImportDataTypes::Animations))
{
const int animCount = context->Scene->getAnimationStackCount();
if (options.SplitObjects && options.ObjectIndex == -1)
if (options.SplitObjects && options.ObjectIndex == -1 && animCount > 1)
{
// Import the first object within this call
options.SplitObjects = false;
options.ObjectIndex = 0;
if (animCount > 1 && options.OnSplitImport.IsBinded())
if (options.OnSplitImport.IsBinded())
{
// Split all animations into separate assets
LOG(Info, "Splitting imported {0} animations", animCount);

View File

@@ -60,6 +60,7 @@ public class Slider : ContainerControl
private float _thumbCenter;
private Float2 _thumbSize = new Float2(16, 16);
private bool _isSliding;
private bool _mouseOverThumb;
/// <summary>
/// Gets or sets the value (normalized to range 0-100).
@@ -163,21 +164,27 @@ public class Slider : ContainerControl
public IBrush FillTrackBrush { get; set; }
/// <summary>
/// The color of the slider thumb when it's not selected
/// The color of the slider thumb when it's not selected.
/// </summary>
[EditorDisplay("Thumb Style"), EditorOrder(2030), Tooltip("The color of the slider thumb when it's not selected."), ExpandGroups]
public Color ThumbColor { get; set; }
/// <summary>
/// The color of the slider thumb when it's highlighted.
/// </summary>
[EditorDisplay("Thumb Style"), EditorOrder(2031), Tooltip("The color of the slider thumb when it's highlighted.")]
public Color ThumbColorHighlighted { get; set; }
/// <summary>
/// The color of the slider thumb when it's selected
/// The color of the slider thumb when it's selected.
/// </summary>
[EditorDisplay("Thumb Style"), EditorOrder(2031), Tooltip("The color of the slider thumb when it's selected.")]
[EditorDisplay("Thumb Style"), EditorOrder(2032), Tooltip("The color of the slider thumb when it's selected.")]
public Color ThumbColorSelected { get; set; }
/// <summary>
/// Gets or sets the brush used for slider thumb drawing.
/// </summary>
[EditorDisplay("Thumb Style"), EditorOrder(2032), Tooltip("The brush of the slider thumb.")]
[EditorDisplay("Thumb Style"), EditorOrder(2033), Tooltip("The brush of the slider thumb.")]
public IBrush ThumbBrush { get; set; }
/// <summary>
@@ -222,6 +229,7 @@ public class Slider : ContainerControl
TrackFillLineColor = style.LightBackground;
ThumbColor = style.BackgroundNormal;
ThumbColorSelected = style.BackgroundSelected;
ThumbColorHighlighted = style.BackgroundHighlighted;
UpdateThumb();
}
@@ -270,7 +278,7 @@ public class Slider : ContainerControl
}
// Draw thumb
var thumbColor = _isSliding ? ThumbColorSelected : ThumbColor;
var thumbColor = _isSliding ? ThumbColorSelected : (_mouseOverThumb ? ThumbColorHighlighted : ThumbColor);
if (ThumbBrush != null)
ThumbBrush.Draw(_thumbRect, thumbColor);
else
@@ -317,6 +325,7 @@ public class Slider : ContainerControl
/// <inheritdoc />
public override void OnMouseMove(Float2 location)
{
_mouseOverThumb = _thumbRect.Contains(location);
if (_isSliding)
{
// Update sliding

View File

@@ -11,6 +11,11 @@ namespace FlaxEngine.GUI
/// </summary>
public abstract class TextBoxBase : ContainerControl
{
/// <summary>
/// The delete control character (used for text filtering).
/// </summary>
protected const char DelChar = (char)0x7F;
/// <summary>
/// The text separators (used for words skipping).
/// </summary>
@@ -351,6 +356,10 @@ namespace FlaxEngine.GUI
if (value.IndexOf('\r') != -1)
value = value.Replace("\r", "");
// Filter text (handle backspace control character)
if (value.IndexOf(DelChar) != -1)
value = value.Replace(DelChar.ToString(), "");
// Clamp length
if (value.Length > MaxLength)
value = value.Substring(0, MaxLength);
@@ -673,6 +682,8 @@ namespace FlaxEngine.GUI
// Filter text
if (str.IndexOf('\r') != -1)
str = str.Replace("\r", "");
if (str.IndexOf(DelChar) != -1)
str = str.Replace(DelChar.ToString(), "");
if (!IsMultiline && str.IndexOf('\n') != -1)
str = str.Replace("\n", "");
@@ -1327,6 +1338,15 @@ namespace FlaxEngine.GUI
if (IsReadOnly)
return true;
if (ctrDown)
{
int prevWordBegin = FindPrevWordBegin();
_text = _text.Remove(prevWordBegin, CaretPosition - prevWordBegin);
SetSelection(prevWordBegin);
OnTextChanged();
return true;
}
int left = SelectionLeft;
if (HasSelection)
{

View File

@@ -360,7 +360,7 @@ namespace FlaxEngine.GUI
{
var containerControl = child as ContainerControl;
var childAtRecursive = containerControl?.GetChildAtRecursive(childLocation);
if (childAtRecursive != null)
if (childAtRecursive != null && childAtRecursive.Visible)
{
child = childAtRecursive;
}
@@ -507,15 +507,19 @@ namespace FlaxEngine.GUI
// Perform automatic navigation based on the layout
var result = NavigationRaycast(direction, location, visited);
if (result == null && direction == NavDirection.Next)
var rightMostLocation = location;
if (result == null && (direction == NavDirection.Next || direction == NavDirection.Previous))
{
// Try wrap the navigation over the layout based on the direction
var visitedWrap = new List<Control>(visited);
result = NavigationWrap(direction, location, visitedWrap);
result = NavigationWrap(direction, location, visitedWrap, out rightMostLocation);
}
if (result != null)
{
result = result.OnNavigate(direction, result.PointFromParent(location), this, visited);
// HACK: only the 'previous' direction needs the rightMostLocation so i used a ternary conditional operator.
// The rightMostLocation can probably become a 'desired raycast origin' that gets calculated correctly in the NavigationWrap method.
var useLocation = direction == NavDirection.Previous ? rightMostLocation : location;
result = result.OnNavigate(direction, result.PointFromParent(useLocation), this, visited);
if (result != null)
return result;
}
@@ -551,8 +555,9 @@ namespace FlaxEngine.GUI
/// <param name="direction">The navigation direction.</param>
/// <param name="location">The navigation start location (in the control-space).</param>
/// <param name="visited">The list with visited controls. Used to skip recursive navigation calls when doing traversal across the UI hierarchy.</param>
/// <param name="rightMostLocation">Returns the rightmost location of the parent container for the raycast used by the child container</param>
/// <returns>The target navigation control or null if didn't performed any navigation.</returns>
protected virtual Control NavigationWrap(NavDirection direction, Float2 location, List<Control> visited)
protected virtual Control NavigationWrap(NavDirection direction, Float2 location, List<Control> visited, out Float2 rightMostLocation)
{
// This searches form a child that calls this navigation event (see Control.OnNavigate) to determinate the layout wrapping size based on that child size
var currentChild = RootWindow?.FocusedControl;
@@ -566,15 +571,22 @@ namespace FlaxEngine.GUI
case NavDirection.Next:
predictedLocation = new Float2(0, location.Y + layoutSize.Y);
break;
case NavDirection.Previous:
predictedLocation = new Float2(Size.X, location.Y - layoutSize.Y);
break;
}
if (new Rectangle(Float2.Zero, Size).Contains(ref predictedLocation))
{
var result = NavigationRaycast(direction, predictedLocation, visited);
if (result != null)
return result;
{
rightMostLocation = predictedLocation;
return result;
}
}
}
return Parent?.NavigationWrap(direction, PointToParent(ref location), visited);
rightMostLocation = location;
return Parent?.NavigationWrap(direction, PointToParent(ref location), visited, out rightMostLocation);
}
private static bool CanGetAutoFocus(Control c)
@@ -613,6 +625,10 @@ namespace FlaxEngine.GUI
uiDir1 = new Float2(1, 0);
uiDir2 = new Float2(0, 1);
break;
case NavDirection.Previous:
uiDir1 = new Float2(-1, 0);
uiDir2 = new Float2(0, -1);
break;
}
Control result = null;
var minDistance = float.MaxValue;

View File

@@ -634,6 +634,7 @@ namespace FlaxEngine.GUI
case NavDirection.Left: return new Float2(0, size.Y * 0.5f);
case NavDirection.Right: return new Float2(size.X, size.Y * 0.5f);
case NavDirection.Next: return Float2.Zero;
case NavDirection.Previous: return size;
default: return size * 0.5f;
}
}

View File

@@ -202,5 +202,10 @@ namespace FlaxEngine.GUI
/// The next item (right with layout wrapping).
/// </summary>
Next,
/// <summary>
/// The previous item (left with layout wrapping).
/// </summary>
Previous,
}
}

View File

@@ -366,6 +366,7 @@ void TextRender::Draw(RenderContext& renderContext)
DrawCall drawCall;
drawCall.World = world;
drawCall.ObjectPosition = drawCall.World.GetTranslation();
drawCall.ObjectRadius = _sphere.Radius;
drawCall.Surface.GeometrySize = _localBox.GetSize();
drawCall.Surface.PrevWorld = _drawState.PrevWorld;
drawCall.Surface.Lightmap = nullptr;

View File

@@ -40,11 +40,11 @@ ShaderGraphValue::ShaderGraphValue(const Variant& v)
break;
case VariantType::Float:
Type = VariantType::Types::Float;
Value = String::Format(TEXT("{}"), v.AsFloat);
Value = String::Format(TEXT("{:.8f}"), v.AsFloat);
break;
case VariantType::Double:
Type = VariantType::Types::Float;
Value = String::Format(TEXT("{}"), (float)v.AsDouble);
Value = String::Format(TEXT("{:.8f}"), (float)v.AsDouble);
break;
case VariantType::Float2:
{