diff options
-rw-r--r-- | source/blender/blenkernel/BKE_geometry_set.hh | 12 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/geometry_component_curve.cc | 33 | ||||
-rw-r--r-- | source/blender/depsgraph/intern/depsgraph_query_iter.cc | 23 | ||||
-rw-r--r-- | source/blender/draw/CMakeLists.txt | 1 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_cache_impl_curve.cc | 161 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_curve_types.h | 7 |
6 files changed, 195 insertions, 42 deletions
diff --git a/source/blender/blenkernel/BKE_geometry_set.hh b/source/blender/blenkernel/BKE_geometry_set.hh index 0ed6eea7954..9b50a9042eb 100644 --- a/source/blender/blenkernel/BKE_geometry_set.hh +++ b/source/blender/blenkernel/BKE_geometry_set.hh @@ -39,6 +39,7 @@ struct Mesh; struct Object; struct PointCloud; struct Volume; +struct Curve; class CurveEval; enum class GeometryOwnershipType { @@ -406,6 +407,15 @@ class CurveComponent : public GeometryComponent { CurveEval *curve_ = nullptr; GeometryOwnershipType ownership_ = GeometryOwnershipType::Owned; + /** + * Curve data necessary to hold the draw cache for rendering, consistent over multiple redraws. + * This is necessary because Blender assumes that objects evaluate to an object data type, and + * we use #CurveEval rather than #Curve here. It also allows us to mostly reuse the same + * batch cache implementation. + */ + mutable Curve *curve_for_render_ = nullptr; + mutable std::mutex curve_for_render_mutex_; + public: CurveComponent(); ~CurveComponent(); @@ -430,6 +440,8 @@ class CurveComponent : public GeometryComponent { bool owns_direct_data() const override; void ensure_owns_direct_data() override; + const Curve *get_curve_for_render() const; + static constexpr inline GeometryComponentType static_type = GEO_COMPONENT_TYPE_CURVE; private: diff --git a/source/blender/blenkernel/intern/geometry_component_curve.cc b/source/blender/blenkernel/intern/geometry_component_curve.cc index be3fdf26cb3..de8dc355557 100644 --- a/source/blender/blenkernel/intern/geometry_component_curve.cc +++ b/source/blender/blenkernel/intern/geometry_component_curve.cc @@ -14,9 +14,14 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#include "DNA_ID_enums.h" +#include "DNA_curve_types.h" + #include "BKE_attribute_access.hh" #include "BKE_attribute_math.hh" +#include "BKE_curve.h" #include "BKE_geometry_set.hh" +#include "BKE_lib_id.h" #include "BKE_spline.hh" #include "attribute_access_intern.hh" @@ -58,6 +63,11 @@ void CurveComponent::clear() if (ownership_ == GeometryOwnershipType::Owned) { delete curve_; } + if (curve_for_render_ != nullptr) { + BKE_id_free(nullptr, curve_for_render_); + curve_for_render_ = nullptr; + } + curve_ = nullptr; } } @@ -118,6 +128,29 @@ void CurveComponent::ensure_owns_direct_data() } } +/** + * Create empty curve data used for rendering the spline's wire edges. + * \note See comment on #curve_for_render_ for further explanation. + */ +const Curve *CurveComponent::get_curve_for_render() const +{ + if (curve_ == nullptr) { + return nullptr; + } + if (curve_for_render_ != nullptr) { + return curve_for_render_; + } + std::lock_guard lock{curve_for_render_mutex_}; + if (curve_for_render_ != nullptr) { + return curve_for_render_; + } + + curve_for_render_ = (Curve *)BKE_id_new_nomain(ID_CU, nullptr); + curve_for_render_->curve_eval = curve_; + + return curve_for_render_; +} + /** \} */ /* -------------------------------------------------------------------- */ diff --git a/source/blender/depsgraph/intern/depsgraph_query_iter.cc b/source/blender/depsgraph/intern/depsgraph_query_iter.cc index ed002321729..df1cf8cc771 100644 --- a/source/blender/depsgraph/intern/depsgraph_query_iter.cc +++ b/source/blender/depsgraph/intern/depsgraph_query_iter.cc @@ -219,6 +219,29 @@ bool deg_iterator_components_step(BLI_Iterator *iter) } } + /* The curve component. */ + if (data->geometry_component_id == 3) { + data->geometry_component_id++; + + const CurveComponent *component = geometry_set->get_component_for_read<CurveComponent>(); + if (component != nullptr) { + const Curve *curve = component->get_curve_for_render(); + + if (curve != nullptr) { + Object *temp_object = &data->temp_geometry_component_object; + *temp_object = *data->geometry_component_owner; + temp_object->type = OB_CURVE; + temp_object->data = (void *)curve; + /* Assign data_eval here too, because curve rendering code tries + * to use a mesh if it can find one in this pointer. */ + temp_object->runtime.data_eval = (ID *)curve; + temp_object->runtime.select_id = data->geometry_component_owner->runtime.select_id; + iter->current = temp_object; + return true; + } + } + } + data->geometry_component_owner = nullptr; return false; } diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index 045adf4b380..afb0f613290 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -31,6 +31,7 @@ set(INC ../depsgraph ../editors/include ../editors/space_view3d + ../functions ../gpu ../imbuf ../makesdna diff --git a/source/blender/draw/intern/draw_cache_impl_curve.cc b/source/blender/draw/intern/draw_cache_impl_curve.cc index ddafc7205bb..5cf99db5485 100644 --- a/source/blender/draw/intern/draw_cache_impl_curve.cc +++ b/source/blender/draw/intern/draw_cache_impl_curve.cc @@ -25,8 +25,11 @@ #include "MEM_guardedalloc.h" +#include "BLI_array.hh" +#include "BLI_float3.hh" #include "BLI_listbase.h" #include "BLI_math_vector.h" +#include "BLI_span.hh" #include "BLI_utildefines.h" #include "DNA_curve_types.h" @@ -34,6 +37,8 @@ #include "BKE_curve.h" #include "BKE_displist.h" #include "BKE_font.h" +#include "BKE_geometry_set.hh" +#include "BKE_spline.hh" #include "GPU_batch.h" #include "GPU_capabilities.h" @@ -48,6 +53,11 @@ #include "draw_cache_impl.h" /* own include */ +using blender::Array; +using blender::float3; +using blender::IndexRange; +using blender::Span; + /* See: edit_curve_point_vert.glsl for duplicate includes. */ #define SELECT 1 #define ACTIVE_NURB (1 << 2) @@ -139,6 +149,21 @@ static void curve_render_wire_verts_edges_len_get(const CurveCache *ob_curve_cac } } +static void curve_eval_render_wire_verts_edges_len_get(const CurveEval &curve_eval, + int *r_curve_len, + int *r_vert_len, + int *r_edge_len) +{ + Span<SplinePtr> splines = curve_eval.splines(); + *r_curve_len = splines.size(); + *r_vert_len = 0; + *r_edge_len = 0; + for (const SplinePtr &spline : splines) { + *r_vert_len += spline->evaluated_points_size(); + *r_edge_len += spline->evaluated_edges_size(); + } +} + static int curve_render_normal_len_get(const ListBase *lb, const CurveCache *ob_curve_cache) { int normal_len = 0; @@ -192,6 +217,9 @@ struct CurveRenderData { /* borrow from 'Object' */ CurveCache *ob_curve_cache; + /* Owned by the evaluated object's geometry set (#geometry_set_eval). */ + const CurveEval *curve_eval; + /* borrow from 'Curve' */ ListBase *nurbs; @@ -230,11 +258,21 @@ static CurveRenderData *curve_render_data_create(Curve *cu, rdata->ob_curve_cache = ob_curve_cache; + rdata->curve_eval = cu->curve_eval; + if (types & CU_DATATYPE_WIRE) { - curve_render_wire_verts_edges_len_get(rdata->ob_curve_cache, - &rdata->wire.curve_len, - &rdata->wire.vert_len, - &rdata->wire.edge_len); + if (rdata->curve_eval != nullptr) { + curve_eval_render_wire_verts_edges_len_get(*rdata->curve_eval, + &rdata->wire.curve_len, + &rdata->wire.vert_len, + &rdata->wire.edge_len); + } + else { + curve_render_wire_verts_edges_len_get(rdata->ob_curve_cache, + &rdata->wire.curve_len, + &rdata->wire.vert_len, + &rdata->wire.edge_len); + } } if (cu->editnurb) { @@ -556,8 +594,6 @@ void DRW_curve_batch_cache_free(Curve *cu) /* GPUBatch cache usage. */ static void curve_create_curves_pos(CurveRenderData *rdata, GPUVertBuf *vbo_curves_pos) { - BLI_assert(rdata->ob_curve_cache != nullptr); - static GPUVertFormat format = {0}; static struct { uint pos; @@ -570,30 +606,46 @@ static void curve_create_curves_pos(CurveRenderData *rdata, GPUVertBuf *vbo_curv GPU_vertbuf_init_with_format(vbo_curves_pos, &format); GPU_vertbuf_data_alloc(vbo_curves_pos, vert_len); - int v_idx = 0; - LISTBASE_FOREACH (const BevList *, bl, &rdata->ob_curve_cache->bev) { - if (bl->nr <= 0) { - continue; - } - const int i_end = v_idx + bl->nr; - for (const BevPoint *bevp = bl->bevpoints; v_idx < i_end; v_idx++, bevp++) { - GPU_vertbuf_attr_set(vbo_curves_pos, attr_id.pos, v_idx, bevp->vec); + if (rdata->curve_eval != nullptr) { + const CurveEval &curve_eval = *rdata->curve_eval; + Span<SplinePtr> splines = curve_eval.splines(); + Array<int> offsets = curve_eval.evaluated_point_offsets(); + BLI_assert(offsets.last() == vert_len); + + for (const int i_spline : splines.index_range()) { + Span<float3> positions = splines[i_spline]->evaluated_positions(); + for (const int i_point : positions.index_range()) { + GPU_vertbuf_attr_set( + vbo_curves_pos, attr_id.pos, offsets[i_spline] + i_point, positions[i_point]); + } } } - LISTBASE_FOREACH (const DispList *, dl, &rdata->ob_curve_cache->disp) { - if (ELEM(dl->type, DL_SEGM, DL_POLY)) { - for (int i = 0; i < dl->nr; v_idx++, i++) { - GPU_vertbuf_attr_set(vbo_curves_pos, attr_id.pos, v_idx, &((float(*)[3])dl->verts)[i]); + else { + BLI_assert(rdata->ob_curve_cache != nullptr); + + int v_idx = 0; + LISTBASE_FOREACH (const BevList *, bl, &rdata->ob_curve_cache->bev) { + if (bl->nr <= 0) { + continue; + } + const int i_end = v_idx + bl->nr; + for (const BevPoint *bevp = bl->bevpoints; v_idx < i_end; v_idx++, bevp++) { + GPU_vertbuf_attr_set(vbo_curves_pos, attr_id.pos, v_idx, bevp->vec); + } + } + LISTBASE_FOREACH (const DispList *, dl, &rdata->ob_curve_cache->disp) { + if (ELEM(dl->type, DL_SEGM, DL_POLY)) { + for (int i = 0; i < dl->nr; v_idx++, i++) { + GPU_vertbuf_attr_set(vbo_curves_pos, attr_id.pos, v_idx, &((float(*)[3])dl->verts)[i]); + } } } + BLI_assert(v_idx == vert_len); } - BLI_assert(v_idx == vert_len); } static void curve_create_curves_lines(CurveRenderData *rdata, GPUIndexBuf *ibo_curve_lines) { - BLI_assert(rdata->ob_curve_cache != nullptr); - const int vert_len = curve_render_data_wire_verts_len_get(rdata); const int edge_len = curve_render_data_wire_edges_len_get(rdata); const int curve_len = curve_render_data_wire_curve_len_get(rdata); @@ -603,34 +655,56 @@ static void curve_create_curves_lines(CurveRenderData *rdata, GPUIndexBuf *ibo_c GPUIndexBufBuilder elb; GPU_indexbuf_init_ex(&elb, GPU_PRIM_LINE_STRIP, index_len, vert_len); - int v_idx = 0; - LISTBASE_FOREACH (const BevList *, bl, &rdata->ob_curve_cache->bev) { - if (bl->nr <= 0) { - continue; - } - const bool is_cyclic = bl->poly != -1; - if (is_cyclic) { - GPU_indexbuf_add_generic_vert(&elb, v_idx + (bl->nr - 1)); - } - for (int i = 0; i < bl->nr; i++) { - GPU_indexbuf_add_generic_vert(&elb, v_idx + i); + if (rdata->curve_eval != nullptr) { + const CurveEval &curve_eval = *rdata->curve_eval; + Span<SplinePtr> splines = curve_eval.splines(); + Array<int> offsets = curve_eval.evaluated_point_offsets(); + BLI_assert(offsets.last() == vert_len); + + for (const int i_spline : splines.index_range()) { + const int eval_size = splines[i_spline]->evaluated_points_size(); + if (splines[i_spline]->is_cyclic()) { + GPU_indexbuf_add_generic_vert(&elb, offsets[i_spline] + eval_size - 1); + } + for (const int i_point : IndexRange(eval_size)) { + GPU_indexbuf_add_generic_vert(&elb, offsets[i_spline] + i_point); + } + GPU_indexbuf_add_primitive_restart(&elb); } - GPU_indexbuf_add_primitive_restart(&elb); - v_idx += bl->nr; } - LISTBASE_FOREACH (const DispList *, dl, &rdata->ob_curve_cache->disp) { - if (ELEM(dl->type, DL_SEGM, DL_POLY)) { - const bool is_cyclic = dl->type == DL_POLY; + else { + BLI_assert(rdata->ob_curve_cache != nullptr); + + int v_idx = 0; + LISTBASE_FOREACH (const BevList *, bl, &rdata->ob_curve_cache->bev) { + if (bl->nr <= 0) { + continue; + } + const bool is_cyclic = bl->poly != -1; if (is_cyclic) { - GPU_indexbuf_add_generic_vert(&elb, v_idx + (dl->nr - 1)); + GPU_indexbuf_add_generic_vert(&elb, v_idx + (bl->nr - 1)); } - for (int i = 0; i < dl->nr; i++) { + for (int i = 0; i < bl->nr; i++) { GPU_indexbuf_add_generic_vert(&elb, v_idx + i); } GPU_indexbuf_add_primitive_restart(&elb); - v_idx += dl->nr; + v_idx += bl->nr; + } + LISTBASE_FOREACH (const DispList *, dl, &rdata->ob_curve_cache->disp) { + if (ELEM(dl->type, DL_SEGM, DL_POLY)) { + const bool is_cyclic = dl->type == DL_POLY; + if (is_cyclic) { + GPU_indexbuf_add_generic_vert(&elb, v_idx + (dl->nr - 1)); + } + for (int i = 0; i < dl->nr; i++) { + GPU_indexbuf_add_generic_vert(&elb, v_idx + i); + } + GPU_indexbuf_add_primitive_restart(&elb); + v_idx += dl->nr; + } } } + GPU_indexbuf_build_in_place(&elb, ibo_curve_lines); } @@ -1070,8 +1144,11 @@ void DRW_curve_batch_cache_create_requested(Object *ob, const struct Scene *scen CurveRenderData *rdata = curve_render_data_create(cu, ob->runtime.curve_cache, mr_flag); - /* DispLists */ - ListBase *lb = &rdata->ob_curve_cache->disp; + /* The object's curve cache can be empty (in one case because we use #CurveEval's cache instead), + * If so, point to an empty DispList list to avoid the need to check for null in the following + * functions. */ + ListBase empty_lb = {nullptr, nullptr}; + ListBase *lb = rdata->ob_curve_cache == nullptr ? &empty_lb : &rdata->ob_curve_cache->disp; /* Generate VBOs */ if (DRW_vbo_requested(cache->ordered.pos_nor)) { diff --git a/source/blender/makesdna/DNA_curve_types.h b/source/blender/makesdna/DNA_curve_types.h index 716c480bab8..f6242679808 100644 --- a/source/blender/makesdna/DNA_curve_types.h +++ b/source/blender/makesdna/DNA_curve_types.h @@ -43,6 +43,7 @@ struct Key; struct Material; struct Object; struct VFont; +struct CurveEval; /* These two Lines with # tell makesdna this struct can be excluded. */ # @@ -300,6 +301,12 @@ typedef struct Curve { char _pad2[6]; float fsize_realtime; + /** + * A pointer to curve data from geometry nodes, currently only set for evaluated + * objects by the dependency graph iterator, and owned by #geometry_set_eval. + */ + struct CurveEval *curve_eval; + void *batch_cache; } Curve; |