Particles.py 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595
  1. from panda3d.core import *
  2. from panda3d.physics import PhysicalNode
  3. from panda3d.physics import ParticleSystem
  4. from panda3d.physics import PointParticleFactory
  5. from panda3d.physics import ZSpinParticleFactory
  6. #from panda3d.physics import OrientedParticleFactory
  7. from panda3d.physics import BaseParticleRenderer
  8. from panda3d.physics import PointParticleRenderer
  9. from panda3d.physics import LineParticleRenderer
  10. from panda3d.physics import GeomParticleRenderer
  11. from panda3d.physics import SparkleParticleRenderer
  12. #from panda3d.physics import SpriteParticleRenderer
  13. from panda3d.physics import BaseParticleEmitter
  14. from panda3d.physics import ArcEmitter
  15. from panda3d.physics import BoxEmitter
  16. from panda3d.physics import DiscEmitter
  17. from panda3d.physics import LineEmitter
  18. from panda3d.physics import PointEmitter
  19. from panda3d.physics import RectangleEmitter
  20. from panda3d.physics import RingEmitter
  21. from panda3d.physics import SphereSurfaceEmitter
  22. from panda3d.physics import SphereVolumeEmitter
  23. from panda3d.physics import TangentRingEmitter
  24. from . import SpriteParticleRendererExt
  25. from direct.directnotify.DirectNotifyGlobal import directNotify
  26. import sys
  27. class Particles(ParticleSystem):
  28. notify = directNotify.newCategory('Particles')
  29. id = 1
  30. def __init__(self, name=None, poolSize=1024):
  31. if (name == None):
  32. self.name = 'particles-%d' % Particles.id
  33. Particles.id += 1
  34. else:
  35. self.name = name
  36. ParticleSystem.__init__(self, poolSize)
  37. # self.setBirthRate(0.02)
  38. # self.setLitterSize(10)
  39. # self.setLitterSpread(0)
  40. # Set up a physical node
  41. self.node = PhysicalNode(self.name)
  42. self.nodePath = NodePath(self.node)
  43. self.setRenderParent(self.node)
  44. self.node.addPhysical(self)
  45. self.factory = None
  46. self.factoryType = "undefined"
  47. # self.setFactory("PointParticleFactory")
  48. self.renderer = None
  49. self.rendererType = "undefined"
  50. # self.setRenderer("PointParticleRenderer")
  51. self.emitter = None
  52. self.emitterType = "undefined"
  53. # self.setEmitter("SphereVolumeEmitter")
  54. # Enable particles by default
  55. self.fEnabled = 0
  56. #self.enable()
  57. self.geomReference = ""
  58. def cleanup(self):
  59. self.disable()
  60. self.clearLinearForces()
  61. self.clearAngularForces()
  62. self.setRenderParent(self.node)
  63. self.node.removePhysical(self)
  64. self.nodePath.removeNode()
  65. del self.node
  66. del self.nodePath
  67. del self.factory
  68. del self.renderer
  69. del self.emitter
  70. def enable(self):
  71. if (self.fEnabled == 0):
  72. base.physicsMgr.attachPhysical(self)
  73. base.particleMgr.attachParticlesystem(self)
  74. self.fEnabled = 1
  75. def disable(self):
  76. if (self.fEnabled == 1):
  77. base.physicsMgr.removePhysical(self)
  78. base.particleMgr.removeParticlesystem(self)
  79. self.fEnabled = 0
  80. def isEnabled(self):
  81. return self.fEnabled
  82. def getNode(self):
  83. return self.node
  84. def setFactory(self, type):
  85. if (self.factoryType == type):
  86. return None
  87. if (self.factory):
  88. self.factory = None
  89. self.factoryType = type
  90. if (type == "PointParticleFactory"):
  91. self.factory = PointParticleFactory()
  92. elif (type == "ZSpinParticleFactory"):
  93. self.factory = ZSpinParticleFactory()
  94. elif (type == "OrientedParticleFactory"):
  95. self.factory = OrientedParticleFactory()
  96. else:
  97. print("unknown factory type: %s" % type)
  98. return None
  99. self.factory.setLifespanBase(0.5)
  100. ParticleSystem.setFactory(self, self.factory)
  101. def setRenderer(self, type):
  102. if (self.rendererType == type):
  103. return None
  104. if (self.renderer):
  105. self.renderer = None
  106. self.rendererType = type
  107. if (type == "PointParticleRenderer"):
  108. self.renderer = PointParticleRenderer()
  109. self.renderer.setPointSize(1.0)
  110. elif (type == "LineParticleRenderer"):
  111. self.renderer = LineParticleRenderer()
  112. elif (type == "GeomParticleRenderer"):
  113. self.renderer = GeomParticleRenderer()
  114. # This was moved here because we do not want to download
  115. # the direct tools with toontown.
  116. if __dev__:
  117. from direct.directtools import DirectSelection
  118. npath = NodePath('default-geom')
  119. bbox = DirectSelection.DirectBoundingBox(npath)
  120. self.renderer.setGeomNode(bbox.lines.node())
  121. elif (type == "SparkleParticleRenderer"):
  122. self.renderer = SparkleParticleRenderer()
  123. elif (type == "SpriteParticleRenderer"):
  124. self.renderer = SpriteParticleRendererExt.SpriteParticleRendererExt()
  125. # self.renderer.setTextureFromFile()
  126. else:
  127. print("unknown renderer type: %s" % type)
  128. return None
  129. ParticleSystem.setRenderer(self, self.renderer)
  130. def setEmitter(self, type):
  131. if (self.emitterType == type):
  132. return None
  133. if (self.emitter):
  134. self.emitter = None
  135. self.emitterType = type
  136. if (type == "ArcEmitter"):
  137. self.emitter = ArcEmitter()
  138. elif (type == "BoxEmitter"):
  139. self.emitter = BoxEmitter()
  140. elif (type == "DiscEmitter"):
  141. self.emitter = DiscEmitter()
  142. elif (type == "LineEmitter"):
  143. self.emitter = LineEmitter()
  144. elif (type == "PointEmitter"):
  145. self.emitter = PointEmitter()
  146. elif (type == "RectangleEmitter"):
  147. self.emitter = RectangleEmitter()
  148. elif (type == "RingEmitter"):
  149. self.emitter = RingEmitter()
  150. elif (type == "SphereSurfaceEmitter"):
  151. self.emitter = SphereSurfaceEmitter()
  152. elif (type == "SphereVolumeEmitter"):
  153. self.emitter = SphereVolumeEmitter()
  154. self.emitter.setRadius(1.0)
  155. elif (type == "TangentRingEmitter"):
  156. self.emitter = TangentRingEmitter()
  157. else:
  158. print("unknown emitter type: %s" % type)
  159. return None
  160. ParticleSystem.setEmitter(self, self.emitter)
  161. def addForce(self, force):
  162. if (force.isLinear()):
  163. self.addLinearForce(force)
  164. else:
  165. self.addAngularForce(force)
  166. def removeForce(self, force):
  167. if (force == None):
  168. self.notify.warning('removeForce() - force == None!')
  169. return
  170. if (force.isLinear()):
  171. self.removeLinearForce(force)
  172. else:
  173. self.removeAngularForce(force)
  174. def setRenderNodePath(self, nodePath):
  175. self.setRenderParent(nodePath.node())
  176. ## Getters ##
  177. def getName(self):
  178. return self.name
  179. def getFactory(self):
  180. return self.factory
  181. def getEmitter(self):
  182. return self.emitter
  183. def getRenderer(self):
  184. return self.renderer
  185. def printParams(self, file = sys.stdout, targ = 'self'):
  186. file.write('# Particles parameters\n')
  187. file.write(targ + '.setFactory(\"' + self.factoryType + '\")\n')
  188. file.write(targ + '.setRenderer(\"' + self.rendererType + '\")\n')
  189. file.write(targ + '.setEmitter(\"' + self.emitterType + '\")\n')
  190. # System parameters
  191. file.write(targ + ('.setPoolSize(%d)\n' %
  192. int(self.getPoolSize())))
  193. file.write(targ + ('.setBirthRate(%.4f)\n' %
  194. self.getBirthRate()))
  195. file.write(targ + ('.setLitterSize(%d)\n' %
  196. int(self.getLitterSize())))
  197. file.write(targ + ('.setLitterSpread(%d)\n' %
  198. self.getLitterSpread()))
  199. file.write(targ + ('.setSystemLifespan(%.4f)\n' %
  200. self.getSystemLifespan()))
  201. file.write(targ + ('.setLocalVelocityFlag(%d)\n' %
  202. self.getLocalVelocityFlag()))
  203. file.write(targ + ('.setSystemGrowsOlderFlag(%d)\n' %
  204. self.getSystemGrowsOlderFlag()))
  205. file.write('# Factory parameters\n')
  206. file.write(targ + ('.factory.setLifespanBase(%.4f)\n' %
  207. self.factory.getLifespanBase()))
  208. file.write(targ + '.factory.setLifespanSpread(%.4f)\n' % \
  209. self.factory.getLifespanSpread())
  210. file.write(targ + '.factory.setMassBase(%.4f)\n' % \
  211. self.factory.getMassBase())
  212. file.write(targ + '.factory.setMassSpread(%.4f)\n' % \
  213. self.factory.getMassSpread())
  214. file.write(targ + '.factory.setTerminalVelocityBase(%.4f)\n' % \
  215. self.factory.getTerminalVelocityBase())
  216. file.write(targ + '.factory.setTerminalVelocitySpread(%.4f)\n' % \
  217. self.factory.getTerminalVelocitySpread())
  218. if (self.factoryType == "PointParticleFactory"):
  219. file.write('# Point factory parameters\n')
  220. elif (self.factoryType == "ZSpinParticleFactory"):
  221. file.write('# Z Spin factory parameters\n')
  222. file.write(targ + '.factory.setInitialAngle(%.4f)\n' % \
  223. self.factory.getInitialAngle())
  224. file.write(targ + '.factory.setInitialAngleSpread(%.4f)\n' % \
  225. self.factory.getInitialAngleSpread())
  226. file.write(targ + '.factory.enableAngularVelocity(%d)\n' % \
  227. self.factory.getAngularVelocityEnabled())
  228. if(self.factory.getAngularVelocityEnabled()):
  229. file.write(targ + '.factory.setAngularVelocity(%.4f)\n' % \
  230. self.factory.getAngularVelocity())
  231. file.write(targ + '.factory.setAngularVelocitySpread(%.4f)\n' % \
  232. self.factory.getAngularVelocitySpread())
  233. else:
  234. file.write(targ + '.factory.setFinalAngle(%.4f)\n' % \
  235. self.factory.getFinalAngle())
  236. file.write(targ + '.factory.setFinalAngleSpread(%.4f)\n' % \
  237. self.factory.getFinalAngleSpread())
  238. elif (self.factoryType == "OrientedParticleFactory"):
  239. file.write('# Oriented factory parameters\n')
  240. file.write(targ + '.factory.setInitialOrientation(%.4f)\n' % \
  241. self.factory.getInitialOrientation())
  242. file.write(targ + '.factory.setFinalOrientation(%.4f)\n' % \
  243. self.factory.getFinalOrientation())
  244. file.write('# Renderer parameters\n')
  245. alphaMode = self.renderer.getAlphaMode()
  246. aMode = "PRALPHANONE"
  247. if (alphaMode == BaseParticleRenderer.PRALPHANONE):
  248. aMode = "PRALPHANONE"
  249. elif (alphaMode == BaseParticleRenderer.PRALPHAOUT):
  250. aMode = "PRALPHAOUT"
  251. elif (alphaMode == BaseParticleRenderer.PRALPHAIN):
  252. aMode = "PRALPHAIN"
  253. elif (alphaMode == BaseParticleRenderer.PRALPHAINOUT):
  254. aMode = "PRALPHAINOUT"
  255. elif (alphaMode == BaseParticleRenderer.PRALPHAUSER):
  256. aMode = "PRALPHAUSER"
  257. file.write(targ + '.renderer.setAlphaMode(BaseParticleRenderer.' + aMode + ')\n')
  258. file.write(targ + '.renderer.setUserAlpha(%.2f)\n' % \
  259. self.renderer.getUserAlpha())
  260. if (self.rendererType == "PointParticleRenderer"):
  261. file.write('# Point parameters\n')
  262. file.write(targ + '.renderer.setPointSize(%.2f)\n' % \
  263. self.renderer.getPointSize())
  264. sColor = self.renderer.getStartColor()
  265. file.write((targ + '.renderer.setStartColor(Vec4(%.2f, %.2f, %.2f, %.2f))\n' % (sColor[0], sColor[1], sColor[2], sColor[3])))
  266. sColor = self.renderer.getEndColor()
  267. file.write((targ + '.renderer.setEndColor(Vec4(%.2f, %.2f, %.2f, %.2f))\n' % (sColor[0], sColor[1], sColor[2], sColor[3])))
  268. blendType = self.renderer.getBlendType()
  269. bType = "PPONECOLOR"
  270. if (blendType == PointParticleRenderer.PPONECOLOR):
  271. bType = "PPONECOLOR"
  272. elif (blendType == PointParticleRenderer.PPBLENDLIFE):
  273. bType = "PPBLENDLIFE"
  274. elif (blendType == PointParticleRenderer.PPBLENDVEL):
  275. bType = "PPBLENDVEL"
  276. file.write(targ + '.renderer.setBlendType(PointParticleRenderer.' + bType + ')\n')
  277. blendMethod = self.renderer.getBlendMethod()
  278. bMethod = "PPNOBLEND"
  279. if (blendMethod == BaseParticleRenderer.PPNOBLEND):
  280. bMethod = "PPNOBLEND"
  281. elif (blendMethod == BaseParticleRenderer.PPBLENDLINEAR):
  282. bMethod = "PPBLENDLINEAR"
  283. elif (blendMethod == BaseParticleRenderer.PPBLENDCUBIC):
  284. bMethod = "PPBLENDCUBIC"
  285. file.write(targ + '.renderer.setBlendMethod(BaseParticleRenderer.' + bMethod + ')\n')
  286. elif (self.rendererType == "LineParticleRenderer"):
  287. file.write('# Line parameters\n')
  288. sColor = self.renderer.getHeadColor()
  289. file.write((targ + '.renderer.setHeadColor(Vec4(%.2f, %.2f, %.2f, %.2f))\n' % (sColor[0], sColor[1], sColor[2], sColor[3])))
  290. sColor = self.renderer.getTailColor()
  291. file.write((targ + '.renderer.setTailColor(Vec4(%.2f, %.2f, %.2f, %.2f))\n' % (sColor[0], sColor[1], sColor[2], sColor[3])))
  292. sf = self.renderer.getLineScaleFactor()
  293. file.write((targ + '.renderer.setLineScaleFactor(%.2f)\n' % (sf)))
  294. elif (self.rendererType == "GeomParticleRenderer"):
  295. file.write('# Geom parameters\n')
  296. node = self.renderer.getGeomNode()
  297. file.write('geomRef = loader.loadModel("' + self.geomReference + '")\n')
  298. file.write(targ + '.renderer.setGeomNode(geomRef.node())\n')
  299. file.write(targ + '.geomReference = "' + self.geomReference + '"\n');
  300. cbmLut = ('MNone','MAdd','MSubtract','MInvSubtract','MMin','MMax')
  301. cboLut = ('OZero','OOne','OIncomingColor','OOneMinusIncomingColor','OFbufferColor',
  302. 'OOneMinusFbufferColor','OIncomingAlpha','OOneMinusIncomingAlpha',
  303. 'OFbufferAlpha','OOneMinusFbufferAlpha','OConstantColor',
  304. 'OOneMinusConstantColor','OConstantAlpha','OOneMinusConstantAlpha',
  305. 'OIncomingColorSaturate')
  306. file.write(targ + '.renderer.setXScaleFlag(%d)\n' % self.renderer.getXScaleFlag())
  307. file.write(targ + '.renderer.setYScaleFlag(%d)\n' % self.renderer.getYScaleFlag())
  308. file.write(targ + '.renderer.setZScaleFlag(%d)\n' % self.renderer.getZScaleFlag())
  309. file.write(targ + '.renderer.setInitialXScale(%.4f)\n' % self.renderer.getInitialXScale())
  310. file.write(targ + '.renderer.setFinalXScale(%.4f)\n' % self.renderer.getFinalXScale())
  311. file.write(targ + '.renderer.setInitialYScale(%.4f)\n' % self.renderer.getInitialYScale())
  312. file.write(targ + '.renderer.setFinalYScale(%.4f)\n' % self.renderer.getFinalYScale())
  313. file.write(targ + '.renderer.setInitialZScale(%.4f)\n' % self.renderer.getInitialZScale())
  314. file.write(targ + '.renderer.setFinalZScale(%.4f)\n' % self.renderer.getFinalZScale())
  315. cbAttrib = self.renderer.getRenderNode().getAttrib(ColorBlendAttrib.getClassType())
  316. if(cbAttrib):
  317. cbMode = cbAttrib.getMode()
  318. if(cbMode > 0):
  319. if(cbMode in (ColorBlendAttrib.MAdd, ColorBlendAttrib.MSubtract, ColorBlendAttrib.MInvSubtract)):
  320. cboa = cbAttrib.getOperandA()
  321. cbob = cbAttrib.getOperandB()
  322. file.write(targ+'.renderer.setColorBlendMode(ColorBlendAttrib.%s, ColorBlendAttrib.%s, ColorBlendAttrib.%s)\n' %
  323. (cbmLut[cbMode], cboLut[cboa], cboLut[cbob]))
  324. else:
  325. file.write(targ+'.renderer.setColorBlendMode(ColorBlendAttrib.%s)\n' % cbmLut[cbMode])
  326. cim = self.renderer.getColorInterpolationManager()
  327. segIdList = [int(seg) for seg in cim.getSegmentIdList().split()]
  328. for sid in segIdList:
  329. seg = cim.getSegment(sid)
  330. if seg.isEnabled():
  331. t_b = seg.getTimeBegin()
  332. t_e = seg.getTimeEnd()
  333. mod = seg.isModulated()
  334. fun = seg.getFunction()
  335. typ = type(fun).__name__
  336. if typ == 'ColorInterpolationFunctionConstant':
  337. c_a = fun.getColorA()
  338. file.write(targ+'.renderer.getColorInterpolationManager().addConstant('+repr(t_b)+','+repr(t_e)+','+ \
  339. 'Vec4('+repr(c_a[0])+','+repr(c_a[1])+','+repr(c_a[2])+','+repr(c_a[3])+'),'+repr(mod)+')\n')
  340. elif typ == 'ColorInterpolationFunctionLinear':
  341. c_a = fun.getColorA()
  342. c_b = fun.getColorB()
  343. file.write(targ+'.renderer.getColorInterpolationManager().addLinear('+repr(t_b)+','+repr(t_e)+','+ \
  344. 'Vec4('+repr(c_a[0])+','+repr(c_a[1])+','+repr(c_a[2])+','+repr(c_a[3])+'),' + \
  345. 'Vec4('+repr(c_b[0])+','+repr(c_b[1])+','+repr(c_b[2])+','+repr(c_b[3])+'),'+repr(mod)+')\n')
  346. elif typ == 'ColorInterpolationFunctionStepwave':
  347. c_a = fun.getColorA()
  348. c_b = fun.getColorB()
  349. w_a = fun.getWidthA()
  350. w_b = fun.getWidthB()
  351. file.write(targ+'.renderer.getColorInterpolationManager().addStepwave('+repr(t_b)+','+repr(t_e)+','+ \
  352. 'Vec4('+repr(c_a[0])+','+repr(c_a[1])+','+repr(c_a[2])+','+repr(c_a[3])+'),' + \
  353. 'Vec4('+repr(c_b[0])+','+repr(c_b[1])+','+repr(c_b[2])+','+repr(c_b[3])+'),' + \
  354. repr(w_a)+','+repr(w_b)+','+repr(mod)+')\n')
  355. elif typ == 'ColorInterpolationFunctionSinusoid':
  356. c_a = fun.getColorA()
  357. c_b = fun.getColorB()
  358. per = fun.getPeriod()
  359. file.write(targ+'.renderer.getColorInterpolationManager().addSinusoid('+repr(t_b)+','+repr(t_e)+','+ \
  360. 'Vec4('+repr(c_a[0])+','+repr(c_a[1])+','+repr(c_a[2])+','+repr(c_a[3])+'),' + \
  361. 'Vec4('+repr(c_b[0])+','+repr(c_b[1])+','+repr(c_b[2])+','+repr(c_b[3])+'),' + \
  362. repr(per)+','+repr(mod)+')\n')
  363. elif (self.rendererType == "SparkleParticleRenderer"):
  364. file.write('# Sparkle parameters\n')
  365. sColor = self.renderer.getCenterColor()
  366. file.write((targ + '.renderer.setCenterColor(Vec4(%.2f, %.2f, %.2f, %.2f))\n' % (sColor[0], sColor[1], sColor[2], sColor[3])))
  367. sColor = self.renderer.getEdgeColor()
  368. file.write((targ + '.renderer.setEdgeColor(Vec4(%.2f, %.2f, %.2f, %.2f))\n' % (sColor[0], sColor[1], sColor[2], sColor[3])))
  369. file.write(targ + '.renderer.setBirthRadius(%.4f)\n' % self.renderer.getBirthRadius())
  370. file.write(targ + '.renderer.setDeathRadius(%.4f)\n' % self.renderer.getDeathRadius())
  371. lifeScale = self.renderer.getLifeScale()
  372. lScale = "SPNOSCALE"
  373. if (lifeScale == SparkleParticleRenderer.SPSCALE):
  374. lScale = "SPSCALE"
  375. file.write(targ + '.renderer.setLifeScale(SparkleParticleRenderer.' + lScale + ')\n')
  376. elif (self.rendererType == "SpriteParticleRenderer"):
  377. file.write('# Sprite parameters\n')
  378. if (self.renderer.getAnimateFramesEnable()):
  379. file.write(targ + '.renderer.setAnimateFramesEnable(True)\n')
  380. rate = self.renderer.getAnimateFramesRate()
  381. if(rate):
  382. file.write(targ + '.renderer.setAnimateFramesRate(%.3f)\n'%rate)
  383. animCount = self.renderer.getNumAnims()
  384. for x in range(animCount):
  385. anim = self.renderer.getAnim(x)
  386. if(anim.getSourceType() == SpriteAnim.STTexture):
  387. file.write(targ + '.renderer.addTextureFromFile(\'%s\')\n' % (anim.getTexSource(),))
  388. else:
  389. file.write(targ + '.renderer.addTextureFromNode(\'%s\',\'%s\')\n' % (anim.getModelSource(), anim.getNodeSource()))
  390. sColor = self.renderer.getColor()
  391. file.write((targ + '.renderer.setColor(Vec4(%.2f, %.2f, %.2f, %.2f))\n' % (sColor[0], sColor[1], sColor[2], sColor[3])))
  392. file.write(targ + '.renderer.setXScaleFlag(%d)\n' % self.renderer.getXScaleFlag())
  393. file.write(targ + '.renderer.setYScaleFlag(%d)\n' % self.renderer.getYScaleFlag())
  394. file.write(targ + '.renderer.setAnimAngleFlag(%d)\n' % self.renderer.getAnimAngleFlag())
  395. file.write(targ + '.renderer.setInitialXScale(%.4f)\n' % self.renderer.getInitialXScale())
  396. file.write(targ + '.renderer.setFinalXScale(%.4f)\n' % self.renderer.getFinalXScale())
  397. file.write(targ + '.renderer.setInitialYScale(%.4f)\n' % self.renderer.getInitialYScale())
  398. file.write(targ + '.renderer.setFinalYScale(%.4f)\n' % self.renderer.getFinalYScale())
  399. file.write(targ + '.renderer.setNonanimatedTheta(%.4f)\n' % self.renderer.getNonanimatedTheta())
  400. blendMethod = self.renderer.getAlphaBlendMethod()
  401. bMethod = "PPNOBLEND"
  402. if (blendMethod == BaseParticleRenderer.PPNOBLEND):
  403. bMethod = "PPNOBLEND"
  404. elif (blendMethod == BaseParticleRenderer.PPBLENDLINEAR):
  405. bMethod = "PPBLENDLINEAR"
  406. elif (blendMethod == BaseParticleRenderer.PPBLENDCUBIC):
  407. bMethod = "PPBLENDCUBIC"
  408. file.write(targ + '.renderer.setAlphaBlendMethod(BaseParticleRenderer.' + bMethod + ')\n')
  409. file.write(targ + '.renderer.setAlphaDisable(%d)\n' % self.renderer.getAlphaDisable())
  410. # Save the color blending to file
  411. cbmLut = ('MNone','MAdd','MSubtract','MInvSubtract','MMin','MMax')
  412. cboLut = ('OZero','OOne','OIncomingColor','OOneMinusIncomingColor','OFbufferColor',
  413. 'OOneMinusFbufferColor','OIncomingAlpha','OOneMinusIncomingAlpha',
  414. 'OFbufferAlpha','OOneMinusFbufferAlpha','OConstantColor',
  415. 'OOneMinusConstantColor','OConstantAlpha','OOneMinusConstantAlpha',
  416. 'OIncomingColorSaturate')
  417. cbAttrib = self.renderer.getRenderNode().getAttrib(ColorBlendAttrib.getClassType())
  418. if(cbAttrib):
  419. cbMode = cbAttrib.getMode()
  420. if(cbMode > 0):
  421. if(cbMode in (ColorBlendAttrib.MAdd, ColorBlendAttrib.MSubtract, ColorBlendAttrib.MInvSubtract)):
  422. cboa = cbAttrib.getOperandA()
  423. cbob = cbAttrib.getOperandB()
  424. file.write(targ+'.renderer.setColorBlendMode(ColorBlendAttrib.%s, ColorBlendAttrib.%s, ColorBlendAttrib.%s)\n' %
  425. (cbmLut[cbMode], cboLut[cboa], cboLut[cbob]))
  426. else:
  427. file.write(targ+'.renderer.setColorBlendMode(ColorBlendAttrib.%s)\n' % cbmLut[cbMode])
  428. cim = self.renderer.getColorInterpolationManager()
  429. segIdList = [int(seg) for seg in cim.getSegmentIdList().split()]
  430. for sid in segIdList:
  431. seg = cim.getSegment(sid)
  432. if seg.isEnabled():
  433. t_b = seg.getTimeBegin()
  434. t_e = seg.getTimeEnd()
  435. mod = seg.isModulated()
  436. fun = seg.getFunction()
  437. typ = type(fun).__name__
  438. if typ == 'ColorInterpolationFunctionConstant':
  439. c_a = fun.getColorA()
  440. file.write(targ+'.renderer.getColorInterpolationManager().addConstant('+repr(t_b)+','+repr(t_e)+','+ \
  441. 'Vec4('+repr(c_a[0])+','+repr(c_a[1])+','+repr(c_a[2])+','+repr(c_a[3])+'),'+repr(mod)+')\n')
  442. elif typ == 'ColorInterpolationFunctionLinear':
  443. c_a = fun.getColorA()
  444. c_b = fun.getColorB()
  445. file.write(targ+'.renderer.getColorInterpolationManager().addLinear('+repr(t_b)+','+repr(t_e)+','+ \
  446. 'Vec4('+repr(c_a[0])+','+repr(c_a[1])+','+repr(c_a[2])+','+repr(c_a[3])+'),' + \
  447. 'Vec4('+repr(c_b[0])+','+repr(c_b[1])+','+repr(c_b[2])+','+repr(c_b[3])+'),'+repr(mod)+')\n')
  448. elif typ == 'ColorInterpolationFunctionStepwave':
  449. c_a = fun.getColorA()
  450. c_b = fun.getColorB()
  451. w_a = fun.getWidthA()
  452. w_b = fun.getWidthB()
  453. file.write(targ+'.renderer.getColorInterpolationManager().addStepwave('+repr(t_b)+','+repr(t_e)+','+ \
  454. 'Vec4('+repr(c_a[0])+','+repr(c_a[1])+','+repr(c_a[2])+','+repr(c_a[3])+'),' + \
  455. 'Vec4('+repr(c_b[0])+','+repr(c_b[1])+','+repr(c_b[2])+','+repr(c_b[3])+'),' + \
  456. repr(w_a)+','+repr(w_b)+','+repr(mod)+')\n')
  457. elif typ == 'ColorInterpolationFunctionSinusoid':
  458. c_a = fun.getColorA()
  459. c_b = fun.getColorB()
  460. per = fun.getPeriod()
  461. file.write(targ+'.renderer.getColorInterpolationManager().addSinusoid('+repr(t_b)+','+repr(t_e)+','+ \
  462. 'Vec4('+repr(c_a[0])+','+repr(c_a[1])+','+repr(c_a[2])+','+repr(c_a[3])+'),' + \
  463. 'Vec4('+repr(c_b[0])+','+repr(c_b[1])+','+repr(c_b[2])+','+repr(c_b[3])+'),' + \
  464. repr(per)+','+repr(mod)+')\n')
  465. file.write('# Emitter parameters\n')
  466. emissionType = self.emitter.getEmissionType()
  467. eType = "ETEXPLICIT"
  468. if (emissionType == BaseParticleEmitter.ETEXPLICIT):
  469. eType = "ETEXPLICIT"
  470. elif (emissionType == BaseParticleEmitter.ETRADIATE):
  471. eType = "ETRADIATE"
  472. elif (emissionType == BaseParticleEmitter.ETCUSTOM):
  473. eType = "ETCUSTOM"
  474. file.write(targ + '.emitter.setEmissionType(BaseParticleEmitter.' + eType + ')\n')
  475. file.write(targ + '.emitter.setAmplitude(%.4f)\n' % self.emitter.getAmplitude())
  476. file.write(targ + '.emitter.setAmplitudeSpread(%.4f)\n' % self.emitter.getAmplitudeSpread())
  477. oForce = self.emitter.getOffsetForce()
  478. file.write((targ + '.emitter.setOffsetForce(Vec3(%.4f, %.4f, %.4f))\n' % (oForce[0], oForce[1], oForce[2])))
  479. oForce = self.emitter.getExplicitLaunchVector()
  480. file.write((targ + '.emitter.setExplicitLaunchVector(Vec3(%.4f, %.4f, %.4f))\n' % (oForce[0], oForce[1], oForce[2])))
  481. orig = self.emitter.getRadiateOrigin()
  482. file.write((targ + '.emitter.setRadiateOrigin(Point3(%.4f, %.4f, %.4f))\n' % (orig[0], orig[1], orig[2])))
  483. if (self.emitterType == "BoxEmitter"):
  484. file.write('# Box parameters\n')
  485. bound = self.emitter.getMinBound()
  486. file.write((targ + '.emitter.setMinBound(Point3(%.4f, %.4f, %.4f))\n' % (bound[0], bound[1], bound[2])))
  487. bound = self.emitter.getMaxBound()
  488. file.write((targ + '.emitter.setMaxBound(Point3(%.4f, %.4f, %.4f))\n' % (bound[0], bound[1], bound[2])))
  489. elif (self.emitterType == "DiscEmitter"):
  490. file.write('# Disc parameters\n')
  491. file.write(targ + '.emitter.setRadius(%.4f)\n' % self.emitter.getRadius())
  492. if (eType == "ETCUSTOM"):
  493. file.write(targ + '.emitter.setOuterAngle(%.4f)\n' % self.emitter.getOuterAngle())
  494. file.write(targ + '.emitter.setInnerAngle(%.4f)\n' % self.emitter.getInnerAngle())
  495. file.write(targ + '.emitter.setOuterMagnitude(%.4f)\n' % self.emitter.getOuterMagnitude())
  496. file.write(targ + '.emitter.setInnerMagnitude(%.4f)\n' % self.emitter.getInnerMagnitude())
  497. file.write(targ + '.emitter.setCubicLerping(%d)\n' % self.emitter.getCubicLerping())
  498. elif (self.emitterType == "LineEmitter"):
  499. file.write('# Line parameters\n')
  500. point = self.emitter.getEndpoint1()
  501. file.write((targ + '.emitter.setEndpoint1(Point3(%.4f, %.4f, %.4f))\n' % (point[0], point[1], point[2])))
  502. point = self.emitter.getEndpoint2()
  503. file.write((targ + '.emitter.setEndpoint2(Point3(%.4f, %.4f, %.4f))\n' % (point[0], point[1], point[2])))
  504. elif (self.emitterType == "PointEmitter"):
  505. file.write('# Point parameters\n')
  506. point = self.emitter.getLocation()
  507. file.write((targ + '.emitter.setLocation(Point3(%.4f, %.4f, %.4f))\n' % (point[0], point[1], point[2])))
  508. elif (self.emitterType == "RectangleEmitter"):
  509. file.write('# Rectangle parameters\n')
  510. point = self.emitter.getMinBound()
  511. file.write((targ + '.emitter.setMinBound(Point2(%.4f, %.4f))\n' % (point[0], point[1])))
  512. point = self.emitter.getMaxBound()
  513. file.write((targ + '.emitter.setMaxBound(Point2(%.4f, %.4f))\n' % (point[0], point[1])))
  514. elif (self.emitterType == "RingEmitter"):
  515. file.write('# Ring parameters\n')
  516. file.write(targ + '.emitter.setRadius(%.4f)\n' % self.emitter.getRadius())
  517. file.write(targ + '.emitter.setRadiusSpread(%.4f)\n' % self.emitter.getRadiusSpread())
  518. if (eType == "ETCUSTOM"):
  519. file.write(targ + '.emitter.setAngle(%.4f)\n' % self.emitter.getAngle())
  520. elif (self.emitterType == "SphereSurfaceEmitter"):
  521. file.write('# Sphere Surface parameters\n')
  522. file.write(targ + '.emitter.setRadius(%.4f)\n' % self.emitter.getRadius())
  523. elif (self.emitterType == "SphereVolumeEmitter"):
  524. file.write('# Sphere Volume parameters\n')
  525. file.write(targ + '.emitter.setRadius(%.4f)\n' % self.emitter.getRadius())
  526. elif (self.emitterType == "TangentRingEmitter"):
  527. file.write('# Tangent Ring parameters\n')
  528. file.write(targ + '.emitter.setRadius(%.4f)\n' % self.emitter.getRadius())
  529. file.write(targ + '.emitter.setRadiusSpread(%.4f)\n' % self.emitter.getRadiusSpread())
  530. def getPoolSizeRanges(self):
  531. litterRange = [max(1,self.getLitterSize()-self.getLitterSpread()),
  532. self.getLitterSize(),
  533. self.getLitterSize()+self.getLitterSpread()]
  534. lifespanRange = [self.factory.getLifespanBase()-self.factory.getLifespanSpread(),
  535. self.factory.getLifespanBase(),
  536. self.factory.getLifespanBase()+self.factory.getLifespanSpread()]
  537. birthRateRange = [self.getBirthRate()] * 3
  538. print('Litter Ranges: %s' % litterRange)
  539. print('LifeSpan Ranges: %s' % lifespanRange)
  540. print('BirthRate Ranges: %s' % birthRateRange)
  541. return dict(zip(('min','median','max'),[l*s/b for l,s,b in zip(litterRange,lifespanRange,birthRateRange)]))
  542. def accelerate(self,time,stepCount = 1,stepTime=0.0):
  543. if time > 0.0:
  544. if stepTime == 0.0:
  545. stepTime = float(time)/stepCount
  546. remainder = 0.0
  547. else:
  548. stepCount = int(float(time)/stepTime)
  549. remainder = time-stepCount*stepTime
  550. for step in range(stepCount):
  551. base.particleMgr.doParticles(stepTime,self,False)
  552. base.physicsMgr.doPhysics(stepTime,self)
  553. if(remainder):
  554. base.particleMgr.doParticles(remainder,self,False)
  555. base.physicsMgr.doPhysics(remainder,self)
  556. self.render()