Blender V5.0
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
8
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
28#include "UI_resources.hh"
29
30#include "RNA_prototypes.hh"
31#include "RNA_types.hh"
32
34
35#include "BLO_read_write.hh"
36
37#include "MOD_ui_common.hh"
38
47static void free_data(ModifierData *md)
48{
50
51 if (psmd->mesh_final) {
52 BKE_id_free(nullptr, psmd->mesh_final);
53 psmd->mesh_final = nullptr;
54 if (psmd->mesh_original) {
55 BKE_id_free(nullptr, psmd->mesh_original);
56 psmd->mesh_original = nullptr;
57 }
58 }
59 psmd->totdmvert = psmd->totdmedge = psmd->totdmface = 0;
60
61 /* blender::ed::object::modifier_remove may have freed this first before calling
62 * BKE_modifier_free (which calls this function) */
63 if (psmd->psys) {
64 psmd->psys->flag |= PSYS_DELETE;
65 }
66}
67
68static void copy_data(const ModifierData *md, ModifierData *target, const int flag)
69{
70#if 0
72#endif
74
76
77 /* NOTE: `psys` pointer here is just copied over from `md` to `target`. This is dangerous, as it
78 * will generate invalid data in case we are copying between different objects. Extra external
79 * code has to be called then to ensure proper remapping of that pointer. See e.g.
80 * `BKE_object_copy_particlesystems` or `BKE_object_copy_modifier`. */
81
82 tpsmd->mesh_final = nullptr;
83 tpsmd->mesh_original = nullptr;
84 tpsmd->totdmvert = tpsmd->totdmedge = tpsmd->totdmface = 0;
85}
86
87static void required_data_mask(ModifierData *md, CustomData_MeshMasks *r_cddata_masks)
88{
90
91 psys_emitter_customdata_mask(psmd->psys, r_cddata_masks);
92}
93
94/* saves the current emitter state for a particle system and calculates particles */
95static void deform_verts(ModifierData *md,
96 const ModifierEvalContext *ctx,
97 Mesh *mesh,
99{
101 ParticleSystem *psys = nullptr;
102
103 if (ctx->object->particlesystem.first) {
104 psys = psmd->psys;
105 }
106 else {
107 return;
108 }
109
110 if (!psys_check_enabled(ctx->object, psys, (ctx->flag & MOD_APPLY_RENDER) != 0)) {
111 return;
112 }
113
114 /* Clear old evaluated mesh. */
115 bool had_mesh_final = (psmd->mesh_final != nullptr);
116 if (psmd->mesh_final) {
117 BKE_id_free(nullptr, psmd->mesh_final);
118 psmd->mesh_final = nullptr;
119 if (psmd->mesh_original) {
120 BKE_id_free(nullptr, psmd->mesh_original);
121 psmd->mesh_original = nullptr;
122 }
123 }
124 else if (psmd->flag & eParticleSystemFlag_file_loaded) {
125 /* in file read mesh just wasn't saved in file so no need to reset everything */
127 if (psys->particles == nullptr) {
129 }
130 /* TODO(sergey): This is not how particles were working prior to copy on
131 * write, but now evaluation is similar to case when one duplicates the
132 * object. In that case particles were doing reset here.
133 *
134 * Don't do reset when entering particle edit mode, as that will destroy the edit mode data.
135 * Shouldn't be an issue, since particles are supposed to be evaluated once prior to entering
136 * edit mode anyway.
137 * Could in theory be an issue when everything is done in a script, but then solution is
138 * not known to me. */
139 if (ctx->object->mode != OB_MODE_PARTICLE_EDIT) {
141 }
142 }
143
144 /* make new mesh */
145 psmd->mesh_final = BKE_mesh_copy_for_eval(*mesh);
146 psmd->mesh_final->vert_positions_for_write().copy_from(positions);
147 psmd->mesh_final->tag_positions_changed();
148
150
151 if (!psmd->mesh_final->runtime->deformed_only) {
152 /* Get the original mesh from the object, this is what the particles
153 * are attached to so in case of non-deform modifiers we need to remap
154 * them to the final mesh (typically subdivision surfaces). */
155 Mesh *mesh_original = nullptr;
156
157 if (ctx->object->type == OB_MESH) {
159
160 if (em) {
161 /* In edit mode get directly from the edit mesh. */
162 psmd->mesh_original = BKE_mesh_from_bmesh_for_eval_nomain(em->bm, nullptr, mesh);
163 }
164 else {
165 /* Otherwise get regular mesh. */
166 mesh_original = static_cast<Mesh *>(ctx->object->data);
167 }
168 }
169 else {
170 mesh_original = mesh;
171 }
172
173 if (mesh_original) {
174 /* Make a persistent copy of the mesh. We don't actually need
175 * all this data, just some topology for remapping. Could be
176 * optimized once. */
177 psmd->mesh_original = BKE_mesh_copy_for_eval(*mesh_original);
178 }
179
181 }
182
183 /* Report change in mesh structure.
184 * This is an unreliable check for the topology check, but allows some
185 * handy configuration like emitting particles from inside particle
186 * instance. */
187 if (had_mesh_final && (psmd->mesh_final->verts_num != psmd->totdmvert ||
188 psmd->mesh_final->edges_num != psmd->totdmedge ||
189 psmd->mesh_final->totface_legacy != psmd->totdmface))
190 {
192 }
193 psmd->totdmvert = psmd->mesh_final->verts_num;
194 psmd->totdmedge = psmd->mesh_final->edges_num;
195 psmd->totdmface = psmd->mesh_final->totface_legacy;
196
197 {
201 ctx->depsgraph, scene, ctx->object, psys, (ctx->flag & MOD_APPLY_RENDER) != 0);
203 }
204
205 if (DEG_is_active(ctx->depsgraph)) {
206 Object *object_orig = DEG_get_original(ctx->object);
207 ModifierData *md_orig = BKE_modifiers_findby_name(object_orig, psmd->modifier.name);
208 BLI_assert(md_orig != nullptr);
210 psmd_orig->flag = psmd->flag;
211 }
212}
213
214static void panel_draw(const bContext * /*C*/, Panel *panel)
215{
216 uiLayout *layout = panel->layout;
217
218 PointerRNA ob_ptr;
220
221 Object *ob = static_cast<Object *>(ob_ptr.data);
222 ModifierData *md = (ModifierData *)ptr->data;
223 ParticleSystem *psys = ((ParticleSystemModifierData *)md)->psys;
224
225 layout->label(RPT_("Settings are inside the Particles tab"), ICON_NONE);
226
227 if (!(ob->mode & OB_MODE_PARTICLE_EDIT)) {
228 if (ELEM(psys->part->ren_as, PART_DRAW_GR, PART_DRAW_OB)) {
229 layout->op("OBJECT_OT_duplicates_make_real",
230 CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Make Instances Real"),
231 ICON_NONE);
232 }
233 else if (psys->part->ren_as == PART_DRAW_PATH) {
234 layout->op("OBJECT_OT_modifier_convert",
236 ICON_NONE);
237 }
238 }
239
241}
242
243static void panel_register(ARegionType *region_type)
244{
246}
247
248static void blend_read(BlendDataReader *reader, ModifierData *md)
249{
251
252 psmd->mesh_final = nullptr;
253 psmd->mesh_original = nullptr;
254 /* This is written as part of ob->particlesystem. */
255 BLO_read_struct(reader, ParticleSystem, &psmd->psys);
258}
259
261 /*idname*/ "ParticleSystem",
262 /*name*/ N_("ParticleSystem"),
263 /*struct_name*/ "ParticleSystemModifierData",
264 /*struct_size*/ sizeof(ParticleSystemModifierData),
265 /*srna*/ &RNA_ParticleSystemModifier,
269 /*icon*/ ICON_MOD_PARTICLES,
270
271 /*copy_data*/ copy_data,
272
273 /*deform_verts*/ deform_verts,
274 /*deform_matrices*/ nullptr,
275 /*deform_verts_EM*/ nullptr,
276 /*deform_matrices_EM*/ nullptr,
277 /*modify_mesh*/ nullptr,
278 /*modify_geometry_set*/ nullptr,
279
280 /*init_data*/ init_data,
281 /*required_data_mask*/ required_data_mask,
282 /*free_data*/ free_data,
283 /*is_disabled*/ nullptr,
284 /*update_depsgraph*/ nullptr,
285 /*depends_on_time*/ nullptr,
286 /*depends_on_normals*/ nullptr,
287 /*foreach_ID_link*/ nullptr,
288 /*foreach_tex_link*/ nullptr,
289 /*free_runtime_data*/ nullptr,
290 /*panel_register*/ panel_register,
291 /*blend_write*/ nullptr,
292 /*blend_read*/ blend_read,
293 /*foreach_cache*/ nullptr,
294 /*foreach_working_space_color*/ nullptr,
295};
BMEditMesh * BKE_editmesh_from_object(Object *ob)
Return the BMEditMesh for a given object.
Definition editmesh.cc:61
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:710
void psys_emitter_customdata_mask(struct ParticleSystem *psys, struct CustomData_MeshMasks *r_cddata_masks)
Definition particle.cc:2207
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 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:323
Scene * DEG_get_evaluated_scene(const Depsgraph *graph)
T * DEG_get_original(T *id)
@ ID_RECALC_PSYS_RESET
Definition DNA_ID.h:1083
#define DNA_struct_default_get(struct_name)
@ eParticleSystemFlag_psys_updated
@ eParticleSystemFlag_file_loaded
@ eModifierType_ParticleSystem
@ OB_MODE_PARTICLE_EDIT
@ OB_MESH
@ PSYS_DELETE
@ PART_DRAW_PATH
@ PART_DRAW_GR
@ PART_DRAW_OB
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)
static void required_data_mask(ModifierData *, CustomData_MeshMasks *r_cddata_masks)
static void blend_read(BlendDataReader *, ModifierData *md)
static void panel_draw(const bContext *, Panel *panel)
static void copy_data(const ModifierData *md, ModifierData *target, const int flag)
static void free_data(ModifierData *md)
Definition MOD_bevel.cc:272
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)
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)
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:53
void label(blender::StringRef name, int icon)
PointerRNA op(wmOperatorType *ot, std::optional< blender::StringRef > name, int icon, blender::wm::OpCallContext context, eUI_Item_Flag flag)
#define N_(msgid)
PointerRNA * ptr
Definition wm_files.cc:4238
uint8_t flag
Definition wm_window.cc:145