207 lines
7.6 KiB
Python
207 lines
7.6 KiB
Python
# ##### 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
|
|
return {'FINISHED'}
|
|
|
|
|
|
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.scale_y = 1.0
|
|
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)
|
|
box.label(text="")
|
|
row = layout.row(align=True)
|
|
row.operator("ktxmeshversions.cleanup", text="Cleanup Mode")
|
|
else:
|
|
layout.operator("ktxmeshversions.init")
|
|
else:
|
|
layout.label(text="Select a Mesh Object")
|
|
layout.operator("ktxmeshversions.cleanup", text="Cleanup Mode")
|
|
|
|
else:
|
|
layout.label(text="All Meshes (Cleanup/Pin):")
|
|
box = layout.box()
|
|
box.scale_y = 1.0
|
|
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)
|
|
box.label(text="")
|
|
else:
|
|
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)
|
|
|
|
|
|
def unregister():
|
|
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()
|