Files
gtav-src/tools_ng/dcc/current/max2012/scripts/pipeline/util/LodViewManipTool.ms
T
2025-09-29 00:52:08 +02:00

446 lines
13 KiB
Plaintext
Executable File

--try (destroyDialog RsLodViewToolRoll) catch ()
rollout RsLodViewToolRoll "LOD Visualisation"
(
local lodViewObj
local toolIsOpen = false
checkButton btnVisActive "LOD Visualisation" offset:[-12,4] across:2
checkBox chkLodSpheres "Show as spheres" offset:[-14,-2]
checkBox chkShowSourceLods "Show source-obj distances" pos:(chkLodSpheres.pos + [0, 20])
radioButtons rdoShowSelAll "Show for:" labels:#("Sel. Objs", "Sel. Hierarchy", "All Objs") offset:[0,-6]
-- Used to define the lod-render bits:
struct renderItem (clr, class = #line, points = #(), extra)
local renderList = #()
fn renderLodView =
(
-- Only continue drawing if editor-tool is still open:
if not toolIsOpen do
(
unregisterRedrawViewsCallback renderLodView
return OK
)
gw.setTransform (Matrix3 1)
local lineClr, textClr
for item in renderList do
(
local points = for pos in item.points collect (gw.wtransPoint pos)
case item.class of
(
#line:
(
gw.setColor #line item.clr
gw.wPolyline points item.extra
)
#marker:
(
gw.Marker points[1] item.extra color:item.clr
)
#text:
(
gw.setColor #text item.clr
gw.text points[1] item.extra
)
)
)
)
-- Returns position of point val (0->1) along bezier defined by three points:
fn quadraticBezierPoint posA posB posC val =
(
local t = 1 - val
local sn = 1 - t
local retVal = [0,0,0]
retVal.X = posA.x*t*t + posB.x*2*t*Sn + posC.x*sn*sn;
retVal.Y = posA.y*t*t + posB.y*2*t*Sn + posC.y*sn*sn;
retVal.Z = posA.z*t*t + posB.z*2*t*Sn + posC.z*sn*sn;
return retVal
)
fn getArcPoints startPoint endPoint height arrow:true =
(
local points = #()
local lineVec = endPoint - startPoint
local midPoint = startPoint + (0.5 * lineVec)
local startPoint2d = [startPoint.x, startPoint.y]
local endPoint2d = [endPoint.x, endPoint.y]
local dist2d = distance startPoint2d endPoint2d
local absHeight = abs height
if (dist2d < absHeight) do
(
height *= (dist2d / absHeight)
)
midPoint += [0, 0, height]
local arrowSize = 3.0
-- Don't arc line if nearly vertical:
local stepper = if (abs height > 0.1) then (1.0 / 6) else 1.0
local points = for val = 0.0 to 1.0 by stepper collect
(
quadraticBezierPoint startPoint midPoint endPoint val
)
if arrow do
(
local arrowStartVal = 1.0 - (arrowSize / (distance startPoint endPoint))
local arrowStartPos = quadraticBezierPoint startPoint midPoint endPoint arrowStartVal
local arrowVec = (endPoint - arrowStartPos)
local arrowParaVec = arrowSize * (normalize (cross arrowVec (arrowVec + [0,0,1])))
append points (arrowStartPos + arrowParaVec)
append points (arrowStartPos - arrowParaVec)
append points endPoint
)
return points
)
fn getCirclePoints pos radius segs =
(
local slice = 360.0 / segs
for n = 0 to (segs - 1) collect
(
local ang = slice * n
[pos.x + (radius * (cos ang)), pos.y + (radius * (sin ang)), pos.z]
)
)
local showObjItems = #()
-- Update render-data:
fn updateLodView updateObjList:true doRedraw:true =
(
-- Clear the current render-list:
renderList.count = 0
if not btnVisActive.checked do
(
deleteAllChangeHandlers id:#RsLodViewTool
return OK
)
unregisterRedrawViewsCallback renderLodView
-- Get render-options from UI:
local showAll = (rdoShowSelAll.state == 3)
local showHierarchy = (rdoShowSelAll.state == 2)
local drawSpheres = chkLodSpheres.checked
local showSourceLods = chkShowSourceLods.checked
if updateObjList then
(
-- Get scene-objects per lod-level:
local lodLevelledObjs = RsGetLodLevelObjs()
showObjItems = #()
for lodLevel = 1 to lodLevelledObjs.count do
(
local objList = lodLevelledObjs[lodLevel]
join showObjItems (for obj in objList where (showAll or obj.isSelected) and (not obj.isHidden) collect (dataPair obj:obj lodLevel:lodLevel))
)
-- Add selected-object parents/child hierarchies to to-render list:
if showHierarchy do
(
local parentObjItems = deepCopy showObjItems
local objNum = 0
while (objNum < parentObjItems.count) do
(
objNum += 1
local objItem = parentObjItems[objNum]
local objPar = RsSceneLink.getparent LinkType_LOD objItem.obj
if (objPar != undefined) do
(
append parentObjItems (dataPair obj:objPar lodLevel:(objItem.lodLevel + 1))
)
)
parentObjItems = for n = (showObjItems.count + 1) to parentObjItems.count collect parentObjItems[n]
local childObjItems = deepCopy showObjItems
local objNum = 0
while (objNum < childObjItems.count) do
(
objNum += 1
local objItem = childObjItems[objNum]
local childLodLevel = objItem.lodLevel - 1
local objChildItems = for childObj in (RsGetLODChildren objItem.obj) collect (dataPair obj:childObj lodLevel:childLodLevel)
join childObjItems objChildItems
)
childObjItems = for n = (showObjItems.count + 1) to childObjItems.count collect childObjItems[n]
-- Add unique-object items to main list:
local objsList = for item in showObjItems collect item.obj
for item in parentObjItems do
(
if (not item.obj.isHidden) and (appendIfUnique objsList item.obj) do (append showObjItems item)
)
for item in childObjItems do
(
if (not item.obj.isHidden) and (appendIfUnique objsList item.obj) do (append showObjItems item)
)
)
-- Set up change-handers for our objects:
local objs = for item in showObjItems collect item.obj
deleteAllChangeHandlers id:#RsLodViewTool
when objs deleted id:#RsLodViewTool do (updateLodView updateObjList:false doRedraw:false)
when transform objs changes id:#RsLodViewTool do (updateLodView updateObjList:false doRedraw:false)
when parameters objs changes id:#RsLodViewTool do (updateLodView updateObjList:false doRedraw:false)
)
-- Collect refDefs first, to preload lod-distances if required.
-- (Using refNums bitarray to avoid doing isRsRef check multiple times)
local refNums = #{}
local contRefNums = #{}
refNums.count = showObjItems.count
contRefNums.count = showObjItems.count
local refDefs = for objNum = 1 to showObjItems.count collect
(
local obj = showObjItems[objNum].obj
case of
(
(isRsRef obj):
(
refNums[objNum] = true
obj.refDef
)
(RsIsContainerLod obj):
(
contRefNums[objNum] = true
obj.refDef
)
default:dontCollect
)
)
refDefs = makeUniqueArray refDefs
RsRefFuncs.loadLodDistances refDefs
struct lodObjStruct (obj, isRef = false, isContRef = false, refdef, instLod = false, lodDist, sourceLodDist, lodParent, lodLevel)
local objItems = for objNum = 1 to showObjItems.count collect
(
local objItem = showObjItems[objNum]
local obj = objItem.obj
local listItem = lodObjStruct obj:obj isRef:refNums[objNum] isContRef:contRefNums[objNum] lodLevel:objItem.lodLevel
local instLod = true
local refDef
case of
(
(listItem.isRef):
(
refDef = listItem.refDef = obj.refDef
instLod = getAttr obj idxInstLodDistance
)
(listItem.isContRef):
(
refDef = listItem.refDef = obj.refDef
instLod = false
)
)
listItem.instLod = instLod
listItem.lodDist = if instLod then
(
listItem.sourceLodDist = if (refDef == undefined) then undefined else
(
refDef.lodDistance
)
getAttr obj idxLodDistance
)
else
(
if (refDef == undefined) then undefined else
(
refDef.lodDistance
)
)
if (listItem.lodDist != undefined) then listItem else dontCollect
)
-- Paramblock list causes updates whenever these objects are changed:
drawNodes = for item in objItems collect item.obj
local instLodClr = (color 180 255 180)
local refLodClr = Black
-- Avoid adding similar circles more than once:
local addedCircleHashes = #()
for item in objItems do
(
local drawColour = if item.instLod then instLodClr else refLodClr
local obj = item.obj
local objPos = obj.pos
local lodDist = item.lodDist
local sourceLodDist = item.sourceLodDist
local lodParent = item.lodParent = RsSceneLink.getparent LinkType_LOD obj
local hasParent = (lodParent != undefined)
local lodPivot = if hasParent then lodParent.pos else obj.pos
local backXform, rotXformA, rotXformB
if drawSpheres do
(
backXform = transMatrix -lodPivot
rotXformA = rotateXMatrix 90
rotXformA[4] = lodPivot
rotXformB = rotateZMatrix 90
rotXformB[4] = lodPivot
)
-- Add main LOD circles:
local thisLodDist = lodDist
local thisClr = drawColour
local hasLevels = (item.lodLevel != 1)
-- Draw non-selected objects with slightly darker circles:
if (not obj.isSelected) do (thisClr *= 0.7)
local circleHash = getHashValue #(thisClr, lodPivot, thisLodDist, item.lodLevel, 0) 1
if (appendIfUnique addedCircleHashes circleHash) do
(
for levelNum = 1 to item.lodLevel do
(
local circlePoints = getCirclePoints [0,0,0] thisLodDist 28
append renderList (renderItem clr:thisClr class:#line points:(for pos in circlePoints collect (pos + lodPivot)) extra:true)
-- Only draw extra lod-level circles for main circle, not for sphere-circles:
if drawSpheres and (levelNum == 1) do
(
append renderList (renderItem clr:thisClr class:#line points:(for pos in circlePoints collect (pos * rotXformA)) extra:true)
append renderList (renderItem clr:thisClr class:#line points:(for pos in circlePoints collect (pos * rotXformB)) extra:true)
)
-- Draw extra lines per lod-level - 10m spacing, darker as they go out
if hasLevels do
(
thisLodDist += 5.0
thisClr *= 0.7
)
)
)
-- Add dashed circle for prop's source-object lod-distance:
if showSourceLods and (sourceLodDist != undefined) do
(
local circleHash = getHashValue #(refLodClr, lodPivot, sourceLodDist, 1, 1) 1
if (appendIfUnique addedCircleHashes circleHash) do
(
local circlePoints = getCirclePoints [0,0,0] sourceLodDist 40
append circlePoints circlePoints[1]
local circleDashes = for n = 1 to (circlePoints.count - 1) by 2 collect #(circlePoints[n] + lodPivot, circlePoints[n + 1] + lodPivot)
if drawSpheres do
(
join circleDashes (for n = 1 to (circlePoints.count - 1) by 2 collect #(circlePoints[n] * rotXformA, circlePoints[n + 1] * rotXformA))
join circleDashes (for n = 1 to (circlePoints.count - 1) by 2 collect #(circlePoints[n] * rotXformB, circlePoints[n + 1] * rotXformB))
)
join renderList (for item in circleDashes collect (renderItem clr:refLodClr class:#line points:item extra:false))
)
)
-- Add arc to parent, if pivots are different:
if hasParent and ((distance objPos lodPivot) > 0.1) do
(
local arcClr = drawColour * 0.7
local arcPoints = getArcPoints objPos lodPivot (-0.15 * lodDist)
append renderList (renderItem clr:arcClr class:#line points:arcPoints extra:false)
append renderList (renderItem clr:drawColour class:#marker points:#(objPos) extra:#xMarker)
)
-- Add lod-pivot marker:
append renderList (renderItem clr:drawColour class:#marker points:#(lodPivot) extra:#circle)
)
registerRedrawViewsCallback renderLodView
if doRedraw do
(
completeRedraw()
)
return OK
)
fn removeCallbacks =
(
renderList.count = 0
deleteAllChangeHandlers id:#RsLodViewTool
callbacks.removeScripts id:#RsLodViewTool
unregisterRedrawViewsCallback renderLodView
)
fn setupCallbacks =
(
callbacks.addScript #selectionSetChanged "RsLodViewToolRoll.updateLodView()" id:#RsLodViewTool
callbacks.addScript #filePostOpenProcess "RsLodViewToolRoll.updateLodView()" id:#RsLodViewTool
callbacks.addScript #filePostSaveProcess "RsLodViewToolRoll.updateLodView()" id:#RsLodViewTool
callbacks.addScript #systemPostReset "RsLodViewToolRoll.updateLodView()" id:#RsLodViewTool
callbacks.addScript #systemPostNew "RsLodViewToolRoll.updateLodView()" id:#RsLodViewTool
registerRedrawViewsCallback renderLodView
)
on btnVisActive changed state do
(
updateLodView()
if not state do (completeRedraw())
)
on chkLodSpheres changed state do (updateLodView updateObjList:false)
on chkShowSourceLods changed state do (updateLodView updateObjList:false)
on rdoShowSelAll changed state do (updateLodView())
on RsLodViewToolRoll open do
(
toolIsOpen = true
setupCallbacks()
updateLodView()
)
on RsLodViewToolRoll close do
(
toolIsOpen = false
removeCallbacks()
if btnVisActive.checked do (completeRedraw())
)
-- Save rolled-up state:
on RsLodViewToolRoll rolledUp down do
(
RsSettingWrite "RsLodViewToolRoll" "rollup" (not down)
)
)
--createDialog RsLodViewToolRoll width:300