Browse Source

Added [WIP] ProtoPalette

Gyedo Jeon 16 years ago
parent
commit
821656be00

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

@@ -14,6 +14,7 @@ base = ShowBase(False)
 
 
 from ObjectMgr import *
 from ObjectMgr import *
 from FileMgr import *
 from FileMgr import *
+from ProtoPalette import *
 
 
 class LevelEditorBase(DirectObject):
 class LevelEditorBase(DirectObject):
     """ Base Class for Panda3D LevelEditor """ 
     """ Base Class for Panda3D LevelEditor """ 
@@ -23,6 +24,7 @@ class LevelEditorBase(DirectObject):
         self.actionEvents = []
         self.actionEvents = []
         self.objectMgr = ObjectMgr(self)
         self.objectMgr = ObjectMgr(self)
         self.fileMgr = FileMgr(self)
         self.fileMgr = FileMgr(self)
+        self.protoPalette = ProtoPalette()
 
 
         # define your own config file in inherited class
         # define your own config file in inherited class
         self.settingsFile = None
         self.settingsFile = None

+ 9 - 2
direct/src/leveleditor/LevelEditorUI.py

@@ -11,6 +11,7 @@ from ObjectPropertyUI import *
 from SceneGraphUI import *
 from SceneGraphUI import *
 from LayerEditorUI import *
 from LayerEditorUI import *
 from HotKeyUI import *
 from HotKeyUI import *
+from ProtoPaletteUI import *
 
 
 class PandaTextDropTarget(wx.TextDropTarget):
 class PandaTextDropTarget(wx.TextDropTarget):
     def __init__(self, editor):
     def __init__(self, editor):
@@ -95,12 +96,15 @@ class LevelEditorUI(WxAppShell):
         self.perspView = Viewport.makePerspective(self.viewFrame)
         self.perspView = Viewport.makePerspective(self.viewFrame)
         self.viewFrame.AppendWindow(self.perspView)
         self.viewFrame.AppendWindow(self.perspView)
 
 
-        self.leftBarUpPane = wx.Panel(self.leftFrame)
+        self.leftBarUpFrame = wx.SplitterWindow(self.leftFrame, wx.SP_3D | wx.SP_BORDER)
+        self.leftBarUpPane = wx.Panel(self.leftBarUpFrame)
+        self.leftBarMidPane = wx.Panel(self.leftBarUpFrame)
         self.leftBarDownPane = wx.Panel(self.leftFrame)
         self.leftBarDownPane = wx.Panel(self.leftFrame)
         self.rightBarUpPane = wx.Panel(self.rightFrame)
         self.rightBarUpPane = wx.Panel(self.rightFrame)
         self.rightBarDownPane = wx.Panel(self.rightFrame)
         self.rightBarDownPane = wx.Panel(self.rightFrame)
 
 
-        self.leftFrame.SplitHorizontally(self.leftBarUpPane, self.leftBarDownPane)
+        self.leftFrame.SplitHorizontally(self.leftBarUpFrame, self.leftBarDownPane)
+        self.leftBarUpFrame.SplitHorizontally(self.leftBarUpPane, self.leftBarMidPane)
         self.rightFrame.SplitHorizontally(self.rightBarUpPane, self.rightBarDownPane)
         self.rightFrame.SplitHorizontally(self.rightBarUpPane, self.rightBarDownPane)
         self.mainFrame.SplitVertically(self.leftFrame, self.baseFrame, 200)
         self.mainFrame.SplitVertically(self.leftFrame, self.baseFrame, 200)
         self.baseFrame.SplitVertically(self.viewFrame, self.rightFrame, 600)
         self.baseFrame.SplitVertically(self.viewFrame, self.rightFrame, 600)
@@ -108,6 +112,7 @@ class LevelEditorUI(WxAppShell):
         self.viewFrame.SetDropTarget(PandaTextDropTarget(self.editor))
         self.viewFrame.SetDropTarget(PandaTextDropTarget(self.editor))
 
 
         self.leftFrame.SetSashGravity(0.5)
         self.leftFrame.SetSashGravity(0.5)
+        self.leftBarUpFrame.SetSashGravity(0.5)
         self.rightFrame.SetSashGravity(0.5)        
         self.rightFrame.SetSashGravity(0.5)        
         self.baseFrame.SetSashGravity(1.0)
         self.baseFrame.SetSashGravity(1.0)
 
 
@@ -116,6 +121,7 @@ class LevelEditorUI(WxAppShell):
         self.SetSizer(sizer); self.Layout()
         self.SetSizer(sizer); self.Layout()
 
 
         self.objectPaletteUI = ObjectPaletteUI(self.leftBarUpPane, self.editor)
         self.objectPaletteUI = ObjectPaletteUI(self.leftBarUpPane, self.editor)
+        self.protoPaletteUI = ProtoPaletteUI(self.leftBarMidPane, self.editor)
         self.objectPropertyUI = ObjectPropertyUI(self.rightBarUpPane, self.editor)
         self.objectPropertyUI = ObjectPropertyUI(self.rightBarUpPane, self.editor)
         self.sceneGraphUI = SceneGraphUI(self.leftBarDownPane, self.editor)
         self.sceneGraphUI = SceneGraphUI(self.leftBarDownPane, self.editor)
         self.layerEditorUI = LayerEditorUI(self.rightBarDownPane, self.editor)
         self.layerEditorUI = LayerEditorUI(self.rightBarDownPane, self.editor)
@@ -190,6 +196,7 @@ class LevelEditorUI(WxAppShell):
         self.sceneGraphUI.showPandaObjectChildren()
         self.sceneGraphUI.showPandaObjectChildren()
 
 
     def onDestroy(self, evt):
     def onDestroy(self, evt):
+        self.editor.protoPalette.saveToFile()
         self.editor.saveSettings()
         self.editor.saveSettings()
 
 
     def updateGrids(self, newSize, newSpacing):
     def updateGrids(self, newSize, newSpacing):

+ 2 - 1
direct/src/leveleditor/ObjectGlobals.py

@@ -7,7 +7,8 @@ OBJ_UID = 0
 OBJ_NP = 1
 OBJ_NP = 1
 OBJ_DEF = 2
 OBJ_DEF = 2
 OBJ_MODEL = 3
 OBJ_MODEL = 3
-OBJ_PROP = 4
+OBJ_ANIM = 4
+OBJ_PROP = 5
 
 
 # supported UI types
 # supported UI types
 PROP_UI_ENTRY = '_PropUIEntry'
 PROP_UI_ENTRY = '_PropUIEntry'

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

@@ -68,8 +68,8 @@ class ObjectHandler:
 
 
 class PandaActor(Actor.Actor):
 class PandaActor(Actor.Actor):
     def __init__(self):
     def __init__(self):
-        Actor.Actor.__init__(self, "models/panda-model.egg",{"walk":"models/panda-walk4.egg"})
+        Actor.Actor.__init__(self, "models/panda-model.egg")
         self.setScale(0.005)
         self.setScale(0.005)
-        self.loop("walk")
+
 
 
     
     

+ 43 - 4
direct/src/leveleditor/ObjectMgr.py

@@ -5,6 +5,7 @@ Defines ObjectMgr
 import os, time, wx
 import os, time, wx
 
 
 from direct.task import Task
 from direct.task import Task
+from direct.actor.Actor import Actor
 from pandac.PandaModules import *
 from pandac.PandaModules import *
 
 
 import ObjectGlobals as OG
 import ObjectGlobals as OG
@@ -63,6 +64,8 @@ class ObjectMgr:
             parent = render
             parent = render
 
 
         objDef = self.editor.objectPalette.findItem(typeName)
         objDef = self.editor.objectPalette.findItem(typeName)
+        if objDef is None:
+            objDef = self.editor.protoPalette.findItem(typeName)
         newobj = None
         newobj = None
         if objDef and type(objDef) != dict:
         if objDef and type(objDef) != dict:
             if objDef.createFunction:
             if objDef.createFunction:
@@ -78,12 +81,29 @@ class ObjectMgr:
 
 
                 # create new obj using function and keyword arguments defined in ObjectPalette
                 # create new obj using function and keyword arguments defined in ObjectPalette
                 newobj = func(**funcArgs)
                 newobj = func(**funcArgs)
-
+            elif objDef.actor:
+                if model is None:
+                    model = objDef.model
+                try:
+                    newobj = Actor(model)
+                except:
+                    newobj = Actor(Filename.fromOsSpecific(model).getFullpath())
             elif objDef.model is not None:
             elif objDef.model is not None:
                 # since this obj is simple model let's load the model
                 # since this obj is simple model let's load the model
                 if model is None:
                 if model is None:
                     model = objDef.model
                     model = objDef.model
-                newobj = loader.loadModel(model)
+                try:
+                    newobj = loader.loadModel(model)
+                except:
+                    newobj = loader.loadModel(Filename.fromOsSpecific(model).getFullpath())
+
+            anim = ''
+            if len(objDef.anims) > 0:
+                anim = objDef.anims[0]
+                # load new anim
+                animName = os.path.basename(anim)
+                newAnim = newobj.loadAnims({animName:anim})
+                newobj.loop(animName)                
 
 
             if newobj is None:
             if newobj is None:
                 return None
                 return None
@@ -102,7 +122,7 @@ class ObjectMgr:
                 properties[key] = objDef.properties[key][OG.PROP_DEFAULT]
                 properties[key] = objDef.properties[key][OG.PROP_DEFAULT]
 
 
             # insert obj data to main repository
             # insert obj data to main repository
-            self.objects[uid] = [uid, newobj, objDef, model, properties]
+            self.objects[uid] = [uid, newobj, objDef, model, anim, properties]
             self.npIndex[NodePath(newobj)] = uid
             self.npIndex[NodePath(newobj)] = uid
 
 
             if fSelectObject:
             if fSelectObject:
@@ -269,7 +289,20 @@ class ObjectMgr:
 
 
             if fSelectObject:
             if fSelectObject:
                 base.direct.select(newobj)        
                 base.direct.select(newobj)        
-        
+
+    def updateObjectAnim(self, anim, obj, fSelectObject=True):
+        """ replace object's anim """
+        if obj[OG.OBJ_ANIM] != anim:
+            base.direct.deselectAll()
+            objNP = obj[OG.OBJ_NP]
+
+            # load new anim
+            animName = os.path.basename(anim)
+            newAnim = objNP.loadAnims({animName:anim})
+            objNP.loop(animName)
+            obj[OG.OBJ_ANIM] = anim
+            if fSelectObject:
+                base.direct.select(objNP)
 
 
     def updateObjectModelFromUI(self, event, obj):
     def updateObjectModelFromUI(self, event, obj):
         """ replace object's model with one selected from UI """
         """ replace object's model with one selected from UI """
@@ -277,6 +310,12 @@ class ObjectMgr:
         if model is not None:
         if model is not None:
             self.updateObjectModel(model, obj)
             self.updateObjectModel(model, obj)
 
 
+    def updateObjectAnimFromUI(self, event, obj):
+        """ replace object's anim with one selected from UI """
+        anim = event.GetString()
+        if anim is not None:
+            self.updateObjectAnim(anim, obj)
+
     def updateObjectProperty(self, event, obj, propName):
     def updateObjectProperty(self, event, obj, propName):
         """
         """
         When an obj's property is updated in UI,
         When an obj's property is updated in UI,

+ 1 - 0
direct/src/leveleditor/ObjectPalette.py

@@ -101,6 +101,7 @@ class ObjectPalette(ObjectPaletteBase):
         self.add('Animal')
         self.add('Animal')
         self.add(ObjectBase(name='Panda',
         self.add(ObjectBase(name='Panda',
                             createFunction = ('.createPanda', {}),
                             createFunction = ('.createPanda', {}),
+                            anims = ['models/panda-walk4.egg',],
                             properties = {}),
                             properties = {}),
                  'Animal')
                  'Animal')
 
 

+ 7 - 4
direct/src/leveleditor/ObjectPaletteBase.py

@@ -1,16 +1,19 @@
+import copy
 import ObjectGlobals as OG
 import ObjectGlobals as OG
 
 
 class ObjectBase:
 class ObjectBase:
     """ Base class for obj definitions """
     """ Base class for obj definitions """
     
     
-    def __init__(self, name='', createFunction = None, model = None, models= [], properties={},
-                 movable = True):
+    def __init__(self, name='', createFunction = None, model = None, models= [], anims = [], properties={},
+                 movable = True, actor = False):
         self.name = name
         self.name = name
         self.createFunction = createFunction
         self.createFunction = createFunction
         self.model = model
         self.model = model
-        self.models = models
-        self.properties = properties
+        self.models = models[:]
+        self.anims = anims[:]
+        self.properties = copy.deepcopy(properties)
         self.movable = movable
         self.movable = movable
+        self.actor = actor
 
 
 class ObjectPaletteBase:
 class ObjectPaletteBase:
     """
     """

+ 39 - 2
direct/src/leveleditor/ObjectPropertyUI.py

@@ -2,13 +2,40 @@
 UI for object property control
 UI for object property control
 """
 """
 import wx
 import wx
-from wx.lib.scrolledpanel import ScrolledPanel
+import os
 
 
+from wx.lib.scrolledpanel import ScrolledPanel
 from direct.wxwidgets.WxSlider import *
 from direct.wxwidgets.WxSlider import *
-
+from pandac.PandaModules import *
 import ObjectGlobals as OG
 import ObjectGlobals as OG
 
 
+class AnimFileDrop(wx.FileDropTarget):
+    def __init__(self, editor):
+        wx.FileDropTarget.__init__(self)
+        self.editor = editor
+
+    def OnDropFiles(self, x, y, filenames):
+        obj = self.editor.objectMgr.findObjectByNodePath(base.direct.selected.last)
+        if obj is None:
+            return
 
 
+        objDef = obj[OG.OBJ_DEF]
+        if not objDef.actor:
+            return
+
+        objNP = obj[OG.OBJ_NP]
+
+        for filename in filenames:
+            name = os.path.basename(filename)
+            animName = Filename.fromOsSpecific(filename).getFullpath()
+            if animName not in objDef.anims:
+                objDef.anims.append(animName)
+
+            objNP.loadAnims({name:animName})
+            objNP.loop(name)
+            obj[OG.OBJ_ANIM] = animName
+            self.editor.ui.objectPropertyUI.updateProps(obj)
+            
 class ObjectPropUI(wx.Panel):
 class ObjectPropUI(wx.Panel):
     """
     """
     Base class for ObjectPropUIs,
     Base class for ObjectPropUIs,
@@ -124,6 +151,8 @@ class ObjectPropertyUI(ScrolledPanel):
         parentSizer.Add(self, 1, wx.EXPAND, 0)
         parentSizer.Add(self, 1, wx.EXPAND, 0)
         parent.SetSizer(parentSizer); parent.Layout()
         parent.SetSizer(parentSizer); parent.Layout()
 
 
+        self.SetDropTarget(AnimFileDrop(self.editor))
+
     def clearPropUI(self):
     def clearPropUI(self):
         sizer = self.GetSizer()
         sizer = self.GetSizer()
         if sizer is not None:
         if sizer is not None:
@@ -175,6 +204,14 @@ class ObjectPropertyUI(ScrolledPanel):
                             self.editor.objectMgr.onLeaveObjectPropUI,
                             self.editor.objectMgr.onLeaveObjectPropUI,
                             lambda p0=None, p1=obj: self.editor.objectMgr.updateObjectModelFromUI(p0, p1))
                             lambda p0=None, p1=obj: self.editor.objectMgr.updateObjectModelFromUI(p0, p1))
 
 
+        if len(objDef.anims) > 0:
+            propUI = ObjectPropUICombo(self.propPane, 'anim', obj[OG.OBJ_ANIM], objDef.anims)
+            sizer.Add(propUI)            
+
+            propUI.bindFunc(self.editor.objectMgr.onEnterObjectPropUI,
+                            self.editor.objectMgr.onLeaveObjectPropUI,
+                            lambda p0=None, p1=obj: self.editor.objectMgr.updateObjectAnimFromUI(p0, p1))
+
         for key in objDef.properties.keys():
         for key in objDef.properties.keys():
             propDef = objDef.properties[key]
             propDef = objDef.properties[key]
             propType = propDef[OG.PROP_TYPE]
             propType = propDef[OG.PROP_TYPE]

+ 58 - 0
direct/src/leveleditor/ProtoPalette.py

@@ -0,0 +1,58 @@
+"""
+Palette for Prototyping
+"""
+import os
+import imp
+import types
+
+from ObjectPaletteBase import *
+
+class ProtoPalette(ObjectPaletteBase):
+    def __init__(self):
+        ObjectPaletteBase.__init__(self)
+
+    def addItems(self, protoData, parent=None):
+        if type(protoData) == types.DictType:
+            for key in protoData.keys():
+                if type(protoData[key]) == types.DictType:
+                    self.add(key, parent)
+                    self.addItems(protoData[key], key)
+                else:
+                    self.add(protoData[key], parent)
+                    
+    def populate(self):
+        dirname = os.path.dirname(__file__)
+        moduleName = 'protoPaletteData'
+        try:
+            file, pathname, description = imp.find_module(moduleName, [dirname])
+            module = imp.load_module(moduleName, file, pathname, description)
+        except:
+            print "protoPaletteData doesn't exist"        
+            return
+
+        self.addItems(module.protoData)
+
+    def saveProtoData(self, f, protoData, depth):
+        tab = ' '*4*depth
+        if not f:
+            return
+
+        for key in protoData.keys():
+            f.write("%s'%s' : "%(tab, key))
+            if type(protoData[key]) == types.DictType:
+                f.write("{\n")
+                self.saveProtoData(f, protoData[key], depth + 1)
+                f.write("%s},\n"%tab)
+            else:
+                f.write("ObjectBase(name='%s', model='%s', anims=%s, actor=True),\n"%(protoData[key].name, protoData[key].model, protoData[key].anims))
+
+    def saveToFile(self):
+        try:
+            f = open(os.path.dirname(__file__) + '/protoPaletteData.py', 'w')
+            f.write("from direct.leveleditor.ObjectPaletteBase import *\n\n")
+            f.write("protoData = {\n")
+            self.saveProtoData(f, self.data, 1)
+            f.write("}\n")
+            f.close()
+        except:
+            pass

+ 71 - 0
direct/src/leveleditor/ProtoPaletteUI.py

@@ -0,0 +1,71 @@
+"""
+Defines ProtoPalette tree UI
+"""
+import wx
+import os
+import cPickle as pickl
+from pandac.PandaModules import *
+from ObjectPaletteBase import *
+
+class FileDrop(wx.FileDropTarget):
+    def __init__(self, editor):
+        wx.FileDropTarget.__init__(self)
+        self.editor = editor
+
+    def OnDropFiles(self, x, y, filenames):
+        for filename in filenames:
+            name = os.path.basename(filename)
+            modelname = Filename.fromOsSpecific(filename).getFullpath()
+            itemData = ObjectBase(name=name, model=modelname, actor=True)
+            base.le.protoPalette.add(itemData)
+            newItem = self.editor.ui.protoPaletteUI.tree.AppendItem(self.editor.ui.protoPaletteUI.root, name)
+            self.editor.ui.protoPaletteUI.tree.SetItemPyData(newItem, itemData)
+            self.editor.ui.protoPaletteUI.tree.ScrollTo(newItem)
+
+class ProtoPaletteUI(wx.Panel):
+    def __init__(self, parent, editor):
+        wx.Panel.__init__(self, parent)
+
+        self.editor = editor
+        self.palette = self.editor.protoPalette
+        self.tree = wx.TreeCtrl(self)
+        self.root = self.tree.AddRoot('Proto Objects')
+        self.addTreeNodes(self.root, self.palette.data)
+
+        sizer = wx.BoxSizer(wx.VERTICAL)
+        sizer.Add(self.tree, 1, wx.EXPAND, 0)
+        self.SetSizer(sizer); self.Layout()
+
+        parentSizer = wx.BoxSizer(wx.VERTICAL)
+        parentSizer.Add(self, 1, wx.EXPAND, 0)
+        parent.SetSizer(parentSizer); parent.Layout()
+
+        self.tree.Bind(wx.EVT_TREE_SEL_CHANGED, self.onSelected)
+        self.tree.Bind(wx.EVT_TREE_BEGIN_DRAG, self.onBeginDrag)
+
+        self.SetDropTarget(FileDrop(self.editor))
+
+    def addTreeNodes(self, parentItem, items):
+        for key in items.keys():
+            newItem = self.tree.AppendItem(parentItem, key)
+            if type(items[key]) == dict:
+                self.addTreeNodes(newItem, items[key])
+            else:
+                self.tree.SetItemPyData(newItem, items[key])
+
+    def onSelected(self, event):
+        data = self.tree.GetItemPyData(event.GetItem())
+        if data:
+            print data.properties
+
+    def onBeginDrag(self, event):
+        item = event.GetItem()
+
+        if item != self.tree.GetRootItem(): # prevent dragging root item
+            text = self.tree.GetItemText(item)
+            print "Starting drag'n'drop with %s..." % repr(text)
+
+            tdo = wx.TextDataObject(text)
+            tds = wx.DropSource(self.tree)
+            tds.SetData(tdo)
+            tds.DoDragDrop(True)