1 # ##### BEGIN GPL LICENSE BLOCK #####
3 # This program is free software; you can redistribute it and/or
4 # modify it under the terms of the GNU General Public License
5 # as published by the Free Software Foundation; either version 2
6 # of the License, or (at your option) any later version.
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU General Public License for more details.
13 # You should have received a copy of the GNU General Public License
14 # along with this program; if not, write to the Free Software Foundation,
15 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 # ##### END GPL LICENSE BLOCK #####
21 from datetime
import datetime
22 from bpy
.types
import Menu
, Panel
23 from bpy
.props
import StringProperty
, BoolProperty
27 "name": "KTX Mesh Versions",
28 "description": "Keep multiple mesh versions of an object",
29 "author": "Roel Koster, @koelooptiemanna, irc:kostex",
31 "blender": (2, 80, 0),
32 "location": "View3D > Properties",
34 "doc_url": "https://github.com/kostex/blenderscripts/",
35 "tracker_url": "https://developer.blender.org/maniphest/task/edit/form/2/",
39 class KTXMESHVERSIONS_OT_Init(bpy
.types
.Operator
):
40 bl_label
= "Initialise Mesh Versioning"
41 bl_idname
= "ktxmeshversions.init"
42 bl_description
= "Initialise the current object to support versioning"
44 def execute(self
, context
):
45 unique_id
= str(time
.time())
46 context
.object.data
.ktx_mesh_id
= context
.object.ktx_object_id
= unique_id
50 class KTXMESHVERSIONS_OT_Select(bpy
.types
.Operator
):
51 bl_label
= "Select Mesh"
52 bl_idname
= "ktxmeshversions.select"
53 bl_description
= "Link the selected mesh to the current object"
55 m_index
: StringProperty()
57 def execute(self
, context
):
58 c_mode
= bpy
.context
.object.mode
59 if c_mode
!= 'OBJECT':
60 bpy
.ops
.object.mode_set(mode
='OBJECT')
62 obj
.data
= bpy
.data
.meshes
[self
.m_index
]
63 bpy
.ops
.object.mode_set(mode
=c_mode
)
67 class KTXMESHVERSIONS_OT_Remove(bpy
.types
.Operator
):
68 bl_label
= "Remove Mesh"
69 bl_idname
= "ktxmeshversions.remove"
70 bl_description
= "Remove/Delete the selected mesh"
72 m_index
: StringProperty()
74 def execute(self
, context
):
75 bpy
.data
.meshes
.remove(bpy
.data
.meshes
[self
.m_index
])
79 class KTXMESHVERSIONS_OT_Cleanup(bpy
.types
.Operator
):
80 bl_label
= "Cleanup Mode"
81 bl_idname
= "ktxmeshversions.cleanup"
82 bl_description
= "Cleanup Mode"
84 def execute(self
, context
):
85 for o
in bpy
.data
.objects
:
87 context
.scene
.objects
.active
= None
91 class KTXMESHVERSIONS_OT_Create(bpy
.types
.Operator
):
92 bl_label
= "Create Mesh Version"
93 bl_idname
= "ktxmeshversions.create"
94 bl_description
= ("Create a copy of the mesh data of the current object\n"
95 "and set it as active")
97 def execute(self
, context
):
98 defpin
= bpy
.context
.scene
.ktx_defpin
100 if obj
.type == 'MESH':
101 c_mode
= bpy
.context
.object.mode
103 if c_mode
!= 'OBJECT':
104 bpy
.ops
.object.mode_set(mode
='OBJECT')
107 obj
.data
.use_fake_user
= defpin
108 bpy
.ops
.object.mode_set(mode
=c_mode
)
112 class KTXMESHVERSIONS_PT_mainPanel(bpy
.types
.Panel
):
113 bl_label
= "KTX Mesh Versions"
114 bl_idname
= "KTXMESHVERSIONS_PT_mainPanel"
115 bl_space_type
= 'VIEW_3D'
116 bl_region_type
= 'UI'
118 bl_options
= {'DEFAULT_CLOSED'}
120 def draw(self
, context
):
121 scene
= context
.scene
125 meshes_exist
= bool(bpy
.data
.meshes
.items() != [])
128 if obj
.type == 'MESH':
129 if obj
.ktx_object_id
!= '' and (obj
.data
.ktx_mesh_id
== obj
.ktx_object_id
):
130 icon
= 'PINNED' if scene
.ktx_defpin
else 'UNPINNED'
131 row
= layout
.row(align
=True)
132 row
.prop(scene
, "ktx_defpin", text
="", icon
=icon
)
133 row
.operator("ktxmeshversions.create")
136 box
.label(text
="Currently active mesh: " + obj
.data
.name
)
137 for m
in bpy
.data
.meshes
:
138 if m
.ktx_mesh_id
== obj
.ktx_object_id
:
140 row
= box
.row(align
=True)
141 row
.operator("ktxmeshversions.select", text
="", icon
='RIGHTARROW').m_index
= mesh_name
142 row
.prop(m
, "name", text
="", icon
='MESH_DATA')
144 row
.operator("ktxmeshversions.remove", text
="", icon
="X").m_index
= mesh_name
145 icon
= 'PINNED' if m
.use_fake_user
else 'UNPINNED'
146 row
.prop(m
, "use_fake_user", text
="", icon
=icon
)
148 row
= layout
.row(align
=True)
149 row
.operator("ktxmeshversions.cleanup", text
="Cleanup Mode")
151 layout
.operator("ktxmeshversions.init")
153 layout
.label(text
="Select a Mesh Object")
154 layout
.operator("ktxmeshversions.cleanup", text
="Cleanup Mode")
157 layout
.label(text
="All Meshes (Cleanup/Pin):")
160 for m
in bpy
.data
.meshes
:
162 row
= box
.row(align
=True)
163 row
.prop(m
, "name", text
="", icon
='MESH_DATA')
165 row
.operator("ktxmeshversions.remove", text
="", icon
="X").m_index
= mesh_name
166 icon
= 'PINNED' if m
.use_fake_user
else 'UNPINNED'
167 row
.prop(m
, "use_fake_user", text
="", icon
=icon
)
170 layout
.label(text
="No Meshes Exist")
174 KTXMESHVERSIONS_PT_mainPanel
,
175 KTXMESHVERSIONS_OT_Init
,
176 KTXMESHVERSIONS_OT_Create
,
177 KTXMESHVERSIONS_OT_Remove
,
178 KTXMESHVERSIONS_OT_Select
,
179 KTXMESHVERSIONS_OT_Cleanup
184 from bpy
.utils
import register_class
186 bpy
.types
.Object
.ktx_object_id
= bpy
.props
.StringProperty(name
="KTX Object ID", description
="Unique ID to 'link' one object to multiple meshes")
187 bpy
.types
.Mesh
.ktx_mesh_id
= bpy
.props
.StringProperty(name
="KTX Mesh ID", description
="Unique ID to 'link' multiple meshes to one object")
188 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)
195 from bpy
.utils
import unregister_class
197 del bpy
.types
.Mesh
.ktx_mesh_id
198 del bpy
.types
.Object
.ktx_object_id
199 del bpy
.types
.Scene
.ktx_defpin
202 unregister_class(cls
)
205 if __name__
== "__main__":