-- 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) ) )