Newer
Older
bl_info = {
"name": "Mesh Cache Tools",
"author": "Oscurart",
"version": (1, 0, 1),
"blender": (2, 70, 0),
"location": "Tools > Mesh Cache Tools",
"description": "Tools for Management Mesh Cache Process",
"warning": "",
"wiki_url": "",
"tracker_url": "https://developer.blender.org/maniphest/task/edit/form/2/",
"category": "Import-Export"}
import bpy
import os
import struct
from bpy_extras.io_utils import ImportHelper
from bpy.types import (
Operator,
Panel,
PropertyGroup,
AddonPreferences,
)
from bpy.props import (
BoolProperty,
IntProperty,
StringProperty,
PointerProperty,
CollectionProperty,
)
class OscurartMeshCacheModifiersSettings(PropertyGroup):
array: BoolProperty(default=True)
bevel: BoolProperty(default=True)
boolean: BoolProperty(default=True)
build: BoolProperty(default=True)
decimate: BoolProperty(default=True)
edge_split: BoolProperty(default=True)
mask: BoolProperty(default=True)
mirror: BoolProperty(default=True)
multires: BoolProperty(default=True)
remesh: BoolProperty(default=True)
screw: BoolProperty(default=True)
skin: BoolProperty(default=True)
solidify: BoolProperty(default=True)
subsurf: BoolProperty(default=True)
triangulate: BoolProperty(default=True)
wireframe: BoolProperty(default=True)
cloth: BoolProperty(default=True)
# bpy.context.scene.pc_auto_load_proxy.remove(0)
class CreaPropiedades(Operator):
bl_idname = "scene.pc_auto_load_proxy_create"
bl_label = "Create Auto Load PC Proxy List"
def execute(self, context):
for gr in bpy.data.collections:
if gr.library is not None:
i = bpy.context.scene.pc_auto_load_proxy.add()
i.name = gr.name
class RemuevePropiedades(Operator):
bl_idname = "scene.pc_auto_load_proxy_remove"
bl_label = "Remove Auto Load PC Proxy List"
def execute(self, context):
for i in bpy.context.scene.pc_auto_load_proxy:
return {'FINISHED'}
class OscurartMeshCacheSceneAutoLoad(PropertyGroup):
name="GroupName",
default=""
)
use_auto_load: BoolProperty(
name="Bool",
default=False
)
@persistent
def CargaAutoLoadPC(dummy):
for gr in bpy.context.scene.pc_auto_load_proxy:
if gr.use_auto_load:
for ob in bpy.data.collections[gr.name].objects:
if MOD.type == "MESH_CACHE":
MOD.cache_format = "PC2"
MOD.forward_axis = "POS_Y"
MOD.up_axis = "POS_Z"
MOD.flip_axis = set(())
MOD.frame_start = bpy.context.scene.pc_pc2_start
abspath = os.path.abspath(bpy.path.abspath("//" + bpy.context.scene.pc_pc2_folder))
MOD.filepath = "%s/%s.pc2" % (abspath, ob.name)
bpy.app.handlers.load_post.append(CargaAutoLoadPC)
class View3DMCPanel():
bl_space_type = 'VIEW_3D'
bl_region_type = 'TOOLS'
class OscEPc2ExporterPanel(View3DMCPanel, Panel):
scene = context.scene
row.prop(scene, "pc_pc2_folder", text="Folder")
row.operator("buttons.set_meshcache_folder", icon='FILEBROWSER', text="Select Folder Path")
row.label(text="EXPORTER:")
row.operator("group.linked_group_to_local", text="Linked To Local", icon="LINKED")
row.operator("object.remove_subsurf_modifier", text="Remove Gen Modifiers", icon="MOD_SUBSURF")
row.prop(scene.mesh_cache_tools_settings, "array", text="Array")
row.prop(scene.mesh_cache_tools_settings, "bevel", text="Bevel")
row.prop(scene.mesh_cache_tools_settings, "boolean", text="Boolean")
row.prop(scene.mesh_cache_tools_settings, "build", text="Build")
row.prop(scene.mesh_cache_tools_settings, "decimate", text="Decimate")
row.prop(scene.mesh_cache_tools_settings, "edge_split", text="Edge Split")
row.prop(scene.mesh_cache_tools_settings, "mask", text="Mask")
row.prop(scene.mesh_cache_tools_settings, "mirror", text="Mirror")
row.prop(scene.mesh_cache_tools_settings, "multires", text="Multires")
row.prop(scene.mesh_cache_tools_settings, "remesh", text="Remesh")
row.prop(scene.mesh_cache_tools_settings, "screw", text="Screw")
row.prop(scene.mesh_cache_tools_settings, "skin", text="Skin")
row.prop(scene.mesh_cache_tools_settings, "solidify", text="Solidify")
row.prop(scene.mesh_cache_tools_settings, "subsurf", text="Subsurf")
row.prop(scene.mesh_cache_tools_settings, "triangulate", text="Triangulate")
row.prop(scene.mesh_cache_tools_settings, "wireframe", text="Wireframe")
# row = layout.column(align=1)
row.prop(scene, "pc_pc2_start", text="Frame Start")
row.prop(scene, "pc_pc2_end", text="Frame End")
row.prop(scene, "pc_pc2_exclude", text="Exclude Token:")
row.prop_search(scene, "pc_pc2_group", bpy.data, "collections", text="")
row.operator("export_shape.pc2_selection", text="Export!", icon="POSE_DATA")
row.prop(scene, "pc_pc2_world_space", text="World Space")
row.label(text="IMPORTER:")
row.operator("import_shape.pc2_selection", text="Import", icon="POSE_DATA")
row.operator("object.modifier_mesh_cache_up", text="MC Top", icon="TRIA_UP")
row = layout.box().column(align=1)
row.label(text="PROXY AUTO LOAD:")
row.operator("scene.pc_auto_load_proxy_create", text="Create List", icon="GROUP")
row.operator("scene.pc_auto_load_proxy_remove", text="Remove List", icon="X")
for i in scene.pc_auto_load_proxy:
if bpy.data.collections[i.name].library is not None:
row.prop(bpy.data.collections[i.name], "name", text="")
row.prop(i, "use_auto_load", text="")
def OscSetFolder(self, context, filepath):
fp = filepath if os.path.isdir(filepath) else os.path.dirname(filepath)
try:
except Exception as e:
self.report({'WARNING'}, "Folder could not be set: {}".format(e))
return {'CANCELLED'}
return {'FINISHED'}
class OscMeshCacheButtonSet(Operator, ImportHelper):
bl_idname = "buttons.set_meshcache_folder"
bl_label = "Set Mesh Cache Folder"
filename_ext = ".txt"
def execute(self, context):
return OscSetFolder(self, context, self.filepath)
def OscFuncExportPc2(self):
start = bpy.context.scene.pc_pc2_start
end = bpy.context.scene.pc_pc2_end
folderpath = bpy.context.scene.pc_pc2_folder
framerange = end - start
for ob in bpy.data.collections[bpy.context.scene.pc_pc2_group].objects[:]:
if any(token not in ob.name for token in bpy.context.scene.pc_pc2_exclude.split(",")):
bpy.context.window_manager.progress_begin(0, 100) # progressbar
if ob.type == "MESH":
with open("%s/%s.pc2" % (os.path.normpath(folderpath), ob.name), mode="wb") as file:
headerFormat = '<12siiffi'
headerStr = struct.pack(headerFormat,
b'POINTCACHE2\0', 1, len(ob.data.vertices[:]), 0, 1.0, (end + 1) - start)
file.write(headerStr)
for i, frame in enumerate(range(start, end + 1)):
print("Percentage of %s bake: %s " % (ob.name, i * 100 / framerange))
bpy.context.window_manager.progress_update(i * 100 / framerange) # progressbarUpdate
bpy.context.scene.frame_set(frame)
me = bpy.data.meshes.new_from_object(
scene=bpy.context.scene,
object=ob,
apply_modifiers=True,
settings="RENDER",
calc_tessface=True,
calc_undeformed=False
)
# rotate
if bpy.context.scene.pc_pc2_world_space:
me.transform(obmat)
me.calc_normals()
file.write(struct.pack("<3f", *vert.co))
# drain mesh
bpy.data.meshes.remove(me)
print("%s Bake finished!" % (ob.name))
bpy.context.window_manager.progress_end() # progressBarClose
class OscPc2ExporterBatch(Operator):
bl_idname = "export_shape.pc2_selection"
bl_label = "Export pc2 for selected Objects"
bl_description = "Export pc2 for selected Objects"
bl_options = {'REGISTER', 'UNDO'}
@classmethod
def poll(cls, context):
return(bpy.context.scene.pc_pc2_group != "" and bpy.context.scene.pc_pc2_folder != 'Set me Please!')
def execute(self, context):
OscFuncExportPc2(self)
return {'FINISHED'}
class OscRemoveSubsurf(Operator):
bl_label = "Remove Subdivision Surface Modifier"
bl_description = "Remove Subdivision Surface Modifier"
bl_options = {'REGISTER', 'UNDO'}
@classmethod
def poll(cls, context):
return(bpy.context.scene.pc_pc2_group != "")
def execute(self, context):
GENERATE = [
'MULTIRES', 'ARRAY', 'BEVEL', 'BOOLEAN', 'BUILD',
'DECIMATE', 'MASK', 'MIRROR', 'REMESH', 'SCREW',
'SKIN', 'SOLIDIFY', 'SUBSURF', 'TRIANGULATE'
]
for OBJ in bpy.data.collections[bpy.context.scene.pc_pc2_group].objects[:]:
for MOD in OBJ.modifiers[:]:
if MOD.type in GENERATE:
if eval("bpy.context.scene.mesh_cache_tools_settings.%s" % (MOD.type.lower())):
OBJ.modifiers.remove(MOD)
class OscPc2iMporterBatch(Operator):
bl_idname = "import_shape.pc2_selection"
bl_label = "Import pc2 for selected Objects"
bl_description = "Import pc2 for selected Objects"
bl_options = {'REGISTER', 'UNDO'}
@classmethod
def poll(cls, context):
return(bpy.context.scene.pc_pc2_folder != 'Set me Please!')
def execute(self, context):
for OBJ in bpy.context.selected_objects[:]:
MOD = OBJ.modifiers.new("MeshCache", 'MESH_CACHE')
MOD.filepath = "//%s%s%s.pc2" % (bpy.context.scene.pc_pc2_folder, os.sep, OBJ.name)
MOD.cache_format = "PC2"
MOD.forward_axis = "POS_Y"
MOD.up_axis = "POS_Z"
MOD.flip_axis = set(())
MOD.frame_start = bpy.context.scene.pc_pc2_start
return {'FINISHED'}
try:
ACTOBJ = bpy.context.active_object
if not ACTOBJ.id_data.instance_collection:
GROBJS = [ob for ob in ACTOBJ.id_data.instance_collection.objects[:] if ob.type == "MESH"]
for ob in ACTOBJ.id_data.instance_collection.objects[:]:
bpy.context.collection.objects.link(ob)
NEWGROUP = bpy.data.collections.new("%s_CLEAN" % (ACTOBJ.name))
bpy.context.collection.objects.unlink(ACTOBJ)
NEWOBJ = []
for ob in GROBJS:
NEWGROUP.objects.link(ob)
NEWOBJ.append(ob)
except:
return False
return True
class OscGroupLinkedToLocal(Operator):
bl_idname = "group.linked_group_to_local"
bl_label = "Group Linked To Local"
bl_description = "Group Linked To Local"
bl_options = {'REGISTER', 'UNDO'}
def execute(self, context):
group_check = OscLinkedGroupToLocal()
if not group_check:
self.report({'WARNING'},
"There is no objects to link or the object already linked. Operation Cancelled")
return {'CANCELLED'}
class OscMeshCacheUp(Operator):
bl_idname = "object.modifier_mesh_cache_up"
bl_label = "Mesh Cache To Top"
bl_description = "Send Mesh Cache Modifiers top"
bl_options = {'REGISTER', 'UNDO'}
@classmethod
def poll(cls, context):
obj = context.object
return (obj and obj.type == "MESH")
def execute(self, context):
actob = bpy.context.view_layer.objects.active
bpy.context.view_layer.objects.active = ob
for mod in ob.modifiers[:]:
if mod.type == "MESH_CACHE":
for up in range(ob.modifiers.keys().index(mod.name)):
bpy.ops.object.modifier_move_up(modifier=mod.name)
bpy.context.view_layer.objects.active = actob
# Add-ons Preferences Update Panel
# Define Panel classes for updating
panels = (
OscEPc2ExporterPanel,
)
message = "Mesh Cache Tools: Updating Panel locations has failed"
for panel in panels:
if "bl_rna" in panel.__dict__:
bpy.utils.unregister_class(panel)
for panel in panels:
panel.bl_category = context.preferences.addons[__name__].preferences.category
bpy.utils.register_class(panel)
except Exception as e:
print("\n[{}]\n{}\n\nError:\n{}".format(__name__, message, e))
pass
class OscurartMeshCacheToolsAddonPreferences(AddonPreferences):
# this must match the addon name, use '__package__'
# when defining this in a submodule of a python package.
bl_idname = __name__
category: StringProperty(
name="Category",
description="Choose a name for the category of the panel",
default="Tools",
update=update_panel,
)
def draw(self, context):
layout = self.layout
row = layout.row()
col = row.column()
col.label(text="Category:")
col.prop(self, "category", text="")
classes = (
OscurartMeshCacheModifiersSettings,
OscGroupLinkedToLocal,
OscMeshCacheButtonSet,
OscMeshCacheUp,
OscPc2ExporterBatch,
OscPc2iMporterBatch,
OscRemoveSubsurf,
OscurartMeshCacheToolsAddonPreferences,
RemuevePropiedades,
OscurartMeshCacheSceneAutoLoad,
CreaPropiedades,
OscEPc2ExporterPanel,
)
# Register
for cls in classes:
bpy.utils.register_class(cls)
Scene.mesh_cache_tools_settings = PointerProperty(
type=OscurartMeshCacheModifiersSettings
)
Scene.pc_auto_load_proxy = CollectionProperty(
type=OscurartMeshCacheSceneAutoLoad
)
Scene.pc_pc2_rotx = BoolProperty(default=True, name="Rotx = 90")
Scene.pc_pc2_world_space = BoolProperty(default=True, name="World Space")
Scene.pc_pc2_modifiers = BoolProperty(default=True, name="Apply Modifiers")
Scene.pc_pc2_subsurf = BoolProperty(default=True, name="Turn Off SubSurf")
Scene.pc_pc2_start = IntProperty(default=0, name="Frame Start")
Scene.pc_pc2_end = IntProperty(default=100, name="Frame End")
Scene.pc_pc2_group = StringProperty()
Scene.pc_pc2_folder = StringProperty(default="Set me Please!")
Scene.pc_pc2_exclude = StringProperty(default="*")
for cls in classes:
bpy.utils.unregister_class(cls)
from bpy.types import Scene
del Scene.mesh_cache_tools_settings
del Scene.pc_auto_load_proxy
del Scene.pc_pc2_rotx
del Scene.pc_pc2_world_space
del Scene.pc_pc2_modifiers
del Scene.pc_pc2_subsurf
del Scene.pc_pc2_start
del Scene.pc_pc2_end
del Scene.pc_pc2_group
del Scene.pc_pc2_folder
del Scene.pc_pc2_exclude
if __name__ == "__main__":