LevelEditorBase.py 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. """
  2. Base class for Level Editor
  3. You should write your own LevelEditor class inheriting this.
  4. Refer LevelEditor.py for example.
  5. """
  6. from pandac.PandaModules import *
  7. from direct.showbase.ShowBase import *
  8. from direct.showbase.DirectObject import *
  9. from direct.directtools.DirectGlobals import *
  10. base = ShowBase(False)
  11. from ObjectMgr import *
  12. from FileMgr import *
  13. from ProtoPalette import *
  14. class LevelEditorBase(DirectObject):
  15. """ Base Class for Panda3D LevelEditor """
  16. def __init__(self):
  17. #loadPrcFileData('startup', 'window-type none')
  18. self.currentFile = None
  19. self.actionEvents = []
  20. self.objectMgr = ObjectMgr(self)
  21. self.fileMgr = FileMgr(self)
  22. self.protoPalette = ProtoPalette()
  23. # define your own config file in inherited class
  24. self.settingsFile = None
  25. def initialize(self):
  26. """ You should call this in your __init__ method of inherited LevelEditor class """
  27. fTk = base.config.GetBool('want-tk', 0)
  28. fWx = 0
  29. base.startDirect(fWantTk = fTk, fWantWx = fWx)
  30. base.closeWindow(base.win)
  31. base.win = base.winList[3]
  32. base.direct.cameraControl.lockRoll = True
  33. base.direct.setFScaleWidgetByCam(1)
  34. unpickables = [
  35. "z-guide",
  36. "y-guide",
  37. "x-guide",
  38. "x-disc-geom",
  39. "x-ring-line",
  40. "x-post-line",
  41. "y-disc-geom",
  42. "y-ring-line",
  43. "y-post-line",
  44. "z-disc-geom",
  45. "z-ring-line",
  46. "z-post-line",
  47. "centerLines",
  48. "majorLines",
  49. "minorLines",
  50. "Sphere",]
  51. for unpickable in unpickables:
  52. base.direct.addUnpickable(unpickable)
  53. base.direct.manipulationControl.optionalSkipFlags |= SKIP_UNPICKABLE
  54. base.direct.manipulationControl.fAllowMarquee = 1
  55. base.direct.manipulationControl.supportMultiView()
  56. base.direct.cameraControl.useMayaCamControls = 1
  57. # [gjeon] to handle delete here first
  58. base.direct.ignore('DIRECT-delete')
  59. # [gjeon] do not use the old way of finding current DR
  60. base.direct.drList.tryToGetCurrentDr = False
  61. # specifiy what obj can be 'selected' as objects
  62. base.direct.selected.addTag('OBJRoot')
  63. self.actionEvents.extend([
  64. # Node path events
  65. ('DIRECT-delete', self.handleDelete),
  66. ('preRemoveNodePath', self.removeNodePathHook),
  67. ('DIRECT_selectedNodePath_fMulti_fTag', self.selectedNodePathHook),
  68. ('DIRECT_deselectAll', self.deselectAll),
  69. ])
  70. # Add all the action events
  71. for event in self.actionEvents:
  72. if len(event) == 3:
  73. self.accept(event[0], event[1], event[2])
  74. else:
  75. self.accept(event[0], event[1])
  76. self.loadSettings()
  77. def removeNodePathHook(self, nodePath):
  78. if nodePath is None:
  79. return
  80. base.direct.deselect(nodePath)
  81. self.objectMgr.removeObjectByNodePath(nodePath)
  82. if (base.direct.selected.last != None and nodePath.compareTo(base.direct.selected.last)==0):
  83. # if base.direct.selected.last is refering to this
  84. # removed obj, clear the reference
  85. if (hasattr(__builtins__,'last')):
  86. __builtins__.last = None
  87. else:
  88. __builtins__['last'] = None
  89. base.direct.selected.last = None
  90. def handleDelete(self):
  91. reply = wx.MessageBox("Do you want to delete selected?", "Delete?",
  92. wx.YES_NO | wx.ICON_QUESTION)
  93. if reply == wx.YES:
  94. base.direct.removeAllSelected()
  95. self.objectMgr.deselectAll()
  96. else:
  97. # need to reset COA
  98. dnp = base.direct.selected.last
  99. # Update camera controls coa to this point
  100. # Coa2Camera = Coa2Dnp * Dnp2Camera
  101. mCoa2Camera = dnp.mCoa2Dnp * dnp.getMat(base.direct.camera)
  102. row = mCoa2Camera.getRow(3)
  103. coa = Vec3(row[0], row[1], row[2])
  104. base.direct.cameraControl.updateCoa(coa)
  105. def selectedNodePathHook(self, nodePath, fMultiSelect = 0, fSelectTag = 1):
  106. # handle unpickable nodepath
  107. if nodePath.getName() in base.direct.iRay.unpickable:
  108. base.direct.deselect(nodePath)
  109. return
  110. self.objectMgr.selectObject(nodePath)
  111. def deselectAll(self):
  112. self.objectMgr.deselectAll()
  113. def reset(self):
  114. base.direct.deselectAll()
  115. self.objectMgr.reset()
  116. def save(self):
  117. if self.currentFile:
  118. self.fileMgr.saveToFile(self.currentFile)
  119. def saveAs(self, fileName):
  120. self.fileMgr.saveToFile(fileName)
  121. def load(self, fileName):
  122. self.reset()
  123. self.fileMgr.loadFromFile(fileName)
  124. self.currentFile = fileName
  125. def saveSettings(self):
  126. if self.settingsFile is None:
  127. return
  128. try:
  129. f = open(self.settingsFile, 'w')
  130. f.write('gridSize\n%f\n'%self.ui.perspView.grid.gridSize)
  131. f.write('gridSpacing\n%f\n'%self.ui.perspView.grid.gridSpacing)
  132. f.write('hotKey\n%s\n'%base.direct.hotKeyMap)
  133. f.close()
  134. except:
  135. pass
  136. def loadSettings(self):
  137. if self.settingsFile is None:
  138. return
  139. try:
  140. f = open(self.settingsFile, 'r')
  141. configLines = f.readlines()
  142. f.close()
  143. gridSize = 100.0
  144. gridSpacing = 5.0
  145. for i in range(0, len(configLines)):
  146. line = configLines[i]
  147. i = i + 1
  148. if line.startswith('gridSize'):
  149. gridSize = float(configLines[i])
  150. elif line.startswith('gridSpacing'):
  151. gridSpacing = float(configLines[i])
  152. elif line.startswith('hotKey'):
  153. base.direct.hotKeyMap = eval(configLines[i])
  154. self.ui.updateGrids(gridSize, gridSpacing)
  155. except:
  156. pass