Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Sharybin <sergey.vfx@gmail.com>2018-05-11 13:44:43 +0300
committerSergey Sharybin <sergey.vfx@gmail.com>2018-05-11 13:49:25 +0300
commitd50821f145550b60078ce1106edd21348476d960 (patch)
tree644681631a283c40ac746279a4b6bc4c298f996c
parentff3e9d0d90e105e0b6c9cd6e09189f420268d9ec (diff)
Particle edit: Initial support of edit with copy-on-write
The idea is that edit mode structure is owned by original object, and used for drawing. This is a bit confusing, especially since path cache is also in that structure and needs evaluated object to calculate cache. In the future we should split edit data from visualization data, but that's bigger refactor.
-rw-r--r--source/blender/blenkernel/intern/particle.c24
-rw-r--r--source/blender/draw/intern/draw_cache.c12
-rw-r--r--source/blender/draw/intern/draw_cache.h6
-rw-r--r--source/blender/draw/intern/draw_cache_impl.h6
-rw-r--r--source/blender/draw/intern/draw_cache_impl_particles.c31
-rw-r--r--source/blender/draw/modes/particle_mode.c49
-rw-r--r--source/blender/editors/physics/particle_edit.c40
-rw-r--r--source/blender/editors/physics/particle_object.c2
-rw-r--r--source/blender/editors/physics/physics_intern.h2
9 files changed, 111 insertions, 61 deletions
diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c
index ae6028c742a..83484089a6a 100644
--- a/source/blender/blenkernel/intern/particle.c
+++ b/source/blender/blenkernel/intern/particle.c
@@ -2575,6 +2575,7 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra, const bool use_re
}
void psys_cache_edit_paths(Depsgraph *depsgraph, Scene *scene, Object *ob, PTCacheEdit *edit, float cfra, const bool use_render_params)
{
+ Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
ParticleCacheKey *ca, **cache = edit->pathcache;
ParticleEditSettings *pset = &scene->toolsettings->particle;
@@ -2582,8 +2583,19 @@ void psys_cache_edit_paths(Depsgraph *depsgraph, Scene *scene, Object *ob, PTCac
PTCacheEditKey *ekey = NULL;
ParticleSystem *psys = edit->psys;
+ ParticleSystem *psys_eval = NULL;
ParticleSystemModifierData *psmd = psys_get_modifier(ob, psys);
- ParticleData *pa = psys ? psys->particles : NULL;
+ ParticleSystemModifierData *psmd_eval = NULL;
+
+ BLI_assert((ob->id.tag & LIB_TAG_COPY_ON_WRITE) == 0);
+ BLI_assert(psmd != NULL);
+
+ if (psmd != NULL) {
+ psmd_eval = (ParticleSystemModifierData *)modifiers_findByName(ob_eval, psmd->modifier.name);
+ psys_eval = psmd_eval->psys;
+ }
+
+ ParticleData *pa = psys_eval ? psys_eval->particles : NULL;
ParticleInterpolationData pind;
ParticleKey result;
@@ -2612,7 +2624,7 @@ void psys_cache_edit_paths(Depsgraph *depsgraph, Scene *scene, Object *ob, PTCac
/* frs_sec = (psys || edit->pid.flag & PTCACHE_VEL_PER_SEC) ? 25.0f : 1.0f; */ /* UNUSED */
- const bool use_weight = (pset->brushtype == PE_BRUSH_WEIGHT) && (psys != NULL) && (psys->particles != NULL);
+ const bool use_weight = (pset->brushtype == PE_BRUSH_WEIGHT) && (psys_eval != NULL) && (psys_eval->particles != NULL);
if (use_weight) {
; /* use weight painting colors now... */
@@ -2657,10 +2669,10 @@ void psys_cache_edit_paths(Depsgraph *depsgraph, Scene *scene, Object *ob, PTCac
cache[i]->segments = segments;
/*--get the first data points--*/
- init_particle_interpolation(ob, psys, pa, &pind);
+ init_particle_interpolation(ob_eval, psys_eval, pa, &pind);
- if (psys) {
- psys_mat_hair_to_global(ob, psmd->dm_final, psys->part->from, pa, hairmat);
+ if (psys_eval) {
+ psys_mat_hair_to_global(ob_eval, psmd_eval->dm_final, psys->part->from, pa, hairmat);
copy_v3_v3(rotmat[0], hairmat[2]);
copy_v3_v3(rotmat[1], hairmat[1]);
copy_v3_v3(rotmat[2], hairmat[0]);
@@ -2679,7 +2691,7 @@ void psys_cache_edit_paths(Depsgraph *depsgraph, Scene *scene, Object *ob, PTCac
time = (float)k / (float)segments;
t = birthtime + time * (dietime - birthtime);
result.time = -t;
- do_particle_interpolation(psys, i, pa, t, &pind, &result);
+ do_particle_interpolation(psys_eval, i, pa, t, &pind, &result);
copy_v3_v3(ca->co, result.co);
/* non-hair points are already in global space */
diff --git a/source/blender/draw/intern/draw_cache.c b/source/blender/draw/intern/draw_cache.c
index b70ed1d053d..6c6e9a732b3 100644
--- a/source/blender/draw/intern/draw_cache.c
+++ b/source/blender/draw/intern/draw_cache.c
@@ -2886,19 +2886,19 @@ Gwn_Batch *DRW_cache_particles_get_dots(Object *object, ParticleSystem *psys)
return DRW_particles_batch_cache_get_dots(object, psys);
}
-Gwn_Batch *DRW_cache_particles_get_edit_strands(struct PTCacheEdit *edit)
+Gwn_Batch *DRW_cache_particles_get_edit_strands(Object *object, struct PTCacheEdit *edit)
{
- return DRW_particles_batch_cache_get_edit_strands(edit);
+ return DRW_particles_batch_cache_get_edit_strands(object, edit);
}
-Gwn_Batch *DRW_cache_particles_get_edit_inner_points(struct PTCacheEdit *edit)
+Gwn_Batch *DRW_cache_particles_get_edit_inner_points(Object *object, struct PTCacheEdit *edit)
{
- return DRW_particles_batch_cache_get_edit_inner_points(edit);
+ return DRW_particles_batch_cache_get_edit_inner_points(object, edit);
}
-Gwn_Batch *DRW_cache_particles_get_edit_tip_points(struct PTCacheEdit *edit)
+Gwn_Batch *DRW_cache_particles_get_edit_tip_points(Object *object, struct PTCacheEdit *edit)
{
- return DRW_particles_batch_cache_get_edit_tip_points(edit);
+ return DRW_particles_batch_cache_get_edit_tip_points(object, edit);
}
Gwn_Batch *DRW_cache_particles_get_prim(int type)
diff --git a/source/blender/draw/intern/draw_cache.h b/source/blender/draw/intern/draw_cache.h
index 66db405786d..2dc07e40c42 100644
--- a/source/blender/draw/intern/draw_cache.h
+++ b/source/blender/draw/intern/draw_cache.h
@@ -169,9 +169,9 @@ struct Gwn_Batch *DRW_cache_lattice_vert_overlay_get(struct Object *ob);
/* Particles */
struct Gwn_Batch *DRW_cache_particles_get_hair(struct ParticleSystem *psys, struct ModifierData *md);
struct Gwn_Batch *DRW_cache_particles_get_dots(struct Object *object, struct ParticleSystem *psys);
-struct Gwn_Batch *DRW_cache_particles_get_edit_strands(struct PTCacheEdit *edit);
-struct Gwn_Batch *DRW_cache_particles_get_edit_inner_points(struct PTCacheEdit *edit);
-struct Gwn_Batch *DRW_cache_particles_get_edit_tip_points(struct PTCacheEdit *edit);
+struct Gwn_Batch *DRW_cache_particles_get_edit_strands(struct Object *object, struct PTCacheEdit *edit);
+struct Gwn_Batch *DRW_cache_particles_get_edit_inner_points(struct Object *object, struct PTCacheEdit *edit);
+struct Gwn_Batch *DRW_cache_particles_get_edit_tip_points(struct Object *object, struct PTCacheEdit *edit);
struct Gwn_Batch *DRW_cache_particles_get_prim(int type);
/* Metaball */
diff --git a/source/blender/draw/intern/draw_cache_impl.h b/source/blender/draw/intern/draw_cache_impl.h
index 4e3c56eb427..9d9668f3ffc 100644
--- a/source/blender/draw/intern/draw_cache_impl.h
+++ b/source/blender/draw/intern/draw_cache_impl.h
@@ -125,8 +125,8 @@ void DRW_mesh_cache_sculpt_coords_ensure(struct Mesh *me);
/* Particles */
struct Gwn_Batch *DRW_particles_batch_cache_get_hair(struct ParticleSystem *psys, struct ModifierData *md);
struct Gwn_Batch *DRW_particles_batch_cache_get_dots(struct Object *object, struct ParticleSystem *psys);
-struct Gwn_Batch *DRW_particles_batch_cache_get_edit_strands(struct PTCacheEdit *edit);
-struct Gwn_Batch *DRW_particles_batch_cache_get_edit_inner_points(struct PTCacheEdit *edit);
-struct Gwn_Batch *DRW_particles_batch_cache_get_edit_tip_points(struct PTCacheEdit *edit);
+struct Gwn_Batch *DRW_particles_batch_cache_get_edit_strands(struct Object *object, struct PTCacheEdit *edit);
+struct Gwn_Batch *DRW_particles_batch_cache_get_edit_inner_points(struct Object *object, struct PTCacheEdit *edit);
+struct Gwn_Batch *DRW_particles_batch_cache_get_edit_tip_points(struct Object *object, struct PTCacheEdit *edit);
#endif /* __DRAW_CACHE_IMPL_H__ */
diff --git a/source/blender/draw/intern/draw_cache_impl_particles.c b/source/blender/draw/intern/draw_cache_impl_particles.c
index 4102b72175f..f1ae9d6ef8c 100644
--- a/source/blender/draw/intern/draw_cache_impl_particles.c
+++ b/source/blender/draw/intern/draw_cache_impl_particles.c
@@ -597,10 +597,25 @@ Gwn_Batch *DRW_particles_batch_cache_get_dots(Object *object, ParticleSystem *ps
return cache->hairs;
}
-Gwn_Batch *DRW_particles_batch_cache_get_edit_strands(PTCacheEdit *edit)
+/* TODO(sergey): Avoid linear lookup. */
+static ParticleBatchCache *particle_batch_cache_get_edit(Object *object, PTCacheEdit *edit)
+{
+ ParticleSystem *psys_orig = edit->psys;
+ for (ParticleSystem *psys_eval = object->particlesystem.first;
+ psys_eval != NULL;
+ psys_eval = psys_eval->next)
+ {
+ if (STREQ(psys_orig->name, psys_eval->name)) {
+ return particle_batch_cache_get(psys_eval);
+ }
+ }
+ return NULL;
+}
+
+Gwn_Batch *DRW_particles_batch_cache_get_edit_strands(Object *object, PTCacheEdit *edit)
{
ParticleSystem *psys = edit->psys;
- ParticleBatchCache *cache = particle_batch_cache_get(psys);
+ ParticleBatchCache *cache = particle_batch_cache_get_edit(object, edit);
if (cache->hairs != NULL) {
return cache->hairs;
}
@@ -676,10 +691,9 @@ static void particle_batch_cache_ensure_edit_inner_pos(
}
}
-Gwn_Batch *DRW_particles_batch_cache_get_edit_inner_points(PTCacheEdit *edit)
+Gwn_Batch *DRW_particles_batch_cache_get_edit_inner_points(Object *object, PTCacheEdit *edit)
{
- ParticleSystem *psys = edit->psys;
- ParticleBatchCache *cache = particle_batch_cache_get(psys);
+ ParticleBatchCache *cache = particle_batch_cache_get_edit(object, edit);
if (cache->edit_inner_points != NULL) {
return cache->edit_inner_points;
}
@@ -692,7 +706,7 @@ Gwn_Batch *DRW_particles_batch_cache_get_edit_inner_points(PTCacheEdit *edit)
}
static void ensure_edit_tip_points_count(const PTCacheEdit *edit,
- ParticleBatchCache *cache)
+ ParticleBatchCache *cache)
{
if (cache->edit_tip_pos != NULL) {
return;
@@ -738,10 +752,9 @@ static void particle_batch_cache_ensure_edit_tip_pos(
}
}
-Gwn_Batch *DRW_particles_batch_cache_get_edit_tip_points(PTCacheEdit *edit)
+Gwn_Batch *DRW_particles_batch_cache_get_edit_tip_points(Object *object, PTCacheEdit *edit)
{
- ParticleSystem *psys = edit->psys;
- ParticleBatchCache *cache = particle_batch_cache_get(psys);
+ ParticleBatchCache *cache = particle_batch_cache_get_edit(object, edit);
if (cache->edit_tip_points != NULL) {
return cache->edit_tip_points;
}
diff --git a/source/blender/draw/modes/particle_mode.c b/source/blender/draw/modes/particle_mode.c
index dc08ba63cb3..d9363a18054 100644
--- a/source/blender/draw/modes/particle_mode.c
+++ b/source/blender/draw/modes/particle_mode.c
@@ -139,18 +139,30 @@ static void particle_cache_init(void *vedata)
DRW_shgroup_uniform_float(stl->g_data->tip_points_group, "outlineWidth", &outline_width, 1);
}
-static void draw_update_ptcache_edit(Object *object, PTCacheEdit *edit)
+/* TODO(sergey): Avoid linear lookup. */
+static void draw_update_ptcache_edit(Object *object_eval, PTCacheEdit *edit)
{
- if (edit->psys && edit->psys->flag & PSYS_HAIR_UPDATED) {
+ if (edit->psys == NULL) {
+ return;
+ }
+ ParticleSystem *psys_eval;
+ for (psys_eval = object_eval->particlesystem.first;
+ psys_eval != NULL;
+ psys_eval = psys_eval->next)
+ {
+ if (STREQ(edit->psys->name, psys_eval->name)) {
+ break;
+ }
+ }
+ if (psys_eval->flag & PSYS_HAIR_UPDATED) {
const DRWContextState *draw_ctx = DRW_context_state_get();
Scene *scene_orig = (Scene *)DEG_get_original_id(&draw_ctx->scene->id);
- Object *object_orig = DEG_get_original_object(object);
+ Object *object_orig = DEG_get_original_object(object_eval);
PE_update_object(draw_ctx->depsgraph, scene_orig, object_orig, 0);
}
BLI_assert(edit->pathcache != NULL);
}
-
static void particle_edit_cache_populate(void *vedata,
Object *object,
PTCacheEdit *edit)
@@ -160,35 +172,32 @@ static void particle_edit_cache_populate(void *vedata,
draw_update_ptcache_edit(object, edit);
ParticleEditSettings *pset = PE_settings(draw_ctx->scene);
{
- struct Gwn_Batch *strands = DRW_cache_particles_get_edit_strands(edit);
+ struct Gwn_Batch *strands =
+ DRW_cache_particles_get_edit_strands(object, edit);
DRW_shgroup_call_add(stl->g_data->strands_group, strands, NULL);
}
if (pset->selectmode == SCE_SELECT_POINT) {
- struct Gwn_Batch *points = DRW_cache_particles_get_edit_inner_points(edit);
+ struct Gwn_Batch *points =
+ DRW_cache_particles_get_edit_inner_points(object, edit);
DRW_shgroup_call_add(stl->g_data->inner_points_group, points, NULL);
}
if (ELEM(pset->selectmode, SCE_SELECT_POINT, SCE_SELECT_END)) {
- struct Gwn_Batch *points = DRW_cache_particles_get_edit_tip_points(edit);
+ struct Gwn_Batch *points =
+ DRW_cache_particles_get_edit_tip_points(object, edit);
DRW_shgroup_call_add(stl->g_data->tip_points_group, points, NULL);
}
}
static void particle_cache_populate(void *vedata, Object *object)
{
- for (ParticleSystem *psys = object->particlesystem.first;
- psys != NULL;
- psys = psys->next)
- {
- if (!psys_check_enabled(object, psys, false)) {
- continue;
- }
- PTCacheEdit *edit = PE_get_current_from_psys(psys);
- if (edit == NULL) {
- continue;
- }
- particle_edit_cache_populate(vedata, object, edit);
- break;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ Object *object_orig = DEG_get_original_object(object);
+ PTCacheEdit *edit = PE_get_current(draw_ctx->scene, object_orig);
+ if (edit == NULL) {
+ printf("Particle edit struct is NULL, not supposed to happen.\n");
+ return;
}
+ particle_edit_cache_populate(vedata, object, edit);
}
/* Optional: Post-cache_populate callback */
diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c
index da8a97bc143..f65e598e204 100644
--- a/source/blender/editors/physics/particle_edit.c
+++ b/source/blender/editors/physics/particle_edit.c
@@ -85,6 +85,8 @@
#include "RNA_access.h"
#include "RNA_define.h"
+#include "DEG_depsgraph_query.h"
+
#include "physics_intern.h"
#include "particle_edit_utildefines.h"
@@ -1185,19 +1187,27 @@ static void PE_update_selection(Depsgraph *depsgraph, Scene *scene, Object *ob,
DEG_id_tag_update(&ob->id, DEG_TAG_SELECT_UPDATE);
}
-void update_world_cos(Object *ob, PTCacheEdit *edit)
+void update_world_cos(Depsgraph *depsgraph, Object *ob, PTCacheEdit *edit)
{
+ Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
ParticleSystem *psys = edit->psys;
- ParticleSystemModifierData *psmd= psys_get_modifier(ob, psys);
+ ParticleSystem *psys_eval = NULL;
+ ParticleSystemModifierData *psmd = psys_get_modifier(ob, psys);
+ ParticleSystemModifierData *psmd_eval = NULL;
POINT_P; KEY_K;
float hairmat[4][4];
- if (psys==0 || psys->edit==0 || psmd->dm_final==NULL)
+ if (psmd != NULL) {
+ psmd_eval = (ParticleSystemModifierData *)modifiers_findByName(ob_eval, psmd->modifier.name);
+ psys_eval = psmd_eval->psys;
+ }
+
+ if (psys == 0 || psys->edit == 0 || psmd_eval->dm_final == NULL)
return;
LOOP_POINTS {
if (!(psys->flag & PSYS_GLOBAL_HAIR))
- psys_mat_hair_to_global(ob, psmd->dm_final, psys->part->from, psys->particles+p, hairmat);
+ psys_mat_hair_to_global(ob_eval, psmd_eval->dm_final, psys->part->from, psys_eval->particles+p, hairmat);
LOOP_KEYS {
copy_v3_v3(key->world_co, key->co);
@@ -1287,7 +1297,7 @@ void PE_update_object(Depsgraph *depsgraph, Scene *scene, Object *ob, int usefla
if (pe_x_mirror(ob))
PE_apply_mirror(ob, edit->psys);
if (edit->psys)
- update_world_cos(ob, edit);
+ update_world_cos(depsgraph, ob, edit);
if (pset->flag & PE_AUTO_VELOCITY)
update_velocities(edit);
PE_hide_keys_time(scene, edit, CFRA);
@@ -2970,7 +2980,7 @@ static int mirror_exec(bContext *C, wmOperator *UNUSED(op))
PE_mirror_x(scene, ob, 0);
- update_world_cos(ob, edit);
+ update_world_cos(CTX_data_depsgraph(C), ob, edit);
WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_EDITED, ob);
DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
@@ -3788,6 +3798,7 @@ static int brush_edit_init(bContext *C, wmOperator *op)
static void brush_edit_apply(bContext *C, wmOperator *op, PointerRNA *itemptr)
{
BrushEdit *bedit= op->customdata;
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
Scene *scene= bedit->scene;
Object *ob= bedit->ob;
PTCacheEdit *edit= bedit->edit;
@@ -3804,8 +3815,6 @@ static void brush_edit_apply(bContext *C, wmOperator *op, PointerRNA *itemptr)
if (!PE_start_edit(edit))
return;
- Depsgraph *depsgraph = CTX_data_depsgraph(C);
-
RNA_float_get_array(itemptr, "mouse", mousef);
mouse[0] = mousef[0];
mouse[1] = mousef[1];
@@ -3984,7 +3993,7 @@ static void brush_edit_apply(bContext *C, wmOperator *op, PointerRNA *itemptr)
if (pset->brushtype == PE_BRUSH_ADD && pe_x_mirror(ob))
PE_mirror_x(scene, ob, 1);
- update_world_cos(ob, edit);
+ update_world_cos(depsgraph, ob, edit);
psys_free_path_cache(NULL, edit);
DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
}
@@ -4213,6 +4222,7 @@ static void shape_cut(PEData *data, int pa_index)
static int shape_cut_exec(bContext *C, wmOperator *UNUSED(op))
{
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
ParticleEditSettings *pset = PE_settings(scene);
@@ -4247,7 +4257,7 @@ static int shape_cut_exec(bContext *C, wmOperator *UNUSED(op))
recalc_lengths(edit);
if (removed) {
- update_world_cos(ob, edit);
+ update_world_cos(depsgraph, ob, edit);
psys_free_path_cache(NULL, edit);
DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
}
@@ -4332,14 +4342,20 @@ void PE_create_particle_edit(
Depsgraph *depsgraph, Scene *scene, Object *ob, PointCache *cache, ParticleSystem *psys)
{
PTCacheEdit *edit;
+ Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
ParticleSystemModifierData *psmd = (psys) ? psys_get_modifier(ob, psys) : NULL;
+ ParticleSystemModifierData *psmd_eval = NULL;
POINT_P; KEY_K;
ParticleData *pa = NULL;
HairKey *hkey;
int totpoint;
+ if (psmd != NULL) {
+ psmd_eval = (ParticleSystemModifierData *)modifiers_findByName(ob_eval, psmd->modifier.name);
+ }
+
/* no psmd->dm happens in case particle system modifier is not enabled */
- if (!(psys && psmd && psmd->dm_final) && !cache)
+ if (!(psys && psmd_eval && psmd_eval->dm_final) && !cache)
return;
if (cache && cache->flag & PTCACHE_DISK_CACHE)
@@ -4386,7 +4402,7 @@ void PE_create_particle_edit(
}
pa++;
}
- update_world_cos(ob, edit);
+ update_world_cos(depsgraph, ob, edit);
}
else {
PTCacheMem *pm;
diff --git a/source/blender/editors/physics/particle_object.c b/source/blender/editors/physics/particle_object.c
index ecebcb1ff6c..76308fe1fd7 100644
--- a/source/blender/editors/physics/particle_object.c
+++ b/source/blender/editors/physics/particle_object.c
@@ -946,7 +946,7 @@ static void copy_particle_edit(
pa++;
}
- update_world_cos(ob, edit);
+ update_world_cos(depsgraph, ob, edit);
UI_GetThemeColor3ubv(TH_EDGE_SELECT, edit->sel_col);
UI_GetThemeColor3ubv(TH_WIRE, edit->nosel_col);
diff --git a/source/blender/editors/physics/physics_intern.h b/source/blender/editors/physics/physics_intern.h
index 72da417da63..108c033a87c 100644
--- a/source/blender/editors/physics/physics_intern.h
+++ b/source/blender/editors/physics/physics_intern.h
@@ -75,7 +75,7 @@ void PE_create_particle_edit(
struct Object *ob, struct PointCache *cache, struct ParticleSystem *psys);
void recalc_lengths(struct PTCacheEdit *edit);
void recalc_emitter_field(struct Object *ob, struct ParticleSystem *psys);
-void update_world_cos(struct Object *ob, struct PTCacheEdit *edit);
+void update_world_cos(struct Depsgraph *depsgraph, struct Object *ob, struct PTCacheEdit *edit);
/* particle_object.c */
void OBJECT_OT_particle_system_add(struct wmOperatorType *ot);