Files
2025-09-29 00:52:08 +02:00

3485 lines
99 KiB
Plaintext
Executable File

--
-- File:: selector.ms
-- Description:: Object Selector Mk2
--
-- Author:: David Muir <david.muir@rockstarnorth.com>
-- Date:: 10 July 2007
--
-- Greg Smith
-- Rockstar North
-- 25/5/2004
-- a whole lot of stuff for selecting objects based on specific attributes such as by
-- txd, collision group etc.
try destroyDialog RsSelToolRoll catch ()
filein (RsConfigGetWildWestDir() + "script/3dsMax/_Common_Functions/FN_Objects.ms")
filein "pipeline/util/IdeUtils.ms"
-- Rs Asset Size utilites
filein "Rockstar/util/assetsizes.ms"
filein "rockstar/util/collutil.ms"
-- Select objects, then redraw:
fn RsSelectObjs objs =
(
undo "select objects" on
(
case ::RsSelToolGeneralRoll.ddlSelectionOperand.selection of
(
1 : -- CLEAR
(
clearselection()
select objs
)
2 : -- ADD
(
selectMore objs
)
3 : -- REMOVE
(
deselect objs
)
)
completeRedraw()
)
)
fn RsAppendToValueString fieldname appendtext =
(
idxObjectField = GetAttrIndex "Gta Object" fieldname
idxAnimHierField = GetAttrIndex "GtaAnimHierarchy" fieldname
for obj in selection do (
idxField = -1
if GetAttrClass obj == "Gta Object" then (
idxField = idxObjectField
)
if GetAttrClass obj == "GtaAnimHierarchy" then (
idxField = idxAnimHierField
)
if idxField != -1 then (
fieldString = GetAttr obj idxField
fieldString = fieldString + appendtext
if fieldString.count < 30 then (
SetAttr obj idxField fieldString
)
)
)
)
fn RsColourByGroup objLists colourList =
(
for i = 1 to objLists.count do
(
local numRounded = mod (i - 1) colourlist.count
local numDivision = abs((i - 1) / colourlist.count)
local numSubtraction = (10 * numDivision)
numSubtraction = mod numSubtraction 255
numSubtraction = numSubtraction / 255.0
objLists[i].wirecolor = (1 - numSubtraction) * colourList[numRounded + 1]
)
)
fn RsColourByFieldValueString objLists =
(
local colourList = #((color 255 0 0),(color 255 0 255),(color 0 0 255),(color 255 255 0),(color 0 255 255),(color 0 255 0),(color 0 128 192))
RsColourByGroup objLists colourList
)
rollout RsSelToolGeneralRoll "Selection:"
(
--label lblSelAllSome "Select from:" align:#left across:2
--radioButtons rdoSelAllSome "" labels:#("All", "Current Selection") columns:2 align:#left default:1 offset:[-50,0]
label lblSelAllSome "Select from:" align:#left across:5 offset:[0,4]
dropdownlist ddlSelectionFilter items:#("All", "Selection") offset:[-10,0]
label lblSelAnd "and" align:#left offset:[-3,4]
dropdownlist ddlSelectionOperand items:#("Clear Selection", "Add To Selection", "Remove From Sel") width:110 align:#left offset:[-50,0]
checkBox chkIgnoreHidden "Ignore Hidden" checked:false align:#right offset:[10,4]
-- Is 'Current Selection' option selected?
fn IsFromSelected =
(
return (ddlSelectionFilter.selection == 2)
)
-- Returns list of objects matching this rollout's controls:
fn objectList attrClass: =
(
local selObjs = (if (IsFromSelected()) then Selection else Objects) as array
if chkIgnoreHidden.checked do
(
selObjs = for obj in selObjs where (not obj.isHidden) collect obj
)
-- Filter by Attribute Class:
if (attrClass != unsupplied) do
(
selObjs = for obj in selObjs where (getAttrClass obj == attrClass) collect obj
)
return selObjs
)
-- Selects faces of mesh/poly objects that are supplied by Func:
fn selObjFaces objs faceLists silent:false =
(
undo "select faces" on
(
-- Filter out non-selecty objects:
local selObjs = #()
local selFaceItems = #()
local selFaceItemObjs = #()
-- Filter out objects with empty face-lists, and make list with no redundant instances:
for n = 1 to faceLists.count where (faceLists[n].numberSet != 0) do
(
local obj = objs[n]
append selObjs obj
-- Don't select faces more than once for instances:
local doObj = True
for otherObj in selFaceItemObjs while doObj do
(
doObj = not (areNodesInstances obj otherObj)
)
if doObj do
(
append selFaceItemObjs obj
append selFaceItems (dataPair obj:obj faceList:faceLists[n])
)
)
-- Stop processing if no objects have faces for selection:
if (selFaceItems.count == 0) do
(
clearSelection()
return OK
)
if (getCommandPanelTaskMode() != #modify) do
(
setCommandPanelTaskMode #modify
)
local obj = selFaceItems[1].obj
if (selFaceItems.count == 1) and (obj.modifiers.count == 0) and ((isKindOf obj Editable_Poly) or (isKindOf obj Editable_Mesh)) then
(
if (getSelectionLevel obj) != #face do
(
setSelectionLevel obj #face
)
setFaceSelection obj selFaceItems[1].faceList
select selObjs
)
else
(
local selWarn = if (selFaceItems.count == 1) then "Warning: Found object has modifiers." else "Warning: Multiple objects found."
if silent or (queryBox (selWarn + "\n\nDo you want to show found faces by adding a \"Poly Select\" modifier?") title:"Add Selection Modifier?") do
(
local timeStart = timeStamp()
with redraw off
(
pushPrompt "Adding Poly Select modifiers"
-- Keep note of objects that were originally mesh, and need to have their face-nums converted:
local notPolyObjNums = #{}
local selObjs = for n = 1 to selFaceItems.count collect
(
local thisObj = selFaceItems[n].obj
notPolyObjNums[n] = ((RsMeshPolyOp thisObj) != polyOp)
thisObj
)
select selObjs
undo off
(
local selMod = Edit_Poly()
modPanel.addModtoSelection selMod
for n = 1 to selFaceItems.count do
(
local promptMsg = stringStream ""
format "Adding Poly Select modifiers (% of %)" n selFaceItems.count to:promptMsg
pushPrompt (promptMsg as string)
local obj = selFaceItems[n].obj
local faceList = selFaceItems[n].faceList
-- Convert face-selection from mesh to poly if required:
if notPolyObjNums[n] do
(
local newFaceList = #{}
local polyCount = (selMod.getNumFaces node:obj)
newFaceList.count = polyCount
local triToPolyList = #()
for polyNum = 1 to polyCount do
(
for polyTriNum = 3 to (selMod.GetFaceDegree polyNum node:obj) do
(
append triToPolyList polyNum
)
)
for faceNum in faceList do
(
newFaceList[triToPolyList[faceNum]] = True
)
faceList = newFaceList
)
selMod.setSelection #Face faceList node:obj
popPrompt()
)
)
-- Add Poly Select modifier to objects, which takes on earlier modifiers' face-selections:
modPanel.addModtoSelection (poly_select())
popPrompt()
-- Remove the temporary edit_poly modifier:
pushPrompt "Deleting temp modifiers..."
suspendEditing()
for obj in selObjs do
(
deleteModifier obj selMod
)
resumeEditing()
popPrompt()
format "Face-select: Modifier-add took %s\n" ((timeStamp() - timeStart) / 1000.0)
)
)
)
local selNode = modPanel.getCurrentObject()
if (isKindOf selNode Poly_Select) or (isKindOf selNode Editable_Poly) or (isKindOf selNode Editable_Mesh) do
(
subobjectLevel = 4
)
)
)
-- LOOP ROLLOUTS AND CALL SELECTION CHANGED FUNCTION
fn updateRolloutsSelectionChanged =
(
local SubRolls = ::RsSelToolRoll.theSubRollout.Rollouts
for SubRoll in SubRolls where (isProperty SubRoll #SelOptionChanged) do
(
SubRoll.SelOptionChanged()
)
)
-- Trigger 'SelOptionChanged' function for shown rollouts that have it:
on ddlSelectionFilter selected Val do
(
updateRolloutsSelectionChanged()
)
-- SAME AS ABOVE BUT FOR THE CHECKBOX
on chkIgnoreHidden changed Val do
(
updateRolloutsSelectionChanged()
)
-- Don't allow rollout to be rolled up:
on RsSelToolGeneralRoll rolledUp Down do
(
if (not Down) do (RsSelToolGeneralRoll.open = True)
)
)
rollout RsSelToolObjRoll "Object Selection"
(
local btnWidth = 60
local btnHeight = 18
spinner spinBoundBox "Bounding Box Volume:" range:[0,1000,0] align:#left width:150 across:3
button btnSelBBLarger "Select >" align:#right width:btnWidth height:btnHeight offset:[-10,-1]
button btnSelBBSmaller "Select <" align:#left width:btnWidth height:btnHeight offset:[-4,-1]
spinner spinPolyCount "Poly Count: " range:[0,100000,0] scale:1.0 align:#left width:150 type:#integer across:3
button btnSelPolyLarger "Select >" align:#right width:btnWidth height:btnHeight offset:[-10,-1]
button btnSelPolySmaller "Select <" align:#left width:btnWidth height:btnHeight offset:[-4,-1]
spinner spinPriority "Priority: " range:[0,3,3] scale:1 type:#integer across:4 align:#left width:180
button btnSelPriorityLarger "Select >=" width:btnWidth height:btnHeight offset:[66,-1]
button btnSelPrioritySmaller "Select <=" width:btnWidth height:btnHeight pos:(btnSelPriorityLarger.pos + [btnWidth + 6,0])
button btnSelPriorityExact "Select ==" width:btnWidth height:btnHeight pos:(btnSelPrioritySmaller.pos + [btnWidth + 6,0])
spinner spinPercent "Reduce Selection %: " range:[0,100,50] scale:1 type:#integer across:2 align:#left width:118
button btnSelPercent "Select" width:btnWidth height:btnHeight offset:[-72,-1] tooltip:"Reduce selection-count to percentage of current selection"
button btnSelFromFile "Select From File" width:116 across:3 tooltip:"Select objects named in a textfile"
button btnSelRotated "Select Rotated" width:116 tooltip:"Select objects with rotation"
button btnSelScaled "Select Scaled" width:116 tooltip:"Select objects with scaling"
local idxPriority = GetAttrIndex "Gta Object" "Priority"
on btnSelPercent pressed do
(
-- Randomise list:
local randomisedItems = for obj in selection collect (dataPair obj:obj num:(random 0 10000))
fn sortByNum v1 v2 = (v1.num - v2.num)
qsort randomisedItems sortByNum
-- Get subset of randomised object-list:
local selCount = (spinPercent.value / 100.0) * randomisedItems.count
local newSel = for n = 1 to selCount collect randomisedItems[n].obj
RsSelectObjs newSel
)
on btnSelRotated pressed do
(
local considerSet = RsSelToolGeneralRoll.objectList attrClass:"Gta Object"
local objsel = for obj in considerSet where (not isIdentity obj.rotation) collect obj
RsSelectObjs objSel
)
on btnSelScaled pressed do
(
local considerSet = RsSelToolGeneralRoll.objectList attrClass:"Gta Object"
local objsel = for obj in considerSet where (distance obj.scale [1,1,1] > 0.0001) collect obj
RsSelectObjs objSel
)
fn getVolume obj =
(
local boundbox = (obj.max - obj.min) / 2.0
return (length boundbox)
)
on btnSelBBLarger pressed do
(
local considerSet = RsSelToolGeneralRoll.objectList()
local selset = for obj in considerSet where (getVolume obj > spinBoundBox.value) collect obj
RsSelectObjs selSet
)
on btnSelBBSmaller pressed do
(
local considerSet = RsSelToolGeneralRoll.objectList()
local selset = for obj in considerSet where (getVolume obj < spinBoundBox.value) collect obj
RsSelectObjs selSet
)
on btnSelPriorityLarger pressed do
(
local considerSet = RsSelToolGeneralRoll.objectList attrClass:"Gta Object"
local selSet = for obj in considerSet where (getattr obj idxPriority) >= spinPriority.value collect obj
RsSelectObjs selSet
)
on btnSelPrioritySmaller pressed do
(
local considerSet = RsSelToolGeneralRoll.objectList attrClass:"Gta Object"
local selSet = for obj in considerSet where (getattr obj idxPriority) <= spinPriority.value collect obj
RsSelectObjs selSet
)
on btnSelPriorityExact pressed do
(
local considerSet = RsSelToolGeneralRoll.objectList attrClass:"Gta Object"
local selSet = for obj in considerSet where (getattr obj idxPriority) == spinPriority.value collect obj
RsSelectObjs selSet
)
on btnSelPolyLarger pressed do
(
local considerSet = RsSelToolGeneralRoll.objectList()
local selset = for obj in considerSet where (isProperty obj #mesh) and (getNumFaces obj.mesh) > spinPolyCount.value collect obj
RsSelectObjs selset
)
on btnSelPolySmaller pressed do
(
local considerSet = RsSelToolGeneralRoll.objectList()
local selset = for obj in considerSet where (isProperty obj #mesh) and (getNumFaces obj.mesh) < spinPolyCount.value collect obj
RsSelectObjs selset
)
on btnSelFromFile pressed do
(
local filename = getopenfilename caption:"list file" types:"Txt (*.txt)|*.txt|"
if filename == undefined do return false
local fileHandle = openfile filename
if fileHandle == undefined then
(
messagebox ("Could not open file" + filename) title:"Textfile load failed"
)
else
(
local considerSet = RsSelToolGeneralRoll.objectList()
local selObjs = #()
while not eof fileHandle do
(
local currLine = trimRight (trimLeft (readline fileHandle))
local getObjs = getNodeByName currLine all:true
for obj in getObjs where (findItem considerSet obj) != 0 do
(
append selObjs obj
)
)
RsSelectObjs selObjs
)
)
)
rollout RsSelToolIplRoll "IPL Selection"
(
local groupNames, objLists
dropdownlist listIplGroup width:290 across:2
button btnRefresh "Refresh" align:#right
button btnSelGroup "Select by" offset:[-14,0] across:3 width:90
button btnAdd2SelGroup "Add to Selection" offset:[-36,0] width:90
button btnColourGroup "Colour wire by" offset:[-58,0] width:90
button buttonAppend "Append To Selected:" offset:[55,0] across:2
edittext appendVal "" fieldWidth:50 offset:[30,2]
fn refresh =
(
local prevSel = listIplGroup.selected
objLists = #()
groupNames = RsGetUniqueNames "IPL Group" objListsOut:objLists includeRefs:true
listIplGroup.items = groupNames
listIplGroup.selection = findItem groupNames prevSel
)
on btnColourGroup pressed do
(
refresh()
RsColourByFieldValueString objLists
)
on btnSelGroup pressed do
(
refresh()
local selGrp = listIplGroup.selection
local considerSet = RsSelToolGeneralRoll.objectList()
local selObjs = if (selGrp == 0) then #() else
(
for obj in objLists[selGrp] where (findItem considerSet obj) != 0 collect obj
)
RsSelectObjs selObjs
)
on btnAdd2SelGroup pressed do
(
refresh()
local currentSelection = $selection as array
local selGrp = listIplGroup.selection
local considerSet = RsSelToolGeneralRoll.objectList()
local selObjs = if (selGrp == 0) then #() else
(
for obj in objLists[selGrp] where (findItem considerSet obj) != 0 collect obj
)
RsSelectObjs selObjs
selectMore currentSelection
completeRedraw()
)
on buttonAppend pressed do
(
RsAppendToValueString "IPL Group" appendVal.text
refresh()
)
on btnRefresh pressed do (refresh())
on RsSelToolIplRoll open do (refresh())
)
rollout RsSelToolTxdRoll "TXD Names:"
(
local txdNames, txdObjs
dropdownlist listTxdGroup width:290 across:2
button btnRefresh "Refresh" align:#right
button btnSelGroup "Select by TXD" offset:[48,-2] across:2
button btnColourGroup "Colour wire by TXD" offset:[-38,-2]
checkBox includeRefchk "Include RSRefs" offset:[0,-25]
button buttonAppend "Suffix Selected:" offset:[53,2] tooltip:"Append suffix to selected objects' TXDs" across:2
edittext appendVal "" fieldWidth:50 offset:[10,4]
fn refresh =
(
txdNames = #()
txdObjs = #()
RsGetTxdList rootnode.children txdNames txdObjs includeRefs:includeRefchk.checked sorted:True
listTxdGroup.items = txdNames
)
on includeRefchk changed args do
(
refresh()
)
on btnColourGroup pressed do
(
refresh()
RsColourByFieldValueString txdObjs
)
on btnSelGroup pressed do
(
if (listTxdGroup.selection != 0) do
(
local considerSet = RsSelToolGeneralRoll.objectList()
local selObjs = for obj in txdObjs[listTxdGroup.selection] where (findItem considerSet obj) != 0 collect obj
RsSelectObjs selObjs
)
)
on buttonAppend pressed do
(
RsAppendToValueString "TXD" appendVal.text
refresh()
)
on btnRefresh pressed do (refresh())
on RsSelToolTxdRoll open do (refresh())
)
rollout RsSelToolAreaCodeRoll "Area Code"
(
fn CreateAreaCodeList =
(
local areacodelist = #()
append areacodelist "Main map"
for i = 1 to 12 do
(
append areacodelist ("Interior" + (i as string))
)
append areacodelist "Always Drawn"
for i = 13 to 17 do
(
append areacodelist ("Interior" + (i as string))
)
return areacodelist
)
local allAreaCodes = CreateAreaCodeList()
dropdownlist listAreaCodes items:allAreaCodes
button buttonAreaCode "Select by" offset:[-50,0]
button buttonColourAreaCode "Colour wire by" offset:[30,-27]
fn colourByFieldValueNumber objLists =
(
local colourlist = #((color 255 255 255),(color 255 0 0),(color 0 255 0),(color 0 0 255),(color 255 255 0),(color 0 255 255),(color 255 0 255))
RsColourByGroup objLists colourList
)
fn selectByFieldValueNumber fieldname fieldvalue =
(
if fieldvalue == undefined then (
return 0
)
selset = #()
idxObjectField = GetAttrIndex "Gta Object" fieldname
idxAnimHierField = GetAttrIndex "GtaAnimHierarchy" fieldname
considerSet = RsSelToolGeneralRoll.objectList()
for obj in considerSet do (
idxField = -1
if GetAttrClass obj == "Gta Object" then (
idxField = idxObjectField
)
if GetAttrClass obj == "GtaAnimHierarchy" then (
idxField = idxAnimHierField
)
if idxField != -1 then (
fieldCompare = GetAttr obj idxField
if fieldCompare == fieldvalue then (
append selset obj
)
)
)
RsSelectObjs selSet
)
on buttonColourAreaCode pressed do
(
colourByFieldValueNumber "Area Code" allAreaCodes
)
on buttonAreaCode pressed do
(
selectByFieldValueNumber "Area Code" (listAreaCodes.selection - 1)
)
)
rollout RsDupeSelector "Duplicate Selection"
(
button btnSearch "Search For Duplicates" align:#center across:2 width:160
checkbox chkSelectDupes "Select Result" align:#left checked:true
edittext txtSetName "Set Name:" align:#left width:160 text:"R* duplicates" across:2
checkbox chkAddToSelSet "Add To Selection Set" align:#left checked:true
--functions
fn CompareObject objA objB =
(
(objA != objB) and -- Same object?
(objA.pos == objB.pos) and -- Same position?
(isKindOf objA (classof objB)) and -- Same class?
(
((isKindOf objA Editable_Mesh) or (isKindOf objA Editable_Poly)) -- Is objA a mesh/poly?
) and
(
(objA.numfaces == objB.numfaces) and -- Same number of faces?
(objA.numverts == objB.numverts)and -- Same number of verts?
(
-- Are all the verts the same?
local sameVerts = True
for i = 1 to objA.numverts while sameVerts do
(
if objA.verts[i].pos != objB.verts[i].pos do (sameVerts = False)
)
sameVerts
)
)
)
fn FindDuplicates objlist =
(
-- Check for geometry repeats
-- local objlist = objects as array
local dupeObjs = #()
local dupes = #{}
progressStart "checking repeats"
totalCount = objlist.count
for i = 1 to objList.count where not dupes[i] while (progressUpdate (100.0 * i / objList.count)) do
(
local obj = objlist[i]
for j = (i + 1) to totalCount where not dupes[j] do
(
objcompare = objlist[j]
if (CompareObject obj objcompare) do
(
append dupeObjs objcompare
dupes[j] = true
)
)
)
progressEnd()
if (dupeObjs.count == 0) then
(
messageBox "No duplicate meshes found" title:"Duplicate Selection" beep:false
)
else
(
local setName = txtSetName.Text
if (chkAddToSelSet.Checked) then
(
if (setName == "") then
(
setName = "R* duplicates"
txtSetName.Text = setName
)
selectionsets[txtSetName.Text] = dupeObjs
)
if (chkSelectDupes.Checked) do
(
RsSelectObjs dupeObjs
)
messageBox (dupeObjs.count as string + " duplicates were found.\nDuplicate objects added to selection-set " + setName) title:"Duplicate Selection"
)
)
--events
on btnSearch pressed do
(
-- local considerSet = RsSelToolGeneralRoll.objectList()
-- txtSetName.Text = considerSet.count as string
FindDuplicates (RsSelToolGeneralRoll.objectList())
)
on chkAddToSelSet changed state do
(
if (state) then
(
txtSetName.Visible = true
)
else
(
txtSetName.Visible = false
if (not chkSelectDupes.Checked) then chkSelectDupes.Checked = true
)
)
on chkSelectDupes changed state do
(
if (not state) then
(
chkAddToSelSet.Checked = true
txtSetName.Visible = true
)
)
)
rollout RsRotationSelector "Rotation selection"
(
group "Full-Matrix Rotation:"
(
checkbox chkFlagSet "'Use Full Matrix' set" checked:True across:4
checkbox chkDynamics "Dynamic props" checked:True offset:[26,0]
checkbox chkRotated "Quat X/Y > 0.05" checked:True offset:[30,0]
button btnSelChecked "Select" align:#right offset:[4,-3]
tooltip:"Select objects that will use full quaternion rotation in-game.\n\n(instead of just z-axis rotation)"
)
local btnWidth = 60
local btnHeight = 18
group "Tilt:"
(
spinner spnTilt "Tilt Angle:" range:[0,90,5] align:#left width:110 across:3
button btnSelTiltGT "Select > Angle" align:#right width:80 height:btnHeight offset:[-40,-1]
button btnSelTiltLT "Select < Angle" align:#left width:80 height:btnHeight offset:[-34,-1]
button btnSuggestFullMatrix "( Not Full Matrix ) and ( > Angle )" height:btnHeight align:#left offset:[0,-2]
tooltip:"Select tilted objects that won't currently show as tilted in-game"
)
local idxDynamic = GetAttrIndex "Gta Object" "Is Dynamic"
local idxUseFullMatrix = GetAttrIndex "Gta Object" "Use Full Matrix"
fn isFullMatrixObj obj flagged:True dynamics:True rotated:True =
(
(GetAttrClass obj == "Gta Object") and
(
(
(flagged) and (getAttr obj idxUseFullMatrix)
) or
(
(dynamics) and
(
(GetAttr obj idxDynamic) or
(
(isRsRef obj) and (obj.refDef != undefined) and (obj.refDef.isDynamic)
)
)
) or
(
(rotated) and (RsHasAutoFullMatrix obj)
)
)
)
on btnSelChecked pressed do
(
local considerSet = RsSelToolGeneralRoll.objectList()
local flagged = chkFlagSet.checked
local dynamics = chkDynamics.checked
local rotated = chkRotated.checked
-- Filter out objects that don't trigger any of the checked criteria:
selObjs = for obj in considerSet where (isFullMatrixObj obj flagged:flagged dynamics:dynamics rotated:rotated) collect obj
RsSelectObjs selObjs
)
on btnSelTiltGT pressed do
(
local considerSet = RsSelToolGeneralRoll.objectList()
local tiltLimit = spnTilt.value
selObjs = for obj in considerSet where ((RsGetObjTilt obj) > tiltLimit) collect obj
RsSelectObjs selObjs
)
on btnSelTiltLT pressed do
(
local considerSet = RsSelToolGeneralRoll.objectList()
local tiltLimit = spnTilt.value
selObjs = for obj in considerSet where ((RsGetObjTilt obj) < tiltLimit) collect obj
RsSelectObjs selObjs
)
on btnSuggestFullMatrix pressed do
(
local considerSet = RsSelToolGeneralRoll.objectList()
local tiltLimit = spnTilt.value
selObjs = for obj in considerSet where (not isFullMatrixObj obj) and ((RsGetObjTilt obj) > tiltLimit) collect obj
RsSelectObjs selObjs
)
)
rollout RsSelToolLodRoll "LOD Value"
(
groupBox grpLodDist "Select by:" width:84 height:64 offset:[7, 0] across:2
spinner spnMinLod "Distance:" range:[0,4000,0] align:#left offset:[-80,3] fieldwidth:40 type:#integer
spinner spnMaxLod "Maximum:" range:[0,4000,0] pos:(spnMinLod.pos + [-88, 20]) fieldwidth:40 type:#integer enabled:False
checkButton chkLodRange "Range" pos:(spnMaxLod.pos + [16,-3])
button btnLodValue "Lod Distance" pos:(grpLodDist.pos + [4,16]) width:76
button btnChildLodValue "Child Lod Dist." pos:(btnLodValue.pos + [0, 23]) width:76
label dummyA "" offset:[0,-14]
button buttonColourLODHierarchy "Colour Wire by Lod" across:3
button btnSelNoChildren "Select With No Children" offset:[4,0]
button btnSelUnlodded "Select Unlodded"
fn colourlodchildren parent level colmultiple =
(
parent.wirecolor = (color 255 0 0) + (level * (color 0 colmultiple colmultiple))
local childnodes = getLODChildren parent
for child in childnodes do
(
colourlodchildren child (level + 1) colmultiple
)
)
on spnMinLod changed val do
(
if (chkLodRange.checked) or (val > spnMaxLod.value) do
(
spnMaxLod.value = val
)
)
on spnMaxLod changed val do
(
if (val < spnMinLod.value) do
(
spnMinLod.value = val
)
)
on chkLodRange changed state do
(
spnMinLod.text = if state then "Minimum:" else "Distance:"
spnMaxLod.enabled = state
if (not state) do
(
spnMaxLod.value = spnMinLod.value
)
)
on buttonColourLODHierarchy pressed do
(
local considerSet = RsSelToolGeneralRoll.objectList()
for obj in considerSet do
(
parentnode = RsSceneLink.getparent LinkType_LOD obj
childnodes = getLODChildren obj
if parentnode == undefined do
(
if childnodes.count == 0 then
(
obj.wirecolor = (color 0 0 255)
)
else
(
maxlevels = getspnMaxLodLevels obj
maxlevels = maxlevels - 1
colmultiple = 255 / maxlevels
colourlodchildren obj 0 colmultiple
)
)
)
)
on btnSelNoChildren pressed do
(
local considerSet = RsSelToolGeneralRoll.objectList attrClass:"Gta Object"
local selSet = for obj in considerSet where ((getLODChildren obj).count == 0) collect obj
RsSelectObjs selSet
)
on btnSelUnlodded pressed do
(
local considerSet = RsSelToolGeneralRoll.objectList attrClass:"Gta Object"
local selSet = for obj in considerSet where
(
((getLODChildren obj).count == 0) and
(RsSceneLink.getparent LinkType_LOD obj == undefined)
)
collect obj
RsSelectObjs selSet
)
on btnLODvalue pressed do
(
local selset = #()
local considerSet = RsSelToolGeneralRoll.objectList attrClass:"Gta Object"
for obj in considerSet do
(
local fieldValue = RsGetObjLodDistance obj
if (fieldValue >= spnMinLod.value) and (fieldValue <= spnMaxLod.value) do
(
append selset obj
)
)
RsSelectObjs selSet
)
on btnChildLodValue pressed do
(
local selset = #()
local considerSet = RsSelToolGeneralRoll.objectList attrClass:"Gta Object"
for obj in considerSet do
(
local fieldValue = getattr obj idxChildLodDistance
if (fieldValue >= spnMinLod.value) and (fieldValue <= spnMaxLod.value) do
(
append selset obj
)
)
RsSelectObjs selSet
)
)
rollout RsSelToolDrawLodRoll "Drawable LOD"
(
button btnSelHD "Select HD models" width:120 tooltip:"Select HD objects (with drawable-lods)" offset:[-4,0] across:3
button btnSelL1 "Select L1 models" tooltip:"Select L1 drawable-lods" width:120
button btnSelL2 "Select L2 models" tooltip:"Select L2 drawable-lods" width:120 offset:[4,0]
fn getDrawableChilds obj =
(
local getObjs = #()
RsSceneLink.GetChildren LinkType_DRAWLOD obj &getObjs
return getObjs
)
fn getDrawableParent obj =
(
RsSceneLink.GetParent LinkType_DRAWLOD obj
)
on btnSelHD pressed do
(
local considerSet = RsSelToolGeneralRoll.objectList attrClass:"Gta Object"
local selset = for obj in considerSet where
(
((getDrawableParent obj) != undefined) and
((getDrawableChilds obj).count == 0)
)
collect obj
RsSelectObjs selSet
)
on btnSelL1 pressed do
(
local selset = #()
local considerSet = RsSelToolGeneralRoll.objectList attrClass:"Gta Object"
for obj in considerSet do
(
local objChilds = getDrawableChilds obj
if (objChilds.count != 0) do
(
if ((getDrawableChilds objChilds[1]).count == 0) do
(
append selSet obj
)
)
)
RsSelectObjs selSet
)
on btnSelL2 pressed do
(
local selset = #()
local considerSet = RsSelToolGeneralRoll.objectList attrClass:"Gta Object"
for obj in considerSet do
(
local objChilds = getDrawableChilds obj
if (objChilds.count != 0) do
(
local objChildChilds = getDrawableChilds objChilds[1]
if (objChildChilds.count != 0) do
(
if ((getDrawableChilds objChildChilds[1]).count == 0) do
(
append selSet obj
)
)
)
)
RsSelectObjs selSet
)
)
rollout RsSelToolProcAttrRoll "Procedural Attribute"
(
button btnSelAllWithProc "Select Procedural ColMeshes" width:170 across:2 tooltip:"Select collision-meshes that have procedural materials"
button btnSelProceduralFaces "Select Procedural Faces" width:170 tooltip:"Select faces on selected collision-mesh that have procedural materials"
on btnSelProceduralFaces pressed do
(
if selection.count != 1 do
(
messagebox "please select just one object"
return false
)
local obj = selection[1]
if classof obj != Col_Mesh do
(
messagebox "only works on a collision mesh"
return false
)
col2mesh obj
facesout = #()
RsGetProceduralFaces obj obj.material facesout
select obj
-- mesh2col obj
setCommandPanelTaskMode mode:#modify
subobjectlevel = 4
setfaceselection obj facesout
)
on btnSelAllWithProc pressed do
(
local considerSet = RsSelToolGeneralRoll.objectList()
local selSet = for obj in considerSet where (isKindOf obj Col_Mesh) and (RsGetDoesObjUseProcedurals obj obj.material) collect obj
RsSelectObjs selSet
)
)
rollout RsSelToolIrefsRoll "Internal Refs"
(
local irefSources, irefObjs
group "Select from Iref group:"
(
button btnSelIRefs "Irefs:" width:80 align:#left offset:[-4,-3]
dropdownlist lstIrefObjs width:232 offset:[80,-14] across:2
button btnRefresh "Refresh" pos:(lstIrefObjs.pos + [lstIrefObjs.width + 2,0])
button btnSelSrc "Source:" width:80 align:#left pos:(btnSelIRefs.pos + [0,24])
)
button btnSelAllIRefs "Select All Irefs"
fn refresh =
(
irefSources = #()
irefObjs = #()
for obj in objects where isInternalRef obj do
(
local src = getIRefSource obj
local irefIdx = findItem irefSources src
if (irefIdx == 0) do
(
if (src == undefined) then
(
insertItem undefined irefSources 1
insertItem #() irefObjs 1
irefIdx = 1
)
else
(
append irefSources src
append irefObjs #()
irefIdx = irefSources.count
)
)
append irefObjs[irefIdx] obj
)
local itemNames = for n = 1 to irefSources.count collect
(
local itemName = if (irefSources[n] == undefined) then "[unassigned]" else irefSources[n].name
itemName + (" (" + irefObjs[n].count as string + " objs)")
)
lstIrefObjs.items = itemNames
)
on btnRefresh pressed do (refresh())
on btnSelSrc pressed do
(
if (lstIrefObjs.selection != 0) do
(
clearSelection()
if isValidNode irefSources[lstIrefObjs.selection] do
(
RsSelectObjs irefSources[lstIrefObjs.selection]
)
)
)
on btnSelIRefs pressed do
(
if (lstIrefObjs.selection != 0) do
(
local considerSet = RsSelToolGeneralRoll.objectList()
local selObjs = for obj in irefObjs[lstIrefObjs.selection] where (findItem considerSet obj != 0) collect obj
RsSelectObjs selObjs
)
)
on btnSelAllIRefs pressed do
(
local selObjs = for obj in (RsSelToolGeneralRoll.objectList()) where isInternalRef obj collect obj
RsSelectObjs selObjs
)
on RsSelToolIrefsRoll open do (refresh())
)
-------------------------------------------------------------------------------------------
-- RsRefs Rollout
-------------------------------------------------------------------------------------------
-- Refs Selection Rollout
rollout RsSelToolRsRefsRoll "RsRefs"
(
-------------------------------------------------------------------------------
-- User Interface
-------------------------------------------------------------------------------
local attrBtnWidth = 90
group "Select by attribute:"
(
button btnSelRefs "Select RsRefs:" width:80 tooltip:"Select RsRef objects matching filter" across:2 align:#left
dropdownlist lstPropType "" tooltip:"Only select RsRef with specific attributes" align:#left pos:(btnSelRefs.pos + [84,0]) width:(RsSelToolRsRefsRoll.width - 110)
button btnSelNonRefs "Select Non-RsRef geometry" tooltip:"Select all non-RsRef geometry-objects" align:#left
)
group "Select by Source LOD Distance:"
(
checkBox chkScaleLodDist "Apply Prop Scales to Distances" checked:True align:#center across:2
checkBox chkDrawableDists "Use Drawable LOD-distances" checked:True align:#center
button btnSelLTLodDist "Select < Distance" width:attrBtnWidth offset:[-10,0] across:3 tooltip:"Select RsRefs with Source LOD Distance below or equal to value"
spinner spnLodDist "LOD Distance:" range:[0,10000,100] offset:[8,3]
button btnSelGTLodDist "Select > Distance" width:attrBtnWidth offset:[10,0] tooltip:"Select RsRefs with Source LOD Distance above or equal to value"
button btnListByLodDist "List Props by LOD Distance" tooltip:"Show RsRefs listed by LOD Distance" width:160
)
group "Select by Volume:"
(
checkBox chkScaleVols "Apply Prop Scales to Volumes" checked:True align:#center
button btnSelLTVol "Select < Volume" width:attrBtnWidth offset:[-10,0] across:3 tooltip:"Select RsRefs with volume below or equal to value"
spinner spnVolume "Volume (m^3):" range:[0,100000000,100] offset:[8,3]
button btnSelGTVol "Select > Volume" width:attrBtnWidth offset:[10,0] tooltip:"Select RsRefs with volume above or equal to value"
button btnListByVolume "List Props by Volume" tooltip:"Show RsRefs listed by volume" width:160
)
local clrBtnWidth = 100
group "Randomise RsRef Colours:"
(
button btnRefClrAll "All Different" width:clrBtnWidth across:3
button btnRefClrObjNames "By Objectname" width:clrBtnWidth
button btnRefClrFilename "By Filename" width:clrBtnWidth
)
group "Misc"
(
button btnSelForceBakeColRefs "Select veg for 'Force Bake Collision'" \
tooltip:"Selects non-scaled non-dynamic vegetation Rsrefs, which will need to have 'Face Bake Collision' attribute set"
)
-------------------------------------------------------------------------------
-- Functions
-------------------------------------------------------------------------------
-- Returns volume of prop:
fn getVolume obj scaled:chkScaleVols.checked =
(
local retVal = if (obj.refDef == undefined) then 0.0 else obj.refDef.volume
if scaled do (retVal = retVal * obj.scale.x * obj.scale.y * obj.scale.z)
return retVal
)
fn gtVol obj = (getVolume obj >= spnVolume.value)
fn ltVol obj = (getVolume obj <= spnVolume.value)
-- Returns lod-distance for prop:
fn getLodDist obj scaled:chkScaleLodDist.checked drawable:chkDrawableDists.checked =
(
local objRef = obj.refDef
local retVal = case of
(
(objRef == undefined):0.0
(drawable and (objRef.drawableLodRefs.count != 0)):(objRef.drawableLodRefs[objRef.drawableLodRefs.count].lodDistance)
Default:objRef.lodDistance
)
if (retVal == undefined) do (retVal = 0.0)
if scaled do (retVal = retVal * obj.scale.z)
return retVal
)
fn gtDist obj = ( getLodDist obj >= spnLodDist.value )
fn ltDist obj = ( getLodDist obj <= spnLodDist.value )
fn getRefObjs func: getVolumes:False getDistances:False doSelect:False drawable:chkDrawableDists.checked =
(
local propFilter
local dontFilter = true
local filtersList = RsRefFuncs.getFiltersList()
local filterNum = lstPropType.selection - 1
-- Get filter-function to use on RsRefs:
if (filterNum > 0) do
(
propFilter = filtersList[lstPropType.selection - 1].filter
dontFilter = false
)
local considerSet = RsSelToolGeneralRoll.objectList()
local selObjs = for obj in considerSet where (isRefObj obj) collect obj
if (not dontFilter) do
(
selObjs = for obj in selObjs where ((obj.refDef != undefined) and (propFilter obj.refDef)) collect obj
)
if (getDistances or getVolumes) and (RsRefFuncs.databaseActive toolName:"Object Selector") do
(
local refDefs = makeUniqueArray (for obj in selObjs collect obj.refDef)
case of
(
getDistances:
(
local distRefDefs = #()
if drawable do
(
-- Get last drawable-ref for each ref:
for refDef in refDefs where (refDef != undefined) do
(
append distRefDefs refDef
local drawables = refDef.drawableLodRefs
if (drawables.count != 0) do
(
append distRefDefs drawables[drawables.count]
)
)
)
RsRefFuncs.loadLodDistances distRefDefs
)
getVolumes:
(
RsRefFuncs.loadBoundingBoxes refDefs:refDefs
)
)
)
if (func != unsupplied) do
(
selObjs = for obj in selObjs where (func obj) collect obj
)
if doSelect do
(
RsSelectObjs selObjs
)
return selObjs
)
fn selNonRefs =
(
local considerSet = RsSelToolGeneralRoll.objectList attrClass:"Gta Object"
local selObjs = for obj in considerSet where not (isRefObj obj includeDelegates:true) collect obj
RsSelectObjs selObjs
)
-- Called when list is double-clicked:
fn listDoubleClick Sender Args =
(
if (args.RowIndex >= 0) do
(
local objName = Sender.Rows.Item[args.RowIndex].Cells.Item[2].Value
RsSelectObjs (getNodeByName objName all:True)
)
)
-------------------------------------------------------------------------------
-- Event Handlers
-------------------------------------------------------------------------------
on btnSelRefs pressed do (getRefObjs doSelect:True)
on btnSelNonRefs pressed do (selNonRefs())
on btnSelLTVol pressed do (getRefObjs doSelect:True func:ltVol getVolumes:True)
on btnSelGTVol pressed do (getRefObjs doSelect:True func:gtVol getVolumes:True)
on btnListByVolume pressed do
(
local refObjs = getRefObjs getVolumes:True
local dataList = for obj in refObjs collect #(getVolume obj, obj.name)
local listChks = #{}
if (dataList.count != 0) do (listChks = #{1..dataList.count})
local retVal = RsQueryBoxMultiBtn "[double-click to select]" title:"RsRef Prop Volumes" labels:#("Select", "Cancel") timeout:-1 listItems:dataList listCheckStates:listChks listTitles:#("Select?", "Volume (m^3)", "Object Name") listDoubleClickFunc:listDoubleClick
if (retVal == 1) do
(
RsSelectObjs (for n = listChks collect refObjs[n])
)
)
on btnSelLTLodDist pressed do (getRefObjs doSelect:True func:ltDist getDistances:True)
on btnSelGTLodDist pressed do (getRefObjs doSelect:True func:gtDist getDistances:True)
on btnListByLodDist pressed do
(
local refObjs = getRefObjs getDistances:True
local dataList = for obj in refObjs collect #(getLodDist obj, obj.name)
local listChks = #{}
if (dataList.count != 0) do (listChks = #{1..dataList.count})
local retVal = RsQueryBoxMultiBtn "[double-click to select]" title:"RsRef Prop LOD Distances" labels:#("Select", "Cancel") timeout:-1 listItems:dataList listCheckStates:listChks listTitles:#("Select?", "LOD Distance (m)", "Object Name") listDoubleClickFunc:listDoubleClick
if (retVal == 1) do
(
RsSelectObjs (for n = listChks collect refObjs[n])
)
)
fn setObjColours objLists =
(
local usedColours = #()
for objList in objLists do
(
local newClr = RsGetRandomColour excludes:usedColours
objList.wireColor = newClr
append usedColours newClr
)
)
on btnRefClrAll pressed do
(
local considerSet = RsSelToolGeneralRoll.objectList()
local useObjs = for obj in considerSet where isRsRef obj collect obj
local objLists = for obj in useObjs collect #(obj)
setObjColours objLists
)
on btnRefClrObjNames pressed do
(
local considerSet = RsSelToolGeneralRoll.objectList()
local useObjs = for obj in considerSet where isRsRef obj collect obj
local objNames = #()
local objLists = #()
for obj in useObjs do
(
local findNum = findItem objNames obj.objectName
if findNum == 0 do
(
append objNames obj.objectName
append objLists #()
findNum = objLists.count
)
append objLists[findNum] obj
)
setObjColours objLists
)
on btnRefClrFilename pressed do
(
local considerSet = RsSelToolGeneralRoll.objectList()
local useObjs = for obj in considerSet where isRsRef obj collect obj
local objFilenames = #()
local objLists = #()
for obj in useObjs do
(
local findNum = findItem objFilenames obj.filename
if findNum == 0 do
(
append objFilenames obj.filename
append objLists #()
findNum = objLists.count
)
append objLists[findNum] obj
)
setObjColours objLists
)
on btnSelForceBakeColRefs pressed do
(
if not RsRefFuncs.DatabaseActive toolName:"Object Selector" do
return False
-- Get rsrefs from scene
local considerSet = RsSelToolGeneralRoll.ObjectList()
local objs = for obj in considerSet where (IsKindOf obj RsrefObject) collect obj
-- Ignore non-vegetation props
objs = for obj in objs where (MatchPattern obj.filename pattern:"*vegetation*") collect obj
-- Ignore dynamics
objs = for obj in objs where not obj.refDef.isDynamic collect obj
-- Ignore scaled nodes
objs = for obj in objs where (Distance obj.scale [1,1,1] < 0.001) collect obj
-- Edit selection
RsSelectObjs objs
)
on RsSelToolRsRefsRoll open do
(
local propFilterNamesList = #("All")
join propFilterNamesList (for item in (RsRefFuncs.getFiltersList()) collect item.name)
lstPropType.items = propFilterNamesList
)
)
-- Refs Selection Rollout
Rollout RsSelToolRefsRoll "All Refs"
(
Group "Select floating props:"
(
Spinner SpnFloatDist "Float Distance:" Value:[0,10,0.01] Scale:0.01 FieldWidth:40 Align:#Right Tooltip:"Select Rsref/Internalref objects that are floating at least this far above a 'ground' object (a non-lodded, unreferenced, collisioned object) or aren't above any ground." Across:2
Button BtnSelFloaters "Select Props" Align:#Left Offset:[6,-3] Tooltip:"Select Rsref/Internalref objects that are floating too far above a 'ground' object (a non-lodded, unreferenced, collisioned object) or aren't above any ground."
)
-- GetFloatingProps:
-- 'FloatDist' is the minimum distance an object must be from a ground-object for it to be considered to be floating.
-- 'ConsiderSet' is the list of objects that prop-list will be restricted to.
fn GetFloatingProps FloatDist:0.01 ConsiderSet: =
(
-- Was a 'ConsiderSet' supplied?
local NoConsiderSet = (not isKindOf ConsiderSet Array)
local PropObjs = #()
local GroundObjs = #()
-- Process scene's geometry-list:
for Obj in Geometry do
(
case of
(
-- Skip objects that have lod-children:
((RsGetLodChildren Obj).Count != 0):
() -- Do nothing
-- Collect ref-objects:
((isRefObj Obj includeDelegates:False) or (isInternalRef Obj)):
(
-- Only collect objects found in the ConsiderSet, if given:
if NoConsiderSet or (FindItem ConsiderSet Obj != 0) do
(
append PropObjs Obj
)
)
-- Skip objects that don't have collision:
(
local NoCollision = True
for Child in Obj.Children while NoCollision do
(
NoCollision = (GetAttrClass Child != "Gta Collision")
)
-- Returns 'True' if obj has no collision-children
NoCollision
):
() -- Do nothing
-- Collect objects that props will be tested against:
Default:
(
append GroundObjs Obj
)
)
)
-- Return empty array if no props were found:
if (PropObjs.Count == 0) do return #()
-- Return all props if no ground was found
if (PropObjs.Count == 0) do return PropObjs
-- Collect list of objects, plus a point on the top of each prop's bounding-box:
struct PropData (Obj, TopPos, Height, MinFloatDist, IsFloating = True)
local PropInfoList = for PropObj in PropObjs collect
(
PropData Obj:PropObj TopPos:[PropObj.Pos.X, PropObj.Pos.Y, PropObj.Max.Z] Height:(PropObj.Max.Z - PropObj.Min.Z)
)
-- Process ground-objects in turn:
for GroundObj in GroundObjs do
(
local GroundMin = GroundObj.Min
local GroundMax = GroundObj.Max
-- Find props that may be above this ground-object:
-- (skip props that have already been confirmed as grounded)
local CheckProps = for Item in PropInfoList where Item.IsFloating collect
(
local PropPos = Item.TopPos
-- Is prop above base of ground's bounding-box?
local CollectObj = case of
(
(PropPos.Z < GroundMin.Z):False
(PropPos.X < GroundMin.X):False
(PropPos.X > GroundMax.X):False
(PropPos.Y < GroundMin.Y):False
(PropPos.Y > GroundMax.Y):False
Default:True
)
-- Collect item is prop was over the base of ground-object's bounding-box:
if CollectObj then Item else DontCollect
)
-- If ground potentially has objects floating over it, test them against its surface:
if (CheckProps.Count != 0) do
(
-- Build RayMesh for this ground-object:
local RayMesh = RayMeshGridIntersect()
RayMesh.Initialize 10
RayMesh.AddNode GroundObj
RayMesh.BuildGrid()
for PropItem in CheckProps do
(
-- Item.IsFloating = False
-- Cast ray down to see if ground is nearby:
local RayHits = RayMesh.IntersectRay (PropItem.TopPos) [0,0,-1] True
-- Check ray-hits against prop's minimum-float distance:
if (RayHits != 0) do
(
for HitIdx = 1 to RayHits do
(
local HitDist = (RayMesh.GetHitDist HitIdx)
-- Collect distance if it's closer than previously-found hits:
if (PropItem.MinFloatDist == undefined) or (HitDist < PropItem.MinFloatDist) do
(
PropItem.MinFloatDist = HitDist
)
)
-- Set prop as non-floating if its float-distance is less than 'FloatDist',
-- or if its bounding-box is embedded in the ground:
PropItem.IsFloating = ((PropItem.MinFloatDist - PropItem.Height) > FloatDist)
)
)
--format "%: %\n" GroundObj.Name CheckProps.count-- (CheckProps as string)
)
)
local FloatProps = for PropItem in PropInfoList where (PropItem.IsFloating) collect PropItem.Obj
return FloatProps
)
on BtnSelFloaters pressed do
(
-- Set 'ConsiderSet' to unsupplied if we don't want to bother filtering to selection:
local ConsiderSet = if (RsSelToolGeneralRoll.IsFromSelected()) then (RsSelToolGeneralRoll.ObjectList()) else Unsupplied
-- Find props floating over scenery:
local FloatingProps = GetFloatingProps FloatDist:SpnFloatDist.Value ConsiderSet:ConsiderSet
Clearselection()
Select FloatingProps
)
)
-------------------------------------------------------------------------------------------
-- Lights Rollout
-------------------------------------------------------------------------------------------
rollout RsSelToolLightsRoll "Lights"
(
button btnSelDay "Select Day Lights" align:#left across:3
button btnSelNight "Select Night Lights" align:#centre offset:[-24,0]
button btnSelShadows "Select Lights With Shadows" align:#right
button btnSelVolume "Select Vol Lights > Multiplier:" align:#left across:2
spinner spnMultiplier "" range:[0,1000,0] align:#left width:60 offset:[-26,2]
button btnSelAttenLess "Select Attenuation <" align:#left across:3
spinner spnAttenuation "" range:[0,1000,0] align:#left width:60 offset:[-2,2]
button btnSelAttenMore "Select Attenuation >" align:#left offset:[-56,0]
button btnRename "Rename Lights" align:#left tooltip:"Rename lights to include Day/Night/Shadow labels"
local lightClassStructs
-- Lights have multiple classes, this allows quick access to indexes for both:
fn setClassStructs =
(
struct lightIdxsStruct
(
class, objs = #(), idxDay, idxNight, idxStatShad, idxDynShad, idxVolDraw, idxVolSize
)
lightClassStructs = for lightClass in #("Gta Light", "Gta LightPhoto") collect
(
local idxStruct = lightIdxsStruct class:lightClass
idxStruct.idxDay = getattrindex lightClass "Day"
idxStruct.idxNight = getattrindex lightClass "Night"
idxStruct.idxStatShad = getattrindex lightClass "Cast Static Object Shadow"
idxStruct.idxDynShad = getattrindex lightClass "Cast Dynamic Object Shadow"
idxStruct.idxVolDraw = getattrindex lightClass "Volume Drawing"
idxStruct.idxVolSize = getattrindex lightClass "Volume Size"
idxStruct
)
return lightClassStructs
)
-- Get objects by light-class:
fn getLightStructs =
(
local considerList = RsSelToolGeneralRoll.objectList()
for item in lightClassStructs do (item.objs = #())
for obj in considerList do
(
local notLight = true
local objClass = getattrclass obj
for item in lightClassStructs while notLight where (objClass == item.class) do
(
append item.objs obj
notLight = false
)
)
return lightClassStructs
)
on btnSelDay pressed do
(
getLightStructs()
local selObjs = #()
for item in lightClassStructs do
(
local idx = item.idxDay
local objs = for obj in item.objs where (getattr obj idx == true) collect obj
join selObjs objs
)
RsSelectObjs selObjs
)
on btnSelNight pressed do
(
getLightStructs()
local selObjs = #()
for item in lightClassStructs do
(
local idx = item.idxNight
local objs = for obj in item.objs where (getattr obj idx == true) collect obj
join selObjs objs
)
RsSelectObjs selObjs
)
on btnSelShadows pressed do
(
getLightStructs()
local selObjs = #()
for item in lightClassStructs do
(
local idxA = item.idxStatShad
local idxB = item.idxDynShad
local objs = for obj in item.objs where (getattr obj idxA == true) or (getattr obj idxB == true) collect obj
join selObjs objs
)
RsSelectObjs selObjs
)
on btnSelVolume pressed do
(
getLightStructs()
local selObjs = #()
local spnVal = spnMultiplier.value
for item in lightClassStructs do
(
local idxA = item.idxVolDraw
local idxB = item.idxVolSize
local objs = for obj in item.objs where (getattr obj idxA == true) or (getattr obj idxB > spnVal) collect obj
join selObjs objs
)
RsSelectObjs selObjs
)
on btnSelAttenLess pressed do
(
getLightStructs()
local selObjs = #()
local spnVal = spnAttenuation.value
for item in lightClassStructs do
(
local objs = for obj in item.objs where (hasProperty obj "farattenend") and (obj.farattenend < spnVal) collect obj
join selObjs objs
)
RsSelectObjs selObjs
)
on btnSelAttenMore pressed do
(
getLightStructs()
local selObjs = #()
local spnVal = spnAttenuation.value
for item in lightClassStructs do
(
local objs = for obj in item.objs where (hasProperty obj "farattenend") and (obj.farattenend > spnVal) collect obj
join selObjs objs
)
RsSelectObjs selObjs
)
on btnRename pressed do
(
getLightStructs()
for item in lightClassStructs do
(
for obj in item.objs do
(
local objName = "Light"
if getattr obj item.idxDay do (objName += "_day")
if getattr obj item.idxNight do (objName += "_night")
if (getattr obj item.idxStatShad) or (getattr obj item.idxDynShad) do (objName += "_shadow")
objName += "_"
obj.name = (uniqueName objName)
)
)
)
on RsSelToolLightsRoll open do
(
setClassStructs()
)
)
rollout RsSelToolShaderRoll "Shaders:"
(
-------------------------------------------------------------------------------
-- UI
-------------------------------------------------------------------------------
button btnSel "Select objs using:" across:3 align:#left
dropdownlist lstAvailableShaders width:190 offset:[-15,0]
button btnRefresh "Refresh" align:#right
-------------------------------------------------------------------------------
-- Event Handlers
-------------------------------------------------------------------------------
fn ObjectList =
(
RsSelToolGeneralRoll.ObjectList attrClass:"Gta Object"
)
fn refresh =
(
-- Get selection from selection rollout, get shaders off those objects
local mapShaders = RsGetShaderListForObjects (ObjectList())
sort mapShaders
lstAvailableShaders.items = mapShaders
)
-- Called whenever RsSelToolGeneralRoll's 'Select From' option is changed:
fn SelOptionChanged =
(
Refresh()
)
on btnSel pressed do
(
PushPrompt "Searching for shader..."
local considerList = RsSelToolGeneralRoll.objectList()
local shaderName = lstAvailableShaders.selected
local selObjs = #()
-- For each object find objects that use selected shader
for obj in considerList do
(
local ObjShaders = RsGetShaderListForObjects #(Obj)
if (FindItem ObjShaders ShaderName != 0) do
(
append selObjs obj
)
)
RsSelectObjs selObjs
PopPrompt()
)
on btnRefresh pressed do
(
refresh()
)
on RsSelToolShaderRoll open do
(
refresh()
)
)
rollout RsSelToolMemoryRoll "Memory"
(
-------------------------------------------------------------------------------
-- Data
-------------------------------------------------------------------------------
-------------------------------------------------------------------------------
-- UI
-------------------------------------------------------------------------------
edittext edtMemorySize "Memory (KB):" width:180 across:2
checkbox chkXRefsIncl "Include Refs" align:#right offset:[0,2] checked:false
local btnWidth = 150
group "Select Objects:"
(
button btnSelMemGTEQ "Model-size >= [Memory]" width:btnWidth align:#right offset:[-2,0] across:2
button btnSelMemLTEQ "Model-size <= [Memory]" width:btnWidth align:#left offset:[2,0]
button btnSelTxdGTEQ "Txd-size >= [Memory]" width:btnWidth align:#right offset:[-2,0] across:2
button btnSelTxdLTEQ "Txd-size <= [Memory]" width:btnWidth align:#left offset:[2,0]
button btnSelGTEQ "Model + Txd >= [Memory]" width:btnWidth align:#right offset:[-2,0] across:2
button btnSelLTEQ "Model + Txd <= [Memory]" width:btnWidth align:#left offset:[2,0]
progressbar barProgress
)
-------------------------------------------------------------------------------
-- Functions
-------------------------------------------------------------------------------
-- Get mem size from edit UI controls
fn getMemSize = (
memSize = 0
try
(
if ( edtMemorySize.text as integer != undefined ) then
memSize = ( edtMemorySize.text as integer ) * 1024
)
catch ()
memSize
)
fn getObjMemSizes memSize:true txdSize:true =
(
local considerSet = RsSelToolGeneralRoll.objectList()
local objSizes = for obj in considerSet collect (dataPair obj:obj size:0)
local getSizes = #()
if memSize do
(
join getSizes (RsAssetDrawableMemSize considerSet inclRefs:chkXRefsIncl.checked progress:barProgress)
)
if txdSize do
(
join getSizes (RsAssetDrawableMemSize considerSet inclRefs:chkXRefsIncl.checked progress:barProgress)
)
for item in getSizes do
(
local objNum = findItem considerSet item.obj
objSizes[objNum].size += item.size
)
return objSizes
)
-------------------------------------------------------------------------------
-- Event Handlers
-------------------------------------------------------------------------------
-------------------------------------------------------------------------------
-- Drawable
-------------------------------------------------------------------------------
on btnSelMemGTEQ pressed do
(
local memSize = getMemSize()
if ( undefined == memSize or 0 == memSize ) then
(
messageBox ("Invalid memory size of " + memSize as string + ". Enter a value in the memory edit box.") title:"Invalid value"
return false
)
local considerSet = getObjMemSizes memSize:true txdSize:false
local selset = for item in considerSet where (item.size != 0) and (item.size >= memSize) collect item.obj
RsSelectObjs selSet
)
on btnSelMemLTEQ pressed do
(
local memSize = getMemSize()
if ( undefined == memSize or 0 == memSize ) then
(
messageBox ("Invalid memory size of " + memSize as string + ". Enter a value in the memory edit box.") title:"Invalid value"
return false
)
local considerSet = getObjMemSizes memSize:true txdSize:false
local selset = for item in considerSet where (item.size != 0) and (item.size <= memSize) collect item.obj
RsSelectObjs selSet
)
-------------------------------------------------------------------------------
-- TXD
-------------------------------------------------------------------------------
on btnSelTxdGTEQ pressed do
(
local memSize = getMemSize()
if ( undefined == memSize or 0 == memSize ) then
(
messageBox ("Invalid memory size of " + memSize as string + ". Enter a value in the memory edit box.") title:"Invalid value"
return false
)
local considerSet = getObjMemSizes memSize:false txdSize:true
local selset = for item in considerSet where (item.size != 0) and (item.size >= memSize) collect item.obj
RsSelectObjs selSet
)
on btnSelTxdLTEQ pressed do
(
local memSize = getMemSize()
if ( undefined == memSize or 0 == memSize ) then
(
messageBox ("Invalid memory size of " + memSize as string + ". Enter a value in the memory edit box.") title:"Invalid value"
return false
)
local considerSet = getObjMemSizes memSize:false txdSize:true
local selset = for item in considerSet where (item.size != 0) and (item.size <= memSize) collect item.obj
RsSelectObjs selSet
)
-------------------------------------------------------------------------------
-- Drawable + Txd
-------------------------------------------------------------------------------
on btnSelGTEQ pressed do
(
local memSize = getMemSize()
if ( undefined == memSize or 0 == memSize ) then
(
messageBox ("Invalid memory size of " + memSize as string + ". Enter a value in the memory edit box.") title:"Invalid value"
return false
)
local considerSet = getObjMemSizes memSize:true txdSize:true
local selset = for item in considerSet where (item.size != 0) and (item.size >= memSize) collect item.obj
RsSelectObjs selSet
)
on btnSelLTEQ pressed do
(
local memSize = getMemSize()
if ( undefined == memSize or 0 == memSize ) then
(
messageBox ("Invalid memory size of " + memSize as string + ". Enter a value in the memory edit box.") title:"Invalid value"
return false
)
local considerSet = getObjMemSizes memSize:true txdSize:true
local selset = for item in considerSet where (item.size != 0) and (item.size <= memSize) collect item.obj
RsSelectObjs selSet
)
)
--//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-- COLLISION
--//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
rollout RsSelToolCollClassRoll "Collision Classes:"
(
button btnSel "Select Objects:" align:#left
dropdownlist lstCollClasses "" width:270 align:#right offset:[0,-26]
label lblAlsoFilters "v Also used to filter other tools v"
local colClasses = #(ColMesh, ColBox, ColSphere, ColCylinder, ColCapsule)
local colClassItems = #(
dataPair name:"All" classes:#{1..5},
dataPair name:"* Collision Mesh" classes:#{1},
dataPair name:"* Primitives" classes:#{2..5},
dataPair name:" * Box" classes:#{2},
dataPair name:" * Sphere" classes:#{3},
dataPair name:" * Cylinder" classes:#{4},
dataPair name:" * Capsule" classes:#{5}
)
fn getSelClasses =
(
local selNum = lstCollClasses.selection
for classNum = colClassItems[selNum].classes collect colClasses[classNum]
)
fn objectList =
(
local selClasses = getSelClasses()
local considerSet = RsSelToolGeneralRoll.objectList attrClass:"Gta Collision"
for obj in considerSet where (findItem selClasses (classOf obj) != 0) collect obj
)
on btnSel pressed do
(
RsSelectObjs (objectList())
)
on RsSelToolCollClassRoll open do
(
lstCollClasses.items = for item in colClassItems collect item.name
)
)
rollout RsSelToolCollGrpRoll "Collision Group:"
(
local groupNames, objLists
button buttonTxdGroup "Select by:" offset:[0,0] align:#left across:3
dropdownlist listCollGroup width:220 offset:[-40, 0]
button btnRefresh "Refresh" align:#left offset:[65, 0]
button buttonColourTxdGroup "Colour wire" align:#left offset:[0,0] across:3
button buttonAppend "Append To Selected:" offset:[-40,0]
edittext appendVal "" fieldWidth:93 offset:[-40,2]
groupbox grpBorder width:290 height:63 offset:[76, -63]
fn refresh =
(
local prevSel = listCollGroup.selected
objLists = #()
groupNames = RsGetUniqueNames "Collision Group" objListsOut:objLists
listCollGroup.items = groupNames
listCollGroup.selection = findItem groupNames prevSel
)
on buttonColourTxdGroup pressed do
(
refresh()
RsColourByFieldValueString objLists
)
on buttonTxdGroup pressed do
(
refresh()
local selGrp = listCollGroup.selection
local selObjs = if (selGrp == 0) then #() else
(
local considerSet = RsSelToolGeneralRoll.objectList()
for obj in objLists[selGrp] where (findItem considerSet obj != 0) collect obj
)
RsSelectObjs selObjs
)
on buttonAppend pressed do
(
RsAppendToValueString "Collision Group" appendVal.text
refresh()
)
on btnRefresh pressed do (refresh())
on RsSelToolCollGrpRoll open do (refresh())
)
rollout RsSelToolCollFlagRoll "Collision Flags:"
(
-------------------------------------------------------------------------------
-- Constants
-------------------------------------------------------------------------------
local idxCollType = getAttrIndex "Gta Collision" "Coll Type"
groupBox grpFlagsA "Object/Material Attributes:" height:140 width:(RsSelToolCollFlagRoll.width - 8) offset:[-9,0]
button btnRefreshLists "Refresh:" tooltip:"Refresh lists to match values used in scene" offset:[-2, 27 - grpFlagsA.height] height:23 across:3 align:#left
dropDownList lstSurfTypes "Surface Type:" offset:[-63, 10 - grpFlagsA.height] width:((RsSelToolCollFlagRoll.width / 2) - 42)
dropDownList lstProcTypes "Procedural Type:" offset:[2, 10 - grpFlagsA.height] width:((RsSelToolCollFlagRoll.width / 2) - 42) align:#right
checkbox chkStairs "Stairs" across:3 --offset:[0, 12 - grpFlagsA.height]
checkbox chkNonCover "Not Cover" --offset:[0, 12 - grpFlagsA.height]
checkbox chkSeeThrough "See Through" --offset:[0, 12 - grpFlagsA.height]
checkbox chkNonClimable "Non Climable" across:3
checkbox chkPath "Path"
checkbox chkShootThrough "Shoot Through"
checkbox chkNonCameraCollidable "Non Camera Collide" across:3
checkbox chkNoDecal "No Decal"
checkBox chkDUMMYA "DUMMY" visible:false
checkbox chkUseProcTint "Use Procedural Tint" across:3
checkbox chkIsClothColl "Is Cloth Collision"
checkBox chkDUMMYB "DUMMY" visible:false
-- Attribute-flag controls, and their matching index in RsCollisionAttrs:
local attrCtrls =
#(
dataPair ctrl:chkStairs idx:(findItem RsCollisionAttrs "Stairs"),
dataPair ctrl:chkNonClimable idx:(findItem RsCollisionAttrs "Non Climbable"),
dataPair ctrl:chkSeeThrough idx:(findItem RsCollisionAttrs "See Through"),
dataPair ctrl:chkShootThrough idx:(findItem RsCollisionAttrs "Shoot Through"),
dataPair ctrl:chkNonCover idx:(findItem RsCollisionAttrs "Does Not Provide Cover"),
dataPair ctrl:chkPath idx:(findItem RsCollisionAttrs "Path"),
dataPair ctrl:chkNonCameraCollidable idx:(findItem RsCollisionAttrs "Non Camera Collidable"),
dataPair ctrl:chkNoDecal idx:(findItem RsCollisionAttrs "No Decal"),
dataPair ctrl:chkUseProcTint idx:(findItem RsCollisionAttrs "Use Procedural Tint"),
dataPair ctrl:chkIsClothColl idx:(findItem RsCollisionAttrs "Is Cloth Collision")
)
groupBox grpFlagsB "Object Types:" height:188 width:grpFlagsA.width pos:(grpFlagsA.pos + [0, grpFlagsA.height + 2])
-- TYPE-FILTER BUTTON-NAMES MUST MATCH FLAG-NAMES!
-- (case-insensitive, underscores can be spaces)
checkBox chkMover "Mover" across:3 offset:[0, 12 - grpFlagsB.height]
checkBox chkWeapon "Weapons" offset:[0, 12 - grpFlagsB.height]
checkBox chkRiver "River" offset:[0, 12 - grpFlagsB.height]
checkBox chkFoliage "Foliage" across:3
checkBox chkHorse "Horse"
checkBox chkCover "Cover"
checkBox chkVehicle "Vehicle" across:3
checkBox chkStairSlope "Stair Slope"
checkBox chkDeepMatSurf "Deep Material Surface"
checkBox chkMaterial "Material"
-- List of controls used for filtering by collision-type flags:
local typeCtrls = #(chkMover, chkWeapon, chkRiver, chkFoliage, chkHorse, chkCover, chkVehicle, chkStairSlope, chkDeepMatSurf, chkMaterial)
listBox colObjTypePresetList "Presets: (Double-Click to Select)" height:5 offset:[0,-2] selection:0
label lblAnyAllFlags "Select objects with:" across:2 align:#left offset:[-4,8]
radioButtons btnsAnyAllFlags "" labels:#("ANY flags", "ALL flags") default:1 pos:(lblAnyAllFlags.pos + [98,0])
button btnSelObjects "Select Matching Objects" offset:[0,0] width:150 across:2
button btnSelFaces "Select Matching Faces" offset:[0,0] width:150
button btnSelMovObjs "Select 'Mover'" tooltip:"Select non-Weapon Mover-collision" across:3 offset:[-2,0]
button btnSelMovWepObjs "Select 'Mover & Weapons'" tooltip:"Select Mover&Weapons-collision" offset:[-6,0]
button btnSelWepObjs "Select 'Weapons'" tooltip:"Select non-Mover Weapons-collision" offset:[-3,0]
-------------------------------------------------------------------------------
-- Functions
-------------------------------------------------------------------------------
fn setGrpsEnabled =
(
grpFlagsA.enabled = False
for item in attrCtrls while not grpFlagsA.enabled do
(
grpFlagsA.enabled = item.ctrl.checked
)
grpFlagsB.enabled = False
for ctrl in typeCtrls while not grpFlagsB.enabled do
(
grpFlagsB.enabled = ctrl.checked
)
)
on chkStairs changed state do (setGrpsEnabled())
on chkNonCover changed state do (setGrpsEnabled())
on chkSeeThrough changed state do (setGrpsEnabled())
on chkNonClimable changed state do (setGrpsEnabled())
on chkPath changed state do (setGrpsEnabled())
on chkShootThrough changed state do (setGrpsEnabled())
on chkNonCameraCollidable changed state do (setGrpsEnabled())
on chkNoDecal changed state do (setGrpsEnabled())
on chkUseProcTint changed state do (setGrpsEnabled())
on chkIsClothColl changed state do (setGrpsEnabled())
on chkMover changed state do (setGrpsEnabled())
on chkWeapon changed state do (setGrpsEnabled())
on chkRiver changed state do (setGrpsEnabled())
on chkFoliage changed state do (setGrpsEnabled())
on chkHorse changed state do (setGrpsEnabled())
on chkCover changed state do (setGrpsEnabled())
on chkVehicle changed state do (setGrpsEnabled())
on chkStairSlope changed state do (setGrpsEnabled())
on chkDeepMatSurf changed state do (setGrpsEnabled())
on chkMaterial changed state do (setGrpsEnabled())
-- Set surface/procedural-type lists to show values used in scene:
fn refreshLists =
(
local colObjs = for obj in objects where (getAttrClass obj == "Gta Collision") collect obj
local surfList = #()
local procList = #()
for obj in colObjs do
(
-- For collision-meshes, check materials; for primitives, check attributes
if (isKindOf obj Col_Mesh) then
(
-- Get list of collision-materials on object:
local objColMats = RSgetMatClassSubMats obj.material RexBoundMtl
local objSurfs = for mat in objColMats collect (toUpper (RexGetCollisionName mat))
local objProcs = for mat in objColMats collect (toUpper (RexGetProceduralName mat))
join surfList objSurfs
join procList objProcs
)
else
(
-- There's no Procedural Type attribute for primitives...
append surfList (toUpper (getAttr obj idxCollType))
)
)
surfList = makeUniqueArray surfList
procList = makeUniqueArray procList
for thisArray in #(surfList, procList) do
(
sort thisArray
insertItem "ANY" thisArray 1
)
lstSurfTypes.items = surfList
lstProcTypes.items = procList
return OK
)
-- Get flag-integer from current attribute-checkbox states:
fn getAttrCtrlFlags justMat:false =
(
local colFlags = 0
-- "justMat" limits flagging to material-flags:
for ctrlNum = 1 to attrCtrls.count where (not justMat) or (ctrlNum <= RsCollisionFlags.count) do
(
local item = attrCtrls[ctrlNum]
colFlags = bit.set colFlags item.idx item.ctrl.state
)
return colFlags
)
-- List the collision Geometry attributes
fn getGtaCollisionGeoAttributes obj flags matchAll:false =
(
fn getCollGeoAttr obj attr = (
theIdx = GetAttrIndex "Gta Collision" attr
theReturn = (GetAttr obj theIdx)
theReturn
)
local hasFlag = false
local geoFlags = #(
datapair idx:1 attrib:"Stairs",
datapair idx:2 attrib:"Non Climable",
datapair idx:3 attrib:"See Through",
datapair idx:9 attrib:"No Decal"
)
local flagArray = #()
for i in geoFlags do
(
flagVal = bit.get flags i.idx
if flagVal == true then
(
if (getCollGeoAttr obj i.attrib) == true then append flagArray 1 else append flagArray 0
)
)
if finditem flagArray 1 != 0 then hasFlag = true
if matchAll == true then if finditem flagArray 0 != 0 then hasFlag = false
hasFlag
)
-- Returns bitarray of object-numbers for matching objects:
fn filterByCollAttrs objs matchAll:false =
(
local flags = getAttrCtrlFlags()
local retVal = #{}
retVal.count = objs.count
if (flags != 0) do
(
for n = 1 to objs.count do
(
local obj = objs[n]
if classof obj == Col_Mesh then retVal[n] = (RsDoesObjectUseFlags obj flags matchAll:matchAll)
else retVal[n] = (getGtaCollisionGeoAttributes obj flags matchAll:matchAll)
)
)
return retVal
)
-- Returns bitarray of object-numbers for matching objects:
fn filterByCollTypes objs matchAll:false =
(
local retVal = #{}
retVal.count = objs.count
-- Build string containing button-names:
local typeFlagsString = ""
for ctrl in typeCtrls do
(
if ctrl.state do
(
typeFlagsString += ctrl.text
typeFlagsString += "|"
)
)
-- Generate flags-bitarray from button-names string:
local getTypes = (gRsCollTypes.getFlagNumsFromString typeFlagsString)
--format "getTypes: %\n" (getTypes as string)
if (getTypes.numberSet != 0) do
(
for n = 1 to objs.count do
(
local obj = objs[n]
-- Get type-flags used by object, and match against filter:
local objTypes = gRsCollTypes.getObjFlagNums obj
local matchedCount = (getTypes * objTypes).numberSet
--format "getObjFlagNums: %\n" (objTypes as string)
local isMatch = true
if matchAll then
(
-- Did all reported object-flags match against 'getTypes'?
isMatch = (matchedCount == objTypes.numberSet)
)
else
(
-- Did any of object's flags match 'getTypes'?
isMatch = (matchedCount != 0)
)
if isMatch do
(
retVal[n] = true
)
)
)
return retVal
)
-- Returns bitarray of object-numbers for objects with matching surface OR procedural type
-- Attributes are checked for collision-primitives; materials are checked for collsion meshes.
fn filterByProcSurfType objs mode:#surf =
(
local retVal = #{}
retVal.count = objs.count
local doSurfMatch = (mode == #surf)
local matchCtrl = if doSurfMatch then lstSurfTypes else lstProcTypes
if (matchCtrl.selection <= 1) do return retVal
-- Get selected surface/procedural-type from control:
local matchVal = matchCtrl.selected
-- Set appropriate material-command for this mode:
local getMatVal = if doSurfMatch then RexGetCollisionName else RexGetProceduralName
for n = 1 to objs.count do
(
local obj = objs[n]
-- For collision-meshes, check materials; for primitives, check attributes
if (isKindOf obj Col_Mesh) then
(
-- Get list of collision-materials on object:
local objColMats = RSgetMatClassSubMats obj.material RexBoundMtl
for mat in objColMats while (not retVal[n]) do
(
local matVal = getMatVal mat
if (matchPattern matVal pattern:matchVal) do
(
retVal[n] = True
)
)
)
else
(
-- There's no Procedural Type attribute for primitives...
if doSurfMatch do
(
-- Does Collision Type value match?
local getVal = getAttr obj idxCollType
if (matchPattern getVal pattern:matchVal) do
(
retVal[n] = True
)
)
)
)
return retVal
)
-------------------------------------------------------------------------------
-- Events
-------------------------------------------------------------------------------
on btnRefreshLists pressed do
(
refreshLists()
)
on btnSelObjects pressed do
(
-- Get collision-objects, filtered by class:
local considerSet = RsSelToolCollClassRoll.objectList()
local matchAll = (btnsAnyAllFlags.state == 2)
-- Only filter attribs/types if any of their flags are ticked:
setGrpsEnabled()
local doAttribFilter = grpFlagsA.enabled
local doTypeFilter = grpFlagsB.enabled
local doSurfFilter = (lstSurfTypes.selection > 1)
local doProcFilter = (lstProcTypes.selection > 1)
local flagMatches = if doAttribFilter then (filterByCollAttrs considerSet matchAll:matchAll) else #{}
local typeMatches = if doTypeFilter then (filterByCollTypes considerSet matchAll:matchAll) else #{}
local surfMatches = if doSurfFilter then (filterByProcSurfType considerSet mode:#surf) else #{}
local procMatches = if doProcFilter then (filterByProcSurfType considerSet mode:#proc) else #{}
-- Get list of used match-lists - inactive searches will not be included in combined match:
local useMatchLists = #(doAttribFilter, doTypeFilter, doSurfFilter, doProcFilter)
local matchLists = #(flagMatches, typeMatches, surfMatches, procMatches)
matchLists = for i = 1 to matchLists.count where useMatchLists[i] collect matchLists[i]
local combinedMatches = #{}
combinedMatches.count = considerSet.count
local firstFilter = True
for thisList in matchLists do
(
if matchAll and (not firstFilter) then
(
combinedMatches *= thisList
)
else
(
combinedMatches += thisList
)
firstFilter = False
)
/*
if doAttribFilter do (format "Flag Matches: %\n" flagMatches)
if doTypeFilter do (format "Type-Flag Matches: %\n" typeMatches)
if doSurfFilter do (format "Surface Type Matches: %\n" surfMatches)
if doProcFilter do (format "Procedural Type Matches: %\n" procMatches)
format "Combined Matches: %\n\n" combinedMatches
*/
local selectlist = for n = combinedMatches collect considerSet[n]
RsSelectObjs selectlist
)
fn selMovWepObjs mover:True weapons:True =
(
-- Get collision-objects, filtered by class:
local considerSet = RsSelToolCollClassRoll.objectList()
local selObjs = for obj in considerSet where (gRsCollTypes.hasMoverWeaponsCombo obj mover:mover weapons:weapons) collect obj
RsSelectObjs selObjs
)
on btnSelMovObjs pressed do (selMovWepObjs mover:True weapons:False)
on btnSelWepObjs pressed do (selMovWepObjs mover:False weapons:True)
on btnSelMovWepObjs pressed do (selMovWepObjs mover:True weapons:True)
--
on btnSelFaces pressed do
(
if selection.count != 1 do
(
messagebox "Can only be run on one object" title:"Selection error"
return False
)
obj = selection[1]
-- Does this object have collision materials?
local colMats = #()
if (isProperty obj #material) do
(
colMats = RSgetMatClassSubMats obj.material RexBoundMtl
)
if (colMats.count == 0) do
(
messagebox "Object must have collision materials applied to it!" title:"Selection error"
return False
)
local surfType = undefined
local procType = undefined
if (lstSurfTypes.selection > 1) do
(
surfType = lstSurfTypes.selected
)
if (lstProcTypes.selection > 1) do
(
procType = lstProcTypes.selected
)
local flagval = getAttrCtrlFlags justMat:true
if (flagval == 0) and (surfType == undefined) and (procType == undefined) do
(
messagebox "Cancelling: No material-flags selected." title:"Flags error"
return false
)
-- No need to convert if this is an editable mesh/poly:
if (isKindOf obj Col_Mesh) do
(
if not querybox "Object will be converted to an Editable Mesh.\n\nCarry on?" title:"Convert to editable?" do
(
return False
)
)
local matchAll = (btnsAnyAllFlags.state == 2)
undo "select collision-faces" on
(
select obj -- needed to allow correct collision-convert undo
RsSetFacesByFlags obj flagval surfType:surfType procType:procType matchAll:matchAll
)
)
on colObjTypePresetList doubleClicked selItem do
(
-- Get list of flag-names to tick:
local selPresets = filterString (toLower colObjTypePresetList.selected) "|"
-- FOR REF, FROM ABOVE: typeCtrls = #(chkMover, chkWeapon, chkRiver, chkFoliage, chkHorse, chkCover, chkVehicle, chkStairSlope, chkDeepMatSurf, chkMaterial)
local ctrlNames = for ctrl in typeCtrls collect ctrl.text
for n = 1 to typeCtrls.count do
(
local ctrlFlagName = toLower typeCtrls[n].text
typeCtrls[n].checked = (findItem selPresets ctrlFlagName != 0)
)
setGrpsEnabled()
)
on RsSelToolCollFlagRoll open do
(
-- Get flag-preset names from global list:
local flagPresets = for item in gRsCollTypes.typesList collect item.name
-- Remove any bracketed comments:
flagPresets = for item in flagPresets collect (filterString item "()" splitEmptyTokens:true)[1]
colObjTypePresetList.items = flagPresets
refreshLists()
setGrpsEnabled()
)
)
-- Collision Faces Selection Utility
rollout RsSelToolCollVolRoll "Collision Faces"
(
-------------------------------------------------------------------------------
-- Constants
-------------------------------------------------------------------------------
local fEPSILON = 0.0001
-------------------------------------------------------------------------------
-- UI
-------------------------------------------------------------------------------
button btnLT "Select Faces <= Ratio" width:120 across:3 tooltip:"Select colmeshes containing faces with smaller size-ratios"
spinner spnRatio "Ratio:" range:[0.01, 200.0, 40.0] type:#float width:100 offset:[-20,2]
button btnGT "Select Faces >= Ratio" width:120 tooltip:"Select colmeshes containing faces with greater size-ratios"
-------------------------------------------------------------------------------
-- Functions
-------------------------------------------------------------------------------
--
-- name: localMatrix
-- desc: Returns the transformation matrix which will transform a point from
-- world into the coordinate system derived from p1-p2 and p1-p3
--
fn localMatrix p1 p2 p3 = (
local v1 = normalize (p2 - p1)
local v3 = normalize (cross v1 (normalize (p3 - p1)))
local v2 = normalize (cross v3 v1)
return matrix3 v1 v2 v3 p1
)
--
-- name: RoundVecZero
-- desc: Round float vector's components to zero if they are almost zero - as
-- defined by fEPSILON constant above.
--
fn RoundVecZero v = (
local p = v
if ( p.x < fEPSILON ) and ( p.x > -fEPSILON ) then
p.x = 0.0
if ( p.y < fEPSILON ) and ( p.y > -fEPSILON ) then
p.y = 0.0
if ( p.z < fEPSILON ) and ( p.z > -fEPSILON ) then
p.z = 0.0
return p
)
-------------------------------------------------------------------------------
-- Events
-------------------------------------------------------------------------------
fn getRatioComparedObjs comparitor =
(
local retVal = #()
local considerSet = for obj in RsSelToolCollClassRoll.objectList() where (isKindOf obj colMesh) collect obj
for obj in considerSet do
(
local theMesh = getColMesh obj
local facesel = #{}
local numFaces = getNumFaces theMesh
local selectObj = false
for i = 1 to numFaces do
(
local face = getFace theMesh i
local r = ( getVert theMesh face.x )
local g = ( getVert theMesh face.y )
local b = ( getVert theMesh face.z )
local p3mat = localMatrix r g b
local p3inv = inverse p3mat
-- Transform points onto a horizontal plane to easily find
-- bounds. Only need to consider x and y from now on.
local v1 = ( RoundVecZero ( r * p3inv ) )
local v2 = ( RoundVecZero ( g * p3inv ) )
local v3 = ( RoundVecZero ( b * p3inv ) )
-- Get bounds
local minx = amin v1.x v2.x v3.x
local maxx = amax v1.x v2.x v3.x
local miny = amin v1.y v2.y v3.y
local maxy = amax v1.y v2.y v3.y
local xsize = maxx - minx
local ysize = maxy - miny
-- Create face selection
if ( comparitor ( xsize / ysize ) ) or
( comparitor ( ysize / xsize ) ) do
(
facesel[i] = true
selectObj = true
)
)
if selectObj do
(
-- Set face selection
--col2Mesh obj
--setFaceSelection o facesel
append retVal obj
)
)
return retVal
)
on btnGT pressed do
(
undo "select collision by face-size ratio" on
(
local selObjects = getRatioComparedObjs (fn compare val = (val >= spnRatio.value))
RsSelectObjs selObjects
)
) -- End of btnGT pressed
on btnLT pressed do
(
undo "select collision by face-size ratio" on
(
local selObjects = getRatioComparedObjs (fn compare val = (val <= spnRatio.value))
RsSelectObjs selObjects
)
) -- End of btnLT pressed
)
--//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-- /COLLISION
--//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-- Collision Volume Selection Utility
rollout RsSelToolTexMapRoll "Texturemap Name:"
(
-------------------------------------------------------------------------------
-- UI
-------------------------------------------------------------------------------
label txtInfo "Enter part of the texture map name to find:\n * Includes extension (e.g. .psd)\n * File path is not searched\n * Can use wildcards (*, ?)" height:52 align:#left
edittext txtTexMap "" across:2 width:(RsSelToolTexMapRoll.width - 116) align:#left
button btnSel "Select" width:80 offset:[0,-2] align:#right
checkbox chkExact "Exact Match (includes manual wildcards)"
-------------------------------------------------------------------------------
-- Functions
-------------------------------------------------------------------------------
fn texSearch findText =
(
local considerSet = for obj in (RsSelToolGeneralRoll.objectList()) where (isKindOf obj GeometryClass) collect obj -- Ignore collision
local selObjs = #()
if not chkExact.checked do (findText = "*" + findText + "*")
local objCount = considerSet.count
local doProgress = (objCount > 0)
local notCancelled = True
if doProgress do
(
progressStart "Matching texture-names"
)
for n = 1 to objCount while (notCancelled = progressUpdate (100.0 * n / objCount)) do
(
local obj = considerSet[n]
local texmaplist = #()
RsGetTexMapsFromObjNoStrip obj texmaplist #() #()
-- Split diffuse/alpha pairs:
local texmapsSplit = #()
for mapName in texmaplist do (join texmapsSplit (filterString mapName "+"))
local notFound = true
for mapName in texmapsSplit while notFound do
(
if matchPattern (filenameFromPath mapName) pattern:findText do
(
append selObjs obj
notFound = false
)
)
)
if doProgress do
(
progressEnd()
)
if notCancelled do
(
RsSelectObjs selObjs
)
return OK
)
-------------------------------------------------------------------------------
-- Events
-------------------------------------------------------------------------------
on btnSel pressed do
(
texSearch txtTexMap.text
)
)
-- Object Class Type or Attribute Class Selection
rollout RsSelToolClassRoll "Select By Class:"
(
-------------------------------------------------------------------------------
-- UI
-------------------------------------------------------------------------------
group "Select by Max Class:"
(
button btnSelMxClass "Select >" align:#left width:60 across:3
dropDownList lstMxClasses "" align:#center width:(RsSelToolClassRoll.width - 156)
button btnRefreshA "Refresh" align:#right width:60
)
group "Select by Attribute Class:"
(
button btnSelAttrClass "Select >" align:#left width:60 across:3
dropDownList lstAttrClasses "" align:#center width:(RsSelToolClassRoll.width - 156)
button btnRefreshB "Refresh" align:#right width:60
groupBox grpRollAttrSel "Select by single attribute:" height:200 width:(RsSelToolClassRoll.width - 28)
editText txtAttrFilter "Filter:" pos:(grpRollAttrSel.pos + [6,16]) width:(grpRollAttrSel.width - 10)
subrollout rollAttrSel "" pos:(grpRollAttrSel.pos + [4,36]) height:(grpRollAttrSel.height - 40) width:(grpRollAttrSel.width - 8)
label lblPaddingA "" height:4
)
local mxClassObjs, attrClassObjs
fn showAttrClassRolls =
(
-- Clear current subrollouts:
for subRoll in rollAttrSel.rollouts do
(
removeSubRollout rollAttrSel subRoll
)
local considerSet = RsSelToolGeneralRoll.objectList()
local selName = lstAttrClasses.selected
if (selName != undefined) do
(
local addRolls = RsCreateObjEditRoll #() propClassName:selName rollType:#attr selector:true filterName:txtAttrFilter.text
for subRoll in addRolls do
(
-- Set new sub-rollout as rolled-up, if the user has previously rolled it up:
local rolledUp = RsSettingsReadBoolean subRoll.name "rollup" false
addSubRollout rollAttrSel subRoll rolledUp:rolledUp
)
)
)
fn refresh =
(
local mxClasses = #()
local attrClasses = #()
mxClassObjs = #()
attrClassObjs = #()
for obj in objects do
(
local mxClass = classOf obj
local attrClass = getAttrClass obj
local findNum = findItem mxClasses mxClass
if (findNum == 0) do
(
append mxClasses mxClass
append mxClassObjs #()
findNum = mxClasses.count
)
append mxClassObjs[findNum] obj
local findNum = findItem attrClasses attrClass
if (findNum == 0) do
(
append attrClasses attrClass
append attrClassObjs #()
findNum = attrClasses.count
)
append attrClassObjs[findNum] obj
)
local maxClassPrevSel = lstMxClasses.selected
local attrClassPrevSel = lstAttrClasses.selected
lstMxClasses.items = (for item in mxClasses collect item as string)
lstAttrClasses.items = (for item in attrClasses collect item as string)
-- Select most-likely classes by default, to minimise clicks
-- If refreshing, select the previous selection, if it's still there
for ctrlData in #(#(lstMxClasses, maxClassPrevSel, #()), #(lstAttrClasses, attrClassPrevSel, #("Gta Object", "Gta Collision", "RS Container"))) do
(
local ctrl = ctrlData[1]
local prevSel = ctrlData[2]
local defSels = ctrlData[3]
local selList = if (prevSel == undefined) then defSels else #(prevSel)
local selNum = 0
for item in selList while (selNum == 0) do
(
selNum = findItem ctrl.items item
)
if (selNum != 0) do
(
ctrl.selection = selNum
)
)
showAttrClassRolls()
)
-------------------------------------------------------------------------------
-- Event Handlers
-------------------------------------------------------------------------------
on txtAttrFilter changed newText do
(
showAttrClassRolls()
)
on btnSelMxClass pressed do
(
local selClass = lstMxClasses.selected
refresh()
local classNum = findItem lstMxClasses.items selClass
if (classNum == 0) do return false
local classObjs = mxClassObjs[classNum]
local considerSet = RsSelToolGeneralRoll.objectList()
local selSet = for obj in classObjs where (findItem considerSet obj != 0) collect obj
RsSelectObjs selSet
)
on btnSelAttrClass pressed do
(
local selClass = lstAttrClasses.selected
refresh()
local classNum = findItem lstAttrClasses.items selClass
if (classNum == 0) do return false
local classObjs = attrClassObjs[classNum]
local considerSet = RsSelToolGeneralRoll.objectList()
local selSet = for obj in classObjs where (findItem considerSet obj != 0) collect obj
RsSelectObjs selSet
)
on lstAttrClasses selected num do
(
showAttrClassRolls()
)
on btnRefreshA pressed do
(
refresh()
)
on btnRefreshB pressed do
(
refresh()
)
on RsSelToolClassRoll open do
(
refresh()
)
)
rollout RsSelToolUVRoll "UVs:"
(
group "Select Faces:"
(
button btnUVRatioDiff "Mismatched UV-Proportions" across:2 align:#left tooltip:"Find faces with mismatched\nmapping/geometry proportions"
spinner spnMaxRatioDiff "Max Ratio Difference:" range:[0,50.0,1.6] scale:0.01 align:#right offset:[0,3]
button btnZeroSizeUVs "Zero-sized UVs" align:#left tooltip:"Find faces with zero-area UVs"
)
-- Function returns faces on obj with UV face-proportions that are different to their geometry faces:
fn findBadFaceMapRatios obj chan:1 maxRatioDiff:1.6 =
(
local faceCount = getNumFaces obj
local objOp = RsMeshPolyOp obj
local objGetFace = RsGetFaceFunc obj
local objGetMapFace = RsGetMapFaceFunc obj
local objGetVert = RsGetVertFunc obj
local objGetFaceMatID = RsGetFaceMatIDFunc obj
local dodgyFaceNums = #{}
dodgyFaceNums.count = faceCount
-- Skip face-checks if object lacks this map-channel:
if (not objOp.getMapSupport obj chan) do return #{}
local bmpSizeRatios = #()
local objMat = obj.material
for faceNum = 1 to faceCount do
(
local matId = objGetFaceMatID obj faceNum
local bmpSizeRatio = bmpSizeRatios[matId]
-- Get the aspect-ratio of this face's texturemap, if found:
if (bmpSizeRatio == undefined) do
(
bmpSizeRatio = 1.0
local subMat = RsGetSubmatByMatId objMat matId
if (isKindOf subMat Rage_Shader) do
(
local numVars = RstGetVariableCount subMat
local texMapNum = 0
-- Check variables:
local notFound = True
for varNum = 1 to numVars while notFound do
(
local varType = RstGetVariableType subMat varNum
if (varType == "texmap") do
(
local varName = RstGetVariableName subMat varNum
texMapNum += 1
if (RsIsDiffuseMap varName) do
(
local notFound = False
local texMap = getSubTexmap subMat texMapNum
if (isKindOf texMap Bitmaptexture) and (texMap.filename != "") do
(
local loadBmp = openBitmap texMap.filename
if (loadBmp != undefined) do
(
bmpSizeRatio = (loadBmp.width as float) / loadBmp.height
close loadBmp
)
)
)
)
)
)
bmpSizeRatios[matId] = bmpSizeRatio
)
local geoVerts = for vertNum in (objGetFace obj faceNum) collect (objGetVert obj vertNum)
local mapVerts = for vertNum in (objGetMapFace obj chan faceNum) collect (objOp.getMapVert obj chan vertNum)
-- Make map-verts use texture-map's aspect-ratio, and remove Z-axis:
mapVerts = for item in mapVerts collect [item.x * bmpSizeRatio, item.y]
local edgeVertIdxList = for n = 1 to (geoVerts.count - 1) collect #(n, n + 1)
append edgeVertIdxList #(geoVerts.count, 1)
local geoEdgeLengths = for edgeVertIdxs in edgeVertIdxList collect
(
distance geoVerts[edgeVertIdxs[1]] geoVerts[edgeVertIdxs[2]]
)
local mapEdgeLengths = for edgeVertIdxs in edgeVertIdxList collect
(
distance mapVerts[edgeVertIdxs[1]] mapVerts[edgeVertIdxs[2]]
)
local edgeCount = edgeVertIdxList.count
local refLength = geoEdgeLengths[1]
local geoRatios = for n = 2 to edgeCount collect (geoEdgeLengths[n] / refLength)
local faceMaxRatioDiff = maxRatioDiff / refLength
local refLength = mapEdgeLengths[1]
local mapRatios = for n = 2 to edgeCount collect (mapEdgeLengths[n] / refLength)
local similarRatio = True
for n = 1 to geoRatios.count while similarRatio do
(
local thisRatio = abs (geoRatios[n] - mapRatios[n])
similarRatio = (thisRatio < faceMaxRatioDiff)
--if not similarRatio do (format "% (%, %) %\n" thisRatio geoRatios[n] mapRatios[n] thisMaxRatioDiff)
)
if not similarRatio do
(
dodgyFaceNums[faceNum] = True
)
)
return dodgyFaceNums
)
-- Function returns faces on obj with zero-area UV faces:
fn findZeroSizeFaces obj chan:1 =
(
local faceCount = getNumFaces obj
local objOp = RsMeshPolyOp obj
local objGetMapFace = RsGetMapFaceFunc obj
local dodgyFaceNums = #{}
dodgyFaceNums.count = faceCount
-- Skip face-checks if object lacks this map-channel:
if (not objOp.getMapSupport obj chan) do return #{}
-- Find zero-sized faces:
for faceNum = 1 to faceCount do
(
local zeroSize = True
local faceMapVerts = objGetMapFace obj chan faceNum
local vertPosList = for thisVert in faceMapVerts collect (objOp.getMapVert obj chan thisVert)
vertPosList.Z = 0
local firstVert = vertPosList[1]
for n = 2 to vertPosList.count while zeroSize do
(
zeroSize = ((distance firstVert vertPosList[n]) < 0.00001)
)
if zeroSize do
(
dodgyFaceNums[faceNum] = True
)
)
return dodgyFaceNums
)
fn runFaceFindFunc faceFindFunc =
(
local notCancelled = True
local objs = for obj in RsSelToolGeneralRoll.objectList() where (isEditPolyMesh obj) collect obj
-- Make a note of which is the first-first instance of an object
local primeInstObjs = #()
local primeInstObjIdxs = #()
local objPrimeIdxs = for objIdx = 1 to objs.count collect
(
local obj = objs[objIdx]
local objPrimeIdx = 0
for primeIdx = 1 to primeInstObjs.count while (objPrimeIdx == 0) do
(
if (areNodesInstances obj primeInstObjs[primeIdx]) do
(
objPrimeIdx = primeIdx
)
)
if (objPrimeIdx == 0) do
(
append primeInstObjs obj
append primeInstObjIdxs objIdx
objPrimeIdx = primeInstObjs.count
)
objPrimeIdx
)
-- If objects are instanced, we only need to examine one instance for each mesh:
progressStart "Examining geometry..."
local primeObjFaceLists = for n = 1 to primeInstObjs.count while (notCancelled = progressUpdate (100.0 * n / primeInstObjs.count)) collect
(
faceFindFunc primeInstObjs[n] maxRatioDiff:spnMaxRatioDiff.value
)
progressEnd()
if notCancelled do
(
faceLists = for idx in objPrimeIdxs collect primeObjFaceLists[idx]
RsSelToolGeneralRoll.selObjFaces objs faceLists
)
)
on btnUVRatioDiff pressed do
(
runFaceFindFunc findBadFaceMapRatios
)
on btnZeroSizeUVs pressed do
(
runFaceFindFunc findZeroSizeFaces
)
)
rollout RsSelToolRoll "Object Selector"
(
dotNetControl rsBannerPanel "Panel" pos:[0,0] height:32 width:RsSelToolRoll.width
local banner = makeRsBanner dn_Panel:rsBannerPanel versionNum:1.23 versionName:"Powerful Frog"
local rollWidth
dotNetControl dnTabs "system.windows.forms.tabControl" width:RsSelToolRoll.width height:25 align:#left pos:[0, 34]
subRollout theSubRollout height:250 offset:[0,10]
local rolloutPages =
#(
DataPair name:"General" rollouts:#( RsSelToolClassRoll, RsSelToolObjRoll, RsDupeSelector, RsRotationSelector, RsSelToolIplRoll, RsSelToolAreaCodeRoll ),
DataPair name:"Memory" rollouts:#( RsSelToolMemoryRoll ),
DataPair name:"LOD" rollouts:#( RsSelToolLodRoll, RsSelToolDrawLodRoll ),
DataPair name:"Refs" rollouts:#( RsSelToolIrefsRoll, RsSelToolRsRefsRoll, RsSelToolRefsRoll ),
DataPair name:"Materials" rollouts:#( RsSelToolTxdRoll, RsSelToolShaderRoll, RsSelToolTexMapRoll, RsSelToolUVRoll ),
DataPair name:"Collision" rollouts:#( RsSelToolCollClassRoll, RsSelToolCollFlagRoll, RsSelToolCollGrpRoll, RsSelToolCollVolRoll, RsSelToolProcAttrRoll ),
DataPair name:"Lights" rollouts:#( RsSelToolLightsRoll )
)
local rolloutCurrentPages = #()
fn SetPage idx =
(
if ( idx <= rolloutPages.count ) then
(
for roll in rolloutCurrentPages do
(
removeSubRollout theSubRollout roll
)
rolloutCurrentPages = #()
for roll in rolloutPages[idx].rollouts do
(
addSubRollout theSubRollout roll
append rolloutCurrentPages roll
)
)
else
(
MessageBox "Internal Error. Tabs misconfigured. Contact tools."
)
)
on dnTabs Click do
(
local tabNum = dnTabs.SelectedIndex + 1
RsSettingWrite "RsSelToolRoll" "tabNum" tabNum
SetPage tabNum
)
fn arrangeCtrls =
(
theSubRollout.height = RsSelToolRoll.height - theSubRollout.pos.y - theSubRollout.pos.x
)
-- Only allow vertical resizing:
on RsSelToolRoll Resized newSize do
(
if (newSize.x != rollWidth) do
(
RsSelToolRoll.width = rollWidth
)
RsSettingWrite "RsSelToolRoll" "height" newSize.y
arrangeCtrls()
)
on RsSelToolRoll open do
(
banner.setup()
rollWidth = RsSelToolRoll.width
arrangeCtrls()
dnTabs.tabPages.clear()
for item in rolloutPages do
(
dnTabs.tabPages.add item.name
)
local tabNum = RsSettingsReadInteger "RsSelToolRoll" "tabNum" 1
if (tabNum > dnTabs.tabPages.count) do
(
tabNum = 1
)
dnTabs.SelectedIndex = (tabNum - 1)
addSubRollout theSubRollout RsSelToolGeneralRoll
SetPage tabNum
)
fn create =
(
destroyDialog RsSelToolRoll
local rollHeight = RsSettingsReadInteger "RsSelToolRoll" "height" 320
CreateDialog RsSelToolRoll modal:false width:430 height:rollHeight style:#(#style_resizing, #style_titlebar, #style_border, #style_sysmenu )
)
) -- End rollout
RsSelToolRoll.create()
-- pipeline/util/selector.ms