From bf2e63f9280215b00ff18174f9796d5cb9bf8db1 Mon Sep 17 00:00:00 2001 From: Fen Dweller Date: Thu, 13 Jan 2022 11:32:18 -0500 Subject: [PATCH] Work on the add-on --- scripts/blender/addons/.vscode/settings.json | 3 + scripts/blender/addons/macrovision.py | 26 ---- .../blender/addons/macrovision/__init__.py | 33 ++++++ .../blender/addons/{mv => macrovision}/ops.py | 111 +++++++++++++----- scripts/blender/addons/macrovision/props.py | 77 ++++++++++++ scripts/blender/addons/macrovision/ui.py | 92 +++++++++++++++ scripts/blender/addons/mv/__init__.py | 0 scripts/blender/addons/mv/ui.py | 31 ----- 8 files changed, 284 insertions(+), 89 deletions(-) create mode 100644 scripts/blender/addons/.vscode/settings.json delete mode 100644 scripts/blender/addons/macrovision.py create mode 100644 scripts/blender/addons/macrovision/__init__.py rename scripts/blender/addons/{mv => macrovision}/ops.py (68%) create mode 100644 scripts/blender/addons/macrovision/props.py create mode 100644 scripts/blender/addons/macrovision/ui.py delete mode 100644 scripts/blender/addons/mv/__init__.py delete mode 100644 scripts/blender/addons/mv/ui.py diff --git a/scripts/blender/addons/.vscode/settings.json b/scripts/blender/addons/.vscode/settings.json new file mode 100644 index 00000000..de288e1e --- /dev/null +++ b/scripts/blender/addons/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "python.formatting.provider": "black" +} \ No newline at end of file diff --git a/scripts/blender/addons/macrovision.py b/scripts/blender/addons/macrovision.py deleted file mode 100644 index 303c3fb7..00000000 --- a/scripts/blender/addons/macrovision.py +++ /dev/null @@ -1,26 +0,0 @@ -import mv.ui -import mv.ops - -import bpy -import importlib - -bl_info = { - "name": "Macrovision", - "blender": (3, 0, 0), - "category": "Import-Export" -} - - -def register(): - importlib.reload(mv.ui) - importlib.reload(mv.ops) - cls_lists = [mv.ops.clses, mv.ui.clses] - for cls_list in cls_lists: - for cls in cls_list: - bpy.utils.register_class(cls) - -def unregister(): - cls_lists = [mv.ops.clses, mv.ui.clses][::-1] - for cls_list in cls_lists[::-1]: - for cls in cls_list: - bpy.utils.register_class(cls) \ No newline at end of file diff --git a/scripts/blender/addons/macrovision/__init__.py b/scripts/blender/addons/macrovision/__init__.py new file mode 100644 index 00000000..c6b1d60b --- /dev/null +++ b/scripts/blender/addons/macrovision/__init__.py @@ -0,0 +1,33 @@ +from macrovision import ui, ops, props + +import bpy +import importlib + +bl_info = { + "name": "Macrovision", + "blender": (3, 0, 0), + "category": "Import-Export" +} + +def register(): + importlib.reload(ui) + importlib.reload(ops) + importlib.reload(props) + cls_lists = [props.clses, ops.clses, ui.clses] + for cls_list in cls_lists: + for cls in cls_list: + bpy.utils.register_class(cls) + + for id, prop in props.scene_props.items(): + setattr(bpy.types.Scene, id, prop) + + +def unregister(): + cls_lists = [props.clses, ops.clses, ui.clses][::-1] + for cls_list in cls_lists[::-1]: + for cls in cls_list: + bpy.utils.unregister_class(cls) + + for id in props.scene_props: + if id in props.scene_props: + delattr(bpy.types.Scene, id) \ No newline at end of file diff --git a/scripts/blender/addons/mv/ops.py b/scripts/blender/addons/macrovision/ops.py similarity index 68% rename from scripts/blender/addons/mv/ops.py rename to scripts/blender/addons/macrovision/ops.py index 59335675..39d85c3f 100644 --- a/scripts/blender/addons/mv/ops.py +++ b/scripts/blender/addons/macrovision/ops.py @@ -1,20 +1,22 @@ import bpy + from mathutils import Vector, Euler, Color import json import pathlib import os from math import pi +import random VIEW_DATA = { - "Front": [0, 1, 2, "Front"], - "Angled": [0.25, 1, 2, "Angled"], - "Corner": [0.5, 1, 2, "Corner"], - "Side": [1, 1, 2, "Side"], - "Back Angled": [1.5, 1, 2, "Back Angled"], - "Back": [2, 1, 2, "Back"], - "Top": [0, 0, 1, "Top"], - "Bottom": [0, 2, 1, "Bottom"], - "Bottom Flipped": [2, 2, 1, "Bottom Flipped"], + "FRONT": [0, 1, 2, "Front"], + "ANGLED": [0.25, 1, 2, "Angled"], + "CORNER": [0.5, 1, 2, "Corner"], + "SIDE": [1, 1, 2, "Side"], + "BACK_ANGLED": [1.5, 1, 2, "Back Angled"], + "BACK": [2, 1, 2, "Back"], + "TOP": [0, 0, 1, "Top"], + "BOTTOM": [0, 2, 1, "Bottom"], + "BOTTOM_FLIPPED": [2, 2, 1, "Bottom Flipped"], } def get_bounds(objects): @@ -46,10 +48,6 @@ class MVConfigCollection(bpy.types.Operator): def execute(self, context: bpy.types.Context): coll = context.scene.collection.children[0] coll.name = "Macrovision" - coll["MVName"] = "Name" - coll["MVViews"] = "Front" - coll["MVKind"] = "objects" - coll["MVViewLabels"] = "Front: Front" mats = [ ("light", 0, 0, 1), @@ -109,18 +107,61 @@ class MVConfigCollection(bpy.types.Operator): bpy.ops.object.lineart_clear_all() - return {"FINISHED"} + return {'FINISHED'} + +class MVAssignMaterials(bpy.types.Operator): + bl_idname = "mv.assign_materials" + bl_label = "Assign Materials" + + def execute(self, context: bpy.types.Context): + mv = bpy.data.collections["Macrovision"] + collections = mv.children + + for coll in collections: + for object in coll.objects: + if object.type != "MESH": + continue + + for index in range(len(object.material_slots)): + if object.material_slots[index].material.name in ('light', 'medium', 'dark'): + continue + if context.scene.mv_material_mode == 'RANDOM': + choices = [ + bpy.data.materials['light'], + bpy.data.materials['medium'], + bpy.data.materials['dark'] + ] + + object.material_slots[index].material = random.choice(choices) + + if context.scene.mv_material_mode == 'NAMES': + material = object.material_slots[index].material + light_choices = context.scene.mv_material_names_light.split(",") + medium_choices = context.scene.mv_material_names_medium.split(",") + + chosen = None + for choice in light_choices: + if choice in material.name or choice in object.name: + chosen = bpy.data.materials['light'] + break + for choice in medium_choices: + if choice in material.name or choice in object.name: + chosen = bpy.data.materials['medium'] + break + + if chosen is None: + chosen = bpy.data.materials['dark'] + + object.material_slots[index].material = chosen + + return {'FINISHED'} class MVExport(bpy.types.Operator): bl_idname = "mv.export" bl_label = "Export objects" - @classmethod - def poll(cls, context: bpy.types.Context): - return True - def execute(self, context: bpy.types.Context): path_info = pathlib.Path(bpy.data.filepath).parent.joinpath("macrovision-directory.txt") config_path = pathlib.Path(open(path_info).read().strip()) @@ -150,20 +191,21 @@ class MVExport(bpy.types.Operator): all_data = {} - all_data["name"] = mv["MVName"] - all_data["kind"] = mv["MVKind"] + all_data["name"] = context.scene.mv_name + all_data["kind"] = context.scene.mv_kind all_data["forms"] = [] default_views = [] - for view in mv["MVViews"].split(","): - default_views.append(VIEW_DATA[view.strip()]) - - if "MVViewLabels" in mv: - for pair in mv["MVViewLabels"].split(","): - key, val = pair.split(":") - VIEW_DATA[key.strip()][3] = val.strip() - + for view in context.scene.mv_views: + key = view.view + default_views.append([ + VIEW_DATA[key][0], + VIEW_DATA[key][1], + VIEW_DATA[key][2], + view.name if view.name != "" else VIEW_DATA[key][3] + ]) + print(default_views) workdir = pathlib.Path(parent_workdir).joinpath(all_data["name"]) @@ -212,15 +254,19 @@ class MVExport(bpy.types.Operator): c.location += Vector([0, 0, size * 2]) @ rot c.data.clip_start = size / 4 c.data.clip_end = size * 8 + + scale_factor = (10 ** context.scene.mv_scale_factor) + + height = dimensions[angles[2]] * scale_factor data["views"].append({ "name": angles[3], - "height": dimensions[angles[2]] + "height": height }) if "Volume" in coll: - data["views"][-1]["volume"] = coll["Volume"] + data["views"][-1]["volume"] = coll["Volume"] * (scale_factor ** 3) if "Mass" in coll: - data["views"][-1]["mass"] = coll["Mass"] + data["views"][-1]["mass"] = coll["Mass"] * (scale_factor ** 3) lineart.hide_render = False filename = f"{coll.name}-{angles[3]}.png" @@ -237,9 +283,10 @@ class MVExport(bpy.types.Operator): with open(workdir.joinpath("data.json"), "w") as file: json.dump(all_data, file) - return {"FINISHED"} + return {'FINISHED'} clses = [ MVExport, + MVAssignMaterials, MVConfigCollection ] \ No newline at end of file diff --git a/scripts/blender/addons/macrovision/props.py b/scripts/blender/addons/macrovision/props.py new file mode 100644 index 00000000..10d636cc --- /dev/null +++ b/scripts/blender/addons/macrovision/props.py @@ -0,0 +1,77 @@ +import bpy + +scene_props = {} + +scene_props["mv_name"] = bpy.props.StringProperty( + name = "Name", + description = "The name of the thing", + default = "" +) + +scene_props["mv_kind"] = bpy.props.StringProperty( + name = "Kind", + description = "What category the entity belongs to", + default = "objects" +) + +class MVView(bpy.types.PropertyGroup): + view: bpy.props.EnumProperty( + name = "View", + description = "The angle to view from", + items = ( + ("FRONT", "Front", ""), + ("ANGLED", "Angled", ""), + ("CORNER", "Corner", ""), + ("SIDE", "Side", ""), + ("BACK", "Back", ""), + ("TOP", "Top", ""), + ("BOTTOM", "Bottom", "") + ) + ) + name: bpy.props.StringProperty(name = "Name", description="What to call this view") + +scene_props["mv_views"] = bpy.props.CollectionProperty( + name = "Views", + description = "The views to view the object from", + type = MVView +) + +scene_props["mv_views_index"] = bpy.props.IntProperty( + name = "Views index", + description = "View list index" +) + +scene_props["mv_scale_factor"] = bpy.props.IntProperty( + name = "Scale Factor", + description = "Scale lengths by 10^x", + min = -20, + max = 20, + soft_min = -20, + soft_max = 20, + default = 5 +) + +scene_props["mv_material_mode"] = bpy.props.EnumProperty( + name = "Material Mode", + description = "How to decide what to replace each material with", + items = ( + ('RANDOM', "Random", 'Randomly assign materials'), + ('NAMES', "Names", 'Turn the specified names medium or light; the rest become dark') + ), +) + +scene_props["mv_material_names_light"] = bpy.props.StringProperty( + name = "Light Colors", + description = "Materials containing these words will become light", + default = "" +) + +scene_props["mv_material_names_medium"] = bpy.props.StringProperty( + name = "Medium Colors", + description = "Materials containing these words will become medium", + default = "" +) + +clses = [ + MVView +] \ No newline at end of file diff --git a/scripts/blender/addons/macrovision/ui.py b/scripts/blender/addons/macrovision/ui.py new file mode 100644 index 00000000..f7d75464 --- /dev/null +++ b/scripts/blender/addons/macrovision/ui.py @@ -0,0 +1,92 @@ +from macrovision import ops + +import bpy + +class MV_UL_ViewList(bpy.types.UIList): + def draw_item(self, context, layout: bpy.types.UILayout, data, item, icon, active_data, active_propname, index): + if self.layout_type in {'DEFAULT', 'COMPACT'}: + layout.prop(item, "view", text="") + layout.prop(item, "name", text="") + elif self.layout_type in {'GRID'}: + layout.alignment = 'CENTER' + layout.label(text='', icon = 'OBJECT_DATAMODE') + +class MV_Views_List_Add(bpy.types.Operator): + bl_idname = "mv.views_list_add" + bl_label = "Add view" + + def execute(self, context: bpy.types.Context): + context.scene.mv_views.add() + return {'FINISHED'} + +class MV_Views_List_Delete(bpy.types.Operator): + bl_idname = "mv.views_list_delete" + bl_label = "Delete view" + + @classmethod + def poll(self, context: bpy.types.Context): + return context.scene.mv_views + + def execute(self, context: bpy.types.Context): + lst = context.scene.mv_views + index = context.scene.mv_views_index + + lst.remove(index) + + index = max(0, index - 1) + index = min(index, len(lst) - 1) + + context.scene.mv_views_index = index + return {'FINISHED'} +class MVPanel(bpy.types.Panel): + bl_idname="OBJECT_PT_MV_menu" + bl_label="Macrovision" + bl_space_type="VIEW_3D" + bl_region_type="UI" + bl_category = "Macrovision" + + @classmethod + def poll(cls, context): + return True + + def draw(self, context): + layout = self.layout + + box = layout.box() + box.label(text="Setup") + + op_props = box.operator("mv.config_collection") + op_props = box.operator("mv.assign_materials") + + box.prop(context.scene, "mv_material_mode") + + if context.scene.mv_material_mode == "NAMES": + box.prop(context.scene, "mv_material_names_light") + box.prop(context.scene, "mv_material_names_medium") + + box = layout.box() + box.label(text="Execute") + + op_props = box.operator("mv.export") + + box.prop(context.scene, "mv_name") + box.prop(context.scene, "mv_kind") + box.template_list( + "MV_UL_ViewList", + "Views", + context.scene, + "mv_views", + context.scene, + "mv_views_index" + ) + row = box.row() + + row.operator("mv.views_list_add", text="+") + row.operator("mv.views_list_delete", text="-") + box.prop(context.scene, 'mv_scale_factor') +clses = [ + MV_UL_ViewList, + MV_Views_List_Add, + MV_Views_List_Delete, + MVPanel +] diff --git a/scripts/blender/addons/mv/__init__.py b/scripts/blender/addons/mv/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/scripts/blender/addons/mv/ui.py b/scripts/blender/addons/mv/ui.py deleted file mode 100644 index 54f8a67c..00000000 --- a/scripts/blender/addons/mv/ui.py +++ /dev/null @@ -1,31 +0,0 @@ -import mv.ops - -import bpy - -class MVPanel(bpy.types.Panel): - bl_idname="OBJECT_PT_MV_menu" - bl_label="Macrovision" - bl_space_type="VIEW_3D" - bl_region_type="UI" - bl_category = "Macrovision" - - @classmethod - def poll(cls, context): - return True - - def draw(self, context): - layout = self.layout - - box = layout.box() - box.label(text="Setup") - - box.operator("mv.config_collection") - - box = layout.box() - box.label(text="Execute") - - box.operator("mv.export") - -clses = [ - MVPanel -]