--------------------------------------------------------------------------------------------------------------------------------------- -- RSL_CollisionOps2Create -- By Paul Truss -- Senior Technical Artist -- Rockstar Games London -- 12/01/2011 -- -- Modified for Rockstar North by Neil Gregory -- 07/2011 -- -- Structure containing functions and UI used by RSL_CollisionOps2 in create mode --------------------------------------------------------------------------------------------------------------------------------------- -- Struct used to store oriented bounding box information struct RSL_OBB ( size = [0,0,0], -- bounding box size matrix -- transformation matrix ) -- main struct struct RSL_CollisionOps2Create ( --------------------------------------------------------------------------------------------------------------------------------------- -- Struct variables --------------------------------------------------------------------------------------------------------------------------------------- INIfile = (RsConfigGetWildWestDir() + "/etc/config/general/collisionOps2.ini"), boxParameterArray = #(), percentPaddingArray = #(), newCollisionMeshArray = #(), -- standard attribute indices idxColType = getAttrIndex "Gta Collision" "Coll Type", idxStairs = getAttrIndex "Gta Collision" "Stairs", idxNoClimb = getAttrIndex "Gta Collision" "Non Climable", idxSee = getAttrIndex "Gta Collision" "See Through", idxNoCamera = getAttrIndex "Gta Collision" "Non Camera Collidable", idxShoot = getAttrIndex "Gta Collision" "Shoot Through", idxWet = getAttrIndex "Gta Collision" "Wet", idxPath = getAttrIndex "Gta Collision" "Path", idxPiece = getAttrIndex "Gta Collision" "Piece Type", idxDay = getAttrIndex "Gta Collision" "Day Brightness", idxNight = getAttrIndex "Gta Collision" "Night Brightness", idxAudio = getAttrIndex "Gta Collision" "Audio Material", idxRoomID = getAttrIndex "Gta Collision" "Room ID", --idxLeeds = getAttrIndex "Gta Collision" "Edited by Leeds", idxBVH = getAttrIndex "Gta Collision" "BVH Bound", idxProcTint = getAttrIndex "Gta Collision" "Use Procedural Tint", idxClothColl = getAttrIndex "Gta Collision" "Is Cloth Collision", currentTool, -- variable containing the interface for the current collision object mode lastType, -- variable containg the name of the last surface type lastBoxType, -- variable containing the name of the last box parameters currentBoxParams, -- variable containing the UI for the current box parameters --------------------------------------------------------------------------------------------------------------------------------------- -- UI variables --------------------------------------------------------------------------------------------------------------------------------------- toolTip = dotNetObject "ToolTip", createTableLayout,createButton,deleteButton,statusLabel, boxCheckButton,sphereCheckButton,cylinderCheckButton,meshCheckButton, parametersGroup,attributesGroup,createGroup, boxParametersTableLayout,bestAlignButton,offsetTypeCheckButton,percentTypeCheckButton, lockAxesButton, radiusNumeric, bestAlignButton,useShortestAxis,paddingNumeric, ignoreOpenEdgeCheckButton,convertToCollisionCheckButton,angleNumeric, expandButton, attributesTableLayout,surfaceTypeButton,cameraCheckBox,physicsCheckBox,hiDetailCheckBox,locoCheckBox, stairsCheckBox,noCoverCheckBox,noClimbCheckBox,pathCheckBox,seeCheckBox,noCameraCheckBox,shootCheckBox,noDecalCheckBox, noNavMeshCheckBox,noRagDollCheckBox,noParticleCheckBox,wetCheckBox, pieceTypeButton,dayNumeric,nightNumeric,audioTextBox,roomIDNumeric,BVHCheckBox,procTintCheckBox,clothCollTintCheckBox, proceduralTypeButton,pedMultiplierNumeric,miloRoomButton, --------------------------------------------------------------------------------------------------------------------------------------- -- -- FUNCTIONS -- --------------------------------------------------------------------------------------------------------------------------------------- --------------------------------------------------------------------------------------------------------------------------------------- -- disableAccelerators() Called when the user enters any control that needs keyboard input e.g. a textBox --------------------------------------------------------------------------------------------------------------------------------------- fn disableAccelerators s e = ( enableAccelerators = false ), --------------------------------------------------------------------------------------------------------------------------------------- -- decimalToFloat() Converts the value of the parsed control from a dotNet decimal to a max script float --------------------------------------------------------------------------------------------------------------------------------------- fn decimalToFloat control = ( local dValue = getProperty control #value asDotNetObject:true local fValue = (dotNetClass "System.Decimal").ToSingle dValue ), --------------------------------------------------------------------------------------------------------------------------------------- -- calculateMaxMin() Calculates the maximum and minimum bounds of the parsed pos (array of vertex positions). Stores the -- results to the parsed &maximum &minimum point3 variables. --------------------------------------------------------------------------------------------------------------------------------------- mapped fn calculateMaxMin pos &maximum &minimum = ( -- if any one of the pos axes is outside the bounds of &maximum or &minimum, set the relevant axis if pos.x > maximum.x then maximum.x = pos.x if pos.y > maximum.y then maximum.y = pos.y if pos.z > maximum.z then maximum.z = pos.z if pos.x < minimum.x then minimum.x = pos.x if pos.y < minimum.y then minimum.y = pos.y if pos.z < minimum.z then minimum.z = pos.z ), --------------------------------------------------------------------------------------------------------------------------------------- -- OBBFromAngle() Returns an RSL_OBB struct based on the parsed vertPositions and rotation. --------------------------------------------------------------------------------------------------------------------------------------- fn OBBFromAngle vertPositions rotation = ( local maximum = [-999999999,-999999999,-999999999] local minimum = [999999999,999999999,999999999] -- get the bounds for the parsed vertPositions calculateMaxMin vertPositions maximum minimum -- calculate the size and transform for the RSL_OBB local size = (maximum - minimum) local center = ((maximum + minimum) * 0.5) * rotation local matrix = rotation as matrix3 matrix.translation = center RSL_OBB size:size matrix:matrix ), --------------------------------------------------------------------------------------------------------------------------------------- -- gatherVertextPositions() Returns an array of vertex positions for the parsed object based on the parsed faceSelection --------------------------------------------------------------------------------------------------------------------------------------- fn gatherVertextPositions object faceSelection = ( local result -- check to see what class the object is and use the correct functions to get the vertex positions case (classOf object.baseObject) of ( editable_mesh: ( result = for index in (meshOp.getVertsUsingFace object faceSelection) collect object.verts[index].pos ) editable_poly: ( result = for index in (polyOp.getVertsUsingFace object faceSelection) collect object.verts[index].pos ) ) result ), --------------------------------------------------------------------------------------------------------------------------------------- -- findOBB() Calculates and returns the smallest RSL_OBB for the parsed opbject based on the parsed faceSelection -- which is used to gather the vertices, the parsed angleStep which is used to rotate the vertex positions by a minimum amount, -- the parsed maximumAngle which controls the total rotation and the parsed baseMatrix which is used as a starting point -- for the rotation. --------------------------------------------------------------------------------------------------------------------------------------- fn findOBB object faceSelection angleStep maximumAngle baseMatrix = ( -- get the vertex positions from the object based on the face selection. local vertPositions = gatherVertextPositions object faceSelection -- create a starting RSL_OBB local firstOBB = OBBFromAngle vertPositions (eulerToQuat (eulerAngles 0 0 0)) -- set the smallestOBB to the firstOBB and setup the smallest size based on the smallestOBB local smallestOBB = firstOBB local smallestSize = smallestOBB.size.x + smallestOBB.size.y + smallestOBB.size.z -- loop through each axis from the -maximumAngle to the maximumAngle by the angleStep for x = -maximumAngle to maximumAngle by angleStep do ( for y = -maximumAngle to maximumAngle by angleStep do ( for z = -maximumAngle to maximumAngle by angleStep do ( -- setup the euler variable so that it contains the rotation from the parsed baseMatrix -- and assign it to the quatRotation variable as a quat local baseEuler = (baseMatrix as eulerAngles) local euler = eulerAngles x y z euler.x += baseEuler.x euler.y += baseEuler.y euler.z += baseEuler.z local quatRotation = eulerToQuat euler -- get the current vertex positions rotated by the quatRotation local currentVertPositions = (for pos in vertPositions collect (pos * (inverse quatRotation))) -- generate an RSL_OBB from the currentVertPositions & quatRotation and calculate the size local currentOBB = (OBBFromAngle currentVertPositions quatRotation) local currentSize = currentOBB.size.x + currentOBB.size.y + currentOBB.size.z -- if the size of the currentOBB is smaller than the smallestSize, we have a smaller RSL_OBB so we -- set the smallestOBB to the currentOBB and the smallestSize to the currentSize if currentSize < smallestSize then ( smallestOBB = currentOBB smallestSize = currentSize ) ) ) ) smallestOBB ), --------------------------------------------------------------------------------------------------------------------------------------- -- setAttribute() Sets the standard attributes for the parsed object based on the attribute parameters --------------------------------------------------------------------------------------------------------------------------------------- fn setAttribute object = ( try (setAttr object idxColType surfaceTypeButton.text) catch(format "S Type:%" (getCurrentException())) try (setAttr object idxStairs stairsCheckBox.checked) catch(format "Stairs:%" (getCurrentException())) try (setAttr object idxNoClimb noClimbCheckBox.checked) catch(format "No Climb:%" (getCurrentException())) try (setAttr object idxSee seeCheckBox.checked) catch(format "See:%" (getCurrentException())) try (setAttr object idxNoCamera noCameraCheckBox.checked) catch(format "No Camera:%" (getCurrentException())) try (setAttr object idxShoot shootCheckBox.checked) catch(format "Shoot:%" (getCurrentException())) try (setAttr object idxWet wetCheckBox.checked) catch(format "Wet:%" (getCurrentException())) try (setAttr object idxPiece ((findItem ::RSL_CollisionOps.attribute.pieceTypeArray pieceTypeButton.text) - 1)) catch(format "Piece:%" (getCurrentException())) try (setAttr object idxPath pathCheckBox.checked) catch(format "Path:%" (getCurrentException())) try (setAttr object idxDay dayNumeric.value) catch(format "Day:%" (getCurrentException())) try (setAttr object idxNight nightNumeric.value) catch(format "Night:%" (getCurrentException())) try (setAttr object idxAudio audioTextBox.text) catch(format "Audio:%" (getCurrentException())) try (setAttr object idxRoomID roomIDNumeric.value) catch(format "Room:%" (getCurrentException())) try (setAttr object idxBVH BVHCheckBox.checked) catch(format "BVH:%" (getCurrentException())) try (setAttr object idxProcTint ProcTintCheckBox.checked) catch(format "ProcTint:%" (getCurrentException())) try (setAttr object idxClothColl clothCollTintCheckBox.checked) catch(format "ClothColl:%" (getCurrentException())) ), --------------------------------------------------------------------------------------------------------------------------------------- -- setRexBound() Sets the rexbound attributes for the parsed object based on the attribute parameters --------------------------------------------------------------------------------------------------------------------------------------- fn setRexBound object = ( -- create a new rexbound material ans set the surface type based on the surfaceTypeButton control local newRexBoundMaterial = RexBoundMtl name:object.name RexSetCollisionName newRexBoundMaterial surfaceTypeButton.text if proceduralTypeButton.text != "NONE" then ( RexSetProceduralName newRexBoundMaterial proceduralTypeButton.text ) -- if the miloRoomButton control .tag has a valid miloRoom object assigned, we can set the roomNode parameter. -- We only check that the node is valid rather than check that it's a miloRoom beacuse we only allow miloRooms -- to be assigned to the control in the first place. We check that it's a valid node in case it has been deleted. if miloRoomButton.tag != undefined and (isValidNode miloRoomButton.tag.value) then ( RexSetRoomNode newRexBoundMaterial miloRoomButton.tag.value ) if pedMultiplierNumeric.value > 0 then ( RexSetPopDensity newRexBoundMaterial pedMultiplierNumeric.value ) -- setup the flags based on the check state of the attributes local flags = 0 /* Stairs = 1 (bit0) Non Climable = 2 (bit1) See Through = 4 (bit2) Shoot Through = 8 (bit3) Doesnt provide cover = 16 (bit4) Path = 32 (bit5) Non Camera Collidable = 64 (bit6) Spare 3 = 128(bit7) No Decal = 256(bit8) No Navmesh = 512(bit9) No Ragdoll = 1024(bit10) No particle effects = 4096 (bit12) */ if stairsCheckBox.checked then ( flags = bit.or flags (bit.shift 1 0) ) if noCoverCheckBox.checked then ( flags = bit.or flags (bit.shift 1 4) ) if noClimbCheckBox.checked then ( flags = bit.or flags (bit.shift 1 1) ) if pathCheckBox.checked then flags = bit.or flags (bit.shift 1 5) if seeCheckBox.checked then ( flags = bit.or flags (bit.shift 1 2) ) if noCameraCheckBox.checked then ( flags = bit.or flags (bit.shift 1 6) ) if shootCheckBox.checked then ( flags = bit.or flags (bit.shift 1 3) ) if noDecalCheckBox.checked then flags = bit.or flags (bit.shift 1 8) if noNavMeshCheckBox.checked then flags = bit.or flags (bit.shift 1 9) if noRagDollCheckBox.checked then flags = bit.or flags (bit.shift 1 10) if noParticleCheckBox.checked then flags = bit.or flags (bit.shift 1 12) RexsetCollisionFlags newRexBoundMaterial flags -- assign the new rexbound material to the object object.material = newRexBoundMaterial ), --------------------------------------------------------------------------------------------------------------------------------------- -- makeBox() Creates a Collision Box for the parsed object based on the parsed faceSelection --------------------------------------------------------------------------------------------------------------------------------------- fn makeBox object faceSelection = ( local okToContinue = true local bound local paddingX = 0 local paddingY = 0 local paddingZ = 0 local offsetX = 0 local offsetY = 0 local offsetZ = 0 -- if we're using the offset parameters, we setup the padding and offset variables if offsetTypeCheckButton.checked then ( paddingX = ((decimalToFloat boxParameterArray[1]) + (decimalToFloat boxParameterArray[2])) paddingY = ((decimalToFloat boxParameterArray[3]) + (decimalToFloat boxParameterArray[4])) paddingZ = ((decimalToFloat boxParameterArray[5]) + (decimalToFloat boxParameterArray[6])) offsetX = ((decimalToFloat boxParameterArray[2]) + -(decimalToFloat boxParameterArray[1])) * 0.5 offsetY = ((decimalToFloat boxParameterArray[4]) + -(decimalToFloat boxParameterArray[3])) * 0.5 offsetZ = ((decimalToFloat boxParameterArray[6]) + -(decimalToFloat boxParameterArray[5])) * 0.5 ) -- if we're aligning to the selection, we calculate the oriented bounding box and assign it to the bound variable if bestAlignButton.checked then ( -- we do this three times, each time the angle step and maximum angle are -- smaller so that we get as close as we can within a reasonable amount of time. bound = findOBB object faceSelection 10.0 90.0 (matrix3 1) bound = findOBB object faceSelection 2.0 10.0 bound.matrix bound = findOBB object faceSelection 0.5 2.0 bound.matrix -- if we're using the percent parameters, we multiply the bound size by the percent parameters -- to get our final size. Otherwise we use the padding variables to get our final size if percentTypeCheckButton.checked then ( bound.size.x = bound.size.x * (decimalToFloat percentPaddingArray[1]) / 100.0 bound.size.y = bound.size.y * (decimalToFloat percentPaddingArray[2]) / 100.0 bound.size.z = bound.size.z * (decimalToFloat percentPaddingArray[3]) / 100.0 ) else ( bound.size.x += paddingX bound.size.y += paddingY bound.size.z += paddingZ ) -- add the offset variables to the transformation matrix of our bound bound.matrix.row4 += [offsetX,offsetY,offsetZ] ) else ( -- we're not aligning to the selection so... local maxBounds = [-999999999999,-999999999999,-999999999999] local minBounds = [999999999999,999999999999,999999999999] local vertexPosArray -- gather an array of the vertex positions based on the faceSelection case classOf object of ( editable_mesh: ( vertexPosArray = for v in ((meshOp.getVertsUsingFace object faceSelection) as array) collect object.verts[v].pos ) editable_poly: ( vertexPosArray = for v in ((polyOp.getVertsUsingFace object faceSelection) as array) collect object.verts[v].pos ) ) -- calculate the bounds of the vertexPosArray and assign the values to the maxBounds and minBounds calculateMaxMin vertexPosArray maxBounds minBounds -- if we're using the percent parameters, we create the oriented bounding box based on the maxBounds, minBounds, percent parameters and offset variables if percentTypeCheckButton.checked then ( bound = RSL_OBB size:[(abs (maxBounds.x - minBounds.x)) * (decimalToFloat percentPaddingArray[1]) / 100.0, \ (abs (maxBounds.y - minBounds.y)) * (decimalToFloat percentPaddingArray[2]) / 100.0, \ (abs (maxBounds.z - minBounds.z)) * (decimalToFloat percentPaddingArray[3]) / 100.0] bound.matrix = transMatrix (((maxBounds + minBounds) * 0.5) + [offsetX,offsetY,offsetZ]) ) else ( -- we're using the offset parameters so we create the oriented bounding box based on the maxBounds, minBounds, padding and offset variables bound = RSL_OBB size:[(abs (maxBounds.x - minBounds.x)) + paddingX, (abs (maxBounds.y - minBounds.y)) + paddingY, (abs (maxBounds.z - minBounds.z)) + paddingZ] bound.matrix = transMatrix (((maxBounds + minBounds) * 0.5) + [offsetX,offsetY,offsetZ]) -- check to see if the bound size for each axis is not a minus number. this means that the padding values are to big somewhere if bound.size.x < 0 or bound.size.y < 0 or bound.size.z < 0 then ( local errorString = stringStream "" format "One or more of the padding values is too high and the resulting mesh cannot be created.\n\n" to:errorString if bound.size.x < 0 then ( format "Width (X) is:%. Change either +X or -X so that the width is greater than 0\n" boxWidth to:errorString ) if bound.size.y < 0 then ( format "Length (y) is:%. Change either +Y or -Y so that the length is greater than 0\n" boxLength to:errorString ) if bound.size.z < 0 then ( format "Height (Z) is:%. Change either +Z or -Z so that the height is greater than 0\n" boxHeight to:errorString ) messageBox errorString title:"Error..." okToContinue = false ) ) ) bound = RsFindMinBox object -- if everthing is ok, we have a valid bound RSL_OBB and we can create the collision box if okToContinue then ( newCollisionMesh = Col_Box name:(uniqueName (object.name + " - colBox")) newCollisionMesh.wireColor = orange newCollisionMesh.transform = bound.transform newCollisionMesh.length = bound.length newCollisionMesh.width = bound.width newCollisionMesh.height = bound.height newCollisionMesh.parent = object setAttribute newCollisionMesh append newCollisionMeshArray newCollisionMesh ) ), --------------------------------------------------------------------------------------------------------------------------------------- -- makeMesh() Creates a Collision Mesh for the parsed object based on the parsed faceSelection --------------------------------------------------------------------------------------------------------------------------------------- fn makeMesh object faceSelection = ( -- depending on the class of our object, we create the newCollisionMesh using the correct functions case (classOf object) of ( Editable_mesh: ( newCollisionMesh = Editable_mesh name:(uniqueName (object.name + " - colMesh")) newCollisionMesh.transform = object.transform -- detach the faceSelection from the object as a copy and assign it to the mesh property of our newCollisionMesh newCollisionMesh.mesh = meshOp.detachFaces object faceSelection delete:false asMesh:true -- set the face ID for all faces to 1 because we're going to assign a rexbound material to the newCollisionMesh for f in newCollisionMesh.faces do ( setFaceMatID newCollisionMesh f.index 1 ) ) Editable_poly: ( -- generate a name for our newCollisionMesh local name = (uniqueName (object.name + " - colMesh")) -- detach the faceSelection from the object as a copy to a new node and then get the node by it's name polyOp.detachFaces object faceSelection delete:false asNode:true name:name newCollisionMesh = getNodeByName name -- set the face ID for all faces to 1 because we're going to assign a rexbound material to the newCollisionMesh polyOp.setFaceMatID newCollisionMesh (for f in newCollisionMesh.faces collect f.index) 1 ) ) newCollisionMesh.material = undefined newCollisionMesh.showVertexColors = false newCollisionMesh.wireColor = orange newCollisionMesh.pivot = object.pivot newCollisionMesh.parent = object resetXForm newCollisionMesh convertTo newCollisionMesh Editable_poly -- get the value of the angleNumeric parameter as a float local currentAngle = (decimalToFloat angleNumeric) -- if the currentAngle is greater than 0 we optimise the newCollisionMesh by removing edges if currentAngle > 0.0 then ( local edgeArray = #() local vertArray = #() -- loop through the edges checking if any of them have face angles less than the currentAngle for edge in newCollisionMesh.edges do ( local edgeFaces = (polyOp.getFacesUsingEdge newCollisionMesh edge) as array if edgeFaces.count == 2 then ( -- get the face normals for the 2 faces connected to the edge local face1Normal = polyOp.getFaceNormal newCollisionMesh edgeFaces[1] local face2Normal = polyOp.getFaceNormal newCollisionMesh edgeFaces[2] -- calculate the angle difference between them local angle = acos (dot face1Normal face2Normal) -- if the angle is less than the currentAngle, we can remove the edge if angle < currentAngle then ( append edgeArray edge.index -- we also add the vertx connected to the edge to see if they can be removed also local verts = (polyOp.getVertsUsingEdge newCollisionMesh edge.index) as array for v in verts do ( appendIfUnique vertArray v ) ) ) ) -- select the edges we want to remove and remove them polyOp.setEdgeSelection newCollisionMesh edgeArray newCollisionMesh.Remove selLevel:#Edge local finalVertArray = #() -- loop through the verts connected to the edges we removed and check to see if they are now connected to -- less than 3 edges and append them to the finalVertArray if they are for vert in vertArray do ( local edges = (polyOp.getEdgesUsingVert newCollisionMesh vert) as array if edges.count < 3 then ( append finalVertArray vert ) ) -- select the vertices we want to remove and remove them polyOp.setVertSelection newCollisionMesh finalVertArray newCollisionMesh.Remove selLevel:#Vertex ) -- if we want to check for open edges local okToConvert = true if not ignoreOpenEdgeCheckButton.checked then ( -- get the open edges local openEdges = (polyop.getOpenEdges newCollisionMesh) as array -- if we have open edges, we query the user if they would like to still convert to a collision mesh or leave the newCollisionMesh -- as an editable poly object if openEdges.count > 0 then ( local warningStream = stringStream "" format "There are holes in the collision mesh (open edges). This could be a problem for dynamic objects.\n" to:warningStream format "Do you want to continue? Pressing no will leave the new collision object as an editable poly and will not assign any collision type attributes." to:warningStream okToConvert = queryBox warningStream title:"Warning..." if not okToConvert then ( convertToCollisionCheckButton.checked = false select newCollisionMesh ) ) ) setRexBound newCollisionMesh append newCollisionMeshArray newCollisionMesh ), --------------------------------------------------------------------------------------------------------------------------------------- -- makeSphere() Creates a Collision Sphere for the parsed object based on the parsed faceSelection --------------------------------------------------------------------------------------------------------------------------------------- fn makeSphere object faceSelection = ( local maxBounds = [-999999999999,-999999999999,-999999999999] local minBounds = [999999999999,999999999999,999999999999] local vertexPosArray -- gather an array of the vertex positions based on the faceSelection case classOf object of ( editable_mesh: ( vertexPosArray = for v in ((meshOp.getVertsUsingFace object faceSelection) as array) collect object.verts[v].pos ) editable_poly: ( vertexPosArray = for v in ((polyOp.getVertsUsingFace object faceSelection) as array) collect object.verts[v].pos ) ) -- calculate the bounds of the vertexPosArray and assign the values to the maxBounds and minBounds calculateMaxMin vertexPosArray maxBounds minBounds -- calculate the bound and padding local bound = (maxBounds - minBounds) * 0.5 local paddingR = (decimalToFloat radiusNumeric) local radius = bound.x if radius < bound.y then radius = bound.y if radius < bound.z then radius = bound.z radius += paddingR -- if the radius is less than 0, the radius padding is too small if radius < 0.0 then ( messageBox "The radius is less than zero. Reduce the Radius Padding and try again." title:"Error..." ) else ( newCollisionMesh = Col_Sphere name:(uniqueName (object.name + " - ColSph")) newCollisionMesh.wireColor = orange newCollisionMesh.pos = (maxBounds + minBounds) * 0.5 newCollisionMesh.radius = radius newCollisionMesh.parent = object setAttribute newCollisionMesh append newCollisionMeshArray newCollisionMesh ) ), --------------------------------------------------------------------------------------------------------------------------------------- -- makeCylinder() Creates a Collision Cylinder for the parsed object based on the parsed faceSelection --------------------------------------------------------------------------------------------------------------------------------------- fn makeCylinder object faceSelection = ( local okToContinue = true local bound local paddingFloat = (decimalToFloat paddingNumeric) -- if we're aligning to the selection, we calculate the oriented bounding box and assign it to the bound variable if bestAlignButton.checked then ( bound = findOBB object faceSelection 10.0 45.0 (matrix3 1) bound = findOBB object faceSelection 4.0 10.0 bound.matrix bound = findOBB object faceSelection 1.0 4.0 bound.matrix bound.size += paddingFloat ) else ( -- we're not aligning to the selection so... local maxBounds = [-999999999999,-999999999999,-999999999999] local minBounds = [999999999999,999999999999,999999999999] local vertexPosArray -- gather an array of the vertex positions based on the faceSelection case classOf object of ( editable_mesh: ( vertexPosArray = for v in ((meshOp.getVertsUsingFace object faceSelection) as array) collect object.verts[v].pos ) editable_poly: ( vertexPosArray = for v in ((polyOp.getVertsUsingFace object faceSelection) as array) collect object.verts[v].pos ) ) -- calculate the bounds of the vertexPosArray and assign the values to the maxBounds and minBounds calculateMaxMin vertexPosArray maxBounds minBounds -- create the bound from the maxBounds, minBounds and paddingFloat bound = RSL_OBB size:[(abs (maxBounds.x - minBounds.x)) + paddingFloat, (abs (maxBounds.y - minBounds.y)) + paddingFloat, (abs (maxBounds.z - minBounds.z)) + paddingFloat] bound.matrix = transMatrix ((maxBounds + minBounds) * 0.5) -- if any of the bound axes are less than 0, the padding is too high if bound.size.x < 0 or bound.size.y < 0 or bound.size.z < 0 then ( local errorString = stringStream "" format "The padding value is too high and the resulting mesh cannot be created. Increase or reduce the padding value." to:errorString messageBox errorString title:"Error..." okToContinue = false ) ) if okToContinue then ( newCollisionMesh = Col_Cylinder name:(uniqueName (object.name + " - ColCylinder")) newCollisionMesh.wireColor = orange newCollisionMesh.transform = bound.matrix local radius local length -- if we're aligning to the selection and we want the shortest axis to be the main cylindrical axis, -- we must rotate the newCollisionMesh based on which bound axis is smaller if bestAlignButton.Checked and useShortestAxis.checked then ( radius = (amax #(bound.size.x, bound.size.y, bound.size.z)) * 0.5 length = amin #(bound.size.x, bound.size.y, bound.size.z) -- if the x axis is the smallest, we rotate 90 degrees aroung z -- if the z axis is the smallest, we rotate 90 degrees aroung x case of ( (bound.size.x < bound.size.y and bound.size.x < bound.size.z): (in coordsys local rotate newCollisionMesh (eulerangles 0 0 90)) (bound.size.z < bound.size.x and bound.size.z < bound.size.y): (in coordsys local rotate newCollisionMesh (eulerangles 90 0 0)) ) ) else ( -- we're not aligning and we're not using the shortest axis so we must rotate the newCollisionMesh -- based on which bound axis is bigger radius = (amin #(bound.size.x, bound.size.y, bound.size.z)) * 0.5 length = amax #(bound.size.x, bound.size.y, bound.size.z) -- if the x axis is the biggest, we rotate 90 degrees aroung z -- if the z axis is the biggest, we rotate 90 degrees aroung x case of ( (bound.size.x > bound.size.y and bound.size.x > bound.size.z): (in coordsys local rotate newCollisionMesh (eulerangles 0 0 90)) (bound.size.z > bound.size.x and bound.size.z > bound.size.y): (in coordsys local rotate newCollisionMesh (eulerangles 90 0 0)) ) ) newCollisionMesh.radius = radius newCollisionMesh.length = length newCollisionMesh.parent = object setAttribute newCollisionMesh append newCollisionMeshArray newCollisionMesh ) ), --------------------------------------------------------------------------------------------------------------------------------------- -- -- UI FUNCTIONS -- --------------------------------------------------------------------------------------------------------------------------------------- --------------------------------------------------------------------------------------------------------------------------------------- -- createMeshTypeControls() Creates the parameter controls for mesh collision objects. Called when the user presses the mesh -- mode --------------------------------------------------------------------------------------------------------------------------------------- fn createMeshTypeControls = ( meshParametersTableLayout = RS_dotNetUI.tableLayout "meshParametersTableLayout" \ collumns:#((dataPair type:"Percent" value:50)) \ rows:(for i = 1 to 3 collect (dataPair type:"Absolute" value:24)) \ dockStyle:RS_dotNetPreset.DS_Fill ignoreOpenEdgeCheckButton = RS_dotNetUI.checkBox "ignoreOpenEdgeCheckButton" text:("Ignore Open Edges") \ textAlign:RS_dotNetPreset.CA_MiddleLeft checkAlign:RS_dotNetPreset.CA_MiddleRight \ dockStyle:RS_dotNetPreset.DS_Fill convertToCollisionCheckButton = RS_dotNetUI.checkBox "convertToCollisionCheckButton" text:("Convert to Collision Mesh") \ textAlign:RS_dotNetPreset.CA_MiddleLeft checkAlign:RS_dotNetPreset.CA_MiddleRight \ dockStyle:RS_dotNetPreset.DS_Fill convertToCollisionCheckButton.Checked = true angleTableLayout = RS_dotNetUI.tableLayout "angleTableLayout" \ collumns:#((dataPair type:"Percent" value:50), (dataPair type:"Percent" value:50)) \ rows:#((dataPair type:"Absolute" value:24)) \ dockStyle:RS_dotNetPreset.DS_Fill angleLabel = RS_dotNetUI.Label "angleLabel" text:(" Optimisation Angle") textAlign:RS_dotNetPreset.CA_MiddleLeft \ borderStyle:RS_dotNetPreset.BS_None dockStyle:RS_dotNetPreset.DS_Fill angleNumeric = RS_dotNetUI.Numeric "angleNumeric" value:0.0 range:#(45.0, 0.0, 0.1, 1) dockStyle:RS_dotNetPreset.DS_Fill dotnet.addEventHandler angleNumeric "Enter" disableAccelerators angleTableLayout.Controls.Add angleLabel 0 0 angleTableLayout.Controls.Add angleNumeric 1 0 meshParametersTableLayout.Controls.Add ignoreOpenEdgeCheckButton 0 0 meshParametersTableLayout.Controls.Add convertToCollisionCheckButton 0 1 meshParametersTableLayout.Controls.Add angleTableLayout 0 2 meshParametersTableLayout ), --------------------------------------------------------------------------------------------------------------------------------------- -- dispatchBestAlignCheck() Dispatches bestAlignCheck(), called when the use checks the bestAlignButton --------------------------------------------------------------------------------------------------------------------------------------- fn dispatchBestAlignCheck s e = ( ::RSL_CollisionOps.createUI.bestAlignCheck s e ), --------------------------------------------------------------------------------------------------------------------------------------- -- bestAlignCheck() Enables the useShortestAxis check button based on the check state of the bestAlignButton. You can -- only use useShortestAxis is you're aligning to the selection. --------------------------------------------------------------------------------------------------------------------------------------- fn bestAlignCheck s e = ( useShortestAxis.enabled = bestAlignButton.Checked ), --------------------------------------------------------------------------------------------------------------------------------------- -- createCylinderTypeControls() Creates the parameter controls for cylinder collision objects. Called when the user presses -- the cylinder mode --------------------------------------------------------------------------------------------------------------------------------------- fn createCylinderTypeControls = ( cylinderParametersTableLayout = RS_dotNetUI.tableLayout "cylinderParametersTableLayout" \ collumns:#((dataPair type:"Percent" value:50)) \ rows:(for i = 1 to 3 collect (dataPair type:"Absolute" value:24)) \ dockStyle:RS_dotNetPreset.DS_Fill bestAlignButton = RS_dotNetUI.checkBox "bestAlignButton" text:("Align To Selection") \ textAlign:RS_dotNetPreset.CA_MiddleLeft checkAlign:RS_dotNetPreset.CA_MiddleRight \ dockStyle:RS_dotNetPreset.DS_Fill bestAlignButton.Checked = true dotnet.addEventHandler bestAlignButton "click" dispatchBestAlignCheck useShortestAxis = RS_dotNetUI.checkBox "useShortestAxis" text:("Align to Shortest Axis") \ textAlign:RS_dotNetPreset.CA_MiddleLeft checkAlign:RS_dotNetPreset.CA_MiddleRight \ dockStyle:RS_dotNetPreset.DS_Fill useShortestAxis.enabled = bestAlignButton.Checked cylinderPaddingTableLayout = RS_dotNetUI.tableLayout "cylinderPaddingTableLayout" \ collumns:#((dataPair type:"Percent" value:50), (dataPair type:"Percent" value:50)) \ rows:#((dataPair type:"Absolute" value:24)) \ dockStyle:RS_dotNetPreset.DS_Fill paddingLabel = RS_dotNetUI.Label "paddingLabel" text:(" Padding") textAlign:RS_dotNetPreset.CA_MiddleLeft \ borderStyle:RS_dotNetPreset.BS_None dockStyle:RS_dotNetPreset.DS_Fill paddingNumeric = RS_dotNetUI.Numeric "paddingNumeric" value:0.0 range:#(100.0, -100.0, 0.001, 3) dockStyle:RS_dotNetPreset.DS_Fill dotnet.addEventHandler paddingNumeric "Enter" disableAccelerators cylinderPaddingTableLayout.Controls.Add paddingLabel 0 0 cylinderPaddingTableLayout.Controls.Add paddingNumeric 1 0 cylinderParametersTableLayout.Controls.Add bestAlignButton 0 0 cylinderParametersTableLayout.Controls.Add useShortestAxis 0 1 cylinderParametersTableLayout.Controls.Add cylinderPaddingTableLayout 0 2 cylinderParametersTableLayout ), --------------------------------------------------------------------------------------------------------------------------------------- -- createSphereTypeControls() Creates the parameter controls for sphere collision objects. Called when the user presses -- the sphere mode --------------------------------------------------------------------------------------------------------------------------------------- fn createSphereTypeControls = ( sphereParametersTableLayout = RS_dotNetUI.tableLayout "sphereParametersTableLayout" \ collumns:#((dataPair type:"Percent" value:50)) \ rows:#((dataPair type:"Absolute" value:24)) \ dockStyle:RS_dotNetPreset.DS_Fill radiusPaddingTableLayout = RS_dotNetUI.tableLayout "radiusPaddingTableLayout" \ collumns:#((dataPair type:"Percent" value:50), (dataPair type:"Percent" value:50)) \ rows:#((dataPair type:"Absolute" value:24)) \ dockStyle:RS_dotNetPreset.DS_Fill radiusLabel = RS_dotNetUI.Label "radiusLabel" text:(" Radius Padding") textAlign:RS_dotNetPreset.CA_MiddleLeft \ borderStyle:RS_dotNetPreset.BS_None dockStyle:RS_dotNetPreset.DS_Fill radiusNumeric = RS_dotNetUI.Numeric "radiusNumeric" value:0.0 range:#(100.0, -100.0, 0.001, 3) dockStyle:RS_dotNetPreset.DS_Fill dotnet.addEventHandler radiusNumeric "Enter" disableAccelerators radiusPaddingTableLayout.Controls.Add radiusLabel 0 0 radiusPaddingTableLayout.Controls.Add radiusNumeric 1 0 sphereParametersTableLayout.Controls.Add radiusPaddingTableLayout 0 0 sphereParametersTableLayout ), --------------------------------------------------------------------------------------------------------------------------------------- -- offsetPaddingControls() Creates the parameter controls for box collision objects in offset padding mode. Called when the -- user presses the offsetTypeCheckButton in box mode --------------------------------------------------------------------------------------------------------------------------------------- fn offsetPaddingControls = ( offsetPaddingTableLayout = RS_dotNetUI.tableLayout "offsetPaddingTableLayout" \ collumns:#((dataPair type:"Percent" value:50),(dataPair type:"Percent" value:50)) \ rows:(for i = 1 to 6 collect (dataPair type:"Absolute" value:24)) \ dockStyle:RS_dotNetPreset.DS_Fill xPaddingLabel = RS_dotNetUI.Label "xPaddingLabel" text:(" X Padding (-X +X)") \ textAlign:RS_dotNetPreset.CA_MiddleLeft borderStyle:RS_dotNetPreset.BS_None \ dockStyle:RS_dotNetPreset.DS_Fill minusXPadding = RS_dotNetUI.Numeric "minusXPadding" value:0.0 range:#(100.0, -100.0, 0.001, 3) dockStyle:RS_dotNetPreset.DS_Fill dotnet.addEventHandler minusXPadding "Enter" disableAccelerators plusXPadding = RS_dotNetUI.Numeric "plusXPadding" value:0.0 range:#(100.0, -100.0, 0.001, 3) dockStyle:RS_dotNetPreset.DS_Fill dotnet.addEventHandler plusXPadding "Enter" disableAccelerators yPaddingLabel = RS_dotNetUI.Label "yPaddingLabel" text:(" Y Padding (-Y +Y)") textAlign:RS_dotNetPreset.CA_MiddleLeft \ borderStyle:RS_dotNetPreset.BS_None dockStyle:RS_dotNetPreset.DS_Fill minusYPadding = RS_dotNetUI.Numeric "minusYPadding" value:0.0 range:#(100.0, -100.0, 0.001, 3) dockStyle:RS_dotNetPreset.DS_Fill dotnet.addEventHandler minusYPadding "Enter" disableAccelerators plusYPadding = RS_dotNetUI.Numeric "plusYPadding" value:0.0 range:#(100.0, -100.0, 0.001, 3) dockStyle:RS_dotNetPreset.DS_Fill dotnet.addEventHandler plusYPadding "Enter" disableAccelerators zPaddingLabel = RS_dotNetUI.Label "zPaddingLabel" text:(" Z Padding (-Z +Z)") textAlign:RS_dotNetPreset.CA_MiddleLeft \ borderStyle:RS_dotNetPreset.BS_None dockStyle:RS_dotNetPreset.DS_Fill minusZPadding = RS_dotNetUI.Numeric "minusZPadding" value:0.0 range:#(100.0, -100.0, 0.001, 3) dockStyle:RS_dotNetPreset.DS_Fill dotnet.addEventHandler minusZPadding "Enter" disableAccelerators plusZPadding = RS_dotNetUI.Numeric "plusZPadding" value:0.0 range:#(100.0, -100.0, 0.001, 3) dockStyle:RS_dotNetPreset.DS_Fill dotnet.addEventHandler plusZPadding "Enter" disableAccelerators offsetPaddingTableLayout.Controls.Add xPaddingLabel 0 0 offsetPaddingTableLayout.Controls.Add minusXPadding 0 1 offsetPaddingTableLayout.Controls.Add plusXPadding 1 1 offsetPaddingTableLayout.Controls.Add yPaddingLabel 0 2 offsetPaddingTableLayout.Controls.Add minusYPadding 0 3 offsetPaddingTableLayout.Controls.Add plusYPadding 1 3 offsetPaddingTableLayout.Controls.Add zPaddingLabel 0 4 offsetPaddingTableLayout.Controls.Add minusZPadding 0 5 offsetPaddingTableLayout.Controls.Add plusZPadding 1 5 boxParameterArray = #(plusXPadding,minusXPadding,plusYPadding,minusYPadding,plusZPadding,minusZPadding) offsetPaddingTableLayout ), --------------------------------------------------------------------------------------------------------------------------------------- -- dispatchLockAxesCheck() Dispatches lockAxesCheck(), called when the user checks the lockAxesButton in the percent padding -- controls of the box mode. --------------------------------------------------------------------------------------------------------------------------------------- fn dispatchLockAxesCheck s e = ( ::RSL_CollisionOps.createUI.lockAxesCheck s e ), --------------------------------------------------------------------------------------------------------------------------------------- -- lockAxesCheck() Sets the percent controls to the same value when checked is true --------------------------------------------------------------------------------------------------------------------------------------- fn lockAxesCheck s e = ( if lockAxesButton.checked then ( local floatValue = decimalToFloat percentPaddingArray[1] for i = 2 to percentPaddingArray.count where entry != s do ( percentPaddingArray[i].value = floatValue ) ) ), --------------------------------------------------------------------------------------------------------------------------------------- -- dispatchPercentPaddingValueChanged() Dispatches percentPaddingValueChanged(), called when the user changes a value in -- one of the percent padding controls --------------------------------------------------------------------------------------------------------------------------------------- fn dispatchPercentPaddingValueChanged s e = ( ::RSL_CollisionOps.createUI.percentPaddingValueChanged s e ), --------------------------------------------------------------------------------------------------------------------------------------- -- percentPaddingValueChanged() Sets the percent controls to the same value if the lockAxesButton is checked --------------------------------------------------------------------------------------------------------------------------------------- fn percentPaddingValueChanged s e = ( if lockAxesButton.checked then ( local floatValue = decimalToFloat s for entry in percentPaddingArray where entry != s do ( entry.value = floatValue ) ) ), --------------------------------------------------------------------------------------------------------------------------------------- -- offsetPaddingControls() Creates the parameter controls for box collision objects in percent padding padding mode. Called -- when the user presses the percentTypeCheckButton in box mode --------------------------------------------------------------------------------------------------------------------------------------- fn percentPaddingControls = ( percentPaddingTableLayout = RS_dotNetUI.tableLayout "percentPaddingTableLayout" \ collumns:#((dataPair type:"Percent" value:50),(dataPair type:"Percent" value:50)) \ rows:(for i = 1 to 4 collect (dataPair type:"Absolute" value:24)) \ dockStyle:RS_dotNetPreset.DS_Fill lockAxesButton = RS_dotNetUI.checkBox "bestAlignButton" text:("Lock Axes") \ textAlign:RS_dotNetPreset.CA_MiddleLeft checkAlign:RS_dotNetPreset.CA_MiddleRight \ dockStyle:RS_dotNetPreset.DS_Fill dotnet.addEventHandler lockAxesButton "click" dispatchLockAxesCheck XLabel = RS_dotNetUI.Label "XLabel" text:(" X Percent:") textAlign:RS_dotNetPreset.CA_MiddleLeft \ borderStyle:RS_dotNetPreset.BS_None dockStyle:RS_dotNetPreset.DS_Fill XPadding = RS_dotNetUI.Numeric "XPadding" value:100.0 range:#(1000.0, 0, 0.1, 1) dockStyle:RS_dotNetPreset.DS_Fill dotnet.addEventHandler XPadding "ValueChanged" dispatchPercentPaddingValueChanged dotnet.addEventHandler XPadding "Enter" disableAccelerators YLabel = RS_dotNetUI.Label "YLabel" text:(" Y Percent:") textAlign:RS_dotNetPreset.CA_MiddleLeft \ borderStyle:RS_dotNetPreset.BS_None dockStyle:RS_dotNetPreset.DS_Fill YPadding = RS_dotNetUI.Numeric "YPadding" value:100.0 range:#(1000.0, 0, 0.1, 1) dockStyle:RS_dotNetPreset.DS_Fill dotnet.addEventHandler YPadding "ValueChanged" dispatchPercentPaddingValueChanged dotnet.addEventHandler YPadding "Enter" disableAccelerators ZLabel = RS_dotNetUI.Label "ZLabel" text:(" Z Percent:") textAlign:RS_dotNetPreset.CA_MiddleLeft \ borderStyle:RS_dotNetPreset.BS_None dockStyle:RS_dotNetPreset.DS_Fill ZPadding = RS_dotNetUI.Numeric "ZPadding" value:100.0 range:#(1000.0, 0, 0.1, 1) dockStyle:RS_dotNetPreset.DS_Fill dotnet.addEventHandler ZPadding "ValueChanged" dispatchPercentPaddingValueChanged dotnet.addEventHandler ZPadding "Enter" disableAccelerators percentPaddingTableLayout.Controls.Add lockAxesButton 0 0 percentPaddingTableLayout.Controls.Add XLabel 0 1 percentPaddingTableLayout.Controls.Add XPadding 1 1 percentPaddingTableLayout.Controls.Add YLabel 0 2 percentPaddingTableLayout.Controls.Add YPadding 1 2 percentPaddingTableLayout.Controls.Add ZLabel 0 3 percentPaddingTableLayout.Controls.Add ZPadding 1 3 percentPaddingTableLayout.SetColumnSpan lockAxesButton 2 percentPaddingArray = #(XPadding, YPadding, ZPadding) percentPaddingTableLayout ), --------------------------------------------------------------------------------------------------------------------------------------- -- dispatchBoxPaddingTypeCheck() Dispatches boxPaddingTypeCheck(), called when the user presses any of the box parameters -- mode buttons --------------------------------------------------------------------------------------------------------------------------------------- fn dispatchBoxPaddingTypeCheck s e = ( ::RSL_CollisionOps.createUI.boxPaddingTypeCheck s e ), --------------------------------------------------------------------------------------------------------------------------------------- -- boxPaddingTypeCheck() Switches the box parameters mode --------------------------------------------------------------------------------------------------------------------------------------- fn boxPaddingTypeCheck s e = ( -- make sure the pressed mode is always checked s.checked = true -- if the pressed mode is not the last mode we pressed, we need to create the controls if s != lastBoxType then ( case s.name of ( "offsetTypeCheckButton": ( -- un-check the percentTypeCheckButton percentTypeCheckButton.checked = false -- dispose of the currentBoxParams and create the offset padding controls if currentBoxParams != undefined then ( currentBoxParams.dispose() ) currentBoxParams = offsetPaddingControls() -- assign the currentBoxParams controls to the boxParametersTableLayout boxParametersTableLayout.Controls.Add currentBoxParams 0 2 boxParametersTableLayout.SetColumnSpan currentBoxParams 2 -- set the row to the correct height createTableLayout.RowStyles.Item[1].Height = 220 -- depending on weather the attributes group is expanded or not, set the correct height for the main form case attributesGroup.text of ( default:(::RSL_CollisionOps.CollisionForm.Height = 554) " Attributes - Basic":(::RSL_CollisionOps.CollisionForm.Height = 554) " Attributes - Advanced":(::RSL_CollisionOps.CollisionForm.Height = 785) ) ) "percentTypeCheckButton": ( -- un-check the offsetTypeCheckButton offsetTypeCheckButton.checked = false -- dispose of the currentBoxParams and create the percent padding controls if currentBoxParams != undefined then ( currentBoxParams.dispose() ) currentBoxParams = percentPaddingControls() -- assign the currentBoxParams controls to the boxParametersTableLayout boxParametersTableLayout.Controls.Add currentBoxParams 0 2 boxParametersTableLayout.SetColumnSpan currentBoxParams 2 -- set the row to the correct height createTableLayout.RowStyles.Item[1].Height = 172 -- depending on weather the attributes group is expanded or not, set the correct height for the main form case attributesGroup.text of ( default:(::RSL_CollisionOps.CollisionForm.Height = 506) " Attributes - Basic":(::RSL_CollisionOps.CollisionForm.Height = 506) " Attributes - Advanced":(::RSL_CollisionOps.CollisionForm.Height = 736) ) ) ) ) lastBoxType = s ), --------------------------------------------------------------------------------------------------------------------------------------- -- createBoxTypeControls() Creates the parameter controls for box collision objects. Called when the user presses -- the box mode --------------------------------------------------------------------------------------------------------------------------------------- fn createBoxTypeControls = ( bestAlignButton = RS_dotNetUI.checkBox "bestAlignButton" text:("Align To Selection") \ textAlign:RS_dotNetPreset.CA_MiddleLeft checkAlign:RS_dotNetPreset.CA_MiddleRight \ dockStyle:RS_dotNetPreset.DS_Fill offsetTypeCheckButton = RS_dotNetUI.checkBox "offsetTypeCheckButton" text:(toUpper "Offset") appearance:RS_dotNetPreset.AC_Button dockStyle:RS_dotNetPreset.DS_Fill dotnet.addEventHandler offsetTypeCheckButton "click" dispatchBoxPaddingTypeCheck offsetTypeCheckButton.checked = true lastBoxType = undefined percentTypeCheckButton = RS_dotNetUI.checkBox "percentTypeCheckButton" text:(toUpper "Percent") appearance:RS_dotNetPreset.AC_Button dockStyle:RS_dotNetPreset.DS_Fill dotnet.addEventHandler percentTypeCheckButton "click" dispatchBoxPaddingTypeCheck boxParametersTableLayout = RS_dotNetUI.tableLayout "boxParametersTableLayout" \ collumns:#((dataPair type:"Percent" value:50), (dataPair type:"Percent" value:50)) \ rows:#((dataPair type:"Absolute" value:24), (dataPair type:"Absolute" value:24), (dataPair type:"Absolute" value:24)) \ dockStyle:RS_dotNetPreset.DS_Fill boxParametersTableLayout.SetColumnSpan bestAlignButton 2 boxParametersTableLayout.Controls.Add bestAlignButton 0 0 boxParametersTableLayout.Controls.Add offsetTypeCheckButton 1 0 boxParametersTableLayout.Controls.Add percentTypeCheckButton 1 1 boxPaddingTypeCheck offsetTypeCheckButton "" boxParametersTableLayout ), --------------------------------------------------------------------------------------------------------------------------------------- -- dispatchSurfaceTypeButtonClick() Dispatches surfaceTypeButtonClick(), called when the user presses the surfaceTypeButton --------------------------------------------------------------------------------------------------------------------------------------- fn dispatchSurfaceTypeButtonClick s e = ( ::RSL_CollisionOps.createUI.surfaceTypeButtonClick s e ), --------------------------------------------------------------------------------------------------------------------------------------- -- surfaceTypeButtonClick() Displays the correct surface type dialog depending on the mode. --------------------------------------------------------------------------------------------------------------------------------------- fn surfaceTypeButtonClick s e = ( -- if the lastType is the mesh mode, we must create the surface type dialog in rexbound mode case lastType.name of ( default: ( ::RSL_CollisionOps.attribute.surfaceTypeDialog #primitive ) "meshCheckButton": ( ::RSL_CollisionOps.attribute.surfaceTypeDialog #rexbound ) ) ), --------------------------------------------------------------------------------------------------------------------------------------- -- dispatchPieceTypeButtonClick() Dispatches pieceTypeButtonClick(), called when the user presses the pieceTypeButton -- which is only available for collision primitives and not collision meshes --------------------------------------------------------------------------------------------------------------------------------------- fn dispatchPieceTypeButtonClick s e = ( ::RSL_CollisionOps.createUI.pieceTypeButtonClick s e ), --------------------------------------------------------------------------------------------------------------------------------------- -- pieceTypeButtonClick() Displays the piece type dialog --------------------------------------------------------------------------------------------------------------------------------------- fn pieceTypeButtonClick s e = ( ::RSL_CollisionOps.attribute.pieceTypeDialog() ), --------------------------------------------------------------------------------------------------------------------------------------- -- dispatchProceduralTypeButtonClick() Dispatches proceduralTypeButtonClick(), called when the user presses the proceduralTypeButton -- which is only available for collision meshes --------------------------------------------------------------------------------------------------------------------------------------- fn dispatchProceduralTypeButtonClick s e = ( ::RSL_CollisionOps.createUI.proceduralTypeButtonClick s e ), --------------------------------------------------------------------------------------------------------------------------------------- -- proceduralTypeButtonClick() Displays the procedural type dialog --------------------------------------------------------------------------------------------------------------------------------------- fn proceduralTypeButtonClick s e = ( ::RSL_CollisionOps.attribute.proceduralTypeDialog() ), --------------------------------------------------------------------------------------------------------------------------------------- -- dispatchMiloRoomButtonClick() Dispatches miloRoomButtonClick(), called when the user presses the miloRoomButton -- which is only available for collision meshes --------------------------------------------------------------------------------------------------------------------------------------- fn dispatchMiloRoomButtonClick s e = ( ::RSL_CollisionOps.createUI.miloRoomButtonClick s e ), --------------------------------------------------------------------------------------------------------------------------------------- -- miloRoomButtonClick() Displays the milo room dialog --------------------------------------------------------------------------------------------------------------------------------------- fn miloRoomButtonClick s e = ( ::RSL_CollisionOps.attribute.miloRoomDialog() ), --------------------------------------------------------------------------------------------------------------------------------------- -- createAttributeControls() Creates the attribute controls based on the parsed type which is either #primitive or #rexbound -- Returns the attributesTableLayout --------------------------------------------------------------------------------------------------------------------------------------- fn createAttributeControls type = ( attributesGroup.controls.clear() surfaceTypeLabel = RS_dotNetUI.Label "surfaceTypeLabel" text:" Surface Type:" textAlign:RS_dotNetPreset.CA_MiddleLeft \ borderStyle:RS_dotNetPreset.BS_None dockStyle:RS_dotNetPreset.DS_Fill surfaceTypeButton = RS_dotNetUI.Button "surfaceTypeButton" text:(::RSL_CollisionOps.attribute.lastType) dockStyle:RS_dotNetPreset.DS_Fill margin:(RS_dotNetObject.paddingObject 2) dotnet.addEventHandler surfaceTypeButton "click" dispatchSurfaceTypeButtonClick local colour = getINISetting INIFile "surfaceColours" ::RSL_CollisionOps.attribute.lastType if colour != "" then ( local colourValue = readExpr (colour as stringStream) surfaceTypeButton.backColor = RS_dotNetClass.colourClass.fromARGB colourValue.r colourValue.g colourValue.b ) collisionTypeLabel = RS_dotNetUI.Label "collisionTypeLabel" text:" Collision Type:" textAlign:RS_dotNetPreset.CA_MiddleLeft \ borderStyle:RS_dotNetPreset.BS_None dockStyle:RS_dotNetPreset.DS_Fill stairsCheckBox = RS_dotNetUI.checkBox "stairsCheckBox" text:("Stairs") dockStyle:RS_dotNetPreset.DS_Left textAlign:RS_dotNetPreset.CA_MiddleLeft --noCoverCheckBox = RS_dotNetUI.checkBox "noCoverCheckBox" text:("Does not Provide Cover") dockStyle:RS_dotNetPreset.DS_Fill textAlign:RS_dotNetPreset.CA_MiddleLeft noClimbCheckBox = RS_dotNetUI.checkBox "noClimbCheckBox" text:("Non Climable") dockStyle:RS_dotNetPreset.DS_Fill textAlign:RS_dotNetPreset.CA_MiddleLeft pathCheckBox = RS_dotNetUI.checkBox "pathCheckBox" text:("Path") dockStyle:RS_dotNetPreset.DS_Fill textAlign:RS_dotNetPreset.CA_MiddleLeft --noWalkCheckBox = RS_dotNetUI.checkBox "noWalkCheckBox" text:("Non Walkable") dockStyle:RS_dotNetPreset.DS_Fill seeCheckBox = RS_dotNetUI.checkBox "seeCheckBox" text:("See Through") dockStyle:RS_dotNetPreset.DS_Fill textAlign:RS_dotNetPreset.CA_MiddleLeft noCameraCheckBox = RS_dotNetUI.checkBox "noCameraCheckBox" text:("Non Camera Collidable") dockStyle:RS_dotNetPreset.DS_Fill textAlign:RS_dotNetPreset.CA_MiddleLeft shootCheckBox = RS_dotNetUI.checkBox "shootCheckBox" text:("Shoot Through") dockStyle:RS_dotNetPreset.DS_Fill textAlign:RS_dotNetPreset.CA_MiddleLeft attributesTableLayout = RS_dotNetUI.tableLayout "attributesTableLayout" text:"attributesTableLayout" \ collumns:#((dataPair type:"Percent" value:50),(dataPair type:"Percent" value:50)) \ rows:#((dataPair type:"Absolute" value:24),(dataPair type:"Absolute" value:20),(dataPair type:"Absolute" value:20),(dataPair type:"Absolute" value:20) ,(dataPair type:"Absolute" value:20)) \ dockStyle:RS_dotNetPreset.DS_Fill attributesTableLayout.controls.add surfaceTypeLabel 0 0 attributesTableLayout.controls.add surfaceTypeButton 1 0 attributesTableLayout.controls.add collisionTypeLabel 0 1 attributesTableLayout.controls.add stairsCheckBox 0 2 --attributesTableLayout.controls.add noCoverCheckBox 1 2 attributesTableLayout.controls.add noClimbCheckBox 1 2 attributesTableLayout.controls.add pathCheckBox 0 3 attributesTableLayout.controls.add seeCheckBox 1 3 attributesTableLayout.controls.add noCameraCheckBox 0 4 attributesTableLayout.controls.add shootCheckBox 1 4 --attributesTableLayout.controls.add noDecalCheckBox 1 5 --attributesTableLayout.controls.add noNavmeshCheckBox 0 6 --attributesTableLayout.controls.add noRagDollCheckBox 1 6 --attributesTableLayout.controls.add noParticleCheckBox 0 7 case type of ( #primitive: ( pieceLabel = RS_dotNetUI.Label "pieceLabel" text:" Piece Type:" textAlign:RS_dotNetPreset.CA_MiddleLeft \ borderStyle:RS_dotNetPreset.BS_None dockStyle:RS_dotNetPreset.DS_Fill pieceTypeButton = RS_dotNetUI.Button "pieceTypeButton" text:"DEFAULT" dockStyle:RS_dotNetPreset.DS_Fill margin:(RS_dotNetObject.paddingObject 2) dotnet.addEventHandler pieceTypeButton "click" dispatchPieceTypeButtonClick dayLabel = RS_dotNetUI.Label "dayLabel" text:" Day Brightness:" textAlign:RS_dotNetPreset.CA_MiddleLeft \ borderStyle:RS_dotNetPreset.BS_None dockStyle:RS_dotNetPreset.DS_Fill dayNumeric = RS_dotNetUI.Numeric "dayNumeric" value:11 range:#(15, 0, 1, 0) dockStyle:RS_dotNetPreset.DS_Fill -- dotnet.addEventHandler dayNumeric "ValueChanged" dispatchDayNumericChanged dotnet.addEventHandler dayNumeric "Enter" disableAccelerators nightLabel = RS_dotNetUI.Label "nightLabel" text:" Night Brightness:" textAlign:RS_dotNetPreset.CA_MiddleLeft \ borderStyle:RS_dotNetPreset.BS_None dockStyle:RS_dotNetPreset.DS_Fill nightNumeric = RS_dotNetUI.Numeric "nightNumeric" value:11 range:#(15, 0, 1, 0) dockStyle:RS_dotNetPreset.DS_Fill -- dotnet.addEventHandler nightNumeric "ValueChanged" dispatchDayNumericChanged dotnet.addEventHandler nightNumeric "Enter" disableAccelerators audioLabel = RS_dotNetUI.Label "audioLabel" text:" Audio Material:" textAlign:RS_dotNetPreset.CA_MiddleLeft \ borderStyle:RS_dotNetPreset.BS_None dockStyle:RS_dotNetPreset.DS_Fill audioTextBox = RS_dotNetUI.textBox "findTextBox" text:"" dockStyle:RS_dotNetPreset.DS_Fill dotnet.addEventHandler audioTextBox "Enter" disableAccelerators roomIDLabel = RS_dotNetUI.Label "roomIDLabel" text:" Room ID:" textAlign:RS_dotNetPreset.CA_MiddleLeft \ borderStyle:RS_dotNetPreset.BS_None dockStyle:RS_dotNetPreset.DS_Fill roomIDNumeric = RS_dotNetUI.Numeric "roomIDNumeric" value:0 range:#(1000, 0, 1, 0) dockStyle:RS_dotNetPreset.DS_Fill -- dotnet.addEventHandler roomIDNumeric "ValueChanged" dispatchRoomIDNumericChanged dotnet.addEventHandler roomIDNumeric "Enter" disableAccelerators --leedsCheckBox = RS_dotNetUI.checkBox "leedsCheckBox" text:("Edited by Leeds") dockStyle:RS_dotNetPreset.DS_Fill textAlign:RS_dotNetPreset.CA_MiddleLeft BVHCheckBox = RS_dotNetUI.checkBox "BVHCheckBox" text:("BVH Bound") dockStyle:RS_dotNetPreset.DS_Fill textAlign:RS_dotNetPreset.CA_MiddleLeft wetCheckBox = RS_dotNetUI.checkBox "wetCheckBox" text:("Wet") dockStyle:RS_dotNetPreset.DS_Fill textAlign:RS_dotNetPreset.CA_MiddleLeft pathCheckBox = RS_dotNetUI.checkBox "pathCheckBox" text:("Path") dockStyle:RS_dotNetPreset.DS_Fill textAlign:RS_dotNetPreset.CA_MiddleLeft procTintCheckBox = RS_dotNetUI.checkBox "procTintCheckBox" text:("Use Procedural Tint") dockStyle:RS_dotNetPreset.DS_Fill textAlign:RS_dotNetPreset.CA_MiddleLeft clothCollTintCheckBox = RS_dotNetUI.checkBox "clothCollCheckBox" text:("Is Cloth Collision") dockStyle:RS_dotNetPreset.DS_Fill textAlign:RS_dotNetPreset.CA_MiddleLeft attributesTableLayout.RowStyles.add (RS_dotNetObject.RowStyleObject "absolute" 24) attributesTableLayout.RowStyles.add (RS_dotNetObject.RowStyleObject "absolute" 24) attributesTableLayout.RowStyles.add (RS_dotNetObject.RowStyleObject "absolute" 24) attributesTableLayout.RowStyles.add (RS_dotNetObject.RowStyleObject "absolute" 24) attributesTableLayout.RowStyles.add (RS_dotNetObject.RowStyleObject "absolute" 24) attributesTableLayout.RowStyles.add (RS_dotNetObject.RowStyleObject "absolute" 24) attributesTableLayout.RowStyles.add (RS_dotNetObject.RowStyleObject "absolute" 24) attributesTableLayout.RowStyles.add (RS_dotNetObject.RowStyleObject "absolute" 24) --attributesTableLayout.RowStyles.add (RS_dotNetObject.RowStyleObject "absolute" 20) attributesTableLayout.controls.add pieceLabel 0 5 attributesTableLayout.controls.add pieceTypeButton 1 5 attributesTableLayout.controls.add dayLabel 0 6 attributesTableLayout.controls.add dayNumeric 1 6 attributesTableLayout.controls.add nightLabel 0 7 attributesTableLayout.controls.add nightNumeric 1 7 attributesTableLayout.controls.add audioLabel 0 8 attributesTableLayout.controls.add audioTextBox 1 8 attributesTableLayout.controls.add roomIDLabel 0 9 attributesTableLayout.controls.add roomIDNumeric 1 9 --attributesTableLayout.controls.add leedsCheckBox 0 11 attributesTableLayout.controls.add BVHCheckBox 0 10 attributesTableLayout.controls.add wetCheckBox 0 11 attributesTableLayout.controls.add pathCheckBox 1 11 attributesTableLayout.controls.add procTintCheckBox 0 12 attributesTableLayout.controls.add clothCollTintCheckBox 1 12 createTableLayout.RowStyles.Item[2].Height = 324 ) #rexbound: ( proceduralTypeLabel = RS_dotNetUI.Label "collisionTypeLabel" text:" Procedural Type:" textAlign:RS_dotNetPreset.CA_MiddleLeft \ borderStyle:RS_dotNetPreset.BS_None dockStyle:RS_dotNetPreset.DS_Fill proceduralTypeButton = RS_dotNetUI.Button "proceduralTypeButton" text:"NONE" dockStyle:RS_dotNetPreset.DS_Fill margin:(RS_dotNetObject.paddingObject 2) dotnet.addEventHandler proceduralTypeButton "click" dispatchProceduralTypeButtonClick pedMultiplierLabel = RS_dotNetUI.Label "collisionTypeLabel" text:" Ped Multiplier:" textAlign:RS_dotNetPreset.CA_MiddleLeft \ borderStyle:RS_dotNetPreset.BS_None dockStyle:RS_dotNetPreset.DS_Fill pedMultiplierLabel.enabled = true pedMultiplierNumeric = RS_dotNetUI.Numeric "ZPadding" value:0 range:#(7, 0, 1, 0) dockStyle:RS_dotNetPreset.DS_Fill pedMultiplierNumeric.enabled = true -- dotnet.addEventHandler pedMultiplierNumeric "ValueChanged" dispatchPedMultiplierChanged dotnet.addEventHandler pedMultiplierNumeric "Enter" disableAccelerators noCoverCheckBox = RS_dotNetUI.checkBox "noCoverCheckBox" text:("Does not Provide Cover") dockStyle:RS_dotNetPreset.DS_Fill textAlign:RS_dotNetPreset.CA_MiddleLeft noDecalCheckBox = RS_dotNetUI.checkBox "noDecalCheckBox" text:("No Decal") dockStyle:RS_dotNetPreset.DS_Fill textAlign:RS_dotNetPreset.CA_MiddleLeft noNavmeshCheckBox = RS_dotNetUI.checkBox "noNavMeshCheckBox" text:("No Navmesh") dockStyle:RS_dotNetPreset.DS_Fill textAlign:RS_dotNetPreset.CA_MiddleLeft noRagDollCheckBox = RS_dotNetUI.checkBox "noRagDollCheckBox" text:("No Ragdoll") dockStyle:RS_dotNetPreset.DS_Fill textAlign:RS_dotNetPreset.CA_MiddleLeft noParticleCheckBox = RS_dotNetUI.checkBox "noParticleCheckBox" text:("No Particle Effects") dockStyle:RS_dotNetPreset.DS_Fill textAlign:RS_dotNetPreset.CA_MiddleLeft miloRoomLabel = RS_dotNetUI.Label "miloRoomLabel" text:" Milo Room:" textAlign:RS_dotNetPreset.CA_MiddleLeft \ borderStyle:RS_dotNetPreset.BS_None dockStyle:RS_dotNetPreset.DS_Fill miloRoomButton = RS_dotNetUI.Button "miloRoomButton" text:"None" dockStyle:RS_dotNetPreset.DS_Fill margin:(RS_dotNetObject.paddingObject 2) dotnet.addEventHandler miloRoomButton "click" dispatchMiloRoomButtonClick attributesTableLayout.RowStyles.add (RS_dotNetObject.RowStyleObject "absolute" 24) attributesTableLayout.RowStyles.add (RS_dotNetObject.RowStyleObject "absolute" 24) attributesTableLayout.RowStyles.add (RS_dotNetObject.RowStyleObject "absolute" 20) attributesTableLayout.controls.add noCoverCheckBox 0 5 attributesTableLayout.controls.add noDecalCheckBox 1 5 attributesTableLayout.controls.add noNavmeshCheckBox 0 6 attributesTableLayout.controls.add noRagDollCheckBox 1 6 attributesTableLayout.controls.add noParticleCheckBox 0 7 attributesTableLayout.controls.add proceduralTypeLabel 0 8 attributesTableLayout.controls.add proceduralTypeButton 1 8 attributesTableLayout.controls.add pedMultiplierLabel 0 9 attributesTableLayout.controls.add pedMultiplierNumeric 1 9 attributesTableLayout.controls.add miloRoomLabel 0 10 attributesTableLayout.controls.add miloRoomButton 1 10 createTableLayout.RowStyles.Item[2].Height = 280 ) ) /* case attributesGroup.text of ( " Attributes - Advanced": ( if type == #rexbound then ( createTableLayout.RowStyles.Item[2].Height = 280 ) else ( createTableLayout.RowStyles.Item[2].Height = 358 ) ) " Attributes - Basic": ( createTableLayout.RowStyles.Item[2].Height = 128 ) ) */ attributesTableLayout ), --------------------------------------------------------------------------------------------------------------------------------------- -- dispatchCreateCheck() Dispatches createCheck(), called when the user presses any of the collision object type buttons --------------------------------------------------------------------------------------------------------------------------------------- fn dispatchCreateCheck s e = ( ::RSL_CollisionOps.createUI.createCheck s e ), --------------------------------------------------------------------------------------------------------------------------------------- -- createCheck() Switches the collision object type mode --------------------------------------------------------------------------------------------------------------------------------------- fn createCheck s e = ( -- set the pressed mode the true s.Checked = true -- if the last mode is not the pressed button, we need to create the controls for the chosen mode if s != lastType then ( case s.name of ( "boxCheckButton": ( -- un-check the other mode buttons sphereCheckButton.checked = false cylinderCheckButton.checked = false meshCheckButton.checked = false -- dispose of the currentTool, create the new controls and add them to the parametersGroup if currentTool != undefined then currentTool.Dispose() currentTool = createBoxTypeControls() parametersGroup.Controls.Add currentTool -- if the last controls were then mesh controls, we need to re-create the attributes for primitive collision objects /* if lastType != undefined and lastType.name == "meshCheckButton" then ( attributesGroup.controls.add (createAttributeControls #primitive) attributesGroup.controls.add expandButton ) */ attributesGroup.controls.add (createAttributeControls #primitive) RSL_CollisionOps.CollisionForm.Height = 744 ) "sphereCheckButton": ( -- un-check the other mode buttons boxCheckButton.checked = false cylinderCheckButton.checked = false meshCheckButton.checked = false -- dispose of the currentTool, create the new controls and add them to the parametersGroup if currentTool != undefined then currentTool.Dispose() currentTool = createSphereTypeControls() parametersGroup.Controls.Add currentTool -- set the height for the row createTableLayout.RowStyles.Item[1].Height = 51 -- set the height of the main form depending on the expanded state of the attributes group /* case attributesGroup.text of ( " Attributes - Basic":(::RSL_CollisionOps.CollisionForm.Height = 386) " Attributes - Advanced":(::RSL_CollisionOps.CollisionForm.Height = 616) ) */ RSL_CollisionOps.CollisionForm.Height = 580 -- if the last controls were then mesh controls, we need to re-create the attributes for primitive collision objects /* if lastType != undefined and lastType.name == "meshCheckButton" then ( attributesGroup.controls.add (createAttributeControls #primitive) attributesGroup.controls.add expandButton ) */ attributesGroup.controls.add (createAttributeControls #primitive) ) "cylinderCheckButton": ( -- un-check the other mode buttons sphereCheckButton.checked = false boxCheckButton.checked = false meshCheckButton.checked = false -- dispose of the currentTool, create the new controls and add them to the parametersGroup if currentTool != undefined then currentTool.Dispose() currentTool = createCylinderTypeControls() parametersGroup.Controls.Add currentTool -- set the height for the row createTableLayout.RowStyles.Item[1].Height = 99 -- set the height of the main form depending on the expanded state of the attributes group /* case attributesGroup.text of ( " Attributes - Basic":(::RSL_CollisionOps.CollisionForm.Height = 434) " Attributes - Advanced":(::RSL_CollisionOps.CollisionForm.Height = 664) ) */ RSL_CollisionOps.CollisionForm.Height = 634 -- if the last controls were then mesh controls, we need to re-create the attributes for primitive collision objects /* if lastType != undefined and lastType.name == "meshCheckButton" then ( attributesGroup.controls.add (createAttributeControls #primitive) attributesGroup.controls.add expandButton ) */ attributesGroup.controls.add (createAttributeControls #primitive) ) "meshCheckButton": ( -- un-check the other mode buttons sphereCheckButton.checked = false cylinderCheckButton.checked = false boxCheckButton.checked = false -- dispose of the currentTool, create the new controls and add them to the parametersGroup if currentTool != undefined then currentTool.Dispose() currentTool = createMeshTypeControls() parametersGroup.Controls.Add currentTool -- set the height for the row createTableLayout.RowStyles.Item[1].Height = 99 -- set the height of the main form depending on the expanded state of the attributes group /* case attributesGroup.text of ( " Attributes - Basic":(::RSL_CollisionOps.CollisionForm.Height = 434) " Attributes - Advanced":(::RSL_CollisionOps.CollisionForm.Height = 586) ) */ RSL_CollisionOps.CollisionForm.Height = 585 -- re-create the attributes for rexbound collision meshes attributesGroup.controls.add (createAttributeControls #rexbound) --attributesGroup.controls.add expandButton ) ) ) lastType = s ), /* --------------------------------------------------------------------------------------------------------------------------------------- -- dispatchAttributesClick() Dispatches attributesClick(), called when the user double clicks the attributesGroup --------------------------------------------------------------------------------------------------------------------------------------- fn dispatchAttributesClick s e = ( ::RSL_CollisionOps.createUI.attributesClick s e ), --------------------------------------------------------------------------------------------------------------------------------------- -- attributesClick() Expands or contracts the attributesGroup - deprecated --------------------------------------------------------------------------------------------------------------------------------------- fn attributesClick s e = ( case attributesGroup.text of ( -- expand the attributesGroup and depending on which collision object mode is pressed, set the correct height -- for the row and the main form " Attributes - Basic": ( case lastType.name of ( "boxCheckButton": ( if lastBoxType.name == "offsetTypeCheckButton" then ( ::RSL_CollisionOps.CollisionForm.Height = 785 ) else ( ::RSL_CollisionOps.CollisionForm.Height = 736 ) createTableLayout.RowStyles.Item[2].Height = 358 ) "sphereCheckButton": ( createTableLayout.RowStyles.Item[2].Height = 358 ::RSL_CollisionOps.CollisionForm.Height = 616 ) "cylinderCheckButton": ( createTableLayout.RowStyles.Item[2].Height = 358 ::RSL_CollisionOps.CollisionForm.Height = 664 ) "meshCheckButton": ( createTableLayout.RowStyles.Item[2].Height = 280 ::RSL_CollisionOps.CollisionForm.Height = 588 ) ) s.text = "-" attributesGroup.text = " Attributes - Advanced" ) -- contract the attributesGroup and depending on which collision object mode is pressed, set the correct height -- for the row and the main form " Attributes - Advanced": ( case lastType.name of ( "boxCheckButton": ( if lastBoxType.name == "offsetTypeCheckButton" then ( ::RSL_CollisionOps.CollisionForm.Height = 554 ) else ( ::RSL_CollisionOps.CollisionForm.Height = 506 ) ) "sphereCheckButton": ( ::RSL_CollisionOps.CollisionForm.Height = 384 ) "cylinderCheckButton": ( ::RSL_CollisionOps.CollisionForm.Height = 434 ) "meshCheckButton": ( ::RSL_CollisionOps.CollisionForm.Height = 434 ) ) createTableLayout.RowStyles.Item[2].Height = 128 s.text = "+" attributesGroup.text = " Attributes - Basic" ) ) ::RSL_CollisionOps.CollisionForm.focus() ), */ --------------------------------------------------------------------------------------------------------------------------------------- -- dispatchCreateButtonClick() Dispatches createButtonClick(), called when the user presses the createButton --------------------------------------------------------------------------------------------------------------------------------------- fn dispatchCreateButtonClick s e = ( ::RSL_CollisionOps.createUI.createButtonClick s e ), --------------------------------------------------------------------------------------------------------------------------------------- -- createButtonClick() Creates a new collision object based on the chosen type and parameters --------------------------------------------------------------------------------------------------------------------------------------- fn createButtonClick s e = ( local faceSelection newCollisionMeshArray = #() -- if only one object is selected, we can attempt to get the faceSelection if the object has selected faces if ::RSL_CollisionOps.theObjects.count == 1 then ( -- make sure we're in the max modify panel and we're at one of the valid sub object levels for faces local modify = getCommandPanelTaskMode() == #modify local faceMode = subObjectLevel == 4 or subObjectLevel == 5 or (subObjectLevel == 3 and (classOf ::RSL_CollisionOps.theObjects[1]) == editable_mesh) local selectedCount = ::RSL_CollisionOps.theObjects[1].SelectedFaces.count -- if we are in the right mode and we have selected faces, we assign the selected indices to faceSelection -- otherwise we assign all the faces' indices in the object to faceSelection if modify and faceMode and selectedCount > 0 then ( faceSelection = for face in ::RSL_CollisionOps.theObjects[1].selectedFaces collect face.index ) else ( faceSelection = for face in ::RSL_CollisionOps.theObjects[1].faces collect face.index ) ) -- loop through each selected object creating the chosen collision object for object in ::RSL_CollisionOps.theObjects do ( -- set the faceSelection to all the faces in the object if we have multiple objects selected if ::RSL_CollisionOps.theObjects.count > 1 then ( faceSelection = for face in object.faces collect face.index ) if boxCheckButton.Checked then ( makeBox object faceSelection ) if meshCheckButton.Checked then ( makeMesh object faceSelection ) if sphereCheckButton.Checked then ( makeSphere object faceSelection ) if cylinderCheckButton.Checked then ( makeCylinder object faceSelection ) ) ), --------------------------------------------------------------------------------------------------------------------------------------- -- dispatchDeleteButtonClick() Dispatches deleteButtonClick(), called when the user presses the deleteButton --------------------------------------------------------------------------------------------------------------------------------------- fn dispatchDeleteButtonClick s e = ( ::RSL_CollisionOps.createUI.deleteButtonClick s e ), --------------------------------------------------------------------------------------------------------------------------------------- -- deleteButtonClick() Deletes all the object found in the newCollisionMeshArray. When a collision object is created, it is -- added to this array. --------------------------------------------------------------------------------------------------------------------------------------- fn deleteButtonClick s e = ( try (delete newCollisionMeshArray) catch() ), --------------------------------------------------------------------------------------------------------------------------------------- -- getUI() Creates the UI for create mode --------------------------------------------------------------------------------------------------------------------------------------- fn getUI = ( boxCheckButton = RS_dotNetUI.checkBox "boxCheckButton" text:(toUpper "Box") appearance:RS_dotNetPreset.AC_Button dockStyle:RS_dotNetPreset.DS_Fill dotnet.addEventHandler boxCheckButton "click" dispatchCreateCheck boxCheckButton.checked = true sphereCheckButton = RS_dotNetUI.checkBox "sphereCheckButton" text:(toUpper "Sphere") appearance:RS_dotNetPreset.AC_Button dockStyle:RS_dotNetPreset.DS_Fill dotnet.addEventHandler sphereCheckButton "click" dispatchCreateCheck cylinderCheckButton = RS_dotNetUI.checkBox "cylinderCheckButton" text:(toUpper "Cylinder") appearance:RS_dotNetPreset.AC_Button dockStyle:RS_dotNetPreset.DS_Fill dotnet.addEventHandler cylinderCheckButton "click" dispatchCreateCheck meshCheckButton = RS_dotNetUI.checkBox "meshCheckButton" text:(toUpper "Mesh") appearance:RS_dotNetPreset.AC_Button dockStyle:RS_dotNetPreset.DS_Fill dotnet.addEventHandler meshCheckButton "click" dispatchCreateCheck parametersGroup = RS_dotNetUI.GroupBox "parametersGroup" Text:"Parameters" dockStyle:RS_dotNetPreset.DS_Fill --expandButton = RS_dotNetUI.Button "expandButton" text:"-" size:[14,14] location:[8,0] margin:(RS_dotNetObject.paddingObject 2) -- expandButton.FlatStyle = RS_dotNetPreset.FS_Flat --expandButton.Font = dotNetObject "System.Drawing.Font" "Small Fonts" 7.0 RS_dotNetPreset.f_Regular--RS_dotNetPreset.FontSmall -- expandButton.TextAlign = (dotNetClass "System.Drawing.ContentAlignment").MiddleCenter --dotnet.addEventHandler expandButton "click" dispatchAttributesClick attributesGroup = RS_dotNetUI.GroupBox "parametersGroup" Text:"Attributes" dockStyle:RS_dotNetPreset.DS_Fill -- dotnet.addEventHandler attributesGroup "MouseDoubleClick" dispatchAttributesClick -- toolTip.SetToolTip attributesGroup "Double Click to expand/Contract Attributes" createButton = RS_dotNetUI.Button "createButton" text:"Create" dockStyle:RS_dotNetPreset.DS_Fill margin:(RS_dotNetObject.paddingObject 2) createButton.enabled = false dotnet.addEventHandler createButton "click" dispatchCreateButtonClick deleteButton = RS_dotNetUI.Button "deleteButton" text:"Delete Last" dockStyle:RS_dotNetPreset.DS_Fill margin:(RS_dotNetObject.paddingObject 2) dotnet.addEventHandler deleteButton "click" dispatchDeleteButtonClick createDeleteTableLayout = RS_dotNetUI.tableLayout "createDeleteTableLayout" text:"createDeleteTableLayout" \ collumns:#((dataPair type:"Percent" value:50)) rows:#((dataPair type:"Absolute" value:24),(dataPair type:"Absolute" value:24)) \ dockStyle:RS_dotNetPreset.DS_Fill createDeleteTableLayout.controls.add createButton 0 0 createDeleteTableLayout.controls.add deleteButton 0 1 createGroup = RS_dotNetUI.GroupBox "createGroup" Text:"Create/Delete" dockStyle:RS_dotNetPreset.DS_Fill createGroup.controls.add createDeleteTableLayout statusLabel = RS_dotNetUI.Label "statusLabel" text:" Selected:" textAlign:RS_dotNetPreset.CA_MiddleLeft \ borderStyle:RS_dotNetPreset.BS_None dockStyle:RS_dotNetPreset.DS_Fill createTableLayout = RS_dotNetUI.tableLayout "createTableLayout" text:"createTableLayout" \ collumns:#((dataPair type:"Percent" value:50),(dataPair type:"Percent" value:50),(dataPair type:"Percent" value:50),(dataPair type:"Percent" value:50)) \ rows:#((dataPair type:"Absolute" value:24),(dataPair type:"Absolute" value:120),(dataPair type:"Absolute" value:100),(dataPair type:"Absolute" value:74) \ ,(dataPair type:"Absolute" value:24),(dataPair type:"Absolute" value:24)) \ dockStyle:RS_dotNetPreset.DS_Fill createTableLayout.controls.add boxCheckButton 0 0 createTableLayout.controls.add sphereCheckButton 1 0 createTableLayout.controls.add cylinderCheckButton 2 0 createTableLayout.controls.add meshCheckButton 3 0 createTableLayout.controls.add parametersGroup 0 1 createTableLayout.controls.add attributesGroup 0 2 createTableLayout.controls.add createGroup 0 3 createTableLayout.controls.add statusLabel 0 4 createTableLayout.SetColumnSpan parametersGroup 4 createTableLayout.SetColumnSpan attributesGroup 4 createTableLayout.SetColumnSpan createGroup 4 createTableLayout.SetColumnSpan statusLabel 4 createCheck boxCheckButton "" attributesGroup.controls.add (createAttributeControls #primitive) --attributesGroup.controls.add expandButton createTableLayout ) )