math_vis: remove use of register_module
[blender-addons.git] / materials_library_vx / __init__.py
blob071318627dea0cc223da94b93dec1566734fcfad
1 # -*- coding:utf-8 -*-
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 #####
21 bl_info = {
22 "name": "Material Library",
23 "author": "Mackraken (mackraken2023@hotmail.com)",
24 "version": (0, 5, 8),
25 "blender": (2, 7, 8),
26 "api": 60995,
27 "location": "Properties > Material",
28 "description": "Material Library VX",
29 "warning": "",
30 "wiki_url": "https://sites.google.com/site/aleonserra/home/scripts/matlib-vx",
31 "tracker_url": "",
32 "category": "Material"}
35 import bpy
36 import os
37 import json
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,
45 PropertyGroup,
46 Scene
50 dev = False
52 matlib_path = os.path.dirname(__file__)
54 if dev:
55 print (30*"-")
56 matlib_path = r"D:\Blender Foundation\Blender\2.72\scripts\addons\matlib"
58 ##debug print variables
59 def dd(*args, dodir=False):
60 if dev:
61 if dodir:
62 print(dir(*args))
63 print(*args)
65 #Regular Functions
66 def winpath(path):
67 return path.replace("\\", "\\\\")
69 def update_search_index(self, context):
70 search = self.search
71 for i, it in enumerate(self.materials):
72 if it.name==search:
73 self.mat_index = i
74 break
76 def check_path(path):
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):
79 try:
80 if bpy.data.filepath and bpy.path.relpath(bpy.data.filepath) == bpy.path.relpath(path):
81 return False
82 except:
83 pass
84 #paths are on different drives. No problem then
85 return True
86 return False
88 def update_lib_index(self, context):
89 self.load_library()
91 def update_cat_index(self, context):
92 dd("cat index:", self.current_category, self.filter)
94 if self.filter:
95 self.filter = True
98 def update_filter(self, context):
100 dd("filter:", self.filter, self.cat_index, self.current_category)
101 # index = self.cat_index
103 # if self.filter:
104 # cat = self.current_category
105 # else:
106 # cat = ""
108 # self.current_library.filter = cat
109 self.update_list()
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:
120 f.write(cmd)
122 import subprocess
124 if output == "createlib.py":
125 code = subprocess.call([bin, "-b", "-P", scriptpath])
126 else:
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
131 return abs(code-1)
133 def list_materials(path, sort=False):
134 list = []
135 with bpy.data.libraries.load(path) as (data_from, data_to):
136 for mat in data_from.materials:
137 list.append(mat)
139 if sort: list = sorted(list)
140 return list
142 #category properties (none atm)
143 class EmptyGroup(PropertyGroup):
144 pass
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)
153 ### CATEGORIES
154 class Categories():
156 #cats = bpy.context.scene.matlib.categories
158 def __init__(self, cats):
159 self.cats = cats
161 def save(self):
162 scn = bpy.context.scene
163 cats = set([cat.name for cat in self.cats])
164 libpath = bpy.context.scene.matlib.current_library.path
166 cmd = """
167 print(30*"+")
168 import bpy
169 if not hasattr(bpy.context.scene, "matlib_categories"):
170 class EmptyProps(bpy.types.PropertyGroup):
171 pass
172 bpy.utils.register_class(EmptyProps)
173 bpy.types.Scene.matlib_categories = bpy.props.CollectionProperty(type=EmptyProps)
174 cats = bpy.context.scene.matlib_categories
175 for cat in cats:
176 cats.remove(0)
178 for cat in cats:
179 cmd += """
180 cat = cats.add()
181 cat.name = "%s" """ % cat.capitalize()
182 cmd +='''
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"))
190 cmd = """
191 import bpy, json
192 class EmptyProps(bpy.types.PropertyGroup):
193 pass
194 bpy.utils.register_class(EmptyProps)
195 bpy.types.Scene.matlib_categories = bpy.props.CollectionProperty(type=EmptyProps)
196 cats = []
197 for cat in bpy.context.scene.matlib_categories:
198 materials = []
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))
205 """ % catfile
206 if pull: send_command(cmd)
208 #leer el fichero
209 with open(catfile, "r") as f:
210 cats = json.loads(f.read())
212 dd(cats)
214 # #refrescar categorias
215 # for cat in self.cats:
216 # self.cats.remove(0)
218 # for cat in cats:
219 # item = self.cats.add()
220 # item.name = cat
222 return cats
224 def view(self):
225 for cat in self.cats:
226 dd(cat.name)
228 def add(self, name):
229 if name and name not in [item.name for item in self.cats]:
230 name = name.strip().capitalize()
231 item = self.cats.add()
232 item.name = name
233 if self.save():
234 dd(name, "added")
235 return True
236 else:
237 dd("duplicated?")
239 def remove(self, index):
240 self.cats.remove(index)
241 self.save()
243 class Library():
245 def __init__(self, matlib_path, name):
246 self.name = name
247 self.path = os.path.join(matlib_path, name)
248 # @property
249 # def default(self):
250 # return self.name == default_library
252 @property
253 def shortname(self):
254 # if self.default:
255 # return "Default Library"
256 return bpy.path.display_name(self.name).title()
259 def __repr__(self):
260 return str(type(self).__name__) + "('" + self.name + "')"
262 #bpy.utils.register_class(Library)
264 def get_libraries():
265 libs = [Library(matlib_path, f) for f in os.listdir(matlib_path) if f[-5::] == "blend"]
266 try:
267 user_path = bpy.context.user_preferences.addons[__name__].preferences.matlib_path
268 if user_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"])
271 else:
272 print("path not found %s" % user_path)
273 except:
274 pass
275 return sorted(libs, key=lambda x: bpy.path.display_name(x.name))
277 libraries = []
278 # get_libraries()
280 ### MATLIB CLASS
281 class matlibProperties(PropertyGroup):
283 #MATLIB PROPERTIES
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)
294 #MATLIB OPTIONS
295 #link: import material linked
296 #force import:
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)
310 #Development only
312 @property
313 def libraries(self):
314 global libraries
315 return libraries
317 @property
318 def current_library(self):
319 if check_index(libraries, self.lib_index):
320 return libraries[self.lib_index]
321 @property
322 def active_material(self):
323 if check_index(self.materials, self.mat_index):
324 return self.materials[self.mat_index]
326 def reload(self):
327 dd("loading libraries")
329 if self.current_library:
330 self.load_library()
331 elif self.lib_index == -1 and len(libraries):
332 self.lib_index = 0
335 def add_library(self, path, setEnabled = False):
336 #sanitize path
337 ext = os.path.extsep + "blend"
338 if not path.endswith(ext):
339 path += ext
341 if check_path(path):
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."
346 else:
347 dd("Can't find " + path)
348 #create file
349 cmd = '''
350 import bpy
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)
357 global libraries
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)
370 if check_path(path):
371 self.filter = False
372 self.cat_index = -1
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()
383 item.name = mat
384 for cat in self.cats:
385 if mat in cat[1]:
386 item.category = cat[0]
387 break
389 self.update_list()
390 else:
391 return 'ERROR', "Library not found!."
393 def update_list(self):
394 ### THIS HAS TO SORT
395 self.empty_list()
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()
403 item.name = mat.name
404 item.category = mat.category
406 def empty_list(self, cats = False):
407 #self.mat_index = -1
408 for it in self.materials:
409 self.materials.remove(0)
411 if cats:
412 for c in self.categories:
413 self.categories.remove(0)
415 ### CATEGORIES
416 @property
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
421 return ""
423 def load_categories(self):
425 for c in self.categories:
426 self.categories.remove(0)
428 for c in self.cats:
429 cat = self.categories.add()
430 cat.name = c[0]
432 def add_category(self, name):
433 if name:
434 name = name.strip().title()
435 dd("add category", name)
436 categories = Categories(self.categories)
438 categories.add(name)
440 # if lib:
441 # cat = xml.find("category", name, lib, create = True)
442 # self.load_categories()
443 # else:
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)
453 if mat:
454 #set mat to 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:
459 return
460 cmd = """
461 import bpy
462 try:
463 mat = bpy.data.materials['%s']
464 except:
465 mat = None
466 if mat:
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
472 mat.category = cat
473 else:
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)
478 # if matnode:
479 # catnode.appendChild(matnode)
480 # else:
481 # matnode = xml.find("material", mat.name, catnode, True)
482 # xml.save()
483 # mat.category = cat
484 # self.current_library.materials[self.mat_index].category = cat
485 #remove mat from any category
486 else:
487 mat.category = ""
488 self.all_materials[self.mat_index].category = ""
489 else:
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]
495 if link:
496 print(name + " linked.")
497 else:
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
507 objects = []
508 active = context.object
509 dummy = self.get_dummy(context)
511 #setup objects
512 if preview:
513 if context.mode == "EDIT_MESH":
514 return "WARNING", "Can't preview on EDIT MODE"
515 if dummy!= active:
516 self.last_selected = context.object.name
517 context.scene.objects.active = dummy
518 objects.append(dummy)
519 #apply
520 else:
521 objects = [obj for obj in context.selected_objects if hasattr(obj.data, "materials")]
523 if not objects:
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"
529 try:
530 last = context.scene.objects[self.last_selected]
531 if last in context.selected_objects:
532 context.scene.objects.active = last
533 else:
534 self.last_selected = ""
535 except:
536 context.scene.objects.active = None
537 dummy.select = False
538 #objects = context.selected_objects
540 material = None
542 #mira si hay materiales linkados de la libreria actual
543 for mat in bpy.data.materials:
544 try:
545 samelib = bpy.path.relpath(mat.library.filepath) == bpy.path.relpath(self.current_library.path)
546 except:
547 samelib = False
549 if mat.name == name and mat.library and samelib:
550 material = mat
551 dd("encontre linked", name, "no importo nada")
552 break
554 if not force:
555 #busca materiales no linkados
556 for mat in bpy.data.materials:
557 if mat.name == name and not mat.library:
558 material = mat
559 dd("encontre no linkado", name, "no importo nada")
560 break
562 if not material:
563 #go get it
564 dd("voy a buscarlo")
565 nmats = len(bpy.data.materials)
567 self.get_material(name, linked)
569 if not self.force_import:
570 try:
571 material = bpy.data.materials[name]
572 except:
573 pass
575 if not material:
576 if nmats == len(bpy.data.materials) and not linked:
577 return "ERROR", name + " doesn't exists at library " + str(linked)
578 else:
579 for mat in reversed(bpy.data.materials):
580 if mat.name[0:len(name)] == name:
581 #careful on how blender writes library paths
582 try:
583 samelib = bpy.path.relpath(mat.library.filepath) == bpy.path.relpath(self.current_library.path)
584 except:
585 samelib = False
587 if linked and mat.library and samelib:
588 material = mat
589 dd(name, "importado con link")
590 break
591 else:
592 if not mat.library:
593 dd(name, "importado sin link")
594 material = mat
595 break
596 if material:
597 material.use_fake_user = False
598 material.user_clear()
600 print ("Material", material, force)
602 #if material:
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":
607 obj = context.object
608 dd(material)
609 index = -1
610 for i, mat in enumerate(obj.data.materials):
611 if mat == material:
612 index = i
613 break
615 if index == -1:
616 obj.data.materials.append(material)
617 index = len(obj.data.materials)-1
618 dd(index)
619 import bmesh
620 bm = bmesh.from_edit_mesh(obj.data)
621 for f in bm.faces:
622 if f.select:
623 f.material_index = index
625 else:
626 for obj in objects:
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
631 else:
632 obj.data.materials.append(material)
634 if not linked:
635 bpy.ops.object.make_local(type="SELECT_OBDATA_MATERIAL")
637 def add_material(self, mat):
639 if not mat:
640 return 'WARNING', "Select a material from the scene."
642 name = mat.name
643 thispath = winpath(bpy.data.filepath)
644 libpath = winpath(self.current_library.path)
646 if not thispath:
647 return 'WARNING', "Save this file before export."
649 if not libpath:
650 return 'WARNING', "Library not found!."
652 elif bpy.data.is_dirty:
653 bpy.ops.wm.save_mainfile(check_existing=True)
655 if mat.library:
656 return 'WARNING', 'Cannot export linked materials.'
658 dd("adding material", name, libpath)
660 overwrite = ""
661 if name in list_materials(libpath):
662 overwrite = '''
663 mat = bpy.data.materials["%s"]
664 mat.name = "tmp"
665 mat.use_fake_user = False
666 mat.user_clear()''' % name
668 cmd = '''
669 import bpy{0}
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):
679 #self.load_library()
680 if not overwrite:
681 item = self.all_materials.add()
682 item.name = name
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()
689 for it in items:
690 item = self.all_materials.add()
691 item.name = it[0]
692 item.category = it[1]
694 self.update_list()
696 return 'INFO', "Material added."
697 else:
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):
705 cmd = '''import bpy
706 mat = bpy.data.materials["%s"]
707 mat.use_fake_user = False
708 mat.user_clear()
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)
712 self.update_list()
713 else:
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"
720 scn = context.scene
721 try:
722 dummy = scn.objects[dummy_name]
723 except:
724 #create dummy
725 try:
726 me = bpy.data.meshes(dummy_mesh)
727 except:
728 me = bpy.data.meshes.new(dummy_mesh)
729 dummy = bpy.data.objects.new(dummy_name, me)
730 scn.objects.link(dummy)
732 dummy.hide = True
733 dummy.hide_render = True
734 dummy.hide_select = True
735 return dummy
737 # bpy.utils.register_class(matlibProperties)
738 # Scene.matlib = PointerProperty(type = matlibProperties)
740 ### MENUS
741 class MATLIB_MT_LibsMenu(Menu):
742 bl_label = "Libraries Menu"
744 def draw(self, context):
745 layout = self.layout
746 libs = libraries
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):
755 layout = self.layout
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)
761 ### OPERATORS
762 #class MATLIB_OT_add(Operator):
763 # """Add Active Material"""
764 # bl_label = "Add"
765 # bl_idname = "matlib.add_material"
767 # @classmethod
768 # def poll(cls, context):
769 # return context.active_object is not None
771 # def exectute(self, context):
772 # print("executing")
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"
782 @classmethod
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":
791 print(success)
792 self.report({success[0]}, success[1])
793 return {'FINISHED'}
795 class MATLIB_OT_remove(Operator):
796 """Remove material from library"""
797 bl_idname = "matlib.remove"
798 bl_label = "Remove material from library"
800 @classmethod
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":
809 print(success)
810 self.report({success[0]}, success[1])
811 return {'FINISHED'}
813 class MATLIB_OT_remove(Operator):
814 """Reload library"""
815 bl_idname = "matlib.reload"
816 bl_label = "Reload library"
818 # @classmethod
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":
829 print(success)
830 self.report({success[0]}, success[1])
831 return {'FINISHED'}
834 class MATLIB_OT_apply(Operator):
835 """Apply selected material"""
836 bl_idname = "matlib.apply"
837 bl_label = "Apply material"
839 @classmethod
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":
851 print(success)
852 self.report({success[0]}, success[1])
853 return {'FINISHED'}
856 class MATLIB_OT_preview(Operator):
857 """Preview selected material"""
858 bl_idname = "matlib.preview"
859 bl_label = "Preview selected material"
861 @classmethod
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":
873 print(success)
874 self.report({success[0]}, success[1])
875 return {'FINISHED'}
878 class MATLIB_OT_flush(Operator):
879 """Flush unused materials"""
880 bl_idname = "matlib.flush"
881 bl_label = "Flush unused materials"
883 @classmethod
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:
895 try:
896 context.scene.objects.active = context.scene.objects[matlib.last_selected]
897 except:
898 pass
900 for slot in dummy.material_slots:
901 slot.material = None
903 for mat in bpy.data.materials:
904 if mat.users==0:
905 i+=1
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.")
912 return {'FINISHED'}
915 class MATLIB_OT_operator(Operator):
916 """Add, Remove, Reload, Apply, Preview, Clean Material"""
917 bl_label = "New"
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'})
925 @classmethod
926 def poll(cls, context):
927 return context.active_object is not None
929 def draw(self, context):
930 layout = self.layout
931 #cmd = LIBRARY_ADD
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):
941 cmd = self.cmd
942 print("invoke", cmd)
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):
958 success = ""
959 matlib = context.scene.matlib
961 if self.cmd == "init":
962 print("initialize")
963 return {'FINISHED'}
965 #Library Commands
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)
975 print(libname)
977 success = matlib.add_library(libname, True)
978 for i, l in enumerate(libraries):
979 if l.name == self.category:
980 matlib.lib_index = i
981 break
983 elif self.cmd == "RELOAD":
984 success = matlib.reload()
986 if not matlib.current_library:
987 self.report({'ERROR'}, "Select a Library")
988 return {'CANCELLED'}
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:
994 matlib.cat_index = i
995 break
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
1007 #Common Commands
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:
1025 try:
1026 context.scene.objects.active = context.scene.objects[matlib.last_selected]
1027 except:
1028 pass
1030 for slot in dummy.material_slots:
1031 slot.material = None
1033 for mat in bpy.data.materials:
1034 if mat.users==0:
1035 i+=1
1036 print (mat.name, "removed.")
1037 bpy.data.materials.remove(mat)
1039 plural = "s"
1040 if i==1:
1041 plural = ""
1043 self.report({'INFO'}, str(i) + " material"+plural+" removed.")
1045 ### CONVERT
1046 elif self.cmd == "CONVERT":
1047 return {'FINISHED'}
1048 lib = matlib.current_library
1049 if lib:
1051 path = os.path.join(matlib_path, "www")
1052 if not os.path.exists(path):
1053 os.mkdir(path)
1054 path = os.path.join(path, lib.shortname)
1055 if not os.path.exists(path):
1056 os.mkdir(path)
1058 path = winpath(path)
1059 libpath = winpath(lib.name)
1061 print(path)
1062 print(libpath)
1064 #decirle a la libreria que cree un fichero blend por cada material que tenga.
1065 cmd = """
1066 print(30*"+")
1067 import bpy, os
1068 def list_materials():
1069 list = []
1070 with bpy.data.libraries.load("{0}") as (data_from, data_to):
1071 for mat in data_from.materials:
1072 list.append(mat)
1073 return sorted(list)
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]
1078 if link:
1079 print(name + " linked.")
1080 else:
1081 print(name + " appended.")
1083 for scn in bpy.data.scenes:
1084 for obj in scn.objects:
1085 scn.objects.unlink(obj)
1086 obj.user_clear()
1087 bpy.data.objects.remove(obj)
1089 def clean_materials():
1090 for mat in bpy.data.materials:
1091 mat.user_clear()
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
1097 for mat in mats:
1098 clean_materials()
1099 matpath = os.path.join("{1}", mat + ".blend")
1100 print(matpath)
1101 get_material(mat)
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)
1106 print(cmd)
1107 send_command(cmd, "createlib.py")
1109 if type(success).__name__ == "tuple":
1110 print(success)
1111 self.report({success[0]}, success[1])
1113 return {'FINISHED'}
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"
1122 @classmethod
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
1133 # matlib.__init__()
1135 #libaries
1136 row = layout.row(align=True)
1137 if matlib.current_library:
1138 text = matlib.current_library.shortname
1139 else:
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)
1146 else:
1147 row.label("")
1149 # #search
1150 if not matlib.hide_search:
1151 row = layout.row(align=True)
1152 row.prop_search(matlib, "search", matlib, "materials", text="", icon="VIEWZOOM")
1154 # #list
1155 row = layout.row()
1156 row.template_list("UI_UL_list", " ", matlib, "materials", matlib, "mat_index", rows=6)
1157 col = row.column(align=True)
1158 row = layout.row()
1160 #operators
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="")
1169 #categories
1170 row = layout.row(align=True)
1171 text = "All"
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"
1179 #prefs
1180 if matlib.show_prefs:
1181 row = layout.row()
1182 row.prop(matlib, "force_import")
1183 row.prop(matlib, "link")
1184 row = layout.row()
1185 row.prop(matlib, "hide_search")
1186 # row = layout.row(align=True)
1187 #row = layout.row()
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)
1193 # else:
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)
1200 @persistent
1201 def refresh_libs(dummy=None):
1202 global libraries
1203 libraries = get_libraries()
1206 def reload_library(self, context):
1207 refresh_libs(self)
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",
1216 default="",
1217 update=reload_library
1220 def draw(self, context):
1221 layout = self.layout
1222 layout.prop(self, "matlib_path")
1225 def register():
1226 global libraries
1227 bpy.utils.register_module(__name__)
1228 # for c in classes:
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()
1236 def unregister():
1237 global libraries
1238 bpy.utils.unregister_module(__name__)
1239 try:
1240 # raise ValueError list.remove(x): x not in list
1241 del Scene.matlib_categories
1242 except:
1243 pass
1244 del Scene.matlib
1245 libraries.clear()
1246 bpy.app.handlers.load_post.remove(refresh_libs)
1247 # for c in classes:
1248 # bpy.utils.unregister_class(c)
1251 if __name__ == "__main__":
1252 register()