Welcome to mirror list, hosted at ThFree Co, Russian Federation.

dupli_group_id.py « misc « amaranth - git.blender.org/blender-addons.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 05fa712961a9a002ec5d8f9e46046ef3f3d1d067 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
#  This program is free software; you can redistribute it and/or
#  modify it under the terms of the GNU General Public License
#  as published by the Free Software Foundation; either version 2
#  of the License, or (at your option) any later version.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with this program; if not, write to the Free Software Foundation,
#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
"""
Object ID for Dupli Groups
Say you have a linked character or asset, you can now set an Object ID for the
entire instance (the objects in the group), and use it with the Object Index
pass later in compositing. Something that I always wanted and it wasn't
possible!

In order for the Object ID to be loaded afterwards on computers without
Amaranth installed, it will automatically create a text file (called
AmaranthStartup.py) and save it inside the .blend, this will autorun on
startup and set the OB IDs. Remember to have auto-run python scripts on your
startup preferences.

Set a Pass Index and press "Apply Object ID to Duplis" on the Relations panel,
Object Properties.
"""


import bpy
from amaranth.scene.debug import AMTH_SCENE_OT_blender_instance_open


# Some settings are bound to be saved on a startup py file
# TODO: refactor this, amth_text should not be declared as a global variable,
#       otherwise becomes confusing when you call it in the classes below.
def amaranth_text_startup(context):

    amth_text_name = "AmaranthStartup.py"
    amth_text_exists = False

    global amth_text

    try:
        if bpy.data.texts:
            for tx in bpy.data.texts:
                if tx.name == amth_text_name:
                    amth_text_exists = True
                    amth_text = bpy.data.texts[amth_text_name]
                    break
                else:
                    amth_text_exists = False

        if not amth_text_exists:
            bpy.ops.text.new()
            amth_text = bpy.data.texts[((len(bpy.data.texts) * -1) + 1)]
            amth_text.name = amth_text_name
            amth_text.write("# Amaranth Startup Script\nimport bpy\n")
            amth_text.use_module = True

        return amth_text_exists
    except AttributeError:
        return None


# FEATURE: Dupli  Group Path
def ui_dupli_group_library_path(self, context):

    ob = context.object

    row = self.layout.row()
    row.alignment = "LEFT"

    if ob and ob.instance_collection and ob.instance_collection.library:
        lib = ob.instance_collection.library.filepath

        row.operator(AMTH_SCENE_OT_blender_instance_open.bl_idname,
                     text="Library: %s" % lib,
                     emboss=False,
                     icon="LINK_BLEND").filepath = lib
# // FEATURE: Dupli  Group Path


# FEATURE: Object ID for objects inside DupliGroups
class AMTH_OBJECT_OT_id_dupligroup(bpy.types.Operator):

    """Set the Object ID for objects in the dupli group"""
    bl_idname = "object.amaranth_object_id_duplis"
    bl_label = "Apply Object ID to Duplis"

    clear = False

    @classmethod
    def poll(cls, context):
        return context.active_object.instance_collection

    def execute(self, context):
        self.__class__.clear = False
        ob = context.active_object
        amaranth_text_startup(context)
        script_exists = False
        script_intro = "# OB ID: %s" % ob.name
        obdata = 'bpy.data.objects[" % s"]' % ob.name
        # TODO: cleanup script var using format or template strings
        script = "%s" % (
            "\nif %(obdata)s and %(obdata)s.instance_collection and %(obdata)s.pass_index != 0: %(obname)s \n"
            "    for dob in %(obdata)s.instance_collection.objects: %(obname)s \n"
            "        dob.pass_index = %(obdata)s.pass_index %(obname)s \n" %
            {"obdata": obdata, "obname": script_intro})

        for txt in bpy.data.texts:
            if txt.name == amth_text.name:
                for li in txt.lines:
                    if script_intro == li.body:
                        script_exists = True
                        continue

        if not script_exists:
            amth_text.write("\n")
            amth_text.write(script_intro)
            amth_text.write(script)

        if ob and ob.instance_collection:
            if ob.pass_index != 0:
                for dob in ob.instance_collection.objects:
                    dob.pass_index = ob.pass_index

        self.report({"INFO"},
                    "%s ID: %s to all objects in this Dupli Group" % (
                        "Applied" if not script_exists else "Updated",
                        ob.pass_index))

        return {"FINISHED"}


class AMTH_OBJECT_OT_id_dupligroup_clear(bpy.types.Operator):

    """Clear the Object ID from objects in dupli group"""
    bl_idname = "object.amaranth_object_id_duplis_clear"
    bl_label = "Clear Object ID from Duplis"

    @classmethod
    def poll(cls, context):
        return context.active_object.instance_collection

    def execute(self, context):
        context.active_object.pass_index = 0
        AMTH_OBJECT_OT_id_dupligroup.clear = True
        amth_text_exists = amaranth_text_startup(context)
        match_first = "# OB ID: %s" % context.active_object.name

        if amth_text_exists:
            for txt in bpy.data.texts:
                if txt.name == amth_text.name:
                    for li in txt.lines:
                        if match_first in li.body:
                            li.body = ""
                            continue

        self.report({"INFO"}, "Object IDs back to normal")
        return {"FINISHED"}


def ui_object_id_duplis(self, context):

    if context.active_object.instance_collection:
        split = self.layout.split()
        row = split.row(align=True)
        row.enabled = context.active_object.pass_index != 0
        row.operator(
            AMTH_OBJECT_OT_id_dupligroup.bl_idname)
        row.operator(
            AMTH_OBJECT_OT_id_dupligroup_clear.bl_idname,
            icon="X", text="")
        split.separator()

        if AMTH_OBJECT_OT_id_dupligroup.clear:
            self.layout.label(text="Next time you save/reload this file, "
                              "object IDs will be back to normal",
                              icon="INFO")
# // FEATURE: Object ID for objects inside DupliGroups


def register():
    bpy.utils.register_class(AMTH_OBJECT_OT_id_dupligroup)
    bpy.utils.register_class(AMTH_OBJECT_OT_id_dupligroup_clear)
    bpy.types.OBJECT_PT_instancing.append(ui_dupli_group_library_path)
    bpy.types.OBJECT_PT_relations.append(ui_object_id_duplis)


def unregister():
    bpy.utils.unregister_class(AMTH_OBJECT_OT_id_dupligroup)
    bpy.utils.unregister_class(AMTH_OBJECT_OT_id_dupligroup_clear)
    bpy.types.OBJECT_PT_instancing.remove(ui_dupli_group_library_path)
    bpy.types.OBJECT_PT_relations.remove(ui_object_id_duplis)