Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKévin Dietrich <kevin.dietrich@mailoo.org>2022-03-02 17:10:26 +0300
committerKévin Dietrich <kevin.dietrich@mailoo.org>2022-03-02 17:19:55 +0300
commit6883c47bb5930be5a95d1c2e8e06fce2d3b68681 (patch)
tree9c5fc32c03e6994a33827f2e7eaaa6d857f5554d
parent4a95c3466fafcd3e9116cd0d7fdcc63f2dc38bd2 (diff)
Fix T94729: GPU subdivision does not support meshes without polygons
There are two issues revealed in the bug report: - the GPU subdivision does not support meshes with only loose geometry - the loose geometry is not subdivided For the first case, checks are added to ensure we still fill the buffers with loose geometry even if no polygons are present. For the second case, this adds `BKE_subdiv_mesh_interpolate_position_on_edge` which encapsulates the loose vertex interpolation mechanism previously found in `subdiv_mesh_vertex_of_loose_edge`. The subdivided loose geometry is stored in a new specific data structure `DRWSubdivLooseGeom` so as to not pollute `MeshExtractLooseGeom`. These structures store the corresponding coarse element data, which will be used for filling GPU buffers appropriately. Differential Revision: https://developer.blender.org/D14171
-rw-r--r--source/blender/blenkernel/BKE_subdiv_mesh.h9
-rw-r--r--source/blender/blenkernel/intern/subdiv_mesh.c48
-rw-r--r--source/blender/draw/intern/draw_cache_extract_mesh.cc25
-rw-r--r--source/blender/draw/intern/draw_cache_impl_subdivision.cc254
-rw-r--r--source/blender/draw/intern/draw_subdivision.h69
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh.h1
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines.cc44
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_points.cc68
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edge_fac.cc11
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edit_data.cc30
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_pos_nor.cc97
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_select_idx.cc75
12 files changed, 518 insertions, 213 deletions
diff --git a/source/blender/blenkernel/BKE_subdiv_mesh.h b/source/blender/blenkernel/BKE_subdiv_mesh.h
index 73a3e8ed02e..2eae5338ae0 100644
--- a/source/blender/blenkernel/BKE_subdiv_mesh.h
+++ b/source/blender/blenkernel/BKE_subdiv_mesh.h
@@ -30,6 +30,7 @@ extern "C" {
#endif
struct Mesh;
+struct MEdge;
struct Subdiv;
typedef struct SubdivToMeshSettings {
@@ -49,6 +50,14 @@ struct Mesh *BKE_subdiv_to_mesh(struct Subdiv *subdiv,
const SubdivToMeshSettings *settings,
const struct Mesh *coarse_mesh);
+/* Interpolate a position along the `coarse_edge` at the relative `u` coordinate. If `is_simple` is
+ * false, this will perform a B-Spline interpolation using the edge neighbors, otherwise a linear
+ * interpolation will be done base on the edge vertices. */
+void BKE_subdiv_mesh_interpolate_position_on_edge(const struct Mesh *coarse_mesh,
+ const struct MEdge *coarse_edge,
+ bool is_simple,
+ float u,
+ float pos_r[3]);
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/intern/subdiv_mesh.c b/source/blender/blenkernel/intern/subdiv_mesh.c
index 333755e0899..95d74b56395 100644
--- a/source/blender/blenkernel/intern/subdiv_mesh.c
+++ b/source/blender/blenkernel/intern/subdiv_mesh.c
@@ -946,11 +946,10 @@ static void subdiv_mesh_vertex_loose(const SubdivForeachContext *foreach_context
/* Get neighbor edges of the given one.
* - neighbors[0] is an edge adjacent to edge->v1.
* - neighbors[1] is an edge adjacent to edge->v2. */
-static void find_edge_neighbors(const SubdivMeshContext *ctx,
+static void find_edge_neighbors(const Mesh *coarse_mesh,
const MEdge *edge,
const MEdge *neighbors[2])
{
- const Mesh *coarse_mesh = ctx->coarse_mesh;
const MEdge *coarse_medge = coarse_mesh->medge;
neighbors[0] = NULL;
neighbors[1] = NULL;
@@ -980,12 +979,11 @@ static void find_edge_neighbors(const SubdivMeshContext *ctx,
}
}
-static void points_for_loose_edges_interpolation_get(SubdivMeshContext *ctx,
+static void points_for_loose_edges_interpolation_get(const Mesh *coarse_mesh,
const MEdge *coarse_edge,
const MEdge *neighbors[2],
float points_r[4][3])
{
- const Mesh *coarse_mesh = ctx->coarse_mesh;
const MVert *coarse_mvert = coarse_mesh->mvert;
/* Middle points corresponds to the edge. */
copy_v3_v3(points_r[1], coarse_mvert[coarse_edge->v1].co);
@@ -1018,6 +1016,30 @@ static void points_for_loose_edges_interpolation_get(SubdivMeshContext *ctx,
}
}
+void BKE_subdiv_mesh_interpolate_position_on_edge(const Mesh *coarse_mesh,
+ const MEdge *coarse_edge,
+ const bool is_simple,
+ const float u,
+ float pos_r[3])
+{
+ if (is_simple) {
+ const MVert *coarse_mvert = coarse_mesh->mvert;
+ const MVert *vert_1 = &coarse_mvert[coarse_edge->v1];
+ const MVert *vert_2 = &coarse_mvert[coarse_edge->v2];
+ interp_v3_v3v3(pos_r, vert_1->co, vert_2->co, u);
+ }
+ else {
+ /* Find neighbors of the coarse edge. */
+ const MEdge *neighbors[2];
+ find_edge_neighbors(coarse_mesh, coarse_edge, neighbors);
+ float points[4][3];
+ points_for_loose_edges_interpolation_get(coarse_mesh, coarse_edge, neighbors, points);
+ float weights[4];
+ key_curve_position_weights(u, weights, KEY_BSPLINE);
+ interp_v3_v3v3v3v3(pos_r, points[0], points[1], points[2], points[3], weights);
+ }
+}
+
static void subdiv_mesh_vertex_of_loose_edge_interpolate(SubdivMeshContext *ctx,
const MEdge *coarse_edge,
const float u,
@@ -1054,9 +1076,6 @@ static void subdiv_mesh_vertex_of_loose_edge(const struct SubdivForeachContext *
Mesh *subdiv_mesh = ctx->subdiv_mesh;
MVert *subdiv_mvert = subdiv_mesh->mvert;
const bool is_simple = ctx->subdiv->settings.is_simple;
- /* Find neighbors of the current loose edge. */
- const MEdge *neighbors[2];
- find_edge_neighbors(ctx, coarse_edge, neighbors);
/* Interpolate custom data when not an end point.
* This data has already been copied from the original vertex by #subdiv_mesh_vertex_loose. */
if (!ELEM(u, 0.0, 1.0)) {
@@ -1064,19 +1083,8 @@ static void subdiv_mesh_vertex_of_loose_edge(const struct SubdivForeachContext *
}
/* Interpolate coordinate. */
MVert *subdiv_vertex = &subdiv_mvert[subdiv_vertex_index];
- if (is_simple) {
- const MVert *coarse_mvert = coarse_mesh->mvert;
- const MVert *vert_1 = &coarse_mvert[coarse_edge->v1];
- const MVert *vert_2 = &coarse_mvert[coarse_edge->v2];
- interp_v3_v3v3(subdiv_vertex->co, vert_1->co, vert_2->co, u);
- }
- else {
- float points[4][3];
- points_for_loose_edges_interpolation_get(ctx, coarse_edge, neighbors, points);
- float weights[4];
- key_curve_position_weights(u, weights, KEY_BSPLINE);
- interp_v3_v3v3v3v3(subdiv_vertex->co, points[0], points[1], points[2], points[3], weights);
- }
+ BKE_subdiv_mesh_interpolate_position_on_edge(
+ coarse_mesh, coarse_edge, is_simple, u, subdiv_vertex->co);
/* Reset flags and such. */
subdiv_vertex->flag = 0;
/* TODO(sergey): This matches old behavior, but we can as well interpolate
diff --git a/source/blender/draw/intern/draw_cache_extract_mesh.cc b/source/blender/draw/intern/draw_cache_extract_mesh.cc
index 8b4962f24b0..fb791916b46 100644
--- a/source/blender/draw/intern/draw_cache_extract_mesh.cc
+++ b/source/blender/draw/intern/draw_cache_extract_mesh.cc
@@ -822,7 +822,27 @@ static void mesh_buffer_cache_create_requested_subdiv(MeshBatchCache *cache,
extractors.append(&extract_fdots_pos);
}
- EXTRACT_ADD_REQUESTED(ibo, lines);
+ if (DRW_ibo_requested(mbuflist->ibo.lines_loose)) {
+ /* `ibo.lines_loose` require the `ibo.lines` buffer. */
+ if (mbuflist->ibo.lines == nullptr) {
+ DRW_ibo_request(nullptr, &mbuflist->ibo.lines);
+ }
+ const MeshExtract *extractor = DRW_ibo_requested(mbuflist->ibo.lines) ?
+ &extract_lines_with_lines_loose :
+ &extract_lines_loose_only;
+ extractors.append(extractor);
+ }
+ else if (DRW_ibo_requested(mbuflist->ibo.lines)) {
+ const MeshExtract *extractor;
+ if (mbuflist->ibo.lines_loose != nullptr) {
+ /* Update `ibo.lines_loose` as it depends on `ibo.lines`. */
+ extractor = &extract_lines_with_lines_loose;
+ }
+ else {
+ extractor = &extract_lines;
+ }
+ extractors.append(extractor);
+ }
EXTRACT_ADD_REQUESTED(ibo, edituv_points);
EXTRACT_ADD_REQUESTED(ibo, edituv_tris);
EXTRACT_ADD_REQUESTED(ibo, edituv_lines);
@@ -851,6 +871,7 @@ static void mesh_buffer_cache_create_requested_subdiv(MeshBatchCache *cache,
mesh_render_data_update_looptris(mr, MR_ITER_LOOPTRI, MR_DATA_LOOPTRI);
mesh_render_data_update_loose_geom(mr, mbc, MR_ITER_LEDGE | MR_ITER_LVERT, MR_DATA_LOOSE_GEOM);
+ DRW_subdivide_loose_geom(subdiv_cache, mbc);
void *data_stack = MEM_mallocN(extractors.data_size_total(), __func__);
uint32_t data_offset = 0;
@@ -884,7 +905,7 @@ static void mesh_buffer_cache_create_requested_subdiv(MeshBatchCache *cache,
}
if (extractor->iter_loose_geom_subdiv) {
- extractor->iter_loose_geom_subdiv(subdiv_cache, mr, &mbc->loose_geom, buffer, data);
+ extractor->iter_loose_geom_subdiv(subdiv_cache, mr, buffer, data);
}
if (extractor->finish_subdiv) {
diff --git a/source/blender/draw/intern/draw_cache_impl_subdivision.cc b/source/blender/draw/intern/draw_cache_impl_subdivision.cc
index f88c1a0e945..c7368c90213 100644
--- a/source/blender/draw/intern/draw_cache_impl_subdivision.cc
+++ b/source/blender/draw/intern/draw_cache_impl_subdivision.cc
@@ -533,6 +533,11 @@ static void draw_patch_map_free(DRWPatchMap *gpu_patch_map)
/** \name DRWSubdivCache
* \{ */
+static bool draw_subdiv_cache_need_polygon_data(const DRWSubdivCache *cache)
+{
+ return cache->subdiv && cache->subdiv->evaluator && cache->num_subdiv_loops != 0;
+}
+
static void draw_subdiv_cache_free_material_data(DRWSubdivCache *cache)
{
GPU_VERTBUF_DISCARD_SAFE(cache->polygon_mat_offset);
@@ -565,6 +570,7 @@ void draw_subdiv_cache_free(DRWSubdivCache *cache)
cache->num_subdiv_triangles = 0;
cache->num_coarse_poly = 0;
cache->num_subdiv_quads = 0;
+ cache->may_have_loose_geom = false;
draw_subdiv_free_edit_mode_cache(cache);
draw_subdiv_cache_free_material_data(cache);
draw_patch_map_free(&cache->gpu_patch_map);
@@ -572,6 +578,11 @@ void draw_subdiv_cache_free(DRWSubdivCache *cache)
GPU_uniformbuf_free(cache->ubo);
cache->ubo = nullptr;
}
+ MEM_SAFE_FREE(cache->loose_geom.edges);
+ MEM_SAFE_FREE(cache->loose_geom.verts);
+ cache->loose_geom.edge_len = 0;
+ cache->loose_geom.vert_len = 0;
+ cache->loose_geom.loop_len = 0;
}
/* Flags used in #DRWSubdivCache.extra_coarse_face_data. The flags are packed in the upper bits of
@@ -744,19 +755,25 @@ static bool draw_subdiv_topology_info_cb(const SubdivForeachContext *foreach_con
const int num_polygons,
const int *subdiv_polygon_offset)
{
- if (num_loops == 0) {
+ /* num_loops does not take into account meshes with only loose geometry, which might be meshes
+ * used as custom bone shapes, so let's check the num_vertices also. */
+ if (num_vertices == 0 && num_loops == 0) {
return false;
}
DRWCacheBuildingContext *ctx = (DRWCacheBuildingContext *)(foreach_context->user_data);
DRWSubdivCache *cache = ctx->cache;
- /* Set topology information. */
- cache->num_subdiv_edges = (uint)num_edges;
- cache->num_subdiv_loops = (uint)num_loops;
- cache->num_subdiv_verts = (uint)num_vertices;
- cache->num_subdiv_quads = (uint)num_polygons;
- cache->subdiv_polygon_offset = static_cast<int *>(MEM_dupallocN(subdiv_polygon_offset));
+ /* Set topology information only if we have loops. */
+ if (num_loops != 0) {
+ cache->num_subdiv_edges = (uint)num_edges;
+ cache->num_subdiv_loops = (uint)num_loops;
+ cache->num_subdiv_verts = (uint)num_vertices;
+ cache->num_subdiv_quads = (uint)num_polygons;
+ cache->subdiv_polygon_offset = static_cast<int *>(MEM_dupallocN(subdiv_polygon_offset));
+ }
+
+ cache->may_have_loose_geom = num_vertices != 0 || num_edges != 0;
/* Initialize cache buffers, prefer dynamic usage so we can reuse memory on the host even after
* it was sent to the device, since we may use the data while building other buffers on the CPU
@@ -795,16 +812,20 @@ static bool draw_subdiv_topology_info_cb(const SubdivForeachContext *foreach_con
ctx->e_origindex = static_cast<int *>(
CustomData_get_layer(&ctx->coarse_mesh->edata, CD_ORIGINDEX));
- ctx->vert_origindex_map = static_cast<int *>(
- MEM_mallocN(cache->num_subdiv_verts * sizeof(int), "subdiv_vert_origindex_map"));
- for (int i = 0; i < num_vertices; i++) {
- ctx->vert_origindex_map[i] = -1;
+ if (cache->num_subdiv_verts) {
+ ctx->vert_origindex_map = static_cast<int *>(
+ MEM_mallocN(cache->num_subdiv_verts * sizeof(int), "subdiv_vert_origindex_map"));
+ for (int i = 0; i < num_vertices; i++) {
+ ctx->vert_origindex_map[i] = -1;
+ }
}
- ctx->edge_origindex_map = static_cast<int *>(
- MEM_mallocN(cache->num_subdiv_edges * sizeof(int), "subdiv_edge_origindex_map"));
- for (int i = 0; i < num_edges; i++) {
- ctx->edge_origindex_map[i] = -1;
+ if (cache->num_subdiv_edges) {
+ ctx->edge_origindex_map = static_cast<int *>(
+ MEM_mallocN(cache->num_subdiv_edges * sizeof(int), "subdiv_edge_origindex_map"));
+ for (int i = 0; i < num_edges; i++) {
+ ctx->edge_origindex_map[i] = -1;
+ }
}
return true;
@@ -848,6 +869,10 @@ static void draw_subdiv_edge_cb(const SubdivForeachContext *foreach_context,
{
DRWCacheBuildingContext *ctx = (DRWCacheBuildingContext *)(foreach_context->user_data);
+ if (!ctx->edge_origindex_map) {
+ return;
+ }
+
int coarse_index = coarse_edge_index;
if (coarse_index != -1) {
@@ -998,7 +1023,8 @@ static bool draw_subdiv_build_cache(DRWSubdivCache *cache,
cache_building_context.cache = cache;
do_subdiv_traversal(&cache_building_context, subdiv);
- if (cache->num_subdiv_loops == 0) {
+ if (cache->num_subdiv_loops == 0 && cache->num_subdiv_verts == 0 &&
+ !cache->may_have_loose_geom) {
/* Either the traversal failed, or we have an empty mesh, either way we cannot go any further.
* The subdiv_polygon_offset cannot then be reliably stored in the cache, so free it directly.
*/
@@ -1006,44 +1032,47 @@ static bool draw_subdiv_build_cache(DRWSubdivCache *cache,
return false;
}
- /* Build buffers for the PatchMap. */
- draw_patch_map_build(&cache->gpu_patch_map, subdiv);
+ /* Only build polygon related data if we have polygons. */
+ if (cache->num_subdiv_loops != 0) {
+ /* Build buffers for the PatchMap. */
+ draw_patch_map_build(&cache->gpu_patch_map, subdiv);
+
+ cache->face_ptex_offset = BKE_subdiv_face_ptex_offset_get(subdiv);
+
+ /* Build patch coordinates for all the face dots. */
+ cache->fdots_patch_coords = gpu_vertbuf_create_from_format(get_blender_patch_coords_format(),
+ mesh_eval->totpoly);
+ CompressedPatchCoord *blender_fdots_patch_coords = (CompressedPatchCoord *)
+ GPU_vertbuf_get_data(cache->fdots_patch_coords);
+ for (int i = 0; i < mesh_eval->totpoly; i++) {
+ const int ptex_face_index = cache->face_ptex_offset[i];
+ if (mesh_eval->mpoly[i].totloop == 4) {
+ /* For quads, the center coordinate of the coarse face has `u = v = 0.5`. */
+ blender_fdots_patch_coords[i] = make_patch_coord(ptex_face_index, 0.5f, 0.5f);
+ }
+ else {
+ /* For N-gons, since they are split into quads from the center, and since the center is
+ * chosen to be the top right corner of each quad, the center coordinate of the coarse face
+ * is any one of those top right corners with `u = v = 1.0`. */
+ blender_fdots_patch_coords[i] = make_patch_coord(ptex_face_index, 1.0f, 1.0f);
+ }
+ }
- cache->face_ptex_offset = BKE_subdiv_face_ptex_offset_get(subdiv);
+ cache->subdiv_polygon_offset_buffer = draw_subdiv_build_origindex_buffer(
+ cache->subdiv_polygon_offset, mesh_eval->totpoly);
- // Build patch coordinates for all the face dots
- cache->fdots_patch_coords = gpu_vertbuf_create_from_format(get_blender_patch_coords_format(),
- mesh_eval->totpoly);
- CompressedPatchCoord *blender_fdots_patch_coords = (CompressedPatchCoord *)GPU_vertbuf_get_data(
- cache->fdots_patch_coords);
- for (int i = 0; i < mesh_eval->totpoly; i++) {
- const int ptex_face_index = cache->face_ptex_offset[i];
- if (mesh_eval->mpoly[i].totloop == 4) {
- /* For quads, the center coordinate of the coarse face has `u = v = 0.5`. */
- blender_fdots_patch_coords[i] = make_patch_coord(ptex_face_index, 0.5f, 0.5f);
- }
- else {
- /* For N-gons, since they are split into quads from the center, and since the center is
- * chosen to be the top right corner of each quad, the center coordinate of the coarse face
- * is any one of those top right corners with `u = v = 1.0`. */
- blender_fdots_patch_coords[i] = make_patch_coord(ptex_face_index, 1.0f, 1.0f);
- }
+ cache->face_ptex_offset_buffer = draw_subdiv_build_origindex_buffer(cache->face_ptex_offset,
+ mesh_eval->totpoly + 1);
+
+ build_vertex_face_adjacency_maps(cache);
}
cache->resolution = to_mesh_settings.resolution;
-
- cache->subdiv_polygon_offset_buffer = draw_subdiv_build_origindex_buffer(
- cache->subdiv_polygon_offset, mesh_eval->totpoly);
-
- cache->face_ptex_offset_buffer = draw_subdiv_build_origindex_buffer(cache->face_ptex_offset,
- mesh_eval->totpoly + 1);
cache->num_coarse_poly = mesh_eval->totpoly;
- build_vertex_face_adjacency_maps(cache);
-
/* Cleanup. */
- MEM_freeN(cache_building_context.vert_origindex_map);
- MEM_freeN(cache_building_context.edge_origindex_map);
+ MEM_SAFE_FREE(cache_building_context.vert_origindex_map);
+ MEM_SAFE_FREE(cache_building_context.edge_origindex_map);
return true;
}
@@ -1199,6 +1228,11 @@ static void drw_subdiv_compute_dispatch(const DRWSubdivCache *cache,
void draw_subdiv_extract_pos_nor(const DRWSubdivCache *cache, GPUVertBuf *pos_nor)
{
+ if (!draw_subdiv_cache_need_polygon_data(cache)) {
+ /* Happens on meshes with only loose geometry. */
+ return;
+ }
+
Subdiv *subdiv = cache->subdiv;
OpenSubdiv_Evaluator *evaluator = subdiv->evaluator;
@@ -1256,6 +1290,11 @@ void draw_subdiv_extract_uvs(const DRWSubdivCache *cache,
const int face_varying_channel,
const int dst_offset)
{
+ if (!draw_subdiv_cache_need_polygon_data(cache)) {
+ /* Happens on meshes with only loose geometry. */
+ return;
+ }
+
Subdiv *subdiv = cache->subdiv;
OpenSubdiv_Evaluator *evaluator = subdiv->evaluator;
@@ -1477,6 +1516,11 @@ void draw_subdiv_build_tris_buffer(const DRWSubdivCache *cache,
GPUIndexBuf *subdiv_tris,
const int material_count)
{
+ if (!draw_subdiv_cache_need_polygon_data(cache)) {
+ /* Happens on meshes with only loose geometry. */
+ return;
+ }
+
const bool do_single_material = material_count <= 1;
const char *defines = "#define SUBDIV_POLYGON_OFFSET\n";
@@ -1513,6 +1557,11 @@ void draw_subdiv_build_fdots_buffers(const DRWSubdivCache *cache,
GPUVertBuf *fdots_nor,
GPUIndexBuf *fdots_indices)
{
+ if (!draw_subdiv_cache_need_polygon_data(cache)) {
+ /* Happens on meshes with only loose geometry. */
+ return;
+ }
+
Subdiv *subdiv = cache->subdiv;
OpenSubdiv_Evaluator *evaluator = subdiv->evaluator;
@@ -1631,6 +1680,11 @@ void draw_subdiv_build_lnor_buffer(const DRWSubdivCache *cache,
GPUVertBuf *pos_nor,
GPUVertBuf *lnor)
{
+ if (!draw_subdiv_cache_need_polygon_data(cache)) {
+ /* Happens on meshes with only loose geometry. */
+ return;
+ }
+
GPUShader *shader = get_subdiv_shader(SHADER_BUFFER_LNOR, "#define SUBDIV_POLYGON_OFFSET\n");
GPU_shader_bind(shader);
@@ -1846,7 +1900,15 @@ static bool draw_subdiv_create_requested_buffers(const Scene *scene,
if (!BKE_subdiv_eval_begin_from_mesh(
subdiv, mesh_eval, nullptr, SUBDIV_EVALUATOR_TYPE_GLSL_COMPUTE, evaluator_cache)) {
- return false;
+ /* This could happen in two situations:
+ * - OpenSubdiv is disabled.
+ * - Something totally bad happened, and OpenSubdiv rejected our
+ * topology.
+ * In either way, we can't safely continue. However, we still have to handle potential loose
+ * geometry, which is done separately. */
+ if (mesh_eval->totpoly) {
+ return false;
+ }
}
DRWSubdivCache *draw_cache = mesh_batch_cache_ensure_subdiv_cache(batch_cache);
@@ -1883,6 +1945,104 @@ static bool draw_subdiv_create_requested_buffers(const Scene *scene,
return true;
}
+void DRW_subdivide_loose_geom(DRWSubdivCache *subdiv_cache, MeshBufferCache *cache)
+{
+ const int coarse_loose_vert_len = cache->loose_geom.vert_len;
+ const int coarse_loose_edge_len = cache->loose_geom.edge_len;
+
+ if (coarse_loose_vert_len == 0 && coarse_loose_edge_len == 0) {
+ /* Nothing to do. */
+ return;
+ }
+
+ if (subdiv_cache->loose_geom.edges || subdiv_cache->loose_geom.verts) {
+ /* Already processed. */
+ return;
+ }
+
+ const Mesh *coarse_mesh = subdiv_cache->mesh;
+ const bool is_simple = subdiv_cache->subdiv->settings.is_simple;
+ const int resolution = subdiv_cache->resolution;
+ const int resolution_1 = resolution - 1;
+ const float inv_resolution_1 = 1.0f / (float)resolution_1;
+ const int num_subdiv_vertices_per_coarse_edge = resolution - 2;
+
+ const int num_subdivided_edge = coarse_loose_edge_len *
+ (num_subdiv_vertices_per_coarse_edge + 1);
+
+ /* Each edge will store data for its 2 verts, that way we can keep the overall logic simple, here
+ * and in the buffer extractors. Although it duplicates memory (and work), the buffers also store
+ * duplicate values. */
+ const int num_subdivided_verts = num_subdivided_edge * 2;
+
+ DRWSubdivLooseEdge *loose_subd_edges = static_cast<DRWSubdivLooseEdge *>(
+ MEM_callocN(sizeof(DRWSubdivLooseEdge) * num_subdivided_edge, "DRWSubdivLooseEdge"));
+
+ DRWSubdivLooseVertex *loose_subd_verts = static_cast<DRWSubdivLooseVertex *>(
+ MEM_callocN(sizeof(DRWSubdivLooseVertex) * (num_subdivided_verts + coarse_loose_vert_len),
+ "DRWSubdivLooseEdge"));
+
+ int subd_edge_offset = 0;
+ int subd_vert_offset = 0;
+
+ /* Subdivide each loose coarse edge. */
+ for (int i = 0; i < coarse_loose_edge_len; i++) {
+ const int coarse_edge_index = cache->loose_geom.edges[i];
+ const MEdge *coarse_edge = &coarse_mesh->medge[cache->loose_geom.edges[i]];
+
+ /* Perform interpolation of each vertex. */
+ for (int i = 0; i < resolution - 1; i++, subd_edge_offset++) {
+ DRWSubdivLooseEdge &subd_edge = loose_subd_edges[subd_edge_offset];
+ subd_edge.coarse_edge_index = coarse_edge_index;
+
+ /* First vert. */
+ DRWSubdivLooseVertex &subd_v1 = loose_subd_verts[subd_vert_offset];
+ subd_v1.coarse_vertex_index = (i == 0) ? coarse_edge->v1 : -1u;
+ const float u1 = i * inv_resolution_1;
+ BKE_subdiv_mesh_interpolate_position_on_edge(
+ coarse_mesh, coarse_edge, is_simple, u1, subd_v1.co);
+
+ subd_edge.loose_subdiv_v1_index = subd_vert_offset++;
+
+ /* Second vert. */
+ DRWSubdivLooseVertex &subd_v2 = loose_subd_verts[subd_vert_offset];
+ subd_v2.coarse_vertex_index = ((i + 1) == resolution - 1) ? coarse_edge->v2 : -1u;
+ const float u2 = (i + 1) * inv_resolution_1;
+ BKE_subdiv_mesh_interpolate_position_on_edge(
+ coarse_mesh, coarse_edge, is_simple, u2, subd_v2.co);
+
+ subd_edge.loose_subdiv_v2_index = subd_vert_offset++;
+ }
+ }
+
+ /* Copy the remaining loose_verts. */
+ for (int i = 0; i < coarse_loose_vert_len; i++) {
+ const int coarse_vertex_index = cache->loose_geom.verts[i];
+ const MVert &coarse_vertex = coarse_mesh->mvert[coarse_vertex_index];
+
+ DRWSubdivLooseVertex &subd_v = loose_subd_verts[subd_vert_offset++];
+ subd_v.coarse_vertex_index = cache->loose_geom.verts[i];
+ copy_v3_v3(subd_v.co, coarse_vertex.co);
+ }
+
+ subdiv_cache->loose_geom.edges = loose_subd_edges;
+ subdiv_cache->loose_geom.verts = loose_subd_verts;
+ subdiv_cache->loose_geom.edge_len = num_subdivided_edge;
+ subdiv_cache->loose_geom.vert_len = coarse_loose_vert_len;
+ subdiv_cache->loose_geom.loop_len = num_subdivided_edge * 2 + coarse_loose_vert_len;
+}
+
+blender::Span<DRWSubdivLooseEdge> draw_subdiv_cache_get_loose_edges(const DRWSubdivCache *cache)
+{
+ return {cache->loose_geom.edges, static_cast<int64_t>(cache->loose_geom.edge_len)};
+}
+
+blender::Span<DRWSubdivLooseVertex> draw_subdiv_cache_get_loose_verts(const DRWSubdivCache *cache)
+{
+ return {cache->loose_geom.verts + cache->loose_geom.edge_len * 2,
+ static_cast<int64_t>(cache->loose_geom.vert_len)};
+}
+
static OpenSubdiv_EvaluatorCache *g_evaluator_cache = nullptr;
void DRW_create_subdivision(const Scene *scene,
diff --git a/source/blender/draw/intern/draw_subdivision.h b/source/blender/draw/intern/draw_subdivision.h
index 5942797ef8f..a2ca1c1735c 100644
--- a/source/blender/draw/intern/draw_subdivision.h
+++ b/source/blender/draw/intern/draw_subdivision.h
@@ -56,6 +56,56 @@ typedef struct DRWPatchMap {
/** \} */
/* -------------------------------------------------------------------- */
+/** \name DRWSubdivLooseEdge
+ *
+ * This stores information about a subdivided loose edge.
+ * \{ */
+
+typedef struct DRWSubdivLooseEdge {
+ /* The corresponding coarse edge, this is always valid. */
+ int coarse_edge_index;
+ /* Pointers into #DRWSubdivLooseGeom.verts. */
+ int loose_subdiv_v1_index;
+ int loose_subdiv_v2_index;
+} DRWSubdivLooseEdge;
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name DRWSubdivLooseVertex
+ *
+ * This stores information about a subdivided loose vertex, that may or may not come from a loose
+ * edge.
+ * \{ */
+
+typedef struct DRWSubdivLooseVertex {
+ /* The corresponding coarse vertex, or -1 if this vertex is the result
+ * of subdivision. */
+ unsigned int coarse_vertex_index;
+ /* Position and normal of the vertex. */
+ float co[3];
+ float nor[3];
+} DRWSubdivLooseVertex;
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name DRWSubdivLooseGeom
+ *
+ * This stores the subdivided vertices and edges of loose geometry from #MeshExtractLooseGeom.
+ * \{ */
+
+typedef struct DRWSubdivLooseGeom {
+ DRWSubdivLooseEdge *edges;
+ DRWSubdivLooseVertex *verts;
+ int edge_len;
+ int vert_len;
+ int loop_len;
+} DRWSubdivLooseGeom;
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name DRWSubdivCache
*
* This holds the various buffers used to evaluate and render subdivision through OpenGL.
@@ -84,6 +134,11 @@ typedef struct DRWSubdivCache {
uint num_subdiv_verts;
uint num_subdiv_quads;
+ /* We only do the subdivision traversal for full faces, however we may have geometries that only
+ * have loose edges (e.g. a custom bone shape). This flag is used to detect those cases, as the
+ * counters above will all be set to zero if we do not have subdivision loops. */
+ bool may_have_loose_geom;
+
/* Number of polygons in the coarse mesh, notably used to compute a coarse polygon index given a
* subdivision loop index. */
int num_coarse_poly;
@@ -128,6 +183,8 @@ typedef struct DRWSubdivCache {
DRWPatchMap gpu_patch_map;
+ DRWSubdivLooseGeom loose_geom;
+
/* UBO to store settings for the various compute shaders. */
struct GPUUniformBuf *ubo;
} DRWSubdivCache;
@@ -243,3 +300,15 @@ void draw_subdiv_build_edituv_stretch_angle_buffer(const DRWSubdivCache *cache,
#ifdef __cplusplus
}
#endif
+
+#ifdef __cplusplus
+# include "BLI_span.hh"
+
+/* Helper to access the loose edges. */
+blender::Span<DRWSubdivLooseEdge> draw_subdiv_cache_get_loose_edges(const DRWSubdivCache *cache);
+
+/* Helper to access only the loose vertices, i.e. not the ones attached to loose edges. To access
+ * loose vertices of loose edges #draw_subdiv_cache_get_loose_edges should be used. */
+blender::Span<DRWSubdivLooseVertex> draw_subdiv_cache_get_loose_verts(const DRWSubdivCache *cache);
+
+#endif
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh.h b/source/blender/draw/intern/mesh_extractors/extract_mesh.h
index 37eb4f80442..a250bc52ea8 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh.h
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh.h
@@ -206,7 +206,6 @@ typedef void(ExtractLVertMeshFn)(const MeshRenderData *mr,
void *data);
typedef void(ExtractLooseGeomSubdivFn)(const struct DRWSubdivCache *subdiv_cache,
const MeshRenderData *mr,
- const MeshExtractLooseGeom *loose_geom,
void *buffer,
void *data);
typedef void(ExtractInitFn)(const MeshRenderData *mr,
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines.cc
index 3d9729dea56..247d4c399e8 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines.cc
@@ -158,30 +158,35 @@ static void extract_lines_finish(const MeshRenderData *UNUSED(mr),
}
static void extract_lines_init_subdiv(const DRWSubdivCache *subdiv_cache,
- const MeshRenderData *mr,
+ const MeshRenderData *UNUSED(mr),
struct MeshBatchCache *UNUSED(cache),
void *buffer,
void *UNUSED(data))
{
+ const DRWSubdivLooseGeom &loose_geom = subdiv_cache->loose_geom;
GPUIndexBuf *ibo = static_cast<GPUIndexBuf *>(buffer);
GPU_indexbuf_init_build_on_device(ibo,
- subdiv_cache->num_subdiv_loops * 2 + mr->edge_loose_len * 2);
+ subdiv_cache->num_subdiv_loops * 2 + loose_geom.edge_len * 2);
+
+ if (subdiv_cache->num_subdiv_loops == 0) {
+ return;
+ }
draw_subdiv_build_lines_buffer(subdiv_cache, ibo);
}
static void extract_lines_loose_geom_subdiv(const DRWSubdivCache *subdiv_cache,
const MeshRenderData *UNUSED(mr),
- const MeshExtractLooseGeom *loose_geom,
void *buffer,
void *UNUSED(data))
{
- if (loose_geom->edge_len == 0) {
+ const DRWSubdivLooseGeom &loose_geom = subdiv_cache->loose_geom;
+ if (loose_geom.edge_len == 0) {
return;
}
GPUIndexBuf *ibo = static_cast<GPUIndexBuf *>(buffer);
- draw_subdiv_build_lines_loose_buffer(subdiv_cache, ibo, static_cast<uint>(loose_geom->edge_len));
+ draw_subdiv_build_lines_loose_buffer(subdiv_cache, ibo, static_cast<uint>(loose_geom.edge_len));
}
constexpr MeshExtract create_extractor_lines()
@@ -231,6 +236,20 @@ static void extract_lines_with_lines_loose_finish(const MeshRenderData *mr,
extract_lines_loose_subbuffer(mr, cache);
}
+static void extract_lines_with_lines_loose_finish_subdiv(const struct DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *UNUSED(mr),
+ struct MeshBatchCache *cache,
+ void *UNUSED(buf),
+ void *UNUSED(_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};
@@ -241,6 +260,9 @@ constexpr MeshExtract create_extractor_lines_with_lines_loose()
extractor.iter_ledge_mesh = extract_lines_iter_ledge_mesh;
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(GPUIndexBufBuilder);
extractor.use_threading = true;
@@ -264,10 +286,22 @@ static void extract_lines_loose_only_init(const MeshRenderData *mr,
extract_lines_loose_subbuffer(mr, cache);
}
+static void extract_lines_loose_only_init_subdiv(const DRWSubdivCache *UNUSED(subdiv_cache),
+ const MeshRenderData *mr,
+ struct MeshBatchCache *cache,
+ void *buffer,
+ void *UNUSED(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;
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_points.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_points.cc
index 2bb4cc0fb47..c5669f79a13 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_points.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_points.cc
@@ -163,8 +163,10 @@ static void extract_points_init_subdiv(const DRWSubdivCache *subdiv_cache,
void *data)
{
GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(data);
- GPU_indexbuf_init(
- elb, GPU_PRIM_POINTS, mr->vert_len, subdiv_cache->num_subdiv_loops + mr->loop_loose_len);
+ GPU_indexbuf_init(elb,
+ GPU_PRIM_POINTS,
+ mr->vert_len,
+ subdiv_cache->num_subdiv_loops + subdiv_cache->loose_geom.loop_len);
}
static void extract_points_iter_subdiv_common(GPUIndexBufBuilder *elb,
@@ -212,46 +214,70 @@ static void extract_points_iter_subdiv_mesh(const DRWSubdivCache *subdiv_cache,
static void extract_points_loose_geom_subdiv(const DRWSubdivCache *subdiv_cache,
const MeshRenderData *mr,
- const MeshExtractLooseGeom *loose_geom,
void *UNUSED(buffer),
void *data)
{
- const int loop_loose_len = loose_geom->edge_len + loose_geom->vert_len;
+ const DRWSubdivLooseGeom &loose_geom = subdiv_cache->loose_geom;
+ const int loop_loose_len = loose_geom.loop_len;
if (loop_loose_len == 0) {
return;
}
GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(data);
+
uint offset = subdiv_cache->num_subdiv_loops;
- if (mr->extract_type == MR_EXTRACT_MESH) {
- const Mesh *coarse_mesh = subdiv_cache->mesh;
- const MEdge *coarse_edges = coarse_mesh->medge;
+ if (mr->extract_type != MR_EXTRACT_BMESH) {
+ blender::Span<DRWSubdivLooseEdge> loose_edges = draw_subdiv_cache_get_loose_edges(
+ subdiv_cache);
+
+ for (const DRWSubdivLooseEdge &loose_edge : loose_edges) {
+ const DRWSubdivLooseVertex &v1 = loose_geom.verts[loose_edge.loose_subdiv_v1_index];
+ const DRWSubdivLooseVertex &v2 = loose_geom.verts[loose_edge.loose_subdiv_v2_index];
+ if (v1.coarse_vertex_index != -1u) {
+ vert_set_mesh(elb, mr, v1.coarse_vertex_index, offset);
+ }
+ if (v2.coarse_vertex_index != -1u) {
+ vert_set_mesh(elb, mr, v2.coarse_vertex_index, offset + 1);
+ }
- for (int i = 0; i < loose_geom->edge_len; i++) {
- const MEdge *loose_edge = &coarse_edges[loose_geom->edges[i]];
- vert_set_mesh(elb, mr, loose_edge->v1, offset);
- vert_set_mesh(elb, mr, loose_edge->v2, offset + 1);
offset += 2;
}
+ blender::Span<DRWSubdivLooseVertex> loose_verts = draw_subdiv_cache_get_loose_verts(
+ subdiv_cache);
- for (int i = 0; i < loose_geom->vert_len; i++) {
- vert_set_mesh(elb, mr, loose_geom->verts[i], offset);
+ for (const DRWSubdivLooseVertex &loose_vert : loose_verts) {
+ vert_set_mesh(elb, mr, loose_vert.coarse_vertex_index, offset);
offset += 1;
}
}
else {
- BMesh *bm = mr->bm;
- for (int i = 0; i < loose_geom->edge_len; i++) {
- const BMEdge *loose_edge = BM_edge_at_index(bm, loose_geom->edges[i]);
- vert_set_bm(elb, loose_edge->v1, offset);
- vert_set_bm(elb, loose_edge->v2, offset + 1);
+ blender::Span<DRWSubdivLooseEdge> loose_edges = draw_subdiv_cache_get_loose_edges(
+ subdiv_cache);
+
+ for (const DRWSubdivLooseEdge &loose_edge : loose_edges) {
+ const DRWSubdivLooseVertex &v1 = loose_geom.verts[loose_edge.loose_subdiv_v1_index];
+ const DRWSubdivLooseVertex &v2 = loose_geom.verts[loose_edge.loose_subdiv_v2_index];
+ if (v1.coarse_vertex_index != -1u) {
+ BMVert *eve = mr->v_origindex ? bm_original_vert_get(mr, v1.coarse_vertex_index) :
+ BM_vert_at_index(mr->bm, v1.coarse_vertex_index);
+ vert_set_bm(elb, eve, offset);
+ }
+ if (v2.coarse_vertex_index != -1u) {
+ BMVert *eve = mr->v_origindex ? bm_original_vert_get(mr, v2.coarse_vertex_index) :
+ BM_vert_at_index(mr->bm, v2.coarse_vertex_index);
+ vert_set_bm(elb, eve, offset + 1);
+ }
+
offset += 2;
}
+ blender::Span<DRWSubdivLooseVertex> loose_verts = draw_subdiv_cache_get_loose_verts(
+ subdiv_cache);
- for (int i = 0; i < loose_geom->vert_len; i++) {
- const BMVert *loose_vert = BM_vert_at_index(bm, loose_geom->verts[i]);
- vert_set_bm(elb, loose_vert, offset);
+ for (const DRWSubdivLooseVertex &loose_vert : loose_verts) {
+ BMVert *eve = mr->v_origindex ? bm_original_vert_get(mr, loose_vert.coarse_vertex_index) :
+ BM_vert_at_index(mr->bm, loose_vert.coarse_vertex_index);
+ vert_set_bm(elb, eve, offset);
offset += 1;
}
}
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edge_fac.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edge_fac.cc
index 8470a71059f..2d4e0a8e246 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edge_fac.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edge_fac.cc
@@ -233,16 +233,17 @@ static GPUVertFormat *get_subdiv_edge_fac_format()
}
static void extract_edge_fac_init_subdiv(const DRWSubdivCache *subdiv_cache,
- const MeshRenderData *mr,
+ const MeshRenderData *UNUSED(mr),
struct MeshBatchCache *cache,
void *buffer,
void *UNUSED(data))
{
+ const DRWSubdivLooseGeom &loose_geom = subdiv_cache->loose_geom;
GPUVertBuf *edge_idx = cache->final.buff.vbo.edge_idx;
GPUVertBuf *pos_nor = cache->final.buff.vbo.pos_nor;
GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buffer);
GPU_vertbuf_init_build_on_device(
- vbo, get_subdiv_edge_fac_format(), subdiv_cache->num_subdiv_loops + mr->loop_loose_len);
+ vbo, get_subdiv_edge_fac_format(), subdiv_cache->num_subdiv_loops + loose_geom.loop_len);
/* Create a temporary buffer for the edge original indices if it was not requested. */
const bool has_edge_idx = edge_idx != nullptr;
@@ -268,11 +269,11 @@ static void extract_edge_fac_init_subdiv(const DRWSubdivCache *subdiv_cache,
static void extract_edge_fac_loose_geom_subdiv(const DRWSubdivCache *subdiv_cache,
const MeshRenderData *UNUSED(mr),
- const MeshExtractLooseGeom *loose_geom,
void *buffer,
void *UNUSED(data))
{
- if (loose_geom->edge_len == 0) {
+ const DRWSubdivLooseGeom &loose_geom = subdiv_cache->loose_geom;
+ if (loose_geom.edge_len == 0) {
return;
}
@@ -282,7 +283,7 @@ static void extract_edge_fac_loose_geom_subdiv(const DRWSubdivCache *subdiv_cach
GPU_vertbuf_use(vbo);
uint offset = subdiv_cache->num_subdiv_loops;
- for (int i = 0; i < loose_geom->edge_len; i++) {
+ for (int i = 0; i < loose_geom.edge_len; i++) {
if (GPU_crappy_amd_driver()) {
float loose_edge_fac[2] = {1.0f, 1.0f};
GPU_vertbuf_update_sub(vbo, offset * sizeof(float), sizeof(loose_edge_fac), loose_edge_fac);
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edit_data.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edit_data.cc
index 046e4b9e4bb..d13d5e98132 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edit_data.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edit_data.cc
@@ -256,14 +256,15 @@ static void extract_edit_data_iter_lvert_mesh(const MeshRenderData *mr,
}
static void extract_edit_data_init_subdiv(const DRWSubdivCache *subdiv_cache,
- const MeshRenderData *mr,
+ const MeshRenderData *UNUSED(mr),
MeshBatchCache *UNUSED(cache),
void *buf,
void *data)
{
+ const DRWSubdivLooseGeom &loose_geom = subdiv_cache->loose_geom;
GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf);
GPU_vertbuf_init_with_format(vbo, get_edit_data_format());
- GPU_vertbuf_data_alloc(vbo, subdiv_cache->num_subdiv_loops + mr->loop_loose_len);
+ GPU_vertbuf_data_alloc(vbo, subdiv_cache->num_subdiv_loops + loose_geom.loop_len);
EditLoopData *vbo_data = (EditLoopData *)GPU_vertbuf_get_data(vbo);
*(EditLoopData **)data = vbo_data;
}
@@ -322,27 +323,38 @@ static void extract_edit_data_iter_subdiv_mesh(const DRWSubdivCache *subdiv_cach
static void extract_edit_data_loose_geom_subdiv(const DRWSubdivCache *subdiv_cache,
const MeshRenderData *mr,
- const MeshExtractLooseGeom *loose_geom,
void *UNUSED(buffer),
void *_data)
{
- if (loose_geom->edge_len == 0) {
+ const DRWSubdivLooseGeom &loose_geom = subdiv_cache->loose_geom;
+ if (loose_geom.edge_len == 0) {
return;
}
+ blender::Span<DRWSubdivLooseEdge> loose_edges = draw_subdiv_cache_get_loose_edges(subdiv_cache);
+
EditLoopData *vbo_data = *(EditLoopData **)_data;
+ int ledge_index = 0;
- for (int ledge_index = 0; ledge_index < loose_geom->edge_len; ledge_index++) {
- const int offset = subdiv_cache->num_subdiv_loops + ledge_index * 2;
+ for (const DRWSubdivLooseEdge &loose_edge : loose_edges) {
+ const int offset = subdiv_cache->num_subdiv_loops + ledge_index++ * 2;
EditLoopData *data = &vbo_data[offset];
memset(data, 0, sizeof(EditLoopData));
- const int edge_index = loose_geom->edges[ledge_index];
+ const int edge_index = loose_edge.coarse_edge_index;
BMEdge *eed = mr->e_origindex ? bm_original_edge_get(mr, edge_index) :
BM_edge_at_index(mr->bm, edge_index);
mesh_render_data_edge_flag(mr, eed, &data[0]);
data[1] = data[0];
- mesh_render_data_vert_flag(mr, eed->v1, &data[0]);
- mesh_render_data_vert_flag(mr, eed->v2, &data[1]);
+
+ const DRWSubdivLooseVertex &v1 = loose_geom.verts[loose_edge.loose_subdiv_v1_index];
+ const DRWSubdivLooseVertex &v2 = loose_geom.verts[loose_edge.loose_subdiv_v2_index];
+
+ if (v1.coarse_vertex_index != -1u) {
+ mesh_render_data_vert_flag(mr, eed->v1, &data[0]);
+ }
+ if (v2.coarse_vertex_index != -1u) {
+ mesh_render_data_vert_flag(mr, eed->v2, &data[1]);
+ }
}
}
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_pos_nor.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_pos_nor.cc
index a844a116a87..12cff6408b6 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_pos_nor.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_pos_nor.cc
@@ -227,16 +227,21 @@ static GPUVertFormat *get_custom_normals_format()
}
static void extract_pos_nor_init_subdiv(const DRWSubdivCache *subdiv_cache,
- const MeshRenderData *mr,
+ const MeshRenderData *UNUSED(mr),
struct MeshBatchCache *UNUSED(cache),
void *buffer,
void *UNUSED(data))
{
GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buffer);
+ const DRWSubdivLooseGeom &loose_geom = subdiv_cache->loose_geom;
/* Initialize the vertex buffer, it was already allocated. */
GPU_vertbuf_init_build_on_device(
- vbo, get_pos_nor_format(), subdiv_cache->num_subdiv_loops + mr->loop_loose_len);
+ vbo, get_pos_nor_format(), subdiv_cache->num_subdiv_loops + loose_geom.loop_len);
+
+ if (subdiv_cache->num_subdiv_loops == 0) {
+ return;
+ }
draw_subdiv_extract_pos_nor(subdiv_cache, vbo);
@@ -289,13 +294,12 @@ static void extract_pos_nor_init_subdiv(const DRWSubdivCache *subdiv_cache,
}
static void extract_pos_nor_loose_geom_subdiv(const DRWSubdivCache *subdiv_cache,
- const MeshRenderData *mr,
- const MeshExtractLooseGeom *loose_geom,
+ const MeshRenderData *UNUSED(mr),
void *buffer,
void *UNUSED(data))
{
- const int loop_loose_len = loose_geom->edge_len + loose_geom->vert_len;
- if (loop_loose_len == 0) {
+ const DRWSubdivLooseGeom &loose_geom = subdiv_cache->loose_geom;
+ if (loose_geom.loop_len == 0) {
return;
}
@@ -309,75 +313,38 @@ static void extract_pos_nor_loose_geom_subdiv(const DRWSubdivCache *subdiv_cache
float flag;
};
- if (mr->extract_type == MR_EXTRACT_MESH) {
- const Mesh *coarse_mesh = subdiv_cache->mesh;
- const MEdge *coarse_edges = coarse_mesh->medge;
- const MVert *coarse_verts = coarse_mesh->mvert;
-
- SubdivPosNorLoop edge_data[2];
- memset(&edge_data, 0, sizeof(SubdivPosNorLoop) * 2);
- for (int i = 0; i < loose_geom->edge_len; i++) {
- const MEdge *loose_edge = &coarse_edges[loose_geom->edges[i]];
- const MVert *loose_vert1 = &coarse_verts[loose_edge->v1];
- const MVert *loose_vert2 = &coarse_verts[loose_edge->v2];
+ /* Make sure buffer is active for sending loose data. */
+ GPU_vertbuf_use(vbo);
- copy_v3_v3(edge_data[0].pos, loose_vert1->co);
- copy_v3_v3(edge_data[1].pos, loose_vert2->co);
+ blender::Span<DRWSubdivLooseEdge> loose_edges = draw_subdiv_cache_get_loose_edges(subdiv_cache);
- GPU_vertbuf_update_sub(
- vbo, offset * sizeof(SubdivPosNorLoop), sizeof(SubdivPosNorLoop) * 2, &edge_data);
+ SubdivPosNorLoop edge_data[2];
+ memset(edge_data, 0, sizeof(SubdivPosNorLoop) * 2);
+ for (const DRWSubdivLooseEdge &loose_edge : loose_edges) {
+ const DRWSubdivLooseVertex &v1 = loose_geom.verts[loose_edge.loose_subdiv_v1_index];
+ const DRWSubdivLooseVertex &v2 = loose_geom.verts[loose_edge.loose_subdiv_v2_index];
- offset += 2;
- }
-
- SubdivPosNorLoop vert_data;
- memset(&vert_data, 0, sizeof(SubdivPosNorLoop));
- for (int i = 0; i < loose_geom->vert_len; i++) {
- const MVert *loose_vertex = &coarse_verts[loose_geom->verts[i]];
+ copy_v3_v3(edge_data[0].pos, v1.co);
+ copy_v3_v3(edge_data[1].pos, v2.co);
- copy_v3_v3(vert_data.pos, loose_vertex->co);
+ GPU_vertbuf_update_sub(
+ vbo, offset * sizeof(SubdivPosNorLoop), sizeof(SubdivPosNorLoop) * 2, &edge_data);
- GPU_vertbuf_update_sub(
- vbo, offset * sizeof(SubdivPosNorLoop), sizeof(SubdivPosNorLoop), &vert_data);
-
- offset += 1;
- }
+ offset += 2;
}
- else {
- BMesh *bm = subdiv_cache->bm;
-
- SubdivPosNorLoop edge_data[2];
- memset(&edge_data, 0, sizeof(SubdivPosNorLoop) * 2);
- for (int i = 0; i < loose_geom->edge_len; i++) {
- const BMEdge *loose_edge = BM_edge_at_index(bm, loose_geom->edges[i]);
- const BMVert *loose_vert1 = loose_edge->v1;
- const BMVert *loose_vert2 = loose_edge->v2;
-
- copy_v3_v3(edge_data[0].pos, loose_vert1->co);
- copy_v3_v3(edge_data[0].nor, loose_vert1->no);
-
- copy_v3_v3(edge_data[1].pos, loose_vert2->co);
- copy_v3_v3(edge_data[1].nor, loose_vert2->no);
- GPU_vertbuf_update_sub(
- vbo, offset * sizeof(SubdivPosNorLoop), sizeof(SubdivPosNorLoop) * 2, &edge_data);
+ SubdivPosNorLoop vert_data;
+ memset(&vert_data, 0, sizeof(SubdivPosNorLoop));
+ blender::Span<DRWSubdivLooseVertex> loose_verts = draw_subdiv_cache_get_loose_verts(
+ subdiv_cache);
- offset += 2;
- }
-
- SubdivPosNorLoop vert_data;
- memset(&vert_data, 0, sizeof(SubdivPosNorLoop));
- for (int i = 0; i < loose_geom->vert_len; i++) {
- const BMVert *loose_vertex = BM_vert_at_index(bm, loose_geom->verts[i]);
+ for (const DRWSubdivLooseVertex &loose_vert : loose_verts) {
+ copy_v3_v3(vert_data.pos, loose_vert.co);
- copy_v3_v3(vert_data.pos, loose_vertex->co);
- copy_v3_v3(vert_data.nor, loose_vertex->no);
+ GPU_vertbuf_update_sub(
+ vbo, offset * sizeof(SubdivPosNorLoop), sizeof(SubdivPosNorLoop), &vert_data);
- GPU_vertbuf_update_sub(
- vbo, offset * sizeof(SubdivPosNorLoop), sizeof(SubdivPosNorLoop), &vert_data);
-
- offset += 1;
- }
+ offset += 1;
}
}
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_select_idx.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_select_idx.cc
index 8d3df75b782..f570a26ae67 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_select_idx.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_select_idx.cc
@@ -204,12 +204,12 @@ static void extract_vert_idx_init_subdiv(const DRWSubdivCache *subdiv_cache,
void *UNUSED(data))
{
GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf);
+ const DRWSubdivLooseGeom &loose_geom = subdiv_cache->loose_geom;
/* Each element points to an element in the ibo.points. */
draw_subdiv_init_origindex_buffer(vbo,
(int *)GPU_vertbuf_get_data(subdiv_cache->verts_orig_index),
subdiv_cache->num_subdiv_loops,
- mr->loop_loose_len);
-
+ loose_geom.loop_len);
if (!mr->v_origindex) {
return;
}
@@ -228,12 +228,11 @@ static void extract_vert_idx_init_subdiv(const DRWSubdivCache *subdiv_cache,
static void extract_vert_idx_loose_geom_subdiv(const DRWSubdivCache *subdiv_cache,
const MeshRenderData *mr,
- const MeshExtractLooseGeom *loose_geom,
void *buffer,
void *UNUSED(data))
{
- const int loop_loose_len = loose_geom->edge_len + loose_geom->vert_len;
- if (loop_loose_len == 0) {
+ const DRWSubdivLooseGeom &loose_geom = subdiv_cache->loose_geom;
+ if (loose_geom.loop_len == 0) {
return;
}
@@ -241,60 +240,57 @@ static void extract_vert_idx_loose_geom_subdiv(const DRWSubdivCache *subdiv_cach
uint *vert_idx_data = (uint *)GPU_vertbuf_get_data(vbo);
uint offset = subdiv_cache->num_subdiv_loops;
- if (mr->extract_type == MR_EXTRACT_MESH) {
- const Mesh *coarse_mesh = subdiv_cache->mesh;
- const MEdge *coarse_edges = coarse_mesh->medge;
- for (int i = 0; i < loose_geom->edge_len; i++) {
- const MEdge *loose_edge = &coarse_edges[loose_geom->edges[i]];
- vert_idx_data[offset] = loose_edge->v1;
- vert_idx_data[offset + 1] = loose_edge->v2;
- offset += 2;
+ blender::Span<DRWSubdivLooseEdge> loose_edges = draw_subdiv_cache_get_loose_edges(subdiv_cache);
+
+ for (const DRWSubdivLooseEdge &loose_edge : loose_edges) {
+ const DRWSubdivLooseVertex &v1 = loose_geom.verts[loose_edge.loose_subdiv_v1_index];
+ const DRWSubdivLooseVertex &v2 = loose_geom.verts[loose_edge.loose_subdiv_v2_index];
+
+ if (v1.coarse_vertex_index != -1u) {
+ vert_idx_data[offset] = mr->v_origindex ? mr->v_origindex[v1.coarse_vertex_index] :
+ v1.coarse_vertex_index;
}
- for (int i = 0; i < loose_geom->vert_len; i++) {
- vert_idx_data[offset] = loose_geom->verts[i];
- offset += 1;
+ if (v2.coarse_vertex_index != -1u) {
+ vert_idx_data[offset + 1] = mr->v_origindex ? mr->v_origindex[v2.coarse_vertex_index] :
+ v2.coarse_vertex_index;
}
+
+ offset += 2;
}
- else {
- BMesh *bm = mr->bm;
- for (int i = 0; i < loose_geom->edge_len; i++) {
- const BMEdge *loose_edge = BM_edge_at_index(bm, loose_geom->edges[i]);
- vert_idx_data[offset] = BM_elem_index_get(loose_edge->v1);
- vert_idx_data[offset + 1] = BM_elem_index_get(loose_edge->v2);
- offset += 2;
- }
- for (int i = 0; i < loose_geom->vert_len; i++) {
- const BMVert *loose_vert = BM_vert_at_index(bm, loose_geom->verts[i]);
- vert_idx_data[offset] = BM_elem_index_get(loose_vert);
- offset += 1;
- }
+ blender::Span<DRWSubdivLooseVertex> loose_verts = draw_subdiv_cache_get_loose_verts(
+ subdiv_cache);
+
+ for (const DRWSubdivLooseVertex &loose_vert : loose_verts) {
+ vert_idx_data[offset] = mr->v_origindex ? mr->v_origindex[loose_vert.coarse_vertex_index] :
+ loose_vert.coarse_vertex_index;
+ offset += 1;
}
}
static void extract_edge_idx_init_subdiv(const DRWSubdivCache *subdiv_cache,
- const MeshRenderData *mr,
+ const MeshRenderData *UNUSED(mr),
MeshBatchCache *UNUSED(cache),
void *buf,
void *UNUSED(data))
{
GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf);
+ const DRWSubdivLooseGeom &loose_geom = subdiv_cache->loose_geom;
draw_subdiv_init_origindex_buffer(
vbo,
static_cast<int *>(GPU_vertbuf_get_data(subdiv_cache->edges_orig_index)),
subdiv_cache->num_subdiv_loops,
- mr->edge_loose_len * 2);
+ loose_geom.edge_len * 2);
}
static void extract_edge_idx_loose_geom_subdiv(const DRWSubdivCache *subdiv_cache,
- const MeshRenderData *UNUSED(mr),
- const MeshExtractLooseGeom *loose_geom,
+ const MeshRenderData *mr,
void *buffer,
void *UNUSED(data))
{
- const int loop_loose_len = loose_geom->edge_len + loose_geom->vert_len;
- if (loop_loose_len == 0) {
+ const DRWSubdivLooseGeom &loose_geom = subdiv_cache->loose_geom;
+ if (loose_geom.edge_len == 0) {
return;
}
@@ -302,9 +298,12 @@ static void extract_edge_idx_loose_geom_subdiv(const DRWSubdivCache *subdiv_cach
uint *vert_idx_data = (uint *)GPU_vertbuf_get_data(vbo);
uint offset = subdiv_cache->num_subdiv_loops;
- for (int i = 0; i < loose_geom->edge_len; i++) {
- vert_idx_data[offset] = loose_geom->edges[i];
- vert_idx_data[offset + 1] = loose_geom->edges[i];
+ blender::Span<DRWSubdivLooseEdge> loose_edges = draw_subdiv_cache_get_loose_edges(subdiv_cache);
+ for (const DRWSubdivLooseEdge &loose_edge : loose_edges) {
+ const int coarse_edge_index = mr->e_origindex ? mr->e_origindex[loose_edge.coarse_edge_index] :
+ loose_edge.coarse_edge_index;
+ vert_idx_data[offset] = coarse_edge_index;
+ vert_idx_data[offset + 1] = coarse_edge_index;
offset += 2;
}
}