adds id editor

This commit is contained in:
Michel Fedde 2024-02-01 00:48:05 +01:00
parent 28ab2072e5
commit 40a7e4b8ba
16 changed files with 367 additions and 18 deletions

6
docu/planned_features.md Normal file
View file

@ -0,0 +1,6 @@
## Planned features
### ID Mask - Editor
- [ ] A way to automatically get already used colors, f.E. you already did it by hand
- [ ] Select by color
- [ ] Update after color change

View file

@ -1,5 +1,22 @@
import bpy
from src.operators.create_id_mask import CreateIDMaskOperator
from src.operators.id_editor_create_id import IDEDITOR_CreateIDOperator
from src.operators.id_editor_paint import IDEDITOR_PaintIDMaskOperator
from src.operators.id_editor_remove_id import IDEDITOR_RemoveIDOperator
from src.panels.id_mask_editor_id_list import IDMaskEditorIDList
from src.properties.id_mask_editor_value_properties import IDMaskEditorValueProperties
from . panels.bake_panel_options import BakeToIDOptionsPanel
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 src.properties.id_mask_editor_properties import IDMaskEditorProperties
bl_info = { bl_info = {
"name": "Bake ID Mask", "name": "ID Mask - Tools",
"author": "iedSoftworks", "author": "iedSoftworks",
"description": "", "description": "",
# !VERSION # !VERSION
@ -7,20 +24,21 @@ bl_info = {
"category": "Object" "category": "Object"
} }
import bpy
from . panels.panel_options import BakeToIDOptionsPanel
from . operators.bake_to_id_map import BakeToIDMapOperator
from . panels.panel import BakeToIDMapPanel
from . panels.panel_info import BakeToIDInfoPanel
from . properties.bake_to_id import BakeToIDProperties
classes = ( classes = (
BakeToIDMapOperator, BakeToIDMapOperator,
BakeToIDMapPanel, BakeToIDMapPanel,
BakeToIDInfoPanel, BakeToIDInfoPanel,
BakeToIDOptionsPanel, BakeToIDOptionsPanel,
BakeToIDProperties, BakeToIDProperties,
IDMaskEditorValueProperties,
IDMaskEditorProperties,
IDMaskEditorPanel,
CreateIDMaskOperator,
IDMaskEditorIDList,
IDEDITOR_CreateIDOperator,
IDEDITOR_RemoveIDOperator,
IDEDITOR_PaintIDMaskOperator
) )
@ -29,7 +47,7 @@ def register():
bpy.utils.register_class(cls) bpy.utils.register_class(cls)
setattr(bpy.types.Scene, 'bake_to_id_props', bpy.props.PointerProperty(type=BakeToIDProperties)) 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(): def unregister():
for cls in reversed(classes): for cls in reversed(classes):

View file

@ -1,6 +1,3 @@
import colorsys
import math
import bpy import bpy
from ..types.colors import get_color from ..types.colors import get_color

View file

@ -0,0 +1,38 @@
import bpy
class CreateIDMaskOperator(bpy.types.Operator):
bl_idname = "id_mask_editor.create_id_mask_attribute"
bl_label = ""
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'}

View file

@ -0,0 +1,33 @@
import bpy
from src.properties.id_mask_editor_value_properties import IDMaskEditorValueProperties
from src.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'}

View file

@ -0,0 +1,38 @@
import bpy
class IDEDITOR_PaintIDMaskOperator(bpy.types.Operator):
bl_idname = "id_mask_editor.paint_id_mask"
bl_label = "Paint"
bl_options = {'INTERNAL'}
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)
selected_polygons = []
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'}

View file

@ -0,0 +1,41 @@
import bpy
from src.properties.id_mask_editor_value_properties import IDMaskEditorValueProperties
from src.types.colors import get_color
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'}

View file

@ -3,7 +3,7 @@ import bpy
class BakeToIDMapPanel(bpy.types.Panel): class BakeToIDMapPanel(bpy.types.Panel):
bl_idname = "PANEL.BAKE_TO_ID_MAP_PT_SETTINGS" bl_idname = "PANEL.BAKE_TO_ID_MAP_PT_SETTINGS"
bl_label = "Bake to ID Map" bl_label = "Bake ID Mask"
bl_space_type = "VIEW_3D" bl_space_type = "VIEW_3D"
bl_region_type = "UI" bl_region_type = "UI"
bl_category = "Tool" bl_category = "Tool"

View file

@ -0,0 +1,90 @@
import bpy
from src.operators.create_id_mask import CreateIDMaskOperator
from src.operators.id_editor_create_id import IDEDITOR_CreateIDOperator
from src.operators.id_editor_paint import IDEDITOR_PaintIDMaskOperator
from src.operators.id_editor_remove_id import IDEDITOR_RemoveIDOperator
from src.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.operator(IDEDITOR_PaintIDMaskOperator.bl_idname, icon='VPAINT_HLT')
col.template_list(
'IDMaskEditorIDList',
'IDMaskEditorIDList',
properties,
'possible_ids',
properties,
'active_id',
rows=3
)
col = row.column(align=True)
col.operator(IDEDITOR_CreateIDOperator.bl_idname, icon='ADD', text="")
col.operator(IDEDITOR_RemoveIDOperator.bl_idname, icon='REMOVE', 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)

View file

@ -0,0 +1,17 @@
import bpy
from src.operators.id_editor_paint import IDEDITOR_PaintIDMaskOperator
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='')
split.emboss = 'NONE'
split2 = split.split(factor=0.75)
split2.prop(attribute, "name", text="")
split2.emboss = 'NORMAL'

View file

@ -0,0 +1,58 @@
import bpy
from bpy.types import (PropertyGroup, Palette, FloatColorAttribute)
from bpy.props import (EnumProperty, BoolProperty, IntProperty, StringProperty, PointerProperty, CollectionProperty)
from src.properties.id_mask_editor_value_properties import IDMaskEditorValueProperties
from src.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
)

View file

@ -0,0 +1,17 @@
from bpy.types import (PropertyGroup)
from bpy.props import (StringProperty, FloatVectorProperty)
class IDMaskEditorValueProperties(PropertyGroup):
name: StringProperty(
name="Name",
description="ID-Name",
default='ID'
)
color: FloatVectorProperty(
name="Color",
subtype='COLOR',
default=[1.0, 1.0, 1.0],
min=0,
max=1
)

View file

@ -23,10 +23,6 @@ def paint_targets(props, targets, colors):
layer_name = props.target_vertex_color_attribute_name layer_name = props.target_vertex_color_attribute_name
for mesh in sorted_targets: for mesh in sorted_targets:
if layer_name in mesh.attributes:
mesh.attributes.remove(mesh.attributes[layer_name])
color_attribute = get_color_attribute(props, mesh.attributes, layer_name) color_attribute = get_color_attribute(props, mesh.attributes, layer_name)
for (indecies, color) in sorted_targets[mesh]: for (indecies, color) in sorted_targets[mesh]: