2009-02-20 20:39:27 +00:00
|
|
|
/*
|
2009-04-20 15:06:46 +00:00
|
|
|
* $Id$
|
2009-01-24 13:45:24 +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
|
|
|
|
* of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* 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-01-24 13:45:24 +00:00
|
|
|
*
|
|
|
|
* The Original Code is Copyright (C) 2007 by Janne Karhu.
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* The Original Code is: all of this file.
|
|
|
|
*
|
|
|
|
* Contributor(s): none yet.
|
|
|
|
*
|
|
|
|
* ***** END GPL LICENSE BLOCK *****
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <math.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
|
|
|
|
#include "DNA_scene_types.h"
|
|
|
|
#include "DNA_mesh_types.h"
|
|
|
|
#include "DNA_meshdata_types.h"
|
|
|
|
#include "DNA_view3d_types.h"
|
|
|
|
#include "DNA_screen_types.h"
|
|
|
|
#include "DNA_space_types.h"
|
|
|
|
|
|
|
|
#include "BKE_DerivedMesh.h"
|
|
|
|
#include "BKE_depsgraph.h"
|
|
|
|
|
|
|
|
#include "BKE_context.h"
|
|
|
|
#include "BKE_global.h"
|
|
|
|
#include "BKE_object.h"
|
|
|
|
#include "BKE_mesh.h"
|
|
|
|
#include "BKE_modifier.h"
|
|
|
|
#include "BKE_particle.h"
|
2009-02-20 20:39:27 +00:00
|
|
|
#include "BKE_report.h"
|
2009-01-24 13:45:24 +00:00
|
|
|
#include "BKE_scene.h"
|
2009-08-29 15:20:36 +00:00
|
|
|
#include "BKE_utildefines.h"
|
|
|
|
#include "BKE_pointcache.h"
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-11-10 20:43:45 +00:00
|
|
|
#include "BLI_math.h"
|
2009-01-24 13:45:24 +00:00
|
|
|
#include "BLI_blenlib.h"
|
|
|
|
#include "BLI_dynstr.h"
|
|
|
|
#include "BLI_kdtree.h"
|
|
|
|
#include "BLI_rand.h"
|
|
|
|
|
|
|
|
|
|
|
|
#include "BIF_gl.h"
|
|
|
|
#include "BIF_glutil.h"
|
|
|
|
|
2009-02-25 19:29:58 +00:00
|
|
|
#include "ED_mesh.h"
|
2009-02-20 20:39:27 +00:00
|
|
|
#include "ED_particle.h"
|
2009-01-24 13:45:24 +00:00
|
|
|
#include "ED_view3d.h"
|
|
|
|
|
|
|
|
#include "UI_resources.h"
|
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
#include "WM_api.h"
|
|
|
|
#include "WM_types.h"
|
|
|
|
|
|
|
|
#include "RNA_access.h"
|
|
|
|
#include "RNA_define.h"
|
|
|
|
|
2009-01-24 13:45:24 +00:00
|
|
|
#include "physics_intern.h"
|
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
static void PE_create_particle_edit(Scene *scene, Object *ob, PointCache *cache, ParticleSystem *psys);
|
|
|
|
static void PTCacheUndo_clear(PTCacheEdit *edit);
|
2010-01-12 13:20:49 +00:00
|
|
|
static void recalc_emitter_field(Object *ob, ParticleSystem *psys);
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
#define KEY_K PTCacheEditKey *key; int k
|
|
|
|
#define POINT_P PTCacheEditPoint *point; int p
|
|
|
|
#define LOOP_POINTS for(p=0, point=edit->points; p<edit->totpoint; p++, point++)
|
|
|
|
#define LOOP_VISIBLE_POINTS for(p=0, point=edit->points; p<edit->totpoint; p++, point++) if(!(point->flag & PEP_HIDE))
|
|
|
|
#define LOOP_SELECTED_POINTS for(p=0, point=edit->points; p<edit->totpoint; p++, point++) if(point_is_selected(point))
|
|
|
|
#define LOOP_UNSELECTED_POINTS for(p=0, point=edit->points; p<edit->totpoint; p++, point++) if(!point_is_selected(point))
|
|
|
|
#define LOOP_EDITED_POINTS for(p=0, point=edit->points; p<edit->totpoint; p++, point++) if(point->flag & PEP_EDIT_RECALC)
|
|
|
|
#define LOOP_TAGGED_POINTS for(p=0, point=edit->points; p<edit->totpoint; p++, point++) if(point->flag & PEP_TAG)
|
|
|
|
#define LOOP_KEYS for(k=0, key=point->keys; k<point->totkey; k++, key++)
|
|
|
|
#define LOOP_VISIBLE_KEYS for(k=0, key=point->keys; k<point->totkey; k++, key++) if(!(key->flag & PEK_HIDE))
|
|
|
|
#define LOOP_SELECTED_KEYS for(k=0, key=point->keys; k<point->totkey; k++, key++) if((key->flag & PEK_SELECT) && !(key->flag & PEK_HIDE))
|
|
|
|
#define LOOP_TAGGED_KEYS for(k=0, key=point->keys; k<point->totkey; k++, key++) if(key->flag & PEK_TAG)
|
|
|
|
|
|
|
|
#define KEY_WCO (key->flag & PEK_USE_WCO ? key->world_co : key->co)
|
2009-02-20 20:39:27 +00:00
|
|
|
|
|
|
|
/**************************** utilities *******************************/
|
|
|
|
|
Sorry, three commits in one, became difficult to untangle..
Editors Modules
* render/ module added in editors, moved the preview render code there and
also shading related operators.
* physics/ module made more consistent with other modules. renaming files,
making a single physics_ops.c for operators and keymaps. Also move all
particle related operators here now.
* space_buttons/ now should have only operators relevant to the buttons
specificially.
Updates & Notifiers
* Material/Texture/World/Lamp can now be passed to DAG_id_flush_update,
which will go back to a callback in editors. Eventually these should
be in the depsgraph itself, but for now this gives a unified call for
doing updates.
* GLSL materials are now refreshed on changes. There's still various
cases missing,
* Preview icons now hook into this system, solving various update cases
that were missed before.
* Also fixes issue in my last commit, where some preview would not render,
problem is avoided in the new system.
Icon Rendering
* On systems with support for non-power of two textures, an OpenGL texture
is now used instead of glDrawPixels. This avoids problems with icons get
clipped on region borders. On my Linux desktop, this gives an 1.1x speedup,
and on my Mac laptop a 2.3x speedup overall in redrawing the full window,
with the default setup. The glDrawPixels implementation on Mac seems to
have a lot of overhread.
* Preview icons are now drawn using proper premul alpha, and never faded so
you can see them clearly.
* Also tried to fix issue with texture node preview rendering, globals can't
be used with threads reliably.
2009-09-29 19:12:12 +00:00
|
|
|
int PE_poll(bContext *C)
|
2009-02-20 20:39:27 +00:00
|
|
|
{
|
|
|
|
Scene *scene= CTX_data_scene(C);
|
|
|
|
Object *ob= CTX_data_active_object(C);
|
|
|
|
|
2009-10-01 16:30:05 +00:00
|
|
|
if(!scene || !ob || !(ob->mode & OB_MODE_PARTICLE_EDIT))
|
2009-02-20 20:39:27 +00:00
|
|
|
return 0;
|
|
|
|
|
2009-10-01 16:30:05 +00:00
|
|
|
return (PE_get_current(scene, ob) != NULL);
|
2009-02-20 20:39:27 +00:00
|
|
|
}
|
|
|
|
|
Sorry, three commits in one, became difficult to untangle..
Editors Modules
* render/ module added in editors, moved the preview render code there and
also shading related operators.
* physics/ module made more consistent with other modules. renaming files,
making a single physics_ops.c for operators and keymaps. Also move all
particle related operators here now.
* space_buttons/ now should have only operators relevant to the buttons
specificially.
Updates & Notifiers
* Material/Texture/World/Lamp can now be passed to DAG_id_flush_update,
which will go back to a callback in editors. Eventually these should
be in the depsgraph itself, but for now this gives a unified call for
doing updates.
* GLSL materials are now refreshed on changes. There's still various
cases missing,
* Preview icons now hook into this system, solving various update cases
that were missed before.
* Also fixes issue in my last commit, where some preview would not render,
problem is avoided in the new system.
Icon Rendering
* On systems with support for non-power of two textures, an OpenGL texture
is now used instead of glDrawPixels. This avoids problems with icons get
clipped on region borders. On my Linux desktop, this gives an 1.1x speedup,
and on my Mac laptop a 2.3x speedup overall in redrawing the full window,
with the default setup. The glDrawPixels implementation on Mac seems to
have a lot of overhread.
* Preview icons are now drawn using proper premul alpha, and never faded so
you can see them clearly.
* Also tried to fix issue with texture node preview rendering, globals can't
be used with threads reliably.
2009-09-29 19:12:12 +00:00
|
|
|
int PE_hair_poll(bContext *C)
|
2009-09-10 22:32:33 +00:00
|
|
|
{
|
|
|
|
Scene *scene= CTX_data_scene(C);
|
|
|
|
Object *ob= CTX_data_active_object(C);
|
|
|
|
PTCacheEdit *edit;
|
|
|
|
|
2009-10-01 16:30:05 +00:00
|
|
|
if(!scene || !ob || !(ob->mode & OB_MODE_PARTICLE_EDIT))
|
2009-09-10 22:32:33 +00:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
edit= PE_get_current(scene, ob);
|
|
|
|
|
2009-10-01 16:30:05 +00:00
|
|
|
return (edit && edit->psys);
|
2009-09-10 22:32:33 +00:00
|
|
|
}
|
|
|
|
|
2010-04-28 07:25:39 +00:00
|
|
|
int PE_poll_view3d(bContext *C)
|
2009-02-20 20:39:27 +00:00
|
|
|
{
|
2009-08-17 17:34:15 +00:00
|
|
|
return PE_poll(C) && CTX_wm_area(C)->spacetype == SPACE_VIEW3D &&
|
|
|
|
CTX_wm_region(C)->regiontype == RGN_TYPE_WINDOW;
|
2009-02-20 20:39:27 +00:00
|
|
|
}
|
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
void PE_free_ptcache_edit(PTCacheEdit *edit)
|
2009-01-24 13:45:24 +00:00
|
|
|
{
|
2009-08-29 15:20:36 +00:00
|
|
|
POINT_P;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
|
|
|
if(edit==0) return;
|
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
PTCacheUndo_clear(edit);
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
if(edit->points) {
|
|
|
|
LOOP_POINTS {
|
|
|
|
if(point->keys)
|
|
|
|
MEM_freeN(point->keys);
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
2009-02-20 20:39:27 +00:00
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
MEM_freeN(edit->points);
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if(edit->mirror_cache)
|
|
|
|
MEM_freeN(edit->mirror_cache);
|
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
if(edit->emitter_cosnos) {
|
2009-01-24 13:45:24 +00:00
|
|
|
MEM_freeN(edit->emitter_cosnos);
|
2009-02-20 20:39:27 +00:00
|
|
|
edit->emitter_cosnos= 0;
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
if(edit->emitter_field) {
|
2009-01-24 13:45:24 +00:00
|
|
|
BLI_kdtree_free(edit->emitter_field);
|
2009-02-20 20:39:27 +00:00
|
|
|
edit->emitter_field= 0;
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
|
2010-05-30 14:53:26 +00:00
|
|
|
psys_free_path_cache(edit->psys, edit);
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
MEM_freeN(edit);
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
2009-02-20 20:39:27 +00:00
|
|
|
|
2009-01-24 13:45:24 +00:00
|
|
|
/************************************************/
|
|
|
|
/* Edit Mode Helpers */
|
|
|
|
/************************************************/
|
2009-02-20 20:39:27 +00:00
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
int PE_start_edit(PTCacheEdit *edit)
|
2009-01-24 13:45:24 +00:00
|
|
|
{
|
2009-08-29 15:20:36 +00:00
|
|
|
if(edit) {
|
|
|
|
edit->edited = 1;
|
2009-09-10 22:32:33 +00:00
|
|
|
if(edit->psys)
|
|
|
|
edit->psys->flag |= PSYS_EDITED;
|
2009-08-29 15:20:36 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ParticleEditSettings *PE_settings(Scene *scene)
|
|
|
|
{
|
2010-02-09 20:03:05 +00:00
|
|
|
return scene->toolsettings ? &scene->toolsettings->particle : NULL;
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
|
2010-01-12 13:40:29 +00:00
|
|
|
/* always gets atleast the first particlesystem even if PSYS_CURRENT flag is not set
|
|
|
|
*
|
|
|
|
* note: this function runs on poll, therefor it can runs many times a second
|
|
|
|
* keep it fast! */
|
2009-10-09 13:25:54 +00:00
|
|
|
static PTCacheEdit *pe_get_current(Scene *scene, Object *ob, int create)
|
2009-01-24 13:45:24 +00:00
|
|
|
{
|
2009-08-29 15:20:36 +00:00
|
|
|
ParticleEditSettings *pset= PE_settings(scene);
|
|
|
|
PTCacheEdit *edit = NULL;
|
|
|
|
ListBase pidlist;
|
|
|
|
PTCacheID *pid;
|
|
|
|
|
2010-02-11 14:24:45 +00:00
|
|
|
if(pset==NULL || ob==NULL)
|
2010-02-09 20:03:05 +00:00
|
|
|
return NULL;
|
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
pset->scene = scene;
|
|
|
|
pset->object = ob;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2010-03-30 12:23:13 +00:00
|
|
|
BKE_ptcache_ids_from_object(&pidlist, ob, NULL, 0);
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
/* in the case of only one editable thing, set pset->edittype accordingly */
|
2009-08-29 17:25:26 +00:00
|
|
|
if(pidlist.first && pidlist.first == pidlist.last) {
|
2009-08-29 15:20:36 +00:00
|
|
|
pid = pidlist.first;
|
|
|
|
switch(pid->type) {
|
|
|
|
case PTCACHE_TYPE_PARTICLES:
|
|
|
|
pset->edittype = PE_TYPE_PARTICLES;
|
|
|
|
break;
|
|
|
|
case PTCACHE_TYPE_SOFTBODY:
|
|
|
|
pset->edittype = PE_TYPE_SOFTBODY;
|
|
|
|
break;
|
|
|
|
case PTCACHE_TYPE_CLOTH:
|
|
|
|
pset->edittype = PE_TYPE_CLOTH;
|
|
|
|
break;
|
|
|
|
}
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
for(pid=pidlist.first; pid; pid=pid->next) {
|
|
|
|
if(pset->edittype == PE_TYPE_PARTICLES && pid->type == PTCACHE_TYPE_PARTICLES) {
|
|
|
|
ParticleSystem *psys = pid->calldata;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
if(psys->flag & PSYS_CURRENT) {
|
|
|
|
if(psys->part && psys->part->type == PART_HAIR) {
|
2009-09-10 22:32:33 +00:00
|
|
|
if(psys->flag & PSYS_HAIR_DYNAMICS && psys->pointcache->flag & PTCACHE_BAKED) {
|
2009-10-09 13:25:54 +00:00
|
|
|
if(create && !psys->pointcache->edit)
|
2009-09-10 22:32:33 +00:00
|
|
|
PE_create_particle_edit(scene, ob, pid->cache, NULL);
|
|
|
|
edit = pid->cache->edit;
|
|
|
|
}
|
|
|
|
else {
|
2009-10-09 13:25:54 +00:00
|
|
|
if(create && !psys->edit && psys->flag & PSYS_HAIR_DONE)
|
2009-09-10 22:32:33 +00:00
|
|
|
PE_create_particle_edit(scene, ob, NULL, psys);
|
|
|
|
edit = psys->edit;
|
|
|
|
}
|
2009-08-29 15:20:36 +00:00
|
|
|
}
|
|
|
|
else {
|
2009-10-09 13:25:54 +00:00
|
|
|
if(create && pid->cache->flag & PTCACHE_BAKED && !pid->cache->edit)
|
2009-08-29 15:20:36 +00:00
|
|
|
PE_create_particle_edit(scene, ob, pid->cache, psys);
|
|
|
|
edit = pid->cache->edit;
|
|
|
|
}
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if(pset->edittype == PE_TYPE_SOFTBODY && pid->type == PTCACHE_TYPE_SOFTBODY) {
|
2009-10-09 13:25:54 +00:00
|
|
|
if(create && pid->cache->flag & PTCACHE_BAKED && !pid->cache->edit)
|
2009-08-29 15:20:36 +00:00
|
|
|
PE_create_particle_edit(scene, ob, pid->cache, NULL);
|
|
|
|
edit = pid->cache->edit;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else if(pset->edittype == PE_TYPE_CLOTH && pid->type == PTCACHE_TYPE_CLOTH) {
|
2009-10-09 13:25:54 +00:00
|
|
|
if(create && pid->cache->flag & PTCACHE_BAKED && !pid->cache->edit)
|
2009-08-29 15:20:36 +00:00
|
|
|
PE_create_particle_edit(scene, ob, pid->cache, NULL);
|
|
|
|
edit = pid->cache->edit;
|
|
|
|
break;
|
|
|
|
}
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
|
2010-01-12 13:40:29 +00:00
|
|
|
if(edit)
|
2009-08-29 15:20:36 +00:00
|
|
|
edit->pid = *pid;
|
|
|
|
|
|
|
|
BLI_freelistN(&pidlist);
|
|
|
|
|
|
|
|
return edit;
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
|
2009-10-09 13:25:54 +00:00
|
|
|
PTCacheEdit *PE_get_current(Scene *scene, Object *ob)
|
|
|
|
{
|
|
|
|
return pe_get_current(scene, ob, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
PTCacheEdit *PE_create_current(Scene *scene, Object *ob)
|
|
|
|
{
|
|
|
|
return pe_get_current(scene, ob, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
void PE_current_changed(Scene *scene, Object *ob)
|
|
|
|
{
|
|
|
|
if(ob->mode == OB_MODE_PARTICLE_EDIT)
|
|
|
|
PE_create_current(scene, ob);
|
|
|
|
}
|
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
void PE_hide_keys_time(Scene *scene, PTCacheEdit *edit, float cfra)
|
2009-01-24 13:45:24 +00:00
|
|
|
{
|
|
|
|
ParticleEditSettings *pset=PE_settings(scene);
|
2009-08-29 15:20:36 +00:00
|
|
|
POINT_P; KEY_K;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
|
|
|
|
if(pset->flag & PE_FADE_TIME && pset->selectmode==SCE_SELECT_POINT) {
|
|
|
|
LOOP_POINTS {
|
|
|
|
LOOP_KEYS {
|
|
|
|
if(fabs(cfra-*key->time) < pset->fade_frames)
|
2009-01-24 13:45:24 +00:00
|
|
|
key->flag &= ~PEK_HIDE;
|
2009-02-20 20:39:27 +00:00
|
|
|
else {
|
2009-01-24 13:45:24 +00:00
|
|
|
key->flag |= PEK_HIDE;
|
2009-08-29 15:20:36 +00:00
|
|
|
//key->flag &= ~PEK_SELECT;
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2009-02-20 20:39:27 +00:00
|
|
|
else {
|
2009-08-29 15:20:36 +00:00
|
|
|
LOOP_POINTS {
|
|
|
|
LOOP_KEYS {
|
2009-01-24 13:45:24 +00:00
|
|
|
key->flag &= ~PEK_HIDE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-01-05 15:23:09 +00:00
|
|
|
static int pe_x_mirror(Object *ob)
|
|
|
|
{
|
|
|
|
if(ob->type == OB_MESH)
|
|
|
|
return (((Mesh*)ob->data)->editflag & ME_EDIT_MIRROR_X);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
/****************** common struct passed to callbacks ******************/
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
typedef struct PEData {
|
|
|
|
ViewContext vc;
|
|
|
|
bglMats mats;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
Scene *scene;
|
|
|
|
Object *ob;
|
|
|
|
DerivedMesh *dm;
|
2009-08-29 15:20:36 +00:00
|
|
|
PTCacheEdit *edit;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
short *mval;
|
|
|
|
rcti *rect;
|
|
|
|
float rad;
|
|
|
|
float dist;
|
|
|
|
float dval;
|
|
|
|
int select;
|
|
|
|
|
|
|
|
float *dvec;
|
|
|
|
float combfac;
|
|
|
|
float pufffac;
|
|
|
|
float cutfac;
|
|
|
|
float smoothfac;
|
|
|
|
float weightfac;
|
|
|
|
float growfac;
|
2009-07-25 22:31:02 +00:00
|
|
|
int totrekey;
|
2009-02-20 20:39:27 +00:00
|
|
|
|
|
|
|
int invert;
|
|
|
|
int tot;
|
|
|
|
float vec[3];
|
|
|
|
} PEData;
|
|
|
|
|
|
|
|
static void PE_set_data(bContext *C, PEData *data)
|
2009-01-24 13:45:24 +00:00
|
|
|
{
|
2009-02-20 20:39:27 +00:00
|
|
|
memset(data, 0, sizeof(*data));
|
|
|
|
|
|
|
|
data->scene= CTX_data_scene(C);
|
|
|
|
data->ob= CTX_data_active_object(C);
|
2009-08-29 15:20:36 +00:00
|
|
|
data->edit= PE_get_current(data->scene, data->ob);
|
2009-02-20 20:39:27 +00:00
|
|
|
}
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
static void PE_set_view3d_data(bContext *C, PEData *data)
|
|
|
|
{
|
|
|
|
PE_set_data(C, data);
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
view3d_set_viewcontext(C, &data->vc);
|
2010-01-26 11:51:28 +00:00
|
|
|
/* note, the object argument means the modelview matrix does not account for the objects matrix, use viewmat rather then (obmat * viewmat) */
|
|
|
|
view3d_get_transformation(data->vc.ar, data->vc.rv3d, NULL, &data->mats);
|
2009-02-25 19:29:58 +00:00
|
|
|
|
|
|
|
if((data->vc.v3d->drawtype>OB_WIRE) && (data->vc.v3d->flag & V3D_ZBUF_SELECT))
|
|
|
|
view3d_validate_backbuf(&data->vc);
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
/*************************** selection utilities *******************************/
|
|
|
|
|
|
|
|
static int key_test_depth(PEData *data, float co[3])
|
2009-01-24 13:45:24 +00:00
|
|
|
{
|
2009-02-20 20:39:27 +00:00
|
|
|
View3D *v3d= data->vc.v3d;
|
2009-01-24 13:45:24 +00:00
|
|
|
double ux, uy, uz;
|
|
|
|
float depth;
|
|
|
|
short wco[3], x,y;
|
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
/* nothing to do */
|
|
|
|
if((v3d->drawtype<=OB_WIRE) || (v3d->flag & V3D_ZBUF_SELECT)==0)
|
|
|
|
return 1;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
project_short(data->vc.ar, co, wco);
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
if(wco[0] == IS_CLIPPED)
|
2009-01-24 13:45:24 +00:00
|
|
|
return 0;
|
2009-02-20 20:39:27 +00:00
|
|
|
|
|
|
|
gluProject(co[0],co[1],co[2], data->mats.modelview, data->mats.projection,
|
|
|
|
(GLint *)data->mats.viewport, &ux, &uy, &uz);
|
|
|
|
|
2009-01-24 13:45:24 +00:00
|
|
|
x=wco[0];
|
|
|
|
y=wco[1];
|
|
|
|
|
2009-12-18 13:35:30 +00:00
|
|
|
x+= (short)data->vc.ar->winrct.xmin;
|
|
|
|
y+= (short)data->vc.ar->winrct.ymin;
|
2009-02-20 20:39:27 +00:00
|
|
|
|
2010-01-26 11:51:28 +00:00
|
|
|
/* PE_set_view3d_data calls this. no need to call here */
|
|
|
|
/* view3d_validate_backbuf(&data->vc); */
|
2009-12-18 13:35:30 +00:00
|
|
|
glReadPixels(x, y, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &depth);
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-12-18 13:35:30 +00:00
|
|
|
if((float)uz - 0.0001 > depth)
|
|
|
|
return 0;
|
|
|
|
else
|
|
|
|
return 1;
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
|
2009-02-25 19:29:58 +00:00
|
|
|
static int key_inside_circle(PEData *data, float rad, float co[3], float *distance)
|
2009-02-20 20:39:27 +00:00
|
|
|
{
|
|
|
|
float dx, dy, dist;
|
|
|
|
short sco[2];
|
|
|
|
|
|
|
|
project_short(data->vc.ar, co, sco);
|
|
|
|
|
|
|
|
if(sco[0] == IS_CLIPPED)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
dx= data->mval[0] - sco[0];
|
|
|
|
dy= data->mval[1] - sco[1];
|
|
|
|
dist= sqrt(dx*dx + dy*dy);
|
|
|
|
|
2009-02-25 19:29:58 +00:00
|
|
|
if(dist > rad)
|
2009-02-20 20:39:27 +00:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
if(key_test_depth(data, co)) {
|
|
|
|
if(distance)
|
|
|
|
*distance=dist;
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int key_inside_rect(PEData *data, float co[3])
|
|
|
|
{
|
|
|
|
short sco[2];
|
|
|
|
|
|
|
|
project_short(data->vc.ar, co,sco);
|
|
|
|
|
|
|
|
if(sco[0] == IS_CLIPPED)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if(sco[0] > data->rect->xmin && sco[0] < data->rect->xmax &&
|
|
|
|
sco[1] > data->rect->ymin && sco[1] < data->rect->ymax)
|
|
|
|
return key_test_depth(data, co);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int key_inside_test(PEData *data, float co[3])
|
|
|
|
{
|
|
|
|
if(data->mval)
|
2009-02-25 19:29:58 +00:00
|
|
|
return key_inside_circle(data, data->rad, co, NULL);
|
2009-02-20 20:39:27 +00:00
|
|
|
else
|
|
|
|
return key_inside_rect(data, co);
|
|
|
|
}
|
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
static int point_is_selected(PTCacheEditPoint *point)
|
2009-01-24 13:45:24 +00:00
|
|
|
{
|
2009-08-29 15:20:36 +00:00
|
|
|
KEY_K;
|
|
|
|
int sel;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
if(point->flag & PEP_HIDE)
|
2009-02-20 20:39:27 +00:00
|
|
|
return 0;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
sel= 0;
|
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
LOOP_SELECTED_KEYS {
|
|
|
|
return 1;
|
|
|
|
}
|
2009-01-24 13:45:24 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
/*************************** iterators *******************************/
|
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
typedef void (*ForPointFunc)(PEData *data, int point_index);
|
|
|
|
typedef void (*ForKeyFunc)(PEData *data, int point_index, int key_index);
|
|
|
|
typedef void (*ForKeyMatFunc)(PEData *data, float mat[][4], float imat[][4], int point_index, int key_index, PTCacheEditKey *key);
|
2009-02-20 20:39:27 +00:00
|
|
|
|
|
|
|
static void for_mouse_hit_keys(PEData *data, ForKeyFunc func, int nearest)
|
2009-01-24 13:45:24 +00:00
|
|
|
{
|
2009-06-23 00:41:55 +00:00
|
|
|
ParticleEditSettings *pset= PE_settings(data->scene);
|
2009-08-29 15:20:36 +00:00
|
|
|
PTCacheEdit *edit= data->edit;
|
|
|
|
POINT_P; KEY_K;
|
|
|
|
int nearest_point, nearest_key;
|
2009-02-20 20:39:27 +00:00
|
|
|
float dist= data->rad;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
/* in path select mode we have no keys */
|
2009-06-23 00:41:55 +00:00
|
|
|
if(pset->selectmode==SCE_SELECT_PATH)
|
2009-02-20 20:39:27 +00:00
|
|
|
return;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
nearest_point= -1;
|
2009-02-20 20:39:27 +00:00
|
|
|
nearest_key= -1;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
LOOP_VISIBLE_POINTS {
|
2009-06-23 00:41:55 +00:00
|
|
|
if(pset->selectmode == SCE_SELECT_END) {
|
2009-02-20 20:39:27 +00:00
|
|
|
/* only do end keys */
|
2009-08-29 15:20:36 +00:00
|
|
|
key= point->keys + point->totkey-1;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
if(nearest) {
|
2009-08-29 15:20:36 +00:00
|
|
|
if(key_inside_circle(data, dist, KEY_WCO, &dist)) {
|
|
|
|
nearest_point= p;
|
|
|
|
nearest_key= point->totkey-1;
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
}
|
2009-08-29 15:20:36 +00:00
|
|
|
else if(key_inside_test(data, KEY_WCO))
|
|
|
|
func(data, p, point->totkey-1);
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
2009-02-20 20:39:27 +00:00
|
|
|
else {
|
|
|
|
/* do all keys */
|
2009-08-29 15:20:36 +00:00
|
|
|
LOOP_VISIBLE_KEYS {
|
2009-02-20 20:39:27 +00:00
|
|
|
if(nearest) {
|
2009-08-29 15:20:36 +00:00
|
|
|
if(key_inside_circle(data, dist, KEY_WCO, &dist)) {
|
|
|
|
nearest_point= p;
|
2009-02-20 20:39:27 +00:00
|
|
|
nearest_key= k;
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
}
|
2009-08-29 15:20:36 +00:00
|
|
|
else if(key_inside_test(data, KEY_WCO))
|
|
|
|
func(data, p, k);
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2009-02-20 20:39:27 +00:00
|
|
|
|
|
|
|
/* do nearest only */
|
2009-08-29 15:20:36 +00:00
|
|
|
if(nearest && nearest_point > -1)
|
|
|
|
func(data, nearest_point, nearest_key);
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
static void foreach_mouse_hit_point(PEData *data, ForPointFunc func, int selected)
|
2009-01-24 13:45:24 +00:00
|
|
|
{
|
2009-06-23 00:41:55 +00:00
|
|
|
ParticleEditSettings *pset= PE_settings(data->scene);
|
2009-08-29 15:20:36 +00:00
|
|
|
PTCacheEdit *edit= data->edit;
|
|
|
|
POINT_P; KEY_K;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
/* all is selected in path mode */
|
2009-06-23 00:41:55 +00:00
|
|
|
if(pset->selectmode==SCE_SELECT_PATH)
|
2009-01-24 13:45:24 +00:00
|
|
|
selected=0;
|
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
LOOP_VISIBLE_POINTS {
|
2009-06-23 00:41:55 +00:00
|
|
|
if(pset->selectmode==SCE_SELECT_END) {
|
2009-02-20 20:39:27 +00:00
|
|
|
/* only do end keys */
|
2009-08-29 15:20:36 +00:00
|
|
|
key= point->keys + point->totkey - 1;
|
2009-02-20 20:39:27 +00:00
|
|
|
|
|
|
|
if(selected==0 || key->flag & PEK_SELECT)
|
2009-08-29 15:20:36 +00:00
|
|
|
if(key_inside_circle(data, data->rad, KEY_WCO, &data->dist))
|
|
|
|
func(data, p);
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
2009-02-20 20:39:27 +00:00
|
|
|
else {
|
|
|
|
/* do all keys */
|
2009-08-29 15:20:36 +00:00
|
|
|
LOOP_VISIBLE_KEYS {
|
2009-02-20 20:39:27 +00:00
|
|
|
if(selected==0 || key->flag & PEK_SELECT) {
|
2009-08-29 15:20:36 +00:00
|
|
|
if(key_inside_circle(data, data->rad, KEY_WCO, &data->dist)) {
|
|
|
|
func(data, p);
|
2009-02-20 20:39:27 +00:00
|
|
|
break;
|
|
|
|
}
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
static void foreach_mouse_hit_key(PEData *data, ForKeyMatFunc func, int selected)
|
2009-01-24 13:45:24 +00:00
|
|
|
{
|
2009-08-29 15:20:36 +00:00
|
|
|
PTCacheEdit *edit = data->edit;
|
|
|
|
ParticleSystem *psys = edit->psys;
|
|
|
|
ParticleSystemModifierData *psmd = NULL;
|
2009-06-23 00:41:55 +00:00
|
|
|
ParticleEditSettings *pset= PE_settings(data->scene);
|
2009-08-29 15:20:36 +00:00
|
|
|
POINT_P; KEY_K;
|
2009-01-24 13:45:24 +00:00
|
|
|
float mat[4][4], imat[4][4];
|
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
if(edit->psys)
|
|
|
|
psmd= psys_get_modifier(data->ob, edit->psys);
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
/* all is selected in path mode */
|
2009-06-23 00:41:55 +00:00
|
|
|
if(pset->selectmode==SCE_SELECT_PATH)
|
2009-02-20 20:39:27 +00:00
|
|
|
selected= 0;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-11-10 20:43:45 +00:00
|
|
|
unit_m4(imat);
|
|
|
|
unit_m4(mat);
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
LOOP_VISIBLE_POINTS {
|
2009-06-23 00:41:55 +00:00
|
|
|
if(pset->selectmode==SCE_SELECT_END) {
|
2009-02-20 20:39:27 +00:00
|
|
|
/* only do end keys */
|
2009-08-29 15:20:36 +00:00
|
|
|
key= point->keys + point->totkey-1;
|
2009-02-20 20:39:27 +00:00
|
|
|
|
2010-01-06 12:00:53 +00:00
|
|
|
if(selected==0 || key->flag & PEK_SELECT) {
|
|
|
|
if(key_inside_circle(data, data->rad, KEY_WCO, &data->dist)) {
|
|
|
|
if(edit->psys && !(edit->psys->flag & PSYS_GLOBAL_HAIR)) {
|
|
|
|
psys_mat_hair_to_global(data->ob, psmd->dm, psys->part->from, psys->particles + p, mat);
|
|
|
|
invert_m4_m4(imat,mat);
|
|
|
|
}
|
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
func(data, mat, imat, p, point->totkey-1, key);
|
2010-01-06 12:00:53 +00:00
|
|
|
}
|
|
|
|
}
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
2009-02-20 20:39:27 +00:00
|
|
|
else {
|
|
|
|
/* do all keys */
|
2009-08-29 15:20:36 +00:00
|
|
|
LOOP_VISIBLE_KEYS {
|
2010-01-06 12:00:53 +00:00
|
|
|
if(selected==0 || key->flag & PEK_SELECT) {
|
|
|
|
if(key_inside_circle(data, data->rad, KEY_WCO, &data->dist)) {
|
|
|
|
if(edit->psys && !(edit->psys->flag & PSYS_GLOBAL_HAIR)) {
|
|
|
|
psys_mat_hair_to_global(data->ob, psmd->dm, psys->part->from, psys->particles + p, mat);
|
|
|
|
invert_m4_m4(imat,mat);
|
|
|
|
}
|
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
func(data, mat, imat, p, k, key);
|
2010-01-06 12:00:53 +00:00
|
|
|
}
|
|
|
|
}
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
static void foreach_selected_point(PEData *data, ForPointFunc func)
|
2009-01-24 13:45:24 +00:00
|
|
|
{
|
2009-08-29 15:20:36 +00:00
|
|
|
PTCacheEdit *edit = data->edit;
|
|
|
|
POINT_P;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
LOOP_SELECTED_POINTS {
|
|
|
|
func(data, p);
|
|
|
|
}
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
static void foreach_selected_key(PEData *data, ForKeyFunc func)
|
2009-01-24 13:45:24 +00:00
|
|
|
{
|
2009-08-29 15:20:36 +00:00
|
|
|
PTCacheEdit *edit = data->edit;
|
|
|
|
POINT_P; KEY_K;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
LOOP_VISIBLE_POINTS {
|
|
|
|
LOOP_SELECTED_KEYS {
|
|
|
|
func(data, p, k);
|
|
|
|
}
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
static void foreach_point(PEData *data, ForPointFunc func)
|
2009-02-20 20:39:27 +00:00
|
|
|
{
|
2009-08-29 15:20:36 +00:00
|
|
|
PTCacheEdit *edit = data->edit;
|
|
|
|
POINT_P;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
LOOP_POINTS {
|
|
|
|
func(data, p);
|
|
|
|
}
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
2009-02-20 20:39:27 +00:00
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
static int count_selected_keys(Scene *scene, PTCacheEdit *edit)
|
2009-01-24 13:45:24 +00:00
|
|
|
{
|
2009-06-23 00:41:55 +00:00
|
|
|
ParticleEditSettings *pset= PE_settings(scene);
|
2009-08-29 15:20:36 +00:00
|
|
|
POINT_P; KEY_K;
|
|
|
|
int sel= 0;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
LOOP_VISIBLE_POINTS {
|
2009-06-23 00:41:55 +00:00
|
|
|
if(pset->selectmode==SCE_SELECT_POINT) {
|
2009-08-29 15:20:36 +00:00
|
|
|
LOOP_SELECTED_KEYS {
|
|
|
|
sel++;
|
|
|
|
}
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
2009-06-23 00:41:55 +00:00
|
|
|
else if(pset->selectmode==SCE_SELECT_END) {
|
2009-08-29 15:20:36 +00:00
|
|
|
key = point->keys + point->totkey - 1;
|
2009-02-20 20:39:27 +00:00
|
|
|
if(key->flag & PEK_SELECT)
|
2009-01-24 13:45:24 +00:00
|
|
|
sel++;
|
|
|
|
}
|
|
|
|
}
|
2009-02-20 20:39:27 +00:00
|
|
|
|
2009-01-24 13:45:24 +00:00
|
|
|
return sel;
|
|
|
|
}
|
|
|
|
|
|
|
|
/************************************************/
|
|
|
|
/* Particle Edit Mirroring */
|
|
|
|
/************************************************/
|
|
|
|
|
|
|
|
static void PE_update_mirror_cache(Object *ob, ParticleSystem *psys)
|
|
|
|
{
|
2009-08-29 15:20:36 +00:00
|
|
|
PTCacheEdit *edit;
|
2009-01-24 13:45:24 +00:00
|
|
|
ParticleSystemModifierData *psmd;
|
|
|
|
KDTree *tree;
|
|
|
|
KDTreeNearest nearest;
|
2009-09-04 23:06:15 +00:00
|
|
|
HairKey *key;
|
|
|
|
PARTICLE_P;
|
2009-01-24 13:45:24 +00:00
|
|
|
float mat[4][4], co[3];
|
2009-09-04 23:06:15 +00:00
|
|
|
int index, totpart;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
|
|
|
edit= psys->edit;
|
|
|
|
psmd= psys_get_modifier(ob, psys);
|
|
|
|
totpart= psys->totpart;
|
|
|
|
|
2009-10-01 16:30:05 +00:00
|
|
|
if(!psmd->dm)
|
|
|
|
return;
|
|
|
|
|
2009-01-24 13:45:24 +00:00
|
|
|
tree= BLI_kdtree_new(totpart);
|
|
|
|
|
|
|
|
/* insert particles into kd tree */
|
2009-09-04 23:06:15 +00:00
|
|
|
LOOP_PARTICLES {
|
|
|
|
key = pa->hair;
|
2009-01-24 13:45:24 +00:00
|
|
|
psys_mat_hair_to_orco(ob, psmd->dm, psys->part->from, pa, mat);
|
2009-09-04 23:06:15 +00:00
|
|
|
VECCOPY(co, key->co);
|
2009-11-10 20:43:45 +00:00
|
|
|
mul_m4_v3(mat, co);
|
2009-09-04 23:06:15 +00:00
|
|
|
BLI_kdtree_insert(tree, p, co, NULL);
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
BLI_kdtree_balance(tree);
|
|
|
|
|
|
|
|
/* lookup particles and set in mirror cache */
|
|
|
|
if(!edit->mirror_cache)
|
|
|
|
edit->mirror_cache= MEM_callocN(sizeof(int)*totpart, "PE mirror cache");
|
|
|
|
|
2009-09-04 23:06:15 +00:00
|
|
|
LOOP_PARTICLES {
|
|
|
|
key = pa->hair;
|
2009-01-24 13:45:24 +00:00
|
|
|
psys_mat_hair_to_orco(ob, psmd->dm, psys->part->from, pa, mat);
|
2009-09-04 23:06:15 +00:00
|
|
|
VECCOPY(co, key->co);
|
2009-11-10 20:43:45 +00:00
|
|
|
mul_m4_v3(mat, co);
|
2009-01-24 13:45:24 +00:00
|
|
|
co[0]= -co[0];
|
|
|
|
|
|
|
|
index= BLI_kdtree_find_nearest(tree, co, NULL, &nearest);
|
|
|
|
|
|
|
|
/* this needs a custom threshold still, duplicated for editmode mirror */
|
2009-09-04 23:06:15 +00:00
|
|
|
if(index != -1 && index != p && (nearest.dist <= 0.0002f))
|
|
|
|
edit->mirror_cache[p]= index;
|
2009-01-24 13:45:24 +00:00
|
|
|
else
|
2009-09-04 23:06:15 +00:00
|
|
|
edit->mirror_cache[p]= -1;
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* make sure mirrors are in two directions */
|
2009-09-04 23:06:15 +00:00
|
|
|
LOOP_PARTICLES {
|
|
|
|
if(edit->mirror_cache[p]) {
|
|
|
|
index= edit->mirror_cache[p];
|
|
|
|
if(edit->mirror_cache[index] != p)
|
|
|
|
edit->mirror_cache[p]= -1;
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
BLI_kdtree_free(tree);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void PE_mirror_particle(Object *ob, DerivedMesh *dm, ParticleSystem *psys, ParticleData *pa, ParticleData *mpa)
|
|
|
|
{
|
|
|
|
HairKey *hkey, *mhkey;
|
2009-08-29 15:20:36 +00:00
|
|
|
PTCacheEditPoint *point, *mpoint;
|
|
|
|
PTCacheEditKey *key, *mkey;
|
|
|
|
PTCacheEdit *edit;
|
2009-01-24 13:45:24 +00:00
|
|
|
float mat[4][4], mmat[4][4], immat[4][4];
|
|
|
|
int i, mi, k;
|
|
|
|
|
|
|
|
edit= psys->edit;
|
|
|
|
i= pa - psys->particles;
|
|
|
|
|
|
|
|
/* find mirrored particle if needed */
|
|
|
|
if(!mpa) {
|
|
|
|
if(!edit->mirror_cache)
|
|
|
|
PE_update_mirror_cache(ob, psys);
|
|
|
|
|
|
|
|
mi= edit->mirror_cache[i];
|
|
|
|
if(mi == -1)
|
|
|
|
return;
|
|
|
|
mpa= psys->particles + mi;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
mi= mpa - psys->particles;
|
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
point = edit->points + i;
|
|
|
|
mpoint = edit->points + mi;
|
|
|
|
|
2009-01-24 13:45:24 +00:00
|
|
|
/* make sure they have the same amount of keys */
|
|
|
|
if(pa->totkey != mpa->totkey) {
|
|
|
|
if(mpa->hair) MEM_freeN(mpa->hair);
|
2009-08-29 15:20:36 +00:00
|
|
|
if(mpoint->keys) MEM_freeN(mpoint->keys);
|
2009-01-24 13:45:24 +00:00
|
|
|
|
|
|
|
mpa->hair= MEM_dupallocN(pa->hair);
|
2009-08-29 15:20:36 +00:00
|
|
|
mpoint->keys= MEM_dupallocN(point->keys);
|
|
|
|
mpoint->totkey= point->totkey;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
|
|
|
mhkey= mpa->hair;
|
2009-08-29 15:20:36 +00:00
|
|
|
mkey= mpoint->keys;
|
2009-01-24 13:45:24 +00:00
|
|
|
for(k=0; k<mpa->totkey; k++, mkey++, mhkey++) {
|
|
|
|
mkey->co= mhkey->co;
|
|
|
|
mkey->time= &mhkey->time;
|
|
|
|
mkey->flag &= PEK_SELECT;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* mirror positions and tags */
|
|
|
|
psys_mat_hair_to_orco(ob, dm, psys->part->from, pa, mat);
|
|
|
|
psys_mat_hair_to_orco(ob, dm, psys->part->from, mpa, mmat);
|
2009-11-10 20:43:45 +00:00
|
|
|
invert_m4_m4(immat, mmat);
|
2009-01-24 13:45:24 +00:00
|
|
|
|
|
|
|
hkey=pa->hair;
|
|
|
|
mhkey=mpa->hair;
|
2009-08-29 15:20:36 +00:00
|
|
|
key= point->keys;
|
|
|
|
mkey= mpoint->keys;
|
2009-01-24 13:45:24 +00:00
|
|
|
for(k=0; k<pa->totkey; k++, hkey++, mhkey++, key++, mkey++) {
|
|
|
|
VECCOPY(mhkey->co, hkey->co);
|
2009-11-10 20:43:45 +00:00
|
|
|
mul_m4_v3(mat, mhkey->co);
|
2009-01-24 13:45:24 +00:00
|
|
|
mhkey->co[0]= -mhkey->co[0];
|
2009-11-10 20:43:45 +00:00
|
|
|
mul_m4_v3(immat, mhkey->co);
|
2009-01-24 13:45:24 +00:00
|
|
|
|
|
|
|
if(key->flag & PEK_TAG)
|
|
|
|
mkey->flag |= PEK_TAG;
|
|
|
|
}
|
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
if(point->flag & PEP_TAG)
|
|
|
|
mpoint->flag |= PEP_TAG;
|
|
|
|
if(point->flag & PEP_EDIT_RECALC)
|
|
|
|
mpoint->flag |= PEP_EDIT_RECALC;
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void PE_apply_mirror(Object *ob, ParticleSystem *psys)
|
|
|
|
{
|
2009-08-29 15:20:36 +00:00
|
|
|
PTCacheEdit *edit;
|
2009-01-24 13:45:24 +00:00
|
|
|
ParticleSystemModifierData *psmd;
|
2009-08-29 15:20:36 +00:00
|
|
|
POINT_P;
|
|
|
|
|
|
|
|
if(!psys)
|
|
|
|
return;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
|
|
|
edit= psys->edit;
|
|
|
|
psmd= psys_get_modifier(ob, psys);
|
|
|
|
|
2010-03-12 16:21:39 +00:00
|
|
|
if(!psmd->dm)
|
2009-10-01 16:30:05 +00:00
|
|
|
return;
|
|
|
|
|
2010-03-12 16:21:39 +00:00
|
|
|
if(!edit->mirror_cache)
|
|
|
|
PE_update_mirror_cache(ob, psys);
|
|
|
|
|
2009-01-24 13:45:24 +00:00
|
|
|
/* we delay settings the PARS_EDIT_RECALC for mirrored particles
|
|
|
|
* to avoid doing mirror twice */
|
2009-08-29 15:20:36 +00:00
|
|
|
LOOP_POINTS {
|
|
|
|
if(point->flag & PEP_EDIT_RECALC) {
|
|
|
|
PE_mirror_particle(ob, psmd->dm, psys, psys->particles + p, NULL);
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
if(edit->mirror_cache[p] != -1)
|
|
|
|
edit->points[edit->mirror_cache[p]].flag &= ~PEP_EDIT_RECALC;
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
LOOP_POINTS {
|
|
|
|
if(point->flag & PEP_EDIT_RECALC)
|
|
|
|
if(edit->mirror_cache[p] != -1)
|
|
|
|
edit->points[edit->mirror_cache[p]].flag |= PEP_EDIT_RECALC;
|
|
|
|
}
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/************************************************/
|
|
|
|
/* Edit Calculation */
|
|
|
|
/************************************************/
|
|
|
|
/* tries to stop edited particles from going through the emitter's surface */
|
2009-08-29 15:20:36 +00:00
|
|
|
static void pe_deflect_emitter(Scene *scene, Object *ob, PTCacheEdit *edit)
|
2009-01-24 13:45:24 +00:00
|
|
|
{
|
2009-02-20 20:39:27 +00:00
|
|
|
ParticleEditSettings *pset= PE_settings(scene);
|
2009-08-29 15:20:36 +00:00
|
|
|
ParticleSystem *psys;
|
|
|
|
ParticleSystemModifierData *psmd;
|
|
|
|
POINT_P; KEY_K;
|
|
|
|
int index;
|
2009-10-21 10:56:31 +00:00
|
|
|
float *vec, *nor, dvec[3], dot, dist_1st=0.0f;
|
2009-01-24 13:45:24 +00:00
|
|
|
float hairimat[4][4], hairmat[4][4];
|
|
|
|
|
2009-09-05 20:12:08 +00:00
|
|
|
if(edit==NULL || edit->psys==NULL || (pset->flag & PE_DEFLECT_EMITTER)==0 || (edit->psys->flag & PSYS_GLOBAL_HAIR))
|
2009-01-24 13:45:24 +00:00
|
|
|
return;
|
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
psys = edit->psys;
|
|
|
|
psmd = psys_get_modifier(ob,psys);
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-10-01 16:30:05 +00:00
|
|
|
if(!psmd->dm)
|
|
|
|
return;
|
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
LOOP_EDITED_POINTS {
|
|
|
|
psys_mat_hair_to_object(ob, psmd->dm, psys->part->from, psys->particles + p, hairmat);
|
|
|
|
|
|
|
|
LOOP_KEYS {
|
2009-11-10 20:43:45 +00:00
|
|
|
mul_m4_v3(hairmat, key->co);
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
LOOP_KEYS {
|
|
|
|
if(k==0) {
|
2009-11-10 20:43:45 +00:00
|
|
|
dist_1st = len_v3v3((key+1)->co, key->co);
|
2009-08-29 15:20:36 +00:00
|
|
|
dist_1st *= 0.75f * pset->emitterdist;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
index= BLI_kdtree_find_nearest(edit->emitter_field,key->co,NULL,NULL);
|
|
|
|
|
|
|
|
vec=edit->emitter_cosnos +index*6;
|
|
|
|
nor=vec+3;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-11-10 20:43:45 +00:00
|
|
|
sub_v3_v3v3(dvec, key->co, vec);
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-11-10 20:43:45 +00:00
|
|
|
dot=dot_v3v3(dvec,nor);
|
2009-08-29 15:20:36 +00:00
|
|
|
VECCOPY(dvec,nor);
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
if(dot>0.0f) {
|
|
|
|
if(dot<dist_1st) {
|
2009-11-10 20:43:45 +00:00
|
|
|
normalize_v3(dvec);
|
|
|
|
mul_v3_fl(dvec,dist_1st-dot);
|
2010-04-21 12:27:48 +00:00
|
|
|
add_v3_v3(key->co, dvec);
|
2009-08-29 15:20:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
2009-11-10 20:43:45 +00:00
|
|
|
normalize_v3(dvec);
|
|
|
|
mul_v3_fl(dvec,dist_1st-dot);
|
2010-04-21 12:27:48 +00:00
|
|
|
add_v3_v3(key->co, dvec);
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
2009-08-29 15:20:36 +00:00
|
|
|
if(k==1)
|
|
|
|
dist_1st*=1.3333f;
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-11-10 20:43:45 +00:00
|
|
|
invert_m4_m4(hairimat,hairmat);
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
LOOP_KEYS {
|
2009-11-10 20:43:45 +00:00
|
|
|
mul_m4_v3(hairimat, key->co);
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* force set distances between neighbouring keys */
|
2009-08-29 15:20:36 +00:00
|
|
|
void PE_apply_lengths(Scene *scene, PTCacheEdit *edit)
|
2009-01-24 13:45:24 +00:00
|
|
|
{
|
2009-08-29 15:20:36 +00:00
|
|
|
|
2009-01-24 13:45:24 +00:00
|
|
|
ParticleEditSettings *pset=PE_settings(scene);
|
2009-08-29 15:20:36 +00:00
|
|
|
POINT_P; KEY_K;
|
2009-01-24 13:45:24 +00:00
|
|
|
float dv1[3];
|
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
if(edit==0 || (pset->flag & PE_KEEP_LENGTHS)==0)
|
2009-01-24 13:45:24 +00:00
|
|
|
return;
|
|
|
|
|
2009-09-05 20:12:08 +00:00
|
|
|
if(edit->psys && edit->psys->flag & PSYS_GLOBAL_HAIR)
|
|
|
|
return;
|
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
LOOP_EDITED_POINTS {
|
|
|
|
LOOP_KEYS {
|
|
|
|
if(k) {
|
2009-11-10 20:43:45 +00:00
|
|
|
sub_v3_v3v3(dv1, key->co, (key - 1)->co);
|
|
|
|
normalize_v3(dv1);
|
|
|
|
mul_v3_fl(dv1, (key - 1)->length);
|
|
|
|
add_v3_v3v3(key->co, (key - 1)->co, dv1);
|
2009-08-29 15:20:36 +00:00
|
|
|
}
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* try to find a nice solution to keep distances between neighbouring keys */
|
2009-08-29 15:20:36 +00:00
|
|
|
static void pe_iterate_lengths(Scene *scene, PTCacheEdit *edit)
|
2009-01-24 13:45:24 +00:00
|
|
|
{
|
|
|
|
ParticleEditSettings *pset=PE_settings(scene);
|
2009-08-29 15:20:36 +00:00
|
|
|
POINT_P;
|
|
|
|
PTCacheEditKey *key;
|
|
|
|
int j, k;
|
2009-01-24 13:45:24 +00:00
|
|
|
float tlen;
|
2009-02-20 20:39:27 +00:00
|
|
|
float dv0[3]= {0.0f, 0.0f, 0.0f};
|
|
|
|
float dv1[3]= {0.0f, 0.0f, 0.0f};
|
|
|
|
float dv2[3]= {0.0f, 0.0f, 0.0f};
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-09-05 20:12:08 +00:00
|
|
|
if(edit==0 || (pset->flag & PE_KEEP_LENGTHS)==0)
|
2009-01-24 13:45:24 +00:00
|
|
|
return;
|
|
|
|
|
2009-09-05 20:12:08 +00:00
|
|
|
if(edit->psys && edit->psys->flag & PSYS_GLOBAL_HAIR)
|
2009-01-24 13:45:24 +00:00
|
|
|
return;
|
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
LOOP_EDITED_POINTS {
|
|
|
|
for(j=1; j<point->totkey; j++) {
|
|
|
|
float mul= 1.0f / (float)point->totkey;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
if(pset->flag & PE_LOCK_FIRST) {
|
2009-08-29 15:20:36 +00:00
|
|
|
key= point->keys + 1;
|
2009-02-20 20:39:27 +00:00
|
|
|
k= 1;
|
|
|
|
dv1[0]= dv1[1]= dv1[2]= 0.0;
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
2009-02-20 20:39:27 +00:00
|
|
|
else {
|
2009-08-29 15:20:36 +00:00
|
|
|
key= point->keys;
|
2009-02-20 20:39:27 +00:00
|
|
|
k= 0;
|
|
|
|
dv0[0]= dv0[1]= dv0[2]= 0.0;
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
for(; k<point->totkey; k++, key++) {
|
2009-02-20 20:39:27 +00:00
|
|
|
if(k) {
|
2009-11-10 20:43:45 +00:00
|
|
|
sub_v3_v3v3(dv0, (key - 1)->co, key->co);
|
|
|
|
tlen= normalize_v3(dv0);
|
|
|
|
mul_v3_fl(dv0, (mul * (tlen - (key - 1)->length)));
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
if(k < point->totkey - 1) {
|
2009-11-10 20:43:45 +00:00
|
|
|
sub_v3_v3v3(dv2, (key + 1)->co, key->co);
|
|
|
|
tlen= normalize_v3(dv2);
|
|
|
|
mul_v3_fl(dv2, mul * (tlen - key->length));
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
if(k) {
|
2010-04-21 12:27:48 +00:00
|
|
|
add_v3_v3((key-1)->co, dv1);
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
VECADD(dv1,dv0,dv2);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* set current distances to be kept between neighbouting keys */
|
2009-08-29 15:20:36 +00:00
|
|
|
static void recalc_lengths(PTCacheEdit *edit)
|
2009-01-24 13:45:24 +00:00
|
|
|
{
|
2009-08-29 15:20:36 +00:00
|
|
|
POINT_P; KEY_K;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
if(edit==0)
|
2009-01-24 13:45:24 +00:00
|
|
|
return;
|
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
LOOP_EDITED_POINTS {
|
|
|
|
key= point->keys;
|
|
|
|
for(k=0; k<point->totkey-1; k++, key++) {
|
2009-11-10 20:43:45 +00:00
|
|
|
key->length= len_v3v3(key->co, (key + 1)->co);
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* calculate a tree for finding nearest emitter's vertice */
|
|
|
|
static void recalc_emitter_field(Object *ob, ParticleSystem *psys)
|
|
|
|
{
|
|
|
|
DerivedMesh *dm=psys_get_modifier(ob,psys)->dm;
|
2009-08-29 15:20:36 +00:00
|
|
|
PTCacheEdit *edit= psys->edit;
|
2009-01-24 13:45:24 +00:00
|
|
|
MFace *mface;
|
|
|
|
MVert *mvert;
|
|
|
|
float *vec, *nor;
|
|
|
|
int i, totface, totvert;
|
|
|
|
|
2009-10-01 16:30:05 +00:00
|
|
|
if(!dm)
|
|
|
|
return;
|
|
|
|
|
2009-01-24 13:45:24 +00:00
|
|
|
if(edit->emitter_cosnos)
|
|
|
|
MEM_freeN(edit->emitter_cosnos);
|
|
|
|
|
|
|
|
BLI_kdtree_free(edit->emitter_field);
|
|
|
|
|
|
|
|
totface=dm->getNumFaces(dm);
|
|
|
|
totvert=dm->getNumVerts(dm);
|
|
|
|
|
|
|
|
edit->emitter_cosnos=MEM_callocN(totface*6*sizeof(float),"emitter cosnos");
|
|
|
|
|
|
|
|
edit->emitter_field= BLI_kdtree_new(totface);
|
|
|
|
|
|
|
|
vec=edit->emitter_cosnos;
|
|
|
|
nor=vec+3;
|
|
|
|
|
|
|
|
mvert=dm->getVertDataArray(dm,CD_MVERT);
|
2009-02-20 20:39:27 +00:00
|
|
|
for(i=0; i<totface; i++, vec+=6, nor+=6) {
|
2009-01-24 13:45:24 +00:00
|
|
|
mface=dm->getFaceData(dm,i,CD_MFACE);
|
|
|
|
|
|
|
|
mvert=dm->getVertData(dm,mface->v1,CD_MVERT);
|
|
|
|
VECCOPY(vec,mvert->co);
|
|
|
|
VECCOPY(nor,mvert->no);
|
|
|
|
|
|
|
|
mvert=dm->getVertData(dm,mface->v2,CD_MVERT);
|
|
|
|
VECADD(vec,vec,mvert->co);
|
|
|
|
VECADD(nor,nor,mvert->no);
|
|
|
|
|
|
|
|
mvert=dm->getVertData(dm,mface->v3,CD_MVERT);
|
|
|
|
VECADD(vec,vec,mvert->co);
|
|
|
|
VECADD(nor,nor,mvert->no);
|
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
if(mface->v4) {
|
2009-01-24 13:45:24 +00:00
|
|
|
mvert=dm->getVertData(dm,mface->v4,CD_MVERT);
|
|
|
|
VECADD(vec,vec,mvert->co);
|
|
|
|
VECADD(nor,nor,mvert->no);
|
|
|
|
|
2009-11-10 20:43:45 +00:00
|
|
|
mul_v3_fl(vec,0.25);
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
else
|
2009-11-10 20:43:45 +00:00
|
|
|
mul_v3_fl(vec,0.3333f);
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-11-10 20:43:45 +00:00
|
|
|
normalize_v3(nor);
|
2009-01-24 13:45:24 +00:00
|
|
|
|
|
|
|
BLI_kdtree_insert(edit->emitter_field, i, vec, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
BLI_kdtree_balance(edit->emitter_field);
|
|
|
|
}
|
|
|
|
|
2009-02-25 19:29:58 +00:00
|
|
|
static void PE_update_selection(Scene *scene, Object *ob, int useflag)
|
2009-01-24 13:45:24 +00:00
|
|
|
{
|
2009-08-29 15:20:36 +00:00
|
|
|
PTCacheEdit *edit= PE_get_current(scene, ob);
|
2009-01-24 13:45:24 +00:00
|
|
|
HairKey *hkey;
|
2009-08-29 15:20:36 +00:00
|
|
|
POINT_P; KEY_K;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
|
|
|
/* flag all particles to be updated if not using flag */
|
|
|
|
if(!useflag)
|
2009-08-29 15:20:36 +00:00
|
|
|
LOOP_POINTS
|
|
|
|
point->flag |= PEP_EDIT_RECALC;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
|
|
|
/* flush edit key flag to hair key flag to preserve selection
|
|
|
|
* on save */
|
2009-08-29 15:20:36 +00:00
|
|
|
if(edit->psys) LOOP_POINTS {
|
|
|
|
hkey = edit->psys->particles[p].hair;
|
|
|
|
LOOP_KEYS {
|
2009-01-24 13:45:24 +00:00
|
|
|
hkey->editflag= key->flag;
|
2009-08-29 15:20:36 +00:00
|
|
|
hkey++;
|
|
|
|
}
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
psys_cache_edit_paths(scene, ob, edit, CFRA);
|
2009-01-24 13:45:24 +00:00
|
|
|
|
|
|
|
|
|
|
|
/* disable update flag */
|
2009-08-29 15:20:36 +00:00
|
|
|
LOOP_POINTS
|
|
|
|
point->flag &= ~PEP_EDIT_RECALC;
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
static void update_world_cos(Object *ob, PTCacheEdit *edit)
|
|
|
|
{
|
|
|
|
ParticleSystem *psys = edit->psys;
|
|
|
|
ParticleSystemModifierData *psmd= psys_get_modifier(ob, psys);
|
|
|
|
POINT_P; KEY_K;
|
|
|
|
float hairmat[4][4];
|
|
|
|
|
2009-10-01 16:30:05 +00:00
|
|
|
if(psys==0 || psys->edit==0 || psmd->dm==NULL)
|
2009-08-29 15:20:36 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
LOOP_POINTS {
|
2009-09-05 20:12:08 +00:00
|
|
|
if(!(psys->flag & PSYS_GLOBAL_HAIR))
|
|
|
|
psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, psys->particles+p, hairmat);
|
2009-08-29 15:20:36 +00:00
|
|
|
|
|
|
|
LOOP_KEYS {
|
|
|
|
VECCOPY(key->world_co,key->co);
|
2009-09-05 20:12:08 +00:00
|
|
|
if(!(psys->flag & PSYS_GLOBAL_HAIR))
|
2009-11-10 20:43:45 +00:00
|
|
|
mul_m4_v3(hairmat, key->world_co);
|
2009-08-29 15:20:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
static void update_velocities(Object *ob, PTCacheEdit *edit)
|
|
|
|
{
|
|
|
|
/*TODO: get frs_sec properly */
|
|
|
|
float vec1[3], vec2[3], frs_sec, dfra;
|
|
|
|
POINT_P; KEY_K;
|
|
|
|
|
|
|
|
/* hair doesn't use velocities */
|
|
|
|
if(edit->psys || !edit->points || !edit->points->keys->vel)
|
|
|
|
return;
|
|
|
|
|
|
|
|
frs_sec = edit->pid.flag & PTCACHE_VEL_PER_SEC ? 25.0f : 1.0f;
|
|
|
|
|
|
|
|
LOOP_EDITED_POINTS {
|
|
|
|
LOOP_KEYS {
|
|
|
|
if(k==0) {
|
|
|
|
dfra = *(key+1)->time - *key->time;
|
|
|
|
|
|
|
|
if(dfra <= 0.0f)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
VECSUB(key->vel, (key+1)->co, key->co);
|
|
|
|
|
|
|
|
if(point->totkey>2) {
|
|
|
|
VECSUB(vec1, (key+1)->co, (key+2)->co);
|
2009-11-10 20:43:45 +00:00
|
|
|
project_v3_v3v3(vec2, vec1, key->vel);
|
2009-08-29 15:20:36 +00:00
|
|
|
VECSUB(vec2, vec1, vec2);
|
|
|
|
VECADDFAC(key->vel, key->vel, vec2, 0.5f);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if(k==point->totkey-1) {
|
|
|
|
dfra = *key->time - *(key-1)->time;
|
|
|
|
|
|
|
|
if(dfra <= 0.0f)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
VECSUB(key->vel, key->co, (key-1)->co);
|
|
|
|
|
|
|
|
if(point->totkey>2) {
|
|
|
|
VECSUB(vec1, (key-2)->co, (key-1)->co);
|
2009-11-10 20:43:45 +00:00
|
|
|
project_v3_v3v3(vec2, vec1, key->vel);
|
2009-08-29 15:20:36 +00:00
|
|
|
VECSUB(vec2, vec1, vec2);
|
|
|
|
VECADDFAC(key->vel, key->vel, vec2, 0.5f);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
dfra = *(key+1)->time - *(key-1)->time;
|
|
|
|
|
|
|
|
if(dfra <= 0.0f)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
VECSUB(key->vel, (key+1)->co, (key-1)->co);
|
|
|
|
}
|
2009-11-10 20:43:45 +00:00
|
|
|
mul_v3_fl(key->vel, frs_sec/dfra);
|
2009-08-29 15:20:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2009-12-07 17:55:58 +00:00
|
|
|
|
2009-01-24 13:45:24 +00:00
|
|
|
void PE_update_object(Scene *scene, Object *ob, int useflag)
|
|
|
|
{
|
2009-12-07 17:55:58 +00:00
|
|
|
/* use this to do partial particle updates, not usable when adding or
|
|
|
|
removing, then a full redo is necessary and calling this may crash */
|
2009-01-24 13:45:24 +00:00
|
|
|
ParticleEditSettings *pset= PE_settings(scene);
|
2009-08-29 15:20:36 +00:00
|
|
|
PTCacheEdit *edit = PE_get_current(scene, ob);
|
|
|
|
POINT_P;
|
|
|
|
|
|
|
|
if(!edit)
|
|
|
|
return;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
|
|
|
/* flag all particles to be updated if not using flag */
|
|
|
|
if(!useflag)
|
2009-08-29 15:20:36 +00:00
|
|
|
LOOP_POINTS {
|
|
|
|
point->flag |= PEP_EDIT_RECALC;
|
|
|
|
}
|
2009-01-24 13:45:24 +00:00
|
|
|
|
|
|
|
/* do post process on particle edit keys */
|
2009-08-29 15:20:36 +00:00
|
|
|
pe_iterate_lengths(scene, edit);
|
|
|
|
pe_deflect_emitter(scene, ob, edit);
|
|
|
|
PE_apply_lengths(scene, edit);
|
2010-01-05 15:23:09 +00:00
|
|
|
if(pe_x_mirror(ob))
|
2009-08-29 15:20:36 +00:00
|
|
|
PE_apply_mirror(ob,edit->psys);
|
|
|
|
if(edit->psys)
|
|
|
|
update_world_cos(ob, edit);
|
|
|
|
if(pset->flag & PE_AUTO_VELOCITY)
|
|
|
|
update_velocities(ob, edit);
|
|
|
|
PE_hide_keys_time(scene, edit, CFRA);
|
2009-01-24 13:45:24 +00:00
|
|
|
|
|
|
|
/* regenerate path caches */
|
2009-08-29 15:20:36 +00:00
|
|
|
psys_cache_edit_paths(scene, ob, edit, CFRA);
|
2009-01-24 13:45:24 +00:00
|
|
|
|
|
|
|
/* disable update flag */
|
2009-08-29 15:20:36 +00:00
|
|
|
LOOP_POINTS {
|
|
|
|
point->flag &= ~PEP_EDIT_RECALC;
|
|
|
|
}
|
|
|
|
|
2009-09-17 22:00:49 +00:00
|
|
|
if(edit->psys)
|
|
|
|
edit->psys->flag &= ~PSYS_HAIR_UPDATED;
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/************************************************/
|
|
|
|
/* Edit Selections */
|
|
|
|
/************************************************/
|
2009-02-20 20:39:27 +00:00
|
|
|
|
2009-01-24 13:45:24 +00:00
|
|
|
/*-----selection callbacks-----*/
|
2009-02-20 20:39:27 +00:00
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
static void select_key(PEData *data, int point_index, int key_index)
|
2009-01-24 13:45:24 +00:00
|
|
|
{
|
2009-08-29 15:20:36 +00:00
|
|
|
PTCacheEdit *edit = data->edit;
|
|
|
|
PTCacheEditPoint *point = edit->points + point_index;
|
|
|
|
PTCacheEditKey *key = point->keys + key_index;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
|
|
|
if(data->select)
|
2009-02-20 20:39:27 +00:00
|
|
|
key->flag |= PEK_SELECT;
|
2009-01-24 13:45:24 +00:00
|
|
|
else
|
2009-02-20 20:39:27 +00:00
|
|
|
key->flag &= ~PEK_SELECT;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
point->flag |= PEP_EDIT_RECALC;
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
static void select_keys(PEData *data, int point_index, int key_index)
|
2009-01-24 13:45:24 +00:00
|
|
|
{
|
2009-08-29 15:20:36 +00:00
|
|
|
PTCacheEdit *edit = data->edit;
|
|
|
|
PTCacheEditPoint *point = edit->points + point_index;
|
|
|
|
KEY_K;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
LOOP_KEYS {
|
2009-01-24 13:45:24 +00:00
|
|
|
if(data->select)
|
2009-02-20 20:39:27 +00:00
|
|
|
key->flag |= PEK_SELECT;
|
2009-01-24 13:45:24 +00:00
|
|
|
else
|
2009-02-20 20:39:27 +00:00
|
|
|
key->flag &= ~PEK_SELECT;
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
point->flag |= PEP_EDIT_RECALC;
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
static void toggle_key_select(PEData *data, int point_index, int key_index)
|
2009-01-24 13:45:24 +00:00
|
|
|
{
|
2009-08-29 15:20:36 +00:00
|
|
|
PTCacheEdit *edit = data->edit;
|
|
|
|
PTCacheEditPoint *point = edit->points + point_index;
|
|
|
|
PTCacheEditKey *key = point->keys + key_index;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
key->flag ^= PEK_SELECT;
|
|
|
|
point->flag |= PEP_EDIT_RECALC;
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
/************************ de select all operator ************************/
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-11-29 22:16:29 +00:00
|
|
|
static int select_all_exec(bContext *C, wmOperator *op)
|
2009-01-24 13:45:24 +00:00
|
|
|
{
|
2009-02-20 20:39:27 +00:00
|
|
|
Scene *scene= CTX_data_scene(C);
|
|
|
|
Object *ob= CTX_data_active_object(C);
|
2009-08-29 15:20:36 +00:00
|
|
|
PTCacheEdit *edit= PE_get_current(scene, ob);
|
|
|
|
POINT_P; KEY_K;
|
2009-11-29 22:16:29 +00:00
|
|
|
int action = RNA_enum_get(op->ptr, "action");
|
|
|
|
|
|
|
|
if (action == SEL_TOGGLE) {
|
|
|
|
action = SEL_SELECT;
|
|
|
|
LOOP_VISIBLE_POINTS {
|
|
|
|
LOOP_SELECTED_KEYS {
|
|
|
|
action = SEL_DESELECT;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (action == SEL_DESELECT)
|
|
|
|
break;
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-11-29 22:16:29 +00:00
|
|
|
LOOP_VISIBLE_POINTS {
|
|
|
|
LOOP_VISIBLE_KEYS {
|
|
|
|
switch (action) {
|
|
|
|
case SEL_SELECT:
|
|
|
|
if ((key->flag & PEK_SELECT) == 0) {
|
2009-01-24 13:45:24 +00:00
|
|
|
key->flag |= PEK_SELECT;
|
2009-08-29 15:20:36 +00:00
|
|
|
point->flag |= PEP_EDIT_RECALC;
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
2009-11-29 22:16:29 +00:00
|
|
|
break;
|
|
|
|
case SEL_DESELECT:
|
|
|
|
if (key->flag & PEK_SELECT) {
|
|
|
|
key->flag &= ~PEK_SELECT;
|
|
|
|
point->flag |= PEP_EDIT_RECALC;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case SEL_INVERT:
|
|
|
|
if ((key->flag & PEK_SELECT) == 0) {
|
2009-01-24 13:45:24 +00:00
|
|
|
key->flag |= PEK_SELECT;
|
2009-08-29 15:20:36 +00:00
|
|
|
point->flag |= PEP_EDIT_RECALC;
|
2009-11-29 22:16:29 +00:00
|
|
|
} else {
|
|
|
|
key->flag &= ~PEK_SELECT;
|
|
|
|
point->flag |= PEP_EDIT_RECALC;
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
2009-11-29 22:16:29 +00:00
|
|
|
break;
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
PE_update_selection(scene, ob, 1);
|
2010-06-18 04:39:32 +00:00
|
|
|
WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, ob);
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
return OPERATOR_FINISHED;
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
|
2009-11-29 22:16:29 +00:00
|
|
|
void PARTICLE_OT_select_all(wmOperatorType *ot)
|
2009-01-24 13:45:24 +00:00
|
|
|
{
|
2009-02-20 20:39:27 +00:00
|
|
|
/* identifiers */
|
2009-11-29 22:16:29 +00:00
|
|
|
ot->name= "Selection of all particles";
|
|
|
|
ot->idname= "PARTICLE_OT_select_all";
|
2009-02-20 20:39:27 +00:00
|
|
|
|
|
|
|
/* api callbacks */
|
2009-11-29 22:16:29 +00:00
|
|
|
ot->exec= select_all_exec;
|
2009-02-20 20:39:27 +00:00
|
|
|
ot->poll= PE_poll;
|
|
|
|
|
|
|
|
/* flags */
|
|
|
|
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
2009-11-29 22:16:29 +00:00
|
|
|
|
|
|
|
WM_operator_properties_select_all(ot);
|
2009-02-20 20:39:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/************************ pick select operator ************************/
|
|
|
|
|
2009-02-25 19:29:58 +00:00
|
|
|
int PE_mouse_particles(bContext *C, short *mval, int extend)
|
2009-02-20 20:39:27 +00:00
|
|
|
{
|
|
|
|
PEData data;
|
|
|
|
Scene *scene= CTX_data_scene(C);
|
|
|
|
Object *ob= CTX_data_active_object(C);
|
2009-08-29 15:20:36 +00:00
|
|
|
PTCacheEdit *edit= PE_get_current(scene, ob);
|
|
|
|
POINT_P; KEY_K;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
if(!PE_start_edit(edit))
|
2009-02-25 19:29:58 +00:00
|
|
|
return OPERATOR_CANCELLED;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-25 19:29:58 +00:00
|
|
|
if(!extend) {
|
2009-08-29 15:20:36 +00:00
|
|
|
LOOP_VISIBLE_POINTS {
|
|
|
|
LOOP_SELECTED_KEYS {
|
|
|
|
key->flag &= ~PEK_SELECT;
|
|
|
|
point->flag |= PEP_EDIT_RECALC;
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
}
|
2009-02-25 19:29:58 +00:00
|
|
|
}
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
PE_set_view3d_data(C, &data);
|
2009-01-24 13:45:24 +00:00
|
|
|
data.mval= mval;
|
|
|
|
data.rad= 75.0f;
|
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
for_mouse_hit_keys(&data, toggle_key_select, 1); /* nearest only */
|
2009-01-24 13:45:24 +00:00
|
|
|
|
|
|
|
PE_update_selection(scene, ob, 1);
|
2010-06-18 04:39:32 +00:00
|
|
|
WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, data.ob);
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-25 19:29:58 +00:00
|
|
|
return OPERATOR_FINISHED;
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
/************************ select first operator ************************/
|
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
static void select_root(PEData *data, int point_index)
|
2009-01-24 13:45:24 +00:00
|
|
|
{
|
2010-04-30 01:22:21 +00:00
|
|
|
if (data->edit->points[point_index].flag & PEP_HIDE)
|
|
|
|
return;
|
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
data->edit->points[point_index].keys->flag |= PEK_SELECT;
|
2009-11-09 08:51:34 +00:00
|
|
|
data->edit->points[point_index].flag |= PEP_EDIT_RECALC; /* redraw selection only */
|
2009-02-20 20:39:27 +00:00
|
|
|
}
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2010-04-30 01:22:21 +00:00
|
|
|
static int select_roots_exec(bContext *C, wmOperator *op)
|
2009-02-20 20:39:27 +00:00
|
|
|
{
|
|
|
|
PEData data;
|
|
|
|
|
|
|
|
PE_set_data(C, &data);
|
2009-08-29 15:20:36 +00:00
|
|
|
foreach_point(&data, select_root);
|
2009-11-09 08:51:34 +00:00
|
|
|
|
|
|
|
PE_update_selection(data.scene, data.ob, 1);
|
2010-06-18 04:39:32 +00:00
|
|
|
WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, data.ob);
|
2009-02-20 20:39:27 +00:00
|
|
|
|
|
|
|
return OPERATOR_FINISHED;
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
|
2010-04-30 01:22:21 +00:00
|
|
|
void PARTICLE_OT_select_roots(wmOperatorType *ot)
|
2009-01-24 13:45:24 +00:00
|
|
|
{
|
2009-02-20 20:39:27 +00:00
|
|
|
/* identifiers */
|
2010-04-30 01:22:21 +00:00
|
|
|
ot->name= "Select Roots";
|
|
|
|
ot->idname= "PARTICLE_OT_select_roots";
|
2009-02-20 20:39:27 +00:00
|
|
|
|
|
|
|
/* api callbacks */
|
2010-04-30 01:22:21 +00:00
|
|
|
ot->exec= select_roots_exec;
|
2009-02-20 20:39:27 +00:00
|
|
|
ot->poll= PE_poll;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
/* flags */
|
|
|
|
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
|
|
|
}
|
|
|
|
|
|
|
|
/************************ select last operator ************************/
|
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
static void select_tip(PEData *data, int point_index)
|
2009-02-20 20:39:27 +00:00
|
|
|
{
|
2009-08-29 15:20:36 +00:00
|
|
|
PTCacheEditPoint *point = data->edit->points + point_index;
|
2010-04-30 01:22:21 +00:00
|
|
|
|
|
|
|
if (point->flag & PEP_HIDE)
|
|
|
|
return;
|
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
point->keys[point->totkey - 1].flag |= PEK_SELECT;
|
2009-11-09 08:51:34 +00:00
|
|
|
point->flag |= PEP_EDIT_RECALC; /* redraw selection only */
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
|
2010-04-30 01:22:21 +00:00
|
|
|
static int select_tips_exec(bContext *C, wmOperator *op)
|
2009-01-24 13:45:24 +00:00
|
|
|
{
|
2009-02-20 20:39:27 +00:00
|
|
|
PEData data;
|
|
|
|
|
|
|
|
PE_set_data(C, &data);
|
2009-08-29 15:20:36 +00:00
|
|
|
foreach_point(&data, select_tip);
|
2009-11-09 08:51:34 +00:00
|
|
|
|
|
|
|
PE_update_selection(data.scene, data.ob, 1);
|
2010-06-18 04:39:32 +00:00
|
|
|
WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, data.ob);
|
2009-02-20 20:39:27 +00:00
|
|
|
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
|
|
|
|
2010-04-30 01:22:21 +00:00
|
|
|
void PARTICLE_OT_select_tips(wmOperatorType *ot)
|
2009-02-20 20:39:27 +00:00
|
|
|
{
|
|
|
|
/* identifiers */
|
2010-04-30 01:22:21 +00:00
|
|
|
ot->name= "Select Tips";
|
|
|
|
ot->idname= "PARTICLE_OT_select_tips";
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
/* api callbacks */
|
2010-04-30 01:22:21 +00:00
|
|
|
ot->exec= select_tips_exec;
|
2009-02-20 20:39:27 +00:00
|
|
|
ot->poll= PE_poll;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
/* flags */
|
|
|
|
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
|
|
|
}
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
/************************ select linked operator ************************/
|
|
|
|
|
|
|
|
static int select_linked_exec(bContext *C, wmOperator *op)
|
|
|
|
{
|
|
|
|
PEData data;
|
|
|
|
short mval[2];
|
|
|
|
int location[2];
|
|
|
|
|
|
|
|
RNA_int_get_array(op->ptr, "location", location);
|
|
|
|
mval[0]= location[0];
|
|
|
|
mval[1]= location[1];
|
|
|
|
|
2009-02-25 19:29:58 +00:00
|
|
|
view3d_operator_needs_opengl(C);
|
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
PE_set_view3d_data(C, &data);
|
|
|
|
data.mval= mval;
|
2009-01-24 13:45:24 +00:00
|
|
|
data.rad=75.0f;
|
2009-02-20 20:39:27 +00:00
|
|
|
data.select= !RNA_boolean_get(op->ptr, "deselect");
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
for_mouse_hit_keys(&data, select_keys, 1); /* nearest only */
|
|
|
|
PE_update_selection(data.scene, data.ob, 1);
|
2010-06-18 04:39:32 +00:00
|
|
|
WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, data.ob);
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
static int select_linked_invoke(bContext *C, wmOperator *op, wmEvent *event)
|
|
|
|
{
|
|
|
|
ARegion *ar= CTX_wm_region(C);
|
|
|
|
int location[2];
|
|
|
|
|
|
|
|
location[0]= event->x - ar->winrct.xmin;
|
|
|
|
location[1]= event->y - ar->winrct.ymin;
|
|
|
|
RNA_int_set_array(op->ptr, "location", location);
|
|
|
|
|
|
|
|
return select_linked_exec(C, op);
|
|
|
|
}
|
|
|
|
|
|
|
|
void PARTICLE_OT_select_linked(wmOperatorType *ot)
|
|
|
|
{
|
|
|
|
/* identifiers */
|
|
|
|
ot->name= "Select Linked";
|
|
|
|
ot->idname= "PARTICLE_OT_select_linked";
|
|
|
|
|
|
|
|
/* api callbacks */
|
|
|
|
ot->exec= select_linked_exec;
|
|
|
|
ot->invoke= select_linked_invoke;
|
2010-04-28 07:25:39 +00:00
|
|
|
ot->poll= PE_poll_view3d;
|
2009-02-20 20:39:27 +00:00
|
|
|
|
|
|
|
/* flags */
|
|
|
|
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
/* properties */
|
|
|
|
RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "Deselect linked keys rather than selecting them.");
|
|
|
|
RNA_def_int_vector(ot->srna, "location", 2, NULL, 0, INT_MAX, "Location", "", 0, 16384);
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
/************************ border select operator ************************/
|
|
|
|
|
2009-11-29 22:16:29 +00:00
|
|
|
int PE_border_select(bContext *C, rcti *rect, int select, int extend)
|
2009-01-24 13:45:24 +00:00
|
|
|
{
|
2009-02-25 19:29:58 +00:00
|
|
|
Scene *scene= CTX_data_scene(C);
|
|
|
|
Object *ob= CTX_data_active_object(C);
|
2009-08-29 15:20:36 +00:00
|
|
|
PTCacheEdit *edit= PE_get_current(scene, ob);
|
2009-02-20 20:39:27 +00:00
|
|
|
PEData data;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
if(!PE_start_edit(edit))
|
2009-02-25 19:29:58 +00:00
|
|
|
return OPERATOR_CANCELLED;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-11-29 22:16:29 +00:00
|
|
|
if (extend == 0 && select) {
|
|
|
|
POINT_P; KEY_K;
|
|
|
|
|
|
|
|
LOOP_VISIBLE_POINTS {
|
|
|
|
LOOP_SELECTED_KEYS {
|
|
|
|
key->flag &= ~PEK_SELECT;
|
|
|
|
point->flag |= PEP_EDIT_RECALC;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-02-25 19:29:58 +00:00
|
|
|
PE_set_view3d_data(C, &data);
|
2009-01-24 13:45:24 +00:00
|
|
|
data.rect= rect;
|
|
|
|
data.select= select;
|
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
for_mouse_hit_keys(&data, select_key, 0);
|
2009-01-24 13:45:24 +00:00
|
|
|
|
|
|
|
PE_update_selection(scene, ob, 1);
|
2010-06-18 04:39:32 +00:00
|
|
|
WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, ob);
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-25 19:29:58 +00:00
|
|
|
return OPERATOR_FINISHED;
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
/************************ circle select operator ************************/
|
|
|
|
|
2009-02-25 19:29:58 +00:00
|
|
|
int PE_circle_select(bContext *C, int selecting, short *mval, float rad)
|
2009-01-24 13:45:24 +00:00
|
|
|
{
|
2009-02-25 19:29:58 +00:00
|
|
|
Scene *scene= CTX_data_scene(C);
|
|
|
|
Object *ob= CTX_data_active_object(C);
|
2009-08-29 15:20:36 +00:00
|
|
|
PTCacheEdit *edit= PE_get_current(scene, ob);
|
2009-02-20 20:39:27 +00:00
|
|
|
PEData data;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
if(!PE_start_edit(edit))
|
2009-02-25 19:29:58 +00:00
|
|
|
return OPERATOR_FINISHED;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-25 19:29:58 +00:00
|
|
|
PE_set_view3d_data(C, &data);
|
|
|
|
data.mval= mval;
|
|
|
|
data.rad= rad;
|
2009-02-20 20:39:27 +00:00
|
|
|
data.select= selecting;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
for_mouse_hit_keys(&data, select_key, 0);
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-25 19:29:58 +00:00
|
|
|
PE_update_selection(scene, ob, 1);
|
2010-06-18 04:39:32 +00:00
|
|
|
WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, ob);
|
2009-02-25 19:29:58 +00:00
|
|
|
|
|
|
|
return OPERATOR_FINISHED;
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
/************************ lasso select operator ************************/
|
|
|
|
|
2009-02-25 19:29:58 +00:00
|
|
|
int PE_lasso_select(bContext *C, short mcords[][2], short moves, short select)
|
2009-01-24 13:45:24 +00:00
|
|
|
{
|
2009-02-25 19:29:58 +00:00
|
|
|
Scene *scene= CTX_data_scene(C);
|
|
|
|
Object *ob= CTX_data_active_object(C);
|
|
|
|
ARegion *ar= CTX_wm_region(C);
|
2009-06-23 00:41:55 +00:00
|
|
|
ParticleEditSettings *pset= PE_settings(scene);
|
2009-08-29 15:20:36 +00:00
|
|
|
PTCacheEdit *edit = PE_get_current(scene, ob);
|
|
|
|
ParticleSystem *psys = edit->psys;
|
|
|
|
ParticleSystemModifierData *psmd = psys_get_modifier(ob, psys);
|
|
|
|
POINT_P; KEY_K;
|
2009-01-24 13:45:24 +00:00
|
|
|
float co[3], mat[4][4];
|
|
|
|
short vertco[2];
|
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
if(!PE_start_edit(edit))
|
2009-02-25 19:29:58 +00:00
|
|
|
return OPERATOR_CANCELLED;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-11-10 20:43:45 +00:00
|
|
|
unit_m4(mat);
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
LOOP_VISIBLE_POINTS {
|
2009-09-05 20:12:08 +00:00
|
|
|
if(edit->psys && !(psys->flag & PSYS_GLOBAL_HAIR))
|
2009-08-29 15:20:36 +00:00
|
|
|
psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, psys->particles + p, mat);
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-06-23 00:41:55 +00:00
|
|
|
if(pset->selectmode==SCE_SELECT_POINT) {
|
2009-08-29 15:20:36 +00:00
|
|
|
LOOP_KEYS {
|
2009-01-24 13:45:24 +00:00
|
|
|
VECCOPY(co, key->co);
|
2009-11-10 20:43:45 +00:00
|
|
|
mul_m4_v3(mat, co);
|
2009-01-24 13:45:24 +00:00
|
|
|
project_short(ar, co, vertco);
|
2009-02-20 20:39:27 +00:00
|
|
|
if((vertco[0] != IS_CLIPPED) && lasso_inside(mcords,moves,vertco[0],vertco[1])) {
|
2009-01-24 13:45:24 +00:00
|
|
|
if(select && !(key->flag & PEK_SELECT)) {
|
2009-02-20 20:39:27 +00:00
|
|
|
key->flag |= PEK_SELECT;
|
2009-08-29 15:20:36 +00:00
|
|
|
point->flag |= PEP_EDIT_RECALC;
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
else if(key->flag & PEK_SELECT) {
|
2009-02-20 20:39:27 +00:00
|
|
|
key->flag &= ~PEK_SELECT;
|
2009-08-29 15:20:36 +00:00
|
|
|
point->flag |= PEP_EDIT_RECALC;
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2009-06-23 00:41:55 +00:00
|
|
|
else if(pset->selectmode==SCE_SELECT_END) {
|
2009-08-29 15:20:36 +00:00
|
|
|
key= point->keys + point->totkey - 1;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
|
|
|
VECCOPY(co, key->co);
|
2009-11-10 20:43:45 +00:00
|
|
|
mul_m4_v3(mat, co);
|
2009-01-24 13:45:24 +00:00
|
|
|
project_short(ar, co,vertco);
|
2009-02-20 20:39:27 +00:00
|
|
|
if((vertco[0] != IS_CLIPPED) && lasso_inside(mcords,moves,vertco[0],vertco[1])) {
|
2009-01-24 13:45:24 +00:00
|
|
|
if(select && !(key->flag & PEK_SELECT)) {
|
2009-02-20 20:39:27 +00:00
|
|
|
key->flag |= PEK_SELECT;
|
2009-08-29 15:20:36 +00:00
|
|
|
point->flag |= PEP_EDIT_RECALC;
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
else if(key->flag & PEK_SELECT) {
|
2009-02-20 20:39:27 +00:00
|
|
|
key->flag &= ~PEK_SELECT;
|
2009-08-29 15:20:36 +00:00
|
|
|
point->flag |= PEP_EDIT_RECALC;
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
PE_update_selection(scene, ob, 1);
|
2010-06-18 04:39:32 +00:00
|
|
|
WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, ob);
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-25 19:29:58 +00:00
|
|
|
return OPERATOR_FINISHED;
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
/*************************** hide operator **************************/
|
|
|
|
|
|
|
|
static int hide_exec(bContext *C, wmOperator *op)
|
2009-01-24 13:45:24 +00:00
|
|
|
{
|
2009-02-20 20:39:27 +00:00
|
|
|
Object *ob= CTX_data_active_object(C);
|
|
|
|
Scene *scene= CTX_data_scene(C);
|
2009-08-29 15:20:36 +00:00
|
|
|
PTCacheEdit *edit= PE_get_current(scene, ob);
|
|
|
|
POINT_P; KEY_K;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
if(RNA_enum_get(op->ptr, "unselected")) {
|
2009-08-29 15:20:36 +00:00
|
|
|
LOOP_UNSELECTED_POINTS {
|
|
|
|
point->flag |= PEP_HIDE;
|
|
|
|
point->flag |= PEP_EDIT_RECALC;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
LOOP_KEYS
|
|
|
|
key->flag &= ~PEK_SELECT;
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
}
|
2009-02-20 20:39:27 +00:00
|
|
|
else {
|
2009-08-29 15:20:36 +00:00
|
|
|
LOOP_SELECTED_POINTS {
|
|
|
|
point->flag |= PEP_HIDE;
|
|
|
|
point->flag |= PEP_EDIT_RECALC;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
LOOP_KEYS
|
|
|
|
key->flag &= ~PEK_SELECT;
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
PE_update_selection(scene, ob, 1);
|
2010-06-18 04:39:32 +00:00
|
|
|
WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, ob);
|
2009-02-20 20:39:27 +00:00
|
|
|
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PARTICLE_OT_hide(wmOperatorType *ot)
|
|
|
|
{
|
|
|
|
/* identifiers */
|
|
|
|
ot->name= "Hide Selected";
|
|
|
|
ot->idname= "PARTICLE_OT_hide";
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
/* api callbacks */
|
|
|
|
ot->exec= hide_exec;
|
|
|
|
ot->poll= PE_poll;
|
|
|
|
|
|
|
|
/* flags */
|
|
|
|
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
|
|
|
|
|
|
|
/* props */
|
|
|
|
RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected.");
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
/*************************** reveal operator **************************/
|
|
|
|
|
|
|
|
static int reveal_exec(bContext *C, wmOperator *op)
|
2009-01-24 13:45:24 +00:00
|
|
|
{
|
2009-02-20 20:39:27 +00:00
|
|
|
Object *ob= CTX_data_active_object(C);
|
|
|
|
Scene *scene= CTX_data_scene(C);
|
2009-08-29 15:20:36 +00:00
|
|
|
PTCacheEdit *edit= PE_get_current(scene, ob);
|
|
|
|
POINT_P; KEY_K;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
LOOP_POINTS {
|
|
|
|
if(point->flag & PEP_HIDE) {
|
|
|
|
point->flag &= ~PEP_HIDE;
|
|
|
|
point->flag |= PEP_EDIT_RECALC;
|
2009-02-20 20:39:27 +00:00
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
LOOP_KEYS
|
2009-02-20 20:39:27 +00:00
|
|
|
key->flag |= PEK_SELECT;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
PE_update_selection(scene, ob, 1);
|
2010-06-18 04:39:32 +00:00
|
|
|
WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, ob);
|
2009-02-20 20:39:27 +00:00
|
|
|
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PARTICLE_OT_reveal(wmOperatorType *ot)
|
|
|
|
{
|
|
|
|
/* identifiers */
|
|
|
|
ot->name= "Reveal";
|
|
|
|
ot->idname= "PARTICLE_OT_reveal";
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
/* api callbacks */
|
|
|
|
ot->exec= reveal_exec;
|
|
|
|
ot->poll= PE_poll;
|
|
|
|
|
|
|
|
/* flags */
|
|
|
|
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
/************************ select less operator ************************/
|
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
static void select_less_keys(PEData *data, int point_index)
|
2009-01-24 13:45:24 +00:00
|
|
|
{
|
2009-08-29 15:20:36 +00:00
|
|
|
PTCacheEdit *edit= data->edit;
|
|
|
|
PTCacheEditPoint *point = edit->points + point_index;
|
|
|
|
KEY_K;
|
2009-02-20 20:39:27 +00:00
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
LOOP_SELECTED_KEYS {
|
2009-02-20 20:39:27 +00:00
|
|
|
if(k==0) {
|
|
|
|
if(((key+1)->flag&PEK_SELECT)==0)
|
2009-08-29 15:20:36 +00:00
|
|
|
key->flag |= PEK_TAG;
|
2009-02-20 20:39:27 +00:00
|
|
|
}
|
2009-08-29 15:20:36 +00:00
|
|
|
else if(k==point->totkey-1) {
|
2009-02-20 20:39:27 +00:00
|
|
|
if(((key-1)->flag&PEK_SELECT)==0)
|
2009-08-29 15:20:36 +00:00
|
|
|
key->flag |= PEK_TAG;
|
2009-02-20 20:39:27 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
if((((key-1)->flag & (key+1)->flag) & PEK_SELECT)==0)
|
2009-08-29 15:20:36 +00:00
|
|
|
key->flag |= PEK_TAG;
|
2009-02-20 20:39:27 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
LOOP_KEYS {
|
2009-11-09 08:51:34 +00:00
|
|
|
if(key->flag&PEK_TAG) {
|
2009-08-29 15:20:36 +00:00
|
|
|
key->flag &= ~(PEK_TAG|PEK_SELECT);
|
2009-11-09 08:51:34 +00:00
|
|
|
point->flag |= PEP_EDIT_RECALC; /* redraw selection only */
|
|
|
|
}
|
2009-02-20 20:39:27 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int select_less_exec(bContext *C, wmOperator *op)
|
|
|
|
{
|
|
|
|
PEData data;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
PE_set_data(C, &data);
|
2009-08-29 15:20:36 +00:00
|
|
|
foreach_point(&data, select_less_keys);
|
2009-11-09 08:51:34 +00:00
|
|
|
|
|
|
|
PE_update_selection(data.scene, data.ob, 1);
|
2010-06-18 04:39:32 +00:00
|
|
|
WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, data.ob);
|
2009-02-20 20:39:27 +00:00
|
|
|
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PARTICLE_OT_select_less(wmOperatorType *ot)
|
|
|
|
{
|
|
|
|
/* identifiers */
|
|
|
|
ot->name= "Select Less";
|
|
|
|
ot->idname= "PARTICLE_OT_select_less";
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
/* api callbacks */
|
|
|
|
ot->exec= select_less_exec;
|
|
|
|
ot->poll= PE_poll;
|
|
|
|
|
|
|
|
/* flags */
|
|
|
|
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
/************************ select more operator ************************/
|
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
static void select_more_keys(PEData *data, int point_index)
|
2009-02-20 20:39:27 +00:00
|
|
|
{
|
2009-08-29 15:20:36 +00:00
|
|
|
PTCacheEdit *edit= data->edit;
|
|
|
|
PTCacheEditPoint *point = edit->points + point_index;
|
|
|
|
KEY_K;
|
2009-02-20 20:39:27 +00:00
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
LOOP_KEYS {
|
2009-02-20 20:39:27 +00:00
|
|
|
if(key->flag & PEK_SELECT) continue;
|
|
|
|
|
|
|
|
if(k==0) {
|
|
|
|
if((key+1)->flag&PEK_SELECT)
|
2009-08-29 15:20:36 +00:00
|
|
|
key->flag |= PEK_TAG;
|
2009-02-20 20:39:27 +00:00
|
|
|
}
|
2009-08-29 15:20:36 +00:00
|
|
|
else if(k==point->totkey-1) {
|
2009-02-20 20:39:27 +00:00
|
|
|
if((key-1)->flag&PEK_SELECT)
|
2009-08-29 15:20:36 +00:00
|
|
|
key->flag |= PEK_TAG;
|
2009-02-20 20:39:27 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
if(((key-1)->flag | (key+1)->flag) & PEK_SELECT)
|
2009-08-29 15:20:36 +00:00
|
|
|
key->flag |= PEK_TAG;
|
2009-02-20 20:39:27 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
LOOP_KEYS {
|
|
|
|
if(key->flag&PEK_TAG) {
|
|
|
|
key->flag &= ~PEK_TAG;
|
2009-02-20 20:39:27 +00:00
|
|
|
key->flag |= PEK_SELECT;
|
2009-11-09 08:51:34 +00:00
|
|
|
point->flag |= PEP_EDIT_RECALC; /* redraw selection only */
|
2009-02-20 20:39:27 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int select_more_exec(bContext *C, wmOperator *op)
|
|
|
|
{
|
|
|
|
PEData data;
|
|
|
|
|
|
|
|
PE_set_data(C, &data);
|
2009-08-29 15:20:36 +00:00
|
|
|
foreach_point(&data, select_more_keys);
|
2009-11-09 08:51:34 +00:00
|
|
|
|
|
|
|
PE_update_selection(data.scene, data.ob, 1);
|
2010-06-18 04:39:32 +00:00
|
|
|
WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, data.ob);
|
2009-02-20 20:39:27 +00:00
|
|
|
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PARTICLE_OT_select_more(wmOperatorType *ot)
|
|
|
|
{
|
|
|
|
/* identifiers */
|
|
|
|
ot->name= "Select More";
|
|
|
|
ot->idname= "PARTICLE_OT_select_more";
|
|
|
|
|
|
|
|
/* api callbacks */
|
|
|
|
ot->exec= select_more_exec;
|
|
|
|
ot->poll= PE_poll;
|
|
|
|
|
|
|
|
/* flags */
|
|
|
|
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
|
|
|
}
|
|
|
|
|
2009-11-09 08:51:34 +00:00
|
|
|
static int select_inverse_exec(bContext *C, wmOperator *op)
|
|
|
|
{
|
|
|
|
PEData data;
|
|
|
|
PTCacheEdit *edit;
|
|
|
|
POINT_P; KEY_K;
|
|
|
|
|
|
|
|
PE_set_data(C, &data);
|
|
|
|
|
|
|
|
edit= PE_get_current(data.scene, data.ob);
|
|
|
|
|
|
|
|
LOOP_VISIBLE_POINTS {
|
|
|
|
LOOP_KEYS {
|
|
|
|
key->flag ^= PEK_SELECT;
|
|
|
|
point->flag |= PEP_EDIT_RECALC; /* redraw selection only */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
PE_update_selection(data.scene, data.ob, 1);
|
2010-06-18 04:39:32 +00:00
|
|
|
WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, data.ob);
|
2009-11-09 08:51:34 +00:00
|
|
|
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PARTICLE_OT_select_inverse(wmOperatorType *ot)
|
|
|
|
{
|
|
|
|
/* identifiers */
|
|
|
|
ot->name= "Select Inverse";
|
|
|
|
ot->idname= "PARTICLE_OT_select_inverse";
|
|
|
|
|
|
|
|
/* api callbacks */
|
|
|
|
ot->exec= select_inverse_exec;
|
|
|
|
ot->poll= PE_poll;
|
|
|
|
|
|
|
|
/* flags */
|
|
|
|
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
|
|
|
}
|
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
/************************ rekey operator ************************/
|
|
|
|
|
|
|
|
static void rekey_particle(PEData *data, int pa_index)
|
2009-01-24 13:45:24 +00:00
|
|
|
{
|
2009-08-29 15:20:36 +00:00
|
|
|
PTCacheEdit *edit= data->edit;
|
|
|
|
ParticleSystem *psys= edit->psys;
|
2009-09-17 22:00:49 +00:00
|
|
|
ParticleSimulationData sim = {data->scene, data->ob, edit->psys, NULL};
|
2009-08-29 15:20:36 +00:00
|
|
|
ParticleData *pa= psys->particles + pa_index;
|
|
|
|
PTCacheEditPoint *point = edit->points + pa_index;
|
2009-01-24 13:45:24 +00:00
|
|
|
ParticleKey state;
|
2009-09-04 23:06:15 +00:00
|
|
|
HairKey *key, *new_keys, *okey;
|
2009-08-29 15:20:36 +00:00
|
|
|
PTCacheEditKey *ekey;
|
2009-01-24 13:45:24 +00:00
|
|
|
float dval, sta, end;
|
|
|
|
int k;
|
|
|
|
|
|
|
|
pa->flag |= PARS_REKEY;
|
|
|
|
|
2009-07-25 22:31:02 +00:00
|
|
|
key= new_keys= MEM_callocN(data->totrekey * sizeof(HairKey),"Hair re-key keys");
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-09-04 23:06:15 +00:00
|
|
|
okey = pa->hair;
|
2009-01-24 13:45:24 +00:00
|
|
|
/* root and tip stay the same */
|
2009-09-04 23:06:15 +00:00
|
|
|
VECCOPY(key->co, okey->co);
|
|
|
|
VECCOPY((key + data->totrekey - 1)->co, (okey + pa->totkey - 1)->co);
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-09-04 23:06:15 +00:00
|
|
|
sta= key->time= okey->time;
|
|
|
|
end= (key + data->totrekey - 1)->time= (okey + pa->totkey - 1)->time;
|
2009-07-25 22:31:02 +00:00
|
|
|
dval= (end - sta) / (float)(data->totrekey - 1);
|
2009-01-24 13:45:24 +00:00
|
|
|
|
|
|
|
/* interpolate new keys from old ones */
|
2009-07-25 22:31:02 +00:00
|
|
|
for(k=1,key++; k<data->totrekey-1; k++,key++) {
|
|
|
|
state.time= (float)k / (float)(data->totrekey-1);
|
2009-09-17 22:00:49 +00:00
|
|
|
psys_get_particle_on_path(&sim, pa_index, &state, 0);
|
2009-01-24 13:45:24 +00:00
|
|
|
VECCOPY(key->co, state.co);
|
2009-02-20 20:39:27 +00:00
|
|
|
key->time= sta + k * dval;
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* replace keys */
|
|
|
|
if(pa->hair)
|
|
|
|
MEM_freeN(pa->hair);
|
2009-02-20 20:39:27 +00:00
|
|
|
pa->hair= new_keys;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
point->totkey=pa->totkey=data->totrekey;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
|
|
|
|
if(point->keys)
|
|
|
|
MEM_freeN(point->keys);
|
|
|
|
ekey= point->keys= MEM_callocN(pa->totkey * sizeof(PTCacheEditKey),"Hair re-key edit keys");
|
2009-01-24 13:45:24 +00:00
|
|
|
|
|
|
|
for(k=0, key=pa->hair; k<pa->totkey; k++, key++, ekey++) {
|
2009-02-20 20:39:27 +00:00
|
|
|
ekey->co= key->co;
|
|
|
|
ekey->time= &key->time;
|
2009-09-05 20:12:08 +00:00
|
|
|
if(!(psys->flag & PSYS_GLOBAL_HAIR))
|
|
|
|
ekey->flag |= PEK_USE_WCO;
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pa->flag &= ~PARS_REKEY;
|
2009-08-29 15:20:36 +00:00
|
|
|
point->flag |= PEP_EDIT_RECALC;
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
static int rekey_exec(bContext *C, wmOperator *op)
|
2009-01-24 13:45:24 +00:00
|
|
|
{
|
2009-02-20 20:39:27 +00:00
|
|
|
PEData data;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
PE_set_data(C, &data);
|
|
|
|
|
2009-07-25 22:31:02 +00:00
|
|
|
data.dval= 1.0f / (float)(data.totrekey-1);
|
|
|
|
data.totrekey= RNA_int_get(op->ptr, "keys");
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
foreach_selected_point(&data, rekey_particle);
|
2009-02-20 20:39:27 +00:00
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
recalc_lengths(data.edit);
|
2009-02-20 20:39:27 +00:00
|
|
|
PE_update_object(data.scene, data.ob, 1);
|
2010-06-18 04:39:32 +00:00
|
|
|
WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_EDITED, data.ob);
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PARTICLE_OT_rekey(wmOperatorType *ot)
|
|
|
|
{
|
|
|
|
/* identifiers */
|
|
|
|
ot->name= "Rekey";
|
|
|
|
ot->idname= "PARTICLE_OT_rekey";
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
/* api callbacks */
|
|
|
|
ot->exec= rekey_exec;
|
2009-07-08 15:34:41 +00:00
|
|
|
ot->invoke= WM_operator_props_popup;
|
2009-02-20 20:39:27 +00:00
|
|
|
ot->poll= PE_poll;
|
|
|
|
|
|
|
|
/* flags */
|
|
|
|
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
/* properties */
|
|
|
|
RNA_def_int(ot->srna, "keys", 2, 2, INT_MAX, "Number of Keys", "", 2, 100);
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
static void rekey_particle_to_time(Scene *scene, Object *ob, int pa_index, float path_time)
|
2009-01-24 13:45:24 +00:00
|
|
|
{
|
2009-08-29 15:20:36 +00:00
|
|
|
PTCacheEdit *edit= PE_get_current(scene, ob);
|
|
|
|
ParticleSystem *psys;
|
2009-09-17 22:00:49 +00:00
|
|
|
ParticleSimulationData sim = {scene, ob, edit ? edit->psys : NULL, NULL};
|
2009-01-24 13:45:24 +00:00
|
|
|
ParticleData *pa;
|
|
|
|
ParticleKey state;
|
|
|
|
HairKey *new_keys, *key;
|
2009-08-29 15:20:36 +00:00
|
|
|
PTCacheEditKey *ekey;
|
2009-01-24 13:45:24 +00:00
|
|
|
int k;
|
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
if(!edit || !edit->psys) return;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
psys = edit->psys;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
pa= psys->particles + pa_index;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
|
|
|
pa->flag |= PARS_REKEY;
|
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
key= new_keys= MEM_dupallocN(pa->hair);
|
2009-01-24 13:45:24 +00:00
|
|
|
|
|
|
|
/* interpolate new keys from old ones (roots stay the same) */
|
|
|
|
for(k=1, key++; k < pa->totkey; k++, key++) {
|
2009-02-20 20:39:27 +00:00
|
|
|
state.time= path_time * (float)k / (float)(pa->totkey-1);
|
2009-09-17 22:00:49 +00:00
|
|
|
psys_get_particle_on_path(&sim, pa_index, &state, 0);
|
2009-01-24 13:45:24 +00:00
|
|
|
VECCOPY(key->co, state.co);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* replace hair keys */
|
|
|
|
if(pa->hair)
|
|
|
|
MEM_freeN(pa->hair);
|
2009-02-20 20:39:27 +00:00
|
|
|
pa->hair= new_keys;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
|
|
|
/* update edit pointers */
|
2009-08-29 15:20:36 +00:00
|
|
|
for(k=0, key=pa->hair, ekey=edit->points[pa_index].keys; k<pa->totkey; k++, key++, ekey++) {
|
2009-02-20 20:39:27 +00:00
|
|
|
ekey->co= key->co;
|
|
|
|
ekey->time= &key->time;
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pa->flag &= ~PARS_REKEY;
|
|
|
|
}
|
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
/************************* utilities **************************/
|
|
|
|
|
2010-01-05 15:23:09 +00:00
|
|
|
static int remove_tagged_particles(Scene *scene, Object *ob, ParticleSystem *psys, int mirror)
|
2009-01-24 13:45:24 +00:00
|
|
|
{
|
2009-08-29 15:20:36 +00:00
|
|
|
PTCacheEdit *edit = psys->edit;
|
2009-01-24 13:45:24 +00:00
|
|
|
ParticleData *pa, *npa=0, *new_pars=0;
|
2009-08-29 15:20:36 +00:00
|
|
|
POINT_P;
|
|
|
|
PTCacheEditPoint *npoint=0, *new_points=0;
|
2009-01-24 13:45:24 +00:00
|
|
|
ParticleSystemModifierData *psmd;
|
2009-02-20 20:39:27 +00:00
|
|
|
int i, totpart, new_totpart= psys->totpart, removed= 0;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2010-01-05 15:23:09 +00:00
|
|
|
if(mirror) {
|
2009-01-24 13:45:24 +00:00
|
|
|
/* mirror tags */
|
2009-02-20 20:39:27 +00:00
|
|
|
psmd= psys_get_modifier(ob, psys);
|
|
|
|
totpart= psys->totpart;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
LOOP_TAGGED_POINTS {
|
|
|
|
PE_mirror_particle(ob, psmd->dm, psys, psys->particles + p, NULL);
|
|
|
|
}
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
LOOP_TAGGED_POINTS {
|
|
|
|
new_totpart--;
|
|
|
|
removed++;
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if(new_totpart != psys->totpart) {
|
|
|
|
if(new_totpart) {
|
2009-02-20 20:39:27 +00:00
|
|
|
npa= new_pars= MEM_callocN(new_totpart * sizeof(ParticleData), "ParticleData array");
|
2009-08-29 15:20:36 +00:00
|
|
|
npoint= new_points= MEM_callocN(new_totpart * sizeof(PTCacheEditPoint), "PTCacheEditKey array");
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
pa= psys->particles;
|
2009-08-29 15:20:36 +00:00
|
|
|
point= edit->points;
|
|
|
|
for(i=0; i<psys->totpart; i++, pa++, point++) {
|
|
|
|
if(point->flag & PEP_TAG) {
|
|
|
|
if(point->keys)
|
|
|
|
MEM_freeN(point->keys);
|
2009-01-24 13:45:24 +00:00
|
|
|
if(pa->hair)
|
|
|
|
MEM_freeN(pa->hair);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
memcpy(npa, pa, sizeof(ParticleData));
|
2009-08-29 15:20:36 +00:00
|
|
|
memcpy(npoint, point, sizeof(PTCacheEditPoint));
|
2009-01-24 13:45:24 +00:00
|
|
|
npa++;
|
2009-08-29 15:20:36 +00:00
|
|
|
npoint++;
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(psys->particles) MEM_freeN(psys->particles);
|
2009-02-20 20:39:27 +00:00
|
|
|
psys->particles= new_pars;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
if(edit->points) MEM_freeN(edit->points);
|
|
|
|
edit->points= new_points;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
|
|
|
if(edit->mirror_cache) {
|
|
|
|
MEM_freeN(edit->mirror_cache);
|
2009-02-20 20:39:27 +00:00
|
|
|
edit->mirror_cache= NULL;
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
|
2009-12-07 17:55:58 +00:00
|
|
|
if(psys->child) {
|
|
|
|
MEM_freeN(psys->child);
|
|
|
|
psys->child= NULL;
|
|
|
|
psys->totchild=0;
|
|
|
|
}
|
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
edit->totpoint= psys->totpart= new_totpart;
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return removed;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void remove_tagged_keys(Scene *scene, Object *ob, ParticleSystem *psys)
|
|
|
|
{
|
2009-08-29 15:20:36 +00:00
|
|
|
PTCacheEdit *edit= psys->edit;
|
2009-01-24 13:45:24 +00:00
|
|
|
ParticleData *pa;
|
2009-08-29 15:20:36 +00:00
|
|
|
HairKey *hkey, *nhkey, *new_hkeys=0;
|
|
|
|
POINT_P; KEY_K;
|
2010-07-23 16:48:45 +00:00
|
|
|
PTCacheEditKey *nkey, *new_keys;
|
2009-01-24 13:45:24 +00:00
|
|
|
ParticleSystemModifierData *psmd;
|
|
|
|
short new_totkey;
|
|
|
|
|
2010-01-05 15:23:09 +00:00
|
|
|
if(pe_x_mirror(ob)) {
|
2009-01-24 13:45:24 +00:00
|
|
|
/* mirror key tags */
|
2009-02-20 20:39:27 +00:00
|
|
|
psmd= psys_get_modifier(ob, psys);
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
LOOP_POINTS {
|
|
|
|
LOOP_TAGGED_KEYS {
|
|
|
|
PE_mirror_particle(ob, psmd->dm, psys, psys->particles + p, NULL);
|
|
|
|
break;
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
LOOP_POINTS {
|
|
|
|
new_totkey= point->totkey;
|
|
|
|
LOOP_TAGGED_KEYS {
|
|
|
|
new_totkey--;
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
/* we can't have elements with less than two keys*/
|
|
|
|
if(new_totkey < 2)
|
2009-08-29 15:20:36 +00:00
|
|
|
point->flag |= PEP_TAG;
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
2010-01-05 15:23:09 +00:00
|
|
|
remove_tagged_particles(scene, ob, psys, pe_x_mirror(ob));
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
LOOP_POINTS {
|
|
|
|
pa = psys->particles + p;
|
2009-02-20 20:39:27 +00:00
|
|
|
new_totkey= pa->totkey;
|
2009-08-29 15:20:36 +00:00
|
|
|
|
|
|
|
LOOP_TAGGED_KEYS {
|
|
|
|
new_totkey--;
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
2009-08-29 15:20:36 +00:00
|
|
|
|
2009-01-24 13:45:24 +00:00
|
|
|
if(new_totkey != pa->totkey) {
|
2009-08-29 15:20:36 +00:00
|
|
|
nhkey= new_hkeys= MEM_callocN(new_totkey*sizeof(HairKey), "HairKeys");
|
2010-07-23 16:48:45 +00:00
|
|
|
nkey= new_keys= MEM_callocN(new_totkey*sizeof(PTCacheEditKey), "particle edit keys");
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2010-07-23 16:48:45 +00:00
|
|
|
hkey= pa->hair;
|
2009-08-29 15:20:36 +00:00
|
|
|
LOOP_KEYS {
|
|
|
|
while(key->flag & PEK_TAG && hkey < pa->hair + pa->totkey) {
|
2009-01-24 13:45:24 +00:00
|
|
|
key++;
|
2009-08-29 15:20:36 +00:00
|
|
|
hkey++;
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
if(hkey < pa->hair + pa->totkey) {
|
|
|
|
VECCOPY(nhkey->co, hkey->co);
|
2010-07-23 16:48:45 +00:00
|
|
|
nhkey->editflag = hkey->editflag;
|
2009-08-29 15:20:36 +00:00
|
|
|
nhkey->time= hkey->time;
|
|
|
|
nhkey->weight= hkey->weight;
|
2010-07-23 16:48:45 +00:00
|
|
|
|
|
|
|
nkey->co= nhkey->co;
|
|
|
|
nkey->time= &nhkey->time;
|
|
|
|
/* these can be copied from old edit keys */
|
|
|
|
nkey->flag = key->flag;
|
|
|
|
nkey->ftime = key->ftime;
|
|
|
|
nkey->length = key->length;
|
|
|
|
VECCOPY(nkey->world_co, key->world_co);
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
2010-07-23 16:48:45 +00:00
|
|
|
nkey++;
|
2009-08-29 15:20:36 +00:00
|
|
|
nhkey++;
|
2010-07-23 16:48:45 +00:00
|
|
|
hkey++;
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
2010-07-23 16:48:45 +00:00
|
|
|
|
2009-01-24 13:45:24 +00:00
|
|
|
if(pa->hair)
|
|
|
|
MEM_freeN(pa->hair);
|
2010-07-23 16:48:45 +00:00
|
|
|
|
|
|
|
if(point->keys)
|
|
|
|
MEM_freeN(point->keys);
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
pa->hair= new_hkeys;
|
2010-07-23 16:48:45 +00:00
|
|
|
point->keys= new_keys;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
point->totkey= pa->totkey= new_totkey;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2010-07-23 16:48:45 +00:00
|
|
|
/* flag for recalculating length */
|
|
|
|
point->flag |= PEP_EDIT_RECALC;
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2009-02-20 20:39:27 +00:00
|
|
|
|
|
|
|
/************************ subdivide opertor *********************/
|
|
|
|
|
2009-01-24 13:45:24 +00:00
|
|
|
/* works like normal edit mode subdivide, inserts keys between neighbouring selected keys */
|
2009-02-20 20:39:27 +00:00
|
|
|
static void subdivide_particle(PEData *data, int pa_index)
|
2009-01-24 13:45:24 +00:00
|
|
|
{
|
2009-08-29 15:20:36 +00:00
|
|
|
PTCacheEdit *edit= data->edit;
|
|
|
|
ParticleSystem *psys= edit->psys;
|
2009-09-17 22:00:49 +00:00
|
|
|
ParticleSimulationData sim = {data->scene, data->ob, edit->psys, NULL};
|
2009-08-29 15:20:36 +00:00
|
|
|
ParticleData *pa= psys->particles + pa_index;
|
|
|
|
PTCacheEditPoint *point = edit->points + pa_index;
|
2009-01-24 13:45:24 +00:00
|
|
|
ParticleKey state;
|
|
|
|
HairKey *key, *nkey, *new_keys;
|
2009-08-29 15:20:36 +00:00
|
|
|
PTCacheEditKey *ekey, *nekey, *new_ekeys;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
|
|
|
int k;
|
|
|
|
short totnewkey=0;
|
|
|
|
float endtime;
|
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
for(k=0, ekey=point->keys; k<pa->totkey-1; k++,ekey++) {
|
2009-01-24 13:45:24 +00:00
|
|
|
if(ekey->flag&PEK_SELECT && (ekey+1)->flag&PEK_SELECT)
|
|
|
|
totnewkey++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(totnewkey==0) return;
|
|
|
|
|
|
|
|
pa->flag |= PARS_REKEY;
|
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
nkey= new_keys= MEM_callocN((pa->totkey+totnewkey)*(sizeof(HairKey)),"Hair subdivide keys");
|
2009-08-29 15:20:36 +00:00
|
|
|
nekey= new_ekeys= MEM_callocN((pa->totkey+totnewkey)*(sizeof(PTCacheEditKey)),"Hair subdivide edit keys");
|
2009-09-04 23:06:15 +00:00
|
|
|
|
|
|
|
key = pa->hair;
|
|
|
|
endtime= key[pa->totkey-1].time;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-09-04 23:06:15 +00:00
|
|
|
for(k=0, ekey=point->keys; k<pa->totkey-1; k++, key++, ekey++) {
|
2009-01-24 13:45:24 +00:00
|
|
|
|
|
|
|
memcpy(nkey,key,sizeof(HairKey));
|
2009-08-29 15:20:36 +00:00
|
|
|
memcpy(nekey,ekey,sizeof(PTCacheEditKey));
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
nekey->co= nkey->co;
|
|
|
|
nekey->time= &nkey->time;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
|
|
|
nkey++;
|
|
|
|
nekey++;
|
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
if(ekey->flag & PEK_SELECT && (ekey+1)->flag & PEK_SELECT) {
|
2009-01-24 13:45:24 +00:00
|
|
|
nkey->time= (key->time + (key+1)->time)*0.5f;
|
2009-02-20 20:39:27 +00:00
|
|
|
state.time= (endtime != 0.0f)? nkey->time/endtime: 0.0f;
|
2009-09-17 22:00:49 +00:00
|
|
|
psys_get_particle_on_path(&sim, pa_index, &state, 0);
|
2009-01-24 13:45:24 +00:00
|
|
|
VECCOPY(nkey->co, state.co);
|
|
|
|
|
|
|
|
nekey->co= nkey->co;
|
|
|
|
nekey->time= &nkey->time;
|
2009-09-05 20:12:08 +00:00
|
|
|
nekey->flag |= PEK_SELECT;
|
|
|
|
if(!(psys->flag & PSYS_GLOBAL_HAIR))
|
|
|
|
nekey->flag |= PEK_USE_WCO;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
|
|
|
nekey++;
|
|
|
|
nkey++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/*tip still not copied*/
|
|
|
|
memcpy(nkey,key,sizeof(HairKey));
|
2009-08-29 15:20:36 +00:00
|
|
|
memcpy(nekey,ekey,sizeof(PTCacheEditKey));
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
nekey->co= nkey->co;
|
|
|
|
nekey->time= &nkey->time;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
|
|
|
if(pa->hair)
|
|
|
|
MEM_freeN(pa->hair);
|
2009-02-20 20:39:27 +00:00
|
|
|
pa->hair= new_keys;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
if(point->keys)
|
|
|
|
MEM_freeN(point->keys);
|
|
|
|
point->keys= new_ekeys;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
point->totkey = pa->totkey = pa->totkey + totnewkey;
|
|
|
|
point->flag |= PEP_EDIT_RECALC;
|
2009-01-24 13:45:24 +00:00
|
|
|
pa->flag &= ~PARS_REKEY;
|
|
|
|
}
|
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
static int subdivide_exec(bContext *C, wmOperator *op)
|
2009-01-24 13:45:24 +00:00
|
|
|
{
|
2009-02-20 20:39:27 +00:00
|
|
|
PEData data;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
PE_set_data(C, &data);
|
2009-08-29 15:20:36 +00:00
|
|
|
foreach_point(&data, subdivide_particle);
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
recalc_lengths(data.edit);
|
2009-02-20 20:39:27 +00:00
|
|
|
PE_update_object(data.scene, data.ob, 1);
|
2010-06-18 04:39:32 +00:00
|
|
|
WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_EDITED, data.ob);
|
2009-02-20 20:39:27 +00:00
|
|
|
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
void PARTICLE_OT_subdivide(wmOperatorType *ot)
|
|
|
|
{
|
|
|
|
/* identifiers */
|
|
|
|
ot->name= "Subdivide";
|
|
|
|
ot->idname= "PARTICLE_OT_subdivide";
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
/* api callbacks */
|
|
|
|
ot->exec= subdivide_exec;
|
|
|
|
ot->poll= PE_poll;
|
|
|
|
|
|
|
|
/* flags */
|
|
|
|
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
/************************ remove doubles opertor *********************/
|
|
|
|
|
|
|
|
static int remove_doubles_exec(bContext *C, wmOperator *op)
|
2009-01-24 13:45:24 +00:00
|
|
|
{
|
2009-02-20 20:39:27 +00:00
|
|
|
Scene *scene= CTX_data_scene(C);
|
|
|
|
Object *ob= CTX_data_active_object(C);
|
2009-08-29 15:20:36 +00:00
|
|
|
PTCacheEdit *edit= PE_get_current(scene, ob);
|
|
|
|
ParticleSystem *psys = edit->psys;
|
2009-01-24 13:45:24 +00:00
|
|
|
ParticleSystemModifierData *psmd;
|
|
|
|
KDTree *tree;
|
|
|
|
KDTreeNearest nearest[10];
|
2009-08-29 15:20:36 +00:00
|
|
|
POINT_P;
|
2009-02-20 20:39:27 +00:00
|
|
|
float mat[4][4], co[3], threshold= RNA_float_get(op->ptr, "threshold");
|
2010-01-05 15:23:09 +00:00
|
|
|
int n, totn, removed, totremoved;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-09-05 20:12:08 +00:00
|
|
|
if(psys->flag & PSYS_GLOBAL_HAIR)
|
|
|
|
return OPERATOR_CANCELLED;
|
|
|
|
|
2009-01-24 13:45:24 +00:00
|
|
|
edit= psys->edit;
|
|
|
|
psmd= psys_get_modifier(ob, psys);
|
|
|
|
totremoved= 0;
|
|
|
|
|
|
|
|
do {
|
|
|
|
removed= 0;
|
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
tree=BLI_kdtree_new(psys->totpart);
|
2009-01-24 13:45:24 +00:00
|
|
|
|
|
|
|
/* insert particles into kd tree */
|
2009-08-29 15:20:36 +00:00
|
|
|
LOOP_SELECTED_POINTS {
|
|
|
|
psys_mat_hair_to_object(ob, psmd->dm, psys->part->from, psys->particles+p, mat);
|
|
|
|
VECCOPY(co, point->keys->co);
|
2009-11-10 20:43:45 +00:00
|
|
|
mul_m4_v3(mat, co);
|
2009-08-29 15:20:36 +00:00
|
|
|
BLI_kdtree_insert(tree, p, co, NULL);
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
BLI_kdtree_balance(tree);
|
|
|
|
|
|
|
|
/* tag particles to be removed */
|
2009-08-29 15:20:36 +00:00
|
|
|
LOOP_SELECTED_POINTS {
|
|
|
|
psys_mat_hair_to_object(ob, psmd->dm, psys->part->from, psys->particles+p, mat);
|
|
|
|
VECCOPY(co, point->keys->co);
|
2009-11-10 20:43:45 +00:00
|
|
|
mul_m4_v3(mat, co);
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
totn= BLI_kdtree_find_n_nearest(tree,10,co,NULL,nearest);
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
for(n=0; n<totn; n++) {
|
|
|
|
/* this needs a custom threshold still */
|
|
|
|
if(nearest[n].index > p && nearest[n].dist < threshold) {
|
|
|
|
if(!(point->flag & PEP_TAG)) {
|
|
|
|
point->flag |= PEP_TAG;
|
|
|
|
removed++;
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
BLI_kdtree_free(tree);
|
|
|
|
|
|
|
|
/* remove tagged particles - don't do mirror here! */
|
2010-01-05 15:23:09 +00:00
|
|
|
remove_tagged_particles(scene, ob, psys, 0);
|
2009-01-24 13:45:24 +00:00
|
|
|
totremoved += removed;
|
|
|
|
} while(removed);
|
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
if(totremoved == 0)
|
|
|
|
return OPERATOR_CANCELLED;
|
|
|
|
|
|
|
|
BKE_reportf(op->reports, RPT_INFO, "Remove %d double particles.", totremoved);
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2.5
Notifiers
---------
Various fixes for wrong use of notifiers, and some new notifiers
to make things a bit more clear and consistent, with two notable
changes:
* Geometry changes are now done with NC_GEOM, rather than
NC_OBJECT|ND_GEOM_, so an object does need to be available.
* Space data now use NC_SPACE|ND_SPACE_*, instead of data
notifiers or even NC_WINDOW in some cases. Note that NC_SPACE
should only be used for notifying about changes in space data,
we don't want to go back to allqueue(REDRAW..).
Depsgraph
---------
The dependency graph now has a different flush call:
DAG_object_flush_update(scene, ob, flag)
is replaced by:
DAG_id_flush_update(id, flag)
It still works basically the same, one difference is that it now
also accepts object data (e.g. Mesh), again to avoid requiring an
Object to be available. Other ID types will simply do nothing at
the moment.
Docs
----
I made some guidelines for how/when to do which kinds of updates
and notifiers. I can't specify totally exact how to make these
decisions, but these are basically the guidelines I use. So, new
and updated docs are here:
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/NotifiersUpdates
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/DataNotifiers
2009-09-04 20:51:09 +00:00
|
|
|
DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
|
2010-06-18 04:39:32 +00:00
|
|
|
WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_EDITED, ob);
|
2009-02-20 20:39:27 +00:00
|
|
|
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PARTICLE_OT_remove_doubles(wmOperatorType *ot)
|
|
|
|
{
|
|
|
|
/* identifiers */
|
|
|
|
ot->name= "Remove Doubles";
|
|
|
|
ot->idname= "PARTICLE_OT_remove_doubles";
|
|
|
|
|
|
|
|
/* api callbacks */
|
|
|
|
ot->exec= remove_doubles_exec;
|
|
|
|
ot->poll= PE_poll;
|
|
|
|
|
|
|
|
/* flags */
|
|
|
|
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
|
|
|
|
|
|
|
/* properties */
|
|
|
|
RNA_def_float(ot->srna, "threshold", 0.0002f, 0.0f, FLT_MAX, "Threshold", "Threshold distance withing which particles are removed", 0.00001f, 0.1f);
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
|
2010-01-15 17:28:00 +00:00
|
|
|
|
|
|
|
static int weight_set_exec(bContext *C, wmOperator *op)
|
|
|
|
{
|
|
|
|
Scene *scene= CTX_data_scene(C);
|
|
|
|
ParticleEditSettings *pset= PE_settings(scene);
|
|
|
|
Object *ob= CTX_data_active_object(C);
|
|
|
|
PTCacheEdit *edit= PE_get_current(scene, ob);
|
|
|
|
ParticleSystem *psys = edit->psys;
|
|
|
|
POINT_P;
|
|
|
|
KEY_K;
|
|
|
|
HairKey *hkey;
|
|
|
|
float weight;
|
|
|
|
ParticleBrushData *brush= &pset->brush[pset->brushtype];
|
2010-04-27 09:54:36 +00:00
|
|
|
float factor= RNA_float_get(op->ptr, "factor");
|
2010-01-15 17:28:00 +00:00
|
|
|
|
2010-03-22 17:12:08 +00:00
|
|
|
weight= brush->strength;
|
2010-04-27 13:22:43 +00:00
|
|
|
edit= psys->edit;
|
2010-01-15 17:28:00 +00:00
|
|
|
|
|
|
|
LOOP_SELECTED_POINTS {
|
|
|
|
ParticleData *pa= psys->particles + p;
|
|
|
|
|
|
|
|
LOOP_SELECTED_KEYS {
|
|
|
|
hkey= pa->hair + k;
|
2010-04-27 09:54:36 +00:00
|
|
|
hkey->weight= interpf(weight, hkey->weight, factor);
|
2010-01-15 17:28:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
|
2010-06-18 04:39:32 +00:00
|
|
|
WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_EDITED, ob);
|
2010-01-15 17:28:00 +00:00
|
|
|
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PARTICLE_OT_weight_set(wmOperatorType *ot)
|
|
|
|
{
|
|
|
|
/* identifiers */
|
|
|
|
ot->name= "Weight Set";
|
|
|
|
ot->idname= "PARTICLE_OT_weight_set";
|
|
|
|
|
|
|
|
/* api callbacks */
|
|
|
|
ot->exec= weight_set_exec;
|
|
|
|
ot->poll= PE_poll;
|
|
|
|
|
|
|
|
/* flags */
|
|
|
|
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
2010-04-27 09:54:36 +00:00
|
|
|
|
|
|
|
RNA_def_float(ot->srna, "factor", 1, 0, 1, "Factor", "", 0, 1);
|
2010-01-15 17:28:00 +00:00
|
|
|
}
|
|
|
|
|
2009-02-25 19:29:58 +00:00
|
|
|
/************************ cursor drawing *******************************/
|
2009-02-20 20:39:27 +00:00
|
|
|
|
2009-02-25 19:29:58 +00:00
|
|
|
static void brush_drawcursor(bContext *C, int x, int y, void *customdata)
|
2009-01-24 13:45:24 +00:00
|
|
|
{
|
2009-02-25 19:29:58 +00:00
|
|
|
ParticleEditSettings *pset= PE_settings(CTX_data_scene(C));
|
|
|
|
ParticleBrushData *brush;
|
|
|
|
|
|
|
|
if(pset->brushtype < 0)
|
|
|
|
return;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-25 19:29:58 +00:00
|
|
|
brush= &pset->brush[pset->brushtype];
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-25 19:29:58 +00:00
|
|
|
if(brush) {
|
|
|
|
glPushMatrix();
|
|
|
|
|
|
|
|
glTranslatef((float)x, (float)y, 0.0f);
|
|
|
|
|
|
|
|
glColor4ub(255, 255, 255, 128);
|
|
|
|
glEnable(GL_LINE_SMOOTH );
|
|
|
|
glEnable(GL_BLEND);
|
|
|
|
glutil_draw_lined_arc(0.0, M_PI*2.0, brush->size, 40);
|
|
|
|
glDisable(GL_BLEND);
|
|
|
|
glDisable(GL_LINE_SMOOTH );
|
|
|
|
|
|
|
|
glPopMatrix();
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
2009-02-25 19:29:58 +00:00
|
|
|
}
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-25 19:29:58 +00:00
|
|
|
static void toggle_particle_cursor(bContext *C, int enable)
|
|
|
|
{
|
|
|
|
ParticleEditSettings *pset= PE_settings(CTX_data_scene(C));
|
|
|
|
|
|
|
|
if(pset->paintcursor && !enable) {
|
|
|
|
WM_paint_cursor_end(CTX_wm_manager(C), pset->paintcursor);
|
|
|
|
pset->paintcursor = NULL;
|
|
|
|
}
|
|
|
|
else if(enable)
|
2010-04-28 07:25:39 +00:00
|
|
|
pset->paintcursor= WM_paint_cursor_activate(CTX_wm_manager(C), PE_poll_view3d, brush_drawcursor, NULL);
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
|
2009-02-25 19:29:58 +00:00
|
|
|
/********************* radial control operator *********************/
|
|
|
|
|
|
|
|
static int brush_radial_control_invoke(bContext *C, wmOperator *op, wmEvent *event)
|
2009-01-24 13:45:24 +00:00
|
|
|
{
|
2009-02-25 19:29:58 +00:00
|
|
|
ParticleEditSettings *pset= PE_settings(CTX_data_scene(C));
|
|
|
|
ParticleBrushData *brush;
|
|
|
|
int mode = RNA_enum_get(op->ptr, "mode");
|
2009-07-16 04:45:52 +00:00
|
|
|
float original_value=1.0f;
|
2009-02-25 19:29:58 +00:00
|
|
|
|
|
|
|
if(pset->brushtype < 0)
|
|
|
|
return OPERATOR_CANCELLED;
|
|
|
|
|
|
|
|
brush= &pset->brush[pset->brushtype];
|
|
|
|
|
|
|
|
toggle_particle_cursor(C, 0);
|
|
|
|
|
|
|
|
if(mode == WM_RADIALCONTROL_SIZE)
|
|
|
|
original_value = brush->size;
|
|
|
|
else if(mode == WM_RADIALCONTROL_STRENGTH)
|
|
|
|
original_value = brush->strength;
|
|
|
|
|
|
|
|
RNA_float_set(op->ptr, "initial_value", original_value);
|
|
|
|
|
|
|
|
return WM_radial_control_invoke(C, op, event);
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
|
2009-02-25 19:29:58 +00:00
|
|
|
static int brush_radial_control_modal(bContext *C, wmOperator *op, wmEvent *event)
|
2009-01-24 13:45:24 +00:00
|
|
|
{
|
2009-02-25 19:29:58 +00:00
|
|
|
int ret = WM_radial_control_modal(C, op, event);
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-25 19:29:58 +00:00
|
|
|
if(ret != OPERATOR_RUNNING_MODAL)
|
|
|
|
toggle_particle_cursor(C, 1);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int brush_radial_control_exec(bContext *C, wmOperator *op)
|
|
|
|
{
|
|
|
|
ParticleEditSettings *pset= PE_settings(CTX_data_scene(C));
|
|
|
|
ParticleBrushData *brush;
|
|
|
|
int mode = RNA_enum_get(op->ptr, "mode");
|
|
|
|
float new_value = RNA_float_get(op->ptr, "new_value");
|
|
|
|
|
|
|
|
if(pset->brushtype < 0)
|
|
|
|
return OPERATOR_CANCELLED;
|
|
|
|
|
|
|
|
brush= &pset->brush[pset->brushtype];
|
|
|
|
|
|
|
|
if(mode == WM_RADIALCONTROL_SIZE)
|
|
|
|
brush->size= new_value;
|
|
|
|
else if(mode == WM_RADIALCONTROL_STRENGTH)
|
|
|
|
brush->strength= new_value;
|
|
|
|
|
2010-03-22 17:12:08 +00:00
|
|
|
WM_event_add_notifier(C, NC_WINDOW, NULL);
|
|
|
|
|
2009-02-25 19:29:58 +00:00
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PARTICLE_OT_brush_radial_control(wmOperatorType *ot)
|
|
|
|
{
|
|
|
|
WM_OT_radial_control_partial(ot);
|
|
|
|
|
|
|
|
ot->name= "Brush Radial Control";
|
|
|
|
ot->idname= "PARTICLE_OT_brush_radial_control";
|
|
|
|
|
|
|
|
ot->invoke= brush_radial_control_invoke;
|
|
|
|
ot->modal= brush_radial_control_modal;
|
|
|
|
ot->exec= brush_radial_control_exec;
|
|
|
|
ot->poll= PE_poll;
|
|
|
|
|
|
|
|
/* flags */
|
2009-07-11 14:51:13 +00:00
|
|
|
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO|OPTYPE_BLOCKING;
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
/*************************** delete operator **************************/
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
enum { DEL_PARTICLE, DEL_KEY };
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
static EnumPropertyItem delete_type_items[]= {
|
2009-06-16 00:52:21 +00:00
|
|
|
{DEL_PARTICLE, "PARTICLE", 0, "Particle", ""},
|
|
|
|
{DEL_KEY, "KEY", 0, "Key", ""},
|
2009-06-23 00:41:55 +00:00
|
|
|
{0, NULL, 0, NULL, NULL}};
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
static void set_delete_particle(PEData *data, int pa_index)
|
|
|
|
{
|
2009-08-29 15:20:36 +00:00
|
|
|
PTCacheEdit *edit= data->edit;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
edit->points[pa_index].flag |= PEP_TAG;
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
static void set_delete_particle_key(PEData *data, int pa_index, int key_index)
|
2009-01-24 13:45:24 +00:00
|
|
|
{
|
2009-08-29 15:20:36 +00:00
|
|
|
PTCacheEdit *edit= data->edit;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
edit->points[pa_index].keys[key_index].flag |= PEK_TAG;
|
2009-02-20 20:39:27 +00:00
|
|
|
}
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
static int delete_exec(bContext *C, wmOperator *op)
|
|
|
|
{
|
|
|
|
PEData data;
|
|
|
|
int type= RNA_enum_get(op->ptr, "type");
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
PE_set_data(C, &data);
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
if(type == DEL_KEY) {
|
|
|
|
foreach_selected_key(&data, set_delete_particle_key);
|
2009-08-29 15:20:36 +00:00
|
|
|
remove_tagged_keys(data.scene, data.ob, data.edit->psys);
|
|
|
|
recalc_lengths(data.edit);
|
2009-02-20 20:39:27 +00:00
|
|
|
}
|
|
|
|
else if(type == DEL_PARTICLE) {
|
2009-08-29 15:20:36 +00:00
|
|
|
foreach_selected_point(&data, set_delete_particle);
|
2010-01-05 15:23:09 +00:00
|
|
|
remove_tagged_particles(data.scene, data.ob, data.edit->psys, pe_x_mirror(data.ob));
|
2009-08-29 15:20:36 +00:00
|
|
|
recalc_lengths(data.edit);
|
2009-02-20 20:39:27 +00:00
|
|
|
}
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2.5
Notifiers
---------
Various fixes for wrong use of notifiers, and some new notifiers
to make things a bit more clear and consistent, with two notable
changes:
* Geometry changes are now done with NC_GEOM, rather than
NC_OBJECT|ND_GEOM_, so an object does need to be available.
* Space data now use NC_SPACE|ND_SPACE_*, instead of data
notifiers or even NC_WINDOW in some cases. Note that NC_SPACE
should only be used for notifying about changes in space data,
we don't want to go back to allqueue(REDRAW..).
Depsgraph
---------
The dependency graph now has a different flush call:
DAG_object_flush_update(scene, ob, flag)
is replaced by:
DAG_id_flush_update(id, flag)
It still works basically the same, one difference is that it now
also accepts object data (e.g. Mesh), again to avoid requiring an
Object to be available. Other ID types will simply do nothing at
the moment.
Docs
----
I made some guidelines for how/when to do which kinds of updates
and notifiers. I can't specify totally exact how to make these
decisions, but these are basically the guidelines I use. So, new
and updated docs are here:
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/NotifiersUpdates
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/DataNotifiers
2009-09-04 20:51:09 +00:00
|
|
|
DAG_id_flush_update(&data.ob->id, OB_RECALC_DATA);
|
2010-06-18 04:39:32 +00:00
|
|
|
WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_EDITED, data.ob);
|
2009-02-20 20:39:27 +00:00
|
|
|
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PARTICLE_OT_delete(wmOperatorType *ot)
|
|
|
|
{
|
|
|
|
/* identifiers */
|
|
|
|
ot->name= "Delete";
|
|
|
|
ot->idname= "PARTICLE_OT_delete";
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
/* api callbacks */
|
|
|
|
ot->exec= delete_exec;
|
|
|
|
ot->invoke= WM_menu_invoke;
|
2009-09-10 22:32:33 +00:00
|
|
|
ot->poll= PE_hair_poll;
|
2009-02-20 20:39:27 +00:00
|
|
|
|
|
|
|
/* flags */
|
|
|
|
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
|
|
|
|
|
|
|
/* properties */
|
2010-01-15 22:40:33 +00:00
|
|
|
ot->prop= RNA_def_enum(ot->srna, "type", delete_type_items, DEL_PARTICLE, "Type", "Delete a full particle or only keys.");
|
2009-02-20 20:39:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*************************** mirror operator **************************/
|
|
|
|
|
|
|
|
static void PE_mirror_x(Scene *scene, Object *ob, int tagged)
|
|
|
|
{
|
|
|
|
Mesh *me= (Mesh*)(ob->data);
|
|
|
|
ParticleSystemModifierData *psmd;
|
2009-08-29 15:20:36 +00:00
|
|
|
PTCacheEdit *edit= PE_get_current(scene, ob);
|
|
|
|
ParticleSystem *psys = edit->psys;
|
2009-02-20 20:39:27 +00:00
|
|
|
ParticleData *pa, *newpa, *new_pars;
|
2009-08-29 15:20:36 +00:00
|
|
|
PTCacheEditPoint *newpoint, *new_points;
|
|
|
|
POINT_P; KEY_K;
|
2009-02-20 20:39:27 +00:00
|
|
|
HairKey *hkey;
|
|
|
|
int *mirrorfaces;
|
2009-08-29 15:20:36 +00:00
|
|
|
int rotation, totpart, newtotpart;
|
2009-02-20 20:39:27 +00:00
|
|
|
|
2009-09-05 20:12:08 +00:00
|
|
|
if(psys->flag & PSYS_GLOBAL_HAIR)
|
|
|
|
return;
|
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
psmd= psys_get_modifier(ob, psys);
|
2009-10-01 16:30:05 +00:00
|
|
|
if(!psmd->dm)
|
|
|
|
return;
|
2009-02-20 20:39:27 +00:00
|
|
|
|
2009-02-25 19:29:58 +00:00
|
|
|
mirrorfaces= mesh_get_x_mirror_faces(ob, NULL);
|
2009-02-20 20:39:27 +00:00
|
|
|
|
|
|
|
if(!edit->mirror_cache)
|
|
|
|
PE_update_mirror_cache(ob, psys);
|
|
|
|
|
|
|
|
totpart= psys->totpart;
|
|
|
|
newtotpart= psys->totpart;
|
2009-08-29 15:20:36 +00:00
|
|
|
LOOP_VISIBLE_POINTS {
|
|
|
|
pa = psys->particles + p;
|
2009-02-20 20:39:27 +00:00
|
|
|
if(!tagged) {
|
2009-08-29 15:20:36 +00:00
|
|
|
if(point_is_selected(point)) {
|
|
|
|
if(edit->mirror_cache[p] != -1) {
|
2009-02-20 20:39:27 +00:00
|
|
|
/* already has a mirror, don't need to duplicate */
|
|
|
|
PE_mirror_particle(ob, psmd->dm, psys, pa, NULL);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
else
|
2009-08-29 15:20:36 +00:00
|
|
|
point->flag |= PEP_TAG;
|
2009-02-20 20:39:27 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
if((point->flag & PEP_TAG) && mirrorfaces[pa->num*2] != -1)
|
2009-02-20 20:39:27 +00:00
|
|
|
newtotpart++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(newtotpart != psys->totpart) {
|
|
|
|
/* allocate new arrays and copy existing */
|
|
|
|
new_pars= MEM_callocN(newtotpart*sizeof(ParticleData), "ParticleData new");
|
2009-08-29 15:20:36 +00:00
|
|
|
new_points= MEM_callocN(newtotpart*sizeof(PTCacheEditPoint), "PTCacheEditPoint new");
|
2009-02-20 20:39:27 +00:00
|
|
|
|
2009-06-08 20:08:19 +00:00
|
|
|
if(psys->particles) {
|
|
|
|
memcpy(new_pars, psys->particles, totpart*sizeof(ParticleData));
|
|
|
|
MEM_freeN(psys->particles);
|
|
|
|
}
|
2009-02-20 20:39:27 +00:00
|
|
|
psys->particles= new_pars;
|
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
if(edit->points) {
|
|
|
|
memcpy(new_points, edit->points, totpart*sizeof(PTCacheEditPoint));
|
|
|
|
MEM_freeN(edit->points);
|
2009-06-08 20:08:19 +00:00
|
|
|
}
|
2009-08-29 15:20:36 +00:00
|
|
|
edit->points= new_points;
|
2009-02-20 20:39:27 +00:00
|
|
|
|
|
|
|
if(edit->mirror_cache) {
|
|
|
|
MEM_freeN(edit->mirror_cache);
|
|
|
|
edit->mirror_cache= NULL;
|
|
|
|
}
|
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
edit->totpoint= psys->totpart= newtotpart;
|
2009-02-20 20:39:27 +00:00
|
|
|
|
|
|
|
/* create new elements */
|
|
|
|
newpa= psys->particles + totpart;
|
2009-08-29 15:20:36 +00:00
|
|
|
newpoint= edit->points + totpart;
|
2009-02-20 20:39:27 +00:00
|
|
|
|
2010-01-05 15:23:09 +00:00
|
|
|
for(p=0, point=edit->points; p<totpart; p++, point++) {
|
2009-08-29 15:20:36 +00:00
|
|
|
pa = psys->particles + p;
|
2009-02-20 20:39:27 +00:00
|
|
|
|
2010-01-05 15:23:09 +00:00
|
|
|
if(point->flag & PEP_HIDE)
|
|
|
|
continue;
|
2009-08-29 15:20:36 +00:00
|
|
|
if(!(point->flag & PEP_TAG) || mirrorfaces[pa->num*2] == -1)
|
2009-02-20 20:39:27 +00:00
|
|
|
continue;
|
|
|
|
|
|
|
|
/* duplicate */
|
|
|
|
*newpa= *pa;
|
2009-08-29 15:20:36 +00:00
|
|
|
*newpoint= *point;
|
2009-02-20 20:39:27 +00:00
|
|
|
if(pa->hair) newpa->hair= MEM_dupallocN(pa->hair);
|
2009-08-29 15:20:36 +00:00
|
|
|
if(point->keys) newpoint->keys= MEM_dupallocN(point->keys);
|
2009-02-20 20:39:27 +00:00
|
|
|
|
|
|
|
/* rotate weights according to vertex index rotation */
|
|
|
|
rotation= mirrorfaces[pa->num*2+1];
|
|
|
|
newpa->fuv[0]= pa->fuv[2];
|
|
|
|
newpa->fuv[1]= pa->fuv[1];
|
|
|
|
newpa->fuv[2]= pa->fuv[0];
|
|
|
|
newpa->fuv[3]= pa->fuv[3];
|
|
|
|
while(rotation-- > 0)
|
|
|
|
if(me->mface[pa->num].v4)
|
|
|
|
SHIFT4(float, newpa->fuv[0], newpa->fuv[1], newpa->fuv[2], newpa->fuv[3])
|
|
|
|
else
|
|
|
|
SHIFT3(float, newpa->fuv[0], newpa->fuv[1], newpa->fuv[2])
|
|
|
|
|
|
|
|
/* assign face inddex */
|
|
|
|
newpa->num= mirrorfaces[pa->num*2];
|
|
|
|
newpa->num_dmcache= psys_particle_dm_face_lookup(ob,psmd->dm,newpa->num,newpa->fuv, NULL);
|
|
|
|
|
|
|
|
/* update edit key pointers */
|
2009-08-29 15:20:36 +00:00
|
|
|
key= newpoint->keys;
|
|
|
|
for(k=0, hkey=newpa->hair; k<newpa->totkey; k++, hkey++, key++) {
|
|
|
|
key->co= hkey->co;
|
|
|
|
key->time= &hkey->time;
|
2009-02-20 20:39:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* map key positions as mirror over x axis */
|
|
|
|
PE_mirror_particle(ob, psmd->dm, psys, pa, newpa);
|
|
|
|
|
|
|
|
newpa++;
|
2009-08-29 15:20:36 +00:00
|
|
|
newpoint++;
|
2009-02-20 20:39:27 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
LOOP_POINTS {
|
|
|
|
point->flag &= ~PEP_TAG;
|
|
|
|
}
|
2009-02-20 20:39:27 +00:00
|
|
|
|
|
|
|
MEM_freeN(mirrorfaces);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int mirror_exec(bContext *C, wmOperator *op)
|
|
|
|
{
|
|
|
|
Scene *scene= CTX_data_scene(C);
|
|
|
|
Object *ob= CTX_data_active_object(C);
|
2009-08-29 15:20:36 +00:00
|
|
|
PTCacheEdit *edit= PE_get_current(scene, ob);
|
2009-02-20 20:39:27 +00:00
|
|
|
|
|
|
|
PE_mirror_x(scene, ob, 0);
|
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
update_world_cos(ob, edit);
|
2010-06-18 04:39:32 +00:00
|
|
|
WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_EDITED, ob);
|
2.5
Notifiers
---------
Various fixes for wrong use of notifiers, and some new notifiers
to make things a bit more clear and consistent, with two notable
changes:
* Geometry changes are now done with NC_GEOM, rather than
NC_OBJECT|ND_GEOM_, so an object does need to be available.
* Space data now use NC_SPACE|ND_SPACE_*, instead of data
notifiers or even NC_WINDOW in some cases. Note that NC_SPACE
should only be used for notifying about changes in space data,
we don't want to go back to allqueue(REDRAW..).
Depsgraph
---------
The dependency graph now has a different flush call:
DAG_object_flush_update(scene, ob, flag)
is replaced by:
DAG_id_flush_update(id, flag)
It still works basically the same, one difference is that it now
also accepts object data (e.g. Mesh), again to avoid requiring an
Object to be available. Other ID types will simply do nothing at
the moment.
Docs
----
I made some guidelines for how/when to do which kinds of updates
and notifiers. I can't specify totally exact how to make these
decisions, but these are basically the guidelines I use. So, new
and updated docs are here:
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/NotifiersUpdates
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/DataNotifiers
2009-09-04 20:51:09 +00:00
|
|
|
DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
|
2009-02-20 20:39:27 +00:00
|
|
|
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PARTICLE_OT_mirror(wmOperatorType *ot)
|
|
|
|
{
|
|
|
|
/* identifiers */
|
|
|
|
ot->name= "Mirror";
|
|
|
|
ot->idname= "PARTICLE_OT_mirror";
|
|
|
|
|
|
|
|
/* api callbacks */
|
|
|
|
ot->exec= mirror_exec;
|
|
|
|
ot->poll= PE_poll;
|
|
|
|
|
|
|
|
/* flags */
|
|
|
|
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
|
|
|
}
|
|
|
|
|
|
|
|
/************************* brush edit callbacks ********************/
|
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
static void brush_comb(PEData *data, float mat[][4], float imat[][4], int point_index, int key_index, PTCacheEditKey *key)
|
2009-02-20 20:39:27 +00:00
|
|
|
{
|
|
|
|
ParticleEditSettings *pset= PE_settings(data->scene);
|
|
|
|
float cvec[3], fac;
|
|
|
|
|
|
|
|
if(pset->flag & PE_LOCK_FIRST && key_index == 0) return;
|
|
|
|
|
|
|
|
fac= (float)pow((double)(1.0f - data->dist / data->rad), (double)data->combfac);
|
|
|
|
|
|
|
|
VECCOPY(cvec,data->dvec);
|
2009-11-10 20:43:45 +00:00
|
|
|
mul_mat3_m4_v3(imat,cvec);
|
|
|
|
mul_v3_fl(cvec, fac);
|
2009-02-20 20:39:27 +00:00
|
|
|
VECADD(key->co, key->co, cvec);
|
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
(data->edit->points + point_index)->flag |= PEP_EDIT_RECALC;
|
2009-02-20 20:39:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void brush_cut(PEData *data, int pa_index)
|
|
|
|
{
|
2009-08-29 15:20:36 +00:00
|
|
|
PTCacheEdit *edit = data->edit;
|
2009-02-20 20:39:27 +00:00
|
|
|
ARegion *ar= data->vc.ar;
|
|
|
|
Object *ob= data->ob;
|
2009-08-29 15:20:36 +00:00
|
|
|
ParticleEditSettings *pset= PE_settings(data->scene);
|
|
|
|
ParticleCacheKey *key= edit->pathcache[pa_index];
|
2009-02-20 20:39:27 +00:00
|
|
|
float rad2, cut_time= 1.0;
|
|
|
|
float x0, x1, v0, v1, o0, o1, xo0, xo1, d, dv;
|
2009-08-29 15:20:36 +00:00
|
|
|
int k, cut, keys= (int)pow(2.0, (double)pset->draw_step);
|
2009-02-20 20:39:27 +00:00
|
|
|
short vertco[2];
|
|
|
|
|
|
|
|
/* blunt scissors */
|
|
|
|
if(BLI_frand() > data->cutfac) return;
|
|
|
|
|
2009-10-18 19:48:33 +00:00
|
|
|
/* don't cut hidden */
|
|
|
|
if(edit->points[pa_index].flag & PEP_HIDE)
|
|
|
|
return;
|
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
rad2= data->rad * data->rad;
|
|
|
|
|
|
|
|
cut=0;
|
|
|
|
|
|
|
|
project_short_noclip(ar, key->co, vertco);
|
|
|
|
x0= (float)vertco[0];
|
|
|
|
x1= (float)vertco[1];
|
|
|
|
|
|
|
|
o0= (float)data->mval[0];
|
|
|
|
o1= (float)data->mval[1];
|
|
|
|
|
|
|
|
xo0= x0 - o0;
|
|
|
|
xo1= x1 - o1;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
|
|
|
/* check if root is inside circle */
|
2009-02-20 20:39:27 +00:00
|
|
|
if(xo0*xo0 + xo1*xo1 < rad2 && key_test_depth(data, key->co)) {
|
|
|
|
cut_time= -1.0f;
|
|
|
|
cut= 1;
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* calculate path time closest to root that was inside the circle */
|
2009-02-20 20:39:27 +00:00
|
|
|
for(k=1, key++; k<=keys; k++, key++) {
|
2009-01-24 13:45:24 +00:00
|
|
|
project_short_noclip(ar, key->co, vertco);
|
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
if(key_test_depth(data, key->co) == 0) {
|
|
|
|
x0= (float)vertco[0];
|
|
|
|
x1= (float)vertco[1];
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
xo0= x0 - o0;
|
|
|
|
xo1= x1 - o1;
|
2009-01-24 13:45:24 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
v0= (float)vertco[0] - x0;
|
|
|
|
v1= (float)vertco[1] - x1;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
dv= v0*v0 + v1*v1;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
d= (v0*xo1 - v1*xo0);
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
d= dv * rad2 - d*d;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
|
|
|
if(d > 0.0f) {
|
2009-02-20 20:39:27 +00:00
|
|
|
d= sqrt(d);
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
cut_time= -(v0*xo0 + v1*xo1 + d);
|
2009-01-24 13:45:24 +00:00
|
|
|
|
|
|
|
if(cut_time > 0.0f) {
|
|
|
|
cut_time /= dv;
|
|
|
|
|
|
|
|
if(cut_time < 1.0f) {
|
|
|
|
cut_time += (float)(k-1);
|
|
|
|
cut_time /= (float)keys;
|
2009-02-20 20:39:27 +00:00
|
|
|
cut= 1;
|
2009-01-24 13:45:24 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
x0= (float)vertco[0];
|
|
|
|
x1= (float)vertco[1];
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
xo0= x0 - o0;
|
|
|
|
xo1= x1 - o1;
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(cut) {
|
|
|
|
if(cut_time < 0.0f) {
|
2009-08-29 15:20:36 +00:00
|
|
|
edit->points[pa_index].flag |= PEP_TAG;
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
else {
|
2009-02-20 20:39:27 +00:00
|
|
|
rekey_particle_to_time(data->scene, ob, pa_index, cut_time);
|
2009-08-29 15:20:36 +00:00
|
|
|
edit->points[pa_index].flag |= PEP_EDIT_RECALC;
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
static void brush_length(PEData *data, int point_index)
|
2009-01-24 13:45:24 +00:00
|
|
|
{
|
2009-08-29 15:20:36 +00:00
|
|
|
PTCacheEdit *edit= data->edit;
|
|
|
|
PTCacheEditPoint *point = edit->points + point_index;
|
|
|
|
KEY_K;
|
2009-10-21 17:56:26 +00:00
|
|
|
float dvec[3],pvec[3] = {0.0f, 0.0f, 0.0f};
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
LOOP_KEYS {
|
|
|
|
if(k==0) {
|
|
|
|
VECCOPY(pvec,key->co);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
VECSUB(dvec,key->co,pvec);
|
|
|
|
VECCOPY(pvec,key->co);
|
2009-11-10 20:43:45 +00:00
|
|
|
mul_v3_fl(dvec,data->growfac);
|
2009-08-29 15:20:36 +00:00
|
|
|
VECADD(key->co,(key-1)->co,dvec);
|
|
|
|
}
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
point->flag |= PEP_EDIT_RECALC;
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
static void brush_puff(PEData *data, int point_index)
|
2009-01-24 13:45:24 +00:00
|
|
|
{
|
2009-08-29 15:20:36 +00:00
|
|
|
PTCacheEdit *edit = data->edit;
|
|
|
|
ParticleSystem *psys = edit->psys;
|
|
|
|
PTCacheEditPoint *point = edit->points + point_index;
|
|
|
|
KEY_K;
|
2009-01-24 13:45:24 +00:00
|
|
|
float mat[4][4], imat[4][4];
|
2010-01-12 14:52:09 +00:00
|
|
|
|
2010-01-12 16:35:34 +00:00
|
|
|
float lastco[3], rootco[3] = {0.0f, 0.0f, 0.0f}, co[3], nor[3], kco[3], dco[3], ofs[3] = {0.0f, 0.0f, 0.0f}, fac=0.0f, length=0.0f;
|
|
|
|
int puff_volume = 0;
|
|
|
|
int change= 0;
|
|
|
|
|
|
|
|
{
|
|
|
|
ParticleEditSettings *pset= PE_settings(data->scene);
|
|
|
|
ParticleBrushData *brush= &pset->brush[pset->brushtype];
|
|
|
|
puff_volume = brush->flag & PE_BRUSH_DATA_PUFF_VOLUME;
|
|
|
|
}
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-09-05 20:12:08 +00:00
|
|
|
if(psys && !(psys->flag & PSYS_GLOBAL_HAIR)) {
|
2009-08-29 15:20:36 +00:00
|
|
|
psys_mat_hair_to_global(data->ob, data->dm, psys->part->from, psys->particles + point_index, mat);
|
2009-11-10 20:43:45 +00:00
|
|
|
invert_m4_m4(imat,mat);
|
2009-08-29 15:20:36 +00:00
|
|
|
}
|
|
|
|
else {
|
2009-11-10 20:43:45 +00:00
|
|
|
unit_m4(mat);
|
|
|
|
unit_m4(imat);
|
2009-08-29 15:20:36 +00:00
|
|
|
}
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
LOOP_KEYS {
|
|
|
|
if(k==0) {
|
|
|
|
/* find root coordinate and normal on emitter */
|
|
|
|
VECCOPY(co, key->co);
|
2009-11-10 20:43:45 +00:00
|
|
|
mul_m4_v3(mat, co);
|
2010-01-14 08:53:10 +00:00
|
|
|
mul_v3_m4v3(kco, data->ob->imat, co); /* use 'kco' as the object space version of worldspace 'co', ob->imat is set before calling */
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2010-01-12 14:52:09 +00:00
|
|
|
point_index= BLI_kdtree_find_nearest(edit->emitter_field, kco, NULL, NULL);
|
2009-08-29 15:20:36 +00:00
|
|
|
if(point_index == -1) return;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
VECCOPY(rootco, co);
|
2009-11-10 20:43:45 +00:00
|
|
|
copy_v3_v3(nor, &edit->emitter_cosnos[point_index*6+3]);
|
2010-01-14 08:53:10 +00:00
|
|
|
mul_mat3_m4_v3(data->ob->obmat, nor); /* normal into worldspace */
|
2010-01-12 14:52:09 +00:00
|
|
|
|
2009-11-10 20:43:45 +00:00
|
|
|
normalize_v3(nor);
|
2009-08-29 15:20:36 +00:00
|
|
|
length= 0.0f;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
fac= (float)pow((double)(1.0f - data->dist / data->rad), (double)data->pufffac);
|
|
|
|
fac *= 0.025f;
|
|
|
|
if(data->invert)
|
|
|
|
fac= -fac;
|
|
|
|
}
|
|
|
|
else {
|
2010-01-12 16:35:34 +00:00
|
|
|
/* compute position as if hair was standing up straight.
|
|
|
|
* */
|
2009-08-29 15:20:36 +00:00
|
|
|
VECCOPY(lastco, co);
|
|
|
|
VECCOPY(co, key->co);
|
2009-11-10 20:43:45 +00:00
|
|
|
mul_m4_v3(mat, co);
|
|
|
|
length += len_v3v3(lastco, co);
|
2010-03-22 17:12:08 +00:00
|
|
|
if((data->select==0 || (key->flag & PEK_SELECT)) && !(key->flag & PEK_HIDE)) {
|
2010-01-12 16:35:34 +00:00
|
|
|
VECADDFAC(kco, rootco, nor, length);
|
|
|
|
|
|
|
|
/* blend between the current and straight position */
|
|
|
|
VECSUB(dco, kco, co);
|
|
|
|
VECADDFAC(co, co, dco, fac);
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2010-01-12 16:35:34 +00:00
|
|
|
/* re-use dco to compare before and after translation and add to the offset */
|
|
|
|
VECCOPY(dco, key->co);
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2010-01-12 16:35:34 +00:00
|
|
|
mul_v3_m4v3(key->co, imat, co);
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2010-01-12 16:35:34 +00:00
|
|
|
if(puff_volume) {
|
|
|
|
/* accumulate the total distance moved to apply to unselected
|
|
|
|
* keys that come after */
|
|
|
|
ofs[0] += key->co[0] - dco[0];
|
|
|
|
ofs[1] += key->co[1] - dco[1];
|
|
|
|
ofs[2] += key->co[2] - dco[2];
|
|
|
|
}
|
|
|
|
change = 1;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
|
|
|
|
if(puff_volume) {
|
|
|
|
#if 0
|
|
|
|
/* this is simple but looks bad, adds annoying kinks */
|
|
|
|
add_v3_v3(key->co, ofs);
|
|
|
|
#else
|
|
|
|
/* translate (not rotate) the rest of the hair if its not selected */
|
|
|
|
if(ofs[0] || ofs[1] || ofs[2]) {
|
2010-01-14 16:14:24 +00:00
|
|
|
#if 0 /* kindof works but looks worse then whats below */
|
|
|
|
|
|
|
|
/* Move the unselected point on a vector based on the
|
|
|
|
* hair direction and the offset */
|
2010-01-12 16:35:34 +00:00
|
|
|
float c1[3], c2[3];
|
|
|
|
VECSUB(dco, lastco, co);
|
2010-01-14 16:14:24 +00:00
|
|
|
mul_mat3_m4_v3(imat, dco); /* into particle space */
|
2010-01-12 16:35:34 +00:00
|
|
|
|
|
|
|
/* move the point allong a vector perpendicular to the
|
|
|
|
* hairs direction, reduces odd kinks, */
|
|
|
|
cross_v3_v3v3(c1, ofs, dco);
|
|
|
|
cross_v3_v3v3(c2, c1, dco);
|
|
|
|
normalize_v3(c2);
|
|
|
|
mul_v3_fl(c2, len_v3(ofs));
|
|
|
|
add_v3_v3(key->co, c2);
|
2010-01-14 16:14:24 +00:00
|
|
|
#else
|
|
|
|
/* Move the unselected point on a vector based on the
|
|
|
|
* the normal of the closest geometry */
|
|
|
|
float oco[3], onor[3];
|
|
|
|
VECCOPY(oco, key->co);
|
|
|
|
mul_m4_v3(mat, oco);
|
|
|
|
mul_v3_m4v3(kco, data->ob->imat, oco); /* use 'kco' as the object space version of worldspace 'co', ob->imat is set before calling */
|
|
|
|
|
|
|
|
point_index= BLI_kdtree_find_nearest(edit->emitter_field, kco, NULL, NULL);
|
|
|
|
if(point_index != -1) {
|
|
|
|
copy_v3_v3(onor, &edit->emitter_cosnos[point_index*6+3]);
|
|
|
|
mul_mat3_m4_v3(data->ob->obmat, onor); /* normal into worldspace */
|
|
|
|
mul_mat3_m4_v3(imat, onor); /* worldspace into particle space */
|
|
|
|
normalize_v3(onor);
|
|
|
|
|
|
|
|
|
|
|
|
mul_v3_fl(onor, len_v3(ofs));
|
|
|
|
add_v3_v3(key->co, onor);
|
|
|
|
}
|
|
|
|
#endif
|
2010-01-12 16:35:34 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
2009-08-29 15:20:36 +00:00
|
|
|
}
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
|
2010-01-12 16:35:34 +00:00
|
|
|
if(change)
|
|
|
|
point->flag |= PEP_EDIT_RECALC;
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
|
2010-01-14 08:53:10 +00:00
|
|
|
|
|
|
|
static void brush_weight(PEData *data, float mat[][4], float imat[][4], int point_index, int key_index, PTCacheEditKey *key)
|
|
|
|
{
|
|
|
|
/* roots have full weight allways */
|
|
|
|
if(key_index) {
|
|
|
|
PTCacheEdit *edit = data->edit;
|
|
|
|
ParticleSystem *psys = edit->psys;
|
|
|
|
|
|
|
|
ParticleData *pa= psys->particles + point_index;
|
|
|
|
pa->hair[key_index].weight = data->weightfac;
|
|
|
|
|
|
|
|
(data->edit->points + point_index)->flag |= PEP_EDIT_RECALC;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
static void brush_smooth_get(PEData *data, float mat[][4], float imat[][4], int point_index, int key_index, PTCacheEditKey *key)
|
|
|
|
{
|
2009-02-20 20:39:27 +00:00
|
|
|
if(key_index) {
|
2009-01-24 13:45:24 +00:00
|
|
|
float dvec[3];
|
|
|
|
|
2009-11-10 20:43:45 +00:00
|
|
|
sub_v3_v3v3(dvec,key->co,(key-1)->co);
|
|
|
|
mul_mat3_m4_v3(mat,dvec);
|
2009-01-24 13:45:24 +00:00
|
|
|
VECADD(data->vec,data->vec,dvec);
|
|
|
|
data->tot++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
static void brush_smooth_do(PEData *data, float mat[][4], float imat[][4], int point_index, int key_index, PTCacheEditKey *key)
|
2009-01-24 13:45:24 +00:00
|
|
|
{
|
|
|
|
float vec[3], dvec[3];
|
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
if(key_index) {
|
2009-01-24 13:45:24 +00:00
|
|
|
VECCOPY(vec,data->vec);
|
2009-11-10 20:43:45 +00:00
|
|
|
mul_mat3_m4_v3(imat,vec);
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-11-10 20:43:45 +00:00
|
|
|
sub_v3_v3v3(dvec,key->co,(key-1)->co);
|
2009-01-24 13:45:24 +00:00
|
|
|
|
|
|
|
VECSUB(dvec,vec,dvec);
|
2009-11-10 20:43:45 +00:00
|
|
|
mul_v3_fl(dvec,data->smoothfac);
|
2009-01-24 13:45:24 +00:00
|
|
|
|
|
|
|
VECADD(key->co,key->co,dvec);
|
|
|
|
}
|
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
(data->edit->points + point_index)->flag |= PEP_EDIT_RECALC;
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
|
2009-10-20 18:49:21 +00:00
|
|
|
static int brush_add(PEData *data, short number)
|
2009-01-24 13:45:24 +00:00
|
|
|
{
|
2009-02-20 20:39:27 +00:00
|
|
|
Scene *scene= data->scene;
|
|
|
|
Object *ob= data->ob;
|
2009-08-29 15:20:36 +00:00
|
|
|
PTCacheEdit *edit = data->edit;
|
|
|
|
ParticleSystem *psys= edit->psys;
|
2009-02-20 20:39:27 +00:00
|
|
|
ParticleData *add_pars= MEM_callocN(number*sizeof(ParticleData),"ParticleData add");
|
|
|
|
ParticleSystemModifierData *psmd= psys_get_modifier(ob,psys);
|
2009-09-17 22:00:49 +00:00
|
|
|
ParticleSimulationData sim = {scene, ob, psys, psmd};
|
2009-01-24 13:45:24 +00:00
|
|
|
ParticleEditSettings *pset= PE_settings(scene);
|
2009-02-20 20:39:27 +00:00
|
|
|
int i, k, n= 0, totpart= psys->totpart;
|
2009-10-13 15:30:19 +00:00
|
|
|
float mco[2];
|
2009-02-20 20:39:27 +00:00
|
|
|
short dmx= 0, dmy= 0;
|
2009-01-24 13:45:24 +00:00
|
|
|
float co1[3], co2[3], min_d, imat[4][4];
|
2009-09-17 22:00:49 +00:00
|
|
|
float framestep, timestep= psys_get_timestep(&sim);
|
2009-02-20 20:39:27 +00:00
|
|
|
short size= pset->brush[PE_BRUSH_ADD].size;
|
|
|
|
short size2= size*size;
|
2009-01-24 13:45:24 +00:00
|
|
|
DerivedMesh *dm=0;
|
2009-11-10 20:43:45 +00:00
|
|
|
invert_m4_m4(imat,ob->obmat);
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-09-05 20:12:08 +00:00
|
|
|
if(psys->flag & PSYS_GLOBAL_HAIR)
|
2009-10-20 18:49:21 +00:00
|
|
|
return 0;
|
2009-09-05 20:12:08 +00:00
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
BLI_srandom(psys->seed+data->mval[0]+data->mval[1]);
|
2009-01-24 13:45:24 +00:00
|
|
|
|
|
|
|
/* painting onto the deformed mesh, could be an option? */
|
2009-02-20 20:39:27 +00:00
|
|
|
if(psmd->dm->deformedOnly)
|
|
|
|
dm= psmd->dm;
|
2009-01-24 13:45:24 +00:00
|
|
|
else
|
2009-02-20 20:39:27 +00:00
|
|
|
dm= mesh_get_derived_deform(scene, ob, CD_MASK_BAREMESH);
|
|
|
|
|
|
|
|
for(i=0; i<number; i++) {
|
|
|
|
if(number>1) {
|
2009-01-24 13:45:24 +00:00
|
|
|
dmx=dmy=size;
|
2009-02-20 20:39:27 +00:00
|
|
|
while(dmx*dmx+dmy*dmy>size2) {
|
2009-01-24 13:45:24 +00:00
|
|
|
dmx=(short)((2.0f*BLI_frand()-1.0f)*size);
|
|
|
|
dmy=(short)((2.0f*BLI_frand()-1.0f)*size);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
mco[0]= data->mval[0] + dmx;
|
|
|
|
mco[1]= data->mval[1] + dmy;
|
|
|
|
viewline(data->vc.ar, data->vc.v3d, mco, co1, co2);
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-11-10 20:43:45 +00:00
|
|
|
mul_m4_v3(imat,co1);
|
|
|
|
mul_m4_v3(imat,co2);
|
2009-01-24 13:45:24 +00:00
|
|
|
min_d=2.0;
|
|
|
|
|
|
|
|
/* warning, returns the derived mesh face */
|
|
|
|
if(psys_intersect_dm(scene, ob,dm,0,co1,co2,&min_d,&add_pars[n].num,add_pars[n].fuv,0,0,0,0)) {
|
|
|
|
add_pars[n].num_dmcache= psys_particle_dm_face_lookup(ob,psmd->dm,add_pars[n].num,add_pars[n].fuv,NULL);
|
|
|
|
n++;
|
|
|
|
}
|
|
|
|
}
|
2009-02-20 20:39:27 +00:00
|
|
|
if(n) {
|
2009-01-24 13:45:24 +00:00
|
|
|
int newtotpart=totpart+n;
|
|
|
|
float hairmat[4][4], cur_co[3];
|
|
|
|
KDTree *tree=0;
|
2009-02-20 20:39:27 +00:00
|
|
|
ParticleData *pa, *new_pars= MEM_callocN(newtotpart*sizeof(ParticleData),"ParticleData new");
|
2009-08-29 15:20:36 +00:00
|
|
|
PTCacheEditPoint *point, *new_points= MEM_callocN(newtotpart*sizeof(PTCacheEditPoint),"PTCacheEditPoint array new");
|
|
|
|
PTCacheEditKey *key;
|
2009-01-24 13:45:24 +00:00
|
|
|
HairKey *hkey;
|
|
|
|
|
|
|
|
/* save existing elements */
|
|
|
|
memcpy(new_pars, psys->particles, totpart * sizeof(ParticleData));
|
2009-08-29 15:20:36 +00:00
|
|
|
memcpy(new_points, edit->points, totpart * sizeof(PTCacheEditPoint));
|
2009-01-24 13:45:24 +00:00
|
|
|
|
|
|
|
/* change old arrays to new ones */
|
|
|
|
if(psys->particles) MEM_freeN(psys->particles);
|
2009-02-20 20:39:27 +00:00
|
|
|
psys->particles= new_pars;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
if(edit->points) MEM_freeN(edit->points);
|
|
|
|
edit->points= new_points;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
|
|
|
if(edit->mirror_cache) {
|
|
|
|
MEM_freeN(edit->mirror_cache);
|
2009-02-20 20:39:27 +00:00
|
|
|
edit->mirror_cache= NULL;
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* create tree for interpolation */
|
2009-02-20 20:39:27 +00:00
|
|
|
if(pset->flag & PE_INTERPOLATE_ADDED && psys->totpart) {
|
2009-01-24 13:45:24 +00:00
|
|
|
tree=BLI_kdtree_new(psys->totpart);
|
|
|
|
|
|
|
|
for(i=0, pa=psys->particles; i<totpart; i++, pa++) {
|
|
|
|
psys_particle_on_dm(psmd->dm,psys->part->from,pa->num,pa->num_dmcache,pa->fuv,pa->foffset,cur_co,0,0,0,0,0);
|
|
|
|
BLI_kdtree_insert(tree, i, cur_co, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
BLI_kdtree_balance(tree);
|
|
|
|
}
|
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
edit->totpoint= psys->totpart= newtotpart;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
|
|
|
/* create new elements */
|
2009-02-20 20:39:27 +00:00
|
|
|
pa= psys->particles + totpart;
|
2009-08-29 15:20:36 +00:00
|
|
|
point= edit->points + totpart;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
for(i=totpart; i<newtotpart; i++, pa++, point++) {
|
2009-01-24 13:45:24 +00:00
|
|
|
memcpy(pa, add_pars + i - totpart, sizeof(ParticleData));
|
2009-02-20 20:39:27 +00:00
|
|
|
pa->hair= MEM_callocN(pset->totaddkey * sizeof(HairKey), "BakeKey key add");
|
2009-08-29 15:20:36 +00:00
|
|
|
key= point->keys= MEM_callocN(pset->totaddkey * sizeof(PTCacheEditKey), "PTCacheEditKey add");
|
|
|
|
point->totkey= pa->totkey= pset->totaddkey;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
for(k=0, hkey=pa->hair; k<pa->totkey; k++, hkey++, key++) {
|
|
|
|
key->co= hkey->co;
|
|
|
|
key->time= &hkey->time;
|
2009-10-13 17:15:12 +00:00
|
|
|
|
|
|
|
if(!(psys->flag & PSYS_GLOBAL_HAIR))
|
|
|
|
key->flag |= PEK_USE_WCO;
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pa->size= 1.0f;
|
2009-09-17 22:00:49 +00:00
|
|
|
initialize_particle(&sim, pa,i);
|
|
|
|
reset_particle(&sim, pa, 0.0, 1.0);
|
2009-08-29 15:20:36 +00:00
|
|
|
point->flag |= PEP_EDIT_RECALC;
|
2010-01-05 15:23:09 +00:00
|
|
|
if(pe_x_mirror(ob))
|
2009-08-29 15:20:36 +00:00
|
|
|
point->flag |= PEP_TAG; /* signal for duplicate */
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
framestep= pa->lifetime/(float)(pset->totaddkey-1);
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
if(tree) {
|
2009-01-24 13:45:24 +00:00
|
|
|
HairKey *hkey;
|
|
|
|
ParticleKey key[3];
|
|
|
|
KDTreeNearest ptn[3];
|
|
|
|
int w, maxw;
|
|
|
|
float maxd, mind, dd, totw=0.0, weight[3];
|
|
|
|
|
|
|
|
psys_particle_on_dm(psmd->dm,psys->part->from,pa->num,pa->num_dmcache,pa->fuv,pa->foffset,co1,0,0,0,0,0);
|
2009-02-20 20:39:27 +00:00
|
|
|
maxw= BLI_kdtree_find_n_nearest(tree,3,co1,NULL,ptn);
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
maxd= ptn[maxw-1].dist;
|
|
|
|
mind= ptn[0].dist;
|
|
|
|
dd= maxd - mind;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
for(w=0; w<maxw; w++) {
|
|
|
|
weight[w]= (float)pow(2.0, (double)(-6.0f * ptn[w].dist / maxd));
|
2009-01-24 13:45:24 +00:00
|
|
|
totw += weight[w];
|
|
|
|
}
|
2009-02-20 20:39:27 +00:00
|
|
|
for(;w<3; w++) {
|
|
|
|
weight[w]= 0.0f;
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for(w=0; w<maxw; w++)
|
|
|
|
weight[w] /= totw;
|
|
|
|
|
|
|
|
for(k=0; k<pset->totaddkey; k++) {
|
2009-09-04 23:06:15 +00:00
|
|
|
hkey= (HairKey*)pa->hair + k;
|
2009-02-20 20:39:27 +00:00
|
|
|
hkey->time= pa->time + k * framestep;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
key[0].time= hkey->time/ 100.0f;
|
2009-09-17 22:00:49 +00:00
|
|
|
psys_get_particle_on_path(&sim, ptn[0].index, key, 0);
|
2009-11-10 20:43:45 +00:00
|
|
|
mul_v3_fl(key[0].co, weight[0]);
|
2009-01-24 13:45:24 +00:00
|
|
|
|
|
|
|
if(maxw>1) {
|
2009-02-20 20:39:27 +00:00
|
|
|
key[1].time= key[0].time;
|
2009-09-17 22:00:49 +00:00
|
|
|
psys_get_particle_on_path(&sim, ptn[1].index, key + 1, 0);
|
2009-11-10 20:43:45 +00:00
|
|
|
mul_v3_fl(key[1].co, weight[1]);
|
2009-01-24 13:45:24 +00:00
|
|
|
VECADD(key[0].co, key[0].co, key[1].co);
|
|
|
|
|
|
|
|
if(maxw>2) {
|
2009-02-20 20:39:27 +00:00
|
|
|
key[2].time= key[0].time;
|
2009-09-17 22:00:49 +00:00
|
|
|
psys_get_particle_on_path(&sim, ptn[2].index, key + 2, 0);
|
2009-11-10 20:43:45 +00:00
|
|
|
mul_v3_fl(key[2].co, weight[2]);
|
2009-01-24 13:45:24 +00:00
|
|
|
VECADD(key[0].co, key[0].co, key[2].co);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(k==0)
|
|
|
|
VECSUB(co1, pa->state.co, key[0].co);
|
|
|
|
|
2009-09-04 23:06:15 +00:00
|
|
|
VECADD(hkey->co, key[0].co, co1);
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-09-04 23:06:15 +00:00
|
|
|
hkey->time= key[0].time;
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
}
|
2009-02-20 20:39:27 +00:00
|
|
|
else {
|
2009-01-24 13:45:24 +00:00
|
|
|
for(k=0, hkey=pa->hair; k<pset->totaddkey; k++, hkey++) {
|
|
|
|
VECADDFAC(hkey->co, pa->state.co, pa->state.vel, k * framestep * timestep);
|
2009-09-04 23:06:15 +00:00
|
|
|
hkey->time += k * framestep;
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
for(k=0, hkey=pa->hair; k<pset->totaddkey; k++, hkey++) {
|
|
|
|
psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, pa, hairmat);
|
2009-11-10 20:43:45 +00:00
|
|
|
invert_m4_m4(imat,hairmat);
|
|
|
|
mul_m4_v3(imat, hkey->co);
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(tree)
|
|
|
|
BLI_kdtree_free(tree);
|
|
|
|
}
|
|
|
|
if(add_pars)
|
|
|
|
MEM_freeN(add_pars);
|
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
if(!psmd->dm->deformedOnly)
|
2009-01-24 13:45:24 +00:00
|
|
|
dm->release(dm);
|
2009-10-20 18:49:21 +00:00
|
|
|
|
|
|
|
return n;
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
2009-02-20 20:39:27 +00:00
|
|
|
|
|
|
|
/************************* brush edit operator ********************/
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
typedef struct BrushEdit {
|
|
|
|
Scene *scene;
|
|
|
|
Object *ob;
|
2009-08-29 15:20:36 +00:00
|
|
|
PTCacheEdit *edit;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
int first;
|
|
|
|
int lastmouse[2];
|
|
|
|
} BrushEdit;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
static int brush_edit_init(bContext *C, wmOperator *op)
|
|
|
|
{
|
|
|
|
Scene *scene= CTX_data_scene(C);
|
|
|
|
Object *ob= CTX_data_active_object(C);
|
|
|
|
ParticleEditSettings *pset= PE_settings(scene);
|
2009-08-29 15:20:36 +00:00
|
|
|
PTCacheEdit *edit= PE_get_current(scene, ob);
|
2009-02-20 20:39:27 +00:00
|
|
|
ARegion *ar= CTX_wm_region(C);
|
|
|
|
BrushEdit *bedit;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
if(pset->brushtype < 0)
|
|
|
|
return 0;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
|
|
|
initgrabz(ar->regiondata, ob->obmat[3][0], ob->obmat[3][1], ob->obmat[3][2]);
|
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
bedit= MEM_callocN(sizeof(BrushEdit), "BrushEdit");
|
|
|
|
bedit->first= 1;
|
|
|
|
op->customdata= bedit;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
bedit->scene= scene;
|
|
|
|
bedit->ob= ob;
|
2009-08-29 15:20:36 +00:00
|
|
|
bedit->edit= edit;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
return 1;
|
|
|
|
}
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
static void brush_edit_apply(bContext *C, wmOperator *op, PointerRNA *itemptr)
|
|
|
|
{
|
|
|
|
BrushEdit *bedit= op->customdata;
|
|
|
|
Scene *scene= bedit->scene;
|
|
|
|
Object *ob= bedit->ob;
|
2009-08-29 15:20:36 +00:00
|
|
|
PTCacheEdit *edit= bedit->edit;
|
2009-02-20 20:39:27 +00:00
|
|
|
ParticleEditSettings *pset= PE_settings(scene);
|
2009-08-29 15:20:36 +00:00
|
|
|
ParticleSystemModifierData *psmd= edit->psys ? psys_get_modifier(ob, edit->psys) : NULL;
|
2009-02-20 20:39:27 +00:00
|
|
|
ParticleBrushData *brush= &pset->brush[pset->brushtype];
|
|
|
|
ARegion *ar= CTX_wm_region(C);
|
2009-08-29 15:20:36 +00:00
|
|
|
float vec[3], mousef[2];
|
2009-02-20 20:39:27 +00:00
|
|
|
short mval[2], mvalo[2];
|
2009-10-20 18:49:21 +00:00
|
|
|
int flip, mouse[2], dx, dy, removed= 0, added=0, selected= 0;
|
2009-09-05 20:12:08 +00:00
|
|
|
int lock_root = pset->flag & PE_LOCK_FIRST;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
if(!PE_start_edit(edit))
|
|
|
|
return;
|
|
|
|
|
2009-08-18 21:14:36 +00:00
|
|
|
RNA_float_get_array(itemptr, "mouse", mousef);
|
|
|
|
mouse[0] = mousef[0];
|
|
|
|
mouse[1] = mousef[1];
|
2010-07-29 12:16:15 +00:00
|
|
|
flip= RNA_boolean_get(itemptr, "pen_flip");
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-25 19:29:58 +00:00
|
|
|
if(bedit->first) {
|
|
|
|
bedit->lastmouse[0]= mouse[0];
|
|
|
|
bedit->lastmouse[1]= mouse[1];
|
|
|
|
}
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
dx= mouse[0] - bedit->lastmouse[0];
|
|
|
|
dy= mouse[1] - bedit->lastmouse[1];
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
mval[0]= mouse[0];
|
|
|
|
mval[1]= mouse[1];
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
mvalo[0]= bedit->lastmouse[0];
|
|
|
|
mvalo[1]= bedit->lastmouse[1];
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-09-05 20:12:08 +00:00
|
|
|
/* disable locking temporatily for disconnected hair */
|
|
|
|
if(edit->psys && edit->psys->flag & PSYS_GLOBAL_HAIR)
|
|
|
|
pset->flag &= ~PE_LOCK_FIRST;
|
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
if(((pset->brushtype == PE_BRUSH_ADD) ?
|
|
|
|
(sqrt(dx * dx + dy * dy) > pset->brush[PE_BRUSH_ADD].step) : (dx != 0 || dy != 0))
|
|
|
|
|| bedit->first) {
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-25 19:29:58 +00:00
|
|
|
view3d_operator_needs_opengl(C);
|
2009-08-29 15:20:36 +00:00
|
|
|
selected= (short)count_selected_keys(scene, edit);
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
switch(pset->brushtype) {
|
|
|
|
case PE_BRUSH_COMB:
|
|
|
|
{
|
|
|
|
PEData data;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
PE_set_view3d_data(C, &data);
|
|
|
|
data.mval= mval;
|
|
|
|
data.rad= (float)brush->size;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2010-03-22 17:12:08 +00:00
|
|
|
data.combfac= (brush->strength - 0.5f) * 2.0f;
|
2009-02-20 20:39:27 +00:00
|
|
|
if(data.combfac < 0.0f)
|
|
|
|
data.combfac= 1.0f - 9.0f * data.combfac;
|
|
|
|
else
|
|
|
|
data.combfac= 1.0f - data.combfac;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-11-10 20:43:45 +00:00
|
|
|
invert_m4_m4(ob->imat, ob->obmat);
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
window_to_3d_delta(ar, vec, dx, dy);
|
|
|
|
data.dvec= vec;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
foreach_mouse_hit_key(&data, brush_comb, selected);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case PE_BRUSH_CUT:
|
|
|
|
{
|
|
|
|
PEData data;
|
2009-08-29 15:20:36 +00:00
|
|
|
|
|
|
|
if(edit->psys && edit->pathcache) {
|
|
|
|
PE_set_view3d_data(C, &data);
|
|
|
|
data.mval= mval;
|
|
|
|
data.rad= (float)brush->size;
|
2010-03-22 17:12:08 +00:00
|
|
|
data.cutfac= brush->strength;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
if(selected)
|
|
|
|
foreach_selected_point(&data, brush_cut);
|
|
|
|
else
|
|
|
|
foreach_point(&data, brush_cut);
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2010-01-05 15:23:09 +00:00
|
|
|
removed= remove_tagged_particles(scene, ob, edit->psys, pe_x_mirror(ob));
|
2009-08-29 15:20:36 +00:00
|
|
|
if(pset->flag & PE_KEEP_LENGTHS)
|
|
|
|
recalc_lengths(edit);
|
|
|
|
}
|
2009-10-20 18:49:21 +00:00
|
|
|
else
|
|
|
|
removed= 0;
|
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case PE_BRUSH_LENGTH:
|
|
|
|
{
|
|
|
|
PEData data;
|
|
|
|
|
|
|
|
PE_set_view3d_data(C, &data);
|
|
|
|
data.mval= mval;
|
|
|
|
|
|
|
|
data.rad= (float)brush->size;
|
2010-03-22 17:12:08 +00:00
|
|
|
data.growfac= brush->strength / 50.0f;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
if(brush->invert ^ flip)
|
|
|
|
data.growfac= 1.0f - data.growfac;
|
|
|
|
else
|
|
|
|
data.growfac= 1.0f + data.growfac;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
foreach_mouse_hit_point(&data, brush_length, selected);
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
if(pset->flag & PE_KEEP_LENGTHS)
|
2009-08-29 15:20:36 +00:00
|
|
|
recalc_lengths(edit);
|
2009-02-20 20:39:27 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case PE_BRUSH_PUFF:
|
|
|
|
{
|
|
|
|
PEData data;
|
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
if(edit->psys) {
|
|
|
|
PE_set_view3d_data(C, &data);
|
|
|
|
data.dm= psmd->dm;
|
|
|
|
data.mval= mval;
|
|
|
|
data.rad= (float)brush->size;
|
2010-03-22 17:12:08 +00:00
|
|
|
data.select= selected;
|
2009-02-20 20:39:27 +00:00
|
|
|
|
2010-03-22 17:12:08 +00:00
|
|
|
data.pufffac= (brush->strength - 0.5f) * 2.0f;
|
2009-08-29 15:20:36 +00:00
|
|
|
if(data.pufffac < 0.0f)
|
|
|
|
data.pufffac= 1.0f - 9.0f * data.pufffac;
|
|
|
|
else
|
|
|
|
data.pufffac= 1.0f - data.pufffac;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
data.invert= (brush->invert ^ flip);
|
2009-11-10 20:43:45 +00:00
|
|
|
invert_m4_m4(ob->imat, ob->obmat);
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
foreach_mouse_hit_point(&data, brush_puff, selected);
|
|
|
|
}
|
2009-02-20 20:39:27 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case PE_BRUSH_ADD:
|
|
|
|
{
|
|
|
|
PEData data;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
if(edit->psys && edit->psys->part->from==PART_FROM_FACE) {
|
2009-02-20 20:39:27 +00:00
|
|
|
PE_set_view3d_data(C, &data);
|
|
|
|
data.mval= mval;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2010-03-22 17:12:08 +00:00
|
|
|
added= brush_add(&data, brush->count);
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
if(pset->flag & PE_KEEP_LENGTHS)
|
2009-08-29 15:20:36 +00:00
|
|
|
recalc_lengths(edit);
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
2009-10-20 18:49:21 +00:00
|
|
|
else
|
|
|
|
added= 0;
|
2009-02-20 20:39:27 +00:00
|
|
|
break;
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
2009-02-20 20:39:27 +00:00
|
|
|
case PE_BRUSH_SMOOTH:
|
|
|
|
{
|
|
|
|
PEData data;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
PE_set_view3d_data(C, &data);
|
|
|
|
data.mval= mval;
|
|
|
|
data.rad= (float)brush->size;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
data.vec[0]= data.vec[1]= data.vec[2]= 0.0f;
|
|
|
|
data.tot= 0;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2010-03-22 17:12:08 +00:00
|
|
|
data.smoothfac= brush->strength;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-11-10 20:43:45 +00:00
|
|
|
invert_m4_m4(ob->imat, ob->obmat);
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
foreach_mouse_hit_key(&data, brush_smooth_get, selected);
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
if(data.tot) {
|
2009-11-10 20:43:45 +00:00
|
|
|
mul_v3_fl(data.vec, 1.0f / (float)data.tot);
|
2009-02-20 20:39:27 +00:00
|
|
|
foreach_mouse_hit_key(&data, brush_smooth_do, selected);
|
|
|
|
}
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2010-01-14 08:53:10 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case PE_BRUSH_WEIGHT:
|
|
|
|
{
|
|
|
|
PEData data;
|
|
|
|
PE_set_view3d_data(C, &data);
|
|
|
|
|
|
|
|
if(edit->psys) {
|
|
|
|
data.dm= psmd->dm;
|
|
|
|
data.mval= mval;
|
|
|
|
data.rad= (float)brush->size;
|
|
|
|
|
2010-03-22 17:12:08 +00:00
|
|
|
data.weightfac = brush->strength; /* note that this will never be zero */
|
2010-01-14 08:53:10 +00:00
|
|
|
|
|
|
|
foreach_mouse_hit_key(&data, brush_weight, selected);
|
|
|
|
}
|
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if((pset->flag & PE_KEEP_LENGTHS)==0)
|
2009-08-29 15:20:36 +00:00
|
|
|
recalc_lengths(edit);
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-10-28 11:35:19 +00:00
|
|
|
if(ELEM(pset->brushtype, PE_BRUSH_ADD, PE_BRUSH_CUT) && (added || removed)) {
|
2010-01-05 15:23:09 +00:00
|
|
|
if(pset->brushtype == PE_BRUSH_ADD && pe_x_mirror(ob))
|
2009-10-28 11:35:19 +00:00
|
|
|
PE_mirror_x(scene, ob, 1);
|
|
|
|
|
|
|
|
update_world_cos(ob,edit);
|
|
|
|
psys_free_path_cache(NULL, edit);
|
|
|
|
DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
2009-02-20 20:39:27 +00:00
|
|
|
else
|
|
|
|
PE_update_object(scene, ob, 1);
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2010-06-18 04:39:32 +00:00
|
|
|
WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_EDITED, ob);
|
2009-02-20 20:39:27 +00:00
|
|
|
|
|
|
|
bedit->lastmouse[0]= mouse[0];
|
|
|
|
bedit->lastmouse[1]= mouse[1];
|
|
|
|
bedit->first= 0;
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
2009-09-05 20:12:08 +00:00
|
|
|
|
|
|
|
pset->flag |= lock_root;
|
2009-02-20 20:39:27 +00:00
|
|
|
}
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
static void brush_edit_exit(bContext *C, wmOperator *op)
|
|
|
|
{
|
|
|
|
BrushEdit *bedit= op->customdata;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
MEM_freeN(bedit);
|
|
|
|
}
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
static int brush_edit_exec(bContext *C, wmOperator *op)
|
|
|
|
{
|
|
|
|
if(!brush_edit_init(C, op))
|
|
|
|
return OPERATOR_CANCELLED;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
RNA_BEGIN(op->ptr, itemptr, "stroke") {
|
|
|
|
brush_edit_apply(C, op, &itemptr);
|
|
|
|
}
|
|
|
|
RNA_END;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
brush_edit_exit(C, op);
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
static void brush_edit_apply_event(bContext *C, wmOperator *op, wmEvent *event)
|
|
|
|
{
|
|
|
|
ARegion *ar= CTX_wm_region(C);
|
|
|
|
PointerRNA itemptr;
|
2009-08-18 21:14:36 +00:00
|
|
|
float mouse[2];
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
mouse[0]= event->x - ar->winrct.xmin;
|
|
|
|
mouse[1]= event->y - ar->winrct.ymin;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
/* fill in stroke */
|
|
|
|
RNA_collection_add(op->ptr, "stroke", &itemptr);
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-08-18 21:14:36 +00:00
|
|
|
RNA_float_set_array(&itemptr, "mouse", mouse);
|
2010-09-14 01:11:54 +00:00
|
|
|
RNA_boolean_set(&itemptr, "pen_flip", event->shift != 0); // XXX hardcoded
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
/* apply */
|
|
|
|
brush_edit_apply(C, op, &itemptr);
|
|
|
|
}
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
static int brush_edit_invoke(bContext *C, wmOperator *op, wmEvent *event)
|
|
|
|
{
|
|
|
|
if(!brush_edit_init(C, op))
|
|
|
|
return OPERATOR_CANCELLED;
|
|
|
|
|
|
|
|
brush_edit_apply_event(C, op, event);
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-09-18 12:43:36 +00:00
|
|
|
WM_event_add_modal_handler(C, op);
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
return OPERATOR_RUNNING_MODAL;
|
|
|
|
}
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
static int brush_edit_modal(bContext *C, wmOperator *op, wmEvent *event)
|
|
|
|
{
|
|
|
|
switch(event->type) {
|
|
|
|
case LEFTMOUSE:
|
|
|
|
case MIDDLEMOUSE:
|
|
|
|
case RIGHTMOUSE: // XXX hardcoded
|
|
|
|
brush_edit_exit(C, op);
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
case MOUSEMOVE:
|
|
|
|
brush_edit_apply_event(C, op, event);
|
|
|
|
break;
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
return OPERATOR_RUNNING_MODAL;
|
|
|
|
}
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
static int brush_edit_cancel(bContext *C, wmOperator *op)
|
|
|
|
{
|
|
|
|
brush_edit_exit(C, op);
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
return OPERATOR_CANCELLED;
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
void PARTICLE_OT_brush_edit(wmOperatorType *ot)
|
2009-01-24 13:45:24 +00:00
|
|
|
{
|
2009-02-20 20:39:27 +00:00
|
|
|
/* identifiers */
|
|
|
|
ot->name= "Brush Edit";
|
|
|
|
ot->idname= "PARTICLE_OT_brush_edit";
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
/* api callbacks */
|
|
|
|
ot->exec= brush_edit_exec;
|
|
|
|
ot->invoke= brush_edit_invoke;
|
|
|
|
ot->modal= brush_edit_modal;
|
|
|
|
ot->cancel= brush_edit_cancel;
|
2010-04-28 07:25:39 +00:00
|
|
|
ot->poll= PE_poll_view3d;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
/* flags */
|
2009-07-11 14:51:13 +00:00
|
|
|
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO|OPTYPE_BLOCKING;
|
2009-02-20 20:39:27 +00:00
|
|
|
|
|
|
|
/* properties */
|
|
|
|
RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", "");
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
/*********************** undo ***************************/
|
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
static void free_PTCacheUndo(PTCacheUndo *undo)
|
2009-01-24 13:45:24 +00:00
|
|
|
{
|
2009-08-29 15:20:36 +00:00
|
|
|
PTCacheEditPoint *point;
|
2009-01-24 13:45:24 +00:00
|
|
|
int i;
|
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
for(i=0, point=undo->points; i<undo->totpoint; i++, point++) {
|
|
|
|
if(undo->particles && (undo->particles + i)->hair)
|
|
|
|
MEM_freeN((undo->particles + i)->hair);
|
|
|
|
if(point->keys)
|
|
|
|
MEM_freeN(point->keys);
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
2009-08-29 15:20:36 +00:00
|
|
|
if(undo->points)
|
|
|
|
MEM_freeN(undo->points);
|
2009-01-24 13:45:24 +00:00
|
|
|
|
|
|
|
if(undo->particles)
|
|
|
|
MEM_freeN(undo->particles);
|
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
BKE_ptcache_free_mem(&undo->mem_cache);
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
2009-02-20 20:39:27 +00:00
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
static void make_PTCacheUndo(PTCacheEdit *edit, PTCacheUndo *undo)
|
2009-01-24 13:45:24 +00:00
|
|
|
{
|
2009-08-29 15:20:36 +00:00
|
|
|
PTCacheEditPoint *point;
|
2009-01-24 13:45:24 +00:00
|
|
|
int i;
|
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
undo->totpoint= edit->totpoint;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
if(edit->psys) {
|
|
|
|
ParticleData *pa;
|
|
|
|
|
|
|
|
pa= undo->particles= MEM_dupallocN(edit->psys->particles);
|
|
|
|
|
|
|
|
for(i=0; i<edit->totpoint; i++, pa++)
|
|
|
|
pa->hair= MEM_dupallocN(pa->hair);
|
2009-09-05 20:12:08 +00:00
|
|
|
|
|
|
|
undo->psys_flag = edit->psys->flag;
|
2009-08-29 15:20:36 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
PTCacheMem *pm;
|
|
|
|
|
|
|
|
BLI_duplicatelist(&undo->mem_cache, &edit->pid.cache->mem_cache);
|
|
|
|
pm = undo->mem_cache.first;
|
|
|
|
|
|
|
|
for(; pm; pm=pm->next) {
|
|
|
|
for(i=0; i<BPHYS_TOT_DATA; i++)
|
|
|
|
pm->data[i] = MEM_dupallocN(pm->data[i]);
|
2010-04-13 19:44:16 +00:00
|
|
|
|
|
|
|
pm->index_array = MEM_dupallocN(pm->index_array);
|
2009-08-29 15:20:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
point= undo->points = MEM_dupallocN(edit->points);
|
|
|
|
undo->totpoint = edit->totpoint;
|
|
|
|
|
|
|
|
for(i=0; i<edit->totpoint; i++, point++) {
|
|
|
|
point->keys= MEM_dupallocN(point->keys);
|
2009-01-24 13:45:24 +00:00
|
|
|
/* no need to update edit key->co & key->time pointers here */
|
|
|
|
}
|
|
|
|
}
|
2009-02-20 20:39:27 +00:00
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
static void get_PTCacheUndo(PTCacheEdit *edit, PTCacheUndo *undo)
|
2009-01-24 13:45:24 +00:00
|
|
|
{
|
2009-08-29 15:20:36 +00:00
|
|
|
ParticleSystem *psys = edit->psys;
|
|
|
|
ParticleData *pa;
|
2009-01-24 13:45:24 +00:00
|
|
|
HairKey *hkey;
|
2009-08-29 15:20:36 +00:00
|
|
|
POINT_P; KEY_K;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
LOOP_POINTS {
|
|
|
|
if(psys && psys->particles[p].hair)
|
|
|
|
MEM_freeN(psys->particles[p].hair);
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
if(point->keys)
|
|
|
|
MEM_freeN(point->keys);
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
2009-08-29 15:20:36 +00:00
|
|
|
if(psys && psys->particles)
|
2009-01-24 13:45:24 +00:00
|
|
|
MEM_freeN(psys->particles);
|
2009-08-29 15:20:36 +00:00
|
|
|
if(edit->points)
|
|
|
|
MEM_freeN(edit->points);
|
|
|
|
if(edit->mirror_cache) {
|
|
|
|
MEM_freeN(edit->mirror_cache);
|
|
|
|
edit->mirror_cache= NULL;
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
edit->points= MEM_dupallocN(undo->points);
|
|
|
|
edit->totpoint = undo->totpoint;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
LOOP_POINTS {
|
|
|
|
point->keys= MEM_dupallocN(point->keys);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(psys) {
|
|
|
|
psys->particles= MEM_dupallocN(undo->particles);
|
|
|
|
|
|
|
|
psys->totpart= undo->totpoint;
|
|
|
|
|
|
|
|
LOOP_POINTS {
|
|
|
|
pa = psys->particles + p;
|
|
|
|
hkey= pa->hair = MEM_dupallocN(pa->hair);
|
|
|
|
|
|
|
|
LOOP_KEYS {
|
|
|
|
key->co= hkey->co;
|
|
|
|
key->time= &hkey->time;
|
|
|
|
hkey++;
|
|
|
|
}
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
2009-09-05 20:12:08 +00:00
|
|
|
|
|
|
|
psys->flag = undo->psys_flag;
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
2009-08-29 15:20:36 +00:00
|
|
|
else {
|
|
|
|
PTCacheMem *pm;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
BKE_ptcache_free_mem(&edit->pid.cache->mem_cache);
|
|
|
|
|
|
|
|
BLI_duplicatelist(&edit->pid.cache->mem_cache, &undo->mem_cache);
|
|
|
|
|
|
|
|
pm = edit->pid.cache->mem_cache.first;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
for(; pm; pm=pm->next) {
|
|
|
|
for(i=0; i<BPHYS_TOT_DATA; i++)
|
|
|
|
pm->data[i] = MEM_dupallocN(pm->data[i]);
|
|
|
|
|
2010-04-13 19:44:16 +00:00
|
|
|
pm->index_array = MEM_dupallocN(pm->index_array);
|
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
BKE_ptcache_mem_init_pointers(pm);
|
|
|
|
|
|
|
|
LOOP_POINTS {
|
|
|
|
LOOP_KEYS {
|
|
|
|
if((int)key->ftime == pm->frame) {
|
|
|
|
key->co = pm->cur[BPHYS_DATA_LOCATION];
|
|
|
|
key->vel = pm->cur[BPHYS_DATA_VELOCITY];
|
|
|
|
key->rot = pm->cur[BPHYS_DATA_ROTATION];
|
|
|
|
key->time = &key->ftime;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
BKE_ptcache_mem_incr_pointers(pm);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void PE_undo_push(Scene *scene, char *str)
|
|
|
|
{
|
2009-08-29 15:20:36 +00:00
|
|
|
PTCacheEdit *edit= PE_get_current(scene, OBACT);
|
|
|
|
PTCacheUndo *undo;
|
2009-01-24 13:45:24 +00:00
|
|
|
int nr;
|
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
if(!edit) return;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
|
|
|
/* remove all undos after (also when curundo==NULL) */
|
|
|
|
while(edit->undo.last != edit->curundo) {
|
|
|
|
undo= edit->undo.last;
|
|
|
|
BLI_remlink(&edit->undo, undo);
|
2009-08-29 15:20:36 +00:00
|
|
|
free_PTCacheUndo(undo);
|
2009-01-24 13:45:24 +00:00
|
|
|
MEM_freeN(undo);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* make new */
|
2009-08-29 15:20:36 +00:00
|
|
|
edit->curundo= undo= MEM_callocN(sizeof(PTCacheUndo), "particle undo file");
|
2009-01-24 13:45:24 +00:00
|
|
|
strncpy(undo->name, str, 64-1);
|
|
|
|
BLI_addtail(&edit->undo, undo);
|
|
|
|
|
|
|
|
/* and limit amount to the maximum */
|
|
|
|
nr= 0;
|
|
|
|
undo= edit->undo.last;
|
|
|
|
while(undo) {
|
|
|
|
nr++;
|
|
|
|
if(nr==U.undosteps) break;
|
|
|
|
undo= undo->prev;
|
|
|
|
}
|
|
|
|
if(undo) {
|
|
|
|
while(edit->undo.first!=undo) {
|
2009-08-29 15:20:36 +00:00
|
|
|
PTCacheUndo *first= edit->undo.first;
|
2009-01-24 13:45:24 +00:00
|
|
|
BLI_remlink(&edit->undo, first);
|
2009-08-29 15:20:36 +00:00
|
|
|
free_PTCacheUndo(first);
|
2009-01-24 13:45:24 +00:00
|
|
|
MEM_freeN(first);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* copy */
|
2009-08-29 15:20:36 +00:00
|
|
|
make_PTCacheUndo(edit,edit->curundo);
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
2009-02-20 20:39:27 +00:00
|
|
|
|
2009-01-24 13:45:24 +00:00
|
|
|
void PE_undo_step(Scene *scene, int step)
|
|
|
|
{
|
2009-08-29 15:20:36 +00:00
|
|
|
PTCacheEdit *edit= PE_get_current(scene, OBACT);
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
if(!edit) return;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
|
|
|
if(step==0) {
|
2009-08-29 15:20:36 +00:00
|
|
|
get_PTCacheUndo(edit,edit->curundo);
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
else if(step==1) {
|
|
|
|
|
2009-02-25 19:29:58 +00:00
|
|
|
if(edit->curundo==NULL || edit->curundo->prev==NULL);
|
2009-01-24 13:45:24 +00:00
|
|
|
else {
|
|
|
|
if(G.f & G_DEBUG) printf("undo %s\n", edit->curundo->name);
|
|
|
|
edit->curundo= edit->curundo->prev;
|
2009-08-29 15:20:36 +00:00
|
|
|
get_PTCacheUndo(edit, edit->curundo);
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* curundo has to remain current situation! */
|
|
|
|
|
2009-02-25 19:29:58 +00:00
|
|
|
if(edit->curundo==NULL || edit->curundo->next==NULL);
|
2009-01-24 13:45:24 +00:00
|
|
|
else {
|
2009-08-29 15:20:36 +00:00
|
|
|
get_PTCacheUndo(edit, edit->curundo->next);
|
2009-01-24 13:45:24 +00:00
|
|
|
edit->curundo= edit->curundo->next;
|
|
|
|
if(G.f & G_DEBUG) printf("redo %s\n", edit->curundo->name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2.5
Notifiers
---------
Various fixes for wrong use of notifiers, and some new notifiers
to make things a bit more clear and consistent, with two notable
changes:
* Geometry changes are now done with NC_GEOM, rather than
NC_OBJECT|ND_GEOM_, so an object does need to be available.
* Space data now use NC_SPACE|ND_SPACE_*, instead of data
notifiers or even NC_WINDOW in some cases. Note that NC_SPACE
should only be used for notifying about changes in space data,
we don't want to go back to allqueue(REDRAW..).
Depsgraph
---------
The dependency graph now has a different flush call:
DAG_object_flush_update(scene, ob, flag)
is replaced by:
DAG_id_flush_update(id, flag)
It still works basically the same, one difference is that it now
also accepts object data (e.g. Mesh), again to avoid requiring an
Object to be available. Other ID types will simply do nothing at
the moment.
Docs
----
I made some guidelines for how/when to do which kinds of updates
and notifiers. I can't specify totally exact how to make these
decisions, but these are basically the guidelines I use. So, new
and updated docs are here:
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/NotifiersUpdates
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/DataNotifiers
2009-09-04 20:51:09 +00:00
|
|
|
DAG_id_flush_update(&OBACT->id, OB_RECALC_DATA);
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
static void PTCacheUndo_number(Scene *scene, PTCacheEdit *edit, int nr)
|
2009-01-24 13:45:24 +00:00
|
|
|
{
|
2009-08-29 15:20:36 +00:00
|
|
|
PTCacheUndo *undo;
|
2009-01-24 13:45:24 +00:00
|
|
|
int a=1;
|
|
|
|
|
|
|
|
for(undo= edit->undo.first; undo; undo= undo->next, a++) {
|
|
|
|
if(a==nr) break;
|
|
|
|
}
|
|
|
|
edit->curundo= undo;
|
|
|
|
PE_undo_step(scene, 0);
|
|
|
|
}
|
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
static void PTCacheUndo_clear(PTCacheEdit *edit)
|
2009-01-24 13:45:24 +00:00
|
|
|
{
|
2009-08-29 15:20:36 +00:00
|
|
|
PTCacheUndo *undo;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
|
|
|
if(edit==0) return;
|
|
|
|
|
|
|
|
undo= edit->undo.first;
|
|
|
|
while(undo) {
|
2009-08-29 15:20:36 +00:00
|
|
|
free_PTCacheUndo(undo);
|
2009-01-24 13:45:24 +00:00
|
|
|
undo= undo->next;
|
|
|
|
}
|
|
|
|
BLI_freelistN(&edit->undo);
|
|
|
|
edit->curundo= NULL;
|
|
|
|
}
|
2009-02-20 20:39:27 +00:00
|
|
|
|
2009-01-24 13:45:24 +00:00
|
|
|
void PE_undo(Scene *scene)
|
|
|
|
{
|
|
|
|
PE_undo_step(scene, 1);
|
|
|
|
}
|
2009-02-20 20:39:27 +00:00
|
|
|
|
2009-01-24 13:45:24 +00:00
|
|
|
void PE_redo(Scene *scene)
|
|
|
|
{
|
|
|
|
PE_undo_step(scene, -1);
|
|
|
|
}
|
2009-02-20 20:39:27 +00:00
|
|
|
|
|
|
|
void PE_undo_menu(Scene *scene, Object *ob)
|
2009-01-24 13:45:24 +00:00
|
|
|
{
|
2009-08-29 15:20:36 +00:00
|
|
|
PTCacheEdit *edit= PE_get_current(scene, ob);
|
|
|
|
PTCacheUndo *undo;
|
2009-01-24 13:45:24 +00:00
|
|
|
DynStr *ds;
|
2009-07-16 04:45:52 +00:00
|
|
|
short event=0;
|
2009-01-24 13:45:24 +00:00
|
|
|
char *menu;
|
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
if(!edit) return;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
|
|
|
ds= BLI_dynstr_new();
|
|
|
|
|
|
|
|
BLI_dynstr_append(ds, "Particlemode Undo History %t");
|
|
|
|
|
|
|
|
for(undo= edit->undo.first; undo; undo= undo->next) {
|
|
|
|
BLI_dynstr_append(ds, "|");
|
|
|
|
BLI_dynstr_append(ds, undo->name);
|
|
|
|
}
|
|
|
|
|
|
|
|
menu= BLI_dynstr_get_cstring(ds);
|
|
|
|
BLI_dynstr_free(ds);
|
|
|
|
|
|
|
|
// XXX event= pupmenu_col(menu, 20);
|
|
|
|
MEM_freeN(menu);
|
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
if(event>0) PTCacheUndo_number(scene, edit, event);
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
/************************ utilities ******************************/
|
|
|
|
|
2009-01-24 13:45:24 +00:00
|
|
|
int PE_minmax(Scene *scene, float *min, float *max)
|
|
|
|
{
|
2009-02-20 20:39:27 +00:00
|
|
|
Object *ob= OBACT;
|
2009-08-29 15:20:36 +00:00
|
|
|
PTCacheEdit *edit= PE_get_current(scene, ob);
|
2009-12-26 20:23:13 +00:00
|
|
|
ParticleSystem *psys;
|
2009-08-29 15:20:36 +00:00
|
|
|
ParticleSystemModifierData *psmd = NULL;
|
|
|
|
POINT_P; KEY_K;
|
2009-01-24 13:45:24 +00:00
|
|
|
float co[3], mat[4][4];
|
2009-08-29 15:20:36 +00:00
|
|
|
int ok= 0;
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
if(!edit) return ok;
|
2009-12-26 20:23:13 +00:00
|
|
|
|
|
|
|
if((psys = edit->psys))
|
2009-08-29 15:20:36 +00:00
|
|
|
psmd= psys_get_modifier(ob, psys);
|
|
|
|
else
|
2009-11-10 20:43:45 +00:00
|
|
|
unit_m4(mat);
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
LOOP_VISIBLE_POINTS {
|
|
|
|
if(psys)
|
|
|
|
psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, psys->particles+p, mat);
|
2009-01-24 13:45:24 +00:00
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
LOOP_SELECTED_KEYS {
|
|
|
|
VECCOPY(co, key->co);
|
2009-11-10 20:43:45 +00:00
|
|
|
mul_m4_v3(mat, co);
|
2009-08-29 15:20:36 +00:00
|
|
|
DO_MINMAX(co, min, max);
|
|
|
|
ok= 1;
|
2009-01-24 13:45:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!ok) {
|
|
|
|
minmax_object(ob, min, max);
|
|
|
|
ok= 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
2009-02-25 19:29:58 +00:00
|
|
|
/************************ particle edit toggle operator ************************/
|
|
|
|
|
|
|
|
/* initialize needed data for bake edit */
|
2009-08-29 15:20:36 +00:00
|
|
|
static void PE_create_particle_edit(Scene *scene, Object *ob, PointCache *cache, ParticleSystem *psys)
|
2009-02-25 19:29:58 +00:00
|
|
|
{
|
2009-10-09 13:25:54 +00:00
|
|
|
PTCacheEdit *edit= (psys)? psys->edit : cache->edit;
|
|
|
|
ParticleSystemModifierData *psmd= (psys)? psys_get_modifier(ob, psys): NULL;
|
2009-08-29 15:20:36 +00:00
|
|
|
POINT_P; KEY_K;
|
|
|
|
ParticleData *pa = NULL;
|
2009-02-25 19:29:58 +00:00
|
|
|
HairKey *hkey;
|
2009-08-29 15:20:36 +00:00
|
|
|
int totpoint;
|
2009-02-25 19:29:58 +00:00
|
|
|
|
2009-10-09 13:25:54 +00:00
|
|
|
/* no psmd->dm happens in case particle system modifier is not enabled */
|
|
|
|
if(!(psys && psmd && psmd->dm) && !cache)
|
2009-02-25 19:29:58 +00:00
|
|
|
return;
|
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
if(cache && cache->flag & PTCACHE_DISK_CACHE)
|
|
|
|
return;
|
2009-02-25 19:29:58 +00:00
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
if(!edit) {
|
|
|
|
totpoint = psys ? psys->totpart : ((PTCacheMem*)cache->mem_cache.first)->totpoint;
|
2009-02-25 19:29:58 +00:00
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
edit= MEM_callocN(sizeof(PTCacheEdit), "PE_create_particle_edit");
|
|
|
|
edit->points=MEM_callocN(totpoint*sizeof(PTCacheEditPoint),"PTCacheEditPoints");
|
|
|
|
edit->totpoint = totpoint;
|
2009-02-25 19:29:58 +00:00
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
if(psys && !cache) {
|
|
|
|
psys->edit= edit;
|
|
|
|
edit->psys = psys;
|
2009-02-25 19:29:58 +00:00
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
psys->free_edit= PE_free_ptcache_edit;
|
2009-02-25 19:29:58 +00:00
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
edit->pathcache = NULL;
|
|
|
|
edit->pathcachebufs.first = edit->pathcachebufs.last = NULL;
|
|
|
|
|
|
|
|
pa = psys->particles;
|
|
|
|
LOOP_POINTS {
|
|
|
|
point->totkey = pa->totkey;
|
|
|
|
point->keys= MEM_callocN(point->totkey*sizeof(PTCacheEditKey),"ParticleEditKeys");
|
|
|
|
point->flag |= PEP_EDIT_RECALC;
|
|
|
|
|
|
|
|
hkey = pa->hair;
|
|
|
|
LOOP_KEYS {
|
|
|
|
key->co= hkey->co;
|
|
|
|
key->time= &hkey->time;
|
|
|
|
key->flag= hkey->editflag;
|
2009-09-05 20:12:08 +00:00
|
|
|
if(!(psys->flag & PSYS_GLOBAL_HAIR))
|
|
|
|
key->flag |= PEK_USE_WCO;
|
2009-08-29 15:20:36 +00:00
|
|
|
hkey++;
|
|
|
|
}
|
|
|
|
pa++;
|
2009-02-25 19:29:58 +00:00
|
|
|
}
|
|
|
|
}
|
2009-08-29 15:20:36 +00:00
|
|
|
else {
|
|
|
|
PTCacheMem *pm;
|
|
|
|
int totframe=0;
|
|
|
|
|
|
|
|
cache->edit= edit;
|
|
|
|
cache->free_edit= PE_free_ptcache_edit;
|
|
|
|
edit->psys = NULL;
|
|
|
|
|
|
|
|
for(pm=cache->mem_cache.first; pm; pm=pm->next)
|
|
|
|
totframe++;
|
|
|
|
|
|
|
|
for(pm=cache->mem_cache.first; pm; pm=pm->next) {
|
|
|
|
BKE_ptcache_mem_init_pointers(pm);
|
|
|
|
|
|
|
|
LOOP_POINTS {
|
|
|
|
if(psys) {
|
2010-04-13 19:44:16 +00:00
|
|
|
if(pm->index_array) {
|
|
|
|
if(pm->index_array[p])
|
|
|
|
BKE_ptcache_mem_seek_pointers(p, pm);
|
|
|
|
else
|
2009-08-29 15:20:36 +00:00
|
|
|
continue;
|
2010-04-13 19:44:16 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
pa = psys->particles + p;
|
|
|
|
if((pm->next && pm->next->frame < pa->time)
|
|
|
|
|| (pm->prev && pm->prev->frame >= pa->dietime)) {
|
|
|
|
BKE_ptcache_mem_incr_pointers(pm);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
2009-08-29 15:20:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if(!point->totkey) {
|
|
|
|
key = point->keys = MEM_callocN(totframe*sizeof(PTCacheEditKey),"ParticleEditKeys");
|
|
|
|
point->flag |= PEP_EDIT_RECALC;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
key = point->keys + point->totkey;
|
2009-02-25 19:29:58 +00:00
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
key->co = pm->cur[BPHYS_DATA_LOCATION];
|
|
|
|
key->vel = pm->cur[BPHYS_DATA_VELOCITY];
|
|
|
|
key->rot = pm->cur[BPHYS_DATA_ROTATION];
|
|
|
|
key->ftime = (float)pm->frame;
|
|
|
|
key->time = &key->ftime;
|
|
|
|
BKE_ptcache_mem_incr_pointers(pm);
|
|
|
|
|
|
|
|
point->totkey++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
psys = NULL;
|
|
|
|
}
|
2009-02-25 19:29:58 +00:00
|
|
|
|
|
|
|
UI_GetThemeColor3ubv(TH_EDGE_SELECT, edit->sel_col);
|
|
|
|
UI_GetThemeColor3ubv(TH_WIRE, edit->nosel_col);
|
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
recalc_lengths(edit);
|
|
|
|
if(psys && !cache)
|
|
|
|
recalc_emitter_field(ob, psys);
|
|
|
|
PE_update_object(scene, ob, 1);
|
2009-02-25 19:29:58 +00:00
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
PTCacheUndo_clear(edit);
|
2009-02-25 19:29:58 +00:00
|
|
|
PE_undo_push(scene, "Original");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int particle_edit_toggle_poll(bContext *C)
|
|
|
|
{
|
|
|
|
Scene *scene= CTX_data_scene(C);
|
|
|
|
Object *ob= CTX_data_active_object(C);
|
|
|
|
|
|
|
|
if(!scene || !ob || ob->id.lib)
|
|
|
|
return 0;
|
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
return (ob->particlesystem.first || modifiers_findByType(ob, eModifierType_Cloth) || modifiers_findByType(ob, eModifierType_Softbody));
|
2009-02-25 19:29:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int particle_edit_toggle_exec(bContext *C, wmOperator *op)
|
|
|
|
{
|
2009-10-09 13:25:54 +00:00
|
|
|
Scene *scene= CTX_data_scene(C);
|
2009-02-25 19:29:58 +00:00
|
|
|
Object *ob= CTX_data_active_object(C);
|
|
|
|
|
2009-08-16 02:35:44 +00:00
|
|
|
if(!(ob->mode & OB_MODE_PARTICLE_EDIT)) {
|
2010-01-12 13:40:29 +00:00
|
|
|
PTCacheEdit *edit;
|
2009-08-16 02:35:44 +00:00
|
|
|
ob->mode |= OB_MODE_PARTICLE_EDIT;
|
2010-01-12 13:40:29 +00:00
|
|
|
edit= PE_create_current(scene, ob);
|
|
|
|
|
|
|
|
/* mesh may have changed since last entering editmode.
|
|
|
|
* note, this may have run before if the edit data was just created, so could avoid this and speed up a little */
|
2010-01-22 21:40:31 +00:00
|
|
|
if(edit && edit->psys)
|
2010-01-12 14:52:09 +00:00
|
|
|
recalc_emitter_field(ob, edit->psys);
|
2010-01-12 13:40:29 +00:00
|
|
|
|
2009-02-25 19:29:58 +00:00
|
|
|
toggle_particle_cursor(C, 1);
|
|
|
|
WM_event_add_notifier(C, NC_SCENE|ND_MODE|NS_MODE_PARTICLE, NULL);
|
|
|
|
}
|
|
|
|
else {
|
2009-08-16 02:35:44 +00:00
|
|
|
ob->mode &= ~OB_MODE_PARTICLE_EDIT;
|
2009-02-25 19:29:58 +00:00
|
|
|
toggle_particle_cursor(C, 0);
|
|
|
|
WM_event_add_notifier(C, NC_SCENE|ND_MODE|NS_MODE_OBJECT, NULL);
|
|
|
|
}
|
|
|
|
|
2.5
Notifiers
---------
Various fixes for wrong use of notifiers, and some new notifiers
to make things a bit more clear and consistent, with two notable
changes:
* Geometry changes are now done with NC_GEOM, rather than
NC_OBJECT|ND_GEOM_, so an object does need to be available.
* Space data now use NC_SPACE|ND_SPACE_*, instead of data
notifiers or even NC_WINDOW in some cases. Note that NC_SPACE
should only be used for notifying about changes in space data,
we don't want to go back to allqueue(REDRAW..).
Depsgraph
---------
The dependency graph now has a different flush call:
DAG_object_flush_update(scene, ob, flag)
is replaced by:
DAG_id_flush_update(id, flag)
It still works basically the same, one difference is that it now
also accepts object data (e.g. Mesh), again to avoid requiring an
Object to be available. Other ID types will simply do nothing at
the moment.
Docs
----
I made some guidelines for how/when to do which kinds of updates
and notifiers. I can't specify totally exact how to make these
decisions, but these are basically the guidelines I use. So, new
and updated docs are here:
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/NotifiersUpdates
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/DataNotifiers
2009-09-04 20:51:09 +00:00
|
|
|
DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
|
2009-02-25 19:29:58 +00:00
|
|
|
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PARTICLE_OT_particle_edit_toggle(wmOperatorType *ot)
|
|
|
|
{
|
|
|
|
/* identifiers */
|
|
|
|
ot->name= "Particle Edit Toggle";
|
|
|
|
ot->idname= "PARTICLE_OT_particle_edit_toggle";
|
|
|
|
|
|
|
|
/* api callbacks */
|
|
|
|
ot->exec= particle_edit_toggle_exec;
|
|
|
|
ot->poll= particle_edit_toggle_poll;
|
|
|
|
|
|
|
|
/* flags */
|
|
|
|
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/************************ set editable operator ************************/
|
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
static int clear_edited_exec(bContext *C, wmOperator *op)
|
2009-02-25 19:29:58 +00:00
|
|
|
{
|
|
|
|
Object *ob= CTX_data_active_object(C);
|
2009-08-29 15:20:36 +00:00
|
|
|
ParticleSystem *psys = psys_get_current(ob);
|
2009-02-25 19:29:58 +00:00
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
if(psys->edit) {
|
|
|
|
if(psys->edit->edited || 1) { // XXX okee("Lose changes done in particle mode?"))
|
|
|
|
PE_free_ptcache_edit(psys->edit);
|
|
|
|
|
|
|
|
psys->edit = NULL;
|
|
|
|
psys->free_edit = NULL;
|
2009-02-25 19:29:58 +00:00
|
|
|
|
2009-06-05 23:59:33 +00:00
|
|
|
psys->recalc |= PSYS_RECALC_RESET;
|
2009-09-05 20:12:08 +00:00
|
|
|
psys->flag &= ~PSYS_GLOBAL_HAIR;
|
2009-09-10 22:32:33 +00:00
|
|
|
psys->flag &= ~PSYS_EDITED;
|
2009-02-25 19:29:58 +00:00
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
psys_reset(psys, PSYS_RESET_DEPSGRAPH);
|
2010-06-18 04:39:32 +00:00
|
|
|
WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_EDITED, ob);
|
2.5
Notifiers
---------
Various fixes for wrong use of notifiers, and some new notifiers
to make things a bit more clear and consistent, with two notable
changes:
* Geometry changes are now done with NC_GEOM, rather than
NC_OBJECT|ND_GEOM_, so an object does need to be available.
* Space data now use NC_SPACE|ND_SPACE_*, instead of data
notifiers or even NC_WINDOW in some cases. Note that NC_SPACE
should only be used for notifying about changes in space data,
we don't want to go back to allqueue(REDRAW..).
Depsgraph
---------
The dependency graph now has a different flush call:
DAG_object_flush_update(scene, ob, flag)
is replaced by:
DAG_id_flush_update(id, flag)
It still works basically the same, one difference is that it now
also accepts object data (e.g. Mesh), again to avoid requiring an
Object to be available. Other ID types will simply do nothing at
the moment.
Docs
----
I made some guidelines for how/when to do which kinds of updates
and notifiers. I can't specify totally exact how to make these
decisions, but these are basically the guidelines I use. So, new
and updated docs are here:
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/NotifiersUpdates
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/DataNotifiers
2009-09-04 20:51:09 +00:00
|
|
|
DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
|
2009-02-25 19:29:58 +00:00
|
|
|
}
|
|
|
|
}
|
2010-09-02 08:06:53 +00:00
|
|
|
else { /* some operation might have protected hair from editing so let's clear the flag */
|
|
|
|
psys->recalc |= PSYS_RECALC_RESET;
|
|
|
|
psys->flag &= ~PSYS_GLOBAL_HAIR;
|
|
|
|
psys->flag &= ~PSYS_EDITED;
|
|
|
|
WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_EDITED, ob);
|
|
|
|
DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
|
|
|
|
}
|
2009-02-25 19:29:58 +00:00
|
|
|
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
void PARTICLE_OT_edited_clear(wmOperatorType *ot)
|
2009-02-25 19:29:58 +00:00
|
|
|
{
|
|
|
|
/* identifiers */
|
2009-08-29 15:20:36 +00:00
|
|
|
ot->name= "Clear Edited";
|
|
|
|
ot->idname= "PARTICLE_OT_edited_clear";
|
2009-02-25 19:29:58 +00:00
|
|
|
|
|
|
|
/* api callbacks */
|
2009-08-29 15:20:36 +00:00
|
|
|
ot->exec= clear_edited_exec;
|
2009-02-25 19:29:58 +00:00
|
|
|
ot->poll= particle_edit_toggle_poll;
|
|
|
|
|
|
|
|
/* flags */
|
|
|
|
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
|
|
|
}
|
|
|
|
|