-- Additions by Allan Hayburn Jan 15 2013 filein "pipeline/util/RsUniversalLog.ms" global RsPropagateMaterialsRollout global gRsPropaMaterialUlogFile = ( RsConfigGetLogDir() + "PropagateMaterials.ulog" ) global gRsPropaMaterialUlog = sRsULog() try ( destroyDialog RsPropagateMaterialsRollout ) catch () struct RsMaxMaterial ( name = undefined, matid = undefined, sps = undefined, params = #() ) struct RsMaxObject ( name = undefined, handle = undefined, materials = #() ) struct RsPropagateMaterials ( fn storeMaterialData obj mat matid &rsMaxObj = ( local textures = #() if ( classof mat ) == Rage_Shader then ( if ( RstGetIsAlphaShader mat ) then ( local rsMat = RsMaxMaterial() rsMat.name = mat.name rsMat.matid = matid rsMat.sps = RstGetShaderName mat local numVars = RstGetVariableCount mat for varId = 1 to numVars do ( local varName = RstGetVariableName mat varId local varType = RstGetVariableType mat varId if varType == "texmap" then ( local diffuseTex = RstGetVariable mat varId local alphaTex = RstGetAlphaTextureName mat varId diffuseTex = toLower ( diffuseTex as string ) alphaTex = toLower ( alphaTex as string ) local param = DataPair constantName:varName data:( DataPair diffuseTexture:diffuseTex alphaTexture:alphaTex ) append rsMat.params param ) ) if rsMat.params.count > 0 then ( append rsMaxObj.materials rsMat ) ) ) ), fn collectMaterialData obj &sceneData = ( if ( classof obj ) == Editable_Mesh or ( classof obj ) == Editable_Poly then ( local rsObj = RsMaxObject() rsObj.name = obj.name rsObj.handle = obj.inode.handle local mat = obj.material if mat != undefined then ( if ( classof mat ) == MultiMaterial then ( for matId = 1 to mat.numsubs do ( local subMat = mat[ matId ] this.storeMaterialData obj subMat matId &rsObj ) ) else ( this.storeMaterialData obj mat undefined &rsObj ) ) if rsObj.materials.count > 0 then ( append sceneData rsObj ) ) ), fn getTabs tabLevel = ( local result = "" for i = 1 to tabLevel do ( result += "\t" ) result ), fn createSceneMaterialFile filename sourceFilename sceneData haveRev = ( if sceneData != undefined then ( local fstream = createFile filename local tabLevel = 1 format "\n" to:fstream format "\n" to:fstream format "%\n" ( this.getTabs tabLevel ) to:fstream tabLevel += 1 format "%%\n" ( this.getTabs tabLevel ) ( toLower sourceFilename ) to:fstream format "%%\n" ( this.getTabs tabLevel ) haveRev to:fstream tabLevel -=1 format "%\n" ( this.getTabs tabLevel ) to:fstream format "%\n" ( this.getTabs tabLevel ) to:fstream tabLevel += 1 for rsObj in sceneData do ( if rsObj != undefined then ( format "%\n" ( this.getTabs tabLevel ) rsObj.name rsObj.handle to:fstream tabLevel += 1 format "%\n" ( this.getTabs tabLevel ) to:fstream tabLevel += 1 for rsMat in rsObj.materials do ( format "%\n" ( this.getTabs tabLevel ) rsMat.name rsMat.matid rsMat.sps to:fstream tabLevel += 1 for param in rsMat.params do ( format "%\n" ( this.getTabs tabLevel ) param.constantName param.data.diffuseTexture param.data.alphaTexture to:fstream ) tabLevel -= 1 format "%\n" ( this.getTabs tabLevel ) to:fstream ) tabLevel -= 1 format "%\n" ( this.getTabs tabLevel ) to:fstream tabLevel -= 1 format "%\n" ( this.getTabs tabLevel ) to:fstream ) ) tabLevel -= 1 format "%\n" ( this.getTabs tabLevel ) to:fstream format "\n" to:fstream close fstream fstream = undefined gc() ) else ( print "No scene data to export! Wtf..." ) ), fn exportCurrentSceneMaterials sourceFilename haveRev = ( progressStart "Exporting materials..." local progress = 0 local sceneData = #() for obj in objects do ( this.collectMaterialData obj &sceneData progress += 1 progressUpdate ( 100 * progress / objects.count ) ) this.createSceneMaterialFile ( ( getdir #temp ) + "\\" + ( getFilenameFile sourceFilename ) + ".matxml" ) sourceFilename sceneData haveRev gRsPropaMaterialUlog.LogMessage ( "Created temporary propagate materials xml file at (" + ( ( getdir #temp ) + "\\" + ( getFilenameFile sourceFilename ) + ".matxml" ) + ")" ) progressEnd() ), fn importMatXml matxmlFilename = ( local result = undefined if ( doesFileExist matxmlFilename ) then ( result = #() local stream = dotNetObject "System.IO.StreamReader" matxmlFilename local doc = dotNetObject "System.Xml.XmlDocument" doc.load stream local root = doc.documentElement local objectNodes = root.SelectNodes ".//objects/object" -- Iterate over each object. for objId = 0 to ( objectNodes.count - 1 ) do ( local objNode = objectNodes.item[ objId ] local objName = objNode.Attributes.item[ 0 ].value local objHandle = ( objNode.Attributes.item[ 1 ].value ) as integer local rsObj = RsMaxObject() rsObj.name = objName rsObj.handle = objHandle local matNodes = objNode.SelectNodes ".//materials/material" -- Iterate over each material for the object. for matId = 0 to ( matNodes.count - 1 ) do ( local objMatNode = matNodes.item[ matId ] local objMatName = objMatNode.Attributes.item[ 0 ].value local objMatId = ( objMatNode.Attributes.item[ 1 ].value ) as integer local objMatSps = objMatNode.Attributes.item[ 2 ].value local rsMat = RsMaxMaterial() rsMat.name = objMatName rsMat.matid = objMatId rsMat.sps = objMatSps local paramNodes = objMatNode.SelectNodes ".//param" -- Iterate over each param for the material. for paramId = 0 to ( paramNodes.count - 1 ) do ( local paramNode = paramNodes.item[ paramId ] local paramConstantName = paramNode.Attributes.item[ 0 ].value local paramDiffuseTex = paramNode.Attributes.item[ 1 ].value local paramAlphaTex = paramNode.Attributes.item[ 2 ].value if paramAlphaTex == "undefined" then ( paramAlphaTex = undefined ) local param = DataPair constantName:paramConstantName data:( DataPair diffuseTexture:paramDiffuseTex alphaTexture:paramAlphaTex ) append rsMat.params param ) append rsObj.materials rsMat ) append result rsObj ) root = undefined stream = undefined doc = undefined gc() ) else ( messageBox "The file doesn't exist!" title:"Rockstar" ) result ), fn propagate sourceFilename fromRev toRev = ( gRsPropaMaterialUlog.Init "Propagate Materials" appendToFile:false forceLogFile:gRsPropaMaterialUlogFile -- Turn off RsRef system. RSrefAllowUpdate = false -- Get the file info for the source file. local fstats = ( gRsPerforce.getFileStats ( sourceFilename ) )[ 1 ] -- in case "haveRev" or "headRev" = undefined - A.H. if fstats.Item[ "haveRev" ] != undefined then haveRev = fstats.Item[ "haveRev" ] as integer if fstats.Item[ "headRev" ] != undefined then headRev = fstats.Item[ "headRev" ] as integer if toRev > headRev then ( messageBox "Cannot propagate to a file revision greater than the head revision! Aborting." title:"Rockstar" ) else ( clearListener() local sourceName = getFilenameFile sourceFilename -- This will be the exported .matxml filename. local matxmlFilename = ( getDir #temp ) + "\\" + sourceName + ".matxml" -- Reset max file. resetMaxFile #noPrompt -- made reset quiet - A.H. -- Sync to the FROM revision. gRsPerforce.sync ( sourceFilename + "#" + fromRev as string ) gRsPropaMaterialUlog.LogMessage ( "Synced to version " + fromRev as string + " for file (" + sourceFilename + ")." ) --adding file check - A.H. checkSyncedFromFile = doesfileExist sourceFilename if checkSyncedFromFile == false then ( local msg = "(" + sourceFilename + ") at revision (" + fromRev as string + ") could not be found! Check perforce revision." messageBox msg title:"Rockstar" gRsPropaMaterialUlog.LogError msg gRsPerforce.sync ( sourceFilename + "#" + toRev as string ) gRsPropaMaterialUlog.validate() return false ) local ext = getFilenameType sourceFilename -- Open the source file. if ext == ".maxc" then ( local sourceContainer = Containers.CreateInheritedContainer sourceFilename if sourceContainer != undefined then ( if sourceContainer.CanEditInPlace() then ( sourceContainer.LoadContainer() sourceContainer.MakeUnique() if not sourceContainer.IsUnique() then ( local msg = "The container for (" + sourceFilename + ") at revision (" + fromRev as string + ") could not be made unique! Aborting material propagation." messageBox msg title:"Rockstar" gRsPropaMaterialUlog.LogError msg return false ) gRsPropaMaterialUlog.LogMessage "Successfully opened container." ) else ( local msg = "The container for (" + sourceFilename + ") could not be opened! Aborting material propagation." messageBox msg title:"Rockstar" gRsPropaMaterialUlog.LogError msg return false ) ) else ( local msg = "Could not inherit the container for (" + sourceFilename + ")! Aborting material propagation." messageBox msg title:"Rockstar" gRsPropaMaterialUlog.LogError msg return false ) ) else if ext == ".max" then ( loadMaxFile sourceFilename quiet:true-- made load quiet - A.H. ) -- Export the scene materials to disk. this.exportCurrentSceneMaterials sourceFilename fromRev gRsPropaMaterialUlog.LogMessage "Successfully exported materials." -- Make sure the .matxml filename exists. if ( doesFileExist matxmlFilename ) then ( -- Reset the current file. resetMaxFile #noPrompt -- Sync to the version of the file we are propagating the materials TO. gRsPerforce.sync ( sourceFilename + "#" + toRev as string ) gRsPropaMaterialUlog.LogMessage ( "Synced to version " + toRev as string + " for file (" + sourceFilename + ")." ) -- Reopen the TO version of the file. if ext == ".maxc" then ( local sourceContainer = Containers.CreateInheritedContainer sourceFilename if sourceContainer != undefined then ( if sourceContainer.CanEditInPlace() then ( sourceContainer.LoadContainer() if sourceContainer.MakeUnique() then ( sourceContainer.sourceDefinitionFilename = sourceFilename ) else ( local msg = "The container for (" + sourceFilename + ") at revision (" + toRev as string + ") could not be made unique! Aborting material propagation." messageBox msg title:"Rockstar" gRsPropaMaterialUlog.LogError msg return false ) ) else ( local msg = "Could not 'Edit in Place' the container for (" + sourceFilename + ")! Aborting material propagation." messageBox msg title:"Rockstar" gRsPropaMaterialUlog.LogError msg return false ) ) else ( local msg = "Could not inherit the container for (" + sourceFilename + ")! Aborting material propagation." messageBox msg title:"Rockstar" gRsPropaMaterialUlog.LogError msg return false ) ) else if ext == ".max" then ( loadMaxFile sourceFilename quiet:true -- made load quiet - A.H. gRsPropaMaterialUlog.LogMessage ( "Opened file (" + sourceFilename + ")." ) ) -- Import and replace the materials. local rsObjs = this.importMatXml matxmlFilename gRsPropaMaterialUlog.LogMessage ( "Successfully imported the propagation material xml file from (" + matxmlFilename + ")." ) if rsObjs != undefined then ( progressStart "Importing materials..." local progress = 0 for rsObj in rsObjs do ( -- First find the object by handle. local realObj = maxops.getNodeByHandle rsObj.handle if realObj != undefined then ( local doContinue = true -- Check to see if the object was renamed and ask what they'd like to do. if realObj.name != rsObj.name then ( local msg = "Found an object name mismatch!\n\nObject named (" + rsObj.name + ") in revision (" + fromRev + ") is now named (" + realObj.name + ") in revision (" + toRev + ").\n\nWould you like to propagate materials to this renamed object?" if ( queryBox msg title:"Rockstar" beep:false ) then ( doContinue = false ) ) if doContinue then ( if realObj.material != undefined then ( local realMat = realObj.material if ( classof realMat ) == Multimaterial then ( for prevMat in rsObj.materials do ( if ( findItem realMat.materialIdList prevMat.matid ) != 0 then ( local realSubMat = realMat.materialList[ prevMat.matid ] if ( classof realSubMat ) == Rage_Shader then ( local spsName = RstGetShaderName realSubMat local propaMaterialParams = true if spsName != prevMat.sps then ( local msg = "Found an sps name mismatch between revisions! Attempt to propagate material anyway?\n\nFROM: " + prevMat.sps + "\n\nTO: " + spsName if ( queryBox msg title:"Rockstar" beep:false ) then ( propaMaterialParams = false ) ) if propaMaterialParams then ( for param in prevMat.params do ( local numParams = RstGetVariableCount realSubMat for paramId = 1 to numParams do ( local paramName = RstGetVariableName realSubMat paramId if paramName == param.constantName then ( RstSetVariable realSubMat paramId param.data.diffuseTexture if ( RstGetIsAlphaShader realSubMat ) then ( RstSetAlphaTextureName realSubMat paramId param.data.alphaTexture ) local msg = "Propagated material (" + realSubMat.name + ") on object (" + realObj.name + ") from file revision (" + fromRev as string +") to revision (" + toRev as string + ")." format "%\n" msg gRsPropaMaterialUlog.LogMessage msg ) ) ) ) else ( local msg = "Skipping propagation for material (" + realSubMat.name + ") on object (" + realObj.name + ") using material id (" + prevMat.matid as string + ")." format "[WARNING] %\n" msg gRsPropaMaterialUlog.LogWarning msg ) ) else ( local msg = "The material (" + realSubMat.name + ") is not a Rage shader, when the old one was! Skipping propagation for this material." format "[WARNING] %\n" msg gRsPropaMaterialUlog.LogWarning msg ) ) else ( local msg = "Could not find the material id (" + prevMat.matid as string + ") on material (" + realMat.name + ") on object (" + realObj.name + ")! Skipping propagation for this material." format "[WARNING] %\n" msg gRsPropaMaterialUlog.LogWarning msg ) ) ) else ( print "not a multimaterial" ) ) else ( local msg = "The object (" + realObj.name + ") no longer has a material assigned! Cannot propagate this object's material." messageBox msg title:"Rockstar" format "[WARNING] %\n" msg gRsPropaMaterialUlog.LogWarning msg ) ) else ( local msg = "[WARNING] Skipping material propagation for object (" + realObj.name + ")." gRsPropaMaterialUlog.LogWarning msg ) ) else ( local msg = "Could not find an object named (" + rsObj.name + ") using handle (" + rsObj.handle as string + ")! Skipping material propagation for this object." messageBox msg title:"Rockstar" format "[WARNING] %\n" msg gRsPropaMaterialUlog.LogWarning msg ) progressUpdate ( 100 * progress / rsObjs.count ) progress += 1 ) progressEnd() messageBox "Finished propagating materials! Please check to make sure everything propagated correctly." title:"Rockstar" ) else ( local msg = "An unknown error occurred reading in the file (" + matxmlFilename + ")! Aborting material propagation." messageBox msg title:"Rockstar" gRsPropaMaterialUlog.LogError msg ) ) else ( local msg = "Could not find the file (" + matxmlFilename + ")! Something went wrong during the material export process.\n\nAborting material propagation." messageBox msg title:"Rockstar" ) ) RSrefAllowUpdate = true gRsPropaMaterialUlog.validate() ) ) rollout RsPropagateMaterialsRollout "Rockstar - Propagate Materials" ( local propaMaterials = RsPropagateMaterials() local haveRev = undefined local headRev = undefined dotNetControl rsBannerPanel "Panel" pos:[0,0] height:32 width:RsPropagateMaterialsRollout.width local banner = makeRsBanner dn_Panel:rsBannerPanel wiki:"propagate materials" filename:(getThisScriptFilename()) edittext etMaxFilename "Max Filename" labelOnTop:true readOnly:true width:348 across:2 button btnPickMaxFilename "..." offset:[ 88, 16 ] label lbCurrentRevision "Current Revision: " align:#left label lbSep01 "" group "Propagate Materials" ( spinner spFromRevision "From Revision:" type:#integer width:90 across:2 offset:[ -24, 0 ] spinner spToRevision "To Revision:" type:#integer width:90 offset:[ -90, 0 ] ) button btnProcess "Process" width:390 height:32 on btnPickMaxFilename pressed do ( result = getOpenFilename filename:( RsConfigGetProjRootDir() + "art\\" ) caption:"Choose a 3dsmax File to Propagate Materials" types:"3dsmax (*.max;*.maxc)|*.max;*.maxc|" if result != undefined then ( etMaxFilename.text = result local fstats = ( gRsPerforce.getFileStats ( result ) )[ 1 ] -- in case "haveRev" or "headRev" = undefined - A.H. if fstats.Item[ "haveRev" ] != undefined then haveRev = fstats.Item[ "haveRev" ] as integer if fstats.Item[ "headRev" ] != undefined then headRev = fstats.Item[ "headRev" ] as integer lbCurrentRevision.text = "Current Revision: " + haveRev as string spFromRevision.range = [ 1, headRev, haveRev ] spToRevision.range = [ 1, headRev, headRev ] ) ) on btnProcess pressed do ( --Added check that there is a filename - A.H. if etMaxFilename.text != "" then propaMaterials.propagate etMaxFilename.text spFromRevision.value spToRevision.value ) on RsPropagateMaterialsRollout open do ( banner.setup() ) ) createDialog RsPropagateMaterialsRollout width:400 height:166 style:#(#style_resizing,#style_titlebar, #style_toolwindow, #style_sysmenu)