protected void BindVertexElementToGpu(VertexElement elem, HardwareVertexBuffer vertexBuffer, int vertexStart,
IList <int> attribsBound, IList <int> instanceAttribsBound)
{
IntPtr pBufferData;
var hwGlBuffer = (GLHardwareVertexBuffer)vertexBuffer;
if (currentCapabilities.HasCapability(Graphics.Capabilities.VertexBuffer))
{
Gl.glBindBufferARB(Gl.GL_ARRAY_BUFFER_ARB, hwGlBuffer.GLBufferID);
pBufferData = BUFFER_OFFSET(elem.Offset);
}
else
{
// ReSharper disable PossibleInvalidCastException
pBufferData = ((GLDefaultHardwareVertexBuffer)(vertexBuffer)).DataPtr(elem.Offset);
// ReSharper restore PossibleInvalidCastException
}
if (vertexStart != 0)
{
pBufferData = pBufferData.Offset(vertexStart * vertexBuffer.VertexSize);
}
var sem = elem.Semantic;
var multitexturing = Capabilities.TextureUnitCount > 1;
var isCustomAttrib = false;
if (this.currentVertexProgram != null)
{
isCustomAttrib = this.currentVertexProgram.IsAttributeValid(sem, (uint)elem.Index);
if (hwGlBuffer.IsInstanceData)
{
var attrib = this.currentVertexProgram.AttributeIndex(sem, (uint)elem.Index);
glVertexAttribDivisor((int)attrib, hwGlBuffer.InstanceDataStepRate);
instanceAttribsBound.Add((int)attrib);
}
}
// Custom attribute support
// tangents, binormals, blendweights etc always via this route
// builtins may be done this way too
if (isCustomAttrib)
{
var attrib = this.currentVertexProgram.AttributeIndex(sem, (uint)elem.Index);
var typeCount = VertexElement.GetTypeCount(elem.Type);
var normalised = Gl.GL_FALSE;
switch (elem.Type)
{
case VertexElementType.Color:
case VertexElementType.Color_ABGR:
case VertexElementType.Color_ARGB:
// Because GL takes these as a sequence of single unsigned bytes, count needs to be 4
// VertexElement::getTypeCount treats them as 1 (RGBA)
// Also need to normalise the fixed-point data
typeCount = 4;
normalised = Gl.GL_TRUE;
break;
default:
break;
}
Gl.glVertexAttribPointerARB(attrib, typeCount, GLHardwareBufferManager.GetGLType(elem.Type), normalised,
vertexBuffer.VertexSize, pBufferData);
Gl.glEnableVertexAttribArrayARB(attrib);
attribsBound.Add((int)attrib);
}
else
{
// fixed-function & builtin attribute support
switch (sem)
{
case VertexElementSemantic.Position:
Gl.glVertexPointer(VertexElement.GetTypeCount(elem.Type), GLHardwareBufferManager.GetGLType(elem.Type),
vertexBuffer.VertexSize, pBufferData);
Gl.glEnableClientState(Gl.GL_VERTEX_ARRAY);
break;
case VertexElementSemantic.Normal:
Gl.glNormalPointer(GLHardwareBufferManager.GetGLType(elem.Type), vertexBuffer.VertexSize, pBufferData);
Gl.glEnableClientState(Gl.GL_NORMAL_ARRAY);
break;
case VertexElementSemantic.Diffuse:
Gl.glColorPointer(4, GLHardwareBufferManager.GetGLType(elem.Type), vertexBuffer.VertexSize, pBufferData);
Gl.glEnableClientState(Gl.GL_COLOR_ARRAY);
break;
case VertexElementSemantic.Specular:
if (this.GLEW_EXT_secondary_color)
{
Gl.glSecondaryColorPointerEXT(4, GLHardwareBufferManager.GetGLType(elem.Type), vertexBuffer.VertexSize,
pBufferData);
Gl.glEnableClientState(Gl.GL_SECONDARY_COLOR_ARRAY);
}
break;
case VertexElementSemantic.TexCoords:
if (this.currentVertexProgram != null)
{
// Programmable pipeline - direct UV assignment
Gl.glClientActiveTextureARB(Gl.GL_TEXTURE0 + elem.Index);
Gl.glTexCoordPointer(VertexElement.GetTypeCount(elem.Type), GLHardwareBufferManager.GetGLType(elem.Type),
vertexBuffer.VertexSize, pBufferData);
Gl.glEnableClientState(Gl.GL_TEXTURE_COORD_ARRAY);
}
else
{
// fixed function matching to units based on tex_coord_set
for (var i = 0; i < disabledTexUnitsFrom; i++)
{
// Only set this texture unit's texcoord pointer if it
// is supposed to be using this element's index
if (this.texCoordIndex[i] != elem.Index || i >= this._fixedFunctionTextureUnits)
{
continue;
}
if (multitexturing)
{
Gl.glClientActiveTextureARB(Gl.GL_TEXTURE0 + i);
}
Gl.glTexCoordPointer(VertexElement.GetTypeCount(elem.Type), GLHardwareBufferManager.GetGLType(elem.Type),
vertexBuffer.VertexSize, pBufferData);
Gl.glEnableClientState(Gl.GL_TEXTURE_COORD_ARRAY);
}
}
break;
default:
break;
}
} // isCustomAttrib
}