Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 26 additions & 2 deletions extension/__init__.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import bpy # type: ignore
import json
from bpy.app.handlers import persistent
from .op_insert_component_modal import InsertComponent, SelectedObjectOptions
from .op_apply_preset import ApplyPresetToBone, ApplyPresetToCollection, ApplyPresetToLight, ApplyPresetToMaterial, ApplyPresetToMesh, ApplyPresetToObject, ApplyPresetToScene
from .cli_dump_component_data import dump_component_data # type: ignore
from .op_insert_component import InsertComponentOnBone, InsertComponentOnCollection, InsertComponentOnLight, InsertComponentOnMaterial, InsertComponentOnMesh, InsertComponentOnObject, InsertComponentOnScene
from .op_insert_component import InsertComponentOnBone, InsertComponentOnCollection, InsertComponentOnLight, InsertComponentOnMaterial, InsertComponentOnMesh, InsertComponentOnObject, InsertComponentOnWindowManager, InsertComponentOnScene
# from .op_insert_component_modal import InsertComponent
from .op_registry_loading import FetchRemoteTypeRegistry, ReloadSkeinRegistryJson
from .op_remove_component import RemoveComponentOnBone, RemoveComponentOnCollection, RemoveComponentOnLight, RemoveComponentOnMaterial, RemoveComponentOnMesh, RemoveComponentOnObject, RemoveComponentOnScene
from .op_remove_component import RemoveComponentOnBone, RemoveComponentOnCollection, RemoveComponentOnLight, RemoveComponentOnMaterial, RemoveComponentOnMesh, RemoveComponentOnObject, RemoveComponentOnScene, RemoveComponentOnWindowManager
from .op_debug_check_components import DebugCheckComponents
from .property_groups import ComponentData
from .skein_panel import SkeinPanelBone, SkeinPanelCollection, SkeinPanelLight, SkeinPanelObject, SkeinPanelMesh, SkeinPanelMaterial, SkeinPanelScene
Expand Down Expand Up @@ -92,6 +94,10 @@ def menu_func(self, context):
self.layout.operator(ReloadSkeinRegistryJson.bl_idname)

def register():
# TODO: move this
bpy.utils.register_class(SelectedObjectOptions)


bpy.utils.register_class(SkeinAddonPreferences)
# data types that are stored on the window because blender
# doesn't seem to have any other good way of storing data
Expand Down Expand Up @@ -135,6 +141,11 @@ def register():
override={"LIBRARY_OVERRIDABLE"},
)

## Used for temporary data, like operators
bpy.types.WindowManager.active_component_index = bpy.props.IntProperty(
min=0
)

# TODO: move this to common property group for all object, material, mesh, etc extras
bpy.types.WindowManager.selected_component = bpy.props.StringProperty(
name="component type path",
Expand All @@ -150,6 +161,7 @@ def register():
bpy.utils.register_class(FetchRemoteTypeRegistry)
bpy.utils.register_class(ReloadSkeinRegistryJson)
bpy.utils.register_class(DebugCheckComponents)
# bpy.utils.register_class(InsertComponent)
## Insertion Operations
bpy.utils.register_class(InsertComponentOnObject)
bpy.utils.register_class(InsertComponentOnMesh)
Expand All @@ -158,6 +170,8 @@ def register():
bpy.utils.register_class(InsertComponentOnLight)
bpy.utils.register_class(InsertComponentOnCollection)
bpy.utils.register_class(InsertComponentOnBone)
bpy.utils.register_class(InsertComponentOnWindowManager)
bpy.utils.register_class(InsertComponent)
## Remove Operations
bpy.utils.register_class(RemoveComponentOnObject)
bpy.utils.register_class(RemoveComponentOnMesh)
Expand All @@ -166,6 +180,7 @@ def register():
bpy.utils.register_class(RemoveComponentOnLight)
bpy.utils.register_class(RemoveComponentOnCollection)
bpy.utils.register_class(RemoveComponentOnBone)
bpy.utils.register_class(RemoveComponentOnWindowManager)
## Preset Operations
bpy.utils.register_class(ApplyPresetToObject)
bpy.utils.register_class(ApplyPresetToMesh)
Expand Down Expand Up @@ -207,6 +222,9 @@ def register():
exporter_extension_layout_draw['Example glTF Extension'] = draw_export # Make sure to use the same name in unregister()

def unregister():
# TODO: move this
bpy.utils.unregister_class(SelectedObjectOptions)

global_skein = bpy.context.window_manager.skein
skein_property_groups = bpy.context.window_manager.skein_property_groups

Expand Down Expand Up @@ -234,6 +252,7 @@ def unregister():
bpy.utils.unregister_class(PGSkeinWindowProps)
bpy.utils.unregister_class(ComponentTypeData)
bpy.utils.unregister_class(ComponentData)
# bpy.utils.unregister_class(InsertComponent)
# operations
bpy.utils.unregister_class(FetchRemoteTypeRegistry)
bpy.utils.unregister_class(ReloadSkeinRegistryJson)
Expand All @@ -244,12 +263,17 @@ def unregister():
bpy.utils.unregister_class(InsertComponentOnMaterial)
bpy.utils.unregister_class(InsertComponentOnLight)
bpy.utils.unregister_class(InsertComponentOnCollection)
bpy.utils.unregister_class(InsertComponentOnWindowManager)
bpy.utils.unregister_class(InsertComponent)
## Remove Operations
bpy.utils.unregister_class(RemoveComponentOnObject)
bpy.utils.unregister_class(RemoveComponentOnMesh)
bpy.utils.unregister_class(RemoveComponentOnMaterial)
bpy.utils.unregister_class(RemoveComponentOnScene)
bpy.utils.unregister_class(RemoveComponentOnLight)
bpy.utils.unregister_class(RemoveComponentOnCollection)
bpy.utils.unregister_class(RemoveComponentOnBone)
bpy.utils.unregister_class(RemoveComponentOnWindowManager)
## Preset Operations
bpy.utils.unregister_class(ApplyPresetToObject)
bpy.utils.unregister_class(ApplyPresetToMesh)
Expand Down
2 changes: 1 addition & 1 deletion extension/object_to_form.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ def object_to_form(context, context_key, data):
data is the component data
"""
if context_key not in context:
return
return

# The current PropertyGroup we're working with
obj = getattr(context, context_key)
Expand Down
22 changes: 20 additions & 2 deletions extension/op_insert_component.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,10 +102,28 @@ def execute(self, context):
insert_component_data(context, context.bone)
return {'FINISHED'}

def insert_component_data(context, obj):
class InsertComponentOnWindowManager(bpy.types.Operator):
"""Insert a component on the window manager"""
bl_idname = "wm.insert_component" # unique identifier. first word is required by extensions review team to be from a specific set of words
bl_label = "Add Component" # Shows up in the UI
bl_options = {'REGISTER', 'UNDO'} # enable undo (which we might not need)

# @classmethod
# def poll(cls, context):
# return context.bone is not None

def execute(self, context):
insert_component_data(context, context.window_manager)
return {'FINISHED'}

def insert_component_data(context, obj, type_path_override=None):
"""
Inserting data is super generic, the only difference is where we're inserting it.
This is basically the same concept as Custom Properties which don't care what object they're on.

Inserts using context.window_manager.selected_component if a type_path_override isn't set

expects a full, raw type_path in type_path_override
"""
debug = False
presets = False
Expand All @@ -118,7 +136,7 @@ def insert_component_data(context, obj):
print("\ninsert_component_data:")

global_skein = context.window_manager.skein
selected_component = context.window_manager.selected_component
selected_component = type_path_override or context.window_manager.selected_component

if global_skein.registry:
registry = json.loads(global_skein.registry)
Expand Down
123 changes: 123 additions & 0 deletions extension/op_insert_component_modal.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import json
import bpy
import inspect

from .form_to_object import get_data_from_active_editor

from .op_insert_component import insert_component_data

from .skein_panel import draw_generic_panel, render_two

from .object_to_form import object_to_form
from .property_groups import hash_over_64

def get_targets(self, context):
match self.ty:
case "MESH":
return [
("active_material","active_material",""),
]
case "LIGHT":
return [("idk","idk","")]
case "CAMERA":
return [("whatever","whatever","")]

# If an exact match is not confirmed, this last case will be used if provided
case _:
return [("no options","no options","")]

class SelectedObjectOptions(bpy.types.PropertyGroup):
"""Options that correspond to selected objects
"""
ty: bpy.props.StringProperty()
targets: bpy.props.EnumProperty(
name="target",
items=get_targets,
default=0
)

class InsertComponent(bpy.types.Operator):
"""Insert Components on Selected Objects

"""
bl_idname = 'wm.insert_component_modal'
bl_label = 'Insert Components'
bl_description ='Select objects and insert components'
bl_options = {'REGISTER', 'UNDO'}

selected: bpy.props.CollectionProperty(
type=SelectedObjectOptions,
)
# active_component_index = bpy.props.IntProperty(
# min=0,
# override={"LIBRARY_OVERRIDABLE"},
# )
# ty = bpy.props.EnumProperty(
# name="type",
# items=[
# ("object","object","object is available"),
# ("mesh","mesh","mesh is available"),
# ("material","material","material is available")
# ],
# default="mesh"
# )
# skein_two = bpy.props.PointerProperty()
# obj_file = bpy.props.StringProperty()

def execute(self, context):
skein_property_groups = context.window_manager.skein_property_groups

# Iterate over all targets with a skein_two field, setting up
# the component data for each.
# "with a skein_two field" is controlled by the bpy.types setups
# and the limits inflicted by the operator's enum lists
for i, target_object in enumerate(bpy.context.selected_objects):
user_selected_target_object = getattr(target_object, self.selected[i].targets)
for component in context.window_manager.skein_two:
type_path = component["selected_type_path"]
## create the new component, touching all PointerProperty fields
## with a "forced" type_path.
insert_component_data(context, user_selected_target_object, type_path)

target_skein_two = user_selected_target_object.skein_two
# -1 is "last element in list"
component_container = target_skein_two[-1]
## Get data from user-created component
if inspect.isclass(skein_property_groups[type_path]):
data = get_data_from_active_editor(component, hash_over_64(type_path))
object_to_form(
component_container,
hash_over_64(type_path),
data
)
else:
data = getattr(component, hash_over_64(type_path))
setattr(component_container, hash_over_64(type_path), data)

self.selected.clear()
return {'FINISHED'}

def invoke(self, context, event):
# self.data = {}
# return self.execute(context)
wm = context.window_manager
## clear any old skein_two data
wm.skein_two.clear()
for id in context.selected_ids:
print("adding", id.type)
select = self.selected.add()
select.ty = id.type
return wm.invoke_props_dialog(self, confirm_text="Insert Components")

def draw(self, context):
split = self.layout.row()
col = split.column()
for selected in self.selected:
layout = col.column()
layout.label(text=selected.ty)
layout.prop(selected, "targets")
# draw_generic_panel(context, obj, self.layout, "object", "OBJECT_PT_skein_preset_panel")
draw_generic_panel(context, context.window_manager, split.column(), "wm", "OBJECT_PT_skein_preset_panel")



24 changes: 20 additions & 4 deletions extension/op_registry_loading.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
import json
import requests # type: ignore
import os

# from .op_insert_component_modal import build_insert_component_operator
from .property_groups import hash_over_64, make_property
# --------------------------------- #
# Fetch and store the bevy type #
Expand Down Expand Up @@ -31,16 +33,12 @@ def execute(self, context):
brp_response = None

try:
print("\nexecute: TODO: a")
rpc_response = brp_simple_request("rpc.discover")
print("\nexecute: TODO: b")
print(rpc_response)
if rpc_response is not None and "error" in rpc_response:
if debug:
print("bevy request errored out", rpc_response["error"])
self.report({"ERROR"}, "request for Bevy registry data returned an error, is the Bevy Remote Protocol Plugin added and is the Bevy app running? :: " + brp_response["error"]["message"])
return {'CANCELLED'}
print("\nexecute: TODO: c")
bevy_version = rpc_response["result"]["info"]["version"]
print(bevy_version)
if bevy_version.startswith("0.16"):
Expand Down Expand Up @@ -253,6 +251,13 @@ def process_registry(context, registry):
# so adding to it is fine
skein_property_groups["skein_internal_container"] = component_container
bpy.utils.register_class(component_container)
# try:
# bpy.utils.unregister_class(skein_property_groups["skein_internal_insert_operator"])
# except:
# # it doesn't matter why this failed, because sometimes it won't exist anyway
# pass

# skein_property_groups["skein_internal_insert_operator"] = build_insert_component_operator(component_container)

# new component list data. Must be set to read component data from .blend file
bpy.types.Object.skein_two = bpy.props.CollectionProperty(
Expand Down Expand Up @@ -287,3 +292,14 @@ def process_registry(context, registry):
type=component_container,
override={"LIBRARY_OVERRIDABLE"},
)

## This is where we store temporary skein_two data.
## for example, passing skein_two access back and forth in
## the generic "insert_component" operator
##
## WindowManager gets cleared when reloading .blend/closing app
## /etc so is fine for temporary data
bpy.types.WindowManager.skein_two = bpy.props.CollectionProperty(
type=component_container,
override={"LIBRARY_OVERRIDABLE"},
)
14 changes: 14 additions & 0 deletions extension/op_remove_component.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,20 @@ def poll(cls, context):
def execute(self, context):
remove_component_data(context, context.bone)
return {'FINISHED'}

class RemoveComponentOnWindowManager(bpy.types.Operator):
"""Remove a component"""
bl_idname = "wm.remove_component" # unique identifier. first word is required by extensions review team to be from a specific set of words
bl_label = "Remove Component" # Shows up in the UI
bl_options = {'REGISTER', 'UNDO'} # enable undo (which we might not need)

# @classmethod
# def poll(cls, context):
# return context.bone is not None

def execute(self, context):
remove_component_data(context, context.window_manager)
return {'FINISHED'}

###
def remove_component_data(context, obj):
Expand Down