--TexTXD -- url:bugstar:313343 --Neil Gregory ----------------------------------------------------------------------------- -- Uses ----------------------------------------------------------------------------- filein (RsConfigGetWildWestDir() + "script/3dsMax/_config_files/Wildwest_header.ms") filein "rockstar/util/material.ms" -- loaded on startup by startup.ms -- .Net ListView Control --filein ( (getdir #maxroot) + "stdplugs/stdscripts/NET_ListViewWrapper.ms" ) ----------------------------------------------------------------------------- -- .Net Initialisation ----------------------------------------------------------------------------- dotNet.loadAssembly "System.Windows.Forms.dll" dotNet.loadassembly "MaxCustomControls.dll" RS_CustomDataGrid() struct TextureObject ( name, --bare name path, --file path width, --pixels height, --pixels size, --KB txdList = #(), --TXDs belongs to fn getArea = ( return (width * height) ) ) ----------------------------------------------------------------------------- -- Rollout ----------------------------------------------------------------------------- try (DestroyDialog TXDSpy_UI)catch() rollout TXDSpy_UI "Texture Map TXD Statistics" ( ----------------------------------------------------------------------------------------- -- Script-scope Variables ----------------------------------------------------------------------------------------- local appTitle = "Texture Map TXD Statistics" local sceneTXDTextures = #() local objectTextures = #() --#(name: val:#(tdxlist), memory, area ) local txdList = RsGetSceneTxdList() local txdAttrIdx = getattrindex "Gta Object" "TXD" local pieHeaders = #(#("ID", 30), #("Object", 100), #("Texture Name", 150), #("Mem Share", 150)) local affinityHeaders = #(#("ID", 30), #("Texture Name", 150)) local DNcolour = dotNetClass "System.Drawing.Color" local textCol = (colorMan.getColor #windowText) * 255 local windowCol = (colorMan.getColor #window) * 255 local textColour = DNcolour.FromArgb textCol[1] textCol[2] textCol[3] local backColour = DNcolour.FromArgb windowCol[1] windowCol[2] windowCol[3] local altBackColour = DNcolour.FromArgb (windowCol[1]-10) (windowCol[2]-10) (windowCol[3]-10) ----------------------------------------------------------------------------------------- -- UI Widgets and Layout ----------------------------------------------------------------------------------------- dotNetControl rsBannerPanel "Panel" pos:[0,0] height:32 width:TXDSpy_UI.width local banner = makeRsBanner dn_Panel:rsBannerPanel wiki:"TextureTXDUsage" filename:(getThisScriptFilename()) --button btnUpdate "Update" align:#left width:100 across:3 group "" ( dropdownlist ddl_TXDList "SceneTXDs:" items:txdList tooltip:"Scene TXD selector" checkButton btnAffinity "Object Texture Affinity" align:#left tooltip:"Textures common amongst object selection" ) --hyperlink lnkHelp "Help?" address:"https://devstar.rockstargames.com/wiki/index.php/Texture_TXD_Stats" align:#right color:(color 0 0 255) hoverColor:(color 0 0 255) visitedColor:(color 0 0 255) --dotNetControl lstView "System.Windows.Forms.DataGridView" height:(300-65) dotNetControl lstView "RsCustomDataGridView" width:595 height:(300-65) offset:[-10, 0] progressbar barProgress --button btnClose "Close" align:#right width:100 ----------------------------------------------------------------------------------------- -- Functions ----------------------------------------------------------------------------------------- fn buildSceneTextureObjects = ( --lets build the textureObjects for those in the sscene TXDs for txd in txdList do ( texmaplist = #() RsGetTexMapsByTxdNameNoStrip texmaplist #() #() #() txd for tex in texmaplist do ( tex = (filterString tex "+")[1] --in case of a double texture take the first bitmap path texName = getFileNameFile tex --print texName --add to dict texExists = (for tex in sceneTXDTextures where tex.name == texName collect tex)[1] --format "texExists: % \n" texExists if texExists == undefined then ( txObj = TextureObject() txObj.name = texName txObj.path = tex texBmp = if doesFileExist tex then openBitmap tex if texBmp != undefined then ( txObj.width = texBmp.width txObj.height = texBmp.height ) txObj.size = (getfilesize tex) / 1024 free texBmp txObj.txdList = append txObj.txdList txd append sceneTXDTextures (DataPair name:texName obj:txObj) ) else --this texture object already exists, update its txd list ( append texExists.obj.txdList txd ) --get the file path --RsGetTexMapTextures tex ) ) ) fn TXDSpy = ( if btnAffinity.checked == true then ( TXDSpy_UI.columnHeaders "affinity" TXDSpy_UI.sharedTextures() return true ) TXDSpy_UI.columnHeaders "pie" --lstView.ListViewItemSorter = dotNetObject "GenericEditor.cListViewColumnNullSorter" lstView.rows.Clear() textureData = #() txdList = RsGetSceneTxdList() --Now match the selection with the built array/dict to determine usage and efficiency --get the textures on the selection and match against the sceneTXDs for obj in $selection do ( objectTextures = #() objTex = #() RsGetTexMapsFromMaterial obj obj.material objTex #() #() --RsGetTexMapListForMat $.material objectTex matIdList:matIDs --TXDTextures = #() --give the number of matches and % of memory for each texture on the selected object TXDMatches = #() memCompare = #() areaCompare = undefined for tex in objTex do ( tex = (filterString tex "+")[1] --in case of a double texture take the first bitmap path --Texture properties --see if the object texture exists already in sceneTXDTextures and retrieve its propertes from there texArea = undefined texMemory = undefined texObj = (for texItem in sceneTXDTextures where texItem.obj.name == tex collect texItem.obj)[1] if texObj == undefined then continue texArea = texObj.getArea() texMemory = texObj.size --now collect up all the texture area and memory for each TXD the texture is used in and compare to its own properties TXDareaShare = 0 TXDmemShare = 0 --format "tex: % texObj: % \n" tex texObj.txdList --get the txd match objectTXD = tolower (getAttr obj txdAttrIdx) UITXD = ddl_TXDList.selected TXD = (for txd in texObj.txdList where UITXD == txd collect txd)[1] --format "TXD: % \n" TXD if TXD != undefined then --for txd in texObj.txdList where (getAttr obj txdAttrIdx) == txd do ( texTXDTotalArea = 0 texTXDTotalMem = 0 --get the txd textures TXDTextures = #() RsGetTexMapsByTxdName TXDTextures #() #() #() TXD srcobjlist:#(obj) --get the textureObjects for those textures TXDTextureObjs = #() for tex in TXDTextures do ( --find the object texObj = (for texItem in sceneTXDTextures where texItem.obj.name == tex collect texItem.obj)[1] if texObj != undefined then ( texTXDTotalArea += texObj.getArea() texTXDTotalMem += texObj.size ) ) --TXDareaShare = (texArea * (100.0 / texTXDTotalArea)) TXDmemShare = (texMemory * (100.0 / texTXDTotalMem)) if TXDmemShare < 0 or TXDmemShare > 100 then TXDmemShare = "--" ) append objectTextures (DataPair name:obj.name props:#(tex, TXD, "TXDareaShare", TXDmemShare)) ) append textureData objectTextures --TXDMatches = makeUniqueArray TXDMatches --format "TXDMatches: %\n" TXDMatches --format "objectTextures: %\n" objectTextures ) count = 0 for objTx in textureData do ( --random --lstView.RowsDefaultCellStyle.backColor = DNcolour.FromArgb (random (windowCol[1]-30) windowCol[1]) (random (windowCol[2]-30) windowCol[2]) (random (windowCol[3]-30) windowCol[3]) objRowCol = DNcolour.FromArgb (random (windowCol[1]-40) windowCol[1]) (random (windowCol[2]-40) windowCol[2]) (random (windowCol[3]-40) windowCol[3]) for tex in objTx do ( rowID = lstView.rows.Add #( count, tex.name, tex.props[1], tex.props[4] as Integer) lstView.rows.item[rowId].DefaultCellStyle.backColor = objRowCol count += 1 ) ) --print the number (and if expanded the names) of the shared textures used between any random selection of objects. ) fn sharedTextures = ( --clear the decks lstView.rows.Clear() if $selection.count < 2 then return false commonTextures = #() textureLib = #() --get the textures from each object for obj in $selection where isKindOf obj GeometryClass do ( objectTextures = #() objTex = #() RsGetTexMapsFromMaterial obj obj.material objTex #() #() print objTex append textureLib (DataPair obj:obj textures:objTex) ) --now boil em up to extract the common textures. --texture centric obj arrays for lib in textureLib do ( --print lib for tex in lib.textures do ( for sibling in textureLib where sibling != lib do ( for sibTex in sibling.textures where tex == sibTex do ( append commonTextures tex ) ) ) ) commonTextures = makeUniqueArray commonTextures --format "common Textures: % \n" commonTextures --format "count: % \n" commonTextures.count count = 0 for tex in commonTextures do ( lstView.rows.Add #( count, tex) count += 1 ) ) fn columnHeaders mode = ( --lvops.ClearColumns lstView lstView.columns.Clear() case mode of ( "pie": ( for item in pieHeaders do ( num = lstView.columns.Add item[1] item[1] lstView.columns.Item[num].minimumWidth = item[2] lstView.columns.Item[num].autoSizeMode = (dotNetClass "System.Windows.Forms.DataGridViewAutoSizeColumnMode").AllCellsExceptHeader ) ) "affinity": ( for item in affinityHeaders do ( num = lstView.columns.Add item[1] item[1] lstView.columns.Item[num].minimumWidth = item[2] lstView.columns.Item[num].autoSizeMode = (dotNetClass "System.Windows.Forms.DataGridViewAutoSizeColumnMode").AllCellsExceptHeader ) ) default: ( for item in pieHeaders do ( num = lstView.columns.Add item[1] item[1] lstView.columns.Item[num].minimumWidth = item[2] lstView.columns.Item[num].autoSizeMode = (dotNetClass "System.Windows.Forms.DataGridViewAutoSizeColumnMode").AllCellsExceptHeader ) ) ) ) fn init = ( format "listView: % \n" lstView lstView.AllowUserToAddRows = false lstView.AllowUserToDeleteRows = false lstView.AllowUserToOrderColumns = true lstView.AllowUserToResizeRows = false lstView.AllowUserToResizeColumns = false lstView.AllowDrop = false lstView.MultiSelect = true lstView.ReadOnly = true lstView.AutoSizeColumnsMode = (dotNetClass "DataGridViewAutoSizeColumnsMode").Fill lstView.dock = lstView.dock.fill lstView.DefaultCellStyle.backColor = backColour lstView.DefaultCellStyle.foreColor = textColour lstView.SelectionMode = (dotNetClass "DataGridViewSelectionMode").FullRowSelect --lstView.AlternatingRowsDefaultCellStyle.BackColor = altBackColour ) ----------------------------------------------------------------------------------------- -- Events dear boy ----------------------------------------------------------------------------------------- on btnUpdate pressed do ( columnHeaders "pie" TXDSpy() ) on btnAffinity changed arg do ( if arg then ( columnHeaders "affinity" sharedTextures() ) else ( columnHeaders "pie" TXDSpy() ) ) fn ddlSelector item = ( columnHeaders "pie" TXDSpy() ) on ddl_TXDList selected item do ddlSelector item /* on lstView ColumnClick args do ( sorting = dotNetClass "System.Windows.Forms.SortOrder" lstView.Sorting = sorting.Ascending lstView.ListViewItemSorter = dotNetObject "GenericEditor.cListViewColumnIntSorter" args.Column lstView.Sort() ) */ on TXDSpy_UI open do ( banner.setup() init() columnHeaders "pie" buildSceneTextureObjects() callbacks.removeScripts id:#TexTXD callbacks.addScript #SelectionSetChanged "TXDSpy_UI.TXDSpy()" id:#TexTXD TXDSpy() ) on TXDSpy_UI close do ( callbacks.removeScripts id:#TexTXD ) ) CreateDialog TXDSpy_UI width:600 height:400 \ --TXDSpy()