Looking for a script

I seem to remember seeing either a wish list or post of a script or need for a script that would locate or identify texture maps of a given size in a scene( byte or dimensions). Cant find anything in the forums about it so I may have been dreaming.

Anyone recall that?

there is a new tool in max 9 to do that…I think it is bitmap proxy.

That works to a degree but I want to generate a list or identify textures in order to change them rather than globally scale them down.

Great idea, it would be nice to at least have a good idea of the big textures used in the scene in case you accidentally forgot to resize it in photoshop, or convert it to jpeg.

I will see how difficult it would be to write one (if MXS has access to filesizes, then it’s absolutely possible and not difficult)

-Colin

Thanks, it would be a tremendous help. We often run into scenes that
have to be re-rendered at hires or something whacky happens and
end up goung through every single material one at a time trying to
find efficiencies.

Something that would create a list or flag textures over a given btye
size and/or pixel dimension would be amazing.

In case you didn’t know, in Windows Explorer you can choose “Dimensions” as one of the columns in “details” view while listing files. Just right-click the columns and select “more…” at the bottom and check it off.

i’d started something like that ages ago.. let me see if i can find it and throw it out for anyone else to play with.

heres most of it.. though it was pretty ghetto because i just needed to find something in a huge file, so the only output is to the maxscript listener


(
r=sysinfo.getSystemMemoryInfo()
for i=2 to 7 do r[i] /= (1024*1024.)
format " mem use % percent free:total:\t %:% MB  \n" r[1] r[3] r[2]
format " RAM in use: \t \t % MB  \n" (r[2]-r[3])
format " Virtual Memory: \t \t% MB  \n \n" (r[6]-r[7])

local mapfiles=#()
fn addmap mapfile =
(
	local mapfileN=mapfile as name
	local index=finditem mapfiles mapfileN
	if index == 0 do append mapfiles mapfileN
)

enumeratefiles addmap
sort mapfiles
for mapfile in mapfiles do
	(
		novrmesh = (matchpattern (mapfile as string) pattern:"*vrmesh*" ignorecase:true)
		if (novrmesh == false) do
		(
			try(bitmaptex = openbitmap mapfile)catch(print ("failed to open" + (mapfile as string)))
			format "..  Map location: % \n" mapfile
			format "....  is Width: % Height: % and % kb \n"  bitmaptex.width bitmaptex.height (getFileSize mapfile)
		)
	)
)

And if i recall correctly, one of the problems with it as is, is that its running on mapfiles instead of bitmaptexture files.. so it would need to be changed in order to ignore silly things like procedural maps

Yeah, problem is not in explorer, its finding the files within MAX as the files are called from all over the place. At present I have to check each one individually, reveal in explorer, check it, change it if need be.
The idea being something that would identify the large texture maps automatically to keep from having to go through each material in the scene, which can be very many.

@dbuchoffer
That is a start will try it out, thanks so much, I unfortunately know very little about scripting but this might be the time to start learning.

Thanks for the input.

Update: forgot to post this last night

v1.3 Now sorts your lists depending on what filtering (size or dimension) you choose
--------------------------------------------
Old:
I wrote this today. It will help us too. It’s very simple, but functional. If you have additional requests or helpful things I could add to it, please let me know!

http://www.colinsenner.com/personal/FindLargeBitmaps1.3.ms

code below


-- FindLargeBitmaps by Colin Senner for Arnold Imaging LLC c2007 
-- v1.3

-- Close previous instances of the script if running
if rf != undefined then closeRolloutFloater rf

-- Rollouts
global rf, rlt_Info, rlt_Main

-- Functions
global openRolloutNextTo, isValidNumber, closeRollout
global sizeSort, dimSort

-- Variables
global whichSort = 0		-- 1 = dimensional sort, 2 = Size sort
global listItems = #()
global listItemsDims = #()
global listItemsSize = #()

fn closeRollout rlt = (	if rlt.open then destroyDialog rlt )
fn openRolloutNextTo sRlt dRlt thewidth theheight = (
	closeRollout dRlt
	if dRlt.open == false then (
		local theposx = rf.pos.x
		local theposy = rf.pos.y
		local thenewposx = (sRlt.width+27)+theposx
		createDialog dRlt width:thewidth height:theheight pos:[thenewposx,theposy]
	)	
)

fn isValidNumber val = (
	if ((val as integer) == undefined) or ((val as integer) == undefined) then 
		return false
	return true	
)

fn sizeSort = (
	for i = 1 to listItemsSize.count do (
		try ( 
			while listItemsSize[i] < listItemsSize[i+1] do (
				swap listItemsSize[i] listItemsSize[i+1]
				swap listItems[i] listItems[i+1]
				swap listItemsDims[i] listItemsDims[i+1]
				i = i - 1
			)
		) catch ()
	)	
)

fn dimSort = (
	for i = 1 to listItemsDims.count do (
		try ( 
			while listItemsDims[i].x < listItemsDims[i+1].x do (
				swap listItemsDims[i] listItemsDims[i+1]
				swap listItems[i] listItems[i+1]
				swap listItemsSize[i] listItemsSize[i+1]

				i = i - 1
			)
		) catch ()
	)		
)

rollout rlt_Info "Maps" (
	listbox lst_maps "Maps matching your criteria" height:20
	edittext edt_Info "path: " width:473

	on rlt_Info open do (
		local toList = #()

		if whichSort == 1 then (			-- Dimensions
			for i = 1 to listItems.count do
				toList[i] = (listItemsDims[i] as string) + "   -   " + (listItemsSize[i] as string) + " KB   -  " + (listItems[i])
		)
		else if whichSort == 2 then (		-- Size
			for i = 1 to listItems.count do
				toList[i] = (listItemsSize[i] as string) + " KB   -   " + (listItemsDims[i] as string) + "  -  " + (listItems[i])
		)

		lst_maps.items = #()		
		lst_maps.items = toList
		whichSort = 0
	)

	on lst_maps selected arg do
		edt_Info.text = listItems[arg]
)

rollout rlt_Main "Find Large Bitmaps" (
	group "Dimensions" (
		label lbl_text1 "If greater than these dimensions"
		edittext edt_wDim "width:  " fieldwidth:40 text:"0"
		label lbl_wPx "px" offset:[-8,-18]
		edittext edt_hDim "height: " fieldwidth:40 text:"0"
		label lbl_hPx "px" offset:[-8,-18]
		button btn_dimFind "Find" offset:[50,-33] width:70
		label lbl_space1 ""
	)
	group "File Size" (
		label lbl_text2 "If larger than this filesize"
		edittext edt_size "" text:"0" fieldwidth:45 offset:[20,4]
		label lbl_text_kb "kb" offset:[-15,-20]
		button btn_sizeFind "Find" align:#center offset:[50,-23] width:70
	)

	fn clearGlobalArrays = (
		listItems = #()
		listItemsDims = #()
		listItemsSize = #()
	)

	fn getBitmaps = (
		local bmaps = getClassInstances BitmapTexture
		local gbmaps = #()

		gbmaps = for b in bmaps where (doesFileExist b.filename) collect b 	
		gbmaps
	)

	fn getBitmapFilter sortType w h size = (  -- if sortType = 1 then filter by Dimensions, if sortType = 2 then filter by Size
		local maps = getBitmaps()
		clearGlobalArrays()

		if sortType == 1 then (			-- Dimensions		
			for i = 1 to maps.count where (maps[i].bitmap.width >= w) and (maps[i].bitmap.height >= h) do (
				append listItems maps[i].filename
				append listItemsDims (point2 maps[i].bitmap.width maps[i].bitmap.height)
				append listItemsSize ((getFileSize maps[i].filename)/1024)
			)
			dimSort()	
			whichSort=1		
		)
		else if sortType == 2 then (		-- Filesize
			for i = 1 to maps.count where (((getFileSize maps[i].filename)/1024) >= size) do (
				append listItems maps[i].filename
				append listItemsDims (point2 maps[i].bitmap.width maps[i].bitmap.height)
				append listItemsSize ((getFileSize maps[i].filename)/1024)
			)
			sizeSort() -- Sorts the arrays based on size of the bitmaps
			whichSort=2
		)
	)

	on btn_dimFind pressed do (
		if (isValidNumber edt_wDim.text) and (isValidNumber edt_hDim.text) then (
			local theWidth = (edt_wDim.text as integer)
			local theHeight = (edt_hDim.text as integer)

			getBitmapFilter 1 theWidth theHeight 0
			openRolloutNextTo rlt_Main rlt_Info 500 315
		)
	)

	on btn_sizeFind pressed do (
		if (isValidNumber edt_size.text) then 
			getBitmapFilter 2 0 0 (edt_size.text as integer)

		openRolloutNextTo rlt_Main rlt_Info 500 315
	)

	on rlt_Main close do
		try ( destroyDialog rlt_Info ) catch ()
)

rf = newRolloutFloater "Find Large Bitmaps v1.3" 230 207
addRollout rlt_Main rf

Very useful, thanks MoonDoggie!

Very simple idea and seems to work perfectly. Great tool. Thanks.

This would be more useful if all your maps are in the same directory (ideally), sometimes that’s not the case.

Found a bug, please download v1.1, improved.

That is amazing, thanks so so much! I can see only one more thing that would be handy, either the material name the material the map is associated with or the object(s) it is applied to, but that can be done looking throught the material editor too.
:smile:
Thanks again, very cool.

Really clever, well done mate.

One thing bugs me though: the discrepancy (sometimes huge) between the size of JPG textures on disk and when rendered.
As you know, a jpg on disk may be 10k, but once loaded and decompressed, may take up any size (imagine a perfectly white - ie. homogeneous-, 8k image, as an extreme).
I was wondering if it could be improved by somehow making it decompress the textures by loading them in a FB (which could also be invisible, making the process a lot faster), and doing a simple difference in system memory used from before and after decompression.
Maybe as an option…

Lele

Friggin lele, with the thinking and the ideas and monkeys poking with sitcks :smile:

yea a statistic display, “on disk” and “in memory”

Wow, thanks so much again. As it stand this has saved me much stick poking monkey wrestling.

i dont think you’d have to actually decompress/load the textures as the size in memory is a rather simple calc for Bitmaps : SizeX*SizeY*BitsPerChannel*NumberofChannels = Size in memory in bits.

Should be readable from the header and should be faster then actually loading the bitmap.

Regards,
Thorsten

Edit : Just saw that you are grabbing the texture dimensions anyways. so it’s easy to calc the size in memory.

duh me, so very right, Thorsten.
It was late at night… :lol:

This means alot, thanks Lele and everyone else.

At any rate, this script was written very fast, so optimizations etc can come later, and it can certainly be a community project if anyone has any ideas as the source script is plain english.

I love the idea about the size in memory. The formula Thorsten posted is relatively self-explanatory. I’d love to see it integrated into the script and UI. I will be happy to do it myself, once some questions are answered.

can you calculate other bitmapTexture formats the same way such as tifs, jpgs, etc.? Also let me know how it would be handled UI wise. A checkbox in the “Size” group that specifies if the maps are that big in memory?

Many thanks,
Colin

It means your code is a hell of a lot cleaner and fool-proof than mine :lol:

Ideally, a checkbox that said “check uncompressed size”, and a pop-up box that warned that the process could take a long time and eat up some ram would be what I would put in, but i am no feng-shui follower when it comes to interface desing…
The fact is that Thorsten formula need YOU to take into account the formats (ie. a Tiff might be 8, 16 or 32 bits, headers may vary between image type flavours and so on and so forth), whereas in the case of a straight open into FB, you would eat up ram, but forget entirely the bother with the code.
A freescenebitmaps() after the FB has been closed and the bitmap flushed should ensure there is no ram pollution.