diff options
author | meta-androcto <meta.androcto1@gmail.com> | 2016-08-07 16:34:46 +0300 |
---|---|---|
committer | meta-androcto <meta.androcto1@gmail.com> | 2016-08-07 16:34:46 +0300 |
commit | 3218a23e11dfb9cd3f4fd2421e93a2fdb77a0a66 (patch) | |
tree | c9a9376ea9177f71d2a0b81d95c6d8efa6424e2a /oscurart_tools | |
parent | 84a93440fd5c5ecbe80d7bb9743c1747d0bde3eb (diff) |
initial commit oscurart tools. re: T48708
Diffstat (limited to 'oscurart_tools')
-rw-r--r-- | oscurart_tools/__init__.py | 391 | ||||
-rw-r--r-- | oscurart_tools/oscurart_animation.py | 70 | ||||
-rw-r--r-- | oscurart_tools/oscurart_files.py | 50 | ||||
-rw-r--r-- | oscurart_tools/oscurart_meshes.py | 562 | ||||
-rw-r--r-- | oscurart_tools/oscurart_objects.py | 526 | ||||
-rw-r--r-- | oscurart_tools/oscurart_render.py | 399 | ||||
-rw-r--r-- | oscurart_tools/oscurart_shapes.py | 469 |
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'} |