/// <summary> /// Binds the geometry stream's buffers to the device in preparation for rendering. /// </summary> private void BindBuffers(UInt32?program, UInt32?offset) { unsafe { var previousBuffer = (uint)OpenGLState.GL_ARRAY_BUFFER_BINDING; if (IsUsingVertexArrayObject) { using (OpenGLState.ScopedBindVertexArrayObject(vao, glElementArrayBufferBinding ?? 0, force: !gl.IsVertexAttribBindingAvailable)) { if (program.HasValue) { DisableVertexAttributesOnCachedProgram(); } if (gl.IsVertexAttribBindingAvailable) { for (int i = 0; i < vbuffers.Count; i++) { var binding = vbuffers[i]; BindVertexAttributesForBuffer_NewAPI(binding.VertexBuffer, (UInt32)i, (UInt32)binding.InstanceFrequency, program, offset); } } else { for (int i = 0; i < vbuffers.Count; i++) { var binding = vbuffers[i]; BindVertexAttributesForBuffer_OldAPI(binding.VertexBuffer, (UInt32)i, (UInt32)binding.InstanceFrequency, program, offset); } } } } else { if (program.HasValue) { DisableVertexAttributesOnCachedProgram(); } for (int i = 0; i < vbuffers.Count; i++) { var binding = vbuffers[i]; BindVertexAttributesForBuffer_OldAPI(binding.VertexBuffer, (UInt32)i, (UInt32)binding.InstanceFrequency, program, offset); } OpenGLState.BindArrayBuffer(previousBuffer); } } }
/// <summary> /// Binds the specified buffer's vertex attributes to the currently cached program using the old API. /// </summary> private unsafe void BindVertexAttributesForBuffer_OldAPI(OpenGLVertexBuffer vbuffer, UInt32 binding, UInt32 frequency, UInt32?program, UInt32?offset) { OpenGLState.BindArrayBuffer(vbuffer.OpenGLName); var position = offset ?? this.offset; var caps = Ultraviolet.GetGraphics().Capabilities; foreach (var element in vbuffer.VertexDeclaration) { var name = GetVertexAttributeNameFromUsage(element.Usage, element.Index); var size = 0; var stride = 0; var normalize = false; var type = GetVertexFormatGL(element.Format, out size, out stride, out normalize); var category = OpenGLAttribCategory.Single; var location = (UInt32)OpenGLState.CurrentProgram.GetAttribLocation(name, out category); if (location >= 0) { if (program.HasValue) { if (gl.IsGLES2) { if (frequency != 0) { throw new NotSupportedException(); } } else { gl.VertexAttribDivisor(location, frequency); gl.ThrowIfError(); } gl.EnableVertexAttribArray(location); gl.ThrowIfError(); } switch (category) { case OpenGLAttribCategory.Single: { gl.VertexAttribPointer(location, size, type, normalize, vbuffer.VertexDeclaration.VertexStride, (void *)(position)); gl.ThrowIfError(); } break; case OpenGLAttribCategory.Double: { if (!caps.SupportsDoublePrecisionVertexAttributes) { throw new NotSupportedException(); } gl.VertexAttribLPointer(location, size, type, vbuffer.VertexDeclaration.VertexStride, (void *)(position)); gl.ThrowIfError(); } break; case OpenGLAttribCategory.Integer: { if (!caps.SupportsIntegerVertexAttributes) { throw new NotSupportedException(); } gl.VertexAttribIPointer(location, size, type, vbuffer.VertexDeclaration.VertexStride, (void *)(position)); gl.ThrowIfError(); } break; } } position += (uint)stride; } }