diff --git a/Source/Editor/Windows/DebugLogWindow.cs b/Source/Editor/Windows/DebugLogWindow.cs index 7900b55c2..560e507eb 100644 --- a/Source/Editor/Windows/DebugLogWindow.cs +++ b/Source/Editor/Windows/DebugLogWindow.cs @@ -2,8 +2,10 @@ using System; using System.Collections.Generic; +using System.IO; using System.Text; using System.Text.RegularExpressions; +using System.Threading; using System.Xml; using FlaxEditor.GUI; using FlaxEditor.GUI.ContextMenu; @@ -183,6 +185,11 @@ namespace FlaxEditor.Windows return true; } } + // Enter + else if (key == KeyboardKeys.Return) + { + Open(); + } // Ctrl+C else if (key == KeyboardKeys.C && Root.GetKey(KeyboardKeys.Control)) { @@ -193,19 +200,28 @@ namespace FlaxEditor.Windows return base.OnKeyDown(key); } + /// + /// Opens the entry location. + /// + public void Open() + { + if (!string.IsNullOrEmpty(Desc.LocationFile) && File.Exists(Desc.LocationFile)) + { + Editor.Instance.CodeEditing.OpenFile(Desc.LocationFile, Desc.LocationLine); + } + } + /// /// Copies the entry information to the system clipboard (as text). /// public void Copy() { - Clipboard.Text = Info.Replace("\n", Environment.NewLine); + Clipboard.Text = Info.Replace("\r\n", "\n").Replace("\n", Environment.NewLine); } public override bool OnMouseDoubleClick(Vector2 location, MouseButton button) { - // Show the location - Editor.Instance.CodeEditing.OpenFile(Desc.LocationFile, Desc.LocationLine); - + Open(); return true; } @@ -238,6 +254,7 @@ namespace FlaxEditor.Windows var menu = new ContextMenu(); menu.AddButton("Copy", Copy); + menu.AddButton("Open", Open).Enabled = !string.IsNullOrEmpty(Desc.LocationFile) && File.Exists(Desc.LocationFile); menu.Show(this, location); } @@ -258,7 +275,8 @@ namespace FlaxEditor.Windows private readonly VerticalPanel _entriesPanel; private LogEntry _selected; private readonly int[] _logCountPerGroup = new int[(int)LogGroup.Max]; - private readonly Regex _logRegex = new Regex("at(.*) in (.*):(\\d*)"); + private readonly Regex _logRegex = new Regex("at (.*) in (.*):(line (\\d*)|(\\d*))"); + private readonly ThreadLocal _stringBuilder = new ThreadLocal(() => new StringBuilder(), false); private InterfaceOptions.TimestampsFormats _timestampsFormats; private readonly object _locker = new object(); @@ -337,7 +355,6 @@ namespace FlaxEditor.Windows Editor.Options.OptionsChanged += OnEditorOptionsChanged; Debug.Logger.LogHandler.SendLog += LogHandlerOnSendLog; Debug.Logger.LogHandler.SendExceptionLog += LogHandlerOnSendExceptionLog; - } private void OnEditorOptionsChanged(EditorOptions options) @@ -488,24 +505,33 @@ namespace FlaxEditor.Windows // Detect code location and remove leading internal stack trace part var matches = _logRegex.Matches(stackTrace); bool foundStart = false, noLocation = true; - var fineStackTrace = new StringBuilder(stackTrace.Length); + var fineStackTrace = _stringBuilder.Value; + fineStackTrace.Clear(); + fineStackTrace.Capacity = Mathf.Max(fineStackTrace.Capacity, stackTrace.Length); for (int i = 0; i < matches.Count; i++) { var match = matches[i]; - if (foundStart) + var matchLocation = match.Groups[1].Value.Trim(); + if (matchLocation.StartsWith("FlaxEngine.Debug.", StringComparison.Ordinal)) + { + // C# start + foundStart = true; + } + else if (matchLocation.StartsWith("DebugLog::", StringComparison.Ordinal)) + { + // C++ start + foundStart = true; + } + else if (foundStart) { if (noLocation) { desc.LocationFile = match.Groups[2].Value; - int.TryParse(match.Groups[3].Value, out desc.LocationLine); + int.TryParse(match.Groups[5].Value, out desc.LocationLine); noLocation = false; } fineStackTrace.AppendLine(match.Groups[0].Value); } - else if (match.Groups[1].Value.Trim().StartsWith("FlaxEngine.Debug.Info", StringComparison.Ordinal)) - { - foundStart = true; - } } desc.Description = fineStackTrace.ToString(); } diff --git a/Source/Engine/Content/AssetReference.h b/Source/Engine/Content/AssetReference.h index 658545d1a..40f57337d 100644 --- a/Source/Engine/Content/AssetReference.h +++ b/Source/Engine/Content/AssetReference.h @@ -193,7 +193,7 @@ public: FORCE_INLINE AssetReference& operator=(const Guid& id) { - OnSet((T*)LoadAsset(id, T::TypeInitializer)); + OnSet((T*)::LoadAsset(id, T::TypeInitializer)); return *this; } diff --git a/Source/Engine/Content/Assets/VisualScript.cpp b/Source/Engine/Content/Assets/VisualScript.cpp index 414d66870..5fd9d6f3f 100644 --- a/Source/Engine/Content/Assets/VisualScript.cpp +++ b/Source/Engine/Content/Assets/VisualScript.cpp @@ -3,6 +3,7 @@ #include "VisualScript.h" #include "Engine/Core/Log.h" #include "Engine/Core/Types/DataContainer.h" +#include "Engine/Content/Content.h" #include "Engine/Content/Factories/BinaryAssetFactory.h" #include "Engine/Scripting/MException.h" #include "Engine/Scripting/Scripting.h" diff --git a/Source/Engine/Content/Utilities/AssetsContainer.h b/Source/Engine/Content/AssetsContainer.h similarity index 87% rename from Source/Engine/Content/Utilities/AssetsContainer.h rename to Source/Engine/Content/AssetsContainer.h index f2c56d747..aefaec8d8 100644 --- a/Source/Engine/Content/Utilities/AssetsContainer.h +++ b/Source/Engine/Content/AssetsContainer.h @@ -2,10 +2,9 @@ #pragma once -#include "Engine/Content/Content.h" #include "Engine/Core/Collections/Array.h" #include "Engine/Content/AssetReference.h" -#include "../Asset.h" +#include "Asset.h" /// /// Assets Container allows to load collection of assets and keep references to them. @@ -27,13 +26,9 @@ public: if (e.GetID() == id) return (T*)e.Get(); } - - auto asset = Content::LoadAsync(id); + auto asset = (T*)::LoadAsset(id, T::TypeInitializer); if (asset) - { Add(asset); - } - return asset; } diff --git a/Source/Engine/Content/WeakAssetReference.h b/Source/Engine/Content/WeakAssetReference.h index 76f6b1fff..4943fd0b5 100644 --- a/Source/Engine/Content/WeakAssetReference.h +++ b/Source/Engine/Content/WeakAssetReference.h @@ -158,7 +158,7 @@ public: FORCE_INLINE WeakAssetReference& operator=(const Guid& id) { - OnSet((T*)LoadAsset(id, T::TypeInitializer)); + OnSet((T*)::LoadAsset(id, T::TypeInitializer)); return *this; } diff --git a/Source/Engine/Content/Utilities/IESLoader.cpp b/Source/Engine/ContentImporters/ImportIES.cpp similarity index 96% rename from Source/Engine/Content/Utilities/IESLoader.cpp rename to Source/Engine/ContentImporters/ImportIES.cpp index 271ab3d5e..b4c9ea433 100644 --- a/Source/Engine/Content/Utilities/IESLoader.cpp +++ b/Source/Engine/ContentImporters/ImportIES.cpp @@ -1,9 +1,11 @@ // Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. +#if COMPILE_WITH_ASSETS_IMPORTER + +#include "ImportIES.h" #include "Engine/Core/Log.h" #include "Engine/Core/RandomStream.h" #include "Engine/Core/Math/Packed.h" -#include "IESLoader.h" #define MAX_LINE 200 @@ -84,7 +86,7 @@ static bool ReadLine(const uint8*& bufferPos, int32& ret) #define PARSE_FLOAT(x) float x; if (!ReadFloat(bufferPos, x)) { return true; } #define PARSE_INT(x) int32 x; if (!ReadLine(bufferPos, x)) { return true; } -bool IESLoader::Load(const byte* buffer) +bool ImportIES::Load(const byte* buffer) { // Referenced IES file format: // http://www.ltblight.com/English.lproj/LTBLhelp/pages/iesformat.html @@ -214,7 +216,7 @@ bool IESLoader::Load(const byte* buffer) #undef PARSE_FLOAT #undef PARSE_INT -float IESLoader::ExtractInR16(Array& output) +float ImportIES::ExtractInR16(Array& output) { const uint32 width = GetWidth(); const uint32 height = GetHeight(); @@ -263,14 +265,14 @@ float IESLoader::ExtractInR16(Array& output) return maxValue / integral; } -float IESLoader::InterpolatePoint(int32 x, int32 y) const +float ImportIES::InterpolatePoint(int32 x, int32 y) const { x %= _hAngles.Count(); y %= _vAngles.Count(); return _candalaValues[y + _vAngles.Count() * x]; } -float IESLoader::InterpolateBilinear(float x, float y) const +float ImportIES::InterpolateBilinear(float x, float y) const { const int32 xInt = static_cast(x); const int32 yInt = static_cast(y); @@ -289,7 +291,7 @@ float IESLoader::InterpolateBilinear(float x, float y) const return Math::Lerp(p0, p1, xFrac); } -float IESLoader::ComputeFilterPos(float value, const Array& sortedValues) +float ImportIES::ComputeFilterPos(float value, const Array& sortedValues) { ASSERT(sortedValues.HasItems()); @@ -336,3 +338,5 @@ float IESLoader::ComputeFilterPos(float value, const Array& sortedValues) return startPos + fraction; } + +#endif diff --git a/Source/Engine/Content/Utilities/IESLoader.h b/Source/Engine/ContentImporters/ImportIES.h similarity index 95% rename from Source/Engine/Content/Utilities/IESLoader.h rename to Source/Engine/ContentImporters/ImportIES.h index f25a9d7ff..158613958 100644 --- a/Source/Engine/Content/Utilities/IESLoader.h +++ b/Source/Engine/ContentImporters/ImportIES.h @@ -2,13 +2,15 @@ #pragma once +#if COMPILE_WITH_ASSETS_IMPORTER + #include "Engine/Core/Types/BaseTypes.h" #include "Engine/Core/Collections/Array.h" /// /// Utility for loading IES files and extract light emission information. /// -class IESLoader +class ImportIES { private: @@ -56,3 +58,5 @@ private: float InterpolateBilinear(float x, float y) const; static float ComputeFilterPos(float value, const Array& sortedValues); }; + +#endif diff --git a/Source/Engine/ContentImporters/ImportTexture.cpp b/Source/Engine/ContentImporters/ImportTexture.cpp index 4537d496f..7daa62d9d 100644 --- a/Source/Engine/ContentImporters/ImportTexture.cpp +++ b/Source/Engine/ContentImporters/ImportTexture.cpp @@ -13,7 +13,7 @@ #include "Engine/Graphics/Textures/TextureUtils.h" #include "Engine/Graphics/PixelFormatExtensions.h" #include "Engine/Content/Storage/ContentStorageManager.h" -#include "Engine/Content/Utilities/IESLoader.h" +#include "Engine/ContentImporters/ImportIES.h" #include "Engine/Content/Assets/CubeTexture.h" #include "Engine/Content/Assets/IESProfile.h" #include "Engine/Content/Assets/Texture.h" @@ -527,7 +527,7 @@ CreateAssetResult ImportTexture::ImportIES(class CreateAssetContext& context) fileData.Add('\0'); // Load IES profile data - IESLoader loader; + ::ImportIES loader; if (loader.Load(fileData.Get())) { return CreateAssetResult::Error; diff --git a/Source/Engine/Core/Math/Quaternion.cs b/Source/Engine/Core/Math/Quaternion.cs index f3bc66f76..125b5b36c 100644 --- a/Source/Engine/Core/Math/Quaternion.cs +++ b/Source/Engine/Core/Math/Quaternion.cs @@ -968,6 +968,17 @@ namespace FlaxEngine RotationMatrix(ref matrix, out result); } + /// + /// Creates a left-handed, look-at quaternion. + /// + /// The position of the viewer's eye. + /// The camera look-at target. + /// The created look-at quaternion. + public static Quaternion LookAt(Vector3 eye, Vector3 target) + { + return LookAt(eye, target, Vector3.Up); + } + /// /// Creates a left-handed, look-at quaternion. /// @@ -993,6 +1004,16 @@ namespace FlaxEngine LookAt(ref eye, ref forward, ref up, out result); } + /// + /// Creates a left-handed, look-at quaternion. + /// + /// The camera's forward direction. + /// The created look-at quaternion. + public static Quaternion RotationLookAt(Vector3 forward) + { + return RotationLookAt(forward, Vector3.Up); + } + /// /// Creates a left-handed, look-at quaternion. /// @@ -1005,6 +1026,16 @@ namespace FlaxEngine return result; } + /// + /// Creates a rotation with the specified forward and upwards directions. + /// + /// The forward direction. Direction to orient towards. + /// The calculated quaternion. + public static Quaternion LookRotation(Vector3 forward) + { + return LookRotation(forward, Vector3.Up); + } + /// /// Creates a rotation with the specified forward and upwards directions. /// diff --git a/Source/Engine/Core/Math/Vector2.cs b/Source/Engine/Core/Math/Vector2.cs index 329253535..c0b84ca04 100644 --- a/Source/Engine/Core/Math/Vector2.cs +++ b/Source/Engine/Core/Math/Vector2.cs @@ -833,6 +833,55 @@ namespace FlaxEngine return value; } + /// + /// Makes sure that Length of the output vector is always below max and above 0. + /// + /// Input Vector. + /// Max Length + public static Vector2 ClampLength(Vector2 vector, float max) + { + return ClampLength(vector, 0, max); + } + + /// + /// Makes sure that Length of the output vector is always below max and above min. + /// + /// Input Vector. + /// Min Length + /// Max Length + public static Vector2 ClampLength(Vector2 vector, float min, float max) + { + ClampLength(ref vector, min, max, out Vector2 retVect); + return retVect; + } + + /// + /// Makes sure that Length of the output vector is always below max and above min. + /// + /// Input Vector. + /// Min Length + /// Max Length + /// The Return Vector + public static void ClampLength(ref Vector2 vector, float min, float max, out Vector2 retVect) + { + retVect.X = vector.X; + retVect.Y = vector.Y; + + float lenSq = retVect.LengthSquared; + if (lenSq > max * max) + { + float scaleFactor = max / (float)Math.Sqrt(lenSq); + retVect.X = retVect.X * scaleFactor; + retVect.Y = retVect.Y * scaleFactor; + } + if (lenSq < min * min) + { + float scaleFactor = min / (float)Math.Sqrt(lenSq); + retVect.X = retVect.X * scaleFactor; + retVect.Y = retVect.Y * scaleFactor; + } + } + /// /// Returns the vector with components rounded to the nearest integer. /// diff --git a/Source/Engine/Core/Math/Vector3.cs b/Source/Engine/Core/Math/Vector3.cs index e331142b9..2674b30e6 100644 --- a/Source/Engine/Core/Math/Vector3.cs +++ b/Source/Engine/Core/Math/Vector3.cs @@ -992,6 +992,58 @@ namespace FlaxEngine return value; } + /// + /// Makes sure that Length of the output vector is always below max and above 0. + /// + /// Input Vector. + /// Max Length + public static Vector3 ClampLength(Vector3 vector, float max) + { + return ClampLength(vector, 0, max); + } + + /// + /// Makes sure that Length of the output vector is always below max and above min. + /// + /// Input Vector. + /// Min Length + /// Max Length + public static Vector3 ClampLength(Vector3 vector, float min, float max) + { + ClampLength(ref vector, min, max, out Vector3 retVect); + return retVect; + } + + /// + /// Makes sure that Length of the output vector is always below max and above min. + /// + /// Input Vector. + /// Min Length + /// Max Length + /// The Return Vector + public static void ClampLength(ref Vector3 vector, float min, float max, out Vector3 retVect) + { + retVect.X = vector.X; + retVect.Y = vector.Y; + retVect.Z = vector.Z; + + float lenSq = retVect.LengthSquared; + if (lenSq > max * max) + { + float scaleFactor = max / (float)Math.Sqrt(lenSq); + retVect.X = retVect.X * scaleFactor; + retVect.Y = retVect.Y * scaleFactor; + retVect.Z = retVect.Z * scaleFactor; + } + if (lenSq < min * min) + { + float scaleFactor = min / (float)Math.Sqrt(lenSq); + retVect.X = retVect.X * scaleFactor; + retVect.Y = retVect.Y * scaleFactor; + retVect.Z = retVect.Z * scaleFactor; + } + } + /// /// Performs a linear interpolation between two vectors. /// diff --git a/Source/Engine/Core/Math/Vector4.cs b/Source/Engine/Core/Math/Vector4.cs index 38c77e705..99430072d 100644 --- a/Source/Engine/Core/Math/Vector4.cs +++ b/Source/Engine/Core/Math/Vector4.cs @@ -792,6 +792,61 @@ namespace FlaxEngine return value; } + /// + /// Makes sure that Length of the output vector is always below max and above 0. + /// + /// Input Vector. + /// Max Length + public static Vector4 ClampLength(Vector4 vector, float max) + { + return ClampLength(vector, 0, max); + } + + /// + /// Makes sure that Length of the output vector is always below max and above min. + /// + /// Input Vector. + /// Min Length + /// Max Length + public static Vector4 ClampLength(Vector4 vector, float min, float max) + { + ClampLength(ref vector, min, max, out Vector4 retVect); + return retVect; + } + + /// + /// Makes sure that Length of the output vector is always below max and above min. + /// + /// Input Vector. + /// Min Length + /// Max Length + /// The Return Vector + public static void ClampLength(ref Vector4 vector, float min, float max, out Vector4 retVect) + { + retVect.X = vector.X; + retVect.Y = vector.Y; + retVect.Z = vector.Z; + retVect.W = vector.W; + + float lenSq = retVect.LengthSquared; + if (lenSq > max * max) + { + float scaleFactor = max / (float)Math.Sqrt(lenSq); + retVect.X = retVect.X * scaleFactor; + retVect.Y = retVect.Y * scaleFactor; + retVect.Z = retVect.Z * scaleFactor; + retVect.W = retVect.W * scaleFactor; + } + if (lenSq < min * min) + { + float scaleFactor = min / (float)Math.Sqrt(lenSq); + retVect.X = retVect.X * scaleFactor; + retVect.Y = retVect.Y * scaleFactor; + retVect.Z = retVect.Z * scaleFactor; + retVect.W = retVect.W * scaleFactor; + } + } + /// /// Performs a linear interpolation between two vectors. /// diff --git a/Source/Engine/Debug/DebugLog.cpp b/Source/Engine/Debug/DebugLog.cpp index bf1da8d7d..9263651b9 100644 --- a/Source/Engine/Debug/DebugLog.cpp +++ b/Source/Engine/Debug/DebugLog.cpp @@ -1,12 +1,7 @@ // Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. #include "DebugLog.h" -#include "Engine/Core/Log.h" -#include "Engine/Scripting/InternalCalls.h" -#include "Engine/Scripting/ScriptingObject.h" -#include "Engine/Scripting/MException.h" #include "Engine/Scripting/Scripting.h" -#include "Engine/Scripting/ScriptingType.h" #include "Engine/Scripting/BinaryModule.h" #include "Engine/Scripting/MainThreadManagedInvokeAction.h" #include "Engine/Scripting/ManagedCLR/MDomain.h" @@ -16,70 +11,7 @@ #include #include -namespace DebugLogHandlerInternal -{ - void LogWrite(LogType level, MonoString* msgObj) - { - StringView msg; - MUtils::ToString(msgObj, msg); - Log::Logger::Write(level, msg); - } - - void Log(LogType level, MonoString* msgObj, ScriptingObject* obj, MonoString* stackTrace) - { - if (msgObj == nullptr) - return; - - // Get info - StringView msg; - MUtils::ToString(msgObj, msg); - //const String objName = obj ? obj->ToString() : String::Empty; - - // Send event - // TODO: maybe option for build to threat warnings and errors as fatal errors? - //const String logMessage = String::Format(TEXT("Debug:{1} {2}"), objName, *msg); - Log::Logger::Write(level, msg); - } - - void LogException(MonoException* exception, ScriptingObject* obj) - { - if (exception == nullptr) - return; - - // Get info - MException ex(exception); - String objName = obj ? obj->ToString() : String::Empty; - - // Print exception including inner exceptions - // TODO: maybe option for build to threat warnings and errors as fatal errors? - ex.Log(LogType::Warning, objName.GetText()); - } -} - -namespace FlaxLogWriterInternal -{ - void WriteStringToLog(MonoString* msg) - { - if (msg == nullptr) - return; - - auto msgStr = (Char*)mono_string_to_utf16(msg); - LOG_STR(Info, msgStr); - } -} - -void DebugLog::RegisterInternalCalls() -{ - // DebugLogHandler - ADD_INTERNAL_CALL("FlaxEngine.DebugLogHandler::Internal_LogWrite", &DebugLogHandlerInternal::LogWrite); - ADD_INTERNAL_CALL("FlaxEngine.DebugLogHandler::Internal_Log", &DebugLogHandlerInternal::Log); - ADD_INTERNAL_CALL("FlaxEngine.DebugLogHandler::Internal_LogException", &DebugLogHandlerInternal::LogException); - - // FlaxLogWriter - ADD_INTERNAL_CALL("FlaxEngine.FlaxLogWriter::Internal_WriteStringToLog", &FlaxLogWriterInternal::WriteStringToLog); -} - -namespace DebugLogImpl +namespace Impl { MMethod* Internal_SendLog = nullptr; MMethod* Internal_SendLogException = nullptr; @@ -87,7 +19,7 @@ namespace DebugLogImpl CriticalSection Locker; } -using namespace DebugLogImpl; +using namespace Impl; void ClearMethods(MAssembly*) { @@ -111,7 +43,7 @@ bool CacheMethods() if (!debugLogHandlerClass) return false; - Internal_SendLog = debugLogHandlerClass->GetMethod("Internal_SendLog", 2); + Internal_SendLog = debugLogHandlerClass->GetMethod("Internal_SendLog", 3); if (!Internal_SendLog) return false; @@ -128,7 +60,7 @@ bool CacheMethods() return false; } -void DebugLog::Log(LogType type, const String& message) +void DebugLog::Log(LogType type, const StringView& message) { if (CacheMethods()) return; @@ -137,15 +69,18 @@ void DebugLog::Log(LogType type, const String& message) MainThreadManagedInvokeAction::ParamsBuilder params; params.AddParam(type); params.AddParam(message, scriptsDomain->GetNative()); +#if BUILD_RELEASE + params.AddParam(StringView::Empty, scriptsDomain->GetNative()); +#else + const String stackTrace = Platform::GetStackTrace(1); + params.AddParam(stackTrace, scriptsDomain->GetNative()); +#endif MainThreadManagedInvokeAction::Invoke(Internal_SendLog, params); } void DebugLog::LogException(MonoObject* exceptionObject) { - if (exceptionObject == nullptr) - return; - - if (CacheMethods()) + if (exceptionObject == nullptr || CacheMethods()) return; MainThreadManagedInvokeAction::ParamsBuilder params; diff --git a/Source/Engine/Debug/DebugLog.h b/Source/Engine/Debug/DebugLog.h index 6ef7f8242..2fd210563 100644 --- a/Source/Engine/Debug/DebugLog.h +++ b/Source/Engine/Debug/DebugLog.h @@ -10,13 +10,6 @@ /// class FLAXENGINE_API DebugLog { -public: - - /// - /// Registers the internal calls to managed code. - /// - static void RegisterInternalCalls(); - public: /// @@ -24,13 +17,13 @@ public: /// /// The message type. /// The message. - static void Log(LogType type, const String& message); + static void Log(LogType type, const StringView& message); /// /// A variant of Debug.Log that logs a warning message to the console. /// /// The text message to display. - FORCE_INLINE static void Log(const String& message) + FORCE_INLINE static void Log(const StringView& message) { Log(LogType::Info, message); } @@ -39,7 +32,7 @@ public: /// A variant of Debug.Log that logs a warning message to the console. /// /// The text message to display. - FORCE_INLINE static void LogWarning(const String& message) + FORCE_INLINE static void LogWarning(const StringView& message) { Log(LogType::Warning, message); } @@ -48,7 +41,7 @@ public: /// A variant of Debug.Log that logs a error message to the console. /// /// The text message to display. - FORCE_INLINE static void LogError(const String& message) + FORCE_INLINE static void LogError(const StringView& message) { Log(LogType::Error, message); } diff --git a/Source/Engine/Engine/DebugLogHandler.cs b/Source/Engine/Engine/DebugLogHandler.cs index c1dc9f9dd..bf9a3bc02 100644 --- a/Source/Engine/Engine/DebugLogHandler.cs +++ b/Source/Engine/Engine/DebugLogHandler.cs @@ -36,19 +36,27 @@ namespace FlaxEngine /// public void Log(LogType logType, Object context, string message) { -#if DEBUG - string stackTrace = Environment.StackTrace; + if (message == null) + return; +#if BUILD_RELEASE + string stackTrace = null; #else - string stackTrace = string.Empty; + string stackTrace = Environment.StackTrace; #endif Internal_Log(logType, message, Object.GetUnmanagedPtr(context), stackTrace); - SendLog?.Invoke(logType, message, context, stackTrace); } - internal static void Internal_SendLog(LogType type, string message) + internal static void Internal_SendLog(LogType logType, string message, string stackTrace) { - Debug.Logger.Log(type, message); + if (message == null) + return; + var logger = Debug.Logger; + if (logger.IsLogTypeAllowed(logType)) + { + Internal_Log(logType, message, IntPtr.Zero, stackTrace); + ((DebugLogHandler)logger.LogHandler).SendLog?.Invoke(logType, message, null, stackTrace); + } } internal static void Internal_SendLogException(Exception exception) diff --git a/Source/Engine/Platform/Base/PlatformBase.cpp b/Source/Engine/Platform/Base/PlatformBase.cpp index ba2d6d5f6..5ffb85a9a 100644 --- a/Source/Engine/Platform/Base/PlatformBase.cpp +++ b/Source/Engine/Platform/Base/PlatformBase.cpp @@ -202,11 +202,11 @@ void PlatformBase::Fatal(const Char* msg, void* context) LOG(Error, ""); // Log stack trace - const auto stackTrace = Platform::GetStackTrace(context ? 0 : 1, 60, context); - if (stackTrace.HasItems()) + const auto stackFrames = Platform::GetStackFrames(context ? 0 : 1, 60, context); + if (stackFrames.HasItems()) { LOG(Error, "Stack trace:"); - for (const auto& frame : stackTrace) + for (const auto& frame : stackFrames) { char chr = 0; int32 num = StringUtils::Length(frame.ModuleName); @@ -217,11 +217,11 @@ void PlatformBase::Fatal(const Char* msg, void* context) if (StringUtils::Length(frame.FileName) != 0) { StringAsUTF16 fileName(frame.FileName); - LOG(Error, " at {0}!{1} in {2}:line {3}", moduleName.Get(), functionName.Get(), fileName.Get(), frame.LineNumber); + LOG(Error, " at {0}!{1}() in {2}:line {3}", moduleName.Get(), functionName.Get(), fileName.Get(), frame.LineNumber); } else if (StringUtils::Length(frame.FunctionName) != 0) { - LOG(Error, " at {0}::{1}", moduleName.Get(), functionName.Get()); + LOG(Error, " at {0}!{1}()", moduleName.Get(), functionName.Get()); } else if (StringUtils::Length(frame.ModuleName) != 0) { @@ -483,11 +483,35 @@ int32 PlatformBase::RunProcess(const StringView& cmdLine, const StringView& work return -1; } -Array PlatformBase::GetStackTrace(int32 skipCount, int32 maxDepth, void* context) +Array PlatformBase::GetStackFrames(int32 skipCount, int32 maxDepth, void* context) { return Array(); } +String PlatformBase::GetStackTrace(int32 skipCount, int32 maxDepth, void* context) +{ + StringBuilder result; + Array stackFrames = Platform::GetStackFrames(skipCount, maxDepth, context); + for (const auto& frame : stackFrames) + { + StringAsUTF16 functionName(frame.FunctionName); + if (StringUtils::Length(frame.FileName) != 0) + { + StringAsUTF16 fileName(frame.FileName); + result.AppendFormat(TEXT(" at {0}() in {1}:line {2}\n"), functionName.Get(), fileName.Get(), frame.LineNumber); + } + else if (StringUtils::Length(frame.FunctionName) != 0) + { + result.AppendFormat(TEXT(" at {0}()\n"), functionName.Get()); + } + else + { + result.AppendFormat(TEXT(" at 0x{0:x}\n"), (uint64)frame.ProgramCounter); + } + } + return result.ToString(); +} + void PlatformBase::CollectCrashData(const String& crashDataFolder, void* context) { } diff --git a/Source/Engine/Platform/Base/PlatformBase.h b/Source/Engine/Platform/Base/PlatformBase.h index e97ce2b34..188bad122 100644 --- a/Source/Engine/Platform/Base/PlatformBase.h +++ b/Source/Engine/Platform/Base/PlatformBase.h @@ -804,7 +804,16 @@ public: /// The maximum depth of the stack to collect. Can be used to prevent too long stack traces in case of stack overflow exception. /// The platform-dependent context for the stack trace collecting (eg. platform exception info). /// The collected stack trace frames. Empty if not supported (eg. platform not implements this feature or not supported in the distributed build). - static Array GetStackTrace(int32 skipCount = 0, int32 maxDepth = 60, void* context = nullptr); + static Array GetStackFrames(int32 skipCount = 0, int32 maxDepth = 60, void* context = nullptr); + + /// + /// Gets current native stack trace information as string. + /// + /// The amount of stack frames to skip from the beginning. Can be used to skip the callee function from the trace (eg. in crash handler). + /// The maximum depth of the stack to collect. Can be used to prevent too long stack traces in case of stack overflow exception. + /// The platform-dependent context for the stack trace collecting (eg. platform exception info). + /// The collected stack trace printed into string. Empty if not supported (eg. platform not implements this feature or not supported in the distributed build). + static String GetStackTrace(int32 skipCount = 0, int32 maxDepth = 60, void* context = nullptr); // Crash dump data handling static void CollectCrashData(const String& crashDataFolder, void* context = nullptr); diff --git a/Source/Engine/Platform/UWP/UWPPlatform.cpp b/Source/Engine/Platform/UWP/UWPPlatform.cpp index ed01948aa..522d5db15 100644 --- a/Source/Engine/Platform/UWP/UWPPlatform.cpp +++ b/Source/Engine/Platform/UWP/UWPPlatform.cpp @@ -6,6 +6,7 @@ #include "Engine/Engine/Engine.h" #include "Engine/Platform/MessageBox.h" #include "Engine/Profiler/ProfilerCPU.h" +#include "Engine/Platform/BatteryInfo.h" #include "Engine/Input/Input.h" #include "Engine/Core/Log.h" #include "UWPWindow.h" @@ -114,6 +115,21 @@ void UWPPlatform::Exit() Win32Platform::Exit(); } +BatteryInfo UWPPlatform::GetBatteryInfo() +{ + BatteryInfo info; + SYSTEM_POWER_STATUS status; + GetSystemPowerStatus(&status); + info.BatteryLifePercent = (float)status.BatteryLifePercent / 255.0f; + if (status.BatteryFlag & 8) + info.State = BatteryInfo::States::BatteryCharging; + else if (status.BatteryFlag & 1 || status.BatteryFlag & 2 || status.BatteryFlag & 4) + info.State = BatteryInfo::States::BatteryDischarging; + else if (status.ACLineStatus == 1 || status.BatteryFlag & 128) + info.State = BatteryInfo::States::Connected; + return info; +} + int32 UWPPlatform::GetDpi() { return SystemDpi; diff --git a/Source/Engine/Platform/UWP/UWPPlatform.h b/Source/Engine/Platform/UWP/UWPPlatform.h index 6a04ac94c..9a946ce98 100644 --- a/Source/Engine/Platform/UWP/UWPPlatform.h +++ b/Source/Engine/Platform/UWP/UWPPlatform.h @@ -30,6 +30,7 @@ public: static void Tick(); static void BeforeExit(); static void Exit(); + static BatteryInfo GetBatteryInfo(); static int32 GetDpi(); static String GetUserLocaleName(); static String GetComputerName(); diff --git a/Source/Engine/Platform/Win32/Win32Platform.cpp b/Source/Engine/Platform/Win32/Win32Platform.cpp index d2b6163e1..e01a8a8e1 100644 --- a/Source/Engine/Platform/Win32/Win32Platform.cpp +++ b/Source/Engine/Platform/Win32/Win32Platform.cpp @@ -5,7 +5,6 @@ #include "Engine/Platform/Platform.h" #include "Engine/Platform/MemoryStats.h" #include "Engine/Platform/CPUInfo.h" -#include "Engine/Platform/BatteryInfo.h" #include "Engine/Core/Types/Guid.h" #include "Engine/Core/Types/String.h" #include "Engine/Core/Math/Math.h" @@ -341,21 +340,6 @@ bool Win32Platform::Is64BitPlatform() #endif } -BatteryInfo Win32Platform::GetBatteryInfo() -{ - BatteryInfo info; - SYSTEM_POWER_STATUS status; - GetSystemPowerStatus(&status); - info.BatteryLifePercent = (float)status.BatteryLifePercent / 255.0f; - if (status.BatteryFlag & 8) - info.State = BatteryInfo::States::BatteryCharging; - else if (status.BatteryFlag & 1 || status.BatteryFlag & 2 || status.BatteryFlag & 4) - info.State = BatteryInfo::States::BatteryDischarging; - else if (status.ACLineStatus == 1 || status.BatteryFlag & 128) - info.State = BatteryInfo::States::Connected; - return info; -} - CPUInfo Win32Platform::GetCPUInfo() { return CpuInfo; diff --git a/Source/Engine/Platform/Win32/Win32Platform.h b/Source/Engine/Platform/Win32/Win32Platform.h index 0b895ae40..02a7d4045 100644 --- a/Source/Engine/Platform/Win32/Win32Platform.h +++ b/Source/Engine/Platform/Win32/Win32Platform.h @@ -33,7 +33,6 @@ public: static void* AllocatePages(uint64 numPages, uint64 pageSize); static void FreePages(void* ptr); static bool Is64BitPlatform(); - static BatteryInfo GetBatteryInfo(); static CPUInfo GetCPUInfo(); static int32 GetCacheLineSize(); static MemoryStats GetMemoryStats(); diff --git a/Source/Engine/Platform/Windows/WindowsPlatform.cpp b/Source/Engine/Platform/Windows/WindowsPlatform.cpp index e01ef7a44..7cea15622 100644 --- a/Source/Engine/Platform/Windows/WindowsPlatform.cpp +++ b/Source/Engine/Platform/Windows/WindowsPlatform.cpp @@ -7,6 +7,7 @@ #include "Engine/Platform/CreateWindowSettings.h" #include "Engine/Platform/WindowsManager.h" #include "Engine/Platform/MemoryStats.h" +#include "Engine/Platform/BatteryInfo.h" #include "Engine/Engine/Globals.h" #include "Engine/Core/Log.h" #include "Engine/Core/Collections/Dictionary.h" @@ -680,6 +681,21 @@ void WindowsPlatform::SetHighDpiAwarenessEnabled(bool enable) FreeLibrary(shCoreDll); } +BatteryInfo WindowsPlatform::GetBatteryInfo() +{ + BatteryInfo info; + SYSTEM_POWER_STATUS status; + GetSystemPowerStatus(&status); + info.BatteryLifePercent = (float)status.BatteryLifePercent / 255.0f; + if (status.BatteryFlag & 8) + info.State = BatteryInfo::States::BatteryCharging; + else if (status.BatteryFlag & 1 || status.BatteryFlag & 2 || status.BatteryFlag & 4) + info.State = BatteryInfo::States::BatteryDischarging; + else if (status.ACLineStatus == 1 || status.BatteryFlag & 128) + info.State = BatteryInfo::States::Connected; + return info; +} + int32 WindowsPlatform::GetDpi() { return SystemDpi; @@ -1107,7 +1123,7 @@ void* WindowsPlatform::LoadLibrary(const Char* filename) return handle; } -Array WindowsPlatform::GetStackTrace(int32 skipCount, int32 maxDepth, void* context) +Array WindowsPlatform::GetStackFrames(int32 skipCount, int32 maxDepth, void* context) { Array result; #if CRASH_LOG_ENABLE diff --git a/Source/Engine/Platform/Windows/WindowsPlatform.h b/Source/Engine/Platform/Windows/WindowsPlatform.h index f437b819c..6a50ede5f 100644 --- a/Source/Engine/Platform/Windows/WindowsPlatform.h +++ b/Source/Engine/Platform/Windows/WindowsPlatform.h @@ -64,6 +64,7 @@ public: static bool IsDebuggerPresent(); #endif static void SetHighDpiAwarenessEnabled(bool enable); + static BatteryInfo GetBatteryInfo(); static int32 GetDpi(); static String GetUserLocaleName(); static String GetComputerName(); @@ -82,7 +83,7 @@ public: static int32 RunProcess(const StringView& cmdLine, const StringView& workingDir, const Dictionary& environment, bool hiddenWindow = true); static Window* CreateWindow(const CreateWindowSettings& settings); static void* LoadLibrary(const Char* filename); - static Array GetStackTrace(int32 skipCount = 0, int32 maxDepth = 60, void* context = nullptr); + static Array GetStackFrames(int32 skipCount = 0, int32 maxDepth = 60, void* context = nullptr); #if CRASH_LOG_ENABLE static void CollectCrashData(const String& crashDataFolder, void* context = nullptr); #endif diff --git a/Source/Engine/Scripting/InternalCalls/EngineInternalCalls.cpp b/Source/Engine/Scripting/InternalCalls/EngineInternalCalls.cpp index 0e06179fa..144eb6c86 100644 --- a/Source/Engine/Scripting/InternalCalls/EngineInternalCalls.cpp +++ b/Source/Engine/Scripting/InternalCalls/EngineInternalCalls.cpp @@ -1,9 +1,10 @@ // Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. #include "Engine/Platform/FileSystem.h" -#include "Engine/Debug/DebugLog.h" #include "Engine/Animations/Graph/AnimGraph.h" #include "Engine/Scripting/InternalCalls.h" +#include "Engine/Scripting/MException.h" +#include "Engine/Scripting/ManagedCLR/MUtils.h" namespace UtilsInternal { @@ -13,9 +14,64 @@ namespace UtilsInternal } } +namespace DebugLogHandlerInternal +{ + void LogWrite(LogType level, MonoString* msgObj) + { + StringView msg; + MUtils::ToString(msgObj, msg); + Log::Logger::Write(level, msg); + } + + void Log(LogType level, MonoString* msgObj, ScriptingObject* obj, MonoString* stackTrace) + { + if (msgObj == nullptr) + return; + + // Get info + StringView msg; + MUtils::ToString(msgObj, msg); + //const String objName = obj ? obj->ToString() : String::Empty; + + // Send event + // TODO: maybe option for build to threat warnings and errors as fatal errors? + //const String logMessage = String::Format(TEXT("Debug:{1} {2}"), objName, *msg); + Log::Logger::Write(level, msg); + } + + void LogException(MonoException* exception, ScriptingObject* obj) + { + if (exception == nullptr) + return; + + // Get info + MException ex(exception); + const String objName = obj ? obj->ToString() : String::Empty; + + // Print exception including inner exceptions + // TODO: maybe option for build to threat warnings and errors as fatal errors? + ex.Log(LogType::Warning, objName.GetText()); + } +} + +namespace FlaxLogWriterInternal +{ + void WriteStringToLog(MonoString* msgObj) + { + if (msgObj == nullptr) + return; + StringView msg; + MUtils::ToString(msgObj, msg); + LOG_STR(Info, msg); + } +} + void registerFlaxEngineInternalCalls() { - DebugLog::RegisterInternalCalls(); AnimGraphExecutor::initRuntime(); ADD_INTERNAL_CALL("FlaxEngine.Utils::MemoryCopy", &UtilsInternal::MemoryCopy); + ADD_INTERNAL_CALL("FlaxEngine.DebugLogHandler::Internal_LogWrite", &DebugLogHandlerInternal::LogWrite); + ADD_INTERNAL_CALL("FlaxEngine.DebugLogHandler::Internal_Log", &DebugLogHandlerInternal::Log); + ADD_INTERNAL_CALL("FlaxEngine.DebugLogHandler::Internal_LogException", &DebugLogHandlerInternal::LogException); + ADD_INTERNAL_CALL("FlaxEngine.FlaxLogWriter::Internal_WriteStringToLog", &FlaxLogWriterInternal::WriteStringToLog); } diff --git a/Source/Engine/Scripting/MainThreadManagedInvokeAction.h b/Source/Engine/Scripting/MainThreadManagedInvokeAction.h index 5af5e5f28..71ea24595 100644 --- a/Source/Engine/Scripting/MainThreadManagedInvokeAction.h +++ b/Source/Engine/Scripting/MainThreadManagedInvokeAction.h @@ -77,12 +77,24 @@ public: AddParam(val); } + FORCE_INLINE void AddParam(const StringView& value) + { + MonoString* val = MUtils::ToString(value); + AddParam(val); + } + FORCE_INLINE void AddParam(const String& value, MonoDomain* domain) { MonoString* val = MUtils::ToString(value, domain); AddParam(val); } + FORCE_INLINE void AddParam(const StringView& value, MonoDomain* domain) + { + MonoString* val = MUtils::ToString(value, domain); + AddParam(val); + } + void GetParams(void* params[8]) { for (int32 i = 0; i < Count; i++) diff --git a/Source/Engine/Scripting/Scripting.cs b/Source/Engine/Scripting/Scripting.cs index 522d0a73c..6cb04b813 100644 --- a/Source/Engine/Scripting/Scripting.cs +++ b/Source/Engine/Scripting/Scripting.cs @@ -148,9 +148,11 @@ namespace FlaxEngine /// internal static void Init() { -#if DEBUG +#if BUILD_DEBUG Debug.Logger.LogHandler.LogWrite(LogType.Info, "Using FlaxAPI in Debug"); -#else +#elif BUILD_DEVELOPMENT + Debug.Logger.LogHandler.LogWrite(LogType.Info, "Using FlaxAPI in Development"); +#elif BUILD_RELEASE Debug.Logger.LogHandler.LogWrite(LogType.Info, "Using FlaxAPI in Release"); #endif diff --git a/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.Layer.cpp b/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.Layer.cpp index 36accc384..8f01ef271 100644 --- a/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.Layer.cpp +++ b/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.Layer.cpp @@ -271,7 +271,7 @@ void MaterialGenerator::prepareLayer(MaterialLayer* layer, bool allowVisiblePara mp.Type = MaterialParameterType::Texture; // Special case for Normal Maps - auto asset = Content::LoadAsync((Guid)param->Value); + auto asset = (Texture*)::LoadAsset((Guid)param->Value, Texture::TypeInitializer); if (asset && !asset->WaitForLoaded() && asset->IsNormalMap()) mp.Type = MaterialParameterType::NormalMap; } diff --git a/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.h b/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.h index bee1efca4..157502224 100644 --- a/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.h +++ b/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.h @@ -6,7 +6,7 @@ #include "Engine/Graphics/Materials/MaterialInfo.h" #include "Engine/Graphics/Materials/MaterialParams.h" -#include "Engine/Content/Utilities/AssetsContainer.h" +#include "Engine/Content/AssetsContainer.h" #include "MaterialLayer.h" #include "Types.h" diff --git a/Source/Engine/Visject/ShaderGraph.h b/Source/Engine/Visject/ShaderGraph.h index 1ed95918a..fe24602cc 100644 --- a/Source/Engine/Visject/ShaderGraph.h +++ b/Source/Engine/Visject/ShaderGraph.h @@ -10,7 +10,7 @@ #include "Engine/Core/Collections/HashSet.h" #include "Engine/Utilities/TextWriter.h" #include "Engine/Graphics/Materials/MaterialParams.h" -#include "Engine/Content/Utilities/AssetsContainer.h" +#include "Engine/Content/AssetsContainer.h" #include "Engine/Animations/Curve.h" #define SHADER_GRAPH_MAX_CALL_STACK 100 diff --git a/Source/Engine/Visject/VisjectGraph.cpp b/Source/Engine/Visject/VisjectGraph.cpp index aafc4e9c9..abe4436dd 100644 --- a/Source/Engine/Visject/VisjectGraph.cpp +++ b/Source/Engine/Visject/VisjectGraph.cpp @@ -723,7 +723,7 @@ void VisjectExecutor::ProcessGroupTools(Box* box, Node* node, Value& value) // Asset Reference case 18: { - value = Content::LoadAsync((Guid)node->Values[0]); + value = ::LoadAsset((Guid)node->Values[0], Asset::TypeInitializer); break; } // To String diff --git a/Source/Engine/Visject/VisjectGraph.h b/Source/Engine/Visject/VisjectGraph.h index 79c923871..7be06566e 100644 --- a/Source/Engine/Visject/VisjectGraph.h +++ b/Source/Engine/Visject/VisjectGraph.h @@ -8,7 +8,7 @@ #include "Engine/Core/Math/Vector4.h" #include "Engine/Content/Asset.h" #include "Engine/Content/AssetReference.h" -#include "Engine/Content/Utilities/AssetsContainer.h" +#include "Engine/Content/AssetsContainer.h" #include "Engine/Animations/Curve.h" #define VISJECT_GRAPH_NODE_MAX_ASSETS 14 @@ -204,7 +204,7 @@ public: // Get Gameplay Global case 16: { - n->Assets[0] = Content::LoadAsync((Guid)n->Values[0]); + n->Assets[0] = ::LoadAsset((Guid)n->Values[0], Asset::TypeInitializer); break; } } diff --git a/Source/Platforms/Windows/Binaries/ThirdParty/x64/dbghelp.dll b/Source/Platforms/Windows/Binaries/ThirdParty/x64/dbghelp.dll index 8193a32a8..91a7ee8d3 100644 --- a/Source/Platforms/Windows/Binaries/ThirdParty/x64/dbghelp.dll +++ b/Source/Platforms/Windows/Binaries/ThirdParty/x64/dbghelp.dll @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:159b30d9f1bbe69ae03e0d19669d4fcb565246d81672b7034a69cef9f466dcbe -size 1369936 +oid sha256:cee97bc83e5aa825df059f2f2e4e83c0e65fe4a263aabbec0ac5476e70bc57e4 +size 1199296