Here is a version that exports the bitmaps used, by layer. The layers that exists but without using any bitmap are simply ignored.
The export is done accordingly.
try:
import poser
except ImportError:
import _POSER_FAKE as poser
import wx
import wx.lib.agw.flatnotebook as fnb
import wx.lib.agw.hypertreelist as HTL
import os
import os.path
import configparser
HTL_ITEM_NORMAL=0
HTL_ITEM_CHECKBOX=1
HTL_ITEM_RADIO=2
class CypMaterialsList(wx.Frame):
# ---------- Dialog part
def __init__(self, dlg_name):
self.parent = poser.WxAuiManager().GetManagedWindow().GetParent()
self.title_font = wx.Font(9, wx.DECORATIVE, wx.NORMAL, wx.BOLD)
self.dlg_name = dlg_name
self.load_config()
self.load_environment()
wx.Frame.__init__(
self,
self.parent,
title=self.get_dialog_title(),
pos=(self.dlg_x, self.dlg_y),
size=(self.dlg_w, self.dlg_h),
style=wx.DEFAULT_FRAME_STYLE|wx.FRAME_TOOL_WINDOW|wx.FRAME_FLOAT_ON_PARENT|wx.FRAME_NO_TASKBAR|wx.FRAME_DRAWER,
name=dlg_name
)
self.Bind(wx.EVT_CLOSE, self.on_close)
self.Bind(wx.EVT_ACTIVATE, self.on_activate)
self.Bind(wx.EVT_SIZING, self.on_sizing)
self.main_panel = wx.Panel(self, size=(5,150))
self.notebook = fnb.FlatNotebook(
self.main_panel,
# fnb.FNB_HIDE_TABS
agwStyle=fnb.FNB_FANCY_TABS|fnb.FNB_NO_X_BUTTON|fnb.FNB_NO_NAV_BUTTONS|fnb.FNB_NO_TAB_FOCUS
)
self.notebook.SetBackgroundColour(wx.Colour(192,192,192))
self.moving_controls = {}
self.create_materiels_page()
self.create_tools_page()
main_sizer = wx.BoxSizer()
main_sizer.Add(self.notebook, 1, wx.ALL | wx.EXPAND, 5)
self.main_panel.SetSizer(main_sizer)
self.Show()
def create_tools_page(self):
self.cmd_panel = wx.Panel(self.notebook)
# Action button
x = 120
y = 100
self.button_export = wx.Button(
self.cmd_panel,
label='Export',
pos=(self.dlg_w-x, self.dlg_h-y),
name='button_export'
)
self.moving_controls[self.button_export] = (x, y)
self.button_export.Bind(wx.EVT_BUTTON, self.action_export)
self.notebook.AddPage(self.cmd_panel, "Tools")
def create_materiels_page(self):
self.HTL_mat_panel = wx.Panel(self.notebook)
self.mats_tree_list = HTL.HyperTreeList(
self.HTL_mat_panel,
agwStyle=wx.TR_DEFAULT_STYLE
)
self.mats_tree_list.AddColumn("Materials")
self.mats_tree_list.AddColumn("Gamma")
self.mats_tree_list.AddColumn("Filtering")
self.mats_tree_root = self.mats_tree_list.AddRoot("Root")
self.mats_tree_root.Expand()
self.tree_root_materials = self.mats_tree_list.AppendItem(self.mats_tree_root, "Object", ct_type=HTL_ITEM_NORMAL)
self.tree_root_materials.Expand()
self.mats_tree_list.SetColumnWidth(0, int(self.dlg_w*0.70))
self.HTL_Prepare_materials_list()
sizer = wx.BoxSizer()
sizer.Add(self.mats_tree_list, 1, wx.ALL | wx.EXPAND, 5)
self.HTL_mat_panel.SetSizer(sizer)
# Drop all this in a notebook page
self.notebook.AddPage(self.HTL_mat_panel, "Material List" )
# ---------- HyperTreeList mamagenemt
def _deep_scan_for_bitmaps(self, from_node=None):
if not from_node: return {}
current_list = {}
detected = {}
if from_node.Type() == 'image_map':
sni = from_node.InputByInternalName('Image_Source')
file_name = sni.Value()
texture = sni.Texture()
gamma = 2.2 if texture.UseSceneGamma() else texture.Gamma()
filtering_i = int(from_node.InputByInternalName('Filtering').Value())
filtering = "Filtering: " + { 1:'none', 2:'fast', 3:'quality', 4:'crisp'}.get(filtering_i, 'unknown')
detected = {file_name: (str(gamma), filtering)}
elif from_node.Type() == 'ccl_ImageTexture':
sni = from_node.InputByInternalName('Image')
file_name = sni.Value()
texture = sni.Texture()
gamma = 2.2 if texture.UseSceneGamma() else texture.Gamma()
detected = {file_name: (str(gamma), "-")}
if not detected:
for sni in from_node.Inputs():
in_node = sni.InNode()
if in_node:
detected = self._deep_scan_for_bitmaps(from_node=in_node)
if detected:
current_list.update(detected)
else:
current_list.update(detected)
return current_list
def OnCompareItems(self, item1, item2):
a = item1.Name()
b = item2.Name()
return (a > b) - (a < b) # equivalent to old cmp function
def HTL_mat_scan_4_bitmaps(self, material, start_place):
mat_ok = False
lay_count = 0
for layer in material.Layers():
if not mat_ok:
mat_ok = True
self.txt_material_list.append(material.Name())
tree = layer.ShaderTree()
root_node = tree.RendererRootNode(self.scene.CurrentRenderEngine())
full_list = self._deep_scan_for_bitmaps(from_node=root_node)
layer_name = layer.ExtName()
layer_place = self.mats_tree_list.AppendItem(start_place, layer_name)
self.txt_material_list.append(f" {layer_name}")
check = False
for file_name, values in dict(sorted(full_list.items())).items():
gamma, filtering = values #full_list[file_name]
check = True
self.txt_material_list.append(f" {file_name}")
img_info = self.mats_tree_list.AppendItem(layer_place, file_name)
img_info.SetText(1, gamma)
img_info.SetText(2, filtering)
if check:
lay_count += 1
layer_place.Expand()
else:
layer_place.Hide(True)
self.txt_material_list.pop()
return lay_count
def HTL_mats_scan(self, place, item):
if not item.IsProp() and not item.IsBodyPart(): return
sorted_materials = [
material
for material in item.Materials()
]
from functools import cmp_to_key
sorted_materials.sort(key=cmp_to_key(self.OnCompareItems))
for material in sorted_materials:
this = self.mats_tree_list.AppendItem(place, material.Name())
if not self.HTL_mat_scan_4_bitmaps(material, this):
this.Hide(True)
else:
this.Expand()
def HTL_Prepare_materials_list(self):
self.tree_root_materials.DeleteChildren(self.mats_tree_list.GetMainWindow())
self.txt_material_list = []
title = "Object"
if self.figure:
if self.figure.IsFigure():
actor = self.figure.RootActor()
title = "Figure: {}".format(self.figure.Name())
else:
actor = self.figure
title = "{}: {}".format(title, actor.Name())
self.txt_material_list = [title]
self.HTL_mats_scan(self.tree_root_materials, actor)
self.tree_root_materials.SetText(0, title)
# ---------- Events management
def on_close(self, event=None):
try:
if self.IsIconized(): self.Iconize(False)
if self.IsMaximized(): self.Maximize(False)
if not self.IsIconized():
self.save_config()
except: pass
self.Destroy()
def on_sizing(self, event=None):
if event:
new_w, new_h = event.GetSize()
for ctrl, rel_pos in self.moving_controls.items():
ctrl.Move(new_w-1-rel_pos[0], new_h-1-rel_pos[1])
event.ResumePropagation(wx.EVENT_PROPAGATE_MAX)
def on_activate(self, event=None):
if not event: return
if event.GetActive():
self.load_environment()
self.SetTitle(self.get_dialog_title())
# ---------- Hypertreelists Management
check = getattr(self, 'mats_tree_root', None)
if check:
self.HTL_Prepare_materials_list()
def action_export(self, event=None):
if not event: return
if not self.txt_material_list:
poser.DialogSimple.MessageBox("Nothing...")
return
get_open_file = poser.DialogFileChooser(
poser.kDialogFileChooserSave,
self.figure.Name(),
"Select output file",
wildcard="Text files (*.txt)|*.txt"
)
if (get_open_file.Show()):
output = open(get_open_file.Path(), 'w')
for line in self.txt_material_list:
print(line, file=output)
output.close()
# ---------- Gen Tools
def get_render_engine(self):
try:
return {
4: " - Superfly",
1: " - Firefly",
3: " - Sketch",
0: " - Preview"
}.get(self.scene.CurrentRenderEngine(), "")
except:
return ''
def load_config(self, def_x=100, def_y=200, def_w=750, def_h=300):
'''
Load the dialog's position from the configuration file, if any
'''
self.section_name = "Materials List"
self.configFile = os.path.join(poser.PrefsLocation(), "Cyp" + os.extsep + "cfg")
self.config = configparser.RawConfigParser()
self.config.read(self.configFile)
if not self.config.has_section(self.section_name): self.config.add_section(self.section_name)
try: self.dlg_x = self.config.getint(self.section_name, "x")
except: self.dlg_x = def_x
try: self.dlg_y = self.config.getint(self.section_name, "y")
except: self.dlg_y = def_y
try: self.dlg_w = self.config.getint(self.section_name, "w")
except: self.dlg_w = def_w
try: self.dlg_h = self.config.getint(self.section_name, "h")
except: self.dlg_h = def_h
def save_config(self):
r = self.GetScreenRect()
self.config.set(self.section_name, "x", r.left)
self.config.set(self.section_name, "y", r.top)
self.config.set(self.section_name, "w", r.width)
self.config.set(self.section_name, "h", r.height)
self.config.write(open(self.configFile, "w"))
def load_environment(self):
'''
Load all values for the dialog,
'''
self.scene = poser.Scene()
try:
figure = self.scene.CurrentActor()
if figure.IsBodyPart():
figure = self.scene.CurrentFigure()
except:
figure = None
self.figure = figure
def get_dialog_title(self):
title = "List of materials {}".format(self.get_render_engine())
if self.figure:
title = "{}: {}".format(title, self.figure.Name())
return title
dlg_name = "Cyp's Materials List"
# Kill any stalled previous instances
[w.Destroy() for w in poser.WxAuiManager().GetManagedWindow().GetParent().Children if w.GetName()==dlg_name]
CypMaterialsList(dlg_name)
In the case of the previous example (
#4480373):
And the exported file looks like this: