2826 lines
85 KiB
Plaintext
Executable File
2826 lines
85 KiB
Plaintext
Executable File
/*--////////////////////////////////////////////////////////////////////////////////////////////////
|
|
Cable generator
|
|
|
|
Generate cables or wires between two points either from nought
|
|
or retrieved from an existing mesh
|
|
|
|
--////////////////////////////////////////////////////////////////////////////////////////////////*/
|
|
--filein (RsConfigGetWildWestDir() + "script/3dsmax/_common_functions/CatenaryCurve.ms")
|
|
|
|
|
|
global cableMaker
|
|
filein (RsConfigGetWildWestDir() + "script/3dsmax/Maps/LegacyCableUpgrade.ms")
|
|
filein (RsConfigGetWildWestDir() + "script/3dsMax/_config_files/Wildwest_header.ms")
|
|
|
|
--create LegacyCableUpgrade() instance
|
|
global cableUpgrade = LegacyCableUpgrade()
|
|
|
|
-- Flag to favour the creation of material presets instead of sps files in certain utility tools
|
|
global RsFavourPresetCreation = (RsProjectConfig.GetBoolParameter "Favour Material Preset Creation")
|
|
if (RsFavourPresetCreation == undefined ) then RsFavourPresetCreation = false
|
|
|
|
--//////////////////////////////////////////////////////////////////////////////////////////////
|
|
-- STRUCTS
|
|
--//////////////////////////////////////////////////////////////////////////////////////////////
|
|
struct CableConnectorsUtilStruct
|
|
(
|
|
connectionConfig = (RsConfigGetWildWestDir() + "etc/config/props/cableConnectors.xml"),
|
|
XML = dotNetObject "System.Xml.XmlDocument",
|
|
|
|
fn hashPoint3 n =
|
|
(
|
|
hash = (n.x * 73856093) as integer;
|
|
hash = bit.xor hash ((n.y * 19349663) as integer );
|
|
bit.xor hash ((n.z * 83492791) as integer );
|
|
),
|
|
|
|
|
|
fn createCableConnectorElement connectPoint prop propNode sibling:unsupplied =
|
|
(
|
|
--get the connection position relative to the prop pivot
|
|
local connectPos = connectPoint.pos - prop.pos
|
|
format "prop: % connectPos: % \n" prop connectPos
|
|
|
|
local connectName = hashPoint3 connectPos
|
|
|
|
local siblingPos = undefined
|
|
local siblingName = undefined
|
|
if(sibling != unsupplied) then
|
|
(
|
|
siblingPos = sibling.pos - prop.pos
|
|
siblingName = hashPoint3 siblingPos
|
|
)
|
|
|
|
--//////////////////////////////////////////
|
|
--Create Connector definition
|
|
--//////////////////////////////////////////
|
|
local cableConnector = XML.createElement "CableConnector"
|
|
local theName = XML.createAttribute "Name"
|
|
theName.value = connectName as String
|
|
cableConnector.setAttributeNode theName
|
|
|
|
--position
|
|
local position = XML.createElement "Position"
|
|
local xAttr = XML.createAttribute "X"
|
|
xAttr.value = connectPos.x as string
|
|
position.setAttributeNode xAttr
|
|
|
|
local yAttr = XML.createAttribute "Y"
|
|
yAttr.value = connectPos.y as string
|
|
position.setAttributeNode yAttr
|
|
|
|
local zAttr = XML.createAttribute "Z"
|
|
zAttr.value = connectPos.z as string
|
|
position.setAttributeNode zAttr
|
|
|
|
cableConnector.appendChild position
|
|
|
|
if (siblingPos != undefined) and (siblingName != undefined) then
|
|
(
|
|
local siblingElem = XML.createElement "Sibling"
|
|
siblingElem.InnerText = siblingName as String
|
|
cableConnector.appendChild siblingElem
|
|
)
|
|
|
|
--add nodes
|
|
propNode.appendChild cableConnector
|
|
),
|
|
|
|
--////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
-- Function to create the cable connector xml config used to generate the helpers on props for creating cable proxies
|
|
--////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
fn createCableAttachPointsXML =
|
|
(
|
|
--local configPath = (RsConfigGetWildWestDir() + "etc/config/props/cableConnectors.xml")
|
|
|
|
--create config
|
|
--local XML = dotNetObject "System.Xml.XmlDocument"
|
|
local declaration = XML.CreateXmlDeclaration "1.0" "utf-8" "yes"
|
|
XML.appendChild declaration
|
|
local rootElem = xml.createElement "CableConnections"
|
|
XML.appendChild rootElem
|
|
|
|
toolMode.coordsys #world
|
|
|
|
--iterate selected props
|
|
for prop in selection where superclassof prop == GeometryClass do
|
|
(
|
|
local theProp = undefined
|
|
local theNode = undefined
|
|
|
|
if (prop.children != undefined) then
|
|
(
|
|
--create the Node
|
|
local propNode = XML.createElement prop.name
|
|
|
|
for connectPoint in prop.children do
|
|
(
|
|
--ok, if this connectPoint has children then its a connector pair
|
|
if (connectPoint.children.count != 0) then
|
|
(
|
|
--this connectPoint should have a connection point pair
|
|
for item in connectPoint.children do
|
|
(
|
|
local connectors = connectPoint.children
|
|
if (item == connectors[1]) then
|
|
(
|
|
createCableConnectorElement connectors[1] prop propNode sibling:connectors[2]
|
|
)
|
|
else
|
|
(
|
|
createCableConnectorElement connectors[2] prop propNode sibling:connectors[1]
|
|
)
|
|
)
|
|
)
|
|
else --its a singular connection
|
|
(
|
|
createCableConnectorElement connectPoint prop propNode
|
|
)
|
|
)
|
|
|
|
--append to root
|
|
rootElem.appendChild propNode
|
|
)
|
|
)
|
|
|
|
--print XML.innerXML
|
|
--save the xml
|
|
--gRsPerforce.add_or_edit #(configPath) silent:false
|
|
XML.save connectionConfig
|
|
)
|
|
)
|
|
|
|
struct CableConnector
|
|
(
|
|
propName = "",
|
|
name = "",
|
|
position = [0,0,0],
|
|
sibling = ""
|
|
)
|
|
|
|
struct CablePresetsStruct
|
|
(
|
|
p4 = RsPerforce(),
|
|
presetLocation = (RsConfigGetWildWestDir()+"etc/config/maps/cableMakerPresets.ini"),
|
|
presets,
|
|
presetKeys,
|
|
presetValues,
|
|
|
|
--Load Presets
|
|
fn loadPresets =
|
|
(
|
|
/*
|
|
if p4.connected() then --sync the presets ini file
|
|
(
|
|
--get depot loc from location
|
|
depotLoc = p4.local2depot presetLocation
|
|
try
|
|
(
|
|
p4.sync depotLoc
|
|
print "Sync success!"
|
|
)
|
|
catch
|
|
(
|
|
print "Sync Fail"
|
|
messageBox "Couldn't sync cable presets"
|
|
return false
|
|
)
|
|
)
|
|
*/
|
|
--check presets file exits
|
|
if doesFileExist presetLocation then
|
|
(
|
|
presets = getINISetting presetLocation
|
|
)
|
|
else
|
|
(
|
|
messageBox "Can't load cable presets\n Check synced from perforce" title:"Error"
|
|
)
|
|
),
|
|
|
|
fn getPreset chosen =
|
|
(
|
|
presetKeys = getINISetting presetLocation chosen
|
|
presetValues = for key in presetKeys collect getINISetting presetLocation chosen key
|
|
),
|
|
|
|
on create do loadPresets()
|
|
)
|
|
cablePresets = CablePresetsStruct()
|
|
|
|
--//////////////////////////////////////////////////////////////////////////////
|
|
-- Export mesh vertex
|
|
--//////////////////////////////////////////////////////////////////////////////
|
|
struct CableMeshVert
|
|
(
|
|
position,
|
|
tangency,
|
|
radius,
|
|
lineDist,
|
|
texCoordX
|
|
)
|
|
|
|
--//////////////////////////////////////////////////////////////////////////////
|
|
-- Cable setup
|
|
--//////////////////////////////////////////////////////////////////////////////
|
|
struct CableMakerStruct
|
|
(
|
|
slackAttr = undefined,
|
|
weight = undefined,
|
|
weightVariance = undefined,
|
|
line = undefined,
|
|
numSegs = undefined,
|
|
|
|
DEBUGMESH = true,
|
|
|
|
meshPoints = #(),
|
|
tangentVecs = #(),
|
|
radius = 0.01, --metres
|
|
abrv = undefined,
|
|
cableColour = orange,
|
|
|
|
cable = undefined,
|
|
cableStartEndNodes = undefined,
|
|
cableTexturePath = (RsConfigGetTextureSourceDir() + "testbed/cable.tga"),
|
|
cableShader = undefined,
|
|
cableTextSize = 1,
|
|
startNode = undefined,
|
|
endNode = undefined,
|
|
connectionConfig = (RsConfigGetWildWestDir() + "etc/config/props/cableConnectors.xml"),
|
|
cableConnectors = #(),
|
|
availableContainers = #(),
|
|
UIHandle = undefined,
|
|
legacyMode = false,
|
|
|
|
|
|
fn createCableAttachPointsXML =
|
|
(
|
|
local ccs = CableConnectorsUtilStruct()
|
|
ccs.createCableAttachPointsXML()
|
|
),
|
|
|
|
--//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
--
|
|
--//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
fn addToContainer items =
|
|
(
|
|
local selContainer = UIHandle.ddlContainers.selected
|
|
|
|
--check against scene container to make sure its there
|
|
local sceneContainerNames = for o in $objects where classOf o == Container collect o.name
|
|
|
|
if findItem sceneContainerNames selContainer == 0 then
|
|
(
|
|
MessageBox "Can't find the container chosen in the list, \n in the current scene" title:"Error"
|
|
)
|
|
else
|
|
(
|
|
--clean the continer array
|
|
local tempArray = for c in availableContainers where isValidNode c collect c
|
|
local containerNames = for c in tempArray collect c.name
|
|
if findItem containerNames selContainer == 0 then
|
|
--notify that theres a mismatch if we got different count
|
|
(
|
|
messagebox "The chosen container doesnt exist anymore, delete the cable and try again,\n or add to a container manually"
|
|
return false
|
|
)
|
|
availableContainers = tempArray
|
|
|
|
local theContainer = (for c in availableContainers where (isValidNode c) == true and c.name == selContainer collect c)[1]
|
|
if theContainer != undefined then
|
|
(
|
|
success = theContainer.AddNodesToContent &items
|
|
|
|
if not success then
|
|
(
|
|
format "oh dear :(\n"
|
|
MessageBox "Failed to add the cable to the chosen container\n" title:"Error"
|
|
)
|
|
)
|
|
)
|
|
|
|
),
|
|
|
|
--//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
-- Loads the cable connector xml config generated by createCableAttachPointsXML()
|
|
--//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
fn loadCableConnectorConfig =
|
|
(
|
|
if doesFileExist connectionConfig == false then
|
|
(
|
|
messagebox "Missing the cableConnectors.xml file"
|
|
return false
|
|
)
|
|
|
|
local XML = dotNetObject "System.Xml.XmlDocument"
|
|
XML.load connectionConfig
|
|
|
|
local root = XML.SelectSingleNode "CableConnections"
|
|
local propNodes = root.childNodes
|
|
|
|
--read the props
|
|
for i = 0 to (propNodes.count - 1) do
|
|
(
|
|
local thisPropNode = propNodes.Item[i]
|
|
local thisPropName = thisPropNode.name
|
|
local connectors = #()
|
|
|
|
--get the CableConnector nodes
|
|
local cableConnectorNodes = thisPropNode.childNodes
|
|
for i=0 to (cableConnectorNodes.count - 1) do
|
|
(
|
|
local currentNode = cableConnectorNodes.item[i]
|
|
|
|
--get the child nodes
|
|
local cableConnectorKids = currentNode.childNodes
|
|
local positionVal = undefined
|
|
local siblingVal = undefined
|
|
|
|
local connector = CableConnector()
|
|
connector.propName = thisPropName
|
|
connector.name = currentNode.getAttribute "Name"
|
|
|
|
for n=0 to (cableConnectorKids.count - 1) do
|
|
(
|
|
local dataNode = cableConnectorKids.item[n]
|
|
|
|
--print dataNode.name
|
|
case dataNode.name of
|
|
(
|
|
"Position":
|
|
(
|
|
connector.position = [(dataNode.getAttribute "X") as Float, (dataNode.getAttribute "Y") as Float, (dataNode.getAttribute "Z") as Float]
|
|
)
|
|
|
|
"Sibling":
|
|
(
|
|
connector.sibling = dataNode.innerText
|
|
)
|
|
)
|
|
)
|
|
|
|
append connectors connector
|
|
)
|
|
|
|
--get the positions
|
|
--local posNodes = thisPropNode.selectNodes "./CableConnector/Position"
|
|
|
|
-- local posValues = for p = 0 to (posNodes.count - 1) collect
|
|
-- (
|
|
-- [(posNodes.ItemOf[p].getAttribute "X") as Float, (posNodes.ItemOf[p].getAttribute "Y") as Float, (posNodes.ItemOf[p].getAttribute "Z") as Float]
|
|
-- )
|
|
|
|
--append cableConnectors (DataPair prop:thisPropName connectionPoints:posValues)
|
|
|
|
append cableConnectors (DataPair prop:thisPropName connectionPoints:connectors)
|
|
)
|
|
),
|
|
|
|
--/////////////////////////////////////////////////////////////////////////////
|
|
-- Populate list with current scene containers
|
|
--/////////////////////////////////////////////////////////////////////////////
|
|
fn getAvailableContainers =
|
|
(
|
|
availableContainers = for o in objects where classOf o == Container collect o
|
|
),
|
|
|
|
--///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
-- Check the continer chosen in the UI still exists in the scene
|
|
--///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
fn checkContainerExists =
|
|
(
|
|
--Check if there is any containers in the scene first
|
|
if (getAvailableContainers()).count == 0 then return true
|
|
local selContainer = UIHandle.ddlContainers.selected
|
|
local tempArray = for c in availableContainers where isValidNode c collect c
|
|
local containerNames = for c in tempArray collect c.name
|
|
|
|
if findItem containerNames selContainer == 0 then
|
|
--notify that theres a mismatch if we got different count
|
|
(
|
|
messagebox "The chosen container doesnt exist anymore, choose again\n"
|
|
getAvailableContainers()
|
|
UIHandle.ddlContainers.items = for c in availableContainers collect c.name
|
|
return false
|
|
)
|
|
|
|
|
|
return true
|
|
),
|
|
|
|
--/////////////////////////////////////////////////////////////////////////////
|
|
--
|
|
--/////////////////////////////////////////////////////////////////////////////
|
|
fn discoverCableStartEndNodes cable =
|
|
(
|
|
startEndNodes = for c in cable.children where (classOf c) == text collect c.children
|
|
startNode = startEndNodes[1]
|
|
endNode = startEndNodes[2]
|
|
),
|
|
|
|
--/////////////////////////////////////////////////////////////////////////////
|
|
--
|
|
--/////////////////////////////////////////////////////////////////////////////
|
|
fn getEdgeLength theMesh theEdge =
|
|
(
|
|
--verts from edge
|
|
verts = (polyOp.getVertsUsingEdge theMesh theEdge) as array
|
|
edgeLength = distance (polyOp.getvert theMesh verts[1]) (polyOp.getvert theMesh verts[2])
|
|
),
|
|
|
|
--/////////////////////////////////////////////////////////////////////////////
|
|
--
|
|
--/////////////////////////////////////////////////////////////////////////////
|
|
fn getVectorFromEdge theMesh theEdge =
|
|
(
|
|
verts = (polyOp.getVertsUsingEdge theMesh theEdge) as array
|
|
vec = normalize((polyOp.getvert theMesh verts[1]) - (polyOp.getvert theMesh verts[2]))
|
|
),
|
|
|
|
--/////////////////////////////////////////////////////////////////////////////
|
|
--
|
|
--/////////////////////////////////////////////////////////////////////////////
|
|
fn getVectorFromVerts theMesh vert1 vert2 =
|
|
(
|
|
out = undefined
|
|
|
|
if (classOf theMesh) == Editable_Mesh then
|
|
(
|
|
out = normalize ((meshOp.getvert theMesh vert1) - (meshOp.getvert theMesh vert2))
|
|
)
|
|
else
|
|
(
|
|
out = normalize ((polyOp.getvert theMesh vert1) - (polyOp.getvert theMesh vert2))
|
|
)
|
|
|
|
out
|
|
),
|
|
|
|
--/////////////////////////////////////////////////////////////////////////////
|
|
-- Set the cable mesh GTA Attributes
|
|
--/////////////////////////////////////////////////////////////////////////////
|
|
fn fixCableGtaAttrs cableMesh =
|
|
(
|
|
--export degenerate Polys
|
|
attrIdx = GetAttrIndex "Gta Object" "Remove Degenerate Polys"
|
|
setAttr cableMesh attrIdx false
|
|
|
|
--weld mesh
|
|
attrIdx = GetAttrIndex "Gta Object" "Weld Mesh"
|
|
setAttr cableMesh attrIdx true
|
|
|
|
--set txd name
|
|
attrIdx = GetAttrIndex "Gta Object" "TXD"
|
|
setAttr cableMesh attrIdx "cablemesh"
|
|
|
|
--set appdata on mesh to mark it out as a cable
|
|
setAppData cableMesh 1 "cableMesh"
|
|
),
|
|
|
|
--/////////////////////////////////////////////////////////////////////////////
|
|
--
|
|
--/////////////////////////////////////////////////////////////////////////////
|
|
fn fixMergedCableNormals theMesh:undefined =
|
|
(
|
|
coordsys #world
|
|
undo off
|
|
--with redraw off
|
|
--(
|
|
with undo off
|
|
(
|
|
--print "FIX MERGER NORMALS"
|
|
if theMesh == undefined then
|
|
(
|
|
theMesh = selection[1]
|
|
)
|
|
|
|
--resetXForm of theMesh
|
|
ResetXForm theMesh
|
|
collapseStack theMesh
|
|
|
|
local theTriMesh = snapshotasmesh theMesh
|
|
|
|
--get element verts
|
|
elemFaces = ::cableUpgrade.getSubElements theMesh
|
|
--print elemFaces
|
|
elemVerts = #()
|
|
theCopy = snapshotasmesh theMesh
|
|
for elem in elemFaces do
|
|
(
|
|
--format "elem: % \n" elem
|
|
faceVerts = #()
|
|
--
|
|
--convertToMesh theCopy
|
|
for f in (elem as array) do join faceVerts (meshOp.getVertsUsingFace theCopy f) as array
|
|
--delete theCopy
|
|
faceVertsTemp = makeUniqueArray faceVerts
|
|
faceVerts = #()
|
|
|
|
--find the pairs and order them as such
|
|
for v=1 to faceVertsTemp.count do
|
|
(
|
|
for x=1 to faceVertsTemp.count do
|
|
(
|
|
if v != x and (findItem faceVerts faceVertsTemp[x]) == 0 then
|
|
(
|
|
if distance (getVert theCopy faceVertsTemp[x]) (getVert theCopy faceVertsTemp[v]) < 0.00001 then
|
|
(
|
|
append faceVerts faceVertsTemp[v]
|
|
append faceVerts faceVertsTemp[x]
|
|
)
|
|
)
|
|
)
|
|
)
|
|
|
|
--add the verts for this element to the master array
|
|
append elemVerts faceVerts
|
|
)
|
|
|
|
--setup normal mod
|
|
normalMod = Edit_Normals()
|
|
addModifier theMesh normalMod
|
|
normalMod.MakeExplicit()
|
|
--Short the name for easier reading
|
|
normalMod = theMesh.modifiers[#Edit_Normals]
|
|
|
|
--Make sure were in modify mode and the current edit_normals modifier is set
|
|
max modify mode
|
|
modPanel.setCurrentObject normalMod
|
|
|
|
--generate new normals
|
|
newNormals = #()
|
|
for verts in elemVerts do
|
|
(
|
|
newNormals = #()
|
|
|
|
--head
|
|
--check for inconsistent vert indexes producing bad normals
|
|
headNormal = getVectorFromVerts theMesh verts[3] verts[1]
|
|
--format "headNormal: % \n" headNormal
|
|
if headNormal == [1, 0 ,0] then
|
|
(
|
|
headNormal = getVectorFromVerts theMesh verts[2] verts[3]
|
|
--format "headNormal: % \n" headNormal
|
|
append newNormals headNormal
|
|
append newNormals headNormal
|
|
)
|
|
else
|
|
(
|
|
append newNormals headNormal
|
|
append newNormals headNormal
|
|
)
|
|
|
|
--body
|
|
for v = 3 to (verts.count - 2) do
|
|
(
|
|
--get vec behind
|
|
behindVec = getVectorFromVerts theMesh verts[v] verts[v-2]
|
|
|
|
if behindVec == [1, 0 ,0] then behindVec = getVectorFromVerts theMesh verts[v] verts[v-1]
|
|
--get vec in front
|
|
frontVec = getVectorFromVerts theMesh verts[v+2] verts[v]
|
|
|
|
if frontVec == [1, 0 ,0] then frontVec = getVectorFromVerts theMesh verts[v+1] verts[v]
|
|
--add and normalize
|
|
append newNormals (normalize(frontVec+behindVec))
|
|
|
|
|
|
)
|
|
|
|
--tail
|
|
append newNormals ( getVectorFromVerts theMesh verts[verts.count] verts[verts.count-2] )
|
|
append newNormals ( getVectorFromVerts theMesh verts[verts.count-1] verts[verts.count-3] )
|
|
|
|
--apply newNormals
|
|
|
|
for v = 1 to verts.count do
|
|
(
|
|
--get vertex normals from vertex id
|
|
local vtx = #{verts[v]}
|
|
local normals = #{}
|
|
|
|
normalMod.EditNormalsMod.ConvertVertexSelection &vtx &normals
|
|
normals = normals as array
|
|
--format "vtx: % normals: % \n" vtx normals
|
|
|
|
--set them to tangency
|
|
for n = 1 to normals.count do
|
|
(
|
|
--format "Tangent: % \n" meshPoints[v].tangency
|
|
normalMod.SetNormalExplicit normals[n]
|
|
normalMod.SetNormal normals[n] newNormals[v]
|
|
)
|
|
)
|
|
)
|
|
|
|
collapseStack theMesh
|
|
|
|
--fix the gta attrs
|
|
fixCableGtaAttrs theMesh
|
|
)
|
|
),
|
|
|
|
--/////////////////////////////////////////////////////////////////////////////
|
|
-- Validate the curve looking for any null values -1.#IND
|
|
--/////////////////////////////////////////////////////////////////////////////
|
|
fn validateCurve startPos endPos numSegs =
|
|
(
|
|
--generate points
|
|
catenaryCurve.slack = 0.03
|
|
catenaryCurve.simulateHangingWire startPos endPos numSegs
|
|
--format "start: % end: % segs: % \n" startPos endPos numSegs
|
|
--trawl the points looking for invalid values
|
|
--return false on the first bad one
|
|
--print "----------"
|
|
--print catenaryCurve.points
|
|
--print "----------"
|
|
for pnt in catenaryCurve.points do
|
|
(
|
|
--print pnt
|
|
if (pnt.z as String) == "-1.#IND" then
|
|
(
|
|
messageBox "Invalid curve generated\nTry moving the start or end slightly in the Z and try again." title:"Invalid Curve"
|
|
return false
|
|
)
|
|
)
|
|
|
|
return true
|
|
),
|
|
|
|
--//////////////////////////////////////////////////////////////////////////////--//////////////////////////////////////////////////////////////////////////////
|
|
--Create cable connector helpers at locations defined in the cable connectors xml config
|
|
--//////////////////////////////////////////////////////////////////////////////--//////////////////////////////////////////////////////////////////////////////
|
|
fn createPropCableConnectors =
|
|
(
|
|
local selected = getCurrentSelection()
|
|
|
|
--get the props out of the selection
|
|
local props = for obj in selected where classOf obj == RSrefObject collect obj
|
|
|
|
--create cables connectors for known props
|
|
local connectionList = #()
|
|
for prop in props do
|
|
(
|
|
--match with cable connectors definition?
|
|
local connections = (for def in cableConnectors where def.prop == prop.objectName collect def.connectionPoints)[1]
|
|
append connectionList connections
|
|
)
|
|
|
|
--create the cable connection helpers
|
|
for p = 1 to connectionList.count do
|
|
(
|
|
local aConnectors = #()
|
|
local thisProp = connectionList[p]
|
|
local propTM = props[p].transform
|
|
|
|
for c = 1 to thisProp.count do
|
|
(
|
|
local thisPropPos = props[p].position + thisProp[c]
|
|
|
|
--format "connection: % \n" thisPropPos
|
|
local connector = Point pos:thisPropPos name:(props[p].objectName + "_CableConnector") constantscreensize:true wirecolor:(color 225 88 199)
|
|
append aConnectors connector
|
|
)
|
|
|
|
--transform by linking etc
|
|
props[p].transform = matrix3 [1, 0, 0] [0, 1, 0] [0, 0, 1] propTM.translation
|
|
|
|
--link helpers to the prop
|
|
for cabcon in aConnectors do cabcon.parent = props[p]
|
|
|
|
--reapply transform
|
|
props[p].transform = propTM
|
|
|
|
--unlink helpers
|
|
for cabcon in aConnectors do cabcon.parent = undefined
|
|
)
|
|
),
|
|
|
|
|
|
--//////////////////////////////////////////////////////////////////////////////
|
|
--Create an artist adjustable cable representation
|
|
--//////////////////////////////////////////////////////////////////////////////
|
|
fn createCableProxy startNode endNode numSegs inSlack:0.003 =
|
|
(
|
|
--check container exists to add to
|
|
local success = checkContainerExists()
|
|
if not success then return false
|
|
|
|
--set catenaary curve slack
|
|
catenaryCurve.slack = inSlack
|
|
|
|
local cable = CableProxy()
|
|
|
|
cable.startNode = startNode
|
|
cable.endNode = endNode
|
|
cable.pntCount = numSegs + 1
|
|
cable.slack = inSlack
|
|
|
|
--return the cable
|
|
cable
|
|
),
|
|
|
|
|
|
--//////////////////////////////////////////////////////////////////////////////
|
|
--Create cables between props automatically
|
|
--//////////////////////////////////////////////////////////////////////////////
|
|
fn AutoGenPropCables propSel =
|
|
(
|
|
clearListener()
|
|
|
|
--use the first one and collect any in the selection that are of the same type
|
|
local firstProp = propSel[1].objectName
|
|
|
|
undo "Create Cables" on
|
|
(
|
|
--get the cable connectors for this type
|
|
local connections = (for def in cableConnectors where (def.prop == firstProp) collect def.connectionPoints)[1]
|
|
if (connections == undefined) then
|
|
(
|
|
messagebox ("no connections defined for this prop type\n" + firstProp) title:"Connections missing"
|
|
return false
|
|
)
|
|
|
|
local slackMin = CableGenerationUI.spnMinSlack.value
|
|
local slackMax = CableGenerationUI.spnMaxSlack.value
|
|
|
|
local createdCables = #()
|
|
|
|
--while we are not 1 away from the end connect the matching connector name between this and the next prop in the list
|
|
for i=1 to (propSel.count - 1) do
|
|
(
|
|
local currentProp = propSel[i]
|
|
local currentPropTM = currentProp.transform
|
|
|
|
local nextProp = propSel[i+1]
|
|
local nextPropTM = nextProp.transform
|
|
|
|
--match up connections between current and next prop
|
|
|
|
for cnx in connections do
|
|
(
|
|
--check if it has a sibling paring.
|
|
--if it has then check we are not trying to connect back past its sibling
|
|
--hopefully this way we can we dont get any crossover connections
|
|
local ignore = false
|
|
|
|
|
|
--get the sibling position if this connector has one
|
|
local siblingPos = undefined
|
|
if (cnx.sibling != undefined) then
|
|
(
|
|
siblingPos = (for item in connections where (item.name == cnx.sibling) collect item.position)[1]
|
|
)
|
|
|
|
|
|
local currentPropPos = currentProp.position + cnx.position
|
|
|
|
--if there is a closer sibling then ignore this cable
|
|
if (siblingPos != undefined) then
|
|
(
|
|
--if it has a closer sibling to the next prop then ignore = true and dont make a cable
|
|
if (distance currentPropPos nextProp.position) < (distance (currentProp.position + siblingPos) nextProp.position) then
|
|
(
|
|
--print "Closer Sibling connector ignoring"
|
|
ignore = true
|
|
)
|
|
)
|
|
|
|
local nextPropPos = if (siblingPos != undefined) then
|
|
(
|
|
nextProp.position + siblingPos
|
|
)
|
|
else
|
|
(
|
|
nextProp.position + cnx.position
|
|
)
|
|
|
|
|
|
if not ignore then
|
|
(
|
|
local currentConnector = Point pos:currentPropPos size:5.0 constantscreensize:true wirecolor:(color 0 255 0) \
|
|
name:"CableStart"
|
|
local nextConnector = Point pos:nextPropPos size:5.0 constantscreensize:true wirecolor:(color 255 0 0) \
|
|
name:"CableEnd"
|
|
|
|
local cable = CableProxy()
|
|
append createdCables cable
|
|
|
|
cable.startNode = currentConnector
|
|
cable.endNode = nextConnector
|
|
cable.pntCount = 10 + 1
|
|
cable.slack = (random slackMin slackMax)
|
|
|
|
cable.points = genCablePoints currentConnector nextConnector 10
|
|
cable.uid = genGuid()
|
|
|
|
cable.editing = true
|
|
|
|
currentProp.transform = matrix3 [1, 0, 0] [0, 1, 0] [0, 0, 1] currentPropTM.translation
|
|
nextProp.transform = matrix3 [1, 0, 0] [0, 1, 0] [0, 0, 1] nextPropTM.translation
|
|
|
|
currentConnector.parent = currentProp
|
|
nextConnector.parent = nextProp
|
|
|
|
currentProp.transform = currentPropTM
|
|
nextProp.transform = nextPropTM
|
|
)
|
|
)
|
|
)
|
|
|
|
--add all the cables to the container
|
|
addToContainer createdCables
|
|
)
|
|
),
|
|
|
|
|
|
--//////////////////////////////////////////////////////////////////////////////
|
|
-- Point to Line distance
|
|
--//////////////////////////////////////////////////////////////////////////////
|
|
fn pointLineDist2 pA pB pC =
|
|
(
|
|
local vAB=pB-pA
|
|
local vAC=pC-pA
|
|
(length (cross vAB vAC))/(length vAB)
|
|
),
|
|
|
|
--/////////////////////////////////////////////////////////////////////////////
|
|
--
|
|
--/////////////////////////////////////////////////////////////////////////////
|
|
fn meshReport theCable =
|
|
(
|
|
format "--------------- MESH REPORT ----------------\n"
|
|
--report the vert positions
|
|
aVtxPos = #()
|
|
for vtx = 1 to getnumverts theCable do
|
|
(
|
|
pos = meshop.getVert theCable vtx
|
|
append aVtxPos pos
|
|
--format "vtx: % pos: %\n" vtx pos
|
|
)
|
|
|
|
|
|
--normals
|
|
aNormals = #()
|
|
|
|
--Create the mod and apply
|
|
normalMod = Edit_Normals()
|
|
addModifier theCable normalMod
|
|
normalMod.MakeExplicit()
|
|
--Short the name for easier reading
|
|
normalMod = theCable.modifiers[#Edit_Normals]
|
|
|
|
--Make sure were in modify mode and the current edit_normals modifier is set
|
|
max modify mode
|
|
modPanel.setCurrentObject normalMod
|
|
|
|
for vtx = 1 to getnumverts theCable do
|
|
(
|
|
for v = 1 to theCable.numVerts do
|
|
(
|
|
nrmlVal = normalMod.EditNormalsMod.GetNormal v
|
|
append aNormals nrmlVal
|
|
)
|
|
)
|
|
|
|
|
|
--report the uv maps1 values
|
|
aTverts = #()
|
|
for tv = 1 to getNumTVerts theCable do
|
|
(
|
|
append aTverts (getTVert theCable tv)
|
|
--format "tvert: % value: %\n" tv (getTVert theCable tv)
|
|
|
|
)
|
|
|
|
--report the vertex color values
|
|
aVtxCols = #()
|
|
for cpv = 1 to (getNumCPVVerts theCable) do
|
|
(
|
|
append aVtxCols (getVertColor theCable cpv)
|
|
--format "vtx: % colour: %\n" cpv (getVertColor theCable cpv)
|
|
)
|
|
|
|
for i = 1 to getnumverts theCable do
|
|
(
|
|
|
|
format "vtx: % Pos: % Normal: % UV: % CPV: %\n" i aVtxPos[i] aNormals[i] aTverts[i] aVtxCols[i]
|
|
)
|
|
format "--------------- MESH REPORT ----------------\n"
|
|
),
|
|
|
|
fn getCableMaterialShaderName =
|
|
(
|
|
if RsFavourPresetCreation then
|
|
"templates/cable.mpt"
|
|
else
|
|
"cable.sps"
|
|
),
|
|
|
|
--/////////////////////////////////////////////////////////////////////////////
|
|
--
|
|
--/////////////////////////////////////////////////////////////////////////////
|
|
fn createCableMaterial =
|
|
(
|
|
local cableShaderName = getCableMaterialShaderName()
|
|
--lets check if a cable material exists in the scene alreadythen we can cut down no dupes
|
|
local cableMaterials = for mat in sceneMaterials where classOf m == Rage_Shader and RstGetShaderName mat == cableShaderName collect mat
|
|
if cableMaterials.count != 0 then
|
|
(
|
|
cableShader = cableMaterials[1]
|
|
return false
|
|
)
|
|
|
|
cableShader = Rage_Shader()
|
|
cableShader.name = "CableMaterial"
|
|
RstSetShaderName cableShader cableShaderName
|
|
|
|
--assign to the mat
|
|
RstSetVariable cableShader 1 cableTexturePath
|
|
|
|
------------------------------------
|
|
--assign colours from UI
|
|
------------------------------------
|
|
--get shader param indices
|
|
local diffuseIdx = 0
|
|
local diffuse2Idx = 0
|
|
local ambientIdx = 0
|
|
local emissiveIdx = 0
|
|
|
|
for i=1 to (RstGetVariableCount cableShader) do
|
|
(
|
|
case (RstGetVariableName cableShader i) of
|
|
(
|
|
"Diffuse":
|
|
(
|
|
local colour = 0.00392157 * (UIHandle.cprDiffOne.color as Point3) --normalized Point3 colour
|
|
RstSetVariable cableShader i colour
|
|
)
|
|
"Diffuse2":
|
|
(
|
|
local colour = 0.00392157 * (UIHandle.cprDiffTwo.color as Point3) --normalized Point3 colour
|
|
RstSetVariable cableShader i colour
|
|
)
|
|
"Ambient":
|
|
(
|
|
local ambientNatural = UIHandle.spnAmbientNatural.value
|
|
local ambientArtificial = UIHandle.spnAmbientArtificial.value
|
|
RstSetVariable cableShader i [ambientNatural, ambientArtificial]
|
|
)
|
|
"Emissive" : RstSetVariable cableShader i UIHandle.spnEmissive.value
|
|
)
|
|
)
|
|
),
|
|
|
|
--//////////////////////////////////////////////////////////////////////////////
|
|
-- Create an export mesh from the proxy representation.
|
|
--//////////////////////////////////////////////////////////////////////////////
|
|
|
|
/* NOTES
|
|
|
|
struct vertexInput
|
|
{
|
|
float3 pos : POSITION;
|
|
float3 tan : NORMAL; // tangent
|
|
float4 col : COLOR0; // xy=phase, z=texcoord.x, w=unused
|
|
float2 r_d : TEXCOORD0;
|
|
};
|
|
|
|
that's what it expects the mesh to contain
|
|
|
|
i haven't hooked up the micromovements yet so the phase xy can be 0, but the
|
|
|
|
texcoord.x (stored in the COLOR blue channel) should go 0 to 255 along the length of the wire
|
|
|
|
r_d (stored in TEXCOORD0) should contain the radius in the x component and the distance to line in the y component
|
|
actually y is really "distance to line times micromovement amplitude scale" .. and can be 0 for now
|
|
|
|
*/
|
|
fn createCableMesh cable startPos endPos numSegs =
|
|
(
|
|
--check container exists to add to
|
|
local success = checkContainerExists()
|
|
if not success then return false
|
|
|
|
local cableClass = classOf cable
|
|
|
|
--check if theres a mesh already and prompt to replace it or not
|
|
local cableMeshes = #()
|
|
case cableClass of
|
|
(
|
|
cableProxy:
|
|
(
|
|
cableMeshes = for o in objects where (superClassOf o == GeometryClass) and ((getAppData o 1) != undefined) and ((getAppData o 2) != undefined) and ((getAppData o 2) == cable.uid) collect o
|
|
)
|
|
|
|
SplineShape:
|
|
(
|
|
cableMeshes = for o in objects where (superClassOf o == GeometryClass) and ((getAppData o 1) != undefined) and ((getAppData o 2) != undefined) and ((getAppData o 2) as IntegerPtr == cable.handle) collect o
|
|
)
|
|
|
|
)
|
|
|
|
if cableMeshes.count == 1 and (not legacyMode) then --we have a mesh
|
|
(
|
|
--if it exists ask if user wants to replace
|
|
answer = queryBox "This cable already has a mesh\n\nYou want to replace it?" title:"Replace cable mesh"
|
|
|
|
if answer == true then --delete the old mesh
|
|
(
|
|
delete cablemeshes[1]
|
|
)
|
|
else --no dont delete the old one, we'll skip out for now
|
|
(
|
|
return false
|
|
)
|
|
)
|
|
|
|
|
|
--use selected cable spline
|
|
--sel = $selection[1]
|
|
--if classOf sel != Editable_Spline then return false
|
|
|
|
--***********************************
|
|
--Generate the catenary curve
|
|
--***********************************
|
|
|
|
--if the ui opt 'TAUT' is set then set slack to very low to make a taut cable mesh
|
|
taut = UIHandle.chkTaut.checked
|
|
if taut == true then
|
|
(
|
|
catenaryCurve.slack = 0.00000001
|
|
cable.slack = 0.00000001
|
|
)
|
|
--catenaryCurve.slack =
|
|
catenaryCurve.simulateHangingWire startPos endPos numSegs
|
|
|
|
--generate tangent vector array
|
|
local curvePointsCount = catenaryCurve.points.count
|
|
tangentVecs = #()
|
|
|
|
--first tangent
|
|
append tangentVecs ( normalize(catenaryCurve.points[2] - catenaryCurve.points[1]))
|
|
--middle
|
|
--0.5 * ((n � n-1) + (n+1 � n))
|
|
for p=2 to (curvePointsCount - 1) do
|
|
(
|
|
append tangentVecs ( normalize(catenaryCurve.points[p+1] - catenaryCurve.points[p-1]))
|
|
)
|
|
|
|
--add the last tangent
|
|
append tangentVecs ( normalize(catenaryCurve.points[curvePointsCount] - catenaryCurve.points[curvePointsCount - 1]))
|
|
|
|
--------------------------------
|
|
-- Generate Mesh Data
|
|
--------------------------------
|
|
--start of mesh
|
|
|
|
--get first point
|
|
firstPoint = CableMeshVert()
|
|
firstPoint.position = startPos
|
|
firstPoint.tangency = tangentVecs[1]
|
|
firstPoint.radius = -radius -- neg radius
|
|
firstPoint.lineDist = 1.0
|
|
firstPoint.texCoordX = 0
|
|
append meshPoints firstPoint
|
|
|
|
firstPoint = undefined
|
|
|
|
--now another but radius opposite
|
|
firstPoint = CableMeshVert()
|
|
firstPoint.position = startPos
|
|
firstPoint.tangency = tangentVecs[1]
|
|
firstPoint.lineDist = 1.0
|
|
firstPoint.texCoordX = 0
|
|
firstPoint.radius = radius -- pos radius
|
|
append meshPoints firstPoint
|
|
|
|
--Now for the cat points
|
|
pointCount = catenaryCurve.points.count
|
|
normPointCount = 1.0 / pointCount
|
|
|
|
--iterate the catenary curve creating points as we go
|
|
for p = 1 to pointCount do
|
|
(
|
|
--make 2 mesh points for each position to create faces
|
|
local pos = catenaryCurve.points[p]
|
|
--local tangency = lengthTangent cable (p * normPointCount) --lerp
|
|
local lineDist = (pointLineDist2 startPos endPos pos)
|
|
|
|
--point1
|
|
local catPoint = CableMeshVert()
|
|
catPoint.position = pos
|
|
catPoint.tangency = tangentVecs[p]
|
|
--neg radius first
|
|
catPoint.radius = -radius
|
|
catPoint.lineDist = 1.0 - lineDist
|
|
if taut == true then catPoint.lineDist = 1.0
|
|
catPoint.texCoordX = (p * (255.0 / pointCount)) as Integer
|
|
append meshPoints catPoint
|
|
|
|
catPoint = undefined
|
|
--point2
|
|
local catPoint = CableMeshVert()
|
|
catPoint.position = pos
|
|
catPoint.tangency = tangentVecs[p]
|
|
--pos radius second
|
|
catPoint.radius = radius
|
|
catPoint.lineDist = 1.0 - lineDist
|
|
if taut == true then catPoint.lineDist = 1.0
|
|
catPoint.texCoordX = (p * (255.0 / pointCount)) as Integer
|
|
append meshPoints catPoint
|
|
)
|
|
--------------------------------
|
|
-- /Generate Mesh Data
|
|
--------------------------------
|
|
|
|
|
|
--------------------------------
|
|
--Generate Mesh
|
|
--------------------------------
|
|
--tverts are currently broken so have to work around
|
|
meshVertices = for cmv in meshPoints collect cmv.position
|
|
--format "Vert Positions: % \n" meshVertices
|
|
|
|
--work out the meshFaces leave out first and last verts
|
|
meshFaces = #()
|
|
matIDs = #()
|
|
meshTVertices = #()
|
|
for p = 1 to (meshVertices.count - 2) do
|
|
(
|
|
if (mod p 2) == 0 then
|
|
(
|
|
append meshFaces [p, p+1, p+2]
|
|
--format "face: % indices: %\n" p [p, p+1, p+2]
|
|
)
|
|
else
|
|
(
|
|
append meshFaces [p, p+2, p+1]
|
|
--format "face: % indices: %\n" p [p, p+2, p+1]
|
|
)
|
|
append matIDs 1
|
|
)
|
|
|
|
--texture verts will hold extra info -
|
|
--meshTVert_tangent = for p = 2 to (meshPoints.count - 1) collect meshPoints[p].tangency
|
|
|
|
--textureverts for [radius, linedist, unused]
|
|
meshTVert_rad_dist = for p = 1 to meshPoints.count collect [meshPoints[p].radius, meshPoints[p].lineDist, 0]
|
|
--format "uv: % \n" meshTVert_rad_dist
|
|
|
|
|
|
cableMesh = mesh vertices:meshVertices faces:meshFaces materialIDs:matIDs tverts:meshTVert_rad_dist
|
|
|
|
--Generate mesh name append preset abbreviation on the end
|
|
cableMesh.name = uniqueName ("CableMesh" + (cableMesh.handle as String) + "_" + abrv)
|
|
|
|
tmesh = cableMesh.mesh
|
|
buildTVFaces tmesh
|
|
for i = 1 to tmesh.numfaces do(setTVFace tmesh i (getFace tmesh i))
|
|
update cableMesh
|
|
--------------------------------
|
|
-- /Generate Mesh
|
|
--------------------------------
|
|
|
|
-----------------------------------------------------------------
|
|
--set the mesh normals to the curve tangency
|
|
-----------------------------------------------------------------
|
|
--for p = 1 to meshPoints.count do format "tangency: %\n" meshPoints[p].tangency
|
|
--Create the mod and apply
|
|
normalMod = Edit_Normals()
|
|
addModifier cableMesh normalMod
|
|
normalMod.MakeExplicit()
|
|
--Short the name for easier reading
|
|
normalMod = cableMesh.modifiers[#Edit_Normals]
|
|
|
|
--Make sure were in modify mode and the current edit_normals modifier is set
|
|
max modify mode
|
|
modPanel.setCurrentObject normalMod
|
|
|
|
|
|
for v = 1 to cableMesh.numVerts do
|
|
(
|
|
--get vertex normals from vertex id
|
|
local vtx = #{v}
|
|
local normals = #{}
|
|
|
|
normalMod.EditNormalsMod.ConvertVertexSelection &vtx &normals
|
|
normals = normals as array
|
|
--format "vtx: % normals: % \n" vtx normals
|
|
|
|
--set them to tangency
|
|
for n = 1 to normals.count do
|
|
(
|
|
--format "Tangent: % \n" meshPoints[v].tangency
|
|
normalMod.SetNormalExplicit normals[n]
|
|
normalMod.SetNormal normals[n] meshPoints[v].tangency
|
|
)
|
|
|
|
)
|
|
|
|
|
|
collapseStack cableMesh
|
|
-----------------------------------------------------------------
|
|
-- /set the mesh normals to the curve tangency
|
|
-----------------------------------------------------------------
|
|
|
|
----------------------------------------------------------------------------------------------------------------
|
|
--Set the vertex BLUE colour along the length of the cable 0-255
|
|
----------------------------------------------------------------------------------------------------------------
|
|
--for p = 1 to meshPoints.count do format "TexCoordX: % \n" meshPoints[p].texCoordX
|
|
local tX = for p = 1 to meshPoints.count collect meshPoints[p].texCoordX
|
|
|
|
--Set the red and green to random values for phase along the length of the cable
|
|
redPhase = random 0 255
|
|
greenPhase = random 0 255
|
|
|
|
--setNumCPVVerts cableMesh meshPoints.count
|
|
--meshop.setNumCPVVerts cableMesh meshPoints.count
|
|
|
|
--first flush the cpv
|
|
for v = 1 to cableMesh.numVerts do
|
|
(
|
|
meshop.setVertColor cableMesh 0 v (color 0 0 0)
|
|
)
|
|
|
|
--now set it
|
|
for v = 1 to tX.count do
|
|
(
|
|
if mod v 2 == 0 then
|
|
(
|
|
meshop.setVertColor cableMesh 0 #{v} (color redPhase greenPhase tX[v-1])
|
|
)
|
|
else
|
|
(
|
|
meshop.setVertColor cableMesh 0 #{v} (color redPhase greenPhase tX[v])
|
|
)
|
|
--setVertColor cableMesh v (color 0 0 tX[v])
|
|
--setVertColor cabeMesh v+1 (color 0 0 tX[v])
|
|
)
|
|
|
|
|
|
--Apply Cable Shader
|
|
cableMaker.createCableMaterial()
|
|
cableMesh.material = cableShader
|
|
|
|
--Fix up GTA attrs
|
|
fixCableGtaAttrs cableMesh
|
|
|
|
--set appdata on mesh to link it back to its proxy cable spline
|
|
case cableClass of
|
|
(
|
|
cableProxy:
|
|
(
|
|
setAppData cableMesh 2 cable.uid
|
|
)
|
|
|
|
|
|
SplineShape:
|
|
(
|
|
setAppData cableMesh 2 (cable.handle as string)
|
|
setAppData cable 1 "CableProxy"
|
|
)
|
|
)
|
|
|
|
--centre pivot
|
|
CenterPivot cableMesh
|
|
|
|
--set the wirecolor
|
|
cableMesh.wireColor = cableColour
|
|
|
|
-- DO A MESH REPORT FOR DEBUGGING PURPOSES
|
|
--meshReport cableMesh
|
|
---------------
|
|
--clean up
|
|
---------------
|
|
meshPoints = #()
|
|
tangentVecs = #()
|
|
--remove temp spline
|
|
--delete cable
|
|
|
|
--add the cable to the selected container in the UI dropdown?
|
|
if availableContainers.count != 0 then
|
|
(
|
|
addToContainer #(cableMesh)
|
|
)
|
|
|
|
cableMesh
|
|
),
|
|
|
|
--/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
--
|
|
--/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
fn createCableMeshFromSpline theSpline numSegs =
|
|
(
|
|
--check container exists to add to
|
|
local success = checkContainerExists()
|
|
if not success then return false
|
|
|
|
--theSpline = convertToSplineShape theSpline
|
|
--check if theres a mesh already and prompt to replace it or not
|
|
|
|
--generate tangent vector array
|
|
|
|
local normPointCount = 1.0 / numSegs
|
|
local normU = 1.0 / (numSegs + 1)
|
|
|
|
tangentVecs = for pt=1 to (numSegs + 1) collect pathTangent theSpline 1 (pt * normU)
|
|
tangentVecs[1] = pathTangent theSpline 1 0.01
|
|
tangentVecs[tangentVecs.count] = pathTangent theSpline 1 0.99
|
|
--------------------------------
|
|
-- Generate Mesh Data
|
|
--------------------------------
|
|
--start of mesh
|
|
|
|
--get first point
|
|
local firstPoint = CableMeshVert()
|
|
firstPoint.position = pathInterp theSpline 1 0.0
|
|
firstPoint.tangency = tangentVecs[1]
|
|
firstPoint.radius = -radius -- neg radius
|
|
firstPoint.lineDist = 1.0
|
|
firstPoint.texCoordX = 0
|
|
append meshPoints firstPoint
|
|
|
|
firstPoint = undefined
|
|
|
|
--now another but radius opposite
|
|
firstPoint = CableMeshVert()
|
|
firstPoint.position = pathInterp theSpline 1 0.0
|
|
firstPoint.tangency = tangentVecs[1]
|
|
firstPoint.lineDist = 1.0
|
|
firstPoint.texCoordX = 0
|
|
firstPoint.radius = radius -- pos radius
|
|
append meshPoints firstPoint
|
|
|
|
--Now for the cat points
|
|
pointCount = catenaryCurve.points.count
|
|
|
|
|
|
--iterate the catenary curve creating points as we go
|
|
for p = 1 to numSegs do
|
|
(
|
|
--make 2 mesh points for each position to create faces
|
|
local pos = pathInterp theSpline 1 (p * normPointCount)
|
|
local lineDist = 0
|
|
|
|
--point1
|
|
local catPoint = CableMeshVert()
|
|
catPoint.position = pos
|
|
catPoint.tangency = tangentVecs[p+1]
|
|
--neg radius first
|
|
catPoint.radius = -radius
|
|
catPoint.lineDist = 1.0
|
|
catPoint.texCoordX = 0
|
|
append meshPoints catPoint
|
|
|
|
catPoint = undefined
|
|
--point2
|
|
local catPoint = CableMeshVert()
|
|
catPoint.position = pos
|
|
catPoint.tangency = tangentVecs[p+1]
|
|
--pos radius second
|
|
catPoint.radius = radius
|
|
catPoint.lineDist = 1.0
|
|
catPoint.texCoordX = 0
|
|
append meshPoints catPoint
|
|
)
|
|
|
|
|
|
--------------------------------
|
|
-- /Generate Mesh Data
|
|
--------------------------------
|
|
|
|
|
|
--------------------------------
|
|
--Generate Mesh
|
|
--------------------------------
|
|
--tverts are currently broken so have to work around
|
|
local meshVertices = for cmv in meshPoints collect cmv.position
|
|
--format "Vert Positions: % \n" meshVertices
|
|
|
|
--work out the meshFaces leave out first and last verts
|
|
local meshFaces = #()
|
|
local matIDs = #()
|
|
local meshTVertices = #()
|
|
for p = 1 to (meshVertices.count - 2) do
|
|
(
|
|
if (mod p 2) == 0 then
|
|
(
|
|
append meshFaces [p, p+1, p+2]
|
|
--format "face: % indices: %\n" p [p, p+1, p+2]
|
|
)
|
|
else
|
|
(
|
|
append meshFaces [p, p+2, p+1]
|
|
--format "face: % indices: %\n" p [p, p+2, p+1]
|
|
)
|
|
append matIDs 1
|
|
)
|
|
|
|
--texture verts will hold extra info -
|
|
--meshTVert_tangent = for p = 2 to (meshPoints.count - 1) collect meshPoints[p].tangency
|
|
|
|
--textureverts for [radius, linedist, unused]
|
|
local meshTVert_rad_dist = for p = 1 to meshPoints.count collect [meshPoints[p].radius, meshPoints[p].lineDist, 0]
|
|
--format "uv: % \n" meshTVert_rad_dist
|
|
|
|
|
|
local cableMesh = mesh vertices:meshVertices faces:meshFaces materialIDs:matIDs tverts:meshTVert_rad_dist
|
|
|
|
--Generate mesh name append preset abbreviation on the end
|
|
cableMesh.name = "CableMesh" + (cableMesh.handle as String) + "_" + abrv
|
|
|
|
local tmesh = cableMesh.mesh
|
|
buildTVFaces tmesh
|
|
for i = 1 to tmesh.numfaces do(setTVFace tmesh i (getFace tmesh i))
|
|
update cableMesh
|
|
--------------------------------
|
|
-- /Generate Mesh
|
|
--------------------------------
|
|
|
|
-----------------------------------------------------------------
|
|
--set the mesh normals to the curve tangency
|
|
-----------------------------------------------------------------
|
|
--for p = 1 to meshPoints.count do format "tangency: %\n" meshPoints[p].tangency
|
|
--Create the mod and apply
|
|
local normalMod = Edit_Normals()
|
|
addModifier cableMesh normalMod
|
|
normalMod.MakeExplicit()
|
|
--Short the name for easier reading
|
|
normalMod = cableMesh.modifiers[#Edit_Normals]
|
|
|
|
--Make sure were in modify mode and the current edit_normals modifier is set
|
|
max modify mode
|
|
modPanel.setCurrentObject normalMod
|
|
|
|
for v = 1 to cableMesh.numVerts do
|
|
(
|
|
--get vertex normals from vertex id
|
|
local vtx = #{v}
|
|
local normals = #{}
|
|
|
|
normalMod.EditNormalsMod.ConvertVertexSelection &vtx &normals
|
|
normals = normals as array
|
|
--format "vtx: % normals: % \n" vtx normals
|
|
|
|
--set them to tangency
|
|
for n = 1 to normals.count do
|
|
(
|
|
--format "Tangent: % \n" meshPoints[v].tangency
|
|
normalMod.SetNormalExplicit normals[n]
|
|
normalMod.SetNormal normals[n] meshPoints[v].tangency
|
|
)
|
|
|
|
)
|
|
|
|
fixMergedCableNormals theMesh:cableMesh
|
|
|
|
collapseStack cableMesh
|
|
-----------------------------------------------------------------
|
|
-- /set the mesh normals to the curve tangency
|
|
-----------------------------------------------------------------
|
|
|
|
----------------------------------------------------------------------------------------------------------------
|
|
--Set the vertex BLUE colour along the length of the cable 0-255
|
|
----------------------------------------------------------------------------------------------------------------
|
|
--for p = 1 to meshPoints.count do format "TexCoordX: % \n" meshPoints[p].texCoordX
|
|
local tX = for p = 1 to meshPoints.count collect meshPoints[p].texCoordX
|
|
|
|
--Set the red and green to random values for phase along the length of the cable
|
|
local redPhase = 0
|
|
local greenPhase = 0
|
|
|
|
--setNumCPVVerts cableMesh meshPoints.count
|
|
--meshop.setNumCPVVerts cableMesh meshPoints.count
|
|
|
|
--first flush the cpv
|
|
for v = 1 to cableMesh.numVerts do
|
|
(
|
|
meshop.setVertColor cableMesh 0 v (color 0 0 0)
|
|
)
|
|
|
|
--now set it
|
|
for v = 1 to tX.count do
|
|
(
|
|
if mod v 2 == 0 then
|
|
(
|
|
meshop.setVertColor cableMesh 0 #{v} (color redPhase greenPhase tX[v-1])
|
|
)
|
|
else
|
|
(
|
|
meshop.setVertColor cableMesh 0 #{v} (color redPhase greenPhase tX[v])
|
|
)
|
|
--setVertColor cableMesh v (color 0 0 tX[v])
|
|
--setVertColor cabeMesh v+1 (color 0 0 tX[v])
|
|
)
|
|
|
|
--Apply Cable Shader
|
|
cableMaker.createCableMaterial()
|
|
cableMesh.material = cableShader
|
|
|
|
--Fix up GTA attrs
|
|
fixCableGtaAttrs cableMesh
|
|
|
|
--set appdata on mesh to link it back to its proxy cable spline
|
|
if spline != undefined then setAppData cableMesh 2 (spline.handle as string)
|
|
|
|
--set the appdata on the spline back to "CableProxy" for id if the mesh needs to be regenerated for it
|
|
--setAppData spline 1 "CableProxy"
|
|
|
|
--Parent the mesh to the spline.
|
|
--cableMesh.parent = spline
|
|
|
|
--centre pivot
|
|
CenterPivot cableMesh
|
|
|
|
--set the wirecolor
|
|
cableMesh.wireColor = cableColour
|
|
|
|
-- DO A MESH REPORT FOR DEBUGGING PURPOSES
|
|
--meshReport cableMesh
|
|
---------------
|
|
--clean up
|
|
---------------
|
|
meshPoints = #()
|
|
tangentVecs = #()
|
|
--remove temp spline
|
|
--delete cable
|
|
|
|
--add the cable to the selected container in the UI dropdown?
|
|
if availableContainers.count != 0 then
|
|
(
|
|
addToContainer #(cableMesh)
|
|
)
|
|
|
|
cableMesh
|
|
)
|
|
|
|
|
|
)
|
|
--END STRUCT
|
|
|
|
|
|
--//////////////////////////////////////////////////////////////////////////////
|
|
-- Cable Diagnostics
|
|
--//////////////////////////////////////////////////////////////////////////////
|
|
struct VisObjCacheStruct
|
|
(
|
|
vPos = #(),
|
|
vCol = #()
|
|
)
|
|
|
|
struct CableMakerDiagnosticsStruct
|
|
(
|
|
objectSelectionList = #(),
|
|
cachedSelectionHash = #(),
|
|
visObj = undefined,
|
|
-- visObjCache = (DataPair vpos:#() vChannel:#()),
|
|
visObjCache = VisObjCacheStruct(),
|
|
visChannel,
|
|
cacheDirty = true,
|
|
|
|
--//////////////////////////////////////////////////////////////////////////////
|
|
-- Find singularities
|
|
--//////////////////////////////////////////////////////////////////////////////
|
|
fn findCoLocatedVerts obj subObjectDisplay:true =
|
|
(
|
|
local epsilon = 0.000001
|
|
local selectionList = #()
|
|
|
|
local meshPolyOpFn = RsMeshPolyOp obj
|
|
local doneVerts = #{}
|
|
|
|
local coLocatedVtx = #()
|
|
for vert in obj.verts where (not doneverts[vert.index]) do
|
|
(
|
|
local matches = 0
|
|
local coLocatedCandidates = #{}
|
|
for other in obj.verts do
|
|
(
|
|
if other.index != vert.index then
|
|
(
|
|
if (distance vert.pos other.pos) < epsilon then
|
|
(
|
|
append coLocatedCandidates other.index
|
|
matches += 1
|
|
)
|
|
)
|
|
)
|
|
|
|
if (matches > 1) do
|
|
(
|
|
append coLocatedVtx (DataPair vtx:vert.index coVtx:coLocatedCandidates)
|
|
doneVerts + coLocatedCandidates
|
|
)
|
|
)
|
|
|
|
--now test connectivity
|
|
for item in coLocatedVtx do
|
|
(
|
|
--find the element its in
|
|
local element = meshPolyOpFn.getElementsUsingFace obj (meshPolyOpFn.getFacesUsingVert obj item.vtx)
|
|
|
|
--now match against the other colocated verts
|
|
--if more than 2 match then its a problem
|
|
local matches = 0
|
|
for coVtx in item.coVtx do
|
|
(
|
|
local coVtxElem = meshPolyOpFn.getElementsUsingFace obj (meshPolyOpFn.getFacesUsingVert obj coVtx)
|
|
if ((element - coVtxElem).numberSet == 0) then matches += 1
|
|
)
|
|
|
|
if (matches > 1) then
|
|
(
|
|
append selectionList item.vtx
|
|
)
|
|
)
|
|
|
|
if selectionList.count == 0 then
|
|
(
|
|
--messagebox "Cable is clean, No singularities found"
|
|
print "Clean"
|
|
)
|
|
else
|
|
(
|
|
gRsUlog.LogError (obj.name + " has singularities")
|
|
obj.selectedVerts = selectionList
|
|
SetCommandPanelTaskMode #modify
|
|
if subObjectDisplay do
|
|
(
|
|
subobjectLevel = 1
|
|
)
|
|
)
|
|
|
|
(selectionList.count == 0)
|
|
),
|
|
|
|
--//////////////////////////////////////////////////////////////////////////////
|
|
--func to test normal deviation
|
|
--//////////////////////////////////////////////////////////////////////////////
|
|
fn isDeviantNormal vec normal =
|
|
(
|
|
local maxDev = 0.1
|
|
local deviation = 1.0 - (dot vec normal)
|
|
|
|
--return
|
|
(deviation > maxDev)
|
|
),
|
|
|
|
--//////////////////////////////////////////////////////////////////////////////
|
|
-- Find bad normals
|
|
--//////////////////////////////////////////////////////////////////////////////
|
|
fn findBadNormals obj subObjectDisplay:true =
|
|
(
|
|
local maxDev = 0.1
|
|
local selectionList = #()
|
|
|
|
local objElements = cableUpgrade.getSubElements obj
|
|
|
|
local editNormalsMod = EditNormals()
|
|
addModifier obj editNormalsMod
|
|
|
|
--go through each element
|
|
for elem in objElements do
|
|
(
|
|
local elemArray = elem as Array
|
|
|
|
--head
|
|
local vec = normalize (obj.verts[elemArray[3]].pos - obj.verts[elemArray[1]].pos)
|
|
local vtxIndex = #{1}
|
|
local vtxNormals = #{}
|
|
editNormalsMod.ConvertVertexSelection &vtxIndex &vtxNormals
|
|
local normalVec = editNormalsMod.GetNormal (vtxNormals as Array)[1]
|
|
if (isDeviantNormal vec normalVec) then
|
|
(
|
|
append selectionList elemArray[1]
|
|
)
|
|
|
|
--body
|
|
for vtx=3 to (elemArray.count - 2) do
|
|
(
|
|
--use 2 verts to get a vector
|
|
local vec = normalize(obj.verts[elemArray[vtx+2]].pos - obj.verts[elemArray[vtx-2]].pos)
|
|
|
|
--get the normal for the vertex
|
|
local vtxIndex = #{vtx}
|
|
local vtxNormals = #{}
|
|
editNormalsMod.ConvertVertexSelection &vtxIndex &vtxNormals
|
|
|
|
local normalVec = editNormalsMod.GetNormal (vtxNormals as Array)[1]
|
|
|
|
--dot them and if they dont agree within some margin mark them as problematic
|
|
if (isDeviantNormal vec normalVec) then
|
|
(
|
|
append selectionList elemArray[vtx]
|
|
)
|
|
)
|
|
|
|
--tail
|
|
local vec = normalize (obj.verts[elemArray[elemArray.count]].pos - obj.verts[elemArray[(elemArray.count - 1)]].pos)
|
|
local vtxIndex = #{elemArray.count}
|
|
local vtxNormals = #{}
|
|
editNormalsMod.ConvertVertexSelection &vtxIndex &vtxNormals
|
|
local normalVec = editNormalsMod.GetNormal (vtxNormals as Array)[1]
|
|
if (isDeviantNormal vec normalVec) then
|
|
(
|
|
append selectionList elemArray[elemArray.count]
|
|
)
|
|
)
|
|
|
|
if selectionList.count == 0 then
|
|
(
|
|
--messagebox "Cable is clean, No singularities found"
|
|
print "Clean"
|
|
deleteModifier obj editNormalsMod
|
|
)
|
|
else
|
|
(
|
|
gRsUlog.LogError (obj.name + " has deviant normals")
|
|
deleteModifier obj editNormalsMod
|
|
obj.selectedVerts = selectionList
|
|
SetCommandPanelTaskMode #modify
|
|
if subObjectDisplay do
|
|
(
|
|
subobjectLevel = 1
|
|
)
|
|
)
|
|
|
|
(selectionList.count == 0)
|
|
),
|
|
|
|
--//////////////////////////////////////////////////////////////////////////////
|
|
-- Find Bad Materials
|
|
--//////////////////////////////////////////////////////////////////////////////
|
|
fn findBadMaterials obj subObjectDisplay:true =
|
|
(
|
|
local matIDs = (RsGetMatIdsUsedByObj obj) as Array
|
|
local cableMaterialAssigned = true
|
|
local nonCableMatIDs = undefined
|
|
|
|
if (isKindOf obj.material Multimaterial) then
|
|
(
|
|
for id in matIDs while not cableMaterialAssigned do
|
|
(
|
|
cableMaterialAssigned = ((RstGetShaderName obj.material.materialList[id]) == getCableMaterialShaderName())
|
|
if not cableMaterialAssigned then nonCableMatIDs = id
|
|
)
|
|
|
|
faceMatId = RsGetFaceMatIDFunc obj
|
|
obj.selectedFaces = (for face in obj.faces where (faceMatId obj face.index) == nonCableMatIDs collect face.index)
|
|
)
|
|
else
|
|
(
|
|
if (not ((RstGetShaderName obj.material) == getCableMaterialShaderName())) then cableMaterialAssigned = false
|
|
)
|
|
|
|
if (not cableMaterialAssigned) and subObjectDisplay then
|
|
(
|
|
subobjectlevel = 4 --face
|
|
)
|
|
|
|
cableMaterialAssigned
|
|
),
|
|
|
|
--//////////////////////////////////////////////////////////////////////////////
|
|
-- Find Bad Attrs
|
|
--//////////////////////////////////////////////////////////////////////////////
|
|
fn findBadAttrs obj =
|
|
(
|
|
--export degenerate Polys
|
|
attrIdx = GetAttrIndex "Gta Object" "Remove Degenerate Polys"
|
|
local removeDegeneratePolys = (not (getAttr obj attrIdx))
|
|
|
|
if not removeDegeneratePolys do gRsUlog.LogError (obj.name + " has remove Degenerate Polys attribute set, this is wrong")
|
|
|
|
--weld mesh
|
|
attrIdx = GetAttrIndex "Gta Object" "Weld Mesh"
|
|
local weldMesh = getAttr obj attrIdx
|
|
|
|
if not weldMesh do gRsUlog.LogError (obj.name + " does not have weld mesh attribute set, this is wrong")
|
|
|
|
--set txd name
|
|
--attrIdx = GetAttrIndex "Gta Object" "TXD"
|
|
--local txd = ((getAttr obj attrIdx) == "cablemesh")
|
|
|
|
(removeDegeneratePolys and weldMesh)
|
|
|
|
),
|
|
|
|
/***
|
|
Get the vert colour from a given map channel for a mesh vert index
|
|
***/
|
|
fn getVertColourFromVert theMesh vIndex vChannel =
|
|
(
|
|
-- Get all faces using the vert as array
|
|
faceArray = (meshop.getFacesUsingVert theMesh vIndex) as array
|
|
|
|
local colours = #()
|
|
|
|
--iterate over the faces
|
|
for f in faceArray do
|
|
(
|
|
--Get geometry face - vertex is either its first, second or third component
|
|
geoFace = getFace theMesh f
|
|
|
|
-- Get map face (index corresponds with geometry face)
|
|
--There may not be a map channel set for this, so catch it accordingly
|
|
try
|
|
(
|
|
mapFace = meshop.getMapFace theMesh vChannel f
|
|
)
|
|
catch
|
|
(
|
|
--add a pure white for a missing channel colour
|
|
append colours #(255, 255, 255)
|
|
--onto the next
|
|
continue
|
|
)
|
|
|
|
-- Find order inside the mesh face - vertex (component) order will be the same in both
|
|
mapVert = case of
|
|
(
|
|
(geoFace.x == vIndex): mapFace.x
|
|
(geoFace.y == vIndex): mapFace.y
|
|
(geoFace.z == vIndex): mapFace.z
|
|
)
|
|
|
|
--collect the mapVert values found
|
|
local mapVal = meshop.getMapVert theMesh vChannel mapVert
|
|
--print mapVal
|
|
appendifunique colours mapVal
|
|
|
|
)--end f loop
|
|
|
|
colours
|
|
),
|
|
|
|
/***
|
|
Get a hash value for a selection array
|
|
***/
|
|
fn getSelectionHash itemArray =
|
|
(
|
|
local retHash
|
|
local ss = StringStream ""
|
|
for item in itemArray do
|
|
(
|
|
format "%" item.name to:ss
|
|
)
|
|
|
|
getHashValue (ss as String) 1
|
|
),
|
|
|
|
/***
|
|
Build the vertex marker cache
|
|
***/
|
|
fn buildMarkerCache =
|
|
(
|
|
print "buildcache"
|
|
|
|
visObjCache.vPos = #()
|
|
visObjCache.vCol = #()
|
|
|
|
--find the object positions and channel values
|
|
for obj in objectSelectionList where (isValidNode obj) do
|
|
(
|
|
if (obj != visObj) do
|
|
(
|
|
--get the cable colour from the object material
|
|
local cableShader = undefined
|
|
|
|
if (classOf obj.material == Multimaterial) then
|
|
(
|
|
visObj = obj.mesh
|
|
|
|
local matIds = RsGetMatIdsUsedByObj obj
|
|
local matIdArray = matIds as Array
|
|
if (matIds.numberSet > 0) then
|
|
(
|
|
-- --
|
|
--get the material diffs in a list
|
|
--
|
|
matDiffs = #()
|
|
|
|
for matID in (matIds as Array) do
|
|
(
|
|
local cableShader = obj.material[matID]
|
|
|
|
local diff1 = (RstGetVariable cableShader 4) * 255.0
|
|
local diff2 = (RstGetVariable cableShader 5) * 255.0
|
|
|
|
append matDiffs (DataPair diff1:diff1 diff2:diff2)
|
|
)
|
|
|
|
--break()
|
|
|
|
--for each material get a bitarray of verts
|
|
--so for each material we want to get the diffuse values to tint via the alpha channel
|
|
for vtx in visObj.verts do
|
|
(
|
|
faces = (meshop.getFacesUsingVert visObj vtx.index) as Array
|
|
local faceMatLookup = findItem matIdArray (getFaceMatID visObj faces[1])
|
|
local faceMat = matDiffs[faceMatLookup]
|
|
|
|
--get the verts
|
|
append visObjCache.vPos ( meshop.getvert visObj vtx.index node:obj )
|
|
local vAlpha = (getVertColourFromVert visObj vtx.index -2)[1]
|
|
|
|
if (visChannel == #alpha) then
|
|
(
|
|
append visObjCache.vCol (vAlpha * 255.0)
|
|
)
|
|
else
|
|
(
|
|
if (vAlpha.x >= 1.0) then
|
|
(
|
|
append visObjCache.vCol faceMat.diff2
|
|
)
|
|
else
|
|
(
|
|
append visObjCache.vCol faceMat.diff1
|
|
)
|
|
)
|
|
)
|
|
)
|
|
else
|
|
(
|
|
local idx = (matIds as Array)[1]
|
|
local mat = obj.material[idx]
|
|
if (classOf mat == Rage_Shader) and (RstGetShaderName mat == getCableMaterialShaderName()) then
|
|
(
|
|
cableShader = mat
|
|
)
|
|
)
|
|
)
|
|
else if (classOf obj.material == Rage_Shader) and (RstGetShaderName obj.material == getCableMaterialShaderName()) then
|
|
(
|
|
visObj = obj.mesh
|
|
|
|
cableShader = obj.material
|
|
local diff1 = (RstGetVariable cableShader 4) * 255.0
|
|
local diff2 = (RstGetVariable cableShader 5) * 255.0
|
|
|
|
for vtx in obj.verts do
|
|
(
|
|
--get the verts
|
|
append visObjCache.vPos ( meshop.getvert visObj vtx.index node:obj )
|
|
local vAlpha = (getVertColourFromVert visObj vtx.index -2)[1]
|
|
|
|
if (visChannel == #alpha) then
|
|
(
|
|
append visObjCache.vCol vAlpha
|
|
)
|
|
else
|
|
(
|
|
if (vAlpha.x >= 1.0) then
|
|
(
|
|
append visObjCache.vCol diff2
|
|
)
|
|
else
|
|
(
|
|
append visObjCache.vCol diff1
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
|
|
--remove duplicate position entries in the cache
|
|
local leanVPos = for vtx = 1 to visObjCache.vPos.count by 2 collect visObjCache.vPos[vtx]
|
|
local leanVCol = for vtx = 1 to visObjCache.vCol.count by 2 collect visObjCache.vCol[vtx]
|
|
|
|
visObjCache.vPos = leanVPos
|
|
visObjCache.vCol = leanVCol
|
|
|
|
cachedSelectionHash = getSelectionHash objectSelectionList
|
|
),
|
|
|
|
/***
|
|
Visualise the vertex colours using viewport drawing methods
|
|
***/
|
|
fn visualiseVerts =
|
|
(
|
|
if (selection.count == 0) do
|
|
(
|
|
objectSelectionList = #()
|
|
unregisterRedrawViewsCallback cableMakerDiagnostics.visualiseVerts
|
|
return false
|
|
)
|
|
|
|
--rebuild the cache if the selection list has changed
|
|
local selectionHash = getSelectionHash objectSelectionList
|
|
|
|
if (selectionHash != cachedSelectionHash) then
|
|
(
|
|
cacheDirty = true
|
|
)
|
|
|
|
if cacheDirty then
|
|
(
|
|
buildMarkerCache()
|
|
cacheDirty = false
|
|
)
|
|
|
|
gw.setTransform (Matrix3 1)
|
|
|
|
--draw the markers
|
|
for v=1 to visObjCache.vPos.count do
|
|
(
|
|
local vPos = visObjCache.vPos[v]
|
|
local vCol = (color visObjCache.vCol[v].x visObjCache.vCol[v].y visObjCache.vCol[v].z)
|
|
|
|
-- Draw filled circles at vert-points:
|
|
local drawPos = gw.htranspoint vPos + [1,1,0]
|
|
gw.hRect (box2 [drawPos.x - 3, drawPos.y - 3] [drawPos.x + 4, drawPos.y + 3]) vCol
|
|
gw.hMarker drawPos #circle color:vCol
|
|
)
|
|
|
|
gw.enlargeUpdateRect #whole
|
|
gw.updateScreen()
|
|
)
|
|
|
|
)--END STRUCT
|
|
|
|
--struct instance
|
|
cableMaker = CableMakerStruct()
|
|
cableMakerDiagnostics = CableMakerDiagnosticsStruct()
|
|
|
|
--//////////////////////////////////////////////////////////////////////////////////////////////
|
|
-- UI
|
|
--//////////////////////////////////////////////////////////////////////////////////////////////
|
|
if CableMakerUI != undefined then destroyDialog CableMakerUI
|
|
|
|
rollout CableMakerUI "Cable Maker"
|
|
(
|
|
--//////////////////////////////////////////////////////////////////////////////
|
|
-- VARIABLES
|
|
--//////////////////////////////////////////////////////////////////////////////
|
|
local tabRollouts = #(::CableGenerationUI, ::LegacyCableUpgradeUI, ::CableDiagnosticsUI, ::CableUtilUI)
|
|
|
|
--//////////////////////////////////////////////////////////////////////////////
|
|
-- CONTROLS
|
|
--//////////////////////////////////////////////////////////////////////////////
|
|
dotNetControl rsBannerPanel "Panel" pos:[0,0] height:32 width:CableMakerUI.width
|
|
local banner = makeRsBanner dn_Panel:rsBannerPanel versionName:"Pumpkin Flumpkin" versionNum:1.05 wiki:"CableMaker" filename:(getThisScriptFilename())
|
|
|
|
dotNetControl dnTabs "system.windows.forms.tabControl" width:CableMakerUI.width height:25 offset:[-12, 0]
|
|
|
|
subRollout theSubRollout width:(CableMakerUI.width - 2) height:(CableMakerUI.height - 60) offset:[-12, 0]--pos:[-1, dnTabs.pos.y + 50]
|
|
|
|
--//////////////////////////////////////////////////////////////////////////////
|
|
-- FUNCTIONS
|
|
--//////////////////////////////////////////////////////////////////////////////
|
|
fn SetPage index =
|
|
(
|
|
if index > tabRollouts.count do messageBox "invalid tab"
|
|
|
|
for roll in theSubRollout.rollouts do
|
|
(
|
|
removeRollout roll
|
|
)
|
|
|
|
AddSubRollout theSubRollout tabRollouts[index] rolledup:false border:true
|
|
)
|
|
|
|
--//////////////////////////////////////////////////////////////////////////////
|
|
-- EVENTS
|
|
--//////////////////////////////////////////////////////////////////////////////
|
|
on dnTabs Click do
|
|
(
|
|
local tabNum = dnTabs.SelectedIndex + 1
|
|
local tabName = tabRollouts[tabNum].name
|
|
|
|
SetPage tabNum
|
|
)
|
|
|
|
on CableMakerUI open do
|
|
(
|
|
banner.setup()
|
|
|
|
for tab in tabRollouts do dnTabs.tabPages.Add tab.title
|
|
SetPage 1
|
|
)
|
|
)
|
|
|
|
rollout CableGenerationUI "Generation"
|
|
(
|
|
--Body
|
|
/*
|
|
group "Cable Settings"
|
|
(
|
|
spinner spnSlack "Slack" tooltip:"How slack the cable is" range:[0.001, 5.0, 0.003]
|
|
spinner spnNumSegs "Segments" tooltip:"Number of segments in proxy" range:[3, 100, 10] type:#integer scale:1
|
|
--spinner spnRadius "Radius" tooltip:"Cable radius in METERS 0.01 = 1 cm" range:[0.01, 1.0, 0.01] scale:0.01
|
|
)
|
|
*/
|
|
|
|
dropdownlist ddlContainers "Scene Containers: " width:150 across:2 tooltip:"Container to add cables to"
|
|
button btnRefreshContainers "R" width:25 offset:[37, 18] tooltip:"Refresh Container List"
|
|
|
|
|
|
group "Generate Proxies"
|
|
(
|
|
button btnMakeConnectors "Create Cable Connectors" tooltip:"Create connection helpers for props" width:200
|
|
--button btnMakeProxy "Create Cable Helper" tooltip:"Create a cable representation" width:200
|
|
button btnToggleLinks "Toggle Selected Cable Links" tooltip:"Toggles visibilty of setup structure" width:200
|
|
)
|
|
|
|
|
|
group "AutoGenerate Prop Cables"
|
|
(
|
|
button btnAutoPropCables "Create Prop Cables" tooltip:"Make a selection of similar props to connect" width:200
|
|
spinner spnMinSlack "Slack Min" tooltip:"Minimum slack variation" range:[0.001, 0.1, 0.003] type:#float scale:0.001 across:2
|
|
spinner spnMaxSlack "Max" tooltip:"Maximum slack variation" range:[0.001, 0.1, 0.003] type:#float scale:0.001
|
|
)
|
|
|
|
|
|
group "Mesh Options"
|
|
(
|
|
dropdownlist ddlPreset "Cable Type" items:cablePresets.presets width:200
|
|
spinner spnMeshSegs "Segments" tooltip:"Final mesh segments" range:[3, 100, 6] type:#integer scale:1 width:80 across:2 align:#left
|
|
checkBox chkTaut "Taut" align:#right
|
|
)
|
|
|
|
|
|
group "Shader Options"
|
|
(
|
|
groupbox grpColour width:(CableGenerationUI.width - 25) height:50
|
|
label lblColour " Colour " align:#left offset:[5, -55]
|
|
colorPicker cprDiffOne "1:" color:(color 0 0 0 ) across:2 offset:[15, 0] width:70 modal:false
|
|
colorPicker cprDiffTwo "2:" color:(color 0 0 0 ) modal:false width:70
|
|
groupbox grpAmbient width:(CableGenerationUI.width - 25) height:50 offset:[0, 10]
|
|
label lblAmbient " Ambient " align:#left offset:[5, -55]
|
|
spinner spnAmbientNatural "Natural" range:[0.0, 1.0, 0.4] type:#float across:2 offset:[-5, 5]
|
|
spinner spnAmbientArtificial "Artificial" range:[0.0, 1.0, 0.4] type:#float offset:[-5, 5]
|
|
spinner spnEmissive "Emissive" range:[0.0, 32.0, 0.0] type:#float align:#left width:60 offset:[0, 10]
|
|
)
|
|
|
|
|
|
group "Generate Mesh"
|
|
(
|
|
button btnGenerateMesh "Create Cable Mesh" tooltip:"Build the mesh" width:200
|
|
button btnGenFromSpline "From Spline" tooltip:"Build a cable mesh from a spline" width:200
|
|
button btnFixCombinedNormals "Fix Combined Normals" width:200
|
|
)
|
|
|
|
--///////////////////////////////////
|
|
-- EVENTS dear boy
|
|
--///////////////////////////////////
|
|
on btnHelp pressed do
|
|
(
|
|
process = dotnetobject "System.Diagnostics.Process"
|
|
process.start "https://devstar.rockstargames.com/wiki/index.php/CableMaker"
|
|
|
|
process.dispose()
|
|
)
|
|
|
|
--/////////////////////////////////////////////////////////////////////////////
|
|
-- Make the cable Connectors
|
|
--/////////////////////////////////////////////////////////////////////////////
|
|
on btnMakeConnectors pressed do
|
|
(
|
|
cableMaker.createPropCableConnectors()
|
|
)
|
|
|
|
--/////////////////////////////////////////////////////////////////////////////
|
|
-- Make the cable proxies
|
|
--/////////////////////////////////////////////////////////////////////////////
|
|
on btnMakeProxy pressed do
|
|
(
|
|
if selection.count == 2 then
|
|
(
|
|
--Use the current settings values for mesh creation
|
|
cablePresets.getPreset ddlPreset.selected
|
|
cableMaker.radius = cablePresets.presetValues[3] as float
|
|
cableMaker.abrv = cablePresets.presetValues[1] as string
|
|
--the cableMakerColour
|
|
theColour = filterString cablePresets.presetValues[2] " "
|
|
cableMaker.cableColour = (color (theColour[1] as float) (theColour[2] as float) (theColour[3] as float))
|
|
|
|
catenaryCurve.slack = spnSlack.value
|
|
cableMaker.createCableProxy selection[1] selection[2] (spnNumSegs.value as Integer) inSlack:spnSlack.value
|
|
)
|
|
else
|
|
(
|
|
messagebox "Bad selection\nExiting!" title:"Error"
|
|
)
|
|
)
|
|
|
|
--/////////////////////////////////////////////////////////////////////////////
|
|
--
|
|
--/////////////////////////////////////////////////////////////////////////////
|
|
on btnToggleLinks pressed do
|
|
(
|
|
if selection.count != 0 then
|
|
(
|
|
if classOf selection[1] == Dummy then
|
|
(
|
|
if selection[1].showLinks == false then
|
|
(
|
|
selection[1].showLinks = true
|
|
)
|
|
else
|
|
(
|
|
selection[1].showLinks = false
|
|
)
|
|
)
|
|
)
|
|
)
|
|
|
|
|
|
--/////////////////////////////////////////////////////////////////////////////
|
|
--
|
|
--/////////////////////////////////////////////////////////////////////////////
|
|
on btnAutoPropCables pressed do
|
|
(
|
|
--get the prop selection
|
|
local userSel = for item in selection where (classof item == RSrefObject) collect item
|
|
if (userSel.count < 2) then
|
|
(
|
|
messageBox "Need more than 1 props selected" title:"Invalid Selection"
|
|
return false
|
|
)
|
|
|
|
--get props types, look for non-uniform selection
|
|
local propTypes = #()
|
|
for item in selection where (classof item == RSrefObject) do
|
|
(
|
|
appendifunique propTypes item.objectName
|
|
)
|
|
|
|
if (propTypes.count > 1) then
|
|
(
|
|
messagebox "More than 1 prop type in selection" title:"Invalid Selection"
|
|
return false
|
|
)
|
|
|
|
cableMaker.AutoGenPropCables userSel
|
|
|
|
)
|
|
|
|
|
|
--/////////////////////////////////////////////////////////////////////////////
|
|
--
|
|
--/////////////////////////////////////////////////////////////////////////////
|
|
on btnGenerateMesh pressed do
|
|
(
|
|
if selection.count == 0 then
|
|
(
|
|
messagebox "Nothing selected!\nNo mesh created." title:"Error"
|
|
return false
|
|
)
|
|
|
|
--Use the current settings values for mesh creation
|
|
cablePresets.getPreset ddlPreset.selected
|
|
cableMaker.radius = cablePresets.presetValues[3] as float
|
|
cableMaker.abrv = cablePresets.presetValues[1] as string
|
|
--the cableMakerColour
|
|
theColour = filterString cablePresets.presetValues[2] " "
|
|
cableMaker.cableColour = (color (theColour[1] as float) (theColour[2] as float) (theColour[3] as float))
|
|
--format "********************preset vals: % \n" cablePresets.presetValues
|
|
|
|
--iterate through all the cable proxy splines selected and create meshes for them
|
|
cableProxies = for o in selection collect o
|
|
|
|
if cableProxies.count == 0 then
|
|
(
|
|
messagebox "This doesn't seem to be a cable proxy spline" title:"Error!"
|
|
return false
|
|
)
|
|
|
|
for cable in cableProxies do
|
|
(
|
|
local startPos = undefined
|
|
local endPos = undefined
|
|
|
|
--branch on cable type
|
|
local validCable = false
|
|
case (classof cable.baseObject) of
|
|
(
|
|
cableProxy: --new system
|
|
(
|
|
--check properties for a cableProxy helper
|
|
if (isProperty cable #startNode) and (isProperty cable #endNode) and (isProperty cable #slack) do
|
|
(
|
|
--get spline start and end
|
|
startPos = cable.startNode.pos
|
|
endPos = cable.endNode.pos
|
|
|
|
--get the child label to change its text to the preset type
|
|
cable.nameTag = ddlPreset.selected
|
|
|
|
--make sure the slack is set as the proxy cable setting
|
|
catenaryCurve.slack = cable.slack
|
|
|
|
validCable = true
|
|
)
|
|
)
|
|
|
|
SplineShape: --old system
|
|
(
|
|
--get spline start and end
|
|
startPos = interpCurve3D cable 1 0.0
|
|
endPos = interpCurve3D cable 1 1.0
|
|
|
|
--make sure the slack is set as the proxy cable setting
|
|
local cableStartEndNodes = for c in cable.children where (classOf c) == text collect c.children
|
|
local thisSlack = for c in cableStartEndNodes[1] where isProperty c "slack" == true collect c.slack
|
|
--print thisSlack
|
|
if thisSlack.count == 0 then break()
|
|
|
|
catenaryCurve.slack = thisSlack[1]
|
|
|
|
validCable = true
|
|
)
|
|
|
|
default: --not a valid cable proxy
|
|
(
|
|
print (classof cable.baseObject) as String
|
|
print "invalid type"
|
|
)
|
|
)
|
|
|
|
--trigger the mesh build if we have a valid cable proxy
|
|
if validCable do
|
|
(
|
|
--set the spline to the preset name for future use
|
|
setAppData cable 1 ddlPreset.selected
|
|
|
|
--set iteration count higher for better curve accuracy
|
|
catenaryCurve.maxIter = 200
|
|
|
|
--
|
|
--CREATE THE MESH
|
|
--
|
|
cableMaker.createCableMesh cable startPos endPos (spnMeshSegs.value as Integer)
|
|
|
|
--set iteration count back for better interactivity
|
|
catenaryCurve.maxIter = 75
|
|
)
|
|
)
|
|
)
|
|
|
|
--/////////////////////////////////////////////////////////////////////////////
|
|
--
|
|
--/////////////////////////////////////////////////////////////////////////////
|
|
on btnGenFromSpline pressed do
|
|
(
|
|
if selection.count == 0 then
|
|
(
|
|
messagebox "Nothing selected!\nNo mesh created." title:"Error"
|
|
return false
|
|
)
|
|
|
|
theSplines = for o in selection where superclassOf o == shape collect o
|
|
|
|
for theSpline in theSplines do
|
|
(
|
|
cableMaker.createCableMeshFromSpline theSpline (spnMeshSegs.value as Integer)
|
|
)
|
|
|
|
)
|
|
|
|
--/////////////////////////////////////////////////////////////////////////////
|
|
--
|
|
--/////////////////////////////////////////////////////////////////////////////
|
|
on btnFixCombinedNormals pressed do
|
|
(
|
|
local selObjs = for item in selection collect item
|
|
for item in selObjs where (getAttrClass item == "Gta Object") do
|
|
(
|
|
--check it has a cable shader applied
|
|
local mat = item.material
|
|
local isCableMesh = false
|
|
if (isKindOf mat Multimaterial) then
|
|
(
|
|
local usedMatIDs = RsGetMatIdsUsedByObj item
|
|
|
|
for id = usedMatIDs while (not isCableMesh) do
|
|
(
|
|
if (RsIsCableTexture mat.materialList[id]) then
|
|
(
|
|
isCableMesh = true
|
|
)
|
|
)
|
|
)
|
|
else if (isKindOf mat Rage_Shader) then
|
|
(
|
|
if (RsIsCableTexture mat) then
|
|
(
|
|
isCableMesh = true
|
|
)
|
|
)
|
|
|
|
if isCableMesh then
|
|
(
|
|
cableMaker.fixMergedCableNormals theMesh:item
|
|
)
|
|
else print "not cable"
|
|
)
|
|
)
|
|
|
|
--/////////////////////////////////////////////////////////////////////////////
|
|
-- Set the catenary struct slack based on the spinner val
|
|
--/////////////////////////////////////////////////////////////////////////////
|
|
on spnSlack changed val do
|
|
(
|
|
catenaryCurve.slack = val
|
|
)
|
|
|
|
--/////////////////////////////////////////////////////////////////////////////
|
|
--
|
|
--/////////////////////////////////////////////////////////////////////////////
|
|
on spnRadius changed val do
|
|
(
|
|
cableMaker.radius = val
|
|
)
|
|
|
|
--/////////////////////////////////////////////////////////////////////////////
|
|
--
|
|
--/////////////////////////////////////////////////////////////////////////////
|
|
on btnRefreshContainers pressed do
|
|
(
|
|
--find availableContainers in the current scene
|
|
cableMaker.getAvailableContainers()
|
|
ddlContainers.items = (for c in cableMaker.availableContainers collect c.name)
|
|
)
|
|
|
|
--/////////////////////////////////////////////////////////////////////////////
|
|
--
|
|
--/////////////////////////////////////////////////////////////////////////////
|
|
on CableGenerationUI open do
|
|
(
|
|
cableMaker.UIHandle = CableGenerationUI
|
|
cablePresets.getPreset ddlPreset.selected
|
|
cableMaker.abrv = cablePresets.presetValues[1] as string
|
|
|
|
--sync and load the cable connections file
|
|
if gRsPerforce.connected() == false then gRsPerforce.connect()
|
|
gRsPerforce.sync cableMaker.connectionConfig silent:true
|
|
cableMaker.loadCableConnectorConfig()
|
|
|
|
--find availableContainers in the current scene
|
|
cableMaker.getAvailableContainers()
|
|
ddlContainers.items = (for c in cableMaker.availableContainers collect c.name)
|
|
)
|
|
|
|
|
|
)
|
|
|
|
--/////////////////////////////////////////////////////////////////////////////
|
|
-- Legacy cable upgrade rollout
|
|
--/////////////////////////////////////////////////////////////////////////////
|
|
rollout LegacyCableUpgradeUI "Cable Upgrade" width:200 height:40
|
|
(
|
|
button btnUpgradeSelected "Upgrade Selected" width:180
|
|
button btnUpgradeCableProxy "Upgrade Scene Cable Proxies" width:180
|
|
|
|
--/////////////////////////////////////////////////////////////////////////////
|
|
--
|
|
--/////////////////////////////////////////////////////////////////////////////
|
|
on btnUpgradeSelected pressed do
|
|
(
|
|
max hold
|
|
|
|
success = cableUpgrade.doUpgrade()
|
|
if success then
|
|
(
|
|
cableMaker.fixMergedCableNormals()
|
|
)
|
|
)
|
|
|
|
/***
|
|
|
|
***/
|
|
on btnUpgradeCableProxy pressed do
|
|
(
|
|
local success = cableUpgrade.upgradeSceneCableProxies()
|
|
if success then
|
|
(
|
|
messagebox "Cable Proxies Upgraded" title:"Done"
|
|
)
|
|
)
|
|
--/////////////////////////////////////////////////////////////////////////////
|
|
--
|
|
--/////////////////////////////////////////////////////////////////////////////
|
|
/*
|
|
on LegacyCableUpgradeUI rolledUp arg do
|
|
(
|
|
if arg then
|
|
(
|
|
CableMakerUI.height = 670
|
|
CableMakerUI.cableUpgrade.height = 60
|
|
)
|
|
else
|
|
(
|
|
CableMakerUI.height = 630
|
|
CableMakerUI.cableUpgrade.height = 25
|
|
)
|
|
)
|
|
*/
|
|
)
|
|
|
|
--/////////////////////////////////////////////////////////////////////////////
|
|
-- Diagnostics rollout
|
|
--/////////////////////////////////////////////////////////////////////////////
|
|
rollout CableDiagnosticsUI "Diagnostics"
|
|
(
|
|
local greenBitmap = (bitmap 17 17 color:green)
|
|
local redBitmap = bitmap 17 17 color:red
|
|
local neutralBitmap = bitmap 17 17 color:((colorMan.getColor #background) * 255.0)
|
|
|
|
local runAllTests = false
|
|
|
|
|
|
group "Object Selection:"
|
|
(
|
|
radiobuttons rdoSelection labels:#("Selected", "All")
|
|
)
|
|
button btnAllTests "Run All Tests" tooltip:"Run all the test below" width:(CableDiagnosticsUI.width - 10)
|
|
button btnShowSingularities "Show Singularities" tooltip:"Show co-located verts" width:(CableDiagnosticsUI.width - 30) align:#left offset:[-8, 0] across:2
|
|
bitmap btnShowSingularitiesResult bitmap:neutralBitmap align:#right offset:[9, 0]
|
|
button btnShowBadNormals "Show Bad Normals" tooltip:"Show bad vertex normals" width:(CableDiagnosticsUI.width - 30) align:#left offset:[-8, 0] across:2
|
|
bitmap btnShowBadNormalsResult bitmap:neutralBitmap align:#right offset:[9, 0]
|
|
button btnShowBadMaterials "Show Bad Materials" tooltip:"Show bad face material assignments" width:(CableDiagnosticsUI.width - 30) align:#left offset:[-8, 0] across:2
|
|
bitmap btnShowBadMaterialsResult bitmap:neutralBitmap align:#right offset:[9, 0]
|
|
button btnBadAttrs "Bad Attributes" tooltip:"Select cables with bad attributes set" width:(CableDiagnosticsUI.width - 30) align:#left offset:[-8, 0] across:2
|
|
bitmap btnBadAttrsResult bitmap:neutralBitmap align:#right offset:[9, 0]
|
|
|
|
group "Show Vertex Colours"
|
|
(
|
|
--checkbox chkVisColour "Colour" checked:true across:2
|
|
--checkbox chkVisAlpha "Alpha"
|
|
radiobuttons rdoVisChannel labels:#("Colour", "Alpha")
|
|
button btnShowVertexColours "Visualise" width:(CableDiagnosticsUI.width - 30)
|
|
)
|
|
|
|
--/////////////////////////////////////////////////////////////////////////////
|
|
--
|
|
--/////////////////////////////////////////////////////////////////////////////
|
|
fn getCables inSelection:true =
|
|
(
|
|
local objSel = if inSelection then objSel = selection else objSel = objects
|
|
local filterSel = #()
|
|
|
|
for obj in objSel where (getAttrClass obj == "Gta Object") and (obj.material != undefined) do
|
|
(
|
|
local excludedClassTypes = for type in #(RsInternalRef, RsRefObject, RsContainerLodRef) \
|
|
collect if not (isKindOf obj type) then dontCollect
|
|
|
|
if excludedClassTypes.count == 0 do
|
|
(
|
|
if (isKindOf obj.material Multimaterial) then
|
|
(
|
|
local matIDs = (RsGetMatIdsUsedByObj obj) as Array
|
|
local cableMaterialAssigned = false
|
|
for id in matIDs while not cableMaterialAssigned do
|
|
(
|
|
cableMaterialAssigned = ((RstGetShaderName obj.material.materialList[id]) == getCableMaterialShaderName())
|
|
)
|
|
|
|
if cableMaterialAssigned do append filterSel obj
|
|
)
|
|
else if RstGetShaderName obj.material == getCableMaterialShaderName() then
|
|
(
|
|
append filterSel obj
|
|
)
|
|
)
|
|
)
|
|
|
|
--retval
|
|
filterSel
|
|
)
|
|
|
|
--/////////////////////////////////////////////////////////////////////////////
|
|
-- Reset all test states to neutral
|
|
--/////////////////////////////////////////////////////////////////////////////
|
|
fn clearResultSwatches =
|
|
(
|
|
btnShowSingularitiesResult.bitmap = neutralBitmap
|
|
btnShowBadNormalsResult.bitmap = neutralBitmap
|
|
btnShowBadMaterialsResult.bitmap = neutralBitmap
|
|
btnBadAttrsResult.bitmap = neutralBitmap
|
|
)
|
|
|
|
--/////////////////////////////////////////////////////////////////////////////
|
|
-- Execute the desired test on the selection
|
|
--/////////////////////////////////////////////////////////////////////////////
|
|
fn executeTest testFn =
|
|
(
|
|
local result = false
|
|
|
|
local cableMeshes = getCables inSelection:(rdoSelection.state == 1)
|
|
if cableMeshes.count > 1 then
|
|
(
|
|
for item in cableMeshes do
|
|
(
|
|
if (testFn item subObjectDisplay:false) then result = true
|
|
)
|
|
)
|
|
else
|
|
(
|
|
if (testFn cableMeshes[1] subObjectDisplay:true) then result = true
|
|
)
|
|
|
|
--return
|
|
result
|
|
)
|
|
|
|
--/////////////////////////////////////////////////////////////////////////////
|
|
-- EVENTS
|
|
--/////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
--/////////////////////////////////////////////////////////////////////////////
|
|
--
|
|
--/////////////////////////////////////////////////////////////////////////////
|
|
on btnShowVertexColours pressed do
|
|
(
|
|
unregisterRedrawViewsCallback cableMakerDiagnostics.visualiseVerts
|
|
|
|
cableMakerDiagnostics.objectSelectionList = getCables()
|
|
|
|
cableMakerDiagnostics.visChannel = case of
|
|
(
|
|
(rdoVisChannel.state == 1):#colour
|
|
(rdoVisChannel.state == 2):#alpha
|
|
|
|
)
|
|
|
|
cableMakerDiagnostics.visualiseVerts()
|
|
registerRedrawViewsCallback cableMakerDiagnostics.visualiseVerts
|
|
)
|
|
|
|
--/////////////////////////////////////////////////////////////////////////////
|
|
--
|
|
--/////////////////////////////////////////////////////////////////////////////
|
|
on btnAllTests pressed do
|
|
(
|
|
--radSelection
|
|
runAllTests = true
|
|
clearResultSwatches()
|
|
|
|
gRsUlog.init "Cable tests"
|
|
|
|
local pass = undefined
|
|
|
|
--SINGULARITIES
|
|
pass = executeTest cableMakerDiagnostics.findCoLocatedVerts
|
|
if pass then
|
|
(
|
|
btnShowSingularitiesResult.bitmap = greenBitmap
|
|
)
|
|
else
|
|
(
|
|
btnShowSingularitiesResult.bitmap = redBitmap
|
|
)
|
|
|
|
--BAD NORMALS
|
|
pass = executeTest cableMakerDiagnostics.findBadNormals
|
|
if pass then
|
|
(
|
|
btnShowBadNormalsResult.bitmap = greenBitmap
|
|
)
|
|
else
|
|
(
|
|
btnShowBadNormalsResult.bitmap = redBitmap
|
|
)
|
|
|
|
--BAD MATERIALS
|
|
pass = executeTest cableMakerDiagnostics.findBadMaterials
|
|
if pass then
|
|
(
|
|
btnShowBadMaterialsResult.bitmap = greenBitmap
|
|
)
|
|
else
|
|
(
|
|
btnShowBadMaterialsResult.bitmap = redBitmap
|
|
)
|
|
|
|
--BAD ATTRS
|
|
pass = executeTest cableMakerDiagnostics.findBadAttrs
|
|
if pass then
|
|
(
|
|
btnBadAttrsResult.bitmap = greenBitmap
|
|
)
|
|
else
|
|
(
|
|
btnBadAttrsResult.bitmap = redBitmap
|
|
)
|
|
|
|
--finalise log
|
|
gRsUlog.Validate()
|
|
|
|
runAllTests = false
|
|
)
|
|
|
|
--/////////////////////////////////////////////////////////////////////////////
|
|
--
|
|
--/////////////////////////////////////////////////////////////////////////////
|
|
on btnShowSingularities pressed do
|
|
(
|
|
gRsUlog.init "Show cable singularities"
|
|
clearResultSwatches()
|
|
|
|
local pass = executeTest cableMakerDiagnostics.findCoLocatedVerts
|
|
if pass then
|
|
(
|
|
btnShowSingularitiesResult.bitmap = greenBitmap
|
|
)
|
|
else
|
|
(
|
|
btnShowSingularitiesResult.bitmap = redBitmap
|
|
)
|
|
|
|
--finalise log
|
|
gRsUlog.Validate()
|
|
)
|
|
|
|
--/////////////////////////////////////////////////////////////////////////////
|
|
--
|
|
--/////////////////////////////////////////////////////////////////////////////
|
|
on btnShowBadNormals pressed do
|
|
(
|
|
gRsUlog.init "Show deviant cable normals"
|
|
clearResultSwatches()
|
|
|
|
local pass = executeTest cableMakerDiagnostics.findBadNormals
|
|
if pass then
|
|
(
|
|
btnShowBadNormalsResult.bitmap = greenBitmap
|
|
)
|
|
else
|
|
(
|
|
btnShowBadNormalsResult.bitmap = redBitmap
|
|
)
|
|
|
|
--finalise log
|
|
gRsUlog.Validate()
|
|
)
|
|
|
|
--/////////////////////////////////////////////////////////////////////////////
|
|
-- find any faces that do not have a cable shader applied
|
|
--/////////////////////////////////////////////////////////////////////////////
|
|
on btnShowBadMaterials pressed do
|
|
(
|
|
gRsUlog.init "Show bad cable materials"
|
|
clearResultSwatches()
|
|
|
|
local pass = executeTest cableMakerDiagnostics.findBadMaterials
|
|
if pass then
|
|
(
|
|
btnShowBadMaterialsResult.bitmap = greenBitmap
|
|
)
|
|
else
|
|
(
|
|
btnShowBadMaterialsResult.bitmap = redBitmap
|
|
)
|
|
|
|
--finalise log
|
|
gRsUlog.Validate()
|
|
)
|
|
|
|
--/////////////////////////////////////////////////////////////////////////////
|
|
--
|
|
--/////////////////////////////////////////////////////////////////////////////
|
|
on btnBadAttrs pressed do
|
|
(
|
|
gRsUlog.init "Show bad cable attributes"
|
|
clearResultSwatches()
|
|
|
|
local pass = executeTest cableMakerDiagnostics.findBadAttrs
|
|
|
|
if pass then
|
|
(
|
|
btnBadAttrsResult.bitmap = greenBitmap
|
|
)
|
|
else
|
|
(
|
|
btnBadAttrsResult.bitmap = redBitmap
|
|
)
|
|
|
|
--finalise log
|
|
gRsUlog.Validate()
|
|
)
|
|
)
|
|
|
|
--/////////////////////////////////////////////////////////////////////////////
|
|
-- Util rollout
|
|
--/////////////////////////////////////////////////////////////////////////////
|
|
rollout CableUtilUI "Utils"
|
|
(
|
|
button btnMakePropConnectors "Export Prop Connectors"
|
|
|
|
on btnMakePropConnectors pressed do
|
|
(
|
|
cableMaker.createCableAttachPointsXML()
|
|
)
|
|
)
|
|
|
|
--//////////////////////////////////////////////////////////////////////////////////////////////
|
|
-- MAIN
|
|
--//////////////////////////////////////////////////////////////////////////////////////////////
|
|
createDialog CableMakerUI width:275 height:580 style:#(#style_titlebar, #style_border, #style_sysmenu, #style_minimizebox)
|
|
--addSubRollout CableMakerUI.cableUpgrade LegacyCableUpgradeUI
|
|
|