[Bf-extensions-cvs] SVN commit: /data/svn/bf-extensions [3413] contrib/py/scripts/addons/ space_view3d_enhanced_3d_cursor.py: Use new MeshCache class; added condition to not raycast objects without polygons
dima glib
dima.glib at gmail.com
Mon May 28 15:06:27 CEST 2012
Revision: 3413
http://projects.blender.org/scm/viewvc.php?view=rev&root=bf-extensions&revision=3413
Author: dairin0d
Date: 2012-05-28 13:06:26 +0000 (Mon, 28 May 2012)
Log Message:
-----------
Use new MeshCache class; added condition to not raycast objects without polygons
Modified Paths:
--------------
contrib/py/scripts/addons/space_view3d_enhanced_3d_cursor.py
Modified: contrib/py/scripts/addons/space_view3d_enhanced_3d_cursor.py
===================================================================
--- contrib/py/scripts/addons/space_view3d_enhanced_3d_cursor.py 2012-05-28 05:51:04 UTC (rev 3412)
+++ contrib/py/scripts/addons/space_view3d_enhanced_3d_cursor.py 2012-05-28 13:06:26 UTC (rev 3413)
@@ -2477,7 +2477,8 @@
def __init__(self, scene, shade):
SnapUtilityBase.__init__(self)
- self.cache = MeshCache(scene)
+ convert_types = {'MESH', 'CURVE', 'SURFACE', 'FONT', 'META'}
+ self.cache = MeshCache(scene, convert_types)
# ? seems that dict is enough
self.bbox_cache = {}#collections.OrderedDict()
@@ -2489,13 +2490,10 @@
mesh.update(calc_tessface=True)
#mesh.calc_tessface()
- self.bbox_obj = self.cache.create_temporary_mesh_obj(mesh, Matrix())
+ self.bbox_obj = self.cache._make_obj(mesh, None)
self.bbox_obj.hide = True
self.bbox_obj.draw_type = 'WIRE'
self.bbox_obj.name = "BoundBoxSnap"
- # make it displayable
- #self.cache.scene.objects.link(self.bbox_obj)
- #self.cache.scene.update()
self.shade_bbox = (shade == 'BOUNDBOX')
@@ -2522,7 +2520,7 @@
bpy.data.objects.remove(self.bbox_obj)
bpy.data.meshes.remove(mesh)
- self.cache.dispose()
+ self.cache.clear()
def hide_bbox(self, hide):
if self.bbox_obj.hide == hide:
@@ -2556,7 +2554,8 @@
m_combined = sys_matrix_inv * m
bbox = [None, None]
- mesh_obj = self.cache[obj, True, self.editmode]
+ variant = ('RAW' if self.editmode else 'PREVIEW')
+ mesh_obj = self.cache.get(obj, variant, reuse=False)
if (mesh_obj is None) or self.shade_bbox or \
(obj.draw_type == 'BOUNDS'):
if is_local:
@@ -2644,9 +2643,10 @@
if not is_bbox:
# Ensure we work with raycastable object.
- obj = self.cache[obj, force, edit]
- if obj is None:
- continue # the object has no geometry
+ variant = ('RAW' if edit else 'PREVIEW')
+ obj = self.cache.get(obj, variant, reuse=(not force))
+ if (obj is None) or (not obj.data.polygons):
+ continue # the object has no raycastable geometry
# If ray must be infinite, ensure that
# endpoints are outside of bounding volume
@@ -2887,125 +2887,276 @@
return n
# ====== CONVERTED-TO-MESH OBJECTS CACHE ====== #
-class MeshCache:
- # ====== INITIALIZATION / CLEANUP ====== #
- def __init__(self, scene):
- self.scene = scene
+#============================================================================#
+class ToggleObjectMode:
+ def __init__(self, mode='OBJECT'):
+ if not isinstance(mode, str):
+ mode = ('OBJECT' if mode else None)
- self.mesh_cache = {}
- self.object_cache = {}
- self.edit_object = None
+ self.mode = mode
- def dispose(self):
- if self.edit_object:
- mesh = self.edit_object.data
- bpy.data.objects.remove(self.edit_object)
- bpy.data.meshes.remove(mesh)
- del self.edit_object
+ def __enter__(self):
+ if self.mode:
+ edit_preferences = bpy.context.user_preferences.edit
+
+ self.global_undo = edit_preferences.use_global_undo
+ self.prev_mode = bpy.context.object.mode
+
+ if self.prev_mode != self.mode:
+ edit_preferences.use_global_undo = False
+ bpy.ops.object.mode_set(mode=self.mode)
- for rco in self.object_cache.values():
- if rco:
- bpy.data.objects.remove(rco)
- del self.object_cache
+ return self
- for mesh in self.mesh_cache.values():
- bpy.data.meshes.remove(mesh)
- del self.mesh_cache
+ def __exit__(self, type, value, traceback):
+ if self.mode:
+ edit_preferences = bpy.context.user_preferences.edit
+
+ if self.prev_mode != self.mode:
+ bpy.ops.object.mode_set(mode=self.prev_mode)
+ edit_preferences.use_global_undo = self.global_undo
+
+class MeshCacheItem:
+ def __init__(self):
+ self.variants = {}
- # ====== GET RELEVANT MESH/OBJECT ====== #
- def __convert(self, obj, force=False, apply_modifiers=True, \
- add_to_cache=True):
- # In Edit (and Sculpt?) mode mesh will not reflect
- # changes until mode is changed to Object.
- unstable_shape = ('EDIT' in obj.mode) or ('SCULPT' in obj.mode)
+ def __getitem__(self, variant):
+ return self.variants[variant][0]
+
+ def __setitem__(self, variant, conversion):
+ mesh = conversion[0].data
+ #mesh.update(calc_tessface=True)
+ #mesh.calc_tessface()
+ mesh.calc_normals()
- force = force or (len(obj.modifiers) != 0)
+ self.variants[variant] = conversion
+
+ def __contains__(self, variant):
+ return variant in self.variants
+
+ def dispose(self):
+ for obj, converted in self.variants.values():
+ if converted:
+ mesh = obj.data
+ bpy.data.objects.remove(obj)
+ bpy.data.meshes.remove(mesh)
+ self.variants = None
+
+class MeshCache:
+ """
+ Keeps a cache of mesh equivalents of requested objects.
+ It is assumed that object's data does not change while
+ the cache is in use.
+ """
+
+ variants_enum = {'RAW', 'PREVIEW', 'RENDER'}
+ variants_normalization = {
+ 'MESH':{},
+ 'CURVE':{},
+ 'SURFACE':{},
+ 'FONT':{},
+ 'META':{'RAW':'PREVIEW'},
+ 'ARMATURE':{'RAW':'PREVIEW', 'RENDER':'PREVIEW'},
+ 'LATTICE':{'RAW':'PREVIEW', 'RENDER':'PREVIEW'},
+ 'EMPTY':{'RAW':'PREVIEW', 'RENDER':'PREVIEW'},
+ 'CAMERA':{'RAW':'PREVIEW', 'RENDER':'PREVIEW'},
+ 'LAMP':{'RAW':'PREVIEW', 'RENDER':'PREVIEW'},
+ 'SPEAKER':{'RAW':'PREVIEW', 'RENDER':'PREVIEW'},
+ }
+ conversible_types = {'MESH', 'CURVE', 'SURFACE', 'FONT',
+ 'META', 'ARMATURE', 'LATTICE'}
+ convert_types = conversible_types
+
+ def __init__(self, scene, convert_types=None):
+ self.scene = scene
+ if convert_types:
+ self.convert_types = convert_types
+ self.cached = {}
+
+ def __del__(self):
+ self.clear()
+
+ def clear(self, expect_zero_users=False):
+ for cache_item in self.cached.values():
+ if cache_item:
+ try:
+ cache_item.dispose()
+ except RuntimeError:
+ if expect_zero_users:
+ raise
+ self.cached.clear()
+
+ def __delitem__(self, obj):
+ cache_item = self.cached.pop(obj, None)
+ if cache_item:
+ cache_item.dispose()
+
+ def __contains__(self, obj):
+ return obj in self.cached
+
+ def __getitem__(self, obj):
+ if isinstance(obj, tuple):
+ return self.get(*obj)
+ return self.get(obj)
+
+ def get(self, obj, variant='PREVIEW', reuse=True):
+ if variant not in self.variants_enum:
+ raise ValueError("Mesh variant must be one of %s" %
+ self.variants_enum)
- if (obj.data.bl_rna.name == 'Mesh'):
- if not (force or unstable_shape):
- # Existing mesh actually satisfies us
- return obj
+ # Make sure the variant is proper for this type of object
+ variant = (self.variants_normalization[obj.type].
+ get(variant, variant))
- #if (not force) and (obj.data in self.mesh_cache):
- if obj.data in self.mesh_cache:
- mesh = self.mesh_cache[obj.data]
+ if obj in self.cached:
+ cache_item = self.cached[obj]
+ try:
+ # cache_item is None if object isn't conversible to mesh
+ return (None if (cache_item is None)
+ else cache_item[variant])
+ except KeyError:
+ pass
else:
- if unstable_shape:
- prev_mode = obj.mode
- bpy.ops.object.mode_set(mode='OBJECT')
-
- mesh = obj.to_mesh(self.scene, apply_modifiers, 'PREVIEW')
- mesh.name = tmp_name
-
- if unstable_shape:
- bpy.ops.object.mode_set(mode=prev_mode)
-
- if add_to_cache:
- self.mesh_cache[obj.data] = mesh
+ cache_item = None
- rco = self.create_temporary_mesh_obj(mesh, obj.matrix_world)
- rco.show_x_ray = obj.show_x_ray # necessary for corrent bbox display
+ if obj.type not in self.conversible_types:
+ self.cached[obj] = None
+ return None
- return rco
+ if not cache_item:
+ cache_item = MeshCacheItem()
+ self.cached[obj] = cache_item
+
+ conversion = self._convert(obj, variant, reuse)
+ cache_item[variant] = conversion
+
+ return conversion[0]
- def __getitem__(self, args):
- # If more than one argument is passed to getitem,
- # Python wraps them into tuple.
- if not isinstance(args, tuple):
- args = (args,)
+ def _convert(self, obj, variant, reuse=True):
+ obj_type = obj.type
+ obj_mode = obj.mode
+ data = obj.data
- obj = args[0]
- force = (args[1] if len(args) > 1 else True)
- edit = (args[2] if len(args) > 2 else False)
+ if obj_type == 'MESH':
+ if reuse and ((variant == 'RAW') or (len(obj.modifiers) == 0)):
+ return (obj, False)
+ else:
+ force_objectmode = (obj_mode in ('EDIT', 'SCULPT'))
+ return (self._to_mesh(obj, variant, force_objectmode), True)
+ elif obj_type in ('CURVE', 'SURFACE', 'FONT'):
+ if variant == 'RAW':
+ bm = bmesh.new()
@@ Diff output truncated at 10240 characters. @@
More information about the Bf-extensions-cvs
mailing list