/// <summary> /// Virtual Unbind implementation. /// </summary> /// <param name="ctx"> /// A <see cref="GraphicsContext"/> used for binding. /// </param> protected virtual void UnbindCore(GraphicsContext ctx) { if (ctx.Caps.GlExtensions.VertexBufferObject_ARB) { Gl.BindBuffer(BufferType, InvalidObjectName); } }
public void BindAttributes(ShaderProgram program) { GenericVBO elementArray = new GenericVBO(0, "", 0, 0, VertexAttribPointerType.Byte, BufferTarget.ArrayBuffer); for (int i = 0; i < vbos.Length; i++) { if (vbos[i].bufferTarget == BufferTarget.ElementArrayBuffer) { elementArray = vbos[i]; continue; } int loc = Gl.GetAttribLocation(program.ProgramID, vbos[i].name); if (loc == -1) { throw new Exception(string.Format("Shader did not contain '{0}'.", vbos[i].name)); } Gl.EnableVertexAttribArray((uint)loc); Gl.BindBuffer(vbos[i].bufferTarget, vbos[i].vboID); Gl.VertexAttribPointer((uint)loc, vbos[i].size, vbos[i].pointerType, true, vbos[i].size * SizeOfType(vbos[i].pointerType), IntPtr.Zero); } if (elementArray.vboID != 0) { Gl.BindBuffer(BufferTarget.ElementArrayBuffer, elementArray.vboID); VertexCount = elementArray.length; } }
/// <summary> /// Generic method for binding the VBOs to their respective attribute locations. /// OpenGL.dll assumes the common naming conventions below: /// vertices: vec3 in_position /// normals: vec3 in_normal /// uv: vec2 in_uv /// tangent: vec3 in_tangent /// </summary> public void BindAttributes(ShaderProgram program) { if (vertex == null || vertex.vboID == 0) { throw new Exception("Error binding attributes. No vertices were supplied."); } if (element == null || element.vboID == 0) { throw new Exception("Error binding attributes. No element array was supplied."); } // Note: Since the shader is already compiled, we cannot set the attribute locations. // Instead we must query the shader for the locations that the linker chose and use them. int loc = Gl.GetAttribLocation(program.ProgramID, "in_position"); if (loc == -1) { throw new Exception("Shader did not contain 'in_position'."); } Gl.EnableVertexAttribArray((uint)loc); Gl.BindBuffer(vertex.BufferTarget, vertex.vboID); Gl.VertexAttribPointer((uint)loc, vertex.Size, vertex.PointerType, true, 12, IntPtr.Zero); if (normal != null && normal.vboID != 0) { loc = Gl.GetAttribLocation(program.ProgramID, "in_normal"); if (loc != -1) { Gl.EnableVertexAttribArray((uint)loc); Gl.BindBuffer(normal.BufferTarget, normal.vboID); Gl.VertexAttribPointer((uint)loc, normal.Size, normal.PointerType, true, 12, IntPtr.Zero); } } if (uv != null && uv.vboID != 0) { loc = Gl.GetAttribLocation(program.ProgramID, "in_uv"); if (loc != -1) { Gl.EnableVertexAttribArray((uint)loc); Gl.BindBuffer(uv.BufferTarget, uv.vboID); Gl.VertexAttribPointer((uint)loc, uv.Size, uv.PointerType, true, 8, IntPtr.Zero); } } if (tangent != null && tangent.vboID != 0) { loc = Gl.GetAttribLocation(program.ProgramID, "in_tangent"); if (loc != -1) { Gl.EnableVertexAttribArray((uint)loc); Gl.BindBuffer(tangent.BufferTarget, tangent.vboID); Gl.VertexAttribPointer((uint)loc, tangent.Size, tangent.PointerType, true, 12, IntPtr.Zero); } } Gl.BindBuffer(BufferTarget.ElementArrayBuffer, element.vboID); }
/// <summary> /// Virtual Bind implementation. /// </summary> /// <param name="ctx"> /// A <see cref="GraphicsContext"/> used for binding. /// </param> protected virtual void BindCore(GraphicsContext ctx) { if (ctx.Caps.GlExtensions.VertexBufferObject_ARB) { CheckThisExistence(ctx); Gl.BindBuffer(BufferType, ObjectName); } }
/// <summary> /// Binds a VBO to a shader attribute. /// </summary> /// <param name="buffer">The VBO to bind to the shader attribute.</param> /// <param name="program">The shader program whose attribute will be bound to.</param> /// <param name="attributeName">The name of the shader attribute to be bound to.</param> public static void BindBufferToShaderAttribute <T>(VBO <T> buffer, ShaderProgram program, string attributeName) where T : struct { uint location = (uint)Gl.GetAttribLocation(program.ProgramID, attributeName); Gl.EnableVertexAttribArray(location); Gl.BindBuffer(buffer); Gl.VertexAttribPointer(location, buffer.Size, buffer.PointerType, true, Marshal.SizeOf(typeof(T)), IntPtr.Zero); }
/// <summary> /// Unbind this BufferObject. /// </summary> /// <param name="ctx"> /// The <see cref="GraphicsContext"/> used for unbinding any BufferObject. /// </param> internal virtual void Unbind(GraphicsContext ctx) { CheckCurrentContext(ctx); if (ctx.Caps.GlExtensions.VertexBufferObject_ARB) { Gl.BindBuffer(BufferType, InvalidObjectName); } }
/// <summary> /// Creates a standard VBO of type T where the length of the VBO is less than or equal to the length of the data. /// </summary> /// <typeparam name="T">The type of the data being stored in the VBO (make sure it's byte aligned).</typeparam> /// <param name="target">The VBO BufferTarget (usually ArrayBuffer or ElementArrayBuffer).</param> /// <param name="data">The data to store in the VBO.</param> /// <param name="hint">The buffer usage hint (usually StaticDraw).</param> /// <param name="length">The length of the VBO (will take the first 'length' elements from data).</param> /// <returns>The buffer ID of the VBO on success, 0 on failure.</returns> public static uint CreateVBO <T>(BufferTarget target, [InAttribute, OutAttribute] T[] data, BufferUsageHint hint, int position, int length) where T : struct { uint vboHandle = Gl.GenBuffer(); if (vboHandle == 0) { return(0); } Gl.BindBuffer(target, vboHandle); Gl.BufferData <T>(target, position * Marshal.SizeOf(typeof(T)), length * Marshal.SizeOf(typeof(T)), data, hint); Gl.BindBuffer(target, 0); return(vboHandle); }
/// <summary> /// Updates a subset of the buffer object's data store. /// </summary> /// <typeparam name="T">The type of data in the data array.</typeparam> /// <param name="vboID">The VBO whose buffer will be updated.</param> /// <param name="target">Specifies the target buffer object. Must be ArrayBuffer, ElementArrayBuffer, PixelPackBuffer or PixelUnpackBuffer.</param> /// <param name="data">The new data that will be copied to the data store.</param> /// <param name="length">The size in bytes of the data store region being replaced.</param> public static void BufferSubData <T>(uint vboID, BufferTarget target, T[] data, int length) where T : struct { GCHandle handle = GCHandle.Alloc(data, GCHandleType.Pinned); try { Gl.BindBuffer(target, vboID); Gl.BufferSubData(target, IntPtr.Zero, (IntPtr)(Marshal.SizeOf(data[0]) * length), handle.AddrOfPinnedObject()); } finally { handle.Free(); } }
/// <summary> /// Creates a standard VBO of type T where the length of the VBO is less than or equal to the length of the data. /// </summary> /// <typeparam name="T">The type of the data being stored in the VBO (make sure it's byte aligned).</typeparam> /// <param name="target">The VBO BufferTarget (usually ArrayBuffer or ElementArrayBuffer).</param> /// <param name="data">The data to store in the VBO.</param> /// <param name="hint">The buffer usage hint (usually StaticDraw).</param> /// <param name="length">The length of the VBO (will take the first 'length' elements from data).</param> /// <returns>The buffer ID of the VBO on success, 0 on failure.</returns> public static uint CreateVBO<T>(BufferTarget target, [In, Out] T[] data, BufferUsageHint hint, int length) where T : struct { uint vboHandle = Gl.GenBuffer(); if (vboHandle == 0) return 0; int size = length * Marshal.SizeOf(typeof(T)); #if MEMORY_LOGGER MemoryLogger.AllocateVBO(vboHandle, size); #endif Gl.BindBuffer(target, vboHandle); Gl.BufferData<T>(target, size, data, hint); Gl.BindBuffer(target, 0); return vboHandle; }
/// <summary> /// Updates a subset of the buffer object's data store. /// </summary> /// <param name="data">The new data that will be copied to the data store.</param> /// <param name="size">The size in bytes of the data store region being replaced.</param> /// <param name="offset">The offset in bytes into the buffer object's data store where data replacement will begin.</param> public void BufferSubData(T[] data, int size, int offset) { if (BufferTarget != OpenGL.BufferTarget.ArrayBuffer && BufferTarget != OpenGL.BufferTarget.ElementArrayBuffer && BufferTarget != OpenGL.BufferTarget.PixelPackBuffer && BufferTarget != OpenGL.BufferTarget.PixelUnpackBuffer) { throw new InvalidOperationException(string.Format("BufferSubData cannot be called with a BufferTarget of type {0}", BufferTarget.ToString())); } GCHandle handle = GCHandle.Alloc(data, GCHandleType.Pinned); try { Gl.BindBuffer(this); Gl.BufferSubData(BufferTarget, (IntPtr)offset, (IntPtr)size, handle.AddrOfPinnedObject()); } finally { handle.Free(); } }
/// <summary> /// Creates a vertex array object based on a series of attribute arrays and and attribute names. /// </summary> /// <param name="program">The shader program that contains the attributes to be bound to.</param> /// <param name="vbo">The VBO containing all of the attribute data.</param> /// <param name="sizes">An array of sizes which correspond to the size of each attribute.</param> /// <param name="types">An array of the attribute pointer types.</param> /// <param name="targets">An array of the buffer targets.</param> /// <param name="names">An array of the attribute names.</param> /// <param name="stride">The stride of the VBO.</param> /// <param name="eboHandle">The element buffer handle.</param> /// <returns>The vertex array object (VAO) ID.</returns> public static uint CreateVAO(ShaderProgram program, uint vbo, int[] sizes, VertexAttribPointerType[] types, BufferTarget[] targets, string[] names, int stride, uint eboHandle) { uint vaoHandle = Gl.GenVertexArray(); Gl.BindVertexArray(vaoHandle); int offset = 0; for (uint i = 0; i < names.Length; i++) { Gl.EnableVertexAttribArray(i); Gl.BindBuffer(targets[i], vbo); Gl.VertexAttribPointer(i, sizes[i], types[i], true, stride, new IntPtr(offset)); Gl.BindAttribLocation(program.ProgramID, i, names[i]); } Gl.BindBuffer(BufferTarget.ElementArrayBuffer, eboHandle); Gl.BindVertexArray(0); return vaoHandle; }
/// <summary> /// Creates a standard VBO of type T where the length of the VBO is less than or equal to the length of the data. /// </summary> /// <typeparam name="T">The type of the data being stored in the VBO (make sure it's byte aligned).</typeparam> /// <param name="target">The VBO BufferTarget (usually ArrayBuffer or ElementArrayBuffer).</param> /// <param name="data">The data to store in the VBO.</param> /// <param name="hint">The buffer usage hint (usually StaticDraw).</param> /// <param name="length">The length of the VBO (will take the first 'length' elements from data).</param> /// <returns>The buffer ID of the VBO on success, 0 on failure.</returns> public static uint CreateVBO <T>(BufferTarget target, [InAttribute, OutAttribute] T[] data, BufferUsageHint hint, int position, int length) where T : struct { uint vboHandle = Gl.GenBuffer(); if (vboHandle == 0) { return(0); } int offset = position * Marshal.SizeOf(typeof(T)); int size = length * Marshal.SizeOf(typeof(T)); #if MEMORY_LOGGER MemoryLogger.AllocateVBO(vboHandle, size - offset); #endif Gl.BindBuffer(target, vboHandle); Gl.BufferData <T>(target, offset, size, data, hint); Gl.BindBuffer(target, 0); return(vboHandle); }
/// <summary> /// Binds a VBO based on the buffer target. /// </summary> /// <param name="buffer">The VBO to bind.</param> public static void BindBuffer <T>(VBO <T> buffer) where T : struct { Gl.BindBuffer(buffer.BufferTarget, buffer.vboID); }
public void BindAttributes(ShaderProgram program) { IGenericVBO elementArray = null; for (int i = 0; i < vbos.Length; i++) { if (vbos[i].BufferTarget == BufferTarget.ElementArrayBuffer) { elementArray = vbos[i]; // To not break compatibility with previous versions of this call, // int is allowed as an element type even though the specs don't allow it. // All cases where int is used as the default element type have been marked obsolete // but until it's completely removed, this will serve to support that use case. if (allowIntAsElementType && vbos[i].PointerType == VertexAttribPointerType.Int) { elementType = DrawElementsType.UnsignedInt; } else { // Check if the element array can be used as an indice buffer. if (!ValidElementTypes.ContainsKey(vbos[i].PointerType)) { throw new Exception($"The element buffer must be an unsigned integral type. See {nameof(DrawElementsType)} enum for valid types."); } elementType = ValidElementTypes[vbos[i].PointerType]; } continue; } // According to OGL spec then, if there is no location for an attribute, -1 is returned. // The same error representation is used here. int loc = program[vbos[i].Name]?.Location ?? -1; if (loc == -1) { throw new Exception(string.Format("Shader did not contain '{0}'.", vbos[i].Name)); } Gl.EnableVertexAttribArray((uint)loc); Gl.BindBuffer(vbos[i].BufferTarget, vbos[i].ID); if (vbos[i].CastToFloat) { Gl.VertexAttribPointer((uint)loc, vbos[i].Size, vbos[i].PointerType, vbos[i].Normalize, 0, IntPtr.Zero); } else if (vbos[i].IsIntegralType) { Gl.VertexAttribIPointer((uint)loc, vbos[i].Size, vbos[i].PointerType, 0, IntPtr.Zero); } else if (vbos[i].PointerType == VertexAttribPointerType.Double) { Gl.VertexAttribLPointer((uint)loc, vbos[i].Size, vbos[i].PointerType, 0, IntPtr.Zero); } else { throw new Exception("VBO shouldn't be cast to float, isn't an integral type and is not a float. No vertex attribute support this combination."); } // 0 is the divisors default value. // No need to set the divisor to its default value. if (vbos[i].Divisor != 0) { Gl.VertexAttribDivisor((uint)loc, vbos[i].Divisor); } } if (elementArray != null) { Gl.BindBuffer(BufferTarget.ElementArrayBuffer, elementArray.ID); VertexCount = elementArray.Length; } }