dataHolder.py 50 KB

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