io_mesh_uv_layout: speed up png export with OIIO (x7)
[blender-addons.git] / mesh_snap_utilities_line / drawing_utilities.py
blobe7eaa4ffc46d6ab4205b1a9309626c7fe9bbe4ea
1 # SPDX-License-Identifier: GPL-2.0-or-later
2 import gpu
3 from mathutils import Vector, Matrix
6 class SnapDrawn():
7 __slots__ = (
8 'out_color',
9 'face_color',
10 'edge_color',
11 'vert_color',
12 'center_color',
13 'perpendicular_color',
14 'constrain_shift_color',
15 'axis_x_color',
16 'axis_y_color',
17 'axis_z_color',
18 'rv3d',
19 '_point_size',
20 '_line_width',
21 '_format_pos',
22 '_format_pos_and_color',
23 '_program_unif_col',
24 '_program_smooth_col',
25 '_UBO',
26 '_batch_point',)
28 def __init__(self, out_color, face_color,
29 edge_color, vert_color, center_color,
30 perpendicular_color, constrain_shift_color,
31 axis_x_color, axis_y_color, axis_z_color, rv3d, ui_scale):
33 import gpu
35 self.out_color = out_color
36 self.face_color = face_color
37 self.edge_color = edge_color
38 self.vert_color = vert_color
39 self.center_color = center_color
40 self.perpendicular_color = perpendicular_color
41 self.constrain_shift_color = constrain_shift_color
43 self.axis_x_color = axis_x_color
44 self.axis_y_color = axis_y_color
45 self.axis_z_color = axis_z_color
47 self.rv3d = rv3d
49 self._point_size = 5 * ui_scale
50 self._line_width = 3 * ui_scale
52 self._format_pos = gpu.types.GPUVertFormat()
53 self._format_pos.attr_add(
54 id="pos", comp_type='F32', len=3, fetch_mode='FLOAT')
56 self._format_pos_and_color = gpu.types.GPUVertFormat()
57 self._format_pos_and_color.attr_add(
58 id="pos", comp_type='F32', len=3, fetch_mode='FLOAT')
59 self._format_pos_and_color.attr_add(
60 id="color", comp_type='F32', len=4, fetch_mode='FLOAT')
62 self._UBO = None
64 self._batch_point = None
66 def _gl_state_push(self, ob_mat=None):
67 clip_planes = self.rv3d.clip_planes if self.rv3d.use_clip_planes else None
68 config = 'CLIPPED' if clip_planes else 'DEFAULT'
69 self._program_unif_col = gpu.shader.from_builtin(
70 "3D_UNIFORM_COLOR", config=config)
71 self._program_smooth_col = gpu.shader.from_builtin(
72 "3D_SMOOTH_COLOR", config=config)
74 gpu.state.program_point_size_set(False)
75 gpu.state.blend_set('ALPHA')
76 gpu.matrix.push()
77 if ob_mat:
78 gpu.matrix.multiply_matrix(ob_mat)
80 if clip_planes:
81 gpu.state.clip_distances_set(4)
82 if self._UBO is None:
83 import ctypes
85 class _GPUClipPlanes(ctypes.Structure):
86 _pack_ = 16
87 _fields_ = [
88 ("ModelMatrix", (ctypes.c_float * 4) * 4),
89 ("world", (ctypes.c_float * 4) * 6),
92 mat = ob_mat.transposed() if ob_mat else Matrix.Identity(4)
94 UBO_data = _GPUClipPlanes()
95 UBO_data.ModelMatrix[0] = mat[0][:]
96 UBO_data.ModelMatrix[1] = mat[1][:]
97 UBO_data.ModelMatrix[2] = mat[2][:]
98 UBO_data.ModelMatrix[3] = mat[3][:]
100 UBO_data.world[0] = clip_planes[0][:]
101 UBO_data.world[1] = clip_planes[1][:]
102 UBO_data.world[2] = clip_planes[2][:]
103 UBO_data.world[3] = clip_planes[3][:]
105 self._UBO = gpu.types.GPUUniformBuf(UBO_data)
107 self._program_unif_col.bind()
108 self._program_unif_col.uniform_block("clipPlanes", self._UBO)
110 self._program_smooth_col.bind()
111 self._program_smooth_col.uniform_block("clipPlanes", self._UBO)
113 def _gl_state_restore(self):
114 gpu.state.blend_set('NONE')
115 gpu.matrix.pop()
116 if self._UBO:
117 # del self._UBO
118 self._UBO = None
119 gpu.state.clip_distances_set(0)
121 def batch_line_strip_create(self, coords):
122 from gpu.types import (
123 GPUVertBuf,
124 GPUBatch,
127 vbo = GPUVertBuf(self._format_pos, len=len(coords))
128 vbo.attr_fill(0, data=coords)
129 batch_lines = GPUBatch(type="LINE_STRIP", buf=vbo)
130 return batch_lines
132 def batch_lines_smooth_color_create(self, coords, colors):
133 from gpu.types import (
134 GPUVertBuf,
135 GPUBatch,
138 vbo = GPUVertBuf(self._format_pos_and_color, len=len(coords))
139 vbo.attr_fill(0, data=coords)
140 vbo.attr_fill(1, data=colors)
141 batch_lines = GPUBatch(type="LINES", buf=vbo)
142 return batch_lines
144 def batch_triangles_create(self, coords):
145 from gpu.types import (
146 GPUVertBuf,
147 GPUBatch,
150 vbo = GPUVertBuf(self._format_pos, len=len(coords))
151 vbo.attr_fill(0, data=coords)
152 batch_tris = GPUBatch(type="TRIS", buf=vbo)
153 return batch_tris
155 def batch_point_get(self):
156 if self._batch_point is None:
157 from gpu.types import (
158 GPUVertBuf,
159 GPUBatch,
161 vbo = GPUVertBuf(self._format_pos, len=1)
162 vbo.attr_fill(0, ((0.0, 0.0, 0.0),))
163 self._batch_point = GPUBatch(type="POINTS", buf=vbo)
164 return self._batch_point
166 def draw(self, type, location, list_verts_co, vector_constrain, prevloc):
167 import gpu
169 self._gl_state_push()
170 self._program_unif_col.bind()
172 if list_verts_co:
173 # draw 3d line OpenGL in the 3D View
174 winmat = gpu.matrix.get_projection_matrix()
175 winmat[3][2] -= 0.0001
176 gpu.matrix.push_projection()
177 gpu.matrix.load_projection_matrix(winmat)
178 gpu.state.line_width_set(self._line_width)
180 batch = self.batch_line_strip_create(
181 [v.to_tuple() for v in list_verts_co] + [location.to_tuple()])
183 self._program_unif_col.bind()
184 self._program_unif_col.uniform_float("color", (1.0, 0.8, 0.0, 0.5))
186 batch.draw(self._program_unif_col)
187 gpu.matrix.pop_projection()
188 del batch
190 gpu.state.depth_test_set('NONE')
192 point_batch = self.batch_point_get()
193 if vector_constrain:
194 if prevloc:
195 gpu.state.point_size_set(self._point_size)
196 gpu.matrix.translate(prevloc)
198 self._program_unif_col.bind()
199 self._program_unif_col.uniform_float(
200 "color", (1.0, 1.0, 1.0, 0.5))
202 point_batch.draw(self._program_unif_col)
203 gpu.matrix.translate(-prevloc)
205 if vector_constrain[2] == 'X':
206 Color4f = self.axis_x_color
207 elif vector_constrain[2] == 'Y':
208 Color4f = self.axis_y_color
209 elif vector_constrain[2] == 'Z':
210 Color4f = self.axis_z_color
211 else:
212 Color4f = self.constrain_shift_color
213 else:
214 if type == 'OUT':
215 Color4f = self.out_color
216 elif type == 'FACE':
217 Color4f = self.face_color
218 elif type == 'EDGE':
219 Color4f = self.edge_color
220 elif type == 'VERT':
221 Color4f = self.vert_color
222 elif type == 'CENTER':
223 Color4f = self.center_color
224 elif type == 'PERPENDICULAR':
225 Color4f = self.perpendicular_color
226 else: # type == None
227 Color4f = self.out_color
229 gpu.state.point_size_set(2 * self._point_size)
231 gpu.matrix.translate(location)
232 self._program_unif_col.bind()
233 self._program_unif_col.uniform_float("color", Color4f)
234 point_batch.draw(self._program_unif_col)
236 # restore opengl defaults
237 gpu.state.point_size_set(1.0)
238 gpu.state.line_width_set(1.0)
239 gpu.state.depth_test_set('LESS_EQUAL')
241 self._gl_state_restore()
243 def draw_elem(self, snap_obj, bm, elem):
244 # TODO: Cache coords (because antialiasing)
245 import gpu
246 from bmesh.types import (
247 BMVert,
248 BMEdge,
249 BMFace,
252 self._gl_state_push(snap_obj.mat)
253 gpu.state.depth_test_set('NONE')
255 if isinstance(elem, BMVert):
256 if elem.link_edges:
257 import numpy as np
259 color = self.vert_color
260 edges = np.empty((len(elem.link_edges), 2), [
261 ("pos", "f4", 3), ("color", "f4", 4)])
262 edges["pos"][:, 0] = elem.co
263 edges["pos"][:, 1] = [e.other_vert(
264 elem).co for e in elem.link_edges]
265 edges["color"][:, 0] = color
266 edges["color"][:, 1] = (color[0], color[1], color[2], 0.0)
267 edges.shape = -1
269 self._program_smooth_col.bind()
270 gpu.state.line_width_set(self._line_width)
271 batch = self.batch_lines_smooth_color_create(
272 edges["pos"], edges["color"])
273 batch.draw(self._program_smooth_col)
274 gpu.state.line_width_set(1.0)
275 else:
276 if isinstance(elem, BMEdge):
277 self._program_unif_col.bind()
278 self._program_unif_col.uniform_float("color", self.edge_color)
280 gpu.state.line_width_set(self._line_width)
281 batch = self.batch_line_strip_create(
282 [v.co for v in elem.verts])
283 batch.draw(self._program_unif_col)
284 gpu.state.line_width_set(1.0)
286 elif isinstance(elem, BMFace):
287 if len(snap_obj.data) == 2:
288 face_color = self.face_color[0], self.face_color[1], self.face_color[2], self.face_color[3] * 0.2
289 self._program_unif_col.bind()
290 self._program_unif_col.uniform_float("color", face_color)
292 tris = snap_obj.data[1].get_loop_tri_co_by_bmface(bm, elem)
293 tris.shape = (-1, 3)
294 batch = self.batch_triangles_create(tris)
295 batch.draw(self._program_unif_col)
297 # restore opengl defaults
298 gpu.state.depth_test_set('LESS_EQUAL')
300 self._gl_state_restore()