Browse Source

Added object duplication and grid snapping

Gyedo Jeon 16 years ago
parent
commit
47b9e90b4c

+ 7 - 1
direct/src/leveleditor/LevelEditorBase.py

@@ -19,6 +19,7 @@ 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)
@@ -130,9 +131,14 @@ class LevelEditorBase(DirectObject):
         base.direct.deselectAll()
         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)
 
     def load(self, fileName):
         self.reset()
         self.fileMgr.loadFromFile(fileName)
+        self.currentFile = fileName

+ 28 - 1
direct/src/leveleditor/LevelEditorUI.py

@@ -48,6 +48,18 @@ class LevelEditorUI(WxAppShell):
 
         menuItem = self.menuFile.Insert(2, -1 , "&Save")
         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):
         self.createMenu()
@@ -132,7 +144,22 @@ class LevelEditorUI(WxAppShell):
         dialog.Destroy()
 
     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)
         if dialog.ShowModal() == wx.ID_OK:
-            self.editor.save(dialog.GetPath())
+            self.editor.saveAs(dialog.GetPath())
         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            

+ 0 - 2
direct/src/leveleditor/ObjectHandler.py

@@ -56,8 +56,6 @@ class ObjectHandler:
             b.reparentTo(objNP)
             a.removeNode()
 
-        base.direct.select(objNP)
-
     def createPanda(self):
         pandaActor = PandaActor()
         return pandaActor

+ 65 - 13
direct/src/leveleditor/ObjectMgr.py

@@ -57,7 +57,7 @@ class ObjectMgr:
             self.lastUidMod = 0
         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 """
         if parent is None:
             parent = render
@@ -93,9 +93,8 @@ class ObjectMgr:
 
             if uid is None:
                 uid = self.genUniqueId()
-                isLoadingArea = False
             else:
-                isLoadingArea = True
+                fSelectObject = False
 
             # populate obj data using default values
             properties = {}
@@ -106,7 +105,7 @@ class ObjectMgr:
             self.objects[uid] = [uid, newobj, objDef, model, properties]
             self.npIndex[NodePath(newobj)] = uid
 
-            if not isLoadingArea:
+            if fSelectObject:
                 base.direct.select(newobj)
 
         return newobj
@@ -235,12 +234,8 @@ class ObjectMgr:
         np.setSy(float(self.editor.ui.objectPropertyUI.propSY.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 """
-        model = event.GetString()
-        if model is None:
-            return
-
         if obj[OG.OBJ_MODEL] != model:
             base.direct.deselectAll()
 
@@ -269,8 +264,16 @@ class ObjectMgr:
             obj[OG.OBJ_NP] = newobj
             obj[OG.OBJ_MODEL] = model
             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):
         """
@@ -329,7 +332,7 @@ class ObjectMgr:
         # now update object prop value and call update function
         self.updateObjectPropValue(obj, propName, val)
 
-    def updateObjectPropValue(self, obj, propName, val):
+    def updateObjectPropValue(self, obj, propName, val, fSelectObject=True):
         """
         Update object property value and
         call update function if defined.         
@@ -368,6 +371,9 @@ class ObjectMgr:
         # finally call update function
         func(**kwargs)
 
+        if fSelectObject:
+            base.direct.select(obj[OG.OBJ_NP])
+
     def updateObjectProperties(self, nodePath, propValues):
         """
         When a saved level is loaded,
@@ -417,5 +423,51 @@ class ObjectMgr:
         self.saveData = []
         self.traverse(render)
         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)

+ 1 - 1
direct/src/leveleditor/ObjectPropertyUI.py

@@ -173,7 +173,7 @@ class ObjectPropertyUI(ScrolledPanel):
 
             propUI.bindFunc(self.editor.objectMgr.onEnterObjectPropUI,
                             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():
             propDef = objDef.properties[key]