2011-02-23 10:52:22 +00:00
|
|
|
/*
|
2009-10-22 23:22:05 +00:00
|
|
|
* ***** BEGIN GPL LICENSE BLOCK *****
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
* as published by the Free Software Foundation; either version 2
|
2018-06-01 18:19:39 +02:00
|
|
|
* of the License, or (at your option) any later version.
|
2009-10-22 23:22:05 +00:00
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software Foundation,
|
2010-02-12 13:34:04 +00:00
|
|
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
2009-10-22 23:22:05 +00:00
|
|
|
*
|
|
|
|
* The Original Code is Copyright (C) 2009 Blender Foundation.
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* Contributor(s): Blender Foundation
|
|
|
|
*
|
|
|
|
* ***** END GPL LICENSE BLOCK *****
|
|
|
|
*/
|
|
|
|
|
2011-02-27 20:29:51 +00:00
|
|
|
/** \file blender/editors/physics/particle_object.c
|
|
|
|
* \ingroup edphys
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
2009-10-22 23:22:05 +00:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
|
|
|
|
#include "DNA_meshdata_types.h"
|
|
|
|
#include "DNA_modifier_types.h"
|
|
|
|
#include "DNA_scene_types.h"
|
|
|
|
|
2009-11-10 20:43:45 +00:00
|
|
|
#include "BLI_math.h"
|
2009-10-22 23:22:05 +00:00
|
|
|
#include "BLI_listbase.h"
|
2011-01-07 18:36:47 +00:00
|
|
|
#include "BLI_utildefines.h"
|
2015-01-15 11:51:30 +01:00
|
|
|
#include "BLI_string.h"
|
2009-10-22 23:22:05 +00:00
|
|
|
|
|
|
|
#include "BKE_context.h"
|
|
|
|
#include "BKE_depsgraph.h"
|
|
|
|
#include "BKE_DerivedMesh.h"
|
|
|
|
#include "BKE_cdderivedmesh.h"
|
2010-01-22 06:48:29 +00:00
|
|
|
#include "BKE_global.h"
|
2015-01-15 11:51:30 +01:00
|
|
|
#include "BKE_library.h"
|
2009-10-22 23:22:05 +00:00
|
|
|
#include "BKE_main.h"
|
2015-01-15 11:51:30 +01:00
|
|
|
#include "BKE_modifier.h"
|
|
|
|
#include "BKE_object.h"
|
2009-10-22 23:22:05 +00:00
|
|
|
#include "BKE_particle.h"
|
|
|
|
#include "BKE_pointcache.h"
|
2012-12-21 09:27:39 +00:00
|
|
|
#include "BKE_report.h"
|
2011-01-07 19:18:31 +00:00
|
|
|
|
2009-10-22 23:22:05 +00:00
|
|
|
#include "RNA_access.h"
|
|
|
|
#include "RNA_define.h"
|
|
|
|
|
|
|
|
#include "WM_api.h"
|
|
|
|
#include "WM_types.h"
|
|
|
|
|
|
|
|
#include "ED_particle.h"
|
2009-12-04 06:33:01 +00:00
|
|
|
#include "ED_screen.h"
|
2012-01-02 17:15:24 +00:00
|
|
|
#include "ED_object.h"
|
2009-10-22 23:22:05 +00:00
|
|
|
|
2015-01-15 11:51:30 +01:00
|
|
|
#include "UI_resources.h"
|
|
|
|
|
2018-03-19 18:16:27 +01:00
|
|
|
#include "particle_edit_utildefines.h"
|
2015-01-15 11:51:30 +01:00
|
|
|
|
2018-03-19 18:16:27 +01:00
|
|
|
#include "physics_intern.h"
|
2015-01-15 11:51:30 +01:00
|
|
|
|
2015-01-15 20:36:51 +01:00
|
|
|
static float I[4][4] = {{1.0f, 0.0f, 0.0f, 0.0f}, {0.0f, 1.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 1.0f, 0.0f}, {0.0f, 0.0f, 0.0f, 1.0f}};
|
|
|
|
|
2009-10-22 23:22:05 +00:00
|
|
|
/********************** particle system slot operators *********************/
|
|
|
|
|
2010-10-15 01:36:14 +00:00
|
|
|
static int particle_system_add_exec(bContext *C, wmOperator *UNUSED(op))
|
2009-10-22 23:22:05 +00:00
|
|
|
{
|
2018-06-13 10:57:10 +02:00
|
|
|
Main *bmain = CTX_data_main(C);
|
2012-01-02 17:15:24 +00:00
|
|
|
Object *ob= ED_object_context(C);
|
2009-10-22 23:22:05 +00:00
|
|
|
Scene *scene = CTX_data_scene(C);
|
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (!scene || !ob)
|
2009-10-22 23:22:05 +00:00
|
|
|
return OPERATOR_CANCELLED;
|
|
|
|
|
2018-06-13 10:57:10 +02:00
|
|
|
object_add_particle_system(bmain, scene, ob, NULL);
|
2018-06-04 09:31:30 +02:00
|
|
|
|
Timeline addition: Display cached frames
This started off doing pointcache debugging but it's also very useful for users too.
Previously it was very hard to see the state of the system when you're working caches
such as physics point cache - is it baked? which frames are cached? is it out of date?
Now, for better feedback, cached frames are drawn for the active object at the bottom
of the timeline - a semitransparent area shows the entire cache extents, and more
solid blocks on top show the frames that are cached. Darker versions indicate it's
using a disk cache.
It can be disabled in general in the timeline View -> Caches menu, or by each individual
system that can be shown.
There's still a bit to do on this, behaviour needs to be clarified still eg. deciding what
shows when it's out of date, or when it's been played back but not cached, etc. etc.
Part of this is due to a lack of definition in the point cache system itself, so we should
try and clean up/clarify this behaviour and what it means to users, at the same time.
Also would be interested in extending this to other caches such as fluid cache,
sequencer memory cache etc. in the future, too.
2010-06-22 02:29:52 +00:00
|
|
|
WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE, ob);
|
|
|
|
WM_event_add_notifier(C, NC_OBJECT|ND_POINTCACHE, ob);
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2009-10-22 23:22:05 +00:00
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
|
|
|
|
|
|
|
void OBJECT_OT_particle_system_add(wmOperatorType *ot)
|
|
|
|
{
|
|
|
|
/* identifiers */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->name = "Add Particle System Slot";
|
|
|
|
ot->idname = "OBJECT_OT_particle_system_add";
|
|
|
|
ot->description = "Add a particle system";
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2009-10-22 23:22:05 +00:00
|
|
|
/* api callbacks */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->poll = ED_operator_object_active_editable;
|
|
|
|
ot->exec = particle_system_add_exec;
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2009-10-22 23:22:05 +00:00
|
|
|
/* flags */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
|
2009-10-22 23:22:05 +00:00
|
|
|
}
|
|
|
|
|
2010-10-15 01:36:14 +00:00
|
|
|
static int particle_system_remove_exec(bContext *C, wmOperator *UNUSED(op))
|
2009-10-22 23:22:05 +00:00
|
|
|
{
|
2018-06-13 10:57:10 +02:00
|
|
|
Main *bmain = CTX_data_main(C);
|
2012-09-14 06:17:14 +00:00
|
|
|
Object *ob = ED_object_context(C);
|
2009-10-22 23:22:05 +00:00
|
|
|
Scene *scene = CTX_data_scene(C);
|
2012-09-14 06:17:14 +00:00
|
|
|
int mode_orig;
|
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (!scene || !ob)
|
2009-10-22 23:22:05 +00:00
|
|
|
return OPERATOR_CANCELLED;
|
|
|
|
|
2012-09-14 06:17:14 +00:00
|
|
|
mode_orig = ob->mode;
|
2018-06-13 10:57:10 +02:00
|
|
|
object_remove_particle_system(bmain, scene, ob);
|
2009-11-06 12:27:28 +00:00
|
|
|
|
|
|
|
/* possible this isn't the active object
|
|
|
|
* object_remove_particle_system() clears the mode on the last psys
|
2012-10-23 03:38:26 +00:00
|
|
|
*/
|
|
|
|
if (mode_orig & OB_MODE_PARTICLE_EDIT) {
|
|
|
|
if ((ob->mode & OB_MODE_PARTICLE_EDIT) == 0) {
|
|
|
|
if (scene->basact && scene->basact->object == ob) {
|
2009-11-06 12:27:28 +00:00
|
|
|
WM_event_add_notifier(C, NC_SCENE|ND_MODE|NS_MODE_OBJECT, NULL);
|
2012-10-23 03:38:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2009-11-06 12:27:28 +00:00
|
|
|
|
Timeline addition: Display cached frames
This started off doing pointcache debugging but it's also very useful for users too.
Previously it was very hard to see the state of the system when you're working caches
such as physics point cache - is it baked? which frames are cached? is it out of date?
Now, for better feedback, cached frames are drawn for the active object at the bottom
of the timeline - a semitransparent area shows the entire cache extents, and more
solid blocks on top show the frames that are cached. Darker versions indicate it's
using a disk cache.
It can be disabled in general in the timeline View -> Caches menu, or by each individual
system that can be shown.
There's still a bit to do on this, behaviour needs to be clarified still eg. deciding what
shows when it's out of date, or when it's been played back but not cached, etc. etc.
Part of this is due to a lack of definition in the point cache system itself, so we should
try and clean up/clarify this behaviour and what it means to users, at the same time.
Also would be interested in extending this to other caches such as fluid cache,
sequencer memory cache etc. in the future, too.
2010-06-22 02:29:52 +00:00
|
|
|
WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE, ob);
|
|
|
|
WM_event_add_notifier(C, NC_OBJECT|ND_POINTCACHE, ob);
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2009-10-22 23:22:05 +00:00
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
|
|
|
|
|
|
|
void OBJECT_OT_particle_system_remove(wmOperatorType *ot)
|
|
|
|
{
|
|
|
|
/* identifiers */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->name = "Remove Particle System Slot";
|
|
|
|
ot->idname = "OBJECT_OT_particle_system_remove";
|
|
|
|
ot->description = "Remove the selected particle system";
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2009-10-22 23:22:05 +00:00
|
|
|
/* api callbacks */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->poll = ED_operator_object_active_editable;
|
|
|
|
ot->exec = particle_system_remove_exec;
|
2009-10-22 23:22:05 +00:00
|
|
|
|
|
|
|
/* flags */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
|
2009-10-22 23:22:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/********************** new particle settings operator *********************/
|
|
|
|
|
2018-07-02 11:47:00 +02:00
|
|
|
static bool psys_poll(bContext *C)
|
2009-10-22 23:22:05 +00:00
|
|
|
{
|
|
|
|
PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
|
|
|
|
return (ptr.data != NULL);
|
|
|
|
}
|
|
|
|
|
2010-10-15 01:36:14 +00:00
|
|
|
static int new_particle_settings_exec(bContext *C, wmOperator *UNUSED(op))
|
2009-10-22 23:22:05 +00:00
|
|
|
{
|
|
|
|
Main *bmain= CTX_data_main(C);
|
|
|
|
ParticleSystem *psys;
|
|
|
|
ParticleSettings *part = NULL;
|
|
|
|
Object *ob;
|
|
|
|
PointerRNA ptr;
|
|
|
|
|
|
|
|
ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
|
|
|
|
|
|
|
|
psys = ptr.data;
|
|
|
|
|
|
|
|
/* add or copy particle setting */
|
2012-03-24 06:38:07 +00:00
|
|
|
if (psys->part)
|
2016-07-10 14:52:00 +02:00
|
|
|
part= BKE_particlesettings_copy(bmain, psys->part);
|
2009-10-22 23:22:05 +00:00
|
|
|
else
|
2018-01-11 09:55:41 +11:00
|
|
|
part= BKE_particlesettings_add(bmain, "ParticleSettings");
|
2009-10-22 23:22:05 +00:00
|
|
|
|
|
|
|
ob= ptr.id.data;
|
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (psys->part)
|
2015-11-09 19:47:10 +01:00
|
|
|
id_us_min(&psys->part->id);
|
2009-10-22 23:22:05 +00:00
|
|
|
|
|
|
|
psys->part = part;
|
|
|
|
|
|
|
|
psys_check_boid_data(psys);
|
|
|
|
|
2013-02-21 19:33:04 +00:00
|
|
|
DAG_relations_tag_update(bmain);
|
2010-12-05 18:59:23 +00:00
|
|
|
DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
|
2009-10-22 23:22:05 +00:00
|
|
|
|
Timeline addition: Display cached frames
This started off doing pointcache debugging but it's also very useful for users too.
Previously it was very hard to see the state of the system when you're working caches
such as physics point cache - is it baked? which frames are cached? is it out of date?
Now, for better feedback, cached frames are drawn for the active object at the bottom
of the timeline - a semitransparent area shows the entire cache extents, and more
solid blocks on top show the frames that are cached. Darker versions indicate it's
using a disk cache.
It can be disabled in general in the timeline View -> Caches menu, or by each individual
system that can be shown.
There's still a bit to do on this, behaviour needs to be clarified still eg. deciding what
shows when it's out of date, or when it's been played back but not cached, etc. etc.
Part of this is due to a lack of definition in the point cache system itself, so we should
try and clean up/clarify this behaviour and what it means to users, at the same time.
Also would be interested in extending this to other caches such as fluid cache,
sequencer memory cache etc. in the future, too.
2010-06-22 02:29:52 +00:00
|
|
|
WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE, ob);
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2009-10-22 23:22:05 +00:00
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PARTICLE_OT_new(wmOperatorType *ot)
|
|
|
|
{
|
|
|
|
/* identifiers */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->name = "New Particle Settings";
|
|
|
|
ot->idname = "PARTICLE_OT_new";
|
|
|
|
ot->description = "Add new particle settings";
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2009-10-22 23:22:05 +00:00
|
|
|
/* api callbacks */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->exec = new_particle_settings_exec;
|
|
|
|
ot->poll = psys_poll;
|
2009-10-22 23:22:05 +00:00
|
|
|
|
|
|
|
/* flags */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
|
2009-10-22 23:22:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/********************** keyed particle target operators *********************/
|
|
|
|
|
2010-10-15 01:36:14 +00:00
|
|
|
static int new_particle_target_exec(bContext *C, wmOperator *UNUSED(op))
|
2009-10-22 23:22:05 +00:00
|
|
|
{
|
2010-08-01 12:47:49 +00:00
|
|
|
Main *bmain = CTX_data_main(C);
|
2009-10-22 23:22:05 +00:00
|
|
|
PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
|
|
|
|
ParticleSystem *psys= ptr.data;
|
|
|
|
Object *ob = ptr.id.data;
|
|
|
|
|
|
|
|
ParticleTarget *pt;
|
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (!psys)
|
2009-10-22 23:22:05 +00:00
|
|
|
return OPERATOR_CANCELLED;
|
|
|
|
|
|
|
|
pt = psys->targets.first;
|
2012-03-24 06:38:07 +00:00
|
|
|
for (; pt; pt=pt->next)
|
2009-10-22 23:22:05 +00:00
|
|
|
pt->flag &= ~PTARGET_CURRENT;
|
|
|
|
|
|
|
|
pt = MEM_callocN(sizeof(ParticleTarget), "keyed particle target");
|
|
|
|
|
|
|
|
pt->flag |= PTARGET_CURRENT;
|
|
|
|
pt->psys = 1;
|
|
|
|
|
|
|
|
BLI_addtail(&psys->targets, pt);
|
|
|
|
|
2013-02-21 19:33:04 +00:00
|
|
|
DAG_relations_tag_update(bmain);
|
2010-12-05 18:59:23 +00:00
|
|
|
DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
|
2009-10-22 23:22:05 +00:00
|
|
|
|
Timeline addition: Display cached frames
This started off doing pointcache debugging but it's also very useful for users too.
Previously it was very hard to see the state of the system when you're working caches
such as physics point cache - is it baked? which frames are cached? is it out of date?
Now, for better feedback, cached frames are drawn for the active object at the bottom
of the timeline - a semitransparent area shows the entire cache extents, and more
solid blocks on top show the frames that are cached. Darker versions indicate it's
using a disk cache.
It can be disabled in general in the timeline View -> Caches menu, or by each individual
system that can be shown.
There's still a bit to do on this, behaviour needs to be clarified still eg. deciding what
shows when it's out of date, or when it's been played back but not cached, etc. etc.
Part of this is due to a lack of definition in the point cache system itself, so we should
try and clean up/clarify this behaviour and what it means to users, at the same time.
Also would be interested in extending this to other caches such as fluid cache,
sequencer memory cache etc. in the future, too.
2010-06-22 02:29:52 +00:00
|
|
|
WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE, ob);
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2009-10-22 23:22:05 +00:00
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PARTICLE_OT_new_target(wmOperatorType *ot)
|
|
|
|
{
|
|
|
|
/* identifiers */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->name = "New Particle Target";
|
|
|
|
ot->idname = "PARTICLE_OT_new_target";
|
|
|
|
ot->description = "Add a new particle target";
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2009-10-22 23:22:05 +00:00
|
|
|
/* api callbacks */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->exec = new_particle_target_exec;
|
2009-10-22 23:22:05 +00:00
|
|
|
|
|
|
|
/* flags */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
|
2009-10-22 23:22:05 +00:00
|
|
|
}
|
|
|
|
|
2010-10-15 01:36:14 +00:00
|
|
|
static int remove_particle_target_exec(bContext *C, wmOperator *UNUSED(op))
|
2009-10-22 23:22:05 +00:00
|
|
|
{
|
2010-08-01 12:47:49 +00:00
|
|
|
Main *bmain = CTX_data_main(C);
|
2009-10-22 23:22:05 +00:00
|
|
|
PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
|
|
|
|
ParticleSystem *psys= ptr.data;
|
|
|
|
Object *ob = ptr.id.data;
|
|
|
|
|
|
|
|
ParticleTarget *pt;
|
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (!psys)
|
2009-10-22 23:22:05 +00:00
|
|
|
return OPERATOR_CANCELLED;
|
|
|
|
|
|
|
|
pt = psys->targets.first;
|
2012-03-24 06:38:07 +00:00
|
|
|
for (; pt; pt=pt->next) {
|
|
|
|
if (pt->flag & PTARGET_CURRENT) {
|
2009-10-22 23:22:05 +00:00
|
|
|
BLI_remlink(&psys->targets, pt);
|
|
|
|
MEM_freeN(pt);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
pt = psys->targets.last;
|
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (pt)
|
2009-10-22 23:22:05 +00:00
|
|
|
pt->flag |= PTARGET_CURRENT;
|
|
|
|
|
2013-02-21 19:33:04 +00:00
|
|
|
DAG_relations_tag_update(bmain);
|
2010-12-05 18:59:23 +00:00
|
|
|
DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
|
2009-10-22 23:22:05 +00:00
|
|
|
|
Timeline addition: Display cached frames
This started off doing pointcache debugging but it's also very useful for users too.
Previously it was very hard to see the state of the system when you're working caches
such as physics point cache - is it baked? which frames are cached? is it out of date?
Now, for better feedback, cached frames are drawn for the active object at the bottom
of the timeline - a semitransparent area shows the entire cache extents, and more
solid blocks on top show the frames that are cached. Darker versions indicate it's
using a disk cache.
It can be disabled in general in the timeline View -> Caches menu, or by each individual
system that can be shown.
There's still a bit to do on this, behaviour needs to be clarified still eg. deciding what
shows when it's out of date, or when it's been played back but not cached, etc. etc.
Part of this is due to a lack of definition in the point cache system itself, so we should
try and clean up/clarify this behaviour and what it means to users, at the same time.
Also would be interested in extending this to other caches such as fluid cache,
sequencer memory cache etc. in the future, too.
2010-06-22 02:29:52 +00:00
|
|
|
WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE, ob);
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2009-10-22 23:22:05 +00:00
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
|
|
|
|
2009-11-28 14:37:21 +00:00
|
|
|
void PARTICLE_OT_target_remove(wmOperatorType *ot)
|
2009-10-22 23:22:05 +00:00
|
|
|
{
|
|
|
|
/* identifiers */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->name = "Remove Particle Target";
|
|
|
|
ot->idname = "PARTICLE_OT_target_remove";
|
|
|
|
ot->description = "Remove the selected particle target";
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2009-10-22 23:22:05 +00:00
|
|
|
/* api callbacks */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->exec = remove_particle_target_exec;
|
2009-10-22 23:22:05 +00:00
|
|
|
|
|
|
|
/* flags */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
|
2009-10-22 23:22:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/************************ move up particle target operator *********************/
|
|
|
|
|
2010-10-15 01:36:14 +00:00
|
|
|
static int target_move_up_exec(bContext *C, wmOperator *UNUSED(op))
|
2009-10-22 23:22:05 +00:00
|
|
|
{
|
|
|
|
PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
|
|
|
|
ParticleSystem *psys= ptr.data;
|
|
|
|
Object *ob = ptr.id.data;
|
|
|
|
ParticleTarget *pt;
|
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (!psys)
|
2009-10-22 23:22:05 +00:00
|
|
|
return OPERATOR_CANCELLED;
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2009-10-22 23:22:05 +00:00
|
|
|
pt = psys->targets.first;
|
2012-03-24 06:38:07 +00:00
|
|
|
for (; pt; pt=pt->next) {
|
|
|
|
if (pt->flag & PTARGET_CURRENT && pt->prev) {
|
2009-10-22 23:22:05 +00:00
|
|
|
BLI_remlink(&psys->targets, pt);
|
2013-02-22 14:12:55 +00:00
|
|
|
BLI_insertlinkbefore(&psys->targets, pt->prev, pt);
|
2009-10-22 23:22:05 +00:00
|
|
|
|
2010-12-05 18:59:23 +00:00
|
|
|
DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
|
Timeline addition: Display cached frames
This started off doing pointcache debugging but it's also very useful for users too.
Previously it was very hard to see the state of the system when you're working caches
such as physics point cache - is it baked? which frames are cached? is it out of date?
Now, for better feedback, cached frames are drawn for the active object at the bottom
of the timeline - a semitransparent area shows the entire cache extents, and more
solid blocks on top show the frames that are cached. Darker versions indicate it's
using a disk cache.
It can be disabled in general in the timeline View -> Caches menu, or by each individual
system that can be shown.
There's still a bit to do on this, behaviour needs to be clarified still eg. deciding what
shows when it's out of date, or when it's been played back but not cached, etc. etc.
Part of this is due to a lack of definition in the point cache system itself, so we should
try and clean up/clarify this behaviour and what it means to users, at the same time.
Also would be interested in extending this to other caches such as fluid cache,
sequencer memory cache etc. in the future, too.
2010-06-22 02:29:52 +00:00
|
|
|
WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE, ob);
|
2009-10-22 23:22:05 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2009-10-22 23:22:05 +00:00
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PARTICLE_OT_target_move_up(wmOperatorType *ot)
|
|
|
|
{
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->name = "Move Up Target";
|
|
|
|
ot->idname = "PARTICLE_OT_target_move_up";
|
|
|
|
ot->description = "Move particle target up in the list";
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->exec = target_move_up_exec;
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2009-10-22 23:22:05 +00:00
|
|
|
/* flags */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
|
2009-10-22 23:22:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/************************ move down particle target operator *********************/
|
|
|
|
|
2010-10-15 01:36:14 +00:00
|
|
|
static int target_move_down_exec(bContext *C, wmOperator *UNUSED(op))
|
2009-10-22 23:22:05 +00:00
|
|
|
{
|
|
|
|
PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
|
|
|
|
ParticleSystem *psys= ptr.data;
|
|
|
|
Object *ob = ptr.id.data;
|
|
|
|
ParticleTarget *pt;
|
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (!psys)
|
2009-10-22 23:22:05 +00:00
|
|
|
return OPERATOR_CANCELLED;
|
|
|
|
pt = psys->targets.first;
|
2012-03-24 06:38:07 +00:00
|
|
|
for (; pt; pt=pt->next) {
|
|
|
|
if (pt->flag & PTARGET_CURRENT && pt->next) {
|
2009-10-22 23:22:05 +00:00
|
|
|
BLI_remlink(&psys->targets, pt);
|
2013-02-22 14:12:55 +00:00
|
|
|
BLI_insertlinkafter(&psys->targets, pt->next, pt);
|
2009-10-22 23:22:05 +00:00
|
|
|
|
2010-12-05 18:59:23 +00:00
|
|
|
DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
|
Timeline addition: Display cached frames
This started off doing pointcache debugging but it's also very useful for users too.
Previously it was very hard to see the state of the system when you're working caches
such as physics point cache - is it baked? which frames are cached? is it out of date?
Now, for better feedback, cached frames are drawn for the active object at the bottom
of the timeline - a semitransparent area shows the entire cache extents, and more
solid blocks on top show the frames that are cached. Darker versions indicate it's
using a disk cache.
It can be disabled in general in the timeline View -> Caches menu, or by each individual
system that can be shown.
There's still a bit to do on this, behaviour needs to be clarified still eg. deciding what
shows when it's out of date, or when it's been played back but not cached, etc. etc.
Part of this is due to a lack of definition in the point cache system itself, so we should
try and clean up/clarify this behaviour and what it means to users, at the same time.
Also would be interested in extending this to other caches such as fluid cache,
sequencer memory cache etc. in the future, too.
2010-06-22 02:29:52 +00:00
|
|
|
WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE, ob);
|
2009-10-22 23:22:05 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2009-10-22 23:22:05 +00:00
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PARTICLE_OT_target_move_down(wmOperatorType *ot)
|
|
|
|
{
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->name = "Move Down Target";
|
|
|
|
ot->idname = "PARTICLE_OT_target_move_down";
|
|
|
|
ot->description = "Move particle target down in the list";
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->exec = target_move_down_exec;
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2009-10-22 23:22:05 +00:00
|
|
|
/* flags */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
|
2009-10-22 23:22:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/************************ move up particle dupliweight operator *********************/
|
|
|
|
|
2010-10-15 01:36:14 +00:00
|
|
|
static int dupliob_move_up_exec(bContext *C, wmOperator *UNUSED(op))
|
2009-10-22 23:22:05 +00:00
|
|
|
{
|
|
|
|
PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
|
|
|
|
ParticleSystem *psys= ptr.data;
|
|
|
|
ParticleSettings *part;
|
|
|
|
ParticleDupliWeight *dw;
|
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (!psys)
|
2009-10-22 23:22:05 +00:00
|
|
|
return OPERATOR_CANCELLED;
|
|
|
|
|
|
|
|
part = psys->part;
|
2012-03-24 06:38:07 +00:00
|
|
|
for (dw=part->dupliweights.first; dw; dw=dw->next) {
|
|
|
|
if (dw->flag & PART_DUPLIW_CURRENT && dw->prev) {
|
2009-10-22 23:22:05 +00:00
|
|
|
BLI_remlink(&part->dupliweights, dw);
|
2013-02-22 14:12:55 +00:00
|
|
|
BLI_insertlinkbefore(&part->dupliweights, dw->prev, dw);
|
2009-10-22 23:22:05 +00:00
|
|
|
|
Timeline addition: Display cached frames
This started off doing pointcache debugging but it's also very useful for users too.
Previously it was very hard to see the state of the system when you're working caches
such as physics point cache - is it baked? which frames are cached? is it out of date?
Now, for better feedback, cached frames are drawn for the active object at the bottom
of the timeline - a semitransparent area shows the entire cache extents, and more
solid blocks on top show the frames that are cached. Darker versions indicate it's
using a disk cache.
It can be disabled in general in the timeline View -> Caches menu, or by each individual
system that can be shown.
There's still a bit to do on this, behaviour needs to be clarified still eg. deciding what
shows when it's out of date, or when it's been played back but not cached, etc. etc.
Part of this is due to a lack of definition in the point cache system itself, so we should
try and clean up/clarify this behaviour and what it means to users, at the same time.
Also would be interested in extending this to other caches such as fluid cache,
sequencer memory cache etc. in the future, too.
2010-06-22 02:29:52 +00:00
|
|
|
WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE, NULL);
|
2009-10-22 23:22:05 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2009-10-22 23:22:05 +00:00
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PARTICLE_OT_dupliob_move_up(wmOperatorType *ot)
|
|
|
|
{
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->name = "Move Up Dupli Object";
|
|
|
|
ot->idname = "PARTICLE_OT_dupliob_move_up";
|
|
|
|
ot->description = "Move dupli object up in the list";
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->exec = dupliob_move_up_exec;
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2009-10-22 23:22:05 +00:00
|
|
|
/* flags */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
|
2009-10-22 23:22:05 +00:00
|
|
|
}
|
|
|
|
|
2009-11-01 00:06:53 +00:00
|
|
|
/********************** particle dupliweight operators *********************/
|
|
|
|
|
2010-10-15 01:36:14 +00:00
|
|
|
static int copy_particle_dupliob_exec(bContext *C, wmOperator *UNUSED(op))
|
2009-11-01 00:06:53 +00:00
|
|
|
{
|
|
|
|
PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
|
|
|
|
ParticleSystem *psys= ptr.data;
|
|
|
|
ParticleSettings *part;
|
|
|
|
ParticleDupliWeight *dw;
|
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (!psys)
|
2009-11-01 00:06:53 +00:00
|
|
|
return OPERATOR_CANCELLED;
|
|
|
|
part = psys->part;
|
2012-03-24 06:38:07 +00:00
|
|
|
for (dw=part->dupliweights.first; dw; dw=dw->next) {
|
|
|
|
if (dw->flag & PART_DUPLIW_CURRENT) {
|
2009-11-01 00:06:53 +00:00
|
|
|
dw->flag &= ~PART_DUPLIW_CURRENT;
|
|
|
|
dw = MEM_dupallocN(dw);
|
|
|
|
dw->flag |= PART_DUPLIW_CURRENT;
|
|
|
|
BLI_addhead(&part->dupliweights, dw);
|
|
|
|
|
Timeline addition: Display cached frames
This started off doing pointcache debugging but it's also very useful for users too.
Previously it was very hard to see the state of the system when you're working caches
such as physics point cache - is it baked? which frames are cached? is it out of date?
Now, for better feedback, cached frames are drawn for the active object at the bottom
of the timeline - a semitransparent area shows the entire cache extents, and more
solid blocks on top show the frames that are cached. Darker versions indicate it's
using a disk cache.
It can be disabled in general in the timeline View -> Caches menu, or by each individual
system that can be shown.
There's still a bit to do on this, behaviour needs to be clarified still eg. deciding what
shows when it's out of date, or when it's been played back but not cached, etc. etc.
Part of this is due to a lack of definition in the point cache system itself, so we should
try and clean up/clarify this behaviour and what it means to users, at the same time.
Also would be interested in extending this to other caches such as fluid cache,
sequencer memory cache etc. in the future, too.
2010-06-22 02:29:52 +00:00
|
|
|
WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE, NULL);
|
2009-11-01 00:06:53 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2009-11-01 00:06:53 +00:00
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PARTICLE_OT_dupliob_copy(wmOperatorType *ot)
|
|
|
|
{
|
|
|
|
/* identifiers */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->name = "Copy Particle Dupliob";
|
|
|
|
ot->idname = "PARTICLE_OT_dupliob_copy";
|
|
|
|
ot->description = "Duplicate the current dupliobject";
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2009-11-01 00:06:53 +00:00
|
|
|
/* api callbacks */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->exec = copy_particle_dupliob_exec;
|
2009-11-01 00:06:53 +00:00
|
|
|
|
|
|
|
/* flags */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
|
2009-11-01 00:06:53 +00:00
|
|
|
}
|
|
|
|
|
2010-10-15 01:36:14 +00:00
|
|
|
static int remove_particle_dupliob_exec(bContext *C, wmOperator *UNUSED(op))
|
2009-11-01 00:06:53 +00:00
|
|
|
{
|
|
|
|
PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
|
|
|
|
ParticleSystem *psys= ptr.data;
|
|
|
|
ParticleSettings *part;
|
|
|
|
ParticleDupliWeight *dw;
|
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (!psys)
|
2009-11-01 00:06:53 +00:00
|
|
|
return OPERATOR_CANCELLED;
|
|
|
|
|
|
|
|
part = psys->part;
|
2012-03-24 06:38:07 +00:00
|
|
|
for (dw=part->dupliweights.first; dw; dw=dw->next) {
|
|
|
|
if (dw->flag & PART_DUPLIW_CURRENT) {
|
2009-11-01 00:06:53 +00:00
|
|
|
BLI_remlink(&part->dupliweights, dw);
|
|
|
|
MEM_freeN(dw);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
dw = part->dupliweights.last;
|
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (dw)
|
2009-11-01 00:06:53 +00:00
|
|
|
dw->flag |= PART_DUPLIW_CURRENT;
|
|
|
|
|
Timeline addition: Display cached frames
This started off doing pointcache debugging but it's also very useful for users too.
Previously it was very hard to see the state of the system when you're working caches
such as physics point cache - is it baked? which frames are cached? is it out of date?
Now, for better feedback, cached frames are drawn for the active object at the bottom
of the timeline - a semitransparent area shows the entire cache extents, and more
solid blocks on top show the frames that are cached. Darker versions indicate it's
using a disk cache.
It can be disabled in general in the timeline View -> Caches menu, or by each individual
system that can be shown.
There's still a bit to do on this, behaviour needs to be clarified still eg. deciding what
shows when it's out of date, or when it's been played back but not cached, etc. etc.
Part of this is due to a lack of definition in the point cache system itself, so we should
try and clean up/clarify this behaviour and what it means to users, at the same time.
Also would be interested in extending this to other caches such as fluid cache,
sequencer memory cache etc. in the future, too.
2010-06-22 02:29:52 +00:00
|
|
|
WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE, NULL);
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2009-11-01 00:06:53 +00:00
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PARTICLE_OT_dupliob_remove(wmOperatorType *ot)
|
|
|
|
{
|
|
|
|
/* identifiers */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->name = "Remove Particle Dupliobject";
|
|
|
|
ot->idname = "PARTICLE_OT_dupliob_remove";
|
|
|
|
ot->description = "Remove the selected dupliobject";
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2009-11-01 00:06:53 +00:00
|
|
|
/* api callbacks */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->exec = remove_particle_dupliob_exec;
|
2009-11-01 00:06:53 +00:00
|
|
|
|
|
|
|
/* flags */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
|
2009-11-01 00:06:53 +00:00
|
|
|
}
|
|
|
|
|
2009-10-22 23:22:05 +00:00
|
|
|
/************************ move down particle dupliweight operator *********************/
|
|
|
|
|
2010-10-15 01:36:14 +00:00
|
|
|
static int dupliob_move_down_exec(bContext *C, wmOperator *UNUSED(op))
|
2009-10-22 23:22:05 +00:00
|
|
|
{
|
|
|
|
PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
|
|
|
|
ParticleSystem *psys= ptr.data;
|
|
|
|
ParticleSettings *part;
|
|
|
|
ParticleDupliWeight *dw;
|
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (!psys)
|
2009-10-22 23:22:05 +00:00
|
|
|
return OPERATOR_CANCELLED;
|
|
|
|
|
|
|
|
part = psys->part;
|
2012-03-24 06:38:07 +00:00
|
|
|
for (dw=part->dupliweights.first; dw; dw=dw->next) {
|
|
|
|
if (dw->flag & PART_DUPLIW_CURRENT && dw->next) {
|
2009-10-22 23:22:05 +00:00
|
|
|
BLI_remlink(&part->dupliweights, dw);
|
2013-02-22 14:12:55 +00:00
|
|
|
BLI_insertlinkafter(&part->dupliweights, dw->next, dw);
|
2009-10-22 23:22:05 +00:00
|
|
|
|
Timeline addition: Display cached frames
This started off doing pointcache debugging but it's also very useful for users too.
Previously it was very hard to see the state of the system when you're working caches
such as physics point cache - is it baked? which frames are cached? is it out of date?
Now, for better feedback, cached frames are drawn for the active object at the bottom
of the timeline - a semitransparent area shows the entire cache extents, and more
solid blocks on top show the frames that are cached. Darker versions indicate it's
using a disk cache.
It can be disabled in general in the timeline View -> Caches menu, or by each individual
system that can be shown.
There's still a bit to do on this, behaviour needs to be clarified still eg. deciding what
shows when it's out of date, or when it's been played back but not cached, etc. etc.
Part of this is due to a lack of definition in the point cache system itself, so we should
try and clean up/clarify this behaviour and what it means to users, at the same time.
Also would be interested in extending this to other caches such as fluid cache,
sequencer memory cache etc. in the future, too.
2010-06-22 02:29:52 +00:00
|
|
|
WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE, NULL);
|
2009-10-22 23:22:05 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2009-10-22 23:22:05 +00:00
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PARTICLE_OT_dupliob_move_down(wmOperatorType *ot)
|
|
|
|
{
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->name = "Move Down Dupli Object";
|
|
|
|
ot->idname = "PARTICLE_OT_dupliob_move_down";
|
|
|
|
ot->description = "Move dupli object down in the list";
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->exec = dupliob_move_down_exec;
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2009-10-22 23:22:05 +00:00
|
|
|
/* flags */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
|
2009-10-22 23:22:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/************************ connect/disconnect hair operators *********************/
|
|
|
|
|
2018-06-13 14:26:26 +02:00
|
|
|
static void disconnect_hair(Main *bmain, Scene *scene, Object *ob, ParticleSystem *psys)
|
2009-10-22 23:22:05 +00:00
|
|
|
{
|
2012-04-29 15:47:02 +00:00
|
|
|
ParticleSystemModifierData *psmd = psys_get_modifier(ob, psys);
|
2010-03-09 03:42:20 +00:00
|
|
|
ParticleEditSettings *pset= PE_settings(scene);
|
2009-10-22 23:22:05 +00:00
|
|
|
ParticleData *pa;
|
|
|
|
PTCacheEdit *edit;
|
|
|
|
PTCacheEditPoint *point;
|
|
|
|
PTCacheEditKey *ekey = NULL;
|
|
|
|
HairKey *key;
|
|
|
|
int i, k;
|
|
|
|
float hairmat[4][4];
|
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (!ob || !psys || psys->flag & PSYS_GLOBAL_HAIR)
|
2009-10-22 23:22:05 +00:00
|
|
|
return;
|
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (!psys->part || psys->part->type != PART_HAIR)
|
2009-10-22 23:22:05 +00:00
|
|
|
return;
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2009-10-22 23:22:05 +00:00
|
|
|
edit = psys->edit;
|
|
|
|
point= edit ? edit->points : NULL;
|
|
|
|
|
2012-04-29 15:47:02 +00:00
|
|
|
for (i=0, pa=psys->particles; i<psys->totpart; i++, pa++) {
|
2012-03-24 06:38:07 +00:00
|
|
|
if (point) {
|
2009-10-22 23:22:05 +00:00
|
|
|
ekey = point->keys;
|
|
|
|
point++;
|
|
|
|
}
|
|
|
|
|
Fix T47038: Particles in Particle Edit Mode get added in completely wrong location.
It also fixes another issue (crash) related to symmetric editing.
Quite involved, we (try to!) fix complete broken logic of parts of particle code, which would use poly index
as tessface one (or vice-versa). Issue most probably goes back to BMesh integration time...
This patch mostly fixes particle editing mode:
- Adding/removing particles when using generative modifiers (like subsurf) should now work.
- Adding/removing particles with a non-tessellated mesh (i.e. one having ngons) should also mostly work.
- X-axis-mirror-editing particles over ngons does not really work, not sure why currently.
- All this in both 'modes' (with or without using modifier stack for particles).
Tech side:
- Store a deformed-only DM in particle modifier data.
- Rename existing DM to make it clear it's a final one.
- Use deformed-only DM's tessface2poly mapping to 'solve' poly/tessface mismatches.
- Make (part of) mirror-editing code able to use a DM instead of raw mesh, so that we can mirror based on final DM
when editing particles using modifier stack (mandatory, since there is no way currently to find orig tessface
from an final DM tessface index).
Note that this patch is not really nice and clean (current particles are beyond hope on this side anyway),
it's more like some urgency bandage. Whole crap needs complete rewrite anyway,
BMesh's polygons make it really hard to work with current system (and looptri would not help much here).
Also, did not test everything possibly affected by those changes, so it needs some users' testing & validation too.
Reviewers: psy-fi
Subscribers: dfelinto, eyecandy
Maniphest Tasks: T47038
Differential Revision: https://developer.blender.org/D1685
2016-01-04 12:19:45 +01:00
|
|
|
psys_mat_hair_to_global(ob, psmd->dm_final, psys->part->from, pa, hairmat);
|
2009-10-22 23:22:05 +00:00
|
|
|
|
2012-04-29 15:47:02 +00:00
|
|
|
for (k=0, key=pa->hair; k<pa->totkey; k++, key++) {
|
|
|
|
mul_m4_v3(hairmat, key->co);
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (ekey) {
|
2009-10-22 23:22:05 +00:00
|
|
|
ekey->flag &= ~PEK_USE_WCO;
|
|
|
|
ekey++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
psys_free_path_cache(psys, psys->edit);
|
|
|
|
|
|
|
|
psys->flag |= PSYS_GLOBAL_HAIR;
|
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (ELEM(pset->brushtype, PE_BRUSH_ADD, PE_BRUSH_PUFF))
|
2010-03-09 03:42:20 +00:00
|
|
|
pset->brushtype = PE_BRUSH_NONE;
|
|
|
|
|
2018-06-13 14:26:26 +02:00
|
|
|
PE_update_object(bmain, scene, ob, 0);
|
2009-10-22 23:22:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int disconnect_hair_exec(bContext *C, wmOperator *op)
|
|
|
|
{
|
2018-06-13 14:26:26 +02:00
|
|
|
Main *bmain = CTX_data_main(C);
|
2009-10-22 23:22:05 +00:00
|
|
|
Scene *scene= CTX_data_scene(C);
|
2012-01-02 17:15:24 +00:00
|
|
|
Object *ob= ED_object_context(C);
|
2009-10-22 23:22:05 +00:00
|
|
|
ParticleSystem *psys= NULL;
|
2014-02-03 18:55:59 +11:00
|
|
|
const bool all = RNA_boolean_get(op->ptr, "all");
|
2009-10-22 23:22:05 +00:00
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (!ob)
|
2009-10-22 23:22:05 +00:00
|
|
|
return OPERATOR_CANCELLED;
|
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (all) {
|
|
|
|
for (psys=ob->particlesystem.first; psys; psys=psys->next) {
|
2018-06-13 14:26:26 +02:00
|
|
|
disconnect_hair(bmain, scene, ob, psys);
|
2009-10-22 23:22:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
2016-03-12 18:55:49 +01:00
|
|
|
psys = psys_get_current(ob);
|
2018-06-13 14:26:26 +02:00
|
|
|
disconnect_hair(bmain, scene, ob, psys);
|
2009-10-22 23:22:05 +00:00
|
|
|
}
|
|
|
|
|
2010-12-05 18:59:23 +00:00
|
|
|
DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
|
Timeline addition: Display cached frames
This started off doing pointcache debugging but it's also very useful for users too.
Previously it was very hard to see the state of the system when you're working caches
such as physics point cache - is it baked? which frames are cached? is it out of date?
Now, for better feedback, cached frames are drawn for the active object at the bottom
of the timeline - a semitransparent area shows the entire cache extents, and more
solid blocks on top show the frames that are cached. Darker versions indicate it's
using a disk cache.
It can be disabled in general in the timeline View -> Caches menu, or by each individual
system that can be shown.
There's still a bit to do on this, behaviour needs to be clarified still eg. deciding what
shows when it's out of date, or when it's been played back but not cached, etc. etc.
Part of this is due to a lack of definition in the point cache system itself, so we should
try and clean up/clarify this behaviour and what it means to users, at the same time.
Also would be interested in extending this to other caches such as fluid cache,
sequencer memory cache etc. in the future, too.
2010-06-22 02:29:52 +00:00
|
|
|
WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE, ob);
|
2009-10-22 23:22:05 +00:00
|
|
|
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PARTICLE_OT_disconnect_hair(wmOperatorType *ot)
|
|
|
|
{
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->name = "Disconnect Hair";
|
|
|
|
ot->description = "Disconnect hair from the emitter mesh";
|
|
|
|
ot->idname = "PARTICLE_OT_disconnect_hair";
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->exec = disconnect_hair_exec;
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2009-10-22 23:22:05 +00:00
|
|
|
/* flags */
|
2016-03-14 21:04:30 +01:00
|
|
|
ot->flag = OPTYPE_UNDO; /* No REGISTER, redo does not work due to missing update, see T47750. */
|
2009-10-22 23:22:05 +00:00
|
|
|
|
|
|
|
RNA_def_boolean(ot->srna, "all", 0, "All hair", "Disconnect all hair systems from the emitter mesh");
|
|
|
|
}
|
|
|
|
|
2015-01-15 20:36:51 +01:00
|
|
|
/* from/to_world_space : whether from/to particles are in world or hair space
|
|
|
|
* from/to_mat : additional transform for from/to particles (e.g. for using object space copying)
|
|
|
|
*/
|
2018-06-13 14:26:26 +02:00
|
|
|
static bool remap_hair_emitter(Main *bmain, Scene *scene, Object *ob, ParticleSystem *psys,
|
2015-01-15 18:15:52 +01:00
|
|
|
Object *target_ob, ParticleSystem *target_psys, PTCacheEdit *target_edit,
|
2015-01-26 14:37:13 +01:00
|
|
|
float from_mat[4][4], float to_mat[4][4], bool from_global, bool to_global)
|
2009-10-22 23:22:05 +00:00
|
|
|
{
|
2015-01-15 18:15:52 +01:00
|
|
|
ParticleSystemModifierData *target_psmd = psys_get_modifier(target_ob, target_psys);
|
2015-01-15 11:51:30 +01:00
|
|
|
ParticleData *pa, *tpa;
|
|
|
|
PTCacheEditPoint *edit_point;
|
|
|
|
PTCacheEditKey *ekey;
|
2011-03-05 10:29:10 +00:00
|
|
|
BVHTreeFromMesh bvhtree= {NULL};
|
2014-06-17 14:58:23 +06:00
|
|
|
MFace *mface = NULL, *mf;
|
|
|
|
MEdge *medge = NULL, *me;
|
2013-06-03 03:47:41 +00:00
|
|
|
MVert *mvert;
|
2015-01-15 18:15:52 +01:00
|
|
|
DerivedMesh *dm, *target_dm;
|
2009-10-22 23:22:05 +00:00
|
|
|
int numverts;
|
|
|
|
int i, k;
|
2015-01-15 20:36:51 +01:00
|
|
|
float from_ob_imat[4][4], to_ob_imat[4][4];
|
|
|
|
float from_imat[4][4], to_imat[4][4];
|
2009-10-22 23:22:05 +00:00
|
|
|
|
Fix T47038: Particles in Particle Edit Mode get added in completely wrong location.
It also fixes another issue (crash) related to symmetric editing.
Quite involved, we (try to!) fix complete broken logic of parts of particle code, which would use poly index
as tessface one (or vice-versa). Issue most probably goes back to BMesh integration time...
This patch mostly fixes particle editing mode:
- Adding/removing particles when using generative modifiers (like subsurf) should now work.
- Adding/removing particles with a non-tessellated mesh (i.e. one having ngons) should also mostly work.
- X-axis-mirror-editing particles over ngons does not really work, not sure why currently.
- All this in both 'modes' (with or without using modifier stack for particles).
Tech side:
- Store a deformed-only DM in particle modifier data.
- Rename existing DM to make it clear it's a final one.
- Use deformed-only DM's tessface2poly mapping to 'solve' poly/tessface mismatches.
- Make (part of) mirror-editing code able to use a DM instead of raw mesh, so that we can mirror based on final DM
when editing particles using modifier stack (mandatory, since there is no way currently to find orig tessface
from an final DM tessface index).
Note that this patch is not really nice and clean (current particles are beyond hope on this side anyway),
it's more like some urgency bandage. Whole crap needs complete rewrite anyway,
BMesh's polygons make it really hard to work with current system (and looptri would not help much here).
Also, did not test everything possibly affected by those changes, so it needs some users' testing & validation too.
Reviewers: psy-fi
Subscribers: dfelinto, eyecandy
Maniphest Tasks: T47038
Differential Revision: https://developer.blender.org/D1685
2016-01-04 12:19:45 +01:00
|
|
|
if (!target_psmd->dm_final)
|
2015-01-15 18:15:52 +01:00
|
|
|
return false;
|
|
|
|
if (!psys->part || psys->part->type != PART_HAIR)
|
|
|
|
return false;
|
|
|
|
if (!target_psys->part || target_psys->part->type != PART_HAIR)
|
2014-04-01 11:34:00 +11:00
|
|
|
return false;
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2015-01-15 11:51:30 +01:00
|
|
|
edit_point = target_edit ? target_edit->points : NULL;
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2015-01-15 20:36:51 +01:00
|
|
|
invert_m4_m4(from_ob_imat, ob->obmat);
|
|
|
|
invert_m4_m4(to_ob_imat, target_ob->obmat);
|
|
|
|
invert_m4_m4(from_imat, from_mat);
|
|
|
|
invert_m4_m4(to_imat, to_mat);
|
2018-06-04 09:31:30 +02:00
|
|
|
|
Fix T47038: Particles in Particle Edit Mode get added in completely wrong location.
It also fixes another issue (crash) related to symmetric editing.
Quite involved, we (try to!) fix complete broken logic of parts of particle code, which would use poly index
as tessface one (or vice-versa). Issue most probably goes back to BMesh integration time...
This patch mostly fixes particle editing mode:
- Adding/removing particles when using generative modifiers (like subsurf) should now work.
- Adding/removing particles with a non-tessellated mesh (i.e. one having ngons) should also mostly work.
- X-axis-mirror-editing particles over ngons does not really work, not sure why currently.
- All this in both 'modes' (with or without using modifier stack for particles).
Tech side:
- Store a deformed-only DM in particle modifier data.
- Rename existing DM to make it clear it's a final one.
- Use deformed-only DM's tessface2poly mapping to 'solve' poly/tessface mismatches.
- Make (part of) mirror-editing code able to use a DM instead of raw mesh, so that we can mirror based on final DM
when editing particles using modifier stack (mandatory, since there is no way currently to find orig tessface
from an final DM tessface index).
Note that this patch is not really nice and clean (current particles are beyond hope on this side anyway),
it's more like some urgency bandage. Whole crap needs complete rewrite anyway,
BMesh's polygons make it really hard to work with current system (and looptri would not help much here).
Also, did not test everything possibly affected by those changes, so it needs some users' testing & validation too.
Reviewers: psy-fi
Subscribers: dfelinto, eyecandy
Maniphest Tasks: T47038
Differential Revision: https://developer.blender.org/D1685
2016-01-04 12:19:45 +01:00
|
|
|
if (target_psmd->dm_final->deformedOnly) {
|
2015-01-15 18:15:52 +01:00
|
|
|
/* we don't want to mess up target_psmd->dm when converting to global coordinates below */
|
Fix T47038: Particles in Particle Edit Mode get added in completely wrong location.
It also fixes another issue (crash) related to symmetric editing.
Quite involved, we (try to!) fix complete broken logic of parts of particle code, which would use poly index
as tessface one (or vice-versa). Issue most probably goes back to BMesh integration time...
This patch mostly fixes particle editing mode:
- Adding/removing particles when using generative modifiers (like subsurf) should now work.
- Adding/removing particles with a non-tessellated mesh (i.e. one having ngons) should also mostly work.
- X-axis-mirror-editing particles over ngons does not really work, not sure why currently.
- All this in both 'modes' (with or without using modifier stack for particles).
Tech side:
- Store a deformed-only DM in particle modifier data.
- Rename existing DM to make it clear it's a final one.
- Use deformed-only DM's tessface2poly mapping to 'solve' poly/tessface mismatches.
- Make (part of) mirror-editing code able to use a DM instead of raw mesh, so that we can mirror based on final DM
when editing particles using modifier stack (mandatory, since there is no way currently to find orig tessface
from an final DM tessface index).
Note that this patch is not really nice and clean (current particles are beyond hope on this side anyway),
it's more like some urgency bandage. Whole crap needs complete rewrite anyway,
BMesh's polygons make it really hard to work with current system (and looptri would not help much here).
Also, did not test everything possibly affected by those changes, so it needs some users' testing & validation too.
Reviewers: psy-fi
Subscribers: dfelinto, eyecandy
Maniphest Tasks: T47038
Differential Revision: https://developer.blender.org/D1685
2016-01-04 12:19:45 +01:00
|
|
|
dm = target_psmd->dm_final;
|
2013-06-03 03:47:41 +00:00
|
|
|
}
|
|
|
|
else {
|
Fix T47038: Particles in Particle Edit Mode get added in completely wrong location.
It also fixes another issue (crash) related to symmetric editing.
Quite involved, we (try to!) fix complete broken logic of parts of particle code, which would use poly index
as tessface one (or vice-versa). Issue most probably goes back to BMesh integration time...
This patch mostly fixes particle editing mode:
- Adding/removing particles when using generative modifiers (like subsurf) should now work.
- Adding/removing particles with a non-tessellated mesh (i.e. one having ngons) should also mostly work.
- X-axis-mirror-editing particles over ngons does not really work, not sure why currently.
- All this in both 'modes' (with or without using modifier stack for particles).
Tech side:
- Store a deformed-only DM in particle modifier data.
- Rename existing DM to make it clear it's a final one.
- Use deformed-only DM's tessface2poly mapping to 'solve' poly/tessface mismatches.
- Make (part of) mirror-editing code able to use a DM instead of raw mesh, so that we can mirror based on final DM
when editing particles using modifier stack (mandatory, since there is no way currently to find orig tessface
from an final DM tessface index).
Note that this patch is not really nice and clean (current particles are beyond hope on this side anyway),
it's more like some urgency bandage. Whole crap needs complete rewrite anyway,
BMesh's polygons make it really hard to work with current system (and looptri would not help much here).
Also, did not test everything possibly affected by those changes, so it needs some users' testing & validation too.
Reviewers: psy-fi
Subscribers: dfelinto, eyecandy
Maniphest Tasks: T47038
Differential Revision: https://developer.blender.org/D1685
2016-01-04 12:19:45 +01:00
|
|
|
dm = target_psmd->dm_deformed;
|
2013-06-03 03:47:41 +00:00
|
|
|
}
|
Fix T47038: Particles in Particle Edit Mode get added in completely wrong location.
It also fixes another issue (crash) related to symmetric editing.
Quite involved, we (try to!) fix complete broken logic of parts of particle code, which would use poly index
as tessface one (or vice-versa). Issue most probably goes back to BMesh integration time...
This patch mostly fixes particle editing mode:
- Adding/removing particles when using generative modifiers (like subsurf) should now work.
- Adding/removing particles with a non-tessellated mesh (i.e. one having ngons) should also mostly work.
- X-axis-mirror-editing particles over ngons does not really work, not sure why currently.
- All this in both 'modes' (with or without using modifier stack for particles).
Tech side:
- Store a deformed-only DM in particle modifier data.
- Rename existing DM to make it clear it's a final one.
- Use deformed-only DM's tessface2poly mapping to 'solve' poly/tessface mismatches.
- Make (part of) mirror-editing code able to use a DM instead of raw mesh, so that we can mirror based on final DM
when editing particles using modifier stack (mandatory, since there is no way currently to find orig tessface
from an final DM tessface index).
Note that this patch is not really nice and clean (current particles are beyond hope on this side anyway),
it's more like some urgency bandage. Whole crap needs complete rewrite anyway,
BMesh's polygons make it really hard to work with current system (and looptri would not help much here).
Also, did not test everything possibly affected by those changes, so it needs some users' testing & validation too.
Reviewers: psy-fi
Subscribers: dfelinto, eyecandy
Maniphest Tasks: T47038
Differential Revision: https://developer.blender.org/D1685
2016-01-04 12:19:45 +01:00
|
|
|
target_dm = target_psmd->dm_final;
|
2016-09-23 15:39:33 +02:00
|
|
|
if (dm == NULL) {
|
|
|
|
return false;
|
|
|
|
}
|
2013-06-03 03:47:41 +00:00
|
|
|
/* don't modify the original vertices */
|
|
|
|
dm = CDDM_copy(dm);
|
2009-10-22 23:22:05 +00:00
|
|
|
|
2012-01-19 19:23:25 +00:00
|
|
|
/* BMESH_ONLY, deform dm may not have tessface */
|
|
|
|
DM_ensure_tessface(dm);
|
|
|
|
|
2013-04-18 01:52:38 +00:00
|
|
|
numverts = dm->getNumVerts(dm);
|
2013-06-03 03:47:41 +00:00
|
|
|
mvert = dm->getVertArray(dm);
|
|
|
|
|
2009-10-22 23:22:05 +00:00
|
|
|
/* convert to global coordinates */
|
|
|
|
for (i=0; i<numverts; i++)
|
2015-01-15 20:36:51 +01:00
|
|
|
mul_m4_v3(to_mat, mvert[i].co);
|
2009-10-22 23:22:05 +00:00
|
|
|
|
2014-06-17 14:58:23 +06:00
|
|
|
if (dm->getNumTessFaces(dm) != 0) {
|
|
|
|
mface = dm->getTessFaceArray(dm);
|
2018-05-03 14:26:39 -03:00
|
|
|
bvhtree_from_mesh_get(&bvhtree, dm, BVHTREE_FROM_FACES, 2);
|
2014-06-17 14:58:23 +06:00
|
|
|
}
|
|
|
|
else if (dm->getNumEdges(dm) != 0) {
|
|
|
|
medge = dm->getEdgeArray(dm);
|
2018-05-03 14:26:39 -03:00
|
|
|
bvhtree_from_mesh_get(&bvhtree, dm, BVHTREE_FROM_EDGES, 2);
|
2014-06-17 14:58:23 +06:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
dm->release(dm);
|
|
|
|
return false;
|
|
|
|
}
|
2009-10-22 23:22:05 +00:00
|
|
|
|
2015-01-15 11:51:30 +01:00
|
|
|
for (i = 0, tpa = target_psys->particles, pa = psys->particles;
|
|
|
|
i < target_psys->totpart;
|
2018-04-16 18:13:48 +02:00
|
|
|
i++, tpa++, pa++)
|
|
|
|
{
|
2015-01-15 20:36:51 +01:00
|
|
|
float from_co[3];
|
2015-01-15 11:51:30 +01:00
|
|
|
BVHTreeNearest nearest;
|
2009-10-22 23:22:05 +00:00
|
|
|
|
2015-01-26 14:37:13 +01:00
|
|
|
if (from_global)
|
2015-01-15 20:36:51 +01:00
|
|
|
mul_v3_m4v3(from_co, from_ob_imat, pa->hair[0].co);
|
|
|
|
else
|
|
|
|
mul_v3_m4v3(from_co, from_ob_imat, pa->hair[0].world_co);
|
|
|
|
mul_m4_v3(from_mat, from_co);
|
|
|
|
|
2009-10-22 23:22:05 +00:00
|
|
|
nearest.index = -1;
|
2014-02-03 02:46:45 +11:00
|
|
|
nearest.dist_sq = FLT_MAX;
|
2009-10-22 23:22:05 +00:00
|
|
|
|
2015-01-15 20:36:51 +01:00
|
|
|
BLI_bvhtree_find_nearest(bvhtree.tree, from_co, &nearest, bvhtree.nearest_callback, &bvhtree);
|
2009-10-22 23:22:05 +00:00
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (nearest.index == -1) {
|
2012-03-31 00:59:17 +00:00
|
|
|
if (G.debug & G_DEBUG)
|
2010-01-22 06:48:29 +00:00
|
|
|
printf("No nearest point found for hair root!");
|
2009-10-22 23:22:05 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2014-06-17 14:58:23 +06:00
|
|
|
if (mface) {
|
2015-01-15 11:51:30 +01:00
|
|
|
float v[4][3];
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2014-06-17 14:58:23 +06:00
|
|
|
mf = &mface[nearest.index];
|
|
|
|
|
|
|
|
copy_v3_v3(v[0], mvert[mf->v1].co);
|
|
|
|
copy_v3_v3(v[1], mvert[mf->v2].co);
|
|
|
|
copy_v3_v3(v[2], mvert[mf->v3].co);
|
|
|
|
if (mf->v4) {
|
|
|
|
copy_v3_v3(v[3], mvert[mf->v4].co);
|
2015-01-15 11:51:30 +01:00
|
|
|
interp_weights_poly_v3(tpa->fuv, v, 4, nearest.co);
|
2014-06-17 14:58:23 +06:00
|
|
|
}
|
|
|
|
else
|
2015-01-15 11:51:30 +01:00
|
|
|
interp_weights_poly_v3(tpa->fuv, v, 3, nearest.co);
|
|
|
|
tpa->foffset = 0.0f;
|
2014-06-17 14:58:23 +06:00
|
|
|
|
2015-01-15 11:51:30 +01:00
|
|
|
tpa->num = nearest.index;
|
Fix T47038: Particles in Particle Edit Mode get added in completely wrong location.
It also fixes another issue (crash) related to symmetric editing.
Quite involved, we (try to!) fix complete broken logic of parts of particle code, which would use poly index
as tessface one (or vice-versa). Issue most probably goes back to BMesh integration time...
This patch mostly fixes particle editing mode:
- Adding/removing particles when using generative modifiers (like subsurf) should now work.
- Adding/removing particles with a non-tessellated mesh (i.e. one having ngons) should also mostly work.
- X-axis-mirror-editing particles over ngons does not really work, not sure why currently.
- All this in both 'modes' (with or without using modifier stack for particles).
Tech side:
- Store a deformed-only DM in particle modifier data.
- Rename existing DM to make it clear it's a final one.
- Use deformed-only DM's tessface2poly mapping to 'solve' poly/tessface mismatches.
- Make (part of) mirror-editing code able to use a DM instead of raw mesh, so that we can mirror based on final DM
when editing particles using modifier stack (mandatory, since there is no way currently to find orig tessface
from an final DM tessface index).
Note that this patch is not really nice and clean (current particles are beyond hope on this side anyway),
it's more like some urgency bandage. Whole crap needs complete rewrite anyway,
BMesh's polygons make it really hard to work with current system (and looptri would not help much here).
Also, did not test everything possibly affected by those changes, so it needs some users' testing & validation too.
Reviewers: psy-fi
Subscribers: dfelinto, eyecandy
Maniphest Tasks: T47038
Differential Revision: https://developer.blender.org/D1685
2016-01-04 12:19:45 +01:00
|
|
|
tpa->num_dmcache = psys_particle_dm_face_lookup(target_dm, dm, tpa->num, tpa->fuv, NULL);
|
2014-06-17 14:58:23 +06:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
me = &medge[nearest.index];
|
|
|
|
|
2015-01-15 11:51:30 +01:00
|
|
|
tpa->fuv[1] = line_point_factor_v3(nearest.co,
|
|
|
|
mvert[me->v1].co,
|
|
|
|
mvert[me->v2].co);
|
|
|
|
tpa->fuv[0] = 1.0f - tpa->fuv[1];
|
|
|
|
tpa->fuv[2] = tpa->fuv[3] = 0.0f;
|
|
|
|
tpa->foffset = 0.0f;
|
2009-10-22 23:22:05 +00:00
|
|
|
|
2015-01-15 11:51:30 +01:00
|
|
|
tpa->num = nearest.index;
|
|
|
|
tpa->num_dmcache = -1;
|
2009-10-22 23:22:05 +00:00
|
|
|
}
|
|
|
|
|
2015-01-15 11:51:30 +01:00
|
|
|
/* translate hair keys */
|
|
|
|
{
|
|
|
|
HairKey *key, *tkey;
|
|
|
|
float hairmat[4][4], imat[4][4];
|
|
|
|
float offset[3];
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2015-01-26 14:37:13 +01:00
|
|
|
if (to_global)
|
2015-01-15 20:36:51 +01:00
|
|
|
copy_m4_m4(imat, target_ob->obmat);
|
|
|
|
else {
|
|
|
|
/* note: using target_dm here, which is in target_ob object space and has full modifiers */
|
|
|
|
psys_mat_hair_to_object(target_ob, target_dm, target_psys->part->from, tpa, hairmat);
|
|
|
|
invert_m4_m4(imat, hairmat);
|
|
|
|
}
|
|
|
|
mul_m4_m4m4(imat, imat, to_imat);
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2015-01-15 11:51:30 +01:00
|
|
|
/* offset in world space */
|
2015-01-15 20:36:51 +01:00
|
|
|
sub_v3_v3v3(offset, nearest.co, from_co);
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2015-01-15 11:51:30 +01:00
|
|
|
if (edit_point) {
|
|
|
|
for (k=0, key=pa->hair, tkey=tpa->hair, ekey = edit_point->keys; k<tpa->totkey; k++, key++, tkey++, ekey++) {
|
2015-01-15 20:36:51 +01:00
|
|
|
float co_orig[3];
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2015-01-26 14:37:13 +01:00
|
|
|
if (from_global)
|
2015-01-15 20:36:51 +01:00
|
|
|
mul_v3_m4v3(co_orig, from_ob_imat, key->co);
|
|
|
|
else
|
|
|
|
mul_v3_m4v3(co_orig, from_ob_imat, key->world_co);
|
|
|
|
mul_m4_v3(from_mat, co_orig);
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2015-01-15 11:51:30 +01:00
|
|
|
add_v3_v3v3(tkey->co, co_orig, offset);
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2015-01-15 20:36:51 +01:00
|
|
|
mul_m4_v3(imat, tkey->co);
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2015-01-15 11:51:30 +01:00
|
|
|
ekey->flag |= PEK_USE_WCO;
|
|
|
|
}
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2015-01-15 11:51:30 +01:00
|
|
|
edit_point++;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
for (k=0, key=pa->hair, tkey=tpa->hair; k<tpa->totkey; k++, key++, tkey++) {
|
2015-01-15 20:36:51 +01:00
|
|
|
float co_orig[3];
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2015-01-26 14:37:13 +01:00
|
|
|
if (from_global)
|
2015-01-15 20:36:51 +01:00
|
|
|
mul_v3_m4v3(co_orig, from_ob_imat, key->co);
|
|
|
|
else
|
|
|
|
mul_v3_m4v3(co_orig, from_ob_imat, key->world_co);
|
|
|
|
mul_m4_v3(from_mat, co_orig);
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2015-01-15 11:51:30 +01:00
|
|
|
add_v3_v3v3(tkey->co, co_orig, offset);
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2015-01-15 20:36:51 +01:00
|
|
|
mul_m4_v3(imat, tkey->co);
|
2015-01-15 11:51:30 +01:00
|
|
|
}
|
2009-10-22 23:22:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
free_bvhtree_from_mesh(&bvhtree);
|
2010-09-08 08:36:12 +00:00
|
|
|
dm->release(dm);
|
2009-10-22 23:22:05 +00:00
|
|
|
|
2015-01-15 11:51:30 +01:00
|
|
|
psys_free_path_cache(target_psys, target_edit);
|
2009-10-22 23:22:05 +00:00
|
|
|
|
2018-06-13 14:26:26 +02:00
|
|
|
PE_update_object(bmain, scene, target_ob, 0);
|
2012-12-21 09:27:39 +00:00
|
|
|
|
2014-04-01 11:34:00 +11:00
|
|
|
return true;
|
2009-10-22 23:22:05 +00:00
|
|
|
}
|
|
|
|
|
2018-06-13 14:26:26 +02:00
|
|
|
static bool connect_hair(Main *bmain, Scene *scene, Object *ob, ParticleSystem *psys)
|
2015-01-15 11:51:30 +01:00
|
|
|
{
|
2015-01-26 14:37:13 +01:00
|
|
|
bool ok;
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2015-01-15 11:51:30 +01:00
|
|
|
if (!psys)
|
|
|
|
return false;
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2018-06-13 14:26:26 +02:00
|
|
|
ok = remap_hair_emitter(bmain, scene, ob, psys, ob, psys, psys->edit,
|
|
|
|
ob->obmat, ob->obmat, psys->flag & PSYS_GLOBAL_HAIR, false);
|
2015-01-15 11:51:30 +01:00
|
|
|
psys->flag &= ~PSYS_GLOBAL_HAIR;
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2015-01-26 14:37:13 +01:00
|
|
|
return ok;
|
2015-01-15 11:51:30 +01:00
|
|
|
}
|
|
|
|
|
2009-10-22 23:22:05 +00:00
|
|
|
static int connect_hair_exec(bContext *C, wmOperator *op)
|
|
|
|
{
|
2018-06-13 14:26:26 +02:00
|
|
|
Main *bmain = CTX_data_main(C);
|
2009-10-22 23:22:05 +00:00
|
|
|
Scene *scene= CTX_data_scene(C);
|
2012-01-02 17:15:24 +00:00
|
|
|
Object *ob= ED_object_context(C);
|
2009-10-22 23:22:05 +00:00
|
|
|
ParticleSystem *psys= NULL;
|
2014-02-03 18:55:59 +11:00
|
|
|
const bool all = RNA_boolean_get(op->ptr, "all");
|
2014-04-01 11:34:00 +11:00
|
|
|
bool any_connected = false;
|
2009-10-22 23:22:05 +00:00
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (!ob)
|
2009-10-22 23:22:05 +00:00
|
|
|
return OPERATOR_CANCELLED;
|
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (all) {
|
|
|
|
for (psys=ob->particlesystem.first; psys; psys=psys->next) {
|
2018-06-13 14:26:26 +02:00
|
|
|
any_connected |= connect_hair(bmain, scene, ob, psys);
|
2009-10-22 23:22:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
2016-03-14 21:04:30 +01:00
|
|
|
psys = psys_get_current(ob);
|
2018-06-13 14:26:26 +02:00
|
|
|
any_connected |= connect_hair(bmain, scene, ob, psys);
|
2012-12-21 09:27:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!any_connected) {
|
2016-03-14 21:04:30 +01:00
|
|
|
BKE_report(op->reports, RPT_WARNING,
|
|
|
|
"No hair connected (can't connect hair if particle system modifier is disabled)");
|
2012-12-21 09:27:39 +00:00
|
|
|
return OPERATOR_CANCELLED;
|
2009-10-22 23:22:05 +00:00
|
|
|
}
|
|
|
|
|
2010-12-05 18:59:23 +00:00
|
|
|
DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
|
Timeline addition: Display cached frames
This started off doing pointcache debugging but it's also very useful for users too.
Previously it was very hard to see the state of the system when you're working caches
such as physics point cache - is it baked? which frames are cached? is it out of date?
Now, for better feedback, cached frames are drawn for the active object at the bottom
of the timeline - a semitransparent area shows the entire cache extents, and more
solid blocks on top show the frames that are cached. Darker versions indicate it's
using a disk cache.
It can be disabled in general in the timeline View -> Caches menu, or by each individual
system that can be shown.
There's still a bit to do on this, behaviour needs to be clarified still eg. deciding what
shows when it's out of date, or when it's been played back but not cached, etc. etc.
Part of this is due to a lack of definition in the point cache system itself, so we should
try and clean up/clarify this behaviour and what it means to users, at the same time.
Also would be interested in extending this to other caches such as fluid cache,
sequencer memory cache etc. in the future, too.
2010-06-22 02:29:52 +00:00
|
|
|
WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE, ob);
|
2009-10-22 23:22:05 +00:00
|
|
|
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PARTICLE_OT_connect_hair(wmOperatorType *ot)
|
|
|
|
{
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->name = "Connect Hair";
|
|
|
|
ot->description = "Connect hair to the emitter mesh";
|
|
|
|
ot->idname = "PARTICLE_OT_connect_hair";
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->exec = connect_hair_exec;
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2009-10-22 23:22:05 +00:00
|
|
|
/* flags */
|
2016-03-14 21:04:30 +01:00
|
|
|
ot->flag = OPTYPE_UNDO; /* No REGISTER, redo does not work due to missing update, see T47750. */
|
2009-10-22 23:22:05 +00:00
|
|
|
|
|
|
|
RNA_def_boolean(ot->srna, "all", 0, "All hair", "Connect all hair systems to the emitter mesh");
|
|
|
|
}
|
|
|
|
|
2015-01-15 11:51:30 +01:00
|
|
|
/************************ particle system copy operator *********************/
|
|
|
|
|
2015-01-15 20:36:51 +01:00
|
|
|
typedef enum eCopyParticlesSpace {
|
|
|
|
PAR_COPY_SPACE_OBJECT = 0,
|
|
|
|
PAR_COPY_SPACE_WORLD = 1,
|
|
|
|
} eCopyParticlesSpace;
|
|
|
|
|
2018-06-13 14:26:26 +02:00
|
|
|
static void copy_particle_edit(Main *bmain, Scene *scene, Object *ob, ParticleSystem *psys, ParticleSystem *psys_from)
|
2015-01-15 11:51:30 +01:00
|
|
|
{
|
|
|
|
PTCacheEdit *edit_from = psys_from->edit, *edit;
|
|
|
|
ParticleData *pa;
|
|
|
|
KEY_K;
|
|
|
|
POINT_P;
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2015-01-15 11:51:30 +01:00
|
|
|
if (!edit_from)
|
|
|
|
return;
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2015-01-15 11:51:30 +01:00
|
|
|
edit = MEM_dupallocN(edit_from);
|
|
|
|
edit->psys = psys;
|
|
|
|
psys->edit = edit;
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2015-01-15 11:51:30 +01:00
|
|
|
edit->pathcache = NULL;
|
|
|
|
BLI_listbase_clear(&edit->pathcachebufs);
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2015-01-15 11:51:30 +01:00
|
|
|
edit->emitter_field = NULL;
|
|
|
|
edit->emitter_cosnos = NULL;
|
2018-03-19 14:17:59 +01:00
|
|
|
|
2015-01-15 11:51:30 +01:00
|
|
|
edit->points = MEM_dupallocN(edit_from->points);
|
|
|
|
pa = psys->particles;
|
|
|
|
LOOP_POINTS {
|
|
|
|
HairKey *hkey = pa->hair;
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2015-01-15 11:51:30 +01:00
|
|
|
point->keys= MEM_dupallocN(point->keys);
|
|
|
|
LOOP_KEYS {
|
|
|
|
key->co = hkey->co;
|
|
|
|
key->time = &hkey->time;
|
|
|
|
key->flag = hkey->editflag;
|
|
|
|
if (!(psys->flag & PSYS_GLOBAL_HAIR)) {
|
|
|
|
key->flag |= PEK_USE_WCO;
|
|
|
|
hkey->editflag |= PEK_USE_WCO;
|
|
|
|
}
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2015-01-15 11:51:30 +01:00
|
|
|
hkey++;
|
|
|
|
}
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2015-01-15 11:51:30 +01:00
|
|
|
pa++;
|
|
|
|
}
|
|
|
|
update_world_cos(ob, edit);
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2015-01-15 11:51:30 +01:00
|
|
|
UI_GetThemeColor3ubv(TH_EDGE_SELECT, edit->sel_col);
|
|
|
|
UI_GetThemeColor3ubv(TH_WIRE, edit->nosel_col);
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2015-01-15 11:51:30 +01:00
|
|
|
recalc_lengths(edit);
|
|
|
|
recalc_emitter_field(ob, psys);
|
2018-06-13 14:26:26 +02:00
|
|
|
PE_update_object(bmain, scene, ob, true);
|
2015-01-15 11:51:30 +01:00
|
|
|
}
|
|
|
|
|
2015-01-16 11:07:00 +01:00
|
|
|
static void remove_particle_systems_from_object(Object *ob_to)
|
2015-01-15 11:51:30 +01:00
|
|
|
{
|
|
|
|
ModifierData *md, *md_next;
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2015-01-15 12:35:19 +01:00
|
|
|
if (ob_to->type != OB_MESH)
|
2015-01-16 11:07:00 +01:00
|
|
|
return;
|
2017-11-06 17:17:10 +01:00
|
|
|
if (!ob_to->data || ID_IS_LINKED(ob_to->data))
|
2015-01-16 11:07:00 +01:00
|
|
|
return;
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2015-01-15 11:51:30 +01:00
|
|
|
for (md = ob_to->modifiers.first; md; md = md_next) {
|
|
|
|
md_next = md->next;
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2015-01-15 11:51:30 +01:00
|
|
|
/* remove all particle system modifiers as well,
|
|
|
|
* these need to sync to the particle system list
|
|
|
|
*/
|
|
|
|
if (ELEM(md->type, eModifierType_ParticleSystem, eModifierType_DynamicPaint, eModifierType_Smoke)) {
|
|
|
|
BLI_remlink(&ob_to->modifiers, md);
|
|
|
|
modifier_free(md);
|
|
|
|
}
|
|
|
|
}
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2015-01-15 11:51:30 +01:00
|
|
|
BKE_object_free_particlesystems(ob_to);
|
2015-01-16 11:07:00 +01:00
|
|
|
}
|
|
|
|
|
2015-01-16 11:42:13 +01:00
|
|
|
/* single_psys_from is optional, if NULL all psys of ob_from are copied */
|
2016-09-23 15:33:07 +02:00
|
|
|
static bool copy_particle_systems_to_object(Main *bmain,
|
|
|
|
Scene *scene,
|
|
|
|
Object *ob_from,
|
|
|
|
ParticleSystem *single_psys_from,
|
|
|
|
Object *ob_to,
|
|
|
|
int space,
|
|
|
|
bool duplicate_settings)
|
2015-01-16 11:07:00 +01:00
|
|
|
{
|
|
|
|
ModifierData *md;
|
2015-08-21 14:46:30 +10:00
|
|
|
ParticleSystem *psys_start = NULL, *psys, *psys_from;
|
2015-01-16 11:07:00 +01:00
|
|
|
ParticleSystem **tmp_psys;
|
|
|
|
DerivedMesh *final_dm;
|
|
|
|
CustomDataMask cdmask;
|
|
|
|
int i, totpsys;
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2015-01-16 11:07:00 +01:00
|
|
|
if (ob_to->type != OB_MESH)
|
|
|
|
return false;
|
2017-11-06 17:17:10 +01:00
|
|
|
if (!ob_to->data || ID_IS_LINKED(ob_to->data))
|
2015-01-16 11:07:00 +01:00
|
|
|
return false;
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2015-01-15 11:51:30 +01:00
|
|
|
/* For remapping we need a valid DM.
|
2015-01-16 11:07:00 +01:00
|
|
|
* Because the modifiers are appended at the end it's safe to use
|
|
|
|
* the final DM of the object without particles.
|
|
|
|
* However, when evaluating the DM all the particle modifiers must be valid,
|
|
|
|
* i.e. have the psys assigned already.
|
|
|
|
* To break this hen/egg problem we create all psys separately first (to collect required customdata masks),
|
|
|
|
* then create the DM, then add them to the object and make the psys modifiers ...
|
2015-01-15 11:51:30 +01:00
|
|
|
*/
|
2015-01-16 11:42:13 +01:00
|
|
|
#define PSYS_FROM_FIRST (single_psys_from ? single_psys_from : ob_from->particlesystem.first)
|
|
|
|
#define PSYS_FROM_NEXT(cur) (single_psys_from ? NULL : (cur)->next)
|
|
|
|
totpsys = single_psys_from ? 1 : BLI_listbase_count(&ob_from->particlesystem);
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2015-01-16 11:07:00 +01:00
|
|
|
tmp_psys = MEM_mallocN(sizeof(ParticleSystem*) * totpsys, "temporary particle system array");
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2015-01-15 18:15:52 +01:00
|
|
|
cdmask = 0;
|
2015-01-16 11:42:13 +01:00
|
|
|
for (psys_from = PSYS_FROM_FIRST, i = 0;
|
|
|
|
psys_from;
|
2018-04-16 18:13:48 +02:00
|
|
|
psys_from = PSYS_FROM_NEXT(psys_from), ++i)
|
|
|
|
{
|
Refactor ID copying (and to some extent, ID freeing).
This will allow much finer controll over how we copy data-blocks, from
full copy in Main database, to "lighter" ones (out of Main, inside an
already allocated datablock, etc.).
This commit also transfers a llot of what was previously handled by
per-ID-type custom code to generic ID handling code in BKE_library.
Hopefully will avoid in future inconsistencies and missing bits we had
all over the codebase in the past.
It also adds missing copying handling for a few types, most notably
Scene (which where using a fully customized handling previously).
Note that the type of allocation used during copying (regular in Main,
allocated but outside of Main, or not allocated by ID handling code at
all) is stored in ID's, which allows to handle them correctly when
freeing. This needs to be taken care of with caution when doing 'weird'
unusual things with ID copying and/or allocation!
As a final note, while rather noisy, this commit will hopefully not
break too much existing branches, old 'API' has been kept for the main
part, as a wrapper around new code. Cleaning it up will happen later.
Design task : T51804
Phab Diff: D2714
2017-08-07 16:39:55 +02:00
|
|
|
psys = BKE_object_copy_particlesystem(psys_from, 0);
|
2015-01-16 11:07:00 +01:00
|
|
|
tmp_psys[i] = psys;
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2015-01-16 11:07:00 +01:00
|
|
|
if (psys_start == NULL)
|
|
|
|
psys_start = psys;
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2015-01-15 18:15:52 +01:00
|
|
|
cdmask |= psys_emitter_customdata_mask(psys);
|
|
|
|
}
|
2015-01-16 11:07:00 +01:00
|
|
|
/* to iterate source and target psys in sync,
|
|
|
|
* we need to know where the newly added psys start
|
|
|
|
*/
|
|
|
|
psys_start = totpsys > 0 ? tmp_psys[0] : NULL;
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2015-01-16 11:07:00 +01:00
|
|
|
/* get the DM (psys and their modifiers have not been appended yet) */
|
2015-01-15 18:15:52 +01:00
|
|
|
final_dm = mesh_get_derived_final(scene, ob_to, cdmask);
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2015-01-16 11:07:00 +01:00
|
|
|
/* now append psys to the object and make modifiers */
|
2015-01-16 11:42:13 +01:00
|
|
|
for (i = 0, psys_from = PSYS_FROM_FIRST;
|
2015-01-16 11:07:00 +01:00
|
|
|
i < totpsys;
|
2018-04-16 18:13:48 +02:00
|
|
|
++i, psys_from = PSYS_FROM_NEXT(psys_from))
|
|
|
|
{
|
2015-01-15 11:51:30 +01:00
|
|
|
ParticleSystemModifierData *psmd;
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2015-01-16 11:07:00 +01:00
|
|
|
psys = tmp_psys[i];
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2015-01-16 11:07:00 +01:00
|
|
|
/* append to the object */
|
|
|
|
BLI_addtail(&ob_to->particlesystem, psys);
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2015-01-15 11:51:30 +01:00
|
|
|
/* add a particle system modifier for each system */
|
|
|
|
md = modifier_new(eModifierType_ParticleSystem);
|
|
|
|
psmd = (ParticleSystemModifierData *)md;
|
|
|
|
/* push on top of the stack, no use trying to reproduce old stack order */
|
|
|
|
BLI_addtail(&ob_to->modifiers, md);
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2015-01-15 11:51:30 +01:00
|
|
|
BLI_snprintf(md->name, sizeof(md->name), "ParticleSystem %i", i);
|
|
|
|
modifier_unique_name(&ob_to->modifiers, (ModifierData *)psmd);
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2015-01-15 11:51:30 +01:00
|
|
|
psmd->psys = psys;
|
Fix T47038: Particles in Particle Edit Mode get added in completely wrong location.
It also fixes another issue (crash) related to symmetric editing.
Quite involved, we (try to!) fix complete broken logic of parts of particle code, which would use poly index
as tessface one (or vice-versa). Issue most probably goes back to BMesh integration time...
This patch mostly fixes particle editing mode:
- Adding/removing particles when using generative modifiers (like subsurf) should now work.
- Adding/removing particles with a non-tessellated mesh (i.e. one having ngons) should also mostly work.
- X-axis-mirror-editing particles over ngons does not really work, not sure why currently.
- All this in both 'modes' (with or without using modifier stack for particles).
Tech side:
- Store a deformed-only DM in particle modifier data.
- Rename existing DM to make it clear it's a final one.
- Use deformed-only DM's tessface2poly mapping to 'solve' poly/tessface mismatches.
- Make (part of) mirror-editing code able to use a DM instead of raw mesh, so that we can mirror based on final DM
when editing particles using modifier stack (mandatory, since there is no way currently to find orig tessface
from an final DM tessface index).
Note that this patch is not really nice and clean (current particles are beyond hope on this side anyway),
it's more like some urgency bandage. Whole crap needs complete rewrite anyway,
BMesh's polygons make it really hard to work with current system (and looptri would not help much here).
Also, did not test everything possibly affected by those changes, so it needs some users' testing & validation too.
Reviewers: psy-fi
Subscribers: dfelinto, eyecandy
Maniphest Tasks: T47038
Differential Revision: https://developer.blender.org/D1685
2016-01-04 12:19:45 +01:00
|
|
|
psmd->dm_final = CDDM_copy(final_dm);
|
|
|
|
CDDM_calc_normals(psmd->dm_final);
|
|
|
|
DM_ensure_tessface(psmd->dm_final);
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2015-01-15 11:51:30 +01:00
|
|
|
if (psys_from->edit)
|
2018-06-13 14:26:26 +02:00
|
|
|
copy_particle_edit(bmain, scene, ob_to, psys, psys_from);
|
2016-09-23 15:33:07 +02:00
|
|
|
|
|
|
|
if (duplicate_settings) {
|
2016-09-23 15:39:33 +02:00
|
|
|
id_us_min(&psys->part->id);
|
2016-09-23 15:33:07 +02:00
|
|
|
psys->part = BKE_particlesettings_copy(bmain, psys->part);
|
|
|
|
}
|
2015-01-15 18:15:52 +01:00
|
|
|
}
|
2015-01-16 11:07:00 +01:00
|
|
|
MEM_freeN(tmp_psys);
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2015-01-15 18:15:52 +01:00
|
|
|
/* note: do this after creating DM copies for all the particle system modifiers,
|
|
|
|
* the remapping otherwise makes final_dm invalid!
|
|
|
|
*/
|
2015-01-16 11:42:13 +01:00
|
|
|
for (psys = psys_start, psys_from = PSYS_FROM_FIRST, i = 0;
|
2015-01-15 18:15:52 +01:00
|
|
|
psys;
|
2018-04-16 18:13:48 +02:00
|
|
|
psys = psys->next, psys_from = PSYS_FROM_NEXT(psys_from), ++i)
|
|
|
|
{
|
2015-01-15 20:36:51 +01:00
|
|
|
float (*from_mat)[4], (*to_mat)[4];
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2015-01-15 20:36:51 +01:00
|
|
|
switch (space) {
|
|
|
|
case PAR_COPY_SPACE_OBJECT:
|
|
|
|
from_mat = I;
|
|
|
|
to_mat = I;
|
|
|
|
break;
|
|
|
|
case PAR_COPY_SPACE_WORLD:
|
|
|
|
from_mat = ob_from->obmat;
|
|
|
|
to_mat = ob_to->obmat;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
/* should not happen */
|
2015-08-12 22:17:27 +02:00
|
|
|
from_mat = to_mat = NULL;
|
2015-01-15 20:36:51 +01:00
|
|
|
BLI_assert(false);
|
|
|
|
break;
|
|
|
|
}
|
2016-09-23 14:51:42 +02:00
|
|
|
if (ob_from != ob_to) {
|
2018-06-13 14:26:26 +02:00
|
|
|
remap_hair_emitter(
|
|
|
|
bmain, scene, ob_from, psys_from, ob_to, psys, psys->edit,
|
|
|
|
from_mat, to_mat, psys_from->flag & PSYS_GLOBAL_HAIR, psys->flag & PSYS_GLOBAL_HAIR);
|
2016-09-23 14:51:42 +02:00
|
|
|
}
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2015-01-15 11:51:30 +01:00
|
|
|
/* tag for recalc */
|
2015-01-15 18:15:52 +01:00
|
|
|
// psys->recalc |= PSYS_RECALC_RESET;
|
2015-01-15 11:51:30 +01:00
|
|
|
}
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2015-01-16 11:42:13 +01:00
|
|
|
#undef PSYS_FROM_FIRST
|
|
|
|
#undef PSYS_FROM_NEXT
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2015-01-15 11:51:30 +01:00
|
|
|
DAG_id_tag_update(&ob_to->id, OB_RECALC_DATA);
|
|
|
|
WM_main_add_notifier(NC_OBJECT | ND_PARTICLE | NA_EDITED, ob_to);
|
2015-01-15 12:35:19 +01:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-07-02 11:47:00 +02:00
|
|
|
static bool copy_particle_systems_poll(bContext *C)
|
2015-01-15 12:35:19 +01:00
|
|
|
{
|
|
|
|
Object *ob;
|
|
|
|
if (!ED_operator_object_active_editable(C))
|
|
|
|
return false;
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2015-01-15 12:35:19 +01:00
|
|
|
ob = ED_object_active_context(C);
|
|
|
|
if (BLI_listbase_is_empty(&ob->particlesystem))
|
|
|
|
return false;
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2015-01-15 12:35:19 +01:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int copy_particle_systems_exec(bContext *C, wmOperator *op)
|
|
|
|
{
|
2015-01-15 20:36:51 +01:00
|
|
|
const int space = RNA_enum_get(op->ptr, "space");
|
2015-01-16 11:07:00 +01:00
|
|
|
const bool remove_target_particles = RNA_boolean_get(op->ptr, "remove_target_particles");
|
2015-01-16 11:42:13 +01:00
|
|
|
const bool use_active = RNA_boolean_get(op->ptr, "use_active");
|
2016-09-23 15:33:07 +02:00
|
|
|
Main *bmain = CTX_data_main(C);
|
2015-01-16 11:42:13 +01:00
|
|
|
Scene *scene = CTX_data_scene(C);
|
|
|
|
Object *ob_from = ED_object_active_context(C);
|
|
|
|
ParticleSystem *psys_from = use_active ? CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem).data : NULL;
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2015-01-15 12:35:19 +01:00
|
|
|
int changed_tot = 0;
|
|
|
|
int fail = 0;
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2015-01-15 12:35:19 +01:00
|
|
|
CTX_DATA_BEGIN (C, Object *, ob_to, selected_editable_objects)
|
|
|
|
{
|
|
|
|
if (ob_from != ob_to) {
|
2015-01-16 11:07:00 +01:00
|
|
|
bool changed = false;
|
|
|
|
if (remove_target_particles) {
|
|
|
|
remove_particle_systems_from_object(ob_to);
|
|
|
|
changed = true;
|
|
|
|
}
|
2016-09-23 15:33:07 +02:00
|
|
|
if (copy_particle_systems_to_object(bmain, scene, ob_from, psys_from, ob_to, space, false))
|
2015-01-16 11:07:00 +01:00
|
|
|
changed = true;
|
2015-01-15 12:35:19 +01:00
|
|
|
else
|
|
|
|
fail++;
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2015-01-16 11:07:00 +01:00
|
|
|
if (changed)
|
|
|
|
changed_tot++;
|
2015-01-15 12:35:19 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
CTX_DATA_END;
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2015-01-15 12:35:19 +01:00
|
|
|
if ((changed_tot == 0 && fail == 0) || fail) {
|
|
|
|
BKE_reportf(op->reports, RPT_ERROR,
|
|
|
|
"Copy particle systems to selected: %d done, %d failed",
|
|
|
|
changed_tot, fail);
|
|
|
|
}
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2015-01-15 11:51:30 +01:00
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PARTICLE_OT_copy_particle_systems(wmOperatorType *ot)
|
|
|
|
{
|
2017-10-18 15:07:26 +11:00
|
|
|
static const EnumPropertyItem space_items[] = {
|
2015-01-15 20:36:51 +01:00
|
|
|
{PAR_COPY_SPACE_OBJECT, "OBJECT", 0, "Object", "Copy inside each object's local space"},
|
|
|
|
{PAR_COPY_SPACE_WORLD, "WORLD", 0, "World", "Copy in world space"},
|
|
|
|
{0, NULL, 0, NULL, NULL}
|
|
|
|
};
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2015-01-15 11:51:30 +01:00
|
|
|
ot->name = "Copy Particle Systems";
|
2015-01-15 12:35:19 +01:00
|
|
|
ot->description = "Copy particle systems from the active object to selected objects";
|
2015-01-15 11:51:30 +01:00
|
|
|
ot->idname = "PARTICLE_OT_copy_particle_systems";
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2015-01-15 12:35:19 +01:00
|
|
|
ot->poll = copy_particle_systems_poll;
|
2015-01-15 11:51:30 +01:00
|
|
|
ot->exec = copy_particle_systems_exec;
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2015-01-15 11:51:30 +01:00
|
|
|
/* flags */
|
|
|
|
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2015-01-15 20:36:51 +01:00
|
|
|
RNA_def_enum(ot->srna, "space", space_items, PAR_COPY_SPACE_OBJECT, "Space", "Space transform for copying from one object to another");
|
2015-01-16 11:07:00 +01:00
|
|
|
RNA_def_boolean(ot->srna, "remove_target_particles", true, "Remove Target Particles", "Remove particle systems on the target objects");
|
2015-01-16 11:42:13 +01:00
|
|
|
RNA_def_boolean(ot->srna, "use_active", false, "Use Active", "Use the active particle system from the context");
|
2015-01-15 11:51:30 +01:00
|
|
|
}
|
2016-09-23 14:32:14 +02:00
|
|
|
|
2018-07-02 11:47:00 +02:00
|
|
|
static bool duplicate_particle_systems_poll(bContext *C)
|
2016-09-23 14:32:14 +02:00
|
|
|
{
|
|
|
|
if (!ED_operator_object_active_editable(C)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
Object *ob = ED_object_active_context(C);
|
|
|
|
if (BLI_listbase_is_empty(&ob->particlesystem)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-09-23 15:33:07 +02:00
|
|
|
static int duplicate_particle_systems_exec(bContext *C, wmOperator *op)
|
2016-09-23 14:32:14 +02:00
|
|
|
{
|
2016-09-23 15:33:07 +02:00
|
|
|
const bool duplicate_settings = RNA_boolean_get(op->ptr, "use_duplicate_settings");
|
2016-09-23 14:32:14 +02:00
|
|
|
Scene *scene = CTX_data_scene(C);
|
|
|
|
Object *ob = ED_object_active_context(C);
|
|
|
|
ParticleSystem *psys = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem).data;
|
2016-09-23 15:33:07 +02:00
|
|
|
copy_particle_systems_to_object(CTX_data_main(C), scene, ob, psys, ob,
|
|
|
|
PAR_COPY_SPACE_OBJECT, duplicate_settings);
|
2016-09-23 14:32:14 +02:00
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PARTICLE_OT_duplicate_particle_system(wmOperatorType *ot)
|
|
|
|
{
|
|
|
|
ot->name = "Duplicate Particle Systems";
|
|
|
|
ot->description = "Duplicate particle system within the active object";
|
|
|
|
ot->idname = "PARTICLE_OT_duplicate_particle_system";
|
|
|
|
|
|
|
|
ot->poll = duplicate_particle_systems_poll;
|
|
|
|
ot->exec = duplicate_particle_systems_exec;
|
|
|
|
|
|
|
|
/* flags */
|
|
|
|
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
2016-09-23 15:33:07 +02:00
|
|
|
|
|
|
|
RNA_def_boolean(ot->srna, "use_duplicate_settings", false, "Duplicate Settings",
|
|
|
|
"Duplicate settings as well, so new particle system uses own settings");
|
2016-09-23 14:32:14 +02:00
|
|
|
}
|