glBufferDataに数字のlistを渡す場合以下のように渡せるがどうゆう実装なのか。

vertices=[0, 1, 2] # x, y, z

glBufferData(GL_ARRAY_BUFFER, 
        len(vertices)*4,  # byte size
        (ctypes.c_float*len(vertices))(*vertices), # 謎のctypes
        GL_STATIC_DRAW)

非常に読み辛かったがVisualStudioでステップ実行して動きを追ってみた。

# site-packages/OpenGL/GL/VERSION/GL_1_5.py
@_lazy( glBufferData )
def glBufferData( baseOperation, target, size, data=None, usage=None ):
    """Copy given data into the currently bound vertex-buffer-data object

    target -- the symbolic constant indicating which buffer type is intended
    size -- if provided, the count-in-bytes of the array
    data -- data-pointer to be used, may be None to initialize without
        copying over a data-set
    usage -- hint to the driver as to how to set up access to the buffer

    Note: parameter "size" can be omitted, which makes the signature
        glBufferData( target, data, usage )
    instead of:
        glBufferData( target, size, data, usage )
    """
    if usage is None:
        usage = data
        data = size
        size = None
    data = ArrayDatatype.asArray( data ) # <- ここでPythonの型をOpenGLに渡せるように変換
    if size is None:
        size = ArrayDatatype.arrayByteCount( data )
    return baseOperation( target, size, data, usage )

難関。デバッガ無しでは追えませんでした。

# site-packages/OpenGL/arrays/arraydatatype.py
class HandlerRegistry( dict ):
    def __init__( self, plugin_match ):
        self.match = plugin_match

    def __call__( self, value ): # 4
        """Lookup of handler for given value"""
        try:
            typ = value.__class__
        except AttributeError as err:
            typ = type(value)
        handler = self.get( typ )
        if not handler:
            if hasattr( typ, '__mro__' ):
                for base in typ.__mro__:
                    handler = self.get( base )
                    if not handler:
                        handler = self.match( base ) # 5
                        if handler:
                            handler = handler.load()
                            if handler:
                                handler = handler()
                    if handler:
                        self[ typ ] = handler
                        if hasattr( handler, 'registerEquivalent' ):
                            handler.registerEquivalent( typ, base )
                        return handler
            raise TypeError(
                    """No array-type handler for type %s.%s (value: %s) registered"""%(
                        typ.__module__, type.__name__, repr(value)[:50]
                        )
                    )
            return handler

GLOBAL_REGISTRY = HandlerRegistry(
    plugins.FormatHandler.match # 6 -> plugins.pyに進む
    ) # 3
class ArrayDatatype( object ):
    getHandler = GLOBAL_REGISTRY.__call__ # 2
    def asArray( cls, value, typeCode=None ): # 0 <- glBufferDataから呼ばれる
        """Given a value, convert to preferred array representation"""
        return cls.getHandler(value).asArray( value, typeCode or cls.typeConstant ) # 1
    asArray = classmethod( logs.logOnFail( asArray, _log ) )
# site-packages/OpenGL/plugins.py
class Plugin( object ):
    """Base class for plugins to be loaded"""
    loaded = False
    def __init__( self, name, import_path, check = None, **named ):
        """Register the plug-in"""
        self.registry.append( self ) # <-  FormatHandlerのインスタンスが登録される

class FormatHandler( Plugin ):
    """Data-type storage-format handler"""
    registry = [] # <- OpenGL/__init__.pyで初期化される
    @classmethod
    def match( cls, value ): # 7
        """Lookup appropriate handler based on value (a type)"""
        key = '%s.%s'%( value.__module__, value.__name__ )
        for plugin in cls.registry: # <- ここにハンドラのリストがある
            set = getattr( plugin, 'check', ())
            if set and key in set:
                return plugin
        return None

これらがimport時にFormatHandlerとして登録される。

# site-packages/OpenGL/__init__.py
FormatHandler( 'none', 'OpenGL.arrays.nones.NoneHandler', [ _bi+'.NoneType'],isOutput=False )

if sys.version_info[0] < 3:
    FormatHandler( 'str', 'OpenGL.arrays.strings.StringHandler',[_bi+'.str'], isOutput=False )
    FormatHandler( 'unicode', 'OpenGL.arrays.strings.UnicodeHandler',[_bi+'.unicode'], isOutput=False )
else:
    FormatHandler( 'bytes', 'OpenGL.arrays.strings.StringHandler',[_bi+'.bytes'], isOutput=False )
    FormatHandler( 'str', 'OpenGL.arrays.strings.UnicodeHandler',[_bi+'.str'], isOutput=False )
    
FormatHandler( 'list', 'OpenGL.arrays.lists.ListHandler', [
    _bi+'.list',
    _bi+'.tuple',
], isOutput=False )
FormatHandler( 'numbers', 'OpenGL.arrays.numbers.NumberHandler', [
    _bi+'.int',
    _bi+'.float',
    _bi+'.long',
], isOutput=False )
FormatHandler(
    'ctypesarrays', 'OpenGL.arrays.ctypesarrays.CtypesArrayHandler',
    [
        '_ctypes.ArrayType',
        '_ctypes.PyCArrayType',
        '_ctypes.Array',
        '_ctypes.array.Array',
    ],
    isOutput=True,
)
FormatHandler(
    'ctypesparameter',
    'OpenGL.arrays.ctypesparameters.CtypesParameterHandler',
    [
        _bi+'.CArgObject',
        'ctypes.c_uint',
        'ctypes.c_int',
        'ctypes.c_float',
        'ctypes.c_double',
        'ctypes.c_ulong',
        'ctypes.c_long',
        'ctypes.c_longlong',
    ],
    isOutput=True,
)
FormatHandler( 'ctypespointer', 'OpenGL.arrays.ctypespointers.CtypesPointerHandler',[
    'ctypes.c_void_p',
    '_ctypes._Pointer',
    'ctypes.c_char_p',
    '_ctypes.pointer._Pointer',
],isOutput=False )
FormatHandler( 'numpy', 'OpenGL.arrays.numpymodule.NumpyHandler', [
    'numpy.ndarray',
    'numpy.core.memmap.memmap',
],isOutput=True )
FormatHandler( 'buffer', 'OpenGL.arrays.buffers.BufferHandler', [
    'OpenGL.arrays._buffers.Py_buffer',
    _bi+'.memoryview',
    _bi+'.bytearray',
],isOutput=True )
FormatHandler( 'vbo', 'OpenGL.arrays.vbo.VBOHandler', ['OpenGL.arrays.vbo.VBO','OpenGL_accelerate.vbo.VBO'],isOutput=False )
FormatHandler( 'vbooffset', 'OpenGL.arrays.vbo.VBOOffsetHandler', ['OpenGL.arrays.vbo.VBOOffset','OpenGL_accelerate.vbo.VBOOffset'],isOutput=False )

numpyとか定義されているね。なるほど。

(ctypes.c_float*len(vertices))(*vertices)ctypes.c_float にマッチして、CtypesArrayHandler によって処理される。 一方、単なるPythonのlistであるverticesは、OpenGL.arrays.lists.ListHandler によって処理されて NotImplementedError に落ちるのであった。

class ListHandler( formathandler.FormatHandler ):
    @classmethod
    def asArray( cls, value, typeCode=None ):
        """Convert given value to a ctypes array value of given typeCode
        
        This does a *lot* of work just to get the data into the correct
        format.  It's not going to be anywhere near as fast as a numpy
        or similar approach!
        """
        if typeCode is None:
            raise NotImplementedError( """Haven't implemented type-inference for lists yet""" )

確かにlistだと中身の型が決められんね。なるほど。