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

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