dataHolder.py 50 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071
  1. ###############################
  2. # TK and PMW INTERFACE MODULES#
  3. ###############################
  4. from direct.showbase.TkGlobal import*
  5. from tkFileDialog import *
  6. import Pmw
  7. import tkFileDialog
  8. import tkMessageBox
  9. from direct.tkwidgets import Dial
  10. from direct.tkwidgets import Floater
  11. #############################
  12. # Scene Editor Python Files #
  13. #############################
  14. from seLights import * # All the scene editor lighting
  15. from seFileSaver import * # The actual File Saving Module which generates Python code
  16. ################################
  17. #Panda Modules #
  18. ################################
  19. from direct.actor import Actor
  20. ###############################
  21. # Core Python Modules #
  22. ###############################
  23. import os
  24. import string
  25. import sys
  26. import seParticleEffect
  27. import seParticles
  28. ######################################################################################################
  29. # Data Holder
  30. # This class will actually hold all data in the form of dictionaries
  31. # This is essentially the entire state of the scene
  32. # When saving a scene, the dictionaries will be accessed and code generated for the loaded content
  33. # Dictionaries are used to access the objects in the scene and their properties so code can be generated
  34. # Write/Use Accessor Methods to interface with these dictionaries
  35. ######################################################################################################
  36. class dataHolder:
  37. ModelDic = {} # Name: Model Nodepath; ModelRoot (whatever loader.loadModel() returns)
  38. ModelRefDic = {} # Name:File Path; (whatever the Open File Dialog Returns)
  39. ActorDic = {} # Name:Actor Actor; Nodepath, ModelRoot (whatever Actor.Actor() returns)
  40. ActorRefDic = {} # Name:File Path; (whatever the Open File Dialog Returns)
  41. curveDict = {} # Node Name: CurveCollection; The actual curve collection data
  42. collisionDict = {} # Node Name: collisionNode; collisionNode in which contains a collision object
  43. blendAnimDict = {} # Node Name: Dictionary of blended animation; User blened animation will be saved in here.
  44. # the data structure in the inner dictionary is
  45. # {"name of blended animation" : [Animation Name A, Animation Name B, Effect(Float)]}
  46. collisionVisable = True # A flag used to record that collision objects are visable or not
  47. dummyDict = {} # Node Name: Dummy Obj; All Object created as a dummy will be save here.
  48. particleDict={} # "Effect Name": Effect Object
  49. particleNodes={} # "Effect Name": Node which is a parent to the effect used to move it aruond easily
  50. ModelNum = 0 # Count of number of models loaded
  51. ActorNum = 0 # Count of number of animations loaded
  52. theScene=None # Global variable to hold a loaded scene
  53. CollisionHandler = CollisionHandlerEvent() # This object shows what happend when collision appeared
  54. # Now, the default is CollisionHandlerEvent Type, which will just send out message when collision happend
  55. controlType = 'Keyboard' # default control input setting
  56. # Default Control setting for keyboard.
  57. controlTarget = camera
  58. # This two dictionary set the basic setting for the keyboard contorl
  59. # Those dictionaries will be passed into controller panel each time it has been opend
  60. # Do NOT change anything about INDEX in the dictionary!! (But it's OK to change the values)
  61. keyboardMapDict = {'KeyForward':'arrow_up',
  62. 'KeyBackward':'arrow_down',
  63. 'KeyLeft':'arrow_left',
  64. 'KeyRight':'arrow_right',
  65. 'KeyUp':'',
  66. 'KeyDown':'',
  67. 'KeyTurnRight':'',
  68. 'KeyTurnLeft':'',
  69. 'KeyTurnUp':'',
  70. 'KeyTurnDown':'',
  71. 'KeyRollRight':'',
  72. 'KeyRollLeft':'',
  73. 'KeyScaleUp':'',
  74. 'KeyScaleDown':'',
  75. 'KeyScaleXUp':'',
  76. 'KeyScaleXDown':'',
  77. 'KeyScaleYUp':'',
  78. 'KeyScaleYDown':'',
  79. 'KeyScaleZUp':'',
  80. 'KeyScaleZDown':''}
  81. keyboardSpeedDict = {'SpeedForward': 0,
  82. 'SpeedBackward': 0,
  83. 'SpeedLeft': 0,
  84. 'SpeedRight': 0,
  85. 'SpeedUp': 0,
  86. 'SpeedDown': 0,
  87. 'SpeedTurnRight': 0,
  88. 'SpeedTurnLeft': 0,
  89. 'SpeedTurnUp': 0,
  90. 'SpeedTurnDown': 0,
  91. 'SpeedRollRight':0,
  92. 'SpeedRollLeft':0,
  93. 'SpeedScaleUp':0,
  94. 'SpeedScaleDown':0,
  95. 'SpeedScaleXUp':0,
  96. 'SpeedScaleXDown':0,
  97. 'SpeedScaleYUp':0,
  98. 'SpeedScaleYDown':0,
  99. 'SpeedScaleZUp':0,
  100. 'SpeedScaleZDown':0}
  101. def __init__(self):
  102. # Creat light manager to contorl the lighting
  103. self.lightManager = seLightManager()
  104. self.lightManager.allOn()
  105. # Initialize the basic message formate from CollisionHandler
  106. self.CollisionHandler.setInPattern("%fnenter%in")
  107. self.CollisionHandler.setOutPattern("%fnexit%in")
  108. pass
  109. def resetAll(self):
  110. #################################################################
  111. # resetAll(self)
  112. # This function will reset the whole scene
  113. #################################################################
  114. # Delete Everything in the Scene Graph
  115. for index in self.ModelDic:
  116. self.ModelDic[index].removeNode()
  117. for index in self.ActorDic:
  118. self.ActorDic[index].removeNode()
  119. for index in self.dummyDict:
  120. self.dummyDict[index].removeNode()
  121. for index in self.collisionDict:
  122. self.collisionDict[index].removeNode()
  123. for index in self.particleNodes:
  124. self.particleDict[index].cleanup()
  125. self.particleNodes[index].removeNode()
  126. # Clear all data containers in the dataHolder
  127. self.ModelDic.clear()
  128. self.ModelRefDic.clear()
  129. self.ActorDic.clear()
  130. self.ActorRefDic.clear()
  131. self.dummyDict.clear()
  132. self.lightManager.deleteAll()
  133. self.blendAnimDict.clear()
  134. self.particleDict.clear()
  135. self.particleNodes.clear()
  136. self.ModelNum=0
  137. self.ActorNum=0
  138. self.theScene=None
  139. messenger.send('SGE_Update Explorer',[render])
  140. print 'Scene should be cleaned up!'
  141. def removeObj(self, nodePath):
  142. #################################################################
  143. # removeObj(self, nodePath)
  144. # This function will take one nodePath obj as a input
  145. # and will remove this node from scene if it is legal to be removed.
  146. # Also, this function will remove all children nodes belong to this specific nodePath by recursive call.
  147. #################################################################
  148. name = nodePath.getName()
  149. ## Check if there is any child node, if so, remove it.
  150. childrenList = nodePath.getChildren()
  151. if self.ModelDic.has_key(name):
  152. del self.ModelDic[name]
  153. del self.ModelRefDic[name]
  154. if len(childrenList) != 0:
  155. for node in childrenList:
  156. self.removeObj(node)
  157. nodePath.removeNode()
  158. self.ModelNum -= 1
  159. pass
  160. elif self.ActorDic.has_key(name):
  161. del self.ActorDic[name]
  162. del self.ActorRefDic[name]
  163. if len(childrenList) != 0:
  164. for node in childrenList:
  165. self.removeObj(node)
  166. nodePath.removeNode()
  167. self.ActorNum -= 1
  168. pass
  169. elif self.collisionDict.has_key(name):
  170. del self.collisionDict[name]
  171. if len(childrenList) != 0:
  172. for node in childrenList:
  173. self.removeObj(node)
  174. nodePath.removeNode()
  175. pass
  176. elif self.dummyDict.has_key(name):
  177. del self.dummyDict[name]
  178. if len(childrenList) != 0:
  179. for node in childrenList:
  180. self.removeObj(node)
  181. nodePath.removeNode()
  182. pass
  183. elif self.lightManager.isLight(name):
  184. if len(childrenList) != 0:
  185. for node in childrenList:
  186. self.removeObj(node)
  187. list = self.lightManager.delete(name)
  188. return list
  189. elif self.particleNodes.has_key(name):
  190. self.particleNodes[name].removeNode()
  191. del self.particleNodes[name]
  192. del self.particleDict[name]
  193. else:
  194. print 'You cannot remove this NodePath'
  195. return
  196. messenger.send('SGE_Update Explorer',[render])
  197. return
  198. def duplicateObj(self, nodePath, pos, hpr, scale, num):
  199. #############################################################################
  200. # duplicateObj(self, nodePath, pos, hpr, scale, num)
  201. # This function now only worked for either Actor or Model type node.
  202. # It won't duplicate lights or others!!!
  203. #
  204. # This function will duplicate the input nodePath "num" times.
  205. # Each time it will use "pos", "hpr" and "scale" as a offset to change the properties of copy.
  206. # Then, reparent copies to the same parent of origin
  207. #
  208. # To Do:
  209. # Make it work for all kinds of objects....
  210. #############################################################################
  211. name = nodePath.getName()
  212. isModel = True
  213. cPos = pos
  214. cHpr = hpr
  215. cScale = scale
  216. parent = nodePath.getParent()
  217. if self.ActorDic.has_key(name):
  218. holder = self.ActorDic
  219. holderRef = self.ActorRefDic
  220. isModel = False
  221. elif self.ModelDic.has_key(name):
  222. holder = self.ModelDic
  223. holderRef = self.ModelRefDic
  224. else:
  225. print '---- DataHolder: Target Obj is not a legal object could be duplicate!'
  226. return
  227. FilePath = holderRef[name]
  228. oPos = holder[name].getPos()+cPos
  229. oHpr = holder[name].getHpr()+cHpr
  230. for i in range(num):
  231. if isModel:
  232. ### copy model node from modelpool
  233. newName = name+'_copy_%d'%i
  234. while self.isInScene(newName):
  235. newName = newName + '_1'
  236. holder[newName] = loader.loadModel(FilePath.getFullpath())
  237. holderRef[newName] = FilePath
  238. self.ModelNum += 1
  239. holder[newName].reparentTo(parent)
  240. holder[newName].setPos(oPos)
  241. holder[newName].setHpr(oHpr)
  242. holder[newName].setScale(cScale)
  243. holder[newName].setName(newName)
  244. oPos = oPos + cPos
  245. oHpr = oHpr + cHpr
  246. else:
  247. ### copy the actor- not includ its animations
  248. '''
  249. Yeah, Yeah, Yeah, I know I should not reload the Actor but get it from modelpool too.
  250. I tried, but it caused some error.
  251. I 'might' be back to fix this problem.
  252. '''
  253. newName = name+'_copy_%d'%i
  254. while self.isInScene(newName):
  255. newName = newName + '_1'
  256. holder[newName] = Actor.Actor(FilePath.getFullpath())
  257. holderRef[newName] = FilePath
  258. self.ActorNum += 1
  259. holder[newName].reparentTo(parent)
  260. holder[newName].setPos(oPos)
  261. holder[newName].setHpr(oHpr)
  262. holder[newName].setScale(cScale)
  263. holder[newName].setName(newName)
  264. oPos = oPos + cPos
  265. oHpr = oHpr + cHpr
  266. messenger.send('SGE_Update Explorer',[render])
  267. return
  268. def loadModel(self, lFilePath, FilePath, Name='Model_'):
  269. ###########################################################################
  270. # loadModel(self, lFilePath, FilePath, Name='Model_')
  271. # This funciton will load a model node into the scene
  272. # and will keep its reference in the ModelDic dictionary. {"NameOfModel":ModelRoot}
  273. # Also it will keep the file path in ModelRefDic dictionary.
  274. #
  275. # The "lFilePath" parameter now is completely useless,
  276. # but I still keep it here because maybe some day we will need it...
  277. # (NOT because I am laze to change the funtion call in the sceneEditor...)
  278. #
  279. ###########################################################################
  280. self.ModelNum += 1
  281. defaultName = Name + '%d'%self.ModelNum
  282. while self.isInScene(defaultName):
  283. defaultName = defaultName + '_1'
  284. self.ModelDic[defaultName] = loader.loadModel(FilePath)
  285. if self.ModelDic[defaultName]==None:
  286. del self.ModelDic[defaultName]
  287. self.ModelNum -= 1
  288. return False
  289. self.ModelRefDic[defaultName] = FilePath
  290. self.ModelDic[defaultName].setName(defaultName)
  291. self.ModelDic[defaultName].reparentTo(render)
  292. messenger.send('SGE_Update Explorer',[render])
  293. messenger.send('DH_LoadingComplete',[self.ModelDic[defaultName]])
  294. return True
  295. def loadActor(self, lFilePath, FilePath, Name='Actor_'):
  296. ###########################################################################
  297. # loadActor(self, lFilePath, FilePath, Name='Actor_')
  298. # This funciton will load an actor node into the scene
  299. # and will keep its reference in the ActorDic dictionary.{"NameOfActor":Actor}
  300. # Also it will keep the file path in ActorRefDic dictionary.
  301. #
  302. # The "lFilePath" parameter now is completely useless,
  303. # but I still keep it here because maybe some day we will need it...
  304. # (NOT because I am laze to change the funtion call in the sceneEditor...)
  305. #
  306. ###########################################################################
  307. self.ActorNum += 1
  308. defaultName = Name + '%d'%self.ActorNum
  309. while self.isInScene(defaultName):
  310. defaultName = defaultName + '_1'
  311. self.ActorDic[defaultName] = Actor.Actor(FilePath.getFullpath())
  312. if self.ActorDic[defaultName]==None:
  313. del self.ActorDic[defaultName]
  314. self.ActorNum -= 1
  315. return False
  316. self.ActorRefDic[defaultName] = FilePath
  317. self.ActorDic[defaultName].setName(defaultName)
  318. self.ActorDic[defaultName].reparentTo(render)
  319. messenger.send('SGE_Update Explorer',[render])
  320. messenger.send('DH_LoadingComplete',[self.ActorDic[defaultName]])
  321. return True
  322. def isActor(self, name):
  323. ###########################################################################
  324. # isActor(self, name)
  325. # This funciton will return True if there is an Actor in the scene named "name"
  326. # and will return False if not.
  327. ###########################################################################
  328. return self.ActorDic.has_key(name)
  329. def getActor(self, name):
  330. ###########################################################################
  331. # getActor(self, name)
  332. # This funciton will return an Actor node named "name"
  333. ###########################################################################
  334. if self.isActor(name):
  335. return self.ActorDic[name]
  336. else:
  337. print '----No Actor named: ', name
  338. return None
  339. def getModel(self, name):
  340. ###########################################################################
  341. # getModel(self, name)
  342. # This funciton will return a model node named "name"
  343. ###########################################################################
  344. if self.isModel(name):
  345. return self.ModelDic[name]
  346. else:
  347. print '----No Model named: ', name
  348. return None
  349. def isModel(self, name):
  350. ###########################################################################
  351. # isModel(self, name)
  352. # This funciton will return True if there is a Model in the scene named "name"
  353. # and will return False if not.
  354. ###########################################################################
  355. return self.ModelDic.has_key(name)
  356. def loadAnimation(self,name, Dic):
  357. ###########################################################################
  358. # loadAnimation(self,name, Dic)
  359. # This funciton will load animation into an Actor NOde named "name."
  360. # All animation data needs to be put into a dictionary "Dic".
  361. # The formate of this dictionary is {"Name of Animation" : Path to the animation Egg file}
  362. #
  363. # Also, it will send out a message after the loading complete.
  364. # 'DataH_loadFinish'+"the name of actor",
  365. # this message will be catched by the sub window in the animation penal.
  366. ###########################################################################
  367. if self.isActor(name):
  368. self.ActorDic[name].loadAnims(Dic)
  369. for anim in Dic:
  370. self.ActorDic[name].bindAnim(anim)
  371. messenger.send('DataH_loadFinish'+name)
  372. return
  373. else:
  374. print '------ Error when loading animation for Actor: ', name
  375. def removeAnimation(self, name, anim):
  376. ###########################################################################
  377. # removeAnimation(self, name, anim)
  378. # This function will remove the specific animation "anim" from the actor named "name."
  379. #
  380. # After remove compelete, it will send out two messages.
  381. # One is 'DataH_removeAnimFinish'+"name of the actor." It will be caught by Animation Panel of this actor.
  382. # The other is 'animRemovedFromNode,' this will be caught by property window of this actor.
  383. ###########################################################################
  384. if self.isActor(name):
  385. self.ActorDic[name].unloadAnims([anim])
  386. AnimDict = self.ActorDic[name].getAnimControlDict()
  387. del AnimDict['lodRoot']['modelRoot'][anim]
  388. messenger.send('DataH_removeAnimFinish'+name)
  389. messenger.send('animRemovedFromNode',[self.ActorDic[name],self.getAnimationDictFromActor(name)])
  390. return
  391. def toggleLight(self):
  392. ###########################################################################
  393. # toggleLight(self)
  394. # This function do noting but call a function inside the lightManger to toggle the lighting.
  395. # If it is on, then it will turn it to off.
  396. # If it is off, it will turn it on.
  397. ###########################################################################
  398. self.lightManager.toggle()
  399. return
  400. def isLight(self,name):
  401. ###########################################################################
  402. # isLight(self, name)
  403. # This function will check that there is a light named "name" of not.
  404. # If it dose have, then return True.
  405. # If it doesn't, then return False
  406. ###########################################################################
  407. return self.lightManager.isLight(name)
  408. def createLight(self, type = 'ambient',
  409. lightcolor=VBase4(0.3,0.3,0.3,1),
  410. specularColor = VBase4(1),
  411. position = Point3(0,0,0),
  412. orientation = Vec3(1,0,0),
  413. constant = 1.0,
  414. linear = 0.0,
  415. quadratic = 0.0,
  416. exponent = 0.0):
  417. ###########################################################################
  418. # createLight(self, type = 'ambient',
  419. # lightcolor=VBase4(0.3,0.3,0.3,1),
  420. # specularColor = VBase4(1),
  421. # position = Point3(0,0,0),
  422. # orientation = Vec3(1,0,0),
  423. # constant = 1.0,
  424. # linear = 0.0,
  425. # quadratic = 0.0,
  426. # exponent = 0.0)
  427. # It will create a light(seLight) into the scene.
  428. #
  429. # For more detail about creating light, please look the seLight.py.
  430. #
  431. ###########################################################################
  432. list,lightNode = self.lightManager.create(type, lightcolor, specularColor, position,
  433. orientation, constant, linear, quadratic, exponent)
  434. messenger.send('SGE_Update Explorer',[render])
  435. return list, lightNode
  436. def getLightList(self):
  437. ###########################################################################
  438. # getLightList(self)
  439. # This function will return the lights(seLight) as a list.
  440. #
  441. # For more detail about creating light, please look the seLight.py.
  442. #
  443. ###########################################################################
  444. return self.lightManager.getLightList()
  445. def getLightNode(self,lightName):
  446. ###########################################################################
  447. # getLightNode(self,lightName)
  448. # This function will return the lightNode(seLigth) named 'lightName' back.
  449. #
  450. # For more detail about creating light, please look the seLight.py.
  451. #
  452. ###########################################################################
  453. return self.lightManager.getLightNode(lightName)
  454. def toggleLightNode(self, lightNode):
  455. ###########################################################################
  456. # toggleLightNode(self, lightNode)
  457. # This function will enable of disable the lightNode user put in.
  458. #
  459. # For more detail about creating light, please look the seLight.py.
  460. #
  461. ###########################################################################
  462. if lightNode.active:
  463. self.lightManager.setOff(lightNode)
  464. else:
  465. self.lightManager.setOn(lightNode)
  466. return
  467. def rename(self,nodePath,nName):
  468. ###########################################################################
  469. # Rename(self,nodePath,nName)
  470. # First, it will check the target object is legal to rename or not.
  471. # this function now doesn't support user to rename everything on the scene gragh.
  472. # If there already has object hase the same name with the target object,
  473. # the new name will be changed.
  474. ###########################################################################
  475. oName = nodePath.getName()
  476. if oName == nName:
  477. # If the new name is the same with old name, do nothing.
  478. return
  479. while self.isInScene(nName):
  480. nName = nName + '_1'
  481. if self.isActor(oName):
  482. self.ActorDic[nName]= self.ActorDic[oName]
  483. self.ActorRefDic[nName]= self.ActorRefDic[oName]
  484. self.ActorDic[nName].setName(nName)
  485. if self.blendAnimDict.has_key(oName):
  486. self.blendAnimDict[nName] = self.blendAnimDict[oName]
  487. del self.blendAnimDict[oName]
  488. del self.ActorDic[oName]
  489. del self.ActorRefDic[oName]
  490. elif self.isModel(oName):
  491. self.ModelDic[nName]= self.ModelDic[oName]
  492. self.ModelRefDic[nName]= self.ModelRefDic[oName]
  493. self.ModelDic[nName].setName(nName)
  494. del self.ModelDic[oName]
  495. del self.ModelRefDic[oName]
  496. elif self.lightManager.isLight(oName):
  497. list, lightNode = self.lightManager.rename(oName, nName)
  498. elif self.dummyDict.has_key(oName):
  499. self.dummyDict[nName]= self.dummyDict[oName]
  500. self.dummyDict[nName].setName(nName)
  501. del self.dummyDict[oName]
  502. elif self.collisionDict.has_key(oName):
  503. self.collisionDict[nName]= self.collisionDict[oName]
  504. self.collisionDict[nName].setName(nName)
  505. del self.collisionDict[oName]
  506. elif self.particleNodes.has_key(oName):
  507. self.particleNodes[nName]= self.particleNodes[oName]
  508. self.particleDict[nName]= self.particleDict[oName]
  509. self.particleDict[nName].setName(nName)
  510. self.particleNodes[nName].setName(nName)
  511. del self.particleNodes[oName]
  512. del self.particleDict[oName]
  513. else:
  514. print '----Error: This Object is not allowed to this function!'
  515. if self.curveDict.has_key(oName):
  516. self.curveDict[nName] = self.curveDict[oName]
  517. del self.curveDict[oName]
  518. if self.lightManager.isLight(nName):
  519. return list, lightNode
  520. def isInScene(self,name):
  521. ###########################################################################
  522. # isInScene(self,name)
  523. # Return True if there is a Node named "name" inside the scene.
  524. # This will check the whole scene, including model, actor, dummy, collisionObj...
  525. ###########################################################################
  526. if self.isActor(name):
  527. return True
  528. elif self.isModel(name):
  529. return True
  530. elif self.lightManager.isLight(name):
  531. return True
  532. elif self.dummyDict.has_key(name):
  533. return True
  534. elif self.collisionDict.has_key(name):
  535. return True
  536. elif self.particleNodes.has_key(name):
  537. return True
  538. elif (name == 'render')or(name == 'SEditor')or(name == 'Lights')or(name == 'camera'):
  539. return True
  540. return False
  541. def bindCurveToNode(self,node,curveCollection):
  542. ###########################################################################
  543. # bindCurveToNode(self,node,curveCollection)
  544. # This function will maintain the curvesDict
  545. # using the node name as a reference to assosiate a list which contains all curves related to that node.
  546. ###########################################################################
  547. name = node.getName()
  548. if self.curveDict.has_key(name):
  549. self.curveDict[name].append(curveCollection)
  550. return
  551. else:
  552. self.curveDict[name] = [curveCollection]
  553. return
  554. return
  555. def getCurveList(self, nodePath):
  556. ###########################################################################
  557. # getCureveList(self, nodePath)
  558. # This function will return a list
  559. # which contains all curves taht have been binded with the inout node
  560. # If the input node has not been bindedwith any curve, it will return None.
  561. ###########################################################################
  562. name = nodePath.getName()
  563. if self.curveDict.has_key(name):
  564. return self.curveDict[name]
  565. else:
  566. return None
  567. def removeCurveFromNode(self, nodePath, curveName):
  568. ###########################################################################
  569. # removeCurveFromNode(self, nodePath, curveName)
  570. # This function will remove the "curveName" curve(Motion path data) from the nodaPath.
  571. # After remove, it will send out a message.
  572. # 'curveRemovedFromNode'
  573. # This message will be caught by Property Window for this node.
  574. ###########################################################################
  575. name =nodePath.getName()
  576. if self.curveDict.has_key(name):
  577. index = None
  578. for curve in self.curveDict[name]:
  579. if curve.getCurve(0).getName() == curveName:
  580. index = self.curveDict[name].index(curve)
  581. break
  582. del self.curveDict[name][index]
  583. if len(self.curveDict[name])!=0:
  584. messenger.send('curveRemovedFromNode',[nodePath, self.curveDict[name]])
  585. else:
  586. del self.curveDict[name]
  587. messenger.send('curveRemovedFromNode',[nodePath, None])
  588. return
  589. def getInfoOfThisNode(self, nodePath):
  590. ###########################################################################
  591. # getInfoOfThisNode(self, nodePath)
  592. # This function will return a list which contains all object properies
  593. # that will be used in property window.
  594. ###########################################################################
  595. type = ''
  596. info = {}
  597. name = nodePath.getName()
  598. if name == 'render':
  599. type = 'render'
  600. elif name == 'camera':
  601. type = 'camera'
  602. cameraNode = base.cam.node()
  603. lens = cameraNode.getLens()
  604. info['lensType'] = lens.getClassType().getName()
  605. info['far'] = lens.getFar()
  606. info['near'] = lens.getNear()
  607. info['FilmSize'] = lens.getFilmSize()
  608. info['fov'] = lens.getFov()
  609. info['hFov'] = lens.getHfov()
  610. info['vFov'] = lens.getVfov()
  611. info['focalLength'] = lens.getFocalLength()
  612. elif name == 'SEditor':
  613. type = 'Special'
  614. elif self.isActor(name):
  615. type = 'Actor'
  616. info['filePath'] = self.ActorRefDic[name]
  617. info['animDict'] = self.getAnimationDictFromActor(name)
  618. elif self.isModel(name):
  619. type = 'Model'
  620. info['filePath'] = self.ModelRefDic[name]
  621. elif self.isLight(name):
  622. type = 'Light'
  623. info['lightNode'] = self.lightManager.getLightNode(name)
  624. elif self.dummyDict.has_key(name):
  625. type = 'dummy'
  626. elif self.collisionDict.has_key(name):
  627. type = 'collisionNode'
  628. info['collisionNode'] = self.collisionDict[name]
  629. if self.curveDict.has_key(name):
  630. info['curveList'] = self.getCurveList(nodePath)
  631. return type, info
  632. def getAnimationDictFromActor(self, actorName):
  633. ###########################################################################
  634. # getAnimationDictFromActor(self, actorName)
  635. # This function will return a Dictionary which contains the animation data in the actor "actorName".
  636. # The data inside is get from the actor, so, it can't be wrong...
  637. ###########################################################################
  638. animContorlDict = self.ActorDic[actorName].getAnimControlDict()
  639. animNameList = self.ActorDic[actorName].getAnimNames()
  640. if len(animNameList)==0:
  641. return {}
  642. animDict = {}
  643. for anim in animNameList:
  644. animDict[anim] = animContorlDict['lodRoot']['modelRoot'][anim][0]
  645. return animDict
  646. def addDummyNode(self,nodePath):
  647. ###########################################################################
  648. # addDummyNode(self,nodePath)
  649. # This function will add a dummy node into the scane and reparent it to nodePath which user put in.
  650. #
  651. # This dummy actually is just a default sphere model.
  652. #
  653. ###########################################################################
  654. number = len(self.dummyDict)
  655. number += 1
  656. name = 'Dummy%d'%number
  657. self.dummyModel = loader.loadModel( "models/misc/sphere" )
  658. self.dummyModel.reparentTo(nodePath)
  659. while self.isInScene(name):
  660. name = name + '_1'
  661. self.dummyModel.setName(name)
  662. self.dummyDict[name] = self.dummyModel
  663. messenger.send('SGE_Update Explorer',[render])
  664. return
  665. def addCollisionObject(self, collisionObj, nodePath, pointA=None, pointB=None, pointC=None, name = None):
  666. ###########################################################################
  667. # addCollisionObject(self, collisionObj, nodePath, pointA=None, pointB=None, pointC=None, name = None)
  668. # This function will add a collision object into a "CollisionNode" object and put it into scene.
  669. # The collision object will be reparent to "nodePath" and
  670. # will be show on the screen if user has enable the "show collision objects" option.
  671. ###########################################################################
  672. if name == None:
  673. name = 'CollisionNode_%d'%len(self.collisionDict)
  674. while self.isInScene(name):
  675. name=name + '_1'
  676. node = CollisionNode(name)
  677. node.addSolid(collisionObj)
  678. self.collisionDict[name] = nodePath.attachNewNode(node)
  679. if pointA!=None:
  680. self.collisionDict[name].setTag('A_X','%f'%pointA.getX())
  681. self.collisionDict[name].setTag('A_Y','%f'%pointA.getY())
  682. self.collisionDict[name].setTag('A_Z','%f'%pointA.getZ())
  683. self.collisionDict[name].setTag('B_X','%f'%pointB.getX())
  684. self.collisionDict[name].setTag('B_Y','%f'%pointB.getY())
  685. self.collisionDict[name].setTag('B_Z','%f'%pointB.getZ())
  686. self.collisionDict[name].setTag('C_X','%f'%pointC.getX())
  687. self.collisionDict[name].setTag('C_Y','%f'%pointC.getY())
  688. self.collisionDict[name].setTag('C_Z','%f'%pointC.getZ())
  689. if self.collisionVisable:
  690. self.collisionDict[name].show()
  691. #Manakel 2/12/2005: replace node by its nodepath
  692. base.cTrav.addCollider( self.collisionDict[name], self.CollisionHandler)
  693. messenger.send('SGE_Update Explorer',[render])
  694. return
  695. def toggleCollisionVisable(self, visable):
  696. ###########################################################################
  697. # toggleCollisionVisable(self, visable)
  698. # This fucntion will toggle the visibility of all collision node in the scene.
  699. ###########################################################################
  700. if visable == 1:
  701. self.collisionVisable = True
  702. for name in self.collisionDict:
  703. if self.collisionDict[name].isHidden():
  704. self.collisionDict[name].show()
  705. else:
  706. self.collisionVisable = False
  707. for name in self.collisionDict:
  708. if not self.collisionDict[name].isHidden():
  709. self.collisionDict[name].hide()
  710. def toggleParticleVisable(self, visable):
  711. if not visable:
  712. for name in self.particleNodes:
  713. self.particleNodes[name].setTransparency(True)
  714. self.particleNodes[name].setAlphaScale(0)
  715. self.particleNodes[name].setBin("fixed", 1)
  716. else:
  717. for name in self.particleNodes:
  718. self.particleNodes[name].setTransparency(False)
  719. self.particleNodes[name].setAlphaScale(1)
  720. self.particleNodes[name].setBin("default", 1)
  721. return
  722. def getBlendAnimAsDict(self, name):
  723. ###########################################################################
  724. # getBlendAnimAsDict(self, name)
  725. # This function will return a dictionry
  726. # which contains user blended animation data for actor named "name."
  727. # The formate of thsi dictionary is
  728. # {"name of Blend Animation" : ["Animation A, Animation B, Effect(Float, 0~1)"]}
  729. ###########################################################################
  730. if self.blendAnimDict.has_key(name):
  731. return self.blendAnimDict[name]
  732. else:
  733. return {}
  734. def saveBlendAnim(self, actorName, blendName, animNameA, animNameB, effect):
  735. ###########################################################################
  736. # saveBlendAnim(self, actorName, blendName, animNameA, animNameB, effect)
  737. # This function will save the blended Animation "blendname" for actor "actorNane"
  738. # and keep the data in the blendAnimDict.
  739. #
  740. # Also, if this blend is the first blend animation that the target actor has,
  741. # this function will add a "Blending" tag on this actor which is "True".
  742. ###########################################################################
  743. if self.blendAnimDict.has_key(actorName):
  744. if self.blendAnimDict[actorName].has_key(blendName):
  745. ### replace the original setting
  746. self.blendAnimDict[actorName][blendName][0] = animNameA
  747. self.blendAnimDict[actorName][blendName][1] = animNameB
  748. self.blendAnimDict[actorName][blendName][2] = effect
  749. else:
  750. ### create new blend animation in the dictionary
  751. self.blendAnimDict[actorName][blendName] = [animNameA, animNameB, effect]
  752. else:
  753. self.getActor(actorName).setTag('Blending','True')
  754. self.blendAnimDict[actorName] = {blendName:[animNameA, animNameB, effect]}
  755. return self.blendAnimDict[actorName]
  756. def renameBlendAnim(self, actorName, nName, oName, animNameA, animNameB, effect):
  757. ###########################################################################
  758. # renameBlendAnim(self, actorName, nName, oName, animNameA, animNameB, effect)
  759. # This function is used to rename a exist blended animation named "oName" to "nName."
  760. # The way it doing this is first remove the original blend fomr the actor
  761. # and then re-create a new one named "nName" in.
  762. # Because it is not just simply rename the animation,
  763. # it will also rewrite the data to the newest one.
  764. ###########################################################################
  765. self.removeBlendAnim(actorName,oName)
  766. print self.blendAnimDict
  767. return self.saveBlendAnim(actorName, nName, animNameA, animNameB, effect)
  768. def removeBlendAnim(self, actorName, blendName):
  769. ###########################################################################
  770. # removeBlendAnim(self, actorName, blendName)
  771. # This fucntion will remove the record of blended animation named "blendName"
  772. # from the actor named "actorName".
  773. #
  774. # Also, it will check that there is any blended animation remained for this actor,
  775. # If none, this function will clear the "Blending" tag of this object.
  776. ###########################################################################
  777. if self.blendAnimDict.has_key(actorName):
  778. if self.blendAnimDict[actorName].has_key(blendName):
  779. ### replace the original setting
  780. del self.blendAnimDict[actorName][blendName]
  781. if len(self.blendAnimDict[actorName])==0:
  782. del self.blendAnimDict[actorName]
  783. self.getActor(actorName).clearTag('Blending')
  784. return {}
  785. return self.blendAnimDict[actorName]
  786. else:
  787. return {}
  788. def getAllObjNameAsList(self):
  789. ###########################################################################
  790. # getAllObjNameAsList(self)
  791. # This function will return a list which contains all objects' names in the scene.
  792. # It means which won't have any kinds of animation, blend animation or Mopath data inside.
  793. ###########################################################################
  794. list = ['camera'] # Default object you can select camera
  795. list = list + self.ModelDic.keys() \
  796. + self.ActorDic.keys() + self.collisionDict.keys() \
  797. + self.dummyDict.keys() + self.particleNodes.keys() \
  798. + self.lightManager.getLightList()
  799. return list
  800. def getObjFromSceneByName(self, name):
  801. ###########################################################################
  802. # getObjFromSceneByName(self, name)
  803. # return a reference to the nodePath named "name"
  804. ###########################################################################
  805. if name == 'camera':
  806. return camera
  807. elif self.ModelDic.has_key(name):
  808. return self.ModelDic[name]
  809. elif self.ActorDic.has_key(name):
  810. return self.ActorDic[name]
  811. elif self.collisionDict.has_key(name):
  812. return self.collisionDict[name]
  813. elif self.dummyDict.has_key(name):
  814. return self.dummyDict[name]
  815. elif self.particleNodes.has_key(name):
  816. return self.particleNodes[name]
  817. elif self.lightManager.isLight(name):
  818. return self.lightManager.getLightNode(name)
  819. return None
  820. def getControlSetting(self):
  821. ###########################################################################
  822. # getControlSetting(self)
  823. # return tqwo things.
  824. # One is the type of the control. The other is the data about that control.
  825. # Now we only support keyboard control, so it will return a list.
  826. # The first object in the list is a reference to the target we want to control.
  827. # The second object in the list is a dictionary which contains a map about
  828. # which keyboard message should be accepted.
  829. # The third and the last object here is a dictionary which contains the data
  830. # indicating that the changing value for each keyboard control event.
  831. ###########################################################################
  832. if self.controlType == 'Keyboard':
  833. return self.controlType, [self.controlTarget, self.keyboardMapDict.copy(), self.keyboardSpeedDict.copy()]
  834. elif self.controlType == 'Tracker':
  835. return self.controlType, []
  836. return
  837. def saveControlSetting(self, controlType, data):
  838. ###########################################################################
  839. # saveControlSetting(self, controlType, data)
  840. # copy the current control setting into dataHolder
  841. # Mainly called by sceneEditor.
  842. ###########################################################################
  843. if controlType == 'Keyboard':
  844. self.controlType = controlType
  845. self.controlTarget = data[0]
  846. self.keyboardMapDict.clear()
  847. self.keyboardMapDict = data[1].copy()
  848. self.keyboardSpeedDict.clear()
  849. self.keyboardSpeedDict = data[2].copy()
  850. return
  851. def loadScene(self):
  852. ###########################################################################
  853. # loadScene(self)
  854. # Opens a dialog box asking for a scene file to load. It then removes
  855. # the current scene and opens the new one.
  856. # It basically proceeds by executig the python file containing the scene
  857. # and then re-populating the various dictionaries based on the dictionaries
  858. # in the scene file hence reviving the state for the scene
  859. ###########################################################################
  860. ### Ask for a filename
  861. OpenFilename = tkFileDialog.askopenfilename(filetypes = [("PY","py")],title = "Load Scene")
  862. if(not OpenFilename):
  863. return None
  864. f=Filename.fromOsSpecific(OpenFilename)
  865. fileName=f.getBasenameWoExtension()
  866. dirName=f.getFullpathWoExtension()
  867. print "DATAHOLDER::" + dirName
  868. ############################################################################
  869. # Append the path to this file to our sys path where python looks for modules
  870. # We do this so that we can use "import" on our saved scene code and execute it
  871. ############################################################################
  872. sys.path.append(os.path.dirname(f.toOsSpecific()))
  873. ############################################################################
  874. # Actually import the scene... this executes the code in the scene
  875. ############################################################################
  876. self.theScene=__import__(fileName)
  877. self.Scene=self.theScene.SavedScene(0,seParticleEffect,seParticles,dirName) # Specify load mode of 0 which will allow us to pass seParticle and seParticleEffect
  878. messenger.send('SGE_Update Explorer',[render])
  879. # Lets call some important initialization methods on our scene:
  880. #self.Scene.starteffects(0,seParticleEffect,seParticles,dirName) # This special calling of start effect with mode 0 is to use seParticleEffect and seParticles
  881. ############################################################################
  882. # Populate Model related Dictionaries
  883. ############################################################################
  884. for model in self.Scene.ModelDic:
  885. self.ModelDic[model]=self.Scene.ModelDic[model]
  886. #self.ModelRefDic[model]=self.Scene.ModelRefDic[model] # The Old absolute paths way
  887. self.ModelRefDic[model]=Filename(dirName + "/" + self.Scene.ModelRefDic[model]) # Relative Paths
  888. self.ModelNum=self.ModelNum+1
  889. ############################################################################
  890. # Populate Actor related Dictionaries
  891. ############################################################################
  892. for actor in self.Scene.ActorDic:
  893. self.ActorDic[actor]=self.Scene.ActorDic[actor]
  894. #self.ActorRefDic[actor]=self.Scene.ActorRefDic[actor] # Old way of doing absolute paths
  895. self.ActorRefDic[actor]=Filename(dirName + "/" + self.Scene.ActorRefDic[actor]) # Relative Paths
  896. if(self.Scene.blendAnimDict.has_key(str(actor))):
  897. self.blendAnimDict[actor]=self.Scene.blendAnimDict[actor]
  898. self.ActorNum=self.ActorNum+1
  899. ############################################################################
  900. # Populate Light related Dictionaries
  901. ############################################################################
  902. #print self.Scene.LightDict
  903. for light in self.Scene.LightDict:
  904. #print light
  905. alight=self.Scene.LightDict[light]
  906. type=self.Scene.LightTypes[light]
  907. thenode=self.Scene.LightNodes[light]
  908. #print type
  909. if type == 'ambient':
  910. self.lightManager.create('ambient',alight.getColor(),name=alight.getName(),tag=thenode.getTag("Metadata"))
  911. elif type == 'directional':
  912. #print alight.getPoint()
  913. #print alight.getDirection()
  914. self.lightManager.create('directional',alight.getColor(),alight.getSpecularColor(),thenode.getPos(),thenode.getHpr(),name=alight.getName(),tag=thenode.getTag("Metadata"))
  915. elif type == 'point':
  916. atten=alight.getAttenuation()
  917. #print alight.getPoint()
  918. self.lightManager.create('point',alight.getColor(),alight.getSpecularColor(),thenode.getPos(),Vec3(1,0,0),atten.getX(),atten.getY(),atten.getZ(),name=alight.getName(),tag=thenode.getTag("Metadata"))
  919. elif type == 'spot':
  920. atten=alight.getAttenuation()
  921. self.lightManager.create('spot',alight.getColor(),alight.getSpecularColor(),thenode.getPos(),thenode.getHpr(),atten.getX(),atten.getY(),atten.getZ(),alight.getExponent(),name=alight.getName(),tag=thenode.getTag("Metadata"))
  922. else:
  923. print 'Invalid light type'
  924. ############################################################################
  925. # Populate Dummy related Dictionaries
  926. ############################################################################
  927. for dummy in self.Scene.dummyDict:
  928. self.dummyDict[dummy] = self.Scene.dummyDict[dummy]
  929. ############################################################################
  930. # Populate Collision related Dictionaries
  931. ############################################################################
  932. for collnode in self.Scene.collisionDict:
  933. self.collisionDict[collnode]=self.Scene.collisionDict[collnode]
  934. ############################################################################
  935. # Populate Mopath related Dictionaries
  936. ############################################################################
  937. for node in self.Scene.curveDict:
  938. curveCollection=self.Scene.curveDict[node]
  939. for curve in curveCollection:
  940. curveColl=ParametricCurveCollection()
  941. nodeP=loader.loadModel(curve)
  942. curveColl.addCurves(nodeP.node())
  943. nodeP.removeNode()
  944. thenode=render.find("**/"+str(node))
  945. self.bindCurveToNode(thenode,curveColl)
  946. ############################################################################
  947. # Populate Particle related Dictionaries
  948. ############################################################################
  949. for effect in self.Scene.particleDict:
  950. theeffect=self.Scene.particleDict[effect]
  951. emitter=loader.loadModel("sphere")
  952. emitter.setPosHprScale(theeffect.getX(),theeffect.getY(),theeffect.getZ(),theeffect.getH(),theeffect.getP(),theeffect.getR(),theeffect.getSx(),theeffect.getSy(),theeffect.getSz())
  953. theeffect.setPos(0,0,0)
  954. theeffect.setName(str(effect))
  955. tempparent=theeffect.getParent()
  956. theeffect.reparentTo(emitter)
  957. emitter.setName(str(effect))
  958. emitter.reparentTo(tempparent)
  959. theeffect.enable()
  960. self.particleDict[effect]=theeffect
  961. self.particleNodes[effect]=emitter
  962. # Clean up things added to scene graph by saved file's code execution
  963. for light in self.Scene.LightDict:
  964. vestige=render.find('**/'+light)
  965. if(vestige != None):
  966. vestige.removeNode()
  967. ############################################################################
  968. # return the filename and update the scenegraph explorer window
  969. ############################################################################
  970. messenger.send('SGE_Update Explorer',[render])
  971. if(OpenFilename):
  972. return OpenFilename
  973. else:
  974. return None
  975. def getList(self):
  976. return self.lightManager.getList()