mesh_snap_utilties_line: Add Gizmos support
This commit is contained in:
parent
afd211e108
commit
1142e21575
|
@ -22,37 +22,40 @@
|
|||
bl_info = {
|
||||
"name": "Snap_Utilities_Line",
|
||||
"author": "Germano Cavalcante",
|
||||
"version": (5, 8, 30),
|
||||
"version": (5, 9, 00),
|
||||
"blender": (2, 80, 0),
|
||||
"location": "View3D > TOOLS > Make Line",
|
||||
"location": "View3D > TOOLS > Line Tool",
|
||||
"description": "Extends Blender Snap controls",
|
||||
#"wiki_url" : "http://blenderartists.org/forum/showthread.php?363859-Addon-CAD-Snap-Utilities",
|
||||
"category": "Mesh"}
|
||||
|
||||
if "bpy" in locals():
|
||||
import importlib
|
||||
importlib.reload(common_classes)
|
||||
importlib.reload(preferences)
|
||||
importlib.reload(ops_line)
|
||||
importlib.reload(common_classes)
|
||||
else:
|
||||
from . import common_classes
|
||||
from . import preferences
|
||||
from . import ops_line
|
||||
|
||||
import bpy
|
||||
from bpy.utils.toolsystem import ToolDef
|
||||
|
||||
if not __package__:
|
||||
__package__ = "mesh_snap_utilities_line"
|
||||
|
||||
@ToolDef.from_fn
|
||||
def tool_make_line():
|
||||
def tool_line():
|
||||
import os
|
||||
def draw_settings(context, layout, tool):
|
||||
addon_prefs = context.preferences.addons["mesh_snap_utilities_line"].preferences
|
||||
addon_prefs = context.preferences.addons[__package__].preferences
|
||||
|
||||
layout.prop(addon_prefs, "incremental")
|
||||
layout.prop(addon_prefs, "increments_grid")
|
||||
if addon_prefs.increments_grid:
|
||||
layout.prop(addon_prefs, "relative_scale")
|
||||
layout.prop(addon_prefs, "create_face")
|
||||
layout.prop(addon_prefs, "outer_verts")
|
||||
if context.mode == 'EDIT_MESH':
|
||||
layout.prop(addon_prefs, "outer_verts")
|
||||
#props = tool.operator_properties("mesh.snap_utilities_line")
|
||||
#layout.prop(props, "radius")
|
||||
|
||||
|
@ -64,9 +67,9 @@ def tool_make_line():
|
|||
"Make Lines\n"
|
||||
"Connect them to split faces"
|
||||
),
|
||||
icon=os.path.join(icons_dir, "ops.mesh.make_line"),
|
||||
#widget="MESH_GGT_mouse_point",
|
||||
operator="mesh.make_line",
|
||||
icon=os.path.join(icons_dir, "ops.mesh.snap_utilities_line"),
|
||||
widget="MESH_GGT_snap_point",
|
||||
#operator="mesh.snap_utilities_line",
|
||||
keymap="3D View Tool: Edit Mesh, Make Line",
|
||||
draw_settings=draw_settings,
|
||||
)
|
||||
|
@ -75,12 +78,13 @@ def tool_make_line():
|
|||
# -----------------------------------------------------------------------------
|
||||
# Tool Registraion
|
||||
|
||||
def km_3d_view_tool_make_line(tool_mouse = 'LEFTMOUSE'):
|
||||
def km_3d_view_snap_tools(tool_mouse = 'LEFTMOUSE'):
|
||||
return [(
|
||||
"3D View Tool: Edit Mesh, Make Line",
|
||||
tool_line.keymap[0],
|
||||
{"space_type": 'VIEW_3D', "region_type": 'WINDOW'},
|
||||
{"items": [
|
||||
("mesh.make_line", {"type": tool_mouse, "value": 'CLICK'}, None),
|
||||
("mesh.snap_utilities_line", {"type": tool_mouse, "value": 'CLICK'},
|
||||
{"properties": [("wait_for_input", False)]}),
|
||||
]},
|
||||
)]
|
||||
|
||||
|
@ -91,67 +95,75 @@ def get_tool_list(space_type, context_mode):
|
|||
return cls._tools[context_mode]
|
||||
|
||||
|
||||
def register_make_line_tool():
|
||||
def register_snap_tools():
|
||||
tools = get_tool_list('VIEW_3D', 'EDIT_MESH')
|
||||
|
||||
for index, tool in enumerate(tools, 1):
|
||||
if isinstance(tool, ToolDef) and tool.text == "Add Cube":
|
||||
if isinstance(tool, ToolDef) and tool.text == "Measure":
|
||||
break
|
||||
|
||||
tools.insert(index, tool_make_line)
|
||||
tools[:index] += None, tool_line
|
||||
|
||||
del tools
|
||||
|
||||
keyconfigs = bpy.context.window_manager.keyconfigs
|
||||
kc_defaultconf = keyconfigs.get("blender")
|
||||
kc_addonconf = keyconfigs.get("blender addon")
|
||||
|
||||
# TODO: find the user defined tool_mouse.
|
||||
keyconfig_data = km_3d_view_tool_make_line()
|
||||
keyconfig_data = km_3d_view_snap_tools()
|
||||
|
||||
# TODO: find the user defined tool_mouse.
|
||||
from bl_keymap_utils.io import keyconfig_init_from_data
|
||||
keyconfig_init_from_data(kc_defaultconf, keyconfig_data)
|
||||
keyconfig_init_from_data(kc_addonconf, keyconfig_data)
|
||||
|
||||
|
||||
def unregister_make_line_tool():
|
||||
def unregister_snap_tools():
|
||||
tools = get_tool_list('VIEW_3D', 'EDIT_MESH')
|
||||
tools.remove(tool_make_line)
|
||||
|
||||
km_name, km_args, km_content = km_3d_view_tool_make_line()[0]
|
||||
index = tools.index(tool_line) - 1 #None
|
||||
tools.pop(index)
|
||||
tools.remove(tool_line)
|
||||
|
||||
del tools
|
||||
del index
|
||||
|
||||
keyconfigs = bpy.context.window_manager.keyconfigs
|
||||
defaultmap = keyconfigs.get("blender").keymaps
|
||||
addonmap = keyconfigs.get("blender addon").keymaps
|
||||
|
||||
addonmap.remove(addonmap.find(km_name, **km_args))
|
||||
defaultmap.remove(defaultmap.find(km_name, **km_args))
|
||||
for keyconfig_data in km_3d_view_snap_tools():
|
||||
km_name, km_args, km_content = keyconfig_data
|
||||
|
||||
addonmap.remove(addonmap.find(km_name, **km_args))
|
||||
defaultmap.remove(defaultmap.find(km_name, **km_args))
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Addon Registraion
|
||||
|
||||
def register():
|
||||
bpy.utils.register_class(preferences.SnapUtilitiesLinePreferences)
|
||||
bpy.utils.register_class(common_classes.VIEW3D_OT_rotate_custom_pivot)
|
||||
bpy.utils.register_class(common_classes.VIEW3D_OT_zoom_custom_target)
|
||||
bpy.utils.register_class(ops_line.SnapUtilitiesLine)
|
||||
#bpy.utils.register_class(common_classes.MousePointWidget)
|
||||
#bpy.utils.register_class(common_classes.MousePointWidgetGroup)
|
||||
classes = (
|
||||
preferences.SnapUtilitiesLinePreferences,
|
||||
ops_line.SnapUtilitiesLine,
|
||||
common_classes.VIEW3D_OT_rotate_custom_pivot,
|
||||
common_classes.VIEW3D_OT_zoom_custom_target,
|
||||
common_classes.SnapPointWidget,
|
||||
common_classes.SnapPointWidgetGroup,
|
||||
)
|
||||
|
||||
register_make_line_tool()
|
||||
def register():
|
||||
for cls in classes:
|
||||
bpy.utils.register_class(cls)
|
||||
|
||||
register_snap_tools()
|
||||
|
||||
|
||||
def unregister():
|
||||
unregister_make_line_tool()
|
||||
unregister_snap_tools()
|
||||
|
||||
#bpy.utils.unregister_class(common_classes.MousePointWidgetGroup)
|
||||
#bpy.utils.unregister_class(common_classes.MousePointWidget)
|
||||
bpy.utils.unregister_class(ops_line.SnapUtilitiesLine)
|
||||
bpy.utils.unregister_class(common_classes.VIEW3D_OT_zoom_custom_target)
|
||||
bpy.utils.unregister_class(common_classes.VIEW3D_OT_rotate_custom_pivot)
|
||||
bpy.utils.unregister_class(preferences.SnapUtilitiesLinePreferences)
|
||||
for cls in reversed(classes):
|
||||
bpy.utils.unregister_class(cls)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
__name__ = "mesh_snap_utilities_line"
|
||||
__package__ = "mesh_snap_utilities_line"
|
||||
register()
|
||||
|
|
|
@ -18,7 +18,13 @@
|
|||
import bpy
|
||||
import bgl
|
||||
|
||||
from .common_utilities import snap_utilities
|
||||
from mathutils import Vector
|
||||
|
||||
from .common_utilities import (
|
||||
convert_distance,
|
||||
get_units_info,
|
||||
snap_utilities,
|
||||
)
|
||||
|
||||
|
||||
class SnapDrawn():
|
||||
|
@ -52,8 +58,6 @@ class SnapDrawn():
|
|||
self._program_smooth_col = gpu.shader.from_builtin("3D_SMOOTH_COLOR")
|
||||
|
||||
self._batch_point = None
|
||||
self._batch_circle = None
|
||||
self._batch_vector = None
|
||||
|
||||
|
||||
def batch_line_strip_create(self, coords):
|
||||
|
@ -171,6 +175,7 @@ class SnapDrawn():
|
|||
gpu.matrix.pop()
|
||||
|
||||
def draw_elem(self, snap_obj, bm, elem):
|
||||
#TODO: Cache coords (because antialiasing)
|
||||
import gpu
|
||||
from bmesh.types import(
|
||||
BMVert,
|
||||
|
@ -332,122 +337,67 @@ class CharMap:
|
|||
'LEFT_ARROW', 'RIGHT_ARROW'
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def modal(self, context, event):
|
||||
c = event.ascii
|
||||
if c:
|
||||
if c == ",":
|
||||
c = "."
|
||||
self.length_entered = self.length_entered[:self.line_pos] + c + self.length_entered[self.line_pos:]
|
||||
self.line_pos += 1
|
||||
if self.length_entered:
|
||||
if event.type == 'BACK_SPACE':
|
||||
self.length_entered = self.length_entered[:self.line_pos - 1] + self.length_entered[self.line_pos:]
|
||||
self.line_pos -= 1
|
||||
def __init__(self, context):
|
||||
scale = context.scene.unit_settings.scale_length
|
||||
separate_units = context.scene.unit_settings.use_separate
|
||||
self.unit_system = context.scene.unit_settings.system
|
||||
self.uinfo = get_units_info(scale, self.unit_system, separate_units)
|
||||
|
||||
elif event.type == 'DEL':
|
||||
self.length_entered = self.length_entered[:self.line_pos] + self.length_entered[self.line_pos + 1:]
|
||||
self.clear()
|
||||
|
||||
elif event.type == 'LEFT_ARROW':
|
||||
self.line_pos = (self.line_pos - 1) % (len(self.length_entered) + 1)
|
||||
def modal_(self, context, event):
|
||||
if event.value == 'PRESS':
|
||||
type = event.type
|
||||
ascii = event.ascii
|
||||
if (type in self.type) or (ascii in self.ascii):
|
||||
if ascii:
|
||||
pos = self.line_pos
|
||||
if ascii == ",":
|
||||
ascii = "."
|
||||
self.length_entered = self.length_entered[:pos] + ascii + self.length_entered[pos:]
|
||||
self.line_pos += 1
|
||||
|
||||
elif event.type == 'RIGHT_ARROW':
|
||||
self.line_pos = (self.line_pos + 1) % (len(self.length_entered) + 1)
|
||||
if self.length_entered:
|
||||
pos = self.line_pos
|
||||
if type == 'BACK_SPACE':
|
||||
self.length_entered = self.length_entered[:pos - 1] + self.length_entered[pos:]
|
||||
self.line_pos -= 1
|
||||
|
||||
g_snap_widget = [None]
|
||||
elif type == 'DEL':
|
||||
self.length_entered = self.length_entered[:pos] + self.length_entered[pos + 1:]
|
||||
|
||||
class MousePointWidget(bpy.types.Gizmo):
|
||||
bl_idname = "VIEW3D_GT_mouse_point"
|
||||
elif type == 'LEFT_ARROW':
|
||||
self.line_pos = (pos - 1) % (len(self.length_entered) + 1)
|
||||
|
||||
__slots__ = (
|
||||
"sctx",
|
||||
"bm",
|
||||
"draw_cache",
|
||||
"geom",
|
||||
"incremental",
|
||||
"preferences",
|
||||
"loc",
|
||||
"snap_obj",
|
||||
"snap_to_grid",
|
||||
"type",
|
||||
)
|
||||
elif type == 'RIGHT_ARROW':
|
||||
self.line_pos = (pos + 1) % (len(self.length_entered) + 1)
|
||||
|
||||
try:
|
||||
self.length_entered_value = bpy.utils.units.to_value(
|
||||
self.unit_system, 'LENGTH', self.length_entered)
|
||||
except: # ValueError:
|
||||
self.length_entered_value = 0.0 #invalid
|
||||
#self.report({'INFO'}, "Operation not supported yet")
|
||||
else:
|
||||
self.length_entered_value = 0.0
|
||||
|
||||
return True
|
||||
|
||||
def test_select(self, context, mval):
|
||||
#print('test_select', mval)
|
||||
self.snap_obj, prev_loc, self.loc, self.type, self.bm, self.geom, len = snap_utilities(
|
||||
self.sctx,
|
||||
None,
|
||||
mval,
|
||||
increment=self.incremental
|
||||
)
|
||||
context.area.tag_redraw()
|
||||
return False
|
||||
|
||||
def draw(self, context):
|
||||
if self.bm:
|
||||
self.draw_cache.draw_elem(self.snap_obj, self.bm, self.geom)
|
||||
self.draw_cache.draw(self.type, self.loc, None, None, None)
|
||||
def get_converted_length_str(self, length):
|
||||
if self.length_entered:
|
||||
pos = self.line_pos
|
||||
ret = self.length_entered[:pos] + '|' + self.length_entered[pos:]
|
||||
else:
|
||||
ret = convert_distance(length, self.uinfo)
|
||||
|
||||
def setup(self):
|
||||
if not hasattr(self, "sctx"):
|
||||
global g_snap_widget
|
||||
g_snap_widget[0] = self
|
||||
return ret
|
||||
|
||||
context = bpy.context
|
||||
|
||||
self.preferences = preferences = context.preferences.addons[__package__].preferences
|
||||
|
||||
#Configure the unit of measure
|
||||
self.snap_to_grid = preferences.increments_grid
|
||||
self.incremental = bpy.utils.units.to_value(
|
||||
context.scene.unit_settings.system, 'LENGTH', str(preferences.incremental))
|
||||
|
||||
self.draw_cache = SnapDrawn(
|
||||
preferences.out_color,
|
||||
preferences.face_color,
|
||||
preferences.edge_color,
|
||||
preferences.vert_color,
|
||||
preferences.center_color,
|
||||
preferences.perpendicular_color,
|
||||
preferences.constrain_shift_color,
|
||||
(*context.preferences.themes[0].user_interface.axis_x, 1.0),
|
||||
(*context.preferences.themes[0].user_interface.axis_y, 1.0),
|
||||
(*context.preferences.themes[0].user_interface.axis_z, 1.0)
|
||||
)
|
||||
|
||||
#Init Snap Context
|
||||
from .snap_context_l import SnapContext
|
||||
from mathutils import Vector
|
||||
|
||||
self.sctx = SnapContext(context.region, context.space_data)
|
||||
self.sctx.set_pixel_dist(12)
|
||||
self.sctx.use_clip_planes(True)
|
||||
|
||||
if preferences.outer_verts:
|
||||
for base in context.visible_bases:
|
||||
self.sctx.add_obj(base.object, base.object.matrix_world)
|
||||
|
||||
self.sctx.set_snap_mode(True, True, True)
|
||||
self.bm = None
|
||||
self.type = 'OUT'
|
||||
self.loc = Vector()
|
||||
|
||||
def __del__(self):
|
||||
global g_snap_widget
|
||||
g_snap_widget[0] = None
|
||||
|
||||
|
||||
class MousePointWidgetGroup(bpy.types.GizmoGroup):
|
||||
bl_idname = "MESH_GGT_mouse_point"
|
||||
bl_label = "Draw Mouse Point"
|
||||
bl_space_type = 'VIEW_3D'
|
||||
bl_region_type = 'WINDOW'
|
||||
bl_options = {'3D'}
|
||||
|
||||
def setup(self, context):
|
||||
snap_widget = self.gizmos.new(MousePointWidget.bl_idname)
|
||||
props = snap_widget.target_set_operator("mesh.make_line")
|
||||
props.wait_for_input = False
|
||||
def clear(self):
|
||||
self.length_entered = ''
|
||||
self.length_entered_value = 0.0
|
||||
self.line_pos = 0
|
||||
|
||||
|
||||
class VIEW3D_OT_rotate_custom_pivot(bpy.types.Operator):
|
||||
|
@ -532,3 +482,292 @@ class VIEW3D_OT_zoom_custom_target(bpy.types.Operator):
|
|||
return {'RUNNING_MODAL'}
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
class SnapUtilities:
|
||||
# __slots__ = (
|
||||
# "sctx",
|
||||
# "draw_cache",
|
||||
# "outer_verts",
|
||||
# "snap_face",
|
||||
# "snap_to_grid",
|
||||
# "unit_system",
|
||||
# "rd",
|
||||
# "incremental",
|
||||
# )
|
||||
|
||||
constrain_keys = {
|
||||
'X': Vector((1,0,0)),
|
||||
'Y': Vector((0,1,0)),
|
||||
'Z': Vector((0,0,1)),
|
||||
'RIGHT_SHIFT': 'shift',
|
||||
'LEFT_SHIFT': 'shift',
|
||||
}
|
||||
|
||||
snap_widget = None
|
||||
snap_widget_refcnt = 0
|
||||
constrain = None
|
||||
|
||||
@staticmethod
|
||||
def set_contrain(context, key):
|
||||
widget = SnapUtilities.snap_widget
|
||||
if SnapUtilities.constrain == key:
|
||||
SnapUtilities.constrain = None
|
||||
return
|
||||
|
||||
SnapUtilities.constrain = key
|
||||
|
||||
|
||||
def visible_objects_and_duplis(self, context):
|
||||
if self.preferences.outer_verts:
|
||||
for obj in context.visible_objects:
|
||||
yield (obj, obj.matrix_world)
|
||||
|
||||
if obj.instance_type == 'COLLECTION':
|
||||
mat = obj.matrix_world.copy()
|
||||
for ob in obj.instance_collection.objects:
|
||||
yield (ob, mat @ ob.matrix_world)
|
||||
else:
|
||||
for obj in context.objects_in_mode_unique_data:
|
||||
yield (obj, obj.matrix_world)
|
||||
|
||||
|
||||
def snap_context_init(self, context, snap_edge_and_vert = True):
|
||||
from .snap_context_l import global_snap_context_get
|
||||
|
||||
#Create Snap Context
|
||||
self.sctx = global_snap_context_get(context.region, context.space_data)
|
||||
self.sctx.set_pixel_dist(12)
|
||||
self.sctx.use_clip_planes(True)
|
||||
|
||||
widget = self.snap_widget
|
||||
|
||||
if widget is not None:
|
||||
self.preferences = widget.preferences
|
||||
self.draw_cache = widget.draw_cache
|
||||
else:
|
||||
preferences = context.preferences.addons[__package__].preferences
|
||||
self.preferences = preferences
|
||||
#Init DrawCache
|
||||
self.draw_cache = SnapDrawn(
|
||||
preferences.out_color,
|
||||
preferences.face_color,
|
||||
preferences.edge_color,
|
||||
preferences.vert_color,
|
||||
preferences.center_color,
|
||||
preferences.perpendicular_color,
|
||||
preferences.constrain_shift_color,
|
||||
tuple(context.preferences.themes[0].user_interface.axis_x) + (1.0,),
|
||||
tuple(context.preferences.themes[0].user_interface.axis_y) + (1.0,),
|
||||
tuple(context.preferences.themes[0].user_interface.axis_z) + (1.0,)
|
||||
)
|
||||
|
||||
self.snap_vert = self.snap_edge = snap_edge_and_vert
|
||||
|
||||
shading = context.space_data.shading
|
||||
self.snap_face = not (snap_edge_and_vert and
|
||||
(shading.show_xray or shading.type == 'WIREFRAME'))
|
||||
|
||||
self.snap_context_update(context)
|
||||
|
||||
#Configure the unit of measure
|
||||
unit_system = context.scene.unit_settings.system
|
||||
scale = context.scene.unit_settings.scale_length
|
||||
scale /= context.space_data.overlay.grid_scale
|
||||
self.rd = bpy.utils.units.to_value(unit_system, 'LENGTH', str(1 / scale))
|
||||
|
||||
self.incremental = bpy.utils.units.to_value(
|
||||
unit_system, 'LENGTH', str(self.preferences.incremental))
|
||||
|
||||
def snap_context_update(self, context):
|
||||
self.sctx.set_snap_mode(
|
||||
self.snap_vert, self.snap_edge, self.snap_face)
|
||||
|
||||
self.sctx.clear_snap_objects()
|
||||
|
||||
for obj, matrix in self.visible_objects_and_duplis(context):
|
||||
self.sctx.add_obj(obj, matrix)
|
||||
|
||||
widget = self.snap_widget
|
||||
|
||||
if widget:
|
||||
self.snap_obj = widget.snap_obj
|
||||
self.bm = widget.bm
|
||||
self.geom = widget.geom
|
||||
self.type = widget.type
|
||||
self.location = widget.location
|
||||
else:
|
||||
#init these variables to avoid errors
|
||||
self.snap_obj = None
|
||||
self.bm = None
|
||||
self.geom = None
|
||||
self.type = 'OUT'
|
||||
self.location = Vector()
|
||||
|
||||
def snap_to_grid(self):
|
||||
if self.type == 'OUT' and self.preferences.increments_grid:
|
||||
loc = self.location / self.rd
|
||||
self.location = Vector((round(loc.x),
|
||||
round(loc.y),
|
||||
round(loc.z))) * self.rd
|
||||
|
||||
def snap_context_free(self):
|
||||
del self.sctx
|
||||
|
||||
del self.bm
|
||||
del self.draw_cache
|
||||
del self.geom
|
||||
del self.location
|
||||
del self.rd
|
||||
del self.snap_face
|
||||
del self.snap_obj
|
||||
del self.type
|
||||
|
||||
del self.preferences
|
||||
|
||||
SnapUtilities.constrain = None
|
||||
|
||||
|
||||
#def mesh_runtime_batchcache_isdirty(me):
|
||||
# import ctypes
|
||||
# batch_cache = ctypes.c_void_p.from_address(me.as_pointer() + 1440)
|
||||
# if batch_cache:
|
||||
# return ctypes.c_bool.from_address(batch_cache.value + 549).value
|
||||
# return False
|
||||
|
||||
|
||||
class SnapWidgetCommon:
|
||||
def draw_point_and_elem(self):
|
||||
if self.bm:
|
||||
if self.bm.is_valid and self.geom.is_valid:
|
||||
self.draw_cache.draw_elem(self.snap_obj, self.bm, self.geom)
|
||||
else:
|
||||
self.bm = None
|
||||
self.geom = None
|
||||
self.sctx.update_all()
|
||||
|
||||
self.draw_cache.draw(self.type, self.location, None, None, None)
|
||||
|
||||
def init_snap_widget(self, context, snap_edge_and_vert = True):
|
||||
self.snap_context_init(context, snap_edge_and_vert)
|
||||
self.mode = context.mode
|
||||
self.wm_operators = context.window_manager.operators
|
||||
self.last_operator = self.wm_operators[-1] if self.wm_operators else None
|
||||
self.last_mval = None
|
||||
|
||||
def update_snap(self, context, mval):
|
||||
if self.last_mval == mval:
|
||||
return -1
|
||||
else:
|
||||
self.last_mval = mval
|
||||
|
||||
last_operator = self.wm_operators[-1] if self.wm_operators else None
|
||||
if last_operator != self.last_operator:
|
||||
if (not last_operator or
|
||||
last_operator.name not in {'Select', 'Loop Select', '(De)select All'}):
|
||||
## Something has changed since the last time.
|
||||
# Has the mesh been changed?
|
||||
# In the doubt lets clear the snap context.
|
||||
self.sctx.update_all()
|
||||
|
||||
self.last_operator = last_operator
|
||||
|
||||
#print('test_select', mval)
|
||||
space = context.space_data
|
||||
self.sctx.update_viewport_context(context.region, space)
|
||||
|
||||
shading = space.shading
|
||||
snap_face = not ((self.snap_vert or self.snap_edge) and
|
||||
(shading.show_xray or shading.type == 'WIREFRAME'))
|
||||
|
||||
if snap_face != self.snap_face:
|
||||
self.snap_face = snap_face
|
||||
self.sctx.set_snap_mode(
|
||||
self.snap_vert, self.snap_edge, self.snap_face)
|
||||
|
||||
self.snap_obj, prev_loc, self.location, self.type, self.bm, self.geom, len = snap_utilities(
|
||||
self.sctx,
|
||||
None,
|
||||
mval,
|
||||
increment=self.incremental
|
||||
)
|
||||
|
||||
def __del__(self):
|
||||
from .snap_context_l import global_snap_context_get
|
||||
sctx = global_snap_context_get(None, None)
|
||||
if sctx:
|
||||
sctx.clear_snap_objects()
|
||||
|
||||
|
||||
class SnapPointWidget(SnapUtilities, SnapWidgetCommon, bpy.types.Gizmo):
|
||||
bl_idname = "VIEW3D_GT_snap_point"
|
||||
|
||||
__slots__ = (
|
||||
"bm",
|
||||
"draw_cache",
|
||||
"geom",
|
||||
"incremental",
|
||||
"preferences",
|
||||
"last_operator",
|
||||
"location",
|
||||
"mode",
|
||||
"snap_edge",
|
||||
"snap_face",
|
||||
"snap_vert",
|
||||
"snap_obj",
|
||||
"type",
|
||||
"wm_operators",
|
||||
)
|
||||
|
||||
def test_select(self, context, mval):
|
||||
self.update_snap(context, mval)
|
||||
self.snap_to_grid()
|
||||
|
||||
context.area.tag_redraw()
|
||||
return -1
|
||||
|
||||
def draw(self, context):
|
||||
self.draw_point_and_elem()
|
||||
|
||||
def setup(self):
|
||||
self.init_snap_widget(bpy.context)
|
||||
SnapUtilities.snap_widget = self
|
||||
|
||||
|
||||
def context_mode_check(context, widget_group):
|
||||
workspace = context.workspace
|
||||
mode = workspace.tools_mode
|
||||
for tool in workspace.tools:
|
||||
if (tool.widget == widget_group) and (tool.mode == mode):
|
||||
break
|
||||
else:
|
||||
return False
|
||||
return True
|
||||
|
||||
class SnapWidgetCommon:
|
||||
bl_space_type = 'VIEW_3D'
|
||||
bl_region_type = 'WINDOW'
|
||||
bl_options = {'3D'}
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return context_mode_check(context, cls.bl_idname)
|
||||
# return context_mode_change(
|
||||
# context, SnapUtilities.snap_widget, cls.bl_idname)
|
||||
|
||||
def init_tool(self, context, gizmo_name):
|
||||
self.gizmos.new(gizmo_name)
|
||||
SnapUtilities.snap_widget_refcnt += 1
|
||||
|
||||
def __del__(self):
|
||||
SnapUtilities.snap_widget_refcnt -= 1
|
||||
if SnapUtilities.snap_widget_refcnt == 0:
|
||||
SnapUtilities.snap_widget = None
|
||||
|
||||
|
||||
class SnapPointWidgetGroup(SnapWidgetCommon, bpy.types.GizmoGroup):
|
||||
bl_idname = "MESH_GGT_snap_point"
|
||||
bl_label = "Draw Snap Point"
|
||||
|
||||
def setup(self, context):
|
||||
self.init_tool(context, SnapPointWidget.bl_idname)
|
||||
|
|
Binary file not shown.
|
@ -27,17 +27,15 @@ from .common_classes import (
|
|||
SnapDrawn,
|
||||
CharMap,
|
||||
SnapNavigation,
|
||||
g_snap_widget, #TODO: remove
|
||||
SnapUtilities,
|
||||
)
|
||||
|
||||
from .common_utilities import (
|
||||
get_units_info,
|
||||
convert_distance,
|
||||
snap_utilities,
|
||||
)
|
||||
|
||||
if not __package__:
|
||||
__package__ = "mesh_snap_utilities"
|
||||
__package__ = "mesh_snap_utilities_line"
|
||||
|
||||
|
||||
def get_closest_edge(bm, point, dist):
|
||||
|
@ -79,7 +77,7 @@ def get_loose_linked_edges(bmvert):
|
|||
return linked
|
||||
|
||||
|
||||
def draw_line(self, bm_geom, location):
|
||||
def make_line(self, bm_geom, location):
|
||||
obj = self.main_snap_obj.data[0]
|
||||
bm = self.main_bm
|
||||
split_faces = set()
|
||||
|
@ -113,8 +111,9 @@ def draw_line(self, bm_geom, location):
|
|||
edge, vert = bmesh.utils.edge_split(bm_geom, bm_geom.verts[0], ret[1])
|
||||
update_edit_mesh = True
|
||||
|
||||
self.list_verts.append(vert)
|
||||
self.geom = vert # hack to highlight in the drawing
|
||||
if self.list_verts == [] or self.list_verts[-1] != vert:
|
||||
self.list_verts.append(vert)
|
||||
self.geom = vert # hack to highlight in the drawing
|
||||
# self.list_edges.append(edge)
|
||||
|
||||
else: # constrain point is near
|
||||
|
@ -134,7 +133,6 @@ def draw_line(self, bm_geom, location):
|
|||
edge = bm.edges.get([v1, v2])
|
||||
if edge:
|
||||
self.list_edges.append(edge)
|
||||
|
||||
else:
|
||||
if not v2.link_edges:
|
||||
edge = bm.edges.new([v1, v2])
|
||||
|
@ -206,71 +204,31 @@ def draw_line(self, bm_geom, location):
|
|||
return [obj.matrix_world @ v.co for v in self.list_verts]
|
||||
|
||||
|
||||
class SnapUtilitiesLine(bpy.types.Operator):
|
||||
class SnapUtilitiesLine(SnapUtilities, bpy.types.Operator):
|
||||
"""Make Lines. Connect them to split faces"""
|
||||
bl_idname = "mesh.make_line"
|
||||
bl_idname = "mesh.snap_utilities_line"
|
||||
bl_label = "Line Tool"
|
||||
bl_options = {'REGISTER'}
|
||||
|
||||
wait_for_input: bpy.props.BoolProperty(name="Wait for Input", default=True)
|
||||
|
||||
constrain_keys = {
|
||||
'X': Vector((1,0,0)),
|
||||
'Y': Vector((0,1,0)),
|
||||
'Z': Vector((0,0,1)),
|
||||
'RIGHT_SHIFT': 'shift',
|
||||
'LEFT_SHIFT': 'shift',
|
||||
}
|
||||
|
||||
def _exit(self, context):
|
||||
del self.main_bm #avoids unpredictable crashs
|
||||
del self.bm
|
||||
#avoids unpredictable crashs
|
||||
del self.main_snap_obj
|
||||
del self.main_bm
|
||||
del self.list_edges
|
||||
del self.list_verts
|
||||
del self.list_verts_co
|
||||
|
||||
bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW')
|
||||
context.area.header_text_set(None)
|
||||
|
||||
if not self.snap_widget:
|
||||
self.sctx.free()
|
||||
del self.draw_cache
|
||||
else:
|
||||
self.sctx = None
|
||||
self.draw_cache = None
|
||||
self.snap_context_free()
|
||||
|
||||
#Restore initial state
|
||||
context.tool_settings.mesh_select_mode = self.select_mode
|
||||
context.space_data.overlay.show_face_center = self.show_face_center
|
||||
|
||||
def _init_snap_context(self, context):
|
||||
if self.sctx:
|
||||
self.sctx.clear_snap_objects()
|
||||
else:
|
||||
#Create Snap Context
|
||||
from .snap_context_l import SnapContext
|
||||
self.sctx = SnapContext(context.region, context.space_data)
|
||||
self.sctx.set_pixel_dist(12)
|
||||
self.sctx.use_clip_planes(True)
|
||||
|
||||
if self.outer_verts:
|
||||
for base in context.visible_bases:
|
||||
self.sctx.add_obj(base.object, base.object.matrix_world)
|
||||
|
||||
self.sctx.set_snap_mode(True, True, self.snap_face)
|
||||
|
||||
if self.snap_widget:
|
||||
self.geom = self.snap_widget.geom
|
||||
self.type = self.snap_widget.type
|
||||
self.location = self.snap_widget.loc
|
||||
if self.snap_widget.snap_obj:
|
||||
context.view_layer.objects.active = self.snap_widget.snap_obj.data[0]
|
||||
else:
|
||||
#init these variables to avoid errors
|
||||
self.geom = None
|
||||
self.type = 'OUT'
|
||||
self.location = Vector()
|
||||
|
||||
def _init_snap_line_context(self, context):
|
||||
self.prevloc = Vector()
|
||||
self.list_verts = []
|
||||
self.list_edges = []
|
||||
|
@ -278,9 +236,6 @@ class SnapUtilitiesLine(bpy.types.Operator):
|
|||
self.bool_update = False
|
||||
self.vector_constrain = ()
|
||||
self.len = 0
|
||||
self.length_entered = ""
|
||||
self.length_entered_value = 0.0
|
||||
self.line_pos = 0
|
||||
|
||||
active_object = context.active_object
|
||||
mesh = active_object.data
|
||||
|
@ -295,22 +250,29 @@ class SnapUtilitiesLine(bpy.types.Operator):
|
|||
context.area.tag_redraw()
|
||||
|
||||
if event.ctrl and event.type == 'Z' and event.value == 'PRESS':
|
||||
del self.bm
|
||||
del self.main_bm
|
||||
|
||||
bpy.ops.ed.undo()
|
||||
bpy.ops.object.mode_set(mode='EDIT') # just to be sure
|
||||
bpy.ops.mesh.select_all(action='DESELECT')
|
||||
context.tool_settings.mesh_select_mode = (True, False, True)
|
||||
context.space_data.overlay.show_face_center = True
|
||||
if not self.wait_for_input:
|
||||
self._exit(context)
|
||||
return {'FINISHED'}
|
||||
else:
|
||||
del self.bm
|
||||
del self.main_bm
|
||||
self.charmap.clear()
|
||||
|
||||
self._init_snap_context(context)
|
||||
self.sctx.update_all()
|
||||
return {'RUNNING_MODAL'}
|
||||
bpy.ops.object.mode_set(mode='EDIT') # just to be sure
|
||||
bpy.ops.mesh.select_all(action='DESELECT')
|
||||
context.tool_settings.mesh_select_mode = (True, False, True)
|
||||
context.space_data.overlay.show_face_center = True
|
||||
|
||||
self.snap_context_update(context)
|
||||
self._init_snap_line_context(context)
|
||||
self.sctx.update_all()
|
||||
|
||||
return {'RUNNING_MODAL'}
|
||||
|
||||
is_making_lines = bool(self.list_verts_co)
|
||||
|
||||
if (event.type == 'MOUSEMOVE' or self.bool_update) and self.length_entered_value == 0.0:
|
||||
if (event.type == 'MOUSEMOVE' or self.bool_update) and self.charmap.length_entered_value == 0.0:
|
||||
if self.rv3d.view_matrix != self.rotMat:
|
||||
self.rotMat = self.rv3d.view_matrix.copy()
|
||||
self.bool_update = True
|
||||
|
@ -326,14 +288,9 @@ class SnapUtilitiesLine(bpy.types.Operator):
|
|||
mval,
|
||||
constrain=self.vector_constrain,
|
||||
previous_vert=(self.list_verts[-1] if self.list_verts else None),
|
||||
increment=self.incremental
|
||||
)
|
||||
increment=self.incremental)
|
||||
|
||||
if self.snap_to_grid and self.type == 'OUT':
|
||||
loc = self.location / self.rd
|
||||
self.location = Vector((round(loc.x),
|
||||
round(loc.y),
|
||||
round(loc.z))) * self.rd
|
||||
self.snap_to_grid()
|
||||
|
||||
if is_making_lines and self.keyf8:
|
||||
lloc = self.list_verts_co[-1]
|
||||
|
@ -356,24 +313,14 @@ class SnapUtilitiesLine(bpy.types.Operator):
|
|||
#del view_vec, orig, location, ax, ay, az, vec
|
||||
|
||||
if event.value == 'PRESS':
|
||||
if is_making_lines and (event.ascii in CharMap.ascii or event.type in CharMap.type):
|
||||
CharMap.modal(self, context, event)
|
||||
if is_making_lines and self.charmap.modal_(context, event):
|
||||
self.bool_update = self.charmap.length_entered_value == 0.0
|
||||
|
||||
if self.length_entered != "":
|
||||
try:
|
||||
self.length_entered_value = bpy.utils.units.to_value(
|
||||
self.unit_system, 'LENGTH', self.length_entered)
|
||||
|
||||
vector = (self.location - self.list_verts_co[-1]).normalized()
|
||||
self.location = (self.list_verts_co[-1] + (vector * self.length_entered_value))
|
||||
del vector
|
||||
|
||||
except: # ValueError:
|
||||
self.length_entered_value = 0.0 #invalid
|
||||
self.report({'INFO'}, "Operation not supported yet")
|
||||
else:
|
||||
self.length_entered_value = 0.0
|
||||
self.bool_update = True
|
||||
if not self.bool_update:
|
||||
text_value = self.charmap.length_entered_value
|
||||
vector = (self.location - self.list_verts_co[-1]).normalized()
|
||||
self.location = self.list_verts_co[-1] + (vector * text_value)
|
||||
del vector
|
||||
|
||||
elif event.type in self.constrain_keys:
|
||||
self.bool_update = True
|
||||
|
@ -400,7 +347,7 @@ class SnapUtilitiesLine(bpy.types.Operator):
|
|||
self.vector_constrain = [loc, loc + self.constrain_keys[event.type], event.type]
|
||||
|
||||
elif event.type in {'LEFTMOUSE', 'RET', 'NUMPAD_ENTER'}:
|
||||
if event.type == 'LEFTMOUSE' or self.length_entered_value != 0.0:
|
||||
if event.type == 'LEFTMOUSE' or self.charmap.length_entered_value != 0.0:
|
||||
if not is_making_lines and self.bm:
|
||||
self.main_snap_obj = self.snap_obj
|
||||
self.main_bm = self.bm
|
||||
|
@ -415,12 +362,10 @@ class SnapUtilitiesLine(bpy.types.Operator):
|
|||
if self.vector_constrain:
|
||||
geom2 = get_closest_edge(self.main_bm, point, .001)
|
||||
|
||||
self.list_verts_co = draw_line(self, geom2, point)
|
||||
self.list_verts_co = make_line(self, geom2, point)
|
||||
|
||||
self.vector_constrain = None
|
||||
self.length_entered = ""
|
||||
self.length_entered_value = 0.0
|
||||
self.line_pos = 0
|
||||
self.charmap.clear()
|
||||
else:
|
||||
self._exit(context)
|
||||
return {'FINISHED'}
|
||||
|
@ -441,19 +386,11 @@ class SnapUtilitiesLine(bpy.types.Operator):
|
|||
self.list_edges = []
|
||||
self.list_verts = []
|
||||
self.list_verts_co = []
|
||||
self.length_entered = ""
|
||||
self.length_entered_value = 0.0
|
||||
self.line_pos = 0
|
||||
self.charmap.clear()
|
||||
|
||||
a = ""
|
||||
if is_making_lines:
|
||||
if self.length_entered:
|
||||
pos = self.line_pos
|
||||
a = 'length: ' + self.length_entered[:pos] + '|' + self.length_entered[pos:]
|
||||
else:
|
||||
length = self.len
|
||||
length = convert_distance(length, self.uinfo)
|
||||
a = 'length: ' + length
|
||||
a = 'length: ' + self.charmap.get_converted_length_str(self.len)
|
||||
|
||||
context.area.header_text_set(text = "hit: %.3f %.3f %.3f %s" % (*self.location, a))
|
||||
|
||||
|
@ -469,6 +406,14 @@ class SnapUtilitiesLine(bpy.types.Operator):
|
|||
|
||||
def invoke(self, context, event):
|
||||
if context.space_data.type == 'VIEW_3D':
|
||||
self.snap_context_init(context)
|
||||
self.intersect = self.preferences.intersect
|
||||
self.create_face = self.preferences.create_face
|
||||
self.navigation_ops = SnapNavigation(context, True)
|
||||
self.charmap = CharMap(context)
|
||||
|
||||
self._init_snap_line_context(context)
|
||||
|
||||
# print('name', __name__, __package__)
|
||||
|
||||
#Store current state
|
||||
|
@ -487,57 +432,14 @@ class SnapUtilitiesLine(bpy.types.Operator):
|
|||
|
||||
#Init event variables
|
||||
self.keyf8 = False
|
||||
self.snap_face = True
|
||||
|
||||
self.snap_widget = g_snap_widget[0]
|
||||
|
||||
if self.snap_widget is not None:
|
||||
self.draw_cache = self.snap_widget.draw_cache
|
||||
self.sctx = self.snap_widget.sctx
|
||||
|
||||
preferences = self.snap_widget.preferences
|
||||
else:
|
||||
preferences = context.preferences.addons[__package__].preferences
|
||||
|
||||
#Init DrawCache
|
||||
self.draw_cache = SnapDrawn(
|
||||
preferences.out_color,
|
||||
preferences.face_color,
|
||||
preferences.edge_color,
|
||||
preferences.vert_color,
|
||||
preferences.center_color,
|
||||
preferences.perpendicular_color,
|
||||
preferences.constrain_shift_color,
|
||||
tuple(context.preferences.themes[0].user_interface.axis_x) + (1.0,),
|
||||
tuple(context.preferences.themes[0].user_interface.axis_y) + (1.0,),
|
||||
tuple(context.preferences.themes[0].user_interface.axis_z) + (1.0,)
|
||||
)
|
||||
|
||||
self.sctx = None
|
||||
|
||||
#Configure the unit of measure
|
||||
self.unit_system = context.scene.unit_settings.system
|
||||
scale = context.scene.unit_settings.scale_length
|
||||
separate_units = context.scene.unit_settings.use_separate
|
||||
self.uinfo = get_units_info(scale, self.unit_system, separate_units)
|
||||
scale /= context.space_data.overlay.grid_scale * preferences.relative_scale
|
||||
self.rd = bpy.utils.units.to_value(self.unit_system, 'LENGTH', str(1 / scale))
|
||||
|
||||
self.intersect = preferences.intersect
|
||||
self.create_face = preferences.create_face
|
||||
self.outer_verts = preferences.outer_verts
|
||||
self.snap_to_grid = preferences.increments_grid
|
||||
self.incremental = bpy.utils.units.to_value(self.unit_system, 'LENGTH', str(preferences.incremental))
|
||||
|
||||
self.navigation_ops = SnapNavigation(context, True)
|
||||
|
||||
self._init_snap_context(context)
|
||||
|
||||
#modals
|
||||
context.window_manager.modal_handler_add(self)
|
||||
|
||||
if not self.wait_for_input:
|
||||
self.modal(context, event)
|
||||
mat_inv = context.object.matrix_world.inverted_safe()
|
||||
point = mat_inv @ self.location
|
||||
self.list_verts_co = make_line(self, self.geom, point)
|
||||
|
||||
self._handle = bpy.types.SpaceView3D.draw_handler_add(self.draw_callback_px, (), 'WINDOW', 'POST_VIEW')
|
||||
|
||||
|
|
|
@ -28,6 +28,14 @@ FACE = 4
|
|||
|
||||
|
||||
class _Internal:
|
||||
global_snap_context = None
|
||||
|
||||
@classmethod
|
||||
def snap_context_free(cls):
|
||||
if cls.global_snap_context != None:
|
||||
cls.global_snap_context.free()
|
||||
del cls
|
||||
|
||||
from .mesh_drawing import (
|
||||
gpu_Indices_enable_state,
|
||||
gpu_Indices_restore_state,
|
||||
|
@ -56,8 +64,6 @@ class _SnapObjectData():
|
|||
class _SnapOffscreen():
|
||||
bound = None
|
||||
def __init__(self, width, height):
|
||||
import ctypes
|
||||
|
||||
self.freed = False
|
||||
self.is_bound = False
|
||||
|
||||
|
@ -72,14 +78,9 @@ class _SnapOffscreen():
|
|||
self.cur_viewport = bgl.Buffer(bgl.GL_INT, 4)
|
||||
|
||||
bgl.glGenRenderbuffers(1, self.buf_depth)
|
||||
bgl.glBindRenderbuffer(bgl.GL_RENDERBUFFER, self.buf_depth[0])
|
||||
bgl.glRenderbufferStorage(bgl.GL_RENDERBUFFER, bgl.GL_DEPTH_COMPONENT, width, height)
|
||||
|
||||
bgl.glGenTextures(1, self.buf_color)
|
||||
bgl.glBindTexture(bgl.GL_TEXTURE_2D, self.buf_color[0])
|
||||
NULL = bgl.Buffer(bgl.GL_INT, 1, (ctypes.c_int32 * 1).from_address(0))
|
||||
bgl.glTexImage2D(bgl.GL_TEXTURE_2D, 0, bgl.GL_R32UI, width, height, 0, bgl.GL_RED_INTEGER, bgl.GL_UNSIGNED_INT, NULL)
|
||||
del NULL
|
||||
self._config_textures()
|
||||
|
||||
bgl.glTexParameteri(bgl.GL_TEXTURE_2D, bgl.GL_TEXTURE_MIN_FILTER, bgl.GL_NEAREST)
|
||||
bgl.glTexParameteri(bgl.GL_TEXTURE_2D, bgl.GL_TEXTURE_MAG_FILTER, bgl.GL_NEAREST)
|
||||
|
||||
|
@ -87,7 +88,10 @@ class _SnapOffscreen():
|
|||
|
||||
bgl.glGenFramebuffers(1, self.fbo)
|
||||
bgl.glBindFramebuffer(bgl.GL_FRAMEBUFFER, self.fbo[0])
|
||||
bgl.glFramebufferRenderbuffer(bgl.GL_FRAMEBUFFER, bgl.GL_DEPTH_ATTACHMENT, bgl.GL_RENDERBUFFER, self.buf_depth[0])
|
||||
bgl.glFramebufferRenderbuffer(
|
||||
bgl.GL_FRAMEBUFFER, bgl.GL_DEPTH_ATTACHMENT,
|
||||
bgl.GL_RENDERBUFFER, self.buf_depth[0])
|
||||
|
||||
bgl.glFramebufferTexture(bgl.GL_FRAMEBUFFER, bgl.GL_COLOR_ATTACHMENT0, self.buf_color[0], 0)
|
||||
|
||||
bgl.glDrawBuffers(1, bgl.Buffer(bgl.GL_INT, 1, [bgl.GL_COLOR_ATTACHMENT0]))
|
||||
|
@ -98,6 +102,21 @@ class _SnapOffscreen():
|
|||
|
||||
bgl.glBindFramebuffer(bgl.GL_FRAMEBUFFER, self.cur_fbo[0])
|
||||
|
||||
def _config_textures(self):
|
||||
import ctypes
|
||||
|
||||
bgl.glBindRenderbuffer(bgl.GL_RENDERBUFFER, self.buf_depth[0])
|
||||
bgl.glRenderbufferStorage(
|
||||
bgl.GL_RENDERBUFFER, bgl.GL_DEPTH_COMPONENT, self.width, self.height)
|
||||
|
||||
NULL = bgl.Buffer(bgl.GL_INT, 1, (ctypes.c_int32 * 1).from_address(0))
|
||||
bgl.glBindTexture(bgl.GL_TEXTURE_2D, self.buf_color[0])
|
||||
bgl.glTexImage2D(
|
||||
bgl.GL_TEXTURE_2D, 0, bgl.GL_R32UI, self.width, self.height,
|
||||
0, bgl.GL_RED_INTEGER, bgl.GL_UNSIGNED_INT, NULL)
|
||||
del NULL
|
||||
|
||||
|
||||
def bind(self):
|
||||
if self is not _SnapOffscreen.bound:
|
||||
if _SnapOffscreen.bound is None:
|
||||
|
@ -130,6 +149,19 @@ class _SnapOffscreen():
|
|||
if not is_bound:
|
||||
self.unbind()
|
||||
|
||||
def resize(self, width, height):
|
||||
is_bound = self is _SnapOffscreen.bound
|
||||
if not is_bound:
|
||||
self.bind()
|
||||
|
||||
self.width = int(width)
|
||||
self.height = int(height)
|
||||
self._config_textures()
|
||||
|
||||
if not is_bound:
|
||||
self.unbind()
|
||||
|
||||
|
||||
def __del__(self):
|
||||
if not self.freed:
|
||||
bgl.glDeleteFramebuffers(1, self.fbo)
|
||||
|
@ -188,6 +220,7 @@ class SnapContext():
|
|||
|
||||
self._offscreen.clear()
|
||||
|
||||
|
||||
## PRIVATE ##
|
||||
|
||||
def _get_snap_obj_by_index(self, index):
|
||||
|
@ -206,8 +239,8 @@ class SnapContext():
|
|||
d = 1
|
||||
m = self.threshold
|
||||
max_val = 2 * m - 1
|
||||
last_value = -1
|
||||
find_next_index = self._snap_mode & FACE and self._snap_mode & (VERT | EDGE)
|
||||
last_value = -1 if find_next_index else 0
|
||||
while m < max_val:
|
||||
for i in range(2):
|
||||
while 2 * loc[i] * d < m:
|
||||
|
@ -218,7 +251,12 @@ class SnapContext():
|
|||
if find_next_index:
|
||||
last_value = value
|
||||
r_snap_obj = self._get_snap_obj_by_index(value)
|
||||
if (r_snap_obj is None) or value < (r_snap_obj.data[1].first_index + len(r_snap_obj.data[1].tri_verts)):
|
||||
if r_snap_obj is not None:
|
||||
snap_data = r_snap_obj.data[1]
|
||||
if value < (snap_data.first_index + len(snap_data.tri_verts)):
|
||||
# snap to a triangle
|
||||
continue
|
||||
else:
|
||||
continue
|
||||
find_next_index = False
|
||||
elif (r_snap_obj is None) or\
|
||||
|
@ -290,6 +328,8 @@ class SnapContext():
|
|||
for snap_obj in self.snap_objects:
|
||||
if len(snap_obj.data) == 2:
|
||||
snap_obj.data[1].free()
|
||||
snap_obj.data.pop(1)
|
||||
|
||||
del snap_obj.data
|
||||
del snap_obj.mat
|
||||
del snap_obj
|
||||
|
@ -297,11 +337,37 @@ class SnapContext():
|
|||
|
||||
## PUBLIC ##
|
||||
|
||||
def update_viewport_context(self, region, space):
|
||||
rv3d = space.region_3d
|
||||
|
||||
if region == self.region and rv3d == self.rv3d:
|
||||
return
|
||||
|
||||
self.region = region
|
||||
self.rv3d = rv3d
|
||||
|
||||
if self.rv3d.is_perspective:
|
||||
self.depth_range = Vector((space.clip_start, space.clip_end))
|
||||
else:
|
||||
self.depth_range = Vector((-space.clip_end, space.clip_end))
|
||||
|
||||
self.winsize = Vector((self.region.width, self.region.height))
|
||||
self._offscreen.resize(*self.winsize)
|
||||
|
||||
def clear_snap_objects(self):
|
||||
self.update_all()
|
||||
self.snap_objects.clear()
|
||||
_Internal.gpu_Indices_mesh_cache_clear()
|
||||
|
||||
def update_all(self):
|
||||
for snap_obj in self.snap_objects:
|
||||
if len(snap_obj.data) == 2:
|
||||
snap_obj.data[1].free()
|
||||
snap_obj.data.pop(1)
|
||||
|
||||
self.update_drawing()
|
||||
|
||||
def update_drawing(self):
|
||||
self.drawn_count = 0
|
||||
self._offset_cur = 1
|
||||
self._offscreen.clear()
|
||||
|
@ -309,23 +375,27 @@ class SnapContext():
|
|||
def tag_update_drawn_snap_object(self, snap_obj):
|
||||
if len(snap_obj.data) > 1:
|
||||
snap_obj.data[1].free()
|
||||
del snap_obj.data[1:]
|
||||
#self.update_all()
|
||||
snap_obj.data.pop(1)
|
||||
#self.update_drawing()
|
||||
# Update on next snap_get call #
|
||||
self.proj_mat = None
|
||||
|
||||
def update_drawn_snap_object(self, snap_obj):
|
||||
_Internal.gpu_Indices_enable_state()
|
||||
|
||||
from .mesh_drawing import GPU_Indices_Mesh
|
||||
snap_vert = self._snap_mode & VERT != 0
|
||||
snap_edge = self._snap_mode & EDGE != 0
|
||||
snap_face = self._snap_mode & FACE != 0
|
||||
|
||||
if len(snap_obj.data) > 1:
|
||||
_Internal.gpu_Indices_enable_state()
|
||||
|
||||
from .mesh_drawing import GPU_Indices_Mesh
|
||||
snap_vert = self._snap_mode & VERT != 0
|
||||
snap_edge = self._snap_mode & EDGE != 0
|
||||
snap_face = self._snap_mode & FACE != 0
|
||||
snap_obj.data[1].free()
|
||||
snap_obj.data[1] = GPU_Indices_Mesh(snap_obj.data[0], snap_face, snap_edge, snap_vert)
|
||||
snap_obj.data.pop(1)
|
||||
|
||||
_Internal.gpu_Indices_restore_state()
|
||||
data = GPU_Indices_Mesh(snap_obj.data[0], snap_face, snap_edge, snap_vert)
|
||||
snap_obj.data.append(data)
|
||||
|
||||
_Internal.gpu_Indices_restore_state()
|
||||
|
||||
def use_clip_planes(self, value):
|
||||
_Internal.gpu_Indices_use_clip_planes(self.rv3d, value)
|
||||
|
@ -350,12 +420,7 @@ class SnapContext():
|
|||
self.update_all()
|
||||
|
||||
def add_obj(self, obj, matrix):
|
||||
matrix = matrix.copy()
|
||||
snap_obj = self._get_snap_obj_by_obj(obj)
|
||||
if not snap_obj:
|
||||
self.snap_objects.append(_SnapObjectData([obj], matrix))
|
||||
else:
|
||||
self.snap_objects.append(_SnapObjectData(snap_obj.data, matrix))
|
||||
self.snap_objects.append(_SnapObjectData([obj], matrix.copy()))
|
||||
|
||||
return self.snap_objects[-1]
|
||||
|
||||
|
@ -382,7 +447,7 @@ class SnapContext():
|
|||
if self.proj_mat != proj_mat:
|
||||
self.proj_mat = proj_mat
|
||||
_Internal.gpu_Indices_set_ProjectionMatrix(self.proj_mat)
|
||||
self.update_all()
|
||||
self.update_drawing()
|
||||
|
||||
ray_dir, ray_orig = self.get_ray(mval)
|
||||
for i, snap_obj in enumerate(self.snap_objects[self.drawn_count:], self.drawn_count):
|
||||
|
@ -410,7 +475,12 @@ class SnapContext():
|
|||
if in_threshold:
|
||||
if len(snap_obj.data) == 1:
|
||||
from .mesh_drawing import GPU_Indices_Mesh
|
||||
snap_obj.data.append(GPU_Indices_Mesh(obj, snap_face, snap_edge, snap_vert))
|
||||
is_bound = obj.display_type == 'BOUNDS'
|
||||
draw_face = snap_face and not is_bound and obj.display_type != 'WIRE'
|
||||
draw_edge = snap_edge and not is_bound
|
||||
draw_vert = snap_vert and not is_bound
|
||||
snap_obj.data.append(GPU_Indices_Mesh(obj, draw_face, draw_edge, draw_vert))
|
||||
|
||||
snap_obj.data[1].set_draw_mode(snap_face, snap_edge, snap_vert)
|
||||
snap_obj.data[1].set_ModelViewMatrix(snap_obj.mat)
|
||||
|
||||
|
@ -449,3 +519,26 @@ class SnapContext():
|
|||
def free(self):
|
||||
self.__del__()
|
||||
self.freed = True
|
||||
|
||||
def global_snap_context_get(region, space):
|
||||
if _Internal.global_snap_context == None:
|
||||
if region is None or space is None:
|
||||
return
|
||||
|
||||
import atexit
|
||||
|
||||
_Internal.global_snap_context = SnapContext(region, space)
|
||||
|
||||
# Make sure we only registered the callback once.
|
||||
atexit.unregister(_Internal.snap_context_free)
|
||||
atexit.register(_Internal.snap_context_free)
|
||||
|
||||
elif region is not None:
|
||||
_Internal.global_snap_context.update_viewport_context(region, space)
|
||||
|
||||
if ((region.width != _Internal.global_snap_context._offscreen.width) or
|
||||
(region.height != _Internal.global_snap_context._offscreen.height)):
|
||||
_Internal.global_snap_context.winsize[:] = region.width, region.height
|
||||
_Internal.global_snap_context._offscreen.resize(region.width, region.height)
|
||||
|
||||
return _Internal.global_snap_context
|
||||
|
|
Loading…
Reference in New Issue