private static Array CreateArray <T>() { T[] array = new T[16]; Random random = new Random(); int arrayItemSize = Marshal.SizeOf(typeof(T)); switch (ArrayBufferItem.GetArrayBaseType(typeof(T))) { case VertexBaseType.Float: unsafe { GCHandle arrayHandle = GCHandle.Alloc(array, GCHandleType.Pinned); try { float *arrayPtr = (float *)arrayHandle.AddrOfPinnedObject().ToPointer(); for (int i = 0; i < (array.Length * arrayItemSize) / Marshal.SizeOf(typeof(float)); i++) { arrayPtr[i] = (float)random.NextDouble(); } } finally { arrayHandle.Free(); } } break; } return(array); }
/// <summary> /// Copy this array buffer object to another one, but having a different array item type. /// </summary> /// <param name="vertexArrayType"> /// A <see cref="ArrayBufferItemType"/> that specify the returned <see cref="ArrayBufferObject"/> item type. /// </param> /// <returns> /// It returns a copy of this ArrayBufferObject, but having a different array item. The returned instance is actually /// a <see cref="ArrayBufferObject"/>. /// </returns> /// <exception cref="ArgumentException"> /// Exception thrown if the array base type of this ArrayBufferObject (<see cref="ArrayBaseType"/>) is different to the one /// derived from <paramref name="vertexArrayType"/>. /// </exception> /// <exception cref="InvalidOperationException"> /// Exception thrown if the number of base components of this ArrayBufferObject cannot be mapped into the base components /// count derived from <paramref name="vertexArrayType"/>. /// </exception> public ArrayBufferObject ConvertItemType(ArrayBufferItemType vertexArrayType) { if (ArrayBufferItem.GetArrayBaseType(_ArrayType) != ArrayBufferItem.GetArrayBaseType(vertexArrayType)) { throw new ArgumentException("base type mismatch", "vertexArrayType"); } uint componentsCount = ItemCount * ArrayBufferItem.GetArrayLength(ArrayType) * ArrayBufferItem.GetArrayRank(ArrayType); uint convComponentsCount = ArrayBufferItem.GetArrayLength(vertexArrayType) * ArrayBufferItem.GetArrayRank(vertexArrayType); Debug.Assert(componentsCount >= convComponentsCount); if ((componentsCount % convComponentsCount) != 0) { throw new InvalidOperationException("components length incompatibility"); } ArrayBufferObject arrayObject = CreateArrayObject(vertexArrayType, Hint); // Different item count due different lengths arrayObject.Create(componentsCount / convComponentsCount); // Memory is copied Memory.MemoryCopy(arrayObject.ClientBufferAddress, ClientBufferAddress, ClientBufferSize); return(arrayObject); }
private void EnableVertexAttribute(GraphicsContext ctx, ShaderProgram.AttributeBinding attributeBinding) { ArrayBufferObjectBase.IArraySection arraySection = ArrayBuffer.GetArraySection(ArraySectionIndex); int arrayBaseType = (int)ArrayBufferItem.GetArrayBaseType(arraySection.ItemType); int arrayLength = (int)ArrayBufferItem.GetArrayLength(arraySection.ItemType); int arrayStride = arraySection.Stride.ToInt32(); // Avoid rendundant buffer binding and relative vertex array setup if (ctx.Caps.GlExtensions.VertexArrayObject_ARB && IsDirty == false) { CheckVertexAttribute(ctx, attributeBinding); return; } // Bind the array buffer ArrayBuffer.Bind(ctx); // Bind varying attribute to currently bound buffer object switch (ArrayBufferItem.GetArrayBaseType(attributeBinding.Type)) { case VertexBaseType.Float: Gl.VertexAttribPointer( attributeBinding.Location, arrayLength, arrayBaseType, arraySection.Normalized, arrayStride, arraySection.Offset ); break; case VertexBaseType.Int: case VertexBaseType.UInt: Gl.VertexAttribIPointer( attributeBinding.Location, arrayLength, arrayBaseType, arrayStride, arraySection.Offset ); break; case VertexBaseType.Double: Gl.VertexAttribLPointer( attributeBinding.Location, arrayLength, arrayBaseType, arrayStride, arraySection.Offset ); break; default: throw new NotSupportedException(String.Format("vertex attribute type {0} not supported", attributeBinding.Type)); } // Enable vertex attribute Gl.EnableVertexAttribArray(attributeBinding.Location); }
internal void CheckVertexAttribute(GraphicsContext ctx, ShaderProgram.AttributeBinding attributeBinding) { if (ArrayBuffer != null) { ArrayBufferObjectBase.IArraySection arraySection = ArrayBuffer.GetArraySection(ArraySectionIndex); int arrayBaseType = (int)ArrayBufferItem.GetArrayBaseType(arraySection.ItemType); int arrayLength = (int)ArrayBufferItem.GetArrayLength(arraySection.ItemType); int arrayStride = arraySection.Stride.ToInt32(); // Check effective state IntPtr vertexAttribPointer; int vertexAttribArrayBufferBinding; int vertexAttribArraySize; int vertexAttribArrayType; int vertexAttribArrayNormalized; int vertexAttribArrayStride; int vertexAttribArrayEnabled; // Attribute pointer/offset Gl.GetVertexAttribPointer(attributeBinding.Location, Gl.VERTEX_ATTRIB_ARRAY_POINTER, out vertexAttribPointer); Debug.Assert(vertexAttribPointer == new IntPtr(arraySection.Pointer.ToInt64() + arraySection.Offset.ToInt64())); // Array buffer binding Gl.GetVertexAttrib(attributeBinding.Location, Gl.VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, out vertexAttribArrayBufferBinding); Debug.Assert(vertexAttribArrayBufferBinding == ArrayBuffer.ObjectName); // Array size Gl.GetVertexAttrib(attributeBinding.Location, Gl.VERTEX_ATTRIB_ARRAY_SIZE, out vertexAttribArraySize); Debug.Assert(vertexAttribArraySize == arrayLength); // Array type Gl.GetVertexAttrib(attributeBinding.Location, Gl.VERTEX_ATTRIB_ARRAY_TYPE, out vertexAttribArrayType); Debug.Assert(vertexAttribArrayType == arrayBaseType); // Array normalized Gl.GetVertexAttrib(attributeBinding.Location, Gl.VERTEX_ATTRIB_ARRAY_NORMALIZED, out vertexAttribArrayNormalized); Debug.Assert((vertexAttribArrayNormalized != 0) == arraySection.Normalized); // Array size Gl.GetVertexAttrib(attributeBinding.Location, Gl.VERTEX_ATTRIB_ARRAY_STRIDE, out vertexAttribArrayStride); Debug.Assert(vertexAttribArrayStride == arrayStride); // Attribute enabled Gl.GetVertexAttrib(attributeBinding.Location, Gl.VERTEX_ATTRIB_ARRAY_ENABLED, out vertexAttribArrayEnabled); Debug.Assert(vertexAttribArrayEnabled == Gl.TRUE); } else { int vertexAttribArrayEnabled; // Attribute disabled Gl.GetVertexAttrib(attributeBinding.Location, Gl.VERTEX_ATTRIB_ARRAY_ENABLED, out vertexAttribArrayEnabled); Debug.Assert(vertexAttribArrayEnabled == Gl.FALSE); } }
/// <summary> /// Copy from an ArrayBufferObject with an indirection defined by an index. /// </summary> /// <param name="buffer"> /// An <see cref="ArrayBufferObject"/> that specify the source data buffer to copy. /// </param> /// <param name="indices"> /// An array of indices indicating the order of the vertices copied from <paramref name="buffer"/>. /// </param> /// <param name="count"> /// A <see cref="UInt32"/> that specify how many elements to copy from <paramref name="buffer"/>. /// </param> /// <param name="offset"> /// A <see cref="UInt32"/> that specify the first index considered from <paramref name="indices"/>. A /// value of 0 indicates that the indices are considered from the first one. /// </param> /// <param name="stride"> /// A <see cref="UInt32"/> that specify the offset between two indexes considered for the copy operations /// from <paramref name="indices"/>. A value of 1 indicates that all considered indices are contiguos. /// </param> /// <exception cref="ArgumentNullException"> /// Exception thrown if <paramref name="buffer"/> or <paramref name="indices"/> are null. /// </exception> /// <exception cref="ArgumentException"> /// Exception thrown if <paramref name="count"/> or <paramref name="stride"/> equals to 0. /// </exception> /// <exception cref="InvalidOperationException"> /// Exception thrown if the combination of <paramref name="count"/>, <paramref name="offset"/> and /// <paramref name="stride"/> will cause a <paramref name="indices"/> array access out of its bounds. /// </exception> /// <exception cref="InvalidOperationException"> /// Exception thrown if this <see cref="ArrayBufferObject"/> have a complex data layout, of it has a vertex /// base type different from <paramref name="buffer"/>. /// </exception> /// <remarks> /// <para> /// After a successfull copy operation, the previous buffer is discarded replaced by the copied buffer from /// <paramref name="buffer"/>. /// </para> /// </remarks> public void Copy(ArrayBufferObject buffer, uint[] indices, uint count, uint offset, uint stride) { if (buffer == null) { throw new ArgumentNullException("buffer"); } if (indices == null) { throw new ArgumentNullException("indices"); } if (count == 0) { throw new ArgumentException("invalid", "count"); } if (stride == 0) { throw new ArgumentException("invalid", "stride"); } if (offset + ((count - 1) * stride) > indices.Length) { throw new InvalidOperationException("indices out of bounds"); } if (ArrayBufferItem.GetArrayBaseType(_ArrayType) != ArrayBufferItem.GetArrayBaseType(buffer._ArrayType)) { throw new InvalidOperationException("base type mismatch"); } Create(count); unsafe { byte *dstPtr = (byte *)ClientBufferAddress.ToPointer(); for (uint i = 0; i < count; i++, dstPtr += ItemSize) { uint arrayIndex = indices[(i * stride) + offset]; // Position 'srcPtr' to the indexed element byte *srcPtr = ((byte *)buffer.ClientBufferAddress.ToPointer()) + (ItemSize * arrayIndex); // Copy the 'arrayIndex'th element Memory.MemoryCopy(dstPtr, srcPtr, ItemSize); } } }
/// <summary> /// Convert this array buffer object in a strongly-typed array. /// </summary> /// <typeparam name="T"> /// An arbitrary structure defining the returned array item. It doesn't need to be correlated with the ArrayBufferObject /// layout. /// </typeparam> /// <param name="arrayLength"> /// A <see cref="UInt32"/> that specify the number of elements of the returned array. /// </param> /// <returns> /// It returns an array having all items stored by this ArrayBufferObject. /// </returns> public T[] ToArray <T>(uint arrayLength) where T : struct { if (arrayLength > ItemCount) { throw new ArgumentOutOfRangeException("arrayLength", arrayLength, "cannot exceed items count"); } if (ClientBufferAddress == IntPtr.Zero) { throw new InvalidOperationException("no client buffer"); } Type arrayElementType = typeof(T); if (arrayElementType == null || !arrayElementType.IsValueType) { throw new InvalidOperationException("invalid array element type"); } // The base type should be corresponding ArrayBufferItemType arrayElementVertexType = ArrayBufferItem.GetArrayType(arrayElementType); if (ArrayBufferItem.GetArrayBaseType(_ArrayType) != ArrayBufferItem.GetArrayBaseType(arrayElementVertexType)) { throw new InvalidOperationException(String.Format("source base type of {0} incompatible with destination base type of {1}", arrayElementType.Name, ArrayBufferItem.GetArrayBaseType(_ArrayType))); } // Array element item size cannot exceed ItemSize uint arrayItemSize = ArrayBufferItem.GetArrayItemSize(arrayElementVertexType); if (arrayItemSize > ItemSize) { throw new ArgumentException("array element type too big", "array"); } T[] array = new T[arrayLength]; // Copy from buffer data to array data CopyArray(array, arrayItemSize, ClientBufferAddress, ItemSize, 0, arrayLength); return(array); }
/// <summary> /// /// </summary> /// <param name="vertexArrayType"></param> public ArrayBufferItemAttribute(ArrayBufferItemType vertexArrayType) { ArrayBaseType = ArrayBufferItem.GetArrayBaseType(vertexArrayType); ArrayLength = ArrayBufferItem.GetArrayLength(vertexArrayType); ArrayRank = ArrayBufferItem.GetArrayRank(vertexArrayType); }
/// <summary> /// Copy from an ArrayBufferObject with an indirection defined by an index (polygon tessellation). /// </summary> /// <param name="buffer"> /// An <see cref="ArrayBufferObject"/> that specify the source data buffer to copy. /// </param> /// <param name="vcount"> /// An array of integers indicating the number of the vertices of the polygon copied from <paramref name="buffer"/>. This parameter /// indicated how many polygons to copy (the array length). Each item specify the number of vertices composing the polygon. /// </param> /// <param name="indices"> /// An array of indices indicating the order of the vertices copied from <paramref name="buffer"/>. /// </param> /// <param name="offset"> /// A <see cref="UInt32"/> that specify the first index considered from <paramref name="indices"/>. A /// value of 0 indicates that the indices are considered from the first one. /// </param> /// <param name="stride"> /// A <see cref="UInt32"/> that specify the offset between two indexes considered for the copy operations /// from <paramref name="indices"/>. A value of 1 indicates that all considered indices are contiguos. /// </param> /// <exception cref="ArgumentNullException"> /// Exception thrown if <paramref name="buffer"/>, <paramref name="indices"/> or <paramref name="vcount"/> are null. /// </exception> /// <exception cref="InvalidOperationException"> /// Exception thrown if this <see cref="ArrayBufferObject"/> have a complex data layout, of it has a vertex /// base type different from <paramref name="buffer"/>. /// </exception> /// <remarks> /// <para> /// After a successfull copy operation, the previous buffer is discarded replaced by the copied buffer from /// <paramref name="buffer"/>. /// </para> /// </remarks> public void Copy(ArrayBufferObject buffer, uint[] indices, uint[] vcount, uint offset, uint stride) { if (buffer == null) { throw new ArgumentNullException("buffer"); } if (indices == null) { throw new ArgumentNullException("indices"); } if (vcount == null) { throw new ArgumentNullException("indices"); } if (stride == 0) { throw new ArgumentException("invalid", "stride"); } if (ArrayBufferItem.GetArrayBaseType(_ArrayType) != ArrayBufferItem.GetArrayBaseType(buffer._ArrayType)) { throw new InvalidOperationException("base type mismatch"); } // Allocate array buffer uint minVertices = UInt32.MaxValue, maxVertices = UInt32.MinValue; Array.ForEach(vcount, delegate(uint v) { minVertices = Math.Min(v, minVertices); maxVertices = Math.Max(v, maxVertices); }); if ((minVertices < 3) && (maxVertices >= 3)) { throw new ArgumentException("ambigous polygons set", "vcount"); } uint totalVerticesCount = 0; Array.ForEach(vcount, delegate(uint v) { if (v == 4) { totalVerticesCount += 6; // Triangulate quad with two triangles } else if (v > 4) { totalVerticesCount += (v - 2) * 3; // Triangulate as if it is a polygon } else { Debug.Assert(v == 3); totalVerticesCount += 3; // Exactly a triangle } }); Create(totalVerticesCount); // Copy polygons (triangulate) uint count = 0; unsafe { byte *dstPtr = (byte *)ClientBufferAddress.ToPointer(); uint indicesIndex = offset; for (uint i = 0; i < vcount.Length; i++) { uint verticesCount = vcount[i]; uint[] verticesIndices; if (verticesCount == 4) { verticesIndices = new uint[6]; verticesIndices[0] = indices[indicesIndex + (0 * stride)]; verticesIndices[1] = indices[indicesIndex + (1 * stride)]; verticesIndices[2] = indices[indicesIndex + (2 * stride)]; verticesIndices[3] = indices[indicesIndex + (0 * stride)]; verticesIndices[4] = indices[indicesIndex + (2 * stride)]; verticesIndices[5] = indices[indicesIndex + (3 * stride)]; indicesIndex += 4 * stride; } else if (verticesCount > 4) { uint triCount = verticesCount - 2; uint pivotIndex = indicesIndex; verticesIndices = new uint[triCount * 3]; // Copy polygon indices for (uint tri = 0; tri < triCount; tri++) { verticesIndices[tri * 3 + 0] = indices[pivotIndex]; verticesIndices[tri * 3 + 1] = indices[indicesIndex + (tri + 2) * stride]; verticesIndices[tri * 3 + 2] = indices[indicesIndex + (tri + 1) * stride]; } indicesIndex += verticesCount * stride; } else { verticesIndices = new uint[verticesCount]; for (int j = 0; j < verticesCount; j++, indicesIndex += stride) { verticesIndices[j] = indices[indicesIndex]; } } count += (uint)verticesIndices.Length; for (uint j = 0; j < verticesIndices.Length; j++, dstPtr += ItemSize) { // Position 'srcPtr' to the indexed element byte *srcPtr = ((byte *)buffer.ClientBufferAddress.ToPointer()) + (ItemSize * verticesIndices[j]); // Copy the 'arrayIndex'th element Memory.MemoryCopy(dstPtr, srcPtr, ItemSize); } } } }