diff options
author | Andre Susano Pinto <andresusanopinto@gmail.com> | 2008-08-22 02:57:25 +0400 |
---|---|---|
committer | Andre Susano Pinto <andresusanopinto@gmail.com> | 2008-08-22 02:57:25 +0400 |
commit | f4ae23f3794605f5b7c0a5b90d982d6dfd20d492 (patch) | |
tree | 0f1c725f89be062437f0114d5ef1a2fe501fd600 /source | |
parent | a06321d55c2f25440120ac2fdead20639863a608 (diff) |
svn merge -r 16174:16215 https://svn.blender.org/svnroot/bf-blender/trunk/blender
Diffstat (limited to 'source')
43 files changed, 1066 insertions, 551 deletions
diff --git a/source/blender/blenkernel/BKE_blender.h b/source/blender/blenkernel/BKE_blender.h index e1eb6718a30..e403fc33e06 100644 --- a/source/blender/blenkernel/BKE_blender.h +++ b/source/blender/blenkernel/BKE_blender.h @@ -41,7 +41,7 @@ struct ListBase; struct MemFile; #define BLENDER_VERSION 247 -#define BLENDER_SUBVERSION 0 +#define BLENDER_SUBVERSION 1 #define BLENDER_MINVERSION 245 #define BLENDER_MINSUBVERSION 15 diff --git a/source/blender/blenkernel/BKE_collision.h b/source/blender/blenkernel/BKE_collision.h index 2966d932a49..c483148e4de 100644 --- a/source/blender/blenkernel/BKE_collision.h +++ b/source/blender/blenkernel/BKE_collision.h @@ -119,8 +119,10 @@ FaceCollPair; ///////////////////////////////////////////////// // used in modifier.c from collision.c ///////////////////////////////////////////////// + BVHTree *bvhtree_build_from_mvert ( MFace *mfaces, unsigned int numfaces, MVert *x, unsigned int numverts, float epsilon ); void bvhtree_update_from_mvert ( BVHTree * bvhtree, MFace *faces, int numfaces, MVert *x, MVert *xnew, int numverts, int moving ); + ///////////////////////////////////////////////// LinkNode *BLI_linklist_append_fast ( LinkNode **listp, void *ptr ); @@ -134,6 +136,15 @@ void collisions_compute_barycentric ( float pv[3], float p1[3], float p2[3], flo void interpolateOnTriangle ( float to[3], float v1[3], float v2[3], float v3[3], double w1, double w2, double w3 ); ///////////////////////////////////////////////// +// used in effect.c +///////////////////////////////////////////////// +CollisionModifierData **get_collisionobjects(Object *self, int *numcollobj); + +///////////////////////////////////////////////// + + + +///////////////////////////////////////////////// #endif diff --git a/source/blender/blenkernel/BKE_effect.h b/source/blender/blenkernel/BKE_effect.h index 3b4c3198179..6475f7a71ac 100644 --- a/source/blender/blenkernel/BKE_effect.h +++ b/source/blender/blenkernel/BKE_effect.h @@ -66,7 +66,7 @@ void pdEndEffectors(struct ListBase *lb); void pdDoEffectors(struct ListBase *lb, float *opco, float *force, float *speed, float cur_time, float loc_time, unsigned int flags); /* required for particle_system.c */ -void do_physical_effector(short type, float force_val, float distance, float falloff, float size, float damp, float *eff_velocity, float *vec_to_part, float *velocity, float *field, int planar, struct RNG *rng, float noise); +void do_physical_effector(Object *ob, float *opco, short type, float force_val, float distance, float falloff, float size, float damp, float *eff_velocity, float *vec_to_part, float *velocity, float *field, int planar, struct RNG *rng, float noise_factor, float charge, float pa_size); float effector_falloff(struct PartDeflect *pd, float *eff_velocity, float *vec_to_part); diff --git a/source/blender/blenkernel/intern/collision.c b/source/blender/blenkernel/intern/collision.c index cfcab54058d..b5e09d551f0 100644 --- a/source/blender/blenkernel/intern/collision.c +++ b/source/blender/blenkernel/intern/collision.c @@ -31,10 +31,11 @@ #include "BKE_cloth.h" -#include "DNA_group_types.h" -#include "DNA_object_types.h" #include "DNA_cloth_types.h" +#include "DNA_group_types.h" #include "DNA_mesh_types.h" +#include "DNA_object_types.h" +#include "DNA_object_force.h" #include "DNA_scene_types.h" #include "BKE_DerivedMesh.h" @@ -1307,9 +1308,34 @@ CollisionModifierData **get_collisionobjects(Object *self, int *numcollobj) for ( base = G.scene->base.first; base; base = base->next ) { coll_ob = base->object; - collmd = ( CollisionModifierData * ) modifiers_findByType ( coll_ob, eModifierType_Collision ); - - if ( !collmd ) + + if(coll_ob->pd && coll_ob->pd->deflect) + { + collmd = ( CollisionModifierData * ) modifiers_findByType ( coll_ob, eModifierType_Collision ); + } + + if ( collmd ) + { + if(coll_ob == self) + continue; + + if(numobj >= maxobj) + { + // realloc + int oldmax = maxobj; + CollisionModifierData **tmp; + maxobj *= 2; + tmp = MEM_callocN(sizeof(CollisionModifierData *)*maxobj, "CollisionObjectsArray"); + memcpy(tmp, objs, sizeof(CollisionModifierData *)*oldmax); + MEM_freeN(objs); + objs = tmp; + + } + + objs[numobj] = collmd; + numobj++; + } + else { if ( coll_ob->dup_group ) { @@ -1319,8 +1345,12 @@ CollisionModifierData **get_collisionobjects(Object *self, int *numcollobj) for ( go= group->gobject.first; go; go= go->next ) { coll_ob = go->ob; - - collmd = ( CollisionModifierData * ) modifiers_findByType ( coll_ob, eModifierType_Collision ); + collmd = NULL; + + if(coll_ob->pd && coll_ob->pd->deflect) + { + collmd = ( CollisionModifierData * ) modifiers_findByType ( coll_ob, eModifierType_Collision ); + } if ( !collmd ) continue; @@ -1347,27 +1377,6 @@ CollisionModifierData **get_collisionobjects(Object *self, int *numcollobj) numobj++; } } - } - else - { - if(coll_ob == self) - continue; - - if(numobj >= maxobj) - { - // realloc - int oldmax = maxobj; - CollisionModifierData **tmp; - maxobj *= 2; - tmp = MEM_callocN(sizeof(CollisionModifierData *)*maxobj, "CollisionObjectsArray"); - memcpy(tmp, objs, sizeof(CollisionModifierData *)*oldmax); - MEM_freeN(objs); - objs = tmp; - - } - - objs[numobj] = collmd; - numobj++; } } *numcollobj = numobj; @@ -1484,6 +1493,9 @@ int cloth_bvh_objcollision ( Object *ob, ClothModifierData * clmd, float step, f BVHTreeOverlap *overlap = NULL; int result = 0; + if(!collmd->bvhtree) + continue; + /* move object to position (step) in time */ collision_move_object ( collmd, step + dt, step ); diff --git a/source/blender/blenkernel/intern/effect.c b/source/blender/blenkernel/intern/effect.c index 7620edac126..0842e55a0ea 100644 --- a/source/blender/blenkernel/intern/effect.c +++ b/source/blender/blenkernel/intern/effect.c @@ -59,6 +59,7 @@ #include "BKE_armature.h" #include "BKE_bad_level_calls.h" #include "BKE_blender.h" +#include "BKE_collision.h" #include "BKE_constraint.h" #include "BKE_deform.h" #include "BKE_depsgraph.h" @@ -228,6 +229,60 @@ void pdEndEffectors(ListBase *lb) /* Effectors */ /************************************************/ +// triangle - ray callback function +static void eff_tri_ray_hit(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit) +{ + // whenever we hit a bounding box, we don't check further + hit->dist = -1; + hit->index = 1; +} + +// get visibility of a wind ray +static float eff_calc_visibility(Object *ob, float *co, float *dir) +{ + CollisionModifierData **collobjs = NULL; + int numcollobj = 0, i; + float norm[3], len = 0.0; + float visibility = 1.0; + + collobjs = get_collisionobjects(ob, &numcollobj); + + if(!collobjs) + return 0; + + VECCOPY(norm, dir); + VecMulf(norm, -1.0); + len = Normalize(norm); + + // check all collision objects + for(i = 0; i < numcollobj; i++) + { + CollisionModifierData *collmd = collobjs[i]; + + if(collmd->bvhtree) + { + BVHTreeRayHit hit; + + hit.index = -1; + hit.dist = len + FLT_EPSILON; + + // check if the way is blocked + if(BLI_bvhtree_ray_cast(collmd->bvhtree, co, norm, &hit, eff_tri_ray_hit, NULL)>=0) + { + // visibility is only between 0 and 1, calculated from 1-absorption + visibility *= MAX2(0.0, MIN2(1.0, (1.0-((float)collmd->absorption)*0.01))); + + if(visibility <= 0.0f) + break; + } + } + } + + MEM_freeN(collobjs); + + return visibility; +} + // noise function for wind e.g. static float wind_func(struct RNG *rng, float strength) { @@ -277,7 +332,10 @@ float effector_falloff(PartDeflect *pd, float *eff_velocity, float *vec_to_part) { float eff_dir[3], temp[3]; float falloff=1.0, fac, r_fac; - + + if(pd->forcefield==PFIELD_LENNARDJ) + return falloff; /* Lennard-Jones field has it's own falloff built in */ + VecCopyf(eff_dir,eff_velocity); Normalize(eff_dir); @@ -314,12 +372,18 @@ float effector_falloff(PartDeflect *pd, float *eff_velocity, float *vec_to_part) return falloff; } -void do_physical_effector(short type, float force_val, float distance, float falloff, float size, float damp, float *eff_velocity, float *vec_to_part, float *velocity, float *field, int planar, struct RNG *rng, float noise) +void do_physical_effector(Object *ob, float *opco, short type, float force_val, float distance, float falloff, float size, float damp, float *eff_velocity, float *vec_to_part, float *velocity, float *field, int planar, struct RNG *rng, float noise_factor, float charge, float pa_size) { float mag_vec[3]={0,0,0}; float temp[3], temp2[3]; float eff_vel[3]; - float wind = 0; + float noise = 0, visibility; + + // calculate visibility + visibility = eff_calc_visibility(ob, opco, vec_to_part); + if(visibility <= 0.0) + return; + falloff *= visibility; VecCopyf(eff_vel,eff_velocity); Normalize(eff_vel); @@ -328,11 +392,11 @@ void do_physical_effector(short type, float force_val, float distance, float fal case PFIELD_WIND: VECCOPY(mag_vec,eff_vel); - // add wind noise here - if(noise> 0.0f) - wind = wind_func(rng, noise); - - VecMulf(mag_vec,(force_val+wind)*falloff); + // add wind noise here, only if we have wind + if((noise_factor > 0.0f) && (force_val > FLT_EPSILON)) + noise = wind_func(rng, noise_factor); + + VecMulf(mag_vec,(force_val+noise)*falloff); VecAddf(field,field,mag_vec); break; @@ -381,19 +445,46 @@ void do_physical_effector(short type, float force_val, float distance, float fal VecMulf(mag_vec,damp*1.9f*(float)sqrt(force_val)); VecSubf(field,field,mag_vec); break; - case PFIELD_NUCLEAR: - /*pow here is root of cosine expression below*/ - //rad=(float)pow(2.0,-1.0/power)*distance/size; - //VECCOPY(mag_vec,vec_to_part); - //Normalize(mag_vec); - //VecMulf(mag_vec,(float)cos(3.0*M_PI/2.0*(1.0-1.0/(pow(rad,power)+1.0)))/(rad+0.2f)); - //VECADDFAC(field,field,mag_vec,force_val); + case PFIELD_CHARGE: + if(planar) + Projf(mag_vec,vec_to_part,eff_vel); + else + VecCopyf(mag_vec,vec_to_part); + + VecMulf(mag_vec,charge*force_val*falloff); + VecAddf(field,field,mag_vec); break; - } -} + case PFIELD_LENNARDJ: + { + float fac; + + if(planar) { + Projf(mag_vec,vec_to_part,eff_vel); + distance = VecLength(mag_vec); + } + else + VecCopyf(mag_vec,vec_to_part); + + /* at this distance the field is 60 times weaker than maximum */ + if(distance > 2.22 * (size+pa_size)) + break; + fac = pow((size+pa_size)/distance,6.0); + + fac = - fac * (1.0 - fac) / distance; + /* limit the repulsive term drastically to avoid huge forces */ + fac = ((fac>2.0) ? 2.0 : fac); + /* 0.003715 is the fac value at 2.22 times (size+pa_size), + substracted to avoid discontinuity at the border + */ + VecMulf(mag_vec, force_val * (fac-0.0037315)); + VecAddf(field,field,mag_vec); + break; + } + } +} /* -------- pdDoEffectors() -------- generic force/speed system, now used for particles and softbodies @@ -451,16 +542,16 @@ void pdDoEffectors(ListBase *lb, float *opco, float *force, float *speed, float VecSubf(vec_to_part, opco, ob->obmat[3]); distance = VecLength(vec_to_part); - falloff=effector_falloff(pd,ob->obmat[2],vec_to_part); - + falloff=effector_falloff(pd,ob->obmat[2],vec_to_part); + if(falloff<=0.0f) ; /* don't do anything */ else { float field[3]={0,0,0}, tmp[3]; VECCOPY(field, force); - do_physical_effector(pd->forcefield,pd->f_strength,distance, + do_physical_effector(ob, opco, pd->forcefield,pd->f_strength,distance, falloff,pd->f_dist,pd->f_damp,ob->obmat[2],vec_to_part, - speed,force,pd->flag&PFIELD_PLANAR, pd->rng, pd->f_noise); + speed,force,pd->flag&PFIELD_PLANAR, pd->rng, pd->f_noise, 0.0f, 0.0f); // for softbody backward compatibility if(flags & PE_WIND_AS_SPEED){ diff --git a/source/blender/blenkernel/intern/implicit.c b/source/blender/blenkernel/intern/implicit.c index 0375ab22909..93e35a4db06 100644 --- a/source/blender/blenkernel/intern/implicit.c +++ b/source/blender/blenkernel/intern/implicit.c @@ -1451,7 +1451,7 @@ void cloth_calc_force(ClothModifierData *clmd, lfVector *lF, lfVector *lX, lfVec float triunnormal[3]={0,0,0}; // not-normalized-triangle normal float tmp[3]={0,0,0}; float factor = (mfaces[i].v4) ? 0.25 : 1.0 / 3.0; - factor *= 0.05; + factor *= 0.02; // calculate face normal if(mfaces[i].v4) diff --git a/source/blender/blenkernel/intern/ipo.c b/source/blender/blenkernel/intern/ipo.c index fe92edfbbd5..4af25ee99e7 100644 --- a/source/blender/blenkernel/intern/ipo.c +++ b/source/blender/blenkernel/intern/ipo.c @@ -182,7 +182,7 @@ int part_ar[PART_TOTIPO]= { PART_EMIT_FREQ, PART_EMIT_LIFE, PART_EMIT_VEL, PART_EMIT_AVE, PART_EMIT_SIZE, PART_AVE, PART_SIZE, PART_DRAG, PART_BROWN, PART_DAMP, PART_LENGTH, PART_CLUMP, PART_GRAV_X, PART_GRAV_Y, PART_GRAV_Z, PART_KINK_AMP, PART_KINK_FREQ, PART_KINK_SHAPE, - PART_BB_TILT, PART_PD_FSTR, PART_PD_FFALL, PART_PD_FMAXD + PART_BB_TILT, PART_PD_FSTR, PART_PD_FFALL, PART_PD_FMAXD, PART_PD2_FSTR, PART_PD2_FFALL, PART_PD2_FMAXD }; @@ -1614,6 +1614,12 @@ void *get_ipo_poin(ID *id, IpoCurve *icu, int *type) poin= (part->pd?(&(part->pd->f_power)):NULL); break; case PART_PD_FMAXD: poin= (part->pd?(&(part->pd->maxdist)):NULL); break; + case PART_PD2_FSTR: + poin= (part->pd2?(&(part->pd2->f_strength)):NULL); break; + case PART_PD2_FFALL: + poin= (part->pd2?(&(part->pd2->f_power)):NULL); break; + case PART_PD2_FMAXD: + poin= (part->pd2?(&(part->pd2->maxdist)):NULL); break; } } diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c index d08f30ff995..f33f33d9d46 100644 --- a/source/blender/blenkernel/intern/modifier.c +++ b/source/blender/blenkernel/intern/modifier.c @@ -5496,7 +5496,7 @@ static void collisionModifier_deformVerts( numverts = dm->getNumVerts ( dm ); - if(current_time > collmd->time) + if((current_time > collmd->time)|| (BKE_ptcache_get_continue_physics())) { // check if mesh has changed if(collmd->x && (numverts != collmd->numverts)) diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c index 643f90637ad..2f4696fc442 100644 --- a/source/blender/blenkernel/intern/particle.c +++ b/source/blender/blenkernel/intern/particle.c @@ -320,8 +320,14 @@ int psys_check_enabled(Object *ob, ParticleSystem *psys) /************************************************/ void psys_free_settings(ParticleSettings *part) { - if(part->pd) + if(part->pd) { MEM_freeN(part->pd); + part->pd = NULL; + } + if(part->pd2) { + MEM_freeN(part->pd2); + part->pd2 = NULL; + } } void free_hair(ParticleSystem *psys, int softbody) @@ -3015,6 +3021,7 @@ ParticleSettings *psys_copy_settings(ParticleSettings *part) partn= copy_libblock(part); if(partn->pd) partn->pd= MEM_dupallocN(part->pd); + if(partn->pd2) partn->pd2= MEM_dupallocN(part->pd2); return partn; } diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c index 60fdbca2021..ef8373ee977 100644 --- a/source/blender/blenkernel/intern/particle_system.c +++ b/source/blender/blenkernel/intern/particle_system.c @@ -60,6 +60,7 @@ #include "BKE_bad_level_calls.h" #include "BKE_cdderivedmesh.h" #include "BKE_displist.h" +#include "BKE_effect.h" #include "BKE_particle.h" #include "BKE_global.h" #include "BKE_utildefines.h" @@ -2205,6 +2206,9 @@ static int get_particles_from_cache(Object *ob, ParticleSystem *psys, int cfra) return 1; } +/************************************************/ +/* Effectors */ +/************************************************/ static void do_texture_effector(Tex *tex, short mode, short is_2d, float nabla, short object, float *pa_co, float obmat[4][4], float force_val, float falloff, float *field) { TexResult result[4]; @@ -2322,10 +2326,11 @@ static void add_to_effectors(ListBase *lb, Object *ob, Object *obsrc, ParticleSy for(i=0; epsys; epsys=epsys->next,i++){ type=0; - if(epsys!=psys){ + if(epsys!=psys || (psys->part->flag & PART_SELF_EFFECT)){ epart=epsys->part; - if(epsys->part->pd && epsys->part->pd->forcefield) + if((epsys->part->pd && epsys->part->pd->forcefield) + || (epsys->part->pd2 && epsys->part->pd2->forcefield)) type=PSYS_EC_PARTICLE; if(epart->type==PART_REACTOR) { @@ -2574,35 +2579,31 @@ void do_effectors(int pa_no, ParticleData *pa, ParticleKey *state, Object *ob, P ListBase *lb=&psys->effectors; ParticleEffectorCache *ec; float distance, vec_to_part[3]; - float falloff; + float falloff, charge = 0.0f; int p; /* check all effector objects for interaction */ if(lb->first){ + if(psys->part->pd && psys->part->pd->forcefield==PFIELD_CHARGE){ + /* Only the charge of the effected particle is used for + interaction, not fall-offs. If the fall-offs aren't the + same this will be unphysical, but for animation this + could be the wanted behavior. If you want physical + correctness the fall-off should be spherical 2.0 anyways. + */ + charge = psys->part->pd->f_strength; + } + if(psys->part->pd2 && psys->part->pd2->forcefield==PFIELD_CHARGE){ + charge += psys->part->pd2->f_strength; + } for(ec = lb->first; ec; ec= ec->next){ eob= ec->ob; if(ec->type & PSYS_EC_EFFECTOR){ pd=eob->pd; if(psys->part->type!=PART_HAIR && psys->part->integrator) where_is_object_time(eob,cfra); - /* Get IPO force strength and fall off values here */ - //if (has_ipo_code(eob->ipo, OB_PD_FSTR)) - // force_val = IPO_GetFloatValue(eob->ipo, OB_PD_FSTR, cfra); - //else - // force_val = pd->f_strength; - - //if (has_ipo_code(eob->ipo, OB_PD_FFALL)) - // ffall_val = IPO_GetFloatValue(eob->ipo, OB_PD_FFALL, cfra); - //else - // ffall_val = pd->f_power; - - //if (has_ipo_code(eob->ipo, OB_PD_FMAXD)) - // maxdist = IPO_GetFloatValue(eob->ipo, OB_PD_FMAXD, cfra); - //else - // maxdist = pd->maxdist; /* use center of object for distance calculus */ - //obloc= eob->obmat[3]; VecSubf(vec_to_part, state->co, eob->obmat[3]); distance = VecLength(vec_to_part); @@ -2615,22 +2616,22 @@ void do_effectors(int pa_no, ParticleData *pa, ParticleKey *state, Object *ob, P pd->flag & PFIELD_TEX_OBJECT, (pd->flag & PFIELD_TEX_ROOTCO) ? rootco : state->co, eob->obmat, pd->f_strength, falloff, force_field); } else { - do_physical_effector(pd->forcefield,pd->f_strength,distance, - falloff,pd->f_dist,pd->f_damp,eob->obmat[2],vec_to_part, - pa->state.vel,force_field,pd->flag&PFIELD_PLANAR, pd->rng, pd->f_noise); + do_physical_effector(eob, state->co, pd->forcefield,pd->f_strength,distance, + falloff,0.0,pd->f_damp,eob->obmat[2],vec_to_part, + pa->state.vel,force_field,pd->flag&PFIELD_PLANAR,pd->rng,pd->f_noise,charge,pa->size); } } if(ec->type & PSYS_EC_PARTICLE){ - int totepart; + int totepart, i; epsys= BLI_findlink(&eob->particlesystem,ec->psys_nbr); epart= epsys->part; - pd= epart->pd; + pd=epart->pd; totepart= epsys->totpart; if(totepart <= 0) continue; - if(pd->forcefield==PFIELD_HARMONIC){ + if(pd && pd->forcefield==PFIELD_HARMONIC){ /* every particle is mapped to only one harmonic effector particle */ p= pa_no%epsys->totpart; totepart= p+1; @@ -2642,31 +2643,27 @@ void do_effectors(int pa_no, ParticleData *pa, ParticleKey *state, Object *ob, P epsys->lattice=psys_get_lattice(ob,psys); for(; p<totepart; p++){ + /* particle skips itself as effector */ + if(epsys==psys && p == pa_no) continue; + epa = epsys->particles + p; estate.time=-1.0; if(psys_get_particle_state(eob,epsys,p,&estate,0)){ VECSUB(vec_to_part, state->co, estate.co); distance = VecLength(vec_to_part); - - //if(pd->forcefield==PFIELD_HARMONIC){ - // //if(cfra < epa->time + radius){ /* radius is fade-in in ui */ - // // eforce*=(cfra-epa->time)/radius; - // //} - //} - //else{ - // /* Limit minimum distance to effector particle so that */ - // /* the force is not too big */ - // if (distance < 0.001) distance = 0.001f; - //} - falloff=effector_falloff(pd,estate.vel,vec_to_part); + for(i=0, pd = epart->pd; i<2; i++,pd = epart->pd2) { + if(pd==NULL || pd->forcefield==0) continue; - if(falloff<=0.0f) - ; /* don't do anything */ - else - do_physical_effector(pd->forcefield,pd->f_strength,distance, - falloff,epart->size,pd->f_damp,estate.vel,vec_to_part, - state->vel,force_field,0, pd->rng, pd->f_noise); + falloff=effector_falloff(pd,estate.vel,vec_to_part); + + if(falloff<=0.0f) + ; /* don't do anything */ + else + do_physical_effector(eob, state->co, pd->forcefield,pd->f_strength,distance, + falloff,epart->size,pd->f_damp,estate.vel,vec_to_part, + state->vel,force_field,0, pd->rng, pd->f_noise,charge,pa->size); + } } else if(pd->forcefield==PFIELD_HARMONIC && cfra-framestep <= epa->dietime && cfra>epa->dietime){ /* first step after key release */ diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 9d7a0302d45..35ca42a4949 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -2589,6 +2589,7 @@ static void lib_link_particlesettings(FileData *fd, Main *main) static void direct_link_particlesettings(FileData *fd, ParticleSettings *part) { part->pd= newdataadr(fd, part->pd); + part->pd2= newdataadr(fd, part->pd2); } static void lib_link_particlesystems(FileData *fd, ID *id, ListBase *particles) diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index b462233528a..d596f57990f 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -535,6 +535,7 @@ static void write_particlesettings(WriteData *wd, ListBase *idbase) writestruct(wd, ID_PA, "ParticleSettings", 1, part); if (part->id.properties) IDP_WriteProperty(part->id.properties, wd); writestruct(wd, DATA, "PartDeflect", 1, part->pd); + writestruct(wd, DATA, "PartDeflect", 1, part->pd2); } part= part->id.next; } diff --git a/source/blender/include/BIF_resources.h b/source/blender/include/BIF_resources.h index df514190270..0d27804dd1a 100644 --- a/source/blender/include/BIF_resources.h +++ b/source/blender/include/BIF_resources.h @@ -524,6 +524,10 @@ enum { TH_EDGE_SHARP, TH_EDITMESH_ACTIVE, + + TH_HANDLE_VERTEX, + TH_HANDLE_VERTEX_SELECT, + TH_HANDLE_VERTEX_SIZE, }; /* XXX WARNING: previous is saved in file, so do not change order! */ diff --git a/source/blender/makesdna/DNA_ipo_types.h b/source/blender/makesdna/DNA_ipo_types.h index 03ffef3cd55..1e30f3f7640 100644 --- a/source/blender/makesdna/DNA_ipo_types.h +++ b/source/blender/makesdna/DNA_ipo_types.h @@ -354,8 +354,8 @@ typedef short IPO_Channel; /* ******************** */ /* particle ipos */ -#define PART_TOTIPO 22 -#define PART_TOTNAM 22 +#define PART_TOTIPO 25 +#define PART_TOTNAM 25 #define PART_EMIT_FREQ 1 #define PART_EMIT_LIFE 2 @@ -385,6 +385,10 @@ typedef short IPO_Channel; #define PART_PD_FFALL 21 #define PART_PD_FMAXD 22 +#define PART_PD2_FSTR 23 +#define PART_PD2_FFALL 24 +#define PART_PD2_FMAXD 25 + /* these are IpoCurve specific */ /* **************** IPO ********************* */ diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h index 9ce04c1c272..0f820e88541 100644 --- a/source/blender/makesdna/DNA_modifier_types.h +++ b/source/blender/makesdna/DNA_modifier_types.h @@ -392,7 +392,8 @@ typedef struct CollisionModifierData { unsigned int numverts; unsigned int numfaces; - int pad; + short absorption; /* used for forces, in % */ + short pad; float time; /* cfra time of modifier */ struct BVHTree *bvhtree; /* bounding volume hierarchy for this cloth object */ } CollisionModifierData; diff --git a/source/blender/makesdna/DNA_object_force.h b/source/blender/makesdna/DNA_object_force.h index 5f6ae7c7f06..5900e16d5e8 100644 --- a/source/blender/makesdna/DNA_object_force.h +++ b/source/blender/makesdna/DNA_object_force.h @@ -156,8 +156,8 @@ typedef struct SoftBody { #define PFIELD_GUIDE 5 #define PFIELD_TEXTURE 6 #define PFIELD_HARMONIC 7 -#define PFIELD_NUCLEAR 8 -#define PFIELD_MDIPOLE 9 +#define PFIELD_CHARGE 8 +#define PFIELD_LENNARDJ 9 /* pd->flag: various settings */ diff --git a/source/blender/makesdna/DNA_particle_types.h b/source/blender/makesdna/DNA_particle_types.h index 4f62cd084cc..363f0075e23 100644 --- a/source/blender/makesdna/DNA_particle_types.h +++ b/source/blender/makesdna/DNA_particle_types.h @@ -166,6 +166,7 @@ typedef struct ParticleSettings { struct Object *bb_ob; struct Ipo *ipo; struct PartDeflect *pd; + struct PartDeflect *pd2; } ParticleSettings; typedef struct ParticleSystem{ /* note, make sure all (runtime) are NULL's in copy_particlesystem */ @@ -264,6 +265,8 @@ typedef struct ParticleSystem{ /* note, make sure all (runtime) are NULL's in #define PART_CHILD_RENDER (1<<29) #define PART_CHILD_GUIDE (1<<30) +#define PART_SELF_EFFECT (1<<22) + /* part->rotfrom */ #define PART_ROT_KEYS 0 /* interpolate directly from keys */ #define PART_ROT_ZINCR 1 /* same as zdir but done incrementally from previous position */ diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h index cd1c047dac9..856324695a9 100644 --- a/source/blender/makesdna/DNA_userdef_types.h +++ b/source/blender/makesdna/DNA_userdef_types.h @@ -101,6 +101,11 @@ typedef struct ThemeSpace { char movie[4], image[4], scene[4], audio[4]; // for sequence editor char effect[4], plugin[4], transition[4], meta[4]; char editmesh_active[4]; + + char handle_vertex[4]; + char handle_vertex_select[4]; + char handle_vertex_size; + char hpad[7]; } ThemeSpace; diff --git a/source/blender/python/api2_2x/Material.c b/source/blender/python/api2_2x/Material.c index ccd24a437b5..20747a167e6 100644 --- a/source/blender/python/api2_2x/Material.c +++ b/source/blender/python/api2_2x/Material.c @@ -554,6 +554,7 @@ static int Material_setSssTexScatter( BPy_Material * self, PyObject * value ); static int Material_setSssFront( BPy_Material * self, PyObject * value ); static int Material_setSssBack( BPy_Material * self, PyObject * value ); static int Material_setSssBack( BPy_Material * self, PyObject * value ); +static int Material_setTexChannel( BPy_Material * self, PyObject * value ); static PyObject *Material_getColorComponent( BPy_Material * self, void * closure ); @@ -633,6 +634,7 @@ static PyObject *Material_getSssBack( BPy_Material * self ); static PyObject *Material_getFilter( BPy_Material * self ); static PyObject *Material_getTranslucency( BPy_Material * self ); static PyObject *Material_getTextures( BPy_Material * self ); +static PyObject *Material_getTexChannel( BPy_Material * self ); static PyObject *Material_clearIpo( BPy_Material * self ); static PyObject *Material_setTexture( BPy_Material * self, PyObject * args ); @@ -1140,7 +1142,11 @@ static PyGetSetDef BPy_Material_getseters[] = { NULL}, {"lightGroup", (getter)Material_getLightGroup, (setter)Material_setLightGroup, - "Set the light group for this material", + "The light group for this material", + NULL}, + {"enabledTextures", + (getter)Material_getTexChannel, (setter)Material_setTexChannel, + "Enabled texture channels for this material", NULL}, {"R", (getter)Material_getColorComponent, (setter)Material_setColorComponent, @@ -1517,6 +1523,36 @@ static PyObject *Material_getLightGroup( BPy_Material * self ) return Group_CreatePyObject( self->material->group ); } +static PyObject *Material_getTexChannel( BPy_Material * self ) +{ + int i; + short mask = 1; + PyObject *list = PyList_New(0); + if( !list ) + return EXPP_ReturnPyObjError( PyExc_MemoryError, + "PyList_New() failed" ); + + for( i = 0, mask = 1; i < MAX_MTEX ; ++i, mask <<= 1 ) { + if( self->material->mtex[i] && (mask & self->material->septex) == 0 ) { + PyObject * val = PyInt_FromLong(i); + if( !val ) { + Py_DECREF( list ); + return EXPP_ReturnPyObjError( PyExc_MemoryError, + "PyInt_FromLong() failed" ); + } + if( PyList_Append( list, val ) < 0 ) { + Py_DECREF( val ); + Py_DECREF( list ); + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "PyList_Append() failed" ); + } + Py_DECREF( val ); + } + } + + return list; +} + static PyObject *Material_getHaloSize( BPy_Material * self ) { return PyFloat_FromDouble( ( double ) self->material->hasize ); @@ -1982,6 +2018,57 @@ static int Material_setLightGroup( BPy_Material * self, PyObject * value ) return GenericLib_assignData(value, (void **) &self->material->group, NULL, 1, ID_GR, 0); } +static int Material_setTexChannel( BPy_Material * self, PyObject * value ) +{ + int i, mask; + short septex = 0; + int result = 1; + + /* fail if input is not a standard sequence */ + if( !PyList_Check( value ) && !PyTuple_Check( value ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected tuple or list of integers" ); + + /* get a fast sequence; in Python 2.5, this just return the original + * list or tuple and INCREFs it, so we must DECREF */ + value = PySequence_Fast( value, "" ); + + /* set the disable bit for each existing texture */ + for( i= 0, mask= 1; i < MAX_MTEX; ++i, mask <<= 1 ) + if( self->material->mtex[i] != NULL ) + septex |= mask; + + /* check the list, and build new septex value */ + for( i= PySequence_Size(value)-1; i >= 0; --i ) { + long ival; + PyObject *item = PySequence_Fast_GET_ITEM( value, i ); + if( !PyInt_Check( item ) ) { + PyErr_SetString ( PyExc_TypeError, + "expected tuple or list of integers" ); + goto exit; + } + ival= PyInt_AsLong( item ); + if(ival < 0 || ival > MAX_MTEX) { + PyErr_SetString( PyExc_ValueError, + "channel value out of range" ); + goto exit; + } + ival&= (1<<MAX_MTEX)-1; + if( self->material->mtex[(int)ival] == NULL ) { + PyErr_SetString( PyExc_ValueError, + "channels must have a texture assigned" ); + goto exit; + } + septex&= ~(1<<ival); + } + self->material->septex= septex; + result = 0; + +exit: + Py_DECREF(value); + return result; +} + static int Material_setAdd( BPy_Material * self, PyObject * value ) { return EXPP_setFloatClamped ( value, &self->material->add, @@ -2313,9 +2400,6 @@ static int Material_setSssBack( BPy_Material * self, PyObject * value ) EXPP_MAT_SSS_BACK_MAX); } - - - static PyObject *Material_setTexture( BPy_Material * self, PyObject * args ) { int texnum; diff --git a/source/blender/python/api2_2x/Mesh.c b/source/blender/python/api2_2x/Mesh.c index 9f68287d658..b3e8fefdb7b 100644 --- a/source/blender/python/api2_2x/Mesh.c +++ b/source/blender/python/api2_2x/Mesh.c @@ -5381,11 +5381,11 @@ static PyObject *MFaceSeq_delete( BPy_MFaceSeq * self, PyObject *args ) if( PySequence_Size( args ) != 2 || !PyArg_ParseTuple( args, "iO", &edge_also, &args ) ) return EXPP_ReturnPyObjError( PyExc_TypeError, - "expected and int and a sequence of ints or MFaces" ); + "expected an int and a sequence of ints or MFaces" ); if( !PyList_Check( args ) && !PyTuple_Check( args ) ) return EXPP_ReturnPyObjError( PyExc_TypeError, - "expected and int and a sequence of ints or MFaces" ); + "expected an int and a sequence of ints or MFaces" ); /* see how many args we need to parse */ len = PySequence_Size( args ); diff --git a/source/blender/python/api2_2x/Object.c b/source/blender/python/api2_2x/Object.c index 45cce46d389..dc70921492c 100644 --- a/source/blender/python/api2_2x/Object.c +++ b/source/blender/python/api2_2x/Object.c @@ -204,6 +204,7 @@ enum obj_consts { EXPP_OBJ_ATTR_SB_INSPRING, EXPP_OBJ_ATTR_SB_INFRICT, + EXPP_OBJ_ATTR_EMPTY_DRAWTYPE }; #define EXPP_OBJECT_DRAWSIZEMIN 0.01f @@ -2431,6 +2432,12 @@ static int Object_setDrawType( BPy_Object * self, PyObject * value ) OB_BOUNDBOX, OB_TEXTURE, 'b' ); } +static int Object_setEmptyShape( BPy_Object * self, PyObject * value ) +{ + return EXPP_setIValueRange( value, &self->object->empty_drawtype, + OB_ARROWS, OB_EMPTY_CONE, 'b' ); +} + static int Object_setEuler( BPy_Object * self, PyObject * args ) { float rot1, rot2, rot3; @@ -3758,6 +3765,9 @@ static PyObject *getIntAttr( BPy_Object *self, void *type ) case EXPP_OBJ_ATTR_DRAWTYPE: param = object->dt; break; + case EXPP_OBJ_ATTR_EMPTY_DRAWTYPE: + param = object->empty_drawtype; + break; case EXPP_OBJ_ATTR_PARENT_TYPE: param = object->partype; break; @@ -4938,6 +4948,10 @@ static PyGetSetDef BPy_Object_getseters[] = { (getter)getIntAttr, (setter)Object_setDrawType, "The object's drawing type", (void *)EXPP_OBJ_ATTR_DRAWTYPE}, + {"emptyShape", + (getter)getIntAttr, (setter)Object_setEmptyShape, + "The empty's drawing shape", + (void *)EXPP_OBJ_ATTR_EMPTY_DRAWTYPE}, {"parentType", (getter)getIntAttr, (setter)NULL, "The object's parent type", @@ -5538,6 +5552,24 @@ static PyObject *M_Object_IpoKeyTypesDict( void ) return M; } +static PyObject *M_Object_EmptyShapesDict( void ) +{ + PyObject *M = PyConstant_New( ); + + if( M ) { + BPy_constant *d = ( BPy_constant * ) M; + PyConstant_Insert( d, "ARROWS", PyInt_FromLong( OB_ARROWS ) ); + PyConstant_Insert( d, "AXES", PyInt_FromLong( OB_PLAINAXES ) ); + PyConstant_Insert( d, "CIRCLE", PyInt_FromLong( OB_CIRCLE ) ); + PyConstant_Insert( d, "ARROW", PyInt_FromLong( OB_SINGLE_ARROW ) ); + PyConstant_Insert( d, "CUBE", PyInt_FromLong( OB_CUBE ) ); + PyConstant_Insert( d, "SPHERE", PyInt_FromLong( OB_EMPTY_SPHERE ) ); + PyConstant_Insert( d, "CONE", PyInt_FromLong( OB_EMPTY_CONE ) ); + } + return M; +} + + /*****************************************************************************/ /* Function: initObject */ /*****************************************************************************/ @@ -5552,6 +5584,7 @@ PyObject *Object_Init( void ) PyObject *RBFlagsDict = M_Object_RBFlagsDict( ); PyObject *RBShapesDict = M_Object_RBShapeBoundDict( ); PyObject *IpoKeyTypesDict = M_Object_IpoKeyTypesDict( ); + PyObject *EmptyShapesDict = M_Object_EmptyShapesDict( ); PyType_Ready( &Object_Type ) ; @@ -5596,7 +5629,9 @@ PyObject *Object_Init( void ) if( RBShapesDict ) PyModule_AddObject( module, "RBShapes", RBShapesDict ); if( IpoKeyTypesDict ) - PyModule_AddObject( module, "IpoKeyTypes", IpoKeyTypesDict ); + PyModule_AddObject( module, "IpoKeyTypes", IpoKeyTypesDict ); + if( EmptyShapesDict ) + PyModule_AddObject( module, "EmptyShapes", EmptyShapesDict ); /*Add SUBMODULES to the module*/ dict = PyModule_GetDict( module ); /*borrowed*/ diff --git a/source/blender/python/api2_2x/doc/Material.py b/source/blender/python/api2_2x/doc/Material.py index a3496164cd1..02f7edd77f5 100644 --- a/source/blender/python/api2_2x/doc/Material.py +++ b/source/blender/python/api2_2x/doc/Material.py @@ -323,6 +323,21 @@ class Material: each color a list of 5 floats [0 - 1], [r,g,b,a,pos]. The colorband can have between 1 and 31 colors. @type colorbandSpecular: list + @type enabledTextures: list of integers + @ivar enabledTextures: The texture channels enabled in this material. + The attribute returns is list of integers in the range [0, 9], each + number representing the respective enabled MTex entry (see + L{getTextures()<getTextures>}). Enabling is done by assigning + a list of ints or an empty list. Attempting to enable a channel + which does not have a texture assigned to it will result in a + ValueError exception. + Example:: + mat.enabledTextures = [] # no texture channels are enabled + mat.enabledTextures = [0, 6] # texture channels 0 and 6 are enabled + ch = mat.enabledTextures + ch.append(4) + mat.enabledTextures = ch + print mat.enabledTextures # will print: [0, 4, 6] @ivar enableSSS: If True, subsurface scattering will be rendered on this material. @type enableSSS: bool @@ -1010,7 +1025,7 @@ class Material: def setTexture(index, texture, texco, mapto): """ - Assign a Blender Texture object to slot number 'number'. + Assign a Blender Texture object to channel number 'number'. @type index: int @param index: material's texture index in [0, 9]. @type texture: Blender Texture @@ -1033,7 +1048,7 @@ class Material: Get this Material's Texture list. @rtype: list of MTex @return: a list of Blender MTex objects. None is returned for each empty - texture slot. + texture channel. """ def getScriptLinks (event): diff --git a/source/blender/python/api2_2x/doc/Object.py b/source/blender/python/api2_2x/doc/Object.py index 2e4850aeb14..07942d58093 100644 --- a/source/blender/python/api2_2x/doc/Object.py +++ b/source/blender/python/api2_2x/doc/Object.py @@ -117,6 +117,10 @@ Example:: attribute. Only one type can be selected at a time. Values are BOX, SPHERE, CYLINDER, CONE, and POLYHEDERON +@type EmptyShapes: readonly dictionary +@var EmptyShapes: Constant dict used for with L{Object.emptyShape} attribute. + Only one type can be selected at a time. Values are + ARROW, ARROWS, AXES, CIRCLE, CONE, CUBE AND SPHERE """ def New (type, name='type'): @@ -347,7 +351,7 @@ class Object: ob.layers = [] # object won't be visible ob.layers = [1, 4] # object visible only in layers 1 and 4 ls = o.layers - ls.append([10]) + ls.append(10) o.layers = ls print ob.layers # will print: [1, 4, 10] B{Note}: changes will only be visible after the screen (at least @@ -525,6 +529,8 @@ class Object: @ivar drawType: The object's drawing type. See L{DrawTypes} constant dict for values. @type drawType: int + @ivar emptyShape: The empty drawing shape. + See L{EmptyShapes} constant dict for values. @ivar parentType: The object's parent type. Read-only. See L{ParentTypes} constant dict for values. @type parentType: int diff --git a/source/blender/src/buttons_object.c b/source/blender/src/buttons_object.c index 132bae8b7b8..78f19ad0608 100644 --- a/source/blender/src/buttons_object.c +++ b/source/blender/src/buttons_object.c @@ -3320,6 +3320,8 @@ static void object_panel_collision(Object *ob) uiDefBut(block, LABEL, 0, "",160,160,150,2, NULL, 0.0, 0, 0, 0, ""); if(pd->deflect) { + CollisionModifierData *collmd = (CollisionModifierData *)modifiers_findByType ( ob, eModifierType_Collision ); + uiDefBut(block, LABEL, 0, "Particle Interaction", 10,135,310,20, NULL, 0.0, 0, 0, 0, ""); uiBlockBeginAlign(block); @@ -3335,12 +3337,18 @@ static void object_panel_collision(Object *ob) uiDefBut(block, LABEL, 0, "Soft Body and Cloth Interaction", 10,65,310,20, NULL, 0.0, 0, 0, 0, ""); uiBlockBeginAlign(block); - uiDefButF(block, NUM, B_FIELD_CHANGE, "Damping:", 10,45,150,20, &pd->pdef_sbdamp, 0.0, 1.0, 10, 0, "Amount of damping during collision"); - uiDefButF(block, NUM, B_FIELD_CHANGE, "Inner:", 10,25,150,20, &pd->pdef_sbift, 0.001, 1.0, 10, 0, "Inner face thickness"); - uiDefButF(block, NUM, B_FIELD_CHANGE, "Outer:", 10, 5,150,20, &pd->pdef_sboft, 0.001, 1.0, 10, 0, "Outer face thickness"); + uiDefButF(block, NUM, B_FIELD_CHANGE, "Inner:", 10,45,150,20, &pd->pdef_sbift, 0.001, 1.0, 10, 0, "Inner face thickness"); + uiDefButF(block, NUM, B_FIELD_CHANGE, "Outer:", 160, 45,150,20, &pd->pdef_sboft, 0.001, 1.0, 10, 0, "Outer face thickness"); uiBlockEndAlign(block); + uiDefButF(block, NUM, B_FIELD_CHANGE, "Damping:", 10,25,150,20, &pd->pdef_sbdamp, 0.0, 1.0, 10, 0, "Amount of damping during collision"); - uiDefButBitS(block, TOG, OB_SB_COLLFINAL, B_FIELD_CHANGE, "Ev.M.Stack", 170,45,150,20, &ob->softflag, 0, 0, 0, 0, "Pick collision object from modifier stack (softbody only)"); + uiDefButBitS(block, TOG, OB_SB_COLLFINAL, B_FIELD_CHANGE, "Ev.M.Stack", 160,25,150,20, &ob->softflag, 0, 0, 0, 0, "Pick collision object from modifier stack (softbody only)"); + + // collision options + if(collmd) + { + uiDefButS(block, NUM, B_FIELD_CHANGE, "Absorption: ", 10,0,150,20, &collmd->absorption, 0.0, 100, 1, 2, "How much of effector force gets lost during collision with this object (in percent)."); + } } } } @@ -3350,6 +3358,7 @@ static void object_panel_fields(Object *ob) uiBut *but; int particles=0; static short actpsys=-1; + static char slot=0; block= uiNewBlock(&curarea->uiblocks, "object_panel_fields", UI_EMBOSS, UI_HELV, curarea->win); if(uiNewPanel(curarea, block, "Fields", "Physics", 0, 0, 318, 204)==0) return; @@ -3371,7 +3380,7 @@ static void object_panel_fields(Object *ob) char *tipstr="Choose field type"; uiBlockBeginAlign(block); - + if(ob->particlesystem.first) { ParticleSystem *psys; char *menustr2= psys_menu_string(ob,1); @@ -3383,8 +3392,16 @@ static void object_panel_fields(Object *ob) if(psys->part->pd==NULL) psys->part->pd= MEM_callocN(sizeof(PartDeflect), "PartDeflect"); - pd= psys->part->pd; + if(psys->part->pd2==NULL) + psys->part->pd2= MEM_callocN(sizeof(PartDeflect), "PartDeflect"); + + pd= ((slot==1) ? psys->part->pd2 : psys->part->pd); particles=1; + + uiDefButC(block, ROW, B_REDR, "", 10, 163, 14, 14, &slot, 3.0, 0, 0, 0, "Edit first particle effector slot"); + uiDefButC(block, ROW, B_REDR, "", 24, 163, 14, 14, &slot, 3.0, 1, 0, 0, "Edit second particle effector slot"); + uiBlockEndAlign(block); + uiBlockBeginAlign(block); } else actpsys= -1; /* -1 = object */ @@ -3397,8 +3414,8 @@ static void object_panel_fields(Object *ob) /* setup menu button */ if(particles){ - sprintf(menustr, "Field Type%%t|None%%x0|Spherical%%x%d|Wind%%x%d|Vortex%%x%d|Magnetic%%x%d|Harmonic%%x%d", - PFIELD_FORCE, PFIELD_WIND, PFIELD_VORTEX, PFIELD_MAGNET, PFIELD_HARMONIC); + sprintf(menustr, "Field Type%%t|None%%x0|Spherical%%x%d|Wind%%x%d|Vortex%%x%d|Magnetic%%x%d|Harmonic%%x%d|Charge%%x%d|Lennard-Jones%%x%d", + PFIELD_FORCE, PFIELD_WIND, PFIELD_VORTEX, PFIELD_MAGNET, PFIELD_HARMONIC, PFIELD_CHARGE, PFIELD_LENNARDJ); if(pd->forcefield==PFIELD_FORCE) tipstr= "Particle attracts or repels particles (On shared object layers)"; else if(pd->forcefield==PFIELD_WIND) tipstr= "Constant force applied in direction of particle Z axis (On shared object layers)"; @@ -3406,11 +3423,11 @@ static void object_panel_fields(Object *ob) } else{ if(ob->type==OB_CURVE) - sprintf(menustr, "Field Type%%t|None%%x0|Spherical%%x%d|Wind%%x%d|Vortex%%x%d|Curve Guide%%x%d|Magnetic%%x%d|Harmonic%%x%d|Texture%%x%d", - PFIELD_FORCE, PFIELD_WIND, PFIELD_VORTEX, PFIELD_GUIDE, PFIELD_MAGNET, PFIELD_HARMONIC, PFIELD_TEXTURE); + sprintf(menustr, "Field Type%%t|None%%x0|Spherical%%x%d|Wind%%x%d|Vortex%%x%d|Curve Guide%%x%d|Magnetic%%x%d|Harmonic%%x%d|Texture%%x%d|Charge%%x%d|Lennard-Jones%%x%d", + PFIELD_FORCE, PFIELD_WIND, PFIELD_VORTEX, PFIELD_GUIDE, PFIELD_MAGNET, PFIELD_HARMONIC, PFIELD_TEXTURE, PFIELD_CHARGE, PFIELD_LENNARDJ); else - sprintf(menustr, "Field Type%%t|None%%x0|Spherical%%x%d|Wind%%x%d|Vortex%%x%d|Magnetic%%x%d|Harmonic%%x%d|Texture%%x%d", - PFIELD_FORCE, PFIELD_WIND, PFIELD_VORTEX, PFIELD_MAGNET, PFIELD_HARMONIC, PFIELD_TEXTURE); + sprintf(menustr, "Field Type%%t|None%%x0|Spherical%%x%d|Wind%%x%d|Vortex%%x%d|Magnetic%%x%d|Harmonic%%x%d|Texture%%x%d|Charge%%x%d|Lennard-Jones%%x%d", + PFIELD_FORCE, PFIELD_WIND, PFIELD_VORTEX, PFIELD_MAGNET, PFIELD_HARMONIC, PFIELD_TEXTURE, PFIELD_CHARGE, PFIELD_LENNARDJ); if(pd->forcefield==PFIELD_FORCE) tipstr= "Object center attracts or repels particles (On shared object layers)"; else if(pd->forcefield==PFIELD_WIND) tipstr= "Constant force applied in direction of Object Z axis (On shared object layers)"; @@ -3425,8 +3442,6 @@ static void object_panel_fields(Object *ob) uiBlockEndAlign(block); uiDefBut(block, LABEL, 0, "",160,180,150,2, NULL, 0.0, 0, 0, 0, ""); - - MEM_freeN(menustr); if(pd->forcefield) { uiBlockBeginAlign(block); @@ -3492,40 +3507,49 @@ static void object_panel_fields(Object *ob) uiBlockEndAlign(block); } else{ - uiDefButS(block, MENU, B_FIELD_DEP, "Fall-off%t|Cone%x2|Tube%x1|Sphere%x0", 160,180,140,20, &pd->falloff, 0.0, 0.0, 0, 0, "Fall-off shape"); - if(pd->falloff==PFIELD_FALL_TUBE) - uiDefBut(block, LABEL, 0, "Longitudinal", 160,160,140,20, NULL, 0.0, 0, 0, 0, ""); - uiBlockBeginAlign(block); - uiDefButBitS(block, TOG, PFIELD_POSZ, B_FIELD_CHANGE, "Pos", 160,140,40,20, &pd->flag, 0.0, 0, 0, 0, "Effect only in direction of positive Z axis"); - uiDefButF(block, NUM, B_FIELD_CHANGE, "Fall-off: ", 200,140,100,20, &pd->f_power, 0, 10, 10, 0, "Falloff power (real gravitational falloff = 2)"); - uiDefButBitS(block, TOG, PFIELD_USEMAX, B_FIELD_CHANGE, "Use", 160,120,40,20, &pd->flag, 0.0, 0, 0, 0, "Use a maximum distance for the field to work"); - uiDefButF(block, NUM, B_FIELD_CHANGE, "MaxDist: ", 200,120,100,20, &pd->maxdist, 0, 1000.0, 10, 0, "Maximum distance for the field to work"); - uiDefButBitS(block, TOG, PFIELD_USEMIN, B_FIELD_CHANGE, "Use", 160,100,40,20, &pd->flag, 0.0, 0, 0, 0, "Use a minimum distance for the field's fall-off"); - uiDefButF(block, NUM, B_FIELD_CHANGE, "MinDist: ", 200,100,100,20, &pd->mindist, 0, 1000.0, 10, 0, "Minimum distance for the field's fall-off"); - uiBlockEndAlign(block); - - if(pd->falloff==PFIELD_FALL_TUBE){ - uiDefBut(block, LABEL, 0, "Radial", 160,80,70,20, NULL, 0.0, 0, 0, 0, ""); - uiBlockBeginAlign(block); - uiDefButF(block, NUM, B_FIELD_CHANGE, "Fall-off: ", 160,60,140,20, &pd->f_power_r, 0, 10, 10, 0, "Radial falloff power (real gravitational falloff = 2)"); - uiDefButBitS(block, TOG, PFIELD_USEMAXR, B_FIELD_CHANGE, "Use", 160,40,40,20, &pd->flag, 0.0, 0, 0, 0, "Use a maximum radial distance for the field to work"); - uiDefButF(block, NUM, B_FIELD_CHANGE, "MaxDist: ", 200,40,100,20, &pd->maxrad, 0, 1000.0, 10, 0, "Maximum radial distance for the field to work"); - uiDefButBitS(block, TOG, PFIELD_USEMINR, B_FIELD_CHANGE, "Use", 160,20,40,20, &pd->flag, 0.0, 0, 0, 0, "Use a minimum radial distance for the field's fall-off"); - uiDefButF(block, NUM, B_FIELD_CHANGE, "MinDist: ", 200,20,100,20, &pd->minrad, 0, 1000.0, 10, 0, "Minimum radial distance for the field's fall-off"); - uiBlockEndAlign(block); + if(pd->forcefield==PFIELD_LENNARDJ) { + uiDefBut(block, LABEL, 0, "Fall-off determined", 160,140,140,20, NULL, 0.0, 0, 0, 0, ""); + uiDefBut(block, LABEL, 0, "by particle sizes", 160,120,140,20, NULL, 0.0, 0, 0, 0, ""); } - else if(pd->falloff==PFIELD_FALL_CONE){ - uiDefBut(block, LABEL, 0, "Angular", 160,80,70,20, NULL, 0.0, 0, 0, 0, ""); + else { + uiDefButS(block, MENU, B_FIELD_DEP, "Fall-off%t|Cone%x2|Tube%x1|Sphere%x0", 160,180,140,20, &pd->falloff, 0.0, 0.0, 0, 0, "Fall-off shape"); + if(pd->falloff==PFIELD_FALL_TUBE) + uiDefBut(block, LABEL, 0, "Longitudinal", 160,160,140,20, NULL, 0.0, 0, 0, 0, ""); uiBlockBeginAlign(block); - uiDefButF(block, NUM, B_FIELD_CHANGE, "Fall-off: ", 160,60,140,20, &pd->f_power_r, 0, 10, 10, 0, "Radial falloff power (real gravitational falloff = 2)"); - uiDefButBitS(block, TOG, PFIELD_USEMAXR, B_FIELD_CHANGE, "Use", 160,40,40,20, &pd->flag, 0.0, 0, 0, 0, "Use a maximum angle for the field to work"); - uiDefButF(block, NUM, B_FIELD_CHANGE, "MaxAngle: ", 200,40,100,20, &pd->maxrad, 0, 89.0, 10, 0, "Maximum angle for the field to work (in radians)"); - uiDefButBitS(block, TOG, PFIELD_USEMINR, B_FIELD_CHANGE, "Use", 160,20,40,20, &pd->flag, 0.0, 0, 0, 0, "Use a minimum angle for the field's fall-off"); - uiDefButF(block, NUM, B_FIELD_CHANGE, "MinAngle: ", 200,20,100,20, &pd->minrad, 0, 89.0, 10, 0, "Minimum angle for the field's fall-off (in radians)"); + uiDefButBitS(block, TOG, PFIELD_POSZ, B_FIELD_CHANGE, "Pos", 160,140,40,20, &pd->flag, 0.0, 0, 0, 0, "Effect only in direction of positive Z axis"); + uiDefButF(block, NUM, B_FIELD_CHANGE, "Fall-off: ", 200,140,100,20, &pd->f_power, 0, 10, 10, 0, "Falloff power (real gravitational falloff = 2)"); + uiDefButBitS(block, TOG, PFIELD_USEMAX, B_FIELD_CHANGE, "Use", 160,120,40,20, &pd->flag, 0.0, 0, 0, 0, "Use a maximum distance for the field to work"); + uiDefButF(block, NUM, B_FIELD_CHANGE, "MaxDist: ", 200,120,100,20, &pd->maxdist, 0, 1000.0, 10, 0, "Maximum distance for the field to work"); + uiDefButBitS(block, TOG, PFIELD_USEMIN, B_FIELD_CHANGE, "Use", 160,100,40,20, &pd->flag, 0.0, 0, 0, 0, "Use a minimum distance for the field's fall-off"); + uiDefButF(block, NUM, B_FIELD_CHANGE, "MinDist: ", 200,100,100,20, &pd->mindist, 0, 1000.0, 10, 0, "Minimum distance for the field's fall-off"); uiBlockEndAlign(block); + + if(pd->falloff==PFIELD_FALL_TUBE){ + uiDefBut(block, LABEL, 0, "Radial", 160,80,70,20, NULL, 0.0, 0, 0, 0, ""); + uiBlockBeginAlign(block); + uiDefButF(block, NUM, B_FIELD_CHANGE, "Fall-off: ", 160,60,140,20, &pd->f_power_r, 0, 10, 10, 0, "Radial falloff power (real gravitational falloff = 2)"); + uiDefButBitS(block, TOG, PFIELD_USEMAXR, B_FIELD_CHANGE, "Use", 160,40,40,20, &pd->flag, 0.0, 0, 0, 0, "Use a maximum radial distance for the field to work"); + uiDefButF(block, NUM, B_FIELD_CHANGE, "MaxDist: ", 200,40,100,20, &pd->maxrad, 0, 1000.0, 10, 0, "Maximum radial distance for the field to work"); + uiDefButBitS(block, TOG, PFIELD_USEMINR, B_FIELD_CHANGE, "Use", 160,20,40,20, &pd->flag, 0.0, 0, 0, 0, "Use a minimum radial distance for the field's fall-off"); + uiDefButF(block, NUM, B_FIELD_CHANGE, "MinDist: ", 200,20,100,20, &pd->minrad, 0, 1000.0, 10, 0, "Minimum radial distance for the field's fall-off"); + uiBlockEndAlign(block); + } + else if(pd->falloff==PFIELD_FALL_CONE){ + uiDefBut(block, LABEL, 0, "Angular", 160,80,70,20, NULL, 0.0, 0, 0, 0, ""); + uiBlockBeginAlign(block); + uiDefButF(block, NUM, B_FIELD_CHANGE, "Fall-off: ", 160,60,140,20, &pd->f_power_r, 0, 10, 10, 0, "Radial falloff power (real gravitational falloff = 2)"); + uiDefButBitS(block, TOG, PFIELD_USEMAXR, B_FIELD_CHANGE, "Use", 160,40,40,20, &pd->flag, 0.0, 0, 0, 0, "Use a maximum angle for the field to work"); + uiDefButF(block, NUM, B_FIELD_CHANGE, "MaxAngle: ", 200,40,100,20, &pd->maxrad, 0, 89.0, 10, 0, "Maximum angle for the field to work (in radians)"); + uiDefButBitS(block, TOG, PFIELD_USEMINR, B_FIELD_CHANGE, "Use", 160,20,40,20, &pd->flag, 0.0, 0, 0, 0, "Use a minimum angle for the field's fall-off"); + uiDefButF(block, NUM, B_FIELD_CHANGE, "MinAngle: ", 200,20,100,20, &pd->minrad, 0, 89.0, 10, 0, "Minimum angle for the field's fall-off (in radians)"); + uiBlockEndAlign(block); + } } } + } + + MEM_freeN(menustr); } } @@ -4372,6 +4396,8 @@ static void object_panel_particle_extra(Object *ob) uiDefButBitI(block, TOG, PART_CHILD_EFFECT, B_PART_RECALC, "Children", butx+(butw*3)/5,buty,(butw*2)/5,buth, &part->flag, 0, 0, 0, 0, "Apply effectors to children"); uiBlockEndAlign(block); } + else if(part->phystype == PART_PHYS_NEWTON) + uiDefButBitI(block, TOG, PART_SELF_EFFECT, B_PART_RECALC, "Self Effect", butx,(buty-=buth),butw,buth, &part->flag, 0, 0, 0, 0, "Particle effectors effect themselves"); else buty-=buth; diff --git a/source/blender/src/drawipo.c b/source/blender/src/drawipo.c index 0e7476bbe82..71854570c8c 100644 --- a/source/blender/src/drawipo.c +++ b/source/blender/src/drawipo.c @@ -1212,16 +1212,9 @@ static void draw_ipovertices(int sel) /*}*/ } else { /* normal non bit curves */ if(ei->flag & IPO_EDIT) { - if(ei->icu->ipo==IPO_BEZ) { - /* Draw the editmode hendels for a bezier curve */ - if( (bezt->f1 & SELECT) == sel)/* && G.v2d->cur.xmin < bezt->vec[0][0] < G.v2d->cur.xmax)*/ - bglVertex3fv(bezt->vec[0]); - - if( (bezt->f3 & SELECT) == sel)/* && G.v2d->cur.xmin < bezt->vec[2][0] < G.v2d->cur.xmax)*/ - bglVertex3fv(bezt->vec[2]); - - } - + /* Only the vertex of the line, the + * handler are draw below. + */ if( (bezt->f2 & SELECT) == sel) /* && G.v2d->cur.xmin < bezt->vec[1][0] < G.v2d->cur.xmax)*/ bglVertex3fv(bezt->vec[1]); @@ -1237,6 +1230,45 @@ static void draw_ipovertices(int sel) bezt++; } bglEnd(); + + if (ei->flag & IPO_EDIT) { + /* Now draw the two vertex of the handler, + * need split it because we can't call glPointSize + * in the middle of a glBegin/glEnd also the + * bug comment before. + */ + a= ei->icu->totvert; + bezt= ei->icu->bezt; + + glPointSize(BIF_GetThemeValuef(TH_HANDLE_VERTEX_SIZE)); + + if(sel) BIF_ThemeColor(TH_HANDLE_VERTEX_SELECT); + else BIF_ThemeColor(TH_HANDLE_VERTEX); + + bglBegin(GL_POINTS); + + while(a--) { + if (ei->disptype!=IPO_DISPBITS) { + if(ei->flag & IPO_EDIT) { + if(ei->icu->ipo==IPO_BEZ) { + /* Draw the editmode hendels for a bezier curve */ + if( (bezt->f1 & SELECT) == sel)/* && G.v2d->cur.xmin < bezt->vec[0][0] < G.v2d->cur.xmax)*/ + bglVertex3fv(bezt->vec[0]); + + if( (bezt->f3 & SELECT) == sel)/* && G.v2d->cur.xmin < bezt->vec[2][0] < G.v2d->cur.xmax)*/ + bglVertex3fv(bezt->vec[2]); + } + } + } + bezt++; + } + bglEnd(); + + /* The color are always reset (see the while) + * but the point size not so we reset now. + */ + glPointSize(BIF_GetThemeValuef(TH_VERTEX_SIZE)); + } } } diff --git a/source/blender/src/editipo.c b/source/blender/src/editipo.c index 63c301658f2..cd6aefdb87c 100644 --- a/source/blender/src/editipo.c +++ b/source/blender/src/editipo.c @@ -462,24 +462,7 @@ static void make_part_editipo(SpaceIpo *si) name = getname_part_ei(part_ar[a]); strcpy(ei->name, name); ei->adrcode= part_ar[a]; - - //if(ei->adrcode & MA_MAP1) { - // ei->adrcode-= MA_MAP1; - // ei->adrcode |= texchannel_to_adrcode(si->channel); - //} - //else { - // if(ei->adrcode==MA_MODE) ei->disptype= IPO_DISPBITS; - //} - ei->col= ipo_rainbow(a, PART_TOTIPO); - - //len= strlen(ei->name); - //if(len) { - // if( ei->name[ len-1 ]=='R') ei->col= 0x5050FF; - // else if( ei->name[ len-1 ]=='G') ei->col= 0x50FF50; - // else if( ei->name[ len-1 ]=='B') ei->col= 0xFF7050; - //} - ei->icu= find_ipocurve(si->ipo, ei->adrcode); if(ei->icu) { ei->flag= ei->icu->flag; @@ -6011,4 +5994,4 @@ void move_to_frame(void) } } BIF_undo_push("Set frame to selected Ipo vertex"); -}
\ No newline at end of file +} diff --git a/source/blender/src/editipo_lib.c b/source/blender/src/editipo_lib.c index 7b3d439833e..e1e286e10cf 100644 --- a/source/blender/src/editipo_lib.c +++ b/source/blender/src/editipo_lib.c @@ -103,7 +103,8 @@ char *ic_name_empty[1] ={ "" }; char *fluidsim_ic_names[FLUIDSIM_TOTNAM] = { "Fac-Visc", "Fac-Time", "GravX","GravY","GravZ", "VelX","VelY","VelZ", "Active" }; char *part_ic_names[PART_TOTNAM] = { "E_Freq", "E_Life", "E_Speed", "E_Angular", "E_Size", "Angular", "Size", "Drag", "Brown", "Damp", "Length", "Clump", -"GravX", "GravY", "GravZ", "KinkAmp", "KinkFreq", "KinkShape", "BBTilt", "FStreng", "FFall", "FMaxD"}; +"GravX", "GravY", "GravZ", "KinkAmp", "KinkFreq", "KinkShape", "BBTilt", +"FStreng", "FFall", "FMaxD", "F2Streng", "F2Fall", "F2MaxD"}; /* gets the appropriate icon for the given blocktype */ int geticon_ipo_blocktype(short blocktype) diff --git a/source/blender/src/resources.c b/source/blender/src/resources.c index f47f14a605c..acd14aae7a5 100644 --- a/source/blender/src/resources.c +++ b/source/blender/src/resources.c @@ -313,7 +313,15 @@ char *BIF_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colorid) cp= ts->transition; break; case TH_SEQ_META: cp= ts->meta; break; - + case TH_HANDLE_VERTEX: + cp= ts->handle_vertex; + break; + case TH_HANDLE_VERTEX_SELECT: + cp= ts->handle_vertex_select; + break; + case TH_HANDLE_VERTEX_SIZE: + cp= &ts->handle_vertex_size; + break; } } @@ -493,6 +501,10 @@ void BIF_InitTheme(void) SETCOL(btheme->tipo.hilite, 0x60, 0xc0, 0x40, 255); btheme->tipo.vertex_size= 3; + SETCOL(btheme->tipo.handle_vertex, 0xff, 0x70, 0xff, 255); + SETCOL(btheme->tipo.handle_vertex_select, 0xff, 0xff, 0x70, 255); + btheme->tipo.handle_vertex_size= 3; + /* space file */ /* to have something initialized */ btheme->tfile= btheme->tv3d; @@ -684,7 +696,10 @@ char *BIF_ThemeColorsPup(int spacetype) str += sprintf(str, "Vertex %%x%d|", TH_VERTEX); str += sprintf(str, "Vertex Selected %%x%d|", TH_VERTEX_SELECT); str += sprintf(str, "Vertex Size %%x%d|", TH_VERTEX_SIZE); - str += sprintf(str, "Current Frame %%x%d", TH_CFRAME); + str += sprintf(str, "Current Frame %%x%d|", TH_CFRAME); + str += sprintf(str, "Handle Vertex %%x%d|", TH_HANDLE_VERTEX); + str += sprintf(str, "Handle Vertex Selected %%x%d|", TH_HANDLE_VERTEX_SELECT); + str += sprintf(str, "Handle Vertex Size %%x%d", TH_HANDLE_VERTEX_SIZE); break; case SPACE_FILE: str += sprintf(str, "Selected file %%x%d", TH_HILITE); diff --git a/source/blender/src/space.c b/source/blender/src/space.c index fb055216f7f..8787cf9efc4 100644 --- a/source/blender/src/space.c +++ b/source/blender/src/space.c @@ -3492,6 +3492,9 @@ static void info_user_themebuts(uiBlock *block, short y1, short y2, short y3, sh uiButSetFunc(but, set_userdef_iconfile_cb, &iconfileindex, NULL); } + else if(th_curcol==TH_HANDLE_VERTEX_SIZE) { + uiDefButC(block, NUMSLI, B_UPDATE_THEME,"Handle size ", 465,y3,200,20, col, 1.0, 10.0, 0, 0, ""); + } else { uiBlockBeginAlign(block); if ELEM9(th_curcol, TH_PANEL, TH_LAMP, TH_FACE, TH_FACE_SELECT, TH_EDITMESH_ACTIVE, TH_MENU_BACK, TH_MENU_HILITE, TH_MENU_ITEM, TH_NODE) { diff --git a/source/blender/src/usiblender.c b/source/blender/src/usiblender.c index 92e49ab29fa..15c2664a9d8 100644 --- a/source/blender/src/usiblender.c +++ b/source/blender/src/usiblender.c @@ -477,7 +477,15 @@ static void init_userdef_file(void) if ((G.main->versionfile < 245) || (G.main->versionfile == 245 && G.main->subversionfile < 16)) { U.flag |= USER_ADD_VIEWALIGNED|USER_ADD_EDITMODE; } - + if ((G.main->versionfile < 247) || (G.main->versionfile == 247 && G.main->subversionfile < 1)) { + bTheme *btheme; + for(btheme= U.themes.first; btheme; btheme= btheme->next) { + SETCOL(btheme->tipo.handle_vertex, 0xff, 0x70, 0xff, 255); + SETCOL(btheme->tipo.handle_vertex_select, 0xff, 0xff, 0x70, 255); + btheme->tipo.handle_vertex_size= 3; + } + } + /* GL Texture Garbage Collection (variable abused above!) */ if (U.textimeout == 0) { U.texcollectrate = 60; diff --git a/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp b/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp index 7de3056e382..16f8ae0095a 100644 --- a/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp +++ b/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp @@ -90,33 +90,10 @@ void update_for_newframe(); static BlendFileData *load_game_data(char *filename) { BlendReadError error; - //this doesn't work anymore for relative paths, so use BLO_read_from_memory instead - //BlendFileData *bfd= BLO_read_from_file(filename, &error); - FILE* file = fopen(filename,"rb"); - BlendFileData *bfd = 0; - if (file) - { - fseek(file, 0L, SEEK_END); - int len= ftell(file); - fseek(file, 0L, SEEK_SET); - char* filebuffer= new char[len];//MEM_mallocN(len, "text_buffer"); - int sizeread = fread(filebuffer,len,1,file); - if (sizeread==1){ - bfd = BLO_read_from_memory(filebuffer, len, &error); - } else { - error = BRE_UNABLE_TO_READ; - } - fclose(file); - // the memory is not released in BLO_read_from_memory, must do it here - delete filebuffer; - } else { - error = BRE_UNABLE_TO_OPEN; - } - + BlendFileData *bfd= BLO_read_from_file(filename, &error); if (!bfd) { printf("Loading %s failed: %s\n", filename, BLO_bre_as_string(error)); } - return bfd; } @@ -139,7 +116,9 @@ extern "C" void StartKetsjiShell(struct ScrArea *area, // Acquire Python's GIL (global interpreter lock) // so we can safely run Python code and API calls PyGILState_STATE gilstate = PyGILState_Ensure(); - + + PyObject *pyGlobalDict = PyDict_New(); /* python utility storage, spans blend file loading */ + bgl::InitExtensions(true); do @@ -333,6 +312,7 @@ extern "C" void StartKetsjiShell(struct ScrArea *area, initRasterizer(rasterizer, canvas); PyObject *gameLogic = initGameLogic(startscene); PyDict_SetItemString(dictionaryobject, "GameLogic", gameLogic); // Same as importing the module. + PyDict_SetItemString(PyModule_GetDict(gameLogic), "globalDict", pyGlobalDict); // Same as importing the module. initGameKeys(); initPythonConstraintBinding(); initMathutils(); @@ -407,6 +387,7 @@ extern "C" void StartKetsjiShell(struct ScrArea *area, // which allows the scene to safely delete them :) // see: (space.c)->start_game PyDict_Clear(PyModule_GetDict(gameLogic)); + PyDict_SetItemString(PyModule_GetDict(gameLogic), "globalDict", pyGlobalDict); ketsjiengine->StopEngine(); exitGamePythonScripting(); diff --git a/source/gameengine/GamePlayer/ghost/GPG_Application.cpp b/source/gameengine/GamePlayer/ghost/GPG_Application.cpp index 7be3b94d8ae..f859193ef7a 100644 --- a/source/gameengine/GamePlayer/ghost/GPG_Application.cpp +++ b/source/gameengine/GamePlayer/ghost/GPG_Application.cpp @@ -97,7 +97,7 @@ extern "C" #include "GHOST_IEventConsumer.h" #include "GHOST_IWindow.h" #include "GHOST_Rect.h" - +#include "marshal.h" static void frameTimerProc(GHOST_ITimerTask* task, GHOST_TUns64 time); @@ -125,7 +125,9 @@ GPG_Application::GPG_Application(GHOST_ISystem* system, struct Main* maggie, STR m_networkdevice(0), m_audiodevice(0), m_blendermat(0), - m_blenderglslmat(0) + m_blenderglslmat(0), + m_pyGlobalDictString(0), + m_pyGlobalDictString_Length(0) { fSystem = system; } @@ -645,14 +647,23 @@ bool GPG_Application::startEngine(void) PyObject* dictionaryobject = initGamePlayerPythonScripting("Ketsji", psl_Lowest); m_ketsjiengine->SetPythonDictionary(dictionaryobject); initRasterizer(m_rasterizer, m_canvas); - PyDict_SetItemString(dictionaryobject, "GameLogic", initGameLogic(startscene)); // Same as importing the module + PyObject *gameLogic = initGameLogic(startscene); + PyDict_SetItemString(dictionaryobject, "GameLogic", gameLogic); // Same as importing the module initGameKeys(); initPythonConstraintBinding(); initMathutils(); - - - + /* Restore the dict */ + if (m_pyGlobalDictString) { + PyObject* pyGlobalDict = PyMarshal_ReadObjectFromString(m_pyGlobalDictString, m_pyGlobalDictString_Length); + if (pyGlobalDict) { + PyDict_SetItemString(PyModule_GetDict(gameLogic), "globalDict", pyGlobalDict); // Same as importing the module. + } else { + PyErr_Clear(); + printf("Error could not marshall string\n"); + } + } + m_sceneconverter->ConvertScene( startscenename, startscene, @@ -688,6 +699,32 @@ bool GPG_Application::startEngine(void) void GPG_Application::stopEngine() { + // get the python dict and convert to a string for future use + { + SetPyGlobalDictMarshal(NULL, 0); + + PyObject* gameLogic = PyImport_ImportModule("GameLogic"); + if (gameLogic) { + PyObject* pyGlobalDict = PyDict_GetItemString(PyModule_GetDict(gameLogic), "globalDict"); // Same as importing the module + if (pyGlobalDict) { + PyObject* pyGlobalDictMarshal = PyMarshal_WriteObjectToString( pyGlobalDict, 2); // Py_MARSHAL_VERSION == 2 as of Py2.5 + if (pyGlobalDictMarshal) { + m_pyGlobalDictString_Length = PyString_Size(pyGlobalDictMarshal); + PyObject_Print(pyGlobalDictMarshal, stderr, 0); + m_pyGlobalDictString = static_cast<char *> (malloc(m_pyGlobalDictString_Length)); + memcpy(m_pyGlobalDictString, PyString_AsString(pyGlobalDictMarshal), m_pyGlobalDictString_Length); + } else { + printf("Error, GameLogic.globalDict could not be marshal'd\n"); + } + } else { + printf("Error, GameLogic.globalDict was removed\n"); + } + } else { + printf("Error, GameLogic failed to import GameLogic.globalDict will be lost\n"); + } + } + + // when exiting the mainloop exitGamePythonScripting(); m_ketsjiengine->StopEngine(); diff --git a/source/gameengine/GamePlayer/ghost/GPG_Application.h b/source/gameengine/GamePlayer/ghost/GPG_Application.h index 17f5add8b19..31f5eb75e52 100644 --- a/source/gameengine/GamePlayer/ghost/GPG_Application.h +++ b/source/gameengine/GamePlayer/ghost/GPG_Application.h @@ -72,6 +72,29 @@ public: bool StartGameEngine(int stereoMode); void StopGameEngine(); + char* + GetPyGlobalDictMarshal() + { + return m_pyGlobalDictString; + }; + + void + SetPyGlobalDictMarshal( char* pyGlobalDictString, int length ) + { + if (m_pyGlobalDictString && m_pyGlobalDictString != pyGlobalDictString) + free(m_pyGlobalDictString); + + m_pyGlobalDictString = pyGlobalDictString; + m_pyGlobalDictString_Length = length; + }; + + int + GetPyGlobalDictMarshalLength() + { + return m_pyGlobalDictString_Length; + }; + + protected: bool handleWheel(GHOST_IEvent* event); bool handleButton(GHOST_IEvent* event, bool isDown); @@ -142,6 +165,12 @@ protected: bool m_blendermat; bool m_blenderglslmat; - + + /* + * GameLogic.globalDict as a string so that loading new blend files can use the same dict. + * Do this because python starts/stops when loading blend files. + */ + char* m_pyGlobalDictString; + int m_pyGlobalDictString_Length; }; diff --git a/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp b/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp index 8222e5c8bac..26a85128025 100644 --- a/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp +++ b/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp @@ -293,7 +293,9 @@ int main(int argc, char** argv) GHOST_TUns32 fullScreenHeight= 0; int fullScreenBpp = 32; int fullScreenFrequency = 60; - + char* pyGlobalDictString = NULL; /* store python dict data between blend file loading */ + int pyGlobalDictString_Length = 0; + #ifdef __linux__ #ifdef __alpha__ signal (SIGFPE, SIG_IGN); @@ -625,6 +627,10 @@ int main(int argc, char** argv) titlename = maggie->name; + // Set the GameLogic.globalDict from marshal'd data, so we can load new blend files + // abd keep data in GameLogic.globalDict + app.SetPyGlobalDictMarshal(pyGlobalDictString, pyGlobalDictString_Length); + // Check whether the game should be displayed full-screen if ((!fullScreenParFound) && (!windowParFound)) { @@ -750,6 +756,12 @@ int main(int argc, char** argv) } } app.StopGameEngine(); + + // GameLogic.globalDict has been converted into a buffer + // store in pyGlobalDictString so we can restore after python has stopped and started. + pyGlobalDictString = app.GetPyGlobalDictMarshal(); + pyGlobalDictString_Length = app.GetPyGlobalDictMarshalLength(); + BLO_blendfiledata_free(bfd); #ifdef __APPLE__ @@ -772,6 +784,11 @@ int main(int argc, char** argv) } } + if (pyGlobalDictString) { + free(pyGlobalDictString); + pyGlobalDictString = NULL; + } + return error ? -1 : 0; } diff --git a/source/gameengine/Ketsji/KX_ConvertPhysicsObjects.cpp b/source/gameengine/Ketsji/KX_ConvertPhysicsObjects.cpp index e0cd5a3bc9e..d6997ee29a8 100644 --- a/source/gameengine/Ketsji/KX_ConvertPhysicsObjects.cpp +++ b/source/gameengine/Ketsji/KX_ConvertPhysicsObjects.cpp @@ -680,188 +680,6 @@ void KX_ConvertODEEngineObject(KX_GameObject* gameobj, // forward declarations -static btCollisionShape* CreateBulletShapeFromMesh(RAS_MeshObject* meshobj, bool polytope) -{ - if (!meshobj) - return 0; - - btCollisionShape* collisionMeshShape = 0; - btConvexHullShape* convexHullShape = 0; - btTriangleMeshShape* concaveShape = 0; - - btTriangleMesh* collisionMeshData = 0; - - //see if there is any polygons, if not, bail out. - - int numPoints = 0; - btVector3* points = 0; - - // Mesh has no polygons! - int numpolys = meshobj->NumPolygons(); - if (!numpolys) - { - return NULL; - } - - // Count the number of collision polygons and check they all come from the same - // vertex array - int numvalidpolys = 0; - int vtxarray = -1; - RAS_IPolyMaterial *poly_material = NULL; - bool reinstance = true; - - for (int p=0; p<numpolys; p++) - { - RAS_Polygon* poly = meshobj->GetPolygon(p); - - // only add polygons that have the collisionflag set - if (poly->IsCollider()) - { - // check polygon is from the same vertex array - if (poly->GetVertexIndexBase().m_vtxarray != vtxarray) - { - if (vtxarray < 0) - vtxarray = poly->GetVertexIndexBase().m_vtxarray; - else - { - reinstance = false; - vtxarray = -1; - } - } - - // check poly is from the same material - if (poly->GetMaterial()->GetPolyMaterial() != poly_material) - { - if (poly_material) - { - reinstance = false; - poly_material = NULL; - } - else - poly_material = poly->GetMaterial()->GetPolyMaterial(); - } - - // count the number of collision polys - numvalidpolys++; - - // We have one collision poly, and we can't reinstance, so we - // might as well break here. - if (!reinstance) - break; - } - } - - // No collision polygons - if (numvalidpolys < 1) - return NULL; - - - if (polytope) - { - convexHullShape = new btConvexHullShape(&points[0].getX(),numPoints); - collisionMeshShape = convexHullShape; - } else - { - collisionMeshData = new btTriangleMesh(); -// concaveShape = new btTriangleMeshShape(collisionMeshData); - //collisionMeshShape = concaveShape; - - } - - - numvalidpolys = 0; - - for (int p2=0; p2<numpolys; p2++) - { - RAS_Polygon* poly = meshobj->GetPolygon(p2); - - // only add polygons that have the collisionflag set - if (poly->IsCollider()) - { - //Bullet can raycast any shape, so - if (polytope) - { - for (int i=0;i<poly->VertexCount();i++) - { - const float* vtx = meshobj->GetVertex(poly->GetVertexIndexBase().m_vtxarray, - poly->GetVertexIndexBase().m_indexarray[i], - poly->GetMaterial()->GetPolyMaterial())->getLocalXYZ(); - btPoint3 point(vtx[0],vtx[1],vtx[2]); - convexHullShape->addPoint(point); - } - if (poly->VertexCount()) - numvalidpolys++; - - } else - { - { - const float* vtx = meshobj->GetVertex(poly->GetVertexIndexBase().m_vtxarray, - poly->GetVertexIndexBase().m_indexarray[2], - poly->GetMaterial()->GetPolyMaterial())->getLocalXYZ(); - btPoint3 vertex0(vtx[0],vtx[1],vtx[2]); - vtx = meshobj->GetVertex(poly->GetVertexIndexBase().m_vtxarray, - poly->GetVertexIndexBase().m_indexarray[1], - poly->GetMaterial()->GetPolyMaterial())->getLocalXYZ(); - btPoint3 vertex1(vtx[0],vtx[1],vtx[2]); - vtx = meshobj->GetVertex(poly->GetVertexIndexBase().m_vtxarray, - poly->GetVertexIndexBase().m_indexarray[0], - poly->GetMaterial()->GetPolyMaterial())->getLocalXYZ(); - btPoint3 vertex2(vtx[0],vtx[1],vtx[2]); - collisionMeshData->addTriangle(vertex0,vertex1,vertex2); - numvalidpolys++; - } - if (poly->VertexCount() == 4) - { - const float* vtx = meshobj->GetVertex(poly->GetVertexIndexBase().m_vtxarray, - poly->GetVertexIndexBase().m_indexarray[3], - poly->GetMaterial()->GetPolyMaterial())->getLocalXYZ(); - btPoint3 vertex0(vtx[0],vtx[1],vtx[2]); - vtx = meshobj->GetVertex(poly->GetVertexIndexBase().m_vtxarray, - poly->GetVertexIndexBase().m_indexarray[2], - poly->GetMaterial()->GetPolyMaterial())->getLocalXYZ(); - btPoint3 vertex1(vtx[0],vtx[1],vtx[2]); - vtx = meshobj->GetVertex(poly->GetVertexIndexBase().m_vtxarray, - poly->GetVertexIndexBase().m_indexarray[0], - poly->GetMaterial()->GetPolyMaterial())->getLocalXYZ(); - btPoint3 vertex2(vtx[0],vtx[1],vtx[2]); - collisionMeshData->addTriangle(vertex0,vertex1,vertex2); - numvalidpolys++; - } - - } - } - } - - - - if (numvalidpolys > 0) - { - - if (!polytope) - { - bool useQuantization = true; - concaveShape = new btBvhTriangleMeshShape( collisionMeshData, useQuantization ); - //concaveShape = new btTriangleMeshShape( collisionMeshData ); - - concaveShape->recalcLocalAabb(); - if (collisionMeshShape) - delete collisionMeshShape; - collisionMeshShape = concaveShape; - - } - - - - return collisionMeshShape; - } - if (collisionMeshShape) - delete collisionMeshShape; - if (collisionMeshData) - delete collisionMeshData; - return NULL; - -} - void KX_ConvertBulletObject( class KX_GameObject* gameobj, class RAS_MeshObject* meshobj, @@ -878,6 +696,7 @@ void KX_ConvertBulletObject( class KX_GameObject* gameobj, bool isbulletdyna = false; CcdConstructionInfo ci; class PHY_IMotionState* motionstate = new KX_MotionState(gameobj->GetSGNode()); + class CcdShapeConstructionInfo *shapeInfo = new CcdShapeConstructionInfo(); @@ -894,120 +713,80 @@ void KX_ConvertBulletObject( class KX_GameObject* gameobj, ci.m_gravity = btVector3(0,0,0); ci.m_localInertiaTensor =btVector3(0,0,0); ci.m_mass = objprop->m_dyna ? shapeprops->m_mass : 0.f; + shapeInfo->m_radius = objprop->m_radius; isbulletdyna = objprop->m_dyna; ci.m_localInertiaTensor = btVector3(ci.m_mass/3.f,ci.m_mass/3.f,ci.m_mass/3.f); - btTransform trans; - trans.setIdentity(); - btCollisionShape* bm = 0; switch (objprop->m_boundclass) { case KX_BOUNDSPHERE: { - float radius = objprop->m_radius; - btVector3 inertiaHalfExtents ( - radius, - radius, - radius); + //float radius = objprop->m_radius; + //btVector3 inertiaHalfExtents ( + // radius, + // radius, + // radius); //blender doesn't support multisphere, but for testing: //bm = new MultiSphereShape(inertiaHalfExtents,,&trans.getOrigin(),&radius,1); - bm = new btSphereShape(objprop->m_radius); - bm->calculateLocalInertia(ci.m_mass,ci.m_localInertiaTensor); + shapeInfo->m_shapeType = PHY_SHAPE_SPHERE; + bm = shapeInfo->CreateBulletShape(); break; }; case KX_BOUNDBOX: { - MT_Vector3 halfExtents ( + shapeInfo->m_halfExtend.setValue( objprop->m_boundobject.box.m_extends[0], - objprop->m_boundobject.box.m_extends[1], - objprop->m_boundobject.box.m_extends[2]); - - halfExtents /= 2.f; - - //btVector3 he (halfExtents[0]-CONVEX_DISTANCE_MARGIN ,halfExtents[1]-CONVEX_DISTANCE_MARGIN ,halfExtents[2]-CONVEX_DISTANCE_MARGIN ); - //he = he.absolute(); - - btVector3 he (halfExtents[0],halfExtents[1],halfExtents[2]); - he = he.absolute(); - + objprop->m_boundobject.box.m_extends[1], + objprop->m_boundobject.box.m_extends[2]); - bm = new btBoxShape(he); - bm->calculateLocalInertia(ci.m_mass,ci.m_localInertiaTensor); + shapeInfo->m_halfExtend /= 2.0; + shapeInfo->m_halfExtend = shapeInfo->m_halfExtend.absolute(); + shapeInfo->m_shapeType = PHY_SHAPE_BOX; + bm = shapeInfo->CreateBulletShape(); break; }; case KX_BOUNDCYLINDER: { - btVector3 halfExtents ( + shapeInfo->m_halfExtend.setValue( objprop->m_boundobject.c.m_radius, objprop->m_boundobject.c.m_radius, objprop->m_boundobject.c.m_height * 0.5f ); - bm = new btCylinderShapeZ(halfExtents); - bm->calculateLocalInertia(ci.m_mass,ci.m_localInertiaTensor); - + shapeInfo->m_shapeType = PHY_SHAPE_CYLINDER; + bm = shapeInfo->CreateBulletShape(); break; } - case KX_BOUNDCONE: + case KX_BOUNDCONE: { - btVector3 halfExtents (objprop->m_boundobject.box.m_extends[0], - objprop->m_boundobject.box.m_extends[1], - objprop->m_boundobject.box.m_extends[2]); - - - halfExtents /= 2.f; - - bm = new btConeShapeZ(objprop->m_boundobject.c.m_radius,objprop->m_boundobject.c.m_height); - bm->calculateLocalInertia(ci.m_mass,ci.m_localInertiaTensor); - + shapeInfo->m_radius = objprop->m_boundobject.c.m_radius; + shapeInfo->m_height = objprop->m_boundobject.c.m_height; + shapeInfo->m_shapeType = PHY_SHAPE_CONE; + bm = shapeInfo->CreateBulletShape(); break; } - case KX_BOUNDPOLYTOPE: - { - bm = CreateBulletShapeFromMesh(meshobj,true); - if (bm) - { - bm->calculateLocalInertia(ci.m_mass,ci.m_localInertiaTensor); - } - break; - } - case KX_BOUNDMESH: - { - if (!ci.m_mass) - { - bm = CreateBulletShapeFromMesh(meshobj,false); - ci.m_localInertiaTensor.setValue(0.f,0.f,0.f); - //no moving concave meshes, so don't bother calculating inertia - //bm->calculateLocalInertia(ci.m_mass,ci.m_localInertiaTensor); - } - - break; - } - - default: - //interpret the shape as a concave triangle-mesh + case KX_BOUNDPOLYTOPE: { - if (meshobj) - { - bm = CreateBulletShapeFromMesh(meshobj,false); - ci.m_localInertiaTensor.setValue(0.f,0.f,0.f); - - // assert(0); - - /* - meshobj->ScheduleCollisionPolygons(); - - KX_DeformableMesh* gfxmesh = new KX_DeformableMesh(meshobj); - gfxmesh->sendFixedMapping(); - //trianglemesh - bm = new TriangleMeshInterface(gfxmesh,trans); - */ + shapeInfo->SetMesh(meshobj, true); + bm = shapeInfo->CreateBulletShape(); + break; + } + case KX_BOUNDMESH: + { + if (!ci.m_mass) + { + shapeInfo->SetMesh(meshobj, false); + bm = shapeInfo->CreateBulletShape(); + //no moving concave meshes, so don't bother calculating inertia + //bm->calculateLocalInertia(ci.m_mass,ci.m_localInertiaTensor); } + + break; } } @@ -1017,44 +796,41 @@ void KX_ConvertBulletObject( class KX_GameObject* gameobj, if (!bm) { delete motionstate; + delete shapeInfo; return; } bm->setMargin(0.06); - if (objprop->m_isCompoundChild) { //find parent, compound shape and add to it //take relative transform into account! KX_BulletPhysicsController* parentCtrl = (KX_BulletPhysicsController*)objprop->m_dynamic_parent->GetPhysicsController(); assert(parentCtrl); + CcdShapeConstructionInfo* parentShapeInfo = parentCtrl->GetShapeInfo(); btRigidBody* rigidbody = parentCtrl->GetRigidBody(); btCollisionShape* colShape = rigidbody->getCollisionShape(); assert(colShape->isCompound()); btCompoundShape* compoundShape = (btCompoundShape*)colShape; - btTransform childTrans; - childTrans.setIdentity(); - NodeList& children = objprop->m_dynamic_parent->GetSGNode()->GetSGChildren(); MT_Point3 childPos = gameobj->GetSGNode()->GetLocalPosition(); MT_Matrix3x3 childRot = gameobj->GetSGNode()->GetLocalOrientation(); MT_Vector3 childScale = gameobj->GetSGNode()->GetLocalScale(); bm->setLocalScaling(btVector3(childScale.x(),childScale.y(),childScale.z())); - childTrans.setOrigin(btVector3(childPos.x(),childPos.y(),childPos.z())); + shapeInfo->m_childTrans.setOrigin(btVector3(childPos.x(),childPos.y(),childPos.z())); float rotval[12]; childRot.getValue(rotval); btMatrix3x3 newRot; newRot.setValue(rotval[0],rotval[1],rotval[2],rotval[4],rotval[5],rotval[6],rotval[8],rotval[9],rotval[10]); newRot = newRot.transpose(); - childTrans.setBasis(newRot); - - - compoundShape->addChildShape(childTrans,bm); - kxscene->AddShape(bm); + shapeInfo->m_childTrans.setBasis(newRot); + parentShapeInfo->AddShape(shapeInfo); + + compoundShape->addChildShape(shapeInfo->m_childTrans,bm); //do some recalc? //recalc inertia for rigidbody if (!rigidbody->isStaticOrKinematicObject()) @@ -1069,15 +845,16 @@ void KX_ConvertBulletObject( class KX_GameObject* gameobj, if (objprop->m_hasCompoundChildren) { - //replace shape by compoundShape + // create a compound shape info + CcdShapeConstructionInfo *compoundShapeInfo = new CcdShapeConstructionInfo(); + compoundShapeInfo->m_shapeType = PHY_SHAPE_COMPOUND; + compoundShapeInfo->AddShape(shapeInfo); + // create the compound shape manually as we already have the child shape btCompoundShape* compoundShape = new btCompoundShape(); - btTransform identTrans; - identTrans.setIdentity(); - compoundShape->addChildShape(identTrans,bm); - //note abount compoundShape: Bullet does not delete the child shapes when - //the compound shape is deleted, so insert also the child shapes - kxscene->AddShape(bm); + compoundShape->addChildShape(shapeInfo->m_childTrans,bm); + // now replace the shape bm = compoundShape; + shapeInfo = compoundShapeInfo; } @@ -1113,6 +890,7 @@ void KX_ConvertBulletObject( class KX_GameObject* gameobj, ci.m_collisionShape = bm; + ci.m_shapeInfo = shapeInfo; ci.m_friction = smmaterial->m_friction;//tweak the friction a bit, so the default 0.5 works nice ci.m_restitution = smmaterial->m_restitution; ci.m_physicsEnv = env; @@ -1124,9 +902,12 @@ void KX_ConvertBulletObject( class KX_GameObject* gameobj, ci.m_collisionFilterGroup = (isbulletdyna) ? short(CcdConstructionInfo::DefaultFilter) : short(CcdConstructionInfo::StaticFilter); ci.m_collisionFilterMask = (isbulletdyna) ? short(CcdConstructionInfo::AllFilter) : short(CcdConstructionInfo::AllFilter ^ CcdConstructionInfo::StaticFilter); ci.m_bRigid = objprop->m_dyna && objprop->m_angular_rigidbody; + MT_Vector3 scaling = gameobj->NodeGetWorldScaling(); + ci.m_scaling.setValue(scaling[0], scaling[1], scaling[2]); KX_BulletPhysicsController* physicscontroller = new KX_BulletPhysicsController(ci,isbulletdyna); - //remember that we created a shape so that we can delete it when the scene is removed (bullet will not delete it) - kxscene->AddShape(bm); + // shapeInfo is reference counted, decrement now as we don't use it anymore + if (shapeInfo) + shapeInfo->Release(); if (objprop->m_in_active_layer) { diff --git a/source/gameengine/Ketsji/KX_PythonInit.cpp b/source/gameengine/Ketsji/KX_PythonInit.cpp index 868439546c3..472ae759d65 100644 --- a/source/gameengine/Ketsji/KX_PythonInit.cpp +++ b/source/gameengine/Ketsji/KX_PythonInit.cpp @@ -733,6 +733,10 @@ PyObject* initGameLogic(KX_Scene* scene) // quick hack to get gravity hook // Add some symbolic constants to the module d = PyModule_GetDict(m); + + // can be overwritten later for gameEngine instances that can load new blend files and re-initialize this module + // for now its safe to make sure it exists for other areas such as the web plugin + PyDict_SetItemString(d, "globalDict", PyDict_New()); ErrorObject = PyString_FromString("GameLogic.error"); PyDict_SetItemString(d, "error", ErrorObject); diff --git a/source/gameengine/Ketsji/KX_Scene.cpp b/source/gameengine/Ketsji/KX_Scene.cpp index 2828663c63d..ab3692d2411 100644 --- a/source/gameengine/Ketsji/KX_Scene.cpp +++ b/source/gameengine/Ketsji/KX_Scene.cpp @@ -234,40 +234,9 @@ KX_Scene::~KX_Scene() { delete m_bucketmanager; } -#ifdef USE_BULLET - // This is a fix for memory leaks in bullet: the collision shapes is not destroyed - // when the physical controllers are destroyed. The reason is that shapes are shared - // between replicas of an object. There is no reference count in Bullet so the - // only workaround that does not involve changes in Bullet is to save in this array - // the list of shapes that are created when the scene is created (see KX_ConvertPhysicsObjects.cpp) - class btCollisionShape* shape; - class btTriangleMeshShape* meshShape; - vector<class btCollisionShape*>::iterator it = m_shapes.begin(); - while (it != m_shapes.end()) { - shape = *it; - if (shape->getShapeType() == TRIANGLE_MESH_SHAPE_PROXYTYPE) - { - meshShape = static_cast<btTriangleMeshShape*>(shape); - // shapes based on meshes use an interface that contains the vertices. - // Again the idea is to be able to share the interface between shapes but - // this is not used in Blender: each base object will have its own interface - btStridingMeshInterface* meshInterface = meshShape->getMeshInterface(); - if (meshInterface) - delete meshInterface; - } - delete shape; - it++; - } -#endif //Py_DECREF(m_attrlist); } -void KX_Scene::AddShape(class btCollisionShape*shape) -{ - m_shapes.push_back(shape); -} - - void KX_Scene::SetProjectionMatrix(MT_CmMatrix4x4& pmat) { m_projectionmat = pmat; diff --git a/source/gameengine/Ketsji/KX_Scene.h b/source/gameengine/Ketsji/KX_Scene.h index 80a2abe287a..1c56dd1ee55 100644 --- a/source/gameengine/Ketsji/KX_Scene.h +++ b/source/gameengine/Ketsji/KX_Scene.h @@ -122,11 +122,6 @@ protected: */ list<class KX_Camera*> m_cameras; /** - * The set of bullet shapes that must be deleted at the end of the scene - * to avoid memory leak (not deleted by bullet because shape are shared between replicas) - */ - vector<class btCollisionShape*> m_shapes; - /** * Various SCA managers used by the scene */ SCA_LogicManager* m_logicmgr; @@ -322,7 +317,6 @@ public: int NewRemoveObject(CValue* gameobj); void ReplaceMesh(CValue* gameobj, void* meshobj); - void AddShape(class btCollisionShape* shape); /** * @section Logic stuff * Initiate an update of the logic system. diff --git a/source/gameengine/Physics/Bullet/CcdPhysicsController.cpp b/source/gameengine/Physics/Bullet/CcdPhysicsController.cpp index b872fae6138..d6a32dfd9c0 100644 --- a/source/gameengine/Physics/Bullet/CcdPhysicsController.cpp +++ b/source/gameengine/Physics/Bullet/CcdPhysicsController.cpp @@ -18,6 +18,7 @@ subject to the following restrictions: #include "PHY_IMotionState.h" #include "CcdPhysicsEnvironment.h" +#include "RAS_MeshObject.h" class BP_Proxy; @@ -44,7 +45,18 @@ CcdPhysicsController::CcdPhysicsController (const CcdConstructionInfo& ci) m_newClientInfo = 0; m_registerCount = 0; + // copy pointers locally to allow smart release m_MotionState = ci.m_MotionState; + m_collisionShape = ci.m_collisionShape; + // apply scaling before creating rigid body + m_collisionShape->setLocalScaling(m_cci.m_scaling); + if (m_cci.m_mass) + m_collisionShape->calculateLocalInertia(m_cci.m_mass, m_cci.m_localInertiaTensor); + // shape info is shared, increment ref count + m_shapeInfo = ci.m_shapeInfo; + if (m_shapeInfo) + m_shapeInfo->AddRef(); + m_bulletMotionState = 0; @@ -116,7 +128,7 @@ void CcdPhysicsController::CreateRigidbody() m_body = new btRigidBody(m_cci.m_mass, m_bulletMotionState, - m_cci.m_collisionShape, + m_collisionShape, m_cci.m_localInertiaTensor * m_cci.m_inertiaFactor, m_cci.m_linearDamping,m_cci.m_angularDamping, m_cci.m_friction,m_cci.m_restitution); @@ -144,6 +156,19 @@ void CcdPhysicsController::CreateRigidbody() } } +static void DeleteBulletShape(btCollisionShape* shape) +{ + if (shape->getShapeType() == TRIANGLE_MESH_SHAPE_PROXYTYPE) + { + // shapes based on meshes use an interface that contains the vertices. + btTriangleMeshShape* meshShape = static_cast<btTriangleMeshShape*>(shape); + btStridingMeshInterface* meshInterface = meshShape->getMeshInterface(); + if (meshInterface) + delete meshInterface; + } + delete shape; +} + CcdPhysicsController::~CcdPhysicsController() { //will be reference counted, due to sharing @@ -155,6 +180,27 @@ CcdPhysicsController::~CcdPhysicsController() if (m_bulletMotionState) delete m_bulletMotionState; delete m_body; + + if (m_collisionShape) + { + // collision shape is always unique to the controller, can delete it here + if (m_collisionShape->isCompound()) + { + // bullet does not delete the child shape, must do it here + btCompoundShape* compoundShape = (btCompoundShape*)m_collisionShape; + int numChild = compoundShape->getNumChildShapes(); + for (int i=numChild-1 ; i >= 0; i--) + { + btCollisionShape* childShape = compoundShape->getChildShape(i); + DeleteBulletShape(childShape); + } + } + DeleteBulletShape(m_collisionShape); + } + if (m_shapeInfo) + { + m_shapeInfo->Release(); + } } @@ -219,11 +265,33 @@ void CcdPhysicsController::PostProcessReplica(class PHY_IMotionState* motionsta { m_MotionState = motionstate; m_registerCount = 0; - + m_collisionShape = NULL; + + // always create a new shape to avoid scaling bug + if (m_shapeInfo) + { + m_shapeInfo->AddRef(); + m_collisionShape = m_shapeInfo->CreateBulletShape(); + + if (m_collisionShape) + { + // new shape has no scaling, apply initial scaling + m_collisionShape->setLocalScaling(m_cci.m_scaling); + if (m_cci.m_mass) + m_collisionShape->calculateLocalInertia(m_cci.m_mass, m_cci.m_localInertiaTensor); + } + } m_body = 0; CreateRigidbody(); - + + if (m_body) + { + if (m_cci.m_mass) + { + m_body->setMassProps(m_cci.m_mass, m_cci.m_localInertiaTensor * m_cci.m_inertiaFactor); + } + } m_cci.m_physicsEnv->addCcdPhysicsController(this); @@ -597,29 +665,32 @@ bool CcdPhysicsController::wantsSleeping() PHY_IPhysicsController* CcdPhysicsController::GetReplica() { - //very experimental, shape sharing is not implemented yet. - //just support btSphereShape/ConeShape for now - + // This is used only to replicate Near and Radar sensor controllers + // The replication of object physics controller is done in KX_BulletPhysicsController::GetReplica() CcdConstructionInfo cinfo = m_cci; - if (cinfo.m_collisionShape) + if (m_shapeInfo) { - switch (cinfo.m_collisionShape->getShapeType()) + // This situation does not normally happen + cinfo.m_collisionShape = m_shapeInfo->CreateBulletShape(); + } + else if (m_collisionShape) + { + switch (m_collisionShape->getShapeType()) { case SPHERE_SHAPE_PROXYTYPE: { - btSphereShape* orgShape = (btSphereShape*)cinfo.m_collisionShape; + btSphereShape* orgShape = (btSphereShape*)m_collisionShape; cinfo.m_collisionShape = new btSphereShape(*orgShape); break; } - case CONE_SHAPE_PROXYTYPE: + case CONE_SHAPE_PROXYTYPE: { - btConeShape* orgShape = (btConeShape*)cinfo.m_collisionShape; + btConeShape* orgShape = (btConeShape*)m_collisionShape; cinfo.m_collisionShape = new btConeShape(*orgShape); break; } - default: { return 0; @@ -628,6 +699,7 @@ PHY_IPhysicsController* CcdPhysicsController::GetReplica() } cinfo.m_MotionState = new DefaultMotionState(); + cinfo.m_shapeInfo = m_shapeInfo; CcdPhysicsController* replica = new CcdPhysicsController(cinfo); return replica; @@ -689,3 +761,201 @@ void DefaultMotionState::calculateWorldTransformations() } +// Shape constructor +bool CcdShapeConstructionInfo::SetMesh(RAS_MeshObject* meshobj, bool polytope) +{ + // assume no shape information + m_shapeType = PHY_SHAPE_NONE; + m_vertexArray.clear(); + + if (!meshobj) + return false; + + // Mesh has no polygons! + int numpolys = meshobj->NumPolygons(); + if (!numpolys) + { + return false; + } + + // check that we have at least one colliding polygon + int numvalidpolys = 0; + + for (int p=0; p<numpolys; p++) + { + RAS_Polygon* poly = meshobj->GetPolygon(p); + + // only add polygons that have the collisionflag set + if (poly->IsCollider()) + { + numvalidpolys++; + break; + } + } + + // No collision polygons + if (numvalidpolys < 1) + return false; + + m_shapeType = (polytope) ? PHY_SHAPE_POLYTOPE : PHY_SHAPE_MESH; + + numvalidpolys = 0; + + for (int p2=0; p2<numpolys; p2++) + { + RAS_Polygon* poly = meshobj->GetPolygon(p2); + + // only add polygons that have the collisionflag set + if (poly->IsCollider()) + { + //Bullet can raycast any shape, so + if (polytope) + { + for (int i=0;i<poly->VertexCount();i++) + { + const float* vtx = meshobj->GetVertex(poly->GetVertexIndexBase().m_vtxarray, + poly->GetVertexIndexBase().m_indexarray[i], + poly->GetMaterial()->GetPolyMaterial())->getLocalXYZ(); + btPoint3 point(vtx[0],vtx[1],vtx[2]); + m_vertexArray.push_back(point); + numvalidpolys++; + } + } else + { + { + const float* vtx = meshobj->GetVertex(poly->GetVertexIndexBase().m_vtxarray, + poly->GetVertexIndexBase().m_indexarray[2], + poly->GetMaterial()->GetPolyMaterial())->getLocalXYZ(); + btPoint3 vertex0(vtx[0],vtx[1],vtx[2]); + vtx = meshobj->GetVertex(poly->GetVertexIndexBase().m_vtxarray, + poly->GetVertexIndexBase().m_indexarray[1], + poly->GetMaterial()->GetPolyMaterial())->getLocalXYZ(); + btPoint3 vertex1(vtx[0],vtx[1],vtx[2]); + vtx = meshobj->GetVertex(poly->GetVertexIndexBase().m_vtxarray, + poly->GetVertexIndexBase().m_indexarray[0], + poly->GetMaterial()->GetPolyMaterial())->getLocalXYZ(); + btPoint3 vertex2(vtx[0],vtx[1],vtx[2]); + m_vertexArray.push_back(vertex0); + m_vertexArray.push_back(vertex1); + m_vertexArray.push_back(vertex2); + numvalidpolys++; + } + if (poly->VertexCount() == 4) + { + const float* vtx = meshobj->GetVertex(poly->GetVertexIndexBase().m_vtxarray, + poly->GetVertexIndexBase().m_indexarray[3], + poly->GetMaterial()->GetPolyMaterial())->getLocalXYZ(); + btPoint3 vertex0(vtx[0],vtx[1],vtx[2]); + vtx = meshobj->GetVertex(poly->GetVertexIndexBase().m_vtxarray, + poly->GetVertexIndexBase().m_indexarray[2], + poly->GetMaterial()->GetPolyMaterial())->getLocalXYZ(); + btPoint3 vertex1(vtx[0],vtx[1],vtx[2]); + vtx = meshobj->GetVertex(poly->GetVertexIndexBase().m_vtxarray, + poly->GetVertexIndexBase().m_indexarray[0], + poly->GetMaterial()->GetPolyMaterial())->getLocalXYZ(); + btPoint3 vertex2(vtx[0],vtx[1],vtx[2]); + m_vertexArray.push_back(vertex0); + m_vertexArray.push_back(vertex1); + m_vertexArray.push_back(vertex2); + numvalidpolys++; + } + } + } + } + + if (!numvalidpolys) + { + // should not happen + m_shapeType = PHY_SHAPE_NONE; + return false; + } + return true; +} + +btCollisionShape* CcdShapeConstructionInfo::CreateBulletShape() +{ + btCollisionShape* collisionShape = 0; + btTriangleMeshShape* concaveShape = 0; + btTriangleMesh* collisionMeshData = 0; + btCompoundShape* compoundShape = 0; + CcdShapeConstructionInfo* nextShapeInfo; + + switch (m_shapeType) + { + case PHY_SHAPE_NONE: + break; + + case PHY_SHAPE_BOX: + collisionShape = new btBoxShape(m_halfExtend); + break; + + case PHY_SHAPE_SPHERE: + collisionShape = new btSphereShape(m_radius); + break; + + case PHY_SHAPE_CYLINDER: + collisionShape = new btCylinderShapeZ(m_halfExtend); + break; + + case PHY_SHAPE_CONE: + collisionShape = new btConeShapeZ(m_radius, m_height); + break; + + case PHY_SHAPE_POLYTOPE: + collisionShape = new btConvexHullShape(&m_vertexArray.begin()->getX(), m_vertexArray.size()); + break; + + case PHY_SHAPE_MESH: + collisionMeshData = new btTriangleMesh(); + // m_vertexArray is necessarily a multiple of 3 + for (std::vector<btPoint3>::iterator it=m_vertexArray.begin(); it != m_vertexArray.end(); ) + { + collisionMeshData->addTriangle(*it++,*it++,*it++); + } + concaveShape = new btBvhTriangleMeshShape( collisionMeshData, true ); + concaveShape->recalcLocalAabb(); + collisionShape = concaveShape; + break; + + case PHY_SHAPE_COMPOUND: + if (m_nextShape) + { + compoundShape = new btCompoundShape(); + for (nextShapeInfo=m_nextShape; nextShapeInfo; nextShapeInfo = nextShapeInfo->m_nextShape) + { + collisionShape = nextShapeInfo->CreateBulletShape(); + if (collisionShape) + { + compoundShape->addChildShape(nextShapeInfo->m_childTrans, collisionShape); + } + } + collisionShape = compoundShape; + } + } + return collisionShape; +} + +void CcdShapeConstructionInfo::AddShape(CcdShapeConstructionInfo* shapeInfo) +{ + CcdShapeConstructionInfo* nextShape = this; + while (nextShape->m_nextShape != NULL) + nextShape = nextShape->m_nextShape; + nextShape->m_nextShape = shapeInfo; +} + +CcdShapeConstructionInfo::~CcdShapeConstructionInfo() +{ + CcdShapeConstructionInfo* childShape = m_nextShape; + + while (childShape) + { + CcdShapeConstructionInfo* nextShape = childShape->m_nextShape; + childShape->m_nextShape = NULL; + childShape->Release(); + childShape = nextShape; + } + + m_vertexArray.clear(); +} + + diff --git a/source/gameengine/Physics/Bullet/CcdPhysicsController.h b/source/gameengine/Physics/Bullet/CcdPhysicsController.h index 448e5622eff..1e1a38aa2a6 100644 --- a/source/gameengine/Physics/Bullet/CcdPhysicsController.h +++ b/source/gameengine/Physics/Bullet/CcdPhysicsController.h @@ -17,11 +17,14 @@ subject to the following restrictions: #ifndef BULLET2_PHYSICSCONTROLLER_H #define BULLET2_PHYSICSCONTROLLER_H +#include <vector> + #include "PHY_IPhysicsController.h" /// PHY_IPhysicsController is the abstract simplified Interface to a physical object. /// It contains the IMotionState and IDeformableMesh Interfaces. #include "btBulletDynamicsCommon.h" +#include "LinearMath/btTransform.h" #include "PHY_IMotionState.h" @@ -31,8 +34,66 @@ extern float gAngularSleepingTreshold; extern bool gDisableDeactivation; class CcdPhysicsEnvironment; class btMotionState; +class RAS_MeshObject; +class btCollisionShape; + +// Shape contructor +// It contains all the information needed to create a simple bullet shape at runtime +class CcdShapeConstructionInfo +{ +public: + CcdShapeConstructionInfo() : + m_shapeType(PHY_SHAPE_NONE), + m_radius(1.0), + m_height(1.0), + m_halfExtend(0.f,0.f,0.f), + m_nextShape(NULL), + m_refCount(1) + { + m_childTrans.setIdentity(); + } + ~CcdShapeConstructionInfo(); + CcdShapeConstructionInfo* AddRef() + { + m_refCount++; + return this; + } + + int Release() + { + if (--m_refCount > 0) + return m_refCount; + delete this; + return 0; + } + + void AddShape(CcdShapeConstructionInfo* shapeInfo); + + CcdShapeConstructionInfo* GetNextShape() + { + return m_nextShape; + } + + bool SetMesh(RAS_MeshObject* mesh, bool polytope); + + btCollisionShape* CreateBulletShape(); + + // member variables + PHY_ShapeType m_shapeType; + btScalar m_radius; + btScalar m_height; + btVector3 m_halfExtend; + btTransform m_childTrans; + std::vector<btPoint3> m_vertexArray; // Contains both vertex array for polytope shape and + // triangle array for concave mesh shape. + // In this case a triangle is made of 3 consecutive points +protected: + CcdShapeConstructionInfo* m_nextShape; // for compound shape + int m_refCount; // this class is shared between replicas + // keep track of users so that we can release it +}; struct CcdConstructionInfo { @@ -65,6 +126,7 @@ struct CcdConstructionInfo m_collisionFilterMask(AllFilter), m_collisionShape(0), m_MotionState(0), + m_shapeInfo(0), m_physicsEnv(0), m_inertiaFactor(1.f) { @@ -89,8 +151,11 @@ struct CcdConstructionInfo short int m_collisionFilterGroup; short int m_collisionFilterMask; + ///these pointers are used as argument passing for the CcdPhysicsController constructor + ///and not anymore after that class btCollisionShape* m_collisionShape; class PHY_IMotionState* m_MotionState; + class CcdShapeConstructionInfo* m_shapeInfo; CcdPhysicsEnvironment* m_physicsEnv; //needed for self-replication float m_inertiaFactor;//tweak the inertia (hooked up to Blender 'formfactor' @@ -106,6 +171,9 @@ class CcdPhysicsController : public PHY_IPhysicsController btRigidBody* m_body; class PHY_IMotionState* m_MotionState; btMotionState* m_bulletMotionState; + class btCollisionShape* m_collisionShape; + class CcdShapeConstructionInfo* m_shapeInfo; + friend class CcdPhysicsEnvironment; // needed when updating the controller @@ -137,6 +205,7 @@ class CcdPhysicsController : public PHY_IPhysicsController btRigidBody* GetRigidBody() { return m_body;} + CcdShapeConstructionInfo* GetShapeInfo() { return m_shapeInfo; } btCollisionShape* GetCollisionShape() { return m_body->getCollisionShape(); diff --git a/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp b/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp index dfbcf115fd7..d8e05fab839 100644 --- a/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp +++ b/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp @@ -1370,8 +1370,9 @@ int CcdPhysicsEnvironment::createConstraint(class PHY_IPhysicsController* ctrl PHY_IPhysicsController* CcdPhysicsEnvironment::CreateConeController(float coneradius,float coneheight) { CcdConstructionInfo cinfo; - //This is a memory leak: Bullet does not delete the shape and it cannot be added to - //the KX_Scene.m_shapes list -- too bad but that's not a lot of data + + // we don't need a CcdShapeConstructionInfo for this shape: + // it is simple enough for the standard copy constructor (see CcdPhysicsController::GetReplica) cinfo.m_collisionShape = new btConeShape(coneradius,coneheight); cinfo.m_MotionState = 0; cinfo.m_physicsEnv = this; diff --git a/source/gameengine/Physics/Bullet/SConscript b/source/gameengine/Physics/Bullet/SConscript index dd6eab0f018..0936d45197a 100644 --- a/source/gameengine/Physics/Bullet/SConscript +++ b/source/gameengine/Physics/Bullet/SConscript @@ -3,7 +3,7 @@ Import ('env') sources = 'CcdPhysicsEnvironment.cpp CcdPhysicsController.cpp' -incs = '. ../common' +incs = '. ../common #source/kernel/gen_system #intern/string #intern/moto/include #source/gameengine/Rasterizer' incs += ' ' + env['BF_BULLET_INC'] diff --git a/source/gameengine/Physics/common/PHY_DynamicTypes.h b/source/gameengine/Physics/common/PHY_DynamicTypes.h index c289b9d8bcb..3b3e42c38d2 100644 --- a/source/gameengine/Physics/common/PHY_DynamicTypes.h +++ b/source/gameengine/Physics/common/PHY_DynamicTypes.h @@ -87,6 +87,18 @@ typedef enum PHY_ConstraintType { } PHY_ConstraintType; +typedef enum PHY_ShapeType { + PHY_SHAPE_NONE, + PHY_SHAPE_BOX, + PHY_SHAPE_SPHERE, + PHY_SHAPE_CYLINDER, + PHY_SHAPE_CONE, + PHY_SHAPE_MESH, + PHY_SHAPE_POLYTOPE, + PHY_SHAPE_COMPOUND +} PHY_ShapeType; + + typedef float PHY_Vector3[3]; #endif //__PHY_DYNAMIC_TYPES |