1 # SPDX-FileCopyrightText: 2019-2023 Blender Foundation
3 # SPDX-License-Identifier: GPL-2.0-or-later
6 from mathutils
import Vector
, Matrix
16 'perpendicular_color',
17 'constrain_shift_color',
25 '_format_pos_and_color',
27 '_program_smooth_col',
31 def __init__(self
, out_color
, face_color
,
32 edge_color
, vert_color
, center_color
,
33 perpendicular_color
, constrain_shift_color
,
34 axis_x_color
, axis_y_color
, axis_z_color
, rv3d
, ui_scale
):
38 self
.out_color
= out_color
39 self
.face_color
= face_color
40 self
.edge_color
= edge_color
41 self
.vert_color
= vert_color
42 self
.center_color
= center_color
43 self
.perpendicular_color
= perpendicular_color
44 self
.constrain_shift_color
= constrain_shift_color
46 self
.axis_x_color
= axis_x_color
47 self
.axis_y_color
= axis_y_color
48 self
.axis_z_color
= axis_z_color
52 self
._point
_size
= 5 * ui_scale
53 self
._line
_width
= 3 * ui_scale
55 self
._format
_pos
= gpu
.types
.GPUVertFormat()
56 self
._format
_pos
.attr_add(
57 id="pos", comp_type
='F32', len=3, fetch_mode
='FLOAT')
59 self
._format
_pos
_and
_color
= gpu
.types
.GPUVertFormat()
60 self
._format
_pos
_and
_color
.attr_add(
61 id="pos", comp_type
='F32', len=3, fetch_mode
='FLOAT')
62 self
._format
_pos
_and
_color
.attr_add(
63 id="color", comp_type
='F32', len=4, fetch_mode
='FLOAT')
67 self
._batch
_point
= None
69 def _gl_state_push(self
, ob_mat
=None):
70 clip_planes
= self
.rv3d
.clip_planes
if self
.rv3d
.use_clip_planes
else None
71 config
= 'CLIPPED' if clip_planes
else 'DEFAULT'
72 self
._program
_unif
_col
= gpu
.shader
.from_builtin(
73 "UNIFORM_COLOR", config
=config
)
74 self
._program
_smooth
_col
= gpu
.shader
.from_builtin(
75 "SMOOTH_COLOR", config
=config
)
77 gpu
.state
.program_point_size_set(False)
78 gpu
.state
.blend_set('ALPHA')
81 gpu
.matrix
.multiply_matrix(ob_mat
)
84 gpu
.state
.clip_distances_set(4)
88 class _GPUClipPlanes(ctypes
.Structure
):
91 ("ModelMatrix", (ctypes
.c_float
* 4) * 4),
92 ("world", (ctypes
.c_float
* 4) * 6),
95 mat
= ob_mat
.transposed() if ob_mat
else Matrix
.Identity(4)
97 UBO_data
= _GPUClipPlanes()
98 UBO_data
.ModelMatrix
[0] = mat
[0][:]
99 UBO_data
.ModelMatrix
[1] = mat
[1][:]
100 UBO_data
.ModelMatrix
[2] = mat
[2][:]
101 UBO_data
.ModelMatrix
[3] = mat
[3][:]
103 UBO_data
.world
[0] = clip_planes
[0][:]
104 UBO_data
.world
[1] = clip_planes
[1][:]
105 UBO_data
.world
[2] = clip_planes
[2][:]
106 UBO_data
.world
[3] = clip_planes
[3][:]
108 self
._UBO
= gpu
.types
.GPUUniformBuf(UBO_data
)
110 self
._program
_unif
_col
.bind()
111 self
._program
_unif
_col
.uniform_block("clipPlanes", self
._UBO
)
113 self
._program
_smooth
_col
.bind()
114 self
._program
_smooth
_col
.uniform_block("clipPlanes", self
._UBO
)
116 def _gl_state_restore(self
):
117 gpu
.state
.blend_set('NONE')
122 gpu
.state
.clip_distances_set(0)
124 def batch_line_strip_create(self
, coords
):
125 from gpu
.types
import (
130 vbo
= GPUVertBuf(self
._format
_pos
, len=len(coords
))
131 vbo
.attr_fill(0, data
=coords
)
132 batch_lines
= GPUBatch(type="LINE_STRIP", buf
=vbo
)
135 def batch_lines_smooth_color_create(self
, coords
, colors
):
136 from gpu
.types
import (
141 vbo
= GPUVertBuf(self
._format
_pos
_and
_color
, len=len(coords
))
142 vbo
.attr_fill(0, data
=coords
)
143 vbo
.attr_fill(1, data
=colors
)
144 batch_lines
= GPUBatch(type="LINES", buf
=vbo
)
147 def batch_triangles_create(self
, coords
):
148 from gpu
.types
import (
153 vbo
= GPUVertBuf(self
._format
_pos
, len=len(coords
))
154 vbo
.attr_fill(0, data
=coords
)
155 batch_tris
= GPUBatch(type="TRIS", buf
=vbo
)
158 def batch_point_get(self
):
159 if self
._batch
_point
is None:
160 from gpu
.types
import (
164 vbo
= GPUVertBuf(self
._format
_pos
, len=1)
165 vbo
.attr_fill(0, ((0.0, 0.0, 0.0),))
166 self
._batch
_point
= GPUBatch(type="POINTS", buf
=vbo
)
167 return self
._batch
_point
169 def draw(self
, type, location
, list_verts_co
, vector_constrain
, prevloc
):
172 self
._gl
_state
_push
()
173 self
._program
_unif
_col
.bind()
176 # draw 3d line OpenGL in the 3D View
177 winmat
= gpu
.matrix
.get_projection_matrix()
178 winmat
[3][2] -= 0.0001
179 gpu
.matrix
.push_projection()
180 gpu
.matrix
.load_projection_matrix(winmat
)
181 gpu
.state
.line_width_set(self
._line
_width
)
183 batch
= self
.batch_line_strip_create(
184 [v
.to_tuple() for v
in list_verts_co
] + [location
.to_tuple()])
186 self
._program
_unif
_col
.bind()
187 self
._program
_unif
_col
.uniform_float("color", (1.0, 0.8, 0.0, 0.5))
189 batch
.draw(self
._program
_unif
_col
)
190 gpu
.matrix
.pop_projection()
193 gpu
.state
.depth_test_set('NONE')
195 point_batch
= self
.batch_point_get()
198 gpu
.state
.point_size_set(self
._point
_size
)
199 gpu
.matrix
.translate(prevloc
)
201 self
._program
_unif
_col
.bind()
202 self
._program
_unif
_col
.uniform_float(
203 "color", (1.0, 1.0, 1.0, 0.5))
205 point_batch
.draw(self
._program
_unif
_col
)
206 gpu
.matrix
.translate(-prevloc
)
208 if vector_constrain
[2] == 'X':
209 Color4f
= self
.axis_x_color
210 elif vector_constrain
[2] == 'Y':
211 Color4f
= self
.axis_y_color
212 elif vector_constrain
[2] == 'Z':
213 Color4f
= self
.axis_z_color
215 Color4f
= self
.constrain_shift_color
218 Color4f
= self
.out_color
220 Color4f
= self
.face_color
222 Color4f
= self
.edge_color
224 Color4f
= self
.vert_color
225 elif type == 'CENTER':
226 Color4f
= self
.center_color
227 elif type == 'PERPENDICULAR':
228 Color4f
= self
.perpendicular_color
230 Color4f
= self
.out_color
232 gpu
.state
.point_size_set(2 * self
._point
_size
)
234 gpu
.matrix
.translate(location
)
235 self
._program
_unif
_col
.bind()
236 self
._program
_unif
_col
.uniform_float("color", Color4f
)
237 point_batch
.draw(self
._program
_unif
_col
)
239 # restore opengl defaults
240 gpu
.state
.point_size_set(1.0)
241 gpu
.state
.line_width_set(1.0)
242 gpu
.state
.depth_test_set('LESS_EQUAL')
244 self
._gl
_state
_restore
()
246 def draw_elem(self
, snap_obj
, bm
, elem
):
247 # TODO: Cache coords (because antialiasing)
249 from bmesh
.types
import (
255 self
._gl
_state
_push
(snap_obj
.mat
)
256 gpu
.state
.depth_test_set('NONE')
258 if isinstance(elem
, BMVert
):
262 color
= self
.vert_color
263 edges
= np
.empty((len(elem
.link_edges
), 2), [
264 ("pos", "f4", 3), ("color", "f4", 4)])
265 edges
["pos"][:, 0] = elem
.co
266 edges
["pos"][:, 1] = [e
.other_vert(
267 elem
).co
for e
in elem
.link_edges
]
268 edges
["color"][:, 0] = color
269 edges
["color"][:, 1] = (color
[0], color
[1], color
[2], 0.0)
272 self
._program
_smooth
_col
.bind()
273 gpu
.state
.line_width_set(self
._line
_width
)
274 batch
= self
.batch_lines_smooth_color_create(
275 edges
["pos"], edges
["color"])
276 batch
.draw(self
._program
_smooth
_col
)
277 gpu
.state
.line_width_set(1.0)
279 if isinstance(elem
, BMEdge
):
280 self
._program
_unif
_col
.bind()
281 self
._program
_unif
_col
.uniform_float("color", self
.edge_color
)
283 gpu
.state
.line_width_set(self
._line
_width
)
284 batch
= self
.batch_line_strip_create(
285 [v
.co
for v
in elem
.verts
])
286 batch
.draw(self
._program
_unif
_col
)
287 gpu
.state
.line_width_set(1.0)
289 elif isinstance(elem
, BMFace
):
290 if len(snap_obj
.data
) == 2:
291 face_color
= self
.face_color
[0], self
.face_color
[1], self
.face_color
[2], self
.face_color
[3] * 0.2
292 self
._program
_unif
_col
.bind()
293 self
._program
_unif
_col
.uniform_float("color", face_color
)
295 tris
= snap_obj
.data
[1].get_loop_tri_co_by_bmface(bm
, elem
)
297 batch
= self
.batch_triangles_create(tris
)
298 batch
.draw(self
._program
_unif
_col
)
300 # restore opengl defaults
301 gpu
.state
.depth_test_set('LESS_EQUAL')
303 self
._gl
_state
_restore
()