492 lines
15 KiB
Plaintext
Executable File
492 lines
15 KiB
Plaintext
Executable File
-- Rockstar Extrude Tool
|
|
-- Rockstar North
|
|
-- 6/12/2005
|
|
-- by Luke Openshaw
|
|
|
|
-- Extrude tool which accommodates for UV mapping of newly created faces
|
|
|
|
|
|
rollout RsModelToolExtrudeRoll "Extrude with Auto Texture"
|
|
(
|
|
--////////////////////////////////////////////////////////////
|
|
-- interface
|
|
--////////////////////////////////////////////////////////////
|
|
hyperlink lnkHelp "Help?" address:"https://devstar.rockstargames.com/wiki/index.php/Modelling_Toolkit#Extrude_with_Auto_Texture" align:#right color:(color 0 0 255) hoverColor:(color 0 0 255) visitedColor:(color 0 0 255)
|
|
|
|
button btnBeginExtrude "Begin Extrude" enabled:true width:100 pos:[140,15]
|
|
button btnEndExtrude "End Extrude" enabled:false width:100 pos:[140,48]
|
|
spinner spnU "U Scale" range:[0.0,1.0,0.05] type:#float scale:0.01 width:60 pos:[46,15]
|
|
spinner spnV "V Scale" range:[0.0,1.0,0.05] type:#float scale:0.01 width:60 pos:[46,48]
|
|
|
|
|
|
group "Flip Texture Coordinates"
|
|
(
|
|
button btnFlipU "Flip U" width:100 pos:[28,85]
|
|
button btnFlipV "Flip V" width:100 pos:[140,85]
|
|
)
|
|
|
|
global initFaceCount = 0
|
|
global classOfObj
|
|
global reversed = false
|
|
global xAligned = false
|
|
global zAligned = false
|
|
|
|
--////////////////////////////////////////////////////////////
|
|
-- methods
|
|
--////////////////////////////////////////////////////////////
|
|
|
|
|
|
--------------------------------------------------------------
|
|
-- Retrieve the texture IDs for a given face.
|
|
--------------------------------------------------------------
|
|
fn SimpleCalcTexIndices obj arrFace = (
|
|
|
|
-- Editable_mesh extruded faces must consist of two faces with
|
|
-- three vertices each while Editable_poly extruded faces
|
|
-- must consist of one face with four vertices
|
|
texVertIndex = #()
|
|
if classOfObj == Editable_mesh then (
|
|
face1 = getTVFace obj arrFace[1]
|
|
face2 = getTVFace obj arrFace[2]
|
|
|
|
texVertIndex = #(face1.x, face1.y, face1.z, face2.x, face2.y, face2.z)
|
|
|
|
)
|
|
else if classOfObj == Editable_poly then (
|
|
texVertIndex = #(((obj.GetMapFaceVertex 1 arrFace 1) + 1), ((obj.GetMapFaceVertex 1 arrFace 2) + 1), ((obj.GetMapFaceVertex 1 arrFace 3) + 1), ((obj.GetMapFaceVertex 1 arrFace 4) + 1))
|
|
|
|
)
|
|
return texVertIndex
|
|
)
|
|
|
|
--------------------------------------------------------------
|
|
-- Calculate the orientation of a face
|
|
--------------------------------------------------------------
|
|
fn CalcOrientation obj arrFace = (
|
|
|
|
-- Calculate the dot product of the current face's normal
|
|
-- and each of the axis.
|
|
if classOfObj == Editable_mesh then (
|
|
|
|
dpZ = dot (getFaceNormal obj arrFace[1]) [0,0,1]
|
|
dpX = dot (getFaceNormal obj arrFace[1]) [1,0,0]
|
|
dpY = dot (getFaceNormal obj arrFace[1]) [0,1,0]
|
|
)
|
|
else if classOfObj == Editable_poly then (
|
|
|
|
dpZ = dot (polyop.getFaceNormal obj arrFace) [0,0,1]
|
|
dpX = dot (polyop.getFaceNormal obj arrFace) [1,0,0]
|
|
dpY = dot (polyop.getFaceNormal obj arrFace) [0,1,0]
|
|
)
|
|
|
|
-- If the dot product of the face and the z-axis is greater then
|
|
-- 0.05 or less than -0.05 then the face is along the the z-axis
|
|
if dpZ > 0.05 then (
|
|
orientation = -1.0
|
|
zAligned = true
|
|
|
|
)
|
|
else if dpZ < -0.05 then (
|
|
orientation = 1.0
|
|
zAligned = true
|
|
)
|
|
-- Else if the determine the faces orientation based upon
|
|
-- Whether is is x-aligned and the direction it is facing.
|
|
else (
|
|
if xAligned == false then (
|
|
if dpX > 0 and reversed == true then (
|
|
orientation = -1.0
|
|
return orientation
|
|
)
|
|
else if dpX > 0 and reversed == false then (
|
|
orientation = 1.0
|
|
return orientation
|
|
)
|
|
else if dpX < 0 and reversed == true then (
|
|
orientation = 1.0
|
|
return orientation
|
|
)
|
|
else if dpX < 0 and reversed == false then (
|
|
orientation = -1.0
|
|
return orientation
|
|
)
|
|
)
|
|
else if xAligned == true then (
|
|
|
|
if dpY > 0 and reversed == true then (
|
|
orientation = 1.0
|
|
return orientation
|
|
)
|
|
else if dpY > 0 and reversed == false then (
|
|
orientation = -1.0
|
|
return orientation
|
|
)
|
|
else if dpY < 0 and reversed == true then (
|
|
orientation = -1.0
|
|
return orientation
|
|
)
|
|
else if dpY < 0 and reversed == false then (
|
|
orientation = 1.0
|
|
return orientation
|
|
)
|
|
|
|
)
|
|
)
|
|
return orientation
|
|
)
|
|
|
|
|
|
--------------------------------------------------------------
|
|
-- The function that moves the two vertices passed to it
|
|
--------------------------------------------------------------
|
|
fn MoveTexCoords index texVertIndex obj arrFace axis = (
|
|
|
|
-- Set the two vertex coordinate variables to the vertex position of two of the vertices
|
|
-- in the vertex index array passed in.
|
|
vertexCoord1 = $.modifiers[#unwrap_uvw].unwrap.getVertexPosition 0 texVertIndex[index]
|
|
vertexCoord2 = $.modifiers[#unwrap_uvw].unwrap.getVertexPosition 0 texVertIndex[index + 1]
|
|
|
|
refPoint = $.modifiers[#unwrap_uvw].unwrap.getVertexPosition 0 texVertIndex[index]
|
|
|
|
-- Calculate the offset value based on the faces orientation (to determine the direction)
|
|
-- and the offset scaling value provided by the user
|
|
if zAligned == true then (
|
|
offset = (CalcOrientation obj arrFace) * spnU.value
|
|
)
|
|
else (
|
|
offset = (CalcOrientation obj arrFace) * spnV.value
|
|
)
|
|
|
|
-- Update the texture vertex coordinates variable in either the x or y direction depending on
|
|
-- orientation. x and y refer to u and v in texture space.
|
|
if axis == "x" then (
|
|
vertexCoord1.x = refPoint.x + offSet
|
|
vertexCoord2.x = refPoint.x + offSet
|
|
)
|
|
else if axis == "y" then (
|
|
vertexCoord1.y = refPoint.y + offSet
|
|
vertexCoord2.y = refPoint.y + offSet
|
|
)
|
|
|
|
-- Update the texture coordinates.
|
|
$.modifiers[#unwrap_uvw].unwrap.setVertexPosition 0 texVertIndex[index] vertexCoord1
|
|
$.modifiers[#unwrap_uvw].unwrap.setVertexPosition 0 texVertIndex[index + 1] vertexCoord2
|
|
zAligned = false
|
|
)
|
|
|
|
|
|
--------------------------------------------------------------
|
|
-- Move the texture coordinates of two of texture vertices
|
|
-- in a direction dependant on face orientation
|
|
--------------------------------------------------------------
|
|
fn CorrectTexCoord texVertIndex obj arrFace = (
|
|
|
|
modPanel.addModToSelection (Unwrap_UVW ()) ui:on
|
|
|
|
--
|
|
if classOfObj == Editable_Mesh then (
|
|
|
|
-- If the current face is xAligned run a dot product against
|
|
-- the y-axis to determine how the tex-coords are generated.
|
|
-- Otherwise run the dot product against the x-axis.
|
|
if xAligned == false then (
|
|
|
|
dpX = dot (getFaceNormal obj arrFace[1]) [1,0,0]
|
|
if dpX > -0.5 and dpX < 0.5 then (
|
|
MoveTexCoords 4 texVertIndex obj arrFace "y"
|
|
)
|
|
else (
|
|
MoveTexCoords 1 texVertIndex obj arrFace "x"
|
|
)
|
|
)
|
|
else if xAligned == true then (
|
|
|
|
dpY = dot (getFaceNormal obj arrFace[1]) [0,1,0]
|
|
if dpY > -0.5 and dpY < 0.5 then (
|
|
MoveTexCoords 4 texVertIndex obj arrFace "y"
|
|
)
|
|
else (
|
|
MoveTexCoords 1 texVertIndex obj arrFace "x"
|
|
)
|
|
)
|
|
)
|
|
|
|
else if classOfObj == Editable_Poly then (
|
|
|
|
-- If the current face is xAligned run a dot product against
|
|
-- the y-axis to determine how the tex-coords are generated.
|
|
-- Otherwise run the dot product against the x-axis.
|
|
if xAligned == false then (
|
|
|
|
dpX = dot (polyOp.getFaceNormal obj arrFace) [1,0,0]
|
|
if dpX > -0.5 and dpX < 0.5 then (
|
|
MoveTexCoords 3 texVertIndex obj arrFace "y"
|
|
)
|
|
else (
|
|
MoveTexCoords 1 texVertIndex obj arrFace "x"
|
|
)
|
|
)
|
|
else if xAligned == true then (
|
|
|
|
dpY = dot (polyOp.getFaceNormal obj arrFace) [0,1,0]
|
|
if dpY > -0.5 and dpY < 0.5 then (
|
|
MoveTexCoords 3 texVertIndex obj arrFace "y"
|
|
|
|
)
|
|
else (
|
|
MoveTexCoords 1 texVertIndex obj arrFace "x"
|
|
)
|
|
)
|
|
)
|
|
|
|
return true
|
|
)
|
|
|
|
|
|
--------------------------------------------------------------
|
|
-- Load in the necessary variables prior to extrusion and
|
|
-- perform some basic validation
|
|
--------------------------------------------------------------
|
|
fn ExtrudeBegin = (
|
|
sel = selection as array
|
|
|
|
if sel.count != 1 then
|
|
(
|
|
messagebox "Please select only one object"
|
|
return false
|
|
)
|
|
|
|
if sel[1].modifiers != undefined then
|
|
(
|
|
if not querybox "To perform this action the object cannot have any modifiers on it. Do you wish to collapse the stack?" then
|
|
(
|
|
return false
|
|
)
|
|
else
|
|
(
|
|
maxOps.CollapseNode sel[1] true
|
|
)
|
|
)
|
|
|
|
-- Store the number of faces in the object prior to extrusion
|
|
initFaceCount = getNumFaces sel[1]
|
|
try
|
|
(
|
|
subObjectLevel = 4
|
|
)
|
|
catch
|
|
(
|
|
print "Unable to perform operation, unable to get to sub object level 4 of object."
|
|
return false
|
|
)
|
|
|
|
-- Set mode to Extrude
|
|
classOfObj = classof sel[1]
|
|
if classOfObj == Editable_mesh then (
|
|
meshOps.startExtrude sel[1]
|
|
)
|
|
else if classOfObj == Editable_Poly then (
|
|
polyOps.startExtrudeFace sel[1]
|
|
)
|
|
|
|
return true
|
|
)
|
|
|
|
|
|
--------------------------------------------------------------
|
|
-- After the extrusion, collect the data about the newly
|
|
-- created faces and run the texture correction
|
|
--------------------------------------------------------------
|
|
fn ExtrudeEnd = (
|
|
sel = selection as array
|
|
|
|
|
|
if sel.count == 0 then (
|
|
messageBox "No object is selected. Bailing out."
|
|
return false
|
|
)
|
|
|
|
-- Store the new face count after the extrusion
|
|
newFaceCount = getNumFaces sel[1]
|
|
|
|
-- If there are no new faces, bail out.
|
|
if newFaceCount == initFacecount then (
|
|
messageBox "No extrusion has occured. Bailing out."
|
|
return false
|
|
)
|
|
|
|
|
|
arrExtFace = (getFaceSelection sel[1]) as array
|
|
|
|
-- Calculate the dot products of the extruded face normal with the x and y axis.
|
|
if classOfObj == Editable_Mesh then dpY = dot (getFaceNormal sel[1] arrExtFace[1]) [0,1,0]
|
|
else if classOfObj == Editable_Poly then dpY = dot (polyOp.getFaceNormal sel[1] arrExtFace[1]) [0,1,0]
|
|
|
|
if classOfObj == Editable_Mesh then dpX = dot (getFaceNormal sel[1] arrExtFace[1]) [1,0,0]
|
|
else if classOfObj == Editable_Poly then dpX = dot (polyOp.getFaceNormal sel[1] arrExtFace[1]) [1,0,0]
|
|
|
|
-- Determine whether the face is x-aligned and then determine the direction it is facing.
|
|
if dpX > -0.5 and dpX < 0.5 then (4
|
|
xAligned = false
|
|
if dpY < 0 then reversed = true
|
|
else reversed = false
|
|
)
|
|
else (
|
|
xAligned = true
|
|
if dpX < 0 then reversed = true
|
|
else reversed = false
|
|
)
|
|
|
|
|
|
faceIndexBegin = initFaceCount+1
|
|
|
|
bitArrFace = #{faceIndexBegin..newFaceCount}
|
|
|
|
-- Calculate the number of faces that need to be textured by
|
|
-- subtracting the new face count from the face count prior
|
|
-- to extrusion
|
|
faceCountDif = newFaceCount - initFaceCount
|
|
if classOfObj == Editable_Mesh then faceCountDif = faceCountDif / 2
|
|
|
|
j = faceIndexBegin
|
|
|
|
texVertIndex = #()
|
|
bitArrFace = #{}
|
|
arrFace = #()
|
|
|
|
-- Fo every new face that has been created, calculate the texture indices and
|
|
-- correct them depending on their orientation.
|
|
for i = 1 to (faceCountDif) do (
|
|
|
|
if classOfObj == Editable_Mesh then (
|
|
bitArrFace = #{j..(j + 1)}
|
|
arrFace = [j,(j + 1)]
|
|
j = j + 2
|
|
)
|
|
else if classOfObj == Editable_Poly then (
|
|
bitArrFace = #{j}
|
|
arrFace = j
|
|
j = j + 1
|
|
)
|
|
|
|
subObjectLevel = 4
|
|
setfaceselection sel[1] bitArrFace
|
|
texVertIndex = SimpleCalcTexIndices sel[1] arrFace
|
|
CorrectTexCoord texVertIndex sel[1] arrFace
|
|
|
|
if classOfObj == Editable_Mesh then convertToMesh sel[1]
|
|
else if classOfObj == Editable_Poly then convertToPoly sel[1]
|
|
)
|
|
return true
|
|
)
|
|
|
|
|
|
--------------------------------------------------------------
|
|
-- Flip the coordinates of the texture vertices either on the
|
|
-- U or V axis
|
|
--------------------------------------------------------------
|
|
fn Flip orientation arrFace texVertIndex obj = (
|
|
|
|
modPanel.addModToSelection (Unwrap_UVW ()) ui:on
|
|
|
|
-- Again because texture vertices are managed differently between a polygon and editable mesh,
|
|
-- they need different code.
|
|
if classOfObj == Editable_mesh then (
|
|
|
|
texBitVertIndex = texVertIndex as bitarray
|
|
|
|
$.modifiers[#unwrap_uvw].unwrap.selectVertices texBitVertIndex
|
|
if orientation == 1 then $.modifiers[#unwrap_uvw].mirrorh()
|
|
if orientation == 0 then $.modifiers[#unwrap_uvw].mirrorv()
|
|
convertToMesh obj
|
|
)
|
|
else if classOfObj == Editable_poly then (
|
|
|
|
texBitVertIndex = texVertIndex as bitarray
|
|
|
|
$.modifiers[#unwrap_uvw].unwrap.selectVertices texBitVertIndex
|
|
if orientation == 1 then $.modifiers[#unwrap_uvw].mirrorh()
|
|
if orientation == 0 then $.modifiers[#unwrap_uvw].mirrorv()
|
|
convertToPoly obj
|
|
)
|
|
)
|
|
|
|
--------------------------------------------------------------
|
|
-- Loop through all the selected faces and flip the coordinates
|
|
-- of the texture vertices
|
|
--------------------------------------------------------------
|
|
fn FlipPrepare orientation = (
|
|
sel = selection as array
|
|
|
|
if sel.count == 0 then (
|
|
messageBox "No object is selected. Bailing out."
|
|
return false
|
|
)
|
|
|
|
arrFace = (getFaceSelection sel[1]) as array
|
|
faceCount = arrFace.count
|
|
if classOfObj == Editable_mesh then faceCount = faceCount / 2
|
|
|
|
j = 1
|
|
for i = 1 to (faceCount) do (
|
|
|
|
|
|
if classOfObj == Editable_mesh then (
|
|
|
|
arrPairFace = #()
|
|
append arrPairFace arrFace[j]
|
|
append arrPairFace arrFace[j + 1]
|
|
texVertIndex = SimpleCalcTexIndices sel[1] arrPairFace
|
|
Flip orientation arrPairFace texVertIndex sel[1]
|
|
j = j + 2
|
|
)
|
|
else if classOfObj == Editable_poly then (
|
|
texVertIndex = SimpleCalcTexIndices sel[1] arrFace[i]
|
|
Flip orientation arrFace[i] texVertIndex sel[1]
|
|
)
|
|
)
|
|
)
|
|
|
|
--////////////////////////////////////////////////////////////
|
|
-- events
|
|
--////////////////////////////////////////////////////////////
|
|
|
|
on btnBeginExtrude pressed do (
|
|
|
|
btnBeginExtrude.enabled = false
|
|
btnEndExtrude.enabled = true
|
|
if ExtrudeBegin() == false then return false
|
|
|
|
return true
|
|
)
|
|
|
|
on btnEndExtrude pressed do (
|
|
|
|
btnBeginExtrude.enabled = true
|
|
btnEndExtrude.enabled = false
|
|
if classOfObj == Editable_mesh then (
|
|
if ExtrudeEnd() == false then return false
|
|
)
|
|
else if classOfObj == Editable_Poly then (
|
|
if ExtrudeEnd() == false then return false
|
|
)
|
|
return false
|
|
)
|
|
|
|
on btnFlipU pressed do (
|
|
|
|
if FlipPrepare 1 == false then return false
|
|
return true
|
|
)
|
|
|
|
on btnFlipV pressed do (
|
|
|
|
if FlipPrepare 0 == false then return false
|
|
return true
|
|
)
|
|
|
|
on RsModelToolExtrudeRoll rolledUp down do
|
|
(
|
|
RsSettingWrite "RsModelToolExtrudeRoll" "rollup" (not down)
|
|
)
|
|
) |