Blender V5.0
MOD_build.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2005 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include "MEM_guardedalloc.h"
10
11#include "BLI_utildefines.h"
12
13#include "BLI_ghash.h"
14#include "BLI_math_vector.h"
15#include "BLI_rand.h"
16
17#include "BLT_translation.hh"
18
19#include "DNA_defaults.h"
20#include "DNA_mesh_types.h"
21#include "DNA_screen_types.h"
22
24
25#include "BKE_customdata.hh"
26#include "BKE_mesh.hh"
27#include "BKE_modifier.hh"
28#include "BKE_scene.hh"
29
31#include "UI_resources.hh"
32
33#include "RNA_access.hh"
34#include "RNA_prototypes.hh"
35
36#include "MOD_ui_common.hh"
37
46
47static bool depends_on_time(Scene * /*scene*/, ModifierData * /*md*/)
48{
49 return true;
50}
51
52static Mesh *modify_mesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
53{
54 Mesh *result;
56 int i, j, k;
57 int faces_dst_num, edges_dst_num, loops_dst_num = 0;
58 float frac;
59 GHashIterator gh_iter;
60 /* maps vert indices in old mesh to indices in new mesh */
61 GHash *vertHash = BLI_ghash_int_new("build ve apply gh");
62 /* maps edge indices in new mesh to indices in old mesh */
63 GHash *edgeHash = BLI_ghash_int_new("build ed apply gh");
64 /* maps edge indices in old mesh to indices in new mesh */
65 GHash *edgeHash2 = BLI_ghash_int_new("build ed apply gh");
66
67 const int vert_src_num = mesh->verts_num;
68 const blender::Span<blender::int2> edges_src = mesh->edges();
69 const blender::OffsetIndices faces_src = mesh->faces();
70 const blender::Span<int> corner_verts_src = mesh->corner_verts();
71 const blender::Span<int> corner_edges_src = mesh->corner_edges();
72
73 int *vertMap = MEM_malloc_arrayN<int>(size_t(vert_src_num), __func__);
74 int *edgeMap = MEM_malloc_arrayN<int>(size_t(edges_src.size()), __func__);
75 int *faceMap = MEM_malloc_arrayN<int>(size_t(faces_src.size()), __func__);
76
77 range_vn_i(vertMap, vert_src_num, 0);
78 range_vn_i(edgeMap, edges_src.size(), 0);
79 range_vn_i(faceMap, faces_src.size(), 0);
80
81 Scene *scene = DEG_get_input_scene(ctx->depsgraph);
82 frac = (BKE_scene_ctime_get(scene) - bmd->start) / bmd->length;
83 CLAMP(frac, 0.0f, 1.0f);
84 if (bmd->flag & MOD_BUILD_FLAG_REVERSE) {
85 frac = 1.0f - frac;
86 }
87
88 faces_dst_num = faces_src.size() * frac;
89 edges_dst_num = edges_src.size() * frac;
90
91 /* if there's at least one face, build based on faces */
92 if (faces_dst_num) {
93 uintptr_t hash_num, hash_num_alt;
94
95 if (bmd->flag & MOD_BUILD_FLAG_RANDOMIZE) {
96 BLI_array_randomize(faceMap, sizeof(*faceMap), faces_src.size(), bmd->seed);
97 }
98
99 /* get the set of all vert indices that will be in the final mesh,
100 * mapped to the new indices
101 */
102 hash_num = 0;
103 for (i = 0; i < faces_dst_num; i++) {
104 const blender::IndexRange face = faces_src[faceMap[i]];
105 for (j = 0; j < face.size(); j++) {
106 const int vert_i = corner_verts_src[face[j]];
107 void **val_p;
108 if (!BLI_ghash_ensure_p(vertHash, POINTER_FROM_INT(vert_i), &val_p)) {
109 *val_p = (void *)hash_num;
110 hash_num++;
111 }
112 }
113
114 loops_dst_num += face.size();
115 }
116 BLI_assert(hash_num == BLI_ghash_len(vertHash));
117
118 /* get the set of edges that will be in the new mesh (i.e. all edges
119 * that have both verts in the new mesh)
120 */
121 hash_num = 0;
122 hash_num_alt = 0;
123 for (i = 0; i < edges_src.size(); i++, hash_num_alt++) {
124 const blender::int2 &edge = edges_src[i];
125
126 if (BLI_ghash_haskey(vertHash, POINTER_FROM_INT(edge[0])) &&
127 BLI_ghash_haskey(vertHash, POINTER_FROM_INT(edge[1])))
128 {
129 BLI_ghash_insert(edgeHash, (void *)hash_num, (void *)hash_num_alt);
130 BLI_ghash_insert(edgeHash2, (void *)hash_num_alt, (void *)hash_num);
131 hash_num++;
132 }
133 }
134 BLI_assert(hash_num == BLI_ghash_len(edgeHash));
135 }
136 else if (edges_dst_num) {
137 uintptr_t hash_num;
138
139 if (bmd->flag & MOD_BUILD_FLAG_RANDOMIZE) {
140 BLI_array_randomize(edgeMap, sizeof(*edgeMap), edges_src.size(), bmd->seed);
141 }
142
143 /* get the set of all vert indices that will be in the final mesh,
144 * mapped to the new indices
145 */
146 const blender::int2 *edges = edges_src.data();
147 hash_num = 0;
148 BLI_assert(hash_num == BLI_ghash_len(vertHash));
149 for (i = 0; i < edges_dst_num; i++) {
150 void **val_p;
151 const blender::int2 &edge = edges[edgeMap[i]];
152
153 if (!BLI_ghash_ensure_p(vertHash, POINTER_FROM_INT(edge[0]), &val_p)) {
154 *val_p = (void *)hash_num;
155 hash_num++;
156 }
157 if (!BLI_ghash_ensure_p(vertHash, POINTER_FROM_INT(edge[1]), &val_p)) {
158 *val_p = (void *)hash_num;
159 hash_num++;
160 }
161 }
162 BLI_assert(hash_num == BLI_ghash_len(vertHash));
163
164 /* get the set of edges that will be in the new mesh */
165 for (i = 0; i < edges_dst_num; i++) {
166 j = BLI_ghash_len(edgeHash);
167
168 BLI_ghash_insert(edgeHash, POINTER_FROM_INT(j), POINTER_FROM_INT(edgeMap[i]));
169 BLI_ghash_insert(edgeHash2, POINTER_FROM_INT(edgeMap[i]), POINTER_FROM_INT(j));
170 }
171 }
172 else {
173 int verts_num = vert_src_num * frac;
174
175 if (bmd->flag & MOD_BUILD_FLAG_RANDOMIZE) {
176 BLI_array_randomize(vertMap, sizeof(*vertMap), vert_src_num, bmd->seed);
177 }
178
179 /* get the set of all vert indices that will be in the final mesh,
180 * mapped to the new indices
181 */
182 for (i = 0; i < verts_num; i++) {
184 }
185 }
186
187 /* now we know the number of verts, edges and faces, we can create the mesh. */
189 mesh, BLI_ghash_len(vertHash), BLI_ghash_len(edgeHash), faces_dst_num, loops_dst_num);
190 blender::MutableSpan<blender::int2> result_edges = result->edges_for_write();
191 blender::MutableSpan<int> result_face_offsets = result->face_offsets_for_write();
192 blender::MutableSpan<int> result_corner_verts = result->corner_verts_for_write();
193 blender::MutableSpan<int> result_corner_edges = result->corner_edges_for_write();
194
195 /* copy the vertices across */
196 GHASH_ITER (gh_iter, vertHash) {
197 int oldIndex = POINTER_AS_INT(BLI_ghashIterator_getKey(&gh_iter));
198 int newIndex = POINTER_AS_INT(BLI_ghashIterator_getValue(&gh_iter));
199 CustomData_copy_data(&mesh->vert_data, &result->vert_data, oldIndex, newIndex, 1);
200 }
201
202 /* copy the edges across, remapping indices */
203 for (i = 0; i < BLI_ghash_len(edgeHash); i++) {
204 blender::int2 source;
205 blender::int2 *dest;
206 int oldIndex = POINTER_AS_INT(BLI_ghash_lookup(edgeHash, POINTER_FROM_INT(i)));
207
208 source = edges_src[oldIndex];
209 dest = &result_edges[i];
210
211 source[0] = POINTER_AS_INT(BLI_ghash_lookup(vertHash, POINTER_FROM_INT(source[0])));
212 source[1] = POINTER_AS_INT(BLI_ghash_lookup(vertHash, POINTER_FROM_INT(source[1])));
213
214 CustomData_copy_data(&mesh->edge_data, &result->edge_data, oldIndex, i, 1);
215 *dest = source;
216 }
217
218 /* copy the faces across, remapping indices */
219 k = 0;
220 for (i = 0; i < faces_dst_num; i++) {
221 const blender::IndexRange src_face = faces_src[faceMap[i]];
222 result_face_offsets[i] = k;
223
224 CustomData_copy_data(&mesh->face_data, &result->face_data, faceMap[i], i, 1);
225
227 &mesh->corner_data, &result->corner_data, src_face.start(), k, src_face.size());
228
229 for (j = 0; j < src_face.size(); j++, k++) {
230 const int vert_src = corner_verts_src[src_face[j]];
231 const int edge_src = corner_edges_src[src_face[j]];
232 result_corner_verts[k] = POINTER_AS_INT(
233 BLI_ghash_lookup(vertHash, POINTER_FROM_INT(vert_src)));
234 result_corner_edges[k] = POINTER_AS_INT(
235 BLI_ghash_lookup(edgeHash2, POINTER_FROM_INT(edge_src)));
236 }
237 }
238
239 BLI_ghash_free(vertHash, nullptr, nullptr);
240 BLI_ghash_free(edgeHash, nullptr, nullptr);
241 BLI_ghash_free(edgeHash2, nullptr, nullptr);
242
243 MEM_freeN(vertMap);
244 MEM_freeN(edgeMap);
246
247 /* TODO(sybren): also copy flags & tags? */
248 return result;
249}
250
251static void panel_draw(const bContext * /*C*/, Panel *panel)
252{
253 uiLayout *layout = panel->layout;
254
256
257 layout->use_property_split_set(true);
258
259 layout->prop(ptr, "frame_start", UI_ITEM_NONE, std::nullopt, ICON_NONE);
260 layout->prop(ptr, "frame_duration", UI_ITEM_NONE, std::nullopt, ICON_NONE);
261 layout->prop(ptr, "use_reverse", UI_ITEM_NONE, std::nullopt, ICON_NONE);
262
264}
265
266static void random_panel_header_draw(const bContext * /*C*/, Panel *panel)
267{
268 uiLayout *layout = panel->layout;
269
271
272 layout->prop(ptr, "use_random_order", UI_ITEM_NONE, std::nullopt, ICON_NONE);
273}
274
275static void random_panel_draw(const bContext * /*C*/, Panel *panel)
276{
277 uiLayout *layout = panel->layout;
278
280
281 layout->use_property_split_set(true);
282
283 layout->active_set(RNA_boolean_get(ptr, "use_random_order"));
284 layout->prop(ptr, "seed", UI_ITEM_NONE, std::nullopt, ICON_NONE);
285}
286
287static void panel_register(ARegionType *region_type)
288{
291 region_type, "randomize", "", random_panel_header_draw, random_panel_draw, panel_type);
292}
293
295 /*idname*/ "Build",
296 /*name*/ N_("Build"),
297 /*struct_name*/ "BuildModifierData",
298 /*struct_size*/ sizeof(BuildModifierData),
299 /*srna*/ &RNA_BuildModifier,
302 /*icon*/ ICON_MOD_BUILD,
303
304 /*copy_data*/ BKE_modifier_copydata_generic,
305
306 /*deform_verts*/ nullptr,
307 /*deform_matrices*/ nullptr,
308 /*deform_verts_EM*/ nullptr,
309 /*deform_matrices_EM*/ nullptr,
310 /*modify_mesh*/ modify_mesh,
311 /*modify_geometry_set*/ nullptr,
312
313 /*init_data*/ init_data,
314 /*required_data_mask*/ nullptr,
315 /*free_data*/ nullptr,
316 /*is_disabled*/ nullptr,
317 /*update_depsgraph*/ nullptr,
318 /*depends_on_time*/ depends_on_time,
319 /*depends_on_normals*/ nullptr,
320 /*foreach_ID_link*/ nullptr,
321 /*foreach_tex_link*/ nullptr,
322 /*free_runtime_data*/ nullptr,
323 /*panel_register*/ panel_register,
324 /*blend_write*/ nullptr,
325 /*blend_read*/ nullptr,
326 /*foreach_cache*/ nullptr,
327 /*foreach_working_space_color*/ nullptr,
328};
CustomData interface, see also DNA_customdata_types.h.
void CustomData_copy_data(const CustomData *source, CustomData *dest, int source_index, int dest_index, int count)
Mesh * BKE_mesh_new_nomain_from_template(const Mesh *me_src, int verts_num, int edges_num, int faces_num, int corners_num)
void BKE_modifier_copydata_generic(const ModifierData *md, ModifierData *md_dst, int flag)
@ eModifierTypeFlag_AcceptsCVs
@ eModifierTypeFlag_AcceptsMesh
float BKE_scene_ctime_get(const Scene *scene)
Definition scene.cc:2370
#define BLI_assert(a)
Definition BLI_assert.h:46
BLI_INLINE void * BLI_ghashIterator_getKey(GHashIterator *ghi) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.h:295
bool BLI_ghash_haskey(const GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.cc:819
BLI_INLINE void * BLI_ghashIterator_getValue(GHashIterator *ghi) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.h:299
#define GHASH_ITER(gh_iter_, ghash_)
Definition BLI_ghash.h:318
unsigned int BLI_ghash_len(const GHash *gh) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.cc:702
void * BLI_ghash_lookup(const GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.cc:731
void BLI_ghash_insert(GHash *gh, void *key, void *val)
Definition BLI_ghash.cc:707
void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
Definition BLI_ghash.cc:860
GHash * BLI_ghash_int_new(const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
bool BLI_ghash_ensure_p(GHash *gh, void *key, void ***r_val) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.cc:752
void range_vn_i(int *array_tar, int size, int start)
Random number functions.
void BLI_array_randomize(void *data, unsigned int elem_size, unsigned int elem_num, unsigned int seed)
Definition rand.cc:156
#define CLAMP(a, b, c)
#define POINTER_FROM_INT(i)
#define POINTER_AS_INT(i)
#define MEMCMP_STRUCT_AFTER_IS_ZERO(struct_var, member)
#define MEMCPY_STRUCT_AFTER(struct_dst, struct_src, member)
Scene * DEG_get_input_scene(const Depsgraph *graph)
#define DNA_struct_default_get(struct_name)
@ eModifierType_Build
@ MOD_BUILD_FLAG_REVERSE
@ MOD_BUILD_FLAG_RANDOMIZE
Read Guarded memory(de)allocation.
static void init_data(ModifierData *md)
static void panel_register(ARegionType *region_type)
static void panel_draw(const bContext *, Panel *panel)
static Mesh * modify_mesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
Definition MOD_array.cc:862
static void init_data(ModifierData *md)
Definition MOD_build.cc:38
static void panel_register(ARegionType *region_type)
Definition MOD_build.cc:287
static void random_panel_draw(const bContext *, Panel *panel)
Definition MOD_build.cc:275
static Mesh * modify_mesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
Definition MOD_build.cc:52
ModifierTypeInfo modifierType_Build
Definition MOD_build.cc:294
static void random_panel_header_draw(const bContext *, Panel *panel)
Definition MOD_build.cc:266
static void panel_draw(const bContext *, Panel *panel)
Definition MOD_build.cc:251
static bool depends_on_time(Scene *, ModifierData *)
Definition MOD_build.cc:47
PanelType * modifier_subpanel_register(ARegionType *region_type, const char *name, const char *label, PanelDrawFn draw_header, PanelDrawFn draw, PanelType *parent)
PanelType * modifier_panel_register(ARegionType *region_type, ModifierType type, PanelDrawFn draw)
PointerRNA * modifier_panel_get_property_pointers(Panel *panel, PointerRNA *r_ob_ptr)
void modifier_error_message_draw(uiLayout *layout, PointerRNA *ptr)
#define UI_ITEM_NONE
constexpr int64_t size() const
constexpr int64_t start() const
constexpr const T * data() const
Definition BLI_span.hh:215
constexpr int64_t size() const
Definition BLI_span.hh:252
CCL_NAMESPACE_BEGIN ccl_device_inline float frac(const float x, ccl_private int *ix)
const int faceMap[6][4]
void * MEM_malloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:133
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
VecBase< int32_t, 2 > int2
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
CustomData edge_data
CustomData corner_data
CustomData face_data
CustomData vert_data
int verts_num
struct uiLayout * layout
void active_set(bool active)
void use_property_split_set(bool value)
void prop(PointerRNA *ptr, PropertyRNA *prop, int index, int value, eUI_Item_Flag flag, std::optional< blender::StringRef > name_opt, int icon, std::optional< blender::StringRef > placeholder=std::nullopt)
i
Definition text_draw.cc:230
#define N_(msgid)
PointerRNA * ptr
Definition wm_files.cc:4238