diff --git a/README.md b/README.md index c70804b..c493838 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,13 @@ -# Blender - ID Mask Tools +# Blender - Bake ID Mask Plugin -A set of tools to quickly create ID masks for meshes. +A plugin to quickly bake ID masks for meshes from/to different sources and targets. -### What is this? -For usage in specific programs like Substance Painter, its useful to create a mask for specific parts for your mesh, so you can easily make out parts of the mesh, to f.E. apply a mterial. -You can specify colors in color attributes that define "IDs" for specific parts of the mesh, which you can then use in different programs. +### Currently supported: +Sources: +- Material Index -Currently this workflow requires you to assign them tediously by using a mixture of Edit Mode and Vertex Paint to paint the mesh correctly. - -This plugin tries to fix that, by providing proper tools for it. The most important is probably the [ID Mask Editor](docu/features/id_mask_editor.md), that allows you to quickly add IDs to faces all within the Edit Mode. +Targets: +- Vertex Color ## Installation 1. Download the newest file from the releases tab. @@ -17,4 +16,12 @@ This plugin tries to fix that, by providing proper tools for it. The most import 4. After selecting it, just enable it and done. ## Usage -Check out the [Features](docu/features.md) page to find more specific information about the usage of each feature. \ No newline at end of file +You find the tool in the panel on the right of the "3D Viewport" under "Tool". +![Panel Location](docu/images/panel.png) + +How to use properly it, highly depends on the selected source. + +### Usage - Material Index Source +Here the IDs are given based on the object and its material indices. + +Lets say, you have 10 objects and each has 2 materials attached to it. Then the amount of IDs given is 20, since each object contains the two material indecies. diff --git a/build/.version b/build/.version index fa31bb9..f3189e3 100644 --- a/build/.version +++ b/build/.version @@ -1 +1 @@ -1.3.1+build.2 \ No newline at end of file +1.0.0+build.5 \ No newline at end of file diff --git a/build/build.py b/build/build.py index e5d6df2..2b54992 100644 --- a/build/build.py +++ b/build/build.py @@ -10,7 +10,6 @@ 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__": @@ -23,14 +22,6 @@ 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: @@ -46,7 +37,4 @@ if __name__ == "__main__": zip.write( os.path.join(root, file), os.path.join(PROJECT_NAME, relativePath) - ) - - with open(INIT_FILE_PATH, 'w') as f: - f.write(original_init_content) + ) \ No newline at end of file diff --git a/build/bump_minor.py b/build/bump_minor.py index 449da17..95053ae 100644 --- a/build/bump_minor.py +++ b/build/bump_minor.py @@ -5,3 +5,4 @@ if __name__ == "__main__": currentVersion = versioning.get_version() nextVersion = currentVersion.bump_minor() versioning.save_version(nextVersion) + diff --git a/docu/features.md b/docu/features.md deleted file mode 100644 index 6cc2a43..0000000 --- a/docu/features.md +++ /dev/null @@ -1,3 +0,0 @@ -# Features -- [ID Mask Editor](features/id_mask_editor.md) -- [Bake ID Mask](features/bake_id_mask.md) diff --git a/docu/features/bake_id_mask.md b/docu/features/bake_id_mask.md deleted file mode 100644 index 8e4c576..0000000 --- a/docu/features/bake_id_mask.md +++ /dev/null @@ -1,52 +0,0 @@ -# Bake ID Mask -This tool allows you to quickly create a ID mask based on different sources - -The tool is found in the Tool category in the Side Panel of the 3D View. -![Panel Location](../images/bake_id_mask.panel.png) - -## The UI -![UI](../images/bake_id_mask.ui.png) - -1. The Bake button. Click on it to bake, after you have setup your selection -2. Selection Mode. See "Parameters" -3. This panel gives you infos about how many ID you gonna bake and how many colors you have in your color source -4. The source specifies, what kind of dataset the system will take to calculate its IDs -5. This box allows the source to have parameters, you can change -6. The target specifies, where the ID get drawn to. Currently only color attributes are supported -7. as with the source, the target can have parameters, as well. -8. This allows you to change the color source, from where the system takes the colors. - -## Parameters -### Selection Mode -The "Selection Mode" has 3 different options: -1. Only active element - The bake will only apply to the actively selected object. If no active object was found, nothing will happens. -2. Use Selection, separate - The bake will apply to all selected objects, but each object will be processed individually by the source. -Example: With Material Index, the ID will always correspond with the Material Index, ignoring what ever happens with the other objects. -3. Use Selection, combined - The bake will apply to all selected object and will be processed together by the source. -Example: With Material Index, it will count up every Material Index it finds. - -### Sources -#### Material Index -This source will give away IDs based on the material index, a face uses. -This can be useful, when you use multiple materials in one mesh and want to export it with only one material and without loosing the info, which face had different materials. - -The "Remove all source materials" option will, if checked, remove all material indecies from the mesh, allowing you to directly export it to your application. - -#### Object ID -This source will only work properly in "Use Selection, combined" - Selection Mode. The source works by giving every selected Object an incrementing ID. - -### Targets -#### Color Attribute / Vertex Color -This target will save the ID-color onto the color attribute specified. - -By default, it will remove the old color attribute completely and replace it, if one already exists with the name. This can be prevent by unchecking "Override Color Attribute". -The ID-color will then just painted on top of the existing attribute, overriding existing colors, if there were any. - -### Color Sources -#### Generated -This color source will generate a list of colors to use, which get increasingly less saturated and bright as further, you approach the limit. - -#### Color Palette -This allows you to specify an own palette, previously created in Blender. - -Due to the way palettes work in Blender, you can **not** create or edit the palette here. You can create one in one of the "Paint" modes, like Vertex Paint. \ No newline at end of file diff --git a/docu/features/id_mask_editor.md b/docu/features/id_mask_editor.md deleted file mode 100644 index d0a78fd..0000000 --- a/docu/features/id_mask_editor.md +++ /dev/null @@ -1,29 +0,0 @@ -# ID Mask Editor -The "ID Mask Editor" allows you to quickly add IDs to faces in a mesh. - -## Getting started -The editor is found in the Tool category in the Side Panel of the 3D View. The editor is only visible when you are in Edit Mode. -![Panel Location](../images/id_mask_editor.panel.png) - -By default, its pretty empty. That is because you need to specify a color attribute, you want to paint your ID-mask to. -You can either select an already existing color attribute or you create a new one using the "Plus"-button. That will automatically create color attribute called "ID_MASK" and set it as ID-mask. - -With the attribute selected, you will see a few more options. - -## The UI -![Panel Options](../images/id_mask_editor.options_0.png) -1. The color source. That specifies how the initial colors are generated, when adding new IDs using the "Plus"-Button -2. This is the ID-list. It works similarly to the Vertex Groups-list. The only big difference is how the items works. You can change the color and name of an ID. Change the color will cause the two buttons to be enabled. They allow you to either "Revert" the change you made or to "Apply" it, which will change the ID-mask to reflect the change. -3. Clicking the "Paint"-button will paint the currently active ID (indicated by the blue background in the list) onto the currently selected **faces**. -4. Clicking the "Select"-button will select every face currently using the currently active ID (indicated by the blue background in the list) -5. Changing the color on a ID will not automatically apply it onto the attribute. This will allow you to apply/revert all those changes, with one click. - -### Additional Features -Using the arrow next to the list allows you to find additional features: -- Find used colors: Using this feature will automatically detect colors found in the attribute, but not found in the ID list, and add them. -Very useful when dealing with a mesh created without this tool or if you accidentally removed an ID from the list. - -## One additional thing -While not directly related to the ID-Mask, but still kinda, there is a new selection found under the "Select" menu. -This will allow you to quickly select faces, with the same ID, then the face you have currently active. -![Select by ID Mask](../images/id_mask_editor.select_by_id_mask.png) diff --git a/docu/images/bake_id_mask.panel.png b/docu/images/bake_id_mask.panel.png deleted file mode 100644 index 8d5b2a4..0000000 Binary files a/docu/images/bake_id_mask.panel.png and /dev/null differ diff --git a/docu/images/bake_id_mask.ui.png b/docu/images/bake_id_mask.ui.png deleted file mode 100644 index a73c4fc..0000000 Binary files a/docu/images/bake_id_mask.ui.png and /dev/null differ diff --git a/docu/images/id_mask_editor.options_0.png b/docu/images/id_mask_editor.options_0.png deleted file mode 100644 index 6865dcf..0000000 Binary files a/docu/images/id_mask_editor.options_0.png and /dev/null differ diff --git a/docu/images/id_mask_editor.panel.png b/docu/images/id_mask_editor.panel.png deleted file mode 100644 index 869f27c..0000000 Binary files a/docu/images/id_mask_editor.panel.png and /dev/null differ diff --git a/docu/images/id_mask_editor.select_by_id_mask.png b/docu/images/id_mask_editor.select_by_id_mask.png deleted file mode 100644 index 9940084..0000000 Binary files a/docu/images/id_mask_editor.select_by_id_mask.png and /dev/null differ diff --git a/docu/images/panel.png b/docu/images/panel.png new file mode 100644 index 0000000..c63bf0a Binary files /dev/null and b/docu/images/panel.png differ diff --git a/docu/planned_features.md b/docu/planned_features.md deleted file mode 100644 index 84ecc16..0000000 --- a/docu/planned_features.md +++ /dev/null @@ -1,6 +0,0 @@ -## Planned features - -### ID Mask - Editor -- [X] A way to automatically get already used colors, f.E. you already did it by hand -- [X] Select by color -- [ ] Update after color change \ No newline at end of file diff --git a/src/__init__.py b/src/__init__.py index f753ac2..95de1cb 100644 --- a/src/__init__.py +++ b/src/__init__.py @@ -1,32 +1,17 @@ import bpy -from . menu import id_mask_select_menu -from . menu.id_mask_editor_options import IDEDITOR_IDMaskEditorOptionsMenu -from . operators.create_id_mask import CreateIDMaskOperator -from . operators.id_editor_apply_color import IDEDITOR_ColorApplyOperator -from . operators.id_editor_create_id import IDEDITOR_CreateIDOperator -from . operators.id_editor_find_used_ids import IDEDITOR_FindUsedIDsOperator -from . operators.id_editor_paint import IDEDITOR_PaintIDMaskOperator -from . operators.id_editor_remove_id import IDEDITOR_RemoveIDOperator -from . operators.id_editor_revert_color import IDEDITOR_ColorResetOperator -from . operators.id_mask_select import IDEDITOR_SelectIDMaskOperator -from . panels.id_mask_editor_id_list import IDMaskEditorIDList -from . properties.id_mask_editor_value_properties import IDMaskEditorValueProperties -from . panels.bake_panel_options import BakeToIDOptionsPanel +from . panels.panel_options import BakeToIDOptionsPanel +from . panels.panel_advanced import BakeToIDAdvancedMenu from . operators.bake_to_id_map import BakeToIDMapOperator -from . panels.bake_panel import BakeToIDMapPanel -from . panels.bake_panel_info import BakeToIDInfoPanel -from . panels.id_mask_editor import IDMaskEditorPanel -from . properties.bake_properties import BakeToIDProperties - -from . properties.id_mask_editor_properties import IDMaskEditorProperties +from . panels.panel import BakeToIDMapPanel +from . panels.panel_info import BakeToIDInfoPanel +from . properties.bake_to_id import BakeToIDProperties bl_info = { - "name": "ID Mask - Tools", + "name": "Bake ID Mask", "author": "iedSoftworks", "description": "", - # !VERSION - "blender": (2, 92, 0), + "blender": (2, 80, 0), "category": "Object" } @@ -35,45 +20,21 @@ classes = ( BakeToIDMapPanel, BakeToIDInfoPanel, BakeToIDOptionsPanel, + BakeToIDAdvancedMenu, BakeToIDProperties, - - IDMaskEditorValueProperties, - IDMaskEditorProperties, - IDMaskEditorPanel, - CreateIDMaskOperator, - IDMaskEditorIDList, - IDEDITOR_CreateIDOperator, - IDEDITOR_RemoveIDOperator, - IDEDITOR_PaintIDMaskOperator, - IDEDITOR_SelectIDMaskOperator, - IDEDITOR_FindUsedIDsOperator, - IDEDITOR_IDMaskEditorOptionsMenu, - IDEDITOR_ColorResetOperator, - IDEDITOR_ColorApplyOperator, ) -menu_additions = [ - id_mask_select_menu -] - def register(): + for cls in classes: bpy.utils.register_class(cls) - for menu in menu_additions: - menu.register() - setattr(bpy.types.Scene, 'bake_to_id_props', bpy.props.PointerProperty(type=BakeToIDProperties)) - setattr(bpy.types.Mesh, 'id_mask_editor_properties', bpy.props.PointerProperty(type=IDMaskEditorProperties)) def unregister(): - for menu in reversed(menu_additions): - menu.unregister() - for cls in reversed(classes): bpy.utils.unregister_class(cls) - del bpy.types.Scene.bake_to_id_props diff --git a/src/menu/id_mask_editor_options.py b/src/menu/id_mask_editor_options.py deleted file mode 100644 index 7590705..0000000 --- a/src/menu/id_mask_editor_options.py +++ /dev/null @@ -1,13 +0,0 @@ -import bpy - -from .. operators.id_editor_find_used_ids import IDEDITOR_FindUsedIDsOperator - - -class IDEDITOR_IDMaskEditorOptionsMenu(bpy.types.Menu): - bl_idname = "VIEW3D_MT_idmask_editor_options" - bl_label = "Options" - - def draw(self, context): - layout = self.layout - - layout.operator(IDEDITOR_FindUsedIDsOperator.bl_idname) \ No newline at end of file diff --git a/src/menu/id_mask_select_menu.py b/src/menu/id_mask_select_menu.py deleted file mode 100644 index b95cb74..0000000 --- a/src/menu/id_mask_select_menu.py +++ /dev/null @@ -1,12 +0,0 @@ -import bpy - -from .. operators.id_mask_select import IDEDITOR_SelectIDMaskOperator - -def id_mask_select_menu_function(self, context): - self.layout.operator(IDEDITOR_SelectIDMaskOperator.bl_idname).isCalledFromEditor = False - -def register(): - bpy.types.VIEW3D_MT_select_edit_mesh.append(id_mask_select_menu_function) - -def unregister(): - bpy.types.VIEW3D_MT_select_edit_mesh.remove(id_mask_select_menu_function) \ No newline at end of file diff --git a/src/operators/bake_to_id_map.py b/src/operators/bake_to_id_map.py index f1ecc50..378a897 100644 --- a/src/operators/bake_to_id_map.py +++ b/src/operators/bake_to_id_map.py @@ -1,8 +1,7 @@ -import bpy +import colorsys +import math -from .. types.colors import get_color -from .. types.sources import get_source -from .. types.targets import get_target +import bpy class BakeToIDMapOperator(bpy.types.Operator): @@ -23,48 +22,102 @@ class BakeToIDMapOperator(bpy.types.Operator): return {'FINISHED'} - def paint_id_mask(self, context, props): - source = get_source(props.source) + @staticmethod + def count_ids(context, props): + count = 0 + if props.source == 'MATERIAL_INDEX': + for obj in context.selected_objects: + count += len(obj.material_slots) - targets = self.get_targets(context, source, props) + return count + + def paint_id_mask(self, context, props): + targets = self.get_targets(context, props) if len(targets) < 1: return - color = get_color(props.colors) - colors = color.get_colors(props) + totalTargets = len(targets) + colors = [] - target = get_target(props.target) - self.paint_targets(props, target, targets, colors) - if 'after_painting' in dir(source): - source.after_painting(context, props) + total_hues = props.adv_total_hues + total_satuations = props.adv_total_satuations + total_brightnesses = props.adv_total_brightnesses - def get_targets(self, context, source, props): - if props.selection_mode == 'SINGLE': - return source.get_targets([context.active_object]) + satuations_break_point = math.pow(total_brightnesses, total_hues) - if props.selection_mode == 'MULTIPLE_COMBINED': - filtered_object = filter(lambda x: x.type == 'MESH', context.selected_objects) - return source.get_targets(list(filtered_object)) + for i in range(totalTargets): + h = (i / total_hues) % 1 + l = (math.ceil(i / total_hues) % total_brightnesses) / total_brightnesses + s = math.ceil(i / satuations_break_point) / total_satuations - if props.selection_mode == 'MULTIPLE_SEPARATE': - result = [] - for obj in context.selected_objects: - if obj.type != 'MESH': - continue + colors.append(colorsys.hls_to_rgb(h, l, s)) - obj_targets = source.get_targets([obj]) - result.append(obj_targets) + self.paint_targets(props, targets, colors) + self.after_painting(context, props) - return result + def get_targets(self, context, props): + if props.source == 'MATERIAL_INDEX': + return self.get_material_targets(context) - raise ValueError('Invalid selection_mode') + return [] - def paint_targets(self, props, target, targets, colors): - if props.selection_mode == 'MULTIPLE_SEPARATE': - for targetList in targets: - target.paint_targets(props,targetList, colors) + 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 - target.paint_targets(props, targets, colors) \ No newline at end of file + 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() diff --git a/src/operators/create_id_mask.py b/src/operators/create_id_mask.py deleted file mode 100644 index a5d6b2c..0000000 --- a/src/operators/create_id_mask.py +++ /dev/null @@ -1,37 +0,0 @@ -import bpy - -class CreateIDMaskOperator(bpy.types.Operator): - bl_idname = "id_mask_editor.create_id_mask_attribute" - bl_label = "Create ID Mask - Attribute" - bl_options = {'INTERNAL'} - - @classmethod - def poll(cls, context): - - obj = context.active_object - if obj.type != 'MESH': - return False - - if not obj.data: - return False - - mesh = obj.data - return 'ID_MASK' not in mesh.color_attributes - - def execute(self, context): - obj = context.active_object - if obj.type != 'MESH': - return {'FINISHED'} - - if not obj.data: - return {'FINISHED'} - - mesh = obj.data - - if 'ID_MASK' in mesh.color_attributes: - return {'FINISHED'} - - bpy.ops.geometry.color_attribute_add(name='ID_MASK', data_type='FLOAT_COLOR', domain='CORNER') - mesh.id_mask_editor_properties.target_attribute = 'ID_MASK' - - return {'FINISHED'} diff --git a/src/operators/id_editor_apply_color.py b/src/operators/id_editor_apply_color.py deleted file mode 100644 index 94fe105..0000000 --- a/src/operators/id_editor_apply_color.py +++ /dev/null @@ -1,84 +0,0 @@ -import bpy - -class IDEDITOR_ColorApplyOperator(bpy.types.Operator): - bl_idname = "id_mask_editor.apply_colors" - bl_label = "Apply changed ID-Mask colors" - bl_description = "Searches the current ID-mask for colors and adds them to the id-list" - bl_options = {'INTERNAL'} - - triggeredByList: bpy.props.BoolProperty(default=False) - listId: bpy.props.IntProperty(default=0) - - @classmethod - def poll(cls, context): - obj = context.active_object - if obj.type != 'MESH': - return False - - if not obj.data: - return False - - mesh = obj.data - properties = mesh.id_mask_editor_properties - - if not properties.target_attribute: - return False - - return True - - def execute(self, context): - obj = context.active_object - - old_mode = bpy.context.object.mode - if old_mode != "OBJECT": - bpy.ops.object.mode_set(mode='OBJECT', toggle=False) - mesh = obj.data - properties = mesh.id_mask_editor_properties - color_attribute = mesh.color_attributes.get(properties.target_attribute) - - colors = [] - - if self.triggeredByList: - list_item = properties.possible_ids[self.listId] - if list_item.color_changed: - colors.append((list_item.original_color, list_item.color)) - else: - for id in properties.possible_ids: - if not id.color_changed: - continue - - colors.append((id.original_color, id.color)) - - for polygon in mesh.polygons: - polygon_color = self.get_color_from_polygon(color_attribute, polygon) - - for (original_color, color) in colors: - if original_color[0] != polygon_color[0] or original_color[1] != polygon_color[1] or original_color[2] != polygon_color[2]: - continue - - for idx in polygon.loop_indices: - color_attribute.data[idx].color = (color.r, color.g, color.b, 1.0) - - break - - if self.triggeredByList: - list_item = properties.possible_ids[self.listId] - list_item.color_changed = False - else: - for id in properties.possible_ids: - id.color_changed = False - - if old_mode != "OBJECT": - bpy.ops.object.mode_set(mode=old_mode, toggle=False) - return {'FINISHED'} - - def reset_color(self, value): - if not value.color_changed: - return - - value.color = value.original_color - value.color_changed = False - - def get_color_from_polygon(self, attribute, polygon): - color = attribute.data[polygon.loop_indices[0]].color - return (color[0], color[1], color[2], 1.0) \ No newline at end of file diff --git a/src/operators/id_editor_create_id.py b/src/operators/id_editor_create_id.py deleted file mode 100644 index 83cfe19..0000000 --- a/src/operators/id_editor_create_id.py +++ /dev/null @@ -1,32 +0,0 @@ -import bpy - -from .. types.colors import get_color - - -class IDEDITOR_CreateIDOperator(bpy.types.Operator): - bl_idname = "id_mask_editor.create_id_mask" - bl_label = "id_mask_editor.create_id_mask" - - bl_options = {'INTERNAL'} - - def execute(self, context): - obj = context.active_object - if obj.type != 'MESH': - return {'FINISHED'} - - if not obj.data: - return {'FINISHED'} - - mesh = obj.data - properties = mesh.id_mask_editor_properties - collection = properties.possible_ids - new_id = collection.add() - - color = get_color(properties.colors) - colors = color.get_colors(properties) - colorCount = len(colors) - current_id_color = colors[properties.current_color_id % colorCount] - new_id.color = current_id_color - properties.current_color_id += 1 - - return {'FINISHED'} diff --git a/src/operators/id_editor_find_used_ids.py b/src/operators/id_editor_find_used_ids.py deleted file mode 100644 index b6f2fe2..0000000 --- a/src/operators/id_editor_find_used_ids.py +++ /dev/null @@ -1,63 +0,0 @@ -import bpy - -class IDEDITOR_FindUsedIDsOperator(bpy.types.Operator): - bl_idname = "id_mask_editor.find_used_ids" - bl_label = "Find used colors" - bl_description = "Searches the current ID-mask for colors and adds them to the id-list" - - @classmethod - def poll(cls, context): - obj = context.active_object - if obj.type != 'MESH': - return False - - if not obj.data: - return False - - mesh = obj.data - properties = mesh.id_mask_editor_properties - - if not properties.target_attribute: - return False - - return True - - def execute(self, context): - obj = context.active_object - - old_mode = bpy.context.object.mode - if old_mode != "OBJECT": - bpy.ops.object.mode_set(mode='OBJECT', toggle=False) - - mesh = obj.data - properties = mesh.id_mask_editor_properties - color_attribute = mesh.color_attributes.get(properties.target_attribute) - - colors = [] - for color_data in color_attribute.data: - colors.append((color_data.color[0], color_data.color[1], color_data.color[2])) - - i = 0 - set_colors = set(colors) - for color in set_colors: - has_color = False - for color_id in properties.possible_ids: - has_color = (color_id.color.r == color[0] and - color_id.color.g == color[1] and - color_id.color.b == color[2]) - - if has_color: - break - - if has_color: - continue - - color_identifier = properties.possible_ids.add() - color_identifier.color = (color[0], color[1], color[2]) - color_identifier.name = "Imported ID " + str(i + 1) - i += 1 - - if old_mode != "OBJECT": - bpy.ops.object.mode_set(mode=old_mode, toggle=False) - - return {'FINISHED'} \ No newline at end of file diff --git a/src/operators/id_editor_paint.py b/src/operators/id_editor_paint.py deleted file mode 100644 index 944f912..0000000 --- a/src/operators/id_editor_paint.py +++ /dev/null @@ -1,36 +0,0 @@ -import bpy - -class IDEDITOR_PaintIDMaskOperator(bpy.types.Operator): - bl_idname = "id_mask_editor.paint_id_mask" - bl_label = "Paint ID Mask" - - def execute(self, context): - obj = context.active_object - if obj.type != 'MESH': - return {'FINISHED'} - - if not obj.data: - return {'FINISHED'} - - old_mode = bpy.context.object.mode - if old_mode != "OBJECT": - bpy.ops.object.mode_set(mode='OBJECT', toggle=False) - - mesh = obj.data - properties = mesh.id_mask_editor_properties - collection = properties.possible_ids - color = collection[properties.active_id].color - - color_attribute = mesh.color_attributes.get(properties.target_attribute) - - for polygon in mesh.polygons: - if not polygon.select: - continue - - for idx in polygon.loop_indices: - color_attribute.data[idx].color = (color.r, color.g, color.b, 1.0) - - if old_mode != "OBJECT": - bpy.ops.object.mode_set(mode=old_mode, toggle=False) - - return {'FINISHED'} diff --git a/src/operators/id_editor_remove_id.py b/src/operators/id_editor_remove_id.py deleted file mode 100644 index 51e3a77..0000000 --- a/src/operators/id_editor_remove_id.py +++ /dev/null @@ -1,37 +0,0 @@ -import bpy - -class IDEDITOR_RemoveIDOperator(bpy.types.Operator): - bl_idname = "id_mask_editor.remove_id_mask" - bl_label = "id_mask_editor.remove_id_mask" - - bl_options = {'INTERNAL'} - - @classmethod - def poll(cls, context): - - obj = context.active_object - if obj.type != 'MESH': - return False - - if not obj.data: - return False - - mesh = obj.data - properties = mesh.id_mask_editor_properties - collection = properties.possible_ids - return 0 <= properties.active_id < len(collection) - - def execute(self, context): - obj = context.active_object - if obj.type != 'MESH': - return {'FINISHED'} - - if not obj.data: - return {'FINISHED'} - - mesh = obj.data - properties = mesh.id_mask_editor_properties - collection = properties.possible_ids - collection.remove(properties.active_id) - - return {'FINISHED'} diff --git a/src/operators/id_editor_revert_color.py b/src/operators/id_editor_revert_color.py deleted file mode 100644 index 5f2881b..0000000 --- a/src/operators/id_editor_revert_color.py +++ /dev/null @@ -1,49 +0,0 @@ -import bpy - -class IDEDITOR_ColorResetOperator(bpy.types.Operator): - bl_idname = "id_mask_editor.reset_colors" - bl_label = "Resets ID-Mask colors" - bl_description = "Resets the colors to the previous values" - bl_options = {'INTERNAL'} - - triggeredByList: bpy.props.BoolProperty(default=False) - listId: bpy.props.IntProperty(default=0) - - @classmethod - def poll(cls, context): - obj = context.active_object - if obj.type != 'MESH': - return False - - if not obj.data: - return False - - mesh = obj.data - properties = mesh.id_mask_editor_properties - - if not properties.target_attribute: - return False - - return True - - def execute(self, context): - obj = context.active_object - - mesh = obj.data - properties = mesh.id_mask_editor_properties - - if self.triggeredByList: - self.reset_color(properties.possible_ids[self.listId]) - return {'FINISHED'} - - for prop in properties.possible_ids: - self.reset_color(prop) - - return {'FINISHED'} - - def reset_color(self, value): - if not value.color_changed: - return - - value.color = value.original_color - value.color_changed = False diff --git a/src/operators/id_mask_select.py b/src/operators/id_mask_select.py deleted file mode 100644 index 927869d..0000000 --- a/src/operators/id_mask_select.py +++ /dev/null @@ -1,70 +0,0 @@ -import bpy - -class IDEDITOR_SelectIDMaskOperator(bpy.types.Operator): - bl_idname = "id_mask_editor.select_id_mask" - bl_label = "Select by ID Mask" - bl_description = "Selects the faces of the active object, based on current ID mask" - - isCalledFromEditor: bpy.props.BoolProperty(default=False) - - @classmethod - def poll(cls, context): - obj = context.active_object - if obj.type != 'MESH': - return False - - if not obj.data: - return False - - mesh = obj.data - properties = mesh.id_mask_editor_properties - - if not properties.target_attribute: - return False - - return True - - def execute(self, context): - obj = context.active_object - - old_mode = bpy.context.object.mode - if old_mode != "OBJECT": - bpy.ops.object.mode_set(mode='OBJECT', toggle=False) - - mesh = obj.data - properties = mesh.id_mask_editor_properties - color_attribute = mesh.color_attributes.get(properties.target_attribute) - - test_color = self.get_test_color(properties, mesh, color_attribute) - if not test_color: - if old_mode != "OBJECT": - bpy.ops.object.mode_set(mode=old_mode, toggle=False) - - return {'FINISHED'} - - for polygon in mesh.polygons: - polygon_color = self.get_color_from_polygon(color_attribute, polygon) - - if test_color[0] != polygon_color[0] or test_color[1] != polygon_color[1] or test_color[2] != polygon_color[2]: - continue - - polygon.select = True - - if old_mode != "OBJECT": - bpy.ops.object.mode_set(mode=old_mode, toggle=False) - - return {'FINISHED'} - - def get_test_color(self, properties, mesh, color_attribute): - if self.isCalledFromEditor: - color = properties.possible_ids[properties.active_id].color - return (color.r, color.g, color.b, 1.0) - - if mesh.polygons.active: - return self.get_color_from_polygon(color_attribute, mesh.polygons[mesh.polygons.active]) - - return None - - def get_color_from_polygon(self, attribute, polygon): - color = attribute.data[polygon.loop_indices[0]].color - return (color[0], color[1], color[2], 1.0) \ No newline at end of file diff --git a/src/panels/bake_panel.py b/src/panels/bake_panel.py deleted file mode 100644 index c89fcf2..0000000 --- a/src/panels/bake_panel.py +++ /dev/null @@ -1,31 +0,0 @@ -import bpy - - -class BakeToIDMapPanel(bpy.types.Panel): - bl_idname = "PANEL.BAKE_TO_ID_MAP_PT_SETTINGS" - bl_label = "Bake ID Mask" - bl_space_type = "VIEW_3D" - bl_region_type = "UI" - bl_category = "Tool" - - def draw(self, context): - layout = self.layout - layout.use_property_split = True - layout.use_property_decorate = False # No animation. - - props = context.scene.bake_to_id_props - - operator_row = layout.row() - operator_row.operator("object.bake_to_id_map", text="Bake") - operator_row.enabled = self.check_if_props_valid(context, props) - - layout.prop(props, "selection_mode") - - def check_if_props_valid(self, context, props): - if (props.selection_mode == "SINGLE" and context.active_object is None): - return False - - if (props.selection_mode != "SINGLE" and len(context.selected_objects) < 1): - return False - - return True \ No newline at end of file diff --git a/src/panels/bake_panel_info.py b/src/panels/bake_panel_info.py deleted file mode 100644 index ae054d5..0000000 --- a/src/panels/bake_panel_info.py +++ /dev/null @@ -1,49 +0,0 @@ -import bpy - -from .. types.colors import get_color -from .. types.sources import get_source - - -class BakeToIDInfoPanel(bpy.types.Panel): - bl_idname = "PANEL.BAKE_TO_ID_MAP_PT_SETTINGS_INFO" - bl_parent_id = "PANEL.BAKE_TO_ID_MAP_PT_SETTINGS" - bl_label = "Infos" - bl_space_type = "VIEW_3D" - bl_region_type = "UI" - bl_category = "Tool" - - def draw(self, context): - layout = self.layout - - props = context.scene.bake_to_id_props - - source = get_source(props.source) - - if props.selection_mode != 'SINGLE': - layout.label(text="Selected Object-Count: " + str(len(context.selected_objects))) - - if props.selection_mode == 'SINGLE': - layout.label(text="ID-Total: " + str(source.estimate_ids([context.active_object]))) - - if props.selection_mode == 'MULTIPLE_SEPARATE': - total = 0 - count = 0 - for obj in context.selected_objects: - if (obj.type != 'MESH'): - continue - - total += source.estimate_ids([obj]) - count += 1 - - layout.label(text="Estimated ID-Total: " + str(total)) - try: - layout.label(text="Estimated ID-Average: " + str(total / count)) - except ZeroDivisionError: - layout.label(text="Estimated ID-Average: 0") - - if props.selection_mode == 'MULTIPLE_COMBINED': - layout.label(text="ID-Total: " + str(source.estimate_ids(context.selected_objects))) - - color = get_color(props.colors) - - layout.label(text="Colors available: " + str(color.get_count(props))) diff --git a/src/panels/bake_panel_options.py b/src/panels/bake_panel_options.py deleted file mode 100644 index 543ab6e..0000000 --- a/src/panels/bake_panel_options.py +++ /dev/null @@ -1,56 +0,0 @@ -import textwrap - -import bpy - -from .. types.colors import get_color -from .. types.sources import get_source -from .. types.targets import get_target - - -class BakeToIDOptionsPanel(bpy.types.Panel): - bl_idname = "PANEL.BAKE_TO_ID_MAP_PT_SETTINGS_OPTIONS" - bl_parent_id = "PANEL.BAKE_TO_ID_MAP_PT_SETTINGS" - bl_label = "Options" - bl_space_type = "VIEW_3D" - bl_region_type = "UI" - bl_category = "Tool" - - def draw(self, context): - layout = self.layout - layout.use_property_split = True - layout.use_property_decorate = False # No animation. - - props = context.scene.bake_to_id_props - - layout.prop(props, "source") - source = get_source(props.source) - self.draw_options(context, layout, props, source) - - layout.separator() - - layout.prop(props, "target") - target = get_target(props.target) - self.draw_options(context, layout, props, target) - - layout.separator() - - layout.prop(props, "colors") - color = get_color(props.colors) - self.draw_options(context, layout, props, color) - - def draw_options(self, context, layout, props, element): - - has_render_ui = 'render_ui' in dir(element) - has_connected_properties = 'connected_properties' in dir(element) and len(element.connected_properties) > 0 - - if not has_render_ui and not has_connected_properties: - return - - object_box = layout.box() - - if has_render_ui: - element.render_ui(context, object_box, props) - return - - for setting in element.connected_properties: - object_box.prop(props, setting) \ No newline at end of file diff --git a/src/panels/id_mask_editor.py b/src/panels/id_mask_editor.py deleted file mode 100644 index 549fdd8..0000000 --- a/src/panels/id_mask_editor.py +++ /dev/null @@ -1,117 +0,0 @@ -import bpy - -from .. menu.id_mask_editor_options import IDEDITOR_IDMaskEditorOptionsMenu -from .. operators.create_id_mask import CreateIDMaskOperator -from .. operators.id_editor_apply_color import IDEDITOR_ColorApplyOperator -from .. operators.id_editor_create_id import IDEDITOR_CreateIDOperator -from .. operators.id_editor_paint import IDEDITOR_PaintIDMaskOperator -from .. operators.id_editor_remove_id import IDEDITOR_RemoveIDOperator -from .. operators.id_editor_revert_color import IDEDITOR_ColorResetOperator -from .. operators.id_mask_select import IDEDITOR_SelectIDMaskOperator -from .. types.colors import get_color - - -class IDMaskEditorPanel(bpy.types.Panel): - bl_idname = "ID_MASK_EDITOR_PT_Panel" - bl_label = "ID Mask Editor" - bl_category = "Tool" - bl_space_type = "VIEW_3D" - bl_region_type = "UI" - - @classmethod - def poll(cls, context): - if not context.object: - return False - - if not context.object.type == 'MESH': - return False - - return context.object.mode == "EDIT" - - def draw(self, context): - layout = self.layout - layout.use_property_decorate = True - - mesh = context.object.data - properties = mesh.id_mask_editor_properties - - target_attribute_row = layout.row(align=True) - has_attribute = properties.target_attribute - - target_attribute_row.prop_search( - properties, - 'target_attribute', - mesh, - 'color_attributes', - icon='GROUP_VCOL' - ) - target_attribute_row.operator(CreateIDMaskOperator.bl_idname, icon='ADD', text="") - - if not has_attribute: - return - - layout.prop(properties, "colors") - color = get_color(properties.colors) - self.draw_options(context, layout, properties, color) - - layout.separator() - - row = layout.row() - - col = row.column() - - col.template_list( - 'IDMaskEditorIDList', - 'IDMaskEditorIDList', - properties, - 'possible_ids', - properties, - 'active_id', - rows=3 - ) - - button_row = col.row() - button_row.operator(IDEDITOR_PaintIDMaskOperator.bl_idname, text='Paint', icon='VPAINT_HLT') - button_row.operator(IDEDITOR_SelectIDMaskOperator.bl_idname, text='Select', icon='SELECT_SET').isCalledFromEditor = True - - color_button_row = button_row.row(align=True) - has_color_changed = False - for id in properties.possible_ids: - if not id.color_changed: - continue - has_color_changed = True - break - - color_button_row.enabled = has_color_changed - - reset_op = color_button_row.operator(IDEDITOR_ColorResetOperator.bl_idname, icon='LOOP_BACK', text='Reset Colors') - reset_op.triggeredByList = False - - apply_op = color_button_row.operator(IDEDITOR_ColorApplyOperator.bl_idname, icon='CHECKMARK', text='Apply Colors') - apply_op.triggeredByList = False - - - col = row.column(align=True) - col.operator(IDEDITOR_CreateIDOperator.bl_idname, icon='ADD', text="") - col.operator(IDEDITOR_RemoveIDOperator.bl_idname, icon='REMOVE', text="") - col.separator() - - col.menu(IDEDITOR_IDMaskEditorOptionsMenu.bl_idname, icon='DOWNARROW_HLT', text="") - - - def draw_options(self, context, layout, props, element): - - has_render_ui = 'render_ui' in dir(element) - has_connected_properties = 'connected_properties' in dir(element) and len(element.connected_properties) > 0 - - if not has_render_ui and not has_connected_properties: - return - - object_box = layout.box() - - if has_render_ui: - element.render_ui(context, object_box, props) - return - - for setting in element.connected_properties: - object_box.prop(props, setting) \ No newline at end of file diff --git a/src/panels/id_mask_editor_id_list.py b/src/panels/id_mask_editor_id_list.py deleted file mode 100644 index 8afff75..0000000 --- a/src/panels/id_mask_editor_id_list.py +++ /dev/null @@ -1,30 +0,0 @@ -import bpy - -from .. operators.id_editor_apply_color import IDEDITOR_ColorApplyOperator -from .. operators.id_editor_revert_color import IDEDITOR_ColorResetOperator - - -class IDMaskEditorIDList(bpy.types.UIList): - def draw_item(self, _context, layout, data, attribute, _icon, _active_data, _active_propname, _index): - layout.alignment = 'EXPAND' - - split = layout.split(factor=0.15) - split.alignment = 'LEFT' - split.prop(attribute, 'color', text='') - - row = split.row() - col = row.column() - col.alignment = 'RIGHT' - col.emboss = 'NONE' - col.prop(attribute, "name", text="") - col.emboss = 'NORMAL' - - row1 = row.row(align=True) - row1.enabled = attribute.color_changed - reset_op = row1.operator(IDEDITOR_ColorResetOperator.bl_idname, icon='LOOP_BACK', text='') - reset_op.triggeredByList = True - reset_op.listId = _index - - apply_op = row1.operator(IDEDITOR_ColorApplyOperator.bl_idname, icon='CHECKMARK', text='') - apply_op.triggeredByList = True - apply_op.listId = _index diff --git a/src/panels/panel.py b/src/panels/panel.py new file mode 100644 index 0000000..23a37d5 --- /dev/null +++ b/src/panels/panel.py @@ -0,0 +1,16 @@ +import bpy + + +class BakeToIDMapPanel(bpy.types.Panel): + bl_idname = "PANEL.BAKE_TO_ID_MAP_PT_SETTINGS" + bl_label = "Bake to ID Map" + bl_space_type = "VIEW_3D" + bl_region_type = "UI" + bl_category = "Tool" + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = False # No animation. + + self.layout.operator("object.bake_to_id_map", text="Bake") diff --git a/src/panels/panel_advanced.py b/src/panels/panel_advanced.py new file mode 100644 index 0000000..9accb61 --- /dev/null +++ b/src/panels/panel_advanced.py @@ -0,0 +1,24 @@ +import math + +import bpy + + +class BakeToIDAdvancedMenu(bpy.types.Panel): + bl_idname = "PANEL.BAKE_TO_ID_MAP_PT_SETTINGS_ADVANCED" + bl_parent_id = "PANEL.BAKE_TO_ID_MAP_PT_SETTINGS" + bl_label = "Advanced" + bl_space_type = "VIEW_3D" + bl_region_type = "UI" + bl_category = "Tool" + bl_options = {'DEFAULT_CLOSED'} + + def draw(self, context): + layout = self.layout + + props = context.scene.bake_to_id_props + layout.label(text="Colors") + layout.prop(props, "adv_total_hues") + layout.prop(props, "adv_total_satuations") + layout.prop(props, "adv_total_brightnesses") + layout.label(text="Max ID-count: " + str( + math.pow(math.pow(props.adv_total_hues, props.adv_total_satuations), props.adv_total_brightnesses))) diff --git a/src/panels/panel_info.py b/src/panels/panel_info.py new file mode 100644 index 0000000..22dde49 --- /dev/null +++ b/src/panels/panel_info.py @@ -0,0 +1,20 @@ +import bpy + +from .. operators.bake_to_id_map import BakeToIDMapOperator + + +class BakeToIDInfoPanel(bpy.types.Panel): + bl_idname = "PANEL.BAKE_TO_ID_MAP_PT_SETTINGS_INFO" + bl_parent_id = "PANEL.BAKE_TO_ID_MAP_PT_SETTINGS" + bl_label = "Infos" + bl_space_type = "VIEW_3D" + bl_region_type = "UI" + bl_category = "Tool" + + def draw(self, context): + layout = self.layout + + props = context.scene.bake_to_id_props + + 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 diff --git a/src/panels/panel_options.py b/src/panels/panel_options.py new file mode 100644 index 0000000..3b74dbe --- /dev/null +++ b/src/panels/panel_options.py @@ -0,0 +1,45 @@ +import bpy + + +class BakeToIDOptionsPanel(bpy.types.Panel): + bl_idname = "PANEL.BAKE_TO_ID_MAP_PT_SETTINGS_OPTIONS" + bl_parent_id = "PANEL.BAKE_TO_ID_MAP_PT_SETTINGS" + bl_label = "Options" + bl_space_type = "VIEW_3D" + bl_region_type = "UI" + bl_category = "Tool" + + def draw(self, context): + layout = self.layout + + props = context.scene.bake_to_id_props + + layout.prop(props, "source") + source_settings_box = layout.box() + source_settings = self.get_source_settings(props) + for setting in source_settings: + source_settings_box.prop(props, setting) + + layout.separator() + + layout.prop(props, "target") + target_settings_box = layout.box() + target_settings = self.get_target_settings(props) + for setting in target_settings: + 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_properties.py b/src/properties/bake_properties.py deleted file mode 100644 index c46f0aa..0000000 --- a/src/properties/bake_properties.py +++ /dev/null @@ -1,62 +0,0 @@ -from bpy.types import (PropertyGroup, Palette) -from bpy.props import (EnumProperty, BoolProperty, IntProperty, StringProperty, PointerProperty) - -from .. types.colors import get_color_enum -from .. types.sources import get_source_enum -from .. types.targets import get_targets_enum - - -class BakeToIDProperties(PropertyGroup): - selection_mode: EnumProperty( - items=[ - ("SINGLE", "Only active element", "Only use the currently selected element", 0), - ("MULTIPLE_SEPARATE", "Use Selection, separate", "It performs the transfer for every selected element, but each get there own ids", 1), - ("MULTIPLE_COMBINED", "Use Selection, combined", "It performs the transfer for every selected element, combining the ids", 2) - ], - name="Selection Mode", - description="Specifies how the 3D View-Selection is gonna be used.", - default="MULTIPLE_SEPARATE" - ) - - source: EnumProperty( - items=get_source_enum(), - name="Source", - description="From where should the IDs be taken", - default="MATERIAL_INDEX" - ) - - target: EnumProperty( - items=get_targets_enum(), - name="Target", - description="To where should the IDs should be baked to", - default=get_targets_enum()[0][0] - ) - - colors: EnumProperty( - items=get_color_enum(), - name="Color Source", - description="From where to take the colors", - default=get_color_enum()[0][0] - ) - - source_materials_remove_all: BoolProperty( - name="Remove all source materials", - default=False, - description="Removes every material except the first one." - ) - - target_vertex_color_attribute_name: StringProperty( - name="Color Attribute", - default="ID_MASK", - ) - target_vertex_color_override_attribute: BoolProperty( - name="Override Color Attribute", - default=True, - description="If set true, the attribute will be deleted and recreated, if it already exists. If set false, the data will just be overwritten." - ) - - colors_color_palette_palette: PointerProperty( - type=Palette, - name='Color Palette', - description="The Color Palette used for colors" - ) \ No newline at end of file diff --git a/src/properties/bake_to_id.py b/src/properties/bake_to_id.py new file mode 100644 index 0000000..b7be6f7 --- /dev/null +++ b/src/properties/bake_to_id.py @@ -0,0 +1,52 @@ +from bpy.types import (PropertyGroup) +from bpy.props import (EnumProperty, BoolProperty, IntProperty, StringProperty) + + +class BakeToIDProperties(PropertyGroup): + source: EnumProperty( + items=[ + ('MATERIAL_INDEX', 'Material Index', "It takes the material index as ID basis", 0) + ], + 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)], + name="Target", + description="To where should the IDs should be baked to", + default="VERTEX_COLORS" + ) + + source_materials_remove_all : BoolProperty( + name="Remove all source materials", + default=False, + description="Removes every material except the first one." + ) + + target_vertex_color_attribute_name: StringProperty( + name="Color Attribute", + default="ID_MASK", + ) + + adv_total_hues: IntProperty( + name="Total Hues", + default=10, + min=1, + soft_max=360, + ) + + adv_total_satuations: IntProperty( + name="Total Satuations", + default=10, + min=1, + soft_max=100, + ) + + adv_total_brightnesses: IntProperty( + name="Total Brightnesses", + default=10, + min=1, + soft_max=100, + ) \ No newline at end of file diff --git a/src/properties/id_mask_editor_properties.py b/src/properties/id_mask_editor_properties.py deleted file mode 100644 index 5d7a8ef..0000000 --- a/src/properties/id_mask_editor_properties.py +++ /dev/null @@ -1,58 +0,0 @@ -import bpy - -from bpy.types import (PropertyGroup, Palette, FloatColorAttribute) -from bpy.props import (EnumProperty, BoolProperty, IntProperty, StringProperty, PointerProperty, CollectionProperty) - -from .. properties.id_mask_editor_value_properties import IDMaskEditorValueProperties -from .. types.colors import get_color_enum - -def on_target_attribute_set(self, value): - return None - -def on_target_attribute_get(self): - if bpy.context.active_object is None: - return None - - if bpy.context.active_object.data is None: - return None - - if bpy.context.active_object.type != 'MESH': - return None - - color_attributes = bpy.context.active_object.data.color_attributes[0] - - return color_attributes - -class IDMaskEditorProperties(PropertyGroup): - colors: EnumProperty( - items=get_color_enum(), - name="Color Source", - description="From where to take the colors", - default=get_color_enum()[0][0] - ) - - colors_color_palette_palette: PointerProperty( - type=Palette, - name='Color Palette', - description="The Color Palette used for colors" - ) - - target_attribute: StringProperty( - name='', - description="The attribute to write the ID Mask to" - ) - - possible_ids: CollectionProperty( - type=IDMaskEditorValueProperties, - name='Entries', - ) - - active_id: IntProperty( - name="", - description="", - default=0 - ) - - current_color_id: IntProperty( - default=0 - ) \ No newline at end of file diff --git a/src/properties/id_mask_editor_value_properties.py b/src/properties/id_mask_editor_value_properties.py deleted file mode 100644 index 29dfed5..0000000 --- a/src/properties/id_mask_editor_value_properties.py +++ /dev/null @@ -1,47 +0,0 @@ -from bpy.types import (PropertyGroup) -from bpy.props import (StringProperty,BoolProperty, FloatVectorProperty) - -def get_color(self): - return self['color'] - -def set_color(self, value): - if 'color' not in self: - self['color'] = value - return - - prev_color = self['color'] - - if not self.color_changed: - self.color_changed = True - self.original_color = prev_color - - self['color'] = value - -class IDMaskEditorValueProperties(PropertyGroup): - name: StringProperty( - name="Name", - description="ID-Name", - default='ID' - ) - - color_changed: BoolProperty( - default=False - ) - - color: FloatVectorProperty( - name="Color", - subtype='COLOR', - default=[1.0, 1.0, 1.0], - min=0, - max=1, - get=get_color, - set=set_color - ) - - original_color: FloatVectorProperty( - name="Original Color", - subtype='COLOR', - default=[1.0, 1.0, 1.0], - min=0, - max=1 - ) \ No newline at end of file diff --git a/src/types/colors/__init__.py b/src/types/colors/__init__.py deleted file mode 100644 index 82e0530..0000000 --- a/src/types/colors/__init__.py +++ /dev/null @@ -1,25 +0,0 @@ -from . import generated, color_palette - -_colors = [ - generated, - color_palette -] - - -def get_color(id): - for color in _colors: - if color.color_id == id: - return color - - raise Exception("Source not found: " + id) - - -def get_color_enum(): - enum_list = [] - i = 0 - for color in _colors: - enum_list.append((color.color_id, color.name, color.description, i)) - i += 1 - - return enum_list - diff --git a/src/types/colors/color_palette.py b/src/types/colors/color_palette.py deleted file mode 100644 index 078078a..0000000 --- a/src/types/colors/color_palette.py +++ /dev/null @@ -1,25 +0,0 @@ -color_id = 'COLOR_PALETTE' -name = 'Palette' -description = "The color palette is specified by the user" - - -def get_colors(props): - if not props.colors_color_palette_palette: - return [] - - return list(map(lambda x: x.color, props.colors_color_palette_palette.colors)) - - -def get_count(props): - if not props.colors_color_palette_palette: - return 0 - - return len(props.colors_color_palette_palette.colors) - - -def render_ui(context, layout, props): - layout.template_ID(props, "colors_color_palette_palette") - if props.colors_color_palette_palette: - row = layout.column() - row.enabled = False - row.template_palette(props, "colors_color_palette_palette", color=True) diff --git a/src/types/colors/generated.py b/src/types/colors/generated.py deleted file mode 100644 index 11488e6..0000000 --- a/src/types/colors/generated.py +++ /dev/null @@ -1,31 +0,0 @@ -import colorsys - -color_id = 'GENERATED' -name = 'Generated' -description = 'The colors get generated on-the-fly' - -MAX_BRIGHTNESS_STEPS = 8 -MAX_SATURATION_STEPS = 8 -MAX_HUES_STEPS = 8 - -def get_colors(props): - return gen_colors() - - -def get_count(props): - return len(gen_colors()) - - -def gen_colors(): - colors = [] - for brightnessStep in range(0, MAX_BRIGHTNESS_STEPS): - v = 1 - (brightnessStep / MAX_BRIGHTNESS_STEPS) - for satuationStep in range(0, MAX_SATURATION_STEPS): - s = 1 - (satuationStep / MAX_SATURATION_STEPS) - for hueStep in range(0, MAX_HUES_STEPS): - h = hueStep / MAX_HUES_STEPS - - color = colorsys.hsv_to_rgb(h, s, v) - colors.append(color) - - return colors \ No newline at end of file diff --git a/src/types/sources/__init__.py b/src/types/sources/__init__.py deleted file mode 100644 index f52c397..0000000 --- a/src/types/sources/__init__.py +++ /dev/null @@ -1,25 +0,0 @@ -from . import material_index -from . import object - -_sources = [ - material_index, - object -] - -def get_source(id): - for source in _sources: - if source.source_id == id: - return source - - raise Exception("Source not found: " + id) - - -def get_source_enum(): - enum_list = [] - i = 0 - for source in _sources: - enum_list.append((source.source_id, source.name, source.description, i)) - i += 1 - - return enum_list - diff --git a/src/types/sources/material_index.py b/src/types/sources/material_index.py deleted file mode 100644 index 39be292..0000000 --- a/src/types/sources/material_index.py +++ /dev/null @@ -1,41 +0,0 @@ -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(objects): - targets = [] - for obj in 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(objects): - count = 0 - for obj in objects: - count += len(obj.material_slots) - - return count diff --git a/src/types/sources/object.py b/src/types/sources/object.py deleted file mode 100644 index 7a94968..0000000 --- a/src/types/sources/object.py +++ /dev/null @@ -1,16 +0,0 @@ -source_id = 'OBJECT' -name = 'Object ID' -description = 'Uses the object id as basis for the ID mask.' - -connected_properties = [] - -def get_targets(objects): - targets = [] - for obj in objects: - mesh = obj.data - targets.append((mesh, mesh.polygons)) - - return targets - -def estimate_ids(objects): - return len(objects) \ No newline at end of file diff --git a/src/types/targets/__init__.py b/src/types/targets/__init__.py deleted file mode 100644 index 95c7908..0000000 --- a/src/types/targets/__init__.py +++ /dev/null @@ -1,23 +0,0 @@ -from . import vertex_colors - -_targets = [ - vertex_colors -] - - -def get_target(id): - for target in _targets: - if target.target_id == id: - return target - - raise Exception("Target not found: " + id) - - -def get_targets_enum(): - enum_list = [] - i = 0 - for target in _targets: - enum_list.append((target.target_id, target.name, target.description, i)) - i += 1 - - return enum_list diff --git a/src/types/targets/vertex_colors.py b/src/types/targets/vertex_colors.py deleted file mode 100644 index b343d01..0000000 --- a/src/types/targets/vertex_colors.py +++ /dev/null @@ -1,40 +0,0 @@ -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', - 'target_vertex_color_override_attribute' -] - - -def paint_targets(props, targets, colors): - sorted_targets = {} - colors_amount = len(colors) - 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 % colors_amount])) - - layer_name = props.target_vertex_color_attribute_name - for mesh in sorted_targets: - color_attribute = get_color_attribute(props, mesh.attributes, layer_name) - - 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) - -def get_color_attribute(props, attributes, layer_name): - if layer_name in attributes: - if not props.target_vertex_color_override_attribute: - return attributes[layer_name] - - attributes.remove(attributes[layer_name]) - - return attributes.new(name=layer_name, type='FLOAT_COLOR', domain='CORNER') \ No newline at end of file