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

277 lines
8.4 KiB
Plaintext
Executable File

(
local obj = $
local faceSel
/*
while (obj.modifiers.count > 0) do (deletemodifier obj 1)
*/
case of
(
((obj == undefined) or (isKindOf obj array) or (not isKindOf obj.baseObject Editable_Poly)):
(
messageBox "Please select an Editable Poly object" title:""
)
(obj.modifiers.count != 0):
(
messageBox "Please select an Editable Poly object with no modifiers" title:"Object has modifiers"
)
(
(subObjectLevel !=0) and ((polyop.getFaceSelection obj) == 0)
):
(
messageBox "Please select at least one face on object" title:"No faces selected"
)
Default:
(
local initialFaceSel = polyop.getFaceSelection obj
local initialEdgeSel = polyop.getEdgeSelection obj
local useFaces = if (subObjectLevel ==0) then #{1..obj.numfaces} else polyop.getFaceSelection obj
local faceEdges = for n = 1 to useFaces.count collect
(
if useFaces[n] then (polyop.getFaceEdges obj n) else undefined
)
for faceNum in useFaces do
(
-- Don't include non-quads:
if (polyop.getFaceVerts obj faceNum).count != 4 do
(
useFaces[faceNum] = false
)
)
-- Create UVWunwrap modifier, select the relevant quads:
local newUVmod = Unwrap_UVW()
newUVmod.unwrap5.setShowMapSeams off
newUVmod.unwrap5.setPeltAlwaysShowSeams off
addModifier obj newUVmod
/*
newUVmod.setApplyToWholeObject true
newUVmod.selectPolygonsUpdate useFaces true
newUVmod.setApplyToWholeObject false
*/
-- Work out which faces are contiguous:
local faceGroups = for n in useFaces collect #{n}
local faceGroupEdges = for item in faceEdges where (item != undefined) collect (item as bitarray)
-- Get edge-lengths for all used edges:
local allUsedEdges = #{}
for item in faceGroupEdges do (allUsedEdges += item)
local edgeNum, edgeVerts
local edgeLengths = for n = 1 to allUsedEdges.count collect
(
if allUsedEdges[n] then
(
edgeVerts = polyop.getEdgeVerts obj n
distance (polyop.getVert obj edgeVerts[1]) (polyop.getVert obj edgeVerts[2])
) else undefined
)
local existingGroups = #{1..faceGroups.count}
local repeatLoop = true
local combinedEdges
while repeatLoop do
(
repeatLoop = false
for grpNum = 1 to faceGroups.count where existingGroups[grpNum] do
(
for compareNum = (grpNum + 1) to faceGroups.count where existingGroups[compareNum] do
(
combinedEdges = faceGroupEdges[grpNum] + faceGroupEdges[compareNum]
-- If the edge-bitarrays overlap, the combined array will have fewer items than the seperate arrays:
if (combinedEdges.numberSet != (faceGroupEdges[grpNum].numberSet + faceGroupEdges[compareNum].numberSet)) do
(
faceGroupEdges[grpNum] = combinedEdges
faceGroups[grpNum] += faceGroups[compareNum]
existingGroups[compareNum] = false
repeatLoop = true
)
)
)
)
-- Keep only the combined facegroups:
local faceGroups = for n = 1 to faceGroups.count where existingGroups[n] collect faceGroups[n]
struct faceEdgeData (faceNum, pos, faceEdges, faceVerts = #(1,2,3,4), neighbours, xSize, ySize)
for faceNums in faceGroups do
(
-- Work out 2d positions for each quad:
local faceEdgeBits = for faceNum in faceNums collect (faceEdges[faceNum] as bitarray)
-- Make array with initial face:
local faceInfoArray = for faceNum in faceNums collect (faceEdgeData faceNum:faceNum faceEdges:faceEdges[faceNum])
faceInfoArray[1].pos = [0,0]
local doneFaces = #{}
local toDofaces = #{1}
local minPos = [0,0]
local maxPos = [0,0]
local adjFaceNum, adjFaceInfo, adjPos, adjFaceEdges, newEdgeList, neighbourNum, rotateVal
while (toDofaces.numberSet != 0) do
(
for toDoNum in toDofaces do
(
toDofaces[toDoNum] = false
doneFaces[toDoNum] = true
local faceInfo = faceInfoArray[toDoNum]
faceInfo.xSize = 0.5 * (edgeLengths[faceInfo.faceEdges[1]] + edgeLengths[faceInfo.faceEdges[3]])
faceInfo.ySize = 0.5 * (edgeLengths[faceInfo.faceEdges[2]] + edgeLengths[faceInfo.faceEdges[4]])
neighbourNum = 0
faceInfo.neighbours = for edgeNum in faceInfo.faceEdges collect
(
neighbourNum += 1
-- Find faces sharing this face's edges:
adjFaceNum = undefined
for n = 1 to faceInfoArray.count
where faceEdgeBits[n][edgeNum] and (n != toDoNum)
while (adjFaceNum == undefined) do
(
adjFaceNum = n
)
-- Set up neighbour-face info, if it hasn't been done already:
if (adjFaceNum != undefined) and not doneFaces[adjFaceNum] and not toDofaces[adjFaceNum] do
(
toDofaces[adjFaceNum] = true
adjFaceInfo = faceInfoArray[adjFaceNum]
adjFaceEdges = adjFaceInfo.faceEdges
-- Rotate neighbour edge-lists to match source-face's alignment:
rotateVal = (findItem adjFaceEdges edgeNum) - #(3,4,1,2)[neighbourNum]
if (rotateVal != 0) do
(
rotateVal = (mod (4 + rotateVal) 4) as integer
newEdgeList = for n = (rotateVal + 1) to 4 collect adjFaceEdges[n]
join newEdgeList (for n = 1 to rotateVal collect adjFaceEdges[n])
adjFaceInfo.faceEdges = newEdgeList
adjFaceInfo.faceVerts = case rotateVal of
(
1:#(2,3,4,1)
2:#(3,4,1,2)
3:#(4,1,2,3)
)
)
-- Set neighbour's grid-position:
adjPos = faceInfo.pos + #([0,-1],[1,0],[0,1],[-1,0])[neighbourNum]
adjFaceInfo.pos = adjPos
if (adjPos.x < minPos.x) do (minPos.x = adjPos.x)
if (adjPos.y < minPos.y) do (minPos.y = adjPos.y)
if (adjPos.x > maxPos.x) do (maxPos.x = adjPos.x)
if (adjPos.y > maxPos.y) do (maxPos.y = adjPos.y)
)
adjFaceNum
)
)
)
-- Get rid of faces that weren't processed for some reason:
for item in faceInfoArray where item.pos == undefined do useFaces[item.faceNum] = false
faceInfoArray = for item in faceInfoArray where item.pos != undefined collect item
-- Shift face-array position-values so that minimum is at [1,1]
for item in faceInfoArray do
(
item.pos -= (minPos - [1,1])
)
maxPos -= (minPos - [1,1])
-- Get heights/widths for each quad column/row:
local columnWidths = for n = 1 to maxPos.x collect #()
local rowHeights = for n = 1 to maxPos.y collect #()
for item in faceInfoArray do
(
append columnWidths[item.pos.x] item.xSize
append rowHeights[item.pos.y] item.ySize
)
-- Average the quad colum/row sizes:
local sumSize
columnWidths = for n = 1 to columnWidths.count collect
(
sumSize = 0.0
for item in columnWidths[n] do
(
sumSize += item
)
sumSize / columnWidths[n].count
)
rowHeights = for n = 1 to rowHeights.count collect
(
sumSize = 0.0
for item in rowHeights[n] do
(
sumSize += item
)
sumSize / rowHeights[n].count
)
local xPositions = #(0.0)
local yPositions = #(0.0)
for n = 1 to columnWidths.count do
(
append xPositions (xPositions[n] + columnWidths[n])
)
for n = 1 to rowHeights.count do
(
append yPositions (yPositions[n] + rowHeights[n])
)
local vertsToWeld = #{}
-- Apply new grid-positions to UV verts:
local minVertPos, maxVertPos, vertPositions
for faceInfo in faceInfoArray do
(
minVertPos = [xPositions[faceInfo.pos.x], yPositions[faceInfo.pos.y],0]
maxVertPos = [xPositions[faceInfo.pos.x + 1], yPositions[faceInfo.pos.y + 1],0]
vertPositions = #(minVertPos, [maxVertPos.x ,minVertPos.y, 0], maxVertPos, [minVertPos.x ,maxVertPos.y, 0])
for n = 1 to 4 do
(
newUVmod.setFaceVertex vertPositions[n] faceInfo.faceNum faceInfo.faceVerts[n] false
vertsToWeld[newUVmod.getVertexIndexFromFace faceInfo.faceNum n] = true
)
)
newUVmod.selectVertices vertsToWeld
newUVmod.weldSelected()
)
-- Select the affected faces
newUVmod.selectPolygonsUpdate useFaces true
newUVmod.setTVSubObjectMode 3
redrawViews()
)
)
OK
)