184 lines
5.8 KiB
Python
Executable File
184 lines
5.8 KiB
Python
Executable File
"""
|
|
Base class for Level Editor
|
|
|
|
You should write your own LevelEditor class inheriting this.
|
|
Refer LevelEditor.py for example.
|
|
"""
|
|
|
|
from pandac.PandaModules import *
|
|
from direct.showbase.ShowBase import *
|
|
from direct.showbase.DirectObject import *
|
|
from direct.directtools.DirectGlobals import *
|
|
|
|
base = ShowBase(False)
|
|
|
|
from ObjectMgr import *
|
|
from FileMgr import *
|
|
|
|
class LevelEditorBase(DirectObject):
|
|
""" Base Class for Panda3D LevelEditor """
|
|
def __init__(self):
|
|
#loadPrcFileData('startup', 'window-type none')
|
|
self.currentFile = None
|
|
self.actionEvents = []
|
|
self.objectMgr = ObjectMgr(self)
|
|
self.fileMgr = FileMgr(self)
|
|
|
|
# define your own config file in inherited class
|
|
self.settingsFile = None
|
|
|
|
def initialize(self):
|
|
""" You should call this in your __init__ method of inherited LevelEditor class """
|
|
fTk = base.config.GetBool('want-tk', 0)
|
|
fWx = 0
|
|
base.startDirect(fWantTk = fTk, fWantWx = fWx)
|
|
base.closeWindow(base.win)
|
|
base.win = base.winList[3]
|
|
|
|
base.direct.cameraControl.lockRoll = True
|
|
base.direct.setFScaleWidgetByCam(1)
|
|
|
|
unpickables = [
|
|
"z-guide",
|
|
"y-guide",
|
|
"x-guide",
|
|
"x-disc-geom",
|
|
"x-ring-line",
|
|
"x-post-line",
|
|
"y-disc-geom",
|
|
"y-ring-line",
|
|
"y-post-line",
|
|
"z-disc-geom",
|
|
"z-ring-line",
|
|
"z-post-line",
|
|
"centerLines",
|
|
"majorLines",
|
|
"minorLines",
|
|
"Sphere",]
|
|
|
|
for unpickable in unpickables:
|
|
base.direct.addUnpickable(unpickable)
|
|
|
|
base.direct.manipulationControl.optionalSkipFlags |= SKIP_UNPICKABLE
|
|
base.direct.manipulationControl.fAllowMarquee = 1
|
|
base.direct.manipulationControl.supportMultiView()
|
|
base.direct.cameraControl.useMayaCamControls = 1
|
|
|
|
# [gjeon] to handle delete here first
|
|
base.direct.ignore('DIRECT-delete')
|
|
|
|
# [gjeon] do not use the old way of finding current DR
|
|
base.direct.drList.tryToGetCurrentDr = False
|
|
|
|
# specifiy what obj can be 'selected' as objects
|
|
base.direct.selected.addTag('OBJRoot')
|
|
|
|
self.actionEvents.extend([
|
|
# Node path events
|
|
('DIRECT-delete', self.handleDelete),
|
|
('preRemoveNodePath', self.removeNodePathHook),
|
|
('DIRECT_selectedNodePath_fMulti_fTag', self.selectedNodePathHook),
|
|
('DIRECT_deselectAll', self.deselectAll),
|
|
])
|
|
|
|
# Add all the action events
|
|
for event in self.actionEvents:
|
|
if len(event) == 3:
|
|
self.accept(event[0], event[1], event[2])
|
|
else:
|
|
self.accept(event[0], event[1])
|
|
|
|
self.loadSettings()
|
|
|
|
def removeNodePathHook(self, nodePath):
|
|
if nodePath is None:
|
|
return
|
|
base.direct.deselect(nodePath)
|
|
self.objectMgr.removeObjectByNodePath(nodePath)
|
|
|
|
if (base.direct.selected.last != None and nodePath.compareTo(base.direct.selected.last)==0):
|
|
# if base.direct.selected.last is refering to this
|
|
# removed obj, clear the reference
|
|
if (hasattr(__builtins__,'last')):
|
|
__builtins__.last = None
|
|
else:
|
|
__builtins__['last'] = None
|
|
base.direct.selected.last = None
|
|
|
|
def handleDelete(self):
|
|
reply = wx.MessageBox("Do you want to delete selected?", "Delete?",
|
|
wx.YES_NO | wx.ICON_QUESTION)
|
|
if reply == wx.YES:
|
|
base.direct.removeAllSelected()
|
|
self.objectMgr.deselectAll()
|
|
else:
|
|
# need to reset COA
|
|
dnp = base.direct.selected.last
|
|
# Update camera controls coa to this point
|
|
# Coa2Camera = Coa2Dnp * Dnp2Camera
|
|
mCoa2Camera = dnp.mCoa2Dnp * dnp.getMat(base.direct.camera)
|
|
row = mCoa2Camera.getRow(3)
|
|
coa = Vec3(row[0], row[1], row[2])
|
|
base.direct.cameraControl.updateCoa(coa)
|
|
|
|
def selectedNodePathHook(self, nodePath, fMultiSelect = 0, fSelectTag = 1):
|
|
# handle unpickable nodepath
|
|
if nodePath.getName() in base.direct.iRay.unpickable:
|
|
base.direct.deselect(nodePath)
|
|
return
|
|
|
|
self.objectMgr.selectObject(nodePath)
|
|
|
|
def deselectAll(self):
|
|
self.objectMgr.deselectAll()
|
|
|
|
def reset(self):
|
|
base.direct.deselectAll()
|
|
self.objectMgr.reset()
|
|
|
|
def save(self):
|
|
if self.currentFile:
|
|
self.fileMgr.saveToFile(self.currentFile)
|
|
|
|
def saveAs(self, fileName):
|
|
self.fileMgr.saveToFile(fileName)
|
|
|
|
def load(self, fileName):
|
|
self.reset()
|
|
self.fileMgr.loadFromFile(fileName)
|
|
self.currentFile = fileName
|
|
|
|
def saveSettings(self):
|
|
if self.settingsFile is None:
|
|
return
|
|
|
|
try:
|
|
f = open(self.settingsFile, 'w')
|
|
f.write('gridSize %f\n'%self.ui.perspView.grid.gridSize)
|
|
f.write('gridSpacing %f\n'%self.ui.perspView.grid.gridSpacing)
|
|
f.close()
|
|
except:
|
|
pass
|
|
|
|
def loadSettings(self):
|
|
if self.settingsFile is None:
|
|
return
|
|
|
|
try:
|
|
f = open(self.settingsFile, 'r')
|
|
configLines = f.readlines()
|
|
f.close()
|
|
|
|
gridSize = 100.0
|
|
gridSpacing = 5.0
|
|
for line in configLines:
|
|
if line.startswith('gridSize'):
|
|
gridSize = float(line.split()[1])
|
|
elif line.startswith('gridSpacing'):
|
|
gridSpacing = float(line.split()[1])
|
|
|
|
self.ui.updateGrids(gridSize, gridSpacing)
|
|
except:
|
|
pass
|
|
|