Fixed preconditioned conjugate to some degree but some issues left for stiffness>1000 (disabled therefore). There's also some issue with the springs function (some springs seem to be missing/not created)

This commit is contained in:
Daniel Genrich 2007-12-12 17:33:59 +00:00
parent e9c9bf5bdb
commit 42637b7252
16 changed files with 152 additions and 54 deletions

@ -200,7 +200,6 @@ typedef void ( *CM_COLLISION_SELF ) ( struct ClothModifierData *clmd, int step )
// only one available in the moment
typedef enum {
CM_IMPLICIT = 0,
CM_VERLET = 1,
} CM_SOLVER_ID;

@ -44,5 +44,6 @@
int BKE_ptcache_id_filename(struct ID *id, char *filename, int cfra, int stack_index, short do_path, short do_ext);
FILE * BKE_ptcache_id_fopen(struct ID *id, char mode, int cfra, int stack_index);
void BKE_ptcache_id_clear(struct ID *id, char mode, int cfra, int stack_index);
int BKE_ptcache_id_exist(struct ID *id, int cfra, int stack_index);
#endif

@ -7,7 +7,7 @@ incs = '. #/intern/guardedalloc ../include ../blenlib ../makesdna'
incs += ' ../python ../render/extern/include #/intern/decimation/extern'
incs += ' ../imbuf ../avi #/intern/elbeem/extern ../nodes'
incs += ' #/intern/iksolver/extern ../blenloader ../quicktime'
incs += ' #/extern/bullet2/src '
incs += ' #/extern/bullet2/src'
incs += ' #/intern/bmfont'
incs += ' ' + env['BF_OPENGL_INC']

@ -115,7 +115,6 @@ double tval()
static CM_SOLVER_DEF solvers [] =
{
{ "Implicit", CM_IMPLICIT, implicit_init, implicit_solver, implicit_free },
// { "Verlet", CM_VERLET, verlet_init, verlet_solver, verlet_free },
};
/* ********** cloth engine ******* */
@ -477,8 +476,9 @@ static int cloth_read_cache(Object *ob, ClothModifierData *clmd, float framenr)
fclose(fp);
}
implicit_set_positions(clmd);
if(clmd->sim_parms->solver_type == 0)
implicit_set_positions(clmd);
return ret;
}
@ -600,6 +600,7 @@ DerivedMesh *clothModifier_do(ClothModifierData *clmd,Object *ob, DerivedMesh *d
tstart();
/* Call the solver. */
if (solvers [clmd->sim_parms->solver_type].solver)
solvers [clmd->sim_parms->solver_type].solver (ob, framenr, clmd, effectors);
@ -625,6 +626,10 @@ DerivedMesh *clothModifier_do(ClothModifierData *clmd,Object *ob, DerivedMesh *d
if(cloth_read_cache(ob, clmd, framenr))
cloth_to_object (ob, result, clmd);
}
else
{
cloth_clear_cache(ob, clmd, 0);
}
}
return result;

@ -241,7 +241,7 @@ DO_INLINE float dot_lfvector(lfVector *fLongVectorA, lfVector *fLongVectorB, uns
unsigned int i = 0;
float temp = 0.0;
// schedule(guided, 2)
#pragma omp parallel for reduction(+: temp)
#pragma omp parallel for reduction(+: temp) private(i)
for(i = 0; i < verts; i++)
{
temp += INPR(fLongVectorA[i], fLongVectorB[i]);
@ -558,6 +558,7 @@ DO_INLINE void mul_bfmatrix_S(fmatrix3x3 *matrix, float scalar)
mul_fmatrix_S(matrix[i].m, scalar);
}
}
/* SPARSE SYMMETRIC multiply big matrix with long vector*/
/* STATUS: verified */
DO_INLINE void mul_bfmatrix_lfvector( float (*to)[3], fmatrix3x3 *from, lfVector *fLongVector)
@ -590,6 +591,20 @@ DO_INLINE void mul_bfmatrix_lfvector( float (*to)[3], fmatrix3x3 *from, lfVector
}
/* SPARSE SYMMETRIC multiply big matrix with long vector (for diagonal preconditioner) */
/* STATUS: verified */
DO_INLINE void mul_prevfmatrix_lfvector( float (*to)[3], fmatrix3x3 *from, lfVector *fLongVector)
{
unsigned int i = 0;
for(i = 0; i < from[0].vcount; i++)
{
mul_fmatrix_fvector(to[from[i].r], from[i].m, fLongVector[from[i].c]);
}
}
/* SPARSE SYMMETRIC add big matrix with big matrix: A = B + C*/
DO_INLINE void add_bfmatrix_bfmatrix( fmatrix3x3 *to, fmatrix3x3 *from, fmatrix3x3 *matrix)
{
@ -983,7 +998,7 @@ int cg_filtered_pre(lfVector *dv, fmatrix3x3 *lA, lfVector *lB, lfVector *z, fma
sub_lfvector_lfvector(r, lB, r, numverts);
filter(r, S);
mul_bfmatrix_lfvector(p, Pinv, r);
mul_prevfmatrix_lfvector(p, Pinv, r);
filter(p, S);
deltaNew = dot_lfvector(r, p, numverts);
@ -1005,7 +1020,7 @@ int cg_filtered_pre(lfVector *dv, fmatrix3x3 *lA, lfVector *lB, lfVector *z, fma
add_lfvector_lfvectorS(r, r, s, -alpha, numverts);
mul_bfmatrix_lfvector(h, Pinv, r);
mul_prevfmatrix_lfvector(h, Pinv, r);
filter(h, S);
deltaOld = deltaNew;
@ -1013,6 +1028,7 @@ int cg_filtered_pre(lfVector *dv, fmatrix3x3 *lA, lfVector *lB, lfVector *z, fma
deltaNew = dot_lfvector(r, h, numverts);
add_lfvector_lfvectorS(p, h, p, deltaNew / deltaOld, numverts);
filter(p, S);
}
@ -1125,6 +1141,7 @@ DO_INLINE void cloth_calc_spring_force(ClothModifierData *clmd, ClothSpring *s,
}
/*
if(s->type == CLOTH_SPRING_TYPE_COLLISION)
{
if(length < L)
@ -1135,6 +1152,7 @@ DO_INLINE void cloth_calc_spring_force(ClothModifierData *clmd, ClothSpring *s,
}
return;
}
*/
// calculate force of structural + shear springs
if(s->type != CLOTH_SPRING_TYPE_BENDING)
@ -1150,7 +1168,7 @@ DO_INLINE void cloth_calc_spring_force(ClothModifierData *clmd, ClothSpring *s,
VECADD(s->f, s->f, stretch_force);
// Ascher & Boxman, p.21: Damping only during elonglation
mul_fvector_S(damping_force, extent, clmd->sim_parms->Cdis * ((INPR(vel,extent)/length)));
mul_fvector_S(damping_force, extent, clmd->sim_parms->Cdis * 0.01 * ((INPR(vel,extent)/length)));
VECADD(s->f, s->f, damping_force);
dfdx_spring_type1(s->dfdx, dir,length,L,k);
@ -1171,12 +1189,17 @@ DO_INLINE void cloth_calc_spring_force(ClothModifierData *clmd, ClothSpring *s,
mul_fvector_S(bending_force, dir, fbstar(length, L, k, cb));
VECADD(s->f, s->f, bending_force);
if(INPR(bending_force,bending_force) > 0.13*0.13)
// if(INPR(bending_force,bending_force) > 0.13*0.13)
{
clmd->sim_parms->flags |= CLOTH_SIMSETTINGS_FLAG_BIG_FORCE;
}
dfdx_spring_type2(s->dfdx, dir,length,L,k, cb);
/*
if(s->ij == 300 || s->kl == 300)
printf("id->F[0]: %f, id->F[1]: %f, id->F[2]: %f\n", s->f[0], s->f[1], s->f[2]);
*/
}
}
}
@ -1192,7 +1215,7 @@ DO_INLINE int cloth_apply_spring_force(ClothModifierData *clmd, ClothSpring *s,
{
sub_fmatrix_fmatrix(dFdV[s->ij].m, dFdV[s->ij].m, s->dfdv);
sub_fmatrix_fmatrix(dFdV[s->kl].m, dFdV[s->kl].m, s->dfdv);
add_fmatrix_fmatrix(dFdV[s->matrix_index].m, dFdV[s->matrix_index].m, s->dfdv);
add_fmatrix_fmatrix(dFdV[s->matrix_index].m, dFdV[s->matrix_index].m, s->dfdv);
}
else if(!(clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_BIG_FORCE))
return 0;
@ -1306,7 +1329,7 @@ void cloth_calc_force(ClothModifierData *clmd, lfVector *lF, lfVector *lX, lfVec
float speed[3] = {0.0f, 0.0f,0.0f};
float force[3]= {0.0f, 0.0f, 0.0f};
#pragma omp parallel for private (i) shared(lF)
// #pragma omp parallel for private (i) shared(lF)
for(i = 0; i < cloth->numverts; i++)
{
float vertexnormal[3]={0,0,0};
@ -1363,7 +1386,6 @@ void cloth_calc_force(ClothModifierData *clmd, lfVector *lF, lfVector *lX, lfVec
}
clmd->sim_parms->flags &= ~CLOTH_SIMSETTINGS_FLAG_BIG_FORCE;
}
void simulate_implicit_euler(lfVector *Vnew, lfVector *lX, lfVector *lV, lfVector *lF, fmatrix3x3 *dFdV, fmatrix3x3 *dFdX, float dt, fmatrix3x3 *A, lfVector *B, lfVector *dV, fmatrix3x3 *S, lfVector *z, fmatrix3x3 *P, fmatrix3x3 *Pinv)
@ -1375,31 +1397,23 @@ void simulate_implicit_euler(lfVector *Vnew, lfVector *lX, lfVector *lV, lfVecto
zero_lfvector(dV, numverts);
subadd_bfmatrixS_bfmatrixS(A, dFdV, dt, dFdX, (dt*dt));
mul_bfmatrix_lfvector(dFdXmV, dFdX, lV);
add_lfvectorS_lfvectorS(B, lF, dt, dFdXmV, (dt*dt), numverts);
// itstart();
// TODO: unstable with quality=5 + stiffness=7000 + no zero_lfvector()
cg_filtered(dV, A, B, z, S); /* conjugate gradient algorithm to solve Ax=b */
// TODO: if anyone finds a way to correct this function =>
// explodes with stiffness = 3000 and 16k verts + pinned at 2 corners
// TODO: unstable with quality=5 + stiffness=7000
// cg_filtered_pre(dV, A, B, z, S, P, Pinv);
// itend();
// printf("cg_filtered calc time: %f\n", (float)itval());
// advance velocities
add_lfvector_lfvector(Vnew, lV, dV, numverts);
del_lfvector(dFdXmV);
}
int implicit_solver (Object *ob, float frame, ClothModifierData *clmd, ListBase *effectors)
{
{
unsigned int i=0;
float step=0.0f, tf=1.0f;
Cloth *cloth = clmd->clothObject;
@ -1418,7 +1432,10 @@ int implicit_solver (Object *ob, float frame, ClothModifierData *clmd, ListBase
// update velocities with constrained velocities from pinned verts
if(verts [i].goal >= SOFTGOALSNAP)
{
VECSUB(id->V[i], cloth->xconst[i], cloth->xold[i]);
float temp[3];
VECSUB(temp, cloth->xconst[i], cloth->xold[i]);
VECSUB(id->z[i], temp, id->V[i]);
// VecMulf(id->V[i], 1.0 / dt);
}
}
@ -1612,6 +1629,8 @@ int collisions_collision_response_static ( ClothModifierData *clmd, CollisionMod
float v1[3], v2[3], relativeVelocity[3];
float magrelVel = 0.0;
float epsilon = clmd->coll_parms->epsilon;
return 0;
cloth1 = clmd->clothObject;
@ -2143,7 +2162,7 @@ int cloth_bvh_objcollision(ClothModifierData * clmd, float step, float prevstep,
int collisions = 0, count = 0;
float (*current_x)[3];
Implicit_Data *id = NULL;
/*
if (!(((Cloth *)clmd->clothObject)->tree))
{
printf("No BVH found\n");
@ -2182,7 +2201,7 @@ int cloth_bvh_objcollision(ClothModifierData * clmd, float step, float prevstep,
// fill collision list
collisions += bvh_traverse ( bvh1->root, bvh2->root, &collision_list );
// call static collision response
if ( collision_list )
{
@ -2223,7 +2242,7 @@ int cloth_bvh_objcollision(ClothModifierData * clmd, float step, float prevstep,
VECADD(cloth->current_x[i], cloth->current_xold[i], cloth->current_v[i]);
}
//////////////////////////////////////////////
*/
/*
// fill collision list
collisions += bvh_traverse(self_bvh->root, self_bvh->root, &collision_list);

@ -672,14 +672,12 @@ static void do_rel_key(int start, int end, int tot, char *basispoin, Key *key, i
/* step 2: do it */
kb= key->block.first;
while(kb) {
for(kb=key->block.first; kb; kb=kb->next) {
if(kb!=key->refkey) {
float icuval= kb->curval;
/* only with value, and no difference allowed */
if(icuval!=0.0f && kb->totelem==tot) {
if(!(kb->flag & KEYBLOCK_MUTE) && icuval!=0.0f && kb->totelem==tot) {
KeyBlock *refb;
float weight, *weights= kb->weights;
@ -738,7 +736,6 @@ static void do_rel_key(int start, int end, int tot, char *basispoin, Key *key, i
}
}
}
kb= kb->next;
}
}
@ -1312,6 +1309,9 @@ int do_ob_key(Object *ob)
if(ob->shapeflag & (OB_SHAPE_LOCK|OB_SHAPE_TEMPLOCK)) {
KeyBlock *kb= BLI_findlink(&key->block, ob->shapenr-1);
if(kb && (kb->flag & KEYBLOCK_MUTE))
kb= key->refkey;
if(kb==NULL) {
kb= key->block.first;
ob->shapenr= 1;

@ -4271,7 +4271,7 @@ void psys_to_softbody(Object *ob, ParticleSystem *psys, int force_recalc)
if((psys->softflag&OB_SB_ENABLE)==0) return;
if((ob->recalc&OB_RECALC_TIME)==0)
if(ob->recalc && (ob->recalc&OB_RECALC_TIME)==0)
psys->softflag|=OB_SB_REDO;
/* let's replace the object's own softbody with the particle softbody */

@ -183,3 +183,11 @@ void BKE_ptcache_id_clear(struct ID *id, char mode, int cfra, int stack_index)
return;
}
int BKE_ptcache_id_exist(struct ID *id, int cfra, int stack_index)
{
char filename[(FILE_MAXDIR+FILE_MAXFILE)*2];
BKE_ptcache_id_filename(id, filename, cfra, stack_index, 1, 1);
return BLI_exists(filename);
}

@ -44,7 +44,7 @@ typedef struct KeyBlock {
float pos;
float curval;
short type, adrcode, relative, pad1; /* relative == 0 means first key is reference */
short type, adrcode, relative, flag; /* relative == 0 means first key is reference */
int totelem, pad2;
void *data;
@ -87,5 +87,8 @@ typedef struct Key {
#define KEY_CARDINAL 1
#define KEY_BSPLINE 2
/* keyblock->flag */
#define KEYBLOCK_MUTE 1
#endif

@ -85,8 +85,11 @@ static void node_composit_exec_normalize(void *data, bNode *node, bNodeStack **i
min = *val;
}
}
min = MIN2(0.1, min);
max = MAX2(0.9, max);
mult = 1.0f/(max-min);
printf("min %f max %f\n", min, max);
composit3_pixel_processor(node, stackbuf, in[0]->data, in[0]->vec, NULL, &min, NULL, &mult, do_normalize, CB_VAL, CB_VAL, CB_VAL);

@ -410,7 +410,6 @@ void do_common_editbuts(unsigned short event) // old name, is a mix of object an
return;
}
}
efa= efa->next;
}
}
else if ELEM(G.obedit->type, OB_CURVE, OB_SURF) {
@ -484,7 +483,7 @@ void do_common_editbuts(unsigned short event) // old name, is a mix of object an
if(ma) {
ob->actcol= find_material_index(ob, ma);
if(ob->actcol==0) {
assign_material(ob, ma, ob->totcol);
assign_material(ob, ma, ob->totcol+1);
ob->actcol= ob->totcol;
}
}
@ -2474,15 +2473,17 @@ static void editing_panel_shapes(Object *ob)
uiBlockBeginAlign(block);
if(ob->shapeflag & OB_SHAPE_LOCK) icon= ICON_PIN_HLT; else icon= ICON_PIN_DEHLT;
uiDefIconButBitS(block, TOG, OB_SHAPE_LOCK, B_LOCKKEY, icon, 10,150,25,20, &ob->shapeflag, 0, 0, 0, 0, "Always show the current Shape for this Object");
if(kb->flag & KEYBLOCK_MUTE) icon= ICON_MUTE_IPO_ON; else icon = ICON_MUTE_IPO_OFF;
uiDefIconButBitS(block, TOG, KEYBLOCK_MUTE, B_MODIFIER_RECALC, icon, 35,150,20,20, &kb->flag, 0, 0, 0, 0, "Mute the current Shape");
uiSetButLock(G.obedit==ob, "Unable to perform in EditMode");
uiDefIconBut(block, BUT, B_PREVKEY, ICON_TRIA_LEFT, 35,150,20,20, NULL, 0, 0, 0, 0, "Previous Shape Key");
uiDefIconBut(block, BUT, B_PREVKEY, ICON_TRIA_LEFT, 55,150,20,20, NULL, 0, 0, 0, 0, "Previous Shape Key");
strp= make_key_menu(key, 1);
uiDefButS(block, MENU, B_SETKEY, strp, 55,150,20,20, &ob->shapenr, 0, 0, 0, 0, "Browse existing choices");
uiDefButS(block, MENU, B_SETKEY, strp, 75,150,20,20, &ob->shapenr, 0, 0, 0, 0, "Browse existing choices");
MEM_freeN(strp);
uiDefIconBut(block, BUT, B_NEXTKEY, ICON_TRIA_RIGHT, 75,150,20,20, NULL, 0, 0, 0, 0, "Next Shape Key");
uiDefIconBut(block, BUT, B_NEXTKEY, ICON_TRIA_RIGHT, 95,150,20,20, NULL, 0, 0, 0, 0, "Next Shape Key");
uiClearButLock();
uiDefBut(block, TEX, B_NAMEKEY, "", 95, 150, 190, 20, kb->name, 0.0, 31.0, 0, 0, "Current Shape Key name");
uiDefBut(block, TEX, B_NAMEKEY, "", 115, 150, 170, 20, kb->name, 0.0, 31.0, 0, 0, "Current Shape Key name");
uiDefIconBut(block, BUT, B_DELKEY, ICON_X, 285,150,25,20, 0, 0, 0, 0, 0, "Deletes current Shape Key");
uiBlockEndAlign(block);

@ -3298,6 +3298,7 @@ static void object_softbodies__enable(void *ob_v, void *arg2)
if (!ob->soft) {
ob->soft= sbNew();
ob->softflag |= OB_SB_GOAL|OB_SB_EDGES;
softbody_clear_cache(ob, CFRA);
}
}
/* needed so that initial state is cached correctly */
@ -3331,6 +3332,7 @@ static void object_softbodies__enable_psys(void *ob_v, void *psys_v)
psys->soft= sbNew();
psys->softflag |= OB_SB_GOAL|OB_SB_EDGES;
psys->soft->particles=psys;
clear_particles_from_cache(ob, psys, CFRA);
}
psys->softflag |= OB_SB_ENABLE;
}

@ -70,6 +70,8 @@
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_meta_types.h"
#include "DNA_modifier_types.h"
#include "DNA_object_force.h"
#include "DNA_object_types.h"
#include "DNA_particle_types.h"
#include "DNA_screen_types.h"
@ -101,8 +103,10 @@
#include "BKE_key.h"
#include "BKE_main.h"
#include "BKE_mesh.h"
#include "BKE_modifier.h"
#include "BKE_object.h"
#include "BKE_particle.h"
#include "BKE_pointcache.h"
#include "BKE_scene.h"
#include "BKE_texture.h"
#include "BKE_utildefines.h"
@ -3292,10 +3296,50 @@ static void inner_play_prefetch_shutdown(int mode)
seq_stop_threads();
}
static int cached_dynamics(int sfra, int efra)
{
Base *base = G.scene->base.first;
Object *ob;
ModifierData *md;
ParticleSystem *psys;
int i, stack_index, cached=1;
while(base && cached) {
ob = base->object;
if(ob->softflag & OB_SB_ENABLE && ob->soft) {
for(i=0, md=ob->modifiers.first; md; i++, md=md->next) {
if(md->type == eModifierType_Softbody) {
stack_index = i;
break;
}
}
for(i=sfra; i<=efra && cached; i++)
cached &= BKE_ptcache_id_exist(&ob->id,i,stack_index);
}
for(psys=ob->particlesystem.first; psys; psys=psys->next) {
stack_index = modifiers_indexInObject(ob,(ModifierData*)psys_get_modifier(ob,psys));
if(psys->part->type==PART_HAIR) {
if(psys->softflag & OB_SB_ENABLE && psys->soft);
else
stack_index = -1;
}
if(stack_index >= 0)
for(i=sfra; i<=efra && cached; i++)
cached &= BKE_ptcache_id_exist(&ob->id,i,stack_index);
}
base = base->next;
}
return cached;
}
void inner_play_anim_loop(int init, int mode)
{
ScrArea *sa;
static int last_cfra = -1;
static int cached = 0;
/* init */
if(init) {
@ -3304,7 +3348,7 @@ void inner_play_anim_loop(int init, int mode)
tottime= 0.0;
curmode= mode;
last_cfra = -1;
cached = cached_dynamics(PSFRA,PEFRA);
return;
}
@ -3328,7 +3372,7 @@ void inner_play_anim_loop(int init, int mode)
if (sa->spacetype == SPACE_SEQ) {
scrarea_do_windraw(sa);
}
}
}
sa= sa->next;
}
@ -3380,8 +3424,10 @@ void inner_play_anim_loop(int init, int mode)
CFRA = PSFRA;
audiostream_stop();
audiostream_start( CFRA );
cached = cached_dynamics(PSFRA,PEFRA);
} else {
if (U.mixbufsize
if (cached
&& U.mixbufsize
&& (G.scene->audio.flag & AUDIO_SYNC)) {
CFRA = audiostream_pos();
} else {

@ -625,7 +625,7 @@ void insert_shapekey(Object *ob)
void delete_key(Object *ob)
{
KeyBlock *kb;
KeyBlock *kb, *rkb;
Key *key;
IpoCurve *icu;
@ -635,6 +635,10 @@ void delete_key(Object *ob)
kb= BLI_findlink(&key->block, ob->shapenr-1);
if(kb) {
for(rkb= key->block.first; rkb; rkb= rkb->next)
if(rkb->relative == ob->shapenr-1)
rkb->relative= 0;
BLI_remlink(&key->block, kb);
key->totkey--;
if(key->refkey== kb) key->refkey= key->block.first;

@ -82,6 +82,7 @@ editmesh_mods.c, UI level access, no geometry changes
#include "BIF_interface.h"
#include "BIF_meshtools.h"
#include "BIF_mywindow.h"
#include "BIF_previewrender.h"
#include "BIF_resources.h"
#include "BIF_screen.h"
#include "BIF_space.h"
@ -2126,6 +2127,12 @@ void mouse_mesh(void)
allqueue(REDRAWIMAGE, 0);
allqueue(REDRAWBUTSEDIT, 0); /* for the texture face panel */
}
if (efa && efa->mat_nr != G.obedit->actcol-1) {
G.obedit->actcol= efa->mat_nr+1;
allqueue(REDRAWBUTSEDIT, 0);
allqueue(REDRAWBUTSSHADING, 0);
BIF_preview_changed(ID_MA);
}
}
rightmouse_transform();

@ -1703,10 +1703,10 @@ static int remove_tagged_elements(Object *ob, ParticleSystem *psys)
}
}
MEM_freeN(psys->particles);
if(psys->particles) MEM_freeN(psys->particles);
psys->particles = new_pars;
MEM_freeN(edit->keys);
if(edit->keys) MEM_freeN(edit->keys);
edit->keys = new_keys;
if(edit->mirror_cache) {
@ -2256,10 +2256,10 @@ static void brush_add(Object *ob, ParticleSystem *psys, short *mval, short numbe
memcpy(new_keys, edit->keys, totpart * sizeof(ParticleEditKey*));
/* change old arrays to new ones */
MEM_freeN(psys->particles);
if(psys->particles) MEM_freeN(psys->particles);
psys->particles = new_pars;
MEM_freeN(edit->keys);
if(edit->keys) MEM_freeN(edit->keys);
edit->keys = new_keys;
if(edit->mirror_cache) {
@ -2267,8 +2267,6 @@ static void brush_add(Object *ob, ParticleSystem *psys, short *mval, short numbe
edit->mirror_cache = NULL;
}
psys->totpart = newtotpart;
/* create tree for interpolation */
if(pset->flag & PE_INTERPOLATE_ADDED && psys->totpart){
tree=BLI_kdtree_new(psys->totpart);
@ -2281,6 +2279,8 @@ static void brush_add(Object *ob, ParticleSystem *psys, short *mval, short numbe
BLI_kdtree_balance(tree);
}
psys->totpart = newtotpart;
/* create new elements */
pa = psys->particles + totpart;
key = edit->keys + totpart;
@ -2691,10 +2691,10 @@ void PE_mirror_x(int tagged)
memcpy(new_pars, psys->particles, totpart*sizeof(ParticleData));
memcpy(new_keys, edit->keys, totpart*sizeof(ParticleEditKey*));
MEM_freeN(psys->particles);
if(psys->particles) MEM_freeN(psys->particles);
psys->particles= new_pars;
MEM_freeN(edit->keys);
if(edit->keys) MEM_freeN(edit->keys);
edit->keys= new_keys;
if(edit->mirror_cache) {