156 lines
6.9 KiB
Python
156 lines
6.9 KiB
Python
import bpy
|
|
from os import path, walk
|
|
from pathlib import Path
|
|
|
|
class TEXTURE_OT_search_bars(bpy.types.Operator):
|
|
"""Add or remove search bars"""
|
|
bl_idname = "texture.bars"
|
|
bl_label = "Add search bar"
|
|
bl_options = {'REGISTER', 'UNDO'}
|
|
bl_region_type = 'UI'
|
|
|
|
add : bpy.props.StringProperty(default="")
|
|
|
|
def execute(self, context):
|
|
if self.add[0] == "T":
|
|
context.scene.fmt_search_bars.add()
|
|
elif self.add[0] == "F":
|
|
context.scene.fmt_search_bars.remove(int(self.add[1:]))
|
|
return {'FINISHED'}
|
|
|
|
class TEXTURE_OT_remove_image(bpy.types.Operator):
|
|
"""Delete the image from the file"""
|
|
bl_idname = "texture.remove_image"
|
|
bl_label = "Delete image"
|
|
bl_options = {'REGISTER', 'UNDO'}
|
|
bl_region_type = 'UI'
|
|
|
|
def execute(self, context):
|
|
if len(bpy.context.scene.fmt_list) > 0:
|
|
image_name = bpy.context.scene.fmt_list[bpy.context.scene.fmt_list_index].img_name
|
|
bpy.context.scene.fmt_list.remove(bpy.context.scene.fmt_list_index)
|
|
bpy.data.images.remove(bpy.data.images[image_name])
|
|
return {'FINISHED'}
|
|
|
|
class TEXTURE_OT_find_in_folder(bpy.types.Operator):
|
|
"""Find your missing textures in this folder and subfolders"""
|
|
bl_idname = "texture.folder_find"
|
|
bl_label = "Find in folder"
|
|
bl_options = {'REGISTER', 'UNDO'}
|
|
bl_region_type = 'UI'
|
|
|
|
def execute(self, context):
|
|
scene = context.scene
|
|
files_dir_list = []
|
|
try:
|
|
for search_path in scene.fmt_search_bars:
|
|
if search_path.bars:
|
|
for dirpath, dirnames, filenames in walk(bpy.path.abspath(search_path.bars)):
|
|
files_dir_list.append([dirpath, filenames])
|
|
except FileNotFoundError:
|
|
print(f"Error - Bad file path {search_path.bars}")
|
|
return {'FINISHED'}
|
|
for missing_img in scene.fmt_list:
|
|
img_file_name = bpy.path.basename(bpy.data.images[missing_img.img_name].filepath)
|
|
for imgs in files_dir_list:
|
|
if img_file_name in imgs[1]:
|
|
bpy.data.images[missing_img.img_name].filepath = path.join(imgs[0], img_file_name)
|
|
elif bpy.context.scene.fmt_extension_replace:
|
|
self.search_different_extension(missing_img, img_file_name, imgs)
|
|
|
|
bpy.ops.texture.find_missing_textures()
|
|
return {'FINISHED'}
|
|
|
|
|
|
def search_different_extension(self, missing_img, img_file_name, imgs):
|
|
base_img_name = path.splitext(img_file_name)[0]
|
|
for img_in_folders in imgs[1]:
|
|
if base_img_name == path.splitext(img_in_folders)[0]:
|
|
bpy.data.images[missing_img.img_name].filepath = path.join(imgs[0], img_in_folders)
|
|
|
|
class TEXTURE_OT_find_missing_textures(bpy.types.Operator):
|
|
"""Search for misssing textures"""
|
|
bl_idname = "texture.find_missing_textures"
|
|
bl_label = "Search missing textures"
|
|
bl_options = {'REGISTER', 'UNDO'}
|
|
bl_region_type = 'UI'
|
|
|
|
def execute(self, context):
|
|
bpy.context.scene.fmt_list.clear()
|
|
self.search_for_missing_texture()
|
|
self.report_full_list()
|
|
if len(bpy.context.scene.fmt_list) > 0:
|
|
self.report({'WARNING'}, "Some texture are missing!")
|
|
return {'FINISHED'}
|
|
|
|
def search_for_missing_texture(self):
|
|
if len(bpy.context.scene.fmt_search_bars) == 0:
|
|
bpy.context.scene.fmt_search_bars.add()
|
|
for img in bpy.data.images:
|
|
if img.name == "Render Result" or img.name == "Viewer Node":
|
|
continue
|
|
if hasattr(img, 'has_data'):
|
|
img.size[0] # Need to do this to refresh the data at the first time
|
|
if img.has_data == False:
|
|
self.add_texture_to_missing_list(img)
|
|
elif not img.packed_file:
|
|
if not Path(bpy.path.abspath(img.filepath)).is_file():
|
|
self.add_texture_to_missing_list(img)
|
|
|
|
def report_full_list(self): # Get list of bad materials
|
|
mat_list = []
|
|
self.report({'INFO'}, f"------------------------------------------")
|
|
self.report({'INFO'}, f"Missing material report:")
|
|
self.report({'INFO'}, f"(Material name >> Node name (Node label) >> Image name)")
|
|
self.report({'INFO'}, f"(Image path)")
|
|
for mat in bpy.data.materials:
|
|
if not mat.name == "Dots Stroke" and hasattr(mat.node_tree, 'nodes'):
|
|
for node in mat.node_tree.nodes:
|
|
if node.type == 'TEX_IMAGE':
|
|
if hasattr(node.image, 'has_data'):
|
|
if not node.image.has_data:
|
|
if node.label == "":
|
|
node_label = node.image.name
|
|
else:
|
|
node_label = node.label
|
|
if not mat.name in mat_list:
|
|
mat_list.append(mat.name)
|
|
self.report({'WARNING'}, f"{mat.name} >> {node.name} ({node_label}) >> {node.image.name}")
|
|
self.report({'WARNING'}, f"{node.image.filepath}")
|
|
if not mat_list:
|
|
self.report({'INFO'}, f"Good work! All the shaders are good!")
|
|
else:
|
|
self.search_object_with_bad_mat(mat_list)
|
|
|
|
def search_object_with_bad_mat(self, mat_list):
|
|
self.deselect_all_objs()
|
|
self.report({'INFO'}, f"------------------------------------------")
|
|
self.report({'INFO'}, f"List of objects with missing textures:")
|
|
if len(bpy.data.scenes) == 1:
|
|
self.report({'INFO'}, f"Object name >> Material name")
|
|
else:
|
|
self.report({'INFO'}, f"Scene name >> Object name >> Material name")
|
|
for scene in bpy.data.scenes:
|
|
for obj in scene.objects:
|
|
if obj.type == "MESH":
|
|
if len(obj.material_slots.items()) > 0:
|
|
for miss_mat in mat_list:
|
|
if miss_mat in obj.material_slots:
|
|
if len(bpy.data.scenes) == 1:
|
|
if bpy.context.scene.fmt_select_bad_obj:
|
|
obj.select_set(True)
|
|
self.report({'WARNING'}, f"{obj.name} >> {miss_mat}")
|
|
else:
|
|
self.report({'WARNING'}, f"{scene.name} >> {obj.name} >> {miss_mat}")
|
|
|
|
def deselect_all_objs(self):
|
|
if bpy.context.scene.fmt_select_bad_obj:
|
|
for obj in bpy.context.selected_objects:
|
|
obj.select_set(False)
|
|
|
|
|
|
def add_texture_to_missing_list(self, img):
|
|
img.reload()
|
|
new_image_list = bpy.context.scene.fmt_list.add()
|
|
new_image_list.img_name = img.name
|
|
new_image_list.img_path = img.filepath |