--------------------------------------------------------------------------------------------------------------------------------------- -- RSL_CollisionOps2Attribute -- 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 --------------------------------------------------------------------------------------------------------------------------------------- -- main struct struct RSL_CollisionOps2Attribute ( --------------------------------------------------------------------------------------------------------------------------------------- -- Struct variables --------------------------------------------------------------------------------------------------------------------------------------- INIfile = (RsConfigGetWildWestDir() + "etc/config/general/collisionOps2.ini"), textureDirectory = (RsConfigGetWildWestDir() +"etc/config/general/collision_textures/"), rsNorthAttFile = (RsConfigGetToolsDir() +"dcc/current/max2011/plugcfg/rsnorth.att"), materialsDatFile = (RsConfigGetCommonDir() + "/data/materials/materials.dat"), proceduralDatFile = (RsConfigGetCommonDir() + "/data/materials/procedural.dat"), -- there are two surface type arrays depending on weather the object has rexbound materials or not and two arrays for each -- because we remove "temp" surface types. The full arrays are used to get the chosen surface type, the reduced arrays -- are used for the surface type dialogs fullAttSurfaceTypeArray = #(), fullMaterialsDatSurfaceTypeArray = #(), attSurfaceTypeArray = #(), matDatSurfaceTypeArray = #(), -- rebound and attribute specific arrays proceduralArray = #(), pieceTypeArray = #(), -- 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", --------------------------------------------------------------------------------------------------------------------------------------- -- UI variables --------------------------------------------------------------------------------------------------------------------------------------- toolTip = dotNetObject "ToolTip", colourDialog = dotNetObject "ColorDialog", copiedColour, lastType, lastColour, mousePoint, surfaceTypeForm,palletteList,surfaceTypeOkButton,surfaceTypeCancelButton, typeControlMenu,editColour,copyColour,pasteColour,selectFaces, pieceTypeForm,pieceTypeListview,pieceTypeOkButton,pieceTypeCancelButton, proceduralTypeForm,proceduralTypeListview,proceduralTypeOkButton,proceduralTypeCancelButton, miloRoomForm,miloRoomListview,miloRoomOkButton,miloRoomCancelButton, --------------------------------------------------------------------------------------------------------------------------------------- -- -- FUNCTIONS -- --------------------------------------------------------------------------------------------------------------------------------------- --------------------------------------------------------------------------------------------------------------------------------------- -- filterTemp() Removes any "temp*" surface types from the two surface type arrays --------------------------------------------------------------------------------------------------------------------------------------- fn filterTemp = ( local tempArray = attSurfaceTypeArray attSurfaceTypeArray = #() for entry in tempArray do ( if not (matchPattern entry.type pattern:"temp*") then ( append attSurfaceTypeArray entry ) ) tempArray = matDatSurfaceTypeArray matDatSurfaceTypeArray = #() for entry in tempArray do ( if not (matchPattern entry.type pattern:"temp*") then ( append matDatSurfaceTypeArray entry ) ) ), --------------------------------------------------------------------------------------------------------------------------------------- -- readAttFile() Reads the rsnorth.att and assigns all surface types to the att surface type arrays --------------------------------------------------------------------------------------------------------------------------------------- fn readAttFile = ( local dataStream = openFile rsNorthAttFile fullAttSurfaceTypeArray = #() attSurfaceTypeArray = #() if dataStream != undefined then ( skipToString dataStream "startui \"Gta Collision\" #editing \"Gta Collision\"" skipToString dataStream "list 7 \"" local line = (readDelimitedString dataStream "\"") pieceTypeArray = filterString line "," skipToString dataStream "tlist 367 \"" line = toUpper (readDelimitedString dataStream "\"") attSurfaceTypeArray = filterString line "," sort attSurfaceTypeArray fullAttSurfaceTypeArray = deepCopy attSurfaceTypeArray for i = 1 to attSurfaceTypeArray.count do ( attSurfaceTypeArray[i] = (dataPair type:attSurfaceTypeArray[i] index:i) ) ) ), --------------------------------------------------------------------------------------------------------------------------------------- -- readMaterialsDatFile() Reads the materials.dat and assigns all surface types to the materials dat surface type arrays --------------------------------------------------------------------------------------------------------------------------------------- fn readMaterialsDatFile = ( local dataStream = openFile materialsDatFile fullMaterialsDatSurfaceTypeArray = #() matDatSurfaceTypeArray = #() if dataStream != undefined then ( readLine dataStream while not (eof dataStream) do ( local line = readLine dataStream if line != "" and line[1] != "#" and line[1] != "\t" then ( local filtered = filterString line "\t" if filtered.count > 0 then ( append matDatSurfaceTypeArray (toUpper filtered[1]) ) ) ) sort matDatSurfaceTypeArray fullMaterialsDatSurfaceTypeArray = deepCopy matDatSurfaceTypeArray for i = 1 to matDatSurfaceTypeArray.count do ( matDatSurfaceTypeArray[i] = (dataPair type:matDatSurfaceTypeArray[i] index:i) ) -- set the last type so that we can set the surface type button lastType = getINISetting INIFile "settings" "lastType" if lastType == "" then lastType = matDatSurfaceTypeArray[1].type ) else ( print "materials dat failed to load." ) close dataStream ), --------------------------------------------------------------------------------------------------------------------------------------- -- readPoceduralDatFile() Reads the procedural.dat and assigns all procedural types to the proceduralArray --------------------------------------------------------------------------------------------------------------------------------------- fn readPoceduralDatFile = ( local dataStream = openFile proceduralDatFile proceduralArray = #() if dataStream != undefined then ( skipToString dataStream "PROCOBJ_DATA_START" while not (eof dataStream) do ( local line = readLine dataStream -- make sure we ignore the lines we don't need if line != "" and line[1] != "#" and line[1] != "\t" and line != "PLANT_DATA_START" and line != "PLANT_DATA_END" and line != "PROCOBJ_DATA_END" then ( local filtered = filterString line " \t" -- make sure we ignore any lines with only tabs in them if filtered.count > 0 then ( appendIfUnique proceduralArray filtered[1] ) ) ) sort proceduralArray insertItem "NONE" proceduralArray 1 ) else ( print "procedural dat failed to load." ) close dataStream ), --------------------------------------------------------------------------------------------------------------------------------------- -- getColours() Gets the colours set in the INI file for each surface type control in the palletteFlow --------------------------------------------------------------------------------------------------------------------------------------- fn getColours = ( for i = 0 to palletteFlow.controls.count - 1 do ( local control = palletteFlow.controls.item[i] local colour = getINISetting INIFile "surfaceColours" control.name -- if a colour setting exists we can set the back colour for the control if colour != "" then ( local colourValue = readExpr (colour as stringStream) control.backColor = RS_dotNetClass.colourClass.fromARGB colourValue.r colourValue.g colourValue.b -- check to see if the back colour is not too similar to the fore colour local backColTotal = colourValue.r + colourValue.g + colourValue.b local foreColTotal = control.foreColor.r + control.foreColor.g + control.foreColor.b -- they are too similar so we set the fore colour to either black or white if (abs (backColTotal - foreColTotal)) < 128 then ( if control.foreColor == RS_dotNetClass.colourClass.White then ( control.foreColor = RS_dotNetClass.colourClass.Black ) else ( control.foreColor = RS_dotNetClass.colourClass.White ) ) ) ) ), --------------------------------------------------------------------------------------------------------------------------------------- -- makeTexture() Creates a texture for the parsed name with the parsed colour. The texture has the parsed name printed -- in the middle. If updateFile is true, we re-create the texture regardless of weather it exists or not. --------------------------------------------------------------------------------------------------------------------------------------- fn makeTexture name colour updateFile:false = ( -- attempt to make the directory if it does not already exist makeDir textureDirectory local file = textureDirectory + name + ".bmp" if not (doesFileExist file) or updateFile then ( -- delete the file if it exists deleteFile file -- if the colour is set to transparent, it's not be set so we make sure it's silver if colour == RS_dotNetClass.colourClass.Transparent then ( colour = RS_dotNetClass.colourClass.Silver ) local bitmapImage = dotNetObject RS_dotNetClass.bitmapClass 256 256 local graphics = (dotNetClass "System.Drawing.Graphics").FromImage bitmapImage local backBrush = dotNetObject RS_dotNetClass.solidBushClass colour local font = dotNetObject "System.Drawing.Font" "Trebuchet MS" ((256 / 100) * 6) RS_dotNetPreset.f_Bold local fontColour = RS_dotNetClass.brushesClass.White -- check to see if the back colour is not too similar to the fore colour local fontColTotal = fontColour.Color.r + fontColour.Color.g + fontColour.Color.b local colourTotal = colour.r + colour.g + colour.b -- they are too similar so we set the font colour to black if (abs (fontColTotal - colourTotal)) < 128 then ( fontColour = RS_dotNetClass.brushesClass.Black ) local size = graphics.MeasureString name font local x = 128.0 - (size.width * 0.5) local y = 128.0 - (size.height * 0.5) -- fill the bitmap with the colur and write the name string to the bitmap graphics.FillRectangle backBrush (dotNetObject RS_dotNetClass.rectangleClass 0 0 256 256) graphics.DrawString name font fontColour x y bitmapImage.save file (RS_dotNetClass.imageFormatClass.bmp) ) ), --------------------------------------------------------------------------------------------------------------------------------------- -- appendSurfaceTypeData() --------------------------------------------------------------------------------------------------------------------------------------- mapped fn appendSurfaceTypeData data array = ( local found = false for entry in array do ( if (matchPattern entry.type pattern:data.type) then ( found = true ) ) if not found then ( append array data ) ), --------------------------------------------------------------------------------------------------------------------------------------- -- generateTextures() Generates the display textures if needed --------------------------------------------------------------------------------------------------------------------------------------- fn generateTextures = ( local tempArray = deepCopy attSurfaceTypeArray appendSurfaceTypeData matDatSurfaceTypeArray tempArray progressStart "Creating Display Textures..." for i = 1 to tempArray.count do ( local entry = tempArray[i] local colour = RS_dotNetClass.colourClass.Transparent local colourString = getINISetting INIFile "surfaceColours" entry.type if colourString != "" then ( local colourValue = readExpr (colourString as stringStream) colour = RS_dotNetClass.colourClass.fromARGB colourValue.r colourValue.g colourValue.b ) makeTexture entry.type colour progressUpdate (i as float / tempArray.count * 100.0) ) progressEnd() ), --------------------------------------------------------------------------------------------------------------------------------------- -- showDisplayMaterial() Sets the diffuse textures in the currentMesh material to displayed --------------------------------------------------------------------------------------------------------------------------------------- fn showDisplayMaterial = ( local material = ::RSL_CollisionOps.currentMesh.material case (classOf material) of ( Standardmaterial: ( -- un-display and then display to ensure they update showTextureMap material material.diffuseMap false showTextureMap material material.diffuseMap true ) Multimaterial: ( for subMaterial in material.materialList where (classOf subMaterial) == Standardmaterial do ( -- un-display and then display to ensure they update showTextureMap subMaterial subMaterial.diffuseMap false showTextureMap subMaterial subMaterial.diffuseMap true ) ) ) ), --------------------------------------------------------------------------------------------------------------------------------------- -- setColour() Sets colour for the parsed name in the INI file to the parsed colour --------------------------------------------------------------------------------------------------------------------------------------- fn setColour name colour = ( setINISetting INIFile "surfaceColours" name ((color colour.r colour.g colour.b) as string) -- re-make the texture because we've changed the colour makeTexture name colour updateFile:true -- if we're in edit mode force the texture to be displayed so that it updates if ::RSL_CollisionOps.currentTool.name == "editTableLayout" then ( showDisplayMaterial() ) ), --------------------------------------------------------------------------------------------------------------------------------------- -- addSurfaceTypeItem() Adds each parsed surfaceType to the parsed listView if it matches the parsed searchText --------------------------------------------------------------------------------------------------------------------------------------- mapped fn addSurfaceTypeItem surfaceType listView searchText = ( local okToContinue = true -- if the searchText has some text, we check that the surfaceType matches if searchText.count > 0 then ( okToContinue = (matchPattern surfaceType.type pattern:("*" + searchText + "*")) ) if okToContinue then ( local newItem = dotNetObject "ListViewItem" surfaceType.type newItem.selected = surfaceType.type == lastType if newItem.selected then ( newItem.EnsureVisible() ) -- get the colour for the surfaceType if it exists in the INI file local colour = getINISetting INIFile "surfaceColours" surfaceType.type if colour != "" then ( local colourValue = readExpr (colour as stringStream) newItem.backColor = RS_dotNetClass.colourClass.fromARGB colourValue.r colourValue.g colourValue.b -- check to see if the back colour is not too similar to the fore colour local backColTotal = colourValue.r + colourValue.g + colourValue.b local foreColTotal = newItem.foreColor.r + newItem.foreColor.g + newItem.foreColor.b -- they are too similar so we set the fore colour to either black or white if (abs (backColTotal - foreColTotal)) < 128 then ( if newItem.foreColor == RS_dotNetClass.colourClass.White then ( newItem.foreColor = RS_dotNetClass.colourClass.Black ) else ( newItem.foreColor = RS_dotNetClass.colourClass.White ) ) ) listView.items.add newItem ) ), --------------------------------------------------------------------------------------------------------------------------------------- -- addTypeItem() Adds each parsed type to the parsed listView. --------------------------------------------------------------------------------------------------------------------------------------- mapped fn addTypeItem type listView = ( local newItem = dotNetObject "ListViewItem" type listView.items.add newItem ), --------------------------------------------------------------------------------------------------------------------------------------- -- addTypeItem() Adds each parsed object to the miloRoomListview. --------------------------------------------------------------------------------------------------------------------------------------- mapped fn addMiloRoomItem object = ( -- make sure we only add GtaMloRoom class objects if (classOf object) == GtaMloRoom then ( local newItem = dotNetObject "ListViewItem" object.name -- assign the object to the tag because we will use it when the user chooses the listViewItem from the dialog newItem.tag = dotNetMXSValue object miloRoomListview.items.add newItem ) ), --------------------------------------------------------------------------------------------------------------------------------------- -- -- UI FUNCTIONS -- --------------------------------------------------------------------------------------------------------------------------------------- --------------------------------------------------------------------------------------------------------------------------------------- -- dispatchOkButtonClick() Dispatches OkButtonClick() Called when the user presses any one of the dialog ok buttons --------------------------------------------------------------------------------------------------------------------------------------- fn dispatchOkButtonClick s e = ( ::RSL_CollisionOps.attribute.OkButtonClick s e ), --------------------------------------------------------------------------------------------------------------------------------------- -- OkButtonClick() Depending on which dialog ok button was pressed, sets the relevant items up based on the choosen item -- in the dialog --------------------------------------------------------------------------------------------------------------------------------------- fn OkButtonClick s e = ( case s.name of ( "surfaceTypeOkButton": ( case ::RSL_CollisionOps.currentTool.name of ( "createTableLayout": ( ::RSL_CollisionOps.createUI.surfaceTypeButton.text = lastType ::RSL_CollisionOps.createUI.surfaceTypeButton.backColor = lastColour ) "selectDisplayTableLayout": ( ::RSL_CollisionOps.selectDisplayUI.surfaceTypeButton.text = lastType ::RSL_CollisionOps.selectDisplayUI.surfaceTypeButton.backColor = lastColour ) ) surfaceTypeForm.close() ) "pieceTypeOkButton": ( if pieceTypeListview.selectedItems.count == 1 then ( case ::RSL_CollisionOps.currentTool.name of ( "createTableLayout": ( ::RSL_CollisionOps.createUI.pieceTypeButton.text = pieceTypeListview.selectedItems.item[0].text ) "editTableLayout": ( ::RSL_CollisionOps.editUI.pieceTypeButton.text = pieceTypeListview.selectedItems.item[0].text ) "selectDisplayTableLayout": ( ::RSL_CollisionOps.selectDisplayUI.pieceTypeButton.text = pieceTypeListview.selectedItems.item[0].text ) ) pieceTypeForm.close() ) else ( messageBox "Nothing selected. You must pick one or cancel." title:"Error..." ) ) "proceduralTypeOkButton": ( if proceduralTypeListview.selectedItems.count == 1 then ( case ::RSL_CollisionOps.currentTool.name of ( "createTableLayout": ( ::RSL_CollisionOps.createUI.proceduralTypeButton.text = proceduralTypeListview.selectedItems.item[0].text ) "editTableLayout": ( ::RSL_CollisionOps.editUI.proceduralTypeButton.text = proceduralTypeListview.selectedItems.item[0].text ) "selectDisplayTableLayout": ( ::RSL_CollisionOps.selectDisplayUI.proceduralTypeButton.text = proceduralTypeListview.selectedItems.item[0].text ) ) proceduralTypeForm.close() ) else ( messageBox "Nothing selected. You must pick one or cancel." title:"Error..." ) ) "miloRoomOkButton": ( if miloRoomListview.selectedItems.count == 1 then ( local selected = miloRoomListview.selectedItems.item[0] local name = "None" if selected.tag != undefined then ( name = selected.tag.value.name ) if ::RSL_CollisionOps.currentTool.name == "createTableLayout" then ( ::RSL_CollisionOps.createUI.miloRoomButton.text = name ::RSL_CollisionOps.createUI.miloRoomButton.tag = selected.tag ) else ( ::RSL_CollisionOps.editUI.miloRoomButton.text = name ::RSL_CollisionOps.editUI.miloRoomButton.tag = selected.tag ) miloRoomForm.close() ) else ( messageBox "Nothing selected. You must pick one or cancel." title:"Error..." ) ) ) ), --------------------------------------------------------------------------------------------------------------------------------------- -- dispatchCancelButtonClick() Dispatches CancelButtonClick() Called when the user presses any one of the dialog cancel buttons --------------------------------------------------------------------------------------------------------------------------------------- fn dispatchCancelButtonClick s e = ( ::RSL_CollisionOps.attribute.CancelButtonClick s e ), --------------------------------------------------------------------------------------------------------------------------------------- -- CancelButtonClick() Depending on which dialog cancel button was pressed, closes the relevant dialog --------------------------------------------------------------------------------------------------------------------------------------- fn CancelButtonClick s e = ( case s.name of ( "surfaceTypeCancelButton": ( surfaceTypeForm.close() ) "pieceTypeCancelButton": ( pieceTypeForm.close() ) "proceduralTypeCancelButton": ( proceduralTypeForm.close() ) "miloRoomCancelButton": ( miloRoomForm.close() ) ) ), --------------------------------------------------------------------------------------------------------------------------------------- -- dispatchMiloRoomFormClosing() Dispatches miloRoomFormClosing() Called when the milo room dialog is closed --------------------------------------------------------------------------------------------------------------------------------------- fn dispatchMiloRoomFormClosing s e = ( ::RSL_CollisionOps.attribute.miloRoomFormClosing s e ), --------------------------------------------------------------------------------------------------------------------------------------- -- miloRoomFormClosing() Enables the main form --------------------------------------------------------------------------------------------------------------------------------------- fn miloRoomFormClosing s e = ( ::RSL_CollisionOps.CollisionForm.enabled = true ), --------------------------------------------------------------------------------------------------------------------------------------- -- miloRoomDialog() Creates the milo room dialog --------------------------------------------------------------------------------------------------------------------------------------- fn miloRoomDialog = ( -- dissable the main form whilst the milo room dialog is open RSL_CollisionOps.CollisionForm.enabled = false --In this case, we're going to use a standard form rather than the custom maxForm written for max. this is because I want to change the -- form back colour which you can't do if you use the custom maxForm. For this to work, we need to set the parent of the form to be Max. -- USING THIS TYPE OF FORM MEANS WE NEED TO DISSABLE ACCELERATORS WHEN WE FOCUS ON A CONTROL THAT TAKES -- KEY PRESSES SUCH AS SPINNERS AND TEXT BOXES --Get the max handle pointer. local maxHandlePointer=(Windows.GetMAXHWND()) --Convert the HWND handle of Max to a dotNet system pointer local sysPointer = DotNetObject "System.IntPtr" maxHandlePointer --Create a dotNet wrapper containing the maxHWND local maxHwnd = DotNetObject "MaxCustomControls.Win32HandleWrapper" sysPointer miloRoomForm = RS_dotNetUI.Form "miloRoomForm" text:"Procedural Types" size:[216,512] min:[216,128] borderStyle:RS_dotNetPreset.FB_SizableToolWindow miloRoomForm.StartPosition = (dotNetClass "System.Windows.Forms.FormStartPosition").CenterScreen dotnet.addEventHandler miloRoomForm "FormClosing" dispatchMiloRoomFormClosing miloRoomListview = RS_dotNetUI.listView "attributeListView" dockStyle:RS_dotNetPreset.DS_Fill miloRoomListview.HeaderStyle = (dotNetClass "System.Windows.Forms.ColumnHeaderStyle").None miloRoomListview.columns.add "Milo Rooms" miloRoomListview.items.Add (dotNetObject "ListViewItem" "None") miloRoomOkButton = RS_dotNetUI.Button "miloRoomOkButton" text:("OK") dockStyle:RS_dotNetPreset.DS_Fill margin:(RS_dotNetObject.paddingObject 2) dotnet.addEventHandler miloRoomOkButton "click" dispatchOkButtonClick miloRoomCancelButton = RS_dotNetUI.Button "miloRoomCancelButton" text:("Cancel") dockStyle:RS_dotNetPreset.DS_Fill margin:(RS_dotNetObject.paddingObject 2) dotnet.addEventHandler miloRoomCancelButton "click" dispatchCancelButtonClick miloRoomLayout = RS_dotNetUI.tableLayout "miloRoomLayout" text:"miloRoomLayout" collumns:#((dataPair type:"Percent" value:50),(dataPair type:"Percent" value:50)) \ rows:#((dataPair type:"Percent" value:50),(dataPair type:"Absolute" value:24)) dockStyle:RS_dotNetPreset.DS_Fill miloRoomLayout.controls.add miloRoomListview 0 0 miloRoomLayout.controls.add miloRoomOkButton 0 1 miloRoomLayout.controls.add miloRoomCancelButton 1 1 miloRoomLayout.SetColumnSpan miloRoomListview 2 miloRoomForm.controls.add miloRoomLayout addMiloRoomItem helpers miloRoomListview.AutoResizeColumns (dotNetClass "ColumnHeaderAutoResizeStyle").HeaderSize miloRoomForm.show maxHwnd ), --------------------------------------------------------------------------------------------------------------------------------------- -- dispatchProceduralFormClosing() Dispatches proceduralFormClosing() Called when the procedural dialog is closed --------------------------------------------------------------------------------------------------------------------------------------- fn dispatchProceduralFormClosing s e = ( ::RSL_CollisionOps.attribute.proceduralFormClosing s e ), --------------------------------------------------------------------------------------------------------------------------------------- -- proceduralFormClosing() Enables the main form --------------------------------------------------------------------------------------------------------------------------------------- fn proceduralFormClosing s e = ( ::RSL_CollisionOps.CollisionForm.enabled = true ), --------------------------------------------------------------------------------------------------------------------------------------- -- proceduralFormClosing() Creates the procedural dialog --------------------------------------------------------------------------------------------------------------------------------------- fn proceduralTypeDialog = ( -- dissable the main form whilst the procedural dialog is open RSL_CollisionOps.CollisionForm.enabled = false --In this case, we're going to use a standard form rather than the custom maxForm written for max. this is because I want to change the -- form back colour which you can't do if you use the custom maxForm. For this to work, we need to set the parent of the form to be Max. -- USING THIS TYPE OF FORM MEANS WE NEED TO DISSABLE ACCELERATORS WHEN WE FOCUS ON A CONTROL THAT TAKES -- KEY PRESSES SUCH AS SPINNERS AND TEXT BOXES --Get the max handle pointer. local maxHandlePointer=(Windows.GetMAXHWND()) --Convert the HWND handle of Max to a dotNet system pointer local sysPointer = DotNetObject "System.IntPtr" maxHandlePointer --Create a dotNet wrapper containing the maxHWND local maxHwnd = DotNetObject "MaxCustomControls.Win32HandleWrapper" sysPointer proceduralTypeForm = RS_dotNetUI.Form "proceduralTypeForm" text:"Procedural Types" size:[216,512] min:[216,128] borderStyle:RS_dotNetPreset.FB_SizableToolWindow proceduralTypeForm.StartPosition = (dotNetClass "System.Windows.Forms.FormStartPosition").CenterScreen dotnet.addEventHandler proceduralTypeForm "FormClosing" dispatchProceduralFormClosing proceduralTypeListview = RS_dotNetUI.listView "attributeListView" dockStyle:RS_dotNetPreset.DS_Fill proceduralTypeListview.HeaderStyle = (dotNetClass "System.Windows.Forms.ColumnHeaderStyle").None proceduralTypeListview.columns.add "type" proceduralTypeOkButton = RS_dotNetUI.Button "proceduralTypeOkButton" text:("OK") dockStyle:RS_dotNetPreset.DS_Fill margin:(RS_dotNetObject.paddingObject 2) dotnet.addEventHandler proceduralTypeOkButton "click" dispatchOkButtonClick proceduralTypeCancelButton = RS_dotNetUI.Button "proceduralTypeCancelButton" text:("Cancel") dockStyle:RS_dotNetPreset.DS_Fill margin:(RS_dotNetObject.paddingObject 2) dotnet.addEventHandler proceduralTypeCancelButton "click" dispatchCancelButtonClick proceduralTypeLayout = RS_dotNetUI.tableLayout "proceduralTypeLayout" text:"proceduralTypeLayout" collumns:#((dataPair type:"Percent" value:50),(dataPair type:"Percent" value:50)) \ rows:#((dataPair type:"Percent" value:50),(dataPair type:"Absolute" value:24)) dockStyle:RS_dotNetPreset.DS_Fill proceduralTypeLayout.controls.add proceduralTypeListview 0 0 proceduralTypeLayout.controls.add proceduralTypeOkButton 0 1 proceduralTypeLayout.controls.add proceduralTypeCancelButton 1 1 proceduralTypeLayout.SetColumnSpan proceduralTypeListview 2 proceduralTypeForm.controls.add proceduralTypeLayout addTypeItem proceduralArray proceduralTypeListview proceduralTypeListview.AutoResizeColumns (dotNetClass "ColumnHeaderAutoResizeStyle").HeaderSize proceduralTypeForm.show maxHwnd ), --------------------------------------------------------------------------------------------------------------------------------------- -- dispatchPieceFormClosing() Dispatches pieceFormClosing() Called when the piece type dialog is closed --------------------------------------------------------------------------------------------------------------------------------------- fn dispatchPieceFormClosing s e = ( ::RSL_CollisionOps.attribute.pieceFormClosing s e ), --------------------------------------------------------------------------------------------------------------------------------------- -- pieceFormClosing() Enables the main form --------------------------------------------------------------------------------------------------------------------------------------- fn pieceFormClosing s e = ( ::RSL_CollisionOps.CollisionForm.enabled = true ), --------------------------------------------------------------------------------------------------------------------------------------- -- pieceFormClosing() Creates the piece type dialog --------------------------------------------------------------------------------------------------------------------------------------- fn pieceTypeDialog = ( -- dissable the main form whilst the piece type dialog is open RSL_CollisionOps.CollisionForm.enabled = false --In this case, we're going to use a standard form rather than the custom maxForm written for max. this is because I want to change the -- form back colour which you can't do if you use the custom maxForm. For this to work, we need to set the parent of the form to be Max. -- USING THIS TYPE OF FORM MEANS WE NEED TO DISSABLE ACCELERATORS WHEN WE FOCUS ON A CONTROL THAT TAKES -- KEY PRESSES SUCH AS SPINNERS AND TEXT BOXES --Get the max handle pointer. local maxHandlePointer=(Windows.GetMAXHWND()) --Convert the HWND handle of Max to a dotNet system pointer local sysPointer = DotNetObject "System.IntPtr" maxHandlePointer --Create a dotNet wrapper containing the maxHWND local maxHwnd = DotNetObject "MaxCustomControls.Win32HandleWrapper" sysPointer pieceTypeForm = RS_dotNetUI.Form "pieceTypeForm" text:"Piece Types" size:[216,512] min:[216,128] borderStyle:RS_dotNetPreset.FB_SizableToolWindow pieceTypeForm.StartPosition = (dotNetClass "System.Windows.Forms.FormStartPosition").CenterScreen dotnet.addEventHandler pieceTypeForm "FormClosing" dispatchPieceFormClosing pieceTypeListview = RS_dotNetUI.listView "attributeListView" dockStyle:RS_dotNetPreset.DS_Fill pieceTypeListview.HeaderStyle = (dotNetClass "System.Windows.Forms.ColumnHeaderStyle").None pieceTypeListview.columns.add "type" pieceTypeOkButton = RS_dotNetUI.Button "pieceTypeOkButton" text:("OK") dockStyle:RS_dotNetPreset.DS_Fill margin:(RS_dotNetObject.paddingObject 2) dotnet.addEventHandler pieceTypeOkButton "click" dispatchOkButtonClick pieceTypeCancelButton = RS_dotNetUI.Button "pieceTypeCancelButton" text:("Cancel") dockStyle:RS_dotNetPreset.DS_Fill margin:(RS_dotNetObject.paddingObject 2) dotnet.addEventHandler pieceTypeCancelButton "click" dispatchCancelButtonClick pieceTypeLayout = RS_dotNetUI.tableLayout "pieceTypeLayout" text:"pieceTypeLayout" collumns:#((dataPair type:"Percent" value:50),(dataPair type:"Percent" value:50)) \ rows:#((dataPair type:"Percent" value:50),(dataPair type:"Absolute" value:24)) dockStyle:RS_dotNetPreset.DS_Fill pieceTypeLayout.controls.add pieceTypeListview 0 0 pieceTypeLayout.controls.add pieceTypeOkButton 0 1 pieceTypeLayout.controls.add pieceTypeCancelButton 1 1 pieceTypeLayout.SetColumnSpan pieceTypeListview 2 pieceTypeForm.controls.add pieceTypeLayout addTypeItem pieceTypeArray pieceTypeListview pieceTypeListview.AutoResizeColumns (dotNetClass "ColumnHeaderAutoResizeStyle").HeaderSize pieceTypeForm.show maxHwnd ), --------------------------------------------------------------------------------------------------------------------------------------- -- dispatchSurfaceFormClosing() Dispatches surfaceFormClosing() Called when the surface type dialog is closed --------------------------------------------------------------------------------------------------------------------------------------- fn dispatchSurfaceFormClosing s e = ( ::RSL_CollisionOps.attribute.surfaceFormClosing s e ), --------------------------------------------------------------------------------------------------------------------------------------- -- surfaceFormClosing() Enables the main form --------------------------------------------------------------------------------------------------------------------------------------- fn surfaceFormClosing s e = ( ::RSL_CollisionOps.CollisionForm.enabled = true ), --------------------------------------------------------------------------------------------------------------------------------------- -- dispatchEditColourClick() Dispatches editColourClick() Called when the editColour menu item is clicked --------------------------------------------------------------------------------------------------------------------------------------- fn dispatchEditColourClick s e = ( ::RSL_CollisionOps.attribute.editColourClick s e ), --------------------------------------------------------------------------------------------------------------------------------------- -- editColourClick() Displays the colour dialog and sets the new colour --------------------------------------------------------------------------------------------------------------------------------------- fn editColourClick s e = ( -- get the listView the menu item is assigned to local listView = s.Owner.SourceControl -- get the list view item that was right clicked local source = listView.GetItemAt mousePoint.x mousePoint.y if source != undefined then ( -- set the colour dialog colour to the back colour of the right clicked list view item colourDialog.Color = source.backColor -- if the user presses the ok button in the colour dialog, we can set the colour if (colourDialog.ShowDialog()) == (dotNetClass "DialogResult").ok then ( source.backColor = colourDialog.Color -- check to see if the fore colour and back colour are too similar local backColTotal = source.backColor.r + source.backColor.g + source.backColor.b local foreColTotal = source.foreColor.r + source.foreColor.g + source.foreColor.b -- they are so we set the fore colour to either white or black if (abs (backColTotal - foreColTotal)) < 128 then ( if source.foreColor == RS_dotNetClass.colourClass.White then ( source.foreColor = RS_dotNetClass.colourClass.Black ) else ( source.foreColor = RS_dotNetClass.colourClass.White ) ) -- save the colour to the INI file and update the texture setColour source.text source.backColor ) ) ), --------------------------------------------------------------------------------------------------------------------------------------- -- dispatchCopyPasteColourClick() Dispatches copyPasteColourClick() Called when either the copyColour or pasteColour menu -- items are clicked --------------------------------------------------------------------------------------------------------------------------------------- fn dispatchCopyPasteColourClick s e = ( ::RSL_CollisionOps.attribute.copyPasteColourClick s e ), --------------------------------------------------------------------------------------------------------------------------------------- -- copyPasteColourClick() Depending on which menu item was clicked, copies the right clicked list view item's colour or pastes -- an alread copied colour onto the right clicked list view item --------------------------------------------------------------------------------------------------------------------------------------- fn copyPasteColourClick s e = ( -- get the listView the menu item is assigned to local listView = s.Owner.SourceControl -- get the list view item that was right clicked local source = listView.GetItemAt mousePoint.x mousePoint.y if source != undefined then ( case s.name of ( "copyColour": ( -- set the copiedColour struct variable to the back colour of the right clicked list view item -- and enable the pasteColour menu item copiedColour = source.backColor pasteColour.enabled = true ) "pasteColour": ( if copiedColour != undefined then ( -- set the bacl colour of the right clicked list view item to the copiedColour source.backColor = copiedColour -- check to see if the fore colour and back colour are too similar local backColTotal = copiedColour.r + copiedColour.g + copiedColour.b local foreColTotal = source.foreColor.r + source.foreColor.g + source.foreColor.b -- they are so we set the fore colour to either white or black if (abs (backColTotal - foreColTotal)) < 128 then ( if source.foreColor == RS_dotNetClass.colourClass.White then ( source.foreColor = RS_dotNetClass.colourClass.Black ) else ( source.foreColor = RS_dotNetClass.colourClass.White ) ) -- save the colour to the INI file and update the texture setColour source.text source.backColor ) ) ) ) ), --------------------------------------------------------------------------------------------------------------------------------------- -- dispatchSelectFacesClick() Dispatches selectFacesClick() Called when the selectFaces copyColour menu item is clicked --------------------------------------------------------------------------------------------------------------------------------------- fn dispatchSelectFacesClick s e = ( ::RSL_CollisionOps.attribute.selectFacesClick s e ), --------------------------------------------------------------------------------------------------------------------------------------- -- selectFacesClick() Selects any faces in the currentMesh if they are set to the surface type of the right clicked list -- view item. THIS IS ONLY AVAILABLE IN EDIT MODE --------------------------------------------------------------------------------------------------------------------------------------- fn selectFacesClick s e = ( -- get the list view local listView = s.Tag.Value -- get the right clicked list view item local source = listView.GetItemAt mousePoint.x mousePoint.y -- get all the surface values for the currentMesh. Uses SimpleFaceData local surfaceArray = ::RSL_CollisionOps.editUI.surfaceChannel.getValues() local faceArray = #() if ::RSL_CollisionOps.currentTool.name == "editTableLayout" then ( -- check to see if the control key is being held down. If so, we add the currently selected faces to faceArray -- so that we will grow the 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 ) ) -- loop through all the surface types on the object and append any face indices for face that have the surface type for i = 1 to surfaceArray.count do ( local surfaceType = fullMaterialsDatSurfaceTypeArray[surfaceArray[i]] if surfaceType == source.text then ( appendIfUnique faceArray i ) ) -- make sure we're in modify mode and face mode, then select the faces setCommandPanelTaskMode #modify subObjectLevel = 4 ::RSL_CollisionOps.currentMesh.selectedFaces = #() ::RSL_CollisionOps.currentMesh.selectedFaces = faceArray ), --------------------------------------------------------------------------------------------------------------------------------------- -- dispatchRightClickOpening() Dispatches rightClickOpening() Called when the user right clicks a list view item in the surface -- type pallette --------------------------------------------------------------------------------------------------------------------------------------- fn dispatchRightClickOpening s e = ( ::RSL_CollisionOps.attribute.rightClickOpening s e ), --------------------------------------------------------------------------------------------------------------------------------------- -- rightClickOpening() Sets the mousePoint struct variable to the mouse position and the enabled state of the selectFaces -- menu item --------------------------------------------------------------------------------------------------------------------------------------- fn rightClickOpening s e = ( local listView = s.SourceControl mousePoint = listView.PointToClient (listView.Cursor.Position) selectFaces.enabled = ::RSL_CollisionOps.currentType == #rexbound ), --------------------------------------------------------------------------------------------------------------------------------------- -- dispatchPalletteListClick() Dispatches PalletteListClick() Called when the user clicks a list view item in the surface -- type pallette --------------------------------------------------------------------------------------------------------------------------------------- fn dispatchPalletteListClick s e = ( ::RSL_CollisionOps.attribute.PalletteListClick s e ), --------------------------------------------------------------------------------------------------------------------------------------- -- PalletteListClick() Sets the mousePoint struct variable to the mouse position, the lastType stuct variable to the text -- of the selected list view item and the lastColour struct variable to the back colour of the selected list view item --------------------------------------------------------------------------------------------------------------------------------------- fn PalletteListClick s e = ( mousePoint = s.PointToClient (s.Cursor.Position) if s.selectedItems.count == 1 then ( lastType = s.selectedItems.item[0].text lastColour = s.selectedItems.item[0].backColor setINISetting INIFile "settings" "lastType" lastType ) ), --------------------------------------------------------------------------------------------------------------------------------------- -- dispatchPalletteListDoubleClick() Dispatches palletteListDoubleClick() Called when the user double clicks a list view item -- in the surface type pallette --------------------------------------------------------------------------------------------------------------------------------------- fn dispatchPalletteListDoubleClick s e = ( ::RSL_CollisionOps.attribute.palletteListDoubleClick s e ), --------------------------------------------------------------------------------------------------------------------------------------- -- palletteListDoubleClick() If we're in Create mode, sets the lastType stuct variable to the text of the selected list view -- item and the lastColour struct variable to the back colour of the selected list view item and then closes the surface type dialog. -- If we're in Edit mode, runs the selectFacesClick function. --------------------------------------------------------------------------------------------------------------------------------------- fn palletteListDoubleClick s e = ( if s.selectedItems.count == 1 then ( if ::RSL_CollisionOps.currentTool.name == "editTableLayout" and ::RSL_CollisionOps.currentType == #rebound then ( selectFacesClick selectFaces "" ) else ( lastType = s.selectedItems.item[0].text lastColour = s.selectedItems.item[0].backColor setINISetting INIFile "settings" "lastType" lastType OkButtonClick surfaceTypeOkButton "" ) ) ), --------------------------------------------------------------------------------------------------------------------------------------- -- dispatchPalletteListResize() Dispatches palletteListResize() Called when the user resizes the surface type dialog or pallette --------------------------------------------------------------------------------------------------------------------------------------- fn dispatchPalletteListResize s e = ( ::RSL_CollisionOps.attribute.palletteListResize s e ), --------------------------------------------------------------------------------------------------------------------------------------- -- palletteListResize() Resizes the list view column --------------------------------------------------------------------------------------------------------------------------------------- fn palletteListResize s e = ( if palletteList.columns.count > 0 then ( palletteList.columns.Item[0].width = (::RSL_CollisionOps.CollisionForm.width - 42) ) ), --------------------------------------------------------------------------------------------------------------------------------------- -- surfaceTypePallette() Creates the surface type pallette for the Edit mode. The parsed type variable controls which -- surface type array we use to populate the pallette. The parsed searchText variable is used the filter the surface types. -- Returns the list view. --------------------------------------------------------------------------------------------------------------------------------------- fn surfaceTypePallette type searchText = ( editColour = RS_dotNetUI.ToolStripMenuItem "editColour" text:"Edit Colour" dotnet.addEventHandler editColour "Click" dispatchEditColourClick copyColour = RS_dotNetUI.ToolStripMenuItem "copyColour" text:"Copy Colour" dotnet.addEventHandler copyColour "Click" dispatchCopyPasteColourClick pasteColour = RS_dotNetUI.ToolStripMenuItem "pasteColour" text:"Paste Colour" pasteColour.enabled = false dotnet.addEventHandler pasteColour "Click" dispatchCopyPasteColourClick selectFaces = RS_dotNetUI.ToolStripMenuItem "selectFaces" text:"Select Faces" selectFaces.enabled = (type == #rexBound) dotnet.addEventHandler selectFaces "Click" dispatchSelectFacesClick typeControlMenu = RS_dotNetUI.ContextMenuStrip "typeControlMenu" items:#(selectFaces,RS_dotNetUI.separator(),editColour,RS_dotNetUI.separator(),copyColour,pasteColour) dotnet.addEventHandler typeControlMenu "Opening" dispatchRightClickOpening colourDialog.FullOpen = true palletteList = RS_dotNetUI.listView "palletteList" dockStyle:RS_dotNetPreset.DS_Fill palletteList.view = (dotNetClass "System.Windows.Forms.View").Details palletteList.HeaderStyle = (dotNetClass "System.Windows.Forms.ColumnHeaderStyle").None palletteList.Sorting = (dotNetClass "System.Windows.Forms.SortOrder").None palletteList.HideSelection = false palletteList.scrollable = true palletteList.fullRowSelect = true palletteList.ContextMenuStrip = typeControlMenu palletteList.backColor = RS_dotNetPreset.controlColour_Medium dotnet.addEventHandler palletteList "SelectedIndexChanged" dispatchPalletteListClick dotnet.addEventHandler palletteList "MouseDoubleClick" dispatchPalletteListDoubleClick dotNet.addEventHandler palletteList "Resize" dispatchPalletteListResize -- Depending on the parsed type, we populate the pallette from the correct surface type array if type == #primitive then ( addSurfaceTypeItem attSurfaceTypeArray palletteList searchText ) else ( addSurfaceTypeItem matDatSurfaceTypeArray palletteList searchText ) selectFaces.tag = dotNetMXSValue palletteList palletteList.Columns.Add "SurfaceType" (::RSL_CollisionOps.CollisionForm.width - 42) palletteList ), --------------------------------------------------------------------------------------------------------------------------------------- -- surfaceTypeDialog() Creates the surface type dialog use in Create mode. The parsed type variable controls which -- surface type array we use to populate the pallette. --------------------------------------------------------------------------------------------------------------------------------------- fn surfaceTypeDialog type = ( RSL_CollisionOps.CollisionForm.enabled = false --In this case, we're going to use a standard form rather than the custom maxForm written for max. this is because I want to change the -- form back colour which you can't do if you use the custom maxForm. For this to work, we need to set the parent of the form to be Max. -- USING THIS TYPE OF FORM MEANS WE NEED TO DISSABLE ACCELERATORS WHEN WE FOCUS ON A CONTROL THAT TAKES -- KEY PRESSES SUCH AS SPINNERS AND TEXT BOXES --Get the max handle pointer. local maxHandlePointer=(Windows.GetMAXHWND()) --Convert the HWND handle of Max to a dotNet system pointer local sysPointer = DotNetObject "System.IntPtr" maxHandlePointer --Create a dotNet wrapper containing the maxHWND local maxHwnd = DotNetObject "MaxCustomControls.Win32HandleWrapper" sysPointer surfaceTypeForm = RS_dotNetUI.Form "surfaceTypeForm" text:"Surface Types" size:[216,512] min:[216,128] borderStyle:RS_dotNetPreset.FB_SizableToolWindow surfaceTypeForm.StartPosition = (dotNetClass "System.Windows.Forms.FormStartPosition").CenterScreen dotnet.addEventHandler surfaceTypeForm "FormClosing" dispatchSurfaceFormClosing editColour = RS_dotNetUI.ToolStripMenuItem "editColour" text:"Edit Colour" dotnet.addEventHandler editColour "Click" dispatchEditColourClick copyColour = RS_dotNetUI.ToolStripMenuItem "copyColour" text:"Copy Colour" dotnet.addEventHandler copyColour "Click" dispatchCopyPasteColourClick pasteColour = RS_dotNetUI.ToolStripMenuItem "pasteColour" text:"Paste Colour" pasteColour.enabled = false dotnet.addEventHandler pasteColour "Click" dispatchCopyPasteColourClick typeControlMenu = RS_dotNetUI.ContextMenuStrip "typeControlMenu" items:#(editColour,RS_dotNetUI.separator(),copyColour,pasteColour) colourDialog.FullOpen = true palletteList = RS_dotNetUI.listView "palletteList" dockStyle:RS_dotNetPreset.DS_Fill palletteList.view = (dotNetClass "System.Windows.Forms.View").Details palletteList.HeaderStyle = (dotNetClass "System.Windows.Forms.ColumnHeaderStyle").None palletteList.Sorting = (dotNetClass "System.Windows.Forms.SortOrder").None palletteList.HideSelection = false palletteList.scrollable = true palletteList.fullRowSelect = true palletteList.ContextMenuStrip = typeControlMenu palletteList.backColor = RS_dotNetPreset.controlColour_Medium dotnet.addEventHandler palletteList "SelectedIndexChanged" dispatchPalletteListClick dotnet.addEventHandler palletteList "MouseDoubleClick" dispatchPalletteListDoubleClick dotNet.addEventHandler palletteList "Resize" dispatchPalletteListResize -- Depending on the parsed type, we populate the pallette from the correct surface type array if type == #primitive then ( addSurfaceTypeItem attSurfaceTypeArray palletteList "" ) else ( addSurfaceTypeItem matDatSurfaceTypeArray palletteList "" ) palletteList.Columns.Add "SurfaceType" (::RSL_CollisionOps.CollisionForm.width - 42) surfaceTypeOkButton = RS_dotNetUI.Button "surfaceTypeOkButton" text:("OK") dockStyle:RS_dotNetPreset.DS_Fill margin:(RS_dotNetObject.paddingObject 2) dotnet.addEventHandler surfaceTypeOkButton "click" dispatchOkButtonClick surfaceTypeCancelButton = RS_dotNetUI.Button "surfaceTypeCancelButton" text:("Cancel") dockStyle:RS_dotNetPreset.DS_Fill margin:(RS_dotNetObject.paddingObject 2) dotnet.addEventHandler surfaceTypeCancelButton "click" dispatchCancelButtonClick surfaceTypeLayout = RS_dotNetUI.tableLayout "surfaceTypeLayout" text:"surfaceTypeLayout" collumns:#((dataPair type:"Percent" value:50),(dataPair type:"Percent" value:50)) \ rows:#((dataPair type:"Percent" value:50),(dataPair type:"Absolute" value:24)) dockStyle:RS_dotNetPreset.DS_Fill surfaceTypeLayout.controls.add palletteList 0 0 surfaceTypeLayout.controls.add surfaceTypeOkButton 0 1 surfaceTypeLayout.controls.add surfaceTypeCancelButton 1 1 surfaceTypeLayout.SetColumnSpan palletteList 2 surfaceTypeForm.controls.add surfaceTypeLayout surfaceTypeForm.show maxHwnd ) )