Blender V4.3
blenkernel/intern/curves.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include <cmath>
10#include <cstring>
11#include <optional>
12
13#include "MEM_guardedalloc.h"
14
15#include "DNA_curves_types.h"
16#include "DNA_defaults.h"
17#include "DNA_material_types.h"
18#include "DNA_object_types.h"
19
20#include "BLI_index_range.hh"
21#include "BLI_math_base.h"
22#include "BLI_math_matrix.hh"
23#include "BLI_rand.hh"
24#include "BLI_span.hh"
25#include "BLI_string.h"
26#include "BLI_utildefines.h"
27#include "BLI_vector.hh"
28
29#include "BKE_anim_data.hh"
30#include "BKE_curves.hh"
32#include "BKE_geometry_set.hh"
33#include "BKE_idtype.hh"
34#include "BKE_lib_id.hh"
35#include "BKE_lib_query.hh"
36#include "BKE_modifier.hh"
37#include "BKE_object.hh"
38#include "BKE_object_types.hh"
39
40#include "BLT_translation.hh"
41
43
44#include "BLO_read_write.hh"
45
46using blender::float3;
50using blender::Span;
51using blender::Vector;
52
53static const char *ATTR_POSITION = "position";
54
55static void curves_init_data(ID *id)
56{
57 Curves *curves = (Curves *)id;
59
61
62 new (&curves->geometry) blender::bke::CurvesGeometry();
63}
64
65static void curves_copy_data(Main * /*bmain*/,
66 std::optional<Library *> /*owner_library*/,
67 ID *id_dst,
68 const ID *id_src,
69 const int /*flag*/)
70{
71 Curves *curves_dst = (Curves *)id_dst;
72 const Curves *curves_src = (const Curves *)id_src;
73 curves_dst->mat = static_cast<Material **>(MEM_dupallocN(curves_src->mat));
74
75 new (&curves_dst->geometry) blender::bke::CurvesGeometry(curves_src->geometry.wrap());
76
77 if (curves_src->surface_uv_map != nullptr) {
78 curves_dst->surface_uv_map = BLI_strdup(curves_src->surface_uv_map);
79 }
80
81 curves_dst->batch_cache = nullptr;
82}
83
84static void curves_free_data(ID *id)
85{
86 Curves *curves = (Curves *)id;
87 BKE_animdata_free(&curves->id, false);
88
89 curves->geometry.wrap().~CurvesGeometry();
90
92
93 MEM_SAFE_FREE(curves->mat);
94 MEM_SAFE_FREE(curves->surface_uv_map);
95}
96
98{
99 Curves *curves = (Curves *)id;
100 for (int i = 0; i < curves->totcol; i++) {
102 }
103 BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, curves->surface, IDWALK_CB_NOP);
104}
105
106static void curves_blend_write(BlendWriter *writer, ID *id, const void *id_address)
107{
108 Curves *curves = (Curves *)id;
109
110 /* Only for forward compatibility. */
111 curves->attributes_active_index_legacy = curves->geometry.attributes_active_index;
112
114 curves->geometry.wrap().blend_write_prepare();
115
116 /* Write LibData */
117 BLO_write_id_struct(writer, Curves, id_address, &curves->id);
118 BKE_id_blend_write(writer, &curves->id);
119
120 /* Direct data */
121 curves->geometry.wrap().blend_write(*writer, curves->id, write_data);
122
123 BLO_write_string(writer, curves->surface_uv_map);
124
125 BLO_write_pointer_array(writer, curves->totcol, curves->mat);
126}
127
129{
130 Curves *curves = (Curves *)id;
131
132 /* Geometry */
133 curves->geometry.wrap().blend_read(*reader);
134
135 BLO_read_string(reader, &curves->surface_uv_map);
136
137 /* Materials */
138 BLO_read_pointer_array(reader, curves->totcol, (void **)&curves->mat);
139}
140
142 /*id_code*/ ID_CV,
143 /*id_filter*/ FILTER_ID_CV,
144 /*dependencies_id_types*/ FILTER_ID_MA | FILTER_ID_OB,
145 /*main_listbase_index*/ INDEX_ID_CV,
146 /*struct_size*/ sizeof(Curves),
147 /*name*/ "Curves",
148 /*name_plural*/ N_("hair_curves"),
149 /*translation_context*/ BLT_I18NCONTEXT_ID_CURVES,
151 /*asset_type_info*/ nullptr,
152
153 /*init_data*/ curves_init_data,
154 /*copy_data*/ curves_copy_data,
155 /*free_data*/ curves_free_data,
156 /*make_local*/ nullptr,
157 /*foreach_id*/ curves_foreach_id,
158 /*foreach_cache*/ nullptr,
159 /*foreach_path*/ nullptr,
160 /*owner_pointer_get*/ nullptr,
161
162 /*blend_write*/ curves_blend_write,
163 /*blend_read_data*/ curves_blend_read_data,
164 /*blend_read_after_liblink*/ nullptr,
165
166 /*blend_read_undo_preserve*/ nullptr,
167
168 /*lib_override_apply_post*/ nullptr,
169};
170
171void *BKE_curves_add(Main *bmain, const char *name)
172{
173 Curves *curves = static_cast<Curves *>(BKE_id_new(bmain, ID_CV, name));
174
175 return curves;
176}
177
178bool BKE_curves_attribute_required(const Curves * /*curves*/, const char *name)
179{
180 return STREQ(name, ATTR_POSITION);
181}
182
184{
185 return reinterpret_cast<Curves *>(
186 BKE_id_copy_ex(nullptr, &curves_src->id, nullptr, LIB_ID_COPY_LOCALIZE));
187}
188
190 Scene *scene,
191 Object *object,
192 blender::bke::GeometrySet &geometry_set)
193{
194 /* Modifier evaluation modes. */
195 const bool use_render = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER);
196 int required_mode = use_render ? eModifierMode_Render : eModifierMode_Realtime;
197 if (BKE_object_is_in_editmode(object)) {
198 required_mode = (ModifierMode)(int(required_mode) | eModifierMode_Editmode);
199 }
200 ModifierApplyFlag apply_flag = use_render ? MOD_APPLY_RENDER : MOD_APPLY_USECACHE;
201 const ModifierEvalContext mectx = {depsgraph, object, apply_flag};
202
204
205 /* Get effective list of modifiers to execute. Some effects like shape keys
206 * are added as virtual modifiers before the user created modifiers. */
207 VirtualModifierData virtual_modifier_data;
208 ModifierData *md = BKE_modifiers_get_virtual_modifierlist(object, &virtual_modifier_data);
209
210 /* Evaluate modifiers. */
211 for (; md; md = md->next) {
212 const ModifierTypeInfo *mti = BKE_modifier_get_info(static_cast<ModifierType>(md->type));
213
214 if (!BKE_modifier_is_enabled(scene, md, required_mode)) {
215 continue;
216 }
217
218 blender::bke::ScopedModifierTimer modifier_timer{*md};
219
220 if (mti->modify_geometry_set != nullptr) {
221 mti->modify_geometry_set(md, &mectx, &geometry_set);
222 }
223 }
224}
225
226void BKE_curves_data_update(Depsgraph *depsgraph, Scene *scene, Object *object)
227{
228 using namespace blender;
229 using namespace blender::bke;
230 /* Free any evaluated data and restore original data. */
232
233 /* Evaluate modifiers. */
234 Curves *curves = static_cast<Curves *>(object->data);
235 GeometrySet geometry_set = GeometrySet::from_curves(curves, GeometryOwnershipType::ReadOnly);
236 if (object->mode == OB_MODE_SCULPT_CURVES) {
237 /* Try to propagate deformation data through modifier evaluation, so that sculpt mode can work
238 * on evaluated curves. */
239 GeometryComponentEditData &edit_component =
241 edit_component.curves_edit_hints_ = std::make_unique<CurvesEditHints>(
242 *static_cast<const Curves *>(DEG_get_original_object(object)->data));
243 }
244 curves_evaluate_modifiers(depsgraph, scene, object, geometry_set);
245
246 /* Assign evaluated object. */
247 Curves *curves_eval = const_cast<Curves *>(geometry_set.get_curves());
248 if (curves_eval == nullptr) {
249 curves_eval = curves_new_nomain(0, 0);
250 BKE_object_eval_assign_data(object, &curves_eval->id, true);
251 }
252 else {
253 BKE_object_eval_assign_data(object, &curves_eval->id, false);
254 }
255 object->runtime->geometry_set_eval = new GeometrySet(std::move(geometry_set));
256}
257
258/* Draw Cache */
259
260void (*BKE_curves_batch_cache_dirty_tag_cb)(Curves *curves, int mode) = nullptr;
261void (*BKE_curves_batch_cache_free_cb)(Curves *curves) = nullptr;
262
264{
265 if (curves->batch_cache) {
267 }
268}
269
271{
272 if (curves->batch_cache) {
274 }
275}
276
277namespace blender::bke {
278
279Curves *curves_new_nomain(const int points_num, const int curves_num)
280{
281 BLI_assert(points_num >= 0);
282 BLI_assert(curves_num >= 0);
283 Curves *curves_id = static_cast<Curves *>(BKE_id_new_nomain(ID_CV, nullptr));
284 CurvesGeometry &curves = curves_id->geometry.wrap();
285 curves.resize(points_num, curves_num);
286 return curves_id;
287}
288
289Curves *curves_new_nomain_single(const int points_num, const CurveType type)
290{
291 Curves *curves_id = curves_new_nomain(points_num, 1);
292 CurvesGeometry &curves = curves_id->geometry.wrap();
293 curves.offsets_for_write().last() = points_num;
294 curves.fill_curve_types(type);
295 return curves_id;
296}
297
299{
300 Curves *curves_id = static_cast<Curves *>(BKE_id_new_nomain(ID_CV, nullptr));
301 curves_id->geometry.wrap() = std::move(curves);
302 return curves_id;
303}
304
306{
307 dst.flag = src.flag;
308 MEM_SAFE_FREE(dst.mat);
309 dst.mat = static_cast<Material **>(MEM_malloc_arrayN(src.totcol, sizeof(Material *), __func__));
310 dst.totcol = src.totcol;
311 MutableSpan(dst.mat, dst.totcol).copy_from(Span(src.mat, src.totcol));
312 dst.symmetry = src.symmetry;
314 dst.surface = src.surface;
316 if (src.surface_uv_map != nullptr) {
318 }
319}
320
322{
323 this->curves_to_world = curves_ob.object_to_world();
325
326 if (surface_ob != nullptr) {
327 this->surface_to_world = surface_ob->object_to_world();
332 }
333}
334
336{
337 const int point_num = this->curves_id_orig.geometry.point_num;
338 if (this->positions().has_value()) {
339 if (this->positions()->size() != point_num) {
340 return false;
341 }
342 }
343 if (this->deform_mats.has_value()) {
344 if (this->deform_mats->size() != point_num) {
345 return false;
346 }
347 }
348 return true;
349}
350
351std::optional<Span<float3>> CurvesEditHints::positions() const
352{
353 if (!this->positions_data.has_value()) {
354 return std::nullopt;
355 }
356 const int points_num = this->curves_id_orig.geometry.wrap().points_num();
357 return Span(static_cast<const float3 *>(this->positions_data.data), points_num);
358}
359
360std::optional<MutableSpan<float3>> CurvesEditHints::positions_for_write()
361{
362 if (!this->positions_data.has_value()) {
363 return std::nullopt;
364 }
365
366 const int points_num = this->curves_id_orig.geometry.wrap().points_num();
368 if (data.sharing_info->is_mutable()) {
369 data.sharing_info->tag_ensured_mutable();
370 }
371 else {
372 auto *new_sharing_info = new ImplicitSharedValue<Array<float3>>(*this->positions());
373 data.sharing_info = ImplicitSharingPtr<>(new_sharing_info);
374 data.data = new_sharing_info->data.data();
375 }
376
377 return MutableSpan(const_cast<float3 *>(static_cast<const float3 *>(data.data)), points_num);
378}
379
381{
382 const bke::CurvesFieldContext context(curves, AttrDomain::Point);
383 fn::FieldEvaluator evaluator(context, curves.points_num());
384 fn::Field<float3> field(std::make_shared<bke::NormalFieldInput>());
385 evaluator.add_with_destination(std::move(field), normals);
386 evaluator.evaluate();
387}
388
389} // namespace blender::bke
void BKE_animdata_free(ID *id, bool do_id_user)
Definition anim_data.cc:263
Low-level operations for curves.
@ IDTYPE_FLAGS_APPEND_IS_REUSABLE
Definition BKE_idtype.hh:39
@ LIB_ID_COPY_LOCALIZE
ID * BKE_id_copy_ex(Main *bmain, const ID *id, ID **new_id_p, int flag)
Definition lib_id.cc:760
void * BKE_id_new(Main *bmain, short type, const char *name)
Definition lib_id.cc:1482
void * BKE_id_new_nomain(short type, const char *name)
Definition lib_id.cc:1487
void BKE_id_blend_write(BlendWriter *writer, ID *id)
Definition lib_id.cc:2560
#define BKE_LIB_FOREACHID_PROCESS_IDSUPER(data_, id_super_, cb_flag_)
@ IDWALK_CB_USER
@ IDWALK_CB_NOP
void BKE_modifiers_clear_errors(Object *ob)
bool BKE_modifier_is_enabled(const Scene *scene, ModifierData *md, int required_mode)
const ModifierTypeInfo * BKE_modifier_get_info(ModifierType type)
ModifierData * BKE_modifiers_get_virtual_modifierlist(const Object *ob, VirtualModifierData *data)
ModifierApplyFlag
@ MOD_APPLY_USECACHE
@ MOD_APPLY_RENDER
General operations, lookup, etc. for blender objects.
bool BKE_object_is_in_editmode(const Object *ob)
void BKE_object_eval_assign_data(Object *object, ID *data, bool is_owned)
void BKE_object_free_derived_caches(Object *ob)
#define BLI_assert(a)
Definition BLI_assert.h:50
char * BLI_strdup(const char *str) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC
Definition string.c:40
#define MEMCMP_STRUCT_AFTER_IS_ZERO(struct_var, member)
#define MEMCPY_STRUCT_AFTER(struct_dst, struct_src, member)
#define STREQ(a, b)
#define BLO_write_id_struct(writer, struct_name, id_address, id)
void BLO_read_string(BlendDataReader *reader, char **ptr_p)
Definition readfile.cc:4992
void BLO_write_string(BlendWriter *writer, const char *data_ptr)
void BLO_read_pointer_array(BlendDataReader *reader, int array_size, void **ptr_p)
Definition readfile.cc:5052
void BLO_write_pointer_array(BlendWriter *writer, uint num, const void *data_ptr)
#define BLT_I18NCONTEXT_ID_CURVES
@ DAG_EVAL_RENDER
eEvaluationMode DEG_get_mode(const Depsgraph *graph)
Object * DEG_get_original_object(Object *object)
#define FILTER_ID_OB
Definition DNA_ID.h:1181
#define FILTER_ID_MA
Definition DNA_ID.h:1175
#define FILTER_ID_CV
Definition DNA_ID.h:1195
@ INDEX_ID_CV
Definition DNA_ID.h:1296
@ ID_CV
CurveType
struct Curves Curves
#define DNA_struct_default_get(struct_name)
@ eModifierMode_Render
@ eModifierMode_Editmode
@ eModifierMode_Realtime
@ OB_MODE_SCULPT_CURVES
Object is a sort of wrapper for general info.
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
void BKE_curves_data_update(Depsgraph *depsgraph, Scene *scene, Object *object)
void BKE_curves_batch_cache_dirty_tag(Curves *curves, int mode)
void * BKE_curves_add(Main *bmain, const char *name)
static void curves_copy_data(Main *, std::optional< Library * >, ID *id_dst, const ID *id_src, const int)
bool BKE_curves_attribute_required(const Curves *, const char *name)
static void curves_blend_read_data(BlendDataReader *reader, ID *id)
static const char * ATTR_POSITION
static void curves_init_data(ID *id)
static void curves_foreach_id(ID *id, LibraryForeachIDData *data)
void(* BKE_curves_batch_cache_free_cb)(Curves *curves)
void BKE_curves_batch_cache_free(Curves *curves)
Curves * BKE_curves_copy_for_eval(const Curves *curves_src)
static void curves_evaluate_modifiers(Depsgraph *depsgraph, Scene *scene, Object *object, blender::bke::GeometrySet &geometry_set)
static void curves_blend_write(BlendWriter *writer, ID *id, const void *id_address)
void(* BKE_curves_batch_cache_dirty_tag_cb)(Curves *curves, int mode)
IDTypeInfo IDType_ID_CV
static void curves_free_data(ID *id)
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
constexpr void copy_from(Span< T > values) const
Definition BLI_span.hh:726
constexpr T & last(const int64_t n=0) const
Definition BLI_span.hh:690
std::optional< MutableSpan< float3 > > positions_for_write()
ImplicitSharingPtrAndData positions_data
std::optional< Span< float3 > > positions() const
std::optional< Array< float3x3 > > deform_mats
void resize(int points_num, int curves_num)
MutableSpan< int > offsets_for_write()
std::unique_ptr< CurvesEditHints > curves_edit_hints_
int add_with_destination(GField field, GVMutableArray dst)
Definition field.cc:743
const Depsgraph * depsgraph
void *(* MEM_malloc_arrayN)(size_t len, size_t size, const char *str)
Definition mallocn.cc:45
void *(* MEM_dupallocN)(const void *vmemh)
Definition mallocn.cc:39
void curves_copy_parameters(const Curves &src, Curves &dst)
Curves * curves_new_nomain_single(int points_num, CurveType type)
Curves * curves_new_nomain(int points_num, int curves_num)
void curves_normals_point_domain_calc(const CurvesGeometry &curves, MutableSpan< float3 > normals)
MatBase< T, NumCol, NumRow > transpose(const MatBase< T, NumRow, NumCol > &mat)
CartesianBasis invert(const CartesianBasis &basis)
CurvesGeometry geometry
char selection_domain
void * batch_cache
int attributes_active_index_legacy
struct Object * surface
struct Material ** mat
char * surface_uv_map
Definition DNA_ID.h:413
struct ModifierData * next
void(* modify_geometry_set)(ModifierData *md, const ModifierEvalContext *ctx, blender::bke::GeometrySet *geometry_set)
GeometryComponent & get_component_for_write(GeometryComponent::Type component_type)
const Curves * get_curves() const
#define N_(msgid)