Files
2025-09-29 00:52:08 +02:00

277 lines
9.2 KiB
Plaintext
Executable File

-- GlueMaker
-- by Neal D Corbett, R*Leeds
-- 26/01/2010
try (DestroyDialog RSL_GlueMaker) catch ()
rollout RSL_GlueMaker "R*Leeds GlueMaker" width:200
(
label GlueLabel "Creates \"glue\" objects from selected\nborder-edges of selected objects,\nso buildings sit on the ground better" align:#left height:46
spinner GlueWidthUI "Glue width:" range:[0.1,20,1]
spinner CornerPushUI "Corner push-factor:" range:[0.0,2,0.0]
spinner AllPushUI "Wall/floor offset:" range:[0.0,1,0.002]
checkbox DelOldGlueUI "Delete object's old glue on create" checked:true
button GlueMakeBtn "Make glue for selected objects"
on GlueMakeBtn pressed do
(
undo "make glue" on
(
local OldSelect = for ThisObj in selection collect ThisObj
for ThisObj in OldSelect where
(
((iskindOf ThisObj Editable_Poly) or (iskindOf ThisObj Editable_Mesh)) and
(not (matchPattern ThisObj.name pattern:"*_glue??"))) do
(
if DelOldGlueUI.checked do
(
(execute ("delete $'" + ThisObj.name + "_glue*'"))
)
local GlueWidth = GlueWidthUI.value
local CornerPush = CornerPushUI.value * GlueWidth
local AllPush = AllPushUI.value
local NewObj = copy ThisObj
NewObj.name = uniquename (ThisObj.name + "_glue")
convertToPoly NewObj
local GlueEdges = (polyOp.getEdgeSelection NewObj) * (polyOp.getOpenEdges NewObj)
if (GlueEdges.numberSet == 0) then delete NewObj else
(
polyOp.setEdgeSelection NewObj GlueEdges
NewObj.ConvertSelectionToBorder #Edge #Edge
-- Generate lists of contiguous edge-selections
local EdgeVertGroups = for Edge in GlueEdges collect (polyOp.getVertsUsingEdge NewObj Edge)
local VertsUsed = polyOp.getVertsUsingEdge NewObj GlueEdges
local VertAdjacents = for n = 1 to VertsUsed.count collect #{}
for Edge in EdgeVertGroups do (for VertNum in Edge do (VertAdjacents[VertNum] += Edge))
-- for n = 1 to VertAdjacents.count where (VertAdjacents[n].count != 0) do (format "%: %\n" n VertAdjacents[n])
local RemoveEdges, Conjunction
local Rearrange = True
while Rearrange do
(
Rearrange = False
RemoveEdges = #{}
for EdgeNum = 1 to EdgeVertGroups.count
where (not RemoveEdges[EdgeNum]) do
(
for SearchEdge = (EdgeNum + 1) to EdgeVertGroups.count
where (not RemoveEdges[SearchEdge]) do
(
Conjunction = EdgeVertGroups[EdgeNum] + EdgeVertGroups[SearchEdge]
if (Conjunction.numberSet != (EdgeVertGroups[EdgeNum].numberSet + EdgeVertGroups[SearchEdge].numberSet)) do
(
EdgeVertGroups[EdgeNum] = Conjunction
RemoveEdges[SearchEdge] = True
Rearrange = True
)
)
)
-- Remove now-combined edge-arrays, in reverse order
RemoveEdges = RemoveEdges as array
for n = RemoveEdges.count to 1 by -1 do
(
deleteItem EdgeVertGroups RemoveEdges[n]
)
)
EdgeVertGroups = for Group in EdgeVertGroups collect (Group as array)
-- Create lists of verts, with all numbers correctly adjacent
for GroupNum = 1 to EdgeVertGroups.count do
(
local NewGroup, NotFound
local OldGroup = EdgeVertGroups[GroupNum]
local Placed = #{}
while ((Placed.numberSet != OldGroup.count) and (not keyboard.escPressed)) do
(
for n = 1 to OldGroup.count where (not Placed[n]) do
(
VertNum = OldGroup[n]
if (NewGroup == undefined) then (NewGroup = #(VertNum); Placed[n] = True) else
(
case of
(
(VertAdjacents[VertNum][NewGroup[NewGroup.count]]):
(
append NewGroup VertNum
Placed[n] = True
)
(VertAdjacents[VertNum][NewGroup[1]]):
(
insertItem VertNum NewGroup 1
Placed[n] = True
)
)
)
)
)
-- Find and break edge-loops
if (VertAdjacents[NewGroup[1]][NewGroup[NewGroup.count]]) do
(
polyOp.breakVerts NewObj NewGroup[1]
local OldVertNum = NewGroup[1]
local NewVertNum = NewObj.numVerts
if (polyOp.getVertsUsingEdge NewObj (polyOp.getEdgesUsingVert NewObj NewVertNum))[NewGroup[2]] then
(
NewGroup[1] = NewVertNum
append NewGroup OldVertNum
)
else
(
append NewGroup NewVertNum
)
)
EdgeVertGroups[GroupNum] = NewGroup
)
-- format "EdgeVertGroups: %\n" (EdgeVertGroups as string)
-- Set out the initial mapping
polyOp.defaultMapFaces NewObj 1
local UVDistance, PrevVertPos, VertPos
for Group in EdgeVertGroups do
(
PrevVertPos = undefined
UVDistance = 0
for VertNum in Group do
(
VertPos = polyOp.getVert NewObj VertNum
if (PrevVertPos != undefined) do
(
UVDistance += ((distance VertPos PrevVertPos) / GlueWidth)
)
polyOp.setMapVert NewObj 1 VertNum [UVDistance,0.5,0]
PrevVertPos = VertPos
)
)
-- format "EdgeFaces: %\n" EdgeFaces
max Modify Mode
modPanel.setCurrentObject NewObj
-- Extrusions:
setSelectionLevel NewObj #edge
NewObj.edgeChamfer = 0.0
NewObj.edgeExtrudeHeight = GlueWidth
NewObj.edgeExtrudeWidth = 0.0
NewObj.edgeChamferOpen = True
NewObj.EditablePoly.buttonOp #Extrude
NewObj.EditablePoly.ConvertSelection #Edge #Face
polyOp.deleteFaces NewObj -(polyOp.getFaceSelection NewObj)
local OuterSelect = polyOp.getEdgeSelection NewObj
NewObj.EditablePoly.GrowSelection()
polyOp.weldEdgesByThreshold NewObj ((polyOp.getEdgeSelection NewObj) - OuterSelect)
local ExtrudeEdges = -(polyOp.getEdgeSelection NewObj)
polyOp.setEdgeSelection NewObj ExtrudeEdges
NewObj.EditablePoly.buttonOp #Extrude
-- White vertex colours
polyOp.SetFaceColor NewObj -2 #{1..NewObj.numFaces} (color 255 255 255)
-- White vertex alpha
polyOp.SetFaceColor NewObj 0 #{1..NewObj.numFaces} (color 255 255 255)
-- Move border-UVs to top & bottom of map
local StartVertCount = (polyop.getNumMapVerts NewObj 1) / 3
local NextNum
for VertNum = 1 to StartVertCount do
(
polyOp.setMapVert NewObj 1 VertNum ((polyOp.getMapVert NewObj 1 VertNum) + [0,-0.5,0])
NextNum = VertNum + StartVertCount
polyOp.setMapVert NewObj 1 NextNum ((polyOp.getMapVert NewObj 1 NextNum) + [0,0.5,0])
)
local VertFaceNums = #()
local VertFaceNormals = #()
local VertFaces, AvNormal
VertFaceNormals = for n = 1 to NewObj.numVerts collect
(
local VertFaces = (polyOp.getFacesUsingVert NewObj n) as array
append VertFaceNums VertFaces
case VertFaces.count of
(
4:
(
AvNormal = [0,0,0]
for FaceNum in VertFaces do (AvNormal += (polyOp.getFaceNormal NewObj FaceNum))
AvNormal /= 4.0
)
Default:Null
)
)
local AvNormal, FaceVerts, FaceHash, FindNum, OppIndex
local MakeEdges = #()
local FaceSearchList = #()
if (CornerPush != 0) do
(
for n = 1 to NewObj.numVerts do
(
case of
(
(VertFaceNormals[n] != null): -- Move wall/floor corner-verts outward
(
polyOp.moveVert NewObj #{n} (VertFaceNormals[n] * CornerPush)
)
(VertFaceNums[n].count == 1): -- Add diagonal edge to single-quad verts
(
-- Find other verts using the quad this vert uses
FaceVerts = polyOp.getFaceVerts NewObj VertFaceNums[n][1]
FaceHash = getHashValue FaceVerts 1
FindNum = findItem FaceSearchList FaceHash
if (FindNum == 0) then
(
-- Find the index of the vert on opposite side of quad, and create edge
OppIndex = (findItem FaceVerts n) + 2
if (OppIndex > 4) do (OppIndex = mod OppIndex 4)
append MakeEdges #(n,FaceVerts[OppIndex])
append FaceSearchList FaceHash
) else
(
-- Don't add edges for single-length glue
deleteItem MakeEdges FindNum
deleteItem FaceSearchList FindNum
)
)
)
)
for Edge in MakeEdges do
(
polyOp.createEdge NewObj Edge[1] Edge[2]
)
)
if (AllPush != 0) do (setSelectionLevel NewObj #face; addModifier NewObj (Push PushValue:AllPush); collapseStack NewObj)
polyOp.autoSmooth NewObj
setSelectionLevel NewObj #object
/*
NewObj.alledges = on
NewObj.wirecolor = orange
NewObj.material = StandardMaterial()
-- NewObj.material.diffuseMap = Gradient()
-- NewObj.material.diffuseMap = Gradient_Ramp()
NewObj.material.diffuseMap = Checker()
NewObj.material.diffuseMap.coords.U_Tiling = 8
NewObj.material.diffuseMap.coords.V_Tiling = 8
showTextureMap NewObj.material on
*/
)
)
select (for ThisObj in OldSelect where (isValidNode ThisObj) collect ThisObj)
)
)
)
createDialog RSL_GlueMaker