mesh_snap_utilities_line: Fix framebuffer being created and cleaned in the wrong context

The solution is somewhat hackistic because it requires the creation of a global framebuffer at the time the addon is registered
This commit is contained in:
Germano Cavalcante 2019-02-10 21:45:47 -02:00
parent 68375994ab
commit a5ebaabeee
3 changed files with 59 additions and 101 deletions

View File

@ -22,7 +22,7 @@
bl_info = {
"name": "Snap_Utilities_Line",
"author": "Germano Cavalcante",
"version": (5, 9, 1),
"version": (5, 9, 2),
"blender": (2, 80, 0),
"location": "View3D > TOOLS > Line Tool",
"description": "Extends Blender Snap controls",
@ -154,6 +154,10 @@ classes = (
)
def register():
from .snap_context_l import global_snap_context_init
# This makes sure that the framebuffer is created in the correct context
global_snap_context_init(None, None, None)
for cls in classes:
bpy.utils.register_class(cls)
@ -161,6 +165,9 @@ def register():
def unregister():
from .snap_context_l import global_snap_context_destroy
global_snap_context_destroy()
unregister_snap_tools()
for cls in reversed(classes):

View File

@ -27,6 +27,12 @@ EDGE = 2
FACE = 4
def check_gl_error():
error = bgl.glGetError()
if error != bgl.GL_NO_ERROR:
raise Exception(error)
class _Internal:
global_snap_context = None
@ -79,15 +85,14 @@ class _SnapOffscreen():
bgl.glGenRenderbuffers(1, self.buf_depth)
bgl.glGenTextures(1, self.buf_color)
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)
self._config_textures()
bgl.glGetIntegerv(bgl.GL_FRAMEBUFFER_BINDING, self.cur_fbo)
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])
@ -116,6 +121,8 @@ class _SnapOffscreen():
0, bgl.GL_RED_INTEGER, bgl.GL_UNSIGNED_INT, NULL)
del NULL
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)
def bind(self):
if self is not _SnapOffscreen.bound:
@ -134,7 +141,7 @@ class _SnapOffscreen():
_SnapOffscreen.bound = None
def clear(self):
is_bound = self is _SnapOffscreen.bound
is_bound = self is _SnapOffscreen.bound
if not is_bound:
self.bind()
@ -161,7 +168,6 @@ class _SnapOffscreen():
if not is_bound:
self.unbind()
def __del__(self):
if not self.freed:
bgl.glDeleteFramebuffers(1, self.fbo)
@ -200,14 +206,6 @@ class SnapContext():
self.snap_objects = []
self.drawn_count = 0
self._offset_cur = 1 # Starts with index 1
self.region = region
self.rv3d = space.region_3d
self.depsgraph = depsgraph
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.proj_mat = None
self.mval = Vector((0, 0))
@ -215,12 +213,26 @@ class SnapContext():
self.set_pixel_dist(12)
self._offscreen = _SnapOffscreen(self.region.width, self.region.height)
self.region = region
self.depsgraph = depsgraph
if not (depsgraph or region or space):
self.rv3d = None
self.depth_range = Vector((-1.0, 1.0))
self._offscreen = _SnapOffscreen(1, 1)
else:
self.rv3d = space.region_3d
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._offscreen = _SnapOffscreen(self.region.width, self.region.height)
self._offscreen.clear()
self.winsize = Vector((self._offscreen.width, self._offscreen.height))
self._offscreen.clear()
## PRIVATE ##
@ -360,7 +372,13 @@ class SnapContext():
self._offscreen.resize(*self.winsize)
def clear_snap_objects(self):
self.update_all()
for snap_obj in self.snap_objects:
if len(snap_obj.data) == 2:
snap_obj.data[1].free()
del snap_obj.data[1:]
self.update_drawing(False)
self.snap_objects.clear()
_Internal.gpu_Indices_mesh_cache_clear()
@ -372,10 +390,11 @@ class SnapContext():
self.update_drawing()
def update_drawing(self):
def update_drawing(self, clear_offscreen = True):
self.drawn_count = 0
self._offset_cur = 1
self._offscreen.clear()
if clear_offscreen:
self._offscreen.clear()
def tag_update_drawn_snap_object(self, snap_obj):
if len(snap_obj.data) > 1:
@ -502,9 +521,11 @@ class SnapContext():
self.drawn_count += 1
bgl.glReadBuffer(bgl.GL_COLOR_ATTACHMENT0)
bgl.glReadPixels(
int(self.mval[0]) - self._dist_px, int(self.mval[1]) - self._dist_px,
self.threshold, self.threshold, bgl.GL_RED_INTEGER, bgl.GL_UNSIGNED_INT, self._snap_buffer)
#bgl.glReadBuffer(bgl.GL_BACK)
#import numpy as np
#a = np.array(self._snap_buffer)
@ -516,6 +537,7 @@ class SnapContext():
ret = self._get_loc(snap_obj, index)
bgl.glDisable(bgl.GL_DEPTH_TEST)
self._offscreen.unbind()
_Internal.gpu_Indices_restore_state()
@ -525,11 +547,9 @@ class SnapContext():
self.__del__()
self.freed = True
def global_snap_context_get(depsgraph, region, space):
if _Internal.global_snap_context == None:
if depsgraph is None or region is None or space is None:
return
def global_snap_context_init(depsgraph, region, space):
if _Internal.global_snap_context == None:
import atexit
_Internal.global_snap_context = SnapContext(depsgraph, region, space)
@ -538,7 +558,14 @@ def global_snap_context_get(depsgraph, region, space):
atexit.unregister(_Internal.snap_context_free)
atexit.register(_Internal.snap_context_free)
elif depsgraph is not None:
def global_snap_context_get(depsgraph, region, space):
if (depsgraph and region and space):
_Internal.global_snap_context.update_viewport_context(depsgraph, region, space, True)
return _Internal.global_snap_context
def global_snap_context_destroy():
if _Internal.global_snap_context != None:
_Internal.global_snap_context.free()

View File

@ -131,66 +131,6 @@ class SnapPointWidget(SnapWidgetCommon, bpy.types.Gizmo):
self.init_snapwidget(bpy.context)
class SnapFaceWidget(SnapWidgetCommon, bpy.types.Gizmo):
bl_idname = "VIEW3D_GT_snap_face_point"
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_snapwidget(bpy.context, False)
class SnapCircleWidget(SnapWidgetCommon, bpy.types.Gizmo):
bl_idname = "VIEW3D_GT_snap_circle"
from mathutils import Vector
zero_vector = Vector()
default_normal = Vector((0.0, 0.0, 1.0))
def get_normal(self, context):
if self.constrain:
return
view_vector, orig = self.sctx.last_ray
if not self.rv3d.is_perspective:
#temporary hack
orig -= view_vector * 100
normal_face = context.scene.ray_cast(context.view_layer, orig, view_vector)[2]
if normal_face and normal_face != self.zero_vector:
self.normal = normal_face
else:
self.normal = self.default_normal
def test_select(self, context, mval):
self.update_snap(context, mval)
self.snap_to_grid()
self.get_normal(context)
context.area.tag_redraw()
return -1
def draw(self, context):
self.draw_point_and_elem()
self.draw_cache.draw_rot_tool(
self.rv3d.view_distance / 15,
self.location, self.normal, None)
def setup(self):
context = bpy.context
self.init_snapwidget(context)
self.rv3d = context.region_data
self.normal = self.default_normal
def context_mode_check(context, widget_group):
workspace = context.workspace
mode = workspace.tools_mode
@ -226,19 +166,3 @@ class SnapPointWidgetGroup(SnapWidgetGroupCommon, bpy.types.GizmoGroup):
def setup(self, context):
self.init_tool(context, SnapPointWidget.bl_idname)
class SnapCircleWidgetGroup(SnapWidgetGroupCommon, bpy.types.GizmoGroup):
bl_idname = "MESH_GGT_snap_circle"
bl_label = "Draw Snap Circle"
def setup(self, context):
self.init_tool(context, SnapCircleWidget.bl_idname)
class SnapFaceWidgetGroup(SnapWidgetGroupCommon, bpy.types.GizmoGroup):
bl_idname = "MESH_GGT_face_snap_point"
bl_label = "Draw Face and Snap Point"
def setup(self, context):
self.init_tool(context, SnapFaceWidget.bl_idname)