from ctypes import c_void_p
from itertools import chain
from OpenGL import GL
from OpenGL.arrays import vbo
from OpenGL.GL.ARB.vertex_array_object import glBindVertexArray
from OpenGLContext.arrays import array
from ..color import Color
from ..util.gl_wrap import glGenVertexArray
from ..geom.vector import Vector
type_to_enum = {
GL.GLubyte: GL.GL_UNSIGNED_BYTE,
GL.GLushort: GL.GL_UNSIGNED_SHORT,
GL.GLuint: GL.GL_UNSIGNED_INT,
}
def get_index_type(num_verts):
[docs] '''
Return the unsigned integer data type required to store the given number.
e.g. 255 can be stored in a GLubyte, whereas 256 rrequires a GLushort.
'''
if num_verts < 256:
return GL.GLubyte
elif num_verts < 65536:
return GL.GLushort
else:
return GL.GLuint
def glarray(gltype, seq, length):
[docs] '''
Convert a list of lists into a flattened ctypes array, eg:
[ (1, 2, 3), (4, 5, 6) ] -> (GLfloat*6)(1, 2, 3, 4, 5, 6)
'''
carray = (gltype * length)()
carray[:] = seq
return carray
class Glyph(object):
[docs] '''
Passed iterables of vertex positions, colors, normals and indices,
converts them into ctypes arrays, stores them in a VBO, and then
creates a VAO that can be used to bind them later for rendering.
.. function:: __init__(num_verts, verts, colors, normals, indices)
'''
# currently we only support a single shader used to render the
# whole scene
shader = None
def __init__(self, num_verts, verts, colors, normals, indices):
[docs] self.num_glverts = num_verts
self.vbo = vbo.VBO(
array(
list(
list(chain(v, c.as_floats(), n))
for v, c, n in zip(verts, colors, normals)
),
'f'
),
usage='GL_STATIC_DRAW'
)
index_type = get_index_type(num_verts)
self.glindices = glarray(index_type, indices, len(indices))
self.index_type = type_to_enum[index_type]
self.vao = glGenVertexArray()
glBindVertexArray(self.vao)
try:
self.vbo.bind()
GL.glEnableVertexAttribArray(self.shader.attrib['position'])
GL.glEnableVertexAttribArray(self.shader.attrib['color'])
GL.glEnableVertexAttribArray(self.shader.attrib['normal'])
STRIDE = 40
GL.glVertexAttribPointer(
Glyph.shader.attrib['position'], Vector.COMPONENTS, GL.GL_FLOAT,
False, STRIDE, c_void_p(0)
)
GL.glVertexAttribPointer(
Glyph.shader.attrib['color'], Color.COMPONENTS, GL.GL_FLOAT,
False, STRIDE, c_void_p(12)
)
GL.glVertexAttribPointer(
Glyph.shader.attrib['normal'], Vector.COMPONENTS, GL.GL_FLOAT,
False, STRIDE, c_void_p(28)
)
finally:
glBindVertexArray(0)
def __repr__(self):
return '<Glyph %x %d verts>' % (id(self), self.num_glverts,)