
from __future__ import with_statement

import numpy
import gobject

import OpenGL.GL as gl

import glitch, glitch.gtk
from glitch.limbo.lights import LightSwitch, AmbientLight
from glitch.limbo.material import Material
from glitch.limbo.particles import ParticleSystem

class Fountain(ParticleSystem):
    def make_particles(self, n):
        a = numpy.ndarray(shape=(n, 10), dtype=numpy.float32)
        # particles start at origin
        a[:,0:3] = 0
        # velocities
        a[:,3] = numpy.random.normal(0, 0.02, n) * 4
        a[:,4] = numpy.random.uniform(0.1, 0.3, n) * 4
        a[:,5] = numpy.random.normal(0, 0.02, n) * 4
        # accelerations
        a[:,6] = 0
        a[:,7] = -0.1
        a[:,8] = 0
        # time to live
        a[:,9] = numpy.random.uniform(1, 20, n)
        return a

class Fire(ParticleSystem):
    def make_particles(self, n):
        a = numpy.ndarray(shape=(n, 10), dtype=numpy.float32)
        # position
        a[:,0] = numpy.random.uniform(-0.4, 0.4)
        a[:,1] = 0
        a[:,2] = numpy.random.uniform(-0.4, 0.4)
        # velocities
        a[:,3] = numpy.random.normal(0, 0.04, n) * 4
        a[:,4] = numpy.random.uniform(0.1, 0.2, n) * 1
        a[:,5] = numpy.random.normal(0, 0.04, n) * 4
        # accelerations
        a[:,6] = 0.9
        a[:,7] = 1.2
        a[:,8] = 0.9
        # time to live
        a[:,9] = numpy.random.uniform(1, 10, n)
        return a

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

def tick():
    fountain.step(0.1)
    fire.step(0.1)
    camera.refresh()
    return True

def set_point_size(widget):
    with camera:
        gl.glPointSize(2)

if __name__ == '__main__':
    fountain = Fountain(1000)
    fire = Fire(1000)
    camera = glitch.gtk.GtkCamera(ref=[0, 4, 0], eye=[0, 4, 10], children=[
        LightSwitch(children=[
            AmbientLight(children=[
                glitch.Translate(-4, children=[
                    glitch.Scale(0.7, 0.7, 0.7, children=[
                        Material(0.3, 0.5, 1.0, children=[fountain])]),
                glitch.Translate(4, children=[
                    glitch.Scale(0.7, 0.7, 0.7, children=[
                        Material(1.0, 0.3, 0.3,
                            children=[fire])])])])])])])
    camera.connect_after('realize', set_point_size)

    gobject.timeout_add(1000/30, tick)
    camera.run()

