Skip to content
Snippets Groups Projects
oscurart_mesh_cache_tools.py 16.7 KiB
Newer Older
  • Learn to ignore specific revisions
  • oscurart's avatar
    oscurart committed
    bl_info = {
        "name": "Mesh Cache Tools",
        "author": "Oscurart",
    
    oscurart's avatar
    oscurart committed
        "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/",
    
    oscurart's avatar
    oscurart committed
        "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,
            )
    
    oscurart's avatar
    oscurart committed
    from bpy.app.handlers import persistent
    
    
    
    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)
    
    oscurart's avatar
    oscurart committed
    
    # ----------------- AUTO LOAD PROXY
    
    
    # bpy.context.scene.pc_auto_load_proxy.remove(0)
    class CreaPropiedades(Operator):
    
    oscurart's avatar
    oscurart committed
        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
    
    oscurart's avatar
    oscurart committed
                    i.use_auto_load = False
            return {'FINISHED'}
    
    
    
    class RemuevePropiedades(Operator):
    
    oscurart's avatar
    oscurart committed
        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:
    
    oscurart's avatar
    oscurart committed
                bpy.context.scene.pc_auto_load_proxy.remove(0)
    
            return {'FINISHED'}
    
    
    class OscurartMeshCacheSceneAutoLoad(PropertyGroup):
    
        name: StringProperty(
    
                name="GroupName",
                default=""
                )
    
        use_auto_load: BoolProperty(
    
    oscurart's avatar
    oscurart committed
    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:
    
    oscurart's avatar
    oscurart committed
                    for MOD in ob.modifiers:
    
                        if MOD.type == "MESH_CACHE":
    
    oscurart's avatar
    oscurart committed
                            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)
    
    oscurart's avatar
    oscurart committed
        bl_space_type = 'VIEW_3D'
        bl_region_type = 'TOOLS'
    
    
    
    class OscEPc2ExporterPanel(View3DMCPanel, Panel):
    
    Eugenio Pignataro's avatar
    Eugenio Pignataro committed
        bl_category = "Tools"
    
    oscurart's avatar
    oscurart committed
        bl_label = "Mesh Cache Tools"
    
    Eugenio Pignataro's avatar
    Eugenio Pignataro committed
        bl_options = {'DEFAULT_CLOSED'}
    
    
    oscurart's avatar
    oscurart committed
        def draw(self, context):
            layout = self.layout
    
    oscurart's avatar
    oscurart committed
    
            row = layout.column(align=1)
    
            row.prop(scene, "pc_pc2_folder", text="Folder")
    
            row.operator("buttons.set_meshcache_folder", icon='FILEBROWSER', text="Select Folder Path")
    
    oscurart's avatar
    oscurart committed
            row = layout.box().column(align=1)
    
            row.label(text="EXPORTER:")
    
    oscurart's avatar
    oscurart committed
            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="")
    
    oscurart's avatar
    oscurart committed
            row.operator("export_shape.pc2_selection", text="Export!", icon="POSE_DATA")
    
            row.prop(scene, "pc_pc2_world_space", text="World Space")
    
    oscurart's avatar
    oscurart committed
            row = layout.box().column(align=1)
    
            row.label(text="IMPORTER:")
    
    oscurart's avatar
    oscurart committed
            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:
    
    oscurart's avatar
    oscurart committed
                    row = layout.row()
    
                    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:
    
    Eugenio Pignataro's avatar
    Eugenio Pignataro committed
            os.chdir(os.path.dirname(bpy.data.filepath))
    
        except Exception as e:
            self.report({'WARNING'}, "Folder could not be set: {}".format(e))
            return {'CANCELLED'}
    
        rfp = os.path.relpath(fp)
    
    oscurart's avatar
    oscurart committed
        for sc in bpy.data.scenes:
    
            sc.pc_pc2_folder = rfp
    
    oscurart's avatar
    oscurart committed
        return {'FINISHED'}
    
    
    class OscMeshCacheButtonSet(Operator, ImportHelper):
    
        bl_idname = "buttons.set_meshcache_folder"
    
    oscurart's avatar
    oscurart committed
        bl_label = "Set Mesh Cache Folder"
        filename_ext = ".txt"
    
        def execute(self, context):
    
            return OscSetFolder(self, context, self.filepath)
    
    oscurart's avatar
    oscurart committed
    
    
    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[:]:
    
    oscurart's avatar
    oscurart committed
            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
    
    oscurart's avatar
    oscurart committed
                if ob.type == "MESH":
                    with open("%s/%s.pc2" % (os.path.normpath(folderpath), ob.name), mode="wb") as file:
    
    oscurart's avatar
    oscurart committed
                        headerFormat = '<12siiffi'
                        headerStr = struct.pack(headerFormat,
                                 b'POINTCACHE2\0', 1, len(ob.data.vertices[:]), 0, 1.0, (end + 1) - start)
                        file.write(headerStr)
    
    oscurart's avatar
    oscurart committed
                        obmat = ob.matrix_world
    
                        for i, frame in enumerate(range(start, end + 1)):
    
    oscurart's avatar
    oscurart committed
                            print("Percentage of %s bake: %s " % (ob.name, i * 100 / framerange))
    
                            bpy.context.window_manager.progress_update(i * 100 / framerange)  # progressbarUpdate
    
    oscurart's avatar
    oscurart committed
                            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
    
    oscurart's avatar
    oscurart committed
                            if bpy.context.scene.pc_pc2_world_space:
                                me.transform(obmat)
                                me.calc_normals()
    
    oscurart's avatar
    oscurart committed
                            for vert in me.vertices[:]:
    
                                file.write(struct.pack("<3f", *vert.co))
                            # drain mesh
    
    oscurart's avatar
    oscurart committed
                            bpy.data.meshes.remove(me)
    
                        print("%s Bake finished!" % (ob.name))
    
    
                bpy.context.window_manager.progress_end()  # progressBarClose
    
    oscurart's avatar
    oscurart committed
        print("Bake Totally Finished!")
    
    
    
    class OscPc2ExporterBatch(Operator):
    
    oscurart's avatar
    oscurart committed
        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):
    
    oscurart's avatar
    oscurart committed
        bl_idname = "object.remove_subsurf_modifier"
    
    Aaron's avatar
    Aaron committed
        bl_label = "Remove Subdivision Surface Modifier"
        bl_description = "Remove Subdivision Surface Modifier"
    
    oscurart's avatar
    oscurart committed
        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[:]:
    
    oscurart's avatar
    oscurart committed
                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)
    
    oscurart's avatar
    oscurart committed
            return {'FINISHED'}
    
    
    
    class OscPc2iMporterBatch(Operator):
    
    oscurart's avatar
    oscurart committed
        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)
    
    oscurart's avatar
    oscurart committed
                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'}
    
    
    oscurart's avatar
    oscurart committed
    def OscLinkedGroupToLocal():
    
        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):
    
    oscurart's avatar
    oscurart committed
        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'}
    
    
    oscurart's avatar
    oscurart committed
            return {'FINISHED'}
    
    
    
    class OscMeshCacheUp(Operator):
    
    oscurart's avatar
    oscurart committed
        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
    
    oscurart's avatar
    oscurart committed
    
            for ob in bpy.context.selected_objects[:]:
    
                bpy.context.view_layer.objects.active = ob
    
    oscurart's avatar
    oscurart committed
                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
    
    oscurart's avatar
    oscurart committed
    
            return {'FINISHED'}
    
    
    
    # Add-ons Preferences Update Panel
    
    # Define Panel classes for updating
    panels = (
            OscEPc2ExporterPanel,
            )
    
    Eugenio Pignataro's avatar
    Eugenio Pignataro committed
    
    
    def update_panel(self, context):
    
        message = "Mesh Cache Tools: Updating Panel locations has failed"
    
    Eugenio Pignataro's avatar
    Eugenio Pignataro committed
        try:
    
            for panel in panels:
                if "bl_rna" in panel.__dict__:
                    bpy.utils.unregister_class(panel)
    
    Eugenio Pignataro's avatar
    Eugenio Pignataro committed
    
    
                panel.bl_category = context.preferences.addons[__name__].preferences.category
    
                bpy.utils.register_class(panel)
    
    Eugenio Pignataro's avatar
    Eugenio Pignataro committed
    
    
        except Exception as e:
            print("\n[{}]\n{}\n\nError:\n{}".format(__name__, message, e))
            pass
    
    class OscurartMeshCacheToolsAddonPreferences(AddonPreferences):
    
    Eugenio Pignataro's avatar
    Eugenio Pignataro committed
        # this must match the addon name, use '__package__'
        # when defining this in a submodule of a python package.
        bl_idname = __name__
    
    
        category: StringProperty(
    
    Eugenio Pignataro's avatar
    Eugenio Pignataro committed
                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
    
    Eugenio Pignataro's avatar
    Eugenio Pignataro committed
    
    
    oscurart's avatar
    oscurart committed
    def register():
    
        for cls in classes:
            bpy.utils.register_class(cls)
    
    
    oscurart's avatar
    oscurart committed
        from bpy.types import Scene
    
        Scene.mesh_cache_tools_settings = PointerProperty(
                                                type=OscurartMeshCacheModifiersSettings
                                                )
        Scene.pc_auto_load_proxy = CollectionProperty(
                                                type=OscurartMeshCacheSceneAutoLoad
                                                )
    
    oscurart's avatar
    oscurart committed
    
        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="*")
    
    
    Eugenio Pignataro's avatar
    Eugenio Pignataro committed
        update_panel(None, bpy.context)
    
    oscurart's avatar
    oscurart committed
    
    
    def unregister():
    
        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
    
    oscurart's avatar
    oscurart committed
        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__":