소스 검색

adding vertex memory explorer

YoungWook Yang 17 년 전
부모
커밋
227ed2dc45
2개의 변경된 파일376개의 추가작업 그리고 19개의 파일을 삭제
  1. 27 19
      direct/src/tkpanels/DirectSessionPanel.py
  2. 349 0
      direct/src/tkwidgets/MemoryExplorer.py

+ 27 - 19
direct/src/tkpanels/DirectSessionPanel.py

@@ -14,6 +14,7 @@ from direct.tkwidgets import Slider
 from direct.tkwidgets import VectorWidgets
 from direct.tkwidgets import SceneGraphExplorer
 from TaskManagerPanel import TaskManagerWidget
+from direct.tkwidgets import MemoryExplorer
 
 """
 Possible to add:
@@ -183,17 +184,22 @@ class DirectSessionPanel(AppShell):
         # Create the notebook pages
         notebook = Pmw.NoteBook(notebookFrame)
         notebook.pack(fill = BOTH, expand = 1)
-        envPage = notebook.add('Environment')
-        lightsPage = notebook.add('Lights')
-        gridPage = notebook.add('Grid')
-        devicePage = notebook.add('Devices')
-        tasksPage = notebook.add('Tasks')
-        scenePage = notebook.add('Scene')
+        self.createEnvPage(notebook.add('Environment'))
+        self.createLightsPage(notebook.add('Lights'))
+        self.createGridPage(notebook.add('Grid'))
+        self.createDevicePage(notebook.add('Devices'))
+        self.createTasksPage(notebook.add('Tasks'))
+        self.createMemPage(notebook.add('Memory'))
+
+        notebook.setnaturalsize()
+
+        framePane.pack(expand = 1, fill = BOTH)
+        mainFrame.pack(fill = 'both', expand = 1)
+        
         # Put this here so it isn't called right away
         notebook['raisecommand'] = self.updateInfo
-
-        ## Environment page ##
-        # Backgroud color
+       
+    def createEnvPage(self, envPage):
         bkgrdFrame = Frame(envPage, borderwidth = 2, relief = 'sunken')
 
         Label(bkgrdFrame, text = 'Background',
@@ -273,7 +279,6 @@ class DirectSessionPanel(AppShell):
         frame.pack(side = LEFT, fill = X, expand = 0)
         fovFrame.pack(fill = X, expand = 1)
 
-
         drFrame.pack(fill = BOTH, expand = 0)
 
         ## Render Style ##
@@ -305,7 +310,7 @@ class DirectSessionPanel(AppShell):
         self.toggleWireframeButton.pack(fill = X, expand = 1)
         toggleFrame.pack(side = LEFT, fill = X, expand = 1)
 
-        ## Lights page ##
+    def createLightsPage(self, lightsPage):
         # Lights #
         lightFrame = Frame(lightsPage, borderwidth = 2, relief = 'sunken')
         self.lightsButton = Menubutton(lightFrame, text = 'Lights',
@@ -470,7 +475,8 @@ class DirectSessionPanel(AppShell):
 
         lightFrame.pack(expand = 1, fill = BOTH)
 
-        ## GRID PAGE ##
+
+    def createGridPage(self, gridPage):
         Label(gridPage, text = 'Grid',
               font=('MSSansSerif', 14, 'bold')).pack(expand = 0)
         self.enableGrid = BooleanVar()
@@ -524,7 +530,7 @@ class DirectSessionPanel(AppShell):
         self.gridSnapAngle['command'] = base.direct.grid.setSnapAngle
         self.gridSnapAngle.pack(fill = X, expand = 0)
 
-        ## DEVICE PAGE ##
+    def createDevicePage(self, devicePage):
         Label(devicePage, text = 'DEVICES',
               font=('MSSansSerif', 14, 'bold')).pack(expand = 0)
 
@@ -590,17 +596,19 @@ class DirectSessionPanel(AppShell):
             self.jbHprSF.pack(fill = X, expand = 0)
             self.bind(self.jbHprSF, 'Set joybox HPR speed multiplier')
 
-        ## TASKS PAGE ##
+    def createTasksPage(self, tasksPage):
         Label(tasksPage, text = 'TASKS',
               font=('MSSansSerif', 14, 'bold')).pack(expand = 0)
         self.taskMgrPanel = TaskManagerWidget(tasksPage, taskMgr)
         self.taskMgrPanel.taskListBox['listbox_height'] = 10
 
-        notebook.setnaturalsize()
-
-        framePane.pack(expand = 1, fill = BOTH)
-        mainFrame.pack(fill = 'both', expand = 1)
-
+    def createMemPage(self, memPage):
+        self.MemExp = MemoryExplorer.MemoryExplorer(
+            memPage, nodePath = render,
+            scrolledCanvas_hull_width = 250,
+            scrolledCanvas_hull_height = 250)
+        self.MemExp.pack(fill = BOTH, expand = 1)
+            
     def toggleDirect(self):
         if self.directEnabled.get():
             base.direct.enable()

+ 349 - 0
direct/src/tkwidgets/MemoryExplorer.py

@@ -0,0 +1,349 @@
+from direct.showbase.DirectObject import DirectObject
+from direct.showbase.TkGlobal import *
+from Tkinter import *
+from Tree import *
+import Pmw
+
+#--------------------------------------------------------------------------
+#--------------------------------------------------------------------------
+DEFAULT_BT_WIDTH = 50.0
+
+#--------------------------------------------------------------------------
+#--------------------------------------------------------------------------
+class MemoryExplorer(Pmw.MegaWidget, DirectObject):
+
+    #--------------------------------------------------------------------------
+    # Init
+    #--------------------------------------------------------------------------    
+    def __init__(self, parent = None, nodePath = render, **kw):
+        optiondefs = (('menuItems',   [],   Pmw.INITOPT),)
+        self.defineoptions(kw, optiondefs)
+        Pmw.MegaWidget.__init__(self, parent)
+
+        self.nodePath = nodePath
+        self.renderItem = None 
+        self.render2dItem = None
+
+        self.buttons = []
+        self.labels = []
+        self.rootItem = None
+
+        self.btWidth = DEFAULT_BT_WIDTH        
+        
+        self.createScrolledFrame()        
+        self.createScale()
+        self.createRefreshBT()
+        
+        self.balloon = Pmw.Balloon(self.interior())
+
+    def createScrolledFrame(self):
+        self.frame = Pmw.ScrolledFrame(self.interior(),
+                                       labelpos = 'n',
+                                       label_text = 'ScrolledFrame',
+                                       usehullsize = 1,
+                                       hull_width = 200,
+                                       hull_height = 220,)
+
+        self.frame.pack(padx = 3, pady = 3, fill = BOTH, expand = 1)
+
+    def createScale(self):
+        self.scaleCtrl = Scale(self.interior(),
+                               label = "Graph Scale",
+                               from_= 0.0,
+                               to = 20.0,
+                               resolution = 0.1,
+                               orient = HORIZONTAL,
+                               command = self.onScaleUpdate)
+        
+        self.scaleCtrl.pack(side = LEFT, fill = BOTH, expand = 1)
+        self.scaleCtrl.set(0.0)
+        
+    def createRefreshBT(self):
+        self.refreshBT = Button(self.interior(), text = 'Refresh', command = self.refresh)
+        self.refreshBT.pack(side = LEFT, fill = BOTH, expand = 1)
+
+    #--------------------------------------------------------------------------
+    # Item Ctrls
+    #--------------------------------------------------------------------------          
+    def createDefaultCtrls(self):
+        if self.renderItem == None or self.render2dItem == None:
+            return
+        
+        totalBytes = self.renderItem.getVertexBytes()+self.render2dItem.getVertexBytes()
+        
+        self.addChildCtrl(self.renderItem, totalBytes)
+        self.addChildCtrl(self.render2dItem, totalBytes)
+
+        self.setTitle("ALL", totalBytes)
+                      
+    def setTitle(self, parent, bytes):
+        self.frame["label_text"] = "[%s] - %s bytes" % (parent, bytes)        
+
+    def resetCtrls(self):    
+        for button in self.buttons:
+            self.balloon.unbind(button)
+            button.destroy()
+        self.buttons = []
+
+        for label in self.labels:
+            label.destroy()
+        self.labels = []
+
+    def getNewButton(self, width, ratio):         
+        newBT =  Button(self.frame.interior(),                        
+                        anchor = W,
+                        width = width)
+
+        if ratio == 0.0:
+            newBT['bg'] = "grey"
+            newBT['text'] = "."
+        else:
+            newBT['bg'] = Pmw.Color.hue2name(0.0, 1.0-ratio)
+            newBT['text'] = "%0.2f%%" % (ratio*100.0)
+
+        return newBT
+
+    def addSelfCtrl(self, item, totalBytes):
+        self.addLabel("[self] : %s bytes" % item.getSelfVertexBytes())
+
+        bt = self.addButton(item.getSelfVertexBytes(),
+                            totalBytes,
+                            self.onSelfButtonLClick,
+                            self.onSelfButtonRClick,
+                            item)
+ 
+    def addChildCtrl(self, item, totalBytes):
+        self.addLabel("%s [+%s] : %s bytes" % (item.getName(),
+                                                item.getNumChildren(),
+                                                item.getVertexBytes()))
+        
+        bt = self.addButton(item.getVertexBytes(),
+                            totalBytes,
+                            self.onChildButtonLClick,
+                            self.onChildButtonRClick,
+                            item)
+
+    def addButton(self, vertexBytes, totalBytes, funcLClick, funcRClick, item):
+        width = self.getBTWidth(vertexBytes, totalBytes)
+
+        if totalBytes == 0:
+            ratio = 0.0
+        else:
+            ratio = vertexBytes/float(totalBytes)
+
+        bt = self.getNewButton(width, ratio)
+
+        def callbackL(event):
+            funcLClick(item)
+            
+        def callbackR(event):
+            funcRClick(item)
+
+        bt.bind("<Button-1>", callbackL)
+        bt.bind("<Button-3>", callbackR)
+        
+        bt.pack(side = TOP, anchor = NW)
+        self.buttons.append(bt)
+
+        self.balloon.bind(bt, item.getPathName())        
+
+        return bt
+
+    def addLabel(self, label):
+        label = Label(self.frame.interior(), text = label)
+        label.pack(side = TOP, anchor = NW,  expand = 0)
+        self.labels.append(label)           
+
+    def getBTWidth(self, vertexBytes, totalBytes):
+        if totalBytes == 0:
+            return 1
+        
+        width = int(self.btWidth * vertexBytes / totalBytes)
+
+        if width == 0:
+            width = 1
+            
+        return width
+
+    #--------------------------------------------------------------------------
+    # Callback
+    #--------------------------------------------------------------------------
+    def onScaleUpdate(self, arg):
+        self.btWidth = DEFAULT_BT_WIDTH +  DEFAULT_BT_WIDTH * float(arg)
+
+        if self.rootItem:
+            self.updateBTWidth()
+        else:
+            self.updateDefaultBTWidth()
+
+    def updateBTWidth(self):
+        self.buttons[0]['width'] = self.getBTWidth(self.rootItem.getSelfVertexBytes(),
+                                                   self.rootItem.getVertexBytes())
+
+        btIndex = 1
+        for item in self.rootItem.getChildrenAsList():
+            self.buttons[btIndex]['width'] = self.getBTWidth(item.getVertexBytes(),
+                                                             self.rootItem.getVertexBytes())
+            btIndex += 1        
+
+    def updateDefaultBTWidth(self):
+        if self.renderItem == None or self.render2dItem == None:
+            return
+        totalBytes = self.renderItem.getVertexBytes() + self.render2dItem.getVertexBytes()
+        self.buttons[0]['width'] = self.getBTWidth(self.renderItem.getVertexBytes(), totalBytes)
+        self.buttons[1]['width'] = self.getBTWidth(self.render2dItem.getVertexBytes(), totalBytes)                   
+    
+    def onSelfButtonLClick(self, item):
+        pass
+
+    def onSelfButtonRClick(self, item):
+        parentItem = item.getParent()
+        self.resetCtrls()
+        self.addItemCtrls(parentItem)     
+
+    def onChildButtonLClick(self, item):
+        if item.getNumChildren() == 0:
+            return
+        
+        self.resetCtrls()
+        self.addItemCtrls(item)
+
+    def onChildButtonRClick(self, item):
+        parentItem = item.getParent()
+        
+        if parentItem:
+            self.resetCtrls()            
+            self.addItemCtrls(parentItem.getParent())
+
+    def addItemCtrls(self, item):
+        self.rootItem = item        
+        if item == None:
+            self.createDefaultCtrls()
+        else:
+            self.addSelfCtrl(item, item.getVertexBytes())
+                               
+            for child in item.getChildrenAsList():
+                self.addChildCtrl(child, item.getVertexBytes())
+                
+            self.setTitle(item.getPathName(), item.getVertexBytes())
+
+    #--------------------------------------------------------------------------
+    # List & Analyze
+    #--------------------------------------------------------------------------          
+    def makeList(self):
+        self.renderItem = MemoryExplorerItem(None, render)
+        self.buildList(self.renderItem)
+
+        self.render2dItem = MemoryExplorerItem(None, render2d)
+        self.buildList(self.render2dItem)
+
+    def buildList(self, parentItem):        
+        for nodePath in parentItem.nodePath.getChildrenAsList():
+            item = MemoryExplorerItem(parentItem, nodePath)
+            parentItem.addChild(item)
+            self.buildList(item)
+
+    def analyze(self):
+        self.renderItem.analyze()
+        self.render2dItem.analyze()
+                                
+    def refresh(self):          
+        self.makeList()
+        self.analyze()
+        
+        self.resetCtrls()
+        self.createDefaultCtrls()
+
+#--------------------------------------------------------------------------
+#--------------------------------------------------------------------------
+class MemoryExplorerItem:
+    def __init__(self, parent, nodePath):
+        self.parent = parent
+        self.nodePath = nodePath
+        self.children = []
+        
+        self.selfVertexBytes = 0
+        self.childrenVertexBytes = 0
+        
+        self.numFaces = 0
+        self.textureBytes = 0
+
+        if parent:
+            self.pathName = parent.pathName + "/" +  nodePath.getName()
+        else:
+            self.pathName = nodePath.getName()
+
+    def getParent(self):
+        return self.parent
+
+    def addChild(self, child):
+        self.children.append(child)
+
+    def getNumChildren(self):
+        return len(self.children)
+
+    def getChildrenAsList(self):
+        return self.children
+
+    def getName(self):
+        return self.nodePath.getName()
+
+    def getPathName(self):
+        return self.pathName
+
+    def getVertexBytes(self):
+        return self.selfVertexBytes + self.childrenVertexBytes
+
+    def getSelfVertexBytes(self):
+        return self.selfVertexBytes
+
+    def analyze(self):
+        self.selfVertexBytes = 0
+        self.childrenVertexBytes = 0
+        
+        self.numFaces = 0
+        self.textureBytes = 0
+        
+        self.calcTextureBytes()
+        
+        if self.nodePath.node().isGeomNode():
+            geomNode = self.nodePath.node()
+            
+            for i in range(geomNode.getNumGeoms()):
+                geom = geomNode.getGeom(i)
+                self.calcVertexBytes(geom)
+                self.calcNumFaces(geom)
+
+        self.analyzeChildren()
+
+    def calcVertexBytes(self, geom):
+        vData = geom.getVertexData()
+        for j in range(vData.getNumArrays()):
+            array = vData.getArray(j)
+            self.selfVertexBytes += array.getDataSizeBytes()
+
+    def calcTextureBytes(self):
+        texCol = self.nodePath.findAllTextures()
+        for i in range(texCol.getNumTextures()):
+            tex = texCol.getTexture(i)
+            self.textureBytes += tex.estimateTextureMemory()
+
+            # what about shared textures by multiple nodes ?
+        
+    def calcNumFaces(self, geom):
+        for k in range(geom.getNumPrimitives()):
+            primitive = geom.getPrimitive(k)
+            self.numFaces += primitive.getNumFaces()
+
+    def analyzeChildren(self):
+        for child in self.children:
+            child.analyze()
+            self.childrenVertexBytes += child.getVertexBytes()
+            self.numFaces += child.numFaces        
+
+    def ls(self, indent = ""):
+        print(indent + self.nodePath.getName() + " " + str(self.vertexBytes) + " " + str(self.numFaces) + " " + str(self.textureBytes))
+        indent = indent +  " "
+
+        for child in self.children:
+            child.ls(indent)