Skip to content
Snippets Groups Projects
object_mesh_versions.py 7.56 KiB
Newer Older
  • Learn to ignore specific revisions
  • # ##### BEGIN GPL LICENSE BLOCK #####
    #
    #  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.
    #
    # ##### END GPL LICENSE BLOCK #####
    
    
    import bpy
    import time
    from datetime import datetime
    from bpy.types import Menu, Panel
    from bpy.props import StringProperty, BoolProperty
    
    
    
    bl_info = {
        "name": "KTX Mesh Versions",
    
        "description": "Keep multiple mesh versions of an object",
    
        "author": "Roel Koster, @koelooptiemanna, irc:kostex",
    
        "version": (1, 5, 3),
    
        "blender": (2, 80, 0),
    
        "location": "View3D > Properties",
    
        "warning": "",
    
        "doc_url": "https://github.com/kostex/blenderscripts/",
    
        "tracker_url": "https://developer.blender.org/maniphest/task/edit/form/2/",
    
        "category": "Object"}
    
    
    
    class KTXMESHVERSIONS_OT_Init(bpy.types.Operator):
    
        bl_label = "Initialise Mesh Versioning"
    
        bl_idname = "ktxmeshversions.init"
    
        bl_description = "Initialise the current object to support versioning"
    
    
        def execute(self, context):
    
            unique_id = str(time.time())
            context.object.data.ktx_mesh_id = context.object.ktx_object_id = unique_id
    
            return {'FINISHED'}
    
    
    class KTXMESHVERSIONS_OT_Select(bpy.types.Operator):
    
        bl_label = "Select Mesh"
    
        bl_idname = "ktxmeshversions.select"
    
        bl_description = "Link the selected mesh to the current object"
    
        m_index : StringProperty()
    
        def execute(self, context):
    
            c_mode = bpy.context.object.mode
    
            if c_mode != 'OBJECT':
                bpy.ops.object.mode_set(mode='OBJECT')
            obj = context.object
            obj.data = bpy.data.meshes[self.m_index]
            bpy.ops.object.mode_set(mode=c_mode)
            return {'FINISHED'}
    
    
    class KTXMESHVERSIONS_OT_Remove(bpy.types.Operator):
    
        bl_label = "Remove Mesh"
    
        bl_idname = "ktxmeshversions.remove"
    
        bl_description = "Remove/Delete the selected mesh"
    
        m_index : StringProperty()
    
        def execute(self, context):
            bpy.data.meshes.remove(bpy.data.meshes[self.m_index])
            return {'FINISHED'}
    
    
    class KTXMESHVERSIONS_OT_Cleanup(bpy.types.Operator):
    
        bl_label = "Cleanup Mode"
    
        bl_idname = "ktxmeshversions.cleanup"
    
        bl_description = "Cleanup Mode"
    
        def execute(self, context):
            for o in bpy.data.objects:
    
                o.select = False
            context.scene.objects.active = None
    
    class KTXMESHVERSIONS_OT_Create(bpy.types.Operator):
    
        bl_label = "Create Mesh Version"
    
        bl_idname = "ktxmeshversions.create"
    
        bl_description = ("Create a copy of the mesh data of the current object\n"
                          "and set it as active")
    
        def execute(self, context):
            defpin = bpy.context.scene.ktx_defpin
            obj = context.object
    
            if obj.type == 'MESH':
                c_mode = bpy.context.object.mode
                me = obj.data
    
                if c_mode != 'OBJECT':
                    bpy.ops.object.mode_set(mode='OBJECT')
    
                new_mesh = me.copy()
                obj.data = new_mesh
                obj.data.use_fake_user = defpin
    
                bpy.ops.object.mode_set(mode=c_mode)
            return {'FINISHED'}
    
    
    class KTXMESHVERSIONS_PT_mainPanel(bpy.types.Panel):
    
        bl_label = "KTX Mesh Versions"
    
        bl_idname = "KTXMESHVERSIONS_PT_mainPanel"
    
        bl_space_type = 'VIEW_3D'
        bl_region_type = 'UI'
    
        bl_category = 'Edit'
        bl_options = {'DEFAULT_CLOSED'}
    
    
        def draw(self, context):
            scene = context.scene
            obj = context.object
            layout = self.layout
    
    
            meshes_exist = bool(bpy.data.meshes.items() != [])
            if meshes_exist:
                if obj != None:
                    if obj.type == 'MESH':
                        if obj.ktx_object_id != '' and (obj.data.ktx_mesh_id == obj.ktx_object_id):
                            icon = 'PINNED' if scene.ktx_defpin else 'UNPINNED'
                            row = layout.row(align=True)
                            row.prop(scene, "ktx_defpin", text="", icon=icon)
    
                            row.operator("ktxmeshversions.create")
    
                            box = layout.box()
    
                            box.label(text="Currently active mesh: " + obj.data.name)
    
                            for m in bpy.data.meshes:
                                if m.ktx_mesh_id == obj.ktx_object_id:
                                    mesh_name = m.name
                                    row = box.row(align=True)
    
                                    row.operator("ktxmeshversions.select", text="", icon='RIGHTARROW').m_index = mesh_name
    
                                    row.prop(m, "name", text="", icon='MESH_DATA')
                                    if m.users == 0:
    
                                        row.operator("ktxmeshversions.remove", text="", icon="X").m_index = mesh_name
    
                                    icon = 'PINNED' if m.use_fake_user else 'UNPINNED'
                                    row.prop(m, "use_fake_user", text="", icon=icon)
    
                            row = layout.row(align=True)
    
                            row.operator("ktxmeshversions.cleanup", text="Cleanup Mode")
    
                            layout.operator("ktxmeshversions.init")
    
                        layout.label(text="Select a Mesh Object")
    
                        layout.operator("ktxmeshversions.cleanup", text="Cleanup Mode")
    
                    layout.label(text="All Meshes (Cleanup/Pin):")
    
                    box = layout.box()
    
                    for m in bpy.data.meshes:
                        mesh_name = m.name
                        row = box.row(align=True)
                        row.prop(m, "name", text="", icon='MESH_DATA')
                        if m.users == 0:
    
                            row.operator("ktxmeshversions.remove", text="", icon="X").m_index = mesh_name
    
                        icon = 'PINNED' if m.use_fake_user else 'UNPINNED'
                        row.prop(m, "use_fake_user", text="", icon=icon)
    
                layout.label(text="No Meshes Exist")
    
    classes = (
    
        KTXMESHVERSIONS_PT_mainPanel,
        KTXMESHVERSIONS_OT_Init,
        KTXMESHVERSIONS_OT_Create,
        KTXMESHVERSIONS_OT_Remove,
        KTXMESHVERSIONS_OT_Select,
        KTXMESHVERSIONS_OT_Cleanup
    
    def register():
    
        from bpy.utils import register_class
    
        bpy.types.Object.ktx_object_id = bpy.props.StringProperty(name="KTX Object ID", description="Unique ID to 'link' one object to multiple meshes")
        bpy.types.Mesh.ktx_mesh_id = bpy.props.StringProperty(name="KTX Mesh ID", description="Unique ID to 'link' multiple meshes to one object")
        bpy.types.Scene.ktx_defpin = bpy.props.BoolProperty(name="Auto Pinning", description="When creating a new version, set pinning to ON automatically (FAKE_USER=TRUE)", default=False)
    
    
        for cls in classes:
            register_class(cls)
    
        from bpy.utils import unregister_class
    
    
        del bpy.types.Mesh.ktx_mesh_id
        del bpy.types.Object.ktx_object_id
    
        del bpy.types.Scene.ktx_defpin
    
    
        for cls in classes:
            unregister_class(cls)
    
    
    if __name__ == "__main__":
        register()