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

792 lines
28 KiB
Plaintext
Executable File

-- TerrainSeamTool.ms
-- 2014 Andy Davis
-- Rockstar London
-- Description: tool snaps terrain seam vertices to adjacent terrain sections
filein (RsConfigGetWildWestDir() + "script/3dsMax/_config_files/Wildwest_header.ms") --wildwest header
filein (RsConfigGetWildWestDir() + "script/3dsMax/_common_functions/RSL_dotNetUIOps.ms") --RS_dotNetPreset structure
RsCollectToolUsageData (getThisScriptFilename())
global EdgeMatch
struct TerrainSeamTool_SeamVert
(
obj,
vertID,
position
)
struct TerrainSeamTool_SeamEdge
(
obj1,
vertids1,
obj2,
vertids2,
axis
)
struct TerrainSeamTool_ObjectSeamData
(
obj,
handle,
minXY,
maxXY,
edgeVertIDs = #{},
northVertIDs = #{},
southVertIDs = #{},
westVertIDs = #{},
eastVertIDs = #{},
nwVert,
neVert,
swVert,
seVert,
northEdgeIDs = #{},
southEdgeIDs = #{},
eastEdgeIDs = #{},
westEdgeIDs = #{},
--finds the end vertex on a row of vertices and removes the vertexID from the incoming array
--used to find corner verts on meshes with non-square edges
fn GetEndVert obj &vertIDs side =
(
vertIDs = vertIDs as array
local endVert
local axis
local numVerts = vertIDs.count
--east and west means looking on the x-axis
if ((side == #west) or (side == #east)) then
axis = 1
else --north and south are y-axis
axis = 2
--south and west means looking for the minimum values
if ((side == #west) or (side == #south)) then
(
local minValue = obj.verts[vertIDs[1]].position[axis]
local minID = 1
for i = 2 to numVerts do
(
local newValue = obj.verts[vertIDs[i]].position[axis]
if (newValue < minValue) then
(
minValue = newValue
minID = i
)
)
--transfer the found corner vert to the endVert variable, removing it from the vertIDs array
endVert = vertIDs[minID]
deleteItem vertIDs minID
)
else --values must be #north or #east
(
local maxValue = obj.verts[vertIDs[1]].position[axis]
local maxID = 1
for i = 2 to numVerts do
(
local newValue = obj.verts[vertIDs[i]].position[axis]
if (newValue > maxValue) then
(
maxValue = newValue
maxID = i
)
)
--transfer the found corner vert to the endVert variable, removing it from the vertIDs array
endVert = vertIDs[maxID]
deleteItem vertIDs maxID
)
return endVert
),
--run InitData when the obj is set up with a valid geometry object to the obj variable
fn InitData =
(
if obj != undefined then
(
local edgeIDs = polyop.getOpenEdges this.obj
this.edgeVertIDs = polyop.getVertsUsingEdge this.obj edgeIDs
local tolerance = 0.001
-- find the corner and edge verts based on proximity to bounds
for id in edgeVertIDs do
(
if (abs (obj.verts[id].position.x - obj.min.x) < tolerance) then
(
if (abs (obj.verts[id].position.y - obj.min.y) < tolerance) then swVert = id
else if (abs (obj.verts[id].position.y - obj.max.y) < tolerance) then nwVert = id
else append westVertIDs id
)
else if (abs (obj.verts[id].position.x - obj.max.x) < tolerance) then
(
if (abs (obj.verts[id].position.y - obj.min.y) < tolerance) then seVert = id
else if (abs (obj.verts[id].position.y - obj.max.y) < tolerance) then neVert = id
else append eastVertIDs id
)
else if (abs (obj.verts[id].position.y - obj.min.y) < tolerance) then append southVertIDs id
else if (abs (obj.verts[id].position.y - obj.max.y) < tolerance) then append northVertIDs id
)
--look for corner verts on meshes with non-square edges
--if found remove them from the vertID arrays: this is done by GetEndVert()
--even after these checks, the corner verts may not be found: two adjacent non-square edges will not yield a corner vert
if (nwVert == undefined) then
(
--check north and west vertices for the corner vert
if ((northVertIDs as array).count > 2) then
nwVert = GetEndVert obj &northVertIDs #west --looking for the most west vertex in the north vertices
else if ((westVertIDs as array).count > 2) then
nwVert = GetEndVert obj &westVertIDs #north
)
if (neVert == undefined) then
(
--check north and east vertices for the corner vert
if ((northVertIDs as array).count > 2) then
neVert = GetEndVert obj &northVertIDs #east
else if ((eastVertIDs as array).count > 2) then
neVert = GetEndVert obj &eastVertIDs #north
)
if (swVert == undefined) then
(
--check south and west vertices for the corner vert
if ((southVertIDs as array).count > 2) then
swVert = GetEndVert obj &southVertIDs #west
else if ((westVertIDs as array).count > 2) then
swVert = GetEndVert obj &westVertIDs #south
)
if (seVert == undefined) then
(
--check south and east vertices for the corner vert
if ((southVertIDs as array).count > 2) then
seVert = GetEndVert obj &southVertIDs #east
else if ((eastVertIDs as array).count > 2) then
seVert = GetEndVert obj &eastVertIDs #south
)
--sort the edges
for id in edgeIDs do
(
local vertIDs = (polyop.GetVertsUsingEdge this.obj id) as array
local edgePosition = (this.obj.verts[vertIDs[1]].position + this.obj.verts[vertIDs[2]].position) / 2
if (abs (edgePosition.x - obj.min.x) < tolerance) then
append westEdgeIDs id
else if (abs (edgePosition.x - obj.max.x) < tolerance) then
append eastEdgeIDs id
else if (abs (edgePosition.y - obj.min.y) < tolerance) then
append southEdgeIDs id
else if (abs (edgePosition.y - obj.max.y) < tolerance) then
append northEdgeIDs id
-- else
-- format "Object % Edge % is not on the periphery\n" this.obj.name id
)
handle = obj.inode.handle
minXY = [obj.min.x, obj.min.y]
maxXY = [obj.max.x, obj.max.y]
-- this.FormatData() --dev
)
else
format "warning: obj is undefined\n"
),
fn FormatData =
(
format "Name: %\t" (MaxOps.GetNodeByHandle this.handle).name
format "Boundaries: [%,%] [%,%]\n" minXY.x minXY.y maxXY.x maxXY.y
format "NE vert: %\nNW vert: %\nSE vert: %\nSW vert: %\n" neVert nwVert seVert swVert
format "--------VERTS----------\n"
format "North Verts: %\n" northVertIDs
format "South Verts: %\n" southVertIDs
format "East Verts: %\n" eastVertIDs
format "West Verts: %\n" westVertIDs
format "--------EDGES----------\n"
format "North Edges: %\n" northEdgeIDs
format "South Edges: %\n" southEdgeIDs
format "East Edges: %\n" eastEdgeIDs
format "West Edges: %\n" westEdgeIDs
format "\n"
)
)
struct EdgeMatchStruct
(
Form,
ToolTip,
InfoPanel,
ApplyButton,
ProgBar,
IniFilePath = (RsConfigGetWildWestDir() + "script/3dsMax/_config_files/AD_Tools.ini"),
ObjectList, --master array containing all data about object edges
searchTolerance = 0.5, --maximum gaps between edge vertices
edgeTolerance = 0.01, --maximum gap between edges
SeamCheckList = #(), --list of all the object seams to check against each other
CornerCheckList = #(), --list of all corners to check against each other
Progress = 0,
------------------------------------------------------------------------------------------------------------------------------------------
--GENERAL FUNCTIONS
------------------------------------------------------------------------------------------------------------------------------------------
fn Apply s e =
(
EdgeMatch.Process()
),
fn UndoClicked s e =
(
print "max undo"
max undo
),
------------------------------------------------------------------------------------------------------------------------------------------
--LOAD/SAVE FUNCTIONS
------------------------------------------------------------------------------------------------------------------------------------------
fn SaveIniFile =
(
setINISetting EdgeMatch.IniFilePath "EdgeMatch" "WinLocX" (EdgeMatch.Form.Location.x as string)
setINISetting EdgeMatch.IniFilePath "EdgeMatch" "WinLocY" (EdgeMatch.Form.Location.y as string)
-- setINISetting EdgeMatch.IniFilePath "EdgeMatch" "WinWidth" (EdgeMatch.Form.Width as string)
-- setINISetting EdgeMatch.IniFilePath "EdgeMatch" "WinHeight" (EdgeMatch.Form.Height as string)
),
fn LoadIniFile =
(
--default values
local WinLocX = 100
local WinLocY = 100
local WinWidth = 200
local WinHeight = 200
try
(
WinLocX = getINISetting EdgeMatch.IniFilePath "EdgeMatch" "WinLocX" as integer
WinLocY = getINISetting EdgeMatch.IniFilePath "EdgeMatch" "WinLocY" as integer
-- WinWidth = getINISetting EdgeMatch.IniFilePath "EdgeMatch" "WinWidth" as integers
-- WinHeight = getINISetting EdgeMatch.IniFilePath "EdgeMatch" "WinHeight" as integer
)
catch()
EdgeMatch.Form.Location = dotNetObject "system.drawing.point" WinLocX WinLocY
-- EdgeMatch.Form.Size = dotNetObject "System.Drawing.Size" WinWidth WinHeight
),
------------------------------------------------------------------------------------------------------------------------------------------
--TOOL CODE
------------------------------------------------------------------------------------------------------------------------------------------
fn GetEdges =
(
for item in selection where (this.IsTerrainMesh item) do
(
convertToPoly item
item.WeldThreshold = 0.01
newTerrainSeamTool_ObjectSeamData = TerrainSeamTool_ObjectSeamData obj:item
newTerrainSeamTool_ObjectSeamData.InitData()
append ObjectList newTerrainSeamTool_ObjectSeamData
)
),
fn IsTerrainMesh obj =
(
IsTerrain = false
if classOf obj == Editable_Poly then IsTerrain = true
if classOf obj == Editable_Mesh then IsTerrain = true
if classOf obj == Edit_Poly then IsTerrain = true
IsTerrain
),
--returns true if the edges of the two supplied edges line up
--edge: #north, #south, #east, #west
fn CheckEdgeOld obj1 obj2 edge =
(
--CheckEdge this.ObjectList[i].obj this.ObjectList[j].obj #east FUBAR ARG
local match = false
local tolerance = 0.001 --seems to be needed due to innaccuracy with logic testing of Max floats: yes, MAXScript is occasionally shit and annoying
case edge of
(
#north: --south edge of obj1 to north edge of obj2
(
if (abs (obj1.max.Y - obj2.min.Y) <= this.edgeTolerance) and (obj1.min.X + tolerance < obj2.max.X) and (obj1.max.X > obj2.min.X + tolerance) then match = true
break
)
#south: --north edge of obj1 to south edge of obj2
(
if (abs (obj1.min.Y - obj2.max.Y) <= this.edgeTolerance) and (obj1.min.X + tolerance < obj2.max.X) and (obj1.max.X > obj2.min.X + tolerance) then match = true
break
)
#east: --west edge of obj1 to east edge of obj2
(
if (abs (obj1.max.X - obj2.min.X) <= this.edgeTolerance) and (obj1.min.Y + tolerance < obj2.max.Y) and (obj1.max.Y > obj2.min.Y + tolerance) then match = true
break
)
#west: --east edge of obj1 to west edge of obj2
(
if (abs (obj1.min.X - obj2.max.X) <= this.edgeTolerance) and (obj1.min.Y + tolerance < obj2.max.Y) and (obj1.max.Y > obj2.min.Y + tolerance) then match = true
break
)
)
match
),
--returns the minimum and maximum values for a set of given vertices along a specific axis
fn GetMinMax obj vertIDs axis =
(
local id
local numVerts = vertIDs.count
if (axis == #x) then id = 1
if (axis == #y) then id = 2
local minValue = obj.verts[vertIDs[1]].position[id]
local maxValue = obj.verts[vertIDs[1]].position[id]
for i = 2 to numVerts do
(
local newValue = obj.verts[vertIDs[i]].position[id]
if (newValue < minValue) then
minValue = newValue
else if (newValue > maxValue) then
maxValue = newValue
)
return (dataPair min:minValue max:maxValue)
),
--returns true if the edges of the two supplied edges line up
--edge: #north, #south, #east, #west
fn CheckEdge obj1 obj2 edge =
(
local match = false
local tolerance = 0.1 --seems to be needed due to innaccuracy with logic testing of Max floats: yes, MAXScript is occasionally shit and annoying
case edge of
(
#north: --south edge of obj1 to north edge of obj2
(
if (abs (obj1.obj.max.Y - obj2.obj.min.Y) <= this.edgeTolerance) then
(
local obj1_southVertsMinMax = this.GetMinMax obj1.obj (obj1.southVertIDs as array) #x
local obj2_northVertsMinMax = this.GetMinMax obj2.obj (obj2.northVertIDs as array) #x
if (obj1_southVertsMinMax.min + tolerance < obj2_northVertsMinMax.max) and (obj1_southVertsMinMax.max > obj2_northVertsMinMax.min + tolerance) then
match = true
)
break
)
#south: --north edge of obj1 to south edge of obj2
(
if (abs (obj1.obj.min.Y - obj2.obj.max.Y) <= this.edgeTolerance) then
(
local obj1_southVertsMinMax = this.GetMinMax obj1.obj (obj1.southVertIDs as array) #x
local obj2_northVertsMinMax = this.GetMinMax obj2.obj (obj2.northVertIDs as array) #x
if (obj1_southVertsMinMax.min + tolerance < obj2_northVertsMinMax.max) and (obj1_southVertsMinMax.max > obj2_northVertsMinMax.min + tolerance) then
match = true
)
break
)
#east: --west edge of obj1 to east edge of obj2
(
if (abs (obj1.obj.max.X - obj2.obj.min.X) <= this.edgeTolerance) then
(
local obj1_eastVertsMinMax = this.GetMinMax obj1.obj (obj1.eastVertIDs as array) #y
local obj2_westVertsMinMax = this.GetMinMax obj2.obj (obj2.westVertIDs as array) #y
if (obj1_eastVertsMinMax.min + tolerance < obj2_westVertsMinMax.max) and (obj1_eastVertsMinMax.max > obj2_westVertsMinMax.min + tolerance) then
match = true
)
break
)
#west: --east edge of obj1 to west edge of obj2
(
if (abs (obj1.obj.min.X - obj2.obj.max.X) <= this.edgeTolerance) then
(
local obj1_westVertsMinMax = this.GetMinMax obj1.obj (obj1.westVertIDs as array) #y
local obj2_eastVertsMinMax = this.GetMinMax obj2.obj (obj2.eastVertIDs as array) #y
if (obj1_westVertsMinMax.min + tolerance < obj2_eastVertsMinMax.max) and (obj1_westVertsMinMax.max > obj2_eastVertsMinMax.min + tolerance) then
match = true
)
break
)
)
match
),
--qsort function
fn SortSeamVertsByX a b =
(
if a.position[1] < b.position[1] do return -1
if a.position[1] > b.position[1] do return 1
return 0
),
--qsort function
fn SortSeamVertsByY a b =
(
if a.position[2] < b.position[2] do return -1
if a.position[2] > b.position[2] do return 1
return 0
),
--matches the vertices along a pair of matching seam edges
--target can be used to force which edge stays in place
--target set to undefined or #obj1 or #obj2
--targetLocks determines whether unmatched verts move to the closest source vert, or whether new verts are created on the source edge
fn WeldSeam Seam target: undefined targetLocked: false =
(
local minValue, maxValue, axisID
local obj1 = Seam.obj1
local obj2 = Seam.obj2
local vertIDs1 = Seam.vertids1
local vertIDs2 = Seam.vertids2
local axis = Seam.axis
local matchedTargetVerts = #{}
local unmatchedVerts
local SeamVertList1 = for item in vertIDs1 collect (TerrainSeamTool_SeamVert obj:obj1 vertid:item position:obj1.verts[item].position)
local SeamVertList2 = for item in vertIDs2 collect (TerrainSeamTool_SeamVert obj:obj2 vertid:item position:obj2.verts[item].position)
local numVerts = SeamVertList1.count + SeamVertList2.count
--the axisID corresponds to whether we are checking in x or y
if axis == #x then
(
axisID = 1
QSort SeamVertList1 SortSeamVertsByX
QSort SeamVertList2 SortSeamVertsByX
)
else
(
axisID = 2
QSort SeamVertList1 SortSeamVertsByY
QSort SeamVertList2 SortSeamVertsByY
)
--find the minimum and maximum values
if (SeamVertList1[1].position[1] < SeamVertList2[1].position[axisID]) then
minValue = SeamVertList1[1].position[axisID]
else
minValue = SeamVertList2[1].position[axisID]
if (SeamVertList1[SeamVertList1.count].position[axisID] > SeamVertList2[SeamVertList2.count].position[1]) then
maxValue = SeamVertList1[SeamVertList1.count].position[axisID]
else
maxValue = SeamVertList2[SeamVertList2.count].position[axisID]
--the list with more verts is matched to the list with fewer
local SeamListSource, SeamListTarget, SourceVertIDs, SourceObject
--find the target
case target of
(
#obj1:
(
SeamListTarget = SeamVertList1
SeamListSource = SeamVertList2
SourceVertIDs = vertiDs2
SourceObject = obj2
break
)
#obj2:
(
SeamListTarget = SeamVertList2
SeamListSource = SeamVertList1
SourceVertIDs = vertiDs1
SourceObject = obj1
break
)
default:
(
--weld verts on edge with more verts
if SeamVertList1.count > SeamVertList2.count then
(
SeamListSource = SeamVertList1
SeamListTarget = SeamVertList2
SourceVertIDs = vertIDs1
SourceObject = obj1
)
else
(
SeamListSource = SeamVertList2
SeamListTarget = SeamVertList1
SourceVertIDs = vertIDs2
SourceObject = obj2
)
break
)
)
for sourceVert in SeamListSource do
(
local matchingVert = this.GetMatch sourceVert SeamListTarget axisID
sourceVert.obj.verts[sourceVert.vertID].position = SeamListTarget[matchingVert].position
sourceVert.position = SeamListTarget[matchingVert].position
append matchedTargetVerts matchingVert
)
--work out which of the target vertices have not had a corresponding source vert matched
unmatchedTargetVerts = #{1..SeamListTarget.count} - matchedTargetVerts
--now, what to do about the unmatched target vertices?
--if targetLocked true: create new verts on the source edge
--if targetLocked false: move the target verts to match source verts
if (not targetLocked) then
(
for id in unmatchedTargetVerts do
(
local targetVert = SeamListTarget[id]
local matchingVert = this.GetMatch targetVert SeamListSource axisID
targetVert.obj.verts[targetVert.vertID].position = SeamListSource[matchingVert].position
)
)
),
--finds the id of the closest edge vert that corresponds to a given vertex position
fn GetMatch vert SeamVertList axisID =
(
local position = vert.position[axisID] --the x or y postion of the test vertex
local numVerts = SeamVertList.count
local foundMatch = false
local match =SeamVertList[numVerts]
local gap = (SeamVertList[numVerts].position[axisID] - SeamVertList[1].position[axisID]) * 2
for i = 1 to numVerts where foundMatch == false do
(
local newGap = abs (SeamVertList[i].position[axisID] - position)
if newGap <= gap then
(
gap = newGap
match = i
)
else foundMatch = true
)
match
),
--generates SeamShcekList and CornerCheckList arrays
fn ProcessEdges =
(
local numObjects = this.ObjectList.count
local edgeMatchList = #()
-- for item in this.ObjectList do item.FormatData() --dev
--find all the edge matches
for i = 1 to (numObjects - 1) do
(
-- fix edges seams and generate CornerCheckList
for j = (i + 1) to numObjects do
(
--check each edge for proximity
if (CheckEdge this.ObjectList[i] this.ObjectList[j] #north) then
(
append edgeMatchList (TerrainSeamTool_SeamEdge obj1:this.ObjectList[i].obj vertids1:this.ObjectList[i].northVertIDs obj2:this.ObjectList[j].obj vertids2:this.ObjectList[j].southVertIDs axis:#x)
-- format "Case 1 (south to north): % matched to %\n" edgeMatchList[edgeMatchList.count].obj1.name edgeMatchList[edgeMatchList.count].obj2.name --dev
)
if (CheckEdge this.ObjectList[i] this.ObjectList[j] #south) then
(
append edgeMatchList (TerrainSeamTool_SeamEdge this.ObjectList[i].obj this.ObjectList[i].southVertIDs this.ObjectList[j].obj this.ObjectList[j].northVertIDs #x)
-- format "Case 2 (north to south): % matched to %\n" edgeMatchList[edgeMatchList.count].obj1.name edgeMatchList[edgeMatchList.count].obj2.name --dev
)
if (CheckEdge this.ObjectList[i] this.ObjectList[j] #east) then
(
append edgeMatchList (TerrainSeamTool_SeamEdge this.ObjectList[i].obj this.ObjectList[i].eastVertIDs this.ObjectList[j].obj this.ObjectList[j].westVertIDs #y)
-- format "Case 3 (west to east): % matched to %\n" edgeMatchList[edgeMatchList.count].obj1.name edgeMatchList[edgeMatchList.count].obj2.name --dev
)
if (CheckEdge this.ObjectList[i] this.ObjectList[j] #west) then
(
append edgeMatchList (TerrainSeamTool_SeamEdge this.ObjectList[i].obj this.ObjectList[i].westVertIDs this.ObjectList[j].obj this.ObjectList[j].eastVertIDs #y)
-- format "Case 4 (east to west): % matched to %\n" edgeMatchList[edgeMatchList.count].obj1.name edgeMatchList[edgeMatchList.count].obj2.name --dev
)
)
)
local numEdgeMatches = edgeMatchList.count
--execute the edge matches
for item in edgeMatchList where (item.vertids1.count > 0) and (item.vertids2.count > 0) do
(
this.Progress += (50 / numEdgeMatches)
this.ProgBar.Value = this.Progress
WeldSeam item
)
),
--move all matching corner points to average positions
fn ProcessCorners =
(
local CornerList = #() --array of SeamVert objects which describe a vertID with it's corresponding object and position
for item in this.ObjectList do
(
-- item.FormatData() --dev
--add the corners to the corner list but only if they exist
if item.nwVert != undefined then
append CornerList (TerrainSeamTool_SeamVert obj:item.obj vertid:item.nwVert position:item.obj.verts[item.nwVert].position)
if item.neVert != undefined then
append CornerList (TerrainSeamTool_SeamVert obj:item.obj vertid:item.neVert position:item.obj.verts[item.neVert].position)
if item.swVert != undefined then
append CornerList (TerrainSeamTool_SeamVert obj:item.obj vertid:item.swVert position:item.obj.verts[item.swVert].position)
if item.seVert != undefined then
append CornerList (TerrainSeamTool_SeamVert obj:item.obj vertid:item.seVert position:item.obj.verts[item.seVert].position)
)
local initialNumCorners = CornerList.count
while CornerList.count > 1 do
(
--iterate through the CornerList looking for matched corner verts
--note the first item in the list
local numCorners = CornerList.count
local refCorner = CornerList[1]
local matchList = #(refCorner)
local matchListIDs = #(1)
local tolerance = 0.001
local averagePosition = refCorner.position
for i = 2 to numCorners do
(
--check the distance between other corners and the refCorner to find matches
local xgap = abs (CornerList[i].position[1] - refCorner.position[1])
local ygap = abs (CornerList[i].position[2] - refCorner.position[2])
if (xgap < tolerance) and (ygap < tolerance) then
(--match found as vertices are within tolerance distance on x and y axes
append matchList CornerList[i]
append matchListIDs i
averagePosition += CornerList[i].position
)
)
local matchListCount = matchList.count
--when a group of matched corners is found, get the average position
if (matchListCount > 1) then
(
averagePosition /= matchList.count
--move the vertices
for item in matchList do
item.obj.verts[item.vertid].position.z = averagePosition.z --we only need the vertical, x and y don't change
--remove these matched corners from the CornerList
for i = 1 to matchListCount do
deleteItem CornerList (matchListIDs[matchListCount - i + 1])
)
else --if no match on current item, remove from the CornerList
deleteItem CornerList 1
this.Progress += (50 * (numCorners - CornerList.count) / initialNumCorners)
this.ProgBar.Value = this.Progress
)
),
fn Process =
(
ClearListener()
--1) Clear data
this.ObjectList = #()
this.Progress = 0
this.ProgBar.Value = 0
--2) Get a list of objects and their edge vertices
this.GetEdges()
--3) Check that they are in proximity: generate SeamCheckList and CornerCheckList
undo on
(
this.ProcessEdges()
--4) Match all the corners
this.ProcessCorners()
--5) Process isolated edge vertices
-- this.ProcessIsolatedVerts()
--6) Weld the edge vertices
for item in this.ObjectList do
polyop.WeldVertsByThreshold item.obj item.edgeVertIDs
)
this.Progress = 0
this.ProgBar.Value = 0
),
------------------------------------------------------------------------------------------------------------------------------------------
--UI
------------------------------------------------------------------------------------------------------------------------------------------
fn CreateUI =
(
-- form setup
Form = dotNetObject "maxCustomControls.maxForm"
Form.Text = "Terrain Seam Tool"
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" 100 100
Form.Size = dotNetObject "System.Drawing.Size" 240 230
Form.FormBorderStyle = RS_dotNetPreset.FB_FixedToolWindow
-- Form.FormBorderStyle = RS_dotNetPreset.FB_Sizable
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 = 4
Table.RowStyles.add (RS_dotNetObject.rowStyleObject "absolute" 40) --banner
Table.RowStyles.add (RS_dotNetObject.rowStyleObject "percent" 100) --info panel
Table.RowStyles.add (RS_dotNetObject.rowStyleObject "absolute" 40) --button
Table.RowStyles.add (RS_dotNetObject.rowStyleObject "absolute" 16) --progress bar
Table.ColumnCount = 1
Table.ColumnStyles.add (RS_dotNetObject.columnStyleObject "percent" 100)
Table.Margin = RS_dotNetPreset.Padding_None
Form.Controls.Add Table
RSBannerPanel = dotNetObject "System.Windows.Forms.Panel"
RSBannerPanel.borderstyle = RS_dotNetClass.borderStyleClass.FixedSingle
RSBannerPanel.dock = RS_dotNetPreset.DS.Fill
local banner = makeRsBanner dn_Panel:RSBannerPanel width:395 studio:"london" mail:"andy.davis@rockstarlondon.com" wiki:"Terrain Seam Tool"
banner.setup()
Table.Controls.Add RSBannerPanel 0 0
InfoPanel = RS_dotNetUI.InitLabel "" RS_dotNetPreset.TA.MiddleLeft
InfoPanel.Margin = dotNetObject "System.Windows.Forms.Padding" 8
InfoPanel.Font = dotNetObject "System.Drawing.Font" "Calibri" 10
InfoPanel.Text = "Select the terrain objects whose seams you want to fix, and hit the button."
InfoPanel.Text += "This tool moves edge vertices to match adjoining terrain sections and welds vertices where they coincide."
Table.Controls.Add InfoPanel 0 1
ButtonTable = dotNetObject "TableLayoutPanel"
ButtonTable.Dock = RS_dotNetPreset.DS_Fill
ButtonTable.RowCount = 1
ButtonTable.RowStyles.add (RS_dotNetObject.rowStyleObject "percent" 100)
ButtonTable.ColumnCount = 2
ButtonTable.ColumnStyles.add (RS_dotNetObject.columnStyleObject "percent" 50)
ButtonTable.ColumnStyles.add (RS_dotNetObject.columnStyleObject "percent" 50)
Table.Controls.Add ButtonTable 0 2
ApplyButton = RS_dotNetUI.InitButton "Fix Terrain Seam"
dotNet.AddEventHandler ApplyButton "Click" Apply
ApplyButton.Font = dotNetObject "System.Drawing.Font" "Arial Black" 11
ButtonTable.Controls.Add ApplyButton 0 0
ButtonTable.SetColumnSpan ApplyButton 2
UndoButton = RS_dotNetUI.InitButton "Undo"
dotNet.AddEventHandler UndoButton "Click" UndoClicked
-- ButtonTable.Controls.Add UndoButton 1 0
ProgBar = dotNetObject "ProgressBar"
ProgBar.Dock = RS_dotNetPreset.DS_Fill
Table.Controls.Add ProgBar 0 3
--draw form
Form.ShowModeless()
Form
)
)
-- ClearListener()
if EdgeMatch != undefined then EdgeMatch.Form.Close()
EdgeMatch = EdgeMatchStruct()
EdgeMatch.CreateUI()
-- EdgeMatch.Process()