|
|
|
@ -6,6 +6,8 @@
|
|
|
|
|
* \ingroup draw
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include "BLI_array_utils.hh"
|
|
|
|
|
|
|
|
|
|
#include "GPU_index_buffer.hh"
|
|
|
|
|
|
|
|
|
|
#include "extract_mesh.hh"
|
|
|
|
@ -15,15 +17,11 @@
|
|
|
|
|
|
|
|
|
|
namespace blender::draw {
|
|
|
|
|
|
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
|
/** \name Extract Edges Indices
|
|
|
|
|
* \{ */
|
|
|
|
|
|
|
|
|
|
static IndexMask calc_edge_visibility(const MeshRenderData &mr,
|
|
|
|
|
const IndexMask &start_mask,
|
|
|
|
|
IndexMaskMemory &memory)
|
|
|
|
|
static IndexMask calc_mesh_edge_visibility(const MeshRenderData &mr,
|
|
|
|
|
const IndexMask &mask,
|
|
|
|
|
IndexMaskMemory &memory)
|
|
|
|
|
{
|
|
|
|
|
IndexMask visible = start_mask;
|
|
|
|
|
IndexMask visible = mask;
|
|
|
|
|
if (!mr.mesh->runtime->subsurf_optimal_display_edges.is_empty()) {
|
|
|
|
|
const BoundedBitSpan visible_bits = mr.mesh->runtime->subsurf_optimal_display_edges;
|
|
|
|
|
visible = IndexMask::from_bits(visible, visible_bits, memory);
|
|
|
|
@ -40,15 +38,6 @@ static IndexMask calc_edge_visibility(const MeshRenderData &mr,
|
|
|
|
|
return visible;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static IndexMask calc_loose_edge_visibility(const MeshRenderData &mr, IndexMaskMemory &memory)
|
|
|
|
|
{
|
|
|
|
|
return calc_edge_visibility(mr, IndexMask::from_indices(mr.loose_edges, memory), memory);
|
|
|
|
|
}
|
|
|
|
|
static IndexMask calc_edge_visibility(const MeshRenderData &mr, IndexMaskMemory &memory)
|
|
|
|
|
{
|
|
|
|
|
return calc_edge_visibility(mr, IndexMask(mr.edges_num), memory);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* In the GPU vertex buffers, the value for each vertex is duplicated to each of its vertex
|
|
|
|
|
* corners. So the edges on the GPU connect face corners rather than vertices. */
|
|
|
|
|
static uint2 edge_from_corners(const IndexRange face, const int corner)
|
|
|
|
@ -57,57 +46,53 @@ static uint2 edge_from_corners(const IndexRange face, const int corner)
|
|
|
|
|
return uint2(corner, corner_next);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void fill_loose_lines_ibo(const int corners_num, MutableSpan<uint2> data)
|
|
|
|
|
static void fill_loose_lines_ibo(const uint corners_num, MutableSpan<uint2> data)
|
|
|
|
|
{
|
|
|
|
|
threading::memory_bandwidth_bound_task(data.size_in_bytes(), [&]() {
|
|
|
|
|
threading::parallel_for(data.index_range(), 4096, [&](const IndexRange range) {
|
|
|
|
|
for (const int loose_edge : range) {
|
|
|
|
|
const int index = corners_num + loose_edge * 2;
|
|
|
|
|
data[loose_edge] = uint2(index, index + 1);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
array_utils::fill_index_range(data.cast<uint>(), corners_num);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void extract_lines_mesh(const MeshRenderData &mr, gpu::IndexBuf *lines, gpu::IndexBuf *lines_loose)
|
|
|
|
|
static void extract_lines_mesh(const MeshRenderData &mr,
|
|
|
|
|
gpu::IndexBuf *lines,
|
|
|
|
|
gpu::IndexBuf *lines_loose)
|
|
|
|
|
{
|
|
|
|
|
IndexMaskMemory memory;
|
|
|
|
|
const IndexMask all_loose_edges = IndexMask::from_indices(mr.loose_edges, memory);
|
|
|
|
|
const IndexMask visible_loose_edges = calc_mesh_edge_visibility(mr, all_loose_edges, memory);
|
|
|
|
|
const int max_index = mr.corners_num + visible_loose_edges.size() * 2;
|
|
|
|
|
|
|
|
|
|
if (DRW_ibo_requested(lines_loose) && !DRW_ibo_requested(lines)) {
|
|
|
|
|
IndexMaskMemory memory;
|
|
|
|
|
const IndexMask visible = calc_loose_edge_visibility(mr, memory);
|
|
|
|
|
|
|
|
|
|
GPUIndexBufBuilder builder;
|
|
|
|
|
GPU_indexbuf_init(
|
|
|
|
|
&builder, GPU_PRIM_LINES, visible.size(), mr.corners_num + mr.loose_indices_num);
|
|
|
|
|
GPU_indexbuf_init(&builder, GPU_PRIM_LINES, visible_loose_edges.size(), max_index);
|
|
|
|
|
MutableSpan<uint2> data = GPU_indexbuf_get_data(&builder).cast<uint2>();
|
|
|
|
|
BLI_assert(data.size() == visible.size());
|
|
|
|
|
|
|
|
|
|
fill_loose_lines_ibo(mr.corners_num, data);
|
|
|
|
|
|
|
|
|
|
GPU_indexbuf_build_in_place_ex(
|
|
|
|
|
&builder, 0, mr.corners_num + visible.size() * 2, false, lines_loose);
|
|
|
|
|
GPU_indexbuf_build_in_place_ex(&builder, 0, max_index, false, lines_loose);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
IndexMaskMemory memory;
|
|
|
|
|
const IndexMask visible = calc_edge_visibility(mr, memory);
|
|
|
|
|
|
|
|
|
|
// TODO: Also add loose edges here.
|
|
|
|
|
const IndexMask non_loose_edges = all_loose_edges.complement(mr.edges.index_range(), memory);
|
|
|
|
|
const IndexMask visible_non_loose_edges = calc_mesh_edge_visibility(mr, non_loose_edges, memory);
|
|
|
|
|
|
|
|
|
|
GPUIndexBufBuilder builder;
|
|
|
|
|
GPU_indexbuf_init(&builder, GPU_PRIM_LINES, visible.size(), mr.corners_num);
|
|
|
|
|
GPU_indexbuf_init(&builder,
|
|
|
|
|
GPU_PRIM_LINES,
|
|
|
|
|
visible_non_loose_edges.size() + visible_loose_edges.size(),
|
|
|
|
|
max_index);
|
|
|
|
|
MutableSpan<uint2> data = GPU_indexbuf_get_data(&builder).cast<uint2>();
|
|
|
|
|
|
|
|
|
|
const OffsetIndices faces = mr.faces;
|
|
|
|
|
const Span<int> corner_edges = mr.corner_edges;
|
|
|
|
|
if (visible.size() == mr.edges_num) {
|
|
|
|
|
/* Use separate boolean array to avoid writing to the same indices again multiple times,
|
|
|
|
|
* possibly from different threads. This is slightly beneficial because booleans are 8 times
|
|
|
|
|
* smaller than the `uint2` for each edge. */
|
|
|
|
|
if (visible_non_loose_edges.size() == mr.edges_num) {
|
|
|
|
|
/* All edges in the mesh are visible. The edges in the GPU buffer will have the same order as
|
|
|
|
|
* the mesh's edges, so any remapping is unnecessary. Use a boolean array to avoid writing to
|
|
|
|
|
* the same indices again multiple times from different threads. This is slightly beneficial
|
|
|
|
|
* because booleans are 8 times smaller than the `uint2` for each edge. */
|
|
|
|
|
Array<bool> used(mr.edges_num, false);
|
|
|
|
|
threading::memory_bandwidth_bound_task(
|
|
|
|
|
used.as_span().size_in_bytes() + data.size_in_bytes() + corner_edges.size_in_bytes(),
|
|
|
|
|
[&]() {
|
|
|
|
|
threading::parallel_for(faces.index_range(), 1024, [&](const IndexRange range) {
|
|
|
|
|
threading::parallel_for(faces.index_range(), 2048, [&](const IndexRange range) {
|
|
|
|
|
for (const int face_index : range) {
|
|
|
|
|
const IndexRange face = faces[face_index];
|
|
|
|
|
for (const int corner : face) {
|
|
|
|
@ -127,8 +112,8 @@ void extract_lines_mesh(const MeshRenderData &mr, gpu::IndexBuf *lines, gpu::Ind
|
|
|
|
|
threading::memory_bandwidth_bound_task(
|
|
|
|
|
map.as_span().size_in_bytes() + data.size_in_bytes() + corner_edges.size_in_bytes(),
|
|
|
|
|
[&]() {
|
|
|
|
|
index_mask::build_reverse_map(visible, map.as_mutable_span());
|
|
|
|
|
threading::parallel_for(faces.index_range(), 1024, [&](const IndexRange range) {
|
|
|
|
|
index_mask::build_reverse_map(visible_non_loose_edges, map.as_mutable_span());
|
|
|
|
|
threading::parallel_for(faces.index_range(), 2048, [&](const IndexRange range) {
|
|
|
|
|
for (const int face_index : range) {
|
|
|
|
|
const IndexRange face = faces[face_index];
|
|
|
|
|
for (const int corner : face) {
|
|
|
|
@ -144,122 +129,70 @@ void extract_lines_mesh(const MeshRenderData &mr, gpu::IndexBuf *lines, gpu::Ind
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GPU_indexbuf_build_in_place_ex(&builder, 0, mr.corners_num + visible.size() * 2, false, lines);
|
|
|
|
|
return;
|
|
|
|
|
fill_loose_lines_ibo(mr.corners_num, data.take_back(visible_loose_edges.size()));
|
|
|
|
|
|
|
|
|
|
GPU_indexbuf_build_in_place_ex(&builder, 0, max_index, false, lines);
|
|
|
|
|
if (DRW_ibo_requested(lines_loose)) {
|
|
|
|
|
GPU_indexbuf_create_subrange_in_place(
|
|
|
|
|
lines_loose, lines, visible_non_loose_edges.size() * 2, visible_loose_edges.size() * 2);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct MeshExtract_LinesData {
|
|
|
|
|
GPUIndexBufBuilder elb;
|
|
|
|
|
BitSpan optimal_display_edges;
|
|
|
|
|
const int *e_origindex;
|
|
|
|
|
Span<bool> hide_edge;
|
|
|
|
|
bool test_visibility;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
BLI_INLINE bool is_edge_visible(const MeshExtract_LinesData *data, const int edge)
|
|
|
|
|
static IndexMask calc_bm_edge_visibility(BMesh &bm, const IndexMask &mask, IndexMaskMemory &memory)
|
|
|
|
|
{
|
|
|
|
|
if (!data->hide_edge.is_empty() && data->hide_edge[edge]) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (data->e_origindex && data->e_origindex[edge] == ORIGINDEX_NONE) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (!data->optimal_display_edges.is_empty() && !data->optimal_display_edges[edge]) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
return IndexMask::from_predicate(mask, GrainSize(2048), memory, [&](const int i) {
|
|
|
|
|
return !BM_elem_flag_test_bool(BM_edge_at_index(&bm, i), BM_ELEM_HIDDEN);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void extract_lines_init(const MeshRenderData &mr,
|
|
|
|
|
MeshBatchCache & /*cache*/,
|
|
|
|
|
void * /*buf*/,
|
|
|
|
|
void *tls_data)
|
|
|
|
|
static void extract_lines_bm(const MeshRenderData &mr,
|
|
|
|
|
gpu::IndexBuf *lines,
|
|
|
|
|
gpu::IndexBuf *lines_loose)
|
|
|
|
|
{
|
|
|
|
|
MeshExtract_LinesData *data = static_cast<MeshExtract_LinesData *>(tls_data);
|
|
|
|
|
/* Put loose edges at the end. */
|
|
|
|
|
GPU_indexbuf_init(&data->elb,
|
|
|
|
|
BMesh &bm = *mr.bm;
|
|
|
|
|
|
|
|
|
|
IndexMaskMemory memory;
|
|
|
|
|
const IndexMask all_loose_edges = IndexMask::from_indices(mr.loose_edges, memory);
|
|
|
|
|
const IndexMask visible_loose_edges = calc_bm_edge_visibility(bm, all_loose_edges, memory);
|
|
|
|
|
const int max_index = mr.corners_num + visible_loose_edges.size() * 2;
|
|
|
|
|
|
|
|
|
|
const IndexMask non_loose_edges = all_loose_edges.complement(IndexRange(bm.totvert), memory);
|
|
|
|
|
const IndexMask visible_non_loose_edges = calc_bm_edge_visibility(bm, non_loose_edges, memory);
|
|
|
|
|
|
|
|
|
|
GPUIndexBufBuilder builder;
|
|
|
|
|
GPU_indexbuf_init(&builder,
|
|
|
|
|
GPU_PRIM_LINES,
|
|
|
|
|
mr.edges_num + mr.loose_edges_num,
|
|
|
|
|
mr.corners_num + mr.loose_indices_num);
|
|
|
|
|
visible_non_loose_edges.size() + visible_loose_edges.size(),
|
|
|
|
|
max_index);
|
|
|
|
|
MutableSpan<uint2> data = GPU_indexbuf_get_data(&builder).cast<uint2>();
|
|
|
|
|
|
|
|
|
|
if (mr.extract_type == MR_EXTRACT_MESH) {
|
|
|
|
|
data->optimal_display_edges = mr.mesh->runtime->subsurf_optimal_display_edges;
|
|
|
|
|
data->e_origindex = mr.hide_unmapped_edges ? mr.e_origindex : nullptr;
|
|
|
|
|
data->hide_edge = mr.use_hide ? Span(mr.hide_edge) : Span<bool>();
|
|
|
|
|
visible_non_loose_edges.foreach_index(GrainSize(4096), [&](const int i, const int pos) {
|
|
|
|
|
const BMEdge &edge = *BM_edge_at_index(&bm, i);
|
|
|
|
|
data[pos] = uint2(BM_elem_index_get(edge.l), BM_elem_index_get(edge.l->next));
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
data->test_visibility = !data->optimal_display_edges.is_empty() || data->e_origindex ||
|
|
|
|
|
!data->hide_edge.is_empty();
|
|
|
|
|
fill_loose_lines_ibo(mr.corners_num, data.take_back(visible_loose_edges.size()));
|
|
|
|
|
|
|
|
|
|
GPU_indexbuf_build_in_place_ex(&builder, 0, max_index, false, lines);
|
|
|
|
|
if (DRW_ibo_requested(lines_loose)) {
|
|
|
|
|
GPU_indexbuf_create_subrange_in_place(
|
|
|
|
|
lines_loose, lines, visible_non_loose_edges.size() * 2, visible_loose_edges.size() * 2);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void extract_lines_iter_face_bm(const MeshRenderData & /*mr*/,
|
|
|
|
|
const BMFace *f,
|
|
|
|
|
const int /*f_index*/,
|
|
|
|
|
void *tls_data)
|
|
|
|
|
void extract_lines(const MeshRenderData &mr, gpu::IndexBuf *lines, gpu::IndexBuf *lines_loose)
|
|
|
|
|
{
|
|
|
|
|
MeshExtract_LinesData *data = static_cast<MeshExtract_LinesData *>(tls_data);
|
|
|
|
|
GPUIndexBufBuilder *elb = &data->elb;
|
|
|
|
|
BMLoop *l_iter, *l_first;
|
|
|
|
|
/* Use #BMLoop.prev to match mesh order (to avoid minor differences in data extraction). */
|
|
|
|
|
l_iter = l_first = BM_FACE_FIRST_LOOP(f)->prev;
|
|
|
|
|
do {
|
|
|
|
|
if (!BM_elem_flag_test(l_iter->e, BM_ELEM_HIDDEN)) {
|
|
|
|
|
GPU_indexbuf_set_line_verts(elb,
|
|
|
|
|
BM_elem_index_get(l_iter->e),
|
|
|
|
|
BM_elem_index_get(l_iter),
|
|
|
|
|
BM_elem_index_get(l_iter->next));
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
GPU_indexbuf_set_line_restart(elb, BM_elem_index_get(l_iter->e));
|
|
|
|
|
}
|
|
|
|
|
} while ((l_iter = l_iter->next) != l_first);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void extract_lines_iter_loose_edge_bm(const MeshRenderData &mr,
|
|
|
|
|
const BMEdge *eed,
|
|
|
|
|
const int loose_edge_i,
|
|
|
|
|
void *tls_data)
|
|
|
|
|
{
|
|
|
|
|
MeshExtract_LinesData *data = static_cast<MeshExtract_LinesData *>(tls_data);
|
|
|
|
|
GPUIndexBufBuilder *elb = &data->elb;
|
|
|
|
|
const int l_index_offset = mr.edges_num + loose_edge_i;
|
|
|
|
|
if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
|
|
|
|
|
const int l_index = mr.corners_num + loose_edge_i * 2;
|
|
|
|
|
GPU_indexbuf_set_line_verts(elb, l_index_offset, l_index, l_index + 1);
|
|
|
|
|
if (mr.extract_type == MR_EXTRACT_MESH) {
|
|
|
|
|
extract_lines_mesh(mr, lines, lines_loose);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
GPU_indexbuf_set_line_restart(elb, l_index_offset);
|
|
|
|
|
extract_lines_bm(mr, lines, lines_loose);
|
|
|
|
|
}
|
|
|
|
|
/* Don't render the edge twice. */
|
|
|
|
|
GPU_indexbuf_set_line_restart(elb, BM_elem_index_get(eed));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void extract_lines_task_reduce(void *_userdata_to, void *_userdata_from)
|
|
|
|
|
{
|
|
|
|
|
GPUIndexBufBuilder *elb_to = static_cast<GPUIndexBufBuilder *>(_userdata_to);
|
|
|
|
|
GPUIndexBufBuilder *elb_from = static_cast<GPUIndexBufBuilder *>(_userdata_from);
|
|
|
|
|
GPU_indexbuf_join(elb_to, elb_from);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void extract_lines_finish(const MeshRenderData & /*mr*/,
|
|
|
|
|
MeshBatchCache & /*cache*/,
|
|
|
|
|
void *buf,
|
|
|
|
|
void *tls_data)
|
|
|
|
|
{
|
|
|
|
|
MeshExtract_LinesData *data = static_cast<MeshExtract_LinesData *>(tls_data);
|
|
|
|
|
GPUIndexBufBuilder *elb = &data->elb;
|
|
|
|
|
gpu::IndexBuf *ibo = static_cast<gpu::IndexBuf *>(buf);
|
|
|
|
|
GPU_indexbuf_build_in_place(elb, ibo);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void extract_lines_init_subdiv(const DRWSubdivCache &subdiv_cache,
|
|
|
|
|
const MeshRenderData & /*mr*/,
|
|
|
|
|
MeshBatchCache & /*cache*/,
|
|
|
|
|
void *buffer,
|
|
|
|
|
void * /*data*/)
|
|
|
|
|
static void generate_subdiv_lines(const DRWSubdivCache &subdiv_cache, gpu::IndexBuf *ibo)
|
|
|
|
|
{
|
|
|
|
|
const DRWSubdivLooseGeom &loose_geom = subdiv_cache.loose_geom;
|
|
|
|
|
gpu::IndexBuf *ibo = static_cast<gpu::IndexBuf *>(buffer);
|
|
|
|
|
GPU_indexbuf_init_build_on_device(ibo,
|
|
|
|
|
subdiv_cache.num_subdiv_loops * 2 + loose_geom.edge_len * 2);
|
|
|
|
|
|
|
|
|
@ -272,8 +205,7 @@ static void extract_lines_init_subdiv(const DRWSubdivCache &subdiv_cache,
|
|
|
|
|
|
|
|
|
|
static void extract_lines_loose_geom_subdiv(const DRWSubdivCache &subdiv_cache,
|
|
|
|
|
const MeshRenderData &mr,
|
|
|
|
|
void *buffer,
|
|
|
|
|
void * /*data*/)
|
|
|
|
|
gpu::IndexBuf *ibo)
|
|
|
|
|
{
|
|
|
|
|
const DRWSubdivLooseGeom &loose_geom = subdiv_cache.loose_geom;
|
|
|
|
|
if (loose_geom.edge_len == 0) {
|
|
|
|
@ -346,131 +278,31 @@ static void extract_lines_loose_geom_subdiv(const DRWSubdivCache &subdiv_cache,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gpu::IndexBuf *ibo = static_cast<gpu::IndexBuf *>(buffer);
|
|
|
|
|
draw_subdiv_build_lines_loose_buffer(subdiv_cache, ibo, flags, uint(loose_geom.edge_len));
|
|
|
|
|
|
|
|
|
|
GPU_vertbuf_discard(flags);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
constexpr MeshExtract create_extractor_lines()
|
|
|
|
|
void extract_lines_subdiv(const DRWSubdivCache &subdiv_cache,
|
|
|
|
|
const MeshRenderData &mr,
|
|
|
|
|
gpu::IndexBuf *lines,
|
|
|
|
|
gpu::IndexBuf *lines_loose)
|
|
|
|
|
{
|
|
|
|
|
MeshExtract extractor = {nullptr};
|
|
|
|
|
extractor.init = extract_lines_init;
|
|
|
|
|
extractor.iter_face_bm = extract_lines_iter_face_bm;
|
|
|
|
|
extractor.iter_loose_edge_bm = extract_lines_iter_loose_edge_bm;
|
|
|
|
|
extractor.init_subdiv = extract_lines_init_subdiv;
|
|
|
|
|
extractor.iter_loose_geom_subdiv = extract_lines_loose_geom_subdiv;
|
|
|
|
|
extractor.task_reduce = extract_lines_task_reduce;
|
|
|
|
|
extractor.finish = extract_lines_finish;
|
|
|
|
|
extractor.data_type = MR_DATA_NONE;
|
|
|
|
|
extractor.data_size = sizeof(MeshExtract_LinesData);
|
|
|
|
|
extractor.use_threading = true;
|
|
|
|
|
extractor.mesh_buffer_offset = offsetof(MeshBufferList, ibo.lines);
|
|
|
|
|
return extractor;
|
|
|
|
|
if (DRW_ibo_requested(lines_loose) && !DRW_ibo_requested(lines)) {
|
|
|
|
|
// TODO: Fix `edge_loose_offset`
|
|
|
|
|
extract_lines_loose_geom_subdiv(subdiv_cache, mr, lines_loose);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
generate_subdiv_lines(subdiv_cache, lines);
|
|
|
|
|
extract_lines_loose_geom_subdiv(subdiv_cache, mr, lines);
|
|
|
|
|
|
|
|
|
|
if (DRW_ibo_requested(lines_loose)) {
|
|
|
|
|
/* Multiply by 2 because these are edges indices. */
|
|
|
|
|
const int start = subdiv_cache.num_subdiv_loops * 2;
|
|
|
|
|
const int len = subdiv_cache.loose_geom.edge_len * 2;
|
|
|
|
|
GPU_indexbuf_create_subrange_in_place(lines_loose, lines, start, len);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** \} */
|
|
|
|
|
|
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
|
/** \name Extract Lines and Loose Edges Sub Buffer
|
|
|
|
|
* \{ */
|
|
|
|
|
|
|
|
|
|
static void extract_lines_loose_subbuffer(const MeshRenderData &mr, MeshBatchCache &cache)
|
|
|
|
|
{
|
|
|
|
|
BLI_assert(cache.final.buff.ibo.lines);
|
|
|
|
|
/* Multiply by 2 because these are edges indices. */
|
|
|
|
|
const int start = mr.edges_num * 2;
|
|
|
|
|
const int len = mr.loose_edges_num * 2;
|
|
|
|
|
GPU_indexbuf_create_subrange_in_place(
|
|
|
|
|
cache.final.buff.ibo.lines_loose, cache.final.buff.ibo.lines, start, len);
|
|
|
|
|
cache.no_loose_wire = (len == 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void extract_lines_with_lines_loose_finish(const MeshRenderData &mr,
|
|
|
|
|
MeshBatchCache &cache,
|
|
|
|
|
void *buf,
|
|
|
|
|
void *tls_data)
|
|
|
|
|
{
|
|
|
|
|
MeshExtract_LinesData *data = static_cast<MeshExtract_LinesData *>(tls_data);
|
|
|
|
|
GPUIndexBufBuilder *elb = &data->elb;
|
|
|
|
|
gpu::IndexBuf *ibo = static_cast<gpu::IndexBuf *>(buf);
|
|
|
|
|
GPU_indexbuf_build_in_place(elb, ibo);
|
|
|
|
|
extract_lines_loose_subbuffer(mr, cache);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void extract_lines_with_lines_loose_finish_subdiv(const DRWSubdivCache &subdiv_cache,
|
|
|
|
|
const MeshRenderData & /*mr*/,
|
|
|
|
|
MeshBatchCache &cache,
|
|
|
|
|
void * /*buf*/,
|
|
|
|
|
void * /*_data*/)
|
|
|
|
|
{
|
|
|
|
|
/* Multiply by 2 because these are edges indices. */
|
|
|
|
|
const int start = subdiv_cache.num_subdiv_loops * 2;
|
|
|
|
|
const int len = subdiv_cache.loose_geom.edge_len * 2;
|
|
|
|
|
GPU_indexbuf_create_subrange_in_place(
|
|
|
|
|
cache.final.buff.ibo.lines_loose, cache.final.buff.ibo.lines, start, len);
|
|
|
|
|
cache.no_loose_wire = (len == 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
constexpr MeshExtract create_extractor_lines_with_lines_loose()
|
|
|
|
|
{
|
|
|
|
|
MeshExtract extractor = {nullptr};
|
|
|
|
|
extractor.init = extract_lines_init;
|
|
|
|
|
extractor.iter_face_bm = extract_lines_iter_face_bm;
|
|
|
|
|
extractor.iter_loose_edge_bm = extract_lines_iter_loose_edge_bm;
|
|
|
|
|
extractor.task_reduce = extract_lines_task_reduce;
|
|
|
|
|
extractor.finish = extract_lines_with_lines_loose_finish;
|
|
|
|
|
extractor.init_subdiv = extract_lines_init_subdiv;
|
|
|
|
|
extractor.iter_loose_geom_subdiv = extract_lines_loose_geom_subdiv;
|
|
|
|
|
extractor.finish_subdiv = extract_lines_with_lines_loose_finish_subdiv;
|
|
|
|
|
extractor.data_type = MR_DATA_NONE;
|
|
|
|
|
extractor.data_size = sizeof(MeshExtract_LinesData);
|
|
|
|
|
extractor.use_threading = true;
|
|
|
|
|
extractor.mesh_buffer_offset = offsetof(MeshBufferList, ibo.lines);
|
|
|
|
|
return extractor;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** \} */
|
|
|
|
|
|
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
|
/** \name Extract Loose Edges Sub Buffer
|
|
|
|
|
* \{ */
|
|
|
|
|
|
|
|
|
|
static void extract_lines_loose_only_init(const MeshRenderData &mr,
|
|
|
|
|
MeshBatchCache &cache,
|
|
|
|
|
void *buf,
|
|
|
|
|
void * /*tls_data*/)
|
|
|
|
|
{
|
|
|
|
|
BLI_assert(buf == cache.final.buff.ibo.lines_loose);
|
|
|
|
|
UNUSED_VARS_NDEBUG(buf);
|
|
|
|
|
extract_lines_loose_subbuffer(mr, cache);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void extract_lines_loose_only_init_subdiv(const DRWSubdivCache & /*subdiv_cache*/,
|
|
|
|
|
const MeshRenderData &mr,
|
|
|
|
|
MeshBatchCache &cache,
|
|
|
|
|
void *buffer,
|
|
|
|
|
void * /*data*/)
|
|
|
|
|
{
|
|
|
|
|
BLI_assert(buffer == cache.final.buff.ibo.lines_loose);
|
|
|
|
|
UNUSED_VARS_NDEBUG(buffer);
|
|
|
|
|
extract_lines_loose_subbuffer(mr, cache);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
constexpr MeshExtract create_extractor_lines_loose_only()
|
|
|
|
|
{
|
|
|
|
|
MeshExtract extractor = {nullptr};
|
|
|
|
|
extractor.init = extract_lines_loose_only_init;
|
|
|
|
|
extractor.init_subdiv = extract_lines_loose_only_init_subdiv;
|
|
|
|
|
extractor.data_type = MR_DATA_LOOSE_GEOM;
|
|
|
|
|
extractor.data_size = 0;
|
|
|
|
|
extractor.use_threading = false;
|
|
|
|
|
extractor.mesh_buffer_offset = offsetof(MeshBufferList, ibo.lines_loose);
|
|
|
|
|
return extractor;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** \} */
|
|
|
|
|
|
|
|
|
|
const MeshExtract extract_lines = create_extractor_lines();
|
|
|
|
|
|
|
|
|
|
} // namespace blender::draw
|
|
|
|
|