Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of AssimpLibaries v0.2.3
plugins/AssimpNet.dll
Decompiled 3 hours ago
The result has been truncated due to the large size, download it to view full contents!
#define DEBUG using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using Assimp.Configs; using Assimp.Unmanaged; using Microsoft.CodeAnalysis; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyTitle("AssimpNet")] [assembly: AssemblyDescription("A .NET Wrapper for the Open Asset Import (Assimp) library.")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("Nicholas Woodfield")] [assembly: AssemblyProduct("AssimpNet")] [assembly: AssemblyCopyright("Copyright © 2012-2020 AssimpNet - Nicholas Woodfield")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("a2aee677-907b-4ec9-a9d4-a52d60542083")] [assembly: AssemblyFileVersion("5.0.0")] [assembly: AssemblyInformationalVersion("5.0.0-beta1")] [assembly: TargetFramework(".NETFramework,Version=v4.0", FrameworkDisplayName = ".NET Framework 4")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("5.0.0.0")] [module: UnverifiableCode] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] internal sealed class IsReadOnlyAttribute : Attribute { } [CompilerGenerated] [Embedded] internal sealed class IsUnmanagedAttribute : Attribute { } } namespace Assimp { public sealed class Animation : IMarshalable<Animation, AiAnimation> { private string m_name; private double m_duration; private double m_ticksPerSecond; private List<NodeAnimationChannel> m_nodeChannels; private List<MeshAnimationChannel> m_meshChannels; private List<MeshMorphAnimationChannel> m_meshMorphChannels; public string Name { get { return m_name; } set { m_name = value; } } public double DurationInTicks { get { return m_duration; } set { m_duration = value; } } public double TicksPerSecond { get { return m_ticksPerSecond; } set { m_ticksPerSecond = value; } } public bool HasNodeAnimations => m_nodeChannels.Count > 0; public int NodeAnimationChannelCount => m_nodeChannels.Count; public List<NodeAnimationChannel> NodeAnimationChannels => m_nodeChannels; public bool HasMeshAnimations => m_meshChannels.Count > 0; public int MeshAnimationChannelCount => m_meshChannels.Count; public int MeshMorphAnimationChannelCount => m_meshMorphChannels.Count; public List<MeshAnimationChannel> MeshAnimationChannels => m_meshChannels; public List<MeshMorphAnimationChannel> MeshMorphAnimationChannels => m_meshMorphChannels; bool IMarshalable<Animation, AiAnimation>.IsNativeBlittable => true; public Animation() { m_name = string.Empty; m_duration = 0.0; m_ticksPerSecond = 0.0; m_nodeChannels = new List<NodeAnimationChannel>(); m_meshChannels = new List<MeshAnimationChannel>(); m_meshMorphChannels = new List<MeshMorphAnimationChannel>(); } void IMarshalable<Animation, AiAnimation>.ToNative(IntPtr thisPtr, out AiAnimation nativeValue) { nativeValue.Name = new AiString(m_name); nativeValue.Duration = m_duration; nativeValue.TicksPerSecond = m_ticksPerSecond; nativeValue.NumChannels = (uint)NodeAnimationChannelCount; nativeValue.NumMeshChannels = (uint)MeshAnimationChannelCount; nativeValue.NumMeshMorphChannels = (uint)MeshMorphAnimationChannelCount; nativeValue.Channels = IntPtr.Zero; nativeValue.MeshChannels = IntPtr.Zero; nativeValue.MeshMorphChannels = IntPtr.Zero; if (nativeValue.NumChannels != 0) { nativeValue.Channels = MemoryHelper.ToNativeArray<NodeAnimationChannel, AiNodeAnim>(m_nodeChannels.ToArray(), arrayOfPointers: true); } if (nativeValue.NumMeshChannels != 0) { nativeValue.MeshChannels = MemoryHelper.ToNativeArray<MeshAnimationChannel, AiMeshAnim>(m_meshChannels.ToArray(), arrayOfPointers: true); } if (nativeValue.NumMeshMorphChannels != 0) { nativeValue.MeshMorphChannels = MemoryHelper.ToNativeArray<MeshMorphAnimationChannel, AiMeshMorphAnim>(m_meshMorphChannels.ToArray(), arrayOfPointers: true); } } void IMarshalable<Animation, AiAnimation>.FromNative(in AiAnimation nativeValue) { m_nodeChannels.Clear(); m_meshChannels.Clear(); m_meshMorphChannels.Clear(); m_name = AiString.GetString(in nativeValue.Name); m_duration = nativeValue.Duration; m_ticksPerSecond = nativeValue.TicksPerSecond; if (nativeValue.NumChannels != 0 && nativeValue.Channels != IntPtr.Zero) { m_nodeChannels.AddRange(MemoryHelper.FromNativeArray<NodeAnimationChannel, AiNodeAnim>(nativeValue.Channels, (int)nativeValue.NumChannels, arrayOfPointers: true)); } if (nativeValue.NumMeshChannels != 0 && nativeValue.MeshChannels != IntPtr.Zero) { m_meshChannels.AddRange(MemoryHelper.FromNativeArray<MeshAnimationChannel, AiMeshAnim>(nativeValue.MeshChannels, (int)nativeValue.NumMeshChannels, arrayOfPointers: true)); } if (nativeValue.NumMeshMorphChannels != 0 && nativeValue.MeshMorphChannels != IntPtr.Zero) { m_meshMorphChannels.AddRange(MemoryHelper.FromNativeArray<MeshMorphAnimationChannel, AiMeshMorphAnim>(nativeValue.MeshMorphChannels, (int)nativeValue.NumMeshMorphChannels, arrayOfPointers: true)); } } public static void FreeNative(IntPtr nativeValue, bool freeNative) { if (!(nativeValue == IntPtr.Zero)) { AiAnimation aiAnimation = MemoryHelper.Read<AiAnimation>(nativeValue); if (aiAnimation.NumChannels != 0 && aiAnimation.Channels != IntPtr.Zero) { MemoryHelper.FreeNativeArray<AiNodeAnim>(aiAnimation.Channels, (int)aiAnimation.NumChannels, NodeAnimationChannel.FreeNative, arrayOfPointers: true); } if (aiAnimation.NumMeshChannels != 0 && aiAnimation.MeshChannels != IntPtr.Zero) { MemoryHelper.FreeNativeArray<AiMeshAnim>(aiAnimation.MeshChannels, (int)aiAnimation.NumMeshChannels, MeshAnimationChannel.FreeNative, arrayOfPointers: true); } if (aiAnimation.NumMeshMorphChannels != 0 && aiAnimation.MeshMorphChannels != IntPtr.Zero) { MemoryHelper.FreeNativeArray<AiMeshMorphAnim>(aiAnimation.MeshMorphChannels, (int)aiAnimation.NumMeshMorphChannels, MeshMorphAnimationChannel.FreeNative, arrayOfPointers: true); } if (freeNative) { MemoryHelper.FreeMemory(nativeValue); } } } } public sealed class AssimpContext : IDisposable { private bool m_isDisposed; private Dictionary<string, PropertyConfig> m_configs; private IOSystem m_ioSystem; private ExportFormatDescription[] m_exportFormats; private string[] m_importFormats; private ImporterDescription[] m_importerDescrs; private float m_scale = 1f; private float m_xAxisRotation = 0f; private float m_yAxisRotation = 0f; private float m_zAxisRotation = 0f; private bool m_buildMatrix = false; private Matrix4x4 m_scaleRot = Matrix4x4.Identity; private IntPtr m_propStore = IntPtr.Zero; public bool IsDisposed => m_isDisposed; public float Scale { get { return m_scale; } set { if (m_scale != value) { m_scale = value; m_buildMatrix = true; } } } public float XAxisRotation { get { return m_xAxisRotation; } set { if (m_xAxisRotation != value) { m_xAxisRotation = value; m_buildMatrix = true; } } } public float YAxisRotation { get { return m_yAxisRotation; } set { if (m_yAxisRotation != value) { m_yAxisRotation = value; m_buildMatrix = true; } } } public float ZAxisRotation { get { return m_zAxisRotation; } set { if (m_zAxisRotation != value) { m_zAxisRotation = value; m_buildMatrix = true; } } } public bool UsingCustomIOSystem => m_ioSystem != null && !m_ioSystem.IsDisposed; public Dictionary<string, PropertyConfig> PropertyConfigurations => m_configs; public AssimpContext() { m_configs = new Dictionary<string, PropertyConfig>(); } public Scene ImportFileFromStream(Stream stream, string formatHint = null) { return ImportFileFromStream(stream, PostProcessSteps.None, formatHint); } public Scene ImportFileFromStream(Stream stream, PostProcessSteps postProcessFlags, string formatHint = null) { CheckDisposed(); if (stream == null || !stream.CanRead) { throw new AssimpException("stream", "Can't read from the stream it's null or write-only"); } IntPtr intPtr = IntPtr.Zero; PrepareImport(); try { intPtr = AssimpLibrary.Instance.ImportFileFromStream(stream, PostProcessSteps.None, formatHint, m_propStore); if (intPtr == IntPtr.Zero) { throw new AssimpException("Error importing file: " + AssimpLibrary.Instance.GetErrorString()); } TransformScene(intPtr); if (postProcessFlags != PostProcessSteps.None) { intPtr = AssimpLibrary.Instance.ApplyPostProcessing(intPtr, postProcessFlags); } return Scene.FromUnmanagedScene(intPtr); } finally { CleanupImport(); if (intPtr != IntPtr.Zero) { AssimpLibrary.Instance.ReleaseImport(intPtr); } } } public Scene ImportFile(string file) { return ImportFile(file, PostProcessSteps.None); } public Scene ImportFile(string file, PostProcessSteps postProcessFlags) { CheckDisposed(); IntPtr intPtr = IntPtr.Zero; IntPtr fileIO = IntPtr.Zero; if (UsingCustomIOSystem) { fileIO = m_ioSystem.AiFileIO; } else if (string.IsNullOrEmpty(file) || !File.Exists(file)) { throw new FileNotFoundException("Filename was null or could not be found", file); } PrepareImport(); try { intPtr = AssimpLibrary.Instance.ImportFile(file, PostProcessSteps.None, fileIO, m_propStore); if (intPtr == IntPtr.Zero) { throw new AssimpException("Error importing file: " + AssimpLibrary.Instance.GetErrorString()); } TransformScene(intPtr); if (postProcessFlags != PostProcessSteps.None) { intPtr = AssimpLibrary.Instance.ApplyPostProcessing(intPtr, postProcessFlags); } return Scene.FromUnmanagedScene(intPtr); } finally { CleanupImport(); if (intPtr != IntPtr.Zero) { AssimpLibrary.Instance.ReleaseImport(intPtr); } } } public bool ExportFile(Scene scene, string fileName, string exportFormatId) { return ExportFile(scene, fileName, exportFormatId, PostProcessSteps.None); } public bool ExportFile(Scene scene, string fileName, string exportFormatId, PostProcessSteps preProcessing) { CheckDisposed(); IntPtr zero = IntPtr.Zero; IntPtr intPtr = IntPtr.Zero; if (scene == null) { throw new ArgumentNullException("scene", "Scene must exist."); } if (!TestIfExportIdIsValid(exportFormatId)) { return false; } try { intPtr = Scene.ToUnmanagedScene(scene); ReturnCode returnCode = AssimpLibrary.Instance.ExportScene(intPtr, exportFormatId, fileName, zero, preProcessing); return returnCode == ReturnCode.Success; } finally { if (intPtr != IntPtr.Zero) { Scene.FreeUnmanagedScene(intPtr); } } } public ExportDataBlob ExportToBlob(Scene scene, string exportFormatId) { return ExportToBlob(scene, exportFormatId, PostProcessSteps.None); } public ExportDataBlob ExportToBlob(Scene scene, string exportFormatId, PostProcessSteps preProcessing) { CheckDisposed(); IntPtr zero = IntPtr.Zero; IntPtr intPtr = IntPtr.Zero; if (scene == null) { throw new ArgumentNullException("scene", "Scene must exist."); } if (!TestIfExportIdIsValid(exportFormatId)) { return null; } try { intPtr = Scene.ToUnmanagedScene(scene); return AssimpLibrary.Instance.ExportSceneToBlob(intPtr, exportFormatId, preProcessing); } finally { if (intPtr != IntPtr.Zero) { Scene.FreeUnmanagedScene(intPtr); } } } public bool ConvertFromFileToFile(string inputFilename, string outputFilename, string exportFormatId) { return ConvertFromFileToFile(inputFilename, PostProcessSteps.None, outputFilename, exportFormatId, PostProcessSteps.None); } public bool ConvertFromFileToFile(string inputFilename, string outputFilename, string exportFormatId, PostProcessSteps exportProcessSteps) { return ConvertFromFileToFile(inputFilename, PostProcessSteps.None, outputFilename, exportFormatId, exportProcessSteps); } public bool ConvertFromFileToFile(string inputFilename, PostProcessSteps importProcessSteps, string outputFilename, string exportFormatId, PostProcessSteps exportProcessSteps) { CheckDisposed(); if (!TestIfExportIdIsValid(exportFormatId)) { return false; } IntPtr intPtr = IntPtr.Zero; IntPtr fileIO = IntPtr.Zero; if (UsingCustomIOSystem) { fileIO = m_ioSystem.AiFileIO; } else if (string.IsNullOrEmpty(inputFilename) || !File.Exists(inputFilename)) { throw new FileNotFoundException("Filename was null or could not be found", inputFilename); } PrepareImport(); try { intPtr = AssimpLibrary.Instance.ImportFile(inputFilename, PostProcessSteps.None, fileIO, m_propStore); if (intPtr == IntPtr.Zero) { throw new AssimpException("Error importing file: " + AssimpLibrary.Instance.GetErrorString()); } TransformScene(intPtr); if (importProcessSteps != PostProcessSteps.None) { intPtr = AssimpLibrary.Instance.ApplyPostProcessing(intPtr, importProcessSteps); } ReturnCode returnCode = AssimpLibrary.Instance.ExportScene(intPtr, exportFormatId, outputFilename, fileIO, exportProcessSteps); return returnCode == ReturnCode.Success; } finally { CleanupImport(); if (intPtr != IntPtr.Zero) { AssimpLibrary.Instance.ReleaseImport(intPtr); } } } public ExportDataBlob ConvertFromFileToBlob(string inputFilename, string exportFormatId) { return ConvertFromFileToBlob(inputFilename, PostProcessSteps.None, exportFormatId, PostProcessSteps.None); } public ExportDataBlob ConvertFromFileToBlob(string inputFilename, string exportFormatId, PostProcessSteps exportProcessSteps) { return ConvertFromFileToBlob(inputFilename, PostProcessSteps.None, exportFormatId, exportProcessSteps); } public ExportDataBlob ConvertFromFileToBlob(string inputFilename, PostProcessSteps importProcessSteps, string exportFormatId, PostProcessSteps exportProcessSteps) { CheckDisposed(); if (!TestIfExportIdIsValid(exportFormatId)) { return null; } IntPtr intPtr = IntPtr.Zero; IntPtr fileIO = IntPtr.Zero; if (UsingCustomIOSystem) { fileIO = m_ioSystem.AiFileIO; } else if (string.IsNullOrEmpty(inputFilename) || !File.Exists(inputFilename)) { throw new FileNotFoundException("Filename was null or could not be found", inputFilename); } PrepareImport(); try { intPtr = AssimpLibrary.Instance.ImportFile(inputFilename, PostProcessSteps.None, fileIO, m_propStore); if (intPtr == IntPtr.Zero) { throw new AssimpException("Error importing file: " + AssimpLibrary.Instance.GetErrorString()); } TransformScene(intPtr); if (importProcessSteps != PostProcessSteps.None) { intPtr = AssimpLibrary.Instance.ApplyPostProcessing(intPtr, importProcessSteps); } return AssimpLibrary.Instance.ExportSceneToBlob(intPtr, exportFormatId, exportProcessSteps); } finally { CleanupImport(); if (intPtr != IntPtr.Zero) { AssimpLibrary.Instance.ReleaseImport(intPtr); } } } public bool ConvertFromStreamToFile(Stream inputStream, string importFormatHint, string outputFilename, string exportFormatId) { return ConvertFromStreamToFile(inputStream, importFormatHint, PostProcessSteps.None, outputFilename, exportFormatId, PostProcessSteps.None); } public bool ConvertFromStreamToFile(Stream inputStream, string importFormatHint, string outputFilename, string exportFormatId, PostProcessSteps exportProcessSteps) { return ConvertFromStreamToFile(inputStream, importFormatHint, PostProcessSteps.None, outputFilename, exportFormatId, exportProcessSteps); } public bool ConvertFromStreamToFile(Stream inputStream, string importFormatHint, PostProcessSteps importProcessSteps, string outputFilename, string exportFormatId, PostProcessSteps exportProcessSteps) { CheckDisposed(); if (inputStream == null || !inputStream.CanRead) { throw new AssimpException("stream", "Can't read from the stream it's null or write-only"); } if (!TestIfExportIdIsValid(exportFormatId)) { return false; } IntPtr intPtr = IntPtr.Zero; PrepareImport(); try { intPtr = AssimpLibrary.Instance.ImportFileFromStream(inputStream, importProcessSteps, importFormatHint, m_propStore); if (intPtr == IntPtr.Zero) { throw new AssimpException("Error importing file: " + AssimpLibrary.Instance.GetErrorString()); } TransformScene(intPtr); if (importProcessSteps != PostProcessSteps.None) { intPtr = AssimpLibrary.Instance.ApplyPostProcessing(intPtr, importProcessSteps); } ReturnCode returnCode = AssimpLibrary.Instance.ExportScene(intPtr, exportFormatId, outputFilename, exportProcessSteps); return returnCode == ReturnCode.Success; } finally { CleanupImport(); if (intPtr != IntPtr.Zero) { AssimpLibrary.Instance.ReleaseImport(intPtr); } } } public ExportDataBlob ConvertFromStreamToBlob(Stream inputStream, string importFormatHint, string exportFormatId) { return ConvertFromStreamToBlob(inputStream, importFormatHint, PostProcessSteps.None, exportFormatId, PostProcessSteps.None); } public ExportDataBlob ConvertFromStreamToBlob(Stream inputStream, string importFormatHint, string exportFormatId, PostProcessSteps exportProcessSteps) { return ConvertFromStreamToBlob(inputStream, importFormatHint, PostProcessSteps.None, exportFormatId, exportProcessSteps); } public ExportDataBlob ConvertFromStreamToBlob(Stream inputStream, string importFormatHint, PostProcessSteps importProcessSteps, string exportFormatId, PostProcessSteps exportProcessSteps) { CheckDisposed(); if (inputStream == null || !inputStream.CanRead) { throw new AssimpException("stream", "Can't read from the stream it's null or write-only"); } if (!TestIfExportIdIsValid(exportFormatId)) { return null; } IntPtr intPtr = IntPtr.Zero; PrepareImport(); try { intPtr = AssimpLibrary.Instance.ImportFileFromStream(inputStream, importProcessSteps, importFormatHint, m_propStore); if (intPtr == IntPtr.Zero) { throw new AssimpException("Error importing file: " + AssimpLibrary.Instance.GetErrorString()); } TransformScene(intPtr); if (importProcessSteps != PostProcessSteps.None) { intPtr = AssimpLibrary.Instance.ApplyPostProcessing(intPtr, importProcessSteps); } return AssimpLibrary.Instance.ExportSceneToBlob(intPtr, exportFormatId, exportProcessSteps); } finally { CleanupImport(); if (intPtr != IntPtr.Zero) { AssimpLibrary.Instance.ReleaseImport(intPtr); } } } public void SetIOSystem(IOSystem ioSystem) { if (ioSystem == null || ioSystem.IsDisposed) { ioSystem = null; } m_ioSystem = ioSystem; } public void RemoveIOSystem() { m_ioSystem = null; } public ExportFormatDescription[] GetSupportedExportFormats() { QueryExportFormatsIfNecessary(); return (ExportFormatDescription[])m_exportFormats.Clone(); } public string[] GetSupportedImportFormats() { QueryImportFormatsIfNecessary(); return (string[])m_importFormats.Clone(); } public ImporterDescription[] GetImporterDescriptions() { QueryImporterDescriptionsIfNecessary(); return (ImporterDescription[])m_importerDescrs.Clone(); } public ImporterDescription GetImporterDescriptionFor(string fileExtension) { if (string.IsNullOrEmpty(fileExtension)) { return null; } QueryImporterDescriptionsIfNecessary(); if (fileExtension.StartsWith(".") && fileExtension.Length >= 2) { fileExtension = fileExtension.Substring(1); } ImporterDescription[] importerDescrs = m_importerDescrs; foreach (ImporterDescription importerDescription in importerDescrs) { string[] fileExtensions = importerDescription.FileExtensions; foreach (string b in fileExtensions) { if (string.Equals(fileExtension, b, StringComparison.Ordinal)) { return importerDescription; } } } return null; } public bool IsImportFormatSupported(string format) { return AssimpLibrary.Instance.IsExtensionSupported(format); } public bool IsExportFormatSupported(string format) { if (string.IsNullOrEmpty(format)) { return false; } QueryExportFormatsIfNecessary(); if (format.StartsWith(".") && format.Length >= 2) { format = format.Substring(1); } ExportFormatDescription[] exportFormats = m_exportFormats; foreach (ExportFormatDescription exportFormatDescription in exportFormats) { if (string.Equals(exportFormatDescription.FileExtension, format, StringComparison.Ordinal)) { return true; } } return false; } public void SetConfig(PropertyConfig config) { if (config != null) { string name = config.Name; m_configs[config.Name] = config; } } public void RemoveConfig(string configName) { if (!string.IsNullOrEmpty(configName) && m_configs.TryGetValue(configName, out var _)) { m_configs.Remove(configName); } } public void RemoveConfigs() { m_configs.Clear(); } public bool ContainsConfig(string configName) { if (string.IsNullOrEmpty(configName)) { return false; } return m_configs.ContainsKey(configName); } public void Dispose() { Dispose(disposing: true); GC.SuppressFinalize(this); } private void Dispose(bool disposing) { if (!m_isDisposed) { if (disposing && UsingCustomIOSystem) { m_ioSystem.Dispose(); } m_isDisposed = true; } } private void CheckDisposed() { if (m_isDisposed) { throw new ObjectDisposedException("Assimp Context has been disposed."); } } private void QueryExportFormatsIfNecessary() { if (m_exportFormats == null) { m_exportFormats = AssimpLibrary.Instance.GetExportFormatDescriptions(); } } private void QueryImportFormatsIfNecessary() { if (m_importFormats == null) { m_importFormats = AssimpLibrary.Instance.GetExtensionList(); } } private void QueryImporterDescriptionsIfNecessary() { if (m_importerDescrs == null) { m_importerDescrs = AssimpLibrary.Instance.GetImporterDescriptions(); } } private void BuildMatrix() { if (m_buildMatrix) { Matrix4x4 matrix4x = Matrix4x4.FromScaling(new Vector3D(m_scale, m_scale, m_scale)); Matrix4x4 matrix4x2 = Matrix4x4.FromRotationX(m_xAxisRotation * ((float)Math.PI / 180f)); Matrix4x4 matrix4x3 = Matrix4x4.FromRotationY(m_yAxisRotation * ((float)Math.PI / 180f)); Matrix4x4 matrix4x4 = Matrix4x4.FromRotationZ(m_zAxisRotation * ((float)Math.PI / 180f)); m_scaleRot = matrix4x * (matrix4x2 * matrix4x3 * matrix4x4); } m_buildMatrix = false; } private bool TransformScene(IntPtr scene) { BuildMatrix(); try { if (!m_scaleRot.IsIdentity) { AiScene aiScene = MemoryHelper.MarshalStructure<AiScene>(scene); if (aiScene.RootNode == IntPtr.Zero) { return false; } IntPtr intPtr = MemoryHelper.AddIntPtr(aiScene.RootNode, MemoryHelper.SizeOf<AiString>()); Matrix4x4 matrix4x = MemoryHelper.Read<Matrix4x4>(intPtr); MemoryHelper.Write<Matrix4x4>(intPtr, matrix4x * m_scaleRot); return true; } } catch (Exception) { } return false; } private void CreateConfigs() { m_propStore = AssimpLibrary.Instance.CreatePropertyStore(); foreach (KeyValuePair<string, PropertyConfig> config in m_configs) { config.Value.ApplyValue(m_propStore); } } private void ReleaseConfigs() { if (m_propStore != IntPtr.Zero) { AssimpLibrary.Instance.ReleasePropertyStore(m_propStore); } } private void PrepareImport() { CreateConfigs(); } private void CleanupImport() { ReleaseConfigs(); if (UsingCustomIOSystem) { m_ioSystem.CloseAllFiles(); } } private bool TestIfExportIdIsValid(string exportFormatId) { if (m_exportFormats == null) { m_exportFormats = AssimpLibrary.Instance.GetExportFormatDescriptions(); } ExportFormatDescription[] exportFormats = m_exportFormats; foreach (ExportFormatDescription exportFormatDescription in exportFormats) { if (exportFormatDescription.FormatId.Equals(exportFormatId, StringComparison.Ordinal)) { return true; } } IEnumerable<LogStream> attachedLogStreams = LogStream.GetAttachedLogStreams(); foreach (LogStream item in attachedLogStreams) { item.Log($"Info, Invalid export format: {exportFormatId}"); } return false; } } public class AssimpException : Exception { public AssimpException() { } public AssimpException(string msg) : base(msg) { } public AssimpException(string paramName, string msg) : base("Parameter: " + paramName + " Error: " + msg) { } public AssimpException(string msg, Exception innerException) : base(msg, innerException) { } } public sealed class Bone : IMarshalable<Bone, AiBone> { private string m_name; private List<VertexWeight> m_weights; private Matrix4x4 m_offsetMatrix; public string Name { get { return m_name; } set { m_name = value; } } public int VertexWeightCount => m_weights.Count; public bool HasVertexWeights => m_weights.Count > 0; public List<VertexWeight> VertexWeights => m_weights; public Matrix4x4 OffsetMatrix { get { return m_offsetMatrix; } set { m_offsetMatrix = value; } } bool IMarshalable<Bone, AiBone>.IsNativeBlittable => true; public Bone() { m_name = null; m_offsetMatrix = Matrix3x3.Identity; m_weights = new List<VertexWeight>(); } public Bone(string name, Matrix3x3 offsetMatrix, VertexWeight[] weights) { m_name = name; m_offsetMatrix = offsetMatrix; m_weights = new List<VertexWeight>(); if (weights != null) { m_weights.AddRange(weights); } } void IMarshalable<Bone, AiBone>.ToNative(IntPtr thisPtr, out AiBone nativeValue) { nativeValue.Name = new AiString(m_name); nativeValue.OffsetMatrix = m_offsetMatrix; nativeValue.NumWeights = (uint)m_weights.Count; nativeValue.Weights = IntPtr.Zero; if (nativeValue.NumWeights != 0) { nativeValue.Weights = MemoryHelper.ToNativeArray(m_weights.ToArray()); } } void IMarshalable<Bone, AiBone>.FromNative(in AiBone nativeValue) { m_name = AiString.GetString(in nativeValue.Name); m_offsetMatrix = nativeValue.OffsetMatrix; m_weights.Clear(); if (nativeValue.NumWeights != 0 && nativeValue.Weights != IntPtr.Zero) { m_weights.AddRange(MemoryHelper.FromNativeArray<VertexWeight>(nativeValue.Weights, (int)nativeValue.NumWeights)); } } public static void FreeNative(IntPtr nativeValue, bool freeNative) { if (!(nativeValue == IntPtr.Zero)) { AiBone aiBone = MemoryHelper.Read<AiBone>(nativeValue); int num = MemoryHelper.Read<int>(MemoryHelper.AddIntPtr(nativeValue, MemoryHelper.SizeOf<AiString>())); IntPtr intPtr = MemoryHelper.AddIntPtr(nativeValue, MemoryHelper.SizeOf<AiString>() + 4); if (aiBone.NumWeights != 0 && aiBone.Weights != IntPtr.Zero) { MemoryHelper.FreeMemory(aiBone.Weights); } if (freeNative) { MemoryHelper.FreeMemory(nativeValue); } } } } public struct BoundingBox : IEquatable<BoundingBox> { public Vector3D Min; public Vector3D Max; public BoundingBox(Vector3D min, Vector3D max) { Min = min; Max = max; } public static bool operator ==(BoundingBox a, BoundingBox b) { return a.Min == b.Min && a.Max == b.Max; } public static bool operator !=(BoundingBox a, BoundingBox b) { return a.Min != b.Min || a.Max != b.Max; } public bool Equals(BoundingBox other) { return Min == other.Min && Max == other.Max; } public override bool Equals(object obj) { if (obj is BoundingBox) { return Equals((BoundingBox)obj); } return false; } public override int GetHashCode() { return Min.GetHashCode() + Max.GetHashCode(); } public override string ToString() { CultureInfo currentCulture = CultureInfo.CurrentCulture; return string.Format(currentCulture, "{{Min:{0} Max:{1}}", new object[2] { Min.ToString(), Max.ToString() }); } } public sealed class Camera : IMarshalable<Camera, AiCamera> { private string m_name; private Vector3D m_position; private Vector3D m_up; private Vector3D m_direction; private float m_fieldOfView; private float m_clipPlaneNear; private float m_clipPlaneFar; private float m_aspectRatio; public string Name { get { return m_name; } set { m_name = value; } } public Vector3D Position { get { return m_position; } set { m_position = value; } } public Vector3D Up { get { return m_up; } set { m_up = value; } } public Vector3D Direction { get { return m_direction; } set { m_direction = value; } } public float FieldOfview { get { return m_fieldOfView; } set { m_fieldOfView = value; } } public float ClipPlaneNear { get { return m_clipPlaneNear; } set { m_clipPlaneNear = value; } } public float ClipPlaneFar { get { return m_clipPlaneFar; } set { m_clipPlaneFar = value; } } public float AspectRatio { get { return m_aspectRatio; } set { m_aspectRatio = value; } } public Matrix4x4 ViewMatrix { get { Vector3D direction = m_direction; direction.Normalize(); Vector3D up = m_up; up.Normalize(); Vector3D a = Vector3D.Cross(m_up, m_direction); direction.Normalize(); Matrix4x4 result = default(Matrix4x4); result.A1 = a.X; result.A2 = a.Y; result.A3 = a.Z; result.A4 = 0f; result.B1 = up.X; result.B2 = up.Y; result.B3 = up.Z; result.B4 = 0f; result.C1 = direction.X; result.C2 = direction.Y; result.C3 = direction.Z; result.C4 = 0f; result.D1 = 0f - Vector3D.Dot(a, m_position); result.D2 = 0f - Vector3D.Dot(up, m_position); result.D3 = 0f - Vector3D.Dot(direction, m_position); result.D4 = 1f; return result; } } bool IMarshalable<Camera, AiCamera>.IsNativeBlittable => true; public Camera() { m_name = string.Empty; } void IMarshalable<Camera, AiCamera>.ToNative(IntPtr thisPtr, out AiCamera nativeValue) { nativeValue.Name = new AiString(m_name); nativeValue.Position = m_position; nativeValue.LookAt = m_direction; nativeValue.Up = m_up; nativeValue.HorizontalFOV = m_fieldOfView; nativeValue.ClipPlaneFar = m_clipPlaneFar; nativeValue.ClipPlaneNear = m_clipPlaneNear; nativeValue.Aspect = m_aspectRatio; } void IMarshalable<Camera, AiCamera>.FromNative(in AiCamera nativeValue) { m_name = AiString.GetString(in nativeValue.Name); m_position = nativeValue.Position; m_direction = nativeValue.LookAt; m_up = nativeValue.Up; m_fieldOfView = nativeValue.HorizontalFOV; m_clipPlaneFar = nativeValue.ClipPlaneFar; m_clipPlaneNear = nativeValue.ClipPlaneNear; m_aspectRatio = nativeValue.Aspect; } public static void FreeNative(IntPtr nativeValue, bool freeNative) { if (nativeValue != IntPtr.Zero && freeNative) { MemoryHelper.FreeMemory(nativeValue); } } } public struct Color3D { public float R; public float G; public float B; public float this[int index] { get { return index switch { 0 => R, 1 => G, 2 => B, _ => 0f, }; } set { switch (index) { case 0: R = value; break; case 1: G = value; break; case 2: B = value; break; } } } public Color3D(float r, float g, float b) { R = r; G = g; B = b; } public Color3D(float value) { R = value; G = value; B = value; } public bool IsBlack() { float num = 0.01f; return Math.Abs(R) < num && Math.Abs(G) < num && Math.Abs(B) < num; } public static Color3D operator +(Color3D a, Color3D b) { Color3D result = default(Color3D); result.R = a.R + b.R; result.G = a.G + b.G; result.B = a.B + b.B; return result; } public static Color3D operator +(Color3D color, float value) { Color3D result = default(Color3D); result.R = color.R + value; result.G = color.G + value; result.B = color.B + value; return result; } public static Color3D operator +(float value, Color3D color) { Color3D result = default(Color3D); result.R = color.R + value; result.G = color.G + value; result.B = color.B + value; return result; } public static Color3D operator -(Color3D a, Color3D b) { Color3D result = default(Color3D); result.R = a.R - b.R; result.G = a.G - b.G; result.B = a.B - b.B; return result; } public static Color3D operator -(Color3D color, float value) { Color3D result = default(Color3D); result.R = color.R - value; result.G = color.G - value; result.B = color.B - value; return result; } public static Color3D operator -(float value, Color3D color) { Color3D result = default(Color3D); result.R = value - color.R; result.G = value - color.G; result.B = value - color.B; return result; } public static Color3D operator *(Color3D a, Color3D b) { Color3D result = default(Color3D); result.R = a.R * b.R; result.G = a.G * b.G; result.B = a.B * b.B; return result; } public static Color3D operator *(Color3D value, float scale) { Color3D result = default(Color3D); result.R = value.R * scale; result.G = value.G * scale; result.B = value.B * scale; return result; } public static Color3D operator *(float scale, Color3D value) { Color3D result = default(Color3D); result.R = value.R * scale; result.G = value.G * scale; result.B = value.B * scale; return result; } public static Color3D operator /(Color3D a, Color3D b) { Color3D result = default(Color3D); result.R = a.R / b.R; result.G = a.G / b.G; result.B = a.B / b.B; return result; } public static Color3D operator /(Color3D color, float divisor) { float num = 1f / divisor; Color3D result = default(Color3D); result.R = color.R * num; result.G = color.G * num; result.B = color.B * num; return result; } public static bool operator ==(Color3D a, Color3D b) { return a.R == b.R && a.G == b.G && a.B == b.B; } public static bool operator !=(Color3D a, Color3D b) { return a.R != b.R || a.G != b.G || a.B != b.B; } public bool Equals(Color3D other) { return R == other.R && G == other.G && B == other.B; } public override bool Equals(object obj) { if (obj is Color3D) { return Equals((Color3D)obj); } return false; } public override int GetHashCode() { return R.GetHashCode() + G.GetHashCode() + B.GetHashCode(); } public override string ToString() { CultureInfo currentCulture = CultureInfo.CurrentCulture; return string.Format(currentCulture, "{{R:{0} G:{1} B:{2}}}", new object[3] { R.ToString(currentCulture), G.ToString(currentCulture), B.ToString(currentCulture) }); } } public struct Color4D : IEquatable<Color4D> { public float R; public float G; public float B; public float A; public float this[int index] { get { return index switch { 0 => R, 1 => G, 2 => B, 3 => A, _ => 0f, }; } set { switch (index) { case 0: R = value; break; case 1: G = value; break; case 2: B = value; break; case 3: A = value; break; } } } public Color4D(float r, float g, float b, float a) { R = r; G = g; B = b; A = a; } public Color4D(float r, float g, float b) { R = r; G = g; B = b; A = 1f; } public Color4D(float value) { R = value; G = value; B = value; A = value; } public Color4D(Color3D rgb) { R = rgb.R; G = rgb.G; B = rgb.B; A = 1f; } public Color4D(Color3D rgb, float alpha) { R = rgb.R; G = rgb.G; B = rgb.B; A = alpha; } public bool IsBlack() { float num = 0.01f; return Math.Abs(R) < num && Math.Abs(G) < num && Math.Abs(B) < num; } public static Color4D operator +(Color4D a, Color4D b) { Color4D result = default(Color4D); result.R = a.R + b.R; result.G = a.G + b.G; result.B = a.B + b.B; result.A = a.A + b.A; return result; } public static Color4D operator +(Color4D color, float value) { Color4D result = default(Color4D); result.R = color.R + value; result.G = color.G + value; result.B = color.B + value; result.A = color.A + value; return result; } public static Color4D operator +(float value, Color4D color) { Color4D result = default(Color4D); result.R = color.R + value; result.G = color.G + value; result.B = color.B + value; result.A = color.A + value; return result; } public static Color4D operator -(Color4D a, Color4D b) { Color4D result = default(Color4D); result.R = a.R - b.R; result.G = a.G - b.G; result.B = a.B - b.B; result.A = a.A - b.A; return result; } public static Color4D operator -(Color4D color, float value) { Color4D result = default(Color4D); result.R = color.R - value; result.G = color.G - value; result.B = color.B - value; result.A = color.A - value; return result; } public static Color4D operator -(float value, Color4D color) { Color4D result = default(Color4D); result.R = value - color.R; result.G = value - color.G; result.B = value - color.B; result.A = value - color.A; return result; } public static Color4D operator *(Color4D a, Color4D b) { Color4D result = default(Color4D); result.R = a.R * b.R; result.G = a.G * b.G; result.B = a.B * b.B; result.A = a.A * b.A; return result; } public static Color4D operator *(Color4D value, float scale) { Color4D result = default(Color4D); result.R = value.R * scale; result.G = value.G * scale; result.B = value.B * scale; result.A = value.A * scale; return result; } public static Color4D operator *(float scale, Color4D value) { Color4D result = default(Color4D); result.R = value.R * scale; result.G = value.G * scale; result.B = value.B * scale; result.A = value.A * scale; return result; } public static Color4D operator /(Color4D a, Color4D b) { Color4D result = default(Color4D); result.R = a.R / b.R; result.G = a.G / b.G; result.B = a.B / b.B; result.A = a.A / b.A; return result; } public static Color4D operator /(Color4D color, float divisor) { float num = 1f / divisor; Color4D result = default(Color4D); result.R = color.R * num; result.G = color.G * num; result.B = color.B * num; result.A = color.A * num; return result; } public static bool operator ==(Color4D a, Color4D b) { return a.R == b.R && a.G == b.G && a.B == b.B && a.A == b.A; } public static bool operator !=(Color4D a, Color4D b) { return a.R != b.R || a.G != b.G || a.B != b.B || a.A != b.A; } public bool Equals(Color4D other) { return R == other.R && G == other.G && B == other.B && A == other.A; } public override bool Equals(object obj) { if (obj is Color4D) { return Equals((Color4D)obj); } return false; } public override int GetHashCode() { return R.GetHashCode() + G.GetHashCode() + B.GetHashCode() + A.GetHashCode(); } public override string ToString() { CultureInfo currentCulture = CultureInfo.CurrentCulture; return string.Format(currentCulture, "{{R:{0} G:{1} B:{2} A:{3}}}", R.ToString(currentCulture), G.ToString(currentCulture), B.ToString(currentCulture), A.ToString(currentCulture)); } } public sealed class EmbeddedTexture : IMarshalable<EmbeddedTexture, AiTexture> { private string m_filename; private bool m_isCompressed; private int m_width; private int m_height; private Texel[] m_nonCompressedData; private byte[] m_compressedData; private string m_compressedFormatHint; public string Filename { get { return m_filename; } set { m_filename = value; } } public bool IsCompressed => m_isCompressed; public int Width => m_width; public int Height => m_height; public bool HasNonCompressedData => m_nonCompressedData != null || m_nonCompressedData.Length != 0; public int NonCompressedDataSize => (m_nonCompressedData != null) ? m_nonCompressedData.Length : 0; public Texel[] NonCompressedData => m_nonCompressedData; public bool HasCompressedData => m_compressedData != null || m_compressedData.Length != 0; public int CompressedDataSize => (m_compressedData != null) ? m_compressedData.Length : 0; public byte[] CompressedData => m_compressedData; public string CompressedFormatHint => m_compressedFormatHint; bool IMarshalable<EmbeddedTexture, AiTexture>.IsNativeBlittable => true; public EmbeddedTexture() { m_isCompressed = false; } public EmbeddedTexture(string compressedFormatHint, byte[] compressedData, string originalFileName = "") { m_filename = originalFileName; m_compressedFormatHint = compressedFormatHint; m_compressedData = compressedData; m_isCompressed = true; m_width = 0; m_height = 0; m_nonCompressedData = null; } public EmbeddedTexture(int width, int height, Texel[] uncompressedData, string originalFileName = "") { m_filename = originalFileName; m_width = width; m_height = height; m_nonCompressedData = uncompressedData; if (m_width * m_height != NonCompressedDataSize) { throw new ArgumentException("Texel data size does not match width * height."); } m_isCompressed = false; m_compressedFormatHint = null; m_compressedData = null; } void IMarshalable<EmbeddedTexture, AiTexture>.ToNative(IntPtr thisPtr, out AiTexture nativeValue) { nativeValue.Filename = new AiString(m_filename); if (IsCompressed) { nativeValue.Width = (uint)CompressedDataSize; nativeValue.Height = 0u; nativeValue.Data = IntPtr.Zero; if (CompressedDataSize > 0) { nativeValue.Data = MemoryHelper.ToNativeArray(m_compressedData); } nativeValue.SetFormatHint(m_compressedFormatHint); } else { nativeValue.Width = (uint)m_width; nativeValue.Height = (uint)m_height; nativeValue.Data = IntPtr.Zero; if (NonCompressedDataSize > 0) { nativeValue.Data = MemoryHelper.ToNativeArray(m_nonCompressedData); } nativeValue.SetFormatHint(null); } } void IMarshalable<EmbeddedTexture, AiTexture>.FromNative(in AiTexture nativeValue) { m_filename = AiString.GetString(in nativeValue.Filename); m_isCompressed = nativeValue.Height == 0; if (IsCompressed) { m_width = 0; m_height = 0; m_nonCompressedData = null; m_compressedData = null; if (nativeValue.Width != 0 && nativeValue.Data != IntPtr.Zero) { m_compressedData = MemoryHelper.FromNativeArray<byte>(nativeValue.Data, (int)nativeValue.Width); } m_compressedFormatHint = AiTexture.GetFormatHint(in nativeValue); return; } m_compressedData = null; m_compressedFormatHint = null; m_nonCompressedData = null; m_width = (int)nativeValue.Width; m_height = (int)nativeValue.Height; int num = m_width * m_height; if (num > 0 && nativeValue.Data != IntPtr.Zero) { m_nonCompressedData = MemoryHelper.FromNativeArray<Texel>(nativeValue.Data, num); } } public static void FreeNative(IntPtr nativeValue, bool freeNative) { if (!(nativeValue == IntPtr.Zero)) { AiTexture aiTexture = MemoryHelper.Read<AiTexture>(nativeValue); if (aiTexture.Width != 0 && aiTexture.Data != IntPtr.Zero) { MemoryHelper.FreeMemory(aiTexture.Data); } if (freeNative) { MemoryHelper.FreeMemory(nativeValue); } } } } public enum MetaDataType { Bool, Int32, UInt64, Float, Double, String, Vector3D } [Flags] public enum PostProcessSteps : uint { None = 0u, CalculateTangentSpace = 1u, JoinIdenticalVertices = 2u, MakeLeftHanded = 4u, Triangulate = 8u, RemoveComponent = 0x10u, GenerateNormals = 0x20u, GenerateSmoothNormals = 0x40u, SplitLargeMeshes = 0x80u, PreTransformVertices = 0x100u, LimitBoneWeights = 0x200u, ValidateDataStructure = 0x400u, ImproveCacheLocality = 0x800u, RemoveRedundantMaterials = 0x1000u, FixInFacingNormals = 0x2000u, SortByPrimitiveType = 0x8000u, FindDegenerates = 0x10000u, FindInvalidData = 0x20000u, GenerateUVCoords = 0x40000u, TransformUVCoords = 0x80000u, FindInstances = 0x100000u, OptimizeMeshes = 0x200000u, OptimizeGraph = 0x400000u, FlipUVs = 0x800000u, FlipWindingOrder = 0x1000000u, SplitByBoneCount = 0x2000000u, Debone = 0x4000000u, GlobalScale = 0x8000000u, EmbedTextures = 0x10000000u, ForceGenerateNormals = 0x20000000u, DropNormals = 0x40000000u, GenerateBoundingBoxes = 0x80000000u } [Flags] public enum ExcludeComponent { None = 0, Normals = 2, TangentBasis = 4, Colors = 8, TexCoords = 0x10, Boneweights = 0x20, Animations = 0x40, Textures = 0x80, Lights = 0x100, Cameras = 0x200, Meshes = 0x400, Materials = 0x800 } [Flags] public enum PrimitiveType { Point = 1, Line = 2, Triangle = 4, Polygon = 8 } public enum AnimationBehaviour { Default, Constant, Linear, Repeat } public enum MeshMorphingMethod { None, VertexBlend, MorphNormalized, MorphRelative } public enum LightSourceType { Undefined, Directional, Point, Spot, Ambient, Area } public enum BlendMode { Default, Additive } public enum ShadingMode { None, Flat, Gouraud, Phong, Blinn, Toon, OrenNayar, Minnaert, CookTorrance, NoShading, Fresnel } [Flags] public enum TextureFlags { Invert = 1, UseAlpha = 2, IgnoreAlpha = 4 } public enum TextureWrapMode { Wrap, Clamp, Mirror, Decal } public enum TextureMapping { FromUV, Sphere, Cylinder, Box, Plane, Unknown } public enum TextureOperation { Multiply, Add, Subtract, Divide, SmoothAdd, SignedAdd } public enum TextureType { None, Diffuse, Specular, Ambient, Emissive, Height, Normals, Shininess, Opacity, Displacement, Lightmap, Reflection, BaseColor, NormalCamera, EmissionColor, Metalness, Roughness, AmbientOcclusion, Unknown } [Flags] public enum SceneFlags { None = 0, Incomplete = 1, Validated = 2, ValidationWarning = 4, NonVerboseFormat = 8, Terrain = 0x10, AllowShared = 0x20 } public enum ReturnCode { Success = 0, Failure = -1, OutOfMemory = -3 } public enum Origin { Set, Current, End } [Flags] public enum DefaultLogStream { File = 1, StdOut = 2, StdErr = 4, Debugger = 8 } public enum PropertyType { Float = 1, Double, String, Integer, Buffer } public enum CompileFlags { Shared = 1, STLport = 2, Debug = 4, NoBoost = 8, SingleThreaded = 0x10 } [Flags] public enum UVTransformFlags { Scaling = 1, Rotation = 2, Translation = 4 } public enum FileIOMode { Write, WriteBinary, WriteText, Read, ReadBinary, ReadText } [Flags] public enum ImporterFeatureFlags { SupportsText = 1, SupportsBinary = 2, SupportsCompressed = 4, LimitedSupport = 8, Experimental = 0x10 } public sealed class ExportDataBlob { private class BlobBinaryReader : BinaryReader { public BlobBinaryReader(Stream stream) : base(stream, Encoding.UTF8) { } protected override void Dispose(bool disposing) { base.Dispose(disposing: false); } } private string m_name; private byte[] m_data; private ExportDataBlob m_next; public string Name => m_name; public byte[] Data => m_data; public ExportDataBlob NextBlob => m_next; public bool HasData => m_data != null; internal ExportDataBlob(ref AiExportDataBlob dataBlob) { m_name = dataBlob.Name.GetString(); if (dataBlob.Size.ToUInt32() != 0 && dataBlob.Data != IntPtr.Zero) { m_data = MemoryHelper.FromNativeArray<byte>(dataBlob.Data, (int)dataBlob.Size.ToUInt32()); } m_next = null; if (dataBlob.NextBlob != IntPtr.Zero) { AiExportDataBlob dataBlob2 = MemoryHelper.MarshalStructure<AiExportDataBlob>(dataBlob.NextBlob); m_next = new ExportDataBlob(ref dataBlob2); } } internal ExportDataBlob(string name, byte[] data) { m_name = name; m_data = data; m_next = null; } public void ToStream(Stream stream) { MemoryStream memoryStream = new MemoryStream(); using BinaryWriter writer = new BinaryWriter(memoryStream); WriteBlob(this, writer); memoryStream.Position = 0L; memoryStream.WriteTo(stream); } public static ExportDataBlob FromStream(Stream stream) { if (stream == null || !stream.CanRead) { return null; } using BlobBinaryReader reader = new BlobBinaryReader(stream); return ReadBlob(reader); } private static void WriteBlob(ExportDataBlob blob, BinaryWriter writer) { if (blob != null && writer != null) { bool flag = blob.NextBlob != null; writer.Write(blob.Name); writer.Write(blob.Data.Length); writer.Write(blob.Data); writer.Write(flag); if (flag) { WriteBlob(blob.NextBlob, writer); } } } private static ExportDataBlob ReadBlob(BinaryReader reader) { if (reader == null) { return null; } string name = reader.ReadString(); int count = reader.ReadInt32(); byte[] data = reader.ReadBytes(count); bool flag = reader.ReadBoolean(); ExportDataBlob exportDataBlob = new ExportDataBlob(name, data); if (flag) { exportDataBlob.m_next = ReadBlob(reader); } return exportDataBlob; } } [DebuggerDisplay("{Description}")] public sealed class ExportFormatDescription { private string m_formatId; private string m_description; private string m_fileExtension; public string FormatId => m_formatId; public string Description => m_description; public string FileExtension => m_fileExtension; internal ExportFormatDescription(in AiExportFormatDesc formatDesc) { m_formatId = Marshal.PtrToStringAnsi(formatDesc.FormatId); m_description = Marshal.PtrToStringAnsi(formatDesc.Description); m_fileExtension = Marshal.PtrToStringAnsi(formatDesc.FileExtension); if (m_fileExtension == "dae") { m_formatId = "collada"; } } } public sealed class Face : IMarshalable<Face, AiFace> { private List<int> m_indices; public int IndexCount => m_indices.Count; public bool HasIndices => m_indices.Count > 0; public List<int> Indices => m_indices; bool IMarshalable<Face, AiFace>.IsNativeBlittable => true; public Face() { m_indices = new List<int>(); } public Face(int[] indices) { m_indices = new List<int>(); if (indices != null) { m_indices.AddRange(indices); } } void IMarshalable<Face, AiFace>.ToNative(IntPtr thisPtr, out AiFace nativeValue) { nativeValue.NumIndices = (uint)IndexCount; nativeValue.Indices = IntPtr.Zero; if (nativeValue.NumIndices != 0) { nativeValue.Indices = MemoryHelper.ToNativeArray(m_indices.ToArray()); } } void IMarshalable<Face, AiFace>.FromNative(in AiFace nativeValue) { m_indices.Clear(); if (nativeValue.NumIndices != 0 && nativeValue.Indices != IntPtr.Zero) { m_indices.AddRange(MemoryHelper.FromNativeArray<int>(nativeValue.Indices, (int)nativeValue.NumIndices)); } } public static void FreeNative(IntPtr nativeValue, bool freeNative) { if (!(nativeValue == IntPtr.Zero)) { AiFace aiFace = MemoryHelper.Read<AiFace>(nativeValue); if (aiFace.NumIndices != 0 && aiFace.Indices != IntPtr.Zero) { MemoryHelper.FreeMemory(aiFace.Indices); } if (freeNative) { MemoryHelper.FreeMemory(nativeValue); } } } } public class FileIOSystem : IOSystem { private List<DirectoryInfo> m_searchDirectories; public FileIOSystem() : this((string[])null) { } public FileIOSystem(params string[] searchPaths) { m_searchDirectories = new List<DirectoryInfo>(); SetSearchDirectories(searchPaths); } public void SetSearchDirectories(params string[] searchPaths) { m_searchDirectories.Clear(); if (searchPaths == null || searchPaths.Length == 0) { return; } foreach (string text in searchPaths) { if (!string.IsNullOrEmpty(text) && Directory.Exists(text)) { m_searchDirectories.Add(new DirectoryInfo(text)); } } } public string[] GetSearchDirectories() { List<string> list = new List<string>(); foreach (DirectoryInfo searchDirectory in m_searchDirectories) { list.Add(searchDirectory.FullName); } return list.ToArray(); } public override IOStream OpenFile(string pathToFile, FileIOMode fileMode) { return new FileIOStream(this, pathToFile, fileMode); } public bool FindFile(string fileName, out string pathToFile) { pathToFile = null; if (string.IsNullOrEmpty(fileName) || m_searchDirectories.Count == 0) { return false; } foreach (DirectoryInfo searchDirectory in m_searchDirectories) { string text = Path.Combine(searchDirectory.FullName, fileName); if (File.Exists(text)) { pathToFile = text; return true; } } return false; } } internal class FileIOStream : IOStream { private FileIOSystem m_parent; private FileStream m_fileStream; public override bool IsValid => m_fileStream != null; public FileIOStream(FileIOSystem parent, string pathToFile, FileIOMode fileMode) : base(pathToFile, fileMode) { m_parent = parent; switch (fileMode) { case FileIOMode.Read: case FileIOMode.ReadBinary: case FileIOMode.ReadText: OpenRead(pathToFile, fileMode); break; case FileIOMode.Write: case FileIOMode.WriteBinary: case FileIOMode.WriteText: OpenWrite(pathToFile, fileMode); break; } } public override long Write(byte[] dataToWrite, long count) { if (dataToWrite == null) { throw new ArgumentOutOfRangeException("dataToWrite", "Data to write cannot be null."); } if (count < 0 || dataToWrite.Length < count) { throw new ArgumentOutOfRangeException("count", "Number of bytes to write is greater than data size."); } if (m_fileStream == null || !m_fileStream.CanWrite) { throw new IOException("Stream is not writable."); } if (m_fileStream.Position >= m_fileStream.Length) { return 0L; } m_fileStream.Write(dataToWrite, (int)m_fileStream.Position, (int)count); return count; } public override long Read(byte[] dataRead, long count) { if (dataRead == null) { throw new ArgumentOutOfRangeException("dataRead", "Array to store data in cannot be null."); } if (count < 0 || dataRead.Length < count) { throw new ArgumentOutOfRangeException("count", "Number of bytes to read is greater than data store size."); } if (m_fileStream == null || !m_fileStream.CanRead) { throw new IOException("Stream is not readable."); } if (m_fileStream.Position >= m_fileStream.Length) { return 0L; } m_fileStream.Read(dataRead, (int)m_fileStream.Position, (int)count); return count; } public override ReturnCode Seek(long offset, Origin seekOrigin) { if (m_fileStream == null || !m_fileStream.CanSeek) { throw new IOException("Stream does not support seeking."); } SeekOrigin origin = SeekOrigin.Begin; switch (seekOrigin) { case Origin.Set: origin = SeekOrigin.Begin; break; case Origin.Current: origin = SeekOrigin.Current; break; case Origin.End: origin = SeekOrigin.End; break; } m_fileStream.Seek(offset, origin); return ReturnCode.Success; } public override long GetPosition() { if (m_fileStream == null) { return -1L; } return m_fileStream.Position; } public override long GetFileSize() { if (m_fileStream == null) { return 0L; } return m_fileStream.Length; } public override void Flush() { if (m_fileStream != null) { m_fileStream.Flush(); } } protected override void Dispose(bool disposing) { if (!base.IsDisposed && disposing) { if (m_fileStream != null) { m_fileStream.Dispose(); } m_fileStream = null; base.Dispose(disposing); } } private void OpenRead(string pathToFile, FileIOMode fileMode) { string fileName = Path.GetFileName(pathToFile); if (m_parent.FindFile(fileName, out var pathToFile2)) { pathToFile = pathToFile2; } if (File.Exists(pathToFile)) { m_fileStream = File.OpenRead(pathToFile); } } private void OpenWrite(string pathToFile, FileIOMode fileMode) { m_fileStream = File.OpenWrite(pathToFile); } } [DebuggerDisplay("{Name}")] public sealed class ImporterDescription { private string m_name; private string m_author; private string m_maintainer; private string m_comments; private ImporterFeatureFlags m_featureFlags; private Version m_minVersion; private Version m_maxVersion; private string[] m_fileExtensions; public string Name => m_name; public string Author => m_author; public string Maintainer => m_maintainer; public string Comments => m_comments; public ImporterFeatureFlags FeatureFlags => m_featureFlags; public Version MinVersion => m_minVersion; public Version MaxVersion => m_maxVersion; public string[] FileExtensions => m_fileExtensions; internal ImporterDescription(in AiImporterDesc descr) { m_name = Marshal.PtrToStringAnsi(descr.Name); m_author = Marshal.PtrToStringAnsi(descr.Author); m_maintainer = Marshal.PtrToStringAnsi(descr.Maintainer); m_comments = Marshal.PtrToStringAnsi(descr.Comments); m_featureFlags = descr.Flags; m_minVersion = new Version((int)descr.MinMajor, (int)descr.MinMinor); m_maxVersion = new Version((int)descr.MaxMajor, (int)descr.MaxMajor); string text = Marshal.PtrToStringAnsi(descr.FileExtensions); if (string.IsNullOrEmpty(text)) { m_fileExtensions = new string[0]; return; } m_fileExtensions = text.Split(new char[1] { ' ' }); } } public interface IMarshalable<Managed, Native> where Managed : class, new() where Native : struct { bool IsNativeBlittable { get; } void ToNative(IntPtr thisPtr, out Native nativeValue); void FromNative(in Native nativeValue); } public interface INativeCustomMarshaler { int NativeDataSize { get; } void MarshalManagedToNative(object managedObj, IntPtr nativeData); object MarshalNativeToManaged(IntPtr nativeData); } public abstract class IOStream : IDisposable { private AiFileWriteProc m_writeProc; private AiFileReadProc m_readProc; private AiFileTellProc m_tellProc; private AiFileTellProc m_fileSizeProc; private AiFileSeek m_seekProc; private AiFileFlushProc m_flushProc; private IntPtr m_filePtr; private bool m_isDiposed; private string m_pathToFile; private FileIOMode m_fileMode; private byte[] m_byteBuffer; public bool IsDisposed => m_isDiposed; public string PathToFile => m_pathToFile; public FileIOMode FileMode => m_fileMode; public abstract bool IsValid { get; } internal IntPtr AiFile => m_filePtr; public IOStream(string pathToFile, FileIOMode fileMode) { m_pathToFile = pathToFile; m_fileMode = fileMode; m_writeProc = OnAiFileWriteProc; m_readProc = OnAiFileReadProc; m_tellProc = OnAiFileTellProc; m_fileSizeProc = OnAiFileSizeProc; m_seekProc = OnAiFileSeekProc; m_flushProc = OnAiFileFlushProc; AiFile aiFile = default(AiFile); aiFile.WriteProc = Marshal.GetFunctionPointerForDelegate((Delegate)m_writeProc); aiFile.ReadProc = Marshal.GetFunctionPointerForDelegate((Delegate)m_readProc); aiFile.TellProc = Marshal.GetFunctionPointerForDelegate((Delegate)m_tellProc); aiFile.FileSizeProc = Marshal.GetFunctionPointerForDelegate((Delegate)m_fileSizeProc); aiFile.SeekProc = Marshal.GetFunctionPointerForDelegate((Delegate)m_seekProc); aiFile.FlushProc = Marshal.GetFunctionPointerForDelegate((Delegate)m_flushProc); aiFile.UserData = IntPtr.Zero; m_filePtr = MemoryHelper.AllocateMemory(MemoryHelper.SizeOf<AiFile>()); Marshal.StructureToPtr((object)aiFile, m_filePtr, fDeleteOld: false); } ~IOStream() { Dispose(disposing: false); } public void Dispose() { Dispose(disposing: true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { if (!m_isDiposed) { if (m_filePtr != IntPtr.Zero) { MemoryHelper.FreeMemory(m_filePtr); m_filePtr = IntPtr.Zero; } if (disposing) { m_writeProc = null; m_readProc = null; m_tellProc = null; m_fileSizeProc = null; m_seekProc = null; m_flushProc = null; } m_isDiposed = true; } } public abstract long Write(byte[] dataToWrite, long count); public abstract long Read(byte[] dataRead, long count); public abstract ReturnCode Seek(long offset, Origin seekOrigin); public abstract long GetPosition(); public abstract long GetFileSize(); public abstract void Flush(); public virtual void Close() { Flush(); Dispose(); } private UIntPtr OnAiFileWriteProc(IntPtr file, IntPtr dataToWrite, UIntPtr sizeOfElemInBytes, UIntPtr numElements) { if (m_filePtr != file) { return UIntPtr.Zero; } long num = (long)sizeOfElemInBytes.ToUInt64(); long num2 = (long)numElements.ToUInt64(); long num3 = num * num2; if (num3 == 0) { return UIntPtr.Zero; } byte[] byteBuffer = GetByteBuffer(num, num2); MemoryHelper.Read(dataToWrite, byteBuffer, 0, (int)num3); long num4 = 0L; try { num4 = Write(byteBuffer, num3); } catch (Exception) { } return new UIntPtr((ulong)num4 / (ulong)num); } private UIntPtr OnAiFileReadProc(IntPtr file, IntPtr dataRead, UIntPtr sizeOfElemInBytes, UIntPtr numElements) { if (m_filePtr != file) { return UIntPtr.Zero; } long num = (long)sizeOfElemInBytes.ToUInt64(); long num2 = (long)numElements.ToUInt64(); long count = num * num2; byte[] byteBuffer = GetByteBuffer(num, num2); long num3 = 0L; try { num3 = Read(byteBuffer, count); if (num3 > 0) { MemoryHelper.Write(dataRead, byteBuffer, 0, (int)num3); } } catch (Exception) { } return new UIntPtr((ulong)num3 / (ulong)num); } private UIntPtr OnAiFileTellProc(IntPtr file) { if (m_filePtr != file) { return UIntPtr.Zero; } long value = 0L; try { value = GetPosition(); } catch (Exception) { } return new UIntPtr((ulong)value); } private UIntPtr OnAiFileSizeProc(IntPtr file) { if (m_filePtr != file) { return UIntPtr.Zero; } long value = 0L; try { value = GetFileSize(); } catch (Exception) { } return new UIntPtr((ulong)value); } private ReturnCode OnAiFileSeekProc(IntPtr file, UIntPtr offset, Origin seekOrigin) { if (m_filePtr != file) { return ReturnCode.Failure; } ReturnCode result = ReturnCode.Failure; try { result = Seek((long)offset.ToUInt64(), seekOrigin); } catch (Exception) { } return result; } private void OnAiFileFlushProc(IntPtr file) { if (m_filePtr != file) { return; } try { Flush(); } catch (Exception) { } } private byte[] GetByteBuffer(long sizeOfElemInBytes, long numElements) { if (m_byteBuffer == null || m_byteBuffer.Length < sizeOfElemInBytes * numElements) { m_byteBuffer = new byte[sizeOfElemInBytes * numElements]; } return m_byteBuffer; } } public abstract class IOSystem : IDisposable { private AiFileOpenProc m_openProc; private AiFileCloseProc m_closeProc; private IntPtr m_fileIOPtr; private bool m_isDisposed; private Dictionary<IntPtr, IOStream> m_openedFiles; public bool IsDisposed => m_isDisposed; public int OpenFileCount => m_openedFiles.Count; internal IntPtr AiFileIO => m_fileIOPtr; public IOSystem() { m_openProc = OnAiFileOpenProc; m_closeProc = OnAiFileCloseProc; AiFileIO aiFileIO = default(AiFileIO); aiFileIO.OpenProc = Marshal.GetFunctionPointerForDelegate((Delegate)m_openProc); aiFileIO.CloseProc = Marshal.GetFunctionPointerForDelegate((Delegate)m_closeProc); aiFileIO.UserData = IntPtr.Zero; m_fileIOPtr = MemoryHelper.AllocateMemory(MemoryHelper.SizeOf<AiFileIO>()); Marshal.StructureToPtr((object)aiFileIO, m_fileIOPtr, fDeleteOld: false); m_openedFiles = new Dictionary<IntPtr, IOStream>(); } ~IOSystem() { Dispose(disposing: false); } public abstract IOStream OpenFile(string pathToFile, FileIOMode fileMode); public virtual void CloseFile(IOStream stream) { if (stream != null && m_openedFiles.ContainsKey(stream.AiFile)) { m_openedFiles.Remove(stream.AiFile); if (!stream.IsDisposed) { stream.Close(); } } } public virtual void CloseAllFiles() { foreach (KeyValuePair<IntPtr, IOStream> openedFile in m_openedFiles) { if (!openedFile.Value.IsDisposed) { openedFile.Value.Close(); } } m_openedFiles.Clear(); } public void Dispose() { Dispose(disposing: true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { if (!m_isDisposed) { if (m_fileIOPtr != IntPtr.Zero) { MemoryHelper.FreeMemory(m_fileIOPtr); m_fileIOPtr = IntPtr.Zero; } if (disposing) { m_openProc = null; m_closeProc = null; CloseAllFiles(); } m_isDisposed = true; } } private IntPtr OnAiFileOpenProc(IntPtr fileIO, string pathToFile, string mode) { if (m_fileIOPtr != fileIO) { return IntPtr.Zero; } FileIOMode fileMode = ConvertFileMode(mode); IOStream iOStream = OpenFile(pathToFile, fileMode); IntPtr intPtr = IntPtr.Zero; if (iOStream != null) { if (iOStream.IsValid) { intPtr = iOStream.AiFile; m_openedFiles.Add(intPtr, iOStream); } else { iOStream.Dispose(); } } return intPtr; } private void OnAiFileCloseProc(IntPtr fileIO, IntPtr file) { if (!(m_fileIOPtr != fileIO) && m_openedFiles.TryGetValue(file, out var value)) { CloseFile(value); } } private FileIOMode ConvertFileMode(string mode) { FileIOMode result = FileIOMode.Read; switch (mode) { case "w": result = FileIOMode.Write; break; case "wb": result = FileIOMode.WriteBinary; break; case "wt": result = FileIOMode.WriteText; break; case "r": result = FileIOMode.Read; break; case "rb": result = FileIOMode.ReadBinary; break; case "rt": result = FileIOMode.ReadText; break; } return result; } } public sealed class Light : IMarshalable<Light, AiLight> { private string m_name; private LightSourceType m_lightType; private float m_angleInnerCone; private float m_angleOuterCone; private float m_attConstant; private float m_attLinear; private float m_attQuadratic; private Vector3D m_position; private Vector3D m_direction; private Vector3D m_up; private Color3D m_diffuse; private Color3D m_specular; private Color3D m_ambient; private Vector2D m_areaSize; public string Name { get { return m_name; } set { m_name = value; } } public LightSourceType LightType { get { return m_lightType; } set { m_lightType = value; } } public float AngleInnerCone { get { return m_angleInnerCone; } set { m_angleInnerCone = value; } } public float AngleOuterCone { get { return m_angleOuterCone; } set { m_angleOuterCone = value; } } public float AttenuationConstant { get { return m_attConstant; } set { m_attConstant = value; } } public float AttenuationLinear { get { return m_attLinear; } set { m_attLinear = value; } } public float AttenuationQuadratic { get { return m_attQuadratic; } set { m_attQuadratic = value; } } public Vector3D Position { get { return m_position; } set { m_position = value; } } public Vector3D Direction { get { return m_direction; } set { m_direction = value; } } public Vector3D Up { get { return m_up; } set { m_up = value; } } public Color3D ColorDiffuse { get { return m_diffuse; } set { m_diffuse = value; } } public Color3D ColorSpecular { get { return m_specular; } set { m_specular = value; } } public Color3D ColorAmbient { get { return m_ambient; } set { m_ambient = value; } } public Vector2D AreaSize { get { return m_areaSize; } set { m_areaSize = value; } } bool IMarshalable<Light, AiLight>.IsNativeBlittable => true; public Light() { m_lightType = LightSourceType.Undefined; m_attConstant = 0f; m_attLinear = 1f; m_attQuadratic = 0f; m_angleInnerCone = (float)Math.PI * 2f; m_angleOuterCone = (float)Math.PI * 2f; m_areaSize = new Vector2D(0f, 0f); } void IMarshalable<Light, AiLight>.ToNative(IntPtr thisPtr, out AiLight nativeValue) { nativeValue.Name = new AiString(m_name); nativeValue.Type = m_lightType; nativeValue.AngleInnerCone = m_angleInnerCone; nativeValue.AngleOuterCone = m_angleOuterCone; nativeValue.AttenuationConstant = m_attConstant; nativeValue.AttenuationLinear = m_attLinear; nativeValue.AttenuationQuadratic = m_attQuadratic; nativeValue.ColorAmbient = m_ambient; nativeValue.ColorDiffuse = m_diffuse; nativeValue.ColorSpecular = m_specular; nativeValue.Direction = m_direction; nativeValue.Up = m_up; nativeValue.Position = m_position; nativeValue.AreaSize = m_areaSize; } void IMarshalable<Light, AiLight>.FromNative(in AiLight nativeValue) { m_name = AiString.GetString(in nativeValue.Name); m_lightType = nativeValue.Type; m_angleInnerCone = nativeValue.AngleInnerCone; m_angleOuterCone = nativeValue.AngleOuterCone; m_attConstant = nativeValue.AttenuationConstant; m_attLinear = nativeValue.AttenuationLinear; m_attQuadratic = nativeValue.AttenuationQuadratic; m_position = nativeValue.Position; m_direction = nativeValue.Direction; m_up = nativeValue.Up; m_diffuse = nativeValue.ColorDiffuse; m_specular = nativeValue.ColorSpecular; m_ambient = nativeValue.ColorAmbient; m_areaSize = nativeValue.AreaSize; } public static void FreeNative(IntPtr nativeValue, bool freeNative) { if (nativeValue != IntPtr.Zero && freeNative) { MemoryHelper.FreeMemory(nativeValue); } } } public delegate void LoggingCallback(string msg, string userData); [DebuggerDisplay("IsAttached = {IsAttached}")] public class LogStream : IDisposable { private static object s_sync; private static List<LogStream> s_activeLogstreams; private LoggingCallback m_logCallback; private AiLogStreamCallback m_assimpCallback; private IntPtr m_logstreamPtr; private string m_userData; private bool m_isDisposed; private bool m_isAttached; public static bool IsVerboseLoggingEnabled { get { return AssimpLibrary.Instance.GetVerboseLoggingEnabled(); } set { AssimpLibrary.Instance.EnableVerboseLogging(value); } } public string UserData { get { return m_userData; } set { m_userData = value; } } public bool IsDisposed => m_isDisposed; public bool IsAttached => m_isAttached; static LogStream() { s_sync = new object(); s_activeLogstreams = new List<LogStream>(); AssimpLibrary.Instance.LibraryFreed += AssimpLibraryFreed; } protected LogStream() : this("") { } protected LogStream(string userData) { Initialize(null, userData); } public LogStream(LoggingCallback callback) { Initialize(callback, string.Empty); } public LogStream(LoggingCallback callback, string userData) { Initialize(callback, userData); } ~LogStream() { Dispose(disposing: false); } public static void DetachAllLogstreams() { lock (s_sync) { foreach (LogStream s_activeLogstream in s_activeLogstreams) { s_activeLogstream.m_isAttached = false; AssimpLibrary.Instance.DetachLogStream(s_activeLogstream.m_logstreamPtr); s_activeLogstream.OnDetach(); } s_activeLogstreams.Clear(); } } public static IEnumerable<LogStream> GetAttachedLogStreams() { lock (s_sync) { return s_activeLogstreams.ToArray(); } } private static void AssimpLibraryFreed(object sender, EventArgs e) { DetachAllLogstreams(); } public void Attach() { if (m_isAttached) { return; } lock (s_sync) { s_activeLogstreams.Add(this); m_isAttached = true; AssimpLibrary.Instance.AttachLogStream(m_logstreamPtr); OnAttach(); } } public void Detach() { if (!m_isAttached) { return; } lock (s_sync) { s_activeLogstreams.Remove(this); m_isAttached = false; AssimpLibrary.Instance.DetachLogStream(m_logstreamPtr); OnDetach(); } } public void Log(string msg) { if (m_isAttached && !string.IsNullOrEmpty(msg)) { OnAiLogStreamCallback(msg, IntPtr.Zero); } } public void Dispose() { Dispose(disposing: true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { if (!m_isDisposed) { if (m_logstreamPtr != IntPtr.Zero) { MemoryHelper.FreeMemory(m_logstreamPtr); m_logstreamPtr = IntPtr.Zero; } if (disposing) { m_assimpCallback = null; } m_isDisposed = true; } } protected virtual void LogMessage(string msg, string userData) { } protected virtual void OnAttach() { } protected virtual void OnDetach() { } private void OnAiLogStreamCallback(string msg, IntPtr userData) { if (m_logCallback != null) { m_logCallback(msg, m_userData); } else { LogMessage(msg, m_userData); } } private void Initialize(LoggingCallback callback, string userData) { if (userData == null) { userData = string.Empty; } m_assimpCallback = OnAiLogStreamCallback; m_logCallback = callback; m_userData = userData; AiLogStream aiLogStream = default(AiLogStream); aiLogStream.Callback = Marshal.GetFunctionPointerForDelegate((Delegate)m_assimpCallback); aiLogStream.UserData = IntPtr.Zero; m_logstreamPtr = MemoryHelper.AllocateMemory(MemoryHelper.SizeOf<AiLogStream>()); Marshal.StructureToPtr((object)aiLogStream, m_logstreamPtr, fDeleteOld: false); } } public sealed class ConsoleLogStream : LogStream { public ConsoleLogStream() { } public ConsoleLogStream(string userData) : base(userData) { } protected override void LogMessage(string msg, string userData) { if (string.IsNullOrEmpty(userData)) { Console.WriteLine(msg); } else { Console.WriteLine($"{userData}: {msg}"); } } } public sealed class Material : IMarshalable<Material, AiMaterial> { public sealed class PBRMaterialProperties { private Material m_parent; public bool HasTextureBaseColor => m_parent.HasProperty("$tex.file", TextureType.BaseColor, 0); public TextureSlot TextureBaseColor { get { m_parent.GetMaterialTexture(TextureType.BaseColor, 0, out var texture); return texture; } set { if (value.TextureIndex == 0 && value.TextureType == TextureType.BaseColor) { m_parent.AddMaterialTexture(in value); } } } public bool HasTextureNormalCamera => m_parent.HasProperty("$tex.file", TextureType.NormalCamera, 0); public TextureSlot TextureNormalCamera { get { m_parent.GetMaterialTexture(TextureType.NormalCamera, 0, out var texture); return texture; } set { if (value.TextureIndex == 0 && value.TextureType == TextureType.NormalCamera) { m_parent.AddMaterialTexture(in value); } } } public bool HasTextureEmissionColor => m_parent.HasProperty("$tex.file", TextureType.EmissionColor, 0); public TextureSlot TextureEmissionColor { get { m_parent.GetMaterialTexture(TextureType.EmissionColor, 0, out var texture); return texture; } set { if (value.TextureIndex == 0 && value.TextureType == TextureType.EmissionColor) { m_parent.AddMaterialTexture(in value); } } } public bool HasTextureMetalness => m_parent.HasProperty("$tex.file", TextureType.Metalness, 0); public TextureSlot TextureMetalness { get { m_parent.GetMaterialTexture(TextureType.Metalness, 0, out var texture); return texture; } set { if (value.TextureIndex == 0 && value.TextureType == TextureType.Metalness) { m_parent.AddMaterialTexture(in value); } } } public bool HasTextureRoughness => m_parent.HasProperty("$tex.file", TextureType.Roughness, 0); public TextureSlot TextureRoughness { get { m_parent.GetMaterialTexture(TextureType.Roughness, 0, out var texture); return texture; } set { if (value.TextureIndex == 0 && value.TextureType == TextureType.Roughness) { m_parent.AddMaterialTexture(in value); } } } internal PBRMaterialProperties(Material parent) { m_parent = parent; } } public sealed class ShaderMaterialProperties { private Material m_parent; public bool HasShaderLanguageType => m_parent.HasProperty("?sh.lang,0,0"); public string ShaderLanguageType { get { return GetStringProperty("?sh.lang,0,0"); } set { SetStringProperty("?sh.lang,0,0", "?sh.lang", value); } } public bool HasVertexShader => m_parent.HasProperty("?sh.vs,0,0"); public string VertexShader { get { return GetStringProperty("?sh.vs,0,0"); } set { SetStringProperty("?sh.vs,0,0", "?sh.vs", value); } } public bool HasFragmentShader => m_parent.HasProperty("?sh.fs,0,0"); public string FragmentShader { get { return GetStringProperty("?sh.fs,0,0"); } set { SetStringProperty("?sh.fs,0,0", "?sh.fs", value); } } public bool HasGeometryShader => m_parent.HasProperty("?sh.gs,0,0"); public string GeometryShader { get { return GetStringProperty("?sh.gs,0,0"); } set { SetStringProperty("?sh.gs,0,0", "?sh.gs", value); } } public bool HasTesselationShader => m_parent.HasProperty("?sh.ts,0,0"); public string TesselationShader { get { return GetStringProperty("?sh.ts,0,0"); } set { SetStringProperty("?sh.ts,0,0", "?sh.ts", value); } } public bool HasPrimitiveShader => m_parent.HasProperty("?sh.ps,0,0"); public string PrimitiveShader { get { return GetStringProperty("?sh.ps,0,0"); } set { SetStringProperty("?sh.ps,0,0", "?sh.ps", value); } } public bool HasComputeShader => m_parent.HasProperty("?sh.cs,0,0"); public string ComputeShader { get { return GetStringProperty("?sh.cs,0,0"); } set { SetStringProperty("?sh.cs,0,0", "?sh.cs", value); } } internal ShaderMaterialProperties(Material parent) { m_parent = parent; } private string GetStringProperty(string fullName) { MaterialProperty property = m_parent.GetProperty(fullName); if (property != null) { return property.GetStringValue(); } return string.Empty; } private void SetStringProperty(string fullName, string baseName, string value) { if (string.IsNullOrEmpty(value)) { value = string.Empty; } MaterialProperty property = m_parent.GetProperty(fullName); if (property == null) { property = new MaterialProperty(baseName, value); m_parent.AddProperty(property); } else { property.SetStringValue(value); } } } private Dictionary<string, MaterialProperty> m_properties; private PBRMaterialProperties m_pbrProperties; private ShaderMaterialProperties m_shaderProperties; public int PropertyCount => m_properties.Count; public bool HasName => HasProperty("?mat.name,0,0"); public string Name { get { MaterialProperty property = GetProperty("?mat.name,0,0"); if (property != null) { return property.GetStringValue(); } return string.Empty; } set { MaterialProperty property = GetProperty("?mat.name,0,0"); if (property == null) { property = new MaterialProperty("?mat.name", value); AddProperty(property); } else { property.SetStringValue(value); } } } public bool HasTwoSided => HasProperty("$mat.twosided,0,0"); public bool IsTwoSided { get { return GetProperty("$mat.twosided,0,0")?.GetBooleanValue() ?? false; } set { MaterialProperty property = GetProperty("$mat.twosided,0,0"); if (property == null) { property = new MaterialProperty("$mat.twosided", value); AddProperty(property); } else { property.SetBooleanValue(value); } } } public bool HasShadingMode => HasProperty("$mat.shadingm,0,0"); public ShadingMode ShadingMode { get { return (ShadingMode)(GetProperty("$mat.shadingm,0,0")?.GetIntegerValue() ?? 0); } set { MaterialProperty property = GetProperty("$mat.shadingm,0,0"); if (property == null) { property = new MaterialProperty("$mat.shadingm", (int)value); AddProperty(property); } else { property.SetIntegerValue((int)value); } } } public bool HasWireFrame => HasProperty("$mat.wireframe,0,0"); public bool IsWireFrameEnabled { get { return GetProperty("$mat.wireframe,0,0")?.GetBooleanValue() ?? false; } set { MaterialProperty property = GetProperty("$mat.wireframe,0,0"); if (property == null) { property = new MaterialProperty("$mat.wireframe", value); AddProperty(property); } else { property.SetBooleanValue(value); } } } public bool HasBlendMode => HasProperty("$mat.blend,0,0"); public BlendMode BlendMode { get { return (BlendMode)(GetProperty("$mat.blend,0,0")?.GetIntegerValue() ?? 0); } set { MaterialProperty property = GetProperty("$mat.blend,0,0"); if (property == null) { property = new MaterialProperty("$mat.blend", (int)value); AddProperty(property); } else { property.SetIntegerValue((int)value); } } } public bool HasOpacity => HasProperty("$mat.opacity,0,0"); public float Opacity { get { return GetProperty("$mat.opacity,0,0")?.GetFloatValue() ?? 1f; } set { MaterialProperty property = GetProperty("$mat.opacity,0,0"); if (property == null) { property = new MaterialProperty("$mat.opacity", value); AddProperty(property); } else { property.SetFloatValue(value); } } } public bool HasTransparencyFactor => HasProperty("$mat.transparencyfactor,0,0"); public float TransparencyFactor { get { return GetProperty("$mat.transparencyfactor,0,0")?.GetFloatValue() ?? 0f; } set { MaterialProperty property = GetProperty("$mat.transparencyfactor,0,0"); if (property == null) { property = new MaterialProperty("$mat.transparencyfactor", value); AddProperty(property); } else { property.SetFloatValue(value); } } } public bool HasBumpScaling => HasProperty("$mat.bumpscaling,0,0"); public float BumpScaling { get { return GetProperty("$mat.bumpscaling,0,0")?.GetFloatValue() ?? 0f; } set { MaterialProperty property = GetProperty("$mat.bumpscaling,0,0"); if (property == null) { property = new MaterialProperty("$mat.bumpscaling", value); AddProperty(property); } else { property.SetFloatValue(value); } } } public bool HasShininess => HasProperty("$mat.shininess,0,0"); public float Shininess { get { return GetProperty("$mat.shininess,0,0")?.GetFloatValue() ?? 0f; } set { MaterialProperty property = GetProperty("$mat.shininess,0,0"); if (property == null) { property = new MaterialProperty("$mat.shininess", value); AddProperty(property); } else { property.SetFloatValue(value); } } } public bool HasShininessStrength => HasProperty("$mat.shinpercent,0,0"); public float ShininessStrength { get { return GetProperty("$mat.shinpercent,0,0")?.GetFloatValue() ?? 1f; } set { MaterialProperty property = GetProperty("$mat.shinpercent,0,0"); if (property == null) { property = new MaterialProperty("$mat.shinpercent", value); AddProperty(property); } else { property.SetFloatValue(value); } } } public bool HasReflectivity => HasProperty("$mat.reflectivity,0,0"); public float Reflectivity { get { return GetProperty("$mat.reflectivity,0,0")?.GetFloatValue() ?? 0f; } set { MaterialProperty property = GetProperty("$mat.reflectivity,0,0"); if (property == null) { property = new MaterialProperty("$mat.reflectivity", value); AddProperty(property); } else { property.SetFloatValue(value); } } } public bool HasColorDiffuse => HasProperty("$clr.diffuse,0,0"); public Color4D ColorDiffuse { get { return GetProperty("$clr.diffuse,0,0")?.GetColor4DValue() ?? new Color4D(1f, 1f, 1f, 1f); } set { MaterialProperty property = GetProperty("$clr.diffuse,0,0"); if (property == null) { property = new MaterialProperty("$clr.diffuse", value); AddProperty(property); } else { property.SetColor4DValue(value); } } } public bool HasColorAmbient => HasProperty("$clr.ambient,0,0"); public Color4D ColorAmbient { get { return GetProperty("$clr.ambient,0,0")?.GetColor4DValue() ?? new Color4D(0.2f, 0.2f, 0.2f, 1f); } set { MaterialProperty property = GetProperty("$clr.ambient,0,0"); if (property == null) { property = new MaterialProperty("$clr.ambient", value); AddProperty(property); } else { property.SetColor4DValue(value); } } } public bool HasColorSpecular => HasProperty("$clr.specular,0,0"); public Color4D ColorSpecular { get { return GetProperty("$clr.specular,0,0")?.GetColor4DValue() ?? new Color4D(0f, 0f, 0f, 1f); } set { MaterialProperty property = GetProperty("$clr.specular,0,0"); if (property == null) { property = new MaterialProperty("$clr.specular", value); AddProperty(property); } else { property.SetColor4DValue(value); } } } public bool HasColorEmissive => HasProperty("$clr.emissive,0,0"); public Color4D ColorEmissive { get { return GetProperty("$clr.emissive,0,0")?.GetColor4DValue() ?? new Color4D(0f, 0f, 0f, 1f); } set { MaterialProperty property = GetProperty("$clr.emissive,0,0"); if (property == null) { property = new MaterialProperty("$clr.emissive", value); AddProperty(property); } else { property.SetColor4DValue(value); } } } public bool HasColorTransparent => HasProperty("$clr.transparent,0,0"); public Color4D ColorTransparent { get { return GetProperty("$clr.transparent,0,0")?.GetColor4DValue() ?? new Color4D(0f, 0f, 0f, 1f); } set { MaterialProperty property = GetProperty("$clr.transparent,0,0"); if (property == null) { property = new MaterialProperty("$clr.transparent", value); AddProperty(property); } else { property.SetColor4DValue(value); } } } public bool HasColorReflective => HasProperty("$clr.reflective,0,0"); public Color4D ColorReflective { get { return GetProperty("$clr.reflective,0,0")?.GetColor4DValue() ?? new Color4D(0f, 0f, 0f, 1f); } set { MaterialProperty property = GetProperty("$clr.reflective,0,0"); if (property == null) { property = new MaterialProperty("$clr.reflective", value); AddProperty(property); } else { property.SetColor4DValue(value); } } } public bool HasTextureDiffuse => HasProperty("$tex.file", TextureType.Diffuse, 0); public TextureSlot TextureDiffuse { get { GetMaterialTexture(TextureType.Diffuse, 0, out var texture); return texture; } set { if (value.TextureIndex == 0 && value.TextureType == TextureType.Diffuse) { AddMaterialTexture(in value); } } } public bool HasTextureSpecular => HasProperty("$tex.file", TextureType.Specular, 0); public TextureSlot TextureSpecular { get { GetMaterialTexture(TextureType.Specular, 0, out var texture); return texture; } set { if (value.TextureIndex == 0 && value.TextureType == TextureType.Specular) { AddMaterialTexture(in value); } } } public bool HasTextureAmbient => HasProperty("$tex.file", TextureType.Ambient, 0); public TextureSlot TextureAmbient { get { GetMaterialTexture(TextureType.Ambient, 0, out var texture); return texture; } set { if (value.TextureIndex == 0 && value.TextureType == TextureType.Ambient) { AddMaterialTexture(in value); } } } public bool HasTextureEmissive => HasProperty("$tex.file", TextureType.Emissive, 0); public TextureSlot TextureEmissive { get { GetMaterialTexture(TextureType.Emissive, 0, out var texture); return texture; } set { if (value.TextureIndex == 0 && value.TextureType == TextureType.Emissive) { AddMaterialTexture(in value); } } } public bool HasTextureHeight => HasProperty("$tex.file", TextureType.Height, 0); public TextureSlot TextureHeight { get { GetMaterialTexture(TextureType.Height, 0, out var texture); return texture; } set { if (value.TextureIndex == 0 && value.TextureType == TextureType.Height) { AddMaterialTexture(in value); } } } public bool HasTextureNormal => HasProperty("$tex.file", TextureType.Normals, 0); public TextureSlot TextureNormal { get { GetMaterialTexture(TextureType.Normals, 0, out var texture); return texture; } set { if (value.TextureIndex == 0 && value.TextureType == TextureType.Normals) { AddMaterialTexture(in value); } } } public bool HasTextureOpacity => HasProperty("$tex.file", TextureType.Opacity, 0); public TextureSlot TextureOpacity { get { GetMaterialTexture(TextureType.Opacity, 0, out var texture); return texture; } set { if (value.TextureIndex == 0 && value.TextureType == TextureType.Opacity) { AddMaterialTexture(in value); } } } public bool HasTextureDisplacement => HasProperty("$tex.file", TextureType.Displacement, 0); public TextureSlot TextureDisplacement { get { GetMaterialTexture(TextureType.Displacement, 0, out var texture); return texture; } set { if (value.TextureIndex == 0 && value.TextureType == TextureType.Displacement) { AddMaterialTexture(in value); } } } public bool HasTextureLightMap => HasProperty("$tex.file", TextureType.Lightmap, 0); public TextureSlot TextureLightMap { get { GetMaterialTexture(TextureType.Lightmap, 0, out var texture); return texture; } set { if (value.TextureIndex == 0 && value.TextureType == TextureType.Lightmap) { AddMaterialTexture(in value); } } } public bool HasTextureAmbientOcclusion => HasProperty("$tex.file", TextureType.AmbientOcclusion, 0); public TextureSlot TextureAmbientOcclusion { get { GetMaterialTexture(TextureType.AmbientOcclusion, 0, out var texture); return texture; } set { if (value.TextureIndex == 0 && value.TextureType == TextureType.AmbientOcclusion) { AddMaterialTexture(in value); } } } public bool HasTextureReflection => HasProperty("$tex.file", TextureType.Reflection, 0); public TextureSlot TextureReflection { get { GetMaterialTexture(TextureType.Reflection, 0, out var texture); return texture; } set { if (value.TextureIndex == 0 && value.TextureType == TextureType.Reflection) { AddMaterialTexture(in value); } } } public bool IsPBRMaterial { get { PBRMaterialProperties pbrProperties = m_pbrProperties; return pbrProperties.HasTextureBaseColor || pbrProperties.HasTextureMetalness || pbrProperties.HasTextureRoughness || pbrProperties.HasTextureNormalCamera || pbrProperties.HasTextureEmissionColor; } } public PBRMaterialProperties PBR => m_pbrProperties; public bool HasShaders { get { ShaderMaterialProperties shaderProperties = m_shaderProperties; return shaderProperties.HasShaderLanguageType && (shaderProperties.HasVertexShader || shaderProperties.HasFragmentShader || shaderProperties.HasGeometryShader || shaderProperties.HasTesselationShader || shaderProperties.HasPrimitiveShader || shaderProperties.HasComputeShader); } } public ShaderMaterialProperties Shaders => m_shaderProperties; bool IMarshalable<Material, AiMaterial>.IsNativeBlittable => true; public Material() { m_properties = new Dictionary<string, MaterialProperty>(); m_pbrProperties = new PBRMaterialProperties(this); m_shaderProperties = new ShaderMaterialProperties(this); } public static string CreateFullyQualifiedName(string baseName, TextureType texType, int texIndex) { if (string.IsNullOrEmpty(baseName)) { return string.Empty; } return $"{baseName},{(int)texType},{texIndex}"; } public MaterialProperty GetNonTextureProperty(string baseName) { if (string.IsNullOrEmpty(baseName)) { return null; } string fullyQualifiedName = CreateFullyQualifiedName(baseName, TextureType.None, 0); return GetProperty(fullyQualifiedName); } public MaterialProperty GetProperty(string baseName, TextureType texType, int texIndex) { if (string.IsNullOrEmpty(baseName)) { return null; } string fullyQualifiedName = CreateFullyQualifiedName(baseName, texType, texIndex); return GetProperty(fullyQualifiedName); } public MaterialProperty GetProperty(string fullyQualifiedName) { if (string.IsNullOrEmpty(fullyQualifiedName)) { return null; } if (!m_properties.TryGetValue(fullyQualifiedName, out var value)) { return null; } return value; } public bool HasNonTextureProperty(string baseName) { if (string.IsNullOrEmpty(baseName)) { return false; } string fullyQualifiedName = CreateFullyQualifiedName(baseName, TextureType.None, 0); return HasProperty(fullyQualifiedName); } public bool HasProperty(string baseName, TextureType texType, int texIndex) { if (string.IsNullOrEmpty(baseName)) { return false; } string fullyQualifiedName = CreateFullyQualifiedName(baseName, texType, texIndex); return HasProperty(fullyQualifiedName); } public bool HasProperty(string fullyQualifiedName) { if (string.IsNullOrEmpty(fullyQualifiedName)) { return false; } return m_properties.ContainsKey(fullyQualifiedName); } public bool AddProperty(MaterialProperty matProp) { if (matProp == null || string.IsNullOrEmpty(matProp.FullyQualifiedName)) { return false; } if (m_properties.ContainsKey(matProp.FullyQualifiedName)) { return false; } m_properties.Add(matProp.FullyQualifiedName, matProp); return true; } public bool RemoveNonTextureProperty(string baseName) { if (string.IsNullOrEmpty(baseName)) { return false; } return RemoveProperty(CreateFullyQualifiedName(baseName, TextureType.None, 0)); } public bool RemoveProperty(string baseName, TextureType texType, int texIndex) { if (string.IsNullOrEmpty(baseName)) { return false; } return RemoveProperty(CreateFullyQualifiedName(baseName, texType, texIndex)); } public bool RemoveProperty(string fullyQualifiedName) { if (string.IsNullOrEmpty(fullyQualifiedName)) { return false; } return m_properties.Remove(fullyQualifiedName); } public void Clear() { m_properties.Clear(); } public MaterialProperty[] GetAllProperties() { MaterialProperty[] array = new MaterialProperty[m_properties.Values.Count]; m_properties.Values.CopyTo(array, 0); return array; } public int GetMaterialTextureCount(TextureType texType) { int num = 0; foreach (KeyValuePair<string, MaterialProperty> property in m_properties) { MaterialProperty value = property.Value; if (value.Name.StartsWith("$tex.file") && value.TextureType == texType) { num++; } } return num; } public bool AddMaterialTexture(in TextureSlot texture) { return AddMaterialTexture(in texture, onlySetFilePath: false); } public bool AddMaterialTexture(in TextureSlot texture, bool onlySetFilePath) { if (string.IsNullOrEmpty(texture.FilePath)) { return false; } TextureType textureType = texture.TextureType; int textureIndex = texture.TextureIndex; string fullyQualifiedName = CreateFullyQualifiedName("$tex.file", textureType, textureIndex); MaterialProperty property = GetProperty(fullyQualifiedName); if (property == null) { AddProperty(new MaterialProperty("$tex.file", texture.FilePath, textureType, textureIndex)); } else { property.SetStringValue(texture.FilePath); } if (onlySetFilePath) { return true; } string fullyQualifiedName2 = CreateFullyQualifiedName("$tex.mapping", textureType, textureIndex); string fullyQualifiedName3 = CreateFullyQualifiedName("$tex.uvwsrc", textureType, textureIndex); string fullyQualifiedName4 = CreateFullyQualifiedName("$tex.blend", textureType, textureIndex); string fullyQualifiedName5 = CreateFullyQualifiedName("$tex.op", textureType, textureIndex); string fullyQualifiedName6 = CreateFullyQualifiedName("$tex.mapmodeu", textureType, textureIndex); string fullyQualifiedName7 = CreateFullyQualifiedName("$tex.mapmodev", textureType, textureIndex); string fullyQualifiedName8 = CreateFullyQualifiedName("$tex.flags", textureType, textureIndex); MaterialProperty property2 = GetProperty(fullyQualifiedName2); MaterialProperty property3 = GetProperty(fullyQualifiedName3); MaterialProperty property4 = GetProperty(fullyQualifiedName4); MaterialProperty property5 = GetProperty(fullyQualifiedName5); MaterialProperty property6 = GetProperty(fullyQualifiedName6); MaterialProperty property7 = GetProperty(fullyQualifiedName7); MaterialProperty property8 = GetProperty(fullyQualifiedName8); if (property2 == null) { AddProperty(new MaterialProperty("$tex.mapping", (int)texture.Mapping)); } else { property2.SetIntegerValue((int)texture.Mapping); } if (property3 == null) { AddProperty(new MaterialProperty("$tex.mapping", (int)texture.Mapping)); } else { property3.SetIntegerValue(texture.UVIndex); } if (property4 == null) { AddProperty(new MaterialProperty("$tex.blend", texture.BlendFactor)); } else { property4.SetFloatValue(texture.BlendFactor); } if (property5 == null) { AddProperty(new MaterialProperty("$tex.op", (int)texture.Operation)); } else { property5.SetIntegerValue((int)texture.Operation); } if (property6 == null) { AddProperty(new MaterialProperty("$tex.mapmodeu", (int)texture.WrapModeU)); } else { property6.SetIntegerValue((int)texture.WrapModeU); } if (property7 == null) { AddProperty(new MaterialProperty("$tex.mapmodev", (int)texture.WrapModeV)); } else { property7.SetIntegerValue((int)texture.WrapModeV); } if (property8 == null) { AddProperty(new MaterialProperty("$tex.flags", texture.Flags)); } else { property8.SetIntegerValue(texture.Flags)