I've been looking for another solution that doesn't swap out code in
pyglet.graphics, and doesn't break the vertex list interface for
existing layers, like pyglet.sprite.

Here's another version that uses a subclassed Batch to return custom
VertexList and IndexedVertexList objects that support numpy arrays for
vertex attributes. The numpy arrays are made available though an
attribute 'n' of the vertex list (i.e vlist.n.vertices instead of
vlist.vertices) so it doesn't change the existing interface.

    >>> b = nverts2.Batch()
    >>> v = b.add(4, 0, None, 'v3f')
    # normal c_array access
    >>> v.vertices[:]
    # numpy ndarray access
    >>> v.n.vertices

Any one have thoughts on designing an interface to Numpy ndarray views
with pyglet.graphics?

--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"pyglet-users" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/pyglet-users?hl=en
-~----------~----~----~----~------~----~------~--~---

"""
Numpy array integration with pyglet.graphics.
"""

import numpy
import ctypes

import pyglet
from pyglet.graphics import vertexdomain


ctypes.pythonapi.PyBuffer_FromReadWriteMemory.restype = ctypes.py_object


def as_numpy_array(c_array):
    """
    Return a view of the c array as a numpy array, with the
    underlying memory shared.
    """
    return numpy.frombuffer(
        ctypes.pythonapi.PyBuffer_FromReadWriteMemory(
                c_array, ctypes.sizeof(c_array._type_) * len(c_array)),
        dtype=c_array._type_)


class Batch(pyglet.graphics.Batch):
    __doc__ = pyglet.graphics.Batch.__doc__
    
    def add(self, count, mode, group, *data):
        formats, initial_arrays = pyglet.graphics._parse_data(data)
        domain = self._get_domain(False, mode, group, formats)
        domain.__formats = formats
            
        # Create vertex list and initialize
        start = domain._safe_alloc(count)
        vlist = VertexList(domain, start, count)
        for i, array in initial_arrays:
            vlist._set_attribute_data(i, array)

        return vlist
    add.__doc__ = pyglet.graphics.Batch.add.__doc__

    def add_indexed(self, count, mode, group, indices, *data):
        formats, initial_arrays = pyglet.graphics._parse_data(data)
        domain = self._get_domain(True, mode, group, formats)
            
        # Create vertex list and initialize
        start = domain._safe_alloc(count)
        index_start = domain._safe_index_alloc(len(indices))
        vlist = IndexedVertexList(
            domain, start, count, index_start, len(indices))
        vlist._set_index_data(map(lambda i: i + start, indices))
        for i, array in initial_arrays:
            vlist._set_attribute_data(i, array)

        return vlist
    add_indexed.__doc__ = pyglet.graphics.Batch.add_indexed.__doc__


class Nviews(object):
    """
    Container for accessing vertex attributes as Numpy ndarrays.
    """
    def __init__(self, vertexlist):
        self._vlist = vertexlist
    
    def _get_shaped_array(self, attribute_name):
        """
        Shapes and transposes the arrays retrieved by the
        vertexattribute property descriptors to reflect the
        vertex/attribute counts.
        """
        array = getattr(self._vlist, '_get_%s' % attribute_name)()
        region = getattr(self._vlist, '_%s_cache' % attribute_name)

        if not hasattr(region, 'ndarray'):
            count = self._vlist.domain.attribute_names[attribute_name].count
            ndarray = as_numpy_array(array)
            ndarray.shape = (len(array) / count, count)
            ndarray = ndarray.transpose()
            region = getattr(self._vlist, '_%s_cache' % attribute_name)
            region.ndarray = ndarray

        return region.ndarray

    def _get_colors(self):
        return self._get_shaped_array('colors')

    def _get_fog_coords(self):
        return self._get_shaped_array('fog_coords')

    def _get_edge_flags(self):
        return self._get_shaped_array('edge_flags')

    def _get_normals(self):
        return self._get_shaped_array('normals')

    def _get_secondary_colors(self):
        return self._get_shaped_array('secondary_colors')

    def _get_tex_coords(self):
        return self._get_shaped_array('tex_coords')

    def _get_vertices(self):
        return self._get_shaped_array('vertices')

    colors = property(
        _get_colors, vertexdomain.VertexList._set_colors,
        doc=vertexdomain.VertexList.colors.__doc__)

    fog_coords = property(
        _get_fog_coords, vertexdomain.VertexList._set_fog_coords,
        doc=vertexdomain.VertexList.fog_coords.__doc__)

    edge_flags = property(
        _get_edge_flags, vertexdomain.VertexList._set_edge_flags,
        doc=vertexdomain.VertexList.edge_flags.__doc__)

    normals = property(
        _get_normals, vertexdomain.VertexList._set_normals,
        doc=vertexdomain.VertexList.normals.__doc__)

    tex_coords = property(
        _get_tex_coords, vertexdomain.VertexList._set_tex_coords,
        doc=vertexdomain.VertexList.tex_coords.__doc__)

    vertices = property(
        _get_vertices, vertexdomain.VertexList._set_vertices,
        doc=vertexdomain.VertexList.vertices.__doc__)


class VertexList(vertexdomain.VertexList):
    __doc__ = vertexdomain.VertexList.__doc__
    
    def __init__(self, domain, start, count):
        super(VertexList, self).__init__(domain, start, count)
        self._n = Nviews(self)

    n = property(lambda self: self._n)


class IndexedVertexList(VertexList, vertexdomain.IndexedVertexList):
    __doc__ = vertexdomain.IndexedVertexList.__doc__
    
    def __init__(self, domain, start, count, index_start, index_count):
        vertexdomain.IndexedVertexList.__init__(
            self, domain, start, count, index_start, index_count)
        self._n = Nviews(self)

Reply via email to