Files
2025-09-29 00:52:08 +02:00

546 lines
15 KiB
Plaintext
Executable File

--
-- File:: rockstar/helpers/TextureStats.ms
-- Description:: 3dsMax Rage Shader Texture Map Statistics
--
-- Author:: David Muir <david.muir@rockstarnorth.com>
-- Date:: 22 June 2007
--
-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
-- Rollout
-----------------------------------------------------------------------------
try (destroyDialog RsTextureMapStatsRoll) catch ()
filein "rockstar/util/mapobj.ms"
rollout RsTextureMapStatsRoll "Texture Map Statistics"
(
-----------------------------------------------------------------------------------------
-- Script-scope Variables
-----------------------------------------------------------------------------------------
local headers = #( "Texture Map", "Objects", "Object\nCount", "TXDs", "TXD\nCount")
local widths = #( 800, 3200, 2600, 3200, 2600, 3200, 2600 )
local idxTXD = GetAttrIndex "Gta Object" "TXD"
-----------------------------------------------------------------------------------------
-- UI Widgets and Layout
-----------------------------------------------------------------------------------------
button btnUpdate "Update" align:#left width:100 height:28 offset:[-8,0] across:6
checkbox chkSelection "Selection Only" pos:(btnUpdate.pos + [104,0])
checkbox chkIncRefs "Include Refs" pos:(chkSelection.pos + [0,14])
editText txtFilter "Filter:" text:"*" pos:(chkSelection.pos + [100,1])
dotNetControl barProgress "Windows.Forms.Progressbar" height:10 pos:(txtFilter.pos + [txtFilter.width + 10,3])
hyperlink lnkHelp "Help?" offset:[0,3] address:"https://devstar.rockstargames.com/wiki/index.php/Texture_Stats" align:#right color:(color 0 0 255) hoverColor:(color 0 0 255) visitedColor:(color 0 0 255)
dotNetControl lstTextures "RsCustomDataGridView" align:#center
bitmap bmpPreview width:256 height:256 pos:(lstTextures.pos + [0,1])
local notFoundText = "FILE NOT FOUND"
local notFoundOffset = [128, 128] - (getTextExtent notFoundText) / 2
label lblNotFound notFoundText pos:(bmpPreview.pos + notFoundOffset) visible:false
dotNetControl txtBmpInfo "MaxCustomControls.MaxTextBox" width:256 pos:(bmpPreview.pos + [0,bmpPreview.height])
------------------------------------------------------------------------------------
-- DotNet values:
------------------------------------------------------------------------------------
local textFont, dingFont, textFontBold
local DNknownColour = dotNetClass "system.Drawing.KnownColor"
local DNcolour = dotNetClass "System.Drawing.Color"
local selColour = DNcolour.fromKnownColor DNknownColour.MenuHighlight
local textCol = (colorMan.getColor #windowText) * 255
local windowCol = (colorMan.getColor #window) * 255
local notLoadedCol = if (windowCol[1] < 128) then (windowCol * 1.5) else (windowCol * 0.85)
local textColour = DNcolour.FromArgb textCol[1] textCol[2] textCol[3]
local backColour = DNcolour.FromArgb windowCol[1] windowCol[2] windowCol[3]
-----------------------------------------------------------------------------------------
-- Functions
-----------------------------------------------------------------------------------------
fn GetIniRolloutSize =
(
RsSettingsReadValue "RsTextureMapStatsRoll" "size" [1015, 520]
)
fn arrangeCtrls size:[RsTextureMapStatsRoll.width, RsTextureMapStatsRoll.height] =
(
bmpPreview.pos.x = size.x - bmpPreview.width
lblNotFound.pos.x = bmpPreview.pos.x + notFoundOffset.x
txtBmpInfo.pos.x = bmpPreview.pos.x
txtBmpInfo.height = size.y - txtBmpInfo.pos.y
lstTextures.width = size.x - bmpPreview.width
lstTextures.height = size.y - lstTextures.pos.y
barProgress.width = size.x - barProgress.pos.x - 54
lnkHelp.pos.x = size.x - 40
)
-- Fill out texture-list:
fn update doSelected:chkSelection.checked doRefs:chkIncRefs.checked =
(
lstTextures.Rows.Clear()
barProgress.value = 0.0
struct textureInfoStruct (name, path, showPath, texMap, objs=#(), txds=#())
local texInfoList = #()
local texPathList = #()
local objs = if doSelected then (selection as array) else (objects as array)
objs = for obj in objs where (GetAttrClass obj == "Gta Object") collect obj
-- Mark objects as being refs, and ignore if not used.
local refNamesUsed = #()
local refsDefsUsed = #()
local objItems = #()
for obj in objs do
(
local isRef = isRSref obj includeDelegates:true
if doRefs or not isRef do
(
local objNum = 0
if isRef do
(
objNum = findItem refNamesUsed obj.objectName
)
if (objNum == 0) then
(
append objItems (dataPair objs:#(obj) isRef:isRef)
if isRef do
(
append refNamesUsed obj.objectName
append refsDefsUsed obj.refDef
)
)
else
(
if isRef do
(
append objItems[objNum].objs obj
)
)
)
)
-- Load RsRef txd data:
if (refsDefsUsed.count != 0) do
(
RsRefFuncs.loadTxds refsDefsUsed
)
local objCount = objItems.count
local objNum = 0
local filterPattern = "*" + txtFilter.text + "*"
local showPathFilter = RsConfigGetTextureSourceDir() + "*"
--local timestart = timeStamp()
-- Holding down Escape will stop processing:
for item in objItems while not keyboard.escPressed do
(
barProgress.value = 100.0 * (objNum += 1) / objCount
local obj = item.objs[1]
local isRef = item.isRef
-- Get texturemap paths from object:
local objMatIds = RsGetMatIdsUsedByObj (if (isRef or (isRsInternalRef obj)) then (copy obj.mesh) else obj)
local objTexMapPaths = RsGetTexPathsFromMat obj.mat matIds:objMatIds
local objTexMapNames = for filename in objTexMapPaths collect (RsRemovePathAndExtension filename)
local txdname = ""
if (objTexMapNames.count != 0) do
(
if isRef then
(
case of
(
(isRsInternalRef obj):
(
local sourceObj = obj.getSourceObj()
txdname = GetAttr sourceObj idxTXD
)
(obj.refDef != undefined):
(
txdname = obj.refDef.txd
)
)
)
else
(
txdname = GetAttr obj idxTXD
)
)
-- Process texture list
for n = 1 to objTexMapNames.count where (isKindOf objTexMapNames[n] string) and (matchPattern objTexMapNames[n] pattern:filterPattern) do
(
local texName = objTexMapNames[n]
local texPath = objTexMapPaths[n]
local listId = findItem texPathList texPath
if (listId == 0) do
(
local showPath = if matchPattern texPath pattern:showPathFilter then
(
showPath = subString texPath showPathFilter.count -1
)
else texPath
local newTexInfo = textureInfoStruct name:texName path:texPath showPath:showPath
append texInfoList newTexInfo
append texPathList texPath
listId = texInfoList.count
)
local texInfo = texInfoList[listId]
join texInfo.objs item.objs
appendIfUnique texInfo.txds txdname
)
)
--format "Time taken: %s\n" ((timeStamp() - timestart) / 1000.0)
for texInfo in texInfoList do
(
texInfo.objs = makeUniqueArray texInfo.objs
)
-- Function to generate comma-separated list-string:
fn makeListString list =
(
local outStream = stringStream ""
for i = 1 to list.count do
(
format "%" list[i] to:outStream
if (i != list.count) do
(
format ", " to:outStream
)
)
return (outStream as string)
)
-- Populate listview
for texInfo in texInfoList do
(
local objsString = makeListString (for obj in texInfo.objs collect obj.name)
local txdsString = makeListString texInfo.txds
local rowData = #(texInfo.name, objsString, texInfo.objs.count, txdsString, texInfo.txds.count)
local rowNum = lstTextures.Rows.add rowData
-- Add texInfo struct as row-tag:
lstTextures.Rows.item[rowNum].tag = dotNetMXSValue texInfo
)
lstTextures.AutoResizeColumns()
local maxAutoWidth = 220
for colNum = 0 to (lstTextures.columns.count - 1) do
(
local col = lstTextures.columns.item[colNum]
if (col.width > maxAutoWidth) do
(
col.width = maxAutoWidth
)
)
lstTextures.ClearSelection()
barProgress.value = 0.0
)
fn updateText =
(
if lstTextures.selectedRows.count == 0 do
(
txtBmpInfo.text = ""
return false
)
local selRowsInfo = for n = 0 to (lstTextures.selectedRows.count - 1) collect lstTextures.selectedRows.item[n].tag.value
local textStream = stringstream ""
local texPaths = #()
local texObjs = #()
local texTxds = #()
for texInfo in selRowsInfo do
(
append texPaths texInfo.showPath
join texObjs texInfo.objs
join texTxds texInfo.txds
)
texObjs = makeUniqueArray texObjs
texTxds = makeUniqueArray texTxds
format "Textures:\n" to:textStream
for texPath in texPaths do
(
format "%\n" texPath to:textStream
)
format "\nTXDs:\n" to:textStream
for texTxd in texTxds do
(
format "%\n" texTxd to:textStream
)
format "\nObjects:\n" to:textStream
for obj in texObjs do
(
format "%\n" obj.name to:textStream
)
txtBmpInfo.text = replace_LF_with_CRLF (textStream as string)
OK
)
fn init =
(
lstTextures.pos.x = 0
lstTextures.SelectionMode = lstTextures.SelectionMode.FullRowSelect
lstTextures.AllowUserToAddRows = false
lstTextures.AllowUserToDeleteRows = false
lstTextures.AllowUserToOrderColumns = true
lstTextures.AllowUserToResizeRows = false
lstTextures.AllowUserToResizeColumns = true
lstTextures.AllowDrop = false
lstTextures.MultiSelect = true
lstTextures.ReadOnly = true
lstTextures.dock = lstTextures.dock.fill
lstTextures.DefaultCellStyle.backColor = backColour
lstTextures.DefaultCellStyle.foreColor = textColour
textFont = lstTextures.font
dingFont = dotNetObject "System.Drawing.Font" "Webdings" textFont.size
textFontBold = dotnetobject "system.drawing.font" textFont (dotnetclass "system.drawing.fontstyle").bold
lstTextures.EnableHeadersVisualStyles = false
lstTextures.ColumnHeadersDefaultCellStyle.backColor = backColour
lstTextures.ColumnHeadersDefaultCellStyle.foreColor = textColour
lstTextures.ColumnHeadersDefaultCellStyle.font = textFontBold
lstTextures.ColumnHeadersHeight = 34
txtBmpInfo.readOnly = true
txtBmpInfo.multiline = true
txtBmpInfo.scrollbars = txtBmpInfo.ScrollBars.vertical
txtBmpInfo.wordWrap = true
txtBmpInfo.backColor = backColour
txtBmpInfo.foreColor = textColour
startSize = GetIniRolloutSize()
arrangeCtrls size:startSize
local colNum
append headers ""
for item in headers do
(
colNum = lstTextures.Columns.add item item
)
local firstCol = lstTextures.Columns.item[0]
local lastCol = lstTextures.Columns.item[colNum]
firstCol.width = 160
lastCol.AutoSizeMode = lastCol.AutoSizeMode.Fill
)
-----------------------------------------------------------------------------------------
-- UI Event Handlers
-----------------------------------------------------------------------------------------
on chkSelection changed state do
(
update()
)
on chkIncRefs changed state do
(
update()
)
on btnUpdate pressed do
(
update()
)
on lstTextures mouseDown args do
(
local clickPoint = dotNetObject "System.Drawing.Point" args.x args.y
local clickedItem = lstTextures.hitTest args.x args.y
if (clickedItem != undefined) do
(
local rowNum = clickedItem.rowIndex
if (rowNum != -1) and (lstTextures.selectedRows.count != 0) do
(
local rightClick = args.button.equals args.button.right
if rightClick then
(
-- Rightclick menu:
rcmenu RSmenu_textureMapStats
(
local selRows
menuItem itmSelObjs "Select objects using textures"
menuItem itmPhotoshop "Open textures in Photoshop"
menuItem itmPerforce "Perforce Checkout/Add textures"
-- Select selected textures' objects:
on itmSelObjs picked do
(
local selObjs = #()
for n = 0 to (selRows.count - 1) do
(
join selObjs (selRows.item[n].tag.value.objs)
)
selObjs = for obj in selObjs where (isValidNode obj) collect obj
clearSelection()
select selObjs
)
fn getSelTexFiles =
(
for n = 0 to (selRows.count - 1) collect
(
local selRow = selRows.Item[n]
local selTexStruct = selRow.tag.value
RsMakeBackSlashes selTexStruct.path
)
)
-- Open selected textures in Photoshop:
on itmPhotoshop picked do
(
for selTexFilename in getSelTexFiles() do
(
format "Opening in Photoshop: %\n" selTexFilename
shelllaunch ("Photoshop.exe") selTexFilename
)
)
-- Perforce checkout/add selected textures:
on itmPerforce picked do
(
local selTexFiles = getSelTexFiles()
gRsPerforce.add_or_edit selTexFiles
)
on RSmenu_textureMapStats open do
(
selRows = lstTextures.selectedRows
local plural = if (selRows.count != 1) then "s" else ""
itmSelObjs.text = "Select objects using texture" + plural
itmPhotoshop.text = "Open texture" + plural + " in Photoshop"
itmPerforce.text = "Perforce Checkout/Add texture" + plural
)
)
popUpMenu RSmenu_textureMapStats
)
else
(
)
)
)
)
on lstTextures selectionChanged ev args do
(
local selRowNum = lstTextures.currentCell.RowIndex
local img = bitmap bmpPreview.width bmpPreview.height color:windowCol
if (lstTextures.selectedRows.count == 0) do
(
bmpPreview.bitmap = img
return false
)
local rowTag = lstTextures.rows.item[selRowNum].tag
if (rowTag == undefined) do (return false)
local rowInfo = rowTag.value
if (doesFileExist rowInfo.path) then
(
renderMap (bitmapTexture bitmap:(openBitmap rowInfo.path)) filter:true into:img
lblNotFound.visible = false
)
else
(
lblNotFound.visible = true
)
bmpPreview.bitmap = img
updateText()
OK
)
on txtFilter entered newText do
(
update()
)
on RsTextureMapStatsRoll resized pntSize do
(
-- Save the new rollout-size:
RsSettingWrite "RsTextureMapStatsRoll" "size" pntSize
arrangeCtrls size:pntSize
)
on RsTextureMapStatsRoll open do
(
init()
update()
)
fn create retry:false =
(
destroyDialog RsTextureMapStatsRoll
RS_CustomDataGrid forceRecompile:retry
local rollSize = RsTextureMapStatsRoll.GetIniRolloutSize()
CreateDialog RsTextureMapStatsRoll modal:false width:rollSize.x height:rollSize.y style:#(#style_resizing, #style_titlebar, #style_border, #style_sysmenu )
)
) -- End of rollout definition
(
-- Try to catch if RsCustomDataGrid fails to work:
try (RsTextureMapStatsRoll.create())
catch (RsTextureMapStatsRoll.create retry:true)
)