filein (RsConfigGetWildWestDir() + "script/3dsmax/_config_files/wildwest_header.ms") struct TextureDataStruct ( normFileName, normName, heightMapName, rageShaderDeps = #() --DataPair shadername: shaderType: ) struct PXMUpgradeStruct ( pxmShaders = for sps in RsGetShaderList() where (matchpattern sps pattern:"*pxm*") collect sps, csvPath = "X:/gta5/Docs/art/Maps/NG/Terrain_normal_textures.csv", nxgTexPath = (RsConfigGetArtDir() + "textures/NXG/....bmp"), textureList = #(), sceneCandidates = #(), actionCandidates = #(), missingHMMaterials = #(), shaderOriginal = #("terrain_cb_w_4lyr_2tex_blend", "terrain_cb_w_4lyr_2tex_blend_ttn", "terrain_cb_w_4lyr_2tex_blend_tt", "terrain_cb_w_4lyr_cm", "terrain_cb_4lyr_2tex", "terrain_cb_4lyr", "terrain_cb_w_4lyr_cm_tnt", "terrain_cb_w_4lyr_spec_int", "terrain_cb_w_4lyr_spec", "terrain_cb_w_4lyr" ), shaderPXM = #("terrain_cb_w_4lyr_2tex_blend_pxm_spm", "terrain_cb_w_4lyr_2tex_blend_pxm_tn_spm", "terrain_cb_w_4lyr_2tex_blend_pxm_tt_spm", "terrain_cb_w_4lyr_cm_pxm", "terrain_cb_4lyr_2tex_pxm", "terrain_cb_4lyr_pxm", "terrain_cb_w_4lyr_cm_tnt_pxm", "terrain_cb_w_4lyr_spec_int_pxm", "terrain_cb_w_4lyr_spec_pxm", "terrain_cb_w_4lyr_pxm" ), hmPathRoot = (RsConfigGetArtDir() + "textures/NXG/Terrain_POM/"), matLookup = #(), /*** Parse the Terrain_normal_textures.csv ***/ fn parseCSV = ( free textureList fh = openfile csvPath while not eof fh do ( local theLine = filterString (tolower(readline fh)) "," if theLine[2] != "~" do ( local texData = TextureDataStruct() texData.normFileName = theLine[1] texData.normName = getFilenameFile theLine[1] texData.heightMapName = theLine[2] append textureList texData ) --for item in (filterString (readline fh) ",") collect (trimLeft item) --append textureList theLine ) close fh --print textureList ), /*** Build a lookup for scene bitmaps to the rage_shader materials they use ***/ fn buildMatLookup = ( local bitmaps = getClassInstances Bitmaptexture local bitmapNames = for item in bitmaps where (item.fileName != undefined) collect toLower(getfilenamefile item.fileName) --local matLookup = #() --dict = dotnetobject "RSG.MaxUtils.MaxDictionary" local rageMats = getClassInstances Rage_Shader for mat in rageMats do ( local rageBitmapNames = for bm in (RsGetTexPathsFromMat mat) collect (tolower(getFilenameFile bm)) for bm in rageBitmapNames do ( local idx = findItem bitmapNames bm if (idx != 0) do ( if matLookup[idx] == undefined then ( matLookup[idx] = #(mat) ) else ( appendIfUnique matLookup[idx] mat ) ) ) ) --print matLookup ), /*** Find materials from scene bitmaps ***/ fn findMaterials = ( local bitmaps = getClassInstances Bitmaptexture local bitmapNames = for item in bitmaps where (item.fileName != undefined) collect toLower(getfilenamefile item.fileName) --match a bitmap against any in the textureList for tex in textureList do ( local idx = findItem bitmapNames (toLower (tex.normName)) if (idx != 0) then ( --print bitmapNames[idx] --local matMatches = for item in refs.dependents bitmaps[idx] where classOf item == Rage_Shader collect item local matMatches = matLookup[idx] local matShaderMatches = #() if matMatches != undefined then ( matShaderMatches = for item in matMatches where (findItem shaderOriginal (getFilenameFile(RstGetShaderName item)) != 0) --or (findItem shaderPXM (getFilenameFile(RstGetShaderName item)) != 0) collect (DataPair material:item shader:(getFilenameFile(RstGetShaderName item))) ) tex.rageShaderDeps = matShaderMatches ) ) ), /*** Filter out any texture data objects in the textureList that have no valid shaders ***/ fn getSceneCandidates = ( sceneCandidates = for item in textureList where item.rageShaderDeps.count != 0 collect item ), /*** ***/ fn harvestActionCandidates actionNames = ( local materialList = #() for tex in textureList do ( local materialNames = for mat in tex.rageShaderDeps collect mat.material.name local foundOne = false for item in materialNames while (foundOne == false) do ( if (findItem actionNames item) != 0 do ( appendIfUnique actionCandidates tex foundOne = true ) ) ) ), /*** If the shader is legacy swap for a pxm version and fill in the heightmap slots where we can if it already is a pxm shader then the heightmap slots should be filled where possible ***/ fn swapPXM debug:false = ( --dCounter = 1 for texData in actionCandidates do ( --get the material local matList = texData.rageShaderDeps format "matList.count: % \n" matList.count for item in matList do ( local mat = item.material local pxmShader = undefined local mapIdx = findItem shaderOriginal item.shader if (mapIdx != 0) then ( pxmShader = shaderPXM[mapIdx] ) --is it already a pxm shader local isPXM = undefined if (mapIdx == 0) then ( isPXM = (findItem shaderPXM item.shader) ) --set the new shader name if we can if (pxmShader != undefined) do ( RstSetShaderName mat (pxmShader + ".sps") ) --find the shadervar local normTex = undefined for i = 1 to (RstGetVariableCount mat) where ((RstGetVariableType mat i) == "texmap") and (MatchPattern (RstGetVariableName mat i) pattern:"*Bump*") do ( local thisNorm = tolower(getFilenameFile(RstGetVariable mat i)) local thisNormPath = tolower(getFilenamePath(RstGetVariable mat i)) if (thisNorm == texData.normName) do ( --get the path and append the heightmap name local hmPath = hmPathRoot + texData.heightMapName + ".bmp" format "thisNorm: % normName: % \n" thisNorm texData.normName --replace the normal for the nxg_ version if it exists local nxgNormPath = (thisNormPath + "nxg_" + thisNorm + ".bmp") --print nxgNormPath if doesFileExist nxgNormPath then ( RstSetVariable mat i nxgNormPath ) --does that path exist if not (doesFileExist hmPath) then --try to sync it ( local success = gRsPerforce.sync #(hmPath) if not success then format "couldnt sync texture: % \n" hmPath ) --set the heightmap tex if (not debug) then ( --meditmaterials[dCounter] = mat --print (RstGetVariableType mat (i+1)) --print (RstGetVariableName mat (i+1)) if (RstGetVariableName mat (i+1) != undefined) and (MatchPattern (RstGetVariableName mat (i+1)) pattern:"Height*") do ( RstSetVariable mat (i+1) hmPath ) ) ) ) ) --dCounter += 1 ) ), fn fixupMissingHM mat = ( if (mat == undefined) do return false --find the shadervar local normTex = undefined for i = 1 to (RstGetVariableCount mat) where ((RstGetVariableType mat i) == "texmap") and (MatchPattern (RstGetVariableName mat i) pattern:"*Bump*") do ( local rawPath = tolower(RstGetVariable mat i) local thisNorm = getFilenameFile rawPath local thisNormPath = getFilenamePath rawPath --find the normal and HM for it local heightMapName = undefined for tex in textureList while (heightMapName == undefined) do ( if (tex.normName == thisNorm) then ( heightMapName = tex.heightMapName ) ) if (heightMapName != undefined) then ( --get the path and append the heightmap name local hmPath = hmPathRoot + heightMapName + ".bmp" format "thisNorm: % heightMapName: % \n" thisNorm heightMapName --replace the normal for the nxg_ version if it exists local nxgNormPath = (thisNormPath + "nxg_" + thisNorm + ".bmp") --print nxgNormPath if doesFileExist nxgNormPath then ( RstSetVariable mat i nxgNormPath ) --does that path exist if not (doesFileExist hmPath) then --try to sync it ( local success = gRsPerforce.sync #(hmPath) if not success then format "couldnt sync texture: % \n" hmPath ) --set the heightmap tex --if (not debug) then --( --meditmaterials[dCounter] = mat --print (RstGetVariableType mat (i+1)) --print (RstGetVariableName mat (i+1)) if (RstGetVariableName mat (i+1) != undefined) and (MatchPattern (RstGetVariableName mat (i+1)) pattern:"Height*") do ( RstSetVariable mat (i+1) hmPath ) --) ) ) ), /*** List any pxm shaders with empty heightmap slots or with dummy NXG_DELETE_H.bmp ***/ fn listMissingHM = ( free missingHMMaterials local rageMats = for shd in (getClassInstances Rage_Shader) where ((finditem shaderPXM (getFilenameFile((RstGetShaderName shd)))) != 0) collect shd --print rageMats.count --now go through and check for any missing heightmap slots for mat in rageMats do ( for i = 1 to (RstGetVariableCount mat) where ((RstGetVariableType mat i) == "texmap") and (MatchPattern (RstGetVariableName mat i) pattern:"Height*") do ( if ((RstGetVariable mat i) == "") or (MatchPattern (getFilenameFile(RstGetVariable mat i)) pattern:"*NXG_DELETE_H*" != false) do ( appendifunique missingHMMaterials mat ) ) ) ) ) --///////////////////////////////////////// -- UI --///////////////////////////////////////// --try(destroyDialog PXMUpgradeUI)catch() rollout PXMUpgradeUI "POM HeightMap Slot Stuffer" width:300 height:460 ( --///////////////////////////////////////// -- VARIABLES --///////////////////////////////////////// local PXMUpgrade = PXMUpgradeStruct() local mlbItemMats = #() local mlbItems = #() local candidateMap = #() --///////////////////////////////////////// -- CONTROLS --///////////////////////////////////////// --dotNetControl rsBannerPanel "Panel" pos:[0,0] height:32 width:PXMUpgradeUI.width --local banner = makeRsBanner dn_Panel:rsBannerPanel wiki:"CHANGEME" versionNum:1.02 versionName:"Yielding Playground" filename:(getThisScriptFilename()) timer ctrlState interval:5000 active:false group "Materials" ( multilistbox mlbMaterials height:20 ) group "" ( dotNetControl btnListMissingHM "Button" text:"Missing HM" width:(PXMUpgradeUI.width - 25) height:dnStyle.stdButtonHeight offset:[0, -5] dotNetControl btnfixMissingHM "Button" text:"Fix" width:(PXMUpgradeUI.width - 25) height:dnStyle.stdButtonHeight ) group "" ( dotNetControl btnRefreshList "Button" text:"Refresh" height:dnStyle.stdButtonHeight across:3 align:#left offset:[0, -5] dotNetControl btnDoUpgrade "Button" text:"Scene Upgrade" width:160 height:dnStyle.stdButtonHeight offset:[0, -5] checkbox chkAll "All" align:#right offset:[0, -2] ) --///////////////////////////////////////// -- FUNCTIONS --///////////////////////////////////////// /*** Sync the textures and lookup csv ***/ fn syncResources = ( --sync any nextgen textures gRsPerforce.sync #(PXMUpgrade.nxgTexPath) --sync latest report pushPrompt "Syncing textures..." gRsPerforce.sync #(PXMUpgrade.csvPath) popPrompt() ) /*** Refresh material list ***/ fn refreshMatList = ( syncResources() PXMUpgrade.parseCSV() PXMUpgrade.buildMatLookup() PXMUpgrade.findMaterials() PXMUpgrade.getSceneCandidates() mlbItemMats = #() mlbItems = #() mlbMaterials.items = #() candidateMap = #() tempItems = #() for i=1 to PXMUpgrade.sceneCandidates.count do ( join tempItems PXMUpgrade.sceneCandidates[i].RageShaderDeps for j=1 to PXMUpgrade.sceneCandidates[i].RageShaderDeps.count do ( append candidateMap i ) ) mlbItemMats = for item in tempItems collect item.material mlbItemMats = makeUniqueArray mlbItemMats mlbItems = for item in tempItems collect item.material.name mlbItems = makeUniqueArray mlbItems --print mlbItems mlbMaterials.items = mlbItems ) --///////////////////////////////////////// -- EVENTS --///////////////////////////////////////// --///////////////////////////////////////// -- --///////////////////////////////////////// on btnListMissingHM click do ( --set style dnStyle.setExecuteStyle btnListMissingHM syncResources() --btnDoUpgrade.enabled = false chkAll.enabled = false PXMUpgrade.listMissingHM() if (PXMUpgrade.missingHMMaterials.count > 0 ) do ( mlbMaterials.items = for item in PXMUpgrade.missingHMMaterials collect item.name mlbItemMats = PXMUpgrade.missingHMMaterials ) --set style ctrlState.active = true dnStyle.setSuccessStyle btnListMissingHM ) --///////////////////////////////////////// -- --///////////////////////////////////////// on btnfixMissingHM click do ( --set style dnStyle.setExecuteStyle btnfixMissingHM syncResources() local actionNames = for idx in mlbMaterials.selection collect mlbMaterials.items[idx] actionNames = makeUniqueArray actionNames --print actionNames --PXMUpgrade.harvestActionCandidates actionNames local terrainMats = #() for mat in PXMUpgrade.matLookup where (mat != undefined) do ( join terrainMats mat ) terrainMats = makeUniqueArray terrainMats for item in actionNames do ( --find the material from its name local theMat = undefined for mat in terrainMats while (theMat == undefined) do ( if (mat.name == item) then ( theMat = mat ) ) --got the mat, now update the HM slots PXMUpgrade.fixupMissingHM theMat ) mlbMaterials.items = #() --set style ctrlState.active = true dnStyle.setSuccessStyle btnfixMissingHM ) --///////////////////////////////////////// -- --///////////////////////////////////////// on btnRefreshList click do ( --set style dnStyle.setExecuteStyle btnRefreshList syncResources() btnDoUpgrade.enabled = true chkAll.enabled = true refreshMatList() --set style ctrlState.active = true dnStyle.setSuccessStyle btnRefreshList ) --///////////////////////////////////////// -- --///////////////////////////////////////// on mlbMaterials doubleClicked arg do ( MatEditor.open() meditmaterials[1] = mlbItemMats[arg] ) --///////////////////////////////////////// -- --///////////////////////////////////////// on chkAll changed arg do ( case arg of ( true:mlbMaterials.selection = #{1..mlbMaterials.items.count} false:mlbMaterials.selection = #{} ) ) --///////////////////////////////////////// -- --///////////////////////////////////////// on btnDoUpgrade click do ( --set style dnStyle.setExecuteStyle btnDoUpgrade --build actionable material list by matching the the selected ui item name to material names local actionNames = for idx in mlbMaterials.selection collect mlbMaterials.items[idx] actionNames = makeUniqueArray actionNames PXMUpgrade.harvestActionCandidates actionNames --PXMUpgrade.actionCandidates = for item in mlbMaterials.selection collect PXMUpgrade.sceneCandidates[item] --for item in PXMUpgrade.textureList where item.rageShaderDeps.count != 0 do print item PXMUpgrade.swapPXM() --refreshMatList() mlbMaterials.selection = #{} chkAll.state = false --set style ctrlState.active = true dnStyle.setSuccessStyle btnDoUpgrade ) --///////////////////////////////////////// -- Switch control state on timer trigger --///////////////////////////////////////// on ctrlState tick do ( dnStyle.setDormantStyle btnListMissingHM dnStyle.setDormantStyle btnfixMissingHM dnStyle.setDormantStyle btnRefreshList dnStyle.setDormantStyle btnDoUpgrade ctrlState.active = false ) --///////////////////////////////////////// -- --///////////////////////////////////////// on PXMUpgradeUI open do ( --banner.setup() --set button styles dnStyle.initButtonStyle btnListMissingHM dnStyle.initButtonStyle btnfixMissingHM dnStyle.initButtonStyle btnRefreshList dnStyle.initButtonStyle btnDoUpgrade windows.processPostedMessages() ) ) --createDialog PXMUpgradeUI