/// <inheritdoc/> public override void Attach(IndexBuffer ibuffer) { Contract.Require(ibuffer, nameof(ibuffer)); Contract.EnsureNot(HasIndices, UltravioletStrings.GeometryStreamAlreadyHasIndices); Contract.EnsureNotDisposed(this, Disposed); Ultraviolet.ValidateResource(ibuffer); var sdlIndexBuffer = (OpenGLIndexBuffer)ibuffer; var sdlIndexBufferName = sdlIndexBuffer.OpenGLName; this.ibuffer = sdlIndexBuffer; if (IsUsingVertexArrayObject) { using (OpenGLState.ScopedBindVertexArrayObject(vao, 0, 0, true)) { gl.BindBuffer(gl.GL_ELEMENT_ARRAY_BUFFER, sdlIndexBufferName); gl.ThrowIfError(); } } this.glElementArrayBufferBinding = sdlIndexBufferName; this.indexBufferElementType = ibuffer.IndexElementType; }
/// <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 new API. /// </summary> private unsafe void BindVertexAttributesForBuffer_NewAPI(OpenGLVertexBuffer vbuffer, UInt32 binding, UInt32 frequency, UInt32?program, UInt32?offset) { var caps = Ultraviolet.GetGraphics().Capabilities; using (OpenGLState.ScopedBindVertexArrayObject(vao, glElementArrayBufferBinding ?? 0)) { if (program.HasValue || offset.HasValue) { gl.VertexArrayVertexBuffer(vao, binding, vbuffer.OpenGLName, (IntPtr)(offset ?? 0), vbuffer.VertexDeclaration.VertexStride); gl.ThrowIfError(); } if (program.HasValue) { gl.VertexArrayBindingDivisor(vao, binding, frequency); gl.ThrowIfError(); var position = 0u; 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) { gl.VertexArrayAttribBinding(vao, location, binding); gl.ThrowIfError(); gl.EnableVertexArrayAttrib(vao, location); gl.ThrowIfError(); unsafe { switch (category) { case OpenGLAttribCategory.Single: { gl.VertexArrayAttribFormat(vao, location, size, type, normalize, position); gl.ThrowIfError(); } break; case OpenGLAttribCategory.Double: { if (!caps.SupportsDoublePrecisionVertexAttributes) { throw new NotSupportedException(); } gl.VertexArrayAttribLFormat(vao, location, size, type, position); gl.ThrowIfError(); } break; case OpenGLAttribCategory.Integer: { if (!caps.SupportsIntegerVertexAttributes) { throw new NotSupportedException(); } gl.VertexArrayAttribIFormat(vao, location, size, type, position); gl.ThrowIfError(); } break; } } } position += (uint)stride; } } } }