[Closed] Asset Browser : Again
I’ve learned so much from everyone here, I couldn’t have come as far as I have without all the invaluable advice and examples. Below is my first go at an asset browser/creator tool. At the moment, it is lacking a ton of planned features but I will get there eventually.
The two big pieces I owe a lot of credit to are two custom dotnet assemblies:
HitchHiker from LoneRobot
KClasses from Artur Leão that he posted here.
I used the Tab Control example from thetutorial by Paul Neal at Pen Productions
ATTENTION: Since this is partially a work related project, I can’t promise that I will release updates or a final version. I definitely don’t have too much time to do support or to add feature requests or any of that. But this is somewhat functional as it is and noobs like me can learn something from it.
You’ll need to download the two .dlls I listed above and put them in your max root folder
Also, we use VRay, so the Create tab will always be set up to render vray thumbnails. If you don’t have VRay, this tab won’t work for you but the browse feature will still work. Basically, you need a .jpg with the exact same name as your .max asset file in the same folder. It is probably best if this jpg is 500×500.
If you have a single small monitor, I appologize. This tool is 1200×900.
I’m at a crossroads now. As I learn more about dotnet, I am contemplating dropping the max rollouts and going with maxForms. If only to force myself to learn them. Maybe your opinions can help me choose a direction at this point. I’d like to figure this out before I go too much further so I don’t have too much to convert.
I plan on adding these features:
[ol]
[li]I would like to figure out how to save the state of each tab when switching and restore the state when switching back[list=1][/li][li]Can I set the ‘current folder’ from the tree using a path string? Aside from the initial ProcessTree method. I want it to process a whole tree but jump to a specific folder in that tree on open or simply when switching back to the browser Tab.[/li]
[/ol]
[li]Add option to save tab states to .ini on close. There will be checkboxes in the Settings tab to set user options and save them to .ini in #userScripts[/li][li]The Create tab will eventually have the tools to add new folders, add keywords to the .jpgs via the tags property hopefully. I hope to add the keyword/tag feature using categorized lists of predefined keywords. I picture them in lists of checkboxes or checkButtons.So a user creating an asset can quickly add keywords without too much manual data entry. It would also be good if the user can add keywords dynamically to the UI…[/li][li]Possibly, add resizing to the whole tool based on percentage widths for the treeview and thumbnail browser… [/li]
[/list]I’m sure it is a formatting mess. Any tips or direction on any of it will be greatly appreciated
/* Credits:
HitchHiker.dll by LoneRobot http://lonerobot.net/?p=260
KClasses.dll by Artur Leão http://dimensao3.com/al/
dotnet Tabbed Control tutorial from PEN Productions http://penproductions.ca/tutorials/dotNet/tabControl/tabControl.htm
Instance replace function based on Denis Trofimov's example http://forums.cgsociety.org/showpost.php?p=6264096&postcount=10
*/
--Destroy the dialog if it is already open
try(destroyDialog ro_Assets)catch()
dotnet.loadAssembly "KClasses.dll"
dotnet.loadAssembly "HitchHiker.dll"
atw = 1200
ath = 860
assetPath = @"\\zgf\data\ZGFResources\3D\Assets"
--Create a rollout
rollout ro_Assets "Asset Tools v0.0.1" width:atw height:ath
(
--Add a dot net tab control
dotNetControl tabs "system.windows.forms.tabControl" width:(atw-600) height:25
--Add a sub rollout.
subRollout subRoll "Sub" width:(atw-30) height:850 offset:[0,-5]
--Write Summary Function
fn getAllFileData theDatFile =
(
pages = #(#summary, #contents, #custom)
for pg in pages do
(
format "%
" (pg as string) to:theDatFile
for i=1 to (fileProperties.getNumProperties pg) do
(
local pname = (fileProperties.getPropertyName pg i)
local pval = (fileProperties.getPropertyValue pg i)
format "% : " pname to:theDatFile
if (pname == "Headers") then
(
format "
" to:theDatFile
for hdr in pval do
(
format "%
" hdr to:theDatFile
local docs = fileProperties.getItems hdr
if docs != undefined then
for d in docs do format "%
" d to:theDatFile
)
)
else format " %
" pval to:theDatFile
)
)
)
--ReadSummaryFile
fn readSummaryInfo sf =
(
theMaxFile = maxFileName
theSimpleName = getFilenameFile theMaxFile
tempText = ""
sumFile = openFile sf mode:"r"
while not eof sumFile do (append tempText ((readline sumFile) +"
"))
close sumFile
return tempText
)
--Merge Placement follows mouse
fn PlaceObj msg ir obj faceNum shift ctrl alt =
(
if ir == undefined then
(
myStr = mouse.pos
)
else
(
myStr = ir.pos
)
case msg of
(
#freeMove:
(
mergeObj.pos = myStr
)
#mousePoint:
(
instance selection
selection.pos = myStr
)
#mouseAbort:
(
delete selection
exit
)
)
#continue
)
--Replace Instances
fn instanceReplaceSelection nodes makeunique:off =
(
act = off
setCommandPanelTaskMode mode:#create
nodes = #()
for o in selection do append nodes o
nodes
file = theMergeFile
if nodes.count > 0 and doesfileexist file do
(
clearSelection()
-- merge only object with the name
mergeMaxFile file #select #mergeDups #neverReparent #useMergedMtlDups quiet:on
if isvalidnode (node = selection[1]) do
(
-- replace all old instances with new one
for obj in nodes do
(
instancereplace obj node
obj.mat = node.mat
)
-- make them unique if necessary
if makeunique do InstanceMgr.MakeObjectsUnique nodes #individual
delete node
act = on
)
)
act
)
--Replace Selection
fn copyReplaceSelection nodes =
(
act = off
setCommandPanelTaskMode mode:#create
file = theMergeFile
if nodes.count > 0 and doesfileexist file do
(
clearSelection()
-- merge only object with the name
mergeMaxFile file #select #mergeDups #neverReparent #useMergedMtlDups quiet:on
if isvalidnode (node = selection[1]) do
(
-- replace all old instances with new one
for obj in nodes do
(
InstanceMgr.MakeObjectsUnique nodes #group
instanceReplace obj node
obj.mat = node.mat
)
delete node
act = on
)
)
act
)
--Tab initilization function.
fn initTabs tab labels:#() =
(
--Clear any existing tabs incase we do an update of them at some point.
tab.tabPages.clear()
--Set the size mode so that we can control their width.
tab.sizeMode=tab.sizeMode.fixed
--Set the width of every tab.
tab.itemSize=dotnetObject "System.Drawing.Size" ((tab.width/labels.count)-2) 25
--Loop through all the labels that we pass to the function and add a tab by the same name.
for x in labels do tab.tabPages.add x
)
-------------------------------------------TABS--------------------------------------------------------------------------
--Add rollouts to the subRollout based on which tab is currently selected.
fn addTabRollout index=
(
--Remove any existing rollouts first.
for x in subRoll.rollouts do removeSubRollout subRoll x
sub=case index of
(
--BROWSER
default:
(
rollout ro_Browser "Browser"
(
--Main Elements
dotnetcontrol tvFolders "KClasses.dnFolders" pos:[0,0] width:290 height:800
dotNetControl HitchHiker "lonerobot.ui.character.HitchHiker" pos:[810,0] width:340 height:800
dotNetControl pic_Preview "pictureBox" pos:[300,0] width:500 height:500
--Info Area
dotnetControl dgr_Info "dataGrid" pos:[525,510] width:275 height:260
button btn_Merge "Merge" pos:[700,780] width:100 height:20
button btn_ReplaceInst "Replace Instances" pos:[600,780] width:100 height:20
button btn_ReplaceCopy "Replace Selection" pos:[500,780] width:100 height:20
button btn_test "test" pos:[300,780]
on btn_test pressed do
(
print tvFolders.Location
)
on ro_Browser open do
(
--initialize thumbnail browser
HitchHiker.ButtonBackColor = (dotnetclass "system.drawing.color").black
HitchHiker.filetype = (dotnetclass "lonerobot.ui.character.HitchHiker+filetypes").jpg
HitchHiker.displaystyle = (dotnetclass "lonerobot.ui.character.HitchHiker+displaystyles").imagetext
HitchHiker.Gap = 0
HitchHiker.RecursiveSearch = false
HitchHiker.ShowToolBar = false
HitchHiker.populate assetPath
--inititalize Preview window
pic_Preview.BackColor = (dotnetClass "System.Drawing.Color").black
--initialize Info area
--dgr_Info.label = "Info"
--iniitialize treeview
--clearListener()
start=timestamp()
tvFolders.ProcessTree(assetPath)
--tvFolders.select (getINISetting (getdir #userScripts + "\AssetTools.ini") "Browser" "TreeViewDefaultLocation" )
end=timestamp()
format "Processing took % seconds
" ((end - start) / 1000.0)
)
--Thumbnail Handlers
on HitchHiker thumbpicked sender args do
(
theMergeFileThumb = args.FileName
theFile = theMergeFileThumb
theName = getFilenameFile theFile
thePath = getFileNamePath theFile
global theMergeFile = (thePath + theName + ".max")
global theSummaryFile = (thePath + theName + ".dat")
pic_Preview.Load args.FileName
if doesFileExist theSummaryFile then
(
dgr_Info.text = (readSummaryInfo theSummaryFile)
)
else
(
dgr_Info.text ="No Data"
)
print args.FileName
)
--TreeView Handlers
on tvFolders NodeMouseClick sender eb do
(
print eb.node.dirName
HitchHiker.populate eb.node.dirName
setINISetting (getdir #userScripts + "\AssetTools.ini") "Browser" "TreeViewDefaultLocation" eb.node.dirName
--showproperties eb.node
)
--Replace Selection Button Handler
on btn_ReplaceCopy pressed do
(
if selection == undefined then
(
messagebox "Nothing Selected"
)
else
(
sellectedObs = #()
for o in selection do append sellectedObs o
copyReplaceSelection sellectedObs
)
)
--Replace all instances Button Handler
on btn_ReplaceInst pressed do
(
if selection == undefined then
(
messagebox "Nothing Selected"
)
else
(
sellectedObs = #()
for o in selection do append sellectedObs o
instanceReplaceSelection sellectedObs
)
)
--Merge Button Handler
on btn_Merge pressed do
(
if selection != undefined do (global mergeSurf = selection[1])
mergeMaxFile theMergeFile #mergeDups #useSceneMtlDups #select
global mergeObj = selection
if mergSurf != undefined
then
(mouseTrack on:mergeSurf snap:#3D trackCallback:PlaceObj)
else
(mouseTrack snap:#3D trackCallback:PlaceObj)
)
on ro_Browser close do
(
HitchHiker.housekeeping()
tvFolders.dispose()
)
)
)
--CREATOR
1:
(
rollout CreateAsset "Asset Creation"
(
dotnetcontrol tvFolders "KClasses.dnFolders" pos:[atw-300,0] width:290 height:800
button btn_Render "Render Thumbnail" height:48 pos:[0,50]
--ButtonEvents
on btn_Render pressed do
(
--ProcessFileName
theMaxFile = maxFileName
theMaxFilePath = maxFilePath
theSimpleName = getFilenameFile theMaxFile
--RenderSetup
sysGamma = IDisplayGamma
sysGamma.colorCorrectionMode = #gamma
sysGamma.gamma = 2.2
backgroundColor = black
renderSceneDialog.close()
vr = renderers.current = vray()
vr.gi_on = true
vr.gi_primary_type = 0
vr.gi_secondary_type = 3
vr.options_lights = true
vr.options_defaultLights = 1
setRenderType #view
rendTimeType = 1
renderWidth = 500
renderHeight = 500
renderPixelAspect = 1.0
print (theMaxFilePath + theSimpleName + ".jpg")
--Create Thumbnail
thumbnail = bitmap 500 500 filename:(theMaxFilePath + theSimpleName + ".jpg")
render to:thumbnail
save thumbnail
close thumbnail
--Create Summary File
datFile = createFile (theMaxFilePath + theSimpleName + ".dat")
getAllFileData datFile
close datFile
)
)
)
--SETTINGS
2:
(
rollout Settings "Settings"
(
button testBt "test Button"
on testBt pressed do (messageBox "You pressed the button" title:"Alert!")
)
)
)
addSubRollout subRoll sub
)
--When the mouse button is released on a tab get the selected tab and pass it to our addTabRollout function.
on tabs MouseUp senderArg arg do
(
addTabRollout senderArg.SelectedIndex
)
--When the rollout opens initilize the tab control
on ro_Assets open do
(
initTabs tabs labels:#("Browse", "Create", "Settings")
addTabRollout 0
)
)
--Create the dialog
createDialog ro_Assets style:#(#style_resizing, #style_titleBar, #style_sysmenu)