Files
gtav-src/tools_ng/wildwest/script/3dsMax/Maps/Materials/terrain_painter.ms
T
2025-09-29 00:52:08 +02:00

2724 lines
84 KiB
Plaintext
Executable File

--
-- Description:: Data driven utilities for manipulating the terrain shader
--
-- Author:: Luke Openshaw <luke.openshaw@rockstarnorth.com>
-- Author:: Marissa Warner-Wu <marissa.warner-wu@rockstarnorth.com>
--
-----------------------------------------------------------------------------
-- HISTORY
-- 11/11/2009
-- by Stuart Macdonald
-- Added undo to vert and face colouring
-- Fixed bitmap resize load ( line 399 )
--
-- 9/11/2009
-- by Marissa Warner-Wu
-- Incorporated terrain texture palette tool from Aaron/Stu.
--
-- 4/12/2008
-- by Luke Openshaw
-- Update: Hack in Multisub support
--
-- 16/05/2014
-- by Neal D Corbett
-- Update: UI rewritten to completely use DotNet controls.
-- Now compatible with RDR UberTerrain shaders.
-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
-- Uses
-----------------------------------------------------------------------------
try (gRsTerrainPalette.ToolForm.Close()) catch ()
Callbacks.RemoveScripts id:#RsTerrainPaint
global gRsTerrainPalette = undefined
RSTA_LoadCommonFunction #("fn_RSTA_vertexColours.ms")
filein (RsConfigGetWildwestDir() + "Script/3dsMax/Maps/Materials/terrain_helperFunctions.ms")
filein (RsConfigGetWildWestDir() + "/script/3dsMax/_common_functions/fn_RSTA_ThumbsMgr.ms")
filein (RsConfigGetWildWestDir() + "script/3dsMax/General_tools/Selection_Funcs.ms")
-- Struct for passing options to 'ev_SelSubObjsMenuItem_Clicked'
struct RsTerrPal_SelSubObjOpts (SubObjName, AddSel = False, RemSel = False, IgnoreBitmaps = False, Dominant = False)
--------------------------------------------------------------
-- Terrain texture palette:
--------------------------------------------------------------
struct RsTerrainPalette
(
RsBannerPanel = DotNetObject "Panel",
BannerStruct = makeRsBanner dn_Panel:RsBannerPanel wiki:"Terrain_Paint" versionNum:1.53 versionName:"Miraculous Tern",
FormSize = [574, 804],
TerrainObj, -- Currently-selected mesh-object
TerrainMatInfoList = #(), -- Terrain-material info-list taken from current 'TerrainObj'
TerrainMatIds, -- MatId lookup-list for 'TerrainMatInfoList'
SelMatInfo, -- Currently-selected material-info
vPaintTool, -- Active instance of VertexPaint
DoneVertChecks = #(), -- Used to track which objects/channels have had 'RsHasCompressedVertChan' run on them.
-- Tool's form and defined controls (so functions can quickly find them)
ToolForm = dotNetObject "MaxCustomControls.MaxForm",
ObjEditPanels = #(),
ScrollPanel, ShowChansPanel, TexmapPanel, MatPanels = #(),
CboShaderType, ChkPickMat, SpnDeselPercent, ChkVertPaint, SpnFillStrength, SldLookupMask, SldTintMask, SldDisplaceMask,
-- Texmap rightclick-menus, per shadertype:
TexmapRCMenus = (DataPair ShaderTypes:#() Menus:#()),
-- Mask-options control-panel is collapsed by default:
MaskDropdownActive = False,
MaskCtrlPanel,
-- Local aliases to hold button-functions:
TexmapBtnFunc, TexmapBtnPaintFunc, SetMaskBtnFunc,
-- Thumbnail-manager:
ToolName = #TerrainPainter,
Thumbs = (RSTA_ThumbsMgr.GetThumbsStruct ToolName),
dnTooltip = (dotNetObject "ToolTip"),
dnColour = (dotNetClass "System.Drawing.Color"),
SizeType_AutoSize = (dotNetClass "SizeType").AutoSize,
SizeType_Absolute = (dotNetClass "SizeType").Absolute,
SizeType_Percent = (dotNetClass "SizeType").Percent,
-- Suspend/ResumeRedraw:
-- Disable/Enable tool's window-redraw functionality:
WM_SETREDRAW=0xB,
fn SuspendRedraw =
(
Windows.Sendmessage ToolForm.Handle WM_SETREDRAW 0 0
),
fn ResumeRedraw =
(
Windows.Sendmessage ToolForm.Handle WM_SETREDRAW 1 0
),
------------------------------------------------------------------------------
-- isBtnChecked:
-- Returns 'True' if a button has been set to 'Flat' style:
------------------------------------------------------------------------------
fn isBtnChecked ThisBtn =
(
return (ThisBtn.FlatStyle == ThisBtn.FlatStyle.Flat)
),
------------------------------------------------------------------------------
-- SetBtnChecked:
-- Sets button style to make it look checked or not
------------------------------------------------------------------------------
fn SetBtnChecked ThisBtn Checked =
(
if Checked then
(
-- Don't allow button to autosize in this mode:
local BtnWidth = ThisBtn.Width
local BtnHeight = ThisBtn.Height
ThisBtn.AutoSize = False
ThisBtn.Width = BtnWidth
ThisBtn.Height = BtnHeight
-- These colours are only shown if button is set to 'Flat' style,
ThisBtn.BackColor = dnColour.Orange
ThisBtn.ForeColor = dnColour.Black
ThisBtn.FlatStyle = ThisBtn.FlatStyle.Flat
)
else
(
ThisBtn.FlatStyle = ThisBtn.FlatStyle.System
ThisBtn.AutoSize = True
)
ThisBtn.Refresh()
),
---------------------------------------------------------------------------------------
-- GetSelMatInfo:
-- Returns currently-selected terrain-material (or 'undefined' if none)
---------------------------------------------------------------------------------------
fn GetSelMatInfo UpdateData:False =
(
-- Ensure that material-faces are still up-to-date:
if UpdateData do
(
::gRsTerrainPalette.PopulateMaterialList()
)
if (TexmapPanel.Tag == undefined) then undefined else
(
TexmapPanel.Tag.Value.MatInfo
)
),
---------------------------------------------------------------------------------------
-- GetSelTexNum:
-- Returns currently-selected texmap-index (or '0' if none)
---------------------------------------------------------------------------------------
fn GetSelTexNum =
(
local TexNum = 0
if (TexmapPanel.Tag != undefined) do
(
TexNum = (TexmapPanel.Tag.Value.TexNum)
)
return TexNum
),
---------------------------------------------------------------------------------------
-- GetSelShaderTypeInfo:
-- Returns currently-selected shadertype-info (with material-list)
---------------------------------------------------------------------------------------
fn GetSelShaderTypeInfo =
(
local SelNum = (CboShaderType.SelectedIndex + 1)
if (SelNum == 0) then undefined else TerrainMatInfoList[SelNum]
),
---------------------------------------------------------------------------------------
-- GetSelShaderTypeDef:
-- Returns currently-active shadertype-definition (or 'undefined' if none)
---------------------------------------------------------------------------------------
fn GetSelShaderTypeDef =
(
local TypeDef = undefined
local SelTypeInfo = GetSelShaderTypeInfo()
if (SelTypeInfo != undefined) do
(
local MatInfo = SelTypeInfo.MatInfoList[1]
if (MatInfo != undefined) do
(
TypeDef = MatInfo.TypeDef
)
)
return TypeDef
),
---------------------------------------------------------------------------------------
-- GetSelShaderMatInfoList:
-- Returns material-info list for currently-active shadertype-definition
---------------------------------------------------------------------------------------
fn GetSelShaderMatInfoList =
(
local MatInfoList = #()
local SelTypeInfo = GetSelShaderTypeInfo()
if (SelTypeInfo != undefined) do
(
MatInfoList = SelTypeInfo.MatInfoList
)
return MatInfoList
),
---------------------------------------------------------------------------------------
-- GetTexmapsCount:
-- Returns maximum texturemap-slot count for shown materials:
---------------------------------------------------------------------------------------
fn GetTexmapsCount =
(
-- Get current shadertype's material-info list:
local MatInfoList = GetSelShaderMatInfoList()
-- Collect texcounts for materials
local TexCounts = for MatInfo in MatInfoList collect MatInfo.TexCount
-- Return highest texcount:
return (aMax TexCounts)
),
-- DoWeldCheck:
-- Check obj for compressed (welded) verts - these will go wrong when painted.
-- tracks objects/channels this has been done for this session, as we shouldn't have to repeat)
fn DoWeldCheck Obj Chans =
(
for Chan in Chans do
(
-- Build string from object-handle and specific channel-number:
local CheckString = ((Obj.Handle as String) + "|" + (Chan as String))
-- Only run check/fix welded verts if object's channel hasn't been checked already:
if (appendIfUnique DoneVertChecks CheckString) do
(
RsHasCompressedVertChan Obj.BaseObject Chan fix:True
)
)
return OK
),
---------------------------------------------------------------------------------------
-- AddGrpBox:
-- Function for adding Max-like dotnet group-boxes:
---------------------------------------------------------------------------------------
fn AddGrpBox AddToPanel Title:"" Size:1 PanelType: =
(
local GrpBox = dotNetObject "GroupBox"
GrpBox.FlatStyle = GrpBox.FlatStyle.System
GrpBox.Text = Title
GrpBox.Dock = GrpBox.Dock.Fill
GrpBox.AutoSize = True
GrpBox.Padding = (dotNetObject "Padding" 1)
-- Add groupbox-panel to parent:
AddToPanel.Controls.Add GrpBox
-- Add subpanel for holding controls:
local SubPanel = GrpBox
if (PanelType != unsupplied) do
(
SubPanel = dotnetobject PanelType
SubPanel.Width = 0
SubPanel.Height = 0
SubPanel.AutoSize = True
SubPanel.Dock = SubPanel.Dock.Fill
GrpBox.Controls.Add SubPanel
)
-- Return inner-panel that'll hold grouped controls:
return SubPanel
),
--------------------------------------------------------------
-- GetMaskColour:
-- Returns colour defined by mask-sliders
--------------------------------------------------------------
fn GetMaskColour TypeDef: =
(
if (TypeDef == unsupplied) do
(
TypeDef = GetSelShaderTypeDef()
)
-- Get mask-value from slider(s) if shown:
local MaskVals = for Item in
#(
(dataPair Slider:SldLookupMask Default:TypeDef.DefLookupMaskVal),
(dataPair Slider:SldTintMask Default:TypeDef.DefTintMaskVal),
(dataPair Slider:SldDisplaceMask Default:TypeDef.DefDisplaceMaskVal)
) collect
(
local MaskVal = undefined
local MaskSlider = Item.Slider
if (MaskSlider == undefined) then
(
MaskVal = Item.Default
)
else
(
MaskVal = MaskSlider.Value / (Float MaskSlider.Maximum)
)
MaskVal
)
local MaskColour
if (TypeDef.LookupMaskSubChan == undefined) then
(
-- Lookup-mask using full greyscale channel:
MaskColour = (White * MaskVals[1])
)
else
(
-- Build mask-colour from slider-values:
MaskColour = [0,0,0]
MaskColour[TypeDef.LookupMaskSubChan] = MaskVals[1] * 255
MaskColour[TypeDef.TintMaskSubChan] = MaskVals[2] * 255
MaskColour[TypeDef.DisplaceMaskSubChan] = MaskVals[3] * 255
MaskColour = (MaskColour as Color)
)
return MaskColour
),
-- Remove/Add callbacks:
fn RemoveCallbacks =
(
Callbacks.RemoveScripts id:#RsTerrainPaint
),
fn AddCallbacks =
(
-- Set up selection-change callback:
Callbacks.AddScript #SelectionSetChanged "gRsTerrainPalette.UpdateCtrls()" id:#RsTerrainPaint
),
--------------------------------------------------------------
-- PaintSelection:
-- Paints selected colour to selected subobjects
--------------------------------------------------------------
fn PaintSelection MaskColour: MaskSubChans: =
(
-- 'MaskSubChans' argument is only supplied by mask-edit buttons:
local JustMask = (MaskSubChans != unsupplied)
-- Set default mask-subchannels:
if (not JustMask) do (MaskSubChans = #{1,2,3})
-- Get selected-texmap index from panel-tag:
local TexNum = if JustMask then -1 else (GetSelTexNum())
-- Abort if no material-selection has been made:
if (TexNum == undefined) or (TexNum == 0) do return False
if not ((isValidNode TerrainObj) and (isEditPolyMesh TerrainObj)) do return False
local TypeDef = GetSelShaderTypeDef()
if (TypeDef == undefined) do return False
local TexClrList = TypeDef.LookupColours
local LookupChan = TypeDef.LookupClrChan
local MaskChan = TypeDef.MaskChan
-- Colour-edit definitions:
local EditDefs = #()
-- Does this shader use a lookup-texture mask-channel?
local HasMask = (MaskChan != undefined)
if HasMask do
(
-- Get 'MaskColour' rgb values from sliders/defaults:
if (not isKindOf MaskColour Color) do
(
MaskColour = GetMaskColour TypeDef:TypeDef
)
-- Add mask-edit to list:
local ModName = ("T-Mask [chan " + (MaskChan as string) + "]")
local MaskEdit = (RsVertClrsEditDef Chan:MaskChan Action:#Set InputVal:MaskColour ModName:ModName SubChans:MaskSubChans)
append EditDefs MaskEdit
)
-- Define colour-edit definition for lookup:
if (not JustMask) do
(
local ModName = ("T-Lookup [chan " + (LookupChan as string) + "]")
local LookupEdit = (RsVertClrsEditDef Chan:LookupChan Action:#Set InputVal:TexClrList[TexNum] ModName:ModName)
append EditDefs LookupEdit
)
-- We'll trigger multiple redraws for face-edits:
local DidFaces = False
case (GetSelectionLevel TerrainObj) of
(
#Object:
(
DidFaces = True
)
#face:
(
DidFaces = True
)
#vertex:
(
-- Vertex-editing will go wrong if channels have uvs used by multiple verts - fix if requried:
-- (once per channel per object per tool-session)
(
local CheckChans = #(LookupChan)
if HasMask do (append CheckChans MaskChan)
-- Check for compressed (welded) verts:
DoWeldCheck TerrainObj CheckChans
)
)
)
-- Apply edits to selection:
-- (with selection-change callbacks disabled)
RemoveCallbacks()
RsApplyVertClrChanges EditDefs doCollapse:True
AddCallbacks()
return OK
),
--------------------------------------------------------------
-- Functions for dealing with VertexPaint modifier:
--------------------------------------------------------------
-- Sets state of control 'ChkVertPaint':
fn SetChkVertPaintState State =
(
SetBtnChecked ChkVertPaint State
ChkVertPaint.Text = if State then "Stop Vertex Paint" else "Start Vertex Paint"
-- Clear link to modifier if deactivating vpaint-mode:
if (not State) do
(
vPaintTool = undefined
)
),
fn SetVertPaintColour =
(
local SelNum = GetSelTexNum()
if (SelNum == 0) or (vPaintTool == undefined) do return False
local SelMatInfo = GetSelMatInfo()
if (SelMatInfo == undefined) do return False
local TexClrList = SelMatInfo.TypeDef.LookupColours
vPaintTool.PaintColor = TexClrList[SelNum]
vPaintTool.CurPaintMode = 1
-- Trigger toolkit-update:
vPaintTool.keepToolboxOpen = vPaintTool.keepToolboxOpen
),
fn SetupVertPaintMod =
(
-- Get currently-selected shadertype-definition:
local TypeDef = GetSelShaderTypeDef()
-- Abort if TypeDef is undefined or terrain-object is invalid:
if (TypeDef == undefined) or (not (isValidNode TerrainObj)) or (not (isEditPolyMesh TerrainObj)) do
(
-- Deactivate button:
SetChkVertPaintState False
return False
)
-- Get lookup-colour channel:
local LookupClrChan = TypeDef.LookupClrChan
-- Make sure that object doesn't have welded lookup-verts:
DoWeldCheck TerrainObj #(LookupClrChan)
-- Search for lookup-vertexpaint modifier:
local vPaintMod = undefined
for ThisMod in TerrainObj.Modifiers while (vPaintMod == undefined) do
(
-- Is this a vertexpaint modifier, set up to edit the lookup-channel?
if (isKindOf ThisMod VertexPaint) and (ThisMod.MapChannel == LookupClrChan) do
(
vPaintMod = ThisMod
)
)
-- Add modifier if one wasn't found:
if (vPaintMod == undefined) do
(
vPaintMod = VertexPaint MapChannel:LookupClrChan
AddModifier TerrainObj vPaintMod
)
-- Get link to vertexpaint-tool:
vPaintTool = VertexPaintTool()
-- Set vertexpaint-colour to currently-active lookup-colour, if any:
SetVertPaintColour()
),
------------------------------------------------------------------------------
-- Functions for dealing with 'Select Channel' controls:
------------------------------------------------------------------------------
-- GetShowChanCtrls:
-- Get list of 'Show Channel' buttons:
------------------------------------------------------------------------------
fn GetShowChanCtrls =
(
for n = 0 to (ShowChansPanel.Controls.Count - 1) collect
(
ShowChansPanel.Controls.Item[n]
)
),
------------------------------------------------------------------------------
-- GetCurrShowChan:
-- Get name of objects' currently-shown terrain-channel:
------------------------------------------------------------------------------
fn GetShownChan =
(
local ChanNum = undefined
local SelObjs = for Obj in (GetCurrentSelection()) where (isEditPolyMesh Obj) collect Obj
for Obj in SelObjs do
(
local ObjChan = False
case of
(
(DisplayColor.Shaded == #Material):
(
if (not Obj.ShowVertexColors) do
(
ObjChan = -3
)
)
(not Obj.ShowVertexColors):()
(Obj.VertexColorType == #Alpha):
(
ObjChan = -2
)
(Obj.VertexColorType == #Color):
(
ObjChan = 0
)
(Obj.VertexColorType == #Map_Channel):
(
ObjChan = Obj.VertexColorMapChannel
)
)
case of
(
-- Stop looping objects if one returns undefined channel-number:
(ObjChan == undefined):(exit)
-- Keep first channel-number found:
(ChanNum == undefined):(ChanNum = ObjChan)
-- Clear ChanNum and stop looping if objects don't share channel-number
(ChanNum != ObjChan):
(
ChanNum = undefined
exit
)
)
)
return ChanNum
),
------------------------------------------------------------------------------
-- SetShowChanClicked:
-- Set matching channel-button to clicked, if applicable.
------------------------------------------------------------------------------
fn SetShowChanClicked ShownChan: =
(
-- Get name of currently-shown channel:
if (ShownChan == unsupplied) do
(
ShownChan = GetShownChan()
)
-- Uncheck all buttons, apart from one with matching name:
for ThisBtn in (GetShowChanCtrls()) do
(
SetBtnChecked ThisBtn (ThisBtn.Tag == ShownChan)
)
),
------------------------------------------------------------------------------
-- ShowChannel:
-- Show a particular vertex-colour channel on 'TerrainObj':
------------------------------------------------------------------------------
fn ShowChannel chan =
(
RsShowObjVertChannel chan
),
------------------------------------------------------------------------------
-- ev_SwapMenuItem_Clicked:
-- Used by texmap-swapper menu-items
-- Swaps two texmap-lookup colours for the current material:
------------------------------------------------------------------------------
fn ev_SwapMenuItem_Clicked Sender Args =
(
-- Get swap-options from control's tag:
local SwapOpts = Sender.Tag.Value
-- Get selected material-data, with updated face-list:
local TheTool = ::gRsTerrainPalette
local SelMatInfo = (TheTool.GetSelMatInfo UpdateData:True)
local SelTexNum = (TheTool.GetSelTexNum())
local SwapTexNum = (SwapOpts.SwapTexNum)
if (SelMatInfo == undefined) or (SelTexNum == 0) or (SelTexNum == SwapTexNum) do return False
-- Alter material/mesh:
SelMatInfo.SwapTexmaps SelTexNum SwapTexNum SwapMatSlots:(SwapOpts.SwapMatSlots) SwapLookups:(SwapOpts.SwapLookups)
-- Update UI buttons if required:
if (SwapOpts.SwapMatSlots) do
(
local SelMat = SelMatInfo.TerrainMat
-- Find material-panel whose tag-value's material matches selected material:
local MatPanel = undefined
for ThisPanel in TheTool.MatPanels while (MatPanel == undefined) do
(
local PanelMatInfo = ThisPanel.Tag.Value
if (PanelMatInfo.TerrainMat == SelMat) do
(
MatPanel = ThisPanel
)
)
-- Get the buttons for the swapped textures:
if (MatPanel != undefined) do
(
-- Get buttons for swap's two texmaps:
local Btns = for TexNum in #(SelTexNum, SwapTexNum) collect
(
-- Get button's highlight-colour panel:
local Ctrl = MatPanel.Controls.Item[TexNum - 1]
-- Get coloured-outline panel:
Ctrl = Ctrl.Controls.Item[0]
-- Collect button:
Ctrl.Controls.Item[0]
)
-- Swap button-images:
local BtnA = Btns[1]
local BtnB = Btns[2]
local ImgA = BtnA.BackgroundImage
BtnA.BackgroundImage = BtnB.BackgroundImage
BtnB.BackgroundImage = ImgA
)
)
),
----------------------------------------------------------------------------------
-- SelSubObjs:
-- Triggers subobject-selection functions with passed options
----------------------------------------------------------------------------------
fn SelSubObjs Opts =
(
local SubObjName = (Opts.SubObjName as Name)
local TheTool = ::gRsTerrainPalette
-- Get selected material-data, with updated face-list:
local SelMatInfo = (TheTool.GetSelMatInfo UpdateData:True)
local SelTexNum = (TheTool.GetSelTexNum())
if (SelMatInfo == undefined) do return False
local BaseObj = SelMatInfo.Obj.BaseObject
if not ((isKindOf BaseObj Editable_Poly) or (isKindOf BaseObj Editable_Mesh)) do return False
SetWaitCursor()
-- Get current subobject-selection, if it's going to be modified:
local SelItems = #{}
if (Opts.AddSel or Opts.RemSel) do
(
local SubObjLevel = RsGetSubObjLevelName()
case of
(
((SubObjName == #Verts) and (SubObjLevel == #Vertex)):
(
SelItems = if (isKindOf BaseObj Editable_Poly) then (PolyOp.GetVertSelection BaseObj) else (GetVertSelection BaseObj)
)
((SubObjName == #Faces) and (SubObjLevel == #Face)):
(
SelItems = if (isKindOf BaseObj Editable_Poly) then (PolyOp.GetFaceSelection BaseObj) else (GetFaceSelection BaseObj)
)
)
)
-- Get verts/faces using selected texmap-index:
local GetSubObjsFunc = case SubObjName of
(
#Verts:(SelMatInfo.GetVertsUsingTexmap)
#Faces:(SelMatInfo.GetFacesUsingTexmap)
)
-- Selects all faces/verts if 'SelTexNum' is zero:
local NewSelItems = GetSubObjsFunc SelTexNum IgnoreBitmaps:Opts.IgnoreBitmaps Dominant:Opts.Dominant
-- Modify select-array:
if Opts.RemSel then
(
SelItems -= NewSelItems
)
else
(
SelItems += NewSelItems
)
SetCommandPanelTaskMode #Modify
ModPanel.SetCurrentObject BaseObj ui:True
-- Select those verts/faces:
case (classOf BaseObj) of
(
(Editable_Poly):
(
case SubObjName of
(
#Verts:
(
SubObjectLevel = 1
PolyOp.SetVertSelection BaseObj SelItems
)
#Faces:
(
SubObjectLevel = 4
PolyOp.SetFaceSelection BaseObj SelItems
)
)
)
(Editable_Mesh):
(
case SubObjName of
(
#Verts:
(
SubObjectLevel = 1
SetVertSelection BaseObj.Mesh SelItems
)
#Faces:
(
SubObjectLevel = 3
SetFaceSelection BaseObj.Mesh SelItems
)
)
)
)
CompleteRedraw()
SetArrowCursor()
return OK
),
----------------------------------------------------------------------------------
-- ev_SelSubObjsMenuItem_Clicked:
-- Triggers subobject-selection with options passed from control-tag
----------------------------------------------------------------------------------
fn ev_SelSubObjsMenuItem_Clicked Sender Args =
(
local SelOpts = (Sender.Tag.Value)
::gRsTerrainPalette.SelSubObjs SelOpts
),
-- Copies selected texmap's path to clipboard:
fn ev_CopyPathMenuItem_Clicked Sender Args =
(
local TheTool = ::gRsTerrainPalette
local SelMatInfo = (TheTool.GetSelMatInfo())
local SelTexNum = (TheTool.GetSelTexNum())
if (SelMatInfo == undefined) or (SelTexNum < 1) do return False
local ThisPath = SelMatInfo.DiffuseTexPaths[SelTexNum]
SetClipboardText (ThisPath as string)
),
fn ev_ApplyClrMenuItem_Clicked Sender Args =
(
local TheTool = Sender.Tag.Value
TheTool.PaintSelection()
),
-- Select faces used by a specific material:
fn ev_BtnMatSelFaces_Clicked Sender Args =
(
-- Set selected-material value from button's tag:
gRsTerrainPalette.SetSelLookupTex Sender.Tag
local SelOpts = (RsTerrPal_SelSubObjOpts SubObjName:"Faces")
::gRsTerrainPalette.SelSubObjs SelOpts
),
-- Apply selected material to selected faces:
fn ev_BtnApplyMat_Clicked Sender Args =
(
-- Get selected-material value from button's tag:
gRsTerrainPalette.SetSelLookupTex Sender.Tag
local SelMatInfo = Sender.Tag.Value.MatInfo
-- Get object and MatId for selected material:
local Obj = SelMatInfo.Obj
local SelMatId = SelMatInfo.MatId
local ObjOp = RsMeshPolyOp Obj
local ObjSetFaceMatID = RsSetFaceMatIDFunc Obj
-- Change face matids:
for FaceNum in (Obj.SelectedFaces as BitArray) do
(
ObjSetFaceMatID Obj FaceNum SelMatId
)
-- Update mesh in viewport:
case ObjOp of
(
polyOp:(polyOp.collapseDeadStructs Obj)
meshOp:(update Obj)
)
),
-- Open/Close mask-sliders panel:
fn ev_ChkMaskOptions_Clicked Sender Args =
(
local TheTool = Sender.Tag.Value
TheTool.MaskDropdownActive = (not TheTool.MaskDropdownActive)
-- Stop redraws while tweaking layout:
local FormHeight = TheTool.ToolForm.Height
TheTool.ToolForm.Height += 1000
local ScrollPanel = TheTool.ScrollPanel
ScrollPanel.Parent.SuspendLayout()
ScrollPanel.SuspendLayout()
-- Toggle checkbutton's appearance:
TheTool.SetBtnChecked Sender TheTool.MaskDropdownActive
-- Rebuild controls in masks-panel:
TheTool.UpdateMaskingControls()
-- Allow form to redraw:
TheTool.ToolForm.Height = FormHeight
ScrollPanel.ResumeLayout()
ScrollPanel.Parent.ResumeLayout()
),
-----------------------------------------------------------------------------------------
-- GetTexmapRCMenu:
-- Generates a rightclick-menu to be applied to texmap-id buttons:
-----------------------------------------------------------------------------------------
fn GetTexmapRCMenu TypeDef: =
(
if (TypeDef == unsupplied) do
(
TypeDef = GetSelShaderTypeDef()
)
-- Have we already generated a rightclick-menu for this shadertype?
local MenuNum = FindItem TexmapRCMenus.ShaderTypes TypeDef.Type
if (MenuNum != 0) do
(
-- Re-use pre-generated menu:
return TexmapRCMenus.Menus[MenuNum]
)
local NewMenu = (DotNetObject "ContextMenuStrip")
-- Add 'Copy texmap path' menuitem:
(
local CmdItem = DotNetObject "ToolStripMenuItem" "Copy Filename to Clipboard"
NewMenu.Items.Add CmdItem
CmdItem.Tag = (DotNetMxsValue This)
DotNet.SetLifetimeControl CmdItem #Dotnet
DotNet.AddEventHandler CmdItem "Click" ev_CopyPathMenuItem_Clicked
)
NewMenu.Items.Add (DotNetObject "ToolStripSeparator")
-- Add selection-menus to 'NewMenu':
(
-- Does this material use a lookup-bitmap?
local UseLookupMask = (TypeDef.MaskChan != undefined)
for SubObjName in #("Verts", "Faces") do
(
local SelSubObjText = ("Select " + SubObjName + ":")
local TypeMenu = (DotNetObject "ToolStripMenuItem" SelSubObjText)
NewMenu.Items.Add TypeMenu
DotNet.SetLifetimeControl TypeMenu #Dotnet
for DomItem in #(DataPair Text:"Using this material/texmap" Val:False, DataPair Text:"Where material/texmap is Dominant" Val:True) do
(
local DomMenu = (DotNetObject "ToolStripMenuItem" DomItem.Text)
TypeMenu.DropDownItems.Add DomMenu
DotNet.SetLifetimeControl DomMenu #Dotnet
-- Bitmap-Ignore menu is only used if shader actually uses a lookup-bitmap...
local IgBmpItems = #(DataPair Text:"Just Vertex Lookup" Val:True)
if UseLookupMask do
(
append IgBmpItems (DataPair Text:"Include Texture Lookup" Val:False)
)
local PrevMenu = DomMenu
for IgBmpItem in IgBmpItems do
(
-- Add Bitmap-Ignore menu, if valid:
if UseLookupMask do
(
PrevMenu = (DotNetObject "ToolStripMenuItem" IgBmpItem.Text)
DomMenu.DropDownItems.Add PrevMenu
DotNet.SetLifetimeControl PrevMenu #Dotnet
)
-- Add selection-commands:
local SelItems = for SelOptItem in
#(
DataPair Text:("Select " + SubObjName) Val:#Sel,
DataPair Text:"Add to selection" Val:#Add,
DataPair Text:"Remove from selection" Val:#Rem) do
(
-- Create menuitem:
local CmdItem = (DotNetObject "ToolStripMenuItem" SelOptItem.Text)
PrevMenu.DropDownItems.Add CmdItem
DotNet.SetLifetimeControl CmdItem #Dotnet
-- Store options to tag:
local SelOpts = (RsTerrPal_SelSubObjOpts SubObjName:SubObjName IgnoreBitmaps:IgBmpItem.Val Dominant:DomItem.Val)
case SelOptItem.Val of
(
#Add:(SelOpts.AddSel = True)
#Rem:(SelOpts.RemSel = True)
)
CmdItem.Tag = (DotNetMxsValue SelOpts)
DotNet.AddEventHandler CmdItem "Click" ev_SelSubObjsMenuItem_Clicked
)
)
)
)
)
NewMenu.Items.Add (DotNetObject "ToolStripSeparator")
-- Add texmap-swaps submenu:
(
local SubMenu = DotNetObject "ToolStripMenuItem" "Swap Texmap with:"
NewMenu.Items.Add SubMenu
local ClrNames = TypeDef.LookupColourNames
local TexCount = GetTexmapsCount()
-- Options for swap-event function:
struct SwapOptsDef (Text, SwapTexNum, SwapMatSlots = True, SwapLookups = True)
for SwapTexNum = 1 to TexCount do
(
local ClrName = ClrNames[SwapTexNum]
local MenuName = StringStream ""
format "%: (%)" SwapTexNum ClrName To:MenuName
-- Create menuitem:
local SwapItem = DotNetObject "ToolStripMenuItem" (MenuName as String)
SubMenu.DropDownItems.Add SwapItem
DotNet.SetLifetimeControl SwapItem #Dotnet
-- Add submenu-options:
for SwapOpts in
#(
(SwapOptsDef Text:"Swap texmaps/vertex-colours" SwapTexNum:SwapTexNum SwapMatSlots:True SwapLookups:True),
(SwapOptsDef Text:"Just swap texmap-slots" SwapTexNum:SwapTexNum SwapMatSlots:True SwapLookups:False),
(SwapOptsDef Text:"Just swap vertex-colours" SwapTexNum:SwapTexNum SwapMatSlots:False SwapLookups:True)
) do
(
local CmdItem = DotNetObject "ToolStripMenuItem" SwapOpts.Text
SwapItem.DropDownItems.Add CmdItem
CmdItem.Tag = (DotNetMxsValue SwapOpts)
DotNet.AddEventHandler CmdItem "Click" ev_SwapMenuItem_Clicked
DotNet.SetLifetimeControl CmdItem #Dotnet
)
)
)
NewMenu.Items.Add (DotNetObject "ToolStripSeparator")
-- Add 'Apply to Selection' menuitem:
(
local CmdItem = DotNetObject "ToolStripMenuItem" "Apply to Selection"
NewMenu.Items.Add CmdItem
DotNet.SetLifetimeControl NewMenu #Dotnet
CmdItem.Tag = (DotNetMxsValue This)
DotNet.SetLifetimeControl CmdItem #Dotnet
DotNet.AddEventHandler CmdItem "Click" ev_ApplyClrMenuItem_Clicked
)
-- Store menu for later retrieval:
append TexmapRCMenus.ShaderTypes TypeDef.Type
append TexmapRCMenus.Menus NewMenu
return NewMenu
),
-- Adds/updates controls in panel 'MaskCtrlPanel'
fn UpdateMaskingControls =
(
MaskCtrlPanel.Controls.Clear()
MaskCtrlPanel.RowCount = 0
-- Get TypeDef for currently-shown shadertype:
local TypeDef = GetSelShaderTypeDef()
-- Does this shader-type use a texturemap-mask?
local HasMaskChan = (TypeDef.MaskChan != undefined)
if (MaskDropdownActive) do
(
if HasMaskChan do
(
-- Collect items for deciding which mask-controls to show:
local MaskItems = #()
-- Collect mask-slider definitions:
(
struct MaskCtrlDef (CtrlName, Text, DefaultVal, ChanText, RangeText, SubChan)
local LookupMaskDef = (MaskCtrlDef CtrlName:#SldLookupMask SubChan:TypeDef.LookupMaskSubChan Text:"Lookup" DefaultVal:TypeDef.DefLookupMaskVal ChanText:TypeDef.LookupMaskChanText RangeText:TypeDef.LookupMaskRangeText)
append MaskItems LookupMaskDef
-- Add definition for tint-mask controls, if used:
if (TypeDef.TintMaskSubChan != undefined) do
(
append MaskItems (MaskCtrlDef CtrlName:#SldTintMask Text:"Tint" SubChan:TypeDef.TintMaskSubChan DefaultVal:TypeDef.DefTintMaskVal ChanText:TypeDef.TintMaskChanText RangeText:TypeDef.TintMaskRangeText)
)
-- Add definition for displacement-mask controls, if used:
if (TypeDef.DisplaceMaskSubChan != undefined) do
(
append MaskItems (MaskCtrlDef CtrlName:#SldDisplaceMask Text:"Displacement" SubChan:TypeDef.DisplaceMaskSubChan DefaultVal:TypeDef.DefDisplaceMaskVal ChanText:TypeDef.DisplaceMaskChanText RangeText:TypeDef.DisplaceMaskRangeText)
)
)
-- Set number of rows in hideable panel's table:
MaskCtrlPanel.RowCount = (MaskItems.Count + 1)
-- Add mask-opacity sliders:
for MaskDef in MaskItems do
(
-- Table to hold slider/labels:
(
local MaskLblText = (MaskDef.Text + " Mask: [" + MaskDef.ChanText + "]")
local MaskTable = AddGrpBox MaskCtrlPanel Title:MaskLblText PanelType:"TableLayoutPanel"
MaskTable.Parent.Margin = (dotNetObject "Padding" 0)
MaskTable.Padding = (dotNetObject "Padding" 0)
MaskTable.Dock = MaskTable.Dock.Fill
MaskTable.AutoSize = True
MaskTable.ColumnCount = 3
MaskTable.RowCount = 2
MaskTable.ColumnStyles.Add (dotNetObject "ColumnStyle" SizeType_Absolute 115)
MaskTable.ColumnStyles.Add (dotNetObject "ColumnStyle" SizeType_Percent 100)
MaskTable.ColumnStyles.Add (dotNetObject "ColumnStyle" SizeType_Absolute 115)
MaskTable.RowStyles.Add (dotNetObject "RowStyle" SizeType_Absolute 25)
MaskTable.RowStyles.Add (dotNetObject "RowStyle" SizeType_Absolute 25)
-- Which sub-channel (rgb) is this mask on? (greyscale if undefined)
local maskSubChans = if (maskDef.subChan == Undefined) then #{1,2,3} else #{maskDef.subChan}
-- Add 0%/100% buttons:
for Item in #(DataPair Text:("[0% - " + MaskDef.RangeText.Min + "]") ColIdx:0, DataPair Text:("[100% - " + MaskDef.RangeText.Max + "]") ColIdx:2) do
(
local NewBtn = DotNetObject "Button"
NewBtn.Text = Item.Text
NewBtn.Tag = (DotNetMxsValue maskSubChans)
NewBtn.FlatStyle = NewBtn.FlatStyle.System
NewBtn.Width = 110
dnTooltip.SetToolTip NewBtn "Set this mask-channel value for selected subobjects"
MaskTable.Controls.Add NewBtn Item.ColIdx 0
dotNet.addEventHandler NewBtn "MouseUp" SetMaskBtnFunc
dotNet.setLifetimeControl NewBtn #dotnet
)
-- Mask-value slider:
(
local MaskSlider = (dotNetObject "TrackBar")
MaskSlider.Margin = (dotNetObject "Padding" 0)
MaskSlider.Padding = (dotNetObject "Padding" 0)
MaskSlider.Dock = MaskSlider.Dock.Fill
MaskSlider.Height -= 12
MaskSlider.Minimum = 0
MaskSlider.Maximum = 4
MaskSlider.Value = (MaskSlider.Maximum * MaskDef.DefaultVal)
MaskSlider.TickFrequency = 1
MaskTable.Controls.Add MaskSlider 1 0
local ToolText = ("Set proportion of " + MaskDef.Text + " that comes from vertex-colours\n(when texmap-buttons are clicked)\n\nThis masks out material's '" + MaskDef.Text + "' texture.")
dnTooltip.SetToolTip MaskTable ToolText
-- Store slider value to SldLookupMask or SldTintMask:
SetProperty This MaskDef.CtrlName MaskSlider
)
-- Add set-from-slider button:
(
local NewBtn = DotNetObject "Button"
NewBtn.Text = ("^ Apply slider value ^")
NewBtn.Tag = (DotNetMxsValue maskSubChans)
NewBtn.FlatStyle = NewBtn.FlatStyle.System
NewBtn.AutoSize = True
NewBtn.Dock = NewBtn.Dock.Fill
NewBtn.Margin = (dotNetObject "Padding" 0 3 0 6)
dnTooltip.SetToolTip NewBtn "Set slider's mask-channel value for selected subobjects"
MaskTable.Controls.Add NewBtn 1 1
dotNet.addEventHandler NewBtn "MouseUp" SetMaskBtnFunc
dotNet.setLifetimeControl NewBtn #dotnet
)
)
)
-- Add all-subchannels mask-edit button: (centred)
(
local BtnTable = AddGrpBox MaskCtrlPanel PanelType:"TableLayoutPanel"
BtnTable.Parent.Margin = (dotNetObject "Padding" 0)
BtnTable.Padding = (dotNetObject "Padding" 0)
BtnTable.Dock = BtnTable.Dock.Fill
BtnTable.AutoSize = True
BtnTable.ColumnCount = 3
BtnTable.ColumnStyles.Add (dotNetObject "ColumnStyle" SizeType_Absolute 115)
BtnTable.ColumnStyles.Add (dotNetObject "ColumnStyle" SizeType_Percent 100)
BtnTable.ColumnStyles.Add (dotNetObject "ColumnStyle" SizeType_Absolute 115)
BtnTable.RowStyles.Add (dotNetObject "RowStyle" SizeType_Absolute 25)
local NewBtn = DotNetObject "Button"
NewBtn.Text = "^ Apply all slider values ^"
NewBtn.Tag = DotNetMxsValue #{1,2,3}
NewBtn.FlatStyle = NewBtn.FlatStyle.System
NewBtn.Dock = NewBtn.Dock.Fill
NewBtn.Margin = (dotNetObject "Padding" 0 0 0 6)
dnTooltip.SetToolTip NewBtn "Applies mask-slider values to selected subobjects' mask-channel\n(doesn't touch the Lookup channel)"
BtnTable.Controls.Add NewBtn 1 0
dotNet.addEventHandler NewBtn "MouseUp" SetMaskBtnFunc
dotNet.setLifetimeControl NewBtn #dotnet
)
)
)
),
--------------------------------------------------------------
-- Update texmap-button selection:
--------------------------------------------------------------
fn SetSelLookupTex SelTexInfoVal =
(
-- Store material/texmap-index info:
TexmapPanel.Tag = SelTexInfoVal
if (SelTexInfoVal == undefined) do return OK
-- Extract selected-material/texmap info from tag-data:
local SelTexInfo = SelTexInfoVal.Value
local MatInfo = SelTexInfo.MatInfo
local SelNum = SelTexInfo.TexNum
-- These colours are safe to use with this colour-index:
local SafeBlends = undefined
if (SelNum != 0) and (MatInfo != undefined) do
(
SafeBlends = MatInfo.TypeDef.LookupSafeCombos[SelNum]
)
if (SelNum != 0) do
(
local FormBackClr = TexmapPanel.BackColor
local SelClr = FormBackClr.Yellow
-- Update texmap-selectedness colours:
for TexmapsPanel in MatPanels do
(
-- Get matinfo from this panel's tag-value:
local PanelMatInfo = TexmapsPanel.Tag.Value
-- Does this panel's matinfo match the newly-selected one?
local isSelMat = (PanelMatInfo == SelTexInfo.MatInfo)
for n = 1 to TexmapsPanel.Controls.Count do
(
-- Highlight texmaps if they match selected MatInfo/TexNum:
local ThisClr = if (isSelMat) and (n == SelNum) then SelClr else FormBackClr
local HiliteBox = TexmapsPanel.Controls.Item[n - 1]
HiliteBox.BackColor = ThisClr
if (SafeBlends != undefined) do
(
local ClrBtn = HiliteBox.Controls.Item[0].Controls.Item[0]
ClrBtn.Text = if SafeBlends[n] then "Safe" else "Artifact"
)
)
-- Make sure yellow bits aren't left behind:
TexmapsPanel.Refresh()
)
)
return OK
),
------------------------------------------------------------------------------
-- AddMatCmdPanel:
-- Add select/apply buttons for a given MatInfo:
------------------------------------------------------------------------------
fn AddMatCmdPanel AddToPanel ThisMatInfo =
(
local BtnWidth = Thumbs.ThumbSize
local MatCmdPanelHeight = (BtnWidth + 3)
local CmdBtnSize = [90,18]
local MatBtnsPanel = (AddGrpBox AddToPanel PanelType:"TableLayoutPanel")
AddToPanel.ColumnStyles.Add (dotNetObject "ColumnStyle" SizeType_AutoSize)
local MatBtnsOutPanel = MatBtnsPanel.Parent--.Parent
MatBtnsOutPanel.Dock = MatBtnsOutPanel.Dock.None
MatBtnsPanel.Margin = (dotNetObject "Padding" 2 2 2 2)
struct CtrlDef (Text, Tooltip, Func, ifHasMat = False)
for Item in
#(
CtrlDef Text:"Select Faces" Tooltip:"Select faces using this material" Func:ev_BtnMatSelFaces_Clicked,
CtrlDef Text:"Apply Material" Tooltip:"Apply this material to selected faces" Func:ev_BtnApplyMat_Clicked ifHasMat:True
)
do
(
if (not Item.ifHasMat) or (ThisMatInfo.TerrainMat != undefined) do
(
local NewBtn = DotNetObject "Button"
NewBtn.Text = Item.Text
NewBtn.FlatStyle = NewBtn.FlatStyle.System
NewBtn.Width = CmdBtnSize.X
NewBtn.Height = CmdBtnSize.Y
NewBtn.Margin = (dotNetObject "Padding" 4 0 4 6)
-- Tag button with material-info:
NewBtn.Tag = (DotNetMxsValue (DataPair MatInfo:ThisMatInfo TexNum:0))
dnTooltip.SetToolTip NewBtn Item.Tooltip
MatBtnsPanel.Controls.Add NewBtn
dotNet.addEventHandler NewBtn "MouseUp" Item.Func
dotNet.setLifetimeControl NewBtn #dotnet
)
)
return MatBtnsOutPanel
),
------------------------------------------------------------------------------
-- UpdateTexmapCtrls:
-- Set up controls in 'TexmapPanel'
------------------------------------------------------------------------------
fn UpdateTexmapCtrls =
(
local TimeStart = TimeStamp()
SetWaitCursor()
PushPrompt "Redrawing Controls..."
SuspendRedraw()
ScrollPanel.SuspendLayout()
-- Reset groupbox-label:
TexmapPanel.Parent.Text = "Texturemaps:"
-- Clear existing button-panels:
(
for TexPanel in MatPanels do
(
TexPanel.Controls.Clear()
)
MatPanels.Count = 0
)
-- Clear panel:
TexmapPanel.Controls.Clear()
SldLookupMask = undefined
SldTintMask = undefined
SldDisplaceMask = undefined
-- Tag-value is used to store active material/colour-index - clear selection:
TexmapPanel.Tag = undefined
-- Get shadertype:
local TypeDef = GetSelShaderTypeDef()
local HelperText = undefined
-- Add per-material panels:
if (TypeDef != undefined) do
(
-- Get shadertype's material-info list:
local MatInfoList = GetSelShaderMatInfoList()
-- Add shader-name to groupbox-label:
TexmapPanel.Parent.Text += (" [" + TypeDef.Pattern + "]")
-- Does this shader-type use a texturemap-mask?
local HasMaskChan = (TypeDef.MaskChan != undefined)
-- This shadertype's lookup-colours:
local LookupClrs = TypeDef.LookupColours
local BtnWidth = Thumbs.ThumbSize
local ScrollPanelHeight = 270
local ScrollPanelWidth = 10 + (BtnWidth * 4)
-- Generate/get rightclick-menu to apply to texmap-buttons...
local TexMapRCmenu = (GetTexmapRCMenu TypeDef:TypeDef)
-- Add groupbox to surround material-panels:
local MatsOuterPanel = (AddGrpBox TexmapPanel PanelType:"TableLayoutPanel")
-- Collect list of texmap-panels per material:
MatPanels = for ThisMatInfo in MatInfoList collect
(
-- Add groupbox-panel to hold texmap-thumbnails:
local MatPanel = AddGrpBox MatsOuterPanel Title:(ThisMatInfo.GetNameString()) PanelType:"TableLayoutPanel"
MatsOuterPanel.RowStyles.Add (dotNetObject "RowStyle" SizeType_AutoSize)
MatPanel.Tag = (DotNetMxsValue ThisMatInfo)
-- Add columns for texmap-buttons, and material-buttons panel:
local TexCount = ThisMatInfo.TexCount
MatPanel.ColumnCount = (TexCount + 1)
-- Add per-texmap panels - background-colour will be changed if texmap is selected:
for ClrNum = 1 to TexCount do
(
-- Add sub-panel to hold colour's controls:
local TexHilitePanel = DotNetObject "FlowLayoutPanel"
TexHilitePanel.AutoSize = True
TexHilitePanel.Margin = (dotNetObject "Padding" 0 0 2 0)
TexHilitePanel.Padding = (dotNetObject "Padding" 2 2 2 2)
-- Tag panel with material-info and texmap-index:
TexHilitePanel.Tag = DotNetMxsValue (dataPair MatInfo:ThisMatInfo TexNum:ClrNum)
MatPanel.Controls.Add TexHilitePanel
MatPanel.ColumnStyles.Add (dotNetObject "ColumnStyle" SizeType_Absolute (BtnWidth + 12))
local TexPath = ThisMatInfo.DiffuseTexPaths[ClrNum]
-- Get colour from list, and make colour for overlaid text:
local LookupClr = LookupClrs[ClrNum]
-- Add Texture-button:
(
-- Add lookup-colour outline:
local ClrPanel = DotNetObject "FlowLayoutPanel"
TexHilitePanel.Controls.Add ClrPanel
ClrPanel.AutoSize = True
ClrPanel.Margin = (dotNetObject "Padding" 0 0 2 0)
ClrPanel.Padding = (dotNetObject "Padding" 2 2 2 2)
-- Set button-background to lookup-colour:
ClrPanel.BackColor = dnColour.FromArgb LookupClr.r LookupClr.g LookupClr.b
local TexBtn = DotNetObject "Button"
TexBtn.FlatStyle = TexBtn.FlatStyle.Flat
TexBtn.Margin = (dotNetObject "Padding" 0)
TexBtn.Padding = (dotNetObject "Padding" 3 3 3 3)
--TexBtn.ForeColor = TexBtn.ForeColor.Yellow
-- Tag button with material-info and texmap-index:
TexBtn.Tag = TexHilitePanel.Tag
-- Add rightclick-menu:
if (TexMapRCmenu != undefined) do
(
TexBtn.ContextMenuStrip = TexMapRCmenu
)
TexBtn.Width = BtnWidth
TexBtn.Height = TexBtn.Width
TexBtn.BackColor = ClrPanel.BackColor
ClrPanel.Controls.Add TexBtn
dotNet.addEventHandler TexBtn "MouseUp" TexmapBtnFunc -- Click-event
dotNet.addEventHandler TexBtn "Paint" TexmapBtnPaintFunc -- Paint-event triggers thumbnail-loader thread
dotNet.setLifetimeControl TexBtn #DotNet
local TooltipText = "Click to apply lookup-colour"
if (TexPath != undefined) and (TexPath != "") do
(
TooltipText += (":\n" + TexPath)
)
-- Show tooltip on texture-button:
dnTooltip.SetToolTip TexBtn TooltipText
)
-- Collect texmap's highlighter-panel:
TexHilitePanel
)
-- Add select/apply buttons for a given MatInfo:
(
AddMatCmdPanel MatPanel ThisMatInfo
)
-- Collect texmaps-panel:
MatPanel
)
-- Set up materials-list panel for scrolling, now its contents have been added:
(
MatsOuterPanel.AutoScroll = True
MatsOuterPanel.MaximumSize = (DotNetObject "System.Drawing.Size" 0 ScrollPanelHeight)
)
-- Add mask-controls panel, and its toggle-button::
(
-- Set up toggle-button:
local ToggleBtn = (dotNetObject "Button")
ToggleBtn.Text = "Masking Options"
ToggleBtn.AutoSize = True
ToggleBtn.Location.X += 10
-- Tag button with this struct:
ToggleBtn.Tag = (dotNetMxsValue This)
-- Sets button's flatstyle:
SetBtnChecked ToggleBtn MaskDropdownActive
-- Create empty subgroup-box, with button instead of label:
local MaskBoxPanel = AddGrpBox TexmapPanel
MaskBoxPanel.Controls.Add ToggleBtn
dnTooltip.SetToolTip ToggleBtn "Show/hide extra options for lookup/tint masking"
dotNet.addEventHandler ToggleBtn "MouseUp" ev_ChkMaskOptions_Clicked
dotNet.setLifetimeControl ToggleBtn #dotnet
MaskCtrlPanel = dotNetObject "TableLayoutPanel"
MaskCtrlPanel.AutoSize = True
MaskCtrlPanel.Dock = MaskCtrlPanel.Dock.Fill
MaskCtrlPanel.Padding = (dotNetObject "Padding" 3 16 3 3)
MaskBoxPanel.Controls.Add MaskCtrlPanel
UpdateMaskingControls()
)
-- Generate text for help-label:
(
HelperText = StringStream ""
format "Click textures to set Lookup" To:HelperText
if HasMaskChan do
(
format "/Mask" To:HelperText
)
format "-channel colour%.\n" (if HasMaskChan then "s" else "") To:HelperText
format "Rightclick textures for more commands." To:HelperText
HelperText = (HelperText as String)
)
)
-- Add extra-info label:
(
local SelObjs = GetCurrentSelection()
-- Choose appropriate label-text:
local Msg = case of
(
(HelperText != undefined):(HelperText)
(SelObjs.Count == 0):("NO OBJECT SELECTED")
(SelObjs.Count != 1):("Please select only one object")
Default:"Object doesn't use any valid terrain-shaders."
)
local LblExtraInfo = dotNetObject "Label"
TexmapPanel.Controls.Add LblExtraInfo
LblExtraInfo.Margin = (dotNetObject "Padding" 6 6 6 6)
LblExtraInfo.AutoSize = True
LblExtraInfo.Text = Msg
)
-- Turn dialog's redraw back on:
ScrollPanel.ResumeLayout()
ResumeRedraw()
ScrollPanel.Refresh()
PopPrompt()
SetArrowCursor()
--format "Took % seconds to redraw (%)\n" ((TimeStamp() - TimeStart) / 1000.0) (Val as string)
return OK
),
------------------------------------------------------------------------------
-- SelListMat:
-- Select combobox-item for material with matching matid :
------------------------------------------------------------------------------
fn SelListMat MatId =
(
-- Skip if no matid was passed in:
if (MatId == 0) do return False
local SelNum = 0
for n = 1 to TerrainMatIds.Count while (SelNum == 0) do
(
if (findItem TerrainMatIds[n] MatId != 0) do
(
SelNum = n
)
)
-- Skip if no terrain-material had this matid:
if (SelNum == 0) do return False
-- Set combobox to show that list-item, and update texmap buttons:
CboShaderType.SelectedIndex = (SelNum - 1)
UpdateTexmapCtrls()
),
------------------------------------------------------------------------------
-- PopulateMaterialList:
-- Update terrain-materials list:
------------------------------------------------------------------------------
fn PopulateMaterialList =
(
SetWaitCursor()
-- Get the material for the previously-selected item:
-- (we're going to re-select this, if it's still in the list later)
local SelMatInfo = GetSelMatInfo()
local SelTexNum = GetSelTexNum()
local PrevSelMat = undefined
if (SelMatInfo != undefined) do
(
PrevSelMat = SelMatInfo.TerrainMat
)
SelMatInfo = undefined
local NewSelInfo = undefined
-- Get data on terrain-object's compatible terrain-materials:
local AllTerrainMatInfoList = gRsTerrainHelpers.GetObjTerrainFaceData TerrainObj
-- Collect materials by terrainshader-type: (i.e. the name-pattern used to distinguish between them)
TerrainMatInfoList = #()
local ShaderTypes = #()
for MatInfo in AllTerrainMatInfoList do
(
local ShaderType = MatInfo.TypeDef.Pattern
local TypeNum = FindItem ShaderTypes ShaderType
if (TypeNum == 0) do
(
append ShaderTypes ShaderType
append TerrainMatInfoList (dataPair ShaderType:ShaderType MatInfoList:#())
TypeNum = ShaderTypes.Count
)
append TerrainMatInfoList[TypeNum].MatInfoList MatInfo
)
-- Sort shadertype-items by name:
fn TypeSorter v1 v2 = (striCmp v1.ShaderType v2.ShaderType)
qsort TerrainMatInfoList TypeSorter
-- Collect MatId lookup-lists:
TerrainMatIds = for Item in TerrainMatInfoList collect
(
for MatInfo in Item.MatInfoList collect MatInfo.MatId
)
-- Set combobox-items to Material Ids/Names:
CboShaderType.Items.Clear()
if (TerrainMatInfoList.Count != 0) do
(
-- Set first selection-index by default:
local SelIdx = 0
for n = 1 to TerrainMatInfoList.Count do
(
local ShaderTypeItem = TerrainMatInfoList[n]
local ItemText = StringStream ""
format "% (% materials)" ShaderTypeItem.ShaderType ShaderTypeItem.MatInfoList.Count To:ItemText
local ItemIdx = CboShaderType.Items.Add (ItemText as String)
CboShaderType.Items.Item[ItemIdx]
-- We'll want to select this item if it includes the previously-selected texmap's material:
for MatItem in ShaderTypeItem.MatInfoList do
(
if (MatItem.TerrainMat == PrevSelMat) do
(
NewSelInfo = MatItem
SelIdx = (n - 1)
)
)
)
-- Set combobox-selection:
CboShaderType.SelectedIndex = SelIdx
-- Set selection-info on main panel's tag to equivalent of what it was before:
if (NewSelInfo != undefined) do
(
NewSelInfo = DotNetMxsValue (DataPair MatInfo:NewSelInfo TexNum:SelTexNum)
)
TexmapPanel.Tag = NewSelInfo
)
SetArrowCursor()
return OK
),
------------------------------------------------------------------------------
-- UpdateCtrls:
-- Update controls to match current selection:
------------------------------------------------------------------------------
fn UpdateCtrls =
(
local SelObjs = GetCurrentSelection()
-- Set 'TerrainObj' value if selection is valid:
TerrainObj = if (SelObjs.Count == 1) and (isProperty SelObjs[1] #mesh) then SelObjs[1] else undefined
local HasObj = (TerrainObj != undefined)
-- Set enabledness of controls in panels that need a valid object to work:
for ThisPanel in ObjEditPanels do
(
local CtrlList = ThisPanel.Controls
for n = 0 to (CtrlList.Count - 1) do
(
CtrlList.Item[n].Enabled = HasObj
)
)
SetShowChanClicked()
PopulateMaterialList()
-- Enable material-picker if object uses multiple terrain-shaders:
ChkPickMat.Enabled = (HasObj and (TerrainMatInfoList.Count > 1))
-- Update texmap-buttons to match selected terrain-material:
UpdateTexmapCtrls()
return true
),
------------------------------------------------------------------------------
-- TexClick:
-- Called when a texmap-button is left-clicked:
------------------------------------------------------------------------------
fn TexClick =
(
if (isBtnChecked ChkVertPaint) then
(
SetVertPaintColour()
)
else
(
PaintSelection()
)
),
------------------------------------------------------------------------------
-- UI EVENTS:
------------------------------------------------------------------------------
-- 'Vertex Colour Toolkit' button clicked:
fn ev_BtnVertColTools_Clicked Sender Args =
(
filein (::RsConfigGetWildwestDir() + "Script/3dsMax/Maps/Materials/vertexColour_ui.ms")
),
-- 'Terrain Shader Editor' button clicked:
fn ev_BtnTerrShadEdit_Clicked Sender Args =
(
filein (::RsConfigGetWildwestDir() + "Script/3dsMax/Maps/Materials/terrain_ShaderEditor.ms")
),
-- 'MapId Projector' button clicked:
fn ev_BtnMapIdProj_Clicked Sender Args =
(
fileIn (::RsConfigGetWildWestDir() + "script/3dsMax/Maps/Materials/RSTA_mapIDProjector.ms")
),
-- 'Init Terrain Chans' clicked:
fn ev_BtnInitChannels_Clicked Sender Args =
(
undo "Init Terrain Channels" on
(
for Obj in (GetCurrentSelection()) where (isEditPolyMesh Obj) do
(
-- Collapse and convert:
ConvertToPoly Obj
-- Make sure channels are turned on - if not, set to black:
for Chan in #(5, 9) where not (PolyOp.GetMapSupport Obj Chan) do
(
PolyOp.SetFaceColor Obj Chan #all black
)
)
)
),
-- 'Remove Non-Terrain Chans' clicked:
fn ev_BtnDelChannels_Clicked Sender Args =
(
local TerrainChans = #(-2, 0, 1, 2, 5, 9, 13)
local HasNonTerrainMats = False
local SelObjs = for Obj in (GetCurrentSelection()) where (isEditPolyMesh Obj) collect Obj
if (SelObjs.Count == 0) do return False
-- Check for non-terrain materials on object-faces:
for Obj in SelObjs while (not HasNonTerrainMats) do
(
-- Get descriptors for materials used on object:
local ObjMatInfos = gRsMaterials.GetObjMatData Obj FlatList:True
-- Do any of these materials use non-terrain shaders?
for MatInfo in ObjMatInfos while (not HasNonTerrainMats) do
(
HasNonTerrainMats = not (MatchPattern MatInfo.ShaderName Pattern:"*terrain*")
)
)
if HasNonTerrainMats do
(
local Msg = "Selection uses non-terrain materials.\nAre you sure you want to remove non-terrain channels?\n\nThese channels will NOT be removed:\n"
append Msg (TerrainChans as string)
if not (QueryBox Msg Title:"WARNING: Non-terrain materials found") do
(
return False
)
)
SetWaitCursor()
local Msg = ("Removing channels from selection, keeping: " + (TerrainChans as string))
format "%\n" Msg
PushPrompt Msg
undo "Delete Channels" on
(
gRsTerrainPalette.RemoveCallbacks()
ClearSelection()
RsRemoveClrChans (SelObjs) KeepChans:TerrainChans
Select SelObjs
gRsTerrainPalette.AddCallbacks()
)
PopPrompt()
DisplayTempPrompt Msg 1000 -- Leave message up a little longer...
SetArrowCursor()
),
-- 'Deselect % Verts' button clicked:
fn ev_BtnDeselVerts_Clicked Sender Args =
(
if (RsGetSubObjLevelName() != #vertex) do return False
local SelObjs = GetCurrentSelection()
local Obj = SelObjs[1]
if (SelObjs.Count != 1) or (not isEditPolyMesh Obj) do return False
local TheTool = Sender.Tag.Value
local DeselPercent = TheTool.SpnDeselPercent.Value
gRsSelectionTools.RandomlyDeselectVerts Obj DeselPercent
),
fn ev_BtnFixSeamVerts_Clicked Sender Args =
(
Filein (RsConfigGetWildwestDir() + "Script/3dsMax/Maps/Materials/RSTA_TerrainSeamFixer_UI.ms")
),
-- Function used by various face-border-selection commands:
fn SelBorderVerts BordersFunc UndoText:"Select Border Verts" =
(
local SelObjs = GetCurrentSelection()
local Obj = SelObjs[1]
if (SelObjs.Count != 1) or (not isEditPolyMesh Obj) do return False
local DoConvert = False
if (not IsKindOf Obj Editable_Poly) do
(
if (QueryBox "Selected object needs to be an Editable Poly.\n\nConvert/Collapse object to Poly?" Title:"Warning: Non-Editable Poly Selected") then
(
DoConvert = True
)
else
(
return False
)
)
undo UndoText on
(
if DoConvert do
(
ConvertToPoly Obj
)
-- Store current face/edge selection:
local FaceSel = GetFaceSelection Obj
local EdgeSel = GetEdgeSelection Obj
local BorderEdges = (BordersFunc Obj)
-- Set vert-selection to border-verts:
SetCommandPanelTaskMode #Modify
SetSelectionLevel Obj #Vertex
PolyOp.SetEdgeSelection Obj BorderEdges
Obj.EditablePoly.ConvertSelection #Edge #Vertex
-- Revert face/edge-selection:
SetFaceSelection Obj FaceSel
SetEdgeSelection Obj EdgeSel
)
return True
),
-- 'Select MatId Borders' button clicked:
fn ev_BtnSelMatBorders_Clicked Sender Args =
(
local selObjs = GetCurrentSelection()
if (selObjs.count != 1) do return False
local obj = selObjs[1]
local ObjOp = (RsMeshPolyOp obj)
if (ObjOp == Undefined) do return False
-- Collect object's faces per matId:
local faceCount = obj.numFaces
local ObjGetMatID = RsGetFaceMatIDFunc obj
local facesPerMatId = #()
for faceNum = 1 to faceCount do
(
local faceMatId = (ObjGetMatID obj faceNum)
local matIdFaces = facesPerMatId[faceMatId]
if (matIdFaces == Undefined) do
(
matIdFaces = #{}
matIdFaces.count = faceCount
facesPerMatId[faceMatId] = matIdFaces
)
matIdFaces[faceNum] = True
)
-- Collect non-open border-edges for each matId:
local borderVerts = #{}
for faces in facesPerMatId where (faces != Undefined) do
(
borderVerts += (RsGeom_GetFaceBorderVerts obj faces onlyBetween:True)
)
-- Select verts:
undo "Select MatId Border Verts" on
(
local ObjSetVertSelection = if (ObjOp == MeshOp) then SetVertSelection else PolyOp.SetVertSelection
ObjSetVertSelection obj borderVerts
SubobjectLevel = 1
)
),
-- 'Select Borders Between Selected MatIds' button clicked:
fn ev_BtnSelBetweenSelMats_Clicked Sender Args =
(
local selObjs = GetCurrentSelection()
if (selObjs.count != 1) do return False
local obj = selObjs[1]
local ObjOp = (RsMeshPolyOp obj)
if (ObjOp == Undefined) do return False
-- Get MatIds used on object's selected faces:
local matIds = #{}
local ObjGetMatID = (RsGetFaceMatIDFunc obj)
for faceNum in (GetFaceSelection obj) do
(
local matId = (ObjGetMatID obj faceNum)
matIds[matId] = True
)
-- Abort if insufficient matIds are selected:
matIds = (matIds as Array)
if (matIds.count < 2) do
(
local msg = "Please select faces with more than one Material ID.\n\nThis tool finds verts on border between selected mat ids."
Messagebox msg title:"Warning: Needs multiple MatIds selected"
return False
)
-- Collect object's faces per matId:
local faceCount = obj.numFaces
local facesPerMatId = #()
for matId in matIds do
(
local faces = #{}
faces.count = faceCount
facesPerMatId[matId] = faces
)
for faceNum = 1 to faceCount do
(
local faceMatId = (ObjGetMatID obj faceNum)
local faces = facesPerMatId[faceMatId]
if (faces != Undefined) do
(
faces[faceNum] = True
)
)
-- Collect verts shared by adjacent matIds:
local borderVerts = #{}
for idxA = 1 to (matIds.count - 1) do
(
local matIdA = matIds[idxA]
local matFacesA = facesPerMatId[matIdA]
local matVertsA = ObjOp.GetVertsUsingFace obj matFacesA
for idxB = (idxA + 1) to matIds.count do
(
local matIdB = matIds[idxB]
local matFacesB = facesPerMatId[matIdB]
local matVertsB = ObjOp.GetVertsUsingFace obj matFacesB
-- Collect verts shared by these two sets of faces:
borderVerts += (matVertsA * matVertsB)
)
)
-- Select verts:
undo "Select Verts Between Selected MatIds" on
(
local ObjSetVertSelection = if (ObjOp == MeshOp) then SetVertSelection else PolyOp.SetVertSelection
ObjSetVertSelection obj borderVerts
SubobjectLevel = 1
)
return OK
),
-- 'Select DPM Borders' button clicked:
fn ev_BtnSelDpmBorders_Clicked Sender Args =
(
local TheTool = Sender.Tag.Value
-- This function is passed to 'SelBorderVerts'
fn GetDpmBorderEdges Obj =
(
-- Get faces using DPM shaders:
local Faces = gRsMaterials.GetObjFacesUsingShaders Obj #("*dpm*", "*uber*snow*")
-- Select faces using this MatId:
Obj.EditablePoly.SetSelection #Face Faces
-- Convert matid-selection to border-edge selection:
Obj.EditablePoly.ConvertSelectionToBorder #Face #Edge
-- Collect selected vert-numbers:
local BorderEdges = (GetEdgeSelection Obj)
return BorderEdges
)
TheTool.SelBorderVerts GetDpmBorderEdges UndoText:"Select DPM-Shader Border Verts"
),
-- 'Select PXM Borders' button clicked:
fn ev_BtnSelPxmBorders_Clicked Sender Args =
(
local TheTool = Sender.Tag.Value
-- This function is passed to 'SelBorderVerts'
fn GetPxmBorderEdges Obj =
(
-- Get faces using PXM shaders:
local Faces = gRsMaterials.GetObjFacesUsingShaders Obj #("*pxm*")
-- Select faces using this MatId:
Obj.EditablePoly.SetSelection #Face Faces
-- Convert matid-selection to border-edge selection:
Obj.EditablePoly.ConvertSelectionToBorder #Face #Edge
-- Collect selected vert-numbers:
local BorderEdges = (GetEdgeSelection Obj)
return BorderEdges
)
TheTool.SelBorderVerts GetPxmBorderEdges UndoText:"Select PXM-Shader Border Verts"
),
-- Combobox selection changed:
fn ev_CboShaderType_Selected Sender Args =
(
local TheTool = Sender.Tag.Value
-- Change the button images to match the textures
TheTool.UpdateTexmapCtrls()
),
-- 'Refresh' button clicked:
fn ev_Refresh_Clicked Sender Args =
(
local TheTool = ::gRsTerrainPalette
TheTool.UpdateCtrls()
),
-- 'Pick' button clicked:
fn ev_PickMat_Clicked Sender Args =
(
local TheTool = ::gRsTerrainPalette
-- Show button as checked:
TheTool.SetBtnChecked Sender True
-- Picker-tool:
Tool RsMatIdPickerTool
(
local obj, rayMesh
on start do
(
-- Update material/face-lists:
local SelMatInfo = gRsTerrainPalette.GetSelMatInfo UpdateData:True
Obj = gRsTerrainPalette.TerrainObj
if (isProperty Obj #mesh) then
(
replacePrompt "Pick Face"
-- Set up RayMesh for object:
rayMesh = RayMeshGridIntersect()
rayMesh.Initialize 10
rayMesh.addNode Obj
rayMesh.BuildGrid()
)
else
(
#stop
)
)
on mousePoint clickNum do
(
-- Cast ray at object:
local mouseRay = (mapScreenToWorldRay mouse.pos)
local hits = rayMesh.intersectRay mouseRay.pos mouseRay.dir False
local hitIdx = rayMesh.getClosestHit() -- Get index of closest ray-hit:
local hitFace = rayMesh.getHitFace hitIdx
local matId = 0
if (hitFace != 0) do
(
matId = getFaceMatID obj.mesh hitFace
)
-- Tell tool to select the material with this matId:
gRsTerrainPalette.SelListMat matId
)
)
-- Start picker-tool:
StartTool RsMatIdPickerTool
-- Uncheck button once tool stops:
TheTool.SetBtnChecked Sender False
),
-- Texmap-button clicked:
fn ev_TexmapBtn_Clicked Sender Args =
(
-- Set current material/texmap:
gRsTerrainPalette.SetSelLookupTex Sender.Tag
-- Was this a rightclick?
local RightClick = Args.Button.Equals Args.Button.Right
-- Apply texmap to mesh if left-clicking:
if (not rightClick) do
(
gRsTerrainPalette.TexClick()
)
),
-- Texmap-button paint-event:
fn ev_TexmapBtn_Paint Sender Args =
(
-- Request thumbnail for button if this hasn't been set yet:
if (Sender.ImageIndex == -1) do
(
local ButtonTag = Sender.Tag.Value
local TexPath = ButtonTag.MatInfo.GetTexPath ButtonTag.TexNum
-- Queue control for thumbnail-update:
::gRsTerrainPalette.Thumbs.SetThumb Sender TexPath
)
),
-- Set-mask button clicked:
-- (this function is added to controls as value 'SetMaskBtnFunc')
fn ev_SetMaskBtn_Clicked Sender Args =
(
-- Highlight button while it's working...
gRsTerrainPalette.SetBtnChecked Sender True
-- Button is tagged with bitarray denoting rgb-subchannel(s) to edit:
local SubChans = Sender.Tag.Value
-- Get table-column this control comes from:
local ColIdx
for n = 0 to 2 while (ColIdx == undefined) do
(
if (Sender == (Sender.Parent.GetControlFromPosition n 0)) do
(
ColIdx = n
)
)
local MaskColour = case ColIdx of
(
0:(Black)
1:(gRsTerrainPalette.GetMaskColour())
2:(White)
)
-- Paint mask-colour to requested subchannels:
gRsTerrainPalette.PaintSelection MaskSubChans:SubChans MaskColour:MaskColour
-- Unhighlight button:
gRsTerrainPalette.SetBtnChecked Sender False
),
-- 'Show Channel' buttons clicked:
fn ev_ShowChan_Clicked Sender Args =
(
::gRsTerrainPalette.ShowChannel (Sender.Tag)
),
fn ev_ChkVertPaint_Clicked Sender Args =
(
local TheTool = Sender.Tag.Value
-- Set new checked-state:
local NewState = (not TheTool.isBtnChecked Sender)
TheTool.SetChkVertPaintState NewState
-- If vertex painting has been switched on:
if NewState do
(
if (TheTool.TerrainMatInfoList.Count == 0) then
(
messagebox "Object is not setup with a compatible terrain-shader." Title:"Invalid materials"
)
else
(
-- Add/retrieve VertexPaint modifier:
TheTool.SetupVertPaintMod()
)
-- Set fill-strength from spinner:
if (TheTool.vPainttool != undefined) do
(
TheTool.vPaintTool.BrushOpacity = TheTool.SpnFillStrength.Value
)
)
),
-- Change VertexPaint brush-opacity if 'Fill Strength' spinner is changed:
fn ev_SpnFillStrength_Changed Sender Args =
(
local TheTool = Sender.Tag.Value
if (TheTool.vPainttool != undefined) do
(
TheTool.vPainttool.BrushOpacity = Sender.Value
)
),
-----------------------------------------------------------------------------
fn selectBorderVerts chan =
(
local obj = selection[1]
if (obj != undefined) and ((isKindOf obj EditablePolyMesh) or (isKindOf obj Editable_mesh)) then
(
local borderVerts = RsGeometry_GetUVBorders obj chan
if (borderVerts.count > 0) then
(
if(classof obj == Editable_mesh) then
(
setvertselection obj borderVerts
)
else
(
polyop.setvertselection obj borderVerts
)
subobjectlevel = 1
)
)
),
-----------------------------------------------------------------------------
fn ev_BtnSelUV1Verts_Clicked =
(
::gRsTerrainPalette.selectBorderVerts 1
),
-----------------------------------------------------------------------------
fn ev_BtnSelUV2Verts_Clicked =
(
::gRsTerrainPalette.selectBorderVerts 2
),
-- Form closed:
fn ToolClose =
(
-- Remove selection-change callback:
RemoveCallbacks()
-- Deregister tool from thumbnails-system
if (gRSTA_ThumbsMgr != undefined) do
(
gRSTA_ThumbsMgr.DeregisterTool ToolName
)
-- Dispose of struct's dotnetobjects:
for PropName in (getPropNames This) do
(
local ThisVal = (getProperty This PropName)
if (isKindOf ThisVal DotNetObject) and (isProperty ThisVal #Dispose) do
(
ThisVal.Dispose()
)
)
gRsTerrainPalette = undefined
),
fn ev_ToolForm_Close Sender Args =
(
Sender.Tag.Value.ToolClose()
),
------------------------------------------------------------------------------
-- InitForm:
-- Initial form-setup steps
------------------------------------------------------------------------------
fn InitForm =
(
PushPrompt "Initialising Terrain Painter..."
-- Set local aliases for event-functions:
TexmapBtnFunc = ev_TexmapBtn_Clicked
TexmapBtnPaintFunc = ev_TexmapBtn_Paint
SetMaskBtnFunc = ev_SetMaskBtn_Clicked
-- Get dotnet colours for current Max colourscheme:
FormClr = (ColorMan.GetColor #background) * 255
FormClr = (dnColour.FromArgb FormClr[1] FormClr[2] FormClr[3])
WindowClr = (ColorMan.GetColor #window) * 255
WindowClr = (dnColour.FromArgb WindowClr[1] WindowClr[2] WindowClr[3])
TextClr = (ColorMan.GetColor #windowText) * 255;
TextClr = (dnColour.FromArgb TextClr[1] TextClr[2] TextClr[3])
ToolForm.Tag = (DotNetMxsValue This)
ToolForm.Text = "Terrain Painter"
ToolForm.Size = DotNetObject "System.Drawing.Size" FormSize.X FormSize.Y
ToolForm.BackColor = FormClr
ToolForm.MinimumSize = (DotNetObject "System.Drawing.Size" FormSize.X 0)
-- Show the tool-form, with redraw deactivated:
(
ToolForm.ShowModeless()
ToolForm.Refresh()
SuspendRedraw()
)
DotNet.addEventHandler ToolForm "Closing" ev_ToolForm_Close
-- Struct for generating lists of controls:
struct CtrlDef (Name, Text, Tooltip, TagVal, Func, Width, FlowBreak = False)
-- Main layout-table:
(
local MainTable = dotNetObject "TableLayoutPanel"
ToolForm.Controls.Add MainTable
MainTable.Dock = MainTable.Dock.Fill
MainTable.CellBorderStyle = MainTable.CellBorderStyle.None
MainTable.BackColor = FormClr
-- Add banner:
(
-- Set fixed row-height:
MainTable.RowStyles.Add (dotNetObject "RowStyle" SizeType_AutoSize)
RsBannerPanel.Margin = (dotNetObject "Padding" 0)
RsBannerPanel.Dock = RsBannerPanel.Dock.Fill
MainTable.Controls.Add RsBannerPanel
)
-- Add scroll-panel:
ScrollPanel = DotNetObject "TableLayoutPanel"
MainTable.Controls.Add ScrollPanel
ScrollPanel.Dock = ScrollPanel.Dock.Fill
ScrollPanel.CellBorderStyle = ScrollPanel.CellBorderStyle.None
ScrollPanel.Padding = (dotNetObject "Padding" 0 0 (dotNetClass "SystemInformation").VerticalScrollBarWidth 0)
ScrollPanel.AutoScroll = True
-- Add shadertype-selection panel:
(
local GrpBox = AddGrpBox ScrollPanel Title:"Select Terrain Shader Type:"
ScrollPanel.RowStyles.Add (dotNetObject "RowStyle" SizeType_AutoSize)
local ThisPanel = dotNetObject "FlowLayoutPanel"
ThisPanel.Padding = (dotNetObject "Padding" 6 6 6 6)
ThisPanel.Dock = ThisPanel.Dock.Fill
ThisPanel.AutoSize = True
GrpBox.Controls.Add ThisPanel
-- Collect object-reliant panel:
-- (controls here are disabled if terrain-object is not selected)
append ObjEditPanels ThisPanel
-- Add Combobox:
(
CboShaderType = dotNetObject "ComboBox"
CboShaderType.Margin = (dotNetObject "Padding" 1 0 4 4)
CboShaderType.Width = 234
CboShaderType.DropDownWidth = 600
CboShaderType.DropDownStyle = CboShaderType.DropDownStyle.DropDownList
CboShaderType.FlatStyle = CboShaderType.FlatStyle.Flat
CboShaderType.BackColor = WindowClr
CboShaderType.ForeColor = TextClr
CboShaderType.Tag = (dotNetMxsValue This)
dotNet.addEventHandler CboShaderType "SelectionChangeCommitted" ev_CboShaderType_Selected
ThisPanel.Controls.Add CboShaderType
)
-- Add material-buttons:
for Item in
#(
CtrlDef Name:#ChkPickMat Text:"Pick" Tooltip:"Pick material from terrain-object" Func:ev_PickMat_Clicked Width:60,
CtrlDef Name:#BtnRefresh Text:"Refresh" Tooltip:"Refresh the terrain-material list" Func:ev_Refresh_Clicked Width:60
)
do
(
local NewBtn = DotNetObject "Button"
NewBtn.Text = Item.Text
NewBtn.FlatStyle = NewBtn.FlatStyle.System
if (Item.Width == undefined) then
(
NewBtn.AutoSize = True
)
else
(
NewBtn.Width = Item.Width
)
NewBtn.Height = 22
NewBtn.Margin = (dotNetObject "Padding" 0 0 3 0)
-- Tag button with this struct:
NewBtn.Tag = Item.TagVal
-- Store reference to pick-button:
if (Item.Name == #ChkPickMat) then
(
This.ChkPickMat = NewBtn
)
else
(
-- Non-stored buttons should have DotNet lifetime-control:
dotNet.setLifetimeControl NewBtn #dotnet
)
ThisPanel.Controls.Add NewBtn
dnTooltip.SetToolTip NewBtn Item.Tooltip
dotNet.addEventHandler NewBtn "MouseUp" Item.Func
)
)
-- Add texmap-buttons panel: (filled out by 'fn UpdateTexmapCtrls')
(
TexmapPanel = AddGrpBox ScrollPanel Title:"Texturemaps:" PanelType:"TableLayoutPanel"
ScrollPanel.RowStyles.Add (dotNetObject "RowStyle" SizeType_AutoSize)
)
-- Add 'Show Channel' controls:
(
local GrpBox = AddGrpBox ScrollPanel Title:"Show Channel:"
ScrollPanel.RowStyles.Add (dotNetObject "RowStyle" SizeType_AutoSize)
local ThisPanel = dotNetObject "FlowLayoutPanel"
ShowChansPanel = ThisPanel
ThisPanel.Dock = ThisPanel.Dock.Fill
ThisPanel.Padding = (dotNetObject "Padding" 6 6 6 6)
ThisPanel.AutoSize = True
GrpBox.Controls.Add ThisPanel
-- Add show-channel buttons:
for Item in
#(
CtrlDef Text:"Off" Tooltip:"Don't show vertex-colours" TagVal:-3,
CtrlDef Text:"Alpha [-2]" Tooltip:"Show Vertex Alpha channel" TagVal:-2,
CtrlDef Text:"VColour [0]" Tooltip:"Show default Vertex Colours channel" TagVal:0,
CtrlDef Text:"Lookup [9]" Tooltip:"Show Terrain Paint lookup-colour channel" TagVal:9,
CtrlDef Text:"Uber Mask [5]" Tooltip:"Show Uber Terrain Shader lookup/tint mask-channel" TagVal:5
)
do
(
local NewBtn = DotNetObject "Button"
NewBtn.Text = Item.Text
NewBtn.Tag = Item.TagVal
NewBtn.FlatStyle = NewBtn.FlatStyle.System
NewBtn.AutoSize = True
NewBtn.Width = 0
NewBtn.Height = 26
NewBtn.Margin = (dotNetObject "Padding" 0 0 3 0)
ThisPanel.Controls.Add NewBtn
dnTooltip.SetToolTip NewBtn Item.Tooltip
dotNet.addEventHandler NewBtn "MouseUp" ev_ShowChan_Clicked
dotNet.setLifetimeControl NewBtn #dotnet
)
)
-- Add sub-table row:
(
local SubTable = DotNetObject "TableLayoutPanel"
SubTable.Dock = SubTable.Dock.Fill
SubTable.Margin = (dotNetObject "Padding" 0)
SubTable.ColumnCount = 2
SubTable.AutoSize = True
ScrollPanel.RowStyles.Add (dotNetObject "RowStyle" SizeType_AutoSize)
ScrollPanel.Controls.Add SubTable
SubTable.ColumnStyles.Add (dotNetObject "ColumnStyle" SizeType_Percent 50)
SubTable.ColumnStyles.Add (dotNetObject "ColumnStyle" SizeType_Percent 50)
SubTable.RowStyles.Add (dotNetObject "RowStyle" SizeType_AutoSize)
-- Add VertexPaint panel:
(
local ThisPanel = AddGrpBox SubTable Title:"VertexPaint:" PanelType:"FlowLayoutPanel"
-- Collect object-reliant panel:
append ObjEditPanels ThisPanel
-- Add 'Start Vertex Paint' checkbutton:
(
local NewBtn = DotNetObject "Button"
ChkVertPaint = NewBtn
NewBtn.Text = "Start Vertex Paint"
NewBtn.FlatStyle = NewBtn.FlatStyle.System
NewBtn.AutoSize = True
NewBtn.Width = 0
NewBtn.Height = 26
NewBtn.Margin = (dotNetObject "Padding" 6 3 0 6)
-- Tag button with this struct:
NewBtn.Tag = (dotNetMxsValue This)
ThisPanel.Controls.Add NewBtn
dnTooltip.SetToolTip NewBtn "Toggle vertex painting"
dotNet.addEventHandler NewBtn "MouseUp" ev_ChkVertPaint_Clicked
)
-- Add VertexPaint/mask fill-strength spinner:
(
local LblFillStr = dotNetObject "Label"
LblFillStr.Text = "Fill Strength:"
LblFillStr.Margin = (dotNetObject "Padding" 6 8 0 6)
LblFillStr.AutoSize = True
SpnFillStrength = dotNetObject "NumericUpDown"
SpnFillStrength.Tag = (dotNetMxsValue This)
SpnFillStrength.Margin = (dotNetObject "Padding" 2 6 0 6)
SpnFillStrength.Width = 50
SpnFillStrength.BackColor = WindowClr
SpnFillStrength.ForeColor = TextClr
SpnFillStrength.DecimalPlaces = 0
SpnFillStrength.Increment = 1
SpnFillStrength.Minimum = 1
SpnFillStrength.Maximum= 100
SpnFillStrength.Value = 100
SpnFillStrength.ReadOnly = False
ThisPanel.Controls.Add LblFillStr
ThisPanel.Controls.Add SpnFillStrength
dotNet.addEventHandler SpnFillStrength "ValueChanged" ev_SpnFillStrength_Changed
)
)
)
-- Add mesh-selection panel:
(
local GrpBox = AddGrpBox ScrollPanel Title:"Vertex Selection:"
SubTable.RowStyles.Add (dotNetObject "RowStyle" SizeType_AutoSize)
MeshSelectPanel = dotNetObject "FlowLayoutPanel"
MeshSelectPanel.Dock = MeshSelectPanel.Dock.Fill
MeshSelectPanel.Padding = (dotNetObject "Padding" 6 6 6 6)
MeshSelectPanel.AutoSize = True
GrpBox.Controls.Add MeshSelectPanel
-- Add channel-shower buttons:
for Item in
#(
CtrlDef Name:#BtnSelMatBorders Text:"MatId Borders (All)" Tooltip:"Select verts joining faces with different MatIds" Func:ev_BtnSelMatBorders_Clicked,
CtrlDef Name:#BtnSelBetweenSelMats Text:"MatId Borders (Selected)" Tooltip:"Select verts joining faces using MatIds used on selected faces" Func:ev_BtnSelBetweenSelMats_Clicked,
CtrlDef Name:#BtnSelDpmBorders Text:"DPM/Snow Borders" Tooltip:"Select verts joining non/tesselation-shader faces" Func:ev_BtnSelDpmBorders_Clicked,
CtrlDef Name:#BtnSelPxmBorders Text:"PXM Borders" Tooltip:"Select verts joining non-PXM/PXM-shader faces" Func:ev_BtnSelPxmBorders_Clicked FlowBreak:True,
CtrlDef Name:#BtnDeselVerts Text:"Deselect % Verts:" Tooltip:"Deselect a portion of current vertex-selection" Func:ev_BtnDeselVerts_Clicked--,
--CtrlDef Name:#BtnSelUV1Verts Text:"Select UV 1 Border" Tooltip:"Select verts on the UV1 border" Func:ev_BtnSelUV1Verts_Clicked,
--CtrlDef Name:#BtnSelUV2Verts Text:"Select UV 2 Border" Tooltip:"Select verts on the UV2 border" Func:ev_BtnSelUV2Verts_Clicked
)
do
(
local NewBtn = DotNetObject "Button"
NewBtn.Text = Item.Text
NewBtn.FlatStyle = NewBtn.FlatStyle.System
--NewBtn.Width = 60
NewBtn.Height = 23
NewBtn.AutoSize = True
NewBtn.Margin = (dotNetObject "Padding" 0 0 4 0)
-- Tag button with this struct:
NewBtn.Tag = (dotNetMxsValue This)
dotNet.addEventHandler NewBtn "MouseUp" Item.Func
MeshSelectPanel.Controls.Add NewBtn
dnTooltip.SetToolTip NewBtn Item.Tooltip
-- Set layout-flow break, or not:
ThisPanel.SetFlowBreak NewBtn Item.FlowBreak
dotNet.setLifetimeControl NewBtn #dotnet
-- Add percentage-spinner after 'Deselect Verts' button:
if (Item.Name == #BtnDeselVerts) do
(
SpnDeselPercent = dotNetObject "NumericUpDown"
SpnDeselPercent.Margin = (dotNetObject "Padding" 1 1 0 0)
SpnDeselPercent.Width = 50
SpnDeselPercent.BackColor = WindowClr
SpnDeselPercent.ForeColor = TextClr
SpnDeselPercent.DecimalPlaces = 0
SpnDeselPercent.Increment = 1
SpnDeselPercent.Minimum = 1
SpnDeselPercent.Maximum= 100
SpnDeselPercent.Value = 50
SpnDeselPercent.ReadOnly = False
MeshSelectPanel.Controls.Add SpnDeselPercent
)
)
)
-- Add Tools panel:
(
local GrpBox = AddGrpBox ScrollPanel Title:"More Tools:"
ScrollPanel.RowStyles.Add (dotNetObject "RowStyle" SizeType_AutoSize)
local ThisPanel = dotNetObject "FlowLayoutPanel"
ThisPanel.Dock = ThisPanel.Dock.Fill
ThisPanel.Padding = (dotNetObject "Padding" 6 6 6 6)
ThisPanel.AutoSize = True
GrpBox.Controls.Add ThisPanel
-- Give last box a bottom-margin
GrpBox.Parent.Parent.Margin = (dotNetObject "Padding" 4 4 4 4)
-- Add extra tool-buttons:
for Item in
#(
CtrlDef Name:#BtnVertColTools Text:"Vertex Colour Toolkit" Func:ev_BtnVertColTools_Clicked \
Tooltip:"Open Vertex Colour Toolkit",
CtrlDef Name:#BtnTerrShadEdit Text:"Terrain Shader Editor" Func:ev_BtnTerrShadEdit_Clicked \
Tooltip:"Terrain Shader Editor\nSimplifies editing of shaders' per-texmap values.",
CtrlDef Name:#BtnMapIdProj Text:"MapId Projector" Func:ev_BtnMapIdProj_Clicked FlowBreak:True \
Tooltip:"Open 'MapID Projector/Render' toolkit",
CtrlDef Name:#BtnInitChannels Text:"Init Terrain Chans" Func:ev_BtnInitChannels_Clicked \
Tooltip:"Activate terrain-related vertex-colour channels for selected geometry,\nif they're not already active.\n\n(Channels 5, 9)" ,
CtrlDef Name:#BtnDelChannels Text:"Remove Non-Terrain Chans" Func:ev_BtnDelChannels_Clicked \
Tooltip:"Deactivate non-terrain-related vertex-colour channels for selected geometry.\nAsks user for permission if object uses non-terrain materials.\n\nKeeps channels -2, 0, 1, 2, 5, 9, 13\n\n(This command can't be undone)",
CtrlDef name:#BtnFixSeamVerts Text:"Find/Fix Seams" func:ev_BtnFixSeamVerts_Clicked \
tooltip:("Find verts between faces with non-blended texmaps, and auto-fix where possible")
)
do
(
local NewBtn = DotNetObject "Button"
NewBtn.Text = Item.Text
NewBtn.FlatStyle = NewBtn.FlatStyle.System
NewBtn.AutoSize = True
NewBtn.Height = 30
NewBtn.Margin = (dotNetObject "Padding" 0 0 3 3)
-- Add tooltip:
dnTooltip.SetToolTip NewBtn Item.Tooltip
dotNet.addEventHandler NewBtn "MouseUp" Item.Func
-- Set layout-flow break, or not:
ThisPanel.SetFlowBreak NewBtn Item.FlowBreak
ThisPanel.Controls.Add NewBtn
dotNet.setLifetimeControl NewBtn #dotnet
)
)
)
-- Set up banner:
BannerStruct.Setup()
-- Update the tool-form:
(
ResumeRedraw()
ToolForm.Refresh()
)
PopPrompt()
),
------------------------------------------------------------------------------
-- Initialise Terrain Palette tool:
------------------------------------------------------------------------------
fn Create =
(
PushPrompt "Initialising Terrain Painter"
-- Initial form-setup:
InitForm()
-- Update controls for current selection:
UpdateCtrls()
-- Set up selection-change callback:
AddCallbacks()
PopPrompt()
)
)
-- Start tool:
gRsTerrainPalette = RsTerrainPalette()
gRsTerrainPalette.Create()
--- TEST:
--gRsTerrainPalette.GetTexmapVerts()
--gRsTerrainPalette.DeconstructColour (128*[1,1,1]/255)