Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender-addons.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormeta-androcto <meta.androcto1@gmail.com>2016-08-07 16:34:46 +0300
committermeta-androcto <meta.androcto1@gmail.com>2016-08-07 16:34:46 +0300
commit3218a23e11dfb9cd3f4fd2421e93a2fdb77a0a66 (patch)
treec9a9376ea9177f71d2a0b81d95c6d8efa6424e2a /oscurart_tools
parent84a93440fd5c5ecbe80d7bb9743c1747d0bde3eb (diff)
initial commit oscurart tools. re: T48708
Diffstat (limited to 'oscurart_tools')
-rw-r--r--oscurart_tools/__init__.py391
-rw-r--r--oscurart_tools/oscurart_animation.py70
-rw-r--r--oscurart_tools/oscurart_files.py50
-rw-r--r--oscurart_tools/oscurart_meshes.py562
-rw-r--r--oscurart_tools/oscurart_objects.py526
-rw-r--r--oscurart_tools/oscurart_render.py399
-rw-r--r--oscurart_tools/oscurart_shapes.py469
7 files changed, 2467 insertions, 0 deletions
diff --git a/oscurart_tools/__init__.py b/oscurart_tools/__init__.py
new file mode 100644
index 00000000..ba217ac5
--- /dev/null
+++ b/oscurart_tools/__init__.py
@@ -0,0 +1,391 @@
+# ##### 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 #####
+
+# <pep8 compliant>
+
+bl_info = {
+ "name": "Oscurart Tools",
+ "author": "Oscurart, CodemanX",
+ "version": (3, 2),
+ "blender": (2, 77, 0),
+ "location": "View3D > Tools > Oscurart Tools",
+ "description": "Tools for objects, render, shapes, and files.",
+ "warning": "",
+ "wiki_url":
+ "http://wiki.blender.org/index.php/Extensions:2.6/Py/Scripts/3D_interaction/Oscurart_Tools",
+ "tracker_url": "https://developer.blender.org/maniphest/task/edit/form/2/",
+ "category": "Object",
+ }
+
+import bpy
+from bpy.types import (
+ AddonPreferences,
+ Panel,
+ PropertyGroup,
+ )
+
+from bpy.props import (
+ StringProperty,
+ BoolProperty,
+ IntProperty,
+ )
+
+from . import oscurart_files
+from . import oscurart_meshes
+from . import oscurart_objects
+from . import oscurart_shapes
+from . import oscurart_render
+from . import oscurart_animation
+
+
+class View3DOscPanel(PropertyGroup):
+ # CREA PANELES EN TOOLS
+ osc_object_tools = BoolProperty(default=True)
+ osc_mesh_tools = BoolProperty(default=True)
+ osc_shapes_tools = BoolProperty(default=True)
+ osc_render_tools = BoolProperty(default=True)
+ osc_files_tools = BoolProperty(default=True)
+ osc_animation_tools = BoolProperty(default=True)
+
+ quick_animation_in = IntProperty(
+ default=1
+ )
+ quick_animation_out = IntProperty(
+ default=250
+ )
+ # SETEO VARIABLE DE ENTORNO
+ SearchAndSelectOt = StringProperty(
+ default="Object name initials"
+ )
+ # RENDER CROP
+ rcPARTS = IntProperty(
+ default=1,
+ min=2,
+ max=50,
+ step=1
+ )
+ RenameObjectOt = StringProperty(
+ default="Type here"
+ )
+
+
+class VarColArchivos(PropertyGroup):
+ filename = bpy.props.StringProperty(
+ name="",
+ default=""
+ )
+ value = bpy.props.IntProperty(
+ name="",
+ default=10
+ )
+ fullpath = bpy.props.StringProperty(
+ name="",
+ default=""
+ )
+ checkbox = bpy.props.BoolProperty(
+ name="",
+ default=True
+ )
+
+
+# PANELES
+class OscPanelControl(Panel):
+ bl_idname = "Oscurart Panel Control"
+ bl_space_type = 'VIEW_3D'
+ bl_region_type = 'TOOLS'
+ bl_category = "Oscurart Tools"
+ bl_label = "Panels Switcher"
+ bl_options = {'DEFAULT_CLOSED'}
+
+ def draw(self, context):
+ layout = self.layout
+ scene = context.scene
+ oscurart = scene.oscurart
+
+ col = layout.column(align=1)
+ col.prop(oscurart, "osc_object_tools", text="Object", icon="OBJECT_DATAMODE")
+ col.prop(oscurart, "osc_mesh_tools", text="Mesh", icon="EDITMODE_HLT")
+ col.prop(oscurart, "osc_shapes_tools", text="Shapes", icon="SHAPEKEY_DATA")
+ col.prop(oscurart, "osc_animation_tools", text="Animation", icon="POSE_DATA")
+ col.prop(oscurart, "osc_render_tools", text="Render", icon="SCENE")
+ col.prop(oscurart, "osc_files_tools", text="Files", icon="IMASEL")
+
+
+class OscPanelObject(Panel):
+ bl_idname = "Oscurart Object Tools"
+ bl_label = "Object Tools"
+ bl_category = "Oscurart Tools"
+ bl_space_type = 'VIEW_3D'
+ bl_region_type = 'TOOLS'
+ bl_options = {'DEFAULT_CLOSED'}
+
+ @classmethod
+ def poll(cls, context):
+ return context.scene.oscurart.osc_object_tools
+
+ def draw(self, context):
+ layout = self.layout
+ col = layout.column(align=1)
+
+ colrow = col.row(align=1)
+ colrow.operator("object.relink_objects_between_scenes", icon="LINKED")
+ colrow = col.row(align=1)
+ colrow.operator("object.copy_objects_groups_layers", icon="LINKED")
+ colrow.operator("object.set_layers_to_other_scenes", icon="LINKED")
+ colrow = col.row(align=1)
+ colrow.operator("object.objects_to_groups", icon="GROUP")
+ colrow = col.row(align=1)
+ colrow.prop(bpy.context.scene.oscurart, "SearchAndSelectOt", text="")
+ colrow.operator("object.search_and_select_osc", icon="ZOOM_SELECTED")
+ colrow = col.row(align=1)
+ colrow.prop(bpy.context.scene.oscurart, "RenameObjectOt", text="")
+ colrow.operator("object.rename_objects_osc", icon="SHORTDISPLAY")
+ col.operator(
+ "object.distribute_osc",
+ icon="OBJECT_DATAMODE",
+ text="Distribute")
+ col.operator(
+ "object.duplicate_object_symmetry_osc",
+ icon="OUTLINER_OB_EMPTY",
+ text="Duplicate Sym")
+ colrow = col.row(align=1)
+ colrow.operator(
+ "object.modifiers_remove_osc",
+ icon="MODIFIER",
+ text="Remove Modifiers")
+ colrow.operator(
+ "object.modifiers_apply_osc",
+ icon="MODIFIER",
+ text="Apply Modifiers")
+ colrow = col.row(align=1)
+ colrow.operator(
+ "group.group_in_out_camera",
+ icon="RENDER_REGION",
+ text="Make Groups in out Camera")
+
+
+class OscPanelMesh(Panel):
+ bl_idname = "Oscurart Mesh Tools"
+ bl_label = "Mesh Tools"
+ bl_category = "Oscurart Tools"
+ bl_space_type = 'VIEW_3D'
+ bl_region_type = 'TOOLS'
+ bl_options = {'DEFAULT_CLOSED'}
+
+ @classmethod
+ def poll(cls, context):
+ return context.scene.oscurart.osc_mesh_tools
+
+ def draw(self, context):
+ layout = self.layout
+ col = layout.column(align=1)
+
+ col.operator("mesh.object_to_mesh_osc", icon="MESH_MONKEY")
+ col.operator("mesh.select_side_osc", icon="VERTEXSEL")
+ colrow = col.row(align=1)
+ colrow.operator("mesh.resym_save_map", icon="UV_SYNC_SELECT")
+ colrow = col.row(align=1)
+ colrow.operator(
+ "mesh.resym_mesh",
+ icon="UV_SYNC_SELECT",
+ text="Resym Mesh")
+ colrow.operator("mesh.resym_vertex_weights_osc", icon="UV_SYNC_SELECT")
+ colrow = col.row(align=1)
+ colrow.operator("mesh.reconst_osc", icon="UV_SYNC_SELECT")
+ colrow = col.row(align=1)
+ colrow.operator("mesh.overlap_uv_faces", icon="UV_FACESEL")
+ colrow = col.row(align=1)
+ colrow.operator("view3d.modal_operator", icon="STICKY_UVS_DISABLE")
+ colrow = col.row(align=1)
+ colrow.operator("file.export_groups_osc", icon='GROUP_VCOL')
+ colrow.operator("file.import_groups_osc", icon='GROUP_VCOL')
+ colrow = col.row(align=1)
+ colrow.operator("mesh.export_vertex_colors", icon='COLOR')
+ colrow.operator("mesh.import_vertex_colors", icon='COLOR')
+
+
+class OscPanelShapes(Panel):
+ bl_idname = "Oscurart Shapes Tools"
+ bl_label = "Shapes Tools"
+ bl_category = "Oscurart Tools"
+ bl_space_type = 'VIEW_3D'
+ bl_region_type = 'TOOLS'
+ bl_options = {'DEFAULT_CLOSED'}
+
+ @classmethod
+ def poll(cls, context):
+ return context.scene.oscurart.osc_shapes_tools
+
+ def draw(self, context):
+ layout = self.layout
+ col = layout.column(align=1)
+
+ col.operator("object.shape_key_to_objects_osc", icon="OBJECT_DATAMODE")
+ col.operator("mesh.create_lmr_groups_osc", icon="GROUP_VERTEX")
+ col.operator("mesh.split_lr_shapes_osc", icon="SHAPEKEY_DATA")
+ colrow = col.row(align=1)
+ colrow.operator("mesh.create_symmetrical_layout_osc", icon="SETTINGS")
+ colrow.operator("mesh.create_asymmetrical_layout_osc", icon="SETTINGS")
+
+
+class OscPanelRender(Panel):
+ bl_idname = "Oscurart Render Tools"
+ bl_label = "Render Tools"
+ bl_category = "Oscurart Tools"
+ bl_space_type = 'VIEW_3D'
+ bl_region_type = 'TOOLS'
+ bl_options = {'DEFAULT_CLOSED'}
+
+ @classmethod
+ def poll(cls, context):
+ return context.scene.oscurart.osc_render_tools
+
+ def draw(self, context):
+ layout = self.layout
+ col = layout.column(align=1)
+
+ colrow = col.row(align=1)
+ colrow.operator(
+ "render.copy_render_settings_osc",
+ icon="LIBRARY_DATA_DIRECT",
+ text="Copy Render Settings").mode = "render"
+ colrow.operator(
+ "render.copy_render_settings_osc",
+ icon="LIBRARY_DATA_DIRECT",
+ text="Copy Cycles Settings").mode = "cycles"
+ colrow = col.row(align=1)
+ colrow.operator(
+ "render.render_all_scenes_osc",
+ icon="RENDER_STILL",
+ text="All Scenes").frametype = False
+ colrow.operator(
+ "render.render_all_scenes_osc",
+ text="> Frame").frametype = True
+ colrow = col.row(align=1)
+ colrow.operator(
+ "render.render_current_scene_osc",
+ icon="RENDER_STILL",
+ text="Active Scene").frametype = False
+ colrow.operator(
+ "render.render_current_scene_osc",
+ text="> Frame").frametype = True
+
+ colrow = col.row(align=1)
+ colrow.operator("render.render_crop_osc", icon="RENDER_REGION")
+ colrow.prop(bpy.context.scene.oscurart, "rcPARTS", text="Parts")
+
+ boxcol = layout.box().column(align=1)
+ colrow = boxcol.row(align=1)
+ colrow.operator(
+ "render.render_selected_scenes_osc",
+ icon="RENDER_STILL",
+ text="Selected Scenes").frametype = False
+ colrow.operator(
+ "render.render_selected_scenes_osc",
+ text="> Frame").frametype = True
+
+ for sc in bpy.data.scenes[:]:
+ boxcol.prop(sc, "use_render_scene", text=sc.name)
+
+
+class OscPanelFiles(Panel):
+ bl_idname = "Oscurart Files Tools"
+ bl_label = "Files Tools"
+ bl_category = "Oscurart Tools"
+ bl_space_type = 'VIEW_3D'
+ bl_region_type = 'TOOLS'
+ bl_options = {'DEFAULT_CLOSED'}
+
+ @classmethod
+ def poll(cls, context):
+ return context.scene.oscurart.osc_files_tools
+
+ def draw(self, context):
+ layout = self.layout
+ col = layout.column(align=1)
+ col.operator("image.reload_images_osc", icon="IMAGE_COL")
+ col.operator("file.sync_missing_groups", icon="LINK_AREA")
+
+
+class OscPanelAnimation(Panel):
+ bl_idname = "Oscurart Animation Tools"
+ bl_label = "Animation Tools"
+ bl_category = "Oscurart Tools"
+ bl_space_type = 'VIEW_3D'
+ bl_region_type = 'TOOLS'
+ bl_options = {'DEFAULT_CLOSED'}
+
+ @classmethod
+ def poll(cls, context):
+ return context.scene.oscurart.osc_animation_tools
+
+ def draw(self, context):
+ layout = self.layout
+ col = layout.column(align=1)
+ row = col.row()
+
+ col.operator("anim.quick_parent_osc", icon="OUTLINER_DATA_POSE")
+ row = col.row(align=1)
+ row.prop(bpy.context.scene.oscurart, "quick_animation_in", text="")
+ row.prop(bpy.context.scene.oscurart, "quick_animation_out", text="")
+
+
+class OscurartToolsAddonPreferences(bpy.types.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="Oscurart Tools",
+ )
+
+ def draw(self, context):
+ layout = self.layout
+ row = layout.row()
+ col = row.column()
+ col.label(text="Category:")
+ col.prop(self, "category", text="")
+
+# ========================= FIN DE SCRIPTS =========================
+
+
+def register():
+ bpy.utils.register_module(__name__)
+
+ bpy.types.Scene.oscurart = bpy.props.PointerProperty(
+ type=View3DOscPanel
+ )
+ bpy.types.Scene.use_render_scene = bpy.props.BoolProperty()
+
+ bpy.types.Scene.broken_files = bpy.props.CollectionProperty(
+ type=VarColArchivos
+ )
+
+
+def unregister():
+ del bpy.types.Scene.oscurart
+ del bpy.types.Scene.use_render_scene
+ del bpy.types.Scene.broken_files
+
+ bpy.utils.unregister_module(__name__)
+
+
+if __name__ == "__main__":
+ register()
diff --git a/oscurart_tools/oscurart_animation.py b/oscurart_tools/oscurart_animation.py
new file mode 100644
index 00000000..8a3e552a
--- /dev/null
+++ b/oscurart_tools/oscurart_animation.py
@@ -0,0 +1,70 @@
+# ##### 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 #####
+
+# <pep8 compliant>
+
+import bpy
+from mathutils import Matrix
+
+# -------------------------QUICK PARENT------------------
+
+
+def DefQuickParent(inf, out):
+ if bpy.context.object.type == "ARMATURE":
+ ob = bpy.context.object
+ target = [object for object in bpy.context.selected_objects if object != ob][0]
+ ob = (bpy.context.active_pose_bone if bpy.context.object.type == 'ARMATURE' else bpy.context.object)
+ target.select = False
+ bpy.context.scene.frame_set(frame=bpy.context.scene.oscurart.quick_animation_in)
+ a = Matrix(target.matrix_world)
+ a.invert()
+ i = Matrix(ob.matrix)
+ for frame in range(inf, out):
+ bpy.context.scene.frame_set(frame=frame)
+ ob.matrix = target.matrix_world * a * i
+ bpy.ops.anim.keyframe_insert(type="LocRotScale")
+ else:
+ ob = bpy.context.object
+ target = [object for object in bpy.context.selected_objects if object != ob][0]
+ ob = (bpy.context.active_pose_bone if bpy.context.object.type == 'ARMATURE' else bpy.context.object)
+ target.select = False
+ bpy.context.scene.frame_set(frame=bpy.context.scene.oscurart.quick_animation_in)
+ a = Matrix(target.matrix_world)
+ a.invert()
+ i = Matrix(ob.matrix_world)
+ for frame in range(inf, out):
+ bpy.context.scene.frame_set(frame=frame)
+ ob.matrix_world = target.matrix_world * a * i
+ bpy.ops.anim.keyframe_insert(type="LocRotScale")
+
+
+class QuickParent(bpy.types.Operator):
+ bl_idname = "anim.quick_parent_osc"
+ bl_label = "Quick Parent"
+ bl_options = {"REGISTER", "UNDO"}
+
+ @classmethod
+ def poll(cls, context):
+ return (context.active_object is not None and
+ len(context.selected_objects) > 1)
+
+ def execute(self, context):
+ DefQuickParent(
+ bpy.context.scene.oscurart.quick_animation_in,
+ bpy.context.scene.oscurart.quick_animation_out)
+ return {'FINISHED'}
diff --git a/oscurart_tools/oscurart_files.py b/oscurart_tools/oscurart_files.py
new file mode 100644
index 00000000..c3a82d7f
--- /dev/null
+++ b/oscurart_tools/oscurart_files.py
@@ -0,0 +1,50 @@
+# ##### 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 #####
+
+# <pep8 compliant>
+
+import bpy
+from bpy.types import Operator
+
+
+# ---------------------RELOAD IMAGES------------------
+
+class reloadImages(Operator):
+ bl_idname = "image.reload_images_osc"
+ bl_label = "Reload Images"
+ bl_options = {"REGISTER", "UNDO"}
+
+ def execute(self, context):
+ for imgs in bpy.data.images:
+ imgs.reload()
+ return {'FINISHED'}
+
+
+# --------------- SYNC MISSING GROUPS -----------------
+
+class reFreshMissingGroups(Operator):
+ bl_idname = "file.sync_missing_groups"
+ bl_label = "Sync Missing Groups"
+ bl_options = {"REGISTER", "UNDO"}
+
+ def execute(self, context):
+ for group in bpy.data.groups:
+ if group.library is not None:
+ with bpy.data.libraries.load(group.library.filepath, link=True) as (linked, local):
+ local.groups = linked.groups
+ return {'FINISHED'}
diff --git a/oscurart_tools/oscurart_meshes.py b/oscurart_tools/oscurart_meshes.py
new file mode 100644
index 00000000..99116a08
--- /dev/null
+++ b/oscurart_tools/oscurart_meshes.py
@@ -0,0 +1,562 @@
+# ##### 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 #####
+
+# <pep8 compliant>
+
+import bpy
+from bpy.types import Operator
+from bpy.props import (
+ IntProperty,
+ BoolProperty,
+ FloatProperty,
+ EnumProperty,
+ )
+import os
+import bmesh
+import time
+import blf
+from bpy_extras.view3d_utils import location_3d_to_region_2d
+
+
+# -----------------------------RECONST---------------------------
+
+def defReconst(self, OFFSET):
+ bpy.ops.object.mode_set(mode='EDIT', toggle=False)
+ bpy.context.tool_settings.mesh_select_mode = (True, True, True)
+ ob = bpy.context.active_object
+ bm = bmesh.from_edit_mesh(ob.data)
+ bm.select_flush(False)
+ for vertice in bm.verts[:]:
+ if abs(vertice.co[0]) < OFFSET:
+ vertice.co[0] = 0
+ for vertice in bm.verts[:]:
+ if vertice.co[0] < 0:
+ bm.verts.remove(vertice)
+ bmesh.update_edit_mesh(ob.data)
+ # mod = ob.modifiers.new("Mirror", "MIRROR")
+ # uv = ob.data.uv_textures.new(name="SYMMETRICAL")
+ for v in bm.faces:
+ v.select = 1
+ bmesh.update_edit_mesh(ob.data)
+ ob.data.uv_textures.active = ob.data.uv_textures['SYMMETRICAL']
+ bpy.ops.uv.unwrap(
+ method='ANGLE_BASED',
+ fill_holes=True,
+ correct_aspect=False,
+ use_subsurf_data=0)
+ bpy.ops.object.mode_set(mode="OBJECT", toggle=False)
+ bpy.ops.object.modifier_apply(apply_as='DATA', modifier="Mirror")
+ bpy.ops.object.mode_set(mode="EDIT", toggle=False)
+ bm = bmesh.from_edit_mesh(ob.data)
+ bm.select_flush(0)
+ # uv = ob.data.uv_textures.new(name="ASYMMETRICAL")
+ ob.data.uv_textures.active = ob.data.uv_textures['ASYMMETRICAL']
+ bpy.ops.uv.unwrap(
+ method='ANGLE_BASED',
+ fill_holes=True,
+ correct_aspect=False,
+ use_subsurf_data=0)
+
+
+class reConst(Operator):
+ bl_idname = "mesh.reconst_osc"
+ bl_label = "ReConst Mesh"
+ bl_options = {"REGISTER", "UNDO"}
+ OFFSET = FloatProperty(
+ name="Offset",
+ default=0.001,
+ min=-0,
+ max=0.1
+ )
+
+ @classmethod
+ def poll(cls, context):
+ return (context.active_object is not None and
+ context.active_object.type == 'MESH')
+
+ def execute(self, context):
+ defReconst(self, self.OFFSET)
+ return {'FINISHED'}
+
+
+# -----------------------------------SELECT LEFT---------------------
+
+def side(self, nombre, offset):
+
+ bpy.ops.object.mode_set(mode="EDIT", toggle=0)
+ OBJECT = bpy.context.active_object
+ ODATA = bmesh.from_edit_mesh(OBJECT.data)
+ bpy.context.tool_settings.mesh_select_mode = (True, False, False)
+ for VERTICE in ODATA.verts[:]:
+ VERTICE.select = False
+ if nombre is False:
+ for VERTICES in ODATA.verts[:]:
+ if VERTICES.co[0] < (offset):
+ VERTICES.select = 1
+ else:
+ for VERTICES in ODATA.verts[:]:
+ if VERTICES.co[0] > (offset):
+ VERTICES.select = 1
+ ODATA.select_flush(False)
+ bpy.ops.object.mode_set(mode="EDIT", toggle=0)
+
+
+class SelectMenor (Operator):
+ bl_idname = "mesh.select_side_osc"
+ bl_label = "Select Side"
+ bl_options = {"REGISTER", "UNDO"}
+
+ @classmethod
+ def poll(cls, context):
+ return (context.active_object is not None and
+ context.active_object.type == 'MESH')
+
+ side = BoolProperty(
+ name="Greater than zero",
+ default=False
+ )
+ offset = FloatProperty(
+ name="Offset",
+ default=0
+ )
+
+ def execute(self, context):
+
+ side(self, self.side, self.offset)
+
+ return {'FINISHED'}
+
+
+# -------------------------RESYM VG----------------------------------
+
+class resymVertexGroups(Operator):
+ bl_idname = "mesh.resym_vertex_weights_osc"
+ bl_label = "Resym Vertex Weights"
+ bl_options = {"REGISTER", "UNDO"}
+
+ @classmethod
+ def poll(cls, context):
+ return (context.active_object is not None and
+ context.active_object.type == 'MESH')
+
+ def execute(self, context):
+
+ with open("%s_%s_SYM_TEMPLATE.xml" % (os.path.join(os.path.dirname(bpy.data.filepath),
+ bpy.context.scene.name), bpy.context.object.name)) as file:
+ ob = bpy.context.object
+ actgr = ob.vertex_groups.active
+ actind = ob.vertex_groups.active_index
+ ls = eval(file.read())
+ wdict = {left: actgr.weight(right) for left, right in ls.items()
+ for group in ob.data.vertices[right].groups if group.group == actind}
+ actgr.remove(
+ [vert.index for vert in ob.data.vertices if vert.co[0] <= 0])
+ for ind, weight in wdict.items():
+ actgr.add([ind], weight, 'REPLACE')
+ bpy.context.object.data.update()
+
+ return {'FINISHED'}
+
+
+# ------------------------IMPORT EXPORT GROUPS--------------------
+
+class OscExportVG(Operator):
+ bl_idname = "file.export_groups_osc"
+ bl_label = "Export Groups"
+ bl_options = {"REGISTER", "UNDO"}
+
+ @classmethod
+ def poll(cls, context):
+ return (context.active_object is not None and
+ context.active_object.type == 'MESH')
+
+ def execute(self, context):
+
+ ob = bpy.context.object
+ with open(os.path.join(os.path.dirname(bpy.data.filepath), ob.name + ".txt"), mode="w") as file:
+ vgindex = {vg.index: vg.name for vg in ob.vertex_groups[:]}
+ vgdict = {}
+ for vert in ob.data.vertices:
+ for vg in vert.groups:
+ vgdict.setdefault(vg.group, []).append(
+ (vert.index, vg.weight))
+ file.write(str(vgdict) + "\n")
+ file.write(str(vgindex))
+
+ return {'FINISHED'}
+
+
+class OscImportVG(Operator):
+ bl_idname = "file.import_groups_osc"
+ bl_label = "Import Groups"
+ bl_options = {"REGISTER", "UNDO"}
+
+ @classmethod
+ def poll(cls, context):
+ return (context.active_object is not None and
+ context.active_object.type == 'MESH')
+
+ def execute(self, context):
+
+ ob = bpy.context.object
+ with open(os.path.join(os.path.dirname(bpy.data.filepath), ob.name + ".txt"), mode="r") as file:
+ vgdict = eval(file.readlines(1)[0].replace("\n", ""))
+ vgindex = eval(file.readlines(2)[0].replace("\n", ""))
+
+ for index, name in vgindex.items():
+ ob.vertex_groups.new(name=name)
+
+ for group, vdata in vgdict.items():
+ for index, weight in vdata:
+ ob.vertex_groups[group].add(
+ index=[index],
+ weight=weight,
+ type="REPLACE")
+
+ return {'FINISHED'}
+
+
+# ------------------------------------ RESYM MESH-------------------------
+
+def reSymSave(self, quality):
+
+ bpy.ops.object.mode_set(mode='OBJECT')
+
+ object = bpy.context.object
+
+ rdqual = quality
+ rd = lambda x: round(x, rdqual)
+ absol = lambda x: (abs(x[0]), x[1], x[2])
+
+ inddict = {
+ tuple(map(rd, vert.co[:])): vert.index for vert in object.data.vertices[:]}
+ reldict = {inddict[vert]: inddict.get(absol(vert), inddict[vert])
+ for vert in inddict if vert[0] <= 0}
+
+ ENTFILEPATH = "%s_%s_SYM_TEMPLATE.xml" % (
+ os.path.join(os.path.dirname(bpy.data.filepath),
+ bpy.context.scene.name),
+ bpy.context.object.name)
+ with open(ENTFILEPATH, mode="w") as file:
+ file.writelines(str(reldict))
+ reldict.clear()
+
+
+def reSymMesh(self, SELECTED, SIDE):
+ bpy.ops.object.mode_set(mode='EDIT')
+ ENTFILEPATH = "%s_%s_SYM_TEMPLATE.xml" % (
+ os.path.join(os.path.dirname(bpy.data.filepath),
+ bpy.context.scene.name),
+ bpy.context.object.name)
+ with open(ENTFILEPATH, mode="r") as file:
+ SYMAP = eval(file.readlines()[0])
+ bm = bmesh.from_edit_mesh(bpy.context.object.data)
+ object = bpy.context.object
+
+ def MAME(SYMAP):
+ if SELECTED:
+ for vert in SYMAP:
+ if bm.verts[SYMAP[vert]].select:
+ bm.verts[vert].co = (-1 * bm.verts[SYMAP[vert]].co[0],
+ bm.verts[SYMAP[vert]].co[1],
+ bm.verts[SYMAP[vert]].co[2])
+ else:
+ for vert in SYMAP:
+ bm.verts[vert].co = (-1 * bm.verts[SYMAP[vert]].co[0],
+ bm.verts[SYMAP[vert]].co[1],
+ bm.verts[SYMAP[vert]].co[2])
+ bmesh.update_edit_mesh(object.data)
+
+ def MEMA(SYMAP):
+ if SELECTED:
+ for vert in SYMAP:
+ if bm.verts[vert].select:
+ bm.verts[SYMAP[vert]].co = (-1 * bm.verts[vert].co[0],
+ bm.verts[vert].co[1],
+ bm.verts[vert].co[2])
+ else:
+ for vert in SYMAP:
+ bm.verts[SYMAP[vert]].co = (-1 * bm.verts[vert].co[0],
+ bm.verts[vert].co[1],
+ bm.verts[vert].co[2])
+ bmesh.update_edit_mesh(object.data)
+
+ if SIDE == "+-":
+ MAME(SYMAP)
+ else:
+ MEMA(SYMAP)
+
+
+class OscResymSave(Operator):
+ bl_idname = "mesh.resym_save_map"
+ bl_label = "Resym save XML Map"
+ bl_options = {"REGISTER", "UNDO"}
+
+ @classmethod
+ def poll(cls, context):
+ return (context.active_object is not None and
+ context.active_object.type == 'MESH')
+
+ quality = IntProperty(
+ default=4,
+ name="Quality"
+ )
+
+ def execute(self, context):
+ reSymSave(self, self.quality)
+ return {'FINISHED'}
+
+
+class OscResymMesh(Operator):
+ bl_idname = "mesh.resym_mesh"
+ bl_label = "Resym save Apply XML"
+ bl_options = {"REGISTER", "UNDO"}
+
+ @classmethod
+ def poll(cls, context):
+ return (context.active_object is not None and
+ context.active_object.type == 'MESH')
+
+ selected = BoolProperty(
+ default=False,
+ name="Only Selected"
+ )
+ side = EnumProperty(
+ name="Side:",
+ description="Select Side",
+ items=(('+-', "+X to -X", "+X to -X"),
+ ('-+', "-X to +X", "-X to +X")),
+ default='+-',
+ )
+
+ def execute(self, context):
+ reSymMesh(self, self.selected, self.side)
+ return {'FINISHED'}
+
+
+# -------------------------- OBJECT TO MESH ------------------------------
+
+def DefOscObjectToMesh():
+ ACTOBJ = bpy.context.object
+ MESH = ACTOBJ.to_mesh(
+ scene=bpy.context.scene,
+ apply_modifiers=True,
+ settings="RENDER",
+ calc_tessface=True)
+ OBJECT = bpy.data.objects.new(("%s_Freeze") % (ACTOBJ.name), MESH)
+ bpy.context.scene.objects.link(OBJECT)
+
+
+class OscObjectToMesh(Operator):
+ bl_idname = "mesh.object_to_mesh_osc"
+ bl_label = "Object To Mesh"
+ bl_description = "Works on Meshes, Meta objects, Curves and Surfaces"
+
+ @classmethod
+ def poll(cls, context):
+ return (context.active_object is not None and
+ context.active_object.type in
+ {'MESH', 'META', 'CURVE', 'SURFACE'})
+
+ def execute(self, context):
+ print("Active type object is", context.object.type)
+ DefOscObjectToMesh()
+ return {'FINISHED'}
+
+
+# ----------------------------- OVERLAP UV -------------------------------
+
+def DefOscOverlapUv(valpresicion):
+ inicio = time.time()
+ mode = bpy.context.object.mode
+ bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
+
+ rd = valpresicion
+ ob = bpy.context.object
+ absco = lambda x: (abs(round(x[0], rd)), round(x[1], rd), round(x[2], rd))
+ rounder = lambda x: (round(x[0], rd), round(x[1], rd), round(x[2], rd))
+
+ # vertice a vertex
+ vertvertex = {}
+ for vert in ob.data.loops:
+ vertvertex.setdefault(vert.vertex_index, []).append(vert.index)
+
+ vertexvert = {}
+ for vertex in ob.data.loops:
+ vertexvert[vertex.index] = vertex.vertex_index
+
+ # posicion de cada vertice y cada face
+ vertloc = {rounder(vert.co[:]): vert for vert in ob.data.vertices}
+ faceloc = {rounder(poly.center[:]): poly for poly in ob.data.polygons}
+
+ # relativo de cada vertice y cada face
+ verteqind = {vert.index: vertloc.get(
+ absco(co),
+ vertloc[co]).index for co,
+ vert in vertloc.items() if co[0] <= 0}
+ polyeq = {face: faceloc.get(
+ absco(center),
+ faceloc[center]) for center,
+ face in faceloc.items() if center[0] <= 0}
+
+ # loops in faces
+ lif = {poly: [i for i in poly.loop_indices] for poly in ob.data.polygons}
+
+ # acomoda
+ for l, r in polyeq.items():
+ if l.select:
+ for lloop in lif[l]:
+ for rloop in lif[r]:
+ if (verteqind[vertexvert[lloop]] == vertexvert[rloop] and
+ ob.data.uv_layers.active.data[rloop].select):
+
+ ob.data.uv_layers.active.data[
+ lloop].uv = ob.data.uv_layers.active.data[
+ rloop].uv
+
+ bpy.ops.object.mode_set(mode=mode, toggle=False)
+
+ print("Time elapsed: %4s seconds" % (time.time() - inicio))
+
+
+class OscOverlapUv(Operator):
+ bl_idname = "mesh.overlap_uv_faces"
+ bl_label = "Overlap Uvs"
+ bl_options = {"REGISTER", "UNDO"}
+
+ @classmethod
+ def poll(cls, context):
+ return (context.active_object is not None and
+ context.active_object.type == 'MESH')
+
+ presicion = IntProperty(
+ default=4,
+ min=1,
+ max=10,
+ name="precision"
+ )
+
+ def execute(self, context):
+ DefOscOverlapUv(self.presicion)
+ return {'FINISHED'}
+
+
+# ------------------------------- IO VERTEX COLORS --------------------
+
+def DefOscExportVC():
+ with open(os.path.join(os.path.dirname(bpy.data.filepath), bpy.context.object.name) + ".vc", mode="w") as file:
+ ob = bpy.context.object
+ di = {loopind: ob.data.vertex_colors.active.data[loopind].color[:]
+ for face in ob.data.polygons for loopind in face.loop_indices[:]}
+ file.write(str(di))
+
+
+def DefOscImportVC():
+ with open(os.path.join(os.path.dirname(bpy.data.filepath), bpy.context.object.name) + ".vc", mode="r") as file:
+ di = eval(file.read())
+ for loopind in di:
+ bpy.context.object.data.vertex_colors.active.data[
+ loopind].color = di[loopind]
+
+
+class OscExportVC(Operator):
+ bl_idname = "mesh.export_vertex_colors"
+ bl_label = "Export Vertex Colors"
+ bl_options = {"REGISTER", "UNDO"}
+
+ @classmethod
+ def poll(cls, context):
+ return (context.active_object is not None and
+ context.active_object.type == 'MESH')
+
+ def execute(self, context):
+ DefOscExportVC()
+ return {'FINISHED'}
+
+
+class OscImportVC(Operator):
+ bl_idname = "mesh.import_vertex_colors"
+ bl_label = "Import Vertex Colors"
+ bl_options = {"REGISTER", "UNDO"}
+
+ @classmethod
+ def poll(cls, context):
+ return (context.active_object is not None and
+ context.active_object.type == 'MESH')
+
+ def execute(self, context):
+ DefOscImportVC()
+ return {'FINISHED'}
+
+
+# ------------------ PRINT VERTICES ----------------------
+
+def dibuja_callback(self, context):
+ font_id = 0
+ bm = bmesh.from_edit_mesh(bpy.context.object.data)
+ for v in bm.verts:
+ cord = location_3d_to_region_2d(
+ context.region,
+ context.space_data.region_3d,
+ self.matr * v.co)
+ blf.position(font_id, cord[0], cord[1], 0)
+ blf.size(font_id, self.tsize, 72)
+ blf.draw(font_id, str(v.index))
+
+
+class ModalIndexOperator(Operator):
+ bl_idname = "view3d.modal_operator"
+ bl_label = "Print Vertices"
+
+ @classmethod
+ def poll(cls, context):
+ return (context.active_object is not None and
+ context.active_object.type == 'MESH')
+
+ def modal(self, context, event):
+ context.area.tag_redraw()
+ if event.type == 'MOUSEMOVE':
+ self.x = event.mouse_region_x
+ self.matr = context.object.matrix_world
+ elif event.type == 'LEFTMOUSE':
+ bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW')
+ return {'FINISHED'}
+ elif event.type == 'PAGE_UP':
+ self.tsize += 1
+ elif event.type == 'PAGE_DOWN':
+ self.tsize -= 1
+ elif event.type in {'RIGHTMOUSE', 'ESC', 'TAB'}:
+ bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW')
+ context.area.header_text_set()
+ return {'CANCELLED'}
+
+ return {'PASS_THROUGH'}
+
+ def invoke(self, context, event):
+ if context.area.type == "VIEW_3D":
+ context.area.header_text_set("Esc: exit, PageUP/Down: text size")
+ bpy.ops.object.mode_set(mode="EDIT")
+ self.tsize = 20
+ args = (self, context)
+ self._handle = bpy.types.SpaceView3D.draw_handler_add(
+ dibuja_callback, args, "WINDOW", "POST_PIXEL")
+ context.window_manager.modal_handler_add(self)
+ return{'RUNNING_MODAL'}
+ else:
+ self.report({"WARNING"}, "Is not a 3D Space")
+ return {'CANCELLED'}
diff --git a/oscurart_tools/oscurart_objects.py b/oscurart_tools/oscurart_objects.py
new file mode 100644
index 00000000..ffae4aae
--- /dev/null
+++ b/oscurart_tools/oscurart_objects.py
@@ -0,0 +1,526 @@
+# ##### 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 #####
+
+# <pep8 compliant>
+
+import bpy
+from bpy.types import Operator
+from bpy.props import BoolProperty
+import os
+from bpy_extras.object_utils import world_to_camera_view
+
+
+# ------------------------ SEARCH AND SELECT ------------------------
+
+class SearchAndSelectOt(Operator):
+ bl_idname = "object.search_and_select_osc"
+ bl_label = "Search And Select"
+ bl_description = "Selection based upon object names in the scene"
+ bl_options = {"REGISTER", "UNDO"}
+
+ start = BoolProperty(name="Start With", default=True)
+ count = BoolProperty(name="Contain", default=True)
+ end = BoolProperty(name="End", default=True)
+
+ def execute(self, context):
+ for objeto in bpy.context.scene.objects:
+ variableNombre = bpy.context.scene.oscurart.SearchAndSelectOt
+ if self.start:
+ if objeto.name.startswith(variableNombre):
+ objeto.select = True
+ if self.count:
+ if objeto.name.count(variableNombre):
+ objeto.select = True
+ if self.end:
+ if objeto.name.count(variableNombre):
+ objeto.select = True
+ return {'FINISHED'}
+
+
+# -------------------------RENAME OBJECTS----------------------------------
+
+class renameObjectsOt (Operator):
+ bl_idname = "object.rename_objects_osc"
+ bl_label = "Rename Objects"
+ bl_options = {"REGISTER", "UNDO"}
+
+ def execute(self, context):
+ listaObj = bpy.context.selected_objects[:]
+ for objeto in listaObj:
+ objeto.name = bpy.context.scene.oscurart.RenameObjectOt
+ return {'FINISHED'}
+
+
+# ---------------------------REMOVE MODIFIERS Y APPLY MODIFIERS-----------
+
+class oscRemModifiers (Operator):
+ bl_idname = "object.modifiers_remove_osc"
+ bl_label = "Remove modifiers"
+ bl_description = "Removes all modifiers on all selected objects"
+ bl_options = {"REGISTER", "UNDO"}
+
+ def execute(self, context):
+ for objeto in bpy.context.selected_objects:
+ for modificador in objeto.modifiers:
+ print(modificador.type)
+ bpy.context.scene.objects.active = objeto
+ bpy.ops.object.modifier_remove(modifier=modificador.name)
+ return {'FINISHED'}
+
+
+class oscApplyModifiers (Operator):
+ bl_idname = "object.modifiers_apply_osc"
+ bl_label = "Apply modifiers"
+ bl_description = ("Applies all modifiers on all selected objects \n"
+ "Warning: Make single user will be applied on Linked Object data")
+ bl_options = {"REGISTER", "UNDO"}
+
+ def execute(self, context):
+ for objeto in bpy.context.selected_objects:
+ bpy.ops.object.select_all(action='DESELECT')
+ bpy.context.scene.objects.active = objeto
+ objeto.select = True
+ if objeto.data.users >= 2:
+ bpy.ops.object.make_single_user(
+ type='SELECTED_OBJECTS',
+ object=True,
+ obdata=True,
+ material=False,
+ texture=False,
+ animation=False)
+ for modificador in objeto.modifiers:
+ try:
+ bpy.ops.object.modifier_apply(
+ apply_as="DATA",
+ modifier=modificador.name)
+ except:
+ bpy.ops.object.modifier_remove(modifier=modificador.name)
+ print("* Modifier %s skipping apply" % (modificador.name))
+
+ return {'FINISHED'}
+
+
+# ------------------------------------ RELINK OBJECTS---------------------
+
+def relinkObjects(self):
+
+ LISTSCENE = []
+ if bpy.selection_osc:
+ for SCENE in bpy.data.scenes[:]:
+ if SCENE.objects:
+ if bpy.selection_osc[-1] in SCENE.objects[:]:
+ LISTSCENE.append(SCENE)
+
+ if LISTSCENE:
+ OBJECTS = bpy.selection_osc[:-1]
+ ACTOBJ = bpy.selection_osc[-1]
+ OBJSEL = bpy.selection_osc[:]
+
+ LISTSCENE.remove(bpy.context.scene)
+
+ bpy.ops.object.select_all(action='DESELECT')
+
+ for OBJETO in OBJECTS:
+ if OBJETO.users != len(bpy.data.scenes):
+ print(OBJETO.name)
+ OBJETO.select = True
+
+ for SCENE in LISTSCENE:
+ bpy.ops.object.make_links_scene(scene=SCENE.name)
+
+ bpy.context.scene.objects.active = ACTOBJ
+ for OBJ in OBJSEL:
+ OBJ.select = True
+ else:
+ self.report({'INFO'}, message="Scenes are empty")
+
+
+class OscRelinkObjectsBetween(Operator):
+ bl_idname = "object.relink_objects_between_scenes"
+ bl_label = "Relink Objects Between Scenes"
+ bl_options = {"REGISTER", "UNDO"}
+
+ def execute(self, context):
+ relinkObjects(self)
+ return {'FINISHED'}
+
+
+# ------------------------------------ COPY GROUPS AND LAYERS-------------
+
+def CopyObjectGroupsAndLayers(self):
+
+ OBSEL = bpy.selection_osc[:]
+ if OBSEL:
+ GLOBALLAYERS = list(OBSEL[-1].layers[:])
+ ACTSCENE = bpy.context.scene
+ GROUPS = OBSEL[-1].users_group
+ ACTOBJ = OBSEL[-1]
+
+ for OBJECT in OBSEL[:-1]:
+ for scene in bpy.data.scenes[:]:
+
+ # SI EL OBJETO ACTIVO ESTA EN LA ESCENA
+ if ACTOBJ in scene.objects[:] and OBJECT in scene.objects[:]:
+ scene.object_bases[
+ OBJECT.name].layers[
+ :] = scene.object_bases[
+ ACTOBJ.name].layers[
+ :]
+ elif ACTOBJ not in scene.objects[:] and OBJECT in scene.objects[:]:
+ scene.object_bases[OBJECT.name].layers[:] = list(GLOBALLAYERS)
+
+ # REMUEVO DE TODO GRUPO
+ for GROUP in bpy.data.groups[:]:
+ if GROUP in OBJECT.users_group[:]:
+ GROUP.objects.unlink(OBJECT)
+
+ # INCLUYO OBJETO EN GRUPOS
+ for GROUP in GROUPS:
+ GROUP.objects.link(OBJECT)
+
+ bpy.context.window.screen.scene = ACTSCENE
+ bpy.context.scene.objects.active = ACTOBJ
+
+
+class OscCopyObjectGAL (Operator):
+ bl_idname = "object.copy_objects_groups_layers"
+ bl_label = "Copy Groups And Layers"
+ bl_options = {"REGISTER", "UNDO"}
+
+ def execute(self, context):
+ CopyObjectGroupsAndLayers(self)
+ return {'FINISHED'}
+
+
+# ------------------------------------ SELECTION -------------------------
+bpy.selection_osc = []
+
+
+def select_osc():
+ if bpy.context.mode == "OBJECT":
+ obj = bpy.context.object
+ sel = len(bpy.context.selected_objects)
+
+ if sel == 0:
+ bpy.selection_osc = []
+ else:
+ if sel == 1:
+ bpy.selection_osc = []
+ bpy.selection_osc.append(obj)
+ elif sel > len(bpy.selection_osc):
+ for sobj in bpy.context.selected_objects:
+ if (sobj in bpy.selection_osc) is False:
+ bpy.selection_osc.append(sobj)
+
+ elif sel < len(bpy.selection_osc):
+ for it in bpy.selection_osc:
+ if (it in bpy.context.selected_objects) is False:
+ bpy.selection_osc.remove(it)
+
+
+class OscSelection(bpy.types.Header):
+ bl_label = "Selection Osc"
+ bl_space_type = "VIEW_3D"
+
+ def __init__(self):
+ select_osc()
+
+ def draw(self, context):
+ """
+ layout = self.layout
+ row = layout.row()
+ row.label("Sels: "+str(len(bpy.selection_osc)))
+ """
+
+
+# =============== DISTRIBUTE ======================
+
+def ObjectDistributeOscurart(self, X, Y, Z):
+ if len(bpy.selection_osc[:]) > 1:
+ # VARIABLES
+ dif = bpy.selection_osc[-1].location - bpy.selection_osc[0].location
+ chunkglobal = dif / (len(bpy.selection_osc[:]) - 1)
+ chunkx = 0
+ chunky = 0
+ chunkz = 0
+ deltafst = bpy.selection_osc[0].location
+
+ # ORDENA
+ for OBJECT in bpy.selection_osc[:]:
+ if X:
+ OBJECT.location.x = deltafst[0] + chunkx
+ if Y:
+ OBJECT.location[1] = deltafst[1] + chunky
+ if Z:
+ OBJECT.location.z = deltafst[2] + chunkz
+ chunkx += chunkglobal[0]
+ chunky += chunkglobal[1]
+ chunkz += chunkglobal[2]
+ else:
+ self.report({'INFO'}, "Needs at least two selected objects")
+
+
+class DialogDistributeOsc(Operator):
+ bl_idname = "object.distribute_osc"
+ bl_label = "Distribute Objects"
+ Boolx = BoolProperty(name="X")
+ Booly = BoolProperty(name="Y")
+ Boolz = BoolProperty(name="Z")
+
+ def execute(self, context):
+ ObjectDistributeOscurart(self, self.Boolx, self.Booly, self.Boolz)
+ return {'FINISHED'}
+
+ def invoke(self, context, event):
+ self.Boolx = True
+ self.Booly = True
+ self.Boolz = True
+ return context.window_manager.invoke_props_dialog(self)
+
+
+# ======================== SET LAYERS TO OTHER SCENES ====================
+
+def DefSetLayersToOtherScenes():
+ actsc = bpy.context.screen.scene
+ for object in bpy.context.selected_objects[:]:
+ bpy.context.screen.scene = actsc
+ lyrs = object.layers[:]
+ for scene in bpy.data.scenes[:]:
+ if object in scene.objects[:]:
+ bpy.context.screen.scene = scene
+ object.layers = lyrs
+ else:
+ print("* %s is not in %s" % (object.name, scene.name))
+
+ bpy.context.screen.scene = actsc
+
+
+class SetLayersToOtherScenes (Operator):
+ bl_idname = "object.set_layers_to_other_scenes"
+ bl_label = "Copy actual Layers to Other Scenes"
+ bl_options = {"REGISTER", "UNDO"}
+
+ def execute(self, context):
+ DefSetLayersToOtherScenes()
+ return {'FINISHED'}
+
+
+# ======================== RENDER OBJECTS IN CAMERA ======================
+
+
+def DefRenderOnlyInCamera():
+ # crea grupos
+ if "INCAMERA" not in bpy.data.groups:
+ bpy.data.groups.new("INCAMERA")
+ if "NOTINCAMERA" not in bpy.data.groups:
+ bpy.data.groups.new("NOTINCAMERA")
+
+ # limpio grupos
+ for ob in bpy.data.objects:
+ if ob.name in bpy.data.groups["INCAMERA"].objects:
+ bpy.data.groups["INCAMERA"].objects.unlink(ob)
+ if ob.name in bpy.data.groups["NOTINCAMERA"].objects:
+ bpy.data.groups["NOTINCAMERA"].objects.unlink(ob)
+
+ # ordeno grupos
+ for ob in bpy.data.objects:
+ obs = False
+ if ob.type == "MESH":
+ tm = ob.to_mesh(bpy.context.scene, True, "RENDER")
+ for vert in tm.vertices:
+ cam = world_to_camera_view(
+ bpy.context.scene,
+ bpy.context.scene.camera,
+ vert.co + ob.location)
+ if cam[0] >= -0 and cam[0] <= 1 and cam[1] >= 0 and cam[1] <= 1:
+ obs = True
+ del(tm)
+ else:
+ obs = True
+ if obs:
+ bpy.data.groups["INCAMERA"].objects.link(ob)
+ else:
+ bpy.data.groups["NOTINCAMERA"].objects.link(ob)
+
+
+class RenderOnlyInCamera (Operator):
+ bl_idname = "group.group_in_out_camera"
+ bl_label = "Make a group for objects in outer camera"
+ bl_options = {"REGISTER", "UNDO"}
+
+ def execute(self, context):
+ DefRenderOnlyInCamera()
+ return {'FINISHED'}
+
+
+# ------------------------ DUPLICATE OBJECTS SYMMETRY ------------------------
+
+def duplicateSymmetrical(self, disconect):
+ for objeto in bpy.context.selected_objects:
+
+ bpy.ops.object.select_all(action='DESELECT')
+ objeto.select = 1
+ bpy.context.scene.objects.active = objeto
+ bpy.ops.object.duplicate(linked=1)
+ OBDUP = bpy.context.active_object
+ print(OBDUP)
+ OBDUP.driver_add("location")
+ OBDUP.animation_data.drivers[0].driver.expression = "-var"
+ OBDUP.animation_data.drivers[0].driver.variables.new()
+ OBDUP.animation_data.drivers[0].driver.variables[0].type = "TRANSFORMS"
+ OBDUP.animation_data.drivers[
+ 0].driver.variables[
+ 0].targets[
+ 0].id = objeto
+ OBDUP.animation_data.drivers[
+ 0].driver.variables[
+ 0].targets[
+ 0].transform_type = 'LOC_X'
+ OBDUP.animation_data.drivers[1].driver.expression = "var"
+ OBDUP.animation_data.drivers[1].driver.variables.new()
+ OBDUP.animation_data.drivers[1].driver.variables[0].type = "TRANSFORMS"
+ OBDUP.animation_data.drivers[
+ 1].driver.variables[
+ 0].targets[
+ 0].id = objeto
+ OBDUP.animation_data.drivers[
+ 1].driver.variables[
+ 0].targets[
+ 0].transform_type = 'LOC_Y'
+ OBDUP.animation_data.drivers[2].driver.expression = "var"
+ OBDUP.animation_data.drivers[2].driver.variables.new()
+ OBDUP.animation_data.drivers[2].driver.variables[0].type = "TRANSFORMS"
+ OBDUP.animation_data.drivers[
+ 2].driver.variables[
+ 0].targets[
+ 0].id = objeto
+ OBDUP.animation_data.drivers[
+ 2].driver.variables[
+ 0].targets[
+ 0].transform_type = 'LOC_Z'
+ OBDUP.driver_add("scale")
+ OBDUP.animation_data.drivers[3].driver.expression = "-var"
+ OBDUP.animation_data.drivers[3].driver.variables.new()
+ OBDUP.animation_data.drivers[3].driver.variables[0].type = "TRANSFORMS"
+ OBDUP.animation_data.drivers[
+ 3].driver.variables[
+ 0].targets[
+ 0].id = objeto
+ OBDUP.animation_data.drivers[
+ 3].driver.variables[
+ 0].targets[
+ 0].transform_type = 'SCALE_X'
+ OBDUP.animation_data.drivers[4].driver.expression = "var"
+ OBDUP.animation_data.drivers[4].driver.variables.new()
+ OBDUP.animation_data.drivers[4].driver.variables[0].type = "TRANSFORMS"
+ OBDUP.animation_data.drivers[
+ 4].driver.variables[
+ 0].targets[
+ 0].id = objeto
+ OBDUP.animation_data.drivers[
+ 4].driver.variables[
+ 0].targets[
+ 0].transform_type = 'SCALE_Y'
+ OBDUP.animation_data.drivers[5].driver.expression = "var"
+ OBDUP.animation_data.drivers[5].driver.variables.new()
+ OBDUP.animation_data.drivers[5].driver.variables[0].type = "TRANSFORMS"
+ OBDUP.animation_data.drivers[
+ 5].driver.variables[
+ 0].targets[
+ 0].id = objeto
+ OBDUP.animation_data.drivers[
+ 5].driver.variables[
+ 0].targets[
+ 0].transform_type = 'SCALE_Z'
+ OBDUP.driver_add("rotation_euler")
+ OBDUP.animation_data.drivers[6].driver.expression = "var"
+ OBDUP.animation_data.drivers[6].driver.variables.new()
+ OBDUP.animation_data.drivers[6].driver.variables[0].type = "TRANSFORMS"
+ OBDUP.animation_data.drivers[
+ 6].driver.variables[
+ 0].targets[
+ 0].id = objeto
+ OBDUP.animation_data.drivers[
+ 6].driver.variables[
+ 0].targets[
+ 0].transform_type = 'ROT_X'
+ OBDUP.animation_data.drivers[7].driver.expression = "-var"
+ OBDUP.animation_data.drivers[7].driver.variables.new()
+ OBDUP.animation_data.drivers[7].driver.variables[0].type = "TRANSFORMS"
+ OBDUP.animation_data.drivers[
+ 7].driver.variables[
+ 0].targets[
+ 0].id = objeto
+ OBDUP.animation_data.drivers[
+ 7].driver.variables[
+ 0].targets[
+ 0].transform_type = 'ROT_Y'
+ OBDUP.animation_data.drivers[8].driver.expression = "-var"
+ OBDUP.animation_data.drivers[8].driver.variables.new()
+ OBDUP.animation_data.drivers[8].driver.variables[0].type = "TRANSFORMS"
+ OBDUP.animation_data.drivers[
+ 8].driver.variables[
+ 0].targets[
+ 0].id = objeto
+ OBDUP.animation_data.drivers[
+ 8].driver.variables[
+ 0].targets[
+ 0].transform_type = 'ROT_Z'
+
+ if disconect is not True:
+ bpy.ops.object.make_single_user(obdata=True, object=True)
+ bpy.context.active_object.driver_remove("location")
+ bpy.context.active_object.driver_remove("rotation_euler")
+ bpy.context.active_object.driver_remove("scale")
+
+
+class oscDuplicateSymmetricalOp(Operator):
+ bl_idname = "object.duplicate_object_symmetry_osc"
+ bl_label = "Oscurart Duplicate Symmetrical"
+ bl_options = {"REGISTER", "UNDO"}
+
+ desconecta = BoolProperty(name="Keep Connection", default=True)
+
+ def execute(self, context):
+
+ duplicateSymmetrical(self, self.desconecta)
+
+ return {'FINISHED'}
+
+
+# ------------------------ OBJECTS TO GROUPS ------------------------
+
+def DefObjectToGroups():
+ scgr = bpy.data.groups.new(
+ "%s_MSH" %
+ (os.path.basename(bpy.data.filepath).replace(".blend", "")))
+ for ob in bpy.data.objects:
+ if ob.type == "MESH":
+ gr = bpy.data.groups.new(ob.name)
+ gr.objects.link(ob)
+ scgr.objects.link(ob)
+
+
+class ObjectsToGroups(Operator):
+ bl_idname = "object.objects_to_groups"
+ bl_label = "Objects to Groups"
+ bl_options = {"REGISTER", "UNDO"}
+
+ def execute(self, context):
+ DefObjectToGroups()
+ return {'FINISHED'}
diff --git a/oscurart_tools/oscurart_render.py b/oscurart_tools/oscurart_render.py
new file mode 100644
index 00000000..a20aafee
--- /dev/null
+++ b/oscurart_tools/oscurart_render.py
@@ -0,0 +1,399 @@
+# ##### 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 #####
+
+# <pep8 compliant>
+
+import bpy
+from bpy.types import (
+ Operator,
+ Panel,
+ )
+import os
+
+
+# -------------------------------- RENDER ALL SCENES ---------------------
+
+def defRenderAll(frametype, scenes):
+
+ activescene = bpy.context.scene
+ FC = bpy.context.scene.frame_current
+ FS = bpy.context.scene.frame_start
+ FE = bpy.context.scene.frame_end
+ print("---------------------")
+ types = {'MESH', 'META', 'CURVE'}
+
+ for ob in bpy.data.objects:
+ if ob.type in types:
+ if not len(ob.material_slots):
+ ob.data.materials.append(None)
+
+ slotlist = {ob: [sl.material for sl in ob.material_slots]
+ for ob in bpy.data.objects if ob.type in types if len(ob.material_slots)}
+
+ for scene in scenes:
+ renpath = scene.render.filepath
+
+ if frametype:
+ scene.frame_start = FC
+ scene.frame_end = FC
+ scene.frame_end = FC
+ scene.frame_start = FC
+
+ filename = os.path.basename(bpy.data.filepath.rpartition(".")[0])
+ uselayers = {layer: layer.use for layer in scene.render.layers}
+ for layer, usado in uselayers.items():
+ if usado:
+ for i in scene.render.layers:
+ i.use = False
+ layer.use = 1
+ print("SCENE: %s" % scene.name)
+ print("LAYER: %s" % layer.name)
+ scene.render.filepath = os.path.join(
+ os.path.dirname(renpath), filename, scene.name, layer.name, "%s_%s_%s" %
+ (filename, scene.name, layer.name))
+ bpy.context.window.screen.scene = scene
+ bpy.ops.render.render(
+ animation=True,
+ write_still=True,
+ layer=layer.name,
+ scene=scene.name)
+ print("DONE")
+ print("---------------------")
+ for layer, usado in uselayers.items():
+ layer.use = usado
+ scene.render.filepath = renpath
+ for ob, slots in slotlist.items():
+ ob.data.materials.clear()
+ for slot in slots:
+ ob.data.materials.append(slot)
+ if frametype:
+ scene.frame_start = FS
+ scene.frame_end = FE
+ scene.frame_end = FE
+ scene.frame_start = FS
+
+ bpy.context.window.screen.scene = activescene
+
+
+class renderAll (Operator):
+ bl_idname = "render.render_all_scenes_osc"
+ bl_label = "Render All Scenes"
+
+ frametype = bpy.props.BoolProperty(default=False)
+
+ def execute(self, context):
+ defRenderAll(self.frametype, [scene for scene in bpy.data.scenes])
+ return {'FINISHED'}
+
+
+# --------------------------------RENDER SELECTED SCENES------------------
+
+class renderSelected (Operator):
+ bl_idname = "render.render_selected_scenes_osc"
+ bl_label = "Render Selected Scenes"
+
+ frametype = bpy.props.BoolProperty(default=False)
+
+ def execute(self, context):
+ defRenderAll(
+ self.frametype,
+ [sc for sc in bpy.data.scenes if sc.oscurart.use_render_scene])
+ return {'FINISHED'}
+
+
+# --------------------------------RENDER CURRENT SCENE--------------------
+
+class renderCurrent (Operator):
+ bl_idname = "render.render_current_scene_osc"
+ bl_label = "Render Current Scene"
+
+ frametype = bpy.props.BoolProperty(default=False)
+
+ def execute(self, context):
+
+ defRenderAll(self.frametype, [bpy.context.scene])
+
+ return {'FINISHED'}
+
+
+# --------------------------RENDER CROP----------------------
+
+def OscRenderCropFunc():
+
+ SCENENAME = os.path.split(bpy.data.filepath)[-1].partition(".")[0]
+ rcParts = bpy.context.scene.oscurart.rcPARTS
+ # don't divide by zero
+ PARTS = (rcParts if rcParts and rcParts > 0 else 1)
+ CHUNKYSIZE = 1 / PARTS
+ FILEPATH = bpy.context.scene.render.filepath
+ bpy.context.scene.render.use_border = True
+ bpy.context.scene.render.use_crop_to_border = True
+ for PART in range(PARTS):
+ bpy.context.scene.render.border_min_y = PART * CHUNKYSIZE
+ bpy.context.scene.render.border_max_y = (
+ PART * CHUNKYSIZE) + CHUNKYSIZE
+ bpy.context.scene.render.filepath = "%s_part%s" % (
+ os.path.join(FILEPATH,
+ SCENENAME,
+ bpy.context.scene.name,
+ SCENENAME),
+ PART
+ )
+ bpy.ops.render.render(animation=False, write_still=True)
+
+ bpy.context.scene.render.filepath = FILEPATH
+
+
+class renderCrop (Operator):
+ bl_idname = "render.render_crop_osc"
+ bl_label = "Render Crop: Render!"
+
+ def execute(self, context):
+ OscRenderCropFunc()
+ return {'FINISHED'}
+
+
+# ---------------------------------- BROKEN FRAMES ---------------------
+
+class SumaFile(Operator):
+ bl_idname = "object.add_broken_file"
+ bl_label = "Add Broken Files"
+
+ def execute(self, context):
+ os.chdir(os.path.dirname(bpy.data.filepath))
+ absdir = os.path.join(
+ os.path.dirname(bpy.data.filepath),
+ bpy.context.scene.render.filepath.replace(r"//",
+ ""))
+ for root, folder, files in os.walk(absdir):
+ for f in files:
+ if os.path.getsize(os.path.join(root, f)) < 10:
+ print(f)
+ i = bpy.context.scene.broken_files.add()
+ i.filename = f
+ i.fullpath = os.path.join(root, f)
+ i.value = os.path.getsize(os.path.join(root, f))
+ i.checkbox = True
+ return {'FINISHED'}
+
+
+class ClearFile(Operator):
+ bl_idname = "object.clear_broken_file"
+ bl_label = "Clear Broken Files"
+
+ def execute(self, context):
+ bpy.context.scene.broken_files.clear()
+ return {'FINISHED'}
+
+
+class DeleteFiles(Operator):
+ bl_idname = "object.delete_broken_file"
+ bl_label = "Delete Broken Files"
+
+ def execute(self, context):
+ for file in bpy.context.scene.broken_files:
+ if file.checkbox:
+ os.remove(file.fullpath)
+ bpy.context.scene.broken_files.clear()
+ return {'FINISHED'}
+
+
+class BrokenFramesPanel(Panel):
+ bl_label = "Oscurart Broken Render Files"
+ bl_idname = "OBJECT_PT_osc_broken_files"
+ bl_space_type = 'PROPERTIES'
+ bl_region_type = 'WINDOW'
+ bl_context = "render"
+
+ def draw(self, context):
+ layout = self.layout
+ col = layout.column(align=1)
+
+ for i in bpy.context.scene.broken_files:
+ colrow = col.row(align=1)
+ colrow.prop(i, "filename")
+ colrow.prop(i, "value")
+ colrow.prop(i, "checkbox")
+
+ col = layout.column(align=1)
+ colrow = col.row(align=1)
+ colrow.operator("object.add_broken_file")
+ colrow.operator("object.clear_broken_file")
+ colrow = col.row(align=1)
+ colrow.operator("object.delete_broken_file")
+
+
+# --------------------------------COPY RENDER SETTINGS--------------------
+
+def defCopyRenderSettings(mode):
+
+ sc = bpy.context.scene
+ sceneslist = bpy.data.scenes[:]
+ sceneslist.remove(sc)
+
+ excludes = {
+ 'name',
+ 'objects',
+ 'object_bases',
+ 'has_multiple_engines',
+ 'display_settings',
+ 'broken_files',
+ 'rna_type',
+ 'frame_subframe',
+ 'view_settings',
+ 'tool_settings',
+ 'render',
+ 'user_clear',
+ 'animation_data_create',
+ 'collada_export',
+ 'keying_sets',
+ 'icon_props',
+ 'image_settings',
+ 'library',
+ 'bake',
+ 'active_layer',
+ 'frame_current_final',
+ 'sequence_editor_clear',
+ 'rigidbody_world',
+ 'unit_settings',
+ 'orientations',
+ '__slots__',
+ 'ray_cast',
+ 'sequencer_colorspace_settings',
+ 'ffmpeg',
+ 'is_movie_format',
+ 'frame_path',
+ 'frame_set',
+ 'network_render',
+ 'animation_data_clear',
+ 'is_nla_tweakmode',
+ 'keying_sets_all',
+ 'sequence_editor',
+ '__doc__',
+ 'file_extension',
+ 'users',
+ 'node_tree',
+ 'is_updated_data',
+ 'bl_rna',
+ 'is_library_indirect',
+ 'cycles_curves',
+ 'timeline_markers',
+ 'statistics',
+ 'use_shading_nodes',
+ 'use_game_engine',
+ 'sequence_editor_create',
+ 'is_updated',
+ '__module__',
+ 'update_tag',
+ 'update',
+ 'animation_data',
+ 'cycles',
+ 'copy',
+ 'game_settings',
+ 'layers',
+ '__weakref__',
+ 'string',
+ 'double',
+ 'use_render_scene',
+ 'engine',
+ 'use_nodes',
+ 'world'}
+
+ if mode == "render":
+ scenerenderdict = {}
+ scenedict = {}
+ sceneimagesettingdict = {}
+ for prop in dir(bpy.context.scene.render):
+ if prop not in excludes:
+ try:
+ scenerenderdict[prop] = getattr(
+ bpy.context.scene.render, prop)
+ except:
+ print("%s does not exist." % (prop))
+
+ for prop in dir(bpy.context.scene):
+ if prop not in excludes:
+ try:
+ scenedict[prop] = getattr(bpy.context.scene, prop)
+ except:
+ print("%s does not exist." % (prop))
+
+ for prop in dir(bpy.context.scene.render.image_settings):
+ if prop not in excludes:
+ try:
+ sceneimagesettingdict[prop] = getattr(
+ bpy.context.scene.render.image_settings,
+ prop)
+ except:
+ print("%s does not exist." % (prop))
+
+ # render
+ for escena in sceneslist:
+ for prop, value in scenerenderdict.items():
+ try:
+ setattr(escena.render, prop, value)
+ except:
+ print("%s was not copied!" % (prop))
+ pass
+ # scene
+ for escena in sceneslist:
+ for prop, value in scenedict.items():
+ try:
+ setattr(escena, prop, value)
+ except:
+ print("%s was not copied!" % (prop))
+ pass
+ # imageSettings
+ for escena in sceneslist:
+ for prop, value in sceneimagesettingdict.items():
+ try:
+ setattr(escena.render.image_settings, prop, value)
+ except:
+ print("%s was not copied!" % (prop))
+ pass
+
+ if mode == "cycles":
+ scenecyclesdict = {}
+ for prop in dir(bpy.context.scene.cycles):
+ if prop not in excludes:
+ try:
+ scenecyclesdict[prop] = getattr(
+ bpy.context.scene.cycles, prop)
+ except:
+ print("%s does not exist." % (prop))
+ # cycles
+ for escena in sceneslist:
+ for prop, value in scenecyclesdict.items():
+ try:
+ setattr(escena.cycles, prop, value)
+ except:
+ print("%s was not copied!" % (prop))
+ pass
+
+
+class copyRenderSettings(Operator):
+ bl_idname = "render.copy_render_settings_osc"
+ bl_label = "Copy Render Settings"
+
+ mode = bpy.props.StringProperty(default="")
+
+ def execute(self, context):
+
+ defCopyRenderSettings(self.mode)
+
+ return {'FINISHED'}
diff --git a/oscurart_tools/oscurart_shapes.py b/oscurart_tools/oscurart_shapes.py
new file mode 100644
index 00000000..10bbd22e
--- /dev/null
+++ b/oscurart_tools/oscurart_shapes.py
@@ -0,0 +1,469 @@
+# ##### 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 #####
+
+# <pep8 compliant>
+
+import bpy
+from bpy.types import Operator
+from bpy.props import (
+ BoolProperty,
+ FloatProperty,
+ )
+import math
+
+
+# ---------------------CREATE SHAPES----------------
+
+def DefSplitShapes(self, ACTIVESHAPE, LAYOUTCOMPAT):
+ bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
+
+ ACTOBJ = bpy.context.active_object
+ has_keys = hasattr(getattr(ACTOBJ.data, "shape_keys", None), "key_blocks")
+ if has_keys:
+ INDEX = ACTOBJ.active_shape_key_index
+
+ if LAYOUTCOMPAT:
+ for SHAPE in ACTOBJ.data.shape_keys.key_blocks:
+ if len(SHAPE.name) > 7:
+ SHAPE.name = SHAPE.name[:8]
+
+ if ACTIVESHAPE:
+ ACTOBJ.active_shape_key_index = INDEX
+ AS = ACTOBJ.active_shape_key
+ AS.value = 1
+ SHAPE = ACTOBJ.shape_key_add(name=AS.name[:8] + "_L", from_mix=True)
+ SHAPE.vertex_group = "_L"
+ SHAPE2 = ACTOBJ.shape_key_add(name=AS.name[:8] + "_R", from_mix=True)
+ SHAPE2.vertex_group = "_R"
+ bpy.ops.object.shape_key_clear()
+ else:
+ for SHAPE in ACTOBJ.data.shape_keys.key_blocks[1:]:
+ SHAPE.value = 1
+ SHAPE1 = ACTOBJ.shape_key_add(
+ name=SHAPE.name[:8] + "_L",
+ from_mix=True)
+ SHAPE1.vertex_group = "_L"
+ SHAPE2 = ACTOBJ.shape_key_add(
+ name=SHAPE.name[:8] + "_R",
+ from_mix=True)
+ SHAPE2.vertex_group = "_R"
+ bpy.ops.object.shape_key_clear()
+ ACTOBJ.active_shape_key_index = INDEX
+
+ return has_keys
+
+
+class CreaShapes(Operator):
+ bl_idname = "mesh.split_lr_shapes_osc"
+ bl_label = "Split LR Shapes"
+ bl_options = {"REGISTER", "UNDO"}
+
+ @classmethod
+ def poll(cls, context):
+ return (context.active_object is not None and
+ context.active_object.type in
+ {'MESH', 'SURFACE', 'CURVE'})
+
+ activeshape = BoolProperty(
+ name="Only Active Shape",
+ default=False
+ )
+ layoutcompat = BoolProperty(
+ name="Layout Compatible",
+ default=True
+ )
+
+ def execute(self, context):
+
+ is_done = DefSplitShapes(self, self.activeshape,
+ self.layoutcompat)
+ if not is_done:
+ self.report({'INFO'}, message="Active object doesn't have shape keys")
+ return {'CANCELLED'}
+
+ return {'FINISHED'}
+
+
+# ----------------------------SHAPES LAYOUT-----------------------
+
+class CreaShapesLayout(Operator):
+ bl_idname = "mesh.create_symmetrical_layout_osc"
+ bl_label = "Symmetrical Layout"
+ bl_options = {"REGISTER", "UNDO"}
+
+ @classmethod
+ def poll(cls, context):
+ return (context.active_object is not None and
+ context.active_object.type in
+ {'MESH', 'SURFACE', 'CURVE'})
+
+ def execute(self, context):
+
+ SEL_OBJ = bpy.context.active_object
+ has_keys = hasattr(getattr(SEL_OBJ.data, "shape_keys", None), "key_blocks")
+ if has_keys:
+ LISTA_KEYS = bpy.context.active_object.data.shape_keys.key_blocks[1:]
+
+ EDITMODE = "bpy.ops.object.mode_set(mode='EDIT')"
+ OBJECTMODE = "bpy.ops.object.mode_set(mode='OBJECT')"
+ POSEMODE = "bpy.ops.object.mode_set(mode='POSE')"
+
+ amt = bpy.data.armatures.new("ArmatureData")
+ ob = bpy.data.objects.new("RIG_LAYOUT_" + SEL_OBJ.name, amt)
+
+ scn = bpy.context.scene
+ scn.objects.link(ob)
+ scn.objects.active = ob
+ ob.select = True
+
+ verticess = [(-1, 1, 0), (1, 1, 0), (1, -1, 0), (-1, -1, 0)]
+ edgess = [(0, 1), (1, 2), (2, 3), (3, 0)]
+ mesh = bpy.data.meshes.new("%s_data_container" % (SEL_OBJ))
+ object = bpy.data.objects.new("GRAPHIC_CONTAINER", mesh)
+ bpy.context.scene.objects.link(object)
+ mesh.from_pydata(verticess, edgess, [])
+
+ gx = 0
+ gy = 0
+
+ for keyblock in LISTA_KEYS:
+ if keyblock.name[-2:] != "_L":
+ if keyblock.name[-2:] != "_R":
+
+ scn.objects.active = ob
+ eval(EDITMODE)
+
+ bone = amt.edit_bones.new(keyblock.name)
+ bone.head = (gx, 0, 0)
+ bone.tail = (gx, 0, 1)
+
+ bonectrl = amt.edit_bones.new(keyblock.name + "_CTRL")
+ bonectrl.head = (gy, 0, 0)
+ bonectrl.tail = (gy, 0, 0.2)
+
+ ob.data.edit_bones[
+ bonectrl.name].parent = ob.data.edit_bones[
+ bone.name]
+ bpy.context.scene.objects.active = ob
+
+ for SIDE in ["L", "R"]:
+ DR = SEL_OBJ.data.shape_keys.key_blocks[
+ keyblock.name + "_" + SIDE].driver_add("value")
+ if SIDE == "L":
+ DR.driver.expression = "var+var_001"
+ else:
+ DR.driver.expression = "-var+var_001"
+ VAR1 = DR.driver.variables.new()
+ VAR2 = DR.driver.variables.new()
+
+ VAR1.targets[0].id = ob
+ VAR1.type = 'TRANSFORMS'
+ VAR1.targets[0].bone_target = bonectrl.name
+ VAR1.targets[0].transform_space = "LOCAL_SPACE"
+ VAR1.targets[0].transform_type = "LOC_X"
+ VAR2.targets[0].id = ob
+ VAR2.type = 'TRANSFORMS'
+ VAR2.targets[0].bone_target = bonectrl.name
+ VAR2.targets[0].transform_space = "LOCAL_SPACE"
+ VAR2.targets[0].transform_type = "LOC_Y"
+
+ eval(POSEMODE)
+
+ ob.pose.bones[keyblock.name].custom_shape = object
+ ob.pose.bones[
+ keyblock.name +
+ "_CTRL"].custom_shape = object
+ CNS = ob.pose.bones[
+ keyblock.name +
+ "_CTRL"].constraints.new(
+ type='LIMIT_LOCATION')
+ CNS.min_x = -1
+ CNS.use_min_x = 1
+ CNS.min_z = 0
+ CNS.use_min_z = 1
+ CNS.min_y = -1
+ CNS.use_min_y = 1
+ CNS.max_x = 1
+ CNS.use_max_x = 1
+ CNS.max_z = 0
+ CNS.use_max_z = 1
+ CNS.max_y = 1
+ CNS.use_max_y = 1
+ CNS.owner_space = "LOCAL"
+ CNS.use_transform_limit = True
+
+ eval(OBJECTMODE)
+
+ bpy.ops.object.text_add(location=(gx, 0, 0))
+ gx = gx + 2.2
+ gy = gy + 2.2
+ texto = bpy.context.object
+
+ texto.data.body = keyblock.name
+ texto.name = "TEXTO_" + keyblock.name
+
+ texto.rotation_euler[0] = math.pi / 2
+ texto.location.x = -1
+ texto.location.z = -1
+ texto.data.size = .2
+
+ CNS = texto.constraints.new(type="COPY_LOCATION")
+ CNS.target = ob
+ CNS.subtarget = ob.pose.bones[keyblock.name].name
+ CNS.use_offset = True
+ else:
+ self.report({'INFO'}, message="Active object doesn't have shape keys")
+ return {'CANCELLED'}
+
+ return {'FINISHED'}
+
+
+# ----------------------------CREATE LMR GROUPS-------------------
+
+def createLMRGroups(self, FACTORVG, ADDVG):
+ bpy.context.window.screen.scene.tool_settings.mesh_select_mode = (
+ True, False, False)
+
+ ACTOBJ = bpy.context.active_object
+ bpy.ops.object.mode_set(mode="EDIT", toggle=False)
+ bpy.ops.mesh.select_all(action='DESELECT')
+ bpy.ops.object.mode_set(mode="OBJECT")
+ GRUPOS = ["_L", "_R"]
+ MIRRORINDEX = 0
+
+ for LADO in GRUPOS:
+ if MIRRORINDEX == 0:
+ bpy.ops.object.vertex_group_add()
+ bpy.ops.object.mode_set(mode='EDIT', toggle=False)
+ bpy.ops.mesh.select_all(action='SELECT')
+ bpy.ops.object.vertex_group_assign()
+ bpy.ops.mesh.select_all(action='DESELECT')
+ bpy.ops.object.mode_set(mode='WEIGHT_PAINT', toggle=False)
+ for VERTICE in ACTOBJ.data.vertices:
+ VERTICE.groups[-1].weight = (VERTICE.co[0] * FACTORVG) + ADDVG
+ ACTOBJ.vertex_groups[-1].name = LADO
+ else:
+ bpy.ops.object.vertex_group_add()
+ bpy.ops.object.mode_set(mode='EDIT', toggle=False)
+ bpy.ops.mesh.select_all(action='SELECT')
+ bpy.ops.object.vertex_group_assign()
+ bpy.ops.mesh.select_all(action='DESELECT')
+ bpy.ops.object.mode_set(mode='WEIGHT_PAINT', toggle=False)
+ for VERTICE in ACTOBJ.data.vertices:
+ VERTICE.groups[-1].weight = (-VERTICE.co[0] * FACTORVG) + ADDVG
+ ACTOBJ.vertex_groups[-1].name = LADO
+ MIRRORINDEX += 1
+
+ ACTOBJ.vertex_groups.active_index = len(ACTOBJ.vertex_groups)
+
+
+class CreaGrupos(Operator):
+ bl_idname = "mesh.create_lmr_groups_osc"
+ bl_label = "Create Mix groups"
+ bl_description = "Create Mix groups"
+ bl_options = {'REGISTER', 'UNDO'}
+
+ FACTORVG = FloatProperty(
+ name="Factor",
+ default=1,
+ min=0,
+ max=1000
+ )
+ ADDVG = FloatProperty(
+ name="Addition",
+ default=.5,
+ min=0,
+ max=1000
+ )
+
+ @classmethod
+ def poll(cls, context):
+ return (context.active_object is not None and
+ context.active_object.type == 'MESH')
+
+ def execute(self, context):
+
+ createLMRGroups(self, self.FACTORVG, self.ADDVG)
+
+ return {'FINISHED'}
+
+
+# ------------------------ SHAPES LAYOUT SYMMETRICA ------------------------
+
+class CreateLayoutAsymmetrical(Operator):
+ bl_idname = "mesh.create_asymmetrical_layout_osc"
+ bl_label = "Asymmetrical Layout"
+ bl_options = {"REGISTER", "UNDO"}
+
+ @classmethod
+ def poll(cls, context):
+ return (context.active_object is not None and
+ context.active_object.type in
+ {'MESH', 'SURFACE', 'CURVE'})
+
+ def execute(self, context):
+
+ SEL_OBJ = bpy.context.active_object
+
+ has_keys = hasattr(getattr(SEL_OBJ.data, "shape_keys", None), "key_blocks")
+ if has_keys:
+ LISTA_KEYS = bpy.context.active_object.data.shape_keys.key_blocks[1:]
+
+ EDITMODE = "bpy.ops.object.mode_set(mode='EDIT')"
+ OBJECTMODE = "bpy.ops.object.mode_set(mode='OBJECT')"
+ POSEMODE = "bpy.ops.object.mode_set(mode='POSE')"
+
+ amtas = bpy.data.armatures.new("ArmatureData")
+ obas = bpy.data.objects.new("RIG_LAYOUT_" + SEL_OBJ.name, amtas)
+
+ scn = bpy.context.scene
+ scn.objects.link(obas)
+ scn.objects.active = obas
+ obas.select = True
+
+ verticess = [(-.1, 1, 0), (.1, 1, 0), (.1, 0, 0), (-.1, 0, 0)]
+ edgess = [(0, 1), (1, 2), (2, 3), (3, 0)]
+ mesh = bpy.data.meshes.new("%s_data_container" % (SEL_OBJ))
+ object = bpy.data.objects.new("GRAPHIC_CONTAINER_AS", mesh)
+ bpy.context.scene.objects.link(object)
+ mesh.from_pydata(verticess, edgess, [])
+
+ eval(EDITMODE)
+ gx = 0
+ gy = 0
+
+ for keyblock in LISTA_KEYS:
+ if keyblock.name[-2:] != "_L":
+ if keyblock.name[-2:] != "_R":
+ scn.objects.active = obas
+ eval(EDITMODE)
+ bone = amtas.edit_bones.new(keyblock.name)
+ bone.head = (gx, 0, 0)
+ bone.tail = (gx, 0, 1)
+
+ bonectrl = amtas.edit_bones.new(keyblock.name + "_CTRL")
+ bonectrl.head = (gy, 0, 0)
+ bonectrl.tail = (gy, 0, 0.2)
+
+ obas.data.edit_bones[
+ bonectrl.name].parent = obas.data.edit_bones[
+ bone.name]
+ bpy.context.scene.objects.active = obas
+
+ bpy.ops.armature.select_all(action="DESELECT")
+
+ DR1 = keyblock.driver_add("value")
+ DR1.driver.expression = "var"
+ VAR2 = DR1.driver.variables.new()
+ VAR2.targets[0].id = obas
+ VAR2.targets[0].bone_target = bonectrl.name
+ VAR2.type = 'TRANSFORMS'
+ VAR2.targets[0].transform_space = "LOCAL_SPACE"
+ VAR2.targets[0].transform_type = "LOC_Y"
+
+ eval(POSEMODE)
+
+ obas.pose.bones[keyblock.name].custom_shape = object
+ obas.pose.bones[
+ keyblock.name +
+ "_CTRL"].custom_shape = object
+
+ bpy.data.objects[
+ "RIG_LAYOUT_" +
+ SEL_OBJ.name].data.bones.active = bpy.data.objects[
+ "RIG_LAYOUT_" +
+ SEL_OBJ.name].data.bones[
+ keyblock.name +
+ "_CTRL"]
+
+ eval(POSEMODE)
+ CNS = obas.pose.bones[
+ keyblock.name +
+ "_CTRL"].constraints.new(
+ type='LIMIT_LOCATION')
+ CNS.min_x = 0
+ CNS.use_min_x = 1
+ CNS.min_z = 0
+ CNS.use_min_z = 1
+ CNS.min_y = 0
+ CNS.use_min_y = 1
+
+ CNS.max_x = 0
+ CNS.use_max_x = 1
+ CNS.max_z = 0
+ CNS.use_max_z = 1
+ CNS.max_y = 1
+ CNS.use_max_y = 1
+
+ CNS.owner_space = "LOCAL"
+ CNS.use_transform_limit = True
+
+ eval(OBJECTMODE)
+
+ bpy.ops.object.text_add(location=(0, 0, 0))
+ gx = gx + 2.2
+ gy = gy + 2.2
+ texto = bpy.context.object
+ texto.data.body = keyblock.name
+ texto.name = "TEXTO_" + keyblock.name
+
+ texto.rotation_euler[0] = math.pi / 2
+ texto.location.x = -.15
+ texto.location.z = -.15
+ texto.data.size = .2
+
+ CNS = texto.constraints.new(type="COPY_LOCATION")
+ CNS.target = obas
+ CNS.subtarget = obas.pose.bones[keyblock.name].name
+ CNS.use_offset = True
+ else:
+ self.report({'INFO'}, message="Active object doesn't have shape keys")
+ return {'CANCELLED'}
+
+ return {'FINISHED'}
+
+
+# ---------------------------SHAPES TO OBJECTS------------------
+
+class ShapeToObjects(Operator):
+ bl_idname = "object.shape_key_to_objects_osc"
+ bl_label = "Shapes To Objects"
+ bl_options = {"REGISTER", "UNDO"}
+
+ @classmethod
+ def poll(cls, context):
+ return (context.active_object is not None and
+ context.active_object.type in
+ {'MESH', 'SURFACE', 'CURVE'})
+
+ def execute(self, context):
+ OBJACT = bpy.context.active_object
+ has_keys = hasattr(getattr(OBJACT.data, "shape_keys", None), "key_blocks")
+ if has_keys:
+ for SHAPE in OBJACT.data.shape_keys.key_blocks[:]:
+ print(SHAPE.name)
+ bpy.ops.object.shape_key_clear()
+ SHAPE.value = 1
+ mesh = OBJACT.to_mesh(bpy.context.scene, True, 'PREVIEW')
+ object = bpy.data.objects.new(SHAPE.name, mesh)
+ bpy.context.scene.objects.link(object)
+ else:
+ self.report({'INFO'}, message="Active object doesn't have shape keys")
+ return {'CANCELLED'}
+
+ return {'FINISHED'}