(ded4a3e0a) v0.9.0.7
This commit is contained in:
@@ -0,0 +1,21 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
namespace Microsoft.Xna.Framework.Graphics
|
||||
{
|
||||
/// <summary>
|
||||
/// A usage hint for optimizing memory placement of graphics buffers.
|
||||
/// </summary>
|
||||
public enum BufferUsage
|
||||
{
|
||||
/// <summary>
|
||||
/// No special usage.
|
||||
/// </summary>
|
||||
None,
|
||||
/// <summary>
|
||||
/// The buffer will not be readable and will be optimized for rendering and writing.
|
||||
/// </summary>
|
||||
WriteOnly
|
||||
}
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Graphics
|
||||
{
|
||||
public class DynamicIndexBuffer : IndexBuffer
|
||||
{
|
||||
/// <summary>
|
||||
/// Special offset used internally by GraphicsDevice.DrawUserXXX() methods.
|
||||
/// </summary>
|
||||
internal int UserOffset;
|
||||
|
||||
public bool IsContentLost { get { return false; } }
|
||||
|
||||
public DynamicIndexBuffer(GraphicsDevice graphicsDevice, IndexElementSize indexElementSize, int indexCount, BufferUsage usage) :
|
||||
base(graphicsDevice, indexElementSize, indexCount, usage, true)
|
||||
{
|
||||
}
|
||||
|
||||
public DynamicIndexBuffer(GraphicsDevice graphicsDevice, Type indexType, int indexCount, BufferUsage usage) :
|
||||
base(graphicsDevice, indexType, indexCount, usage, true)
|
||||
{
|
||||
}
|
||||
|
||||
public void SetData<T>(int offsetInBytes, T[] data, int startIndex, int elementCount, SetDataOptions options) where T : struct
|
||||
{
|
||||
base.SetDataInternal<T>(offsetInBytes, data, startIndex, elementCount, options);
|
||||
}
|
||||
|
||||
public void SetData<T>(T[] data, int startIndex, int elementCount, SetDataOptions options) where T : struct
|
||||
{
|
||||
base.SetDataInternal<T>(0, data, startIndex, elementCount, options);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
using MonoGame.Utilities;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Graphics
|
||||
{
|
||||
public class DynamicVertexBuffer : VertexBuffer
|
||||
{
|
||||
/// <summary>
|
||||
/// Special offset used internally by GraphicsDevice.DrawUserXXX() methods.
|
||||
/// </summary>
|
||||
internal int UserOffset;
|
||||
|
||||
public bool IsContentLost { get { return false; } }
|
||||
|
||||
public DynamicVertexBuffer(GraphicsDevice graphicsDevice, VertexDeclaration vertexDeclaration, int vertexCount, BufferUsage bufferUsage)
|
||||
: base(graphicsDevice, vertexDeclaration, vertexCount, bufferUsage, true)
|
||||
{
|
||||
}
|
||||
|
||||
public DynamicVertexBuffer(GraphicsDevice graphicsDevice, Type type, int vertexCount, BufferUsage bufferUsage)
|
||||
: base(graphicsDevice, VertexDeclaration.FromType(type), vertexCount, bufferUsage, true)
|
||||
{
|
||||
}
|
||||
|
||||
public void SetData<T>(int offsetInBytes, T[] data, int startIndex, int elementCount, int vertexStride, SetDataOptions options) where T : struct
|
||||
{
|
||||
base.SetDataInternal<T>(offsetInBytes, data, startIndex, elementCount, vertexStride, options);
|
||||
}
|
||||
|
||||
public void SetData<T>(T[] data, int startIndex, int elementCount, SetDataOptions options) where T : struct
|
||||
{
|
||||
var elementSizeInBytes = ReflectionHelpers.SizeOf<T>.Get();
|
||||
base.SetDataInternal<T>(0, data, startIndex, elementCount, elementSizeInBytes, options);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace Microsoft.Xna.Framework.Graphics
|
||||
{
|
||||
public interface IVertexType
|
||||
{
|
||||
VertexDeclaration VertexDeclaration
|
||||
{
|
||||
get;
|
||||
}
|
||||
}
|
||||
}
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Graphics
|
||||
{
|
||||
/// <summary>
|
||||
/// Immutable version of <see cref="VertexInputLayout"/>. Can be used as a key in the
|
||||
/// <see cref="InputLayoutCache"/>.
|
||||
/// </summary>
|
||||
internal sealed class ImmutableVertexInputLayout : VertexInputLayout
|
||||
{
|
||||
private readonly int _hashCode;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ImmutableVertexInputLayout"/> class.
|
||||
/// </summary>
|
||||
/// <param name="vertexDeclarations">The vertex declarations per resource slot.</param>
|
||||
/// <param name="instanceFrequencies">The instance frequencies per resource slot.</param>
|
||||
/// <remarks>
|
||||
/// The specified arrays are stored internally - the arrays are not copied.
|
||||
/// </remarks>
|
||||
public ImmutableVertexInputLayout(VertexDeclaration[] vertexDeclarations, int[] instanceFrequencies)
|
||||
: base(vertexDeclarations, instanceFrequencies, vertexDeclarations.Length)
|
||||
{
|
||||
Debug.Assert(VertexDeclarations.Length == Count);
|
||||
Debug.Assert(InstanceFrequencies.Length == Count);
|
||||
|
||||
// Pre-calculate hash code for fast lookup in dictionary.
|
||||
_hashCode = base.GetHashCode();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns a hash code for this instance.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A hash code for this instance, suitable for use in hashing algorithms and data
|
||||
/// structures like a hash table.
|
||||
/// </returns>
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return _hashCode;
|
||||
}
|
||||
}
|
||||
}
|
||||
+172
@@ -0,0 +1,172 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using MonoGame.Utilities;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Graphics
|
||||
{
|
||||
public partial class IndexBuffer
|
||||
{
|
||||
private SharpDX.Direct3D11.Buffer _buffer;
|
||||
|
||||
internal SharpDX.Direct3D11.Buffer Buffer
|
||||
{
|
||||
get
|
||||
{
|
||||
GenerateIfRequired();
|
||||
return _buffer;
|
||||
}
|
||||
}
|
||||
|
||||
private void PlatformConstruct(IndexElementSize indexElementSize, int indexCount)
|
||||
{
|
||||
GenerateIfRequired();
|
||||
}
|
||||
|
||||
private void PlatformGraphicsDeviceResetting()
|
||||
{
|
||||
SharpDX.Utilities.Dispose(ref _buffer);
|
||||
}
|
||||
|
||||
void GenerateIfRequired()
|
||||
{
|
||||
if (_buffer != null)
|
||||
return;
|
||||
|
||||
// TODO: To use true Immutable resources we would need to delay creation of
|
||||
// the Buffer until SetData() and recreate them if set more than once.
|
||||
|
||||
var sizeInBytes = IndexCount * (this.IndexElementSize == IndexElementSize.SixteenBits ? 2 : 4);
|
||||
|
||||
var accessflags = SharpDX.Direct3D11.CpuAccessFlags.None;
|
||||
var resUsage = SharpDX.Direct3D11.ResourceUsage.Default;
|
||||
|
||||
if (_isDynamic)
|
||||
{
|
||||
accessflags |= SharpDX.Direct3D11.CpuAccessFlags.Write;
|
||||
resUsage = SharpDX.Direct3D11.ResourceUsage.Dynamic;
|
||||
}
|
||||
|
||||
_buffer = new SharpDX.Direct3D11.Buffer(GraphicsDevice._d3dDevice,
|
||||
sizeInBytes,
|
||||
resUsage,
|
||||
SharpDX.Direct3D11.BindFlags.IndexBuffer,
|
||||
accessflags,
|
||||
SharpDX.Direct3D11.ResourceOptionFlags.None,
|
||||
0 // StructureSizeInBytes
|
||||
);
|
||||
}
|
||||
|
||||
private void PlatformGetData<T>(int offsetInBytes, T[] data, int startIndex, int elementCount) where T : struct
|
||||
{
|
||||
GenerateIfRequired();
|
||||
|
||||
if (_isDynamic)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
else
|
||||
{
|
||||
var deviceContext = GraphicsDevice._d3dContext;
|
||||
|
||||
// Copy the texture to a staging resource
|
||||
var stagingDesc = _buffer.Description;
|
||||
stagingDesc.BindFlags = SharpDX.Direct3D11.BindFlags.None;
|
||||
stagingDesc.CpuAccessFlags = SharpDX.Direct3D11.CpuAccessFlags.Read | SharpDX.Direct3D11.CpuAccessFlags.Write;
|
||||
stagingDesc.Usage = SharpDX.Direct3D11.ResourceUsage.Staging;
|
||||
stagingDesc.OptionFlags = SharpDX.Direct3D11.ResourceOptionFlags.None;
|
||||
using (var stagingBuffer = new SharpDX.Direct3D11.Buffer(GraphicsDevice._d3dDevice, stagingDesc))
|
||||
{
|
||||
lock (GraphicsDevice._d3dContext)
|
||||
deviceContext.CopyResource(_buffer, stagingBuffer);
|
||||
|
||||
int TsizeInBytes = SharpDX.Utilities.SizeOf<T>();
|
||||
var dataHandle = GCHandle.Alloc(data, GCHandleType.Pinned);
|
||||
try
|
||||
{
|
||||
var startBytes = startIndex * TsizeInBytes;
|
||||
var dataPtr = (IntPtr)(dataHandle.AddrOfPinnedObject().ToInt64() + startBytes);
|
||||
SharpDX.DataPointer DataPointer = new SharpDX.DataPointer(dataPtr, elementCount * TsizeInBytes);
|
||||
|
||||
lock (GraphicsDevice._d3dContext)
|
||||
{
|
||||
// Map the staging resource to a CPU accessible memory
|
||||
var box = deviceContext.MapSubresource(stagingBuffer, 0, SharpDX.Direct3D11.MapMode.Read, SharpDX.Direct3D11.MapFlags.None);
|
||||
|
||||
SharpDX.Utilities.CopyMemory(dataPtr, box.DataPointer + offsetInBytes, elementCount * TsizeInBytes);
|
||||
|
||||
// Make sure that we unmap the resource in case of an exception
|
||||
deviceContext.UnmapSubresource(stagingBuffer, 0);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
dataHandle.Free();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void PlatformSetDataInternal<T>(int offsetInBytes, T[] data, int startIndex, int elementCount, SetDataOptions options) where T : struct
|
||||
{
|
||||
GenerateIfRequired();
|
||||
|
||||
if (_isDynamic)
|
||||
{
|
||||
// We assume discard by default.
|
||||
var mode = SharpDX.Direct3D11.MapMode.WriteDiscard;
|
||||
if ((options & SetDataOptions.NoOverwrite) == SetDataOptions.NoOverwrite)
|
||||
mode = SharpDX.Direct3D11.MapMode.WriteNoOverwrite;
|
||||
|
||||
var d3dContext = GraphicsDevice._d3dContext;
|
||||
lock (d3dContext)
|
||||
{
|
||||
var dataBox = d3dContext.MapSubresource(_buffer, 0, mode, SharpDX.Direct3D11.MapFlags.None);
|
||||
SharpDX.Utilities.Write(IntPtr.Add(dataBox.DataPointer, offsetInBytes), data, startIndex,
|
||||
elementCount);
|
||||
d3dContext.UnmapSubresource(_buffer, 0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var elementSizeInBytes = ReflectionHelpers.SizeOf<T>.Get();
|
||||
var dataHandle = GCHandle.Alloc(data, GCHandleType.Pinned);
|
||||
try
|
||||
{
|
||||
var startBytes = startIndex * elementSizeInBytes;
|
||||
var dataPtr = (IntPtr)(dataHandle.AddrOfPinnedObject().ToInt64() + startBytes);
|
||||
|
||||
var box = new SharpDX.DataBox(dataPtr, elementCount * elementSizeInBytes, 0);
|
||||
|
||||
var region = new SharpDX.Direct3D11.ResourceRegion();
|
||||
region.Top = 0;
|
||||
region.Front = 0;
|
||||
region.Back = 1;
|
||||
region.Bottom = 1;
|
||||
region.Left = offsetInBytes;
|
||||
region.Right = offsetInBytes + (elementCount * elementSizeInBytes);
|
||||
|
||||
// TODO: We need to deal with threaded contexts here!
|
||||
var d3dContext = GraphicsDevice._d3dContext;
|
||||
lock (d3dContext)
|
||||
d3dContext.UpdateSubresource(box, _buffer, 0, region);
|
||||
}
|
||||
finally
|
||||
{
|
||||
dataHandle.Free();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
SharpDX.Utilities.Dispose(ref _buffer);
|
||||
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
}
|
||||
}
|
||||
+148
@@ -0,0 +1,148 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Runtime.InteropServices;
|
||||
using MonoGame.OpenGL;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Graphics
|
||||
{
|
||||
public partial class IndexBuffer
|
||||
{
|
||||
internal int ibo;
|
||||
|
||||
private void PlatformConstruct(IndexElementSize indexElementSize, int indexCount)
|
||||
{
|
||||
Threading.BlockOnUIThread(GenerateIfRequired);
|
||||
}
|
||||
|
||||
private void PlatformGraphicsDeviceResetting()
|
||||
{
|
||||
ibo = 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// If the IBO does not exist, create it.
|
||||
/// </summary>
|
||||
void GenerateIfRequired()
|
||||
{
|
||||
if (ibo == 0)
|
||||
{
|
||||
var sizeInBytes = IndexCount * (this.IndexElementSize == IndexElementSize.SixteenBits ? 2 : 4);
|
||||
|
||||
GL.GenBuffers(1, out ibo);
|
||||
GraphicsExtensions.CheckGLError();
|
||||
GL.BindBuffer(BufferTarget.ElementArrayBuffer, ibo);
|
||||
GraphicsExtensions.CheckGLError();
|
||||
GL.BufferData(BufferTarget.ElementArrayBuffer,
|
||||
(IntPtr)sizeInBytes, IntPtr.Zero, _isDynamic ? BufferUsageHint.StreamDraw : BufferUsageHint.StaticDraw);
|
||||
GraphicsExtensions.CheckGLError();
|
||||
}
|
||||
}
|
||||
|
||||
private void PlatformGetData<T>(int offsetInBytes, T[] data, int startIndex, int elementCount) where T : struct
|
||||
{
|
||||
#if GLES
|
||||
// Buffers are write-only on OpenGL ES 1.1 and 2.0. See the GL_OES_mapbuffer extension for more information.
|
||||
// http://www.khronos.org/registry/gles/extensions/OES/OES_mapbuffer.txt
|
||||
throw new NotSupportedException("Index buffers are write-only on OpenGL ES platforms");
|
||||
#endif
|
||||
#if !GLES
|
||||
if (Threading.IsOnUIThread())
|
||||
{
|
||||
GetBufferData(offsetInBytes, data, startIndex, elementCount);
|
||||
}
|
||||
else
|
||||
{
|
||||
Threading.BlockOnUIThread(() => GetBufferData(offsetInBytes, data, startIndex, elementCount));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !GLES
|
||||
private void GetBufferData<T>(int offsetInBytes, T[] data, int startIndex, int elementCount) where T : struct
|
||||
{
|
||||
GL.BindBuffer(BufferTarget.ElementArrayBuffer, ibo);
|
||||
GraphicsExtensions.CheckGLError();
|
||||
var elementSizeInByte = Marshal.SizeOf(typeof(T));
|
||||
IntPtr ptr = GL.MapBuffer(BufferTarget.ElementArrayBuffer, BufferAccess.ReadOnly);
|
||||
// Pointer to the start of data to read in the index buffer
|
||||
ptr = new IntPtr(ptr.ToInt64() + offsetInBytes);
|
||||
if (typeof(T) == typeof(byte))
|
||||
{
|
||||
byte[] buffer = data as byte[];
|
||||
// If data is already a byte[] we can skip the temporary buffer
|
||||
// Copy from the index buffer to the destination array
|
||||
Marshal.Copy(ptr, buffer, startIndex * elementSizeInByte, elementCount * elementSizeInByte);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Temporary buffer to store the copied section of data
|
||||
byte[] buffer = new byte[elementCount * elementSizeInByte];
|
||||
// Copy from the index buffer to the temporary buffer
|
||||
Marshal.Copy(ptr, buffer, 0, buffer.Length);
|
||||
// Copy from the temporary buffer to the destination array
|
||||
Buffer.BlockCopy(buffer, 0, data, startIndex * elementSizeInByte, elementCount * elementSizeInByte);
|
||||
}
|
||||
GL.UnmapBuffer(BufferTarget.ElementArrayBuffer);
|
||||
GraphicsExtensions.CheckGLError();
|
||||
}
|
||||
#endif
|
||||
|
||||
private void PlatformSetDataInternal<T>(int offsetInBytes, T[] data, int startIndex, int elementCount, SetDataOptions options) where T : struct
|
||||
{
|
||||
if (Threading.IsOnUIThread())
|
||||
{
|
||||
BufferData(offsetInBytes, data, startIndex, elementCount, options);
|
||||
}
|
||||
else
|
||||
{
|
||||
Threading.BlockOnUIThread(() => BufferData(offsetInBytes, data, startIndex, elementCount, options));
|
||||
}
|
||||
}
|
||||
|
||||
private void BufferData<T>(int offsetInBytes, T[] data, int startIndex, int elementCount, SetDataOptions options) where T : struct
|
||||
{
|
||||
GenerateIfRequired();
|
||||
|
||||
var elementSizeInByte = Marshal.SizeOf(typeof(T));
|
||||
var sizeInBytes = elementSizeInByte * elementCount;
|
||||
var dataHandle = GCHandle.Alloc(data, GCHandleType.Pinned);
|
||||
var dataPtr = (IntPtr)(dataHandle.AddrOfPinnedObject().ToInt64() + startIndex * elementSizeInByte);
|
||||
var bufferSize = IndexCount * (IndexElementSize == IndexElementSize.SixteenBits ? 2 : 4);
|
||||
|
||||
GL.BindBuffer(BufferTarget.ElementArrayBuffer, ibo);
|
||||
GraphicsExtensions.CheckGLError();
|
||||
|
||||
if (options == SetDataOptions.Discard)
|
||||
{
|
||||
// By assigning NULL data to the buffer this gives a hint
|
||||
// to the device to discard the previous content.
|
||||
GL.BufferData( BufferTarget.ElementArrayBuffer,
|
||||
(IntPtr)bufferSize,
|
||||
IntPtr.Zero,
|
||||
_isDynamic ? BufferUsageHint.StreamDraw : BufferUsageHint.StaticDraw);
|
||||
GraphicsExtensions.CheckGLError();
|
||||
}
|
||||
|
||||
GL.BufferSubData(BufferTarget.ElementArrayBuffer, (IntPtr)offsetInBytes, (IntPtr)sizeInBytes, dataPtr);
|
||||
GraphicsExtensions.CheckGLError();
|
||||
|
||||
dataHandle.Free();
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (!IsDisposed)
|
||||
{
|
||||
if (GraphicsDevice != null)
|
||||
GraphicsDevice.DisposeBuffer(ibo);
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
}
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Graphics
|
||||
{
|
||||
public partial class IndexBuffer
|
||||
{
|
||||
private void PlatformConstruct(IndexElementSize indexElementSize, int indexCount)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private void PlatformGraphicsDeviceResetting()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private void PlatformGetData<T>(int offsetInBytes, T[] data, int startIndex, int elementCount) where T : struct
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private void PlatformSetDataInternal<T>(int offsetInBytes, T[] data, int startIndex, int elementCount, SetDataOptions options) where T : struct
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
using MonoGame.Utilities;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Graphics
|
||||
{
|
||||
public partial class IndexBuffer : GraphicsResource
|
||||
{
|
||||
private readonly bool _isDynamic;
|
||||
|
||||
public BufferUsage BufferUsage { get; private set; }
|
||||
public int IndexCount { get; private set; }
|
||||
public IndexElementSize IndexElementSize { get; private set; }
|
||||
|
||||
protected IndexBuffer(GraphicsDevice graphicsDevice, Type indexType, int indexCount, BufferUsage usage, bool dynamic)
|
||||
: this(graphicsDevice, SizeForType(graphicsDevice, indexType), indexCount, usage, dynamic)
|
||||
{
|
||||
}
|
||||
|
||||
protected IndexBuffer(GraphicsDevice graphicsDevice, IndexElementSize indexElementSize, int indexCount, BufferUsage usage, bool dynamic)
|
||||
{
|
||||
if (graphicsDevice == null)
|
||||
{
|
||||
throw new ArgumentNullException("graphicsDevice", FrameworkResources.ResourceCreationWhenDeviceIsNull);
|
||||
}
|
||||
this.GraphicsDevice = graphicsDevice;
|
||||
this.IndexElementSize = indexElementSize;
|
||||
this.IndexCount = indexCount;
|
||||
this.BufferUsage = usage;
|
||||
|
||||
_isDynamic = dynamic;
|
||||
|
||||
PlatformConstruct(indexElementSize, indexCount);
|
||||
}
|
||||
|
||||
public IndexBuffer(GraphicsDevice graphicsDevice, IndexElementSize indexElementSize, int indexCount, BufferUsage bufferUsage) :
|
||||
this(graphicsDevice, indexElementSize, indexCount, bufferUsage, false)
|
||||
{
|
||||
}
|
||||
|
||||
public IndexBuffer(GraphicsDevice graphicsDevice, Type indexType, int indexCount, BufferUsage usage) :
|
||||
this(graphicsDevice, SizeForType(graphicsDevice, indexType), indexCount, usage, false)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the relevant IndexElementSize enum value for the given type.
|
||||
/// </summary>
|
||||
/// <param name="graphicsDevice">The graphics device.</param>
|
||||
/// <param name="type">The type to use for the index buffer</param>
|
||||
/// <returns>The IndexElementSize enum value that matches the type</returns>
|
||||
static IndexElementSize SizeForType(GraphicsDevice graphicsDevice, Type type)
|
||||
{
|
||||
switch (ReflectionHelpers.ManagedSizeOf(type))
|
||||
{
|
||||
case 2:
|
||||
return IndexElementSize.SixteenBits;
|
||||
case 4:
|
||||
if (graphicsDevice.GraphicsProfile == GraphicsProfile.Reach)
|
||||
throw new NotSupportedException("The profile does not support an elementSize of IndexElementSize.ThirtyTwoBits; use IndexElementSize.SixteenBits or a type that has a size of two bytes.");
|
||||
return IndexElementSize.ThirtyTwoBits;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException("type","Index buffers can only be created for types that are sixteen or thirty two bits in length");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The GraphicsDevice is resetting, so GPU resources must be recreated.
|
||||
/// </summary>
|
||||
internal protected override void GraphicsDeviceResetting()
|
||||
{
|
||||
PlatformGraphicsDeviceResetting();
|
||||
}
|
||||
|
||||
public void GetData<T>(int offsetInBytes, T[] data, int startIndex, int elementCount) where T : struct
|
||||
{
|
||||
if (data == null)
|
||||
throw new ArgumentNullException("data");
|
||||
if (data.Length < (startIndex + elementCount))
|
||||
throw new InvalidOperationException("The array specified in the data parameter is not the correct size for the amount of data requested.");
|
||||
if (BufferUsage == BufferUsage.WriteOnly)
|
||||
throw new NotSupportedException("This IndexBuffer was created with a usage type of BufferUsage.WriteOnly. Calling GetData on a resource that was created with BufferUsage.WriteOnly is not supported.");
|
||||
|
||||
PlatformGetData<T>(offsetInBytes, data, startIndex, elementCount);
|
||||
}
|
||||
|
||||
public void GetData<T>(T[] data, int startIndex, int elementCount) where T : struct
|
||||
{
|
||||
this.GetData<T>(0, data, startIndex, elementCount);
|
||||
}
|
||||
|
||||
public void GetData<T>(T[] data) where T : struct
|
||||
{
|
||||
this.GetData<T>(0, data, 0, data.Length);
|
||||
}
|
||||
|
||||
public void SetData<T>(int offsetInBytes, T[] data, int startIndex, int elementCount) where T : struct
|
||||
{
|
||||
SetDataInternal<T>(offsetInBytes, data, startIndex, elementCount, SetDataOptions.None);
|
||||
}
|
||||
|
||||
public void SetData<T>(T[] data, int startIndex, int elementCount) where T : struct
|
||||
{
|
||||
SetDataInternal<T>(0, data, startIndex, elementCount, SetDataOptions.None);
|
||||
}
|
||||
|
||||
public void SetData<T>(T[] data) where T : struct
|
||||
{
|
||||
SetDataInternal<T>(0, data, 0, data.Length, SetDataOptions.None);
|
||||
}
|
||||
|
||||
protected void SetDataInternal<T>(int offsetInBytes, T[] data, int startIndex, int elementCount, SetDataOptions options) where T : struct
|
||||
{
|
||||
if (data == null)
|
||||
throw new ArgumentNullException("data");
|
||||
if (data.Length < (startIndex + elementCount))
|
||||
throw new InvalidOperationException("The array specified in the data parameter is not the correct size for the amount of data requested.");
|
||||
|
||||
PlatformSetDataInternal<T>(offsetInBytes, data, startIndex, elementCount, options);
|
||||
}
|
||||
}
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
namespace Microsoft.Xna.Framework.Graphics
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines size for index in <see cref="IndexBuffer"/> and <see cref="DynamicIndexBuffer"/>.
|
||||
/// </summary>
|
||||
public enum IndexElementSize
|
||||
{
|
||||
/// <summary>
|
||||
/// 16-bit short/ushort value been used.
|
||||
/// </summary>
|
||||
SixteenBits,
|
||||
/// <summary>
|
||||
/// 32-bit int/uint value been used.
|
||||
/// </summary>
|
||||
ThirtyTwoBits
|
||||
}
|
||||
}
|
||||
+181
@@ -0,0 +1,181 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using SharpDX;
|
||||
using SharpDX.Direct3D11;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Graphics
|
||||
{
|
||||
/// <summary>
|
||||
/// Caches DirectX input layouts for the input assembler stage.
|
||||
/// </summary>
|
||||
internal class InputLayoutCache : IDisposable
|
||||
{
|
||||
#if DEBUG
|
||||
// Flag to print warning only once per shader.
|
||||
private bool _printWarning = true;
|
||||
#endif
|
||||
private readonly GraphicsDevice _graphicsDevice;
|
||||
private readonly byte[] _shaderByteCode;
|
||||
private readonly Dictionary<VertexInputLayout, InputLayout> _cache;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="InputLayoutCache"/> class.
|
||||
/// </summary>
|
||||
/// <param name="graphicsDevice">The graphics device.</param>
|
||||
/// <param name="shaderByteCode">The byte code of the vertex shader.</param>
|
||||
public InputLayoutCache(GraphicsDevice graphicsDevice, byte[] shaderByteCode)
|
||||
{
|
||||
Debug.Assert(graphicsDevice != null);
|
||||
Debug.Assert(shaderByteCode != null);
|
||||
|
||||
_graphicsDevice = graphicsDevice;
|
||||
_shaderByteCode = shaderByteCode;
|
||||
_cache = new Dictionary<VertexInputLayout, InputLayout>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Releases all resources used by an instance of the <see cref="InputLayoutCache"/> class.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This method calls the virtual <see cref="Dispose(bool)"/> method, passing in
|
||||
/// <see langword="true"/>, and then suppresses finalization of the instance.
|
||||
/// </remarks>
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Releases the unmanaged resources used by an instance of the
|
||||
/// <see cref="InputLayoutCache"/> class and optionally releases the managed resources.
|
||||
/// </summary>
|
||||
/// <param name="disposing">
|
||||
/// <see langword="true"/> to release both managed and unmanaged resources;
|
||||
/// <see langword="false"/> to release only unmanaged resources.
|
||||
/// </param>
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
// Dispose managed resources.
|
||||
foreach (var entry in _cache)
|
||||
entry.Value.Dispose();
|
||||
|
||||
_cache.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or create the DirectX input layout for the specified vertex buffers.
|
||||
/// </summary>
|
||||
/// <param name="vertexBuffers">The vertex buffers.</param>
|
||||
/// <returns>The DirectX input layout.</returns>
|
||||
public InputLayout GetOrCreate(VertexBufferBindings vertexBuffers)
|
||||
{
|
||||
InputLayout inputLayout;
|
||||
if (_cache.TryGetValue(vertexBuffers, out inputLayout))
|
||||
return inputLayout;
|
||||
|
||||
var vertexInputLayout = vertexBuffers.ToImmutable();
|
||||
var inputElements = vertexInputLayout.GetInputElements();
|
||||
try
|
||||
{
|
||||
inputLayout = new InputLayout(_graphicsDevice._d3dDevice, _shaderByteCode, inputElements);
|
||||
}
|
||||
catch (SharpDXException ex)
|
||||
{
|
||||
if (ex.Descriptor != Result.InvalidArg)
|
||||
throw;
|
||||
|
||||
// If InputLayout ctor fails with InvalidArg then it's most likely because the
|
||||
// vertex declaration doesn't match the vertex shader.
|
||||
// Shader probably used the semantic "SV_Position" in the vertex shader input.
|
||||
// Background information:
|
||||
// "SV_Position" is a "system-value semantic" which is interpreted by the
|
||||
// rasterizer stage. This means it needs to be used in the vertex shader output
|
||||
// or the pixel shader input. (See
|
||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/bb509647.aspx)
|
||||
//
|
||||
// However, some effects (notably the original XNA stock effects) use
|
||||
// "SV_Position" for the vertex shader input. This is technically allowed, but
|
||||
// rather uncommon and causes problems:
|
||||
// - XNA/MonoGame only has VertexElementUsage.Position, so there is no way to
|
||||
// distinguish between "POSITION" and "SV_Position".
|
||||
// - "SV_Position" cannot be used with any index other than 0, i.e. the DirectX
|
||||
// FX compiler does not accept "SV_Position1", "SV_Position2", ...
|
||||
// This is a problem when using multiple vertex streams, e.g. for blend shape
|
||||
// animations. It makes it impossible to correctly match the vertex
|
||||
// declaration with the vertex shader signature.
|
||||
//
|
||||
// Conclusion:
|
||||
// - MonoGame needs to translate VertexElementUsage.Position to "POSITION".
|
||||
// - MonoGame effects should always use "POSITION" for vertex shader inputs.
|
||||
|
||||
// Here is a workaround ("hack") for old vertex shaders which haven't been
|
||||
// updated: Rename "POSITION0" to "SV_Position" and try again.
|
||||
bool retry = false;
|
||||
for (int i = 0; i < inputElements.Length; i++)
|
||||
{
|
||||
if (inputElements[i].SemanticIndex == 0 && inputElements[i].SemanticName.Equals("POSITION", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
inputElements[i].SemanticName = "SV_Position";
|
||||
retry = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!retry)
|
||||
throw new InvalidOperationException(GetInvalidArgMessage(inputElements), ex);
|
||||
|
||||
try
|
||||
{
|
||||
inputLayout = new InputLayout(_graphicsDevice._d3dDevice, _shaderByteCode, inputElements);
|
||||
|
||||
// Workaround succeeded? This means that there is a vertex shader that needs
|
||||
// to be updated.
|
||||
#if DEBUG
|
||||
if (_printWarning)
|
||||
{
|
||||
Debug.WriteLine(
|
||||
"Warning: Vertex shader uses semantic 'SV_Position' for input register. " +
|
||||
"Please update the shader and use the semantic 'POSITION0' instead. The " +
|
||||
"semantic 'SV_Position' should only be used for the vertex shader output or " +
|
||||
"pixel shader input!");
|
||||
_printWarning = false;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
catch (SharpDXException)
|
||||
{
|
||||
// Workaround failed.
|
||||
throw new InvalidOperationException(GetInvalidArgMessage(inputElements), ex);
|
||||
}
|
||||
}
|
||||
|
||||
_cache.Add(vertexInputLayout, inputLayout);
|
||||
|
||||
return inputLayout;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a more helpful message for the SharpDX invalid arg error.
|
||||
/// </summary>
|
||||
/// <param name="inputElements">The input elements.</param>
|
||||
/// <returns>The exception message.</returns>
|
||||
private static string GetInvalidArgMessage(InputElement[] inputElements)
|
||||
{
|
||||
var elements = string.Join(", ", inputElements.Select(x => x.SemanticName + x.SemanticIndex));
|
||||
return "An error occurred while preparing to draw. "
|
||||
+ "This is probably because the current vertex declaration does not include all the elements "
|
||||
+ "required by the current vertex shader. The current vertex declaration includes these elements: "
|
||||
+ elements + ".";
|
||||
}
|
||||
}
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
namespace Microsoft.Xna.Framework.Graphics
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines how vertex data is ordered.
|
||||
/// </summary>
|
||||
public enum PrimitiveType
|
||||
{
|
||||
/// <summary>
|
||||
/// Renders the specified vertices as a sequence of isolated triangles. Each group of three vertices defines a separate triangle. Back-face culling is affected by the current winding-order render state.
|
||||
/// </summary>
|
||||
TriangleList,
|
||||
|
||||
/// <summary>
|
||||
/// Renders the vertices as a triangle strip. The back-face culling flag is flipped automatically on even-numbered triangles.
|
||||
/// </summary>
|
||||
TriangleStrip,
|
||||
|
||||
/// <summary>
|
||||
/// Renders the vertices as a list of isolated straight line segments; the count may be any positive integer.
|
||||
/// </summary>
|
||||
LineList,
|
||||
|
||||
/// <summary>
|
||||
/// Renders the vertices as a single polyline; the count may be any positive integer.
|
||||
/// </summary>
|
||||
LineStrip,
|
||||
}
|
||||
}
|
||||
+225
@@ -0,0 +1,225 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Graphics
|
||||
{
|
||||
public partial class VertexBuffer
|
||||
{
|
||||
private SharpDX.Direct3D11.Buffer _buffer;
|
||||
|
||||
private SharpDX.Direct3D11.Buffer _cachedStagingBuffer;
|
||||
|
||||
internal SharpDX.Direct3D11.Buffer Buffer
|
||||
{
|
||||
get
|
||||
{
|
||||
GenerateIfRequired();
|
||||
return _buffer;
|
||||
}
|
||||
}
|
||||
|
||||
private void PlatformConstruct()
|
||||
{
|
||||
GenerateIfRequired();
|
||||
}
|
||||
|
||||
private void PlatformGraphicsDeviceResetting()
|
||||
{
|
||||
SharpDX.Utilities.Dispose(ref _buffer);
|
||||
}
|
||||
|
||||
void GenerateIfRequired()
|
||||
{
|
||||
if (_buffer != null)
|
||||
return;
|
||||
|
||||
// TODO: To use Immutable resources we would need to delay creation of
|
||||
// the Buffer until SetData() and recreate them if set more than once.
|
||||
|
||||
var accessflags = SharpDX.Direct3D11.CpuAccessFlags.None;
|
||||
var usage = SharpDX.Direct3D11.ResourceUsage.Default;
|
||||
|
||||
if (_isDynamic)
|
||||
{
|
||||
accessflags |= SharpDX.Direct3D11.CpuAccessFlags.Write;
|
||||
usage = SharpDX.Direct3D11.ResourceUsage.Dynamic;
|
||||
}
|
||||
|
||||
_buffer = new SharpDX.Direct3D11.Buffer(GraphicsDevice._d3dDevice,
|
||||
VertexDeclaration.VertexStride * VertexCount,
|
||||
usage,
|
||||
SharpDX.Direct3D11.BindFlags.VertexBuffer,
|
||||
accessflags,
|
||||
SharpDX.Direct3D11.ResourceOptionFlags.None,
|
||||
0 // StructureSizeInBytes
|
||||
);
|
||||
}
|
||||
|
||||
void CreatedCachedStagingBuffer()
|
||||
{
|
||||
if (_cachedStagingBuffer != null)
|
||||
return;
|
||||
|
||||
var stagingDesc = _buffer.Description;
|
||||
stagingDesc.BindFlags = SharpDX.Direct3D11.BindFlags.None;
|
||||
stagingDesc.CpuAccessFlags = SharpDX.Direct3D11.CpuAccessFlags.Read | SharpDX.Direct3D11.CpuAccessFlags.Write;
|
||||
stagingDesc.Usage = SharpDX.Direct3D11.ResourceUsage.Staging;
|
||||
stagingDesc.OptionFlags = SharpDX.Direct3D11.ResourceOptionFlags.None;
|
||||
|
||||
_cachedStagingBuffer = new SharpDX.Direct3D11.Buffer(GraphicsDevice._d3dDevice, stagingDesc);
|
||||
}
|
||||
|
||||
private void PlatformGetData<T>(int offsetInBytes, T[] data, int startIndex, int elementCount, int vertexStride) where T : struct
|
||||
{
|
||||
GenerateIfRequired();
|
||||
|
||||
if (_isDynamic)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
else
|
||||
{
|
||||
var deviceContext = GraphicsDevice._d3dContext;
|
||||
|
||||
if (_cachedStagingBuffer == null)
|
||||
CreatedCachedStagingBuffer();
|
||||
|
||||
lock (GraphicsDevice._d3dContext)
|
||||
deviceContext.CopyResource(_buffer, _cachedStagingBuffer);
|
||||
|
||||
int TsizeInBytes = SharpDX.Utilities.SizeOf<T>();
|
||||
var dataHandle = GCHandle.Alloc(data, GCHandleType.Pinned);
|
||||
|
||||
try
|
||||
{
|
||||
var startBytes = startIndex * TsizeInBytes;
|
||||
var dataPtr = (IntPtr)(dataHandle.AddrOfPinnedObject().ToInt64() + startBytes);
|
||||
|
||||
lock (GraphicsDevice._d3dContext)
|
||||
{
|
||||
// Map the staging resource to a CPU accessible memory
|
||||
var box = deviceContext.MapSubresource(_cachedStagingBuffer, 0, SharpDX.Direct3D11.MapMode.Read, SharpDX.Direct3D11.MapFlags.None);
|
||||
|
||||
if (vertexStride == TsizeInBytes)
|
||||
{
|
||||
SharpDX.Utilities.CopyMemory(dataPtr, box.DataPointer + offsetInBytes, vertexStride * elementCount);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < elementCount; i++)
|
||||
SharpDX.Utilities.CopyMemory(dataPtr + i * TsizeInBytes, box.DataPointer + i * vertexStride + offsetInBytes, TsizeInBytes);
|
||||
}
|
||||
|
||||
// Make sure that we unmap the resource in case of an exception
|
||||
deviceContext.UnmapSubresource(_cachedStagingBuffer, 0);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
dataHandle.Free();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void PlatformSetDataInternal<T>(int offsetInBytes, T[] data, int startIndex, int elementCount, int vertexStride, SetDataOptions options, int bufferSize, int elementSizeInBytes) where T : struct
|
||||
{
|
||||
GenerateIfRequired();
|
||||
|
||||
if (_isDynamic)
|
||||
{
|
||||
// We assume discard by default.
|
||||
var mode = SharpDX.Direct3D11.MapMode.WriteDiscard;
|
||||
if ((options & SetDataOptions.NoOverwrite) == SetDataOptions.NoOverwrite)
|
||||
mode = SharpDX.Direct3D11.MapMode.WriteNoOverwrite;
|
||||
|
||||
var d3dContext = GraphicsDevice._d3dContext;
|
||||
lock (d3dContext)
|
||||
{
|
||||
var dataBox = d3dContext.MapSubresource(_buffer, 0, mode, SharpDX.Direct3D11.MapFlags.None);
|
||||
if (vertexStride == elementSizeInBytes)
|
||||
{
|
||||
SharpDX.Utilities.Write(dataBox.DataPointer + offsetInBytes, data, startIndex, elementCount);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < elementCount; i++)
|
||||
SharpDX.Utilities.Write(dataBox.DataPointer + offsetInBytes + i * vertexStride, data, startIndex + i, 1);
|
||||
}
|
||||
|
||||
d3dContext.UnmapSubresource(_buffer, 0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var dataHandle = GCHandle.Alloc(data, GCHandleType.Pinned);
|
||||
try
|
||||
{
|
||||
var startBytes = startIndex * elementSizeInBytes;
|
||||
var dataPtr = (IntPtr)(dataHandle.AddrOfPinnedObject().ToInt64() + startBytes);
|
||||
|
||||
var d3dContext = GraphicsDevice._d3dContext;
|
||||
|
||||
if (vertexStride == elementSizeInBytes)
|
||||
{
|
||||
var box = new SharpDX.DataBox(dataPtr, elementCount * elementSizeInBytes, 0);
|
||||
|
||||
var region = new SharpDX.Direct3D11.ResourceRegion();
|
||||
region.Top = 0;
|
||||
region.Front = 0;
|
||||
region.Back = 1;
|
||||
region.Bottom = 1;
|
||||
region.Left = offsetInBytes;
|
||||
region.Right = offsetInBytes + (elementCount * elementSizeInBytes);
|
||||
|
||||
lock (d3dContext)
|
||||
d3dContext.UpdateSubresource(box, _buffer, 0, region);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_cachedStagingBuffer == null)
|
||||
CreatedCachedStagingBuffer();
|
||||
|
||||
lock (d3dContext)
|
||||
{
|
||||
d3dContext.CopyResource(_buffer, _cachedStagingBuffer);
|
||||
|
||||
// Map the staging resource to a CPU accessible memory
|
||||
var box = d3dContext.MapSubresource(_cachedStagingBuffer, 0, SharpDX.Direct3D11.MapMode.Read,
|
||||
SharpDX.Direct3D11.MapFlags.None);
|
||||
|
||||
for (int i = 0; i < elementCount; i++)
|
||||
SharpDX.Utilities.CopyMemory(
|
||||
box.DataPointer + i * vertexStride + offsetInBytes,
|
||||
dataPtr + i * elementSizeInBytes, elementSizeInBytes);
|
||||
|
||||
// Make sure that we unmap the resource in case of an exception
|
||||
d3dContext.UnmapSubresource(_cachedStagingBuffer, 0);
|
||||
|
||||
// Copy back from staging resource to real buffer.
|
||||
d3dContext.CopyResource(_cachedStagingBuffer, _buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
dataHandle.Free();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
SharpDX.Utilities.Dispose(ref _buffer);
|
||||
SharpDX.Utilities.Dispose(ref _cachedStagingBuffer);
|
||||
}
|
||||
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
}
|
||||
}
|
||||
+183
@@ -0,0 +1,183 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Runtime.InteropServices;
|
||||
using MonoGame.OpenGL;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Graphics
|
||||
{
|
||||
public partial class VertexBuffer
|
||||
{
|
||||
//internal uint vao;
|
||||
internal int vbo;
|
||||
|
||||
private void PlatformConstruct()
|
||||
{
|
||||
Threading.BlockOnUIThread(GenerateIfRequired);
|
||||
}
|
||||
|
||||
private void PlatformGraphicsDeviceResetting()
|
||||
{
|
||||
vbo = 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// If the VBO does not exist, create it.
|
||||
/// </summary>
|
||||
void GenerateIfRequired()
|
||||
{
|
||||
if (vbo == 0)
|
||||
{
|
||||
//GLExt.Oes.GenVertexArrays(1, out this.vao);
|
||||
//GLExt.Oes.BindVertexArray(this.vao);
|
||||
GL.GenBuffers(1, out this.vbo);
|
||||
GraphicsExtensions.CheckGLError();
|
||||
GL.BindBuffer(BufferTarget.ArrayBuffer, this.vbo);
|
||||
GraphicsExtensions.CheckGLError();
|
||||
GL.BufferData(BufferTarget.ArrayBuffer,
|
||||
new IntPtr(VertexDeclaration.VertexStride * VertexCount), IntPtr.Zero,
|
||||
_isDynamic ? BufferUsageHint.StreamDraw : BufferUsageHint.StaticDraw);
|
||||
GraphicsExtensions.CheckGLError();
|
||||
}
|
||||
}
|
||||
|
||||
private void PlatformGetData<T>(int offsetInBytes, T[] data, int startIndex, int elementCount, int vertexStride) where T : struct
|
||||
{
|
||||
#if GLES
|
||||
// Buffers are write-only on OpenGL ES 1.1 and 2.0. See the GL_OES_mapbuffer extension for more information.
|
||||
// http://www.khronos.org/registry/gles/extensions/OES/OES_mapbuffer.txt
|
||||
throw new NotSupportedException("Vertex buffers are write-only on OpenGL ES platforms");
|
||||
#else
|
||||
Threading.BlockOnUIThread (() => GetBufferData(offsetInBytes, data, startIndex, elementCount, vertexStride));
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !GLES
|
||||
|
||||
private void GetBufferData<T>(int offsetInBytes, T[] data, int startIndex, int elementCount, int vertexStride) where T : struct
|
||||
{
|
||||
GL.BindBuffer(BufferTarget.ArrayBuffer, vbo);
|
||||
GraphicsExtensions.CheckGLError();
|
||||
|
||||
// Pointer to the start of data in the vertex buffer
|
||||
var ptr = GL.MapBuffer(BufferTarget.ArrayBuffer, BufferAccess.ReadOnly);
|
||||
GraphicsExtensions.CheckGLError();
|
||||
|
||||
ptr = (IntPtr) (ptr.ToInt64() + offsetInBytes);
|
||||
|
||||
if (typeof(T) == typeof(byte) && vertexStride == 1)
|
||||
{
|
||||
// If data is already a byte[] and stride is 1 we can skip the temporary buffer
|
||||
var buffer = data as byte[];
|
||||
Marshal.Copy(ptr, buffer, startIndex * vertexStride, elementCount * vertexStride);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Temporary buffer to store the copied section of data
|
||||
var tmp = new byte[elementCount * vertexStride];
|
||||
// Copy from the vertex buffer to the temporary buffer
|
||||
Marshal.Copy(ptr, tmp, 0, tmp.Length);
|
||||
|
||||
// Copy from the temporary buffer to the destination array
|
||||
var tmpHandle = GCHandle.Alloc(tmp, GCHandleType.Pinned);
|
||||
var tmpPtr = tmpHandle.AddrOfPinnedObject();
|
||||
try
|
||||
{
|
||||
for (var i = 0; i < elementCount; i++)
|
||||
{
|
||||
data[startIndex + i] = (T) Marshal.PtrToStructure(tmpPtr, typeof(T));
|
||||
tmpPtr = (IntPtr) (tmpPtr.ToInt64() + vertexStride);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
tmpHandle.Free();
|
||||
}
|
||||
}
|
||||
|
||||
GL.UnmapBuffer(BufferTarget.ArrayBuffer);
|
||||
GraphicsExtensions.CheckGLError();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
private void PlatformSetDataInternal<T>(int offsetInBytes, T[] data, int startIndex, int elementCount, int vertexStride, SetDataOptions options, int bufferSize, int elementSizeInBytes) where T : struct
|
||||
{
|
||||
Threading.BlockOnUIThread(() => SetBufferData(bufferSize, elementSizeInBytes, offsetInBytes, data, startIndex, elementCount, vertexStride, options));
|
||||
}
|
||||
|
||||
private void SetBufferData<T>(int bufferSize, int elementSizeInBytes, int offsetInBytes, T[] data, int startIndex, int elementCount, int vertexStride, SetDataOptions options) where T : struct
|
||||
{
|
||||
GenerateIfRequired();
|
||||
|
||||
GL.BindBuffer(BufferTarget.ArrayBuffer, vbo);
|
||||
GraphicsExtensions.CheckGLError();
|
||||
|
||||
if (options == SetDataOptions.Discard)
|
||||
{
|
||||
// By assigning NULL data to the buffer this gives a hint
|
||||
// to the device to discard the previous content.
|
||||
GL.BufferData( BufferTarget.ArrayBuffer,
|
||||
(IntPtr)bufferSize,
|
||||
IntPtr.Zero,
|
||||
_isDynamic ? BufferUsageHint.StreamDraw : BufferUsageHint.StaticDraw);
|
||||
GraphicsExtensions.CheckGLError();
|
||||
}
|
||||
|
||||
var elementSizeInByte = Marshal.SizeOf(typeof(T));
|
||||
if (elementSizeInByte == vertexStride || elementSizeInByte % vertexStride == 0)
|
||||
{
|
||||
// there are no gaps so we can copy in one go
|
||||
var dataHandle = GCHandle.Alloc(data, GCHandleType.Pinned);
|
||||
var dataPtr = (IntPtr) (dataHandle.AddrOfPinnedObject().ToInt64() + startIndex * elementSizeInBytes);
|
||||
try
|
||||
{
|
||||
GL.BufferSubData(BufferTarget.ArrayBuffer, (IntPtr) offsetInBytes, (IntPtr) (elementSizeInBytes * elementCount), dataPtr);
|
||||
GraphicsExtensions.CheckGLError();
|
||||
}
|
||||
finally
|
||||
{
|
||||
dataHandle.Free();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// else we must copy each element separately
|
||||
var dataHandle = GCHandle.Alloc(data, GCHandleType.Pinned);
|
||||
try
|
||||
{
|
||||
var dstOffset = offsetInBytes;
|
||||
var dataPtr = (IntPtr) (dataHandle.AddrOfPinnedObject().ToInt64() + startIndex * elementSizeInByte);
|
||||
for (var i = 0; i < elementCount; i++)
|
||||
{
|
||||
GL.BufferSubData(BufferTarget.ArrayBuffer, (IntPtr) dstOffset, (IntPtr) elementSizeInByte, dataPtr);
|
||||
GraphicsExtensions.CheckGLError();
|
||||
|
||||
dstOffset += vertexStride;
|
||||
dataPtr = (IntPtr) (dataPtr.ToInt64() + elementSizeInByte);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
dataHandle.Free();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (!IsDisposed)
|
||||
{
|
||||
if (GraphicsDevice != null)
|
||||
GraphicsDevice.DisposeBuffer(vbo);
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
}
|
||||
}
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Graphics
|
||||
{
|
||||
public partial class VertexBuffer
|
||||
{
|
||||
private void PlatformConstruct()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private void PlatformGetData<T>(
|
||||
int offsetInBytes,
|
||||
T[] data,
|
||||
int startIndex,
|
||||
int elementCount,
|
||||
int vertexStride)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private void PlatformSetDataInternal<T>(
|
||||
int offsetInBytes,
|
||||
T[] data,
|
||||
int startIndex,
|
||||
int elementCount,
|
||||
int vertexStride,
|
||||
SetDataOptions options,
|
||||
int bufferSize,
|
||||
int elementSizeInBytes)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private void PlatformGraphicsDeviceResetting()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
+217
@@ -0,0 +1,217 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
using MonoGame.Utilities;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Graphics
|
||||
{
|
||||
public partial class VertexBuffer : GraphicsResource
|
||||
{
|
||||
private readonly bool _isDynamic;
|
||||
|
||||
public int VertexCount { get; private set; }
|
||||
public VertexDeclaration VertexDeclaration { get; private set; }
|
||||
public BufferUsage BufferUsage { get; private set; }
|
||||
|
||||
protected VertexBuffer(GraphicsDevice graphicsDevice, VertexDeclaration vertexDeclaration, int vertexCount, BufferUsage bufferUsage, bool dynamic)
|
||||
{
|
||||
if (graphicsDevice == null)
|
||||
{
|
||||
throw new ArgumentNullException("graphicsDevice", FrameworkResources.ResourceCreationWhenDeviceIsNull);
|
||||
}
|
||||
this.GraphicsDevice = graphicsDevice;
|
||||
this.VertexDeclaration = vertexDeclaration;
|
||||
this.VertexCount = vertexCount;
|
||||
this.BufferUsage = bufferUsage;
|
||||
|
||||
// Make sure the graphics device is assigned in the vertex declaration.
|
||||
if (vertexDeclaration.GraphicsDevice != graphicsDevice)
|
||||
vertexDeclaration.GraphicsDevice = graphicsDevice;
|
||||
|
||||
_isDynamic = dynamic;
|
||||
|
||||
PlatformConstruct();
|
||||
}
|
||||
|
||||
public VertexBuffer(GraphicsDevice graphicsDevice, VertexDeclaration vertexDeclaration, int vertexCount, BufferUsage bufferUsage) :
|
||||
this(graphicsDevice, vertexDeclaration, vertexCount, bufferUsage, false)
|
||||
{
|
||||
}
|
||||
|
||||
public VertexBuffer(GraphicsDevice graphicsDevice, Type type, int vertexCount, BufferUsage bufferUsage) :
|
||||
this(graphicsDevice, VertexDeclaration.FromType(type), vertexCount, bufferUsage, false)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The GraphicsDevice is resetting, so GPU resources must be recreated.
|
||||
/// </summary>
|
||||
internal protected override void GraphicsDeviceResetting()
|
||||
{
|
||||
PlatformGraphicsDeviceResetting();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the vertex data froom this VertexBuffer.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The struct you want to fill.</typeparam>
|
||||
/// <param name="offsetInBytes">The offset to the first element in the vertex buffer in bytes.</param>
|
||||
/// <param name="data">An array of T's to be filled.</param>
|
||||
/// <param name="startIndex">The index to start filling the data array.</param>
|
||||
/// <param name="elementCount">The number of T's to get.</param>
|
||||
/// <param name="vertexStride">The size of how a vertex buffer element should be interpreted.</param>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Note that this pulls data from VRAM into main memory and because of that is a very expensive operation.
|
||||
/// It is often a better idea to keep a copy of the data in main memory.
|
||||
/// </remarks>
|
||||
///
|
||||
/// <remarks>
|
||||
/// <p>Using this operation it is easy to get certain vertex elements from a VertexBuffer.</p>
|
||||
/// <p>
|
||||
/// For example to get the texture coordinates from a VertexBuffer of <see cref="VertexPositionTexture"/> you can call
|
||||
/// GetData(4 * 3, data, elementCount, 20). 'data'should be an array of <see cref="Vector2"/> in this example.
|
||||
/// The offsetInBytes is the number of bytes taken up by the <see cref="VertexPositionTexture.Position"/> of the vertex.
|
||||
/// For vertexStride we pass the size of a <see cref="VertexPositionTexture"/>.
|
||||
/// </p>
|
||||
/// </remarks>
|
||||
public void GetData<T> (int offsetInBytes, T[] data, int startIndex, int elementCount, int vertexStride = 0) where T : struct
|
||||
{
|
||||
var elementSizeInBytes = ReflectionHelpers.SizeOf<T>.Get();
|
||||
if (vertexStride == 0)
|
||||
vertexStride = elementSizeInBytes;
|
||||
|
||||
var vertexByteSize = VertexCount * VertexDeclaration.VertexStride;
|
||||
if (vertexStride > vertexByteSize)
|
||||
throw new ArgumentOutOfRangeException("vertexStride", "Vertex stride can not be larger than the vertex buffer size.");
|
||||
|
||||
if (data == null)
|
||||
throw new ArgumentNullException("data");
|
||||
if (data.Length < (startIndex + elementCount))
|
||||
throw new ArgumentOutOfRangeException("elementCount", "This parameter must be a valid index within the array.");
|
||||
if (BufferUsage == BufferUsage.WriteOnly)
|
||||
throw new NotSupportedException("Calling GetData on a resource that was created with BufferUsage.WriteOnly is not supported.");
|
||||
if (elementCount > 1 && elementCount * vertexStride > vertexByteSize)
|
||||
throw new InvalidOperationException("The array is not the correct size for the amount of data requested.");
|
||||
|
||||
PlatformGetData<T>(offsetInBytes, data, startIndex, elementCount, vertexStride);
|
||||
}
|
||||
|
||||
public void GetData<T>(T[] data, int startIndex, int elementCount) where T : struct
|
||||
{
|
||||
this.GetData<T>(0, data, startIndex, elementCount, 0);
|
||||
}
|
||||
|
||||
public void GetData<T>(T[] data) where T : struct
|
||||
{
|
||||
var elementSizeInByte = ReflectionHelpers.SizeOf<T>.Get();
|
||||
this.GetData<T>(0, data, 0, data.Length, elementSizeInByte);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the vertex buffer data, specifying the index at which to start copying from the source data array,
|
||||
/// the number of elements to copy from the source data array,
|
||||
/// and how far apart elements from the source data array should be when they are copied into the vertex buffer.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type of elements in the data array.</typeparam>
|
||||
/// <param name="offsetInBytes">Offset in bytes from the beginning of the vertex buffer to the start of the copied data.</param>
|
||||
/// <param name="data">Data array.</param>
|
||||
/// <param name="startIndex">Index at which to start copying from <paramref name="data"/>.
|
||||
/// Must be within the <paramref name="data"/> array bounds.</param>
|
||||
/// <param name="elementCount">Number of elements to copy from <paramref name="data"/>.
|
||||
/// The combination of <paramref name="startIndex"/> and <paramref name="elementCount"/>
|
||||
/// must be within the <paramref name="data"/> array bounds.</param>
|
||||
/// <param name="vertexStride">Specifies how far apart, in bytes, elements from <paramref name="data"/> should be when
|
||||
/// they are copied into the vertex buffer.
|
||||
/// In almost all cases this should be <c>sizeof(T)</c>, to create a tightly-packed vertex buffer.
|
||||
/// If you specify <c>sizeof(T)</c>, elements from <paramref name="data"/> will be copied into the
|
||||
/// vertex buffer with no padding between each element.
|
||||
/// If you specify a value greater than <c>sizeof(T)</c>, elements from <paramref name="data"/> will be copied
|
||||
/// into the vertex buffer with padding between each element.
|
||||
/// If you specify <c>0</c> for this parameter, it will be treated as if you had specified <c>sizeof(T)</c>.
|
||||
/// With the exception of <c>0</c>, you must specify a value greater than or equal to <c>sizeof(T)</c>.</param>
|
||||
/// <remarks>
|
||||
/// If <c>T</c> is <c>VertexPositionTexture</c>, but you want to set only the position component of the vertex data,
|
||||
/// you would call this method as follows:
|
||||
/// <code>
|
||||
/// Vector3[] positions = new Vector3[numVertices];
|
||||
/// vertexBuffer.SetData(0, positions, 0, numVertices, vertexBuffer.VertexDeclaration.VertexStride);
|
||||
/// </code>
|
||||
///
|
||||
/// Continuing from the previous example, if you want to set only the texture coordinate component of the vertex data,
|
||||
/// you would call this method as follows (note the use of <paramref name="offsetInBytes"/>:
|
||||
/// <code>
|
||||
/// Vector2[] texCoords = new Vector2[numVertices];
|
||||
/// vertexBuffer.SetData(12, texCoords, 0, numVertices, vertexBuffer.VertexDeclaration.VertexStride);
|
||||
/// </code>
|
||||
/// </remarks>
|
||||
/// <remarks>
|
||||
/// If you provide a <c>byte[]</c> in the <paramref name="data"/> parameter, then you should almost certainly
|
||||
/// set <paramref name="vertexStride"/> to <c>1</c>, to avoid leaving any padding between the <c>byte</c> values
|
||||
/// when they are copied into the vertex buffer.
|
||||
/// </remarks>
|
||||
public void SetData<T>(int offsetInBytes, T[] data, int startIndex, int elementCount, int vertexStride) where T : struct
|
||||
{
|
||||
SetDataInternal<T>(offsetInBytes, data, startIndex, elementCount, vertexStride, SetDataOptions.None);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the vertex buffer data, specifying the index at which to start copying from the source data array,
|
||||
/// and the number of elements to copy from the source data array. This is the same as calling
|
||||
/// <see cref="SetData{T}(int, T[], int, int, int)"/> with <c>offsetInBytes</c> equal to <c>0</c>,
|
||||
/// and <c>vertexStride</c> equal to <c>sizeof(T)</c>.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type of elements in the data array.</typeparam>
|
||||
/// <param name="data">Data array.</param>
|
||||
/// <param name="startIndex">Index at which to start copying from <paramref name="data"/>.
|
||||
/// Must be within the <paramref name="data"/> array bounds.</param>
|
||||
/// <param name="elementCount">Number of elements to copy from <paramref name="data"/>.
|
||||
/// The combination of <paramref name="startIndex"/> and <paramref name="elementCount"/>
|
||||
/// must be within the <paramref name="data"/> array bounds.</param>
|
||||
public void SetData<T>(T[] data, int startIndex, int elementCount) where T : struct
|
||||
{
|
||||
var elementSizeInBytes = ReflectionHelpers.SizeOf<T>.Get();
|
||||
SetDataInternal<T>(0, data, startIndex, elementCount, elementSizeInBytes, SetDataOptions.None);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the vertex buffer data. This is the same as calling <see cref="SetData{T}(int, T[], int, int, int)"/>
|
||||
/// with <c>offsetInBytes</c> and <c>startIndex</c> equal to <c>0</c>, <c>elementCount</c> equal to <c>data.Length</c>,
|
||||
/// and <c>vertexStride</c> equal to <c>sizeof(T)</c>.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type of elements in the data array.</typeparam>
|
||||
/// <param name="data">Data array.</param>
|
||||
public void SetData<T>(T[] data) where T : struct
|
||||
{
|
||||
var elementSizeInBytes = ReflectionHelpers.SizeOf<T>.Get();
|
||||
SetDataInternal<T>(0, data, 0, data.Length, elementSizeInBytes, SetDataOptions.None);
|
||||
}
|
||||
|
||||
protected void SetDataInternal<T>(int offsetInBytes, T[] data, int startIndex, int elementCount, int vertexStride, SetDataOptions options) where T : struct
|
||||
{
|
||||
if (data == null)
|
||||
throw new ArgumentNullException("data");
|
||||
|
||||
var elementSizeInBytes = ReflectionHelpers.SizeOf<T>.Get();
|
||||
var bufferSize = VertexCount * VertexDeclaration.VertexStride;
|
||||
|
||||
if (vertexStride == 0)
|
||||
vertexStride = elementSizeInBytes;
|
||||
|
||||
var vertexByteSize = VertexCount * VertexDeclaration.VertexStride;
|
||||
if (vertexStride > vertexByteSize)
|
||||
throw new ArgumentOutOfRangeException("vertexStride", "Vertex stride can not be larger than the vertex buffer size.");
|
||||
|
||||
if (startIndex + elementCount > data.Length || elementCount <= 0)
|
||||
throw new ArgumentOutOfRangeException("data","The array specified in the data parameter is not the correct size for the amount of data requested.");
|
||||
if (elementCount > 1 && (elementCount * vertexStride > bufferSize))
|
||||
throw new InvalidOperationException("The vertex stride is larger than the vertex buffer.");
|
||||
if (vertexStride < elementSizeInBytes)
|
||||
throw new ArgumentOutOfRangeException("The vertex stride must be greater than or equal to the size of the specified data (" + elementSizeInBytes + ").");
|
||||
|
||||
PlatformSetDataInternal<T>(offsetInBytes, data, startIndex, elementCount, vertexStride, options, bufferSize, elementSizeInBytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
+103
@@ -0,0 +1,103 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Graphics
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines how a vertex buffer is bound to the graphics device for rendering.
|
||||
/// </summary>
|
||||
public struct VertexBufferBinding
|
||||
{
|
||||
private readonly VertexBuffer _vertexBuffer;
|
||||
private readonly int _vertexOffset;
|
||||
private readonly int _instanceFrequency;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the vertex buffer.
|
||||
/// </summary>
|
||||
/// <value>The vertex buffer.</value>
|
||||
public VertexBuffer VertexBuffer
|
||||
{
|
||||
get { return _vertexBuffer; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the index of the first vertex in the vertex buffer to use.
|
||||
/// </summary>
|
||||
/// <value>The index of the first vertex in the vertex buffer to use.</value>
|
||||
public int VertexOffset
|
||||
{
|
||||
get { return _vertexOffset; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of instances to draw using the same per-instance data before advancing
|
||||
/// in the buffer by one element.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The number of instances to draw using the same per-instance data before advancing in the
|
||||
/// buffer by one element. This value must be 0 for an element that contains per-vertex
|
||||
/// data and greater than 0 for per-instance data.
|
||||
/// </value>
|
||||
public int InstanceFrequency
|
||||
{
|
||||
get { return _instanceFrequency; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates an instance of <see cref="VertexBufferBinding"/>.
|
||||
/// </summary>
|
||||
/// <param name="vertexBuffer">The vertex buffer to bind.</param>
|
||||
public VertexBufferBinding(VertexBuffer vertexBuffer)
|
||||
: this(vertexBuffer, 0, 0)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates an instance of <see cref="VertexBufferBinding"/>.
|
||||
/// </summary>
|
||||
/// <param name="vertexBuffer">The vertex buffer to bind.</param>
|
||||
/// <param name="vertexOffset">
|
||||
/// The index of the first vertex in the vertex buffer to use.
|
||||
/// </param>
|
||||
public VertexBufferBinding(VertexBuffer vertexBuffer, int vertexOffset)
|
||||
: this(vertexBuffer, vertexOffset, 0)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates an instance of VertexBufferBinding.
|
||||
/// </summary>
|
||||
/// <param name="vertexBuffer">The vertex buffer to bind.</param>
|
||||
/// <param name="vertexOffset">
|
||||
/// The index of the first vertex in the vertex buffer to use.
|
||||
/// </param>
|
||||
/// <param name="instanceFrequency">
|
||||
/// The number of instances to draw using the same per-instance data before advancing in the
|
||||
/// buffer by one element. This value must be 0 for an element that contains per-vertex data
|
||||
/// and greater than 0 for per-instance data.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="vertexBuffer"/> is <see langword="null"/>.
|
||||
/// </exception>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// <paramref name="vertexOffset"/> or <paramref name="instanceFrequency"/> is invalid.
|
||||
/// </exception>
|
||||
public VertexBufferBinding(VertexBuffer vertexBuffer, int vertexOffset, int instanceFrequency)
|
||||
{
|
||||
if (vertexBuffer == null)
|
||||
throw new ArgumentNullException("vertexBuffer");
|
||||
if (vertexOffset < 0 || vertexOffset >= vertexBuffer.VertexCount)
|
||||
throw new ArgumentOutOfRangeException("vertexOffset");
|
||||
if (instanceFrequency < 0)
|
||||
throw new ArgumentOutOfRangeException("instanceFrequency");
|
||||
|
||||
_vertexBuffer = vertexBuffer;
|
||||
_vertexOffset = vertexOffset;
|
||||
_instanceFrequency = instanceFrequency;
|
||||
}
|
||||
}
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
|
||||
|
||||
namespace Microsoft.Xna.Framework.Graphics
|
||||
{
|
||||
partial class VertexBufferBindings
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates an <see cref="ImmutableVertexInputLayout"/> that can be used as a key in the
|
||||
/// <see cref="InputLayoutCache"/>.
|
||||
/// </summary>
|
||||
/// <returns>The <see cref="ImmutableVertexInputLayout"/>.</returns>
|
||||
public ImmutableVertexInputLayout ToImmutable()
|
||||
{
|
||||
int count = Count;
|
||||
|
||||
var vertexDeclarations = new VertexDeclaration[count];
|
||||
Array.Copy(VertexDeclarations, vertexDeclarations, count);
|
||||
|
||||
var instanceFrequencies = new int[count];
|
||||
Array.Copy(InstanceFrequencies, instanceFrequencies, count);
|
||||
|
||||
return new ImmutableVertexInputLayout(vertexDeclarations, instanceFrequencies);
|
||||
}
|
||||
}
|
||||
}
|
||||
+169
@@ -0,0 +1,169 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
|
||||
namespace Microsoft.Xna.Framework.Graphics
|
||||
{
|
||||
/// <summary>
|
||||
/// Stores the vertex buffers to be bound to the input assembler stage.
|
||||
/// </summary>
|
||||
internal sealed partial class VertexBufferBindings : VertexInputLayout
|
||||
{
|
||||
private readonly VertexBuffer[] _vertexBuffers;
|
||||
private readonly int[] _vertexOffsets;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="VertexBufferBindings" /> class.
|
||||
/// </summary>
|
||||
/// <param name="maxVertexBufferSlots">The maximum number of vertex buffer slots.</param>
|
||||
public VertexBufferBindings(int maxVertexBufferSlots)
|
||||
: base(new VertexDeclaration[maxVertexBufferSlots], new int[maxVertexBufferSlots], 0)
|
||||
{
|
||||
_vertexBuffers = new VertexBuffer[maxVertexBufferSlots];
|
||||
_vertexOffsets = new int[maxVertexBufferSlots];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears the vertex buffer slots.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// <see langword="true"/> if the input layout was changed; otherwise,
|
||||
/// <see langword="false"/>.
|
||||
/// </returns>
|
||||
public bool Clear()
|
||||
{
|
||||
if (Count == 0)
|
||||
return false;
|
||||
|
||||
Array.Clear(VertexDeclarations, 0, Count);
|
||||
Array.Clear(InstanceFrequencies, 0, Count);
|
||||
Array.Clear(_vertexBuffers, 0, Count);
|
||||
Array.Clear(_vertexOffsets, 0, Count);
|
||||
Count = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Binds the specified vertex buffer to the first input slot.
|
||||
/// </summary>
|
||||
/// <param name="vertexBuffer">The vertex buffer.</param>
|
||||
/// <param name="vertexOffset">
|
||||
/// The offset (in vertices) from the beginning of the vertex buffer to the first vertex to
|
||||
/// use.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// <see langword="true"/> if the input layout was changed; otherwise,
|
||||
/// <see langword="false"/>.
|
||||
/// </returns>
|
||||
public bool Set(VertexBuffer vertexBuffer, int vertexOffset)
|
||||
{
|
||||
Debug.Assert(vertexBuffer != null);
|
||||
Debug.Assert(0 <= vertexOffset && vertexOffset < vertexBuffer.VertexCount);
|
||||
|
||||
if (Count == 1
|
||||
&& InstanceFrequencies[0] == 0
|
||||
&& _vertexBuffers[0] == vertexBuffer
|
||||
&& _vertexOffsets[0] == vertexOffset)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
VertexDeclarations[0] = vertexBuffer.VertexDeclaration;
|
||||
InstanceFrequencies[0] = 0;
|
||||
_vertexBuffers[0] = vertexBuffer;
|
||||
_vertexOffsets[0] = vertexOffset;
|
||||
if (Count > 1)
|
||||
{
|
||||
Array.Clear(VertexDeclarations, 1, Count - 1);
|
||||
Array.Clear(InstanceFrequencies, 1, Count - 1);
|
||||
Array.Clear(_vertexBuffers, 1, Count - 1);
|
||||
Array.Clear(_vertexOffsets, 1, Count - 1);
|
||||
}
|
||||
|
||||
Count = 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Binds the the specified vertex buffers to the input slots.
|
||||
/// </summary>
|
||||
/// <param name="vertexBufferBindings">The vertex buffer bindings.</param>
|
||||
/// <returns>
|
||||
/// <see langword="true"/> if the input layout was changed; otherwise,
|
||||
/// <see langword="false"/>.
|
||||
/// </returns>
|
||||
public bool Set(params VertexBufferBinding[] vertexBufferBindings)
|
||||
{
|
||||
Debug.Assert(vertexBufferBindings != null);
|
||||
Debug.Assert(vertexBufferBindings.Length > 0);
|
||||
Debug.Assert(vertexBufferBindings.Length <= _vertexBuffers.Length);
|
||||
|
||||
bool isDirty = false;
|
||||
for (int i = 0; i < vertexBufferBindings.Length; i++)
|
||||
{
|
||||
Debug.Assert(vertexBufferBindings[i].VertexBuffer != null);
|
||||
|
||||
if (InstanceFrequencies[i] == vertexBufferBindings[i].InstanceFrequency
|
||||
&& _vertexBuffers[i] == vertexBufferBindings[i].VertexBuffer
|
||||
&& _vertexOffsets[i] == vertexBufferBindings[i].VertexOffset)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
VertexDeclarations[i] = vertexBufferBindings[i].VertexBuffer.VertexDeclaration;
|
||||
InstanceFrequencies[i] = vertexBufferBindings[i].InstanceFrequency;
|
||||
_vertexBuffers[i] = vertexBufferBindings[i].VertexBuffer;
|
||||
_vertexOffsets[i] = vertexBufferBindings[i].VertexOffset;
|
||||
isDirty = true;
|
||||
}
|
||||
|
||||
if (Count > vertexBufferBindings.Length)
|
||||
{
|
||||
int startIndex = vertexBufferBindings.Length;
|
||||
int length = Count - startIndex;
|
||||
Array.Clear(VertexDeclarations, startIndex, length);
|
||||
Array.Clear(InstanceFrequencies, startIndex, length);
|
||||
Array.Clear(_vertexBuffers, startIndex, length);
|
||||
Array.Clear(_vertexOffsets, startIndex, length);
|
||||
isDirty = true;
|
||||
}
|
||||
|
||||
Count = vertexBufferBindings.Length;
|
||||
return isDirty;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets vertex buffer bound to the specified input slots.
|
||||
/// </summary>
|
||||
/// <returns>The vertex buffer binding.</returns>
|
||||
public VertexBufferBinding Get(int slot)
|
||||
{
|
||||
Debug.Assert(0 <= slot && slot < Count);
|
||||
|
||||
return new VertexBufferBinding(
|
||||
_vertexBuffers[slot],
|
||||
_vertexOffsets[slot],
|
||||
InstanceFrequencies[slot]);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets vertex buffers bound to the input slots.
|
||||
/// </summary>
|
||||
/// <returns>The vertex buffer bindings.</returns>
|
||||
public VertexBufferBinding[] Get()
|
||||
{
|
||||
var bindings = new VertexBufferBinding[Count];
|
||||
for (int i = 0; i < bindings.Length; i++)
|
||||
bindings[i] = new VertexBufferBinding(
|
||||
_vertexBuffers[i],
|
||||
_vertexOffsets[i],
|
||||
InstanceFrequencies[i]);
|
||||
|
||||
return bindings;
|
||||
}
|
||||
}
|
||||
}
|
||||
+95
@@ -0,0 +1,95 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using MonoGame.OpenGL;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Graphics
|
||||
{
|
||||
public partial class VertexDeclaration
|
||||
{
|
||||
private readonly Dictionary<int, VertexDeclarationAttributeInfo> _shaderAttributeInfo = new Dictionary<int, VertexDeclarationAttributeInfo>();
|
||||
|
||||
internal VertexDeclarationAttributeInfo GetAttributeInfo(Shader shader, int programHash)
|
||||
{
|
||||
VertexDeclarationAttributeInfo attrInfo;
|
||||
if (_shaderAttributeInfo.TryGetValue(programHash, out attrInfo))
|
||||
return attrInfo;
|
||||
|
||||
// Get the vertex attribute info and cache it
|
||||
attrInfo = new VertexDeclarationAttributeInfo(GraphicsDevice.MaxVertexAttributes);
|
||||
|
||||
foreach (var ve in InternalVertexElements)
|
||||
{
|
||||
var attributeLocation = shader.GetAttribLocation(ve.VertexElementUsage, ve.UsageIndex);
|
||||
// XNA appears to ignore usages it can't find a match for, so we will do the same
|
||||
if (attributeLocation < 0)
|
||||
continue;
|
||||
|
||||
attrInfo.Elements.Add(new VertexDeclarationAttributeInfo.Element
|
||||
{
|
||||
Offset = ve.Offset,
|
||||
AttributeLocation = attributeLocation,
|
||||
NumberOfElements = ve.VertexElementFormat.OpenGLNumberOfElements(),
|
||||
VertexAttribPointerType = ve.VertexElementFormat.OpenGLVertexAttribPointerType(),
|
||||
Normalized = ve.OpenGLVertexAttribNormalized(),
|
||||
});
|
||||
attrInfo.EnabledAttributes[attributeLocation] = true;
|
||||
}
|
||||
|
||||
_shaderAttributeInfo.Add(programHash, attrInfo);
|
||||
return attrInfo;
|
||||
}
|
||||
|
||||
|
||||
internal void Apply(Shader shader, IntPtr offset, int programHash)
|
||||
{
|
||||
var attrInfo = GetAttributeInfo(shader, programHash);
|
||||
|
||||
// Apply the vertex attribute info
|
||||
foreach (var element in attrInfo.Elements)
|
||||
{
|
||||
GL.VertexAttribPointer(element.AttributeLocation,
|
||||
element.NumberOfElements,
|
||||
element.VertexAttribPointerType,
|
||||
element.Normalized,
|
||||
VertexStride,
|
||||
(IntPtr)(offset.ToInt64() + element.Offset));
|
||||
#if !(GLES || MONOMAC)
|
||||
if (GraphicsDevice.GraphicsCapabilities.SupportsInstancing)
|
||||
GL.VertexAttribDivisor(element.AttributeLocation, 0);
|
||||
#endif
|
||||
GraphicsExtensions.CheckGLError();
|
||||
}
|
||||
GraphicsDevice.SetVertexAttributeArray(attrInfo.EnabledAttributes);
|
||||
GraphicsDevice._attribsDirty = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Vertex attribute information for a particular shader/vertex declaration combination.
|
||||
/// </summary>
|
||||
internal class VertexDeclarationAttributeInfo
|
||||
{
|
||||
internal bool[] EnabledAttributes;
|
||||
|
||||
internal class Element
|
||||
{
|
||||
public int Offset;
|
||||
public int AttributeLocation;
|
||||
public int NumberOfElements;
|
||||
public VertexAttribPointerType VertexAttribPointerType;
|
||||
public bool Normalized;
|
||||
}
|
||||
|
||||
internal List<Element> Elements;
|
||||
|
||||
internal VertexDeclarationAttributeInfo(int maxVertexAttributes)
|
||||
{
|
||||
EnabledAttributes = new bool[maxVertexAttributes];
|
||||
Elements = new List<Element>();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Graphics
|
||||
{
|
||||
public partial class VertexDeclaration
|
||||
{
|
||||
internal void Apply(Shader shader, IntPtr offset)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
+316
@@ -0,0 +1,316 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using MonoGame.Utilities;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Graphics
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines per-vertex data of a vertex buffer.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <see cref="VertexDeclaration"/> implements <see cref="IEquatable{T}"/> and can be used as
|
||||
/// a key in a dictionary. Two vertex declarations are considered equal if the vertices are
|
||||
/// structurally equivalent, i.e. the vertex elements and the vertex stride are identical. (The
|
||||
/// properties <see cref="GraphicsResource.Name"/> and <see cref="GraphicsResource.Tag"/> are
|
||||
/// ignored in <see cref="GetHashCode"/> and <see cref="Equals(VertexDeclaration)"/>!)
|
||||
/// </remarks>
|
||||
public partial class VertexDeclaration : GraphicsResource, IEquatable<VertexDeclaration>
|
||||
{
|
||||
// Note for future refactoring:
|
||||
// For XNA-compatibility VertexDeclaration is derived from GraphicsResource, which means it
|
||||
// has GraphicsDevice, Name, Tag and implements IDisposable. This is unnecessary in
|
||||
// MonoGame. VertexDeclaration.GraphicsDevice is never set.
|
||||
// --> VertexDeclaration should be a lightweight immutable type. No base class, no IDisposable.
|
||||
// (Use the internal type Data. Do not expose a constructor. Use a factory method to
|
||||
// cache the vertex declarations.)
|
||||
|
||||
#region ----- Data shared between structurally identical vertex declarations -----
|
||||
|
||||
private sealed class Data : IEquatable<Data>
|
||||
{
|
||||
private readonly int _hashCode;
|
||||
public readonly int VertexStride;
|
||||
public VertexElement[] Elements;
|
||||
|
||||
public Data(int vertexStride, VertexElement[] elements)
|
||||
{
|
||||
VertexStride = vertexStride;
|
||||
Elements = elements;
|
||||
|
||||
// Pre-calculate hash code for fast comparisons and lookup in dictionaries.
|
||||
unchecked
|
||||
{
|
||||
_hashCode = elements[0].GetHashCode();
|
||||
for (int i = 1; i < elements.Length; i++)
|
||||
_hashCode = (_hashCode * 397) ^ elements[i].GetHashCode();
|
||||
|
||||
_hashCode = (_hashCode * 397) ^ elements.Length;
|
||||
_hashCode = (_hashCode * 397) ^ vertexStride;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return Equals(obj as Data);
|
||||
}
|
||||
|
||||
public bool Equals(Data other)
|
||||
{
|
||||
if (ReferenceEquals(null, other))
|
||||
return false;
|
||||
if (ReferenceEquals(this, other))
|
||||
return true;
|
||||
|
||||
if (_hashCode != other._hashCode
|
||||
|| VertexStride != other.VertexStride
|
||||
|| Elements.Length != other.Elements.Length)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < Elements.Length; i++)
|
||||
if (!Elements[i].Equals(other.Elements[i]))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return _hashCode;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
#region ----- VertexDeclaration Cache -----
|
||||
|
||||
private static readonly Dictionary<Data, VertexDeclaration> _vertexDeclarationCache;
|
||||
|
||||
static VertexDeclaration()
|
||||
{
|
||||
_vertexDeclarationCache = new Dictionary<Data, VertexDeclaration>();
|
||||
}
|
||||
|
||||
internal static VertexDeclaration GetOrCreate(int vertexStride, VertexElement[] elements)
|
||||
{
|
||||
lock (_vertexDeclarationCache)
|
||||
{
|
||||
var data = new Data(vertexStride, elements);
|
||||
VertexDeclaration vertexDeclaration;
|
||||
if (!_vertexDeclarationCache.TryGetValue(data, out vertexDeclaration))
|
||||
{
|
||||
// Data.Elements have already been set in the Data ctor. However, entries
|
||||
// in the vertex declaration cache must be immutable. Therefore, we create a
|
||||
// copy of the array, which the user cannot access.
|
||||
data.Elements = (VertexElement[])elements.Clone();
|
||||
|
||||
vertexDeclaration = new VertexDeclaration(data);
|
||||
_vertexDeclarationCache[data] = vertexDeclaration;
|
||||
}
|
||||
|
||||
return vertexDeclaration;
|
||||
}
|
||||
}
|
||||
|
||||
private VertexDeclaration(Data data)
|
||||
{
|
||||
_data = data;
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
private readonly Data _data;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the internal vertex elements array.
|
||||
/// </summary>
|
||||
/// <value>The internal vertex elements array.</value>
|
||||
internal VertexElement[] InternalVertexElements
|
||||
{
|
||||
get { return _data.Elements; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="VertexDeclaration"/> class.
|
||||
/// </summary>
|
||||
/// <param name="elements">The vertex elements.</param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="elements"/> is <see langword="null"/> or empty.
|
||||
/// </exception>
|
||||
public VertexDeclaration(params VertexElement[] elements)
|
||||
: this(GetVertexStride(elements), elements)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="VertexDeclaration"/> class.
|
||||
/// </summary>
|
||||
/// <param name="vertexStride">The size of a vertex (including padding) in bytes.</param>
|
||||
/// <param name="elements">The vertex elements.</param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="elements"/> is <see langword="null"/> or empty.
|
||||
/// </exception>
|
||||
public VertexDeclaration(int vertexStride, params VertexElement[] elements)
|
||||
{
|
||||
if ((elements == null) || (elements.Length == 0))
|
||||
throw new ArgumentNullException("elements", "Elements cannot be empty");
|
||||
|
||||
lock (_vertexDeclarationCache)
|
||||
{
|
||||
var data = new Data(vertexStride, elements);
|
||||
VertexDeclaration vertexDeclaration;
|
||||
if (_vertexDeclarationCache.TryGetValue(data, out vertexDeclaration))
|
||||
{
|
||||
// Reuse existing data.
|
||||
_data = vertexDeclaration._data;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Cache new vertex declaration.
|
||||
data.Elements = (VertexElement[])elements.Clone();
|
||||
_data = data;
|
||||
_vertexDeclarationCache[data] = this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static int GetVertexStride(VertexElement[] elements)
|
||||
{
|
||||
int max = 0;
|
||||
for (var i = 0; i < elements.Length; i++)
|
||||
{
|
||||
var start = elements[i].Offset + elements[i].VertexElementFormat.GetSize();
|
||||
if (max < start)
|
||||
max = start;
|
||||
}
|
||||
|
||||
return max;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the VertexDeclaration for Type.
|
||||
/// </summary>
|
||||
/// <param name="vertexType">A value type which implements the IVertexType interface.</param>
|
||||
/// <returns>The VertexDeclaration.</returns>
|
||||
/// <remarks>
|
||||
/// Prefer to use VertexDeclarationCache when the declaration lookup
|
||||
/// can be performed with a templated type.
|
||||
/// </remarks>
|
||||
internal static VertexDeclaration FromType(Type vertexType)
|
||||
{
|
||||
if (vertexType == null)
|
||||
throw new ArgumentNullException("vertexType", "Cannot be null");
|
||||
|
||||
if (!ReflectionHelpers.IsValueType(vertexType))
|
||||
{
|
||||
throw new ArgumentException("Must be value type", "vertexType");
|
||||
}
|
||||
|
||||
var type = Activator.CreateInstance(vertexType) as IVertexType;
|
||||
if (type == null)
|
||||
{
|
||||
throw new ArgumentException("vertexData does not inherit IVertexType");
|
||||
}
|
||||
|
||||
var vertexDeclaration = type.VertexDeclaration;
|
||||
if (vertexDeclaration == null)
|
||||
{
|
||||
throw new Exception("VertexDeclaration cannot be null");
|
||||
}
|
||||
|
||||
return vertexDeclaration;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a copy of the vertex elements.
|
||||
/// </summary>
|
||||
/// <returns>A copy of the vertex elements.</returns>
|
||||
public VertexElement[] GetVertexElements()
|
||||
{
|
||||
return (VertexElement[])_data.Elements.Clone();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the size of a vertex (including padding) in bytes.
|
||||
/// </summary>
|
||||
/// <value>The size of a vertex (including padding) in bytes.</value>
|
||||
public int VertexStride
|
||||
{
|
||||
get { return _data.VertexStride; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified <see cref="object"/> is equal to this instance.
|
||||
/// </summary>
|
||||
/// <param name="obj">The object to compare with the current object.</param>
|
||||
/// <returns>
|
||||
/// <see langword="true"/> if the specified <see cref="object"/> is equal to this instance;
|
||||
/// otherwise, <see langword="false"/>.
|
||||
/// </returns>
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return Equals(obj as VertexDeclaration);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified <see cref="VertexDeclaration"/> is equal to this
|
||||
/// instance.
|
||||
/// </summary>
|
||||
/// <param name="other">The object to compare with the current object.</param>
|
||||
/// <returns>
|
||||
/// <see langword="true"/> if the specified <see cref="VertexDeclaration"/> is equal to this
|
||||
/// instance; otherwise, <see langword="false"/>.
|
||||
/// </returns>
|
||||
public bool Equals(VertexDeclaration other)
|
||||
{
|
||||
return other != null && ReferenceEquals(_data, other._data);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a hash code for this instance.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A hash code for this instance, suitable for use in hashing algorithms and data
|
||||
/// structures like a hash table.
|
||||
/// </returns>
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return _data.GetHashCode();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compares two <see cref="VertexElement"/> instances to determine whether they are the
|
||||
/// same.
|
||||
/// </summary>
|
||||
/// <param name="left">The first instance.</param>
|
||||
/// <param name="right">The second instance.</param>
|
||||
/// <returns>
|
||||
/// <see langword="true"/> if the <paramref name="left"/> and <paramref name="right"/> are
|
||||
/// the same; otherwise, <see langword="false"/>.
|
||||
/// </returns>
|
||||
public static bool operator ==(VertexDeclaration left, VertexDeclaration right)
|
||||
{
|
||||
return Equals(left, right);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compares two <see cref="VertexElement"/> instances to determine whether they are
|
||||
/// different.
|
||||
/// </summary>
|
||||
/// <param name="left">The first instance.</param>
|
||||
/// <param name="right">The second instance.</param>
|
||||
/// <returns>
|
||||
/// <see langword="true"/> if the <paramref name="left"/> and <paramref name="right"/> are
|
||||
/// the different; otherwise, <see langword="false"/>.
|
||||
/// </returns>
|
||||
public static bool operator !=(VertexDeclaration left, VertexDeclaration right)
|
||||
{
|
||||
return !Equals(left, right);
|
||||
}
|
||||
}
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
namespace Microsoft.Xna.Framework.Graphics
|
||||
{
|
||||
/// <summary>
|
||||
/// Helper class which ensures we only lookup a vertex
|
||||
/// declaration for a particular type once.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">A vertex structure which implements IVertexType.</typeparam>
|
||||
internal class VertexDeclarationCache<T>
|
||||
where T : struct, IVertexType
|
||||
{
|
||||
static private VertexDeclaration _cached;
|
||||
|
||||
static public VertexDeclaration VertexDeclaration
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_cached == null)
|
||||
_cached = VertexDeclaration.FromType(typeof(T));
|
||||
|
||||
return _cached;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+117
@@ -0,0 +1,117 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Graphics
|
||||
{
|
||||
partial struct VertexElement
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the DirectX <see cref="SharpDX.Direct3D11.InputElement"/>.
|
||||
/// </summary>
|
||||
/// <param name="slot">The input resource slot.</param>
|
||||
/// <param name="instanceFrequency">
|
||||
/// The number of instances to draw using the same per-instance data before advancing in the
|
||||
/// buffer by one element. This value must be 0 for an element that contains per-vertex
|
||||
/// data.
|
||||
/// </param>
|
||||
/// <returns><see cref="SharpDX.Direct3D11.InputElement"/>.</returns>
|
||||
/// <exception cref="NotSupportedException">
|
||||
/// Unknown vertex element format or usage!
|
||||
/// </exception>
|
||||
internal SharpDX.Direct3D11.InputElement GetInputElement(int slot, int instanceFrequency)
|
||||
{
|
||||
var element = new SharpDX.Direct3D11.InputElement();
|
||||
|
||||
switch (_usage)
|
||||
{
|
||||
case VertexElementUsage.Position:
|
||||
element.SemanticName = "POSITION";
|
||||
break;
|
||||
case VertexElementUsage.Color:
|
||||
element.SemanticName = "COLOR";
|
||||
break;
|
||||
case VertexElementUsage.Normal:
|
||||
element.SemanticName = "NORMAL";
|
||||
break;
|
||||
case VertexElementUsage.TextureCoordinate:
|
||||
element.SemanticName = "TEXCOORD";
|
||||
break;
|
||||
case VertexElementUsage.BlendIndices:
|
||||
element.SemanticName = "BLENDINDICES";
|
||||
break;
|
||||
case VertexElementUsage.BlendWeight:
|
||||
element.SemanticName = "BLENDWEIGHT";
|
||||
break;
|
||||
case VertexElementUsage.Binormal:
|
||||
element.SemanticName = "BINORMAL";
|
||||
break;
|
||||
case VertexElementUsage.Tangent:
|
||||
element.SemanticName = "TANGENT";
|
||||
break;
|
||||
case VertexElementUsage.PointSize:
|
||||
element.SemanticName = "PSIZE";
|
||||
break;
|
||||
default:
|
||||
throw new NotSupportedException("Unknown vertex element usage!");
|
||||
}
|
||||
|
||||
element.SemanticIndex = _usageIndex;
|
||||
|
||||
switch (_format)
|
||||
{
|
||||
case VertexElementFormat.Single:
|
||||
element.Format = SharpDX.DXGI.Format.R32_Float;
|
||||
break;
|
||||
case VertexElementFormat.Vector2:
|
||||
element.Format = SharpDX.DXGI.Format.R32G32_Float;
|
||||
break;
|
||||
case VertexElementFormat.Vector3:
|
||||
element.Format = SharpDX.DXGI.Format.R32G32B32_Float;
|
||||
break;
|
||||
case VertexElementFormat.Vector4:
|
||||
element.Format = SharpDX.DXGI.Format.R32G32B32A32_Float;
|
||||
break;
|
||||
case VertexElementFormat.Color:
|
||||
element.Format = SharpDX.DXGI.Format.R8G8B8A8_UNorm;
|
||||
break;
|
||||
case VertexElementFormat.Byte4:
|
||||
element.Format = SharpDX.DXGI.Format.R8G8B8A8_UInt;
|
||||
break;
|
||||
case VertexElementFormat.Short2:
|
||||
element.Format = SharpDX.DXGI.Format.R16G16_SInt;
|
||||
break;
|
||||
case VertexElementFormat.Short4:
|
||||
element.Format = SharpDX.DXGI.Format.R16G16B16A16_SInt;
|
||||
break;
|
||||
case VertexElementFormat.NormalizedShort2:
|
||||
element.Format = SharpDX.DXGI.Format.R16G16_SNorm;
|
||||
break;
|
||||
case VertexElementFormat.NormalizedShort4:
|
||||
element.Format = SharpDX.DXGI.Format.R16G16B16A16_SNorm;
|
||||
break;
|
||||
case VertexElementFormat.HalfVector2:
|
||||
element.Format = SharpDX.DXGI.Format.R16G16_Float;
|
||||
break;
|
||||
case VertexElementFormat.HalfVector4:
|
||||
element.Format = SharpDX.DXGI.Format.R16G16B16A16_Float;
|
||||
break;
|
||||
default:
|
||||
throw new NotSupportedException("Unknown vertex element format!");
|
||||
}
|
||||
|
||||
element.Slot = slot;
|
||||
element.AlignedByteOffset = _offset;
|
||||
|
||||
// Note that instancing is only supported in feature level 9.3 and above.
|
||||
element.Classification = (instanceFrequency == 0)
|
||||
? SharpDX.Direct3D11.InputClassification.PerVertexData
|
||||
: SharpDX.Direct3D11.InputClassification.PerInstanceData;
|
||||
element.InstanceDataStepRate = instanceFrequency;
|
||||
|
||||
return element;
|
||||
}
|
||||
}
|
||||
}
|
||||
+179
@@ -0,0 +1,179 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Graphics
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines a single element in a vertex.
|
||||
/// </summary>
|
||||
public partial struct VertexElement : IEquatable<VertexElement>
|
||||
{
|
||||
private int _offset;
|
||||
private VertexElementFormat _format;
|
||||
private VertexElementUsage _usage;
|
||||
private int _usageIndex;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the offset in bytes from the beginning of the stream to the vertex element.
|
||||
/// </summary>
|
||||
/// <value>The offset in bytes.</value>
|
||||
public int Offset
|
||||
{
|
||||
get { return _offset; }
|
||||
set { _offset = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the data format.
|
||||
/// </summary>
|
||||
/// <value>The data format.</value>
|
||||
public VertexElementFormat VertexElementFormat
|
||||
{
|
||||
get { return _format; }
|
||||
set { _format = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the HLSL semantic of the element in the vertex shader input.
|
||||
/// </summary>
|
||||
/// <value>The HLSL semantic of the element in the vertex shader input.</value>
|
||||
public VertexElementUsage VertexElementUsage
|
||||
{
|
||||
get { return _usage; }
|
||||
set { _usage = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the semantic index.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The semantic index, which is required if the semantic is used for more than one vertex
|
||||
/// element.
|
||||
/// </value>
|
||||
/// <remarks>
|
||||
/// Usage indices in a vertex declaration usually start with 0. When multiple vertex buffers
|
||||
/// are bound to the input assembler stage (see <see cref="GraphicsDevice.SetVertexBuffers"/>),
|
||||
/// MonoGame internally adjusts the usage indices based on the order in which the vertex
|
||||
/// buffers are bound.
|
||||
/// </remarks>
|
||||
public int UsageIndex
|
||||
{
|
||||
get { return _usageIndex; }
|
||||
set { _usageIndex = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="VertexElement"/> struct.
|
||||
/// </summary>
|
||||
/// <param name="offset">The offset in bytes from the beginning of the stream to the vertex element.</param>
|
||||
/// <param name="elementFormat">The element format.</param>
|
||||
/// <param name="elementUsage">The HLSL semantic of the element in the vertex shader input-signature.</param>
|
||||
/// <param name="usageIndex">The semantic index, which is required if the semantic is used for more than one vertex element.</param>
|
||||
public VertexElement(int offset, VertexElementFormat elementFormat, VertexElementUsage elementUsage, int usageIndex)
|
||||
{
|
||||
_offset = offset;
|
||||
_format = elementFormat;
|
||||
_usageIndex = usageIndex;
|
||||
_usage = elementUsage;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a hash code for this instance.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A hash code for this instance, suitable for use in hashing algorithms and data
|
||||
/// structures like a hash table.
|
||||
/// </returns>
|
||||
public override int GetHashCode()
|
||||
{
|
||||
// ReSharper disable NonReadonlyMemberInGetHashCode
|
||||
|
||||
// Optimized hash:
|
||||
// - DirectX 11 has max 32 registers. A register is max 16 byte. _offset is in the range
|
||||
// 0 to 512 (exclusive). --> _offset needs 9 bit.
|
||||
// - VertexElementFormat has 12 values. --> _format needs 4 bit.
|
||||
// - VertexElementUsage has 13 values. --> _usage needs 4 bit.
|
||||
// - DirectX 11 has max 32 registers. --> _usageIndex needs 6 bit.
|
||||
// (Note: If these assumptions are correct we get a unique hash code. If these
|
||||
// assumptions are not correct, we still get a useful hash code because we use XOR.)
|
||||
int hashCode = _offset;
|
||||
hashCode ^= (int)_format << 9;
|
||||
hashCode ^= (int)_usage << (9 + 4);
|
||||
hashCode ^= _usageIndex << (9 + 4 + 4);
|
||||
return hashCode;
|
||||
// ReSharper restore NonReadonlyMemberInGetHashCode
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a <see cref="string" /> that represents this instance.
|
||||
/// </summary>
|
||||
/// <returns>A <see cref="string" /> that represents this instance.</returns>
|
||||
public override string ToString()
|
||||
{
|
||||
return "{Offset:" + _offset + " Format:" + _format + " Usage:" + _usage + " UsageIndex: " + _usageIndex + "}";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified <see cref="object"/> is equal to this instance.
|
||||
/// </summary>
|
||||
/// <param name="obj">The object to compare with the current object.</param>
|
||||
/// <returns>
|
||||
/// <see langword="true"/> if the specified <see cref="object"/> is equal to this instance;
|
||||
/// otherwise, <see langword="false"/>.
|
||||
/// </returns>
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return obj is VertexElement && Equals((VertexElement)obj);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified <see cref="VertexElement"/> is equal to this
|
||||
/// instance.
|
||||
/// </summary>
|
||||
/// <param name="other">The object to compare with the current object.</param>
|
||||
/// <returns>
|
||||
/// <see langword="true"/> if the specified <see cref="VertexElement"/> is equal to this
|
||||
/// instance; otherwise, <see langword="false"/>.
|
||||
/// </returns>
|
||||
public bool Equals(VertexElement other)
|
||||
{
|
||||
return _offset == other._offset
|
||||
&& _format == other._format
|
||||
&& _usage == other._usage
|
||||
&& _usageIndex == other._usageIndex;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compares two <see cref="VertexElement"/> instances to determine whether they are the
|
||||
/// same.
|
||||
/// </summary>
|
||||
/// <param name="left">The first instance.</param>
|
||||
/// <param name="right">The second instance.</param>
|
||||
/// <returns>
|
||||
/// <see langword="true"/> if the <paramref name="left"/> and <paramref name="right"/> are
|
||||
/// the same; otherwise, <see langword="false"/>.
|
||||
/// </returns>
|
||||
public static bool operator ==(VertexElement left, VertexElement right)
|
||||
{
|
||||
return left.Equals(right);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compares two <see cref="VertexElement"/> instances to determine whether they are
|
||||
/// different.
|
||||
/// </summary>
|
||||
/// <param name="left">The first instance.</param>
|
||||
/// <param name="right">The second instance.</param>
|
||||
/// <returns>
|
||||
/// <see langword="true"/> if the <paramref name="left"/> and <paramref name="right"/> are
|
||||
/// the different; otherwise, <see langword="false"/>.
|
||||
/// </returns>
|
||||
public static bool operator !=(VertexElement left, VertexElement right)
|
||||
{
|
||||
return !left.Equals(right);
|
||||
}
|
||||
}
|
||||
}
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
namespace Microsoft.Xna.Framework.Graphics
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines vertex element formats.
|
||||
/// </summary>
|
||||
public enum VertexElementFormat
|
||||
{
|
||||
/// <summary>
|
||||
/// Single 32-bit floating point number.
|
||||
/// </summary>
|
||||
Single,
|
||||
/// <summary>
|
||||
/// Two component 32-bit floating point number.
|
||||
/// </summary>
|
||||
Vector2,
|
||||
/// <summary>
|
||||
/// Three component 32-bit floating point number.
|
||||
/// </summary>
|
||||
Vector3,
|
||||
/// <summary>
|
||||
/// Four component 32-bit floating point number.
|
||||
/// </summary>
|
||||
Vector4,
|
||||
/// <summary>
|
||||
/// Four component, packed unsigned byte, mapped to 0 to 1 range.
|
||||
/// </summary>
|
||||
Color,
|
||||
/// <summary>
|
||||
/// Four component unsigned byte.
|
||||
/// </summary>
|
||||
Byte4,
|
||||
/// <summary>
|
||||
/// Two component signed 16-bit integer.
|
||||
/// </summary>
|
||||
Short2,
|
||||
/// <summary>
|
||||
/// Four component signed 16-bit integer.
|
||||
/// </summary>
|
||||
Short4,
|
||||
/// <summary>
|
||||
/// Normalized, two component signed 16-bit integer.
|
||||
/// </summary>
|
||||
NormalizedShort2,
|
||||
/// <summary>
|
||||
/// Normalized, four component signed 16-bit integer.
|
||||
/// </summary>
|
||||
NormalizedShort4,
|
||||
/// <summary>
|
||||
/// Two component 16-bit floating point number.
|
||||
/// </summary>
|
||||
HalfVector2,
|
||||
/// <summary>
|
||||
/// Four component 16-bit floating point number.
|
||||
/// </summary>
|
||||
HalfVector4
|
||||
}
|
||||
}
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
namespace Microsoft.Xna.Framework.Graphics
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines usage for vertex elements.
|
||||
/// </summary>
|
||||
public enum VertexElementUsage
|
||||
{
|
||||
/// <summary>
|
||||
/// Position data.
|
||||
/// </summary>
|
||||
Position,
|
||||
/// <summary>
|
||||
/// Color data.
|
||||
/// </summary>
|
||||
Color,
|
||||
/// <summary>
|
||||
/// Texture coordinate data or can be used for user-defined data.
|
||||
/// </summary>
|
||||
TextureCoordinate,
|
||||
/// <summary>
|
||||
/// Normal data.
|
||||
/// </summary>
|
||||
Normal,
|
||||
/// <summary>
|
||||
/// Binormal data.
|
||||
/// </summary>
|
||||
Binormal,
|
||||
/// <summary>
|
||||
/// Tangent data.
|
||||
/// </summary>
|
||||
Tangent,
|
||||
/// <summary>
|
||||
/// Blending indices data.
|
||||
/// </summary>
|
||||
BlendIndices,
|
||||
/// <summary>
|
||||
/// Blending weight data.
|
||||
/// </summary>
|
||||
BlendWeight,
|
||||
/// <summary>
|
||||
/// Depth data.
|
||||
/// </summary>
|
||||
Depth,
|
||||
/// <summary>
|
||||
/// Fog data.
|
||||
/// </summary>
|
||||
Fog,
|
||||
/// <summary>
|
||||
/// Point size data. Usable for drawing point sprites.
|
||||
/// </summary>
|
||||
PointSize,
|
||||
/// <summary>
|
||||
/// Sampler data for specifies the displacement value to look up.
|
||||
/// </summary>
|
||||
Sample,
|
||||
/// <summary>
|
||||
/// Single, positive float value, specifies a tessellation factor used in the tessellation unit to control the rate of tessellation.
|
||||
/// </summary>
|
||||
TessellateFactor
|
||||
}
|
||||
}
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using SharpDX.Direct3D11;
|
||||
|
||||
|
||||
namespace Microsoft.Xna.Framework.Graphics
|
||||
{
|
||||
partial class VertexInputLayout
|
||||
{
|
||||
public InputElement[] GetInputElements()
|
||||
{
|
||||
var list = new List<InputElement>();
|
||||
for (int i = 0; i < Count; i++)
|
||||
{
|
||||
foreach (var vertexElement in VertexDeclarations[i].InternalVertexElements)
|
||||
{
|
||||
var inputElement = vertexElement.GetInputElement(i, InstanceFrequencies[i]);
|
||||
list.Add(inputElement);
|
||||
}
|
||||
}
|
||||
|
||||
var inputElements = list.ToArray();
|
||||
|
||||
// Fix semantics indices. (If there are more vertex declarations with, for example,
|
||||
// POSITION0, the indices are changed to POSITION1/2/3/...)
|
||||
for (int i = 1; i < inputElements.Length; i++)
|
||||
{
|
||||
string semanticName = inputElements[i].SemanticName;
|
||||
int semanticIndex = inputElements[i].SemanticIndex;
|
||||
for (int j = 0; j < i; j++)
|
||||
{
|
||||
if (inputElements[j].SemanticName == semanticName && inputElements[j].SemanticIndex == semanticIndex)
|
||||
{
|
||||
// Semantic index already used.
|
||||
semanticIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
inputElements[i].SemanticIndex = semanticIndex;
|
||||
}
|
||||
|
||||
return inputElements;
|
||||
}
|
||||
}
|
||||
}
|
||||
+165
@@ -0,0 +1,165 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
|
||||
namespace Microsoft.Xna.Framework.Graphics
|
||||
{
|
||||
/// <summary>
|
||||
/// Stores the vertex layout (input elements) for the input assembler stage.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// In the DirectX version the input layouts are cached in a dictionary. The
|
||||
/// <see cref="VertexInputLayout"/> is used as the key in the dictionary and therefore needs to
|
||||
/// implement <see cref="IEquatable{T}"/>. Two <see cref="VertexInputLayout"/> instance are
|
||||
/// considered equal if the vertex layouts are structurally identical.
|
||||
/// </remarks>
|
||||
internal abstract partial class VertexInputLayout : IEquatable<VertexInputLayout>
|
||||
{
|
||||
protected VertexDeclaration[] VertexDeclarations { get; private set; }
|
||||
protected int[] InstanceFrequencies { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the number of used input slots.
|
||||
/// </summary>
|
||||
/// <value>The number of used input slots.</value>
|
||||
public int Count { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="VertexInputLayout"/> class.
|
||||
/// </summary>
|
||||
/// <param name="maxVertexBufferSlots">The maximum number of vertex buffer slots.</param>
|
||||
protected VertexInputLayout(int maxVertexBufferSlots)
|
||||
: this(new VertexDeclaration[maxVertexBufferSlots], new int[maxVertexBufferSlots], 0)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="VertexInputLayout"/> class.
|
||||
/// </summary>
|
||||
/// <param name="vertexDeclarations">The array for storing vertex declarations.</param>
|
||||
/// <param name="instanceFrequencies">The array for storing instance frequencies.</param>
|
||||
/// <param name="count">The number of used slots.</param>
|
||||
protected VertexInputLayout(VertexDeclaration[] vertexDeclarations, int[] instanceFrequencies, int count)
|
||||
{
|
||||
Debug.Assert(vertexDeclarations != null);
|
||||
Debug.Assert(instanceFrequencies != null);
|
||||
Debug.Assert(count >= 0);
|
||||
Debug.Assert(vertexDeclarations.Length >= count);
|
||||
Debug.Assert(vertexDeclarations.Length == instanceFrequencies.Length);
|
||||
|
||||
Count = count;
|
||||
VertexDeclarations = vertexDeclarations;
|
||||
InstanceFrequencies = instanceFrequencies;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified <see cref="object"/> is equal to this instance.
|
||||
/// </summary>
|
||||
/// <param name="obj">The object to compare with the current object.</param>
|
||||
/// <returns>
|
||||
/// <see langword="true"/> if the specified <see cref="object"/> is equal to this instance;
|
||||
/// otherwise, <see langword="false"/>.
|
||||
/// </returns>
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return Equals(obj as VertexInputLayout);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified <see cref="VertexInputLayout"/> is equal to this
|
||||
/// instance.
|
||||
/// </summary>
|
||||
/// <param name="other">The object to compare with the current object.</param>
|
||||
/// <returns>
|
||||
/// <see langword="true"/> if the specified <see cref="VertexInputLayout"/> is equal to this
|
||||
/// instance; otherwise, <see langword="false"/>.
|
||||
/// </returns>
|
||||
public bool Equals(VertexInputLayout other)
|
||||
{
|
||||
if (ReferenceEquals(null, other))
|
||||
return false;
|
||||
if (ReferenceEquals(this, other))
|
||||
return true;
|
||||
|
||||
if (Count != other.Count)
|
||||
return false;
|
||||
|
||||
for (int i = 0; i < Count; i++)
|
||||
{
|
||||
Debug.Assert(VertexDeclarations[i] != null);
|
||||
if (!VertexDeclarations[i].Equals(other.VertexDeclarations[i]))
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < Count; i++)
|
||||
{
|
||||
if (!InstanceFrequencies[i].Equals(other.InstanceFrequencies[i]))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a hash code for this instance.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A hash code for this instance, suitable for use in hashing algorithms and data
|
||||
/// structures like a hash table.
|
||||
/// </returns>
|
||||
public override int GetHashCode()
|
||||
{
|
||||
// ReSharper disable NonReadonlyMemberInGetHashCode
|
||||
unchecked
|
||||
{
|
||||
int hashCode = 0;
|
||||
if (Count > 0)
|
||||
{
|
||||
hashCode = VertexDeclarations[0].GetHashCode();
|
||||
hashCode = (hashCode * 397) ^ InstanceFrequencies[0];
|
||||
for (int i = 1; i < Count; i++)
|
||||
{
|
||||
hashCode = (hashCode * 397) ^ VertexDeclarations[i].GetHashCode();
|
||||
hashCode = (hashCode * 397) ^ InstanceFrequencies[i];
|
||||
}
|
||||
}
|
||||
return hashCode;
|
||||
}
|
||||
// ReSharper restore NonReadonlyMemberInGetHashCode
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compares two <see cref="VertexInputLayout"/> instances to determine whether they are the
|
||||
/// same.
|
||||
/// </summary>
|
||||
/// <param name="left">The first instance.</param>
|
||||
/// <param name="right">The second instance.</param>
|
||||
/// <returns>
|
||||
/// <see langword="true"/> if the <paramref name="left"/> and <paramref name="right"/> are
|
||||
/// the same; otherwise, <see langword="false"/>.
|
||||
/// </returns>
|
||||
public static bool operator ==(VertexInputLayout left, VertexInputLayout right)
|
||||
{
|
||||
return Equals(left, right);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compares two <see cref="VertexInputLayout"/> instances to determine whether they are
|
||||
/// different.
|
||||
/// </summary>
|
||||
/// <param name="left">The first instance.</param>
|
||||
/// <param name="right">The second instance.</param>
|
||||
/// <returns>
|
||||
/// <see langword="true"/> if the <paramref name="left"/> and <paramref name="right"/> are
|
||||
/// the different; otherwise, <see langword="false"/>.
|
||||
/// </returns>
|
||||
public static bool operator !=(VertexInputLayout left, VertexInputLayout right)
|
||||
{
|
||||
return !Equals(left, right);
|
||||
}
|
||||
}
|
||||
}
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System.Runtime.Serialization;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Graphics
|
||||
{
|
||||
[DataContract]
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct VertexPosition : IVertexType
|
||||
{
|
||||
[DataMember]
|
||||
public Vector3 Position;
|
||||
|
||||
public static readonly VertexDeclaration VertexDeclaration;
|
||||
|
||||
public VertexPosition(Vector3 position)
|
||||
{
|
||||
Position = position;
|
||||
}
|
||||
|
||||
VertexDeclaration IVertexType.VertexDeclaration
|
||||
{
|
||||
get { return VertexDeclaration; }
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return Position.GetHashCode();
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return "{{Position:" + Position + "}}";
|
||||
}
|
||||
|
||||
public static bool operator == (VertexPosition left, VertexPosition right)
|
||||
{
|
||||
return left.Position == right.Position;
|
||||
}
|
||||
|
||||
public static bool operator != (VertexPosition left, VertexPosition right)
|
||||
{
|
||||
return !(left == right);
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (obj.GetType() != GetType())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return this == (VertexPosition) obj;
|
||||
}
|
||||
|
||||
static VertexPosition()
|
||||
{
|
||||
VertexElement[] elements = { new VertexElement (0, VertexElementFormat.Vector3, VertexElementUsage.Position, 0) };
|
||||
VertexDeclaration declaration = new VertexDeclaration(elements);
|
||||
VertexDeclaration = declaration;
|
||||
}
|
||||
}
|
||||
}
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
using System;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Graphics
|
||||
{
|
||||
[DataContract]
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct VertexPositionColor : IVertexType
|
||||
{
|
||||
[DataMember]
|
||||
public Vector3 Position;
|
||||
|
||||
[DataMember]
|
||||
public Color Color;
|
||||
|
||||
public static readonly VertexDeclaration VertexDeclaration;
|
||||
|
||||
public VertexPositionColor(Vector3 position, Color color)
|
||||
{
|
||||
this.Position = position;
|
||||
Color = color;
|
||||
}
|
||||
|
||||
VertexDeclaration IVertexType.VertexDeclaration
|
||||
{
|
||||
get
|
||||
{
|
||||
return VertexDeclaration;
|
||||
}
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
return (Position.GetHashCode() * 397) ^ Color.GetHashCode();
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return "{{Position:" + this.Position + " Color:" + this.Color + "}}";
|
||||
}
|
||||
|
||||
public static bool operator == (VertexPositionColor left, VertexPositionColor right)
|
||||
{
|
||||
return ((left.Color == right.Color) && (left.Position == right.Position));
|
||||
}
|
||||
|
||||
public static bool operator != (VertexPositionColor left, VertexPositionColor right)
|
||||
{
|
||||
return !(left == right);
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (obj.GetType () != base.GetType ()) {
|
||||
return false;
|
||||
}
|
||||
return (this == ((VertexPositionColor)obj));
|
||||
}
|
||||
|
||||
static VertexPositionColor()
|
||||
{
|
||||
VertexElement[] elements = new VertexElement[] { new VertexElement (0, VertexElementFormat.Vector3, VertexElementUsage.Position, 0), new VertexElement (12, VertexElementFormat.Color, VertexElementUsage.Color, 0) };
|
||||
VertexDeclaration declaration = new VertexDeclaration (elements);
|
||||
VertexDeclaration = declaration;
|
||||
}
|
||||
}
|
||||
}
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Graphics
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct VertexPositionColorTexture : IVertexType
|
||||
{
|
||||
public Vector3 Position;
|
||||
public Color Color;
|
||||
public Vector2 TextureCoordinate;
|
||||
public static readonly VertexDeclaration VertexDeclaration;
|
||||
|
||||
public VertexPositionColorTexture(Vector3 position, Color color, Vector2 textureCoordinate)
|
||||
{
|
||||
Position = position;
|
||||
Color = color;
|
||||
TextureCoordinate = textureCoordinate;
|
||||
}
|
||||
|
||||
VertexDeclaration IVertexType.VertexDeclaration
|
||||
{
|
||||
get
|
||||
{
|
||||
return VertexDeclaration;
|
||||
}
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
var hashCode = Position.GetHashCode();
|
||||
hashCode = (hashCode * 397) ^ Color.GetHashCode();
|
||||
hashCode = (hashCode * 397) ^ TextureCoordinate.GetHashCode();
|
||||
return hashCode;
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return "{{Position:" + this.Position + " Color:" + this.Color + " TextureCoordinate:" + this.TextureCoordinate + "}}";
|
||||
}
|
||||
|
||||
public static bool operator ==(VertexPositionColorTexture left, VertexPositionColorTexture right)
|
||||
{
|
||||
return (((left.Position == right.Position) && (left.Color == right.Color)) && (left.TextureCoordinate == right.TextureCoordinate));
|
||||
}
|
||||
|
||||
public static bool operator !=(VertexPositionColorTexture left, VertexPositionColorTexture right)
|
||||
{
|
||||
return !(left == right);
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj == null)
|
||||
return false;
|
||||
|
||||
if (obj.GetType() != base.GetType())
|
||||
return false;
|
||||
|
||||
return (this == ((VertexPositionColorTexture)obj));
|
||||
}
|
||||
|
||||
static VertexPositionColorTexture()
|
||||
{
|
||||
var elements = new VertexElement[]
|
||||
{
|
||||
new VertexElement(0, VertexElementFormat.Vector3, VertexElementUsage.Position, 0),
|
||||
new VertexElement(12, VertexElementFormat.Color, VertexElementUsage.Color, 0),
|
||||
new VertexElement(16, VertexElementFormat.Vector2, VertexElementUsage.TextureCoordinate, 0)
|
||||
};
|
||||
VertexDeclaration = new VertexDeclaration(elements);
|
||||
}
|
||||
}
|
||||
}
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Graphics
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct VertexPositionNormalTexture : IVertexType
|
||||
{
|
||||
public Vector3 Position;
|
||||
public Vector3 Normal;
|
||||
public Vector2 TextureCoordinate;
|
||||
public static readonly VertexDeclaration VertexDeclaration;
|
||||
public VertexPositionNormalTexture(Vector3 position, Vector3 normal, Vector2 textureCoordinate)
|
||||
{
|
||||
this.Position = position;
|
||||
this.Normal = normal;
|
||||
this.TextureCoordinate = textureCoordinate;
|
||||
}
|
||||
|
||||
VertexDeclaration IVertexType.VertexDeclaration
|
||||
{
|
||||
get
|
||||
{
|
||||
return VertexDeclaration;
|
||||
}
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
var hashCode = Position.GetHashCode();
|
||||
hashCode = (hashCode * 397) ^ Normal.GetHashCode();
|
||||
hashCode = (hashCode * 397) ^ TextureCoordinate.GetHashCode();
|
||||
return hashCode;
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return "{{Position:" + this.Position + " Normal:" + this.Normal + " TextureCoordinate:" + this.TextureCoordinate + "}}";
|
||||
}
|
||||
|
||||
public static bool operator ==(VertexPositionNormalTexture left, VertexPositionNormalTexture right)
|
||||
{
|
||||
return (((left.Position == right.Position) && (left.Normal == right.Normal)) && (left.TextureCoordinate == right.TextureCoordinate));
|
||||
}
|
||||
|
||||
public static bool operator !=(VertexPositionNormalTexture left, VertexPositionNormalTexture right)
|
||||
{
|
||||
return !(left == right);
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (obj.GetType() != base.GetType())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return (this == ((VertexPositionNormalTexture)obj));
|
||||
}
|
||||
|
||||
static VertexPositionNormalTexture()
|
||||
{
|
||||
VertexElement[] elements = new VertexElement[] { new VertexElement(0, VertexElementFormat.Vector3, VertexElementUsage.Position, 0), new VertexElement(12, VertexElementFormat.Vector3, VertexElementUsage.Normal, 0), new VertexElement(0x18, VertexElementFormat.Vector2, VertexElementUsage.TextureCoordinate, 0) };
|
||||
VertexDeclaration declaration = new VertexDeclaration(elements);
|
||||
VertexDeclaration = declaration;
|
||||
}
|
||||
}
|
||||
}
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Graphics
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, Pack=1)]
|
||||
public struct VertexPositionTexture : IVertexType
|
||||
{
|
||||
public Vector3 Position;
|
||||
public Vector2 TextureCoordinate;
|
||||
public static readonly VertexDeclaration VertexDeclaration;
|
||||
public VertexPositionTexture(Vector3 position, Vector2 textureCoordinate)
|
||||
{
|
||||
this.Position = position;
|
||||
this.TextureCoordinate = textureCoordinate;
|
||||
}
|
||||
|
||||
VertexDeclaration IVertexType.VertexDeclaration
|
||||
{
|
||||
get
|
||||
{
|
||||
return VertexDeclaration;
|
||||
}
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
return (Position.GetHashCode() * 397) ^ TextureCoordinate.GetHashCode();
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return "{{Position:" + this.Position + " TextureCoordinate:" + this.TextureCoordinate + "}}";
|
||||
}
|
||||
|
||||
public static bool operator ==(VertexPositionTexture left, VertexPositionTexture right)
|
||||
{
|
||||
return ((left.Position == right.Position) && (left.TextureCoordinate == right.TextureCoordinate));
|
||||
}
|
||||
|
||||
public static bool operator !=(VertexPositionTexture left, VertexPositionTexture right)
|
||||
{
|
||||
return !(left == right);
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (obj.GetType() != base.GetType())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return (this == ((VertexPositionTexture)obj));
|
||||
}
|
||||
|
||||
static VertexPositionTexture()
|
||||
{
|
||||
VertexElement[] elements = new VertexElement[] { new VertexElement(0, VertexElementFormat.Vector3, VertexElementUsage.Position, 0), new VertexElement(12, VertexElementFormat.Vector2, VertexElementUsage.TextureCoordinate, 0) };
|
||||
VertexDeclaration declaration = new VertexDeclaration(elements);
|
||||
VertexDeclaration = declaration;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user