Browse Source

Added curve editing feature

Shuying Feng 15 years ago
parent
commit
be8dcd75cb

+ 7 - 1
direct/src/directtools/DirectSession.py

@@ -199,7 +199,7 @@ class DirectSession(DirectObject):
         keyList.extend(map(chr, range(48, 58)))
         keyList.extend(["`", "-", "=", "[", "]", ";", "'", ",", ".", "/", "\\"])
 
-        self.specialKeys = ['escape', 'delete', 'page_up', 'page_down']
+        self.specialKeys = ['escape', 'delete', 'page_up', 'page_down', 'enter']
 
         def addCtrl(a):
             return "control-%s"%a
@@ -286,6 +286,10 @@ class DirectSession(DirectObject):
             'control-q': ('Quit', 'LE-Quit'),
             }
 
+        self.speicalKeyMap = {
+                              'enter': 'DIRECT-enter',
+                             }
+
         self.passThroughKeys = ['v','b','l','p', 'r', 'shift-r', 's', 't','shift-a', 'w'] 
 
         if base.wantTk:
@@ -555,6 +559,8 @@ class DirectSession(DirectObject):
         if input in self.hotKeyMap.keys():
             keyDesc = self.hotKeyMap[input]
             messenger.send(keyDesc[1])
+        elif input in self.speicalKeyMap.keys():
+            messenger.send(self.speicalKeyMap[input])
         elif input in self.directOnlyKeyMap.keys():
             if self.fIgnoreDirectOnlyKeyMap:
                 return

+ 145 - 0
direct/src/leveleditor/CurveEditor.py

@@ -0,0 +1,145 @@
+"""
+This is the module for curve edit
+"""
+
+from pandac.PandaModules import *
+from direct.showbase.DirectObject import *
+from direct.directtools.DirectSelection import SelectionRay
+from direct.showutil.Rope import Rope
+from ActionMgr import *
+from direct.task import Task
+import ObjectGlobals as OG
+
+class CurveEditor(DirectObject):
+    """ CurveEditor will create and edit the curve """
+    def __init__(self, editor):
+        self.editor = editor
+        self.i = 0
+        self.ropeNum = 0
+        self.curve = []
+        self.curveControl = [] 
+        self.currentRope = None
+        self.degree = 3
+    
+    def createCurve(self):
+        if self.editor.mode == self.editor.CREATE_CURVE_MODE:
+            self.view = self.editor.ui.currentView
+            
+            #Get the mouse position
+            x = base.direct.dr.mouseX
+            y = base.direct.dr.mouseY    
+            
+            if self.editor.fMoveCamera == False and self.view != None:
+                self.createControler(x,y)
+                if self.currentRope != None:
+                    self.currentRope.detachNode()
+                self.ropeUpdate(self.curve)
+                self.accept("DIRECT-enter", self.onBaseMode)
+            
+            self.accept("DIRECT-enter", self.onBaseMode) 
+    
+    def editCurve(self, task):
+        if self.editor.mode == self.editor.EDIT_CURVE_MODE:
+            if self.editor.fMoveCamera == False:
+                self.selected = None
+                self.selected = base.direct.selected.last
+                if self.selected != None:
+                    for item in self.curveControl:
+                        if item[1] == self.selected:
+                            self.point = item  #temporarily save the controler information for further use
+                            self.currentCurve = self.currentRope.ropeNode.getCurve()
+                            self.currentCurve.setVertex(item[0], self.selected.getPos())
+                            self.accept("DIRECT-delete", self.onControlerDelete) 
+                            return task.cont 
+    
+    def onControlerDelete(self):
+        if self.editor.mode == self.editor.EDIT_CURVE_MODE:
+            self.curve.remove(self.curve[self.point[0]])
+            #reset the controller list
+            for item in self.curveControl:
+                if item[0] > self.point[0]:
+                    newname = 'controler%d' % (item[0]-1)
+                    item[1].setName(newname)
+                    self.curveControl[item[0]] = (item[0]-1, item[1])
+            self.curveControl.remove(self.point)
+            self.currentRope.setup(self.degree,self.curve)
+
+    def ropeUpdate(self, curve):
+        self.currentRope = Rope()
+        self.currentRope.setup(self.degree, curve)
+        self.currentRope.reparentTo(render)
+        
+    def onBaseMode(self):
+        self.editor.preMode = self.editor.mode
+        self.editor.mode = self.editor.BASE_MODE
+        self.editor.ui.editCurveMenuItem.Check(False)
+        self.editor.ui.createCurveMenuItem.Check(False)
+        self.i = 0
+        for item in self.curveControl:
+            item[1].hide()
+        if self.editor.preMode == self.editor.BASE_MODE :
+            pass
+        if self.editor.preMode == self.editor.CREATE_CURVE_MODE :
+            self.updateScene()
+        if self.editor.preMode == self.editor.EDIT_CURVE_MODE :
+            self.doneEdit()
+        self.curveControl = []
+        self.curve = []
+        self.currentRope = None
+        base.direct.manipulationControl.enableManipulation()
+        self.editor.ui.createCurveMenuItem.Check(False)
+        self.editor.ui.editCurveMenuItem.Check(False)
+        
+    def updateScene(self):
+        curveObjNP = self.editor.objectMgr.addNewCurve(self.curveControl, self.degree, nodePath=self.currentRope)
+        curveObj = self.editor.objectMgr.findObjectByNodePath(curveObjNP)
+        for item in self.curveControl:
+            item[1].reparentTo(curveObjNP)
+        self.editor.objectMgr.updateObjectPropValue(curveObj, 'Degree', self.degree, fSelectObject=False, fUndo=False)
+                                    
+    def doneEdit(self):
+        base.direct.selected.last = None
+            
+    def createControler(self, x, y):
+        if self.view != None:
+            self.controler = render.attachNewNode("controler")
+            self.controler = loader.loadModel('models/misc/smiley')
+            controlerPathname = 'controler%d' % self.i
+            self.controler.setName(controlerPathname)
+            self.controler.setColor(0, 0, 0, 1)
+            self.controler.setScale(0.2)
+            self.controler.reparentTo(render)
+            self.controler.setTag('OBJRoot','1')
+            self.controler.setTag('Controller','1') #controller Tag
+            self.i += 1
+        
+            iRay = SelectionRay(self.view.camera)
+            iRay.collider.setFromLens(self.view.camNode, x, y)
+            iRay.collideWithBitMask(BitMask32.bit(21))
+            iRay.ct.traverse(self.view.collPlane)
+            if iRay.getNumEntries() > 0:
+                entry = iRay.getEntry(0)
+                hitPt = entry.getSurfacePoint(entry.getFromNodePath())
+
+            if hitPt:
+                # create a temp nodePath to get the position
+                np = NodePath('temp')
+                np.setPos(self.view.camera, hitPt)
+
+                if base.direct.manipulationControl.fGridSnap:
+                    snappedPos = self.view.grid.computeSnapPoint(np.getPos())
+                    np.setPos(snappedPos)
+            
+                # update temp nodePath's HPR and scale with newobj's
+                np.setHpr(self.controler.getHpr())
+                np.setScale(self.controler.getScale())
+
+                # transform newobj to cursor position
+                self.controler.setMat(Mat4(np.getMat()))
+                np.remove()
+            iRay.collisionNodePath.removeNode()
+            del iRay
+
+            self.curve.append((None, self.controler.getPos()))
+            self.curveControl.append((self.i-1, self.controler))
+            

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

@@ -5,11 +5,11 @@ LevelEditor, ObjectHandler, ObjectPalette should be rewritten
 to be game specific.
 """
 
+from LevelEditorUI import *
 from LevelEditorBase import *
 from ObjectMgr import *
 from ObjectHandler import *
 from ObjectPalette import *
-from LevelEditorUI import *
 from ProtoPalette import *
 
 class LevelEditor(LevelEditorBase):

+ 19 - 4
direct/src/leveleditor/LevelEditorBase.py

@@ -9,6 +9,7 @@ from direct.showbase.DirectObject import *
 from direct.directtools.DirectUtil import *
 from direct.gui.DirectGui import *
 
+from CurveEditor import *
 from FileMgr import *
 from ActionMgr import *
 from MayaConverter import *
@@ -21,6 +22,7 @@ class LevelEditorBase(DirectObject):
         self.fNeedToSave = False
         self.actionEvents = []
         #self.objectMgr = ObjectMgr(self)
+        self.curveEditor = CurveEditor(self)
         self.fileMgr = FileMgr(self)
         self.actionMgr = ActionMgr()
 
@@ -32,7 +34,12 @@ class LevelEditorBase(DirectObject):
         self.settingsFile = None
 
         # you can show/hide specific properties by using propertiesMask and this mode
-        self.mode = BitMask32()
+        self.BASE_MODE = BitMask32.bit(0)
+        self.CREATE_CURVE_MODE = BitMask32.bit(2)
+        self.EDIT_CURVE_MODE = BitMask32.bit(3)
+        
+        self.mode = self.BASE_MODE
+        self.preMode = None
         
     def initialize(self):
         """ You should call this in your __init__ method of inherited LevelEditor class """
@@ -122,10 +129,14 @@ class LevelEditorBase(DirectObject):
         if base.direct.fAlt or modifiers == 4:
             self.fMoveCamera = True
             return
+        if self.mode == self.CREATE_CURVE_MODE :
+            self.curveEditor.createCurve()
+
 
-    def handleMouse1Up(self):
+    def handleMouse1Up(self):        
         self.fMoveCamera = False
 
+
     def handleMouse2(self, modifiers):
         if base.direct.fAlt or modifiers == 4:
             self.fMoveCamera = True
@@ -138,7 +149,7 @@ class LevelEditorBase(DirectObject):
         if base.direct.fAlt or modifiers == 4:
             self.fMoveCamera = True
             return
-
+        
         self.ui.onRightDown()
 
     def handleMouse3Up(self):
@@ -209,7 +220,11 @@ class LevelEditorBase(DirectObject):
                  self.ui.sceneGraphUI.deSelect(obj[OG.OBJ_UID])
         self.objectMgr.selectObject(nodePath, fLEPane)
         self.ui.buildContextMenu(nodePath)
-        
+       
+        if self.mode == self.EDIT_CURVE_MODE:
+            taskMgr.add(self.curveEditor.editCurve, "modify")
+            self.curveEditor.accept("DIRECT-enter", self.curveEditor.onBaseMode) 
+ 
     def deselectAll(self, np=None):
         if len(base.direct.selected.getSelectedAsList()) ==0:
             return

+ 109 - 2
direct/src/leveleditor/LevelEditorUIBase.py

@@ -29,6 +29,7 @@ class PandaTextDropTarget(wx.TextDropTarget):
         action = ActionAddNewObj(self.editor, text, parent=parentNPRef[0])
         self.editor.actionMgr.push(action)
         newobj = action()
+        print newobj
         if newobj is None:
             return
 
@@ -114,6 +115,9 @@ ID_SHOW_PANDA_OBJECT = 304
 ID_HOT_KEYS = 305
 ID_PARENT_TO_SELECTED = 306
 
+ID_CREATE_CURVE = 601
+ID_EDIT_CURVE = 602
+
 class LevelEditorUIBase(WxPandaShell):
     """ Class for Panda3D LevelEditor """ 
     def __init__(self, editor):
@@ -132,7 +136,9 @@ class LevelEditorUIBase(WxPandaShell):
             ID_GRID_SNAP : ("Grid S&nap", None),
             ID_SHOW_PANDA_OBJECT : ("Show &Panda Objects", None),
             ID_HOT_KEYS : ("&Hot Keys", None),
-            ID_PARENT_TO_SELECTED : ("&Parent To Selected", None)
+            ID_PARENT_TO_SELECTED : ("&Parent To Selected", None),
+            ID_CREATE_CURVE : ("&Create Curve", None),
+            ID_EDIT_CURVE : ("&Edit Curve", None)
             })
 
         self.editor = editor
@@ -197,9 +203,81 @@ class LevelEditorUIBase(WxPandaShell):
 
         self.hotKeysMenuItem = self.menuOptions.Append(ID_HOT_KEYS, self.MENU_TEXTS[ID_HOT_KEYS][0])
         self.Bind(wx.EVT_MENU, self.onHotKeys, self.hotKeysMenuItem)
+        
+        self.menuCurve = wx.Menu()
+        self.menuBar.Insert(3, self.menuCurve, "&CurveMode")
+        
+        self.createCurveMenuItem = self.menuCurve.Append(ID_CREATE_CURVE, self.MENU_TEXTS[ID_CREATE_CURVE][0], kind = wx.ITEM_CHECK)
+        self.Bind(wx.EVT_MENU, self.onCreateCurve, self.createCurveMenuItem)
+        
+        self.editCurveMenuItem = self.menuCurve.Append(ID_EDIT_CURVE, self.MENU_TEXTS[ID_EDIT_CURVE][0], kind = wx.ITEM_CHECK)
+        self.Bind(wx.EVT_MENU, self.onEditCurve, self.editCurveMenuItem)
 
         WxPandaShell.createMenu(self)
-
+        
+    def onCreateCurve(self,e):
+        """Function to invoke curve creating, need to check previous mode"""
+        if self.editor.mode == self.editor.CREATE_CURVE_MODE:
+            self.createCurveMenuItem.Check(False)
+            self.editor.curveEditor.onBaseMode() 
+        else:
+            if self.editor.mode == self.editor.EDIT_CURVE_MODE:
+                self.editor.curveEditor.onBaseMode()
+                self.editCurveMenuItem.Check(False)
+                self.createCurveMenuItem.Check(True)
+                self.onCreateCurve(None)
+            else:
+                self.currentView = self.getCurrentView()
+                if self.currentView == None:
+                    dlg = wx.MessageDialog(None, 'Please select a viewport first.Do not support curve creation under four viewports.', 'NOTICE', wx.OK )
+                    dlg.ShowModal()
+                    dlg.Destroy()
+                    self.createCurveMenuItem.Check(False)
+                else:
+                    self.editor.mode = self.editor.CREATE_CURVE_MODE
+                    self.editor.updateStatusReadout('Please press ENTER to end the curve creation.')
+                    degreeUI = CurveDegreeUI(self, -1, 'Curve Degree')
+                    degreeUI.ShowModal()
+                    degreeUI.Destroy()
+                    base.direct.manipulationControl.disableManipulation()
+                    self.editCurveMenuItem.Check(False)
+    
+    def onEditCurve(self,e):
+        """Function to invoke curve editing and transfer global information to local information. Need to check previous mode"""
+        if self.editor.mode == self.editor.EDIT_CURVE_MODE:
+            self.editCurveMenuItem.Check(False)
+            self.editor.curveEditor.onBaseMode() 
+        else:
+            if self.editor.mode == self.editor.CREATE_CURVE_MODE:
+                self.editor.curveEditor.onBaseMode()
+                self.editCurveMenuItem.Check(True)
+                self.createCurveMenuItem.Check(False)
+                self.onEditCurve(None)
+            else:
+                if base.direct.selected.last == None:
+                    dlg = wx.MessageDialog(None, 'Please select a curve first.', 'NOTICE', wx.OK )
+                    dlg.ShowModal()
+                    dlg.Destroy()
+                    self.editCurveMenuItem.Check(False)
+                if base.direct.selected.last != None :
+                    base.direct.manipulationControl.enableManipulation()
+                    self.createCurveMenuItem.Check(False)
+                    self.curveObj = self.editor.objectMgr.findObjectByNodePath(base.direct.selected.last)
+                    if self.curveObj[OG.OBJ_DEF].name == '__Curve__':
+                        self.editor.mode = self.editor.EDIT_CURVE_MODE
+                        self.editor.updateStatusReadout('Please press ENTER to end the curve editing.')
+                        self.editor.curveEditor.currentRope = self.curveObj[OG.OBJ_NP]
+                        self.editor.curveEditor.curveControl = self.curveObj[OG.OBJ_PROP]['curveInfo']
+                        self.editor.curveEditor.degree = self.curveObj[OG.OBJ_PROP]['Degree']
+                        for item in self.editor.curveEditor.curveControl:
+                            item[1].show()
+                            self.editor.curveEditor.curve.append((None, item[1].getPos()))
+                    else:
+                        dlg = wx.MessageDialog(None, 'Please select a curve first.', 'NOTICE', wx.OK )
+                        dlg.ShowModal()
+                        dlg.Destroy()
+                        self.editCurveMenuItem.Check(False)
+                
     def updateMenu(self):
         hotKeyDict = {}
         for hotKey in base.direct.hotKeyMap.keys():
@@ -521,3 +599,32 @@ class ViewportMenu(wx.Menu):
         parent.AppendMenu(id, name, subMenu)
         return subMenu
 
+class CurveDegreeUI(wx.Dialog):
+    def __init__(self, parent, id, title):
+        wx.Dialog.__init__(self, parent, id, title, size=(150, 120))
+
+        self.parent = parent
+        panel = wx.Panel(self, -1)
+        degreeBox = wx.BoxSizer(wx.VERTICAL)
+    
+        degreeList = ['2','3','4']
+        
+        self.degree = wx.RadioBox(panel, -1, 'Curve Degree', (5, 5), wx.DefaultSize, degreeList, 3, wx.RA_SPECIFY_COLS)
+        self.degree.SetToolTipString("Select the degree of the curve.")
+        self.degree.SetSelection(1)
+        
+        okButton = wx.Button(self, -1, 'Apply', size=(70, 20))
+        okButton.Bind(wx.EVT_BUTTON, self.onApply)
+        
+        degreeBox.Add(panel, 1, wx.ALIGN_CENTER | wx.TOP | wx.BOTTOM, 5)
+        degreeBox.Add(okButton, 0, wx.ALIGN_CENTER | wx.TOP | wx.BOTTOM, 5)
+        self.SetSizer(degreeBox)
+        
+    def onApply(self, evt):
+        if(str(self.degree.GetSelection())=='0'):
+            self.parent.editor.curveEditor.degree = 2
+        if(str(self.degree.GetSelection())=='1'):
+            self.parent.editor.curveEditor.degree = 3
+        if(str(self.degree.GetSelection())=='2'):
+            self.parent.editor.curveEditor.degree = 4
+        self.Destroy()

+ 107 - 8
direct/src/leveleditor/ObjectMgrBase.py

@@ -70,6 +70,84 @@ class ObjectMgrBase:
             self.lastUidMod = 0
         return newUid
 
+    def addNewCurveFromFile(self, curveInfo, degree, uid=None, parent=None, fSelectObject=True, nodePath=None):
+        """ function to add new curve to the scene from file"""
+        curve = []
+        curveControl = []
+        
+        #transfer the curve information from simple positions into control nodes
+        for item in curveInfo:
+            controler = render.attachNewNode("controler")
+            controler = loader.loadModel('models/misc/smiley')
+            controlerPathname = 'controler%d' % item[0]
+            controler.setName(controlerPathname)
+            controler.setPos(item[1])
+            controler.setColor(0, 0, 0, 1)
+            controler.setScale(0.2)
+            controler.reparentTo(render)
+            controler.setTag('OBJRoot','1')
+            controler.setTag('Controller','1') 
+            curve.append((None, item[1]))
+            curveControl.append((item[0], controler))
+        
+        self.editor.curveEditor.degree = degree
+        self.editor.curveEditor.ropeUpdate (curve)
+        #add new curve to the scene
+        curveObjNP = self.addNewCurve(curveControl, degree, uid, parent, fSelectObject, nodePath = self.editor.curveEditor.currentRope)
+        curveObj = self.findObjectByNodePath(curveObjNP)
+        self.editor.objectMgr.updateObjectPropValue(curveObj, 'Degree', degree, fSelectObject=False, fUndo=False)
+        
+        for item in curveControl:
+            item[1].reparentTo(curveObjNP)
+            item[1].hide()
+        
+        curveControl = []
+        curve = []
+        self.editor.curveEditor.currentRope = None
+        
+        return curveObjNP
+
+    def addNewCurve(self, curveInfo, degree, uid=None, parent=None, fSelectObject=True, nodePath=None):
+        """ function to add new curve to the scene"""
+        if parent is None:
+            parent = self.editor.NPParent
+        
+        if uid is None:
+            uid = self.genUniqueId()
+
+        if self.editor:
+            objDef = self.editor.objectPalette.findItem('__Curve__')
+        
+        if nodePath is None:
+            # we need to create curve
+            # and then create newobj with newly created curve
+            pass
+        else:
+            newobj = nodePath
+
+        newobj.reparentTo(parent)
+        newobj.setTag('OBJRoot','1')
+
+        # populate obj data using default values
+        properties = {}
+        for key in objDef.properties.keys():
+            properties[key] = objDef.properties[key][OG.PROP_DEFAULT]
+
+        properties['Degree'] = degree
+        properties['curveInfo'] = curveInfo
+            
+        # insert obj data to main repository
+        self.objects[uid] = [uid, newobj, objDef, None, None, properties, (1,1,1,1)]
+        self.npIndex[NodePath(newobj)] = uid        
+
+        if self.editor:
+            if fSelectObject:
+                self.editor.select(newobj, fUndo=0)
+            self.editor.ui.sceneGraphUI.add(newobj, parent)
+            self.editor.fNeedToSave = True
+
+        return newobj
+
     def addNewObject(self, typeName, uid = None, model = None, parent=None, anim = None, fSelectObject=True, nodePath=None, nameStr=None):
         """ function to add new obj to the scene """
         if parent is None:
@@ -529,9 +607,6 @@ class ObjectMgrBase:
         elif propType == OG.PROP_UI_COMBO_DYNAMIC:
             val = event.GetString()
 
-        elif propType == OG.PROP_UI_TIME:
-            val = event.ClientObject.GetParent().GetParent().getValue()
-
         else:
             # unsupported property type
             return
@@ -612,14 +687,23 @@ class ObjectMgrBase:
             if fSelectObject:
                 base.direct.select(obj[OG.OBJ_NP], fUndo=0)
 
+    def updateCurve(self, val, obj):
+        curve = obj[OG.OBJ_NP]
+        degree = int(val)
+        curveNode = obj[OG.OBJ_PROP]['curveInfo']
+        curveInfor = []
+        for item in curveNode:
+                curveInfor.append((None, item[1].getPos()))
+        curve.setup(degree, curveInfor)
+
     def updateObjectProperties(self, nodePath, propValues):
         """
         When a saved level is loaded,
         update an object's properties
         And call update function if defined.
         """
-
         obj = self.findObjectByNodePath(nodePath)
+        
         if obj:
             for propName in propValues:
                 self.updateObjectPropValue(obj, propName, propValues[propName])
@@ -629,7 +713,7 @@ class ObjectMgrBase:
         Trasverse scene graph to gather data for saving
         """
         for child in parent.getChildren():
-            if child.hasTag('OBJRoot'):
+            if child.hasTag('OBJRoot') and not child.hasTag('Controller'):
                 obj = self.findObjectByNodePath(child)
 
                 if obj:
@@ -640,7 +724,7 @@ class ObjectMgrBase:
                     objAnim = obj[OG.OBJ_ANIM]
                     objProp = obj[OG.OBJ_PROP]
                     objRGBA = obj[OG.OBJ_RGBA]
-
+                        
                     if parentId:
                         parentStr = "objects['%s']"%parentId
                     else:
@@ -661,13 +745,28 @@ class ObjectMgrBase:
                     else:
                         nameStr = "None"
 
-                    self.saveData.append("\nobjects['%s'] = objectMgr.addNewObject('%s', '%s', %s, %s, %s, False, None, %s)"%(uid, objDef.name, uid, modelStr, parentStr, animStr, nameStr))
+                    if objDef.name == '__Curve__':
+                        #transfer the curve information from control nodes into simple positions for file save
+                        objCurveInfo = obj[OG.OBJ_PROP]['curveInfo']
+                        self.objDegree = obj[OG.OBJ_PROP]['Degree']
+                        newobjCurveInfo = []
+                        for item in objCurveInfo:
+                            newobjCurveInfo.append((item[0], item[1].getPos()))
+                            
+                        self.saveData.append("\nobjects['%s'] = objectMgr.addNewCurveFromFile(%s, %s, '%s', %s, False, None)"%(uid, newobjCurveInfo, self.objDegree, uid, parentStr))    
+                    else:
+                        self.saveData.append("\nobjects['%s'] = objectMgr.addNewObject('%s', '%s', %s, %s, %s, False, None, %s)"%(uid, objDef.name, uid, modelStr, parentStr, animStr, nameStr))
+                    
                     self.saveData.append("if objects['%s']:"%uid)
                     self.saveData.append("    objects['%s'].setPos(%s)"%(uid, np.getPos()))
                     self.saveData.append("    objects['%s'].setHpr(%s)"%(uid, np.getHpr()))
                     self.saveData.append("    objects['%s'].setScale(%s)"%(uid, np.getScale()))
                     self.saveData.append("    objectMgr.updateObjectColor(%f, %f, %f, %f, objects['%s'])"%(objRGBA[0], objRGBA[1], objRGBA[2], objRGBA[3], uid))
-                    self.saveData.append("    objectMgr.updateObjectProperties(objects['%s'], %s)"%(uid,objProp))
+                    
+                    if objDef.name == '__Curve__':
+                        pass
+                    else:
+                        self.saveData.append("    objectMgr.updateObjectProperties(objects['%s'], %s)"%(uid,objProp))
                     
                 self.traverse(child, uid)
 

+ 13 - 0
direct/src/leveleditor/ObjectPaletteBase.py

@@ -27,6 +27,15 @@ class ObjectBase(ObjectGen):
         # to show/hide properties per editor mode
         self.propertiesMask = copy.deepcopy(propertiesMask)
 
+class ObjectCurve(ObjectBase):
+    def __init__(self, *args, **kw):
+        ObjectBase.__init__(self, *args, **kw)
+        self.properties['Degree'] =[OG.PROP_UI_COMBO,   # UI type
+                                    OG.PROP_INT,        # data type
+                                    ('base.le.objectMgr.updateCurve', {'val':OG.ARG_VAL, 'obj':OG.ARG_OBJ}),    # update function
+                                    3,                  # default value
+                                    [2, 3, 4]]          # value range
+
 class ObjectPaletteBase:
     """
     Base class for objectPalette
@@ -40,6 +49,7 @@ class ObjectPaletteBase:
         self.data = {}
         self.dataStruct = {}
         self.dataKeys = []
+        self.populateSystemObjs()
         #self.populate()
 
     def insertItem(self, item, parentName):
@@ -128,6 +138,9 @@ class ObjectPaletteBase:
             return False
         return True
 
+    def populateSystemObjs(self):
+        self.addHidden(ObjectCurve(name='__Curve__'))
+
     def populate(self):
         # You should implement this in subclass
         raise NotImplementedError('populate() must be implemented in ObjectPalette.py')

+ 18 - 1
direct/src/wxwidgets/WxPandaShell.py

@@ -64,7 +64,7 @@ class WxPandaShell(WxAppShell):
 
         menuItem = self.menuView.AppendRadioItem(ID_LEFT_VIEW, self.MENU_TEXTS[ID_LEFT_VIEW][0])
         self.Bind(wx.EVT_MENU, lambda p0=None, p1=2:self.onViewChange(p0, p1), menuItem)
-
+        
         self.perspViewMenuItem = self.menuView.AppendRadioItem(ID_PERSP_VIEW, self.MENU_TEXTS[ID_PERSP_VIEW][0])
         self.Bind(wx.EVT_MENU, lambda p0=None, p1=3:self.onViewChange(p0, p1), self.perspViewMenuItem)
 
@@ -223,3 +223,20 @@ class WxPandaShell(WxAppShell):
                 base.winList[i].setActive(1)
 
         self.viewFrame.SetExpanded(viewIdx)
+    
+    def getCurrentView(self):
+        """Function for get the current Viewport"""
+        if self.viewFrame._expanded == -1: #four view
+            self.currentView = None
+        if self.viewFrame._expanded == 0: #top view
+            self.currentView = self.topView
+        if self.viewFrame._expanded == 1: #front view
+            self.currentView = self.frontView
+        if self.viewFrame._expanded == 2: #left view
+            self.currentView = self.leftView
+        if self.viewFrame._expanded == 3: #perspect view
+            self.currentView = self.perspView
+            
+        return self.currentView
+        
+