Hello guys. I tried to modified Mesh Info by Roger Hyde to looks the way I like, which is mimicking how modo looks like, here is the code so far:
---------------------------------------------------------------------
-- Based on Mesh Info by; Roger Hyde
-- http://www.scriptspot.com/3ds-max/scripts/meshinfo
---------------------------------------------------------------------
(
function none =
(
if (selection.count == 1) then st = $.name
else if (selection.count >= 2) then st = "Multiple Selected"
else st = "None Selected"
ss = stringstream ""
format "%" st to:ss
return ss as string
)
function getSceneFacesAsString =
(
tf = 0
sf = 0
for o in $geometry do
(
tf += o.mesh.numFaces
if o.isSelected do sf += o.mesh.numFaces
)
tf = (dotNetClass "System.String").Format "{0:n0}" tf
sf = (dotNetClass "System.String").Format "{0:n0}" sf
ss = stringstream ""
format "GL: % (%)" tf sf to:ss
return ss as string
)
function getNumVertsAsString obj =
(
try(
tv = (dotNetClass "System.String").Format "{0:n0}" (obj.baseobject.mesh.numVerts)
sv = (dotNetClass "System.String").Format "{0:n0}" (obj.baseobject.mesh.selectedverts.count)
ss = stringstream ""
format "Verts: % (%)" sv tv to:ss
return ss as string
)catch()
)
function getNumEdgesAsString obj =
(
try(
te = (dotNetClass "System.String").Format "{0:n0}" (obj.baseobject.mesh.edges.count)
se = (dotNetClass "System.String").Format "{0:n0}" (obj.baseobject.mesh.selectededges.count)
ss = stringstream ""
format "Edges: % (%)" se te to:ss
return ss as string
)catch()
)
function getNumFacesAsString obj =
(
try(
tf = (dotNetClass "System.String").Format "{0:n0}" (obj.baseobject.mesh.numFaces)
sf = (dotNetClass "System.String").Format "{0:n0}" (obj.baseobject.mesh.selectedFaces.count)
ss = stringstream ""
format "Tris: % (%)" sf tf to:ss
return ss as string
)catch()
)
-- function getNumPolysAsString obj =
-- (
-- try(
-- tp = (dotNetClass "System.String").Format "{0:n0}" (obj.baseobject.mesh.numFaces)
-- sp = (dotNetClass "System.String").Format "{0:n0}" (obj.baseobject.mesh.selectedfaces.count)
-- ss = stringstream ""
-- format "Polys: % (%)" sp tp to:ss
-- return ss as string
-- )catch()
-- )
function isValidObject obj =
(
validclasses = #(Editable_Mesh, Editable_Poly)
for o in validclasses do
(
if classOf obj == o do return true
)
return false
)
function isMesh obj =
(
meshclasses = #(Editable_Mesh)
for o in meshclasses do
(
if classOf obj == o do return true
)
return false
)
function gridSize =
(
try(
if (activeGrid == undefined) then gs = gridPrefs.spacing
else gs = activeGrid.grid
case (units.SystemType) of
(
#Inches: (un = "in"; gs = 0.393701*gs)
#Feet: (un = "ft"; gs = 0.0328084*gs)
#Miles: (un = "mi"; gs = 6.21371e-006*gs)
#Millimeters: (un = "mm"; gs = 10*gs)
#Centimeters: (un = "cm"; gs = 1*gs)
#Meters: (un = "m"; gs = 0.01*gs)
#Kilometers: (un = "km"; gs = 1e-005*gs)
)
ss = stringstream ""
format "Grid: % %" gs un to:ss
return ss as string
)catch()
)
function drawInfo =
(
noneString = none() as string
globalString = getSceneFacesAsString() as string
vertsString = (getNumVertsAsString $) as string
edgesString = (getNumEdgesAsString $) as string
trisString = (getNumFacesAsString $) as string
-- polysString = (getNumPolysAsString $) as string
gridString = gridSize() as string
noneExtent = gw.getTextExtent noneString
globalExtent = gw.getTextExtent globalString
vertsExtent = gw.getTextExtent vertsString
edgesExtent = gw.getTextExtent edgesString
trisExtent = gw.getTextExtent trisString
-- polysExtent = gw.getTextExtent polysString
gridExtent = gw.getTextExtent gridString
nonePosX = (gw.getWinSizeX() - noneExtent.x - 10)
nonePosY = (gw.getWinSizeY() - noneExtent.y - 40)
globalPosX = (gw.getWinSizeX() - globalExtent.x - 10)
globalPosY = (gw.getWinSizeY() - globalExtent.y - 40)
vertsPosX = (gw.getWinSizeX() - vertsExtent.x - 10)
vertsPosY = (gw.getWinSizeY() - vertsExtent.y - 40)
edgesPosX = (gw.getWinSizeX() - edgesExtent.x - 10)
edgesPosY = (gw.getWinSizeY() - edgesExtent.y - 40)
trisPosX = (gw.getWinSizeX() - trisExtent.x - 10)
trisPosY = (gw.getWinSizeY() - trisExtent.y - 40)
-- polysPosX = (gw.getWinSizeX() - polysExtent.x - 10)
-- polysPosY = (gw.getWinSizeY() - polysExtent.y - 40)
gridPosX = (gw.getWinSizeX() - gridExtent.x - 10)
gridPosY = (gw.getWinSizeY() - gridExtent.y - 40)
none_line_pos = [nonePosX,nonePosY,0]
global_line_pos = [globalPosX,globalPosY,0]
verts_line_pos = [vertsPosX,vertsPosY,0]
edges_line_pos = [edgesPosX,edgesPosY,0]
tris_line_pos = [trisPosX,trisPosY,0]
-- polys_line_pos = [polysPosX,polysPosY,0]
grid_line_pos = [gridPosX,gridPosY,0]
line_height = [0, 15, 0]
if subobjectLevel != undefined then
(
if (subObjectLevel > 0) and (isValidObject (modPanel.getCurrentObject())) then
(
case subobjectlevel of
(
1:
(
gw.wText verts_line_pos (getNumVertsAsString $) color:[255,199,71]
global_line_pos += line_height
gw.wText global_line_pos (getSceneFacesAsString()) color:[165,165,165]
grid_line_pos += (line_height)*3
gw.wText grid_line_pos (gridSize()) color:[165,165,165]
)
2:
(
gw.wText edges_line_pos (getNumEdgesAsString $) color:[255,199,71]
global_line_pos += line_height
gw.wText global_line_pos (getSceneFacesAsString()) color:[165,165,165]
grid_line_pos += (line_height)*3
gw.wText grid_line_pos (gridSize()) color:[165,165,165]
)
3:
(
if isMesh (modPanel.getCurrentObject()) then
(
(gw.wText tris_line_pos (getNumFacesAsString $) color:[255,199,71])
global_line_pos += line_height
)
else
(
gw.wText edges_line_pos (getNumEdgesAsString $) color:[255,199,71]
global_line_pos += line_height
)
gw.wText global_line_pos (getSceneFacesAsString()) color:[165,165,165]
grid_line_pos += (line_height)*3
gw.wText grid_line_pos (gridSize()) color:[165,165,165]
)
4:
(
gw.wText tris_line_pos (getNumFacesAsString $) color:[255,199,71]
global_line_pos += line_height
gw.wText global_line_pos (getSceneFacesAsString()) color:[165,165,165]
grid_line_pos += (line_height)*3
gw.wText grid_line_pos (gridSize()) color:[165,165,165]
)
5:
(
gw.wText tris_line_pos (getNumFacesAsString $) color:[255,199,71]
global_line_pos += line_height
gw.wText global_line_pos (getSceneFacesAsString()) color:[165,165,165]
grid_line_pos += (line_height)*3
gw.wText grid_line_pos (gridSize()) color:[165,165,165]
)
)
gw.enlargeUpdateRect #whole
gw.updateScreen()
)
else
(
gw.wText none_line_pos (none()) color:[255,199,71]
global_line_pos += line_height
gw.wText global_line_pos (getSceneFacesAsString()) color:[165,165,165]
grid_line_pos += (line_height)*3
gw.wText grid_line_pos (gridSize()) color:[165,165,165]
gw.enlargeUpdateRect #whole
gw.updateScreen()
)
)
else
(
gw.wText none_line_pos (none()) color:[255,199,71]
global_line_pos += line_height
gw.wText global_line_pos (getSceneFacesAsString()) color:[165,165,165]
grid_line_pos += (line_height)*3
gw.wText grid_line_pos (gridSize()) color:[165,165,165]
gw.enlargeUpdateRect #whole
gw.updateScreen()
)
)
function startDrawInfo =
(
unregisterRedrawViewsCallback drawInfo
registerRedrawViewsCallback drawinfo
drawInfo()
forceCompleteRedraw()
)
startDrawInfo()
)
It looks correct, but the problem is that the viewport redraw become lagging, like the text flickering when I do anything on the viewport. My maxscript knowledge is very limited so I have no idea how to improve the performance here, could anyone take a look and give some suggestion on how to improve this?
PS; I'm using Max 2009 at home, but in office using Max 2014 I don't think I remember any flickering issue, need to double confirm on this next Monday.
Replies
About the code:
this creates copy(in the memory) of the object each time when it is executed. In the same loop it is used twice. The same is valid for
every xxxx.mesh.yyyy. And it is executed on each viewport redraw several times. For scene with several low poly objects this may not affet the performance, but....
@Swordslayer - wow! you really trim down the code! thanks!..but I notice that if I use; ..the display will gone when I do anything with the viewport but if I replace with "gw.enlargeUpdateRect #whole" it'll stay there. Any reason for this such behavior?
But it clearly that your code make run run much more smoothly despite the constant flickering. Tested with a mesh around 1mil tris, the viewport didnt suffer with a slowdown as much as the previous code I wrote. It seems like related to miauu's point regarding the code creates a copy on a memory. Thanks so much!
Sorry about that, looks like that doesn't have any effect in nitrous.
If you don't mind the polygon count you don't need to loop through all objects. You can just access the mesh totals from fileProperties.
If you do want triangle counts keep in mind you don't need to access the .mesh property for vertex and edge totals.
A while back when I created a viewport callback script I skipped calculations while the mouse was moving and a mouse button was pressed. This allowed the user to pan / orbit the view at full speed.
@monster - yeah, you're right. I do want to display tris instead of polys so I added back .mesh for tris count. That's interesting idea to read only on mouse move, I tried to use mouse.mode since on the help file said; 0-idle, 1-point, 2-move, but no matter what I check (and move my mouse like crazy) while execute the script from the listener, it still return 0 (which means idle?), so how do you check that?
Vertex/edge counters return 0 for me only for the 'selected' subobjects when Show End Result is toggled on (which is to be expected since you are getting the top result of the stack).
By the way, since you are using .mesh once again, save the .mesh to a variable, get your stats and delete it afterwards.
As for the mouse moving or not, you can save mouse position and check if it changed since the last time.
About the count being 0, I guess I can live with that, since the default Max's own statistic (default hotkey:7) also showed 0 when there is a modifier ontop.
Eh? saving the .mesh as a variable? you mean like assigning; ..and use the numFace instead? wasn't too sure tough, better to confirm with you first before putting some junk code into my script
About the mouse position, I seems like can't get anything working, what miauu suggest to use mouse.buttonStates always return #{} or once I got #{3}. I found a really primitive way to check whether mouse is moving of not by declaring 3 variables; ..so basically mouseInitPos will be a static number (initial position) and mouseNewPos will be the dynamic number (new moved position) and compare between the two, when mouse idle it'll return true, when moving will return false. So the problem is....where should I sneak it in?...man! scripting is so addicting!haha
mesh to a variable like this and you call _mesh instead of $.mesh you usually do this when you want to call the same thing more than once...
About assigning the $.mesh into a _mesh variable, is there any benefit by doing so? And I notice if using .mesh for an edge, it will return "wrong" value since 1 quad have 5 edges in mesh (instead of 4 in poly).
and now compare it to
The other things like checking mouse position.. well, I've taken the liberty to bend the code to fit that purpose once again, I'm not that good with explaining:
Basically, save everything to a struct, redraw with each viewport redraw, update only when mouse positon changes.
Another thing is, isit save to add forceCompleteRedraw() inside the drawInfo function? since currently the text will overlap each other before viewport redraw?
I'm sorry man...I just....I just a little bit OCD when it comes about UI....
About max handling heavy object will slow down viewport, I guess it's just max being...max...hmm...
Couldn't do all this without your help Swordslayer, thanks so much
Watch this video to see which is better to be used.
I google around for a solution before and found something like this; ..not sure is it possible to use this on the code or not, if possible we need to implement it when "Idle State" is displayed, hold the redraw (which basically whenever any one of the mouse button pressed, hold the redraw). Just throwing some idea
Hmmm...now it seems like too less redraw, when selecting subobject even after I mouse up, it still didn't redraw the new number until I pan/rotate/zoom the viewport, tested on Max 2014. How is it on your end?
EDIT: Play with it a little bit more, by adding a completeRedraw() below meshInfo.redraw(), makes it better
Was thinking of using it something like this; ..so intended to use it as glRevelTemp.mouseBtn() and return either #left/ #mid/ #right...but the "???" obviously stop the code from being any useful...