--------------------------------------------------------------------------------------------------------------------------------------- -- RSL_CollisionOps2Edit -- 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 edit mode --------------------------------------------------------------------------------------------------------------------------------------- -- Struct used to store per material rexbound data gathered from the currentMesh struct RSL_RexBoundData ( --------------------------------------------------------------------------------------------------------------------------------------- -- Struct variables --------------------------------------------------------------------------------------------------------------------------------------- surfaceType, flags = 0, proceduralType = -1, miloRoom = -1, faceArray = #(), ID = 1, --------------------------------------------------------------------------------------------------------------------------------------- -- -- FUNCTIONS -- --------------------------------------------------------------------------------------------------------------------------------------- --------------------------------------------------------------------------------------------------------------------------------------- -- compare() Compares the parsed data which is a RSL_RexBoundData with the struct variables. Returns true if they are the same. -- faceArray and ID struct variables are ignored. --------------------------------------------------------------------------------------------------------------------------------------- fn compare data = ( local result = true if data.surfaceType != surfaceType then result = false if data.flags != flags then result = false if data.proceduralType != proceduralType then result = false if data.miloRoom != miloRoom then result = false result ), --------------------------------------------------------------------------------------------------------------------------------------- -- compareType() Compares the surfaceType for the parsed data which is a RSL_RexBoundData with the surfaceType struct variable. -- Returns true if they are the same. faceArray and ID struct variables are ignored. --------------------------------------------------------------------------------------------------------------------------------------- fn compareType data = ( data.surfaceType == surfaceType ), --------------------------------------------------------------------------------------------------------------------------------------- -- compareAttr() Compares the attributes for the parsed data which is a RSL_RexBoundData with the attributes of the struct. -- Returns true if they are the same. faceArray and ID struct variables are ignored. --------------------------------------------------------------------------------------------------------------------------------------- fn compareAttr data = ( local result = true if data.flags != flags then result = false if data.proceduralType != proceduralType then result = false if data.miloRoom != miloRoom then result = false result ) ) -- main struct struct RSL_CollisionOps2Edit ( --------------------------------------------------------------------------------------------------------------------------------------- -- Struct variables --------------------------------------------------------------------------------------------------------------------------------------- INIfile = (RsConfigGetWildWestDir() + "script\\max\\Rockstar_London\\config\\collisionOps2.ini"), -- 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", -- surface type used if we cannot get the correct surface type from the object defaultType = "DEFAULT", displayBitmapArray = #(), -- SimpleFaceData IDs surfaceTypeID = #(0x3b6adfa6, 0xec24cd5), flagsID = #(0x38aacec5, 0x12f38bdc), proceduralTypeID = #(0x5c8d87e0, 0x63ac911b), miloRoomID = #(0x10ec28e7, 0x106a0362), -- SimpleFaceData channel variables surfaceChannel, flagsChannel, proceduralChannel, miloRoomChannel, pickType, mouseTrackType, selectType, assignType, --------------------------------------------------------------------------------------------------------------------------------------- -- UI variables --------------------------------------------------------------------------------------------------------------------------------------- pallette,searchTextBox,attributesGroup,pickGroup,selectGroup,assignGroup,editTableLayout, attributesTableLayout, stairsCheckBox,noCoverCheckBox,noClimbCheckBox,noWalkCheckBox,seeCheckBox,noCameraCheckBox,shootCheckBox, stairsSelectButton,noCoverSelectButton,noClimbSelectButton,noWalkSelectButton,seeSelectButton,noCamSelectButton,shootSelectButton, pieceTypeButton,dayNumeric,nightNumeric,audioTextBox,roomIDNumeric,BVHCheckBox,procTintCheckBox,clothCollCheckBox, proceduralTypeButton,pedMultiplierNumeric,miloRoomButton, toolTip = dotNetObject "ToolTip", --------------------------------------------------------------------------------------------------------------------------------------- -- -- FUNCTIONS -- --------------------------------------------------------------------------------------------------------------------------------------- --------------------------------------------------------------------------------------------------------------------------------------- -- disableAccelerators() Called when the user enters any control that needs keyboard input e.g. a textBox --------------------------------------------------------------------------------------------------------------------------------------- fn disableAccelerators s e = ( enableAccelerators = false ), --------------------------------------------------------------------------------------------------------------------------------------- -- isUsedInObject() Checks the parsed object to see if the parsed ID is used in the object. -- Returns true if the ID and therefore the material is used. --------------------------------------------------------------------------------------------------------------------------------------- fn isUsedInObject object ID = ( -- create a temp mesh object so that we dont have to worry about object class when getting the material ID from the face local tempMesh = snapshotasmesh object local result = false for face in tempMesh.faces do ( if (getFaceMatID tempMesh face.index) == ID then ( result = true exit ) ) delete tempMesh result ), --------------------------------------------------------------------------------------------------------------------------------------- -- getType() Checks the class of the object and returns the type. #rexbound if it's a collision mesh or #primitive for any other -- class of collision object --------------------------------------------------------------------------------------------------------------------------------------- fn getType object = ( if (classOf object) == Col_Mesh then ( #rexbound ) else ( #primitive ) ), --------------------------------------------------------------------------------------------------------------------------------------- -- findID() Searches the parsed array for any item with the same ID as the parsed ID. Returns the index if found or 0 --------------------------------------------------------------------------------------------------------------------------------------- fn findID array ID = ( local result = 0 for i = 1 to array.count where array[i] != undefined do ( if array[i].ID == ID then ( result = i ) ) result ), --------------------------------------------------------------------------------------------------------------------------------------- -- getIDFaceArray() Gathers a dataPair for each unique material ID found on the object and an array of faces assigned that ID. -- Returns an array of all the unique dataPairs --------------------------------------------------------------------------------------------------------------------------------------- fn getIDFaceArray object = ( local result = #() for face in object.faces do ( -- get the ID from the face local ID = (getFaceMatID object face.index) -- check that we don't alreadi have a dataPair for that ID local index = findID result ID -- if we do then append the face.index to the faceArray of the found dataPair. Other wise we -- create a new dataPair and append it to the result array if index > 0 then ( append result[index].faceArray face.index ) else ( append result (dataPair ID:ID faceArray:#(face.index)) ) ) result ), --------------------------------------------------------------------------------------------------------------------------------------- -- fixMatIDs() Fixes any out of range IDs e.g. ID:10 when there are only 5 sub materials assigned. --------------------------------------------------------------------------------------------------------------------------------------- fn fixMatIDs array object = ( local result = #() local materialCount = object.material.numSubs for entry in array do ( if entry.ID > materialCount then ( -- fix the ID if it's out of range. If it's not, it will return the same value local newID = int (mod entry.ID materialCount) if newID == 0 then ( newID = materialCount ) -- check to see if we already have a dataPair with that ID in the parsed array local index = findID array newID if index > 0 then ( -- check to see if we already have a dataPair with that ID in the result array local fIndex = findID result newID -- if we do have one in the result array, we add the face indices from the entry dataPair to the -- found dataPair faceArray in the result array. Otherwise we create a new dataPair with the combined -- faceArrays from the entry dataPair and the array[index] dataPair. if fIndex > 0 then ( result[fIndex].faceArray = makeUniqueArray (result[fIndex].faceArray + entry.faceArray) ) else ( append result (dataPair ID:newID faceArray:(makeUniqueArray (array[index].faceArray + entry.faceArray))) ) ) else ( append result (dataPair ID:newID faceArray:entry.faceArray) ) ) else ( append result entry ) ) result ), --------------------------------------------------------------------------------------------------------------------------------------- -- compareID() Qsort function used to compare ID variables --------------------------------------------------------------------------------------------------------------------------------------- fn compareID v1 v2 = ( case of ( (v1.ID > v2.ID):1 (v1.ID < v2.ID):-1 default:0 ) ), --------------------------------------------------------------------------------------------------------------------------------------- -- setID() Mapped function to set the face ID on editable meshes --------------------------------------------------------------------------------------------------------------------------------------- mapped fn setID face object ID = ( setFaceMatID object face ID ), --------------------------------------------------------------------------------------------------------------------------------------- -- reNumberMatIDs() Re-numbers the IDs in the parsed array and sets the face IDs on the parsed object --------------------------------------------------------------------------------------------------------------------------------------- fn reNumberMatIDs array object = ( for i = 1 to array.count do ( setID array[i].faceArray object i array[i].ID = i ) ), --------------------------------------------------------------------------------------------------------------------------------------- -- findRexBoundData() Searches the parsed array for the parse data. Returns the index in the array or 0 --------------------------------------------------------------------------------------------------------------------------------------- fn findRexBoundData array data = ( local result = 0 for i = 1 to array.count do ( if (data.compare array[i]) then ( result = i exit ) ) result ), --------------------------------------------------------------------------------------------------------------------------------------- -- getFlagsFromAttributes() Generates a rexBound flag integer from the standard attributes of the parsed object --------------------------------------------------------------------------------------------------------------------------------------- fn getFlagsFromAttributes object = ( local result = 0 if (try(getAttr object idxStairs) catch (false)) == true then ( result = bit.or result (bit.shift 1 0) ) if (try(getAttr object idxNoClimb) catch (false)) == true then ( result = bit.or result (bit.shift 1 1) ) if (try(getAttr object idxSee) catch (false)) == true then ( result = bit.or result (bit.shift 1 2) ) if (try(getAttr object idxShoot) catch (false)) == true then ( result = bit.or result (bit.shift 1 3) ) if (try(getAttr object idxWet) catch (false)) == true then ( result = bit.or result (bit.shift 1 4) ) if (try(getAttr object idxPath) catch (false)) == true then ( result = bit.or result (bit.shift 1 5) ) /* if (try(getAttr object idxLeeds) catch (false)) == true then ( result = bit.or result (bit.shift 1 6) ) */ if (try(getAttr object idxNoCamera) catch (false)) == true then ( result = bit.or result (bit.shift 1 7) ) if (try(getAttr object idxBVH) catch (false)) == true then ( result = bit.or result (bit.shift 1 8) ) if (try(getAttr object idxProcTint) catch (false)) == true then ( result = bit.or result (bit.shift 1 9) ) if (try(getAttr object idxClothColl) catch (false)) == true then ( result = bit.or result (bit.shift 1 10) ) result ), --------------------------------------------------------------------------------------------------------------------------------------- -- getFaceDataFromMaterial() Generates an array of RSL_RexBoundData structs from the parsed material if it is a rexBound -- material or a multimaterial with rexBound materials. Uses the parsed attributeData if the material is not a rexBound material -- or a multimaterial. --------------------------------------------------------------------------------------------------------------------------------------- fn getFaceDataFromMaterial material object attributeData = ( local result = #() local default = (findItem ::RSL_CollisionOps.attribute.fullMaterialsDatSurfaceTypeArray defaultType) case (classOf material) of ( default: ( -- the material is not a rexBoung material or a multimaterial so we must use the standard attributes of the parsed object attributeData.faceArray = (for f in object.faces collect f.index) append result attributeData ) RexBoundMtl: ( -- it's a rexBound material so we can gather the data from the material local newData = RSL_RexBoundData surfaceType:default faceArray:(for f in object.faces collect f.index) local type = findItem ::RSL_CollisionOps.attribute.fullMaterialsDatSurfaceTypeArray (toUpper (RexGetCollisionName material)) local flags = RexGetCollisionFlags material local proc = findItem ::RSL_CollisionOps.attribute.proceduralArray (RexGetProceduralName material) if proc == 0 then proc = -1 local miloHandle = -1 local miloRoom = (RexGetRoomNode material) if (isValidNode miloRoom) then ( miloHandle = miloRoom.inode.handle ) if type > 0 then ( newData.surfaceType = type ) newData.flags = flags newData.proceduralType = proc newData.miloRoom = miloHandle append result newData ) Multimaterial: ( -- gather the face ID data and sort the array. Fix the ID is needed at the same time local IDArray = fixMatIDs (getIDFaceArray object) object qSort IDArray compareID -- for each data in the array we create a RSL_RexBoundData struct. We setup the struct as a default struct -- in case the sub material the ID points to is not a rexBound material for IDData in IDArray do ( local newData = RSL_RexBoundData surfaceType:default faceArray:IDData.faceArray ID:IDData.ID -- check to see if the ID exists in the materialIDList idxID = findItem material.materialIDList IDData.ID -- if it does, we can attempt to get the data. Otherwise we leave the RSL_RexBoundData struct as default if idxID > 0 then ( local subMaterial = object.material.materialList[idxID] -- if the subMaterial is a rexBound material, get the data from the material if (classOf subMaterial) == RexBoundMtl then ( local type = findItem ::RSL_CollisionOps.attribute.fullMaterialsDatSurfaceTypeArray (toUpper (RexGetCollisionName subMaterial)) local flags = RexGetCollisionFlags subMaterial local proc = findItem ::RSL_CollisionOps.attribute.proceduralArray (RexGetProceduralName subMaterial) if proc == 0 then proc = -1 -- -1 because dotNet indices start at 0 local miloHandle = -1 -- -1 just in case local miloRoom = (RexGetRoomNode subMaterial) -- if the miloRoom is a valid node e.g. it's not been deleted, we get the handle if (isValidNode miloRoom) then ( miloHandle = miloRoom.inode.handle ) if type > 0 then ( newData.surfaceType = type ) newData.flags = flags newData.proceduralType = proc newData.miloRoom = miloHandle ) ) else ( ) -- check to see if we already have a RSL_RexBoundData struct in the array that matches our newly created struct -- We do this to avoid duplicates local index = findRexBoundData result newData -- if we don't, we append the new RSL_RexBoundData struct to the result array if index == 0 then ( append result newData ) else ( -- we already have a RSL_RexBoundData struct that matches so we set the face ID to the found struct's ID -- and add teh faceArray to the found struct setID IDData.faceArray object result[index].ID join result[index].faceArray IDData.faceArray ) ) ) ) reNumberMatIDs result object result ), --------------------------------------------------------------------------------------------------------------------------------------- -- setData() sets the value for each parsed face to the parse value in the parsed faceChannel --------------------------------------------------------------------------------------------------------------------------------------- mapped fn setData face faceChannel value = ( faceChannel.setValue face value ), --------------------------------------------------------------------------------------------------------------------------------------- -- setFaceData() Sets the face data for all the face channels on the parsed objects using the parsed data --------------------------------------------------------------------------------------------------------------------------------------- fn setFaceData object data = ( -- add the face data channels to the parsed object surfaceChannel = simpleFaceManager.addChannel object id:surfaceTypeID flagsChannel = simpleFaceManager.addChannel object id:flagsID proceduralChannel = simpleFaceManager.addChannel object id:proceduralTypeID miloRoomChannel = simpleFaceManager.addChannel object id:miloRoomID for entry in data do ( setData entry.faceArray surfaceChannel entry.surfaceType setData entry.faceArray flagsChannel entry.flags setData entry.faceArray proceduralChannel entry.proceduralType setData entry.faceArray miloRoomChannel entry.miloRoom ) ), --------------------------------------------------------------------------------------------------------------------------------------- -- getFaceData() Generates an array of RSL_RexBoundData structs from the faces of the parsed object. InputArray is -- used when we want to get the data from a particular array of faces in the parsed object --------------------------------------------------------------------------------------------------------------------------------------- fn getFaceData object inputArray:undefined = ( local result = #() local faceArray -- setup faceArray depending on weather inputArray is undefined of not. if inputArray != undefined then ( faceArray = inputArray ) else ( faceArray = object.faces ) -- get the data for each face in faceArray for face in faceArray do ( local newData = RSL_RexBoundData surfaceType:(surfaceChannel.getValue face.index) faceArray:#(face.index) newData.flags = flagsChannel.getValue face.index newData.proceduralType = proceduralChannel.getValue face.index newData.miloRoom = miloRoomChannel.getValue face.index -- check to see if we already have a RSL_RexBoundData struct that matches our newly created struct local index = findRexBoundData result newData -- if we do, we append the face index to the faceArray of the found struct if index > 0 then ( append result[index].faceArray face.index ) else ( append result newData ) ) -- we only use inputArray when we want to get the data for a particular set of faces and only when we want to update -- the UI. When we want to get all the data, we might have changed the data so we make sure the faces have the correct -- IDs if inputArray == undefined then ( for i = 1 to result.count do ( setID result[i].faceArray object i result.ID = i ) ) result ), --------------------------------------------------------------------------------------------------------------------------------------- -- setDisplayMaterial() Generates a display material for the parsed object based on the parsed faceData --------------------------------------------------------------------------------------------------------------------------------------- fn setDisplayMaterial object faceData = ( local displayMaterial displayBitmapArray = #() -- if there's more than one set of face data, we create a Multimaterial if faceData.count > 1 then ( displayMaterial = Multimaterial numSubs:faceData.count name:"RSL_CollisionOps_Display" for i = 1 to faceData.count do ( local data = faceData[i] local surfaceType = ::RSL_CollisionOps.attribute.fullMaterialsDatSurfaceTypeArray[data.surfaceType] local collisionBitmap = ::RSL_CollisionOps.attribute.textureDirectory + surfaceType + ".bmp" local subMaterial = standardMaterial name:(surfaceType + " - " + i as string) diffuseMap:(bitmapTexture filename:collisionBitmap) --showInViewport:true -- set the opacity so that in shaded mode, we can see the render geometry behide the collision mesh. -- set the self illumination so that the collision geometry is always visible. subMaterial.opacity = 75 subMaterial.selfIllumAmount = 50 showTextureMap subMaterial subMaterial.diffuseMap true displayMaterial.materialList[i] = subMaterial displayMaterial.names[i] = surfaceType append displayBitmapArray subMaterial.diffuseMap ) ) else ( local surfaceType = ::RSL_CollisionOps.attribute.fullMaterialsDatSurfaceTypeArray[faceData[1].surfaceType] local collisionBitmap = ::RSL_CollisionOps.attribute.textureDirectory + surfaceType + ".bmp" displayMaterial = standardMaterial name:"RSL_CollisionOps_Display" diffuseMap:(bitmapTexture filename:collisionBitmap) --showInViewport:true -- set the opacity so that in shaded mode, we can see the render geometry behide the collision mesh. -- set the self illumination so that the collision geometry is always visible. displayMaterial.opacity = 75 displayMaterial.selfIllumAmount = 50 showTextureMap displayMaterial displayMaterial.diffuseMap true append displayBitmapArray displayMaterial.diffuseMap ) -- store the sub level if needed and then set it to 0 so that when we assign the material, -- we do not accidentally assign it to a face selection local level if subObjectLevel > 0 then ( level = subObjectLevel subObjectLevel = 0 ) object.material = displayMaterial -- if we've stored the sub level before we assigned the material, set it back again if level != undefined then ( subObjectLevel = level ) ), --------------------------------------------------------------------------------------------------------------------------------------- -- setRexBoundAttributes() Set the parsed data attributes on the parsed material which is a rexdBound material --------------------------------------------------------------------------------------------------------------------------------------- fn setRexBoundAttributes material data = ( RexSetCollisionName material ::RSL_CollisionOps.attribute.fullMaterialsDatSurfaceTypeArray[data.surfaceType] if data.proceduralType > 0 then ( RexSetProceduralName material ::RSL_CollisionOps.attribute.proceduralArray[data.proceduralType] ) if data.miloRoom > 0 then ( local miloRoom = maxOps.getNodeByHandle data.miloRoom if (isValidNode miloRoom) and (classOf miloRoom) == GtaMloRoom then ( RexSetRoomNode material miloRoom ) ) RexsetCollisionFlags material data.flags ), --------------------------------------------------------------------------------------------------------------------------------------- -- setRexBoundMaterial() Creates a rexBound material or series of rexBound materials for the parsed object based on the -- parsed faceData --------------------------------------------------------------------------------------------------------------------------------------- fn setRexBoundMaterial object faceData = ( local rexBoundMaterial -- if we have more than one set of faceData, we create a multimaterial if faceData.count > 1 then ( rexBoundMaterial = Multimaterial numSubs:faceData.count name:(Object.name) for i = 1 to faceData.count do ( local data = faceData[i] local surfaceType = ::RSL_CollisionOps.attribute.fullMaterialsDatSurfaceTypeArray[data.surfaceType] setID data.faceArray object i local subMaterial = RexBoundMtl name:(Object.name + " - " + surfaceType + " " + i as string) setRexBoundAttributes subMaterial data rexBoundMaterial.materialList[i] = subMaterial rexBoundMaterial.names[i] = surfaceType ) ) else ( rexBoundMaterial = RexBoundMtl name:(Object.name) setRexBoundAttributes rexBoundMaterial faceData[1] setID faceData[1].faceArray object 1 ) object.material = rexBoundMaterial ), --------------------------------------------------------------------------------------------------------------------------------------- -- getAttributeData() Creates and returns an RSL_RexBoundData struct based on the standard attributes of the parsed object. --------------------------------------------------------------------------------------------------------------------------------------- fn getAttributeData object = ( local result = RSL_RexBoundData surfaceType:(findItem ::RSL_CollisionOps.attribute.fullMaterialsDatSurfaceTypeArray (toUpper (getAttr object idxColType))) result.flags = getFlagsFromAttributes object result ), --------------------------------------------------------------------------------------------------------------------------------------- -- setEdgeVisByMaterial() Experimental function to make sure that edges of teh parsed object on a boundary between materials are visible. -- Only used when the script worked on editable poly objects. Sadly the function is way too slow and currently this is not used. --------------------------------------------------------------------------------------------------------------------------------------- fn setEdgeVisByMaterial object = ( if (classOf object.material) == Multimaterial then ( local processed = #() print "setEdgeVisByMaterial" -- loop through the edges of the parsed object for this in object.edges where (findItem processed this.index) == 0 do ( -- get the reverse edge, there are 2 edges between 2 faces in an editable mesh object local other = ((meshop.getEdgesReverseEdge object this.index) as array)[1] -- if there is a reverse edge... if other != undefined then ( -- get the 2 faces local thisFace = ((meshop.getFacesUsingEdge object this.index) as array)[1] local otherFace = ((meshop.getFacesUsingEdge object other) as array)[1] -- if the faces have different material IDs, make the edges visible if (getFaceMatID object thisFace) != (getFaceMatID object otherFace) then ( local thisIndex = findItem ((meshop.getEdgesUsingFace object thisFace) as array) this.index local otherIndex = findItem ((meshop.getEdgesUsingFace object otherFace) as array) other setEdgeVis object thisFace thisIndex true setEdgeVis object otherFace otherIndex true append processed this.index append processed other ) ) ) print "setEdgeVisByMaterial End" ) ), --------------------------------------------------------------------------------------------------------------------------------------- -- switchToMesh() Takes the parsed object and converts it to a mesh object with a display material. --------------------------------------------------------------------------------------------------------------------------------------- fn switchToMesh object = ( -- get the standard attribute data in case the object does not have rexBound materials local attrData = getAttributeData object -- switch to create mode in the max command panel before we convert because collision meshes do not properly -- update when they are converted setCommandPanelTaskMode #create col2mesh object setCommandPanelTaskMode #modify -- create face data from the object's material, set it on the faces via SimpleFaceData, give the object some basic -- uv co-ordinates to esure the display textures show up properly and then create and assign a display material local faceDataArray = getFaceDataFromMaterial object.material object attrData setFaceData object faceDataArray meshOp.applyUVWMap object #box uTile:2.0 vTile:2.0 setDisplayMaterial object faceDataArray ), --------------------------------------------------------------------------------------------------------------------------------------- -- switchToCollision() Takes the parsed object and converts it to a collision mesh with a rexBound material based on the -- object's face data --------------------------------------------------------------------------------------------------------------------------------------- fn switchToCollision object = ( -- create mode in the max command panel before setting the sub object level and making sure the faces are un-selected. -- I some times had it loose data when I did not do this, not sure why though. setCommandPanelTaskMode #create subObjectLevel = 0 object.selectedFaces = #() -- get the face data from the object and create a rexBound material local faceDataArray = getFaceData object setRexBoundMaterial object faceDataArray -- remove the SimpleFaceData channels because if we don't, we can no longer create and access them. simpleFaceManager.removeChannel object surfaceTypeID simpleFaceManager.removeChannel object flagsID simpleFaceManager.removeChannel object proceduralTypeID simpleFaceManager.removeChannel object miloRoomID -- convert to collision mesh mesh2Col object setCommandPanelTaskMode #modify -- if we've modified the collision types, set the attributes from the currentColType struct /* if ::RSL_CollisionOps.currentColType.modified then ( try (setAttr object idxCamera ::RSL_CollisionOps.currentColType.camera) catch() try (setAttr object idxPhysics ::RSL_CollisionOps.currentColType.physics) catch() try (setAttr object idxHiDetail ::RSL_CollisionOps.currentColType.hiDetail) catch() try (setAttr object idxLoco ::RSL_CollisionOps.currentColType.loco) catch() ) */ completeRedraw() ), --------------------------------------------------------------------------------------------------------------------------------------- -- setAttributeControlsRex() Sets the rexBound attribute controls based on the parsed faceNum. This is used in the pick functions --------------------------------------------------------------------------------------------------------------------------------------- fn setAttributeControlsRex faceNum = ( -- get the face data for the chosen faceNum local faceData = (getFaceData ::RSL_CollisionOps.currentMesh inputArray:#(::RSL_CollisionOps.currentMesh.faces[faceNum]))[1] -- set the surface type if we've used a pick function that supports it if pickType == "pickSurfaceButton" or pickType == "pickAllButton" then ( local surfaceType = ::RSL_CollisionOps.attribute.fullMaterialsDatSurfaceTypeArray[faceData.surfaceType] for i = 0 to pallette.items.count - 1 do ( local item = pallette.items.item[i] if (toUpper item.text) == (toUpper surfaceType) then ( item.selected = true -- this makes sure the list view item is visible in the list view. It will scroll to it if needed item.EnsureVisible() ) ) ) -- set the attribute check buttons if we've used a pick function that supports it if pickType == "pickFlagsButton" or pickType == "pickAllButton" then ( stairsCheckBox.checked = (bit.and faceData.flags (bit.shift 1 0) > 0) --noCoverCheckBox.checked = (bit.and faceData.flags (bit.shift 1 4) > 0) noClimbCheckBox.checked = (bit.and faceData.flags (bit.shift 1 1) > 0) --noWalkCheckBox.checked = (bit.and faceData.flags (bit.shift 1 5) > 0) seeCheckBox.checked = (bit.and faceData.flags (bit.shift 1 2) > 0) noCameraCheckBox.checked = (bit.and faceData.flags (bit.shift 1 7) > 0) shootCheckBox.checked = (bit.and faceData.flags (bit.shift 1 3) > 0) if faceData.proceduralType > 0 then ( proceduralTypeButton.text = ::RSL_CollisionOps.attribute.proceduralArray[faceData.proceduralType + 1] ) else ( proceduralTypeButton.text = "None" ) if faceData.miloRoom > 0 then ( local miloRoom = maxOps.getNodeByHandle faceData.miloRoom if (isValidNode miloRoom) and (classOf miloRoom) == GtaMloRoom then ( miloRoomButton.text = miloRoom.name miloRoomButton.tag = dotNetMXSValue miloRoom ) ) else ( miloRoomButton.text = "None" miloRoomButton.tag = undefined ) ) ), --------------------------------------------------------------------------------------------------------------------------------------- -- findFaceIndex() Searches the parsed array for the parsed index in the faceArray. Returns the index or 0 --------------------------------------------------------------------------------------------------------------------------------------- fn findFaceIndex array index = ( local result = 0 for i = 1 to array.count do ( if (findItem array[i].faceArray index) > 0 then ( result = i exit ) ) result ), --------------------------------------------------------------------------------------------------------------------------------------- -- selectFacesByAttributes() Selects faces on the currentMesh struct variable if they match the criteria of the chosen -- select function. --------------------------------------------------------------------------------------------------------------------------------------- fn selectFacesByAttributes faceNum ctrl = ( local faceDataArray = getFaceData ::RSL_CollisionOps.currentMesh local index = findFaceIndex faceDataArray faceNum local faceData = faceDataArray[index] local faceArray = #() -- if the control button is down, add the currently selected faces to faceArray so that we grow the face -- selection rather than replace it if ctrl then ( faceArray = for f in ::RSL_CollisionOps.currentMesh.selectedFaces collect f.index ) case selectType of ( "selectSurfaceButton": ( for entry in faceDataArray do ( if (entry.compareType faceData) then ( faceArray += entry.faceArray ) ) ) "selectFlagsButton": ( for entry in faceDataArray do ( if (entry.compareAttr faceData) then ( faceArray += entry.faceArray ) ) ) "selectAllButton": ( for entry in faceDataArray do ( if (entry.compare faceData) then ( faceArray += entry.faceArray ) ) ) ) -- make sure we're in face sub object mode and then select the faces subObjectLevel = 4 ::RSL_CollisionOps.currentMesh.selectedFaces = #() ::RSL_CollisionOps.currentMesh.selectedFaces = faceArray ), --------------------------------------------------------------------------------------------------------------------------------------- -- cb_mouseTrack() Mouse track function used by pick and select functions. The function ends when we click on a face. --------------------------------------------------------------------------------------------------------------------------------------- fn cb_mouseTrack msg ir obj faceNum shift ctrl alt = ( case msg of ( #freeMove: ( #continue ) #mousePoint: ( if ir != undefined then ( -- if we're using one of the pick functions, we set eh attribute controls based on the face we clicked -- otherwise we're using select functions so we select similar attrbute faces to the face we clicked if mouseTrackType == #pick then ( setAttributeControlsRex faceNum ) else ( selectFacesByAttributes faceNum ctrl ) ::RSL_CollisionOps.CollisionForm.enabled = true #exit ) else ( #continue ) ) #mouseMove: ( if ir != undefined then ( -- if we're using one of the pick functions, we set eh attribute controls based on the face we clicked -- otherwise we're using select functions so we select similar attrbute faces to the face we clicked if mouseTrackType == #pick then ( setAttributeControlsRex faceNum ) else ( selectFacesByAttributes faceNum ctrl ) ::RSL_CollisionOps.CollisionForm.enabled = true #exit ) else ( #continue ) ) #mouseAbort: ( ::RSL_CollisionOps.CollisionForm.enabled = true #exit ) ) ), --------------------------------------------------------------------------------------------------------------------------------------- -- pickFilter() Filter function used to ensure we only pick from object we have selected --------------------------------------------------------------------------------------------------------------------------------------- fn pickFilter object = ( findItem ::RSL_CollisionOps.theObjects object > 0 ), --------------------------------------------------------------------------------------------------------------------------------------- -- pickPrimitiveAttributes() Sets the standard attribute controls based on the object we pick. This is used in the pick functions --------------------------------------------------------------------------------------------------------------------------------------- fn pickPrimitiveAttributes = ( -- pick an object from the selected objects local pickedObject = pickObject filter:pickFilter if pickedObject != undefined then ( -- get eh attribute daat for the picked object local AttributeData = getAttributeData pickedObject -- set the surface type if we've used a pick function that supports it if pickType == "pickSurfaceButton" or pickType == "pickAllButton" then ( local surfaceType = ::RSL_CollisionOps.attribute.fullAttSurfaceTypeArray[AttributeData.surfaceType] for i = 0 to pallette.items.count - 1 do ( local item = pallette.items.item[i] if (toUpper item.text) == (toUpper surfaceType) then ( item.selected = true item.EnsureVisible() ) ) ) -- set the attribute check buttons if we've used a pick function that supports it if pickType == "pickFlagsButton" or pickType == "pickAllButton" then ( stairsCheckBox.checked = (bit.and faceData.flags (bit.shift 1 0) > 0) noCoverCheckBox.checked = (bit.and faceData.flags (bit.shift 1 4) > 0) noClimbCheckBox.checked = (bit.and faceData.flags (bit.shift 1 1) > 0) --noWalkCheckBox.checked = (bit.and faceData.flags (bit.shift 1 5) > 0) seeCheckBox.checked = (bit.and faceData.flags (bit.shift 1 2) > 0) noCameraCheckBox.checked = (bit.and faceData.flags (bit.shift 1 7) > 0) shootCheckBox.checked = (bit.and faceData.flags (bit.shift 1 3) > 0) pieceTypeButton.text = ::RSL_CollisionOps.attribute.pieceTypeArray[(getAttr pickedObject idxPiece) + 1] dayNumeric.value = (getAttr pickedObject idxDay) nightNumeric.value = (getAttr pickedObject idxNight) audioTextBox.text = (getAttr pickedObject idxAudio) roomIDNumeric.value = (getAttr pickedObject idxRoomID) --leedsCheckBox.checked = (getAttr pickedObject idxLeeds) BVHCheckBox.checked = (getAttr pickedObject idxBVH) procTintCheckBox.checked = (getAttr pickedObject idxProcTint) clothCollCheckBox.checked = (getAttr pickedObject idxClothColl) ) ) ), --------------------------------------------------------------------------------------------------------------------------------------- -- pickRexBoundAttributes() Starts the mouse track function for picking attributes and selecting faces --------------------------------------------------------------------------------------------------------------------------------------- fn pickSelectRexBoundAttributes = ( ::RSL_CollisionOps.CollisionForm.enabled = false mouseTrack on:::RSL_CollisionOps.currentMesh trackCallback:::RSL_CollisionOps.editUI.cb_mouseTrack ), --------------------------------------------------------------------------------------------------------------------------------------- -- assignPrimitiveAttributes() Assigns standard attrbiutes for each parsed object based on the attribute controls --------------------------------------------------------------------------------------------------------------------------------------- mapped fn assignPrimitiveAttributes object = ( -- set the surface type if we've used an assign function that supports it if assignType == "assignSurfaceButton" or assignType == "assignAllButton" then ( try (setAttr object idxColType pallette.selectedItems.item[0].text) catch() ) -- set the attributes if we've used an assign function that supports it if assignType == "assignFlagsButton" or assignType == "assignAllButton" then ( try (setAttr object idxStairs stairsCheckBox.checked) catch() try (setAttr object idxNoCover noCoverCheckBox.checked) catch() try (setAttr object idxNoClimb noClimbCheckBox.checked) catch() try (setAttr object idxNoWalk noWalkCheckBox.checked) catch() try (setAttr object idxSee seeCheckBox.checked) catch() try (setAttr object idxNoCamera noCameraCheckBox.checked) catch() try (setAttr object idxShoot shootCheckBox.checked) catch() try (setAttr object idxPiece ((findItem ::RSL_CollisionOps.attribute.pieceTypeArray pieceTypeButton.text) - 1)) catch() try (setAttr object idxDay dayNumeric.value) catch() try (setAttr object idxNight nightNumeric.value) catch() try (setAttr object idxAudio audioTextBox.text) catch() try (setAttr object idxRoomID roomIDNumeric.value) catch() --try (setAttr object idxLeeds leedsCheckBox.checked) catch() try (setAttr object idxBVH BVHCheckBox.checked) catch() ) ), --------------------------------------------------------------------------------------------------------------------------------------- -- assignRexboundAttibutes() Assigns rexBound attrbiutes for each parsed object based on the attribute controls --------------------------------------------------------------------------------------------------------------------------------------- fn assignRexboundAttibutes = ( local okToContinue = pallette.selectedItems.count == 1 local faceArray -- setup the faceArray and make sure we want to assign to the entire object if we don't have a face selection if ::RSL_CollisionOps.currentMesh.selectedFaces.count > 0 and subObjectLevel != 0 then ( faceArray = for f in ::RSL_CollisionOps.currentMesh.selectedFaces collect f.index ) else ( okToContinue = queryBox "Ok to assign to the entire object?" title:"Warning..." faceArray = for f in ::RSL_CollisionOps.currentMesh.faces collect f.index ) if okToContinue then ( -- set the surface type if we've used an assign function that supports it if assignType == "assignSurfaceButton" or assignType == "assignAllButton" then ( local surfaceValue = findItem ::RSL_CollisionOps.attribute.fullMaterialsDatSurfaceTypeArray (pallette.selectedItems.item[0].text) setData faceArray surfaceChannel surfaceValue local faceDataArray = getFaceData ::RSL_CollisionOps.currentMesh setDisplayMaterial ::RSL_CollisionOps.currentMesh faceDataArray ) -- set the attributes if we've used an assign function that supports it if assignType == "assignFlagsButton" or assignType == "assignAllButton" then ( local flags = 0 if stairsCheckBox.checked then ( flags = bit.or flags (bit.shift 1 0) ) if noClimbCheckBox.checked then ( flags = bit.or flags (bit.shift 1 1) ) if seeCheckBox.checked then ( flags = bit.or flags (bit.shift 1 2) ) if shootCheckBox.checked then ( flags = bit.or flags (bit.shift 1 3) ) if noCoverCheckBox.checked then ( flags = bit.or flags (bit.shift 1 4) ) --if noWalkCheckBox.checked then --( -- flags = bit.or flags (bit.shift 1 5) --) if noCameraCheckBox.checked then ( flags = bit.or flags (bit.shift 1 6) ) local procValue = (findItem ::RSL_CollisionOps.attribute.proceduralArray proceduralTypeButton.text) - 1 if procValue == 0 then procValue = -1 local miloHandle = -1 if miloRoomButton.tag != undefined then ( miloHandle = miloRoomButton.tag.value.inode.handle ) setData faceArray flagsChannel flags setData faceArray proceduralChannel procValue setData faceArray miloRoomChannel miloHandle ) ) ), --------------------------------------------------------------------------------------------------------------------------------------- -- -- UI FUNCTIONS -- --------------------------------------------------------------------------------------------------------------------------------------- --------------------------------------------------------------------------------------------------------------------------------------- -- dispatchFlagSelectClick() Dispatches flagSelectClick() Called when the user clicks any one of the attribute selection buttons --------------------------------------------------------------------------------------------------------------------------------------- fn dispatchFlagSelectClick s e = ( ::RSL_CollisionOps.editUI.flagSelectClick s e ), --------------------------------------------------------------------------------------------------------------------------------------- -- flagSelectClick() Selects any faces on the currentMesh that have the clicked attributes state e.g. click stairs selection button -- when the stairs attribute is unchecked will select all faces not marked as stairs --------------------------------------------------------------------------------------------------------------------------------------- fn flagSelectClick s e = ( if ::RSL_CollisionOps.currentType == #rexbound then ( local bitInteger = s.tag.value[1] local bool = s.tag.value[2] local faceDataArray = getFaceData ::RSL_CollisionOps.currentMesh local faceArray = #() -- check to see if the control button is down and append the selected faces to faceArray so that we grow the face -- selection rather than replace it local control = dotNetClass "system.windows.forms.control" if control.modifierKeys == control.modifierKeys.Control then ( faceArray = for f in ::RSL_CollisionOps.currentMesh.selectedFaces collect f.index ) for entry in faceDataArray do ( if bool then ( if (bit.and entry.flags (bit.shift 1 bitInteger) > 0) then ( faceArray += entry.faceArray ) ) else ( if (bit.and entry.flags (bit.shift 1 bitInteger) == 0) then ( faceArray += entry.faceArray ) ) ) -- set the sub object level the face and select the faces subObjectLevel = 4 ::RSL_CollisionOps.currentMesh.selectedFaces = #() ::RSL_CollisionOps.currentMesh.selectedFaces = faceArray ) ), --------------------------------------------------------------------------------------------------------------------------------------- -- dispatchFlagCheck() Dispatches flagCheck() Called when the user checks any one of the attribute buttons --------------------------------------------------------------------------------------------------------------------------------------- fn dispatchFlagCheck s e = ( ::RSL_CollisionOps.editUI.flagCheck s e ), --------------------------------------------------------------------------------------------------------------------------------------- -- flagCheck() Sets the tag of the relevant attribute selection button to the state of the check button so that the selection -- button knows what to look for when it's pressed --------------------------------------------------------------------------------------------------------------------------------------- fn flagCheck s e = ( case s.name of ( "stairsCheckBox":(stairsSelectButton.tag.value[2] = s.checked) --"noCoverCheckBox":(noCoverSelectButton.tag.value[2] = s.checked) "noClimbCheckBox":(noClimbSelectButton.tag.value[2] = s.checked) --"noWalkCheckBox":(noWalkSelectButton.tag.value[2] = s.checked) "seeCheckBox":(seeSelectButton.tag.value[2] = s.checked) "noCameraCheckBox":(noCamSelectButton.tag.value[2] = s.checked) "shootCheckBox":(shootSelectButton.tag.value[2] = s.checked) ) ), --------------------------------------------------------------------------------------------------------------------------------------- -- 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.editUI.pieceTypeButtonClick s e ), --------------------------------------------------------------------------------------------------------------------------------------- -- pieceTypeButtonClick() Displays the piece type dialog --------------------------------------------------------------------------------------------------------------------------------------- fn pieceTypeButtonClick s e = ( ::RSL_CollisionOps.attribute.pieceTypeDialog() ), --------------------------------------------------------------------------------------------------------------------------------------- -- dispatchRexAttrSelectClick() Dispatches rexAttrSelectClick(), called when the user presses one of the rexBound specific -- attributes selection buttons e.g. proceduralSelectButton --------------------------------------------------------------------------------------------------------------------------------------- fn dispatchRexAttrSelectClick s e = ( ::RSL_CollisionOps.editUI.rexAttrSelectClick s e ), --------------------------------------------------------------------------------------------------------------------------------------- -- rexAttrSelectClick() Selects any faces on the currentMesh that have the clicked rexBound attributes state -- e.g. click proceduralSelectButton to select any faces that match to current state of the procedural attribute --------------------------------------------------------------------------------------------------------------------------------------- fn rexAttrSelectClick s e = ( local faceDataArray = getFaceData ::RSL_CollisionOps.currentMesh local faceArray = #() -- check to see if the control button is down and append the selected faces to faceArray so that we grow the face -- selection rather than replace it local control = dotNetClass "system.windows.forms.control" if control.modifierKeys == control.modifierKeys.Control then ( faceArray = for f in ::RSL_CollisionOps.currentMesh.selectedFaces collect f.index ) local procIndex = (findItem ::RSL_CollisionOps.attribute.proceduralArray proceduralTypeButton.text) - 1 if procIndex == 0 then ( procIndex = -1 ) local miloHandle = -1 if miloRoomButton.tag != undefined then ( miloHandle = miloRoomButton.tag.value.inode.handle ) for entry in faceDataArray do ( case s.name of ( "proceduralSelectButton": ( if entry.proceduralType == procIndex then ( faceArray += entry.faceArray ) ) "miloRoomSelectButton": ( if entry.miloRoom == miloHandle then ( faceArray += entry.faceArray ) ) ) ) -- set the sub object level the face and select the faces subObjectLevel = 4 ::RSL_CollisionOps.currentMesh.selectedFaces = #() ::RSL_CollisionOps.currentMesh.selectedFaces = faceArray ), --------------------------------------------------------------------------------------------------------------------------------------- -- dispatchProceduralTypeButtonClick() Dispatches proceduralTypeButtonClick(), called when the user presses the proceduralTypeButton -- which is only available for collision meshes --------------------------------------------------------------------------------------------------------------------------------------- fn dispatchProceduralTypeButtonClick s e = ( ::RSL_CollisionOps.editUI.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.editUI.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 --------------------------------------------------------------------------------------------------------------------------------------- fn createAttributeControls type = ( attributesGroup.controls.clear() collisionTypeLabel = RS_dotNetUI.Label "collisionTypeLabel" text:" Per Object Collision Type:" textAlign:RS_dotNetPreset.CA_MiddleLeft \ borderStyle:RS_dotNetPreset.BS_None dockStyle:RS_dotNetPreset.DS_Fill stairsSelectButton = RS_dotNetUI.Button "stairsSelectButton" text:"Stairs" dockStyle:RS_dotNetPreset.DS_Fill margin:(RS_dotNetObject.paddingObject 2) stairsSelectButton.FlatStyle = RS_dotNetPreset.FS_Flat stairsSelectButton.tag = dotNetMXSValue #(0,false) dotnet.addEventHandler stairsSelectButton "click" dispatchFlagSelectClick stairsCheckBox = RS_dotNetUI.checkBox "stairsCheckBox" text:"" dockStyle:RS_dotNetPreset.DS_Fill dotnet.addEventHandler stairsCheckBox "CheckedChanged" dispatchFlagCheck stairsTableLayout = RS_dotNetUI.tableLayout "stairsTableLayout" \ collumns:#((dataPair type:"Absolute" value:20),(dataPair type:"Percent" value:50)) \ rows:#((dataPair type:"Absolute" value:24)) dockStyle:RS_dotNetPreset.DS_Fill stairsTableLayout.controls.add stairsCheckBox 0 0 stairsTableLayout.controls.add stairsSelectButton 1 0 /* noCoverSelectButton = RS_dotNetUI.Button "noCoverSelectButton" text:"Doesn't Provide Cover" dockStyle:RS_dotNetPreset.DS_Fill margin:(RS_dotNetObject.paddingObject 2) noCoverSelectButton.FlatStyle = RS_dotNetPreset.FS_Flat noCoverSelectButton.tag = dotNetMXSValue #(4,false) dotnet.addEventHandler noCoverSelectButton "click" dispatchFlagSelectClick noCoverCheckBox = RS_dotNetUI.checkBox "noCoverCheckBox" text:"" dockStyle:RS_dotNetPreset.DS_Fill dotnet.addEventHandler noCoverCheckBox "CheckedChanged" dispatchFlagCheck noCoverTableLayout = RS_dotNetUI.tableLayout "noCoverTableLayout" \ collumns:#((dataPair type:"Absolute" value:20),(dataPair type:"Percent" value:50)) \ rows:#((dataPair type:"Absolute" value:20)) dockStyle:RS_dotNetPreset.DS_Fill noCoverTableLayout.controls.add noCoverCheckBox 0 0 noCoverTableLayout.controls.add noCoverSelectButton 1 0 */ noClimbSelectButton = RS_dotNetUI.Button "noClimbSelectButton" text:"Non Climable" dockStyle:RS_dotNetPreset.DS_Fill margin:(RS_dotNetObject.paddingObject 2) noClimbSelectButton.FlatStyle = RS_dotNetPreset.FS_Flat noClimbSelectButton.tag = dotNetMXSValue #(1,false) dotnet.addEventHandler noClimbSelectButton "click" dispatchFlagSelectClick noClimbCheckBox = RS_dotNetUI.checkBox "noClimbCheckBox" text:"" dockStyle:RS_dotNetPreset.DS_Fill dotnet.addEventHandler noClimbCheckBox "CheckedChanged" dispatchFlagCheck noClimbTableLayout = RS_dotNetUI.tableLayout "noClimbTableLayout" \ collumns:#((dataPair type:"Absolute" value:20),(dataPair type:"Percent" value:50)) \ rows:#((dataPair type:"Absolute" value:24)) dockStyle:RS_dotNetPreset.DS_Fill noClimbTableLayout.controls.add noClimbCheckBox 0 0 noClimbTableLayout.controls.add noClimbSelectButton 1 0 /* noWalkSelectButton = RS_dotNetUI.Button "noWalkSelectButton" text:"Non Walkable" dockStyle:RS_dotNetPreset.DS_Fill margin:(RS_dotNetObject.paddingObject 2) noWalkSelectButton.FlatStyle = RS_dotNetPreset.FS_Flat noWalkSelectButton.tag = dotNetMXSValue #(5,false) dotnet.addEventHandler noWalkSelectButton "click" dispatchFlagSelectClick noWalkCheckBox = RS_dotNetUI.checkBox "noWalkCheckBox" text:"" dockStyle:RS_dotNetPreset.DS_Fill dotnet.addEventHandler noWalkCheckBox "CheckedChanged" dispatchFlagCheck noWalkTableLayout = RS_dotNetUI.tableLayout "noWalkTableLayout" \ collumns:#((dataPair type:"Absolute" value:20),(dataPair type:"Percent" value:50)) \ rows:#((dataPair type:"Absolute" value:20)) dockStyle:RS_dotNetPreset.DS_Fill noWalkTableLayout.controls.add noWalkCheckBox 0 0 noWalkTableLayout.controls.add noWalkSelectButton 1 0 */ seeSelectButton = RS_dotNetUI.Button "seeSelectButton" text:"See Through" dockStyle:RS_dotNetPreset.DS_Fill margin:(RS_dotNetObject.paddingObject 2) seeSelectButton.FlatStyle = RS_dotNetPreset.FS_Flat seeSelectButton.tag = dotNetMXSValue #(2,false) dotnet.addEventHandler seeSelectButton "click" dispatchFlagSelectClick seeCheckBox = RS_dotNetUI.checkBox "seeCheckBox" text:"" dockStyle:RS_dotNetPreset.DS_Fill dotnet.addEventHandler seeCheckBox "CheckedChanged" dispatchFlagCheck seeTableLayout = RS_dotNetUI.tableLayout "seeTableLayout" \ collumns:#((dataPair type:"Absolute" value:20),(dataPair type:"Percent" value:50)) \ rows:#((dataPair type:"Absolute" value:24)) dockStyle:RS_dotNetPreset.DS_Fill seeTableLayout.controls.add seeCheckBox 0 0 seeTableLayout.controls.add seeSelectButton 1 0 noCamSelectButton = RS_dotNetUI.Button "noCamSelectButton" text:"Non Camera Collide" dockStyle:RS_dotNetPreset.DS_Fill margin:(RS_dotNetObject.paddingObject 2) noCamSelectButton.FlatStyle = RS_dotNetPreset.FS_Flat noCamSelectButton.tag = dotNetMXSValue #(6,false) dotnet.addEventHandler noCamSelectButton "click" dispatchFlagSelectClick noCameraCheckBox = RS_dotNetUI.checkBox "noCameraCheckBox" text:"" dockStyle:RS_dotNetPreset.DS_Fill dotnet.addEventHandler noCameraCheckBox "CheckedChanged" dispatchFlagCheck noCamTableLayout = RS_dotNetUI.tableLayout "noCamTableLayout" \ collumns:#((dataPair type:"Absolute" value:20),(dataPair type:"Percent" value:50)) \ rows:#((dataPair type:"Absolute" value:24)) dockStyle:RS_dotNetPreset.DS_Fill noCamTableLayout.controls.add noCameraCheckBox 0 0 noCamTableLayout.controls.add noCamSelectButton 1 0 shootSelectButton = RS_dotNetUI.Button "shootSelectButton" text:"Shoot Through" dockStyle:RS_dotNetPreset.DS_Fill margin:(RS_dotNetObject.paddingObject 2) shootSelectButton.FlatStyle = RS_dotNetPreset.FS_Flat shootSelectButton.tag = dotNetMXSValue #(3,false) dotnet.addEventHandler shootSelectButton "click" dispatchFlagSelectClick shootCheckBox = RS_dotNetUI.checkBox "shootCheckBox" text:"" dockStyle:RS_dotNetPreset.DS_Fill dotnet.addEventHandler shootCheckBox "CheckedChanged" dispatchFlagCheck shootTableLayout = RS_dotNetUI.tableLayout "shootTableLayout" \ collumns:#((dataPair type:"Absolute" value:20),(dataPair type:"Percent" value:50)) \ rows:#((dataPair type:"Absolute" value:24)) dockStyle:RS_dotNetPreset.DS_Fill shootTableLayout.controls.add shootCheckBox 0 0 shootTableLayout.controls.add shootSelectButton 1 0 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:24),(dataPair type:"Absolute" value:24),(dataPair type:"Absolute" value:24), (dataPair type:"Absolute" value:24)) \ dockStyle:RS_dotNetPreset.DS_Fill attributesTableLayout.controls.add collisionTypeLabel 0 0 attributesTableLayout.controls.add stairsTableLayout 0 1 --stairsCheckBox --attributesTableLayout.controls.add noCoverTableLayout 1 4 --noCoverCheckBox attributesTableLayout.controls.add noClimbTableLayout 0 2 --noClimbCheckBox --attributesTableLayout.controls.add noWalkTableLayout 1 5 --noWalkCheckBox attributesTableLayout.controls.add seeTableLayout 0 3 --seeCheckBox attributesTableLayout.controls.add noCamTableLayout 1 3 --noCameraCheckBox attributesTableLayout.controls.add shootTableLayout 0 4 --shootCheckBox 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 "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 "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 "Enter" disableAccelerators --leedsCheckBox = RS_dotNetUI.checkBox "leedsCheckBox" text:("Edited by Leeds") dockStyle:RS_dotNetPreset.DS_Fill BVHCheckBox = RS_dotNetUI.checkBox "BVHCheckBox" text:("BVH Bound") dockStyle:RS_dotNetPreset.DS_Fill procTintCheckBox = RS_dotNetUI.checkBox "procTintCheckBox" text:("Use Procedural Tint") dockStyle:RS_dotNetPreset.DS_Fill clothCollCheckBox = RS_dotNetUI.checkBox "clothCollCheckBox" text:("Is Cloth Collision") dockStyle:RS_dotNetPreset.DS_Fill 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 10 attributesTableLayout.controls.add BVHCheckBox 1 10 attributesTableLayout.controls.add procTintCheckBox 0 11 attributesTableLayout.controls.add clothCollCheckBox 1 11 editTableLayout.RowStyles.Item[2].Height = (296 + 16) ) #rexbound: ( proceduralSelectButton = RS_dotNetUI.Button "proceduralSelectButton" text:"Procedural Type:" dockStyle:RS_dotNetPreset.DS_Fill margin:(RS_dotNetObject.paddingObject 2) proceduralSelectButton.FlatStyle = RS_dotNetPreset.FS_Flat dotnet.addEventHandler proceduralSelectButton "click" dispatchRexAttrSelectClick 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 = false pedMultiplierNumeric = RS_dotNetUI.Numeric "ZPadding" value:0 range:#(7, 0, 1, 0) dockStyle:RS_dotNetPreset.DS_Fill pedMultiplierNumeric.enabled = false dotnet.addEventHandler pedMultiplierNumeric "Enter" disableAccelerators miloRoomSelectButton = RS_dotNetUI.Button "miloRoomSelectButton" text:"Milo Room:" dockStyle:RS_dotNetPreset.DS_Fill margin:(RS_dotNetObject.paddingObject 2) miloRoomSelectButton.FlatStyle = RS_dotNetPreset.FS_Flat dotnet.addEventHandler miloRoomSelectButton "click" dispatchRexAttrSelectClick 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" 24) --attributesTableLayout.RowStyles.add (RS_dotNetObject.RowStyleObject "absolute" 20) attributesTableLayout.controls.add proceduralSelectButton 0 5 --proceduralTypeLabel attributesTableLayout.controls.add proceduralTypeButton 1 5 attributesTableLayout.controls.add pedMultiplierLabel 0 6 attributesTableLayout.controls.add pedMultiplierNumeric 1 6 attributesTableLayout.controls.add miloRoomSelectButton 0 7 --miloRoomLabel attributesTableLayout.controls.add miloRoomButton 1 7 editTableLayout.RowStyles.Item[2].Height = (206 + 16) ) ) attributesTableLayout ), --------------------------------------------------------------------------------------------------------------------------------------- -- dispatchSearchTextChanged() Dispatches searchTextChanged(), called when the user changes the text in the searchTextBox --------------------------------------------------------------------------------------------------------------------------------------- fn dispatchSearchTextChanged s e = ( ::RSL_CollisionOps.editUI.searchTextChanged s e ), --------------------------------------------------------------------------------------------------------------------------------------- -- searchTextChanged() Re-populates the surface pallette based on the search text --------------------------------------------------------------------------------------------------------------------------------------- fn searchTextChanged s e = ( pallette.Items.clear() ::RSL_CollisionOps.attribute.addSurfaceTypeItem ::RSL_CollisionOps.attribute.matDatSurfaceTypeArray pallette searchTextBox.text ), --------------------------------------------------------------------------------------------------------------------------------------- -- dispatchPickButtonClick() Dispatches pickButtonClick(), called when the user presses one of the pick check buttons --------------------------------------------------------------------------------------------------------------------------------------- fn dispatchPickButtonClick s e = ( ::RSL_CollisionOps.editUI.pickButtonClick s e ), --------------------------------------------------------------------------------------------------------------------------------------- -- pickButtonClick() Runs the correct pick function based on the currentType struct variable --------------------------------------------------------------------------------------------------------------------------------------- fn pickButtonClick s e = ( -- set the mouseTrackType to #pick so that the mouse track function know which functions to run when we pick a face mouseTrackType = #pick searchTextBox.text = "" pickType = s.name if ::RSL_CollisionOps.currentType == #primitive then ( pickPrimitiveAttributes() ) else ( pickSelectRexBoundAttributes() ) s.checked = false ), --------------------------------------------------------------------------------------------------------------------------------------- -- dispatchSelectButtonClick() Dispatches selectButtonClick(), called when the user presses one of the select check buttons --------------------------------------------------------------------------------------------------------------------------------------- fn dispatchSelectButtonClick s e = ( ::RSL_CollisionOps.editUI.selectButtonClick s e ), --------------------------------------------------------------------------------------------------------------------------------------- -- selectButtonClick() Runs the function for selecting rexBound attribute faces --------------------------------------------------------------------------------------------------------------------------------------- fn selectButtonClick s e = ( -- set the mouseTrackType to #select so that the mouse track function know which functions to run when we pick a face mouseTrackType = #select selectType = s.name pickSelectRexBoundAttributes() ), --------------------------------------------------------------------------------------------------------------------------------------- -- dispatchAssignButtonClick() Dispatches assignButtonClick(), called when the user presses one of the assign buttons --------------------------------------------------------------------------------------------------------------------------------------- fn dispatchAssignButtonClick s e = ( ::RSL_CollisionOps.editUI.assignButtonClick s e ), --------------------------------------------------------------------------------------------------------------------------------------- -- assignButtonClick() Runs the correct assign function based on the currentType struct variable --------------------------------------------------------------------------------------------------------------------------------------- fn assignButtonClick s e = ( assignType = s.name if ::RSL_CollisionOps.currentType == #primitive then ( assignPrimitiveAttributes ::RSL_CollisionOps.theObjects ) else ( assignRexboundAttibutes() ) ), --------------------------------------------------------------------------------------------------------------------------------------- -- getUI() Creates the edit mode UI. Returns the editTableLayout --------------------------------------------------------------------------------------------------------------------------------------- fn getUI = ( editTableLayout = RS_dotNetUI.tableLayout "editTableLayout" text:"editTableLayout" \ collumns:#((dataPair type:"Percent" value:50),(dataPair type:"Percent" value:50)) \ rows:#((dataPair type:"Percent" value:50),(dataPair type:"Absolute" value:24),(dataPair type:"Absolute" value:260) ,(dataPair type:"Absolute" value:(48 + 24)),(dataPair type:"Absolute" value:(48 + 24))) \ dockStyle:RS_dotNetPreset.DS_Fill pallette = ::RSL_CollisionOps.attribute.surfaceTypePallette ::RSL_CollisionOps.currentType "" searchLabel = RS_dotNetUI.Label "searchLabel" text:(" Search:") \ textAlign:RS_dotNetPreset.CA_MiddleLeft borderStyle:RS_dotNetPreset.BS_None \ dockStyle:RS_dotNetPreset.DS_Fill searchTextBox = RS_dotNetUI.textBox "searchTextBox" borderStyle:RS_dotNetPreset.BS_Fixed3D dockStyle:RS_dotNetPreset.DS_Fill dotNet.addEventHandler searchTextBox "TextChanged" dispatchSearchTextChanged dotnet.addEventHandler searchTextBox "Enter" disableAccelerators attributesGroup = RS_dotNetUI.GroupBox "attributesGroup" Text:"Attributes" dockStyle:RS_dotNetPreset.DS_Fill attributesGroup.controls.add (createAttributeControls ::RSL_CollisionOps.currentType) pickSurfaceButton = RS_dotNetUI.checkBox "pickSurfaceButton" text:("Surface") appearance:RS_dotNetPreset.AC_Button dockStyle:RS_dotNetPreset.DS_Fill dotnet.addEventHandler pickSurfaceButton "click" dispatchPickButtonClick pickFlagsButton = RS_dotNetUI.checkBox "pickFlagsButton" text:("Attributes") appearance:RS_dotNetPreset.AC_Button dockStyle:RS_dotNetPreset.DS_Fill dotnet.addEventHandler pickFlagsButton "click" dispatchPickButtonClick pickAllButton = RS_dotNetUI.checkBox "pickAllButton" text:("All") appearance:RS_dotNetPreset.AC_Button dockStyle:RS_dotNetPreset.DS_Fill dotnet.addEventHandler pickAllButton "click" dispatchPickButtonClick pickTableLayout = RS_dotNetUI.tableLayout "pickTableLayout" text:"pickTableLayout" \ collumns:#((dataPair type:"Percent" value:50),(dataPair type:"Percent" value:50)) \ rows:#((dataPair type:"Absolute" value:24),(dataPair type:"Absolute" value:24)) \ dockStyle:RS_dotNetPreset.DS_Fill pickTableLayout.controls.add pickSurfaceButton 0 0 pickTableLayout.controls.add pickFlagsButton 1 0 pickTableLayout.controls.add pickAllButton 0 1 pickTableLayout.SetColumnSpan pickAllButton 2 pickGroup = RS_dotNetUI.GroupBox "pickGroup" Text:"Pick" dockStyle:RS_dotNetPreset.DS_Fill pickGroup.controls.add pickTableLayout selectSurfaceButton = RS_dotNetUI.Button "selectSurfaceButton" text:"Surface" dockStyle:RS_dotNetPreset.DS_Fill margin:(RS_dotNetObject.paddingObject 2) dotnet.addEventHandler selectSurfaceButton "click" dispatchSelectButtonClick selectFlagsButton = RS_dotNetUI.Button "selectFlagsButton" text:"Attributes" dockStyle:RS_dotNetPreset.DS_Fill margin:(RS_dotNetObject.paddingObject 2) dotnet.addEventHandler selectFlagsButton "click" dispatchSelectButtonClick selectAllButton = RS_dotNetUI.Button "selectAllButton" text:"All" dockStyle:RS_dotNetPreset.DS_Fill margin:(RS_dotNetObject.paddingObject 2) dotnet.addEventHandler selectAllButton "click" dispatchSelectButtonClick selectTableLayout = RS_dotNetUI.tableLayout "selectTableLayout" text:"editTableLayout" \ collumns:#((dataPair type:"Percent" value:50),(dataPair type:"Percent" value:50)) \ rows:#((dataPair type:"Absolute" value:24),(dataPair type:"Absolute" value:24)) \ dockStyle:RS_dotNetPreset.DS_Fill selectTableLayout.controls.add selectSurfaceButton 0 0 selectTableLayout.controls.add selectFlagsButton 1 0 selectTableLayout.controls.add selectAllButton 0 1 selectTableLayout.SetColumnSpan selectAllButton 2 selectGroup = RS_dotNetUI.GroupBox "selectGroup" Text:"Select" dockStyle:RS_dotNetPreset.DS_Fill selectGroup.controls.add selectTableLayout assignSurfaceButton = RS_dotNetUI.Button "assignSurfaceButton" text:"Surface" dockStyle:RS_dotNetPreset.DS_Fill margin:(RS_dotNetObject.paddingObject 2) dotnet.addEventHandler assignSurfaceButton "click" dispatchAssignButtonClick assignFlagsButton = RS_dotNetUI.Button "assignFlagsButton" text:"Attributes" dockStyle:RS_dotNetPreset.DS_Fill margin:(RS_dotNetObject.paddingObject 2) dotnet.addEventHandler assignFlagsButton "click" dispatchAssignButtonClick assignAllButton = RS_dotNetUI.Button "assignAllButton" text:"All" dockStyle:RS_dotNetPreset.DS_Fill margin:(RS_dotNetObject.paddingObject 2) dotnet.addEventHandler assignAllButton "click" dispatchAssignButtonClick assignTableLayout = RS_dotNetUI.tableLayout "assignTableLayout" text:"editTableLayout" \ collumns:#((dataPair type:"Percent" value:50),(dataPair type:"Percent" value:50)) \ rows:#((dataPair type:"Absolute" value:24),(dataPair type:"Absolute" value:24)) \ dockStyle:RS_dotNetPreset.DS_Fill assignTableLayout.controls.add assignSurfaceButton 0 0 assignTableLayout.controls.add assignFlagsButton 1 0 assignTableLayout.controls.add assignAllButton 0 1 assignTableLayout.SetColumnSpan assignAllButton 2 assignGroup = RS_dotNetUI.GroupBox "assignGroup" Text:"Assign" dockStyle:RS_dotNetPreset.DS_Fill assignGroup.controls.add assignTableLayout editTableLayout.controls.add pallette 0 0 editTableLayout.controls.add searchLabel 0 1 editTableLayout.controls.add searchTextBox 1 1 editTableLayout.controls.add attributesGroup 0 2 editTableLayout.controls.add pickGroup 0 3 editTableLayout.controls.add selectGroup 1 3 editTableLayout.controls.add assignGroup 0 4 editTableLayout.SetColumnSpan pallette 2 editTableLayout.SetColumnSpan attributesGroup 2 editTableLayout.SetColumnSpan assignGroup 2 editTableLayout ) )