Skip to content

Commit

Permalink
WIP work
Browse files Browse the repository at this point in the history
  • Loading branch information
Saalvage committed Dec 10, 2024
1 parent ea88779 commit 6ca492b
Show file tree
Hide file tree
Showing 7 changed files with 49 additions and 140 deletions.
41 changes: 23 additions & 18 deletions AssimpNet/AssimpContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -176,21 +176,27 @@ public Scene ImportFileFromStream(Stream stream, string formatHint = null)
/// <returns>The imported scene</returns>
/// <exception cref="AssimpException">Thrown if the stream is not valid (null or write-only).</exception>
/// <exception cref="System.ObjectDisposedException">Thrown if the context has already been disposed of.</exception>
public Scene ImportFileFromStream(Stream stream, PostProcessSteps postProcessFlags, string formatHint = null)
public unsafe Scene ImportFileFromStream(Stream stream, PostProcessSteps postProcessFlags, string formatHint = null)
{
CheckDisposed();

if(stream == null || stream.CanRead != true)
throw new AssimpException(nameof(stream), "Can't read from the stream it's null or write-only");

IntPtr ptr = IntPtr.Zero;
AiScene* ptr = null;
PrepareImport();

var bytes = MemoryHelper.ReadStreamFully(stream, 0);

try
{
ptr = AssimpLibrary.Instance.ImportFileFromStream(stream, PostProcessSteps.None, formatHint, m_propStore);
fixed (byte* buffer = bytes)
{
ptr = AssimpLibrary.aiImportFileFromMemoryWithProperties(buffer, (uint)bytes.Length, PostProcessSteps.None,
formatHint, m_propStore);
}

if(ptr == IntPtr.Zero)
if (ptr == null)
throw new AssimpException("Error importing file: " + AssimpLibrary.Instance.GetErrorString());

TransformScene(ptr);
Expand All @@ -203,9 +209,9 @@ public Scene ImportFileFromStream(Stream stream, PostProcessSteps postProcessFla
{
CleanupImport();

if(ptr != IntPtr.Zero)
if(ptr != null)
{
AssimpLibrary.Instance.ReleaseImport(ptr);
AssimpLibrary.aiReleaseImport(ptr);
}
}
}
Expand Down Expand Up @@ -264,19 +270,19 @@ public unsafe Scene ImportFile(string file, PostProcessSteps postProcessFlags)
if(ptr == null)
throw new AssimpException("Error importing file: " + AssimpLibrary.Instance.GetErrorString());

TransformScene(new(ptr));
TransformScene(ptr);

ptr = (AiScene*)ApplyPostProcessing(new(ptr), postProcessFlags);
ptr = (AiScene*)ApplyPostProcessing(ptr, postProcessFlags);

return Scene.FromUnmanagedScene(new(ptr));
return Scene.FromUnmanagedScene(ptr);
}
finally
{
CleanupImport();

if(ptr != null)
{
AssimpLibrary.Instance.ReleaseImport(new(ptr));
AssimpLibrary.aiReleaseImport(ptr);
}
}
}
Expand Down Expand Up @@ -1013,19 +1019,18 @@ private void BuildMatrix()
}

//Transforms the root node of the scene and writes it back to the native structure
private bool TransformScene(IntPtr scene)
private unsafe bool TransformScene(AiScene* scene)
{
BuildMatrix();

try
{
if(!m_scaleRot.IsIdentity)
{
AiScene aiScene = MemoryHelper.MarshalStructure<AiScene>(scene);
if(aiScene.RootNode == IntPtr.Zero)
if(scene->RootNode == IntPtr.Zero)
return false;

IntPtr matrixPtr = aiScene.RootNode + MemoryHelper.SizeOf<AiString>(); //Skip over Node Name
IntPtr matrixPtr = scene->RootNode + MemoryHelper.SizeOf<AiString>(); //Skip over Node Name

Matrix4x4 matrix = MemoryHelper.Read<Matrix4x4>(matrixPtr); //Get the root transform
matrix = matrix * m_scaleRot; //Transform
Expand All @@ -1044,14 +1049,14 @@ private bool TransformScene(IntPtr scene)
return false;
}

private IntPtr ApplyPostProcessing(IntPtr scene, PostProcessSteps postProcessFlags)
private unsafe AiScene* ApplyPostProcessing(AiScene* scene, PostProcessSteps postProcessFlags)
{
if(postProcessFlags == PostProcessSteps.None || scene == IntPtr.Zero)
if(postProcessFlags == PostProcessSteps.None || scene == null)
return scene;

scene = AssimpLibrary.Instance.ApplyPostProcessing(scene, postProcessFlags);
scene = AssimpLibrary.aiApplyPostProcessing(scene, postProcessFlags);

if(scene == IntPtr.Zero)
if(scene == null)
{
string error = AssimpLibrary.Instance.GetErrorString();
throw new AssimpException(error.Length == 0
Expand Down
2 changes: 1 addition & 1 deletion AssimpNet/AssimpNet.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<Authors>Nicholas Woodfield, Salvage</Authors>
<Company />
<Version>5.4.3.0</Version>
<Version>5.4.3.1</Version>
<PackageLicenseFile>License.txt</PackageLicenseFile>
<Copyright>Copyright © 2012-2020 Nicholas Woodfield, © 2024 Salvage</Copyright>
<PackageIcon>logo.png</PackageIcon>
Expand Down
2 changes: 1 addition & 1 deletion AssimpNet/Bone.cs
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ public static void FreeNative(IntPtr nativeValue, bool freeNative)
int numWeights = MemoryHelper.Read<int>(nativeValue + MemoryHelper.SizeOf<AiString>());
IntPtr weightsPtr = nativeValue + MemoryHelper.SizeOf<AiString>() + sizeof(uint);

if(aiBone.NumWeights > 0 && aiBone.Weights != IntPtr.Zero)
if(aiBone.NumWeights > 0 && aiBone.Weights != null)
MemoryHelper.FreeMemory(aiBone.Weights);

if(freeNative)
Expand Down
10 changes: 5 additions & 5 deletions AssimpNet/ExportDataBlob.cs
Original file line number Diff line number Diff line change
Expand Up @@ -77,18 +77,18 @@ public sealed class ExportDataBlob
/// Creates a new ExportDataBlob.
/// </summary>
/// <param name="dataBlob">Unmanaged structure.</param>
internal ExportDataBlob(ref AiExportDataBlob dataBlob)
internal unsafe 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());
if(dataBlob.Size.ToUInt32() > 0 && dataBlob.Data != null)
m_data = MemoryHelper.FromNativeArray<byte>(dataBlob.Data, (int)dataBlob.Size.ToUInt32());

m_next = null;

if(dataBlob.NextBlob != IntPtr.Zero)
if(dataBlob.NextBlob != null)
{
AiExportDataBlob nextBlob = MemoryHelper.MarshalStructure<AiExportDataBlob>(dataBlob.NextBlob);
AiExportDataBlob nextBlob = *dataBlob.NextBlob;
m_next = new ExportDataBlob(ref nextBlob);
}
}
Expand Down
116 changes: 10 additions & 106 deletions AssimpNet/MemoryHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ public static IntPtr ToNativeArray<Managed, Native>(IReadOnlyCollection<Managed>
return IntPtr.Zero;

bool isNativeBlittable = IsNativeBlittable<Managed, Native>(managedColl);
int sizeofNative = (isNativeBlittable) ? SizeOf<Native>() : MarshalSizeOf<Native>();
int sizeofNative = SizeOf<Native>();

//If the pointer is a void** we need to step by the pointer size, otherwise it's just a void* and step by the type size.
int stride = (arrayOfPointers) ? IntPtr.Size : sizeofNative;
Expand Down Expand Up @@ -218,9 +218,9 @@ public static IntPtr ToNativeArray<T>(List<T> managedArray) where T : struct
/// <param name="nativeArray">Pointer to unmanaged memory</param>
/// <param name="length">Number of elements to read</param>
/// <returns>Managed array</returns>
public static T[] FromNativeArray<T>(IntPtr nativeArray, int length) where T : struct
public static unsafe T[] FromNativeArray<T>(void* nativeArray, int length) where T : struct
{
if(nativeArray == IntPtr.Zero || length == 0)
if(nativeArray == null || length == 0)
return Array.Empty<T>();

T[] managedArray = new T[length];
Expand Down Expand Up @@ -305,118 +305,22 @@ public static IntPtr ToNativePointer<Managed, Native>(Managed managedValue)
/// <typeparam name="Native">Unmanaged type</typeparam>
/// <param name="ptr">Pointer to unmanaged memory</param>
/// <returns>The marshaled managed value</returns>
public static Managed FromNativePointer<Managed, Native>(IntPtr ptr)
public static unsafe Managed FromNativePointer<Managed, Native>(Native* ptr)

Check warning on line 308 in AssimpNet/MemoryHelper.cs

View workflow job for this annotation

GitHub Actions / Build MacOS ARM64 Debug

This takes the address of, gets the size of, or declares a pointer to a managed type ('Native')

Check warning on line 308 in AssimpNet/MemoryHelper.cs

View workflow job for this annotation

GitHub Actions / Build MacOS ARM64 Release

This takes the address of, gets the size of, or declares a pointer to a managed type ('Native')

Check warning on line 308 in AssimpNet/MemoryHelper.cs

View workflow job for this annotation

GitHub Actions / Build Linux Debug

This takes the address of, gets the size of, or declares a pointer to a managed type ('Native')

Check warning on line 308 in AssimpNet/MemoryHelper.cs

View workflow job for this annotation

GitHub Actions / Build Linux Release

This takes the address of, gets the size of, or declares a pointer to a managed type ('Native')

Check warning on line 308 in AssimpNet/MemoryHelper.cs

View workflow job for this annotation

GitHub Actions / Build MacOS x64 Debug

This takes the address of, gets the size of, or declares a pointer to a managed type ('Native')

Check warning on line 308 in AssimpNet/MemoryHelper.cs

View workflow job for this annotation

GitHub Actions / Build MacOS x64 Release

This takes the address of, gets the size of, or declares a pointer to a managed type ('Native')

Check warning on line 308 in AssimpNet/MemoryHelper.cs

View workflow job for this annotation

GitHub Actions / Build Windows x86 Debug

This takes the address of, gets the size of, or declares a pointer to a managed type ('Native')

Check warning on line 308 in AssimpNet/MemoryHelper.cs

View workflow job for this annotation

GitHub Actions / Build Windows x64 Release

This takes the address of, gets the size of, or declares a pointer to a managed type ('Native')

Check warning on line 308 in AssimpNet/MemoryHelper.cs

View workflow job for this annotation

GitHub Actions / Build Windows x64 Debug

This takes the address of, gets the size of, or declares a pointer to a managed type ('Native')

Check warning on line 308 in AssimpNet/MemoryHelper.cs

View workflow job for this annotation

GitHub Actions / Build Windows x86 Release

This takes the address of, gets the size of, or declares a pointer to a managed type ('Native')
where Managed : class, IMarshalable<Managed, Native>, new()
where Native : struct
{

if(ptr == IntPtr.Zero)
if(ptr == null)
return null;

Managed managedValue = Activator.CreateInstance<Managed>();

//Marshal pointer to structure
Native nativeValue;

if(managedValue.IsNativeBlittable)
{
Read<Native>(ptr, out nativeValue);
}
else
{
MarshalStructure<Native>(ptr, out nativeValue);
}

//Populate managed value
managedValue.FromNative(nativeValue);
managedValue.FromNative(*ptr);

return managedValue;
}

/// <summary>
/// Convienence method for marshaling a pointer to a structure. Only use if the type is not blittable, otherwise
/// use the read methods for blittable types.
/// </summary>
/// <typeparam name="T">Struct type</typeparam>
/// <param name="ptr">Pointer to marshal</param>
/// <param name="value">The marshaled structure</param>
public static void MarshalStructure<T>(IntPtr ptr, out T value) where T : struct
{
if(ptr == IntPtr.Zero)
value = default(T);

Type type = typeof(T);

INativeCustomMarshaler marshaler;
if (HasNativeCustomMarshaler(type, out marshaler))
{
value = (T)marshaler.MarshalNativeToManaged(ptr);
return;
}

value = Marshal.PtrToStructure<T>(ptr);
}

/// <summary>
/// Convienence method for marshaling a pointer to a structure. Only use if the type is not blittable, otherwise
/// use the read methods for blittable types.
/// </summary>
/// <typeparam name="T">Struct type</typeparam>
/// <param name="ptr">Pointer to marshal</param>
/// <returns>The marshaled structure</returns>
public static T MarshalStructure<T>(IntPtr ptr) where T : struct
{
if(ptr == IntPtr.Zero)
return default(T);

Type type = typeof(T);

INativeCustomMarshaler marshaler;
if (HasNativeCustomMarshaler(type, out marshaler))
return (T) marshaler.MarshalNativeToManaged(ptr);

return Marshal.PtrToStructure<T>(ptr);
}

/// <summary>
/// Convienence method for marshaling a structure to a pointer. Only use if the type is not blittable, otherwise
/// use the write methods for blittable types.
/// </summary>
/// <typeparam name="T">Struct type</typeparam>
/// <param name="value">Struct to marshal</param>
/// <param name="ptr">Pointer to unmanaged chunk of memory which must be allocated prior to this call</param>
public static void MarshalPointer<T>(in T value, IntPtr ptr) where T : struct
{
if (ptr == IntPtr.Zero)
return;

INativeCustomMarshaler marshaler;
if (HasNativeCustomMarshaler(typeof(T), out marshaler))
{
marshaler.MarshalManagedToNative((object)value, ptr);
return;
}

Marshal.StructureToPtr<T>(value, ptr, true);
}

/// <summary>
/// Computes the size of the struct type using Marshal SizeOf. Only use if the type is not blittable, thus requiring marshaling by the runtime,
/// (e.g. has MarshalAs attributes), otherwise use the SizeOf methods for blittable types.
/// </summary>
/// <typeparam name="T">Struct type</typeparam>
/// <returns>Size of the struct in bytes.</returns>
public static unsafe int MarshalSizeOf<T>() where T : struct
{
Type type = typeof(T);

INativeCustomMarshaler marshaler;
if (HasNativeCustomMarshaler(type, out marshaler))
return marshaler.NativeDataSize;

return Marshal.SizeOf<T>();
}

#endregion

#region Memory Interop (Shared code from other Projects)
Expand Down Expand Up @@ -559,9 +463,9 @@ public static unsafe void CopyMemory(IntPtr pDest, IntPtr pSrc, int sizeInBytesT
/// <param name="data">Array to store the copied data</param>
/// <param name="startIndexInArray">Zero-based element index to start writing data to in the element array.</param>
/// <param name="count">Number of elements to copy</param>
public static unsafe void Read<T>(IntPtr pSrc, T[] data, int startIndexInArray, int count) where T : struct
public static unsafe void Read<T>(void* pSrc, T[] data, int startIndexInArray, int count) where T : struct
{
ReadOnlySpan<T> src = new ReadOnlySpan<T>(pSrc.ToPointer(), count);
ReadOnlySpan<T> src = new ReadOnlySpan<T>(pSrc, count);
Span<T> dst = new Span<T>(data, startIndexInArray, count);
src.CopyTo(dst);
}
Expand All @@ -583,9 +487,9 @@ public static unsafe T Read<T>(IntPtr pSrc) where T : struct
/// <typeparam name="T">Struct type</typeparam>
/// <param name="pSrc">Pointer to memory location</param>
/// <param name="value">The read value.</param>
public static unsafe void Read<T>(IntPtr pSrc, out T value) where T : struct
public static unsafe void Read<T>(T* pSrc, out T value) where T : struct

Check warning on line 490 in AssimpNet/MemoryHelper.cs

View workflow job for this annotation

GitHub Actions / Build MacOS ARM64 Debug

This takes the address of, gets the size of, or declares a pointer to a managed type ('T')

Check warning on line 490 in AssimpNet/MemoryHelper.cs

View workflow job for this annotation

GitHub Actions / Build MacOS ARM64 Release

This takes the address of, gets the size of, or declares a pointer to a managed type ('T')

Check warning on line 490 in AssimpNet/MemoryHelper.cs

View workflow job for this annotation

GitHub Actions / Build Linux Debug

This takes the address of, gets the size of, or declares a pointer to a managed type ('T')

Check warning on line 490 in AssimpNet/MemoryHelper.cs

View workflow job for this annotation

GitHub Actions / Build Linux Release

This takes the address of, gets the size of, or declares a pointer to a managed type ('T')

Check warning on line 490 in AssimpNet/MemoryHelper.cs

View workflow job for this annotation

GitHub Actions / Build MacOS x64 Debug

This takes the address of, gets the size of, or declares a pointer to a managed type ('T')

Check warning on line 490 in AssimpNet/MemoryHelper.cs

View workflow job for this annotation

GitHub Actions / Build MacOS x64 Release

This takes the address of, gets the size of, or declares a pointer to a managed type ('T')

Check warning on line 490 in AssimpNet/MemoryHelper.cs

View workflow job for this annotation

GitHub Actions / Build Windows x86 Debug

This takes the address of, gets the size of, or declares a pointer to a managed type ('T')

Check warning on line 490 in AssimpNet/MemoryHelper.cs

View workflow job for this annotation

GitHub Actions / Build Windows x64 Release

This takes the address of, gets the size of, or declares a pointer to a managed type ('T')

Check warning on line 490 in AssimpNet/MemoryHelper.cs

View workflow job for this annotation

GitHub Actions / Build Windows x64 Debug

This takes the address of, gets the size of, or declares a pointer to a managed type ('T')

Check warning on line 490 in AssimpNet/MemoryHelper.cs

View workflow job for this annotation

GitHub Actions / Build Windows x86 Release

This takes the address of, gets the size of, or declares a pointer to a managed type ('T')
{
value = Unsafe.ReadUnaligned<T>(pSrc.ToPointer());
value = Unsafe.ReadUnaligned<T>(pSrc);
}

/// <summary>
Expand Down
4 changes: 2 additions & 2 deletions AssimpNet/Scene.cs
Original file line number Diff line number Diff line change
Expand Up @@ -273,9 +273,9 @@ public static IntPtr ToUnmanagedScene(Scene scene)
/// </summary>
/// <param name="scenePtr">The unmanaged scene data</param>
/// <returns>The managed scene, or null if the pointer is NULL</returns>
public static Scene FromUnmanagedScene(IntPtr scenePtr)
public static unsafe Scene FromUnmanagedScene(AiScene* scenePtr)
{
if(scenePtr == IntPtr.Zero)
if(scenePtr == null)
return null;

return MemoryHelper.FromNativePointer<Scene, AiScene>(scenePtr);
Expand Down
14 changes: 7 additions & 7 deletions AssimpNet/Unmanaged/UnmanagedStructures.cs
Original file line number Diff line number Diff line change
Expand Up @@ -408,7 +408,7 @@ public static string GetFormatHint(in AiTexture aiTex)
/// Represents an aiFace struct.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public struct AiFace
public unsafe struct AiFace
{
/// <summary>
/// Number of indices in the face.
Expand All @@ -418,14 +418,14 @@ public struct AiFace
/// <summary>
/// unsigned int*, array of indices.
/// </summary>
public IntPtr Indices;
public uint* Indices;
}

/// <summary>
/// Represents an aiBone struct.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public struct AiBone
public unsafe struct AiBone
{
/// <summary>
/// Name of the bone.
Expand All @@ -450,7 +450,7 @@ public struct AiBone
/// <summary>
/// VertexWeight*, array of vertex weights.
/// </summary>
public IntPtr Weights;
public VertexWeight* Weights;

/// <summary>
/// Matrix that transforms the vertex from mesh to bone space in bind pose
Expand Down Expand Up @@ -1137,7 +1137,7 @@ public struct AiExportFormatDesc
/// blobs represent auxillary files produced by the exporter (e.g. material files) and are named accordingly.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public struct AiExportDataBlob
public unsafe struct AiExportDataBlob
{
/// <summary>
/// size_t, size of the data in bytes.
Expand All @@ -1147,7 +1147,7 @@ public struct AiExportDataBlob
/// <summary>
/// void*, the data.
/// </summary>
public IntPtr Data;
public void* Data;

/// <summary>
/// AiString, name of the blob.
Expand All @@ -1157,7 +1157,7 @@ public struct AiExportDataBlob
/// <summary>
/// aiExportDataBlob*, pointer to the next blob in the chain.
/// </summary>
public IntPtr NextBlob;
public AiExportDataBlob* NextBlob;
}

/// <summary>
Expand Down

0 comments on commit 6ca492b

Please sign in to comment.