3 # #####BEGIN GPL LICENSE BLOCK #####
5 # This program is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU General Public License
7 # as published by the Free Software Foundation; either version 2
8 # of the License, or (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software Foundation,
17 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 # #####END GPL LICENSE BLOCK #####
22 "name": "Material Library",
23 "author": "Mackraken (mackraken2023@hotmail.com)",
27 "location": "Properties > Material",
28 "description": "Material Library VX",
30 "wiki_url": "https://sites.google.com/site/aleonserra/home/scripts/matlib-vx",
32 "category": "Material"}
38 from bpy
.app
.handlers
import persistent
39 from bpy
.props
import (
40 StringProperty
, IntProperty
, BoolProperty
,
41 PointerProperty
, CollectionProperty
43 from bpy
.types
import (
44 Panel
, Menu
, AddonPreferences
, Operator
,
52 matlib_path
= os
.path
.dirname(__file__
)
56 matlib_path
= r
"D:\Blender Foundation\Blender\2.72\scripts\addons\matlib"
58 ##debug print variables
59 def dd(*args
, dodir
=False):
67 return path
.replace("\\", "\\\\")
69 def update_search_index(self
, context
):
71 for i
, it
in enumerate(self
.materials
):
77 #isabs sometimes returns true on relpaths
78 if path
and os
.path
.exists(path
) and os
.path
.isfile(path
) and os
.path
.isabs(path
):
80 if bpy
.data
.filepath
and bpy
.path
.relpath(bpy
.data
.filepath
) == bpy
.path
.relpath(path
):
84 #paths are on different drives. No problem then
88 def update_lib_index(self
, context
):
91 def update_cat_index(self
, context
):
92 dd("cat index:", self
.current_category
, self
.filter)
98 def update_filter(self
, context
):
100 dd("filter:", self
.filter, self
.cat_index
, self
.current_category
)
101 # index = self.cat_index
104 # cat = self.current_category
108 # self.current_library.filter = cat
111 def check_index(collection
, index
):
112 count
= len(collection
)
113 return count
>0 and index
<count
and index
>=0
115 def send_command(cmd
, output
="sendmat.py"):
116 bin
= winpath(bpy
.app
.binary_path
)
117 scriptpath
= winpath(os
.path
.join(bpy
.app
.tempdir
, output
))
119 with
open(scriptpath
, "w") as f
:
124 if output
== "createlib.py":
125 code
= subprocess
.call([bin
, "-b", "-P", scriptpath
])
127 libpath
= winpath(bpy
.context
.scene
.matlib
.current_library
.path
)
128 code
= subprocess
.call([bin
, "-b", libpath
, "-P", scriptpath
])
130 #code returns 0 if ok, 1 if not
133 def list_materials(path
, sort
=False):
135 with bpy
.data
.libraries
.load(path
) as (data_from
, data_to
):
136 for mat
in data_from
.materials
:
139 if sort
: list = sorted(list)
142 #category properties (none atm)
143 class EmptyGroup(PropertyGroup
):
145 # bpy.utils.register_class(EmptyGroup)
147 class matlibMaterials(PropertyGroup
):
148 category
= StringProperty()
149 # bpy.utils.register_class(matlibMaterials)
151 #bpy.types.Scene.matlib_categories = CollectionProperty(type=EmptyGroup)
156 #cats = bpy.context.scene.matlib.categories
158 def __init__(self
, cats
):
162 scn
= bpy
.context
.scene
163 cats
= set([cat
.name
for cat
in self
.cats
])
164 libpath
= bpy
.context
.scene
.matlib
.current_library
.path
169 if not hasattr(bpy.context.scene, "matlib_categories"):
170 class EmptyProps(bpy.types.PropertyGroup):
172 bpy.utils.register_class(EmptyProps)
173 bpy.types.Scene.matlib_categories = bpy.props.CollectionProperty(type=EmptyProps)
174 cats = bpy.context.scene.matlib_categories
181 cat.name = "%s" """ % cat
.capitalize()
183 bpy.ops.wm.save_mainfile(filepath="%s", check_existing=False, compress=True)''' % winpath(libpath
)
185 return send_command(cmd
, "save_categories.py")
187 def read(self
, pull
=True):
188 #mandar a imprimir el listado
189 catfile
= winpath(os
.path
.join(matlib_path
, "categories.txt"))
192 class EmptyProps(bpy.types.PropertyGroup):
194 bpy.utils.register_class(EmptyProps)
195 bpy.types.Scene.matlib_categories = bpy.props.CollectionProperty(type=EmptyProps)
197 for cat in bpy.context.scene.matlib_categories:
199 for mat in bpy.data.materials:
200 if "category" in mat.keys() and mat['category'] == cat.name:
201 materials.append(mat.name)
202 cats.append([cat.name, materials])
203 with open("%s", "w") as f:
204 f.write(json.dumps(cats, sort_keys=True, indent=4))
206 if pull
: send_command(cmd
)
209 with
open(catfile
, "r") as f
:
210 cats
= json
.loads(f
.read())
214 # #refrescar categorias
215 # for cat in self.cats:
216 # self.cats.remove(0)
219 # item = self.cats.add()
225 for cat
in self
.cats
:
229 if name
and name
not in [item
.name
for item
in self
.cats
]:
230 name
= name
.strip().capitalize()
231 item
= self
.cats
.add()
239 def remove(self
, index
):
240 self
.cats
.remove(index
)
245 def __init__(self
, matlib_path
, name
):
247 self
.path
= os
.path
.join(matlib_path
, name
)
250 # return self.name == default_library
255 # return "Default Library"
256 return bpy
.path
.display_name(self
.name
).title()
260 return str(type(self
).__name
__) + "('" + self
.name
+ "')"
262 #bpy.utils.register_class(Library)
265 libs
= [Library(matlib_path
, f
) for f
in os
.listdir(matlib_path
) if f
[-5::] == "blend"]
267 user_path
= bpy
.context
.user_preferences
.addons
[__name__
].preferences
.matlib_path
269 if os
.path
.exists(user_path
):
270 libs
.extend([Library(user_path
, f
) for f
in os
.listdir(user_path
) if f
[-5::] == "blend"])
272 print("path not found %s" % user_path
)
275 return sorted(libs
, key
=lambda x
: bpy
.path
.display_name(x
.name
))
281 class matlibProperties(PropertyGroup
):
285 #libraries are read from the xml
286 lib_index
= IntProperty(min = -1, default
= 2, update
=update_lib_index
)
287 all_materials
= CollectionProperty(type = matlibMaterials
)
288 materials
= CollectionProperty(type = matlibMaterials
)
289 mat_index
= IntProperty(min = -1, default
= -1)
290 categories
= CollectionProperty(type = EmptyGroup
)
291 cat_index
= IntProperty(min = -1, default
= -1, update
=update_cat_index
)
292 search
= StringProperty(name
="Search", description
="Find By Name", update
=update_search_index
)
295 #link: import material linked
297 # if disable it wont import a material if its present in the scene,(avoid duplicates)
298 # instead it will apply the scene material rather than importing the same one from the library
299 #filter: enable or disable category filter
300 #last selected: store the last selected object to regain focus when apply a material.
301 #hide_search: Hides Search Field
302 link
= BoolProperty(name
= "Linked", description
="Link the material", default
= False)
303 force_import
= BoolProperty(name
= "Force Import", description
="Use Scene Materials by default", default
= False)
304 filter = BoolProperty(name
= "Filter",description
="Filter Categories", default
= False, update
=update_filter
)
305 show_prefs
= BoolProperty(name
= "show_prefs", description
="Preferences", default
= False)
306 last_selected
= StringProperty(name
="Last Selected")
307 hide_search
= BoolProperty(name
="Hide Search", description
="Use Blender Search Only")
308 #import_file = StringProperty("Import File", subtype="FILE_PATH")
309 #path = os.path.dirname(path)
318 def current_library(self
):
319 if check_index(libraries
, self
.lib_index
):
320 return libraries
[self
.lib_index
]
322 def active_material(self
):
323 if check_index(self
.materials
, self
.mat_index
):
324 return self
.materials
[self
.mat_index
]
327 dd("loading libraries")
329 if self
.current_library
:
331 elif self
.lib_index
== -1 and len(libraries
):
335 def add_library(self
, path
, setEnabled
= False):
337 ext
= os
.path
.extsep
+ "blend"
338 if not path
.endswith(ext
):
342 # if path == default_library:
343 # return 'ERROR', "Cannot add default library."
344 #if path in [lib.path for lib in self.libraries]:
345 return 'ERROR', "Library already exists."
347 dd("Can't find " + path
)
351 bpy.ops.wm.save_mainfile(filepath="%s", check_existing=False, compress=True)''' % winpath(path
)
352 if not (send_command(cmd
, "createlib.py")):
353 return 'ERROR', "There was an error creating the file. Make sure you run Blender with admin rights."
355 #self.libraries = sorted(self.libraries, key=lambda lib: sortlibs(lib))
356 dd("adding library", path
)
358 libraries
= get_libraries()
359 return "INFO", "Library added"
361 def load_library(self
):
362 self
.empty_list(True)
363 if not self
.current_library
:
364 return 'ERROR', "Library not found!."
366 path
= self
.current_library
.path
368 dd("loading library", self
.lib_index
, path
)
374 categories
= Categories(self
.categories
)
375 self
.cats
= categories
.read(True)
376 self
.load_categories()
378 for mat
in self
.all_materials
:
379 self
.all_materials
.remove(0)
381 for mat
in list_materials(self
.current_library
.path
, True):
382 item
= self
.all_materials
.add()
384 for cat
in self
.cats
:
386 item
.category
= cat
[0]
391 return 'ERROR', "Library not found!."
393 def update_list(self
):
396 if self
.current_library
:
397 current_category
= self
.current_category
398 #sorteditems = sorted(self.all_materials, key=lambda x: x.name)
399 for mat
in self
.all_materials
:
400 #print(current_category, mat.category)
401 if not self
.filter or (self
.filter and mat
.category
== current_category
) or current_category
== "":
402 item
= self
.materials
.add()
404 item
.category
= mat
.category
406 def empty_list(self
, cats
= False):
408 for it
in self
.materials
:
409 self
.materials
.remove(0)
412 for c
in self
.categories
:
413 self
.categories
.remove(0)
417 def current_category(self
):
418 #print(self.mat_index)
419 if check_index(self
.categories
, self
.cat_index
):
420 return self
.categories
[self
.cat_index
].name
423 def load_categories(self
):
425 for c
in self
.categories
:
426 self
.categories
.remove(0)
429 cat
= self
.categories
.add()
432 def add_category(self
, name
):
434 name
= name
.strip().title()
435 dd("add category", name
)
436 categories
= Categories(self
.categories
)
441 # cat = xml.find("category", name, lib, create = True)
442 # self.load_categories()
444 # return 'ERROR', "Library not found"
445 def remove_category(self
):
446 dd("removing category", self
.current_category
)
447 categories
= Categories(self
.categories
)
448 categories
.remove(self
.cat_index
)
450 def set_category(self
):
451 mat
= self
.active_material
452 #dd(lib, mat, self.current_category)
455 if self
.cat_index
>-1:
456 dd(self
.current_category
)
457 cat
= self
.current_category
458 if cat
== self
.all_materials
[self
.mat_index
].category
:
463 mat = bpy.data.materials['%s']
467 mat['category'] = "%s"
468 bpy.ops.wm.save_mainfile(filepath="%s", check_existing=False, compress=True)
469 """ % (mat
.name
, cat
, winpath(self
.current_library
.path
))
470 if send_command(cmd
):
471 self
.all_materials
[self
.mat_index
].category
= cat
474 return "WARNING", "There was an error."
476 # catnode = xml.find("category", self.current_category, lib, True)
477 # matnode = xml.find("material", mat.name, lib)
479 # catnode.appendChild(matnode)
481 # matnode = xml.find("material", mat.name, catnode, True)
484 # self.current_library.materials[self.mat_index].category = cat
485 #remove mat from any category
488 self
.all_materials
[self
.mat_index
].category
= ""
490 return "WARNING", "Select a material"
492 def get_material(self
, name
, link
=False):
493 with bpy
.data
.libraries
.load(self
.current_library
.path
, link
, False) as (data_from
, data_to
):
494 data_to
.materials
= [name
]
496 print(name
+ " linked.")
498 print(name
+ " appended.")
500 def apply(self
, context
, preview
=False):
501 name
= self
.active_material
.name
502 if not name
: return "WARNING", "Select a material from the list."
504 linked
= self
.link
or preview
505 force
= self
.force_import
or linked
508 active
= context
.object
509 dummy
= self
.get_dummy(context
)
513 if context
.mode
== "EDIT_MESH":
514 return "WARNING", "Can't preview on EDIT MODE"
516 self
.last_selected
= context
.object.name
517 context
.scene
.objects
.active
= dummy
518 objects
.append(dummy
)
521 objects
= [obj
for obj
in context
.selected_objects
if hasattr(obj
.data
, "materials")]
524 return "INFO", "Please select an object"
526 if dummy
== context
.object and not preview
:
527 if (len(objects
)==1 and dummy
.select
):
528 return "ERROR", "Apply is disabled for the Material Preview Object"
530 last
= context
.scene
.objects
[self
.last_selected
]
531 if last
in context
.selected_objects
:
532 context
.scene
.objects
.active
= last
534 self
.last_selected
= ""
536 context
.scene
.objects
.active
= None
538 #objects = context.selected_objects
542 #mira si hay materiales linkados de la libreria actual
543 for mat
in bpy
.data
.materials
:
545 samelib
= bpy
.path
.relpath(mat
.library
.filepath
) == bpy
.path
.relpath(self
.current_library
.path
)
549 if mat
.name
== name
and mat
.library
and samelib
:
551 dd("encontre linked", name
, "no importo nada")
555 #busca materiales no linkados
556 for mat
in bpy
.data
.materials
:
557 if mat
.name
== name
and not mat
.library
:
559 dd("encontre no linkado", name
, "no importo nada")
565 nmats
= len(bpy
.data
.materials
)
567 self
.get_material(name
, linked
)
569 if not self
.force_import
:
571 material
= bpy
.data
.materials
[name
]
576 if nmats
== len(bpy
.data
.materials
) and not linked
:
577 return "ERROR", name
+ " doesn't exists at library " + str(linked
)
579 for mat
in reversed(bpy
.data
.materials
):
580 if mat
.name
[0:len(name
)] == name
:
581 #careful on how blender writes library paths
583 samelib
= bpy
.path
.relpath(mat
.library
.filepath
) == bpy
.path
.relpath(self
.current_library
.path
)
587 if linked
and mat
.library
and samelib
:
589 dd(name
, "importado con link")
593 dd(name
, "importado sin link")
597 material
.use_fake_user
= False
598 material
.user_clear()
600 print ("Material", material
, force
)
603 #maybe some test cases doesnt return a material, gotta take care of that
604 #i cannot think of any case like that right now
605 #maybe import linked when the database isnt sync
606 if context
.mode
== "EDIT_MESH":
610 for i
, mat
in enumerate(obj
.data
.materials
):
616 obj
.data
.materials
.append(material
)
617 index
= len(obj
.data
.materials
)-1
620 bm
= bmesh
.from_edit_mesh(obj
.data
)
623 f
.material_index
= index
627 index
= obj
.active_material_index
628 if index
< len(obj
.material_slots
):
629 obj
.material_slots
[index
].material
= None
630 obj
.material_slots
[index
].material
= material
632 obj
.data
.materials
.append(material
)
635 bpy
.ops
.object.make_local(type="SELECT_OBDATA_MATERIAL")
637 def add_material(self
, mat
):
640 return 'WARNING', "Select a material from the scene."
643 thispath
= winpath(bpy
.data
.filepath
)
644 libpath
= winpath(self
.current_library
.path
)
647 return 'WARNING', "Save this file before export."
650 return 'WARNING', "Library not found!."
652 elif bpy
.data
.is_dirty
:
653 bpy
.ops
.wm
.save_mainfile(check_existing
=True)
656 return 'WARNING', 'Cannot export linked materials.'
658 dd("adding material", name
, libpath
)
661 if name
in list_materials(libpath
):
663 mat = bpy.data.materials["%s"]
665 mat.use_fake_user = False
666 mat.user_clear()''' % name
670 with bpy.data.libraries.load("{1}") as (data_from, data_to):
671 data_to.materials = ["{2}"]
672 mat = bpy.data.materials["{2}"]
673 mat.use_fake_user=True
674 bpy.ops.file.pack_all()
675 bpy.ops.wm.save_mainfile(filepath="{3}", check_existing=False, compress=True)
676 '''.format(overwrite
, thispath
, name
, libpath
)
678 if send_command(cmd
):
681 item
= self
.all_materials
.add()
683 if "category" in mat
.keys():
684 item
.category
= mat
['category']
685 #reorder all_materials
686 items
= sorted([[item
.name
, item
.category
] for item
in self
.all_materials
], key
= lambda x
: x
[0])
688 self
.all_materials
.clear()
690 item
= self
.all_materials
.add()
692 item
.category
= it
[1]
696 return 'INFO', "Material added."
698 print("Save Material Error: Run Blender with administrative priviledges.")
699 return 'WARNING', "There was an error saving the material"
701 def remove_material(self
):
702 name
= self
.active_material
.name
703 libpath
= winpath(self
.current_library
.path
)
704 if name
and libpath
and name
in list_materials(libpath
):
706 mat = bpy.data.materials["%s"]
707 mat.use_fake_user = False
709 bpy.ops.wm.save_mainfile(filepath="%s", check_existing=False, compress=True)''' % (name
, libpath
)
710 if send_command(cmd
, "removemat.py"):
711 self
.all_materials
.remove(self
.mat_index
)
714 return 'ERROR', "There was an error."
715 return "INFO", name
+ " removed."
717 def get_dummy(self
, context
):
718 dummy_name
= "Material_Preview_Dummy"
719 dummy_mesh
= "Material_Preview_Mesh"
722 dummy
= scn
.objects
[dummy_name
]
726 me
= bpy
.data
.meshes(dummy_mesh
)
728 me
= bpy
.data
.meshes
.new(dummy_mesh
)
729 dummy
= bpy
.data
.objects
.new(dummy_name
, me
)
730 scn
.objects
.link(dummy
)
733 dummy
.hide_render
= True
734 dummy
.hide_select
= True
737 # bpy.utils.register_class(matlibProperties)
738 # Scene.matlib = PointerProperty(type = matlibProperties)
741 class MATLIB_MT_LibsMenu(Menu
):
742 bl_label
= "Libraries Menu"
744 def draw(self
, context
):
747 #layout.operator("matlib.operator", text="Default Library").cmd="lib-1"
748 for i
, lib
in enumerate(libs
):
749 layout
.operator("matlib.operator", text
=lib
.shortname
).cmd
="lib"+str(i
)
751 class MATLIB_MT_CatsMenu(Menu
):
752 bl_label
= "Categories Menu"
754 def draw(self
, context
):
756 cats
= context
.scene
.matlib
.categories
757 layout
.operator("matlib.operator", text
="All").cmd
="cat-1"
758 for i
, cat
in enumerate(cats
):
759 layout
.operator("matlib.operator", text
=cat
.name
).cmd
="cat"+str(i
)
762 #class MATLIB_OT_add(Operator):
763 # """Add Active Material"""
765 # bl_idname = "matlib.add_material"
768 # def poll(cls, context):
769 # return context.active_object is not None
771 # def exectute(self, context):
773 # return {"FINISHED"}
777 class MATLIB_OT_add(Operator
):
778 """Add active material to library"""
779 bl_idname
= "matlib.add"
780 bl_label
= "Add active material"
783 def poll(cls
, context
):
784 obj
= context
.active_object
785 return obj
is not None and obj
.active_material
is not None
787 def execute(self
, context
):
788 matlib
= context
.scene
.matlib
789 success
= matlib
.add_material(context
.object.active_material
)
790 if type(success
).__name
__ == "tuple":
792 self
.report({success
[0]}, success
[1])
795 class MATLIB_OT_remove(Operator
):
796 """Remove material from library"""
797 bl_idname
= "matlib.remove"
798 bl_label
= "Remove material from library"
801 def poll(cls
, context
):
802 matlib
= context
.scene
.matlib
803 return check_index(matlib
.materials
, matlib
.mat_index
)
805 def execute(self
, context
):
806 matlib
= context
.scene
.matlib
807 success
= matlib
.remove_material()
808 if type(success
).__name
__ == "tuple":
810 self
.report({success
[0]}, success
[1])
813 class MATLIB_OT_remove(Operator
):
815 bl_idname
= "matlib.reload"
816 bl_label
= "Reload library"
819 # def poll(cls, context):
820 # matlib = context.scene.matlib
821 # index = matlib.mat_index
822 # l = len(matlib.materials)
823 # return l>0 and index >=0 and index < l
825 def execute(self
, context
):
826 matlib
= context
.scene
.matlib
827 success
= matlib
.reload()
828 if type(success
).__name
__ == "tuple":
830 self
.report({success
[0]}, success
[1])
834 class MATLIB_OT_apply(Operator
):
835 """Apply selected material"""
836 bl_idname
= "matlib.apply"
837 bl_label
= "Apply material"
840 def poll(cls
, context
):
841 matlib
= context
.scene
.matlib
842 index
= matlib
.mat_index
843 l
= len(matlib
.materials
)
844 obj
= context
.active_object
845 return l
>0 and index
>=0 and index
< l
and obj
is not None
847 def execute(self
, context
):
848 matlib
= context
.scene
.matlib
849 success
= matlib
.apply(context
, False)
850 if type(success
).__name
__ == "tuple":
852 self
.report({success
[0]}, success
[1])
856 class MATLIB_OT_preview(Operator
):
857 """Preview selected material"""
858 bl_idname
= "matlib.preview"
859 bl_label
= "Preview selected material"
862 def poll(cls
, context
):
863 matlib
= context
.scene
.matlib
864 index
= matlib
.mat_index
865 l
= len(matlib
.materials
)
866 obj
= context
.active_object
867 return l
>0 and index
>=0 and index
< l
869 def execute(self
, context
):
870 matlib
= context
.scene
.matlib
871 success
= matlib
.apply(context
, True)
872 if type(success
).__name
__ == "tuple":
874 self
.report({success
[0]}, success
[1])
878 class MATLIB_OT_flush(Operator
):
879 """Flush unused materials"""
880 bl_idname
= "matlib.flush"
881 bl_label
= "Flush unused materials"
884 def poll(cls
, context
):
885 matlib
= context
.scene
.matlib
886 index
= matlib
.mat_index
887 l
= len(matlib
.materials
)
888 obj
= context
.active_object
889 return l
>0 and index
>=0 and index
< l
891 def execute(self
, context
):
892 matlib
= context
.scene
.matlib
893 dummy
= matlib
.get_dummy(context
)
894 if dummy
== context
.object:
896 context
.scene
.objects
.active
= context
.scene
.objects
[matlib
.last_selected
]
900 for slot
in dummy
.material_slots
:
903 for mat
in bpy
.data
.materials
:
906 print (mat
.name
, "removed.")
907 bpy
.data
.materials
.remove(mat
)
909 plural
= "" if i
== 1 else "s"
910 self
.report({'INFO'}, str(i
) + " material"+plural
+" removed.")
915 class MATLIB_OT_operator(Operator
):
916 """Add, Remove, Reload, Apply, Preview, Clean Material"""
918 bl_idname
= "matlib.operator"
919 __doc__
= "Add, Remove, Reload, Apply, Preview, Clean Material"
921 category
= StringProperty(name
="Category")
922 filepath
= StringProperty(options
={'HIDDEN'})
923 cmd
= bpy
.props
.StringProperty(name
="Command", options
={'HIDDEN'})
924 filter_glob
= StringProperty(default
="*.blend", options
={'HIDDEN'})
926 def poll(cls
, context
):
927 return context
.active_object
is not None
929 def draw(self
, context
):
932 if self
.cmd
== "LIBRARY_ADD":
933 #layout.label("Select a blend file as library or")
934 #layout.label("Type a name to create a new library.")
935 layout
.prop(self
, "category", text
="Library")
936 elif self
.cmd
== "FILTER_ADD":
937 layout
.prop(self
, "category")
939 def invoke(self
, context
, event
):
944 if cmd
== "LIBRARY_ADD":
945 self
.filepath
= matlib_path
+ os
.path
.sep
946 dd("filepath", self
.filepath
, matlib_path
)
947 #context.window_manager.fileselect_add(self)
948 context
.window_manager
.invoke_props_dialog(self
)
949 return {'RUNNING_MODAL'}
950 elif cmd
== "FILTER_ADD":
951 context
.window_manager
.invoke_props_dialog(self
)
952 return {'RUNNING_MODAL'}
953 return self
.execute(context
)
955 ### TODO: execute doesnt trigger remove
956 def execute(self
, context
):
959 matlib
= context
.scene
.matlib
961 if self
.cmd
== "init":
966 if self
.cmd
[0:3] == "lib":
967 index
= int(self
.cmd
[3::])
968 matlib
.lib_index
= index
969 #success = matlib.load_library()
970 elif self
.cmd
== "LIBRARY_ADD":
971 dd("execute lib add")
972 libname
= self
.category
973 if libname
[-6::] != ".blend": libname
+= ".blend"
974 libname
= os
.path
.join(matlib_path
, libname
)
977 success
= matlib
.add_library(libname
, True)
978 for i
, l
in enumerate(libraries
):
979 if l
.name
== self
.category
:
983 elif self
.cmd
== "RELOAD":
984 success
= matlib
.reload()
986 if not matlib
.current_library
:
987 self
.report({'ERROR'}, "Select a Library")
990 if self
.cmd
== "FILTER_ADD":
991 success
= matlib
.add_category(self
.category
)
992 for i
, cat
in enumerate(matlib
.categories
):
993 if cat
.name
== self
.category
:
997 elif self
.cmd
== "FILTER_REMOVE":
998 matlib
.remove_category()
1000 elif self
.cmd
== "FILTER_SET":
1001 success
= matlib
.set_category()
1003 elif self
.cmd
[0:3] == "cat":
1004 index
= int(self
.cmd
[3::])
1005 matlib
.cat_index
= index
1008 elif self
.cmd
== "ADD":
1009 success
= matlib
.add_material(context
.object.active_material
)
1011 elif self
.cmd
== "REMOVE":
1012 success
= matlib
.remove_material()
1015 elif self
.cmd
== "APPLY":
1016 success
= matlib
.apply(context
)
1018 elif self
.cmd
== "PREVIEW":
1019 success
= matlib
.apply(context
, True)
1021 elif self
.cmd
=="FLUSH":
1022 #release dummy materials
1023 dummy
= matlib
.get_dummy(context
)
1024 if dummy
== context
.object:
1026 context
.scene
.objects
.active
= context
.scene
.objects
[matlib
.last_selected
]
1030 for slot
in dummy
.material_slots
:
1031 slot
.material
= None
1033 for mat
in bpy
.data
.materials
:
1036 print (mat
.name
, "removed.")
1037 bpy
.data
.materials
.remove(mat
)
1043 self
.report({'INFO'}, str(i
) + " material"+plural
+" removed.")
1046 elif self
.cmd
== "CONVERT":
1048 lib
= matlib
.current_library
1051 path
= os
.path
.join(matlib_path
, "www")
1052 if not os
.path
.exists(path
):
1054 path
= os
.path
.join(path
, lib
.shortname
)
1055 if not os
.path
.exists(path
):
1058 path
= winpath(path
)
1059 libpath
= winpath(lib
.name
)
1064 #decirle a la libreria que cree un fichero blend por cada material que tenga.
1068 def list_materials():
1070 with bpy.data.libraries.load("{0}") as (data_from, data_to):
1071 for mat in data_from.materials:
1075 def get_material(name, link=False):
1076 with bpy.data.libraries.load("{0}", link, False) as (data_from, data_to):
1077 data_to.materials = [name]
1079 print(name + " linked.")
1081 print(name + " appended.")
1083 for scn in bpy.data.scenes:
1084 for obj in scn.objects:
1085 scn.objects.unlink(obj)
1087 bpy.data.objects.remove(obj)
1089 def clean_materials():
1090 for mat in bpy.data.materials:
1092 bpy.data.materials.remove(mat)
1094 bin = bpy.app.binary_path
1095 mats = list_materials()
1096 bpy.context.user_preferences.filepaths.save_version = 0
1099 matpath = os.path.join("{1}", mat + ".blend")
1102 material = bpy.data.materials[0]
1103 material.use_fake_user = True
1104 bpy.ops.wm.save_mainfile(filepath = matpath, compress=True, check_existing=False)
1105 """.format(libpath
, path
)
1107 send_command(cmd
, "createlib.py")
1109 if type(success
).__name
__ == "tuple":
1111 self
.report({success
[0]}, success
[1])
1116 class MATLIB_PT_vxPanel(Panel
):
1117 bl_label
= "Material Library VX"
1118 bl_space_type
= "PROPERTIES"
1119 bl_region_type
= "WINDOW"
1120 bl_context
= "material"
1123 def poll(self
, context
):
1124 return context
.active_object
.active_material
!=None
1126 def draw(self
, context
):
1127 layout
= self
.layout
1128 matlib
= context
.scene
.matlib
1130 #hyper ugly trick but i dont know how to init classes at register time
1131 # if matlibProperties.init:
1132 # matlibProperties.init = False
1136 row
= layout
.row(align
=True)
1137 if matlib
.current_library
:
1138 text
= matlib
.current_library
.shortname
1140 text
= "Select a Library"
1142 row
.menu("MATLIB_MT_LibsMenu",text
=text
)
1143 row
.operator("matlib.operator", icon
="ZOOMIN", text
="").cmd
= "LIBRARY_ADD"
1144 if matlib
.active_material
:
1145 row
.label(matlib
.active_material
.category
)
1150 if not matlib
.hide_search
:
1151 row
= layout
.row(align
=True)
1152 row
.prop_search(matlib
, "search", matlib
, "materials", text
="", icon
="VIEWZOOM")
1156 row
.template_list("UI_UL_list", " ", matlib
, "materials", matlib
, "mat_index", rows
=6)
1157 col
= row
.column(align
=True)
1161 col
.operator("matlib.add", icon
="ZOOMIN", text
="")
1162 col
.operator("matlib.remove", icon
="ZOOMOUT", text
="")
1163 col
.operator("matlib.reload", icon
="FILE_REFRESH", text
="")
1164 col
.operator("matlib.apply", icon
="MATERIAL", text
="")
1165 col
.operator("matlib.preview", icon
="COLOR", text
="")
1166 col
.operator("matlib.flush", icon
="GHOST_DISABLED", text
="")
1167 col
.prop(matlib
, "show_prefs", icon
="MODIFIER", text
="")
1170 row
= layout
.row(align
=True)
1172 if matlib
.current_category
: text
= matlib
.current_category
1173 row
.menu("MATLIB_MT_CatsMenu",text
=text
)
1174 row
.prop(matlib
, "filter", icon
="FILTER", text
="")
1175 row
.operator("matlib.operator", icon
="FILE_PARENT", text
="").cmd
="FILTER_SET"
1176 row
.operator("matlib.operator", icon
="ZOOMIN", text
="").cmd
="FILTER_ADD"
1177 row
.operator("matlib.operator", icon
="ZOOMOUT", text
="").cmd
="FILTER_REMOVE"
1180 if matlib
.show_prefs
:
1182 row
.prop(matlib
, "force_import")
1183 row
.prop(matlib
, "link")
1185 row
.prop(matlib
, "hide_search")
1186 # row = layout.row(align=True)
1188 #row.operator("matlib.operator", icon="URL", text="Convert Library").cmd="CONVERT"
1190 # row = layout.row()
1191 # if (matlib.current_library):
1192 # row.label(matlib.current_library.name)
1194 # row.label("Library not found!.")
1196 #classes = [MATLIB_PT_vxPanel, MATLIB_OT_operator, MATLIB_MT_LibsMenu, MATLIB_MT_CatsMenu]
1197 #print(bpy.context.scene)
1201 def refresh_libs(dummy
=None):
1203 libraries
= get_libraries()
1206 def reload_library(self
, context
):
1210 class matlibvxPref(AddonPreferences
):
1211 bl_idname
= __name__
1213 matlib_path
= StringProperty(
1214 name
="Additional Path",
1215 description
="User defined path to .blend libraries files",
1217 update
=reload_library
1220 def draw(self
, context
):
1221 layout
= self
.layout
1222 layout
.prop(self
, "matlib_path")
1227 bpy
.utils
.register_module(__name__
)
1229 # bpy.utils.register_class(c)
1230 Scene
.matlib_categories
= CollectionProperty(type=EmptyGroup
)
1231 Scene
.matlib
= PointerProperty(type = matlibProperties
)
1232 bpy
.app
.handlers
.load_post
.append(refresh_libs
)
1233 libraries
= get_libraries()
1238 bpy
.utils
.unregister_module(__name__
)
1240 # raise ValueError list.remove(x): x not in list
1241 del Scene
.matlib_categories
1246 bpy
.app
.handlers
.load_post
.remove(refresh_libs
)
1248 # bpy.utils.unregister_class(c)
1251 if __name__
== "__main__":