Notifications
Clear all

[Closed] Viewport Statistics Improvement

I had an idea for a much improved viewport statistics, I made something that did the basics then Daniel Santana got involved and improved it. There’s still a lag with a large amount of objects for getting the total poly counts or if you have a lot of objects selected.

Can anyone make it faster? @DenisT the viewport statistics that exist would be nice to expose

/*
Advanced Viewport Stats
(c) 2015 Dave Wortley & Daniel Santana
*/
try(unregisterRedrawViewsCallback drawStatsInfo.drawObjNameInfo)catch()
gc light:true
global drawStatsInfo
try(dw_ds_callback.enabled = false)catch()
dw_ds_callback = undefined
global dw_ds_callback	

fn dw_ds_formatNumber val =
(
	local l = val.count
	while (l - 2) > 1 do (val = replace val (l - 2) 0 ","; l -= 3)
	val
)


struct drawStatsInfo
(
	lastObjectHandle,
	lastObjectName,
	lastObjectLayer,
	lastObjectClass, 
	lastObjectSuperClass, 
	lastObjectParent,
	lastObjectChilds,
	lastObjectMat,
	lastObjectFaceCount,
	lastObjectVertCount,
	lastObjectSize,
	lastObjectDebug = "",
	totalCounts,
	totalFaceCount,
	totalVertCount,
	totalDebug = "",
	updateObjectSizeDebug ="
",
	disableTotalCount = true,
	debug = false,
	cfg = "$plugcfg/drawstatsinfo.ini",
	ver = 0.7,
	enabled = false,
	
	fn updateObjectStats force:false =
	(
		st = timestamp()
		if selection.count != 1 do return()
		obj = selection[1]
		if force == false and drawStatsInfo.lastObjectHandle == GetHandleByAnim obj do return()
		drawStatsInfo.lastObjectHandle = GetHandleByAnim obj
		drawStatsInfo.lastObjectName = obj.name
		drawStatsInfo.lastObjectClass = (classof obj) as string
		drawStatsInfo.lastObjectSuperClass = (superclassof obj) as string
		drawStatsInfo.lastObjectLayer = obj.layer.name
		drawStatsInfo.lastObjectParent = (if obj.parent == undefined then "sceneRootNode" else obj.parent.name)
		drawStatsInfo.lastObjectChilds = dw_ds_formatNumber (obj.children.count as string)
		drawStatsInfo.lastObjectMat = (if obj.material != undefined then classof obj.material as string + ": " + obj.material.name as string else "Unassigned")
		drawStatsInfo.lastObjectFaceCount = (if superclassof obj == geometryclass then "
Faces: " + (dw_ds_formatNumber (obj.mesh.faces.count as string)) else "")
		drawStatsInfo.lastObjectVertCount = (if superclassof obj == geometryclass then "
Vertices: " + (dw_ds_formatNumber (obj.mesh.vertices.count as string)) else "")
		s = obj.max - obj.min
		f = units.formatValue
		drawStatsInfo.lastObjectSize = "
Size: X=" + f(s.x) + " Y=" + f(s.y) + " Z:" + f(s.z)
		--if drawStatsInfo.debug do 
		(
			ss = stringstream ""
			format "

[DEBUG]
updateObject took: %s
" ((timestamp()-st)/1000.0) to:ss
			drawStatsInfo.lastObjectDebug = ss as string
			--format (ss as string)
		)
	),
	
	fn drawObjNameInfo =
	(
		try
		(
		textColour = (colorMan.getColor #activeViewportBorder) * 255.0
		textColour = color 196 196 196
			
		--tt = fileProperties.getItems "Mesh Totals"
		--st = fileProperties.getItems "Scene Totals"
		drawStatsInfo.updateObjectStats()
		dtext = case of
		(
			(selection.count == 0): (
				""
			)
			(selection.count == 1): (		
				"Object: " + drawStatsInfo.lastObjectName + \
				"
Class: " + drawStatsInfo.lastObjectClass + "  (" + drawStatsInfo.lastObjectSuperClass + ")" + \
				"
Layer: " + drawStatsInfo.lastObjectLayer + \
				"
Parent: " + drawStatsInfo.lastObjectParent + \
				"
Children: " + drawStatsInfo.lastObjectChilds + \
				"
Material: " + drawStatsInfo.lastObjectMat + \
				drawStatsInfo.lastObjectFaceCount + \
				drawStatsInfo.lastObjectVertCount + \
				drawStatsInfo.lastObjectSize + \
				(if drawStatsInfo.debug then drawStatsInfo.lastObjectDebug else "") + \
				(if drawStatsInfo.debug then drawStatsInfo.totalDebug else "") + \
				(if drawStatsInfo.debug then drawStatsInfo.updateObjectSizeDebug as string else "") + \
				(if not drawStatsInfo.disableTotalCount then "

Total Faces: "  + drawStatsInfo.totalFaceCount else "
") + \
				--"
Total Vertices: "  + drawStatsInfo.totalVertCount  + \
				"
Scene Object Count: "  + objects.count as string + \
				"
FPS: " + viewport.getFPS() as string
				
			)
			(selection.count > 1): (
				types = #()
				for o in selection do appendifunique types ((classof o))
				
				(selection.count as string) + " Objects Selected" + \
				"
" + (types.count as string) + " classes " + (types as string) + \
				"
Geometry: " + (for o in selection where superclassof o == geometryclass collect o).count as string + \
				"
Shapes: " + (for o in selection where superclassof o == shape collect o).count as string + \
				"
Lights: " + (for o in selection where superclassof o == light collect o).count as string + \
				"
Cameras: " + (for o in selection where superclassof o == camera collect o).count as string + \
				"
Helpers: " + (for o in selection where superclassof o == helper collect o).count as string + \
				"
Space Warps: " + (for o in selection where superclassof o == spacewarpObject collect o).count as string --+ \
				--"
Particle Systems: " + (for o in selection where superclassof o == particlesystem collect o).count as string + \
				--"
Bone Objects: " + (for o in selection where superclassof o == geometryclass collect o).count as string
				
				
			)
		)
		
		
		local pos = [10,38]
			
		gw.setTransform(Matrix3 1)
		gw.wText [pos.x, pos.y, 0] dtext color:textColour
		)
		catch(print ("issue" + (getCurrentException())))
	),
	fn loadSettings =
	(
		if not doesfileexist cfg do return false
		if hasINISetting  drawStatsInfo.cfg "Options" "Debug" do
			drawStatsInfo.debug = getIniSetting drawStatsInfo.cfg "Options" "Debug" as BooleanClass
		if hasINISetting  drawStatsInfo.cfg "Options" "TotalCount" do
			drawStatsInfo.disableTotalCount = getIniSetting drawStatsInfo.cfg "Options" "TotalCount" as BooleanClass
		if hasINISetting  drawStatsInfo.cfg "Options" "Enabled" do
			drawStatsInfo.enabled = getIniSetting drawStatsInfo.cfg "Options" "Enabled" as BooleanClass
	),
	fn show =
	(
		global dw_ds_DrawStatsInfoUI
		try(destroydialog dw_ds_DrawStatsInfoUI)catch()
		rollout dw_ds_DrawStatsInfoUI "Viewport Stat Options" width:245
		(
			group "Options"
			(
				checkbox ckbDebug "Debug mode" checked:drawStatsInfo.debug
				on ckbDebug changed val do drawStatsInfo.debug = ckbDebug.checked
				checkbox ckbTotal "Enable total face count" checked:(not drawStatsInfo.disableTotalCount)
			)
			checkbutton ckbEnable "Enabled" checked:drawStatsInfo.enabled
			button btnClose "Close" align:#right
			on btnClose pressed do try(destroydialog dw_ds_DrawStatsInfoUI)catch()
			label lblVer "Version: 0.000" align:#left
			hyperLink lblAbout1 "© 2015 Dave Wortley" address:"http://www.taylorjames.com/" across:3 align:#left
			label lblAboutM "and" align:#middle offset:[15,0]
			hyperLink lblAbout2 "Daniel Santana" address:"http://www.ycdivfx.com/" align:#left
			
			on dw_ds_DrawStatsInfoUI open do lblVer.text = "Version: " + drawStatsInfo.ver as string
			
			on dw_ds_DrawStatsInfoUI close do
			(
				setIniSetting drawStatsInfo.cfg "Options" "Debug" (drawStatsInfo.debug as string)
				setIniSetting drawStatsInfo.cfg "Options" "TotalCount" (drawStatsInfo.disableTotalCount as string)
				setIniSetting drawStatsInfo.cfg "Options" "Enabled" (drawStatsInfo.enabled as string)
			)
			
			on ckbTotal changed val do
			(
				drawStatsInfo.disableTotalCount = not val
				if not drawStatsInfo.disableTotalCount do ::dw_ds_updateTotals ok ok
			)
			
			on ckbEnable changed val do
			(
				::drawStatsInfo.enabled = val
				::drawStatsInfo.enable()
			)

		)
		createdialog dw_ds_DrawStatsInfoUI
	),
	fn createMacros =
	(
		files = getfiles (pathConfig.appendPath (getdir #usermacros) "*.mcr")
		macr = for f in files where findstring (tolower (getfilenamefile f)) "dwdsviewportstats" != undefined collect f
		if macr.count == 0 do
		(
			macros.new "Views" "Macro_DwDsViewportStats" "DrawStatsInfoUI" "DrawStatsInfoUI" "
on execute do
(
::drawStatsInfo.show();
)
"
			format "DrawStatsInfo Macro created.
"
		)
	),
	fn enable =
	(
		try(unregisterRedrawViewsCallback drawStatsInfo.drawObjNameInfo)catch()
		if drawStatsInfo.enabled do registerRedrawViewsCallback (drawStatsInfo.drawObjNameInfo)
	),
	fn setup =
	(
		drawStatsInfo.loadSettings()
		drawStatsInfo.createMacros()
		drawStatsInfo.enable()
	)--,
	--init = setup()
)
if not IsNetServer() do
(
drawStatsInfo = drawStatsInfo()
drawStatsInfo.setup()
global dw_ds_updateTotals
global dw_ds_updateObject
global dw_ds_updateObjectSize

fn dw_ds_updateTotals evt nds =
(
	try(
	st = timestamp()
	drawStatsInfo.totalCounts = objects.count as string
	--tv = 0
	tf = 0
	--for o in objects where superclassof o == geometryclass do (try(tv += o.mesh.numvertices)catch())
	if not drawStatsInfo.disableTotalCount do for o in objects where superclassof o == geometryclass do (try(tf += o.mesh.numfaces)catch())
	drawStatsInfo.totalFaceCount = dw_ds_formatNumber (tf as string)
	--drawStatsInfo.totalVertCount = tv as string
	drawStatsInfo.updateObjectStats force:true
	--if drawStatsInfo.debug do
	(
		ss = stringstream ""
		format "updateTotals took: %s" ((timestamp()-st)/1000.0) to:ss
		drawStatsInfo.totalDebug = ss as string
		--format (ss as string)
	)
	)catch()
)
fn dw_ds_updateObject evt nds =
(
	try
	(
		drawStatsInfo.updateObjectStats force:true
	)
	catch()
)
fn dw_ds_updateObjectSize evt nds =
(
	try
	(
		st = timestamp()
		if selection.count != 1 do return()
		obj = selection[1]
		s = obj.max - obj.min
		f = units.formatValue
		drawStatsInfo.lastObjectSize = "
Size: X=" + f(s.x) + " Y=" + f(s.y) + " Z:" + f(s.z)
		--if drawStatsInfo.debug do
		(
			ss = stringstream ""
			format "
updateObjectSize took: %s" ((timestamp()-st)/1000.0) to:ss
			drawStatsInfo.updateObjectSizeDebug = ss as string
			--format (ss as string)
		)
	)
	catch(print "ooops")
)
dw_ds_updateTotals undefined undefined
dw_ds_callback = NodeEventCallback enabled:true mouseup:true delay:50 topologyChanged:(dw_ds_updateTotals) added:(dw_ds_updateTotals) deleted:(dw_ds_updateTotals) materialStructured:(dw_ds_updateObject) nameChanged:(dw_ds_updateObject) geometryChanged:(dw_ds_updateObjectSize) controllerOtherEvent:(dw_ds_updateObjectSize)
)

22 Replies

I did a quick test and the whole slowdown seems to revolve around this:

for o in objects where superclassof o == geometryclass do (try(tf += o.mesh.numfaces)catch())

– time:1734 ram:178776L tris:19245792

As you are getting the mesh of every object, it will be indeed slow. Even the build in Polygon Counter Utility is as slow as your script.

Do you need to get the number of polygons or triangles?
Do you have Editable Poly and Editable Mesh on the same scene?

1 Reply
(@denist)
Joined: 11 months ago

Posts: 0

*.mesh access is a bottleneck. if you count editable meshes and editable polys it might faster because you can get number verts and faces(polys) using deformable object polycount.

def_visible_primitive(getPolygonCount, "getPolygonCount");
Value* getPolygonCount_cf(Value** arg_list, int count)
{
	check_arg_count(getPolygonCount, 1, count);
	INode* node = arg_list[0]->to_node();
	TimeValue t = MAXScript_time();
	ObjectState os = node->EvalWorldState(t);
	if (os.obj && os.obj->IsRenderable() && os.obj->IsDeformable()) 
    {
		int numv, numf;
		os.obj->PolygonCount(t, numf, numv);
		return new Point2Value(Point2(numv, numf));
	}
	return new Point2Value(0.0f, 0.0f);
} 

also you can get verts and faces count using render mesh instead of trimesh which is faster because doesn’t need conversion


def_visible_primitive(numVertsAndTris, "numVertsAndTris");
Value* numVertsAndTris_cf(Value** arg_list, int count)
{
	check_arg_count(numVertsAndTris, 1, count);
	INode* node = arg_list[0]->to_node();
	TimeValue t = MAXScript_time();
	const ObjectState& os = node->EvalWorldState(t); // Get the object that is referenced at the time
	Object* ob = os.obj;
	if (ob && (ob->SuperClassID() == GEOMOBJECT_CLASS_ID || ob->SuperClassID() == SHAPE_CLASS_ID))
	{
		BOOL needDel;
		NullView nullView;	// Set up a null viewport so that we get the right mesh..
		Mesh *mesh = ((GeomObject*)ob)->GetRenderMesh(t, node, nullView, needDel); // Type cast to a geometric object and then retriev
		int numv = mesh->numVerts;
		int numf = mesh->numFaces;
		if (needDel) delete mesh;
		return new Point2Value(Point2(numv, numf));
	}
	return new Point2Value(0.0f, 0.0f);
}

I like it.
But, tell everyone that the script installs a macro under “Views” category. I spend few minutes wondering why the script not works. Only reading the code can tell us how to use the script.

The Size of the object measure the world boundingbox of the object and shows that dimension – the same as is shown in the Utilities – Measure. But when you open the Object Properties(from the quad menu) you will get the size of the object using its local bounding box.

I remember that I’ve told you about the same when you released the Object Properties 2.0 script.

PolyTools3D
o.mesh creates a copy of the mesh each time when it is executed, right?

I remember that there is a command in maxscript that returns the count of the faces/polygons, verts, etc as array, but I can’t find it.
If someone knows it…

For polys or objects with modifiers yes:

(
	poly = converttopoly (sphere segments:200)
	mesh = converttomesh (sphere segments:200)

	gc()
	st=timestamp(); sh=heapfree
	tris = 0
	for j = 1 to 100 do tris += poly.mesh.numfaces
	format "time:% ram:% tris:%
" (timestamp()-st) (sh-heapfree) tris
	
	gc()
	st=timestamp(); sh=heapfree
	tris = 0
	for j = 1 to 100 do tris += mesh.mesh.numfaces
	format "time:% ram:% tris:%
" (timestamp()-st) (sh-heapfree) tris
	
	delete #(poly, mesh)
)

– time:281 ram:7488L tris:3960000
– time:0 ram:7496L tris:3960000

getPolygonCount(), but its broken.

4 Replies
(@dgsantana)
Joined: 11 months ago

Posts: 0

In 2016, seems to work ok, and its fast. For 13 millions took 0.038s, which for me seems aceptable. I will try DennisT solution also, but if we could keep this without needing extra files, it would be great. Easy sharing

with a modifier on top

(@miauu)
Joined: 11 months ago

Posts: 0

The same. Thank you. I have often to use INDEX tab when using maxscritp reference, because SEARCH tab returns nothing for “getPoly” or “getPolygon”.

dgsantana, what about the size issue?

(@dgsantana)
Joined: 11 months ago

Posts: 0

What was the problem, exactly? Right now it uses the bounding box for determine the size.

I was building the c++ version that dennisT posted, and also doing a c# version, (dynamic compile), and check the results, see if I could get away from using an extra dlx. Just so we could get the right count results (tris).

(@miauu)
Joined: 11 months ago

Posts: 0

Create a box. Rotate it. Then check its size using Utilities-Measure and right click – Object Properties. You will see that there are two diferent sizes of the same object.
Utilities-Measure gives you the size according the world boundingbox ($.min-$.max), the ObjectProperties gives you the size using the local bbox of the object.

For example:

  • box with X = 100 Y = 100, Z = 100 units size.
  • rotate it 45 deg along the X axis
  • Utilities – Measure(and your script) will gives you: Dimensions: X = 100, Y = 141.421, Z = 141.421
  • riglh click – Object Properties will gives you: Dimensins: X = 100, Y = 100, Z = 100.

Yes, it is much faster.

Unfortunately it doesn’t seem to be fixed in Max 2016. According to the documentation it should return the number of triangles.

5 Replies
(@denist)
Joined: 11 months ago

Posts: 0

it depends on base mesh type. if the base mesh is Mesh it returns tris, if the base is MNMesh it returns polygons

(@polytools3d)
Joined: 11 months ago

Posts: 0

Not exactly.
A base Mesh with an Edit Poly modifier returns polygons.
A base Poly with an Edit Mesh modifier returns tris.

And from the help:
“…The number of faces and vertices returned are the number that would be present if the node was converted to a mesh object…”
Which is not true.

Daniel, if getPolygonCount() does the work you are looking for then you might want to just use obj.numfaces or getnumfaces(), both are 20 times faster than getPolygonCount()

(@dgsantana)
Joined: 11 months ago

Posts: 0

Well, there was some (probably strange) reason for me and Dave not using it. I still need to try in a few real scenes, this last solution.

(@polytools3d)
Joined: 11 months ago

Posts: 0

It might not be strange at all. The number of polygons and the number of triangles are two completely different things.

For real time engines development, the number of polygons is not much relevant, so what you would often want to know is the number of triangles.

For getting the number of triangles of any object class, the only MXS build-in solution I know is the one you are currently using, get the mesh of the object and then the number of faces.

But I wouldn’t be surprised if there is another easter egg lost in the undocumented MXS universe.

(@denist)
Joined: 11 months ago

Posts: 0

i forgot. it returns according to current object state. where
A base Mesh with an Edit Poly modifier is PolyMeshObject
A base Poly with an Edit Mesh modifier is Editable_mesh

There is indeed a native method for getting the number of Tris.

GetTriMeshFaceCount()

And it is well documented.
I may should say: “It is, well, documented”.
Better yet: “Well, it is documented”

Now that we have:

[b]GetPolygonCount[/b]() -- Returns the number of polygons at the top of the modifier stack
[b]GetTriMeshFaceCount[/b]() -- Returns the number of triangles at the top of the modifier stack

I think both work well, as they were planned. It is just the documentation of the GetPolygonCount() function what is wrong.

Great find Jorge . miauu, you are right I will change it during the day to use the local bbox instead of the world one.
Here is the changed code.


/*
Advanced Viewport Stats
(c) 2015 Dave Wortley & Daniel Santana
*/
try(unregisterRedrawViewsCallback drawStatsInfo.drawObjNameInfo)catch()
gc light:true
global drawStatsInfo
try(dw_ds_callback.enabled = false)catch()
dw_ds_callback = undefined
global dw_ds_callback	

fn dw_ds_formatNumber val =
(
	local l = val.count
	while (l - 2) > 1 do (val = replace val (l - 2) 0 ","; l -= 3)
	val
)


struct drawStatsInfo
(
	lastObjectHandle,
	lastObjectName,
	lastObjectLayer,
	lastObjectClass, 
	lastObjectSuperClass, 
	lastObjectParent,
	lastObjectChilds,
	lastObjectMat,
	lastObjectFaceCount,
	lastObjectVertCount,
	lastObjectSize,
	lastObjectDebug = "",
	totalCounts,
	totalFaceCount,
	totalVertCount,
	totalDebug = "",
	updateObjectSizeDebug ="
",
	disableTotalCount = true,
	debug = false,
	cfg = "$plugcfg/drawstatsinfo.ini",
	ver = 0.8,
	enabled = false,
	
	fn updateObjectStats force:false =
	(
		st = timestamp()
		if selection.count != 1 do return()
		obj = selection[1]
		if force == false and drawStatsInfo.lastObjectHandle == GetHandleByAnim obj do return()
		drawStatsInfo.lastObjectHandle = GetHandleByAnim obj
		drawStatsInfo.lastObjectName = obj.name
		drawStatsInfo.lastObjectClass = (classof obj) as string
		drawStatsInfo.lastObjectSuperClass = (superclassof obj) as string
		drawStatsInfo.lastObjectLayer = obj.layer.name
		drawStatsInfo.lastObjectParent = (if obj.parent == undefined then "sceneRootNode" else obj.parent.name)
		drawStatsInfo.lastObjectChilds = dw_ds_formatNumber (obj.children.count as string)
		drawStatsInfo.lastObjectMat = (if obj.material != undefined then classof obj.material as string + ": " + obj.material.name as string else "Unassigned")
		drawStatsInfo.lastObjectFaceCount = (if superclassof obj == geometryclass then "
Faces: " + (dw_ds_formatNumber (obj.mesh.faces.count as string)) else "")
		drawStatsInfo.lastObjectVertCount = (if superclassof obj == geometryclass then "
Vertices: " + (dw_ds_formatNumber (obj.mesh.vertices.count as string)) else "")
		s = obj.max - obj.min
		f = units.formatValue
		drawStatsInfo.lastObjectSize = "
Size: X=" + f(s.x) + " Y=" + f(s.y) + " Z:" + f(s.z)
		--if drawStatsInfo.debug do 
		(
			ss = stringstream ""
			format "

[DEBUG]
updateObject took: %s
" ((timestamp()-st)/1000.0) to:ss
			drawStatsInfo.lastObjectDebug = ss as string
			--format (ss as string)
		)
	),
	
	fn drawObjNameInfo =
	(
		try
		(
		textColour = (colorMan.getColor #activeViewportBorder) * 255.0
		textColour = color 196 196 196
			
		--tt = fileProperties.getItems "Mesh Totals"
		--st = fileProperties.getItems "Scene Totals"
		drawStatsInfo.updateObjectStats()
		dtext = case of
		(
			(selection.count == 0): (
				""
			)
			(selection.count == 1): (		
				"Object: " + drawStatsInfo.lastObjectName + \
				"
Class: " + drawStatsInfo.lastObjectClass + "  (" + drawStatsInfo.lastObjectSuperClass + ")" + \
				"
Layer: " + drawStatsInfo.lastObjectLayer + \
				"
Parent: " + drawStatsInfo.lastObjectParent + \
				"
Children: " + drawStatsInfo.lastObjectChilds + \
				"
Material: " + drawStatsInfo.lastObjectMat + \
				drawStatsInfo.lastObjectFaceCount + \
				drawStatsInfo.lastObjectVertCount + \
				drawStatsInfo.lastObjectSize + \
				(if drawStatsInfo.debug then drawStatsInfo.lastObjectDebug else "") + \
				(if drawStatsInfo.debug then drawStatsInfo.totalDebug else "") + \
				(if drawStatsInfo.debug then drawStatsInfo.updateObjectSizeDebug as string else "") + \
				(if not drawStatsInfo.disableTotalCount then "

Total Faces: "  + drawStatsInfo.totalFaceCount else "
") + \
				--"
Total Vertices: "  + drawStatsInfo.totalVertCount  + \
				"
Scene Object Count: "  + objects.count as string + \
				"
FPS: " + viewport.getFPS() as string
				
			)
			(selection.count > 1): (
				types = #()
				for o in selection do appendifunique types ((classof o))
				
				(selection.count as string) + " Objects Selected" + \
				"
" + (types.count as string) + " classes " + (types as string) + \
				"
Geometry: " + (for o in selection where superclassof o == geometryclass collect o).count as string + \
				"
Shapes: " + (for o in selection where superclassof o == shape collect o).count as string + \
				"
Lights: " + (for o in selection where superclassof o == light collect o).count as string + \
				"
Cameras: " + (for o in selection where superclassof o == camera collect o).count as string + \
				"
Helpers: " + (for o in selection where superclassof o == helper collect o).count as string + \
				"
Space Warps: " + (for o in selection where superclassof o == spacewarpObject collect o).count as string + \
				"
Particle Systems: " + (for o in selection where superclassof o == particlesystem collect o).count as string + \
				"
Bone Objects: " + (for o in selection where superclassof o == geometryclass collect o).count as string
				
				
			)
		)
		
		
		local pos = [10,38]
			
		gw.setTransform(Matrix3 1)
		gw.wText [pos.x, pos.y, 0] dtext color:textColour
		)
		catch(print ("issue" + (getCurrentException())))
	),
	fn loadSettings =
	(
		if not doesfileexist cfg do return false
		if hasINISetting  drawStatsInfo.cfg "Options" "Debug" do
			drawStatsInfo.debug = getIniSetting drawStatsInfo.cfg "Options" "Debug" as BooleanClass
		if hasINISetting  drawStatsInfo.cfg "Options" "TotalCount" do
			drawStatsInfo.disableTotalCount = getIniSetting drawStatsInfo.cfg "Options" "TotalCount" as BooleanClass
		if hasINISetting  drawStatsInfo.cfg "Options" "Enabled" do
			drawStatsInfo.enabled = getIniSetting drawStatsInfo.cfg "Options" "Enabled" as BooleanClass
	),
	fn show =
	(
		global dw_ds_DrawStatsInfoUI
		try(destroydialog dw_ds_DrawStatsInfoUI)catch()
		rollout dw_ds_DrawStatsInfoUI "Viewport Stat Options" width:245
		(
			group "Options"
			(
				checkbox ckbDebug "Debug mode" checked:drawStatsInfo.debug
				on ckbDebug changed val do drawStatsInfo.debug = ckbDebug.checked
				checkbox ckbTotal "Enable total face count" checked:(not drawStatsInfo.disableTotalCount)
			)
			checkbutton ckbEnable "Enabled" checked:drawStatsInfo.enabled
			button btnClose "Close" align:#right
			on btnClose pressed do try(destroydialog dw_ds_DrawStatsInfoUI)catch()
			label lblVer "Version: 0.000" align:#left
			hyperLink lblAbout1 "© 2015 Dave Wortley" address:"http://www.taylorjames.com/" across:3 align:#left
			label lblAboutM "and" align:#middle offset:[15,0]
			hyperLink lblAbout2 "Daniel Santana" address:"http://www.ycdivfx.com/" align:#left
			
			on dw_ds_DrawStatsInfoUI open do lblVer.text = "Version: " + drawStatsInfo.ver as string
			
			on dw_ds_DrawStatsInfoUI close do
			(
				setIniSetting drawStatsInfo.cfg "Options" "Debug" (drawStatsInfo.debug as string)
				setIniSetting drawStatsInfo.cfg "Options" "TotalCount" (drawStatsInfo.disableTotalCount as string)
				setIniSetting drawStatsInfo.cfg "Options" "Enabled" (drawStatsInfo.enabled as string)
			)
			
			on ckbTotal changed val do
			(
				drawStatsInfo.disableTotalCount = not val
				if not drawStatsInfo.disableTotalCount do ::dw_ds_updateTotals ok ok
			)
			
			on ckbEnable changed val do
			(
				::drawStatsInfo.enabled = val
				::drawStatsInfo.enable()
			)

		)
		createdialog dw_ds_DrawStatsInfoUI
	),
	fn createMacros =
	(
		files = getfiles (pathConfig.appendPath (getdir #usermacros) "*.mcr")
		macr = for f in files where findstring (tolower (getfilenamefile f)) "dwdsviewportstats" != undefined collect f
		if macr.count == 0 do
		(
			macros.new "Views" "Macro_DwDsViewportStats" "DrawStatsInfoUI" "DrawStatsInfoUI" "
on execute do
(
::drawStatsInfo.show();
)
"
			format "DrawStatsInfo Macro created.
"
		)
	),
	fn enable =
	(
		try(unregisterRedrawViewsCallback drawStatsInfo.drawObjNameInfo)catch()
		if drawStatsInfo.enabled do registerRedrawViewsCallback (drawStatsInfo.drawObjNameInfo)
	),
	fn setup =
	(
		drawStatsInfo.loadSettings()
		drawStatsInfo.createMacros()
		drawStatsInfo.enable()
	)--,
	--init = setup()
)
if not IsNetServer() do
(
drawStatsInfo = drawStatsInfo()
drawStatsInfo.setup()
global dw_ds_updateTotals
global dw_ds_updateObject
global dw_ds_updateObjectSize

fn dw_ds_updateTotals evt nds =
(
	try(
	st = timestamp()
	drawStatsInfo.totalCounts = objects.count as string
	--tv = 0
	tf = 0
	--for o in objects where superclassof o == geometryclass do (try(tv += o.mesh.numvertices)catch())
	if not drawStatsInfo.disableTotalCount do for o in objects where superclassof o == geometryclass do (try(tf += (GetTriMeshFaceCount o)[1]/*o.mesh.numfaces*/)catch())
	drawStatsInfo.totalFaceCount = dw_ds_formatNumber (tf as string)
	--drawStatsInfo.totalVertCount = tv as string
	drawStatsInfo.updateObjectStats force:true
	--if drawStatsInfo.debug do
	(
		ss = stringstream ""
		format "updateTotals took: %s" ((timestamp()-st)/1000.0) to:ss
		drawStatsInfo.totalDebug = ss as string
		--format (ss as string)
	)
	)catch()
)
fn dw_ds_updateObject evt nds =
(
	try
	(
		drawStatsInfo.updateObjectStats force:true
	)
	catch()
)
fn dw_ds_updateObjectSize evt nds =
(
	try
	(
		st = timestamp()
		if selection.count != 1 do return()
		obj = selection[1]
		s = obj.max - obj.min
		f = units.formatValue
		drawStatsInfo.lastObjectSize = "
Size: X=" + f(s.x) + " Y=" + f(s.y) + " Z:" + f(s.z)
		--if drawStatsInfo.debug do
		(
			ss = stringstream ""
			format "
updateObjectSize took: %s" ((timestamp()-st)/1000.0) to:ss
			drawStatsInfo.updateObjectSizeDebug = ss as string
			--format (ss as string)
		)
	)
	catch(print "ooops")
)
dw_ds_updateTotals undefined undefined
dw_ds_callback = NodeEventCallback enabled:true mouseup:true delay:50 topologyChanged:(dw_ds_updateTotals) added:(dw_ds_updateTotals) deleted:(dw_ds_updateTotals) materialStructured:(dw_ds_updateObject) nameChanged:(dw_ds_updateObject) geometryChanged:(dw_ds_updateObjectSize) controllerOtherEvent:(dw_ds_updateObjectSize)
)


Page 1 / 2