from pandac.PandaModules import *

from pandac.PandaModules import ParticleSystem
from pandac.PandaModules import BaseParticleFactory
from pandac.PandaModules import PointParticleFactory
from pandac.PandaModules import ZSpinParticleFactory
#from pandac.PandaModules import OrientedParticleFactory
from pandac.PandaModules import BaseParticleRenderer
from pandac.PandaModules import PointParticleRenderer
from pandac.PandaModules import LineParticleRenderer
from pandac.PandaModules import GeomParticleRenderer
from pandac.PandaModules import SparkleParticleRenderer
#from pandac.PandaModules import SpriteParticleRenderer
from pandac.PandaModules import BaseParticleEmitter
from pandac.PandaModules import ArcEmitter
from pandac.PandaModules import BoxEmitter
from pandac.PandaModules import DiscEmitter
from pandac.PandaModules import LineEmitter
from pandac.PandaModules import PointEmitter
from pandac.PandaModules import RectangleEmitter
from pandac.PandaModules import RingEmitter
from pandac.PandaModules import SphereSurfaceEmitter
from pandac.PandaModules import SphereVolumeEmitter
from pandac.PandaModules import TangentRingEmitter

import SpriteParticleRendererExt

import string
import os
from direct.directnotify.DirectNotifyGlobal import directNotify
import sys

class Particles(ParticleSystem):
    notify = directNotify.newCategory('Particles')
    id = 1

    def __init__(self, name=None, poolSize=1024):
        if (name == None):
            self.name = 'particles-%d' % Particles.id
            Particles.id += 1
        else:
            self.name = name
        ParticleSystem.__init__(self, poolSize)
        # self.setBirthRate(0.02)
        # self.setLitterSize(10)
        # self.setLitterSpread(0)

        # Set up a physical node
        self.node = PhysicalNode(self.name)
        self.nodePath = NodePath(self.node)
        self.setRenderParent(self.node)
        self.node.addPhysical(self)

        self.factory = None
        self.factoryType = "undefined"
        # self.setFactory("PointParticleFactory")
        self.renderer = None
        self.rendererType = "undefined"
        # self.setRenderer("PointParticleRenderer")
        self.emitter = None
        self.emitterType = "undefined"
        # self.setEmitter("SphereVolumeEmitter")

        # Enable particles by default
        self.fEnabled = 0
        #self.enable()
        self.geomReference = ""

    def cleanup(self):
        self.disable()
        self.clearLinearForces()
        self.clearAngularForces()
        self.setRenderParent(self.node)
        self.node.removePhysical(self)
        self.nodePath.removeNode()
        del self.node
        del self.nodePath
        del self.factory
        del self.renderer
        del self.emitter

    def enable(self):
        if (self.fEnabled == 0):
            base.physicsMgr.attachPhysical(self)
            base.particleMgr.attachParticlesystem(self)
            self.fEnabled = 1

    def disable(self):
        if (self.fEnabled == 1):
            base.physicsMgr.removePhysical(self)
            base.particleMgr.removeParticlesystem(self)
            self.fEnabled = 0

    def isEnabled(self):
        return self.fEnabled

    def getNode(self):
        return self.node

    def setFactory(self, type):
        if (self.factoryType == type):
            return None
        if (self.factory):
            self.factory = None
        self.factoryType = type
        if (type == "PointParticleFactory"):
            self.factory = PointParticleFactory()
        elif (type == "ZSpinParticleFactory"):
            self.factory = ZSpinParticleFactory()
        elif (type == "OrientedParticleFactory"):
            self.factory = OrientedParticleFactory()
        else:
            print "unknown factory type: %s" % type
            return None
        self.factory.setLifespanBase(0.5)
        ParticleSystem.setFactory(self, self.factory)

    def setRenderer(self, type):
        if (self.rendererType == type):
            return None
        if (self.renderer):
            self.renderer = None
        self.rendererType = type
        if (type == "PointParticleRenderer"):
            self.renderer = PointParticleRenderer()
            self.renderer.setPointSize(1.0)
        elif (type == "LineParticleRenderer"):
            self.renderer = LineParticleRenderer()
        elif (type == "GeomParticleRenderer"):
            self.renderer = GeomParticleRenderer()
            # This was moved here because we do not want to download
            # the direct tools with toontown.
            if __dev__:
                from direct.directtools import DirectSelection
                npath = NodePath('default-geom')
                bbox = DirectSelection.DirectBoundingBox(npath)
                self.renderer.setGeomNode(bbox.lines.node())
        elif (type == "SparkleParticleRenderer"):
            self.renderer = SparkleParticleRenderer()
        elif (type == "SpriteParticleRenderer"):
            self.renderer = SpriteParticleRendererExt.SpriteParticleRendererExt()
            # self.renderer.setTextureFromFile()
        else:
            print "unknown renderer type: %s" % type
            return None
        ParticleSystem.setRenderer(self, self.renderer)

    def setEmitter(self, type):
        if (self.emitterType == type):
            return None
        if (self.emitter):
            self.emitter = None
        self.emitterType = type
        if (type == "ArcEmitter"):
            self.emitter = ArcEmitter()
        elif (type == "BoxEmitter"):
            self.emitter = BoxEmitter()
        elif (type == "DiscEmitter"):
            self.emitter = DiscEmitter()
        elif (type == "LineEmitter"):
            self.emitter = LineEmitter()
        elif (type == "PointEmitter"):
            self.emitter = PointEmitter()
        elif (type == "RectangleEmitter"):
            self.emitter = RectangleEmitter()
        elif (type == "RingEmitter"):
            self.emitter = RingEmitter()
        elif (type == "SphereSurfaceEmitter"):
            self.emitter = SphereSurfaceEmitter()
        elif (type == "SphereVolumeEmitter"):
            self.emitter = SphereVolumeEmitter()
            self.emitter.setRadius(1.0)
        elif (type == "TangentRingEmitter"):
            self.emitter = TangentRingEmitter()
        else:
            print "unknown emitter type: %s" % type
            return None
        ParticleSystem.setEmitter(self, self.emitter)

    def addForce(self, force):
        if (force.isLinear()):
            self.addLinearForce(force)
        else:
            self.addAngularForce(force)

    def removeForce(self, force):
        if (force == None):
            self.notify.warning('removeForce() - force == None!')
            return
        if (force.isLinear()):
            self.removeLinearForce(force)
        else:
            self.removeAngularForce(force)

    def setRenderNodePath(self, nodePath):
        self.setRenderParent(nodePath.node())

    ## Getters ##
    def getName(self):
        return self.name

    def getFactory(self):
        return self.factory

    def getEmitter(self):
        return self.emitter

    def getRenderer(self):
        return self.renderer

    def printParams(self, file = sys.stdout, targ = 'self'):
        file.write('# Particles parameters\n')
        file.write(targ + '.setFactory(\"' + self.factoryType + '\")\n')
        file.write(targ + '.setRenderer(\"' + self.rendererType + '\")\n')
        file.write(targ + '.setEmitter(\"' + self.emitterType + '\")\n')

        # System parameters
        file.write(targ + ('.setPoolSize(%d)\n' %
                           int(self.getPoolSize())))
        file.write(targ + ('.setBirthRate(%.4f)\n' %
                           self.getBirthRate()))
        file.write(targ + ('.setLitterSize(%d)\n' %
                           int(self.getLitterSize())))
        file.write(targ + ('.setLitterSpread(%d)\n' %
                           self.getLitterSpread()))
        file.write(targ + ('.setSystemLifespan(%.4f)\n' %
                           self.getSystemLifespan()))
        file.write(targ + ('.setLocalVelocityFlag(%d)\n' %
                           self.getLocalVelocityFlag()))
        file.write(targ + ('.setSystemGrowsOlderFlag(%d)\n' %
                           self.getSystemGrowsOlderFlag()))
        file.write('# Factory parameters\n')
        file.write(targ + ('.factory.setLifespanBase(%.4f)\n' %
                           self.factory.getLifespanBase()))
        file.write(targ + '.factory.setLifespanSpread(%.4f)\n' % \
                                self.factory.getLifespanSpread())
        file.write(targ + '.factory.setMassBase(%.4f)\n' % \
                                self.factory.getMassBase())
        file.write(targ + '.factory.setMassSpread(%.4f)\n' % \
                                self.factory.getMassSpread())
        file.write(targ + '.factory.setTerminalVelocityBase(%.4f)\n' % \
                                self.factory.getTerminalVelocityBase())
        file.write(targ + '.factory.setTerminalVelocitySpread(%.4f)\n' % \
                                self.factory.getTerminalVelocitySpread())
        if (self.factoryType == "PointParticleFactory"):
            file.write('# Point factory parameters\n')
        elif (self.factoryType == "ZSpinParticleFactory"):
            file.write('# Z Spin factory parameters\n')
            file.write(targ + '.factory.setInitialAngle(%.4f)\n' % \
                                        self.factory.getInitialAngle())
            file.write(targ + '.factory.setInitialAngleSpread(%.4f)\n' % \
                                        self.factory.getInitialAngleSpread())
            file.write(targ + '.factory.enableAngularVelocity(%d)\n' % \
                                        self.factory.getAngularVelocityEnabled())
            if(self.factory.getAngularVelocityEnabled()):
                file.write(targ + '.factory.setAngularVelocity(%.4f)\n' % \
                                            self.factory.getAngularVelocity())
                file.write(targ + '.factory.setAngularVelocitySpread(%.4f)\n' % \
                                            self.factory.getAngularVelocitySpread())
            else:
                file.write(targ + '.factory.setFinalAngle(%.4f)\n' % \
                                            self.factory.getFinalAngle())
                file.write(targ + '.factory.setFinalAngleSpread(%.4f)\n' % \
                                        self.factory.getFinalAngleSpread())

        elif (self.factoryType == "OrientedParticleFactory"):
            file.write('# Oriented factory parameters\n')
            file.write(targ + '.factory.setInitialOrientation(%.4f)\n' % \
                                        self.factory.getInitialOrientation())
            file.write(targ + '.factory.setFinalOrientation(%.4f)\n' % \
                                        self.factory.getFinalOrientation())

        file.write('# Renderer parameters\n')
        alphaMode = self.renderer.getAlphaMode()
        aMode = "PRALPHANONE"
        if (alphaMode == BaseParticleRenderer.PRALPHANONE):
            aMode = "PRALPHANONE"
        elif (alphaMode == BaseParticleRenderer.PRALPHAOUT):
            aMode = "PRALPHAOUT"
        elif (alphaMode == BaseParticleRenderer.PRALPHAIN):
            aMode = "PRALPHAIN"
        elif (alphaMode == BaseParticleRenderer.PRALPHAINOUT):
            aMode = "PRALPHAINOUT"
        elif (alphaMode == BaseParticleRenderer.PRALPHAUSER):
            aMode = "PRALPHAUSER"
        file.write(targ + '.renderer.setAlphaMode(BaseParticleRenderer.' + aMode + ')\n')
        file.write(targ + '.renderer.setUserAlpha(%.2f)\n' % \
                                        self.renderer.getUserAlpha())
        if (self.rendererType == "PointParticleRenderer"):
            file.write('# Point parameters\n')
            file.write(targ + '.renderer.setPointSize(%.2f)\n' % \
                                        self.renderer.getPointSize())
            sColor = self.renderer.getStartColor()
            file.write((targ + '.renderer.setStartColor(Vec4(%.2f, %.2f, %.2f, %.2f))\n' % (sColor[0], sColor[1], sColor[2], sColor[3])))
            sColor = self.renderer.getEndColor()
            file.write((targ + '.renderer.setEndColor(Vec4(%.2f, %.2f, %.2f, %.2f))\n' % (sColor[0], sColor[1], sColor[2], sColor[3])))
            blendType = self.renderer.getBlendType()
            bType = "PPONECOLOR"
            if (blendType == PointParticleRenderer.PPONECOLOR):
                bType = "PPONECOLOR"
            elif (blendType == PointParticleRenderer.PPBLENDLIFE):
                bType = "PPBLENDLIFE"
            elif (blendType == PointParticleRenderer.PPBLENDVEL):
                bType = "PPBLENDVEL"
            file.write(targ + '.renderer.setBlendType(PointParticleRenderer.' + bType + ')\n')
            blendMethod = self.renderer.getBlendMethod()
            bMethod = "PPNOBLEND"
            if (blendMethod == BaseParticleRenderer.PPNOBLEND):
                bMethod = "PPNOBLEND"
            elif (blendMethod == BaseParticleRenderer.PPBLENDLINEAR):
                bMethod = "PPBLENDLINEAR"
            elif (blendMethod == BaseParticleRenderer.PPBLENDCUBIC):
                bMethod = "PPBLENDCUBIC"
            file.write(targ + '.renderer.setBlendMethod(BaseParticleRenderer.' + bMethod + ')\n')
        elif (self.rendererType == "LineParticleRenderer"):
            file.write('# Line parameters\n')
            sColor = self.renderer.getHeadColor()
            file.write((targ + '.renderer.setHeadColor(Vec4(%.2f, %.2f, %.2f, %.2f))\n' % (sColor[0], sColor[1], sColor[2], sColor[3])))
            sColor = self.renderer.getTailColor()
            file.write((targ + '.renderer.setTailColor(Vec4(%.2f, %.2f, %.2f, %.2f))\n' % (sColor[0], sColor[1], sColor[2], sColor[3])))
            sf = self.renderer.getLineScaleFactor()
            file.write((targ + '.renderer.setLineScaleFactor(%.2f)\n' % (sf)))
        elif (self.rendererType == "GeomParticleRenderer"):
            file.write('# Geom parameters\n')
            node = self.renderer.getGeomNode()
            file.write('geomRef = loader.loadModel("' + self.geomReference + '")\n')
            file.write(targ + '.renderer.setGeomNode(geomRef.node())\n')
            file.write(targ + '.geomReference = "' + self.geomReference + '"\n');
            cbmLut = ('MNone','MAdd','MSubtract','MInvSubtract','MMin','MMax')
            cboLut = ('OZero','OOne','OIncomingColor','OOneMinusIncomingColor','OFbufferColor',
                      'OOneMinusFbufferColor','OIncomingAlpha','OOneMinusIncomingAlpha',
                      'OFbufferAlpha','OOneMinusFbufferAlpha','OConstantColor',
                      'OOneMinusConstantColor','OConstantAlpha','OOneMinusConstantAlpha',
                      'OIncomingColorSaturate')
            file.write(targ + '.renderer.setXScaleFlag(%d)\n' % self.renderer.getXScaleFlag())
            file.write(targ + '.renderer.setYScaleFlag(%d)\n' % self.renderer.getYScaleFlag())
            file.write(targ + '.renderer.setZScaleFlag(%d)\n' % self.renderer.getZScaleFlag())
            file.write(targ + '.renderer.setInitialXScale(%.4f)\n' % self.renderer.getInitialXScale())
            file.write(targ + '.renderer.setFinalXScale(%.4f)\n' % self.renderer.getFinalXScale())
            file.write(targ + '.renderer.setInitialYScale(%.4f)\n' % self.renderer.getInitialYScale())
            file.write(targ + '.renderer.setFinalYScale(%.4f)\n' % self.renderer.getFinalYScale())
            file.write(targ + '.renderer.setInitialZScale(%.4f)\n' % self.renderer.getInitialZScale())
            file.write(targ + '.renderer.setFinalZScale(%.4f)\n' % self.renderer.getFinalZScale())

            cbAttrib = self.renderer.getRenderNode().getAttrib(ColorBlendAttrib.getClassType())
            if(cbAttrib):
                cbMode = cbAttrib.getMode()
                if(cbMode > 0):
                    if(cbMode in (ColorBlendAttrib.MAdd, ColorBlendAttrib.MSubtract, ColorBlendAttrib.MInvSubtract)):
                        cboa = cbAttrib.getOperandA()
                        cbob = cbAttrib.getOperandB()
                        file.write(targ+'.renderer.setColorBlendMode(ColorBlendAttrib.%s, ColorBlendAttrib.%s, ColorBlendAttrib.%s)\n' %
                                (cbmLut[cbMode], cboLut[cboa], cboLut[cbob]))
                    else:
                        file.write(targ+'.renderer.setColorBlendMode(ColorBlendAttrib.%s)\n' % cbmLut[cbMode])
            cim = self.renderer.getColorInterpolationManager()
            segIdList = [int(seg) for seg in cim.getSegmentIdList().split()]
            for sid in segIdList:
                seg = cim.getSegment(sid)
                if seg.isEnabled():
                    t_b = seg.getTimeBegin()
                    t_e = seg.getTimeEnd()
                    mod = seg.isModulated()
                    fun = seg.getFunction()
                    typ = type(fun).__name__
                    if typ == 'ColorInterpolationFunctionConstant':
                        c_a = fun.getColorA()
                        file.write(targ+'.renderer.getColorInterpolationManager().addConstant('+repr(t_b)+','+repr(t_e)+','+ \
                                   'Vec4('+repr(c_a[0])+','+repr(c_a[1])+','+repr(c_a[2])+','+repr(c_a[3])+'),'+repr(mod)+')\n')
                    elif typ == 'ColorInterpolationFunctionLinear':
                        c_a = fun.getColorA()
                        c_b = fun.getColorB()
                        file.write(targ+'.renderer.getColorInterpolationManager().addLinear('+repr(t_b)+','+repr(t_e)+','+ \
                                   'Vec4('+repr(c_a[0])+','+repr(c_a[1])+','+repr(c_a[2])+','+repr(c_a[3])+'),' + \
                                   'Vec4('+repr(c_b[0])+','+repr(c_b[1])+','+repr(c_b[2])+','+repr(c_b[3])+'),'+repr(mod)+')\n')
                    elif typ == 'ColorInterpolationFunctionStepwave':
                        c_a = fun.getColorA()
                        c_b = fun.getColorB()
                        w_a = fun.getWidthA()
                        w_b = fun.getWidthB()
                        file.write(targ+'.renderer.getColorInterpolationManager().addStepwave('+repr(t_b)+','+repr(t_e)+','+ \
                                   'Vec4('+repr(c_a[0])+','+repr(c_a[1])+','+repr(c_a[2])+','+repr(c_a[3])+'),' + \
                                   'Vec4('+repr(c_b[0])+','+repr(c_b[1])+','+repr(c_b[2])+','+repr(c_b[3])+'),' + \
                                   repr(w_a)+','+repr(w_b)+','+repr(mod)+')\n')
                    elif typ == 'ColorInterpolationFunctionSinusoid':
                        c_a = fun.getColorA()
                        c_b = fun.getColorB()
                        per = fun.getPeriod()
                        file.write(targ+'.renderer.getColorInterpolationManager().addSinusoid('+repr(t_b)+','+repr(t_e)+','+ \
                                   'Vec4('+repr(c_a[0])+','+repr(c_a[1])+','+repr(c_a[2])+','+repr(c_a[3])+'),' + \
                                   'Vec4('+repr(c_b[0])+','+repr(c_b[1])+','+repr(c_b[2])+','+repr(c_b[3])+'),' + \
                                   repr(per)+','+repr(mod)+')\n')

        elif (self.rendererType == "SparkleParticleRenderer"):
            file.write('# Sparkle parameters\n')
            sColor = self.renderer.getCenterColor()
            file.write((targ + '.renderer.setCenterColor(Vec4(%.2f, %.2f, %.2f, %.2f))\n' % (sColor[0], sColor[1], sColor[2], sColor[3])))
            sColor = self.renderer.getEdgeColor()
            file.write((targ + '.renderer.setEdgeColor(Vec4(%.2f, %.2f, %.2f, %.2f))\n' % (sColor[0], sColor[1], sColor[2], sColor[3])))
            file.write(targ + '.renderer.setBirthRadius(%.4f)\n' % self.renderer.getBirthRadius())
            file.write(targ + '.renderer.setDeathRadius(%.4f)\n' % self.renderer.getDeathRadius())
            lifeScale = self.renderer.getLifeScale()
            lScale = "SPNOSCALE"
            if (lifeScale == SparkleParticleRenderer.SPSCALE):
                lScale = "SPSCALE"
            file.write(targ + '.renderer.setLifeScale(SparkleParticleRenderer.' + lScale + ')\n')
        elif (self.rendererType == "SpriteParticleRenderer"):
            file.write('# Sprite parameters\n')
            if (self.renderer.getAnimateFramesEnable()):
                file.write(targ + '.renderer.setAnimateFramesEnable(True)\n')
                rate = self.renderer.getAnimateFramesRate()
                if(rate):
                    file.write(targ + '.renderer.setAnimateFramesRate(%.3f)\n'%rate)
            animCount = self.renderer.getNumAnims()
            for x in range(animCount):
                anim = self.renderer.getAnim(x)
                if(anim.getSourceType() == SpriteAnim.STTexture):
                    file.write(targ + '.renderer.addTextureFromFile(\'%s\')\n' % (anim.getTexSource(),))
                else:
                    file.write(targ + '.renderer.addTextureFromNode(\'%s\',\'%s\')\n' % (anim.getModelSource(), anim.getNodeSource()))
            sColor = self.renderer.getColor()
            file.write((targ + '.renderer.setColor(Vec4(%.2f, %.2f, %.2f, %.2f))\n' % (sColor[0], sColor[1], sColor[2], sColor[3])))
            file.write(targ + '.renderer.setXScaleFlag(%d)\n' % self.renderer.getXScaleFlag())
            file.write(targ + '.renderer.setYScaleFlag(%d)\n' % self.renderer.getYScaleFlag())
            file.write(targ + '.renderer.setAnimAngleFlag(%d)\n' % self.renderer.getAnimAngleFlag())
            file.write(targ + '.renderer.setInitialXScale(%.4f)\n' % self.renderer.getInitialXScale())
            file.write(targ + '.renderer.setFinalXScale(%.4f)\n' % self.renderer.getFinalXScale())
            file.write(targ + '.renderer.setInitialYScale(%.4f)\n' % self.renderer.getInitialYScale())
            file.write(targ + '.renderer.setFinalYScale(%.4f)\n' % self.renderer.getFinalYScale())
            file.write(targ + '.renderer.setNonanimatedTheta(%.4f)\n' % self.renderer.getNonanimatedTheta())
            blendMethod = self.renderer.getAlphaBlendMethod()
            bMethod = "PPNOBLEND"
            if (blendMethod == BaseParticleRenderer.PPNOBLEND):
                bMethod = "PPNOBLEND"
            elif (blendMethod == BaseParticleRenderer.PPBLENDLINEAR):
                bMethod = "PPBLENDLINEAR"
            elif (blendMethod == BaseParticleRenderer.PPBLENDCUBIC):
                bMethod = "PPBLENDCUBIC"
            file.write(targ + '.renderer.setAlphaBlendMethod(BaseParticleRenderer.' + bMethod + ')\n')
            file.write(targ + '.renderer.setAlphaDisable(%d)\n' % self.renderer.getAlphaDisable())
            # Save the color blending to file
            cbmLut = ('MNone','MAdd','MSubtract','MInvSubtract','MMin','MMax')
            cboLut = ('OZero','OOne','OIncomingColor','OOneMinusIncomingColor','OFbufferColor',
                      'OOneMinusFbufferColor','OIncomingAlpha','OOneMinusIncomingAlpha',
                      'OFbufferAlpha','OOneMinusFbufferAlpha','OConstantColor',
                      'OOneMinusConstantColor','OConstantAlpha','OOneMinusConstantAlpha',
                      'OIncomingColorSaturate')
            cbAttrib = self.renderer.getRenderNode().getAttrib(ColorBlendAttrib.getClassType())
            if(cbAttrib):
                cbMode = cbAttrib.getMode()
                if(cbMode > 0):
                    if(cbMode in (ColorBlendAttrib.MAdd, ColorBlendAttrib.MSubtract, ColorBlendAttrib.MInvSubtract)):
                        cboa = cbAttrib.getOperandA()
                        cbob = cbAttrib.getOperandB()
                        file.write(targ+'.renderer.setColorBlendMode(ColorBlendAttrib.%s, ColorBlendAttrib.%s, ColorBlendAttrib.%s)\n' %
                                (cbmLut[cbMode], cboLut[cboa], cboLut[cbob]))
                    else:
                        file.write(targ+'.renderer.setColorBlendMode(ColorBlendAttrib.%s)\n' % cbmLut[cbMode])
            cim = self.renderer.getColorInterpolationManager()
            segIdList = [int(seg) for seg in cim.getSegmentIdList().split()]
            for sid in segIdList:
                seg = cim.getSegment(sid)
                if seg.isEnabled():
                    t_b = seg.getTimeBegin()
                    t_e = seg.getTimeEnd()
                    mod = seg.isModulated()
                    fun = seg.getFunction()                    
                    typ = type(fun).__name__
                    if typ == 'ColorInterpolationFunctionConstant':
                        c_a = fun.getColorA()
                        file.write(targ+'.renderer.getColorInterpolationManager().addConstant('+repr(t_b)+','+repr(t_e)+','+ \
                                   'Vec4('+repr(c_a[0])+','+repr(c_a[1])+','+repr(c_a[2])+','+repr(c_a[3])+'),'+repr(mod)+')\n')
                    elif typ == 'ColorInterpolationFunctionLinear':
                        c_a = fun.getColorA()
                        c_b = fun.getColorB()
                        file.write(targ+'.renderer.getColorInterpolationManager().addLinear('+repr(t_b)+','+repr(t_e)+','+ \
                                   'Vec4('+repr(c_a[0])+','+repr(c_a[1])+','+repr(c_a[2])+','+repr(c_a[3])+'),' + \
                                   'Vec4('+repr(c_b[0])+','+repr(c_b[1])+','+repr(c_b[2])+','+repr(c_b[3])+'),'+repr(mod)+')\n')
                    elif typ == 'ColorInterpolationFunctionStepwave':
                        c_a = fun.getColorA()
                        c_b = fun.getColorB()
                        w_a = fun.getWidthA()
                        w_b = fun.getWidthB()
                        file.write(targ+'.renderer.getColorInterpolationManager().addStepwave('+repr(t_b)+','+repr(t_e)+','+ \
                                   'Vec4('+repr(c_a[0])+','+repr(c_a[1])+','+repr(c_a[2])+','+repr(c_a[3])+'),' + \
                                   'Vec4('+repr(c_b[0])+','+repr(c_b[1])+','+repr(c_b[2])+','+repr(c_b[3])+'),' + \
                                   repr(w_a)+','+repr(w_b)+','+repr(mod)+')\n')
                    elif typ == 'ColorInterpolationFunctionSinusoid':
                        c_a = fun.getColorA()
                        c_b = fun.getColorB()
                        per = fun.getPeriod()
                        file.write(targ+'.renderer.getColorInterpolationManager().addSinusoid('+repr(t_b)+','+repr(t_e)+','+ \
                                   'Vec4('+repr(c_a[0])+','+repr(c_a[1])+','+repr(c_a[2])+','+repr(c_a[3])+'),' + \
                                   'Vec4('+repr(c_b[0])+','+repr(c_b[1])+','+repr(c_b[2])+','+repr(c_b[3])+'),' + \
                                   repr(per)+','+repr(mod)+')\n')

        file.write('# Emitter parameters\n')
        emissionType = self.emitter.getEmissionType()
        eType = "ETEXPLICIT"
        if (emissionType == BaseParticleEmitter.ETEXPLICIT):
            eType = "ETEXPLICIT"
        elif (emissionType == BaseParticleEmitter.ETRADIATE):
            eType = "ETRADIATE"
        elif (emissionType == BaseParticleEmitter.ETCUSTOM):
            eType = "ETCUSTOM"
        file.write(targ + '.emitter.setEmissionType(BaseParticleEmitter.' + eType + ')\n')
        file.write(targ + '.emitter.setAmplitude(%.4f)\n' % self.emitter.getAmplitude())
        file.write(targ + '.emitter.setAmplitudeSpread(%.4f)\n' % self.emitter.getAmplitudeSpread())
        oForce = self.emitter.getOffsetForce()
        file.write((targ + '.emitter.setOffsetForce(Vec3(%.4f, %.4f, %.4f))\n' % (oForce[0], oForce[1], oForce[2])))
        oForce = self.emitter.getExplicitLaunchVector()
        file.write((targ + '.emitter.setExplicitLaunchVector(Vec3(%.4f, %.4f, %.4f))\n' % (oForce[0], oForce[1], oForce[2])))
        orig = self.emitter.getRadiateOrigin()
        file.write((targ + '.emitter.setRadiateOrigin(Point3(%.4f, %.4f, %.4f))\n' % (orig[0], orig[1], orig[2])))
        if (self.emitterType == "BoxEmitter"):
            file.write('# Box parameters\n')
            bound = self.emitter.getMinBound()
            file.write((targ + '.emitter.setMinBound(Point3(%.4f, %.4f, %.4f))\n' % (bound[0], bound[1], bound[2])))
            bound = self.emitter.getMaxBound()
            file.write((targ + '.emitter.setMaxBound(Point3(%.4f, %.4f, %.4f))\n' % (bound[0], bound[1], bound[2])))
        elif (self.emitterType == "DiscEmitter"):
            file.write('# Disc parameters\n')
            file.write(targ + '.emitter.setRadius(%.4f)\n' % self.emitter.getRadius())
            if (eType == "ETCUSTOM"):
                file.write(targ + '.emitter.setOuterAngle(%.4f)\n' % self.emitter.getOuterAngle())
                file.write(targ + '.emitter.setInnerAngle(%.4f)\n' % self.emitter.getInnerAngle())
                file.write(targ + '.emitter.setOuterMagnitude(%.4f)\n' % self.emitter.getOuterMagnitude())
                file.write(targ + '.emitter.setInnerMagnitude(%.4f)\n' % self.emitter.getInnerMagnitude())
                file.write(targ + '.emitter.setCubicLerping(%d)\n' % self.emitter.getCubicLerping())

        elif (self.emitterType == "LineEmitter"):
            file.write('# Line parameters\n')
            point = self.emitter.getEndpoint1()
            file.write((targ + '.emitter.setEndpoint1(Point3(%.4f, %.4f, %.4f))\n' % (point[0], point[1], point[2])))
            point = self.emitter.getEndpoint2()
            file.write((targ + '.emitter.setEndpoint2(Point3(%.4f, %.4f, %.4f))\n' % (point[0], point[1], point[2])))
        elif (self.emitterType == "PointEmitter"):
            file.write('# Point parameters\n')
            point = self.emitter.getLocation()
            file.write((targ + '.emitter.setLocation(Point3(%.4f, %.4f, %.4f))\n' % (point[0], point[1], point[2])))
        elif (self.emitterType == "RectangleEmitter"):
            file.write('# Rectangle parameters\n')
            point = self.emitter.getMinBound()
            file.write((targ + '.emitter.setMinBound(Point2(%.4f, %.4f))\n' % (point[0], point[1])))
            point = self.emitter.getMaxBound()
            file.write((targ + '.emitter.setMaxBound(Point2(%.4f, %.4f))\n' % (point[0], point[1])))
        elif (self.emitterType == "RingEmitter"):
            file.write('# Ring parameters\n')
            file.write(targ + '.emitter.setRadius(%.4f)\n' % self.emitter.getRadius())
            file.write(targ + '.emitter.setRadiusSpread(%.4f)\n' % self.emitter.getRadiusSpread())
            if (eType == "ETCUSTOM"):
                file.write(targ + '.emitter.setAngle(%.4f)\n' % self.emitter.getAngle())
        elif (self.emitterType == "SphereSurfaceEmitter"):
            file.write('# Sphere Surface parameters\n')
            file.write(targ + '.emitter.setRadius(%.4f)\n' % self.emitter.getRadius())
        elif (self.emitterType == "SphereVolumeEmitter"):
            file.write('# Sphere Volume parameters\n')
            file.write(targ + '.emitter.setRadius(%.4f)\n' % self.emitter.getRadius())
        elif (self.emitterType == "TangentRingEmitter"):
            file.write('# Tangent Ring parameters\n')
            file.write(targ + '.emitter.setRadius(%.4f)\n' % self.emitter.getRadius())
            file.write(targ + '.emitter.setRadiusSpread(%.4f)\n' % self.emitter.getRadiusSpread())
            
    def getPoolSizeRanges(self):
        litterRange = [max(1,self.getLitterSize()-self.getLitterSpread()),
                       self.getLitterSize(),
                       self.getLitterSize()+self.getLitterSpread()]
        lifespanRange = [self.factory.getLifespanBase()-self.factory.getLifespanSpread(),
                         self.factory.getLifespanBase(),
                         self.factory.getLifespanBase()+self.factory.getLifespanSpread()]
        birthRateRange = [self.getBirthRate()] * 3

        print 'Litter Ranges:    ',litterRange
        print 'LifeSpan Ranges:  ',lifespanRange
        print 'BirthRate Ranges: ',birthRateRange
        
        return dict(zip(('min','median','max'),[l*s/b for l,s,b in zip(litterRange,lifespanRange,birthRateRange)]))
            

    def accelerate(self,time,stepCount = 1,stepTime=0.0):
        if time > 0.0:
            if stepTime == 0.0:
                stepTime = float(time)/stepCount
                remainder = 0.0
            else:
                stepCount = int(float(time)/stepTime)
                remainder = time-stepCount*stepTime
                
            for step in range(stepCount):
                base.particleMgr.doParticles(stepTime,self,False)
                base.physicsMgr.doPhysics(stepTime,self)
                
            if(remainder):
                base.particleMgr.doParticles(remainder,self,False)
                base.physicsMgr.doPhysics(remainder,self)
                
            self.render()