1 # SPDX-License-Identifier: GPL-2.0-or-later
3 from mathutils
import Vector
, Matrix
13 'perpendicular_color',
14 'constrain_shift_color',
22 '_format_pos_and_color',
24 '_program_smooth_col',
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
):
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
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')
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')
78 gpu
.matrix
.multiply_matrix(ob_mat
)
81 gpu
.state
.clip_distances_set(4)
85 class _GPUClipPlanes(ctypes
.Structure
):
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')
119 gpu
.state
.clip_distances_set(0)
121 def batch_line_strip_create(self
, coords
):
122 from gpu
.types
import (
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
)
132 def batch_lines_smooth_color_create(self
, coords
, colors
):
133 from gpu
.types
import (
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
)
144 def batch_triangles_create(self
, coords
):
145 from gpu
.types
import (
150 vbo
= GPUVertBuf(self
._format
_pos
, len=len(coords
))
151 vbo
.attr_fill(0, data
=coords
)
152 batch_tris
= GPUBatch(type="TRIS", buf
=vbo
)
155 def batch_point_get(self
):
156 if self
._batch
_point
is None:
157 from gpu
.types
import (
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
):
169 self
._gl
_state
_push
()
170 self
._program
_unif
_col
.bind()
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()
190 gpu
.state
.depth_test_set('NONE')
192 point_batch
= self
.batch_point_get()
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
212 Color4f
= self
.constrain_shift_color
215 Color4f
= self
.out_color
217 Color4f
= self
.face_color
219 Color4f
= self
.edge_color
221 Color4f
= self
.vert_color
222 elif type == 'CENTER':
223 Color4f
= self
.center_color
224 elif type == 'PERPENDICULAR':
225 Color4f
= self
.perpendicular_color
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)
246 from bmesh
.types
import (
252 self
._gl
_state
_push
(snap_obj
.mat
)
253 gpu
.state
.depth_test_set('NONE')
255 if isinstance(elem
, BMVert
):
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)
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)
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
)
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
()