Blender V5.0
extract_mesh_vbo_paint_overlay_flag.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2025 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#include "extract_mesh.hh"
6
7#include "draw_subdivision.hh"
8
9namespace blender::draw {
10
12{
13 const bool use_face_select = (mr.mesh->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
14 Span<bool> selection;
16 selection = mr.select_poly;
17 }
18 else if (mr.mesh->editflag & ME_EDIT_PAINT_VERT_SEL) {
19 selection = mr.select_vert;
20 }
21 if (selection.is_empty() && mr.hide_poly.is_empty() && (!mr.edit_bmesh || !mr.orig_index_vert)) {
22 flags.fill(0);
23 return;
24 }
25 const OffsetIndices faces = mr.faces;
26 threading::parallel_for(faces.index_range(), 1024, [&](const IndexRange range) {
27 if (selection.is_empty()) {
28 flags.fill(0);
29 }
30 else {
31 if (use_face_select) {
32 for (const int face : range) {
33 flags.slice(faces[face]).fill(selection[face] ? 1 : 0);
34 }
35 }
36 else {
37 const Span<int> corner_verts = mr.corner_verts;
38 for (const int face : range) {
39 for (const int corner : faces[face]) {
40 flags[corner] = selection[corner_verts[corner]] ? 1 : 0;
41 }
42 }
43 }
44 }
45 if (!mr.hide_poly.is_empty()) {
46 const Span<bool> hide_poly = mr.hide_poly;
47 for (const int face : range) {
48 if (hide_poly[face]) {
49 flags.slice(faces[face]).fill(-1);
50 }
51 }
52 }
53 if (mr.edit_bmesh && mr.orig_index_vert) {
54 const Span<int> corner_verts = mr.corner_verts;
55 const Span<int> orig_indices(mr.orig_index_vert, mr.verts_num);
56 for (const int face : range) {
57 for (const int corner : faces[face]) {
58 if (orig_indices[corner_verts[corner]] == ORIGINDEX_NONE) {
59 flags[corner] = -1;
60 }
61 }
62 }
63 }
64 });
65}
66
68{
69 /* TODO: Return early if there are no hidden faces. */
70 const BMesh &bm = *mr.bm;
71 threading::parallel_for(IndexRange(bm.totface), 2048, [&](const IndexRange range) {
72 for (const int face_index : range) {
73 const BMFace &face = *BM_face_at_index(&const_cast<BMesh &>(bm), face_index);
74 if (BM_elem_flag_test(&face, BM_ELEM_HIDDEN)) {
75 const IndexRange face_range(BM_elem_index_get(BM_FACE_FIRST_LOOP(&face)), face.len);
76 flags.slice(face_range).fill(-1);
77 }
78 }
79 });
80}
81
83{
84 static const GPUVertFormat format = GPU_vertformat_from_attribute("paint_overlay_flag",
85 gpu::VertAttrType::SINT_32);
86 return format;
87}
88
90{
91 const int size = mr.corners_num + mr.loose_indices_num;
95 MutableSpan vbo_data = vbo->data<int>();
96 MutableSpan corners_data = vbo_data.take_front(mr.corners_num);
97 MutableSpan loose_data = vbo_data.take_back(mr.loose_indices_num);
98
100 extract_paint_overlay_flags(mr, corners_data);
101 }
102 else {
103 extract_edit_flags_bm(mr, corners_data);
104 }
105
106 loose_data.fill(0);
107 return vbo;
108}
109
110static void update_loose_flags(const MeshRenderData &mr,
111 const DRWSubdivCache &subdiv_cache,
112 gpu::VertBuf &flags)
113{
114 const int vbo_size = subdiv_full_vbo_size(mr, subdiv_cache);
115 const int loose_geom_start = subdiv_cache.num_subdiv_loops;
116
117 /* Push VBO content to the GPU and bind the VBO so that #GPU_vertbuf_update_sub can work. */
118 GPU_vertbuf_use(&flags);
119
120 /* Default to zeroed attribute. The overlay shader should expect this and render engines should
121 * never draw loose geometry. */
122 const int default_value = 0;
123 for (const int i : IndexRange::from_begin_end(loose_geom_start, vbo_size)) {
124 /* TODO(fclem): This has HORRENDOUS performance. Prefer clearing the buffer on device with
125 * something like glClearBufferSubData. */
126 GPU_vertbuf_update_sub(&flags, i * sizeof(int), sizeof(int), &default_value);
127 }
128}
129
131 const DRWSubdivCache &subdiv_cache)
132{
135
137
138 update_loose_flags(mr, subdiv_cache, *flags);
139 return flags;
140}
141
142} // namespace blender::draw
@ ME_EDIT_PAINT_VERT_SEL
@ ME_EDIT_PAINT_FACE_SEL
blender::gpu::VertBuf * GPU_vertbuf_create_on_device(const GPUVertFormat &format, uint v_len)
void GPU_vertbuf_use(blender::gpu::VertBuf *)
static blender::gpu::VertBuf * GPU_vertbuf_create_with_format(const GPUVertFormat &format)
void GPU_vertbuf_data_alloc(blender::gpu::VertBuf &verts, uint v_len)
void GPU_vertbuf_update_sub(blender::gpu::VertBuf *verts, uint start, uint len, const void *data)
GPUVertFormat GPU_vertformat_from_attribute(blender::StringRef name, blender::gpu::VertAttrType type)
BMesh * bm
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
constexpr bool is_empty() const
Definition BLI_span.hh:260
static constexpr IndexRange from_begin_end(const int64_t begin, const int64_t end)
constexpr MutableSpan take_back(const int64_t n) const
Definition BLI_span.hh:640
constexpr T * data() const
Definition BLI_span.hh:539
constexpr void fill(const T &value) const
Definition BLI_span.hh:517
constexpr MutableSpan take_front(const int64_t n) const
Definition BLI_span.hh:629
constexpr bool is_empty() const
Definition BLI_span.hh:260
Extraction of Mesh data into VBO to feed to GPU.
format
static char faces[256]
static const GPUVertFormat & get_paint_overlay_flag_format()
void draw_subdiv_build_paint_overlay_flag_buffer(const DRWSubdivCache &cache, gpu::VertBuf &flags)
int subdiv_full_vbo_size(const MeshRenderData &mr, const DRWSubdivCache &cache)
static void extract_edit_flags_bm(const MeshRenderData &mr, MutableSpan< int > flags)
gpu::VertBufPtr extract_paint_overlay_flags_subdiv(const MeshRenderData &mr, const DRWSubdivCache &subdiv_cache)
gpu::VertBufPtr extract_paint_overlay_flags(const MeshRenderData &mr)
static void update_loose_flags(const MeshRenderData &mr, const DRWSubdivCache &subdiv_cache, gpu::VertBuf &flags)
std::unique_ptr< gpu::VertBuf, gpu::VertBufDeleter > VertBufPtr
void parallel_for(const IndexRange range, const int64_t grain_size, const Function &function, const TaskSizeHints &size_hints=detail::TaskSizeHints_Static(1))
Definition BLI_task.hh:93
char editflag
VArraySpan< bool > select_vert
VArraySpan< bool > select_poly
OffsetIndices< int > faces
i
Definition text_draw.cc:230