/// <summary> /// Creates a <see cref="VertexAttribDescription"/> where the format of the data declared /// in the shader isn't the same as the format the data will be read as. /// </summary> /// <param name="attribType">The type of the attribute declared in the shader.</param> /// <param name="normalized">Whether the vertex data should be normalized before being loaded into the shader.</param> /// <param name="dataBaseType">The base type in which the data will be read from the buffer.</param> /// <param name="attribDivisor">The divisor that defines how reading this attribute advances on instanced rendering.</param> public VertexAttribDescription(AttributeType attribType, bool normalized, AttributeBaseType dataBaseType, uint attribDivisor = 0) { ValidateAttribDivisor(attribDivisor); if (normalized) { if (!TrippyUtils.IsVertexAttribIntegerType(dataBaseType)) { throw new ArgumentException("For normalized vertex attributes, the dataBaseType must be an integer", nameof(dataBaseType)); } if (!(TrippyUtils.IsVertexAttribFloatType(attribType) || TrippyUtils.IsVertexAttribDoubleType(attribType))) { throw new ArgumentException("For normalized vertex attributes, the attribType must be a float or a double", nameof(attribType)); } } Normalized = normalized; AttribDivisor = attribDivisor; AttribBaseType = dataBaseType; AttribType = attribType; Size = TrippyUtils.GetVertexAttribTypeSize(attribType); AttribIndicesUseCount = TrippyUtils.GetVertexAttribTypeIndexCount(attribType); SizeInBytes = TrippyUtils.GetVertexAttribSizeInBytes(dataBaseType) * (uint)Size * AttribIndicesUseCount; }
/// <summary> /// Gets the size in bytes of the given <see cref="AttributeBaseType"/>. /// </summary> public static uint GetVertexAttribSizeInBytes(AttributeBaseType type) { switch (type) { case AttributeBaseType.Byte: case AttributeBaseType.UnsignedByte: return(1); case AttributeBaseType.Short: case AttributeBaseType.UnsignedShort: case AttributeBaseType.HalfFloat: return(2); case AttributeBaseType.Float: case AttributeBaseType.Int: case AttributeBaseType.UnsignedInt: case AttributeBaseType.Fixed: return(4); case AttributeBaseType.Double: return(8); default: throw new NotSupportedException(string.Concat("Cannot get size for " + nameof(AttributeBaseType) + ":", type.ToString())); } }
public AttributeDefinition(string name, AttributeBaseType baseType, int dimensions) { this.name = name; type = new AttributeType { baseType = baseType, dimensions = dimensions }; defaultValue = NullValue(); }
/// <summary> /// Creates a <see cref="VertexAttribDescription"/> that represents no real attributes and is /// used to indicate padding (unused, ignored buffer memory in between other vertex attribs). /// </summary> /// <param name="paddingBytes">The amount of padding in bytes.</param> public VertexAttribDescription(uint paddingBytes) { if (paddingBytes <= 0) { throw new ArgumentOutOfRangeException(nameof(paddingBytes), paddingBytes, nameof(paddingBytes) + " must be greater than 0"); } Size = 0; AttribBaseType = 0; SizeInBytes = paddingBytes; // The only non-zero field when a VertexAttribDescription is used for padding, stores the padding in bytes Normalized = false; AttribIndicesUseCount = 0; // We'll use this value to be the one that decides whether this is padding. If it uses 0 indices, it's padding. AttribType = default; AttribDivisor = 0; }
public AttributeDefinition AddFaceAttribute(string name, AttributeBaseType baseType, int dimensions) { return(AddFaceAttribute(new AttributeDefinition(name, baseType, dimensions))); }
/// <summary> /// Creates a <see cref="VertexAttribSource"/> with a given <see cref="BufferObjectSubset"/> and specifies /// a vertex attribute where the data format in the shader and the buffer don't match and need conversion. /// </summary> /// <param name="bufferSubset">The <see cref="BufferObjectSubset"/> where the vertex attrib data is located. Must be a subset usable for vertex data.</param> /// <param name="attribType">The type of attribute declared in the shader.</param> /// <param name="normalized">Whether the data needs to be normalized (uint/ushort/byte -> float between 0 and 1, or int/short/sbyte -> float between -1 and 1).</param> /// <param name="dataBaseType">The base type of the data found on the buffer. If normalized is true, this must be an integer type.</param> /// <param name="attribDivisor">The divisor that defines how reading this attribute advances on instanced rendering.</param> public VertexAttribSource(DataBufferSubset bufferSubset, AttributeType attribType, bool normalized, AttributeBaseType dataBaseType, uint attribDivisor = 0) : this(bufferSubset, new VertexAttribDescription(attribType, normalized, dataBaseType, attribDivisor)) { }
/// <summary> /// Creates a <see cref="VertexAttribSource"/> that specifies padding for an /// amount of bytes calculated based on the baseType and size parameters. /// </summary> /// <param name="bufferSubset">The buffer subset in which the padding will be applied.</param> /// <param name="baseType">The base type of the attribute.</param> /// <param name="size">The size of the attribute.</param> public static VertexAttribSource CreatePadding(DataBufferSubset bufferSubset, AttributeBaseType baseType, uint size) { return(new VertexAttribSource(bufferSubset, VertexAttribDescription.CreatePadding(baseType, size))); }
/// <summary> /// Creates a <see cref="VertexAttribDescription"/> that specifies padding for an /// amount of bytes calculated based on the baseType and size parameters. /// </summary> /// <remarks> /// Padding indicators ignore padding based on type that occurs when using compensation /// for struct padding (which is the default behavior in <see cref="VertexArray"/>). /// </remarks> public static VertexAttribDescription CreatePadding(AttributeBaseType baseType, uint size) { return(new VertexAttribDescription(TrippyUtils.GetVertexAttribSizeInBytes(baseType) * size)); }
/// <summary> /// Updates the places where vertex data is read from for this <see cref="VertexArray"/>. /// Call this whenever you modify a buffer subset used by this <see cref="VertexArray"/>. /// </summary> /// <param name="compensateStructPadding">Whether to compensate for struct padding. Default is true.</param> /// <param name="paddingPackValue">The struct packing value for compensating for padding. Default is 4.</param> public void UpdateVertexAttributes(bool compensateStructPadding = true, uint paddingPackValue = 4) { // Makes all glVertexAttribPointer calls to specify the vertex attrib data on the VAO and enables the vertex attributes. // The parameters of glVertexAttribPointer are calculated based on the VertexAttribSource-s from AttribSources GraphicsDevice.VertexArray = this; AttribCallDesc[] calls = new AttribCallDesc[attribSources.Length]; uint attribIndex = 0; for (int i = 0; i < calls.Length; i++) { calls[i] = new AttribCallDesc { source = attribSources[i], index = attribIndex, originalIndex = i }; attribIndex += calls[i].source.AttribDescription.AttribIndicesUseCount; } // Sort by buffer object, so all sources that share BufferObject are grouped together. // This facilitates calculating the offset values, since we only need to work with one offset at a time // rather than save the offset of each buffer simultaneously. Array.Sort(calls); // The calls array is now sorted. First by buffer handle, secondly by attrib index // and lastly, if two items have the same buffer handle and attrib index, they are sorted // by the original index they had in the calls array. // This logic is implemented in AttribCallDesc.CompareTo() if (compensateStructPadding) { #region CalculateOffsetsWithPadding uint offset = 0; BufferObjectSubset prevSubset = null; // Setting this to null ensures the first for loop will enter the "different subset" if and initialize these variables AttributeBaseType currentBaseType = 0; for (int i = 0; i < calls.Length; i++) { if (calls[i].source.BufferSubset != prevSubset) { // it's a different buffer subset, so let's calculate the padding values as for a new, different struct offset = 0; prevSubset = calls[i].source.BufferSubset; currentBaseType = calls[i].source.AttribDescription.AttribBaseType; calls[i].offset = 0; } else if (currentBaseType != calls[i].source.AttribDescription.AttribBaseType) { // the base type has changed, let's ensure padding is applied to offset currentBaseType = calls[i].source.AttribDescription.AttribBaseType; if (!calls[i].source.IsPadding) { // We add the manual padding, unless it is padding added specifically by the user uint packval = Math.Min(TrippyUtils.GetVertexAttribSizeInBytes(currentBaseType), paddingPackValue); // offset should be aligned by the default packing value or the size of the base type offset = (offset + packval - 1) / packval * packval; // Make offset be greater or equal to offset and divisible by packval } } calls[i].offset = offset; offset += calls[i].source.AttribDescription.SizeInBytes; } #endregion } else { #region CalculateOffsetsWithoutPadding uint offset = 0; uint prevBufferHandle = 0; for (int i = 0; i < calls.Length; i++) { if (prevBufferHandle != calls[i].source.BufferSubset.BufferHandle) { prevBufferHandle = calls[i].source.BufferSubset.BufferHandle; offset = 0; } calls[i].offset = offset; offset += calls[i].source.AttribDescription.SizeInBytes; } #endregion } for (int i = 0; i < calls.Length; i++) { calls[i].CallGlVertexAttribPointer(GL); } GL.BindBuffer(BufferTargetARB.ElementArrayBuffer, IndexBuffer == null ? 0 : IndexBuffer.BufferHandle); }
/// <summary> /// Gets the corresponding variables for the given <see cref="AttributeType"/>. /// </summary> /// <param name="attribType">The <see cref="AttributeType"/> type to get variables for.</param> /// <param name="indexUseCount">The amount of attribute indices it will need.</param> /// <param name="size">The amount of components each index will have.</param> /// <param name="type">The base type of each component.</param> public static void GetVertexAttribTypeData(AttributeType attribType, out uint indexUseCount, out int size, out AttributeBaseType type) { indexUseCount = GetVertexAttribTypeIndexCount(attribType); size = GetVertexAttribTypeSize(attribType); type = GetVertexAttribBaseType(attribType); }
/// <summary> /// Returns whether the given <see cref="AttributeBaseType"/> is of integer format (such as byte, ushort, int, uint). /// </summary> public static bool IsVertexAttribIntegerType(AttributeBaseType dataBaseType) { return(dataBaseType >= AttributeBaseType.Byte && dataBaseType <= AttributeBaseType.UnsignedInt); // accepted: Byte, UnsignedByte, Short, UnsignedShort, Int, UnsignedInt }