Home Technical Talk
The BRAWL² Tournament Challenge has been announced!

It starts May 12, and ends Sept 12. Let's see what you got!

https://polycount.com/discussion/237047/the-brawl²-tournament

[MAXScript] View Stats

interpolator
Offline / Send Message
Revel interpolator
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:
  1. ---------------------------------------------------------------------
  2. -- Based on Mesh Info by; Roger Hyde
  3. -- http://www.scriptspot.com/3ds-max/scripts/meshinfo
  4. ---------------------------------------------------------------------
  5.  
  6. (
  7. function none =
  8. (
  9. if (selection.count == 1) then st = $.name
  10. else if (selection.count >= 2) then st = "Multiple Selected"
  11. else st = "None Selected"
  12. ss = stringstream ""
  13. format "%" st to:ss
  14. return ss as string
  15. )
  16. function getSceneFacesAsString =
  17. (
  18. tf = 0
  19. sf = 0
  20. for o in $geometry do
  21. (
  22. tf += o.mesh.numFaces
  23. if o.isSelected do sf += o.mesh.numFaces
  24. )
  25. tf = (dotNetClass "System.String").Format "{0:n0}" tf
  26. sf = (dotNetClass "System.String").Format "{0:n0}" sf
  27. ss = stringstream ""
  28. format "GL: % (%)" tf sf to:ss
  29. return ss as string
  30. )
  31. function getNumVertsAsString obj =
  32. (
  33. try(
  34. tv = (dotNetClass "System.String").Format "{0:n0}" (obj.baseobject.mesh.numVerts)
  35. sv = (dotNetClass "System.String").Format "{0:n0}" (obj.baseobject.mesh.selectedverts.count)
  36. ss = stringstream ""
  37. format "Verts: % (%)" sv tv to:ss
  38. return ss as string
  39. )catch()
  40. )
  41. function getNumEdgesAsString obj =
  42. (
  43. try(
  44. te = (dotNetClass "System.String").Format "{0:n0}" (obj.baseobject.mesh.edges.count)
  45. se = (dotNetClass "System.String").Format "{0:n0}" (obj.baseobject.mesh.selectededges.count)
  46. ss = stringstream ""
  47. format "Edges: % (%)" se te to:ss
  48. return ss as string
  49. )catch()
  50. )
  51. function getNumFacesAsString obj =
  52. (
  53. try(
  54. tf = (dotNetClass "System.String").Format "{0:n0}" (obj.baseobject.mesh.numFaces)
  55. sf = (dotNetClass "System.String").Format "{0:n0}" (obj.baseobject.mesh.selectedFaces.count)
  56. ss = stringstream ""
  57. format "Tris: % (%)" sf tf to:ss
  58. return ss as string
  59. )catch()
  60. )
  61. -- function getNumPolysAsString obj =
  62. -- (
  63. -- try(
  64. -- tp = (dotNetClass "System.String").Format "{0:n0}" (obj.baseobject.mesh.numFaces)
  65. -- sp = (dotNetClass "System.String").Format "{0:n0}" (obj.baseobject.mesh.selectedfaces.count)
  66. -- ss = stringstream ""
  67. -- format "Polys: % (%)" sp tp to:ss
  68. -- return ss as string
  69. -- )catch()
  70. -- )
  71. function isValidObject obj =
  72. (
  73. validclasses = #(Editable_Mesh, Editable_Poly)
  74. for o in validclasses do
  75. (
  76. if classOf obj == o do return true
  77. )
  78. return false
  79. )
  80. function isMesh obj =
  81. (
  82. meshclasses = #(Editable_Mesh)
  83. for o in meshclasses do
  84. (
  85. if classOf obj == o do return true
  86. )
  87. return false
  88. )
  89. function gridSize =
  90. (
  91. try(
  92. if (activeGrid == undefined) then gs = gridPrefs.spacing
  93. else gs = activeGrid.grid
  94. case (units.SystemType) of
  95. (
  96. #Inches: (un = "in"; gs = 0.393701*gs)
  97. #Feet: (un = "ft"; gs = 0.0328084*gs)
  98. #Miles: (un = "mi"; gs = 6.21371e-006*gs)
  99. #Millimeters: (un = "mm"; gs = 10*gs)
  100. #Centimeters: (un = "cm"; gs = 1*gs)
  101. #Meters: (un = "m"; gs = 0.01*gs)
  102. #Kilometers: (un = "km"; gs = 1e-005*gs)
  103. )
  104. ss = stringstream ""
  105. format "Grid: % %" gs un to:ss
  106. return ss as string
  107. )catch()
  108. )
  109. function drawInfo =
  110. (
  111. noneString = none() as string
  112. globalString = getSceneFacesAsString() as string
  113. vertsString = (getNumVertsAsString $) as string
  114. edgesString = (getNumEdgesAsString $) as string
  115. trisString = (getNumFacesAsString $) as string
  116. -- polysString = (getNumPolysAsString $) as string
  117. gridString = gridSize() as string
  118. noneExtent = gw.getTextExtent noneString
  119. globalExtent = gw.getTextExtent globalString
  120. vertsExtent = gw.getTextExtent vertsString
  121. edgesExtent = gw.getTextExtent edgesString
  122. trisExtent = gw.getTextExtent trisString
  123. -- polysExtent = gw.getTextExtent polysString
  124. gridExtent = gw.getTextExtent gridString
  125. nonePosX = (gw.getWinSizeX() - noneExtent.x - 10)
  126. nonePosY = (gw.getWinSizeY() - noneExtent.y - 40)
  127. globalPosX = (gw.getWinSizeX() - globalExtent.x - 10)
  128. globalPosY = (gw.getWinSizeY() - globalExtent.y - 40)
  129. vertsPosX = (gw.getWinSizeX() - vertsExtent.x - 10)
  130. vertsPosY = (gw.getWinSizeY() - vertsExtent.y - 40)
  131. edgesPosX = (gw.getWinSizeX() - edgesExtent.x - 10)
  132. edgesPosY = (gw.getWinSizeY() - edgesExtent.y - 40)
  133. trisPosX = (gw.getWinSizeX() - trisExtent.x - 10)
  134. trisPosY = (gw.getWinSizeY() - trisExtent.y - 40)
  135. -- polysPosX = (gw.getWinSizeX() - polysExtent.x - 10)
  136. -- polysPosY = (gw.getWinSizeY() - polysExtent.y - 40)
  137. gridPosX = (gw.getWinSizeX() - gridExtent.x - 10)
  138. gridPosY = (gw.getWinSizeY() - gridExtent.y - 40)
  139. none_line_pos = [nonePosX,nonePosY,0]
  140. global_line_pos = [globalPosX,globalPosY,0]
  141. verts_line_pos = [vertsPosX,vertsPosY,0]
  142. edges_line_pos = [edgesPosX,edgesPosY,0]
  143. tris_line_pos = [trisPosX,trisPosY,0]
  144. -- polys_line_pos = [polysPosX,polysPosY,0]
  145. grid_line_pos = [gridPosX,gridPosY,0]
  146. line_height = [0, 15, 0]
  147. if subobjectLevel != undefined then
  148. (
  149. if (subObjectLevel > 0) and (isValidObject (modPanel.getCurrentObject())) then
  150. (
  151. case subobjectlevel of
  152. (
  153. 1:
  154. (
  155. gw.wText verts_line_pos (getNumVertsAsString $) color:[255,199,71]
  156. global_line_pos += line_height
  157. gw.wText global_line_pos (getSceneFacesAsString()) color:[165,165,165]
  158. grid_line_pos += (line_height)*3
  159. gw.wText grid_line_pos (gridSize()) color:[165,165,165]
  160. )
  161. 2:
  162. (
  163. gw.wText edges_line_pos (getNumEdgesAsString $) color:[255,199,71]
  164. global_line_pos += line_height
  165. gw.wText global_line_pos (getSceneFacesAsString()) color:[165,165,165]
  166. grid_line_pos += (line_height)*3
  167. gw.wText grid_line_pos (gridSize()) color:[165,165,165]
  168. )
  169. 3:
  170. (
  171. if isMesh (modPanel.getCurrentObject()) then
  172. (
  173. (gw.wText tris_line_pos (getNumFacesAsString $) color:[255,199,71])
  174. global_line_pos += line_height
  175. )
  176. else
  177. (
  178. gw.wText edges_line_pos (getNumEdgesAsString $) color:[255,199,71]
  179. global_line_pos += line_height
  180. )
  181. gw.wText global_line_pos (getSceneFacesAsString()) color:[165,165,165]
  182. grid_line_pos += (line_height)*3
  183. gw.wText grid_line_pos (gridSize()) color:[165,165,165]
  184. )
  185. 4:
  186. (
  187. gw.wText tris_line_pos (getNumFacesAsString $) color:[255,199,71]
  188. global_line_pos += line_height
  189. gw.wText global_line_pos (getSceneFacesAsString()) color:[165,165,165]
  190. grid_line_pos += (line_height)*3
  191. gw.wText grid_line_pos (gridSize()) color:[165,165,165]
  192. )
  193. 5:
  194. (
  195. gw.wText tris_line_pos (getNumFacesAsString $) color:[255,199,71]
  196. global_line_pos += line_height
  197. gw.wText global_line_pos (getSceneFacesAsString()) color:[165,165,165]
  198. grid_line_pos += (line_height)*3
  199. gw.wText grid_line_pos (gridSize()) color:[165,165,165]
  200. )
  201. )
  202. gw.enlargeUpdateRect #whole
  203. gw.updateScreen()
  204. )
  205. else
  206. (
  207. gw.wText none_line_pos (none()) color:[255,199,71]
  208. global_line_pos += line_height
  209. gw.wText global_line_pos (getSceneFacesAsString()) color:[165,165,165]
  210. grid_line_pos += (line_height)*3
  211. gw.wText grid_line_pos (gridSize()) color:[165,165,165]
  212. gw.enlargeUpdateRect #whole
  213. gw.updateScreen()
  214. )
  215. )
  216. else
  217. (
  218. gw.wText none_line_pos (none()) color:[255,199,71]
  219. global_line_pos += line_height
  220. gw.wText global_line_pos (getSceneFacesAsString()) color:[165,165,165]
  221. grid_line_pos += (line_height)*3
  222. gw.wText grid_line_pos (gridSize()) color:[165,165,165]
  223. gw.enlargeUpdateRect #whole
  224. gw.updateScreen()
  225. )
  226. )
  227. function startDrawInfo =
  228. (
  229. unregisterRedrawViewsCallback drawInfo
  230. registerRedrawViewsCallback drawinfo
  231. drawInfo()
  232. forceCompleteRedraw()
  233. )
  234. startDrawInfo()
  235. )
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

  • miauu
    Offline / Send Message
    miauu polycounter lvl 15
    In 3dsMax that uses Nitrous viewport there is no flickering. In 3dsMax 2009 the flickering is constant. The problem is in 3dsMax. You can't overcome it.
    About the code:

    this
    1. o.mesh.numfaces
    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
    Offline / Send Message
    Swordslayer interpolator
    You could simplify the code quite a bit, skip the .mesh part and only check deformable objects (you are already skipping shapes, you can skip primitives with no modifier apllied, too) and avoid creating so many stringstreams and doing things you can do once multiple times. Also the unit conversion as you do it would work only in a specific case, use the built-in one, it makes more sense to use the display units anyway:
    1. (
    2. unregisterRedrawViewsCallback ::drawInfo
    3.  
    4. local stringFormat = (dotNetClass "System.String").Format
    5. local lineHeight = (getTextExtent #I).y + 2
    6. local yellowish = color 255 199 71
    7. local grayish = color 165 165 165
    8.  
    9. function none =
    10. case selection.count of
    11. (
    12. 0 : "None Selected"
    13. 1 : $.name
    14. default : "Multiple Selected"
    15. )
    16.  
    17. function getSceneFacesAsString =
    18. (
    19. local totalFaces = 0
    20. local selectedFaces = 0
    21. for obj in geometry where isDeformable obj do
    22. (
    23. totalFaces += obj.numFaces
    24. if obj.isSelected do selectedFaces += obj.numFaces
    25. )
    26. stringFormat "GL: {0:n0} ({1:n0})" totalFaces selectedFaces
    27. )
    28.  
    29. function getNumVertsAsString obj =
    30. stringFormat "Verts: {0:n0} ({1:n0})" (numPoints obj) obj.selectedVerts.count
    31.  
    32. function getNumEdgesAsString obj =
    33. stringFormat "Edges: {0:n0} ({1:n0})" obj.edges.count obj.selectedEdges.count
    34.  
    35. function getNumFacesAsString obj =
    36. stringFormat "Faces: {0:n0} ({1:n0})" obj.numFaces obj.selectedFaces.count
    37.  
    38. function isValidObject obj =
    39. isKindOf obj Editable_Poly or isKindOf obj Editable_Mesh
    40.  
    41. function isMesh obj =
    42. isKindOf obj Editable_Mesh
    43.  
    44. function gridSize =
    45. "Grid: " + units.formatValue (if activeGrid == undefined then gridPrefs.spacing else activeGrid.grid)
    46.  
    47. function getTextLocation textExt winSizeX winSizeY lineMult =
    48. [winSizeX - textExt - 10, winSizeY - 40 + lineHeight * lineMult, 0]
    49.  
    50. function getTextBox winSizeX winSizeY textExt =
    51. Box2 [winSizeX - textExt - 10, winSizeY - 40 + lineHeight * 2] [winSizeX, winSizeY]
    52.  
    53. function redrawRectangle subObjsStr globalCountStr gridSizeStr =
    54. (
    55. local winSizeX = gw.getWinSizeX()
    56. local winSizeY = gw.getWinSizeY()
    57. local subObjsStrExt = (getTextExtent subObjsStr).x
    58. local globalCountStrExt = (getTextExtent globalCountStr).x
    59. local gridSizeStrExt = (getTextExtent gridSizeStr).x
    60.  
    61. gw.wText (getTextLocation subObjsStrExt winSizeX winSizeY -1) subObjsStr color:yellowish
    62. gw.wText (getTextLocation globalCountStrExt winSizeX winSizeY 0) globalCountStr color:grayish
    63. gw.wText (getTextLocation gridSizeStrExt winSizeX winSizeY 2) gridSizeStr color:grayish
    64.  
    65. gw.enlargeUpdateRect (getTextBox winSizeX winSizeY (amax subObjsStrExt globalCountStrExt gridSizeStrExt))
    66. gw.updateScreen()
    67. )
    68.  
    69. function drawInfo =
    70. (
    71. local obj = modPanel.getCurrentObject()
    72.  
    73. if subObjectLevel != undefined and subObjectLevel > 0 and isValidObject obj then
    74. (
    75. case subObjectLevel of
    76. (
    77. 1: redrawRectangle (getNumVertsAsString $) (getSceneFacesAsString()) (gridSize())
    78. 2: redrawRectangle (getNumEdgesAsString $) (getSceneFacesAsString()) (gridSize())
    79. 3:
    80. (
    81. if isMesh obj then redrawRectangle (getNumFacesAsString $) (getSceneFacesAsString()) (gridSize())
    82. else redrawRectangle (getNumEdgesAsString $) (getSceneFacesAsString()) (gridSize())
    83. )
    84. 4: redrawRectangle (getNumFacesAsString $) (getSceneFacesAsString()) (gridSize())
    85. 5: redrawRectangle (getNumFacesAsString $) (getSceneFacesAsString()) (gridSize())
    86. )
    87. )
    88. else redrawRectangle (none()) (getSceneFacesAsString()) (gridSize())
    89. )
    90.  
    91. function startDrawInfo =
    92. (
    93. registerRedrawViewsCallback ::drawInfo
    94. setNeedsRedraw()
    95. )
    96.  
    97. startDrawInfo()
    98. )
  • Revel
    Offline / Send Message
    Revel interpolator
    @miauu - thanks for the clarification man..hmm, that's bad too hear since at home I'm using max 2009 currently..ah well....

    @Swordslayer - wow! you really trim down the code! thanks!..but I notice that if I use;
    1. gw.enlargeUpdateRect (getTextBox winSizeX winSizeY (amax subObjsStrExt globalCountStrExt gridSizeStrExt))
    ..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! :)
  • Swordslayer
    Offline / Send Message
    Swordslayer interpolator
    Oops, wrong sign, the getTextBox body should have instead been:
    1. Box2 [winSizeX - textExt - 10, winSizeY - 40 - lineHeight * 2] [winSizeX, winSizeY]

    Sorry about that, looks like that doesn't have any effect in nitrous.
  • monster
    Offline / Send Message
    monster polycounter
    Revel, if you don't use .mesh you'll get the polygon count and not the triangle count.

    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.
  • Revel
    Offline / Send Message
    Revel interpolator
    @Swordslayer - still not work man, it even gives an error and crashed the script. What does it do actually? using #whole seems like fine to me. Also I notice that when I have modifier (example; turbosmooth) ontop of my Editable Poly object, the verts and edges count always return 0 eventhough I'm on the base object..hmmm......

    @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?
  • Swordslayer
    Offline / Send Message
    Swordslayer interpolator
    It limits viewport redraw only to the part where the text is (it doesn't work in nitrous, though), which would help with th flickering. I don't have 2009 to test with, works okay with max 9 though.

    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.
  • miauu
    Offline / Send Message
    miauu polycounter lvl 15
    For mouse moving - use mouse.buttonstates. It will tell you when the left mouse button is pressed or not.
  • Revel
    Offline / Send Message
    Revel interpolator
    Whoops sorry Swordslayer, my mistake! I mistakenly thought you asked me to change the line become:
    1. gw.enlargeUpdateRect (Box2 [winSizeX - textExt - 10, winSizeY - 40 - lineHeight * 2] [winSizeX, winSizeY])
    ..instead of assigning the value to the getTextBox haha! now everything works fine :)
    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;
    1. tempFaces = $.mesh.faces.count
    2. numFaces = tempFaces as integer
    3. tempFaces = undefined
    ..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;
    1. mouseInitPos = mouse.screenPos
    2. mousePos = a as point2
    3. mouseInitPos = undefines
    4. mouseNewPos = mouse.screenPos
    5. mouseInitPos == mouseNewPos
    ..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
  • RappyBMX
    Offline / Send Message
    RappyBMX polycounter lvl 17
    1. function drawInfo = (
    to
    1. function drawInfo = if mouse.buttonstates.isEmpty do (
    also you could
    1. function drawInfo = if not isAnimPlaying() and mouse.buttonstates.isEmpty do (

    mesh to a variable like this
    1. _mesh = $.mesh
    and you call _mesh instead of $.mesh
    1. _mesh.verts.count
    2. _mesh.edges.count
    3. _mesh.faces.count
    you usually do this when you want to call the same thing more than once...
  • Revel
    Offline / Send Message
    Revel interpolator
    @RappyBMX - hmmm...theoretically it should work, but since mouse.buttonStates always gives empty array #{} no matter in what situation, the script will always run...until I right-clicked, the array will always return #{3} which makes the View Stats completely ignored but the code (since now it's not empty anymore).

    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).
  • Swordslayer
    Offline / Send Message
    Swordslayer interpolator
    Not just saving it to a variable, deleting it afterwards, too. Launch task manager to see the RAM usage of 3dsmax process and see it rising with
    1. (
    2. local t = Teapot segments:64
    3. for i = 1 to 1000 do
    4. t.mesh.verts.count
    5. )

    and now compare it to
    1. (
    2. local t = Teapot segments:64
    3. local m -- one variable to hold them all, outside the loop/functions
    4. for i = 1 to 1000 do
    5. (
    6. m = t.mesh
    7. m.verts.count
    8. delete m
    9. )
    10. )

    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:
    1. (
    2. unregisterRedrawViewsCallback ::drawInfo
    3.  
    4. local stringFormat = (dotNetClass "System.String").Format
    5. local lineHeight = (getTextExtent #I).y + 2
    6. local meshInfo
    7. local meshObj
    8. local prevPos
    9.  
    10. struct meshInfoDef
    11. (
    12. yellowish = color 255 199 71,
    13. grayish = color 165 165 165,
    14.  
    15. winSizeX, winSizeY, textBox,
    16.  
    17. lineSub = dataPair(),
    18. lineTotal = dataPair(),
    19. lineGrid = dataPair(),
    20.  
    21. function getTextLocation textExt winSizeX winSizeY lineMult =
    22. [winSizeX - textExt - 10, winSizeY - 40 + lineHeight * lineMult, 0],
    23.  
    24. function getTextBox winSizeX winSizeY textExt =
    25. Box2 [winSizeX - textExt - 10, winSizeY - 40 - lineHeight * 2] [winSizeX, winSizeY],
    26.  
    27. function update subObjsStr globalCountStr gridSizeStr =
    28. (
    29. local subObjsStrExt = (getTextExtent subObjsStr).x
    30. local globalCountStrExt = (getTextExtent globalCountStr).x
    31. local gridSizeStrExt = (getTextExtent gridSizeStr).x
    32. local winSizeX = gw.getWinSizeX()
    33. local winSizeY = gw.getWinSizeY()
    34.  
    35. textBox = getTextBox winSizeX winSizeY (amax subObjsStrExt globalCountStrExt gridSizeStrExt)
    36.  
    37. lineSub.v1 = getTextLocation subObjsStrExt winSizeX winSizeY -1
    38. lineTotal.v1 = getTextLocation globalCountStrExt winSizeX winSizeY 0
    39. lineGrid.v1 = getTextLocation gridSizeStrExt winSizeX winSizeY 2
    40. lineSub.v2 = subObjsStr
    41. lineTotal.v2 = globalCountStr
    42. lineGrid.v2 = gridSizeStr
    43. ),
    44.  
    45. function redraw =
    46. (
    47. gw.wText lineSub.v1 lineSub.v2 color:yellowish
    48. gw.wText lineTotal.v1 lineTotal.v2 color:grayish
    49. gw.wText lineGrid.v1 lineGrid.v2 color:grayish
    50.  
    51. gw.enlargeUpdateRect textBox
    52. gw.updateScreen()
    53. )
    54. )
    55.  
    56. function none =
    57. case selection.count of
    58. (
    59. 0 : "None Selected"
    60. 1 : $.name
    61. default : "Multiple Selected"
    62. )
    63.  
    64. function getSceneTrisAsString =
    65. (
    66. local totalFaces = 0
    67. local selectedFaces = 0
    68.  
    69. for obj in geometry where not isKindOf obj TargetObject do
    70. (
    71. meshObj = obj.mesh
    72. totalFaces += meshObj.numFaces
    73. if obj.isSelected do selectedFaces += meshObj.numFaces
    74. delete meshObj
    75. )
    76.  
    77. stringFormat "GL: {0:n0} ({1:n0})" totalFaces selectedFaces
    78. )
    79.  
    80. function getNumVertsAsString obj =
    81. stringFormat "Verts: {0:n0} ({1:n0})" (numPoints obj) obj.selectedVerts.count
    82.  
    83. function getNumEdgesAsString obj =
    84. stringFormat "Edges: {0:n0} ({1:n0})" obj.edges.count obj.selectedEdges.count
    85.  
    86. function getNumTrisAsString obj =
    87. (
    88. meshObj = obj.mesh
    89. local numTrisStr = stringFormat "Tris: {0:n0} ({1:n0})" meshObj.numFaces meshObj.selectedFaces.count
    90. delete meshObj
    91. numTrisStr
    92. )
    93.  
    94. function isValidObject obj =
    95. isKindOf obj Editable_Poly or isKindOf obj Editable_Mesh
    96.  
    97. function isMesh obj =
    98. isKindOf obj Editable_Mesh
    99.  
    100. function gridSize =
    101. "Grid: " + units.formatValue (if activeGrid == undefined then gridPrefs.spacing else activeGrid.grid)
    102.  
    103. function drawInfo =
    104. (
    105. local pos = mouse.screenPos
    106.  
    107. if pos != prevPos do
    108. (
    109. local obj = modPanel.getCurrentObject()
    110.  
    111. if subObjectLevel != undefined and subObjectLevel > 0 and isValidObject obj then
    112. (
    113. case subObjectLevel of
    114. (
    115. 1: meshInfo.update (getNumVertsAsString $) (getSceneTrisAsString()) (gridSize())
    116. 2: meshInfo.update (getNumEdgesAsString $) (getSceneTrisAsString()) (gridSize())
    117. 3:
    118. (
    119. if isMesh obj then meshInfo.update (getNumTrisAsString $) (getSceneTrisAsString()) (gridSize())
    120. else meshInfo.update (getNumEdgesAsString $) (getSceneTrisAsString()) (gridSize())
    121. )
    122. 4: meshInfo.update (getNumTrisAsString $) (getSceneTrisAsString()) (gridSize())
    123. 5: meshInfo.update (getNumTrisAsString $) (getSceneTrisAsString()) (gridSize())
    124. )
    125. )
    126. else meshInfo.update (none()) (getSceneTrisAsString()) (gridSize())
    127.  
    128. prevPos = pos
    129. )
    130. meshInfo.redraw()
    131. )
    132.  
    133. function startDrawInfo =
    134. (
    135. meshInfo = meshInfoDef()
    136. registerRedrawViewsCallback ::drawInfo
    137. setNeedsRedraw()
    138. )
    139.  
    140. startDrawInfo()
    141. )

    Basically, save everything to a struct, redraw with each viewport redraw, update only when mouse positon changes.
  • Revel
    Offline / Send Message
    Revel interpolator
    That sounds great, but Max throw me en error saying unable to convert:0 to type:string by highlighting the local subObjsStrExt = (getTextExtent subObjsStr).x :(
  • Swordslayer
    Offline / Send Message
    Swordslayer interpolator
    Should be already fixed (I've edited the cody shortly after posting).
  • Revel
    Offline / Send Message
    Revel interpolator
    Yeaps!now it's working fine! :)
    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....
  • Swordslayer
    Offline / Send Message
    Swordslayer interpolator
    The trouble is I don't have max 2009 to test it on, nitrous handles things differently so things like this one are not apparent. Let's see, IIRC you can use gw.clearScreen for that (should be a better idea than redrawing views and trigger redrawViewsCallback again) though that one works kinda weird in nitrous. If you put gw.clearScreen textBox useBkg:true before gw.enlargeUpdateRect textBox does it work/fail/do funny things? Maybe also gw.resetUpdateRect() after gw.updateScreen() (doesn't do anything in nitrous, might have some impact in your case).
  • Revel
    Offline / Send Message
    Revel interpolator
    No worries man, I tested it on max 2014 as well but give a similar behavior (overlapped text) but clearly more faster (and slightly) faster viewport response operation over max 2009. I did try put the forceCompleteRedraw() it fix the problem with redraw text. Will try the code you gave just now and see how it looks ;)

    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 :)
  • miauu
    Offline / Send Message
    miauu polycounter lvl 15
    Revel, why do you think that the mouse.buttonstates not works?
    Watch this video to see which is better to be used.
  • Revel
    Offline / Send Message
    Revel interpolator
    Yeah miauu, your video explain it well. What I did before was typing the mouse.buttonStates on the listener and execute it while holding my left/mid/right button, all return #{ } or #{3} when holding the right click. Your solution does more simplified the vp redraw. But I'm just curious when pan/rotate/zoom, isit possible to stop the text redraw as well?

    I google around for a solution before and found something like this;
    1. rollout click_test "Click Test"
    2. (
    3. timer tick_tock interval:100 active:true
    4. label lbl_button "Idle State"
    5. local dnc_control
    6. local mouseButtonStates
    7. local leftBtn
    8. local midBtn
    9. local rightBtn
    10. local idleState
    11. on tick_tock tick do
    12. (
    13. mouseButtonStates = dnc_control.MouseButtons.value__
    14. theButtonStr = ""
    15. if (dotnet.CompareEnums mouseButtonStates leftBtn) do (idleState = true)
    16. if (dotnet.CompareEnums mouseButtonStates midBtn) do (idleState = true)
    17. if (dotnet.CompareEnums mouseButtonStates rightBtn) do (idleState = true)
    18. if idleState == true then
    19. (
    20. lbl_button.text = "Idle State"
    21. idleState = false
    22. )
    23. else
    24. (
    25. lbl_button.text = ""
    26. )
    27. )
    28. on click_test open do
    29. (
    30. dnc_control = dotNetClass "Control"
    31. mouseButtons = dnc_control.MouseButtons
    32. leftBtn = mouseButtons.Left.value__
    33. midBtn = mouseButtons.Middle.value__
    34. rightBtn = mouseButtons.Right.value__
    35. )
    36. )
    37. createDialog click_test
    ..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 :)
  • Swordslayer
    Offline / Send Message
    Swordslayer interpolator
    Hmmm, and what about something like this?
    1. (
    2. ::drawInfoNodeCallback = undefined
    3. unregisterRedrawViewsCallback ::drawInfo
    4.  
    5. local stringFormat = (dotNetClass "System.String").Format
    6. local lineHeight = (getTextExtent #I).y + 2
    7. local meshInfo
    8. local meshObj
    9.  
    10. struct meshInfoDef
    11. (
    12. yellowish = color 255 199 71,
    13. grayish = color 165 165 165,
    14.  
    15. winSizeX, winSizeY, textBox,
    16.  
    17. lineSub = dataPair(),
    18. lineTotal = dataPair(),
    19. lineGrid = dataPair(),
    20.  
    21. function getTextLocation textExt winSizeX winSizeY lineMult =
    22. [winSizeX - textExt - 10, winSizeY - 40 + lineHeight * lineMult, 0],
    23.  
    24. function getTextBox winSizeX winSizeY textExt =
    25. Box2 [winSizeX - textExt - 10, winSizeY - 40 - lineHeight * 2] [winSizeX, winSizeY],
    26.  
    27. function update subObjsStr globalCountStr gridSizeStr =
    28. (
    29. local subObjsStrExt = (getTextExtent subObjsStr).x
    30. local globalCountStrExt = (getTextExtent globalCountStr).x
    31. local gridSizeStrExt = (getTextExtent gridSizeStr).x
    32. local winSizeX = gw.getWinSizeX()
    33. local winSizeY = gw.getWinSizeY()
    34.  
    35. textBox = getTextBox winSizeX winSizeY (amax subObjsStrExt globalCountStrExt gridSizeStrExt)
    36.  
    37. lineSub.v1 = getTextLocation subObjsStrExt winSizeX winSizeY -1
    38. lineTotal.v1 = getTextLocation globalCountStrExt winSizeX winSizeY 0
    39. lineGrid.v1 = getTextLocation gridSizeStrExt winSizeX winSizeY 2
    40. lineSub.v2 = subObjsStr
    41. lineTotal.v2 = globalCountStr
    42. lineGrid.v2 = gridSizeStr
    43. ),
    44.  
    45. function redraw =
    46. (
    47. gw.wText lineSub.v1 lineSub.v2 color:yellowish
    48. gw.wText lineTotal.v1 lineTotal.v2 color:grayish
    49. gw.wText lineGrid.v1 lineGrid.v2 color:grayish
    50.  
    51. gw.enlargeUpdateRect textBox
    52. gw.updateScreen()
    53. )
    54. )
    55.  
    56. function none =
    57. case selection.count of
    58. (
    59. 0 : "None Selected"
    60. 1 : $.name
    61. default : "Multiple Selected"
    62. )
    63.  
    64. function getSceneTrisAsString =
    65. (
    66. local totalFaces = 0
    67. local selectedFaces = 0
    68.  
    69. for obj in geometry where not isKindOf obj TargetObject do
    70. (
    71. meshObj = obj.mesh
    72. totalFaces += meshObj.numFaces
    73. if obj.isSelected do selectedFaces += meshObj.numFaces
    74. delete meshObj
    75. )
    76.  
    77. stringFormat "GL: {0:n0} ({1:n0})" totalFaces selectedFaces
    78. )
    79.  
    80. function getNumVertsAsString obj =
    81. stringFormat "Verts: {0:n0} ({1:n0})" (numPoints obj) obj.selectedVerts.count
    82.  
    83. function getNumEdgesAsString obj =
    84. stringFormat "Edges: {0:n0} ({1:n0})" obj.edges.count obj.selectedEdges.count
    85.  
    86. function getNumTrisAsString obj =
    87. (
    88. meshObj = obj.mesh
    89. local numTrisStr = stringFormat "Tris: {0:n0} ({1:n0})" meshObj.numFaces meshObj.selectedFaces.count
    90. delete meshObj
    91. numTrisStr
    92. )
    93.  
    94. function isValidObject obj =
    95. isKindOf obj Editable_Poly or isKindOf obj Editable_Mesh
    96.  
    97. function isMesh obj =
    98. isKindOf obj Editable_Mesh
    99.  
    100. function gridSize =
    101. "Grid: " + units.formatValue (if activeGrid == undefined then gridPrefs.spacing else activeGrid.grid)
    102.  
    103. function drawInfo updated:false =
    104. (
    105. if updated do
    106. (
    107. local obj = modPanel.getCurrentObject()
    108.  
    109. if subObjectLevel != undefined and subObjectLevel > 0 and isValidObject obj then
    110. (
    111. case subObjectLevel of
    112. (
    113. 1: meshInfo.update (getNumVertsAsString $) (getSceneTrisAsString()) (gridSize())
    114. 2: meshInfo.update (getNumEdgesAsString $) (getSceneTrisAsString()) (gridSize())
    115. 3:
    116. (
    117. if isMesh obj then meshInfo.update (getNumTrisAsString $) (getSceneTrisAsString()) (gridSize())
    118. else meshInfo.update (getNumEdgesAsString $) (getSceneTrisAsString()) (gridSize())
    119. )
    120. 4: meshInfo.update (getNumTrisAsString $) (getSceneTrisAsString()) (gridSize())
    121. 5: meshInfo.update (getNumTrisAsString $) (getSceneTrisAsString()) (gridSize())
    122. )
    123. )
    124. else meshInfo.update (none()) (getSceneTrisAsString()) (gridSize())
    125. )
    126. meshInfo.redraw()
    127. )
    128. function updateDrawInfo evnt arg =
    129. drawInfo updated:true
    130.  
    131. function startDrawInfo =
    132. (
    133. meshInfo = meshInfoDef()
    134. registerRedrawViewsCallback ::drawInfo
    135. ::drawInfoNodeCallback = NodeEventCallback mouseUp:true all:updateDrawInfo
    136. drawInfo updated:true
    137. setNeedsRedraw()
    138. )
    139.  
    140. startDrawInfo()
    141. )
  • Revel
    Offline / Send Message
    Revel interpolator
    Sorry, just can test this now, was busy with another script since yesterday :)
    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 :)
  • Revel
    Offline / Send Message
    Revel interpolator
    Guys, on this few post before I posted a code about utilizing a dotNet stuff. Isit possible to extract it to work as a function without the rollout?
    1. on click_test open do
    ..this bits, what should I replaced it with if Ii want to use it without a rollout? or is it even possible? I run out of a keyword to search on the Maxscript help still couldn't find anything close for a solution =__=

    Was thinking of using it something like this;
    1. global glRevelTemp
    2.  
    3. (
    4. struct stRevelTemp
    5. (
    6. fn mouseBtn =
    7. (
    8. timer tick_tock interval:100 active:true
    9. local dnc_control
    10. local mouseButtonStates
    11. local leftBtn, midBtn, rightBtn
    12. local leftClicked, midClicked, rightClicked
    13. on tick_tock tick do
    14. (
    15. mouseButtonStates = dnc_control.MouseButtons.value__
    16. if (dotnet.CompareEnums mouseButtonStates leftBtn) do (leftClicked = true)
    17. if (dotnet.CompareEnums mouseButtonStates midBtn) do (midClicked = true)
    18. if (dotnet.CompareEnums mouseButtonStates rightBtn) do (rightClicked = true)
    19. case of
    20. (
    21. (leftClicked == true): (print "left"; leftClicked = false; return #left)
    22. (midClicked == true): (print "mid"; midClicked = false; return #mid)
    23. (rightClicked == true): (print "right"; rightClicked = false; return #right)
    24. )
    25. )
    26. on ??? do
    27. (
    28. dnc_control = dotNetClass "Control"
    29. mouseButtons = dnc_control.MouseButtons
    30. leftBtn = mouseButtons.Left.value__
    31. midBtn = mouseButtons.Middle.value__
    32. rightBtn = mouseButtons.Right.value__
    33. )
    34. )
    35. )
    36. glRevelTemp = stRevelTemp()
    37. )
    ..so intended to use it as glRevelTemp.mouseBtn() and return either #left/ #mid/ #right...but the "???" obviously stop the code from being any useful...
Sign In or Register to comment.