(ded4a3e0a) v0.9.0.7

This commit is contained in:
Joonas Rikkonen
2019-06-25 16:00:44 +03:00
parent e5ae622c77
commit 4a51db77b5
1777 changed files with 421528 additions and 917 deletions
@@ -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
}
}
@@ -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);
}
}
}
@@ -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;
}
}
}
@@ -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;
}
}
}
@@ -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);
}
}
}
@@ -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);
}
}
}
@@ -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);
}
}
}
@@ -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
}
}
@@ -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 + ".";
}
}
}
@@ -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,
}
}
@@ -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);
}
}
}
@@ -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);
}
}
}
@@ -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();
}
}
}
@@ -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);
}
}
}
@@ -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;
}
}
}
@@ -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);
}
}
}
@@ -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;
}
}
}
@@ -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>();
}
}
}
}
@@ -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();
}
}
}
@@ -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);
}
}
}
@@ -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;
}
}
}
}
@@ -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;
}
}
}
@@ -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);
}
}
}
@@ -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
}
}
@@ -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
}
}
@@ -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;
}
}
}
@@ -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);
}
}
}
@@ -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;
}
}
}
@@ -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;
}
}
}
@@ -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);
}
}
}
@@ -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;
}
}
}
@@ -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;
}
}
}