Blender V4.3
MOD_particlesystem.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
9#include <cstddef>
10#include <cstring>
11
12#include "BLI_utildefines.h"
13
14#include "BLT_translation.hh"
15
16#include "DNA_defaults.h"
17#include "DNA_mesh_types.h"
18#include "DNA_screen_types.h"
19
20#include "BKE_editmesh.hh"
21#include "BKE_lib_id.hh"
22#include "BKE_mesh.hh"
24#include "BKE_modifier.hh"
25#include "BKE_particle.h"
26
27#include "UI_interface.hh"
28#include "UI_resources.hh"
29
30#include "RNA_prototypes.hh"
31
33
34#include "BLO_read_write.hh"
35
36#include "MOD_ui_common.hh"
37
46static void free_data(ModifierData *md)
47{
49
50 if (psmd->mesh_final) {
51 BKE_id_free(nullptr, psmd->mesh_final);
52 psmd->mesh_final = nullptr;
53 if (psmd->mesh_original) {
54 BKE_id_free(nullptr, psmd->mesh_original);
55 psmd->mesh_original = nullptr;
56 }
57 }
58 psmd->totdmvert = psmd->totdmedge = psmd->totdmface = 0;
59
60 /* blender::ed::object::modifier_remove may have freed this first before calling
61 * BKE_modifier_free (which calls this function) */
62 if (psmd->psys) {
63 psmd->psys->flag |= PSYS_DELETE;
64 }
65}
66
67static void copy_data(const ModifierData *md, ModifierData *target, const int flag)
68{
69#if 0
71#endif
73
75
76 /* NOTE: `psys` pointer here is just copied over from `md` to `target`. This is dangerous, as it
77 * will generate invalid data in case we are copying between different objects. Extra external
78 * code has to be called then to ensure proper remapping of that pointer. See e.g.
79 * `BKE_object_copy_particlesystems` or `BKE_object_copy_modifier`. */
80
81 tpsmd->mesh_final = nullptr;
82 tpsmd->mesh_original = nullptr;
83 tpsmd->totdmvert = tpsmd->totdmedge = tpsmd->totdmface = 0;
84}
85
86static void required_data_mask(ModifierData *md, CustomData_MeshMasks *r_cddata_masks)
87{
89
90 psys_emitter_customdata_mask(psmd->psys, r_cddata_masks);
91}
92
93/* saves the current emitter state for a particle system and calculates particles */
94static void deform_verts(ModifierData *md,
95 const ModifierEvalContext *ctx,
96 Mesh *mesh,
98{
100 ParticleSystem *psys = nullptr;
101
102 if (ctx->object->particlesystem.first) {
103 psys = psmd->psys;
104 }
105 else {
106 return;
107 }
108
109 if (!psys_check_enabled(ctx->object, psys, (ctx->flag & MOD_APPLY_RENDER) != 0)) {
110 return;
111 }
112
113 /* Clear old evaluated mesh. */
114 bool had_mesh_final = (psmd->mesh_final != nullptr);
115 if (psmd->mesh_final) {
116 BKE_id_free(nullptr, psmd->mesh_final);
117 psmd->mesh_final = nullptr;
118 if (psmd->mesh_original) {
119 BKE_id_free(nullptr, psmd->mesh_original);
120 psmd->mesh_original = nullptr;
121 }
122 }
123 else if (psmd->flag & eParticleSystemFlag_file_loaded) {
124 /* in file read mesh just wasn't saved in file so no need to reset everything */
125 psmd->flag &= ~eParticleSystemFlag_file_loaded;
126 if (psys->particles == nullptr) {
128 }
129 /* TODO(sergey): This is not how particles were working prior to copy on
130 * write, but now evaluation is similar to case when one duplicates the
131 * object. In that case particles were doing reset here.
132 *
133 * Don't do reset when entering particle edit mode, as that will destroy the edit mode data.
134 * Shouldn't be an issue, since particles are supposed to be evaluated once prior to entering
135 * edit mode anyway.
136 * Could in theory be an issue when everything is done in a script, but then solution is
137 * not known to me. */
138 if (ctx->object->mode != OB_MODE_PARTICLE_EDIT) {
140 }
141 }
142
143 /* make new mesh */
144 psmd->mesh_final = BKE_mesh_copy_for_eval(*mesh);
145 psmd->mesh_final->vert_positions_for_write().copy_from(positions);
146 psmd->mesh_final->tag_positions_changed();
147
149
150 if (!psmd->mesh_final->runtime->deformed_only) {
151 /* Get the original mesh from the object, this is what the particles
152 * are attached to so in case of non-deform modifiers we need to remap
153 * them to the final mesh (typically subdivision surfaces). */
154 Mesh *mesh_original = nullptr;
155
156 if (ctx->object->type == OB_MESH) {
158
159 if (em) {
160 /* In edit mode get directly from the edit mesh. */
161 psmd->mesh_original = BKE_mesh_from_bmesh_for_eval_nomain(em->bm, nullptr, mesh);
162 }
163 else {
164 /* Otherwise get regular mesh. */
165 mesh_original = static_cast<Mesh *>(ctx->object->data);
166 }
167 }
168 else {
169 mesh_original = mesh;
170 }
171
172 if (mesh_original) {
173 /* Make a persistent copy of the mesh. We don't actually need
174 * all this data, just some topology for remapping. Could be
175 * optimized once. */
176 psmd->mesh_original = BKE_mesh_copy_for_eval(*mesh_original);
177 }
178
180 }
181
182 /* Report change in mesh structure.
183 * This is an unreliable check for the topology check, but allows some
184 * handy configuration like emitting particles from inside particle
185 * instance. */
186 if (had_mesh_final && (psmd->mesh_final->verts_num != psmd->totdmvert ||
187 psmd->mesh_final->edges_num != psmd->totdmedge ||
188 psmd->mesh_final->totface_legacy != psmd->totdmface))
189 {
191 }
192 psmd->totdmvert = psmd->mesh_final->verts_num;
193 psmd->totdmedge = psmd->mesh_final->edges_num;
194 psmd->totdmface = psmd->mesh_final->totface_legacy;
195
196 {
198 psmd->flag &= ~eParticleSystemFlag_psys_updated;
200 ctx->depsgraph, scene, ctx->object, psys, (ctx->flag & MOD_APPLY_RENDER) != 0);
202 }
203
204 if (DEG_is_active(ctx->depsgraph)) {
205 Object *object_orig = DEG_get_original_object(ctx->object);
206 ModifierData *md_orig = BKE_modifiers_findby_name(object_orig, psmd->modifier.name);
207 BLI_assert(md_orig != nullptr);
209 psmd_orig->flag = psmd->flag;
210 }
211}
212
213static void panel_draw(const bContext * /*C*/, Panel *panel)
214{
215 uiLayout *layout = panel->layout;
216
217 PointerRNA ob_ptr;
219
220 Object *ob = static_cast<Object *>(ob_ptr.data);
222 ParticleSystem *psys = ((ParticleSystemModifierData *)md)->psys;
223
224 uiItemL(layout, RPT_("Settings are inside the Particles tab"), ICON_NONE);
225
226 if (!(ob->mode & OB_MODE_PARTICLE_EDIT)) {
227 if (ELEM(psys->part->ren_as, PART_DRAW_GR, PART_DRAW_OB)) {
228 uiItemO(layout,
229 CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Make Instances Real"),
230 ICON_NONE,
231 "OBJECT_OT_duplicates_make_real");
232 }
233 else if (psys->part->ren_as == PART_DRAW_PATH) {
234 uiItemO(layout,
236 ICON_NONE,
237 "OBJECT_OT_modifier_convert");
238 }
239 }
240
241 modifier_panel_end(layout, ptr);
242}
243
244static void panel_register(ARegionType *region_type)
245{
247}
248
249static void blend_read(BlendDataReader *reader, ModifierData *md)
250{
252
253 psmd->mesh_final = nullptr;
254 psmd->mesh_original = nullptr;
255 /* This is written as part of ob->particlesystem. */
256 BLO_read_struct(reader, ParticleSystem, &psmd->psys);
257 psmd->flag &= ~eParticleSystemFlag_psys_updated;
259}
260
262 /*idname*/ "ParticleSystem",
263 /*name*/ N_("ParticleSystem"),
264 /*struct_name*/ "ParticleSystemModifierData",
265 /*struct_size*/ sizeof(ParticleSystemModifierData),
266 /*srna*/ &RNA_ParticleSystemModifier,
270 /*icon*/ ICON_MOD_PARTICLES,
271
272 /*copy_data*/ copy_data,
273
274 /*deform_verts*/ deform_verts,
275 /*deform_matrices*/ nullptr,
276 /*deform_verts_EM*/ nullptr,
277 /*deform_matrices_EM*/ nullptr,
278 /*modify_mesh*/ nullptr,
279 /*modify_geometry_set*/ nullptr,
280
281 /*init_data*/ init_data,
282 /*required_data_mask*/ required_data_mask,
283 /*free_data*/ free_data,
284 /*is_disabled*/ nullptr,
285 /*update_depsgraph*/ nullptr,
286 /*depends_on_time*/ nullptr,
287 /*depends_on_normals*/ nullptr,
288 /*foreach_ID_link*/ nullptr,
289 /*foreach_tex_link*/ nullptr,
290 /*free_runtime_data*/ nullptr,
291 /*panel_register*/ panel_register,
292 /*blend_write*/ nullptr,
293 /*blend_read*/ blend_read,
294 /*foreach_cache*/ nullptr,
295};
BMEditMesh * BKE_editmesh_from_object(Object *ob)
Return the BMEditMesh for a given object.
Definition editmesh.cc:63
void BKE_id_free(Main *bmain, void *idv)
Mesh * BKE_mesh_copy_for_eval(const Mesh &source)
Mesh * BKE_mesh_from_bmesh_for_eval_nomain(BMesh *bm, const CustomData_MeshMasks *cd_mask_extra, const Mesh *me_settings)
void BKE_mesh_tessface_ensure(Mesh *mesh)
void BKE_modifier_copydata_generic(const ModifierData *md, ModifierData *md_dst, int flag)
@ eModifierTypeFlag_UsesPointCache
@ eModifierTypeFlag_SupportsMapping
@ eModifierTypeFlag_AcceptsMesh
ModifierData * BKE_modifiers_findby_name(const Object *ob, const char *name)
@ MOD_APPLY_RENDER
bool psys_check_enabled(struct Object *ob, struct ParticleSystem *psys, bool use_render_params)
Definition particle.cc:706
void psys_emitter_customdata_mask(struct ParticleSystem *psys, struct CustomData_MeshMasks *r_cddata_masks)
Definition particle.cc:2202
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:50
#define ELEM(...)
#define MEMCMP_STRUCT_AFTER_IS_ZERO(struct_var, member)
#define MEMCPY_STRUCT_AFTER(struct_dst, struct_src, member)
#define BLO_read_struct(reader, struct_name, ptr_p)
#define RPT_(msgid)
#define CTX_IFACE_(context, msgid)
#define BLT_I18NCONTEXT_OPERATOR_DEFAULT
bool DEG_is_active(const Depsgraph *depsgraph)
Definition depsgraph.cc:318
Scene * DEG_get_evaluated_scene(const Depsgraph *graph)
Object * DEG_get_original_object(Object *object)
@ ID_RECALC_PSYS_RESET
Definition DNA_ID.h:1050
#define DNA_struct_default_get(struct_name)
@ eParticleSystemFlag_psys_updated
@ eParticleSystemFlag_file_loaded
struct ParticleSystemModifierData ParticleSystemModifierData
@ eModifierType_ParticleSystem
@ OB_MODE_PARTICLE_EDIT
@ OB_MESH
@ PART_DRAW_PATH
@ PART_DRAW_GR
@ PART_DRAW_OB
@ PSYS_DELETE
static void init_data(ModifierData *md)
static void deform_verts(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh, blender::MutableSpan< blender::float3 > positions)
static void panel_register(ARegionType *region_type)
ModifierTypeInfo modifierType_ParticleSystem
static void free_data(ModifierData *md)
static void blend_read(BlendDataReader *reader, ModifierData *md)
static void panel_draw(const bContext *, Panel *panel)
static void required_data_mask(ModifierData *md, CustomData_MeshMasks *r_cddata_masks)
static void copy_data(const ModifierData *md, ModifierData *target, const int flag)
void modifier_panel_end(uiLayout *layout, PointerRNA *ptr)
PanelType * modifier_panel_register(ARegionType *region_type, ModifierType type, PanelDrawFn draw)
PointerRNA * modifier_panel_get_property_pointers(Panel *panel, PointerRNA *r_ob_ptr)
void uiItemL(uiLayout *layout, const char *name, int icon)
void uiItemO(uiLayout *layout, const char *name, int icon, const char *opname)
void * first
int edges_num
MeshRuntimeHandle * runtime
int totface_legacy
int verts_num
ModifierApplyFlag flag
ListBase particlesystem
struct uiLayout * layout
struct ParticleSystem * psys
ParticleData * particles
ParticleSettings * part
void * data
Definition RNA_types.hh:42
#define N_(msgid)
PointerRNA * ptr
Definition wm_files.cc:4126
uint8_t flag
Definition wm_window.cc:138