# SPDX-License-Identifier: GPL-2.0-or-later import gpu from mathutils import Vector, Matrix class SnapDrawn(): __slots__ = ( 'out_color', 'face_color', 'edge_color', 'vert_color', 'center_color', 'perpendicular_color', 'constrain_shift_color', 'axis_x_color', 'axis_y_color', 'axis_z_color', 'rv3d', '_point_size', '_line_width', '_format_pos', '_format_pos_and_color', '_program_unif_col', '_program_smooth_col', '_UBO', '_batch_point',) def __init__(self, out_color, face_color, edge_color, vert_color, center_color, perpendicular_color, constrain_shift_color, axis_x_color, axis_y_color, axis_z_color, rv3d, ui_scale): import gpu self.out_color = out_color self.face_color = face_color self.edge_color = edge_color self.vert_color = vert_color self.center_color = center_color self.perpendicular_color = perpendicular_color self.constrain_shift_color = constrain_shift_color self.axis_x_color = axis_x_color self.axis_y_color = axis_y_color self.axis_z_color = axis_z_color self.rv3d = rv3d self._point_size = 5 * ui_scale self._line_width = 3 * ui_scale self._format_pos = gpu.types.GPUVertFormat() self._format_pos.attr_add( id="pos", comp_type='F32', len=3, fetch_mode='FLOAT') self._format_pos_and_color = gpu.types.GPUVertFormat() self._format_pos_and_color.attr_add( id="pos", comp_type='F32', len=3, fetch_mode='FLOAT') self._format_pos_and_color.attr_add( id="color", comp_type='F32', len=4, fetch_mode='FLOAT') self._UBO = None self._batch_point = None def _gl_state_push(self, ob_mat=None): clip_planes = self.rv3d.clip_planes if self.rv3d.use_clip_planes else None config = 'CLIPPED' if clip_planes else 'DEFAULT' self._program_unif_col = gpu.shader.from_builtin( "3D_UNIFORM_COLOR", config=config) self._program_smooth_col = gpu.shader.from_builtin( "3D_SMOOTH_COLOR", config=config) gpu.state.program_point_size_set(False) gpu.state.blend_set('ALPHA') gpu.matrix.push() if ob_mat: gpu.matrix.multiply_matrix(ob_mat) if clip_planes: gpu.state.clip_distances_set(4) if self._UBO is None: import ctypes class _GPUClipPlanes(ctypes.Structure): _pack_ = 16 _fields_ = [ ("ModelMatrix", (ctypes.c_float * 4) * 4), ("world", (ctypes.c_float * 4) * 6), ] mat = ob_mat.transposed() if ob_mat else Matrix.Identity(4) UBO_data = _GPUClipPlanes() UBO_data.ModelMatrix[0] = mat[0][:] UBO_data.ModelMatrix[1] = mat[1][:] UBO_data.ModelMatrix[2] = mat[2][:] UBO_data.ModelMatrix[3] = mat[3][:] UBO_data.world[0] = clip_planes[0][:] UBO_data.world[1] = clip_planes[1][:] UBO_data.world[2] = clip_planes[2][:] UBO_data.world[3] = clip_planes[3][:] self._UBO = gpu.types.GPUUniformBuf(UBO_data) self._program_unif_col.bind() self._program_unif_col.uniform_block("clipPlanes", self._UBO) self._program_smooth_col.bind() self._program_smooth_col.uniform_block("clipPlanes", self._UBO) def _gl_state_restore(self): gpu.state.blend_set('NONE') gpu.matrix.pop() if self._UBO: # del self._UBO self._UBO = None gpu.state.clip_distances_set(0) def batch_line_strip_create(self, coords): from gpu.types import ( GPUVertBuf, GPUBatch, ) vbo = GPUVertBuf(self._format_pos, len=len(coords)) vbo.attr_fill(0, data=coords) batch_lines = GPUBatch(type="LINE_STRIP", buf=vbo) return batch_lines def batch_lines_smooth_color_create(self, coords, colors): from gpu.types import ( GPUVertBuf, GPUBatch, ) vbo = GPUVertBuf(self._format_pos_and_color, len=len(coords)) vbo.attr_fill(0, data=coords) vbo.attr_fill(1, data=colors) batch_lines = GPUBatch(type="LINES", buf=vbo) return batch_lines def batch_triangles_create(self, coords): from gpu.types import ( GPUVertBuf, GPUBatch, ) vbo = GPUVertBuf(self._format_pos, len=len(coords)) vbo.attr_fill(0, data=coords) batch_tris = GPUBatch(type="TRIS", buf=vbo) return batch_tris def batch_point_get(self): if self._batch_point is None: from gpu.types import ( GPUVertBuf, GPUBatch, ) vbo = GPUVertBuf(self._format_pos, len=1) vbo.attr_fill(0, ((0.0, 0.0, 0.0),)) self._batch_point = GPUBatch(type="POINTS", buf=vbo) return self._batch_point def draw(self, type, location, list_verts_co, vector_constrain, prevloc): import gpu self._gl_state_push() self._program_unif_col.bind() if list_verts_co: # draw 3d line OpenGL in the 3D View winmat = gpu.matrix.get_projection_matrix() winmat[3][2] -= 0.0001 gpu.matrix.push_projection() gpu.matrix.load_projection_matrix(winmat) gpu.state.line_width_set(self._line_width) batch = self.batch_line_strip_create( [v.to_tuple() for v in list_verts_co] + [location.to_tuple()]) self._program_unif_col.bind() self._program_unif_col.uniform_float("color", (1.0, 0.8, 0.0, 0.5)) batch.draw(self._program_unif_col) gpu.matrix.pop_projection() del batch gpu.state.depth_test_set('NONE') point_batch = self.batch_point_get() if vector_constrain: if prevloc: gpu.state.point_size_set(self._point_size) gpu.matrix.translate(prevloc) self._program_unif_col.bind() self._program_unif_col.uniform_float( "color", (1.0, 1.0, 1.0, 0.5)) point_batch.draw(self._program_unif_col) gpu.matrix.translate(-prevloc) if vector_constrain[2] == 'X': Color4f = self.axis_x_color elif vector_constrain[2] == 'Y': Color4f = self.axis_y_color elif vector_constrain[2] == 'Z': Color4f = self.axis_z_color else: Color4f = self.constrain_shift_color else: if type == 'OUT': Color4f = self.out_color elif type == 'FACE': Color4f = self.face_color elif type == 'EDGE': Color4f = self.edge_color elif type == 'VERT': Color4f = self.vert_color elif type == 'CENTER': Color4f = self.center_color elif type == 'PERPENDICULAR': Color4f = self.perpendicular_color else: # type == None Color4f = self.out_color gpu.state.point_size_set(2 * self._point_size) gpu.matrix.translate(location) self._program_unif_col.bind() self._program_unif_col.uniform_float("color", Color4f) point_batch.draw(self._program_unif_col) # restore opengl defaults gpu.state.point_size_set(1.0) gpu.state.line_width_set(1.0) gpu.state.depth_test_set('LESS_EQUAL') self._gl_state_restore() def draw_elem(self, snap_obj, bm, elem): # TODO: Cache coords (because antialiasing) import gpu from bmesh.types import( BMVert, BMEdge, BMFace, ) self._gl_state_push(snap_obj.mat) gpu.state.depth_test_set('NONE') if isinstance(elem, BMVert): if elem.link_edges: import numpy as np color = self.vert_color edges = np.empty((len(elem.link_edges), 2), [ ("pos", "f4", 3), ("color", "f4", 4)]) edges["pos"][:, 0] = elem.co edges["pos"][:, 1] = [e.other_vert( elem).co for e in elem.link_edges] edges["color"][:, 0] = color edges["color"][:, 1] = (color[0], color[1], color[2], 0.0) edges.shape = -1 self._program_smooth_col.bind() gpu.state.line_width_set(self._line_width) batch = self.batch_lines_smooth_color_create( edges["pos"], edges["color"]) batch.draw(self._program_smooth_col) gpu.state.line_width_set(1.0) else: if isinstance(elem, BMEdge): self._program_unif_col.bind() self._program_unif_col.uniform_float("color", self.edge_color) gpu.state.line_width_set(self._line_width) batch = self.batch_line_strip_create( [v.co for v in elem.verts]) batch.draw(self._program_unif_col) gpu.state.line_width_set(1.0) elif isinstance(elem, BMFace): if len(snap_obj.data) == 2: face_color = self.face_color[0], self.face_color[1], self.face_color[2], self.face_color[3] * 0.2 self._program_unif_col.bind() self._program_unif_col.uniform_float("color", face_color) tris = snap_obj.data[1].get_loop_tri_co_by_bmface(bm, elem) tris.shape = (-1, 3) batch = self.batch_triangles_create(tris) batch.draw(self._program_unif_col) # restore opengl defaults gpu.state.depth_test_set('LESS_EQUAL') self._gl_state_restore()