This commit is contained in:
x-o-i-o-x 2025-10-04 20:18:22 +02:00
parent 3cb8961d6e
commit cdc2b263f4
6 changed files with 211 additions and 0 deletions

40
__init__.py Normal file
View File

@ -0,0 +1,40 @@
__addon_enabled__ = False # Default state, Blender will manage this
bl_info = {
"name": "Virtual Painter",
"author": "Andrin Honegger",
"version": (0, 1, 0),
"blender": (4, 3, 2),
"location": "3D Viewport > Tool Shelf > Tool",
"description": "",
"warning": "",
"category": "Paint",
}
from . import (
paintListener,
paintModifier,
ui,
preferences,
)
import bpy # Blender Python API
# Register and Unregister Classes
module_tuple = (
#paintListener,
#paintModifier,
ui,
#preferences,
)
def register():
for item in module_tuple:
item.register()
def unregister():
for item in module_tuple:
item.unregister()
if __name__ == "__main__":
register()

16
blender_manifest.toml Normal file
View File

@ -0,0 +1,16 @@
schema_version = "1.0.0"
id = "virtual_painter"
version = "0.1.0"
name = "Virtual Painter"
tagline = "Painting extension for painting normals for a painted style"
maintainer = "Andrin Honegger"
type = "add-on"
tags = ["Paint"]
blender_version_min = "4.3.2"
license = [
"SPDX:GPL-3.0-or-later",
]

7
paintListener.py Normal file
View File

@ -0,0 +1,7 @@
import bpy
def register():
pass
def unregister():
pass

7
paintModifier.py Normal file
View File

@ -0,0 +1,7 @@
import bpy
def register():
pass
def unregister():
pass

7
preferences.py Normal file
View File

@ -0,0 +1,7 @@
import bpy
def register():
pass
def unregister():
pass

134
ui.py Normal file
View File

@ -0,0 +1,134 @@
import bpy
class vPainterSetting(bpy.types.PropertyGroup):
is_vPainter_enabled: bpy.props.BoolProperty(
name="Addon Enabled",
description="Enable / disable the virtual Painter",
default=False,
update=lambda self, context: toggle_operator(context)
)
texture_panel_state: bpy.props.BoolProperty(
name="Textures",
default=False,
description="Textures used for painting"
)
def toggle_operator(context):
"""Start or stop the modal operator based on the checkbox."""
if context.scene.vPainter_settings.is_vPainter_enabled:
# Start the operator
bpy.ops.paint.virtual_painter('INVOKE_DEFAULT')
class textureSelection(bpy.types.PropertyGroup):
texture: bpy.props.PointerProperty(
name="Texture",
type=bpy.types.Image,
description="Select a texture",
)
color: bpy.props.FloatVectorProperty(
name="Color",
subtype='COLOR',
size=4,
min=0.0,
max=1.0,
default=(1.0, 1.0, 1.0, 1.0),
description="Select a color (RGBA)",
)
class VIEW3D_PT_ToolActiveToolPanel(bpy.types.Panel):
bl_space_type = 'VIEW_3D'
bl_region_type = 'UI'
bl_category = "Tool"
bl_label = "Virtual Painter"
bl_idname = "VIEW3D_PT_virtual_Painter"
def draw(self, context):
layout = self.layout
tool_settings = context.scene.vPainter_settings
normal_texture = context.scene.normal_texture_settings
texture_collection = context.scene.texture_collection_settings
# Add the checkbox to toggle the operator
layout.prop(
tool_settings,
"is_vPainter_enabled",
text="DISABLE" if tool_settings.is_vPainter_enabled else "ENABLE",
toggle=True,
invert_checkbox=True
)
# Collapsible section of used textures
layout.prop(
tool_settings,
"texture_panel_state",
emboss=False,
icon="DOWNARROW_HLT" if tool_settings.texture_panel_state else "RIGHTARROW",
toggle=True
)
if tool_settings.texture_panel_state:
section = layout.box()
section.label(text="Normal Texture")
# Normal texture selection
section.prop(normal_texture, "texture", text="", icon="TEXTURE")
section.separator(type='LINE')
# Custom texture selection
section.label(text="Custom Texture")
# Display all items in the collection
for index, item in enumerate(texture_collection):
box = section.box()
box.prop(item, "texture", text="", icon="TEXTURE")
box.prop(item, "color", text="", icon="COLOR")
box.operator("custom_texture.remove_item", text="", icon="X").index = index
section.operator("custom_texture.add_item", icon="ADD")
# Operator to add new items to the collection
class IMAGE_OT_AddItem(bpy.types.Operator):
bl_idname = "custom_texture.add_item"
bl_label = "Add New"
bl_description = "Add a new texture"
def execute(self, context):
texture_collection = context.scene.texture_collection_settings
texture_collection.add()
return {'FINISHED'}
# Operator to remove items from the collection
class IMAGE_OT_RemoveItem(bpy.types.Operator):
bl_idname = "custom_texture.remove_item"
bl_label = ""
bl_description = "Remove this texture"
index: bpy.props.IntProperty()
def execute(self, context):
texture_collection = context.scene.texture_collection_settings
if 0 <= self.index < len(texture_collection):
texture_collection.remove(self.index)
return {'FINISHED'}
def register():
bpy.utils.register_class(vPainterSetting)
bpy.utils.register_class(textureSelection)
bpy.utils.register_class(VIEW3D_PT_ToolActiveToolPanel)
bpy.utils.register_class(IMAGE_OT_AddItem)
bpy.utils.register_class(IMAGE_OT_RemoveItem)
bpy.types.Scene.vPainter_settings = bpy.props.PointerProperty(type=vPainterSetting)
bpy.types.Scene.normal_texture_settings = bpy.props.PointerProperty(type=textureSelection)
bpy.types.Scene.texture_collection_settings = bpy.props.CollectionProperty(type=textureSelection)
def unregister():
bpy.utils.unregister_class(vPainterSetting)
bpy.utils.unregister_class(textureSelection)
bpy.utils.unregister_class(VIEW3D_PT_ToolActiveToolPanel)
bpy.utils.unregister_class(IMAGE_OT_AddItem)
bpy.utils.unregister_class(IMAGE_OT_RemoveItem)
del bpy.types.Scene.vPainter_settings
del bpy.types.Scene.normal_texture_settings
del bpy.types.Scene.texture_collection_settings