mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-03 10:22:45 -04:00
Added object duplication and grid snapping
This commit is contained in:
parent
d1d8685fe5
commit
47b9e90b4c
@ -19,6 +19,7 @@ class LevelEditorBase(DirectObject):
|
|||||||
""" Base Class for Panda3D LevelEditor """
|
""" Base Class for Panda3D LevelEditor """
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
#loadPrcFileData('startup', 'window-type none')
|
#loadPrcFileData('startup', 'window-type none')
|
||||||
|
self.currentFile = None
|
||||||
self.actionEvents = []
|
self.actionEvents = []
|
||||||
self.objectMgr = ObjectMgr(self)
|
self.objectMgr = ObjectMgr(self)
|
||||||
self.fileMgr = FileMgr(self)
|
self.fileMgr = FileMgr(self)
|
||||||
@ -130,9 +131,14 @@ class LevelEditorBase(DirectObject):
|
|||||||
base.direct.deselectAll()
|
base.direct.deselectAll()
|
||||||
self.objectMgr.reset()
|
self.objectMgr.reset()
|
||||||
|
|
||||||
def save(self, fileName):
|
def save(self):
|
||||||
|
if self.currentFile:
|
||||||
|
self.fileMgr.saveToFile(self.currentFile)
|
||||||
|
|
||||||
|
def saveAs(self, fileName):
|
||||||
self.fileMgr.saveToFile(fileName)
|
self.fileMgr.saveToFile(fileName)
|
||||||
|
|
||||||
def load(self, fileName):
|
def load(self, fileName):
|
||||||
self.reset()
|
self.reset()
|
||||||
self.fileMgr.loadFromFile(fileName)
|
self.fileMgr.loadFromFile(fileName)
|
||||||
|
self.currentFile = fileName
|
||||||
|
@ -48,6 +48,18 @@ class LevelEditorUI(WxAppShell):
|
|||||||
|
|
||||||
menuItem = self.menuFile.Insert(2, -1 , "&Save")
|
menuItem = self.menuFile.Insert(2, -1 , "&Save")
|
||||||
self.Bind(wx.EVT_MENU, self.onSave, menuItem)
|
self.Bind(wx.EVT_MENU, self.onSave, menuItem)
|
||||||
|
|
||||||
|
menuItem = self.menuFile.Insert(3, -1 , "Save &As")
|
||||||
|
self.Bind(wx.EVT_MENU, self.onSaveAs, menuItem)
|
||||||
|
|
||||||
|
self.menuEdit = wx.Menu()
|
||||||
|
self.menuBar.Insert(1, self.menuEdit, "&Edit")
|
||||||
|
|
||||||
|
menuItem = self.menuEdit.Append(-1, "&Duplicate")
|
||||||
|
self.Bind(wx.EVT_MENU, self.onDuplicate, menuItem)
|
||||||
|
|
||||||
|
self.gridSnapMenuItem = self.menuEdit.Append(-1, "&Grid Snap", kind = wx.ITEM_CHECK)
|
||||||
|
self.Bind(wx.EVT_MENU, self.toggleGridSnap, self.gridSnapMenuItem)
|
||||||
|
|
||||||
def createInterface(self):
|
def createInterface(self):
|
||||||
self.createMenu()
|
self.createMenu()
|
||||||
@ -132,7 +144,22 @@ class LevelEditorUI(WxAppShell):
|
|||||||
dialog.Destroy()
|
dialog.Destroy()
|
||||||
|
|
||||||
def onSave(self, evt):
|
def onSave(self, evt):
|
||||||
|
if self.editor.currentFile is None:
|
||||||
|
self.onSaveAs(evt)
|
||||||
|
else:
|
||||||
|
self.editor.save()
|
||||||
|
|
||||||
|
def onSaveAs(self, evt):
|
||||||
dialog = wx.FileDialog(None, "Choose a file", os.getcwd(), "", "*.py", wx.SAVE)
|
dialog = wx.FileDialog(None, "Choose a file", os.getcwd(), "", "*.py", wx.SAVE)
|
||||||
if dialog.ShowModal() == wx.ID_OK:
|
if dialog.ShowModal() == wx.ID_OK:
|
||||||
self.editor.save(dialog.GetPath())
|
self.editor.saveAs(dialog.GetPath())
|
||||||
dialog.Destroy()
|
dialog.Destroy()
|
||||||
|
|
||||||
|
def onDuplicate(self, evt):
|
||||||
|
self.editor.objectMgr.duplicateSelected()
|
||||||
|
|
||||||
|
def toggleGridSnap(self, evt):
|
||||||
|
if self.gridSnapMenuItem.IsChecked():
|
||||||
|
base.direct.manipulationControl.fGridSnap = 1
|
||||||
|
else:
|
||||||
|
base.direct.manipulationControl.fGridSnap = 0
|
||||||
|
@ -56,8 +56,6 @@ class ObjectHandler:
|
|||||||
b.reparentTo(objNP)
|
b.reparentTo(objNP)
|
||||||
a.removeNode()
|
a.removeNode()
|
||||||
|
|
||||||
base.direct.select(objNP)
|
|
||||||
|
|
||||||
def createPanda(self):
|
def createPanda(self):
|
||||||
pandaActor = PandaActor()
|
pandaActor = PandaActor()
|
||||||
return pandaActor
|
return pandaActor
|
||||||
|
@ -57,7 +57,7 @@ class ObjectMgr:
|
|||||||
self.lastUidMod = 0
|
self.lastUidMod = 0
|
||||||
return newUid
|
return newUid
|
||||||
|
|
||||||
def addNewObject(self, typeName, uid = None, model = None, parent=None):
|
def addNewObject(self, typeName, uid = None, model = None, parent=None, fSelectObject=True):
|
||||||
""" function to add new obj to the scene """
|
""" function to add new obj to the scene """
|
||||||
if parent is None:
|
if parent is None:
|
||||||
parent = render
|
parent = render
|
||||||
@ -93,9 +93,8 @@ class ObjectMgr:
|
|||||||
|
|
||||||
if uid is None:
|
if uid is None:
|
||||||
uid = self.genUniqueId()
|
uid = self.genUniqueId()
|
||||||
isLoadingArea = False
|
|
||||||
else:
|
else:
|
||||||
isLoadingArea = True
|
fSelectObject = False
|
||||||
|
|
||||||
# populate obj data using default values
|
# populate obj data using default values
|
||||||
properties = {}
|
properties = {}
|
||||||
@ -106,7 +105,7 @@ class ObjectMgr:
|
|||||||
self.objects[uid] = [uid, newobj, objDef, model, properties]
|
self.objects[uid] = [uid, newobj, objDef, model, properties]
|
||||||
self.npIndex[NodePath(newobj)] = uid
|
self.npIndex[NodePath(newobj)] = uid
|
||||||
|
|
||||||
if not isLoadingArea:
|
if fSelectObject:
|
||||||
base.direct.select(newobj)
|
base.direct.select(newobj)
|
||||||
|
|
||||||
return newobj
|
return newobj
|
||||||
@ -235,12 +234,8 @@ class ObjectMgr:
|
|||||||
np.setSy(float(self.editor.ui.objectPropertyUI.propSY.getValue()))
|
np.setSy(float(self.editor.ui.objectPropertyUI.propSY.getValue()))
|
||||||
np.setSz(float(self.editor.ui.objectPropertyUI.propSZ.getValue()))
|
np.setSz(float(self.editor.ui.objectPropertyUI.propSZ.getValue()))
|
||||||
|
|
||||||
def updateObjectModel(self, event, obj):
|
def updateObjectModel(self, model, obj, fSelectObject=True):
|
||||||
""" replace object's model """
|
""" replace object's model """
|
||||||
model = event.GetString()
|
|
||||||
if model is None:
|
|
||||||
return
|
|
||||||
|
|
||||||
if obj[OG.OBJ_MODEL] != model:
|
if obj[OG.OBJ_MODEL] != model:
|
||||||
base.direct.deselectAll()
|
base.direct.deselectAll()
|
||||||
|
|
||||||
@ -269,8 +264,16 @@ class ObjectMgr:
|
|||||||
obj[OG.OBJ_NP] = newobj
|
obj[OG.OBJ_NP] = newobj
|
||||||
obj[OG.OBJ_MODEL] = model
|
obj[OG.OBJ_MODEL] = model
|
||||||
self.npIndex[NodePath(newobj)] = obj[OG.OBJ_UID]
|
self.npIndex[NodePath(newobj)] = obj[OG.OBJ_UID]
|
||||||
|
|
||||||
base.direct.select(newobj)
|
if fSelectObject:
|
||||||
|
base.direct.select(newobj)
|
||||||
|
|
||||||
|
|
||||||
|
def updateObjectModelFromUI(self, event, obj):
|
||||||
|
""" replace object's model with one selected from UI """
|
||||||
|
model = event.GetString()
|
||||||
|
if model is not None:
|
||||||
|
self.updateObjectModel(model, obj)
|
||||||
|
|
||||||
def updateObjectProperty(self, event, obj, propName):
|
def updateObjectProperty(self, event, obj, propName):
|
||||||
"""
|
"""
|
||||||
@ -329,7 +332,7 @@ class ObjectMgr:
|
|||||||
# now update object prop value and call update function
|
# now update object prop value and call update function
|
||||||
self.updateObjectPropValue(obj, propName, val)
|
self.updateObjectPropValue(obj, propName, val)
|
||||||
|
|
||||||
def updateObjectPropValue(self, obj, propName, val):
|
def updateObjectPropValue(self, obj, propName, val, fSelectObject=True):
|
||||||
"""
|
"""
|
||||||
Update object property value and
|
Update object property value and
|
||||||
call update function if defined.
|
call update function if defined.
|
||||||
@ -368,6 +371,9 @@ class ObjectMgr:
|
|||||||
# finally call update function
|
# finally call update function
|
||||||
func(**kwargs)
|
func(**kwargs)
|
||||||
|
|
||||||
|
if fSelectObject:
|
||||||
|
base.direct.select(obj[OG.OBJ_NP])
|
||||||
|
|
||||||
def updateObjectProperties(self, nodePath, propValues):
|
def updateObjectProperties(self, nodePath, propValues):
|
||||||
"""
|
"""
|
||||||
When a saved level is loaded,
|
When a saved level is loaded,
|
||||||
@ -417,5 +423,51 @@ class ObjectMgr:
|
|||||||
self.saveData = []
|
self.saveData = []
|
||||||
self.traverse(render)
|
self.traverse(render)
|
||||||
return self.saveData
|
return self.saveData
|
||||||
|
|
||||||
|
def duplicateObject(self, nodePath, parent=None):
|
||||||
|
obj = self.findObjectByNodePath(nodePath)
|
||||||
|
if obj is None:
|
||||||
|
return None
|
||||||
|
objDef = obj[OG.OBJ_DEF]
|
||||||
|
if parent is None:
|
||||||
|
parent = nodePath.getParent()
|
||||||
|
|
||||||
|
newObjNP = self.addNewObject(objDef.name, parent=parent, fSelectObject = False)
|
||||||
|
|
||||||
|
# copy transform data
|
||||||
|
newObjNP.setPos(obj[OG.OBJ_NP].getPos())
|
||||||
|
newObjNP.setHpr(obj[OG.OBJ_NP].getHpr())
|
||||||
|
newObjNP.setScale(obj[OG.OBJ_NP].getScale())
|
||||||
|
|
||||||
|
newObj = self.findObjectByNodePath(NodePath(newObjNP))
|
||||||
|
if newObj is None:
|
||||||
|
return None
|
||||||
|
# copy model info
|
||||||
|
self.updateObjectModel(obj[OG.OBJ_MODEL], newObj, fSelectObject=False)
|
||||||
|
|
||||||
|
# copy other properties
|
||||||
|
for key in obj[OG.OBJ_PROP]:
|
||||||
|
self.updateObjectPropValue(newObj, key, obj[OG.OBJ_PROP][key], fSelectObject=False)
|
||||||
|
|
||||||
|
return newObjNP
|
||||||
|
|
||||||
|
def duplicateChild(self, nodePath, parent):
|
||||||
|
children = nodePath.findAllMatches('=OBJRoot')
|
||||||
|
for childNP in children:
|
||||||
|
newChildObjNP = self.duplicateObject(childNP, parent)
|
||||||
|
if newChildObjNP is not None:
|
||||||
|
self.duplicateChild(childNP, newChildObjNP)
|
||||||
|
|
||||||
|
def duplicateSelected(self):
|
||||||
|
selectedNPs = base.direct.selected.getSelectedAsList()
|
||||||
|
duplicatedNPs = []
|
||||||
|
for nodePath in selectedNPs:
|
||||||
|
newObjNP = self.duplicateObject(nodePath)
|
||||||
|
if newObjNP is not None:
|
||||||
|
self.duplicateChild(nodePath, newObjNP)
|
||||||
|
duplicatedNPs.append(newObjNP)
|
||||||
|
|
||||||
|
base.direct.deselectAll()
|
||||||
|
print duplicatedNPs
|
||||||
|
for newNodePath in duplicatedNPs:
|
||||||
|
base.direct.select(newNodePath, fMultiSelect = 1)
|
||||||
|
@ -173,7 +173,7 @@ class ObjectPropertyUI(ScrolledPanel):
|
|||||||
|
|
||||||
propUI.bindFunc(self.editor.objectMgr.onEnterObjectPropUI,
|
propUI.bindFunc(self.editor.objectMgr.onEnterObjectPropUI,
|
||||||
self.editor.objectMgr.onLeaveObjectPropUI,
|
self.editor.objectMgr.onLeaveObjectPropUI,
|
||||||
lambda p0=None, p1=obj: self.editor.objectMgr.updateObjectModel(p0, p1))
|
lambda p0=None, p1=obj: self.editor.objectMgr.updateObjectModelFromUI(p0, p1))
|
||||||
|
|
||||||
for key in objDef.properties.keys():
|
for key in objDef.properties.keys():
|
||||||
propDef = objDef.properties[key]
|
propDef = objDef.properties[key]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user