417 lines
17 KiB
Plaintext
Executable File
417 lines
17 KiB
Plaintext
Executable File
---------------------------------------------------------
|
|
-- Script for updating multiSub materials using a preset
|
|
-- Stewart Wright - Rockstar North - August 2012
|
|
---------------------------------------------------------
|
|
filein (RsConfigGetWildWestDir() + "script/3dsMax/_config_files/Wildwest_header.ms")
|
|
|
|
(
|
|
---------------------------------------------------------
|
|
-- LOCALS --------------------------------------------
|
|
local warnValue = 5
|
|
local updateCount = #(0,0,0,0) --(materials, rage materials, updated materials, updated to detail materials)
|
|
---------------------------------------------------------
|
|
-- GLOBALS -------------------------------------------
|
|
global rs_MulitSubUpdater
|
|
---------------------------------------------------------
|
|
-- FUNCTIONS --------------------------------------
|
|
---------------------------------------------------------
|
|
fn get_presetList =
|
|
(
|
|
returnArray = #()
|
|
presetFiles = getFiles (mapShaderPresetPath + "*.txt")
|
|
|
|
for i in presetFiles do
|
|
(
|
|
tempArray = filterString i @"\ /"
|
|
justName = tempArray[tempArray.count]
|
|
justName = substring justName 1 (justName.count-4)
|
|
append returnArray justName
|
|
)
|
|
return returnArray
|
|
)--end get_presetList
|
|
---------------------------------------------------------
|
|
--function for writing out the shader values to a text file
|
|
fn saveMaterialSettings toWrite saveAs =
|
|
-- toWrite = the array data we're going to write out
|
|
-- saveAs = what we're saving the file as
|
|
(
|
|
if (saveAs!= "") do
|
|
(
|
|
safeToSave = true
|
|
presetFile = (mapShaderPresetPath + saveAs + ".txt")
|
|
presetFile = rsMakeSafeSlashes presetFile
|
|
|
|
if (gRsPerforce.sync #(presetFile) silent:true) == true then --try and sync the file
|
|
(
|
|
if not(queryBox "Preset already exists, Do you want to continue?" title:"Warning!") then (safeToSave = false) --if it already exists
|
|
else
|
|
(
|
|
gRsPerforce.edit #(presetFile) silent:true
|
|
safeToSave = true
|
|
)
|
|
)
|
|
else --if it is new
|
|
(
|
|
gRsPerforce.add #(presetFile) silent:true
|
|
safeToSave = true
|
|
)
|
|
|
|
if (safeToSave) do
|
|
(
|
|
saveFile = createFile presetFile --now we make the text file using the above settings
|
|
print toWrite to: saveFile --write the contents of our array to the text file
|
|
close saveFile --housekeeping. this closes the txt file
|
|
rs_MulitSubUpdater.ddlPresets.items = (get_presetList())
|
|
)
|
|
)
|
|
)--end saveMaterialSettings
|
|
---------------------------------------------------------
|
|
--function for reading in the shader values from a text file
|
|
fn loadMaterialPreset =
|
|
(
|
|
readData = #() --housekeeping. empty the array before we start
|
|
|
|
presetName = rs_MulitSubUpdater.ddlPresets.selected
|
|
sourceFile = mapShaderPresetPath + presetName + ".txt"
|
|
|
|
shaderFile = openFile sourceFile
|
|
|
|
if shaderFile != undefined then
|
|
(
|
|
while not eof shaderFile do --as long as we haven't reached the end of the file keep going
|
|
(
|
|
checkLine = readValue shaderFile ignoreStringEscapes:true --readValue gets the info from the txt file
|
|
append readData checkLine --adds each line of the text file to our array
|
|
)
|
|
close shaderFile --housekeeping. this closes the txt file
|
|
|
|
readData --pass out the array
|
|
)
|
|
else
|
|
(
|
|
mText = "I couldn't find " + sourcefile + ".txt"
|
|
messagebox mText title:"Error"
|
|
)
|
|
)--end loadMaterialPreset
|
|
---------------------------------------------------------
|
|
--function to read the material and save it as a preset
|
|
fn readMaterial getMat =
|
|
--getMat = the material we're updating
|
|
(
|
|
multiSubArray = #()
|
|
|
|
if classOf getMat == Multimaterial then
|
|
(
|
|
for subID=1 to getMat.numSubs do
|
|
(
|
|
if classOf getMat[subID] == Rage_Shader do
|
|
(
|
|
shadertype = RstGetShaderName getMat[subID]
|
|
shaderArray = #() --lets make a 'disposable' array for storing the settings
|
|
|
|
for shaderVar=1 to RstGetVariableCount getMat[subID] do
|
|
(
|
|
varValue = (RstGetVariable getMat[subID] shaderVar) --get the variable value
|
|
append shaderArray varValue
|
|
)
|
|
append multiSubArray #(shaderType, shaderArray)
|
|
)
|
|
)
|
|
saveMaterialSettings multiSubArray rs_MulitSubUpdater.edtName.text
|
|
)
|
|
else
|
|
(
|
|
messageBox "This isn't a multi/sub material."
|
|
)
|
|
)--end readMaterial
|
|
---------------------------------------------------------
|
|
--a function to find all items in an array. similar to findItem but returns multiple values, not just the first hit
|
|
fn findAllItems arrayToSearch val =
|
|
(
|
|
local foundIndexes = #()
|
|
local arrayCopy = deepCopy arrayToSearch
|
|
|
|
while ((foundIndex = (findItem arrayCopy val)) != 0) do
|
|
(
|
|
append foundIndexes foundIndex
|
|
arrayCopy[foundIndex] = undefined
|
|
)
|
|
foundIndexes --pass out the results
|
|
)--end findAllItems
|
|
---------------------------------------------------------
|
|
--a function to apply the preset values to the active material
|
|
fn applyMaterial getMat presetArray=
|
|
--getMat = the material we're updating
|
|
--presetArray = the pesets we're loading
|
|
(
|
|
if classOf getMat == Multimaterial then
|
|
(
|
|
justTheShaderType = #()
|
|
justTheShaderValues = #()
|
|
for readShaderType=1 to presetArray.count do
|
|
(
|
|
append justTheShaderType presetArray[readShaderType][1]--make an array containing just the shader type
|
|
append justTheShaderValues presetArray[readShaderType][2]--make an array containing just the shader values
|
|
)
|
|
|
|
for subID=1 to getMat.numSubs do--for every sub material
|
|
(
|
|
updateCount[1] = (updateCount[1] + 1)--update our counter for the materials
|
|
shaderUpdateStatus = false
|
|
|
|
if classOf getMat[subID] == Rage_Shader do--if the shader is a rage material
|
|
(
|
|
updateCount[2] = (updateCount[2] + 1)--update our counter for the rage materials
|
|
|
|
shaderType = RstGetShaderName getMat[subID] --the selected shader type
|
|
|
|
filteredShaderType = filterString shaderType "."--attempt to create a detail version of this shader
|
|
detailShaderType = filteredShaderType[1] + "_detail." + filteredShaderType[2]
|
|
|
|
matchedShaders = findAllItems justTheShaderType shaderType --search our array for shader mathes
|
|
matchedDetailShaders = findAllItems justTheShaderType detailShaderType --search our array for shader mathes
|
|
|
|
join matchedShaders matchedDetailShaders
|
|
|
|
if matchedShaders.count > 0 do --if we've found shader matches
|
|
(
|
|
matchedShaderValues = #()
|
|
matchedShadersType = #()
|
|
for matched=1 to matchedShaders.count do
|
|
(
|
|
append matchedShadersType justTheShaderType[matchedShaders[matched]]--make a new array with just the matching shader data
|
|
append matchedShaderValues justTheShaderValues[matchedShaders[matched]]--make a new array with just the matching shader data
|
|
)
|
|
|
|
arrayToMatch = #() --lets make a 'disposable' array for storing the settings
|
|
for shaderVar=1 to RstGetVariableCount getMat[subID] do --for each variable in the shader
|
|
(
|
|
varValue = (RstGetVariable getMat[subID] shaderVar) --get the variable value
|
|
varName = (RstGetVariableName getMat[subID] shaderVar) --get the variable value
|
|
if (RstGetVariableType getMat[subID] shaderVar == "texmap") and (varName != "Detail Map") do --if it is a texture we'll note it, this is what we are checking for matches against
|
|
(
|
|
append arrayToMatch #(varValue, shaderVar)--we are storing the value and the position within the shader
|
|
)
|
|
)
|
|
|
|
for checkMe=1 to matchedShaderValues.count do --for every shader match
|
|
(
|
|
if shaderUpdateStatus != true do --if we haven't found a match yet
|
|
(
|
|
matchingPair = #()
|
|
for checkAgainst=1 to arrayToMatch.count do --for every texture in the current shader
|
|
(
|
|
append matchingPair (arrayToMatch[checkAgainst][1] == matchedShaderValues[checkMe][arrayToMatch[checkAgainst][2]]) --store if we find a match. match == true
|
|
)
|
|
|
|
if (findItem matchingPair false) == 0 and (matchingPair.count != 0) then --if we don't find any false matches then we can update this shader
|
|
(
|
|
for shaderVar=1 to RstGetVariableCount getMat[subID] do --for every variable in the shader
|
|
(
|
|
RstSetVariable getMat[subID] shaderVar matchedShaderValues[checkMe][shaderVar] --update it with our preset values
|
|
if shaderVar==RstGetVariableCount getMat[subID] do
|
|
(
|
|
updateCount[3] = (updateCount[3] + 1)--update our counter for the updated rage materials
|
|
shaderUpdateStatus = true --set the status of the update so we can stop and move on to the next
|
|
)
|
|
)
|
|
)
|
|
else-- we'll do some checks to see if this shader matches a detail version
|
|
(
|
|
if shaderUpdateStatus != true do --if we haven't found a match yet
|
|
(
|
|
matchedDetailShaderValues = #()
|
|
for matched=1 to matchedShaders.count do
|
|
(
|
|
append matchedDetailShaderValues justTheShaderValues[matchedShaders[matched]]--make a new array with just the matching shader data
|
|
)
|
|
|
|
tempMatCopy = mlib[24]--copy slot24, we'll replace it once we're done
|
|
|
|
mlib[24] = copy getMat[subID]
|
|
RstSetShaderName mlib[24] detailShaderType
|
|
|
|
if RstGetVariableCount mlib[24] > 0 do --if it is a valid shader it will have a positive number
|
|
(
|
|
detailArrayToMatch = #() --lets make a 'disposable' array for storing the settings
|
|
for shaderVar=1 to RstGetVariableCount mlib[24] do --for each variable in the shader
|
|
(
|
|
varValue = (RstGetVariable mlib[24] shaderVar) --get the variable value
|
|
varName = (RstGetVariableName mlib[24] shaderVar) --get the variable value
|
|
if RstGetVariableType mlib[24] shaderVar == "texmap" do --if it is a texture we'll note it, this is what we are checking for matches against
|
|
(
|
|
if upperCase varName != "DETAIL MAP" do --we don't care about the detail map. if we are going from a non detail shader to a detail shader the original shader won't have this slot
|
|
(
|
|
append detailArrayToMatch #(varValue, shaderVar)--we are storing the value and the position within the shader
|
|
)
|
|
)
|
|
)
|
|
|
|
mlib[24] = tempMatCopy--return slot24 to what i used to be
|
|
|
|
if detailArrayToMatch.count != 0 do --if we find some matches
|
|
(
|
|
for checkMe=1 to matchedDetailShaderValues.count do --for every shader match
|
|
(
|
|
matchingPair = #()
|
|
for checkAgainst=1 to arrayToMatch.count do --for every texture in the current shader
|
|
(
|
|
append matchingPair (detailArrayToMatch[checkAgainst][1] == matchedDetailShaderValues[checkMe][detailArrayToMatch[checkAgainst][2]]) --store if we find a match. match == true
|
|
)
|
|
if (findItem matchingPair false) == 0 and (matchingPair.count != 0) then --if we don't find any false matches then we can update this shader
|
|
(
|
|
RstSetShaderName getMat[subID] matchedShadersType[checkMe] --change the shader type
|
|
for shaderVar=1 to RstGetVariableCount getMat[subID] do --for every variable in the shader
|
|
(
|
|
RstSetVariable getMat[subID] shaderVar matchedDetailShaderValues[checkMe][shaderVar] --update it with our preset values
|
|
if shaderVar==RstGetVariableCount getMat[subID] do
|
|
(
|
|
updateCount[4] = (updateCount[4] + 1)--update our counter for the updated rage materials
|
|
shaderUpdateStatus = true --set the status of the update so we can stop and move on to the next
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
mlib[24] = tempMatCopy--return slot24 to what i used to be#
|
|
)
|
|
)--end of else loop. this loop is for detail shader upgrades
|
|
)
|
|
)
|
|
)--end shader match
|
|
)
|
|
)-- end for every sub material loop
|
|
)
|
|
)--end applyMaterial
|
|
---------------------------------------------------------
|
|
-- UI --------------------------------------------------
|
|
---------------------------------------------------------
|
|
(
|
|
try (destroyDialog rs_MulitSubUpdater) catch()
|
|
-- LOCALS -------------------------------------------
|
|
local theState = 1
|
|
---------------------------------------------------------
|
|
rollout rs_MulitSubUpdater "MultiSub Material Presets"
|
|
(
|
|
dotNetControl rsBannerPanel "Panel" pos:[0,0] height:32 width:rs_MulitSubUpdater.width
|
|
local banner = makeRsBanner dn_Panel:rsBannerPanel colourScheme:#eval filename:(getThisScriptFilename())
|
|
|
|
group "Create New MultiSub Preset"
|
|
(
|
|
label presetName "Preset Name:" align:#left
|
|
editText edtName width:140 offset:[0,0]
|
|
button btnSave "Save MultiSub As Preset" width:130 tooltip:"Create preset from selecte material"
|
|
)
|
|
|
|
group "MultiSub Shader Preset"
|
|
(
|
|
button btnFetch "Sync Presets" width:130 toolTip:"Fetch the latest data from perforce"
|
|
dropdownlist ddlPresets width:140 items:(get_presetList())
|
|
label materialSource "Update Material On Selected:" align:#left
|
|
radiobuttons radObjectOrMaterial labels:#("Object", "Material") toolTip:"Select how you want to define the material to update"
|
|
button btnLoad "Apply MultiSub Preset" width:130 toolTip:"Load preset on to selected material."
|
|
)
|
|
---------------------------------------------------------
|
|
-- EVENTS ------------------------------------------
|
|
---------------------------------------------------------
|
|
on ddlPresets selected sel do (loadMaterialPreset())
|
|
-----------------------------------------------------------
|
|
on radObjectOrMaterial changed newState do (theState = newState)
|
|
-----------------------------------------------------------
|
|
on btnSave pressed do
|
|
(
|
|
materialWindowState = MatEditor.isOpen()--store the material editor window state
|
|
MatEditor.Close()--close the material editor if it is open
|
|
readMaterial (medit.getcurmtl())
|
|
if materialWindowState == true do MatEditor.Open()--open the material editor again if it was when we started
|
|
)
|
|
on btnLoad pressed do
|
|
(
|
|
if rs_MulitSubUpdater.ddlPresets.selected != undefined then
|
|
(
|
|
loadedData = loadMaterialPreset()
|
|
updateCount = #(0,0,0,0)--empty this, we'll fill it with report stats
|
|
|
|
case of
|
|
(
|
|
(theState == 1):--if the 'object' button is checked
|
|
(
|
|
if selection.count > 0 then--if we have at least 1 thing selected
|
|
(
|
|
if selection.count > warnValue then
|
|
(
|
|
if (queryBox "There are more than 5 objects selected.\r\nThis might take a while.\r\nDo you want to continue?" title:"Warning!") do--a warning about large selection counts
|
|
(
|
|
materialWindowState = MatEditor.isOpen()--store the material editor window state
|
|
MatEditor.Close()--close the material editor if it is open
|
|
|
|
whatMaterials = #()--an array to store the materials in
|
|
for selectedObject=1 to selection.count do
|
|
(
|
|
if superClassOf selection[selectedObject] == GeometryClass then
|
|
(
|
|
if classOf selection[selectedObject].material == Multimaterial then
|
|
(
|
|
whatMaterial = selection[selectedObject].material
|
|
appendIfUnique whatMaterials whatMaterial --add the material if it is unique
|
|
)
|
|
else (print "The material is not a multiSub.")
|
|
)
|
|
else (print "The selected object is not geometry.")
|
|
)
|
|
|
|
if whatMaterials.count > 0 do --if we have some materials to update
|
|
(
|
|
for singleMaterial=1 to whatMaterials.count do --for every material
|
|
(
|
|
applyMaterial whatMaterials[singleMaterial] loadedData --update the material
|
|
)
|
|
)
|
|
|
|
if materialWindowState == true do MatEditor.Open()--open the material editor again if it was when we started
|
|
)--end querybox
|
|
)
|
|
)
|
|
else (messageBox "Please select a mesh.")
|
|
)
|
|
(theState == 2):--if the 'material' button is checked
|
|
(
|
|
if classOf (medit.getcurmtl()) == Multimaterial then--if the material is a rage shader we'll use it
|
|
(
|
|
materialWindowState = MatEditor.isOpen()--store the material editor window state
|
|
MatEditor.Close()--close the material editor if it is open
|
|
whatMaterial = medit.getcurmtl()
|
|
applyMaterial whatMaterial loadedData
|
|
if materialWindowState == true do MatEditor.Open()--open the material editor again if it was when we started
|
|
)
|
|
else (messageBox "Please open the material editor and select a multiSub shader.")
|
|
)
|
|
)
|
|
|
|
updateStatsText = updateCount[1] as string + " total materials checked. Of which " + updateCount[2] as string + " were Rage Shaders.\r\n" + updateCount[3] as string + " Rage Shaders updated.\r\n" + updateCount[4] as string + " Rage Shaders converted to details shaders.\r\n"
|
|
messageBox updateStatsText title:"Update Stats Report:"
|
|
)
|
|
else (messageBox "Please select a preset.")
|
|
)
|
|
-----------------------------------------------------------
|
|
on btnFetch pressed do
|
|
(
|
|
WWP4vSync mapShaderPresetFiles
|
|
)
|
|
---------------------------------------------------------
|
|
---------------------------------------------------------
|
|
on rs_MulitSubUpdater open do
|
|
(
|
|
rs_dialogPosition "get" rs_MulitSubUpdater
|
|
rs_MulitSubUpdater.banner.setup()
|
|
)
|
|
---------------------------------------------------------
|
|
on rs_MulitSubUpdater close do
|
|
(
|
|
rs_dialogPosition "set" rs_MulitSubUpdater
|
|
)
|
|
)
|
|
createDialog rs_MulitSubUpdater width:165 style:#(#style_border,#style_toolwindow,#style_sysmenu)
|
|
)--end UI
|
|
) |