Source code for direct.tkwidgets.MemoryExplorer

from direct.showbase.DirectObject import DirectObject
from direct.showbase.TkGlobal import *
from .Tree import *
import Pmw

#--------------------------------------------------------------------------
#--------------------------------------------------------------------------
DEFAULT_BT_WIDTH = 50.0

#--------------------------------------------------------------------------
#--------------------------------------------------------------------------
[docs]class MemoryExplorer(Pmw.MegaWidget, DirectObject): #-------------------------------------------------------------------------- # Init #--------------------------------------------------------------------------
[docs] def __init__(self, parent = None, nodePath = None, **kw): if nodePath is None: nodePath = render 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())
[docs] 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)
[docs] 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)
[docs] def createRefreshBT(self): self.refreshBT = Button(self.interior(), text = 'Refresh', command = self.refresh) self.refreshBT.pack(side = LEFT, fill = BOTH, expand = 1)
#-------------------------------------------------------------------------- # Item Ctrls #--------------------------------------------------------------------------
[docs] def createDefaultCtrls(self): if self.renderItem is None or self.render2dItem is None: return totalBytes = self.renderItem.getVertexBytes()+self.render2dItem.getVertexBytes() self.addChildCtrl(self.renderItem, totalBytes) self.addChildCtrl(self.render2dItem, totalBytes) self.setTitle("ALL", totalBytes)
[docs] def setTitle(self, parent, bytes): self.frame["label_text"] = "[%s] - %s bytes" % (parent, bytes)
[docs] 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 = []
[docs] 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
[docs] def addSelfCtrl(self, item, totalBytes): self.addLabel("[self] : %s bytes" % item.getSelfVertexBytes()) bt = self.addButton(item.getSelfVertexBytes(), totalBytes, self.onSelfButtonLClick, self.onSelfButtonRClick, item)
[docs] 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)
[docs] 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
[docs] def addLabel(self, label): label = Label(self.frame.interior(), text = label) label.pack(side = TOP, anchor = NW, expand = 0) self.labels.append(label)
[docs] def getBTWidth(self, vertexBytes, totalBytes): if totalBytes == 0: return 1 width = int(self.btWidth * vertexBytes / totalBytes) if width == 0: width = 1 return width
#-------------------------------------------------------------------------- # Callback #--------------------------------------------------------------------------
[docs] def onScaleUpdate(self, arg): self.btWidth = DEFAULT_BT_WIDTH + DEFAULT_BT_WIDTH * float(arg) if self.rootItem: self.updateBTWidth() else: self.updateDefaultBTWidth()
[docs] def updateBTWidth(self): self.buttons[0]['width'] = self.getBTWidth(self.rootItem.getSelfVertexBytes(), self.rootItem.getVertexBytes()) btIndex = 1 for item in self.rootItem.getChildren(): self.buttons[btIndex]['width'] = self.getBTWidth(item.getVertexBytes(), self.rootItem.getVertexBytes()) btIndex += 1
[docs] def updateDefaultBTWidth(self): if self.renderItem is None or self.render2dItem is 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)
[docs] def onSelfButtonLClick(self, item): pass
[docs] def onSelfButtonRClick(self, item): parentItem = item.getParent() self.resetCtrls() self.addItemCtrls(parentItem)
[docs] def onChildButtonLClick(self, item): if item.getNumChildren() == 0: return self.resetCtrls() self.addItemCtrls(item)
[docs] def onChildButtonRClick(self, item): parentItem = item.getParent() if parentItem: self.resetCtrls() self.addItemCtrls(parentItem.getParent())
[docs] def addItemCtrls(self, item): self.rootItem = item if item is None: self.createDefaultCtrls() else: self.addSelfCtrl(item, item.getVertexBytes()) for child in item.getChildren(): self.addChildCtrl(child, item.getVertexBytes()) self.setTitle(item.getPathName(), item.getVertexBytes())
#-------------------------------------------------------------------------- # List & Analyze #--------------------------------------------------------------------------
[docs] def makeList(self): self.renderItem = MemoryExplorerItem(None, render) self.buildList(self.renderItem) self.render2dItem = MemoryExplorerItem(None, render2d) self.buildList(self.render2dItem)
[docs] def buildList(self, parentItem): for nodePath in parentItem.nodePath.getChildren(): item = MemoryExplorerItem(parentItem, nodePath) parentItem.addChild(item) self.buildList(item)
[docs] def analyze(self): self.renderItem.analyze() self.render2dItem.analyze()
[docs] def refresh(self): self.makeList() self.analyze() self.resetCtrls() self.createDefaultCtrls()
#-------------------------------------------------------------------------- #--------------------------------------------------------------------------
[docs]class MemoryExplorerItem:
[docs] 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()
[docs] def getParent(self): return self.parent
[docs] def addChild(self, child): self.children.append(child)
[docs] def getNumChildren(self): return len(self.children)
[docs] def getChildren(self): return self.children
[docs] def getName(self): return self.nodePath.getName()
[docs] def getPathName(self): return self.pathName
[docs] def getVertexBytes(self): return self.selfVertexBytes + self.childrenVertexBytes
[docs] def getSelfVertexBytes(self): return self.selfVertexBytes
[docs] 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()
[docs] def calcVertexBytes(self, geom): vData = geom.getVertexData() for j in range(vData.getNumArrays()): array = vData.getArray(j) self.selfVertexBytes += array.getDataSizeBytes()
[docs] 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 ?
[docs] def calcNumFaces(self, geom): for k in range(geom.getNumPrimitives()): primitive = geom.getPrimitive(k) self.numFaces += primitive.getNumFaces()
[docs] def analyzeChildren(self): for child in self.children: child.analyze() self.childrenVertexBytes += child.getVertexBytes() self.numFaces += child.numFaces
[docs] 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)