546 lines
15 KiB
Plaintext
Executable File
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)
|
|
) |