515 lines
18 KiB
Plaintext
Executable File
515 lines
18 KiB
Plaintext
Executable File
--- ROCKSTAR SUBSTANCE FUNCTIONS
|
|
-- Useage : Converts substance information that is used on export to create RAGE shaders for game
|
|
-- Allan Hayburn
|
|
-- Nov 2012
|
|
|
|
-----------------------------------------------------------------
|
|
-- CALLS TO CONVERT A SUBSTANCE SCENE -----
|
|
-----------------------------------------------------------------
|
|
|
|
--rsMaterialHolder = rsSubstanceMaterialHolder() --- This generates the rsMaterialHolder
|
|
-- struct that, on create, holds all the substance materials in scene
|
|
|
|
--rsMaterialHolder.convertSceneToRage() -- Call to convert scene
|
|
|
|
--rsMaterialHolder.returnSceneToSubstance() -- Call to return scene
|
|
|
|
|
|
|
|
|
|
filein (rsConfigGetWildWestDir() + "script/3dsmax/_config_files/wildwest_header.ms")
|
|
filein (RsConfigGetToolsDir()+"dcc/current/max2012/scripts/pipeline/util/p4.ms")
|
|
rsSubstanceMappingFile = (RsConfigGetProjBinConfigDir()+"generic/SubstanceMappingTable.xml")
|
|
|
|
struct rsSubstanceFunctions
|
|
(
|
|
substanceMappingFile = rsSubstanceMappingFile,
|
|
--------------------------------------------------------------------------------------------------------------------------------
|
|
-- fn checkRenderedMaps -- does perforce checks for rendered files. will add to new CL.
|
|
--------------------------------------------------------------------------------------------------------------------------------
|
|
fn checkRenderedMaps files =
|
|
(
|
|
checkFiles = gRsPerforce.getFileStats files
|
|
filesInP4 = #()
|
|
submitList = #()
|
|
fileNames = #()
|
|
checkingP4 = false
|
|
for i in 1 to files.count do -- adds the files arg names to array to check in p4
|
|
(
|
|
append fileNames (getfilenamefile files[i])
|
|
)
|
|
|
|
checknames = #()
|
|
for i in 1 to checkFiles.count do -- creates a struct and gets the name of the file for each file in p4
|
|
(
|
|
theRecordStruct = gRsPerforce.record2struct checkFiles[i]
|
|
theFileProps = getpropnames theRecordStruct
|
|
doesItHaveHeadRev = finditem theFileProps #headRev
|
|
if doesItHaveHeadRev != 0 then
|
|
(
|
|
append checknames (getfilenamefile theRecordStruct.depotFile)
|
|
)
|
|
)
|
|
for i in 1 to filenames.count do
|
|
(
|
|
inP4 = finditem checknames filenames[i] -- is our file in p4?
|
|
if inP4 == 0 then
|
|
(
|
|
append submitList files[i] -- if no add to submit list
|
|
) else
|
|
(
|
|
|
|
append filesInP4 files[i] -- if yes then checkout dialog
|
|
)
|
|
)
|
|
format "New Files: \n"
|
|
for f in submitList do format "%\n" f
|
|
format "In P4 Files:\n" filesInP4
|
|
for f in filesInP4 do format "%\n" f
|
|
if submitList.count > 0 then
|
|
(
|
|
gRsPerforce.addToChangelistByName "Substance Generated Maps" submitList
|
|
checkingP4 = true
|
|
)
|
|
if filesInP4.count > 0 then
|
|
(
|
|
checkingP4 = gRsPerforce.readOnlyP4Check filesInP4
|
|
)
|
|
checkingP4
|
|
),
|
|
--------------------------------------------------------------------------------------------------------------------------------
|
|
-- fn makeRageFromSubstance -- converts to substance shader to rage shader
|
|
--------------------------------------------------------------------------------------------------------------------------------
|
|
fn makeRageFromSubstance theMaterial theMaps =
|
|
(
|
|
local theSubstanceSettings = theMaterial.ambientmap
|
|
newRageMaterial = rage_shader()
|
|
newRageMaterial.name = theMaterial.name
|
|
RstSetShaderName newRageMaterial theSubstanceSettings.presetType
|
|
theRsVariables = RstGetVariableCount newRageMaterial
|
|
for i in 1 to theMaps.count do
|
|
(
|
|
for ii in 1 to theRsVariables do
|
|
(
|
|
if (tolower (RstGetVariableName newRageMaterial ii)) == theMaps[i].slot then
|
|
(
|
|
RstSetVariable newRageMaterial ii theMaps[i].map
|
|
)
|
|
)
|
|
)
|
|
newRageMaterial
|
|
),
|
|
--------------------------------------------------------------------------------------------------------------------------------
|
|
-- fn renderSubstanceMaps -- renders the substance maps defined by the preset - if test: = true then it will only generate a list of maps, not render them.
|
|
--------------------------------------------------------------------------------------------------------------------------------
|
|
fn renderSubstanceMaps theMaterial presetArray dataPairArray iterateVal test:false =
|
|
(
|
|
format "%\n" theMaterial
|
|
local theSubstanceSettings = theMaterial.ambientmap
|
|
local rsMaps = #()
|
|
local rsPreset = getfilenamefile theSubstanceSettings.presetType
|
|
local notfound = true, res
|
|
for i = 1 to presetArray.count while notfound do
|
|
if presetArray[i].preset == rsPreset then (res = i; notfound = false;)
|
|
res
|
|
if notfound == false do
|
|
(
|
|
|
|
local theMappings = presetArray[res].mappings
|
|
for i in 1 to theMappings.count do
|
|
(
|
|
local theMap = (tolower theMappings[i].mapping1)
|
|
local theMapType = case theMap of
|
|
(
|
|
|
|
"diffusemap":"texture"
|
|
"specularmap":"texture"
|
|
"bumpmap":"texture"
|
|
"specular_levels_out":"float"
|
|
"normal_strength":"float"
|
|
)
|
|
if theMapType == "texture" then
|
|
(
|
|
local rendertype = case theMap of
|
|
(
|
|
|
|
"diffusemap":theMaterial.diffusemap
|
|
"specularmap":theMaterial.SpecularMap
|
|
"bumpmap":theMaterial.bumpMap
|
|
)
|
|
local theSuffix = case theMap of
|
|
(
|
|
|
|
"diffusemap":"_d"
|
|
"specularmap":"_s"
|
|
"bumpmap":"_n"
|
|
)
|
|
|
|
local theBaseTex = ((substring (getfilenamefile theSubstanceSettings.baseTexture.filename) 1 8)+"_Subst"+iterateVal as string )
|
|
|
|
local theRsMapFile = (theSubstanceSettings.textureOutputDirectory+theBaseTex+theSuffix+".tif")
|
|
|
|
if test == true then
|
|
(
|
|
|
|
--theDataPair = datapair BaseTexture:theBaseTex MatArray:(datapair mat:theMaterial texture:theRsMapFile)
|
|
--format "--------------------------\n\n%\n\n-------------------------\n\n" theDataPair
|
|
) else (
|
|
|
|
format "Rendering Substance Bitmap:%\n" theRsMapFile
|
|
rm = renderMap rendertype size:[1024,1024] fileName:theRsMapFile
|
|
rm.gamma = IDisplayGamma.gamma
|
|
save rm
|
|
|
|
)
|
|
append rsMaps (datapair Slot:(tolower theMappings[i].mapping2) Map:theRsMapFile)
|
|
|
|
) else if theMapType == "float" then (
|
|
|
|
local rendervalue = case theMap of
|
|
(
|
|
"specular_levels_out":theMaterial.ambientmap.substance.Specular_Levels_Out.x
|
|
"normal_strength":theMaterial.ambientmap.substance.Normal_Strength
|
|
|
|
)
|
|
local valArray = (datapair Slot:(tolower theMappings[i].mapping2.mapping2) Map:rendervalue)
|
|
append rsMaps valArray
|
|
)
|
|
|
|
)
|
|
)
|
|
rsMaps
|
|
),
|
|
--------------------------------------------------------------------------------------------------------------------------------
|
|
-- fn makeRagePresetArray -- Generates the list of rage presets that have been defined in the xml file
|
|
--------------------------------------------------------------------------------------------------------------------------------
|
|
fn makeRagePresetArray =
|
|
(
|
|
local presetArray = #()
|
|
if presetArray == undefined then format "No Preset Array Defined" else
|
|
(
|
|
if doesfileexist substanceMappingFile == true then
|
|
(
|
|
xmlDoc = dotnetobject "System.XML.XMLDocument"
|
|
xmlDoc.load substanceMappingFile
|
|
theEle = xmlDoc.DocumentElement
|
|
|
|
for i = 0 to theEle.childNodes.count-1 do
|
|
(
|
|
theObject = theEle.ChildNodes.itemOf[i]
|
|
if theObject.attributes.getnameditem "type" != undefined then
|
|
(
|
|
if ((theObject.GetAttributeNode "type").value) == "preset" then
|
|
(
|
|
mappingArray = #()
|
|
for chld = 0 to theObject.childNodes.count-1 do
|
|
(
|
|
theMapping = theObject.ChildNodes.itemOf[chld]
|
|
if theMapping.name != "#comment" then
|
|
(
|
|
if ((theMapping.GetAttributeNode "type").value) == "texture" then
|
|
(
|
|
thePair = (datapair mapping1:(theMapping.GetAttributeNode "mapping1").value mapping2:(theMapping.GetAttributeNode "mapping2").value)
|
|
append mappingArray thePair
|
|
)
|
|
|
|
if ((theMapping.GetAttributeNode "type").value) == "float" then
|
|
(
|
|
local theValues = datapair mapping2:(theMapping.GetAttributeNode "mapping2").value values:#((theMapping.GetAttributeNode "value1").value,(theMapping.GetAttributeNode "value2").value)
|
|
thePair = datapair mapping1:(theMapping.GetAttributeNode "mapping1").value mapping2:theValues
|
|
-- print thePair
|
|
append mappingArray thePair
|
|
)
|
|
)
|
|
)
|
|
append presetArray (datapair preset:(theObject.GetAttributeNode "name").value mappings:mappingArray)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
presetArray
|
|
),
|
|
--------------------------------------------------------------------------------------------------------------------------------
|
|
-- fn makePresetList -- Generates the list of rage presets for ui
|
|
--------------------------------------------------------------------------------------------------------------------------------
|
|
fn makePresetList =
|
|
(
|
|
presetArray = makeRagePresetArray()
|
|
presetlist = #()
|
|
for i in 1 to presetArray.count do
|
|
(
|
|
append presetlist (presetArray[i].preset + ".sps")
|
|
)
|
|
sort presetlist
|
|
presetlist
|
|
),
|
|
--------------------------------------------------------------------------------------------------------------------------------
|
|
-- fn replaceShaderScenObjs -- looks for scene objects with the mat and converts their material
|
|
--------------------------------------------------------------------------------------------------------------------------------
|
|
fn replaceShaderScenObjs theMat theNewMat=
|
|
(
|
|
local theObjs = $objects as array
|
|
local theMatObjs = #()
|
|
for i in 1 to theObjs.count do
|
|
(
|
|
if theObjs[i].material == theMat then theObjs[i].material = theNewMat
|
|
)
|
|
theMatObjs
|
|
),
|
|
--------------------------------------------------------------------------------------------------------------------------------
|
|
-- fn findTextures -- finds the given texture in a material
|
|
--------------------------------------------------------------------------------------------------------------------------------
|
|
fn findTextures ThisTexture =
|
|
(
|
|
local notfound = true, res = false
|
|
if ThisTexture != undefined do
|
|
(
|
|
if ThisTexture == medit.GetCurMtl() do (res = true; notfound = false;)
|
|
texcount = (getNumSubTexmaps ThisTexture)
|
|
for i in 1 to texcount do
|
|
(
|
|
Texture = getSubTexMap ThisTexture i
|
|
findTextures (Texture)
|
|
)
|
|
)
|
|
res
|
|
),
|
|
--------------------------------------------------------------------------------------------------------------------------------
|
|
-- fn findParentMaterials -- finds the parent material of a texture
|
|
--------------------------------------------------------------------------------------------------------------------------------
|
|
fn findParentMaterials =
|
|
(
|
|
if classof (medit.GetTopMtlSlot (medit.GetActiveMtlSlot() )) != multimaterial then
|
|
(
|
|
theMaterial = ( medit.GetTopMtlSlot (medit.GetActiveMtlSlot() ))
|
|
theParentMaterial = theMaterial
|
|
theNum = 1
|
|
) else (
|
|
theMulti = ( medit.GetTopMtlSlot (medit.GetActiveMtlSlot() ))
|
|
submatcount = getNumSubMtls theMulti
|
|
for m in 1 to submatcount do
|
|
(
|
|
if theMulti[m] != undefined do
|
|
(
|
|
--check the subtextures
|
|
subtexcount = getNumSubTexmaps theMulti[m]
|
|
for i in 1 to subtexcount do
|
|
(
|
|
checkThis = findTextures (getSubTexMap theMulti[m] i)
|
|
if checkThis == true then
|
|
(
|
|
theNum = m
|
|
theMaterial = theMulti[m]
|
|
)
|
|
)
|
|
|
|
)
|
|
)
|
|
theParentMaterial = theMulti
|
|
)
|
|
datapair pMaterial:theParentMaterial mMaterial:(datapair mat:theMaterial num:theNum)
|
|
)
|
|
)
|
|
|
|
global grsSubstance = rsSubstanceFunctions()
|
|
|
|
struct rsSubstanceMaterialHolder
|
|
(
|
|
thePresetArray = undefined,
|
|
sceneHasSubstanceMaterials = false,
|
|
substanceObjects = #(),
|
|
substanceMaterials = #(),
|
|
tempMaterials = #(),
|
|
textureDataPairs = #(),
|
|
func1 = undefined, -- These functions are left undefined so that on create we can leverage functions from the rsSubstanceFunctions struct.
|
|
func2 = undefined,
|
|
func3 = undefined,
|
|
func4 = undefined,
|
|
iterateVal = 0,
|
|
conversion = false,
|
|
--------------------------------------------------------------------------------------------------------------------------------
|
|
-- fn checkForSubstanceTexture -- finds any substance texture that is used as an ambient map in the given material
|
|
--------------------------------------------------------------------------------------------------------------------------------
|
|
fn checkForSubstanceTexture mat =
|
|
(
|
|
retval = #()
|
|
if classof mat != multimaterial then
|
|
(
|
|
if mat != undefined and hasProperty mat #ambientmap and classof mat.ambientmap == rsSubstance do
|
|
(
|
|
append retval 1
|
|
)
|
|
) else
|
|
(
|
|
for m in 1 to mat.count where mat[m] != undefined AND hasProperty mat[m] #ambientmap AND classof mat[m].ambientmap == rsSubstance do
|
|
(
|
|
append retval m
|
|
)
|
|
)
|
|
retval
|
|
),
|
|
|
|
--------------------------------------------------------------------------------------------------------------------------------
|
|
-- fn findRsSubstanceInScene -- finds any object in the scene that is using a substance texture and adds that to material and object to the lists.
|
|
--------------------------------------------------------------------------------------------------------------------------------
|
|
fn findRsSubstanceInScene =
|
|
(
|
|
substanceObjects = #()
|
|
substanceMaterials = #()
|
|
tempMaterials = #()
|
|
textureDataPairs = #()
|
|
|
|
local theObjs = $objects as array
|
|
for i in 1 to theObjs.count do
|
|
(
|
|
local testMat = checkForSubstanceTexture theObjs[i].material
|
|
if testMat.count > 0 then
|
|
(
|
|
sceneHasSubstanceMaterials = true
|
|
isUnique = appendifUnique substanceMaterials theObjs[i].material
|
|
if isUnique == true then
|
|
(
|
|
append tempMaterials (copy theObjs[i].material )
|
|
append substanceObjects (datapair Material:(theObjs[i].material as string) objects:#(theObjs[i]))
|
|
) else
|
|
(
|
|
for o in 1 to substanceObjects.count do
|
|
(
|
|
hasMat =substanceObjects[o].material == (theObjs[i].material as string)
|
|
if hasMat == true then append substanceObjects[o].objects theObjs[i]
|
|
)
|
|
)
|
|
)
|
|
)
|
|
sceneHasSubstanceMaterials
|
|
),
|
|
|
|
--------------------------------------------------------------------------------------------------------------------------------
|
|
-- fn convertSceneToRage -- goes through the created lists of materials and objects and converts them to rage shaders.
|
|
--------------------------------------------------------------------------------------------------------------------------------
|
|
fn convertSceneToRage =
|
|
(
|
|
local submissionTextures = #()
|
|
local theRageMat = undefined
|
|
if sceneHasSubstanceMaterials == true then
|
|
(
|
|
Format "Converting Substance Materials to Rage Shaders:\n"
|
|
for m in SubstanceMaterials do
|
|
(
|
|
if classof m != multimaterial then
|
|
(
|
|
iterateVal = iterateVal+1
|
|
theMaps = (func2 m thePresetArray textureDataPairs iterateVal test:true )
|
|
for i in 1 to theMaps.count do
|
|
(
|
|
if (classof theMaps[i].map) == string then append submissionTextures theMaps[i].map
|
|
)
|
|
) else
|
|
(
|
|
theSubMats = (checkForSubstanceTexture m)
|
|
for sm in 1 to theSubMats.count do
|
|
(
|
|
iterateVal = iterateVal+1
|
|
theMaps = (func2 m[theSubMats[sm]] thePresetArray textureDataPairs iterateVal test:true )
|
|
for i in 1 to theMaps.count do
|
|
(
|
|
if (classof theMaps[i].map) == string then append submissionTextures theMaps[i].map
|
|
)
|
|
)
|
|
)
|
|
)
|
|
func3 submissionTextures
|
|
iterateVal = 0
|
|
for m in 1 to SubstanceMaterials.count do
|
|
(
|
|
mm = SubstanceMaterials[m]
|
|
if classof mm != multimaterial then
|
|
(
|
|
iterateVal = iterateVal+1
|
|
theMaps = (func2 mm thePresetArray textureDataPairs iterateVal test:false )
|
|
theRageMat = func4 mm theMaps
|
|
for i in 1 to substanceObjects[m].objects.count do
|
|
(
|
|
substanceObjects[m].objects[i].material = theRageMat
|
|
)
|
|
) else
|
|
(
|
|
theSubMats = (checkForSubstanceTexture mm)
|
|
for sm in 1 to theSubMats.count do
|
|
(
|
|
iterateVal = iterateVal+1
|
|
theMaps = (func2 mm[theSubMats[sm]] thePresetArray textureDataPairs iterateVal test:false )
|
|
theRageMat = func4 mm[theSubMats[sm]] theMaps
|
|
mm[theSubMats[sm]] = theRageMat
|
|
for i in 1 to substanceObjects[m].objects.count do
|
|
(
|
|
substanceObjects[m].objects[i].material = mm
|
|
)
|
|
)
|
|
)
|
|
)
|
|
|
|
)
|
|
),
|
|
|
|
--------------------------------------------------------------------------------------------------------------------------------
|
|
-- fn returnSceneToSubstance -- reverts any object in list back to a substance shader
|
|
--------------------------------------------------------------------------------------------------------------------------------
|
|
fn returnSceneToSubstance =
|
|
(
|
|
if sceneHasSubstanceMaterials == true then
|
|
(
|
|
for i in 1 to substanceObjects.count do
|
|
(
|
|
for o in substanceObjects[i].objects do
|
|
(
|
|
o.material = tempMaterials[i]
|
|
)
|
|
)
|
|
)
|
|
),
|
|
|
|
on create do
|
|
(
|
|
thePresetArray = (grsSubstance.makeRagePresetArray())
|
|
func2 = grsSubstance.renderSubstanceMaps
|
|
func3 = grsSubstance.checkRenderedMaps
|
|
func4 = grsSubstance.makeRageFromSubstance
|
|
max select none
|
|
)
|
|
)
|
|
|
|
global rsMaterialHolder = rsSubstanceMaterialHolder()
|
|
|
|
global ConvertRsSubstance
|
|
(try ConvertRsSubstance R1 catch())
|
|
Rollout ConvertRsSubstance "RS Substance Conversion"
|
|
(
|
|
local substancesConverted = false
|
|
Button B2 "Convert All Substance To Rage" width:230
|
|
Button B3 "Return All Rage to Substance" width:230
|
|
|
|
on B2 Pressed do (
|
|
rsMaterialHolder.convertSceneToRage()
|
|
substancesConverted = true
|
|
)
|
|
on B3 Pressed do (
|
|
rsMaterialHolder.returnSceneToSubstance()
|
|
substancesConverted = false
|
|
)
|
|
|
|
on R1 open do
|
|
(
|
|
rsMaterialHolder = rsSubstanceMaterialHolder()
|
|
rsMaterialHolder.findRsSubstanceInScene()
|
|
|
|
)
|
|
on R1 oktoclose do
|
|
(
|
|
if substancesConverted == true then querybox "You have unreverted Substances. Close?"
|
|
|
|
)
|
|
)
|
|
|