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 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 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 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 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)