diff --git a/build/.version b/build/.version index f3189e3..155f135 100644 --- a/build/.version +++ b/build/.version @@ -1 +1 @@ -1.0.0+build.5 \ No newline at end of file +1.0.0+build.18 \ No newline at end of file diff --git a/build/build.py b/build/build.py index 2b54992..e5d6df2 100644 --- a/build/build.py +++ b/build/build.py @@ -10,6 +10,7 @@ PROJECT_NAME = "Bake ID Mask" CURRENT_PATH = os.path.dirname(os.path.realpath(__file__)) SOURCE_PATH = os.path.join(CURRENT_PATH, "../src") +INIT_FILE_PATH = os.path.join(SOURCE_PATH, "__init__.py") TARGET_PATH = os.path.join(CURRENT_PATH, '../dist') if __name__ == "__main__": @@ -22,6 +23,14 @@ if __name__ == "__main__": versioning.save_version(nextVersion) filename = os.path.join(TARGET_PATH, ZIP_FILE_NAME.format(version=nextVersion.__str__())) + original_init_content = '' + with open(INIT_FILE_PATH, 'r') as f: + original_init_content = f.read() + + version_insert = original_init_content.replace('# !VERSION', '"version": ({}, {}, {}),'.format(nextVersion.major, nextVersion.minor, nextVersion.patch)) + with open(INIT_FILE_PATH, 'w') as f: + f.write(version_insert) + with zipfile.ZipFile(filename, 'w', zipfile.ZIP_DEFLATED) as zip: for (root, dirs, files) in os.walk(SOURCE_PATH): if '__pycache__' in dirs: @@ -37,4 +46,7 @@ if __name__ == "__main__": zip.write( os.path.join(root, file), os.path.join(PROJECT_NAME, relativePath) - ) \ No newline at end of file + ) + + with open(INIT_FILE_PATH, 'w') as f: + f.write(original_init_content) diff --git a/src/__init__.py b/src/__init__.py index 95de1cb..65b5393 100644 --- a/src/__init__.py +++ b/src/__init__.py @@ -1,3 +1,12 @@ +bl_info = { + "name": "Bake ID Mask", + "author": "iedSoftworks", + "description": "", + # !VERSION + "blender": (2, 92, 0), + "category": "Object" +} + import bpy from . panels.panel_options import BakeToIDOptionsPanel @@ -7,14 +16,6 @@ from . panels.panel import BakeToIDMapPanel from . panels.panel_info import BakeToIDInfoPanel from . properties.bake_to_id import BakeToIDProperties -bl_info = { - "name": "Bake ID Mask", - "author": "iedSoftworks", - "description": "", - "blender": (2, 80, 0), - "category": "Object" -} - classes = ( BakeToIDMapOperator, BakeToIDMapPanel, @@ -24,13 +25,14 @@ classes = ( BakeToIDProperties, ) -def register(): +def register(): for cls in classes: bpy.utils.register_class(cls) setattr(bpy.types.Scene, 'bake_to_id_props', bpy.props.PointerProperty(type=BakeToIDProperties)) + def unregister(): for cls in reversed(classes): bpy.utils.unregister_class(cls) diff --git a/src/operators/bake_to_id_map.py b/src/operators/bake_to_id_map.py index 378a897..dcd6643 100644 --- a/src/operators/bake_to_id_map.py +++ b/src/operators/bake_to_id_map.py @@ -3,6 +3,8 @@ import math import bpy +from .. types import (get_source, get_target) + class BakeToIDMapOperator(bpy.types.Operator): bl_idname = "object.bake_to_id_map" @@ -22,17 +24,10 @@ class BakeToIDMapOperator(bpy.types.Operator): return {'FINISHED'} - @staticmethod - def count_ids(context, props): - count = 0 - if props.source == 'MATERIAL_INDEX': - for obj in context.selected_objects: - count += len(obj.material_slots) - - return count - def paint_id_mask(self, context, props): - targets = self.get_targets(context, props) + source = get_source(props.source) + + targets = source.get_targets(context) if len(targets) < 1: return @@ -53,71 +48,6 @@ class BakeToIDMapOperator(bpy.types.Operator): colors.append(colorsys.hls_to_rgb(h, l, s)) - self.paint_targets(props, targets, colors) - self.after_painting(context, props) - - def get_targets(self, context, props): - if props.source == 'MATERIAL_INDEX': - return self.get_material_targets(context) - - return [] - - def get_material_targets(self, context): - targets = [] - for obj in context.selected_objects: - if not obj.material_slots: continue - - mesh = obj.data - if len(obj.material_slots) < 2: - targets.append((mesh, mesh.polygons)) - continue - - polygonMaterials = {} - for poly in mesh.polygons: - if poly.material_index not in polygonMaterials: - polygonMaterials[poly.material_index] = [] - - polygonMaterials[poly.material_index].append(poly) - - for polygons in polygonMaterials.values(): - targets.append((mesh, polygons)) - - return targets - - def paint_targets(self, props, targets, colors): - if props.target == 'VERTEX_COLORS': - self.paint_targets_vertex_colors(props, targets, colors) - - def paint_targets_vertex_colors(self, props, targets, colors): - sortedTargets = {} - for i in range(len(targets)): - target = targets[i] - obj = target[0] - indecies = target[1] - - if obj not in sortedTargets: - sortedTargets[obj] = [] - - sortedTargets[obj].append((indecies, colors[i])) - - layer_name = props.target_vertex_color_attribute_name - for mesh in sortedTargets: - if layer_name in mesh.vertex_colors: - mesh.vertex_colors.remove(mesh.vertex_colors[layer_name]) - - vertex_color_layer = mesh.vertex_colors.new(name=layer_name) - - for (indecies, color) in sortedTargets[mesh]: - for polygon in indecies: - for idx in polygon.loop_indices: - vertex_color_layer.data[idx].color = (color[0], color[1], color[2], 1.0) - - def after_painting(self, context, props): - if props.source == 'MATERIAL_INDEX': - self.after_painting_source_material_index(props, context) - return - - def after_painting_source_material_index(self, props, context): - if props.source_materials_remove_all: - for obj in context.selected_objects: - obj.data.materials.clear() + target = get_target(props.target) + target.paint_targets(props, targets, colors) + source.after_painting(context, props) \ No newline at end of file diff --git a/src/panels/panel_info.py b/src/panels/panel_info.py index 22dde49..7ac9a0f 100644 --- a/src/panels/panel_info.py +++ b/src/panels/panel_info.py @@ -1,6 +1,7 @@ import bpy from .. operators.bake_to_id_map import BakeToIDMapOperator +from ..types import get_source class BakeToIDInfoPanel(bpy.types.Panel): @@ -16,5 +17,7 @@ class BakeToIDInfoPanel(bpy.types.Panel): props = context.scene.bake_to_id_props + source = get_source(props.source) + layout.label(text="Selected Object-Count: " + str(len(context.selected_objects))) - layout.label(text="Estimated ID-Count: " + str(BakeToIDMapOperator.count_ids(context, props))) \ No newline at end of file + layout.label(text="Estimated ID-Count: " + str(source.estimate_ids(context, props))) \ No newline at end of file diff --git a/src/panels/panel_options.py b/src/panels/panel_options.py index 3b74dbe..2d1445e 100644 --- a/src/panels/panel_options.py +++ b/src/panels/panel_options.py @@ -1,5 +1,9 @@ +import textwrap + import bpy +from src.types import get_source, get_target + class BakeToIDOptionsPanel(bpy.types.Panel): bl_idname = "PANEL.BAKE_TO_ID_MAP_PT_SETTINGS_OPTIONS" @@ -15,31 +19,15 @@ class BakeToIDOptionsPanel(bpy.types.Panel): props = context.scene.bake_to_id_props layout.prop(props, "source") + source = get_source(props.source) source_settings_box = layout.box() - source_settings = self.get_source_settings(props) - for setting in source_settings: + for setting in source.connected_properties: source_settings_box.prop(props, setting) layout.separator() layout.prop(props, "target") + target = get_target(props.target) target_settings_box = layout.box() - target_settings = self.get_target_settings(props) - for setting in target_settings: + for setting in target.connected_properties: target_settings_box.prop(props, setting) - - def get_source_settings(self, props): - if props.source == 'MATERIAL_INDEX': - return [ - 'source_materials_remove_all' - ] - - return [] - - def get_target_settings(self, props): - if props.target == 'VERTEX_COLORS': - return [ - 'target_vertex_color_attribute_name' - ] - - return [] \ No newline at end of file diff --git a/src/properties/bake_to_id.py b/src/properties/bake_to_id.py index b7be6f7..019941a 100644 --- a/src/properties/bake_to_id.py +++ b/src/properties/bake_to_id.py @@ -1,22 +1,22 @@ from bpy.types import (PropertyGroup) from bpy.props import (EnumProperty, BoolProperty, IntProperty, StringProperty) +from src.types import get_source_enum, get_targets_enum + class BakeToIDProperties(PropertyGroup): source: EnumProperty( - items=[ - ('MATERIAL_INDEX', 'Material Index', "It takes the material index as ID basis", 0) - ], + items=get_source_enum(), name="Source", description="From where should the IDs be taken", default = "MATERIAL_INDEX" ) target: EnumProperty( - items=[('VERTEX_COLORS', 'Vertex Colors', "It bakes the ID to the vertex colors", 0)], + items=get_targets_enum(), name="Target", description="To where should the IDs should be baked to", - default="VERTEX_COLORS" + default=get_targets_enum()[0][0] ) source_materials_remove_all : BoolProperty( diff --git a/src/types/__init__.py b/src/types/__init__.py new file mode 100644 index 0000000..c814b4c --- /dev/null +++ b/src/types/__init__.py @@ -0,0 +1,43 @@ +from . sources import material_index as source_mat_index + +from . targets import vertex_colors as target_vertex_colors + +_sources = [ + source_mat_index +] + +_targets = [ + target_vertex_colors +] + +def get_source(id): + for source in _sources: + if source.source_id == id: + return source + + raise Exception("Source not found: " + id) + +def get_target(id): + for target in _targets: + if target.target_id == id: + return target + + raise Exception("Target not found: " + id) + +def get_source_enum(): + enumList = [] + i = 0 + for source in _sources: + enumList.append((source.source_id, source.name, source.description, i)) + i += 1 + + return enumList + +def get_targets_enum(): + enumList = [] + i = 0 + for target in _targets: + enumList.append((target.target_id, target.name, target.description, i)) + i += 1 + + return enumList diff --git a/src/types/sources/material_index.py b/src/types/sources/material_index.py new file mode 100644 index 0000000..d7b1b5b --- /dev/null +++ b/src/types/sources/material_index.py @@ -0,0 +1,41 @@ +source_id = 'MATERIAL_INDEX' +name = 'Material Index' +description = 'Uses the current material index as basis for ID mask.' + +connected_properties = [ + 'source_materials_remove_all' +] + +def get_targets(context): + targets = [] + for obj in context.selected_objects: + if not obj.material_slots: continue + + mesh = obj.data + if len(obj.material_slots) < 2: + targets.append((mesh, mesh.polygons)) + continue + + polygonMaterials = {} + for poly in mesh.polygons: + if poly.material_index not in polygonMaterials: + polygonMaterials[poly.material_index] = [] + + polygonMaterials[poly.material_index].append(poly) + + for polygons in polygonMaterials.values(): + targets.append((mesh, polygons)) + + return targets + +def after_painting(context, props): + if props.source_materials_remove_all: + for obj in context.selected_objects: + obj.data.materials.clear() + +def estimate_ids(context, props): + count = 0 + for obj in context.selected_objects: + count += len(obj.material_slots) + + return count diff --git a/src/types/targets/vertex_colors.py b/src/types/targets/vertex_colors.py new file mode 100644 index 0000000..f77a718 --- /dev/null +++ b/src/types/targets/vertex_colors.py @@ -0,0 +1,32 @@ +target_id = 'COLOR_ATTRIBUTE' +name = 'Color Attribute / Vertex Color' +description = 'Bakes the ID onto a color attribute (previously known as Vertex Color)' + +connected_properties = [ + 'target_vertex_color_attribute_name' +] + + +def paint_targets(props, targets, colors): + sorted_targets = {} + for i in range(len(targets)): + target = targets[i] + obj = target[0] + indecies = target[1] + + if obj not in sorted_targets: + sorted_targets[obj] = [] + + sorted_targets[obj].append((indecies, colors[i])) + + layer_name = props.target_vertex_color_attribute_name + for mesh in sorted_targets: + if layer_name in mesh.attributes: + mesh.attributes.remove(mesh.attributes[layer_name]) + + color_attribute = mesh.attributes.new(name=layer_name, type='FLOAT_COLOR', domain='CORNER') + + for (indecies, color) in sorted_targets[mesh]: + for polygon in indecies: + for idx in polygon.loop_indices: + color_attribute.data[idx].color = (color[0], color[1], color[2], 1.0) \ No newline at end of file