277 lines
9.2 KiB
Plaintext
Executable File
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
|