
"Particle systems using numpy."

from __future__ import with_statement

import OpenGL.GL as gl
import OpenGL.arrays.vbo as vbo

import glitch

class ParticleSystem(glitch.Node):
    def __init__(self, size, **kw):
        glitch.Node.__init__(self, **kw)

        self.size = size
        # make_particles() should return a numpy array has the shape (size,
        # 10), where 10 is the number of fields (x, y, z, dx, dy, dz, ddz,
        # ddy, ddz, ttl).
        self.particles = self.make_particles(size)
        assert self.particles is not None

    def step(self, amount):
        a = self.particles
        a[:,0:3] += amount * a[:,3:6]
        self.accelerate(amount)
        a[:,9] -= amount

        # replace dead particles
        dead = a[:,9] < 0
        a[dead,:] = self.make_particles(len(a[dead,:]))

    def accelerate(self, amount):
        a = self.particles
        a[:,3:6] += amount * a[:,6:9]

    def draw(self, ctx):
        # In principle, we should just have one VBO and update it on each
        # draw, but it doesn't seem to be any faster in practice.
        buffer = vbo.VBO(self.particles)
        buffer.bind()
        gl.glEnableClientState(gl.GL_VERTEX_ARRAY)
        # Three coordinates per vertex, with a stride of sizeof(float) * the
        # number of fields.
        gl.glVertexPointer(3, gl.GL_FLOAT, 40, buffer)
        gl.glDrawArrays(gl.GL_POINTS, 0, self.size)
        gl.glDisableClientState(gl.GL_VERTEX_ARRAY)
        buffer.unbind()

