mirror of
https://github.com/AlexMacocian/MonoGame.Extended.git
synced 2026-07-24 03:56:31 +00:00
153 lines
4.6 KiB
C#
153 lines
4.6 KiB
C#
using System;
|
|
using System.Runtime.InteropServices;
|
|
|
|
namespace MonoGame.Extended.Particles
|
|
{
|
|
public class ParticleBuffer : IDisposable
|
|
{
|
|
private readonly ParticleIterator _iterator;
|
|
private readonly IntPtr _nativePointer;
|
|
|
|
// points to the first memory pos after the buffer
|
|
protected readonly unsafe Particle* BufferEnd;
|
|
|
|
private bool _disposed;
|
|
// points to the particle after the last active particle.
|
|
protected unsafe Particle* Tail;
|
|
|
|
public unsafe ParticleBuffer(int size)
|
|
{
|
|
Size = size;
|
|
_nativePointer = Marshal.AllocHGlobal(SizeInBytes);
|
|
|
|
BufferEnd = (Particle*) (_nativePointer + SizeInBytes);
|
|
Head = (Particle*) _nativePointer;
|
|
Tail = (Particle*) _nativePointer;
|
|
|
|
_iterator = new ParticleIterator(this);
|
|
|
|
GC.AddMemoryPressure(SizeInBytes);
|
|
}
|
|
|
|
public int Size { get; }
|
|
|
|
public ParticleIterator Iterator => _iterator.Reset();
|
|
// pointer to the first particle
|
|
public unsafe Particle* Head { get; private set; }
|
|
|
|
// Number of available particle spots in the buffer
|
|
public int Available => Size - Count;
|
|
// current number of particles
|
|
public int Count { get; private set; }
|
|
// total size of the buffer (add one extra spot in memory for margin between head and tail so the iterator can see that it's at the end)
|
|
public int SizeInBytes => Particle.SizeInBytes*(Size + 1);
|
|
// total size of active particles
|
|
public int ActiveSizeInBytes => Particle.SizeInBytes*Count;
|
|
|
|
public void Dispose()
|
|
{
|
|
if (!_disposed)
|
|
{
|
|
Marshal.FreeHGlobal(_nativePointer);
|
|
_disposed = true;
|
|
GC.RemoveMemoryPressure(SizeInBytes);
|
|
}
|
|
|
|
GC.SuppressFinalize(this);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Release the given number of particles or the most available.
|
|
/// Returns a started iterator to iterate over the new particles.
|
|
/// </summary>
|
|
public unsafe ParticleIterator Release(int releaseQuantity)
|
|
{
|
|
var numToRelease = Math.Min(releaseQuantity, Available);
|
|
|
|
var prevCount = Count;
|
|
Count += numToRelease;
|
|
|
|
Tail += numToRelease;
|
|
if (Tail >= BufferEnd) Tail -= Size + 1;
|
|
|
|
return Iterator.Reset(prevCount);
|
|
}
|
|
|
|
public unsafe void Reclaim(int number)
|
|
{
|
|
Count -= number;
|
|
|
|
Head += number;
|
|
if (Head >= BufferEnd)
|
|
Head -= Size + 1;
|
|
}
|
|
|
|
//public void CopyTo(IntPtr destination)
|
|
//{
|
|
// memcpy(destination, _nativePointer, ActiveSizeInBytes);
|
|
//}
|
|
|
|
//public void CopyToReverse(IntPtr destination)
|
|
//{
|
|
// var offset = 0;
|
|
// for (var i = ActiveSizeInBytes - Particle.SizeInBytes; i >= 0; i -= Particle.SizeInBytes)
|
|
// {
|
|
// memcpy(IntPtr.Add(destination, offset), IntPtr.Add(_nativePointer, i), Particle.SizeInBytes);
|
|
// offset += Particle.SizeInBytes;
|
|
// }
|
|
//}
|
|
|
|
//[DllImport("msvcrt.dll", EntryPoint = "memcpy", CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
|
|
//public static extern void memcpy(IntPtr dest, IntPtr src, int count);
|
|
|
|
~ParticleBuffer()
|
|
{
|
|
Dispose();
|
|
}
|
|
|
|
public class ParticleIterator
|
|
{
|
|
private readonly ParticleBuffer _buffer;
|
|
|
|
private unsafe Particle* _current;
|
|
|
|
public int Total;
|
|
|
|
public ParticleIterator(ParticleBuffer buffer)
|
|
{
|
|
_buffer = buffer;
|
|
}
|
|
|
|
public unsafe bool HasNext => _current != _buffer.Tail;
|
|
|
|
public unsafe ParticleIterator Reset()
|
|
{
|
|
_current = _buffer.Head;
|
|
Total = _buffer.Count;
|
|
return this;
|
|
}
|
|
|
|
internal unsafe ParticleIterator Reset(int offset)
|
|
{
|
|
Total = _buffer.Count;
|
|
|
|
_current = _buffer.Head + offset;
|
|
if (_current >= _buffer.BufferEnd)
|
|
_current -= _buffer.Size + 1;
|
|
|
|
return this;
|
|
}
|
|
|
|
public unsafe Particle* Next()
|
|
{
|
|
var p = _current;
|
|
_current++;
|
|
if (_current == _buffer.BufferEnd)
|
|
_current = (Particle*) _buffer._nativePointer;
|
|
|
|
return p;
|
|
}
|
|
}
|
|
}
|
|
}
|