Blender  V3.3
MOD_particlesystem.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2005 Blender Foundation. All rights reserved. */
3 
8 #include <cstddef>
9 #include <cstring>
10 
11 #include "BLI_utildefines.h"
12 
13 #include "BLT_translation.h"
14 
15 #include "DNA_defaults.h"
16 #include "DNA_material_types.h"
17 #include "DNA_mesh_types.h"
18 #include "DNA_screen_types.h"
19 
20 #include "BKE_context.h"
21 #include "BKE_editmesh.h"
22 #include "BKE_lib_id.h"
23 #include "BKE_mesh.h"
25 #include "BKE_modifier.h"
26 #include "BKE_particle.h"
27 #include "BKE_screen.h"
28 
29 #include "UI_interface.h"
30 #include "UI_resources.h"
31 
32 #include "RNA_access.h"
33 #include "RNA_prototypes.h"
34 
35 #include "DEG_depsgraph_query.h"
36 
37 #include "BLO_read_write.h"
38 
39 #include "MOD_ui_common.h"
40 #include "MOD_util.h"
41 
42 static void initData(ModifierData *md)
43 {
45 
46  BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(psmd, modifier));
47 
49 }
50 static void freeData(ModifierData *md)
51 {
53 
54  if (psmd->mesh_final) {
55  BKE_id_free(nullptr, psmd->mesh_final);
56  psmd->mesh_final = nullptr;
57  if (psmd->mesh_original) {
58  BKE_id_free(nullptr, psmd->mesh_original);
59  psmd->mesh_original = nullptr;
60  }
61  }
62  psmd->totdmvert = psmd->totdmedge = psmd->totdmface = 0;
63 
64  /* ED_object_modifier_remove may have freed this first before calling
65  * BKE_modifier_free (which calls this function) */
66  if (psmd->psys) {
67  psmd->psys->flag |= PSYS_DELETE;
68  }
69 }
70 
71 static void copyData(const ModifierData *md, ModifierData *target, const int flag)
72 {
73 #if 0
75 #endif
77 
78  BKE_modifier_copydata_generic(md, target, flag);
79 
80  /* NOTE: `psys` pointer here is just copied over from `md` to `target`. This is dangerous, as it
81  * will generate invalid data in case we are copying between different objects. Extra external
82  * code has to be called then to ensure proper remapping of that pointer. See e.g.
83  * `BKE_object_copy_particlesystems` or `BKE_object_copy_modifier`. */
84 
85  tpsmd->mesh_final = nullptr;
86  tpsmd->mesh_original = nullptr;
87  tpsmd->totdmvert = tpsmd->totdmedge = tpsmd->totdmface = 0;
88 }
89 
90 static void requiredDataMask(Object *UNUSED(ob),
91  ModifierData *md,
92  CustomData_MeshMasks *r_cddata_masks)
93 {
95 
96  psys_emitter_customdata_mask(psmd->psys, r_cddata_masks);
97 }
98 
99 /* saves the current emitter state for a particle system and calculates particles */
100 static void deformVerts(ModifierData *md,
101  const ModifierEvalContext *ctx,
102  Mesh *mesh,
103  float (*vertexCos)[3],
104  int verts_num)
105 {
106  Mesh *mesh_src = mesh;
108  ParticleSystem *psys = nullptr;
109 
110  if (ctx->object->particlesystem.first) {
111  psys = psmd->psys;
112  }
113  else {
114  return;
115  }
116 
117  if (!psys_check_enabled(ctx->object, psys, (ctx->flag & MOD_APPLY_RENDER) != 0)) {
118  return;
119  }
120 
121  if (mesh_src == nullptr) {
122  mesh_src = MOD_deform_mesh_eval_get(
123  ctx->object, nullptr, nullptr, vertexCos, verts_num, false, true);
124  if (mesh_src == nullptr) {
125  return;
126  }
127  }
128 
129  /* clear old dm */
130  bool had_mesh_final = (psmd->mesh_final != nullptr);
131  if (psmd->mesh_final) {
132  BKE_id_free(nullptr, psmd->mesh_final);
133  psmd->mesh_final = nullptr;
134  if (psmd->mesh_original) {
135  BKE_id_free(nullptr, psmd->mesh_original);
136  psmd->mesh_original = nullptr;
137  }
138  }
139  else if (psmd->flag & eParticleSystemFlag_file_loaded) {
140  /* in file read mesh just wasn't saved in file so no need to reset everything */
142  if (psys->particles == nullptr) {
143  psys->recalc |= ID_RECALC_PSYS_RESET;
144  }
145  /* TODO(sergey): This is not how particles were working prior to copy on
146  * write, but now evaluation is similar to case when one duplicates the
147  * object. In that case particles were doing reset here.
148  *
149  * Don't do reset when entering particle edit mode, as that will destroy the edit mode data.
150  * Shouldn't be an issue, since particles are supposed to be evaluated once prior to entering
151  * edit mode anyway.
152  * Could in theory be an issue when everything is done in a script, but then solution is
153  * not known to me. */
154  if (ctx->object->mode != OB_MODE_PARTICLE_EDIT) {
155  psys->recalc |= ID_RECALC_PSYS_RESET;
156  }
157  }
158 
159  /* make new mesh */
160  psmd->mesh_final = BKE_mesh_copy_for_eval(mesh_src, false);
161  BKE_mesh_vert_coords_apply(psmd->mesh_final, vertexCos);
162 
164 
165  if (!psmd->mesh_final->runtime.deformed_only) {
166  /* Get the original mesh from the object, this is what the particles
167  * are attached to so in case of non-deform modifiers we need to remap
168  * them to the final mesh (typically subdivision surfaces). */
169  Mesh *mesh_original = nullptr;
170 
171  if (ctx->object->type == OB_MESH) {
173 
174  if (em) {
175  /* In edit mode get directly from the edit mesh. */
177  }
178  else {
179  /* Otherwise get regular mesh. */
180  mesh_original = static_cast<Mesh *>(ctx->object->data);
181  }
182  }
183  else {
184  mesh_original = mesh_src;
185  }
186 
187  if (mesh_original) {
188  /* Make a persistent copy of the mesh. We don't actually need
189  * all this data, just some topology for remapping. Could be
190  * optimized once. */
191  psmd->mesh_original = BKE_mesh_copy_for_eval(mesh_original, false);
192  }
193 
195  }
196 
197  if (!ELEM(mesh_src, nullptr, mesh, psmd->mesh_final)) {
198  BKE_id_free(nullptr, mesh_src);
199  }
200 
201  /* Report change in mesh structure.
202  * This is an unreliable check for the topology check, but allows some
203  * handy configuration like emitting particles from inside particle
204  * instance. */
205  if (had_mesh_final && (psmd->mesh_final->totvert != psmd->totdmvert ||
206  psmd->mesh_final->totedge != psmd->totdmedge ||
207  psmd->mesh_final->totface != psmd->totdmface)) {
208  psys->recalc |= ID_RECALC_PSYS_RESET;
209  }
210  psmd->totdmvert = psmd->mesh_final->totvert;
211  psmd->totdmedge = psmd->mesh_final->totedge;
212  psmd->totdmface = psmd->mesh_final->totface;
213 
214  {
218  ctx->depsgraph, scene, ctx->object, psys, (ctx->flag & MOD_APPLY_RENDER) != 0);
220  }
221 
222  if (DEG_is_active(ctx->depsgraph)) {
223  Object *object_orig = DEG_get_original_object(ctx->object);
224  ModifierData *md_orig = BKE_modifiers_findby_name(object_orig, psmd->modifier.name);
225  BLI_assert(md_orig != nullptr);
227  psmd_orig->flag = psmd->flag;
228  }
229 }
230 
231 /* disabled particles in editmode for now, until support for proper evaluated mesh
232  * updates is coded */
233 #if 0
234 static void deformVertsEM(ModifierData *md,
235  Object *ob,
236  BMEditMesh *editData,
237  Mesh *mesh,
238  float (*vertexCos)[3],
239  int verts_num)
240 {
241  const bool do_temp_mesh = (mesh == nullptr);
242  if (do_temp_mesh) {
243  mesh = BKE_id_new_nomain(ID_ME, ((ID *)ob->data)->name);
244  BM_mesh_bm_to_me(nullptr, editData->bm, mesh, &((BMeshToMeshParams){0}));
245  }
246 
247  deformVerts(md, ob, mesh, vertexCos, verts_num);
248 
249  if (derivedData) {
250  BKE_id_free(nullptr, mesh);
251  }
252 }
253 #endif
254 
255 static void panel_draw(const bContext *UNUSED(C), Panel *panel)
256 {
257  uiLayout *layout = panel->layout;
258 
259  PointerRNA ob_ptr;
261 
262  Object *ob = static_cast<Object *>(ob_ptr.data);
263  ModifierData *md = (ModifierData *)ptr->data;
264  ParticleSystem *psys = ((ParticleSystemModifierData *)md)->psys;
265 
266  uiItemL(layout, TIP_("Settings are in the particle tab"), ICON_NONE);
267 
268  if (!(ob->mode & OB_MODE_PARTICLE_EDIT)) {
269  if (ELEM(psys->part->ren_as, PART_DRAW_GR, PART_DRAW_OB)) {
270  uiItemO(layout,
271  CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Make Instances Real"),
272  ICON_NONE,
273  "OBJECT_OT_duplicates_make_real");
274  }
275  else if (psys->part->ren_as == PART_DRAW_PATH) {
276  uiItemO(layout,
277  CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Convert to Mesh"),
278  ICON_NONE,
279  "OBJECT_OT_modifier_convert");
280  }
281  }
282 
283  modifier_panel_end(layout, ptr);
284 }
285 
286 static void panelRegister(ARegionType *region_type)
287 {
289 }
290 
291 static void blendRead(BlendDataReader *reader, ModifierData *md)
292 {
294 
295  psmd->mesh_final = nullptr;
296  psmd->mesh_original = nullptr;
297  /* This is written as part of ob->particlesystem. */
298  BLO_read_data_address(reader, &psmd->psys);
301 }
302 
304  /* name */ N_("ParticleSystem"),
305  /* structName */ "ParticleSystemModifierData",
306  /* structSize */ sizeof(ParticleSystemModifierData),
307  /* srna */ &RNA_ParticleSystemModifier,
308  /* type */ eModifierTypeType_OnlyDeform,
311 #if 0
313 #endif
314  ,
315  /* icon */ ICON_MOD_PARTICLES,
316 
317  /* copyData */ copyData,
318 
319  /* deformVerts */ deformVerts,
320  /* deformMatrices */ nullptr,
321  /* deformVertsEM */ nullptr,
322  /* deformMatricesEM */ nullptr,
323  /* modifyMesh */ nullptr,
324  /* modifyGeometrySet */ nullptr,
325 
326  /* initData */ initData,
327  /* requiredDataMask */ requiredDataMask,
328  /* freeData */ freeData,
329  /* isDisabled */ nullptr,
330  /* updateDepsgraph */ nullptr,
331  /* dependsOnTime */ nullptr,
332  /* dependsOnNormals */ nullptr,
333  /* foreachIDLink */ nullptr,
334  /* foreachTexLink */ nullptr,
335  /* freeRuntimeData */ nullptr,
336  /* panelRegister */ panelRegister,
337  /* blendWrite */ nullptr,
338  /* blendRead */ blendRead,
339 };
BMEditMesh * BKE_editmesh_from_object(struct Object *ob)
Return the BMEditMesh for a given object.
Definition: editmesh.c:58
void * BKE_id_new_nomain(short type, const char *name)
Definition: lib_id.c:1173
void BKE_id_free(struct Main *bmain, void *idv)
struct Mesh * BKE_mesh_copy_for_eval(const struct Mesh *source, bool reference)
void BKE_mesh_vert_coords_apply(struct Mesh *mesh, const float(*vert_coords)[3])
Definition: mesh.cc:1834
struct Mesh * BKE_mesh_from_bmesh_for_eval_nomain(struct BMesh *bm, const struct CustomData_MeshMasks *cd_mask_extra, const struct Mesh *me_settings)
void BKE_mesh_tessface_ensure(struct Mesh *mesh)
@ eModifierTypeFlag_UsesPointCache
Definition: BKE_modifier.h:90
@ eModifierTypeFlag_SupportsMapping
Definition: BKE_modifier.h:68
@ eModifierTypeFlag_EnableInEditmode
Definition: BKE_modifier.h:78
@ eModifierTypeFlag_SupportsEditmode
Definition: BKE_modifier.h:69
@ eModifierTypeFlag_AcceptsMesh
Definition: BKE_modifier.h:66
void BKE_modifier_copydata_generic(const struct ModifierData *md, struct ModifierData *md_dst, int flag)
@ eModifierTypeType_OnlyDeform
Definition: BKE_modifier.h:44
struct ModifierData * BKE_modifiers_findby_name(const struct Object *ob, const char *name)
@ MOD_APPLY_RENDER
Definition: BKE_modifier.h:115
bool psys_check_enabled(struct Object *ob, struct ParticleSystem *psys, bool use_render_params)
Definition: particle.c:801
void psys_emitter_customdata_mask(struct ParticleSystem *psys, struct CustomData_MeshMasks *r_cddata_masks)
Definition: particle.c:2283
void particle_system_update(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, struct ParticleSystem *psys, bool use_render_params)
#define BLI_assert(a)
Definition: BLI_assert.h:46
#define UNUSED(x)
#define ELEM(...)
#define MEMCMP_STRUCT_AFTER_IS_ZERO(struct_var, member)
#define MEMCPY_STRUCT_AFTER(struct_dst, struct_src, member)
#define BLO_read_data_address(reader, ptr_p)
#define TIP_(msgid)
#define CTX_IFACE_(context, msgid)
#define BLT_I18NCONTEXT_OPERATOR_DEFAULT
bool DEG_is_active(const struct Depsgraph *depsgraph)
Definition: depsgraph.cc:312
struct Object * DEG_get_original_object(struct Object *object)
struct Scene * DEG_get_evaluated_scene(const struct Depsgraph *graph)
@ ID_RECALC_PSYS_RESET
Definition: DNA_ID.h:800
@ ID_ME
Definition: DNA_ID_enums.h:48
#define DNA_struct_default_get(struct_name)
Definition: DNA_defaults.h:29
@ eParticleSystemFlag_psys_updated
@ eParticleSystemFlag_file_loaded
struct ParticleSystemModifierData ParticleSystemModifierData
@ eModifierType_ParticleSystem
@ OB_MODE_PARTICLE_EDIT
@ OB_MESH
#define PART_DRAW_PATH
#define PART_DRAW_OB
#define PSYS_DELETE
#define PART_DRAW_GR
static void deformVertsEM(ModifierData *md, const ModifierEvalContext *ctx, struct BMEditMesh *em, Mesh *mesh, float(*vertexCos)[3], int verts_num)
Definition: MOD_armature.c:155
static void copyData(const ModifierData *md, ModifierData *target, const int flag)
static void deformVerts(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh, float(*vertexCos)[3], int verts_num)
ModifierTypeInfo modifierType_ParticleSystem
static void blendRead(BlendDataReader *reader, ModifierData *md)
static void panel_draw(const bContext *UNUSED(C), Panel *panel)
static void initData(ModifierData *md)
static void panelRegister(ARegionType *region_type)
static void freeData(ModifierData *md)
static void requiredDataMask(Object *UNUSED(ob), ModifierData *md, CustomData_MeshMasks *r_cddata_masks)
PointerRNA * modifier_panel_get_property_pointers(Panel *panel, PointerRNA *r_ob_ptr)
void modifier_panel_end(uiLayout *layout, PointerRNA *ptr)
Definition: MOD_ui_common.c:91
PanelType * modifier_panel_register(ARegionType *region_type, ModifierType type, PanelDrawFn draw)
Mesh * MOD_deform_mesh_eval_get(Object *ob, struct BMEditMesh *em, Mesh *mesh, const float(*vertexCos)[3], const int verts_num, const bool use_normals, const bool use_orco)
Definition: MOD_util.c:167
#define C
Definition: RandGen.cpp:25
void uiItemL(uiLayout *layout, const char *name, int icon)
void uiItemO(uiLayout *layout, const char *name, int icon, const char *opname)
void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMeshParams *params)
Scene scene
struct BMesh * bm
Definition: BKE_editmesh.h:40
Definition: DNA_ID.h:368
void * first
Definition: DNA_listBase.h:31
int totedge
int totvert
int totface
Mesh_Runtime runtime
struct Depsgraph * depsgraph
Definition: BKE_modifier.h:140
ModifierApplyFlag flag
Definition: BKE_modifier.h:142
struct Object * object
Definition: BKE_modifier.h:141
ListBase particlesystem
void * data
struct uiLayout * layout
struct ParticleSystem * psys
ParticleData * particles
void * data
Definition: RNA_types.h:38
#define N_(msgid)
PointerRNA * ptr
Definition: wm_files.c:3480