Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender-addons.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGermano <germano.costa@ig.com.br>2017-09-10 02:11:38 +0300
committerGermano <germano.costa@ig.com.br>2017-09-10 02:11:38 +0300
commit136a8f839aab01c23a809eba13db014d654511c3 (patch)
tree6946ea9f162b65841c1c280219e5852fc49ad5b4
parent1d9d466de8a56705edf8d274fe36157f4701bdb9 (diff)
New `snap_context` module for `addons/module`
This module basically uses OpenGL to draw, in an offscreen, the vertices, edges and tris of specific objects and use colors as information for snap
-rw-r--r--modules/snap_context/__init__.py292
-rw-r--r--modules/snap_context/bgl_ext.py140
-rw-r--r--modules/snap_context/mesh_drawing.py505
-rw-r--r--modules/snap_context/resources/3D_vert.glsl27
-rw-r--r--modules/snap_context/resources/primitive_id_frag.glsl22
-rw-r--r--modules/snap_context/utils_projection.py213
-rw-r--r--modules/snap_context/utils_shader.py85
7 files changed, 1284 insertions, 0 deletions
diff --git a/modules/snap_context/__init__.py b/modules/snap_context/__init__.py
new file mode 100644
index 00000000..4767862f
--- /dev/null
+++ b/modules/snap_context/__init__.py
@@ -0,0 +1,292 @@
+# ##### 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 3
+# 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, see <http://www.gnu.org/licenses/>.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+import bgl
+import gpu
+from mathutils import Vector, Matrix
+from mathutils.geometry import intersect_point_line, intersect_ray_tri
+
+from .bgl_ext import VoidBufValue, get_clip_planes
+from .mesh_drawing import GPU_Indices_Mesh, gpu_Indices_enable_state, gpu_Indices_restore_state
+from .utils_projection import (
+ region_2d_to_orig_and_view_vector as _get_ray,
+ intersect_boundbox_threshold,
+ intersect_ray_segment_fac,
+ project_co_v3,
+ )
+
+VERT = 1
+EDGE = 2
+FACE = 4
+
+class _SnapObjectData():
+ def __init__(self, data, omat):
+ self.data = data
+ self.mat = omat
+
+
+class SnapContext():
+ def __init__(self, region, space):
+ self.freed = False
+ self.snap_objects = []
+ self.drawn_count = 0
+ self._offset_cur = 1 # Starts with index 1
+ self.region = region
+ self.rv3d = space.region_3d
+ self.proj_mat = Matrix.Identity(4)
+ self.depth_range = Vector((space.clip_start, space.clip_end))
+ self.mval = Vector((0, 0))
+ self._snap_mode = VERT | EDGE | FACE
+
+ self.set_pixel_dist(12)
+
+ self._offscreen = gpu.offscreen.new(self.region.width, self.region.height)
+
+ self._texture = self._offscreen.color_texture
+ bgl.glBindTexture(bgl.GL_TEXTURE_2D, self._texture)
+
+ NULL = VoidBufValue(0)
+ bgl.glTexImage2D(bgl.GL_TEXTURE_2D, 0, bgl.GL_R32UI, self.region.width, self.region.height, 0, bgl.GL_RED_INTEGER, bgl.GL_UNSIGNED_INT, NULL.buf)
+ 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)
+ bgl.glBindTexture(bgl.GL_TEXTURE_2D, 0)
+
+ self.winsize = Vector((self._offscreen.width, self._offscreen.height))
+
+ ## PRIVATE ##
+
+ def _get_snap_obj_by_index(self, index):
+ for snap_obj in self.snap_objects[:self.drawn_count]:
+ data = snap_obj.data[1]
+ if index < data.first_index + data.get_tot_elems():
+ return snap_obj
+ return None
+
+ def _get_nearest_index(self):
+ loc = [self._dist_px, self._dist_px]
+ d = 1
+ m = self.threshold
+ max = 2 * m - 1
+ offset = 1
+ last_snap_obj = None
+ r_value = 0
+ while m < max:
+ for i in range(2):
+ while 2 * loc[i] * d < m:
+ value = int(self._snap_buffer[loc[0]][loc[1]])
+ loc[i] += d
+ if value >= offset:
+ r_value = value
+ snap_obj = self._get_snap_obj_by_index(r_value)
+
+ if self._snap_mode & FACE and self._snap_mode & (VERT | EDGE) and last_snap_obj != snap_obj:
+ data = snap_obj.data[1]
+ offset = data.first_index + data.num_tris
+ last_snap_obj = snap_obj
+ continue
+ return snap_obj, r_value
+ d = -d
+ m += 4 * self._dist_px * d + 1
+
+ return last_snap_obj, r_value
+
+ def _get_loc(self, snap_obj, index):
+ index -= snap_obj.data[1].first_index
+ gpu_data = snap_obj.data[1]
+
+ if gpu_data.draw_tris:
+ if index < snap_obj.data[1].num_tris:
+ tri_verts = gpu_data.get_tri_verts(index)
+ tri_co = [snap_obj.mat * Vector(v) for v in gpu_data.get_tri_co(index)]
+ return intersect_ray_tri(*tri_co, *self.last_ray, False), tri_verts
+
+ index -= gpu_data.num_tris
+
+ if gpu_data.draw_edges:
+ if index < snap_obj.data[1].num_edges:
+ edge_verts = gpu_data.get_edge_verts(index)
+ edge_co = [snap_obj.mat * Vector(v) for v in gpu_data.get_edge_co(index)]
+ fac = intersect_ray_segment_fac(*edge_co, *self.last_ray)
+
+ if (self._snap_mode) & VERT and (fac < 0.25 or fac > 0.75):
+ co = edge_co[0] if fac < 0.5 else edge_co[1]
+ proj_co = project_co_v3(self, co)
+ dist = self.mval - proj_co
+ if abs(dist.x) < self._dist_px and abs(dist.y) < self._dist_px:
+ return co, (edge_verts[0] if fac < 0.5 else edge_verts[1],)
+
+ if fac <= 0.0:
+ co = edge_co[0]
+ elif fac >= 1.0:
+ co = edge_co[1]
+ else:
+ co = edge_co[0] + fac * (edge_co[1] - edge_co[0])
+
+ return co, edge_verts
+
+ index -= gpu_data.num_edges
+
+ if gpu_data.draw_verts:
+ if index < snap_obj.data[1].num_verts:
+ return snap_obj.mat * Vector(gpu_data.get_loosevert_co(index)), (gpu_data.get_loosevert_index(index),)
+
+ return None, None
+
+
+ def _get_snap_obj_by_obj(self, obj):
+ for snap_obj in self.snap_objects:
+ if obj == snap_obj.data[0]:
+ return snap_obj
+
+ def __del__(self):
+ if not self.freed:
+ self._offscreen.free()
+ del self.snap_objects
+
+ ## PUBLIC ##
+
+ def update_all(self):
+ self.drawn_count = 0
+ self._offset_cur = 1
+
+ bgl.glClearColor(0.0, 0.0, 0.0, 0.0)
+ bgl.glClear(bgl.GL_COLOR_BUFFER_BIT | bgl.GL_DEPTH_BUFFER_BIT)
+
+ def update_drawn_snap_object(self, snap_obj):
+ if len(snap_obj.data) > 1:
+ del snap_obj.data[1:]
+ #self.update_all()
+ # Update on next snap_get call #
+ self.proj_mat = Matrix.Identity(4)
+
+ def use_clip_planes(self, value):
+ planes = get_clip_planes(self.rv3d)
+ if planes:
+ self._store_current_shader_state()
+ GPU_Indices_Mesh.shader
+ bgl.glUseProgram(GPU_Indices_Mesh.shader.program)
+ bgl.glUniform1i(GPU_Indices_Mesh.unif_use_clip_planes, value)
+
+ bgl.glUniform4fv(GPU_Indices_Mesh.unif_clip_plane, 4, planes)
+
+ self._restore_shader_state()
+
+ def set_pixel_dist(self, dist_px):
+ self._dist_px = int(dist_px)
+ self._dist_px_sq = self._dist_px ** 2
+ self.threshold = 2 * self._dist_px + 1
+ self._snap_buffer = bgl.Buffer(bgl.GL_FLOAT, (self.threshold, self.threshold))
+
+ def set_snap_mode(self, snap_to_vert, snap_to_edge, snap_to_face):
+ snap_mode = 0
+ if snap_to_vert:
+ snap_mode |= VERT
+ if snap_to_edge:
+ snap_mode |= EDGE
+ if snap_to_face:
+ snap_mode |= FACE
+
+ if snap_mode != self._snap_mode:
+ self._snap_mode = snap_mode
+ self.update_all()
+
+ def add_obj(self, obj, matrix):
+ matrix = matrix.freeze()
+ 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))
+
+ return self.snap_objects[-1]
+
+ def get_ray(self, mval):
+ self.last_ray = _get_ray(self.region, self.rv3d, mval)
+ return self.last_ray
+
+ def snap_get(self, mval):
+ ret = None, None
+ self.mval[:] = mval
+ snap_vert = self._snap_mode & VERT != 0
+ snap_edge = self._snap_mode & EDGE != 0
+ snap_face = self._snap_mode & FACE != 0
+
+ gpu_Indices_enable_state()
+ self._offscreen.bind()
+
+ #bgl.glDisable(bgl.GL_DITHER) # dithering and AA break color coding, so disable #
+ #multisample_enabled = bgl.glIsEnabled(bgl.GL_MULTISAMPLE)
+ #bgl.glDisable(bgl.GL_MULTISAMPLE)
+ bgl.glEnable(bgl.GL_DEPTH_TEST)
+
+ proj_mat = self.rv3d.perspective_matrix.copy()
+ if self.proj_mat != proj_mat:
+ self.proj_mat = proj_mat
+ GPU_Indices_Mesh.set_ProjectionMatrix(self.proj_mat)
+ self.update_all()
+
+ ray_dir, ray_orig = self.get_ray(mval)
+ for i, snap_obj in enumerate(self.snap_objects[self.drawn_count:], self.drawn_count):
+ obj = snap_obj.data[0]
+ bbmin = Vector(obj.bound_box[0])
+ bbmax = Vector(obj.bound_box[6])
+
+ if bbmin != bbmax:
+ MVP = proj_mat * snap_obj.mat
+ mat_inv = snap_obj.mat.inverted()
+ ray_orig_local = mat_inv * ray_orig
+ ray_dir_local = ray_dir * snap_obj.mat
+ in_threshold = intersect_boundbox_threshold(self, MVP, ray_orig_local, ray_dir_local, bbmin, bbmax)
+ else:
+ proj_co = project_co_v3(self, snap_obj.mat.translation)
+ dist = self.mval - proj_co
+ in_threshold = abs(dist.x) < self._dist_px and abs(dist.y) < self._dist_px
+ #snap_obj.data[1] = primitive_point
+
+ if in_threshold:
+ if len(snap_obj.data) == 1:
+ snap_obj.data.append(GPU_Indices_Mesh(obj, snap_face, snap_edge, snap_vert))
+ snap_obj.data[1].set_draw_mode(snap_face, snap_edge, snap_vert)
+ snap_obj.data[1].set_ModelViewMatrix(snap_obj.mat)
+ snap_obj.data[1].Draw(self._offset_cur)
+ self._offset_cur += snap_obj.data[1].get_tot_elems()
+
+ self.snap_objects[self.drawn_count], self.snap_objects[i] = self.snap_objects[i], self.snap_objects[self.drawn_count]
+ 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)
+
+ snap_obj, index = self._get_nearest_index()
+ #print(index)
+ if snap_obj:
+ ret = self._get_loc(snap_obj, index)
+
+ self._offscreen.unbind()
+ gpu_Indices_restore_state()
+
+ return snap_obj, ret[0], ret[1]
+
+ def free(self):
+ self.__del__()
+ self.freed = True
+
diff --git a/modules/snap_context/bgl_ext.py b/modules/snap_context/bgl_ext.py
new file mode 100644
index 00000000..46ce3186
--- /dev/null
+++ b/modules/snap_context/bgl_ext.py
@@ -0,0 +1,140 @@
+# ##### 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 3
+# 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, see <http://www.gnu.org/licenses/>.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+
+import bgl
+import ctypes
+import numpy as np
+
+
+# figure out size of _Py_ssize_t
+if hasattr(ctypes.pythonapi, 'Py_InitModule4_64'):
+ _Py_ssize_t = ctypes.c_int64
+else:
+ _Py_ssize_t = ctypes.c_int
+
+class _PyObject(ctypes.Structure):
+ pass
+
+_PyObject._fields_ = [
+ ('ob_refcnt', _Py_ssize_t),
+ ('ob_type', ctypes.POINTER(_PyObject)),
+]
+
+if object.__basicsize__ != ctypes.sizeof(_PyObject):
+ # python with trace
+ class _PyObject(ctypes.Structure):
+ _fields_ = [
+ ('_ob_next', ctypes.POINTER(_PyObject)),
+ ('_ob_prev', ctypes.POINTER(_PyObject)),
+ ('ob_refcnt', _Py_ssize_t),
+ ('ob_type', ctypes.POINTER(_PyObject)),
+ ]
+
+class _PyVarObject(_PyObject):
+ _fields_ = [
+ ('ob_size', _Py_ssize_t),
+ ]
+
+class C_Buffer(_PyVarObject):
+ _fields_ = [
+ ("parent", ctypes.py_object),
+ ("type", ctypes.c_int),
+ ("ndimensions", ctypes.c_int),
+ ("dimensions", ctypes.POINTER(ctypes.c_int)),
+ ("buf", ctypes.c_void_p),
+ ]
+
+assert ctypes.sizeof(C_Buffer) == bgl.Buffer.__basicsize__
+
+class VoidBufValue():
+ def __init__(self, value):
+ self.buf = bgl.Buffer(bgl.GL_BYTE, 1)
+ self.c_buf = C_Buffer.from_address(id(self.buf))
+ self._allocated_buf = self.c_buf.buf
+ self.c_buf.buf = value
+ self.c_buf.type = 0 # allows repr
+ def __del__(self):
+ self.c_buf.buf = self._allocated_buf
+ #del self._allocated_buf
+ del self.buf
+
+
+def np_array_as_bgl_Buffer(array):
+ type = array.dtype
+ if type == np.int8:
+ type = bgl.GL_BYTE
+ elif type == np.int16:
+ type = bgl.GL_SHORT
+ elif type == np.int32:
+ type = bgl.GL_INT
+ elif type == np.float32:
+ type = bgl.GL_FLOAT
+ elif type == np.float64:
+ type = bgl.GL_DOUBLE
+ else:
+ raise
+
+ _decref = ctypes.pythonapi.Py_DecRef
+ _incref = ctypes.pythonapi.Py_IncRef
+
+ _decref.argtypes = _incref.argtypes = [ctypes.py_object]
+ _decref.restype = _incref.restype = None
+
+ buf = bgl.Buffer(bgl.GL_BYTE, (1, *array.shape))[0]
+ c_buf = C_Buffer.from_address(id(buf))
+
+ _decref(c_buf.parent)
+ _incref(array)
+
+ c_buf.parent = array # Prevents MEM_freeN
+ c_buf.type = type
+ c_buf.buf = array.ctypes.data
+
+ return buf
+
+
+def bgl_Buffer_reshape(buf, shape):
+ assert np.prod(buf.dimensions) == np.prod(shape)
+
+ c_buf = C_Buffer.from_address(id(buf))
+ c_buf.ndimensions = len(shape)
+
+ tmp_buf = bgl.Buffer(c_buf.type, (1,) * len(shape))
+ c_tmp_buf = C_Buffer.from_address(id(tmp_buf))
+ for i, v in enumerate(shape):
+ c_tmp_buf.dimensions[i] = v
+
+ offset = C_Buffer.dimensions.offset
+ a = ctypes.pointer(ctypes.c_void_p.from_address(id(tmp_buf) + offset))
+ b = ctypes.pointer(ctypes.c_void_p.from_address(id(buf) + offset))
+
+ a[0], b[0] = b[0], a[0]
+
+ del c_buf
+ del c_tmp_buf
+ del tmp_buf
+
+
+def get_clip_planes(rv3d):
+ #(int)(&((struct RegionView3D *)0)->rflag) == 842
+ #(int)(&((struct RegionView3D *)0)->clip) == 464
+ rv3d_ptr = rv3d.as_pointer()
+ rflag = ctypes.c_short.from_address(rv3d_ptr + 842).value
+ if rflag & 4: # RV3D_CLIPPING
+ clip = (6 * (4 * ctypes.c_float)).from_address(rv3d_ptr + 464)
+ return bgl.Buffer(bgl.GL_FLOAT, (6, 4), clip)
diff --git a/modules/snap_context/mesh_drawing.py b/modules/snap_context/mesh_drawing.py
new file mode 100644
index 00000000..f7087b16
--- /dev/null
+++ b/modules/snap_context/mesh_drawing.py
@@ -0,0 +1,505 @@
+# ##### 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 3
+# 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, see <http://www.gnu.org/licenses/>.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+
+import bgl
+import bmesh
+import numpy as np
+from mathutils import Matrix
+
+from .bgl_ext import VoidBufValue, np_array_as_bgl_Buffer, bgl_Buffer_reshape
+from .utils_shader import Shader
+
+
+def load_shader(shadername):
+ from os import path
+ with open(path.join(path.dirname(__file__), 'resources', shadername), 'r') as f:
+ return f.read()
+
+
+def get_mesh_vert_co_array(me):
+ tot_vco = len(me.vertices)
+ if tot_vco:
+ verts_co = bgl.Buffer(bgl.GL_FLOAT, (tot_vco * 3))
+ me.vertices.foreach_get("co", verts_co)
+ bgl_Buffer_reshape(verts_co, (tot_vco, 3))
+ return verts_co
+ return None
+
+
+def get_bmesh_vert_co_array(bm):
+ tot_vco = len(bm.verts)
+ if tot_vco:
+ return bgl.Buffer(bgl.GL_FLOAT, (tot_vco, 3), [v.co for v in bm.verts])
+ return None
+
+
+def get_mesh_tri_verts_array(me):
+ num_tris = len(me.loops) - 2 * len(me.polygons)
+ if num_tris:
+ bm = bmesh.new()
+ bm.from_mesh(me, face_normals=False)
+ ltris = bm.calc_tessface()
+ tris = bgl.Buffer(bgl.GL_INT, (num_tris, 3))
+ for i, ltri in enumerate(ltris):
+ tris[i] = ltri[0].vert.index, ltri[1].vert.index, ltri[2].vert.index
+ bm.free()
+ return tris
+ return None
+
+
+def get_mesh_tri_co_array(me, tri_verts):
+ num_tris = len(tri_verts)
+ if num_tris:
+ verts = me.vertices
+ tris = bgl.Buffer(bgl.GL_FLOAT, (num_tris, 3, 3))
+ for i, tri in enumerate(tri_verts):
+ tris[i] = verts[tri[0]].co, verts[tri[1]].co, verts[tri[2]].co
+ return tris
+ return None
+
+
+def get_bmesh_tri_verts_array(bm):
+ ltris = bm.calc_tessface()
+ tris = [[ltri[0].vert.index, ltri[1].vert.index, ltri[2].vert.index] for ltri in ltris if not ltri[0].face.hide]
+ if tris:
+ return bgl.Buffer(bgl.GL_INT, (len(tris), 3), tris)
+ return None
+
+
+def get_bmesh_tri_co_array(bm, tri_verts):
+ num_tris = len(tri_verts)
+ if num_tris:
+ verts = bm.verts
+ tris = bgl.Buffer(bgl.GL_FLOAT, (num_tris, 3, 3))
+ for i, tri in enumerate(tri_verts):
+ tris[i] = verts[tri[0]].co, verts[tri[1]].co, verts[tri[2]].co
+ return tris
+ return None
+
+
+def get_mesh_edge_verts_array(me):
+ tot_edges = len(me.edges)
+ if tot_edges:
+ edge_verts = np.empty(tot_edges * 2, 'i4')
+ me.edges.foreach_get("vertices", edge_verts)
+ edge_verts.shape = tot_edges, 2
+ return np_array_as_bgl_Buffer(edge_verts)
+ return None
+
+
+def get_mesh_edge_co_array(me, edge_verts):
+ if edge_verts:
+ edges_co = bgl.Buffer(bgl.GL_FLOAT, (len(edge_verts), 2, 3))
+ verts = me.vertices
+ for i, (v0, v1) in enumerate(edge_verts):
+ edges_co[i][0] = verts[v0].co
+ edges_co[i][1] = verts[v1].co
+ return edges_co
+ return None
+
+
+def get_bmesh_edge_verts_array(bm):
+ bm.edges.ensure_lookup_table()
+ edges = [[e.verts[0].index, e.verts[1].index] for e in bm.edges if not e.hide]
+ if edges:
+ return bgl.Buffer(bgl.GL_INT, (len(edges), 2), edges)
+ return None
+
+
+def get_bmesh_edge_co_array(bm, edge_verts):
+ if edge_verts:
+ edges_co = bgl.Buffer(bgl.GL_FLOAT, (len(edge_verts), 2, 3))
+ verts = bm.verts
+ for i, (v0, v1) in enumerate(edge_verts):
+ edges_co[i][0] = verts[v0].co
+ edges_co[i][1] = verts[v1].co
+ return edges_co
+ return None
+
+
+def get_mesh_loosevert_array(me, edges):
+ verts = np.arange(len(me.vertices))
+
+ mask = np.in1d(verts, edges, invert=True)
+
+ verts = verts[mask]
+ if len(verts):
+ return bgl.Buffer(bgl.GL_INT, len(verts), verts)
+ return None
+
+
+def get_bmesh_loosevert_array(bm):
+ looseverts = [v.index for v in bm.verts if not (v.link_edges or v.hide)]
+ if looseverts:
+ return bgl.Buffer(bgl.GL_INT, len(looseverts), looseverts)
+ return None
+
+
+class _Mesh_Arrays():
+ def __init__(self, obj, create_tris, create_edges, create_looseverts):
+ self.tri_verts = self.edge_verts = self.looseverts = None
+ self.tris_co = self.edges_co = self.looseverts_co = None
+ if obj.type == 'MESH':
+ me = obj.data
+ if me.is_editmode:
+ bm = bmesh.from_edit_mesh(me)
+ bm.verts.ensure_lookup_table()
+
+ if False: #Blender 2.8
+ self.verts = get_bmesh_vert_co_array(bm)
+ if create_tris:
+ self.tri_verts = get_bmesh_tri_verts_array(bm)
+ self.tris_co = get_bmesh_tri_co_array(bm, self.tri_verts)
+ if create_edges:
+ self.edge_verts = get_bmesh_edge_verts_array(bm)
+ self.edges_co = get_bmesh_edge_co_array(bm, self.edge_verts)
+ if create_looseverts:
+ self.looseverts = get_bmesh_loosevert_array(bm)
+ if self.looseverts:
+ self.looseverts_co = bgl.Buffer(bgl.GL_FLOAT, (len(self.looseverts), 3), [bm.verts[i].co for i in self.looseverts])
+ else:
+ if False: #Blender 2.8
+ self.verts = get_mesh_vert_co_array(me)
+ if create_tris:
+ self.tri_verts = get_mesh_tri_verts_array(me)
+ self.tris_co = get_mesh_tri_co_array(me, self.tri_verts)
+ if create_edges or create_looseverts:
+ self.edge_verts = get_mesh_edge_verts_array(me)
+
+ if create_edges:
+ self.edges_co = get_mesh_edge_co_array(me, self.edge_verts)
+ if create_looseverts:
+ self.looseverts = get_mesh_loosevert_array(me, self.edge_verts)
+ if self.looseverts:
+ self.looseverts_co = bgl.Buffer(bgl.GL_FLOAT, (len(self.looseverts), 3), [me.vertices[i].co for i in self.looseverts])
+
+ else: #TODO
+ self.looseverts = bgl.Buffer(bgl.GL_INT, 1)
+ self.looseverts_co = bgl.Buffer(bgl.GL_FLOAT, (1, 3))
+
+ def __del__(self):
+ del self.tri_verts, self.edge_verts, self.looseverts
+ del self.tris_co, self.edges_co, self.looseverts_co
+
+
+class GPU_Indices_Mesh():
+ shader = Shader(
+ load_shader('3D_vert.glsl'),
+ None,
+ load_shader('primitive_id_frag.glsl'),
+ )
+
+ unif_use_clip_planes = bgl.glGetUniformLocation(shader.program, 'use_clip_planes')
+ unif_clip_plane = bgl.glGetUniformLocation(shader.program, 'clip_plane')
+
+ unif_MVP = bgl.glGetUniformLocation(shader.program, 'MVP')
+ unif_MV = bgl.glGetUniformLocation(shader.program, 'MV')
+ unif_offset = bgl.glGetUniformLocation(shader.program, 'offset')
+
+ attr_pos = bgl.glGetAttribLocation(shader.program, 'pos')
+ attr_primitive_id = bgl.glGetAttribLocation(shader.program, 'primitive_id')
+
+ P = bgl.Buffer(bgl.GL_FLOAT, (4, 4))
+ MV = bgl.Buffer(bgl.GL_FLOAT, (4, 4))
+
+ # returns of public API #
+ vert_index = bgl.Buffer(bgl.GL_INT, 1)
+
+ tri_co = bgl.Buffer(bgl.GL_FLOAT, (3, 3))
+ edge_co = bgl.Buffer(bgl.GL_FLOAT, (2, 3))
+ vert_co = bgl.Buffer(bgl.GL_FLOAT, 3)
+
+ def __init__(self, obj, draw_tris, draw_edges, draw_verts):
+ self._NULL = VoidBufValue(0)
+
+ self.MVP = bgl.Buffer(bgl.GL_FLOAT, (4, 4))
+
+ self.obj = obj
+ self.draw_tris = draw_tris
+ self.draw_edges = draw_edges
+ self.draw_verts = draw_verts
+
+ self.vbo = None
+ self.vbo_tris = None
+ self.vbo_edges = None
+ self.vbo_verts = None
+
+ ## Create VAO ##
+ self.vao = bgl.Buffer(bgl.GL_INT, 1)
+ bgl.glGenVertexArrays(1, self.vao)
+ bgl.glBindVertexArray(self.vao[0])
+
+ ## Init Array ##
+ mesh_arrays = _Mesh_Arrays(obj, draw_tris, draw_edges, draw_verts)
+
+ ## Create VBO for vertices ##
+ if False: # Blender 2.8
+ if not mesh_arrays.verts:
+ self.draw_tris = False
+ self.draw_edges = False
+ self.draw_verts = False
+ return
+
+ self.vbo_len = len(mesh_arrays.verts)
+
+ self.vbo = bgl.Buffer(bgl.GL_INT, 1)
+ bgl.glGenBuffers(1, self.vbo)
+ bgl.glBindBuffer(bgl.GL_ARRAY_BUFFER, self.vbo[0])
+ bgl.glBufferData(bgl.GL_ARRAY_BUFFER, self.vbo_len * 12, mesh_arrays.verts, bgl.GL_STATIC_DRAW)
+
+ ## Create VBO for Tris ##
+ if mesh_arrays.tri_verts:
+ self.tri_verts = mesh_arrays.tri_verts
+ self.num_tris = len(self.tri_verts)
+
+ self.vbo_tris = bgl.Buffer(bgl.GL_INT, 1)
+ bgl.glGenBuffers(1, self.vbo_tris)
+ bgl.glBindBuffer(bgl.GL_ARRAY_BUFFER, self.vbo_tris[0])
+ bgl.glBufferData(bgl.GL_ARRAY_BUFFER, self.num_tris * 36, mesh_arrays.tris_co, bgl.GL_STATIC_DRAW)
+
+ tri_indices = np.repeat(np.arange(self.num_tris, dtype = 'f4'), 3)
+ self.vbo_tri_indices = bgl.Buffer(bgl.GL_INT, 1)
+ bgl.glGenBuffers(1, self.vbo_tri_indices)
+ bgl.glBindBuffer(bgl.GL_ARRAY_BUFFER, self.vbo_tri_indices[0])
+ bgl.glBufferData(bgl.GL_ARRAY_BUFFER, self.num_tris * 12, np_array_as_bgl_Buffer(tri_indices), bgl.GL_STATIC_DRAW)
+ del tri_indices
+
+ else:
+ self.num_tris = 0
+ self.draw_tris = False
+
+ ## Create VBO for Edges ##
+ if mesh_arrays.edge_verts:
+ self.edge_verts = mesh_arrays.edge_verts
+ self.num_edges = len(self.edge_verts)
+
+ self.vbo_edges = bgl.Buffer(bgl.GL_INT, 1)
+ bgl.glGenBuffers(1, self.vbo_edges)
+ bgl.glBindBuffer(bgl.GL_ARRAY_BUFFER, self.vbo_edges[0])
+ bgl.glBufferData(bgl.GL_ARRAY_BUFFER, self.num_edges * 24, mesh_arrays.edges_co, bgl.GL_STATIC_DRAW)
+
+ edge_indices = np.repeat(np.arange(self.num_edges, dtype = 'f4'),2)
+ self.vbo_edge_indices = bgl.Buffer(bgl.GL_INT, 1)
+ bgl.glGenBuffers(1, self.vbo_edge_indices)
+ bgl.glBindBuffer(bgl.GL_ARRAY_BUFFER, self.vbo_edge_indices[0])
+ bgl.glBufferData(bgl.GL_ARRAY_BUFFER, self.num_edges * 8, np_array_as_bgl_Buffer(edge_indices), bgl.GL_STATIC_DRAW)
+ del edge_indices
+ else:
+ self.num_edges = 0
+ self.draw_edges = False
+
+ ## Create EBO for Loose Verts ##
+ if mesh_arrays.looseverts:
+ self.looseverts = mesh_arrays.looseverts
+ self.num_verts = len(mesh_arrays.looseverts)
+
+ self.vbo_verts = bgl.Buffer(bgl.GL_INT, 1)
+ bgl.glGenBuffers(1, self.vbo_verts)
+ bgl.glBindBuffer(bgl.GL_ARRAY_BUFFER, self.vbo_verts[0])
+ bgl.glBufferData(bgl.GL_ARRAY_BUFFER, self.num_verts * 12, mesh_arrays.looseverts_co, bgl.GL_STATIC_DRAW)
+
+ looseverts_indices = np.arange(self.num_verts, dtype = 'f4')
+ self.vbo_looseverts_indices = bgl.Buffer(bgl.GL_INT, 1)
+ bgl.glGenBuffers(1, self.vbo_looseverts_indices)
+ bgl.glBindBuffer(bgl.GL_ARRAY_BUFFER, self.vbo_looseverts_indices[0])
+ bgl.glBufferData(bgl.GL_ARRAY_BUFFER, self.num_verts * 4, np_array_as_bgl_Buffer(looseverts_indices), bgl.GL_STATIC_DRAW)
+ del looseverts_indices
+ else:
+ self.num_verts = 0
+ self.draw_verts = False
+
+ del mesh_arrays
+
+ bgl.glBindVertexArray(0)
+
+
+ def get_tot_elems(self):
+ tot = 0
+
+ if self.draw_tris:
+ tot += self.num_tris
+
+ if self.draw_edges:
+ tot += self.num_edges
+
+ if self.draw_verts:
+ tot += self.num_verts
+
+ return tot
+
+
+ def set_draw_mode(self, draw_tris, draw_edges, draw_verts):
+ self.draw_tris = draw_tris and self.vbo_tris
+ self.draw_edges = draw_edges and self.vbo_edges
+ self.draw_verts = draw_verts and self.vbo_verts
+
+
+ @classmethod
+ def set_ProjectionMatrix(cls, P):
+ cls.P[:] = P
+
+
+ def set_ModelViewMatrix(self, MV):
+ self.MV[:] = MV[:]
+ self.MVP[:] = Matrix(self.P) * MV
+
+
+ def Draw(self, index_offset):
+ self.first_index = index_offset
+ bgl.glUseProgram(self.shader.program)
+ bgl.glBindVertexArray(self.vao[0])
+
+ bgl.glUniformMatrix4fv(self.unif_MV, 1, bgl.GL_TRUE, self.MV)
+ bgl.glUniformMatrix4fv(self.unif_MVP, 1, bgl.GL_TRUE, self.MVP)
+
+ if self.draw_tris:
+ bgl.glUniform1f(self.unif_offset, float(index_offset)) # bgl has no glUniform1ui :\
+
+ bgl.glBindBuffer(bgl.GL_ARRAY_BUFFER, self.vbo_tris[0])
+ bgl.glEnableVertexAttribArray(self.attr_pos)
+ bgl.glVertexAttribPointer(self.attr_pos, 3, bgl.GL_FLOAT, bgl.GL_FALSE, 0, self._NULL.buf)
+
+ bgl.glBindBuffer(bgl.GL_ARRAY_BUFFER, self.vbo_tri_indices[0])
+ bgl.glEnableVertexAttribArray(self.attr_primitive_id)
+ bgl.glVertexAttribPointer(self.attr_primitive_id, 1, bgl.GL_FLOAT, bgl.GL_FALSE, 0, self._NULL.buf)
+
+ bgl.glDrawArrays(bgl.GL_TRIANGLES, 0, self.num_tris * 3)
+
+ index_offset += self.num_tris
+ bgl.glDepthRange(-0.00005, 0.99995)
+
+ if self.draw_edges:
+ bgl.glUniform1f(self.unif_offset, float(index_offset)) #TODO: use glUniform1ui
+
+ bgl.glBindBuffer(bgl.GL_ARRAY_BUFFER, self.vbo_edges[0])
+ bgl.glVertexAttribPointer(self.attr_pos, 3, bgl.GL_FLOAT, bgl.GL_FALSE, 0, self._NULL.buf)
+ bgl.glEnableVertexAttribArray(self.attr_pos)
+
+ bgl.glBindBuffer(bgl.GL_ARRAY_BUFFER, self.vbo_edge_indices[0])
+ bgl.glVertexAttribPointer(self.attr_primitive_id, 1, bgl.GL_FLOAT, bgl.GL_FALSE, 0, self._NULL.buf)
+ bgl.glEnableVertexAttribArray(self.attr_primitive_id)
+
+ bgl.glDrawArrays(bgl.GL_LINES, 0, self.num_edges * 2)
+
+ index_offset += self.num_edges
+
+ if self.draw_verts:
+ bgl.glUniform1f(self.unif_offset, float(index_offset)) #TODO: use glUniform1ui
+
+ bgl.glBindBuffer(bgl.GL_ARRAY_BUFFER, self.vbo_verts[0])
+ bgl.glVertexAttribPointer(self.attr_pos, 3, bgl.GL_FLOAT, bgl.GL_FALSE, 0, self._NULL.buf)
+ bgl.glEnableVertexAttribArray(self.attr_pos)
+
+ bgl.glBindBuffer(bgl.GL_ARRAY_BUFFER, self.vbo_looseverts_indices[0])
+ bgl.glVertexAttribPointer(self.attr_primitive_id, 1, bgl.GL_FLOAT, bgl.GL_FALSE, 0, self._NULL.buf)
+ bgl.glEnableVertexAttribArray(self.attr_primitive_id)
+
+ bgl.glDrawArrays(bgl.GL_POINTS, 0, self.num_verts)
+
+ bgl.glDepthRange(0.0, 1.0)
+
+
+ def get_tri_co(self, index):
+ bgl.glBindVertexArray(self.vao[0])
+ bgl.glBindBuffer(bgl.GL_ARRAY_BUFFER, self.vbo_tris[0])
+ bgl.glGetBufferSubData(bgl.GL_ARRAY_BUFFER, index * 36, 36, self.tri_co)
+ bgl.glBindVertexArray(0)
+ return self.tri_co
+
+
+ def get_edge_co(self, index):
+ bgl.glBindVertexArray(self.vao[0])
+ bgl.glBindBuffer(bgl.GL_ARRAY_BUFFER, self.vbo_edges[0])
+ bgl.glGetBufferSubData(bgl.GL_ARRAY_BUFFER, index * 24, 24, self.edge_co)
+ bgl.glBindVertexArray(0)
+ return self.edge_co
+
+
+ def get_loosevert_co(self, index):
+ bgl.glBindVertexArray(self.vao[0])
+ bgl.glBindBuffer(bgl.GL_ARRAY_BUFFER, self.vbo_verts[0])
+ bgl.glGetBufferSubData(bgl.GL_ARRAY_BUFFER, index * 12, 12, self.vert_co)
+ bgl.glBindVertexArray(0)
+ return self.vert_co
+
+
+ def get_tri_verts(self, index):
+ return self.tri_verts[index]
+
+
+ def get_edge_verts(self, index):
+ return self.edge_verts[index]
+
+
+ def get_loosevert_index(self, index):
+ return self.looseverts[index]
+
+
+ def __del__(self):
+ del self._NULL
+
+ if self.vbo_tris:
+ bgl.glDeleteBuffers(1, self.vbo_tris)
+ bgl.glDeleteBuffers(1, self.vbo_tri_indices)
+ del self.tri_verts
+
+ if self.vbo_edges:
+ bgl.glDeleteBuffers(1, self.vbo_edges)
+ bgl.glDeleteBuffers(1, self.vbo_edge_indices)
+ del self.edge_verts
+
+ if self.vbo_verts:
+ bgl.glDeleteBuffers(1, self.vbo_verts)
+ bgl.glDeleteBuffers(1, self.vbo_looseverts_indices)
+ del self.looseverts
+
+ bgl.glDeleteVertexArrays(1, self.vao)
+ #print('mesh_del', self.obj.name)
+
+
+class PreviousGLState:
+ buf = bgl.Buffer(bgl.GL_INT, (4, 1))
+ cur_program = buf[0]
+ cur_vao = buf[1]
+ cur_vbo = buf[2]
+ cur_ebo = buf[3]
+
+
+def _store_current_shader_state(cls):
+ bgl.glGetIntegerv(bgl.GL_CURRENT_PROGRAM, cls.cur_program)
+ bgl.glGetIntegerv(bgl.GL_VERTEX_ARRAY_BINDING, cls.cur_vao)
+ bgl.glGetIntegerv(bgl.GL_ARRAY_BUFFER_BINDING, cls.cur_vbo)
+ bgl.glGetIntegerv(bgl.GL_ELEMENT_ARRAY_BUFFER_BINDING, cls.cur_ebo)
+
+
+def _restore_shader_state(cls):
+ bgl.glUseProgram(cls.cur_program[0])
+ bgl.glBindVertexArray(cls.cur_vao[0])
+ bgl.glBindBuffer(bgl.GL_ARRAY_BUFFER, cls.cur_vbo[0])
+ bgl.glBindBuffer(bgl.GL_ELEMENT_ARRAY_BUFFER, cls.cur_ebo[0])
+
+
+def gpu_Indices_enable_state():
+ _store_current_shader_state(PreviousGLState)
+
+ bgl.glUseProgram(GPU_Indices_Mesh.shader.program)
+ #bgl.glBindVertexArray(GPU_Indices_Mesh.vao[0])
+
+def gpu_Indices_restore_state():
+ bgl.glBindVertexArray(0)
+ _restore_shader_state(PreviousGLState)
diff --git a/modules/snap_context/resources/3D_vert.glsl b/modules/snap_context/resources/3D_vert.glsl
new file mode 100644
index 00000000..63891b93
--- /dev/null
+++ b/modules/snap_context/resources/3D_vert.glsl
@@ -0,0 +1,27 @@
+#version 120
+
+uniform bool use_clip_planes;
+uniform vec4 clip_plane[4];
+varying vec4 clip_distance;
+
+uniform mat4 MV;
+uniform mat4 MVP;
+
+attribute vec3 pos;
+attribute float primitive_id;
+varying float primitive_id_var;
+
+void main()
+{
+ if (use_clip_planes) {
+ vec4 g_pos = MV * vec4(pos, 1.0);
+
+ clip_distance[0] = dot(clip_plane[0], g_pos);
+ clip_distance[1] = dot(clip_plane[1], g_pos);
+ clip_distance[2] = dot(clip_plane[2], g_pos);
+ clip_distance[3] = dot(clip_plane[3], g_pos);
+ }
+
+ primitive_id_var = primitive_id;
+ gl_Position = MVP * vec4(pos, 1.0);
+}
diff --git a/modules/snap_context/resources/primitive_id_frag.glsl b/modules/snap_context/resources/primitive_id_frag.glsl
new file mode 100644
index 00000000..43801425
--- /dev/null
+++ b/modules/snap_context/resources/primitive_id_frag.glsl
@@ -0,0 +1,22 @@
+#version 120
+
+uniform bool use_clip_planes;
+varying vec4 clip_distance;
+
+uniform float offset;
+
+flat varying float primitive_id_var;
+
+void main()
+{
+ if (use_clip_planes &&
+ ((clip_distance[0] < 0) ||
+ (clip_distance[1] < 0) ||
+ (clip_distance[2] < 0) ||
+ (clip_distance[3] < 0)))
+ {
+ discard;
+ }
+
+ gl_FragColor = vec4(offset + primitive_id_var, 0, 0, 0);
+}
diff --git a/modules/snap_context/utils_projection.py b/modules/snap_context/utils_projection.py
new file mode 100644
index 00000000..70c110f4
--- /dev/null
+++ b/modules/snap_context/utils_projection.py
@@ -0,0 +1,213 @@
+# ##### 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 3
+# 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, see <http://www.gnu.org/licenses/>.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+
+from mathutils import Vector
+from mathutils.geometry import intersect_point_line
+
+
+def depth_get(co, ray_start, ray_dir):
+ dvec = co - ray_start
+ return dvec.dot(ray_dir)
+
+
+def region_2d_to_orig_and_view_vector(region, rv3d, coord):
+ viewinv = rv3d.view_matrix.inverted()
+ persinv = rv3d.perspective_matrix.inverted()
+
+ dx = (2.0 * coord[0] / region.width) - 1.0
+ dy = (2.0 * coord[1] / region.height) - 1.0
+
+ if rv3d.is_perspective:
+ origin_start = viewinv.translation.copy()
+
+ out = Vector((dx, dy, -0.5))
+
+ w = out.dot(persinv[3].xyz) + persinv[3][3]
+
+ view_vector = ((persinv * out) / w) - origin_start
+ else:
+ view_vector = -viewinv.col[2].xyz
+
+ origin_start = ((persinv.col[0].xyz * dx) +
+ (persinv.col[1].xyz * dy) +
+ viewinv.translation)
+
+ view_vector.normalize()
+ return view_vector, origin_start
+
+
+def project_co_v3(sctx, co):
+ proj_co = sctx.proj_mat * co.to_4d()
+ proj_co.xy /= proj_co.w
+
+ win_half = sctx.winsize * 0.5
+ proj_co[0] = (proj_co[0] + 1.0) * win_half[0]
+ proj_co[1] = (proj_co[1] + 1.0) * win_half[1]
+
+ return proj_co.xy
+
+
+
+def intersect_boundbox_threshold(sctx, MVP, ray_origin_local, ray_direction_local, bbmin, bbmax):
+ local_bvmin = Vector()
+ local_bvmax = Vector()
+ tmin = Vector()
+ tmax = Vector()
+
+ if (ray_direction_local[0] < 0.0):
+ local_bvmin[0] = bbmax[0]
+ local_bvmax[0] = bbmin[0]
+ else:
+ local_bvmin[0] = bbmin[0]
+ local_bvmax[0] = bbmax[0]
+
+ if (ray_direction_local[1] < 0.0):
+ local_bvmin[1] = bbmax[1]
+ local_bvmax[1] = bbmin[1]
+ else:
+ local_bvmin[1] = bbmin[1]
+ local_bvmax[1] = bbmax[1]
+
+ if (ray_direction_local[2] < 0.0):
+ local_bvmin[2] = bbmax[2]
+ local_bvmax[2] = bbmin[2]
+ else:
+ local_bvmin[2] = bbmin[2]
+ local_bvmax[2] = bbmax[2]
+
+ if (ray_direction_local[0]):
+ tmin[0] = (local_bvmin[0] - ray_origin_local[0]) / ray_direction_local[0]
+ tmax[0] = (local_bvmax[0] - ray_origin_local[0]) / ray_direction_local[0]
+ else:
+ tmin[0] = tmax[0] = sctx.depth_range[1]
+
+ if (ray_direction_local[1]):
+ tmin[1] = (local_bvmin[1] - ray_origin_local[1]) / ray_direction_local[1]
+ tmax[1] = (local_bvmax[1] - ray_origin_local[1]) / ray_direction_local[1]
+ else:
+ tmin[1] = tmax[1] = sctx.depth_range[1]
+
+ if (ray_direction_local[2]):
+ tmin[2] = (local_bvmin[2] - ray_origin_local[2]) / ray_direction_local[2]
+ tmax[2] = (local_bvmax[2] - ray_origin_local[2]) / ray_direction_local[2]
+ else:
+ tmin[2] = tmax[2] = sctx.depth_range[1]
+
+ # `va` and `vb` are the coordinates of the AABB edge closest to the ray #
+ va = Vector()
+ vb = Vector()
+ # `rtmin` and `rtmax` are the minimum and maximum distances of the ray hits on the AABB #
+
+ if ((tmax[0] <= tmax[1]) and (tmax[0] <= tmax[2])):
+ rtmax = tmax[0]
+ va[0] = vb[0] = local_bvmax[0]
+ main_axis = 3
+ elif ((tmax[1] <= tmax[0]) and (tmax[1] <= tmax[2])):
+ rtmax = tmax[1]
+ va[1] = vb[1] = local_bvmax[1]
+ main_axis = 2
+ else:
+ rtmax = tmax[2]
+ va[2] = vb[2] = local_bvmax[2]
+ main_axis = 1
+
+ if ((tmin[0] >= tmin[1]) and (tmin[0] >= tmin[2])):
+ rtmin = tmin[0]
+ va[0] = vb[0] = local_bvmin[0]
+ main_axis -= 3
+
+ elif ((tmin[1] >= tmin[0]) and (tmin[1] >= tmin[2])):
+ rtmin = tmin[1]
+ va[1] = vb[1] = local_bvmin[1]
+ main_axis -= 1
+
+ else:
+ rtmin = tmin[2]
+ va[2] = vb[2] = local_bvmin[2]
+ main_axis -= 2
+
+ if (main_axis < 0):
+ main_axis += 3
+
+#ifdef IGNORE_BEHIND_RAY
+ depth_max = depth_get(local_bvmax, ray_origin_local, ray_direction_local)
+ if (depth_max < sctx.depth_range[0]):
+ return False
+#endif
+
+ if (rtmin <= rtmax):
+ # if rtmin < rtmax, ray intersect `AABB` #
+ return True
+
+ if (ray_direction_local[main_axis] < 0.0):
+ va[main_axis] = local_bvmax[main_axis]
+ vb[main_axis] = local_bvmin[main_axis]
+
+ else:
+ va[main_axis] = local_bvmin[main_axis]
+ vb[main_axis] = local_bvmax[main_axis]
+
+ win_half = sctx.winsize * 0.5
+
+ scale = abs(local_bvmax[main_axis] - local_bvmin[main_axis])
+
+ va2d = Vector((
+ (MVP[0].xyz.dot(va) + MVP[0][3]),
+ (MVP[1].xyz.dot(va) + MVP[1][3]),
+ ))
+
+ vb2d = Vector((
+ (va2d[0] + MVP[0][main_axis] * scale),
+ (va2d[1] + MVP[1][main_axis] * scale),
+ ))
+
+ depth_a = MVP[3].xyz.dot(va) + MVP[3][3]
+ depth_b = depth_a + MVP[3][main_axis] * scale
+
+ va2d /= depth_a
+ vb2d /= depth_b
+
+ va2d[0] = (va2d[0] + 1.0) * win_half[0]
+ va2d[1] = (va2d[1] + 1.0) * win_half[1]
+ vb2d[0] = (vb2d[0] + 1.0) * win_half[0]
+ vb2d[1] = (vb2d[1] + 1.0) * win_half[1]
+
+ p, fac = intersect_point_line(sctx.mval, va2d, vb2d)
+ if fac < 0.0:
+ return (sctx.mval - va2d).length_squared < sctx._dist_px_sq
+ elif fac > 1.0:
+ return (sctx.mval - vb2d).length_squared < sctx._dist_px_sq
+ else:
+ return (sctx.mval - p).length_squared < sctx._dist_px_sq
+
+
+def intersect_ray_segment_fac(v0, v1, ray_direction, ray_origin):
+ a = v1 - v0
+ t = v0 - ray_origin
+ n = a.cross(ray_direction)
+ nlen = n.length_squared
+
+ # if (nlen == 0.0f) the lines are parallel, has no nearest point, only distance squared.*/
+ if nlen == 0.0:
+ # Calculate the distance to the nearest point to origin then #
+ return a.dot(ray_direction) < 0
+ else:
+ c = n - t
+ cray = c.cross(ray_direction)
+ return cray.dot(n) / nlen
+
diff --git a/modules/snap_context/utils_shader.py b/modules/snap_context/utils_shader.py
new file mode 100644
index 00000000..7a664ad6
--- /dev/null
+++ b/modules/snap_context/utils_shader.py
@@ -0,0 +1,85 @@
+# ##### 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 3
+# 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, see <http://www.gnu.org/licenses/>.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+
+import bgl
+
+def check_shaderError(shader, flag, isProgram, errorMessage):
+ success = bgl.Buffer(bgl.GL_INT, 1)
+
+ if isProgram:
+ bgl.glGetProgramiv(shader, flag, success)
+ else:
+ bgl.glGetShaderiv(shader, flag, success)
+
+ if success[0] == bgl.GL_FALSE:
+ import numpy as np
+ from .bgl_ext import VoidBufValue
+
+ offset = VoidBufValue(None)
+ error = bgl.Buffer(bgl.GL_BYTE, 1024)
+ if isProgram:
+ bgl.glGetProgramInfoLog(shader, 1024, offset.buf, error)
+ print(errorMessage, np.bytes_(error).decode("utf-8"))
+ else:
+ bgl.glGetShaderInfoLog(shader, 1024, offset.buf, error)
+ print(errorMessage, np.bytes_(error).decode("utf-8"))
+
+ del offset
+ raise #RuntimeError(errorMessage, bgl.glGetShaderInfoLog(shader))
+
+
+def create_shader(source, shaderType):
+ shader = bgl.glCreateShader(shaderType)
+
+ if shader == 0:
+ raise RuntimeError("Error: Shader creation failed!")
+
+ bgl.glShaderSource(shader, source)
+ bgl.glCompileShader(shader)
+
+ check_shaderError(shader, bgl.GL_COMPILE_STATUS, False, "Error: Shader compilation failed:")
+
+ return shader
+
+
+class Shader():
+ def __init__(self, vertexcode, geomcode, fragcode):
+ self.program = bgl.glCreateProgram()
+ self.shaders = []
+
+ if vertexcode:
+ self.shaders.append(create_shader(vertexcode, bgl.GL_VERTEX_SHADER))
+ if geomcode:
+ self.shaders.append(create_shader(geomcode, bgl.GL_GEOMETRY_SHADER))
+ if fragcode:
+ self.shaders.append(create_shader(fragcode, bgl.GL_FRAGMENT_SHADER))
+
+ for shad in self.shaders:
+ bgl.glAttachShader(self.program, shad)
+
+ bgl.glLinkProgram(self.program)
+ check_shaderError(self.program, bgl.GL_LINK_STATUS, True, "Error: Program linking failed:")
+ bgl.glValidateProgram(self.program)
+ check_shaderError(self.program, bgl.GL_VALIDATE_STATUS, True, "Error: Program is invalid:")
+
+ def __del__(self):
+ for shad in self.shaders:
+ bgl.glDetachShader(self.program, shad)
+ bgl.glDeleteShader(shad)
+ bgl.glDeleteProgram(self.program)
+ print('shader_del')