Files
gtav-src/tools_ng/wildwest/script/3dsMax/Maps/PxmUpgradeTool.ms
T
2025-09-29 00:52:08 +02:00

616 lines
16 KiB
Plaintext
Executable File

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