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

1087 lines
36 KiB
Plaintext
Executable File

-- RS_NormalTweaker.ms
-- 2012 Andy Davis
-- Rockstar London
-- Script provides UI to allow access to control over vertex normals
filein (RsConfigGetWildWestDir() + "script/3dsMax/_config_files/Wildwest_header.ms") --wildwest header
filein (RsConfigGetWildWestDir() + "script/3dsMax/_common_functions/RSL_dotNetUIOps.ms") --RS_dotNetPreset structure
global NormalTweaker
struct NormalTweakerStruct
(
--controls
Form,
Table,
ToolTip,
InfoPanel,
ButtonSet = #(),
ButtonTable,
IniFilePath = (RsConfigGetWildWestDir() + "script/3dsMax/_config_files/RSL_Tools.ini"),
SliderLabel,
SliderBar,
BlankLabel,
SinglePanel,
MultiPanel,
FlowPanel,
ContentPanel,
IDCheckBox,
PreserveCheckBox,
ProgBar,
ProgressValue = 0.0,
MiniMenu,
FocusVector = [0,0,0],
--data
objList,
faceList,
objectList,
--presets
mainColor = color 100 108 132,
------------------------------------------------------------------------------------------------------------------------------------------
--EVENT HANDLERS
------------------------------------------------------------------------------------------------------------------------------------------
fn ToggleAffectAll s e =
(
count = s.Parent.Controls.Count - 1 -- minus 1 because the last control item is a blank label spacer
s.Parent.Controls.Item[count].Enabled = not s.Parent.Controls.Item[count].Enabled
),
fn GetProcessData materialTab =
(
if (materialTab.Controls.Item[0].Checked) then
(
--objList stored in the objectLabel tag
local objs = materialTab.Controls.Item[1].Tag.Value
for this in objs do
(
addModifier this (Edit_Normals())
append NormalTweaker.objList this
append NormalTweaker.faceList (NormalTweaker.IntegerToBitArray (this.Faces.Count))
)
)
),
fn PickFocusObject obj =
(
classOf obj == Dummy or classOf obj == Point
),
fn PickStealObject obj =
(
local valid = true
--ensure that the steal object has verts...
if not (classOf obj == Editable_mesh or classOf obj == Editable_poly or classOf obj == PolyMeshObject) then
valid = false
--we can't select an object in selection to steal normals from...
for this in selection do
(
if (obj == this) then
valid = false
)
return valid
),
fn TweakNormals s e =
(
local QueryScript = (RsConfigGetWildWestDir() + "script/3dsMax/Maps/RSL_NormalTweaker_CB.ms")
local tweakValue = NormalTweaker.SliderBar.Value / 100.0
local origSelection = selection as array
local mode = s.Tag
--find out which faces are to be processed
NormalTweaker.objList = #() --objects to be processed
NormalTweaker.faceList =#() --bitarray of faces for each object
--processing involves:
--1) applying an edit normal modifier to objects that will get affected only
--2) getting data for the list of objects
--3) getting data for the respective faces on these objects
--4) sending the data to functions to perform the appropriate operation
--iterate through the materials
local numMaterials = NormalTweaker.ContentPanel.Controls.Count - 1
for i = 1 to numMaterials do
(
local thisMatTab = NormalTweaker.ContentPanel.Controls.Item[i - 1]
local mat = thisMatTab.Tag.Value
--process the undefined materials
if (mat == undefined) then
(
NormalTweaker.GetProcessData thisMatTab
)
else
(
--process the single materials
if (classOf mat != Multimaterial) then
(
NormalTweaker.GetProcessData thisMatTab
)
--process the multimaterials
else
(
local objs = thisMatTab.Controls.Item[1].Tag.Value
if (thisMatTab.Controls.Item[2].Checked) then
(
for this in objs do
(
addModifier this (Edit_Normals())
append NormalTweaker.objList this
append NormalTweaker.faceList (NormalTweaker.IntegerToBitArray (this.Faces.Count))
)
)
else --individual material faces are to be tweaked
(
local subMatList = #() --get a list of the checked submaterials
for j = 1 to (thisMatTab.Controls.Item[3].Controls.Count) do
(
if (thisMatTab.Controls.Item[3].Controls.Item[j - 1].Checked) then
append subMatList thisMatTab.Controls.Item[3].Controls.Item[j - 1].Tag.Value
)
--find the corresponding faces on the objects and note them as bitarrays
if (subMatList.Count > 0) then
(
for thisObj in objs do
(
local matFaces = #{}
addModifier thisObj (Edit_Normals())
for k = 1 to thisObj.Faces.Count do
(
local thisMatID = polyop.GetFaceMatID thisObj k
if ((findItem subMatList thisMatID) != 0) then
(
append matFaces k
)
)
if (matFaces.Count != 0) then
(
append NormalTweaker.objList thisObj
append NormalTweaker.faceList matFaces
)
)
)
)
)
)
)
if (NormalTweaker.objList.Count > 0) then
(
--process objects
NormalTweaker.ProgressValue = 0.0
NormalTweaker.ProgBar.Value = NormalTweaker.ProgressValue
callbacks.removeScripts #selectionSetChanged id:#NormalTweakerCallbacks
if (mode == "focus") then
(
NormalTweaker.InfoPanel.Text = "Select a dummy or pointer object."
local pick = pickObject prompt:"Select a dummy or pointer object." filter:NormalTweaker.PickFocusObject
if pick == undefined then
(
NormalTweaker.InfoPanel.Text = "No helper selected"
return false
)
else
(
NormalTweaker.FocusVector = pick.Position
NormalTweaker.InfoPanel.Text = (pick.Name + " selected as focus object")
print (pick.Name + " selected as focus object")
)
)
if (mode == "steal") then
(
NormalTweaker.InfoPanel.Text = "Select geometry to steal the normals from."
local pick = pickObject prompt:"Select geometry to steal the normals from." filter:NormalTweaker.PickStealObject
if pick == undefined then
(
NormalTweaker.InfoPanel.Text = "No object selected."
return false
)
else
(
NormalTweaker.InfoPanel.text = (pick.Name + " selected as source object")
print (pick.Name + " selected as source object")
for i = 1 to NormalTweaker.objList.Count do
(
NormalTweaker.StealNormals pick NormalTweaker.objList[i] NormalTweaker.faceList[i]
)
)
)
-- disableSceneRedraw()
if (mode == "reset") then
(
NormalTweaker.InfoPanel.Text = "Normals reset on selection."
for i = 1 to NormalTweaker.objList.Count do
(
NormalTweaker.ResetNormals NormalTweaker.objList[i] NormalTweaker.faceList[i]
NormalTweaker.ProgressValue += (100 / NormalTweaker.objList.Count)
NormalTweaker.ProgBar.Value = NormalTweaker.ProgressValue
)
)
if (mode =="up" or mode == "explode" or mode == "focus") then
(
NormalTweaker.InfoPanel.Text = ("Normals set to " + s.Tag + " on selection by " + NormalTweaker.SliderBar.Value as string + "%.")
for i = 1 to NormalTweaker.objList.Count do
NormalTweaker.SetNormalsOnObject NormalTweaker.objList[i] NormalTweaker.faceList[i] tweakValue s.Tag
)
NormalTweaker.ProgressValue = 0.0
NormalTweaker.ProgBar.Value = NormalTweaker.ProgressValue
subObjectLevel = 0
select origSelection
-- enableSceneRedraw()
callbacks.addScript #selectionSetChanged fileName:QueryScript id:#NormalTweakerCallbacks
)
else
NormalTweaker.InfoPanel.Text = "Please select faces from the list above."
),
fn SelectListedObjects s e =
(
print "asdfkasdfoasdf"
ClearSelection()
select NormalTweaker.objectList
NormalTweaker.MiniMenu.Hide()
),
fn SelectAllObjects s e =
(
print "SelectAllObjects"
NormalTweaker.MiniMenu.Hide()
),
fn Cancel =
(
NormalTweaker.MiniMenu.Hide()
),
fn SetObjectList s e =
(
NormalTweaker.objectList = s.Tag.Value
NormalTweaker.MiniMenu.Hide()
print NormalTweaker.objectList
),
------------------------------------------------------------------------------------------------------------------------------------------
--GENERAL FUNCTIONS
------------------------------------------------------------------------------------------------------------------------------------------
fn IntegerToBitArray num =
(
ba = #{}
for i = 1 to num do
append ba i
return ba
),
fn InitContentPanel =
(
NormalTweaker.ContentPanel = dotNetObject "TableLayoutPanel"
NormalTweaker.ContentPanel.Dock = RS_dotNetPreset.DS.Fill
NormalTweaker.ContentPanel.ColumnCount = 1
NormalTweaker.ContentPanel.BackColor = ARGB 48 48 48
),
fn ShowMiniMenu s e =
(
if (e.Button == e.Button.Right) then
(
local location = [(e.x + NormalTweaker.Form.Location.x), (e.y + NormalTweaker.Form.Location.y + 70)]
NormalTweaker.MiniMenu.Location = dotNetObject "system.drawing.point" location[1] location[2]
NormalTweaker.MiniMenu.ShowModal()
)
else
print "not right button"
),
fn InitUndefinedMatTable objList =
(
local NewCheckBox
local NewTable = dotNetObject "TableLayoutPanel"
NewTable.Dock = RS_dotNetPreset.DS.Fill
NewTable.RowCount = 2
NewTable.ColumnCount = 1
NewTable.RowStyles.add (RS_dotNetObject.rowStyleObject "absolute" 25)
NewTable.RowStyles.add (RS_dotNetObject.rowStyleObject "absolute" 25)
NewTable.BackColor = RS_dotNetPreset.ARGB 128 0 0
NewTable.Tag = dotNetMXSValue undefined
local infoString = "Objects: " + objList[1].Name
if (objList.Count > 1) then
(
for i = 2 to objList.Count do
infoString += ", " + objList[i].Name
)
NewCheckBox = RS_dotNetUI.InitCheckBox "No Material"
NewTable.Controls.Add NewCheckBox 0 0
local NewLabel = RS_dotNetUI.InitLabel infoString RS_dotNetPreset.TA.MiddleLeft
NewLabel.Tag = dotNetMXSValue objList
-- dotNet.AddEventHandler NewLabel "Click" SetObjectList
-- dotNet.AddEventHandler NewLabel "MouseClick" ShowMiniMenu
NewTable.Controls.Add NewLabel 0 1
return NewTable
),
fn InitSingleMatTable mat objList =
(
local NewTable = dotNetObject "TableLayoutPanel"
NewTable.Dock = RS_dotNetPreset.DS.Fill
NewTable.RowCount = 2
NewTable.ColumnCount = 1
NewTable.RowStyles.add (RS_dotNetObject.rowStyleObject "absolute" 25)
NewTable.RowStyles.add (RS_dotNetObject.rowStyleObject "absolute" 25)
NewTable.BackColor = RS_dotNetPreset.ARGB 0 32 128
NewTable.Tag = dotNetMXSValue mat
local infoString = "Objects: " + objList[1].Name
if (objList.Count > 1) then
(
for i = 2 to objList.Count do
infoString += ", " + objList[i].Name
)
local NewLabel = RS_dotNetUI.InitLabel infoString RS_dotNetPreset.TA.MiddleLeft
NewLabel.Tag = dotNetMXSValue objList
local NewCheckBox = RS_dotNetUI.InitCheckBox (classOf mat as string + ": " + mat.Name)
NewTable.Controls.Add NewCheckBox 0 0
NewTable.Controls.Add NewLabel 0 1
return NewTable
),
fn InitMultiMatTable mat objList =
(
local NewTable = dotNetObject "TableLayoutPanel"
local matIDs = #()
--get a list of material ID's and their materials from the objList
for obj in objList do
(
if (classOf obj != Editable_Poly) then
addModifier obj (Edit_Poly())
for i = 1 to obj.faces.count do
AppendIfUnique matIDs (polyop.GetFaceMatID obj i)
)
sort matIDs
--build the table
NewTable.Dock = RS_dotNetPreset.DS.Fill
NewTable.RowCount = 4
NewTable.ColumnCount = 1
NewTable.RowStyles.add (RS_dotNetObject.rowStyleObject "absolute" 25)
NewTable.RowStyles.add (RS_dotNetObject.rowStyleObject "absolute" 25)
NewTable.RowStyles.add (RS_dotNetObject.rowStyleObject "absolute" 25)
NewTable.RowStyles.add (RS_dotNetObject.rowStyleObject "absolute" 25)
NewTable.BackColor = RS_dotNetPreset.ARGB 0 128 32
NewTable.Tag = dotNetMXSValue mat
NewLabel = RS_dotNetUI.InitLabel ("Multimaterial: " + mat.name) RS_dotNetPreset.TA.MiddleLeft
NewTable.Controls.Add NewLabel 0 0
local infoString = "Objects: " + objList[1].Name
if (objList.Count > 1) then
(
for i = 2 to objList.Count do
infoString += ", " + objList[i].Name
)
local NewLabel = RS_dotNetUI.InitLabel infoString RS_dotNetPreset.TA.MiddleLeft
NewLabel.Tag = dotNetMXSValue objList
NewTable.Controls.Add NewLabel 0 1
local NewCheckBox = RS_dotNetUI.InitCheckBox "affect all material id's"
NewCheckBox.Checked = false
NewTable.Controls.Add NewCheckBox 0 2
dotNet.AddEventHandler NewCheckBox "CheckedChanged" ToggleAffectAll
local SubMatTable = dotNetObject "TableLayoutPanel"
SubMatTable.Dock = RS_dotNetPreset.DS.Fill
SubMatTable.Tag = dotNetMXSValue matIDs
SubMatTable.RowCount = matIDs.Count
SubMatTable.BackColor = RS_dotNetPreset.ARGB 0 108 12
for i = 1 to matIDs.Count do
(
local matName
local matNumber = findItem mat.MaterialIDList matIDs[i]
if matNumber == 0 then
matName = "(no material)"
else
matName = (classOf mat.MaterialList[i] as string + ": " + mat.MaterialList[i].Name)
SubMatTable.RowStyles.add (RS_dotNetObject.rowStyleObject "absolute" 25)
newCheckBox = RS_dotNetUI.InitCheckBox ("[" + matIDs[i] as string + "] " + matName)
newCheckBox.Tag = dotNetMXSValue matIDs[i]
SubMatTable.Controls.Add newCheckBox 0 (i - 1)
)
NewTable.Controls.Add SubMatTable 0 3
return NewTable
),
fn SplitCasing instring capstart:true =
(
local regexObject = dotNetObject (regExType = (dotNetClass "System.Text.RegularExpressions.Regex")) (@"(?<!^)(?=[A-Z])")
local stringArray = regexObject.split instring
local returnString = stringArray[1]
if (capstart == true) then
returnString[1] = toUpper returnString[1]
if stringArray.count > 1 then
(
for i = 2 to stringArray.count do
(
returnString = returnString + " " + toLower (stringArray[i])
)
)
return returnString
),
fn UpdateSliderValue s e =
(
NormalTweaker.SliderLabel.Text = ("Tweak amount: " + s.Value as string + "%")
),
fn Refresh =
(
--garbage collection
dgc = dotnetclass "system.gc"
dgc.collect()
gc()
meshObjects = for this in selection where ((superClassOf this == GeometryClass) and (classOf this != XRefObject)) collect this
if (meshObjects.Count == 0) then
(
if (NormalTweaker.Table.Tag == "content") then
(
NormalTweaker.Table.Controls.Remove NormalTweaker.ContentPanel
NormalTweaker.Table.Controls.Add NormalTweaker.BlankLabel 0 1
NormalTweaker.InfoPanel.Text = "Selection: no suitable mesh object selected"
for thisButton in NormalTweaker.ButtonSet do
thisButton.Enabled = false
NormalTweaker.Table.Tag = "blank"
)
)
else
(
local materialSet = #()
local objectSet = #()
local undefinedSet = #()
local color1 = NormalTweaker.mainColor
local color2 = color (NormalTweaker.mainColor.r + 8) (NormalTweaker.mainColor.g + 8) (NormalTweaker.mainColor.b + 8)
--get material data
for this in meshObjects do
(
if this.material == undefined then
append undefinedSet this
else
(
local matItem = findItem materialSet this.material
if (matItem == 0) then
(
append materialSet this.material
append objectSet #(this)
)
else
(
append objectSet[matItem] this
)
)
)
--build material table
NormalTweaker.ContentPanel.Controls.Clear()
NormalTweaker.ContentPanel.RowStyles.Clear()
NormalTweaker.ContentPanel.RowCount = materialSet.Count
if (undefinedSet.Count > 0) then
(
NormalTweaker.ContentPanel.RowStyles.add (RS_dotNetObject.rowStyleObject "absolute" 60)
local matTable = NormalTweaker.InitUndefinedMatTable undefinedSet
NormalTweaker.ContentPanel.Controls.Add matTable 0 0
)
if (materialSet.Count > 0) then
(
for i = 1 to materialSet.Count do
(
local matTable
if (classOf materialSet[i] == MultiMaterial) then
(
matTable = NormalTweaker.InitMultiMatTable materialSet[i] objectSet[i]
NormalTweaker.ContentPanel.Controls.Add matTable 0 NormalTweaker.ContentPanel.Controls.Count
local numControls = NormalTweaker.ContentPanel.Controls.Count
local currentMat = NormalTweaker.ContentPanel.Controls.Item[numControls - 1]
local numSubMats = currentMat.Controls.Item[3].Controls.Count
local blockHeight = 85 + 25 * numSubMats
NormalTweaker.ContentPanel.RowStyles.add (RS_dotNetObject.rowStyleObject "absolute" blockHeight)
)
else -- must be a single material
(
NormalTweaker.ContentPanel.RowStyles.add (RS_dotNetObject.rowStyleObject "absolute" 60)
local matTable = InitSingleMatTable materialSet[i] objectSet[i]
NormalTweaker.ContentPanel.Controls.Add matTable 0 NormalTweaker.ContentPanel.Controls.Count
)
)
)
--place spacer panel on table
--annoyingly necessary or the bottom element on the table expands to fill the space
NormalTweaker.ContentPanel.RowStyles.Add (RS_dotNetObject.rowStyleObject "percent" 100)
spacerPanel = RS_dotNetUI.InitLabel "" RS_dotNetPreset.TA.MiddleCenter
NormalTweaker.ContentPanel.Controls.Add spacerPanel 0 NormalTweaker.ContentPanel.Controls.Count
if (NormalTweaker.Table.Tag == "blank") then
(
NormalTweaker.Table.Controls.Remove NormalTweaker.BlankLabel
NormalTweaker.Table.Controls.Add NormalTweaker.ContentPanel 0 1
for thisButton in NormalTweaker.ButtonSet do
thisButton.Enabled = true
NormalTweaker.Table.Tag = "content"
)
local matTypes = NormalTweaker.ContentPanel.Controls.Count - 1
if (matTypes == 1) then
NormalTweaker.InfoPanel.Text = "1 material detected"
else
NormalTweaker.InfoPanel.Text = (matTypes as string + " materials detected\nPlease select the materials that you want to affect.")
)
),
fn GetNormalsFromFaces obj facelist =
(
local normalList = #{}
max modify mode
select obj
for thisFace in faceList do
(
local faceDegree = obj.Edit_Normals.GetFaceDegree thisFace
for thisCorner in 1 to faceDegree do
(
appendIfUnique normalList (obj.Edit_Normals.GetNormalID thisFace thisCorner)
)
)
return normalList
),
fn ResetNormals obj faceList preserveStack:false =
(
local normalSet = #{}
max modify mode
select obj
--calculate normalSet based on faceList
normalSet = NormalTweaker.GetNormalsFromFaces obj faceList
obj.Edit_Normals.Select normalSet
obj.Edit_Normals.Reset()
if (not NormalTweaker.PreserveCheckBox.Checked and preserveStack == false) then
convertToPoly obj
),
fn SetNormalsOnObject obj faceList amount mode =
(
local upVector = [0,0,1]
max modify mode
select obj
for thisFace in faceList do
(
local faceDegree = obj.Edit_Normals.GetFaceDegree thisFace
for thisCorner in 1 to faceDegree do
(
local vertexID = obj.Edit_Normals.getVertexID thisFace thisCorner
local normalID = obj.Edit_Normals.getNormalID thisFace thisCorner
local vertexPosition = obj.Edit_Normals.GetVertex vertexID
local currentNormalVector = obj.Edit_Normals.getNormal normalID
local tweakVector
case mode of
(
"up":
(
tweakVector = upVector
break
)
"explode":
(
tweakVector = normalize (vertexPosition + obj.position - obj.center)
break
)
"focus":
(
tweakVector = normalize (vertexPosition + obj.position - NormalTweaker.FocusVector)
break
)
)
local outputVector = normalize ((amount * (tweakVector - currentNormalVector)) + currentNormalVector)
obj.Edit_Normals.SetNormal normalID outputVector
--we need to set the normal to explicit so that the normal tweak is preserved on collapse
obj.Edit_Normals.SetNormalExplicit normalID
)
NormalTweaker.ProgressValue += (100.0 / NormalTweaker.objList.Count) / faceList.Count
NormalTweaker.ProgBar.Value = NormalTweaker.ProgressValue
)
--collapse the stack if required
if (not NormalTweaker.PreserveCheckBox.Checked) then
convertToPoly obj
),
fn StealNormals source obj faceList =
-- this script needs a different approach because the reference normal vector changes for each point
(
local sourceFaces = (NormalTweaker.IntegerToBitArray (source.Faces.Count))
local objFaces = (NormalTweaker.IntegerToBitArray (obj.Faces.Count))
local normalVectorList = #() --list of normals vectors for each vertex on the source object
local normalPositionList = #()
local normalBuffer = #{}
local sourceVertMax = 200
local amount = NormalTweaker.SliderBar.Value / 100.0
if (source.verts.count > sourceVertMax) then
(
if not (queryBox ("Source object (" + source.Name + ") contains more than " + sourceVertMax as string + " vertices.\nDo you wish to continue?") title:"RSL Normal Tweaker - Steal Normals") then
(
NormalTweaker.InfoPanel.Text = "Operation aborted."
return false
)
)
--reset normals on source object and get a list of the normals and their locations
select source
addModifier source (Edit_Normals())
NormalTweaker.ResetNormals source sourceFaces preserveStack:true
max modify mode
for i = 1 to source.Verts.Count do
(
--find the normal vector for each vertex
source.Edit_Normals.ConvertVertexSelection #{i} normalBuffer
append normalVectorList (source.Edit_Normals.GetNormal (normalBuffer as array)[1])
append normalPositionList source.Verts[i].position
)
deleteModifier source source.Edit_Normals
--reset normals on target object
select obj
NormalTweaker.ResetNormals obj objFaces preserveStack:true
NormalTweaker.ProgressValue = 0.0
NormalTweaker.ProgBar.Value = NormalTweaker.ProgressValue
faceList = faceList as array
--need to do this due to 3ds Max bug concerning accessing normal information when normals are set to explicit
--this bodge involves creating a new edit_normals modifier and deleting the previous one
deleteModifier obj obj.Edit_Normals
addModifier obj (Edit_Normals())
obj.Edit_Normals.Name = "Stolen Normals"
for thisFace in faceList do
(
local faceDegree = obj.Edit_Normals.GetFaceDegree thisFace
for thisCorner in 1 to faceDegree do
(
local vertexID = obj.Edit_Normals.getVertexID thisFace thisCorner
local normalID = obj.Edit_Normals.getNormalID thisFace thisCorner
local currentNormalVector = obj.Edit_Normals.getNormal normalID
local distanceArray = #() --array of distance between the target vertex and each vertex in the source object
local finalVector = [0,0,0]
for j = 1 to normalPositionList.Count do
(
append distanceArray (distance obj.Verts[vertexID].position normalPositionList[j])
)
-- local influenceArray = NormalTweaker.ProcessDistanceArray distanceArray "linear"
local influenceArray = NormalTweaker.ProcessDistanceArray distanceArray "exponential"
for j = 1 to normalVectorList.Count do
(
finalVector += (normalVectorList[j] * influenceArray[j])
)
finalVector = normalize finalVector
--get and set current normal
local tweakVector = normalize ((amount * (finalVector - currentNormalVector)) + currentNormalVector)
obj.Edit_Normals.SetNormal normalID tweakVector
obj.Edit_Normals.SetNormalExplicit normalID
)
NormalTweaker.ProgressValue += (100.0 / NormalTweaker.objList.Count) / faceList.Count
NormalTweaker.ProgBar.Value = NormalTweaker.ProgressValue
)
),
fn ProcessDistanceArray inArray mode =
--function takes an array of distances and returns an array of respective influence from 0 to 1
--where the smallest distance has a value of 1
--and the largest distance has a value of 0
--exponential mode may be more reflective of an intricate source object shape than linear mode
(
local hival = inArray[1]
local lowval = inArray[1]
local outArray = #()
for i = 2 to inArray.Count do
(
if (inArray[i] > hival) then
hival = inArray[i]
if (inArray[i] < lowval) then
lowval = inArray[i]
)
for i = 1 to inArray.Count do
(
local fieldValue = (hival - inArray[i]) / (hival - lowval)
case mode of
(
"linear":
(
append outArray fieldValue
break
)
"exponential":
(
-- --high powers yield more accurate results as the closest vertices have much greater relative influence
append outArray (fieldValue ^ 16)
break
)
)
)
return outArray
),
------------------------------------------------------------------------------------------------------------------------------------------
--LOAD/SAVE/CALLBACK FUNCTIONS
------------------------------------------------------------------------------------------------------------------------------------------
fn SaveIniFile =
(
setINISetting NormalTweaker.IniFilePath "NormalTweaker" "WinLocX" (NormalTweaker.Form.Location.x as string)
setINISetting NormalTweaker.IniFilePath "NormalTweaker" "WinLocY" (NormalTweaker.Form.Location.y as string)
setINISetting NormalTweaker.IniFilePath "NormalTweaker" "WinWidth" (NormalTweaker.Form.Width as string)
setINISetting NormalTweaker.IniFilePath "NormalTweaker" "WinHeight" (NormalTweaker.Form.Height as string)
setINISetting NormalTweaker.IniFilePath "NormalTweaker" "TweakValue" (NormalTweaker.SliderBar.Value as string)
setINISetting NormalTweaker.IniFilePath "NormalTweaker" "IDCheckState" (NormalTweaker.IDCheckBox.Checked as string)
setINISetting NormalTweaker.IniFilePath "NormalTweaker" "PreserveCheckState" (NormalTweaker.PreserveCheckBox.Checked as string)
callbacks.removeScripts #selectionSetChanged id:#NormalTweakerCallbacks
NormalTweaker.MiniMenu.Close()
),
fn LoadIniFile =
(
--default values
local WinLocX = 100
local WinLocY = 100
local WinWidth = 200
local WinHeight = 200
local TweakValue = 25
local IDCheckState = false
local PreserveCheckState = false
local QueryScript = (RsConfigGetWildWestDir() + "script/3dsMax/Maps/RSL_NormalTweaker_CB.ms")
try
(
WinLocX = getINISetting NormalTweaker.IniFilePath "NormalTweaker" "WinLocX" as Integer
WinLocY = getINISetting NormalTweaker.IniFilePath "NormalTweaker" "WinLocY" as Integer
WinWidth = getINISetting NormalTweaker.IniFilePath "NormalTweaker" "WinWidth" as Integer
WinHeight = getINISetting NormalTweaker.IniFilePath "NormalTweaker" "WinHeight" as Integer
TweakValue = getINISetting NormalTweaker.IniFilePath "NormalTweaker" "TweakValue" as Float
IDCheckState = getINISetting NormalTweaker.IniFilePath "NormalTweaker" "IDCheckState" as BooleanClass
PreserveCheckState = getINISetting NormalTweaker.IniFilePath "NormalTweaker" "PreserveCheckState" as BooleanClass
)
catch()
Form.Location = dotNetObject "system.drawing.point" WinLocX WinLocY
Form.Size = dotNetObject "System.Drawing.Size" WinWidth WinHeight
NormalTweaker.SliderBar.Value = TweakValue
NormalTweaker.SliderLabel.Text = ("Tweak amount: " + TweakValue as string + "%")
NormalTweaker.IDCheckBox.Checked = IDCheckState
NormalTweaker.PreserveCheckBox.Checked = PreserveCheckState
NormalTweaker.FlowPanel.Enabled = not NormalTweaker.IDCheckBox.Checked
callbacks.addScript #selectionSetChanged fileName:QueryScript id:#NormalTweakerCallbacks
NormalTweaker.Refresh()
),
------------------------------------------------------------------------------------------------------------------------------------------
--UI
------------------------------------------------------------------------------------------------------------------------------------------
fn CreateUI =
(
-- form setup
Form = dotNetObject "maxCustomControls.maxForm"
Form.Text = "RSL Normal Tweaker"
Form.StartPosition = (dotNetClass "System.Windows.Forms.FormStartPosition").manual
Form.Location = dotNetObject "system.drawing.point" 0 80
Form.MaximumSize = dotNetObject "System.Drawing.Size" 1600 1200
Form.MinimumSize = dotNetObject "System.Drawing.Size" 320 480
Form.FormBorderStyle = RS_dotNetPreset.FBS_Sizable
Form.SizeGripStyle = (dotNetClass "SizeGripStyle").show
dotNet.AddEventHandler Form "Load" LoadIniFile
dotNet.AddEventHandler Form "Closing" SaveIniFile
--content
ToolTip = dotnetobject "ToolTip"
Table = dotNetObject "TableLayoutPanel"
Table.Dock = RS_dotNetPreset.DS.Fill
Table.RowCount = 8
Table.RowStyles.add (RS_dotNetObject.rowStyleObject "absolute" 40) --RSBannerPanel
Table.RowStyles.add (RS_dotNetObject.rowStyleObject "percent" 100) --ContentPanel
Table.RowStyles.add (RS_dotNetObject.rowStyleObject "absolute" 15) --SliderLabel
Table.RowStyles.add (RS_dotNetObject.rowStyleObject "absolute" 30) --SliderBar
Table.RowStyles.add (RS_dotNetObject.rowStyleObject "absolute" 25) --PreserveCheckBox
Table.RowStyles.add (RS_dotNetObject.rowStyleObject "absolute" 75) --ButtonTable
Table.RowStyles.add (RS_dotNetObject.rowStyleObject "absolute" 50) --InfoPanel
Table.RowStyles.add (RS_dotNetObject.rowStyleObject "absolute" 15) --ProgressBar
Table.ColumnCount = 1
Table.ColumnStyles.add (RS_dotNetObject.columnStyleObject "percent" 100)
Form.Controls.Add Table
RSBannerPanel = dotNetObject "System.Windows.Forms.Panel"
RSBannerPanel.borderstyle = (dotnetClass "System.Windows.Forms.BorderStyle").FixedSingle
RSBannerPanel.dock = RS_dotNetPreset.DS.Fill
local banner = makeRsBanner dn_Panel:RSBannerPanel width:395 versionNum:1.0 versionName:"Unkle Munkle" studio:"london" mail:"andy.davis@rockstarlondon.com" wiki:"Map_Art_Tech"
banner.setup()
Table.Controls.Add RSBannerPanel 0 0
BlankLabel = RS_dotNetUI.InitLabel "Object selected needs to be an editable poly or editable mesh object." RS_dotNetPreset.TA.MiddleLeft
BlankLabel.Dock = RS_dotNetPreset.DS_Fill
BlankLabel.BackColor = RS_dotNetPreset.ARGB 48 48 48
Table.Tag = "blank"
Table.Controls.Add BlankLabel 0 1
ContentPanel = dotNetObject "TableLayoutPanel"
ContentPanel.Dock = RS_dotNetPreset.DS_Fill
ContentPanel.ColumnCount = 1
ContentPanel.AutoScroll = true
ContentPanel.BackColor = RS_dotNetPreset.ARGB 48 48 48
SliderLabel = RS_dotNetUI.InitLabel "Tweak amount: 50%" RS_dotNetPreset.TA.MiddleLeft
Table.Controls.Add SliderLabel 0 2
SliderBar = dotNetObject "TrackBar"
SliderBar.Dock = RS_dotNetPreset.DS_Fill
SliderBar.Minimum = 0
SliderBar.Maximum = 100
SliderBar.Value = 50
SliderBar.TickFrequency = 10
ToolTip.SetToolTip SliderBar "Set the amount to affect the normals by"
dotNet.AddEventHandler SliderBar "Scroll" UpdateSliderValue
Table.Controls.Add SliderBar 0 3
PreserveCheckBox = RS_dotNetUI.InitCheckBox "Preserve Modifier Stack"
ToolTip.SetToolTip PreserveCheckBox "Leave the edit normals modifier in the stack without collapsing"
Table.Controls.Add PreserveCheckBox 0 4
-- BUTTONS
ButtonTable = dotNetObject "TableLayoutPanel"
ButtonTable.Dock = RS_dotNetPreset.DS_Fill
ButtonTable.RowCount = 3
ButtonTable.RowStyles.add (RS_dotNetObject.rowStyleObject "percent" 33)
ButtonTable.RowStyles.add (RS_dotNetObject.rowStyleObject "percent" 33)
ButtonTable.RowStyles.add (RS_dotNetObject.rowStyleObject "percent" 33)
ButtonTable.ColumnCount = 2
ButtonTable.ColumnStyles.add (RS_dotNetObject.columnStyleObject "percent" 50)
ButtonTable.ColumnStyles.add (RS_dotNetObject.columnStyleObject "percent" 50)
Table.Controls.Add ButtonTable 0 5
RefreshButton = RS_dotNetUI.InitButton "Refresh"
ToolTip.SetToolTip RefreshButton "Refresh tool to reflect changes"
dotNet.AddEventHandler RefreshButton "Click" Refresh
ButtonTable.Controls.Add RefreshButton 0 0
AlignUpButton = RS_dotNetUI.InitButton "Align Normals Up"
AlignUpButton.Tag = "up"
ToolTip.SetToolTip AlignUpButton "Align normals based on Z-axis"
dotNet.AddEventHandler AlignUpButton "Click" TweakNormals
append NormalTweaker.ButtonSet AlignUpButton
ButtonTable.Controls.Add AlignUpButton 1 0
ExplodeButton = RS_dotNetUI.InitButton "Explode Normals"
ExplodeButton.Tag = "explode"
ToolTip.SetToolTip ExplodeButton "Align normals based on the object centre"
dotNet.AddEventHandler ExplodeButton "Click" TweakNormals
append NormalTweaker.ButtonSet ExplodeButton
ButtonTable.Controls.Add ExplodeButton 0 1
ResetButton = RS_dotNetUI.InitButton "Reset Normals"
ResetButton.Tag = "reset"
ToolTip.SetToolTip ResetButton "Reset vertex normals to default value"
dotNet.AddEventHandler ResetButton "Click" TweakNormals
append NormalTweaker.ButtonSet ResetButton
ButtonTable.Controls.Add ResetButton 1 1
FocusButton = RS_dotNetUI.InitButton "Focus Normals"
FocusButton.Tag= "focus"
ToolTip.SetToolTip FocusButton "Align normals based on a point helper"
dotNet.AddEventHandler FocusButton "Click" TweakNormals
append NormalTweaker.ButtonSet FocusButton
ButtonTable.Controls.Add FocusButton 0 2
StealButton = RS_dotNetUi.InitButton "Steal Normals"
StealButton.Tag= "steal"
ToolTip.SetToolTip StealButton "Align normals based on a source object"
dotNet.AddEventHandler StealButton "Click" TweakNormals
append NormalTweaker.ButtonSet StealButton
ButtonTable.Controls.Add StealButton 1 2
-- OTHER STUFF
InfoPanel = RS_dotNetUI.InitLabel "Selection: none" RS_dotNetPreset.TA.MiddleLeft
Table.Controls.Add InfoPanel 0 6
ProgBar = dotNetObject "ProgressBar"
ProgBar.Dock = RS_dotNetPreset.DS.Fill
ProgBar.Value = 0
ProgBar.Minimum = 0
ProgBar.Maximum = 100
Table.Controls.Add ProgBar 0 7
SinglePanel = dotNetObject "TableLayoutPanel"
SinglePanel.Dock = RS_dotNetPreset.DS.Fill
SinglePanel.RowCount = 2
SinglePanel.RowStyles.add (RS_dotNetObject.rowStyleObject "absolute" 20)
SinglePanel.RowStyles.add (RS_dotNetObject.rowStyleObject "percent" 100)
SinglePanel.Tag = "single"
IDCheckBox = dotNetObject "CheckBox"
IDCheckBox.Text = "affect all material id's"
IDCheckBox.Checked = false
IDCheckBox.Dock = RS_dotNetPreset.DS.Fill
dotNet.AddEventHandler IDCheckBox "CheckedChanged" ToggleAffectAll
SinglePanel.Controls.Add IDCheckBox 0 0
FlowPanel = dotNetObject "FlowLayoutPanel"
FlowPanel.Dock = RS_dotNetPreset.DS.Fill
FlowPanel.FlowDirection = FlowPanel.FlowDirection.TopDown
SinglePanel.Controls.Add FlowPanel 0 1
MultiPanel = dotNetObject "ListBox"
MultiPanel.Dock = RS_dotNetPreset.DS.Fill
MultiPanel.Tag = "multi"
--mini menu - currently not plugged in
MiniMenu = dotNetObject "maxCustomControls.maxForm"
MiniMenu.StartPosition = (dotNetClass "System.Windows.Forms.FormStartPosition").manual
MiniMenu.FormBorderStyle = RS_dotNetPreset.FBS_None
MiniMenu.Size = dotNetObject "System.Drawing.Size" 160 120
MiniTable = dotNetObject "TableLayoutPanel"
MiniTable.Dock = RS_dotNetPreset.DS.Fill
MiniTable.RowCount = 3
MiniTable.RowStyles.add (RS_dotNetObject.rowStyleObject "percent" 33)
MiniTable.RowStyles.add (RS_dotNetObject.rowStyleObject "percent" 33)
MiniTable.RowStyles.add (RS_dotNetObject.rowStyleObject "percent" 33)
MiniTable.ColumnCount = 1
MiniTable.ColumnStyles.add (RS_dotNetObject.columnStyleObject "percent" 100)
MiniMenu.Controls.Add MiniTable
SelectListedObjectsButton = RS_dotNetUI.InitButton "Select Listed Objects"
dotNet.AddEventHandler SelectListedObjectsButton "Click" SelectListedObjects
MiniTable.Controls.Add SelectListedObjectsButton 0 0
SelectAllObjectsButton = RS_dotNetUI.InitButton "Select All Objects"
dotNet.AddEventHandler SelectAllObjectsButton "Click" SelectAllObjects
MiniTable.Controls.Add SelectAllObjectsButton 0 1
CancelButton = RS_dotNetUI.InitButton "Cancel"
dotNet.AddEventHandler CancelButton "Click" Cancel
MiniTable.Controls.Add CancelButton 0 2
--draw form
Form.ShowModeless()
Form
)
)
if NormalTweaker != undefined then
(
NormalTweaker.Form.Close()
)
NormalTweaker = NormalTweakerStruct()
NormalTweaker.CreateUI()