Add Oscurart Tools for 2.8

This commit is contained in:
Eugenio Pignataro 2018-12-21 11:32:12 -03:00
parent 7fbe716603
commit 1f36b19604
12 changed files with 954 additions and 0 deletions

166
oscurart_tools/__init__.py Normal file
View File

@ -0,0 +1,166 @@
# ##### 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": (4, 0, 0),
"blender": (2, 80, 0),
"location": "View3D > Toolbar and View3D > Specials (W-key)",
"description": "Tools for objects, render, shapes, and files.",
"warning": "",
"wiki_url": "https://wiki.blender.org/index.php/Extensions:2.6/Py/"
"Scripts/3D_interaction/Oscurart_Tools",
"category": "Object",
}
import bpy
from bpy.types import Menu
from oscurart_tools.files import reload_images
from oscurart_tools.files import save_incremental
from oscurart_tools.files import collect_images
from oscurart_tools.mesh import overlap_uvs
from oscurart_tools.mesh import overlap_island
from oscurart_tools.mesh import select_doubles
from oscurart_tools.mesh import shapes_to_objects
from oscurart_tools.object import distribute
from oscurart_tools.object import selection
from oscurart_tools.object import search_and_select
from oscurart_tools.mesh import apply_linked_meshes
from bpy.types import (
AddonPreferences,
Panel,
PropertyGroup,
)
from bpy.props import (
StringProperty,
BoolProperty,
IntProperty,
PointerProperty,
CollectionProperty,
)
# mesh
class VIEW3D_MT_edit_mesh_oscurarttools(Menu):
bl_label = "OscurartTools"
def draw(self, context):
layout = self.layout
layout.operator("mesh.uv_island_copy")
layout.operator("mesh.uv_island_paste")
layout.operator("mesh.select_doubles")
layout.separator()
layout.operator("image.reload_images_osc")
layout.operator("file.save_incremental_backup")
layout.operator("file.collect_all_images")
def menu_funcMesh(self, context):
self.layout.menu("VIEW3D_MT_edit_mesh_oscurarttools")
self.layout.separator()
# image
class IMAGE_MT_uvs_oscurarttools(Menu):
bl_label = "OscurartTools"
def draw(self, context):
layout = self.layout
layout.operator("mesh.uv_island_copy")
layout.operator("mesh.uv_island_paste")
layout.operator("mesh.overlap_uv_faces")
layout.separator()
layout.operator("image.reload_images_osc")
layout.operator("file.save_incremental_backup")
layout.operator("file.collect_all_images")
def menu_funcImage(self, context):
self.layout.menu("IMAGE_MT_uvs_oscurarttools")
self.layout.separator()
# object
class VIEW3D_MT_object_oscurarttools(Menu):
bl_label = "OscurartTools"
def draw(self, context):
layout = self.layout
layout.operator("object.distribute_osc")
layout.operator("object.search_and_select_osc")
layout.operator("object.shape_key_to_objects_osc")
layout.operator("mesh.apply_linked_meshes")
layout.separator()
layout.operator("image.reload_images_osc")
layout.operator("file.save_incremental_backup")
layout.operator("file.collect_all_images")
def menu_funcObject(self, context):
self.layout.menu("VIEW3D_MT_object_oscurarttools")
self.layout.separator()
# ========================= End of Scripts =========================
classes = (
VIEW3D_MT_edit_mesh_oscurarttools,
IMAGE_MT_uvs_oscurarttools,
VIEW3D_MT_object_oscurarttools,
reload_images.reloadImages,
overlap_uvs.CopyUvIsland,
overlap_uvs.PasteUvIsland,
distribute.DistributeOsc,
selection.OscSelection,
save_incremental.saveIncrementalBackup,
collect_images.collectImagesOsc,
overlap_island.OscOverlapUv,
select_doubles.SelectDoubles,
shapes_to_objects.ShapeToObjects,
search_and_select.SearchAndSelectOt,
apply_linked_meshes.ApplyLRT,
)
def register():
from bpy.types import Scene
Scene.multimeshedit = StringProperty()
bpy.types.VIEW3D_MT_edit_mesh_specials.prepend(menu_funcMesh)
bpy.types.IMAGE_MT_specials.prepend(menu_funcImage)
bpy.types.VIEW3D_MT_object_specials.prepend(menu_funcObject)
from bpy.utils import register_class
for cls in classes:
register_class(cls)
def unregister():
del bpy.types.Scene.SearchAndSelectOt
bpy.types.VIEW3D_MT_edit_mesh_specials.remove(menu_funcMesh)
bpy.types.IMAGE_MT_specials.remove(menu_funcImage)
bpy.types.VIEW3D_MT_object_specials.remove(menu_funcObject)
from bpy.utils import unregister_class
for cls in reversed(classes):
unregister_class(cls)
if __name__ == "__main__":
register()

View File

@ -0,0 +1,59 @@
# ##### 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
import os
import shutil
class collectImagesOsc(Operator):
"""Collect all images in the blend file and put them in IMAGES folder"""
bl_idname = "file.collect_all_images"
bl_label = "Collect Images"
bl_options = {"REGISTER", "UNDO"}
def execute(self, context):
imagespath = "%s/IMAGES" % (os.path.dirname(bpy.data.filepath))
if not os.path.exists(imagespath):
os.mkdir(imagespath)
bpy.ops.file.make_paths_absolute()
for image in bpy.data.images:
try:
image.update()
if image.has_data:
if not os.path.exists(os.path.join(imagespath,os.path.basename(image.filepath))):
shutil.copy(image.filepath, os.path.join(imagespath,os.path.basename(image.filepath)))
image.filepath = os.path.join(imagespath,os.path.basename(image.filepath))
else:
print("%s exists." % (image.name))
else:
print("%s missing path." % (image.name))
except:
print("%s missing path." % (image.name))
bpy.ops.file.make_paths_relative()
return {'FINISHED'}

View File

@ -0,0 +1,37 @@
# ##### 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
class reloadImages (Operator):
"""Reloads all bitmaps in the scene"""
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'}

View File

@ -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 bpy.types import Operator
import os
def saveBkp (self, context):
fileFolder = os.path.dirname(bpy.data.filepath)
versionFolder = os.path.join(fileFolder,"VERSIONS")
#creo folder
if os.path.exists(versionFolder):
print("existe")
else:
os.mkdir(versionFolder)
#sin version a versionada
if not bpy.data.filepath.count("_v"):
filelist = [file for file in os.listdir(versionFolder) if file.count("_v") and not file.count("blend1")]
filelower = 0
print(filelist)
for file in filelist:
if int(file.split(".")[0][-2:]) > filelower:
filelower = int(file.split(".")[0][-2:])
savepath = "%s/VERSIONS/%s_v%02d.blend" % (os.path.dirname(bpy.data.filepath),bpy.path.basename(bpy.data.filepath).split('.')[0],filelower+1)
print("Copia versionada guardada.")
bpy.ops.wm.save_as_mainfile()
bpy.ops.wm.save_as_mainfile(filepath=savepath, copy=True)
else:
#versionada a sin version
if bpy.data.filepath.count("_v"):
filename = "%s/../%s.blend" % (os.path.dirname(bpy.data.filepath),os.path.basename(bpy.data.filepath).rpartition(".")[0].rpartition("_")[0])
print(filename)
bpy.ops.wm.save_as_mainfile(filepath=filename, copy=True)
print("Copia sin version guardada.")
class saveIncrementalBackup (bpy.types.Operator):
"""Save incremental backup in versions folder"""
bl_idname = "file.save_incremental_backup"
bl_label = "Save Incremental Backup"
bl_options = {'REGISTER', 'UNDO'}
def execute(self, context):
saveBkp(self, context)
return {'FINISHED'}

View File

@ -0,0 +1,60 @@
# ##### 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
def applyLRTEx(self, context):
actObj = bpy.context.active_object
actObjMatrixWorld = actObj.matrix_world.copy()
bpy.ops.object.select_linked(extend=False, type="OBDATA")
linkedObjects = bpy.context.selected_objects
linkedObjects.remove(actObj)
for vert in actObj.data.vertices:
vert.co = actObjMatrixWorld @ vert.co
actObj.location = (0,0,0)
actObj.rotation_euler = (0,0,0)
actObj.scale = (1,1,1)
for ob in linkedObjects:
ob.matrix_world = ob.matrix_world @ actObj.matrix_world.inverted()
class ApplyLRT(bpy.types.Operator):
"""Apply LRT with linked mesh data"""
bl_idname = "mesh.apply_linked_meshes"
bl_label = "Apply LRT with linked meshes"
bl_options = {"REGISTER", "UNDO"}
@classmethod
def poll(cls, context):
return (context.view_layer.objects.active is not None and
context.view_layer.objects.active.type == 'MESH')
def execute(self, context):
applyLRTEx(self, context)
return {'FINISHED'}

View File

@ -0,0 +1,100 @@
# ##### 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 Vector
from bpy.types import Operator
from bpy.props import (
IntProperty,
BoolProperty,
FloatProperty,
EnumProperty,
)
import bmesh
import time
C = bpy.context
D = bpy.data
def DefOscOverlapUv(self,offset,rotate):
me = bpy.context.object.data
bm = bmesh.from_edit_mesh(me)
bm.faces.ensure_lookup_table()
faces = [face for face in bm.faces if face.select]
uv_layer = bm.loops.layers.uv[bpy.context.object.data.uv_layers.active.name]
faceDict = {}
faceReverse = []
bm.select_mode = {'FACE'}
for face in faces:
bpy.ops.mesh.select_all(action="DESELECT")
face.select = True
bpy.ops.mesh.select_mirror()
faceDict[face.index] = [mirrorface for mirrorface in bm.faces if mirrorface.select][0].index
faceReverse.append([mirrorface for mirrorface in bm.faces if mirrorface.select][0])
for selFace,mirrorFace in faceDict.items():
for loop,mirrorLoop in zip(bm.faces[selFace].loops,bm.faces[mirrorFace].loops):
mirrorLoop.copy_from(loop)
if offset:
for loop,mirrorLoop in zip(bm.faces[selFace].loops,bm.faces[mirrorFace].loops):
mirrorLoop[uv_layer].uv += Vector((1,0))
#invierto direcciones
bmesh.ops.reverse_uvs(bm, faces=[f for f in faceReverse])
bmesh.ops.rotate_uvs(bm, faces=[f for f in faceReverse])
if rotate:
bmesh.ops.rotate_uvs(bm, faces=[f for f in faceReverse])
bmesh.update_edit_mesh(me)
class OscOverlapUv(Operator):
"""Overlaps the uvs on one side of the model symmetry plane. """ \
"""Useful to get more detail on fixed resolution bitmaps"""
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')
offset : BoolProperty(
default=True,
name="Offset"
)
rotate : BoolProperty(
default=False,
name="Rotate"
)
def execute(self, context):
DefOscOverlapUv(self,self.offset,self.rotate)
return {'FINISHED'}

View File

@ -0,0 +1,131 @@
# ##### 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 Vector
from bpy.types import Operator
from bpy.props import (
IntProperty,
BoolProperty,
FloatProperty,
EnumProperty,
)
import os
import bmesh
C = bpy.context
D = bpy.data
# -------------------------- OVERLAP UV ISLANDS
def defCopyUvsIsland(self, context):
bpy.ops.object.mode_set(mode="OBJECT")
global obLoop
global islandFaces
obLoop = []
islandFaces = []
for poly in bpy.context.object.data.polygons:
if poly.select:
islandFaces.append(poly.index)
for li in poly.loop_indices:
obLoop.append(li)
bpy.ops.object.mode_set(mode="EDIT")
def defPasteUvsIsland(self, uvOffset, rotateUv,context):
bpy.ops.object.mode_set(mode="OBJECT")
selPolys = [poly.index for poly in bpy.context.object.data.polygons if poly.select]
for island in selPolys:
bpy.ops.object.mode_set(mode="EDIT")
bpy.ops.mesh.select_all(action="DESELECT")
bpy.ops.object.mode_set(mode="OBJECT")
bpy.context.object.data.polygons[island].select = True
bpy.ops.object.mode_set(mode="EDIT")
bpy.ops.mesh.select_linked()
bpy.ops.object.mode_set(mode="OBJECT")
TobLoop = []
TislandFaces = []
for poly in bpy.context.object.data.polygons:
if poly.select:
TislandFaces.append(poly.index)
for li in poly.loop_indices:
TobLoop.append(li)
for source,target in zip(range(min(obLoop),max(obLoop)+1),range(min(TobLoop),max(TobLoop)+1)):
bpy.context.object.data.uv_layers.active.data[target].uv = bpy.context.object.data.uv_layers.active.data[source].uv + Vector((uvOffset,0))
bpy.ops.object.mode_set(mode="EDIT")
if rotateUv:
bpy.ops.object.mode_set(mode="OBJECT")
for poly in selPolys:
bpy.context.object.data.polygons[poly].select = True
bpy.ops.object.mode_set(mode="EDIT")
bm = bmesh.from_edit_mesh(bpy.context.object.data)
bmesh.ops.reverse_uvs(bm, faces=[f for f in bm.faces if f.select])
bmesh.ops.rotate_uvs(bm, faces=[f for f in bm.faces if f.select])
#bmesh.update_edit_mesh(bpy.context.object.data, tessface=False, destructive=False)
class CopyUvIsland(Operator):
"""Copy Uv Island"""
bl_idname = "mesh.uv_island_copy"
bl_label = "Copy Uv Island"
bl_options = {"REGISTER", "UNDO"}
@classmethod
def poll(cls, context):
return (context.active_object is not None and
context.active_object.type == 'MESH' and
context.active_object.mode == "EDIT")
def execute(self, context):
defCopyUvsIsland(self, context)
return {'FINISHED'}
class PasteUvIsland(Operator):
"""Paste Uv Island"""
bl_idname = "mesh.uv_island_paste"
bl_label = "Paste Uv Island"
bl_options = {"REGISTER", "UNDO"}
uvOffset : BoolProperty(
name="Uv Offset",
default=False
)
rotateUv : BoolProperty(
name="Rotate Uv Corner",
default=False
)
@classmethod
def poll(cls, context):
return (context.active_object is not None and
context.active_object.type == 'MESH' and
context.active_object.mode == "EDIT")
def execute(self, context):
defPasteUvsIsland(self, self.uvOffset, self.rotateUv, context)
return {'FINISHED'}

View File

@ -0,0 +1,76 @@
# ##### 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 Vector
from bpy.types import Operator
from bpy.props import (
IntProperty,
BoolProperty,
FloatProperty,
EnumProperty,
)
import os
import bmesh
C = bpy.context
D = bpy.data
def SelDoubles(self, context):
bm = bmesh.from_edit_mesh(bpy.context.object.data)
for v in bm.verts:
v.select = 0
dictloc = {}
rd = lambda x: (round(x[0], 4), round(x[1], 4), round(x[2], 4))
for vert in bm.verts:
dictloc.setdefault(rd(vert.co), []).append(vert.index)
for loc, ind in dictloc.items():
if len(ind) > 1:
for v in ind:
bm.verts[v].select = 1
bpy.context.view_layer.objects.active = bpy.context.view_layer.objects.active
class SelectDoubles(Operator):
"""Selects duplicated vertex without merge them"""
bl_idname = "mesh.select_doubles"
bl_label = "Select Doubles"
bl_options = {"REGISTER", "UNDO"}
@classmethod
def poll(cls, context):
return (context.view_layer.objects.active is not None and
context.view_layer.objects.active.type == 'MESH' and
context.view_layer.objects.active.mode == "EDIT")
def execute(self, context):
SelDoubles(self, context)
return {'FINISHED'}

View File

@ -0,0 +1,58 @@
# ##### 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
class ShapeToObjects(Operator):
"""It creates a new object for every shapekey in the selected object, ideal to export to other 3D software Apps"""
bl_idname = "object.shape_key_to_objects_osc"
bl_label = "Shapes To Objects"
bl_options = {"REGISTER", "UNDO"}
@classmethod
def poll(cls, context):
return (context.view_layer.objects.active is not None and
context.view_layer.objects.active.type in
{'MESH', 'SURFACE', 'CURVE'})
def execute(self, context):
OBJACT = bpy.context.view_layer.objects.active
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.depsgraph, True, calc_undeformed=False)
object = bpy.data.objects.new(SHAPE.name, mesh)
bpy.context.scene.collection.objects.link(object)
else:
self.report({'INFO'}, message="Active object doesn't have shape keys")
return {'CANCELLED'}
return {'FINISHED'}

View File

@ -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
import os
from bpy.types import Operator
from bpy.props import BoolProperty
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 DistributeOsc(Operator):
"""Distribute evenly the selected objects in x y z"""
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)

View File

@ -0,0 +1,62 @@
# ##### 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
from bpy.props import StringProperty
# ------------------------ SEARCH AND SELECT ------------------------
class SearchAndSelectOt(bpy.types.Operator):
"""Search and select objects, by name"""
bl_idname = "object.search_and_select_osc"
bl_label = "Search And Select"
bl_options = {"REGISTER", "UNDO"}
keyword : StringProperty(name="Keyword", default="Type Here")
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 = self.keyword
if self.start:
if objeto.name.startswith(variableNombre):
objeto.select_set(True)
if self.count:
if objeto.name.count(variableNombre):
objeto.select_set(True)
if self.end:
if objeto.name.count(variableNombre):
objeto.select_set(True)
return {'FINISHED'}
def invoke(self, context, event):
self.keyword = "Type Here"
self.start = True
self.count = True
self.end = True
return context.window_manager.invoke_props_dialog(self)

View File

@ -0,0 +1,65 @@
# ##### 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
# ------------------------------------ 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)))
"""