diff options
author | Ian Thompson <quornian@googlemail.com> | 2008-08-30 18:32:16 +0400 |
---|---|---|
committer | Ian Thompson <quornian@googlemail.com> | 2008-08-30 18:32:16 +0400 |
commit | 3bab89cc1c51e80e15efb4f5d751940ac06001a4 (patch) | |
tree | b8b97416afc2b71aa7715be1ea5ad71d202ae0ac /source | |
parent | bccce7e30e51b43d937f4982ad6d66222f8d961b (diff) |
Merge from trunk 16122-16307
Diffstat (limited to 'source')
204 files changed, 6091 insertions, 2069 deletions
diff --git a/source/Makefile b/source/Makefile index d06962cbe3f..91dd17d73dd 100644 --- a/source/Makefile +++ b/source/Makefile @@ -250,6 +250,7 @@ SPLIB += $(OCGDIR)/blender/readblenfile/$(DEBUG_DIR)libreadblenfile.a # but somehow it consistently fails to resolve these symbols... or # can I just not check them? nm claims they aren't... SPLIB += $(OCGDIR)/blender/blenkernel/blenkernel_blc/$(DEBUG_DIR)libblenkernel_blc.a +SPLIB += $(OCGDIR)/blender/python/$(DEBUG_DIR)libpython.a # These three need to be explicitly mentioned on the cl, because # if they are offered as a lib, they are optimized away. (nzc) 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_customdata.h b/source/blender/blenkernel/BKE_customdata.h index e84c7d30956..c84b690bc49 100644 --- a/source/blender/blenkernel/BKE_customdata.h +++ b/source/blender/blenkernel/BKE_customdata.h @@ -32,9 +32,11 @@ #ifndef BKE_CUSTOMDATA_H #define BKE_CUSTOMDATA_H +#include "BLO_sys_types.h" // for intptr_t support + struct CustomData; struct CustomDataLayer; -typedef long CustomDataMask; +typedef intptr_t CustomDataMask; extern const CustomDataMask CD_MASK_BAREMESH; extern const CustomDataMask CD_MASK_MESH; diff --git a/source/blender/blenkernel/BKE_deform.h b/source/blender/blenkernel/BKE_deform.h index a1975dd4265..e982806a6cc 100644 --- a/source/blender/blenkernel/BKE_deform.h +++ b/source/blender/blenkernel/BKE_deform.h @@ -38,6 +38,7 @@ struct Object; struct ListBase; struct bDeformGroup; +struct MDeformVert; void copy_defgroups (struct ListBase *lb1, struct ListBase *lb2); struct bDeformGroup *copy_defgroup (struct bDeformGroup *ingroup); @@ -46,5 +47,8 @@ int get_defgroup_num (struct Object *ob, struct bDeformGroup *dg); int get_named_vertexgroup_num (Object *ob, char *name); void unique_vertexgroup_name (struct bDeformGroup *dg, struct Object *ob); +float deformvert_get_weight(const struct MDeformVert *dvert, int group_num); +float vertexgroup_get_vertex_weight(const struct MDeformVert *dvert, int index, int group_num); + #endif diff --git a/source/blender/blenkernel/BKE_effect.h b/source/blender/blenkernel/BKE_effect.h index 3763a659f2f..6475f7a71ac 100644 --- a/source/blender/blenkernel/BKE_effect.h +++ b/source/blender/blenkernel/BKE_effect.h @@ -37,6 +37,7 @@ struct Effect; struct ListBase; struct Particle; struct Group; +struct RNG; typedef struct pEffectorCache { struct pEffectorCache *next, *prev; @@ -64,6 +65,11 @@ struct ListBase *pdInitEffectors(struct Object *obsrc, struct Group *group); 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(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); + + #endif diff --git a/source/blender/blenkernel/BKE_endian.h b/source/blender/blenkernel/BKE_endian.h index 1757103eaf6..dc5efd5ea46 100644 --- a/source/blender/blenkernel/BKE_endian.h +++ b/source/blender/blenkernel/BKE_endian.h @@ -33,11 +33,11 @@ #define BKE_ENDIANNESS(a) { \ union { \ - long l; \ - char c[sizeof (long)]; \ + intptr_t l; \ + char c[sizeof (intptr_t)]; \ } u; \ u.l = 1; \ - a = (u.c[sizeof (long) - 1] == 1) ? 1 : 0; \ + a = (u.c[sizeof (intptr_t) - 1] == 1) ? 1 : 0; \ } #endif diff --git a/source/blender/blenkernel/BKE_shrinkwrap.h b/source/blender/blenkernel/BKE_shrinkwrap.h new file mode 100644 index 00000000000..e8276238ff2 --- /dev/null +++ b/source/blender/blenkernel/BKE_shrinkwrap.h @@ -0,0 +1,146 @@ +/** + * BKE_shrinkwrap.h + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ +#ifndef BKE_SHRINKWRAP_H +#define BKE_SHRINKWRAP_H + +/* mesh util */ +//TODO: move this somewhere else +#include "BKE_customdata.h" +struct DerivedMesh; +struct Object; +struct DerivedMesh *object_get_derived_final(struct Object *ob, CustomDataMask dataMask); + + +/* SpaceTransform stuff */ +/* + * TODO: move this somewhere else + * + * this structs encapsulates all needed data to convert between 2 coordinate spaces + * (where conversion can be represented by a matrix multiplication) + * + * This is used to reduce the number of arguments to pass to functions that need to perform + * this kind of operation and make it easier for the coder, as he/she doenst needs to recode + * the matrix calculation. + * + * A SpaceTransform is initialized using: + * space_transform_setup( &data, ob1, ob2 ) + * + * After that the following calls can be used: + * space_transform_apply (&data, co); //converts a coordinate in ob1 coords space to the corresponding ob2 coords + * space_transform_invert(&data, co); //converts a coordinate in ob2 coords space to the corresponding ob1 coords + * + * //Same Concept as space_transform_apply and space_transform_invert, but no is normalized after conversion + * space_transform_apply_normal (&data, &no); + * space_transform_invert_normal(&data, &no); + * + */ +struct Object; + +typedef struct SpaceTransform +{ + float local2target[4][4]; + float target2local[4][4]; + +} SpaceTransform; + +void space_transform_from_matrixs(SpaceTransform *data, float local[][4], float target[][4]); +#define space_transform_setup(data, local, target) space_transform_from_matrixs(data, (local)->obmat, (target)->obmat) + +void space_transform_apply (const SpaceTransform *data, float *co); +void space_transform_invert(const SpaceTransform *data, float *co); + +void space_transform_apply_normal (const SpaceTransform *data, float *no); +void space_transform_invert_normal(const SpaceTransform *data, float *no); + +/* Shrinkwrap stuff */ +#include "BKE_bvhutils.h" + +/* + * Shrinkwrap is composed by a set of functions and options that define the type of shrink. + * + * 3 modes are available: + * - Nearest vertex + * - Nearest surface + * - Normal projection + * + * ShrinkwrapCalcData encapsulates all needed data for shrinkwrap functions. + * (So that you dont have to pass an enormous ammount of arguments to functions) + */ + +struct Object; +struct DerivedMesh; +struct ShrinkwrapModifierData; +struct BVHTree; + + +typedef struct ShrinkwrapCalcData +{ + ShrinkwrapModifierData *smd; //shrinkwrap modifier data + + struct Object *ob; //object we are applying shrinkwrap to + struct DerivedMesh *original; //mesh before shrinkwrap + + float (*vertexCos)[3]; //vertexs being shrinkwraped + int numVerts; + + struct DerivedMesh *target; //mesh we are shrinking to + SpaceTransform local2target; //transform to move bettwem local and target space + + float keepDist; //Distance to kept from target (units are in local space) + +} ShrinkwrapCalcData; + +void shrinkwrap_calc_nearest_vertex(ShrinkwrapCalcData *data); +void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *data); +void shrinkwrap_calc_nearest_surface_point(ShrinkwrapCalcData *data); + +void shrinkwrapModifier_deform(struct ShrinkwrapModifierData *smd, struct Object *ob, struct DerivedMesh *dm, float (*vertexCos)[3], int numVerts); + +/* + * This function casts a ray in the given BVHTree.. but it takes into consideration the space_transform, that is: + * + * if transf was configured with "space_transform_setup( &transf, ob1, ob2 )" + * then the input (vert, dir, BVHTreeRayHit) must be defined in ob1 coordinates space + * and the BVHTree must be built in ob2 coordinate space. + * + * Thus it provides an easy way to cast the same ray across several trees (where each tree was built on its own coords space) + */ +int normal_projection_project_vertex(char options, const float *vert, const float *dir, const SpaceTransform *transf, BVHTree *tree, BVHTreeRayHit *hit, BVHTree_RayCastCallback callback, void *userdata); + +/* + * NULL initializers to local data + */ +#define NULL_ShrinkwrapCalcData {NULL, } +#define NULL_BVHTreeFromMesh {NULL, } +#define NULL_BVHTreeRayHit {NULL, } +#define NULL_BVHTreeNearest {0, } + + +#endif + diff --git a/source/blender/blenkernel/BKE_utildefines.h b/source/blender/blenkernel/BKE_utildefines.h index a96a3e10f40..f389521ffa0 100644 --- a/source/blender/blenkernel/BKE_utildefines.h +++ b/source/blender/blenkernel/BKE_utildefines.h @@ -197,8 +197,8 @@ /* Warning-free macros for storing ints in pointers. Use these _only_ * for storing an int in a pointer, not a pointer in an int (64bit)! */ -#define SET_INT_IN_POINTER(i) ((void*)(long)(i)) -#define GET_INT_FROM_POINTER(i) ((int)(long)(i)) +#define SET_INT_IN_POINTER(i) ((void*)(intptr_t)(i)) +#define GET_INT_FROM_POINTER(i) ((int)(intptr_t)(i)) #endif diff --git a/source/blender/blenkernel/intern/CCGSubSurf.c b/source/blender/blenkernel/intern/CCGSubSurf.c index 9dcb6b6e7fa..1652b24e1e5 100644 --- a/source/blender/blenkernel/intern/CCGSubSurf.c +++ b/source/blender/blenkernel/intern/CCGSubSurf.c @@ -7,6 +7,8 @@ #include "CCGSubSurf.h" +#include "BLO_sys_types.h" // for intptr_t support + /***/ typedef unsigned char byte; @@ -35,7 +37,7 @@ typedef struct _EHash { #define EHASH_alloc(eh, nb) ((eh)->allocatorIFC.alloc((eh)->allocator, nb)) #define EHASH_free(eh, ptr) ((eh)->allocatorIFC.free((eh)->allocator, ptr)) -#define EHASH_hash(eh, item) (((unsigned long) (item))%((unsigned int) (eh)->curSize)) +#define EHASH_hash(eh, item) (((uintptr_t) (item))%((unsigned int) (eh)->curSize)) static EHash *_ehash_new(int estimatedNumEntries, CCGAllocatorIFC *allocatorIFC, CCGAllocatorHDL allocator) { EHash *eh = allocatorIFC->alloc(allocator, sizeof(*eh)); diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c index 67cf89d5ee2..1dabab98a6e 100644 --- a/source/blender/blenkernel/intern/DerivedMesh.c +++ b/source/blender/blenkernel/intern/DerivedMesh.c @@ -79,6 +79,8 @@ #include "BKE_utildefines.h" #include "BKE_particle.h" +#include "BLO_sys_types.h" // for intptr_t support + #ifdef WITH_VERSE #include "BKE_verse.h" #endif @@ -479,7 +481,7 @@ static void emDM_foreachMappedEdge(DerivedMesh *dm, void (*func)(void *userData, EditVert *eve; for (i=0,eve=emdm->em->verts.first; eve; eve= eve->next) - eve->tmp.l = (long) i++; + eve->tmp.l = (intptr_t) i++; for(i=0,eed= emdm->em->edges.first; eed; i++,eed= eed->next) func(userData, i, emdm->vertexCos[(int) eed->v1->tmp.l], emdm->vertexCos[(int) eed->v2->tmp.l]); } else { @@ -497,7 +499,7 @@ static void emDM_drawMappedEdges(DerivedMesh *dm, int (*setDrawOptions)(void *us EditVert *eve; for (i=0,eve=emdm->em->verts.first; eve; eve= eve->next) - eve->tmp.l = (long) i++; + eve->tmp.l = (intptr_t) i++; glBegin(GL_LINES); for(i=0,eed= emdm->em->edges.first; eed; i++,eed= eed->next) { @@ -532,7 +534,7 @@ static void emDM_drawMappedEdgesInterp(DerivedMesh *dm, int (*setDrawOptions)(vo EditVert *eve; for (i=0,eve=emdm->em->verts.first; eve; eve= eve->next) - eve->tmp.l = (long) i++; + eve->tmp.l = (intptr_t) i++; glBegin(GL_LINES); for (i=0,eed= emdm->em->edges.first; eed; i++,eed= eed->next) { @@ -619,7 +621,7 @@ static void emDM_foreachMappedFaceCenter(DerivedMesh *dm, void (*func)(void *use if (emdm->vertexCos) { for (i=0,eve=emdm->em->verts.first; eve; eve= eve->next) - eve->tmp.l = (long) i++; + eve->tmp.l = (intptr_t) i++; } for(i=0,efa= emdm->em->faces.first; efa; i++,efa= efa->next) { @@ -637,7 +639,7 @@ static void emDM_drawMappedFaces(DerivedMesh *dm, int (*setDrawOptions)(void *us EditVert *eve; for (i=0,eve=emdm->em->verts.first; eve; eve= eve->next) - eve->tmp.l = (long) i++; + eve->tmp.l = (intptr_t) i++; for (i=0,efa= emdm->em->faces.first; efa; i++,efa= efa->next) { int drawSmooth = (efa->flag & ME_SMOOTH); @@ -733,7 +735,7 @@ static void emDM_drawFacesTex_common(DerivedMesh *dm, EditVert *eve; for (i=0,eve=em->verts.first; eve; eve= eve->next) - eve->tmp.l = (long) i++; + eve->tmp.l = (intptr_t) i++; for (i=0,efa= em->faces.first; efa; i++,efa= efa->next) { MTFace *tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); @@ -1053,7 +1055,7 @@ void emDM_copyEdgeArray(DerivedMesh *dm, MEdge *edge_r) /* store vertex indices in tmp union */ for(ev = em->verts.first, i = 0; ev; ev = ev->next, ++i) - ev->tmp.l = (long) i; + ev->tmp.l = (intptr_t) i; for( ; ee; ee = ee->next, ++edge_r) { edge_r->crease = (unsigned char) (ee->crease*255.0f); @@ -1081,7 +1083,7 @@ void emDM_copyFaceArray(DerivedMesh *dm, MFace *face_r) /* store vertexes indices in tmp union */ for(ev = em->verts.first, i = 0; ev; ev = ev->next, ++i) - ev->tmp.l = (long) i; + ev->tmp.l = (intptr_t) i; for( ; ef; ef = ef->next, ++face_r) { face_r->mat_nr = ef->mat_nr; @@ -1168,7 +1170,7 @@ static DerivedMesh *getEditMeshDerivedMesh(EditMesh *em, Object *ob, int i; for (i=0,eve=em->verts.first; eve; eve= eve->next) - eve->tmp.l = (long) i++; + eve->tmp.l = (intptr_t) i++; emdm->vertexNos = MEM_callocN(sizeof(*emdm->vertexNos)*i, "emdm_vno"); emdm->faceNos = MEM_mallocN(sizeof(*emdm->faceNos)*totface, "emdm_vno"); diff --git a/source/blender/blenkernel/intern/bvhutils.c b/source/blender/blenkernel/intern/bvhutils.c index 042e2afad53..ae449843d2a 100644 --- a/source/blender/blenkernel/intern/bvhutils.c +++ b/source/blender/blenkernel/intern/bvhutils.c @@ -81,7 +81,7 @@ static float sphereray_tri_intersection(const BVHTreeRay *ray, float radius, con * Function adapted from David Eberly's distance tools (LGPL) * http://www.geometrictools.com/LibFoundation/Distance/Distance.html */ -static float nearest_point_in_tri_surface(const float *v0,const float *v1,const float *v2,const float *p, int *v, int *e, float *d, float *nearest ) +static float nearest_point_in_tri_surface(const float *v0,const float *v1,const float *v2,const float *p, int *v, int *e, float *nearest ) { float diff[3]; float e0[3]; @@ -386,7 +386,7 @@ static float nearest_point_in_tri_surface(const float *v0,const float *v1,const VecMulf(y, T); VECADD(z, w, x); VECADD(z, z, y); - VECSUB(d, p, z); + //VECSUB(d, p, z); VECCOPY(nearest, z); // d = p - ( v0 + S * e0 + T * e1 ); } @@ -418,16 +418,16 @@ static void mesh_faces_nearest_point(void *userdata, int index, const float *co, do { - float nearest_tmp[3], col_normal[3], dist; + float nearest_tmp[3], dist; int vertex, edge; - dist = nearest_point_in_tri_surface(t0, t1, t2, co, &vertex, &edge, col_normal, nearest_tmp); + dist = nearest_point_in_tri_surface(t0, t1, t2, co, &vertex, &edge, nearest_tmp); if(dist < nearest->dist) { nearest->index = index; nearest->dist = dist; VECCOPY(nearest->co, nearest_tmp); - VECCOPY(nearest->no, col_normal); + CalcNormFloat(t0, t1, t2, nearest->no); } t1 = t2; diff --git a/source/blender/blenkernel/intern/cloth.c b/source/blender/blenkernel/intern/cloth.c index c7817b017ef..dbc94571cad 100644 --- a/source/blender/blenkernel/intern/cloth.c +++ b/source/blender/blenkernel/intern/cloth.c @@ -155,7 +155,7 @@ void cloth_init ( ClothModifierData *clmd ) BVHTree *bvhselftree_build_from_cloth (ClothModifierData *clmd, float epsilon) { - int i; + unsigned int i; BVHTree *bvhtree; Cloth *cloth = clmd->clothObject; ClothVertex *verts; @@ -196,7 +196,7 @@ BVHTree *bvhselftree_build_from_cloth (ClothModifierData *clmd, float epsilon) BVHTree *bvhtree_build_from_cloth (ClothModifierData *clmd, float epsilon) { - int i; + unsigned int i; BVHTree *bvhtree; Cloth *cloth = clmd->clothObject; ClothVertex *verts; @@ -782,11 +782,11 @@ static void cloth_to_object (Object *ob, ClothModifierData *clmd, DerivedMesh * /* can be optimized to do all groups in one loop */ static void cloth_apply_vgroup ( ClothModifierData *clmd, DerivedMesh *dm ) { - unsigned int i = 0; - unsigned int j = 0; + int i = 0; + int j = 0; MDeformVert *dvert = NULL; Cloth *clothObj = NULL; - unsigned int numverts = dm->getNumVerts ( dm ); + int numverts = dm->getNumVerts ( dm ); float goalfac = 0; ClothVertex *verts = NULL; @@ -857,7 +857,7 @@ static void cloth_apply_vgroup ( ClothModifierData *clmd, DerivedMesh *dm ) static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *dm, float framenr, int first) { - unsigned int i = 0; + int i = 0; MVert *mvert = NULL; ClothVertex *verts = NULL; float tnull[3] = {0,0,0}; @@ -1082,13 +1082,13 @@ int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm ) Cloth *cloth = clmd->clothObject; ClothSpring *spring = NULL, *tspring = NULL, *tspring2 = NULL; unsigned int struct_springs = 0, shear_springs=0, bend_springs = 0; - unsigned int i = 0; - unsigned int numverts = dm->getNumVerts ( dm ); - unsigned int numedges = dm->getNumEdges ( dm ); - unsigned int numfaces = dm->getNumFaces ( dm ); + int i = 0; + int numverts = dm->getNumVerts ( dm ); + int numedges = dm->getNumEdges ( dm ); + int numfaces = dm->getNumFaces ( dm ); MEdge *medge = CDDM_get_edges ( dm ); MFace *mface = CDDM_get_faces ( dm ); - unsigned int index2 = 0; // our second vertex index + int index2 = 0; // our second vertex index LinkNode **edgelist = NULL; EdgeHash *edgehash = NULL; LinkNode *search = NULL, *search2 = NULL; 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/deform.c b/source/blender/blenkernel/intern/deform.c index ab53571b62d..3143c5e4df2 100644 --- a/source/blender/blenkernel/intern/deform.c +++ b/source/blender/blenkernel/intern/deform.c @@ -220,3 +220,31 @@ void unique_vertexgroup_name (bDeformGroup *dg, Object *ob) } } } + +float deformvert_get_weight(const struct MDeformVert *dvert, int group_num) +{ + if(dvert) + { + const MDeformWeight *dw = dvert->dw; + int i; + + for(i=dvert->totweight; i>0; i--, dw++) + if(dw->def_nr == group_num) + return dw->weight; + } + + /* Not found */ + return 0.0; +} + +float vertexgroup_get_vertex_weight(const struct MDeformVert *dvert, int index, int group_num) +{ + if(group_num == -1) + return 1.0; + + if(dvert == 0) + return 0.0; + + return deformvert_get_weight(dvert+index, group_num); +} + diff --git a/source/blender/blenkernel/intern/displist.c b/source/blender/blenkernel/intern/displist.c index 298e4b81d5b..3b79f6689c0 100644 --- a/source/blender/blenkernel/intern/displist.c +++ b/source/blender/blenkernel/intern/displist.c @@ -88,6 +88,8 @@ #include "RE_pipeline.h" #include "RE_shader_ext.h" +#include "BLO_sys_types.h" // for intptr_t support + static void boundbox_displist(Object *ob); @@ -986,9 +988,9 @@ void filldisplist(ListBase *dispbase, ListBase *to) efa= fillfacebase.first; index= dlnew->index; while(efa) { - index[0]= (long)efa->v1->tmp.l; - index[1]= (long)efa->v2->tmp.l; - index[2]= (long)efa->v3->tmp.l; + index[0]= (intptr_t)efa->v1->tmp.l; + index[1]= (intptr_t)efa->v2->tmp.l; + index[2]= (intptr_t)efa->v3->tmp.l; index+= 3; efa= efa->next; diff --git a/source/blender/blenkernel/intern/effect.c b/source/blender/blenkernel/intern/effect.c index 4588ef800e1..72f70cf17ff 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" @@ -157,6 +158,13 @@ static void add_to_effectorcache(ListBase *lb, Object *ob, Object *obsrc) } } else if(pd->forcefield) { + + if(pd->forcefield == PFIELD_WIND) + { + pd->rng = rng_new(1); + rng_srandom(pd->rng, (unsigned int)(ceil(PIL_check_seconds_timer()))); // use better seed + } + ec= MEM_callocN(sizeof(pEffectorCache), "effector cache"); ec->ob= ob; BLI_addtail(lb, ec); @@ -205,13 +213,288 @@ void pdEndEffectors(ListBase *lb) pEffectorCache *ec; /* restore full copy */ for(ec= lb->first; ec; ec= ec->next) + { + if(ec->ob->pd && (ec->ob->pd->forcefield == PFIELD_WIND)) + rng_free(ec->ob->pd->rng); + *(ec->ob)= ec->obcopy; + } BLI_freelistN(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) +{ + int random = (rng_getInt(rng)+1) % 65535; // max 2357 + float force = rng_getFloat(rng) + 1.0f; + float ret; + float sign = 0; + + sign = (random > 32000.0) ? 1.0: -1.0; // dividing by 2 is not giving equal sign distribution + + ret = sign*((float)random / force)*strength/65535.0f; + + return ret; +} + + +static float falloff_func(float fac, int usemin, float mindist, int usemax, float maxdist, float power) +{ + if(!usemin) + mindist= 0.0f; + + if(fac < mindist) { + return 1.0f; + } + else if(usemax) { + if(fac>maxdist || (maxdist-mindist)<=0.0f) + return 0.0f; + + fac= (fac-mindist)/(maxdist-mindist); + return 1.0f - (float)pow((double)fac, (double)power); + } + else + return pow((double)1.0f+fac-mindist, (double)-power); +} + +static float falloff_func_dist(PartDeflect *pd, float fac) +{ + return falloff_func(fac, pd->flag&PFIELD_USEMIN, pd->mindist, pd->flag&PFIELD_USEMAX, pd->maxdist, pd->f_power); +} + +static float falloff_func_rad(PartDeflect *pd, float fac) +{ + return falloff_func(fac, pd->flag&PFIELD_USEMINR, pd->minrad, pd->flag&PFIELD_USEMAXR, pd->maxrad, pd->f_power_r); +} + +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); + + if(pd->flag & PFIELD_POSZ && Inpf(eff_dir,vec_to_part)<0.0f) + falloff=0.0f; + else switch(pd->falloff){ + case PFIELD_FALL_SPHERE: + fac=VecLength(vec_to_part); + falloff= falloff_func_dist(pd, fac); + break; + + case PFIELD_FALL_TUBE: + fac=Inpf(vec_to_part,eff_dir); + falloff= falloff_func_dist(pd, ABS(fac)); + if(falloff == 0.0f) + break; + + VECADDFAC(temp,vec_to_part,eff_dir,-fac); + r_fac=VecLength(temp); + falloff*= falloff_func_rad(pd, r_fac); + break; + case PFIELD_FALL_CONE: + fac=Inpf(vec_to_part,eff_dir); + falloff= falloff_func_dist(pd, ABS(fac)); + if(falloff == 0.0f) + break; + + r_fac=saacos(fac/VecLength(vec_to_part))*180.0f/(float)M_PI; + falloff*= falloff_func_rad(pd, r_fac); + + break; + } + + return falloff; +} + +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 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); + + switch(type){ + case PFIELD_WIND: + VECCOPY(mag_vec,eff_vel); + + // 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; + + case PFIELD_FORCE: + if(planar) + Projf(mag_vec,vec_to_part,eff_vel); + else + VecCopyf(mag_vec,vec_to_part); + + Normalize(mag_vec); + + VecMulf(mag_vec,force_val*falloff); + VecAddf(field,field,mag_vec); + break; + + case PFIELD_VORTEX: + Crossf(mag_vec,eff_vel,vec_to_part); + + Normalize(mag_vec); + + VecMulf(mag_vec,force_val*distance*falloff); + VecAddf(field,field,mag_vec); + + break; + case PFIELD_MAGNET: + if(planar) + VecCopyf(temp,eff_vel); + else + /* magnetic field of a moving charge */ + Crossf(temp,eff_vel,vec_to_part); + + Normalize(temp); + + Crossf(temp2,velocity,temp); + VecAddf(mag_vec,mag_vec,temp2); + + VecMulf(mag_vec,force_val*falloff); + VecAddf(field,field,mag_vec); + break; + case PFIELD_HARMONIC: + if(planar) + Projf(mag_vec,vec_to_part,eff_vel); + else + VecCopyf(mag_vec,vec_to_part); + + Normalize(mag_vec); + + VecMulf(mag_vec,force_val*falloff); + VecSubf(field,field,mag_vec); + + VecCopyf(mag_vec,velocity); + /* 1.9 is an experimental value to get critical damping at damp=1.0 */ + VecMulf(mag_vec,damp*1.9f*(float)sqrt(force_val)); + VecSubf(field,field,mag_vec); + break; + case PFIELD_CHARGE: + if(planar) + Projf(mag_vec,vec_to_part,eff_vel); + else + VecCopyf(mag_vec,vec_to_part); + + Normalize(mag_vec); + + 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 lb = listbase with objects that take part in effecting @@ -244,13 +527,10 @@ void pdDoEffectors(ListBase *lb, float *opco, float *force, float *speed, float pEffectorCache *ec; PartDeflect *pd; float vect_to_vert[3]; - float f_force, force_vec[3]; float *obloc; - float distance, force_val, ffall_val; - float guidecollect[3], guidedist= 0.0f; - int cur_frame; - guidecollect[0]= guidecollect[1]= guidecollect[2]=0.0f; + float distance, vec_to_part[3]; + float falloff; /* Cycle through collected objects, get total of (1/(gravity_strength * dist^gravity_power)) */ /* Check for min distance here? (yes would be cool to add that, ton) */ @@ -261,178 +541,28 @@ void pdDoEffectors(ListBase *lb, float *opco, float *force, float *speed, float pd= ob->pd; /* Get IPO force strength and fall off values here */ - if (has_ipo_code(ob->ipo, OB_PD_FSTR)) - force_val = IPO_GetFloatValue(ob->ipo, OB_PD_FSTR, cur_time); - else - force_val = pd->f_strength; - - if (has_ipo_code(ob->ipo, OB_PD_FFALL)) - ffall_val = IPO_GetFloatValue(ob->ipo, OB_PD_FFALL, cur_time); - else - ffall_val = pd->f_power; - - /* Need to set r.cfra for paths (investigate, ton) (uses ob->ctime now, ton) */ - if(ob->ctime!=cur_time) { - cur_frame = G.scene->r.cfra; - G.scene->r.cfra = (int)cur_time; - where_is_object_time(ob, cur_time); - G.scene->r.cfra = cur_frame; - } + where_is_object_time(ob,cur_time); /* use center of object for distance calculus */ - obloc= ob->obmat[3]; - VECSUB(vect_to_vert, obloc, opco); - distance = VecLength(vect_to_vert); - - if((pd->flag & PFIELD_USEMAX) && distance>pd->maxdist && pd->forcefield != PFIELD_GUIDE) - ; /* don't do anything */ - else if((pd->flag & PFIELD_USEMIN) && distance<pd->mindist && pd->forcefield != PFIELD_GUIDE) + VecSubf(vec_to_part, opco, ob->obmat[3]); + distance = VecLength(vec_to_part); + + falloff=effector_falloff(pd,ob->obmat[2],vec_to_part); + + if(falloff<=0.0f) ; /* don't do anything */ - else if(pd->forcefield == PFIELD_WIND) { - VECCOPY(force_vec, ob->obmat[2]); - - /* wind works harder perpendicular to normal, would be nice for softbody later (ton) */ - - /* Limit minimum distance to vertex so that */ - /* the force is not too big */ - if (distance < 0.001) distance = 0.001f; - f_force = (force_val)*(1/(1000 * (float)pow((double)distance, (double)ffall_val))); - /* this option for softbody only */ - if(flags && PE_WIND_AS_SPEED){ - speed[0] -= (force_vec[0] * f_force ); - speed[1] -= (force_vec[1] * f_force ); - speed[2] -= (force_vec[2] * f_force ); - } - else{ - force[0] += force_vec[0]*f_force; - force[1] += force_vec[1]*f_force; - force[2] += force_vec[2]*f_force; - } - } - else if(pd->forcefield == PFIELD_FORCE) { - - /* only use center of object */ - obloc= ob->obmat[3]; - - /* Now calculate the gravitational force */ - VECSUB(vect_to_vert, obloc, opco); - distance = VecLength(vect_to_vert); - - /* Limit minimum distance to vertex so that */ - /* the force is not too big */ - if (distance < 0.001) distance = 0.001f; - f_force = (force_val)*(1.0/(1000.0 * (float)pow((double)distance, (double)ffall_val))); - force[0] += (vect_to_vert[0] * f_force ); - force[1] += (vect_to_vert[1] * f_force ); - force[2] += (vect_to_vert[2] * f_force ); - } - else if(pd->forcefield == PFIELD_VORTEX) { - float vortexvec[3]; + else { + float field[3]={0,0,0}, tmp[3]; + VECCOPY(field, force); + 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, 0.0f, 0.0f); - /* only use center of object */ - obloc= ob->obmat[3]; - - /* Now calculate the vortex force */ - VECSUB(vect_to_vert, obloc, opco); - distance = VecLength(vect_to_vert); - - Crossf(force_vec, ob->obmat[2], vect_to_vert); - Normalize(force_vec); - - /* Limit minimum distance to vertex so that */ - /* the force is not too big */ - if (distance < 0.001) distance = 0.001f; - f_force = (force_val)*(1.0/(100.0 * (float)pow((double)distance, (double)ffall_val))); - vortexvec[0]= -(force_vec[0] * f_force ); - vortexvec[1]= -(force_vec[1] * f_force ); - vortexvec[2]= -(force_vec[2] * f_force ); - - /* this option for softbody only */ - if(flags &&PE_WIND_AS_SPEED) { - speed[0]+= vortexvec[0]; - speed[1]+= vortexvec[1]; - speed[2]+= vortexvec[2]; - } - else { - /* since vortex alters the speed, we have to correct for the previous vortex result */ - speed[0]+= vortexvec[0] - ec->oldspeed[0]; - speed[1]+= vortexvec[1] - ec->oldspeed[1]; - speed[2]+= vortexvec[2] - ec->oldspeed[2]; - - VECCOPY(ec->oldspeed, vortexvec); + // for softbody backward compatibility + if(flags & PE_WIND_AS_SPEED){ + VECSUB(tmp, force, field); + VECSUB(speed, speed, tmp); } } - else if(pd->forcefield == PFIELD_GUIDE) { - float guidevec[4], guidedir[3]; - float mindist= force_val; /* force_val is actually mindist in the UI */ - - distance= ec->guide_dist; - - /* WARNING: bails out with continue here */ - if((pd->flag & PFIELD_USEMAX) && distance>pd->maxdist) continue; - - /* calculate contribution factor for this guide */ - if(distance<=mindist) f_force= 1.0f; - else if(pd->flag & PFIELD_USEMAX) { - if(distance>pd->maxdist || mindist>=pd->maxdist) f_force= 0.0f; - else { - f_force= 1.0f - (distance-mindist)/(pd->maxdist - mindist); - if(ffall_val!=0.0f) - f_force = (float)pow(f_force, ffall_val+1.0); - } - } - else { - f_force= 1.0f/(1.0f + distance-mindist); - if(ffall_val!=0.0f) - f_force = (float)pow(f_force, ffall_val+1.0); - } - - /* now derive path point from loc_time */ - if(pd->flag & PFIELD_GUIDE_PATH_ADD) - where_on_path(ob, f_force*loc_time*ec->time_scale, guidevec, guidedir); - else - where_on_path(ob, loc_time*ec->time_scale, guidevec, guidedir); - - VECSUB(guidedir, guidevec, ec->oldloc); - VECCOPY(ec->oldloc, guidevec); - - Mat4Mul3Vecfl(ob->obmat, guidedir); - VecMulf(guidedir, ec->scale); /* correction for lifetime and speed */ - - /* we subtract the speed we gave it previous step */ - VECCOPY(guidevec, guidedir); - VECSUB(guidedir, guidedir, ec->oldspeed); - VECCOPY(ec->oldspeed, guidevec); - - /* if it fully contributes, we stop */ - if(f_force==1.0) { - VECCOPY(guidecollect, guidedir); - guidedist= 1.0f; - break; - } - else if(guidedist<1.0f) { - VecMulf(guidedir, f_force); - VECADD(guidecollect, guidecollect, guidedir); - guidedist += f_force; - } - } - } - - /* all guides are accumulated here */ - if(guidedist!=0.0f) { - if(guidedist!=1.0f) VecMulf(guidecollect, 1.0f/guidedist); - VECADD(speed, speed, guidecollect); } } - - -/* for paf start to end, store all matrices for objects */ -typedef struct pMatrixCache { - float obmat[4][4]; - float imat[3][3]; -} pMatrixCache; - -/* for fluidsim win32 debug messages */ -#if defined(WIN32) && (!(defined snprintf)) -#define snprintf _snprintf -#endif diff --git a/source/blender/blenkernel/intern/icons.c b/source/blender/blenkernel/intern/icons.c index cab7865c1b6..b9e3c593ddf 100644 --- a/source/blender/blenkernel/intern/icons.c +++ b/source/blender/blenkernel/intern/icons.c @@ -50,6 +50,8 @@ #include "BKE_icons.h" #include "BKE_utildefines.h" +#include "BLO_sys_types.h" // for intptr_t support + #define GS(a) (*((short *)(a))) /* GLOBALS */ diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c index b6c8ad59e08..07537e3a81c 100644 --- a/source/blender/blenkernel/intern/image.c +++ b/source/blender/blenkernel/intern/image.c @@ -86,6 +86,8 @@ #include "blendef.h" #include "BSE_time.h" +#include "BLO_sys_types.h" // for intptr_t support + /* max int, to indicate we don't store sequences in ibuf */ #define IMA_NO_INDEX 0x7FEFEFEF @@ -630,11 +632,11 @@ void free_old_images() } } -static unsigned long image_mem_size(Image *ima) +static uintptr_t image_mem_size(Image *ima) { ImBuf *ibuf, *ibufm; int level; - unsigned long size = 0; + uintptr_t size = 0; size= 0; for(ibuf= ima->ibufs.first; ibuf; ibuf= ibuf->next) { @@ -656,7 +658,7 @@ static unsigned long image_mem_size(Image *ima) void BKE_image_print_memlist(void) { Image *ima; - unsigned long size, totsize= 0; + uintptr_t size, totsize= 0; for(ima= G.main->image.first; ima; ima= ima->id.next) totsize += image_mem_size(ima); diff --git a/source/blender/blenkernel/intern/implicit.c b/source/blender/blenkernel/intern/implicit.c index 297ac0b1530..93e35a4db06 100644 --- a/source/blender/blenkernel/intern/implicit.c +++ b/source/blender/blenkernel/intern/implicit.c @@ -1354,25 +1354,57 @@ DO_INLINE void cloth_apply_spring_force(ClothModifierData *clmd, ClothSpring *s, } } + +static void CalcFloat( float *v1, float *v2, float *v3, float *n) +{ + float n1[3],n2[3]; + + n1[0]= v1[0]-v2[0]; + n2[0]= v2[0]-v3[0]; + n1[1]= v1[1]-v2[1]; + n2[1]= v2[1]-v3[1]; + n1[2]= v1[2]-v2[2]; + n2[2]= v2[2]-v3[2]; + n[0]= n1[1]*n2[2]-n1[2]*n2[1]; + n[1]= n1[2]*n2[0]-n1[0]*n2[2]; + n[2]= n1[0]*n2[1]-n1[1]*n2[0]; +} + +static void CalcFloat4( float *v1, float *v2, float *v3, float *v4, float *n) +{ + /* real cross! */ + float n1[3],n2[3]; + + n1[0]= v1[0]-v3[0]; + n1[1]= v1[1]-v3[1]; + n1[2]= v1[2]-v3[2]; + + n2[0]= v2[0]-v4[0]; + n2[1]= v2[1]-v4[1]; + n2[2]= v2[2]-v4[2]; + + n[0]= n1[1]*n2[2]-n1[2]*n2[1]; + n[1]= n1[2]*n2[0]-n1[0]*n2[2]; + n[2]= n1[0]*n2[1]-n1[1]*n2[0]; +} + float calculateVertexWindForce(float wind[3], float vertexnormal[3]) { - return fabs(INPR(wind, vertexnormal)); + return (INPR(wind, vertexnormal)); } void cloth_calc_force(ClothModifierData *clmd, lfVector *lF, lfVector *lX, lfVector *lV, fmatrix3x3 *dFdV, fmatrix3x3 *dFdX, ListBase *effectors, float time, fmatrix3x3 *M) { /* Collect forces and derivatives: F,dFdX,dFdV */ Cloth *cloth = clmd->clothObject; - long i = 0; + int i = 0; float spring_air = clmd->sim_parms->Cvi * 0.01f; /* viscosity of air scaled in percent */ float gravity[3]; float tm2[3][3] = {{-spring_air,0,0}, {0,-spring_air,0},{0,0,-spring_air}}; MFace *mfaces = cloth->mfaces; - //ClothVertex *verts = cloth->verts; - float wind_normalized[3]; unsigned int numverts = cloth->numverts; LinkNode *search = cloth->springs; - + lfVector *winvec; VECCOPY(gravity, clmd->sim_parms->gravity); mul_fvector_S(gravity, gravity, 0.001f); /* scale gravity force */ @@ -1387,7 +1419,7 @@ void cloth_calc_force(ClothModifierData *clmd, lfVector *lF, lfVector *lX, lfVec /* multiply lF with mass matrix // force = mass * acceleration (in this case: gravity) */ - for(i = 0; i < (long)numverts; i++) + for(i = 0; i < numverts; i++) { float temp[3]; VECCOPY(temp, lF[i]); @@ -1399,70 +1431,61 @@ void cloth_calc_force(ClothModifierData *clmd, lfVector *lF, lfVector *lX, lfVec /* handle external forces like wind */ if(effectors) { - for(i = 0; i < cloth->numfaces; i++) + // 0 = force, 1 = normalized force + winvec = create_lfvector(cloth->numverts); + + if(!winvec) + printf("winvec: out of memory in implicit.c\n"); + + // precalculate wind forces + for(i = 0; i < cloth->numverts; i++) { - float vertexnormal[3]={0,0,0}; float speed[3] = {0.0f, 0.0f,0.0f}; - float force[3]= {0.0f, 0.0f, 0.0f}; + pdDoEffectors(effectors, lX[i], winvec[i], speed, (float)G.scene->r.cfra, 0.0f, 0); + } + + for(i = 0; i < cloth->numfaces; i++) + { + float trinormal[3]={0,0,0}; // normalized triangle normal + 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.02; + + // calculate face normal if(mfaces[i].v4) - CalcNormFloat4(lX[mfaces[i].v1],lX[mfaces[i].v2],lX[mfaces[i].v3],lX[mfaces[i].v4],vertexnormal); + CalcFloat4(lX[mfaces[i].v1],lX[mfaces[i].v2],lX[mfaces[i].v3],lX[mfaces[i].v4],triunnormal); else - CalcNormFloat(lX[mfaces[i].v1],lX[mfaces[i].v2],lX[mfaces[i].v3],vertexnormal); + CalcFloat(lX[mfaces[i].v1],lX[mfaces[i].v2],lX[mfaces[i].v3],triunnormal); - pdDoEffectors(effectors, lX[mfaces[i].v1], force, speed, (float)G.scene->r.cfra, 0.0f, PE_WIND_AS_SPEED); - VECCOPY(wind_normalized, speed); - Normalize(wind_normalized); - VecMulf(wind_normalized, -calculateVertexWindForce(speed, vertexnormal)); + VECCOPY(trinormal, triunnormal); + Normalize(trinormal); - if(mfaces[i].v4) - { - VECADDS(lF[mfaces[i].v1], lF[mfaces[i].v1], wind_normalized, 0.25); - } - else - { - VECADDS(lF[mfaces[i].v1], lF[mfaces[i].v1], wind_normalized, 1.0 / 3.0); - } + // add wind from v1 + VECCOPY(tmp, trinormal); + VecMulf(tmp, calculateVertexWindForce(winvec[mfaces[i].v1], triunnormal)); + VECADDS(lF[mfaces[i].v1], lF[mfaces[i].v1], tmp, factor); - speed[0] = speed[1] = speed[2] = 0.0; - pdDoEffectors(effectors, lX[mfaces[i].v2], force, speed, (float)G.scene->r.cfra, 0.0f, PE_WIND_AS_SPEED); - VECCOPY(wind_normalized, speed); - Normalize(wind_normalized); - VecMulf(wind_normalized, -calculateVertexWindForce(speed, vertexnormal)); - if(mfaces[i].v4) - { - VECADDS(lF[mfaces[i].v2], lF[mfaces[i].v2], wind_normalized, 0.25); - } - else - { - VECADDS(lF[mfaces[i].v2], lF[mfaces[i].v2], wind_normalized, 1.0 / 3.0); - } + // add wind from v2 + VECCOPY(tmp, trinormal); + VecMulf(tmp, calculateVertexWindForce(winvec[mfaces[i].v2], triunnormal)); + VECADDS(lF[mfaces[i].v2], lF[mfaces[i].v2], tmp, factor); - speed[0] = speed[1] = speed[2] = 0.0; - pdDoEffectors(effectors, lX[mfaces[i].v3], force, speed, (float)G.scene->r.cfra, 0.0f, PE_WIND_AS_SPEED); - VECCOPY(wind_normalized, speed); - Normalize(wind_normalized); - VecMulf(wind_normalized, -calculateVertexWindForce(speed, vertexnormal)); - if(mfaces[i].v4) - { - VECADDS(lF[mfaces[i].v3], lF[mfaces[i].v3], wind_normalized, 0.25); - } - else - { - VECADDS(lF[mfaces[i].v3], lF[mfaces[i].v3], wind_normalized, 1.0 / 3.0); - } + // add wind from v3 + VECCOPY(tmp, trinormal); + VecMulf(tmp, calculateVertexWindForce(winvec[mfaces[i].v3], triunnormal)); + VECADDS(lF[mfaces[i].v3], lF[mfaces[i].v3], tmp, factor); - speed[0] = speed[1] = speed[2] = 0.0; + // add wind from v4 if(mfaces[i].v4) { - pdDoEffectors(effectors, lX[mfaces[i].v4], force, speed, (float)G.scene->r.cfra, 0.0f, PE_WIND_AS_SPEED); - VECCOPY(wind_normalized, speed); - Normalize(wind_normalized); - VecMulf(wind_normalized, -calculateVertexWindForce(speed, vertexnormal)); - VECADDS(lF[mfaces[i].v4], lF[mfaces[i].v4], wind_normalized, 0.25); + VECCOPY(tmp, trinormal); + VecMulf(tmp, calculateVertexWindForce(winvec[mfaces[i].v4], triunnormal)); + VECADDS(lF[mfaces[i].v4], lF[mfaces[i].v4], tmp, factor); } - } + del_lfvector(winvec); } // calculate spring forces diff --git a/source/blender/blenkernel/intern/ipo.c b/source/blender/blenkernel/intern/ipo.c index 59eb3837aab..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_BB_TILT, PART_PD_FSTR, PART_PD_FFALL, PART_PD_FMAXD, PART_PD2_FSTR, PART_PD2_FFALL, PART_PD2_FMAXD }; @@ -1608,6 +1608,18 @@ void *get_ipo_poin(ID *id, IpoCurve *icu, int *type) poin= &(part->kink_shape); break; case PART_BB_TILT: poin= &(part->bb_tilt); break; + case PART_PD_FSTR: + poin= (part->pd?(&(part->pd->f_strength)):NULL); break; + case PART_PD_FFALL: + 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 1dc76296c28..4c74fe1cca2 100644 --- a/source/blender/blenkernel/intern/modifier.c +++ b/source/blender/blenkernel/intern/modifier.c @@ -101,6 +101,8 @@ #include "BKE_utildefines.h" #include "depsgraph_private.h" #include "BKE_bmesh.h" +#include "BKE_deform.h" +#include "BKE_shrinkwrap.h" #include "LOD_DependKludge.h" #include "LOD_decimation.h" @@ -5493,7 +5495,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)) @@ -6120,22 +6122,6 @@ CustomDataMask explodeModifier_requiredDataMask(ModifierData *md) return dataMask; } -/* this should really be put somewhere permanently */ -static float vert_weight(MDeformVert *dvert, int group) -{ - MDeformWeight *dw; - int i; - - if(dvert) { - dw= dvert->dw; - for(i= dvert->totweight; i>0; i--, dw++) { - if(dw->def_nr == group) return dw->weight; - if(i==1) break; /*otherwise dw will point to somewhere it shouldn't*/ - } - } - return 0.0; -} - static void explodeModifier_createFacepa(ExplodeModifierData *emd, ParticleSystemModifierData *psmd, Object *ob, DerivedMesh *dm) @@ -6179,7 +6165,7 @@ static void explodeModifier_createFacepa(ExplodeModifierData *emd, for(i=0; i<totvert; i++){ val = BLI_frand(); val = (1.0f-emd->protect)*val + emd->protect*0.5f; - if(val < vert_weight(dvert+i,emd->vgroup-1)) + if(val < deformvert_get_weight(dvert+i,emd->vgroup-1)) vertpa[i] = -1; } } @@ -7236,6 +7222,126 @@ static void meshdeformModifier_deformVertsEM( dm->release(dm); } + +/* Shrinkwrap */ + +static void shrinkwrapModifier_initData(ModifierData *md) +{ + ShrinkwrapModifierData *smd = (ShrinkwrapModifierData*) md; + smd->shrinkType = MOD_SHRINKWRAP_NEAREST_SURFACE; + smd->shrinkOpts = MOD_SHRINKWRAP_PROJECT_ALLOW_POS_DIR; + smd->keepDist = 0.0f; + + smd->target = NULL; + smd->auxTarget = NULL; +} + +static void shrinkwrapModifier_copyData(ModifierData *md, ModifierData *target) +{ + ShrinkwrapModifierData *smd = (ShrinkwrapModifierData*)md; + ShrinkwrapModifierData *tsmd = (ShrinkwrapModifierData*)target; + + tsmd->target = smd->target; + tsmd->auxTarget = smd->auxTarget; + + strcpy(tsmd->vgroup_name, smd->vgroup_name); + + tsmd->keepDist = smd->keepDist; + tsmd->shrinkType= smd->shrinkType; + tsmd->shrinkOpts= smd->shrinkOpts; +} + +CustomDataMask shrinkwrapModifier_requiredDataMask(ModifierData *md) +{ + ShrinkwrapModifierData *smd = (ShrinkwrapModifierData *)md; + CustomDataMask dataMask = 0; + + /* ask for vertexgroups if we need them */ + if(smd->vgroup_name[0]) + dataMask |= (1 << CD_MDEFORMVERT); + + if(smd->shrinkType == MOD_SHRINKWRAP_PROJECT + && smd->projAxis == MOD_SHRINKWRAP_PROJECT_OVER_NORMAL) + dataMask |= (1 << CD_MVERT); + + return dataMask; +} + +static int shrinkwrapModifier_isDisabled(ModifierData *md) +{ + ShrinkwrapModifierData *smd = (ShrinkwrapModifierData*) md; + return !smd->target; +} + + +static void shrinkwrapModifier_foreachObjectLink(ModifierData *md, Object *ob, ObjectWalkFunc walk, void *userData) +{ + ShrinkwrapModifierData *smd = (ShrinkwrapModifierData*) md; + + walk(userData, ob, &smd->target); + walk(userData, ob, &smd->auxTarget); +} + +static void shrinkwrapModifier_deformVerts(ModifierData *md, Object *ob, DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts) +{ + DerivedMesh *dm = NULL; + CustomDataMask dataMask = shrinkwrapModifier_requiredDataMask(md); + + /* We implement requiredDataMask but thats not really usefull since mesh_calc_modifiers pass a NULL derivedData or without the modified vertexs applied */ + if(shrinkwrapModifier_requiredDataMask(md)) + { + if(derivedData) dm = CDDM_copy(derivedData); + else if(ob->type==OB_MESH) dm = CDDM_from_mesh(ob->data, ob); + else return; + + if(dataMask & CD_MVERT) + { + CDDM_apply_vert_coords(dm, vertexCos); + CDDM_calc_normals(dm); + } + } + + shrinkwrapModifier_deform((ShrinkwrapModifierData*)md, ob, dm, vertexCos, numVerts); + + if(dm) + dm->release(dm); +} + +static void shrinkwrapModifier_deformVertsEM(ModifierData *md, Object *ob, EditMesh *editData, DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts) +{ + DerivedMesh *dm = NULL; + CustomDataMask dataMask = shrinkwrapModifier_requiredDataMask(md); + + if(dataMask) + { + if(derivedData) dm = CDDM_copy(derivedData); + else if(ob->type==OB_MESH) dm = CDDM_from_editmesh(editData, ob->data); + else return; + + if(dataMask & CD_MVERT) + { + CDDM_apply_vert_coords(dm, vertexCos); + CDDM_calc_normals(dm); + } + } + + shrinkwrapModifier_deform((ShrinkwrapModifierData*)md, ob, dm, vertexCos, numVerts); + + if(dm) + dm->release(dm); +} + +static void shrinkwrapModifier_updateDepgraph(ModifierData *md, DagForest *forest, Object *ob, DagNode *obNode) +{ + ShrinkwrapModifierData *smd = (ShrinkwrapModifierData*) md; + + if (smd->target) + dag_add_relation(forest, dag_get_node(forest, smd->target), obNode, DAG_RL_OB_DATA | DAG_RL_DATA_DATA, "Shrinkwrap Modifier"); + + if (smd->auxTarget) + dag_add_relation(forest, dag_get_node(forest, smd->auxTarget), obNode, DAG_RL_OB_DATA | DAG_RL_DATA_DATA, "Shrinkwrap Modifier"); +} + /***/ static ModifierTypeInfo typeArr[NUM_MODIFIER_TYPES]; @@ -7557,6 +7663,21 @@ ModifierTypeInfo *modifierType_getInfo(ModifierType type) mti->requiredDataMask = explodeModifier_requiredDataMask; mti->applyModifier = explodeModifier_applyModifier; + mti = INIT_TYPE(Shrinkwrap); + mti->type = eModifierTypeType_OnlyDeform; + mti->flags = eModifierTypeFlag_AcceptsMesh + | eModifierTypeFlag_AcceptsCVs + | eModifierTypeFlag_SupportsEditmode + | eModifierTypeFlag_EnableInEditmode; + mti->initData = shrinkwrapModifier_initData; + mti->copyData = shrinkwrapModifier_copyData; + mti->requiredDataMask = shrinkwrapModifier_requiredDataMask; + mti->isDisabled = shrinkwrapModifier_isDisabled; + mti->foreachObjectLink = shrinkwrapModifier_foreachObjectLink; + mti->deformVerts = shrinkwrapModifier_deformVerts; + mti->deformVertsEM = shrinkwrapModifier_deformVertsEM; + mti->updateDepgraph = shrinkwrapModifier_updateDepgraph; + typeArrInit = 0; #undef INIT_TYPE } diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c index 643f90637ad..15d6f71073f 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) @@ -373,8 +379,11 @@ void psys_free_children(ParticleSystem *psys) } /* free everything */ void psys_free(Object *ob, ParticleSystem * psys) -{ +{ if(psys){ + int nr = 0; + ParticleSystem * tpsys; + if(ob->particlesystem.first == NULL && G.f & G_PARTICLEEDIT) G.f &= ~G_PARTICLEEDIT; @@ -400,6 +409,21 @@ void psys_free(Object *ob, ParticleSystem * psys) if(psys->effectors.first) psys_end_effectors(psys); + + // check if we are last non-visible particle system + for(tpsys=ob->particlesystem.first; tpsys; tpsys=tpsys->next){ + if(tpsys->part) + { + if(ELEM(tpsys->part->draw_as,PART_DRAW_OB,PART_DRAW_GR)) + { + nr++; + break; + } + } + } + // clear do-not-draw-flag + if(!nr) + ob->transflag &= ~OB_DUPLIPARTS; if(psys->part){ psys->part->id.us--; @@ -411,7 +435,7 @@ void psys_free(Object *ob, ParticleSystem * psys) if(psys->pointcache) BKE_ptcache_free(psys->pointcache); - + MEM_freeN(psys); } } @@ -3015,6 +3039,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 d1c0cdec71d..92c2f27bc31 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" @@ -2208,174 +2209,6 @@ static int get_particles_from_cache(Object *ob, ParticleSystem *psys, int cfra) /************************************************/ /* Effectors */ /************************************************/ -static float falloff_func(float fac, int usemin, float mindist, int usemax, float maxdist, float power) -{ - if(!usemin) - mindist= 0.0f; - - if(fac < mindist) { - return 1.0f; - } - else if(usemax) { - if(fac>maxdist || (maxdist-mindist)<=0.0f) - return 0.0f; - - fac= (fac-mindist)/(maxdist-mindist); - return 1.0f - (float)pow((double)fac, (double)power); - } - else - return pow((double)1.0f+fac-mindist, (double)-power); -} - -static float falloff_func_dist(PartDeflect *pd, float fac) -{ - return falloff_func(fac, pd->flag&PFIELD_USEMIN, pd->mindist, pd->flag&PFIELD_USEMAX, pd->maxdist, pd->f_power); -} - -static float falloff_func_rad(PartDeflect *pd, float fac) -{ - return falloff_func(fac, pd->flag&PFIELD_USEMINR, pd->minrad, pd->flag&PFIELD_USEMAXR, pd->maxrad, pd->f_power_r); -} - -static 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; - - VecCopyf(eff_dir,eff_velocity); - Normalize(eff_dir); - - if(pd->flag & PFIELD_POSZ && Inpf(eff_dir,vec_to_part)<0.0f) - falloff=0.0f; - else switch(pd->falloff){ - case PFIELD_FALL_SPHERE: - fac=VecLength(vec_to_part); - falloff= falloff_func_dist(pd, fac); - break; - - case PFIELD_FALL_TUBE: - fac=Inpf(vec_to_part,eff_dir); - falloff= falloff_func_dist(pd, ABS(fac)); - if(falloff == 0.0f) - break; - - VECADDFAC(temp,vec_to_part,eff_dir,-fac); - r_fac=VecLength(temp); - falloff*= falloff_func_rad(pd, r_fac); - break; - case PFIELD_FALL_CONE: - fac=Inpf(vec_to_part,eff_dir); - falloff= falloff_func_dist(pd, ABS(fac)); - if(falloff == 0.0f) - break; - - r_fac=saacos(fac/VecLength(vec_to_part))*180.0f/(float)M_PI; - falloff*= falloff_func_rad(pd, r_fac); - - break; -// case PFIELD_FALL_INSIDE: - //for(i=0; i<totface; i++,mface++){ - // VECCOPY(v1,mvert[mface->v1].co); - // VECCOPY(v2,mvert[mface->v2].co); - // VECCOPY(v3,mvert[mface->v3].co); - - // if(AxialLineIntersectsTriangle(a,co1, co2, v2, v3, v1, &lambda)){ - // if(from==PART_FROM_FACE) - // (pa+(int)(lambda*size[a])*a0mul)->flag &= ~PARS_UNEXIST; - // else /* store number of intersections */ - // (pa+(int)(lambda*size[a])*a0mul)->loop++; - // } - // - // if(mface->v4){ - // VECCOPY(v4,mvert[mface->v4].co); - - // if(AxialLineIntersectsTriangle(a,co1, co2, v4, v1, v3, &lambda)){ - // if(from==PART_FROM_FACE) - // (pa+(int)(lambda*size[a])*a0mul)->flag &= ~PARS_UNEXIST; - // else - // (pa+(int)(lambda*size[a])*a0mul)->loop++; - // } - // } - //} - -// break; - } - - return falloff; -} -static 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) -{ - float mag_vec[3]={0,0,0}; - float temp[3], temp2[3]; - float eff_vel[3]; - - VecCopyf(eff_vel,eff_velocity); - Normalize(eff_vel); - - switch(type){ - case PFIELD_WIND: - VECCOPY(mag_vec,eff_vel); - - VecMulf(mag_vec,force_val*falloff); - VecAddf(field,field,mag_vec); - break; - - case PFIELD_FORCE: - if(planar) - Projf(mag_vec,vec_to_part,eff_vel); - else - VecCopyf(mag_vec,vec_to_part); - - VecMulf(mag_vec,force_val*falloff); - VecAddf(field,field,mag_vec); - break; - - case PFIELD_VORTEX: - Crossf(mag_vec,eff_vel,vec_to_part); - Normalize(mag_vec); - - VecMulf(mag_vec,force_val*distance*falloff); - VecAddf(field,field,mag_vec); - - break; - case PFIELD_MAGNET: - if(planar) - VecCopyf(temp,eff_vel); - else - /* magnetic field of a moving charge */ - Crossf(temp,eff_vel,vec_to_part); - - Crossf(temp2,velocity,temp); - VecAddf(mag_vec,mag_vec,temp2); - - VecMulf(mag_vec,force_val*falloff); - VecAddf(field,field,mag_vec); - break; - case PFIELD_HARMONIC: - if(planar) - Projf(mag_vec,vec_to_part,eff_vel); - else - VecCopyf(mag_vec,vec_to_part); - - VecMulf(mag_vec,force_val*falloff); - VecSubf(field,field,mag_vec); - - VecCopyf(mag_vec,velocity); - /* 1.9 is an experimental value to get critical damping at damp=1.0 */ - 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); - break; - } -} 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]; @@ -2468,7 +2301,15 @@ static void add_to_effectors(ListBase *lb, Object *ob, Object *obsrc, ParticleSy } } else if(pd->forcefield) + { type |= PSYS_EC_EFFECTOR; + + if(pd->forcefield == PFIELD_WIND) + { + pd->rng = rng_new(1); + rng_srandom(pd->rng, (unsigned int)(ceil(PIL_check_seconds_timer()))); // use better seed + } + } } if(pd && pd->deflect) @@ -2493,10 +2334,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) { @@ -2579,6 +2421,9 @@ void psys_end_effectors(ParticleSystem *psys) if(ec->tree) BLI_kdtree_free(ec->tree); + + if(ec->ob->pd && (ec->ob->pd->forcefield == PFIELD_WIND)) + rng_free(ec->ob->pd->rng); } BLI_freelistN(lb); @@ -2745,35 +2590,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); @@ -2786,22 +2627,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); + 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; @@ -2813,31 +2654,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); + 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 */ @@ -3948,27 +3785,44 @@ static void boid_body(BoidVecFunc *bvf, ParticleData *pa, ParticleSystem *psys, bvf->Addf(dvec,dvec,bvec); bvf->Addf(state->co,state->co,dvec); - /* air speed from wind effectors */ - if(psys->effectors.first){ + /* air speed from wind and vortex effectors */ + if(psys->effectors.first) { ParticleEffectorCache *ec; - for(ec=psys->effectors.first; ec; ec=ec->next){ - if(ec->type & PSYS_EC_EFFECTOR){ + for(ec=psys->effectors.first; ec; ec=ec->next) { + if(ec->type & PSYS_EC_EFFECTOR) { Object *eob = ec->ob; PartDeflect *pd = eob->pd; + float direction[3], vec_to_part[3]; + float falloff; + + if(pd->f_strength != 0.0f) { + VecCopyf(direction, eob->obmat[2]); + VecSubf(vec_to_part, state->co, eob->obmat[3]); + + falloff=effector_falloff(pd, direction, vec_to_part); + + switch(pd->forcefield) { + case PFIELD_WIND: + if(falloff <= 0.0f) + ; /* don't do anything */ + else { + Normalize(direction); + VecMulf(direction, pd->f_strength * falloff); + bvf->Addf(state->co, state->co, direction); + } + break; + case PFIELD_VORTEX: + { + float distance, mag_vec[3]; + Crossf(mag_vec, direction, vec_to_part); + Normalize(mag_vec); - if(pd->forcefield==PFIELD_WIND && pd->f_strength!=0.0){ - float distance, wind[3]; - VecCopyf(wind,eob->obmat[2]); - distance=VecLenf(state->co,eob->obmat[3]); - - if (distance < 0.001) distance = 0.001f; + distance = VecLength(vec_to_part); - if(pd->flag&PFIELD_USEMAX && distance > pd->maxdist) - ; - else{ - Normalize(wind); - VecMulf(wind,pd->f_strength/(float)pow((double)distance,(double)pd->f_power)); - bvf->Addf(state->co,state->co,wind); + VecMulf(mag_vec, pd->f_strength * distance * falloff); + bvf->Addf(state->co, state->co, mag_vec); + break; + } } } } diff --git a/source/blender/blenkernel/intern/sca.c b/source/blender/blenkernel/intern/sca.c index fcf1c7ce311..47d11bb9d29 100644 --- a/source/blender/blenkernel/intern/sca.c +++ b/source/blender/blenkernel/intern/sca.c @@ -153,6 +153,9 @@ void init_sensor(bSensor *sens) case SENS_ACTUATOR: sens->data= MEM_callocN(sizeof(bActuatorSensor), "actsens"); break; + case SENS_DELAY: + sens->data= MEM_callocN(sizeof(bDelaySensor), "delaysens"); + break; case SENS_MOUSE: ms=sens->data= MEM_callocN(sizeof(bMouseSensor), "mousesens"); ms->type= LEFTMOUSE; diff --git a/source/blender/blenkernel/intern/shrinkwrap.c b/source/blender/blenkernel/intern/shrinkwrap.c new file mode 100644 index 00000000000..c60535cade2 --- /dev/null +++ b/source/blender/blenkernel/intern/shrinkwrap.c @@ -0,0 +1,588 @@ +/** + * shrinkwrap.c + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): André Pinto + * + * ***** END GPL LICENSE BLOCK ***** + */ +#include <string.h> +#include <float.h> +#include <math.h> +#include <memory.h> +#include <stdio.h> +#include <time.h> +#include <assert.h> + +#include "DNA_object_types.h" +#include "DNA_modifier_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_mesh_types.h" + +#include "BKE_shrinkwrap.h" +#include "BKE_DerivedMesh.h" +#include "BKE_utildefines.h" +#include "BKE_deform.h" +#include "BKE_cdderivedmesh.h" +#include "BKE_displist.h" +#include "BKE_global.h" +#include "BKE_subsurf.h" + +#include "BLI_arithb.h" +#include "BLI_kdtree.h" +#include "BLI_kdopbvh.h" + +#include "RE_raytrace.h" +#include "MEM_guardedalloc.h" + + +/* Util macros */ +#define TO_STR(a) #a +#define JOIN(a,b) a##b + +#define OUT_OF_MEMORY() ((void)printf("Shrinkwrap: Out of memory\n")) + +/* Benchmark macros */ +#if !defined(_WIN32) && 0 + +#include <sys/time.h> + +#define BENCH(a) \ + do { \ + double _t1, _t2; \ + struct timeval _tstart, _tend; \ + clock_t _clock_init = clock(); \ + gettimeofday ( &_tstart, NULL); \ + (a); \ + gettimeofday ( &_tend, NULL); \ + _t1 = ( double ) _tstart.tv_sec + ( double ) _tstart.tv_usec/ ( 1000*1000 ); \ + _t2 = ( double ) _tend.tv_sec + ( double ) _tend.tv_usec/ ( 1000*1000 ); \ + printf("%s: %fs (real) %fs (cpu)\n", #a, _t2-_t1, (float)(clock()-_clock_init)/CLOCKS_PER_SEC);\ + } while(0) + +#else + +#define BENCH(a) (a) + +#endif + +typedef void ( *Shrinkwrap_ForeachVertexCallback) (DerivedMesh *target, float *co, float *normal); + +/* get derived mesh */ +//TODO is anyfunction that does this? returning the derivedFinal witouth we caring if its in edit mode or not? +DerivedMesh *object_get_derived_final(Object *ob, CustomDataMask dataMask) +{ + if (ob==G.obedit) + { + DerivedMesh *final = NULL; + editmesh_get_derived_cage_and_final(&final, dataMask); + return final; + } + else + return mesh_get_derived_final(ob, dataMask); +} + +/* Space transform */ +void space_transform_from_matrixs(SpaceTransform *data, float local[4][4], float target[4][4]) +{ + float itarget[4][4]; + Mat4Invert(itarget, target); + Mat4MulSerie(data->local2target, itarget, local, 0, 0, 0, 0, 0, 0); + Mat4Invert(data->target2local, data->local2target); +} + +void space_transform_apply(const SpaceTransform *data, float *co) +{ + VecMat4MulVecfl(co, ((SpaceTransform*)data)->local2target, co); +} + +void space_transform_invert(const SpaceTransform *data, float *co) +{ + VecMat4MulVecfl(co, ((SpaceTransform*)data)->target2local, co); +} + +void space_transform_apply_normal(const SpaceTransform *data, float *no) +{ + Mat4Mul3Vecfl( ((SpaceTransform*)data)->local2target, no); + Normalize(no); // TODO: could we just determine de scale value from the matrix? +} + +void space_transform_invert_normal(const SpaceTransform *data, float *no) +{ + Mat4Mul3Vecfl(((SpaceTransform*)data)->target2local, no); + Normalize(no); // TODO: could we just determine de scale value from the matrix? +} + +/* + * Returns the squared distance between two given points + */ +static float squared_dist(const float *a, const float *b) +{ + float tmp[3]; + VECSUB(tmp, a, b); + return INPR(tmp, tmp); +} + +/* Main shrinkwrap function */ +void shrinkwrapModifier_deform(ShrinkwrapModifierData *smd, Object *ob, DerivedMesh *dm, float (*vertexCos)[3], int numVerts) +{ + + ShrinkwrapCalcData calc = NULL_ShrinkwrapCalcData; + + //remove loop dependencies on derived meshs (TODO should this be done elsewhere?) + if(smd->target == ob) smd->target = NULL; + if(smd->auxTarget == ob) smd->auxTarget = NULL; + + + //Configure Shrinkwrap calc data + calc.smd = smd; + calc.ob = ob; + calc.original = dm; + calc.numVerts = numVerts; + calc.vertexCos = vertexCos; + + if(smd->target) + { + //TODO currently we need a copy in case object_get_derived_final returns an emDM that does not defines getVertArray or getFace array + calc.target = CDDM_copy( object_get_derived_final(smd->target, CD_MASK_BAREMESH) ); + + //TODO there might be several "bugs" on non-uniform scales matrixs.. because it will no longer be nearest surface, not sphere projection + //because space has been deformed + space_transform_setup(&calc.local2target, ob, smd->target); + + calc.keepDist = smd->keepDist; //TODO: smd->keepDist is in global units.. must change to local + } + + + //Projecting target defined - lets work! + if(calc.target) + { + switch(smd->shrinkType) + { + case MOD_SHRINKWRAP_NEAREST_SURFACE: + BENCH(shrinkwrap_calc_nearest_surface_point(&calc)); + break; + + case MOD_SHRINKWRAP_PROJECT: + BENCH(shrinkwrap_calc_normal_projection(&calc)); + break; + + case MOD_SHRINKWRAP_NEAREST_VERTEX: + BENCH(shrinkwrap_calc_nearest_vertex(&calc)); + break; + } + } + + //free memory + if(calc.target) + calc.target->release( calc.target ); +} + +/* + * Shrinkwrap to the nearest vertex + * + * it builds a kdtree of vertexs we can attach to and then + * for each vertex performs a nearest vertex search on the tree + */ +void shrinkwrap_calc_nearest_vertex(ShrinkwrapCalcData *calc) +{ + int i; + const int vgroup = get_named_vertexgroup_num(calc->ob, calc->smd->vgroup_name); + MDeformVert *const dvert = calc->original ? calc->original->getVertDataArray(calc->original, CD_MDEFORMVERT) : NULL; + + BVHTreeFromMesh treeData = NULL_BVHTreeFromMesh; + BVHTreeNearest nearest = NULL_BVHTreeNearest; + + + BENCH(bvhtree_from_mesh_verts(&treeData, calc->target, 0.0, 2, 6)); + if(treeData.tree == NULL) return OUT_OF_MEMORY(); + + //Setup nearest + nearest.index = -1; + nearest.dist = FLT_MAX; + +#pragma omp parallel for default(none) private(i) firstprivate(nearest) shared(treeData,calc) schedule(static) + for(i = 0; i<calc->numVerts; ++i) + { + float *co = calc->vertexCos[i]; + float tmp_co[3]; + float weight = vertexgroup_get_vertex_weight(dvert, i, vgroup); + if(weight == 0.0f) continue; + + VECCOPY(tmp_co, co); + space_transform_apply(&calc->local2target, tmp_co); //Convert the coordinates to the tree coordinates + + //Use local proximity heuristics (to reduce the nearest search) + // + //If we already had an hit before.. we assume this vertex is going to have a close hit to that other vertex + //so we can initiate the "nearest.dist" with the expected value to that last hit. + //This will lead in prunning of the search tree. + if(nearest.index != -1) + nearest.dist = squared_dist(tmp_co, nearest.co); + else + nearest.dist = FLT_MAX; + + BLI_bvhtree_find_nearest(treeData.tree, tmp_co, &nearest, treeData.nearest_callback, &treeData); + + + //Found the nearest vertex + if(nearest.index != -1) + { + //Adjusting the vertex weight, so that after interpolating it keeps a certain distance from the nearest position + float dist = sasqrt(nearest.dist); + if(dist > FLT_EPSILON) weight *= (dist - calc->keepDist)/dist; + + //Convert the coordinates back to mesh coordinates + VECCOPY(tmp_co, nearest.co); + space_transform_invert(&calc->local2target, tmp_co); + + VecLerpf(co, co, tmp_co, weight); //linear interpolation + } + } + + free_bvhtree_from_mesh(&treeData); +} + +/* + * This function raycast a single vertex and updates the hit if the "hit" is considered valid. + * Returns TRUE if "hit" was updated. + * Opts control whether an hit is valid or not + * Supported options are: + * MOD_SHRINKWRAP_CULL_TARGET_FRONTFACE (front faces hits are ignored) + * MOD_SHRINKWRAP_CULL_TARGET_BACKFACE (back faces hits are ignored) + */ +int normal_projection_project_vertex(char options, const float *vert, const float *dir, const SpaceTransform *transf, BVHTree *tree, BVHTreeRayHit *hit, BVHTree_RayCastCallback callback, void *userdata) +{ + float tmp_co[3], tmp_no[3]; + const float *co, *no; + BVHTreeRayHit hit_tmp; + + //Copy from hit (we need to convert hit rays from one space coordinates to the other + memcpy( &hit_tmp, hit, sizeof(hit_tmp) ); + + //Apply space transform (TODO readjust dist) + if(transf) + { + VECCOPY( tmp_co, vert ); + space_transform_apply( transf, tmp_co ); + co = tmp_co; + + VECCOPY( tmp_no, dir ); + space_transform_apply_normal( transf, tmp_no ); + no = tmp_no; + + hit_tmp.dist *= Mat4ToScalef( ((SpaceTransform*)transf)->local2target ); + } + else + { + co = vert; + no = dir; + } + + hit_tmp.index = -1; + + BLI_bvhtree_ray_cast(tree, co, no, &hit_tmp, callback, userdata); + + if(hit_tmp.index != -1) + { + float dot = INPR( dir, hit_tmp.no); + + if(((options & MOD_SHRINKWRAP_CULL_TARGET_FRONTFACE) && dot <= 0.0f) + || ((options & MOD_SHRINKWRAP_CULL_TARGET_BACKFACE) && dot >= 0.0f)) + return FALSE; //Ignore hit + + + //Inverting space transform (TODO make coeherent with the initial dist readjust) + if(transf) + { + space_transform_invert( transf, hit_tmp.co ); + space_transform_invert_normal( transf, hit_tmp.no ); + + hit_tmp.dist = VecLenf( (float*)vert, hit_tmp.co ); + } + + memcpy(hit, &hit_tmp, sizeof(hit_tmp) ); + return TRUE; + } + return FALSE; +} + + +void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc) +{ + int i; + + //Options about projection direction + const char use_normal = calc->smd->shrinkOpts; + float proj_axis[3] = {0.0f, 0.0f, 0.0f}; + MVert *vert = NULL; //Needed in case of vertex normal + DerivedMesh* ss_mesh = NULL; + + //Vertex group data + const int vgroup = get_named_vertexgroup_num(calc->ob, calc->smd->vgroup_name); + const MDeformVert *dvert = calc->original ? calc->original->getVertDataArray(calc->original, CD_MDEFORMVERT) : NULL; + + + //Raycast and tree stuff + BVHTreeRayHit hit; + BVHTreeFromMesh treeData = NULL_BVHTreeFromMesh; //target + + //auxiliar target + DerivedMesh * aux_mesh = NULL; + BVHTreeFromMesh auxData= NULL_BVHTreeFromMesh; + SpaceTransform local2aux; + +do +{ + + //Prepare data to retrieve the direction in which we should project each vertex + if(calc->smd->projAxis == MOD_SHRINKWRAP_PROJECT_OVER_NORMAL) + { + //No Mvert information: jump to "free memory and return" part + if(calc->original == NULL) break; + + if(calc->smd->subsurfLevels) + { + SubsurfModifierData smd; + memset(&smd, 0, sizeof(smd)); + smd.subdivType = ME_CC_SUBSURF; //catmull clark + smd.levels = calc->smd->subsurfLevels; //levels + + ss_mesh = subsurf_make_derived_from_derived(calc->original, &smd, FALSE, NULL, 0, 0); + + if(ss_mesh) + { + vert = ss_mesh->getVertDataArray(ss_mesh, CD_MVERT); + if(vert) + { + //TRICKY: this code assumes subsurface will have the transformed original vertices + //in their original order at the end of the vert array. + vert = vert + + ss_mesh->getNumVerts(ss_mesh) + - calc->original->getNumVerts(calc->original); + } + } + + //To make sure we are not letting any memory behind + assert(smd.emCache == NULL); + assert(smd.mCache == NULL); + } + else + vert = calc->original->getVertDataArray(calc->original, CD_MVERT); + + //Not able to get vert information: jump to "free memory and return" part + if(vert == NULL) break; + } + else + { + //The code supports any axis that is a combination of X,Y,Z.. altought currently UI only allows to set the 3 diferent axis + if(calc->smd->projAxis & MOD_SHRINKWRAP_PROJECT_OVER_X_AXIS) proj_axis[0] = 1.0f; + if(calc->smd->projAxis & MOD_SHRINKWRAP_PROJECT_OVER_Y_AXIS) proj_axis[1] = 1.0f; + if(calc->smd->projAxis & MOD_SHRINKWRAP_PROJECT_OVER_Z_AXIS) proj_axis[2] = 1.0f; + + Normalize(proj_axis); + + //Invalid projection direction: jump to "free memory and return" part + if(INPR(proj_axis, proj_axis) < FLT_EPSILON) break; + } + + //If the user doesn't allows to project in any direction of projection axis... then theres nothing todo. + if((use_normal & (MOD_SHRINKWRAP_PROJECT_ALLOW_POS_DIR | MOD_SHRINKWRAP_PROJECT_ALLOW_NEG_DIR)) == 0) + break; //jump to "free memory and return" part + + + //Build target tree + BENCH(bvhtree_from_mesh_faces(&treeData, calc->target, calc->keepDist, 4, 6)); + if(treeData.tree == NULL) + break; //jump to "free memory and return" part + + + //Build auxiliar target + if(calc->smd->auxTarget) + { + space_transform_setup( &local2aux, calc->ob, calc->smd->auxTarget); + + aux_mesh = CDDM_copy( object_get_derived_final(calc->smd->auxTarget, CD_MASK_BAREMESH) ); //TODO currently we need a copy in case object_get_derived_final returns an emDM that does not defines getVertArray or getFace array + if(aux_mesh) + BENCH(bvhtree_from_mesh_faces(&auxData, aux_mesh, 0.0, 4, 6)); + else + printf("Auxiliar target finalDerived mesh is null\n"); + } + + + //Now, everything is ready to project the vertexs! +#pragma omp parallel for private(i,hit) schedule(static) + for(i = 0; i<calc->numVerts; ++i) + { + float *co = calc->vertexCos[i]; + float tmp_co[3], tmp_no[3]; + float lim = 10000.0f; //TODO: we should use FLT_MAX here, but sweepsphere code isnt prepared for that + float weight = vertexgroup_get_vertex_weight(dvert, i, vgroup); + + if(weight == 0.0f) continue; + + if(ss_mesh) + { + VECCOPY(tmp_co, vert[i].co); + } + else + { + VECCOPY(tmp_co, co); + } + + + if(vert) + NormalShortToFloat(tmp_no, vert[i].no); + else + VECCOPY( tmp_no, proj_axis ); + + + hit.index = -1; + hit.dist = lim; + + + //Project over positive direction of axis + if(use_normal & MOD_SHRINKWRAP_PROJECT_ALLOW_POS_DIR) + { + + if(auxData.tree) + normal_projection_project_vertex(0, tmp_co, tmp_no, &local2aux, auxData.tree, &hit, auxData.raycast_callback, &auxData); + + normal_projection_project_vertex(calc->smd->shrinkOpts, tmp_co, tmp_no, &calc->local2target, treeData.tree, &hit, treeData.raycast_callback, &treeData); + } + + //Project over negative direction of axis + if(use_normal & MOD_SHRINKWRAP_PROJECT_ALLOW_NEG_DIR) + { + float inv_no[3] = { -tmp_no[0], -tmp_no[1], -tmp_no[2] }; + + + if(auxData.tree) + normal_projection_project_vertex(0, tmp_co, inv_no, &local2aux, auxData.tree, &hit, auxData.raycast_callback, &auxData); + + normal_projection_project_vertex(calc->smd->shrinkOpts, tmp_co, inv_no, &calc->local2target, treeData.tree, &hit, treeData.raycast_callback, &treeData); + } + + + if(hit.index != -1) + { + VecLerpf(co, co, hit.co, weight); + } + } + + +//Simple do{} while(0) structure to allow to easily jump to the "free memory and return" part +} while(0); + + //free data structures + + free_bvhtree_from_mesh(&treeData); + free_bvhtree_from_mesh(&auxData); + + if(aux_mesh) + aux_mesh->release(aux_mesh); + + if(ss_mesh) + ss_mesh->release(ss_mesh); +} + +/* + * Shrinkwrap moving vertexs to the nearest surface point on the target + * + * it builds a BVHTree from the target mesh and then performs a + * NN matchs for each vertex + */ +void shrinkwrap_calc_nearest_surface_point(ShrinkwrapCalcData *calc) +{ + int i; + + const int vgroup = get_named_vertexgroup_num(calc->ob, calc->smd->vgroup_name); + const MDeformVert *const dvert = calc->original ? calc->original->getVertDataArray(calc->original, CD_MDEFORMVERT) : NULL; + + BVHTreeFromMesh treeData = NULL_BVHTreeFromMesh; + BVHTreeNearest nearest = NULL_BVHTreeNearest; + + + + //Create a bvh-tree of the given target + BENCH(bvhtree_from_mesh_faces( &treeData, calc->target, 0.0, 2, 6)); + if(treeData.tree == NULL) return OUT_OF_MEMORY(); + + //Setup nearest + nearest.index = -1; + nearest.dist = FLT_MAX; + + + //Find the nearest vertex +#pragma omp parallel for default(none) private(i) firstprivate(nearest) shared(calc,treeData) schedule(static) + for(i = 0; i<calc->numVerts; ++i) + { + float *co = calc->vertexCos[i]; + float tmp_co[3]; + float weight = vertexgroup_get_vertex_weight(dvert, i, vgroup); + if(weight == 0.0f) continue; + + //Convert the vertex to tree coordinates + VECCOPY(tmp_co, co); + space_transform_apply(&calc->local2target, tmp_co); + + //Use local proximity heuristics (to reduce the nearest search) + // + //If we already had an hit before.. we assume this vertex is going to have a close hit to that other vertex + //so we can initiate the "nearest.dist" with the expected value to that last hit. + //This will lead in prunning of the search tree. + if(nearest.index != -1) + nearest.dist = squared_dist(tmp_co, nearest.co); + else + nearest.dist = FLT_MAX; + + BLI_bvhtree_find_nearest(treeData.tree, tmp_co, &nearest, treeData.nearest_callback, &treeData); + + //Found the nearest vertex + if(nearest.index != -1) + { + if(calc->smd->shrinkOpts & MOD_SHRINKWRAP_KEEP_ABOVE_SURFACE) + { + //Make the vertex stay on the front side of the face + VECADDFAC(tmp_co, nearest.co, nearest.no, calc->keepDist); + } + else + { + //Adjusting the vertex weight, so that after interpolating it keeps a certain distance from the nearest position + float dist = sasqrt( nearest.dist ); + if(dist > FLT_EPSILON) + VecLerpf(tmp_co, tmp_co, nearest.co, (dist - calc->keepDist)/dist); //linear interpolation + else + VECCOPY( tmp_co, nearest.co ); + } + + //Convert the coordinates back to mesh coordinates + space_transform_invert(&calc->local2target, tmp_co); + VecLerpf(co, co, tmp_co, weight); //linear interpolation + } + } + + + free_bvhtree_from_mesh(&treeData); +} + diff --git a/source/blender/blenlib/BLI_editVert.h b/source/blender/blenlib/BLI_editVert.h index d42663e17c7..447f6a2a485 100644 --- a/source/blender/blenlib/BLI_editVert.h +++ b/source/blender/blenlib/BLI_editVert.h @@ -38,6 +38,8 @@ #include "DNA_customdata_types.h" #include "DNA_mesh_types.h" +#include "BLO_sys_types.h" // for intptr_t support + struct DerivedMesh; struct RetopoPaintData; @@ -53,7 +55,7 @@ typedef struct EditVert struct EditEdge *e; struct EditFace *f; void *p; - long l; + intptr_t l; float fp; } tmp; float no[3]; /*vertex normal */ @@ -95,7 +97,7 @@ typedef struct EditEdge struct EditEdge *e; struct EditFace *f; void *p; - long l; + intptr_t l; float fp; } tmp; short f1, f2; /* short, f1 is (ab)used in subdiv */ @@ -122,7 +124,7 @@ typedef struct EditFace struct EditEdge *e; struct EditFace *f; void *p; - long l; + intptr_t l; float fp; } tmp; float n[3], cent[3]; diff --git a/source/blender/blenlib/BLI_rand.h b/source/blender/blenlib/BLI_rand.h index 0e534783c17..266aa347aff 100644 --- a/source/blender/blenlib/BLI_rand.h +++ b/source/blender/blenlib/BLI_rand.h @@ -44,6 +44,7 @@ struct RNG* rng_new (unsigned int seed); void rng_free (struct RNG* rng); void rng_seed (struct RNG* rng, unsigned int seed); +void rng_srandom(struct RNG *rng, unsigned int seed); int rng_getInt (struct RNG* rng); double rng_getDouble (struct RNG* rng); float rng_getFloat (struct RNG* rng); diff --git a/source/blender/blenlib/BLI_winstuff.h b/source/blender/blenlib/BLI_winstuff.h index 11150075bac..3bb63506c95 100644 --- a/source/blender/blenlib/BLI_winstuff.h +++ b/source/blender/blenlib/BLI_winstuff.h @@ -61,6 +61,10 @@ // These definitions are also in arithb for simplicity +#ifdef __cplusplus +extern "C" { +#endif + #ifndef M_PI #define M_PI 3.14159265358979323846 #endif @@ -116,5 +120,9 @@ int closedir (DIR *dp); void get_default_root(char *root); int check_file_chars(char *filename); +#ifdef __cplusplus +} +#endif + #endif /* __WINSTUFF_H__ */ diff --git a/source/blender/blenlib/intern/BLI_ghash.c b/source/blender/blenlib/intern/BLI_ghash.c index 227cb8f5e9a..e9271ca3bb5 100644 --- a/source/blender/blenlib/intern/BLI_ghash.c +++ b/source/blender/blenlib/intern/BLI_ghash.c @@ -34,6 +34,8 @@ #include "MEM_guardedalloc.h" #include "BLI_ghash.h" +#include "BLO_sys_types.h" // for intptr_t support + #ifdef HAVE_CONFIG_H #include <config.h> #endif @@ -256,11 +258,7 @@ int BLI_ghashutil_ptrcmp(void *a, void *b) { } unsigned int BLI_ghashutil_inthash(void *ptr) { -#if defined(_WIN64) - unsigned __int64 key = (unsigned __int64)ptr; -#else - unsigned long key = (unsigned long)ptr; -#endif + uintptr_t key = (uintptr_t)ptr; key += ~(key << 16); key ^= (key >> 5); diff --git a/source/blender/blenlib/intern/BLI_kdopbvh.c b/source/blender/blenlib/intern/BLI_kdopbvh.c index 9671551a7f1..989e516d161 100644 --- a/source/blender/blenlib/intern/BLI_kdopbvh.c +++ b/source/blender/blenlib/intern/BLI_kdopbvh.c @@ -46,6 +46,7 @@ #define MAX_TREETYPE 32 +#define DEFAULT_FIND_NEAREST_HEAP_SIZE 1024 typedef struct BVHNode { @@ -81,7 +82,7 @@ typedef struct BVHOverlapData typedef struct BVHNearestData { BVHTree *tree; - float *co; + const float *co; BVHTree_NearestPointCallback callback; void *userdata; float proj[13]; //coordinates projection over axis @@ -119,6 +120,72 @@ static float KDOP_AXES[13][3] = {0, 1.0, -1.0} }; +/* + * Generic push and pop heap + */ +#define PUSH_HEAP_BODY(HEAP_TYPE,PRIORITY,heap,heap_size) \ +{ \ + HEAP_TYPE element = heap[heap_size-1]; \ + int child = heap_size-1; \ + while(child != 0) \ + { \ + int parent = (child-1) / 2; \ + if(PRIORITY(element, heap[parent])) \ + { \ + heap[child] = heap[parent]; \ + child = parent; \ + } \ + else break; \ + } \ + heap[child] = element; \ +} + +#define POP_HEAP_BODY(HEAP_TYPE, PRIORITY,heap,heap_size) \ +{ \ + HEAP_TYPE element = heap[heap_size-1]; \ + int parent = 0; \ + while(parent < (heap_size-1)/2 ) \ + { \ + int child2 = (parent+1)*2; \ + if(PRIORITY(heap[child2-1], heap[child2])) \ + --child2; \ + \ + if(PRIORITY(element, heap[child2])) \ + break; \ + \ + heap[parent] = heap[child2]; \ + parent = child2; \ + } \ + heap[parent] = element; \ +} + +int ADJUST_MEMORY(void *local_memblock, void **memblock, int new_size, int *max_size, int size_per_item) +{ + int new_max_size = *max_size * 2; + void *new_memblock = NULL; + + if(new_size <= *max_size) + return TRUE; + + if(*memblock == local_memblock) + { + new_memblock = malloc( size_per_item * new_max_size ); + memcpy( new_memblock, *memblock, size_per_item * *max_size ); + } + else + new_memblock = realloc(*memblock, size_per_item * new_max_size ); + + if(new_memblock) + { + *memblock = new_memblock; + *max_size = new_max_size; + return TRUE; + } + else + return FALSE; +} + + ////////////////////////////////////////////////////////////////////////////////////////////////////// // Introsort // with permission deriven from the following Java code: @@ -634,6 +701,18 @@ static void non_recursive_bvh_div_nodes(BVHTree *tree, BVHNode *branches_array, BVHBuildHelper data; int depth; + //Most of bvhtree code relies on 1-leaf trees having at least one branch + //We handle that special case here + if(num_leafs == 1) + { + BVHNode *root = branches_array+0; + refit_kdop_hull(tree, root, 0, num_leafs); + root->main_axis = get_largest_axis(root->bv) / 2; + root->totnode = 1; + root->children[0] = leafs_array[0]; + return; + } + branches_array--; //Implicit trees use 1-based indexs build_implicit_tree_helper(tree, &data); @@ -722,6 +801,11 @@ BVHTree *BLI_bvhtree_new(int maxsize, float epsilon, char tree_type, char axis) return NULL; tree = (BVHTree *)MEM_callocN(sizeof(BVHTree), "BVHTree"); + + //tree epsilon must be >= FLT_EPSILON + //so that tangent rays can still hit a bounding volume.. + //this bug would show up when casting a ray aligned with a kdop-axis and with an edge of 2 faces + epsilon = MAX2(FLT_EPSILON, epsilon); if(tree) { @@ -1114,15 +1198,18 @@ static float calc_nearest_point(BVHNearestData *data, BVHNode *node, float *near } -// TODO: use a priority queue to reduce the number of nodes looked on -static void dfs_find_nearest(BVHNearestData *data, BVHNode *node) +typedef struct NodeDistance { - int i; - float nearest[3], sdist; + BVHNode *node; + float dist; - sdist = calc_nearest_point(data, node, nearest); - if(sdist >= data->nearest.dist) return; +} NodeDistance; +#define NodeDistance_priority(a,b) ( (a).dist < (b).dist ) + +// TODO: use a priority queue to reduce the number of nodes looked on +static void dfs_find_nearest_dfs(BVHNearestData *data, BVHNode *node) +{ if(node->totnode == 0) { if(data->callback) @@ -1130,17 +1217,129 @@ static void dfs_find_nearest(BVHNearestData *data, BVHNode *node) else { data->nearest.index = node->index; - VECCOPY(data->nearest.co, nearest); - data->nearest.dist = sdist; + data->nearest.dist = calc_nearest_point(data, node, data->nearest.co); } } else { - for(i=0; i != node->totnode; i++) - dfs_find_nearest(data, node->children[i]); + //Better heuristic to pick the closest node to dive on + int i; + float nearest[3]; + + if(data->proj[ node->main_axis ] <= node->children[0]->bv[node->main_axis*2+1]) + { + + for(i=0; i != node->totnode; i++) + { + if( calc_nearest_point(data, node->children[i], nearest) >= data->nearest.dist) continue; + dfs_find_nearest_dfs(data, node->children[i]); + } + } + else + { + for(i=node->totnode-1; i >= 0 ; i--) + { + if( calc_nearest_point(data, node->children[i], nearest) >= data->nearest.dist) continue; + dfs_find_nearest_dfs(data, node->children[i]); + } + } } } +static void dfs_find_nearest_begin(BVHNearestData *data, BVHNode *node) +{ + float nearest[3], sdist; + sdist = calc_nearest_point(data, node, nearest); + if(sdist >= data->nearest.dist) return; + dfs_find_nearest_dfs(data, node); +} + + +static void NodeDistance_push_heap(NodeDistance *heap, int heap_size) +PUSH_HEAP_BODY(NodeDistance, NodeDistance_priority, heap, heap_size) + +static void NodeDistance_pop_heap(NodeDistance *heap, int heap_size) +POP_HEAP_BODY(NodeDistance, NodeDistance_priority, heap, heap_size) + +//NN function that uses an heap.. this functions leads to an optimal number of min-distance +//but for normal tri-faces and BV 6-dop.. a simple dfs with local heuristics (as implemented +//in source/blender/blenkernel/intern/shrinkwrap.c) works faster. +// +//It may make sense to use this function if the callback queries are very slow.. or if its impossible +//to get a nice heuristic +// +//this function uses "malloc/free" instead of the MEM_* because it intends to be openmp safe +static void bfs_find_nearest(BVHNearestData *data, BVHNode *node) +{ + int i; + NodeDistance default_heap[DEFAULT_FIND_NEAREST_HEAP_SIZE]; + NodeDistance *heap=default_heap, current; + int heap_size = 0, max_heap_size = sizeof(default_heap)/sizeof(default_heap[0]); + float nearest[3]; + + int callbacks = 0, push_heaps = 0; + + if(node->totnode == 0) + { + dfs_find_nearest_dfs(data, node); + return; + } + + current.node = node; + current.dist = calc_nearest_point(data, node, nearest); + + while(current.dist < data->nearest.dist) + { +// printf("%f : %f\n", current.dist, data->nearest.dist); + for(i=0; i< current.node->totnode; i++) + { + BVHNode *child = current.node->children[i]; + if(child->totnode == 0) + { + callbacks++; + dfs_find_nearest_dfs(data, child); + } + else + { + //adjust heap size + if(heap_size >= max_heap_size + && ADJUST_MEMORY(default_heap, (void**)&heap, heap_size+1, &max_heap_size, sizeof(heap[0])) == FALSE) + { + printf("WARNING: bvh_find_nearest got out of memory\n"); + + if(heap != default_heap) + free(heap); + + return; + } + + heap[heap_size].node = current.node->children[i]; + heap[heap_size].dist = calc_nearest_point(data, current.node->children[i], nearest); + + if(heap[heap_size].dist >= data->nearest.dist) continue; + heap_size++; + + NodeDistance_push_heap(heap, heap_size); + // PUSH_HEAP_BODY(NodeDistance, NodeDistance_priority, heap, heap_size); + push_heaps++; + } + } + + if(heap_size == 0) break; + + current = heap[0]; + NodeDistance_pop_heap(heap, heap_size); +// POP_HEAP_BODY(NodeDistance, NodeDistance_priority, heap, heap_size); + heap_size--; + } + +// printf("hsize=%d, callbacks=%d, pushs=%d\n", heap_size, callbacks, push_heaps); + + if(heap != default_heap) + free(heap); +} + + int BLI_bvhtree_find_nearest(BVHTree *tree, const float *co, BVHTreeNearest *nearest, BVHTree_NearestPointCallback callback, void *userdata) { int i; @@ -1172,7 +1371,7 @@ int BLI_bvhtree_find_nearest(BVHTree *tree, const float *co, BVHTreeNearest *nea //dfs search if(root) - dfs_find_nearest(&data, root); + dfs_find_nearest_begin(&data, root); //copy back results if(nearest) @@ -1212,7 +1411,7 @@ static float ray_nearest_hit(BVHRayCastData *data, BVHNode *node) float ll = (bv[0] - data->ray.origin[i]) / data->ray_dot_axis[i]; float lu = (bv[1] - data->ray.origin[i]) / data->ray_dot_axis[i]; - if(data->ray_dot_axis[i] > 0) + if(data->ray_dot_axis[i] > 0.0f) { if(ll > low) low = ll; if(lu < upper) upper = lu; @@ -1252,7 +1451,7 @@ static void dfs_raycast(BVHRayCastData *data, BVHNode *node) else { //pick loop direction to dive into the tree (based on ray direction and split axis) - if(data->ray_dot_axis[ node->main_axis ] > 0) + if(data->ray_dot_axis[ node->main_axis ] > 0.0f) { for(i=0; i != node->totnode; i++) { @@ -1289,7 +1488,7 @@ int BLI_bvhtree_ray_cast(BVHTree *tree, const float *co, const float *dir, BVHTr { data.ray_dot_axis[i] = INPR( data.ray.direction, KDOP_AXES[i]); - if(fabs(data.ray_dot_axis[i]) < 1e-7) + if(fabs(data.ray_dot_axis[i]) < FLT_EPSILON) data.ray_dot_axis[i] = 0.0; } diff --git a/source/blender/blenlib/intern/fileops.c b/source/blender/blenlib/intern/fileops.c index 96de5e99f4f..2acbbbe6712 100644 --- a/source/blender/blenlib/intern/fileops.c +++ b/source/blender/blenlib/intern/fileops.c @@ -62,6 +62,8 @@ #include "BKE_utildefines.h" #include <errno.h> +#include "BLO_sys_types.h" // for intptr_t support + /* implementations: */ char *first_slash(char *string) { char *ffslash, *fbslash; @@ -72,7 +74,7 @@ char *first_slash(char *string) { if (!ffslash) return fbslash; else if (!fbslash) return ffslash; - if ((long)ffslash < (long)fbslash) return ffslash; + if ((intptr_t)ffslash < (intptr_t)fbslash) return ffslash; else return fbslash; } @@ -85,7 +87,7 @@ char *BLI_last_slash(const char *string) { if (!lfslash) return lbslash; else if (!lbslash) return lfslash; - if ((long)lfslash < (long)lbslash) return lbslash; + if ((intptr_t)lfslash < (intptr_t)lbslash) return lbslash; else return lfslash; } diff --git a/source/blender/blenlib/intern/psfont.c b/source/blender/blenlib/intern/psfont.c index 498c87cdef9..216246dcdd7 100644 --- a/source/blender/blenlib/intern/psfont.c +++ b/source/blender/blenlib/intern/psfont.c @@ -43,6 +43,8 @@ #include "DNA_packedFile_types.h" #include "DNA_curve_types.h" +#include "BLO_sys_types.h" // for intptr_t support + #ifdef HAVE_CONFIG_H #include <config.h> #endif @@ -54,7 +56,7 @@ typedef struct chardesc { short llx, lly; /* bounding box */ short urx, ury; short *data; /* char data */ - long datalen; + intptr_t datalen; } chardesc; typedef struct objfnt { diff --git a/source/blender/blenlib/intern/rand.c b/source/blender/blenlib/intern/rand.c index ccc478203fe..c484a307393 100644 --- a/source/blender/blenlib/intern/rand.c +++ b/source/blender/blenlib/intern/rand.c @@ -81,6 +81,16 @@ void rng_seed(RNG *rng, unsigned int seed) { rng->X= (((r_uint64) seed)<<16) | LOWSEED; } +void rng_srandom(RNG *rng, unsigned int seed) { + extern unsigned char hash[]; // noise.c + + rng_seed(rng, seed + hash[seed & 255]); + seed= rng_getInt(rng); + rng_seed(rng, seed + hash[seed & 255]); + seed= rng_getInt(rng); + rng_seed(rng, seed + hash[seed & 255]); +} + int rng_getInt(RNG *rng) { rng->X= (MULTIPLIER*rng->X + ADDEND)&MASK; return (int) (rng->X>>17); @@ -132,13 +142,7 @@ void BLI_srand(unsigned int seed) { /* using hash table to create better seed */ void BLI_srandom(unsigned int seed) { - extern unsigned char hash[]; // noise.c - - rng_seed(&theBLI_rng, seed + hash[seed & 255]); - seed= rng_getInt(&theBLI_rng); - rng_seed(&theBLI_rng, seed + hash[seed & 255]); - seed= rng_getInt(&theBLI_rng); - rng_seed(&theBLI_rng, seed + hash[seed & 255]); + rng_srandom(&theBLI_rng, seed); } int BLI_rand(void) { diff --git a/source/blender/blenlib/intern/util.c b/source/blender/blenlib/intern/util.c index 48ebf770e1b..a31121148e3 100644 --- a/source/blender/blenlib/intern/util.c +++ b/source/blender/blenlib/intern/util.c @@ -1970,7 +1970,7 @@ void BLI_timestr(double _time, char *str) int BLI_int_from_pointer(void *poin) { - long lval= (long)poin; + intptr_t lval= (intptr_t)poin; return (int)(lval>>3); } @@ -1978,17 +1978,17 @@ int BLI_int_from_pointer(void *poin) void *BLI_pointer_from_int(int val) { static int firsttime= 1; - static long basevalue= 0; + static intptr_t basevalue= 0; if(firsttime) { void *poin= malloc(10000); - basevalue= (long)poin; + basevalue= (intptr_t)poin; basevalue &= ~PMASK; printf("base: %d pointer %p\n", basevalue, poin); /* debug */ firsttime= 0; free(poin); } - return (void *)(basevalue | (((long)val)<<3)); + return (void *)(basevalue | (((intptr_t)val)<<3)); } #else diff --git a/source/blender/blenloader/BLO_sys_types.h b/source/blender/blenloader/BLO_sys_types.h index a1885894fe3..a9d29375eac 100644 --- a/source/blender/blenloader/BLO_sys_types.h +++ b/source/blender/blenloader/BLO_sys_types.h @@ -43,11 +43,6 @@ #ifdef __cplusplus extern "C" { #endif - -#ifdef FREE_WINDOWS -typedef unsigned char uint8_t; -typedef unsigned int uint32_t; -#endif #if defined(_WIN32) && !defined(FREE_WINDOWS) @@ -64,6 +59,14 @@ typedef unsigned __int16 uint16_t; typedef unsigned __int32 uint32_t; typedef unsigned __int64 uint64_t; +#ifdef _WIN64 +typedef __int64 intptr_t; +typedef unsigned __int64 uintptr_t; +#else +typedef long intptr_t; +typedef unsigned long uintptr_t; +#endif + #elif defined(__linux__) /* Linux-i386, Linux-Alpha, Linux-ppc */ @@ -73,6 +76,10 @@ typedef unsigned __int64 uint64_t; #include <inttypes.h> +#elif defined(FREE_WINDOWS) + +#include <stdint.h> + #else /* FreeBSD, Irix, Solaris */ diff --git a/source/blender/blenloader/intern/genfile.c b/source/blender/blenloader/intern/genfile.c index 87c859de839..86338ca9e89 100644 --- a/source/blender/blenloader/intern/genfile.c +++ b/source/blender/blenloader/intern/genfile.c @@ -58,6 +58,8 @@ #include "genfile.h" +#include "BLO_sys_types.h" // for intptr_t support + /* gcc 4.1 on mingw was complaining that __int64 was alredy defined actually is saw the line below as typedef long long long long... Anyhow, since its alredy defined, its safe to do an ifndef here- Cambpell*/ @@ -315,7 +317,7 @@ static void init_structDNA(struct SDNA *sdna, int do_endian_swap) /* in sdna->data the data, now we convert that to something understandable */ { int *data, *verg; - long nr; + intptr_t nr; short *sp; char str[8], *cp; @@ -351,7 +353,7 @@ static void init_structDNA(struct SDNA *sdna, int do_endian_swap) cp++; nr++; } - nr= (long)cp; /* prevent BUS error */ + nr= (intptr_t)cp; /* prevent BUS error */ nr= (nr+3) & ~3; cp= (char *)nr; @@ -389,7 +391,7 @@ static void init_structDNA(struct SDNA *sdna, int do_endian_swap) cp++; nr++; } - nr= (long)cp; /* prevent BUS error */ + nr= (intptr_t)cp; /* prevent BUS error */ nr= (nr+3) & ~3; cp= (char *)nr; @@ -1098,7 +1100,7 @@ int dna_elem_offset(struct SDNA *sdna, char *stype, char *vartype, char *name) int SDNAnr= dna_findstruct_nr(sdna, stype); short *spo= sdna->structs[SDNAnr]; char *cp= find_elem(sdna, vartype, name, spo, NULL, NULL); - return (int)((long)cp); + return (int)((intptr_t)cp); } diff --git a/source/blender/blenloader/intern/readblenentry.c b/source/blender/blenloader/intern/readblenentry.c index f56b261efe2..5a75b5c8b11 100644 --- a/source/blender/blenloader/intern/readblenentry.c +++ b/source/blender/blenloader/intern/readblenentry.c @@ -63,6 +63,8 @@ #include "BLO_readblenfile.h" +#include "BLO_sys_types.h" // needed for intptr_t + /** * IDType stuff, I plan to move this * out into its own file + prefix, and @@ -193,7 +195,7 @@ void BLO_blendhandle_print_sizes(BlendHandle *bh, void *fp) buf[2]= buf[2]?buf[2]:' '; buf[3]= buf[3]?buf[3]:' '; - fprintf(fp, "['%.4s', '%s', %d, %ld ], \n", buf, name, bhead->nr, (long)bhead->len+sizeof(BHead)); + fprintf(fp, "['%.4s', '%s', %d, %ld ], \n", buf, name, bhead->nr, (intptr_t)bhead->len+sizeof(BHead)); } } fprintf(fp, "]\n"); diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 29fd314236b..6affec0e104 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -2583,6 +2583,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) @@ -2943,11 +2944,9 @@ static void lib_link_object(FileData *fd, Main *main) sens= ob->sensors.first; while(sens) { - if(ob->id.lib==NULL) { // done in expand_main - for(a=0; a<sens->totlinks; a++) { - sens->links[a]= newglobadr(fd, sens->links[a]); - } - } + for(a=0; a<sens->totlinks; a++) + sens->links[a]= newglobadr(fd, sens->links[a]); + if(sens->type==SENS_TOUCH) { bTouchSensor *ts= sens->data; ts->ma= newlibadr(fd, ob->id.lib, ts->ma); @@ -2962,11 +2961,9 @@ static void lib_link_object(FileData *fd, Main *main) cont= ob->controllers.first; while(cont) { - if(ob->id.lib==NULL) { // done in expand_main - for(a=0; a<cont->totlinks; a++) { - cont->links[a]= newglobadr(fd, cont->links[a]); - } - } + for(a=0; a<cont->totlinks; a++) + cont->links[a]= newglobadr(fd, cont->links[a]); + if(cont->type==CONT_PYTHON) { bPythonCont *pc= cont->data; pc->text= newlibadr(fd, ob->id.lib, pc->text); @@ -3594,9 +3591,9 @@ static void direct_link_scene(FileData *fd, Scene *sce) { Sequence temp; char *poin; - long offset; + intptr_t offset; - offset= ((long)&(temp.seqbase)) - ((long)&temp); + offset= ((intptr_t)&(temp.seqbase)) - ((intptr_t)&temp); /* root pointer */ if(ed->seqbasep == old_seqbasep) { @@ -4095,7 +4092,7 @@ static void direct_link_screen(FileData *fd, bScreen *sc) while(se) { se->v1= newdataadr(fd, se->v1); se->v2= newdataadr(fd, se->v2); - if( (long)se->v1 > (long)se->v2) { + if( (intptr_t)se->v1 > (intptr_t)se->v2) { sv= se->v1; se->v1= se->v2; se->v2= sv; @@ -7731,31 +7728,6 @@ static void do_versions(FileData *fd, Library *lib, Main *main) idproperties_fix_group_lengths(main->brush); idproperties_fix_group_lengths(main->particle); } - - /* only needed until old bad svn/RC1,2 files are saved with a > 17 version -dg */ - if(main->versionfile == 245 && main->subversionfile < 17) { - ModifierData *md; - Object *ob; - - for(ob = main->object.first; ob; ob= ob->id.next) { - for(md=ob->modifiers.first; md; ) { - if(md->type==eModifierType_Cloth) { - ModifierData *next; - MEM_freeN(((ClothModifierData *)md)->sim_parms); - MEM_freeN(((ClothModifierData *)md)->coll_parms); - MEM_freeN(((ClothModifierData *)md)->point_cache); - ((ClothModifierData *)md)->sim_parms = NULL; - ((ClothModifierData *)md)->coll_parms = NULL; - ((ClothModifierData *)md)->point_cache = NULL; - next=md->next; - BLI_remlink(&ob->modifiers, md); - md = next; - } - else - md = md->next; - } - } - } /* sun/sky */ if(main->versionfile < 246) { @@ -7782,6 +7754,14 @@ static void do_versions(FileData *fd, Library *lib, Main *main) for(me=main->mesh.first; me; me= me->id.next) alphasort_version_246(fd, lib, me); } + + if(main->versionfile <= 246 && main->subversionfile < 1){ + Object *ob; + for(ob = main->object.first; ob; ob= ob->id.next) { + if(ob->pd && (ob->pd->forcefield == PFIELD_WIND)) + ob->pd->f_noise = 0.0; + } + } /* WATCH IT!!!: pointers from libdata have not been converted yet here! */ /* WATCH IT 2!: Userdef struct init has to be in src/usiblender.c! */ @@ -8499,9 +8479,6 @@ static void expand_object(FileData *fd, Main *mainvar, Object *ob) sens= ob->sensors.first; while(sens) { - for(a=0; a<sens->totlinks; a++) { - sens->links[a]= newglobadr(fd, sens->links[a]); - } if(sens->type==SENS_TOUCH) { bTouchSensor *ts= sens->data; expand_doit(fd, mainvar, ts->ma); @@ -8515,9 +8492,6 @@ static void expand_object(FileData *fd, Main *mainvar, Object *ob) cont= ob->controllers.first; while(cont) { - for(a=0; a<cont->totlinks; a++) { - cont->links[a]= newglobadr(fd, cont->links[a]); - } if(cont->type==CONT_PYTHON) { bPythonCont *pc= cont->data; expand_doit(fd, mainvar, pc->text); diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index 3af7d3f7c25..3bc6799d616 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; } @@ -608,6 +609,9 @@ static void write_sensors(WriteData *wd, ListBase *lb) case SENS_ACTUATOR: writestruct(wd, DATA, "bActuatorSensor", 1, sens->data); break; + case SENS_DELAY: + writestruct(wd, DATA, "bDelaySensor", 1, sens->data); + break; case SENS_COLLISION: writestruct(wd, DATA, "bCollisionSensor", 1, sens->data); break; diff --git a/source/blender/blenpluginapi/intern/pluginapi.c b/source/blender/blenpluginapi/intern/pluginapi.c index e65148a0b04..9c08a0b2f9d 100644 --- a/source/blender/blenpluginapi/intern/pluginapi.c +++ b/source/blender/blenpluginapi/intern/pluginapi.c @@ -50,10 +50,12 @@ #include "plugin.h" #include "MEM_guardedalloc.h" +#include "BLO_sys_types.h" // needed for intptr_t + #include "BLI_blenlib.h" /* util and noise functions */ #include "BLI_threads.h" /* For threadsfe guardedalloc malloc/calloc/free */ #include "IMB_imbuf.h" /* image buffer stuff */ -#define GET_INT_FROM_POINTER(i) ((int)(long)(i)) /* should use BKE_utildefines.h */ +#define GET_INT_FROM_POINTER(i) ((int)(intptr_t)(i)) /* should use BKE_utildefines.h */ /* -------------------------------------------------------------------------- */ /* stuff from util.h */ diff --git a/source/blender/imbuf/intern/cineon/cineonlib.c b/source/blender/imbuf/intern/cineon/cineonlib.c index 3b45a9de822..ecee3c7d6c0 100644 --- a/source/blender/imbuf/intern/cineon/cineonlib.c +++ b/source/blender/imbuf/intern/cineon/cineonlib.c @@ -67,12 +67,12 @@ fillCineonFileInfo(CineonFile* cineon, CineonFileInformation* fileInfo, const ch static void dumpCineonFileInfo(CineonFileInformation* fileInfo) { d_printf("\n--File Information--\n"); - d_printf("Magic: %8.8lX\n", (unsigned long)ntohl(fileInfo->magic_num)); - d_printf("Image Offset %ld\n", (long)ntohl(fileInfo->image_offset)); - d_printf("Generic Header size %ld\n", (long)ntohl(fileInfo->gen_hdr_size)); - d_printf("Industry Header size %ld\n", (long)ntohl(fileInfo->ind_hdr_size)); - d_printf("User Data size %ld\n", (long)ntohl(fileInfo->user_data_size)); - d_printf("File size %ld\n", (long)ntohl(fileInfo->file_size)); + d_printf("Magic: %8.8lX\n", (uintptr_t)ntohl(fileInfo->magic_num)); + d_printf("Image Offset %ld\n", (intptr_t)ntohl(fileInfo->image_offset)); + d_printf("Generic Header size %ld\n", (intptr_t)ntohl(fileInfo->gen_hdr_size)); + d_printf("Industry Header size %ld\n", (intptr_t)ntohl(fileInfo->ind_hdr_size)); + d_printf("User Data size %ld\n", (intptr_t)ntohl(fileInfo->user_data_size)); + d_printf("File size %ld\n", (intptr_t)ntohl(fileInfo->file_size)); d_printf("Version \"%s\"\n", fileInfo->vers); d_printf("File name \"%s\"\n", fileInfo->file_name); d_printf("Creation date \"%s\"\n", fileInfo->create_date); @@ -112,11 +112,11 @@ dumpCineonChannelInfo(CineonChannelInformation* chan) { default: d_printf(" (unknown)\n"); break; } d_printf(" Bits per pixel %d\n", chan->bits_per_pixel); - d_printf(" Pixels per line %ld\n", (long)ntohl(chan->pixels_per_line)); - d_printf(" Lines per image %ld\n", (long)ntohl(chan->lines_per_image)); - d_printf(" Ref low data %ld\n", (long)ntohl(chan->ref_low_data)); + d_printf(" Pixels per line %ld\n", (intptr_t)ntohl(chan->pixels_per_line)); + d_printf(" Lines per image %ld\n", (intptr_t)ntohl(chan->lines_per_image)); + d_printf(" Ref low data %ld\n", (intptr_t)ntohl(chan->ref_low_data)); d_printf(" Ref low quantity %f\n", ntohf(chan->ref_low_quantity)); - d_printf(" Ref high data %ld\n", (long)ntohl(chan->ref_high_data)); + d_printf(" Ref high data %ld\n", (intptr_t)ntohl(chan->ref_high_data)); d_printf(" Ref high quantity %f\n", ntohf(chan->ref_high_quantity)); } @@ -231,8 +231,8 @@ dumpCineonFormatInfo(CineonFormatInformation* formatInfo) { } else { d_printf(" positive\n"); } - d_printf("End of line padding %ld\n", (long)ntohl(formatInfo->line_padding)); - d_printf("End of channel padding %ld\n", (long)ntohl(formatInfo->channel_padding)); + d_printf("End of line padding %ld\n", (intptr_t)ntohl(formatInfo->line_padding)); + d_printf("End of channel padding %ld\n", (intptr_t)ntohl(formatInfo->channel_padding)); } static void @@ -256,8 +256,8 @@ fillCineonOriginationInfo(CineonFile* cineon, static void dumpCineonOriginationInfo(CineonOriginationInformation* originInfo) { d_printf("\n--Origination Information--\n"); - d_printf("X offset %ld\n", (long)ntohl(originInfo->x_offset)); - d_printf("Y offset %ld\n", (long)ntohl(originInfo->y_offset)); + d_printf("X offset %ld\n", (intptr_t)ntohl(originInfo->x_offset)); + d_printf("Y offset %ld\n", (intptr_t)ntohl(originInfo->y_offset)); d_printf("File name \"%s\"\n", originInfo->file_name); d_printf("Creation date \"%s\"\n", originInfo->create_date); d_printf("Creation time \"%s\"\n", originInfo->create_time); @@ -529,7 +529,7 @@ cineonOpen(const char* filename) { /* let's assume cineon files are always network order */ if (header.fileInfo.magic_num != ntohl(CINEON_FILE_MAGIC)) { if (verbose) d_printf("Bad magic number %8.8lX in \"%s\".\n", - (unsigned long)ntohl(header.fileInfo.magic_num), filename); + (uintptr_t)ntohl(header.fileInfo.magic_num), filename); cineonClose(cineon); return 0; } @@ -628,7 +628,7 @@ cineonOpenFromMem(unsigned char *mem, unsigned int size) { /* let's assume cineon files are always network order */ if (header.fileInfo.magic_num != ntohl(CINEON_FILE_MAGIC)) { - if (verbose) d_printf("Bad magic number %8.8lX in\n", (unsigned long)ntohl(header.fileInfo.magic_num)); + if (verbose) d_printf("Bad magic number %8.8lX in\n", (uintptr_t)ntohl(header.fileInfo.magic_num)); cineonClose(cineon); return 0; diff --git a/source/blender/imbuf/intern/cineon/dpxlib.c b/source/blender/imbuf/intern/cineon/dpxlib.c index 500c09ba265..1710cdde501 100644 --- a/source/blender/imbuf/intern/cineon/dpxlib.c +++ b/source/blender/imbuf/intern/cineon/dpxlib.c @@ -58,15 +58,15 @@ fillDpxChannelInfo(DpxFile* dpx, DpxChannelInformation* chan, int des) { static void dumpDpxChannelInfo(DpxChannelInformation* chan) { - d_printf(" Signage %ld", (long)ntohl(chan->signage)); - d_printf(" Ref low data %ld\n", (long)ntohl(chan->ref_low_data)); + d_printf(" Signage %ld", (intptr_t)ntohl(chan->signage)); + d_printf(" Ref low data %ld\n", (intptr_t)ntohl(chan->ref_low_data)); d_printf(" Ref low quantity %f\n", ntohf(chan->ref_low_quantity)); - d_printf(" Ref high data %ld\n", (long)ntohl(chan->ref_high_data)); + d_printf(" Ref high data %ld\n", (intptr_t)ntohl(chan->ref_high_data)); d_printf(" Ref high quantity %f\n", ntohf(chan->ref_high_quantity)); d_printf(" Designator1: %d,", chan->designator1); d_printf(" Bits per pixel %d\n", chan->bits_per_pixel); d_printf(" Packing: %d,", ntohs(chan->packing)); - d_printf(" Data Offset: %ld,", (long)ntohl(chan->data_offset)); + d_printf(" Data Offset: %ld,", (intptr_t)ntohl(chan->data_offset)); } static void @@ -110,19 +110,19 @@ static void dumpDpxFileInfo(DpxFileInformation* fileInfo) { d_printf("\n--File Information--\n"); d_printf("Magic: %8.8lX\n", (unsigned long)ntohl(fileInfo->magic_num)); - d_printf("Image Offset %ld\n", (long)ntohl(fileInfo->offset)); + d_printf("Image Offset %ld\n", (intptr_t)ntohl(fileInfo->offset)); d_printf("Version \"%s\"\n", fileInfo->vers); - d_printf("File size %ld\n", (long)ntohl(fileInfo->file_size)); - d_printf("Ditto key %ld\n", (long)ntohl(fileInfo->ditto_key)); - d_printf("Generic Header size %ld\n", (long)ntohl(fileInfo->gen_hdr_size)); - d_printf("Industry Header size %ld\n", (long)ntohl(fileInfo->ind_hdr_size)); - d_printf("User Data size %ld\n", (long)ntohl(fileInfo->user_data_size)); + d_printf("File size %ld\n", (intptr_t)ntohl(fileInfo->file_size)); + d_printf("Ditto key %ld\n", (intptr_t)ntohl(fileInfo->ditto_key)); + d_printf("Generic Header size %ld\n", (intptr_t)ntohl(fileInfo->gen_hdr_size)); + d_printf("Industry Header size %ld\n", (intptr_t)ntohl(fileInfo->ind_hdr_size)); + d_printf("User Data size %ld\n", (intptr_t)ntohl(fileInfo->user_data_size)); d_printf("File name \"%s\"\n", fileInfo->file_name); d_printf("Creation date \"%s\"\n", fileInfo->create_date); d_printf("Creator \"%s\"\n", fileInfo->creator); d_printf("Project \"%s\"\n", fileInfo->project); d_printf("Copyright \"%s\"\n", fileInfo->copyright); - d_printf("Key %ld\n", (long)ntohl(fileInfo->key)); + d_printf("Key %ld\n", (intptr_t)ntohl(fileInfo->key)); } static void @@ -150,8 +150,8 @@ dumpDpxImageInfo(DpxImageInformation* imageInfo) { d_printf("Image orientation %d,", ntohs(imageInfo->orientation)); n = ntohs(imageInfo->channels_per_image); d_printf("Channels %d\n", n); - d_printf("Pixels per line %ld\n", (long)ntohl(imageInfo->pixels_per_line)); - d_printf("Lines per image %ld\n", (long)ntohl(imageInfo->lines_per_image)); + d_printf("Pixels per line %ld\n", (intptr_t)ntohl(imageInfo->pixels_per_line)); + d_printf("Lines per image %ld\n", (intptr_t)ntohl(imageInfo->lines_per_image)); for (i = 0; i < n; ++i) { d_printf(" --Channel %d--\n", i); dumpDpxChannelInfo(&imageInfo->channel[i]); @@ -166,12 +166,12 @@ fillDpxOriginationInfo( static void dumpDpxOriginationInfo(DpxOriginationInformation* originInfo) { d_printf("\n--Origination Information--\n"); - d_printf("X offset %ld\n", (long)ntohl(originInfo->x_offset)); - d_printf("Y offset %ld\n", (long)ntohl(originInfo->y_offset)); + d_printf("X offset %ld\n", (intptr_t)ntohl(originInfo->x_offset)); + d_printf("Y offset %ld\n", (intptr_t)ntohl(originInfo->y_offset)); d_printf("X centre %f\n", ntohf(originInfo->x_centre)); d_printf("Y centre %f\n", ntohf(originInfo->y_centre)); - d_printf("Original X %ld\n", (long)ntohl(originInfo->x_original_size)); - d_printf("Original Y %ld\n", (long)ntohl(originInfo->y_original_size)); + d_printf("Original X %ld\n", (intptr_t)ntohl(originInfo->x_original_size)); + d_printf("Original Y %ld\n", (intptr_t)ntohl(originInfo->y_original_size)); d_printf("File name \"%s\"\n", originInfo->file_name); d_printf("Creation time \"%s\"\n", originInfo->creation_time); d_printf("Input device \"%s\"\n", originInfo->input_device); @@ -417,7 +417,7 @@ intern_dpxOpen(int mode, const char* bytestuff, int bufsize) { /* let's assume dpx files are always network order */ if (header.fileInfo.magic_num != ntohl(DPX_FILE_MAGIC)) { if (verbose) d_printf("Bad magic number %8.8lX in \"%s\".\n", - (unsigned long)ntohl(header.fileInfo.magic_num), filename); + (uintptr_t)ntohl(header.fileInfo.magic_num), filename); dpxClose(dpx); return 0; } diff --git a/source/blender/imbuf/intern/cineon/logImageCore.h b/source/blender/imbuf/intern/cineon/logImageCore.h index 01eff8d570d..2646e8b3c12 100644 --- a/source/blender/imbuf/intern/cineon/logImageCore.h +++ b/source/blender/imbuf/intern/cineon/logImageCore.h @@ -34,7 +34,9 @@ extern "C" { #endif - +#include "BLO_sys_types.h" // for intptr_t support +#undef ntohl +#undef htonl typedef int (GetRowFn)(LogImageFile* logImage, unsigned short* row, int lineNum); typedef int (SetRowFn)(LogImageFile* logImage, const unsigned short* row, int lineNum); typedef void (CloseFn)(LogImageFile* logImage); @@ -80,7 +82,7 @@ struct _Log_Image_File_t_ CloseFn* close; unsigned char *membuffer; - unsigned long membuffersize; + uintptr_t membuffersize; unsigned char *memcursor; }; diff --git a/source/blender/imbuf/intern/cineon/logmemfile.c b/source/blender/imbuf/intern/cineon/logmemfile.c index 20359335933..160e8453713 100644 --- a/source/blender/imbuf/intern/cineon/logmemfile.c +++ b/source/blender/imbuf/intern/cineon/logmemfile.c @@ -24,10 +24,10 @@ #include "logImageCore.h" -int logimage_fseek(void* logfile, long offsett, int origin) +int logimage_fseek(void* logfile, intptr_t offsett, int origin) { struct _Log_Image_File_t_ *file = (struct _Log_Image_File_t_*) logfile; - long offset = offsett; + intptr_t offset = offsett; if (file->file) fseek(file->file, offset, origin); else { /*we're seeking in memory*/ @@ -38,7 +38,7 @@ int logimage_fseek(void* logfile, long offsett, int origin) if (offset > file->membuffersize) return 1; file->memcursor = (file->membuffer + file->membuffersize) - offset; } else if (origin==SEEK_CUR) { - unsigned long pos = (unsigned long)file->membuffer - (unsigned long)file->memcursor; + uintptr_t pos = (uintptr_t)file->membuffer - (uintptr_t)file->memcursor; if (pos + offset > file->membuffersize) return 1; if (pos < 0) return 1; file->memcursor += offset; diff --git a/source/blender/imbuf/intern/cineon/logmemfile.h b/source/blender/imbuf/intern/cineon/logmemfile.h index 6e82cf2b145..39e2f36dad9 100644 --- a/source/blender/imbuf/intern/cineon/logmemfile.h +++ b/source/blender/imbuf/intern/cineon/logmemfile.h @@ -22,7 +22,7 @@ #ifndef _LOGMEMFILE_H #define _LOGMEMFILE_H -int logimage_fseek(void* logfile, long offsett, int origin); +int logimage_fseek(void* logfile, intptr_t offsett, int origin); int logimage_fwrite(void *buffer, unsigned int size, unsigned int count, void *logfile); int logimage_fread(void *buffer, unsigned int size, unsigned int count, void *logfile); diff --git a/source/blender/imbuf/intern/scaling.c b/source/blender/imbuf/intern/scaling.c index 40c1f83c98c..8257eb4643e 100644 --- a/source/blender/imbuf/intern/scaling.c +++ b/source/blender/imbuf/intern/scaling.c @@ -39,6 +39,8 @@ #include "IMB_allocimbuf.h" #include "IMB_filter.h" +#include "BLO_sys_types.h" // for intptr_t support + /************************************************************************/ /* SCALING */ /************************************************************************/ @@ -490,8 +492,8 @@ static void enlarge_picture_byte( / (double) (src_width - 1.001); double ratioy = (double) (dst_height - 1.0) / (double) (src_height - 1.001); - unsigned long x_src, dx_src, x_dst; - unsigned long y_src, dy_src, y_dst; + uintptr_t x_src, dx_src, x_dst; + uintptr_t y_src, dy_src, y_dst; dx_src = 65536.0 / ratiox; dy_src = 65536.0 / ratioy; @@ -500,8 +502,8 @@ static void enlarge_picture_byte( for (y_dst = 0; y_dst < dst_height; y_dst++) { unsigned char* line1 = src + (y_src >> 16) * 4 * src_width; unsigned char* line2 = line1 + 4 * src_width; - unsigned long weight1y = 65536 - (y_src & 0xffff); - unsigned long weight2y = 65536 - weight1y; + uintptr_t weight1y = 65536 - (y_src & 0xffff); + uintptr_t weight2y = 65536 - weight1y; if ((y_src >> 16) == src_height - 1) { line2 = line1; @@ -509,8 +511,8 @@ static void enlarge_picture_byte( x_src = 0; for (x_dst = 0; x_dst < dst_width; x_dst++) { - unsigned long weight1x = 65536 - (x_src & 0xffff); - unsigned long weight2x = 65536 - weight1x; + uintptr_t weight1x = 65536 - (x_src & 0xffff); + uintptr_t weight2x = 65536 - weight1x; unsigned long x = (x_src >> 16) * 4; @@ -557,12 +559,12 @@ static void enlarge_picture_byte( } struct scale_outpix_byte { - unsigned long r; - unsigned long g; - unsigned long b; - unsigned long a; + uintptr_t r; + uintptr_t g; + uintptr_t b; + uintptr_t a; - unsigned long weight; + uintptr_t weight; }; static void shrink_picture_byte( @@ -571,9 +573,9 @@ static void shrink_picture_byte( { double ratiox = (double) (dst_width) / (double) (src_width); double ratioy = (double) (dst_height) / (double) (src_height); - unsigned long x_src, dx_dst, x_dst; - unsigned long y_src, dy_dst, y_dst; - long y_counter; + uintptr_t x_src, dx_dst, x_dst; + uintptr_t y_src, dy_dst, y_dst; + intptr_t y_counter; unsigned char * dst_begin = dst; struct scale_outpix_byte * dst_line1 = NULL; @@ -593,16 +595,16 @@ static void shrink_picture_byte( y_counter = 65536; for (y_src = 0; y_src < src_height; y_src++) { unsigned char* line = src + y_src * 4 * src_width; - unsigned long weight1y = 65536 - (y_dst & 0xffff); - unsigned long weight2y = 65536 - weight1y; + uintptr_t weight1y = 65536 - (y_dst & 0xffff); + uintptr_t weight2y = 65536 - weight1y; x_dst = 0; for (x_src = 0; x_src < src_width; x_src++) { - unsigned long weight1x = 65536 - (x_dst & 0xffff); - unsigned long weight2x = 65536 - weight1x; + uintptr_t weight1x = 65536 - (x_dst & 0xffff); + uintptr_t weight2x = 65536 - weight1x; - unsigned long x = x_dst >> 16; + uintptr_t x = x_dst >> 16; - unsigned long w; + uintptr_t w; w = (weight1y * weight1x) >> 16; @@ -643,13 +645,13 @@ static void shrink_picture_byte( y_dst += dy_dst; y_counter -= dy_dst; if (y_counter < 0) { - unsigned long x; + uintptr_t x; struct scale_outpix_byte * temp; y_counter += 65536; for (x=0; x < dst_width; x++) { - unsigned long f = 0x80000000UL + uintptr_t f = 0x80000000UL / dst_line1[x].weight; *dst++ = (dst_line1[x].r * f) >> 15; *dst++ = (dst_line1[x].g * f) >> 15; @@ -664,9 +666,9 @@ static void shrink_picture_byte( } } if (dst - dst_begin < dst_width * dst_height * 4) { - unsigned long x; + uintptr_t x; for (x = 0; x < dst_width; x++) { - unsigned long f = 0x80000000UL / dst_line1[x].weight; + uintptr_t f = 0x80000000UL / dst_line1[x].weight; *dst++ = (dst_line1[x].r * f) >> 15; *dst++ = (dst_line1[x].g * f) >> 15; *dst++ = (dst_line1[x].b * f) >> 15; @@ -698,8 +700,8 @@ static void enlarge_picture_float( / (double) (src_width - 1.001); double ratioy = (double) (dst_height - 1.0) / (double) (src_height - 1.001); - unsigned long x_dst; - unsigned long y_dst; + uintptr_t x_dst; + uintptr_t y_dst; double x_src, dx_src; double y_src, dy_src; @@ -727,7 +729,7 @@ static void enlarge_picture_float( float w12 = weight1y * weight2x; float w22 = weight2y * weight2x; - unsigned long x = ((int) x_src) * 4; + uintptr_t x = ((int) x_src) * 4; *dst++ = line1[x] * w11 + line2[x] * w21 @@ -770,8 +772,8 @@ static void shrink_picture_float( { double ratiox = (double) (dst_width) / (double) (src_width); double ratioy = (double) (dst_height) / (double) (src_height); - unsigned long x_src; - unsigned long y_src; + uintptr_t x_src; + uintptr_t y_src; float dx_dst, x_dst; float dy_dst, y_dst; float y_counter; @@ -794,14 +796,14 @@ static void shrink_picture_float( y_counter = 1.0; for (y_src = 0; y_src < src_height; y_src++) { float* line = src + y_src * 4 * src_width; - unsigned long weight1y = 1.0 - (y_dst - (int) y_dst); - unsigned long weight2y = 1.0 - weight1y; + uintptr_t weight1y = 1.0 - (y_dst - (int) y_dst); + uintptr_t weight2y = 1.0 - weight1y; x_dst = 0; for (x_src = 0; x_src < src_width; x_src++) { - unsigned long weight1x = 1.0 - (x_dst - (int) x_dst); - unsigned long weight2x = 1.0 - weight1x; + uintptr_t weight1x = 1.0 - (x_dst - (int) x_dst); + uintptr_t weight2x = 1.0 - weight1x; - unsigned long x = (int) x_dst; + uintptr_t x = (int) x_dst; float w; @@ -844,7 +846,7 @@ static void shrink_picture_float( y_dst += dy_dst; y_counter -= dy_dst; if (y_counter < 0) { - unsigned long x; + uintptr_t x; struct scale_outpix_float * temp; y_counter += 1.0; @@ -864,7 +866,7 @@ static void shrink_picture_float( } } if (dst - dst_begin < dst_width * dst_height * 4) { - unsigned long x; + uintptr_t x; for (x = 0; x < dst_width; x++) { float f = 1.0 / dst_line1[x].weight; *dst++ = dst_line1[x].r * f; diff --git a/source/blender/include/BDR_gpencil.h b/source/blender/include/BDR_gpencil.h index eb749cf28ec..9b9294b0343 100644 --- a/source/blender/include/BDR_gpencil.h +++ b/source/blender/include/BDR_gpencil.h @@ -43,7 +43,6 @@ struct bGPDframe; /* Temporary 'Stroke Point' data */ typedef struct tGPspoint { short x, y; /* x and y coordinates of cursor (in relative to area) */ - float xf, yf; /* same as x and y, but as floats */ float pressure; /* pressure of tablet at this point */ } tGPspoint; @@ -77,6 +76,9 @@ void gpencil_delete_laststroke(struct bGPdata *gpd); void gpencil_delete_operation(short mode); void gpencil_delete_menu(void); +void gpencil_convert_operation(short mode); +void gpencil_convert_menu(void); + //short gpencil_paint(short mousebutton); short gpencil_do_paint(struct ScrArea *sa, short mousebutton); diff --git a/source/blender/include/BIF_drawgpencil.h b/source/blender/include/BIF_drawgpencil.h index 418446313df..eacafce058d 100644 --- a/source/blender/include/BIF_drawgpencil.h +++ b/source/blender/include/BIF_drawgpencil.h @@ -28,15 +28,18 @@ #ifndef BIF_DRAWGPENCIL_H #define BIF_DRAWGPENCIL_H + +struct bGPdata; struct ScrArea; struct View3D; struct SpaceNode; struct SpaceSeq; -struct bGPdata; struct uiBlock; +struct ImBuf; short draw_gpencil_panel(struct uiBlock *block, struct bGPdata *gpd, struct ScrArea *sa); +void draw_gpencil_2dimage(struct ScrArea *sa, struct ImBuf *ibuf); void draw_gpencil_2dview(struct ScrArea *sa, short onlyv2d); void draw_gpencil_3dview(struct ScrArea *sa, short only3d); void draw_gpencil_oglrender(struct View3D *v3d, int winx, int winy); diff --git a/source/blender/include/BIF_editarmature.h b/source/blender/include/BIF_editarmature.h index 07fc8f08b4a..b2bdb2dad73 100644 --- a/source/blender/include/BIF_editarmature.h +++ b/source/blender/include/BIF_editarmature.h @@ -91,6 +91,7 @@ void free_editArmature(void); int join_armature(void); void separate_armature(void); +void apply_armature_pose2bones(void); void load_editArmature(void); void make_bone_parent(void); diff --git a/source/blender/include/BIF_editview.h b/source/blender/include/BIF_editview.h index d2c6c56d01a..204733a19d6 100644 --- a/source/blender/include/BIF_editview.h +++ b/source/blender/include/BIF_editview.h @@ -40,6 +40,7 @@ void arrows_move_cursor(unsigned short event); void lasso_select_boundbox(struct rcti *rect, short mcords[][2], short moves); int lasso_inside(short mcords[][2], short moves, short sx, short sy); int lasso_inside_edge(short mcords[][2], short moves, int x0, int y0, int x1, int y1); +int edge_inside_circle(short centx, short centy, short rad, short x1, short y1, short x2, short y2); void borderselect(void); void circle_select(void); void deselectall(void); diff --git a/source/blender/include/BIF_meshtools.h b/source/blender/include/BIF_meshtools.h index b08c66fd16e..d809d1f21f9 100644 --- a/source/blender/include/BIF_meshtools.h +++ b/source/blender/include/BIF_meshtools.h @@ -40,7 +40,7 @@ extern void objects_bake_render_menu(void); extern void objects_bake_render_ui(short event); extern void objects_bake_render(short event, char **error_msg); -extern long mesh_octree_table(struct Object *ob, float *co, char mode); +extern intptr_t mesh_octree_table(struct Object *ob, float *co, char mode); extern int mesh_get_x_mirror_vert(struct Object *ob, int index); extern struct EditVert *editmesh_get_x_mirror_vert(struct Object *ob, float *co); extern int *mesh_get_x_mirror_faces(struct Object *ob); diff --git a/source/blender/include/BIF_resources.h b/source/blender/include/BIF_resources.h index 92f18a89a4b..5099c253c79 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/include/BSE_drawipo.h b/source/blender/include/BSE_drawipo.h index 932f103a579..b8388b2172a 100644 --- a/source/blender/include/BSE_drawipo.h +++ b/source/blender/include/BSE_drawipo.h @@ -42,6 +42,7 @@ struct ScrArea; struct EditIpo; struct View2D; struct rctf; +struct SpaceLink; void calc_ipogrid(void); void draw_ipogrid(void); @@ -50,6 +51,8 @@ void areamouseco_to_ipoco (struct View2D *v2d, short *mval, float *x, float *y); void ipoco_to_areaco (struct View2D *v2d, float *vec, short *mval); void ipoco_to_areaco_noclip (struct View2D *v2d, float *vec, short *mval); +struct View2D *spacelink_get_view2d(struct SpaceLink *sl); + void view2d_do_locks (struct ScrArea *cursa, int flag); void view2d_zoom (struct View2D *v2d, float factor, int winx, int winy); void view2d_getscale (struct View2D *v2d, float *x, float *y); diff --git a/source/blender/include/transform.h b/source/blender/include/transform.h index 720b856a149..51fa39ff9d6 100644 --- a/source/blender/include/transform.h +++ b/source/blender/include/transform.h @@ -466,7 +466,6 @@ int validSnappingNormal(TransInfo *t); /*********************** Generics ********************************/ void initTrans(TransInfo *t); -void initTransModeFlags(TransInfo *t, int mode); void postTrans (TransInfo *t); void drawLine(float *center, float *dir, char axis, short options); @@ -498,6 +497,7 @@ TransInfo * BIF_GetTransInfo(void); /*********************** NumInput ********************************/ +void initNumInput(NumInput *n); void outputNumInput(NumInput *n, char *str); short hasNumInput(NumInput *n); void applyNumInput(NumInput *n, float *vec); diff --git a/source/blender/makesdna/DNA_actuator_types.h b/source/blender/makesdna/DNA_actuator_types.h index 7444ce95f56..59d0555b452 100644 --- a/source/blender/makesdna/DNA_actuator_types.h +++ b/source/blender/makesdna/DNA_actuator_types.h @@ -81,7 +81,9 @@ typedef struct bEditObjectActuator { struct Mesh *me; char name[32]; float linVelocity[3]; /* initial lin. velocity on creation */ - short localflag; /* flag for the lin. vel: apply locally */ + float angVelocity[3]; /* initial ang. velocity on creation */ + float pad; + short localflag; /* flag for the lin & ang. vel: apply locally */ short dyn_operation; } bEditObjectActuator; @@ -384,6 +386,9 @@ typedef struct FreeCamera { #define ACT_EDOB_TRACK_TO 3 #define ACT_EDOB_DYNAMICS 4 +/* editObjectActuator->localflag */ +#define ACT_EDOB_LOCAL_LINV 2 +#define ACT_EDOB_LOCAL_ANGV 4 /* editObjectActuator->flag */ diff --git a/source/blender/makesdna/DNA_gpencil_types.h b/source/blender/makesdna/DNA_gpencil_types.h index dca4e28688d..cc0c9912057 100644 --- a/source/blender/makesdna/DNA_gpencil_types.h +++ b/source/blender/makesdna/DNA_gpencil_types.h @@ -59,8 +59,10 @@ typedef struct bGPDstroke { #define GP_STROKE_3DSPACE (1<<0) /* stroke is in 2d-space */ #define GP_STROKE_2DSPACE (1<<1) - /* stroke is an "eraser" stroke */ -#define GP_STROKE_ERASER (1<<2) + /* stroke is in 2d-space (but with special 'image' scaling) */ +#define GP_STROKE_2DIMAGE (1<<2) + /* only for use with stroke-buffer (while drawing eraser) */ +#define GP_STROKE_ERASER (1<<15) /* Grease-Pencil Annotations - 'Frame' diff --git a/source/blender/makesdna/DNA_ipo_types.h b/source/blender/makesdna/DNA_ipo_types.h index 3954a500dc7..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 19 -#define PART_TOTNAM 19 +#define PART_TOTIPO 25 +#define PART_TOTNAM 25 #define PART_EMIT_FREQ 1 #define PART_EMIT_LIFE 2 @@ -381,6 +381,14 @@ typedef short IPO_Channel; #define PART_BB_TILT 19 +#define PART_PD_FSTR 20 +#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 a44d9793062..9599cc1d247 100644 --- a/source/blender/makesdna/DNA_modifier_types.h +++ b/source/blender/makesdna/DNA_modifier_types.h @@ -35,6 +35,7 @@ typedef enum ModifierType { eModifierType_Cloth, eModifierType_Collision, eModifierType_Bevel, + eModifierType_Shrinkwrap, NUM_MODIFIER_TYPES } ModifierType; @@ -390,7 +391,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; @@ -490,4 +492,45 @@ typedef struct ExplodeModifierData { float protect; } ExplodeModifierData; +typedef struct ShrinkwrapModifierData { + ModifierData modifier; + + struct Object *target; /* shrink target */ + struct Object *auxTarget; /* additional shrink target */ + char vgroup_name[32]; /* optional vertexgroup name */ + float keepDist; /* distance offset to keep from mesh/projection point */ + short shrinkType; /* shrink type projection */ + short shrinkOpts; /* shrink options */ + char projAxis; /* axis to project over */ + + /* + * if using projection over vertex normal this controls the + * the level of subsurface that must be done before getting the + * vertex coordinates and normal + */ + char subsurfLevels; + + char pad[6]; + +} ShrinkwrapModifierData; + +/* Shrinkwrap->shrinkType */ +#define MOD_SHRINKWRAP_NEAREST_SURFACE 0 +#define MOD_SHRINKWRAP_PROJECT 1 +#define MOD_SHRINKWRAP_NEAREST_VERTEX 2 + +/* Shrinkwrap->shrinkOpts */ +#define MOD_SHRINKWRAP_PROJECT_ALLOW_POS_DIR (1<<0) /* allow shrinkwrap to move the vertex in the positive direction of axis */ +#define MOD_SHRINKWRAP_PROJECT_ALLOW_NEG_DIR (1<<1) /* allow shrinkwrap to move the vertex in the negative direction of axis */ + +#define MOD_SHRINKWRAP_CULL_TARGET_FRONTFACE (1<<3) /* ignore vertex moves if a vertex ends projected on a front face of the target */ +#define MOD_SHRINKWRAP_CULL_TARGET_BACKFACE (1<<4) /* ignore vertex moves if a vertex ends projected on a back face of the target */ + +#define MOD_SHRINKWRAP_KEEP_ABOVE_SURFACE (1<<5) /* distance is measure to the front face of the target */ + +#define MOD_SHRINKWRAP_PROJECT_OVER_X_AXIS (1<<0) +#define MOD_SHRINKWRAP_PROJECT_OVER_Y_AXIS (1<<1) +#define MOD_SHRINKWRAP_PROJECT_OVER_Z_AXIS (1<<2) +#define MOD_SHRINKWRAP_PROJECT_OVER_NORMAL 0 /* projection over normal is used if no axis is selected */ + #endif diff --git a/source/blender/makesdna/DNA_object_force.h b/source/blender/makesdna/DNA_object_force.h index dc6c2bcbcc0..5900e16d5e8 100644 --- a/source/blender/makesdna/DNA_object_force.h +++ b/source/blender/makesdna/DNA_object_force.h @@ -67,6 +67,9 @@ typedef struct PartDeflect { float tex_nabla; short tex_mode, kink, kink_axis, rt2; struct Tex *tex; /* Texture of the texture effector */ + struct RNG *rng; /* random noise generator for e.g. wind */ + float f_noise; /* noise of force (currently used for wind) */ + int pad; } PartDeflect; typedef struct PointCache { @@ -153,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_sensor_types.h b/source/blender/makesdna/DNA_sensor_types.h index c0306f43730..d508ff3a552 100644 --- a/source/blender/makesdna/DNA_sensor_types.h +++ b/source/blender/makesdna/DNA_sensor_types.h @@ -88,6 +88,13 @@ typedef struct bActuatorSensor { char name[32]; } bActuatorSensor; +typedef struct bDelaySensor { + short delay; + short duration; + short flag; + short pad; +} bDelaySensor; + typedef struct bCollisionSensor { char name[32]; /* property name */ char materialName[32]; /* material */ @@ -204,6 +211,7 @@ typedef struct bJoystickSensor { #define SENS_MESSAGE 10 #define SENS_JOYSTICK 11 #define SENS_ACTUATOR 12 +#define SENS_DELAY 13 /* sensor->flag */ #define SENS_SHOW 1 #define SENS_DEL 2 @@ -229,6 +237,9 @@ typedef struct bJoystickSensor { * */ /* #define SENS_COLLISION_PROPERTY 0 */ #define SENS_COLLISION_MATERIAL 1 +/* ray specific mode */ +/* X-Ray means that the ray will traverse objects that don't have the property/material */ +#define SENS_RAY_XRAY 2 /* Some stuff for the mouse sensor Type: */ #define BL_SENS_MOUSE_LEFT_BUTTON 1 @@ -254,5 +265,7 @@ typedef struct bJoystickSensor { #define SENS_JOY_HAT 2 #define SENS_JOY_HAT_DIR 0 +#define SENS_DELAY_REPEAT 1 + #endif diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h index 1e3f337ad99..8e849c5aa3d 100644 --- a/source/blender/makesdna/DNA_space_types.h +++ b/source/blender/makesdna/DNA_space_types.h @@ -247,6 +247,7 @@ typedef struct SpaceImage { float xof, yof; /* user defined offset, image is centered */ float centx, centy; /* storage for offset while render drawing */ + struct bGPdata *gpd; /* grease pencil data */ } SpaceImage; typedef struct SpaceNla { 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/makesdna/intern/makesdna.c b/source/blender/makesdna/intern/makesdna.c index 3818d66b39c..b4deb1f2b60 100644 --- a/source/blender/makesdna/intern/makesdna.c +++ b/source/blender/makesdna/intern/makesdna.c @@ -55,6 +55,8 @@ #include "MEM_guardedalloc.h" #include "DNA_sdna_types.h" +#include "BLO_sys_types.h" // for intptr_t support + #ifdef HAVE_CONFIG_H #include <config.h> #endif @@ -955,7 +957,7 @@ int make_structDNA(char *baseDirectory, FILE *file) /* calculate size of datablock with strings */ cp= names[nr_names-1]; cp+= strlen(names[nr_names-1]) + 1; /* +1: null-terminator */ - len= (long) (cp - (char*) names[0]); + len= (intptr_t) (cp - (char*) names[0]); len= (len+3) & ~3; dna_write(file, names[0], len); @@ -968,7 +970,7 @@ int make_structDNA(char *baseDirectory, FILE *file) /* calculate datablock size */ cp= types[nr_types-1]; cp+= strlen(types[nr_types-1]) + 1; /* +1: null-terminator */ - len= (long) (cp - (char*) types[0]); + len= (intptr_t) (cp - (char*) types[0]); len= (len+3) & ~3; dna_write(file, types[0], len); @@ -990,7 +992,7 @@ int make_structDNA(char *baseDirectory, FILE *file) /* calc datablock size */ sp= structs[nr_structs-1]; sp+= 2+ 2*( sp[1] ); - len= (long) ((char*) sp - (char*) structs[0]); + len= (intptr_t) ((char*) sp - (char*) structs[0]); len= (len+3) & ~3; dna_write(file, structs[0], len); diff --git a/source/blender/python/api2_2x/Draw.c b/source/blender/python/api2_2x/Draw.c index 047a035fb8b..bd19a6a6a3e 100644 --- a/source/blender/python/api2_2x/Draw.c +++ b/source/blender/python/api2_2x/Draw.c @@ -1554,6 +1554,12 @@ static PyObject *Method_Number( PyObject * self, PyObject * args ) UI_METHOD_ERRORCHECK; + if ( !PyNumber_Check(inio) || !PyNumber_Check(mino) || + !PyNumber_Check(maxo) ) { + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected ints or floats for the initial, min and max values" ); + } + but = newbutton( ); if (tip) strncpy(but->tooltip, tip, BPY_MAX_TOOLTIP); block = Get_uiBlock( ); 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/Particle.c b/source/blender/python/api2_2x/Particle.c index 2c2e724129e..bc65426e16c 100644 --- a/source/blender/python/api2_2x/Particle.c +++ b/source/blender/python/api2_2x/Particle.c @@ -804,7 +804,7 @@ static PyObject *Part_GetLoc( BPy_PartSys * self, PyObject * args ) { ParticleSystem *psys = 0L; Object *ob = 0L; - PyObject *partlist,*seglist; + PyObject *partlist,*seglist=0L; ParticleCacheKey **cache,*path; PyObject* loc = 0L; ParticleKey state; @@ -1107,7 +1107,7 @@ static PyObject *Part_GetSize( BPy_PartSys * self, PyObject * args ) ParticleSystem *psys = 0L; ParticleData *data; Object *ob = 0L; - PyObject *partlist,*tuple; + PyObject *partlist,*tuple=0L; DerivedMesh* dm; float vm[4][4],wm[4][4]; float size; @@ -1217,7 +1217,7 @@ static PyObject *Part_GetAge( BPy_PartSys * self, PyObject * args ) ParticleSystem *psys = 0L; ParticleData *data; Object *ob = 0L; - PyObject *partlist,*tuple; + PyObject *partlist,*tuple=0L; DerivedMesh* dm; float vm[4][4],wm[4][4]; float life; diff --git a/source/blender/python/api2_2x/Text3d.c b/source/blender/python/api2_2x/Text3d.c index 5137e989b8d..202195cdcb4 100644 --- a/source/blender/python/api2_2x/Text3d.c +++ b/source/blender/python/api2_2x/Text3d.c @@ -132,9 +132,12 @@ static PyObject *Text3d_getAlignment( BPy_Text3d * self ); static PyObject *Text3d_setAlignment( BPy_Text3d * self, PyObject * args ); static PyObject *Text3d_getFont( BPy_Text3d * self ); static PyObject *Text3d_setFont( BPy_Text3d * self, PyObject * args ); +static PyObject *Text3d_getMaterial( BPy_Text3d * self, PyObject * value ); +static PyObject *Text3d_setMaterial( BPy_Text3d * self, PyObject * args ); static PyObject *Text3d_addFrame( BPy_Text3d * self ); static PyObject *Text3d_removeFrame( BPy_Text3d * self, PyObject * args ); + /*****************************************************************************/ /* Python BPy_Text3d methods table: */ /*****************************************************************************/ @@ -210,6 +213,10 @@ static PyMethodDef BPy_Text3d_methods[] = { METH_NOARGS, "() - Gets font list for Text3d"}, {"setFont", ( PyCFunction ) Text3d_setFont, METH_VARARGS, "() - Sets font for Text3d"}, + {"getMaterial", ( PyCFunction ) Text3d_getMaterial, + METH_O, "() - Gets font list for Text3d"}, + {"setMaterial", ( PyCFunction ) Text3d_setMaterial, + METH_VARARGS, "() - Sets font for Text3d"}, {"addFrame", ( PyCFunction ) Text3d_addFrame, METH_NOARGS, "() - adds a new text frame"}, {"removeFrame", ( PyCFunction ) Text3d_removeFrame, @@ -1132,6 +1139,45 @@ static PyObject *Text3d_setFont( BPy_Text3d * self, PyObject * args ) Py_RETURN_NONE; } +/* todo, add style access, will be almost exact copy of these 2 */ +static PyObject *Text3d_getMaterial( BPy_Text3d * self, PyObject * value ) +{ + int index = PyInt_AsLong( value ); + if (index == -1 && PyErr_Occurred()) + return EXPP_ReturnPyObjError( PyExc_TypeError, "expected a character index" ); + + if (index < 0) + index = self->curve->len + index; + + if ( index < 0 || index >= self->curve->len ) + return EXPP_ReturnPyObjError( PyExc_IndexError, "character index out of range" ); + + return PyInt_FromLong( self->curve->strinfo[index].mat_nr ); +} + +static PyObject *Text3d_setMaterial( BPy_Text3d * self, PyObject * args ) +{ + int index, mat_nr; + if( !PyArg_ParseTuple( args, "ii",&index, &mat_nr) ) + return NULL; /* Python error is ok */ + + if (index < 0) + index = self->curve->len + index; + + if ( index < 0 || index >= self->curve->len ) + return EXPP_ReturnPyObjError( PyExc_IndexError, "character index out of range" ); + + if (mat_nr < 0) + mat_nr = self->curve->totcol + mat_nr; + + if ( mat_nr < 0 || mat_nr >= self->curve->totcol ) + return EXPP_ReturnPyObjError( PyExc_IndexError, "material index out of range" ); + + self->curve->strinfo[index].mat_nr = mat_nr; + + Py_RETURN_NONE; +} + static PyObject *Text3d_addFrame( BPy_Text3d * self ) { Curve *cu = self->curve; 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/Mathutils.py b/source/blender/python/api2_2x/doc/Mathutils.py index 8b0c41b9a69..524d1fb6d4c 100644 --- a/source/blender/python/api2_2x/doc/Mathutils.py +++ b/source/blender/python/api2_2x/doc/Mathutils.py @@ -521,6 +521,15 @@ class Vector: @return: Return a quaternion rotation from the vector and the track and up axis. """ + def reflect(mirror): + """ + Return the reflection vector from the mirror vector argument. + @type mirror: Vector object + @param mirror: This vector could be a normal from the reflecting surface. + @rtype: Vector object matching the size of this vector. + @return: The reflected vector. + """ + class Euler: """ The Euler object 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/python/api2_2x/doc/Text3d.py b/source/blender/python/api2_2x/doc/Text3d.py index a7d8c585078..4bd989014f4 100644 --- a/source/blender/python/api2_2x/doc/Text3d.py +++ b/source/blender/python/api2_2x/doc/Text3d.py @@ -287,6 +287,26 @@ class Text3d: @param align: The new text3d's Alignment value. """ + def getMaterial(index): + """ + get the material index of a character. + @rtype: int + @return: the material index if the character + @type index: int + @param index: the index of the character in a string + """ + + def setMaterial(index, material_index): + """ + Set a characters material. + @note: after changing this youll need to update the object with object.makeDisplayList() to see the changes. + @rtype: None + @type index: int + @param index: the index of the character in a string + @type material_index: int + @param material_index: the material index set set the character. + """ + def addFrame(): """ Adds a text frame. maximum number of frames is 255. diff --git a/source/blender/python/api2_2x/vector.c b/source/blender/python/api2_2x/vector.c index 33ca993fb49..fe28f0fac42 100644 --- a/source/blender/python/api2_2x/vector.c +++ b/source/blender/python/api2_2x/vector.c @@ -42,6 +42,7 @@ char Vector_Resize3D_doc[] = "() - resize a vector to [x,y,z]"; char Vector_Resize4D_doc[] = "() - resize a vector to [x,y,z,w]"; char Vector_toPoint_doc[] = "() - create a new Point Object from this vector"; char Vector_ToTrackQuat_doc[] = "(track, up) - extract a quaternion from the vector and the track and up axis"; +char Vector_reflect_doc[] = "(mirror) - return a vector reflected on the mirror normal"; char Vector_copy_doc[] = "() - return a copy of the vector"; /*-----------------------METHOD DEFINITIONS ----------------------*/ struct PyMethodDef Vector_methods[] = { @@ -53,6 +54,7 @@ struct PyMethodDef Vector_methods[] = { {"resize4D", (PyCFunction) Vector_Resize4D, METH_NOARGS, Vector_Resize2D_doc}, {"toPoint", (PyCFunction) Vector_toPoint, METH_NOARGS, Vector_toPoint_doc}, {"toTrackQuat", ( PyCFunction ) Vector_ToTrackQuat, METH_VARARGS, Vector_ToTrackQuat_doc}, + {"reflect", ( PyCFunction ) Vector_reflect, METH_O, Vector_reflect_doc}, {"copy", (PyCFunction) Vector_copy, METH_NOARGS, Vector_copy_doc}, {"__copy__", (PyCFunction) Vector_copy, METH_NOARGS, Vector_copy_doc}, {NULL, NULL, 0, NULL} @@ -273,7 +275,55 @@ PyObject *Vector_ToTrackQuat( VectorObject * self, PyObject * args ) return newQuaternionObject(quat, Py_NEW); } - +/*----------------------------Vector.reflect(mirror) ---------------------- + return a reflected vector on the mirror normal + ((2 * DotVecs(vec, mirror)) * mirror) - vec + using arithb.c would be nice here */ +PyObject *Vector_reflect( VectorObject * self, PyObject * value ) +{ + VectorObject *mirrvec; + float mirror[3]; + float vec[3]; + float reflect[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + float dot2; + + /* for normalizing */ + int i; + float norm = 0.0f; + + if (!VectorObject_Check(value)) + return EXPP_ReturnPyObjError( PyExc_TypeError, "expected a vector argument" ); + + mirrvec = (VectorObject *)value; + + mirror[0] = mirrvec->vec[0]; + mirror[1] = mirrvec->vec[1]; + if (mirrvec->size > 2) mirror[2] = mirrvec->vec[2]; + else mirror[2] = 0.0; + + /* normalize, whos idea was it not to use arithb.c? :-/ */ + for(i = 0; i < 3; i++) { + norm += mirror[i] * mirror[i]; + } + norm = (float) sqrt(norm); + for(i = 0; i < 3; i++) { + mirror[i] /= norm; + } + /* done */ + + vec[0] = self->vec[0]; + vec[1] = self->vec[1]; + if (self->size > 2) vec[2] = self->vec[2]; + else vec[2] = 0.0; + + dot2 = 2 * vec[0]*mirror[0]+vec[1]*mirror[1]+vec[2]*mirror[2]; + + reflect[0] = (dot2 * mirror[0]) - vec[0]; + reflect[1] = (dot2 * mirror[1]) - vec[1]; + reflect[2] = (dot2 * mirror[2]) - vec[2]; + + return newVectorObject(reflect, self->size, Py_NEW); +} /*----------------------------Vector.copy() -------------------------------------- return a copy of the vector */ diff --git a/source/blender/python/api2_2x/vector.h b/source/blender/python/api2_2x/vector.h index a86f2ddfe42..61b50d5f458 100644 --- a/source/blender/python/api2_2x/vector.h +++ b/source/blender/python/api2_2x/vector.h @@ -52,6 +52,7 @@ PyObject *Vector_Resize3D( VectorObject * self ); PyObject *Vector_Resize4D( VectorObject * self ); PyObject *Vector_toPoint( VectorObject * self ); PyObject *Vector_ToTrackQuat( VectorObject * self, PyObject * args ); +PyObject *Vector_reflect( VectorObject * self, PyObject * value ); PyObject *Vector_copy( VectorObject * self ); PyObject *newVectorObject(float *vec, int size, int type); diff --git a/source/blender/radiosity/CMakeLists.txt b/source/blender/radiosity/CMakeLists.txt index 36e9ad19770..941da41a5b2 100644 --- a/source/blender/radiosity/CMakeLists.txt +++ b/source/blender/radiosity/CMakeLists.txt @@ -29,7 +29,7 @@ FILE(GLOB SRC intern/source/*.c) SET(INC extern/include ../blenlib ../blenkernel ../makesdna ../include ../../../intern/guardedalloc ../render/extern/include - ../render/intern/include + ../render/intern/include ../blenloader ) BLENDERLIB_NOLIST(blender_radiosity "${SRC}" "${INC}") diff --git a/source/blender/radiosity/SConscript b/source/blender/radiosity/SConscript index 102f79683f9..a86b76bb4b1 100644 --- a/source/blender/radiosity/SConscript +++ b/source/blender/radiosity/SConscript @@ -5,7 +5,7 @@ sources = env.Glob('intern/source/*.c') incs = 'extern/include ../blenlib ../blenkernel ../makesdna ../include' incs += ' #/intern/guardedalloc ../render/extern/include' -incs += ' ../render/intern/include' +incs += ' ../render/intern/include ../blenloader' incs += ' ' + env['BF_OPENGL_INC'] diff --git a/source/blender/radiosity/intern/source/Makefile b/source/blender/radiosity/intern/source/Makefile index 19768c959c7..e5ff8c40d08 100644 --- a/source/blender/radiosity/intern/source/Makefile +++ b/source/blender/radiosity/intern/source/Makefile @@ -44,6 +44,7 @@ CPPFLAGS += -I../../../blenlib CPPFLAGS += -I../../../makesdna CPPFLAGS += -I../../../imbuf CPPFLAGS += -I../../../ +CPPFLAGS += -I../../../blenloader CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include # first /include is my own includes, second are the external includes diff --git a/source/blender/radiosity/intern/source/radnode.c b/source/blender/radiosity/intern/source/radnode.c index 5517a22eb93..042fe6840fc 100644 --- a/source/blender/radiosity/intern/source/radnode.c +++ b/source/blender/radiosity/intern/source/radnode.c @@ -50,6 +50,8 @@ #include "radio.h" +#include "BLO_sys_types.h" // for intptr_t support + #ifdef HAVE_CONFIG_H #include <config.h> #endif @@ -167,14 +169,14 @@ void *calloc_fast(int size) void free_fast(void *poin, int size) { MallocGroup *mg; - long val; + intptr_t val; mg= MallocBase.last; while(mg) { if(mg->size==size) { - if( ((long)poin) >= ((long)mg->data) ) { - if( ((long)poin) < ((long)(mg->data+MAL_GROUPSIZE*size)) ) { - val= ((long)poin) - ((long)mg->data); + if( ((intptr_t)poin) >= ((intptr_t)mg->data) ) { + if( ((intptr_t)poin) < ((intptr_t)(mg->data+MAL_GROUPSIZE*size)) ) { + val= ((intptr_t)poin) - ((intptr_t)mg->data); val/= size; mg->curfree= val; mg->flags[val]= 0; diff --git a/source/blender/radiosity/intern/source/radpreprocess.c b/source/blender/radiosity/intern/source/radpreprocess.c index 5f8a39786c1..07b933b6db9 100644 --- a/source/blender/radiosity/intern/source/radpreprocess.c +++ b/source/blender/radiosity/intern/source/radpreprocess.c @@ -68,6 +68,8 @@ #include "radio.h" +#include "BLO_sys_types.h" // for intptr_t support + #ifdef HAVE_CONFIG_H #include <config.h> #endif @@ -179,7 +181,7 @@ int vergedge(const void *v1,const void *v2) void addedge(float *v1, float *v2, EdSort *es) { - if( ((long)v1)<((long)v2) ) { + if( ((intptr_t)v1)<((intptr_t)v2) ) { es->v1= v1; es->v2= v2; } diff --git a/source/blender/render/CMakeLists.txt b/source/blender/render/CMakeLists.txt index b543dff49ff..0b659554d1a 100644 --- a/source/blender/render/CMakeLists.txt +++ b/source/blender/render/CMakeLists.txt @@ -29,7 +29,7 @@ FILE(GLOB SRC intern/source/*.c) SET(INC intern/include ../../../intern/guardedalloc ../blenlib ../makesdna extern/include ../blenkernel ../radiosity/extern/include ../imbuf - ../quicktime ../include ../../kernel/gen_messaging ../yafray + ../quicktime ../include ../../kernel/gen_messaging ../yafray ../blenloader ) IF(WITH_OPENEXR) diff --git a/source/blender/render/SConscript b/source/blender/render/SConscript index b1bc9673f23..f0d1353b0d3 100644 --- a/source/blender/render/SConscript +++ b/source/blender/render/SConscript @@ -6,7 +6,7 @@ sources = env.Glob('intern/source/*.c') incs = 'intern/include #/intern/guardedalloc ../blenlib ../makesdna' incs += ' extern/include ../blenkernel ../radiosity/extern/include ../imbuf' -incs += ' ../quicktime ../include ../../kernel/gen_messaging' +incs += ' ../quicktime ../include ../../kernel/gen_messaging ../blenloader' defs = [] diff --git a/source/blender/render/intern/include/render_types.h b/source/blender/render/intern/include/render_types.h index 2f97b19f75c..f83bbd7e8b2 100644 --- a/source/blender/render/intern/include/render_types.h +++ b/source/blender/render/intern/include/render_types.h @@ -44,6 +44,8 @@ #include "RE_shader_ext.h" /* TexResult, ShadeResult, ShadeInput */ #include "sunsky.h" +#include "BLO_sys_types.h" // for intptr_t support + struct Object; struct MemArena; struct VertTableNode; @@ -89,11 +91,11 @@ typedef struct RenderPart int *rectp; /* polygon index table */ int *rectz; /* zbuffer */ int *rectmask; /* negative zmask */ - long *rectdaps; /* delta acum buffer for pixel structs */ + intptr_t *rectdaps; /* delta acum buffer for pixel structs */ int *rectbacko; /* object table for backside sss */ int *rectbackp; /* polygon index table for backside sss */ int *rectbackz; /* zbuffer for backside sss */ - long *rectall; /* buffer for all faces for sss */ + intptr_t *rectall; /* buffer for all faces for sss */ rcti disprect; /* part coordinates within total picture */ int rectx, recty; /* the size */ @@ -226,7 +228,7 @@ struct ISBData; typedef struct ShadSampleBuf { struct ShadSampleBuf *next, *prev; - long *zbuf; + intptr_t *zbuf; char *cbuf; } ShadSampleBuf; diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c index e4a5ad67631..8626fb0f9d0 100644 --- a/source/blender/render/intern/source/convertblender.c +++ b/source/blender/render/intern/source/convertblender.c @@ -1565,7 +1565,7 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem float hasize, pa_size, pa_time, r_tilt, cfra=bsystem_time(ob,(float)CFRA,0.0); float adapt_angle=0.0, adapt_pix=0.0, random, simplify[2]; int i, a, k, max_k=0, totpart, totuv=0, totcol=0, override_uv=-1, dosimplify = 0, dosurfacecache = 0; - int path_possible=0, keys_possible=0, baked_keys=0, totchild=psys->totchild; + int path_possible=0, keys_possible=0, baked_keys=0, totchild=0; int seed, path_nbr=0, path=0, orco1=0, adapt=0, uv[3]={0,0,0}, num; int totface, *origindex = 0; char **uv_name=0; @@ -1573,6 +1573,8 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem /* 1. check that everything is ok & updated */ if(psys==NULL) return 0; + + totchild=psys->totchild; part=psys->part; pars=psys->particles; diff --git a/source/blender/render/intern/source/occlusion.c b/source/blender/render/intern/source/occlusion.c index d70c51b83bc..15c57eb9362 100644 --- a/source/blender/render/intern/source/occlusion.c +++ b/source/blender/render/intern/source/occlusion.c @@ -1670,7 +1670,7 @@ void cache_occ_samples(Render *re, RenderPart *pa, ShadeSample *ssamp) OcclusionCacheSample *sample; OccFace exclude; ShadeInput *shi; - long *rd=NULL; + intptr_t *rd=NULL; int *ro=NULL, *rp=NULL, *rz=NULL, onlyshadow; int x, y, step = CACHE_STEP; diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c index 6a0af82b4d7..3cd7bdc6772 100644 --- a/source/blender/render/intern/source/pipeline.c +++ b/source/blender/render/intern/source/pipeline.c @@ -138,7 +138,7 @@ static void print_error(char *str) {printf("ERROR: %s\n", str);} static void stats_background(RenderStats *rs) { - extern unsigned long mem_in_use; + extern uintptr_t mem_in_use; float megs_used_memory= mem_in_use/(1024.0*1024.0); char str[400], *spos= str; diff --git a/source/blender/render/intern/source/rendercore.c b/source/blender/render/intern/source/rendercore.c index 4520e4c10bb..4a2ad995b39 100644 --- a/source/blender/render/intern/source/rendercore.c +++ b/source/blender/render/intern/source/rendercore.c @@ -243,7 +243,7 @@ static void halo_tile(RenderPart *pa, RenderLayer *rl) rcti disprect= pa->disprect, testrect= pa->disprect; float dist, xsq, ysq, xn, yn; float col[4]; - long *rd= NULL; + intptr_t *rd= NULL; int a, *rz, zz, y, sample, totsample, od; short minx, maxx, miny, maxy, x; unsigned int lay= rl->lay; @@ -324,7 +324,7 @@ static void lamphalo_tile(RenderPart *pa, RenderLayer *rl) ShadeInput shi; float *pass; float fac, col[4]; - long *rd= pa->rectdaps; + intptr_t *rd= pa->rectdaps; int *rz= pa->rectz; int x, y, sample, totsample, fullsample, od; @@ -767,7 +767,7 @@ static void shadeDA_tile(RenderPart *pa, RenderLayer *rl) { RenderResult *rr= pa->result; ShadeSample ssamp; - long *rd, *rectdaps= pa->rectdaps; + intptr_t *rd, *rectdaps= pa->rectdaps; int samp; int x, y, seed, crop=0, offs=0, od; @@ -874,7 +874,7 @@ static void freeps(ListBase *lb) lb->first= lb->last= NULL; } -static void addps(ListBase *lb, long *rd, int obi, int facenr, int z, int maskz, unsigned short mask) +static void addps(ListBase *lb, intptr_t *rd, int obi, int facenr, int z, int maskz, unsigned short mask) { PixStrMain *psm; PixStr *ps, *last= NULL; @@ -901,7 +901,7 @@ static void addps(ListBase *lb, long *rd, int obi, int facenr, int z, int maskz, ps= psm->ps + psm->counter++; if(last) last->next= ps; - else *rd= (long)ps; + else *rd= (intptr_t)ps; ps->next= NULL; ps->obi= obi; @@ -1027,7 +1027,7 @@ static void reset_sky_speed(RenderPart *pa, RenderLayer *rl) static unsigned short *make_solid_mask(RenderPart *pa) { - long *rd= pa->rectdaps; + intptr_t *rd= pa->rectdaps; unsigned short *solidmask, *sp; int x; @@ -1092,7 +1092,7 @@ void make_pixelstructs(RenderPart *pa, ZSpan *zspan, int sample, void *data) { ZbufSolidData *sdata= (ZbufSolidData*)data; ListBase *lb= sdata->psmlist; - long *rd= pa->rectdaps; + intptr_t *rd= pa->rectdaps; int *ro= zspan->recto; int *rp= zspan->rectp; int *rz= zspan->rectz; @@ -1133,7 +1133,7 @@ void zbufshadeDA_tile(RenderPart *pa) /* initialize pixelstructs and edge buffer */ addpsmain(&psmlist); - pa->rectdaps= MEM_callocN(sizeof(long)*pa->rectx*pa->recty+4, "zbufDArectd"); + pa->rectdaps= MEM_callocN(sizeof(intptr_t)*pa->rectx*pa->recty+4, "zbufDArectd"); if(rl->layflag & SCE_LAY_EDGE) if(R.r.mode & R_EDGE) @@ -1433,7 +1433,7 @@ static void addps_sss(void *cb_handle, int obi, int facenr, int x, int y, int z) return; if(pa->rectall) { - long *rs= pa->rectall + pa->rectx*y + x; + intptr_t *rs= pa->rectall + pa->rectx*y + x; addps(&handle->psmlist, rs, obi, facenr, z, 0, 0); handle->totps++; @@ -1569,7 +1569,7 @@ void zbufshade_sss_tile(RenderPart *pa) int *ro, *rz, *rp, *rbo, *rbz, *rbp, lay; #if 0 PixStr *ps; - long *rs; + intptr_t *rs; int z; #endif @@ -1581,7 +1581,7 @@ void zbufshade_sss_tile(RenderPart *pa) handle.psmlist.first= handle.psmlist.last= NULL; addpsmain(&handle.psmlist); - pa->rectall= MEM_callocN(sizeof(long)*pa->rectx*pa->recty+4, "rectall"); + pa->rectall= MEM_callocN(sizeof(intptr_t)*pa->rectx*pa->recty+4, "rectall"); #else pa->recto= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "recto"); pa->rectp= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "rectp"); diff --git a/source/blender/render/intern/source/shadbuf.c b/source/blender/render/intern/source/shadbuf.c index f3258b601de..f477df3ed8c 100644 --- a/source/blender/render/intern/source/shadbuf.c +++ b/source/blender/render/intern/source/shadbuf.c @@ -171,7 +171,7 @@ static void compress_shadowbuf(ShadBuf *shb, int *rectz, int square) { ShadSampleBuf *shsample; float dist; - unsigned long *ztile; + uintptr_t *ztile; int *rz, *rz1, verg, verg1, size= shb->size; int a, x, y, minx, miny, byt1, byt2; char *rc, *rcline, *ctile, *zt; @@ -179,10 +179,10 @@ static void compress_shadowbuf(ShadBuf *shb, int *rectz, int square) shsample= MEM_mallocN( sizeof(ShadSampleBuf), "shad sample buf"); BLI_addtail(&shb->buffers, shsample); - shsample->zbuf= MEM_mallocN( sizeof(unsigned long)*(size*size)/256, "initshadbuf2"); + shsample->zbuf= MEM_mallocN( sizeof(uintptr_t)*(size*size)/256, "initshadbuf2"); shsample->cbuf= MEM_callocN( (size*size)/256, "initshadbuf3"); - ztile= (unsigned long *)shsample->zbuf; + ztile= (uintptr_t *)shsample->zbuf; ctile= shsample->cbuf; /* help buffer */ @@ -237,7 +237,7 @@ static void compress_shadowbuf(ShadBuf *shb, int *rectz, int square) } if(byt1 && byt2) { /* only store byte */ *ctile= 1; - *ztile= (unsigned long)MEM_mallocN(256+4, "tile1"); + *ztile= (uintptr_t)MEM_mallocN(256+4, "tile1"); rz= (int *)*ztile; *rz= *rz1; @@ -247,7 +247,7 @@ static void compress_shadowbuf(ShadBuf *shb, int *rectz, int square) } else if(byt1) { /* only store short */ *ctile= 2; - *ztile= (unsigned long)MEM_mallocN(2*256+4,"Tile2"); + *ztile= (uintptr_t)MEM_mallocN(2*256+4,"Tile2"); rz= (int *)*ztile; *rz= *rz1; @@ -260,7 +260,7 @@ static void compress_shadowbuf(ShadBuf *shb, int *rectz, int square) } else { /* store triple */ *ctile= 3; - *ztile= (unsigned long)MEM_mallocN(3*256,"Tile3"); + *ztile= (uintptr_t)MEM_mallocN(3*256,"Tile3"); zt= (char *)*ztile; rc= rcline; @@ -542,7 +542,7 @@ void freeshadowbuf(LampRen *lar) v= (shb->size*shb->size)/256; for(shsample= shb->buffers.first; shsample; shsample= shsample->next) { - long *ztile= shsample->zbuf; + intptr_t *ztile= shsample->zbuf; char *ctile= shsample->cbuf; for(b=0; b<v; b++, ztile++, ctile++) @@ -1752,7 +1752,7 @@ static void isb_make_buffer(RenderPart *pa, LampRen *lar) ISBSample *samp, *samplebuf[16]; /* should be RE_MAX_OSA */ ISBBranch root; MemArena *memarena; - long *rd; + intptr_t *rd; int *recto, *rectp, x, y, sindex, sample, bsp_err=0; /* storage for shadow, per thread */ diff --git a/source/blender/render/intern/source/strand.c b/source/blender/render/intern/source/strand.c index 591d51a969d..05e36160f0e 100644 --- a/source/blender/render/intern/source/strand.c +++ b/source/blender/render/intern/source/strand.c @@ -416,7 +416,7 @@ typedef struct StrandPart { int *totapixbuf; int *rectz; int *rectmask; - long *rectdaps; + intptr_t *rectdaps; int rectx, recty; int sample; @@ -510,7 +510,7 @@ static void do_strand_fillac(void *handle, int x, int y, float u, float v, float if(spart->rectdaps) { /* find the z of the sample */ PixStr *ps; - long *rd= spart->rectdaps + offset; + intptr_t *rd= spart->rectdaps + offset; bufferz= 0x7FFFFFFF; if(spart->rectmask) maskz= 0x7FFFFFFF; diff --git a/source/blender/render/intern/source/zbuf.c b/source/blender/render/intern/source/zbuf.c index c91c9e2f799..29aa6e3be29 100644 --- a/source/blender/render/intern/source/zbuf.c +++ b/source/blender/render/intern/source/zbuf.c @@ -2278,7 +2278,7 @@ static int hashlist_projectvert(float *v1, float winmat[][4], float *hoco) return 0; } - buck= &bucket[ (((long)v1)/16) & 255 ]; + buck= &bucket[ (((intptr_t)v1)/16) & 255 ]; if(buck->vert==v1) { QUATCOPY(hoco, buck->hoco); return buck->clip; @@ -3263,7 +3263,7 @@ static void copyto_abufz(RenderPart *pa, int *arectz, int *rectmask, int sample) { PixStr *ps; int x, y, *rza, *rma; - long *rd; + intptr_t *rd; if(R.osa==0) { memcpy(arectz, pa->rectz, sizeof(int)*pa->rectx*pa->recty); @@ -3484,7 +3484,7 @@ static int zbuffer_abuf(RenderPart *pa, APixstr *APixbuf, ListBase *apsmbase, Re /* speed pointer NULL = sky, we clear */ /* else if either alpha is full or no solid was filled in: copy speed */ /* else fill in minimum speed */ -void add_transp_speed(RenderLayer *rl, int offset, float *speed, float alpha, long *rdrect) +void add_transp_speed(RenderLayer *rl, int offset, float *speed, float alpha, intptr_t *rdrect) { RenderPass *rpass; @@ -3958,7 +3958,7 @@ unsigned short *zbuffer_transp_shade(RenderPart *pa, RenderLayer *rl, float *pas ZTranspRow zrow[MAX_ZROW]; StrandShadeCache *sscache= NULL; float sampalpha, alpha, *passrect= pass; - long *rdrect; + intptr_t *rdrect; int x, y, crop=0, a, b, totface, totsample, doztra; int addpassflag, offs= 0, od, addzbuf, osa = (R.osa? R.osa: 1); unsigned short *ztramask= NULL, filled; diff --git a/source/blender/src/buttons_editing.c b/source/blender/src/buttons_editing.c index cb6f7e629fa..76f244db6fc 100644 --- a/source/blender/src/buttons_editing.c +++ b/source/blender/src/buttons_editing.c @@ -1826,6 +1826,16 @@ static void draw_modifier(uiBlock *block, Object *ob, ModifierData *md, int *xco height = 94; } else if (md->type==eModifierType_Explode) { height = 94; + } else if (md->type==eModifierType_Shrinkwrap) { + ShrinkwrapModifierData *smd = (ShrinkwrapModifierData*) md; + height = 86 + 3; + if (smd->shrinkType == MOD_SHRINKWRAP_PROJECT) + { + height += 19*5; + if(smd->projAxis == 0) height += 19; + } + else if (smd->shrinkType == MOD_SHRINKWRAP_NEAREST_SURFACE) + height += 19; } /* roundbox 4 free variables: corner-rounding, nop, roundbox type, shade */ uiDefBut(block, ROUNDBOX, 0, "", x-10, y-height-2, width, height-2, NULL, 5.0, 0.0, 12, 40, ""); @@ -2446,6 +2456,51 @@ static void draw_modifier(uiBlock *block, Object *ob, ModifierData *md, int *xco uiDefButBitS(block, TOG, eExplodeFlag_Alive, B_MODIFIER_RECALC, "Alive", lx+buttonWidth/3, cy, buttonWidth/3,19, &emd->flag, 0, 0, 0, 0, "Show mesh when particles are alive"); uiDefButBitS(block, TOG, eExplodeFlag_Dead, B_MODIFIER_RECALC, "Dead", lx+buttonWidth*2/3, cy, buttonWidth/3,19, &emd->flag, 0, 0, 0, 0, "Show mesh when particles are dead"); uiBlockEndAlign(block); + } else if (md->type==eModifierType_Shrinkwrap) { + ShrinkwrapModifierData *smd = (ShrinkwrapModifierData*) md; + + char shrinktypemenu[]="Shrinkwrap type%t|nearest surface point %x0|projection %x1|nearest vertex %x2"; + + uiDefIDPoinBut(block, modifier_testMeshObj, ID_OB, B_CHANGEDEP, "Ob: ", lx, (cy-=19), buttonWidth,19, &smd->target, "Target to shrink to"); + + but=uiDefBut(block, TEX, B_MODIFIER_RECALC, "VGroup: ", lx, (cy-=19), buttonWidth,19, &smd->vgroup_name, 0, 31, 0, 0, "Vertex Group name"); + uiButSetCompleteFunc(but, autocomplete_vgroup, (void *)ob); + + uiDefButF(block, NUM, B_MODIFIER_RECALC, "Offset:", lx,(cy-=19),buttonWidth,19, &smd->keepDist, 0.0f, 100.0f, 1.0f, 0, "Specify distance to keep from the target"); + + cy -= 3; + uiDefButS(block, MENU, B_MODIFIER_RECALC, shrinktypemenu, lx,(cy-=19),buttonWidth,19, &smd->shrinkType, 0, 0, 0, 0, "Selects type of shrinkwrap algorithm for target position."); + + if (smd->shrinkType == MOD_SHRINKWRAP_PROJECT){ + + + /* UI for projection axis */ + uiBlockBeginAlign(block); + uiDefButC(block, ROW, B_MODIFIER_RECALC, "Normal" , lx,(cy-=19),buttonWidth,19, &smd->projAxis, 18.0, MOD_SHRINKWRAP_PROJECT_OVER_NORMAL, 0, 0, "Projection over X axis"); + if(smd->projAxis == 0) + { + uiDefButC(block, NUM, B_MODIFIER_RECALC, "SS Levels:", lx, (cy-=19), buttonWidth,19, &smd->subsurfLevels, 0, 6, 0, 0, "This indicates the number of CCSubdivisions that must be performed before extracting vertexs positions and normals"); + } + + uiDefButBitC(block, TOG, MOD_SHRINKWRAP_PROJECT_OVER_X_AXIS, B_MODIFIER_RECALC, "X", lx+buttonWidth/3*0,(cy-=19),buttonWidth/3,19, &smd->projAxis, 0, 0, 0, 0, "Projection over X axis"); + uiDefButBitC(block, TOG, MOD_SHRINKWRAP_PROJECT_OVER_Y_AXIS, B_MODIFIER_RECALC, "Y", lx+buttonWidth/3*1,cy,buttonWidth/3,19, &smd->projAxis, 0, 0, 0, 0, "Projection over Y axis"); + uiDefButBitC(block, TOG, MOD_SHRINKWRAP_PROJECT_OVER_Z_AXIS, B_MODIFIER_RECALC, "Z", lx+buttonWidth/3*2,cy,buttonWidth/3,19, &smd->projAxis, 0, 0, 0, 0, "Projection over Z axis"); + + + /* allowed directions of projection axis */ + uiDefButBitS(block, TOG, MOD_SHRINKWRAP_PROJECT_ALLOW_NEG_DIR, B_MODIFIER_RECALC, "Negative", lx,(cy-=19),buttonWidth/2,19, &smd->shrinkOpts, 0, 0, 0, 0, "Allows to move the vertex in the negative direction of axis"); + uiDefButBitS(block, TOG, MOD_SHRINKWRAP_PROJECT_ALLOW_POS_DIR, B_MODIFIER_RECALC, "Positive", lx + buttonWidth/2,cy,buttonWidth/2,19, &smd->shrinkOpts, 0, 0, 0, 0, "Allows to move the vertex in the positive direction of axis"); + + uiDefButBitS(block, TOG, MOD_SHRINKWRAP_CULL_TARGET_FRONTFACE, B_MODIFIER_RECALC, "Cull frontfaces",lx,(cy-=19),buttonWidth/2,19, &smd->shrinkOpts, 0, 0, 0, 0, "Controls whether a vertex can be projected to a front face on target"); + uiDefButBitS(block, TOG, MOD_SHRINKWRAP_CULL_TARGET_BACKFACE, B_MODIFIER_RECALC, "Cull backfaces", lx+buttonWidth/2,cy,buttonWidth/2,19, &smd->shrinkOpts, 0, 0, 0, 0, "Controls whether a vertex can be projected to a back face on target"); + uiDefIDPoinBut(block, modifier_testMeshObj, ID_OB, B_CHANGEDEP, "Ob2: ", lx, (cy-=19), buttonWidth,19, &smd->auxTarget, "Aditional mesh to project over"); + } + else if (smd->shrinkType == MOD_SHRINKWRAP_NEAREST_SURFACE){ + uiDefButBitS(block, TOG, MOD_SHRINKWRAP_KEEP_ABOVE_SURFACE, B_MODIFIER_RECALC, "Above surface", lx,(cy-=19),buttonWidth,19, &smd->shrinkOpts, 0, 0, 0, 0, "Vertices are kept on the front side of faces"); + } + + uiBlockEndAlign(block); + } uiBlockEndAlign(block); @@ -4145,7 +4200,7 @@ static void validate_posebonebutton_cb(void *bonev, void *namev) static void armature_layer_cb(void *lay_v, void *value_v) { short *layer= lay_v; - int value= (long)value_v; + int value= (intptr_t)value_v; if(*layer==0 || G.qual==0) *layer= value; allqueue(REDRAWBUTSEDIT, 0); diff --git a/source/blender/src/buttons_logic.c b/source/blender/src/buttons_logic.c index 8788363c19b..9b41b646bc8 100644 --- a/source/blender/src/buttons_logic.c +++ b/source/blender/src/buttons_logic.c @@ -683,6 +683,8 @@ static char *sensor_name(int type) return "Property"; case SENS_ACTUATOR: return "Actuator"; + case SENS_DELAY: + return "Delay"; case SENS_MOUSE: return "Mouse"; case SENS_COLLISION: @@ -704,7 +706,7 @@ static char *sensor_name(int type) static char *sensor_pup(void) { /* the number needs to match defines in game.h */ - return "Sensors %t|Always %x0|Keyboard %x3|Mouse %x5|" + return "Sensors %t|Always %x0|Delay %x13|Keyboard %x3|Mouse %x5|" "Touch %x1|Collision %x6|Near %x2|Radar %x7|" "Property %x4|Random %x8|Ray %x9|Message %x10|Joystick %x11|Actuator %x12"; } @@ -1000,6 +1002,7 @@ static int get_col_sensor(int type) { switch(type) { case SENS_ALWAYS: return TH_BUT_ACTION; + case SENS_DELAY: return TH_BUT_ACTION; case SENS_TOUCH: return TH_BUT_NEUTRAL; case SENS_COLLISION: return TH_BUT_SETTING; case SENS_NEAR: return TH_BUT_SETTING1; @@ -1070,8 +1073,8 @@ static short draw_sensorbuttons(bSensor *sens, uiBlock *block, short xco, short bRaySensor *raySens = NULL; bMessageSensor *mes = NULL; bJoystickSensor *joy = NULL; - bActuatorSensor *as = NULL; - + bActuatorSensor *as = NULL; + bDelaySensor *ds = NULL; short ysize; char *str; @@ -1297,6 +1300,27 @@ static short draw_sensorbuttons(bSensor *sens, uiBlock *block, short xco, short yco-= ysize; break; } + case SENS_DELAY: + { + ysize= 48; + + glRects(xco, yco-ysize, xco+width, yco); + uiEmboss((float)xco, (float)yco-ysize, + (float)xco+width, (float)yco, 1); + + draw_default_sensor_header(sens, block, xco, yco, width); + ds = sens->data; + + uiDefButS(block, NUM, 0, "Delay",(short)(10+xco),(short)(yco-44),(short)((width-22)*0.4+10), 19, + &ds->delay, 0.0, 5000.0, 0, 0, "Delay in number of frames before the positive trigger"); + uiDefButS(block, NUM, 0, "Dur",(short)(10+xco+(width-22)*0.4+10),(short)(yco-44),(short)((width-22)*0.4-10), 19, + &ds->duration, 0.0, 5000.0, 0, 0, "If >0, delay in number of frames before the negative trigger following the positive trigger"); + uiDefButBitS(block, TOG, SENS_DELAY_REPEAT, 0, "REP",(short)(xco + 10 + (width-22)*0.8),(short)(yco - 44), + (short)(0.20 * (width-22)), 19, &ds->flag, 0.0, 0.0, 0, 0, + "Toggle repeat option. If selected, the sensor restarts after Delay+Dur frames"); + yco-= ysize; + break; + } case SENS_MOUSE: { ms= sens->data; @@ -1366,9 +1390,14 @@ static short draw_sensorbuttons(bSensor *sens, uiBlock *block, short xco, short &raySens->propname, 0, 31, 0, 0, "Only look for Objects with this property"); } - + + /* X-Ray option */ + uiDefButBitS(block, TOG, SENS_RAY_XRAY, 1, "X", + xco + 10,yco - 68, 0.10 * (width-20), 19, + &raySens->mode, 0.0, 0.0, 0, 0, + "Toggle X-Ray option (see through objects that don't have the property)"); /* 2. sensing range */ - uiDefButF(block, NUM, 1, "Range", xco+10, yco-68, 0.6 * (width-20), 19, + uiDefButF(block, NUM, 1, "Range", xco+10 + 0.10 * (width-20), yco-68, 0.5 * (width-20), 19, &raySens->range, 0.01, 10000.0, 100, 0, "Sense objects no farther than this distance"); @@ -1833,7 +1862,7 @@ static short draw_actuatorbuttons(Object *ob, bActuator *act, uiBlock *block, sh but = uiDefButBitS(block, TOG, ACT_IPOFORCE, ACT_IPOFORCE, "Force", xco+10+(width-20)/2, yco-24, (width-20)/4-10, 19, &ia->flag, 0, 0, 0, 0, - "Convert Ipo to force. Force is applied in global or local coordinate according to Local flag"); + "Apply Ipo as a global or local force depending on the local option (dynamic objects only)"); uiButSetFunc(but, change_ipo_actuator, but, ia); but = uiDefButBitS(block, TOG, ACT_IPOADD, ACT_IPOADD, @@ -1998,7 +2027,7 @@ static short draw_actuatorbuttons(Object *ob, bActuator *act, uiBlock *block, sh if(eoa->type==ACT_EDOB_ADD_OBJECT) { int wval; /* just a temp width */ - ysize = 72; + ysize = 92; glRects(xco, yco-ysize, xco+width, yco); uiEmboss((float)xco, (float)yco-ysize, (float)xco+width, (float)yco, 1); @@ -2018,9 +2047,27 @@ static short draw_actuatorbuttons(Object *ob, bActuator *act, uiBlock *block, sh uiDefButF(block, NUM, 0, "", xco+45+2*wval, yco-68, wval, 19, eoa->linVelocity+2, -100.0, 100.0, 10, 0, "Velocity upon creation, z component."); - uiDefButBitS(block, TOG, 2, 0, "L", xco+45+3*wval, yco-68, 15, 19, + uiDefButBitS(block, TOG, ACT_EDOB_LOCAL_LINV, 0, "L", xco+45+3*wval, yco-68, 15, 19, &eoa->localflag, 0.0, 0.0, 0, 0, "Apply the transformation locally"); + + + uiDefBut(block, LABEL, 0, "AngV", xco, yco-90, 45, 19, + NULL, 0, 0, 0, 0, + "Angular velocity upon creation."); + uiDefButF(block, NUM, 0, "", xco+45, yco-90, wval, 19, + eoa->angVelocity, -10000.0, 10000.0, 10, 0, + "Angular velocity upon creation, x component."); + uiDefButF(block, NUM, 0, "", xco+45+wval, yco-90, wval, 19, + eoa->angVelocity+1, -10000.0, 10000.0, 10, 0, + "Angular velocity upon creation, y component."); + uiDefButF(block, NUM, 0, "", xco+45+2*wval, yco-90, wval, 19, + eoa->angVelocity+2, -10000.0, 10000.0, 10, 0, + "Angular velocity upon creation, z component."); + uiDefButBitS(block, TOG, ACT_EDOB_LOCAL_ANGV, 0, "L", xco+45+3*wval, yco-90, 15, 19, + &eoa->localflag, 0.0, 0.0, 0, 0, + "Apply the rotation locally"); + } else if(eoa->type==ACT_EDOB_END_OBJECT) { @@ -3183,7 +3230,8 @@ void logic_buts(void) while(cont) { for (iact=0; iact<cont->totlinks; iact++) { act = cont->links[iact]; - act->flag |= ACT_LINKED; + if (act) + act->flag |= ACT_LINKED; } controller_state_mask |= cont->state_mask; cont = cont->next; @@ -3231,7 +3279,8 @@ void logic_buts(void) /* this controller is visible, mark all its actuator */ for (iact=0; iact<cont->totlinks; iact++) { act = cont->links[iact]; - act->flag |= ACT_VISIBLE; + if (act) + act->flag |= ACT_VISIBLE; } uiBlockSetEmboss(block, UI_EMBOSSM); uiDefIconButBitS(block, TOG, CONT_DEL, B_DEL_CONT, ICON_X, xco, yco, 22, 19, &cont->flag, 0, 0, 0, 0, "Delete Controller"); @@ -3323,8 +3372,8 @@ void logic_buts(void) ycoo= yco; if(sens->flag & SENS_SHOW) { - uiDefButS(block, MENU, B_CHANGE_SENS, sensor_pup(), (short)(xco+22), yco, 100, 19, &sens->type, 0, 0, 0, 0, "Sensor type"); - but= uiDefBut(block, TEX, 1, "", (short)(xco+122), yco, (short)(width-144), 19, sens->name, 0, 31, 0, 0, "Sensor name"); + uiDefButS(block, MENU, B_CHANGE_SENS, sensor_pup(), (short)(xco+22), yco, 80, 19, &sens->type, 0, 0, 0, 0, "Sensor type"); + but= uiDefBut(block, TEX, 1, "", (short)(xco+102), yco, (short)(width-124), 19, sens->name, 0, 31, 0, 0, "Sensor name"); uiButSetFunc(but, make_unique_prop_names_cb, sens->name, (void*) 0); sens->otype= sens->type; @@ -3334,9 +3383,9 @@ void logic_buts(void) else { set_col_sensor(sens->type, 1); glRecti(xco+22, yco, xco+width-22,yco+19); - but= uiDefBut(block, LABEL, 0, sensor_name(sens->type), (short)(xco+22), yco, 100, 19, sens, 0, 0, 0, 0, ""); + but= uiDefBut(block, LABEL, 0, sensor_name(sens->type), (short)(xco+22), yco, 80, 19, sens, 0, 0, 0, 0, ""); uiButSetFunc(but, sca_move_sensor, sens, NULL); - but= uiDefBut(block, LABEL, 0, sens->name, (short)(xco+122), yco, (short)(width-144), 19, sens, 0, 31, 0, 0, ""); + but= uiDefBut(block, LABEL, 0, sens->name, (short)(xco+102), yco, (short)(width-124), 19, sens, 0, 31, 0, 0, ""); uiButSetFunc(but, sca_move_sensor, sens, NULL); } @@ -3393,8 +3442,8 @@ void logic_buts(void) if(act->flag & ACT_SHOW) { act->otype= act->type; - uiDefButS(block, MENU, B_CHANGE_ACT, actuator_pup(ob), (short)(xco+22), yco, 100, 19, &act->type, 0, 0, 0, 0, "Actuator type"); - but= uiDefBut(block, TEX, 1, "", (short)(xco+122), yco, (short)(width-144), 19, act->name, 0, 31, 0, 0, "Actuator name"); + uiDefButS(block, MENU, B_CHANGE_ACT, actuator_pup(ob), (short)(xco+22), yco, 90, 19, &act->type, 0, 0, 0, 0, "Actuator type"); + but= uiDefBut(block, TEX, 1, "", (short)(xco+112), yco, (short)(width-134), 19, act->name, 0, 31, 0, 0, "Actuator name"); uiButSetFunc(but, make_unique_prop_names_cb, act->name, (void*) 0); ycoo= yco; @@ -3404,9 +3453,9 @@ void logic_buts(void) else { set_col_actuator(act->type, 1); glRecti((short)(xco+22), yco, (short)(xco+width-22),(short)(yco+19)); - but= uiDefBut(block, LABEL, 0, actuator_name(act->type), (short)(xco+22), yco, 100, 19, act, 0, 0, 0, 0, "Actuator type"); + but= uiDefBut(block, LABEL, 0, actuator_name(act->type), (short)(xco+22), yco, 90, 19, act, 0, 0, 0, 0, "Actuator type"); uiButSetFunc(but, sca_move_actuator, act, NULL); - but= uiDefBut(block, LABEL, 0, act->name, (short)(xco+122), yco, (short)(width-144), 19, act, 0, 0, 0, 0, "Actuator name"); + but= uiDefBut(block, LABEL, 0, act->name, (short)(xco+112), yco, (short)(width-134), 19, act, 0, 0, 0, 0, "Actuator name"); uiButSetFunc(but, sca_move_actuator, act, NULL); ycoo= yco; } diff --git a/source/blender/src/buttons_object.c b/source/blender/src/buttons_object.c index 58f3bff09c8..b0d612456d2 100644 --- a/source/blender/src/buttons_object.c +++ b/source/blender/src/buttons_object.c @@ -3279,6 +3279,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); @@ -3294,12 +3296,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)."); + } } } } @@ -3309,6 +3317,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; @@ -3330,7 +3339,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); @@ -3342,8 +3351,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 */ @@ -3356,8 +3373,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)"; @@ -3365,11 +3382,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)"; @@ -3384,8 +3401,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); @@ -3411,6 +3426,8 @@ static void object_panel_fields(Object *ob) } else if(pd->forcefield == PFIELD_HARMONIC) uiDefButF(block, NUM, B_FIELD_CHANGE, "Damp: ", 10,120,140,20, &pd->f_damp, 0, 10, 10, 0, "Damping of the harmonic force"); + else if(pd->forcefield == PFIELD_WIND) + uiDefButF(block, NUM, B_FIELD_CHANGE, "Noise: ",10,120,140,20, &pd->f_noise, 0, 10, 100, 0, "Noise of the wind force"); } uiBlockEndAlign(block); @@ -3449,40 +3466,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); } } @@ -4329,6 +4355,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/buttons_scene.c b/source/blender/src/buttons_scene.c index fb6a7636e16..5205be3e1b0 100644 --- a/source/blender/src/buttons_scene.c +++ b/source/blender/src/buttons_scene.c @@ -33,6 +33,7 @@ #include <string.h> #include "MEM_guardedalloc.h" +#include "BLO_sys_types.h" // for intptr_t support #include "DNA_node_types.h" #include "DNA_screen_types.h" #include "DNA_space_types.h" @@ -3261,7 +3262,7 @@ static void layer_copy_func(void *lay_v, void *lay_p) static void delete_scene_layer_func(void *srl_v, void *act_i) { if(BLI_countlist(&G.scene->r.layers)>1) { - long act= (long)act_i; + intptr_t act= (intptr_t)act_i; BLI_remlink(&G.scene->r.layers, srl_v); MEM_freeN(srl_v); @@ -3322,7 +3323,7 @@ static char *scene_layer_menu(void) static void draw_3d_layer_buttons(uiBlock *block, int type, unsigned int *poin, short xco, short yco, short dx, short dy, char *tip) { uiBut *bt; - long a; + intptr_t a; uiBlockBeginAlign(block); for(a=0; a<5; a++) { @@ -3381,7 +3382,7 @@ static void render_panel_layers(void) uiDefButBitI(block, TOG, R_SINGLE_LAYER, B_NOP, "Single", 230,145,60,20, &G.scene->r.scemode, 0, 0, 0, 0, "Only render this layer"); bt=uiDefIconBut(block, BUT, B_NOP, ICON_X, 285, 145, 25, 20, 0, 0, 0, 0, 0, "Deletes current Render Layer"); - uiButSetFunc(bt, delete_scene_layer_func, srl, (void *)(long)G.scene->r.actlay); + uiButSetFunc(bt, delete_scene_layer_func, srl, (void *)(intptr_t)G.scene->r.actlay); uiBlockEndAlign(block); /* RenderLayer visible-layers */ diff --git a/source/blender/src/drawgpencil.c b/source/blender/src/drawgpencil.c index ee28049e2c0..15f65bfe3cf 100644 --- a/source/blender/src/drawgpencil.c +++ b/source/blender/src/drawgpencil.c @@ -37,6 +37,9 @@ #include "MEM_guardedalloc.h" +#include "IMB_imbuf.h" +#include "IMB_imbuf_types.h" + #include "BMF_Api.h" #include "BLI_arithb.h" @@ -142,6 +145,13 @@ void gp_ui_delframe_cb (void *gpd, void *gpl) allqueue(REDRAWACTION, 0); } +/* convert the active layer to geometry */ +void gp_ui_convertlayer_cb (void *gpd, void *gpl) +{ + gpencil_layer_setactive(gpd, gpl); + gpencil_convert_menu(); +} + /* ------- Drawing Code ------- */ /* draw the controls for a given layer */ @@ -163,7 +173,7 @@ static void gp_drawui_layer (uiBlock *block, bGPdata *gpd, bGPDlayer *gpl, short /* rounded header */ if (active) uiBlockSetCol(block, TH_BUT_ACTION); rb_col= (active)?-20:20; - uiDefBut(block, ROUNDBOX, B_DIFF, "", *xco-8, *yco-2, width, 24, NULL, 5.0, 0.0, 15 , rb_col-20, ""); + uiDefBut(block, ROUNDBOX, B_REDR, "", *xco-8, *yco-2, width, 24, NULL, 5.0, 0.0, 15 , rb_col-20, ""); if (active) uiBlockSetCol(block, TH_AUTO); /* lock toggle */ @@ -174,7 +184,7 @@ static void gp_drawui_layer (uiBlock *block, bGPdata *gpd, bGPDlayer *gpl, short if (gpl->flag & (GP_LAYER_LOCKED|GP_LAYER_HIDE)) { char name[256]; /* gpl->info is 128, but we need space for 'locked/hidden' as well */ - height= 26; + height= 0; /* visibility button (only if hidden but not locked!) */ if ((gpl->flag & GP_LAYER_HIDE) && !(gpl->flag & GP_LAYER_LOCKED)) @@ -246,8 +256,14 @@ static void gp_drawui_layer (uiBlock *block, bGPdata *gpd, bGPDlayer *gpl, short /* options */ uiBlockBeginAlign(block); - but= uiDefBut(block, BUT, B_REDR, "Del Active Frame", *xco+160, *yco-75, 140, 20, NULL, 0, 0, 0, 0, "Erases the the active frame for this layer (Hotkey = Alt-XKEY/DEL)"); - uiButSetFunc(but, gp_ui_delframe_cb, gpd, gpl); + if (curarea->spacetype == SPACE_VIEW3D) { + but= uiDefBut(block, BUT, B_REDR, "Convert to...", *xco+160, *yco-75, 140, 20, NULL, 0, 0, 0, 0, "Converts this layer's strokes to geometry (Hotkey = Alt-Shift-C)"); + uiButSetFunc(but, gp_ui_convertlayer_cb, gpd, gpl); + } + else { + but= uiDefBut(block, BUT, B_REDR, "Del Active Frame", *xco+160, *yco-75, 140, 20, NULL, 0, 0, 0, 0, "Erases the the active frame for this layer (Hotkey = Alt-XKEY/DEL)"); + uiButSetFunc(but, gp_ui_delframe_cb, gpd, gpl); + } but= uiDefBut(block, BUT, B_REDR, "Del Last Stroke", *xco+160, *yco-95, 140, 20, NULL, 0, 0, 0, 0, "Erases the last stroke from the active frame (Hotkey = Alt-XKEY/DEL)"); uiButSetFunc(but, gp_ui_delstroke_cb, gpd, gpl); @@ -317,8 +333,12 @@ enum { GP_DRAWDATA_NOSTATUS = (1<<0), /* don't draw status info */ GP_DRAWDATA_ONLY3D = (1<<1), /* only draw 3d-strokes */ GP_DRAWDATA_ONLYV2D = (1<<2), /* only draw 'canvas' strokes */ + GP_DRAWDATA_ONLYI2D = (1<<3), /* only draw 'image' strokes */ }; +/* thickness above which we should use special drawing */ +#define GP_DRAWTHICKNESS_SPECIAL 3 + /* ----- Tool Buffer Drawing ------ */ /* draw stroke defined in buffer (simple ogl lines/points for now, as dotted lines) */ @@ -343,23 +363,13 @@ static void gp_draw_stroke_buffer (tGPspoint *points, int totpoints, short thick glEnd(); } else if (sflag & GP_STROKE_ERASER) { - /* draw stroke curve - just standard thickness */ - setlinestyle(4); - glLineWidth(1.0f); - - glBegin(GL_LINE_STRIP); - for (i=0, pt=points; i < totpoints && pt; i++, pt++) { - glVertex2f(pt->x, pt->y); - } - glEnd(); - - setlinestyle(0); + /* don't draw stroke at all! */ } else { float oldpressure = 0.0f; /* draw stroke curve */ - setlinestyle(2); + if (G.f & G_DEBUG) setlinestyle(2); glBegin(GL_LINE_STRIP); for (i=0, pt=points; i < totpoints && pt; i++, pt++) { @@ -377,14 +387,14 @@ static void gp_draw_stroke_buffer (tGPspoint *points, int totpoints, short thick } glEnd(); - setlinestyle(0); + if (G.f & G_DEBUG) setlinestyle(0); } } /* ----- Existing Strokes Drawing (3D and Point) ------ */ /* draw a given stroke - just a single dot (only one point) */ -static void gp_draw_stroke_point (bGPDspoint *points, short sflag, int winx, int winy) +static void gp_draw_stroke_point (bGPDspoint *points, short thickness, short sflag, int winx, int winy) { /* draw point */ if (sflag & GP_STROKE_3DSPACE) { @@ -392,18 +402,38 @@ static void gp_draw_stroke_point (bGPDspoint *points, short sflag, int winx, int glVertex3f(points->x, points->y, points->z); glEnd(); } - else if (sflag & GP_STROKE_2DSPACE) { - glBegin(GL_POINTS); - glVertex2f(points->x, points->y); - glEnd(); - } else { - const float x= (points->x / 1000 * winx); - const float y= (points->y / 1000 * winy); + float co[2]; - glBegin(GL_POINTS); - glVertex2f(x, y); - glEnd(); + /* get coordinates of point */ + if (sflag & GP_STROKE_2DSPACE) { + co[0]= points->x; + co[1]= points->y; + } + else { + co[0]= (points->x / 1000 * winx); + co[1]= (points->y / 1000 * winy); + } + + /* if thickness is less than GP_DRAWTHICKNESS_SPECIAL, simple opengl point will do */ + if (thickness < GP_DRAWTHICKNESS_SPECIAL) { + glBegin(GL_POINTS); + glVertex2fv(co); + glEnd(); + } + else { + /* draw filled circle as is done in circf (but without the matrix push/pops which screwed things up) */ + GLUquadricObj *qobj = gluNewQuadric(); + + gluQuadricDrawStyle(qobj, GLU_FILL); + + /* need to translate drawing position, but must reset after too! */ + glTranslatef(co[0], co[1], 0.); + gluDisk( qobj, 0.0, thickness, 32, 1); + glTranslatef(-co[0], -co[1], 0.); + + gluDeleteQuadric(qobj); + } } } @@ -445,8 +475,8 @@ static void gp_draw_stroke_3d (bGPDspoint *points, int totpoints, short thicknes /* draw a given stroke in 2d */ static void gp_draw_stroke (bGPDspoint *points, int totpoints, short thickness, short dflag, short sflag, short debug, int winx, int winy) { - /* if thickness is less than 3, 'smooth' opengl lines look better */ - if ((thickness < 3) || (G.rt==0)) { + /* if thickness is less than GP_DRAWTHICKNESS_SPECIAL, 'smooth' opengl lines look better */ + if (thickness < GP_DRAWTHICKNESS_SPECIAL) { bGPDspoint *pt; int i; @@ -466,18 +496,18 @@ static void gp_draw_stroke (bGPDspoint *points, int totpoints, short thickness, } else { /* tesselation code: currently only enabled with rt != 0 */ bGPDspoint *pt1, *pt2; - float p0[2], p1[2], pm[2]; + float pm[2]; int i; glShadeModel(GL_FLAT); - glBegin(GL_QUAD_STRIP); + glBegin(GL_QUADS); for (i=0, pt1=points, pt2=points+1; i < (totpoints-1); i++, pt1++, pt2++) { float s0[2], s1[2]; /* segment 'center' points */ float t0[2], t1[2]; /* tesselated coordinates */ float m1[2], m2[2]; /* gradient and normal */ - float pthick, dist; /* thickness at segment point, and length of segment */ - float sminorang; /* minor angle between strokes */ + float mt[2], sc[2]; /* gradient for thickness, point for end-cap */ + float pthick; /* thickness at segment point */ /* get x and y coordinates from points */ if (sflag & GP_STROKE_2DSPACE) { @@ -494,91 +524,123 @@ static void gp_draw_stroke (bGPDspoint *points, int totpoints, short thickness, /* calculate gradient and normal - 'angle'=(ny/nx) */ m1[1]= s1[1] - s0[1]; m1[0]= s1[0] - s0[0]; - dist = Vec2Lenf(s0, s1); - m2[1]= -(m1[0]) / dist; - m2[0]= m1[1] / dist; + Normalize2(m1); + m2[1]= -m1[0]; + m2[0]= m1[1]; + + /* always use pressure from first point here */ + pthick= (pt1->pressure * thickness); - /* if the first segment, initialise the first segment using segment's normal */ - if (i == 0) { - pthick= (pt1->pressure * thickness); + /* if the first segment, start of segment is segment's normal */ + if (i == 0) { + /* draw start cap first + * - make points slightly closer to center (about halfway across) + */ + mt[0]= m2[0] * pthick * 0.5; + mt[1]= m2[1] * pthick * 0.5; + sc[0]= s0[0] - (m1[0] * pthick * 0.75); + sc[1]= s0[1] - (m1[1] * pthick * 0.75); + + t0[0]= sc[0] - mt[0]; + t0[1]= sc[1] - mt[1]; + t1[0]= sc[0] + mt[0]; + t1[1]= sc[1] + mt[1]; + + glVertex2fv(t0); + glVertex2fv(t1); - // TODO: also draw/do a round end-cap first + /* calculate points for start of segment */ + mt[0]= m2[0] * pthick; + mt[1]= m2[1] * pthick; - p0[0]= s0[0] - (pthick * m2[0]); - p0[1]= s0[1] - (pthick * m2[1]); - p1[0]= s1[0] + (pthick * m2[0]); - p1[1]= s1[1] + (pthick * m2[1]); + t0[0]= s0[0] - mt[0]; + t0[1]= s0[1] - mt[1]; + t1[0]= s0[0] + mt[0]; + t1[1]= s0[1] + mt[1]; - Vec2Copyf(pm, m1); + /* draw this line twice (first to finish off start cap, then for stroke) */ + glVertex2fv(t1); + glVertex2fv(t0); + glVertex2fv(t0); + glVertex2fv(t1); } - - /* if the minor angle between the current segment and the previous one is less than 90 degrees */ - if (i) - sminorang= NormalizedVecAngle2_2D(pm, m1); - else - sminorang= 0.0f; - - if ((IS_EQ(sminorang, 0)==0) && (abs(sminorang) < M_PI_2) ) - { - float closep[2]; + /* if not the first segment, use bisector of angle between segments */ + else { + float mb[2]; /* bisector normal */ + float athick, dfac; /* actual thickness, difference between thicknesses */ + + /* calculate gradient of bisector (as average of normals) */ + mb[0]= (pm[0] + m2[0]) / 2; + mb[1]= (pm[1] + m2[1]) / 2; + Normalize2(mb); - /* recalculate startpoint of segment, where the new start-line: - * - starts a new gl-quad-strip - * - uses the vert of old startpoint closer to our endpoint - * - distance between new startpoints = distance between old startpoints - * - new startpoints occur on same gradient as old segment does (has potential for some 'minor' overlap, but ok) + /* calculate gradient to apply + * - as basis, use just pthick * bisector gradient + * - if cross-section not as thick as it should be, add extra padding to fix it */ + mt[0]= mb[0] * pthick; + mt[1]= mb[1] * pthick; + athick= Vec2Length(mt); + dfac= pthick - (athick * 2); + if ( ((athick * 2) < pthick) && (IS_EQ(athick, pthick)==0) ) + { + mt[0] += (mb[0] * dfac); + mt[1] += (mb[1] * dfac); + } - /* find the closer vertex, and distance between startpoints */ - if (Vec2Lenf(p0, s1) > Vec2Lenf(p1, s1)) - Vec2Copyf(closep, p1); - else - Vec2Copyf(closep, p0); - - /* determine which side this closer vertex should be on */ - pthick= (pt1->pressure * thickness * 2); - if ( ((closep[0] - s0[0]) > 0) || ((closep[1] - s0[1]) > 0) ) { - /* assumes this is the 'second' point, (i.e. the 'plus' one), so the other is subtracting */ - p0[0]= closep[0] - (pthick * pm[0]); - p0[1]= closep[1] - (pthick * pm[1]); - p1[0]= closep[0]; - p1[1]= closep[1]; - } - else if ( ((closep[0] - s0[0]) < 0) || ((closep[1] - s0[1]) < 0) ) { - /* assumes this is the 'first' point, (i.e. the 'minus' one), so the other is adding */ - p0[0]= closep[0]; - p0[1]= closep[1]; - p1[0]= closep[0] + (pthick * pm[0]); - p1[1]= closep[1] + (pthick * pm[1]); - } + /* calculate points for start of segment */ + t0[0]= s0[0] - mt[0]; + t0[1]= s0[1] - mt[1]; + t1[0]= s0[0] + mt[0]; + t1[1]= s0[1] + mt[1]; - /* reset gl-states! */ - glEnd(); - glBegin(GL_QUAD_STRIP); + /* draw this line twice (once for end of current segment, and once for start of next) */ + glVertex2fv(t1); + glVertex2fv(t0); + glVertex2fv(t0); + glVertex2fv(t1); } - /* do the end of this segment */ - pthick= (pt2->pressure * thickness); - t0[0] = s1[0] - (pthick * m2[0]); - t0[1] = s1[1] - (pthick * m2[1]); - t1[0] = s1[0] + (pthick * m2[0]); - t1[1] = s1[1] + (pthick * m2[1]); - - /* draw this segment */ - glVertex2f(p0[0], p0[1]); - glVertex2f(p1[0], p1[1]); - glVertex2f(t0[0], t0[1]); - glVertex2f(t1[0], t1[1]); - - // TODO: draw end cap if last segment + /* if last segment, also draw end of segment (defined as segment's normal) */ if (i == totpoints-2) { - + /* for once, we use second point's pressure (otherwise it won't be drawn) */ + pthick= (pt2->pressure * thickness); + + /* calculate points for end of segment */ + mt[0]= m2[0] * pthick; + mt[1]= m2[1] * pthick; + + t0[0]= s1[0] - mt[0]; + t0[1]= s1[1] - mt[1]; + t1[0]= s1[0] + mt[0]; + t1[1]= s1[1] + mt[1]; + + /* draw this line twice (once for end of stroke, and once for endcap)*/ + glVertex2fv(t1); + glVertex2fv(t0); + glVertex2fv(t0); + glVertex2fv(t1); + + + /* draw end cap as last step + * - make points slightly closer to center (about halfway across) + */ + mt[0]= m2[0] * pthick * 0.5; + mt[1]= m2[1] * pthick * 0.5; + sc[0]= s1[0] + (m1[0] * pthick * 0.75); + sc[1]= s1[1] + (m1[1] * pthick * 0.75); + + t0[0]= sc[0] - mt[0]; + t0[1]= sc[1] - mt[1]; + t1[0]= sc[0] + mt[0]; + t1[1]= sc[1] + mt[1]; + + glVertex2fv(t1); + glVertex2fv(t0); } - /* store current points for next segment to use */ - Vec2Copyf(p0, t0); - Vec2Copyf(p1, t1); - Vec2Copyf(pm, m1); + /* store stroke's 'natural' normal for next stroke to use */ + Vec2Copyf(pm, m2); } glEnd(); @@ -626,12 +688,16 @@ static void gp_draw_strokes (bGPDframe *gpf, int winx, int winy, int dflag, shor continue; if (!(dflag & GP_DRAWDATA_ONLYV2D) && (gps->flag & GP_STROKE_2DSPACE)) continue; + if ((dflag & GP_DRAWDATA_ONLYI2D) && !(gps->flag & GP_STROKE_2DIMAGE)) + continue; + if (!(dflag & GP_DRAWDATA_ONLYI2D) && (gps->flag & GP_STROKE_2DIMAGE)) + continue; if ((gps->points == 0) || (gps->totpoints < 1)) continue; /* check which stroke-drawer to use */ if (gps->totpoints == 1) - gp_draw_stroke_point(gps->points, gps->flag, winx, winy); + gp_draw_stroke_point(gps->points, lthick, gps->flag, winx, winy); else if (dflag & GP_DRAWDATA_ONLY3D) gp_draw_stroke_3d(gps->points, gps->totpoints, lthick, dflag, gps->flag, debug, winx, winy); else if (gps->totpoints > 1) @@ -796,6 +862,22 @@ static void gp_draw_data (bGPdata *gpd, int winx, int winy, int dflag) /* ----- Grease Pencil Sketches Drawing API ------ */ +/* draw grease-pencil sketches to specified 2d-view that uses ibuf corrections */ +void draw_gpencil_2dimage (ScrArea *sa, ImBuf *ibuf) +{ + bGPdata *gpd; + int dflag = 0; + + /* check that we have grease-pencil stuff to draw */ + if (ELEM(NULL, sa, ibuf)) return; + gpd= gpencil_data_getactive(sa); + if (gpd == NULL) return; + + /* draw it! */ + dflag = (GP_DRAWDATA_ONLYI2D|GP_DRAWDATA_NOSTATUS); + gp_draw_data(gpd, sa->winx, sa->winy, dflag); +} + /* draw grease-pencil sketches to specified 2d-view assuming that matrices are already set correctly * Note: this gets called twice - first time with onlyv2d=1 to draw 'canvas' strokes, second time with onlyv2d=0 for screen-aligned strokes */ diff --git a/source/blender/src/drawipo.c b/source/blender/src/drawipo.c index 0e7476bbe82..9b5be04eac1 100644 --- a/source/blender/src/drawipo.c +++ b/source/blender/src/drawipo.c @@ -442,7 +442,7 @@ int in_ipo_buttons(void) else return 1; } -static View2D *spacelink_get_view2d(SpaceLink *sl) +View2D *spacelink_get_view2d(SpaceLink *sl) { if(sl->spacetype==SPACE_IPO) return &((SpaceIpo *)sl)->v2d; @@ -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/drawmesh.c b/source/blender/src/drawmesh.c index dd512595ebc..09f74c01c71 100644 --- a/source/blender/src/drawmesh.c +++ b/source/blender/src/drawmesh.c @@ -664,7 +664,7 @@ static int draw_tfaces3D__setHiddenOpts(void *userData, int index) { struct { Mesh *me; EdgeHash *eh; } *data = userData; MEdge *med = &data->me->medge[index]; - unsigned long flags = (long) BLI_edgehash_lookup(data->eh, med->v1, med->v2); + uintptr_t flags = (intptr_t) BLI_edgehash_lookup(data->eh, med->v1, med->v2); if((G.f & G_DRAWSEAMS) && (med->flag&ME_SEAM)) { return 0; @@ -682,7 +682,7 @@ static int draw_tfaces3D__setSeamOpts(void *userData, int index) { struct { Mesh *me; EdgeHash *eh; } *data = userData; MEdge *med = &data->me->medge[index]; - unsigned long flags = (long) BLI_edgehash_lookup(data->eh, med->v1, med->v2); + uintptr_t flags = (intptr_t) BLI_edgehash_lookup(data->eh, med->v1, med->v2); if (med->flag&ME_SEAM) { if (G.f&G_HIDDENEDGES) { @@ -698,7 +698,7 @@ static int draw_tfaces3D__setSelectOpts(void *userData, int index) { struct { Mesh *me; EdgeHash *eh; } *data = userData; MEdge *med = &data->me->medge[index]; - unsigned long flags = (long) BLI_edgehash_lookup(data->eh, med->v1, med->v2); + uintptr_t flags = (intptr_t) BLI_edgehash_lookup(data->eh, med->v1, med->v2); return flags & eEdge_Select; } @@ -706,7 +706,7 @@ static int draw_tfaces3D__setActiveOpts(void *userData, int index) { struct { Mesh *me; EdgeHash *eh; } *data = userData; MEdge *med = &data->me->medge[index]; - unsigned long flags = (long) BLI_edgehash_lookup(data->eh, med->v1, med->v2); + uintptr_t flags = (intptr_t) BLI_edgehash_lookup(data->eh, med->v1, med->v2); if (flags & eEdge_Select) { return 1; diff --git a/source/blender/src/drawobject.c b/source/blender/src/drawobject.c index 1a469e8b366..213f49528f0 100644 --- a/source/blender/src/drawobject.c +++ b/source/blender/src/drawobject.c @@ -5315,7 +5315,7 @@ void draw_object_ext(Base *base) static void bbs_mesh_verts__mapFunc(void *userData, int index, float *co, float *no_f, short *no_s) { - int offset = (long) userData; + int offset = (intptr_t) userData; EditVert *eve = EM_get_vert_for_index(index); if (eve->h==0) { @@ -5327,7 +5327,7 @@ static int bbs_mesh_verts(DerivedMesh *dm, int offset) { glPointSize( BIF_GetThemeValuef(TH_VERTEX_SIZE) ); bglBegin(GL_POINTS); - dm->foreachMappedVert(dm, bbs_mesh_verts__mapFunc, (void*)(long) offset); + dm->foreachMappedVert(dm, bbs_mesh_verts__mapFunc, (void*)(intptr_t) offset); bglEnd(); glPointSize(1.0); @@ -5336,7 +5336,7 @@ static int bbs_mesh_verts(DerivedMesh *dm, int offset) static int bbs_mesh_wire__setDrawOptions(void *userData, int index) { - int offset = (long) userData; + int offset = (intptr_t) userData; EditEdge *eed = EM_get_edge_for_index(index); if (eed->h==0) { @@ -5348,7 +5348,7 @@ static int bbs_mesh_wire__setDrawOptions(void *userData, int index) } static int bbs_mesh_wire(DerivedMesh *dm, int offset) { - dm->drawMappedEdges(dm, bbs_mesh_wire__setDrawOptions, (void*)(long) offset); + dm->drawMappedEdges(dm, bbs_mesh_wire__setDrawOptions, (void*)(intptr_t) offset); return offset + G.totedge; } @@ -5382,7 +5382,7 @@ static int bbs_mesh_solid_EM(DerivedMesh *dm, int facecol) cpack(0); if (facecol) { - dm->drawMappedFaces(dm, bbs_mesh_solid__setSolidDrawOptions, (void*)(long) 1, 0); + dm->drawMappedFaces(dm, bbs_mesh_solid__setSolidDrawOptions, (void*)(intptr_t) 1, 0); if( CHECK_OB_DRAWFACEDOT(G.scene, G.vd, G.obedit->dt) ) { glPointSize(BIF_GetThemeValuef(TH_FACEDOT_SIZE)); @@ -5415,7 +5415,7 @@ static int bbs_mesh_wire__setDrawOpts(void *userData, int index) { struct { Mesh *me; EdgeHash *eh; int offset; } *data = userData; MEdge *med = data->me->medge + index; - unsigned long flags = (long)BLI_edgehash_lookup(data->eh, med->v1, med->v2); + uintptr_t flags = (intptr_t)BLI_edgehash_lookup(data->eh, med->v1, med->v2); if (flags & 1) { set_framebuffer_index_color(data->offset+index); diff --git a/source/blender/src/editarmature.c b/source/blender/src/editarmature.c index 35986fcff4a..5e50c8117cc 100644 --- a/source/blender/src/editarmature.c +++ b/source/blender/src/editarmature.c @@ -439,6 +439,109 @@ void docenter_armature (Object *ob, int centermode) } } +/* helper for apply_armature_pose2bones - fixes parenting of objects that are bone-parented to armature */ +static void applyarmature_fix_boneparents (Object *armob) +{ + Object *ob; + + /* go through all objects in database */ + for (ob= G.main->object.first; ob; ob= ob->id.next) { + /* if parent is bone in this armature, apply corrections */ + if ((ob->parent == armob) && (ob->partype == PARBONE)) { + /* apply current transform from parent (not yet destroyed), + * then calculate new parent inverse matrix + */ + apply_obmat(ob); + + what_does_parent(ob); + Mat4Invert(ob->parentinv, workob.obmat); + } + } +} + +/* set the current pose as the restpose */ +void apply_armature_pose2bones(void) +{ + Object *ob; + bArmature *arm; + bPose *pose; + bPoseChannel *pchan; + EditBone *curbone; + + /* don't check if editmode (should be done by caller) */ + ob= OBACT; + if (ob->type!=OB_ARMATURE) return; + if (object_data_is_libdata(ob)) { + error_libdata(); + return; + } + arm= get_armature(ob); + + /* helpful warnings... */ + // TODO: add warnings to be careful about actions, applying deforms first, etc. + + /* Get editbones of active armature to alter */ + if (G.edbo.first) BLI_freelistN(&G.edbo); + make_boneList(&G.edbo, &arm->bonebase, NULL); + + /* get pose of active object and move it out of posemode */ + pose= ob->pose; + + for (pchan=pose->chanbase.first; pchan; pchan=pchan->next) { + curbone= editbone_name_exists(&G.edbo, pchan->name); + + /* simply copy the head/tail values from pchan over to curbone */ + VECCOPY(curbone->head, pchan->pose_head); + VECCOPY(curbone->tail, pchan->pose_tail); + + /* fix roll: + * 1. find auto-calculated roll value for this bone now + * 2. remove this from the 'visual' y-rotation + */ + { + float premat[3][3], imat[3][3],pmat[3][3], tmat[3][3]; + float delta[3], eul[3]; + + /* obtain new auto y-rotation */ + VecSubf(delta, curbone->tail, curbone->head); + vec_roll_to_mat3(delta, 0.0, premat); + Mat3Inv(imat, premat); + + /* get pchan 'visual' matrix */ + Mat3CpyMat4(pmat, pchan->pose_mat); + + /* remove auto from visual and get euler rotation */ + Mat3MulMat3(tmat, imat, pmat); + Mat3ToEul(tmat, eul); + + /* just use this euler-y as new roll value */ + curbone->roll= eul[1]; + } + + /* clear transform values for pchan */ + pchan->loc[0]= pchan->loc[1]= pchan->loc[2]= 0; + pchan->quat[1]= pchan->quat[2]= pchan->quat[3]= 0; + pchan->quat[0]= pchan->size[0]= pchan->size[1]= pchan->size[2]= 1; + + /* set anim lock */ + curbone->flag |= BONE_UNKEYED; + } + + /* convert editbones back to bones */ + editbones_to_armature(&G.edbo, ob); + if (G.edbo.first) BLI_freelistN(&G.edbo); + + /* flush positions of posebones */ + where_is_pose(ob); + + /* fix parenting of objects which are bone-parented */ + applyarmature_fix_boneparents(ob); + + BIF_undo_push("Apply new restpose"); + allqueue(REDRAWVIEW3D, 0); +} + + /* Helper function for armature joining - link fixing */ static void joined_armature_fix_links(Object *tarArm, Object *srcArm, bPoseChannel *pchan, EditBone *curbone) { 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 41044ad13d7..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"}; +"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/editkey.c b/source/blender/src/editkey.c index 1f24fb07667..ce798064632 100644 --- a/source/blender/src/editkey.c +++ b/source/blender/src/editkey.c @@ -84,6 +84,8 @@ #include "blendef.h" #include "mydevice.h" +#include "BLO_sys_types.h" // for intptr_t support + extern ListBase editNurb; /* in editcurve.c */ /* temporary storage for slider values */ @@ -162,7 +164,7 @@ static void rvk_slider_func(void *voidob, void *voidkeynum) IpoCurve *icu=NULL; BezTriple *bezt=NULL; float cfra, rvkval; - int keynum = (long) voidkeynum; + int keynum = (intptr_t) voidkeynum; cfra = frame_to_float(CFRA); @@ -275,7 +277,7 @@ void make_rvk_slider(uiBlock *block, Object *ob, int keynum, x, y , w, h, meshslidervals+keynum, min, max, 10, 2, tip); - uiButSetFunc(but, rvk_slider_func, ob, (void *)(long)keynum); + uiButSetFunc(but, rvk_slider_func, ob, (void *)(intptr_t)keynum); // no hilite, the winmatrix is not correct later on... uiButSetFlag(but, UI_NO_HILITE); diff --git a/source/blender/src/editmesh_mods.c b/source/blender/src/editmesh_mods.c index 6dfbd67720b..c162c904776 100644 --- a/source/blender/src/editmesh_mods.c +++ b/source/blender/src/editmesh_mods.c @@ -109,6 +109,7 @@ editmesh_mods.c, UI level access, no geometry changes #include "editmesh.h" +#include "BLO_sys_types.h" // for intptr_t support /* ****************************** MIRROR **************** */ @@ -2937,7 +2938,7 @@ void select_sharp_edges(void) EditFace *efa; EditFace **efa1; EditFace **efa2; - long edgecount = 0, i; + intptr_t edgecount = 0, i; static short sharpness = 135; float fsharpness; @@ -3041,7 +3042,7 @@ void select_linked_flat_faces(void) EditFace *efa; EditFace **efa1; EditFace **efa2; - long edgecount = 0, i, faceselcount=0, faceselcountold=0; + intptr_t edgecount = 0, i, faceselcount=0, faceselcountold=0; static short sharpness = 135; float fsharpness; diff --git a/source/blender/src/editmesh_tools.c b/source/blender/src/editmesh_tools.c index f9bb14a08c6..2b25253dc95 100644 --- a/source/blender/src/editmesh_tools.c +++ b/source/blender/src/editmesh_tools.c @@ -110,6 +110,8 @@ editmesh_tool.c: UI called tools for editmesh, geometry changes here, otherwise #include "PIL_time.h" +#include "BLO_sys_types.h" // for intptr_t support + /* local prototypes ---------------*/ void bevel_menu(void); static void free_tagged_edges_faces(EditEdge *eed, EditFace *efa); @@ -132,7 +134,7 @@ static int vergxco(const void *v1, const void *v2) } struct facesort { - unsigned long x; + uintptr_t x; struct EditFace *efa; }; @@ -433,8 +435,8 @@ int removedoublesflag(short flag, short automerge, float limit) /* return amoun efa= em->faces.first; while(efa) { if(efa->f1 & 1) { - if(efa->v4) vsb->x= (unsigned long) MIN4( (unsigned long)efa->v1, (unsigned long)efa->v2, (unsigned long)efa->v3, (unsigned long)efa->v4); - else vsb->x= (unsigned long) MIN3( (unsigned long)efa->v1, (unsigned long)efa->v2, (unsigned long)efa->v3); + if(efa->v4) vsb->x= (uintptr_t) MIN4( (uintptr_t)efa->v1, (uintptr_t)efa->v2, (uintptr_t)efa->v3, (uintptr_t)efa->v4); + else vsb->x= (uintptr_t) MIN3( (uintptr_t)efa->v1, (uintptr_t)efa->v2, (uintptr_t)efa->v3); vsb->efa= efa; vsb++; @@ -4665,6 +4667,7 @@ int EdgeLoopDelete(void) { int EdgeSlide(short immediate, float imperc) { + NumInput num; EditMesh *em = G.editMesh; EditFace *efa; EditEdge *eed,*first=NULL,*last=NULL, *temp = NULL; @@ -4681,6 +4684,8 @@ int EdgeSlide(short immediate, float imperc) char str[128]; float labda = 0.0f; + initNumInput(&num); + view3d_get_object_project_mat(curarea, G.obedit, projectMat, viewMat); mvalo[0] = -1; mvalo[1] = -1; @@ -4992,17 +4997,84 @@ int EdgeSlide(short immediate, float imperc) float v2[2], v3[2]; EditVert *centerVert, *upVert, *downVert; - - getmouseco_areawin(mval); if (!immediate && (mval[0] == mvalo[0] && mval[1] == mvalo[1])) { PIL_sleep_ms(10); } else { + char *p = str;; mvalo[0] = mval[0]; mvalo[1] = mval[1]; + + tempsv = BLI_ghash_lookup(vertgh,nearest); + + centerVert = editedge_getSharedVert(tempsv->up, tempsv->down); + upVert = editedge_getOtherVert(tempsv->up, centerVert); + downVert = editedge_getOtherVert(tempsv->down, centerVert); + + view3d_project_float(curarea, upVert->co, v2, projectMat); + view3d_project_float(curarea, downVert->co, v3, projectMat); + + /* Determine the % on which the loop should be cut */ + + rc[0]= v3[0]-v2[0]; + rc[1]= v3[1]-v2[1]; + len= rc[0]*rc[0]+ rc[1]*rc[1]; + if (len==0) {len = 0.0001;} + + if ((G.qual & LR_SHIFTKEY)==0) { + wasshift = 0; + labda= ( rc[0]*((mval[0]-v2[0])) + rc[1]*((mval[1]-v2[1])) )/len; + } + else { + if (wasshift==0) { + wasshift = 1; + shiftlabda = labda; + } + labda= ( rc[0]*((mval[0]-v2[0])) + rc[1]*((mval[1]-v2[1])) )/len / 10.0 + shiftlabda; + } + + + if(labda<=0.0) labda=0.0; + else if(labda>=1.0)labda=1.0; + + perc=((1-labda)*2)-1; + + if(G.qual == 0) { + perc *= 100; + perc = floor(perc); + perc /= 100; + } else if (G.qual == LR_CTRLKEY) { + perc *= 10; + perc = floor(perc); + perc /= 10; + } + + if(prop == 0) { + len = VecLenf(upVert->co,downVert->co)*((perc+1)/2); + if(flip == 1) { + len = VecLenf(upVert->co,downVert->co) - len; + } + } + + if (hasNumInput(&num)) + { + applyNumInput(&num, &perc); + + if (prop) + { + perc = MIN2(perc, 1); + perc = MAX2(perc, -1); + } + else + { + len = MIN2(perc, VecLenf(upVert->co,downVert->co)); + len = MAX2(len, 0); + } + } + //Adjust Edgeloop if(immediate) { perc = imperc; @@ -5041,13 +5113,7 @@ int EdgeSlide(short immediate, float imperc) } - tempsv = BLI_ghash_lookup(vertgh,nearest); - - centerVert = editedge_getSharedVert(tempsv->up, tempsv->down); - upVert = editedge_getOtherVert(tempsv->up, centerVert); - downVert = editedge_getOtherVert(tempsv->down, centerVert); // Highlight the Control Edges - scrarea_do_windraw(curarea); persp(PERSP_VIEW); glPushMatrix(); @@ -5075,55 +5141,36 @@ int EdgeSlide(short immediate, float imperc) glPopMatrix(); - view3d_project_float(curarea, upVert->co, v2, projectMat); - view3d_project_float(curarea, downVert->co, v3, projectMat); - - /* Determine the % on which the loop should be cut */ - - rc[0]= v3[0]-v2[0]; - rc[1]= v3[1]-v2[1]; - len= rc[0]*rc[0]+ rc[1]*rc[1]; - if (len==0) {len = 0.0001;} - - if ((G.qual & LR_SHIFTKEY)==0) { - wasshift = 0; - labda= ( rc[0]*((mval[0]-v2[0])) + rc[1]*((mval[1]-v2[1])) )/len; + if(prop) { + p += sprintf(str, "(P)ercentage: "); + } else { + p += sprintf(str, "Non (P)rop Length: "); } - else { - if (wasshift==0) { - wasshift = 1; - shiftlabda = labda; - } - labda= ( rc[0]*((mval[0]-v2[0])) + rc[1]*((mval[1]-v2[1])) )/len / 10.0 + shiftlabda; + + if (hasNumInput(&num)) + { + char num_str[20]; + + outputNumInput(&num, num_str); + p += sprintf(p, "%s", num_str); + } + else + { + if (prop) + { + p += sprintf(p, "%f", perc); + } + else + { + p += sprintf(p, "%f", len); + } } - - if(labda<=0.0) labda=0.0; - else if(labda>=1.0)labda=1.0; - - perc=((1-labda)*2)-1; - if(G.qual == 0) { - perc *= 100; - perc = floor(perc); - perc /= 100; - } else if (G.qual == LR_CTRLKEY) { - perc *= 10; - perc = floor(perc); - perc /= 10; - } - if(prop) { - sprintf(str, "(P)ercentage: %f", perc); - } else { - len = VecLenf(upVert->co,downVert->co)*((perc+1)/2); - if(flip == 1) { - len = VecLenf(upVert->co,downVert->co) - len; - } - sprintf(str, "Non (P)rop Length: %f, Press (F) to flip control side", len); + if (prop == 0) { + p += sprintf(p, ", Press (F) to flip control side"); } - - headerprint(str); screen_swapbuffers(); } @@ -5146,7 +5193,14 @@ int EdgeSlide(short immediate, float imperc) perc = 0; immediate = 1; } else if(event==PKEY) { - (prop == 1) ? (prop = 0):(prop = 1); + initNumInput(&num); /* reset num input */ + if (prop) { + prop = 0; + num.flag |= NUM_NO_NEGATIVE; + } + else { + prop = 1; + } mvalo[0] = -1; } else if(event==FKEY) { (flip == 1) ? (flip = 0):(flip = 1); @@ -5184,7 +5238,13 @@ int EdgeSlide(short immediate, float imperc) look = look->next; } } + + if (handleNumInput(&num, event)) + { + mvalo[0] = -1; /* NEED A BETTER WAY TO TRIGGER REDRAW */ + } } + } } else { draw = 0; diff --git a/source/blender/src/editnode.c b/source/blender/src/editnode.c index 98f4f1bb46f..eba6c5b4488 100644 --- a/source/blender/src/editnode.c +++ b/source/blender/src/editnode.c @@ -2110,6 +2110,7 @@ static void node_border_link_delete(SpaceNode *snode) mval[1]= rect.ymax; areamouseco_to_ipoco(&snode->v2d, mval, &rectf.xmax, &rectf.ymax); + glLoadIdentity(); myortho2(rectf.xmin, rectf.xmax, rectf.ymin, rectf.ymax); glSelectBuffer(256, buffer); diff --git a/source/blender/src/editobject.c b/source/blender/src/editobject.c index fee967bcd9a..2094074e3f3 100644 --- a/source/blender/src/editobject.c +++ b/source/blender/src/editobject.c @@ -172,6 +172,7 @@ #include "BDR_drawobject.h" #include "BDR_editcurve.h" #include "BDR_unwrapper.h" +#include "BDR_gpencil.h" #include <time.h> #include "mydevice.h" @@ -2827,7 +2828,7 @@ void convertmenu(void) if(G.scene->id.lib) return; obact= OBACT; - if(obact==0) return; + if (obact == NULL) return; if(!obact->flag & SELECT) return; if(G.obedit) return; @@ -4130,15 +4131,26 @@ void apply_object( void ) } allqueue(REDRAWVIEW3D, 0); - } else { + } + else { + ob= OBACT; - evt = pupmenu("Apply Object%t|Scale and Rotation to ObData|Visual Transform to Objects Loc/Scale/Rot"); + if ((ob->pose) && (ob->flag & OB_POSEMODE)) + evt = pupmenu("Apply Object%t|Current Pose as RestPose%x3"); + else + evt = pupmenu("Apply Object%t|Scale and Rotation to ObData%x1|Visual Transform to Objects Loc/Scale/Rot%x2"); if (evt==-1) return; - if (evt==1) { - apply_objects_locrot(); - } else if (evt==2) { - apply_objects_visual_tx(); + switch (evt) { + case 1: + apply_objects_locrot(); + break; + case 2: + apply_objects_visual_tx(); + break; + case 3: + apply_armature_pose2bones(); + break; } } } diff --git a/source/blender/src/editview.c b/source/blender/src/editview.c index a3fcad7885c..d2e59ae676d 100644 --- a/source/blender/src/editview.c +++ b/source/blender/src/editview.c @@ -1631,7 +1631,7 @@ void mouse_select(void) /* ------------------------------------------------------------------------- */ -static int edge_inside_circle(short centx, short centy, short rad, short x1, short y1, short x2, short y2) +int edge_inside_circle(short centx, short centy, short rad, short x1, short y1, short x2, short y2) { int radsq= rad*rad; float v1[2], v2[2], v3[2]; diff --git a/source/blender/src/gpencil.c b/source/blender/src/gpencil.c index eef21323a44..ed046929d2e 100644 --- a/source/blender/src/gpencil.c +++ b/source/blender/src/gpencil.c @@ -39,11 +39,16 @@ #include "BMF_Api.h" +#include "IMB_imbuf.h" +#include "IMB_imbuf_types.h" + #include "BLI_arithb.h" #include "BLI_blenlib.h" #include "DNA_listBase.h" +#include "DNA_curve_types.h" #include "DNA_gpencil_types.h" +#include "DNA_object_types.h" #include "DNA_scene_types.h" #include "DNA_screen_types.h" #include "DNA_space_types.h" @@ -54,6 +59,7 @@ #include "BKE_global.h" #include "BKE_utildefines.h" #include "BKE_blender.h" +#include "BKE_curve.h" #include "BIF_gl.h" #include "BIF_glutil.h" @@ -71,6 +77,8 @@ #include "BDR_gpencil.h" #include "BIF_drawgpencil.h" +#include "BDR_editobject.h" + #include "BSE_drawipo.h" #include "BSE_headerbuttons.h" #include "BSE_view.h" @@ -312,11 +320,17 @@ bGPdata *gpencil_data_getactive (ScrArea *sa) { SpaceSeq *sseq= sa->spacedata.first; - /* only applicable for "Image Preview" mode */ + /* only applicable for image modes */ if (sseq->mainb) return sseq->gpd; } break; + case SPACE_IMAGE: + { + SpaceImage *sima= sa->spacedata.first; + return sima->gpd; + } + break; } /* nothing found */ @@ -379,6 +393,17 @@ short gpencil_data_setactive (ScrArea *sa, bGPdata *gpd) } } break; + case SPACE_IMAGE: + { + SpaceImage *sima= sa->spacedata.first; + + if (sima->gpd) + free_gpencil_data(sima->gpd); + sima->gpd= gpd; + + return 1; + } + break; } /* failed to add */ @@ -589,7 +614,7 @@ void gpencil_layer_delactive (bGPdata *gpd) } /* ************************************************** */ -/* GREASE-PENCIL EDITING MODE - Tools */ +/* GREASE-PENCIL EDITING - Tools */ /* --------- Data Deletion ---------- */ @@ -658,6 +683,208 @@ void gpencil_delete_menu (void) gpencil_delete_operation(mode); } +/* --------- Data Conversion ---------- */ + +/* convert the coordinates from the given stroke point into 3d-coordinates */ +static void gp_strokepoint_convertcoords (bGPDstroke *gps, bGPDspoint *pt, float p3d[3]) +{ + if (gps->flag & GP_STROKE_3DSPACE) { + /* directly use 3d-coordinates */ + // FIXME: maybe we need to counterotate this for object rotation? + VecCopyf(p3d, &pt->x); + } + else { + short mval[2], mx, my; + float *fp= give_cursor(); + float dvec[3]; + + /* get screen coordinate */ + if (gps->flag & GP_STROKE_2DSPACE) { + View2D *v2d= spacelink_get_view2d(curarea->spacedata.first); + ipoco_to_areaco_noclip(v2d, &pt->x, mval); + } + else { + mval[0]= (pt->x / 1000 * curarea->winx); + mval[1]= (pt->y / 1000 * curarea->winy); + } + mx= mval[0]; + my= mval[1]; + + /* convert screen coordinate to 3d coordinates + * - method taken from editview.c - mouse_cursor() + */ + project_short_noclip(fp, mval); + window_to_3d(dvec, mval[0]-mx, mval[1]-my); + VecSubf(p3d, fp, dvec); + } +} + +/* convert stroke to 3d path */ +static void gp_layer_to_path (bGPDlayer *gpl, bGPDstroke *gps, Curve *cu) +{ + bGPDspoint *pt; + Nurb *nu; + BPoint *bp; + int i; + + /* create new 'nurb' within the curve */ + nu = (Nurb *)MEM_callocN(sizeof(Nurb), "gpstroke_to_path(nurb)"); + + nu->pntsu= gps->totpoints; + nu->pntsv= 1; + nu->orderu= gps->totpoints; + nu->flagu= 2; /* endpoint */ + nu->resolu= 32; + + nu->bp= (BPoint *)MEM_callocN(sizeof(BPoint)*gps->totpoints, "bpoints"); + + /* add points */ + for (i=0, pt=gps->points, bp=nu->bp; i < gps->totpoints; i++, pt++, bp++) { + float p3d[3]; + + /* get coordinates to add at */ + gp_strokepoint_convertcoords(gps, pt, p3d); + VecCopyf(bp->vec, p3d); + + /* set settings */ + bp->f1= SELECT; + bp->radius = bp->weight = pt->pressure * gpl->thickness; + } + + /* add nurb to curve */ + BLI_addtail(&cu->nurb, nu); +} + +/* convert stroke to 3d bezier */ +static void gp_layer_to_bezier (bGPDlayer *gpl, bGPDstroke *gps, Curve *cu) +{ + bGPDspoint *pt; + Nurb *nu; + BezTriple *bezt; + int i; + + /* create new 'nurb' within the curve */ + nu = (Nurb *)MEM_callocN(sizeof(Nurb), "gpstroke_to_bezier(nurb)"); + + nu->pntsu= gps->totpoints; + nu->resolu= 12; + nu->resolv= 12; + nu->type= CU_BEZIER; + nu->bezt = (BezTriple *)MEM_callocN(gps->totpoints*sizeof(BezTriple), "bezts"); + + /* add points */ + for (i=0, pt=gps->points, bezt=nu->bezt; i < gps->totpoints; i++, pt++, bezt++) { + float p3d[3]; + + /* get coordinates to add at */ + gp_strokepoint_convertcoords(gps, pt, p3d); + + /* TODO: maybe in future the handles shouldn't be in same place */ + VecCopyf(bezt->vec[0], p3d); + VecCopyf(bezt->vec[1], p3d); + VecCopyf(bezt->vec[2], p3d); + + /* set settings */ + bezt->h1= bezt->h2= HD_FREE; + bezt->f1= bezt->f2= bezt->f3= SELECT; + bezt->radius = bezt->weight = pt->pressure * gpl->thickness; + } + + /* must calculate handles or else we crash */ + calchandlesNurb(nu); + + /* add nurb to curve */ + BLI_addtail(&cu->nurb, nu); +} + +/* convert a given grease-pencil layer to a 3d-curve representation (using current view if appropriate) */ +static void gp_layer_to_curve (bGPdata *gpd, bGPDlayer *gpl, short mode) +{ + bGPDframe *gpf= gpencil_layer_getframe(gpl, CFRA, 0); + bGPDstroke *gps; + Object *ob; + Curve *cu; + + /* error checking */ + if (ELEM3(NULL, gpd, gpl, gpf)) + return; + + /* only convert if there are any strokes on this layer's frame to convert */ + if (gpf->strokes.first == NULL) + return; + + /* initialise the curve */ + cu= add_curve(gpl->info, 1); + cu->flag |= CU_3D; + + /* init the curve object (remove rotation and assign curve data to it) */ + add_object_draw(OB_CURVE); + ob= OBACT; + ob->loc[0]= ob->loc[1]= ob->loc[2]= 0; + ob->rot[0]= ob->rot[1]= ob->rot[2]= 0; + ob->data= cu; + + /* add points to curve */ + for (gps= gpf->strokes.first; gps; gps= gps->next) { + switch (mode) { + case 1: + gp_layer_to_path(gpl, gps, cu); + break; + case 2: + gp_layer_to_bezier(gpl, gps, cu); + break; + } + } +} + +/* convert grease-pencil strokes to another representation + * mode: 1 - Active layer to path + * 2 - Active layer to bezier + */ +void gpencil_convert_operation (short mode) +{ + bGPdata *gpd; + float *fp= give_cursor(); + + /* get datablock to work on */ + gpd= gpencil_data_getactive(NULL); + if (gpd == NULL) return; + + /* initialise 3d-cursor correction globals */ + initgrabz(fp[0], fp[1], fp[2]); + + /* handle selection modes */ + switch (mode) { + case 1: /* active layer only (to path) */ + case 2: /* active layer only (to bezier) */ + { + bGPDlayer *gpl= gpencil_layer_getactive(gpd); + gp_layer_to_curve(gpd, gpl, mode); + } + break; + } + + /* redraw and undo-push */ + BIF_undo_push("GPencil Convert"); + allqueue(REDRAWVIEW3D, 0); + allqueue(REDRAWOOPS, 0); +} + +/* display a menu for converting grease-pencil strokes */ +void gpencil_convert_menu (void) +{ + bGPdata *gpd= gpencil_data_getactive(NULL); + short mode; + + /* only show menu if it will be relevant */ + if (gpd == NULL) return; + + mode= pupmenu("Grease Pencil Convert %t|Active Layer To Path%x1|Active Layer to Bezier%x2"); + if (mode <= 0) return; + + gpencil_convert_operation(mode); +} + /* ************************************************** */ /* GREASE-PENCIL EDITING MODE - Painting */ @@ -679,6 +906,7 @@ void gpencil_delete_menu (void) typedef struct tGPsdata { ScrArea *sa; /* area where painting originated */ View2D *v2d; /* needed for GP_STROKE_2DSPACE */ + ImBuf *ibuf; /* needed for GP_STROKE_2DIMAGE */ bGPdata *gpd; /* gp-datablock layer comes from */ bGPDlayer *gpl; /* layer we're working on */ @@ -686,6 +914,10 @@ typedef struct tGPsdata { short status; /* current status of painting */ short paintmode; /* mode for painting */ + + short mval[2]; /* current mouse-position */ + short mvalo[2]; /* previous recorded mouse-position */ + short radius; /* radius of influence for eraser */ } tGPsdata; /* values for tGPsdata->status */ @@ -800,6 +1032,16 @@ static void gp_session_initpaint (tGPsdata *p) } } break; + case SPACE_IMAGE: + { + SpaceImage *sima= curarea->spacedata.first; + + /* set the current area */ + p->sa= curarea; + p->v2d= &sima->v2d; + //p->ibuf= BKE_image_get_ibuf(sima->image, &sima->iuser); + } + break; /* unsupported views */ default: { @@ -869,6 +1111,7 @@ static short gp_stroke_filtermval (tGPsdata *p, short mval[2], short pmval[2]) return 1; /* check if the distance since the last point is significant enough */ + // future optimisation: sqrt here may be too slow? else if (sqrt(dx*dx + dy*dy) > MIN_EUCLIDEAN_PX) return 1; @@ -884,7 +1127,7 @@ static void gp_stroke_convertcoords (tGPsdata *p, short mval[], float out[]) /* in 3d-space - pt->x/y/z are 3 side-by-side floats */ if (gpd->sbuffer_sflag & GP_STROKE_3DSPACE) { - short mx=mval[0], my=mval[1]; + const short mx=mval[0], my=mval[1]; float *fp= give_cursor(); float dvec[3]; @@ -904,6 +1147,26 @@ static void gp_stroke_convertcoords (tGPsdata *p, short mval[], float out[]) out[1]= y; } + /* 2d - on image 'canvas' (asume that p->v2d is set) */ + else if ( (gpd->sbuffer_sflag & GP_STROKE_2DIMAGE) && + (p->v2d) && (p->ibuf) ) + { + ImBuf *ibuf= p->ibuf; + float x, y; + + /* convert to 'canvas' coordinates, then adjust for view */ + areamouseco_to_ipoco(p->v2d, mval, &x, &y); + + if (ibuf) { + out[0]= x*ibuf->x; + out[1]= y*ibuf->y; + } + else { + out[0]= x; + out[1]= y; + } + } + /* 2d - relative to screen (viewport area) */ else { out[0] = (float)(mval[0]) / (float)(p->sa->winx) * 1000; @@ -927,8 +1190,6 @@ static short gp_stroke_addpoint (tGPsdata *p, short mval[2], float pressure) /* store settings */ pt->x= mval[0]; pt->y= mval[1]; - pt->xf= (float)mval[0]; - pt->yf= (float)mval[0]; pt->pressure= pressure; /* increment counters */ @@ -949,9 +1210,18 @@ static void gp_stroke_newfrombuffer (tGPsdata *p) bGPDspoint *pt; tGPspoint *ptc; int i, totelem; + + /* macro to test if only converting endpoints */ + #define GP_BUFFER2STROKE_ENDPOINTS ((gpd->flag & GP_DATA_EDITPAINT) && (G.qual & LR_CTRLKEY)) - /* get total number of points to allocate space for */ - totelem = gpd->sbuffer_size; + /* get total number of points to allocate space for: + * - in 'Draw Mode', holding the Ctrl-Modifier will only take endpoints + * - otherwise, do whole stroke + */ + if (GP_BUFFER2STROKE_ENDPOINTS) + totelem = (gpd->sbuffer_size >= 2) ? 2: gpd->sbuffer_size; + else + totelem = gpd->sbuffer_size; /* exit with error if no valid points from this stroke */ if (totelem == 0) { @@ -972,45 +1242,53 @@ static void gp_stroke_newfrombuffer (tGPsdata *p) gps->flag= gpd->sbuffer_sflag; /* copy points from the buffer to the stroke */ - for (i=0, ptc=gpd->sbuffer; i < gpd->sbuffer_size && ptc; i++, ptc++) { - /* convert screen-coordinates to appropriate coordinates (and store them) */ - gp_stroke_convertcoords(p, &ptc->x, &pt->x); - - /* copy pressure */ - pt->pressure= ptc->pressure; - - pt++; + if (GP_BUFFER2STROKE_ENDPOINTS) { + /* 'Draw Mode' + Ctrl-Modifier - only endpoints */ + { + /* first point */ + ptc= gpd->sbuffer; + + /* convert screen-coordinates to appropriate coordinates (and store them) */ + gp_stroke_convertcoords(p, &ptc->x, &pt->x); + + /* copy pressure */ + pt->pressure= ptc->pressure; + + pt++; + } + + if (totelem == 2) { + /* last point if applicable */ + ptc= ((tGPspoint *)gpd->sbuffer) + (gpd->sbuffer_size - 1); + + /* convert screen-coordinates to appropriate coordinates (and store them) */ + gp_stroke_convertcoords(p, &ptc->x, &pt->x); + + /* copy pressure */ + pt->pressure= ptc->pressure; + } + } + else { + /* convert all points (normal behaviour) */ + for (i=0, ptc=gpd->sbuffer; i < gpd->sbuffer_size && ptc; i++, ptc++) { + /* convert screen-coordinates to appropriate coordinates (and store them) */ + gp_stroke_convertcoords(p, &ptc->x, &pt->x); + + /* copy pressure */ + pt->pressure= ptc->pressure; + + pt++; + } } /* add stroke to frame */ BLI_addtail(&p->gpf->strokes, gps); + + /* undefine macro to test if only converting endpoints */ + #undef GP_BUFFER2STROKE_ENDPOINTS } /* --- 'Eraser' for 'Paint' Tool ------ */ -/* User should draw 'circles' around the parts of the sketches they wish to - * delete instead of drawing squiggles over existing lines. This should be - * easier to manage than if it was done otherwise. - */ - -/* convert gp-buffer stroke into mouse-coordinates array */ -static short (*gp_stroke_eraser_2mco (bGPdata *gpd))[2] -{ - tGPspoint *pt; - short (*mcoords)[2]; - int i; - - /* allocate memory for coordinates array */ - mcoords= MEM_mallocN(sizeof(*mcoords)*gpd->sbuffer_size,"gp_buf_mcords"); - - /* copy coordinates */ - for (pt=gpd->sbuffer, i=0; i < gpd->sbuffer_size; i++, pt++) { - mcoords[i][0]= pt->x; - mcoords[i][1]= pt->y; - } - - /* return */ - return mcoords; -} /* eraser tool - remove segment from stroke/split stroke (after lasso inside) */ static short gp_stroke_eraser_splitdel (bGPDframe *gpf, bGPDstroke *gps, int i) @@ -1080,8 +1358,19 @@ static short gp_stroke_eraser_splitdel (bGPDframe *gpf, bGPDstroke *gps, int i) } } +/* eraser tool - check if part of stroke occurs within last segment drawn by eraser */ +static short gp_stroke_eraser_strokeinside (short mval[], short mvalo[], short rad, short x0, short y0, short x1, short y1) +{ + /* simple within-radius check for now */ + if (edge_inside_circle(mval[0], mval[1], rad, x0, y0, x1, y1)) + return 1; + + /* not inside */ + return 0; +} + /* eraser tool - evaluation per stroke */ -static void gp_stroke_eraser_dostroke (tGPsdata *p, short mcoords[][2], short moves, rcti *rect, bGPDframe *gpf, bGPDstroke *gps) +static void gp_stroke_eraser_dostroke (tGPsdata *p, short mval[], short mvalo[], short rad, rcti *rect, bGPDframe *gpf, bGPDstroke *gps) { bGPDspoint *pt1, *pt2; short x0=0, y0=0, x1=0, y1=0; @@ -1097,10 +1386,9 @@ static void gp_stroke_eraser_dostroke (tGPsdata *p, short mcoords[][2], short mo else if (gps->totpoints == 1) { /* get coordinates */ if (gps->flag & GP_STROKE_3DSPACE) { - // FIXME: this may not be the correct correction project_short(&gps->points->x, xyval); x0= xyval[0]; - x1= xyval[1]; + y0= xyval[1]; } else if (gps->flag & GP_STROKE_2DSPACE) { ipoco_to_areaco_noclip(p->v2d, &gps->points->x, xyval); @@ -1115,7 +1403,7 @@ static void gp_stroke_eraser_dostroke (tGPsdata *p, short mcoords[][2], short mo /* do boundbox check first */ if (BLI_in_rcti(rect, x0, y0)) { /* only check if point is inside */ - if (lasso_inside(mcoords, moves, x0, y0)) { + if ( ((x0-mval[0])*(x0-mval[0]) + (y0-mval[1])*(y0-mval[1])) <= rad*rad ) { /* free stroke */ MEM_freeN(gps->points); BLI_freelinkN(&gpf->strokes, gps); @@ -1133,10 +1421,13 @@ static void gp_stroke_eraser_dostroke (tGPsdata *p, short mcoords[][2], short mo /* get coordinates */ if (gps->flag & GP_STROKE_3DSPACE) { - // FIXME: may not be correct correction - project_short(&gps->points->x, xyval); + project_short(&pt1->x, xyval); x0= xyval[0]; - x1= xyval[1]; + y0= xyval[1]; + + project_short(&pt2->x, xyval); + x1= xyval[0]; + y1= xyval[1]; } else if (gps->flag & GP_STROKE_2DSPACE) { ipoco_to_areaco_noclip(p->v2d, &pt1->x, xyval); @@ -1159,9 +1450,8 @@ static void gp_stroke_eraser_dostroke (tGPsdata *p, short mcoords[][2], short mo /* check if point segment of stroke had anything to do with * eraser region (either within stroke painted, or on its lines) * - this assumes that linewidth is irrelevant - * - handled using the lasso-select checking code */ - if (lasso_inside_edge(mcoords, moves, x0, y0, x1, x1)) { + if (gp_stroke_eraser_strokeinside(mval, mvalo, rad, x0, y0, x1, y1)) { /* if function returns true, break this loop (as no more point to check) */ if (gp_stroke_eraser_splitdel(gpf, gps, i)) break; @@ -1176,24 +1466,21 @@ static void gp_stroke_eraser_dostroke (tGPsdata *p, short mcoords[][2], short mo /* erase strokes which fall under the eraser strokes */ static void gp_stroke_doeraser (tGPsdata *p) { - bGPdata *gpd= p->gpd; bGPDframe *gpf= p->gpf; bGPDstroke *gps, *gpn; - short (*mcoords)[2]; rcti rect; - /* get buffer-stroke coordinates as shorts array, and then get bounding box */ - mcoords= gp_stroke_eraser_2mco(gpd); - lasso_select_boundbox(&rect, mcoords, gpd->sbuffer_size); + /* rect is rectangle of eraser */ + rect.xmin= p->mval[0] - p->radius; + rect.ymin= p->mval[1] - p->radius; + rect.xmax= p->mval[0] + p->radius; + rect.ymax= p->mval[1] + p->radius; /* loop over strokes, checking segments for intersections */ for (gps= gpf->strokes.first; gps; gps= gpn) { gpn= gps->next; - gp_stroke_eraser_dostroke(p, mcoords, gpd->sbuffer_size, &rect, gpf, gps); + gp_stroke_eraser_dostroke(p, p->mval, p->mvalo, p->radius, &rect, gpf, gps); } - - /* free mcoords array */ - MEM_freeN(mcoords); } /* ---------- 'Paint' Tool ------------ */ @@ -1247,6 +1534,12 @@ static void gp_paint_initstroke (tGPsdata *p, short paintmode) case SPACE_SEQ: { /* for now, this is not applicable here... */ + //p->gpd->sbuffer_sflag |= GP_STROKE_2DIMAGE; + } + break; + case SPACE_IMAGE: + { + p->gpd->sbuffer_sflag |= GP_STROKE_2DIMAGE; } break; } @@ -1257,11 +1550,7 @@ static void gp_paint_initstroke (tGPsdata *p, short paintmode) static void gp_paint_strokeend (tGPsdata *p) { /* check if doing eraser or not */ - if (p->gpd->sbuffer_sflag & GP_STROKE_ERASER) { - /* get rid of relevant sections of strokes */ - gp_stroke_doeraser(p); - } - else { + if ((p->gpd->sbuffer_sflag & GP_STROKE_ERASER) == 0) { /* transfer stroke to frame */ gp_stroke_newfrombuffer(p); } @@ -1295,7 +1584,6 @@ static void gp_paint_cleanup (tGPsdata *p) short gpencil_paint (short mousebutton, short paintmode) { tGPsdata p; - short prevmval[2], mval[2]; float opressure, pressure; short ok = GP_STROKEADD_NORMAL; @@ -1315,31 +1603,51 @@ short gpencil_paint (short mousebutton, short paintmode) setcursor_space(p.sa->spacetype, CURSOR_VPAINT); /* init drawing-device settings */ - getmouseco_areawin(mval); + getmouseco_areawin(p.mval); pressure = get_pressure(); - prevmval[0]= mval[0]; - prevmval[1]= mval[1]; + p.mvalo[0]= p.mval[0]; + p.mvalo[1]= p.mval[1]; opressure= pressure; + /* radius for eraser circle is thickness^2 */ + p.radius= p.gpl->thickness * p.gpl->thickness; + + /* start drawing eraser-circle (if applicable) */ + if (paintmode == GP_PAINTMODE_ERASER) + draw_sel_circle(p.mval, NULL, p.radius, p.radius, 0); // draws frontbuffer, but sets backbuf again + /* only allow painting of single 'dots' if: * - pressure is not excessive (as it can be on some windows tablets) * - draw-mode for active datablock is turned on + * - not erasing */ - if (!(pressure >= 0.99f) || (p.gpd->flag & GP_DATA_EDITPAINT)) { - gp_stroke_addpoint(&p, mval, pressure); + if (paintmode != GP_PAINTMODE_ERASER) { + if (!(pressure >= 0.99f) || (p.gpd->flag & GP_DATA_EDITPAINT)) { + gp_stroke_addpoint(&p, p.mval, pressure); + } } /* paint loop */ do { /* get current user input */ - getmouseco_areawin(mval); + getmouseco_areawin(p.mval); pressure = get_pressure(); /* only add current point to buffer if mouse moved (otherwise wait until it does) */ - if (gp_stroke_filtermval(&p, mval, prevmval)) { + if (paintmode == GP_PAINTMODE_ERASER) { + /* do 'live' erasing now */ + gp_stroke_doeraser(&p); + + draw_sel_circle(p.mval, p.mvalo, p.radius, p.radius, 0); + force_draw(0); + + p.mvalo[0]= p.mval[0]; + p.mvalo[1]= p.mval[1]; + } + else if (gp_stroke_filtermval(&p, p.mval, p.mvalo)) { /* try to add point */ - ok= gp_stroke_addpoint(&p, mval, pressure); + ok= gp_stroke_addpoint(&p, p.mval, pressure); /* handle errors while adding point */ if ((ok == GP_STROKEADD_FULL) || (ok == GP_STROKEADD_OVERFLOW)) { @@ -1347,8 +1655,8 @@ short gpencil_paint (short mousebutton, short paintmode) gp_paint_strokeend(&p); /* start a new stroke, starting from previous point */ - gp_stroke_addpoint(&p, prevmval, opressure); - ok= gp_stroke_addpoint(&p, mval, pressure); + gp_stroke_addpoint(&p, p.mvalo, opressure); + ok= gp_stroke_addpoint(&p, p.mval, pressure); } else if (ok == GP_STROKEADD_INVALID) { /* the painting operation cannot continue... */ @@ -1361,8 +1669,8 @@ short gpencil_paint (short mousebutton, short paintmode) } force_draw(0); - prevmval[0]= mval[0]; - prevmval[1]= mval[1]; + p.mvalo[0]= p.mval[0]; + p.mvalo[1]= p.mval[1]; opressure= pressure; } else @@ -1380,8 +1688,10 @@ short gpencil_paint (short mousebutton, short paintmode) setcursor_space(p.sa->spacetype, CURSOR_STD); /* check size of buffer before cleanup, to determine if anything happened here */ - if (paintmode == GP_PAINTMODE_ERASER) - ok= (p.gpd->sbuffer_size > 1); + if (paintmode == GP_PAINTMODE_ERASER) { + ok= 1; // fixme + draw_sel_circle(NULL, p.mvalo, 0, p.radius, 0); + } else ok= p.gpd->sbuffer_size; @@ -1408,7 +1718,8 @@ short gpencil_do_paint (ScrArea *sa, short mbut) /* currently, we will only 'paint' if: * 1. draw-mode on gpd is set (for accessibility reasons) - * (single 'dots' are only available via this method) + * a) single dots are only available by this method if a single click is made + * b) a straight line is drawn if ctrl-modifier is held (check is done when stroke is converted!) * 2. if shift-modifier is held + lmb -> 'quick paint' * * OR diff --git a/source/blender/src/header_info.c b/source/blender/src/header_info.c index a9280d9dd19..8b8fd9ef266 100644 --- a/source/blender/src/header_info.c +++ b/source/blender/src/header_info.c @@ -39,6 +39,8 @@ #include <config.h> #endif +#include "BLO_sys_types.h" // for intptr_t support + #include "DNA_group_types.h" #include "DNA_ID.h" #include "DNA_image_types.h" @@ -2106,7 +2108,7 @@ static void info_text(int x, int y) { Object *ob= OBACT; extern float hashvectf[]; - extern unsigned long mem_in_use, mmap_in_use; + extern uintptr_t mem_in_use, mmap_in_use; unsigned int swatch_color; float fac1, fac2, fac3; char infostr[300], memstr[64]; diff --git a/source/blender/src/header_script.c b/source/blender/src/header_script.c index 3c96e1692bf..53c4b9b5953 100644 --- a/source/blender/src/header_script.c +++ b/source/blender/src/header_script.c @@ -63,12 +63,14 @@ #include "blendef.h" #include "mydevice.h" +#include "BLO_sys_types.h" // for intptr_t support + /* ********************** SCRIPT ****************************** */ /* action executed after clicking in Scripts menu */ static void do_scripts_submenus(void *int_arg, int event) { - int menutype = (long)int_arg; + int menutype = (intptr_t)int_arg; BPY_menu_do_python (menutype, event); @@ -80,7 +82,7 @@ static uiBlock *script_scripts_submenus(void *int_menutype) uiBlock *block; short yco = 20, menuwidth = 120; BPyMenu *pym; - int i = 0, menutype = (long)int_menutype; + int i = 0, menutype = (intptr_t)int_menutype; if ((menutype < 0) || (menutype > PYMENU_SCRIPTS_MENU_TOTAL)) return NULL; @@ -132,7 +134,7 @@ static uiBlock *script_scriptsmenu(void *arg_unused) uiBlockSetButmFunc(block, do_script_scriptsmenu, NULL); for (i = 0; i < PYMENU_SCRIPTS_MENU_TOTAL; i++) { - uiDefIconTextBlockBut(block, script_scripts_submenus, (void *)(long)i, ICON_RIGHTARROW_THIN, BPyMenu_group_itoa(i), 0, yco-=20, menuwidth, 19, ""); + uiDefIconTextBlockBut(block, script_scripts_submenus, (void *)(intptr_t)i, ICON_RIGHTARROW_THIN, BPyMenu_group_itoa(i), 0, yco-=20, menuwidth, 19, ""); } uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, ""); diff --git a/source/blender/src/header_view3d.c b/source/blender/src/header_view3d.c index fcf4caf4522..e57a3480b52 100644 --- a/source/blender/src/header_view3d.c +++ b/source/blender/src/header_view3d.c @@ -4370,6 +4370,9 @@ static void do_view3d_pose_armaturemenu(void *arg, int event) case 18: pose_autoside_names(event-16); break; + case 19: /* assign pose as restpose */ + apply_armature_pose2bones(); + break; } allqueue(REDRAWVIEW3D, 0); @@ -4395,6 +4398,7 @@ static uiBlock *view3d_pose_armaturemenu(void *arg_unused) uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, ""); uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Relax Pose|W", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 15, ""); + uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Apply Pose as Restpose|Ctrl A", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 19, ""); uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, ""); diff --git a/source/blender/src/interface.c b/source/blender/src/interface.c index e7b5b176979..a2b2af05083 100644 --- a/source/blender/src/interface.c +++ b/source/blender/src/interface.c @@ -105,6 +105,8 @@ #include "blendef.h" #include "winlay.h" +#include "BLO_sys_types.h" // for intptr_t support + #define INSIDE_BLOCK 1 #define INSIDE_PANEL_HEADER 2 #define INSIDE_PANEL_SCALE 3 @@ -6039,7 +6041,7 @@ void autocomplete_end(AutoComplete *autocpl, char *autoname) /* autocomplete callback for ID buttons */ static void autocomplete_id(char *str, void *arg_v) { - int blocktype= (long)arg_v; + int blocktype= (intptr_t)arg_v; ListBase *listb= wich_libbase(G.main, blocktype); if(listb==NULL) return; @@ -6370,7 +6372,7 @@ uiBut *uiDefIDPoinBut(uiBlock *block, uiIDPoinFuncFP func, short blocktype, int ui_check_but(but); if(blocktype) - uiButSetCompleteFunc(but, autocomplete_id, (void *)(long)blocktype); + uiButSetCompleteFunc(but, autocomplete_id, (void *)(intptr_t)blocktype); return but; } diff --git a/source/blender/src/meshlaplacian.c b/source/blender/src/meshlaplacian.c index 60f569ecf0e..2de6367c9ad 100644 --- a/source/blender/src/meshlaplacian.c +++ b/source/blender/src/meshlaplacian.c @@ -63,6 +63,8 @@ #include "ONL_opennl.h" +#include "BLO_sys_types.h" // for intptr_t support + /************************** Laplacian System *****************************/ struct LaplacianSystem { @@ -126,14 +128,14 @@ static void laplacian_increase_edge_count(EdgeHash *edgehash, int v1, int v2) void **p = BLI_edgehash_lookup_p(edgehash, v1, v2); if(p) - *p = (void*)((long)*p + (long)1); + *p = (void*)((intptr_t)*p + (intptr_t)1); else - BLI_edgehash_insert(edgehash, v1, v2, (void*)(long)1); + BLI_edgehash_insert(edgehash, v1, v2, (void*)(intptr_t)1); } static int laplacian_edge_count(EdgeHash *edgehash, int v1, int v2) { - return (int)(long)BLI_edgehash_lookup(edgehash, v1, v2); + return (int)(intptr_t)BLI_edgehash_lookup(edgehash, v1, v2); } static float cotan_weight(float *v1, float *v2, float *v3) diff --git a/source/blender/src/meshtools.c b/source/blender/src/meshtools.c index 0f30aef04df..99833625baa 100644 --- a/source/blender/src/meshtools.c +++ b/source/blender/src/meshtools.c @@ -107,6 +107,8 @@ void sort_faces(void); #include "IMB_imbuf_types.h" #include "IMB_imbuf.h" +#include "BLO_sys_types.h" // for intptr_t support + /* from rendercode.c */ #define VECMUL(dest, f) dest[0]*= f; dest[1]*= f; dest[2]*= f @@ -592,7 +594,7 @@ void sort_faces(void) typedef struct MocNode { struct MocNode *next; - long index[MOC_NODE_RES]; + intptr_t index[MOC_NODE_RES]; } MocNode; static int mesh_octree_get_base_offs(float *co, float *offs, float *div) @@ -610,7 +612,7 @@ static int mesh_octree_get_base_offs(float *co, float *offs, float *div) return (vx*MOC_RES*MOC_RES) + vy*MOC_RES + vz; } -static void mesh_octree_add_node(MocNode **bt, long index) +static void mesh_octree_add_node(MocNode **bt, intptr_t index) { if(*bt==NULL) { *bt= MEM_callocN(sizeof(MocNode), "MocNode"); @@ -642,7 +644,7 @@ static void mesh_octree_free_node(MocNode **bt) /* temporal define, just to make nicer code below */ #define MOC_ADDNODE(vx, vy, vz) mesh_octree_add_node(basetable + ((vx)*MOC_RES*MOC_RES) + (vy)*MOC_RES + (vz), index) -static void mesh_octree_add_nodes(MocNode **basetable, float *co, float *offs, float *div, long index) +static void mesh_octree_add_nodes(MocNode **basetable, float *co, float *offs, float *div, intptr_t index) { float fx, fy, fz; int vx, vy, vz; @@ -690,7 +692,7 @@ static void mesh_octree_add_nodes(MocNode **basetable, float *co, float *offs, f } -static long mesh_octree_find_index(MocNode **bt, float (*orco)[3], MVert *mvert, float *co) +static intptr_t mesh_octree_find_index(MocNode **bt, float (*orco)[3], MVert *mvert, float *co) { float *vec; int a; @@ -734,7 +736,7 @@ static struct { /* mode is 's' start, or 'e' end, or 'u' use */ /* if end, ob can be NULL */ -long mesh_octree_table(Object *ob, float *co, char mode) +intptr_t mesh_octree_table(Object *ob, float *co, char mode) { MocNode **bt; @@ -805,7 +807,7 @@ long mesh_octree_table(Object *ob, float *co, char mode) EditVert *eve; for(eve= G.editMesh->verts.first; eve; eve= eve->next) { - mesh_octree_add_nodes(MeshOctree.table, eve->co, MeshOctree.offs, MeshOctree.div, (long)(eve)); + mesh_octree_add_nodes(MeshOctree.table, eve->co, MeshOctree.offs, MeshOctree.div, (intptr_t)(eve)); } } else { @@ -863,7 +865,7 @@ int mesh_get_x_mirror_vert(Object *ob, int index) EditVert *editmesh_get_x_mirror_vert(Object *ob, float *co) { float vec[3]; - long poinval; + intptr_t poinval; /* ignore nan verts */ if (isnan(co[0]) || !finite(co[0]) || diff --git a/source/blender/src/parametrizer.c b/source/blender/src/parametrizer.c index 096629b01ec..7aa27f99d77 100644 --- a/source/blender/src/parametrizer.c +++ b/source/blender/src/parametrizer.c @@ -22,6 +22,8 @@ #include <stdio.h> #include <string.h> +#include "BLO_sys_types.h" // for intptr_t support + #if defined(_WIN32) #define M_PI 3.14159265358979323846 #endif @@ -38,7 +40,7 @@ static int PHashSizes[] = { 4194319, 8388617, 16777259, 33554467, 67108879, 134217757, 268435459 }; -#define PHASH_hash(ph, item) (((unsigned long) (item))%((unsigned int) (ph)->cursize)) +#define PHASH_hash(ph, item) (((uintptr_t) (item))%((unsigned int) (ph)->cursize)) #define PHASH_edge(v1, v2) ((v1)^(v2)) static PHash *phash_new(PHashLink **list, int sizehint) diff --git a/source/blender/src/parametrizer.h b/source/blender/src/parametrizer.h index 80fab110d5f..c468b8d62c5 100644 --- a/source/blender/src/parametrizer.h +++ b/source/blender/src/parametrizer.h @@ -5,9 +5,11 @@ #ifdef __cplusplus extern "C" { #endif + +#include "BLO_sys_types.h" // for intptr_t support typedef void ParamHandle; /* handle to a set of charts */ -typedef long ParamKey; /* (hash) key for identifying verts and faces */ +typedef intptr_t ParamKey; /* (hash) key for identifying verts and faces */ typedef enum ParamBool { PARAM_TRUE = 1, PARAM_FALSE = 0 diff --git a/source/blender/src/parametrizer_intern.h b/source/blender/src/parametrizer_intern.h index f7a32816b33..bc38cb4bc0f 100644 --- a/source/blender/src/parametrizer_intern.h +++ b/source/blender/src/parametrizer_intern.h @@ -30,7 +30,7 @@ typedef enum PBool { /* Special Purpose Hash */ -typedef long PHashKey; +typedef intptr_t PHashKey; typedef struct PHashLink { struct PHashLink *next; diff --git a/source/blender/src/renderwin.c b/source/blender/src/renderwin.c index 6c150f3d30f..88f5f6efe15 100644 --- a/source/blender/src/renderwin.c +++ b/source/blender/src/renderwin.c @@ -50,6 +50,8 @@ #endif +#include "BLO_sys_types.h" // for intptr_t support + #include <limits.h> #include "BLI_blenlib.h" @@ -901,7 +903,7 @@ static void renderwin_progress_display_cb(RenderResult *rr, volatile rcti *rect) void make_renderinfo_string(RenderStats *rs, char *str) { extern char info_time_str[32]; // header_info.c - extern unsigned long mem_in_use, mmap_in_use; + extern uintptr_t mem_in_use, mmap_in_use; float megs_used_memory, mmap_used_memory; char *spos= str; 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 79fdb312309..81b0efeef0d 100644 --- a/source/blender/src/space.c +++ b/source/blender/src/space.c @@ -182,6 +182,8 @@ #include "SYS_System.h" /* for the user def menu ... should move elsewhere. */ +#include "BLO_sys_types.h" // for intptr_t support + /* maybe we need this defined somewhere else */ extern void StartKetsjiShell(ScrArea *area, char* startscenename, struct Main* maggie, struct SpaceIpo* sipo,int always_use_expand_framing); extern void StartKetsjiShellSimulation(ScrArea *area, char* startscenename, struct Main* maggie, struct SpaceIpo* sipo,int always_use_expand_framing);/*rcruiz*/ @@ -460,7 +462,7 @@ static LinkNode *save_and_reset_all_scene_cfra(void) Scene *sc; for (sc= G.main->scene.first; sc; sc= sc->id.next) { - BLI_linklist_prepend(&storelist, (void*) (long) sc->r.cfra); + BLI_linklist_prepend(&storelist, (void*) (intptr_t) sc->r.cfra); /* why is this reset to 1 ?*/ /* sc->r.cfra= 1;*/ @@ -478,7 +480,7 @@ static void restore_all_scene_cfra(LinkNode *storelist) { Scene *sc; for (sc= G.main->scene.first; sc; sc= sc->id.next) { - int stored_cfra= (long) sc_store->link; + int stored_cfra= (intptr_t) sc_store->link; sc->r.cfra= stored_cfra; set_scene_bg(sc); @@ -1904,6 +1906,8 @@ static void winqreadview3dspace(ScrArea *sa, void *spacedata, BWinEvent *evt) else copy_attr_menu(); } + else if(G.qual==(LR_ALTKEY|LR_SHIFTKEY)) + gpencil_convert_menu(); /* gpencil.c */ else if(G.qual==LR_ALTKEY) { if(ob && (ob->flag & OB_POSEMODE)) pose_clear_constraints(); /* poseobject.c */ @@ -1962,7 +1966,7 @@ static void winqreadview3dspace(ScrArea *sa, void *spacedata, BWinEvent *evt) G.vd->drawtype= pupval; doredraw= 1; } - } + } break; case EKEY: @@ -3490,6 +3494,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/toolbox.c b/source/blender/src/toolbox.c index cd71e7fd8e6..5b2120424f1 100644 --- a/source/blender/src/toolbox.c +++ b/source/blender/src/toolbox.c @@ -123,6 +123,8 @@ #include "BPY_extern.h" #include "BPY_menus.h" +#include "BLO_sys_types.h" // for intptr_t support + void asciitoraw(int ch, unsigned short *event, unsigned short *qual) { if( isupper(ch) ) { @@ -238,7 +240,7 @@ void error_libdata(void) int saveover(char *file) { - int len= strlen(file); + size_t len= strlen(file); if(len==0) return 0; @@ -1756,8 +1758,8 @@ static uiBlock *tb_makemenu(void *arg) static int tb_mainx= 1234, tb_mainy= 0; static void store_main(void *arg1, void *arg2) { - tb_mainx= (long)arg1; - tb_mainy= (long)arg2; + tb_mainx= (intptr_t)arg1; + tb_mainy= (intptr_t)arg2; } static void do_group_addmenu(void *arg, int event) @@ -2185,27 +2187,27 @@ void toolbox_n(void) but=uiDefBlockBut(block, tb_makemenu, menu1, str1, mval[0]-(1.5*dx)+tb_mainx,mval[1]+tb_mainy, dx, 19, ""); uiButSetFlag(but, UI_MAKE_TOP|UI_MAKE_RIGHT); - uiButSetFunc(but, store_main, (void *)(long)dx, (void *)(long)-5); + uiButSetFunc(but, store_main, (void *)(intptr_t)dx, (void *)(intptr_t)-5); but=uiDefBlockBut(block, tb_makemenu, menu2, str2, mval[0]-(0.5*dx)+tb_mainx,mval[1]+tb_mainy, dx, 19, ""); uiButSetFlag(but, UI_MAKE_TOP); - uiButSetFunc(but, store_main, (void *)(long)0, (void *)(long)-5); + uiButSetFunc(but, store_main, (void *)(intptr_t)0, (void *)(intptr_t)-5); but=uiDefBlockBut(block, tb_makemenu, menu3, str3, mval[0]+(0.5*dx)+tb_mainx,mval[1]+tb_mainy, dx, 19, ""); uiButSetFlag(but, UI_MAKE_TOP|UI_MAKE_LEFT); - uiButSetFunc(but, store_main, (void *)(long)-dx, (void *)(long)-5); + uiButSetFunc(but, store_main, (void *)(intptr_t)-dx, (void *)(intptr_t)-5); but=uiDefBlockBut(block, tb_makemenu, menu4, str4, mval[0]-(1.5*dx)+tb_mainx,mval[1]+tb_mainy-20, dx, 19, ""); uiButSetFlag(but, UI_MAKE_DOWN|UI_MAKE_RIGHT); - uiButSetFunc(but, store_main, (void *)(long)dx, (void *)(long)5); + uiButSetFunc(but, store_main, (void *)(intptr_t)dx, (void *)(intptr_t)5); but=uiDefBlockBut(block, tb_makemenu, menu5, str5, mval[0]-(0.5*dx)+tb_mainx,mval[1]+tb_mainy-20, dx, 19, ""); uiButSetFlag(but, UI_MAKE_DOWN); - uiButSetFunc(but, store_main, (void *)(long)0, (void *)(long)5); + uiButSetFunc(but, store_main, (void *)(intptr_t)0, (void *)(intptr_t)5); but=uiDefBlockBut(block, tb_makemenu, menu6, str6, mval[0]+(0.5*dx)+tb_mainx,mval[1]+tb_mainy-20, dx, 19, ""); uiButSetFlag(but, UI_MAKE_DOWN|UI_MAKE_LEFT); - uiButSetFunc(but, store_main, (void *)(long)-dx, (void *)(long)5); + uiButSetFunc(but, store_main, (void *)(intptr_t)-dx, (void *)(intptr_t)5); } else if (tot==5 || tot==7) { /* check if it fits, dubious */ if(mval[0]-0.25*dx+tb_mainx < 6) mval[0]= 6 + 0.25*dx -tb_mainx; @@ -2282,7 +2284,7 @@ void toolbox_generic( TBitem *generic_menu ) TBitem *menu; int dx=96, first=1, len; short event, mval[2]; - long ypos = -5; + intptr_t ypos = -5; tb_mainx= -32; tb_mainy= -5; diff --git a/source/blender/src/transform_conversions.c b/source/blender/src/transform_conversions.c index 9f2f58d0cdb..efb86b59ed1 100644 --- a/source/blender/src/transform_conversions.c +++ b/source/blender/src/transform_conversions.c @@ -144,6 +144,8 @@ extern ListBase editelems; #include "transform.h" +#include "BLO_sys_types.h" // for intptr_t support + /* local function prototype - for Object/Bone Constraints */ static short constraints_list_needinv(TransInfo *t, ListBase *list); /* local function prototype - for finding number of keyframes that are selected for editing */ @@ -1913,7 +1915,7 @@ static void set_crazyspace_quats(float *origcos, float *mappedcos, float *quats) EditVert *eve, *prev; EditFace *efa; float *v1, *v2, *v3, *v4, *co1, *co2, *co3, *co4; - long index= 0; + intptr_t index= 0; /* two abused locations in vertices */ for(eve= em->verts.first; eve; eve= eve->next, index++) { @@ -1925,13 +1927,13 @@ static void set_crazyspace_quats(float *origcos, float *mappedcos, float *quats) for(efa= em->faces.first; efa; efa= efa->next) { /* retrieve mapped coordinates */ - v1= mappedcos + 3*(long)(efa->v1->prev); - v2= mappedcos + 3*(long)(efa->v2->prev); - v3= mappedcos + 3*(long)(efa->v3->prev); + v1= mappedcos + 3*(intptr_t)(efa->v1->prev); + v2= mappedcos + 3*(intptr_t)(efa->v2->prev); + v3= mappedcos + 3*(intptr_t)(efa->v3->prev); - co1= (origcos)? origcos + 3*(long)(efa->v1->prev): efa->v1->co; - co2= (origcos)? origcos + 3*(long)(efa->v2->prev): efa->v2->co; - co3= (origcos)? origcos + 3*(long)(efa->v3->prev): efa->v3->co; + co1= (origcos)? origcos + 3*(intptr_t)(efa->v1->prev): efa->v1->co; + co2= (origcos)? origcos + 3*(intptr_t)(efa->v2->prev): efa->v2->co; + co3= (origcos)? origcos + 3*(intptr_t)(efa->v3->prev): efa->v3->co; if(efa->v2->tmp.p==NULL && efa->v2->f1) { set_crazy_vertex_quat(quats, co2, co3, co1, v2, v3, v1); @@ -1940,8 +1942,8 @@ static void set_crazyspace_quats(float *origcos, float *mappedcos, float *quats) } if(efa->v4) { - v4= mappedcos + 3*(long)(efa->v4->prev); - co4= (origcos)? origcos + 3*(long)(efa->v4->prev): efa->v4->co; + v4= mappedcos + 3*(intptr_t)(efa->v4->prev); + co4= (origcos)? origcos + 3*(intptr_t)(efa->v4->prev): efa->v4->co; if(efa->v1->tmp.p==NULL && efa->v1->f1) { set_crazy_vertex_quat(quats, co1, co2, co4, v1, v2, v4); diff --git a/source/blender/src/transform_generics.c b/source/blender/src/transform_generics.c index c332fd723eb..a1440b8cbce 100644 --- a/source/blender/src/transform_generics.c +++ b/source/blender/src/transform_generics.c @@ -32,6 +32,8 @@ #include "MEM_guardedalloc.h" +#include "BLO_sys_types.h" // for intptr_t support + #include "DNA_action_types.h" #include "DNA_armature_types.h" #include "DNA_constraint_types.h" @@ -581,39 +583,6 @@ void recalcData(TransInfo *t) reshadeall_displist(); } -void initTransModeFlags(TransInfo *t, int mode) -{ - t->mode = mode; - t->num.flag = 0; - - /* REMOVING RESTRICTIONS FLAGS */ - t->flag &= ~T_ALL_RESTRICTIONS; - - switch (mode) { - case TFM_RESIZE: - t->flag |= T_NULL_ONE; - t->num.flag |= NUM_NULL_ONE; - t->num.flag |= NUM_AFFECT_ALL; - if (!G.obedit) { - t->flag |= T_NO_ZERO; - t->num.flag |= NUM_NO_ZERO; - } - break; - case TFM_TOSPHERE: - t->num.flag |= NUM_NULL_ONE; - t->num.flag |= NUM_NO_NEGATIVE; - t->flag |= T_NO_CONSTRAINT; - break; - case TFM_SHEAR: - case TFM_CREASE: - case TFM_BONE_ENVELOPE: - case TFM_CURVE_SHRINKFATTEN: - case TFM_BONE_ROLL: - t->flag |= T_NO_CONSTRAINT; - break; - } -} - void drawLine(float *center, float *dir, char axis, short options) { extern void make_axis_color(char *col, char *col2, char axis); // drawview.c @@ -672,19 +641,10 @@ void initTrans (TransInfo *t) t->transform = NULL; t->handleEvent = NULL; - t->total = - t->num.idx = - t->num.idx_max = - t->num.ctrl[0] = - t->num.ctrl[1] = - t->num.ctrl[2] = 0; + t->total = 0; t->val = 0.0f; - t->num.val[0] = - t->num.val[1] = - t->num.val[2] = 0.0f; - t->vec[0] = t->vec[1] = t->vec[2] = 0.0f; @@ -706,7 +666,8 @@ void initTrans (TransInfo *t) t->around = V3D_CENTER; setTransformViewMatrices(t); - initNDofInput(&(t->ndof)); + initNumInput(&t->num); + initNDofInput(&t->ndof); } /* Here I would suggest only TransInfo related issues, like free data & reset vars. Not redraws */ diff --git a/source/blender/src/transform_numinput.c b/source/blender/src/transform_numinput.c index 9b811595a9a..89a76c097e0 100644 --- a/source/blender/src/transform_numinput.c +++ b/source/blender/src/transform_numinput.c @@ -41,6 +41,20 @@ /* ************************** NUMINPUT **************************** */ +void initNumInput(NumInput *n) +{ + n->flag = + n->idx = + n->idx_max = + n->ctrl[0] = + n->ctrl[1] = + n->ctrl[2] = 0; + + n->val[0] = + n->val[1] = + n->val[2] = 0.0f; +} + void outputNumInput(NumInput *n, char *str) { char cur; diff --git a/source/blender/src/usiblender.c b/source/blender/src/usiblender.c index 36d98245827..e757f634a45 100644 --- a/source/blender/src/usiblender.c +++ b/source/blender/src/usiblender.c @@ -479,7 +479,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/blender/yafray/intern/export_Plugin.cpp b/source/blender/yafray/intern/export_Plugin.cpp index 6ae4a31bf50..77d53c4ed96 100644 --- a/source/blender/yafray/intern/export_Plugin.cpp +++ b/source/blender/yafray/intern/export_Plugin.cpp @@ -74,7 +74,7 @@ extern "C" { extern char bprogname[]; } // add drive character if not in path string, using blender executable location as reference static void addDrive(string &path) { - int sp = path.find_first_of(":"); + size_t sp = path.find_first_of(":"); if (sp==-1) { string blpath = bprogname; sp = blpath.find_first_of(":"); 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/BlenderRoutines/KX_BlenderRenderTools.cpp b/source/gameengine/BlenderRoutines/KX_BlenderRenderTools.cpp index e4eff163d5b..dafc2599850 100644 --- a/source/gameengine/BlenderRoutines/KX_BlenderRenderTools.cpp +++ b/source/gameengine/BlenderRoutines/KX_BlenderRenderTools.cpp @@ -131,11 +131,11 @@ void KX_BlenderRenderTools::SetClientObject(void* obj) } } -bool KX_BlenderRenderTools::RayHit(KX_ClientObjectInfo* client, MT_Point3& hit_point, MT_Vector3& hit_normal, void * const data) +bool KX_BlenderRenderTools::RayHit(KX_ClientObjectInfo* client, KX_RayCast* result, void * const data) { double* const oglmatrix = (double* const) data; - MT_Point3 resultpoint(hit_point); - MT_Vector3 resultnormal(hit_normal); + MT_Point3 resultpoint(result->m_hitPoint); + MT_Vector3 resultnormal(result->m_hitNormal); MT_Vector3 left(oglmatrix[0],oglmatrix[1],oglmatrix[2]); MT_Vector3 dir = -(left.cross(resultnormal)).safe_normalized(); left = (dir.cross(resultnormal)).safe_normalized(); @@ -236,9 +236,8 @@ void KX_BlenderRenderTools::applyTransform(RAS_IRasterizer* rasty,double* oglmat if (parent) parent->Release(); - MT_Point3 resultpoint; - MT_Vector3 resultnormal; - if (!KX_RayCast::RayTest(physics_controller, physics_environment, frompoint, topoint, resultpoint, resultnormal, KX_RayCast::Callback<KX_BlenderRenderTools>(this, oglmatrix))) + KX_RayCast::Callback<KX_BlenderRenderTools> callback(this, physics_controller, oglmatrix); + if (!KX_RayCast::RayTest(physics_environment, frompoint, topoint, callback)) { // couldn't find something to cast the shadow on... glMultMatrixd(oglmatrix); diff --git a/source/gameengine/BlenderRoutines/KX_BlenderRenderTools.h b/source/gameengine/BlenderRoutines/KX_BlenderRenderTools.h index 8abce1b8c3e..8027136aa52 100644 --- a/source/gameengine/BlenderRoutines/KX_BlenderRenderTools.h +++ b/source/gameengine/BlenderRoutines/KX_BlenderRenderTools.h @@ -37,6 +37,7 @@ #include "RAS_IRenderTools.h" struct KX_ClientObjectInfo; +class KX_RayCast; /** BlenderRenderTools are a set of tools to apply 2D/3D graphics effects, which are not @@ -97,7 +98,8 @@ public: void* clientobject, void* tface); - bool RayHit(KX_ClientObjectInfo* client, MT_Point3& hit_point, MT_Vector3& hit_normal, void * const data); + bool RayHit(KX_ClientObjectInfo* client, class KX_RayCast* result, void * const data); + bool NeedRayCast(KX_ClientObjectInfo*) { return true; } virtual void MotionBlur(RAS_IRasterizer* rasterizer); diff --git a/source/gameengine/Converter/BL_BlenderDataConversion.cpp b/source/gameengine/Converter/BL_BlenderDataConversion.cpp index a6337403cd1..edc14dabc70 100644 --- a/source/gameengine/Converter/BL_BlenderDataConversion.cpp +++ b/source/gameengine/Converter/BL_BlenderDataConversion.cpp @@ -1946,10 +1946,22 @@ void BL_ConvertBlenderObjects(struct Main* maggie, //parentinversenode->SetLocalOrientation(parinvtrans.getBasis()); // Extract the rotation and the scaling from the basis - MT_Matrix3x3 inverseOrientation(parinvtrans.getRotation()); - parentinversenode->SetLocalOrientation(inverseOrientation); - MT_Matrix3x3 scale(inverseOrientation.transposed()*parinvtrans.getBasis()); - parentinversenode->SetLocalScale(MT_Vector3(scale[0][0], scale[1][1], scale[2][2])); + MT_Matrix3x3 ori(parinvtrans.getBasis()); + MT_Vector3 x(ori.getColumn(0)); + MT_Vector3 y(ori.getColumn(1)); + MT_Vector3 z(ori.getColumn(2)); + MT_Vector3 scale(x.length(), y.length(), z.length()); + if (!MT_fuzzyZero(scale[0])) + x /= scale[0]; + if (!MT_fuzzyZero(scale[1])) + y /= scale[1]; + if (!MT_fuzzyZero(scale[2])) + z /= scale[2]; + ori.setColumn(0, x); + ori.setColumn(1, y); + ori.setColumn(2, z); + parentinversenode->SetLocalOrientation(ori); + parentinversenode->SetLocalScale(scale); parentinversenode->AddChild(gameobj->GetSGNode()); } @@ -2129,7 +2141,24 @@ void BL_ConvertBlenderObjects(struct Main* maggie, float* fl = (float*) blenderobject->parentinv; MT_Transform parinvtrans(fl); parentinversenode->SetLocalPosition(parinvtrans.getOrigin()); - parentinversenode->SetLocalOrientation(parinvtrans.getBasis()); + + // Extract the rotation and the scaling from the basis + MT_Matrix3x3 ori(parinvtrans.getBasis()); + MT_Vector3 x(ori.getColumn(0)); + MT_Vector3 y(ori.getColumn(1)); + MT_Vector3 z(ori.getColumn(2)); + MT_Vector3 scale(x.length(), y.length(), z.length()); + if (!MT_fuzzyZero(scale[0])) + x /= scale[0]; + if (!MT_fuzzyZero(scale[1])) + y /= scale[1]; + if (!MT_fuzzyZero(scale[2])) + z /= scale[2]; + ori.setColumn(0, x); + ori.setColumn(1, y); + ori.setColumn(2, z); + parentinversenode->SetLocalOrientation(ori); + parentinversenode->SetLocalScale(scale); parentinversenode->AddChild(gameobj->GetSGNode()); } diff --git a/source/gameengine/Converter/KX_ConvertActuators.cpp b/source/gameengine/Converter/KX_ConvertActuators.cpp index cb2521de9a4..7e976beaf44 100644 --- a/source/gameengine/Converter/KX_ConvertActuators.cpp +++ b/source/gameengine/Converter/KX_ConvertActuators.cpp @@ -355,22 +355,26 @@ void BL_ConvertActuators(char* maggiename, if (soundActuatorType != KX_SoundActuator::KX_SOUNDACT_NODEF) { - SND_SoundObject* sndobj = NULL; + SND_Scene* soundscene = scene->GetSoundScene(); + STR_String samplename = ""; + bool sampleisloaded = false; - if (soundact->sound) - { - SND_Scene* soundscene = scene->GetSoundScene(); - STR_String samplename = soundact->sound->name; + if (soundact->sound) { + /* Need to convert the samplename into absolute path + * before checking if its loaded */ + char fullpath[sizeof(soundact->sound->name)]; - bool sampleisloaded = false; + /* dont modify soundact->sound->name, only change a copy */ + BLI_strncpy(fullpath, soundact->sound->name, sizeof(fullpath)); + BLI_convertstringcode(fullpath, maggiename); + samplename = fullpath; /* let's see if the sample was already loaded */ if (soundscene->IsSampleLoaded(samplename)) { sampleisloaded = true; } - else - { + else { /* if not, make it so */ PackedFile* pf = soundact->sound->newpackedfile; @@ -383,21 +387,33 @@ void BL_ConvertActuators(char* maggiename, /* or else load it from disk */ else { - /* but we need to convert the samplename into absolute pathname first */ - BLI_convertstringcode(soundact->sound->name, maggiename); - samplename = soundact->sound->name; - - /* and now we can load it */ - if (soundscene->LoadSample(samplename, NULL, 0) > -1) + if (soundscene->LoadSample(samplename, NULL, 0) > -1) { sampleisloaded = true; + } + else { + std::cout << "WARNING: Sound actuator \"" << bact->name << + "\" from object \"" << blenderobject->id.name+2 << + "\" failed to load sample." << std::endl; + } } } - - if (sampleisloaded) - { - sndobj = new SND_SoundObject(); - sndobj->SetSampleName(samplename.Ptr()); - sndobj->SetObjectName(bact->name); + } else { + std::cout << "WARNING: Sound actuator \"" << bact->name << + "\" from object \"" << blenderobject->id.name+2 << + "\" has no sound datablock." << std::endl; + } + + /* Note, allowing actuators for sounds that are not there was added since 2.47 + * This is because python may expect the actuator and raise an exception if it dosnt find it + * better just to add a dummy sound actuator. */ + SND_SoundObject* sndobj = NULL; + if (sampleisloaded) + { + /* setup the SND_SoundObject */ + sndobj = new SND_SoundObject(); + sndobj->SetSampleName(samplename.Ptr()); + sndobj->SetObjectName(bact->name); + if (soundact->sound) { sndobj->SetRollOffFactor(soundact->sound->attenuation); sndobj->SetGain(soundact->sound->volume); sndobj->SetPitch(exp((soundact->sound->pitch / 12.0) * log(2.0))); @@ -410,8 +426,9 @@ void BL_ConvertActuators(char* maggiename, else sndobj->SetLoopMode(SND_LOOP_NORMAL); } - else + else { sndobj->SetLoopMode(SND_LOOP_OFF); + } if (soundact->sound->flags & SOUND_FLAGS_PRIORITY) sndobj->SetHighPriority(true); @@ -422,22 +439,30 @@ void BL_ConvertActuators(char* maggiename, sndobj->Set3D(true); else sndobj->Set3D(false); - - KX_SoundActuator* tmpsoundact = - new KX_SoundActuator(gameobj, - sndobj, - scene->GetSoundScene(), // needed for replication! - soundActuatorType, - startFrame, - stopFrame); - - tmpsoundact->SetName(bact->name); - baseact = tmpsoundact; - soundscene->AddObject(sndobj); - } else { - std::cout << "WARNING: Sound actuator " << bact->name << " failed to load sample." << std::endl; + } + else { + /* dummy values for a NULL sound + * see editsound.c - defaults are unlikely to change soon */ + sndobj->SetRollOffFactor(1.0); + sndobj->SetGain(1.0); + sndobj->SetPitch(1.0); + sndobj->SetLoopMode(SND_LOOP_OFF); + sndobj->SetHighPriority(false); + sndobj->Set3D(false); } } + KX_SoundActuator* tmpsoundact = + new KX_SoundActuator(gameobj, + sndobj, + scene->GetSoundScene(), // needed for replication! + soundActuatorType, + startFrame, + stopFrame); + + tmpsoundact->SetName(bact->name); + baseact = tmpsoundact; + if (sndobj) + soundscene->AddObject(sndobj); } break; } @@ -550,10 +575,16 @@ void BL_ConvertActuators(char* maggiename, originalval = converter->FindGameObject(editobact->ob); } } - MT_Vector3 linvelvec ( KX_BLENDERTRUNC(editobact->linVelocity[0]), + MT_Vector3 linvelvec ( + KX_BLENDERTRUNC(editobact->linVelocity[0]), KX_BLENDERTRUNC(editobact->linVelocity[1]), KX_BLENDERTRUNC(editobact->linVelocity[2])); - + + MT_Vector3 angvelvec ( + KX_BLENDERTRUNC(editobact->angVelocity[0]), + KX_BLENDERTRUNC(editobact->angVelocity[1]), + KX_BLENDERTRUNC(editobact->angVelocity[2])); + KX_SCA_AddObjectActuator* tmpaddact = new KX_SCA_AddObjectActuator( gameobj, @@ -561,7 +592,9 @@ void BL_ConvertActuators(char* maggiename, editobact->time, scene, linvelvec.getValue(), - editobact->localflag!=0 + (editobact->localflag & ACT_EDOB_LOCAL_LINV)!=0, + angvelvec.getValue(), + (editobact->localflag & ACT_EDOB_LOCAL_ANGV)!=0 ); //editobact->ob to gameobj diff --git a/source/gameengine/Converter/KX_ConvertSensors.cpp b/source/gameengine/Converter/KX_ConvertSensors.cpp index 5e433bb821b..db47dc2dd3d 100644 --- a/source/gameengine/Converter/KX_ConvertSensors.cpp +++ b/source/gameengine/Converter/KX_ConvertSensors.cpp @@ -65,6 +65,7 @@ probably misplaced */ #include "SCA_JoystickSensor.h" #include "KX_NetworkMessageSensor.h" #include "SCA_ActuatorSensor.h" +#include "SCA_DelaySensor.h" #include "SCA_PropertySensor.h" @@ -281,6 +282,22 @@ void BL_ConvertSensors(struct Object* blenderobject, break; } + case SENS_DELAY: + { + // we can reuse the Always event manager for the delay sensor + SCA_EventManager* eventmgr = logicmgr->FindEventManager(SCA_EventManager::ALWAYS_EVENTMGR); + if (eventmgr) + { + bDelaySensor* delaysensor = (bDelaySensor*)sens->data; + gamesensor = new SCA_DelaySensor(eventmgr, + gameobj, + delaysensor->delay, + delaysensor->duration, + (delaysensor->flag & SENS_DELAY_REPEAT) != 0); + } + break; + } + case SENS_COLLISION: { SCA_EventManager* eventmgr = logicmgr->FindEventManager(SCA_EventManager::TOUCH_EVENTMGR); @@ -616,6 +633,7 @@ void BL_ConvertSensors(struct Object* blenderobject, if (eventmgr) { bool bFindMaterial = (blenderraysensor->mode & SENS_COLLISION_MATERIAL); + bool bXRay = (blenderraysensor->mode & SENS_RAY_XRAY); STR_String checkname = (bFindMaterial? blenderraysensor->matname : blenderraysensor->propname); @@ -628,6 +646,7 @@ void BL_ConvertSensors(struct Object* blenderobject, gameobj, checkname, bFindMaterial, + bXRay, distance, axis, kxscene); @@ -741,10 +760,24 @@ void BL_ConvertSensors(struct Object* blenderobject, for (int i=0;i<sens->totlinks;i++) { bController* linkedcont = (bController*) sens->links[i]; - SCA_IController* gamecont = converter->FindGameController(linkedcont); + if (linkedcont) { + SCA_IController* gamecont = converter->FindGameController(linkedcont); - if (gamecont) { - logicmgr->RegisterToSensor(gamecont,gamesensor); + if (gamecont) { + logicmgr->RegisterToSensor(gamecont,gamesensor); + } else { + printf( + "Warning, sensor \"%s\" could not find its controller " + "(link %d of %d) from object \"%s\"\n" + "\tthere has been an error converting the blender controller for the game engine," + "logic may be incorrect\n", sens->name, i+1, sens->totlinks, blenderobject->id.name+2); + } + } else { + printf( + "Warning, sensor \"%s\" has lost a link to a controller " + "(link %d of %d) from object \"%s\"\n" + "\tpossible causes are partially appended objects or an error reading the file," + "logic may be incorrect\n", sens->name, i+1, sens->totlinks, blenderobject->id.name+2); } } // done with gamesensor diff --git a/source/gameengine/Expressions/PyObjectPlus.h b/source/gameengine/Expressions/PyObjectPlus.h index f433a08faba..65cd4e890f7 100644 --- a/source/gameengine/Expressions/PyObjectPlus.h +++ b/source/gameengine/Expressions/PyObjectPlus.h @@ -102,6 +102,12 @@ static inline void Py_Fatal(char *M) { return ((class_name*) self)->Py##method_name(self, args, kwds); \ }; \ +#define KX_PYMETHOD_VARARGS(class_name, method_name) \ + PyObject* Py##method_name(PyObject* self, PyObject* args); \ + static PyObject* sPy##method_name( PyObject* self, PyObject* args) { \ + return ((class_name*) self)->Py##method_name(self, args); \ + }; \ + #define KX_PYMETHOD_NOARGS(class_name, method_name) \ PyObject* Py##method_name(PyObject* self); \ static PyObject* sPy##method_name( PyObject* self) { \ @@ -150,6 +156,9 @@ static inline void Py_Fatal(char *M) { #define KX_PYMETHODTABLE(class_name, method_name) \ {#method_name , (PyCFunction) class_name::sPy##method_name, METH_VARARGS, class_name::method_name##_doc} +#define KX_PYMETHODTABLE_NOARG(class_name, method_name) \ + {#method_name , (PyCFunction) class_name::sPy##method_name, METH_NOARGS, class_name::method_name##_doc} + /** * Function implementation macro */ @@ -157,6 +166,9 @@ static inline void Py_Fatal(char *M) { char class_name::method_name##_doc[] = doc_string; \ PyObject* class_name::Py##method_name(PyObject*, PyObject* args, PyObject*) +#define KX_PYMETHODDEF_DOC_NOARG(class_name, method_name, doc_string) \ +char class_name::method_name##_doc[] = doc_string; \ +PyObject* class_name::Py##method_name(PyObject*) /*------------------------------ * PyObjectPlus diff --git a/source/gameengine/GameLogic/SCA_DelaySensor.cpp b/source/gameengine/GameLogic/SCA_DelaySensor.cpp new file mode 100644 index 00000000000..4d05250e91c --- /dev/null +++ b/source/gameengine/GameLogic/SCA_DelaySensor.cpp @@ -0,0 +1,257 @@ +/** + * Delay trigger + * + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#ifdef WIN32 +// This warning tells us about truncation of __long__ stl-generated names. +// It can occasionally cause DevStudio to have internal compiler warnings. +#pragma warning( disable : 4786 ) +#endif + +#include "SCA_DelaySensor.h" +#include "SCA_LogicManager.h" +#include "SCA_EventManager.h" + +/* ------------------------------------------------------------------------- */ +/* Native functions */ +/* ------------------------------------------------------------------------- */ + +SCA_DelaySensor::SCA_DelaySensor(class SCA_EventManager* eventmgr, + SCA_IObject* gameobj, + int delay, + int duration, + bool repeat, + PyTypeObject* T) + : SCA_ISensor(gameobj,eventmgr, T), + m_delay(delay), + m_duration(duration), + m_repeat(repeat) +{ + Init(); +} + +void SCA_DelaySensor::Init() +{ + m_lastResult = false; + m_frameCount = -1; + m_reset = true; +} + +SCA_DelaySensor::~SCA_DelaySensor() +{ + /* intentionally empty */ +} + +CValue* SCA_DelaySensor::GetReplica() +{ + CValue* replica = new SCA_DelaySensor(*this); + // this will copy properties and so on... + CValue::AddDataToReplica(replica); + + return replica; +} + + + +bool SCA_DelaySensor::IsPositiveTrigger() +{ + return (m_invert ? !m_lastResult : m_lastResult); +} + +bool SCA_DelaySensor::Evaluate(CValue* event) +{ + bool trigger = false; + bool result; + + if (m_frameCount==-1) { + // this is needed to ensure ON trigger in case delay==0 + // and avoid spurious OFF trigger when duration==0 + m_lastResult = false; + m_frameCount = 0; + } + + if (m_frameCount<m_delay) { + m_frameCount++; + result = false; + } else if (m_duration > 0) { + if (m_frameCount < m_delay+m_duration) { + m_frameCount++; + result = true; + } else { + result = false; + if (m_repeat) + m_frameCount = -1; + } + } else { + result = true; + if (m_repeat) + m_frameCount = -1; + } + if ((m_reset && m_level) || result != m_lastResult) + trigger = true; + m_reset = false; + m_lastResult = result; + return trigger; +} + +/* ------------------------------------------------------------------------- */ +/* Python functions */ +/* ------------------------------------------------------------------------- */ + +/* Integration hooks ------------------------------------------------------- */ +PyTypeObject SCA_DelaySensor::Type = { + PyObject_HEAD_INIT(&PyType_Type) + 0, + "SCA_DelaySensor", + sizeof(SCA_DelaySensor), + 0, + PyDestructor, + 0, + __getattr, + __setattr, + 0, //&MyPyCompare, + __repr, + 0, //&cvalue_as_number, + 0, + 0, + 0, + 0 +}; + +PyParentObject SCA_DelaySensor::Parents[] = { + &SCA_DelaySensor::Type, + &SCA_ISensor::Type, + &SCA_ILogicBrick::Type, + &CValue::Type, + NULL +}; + +PyMethodDef SCA_DelaySensor::Methods[] = { + /* setProperty */ + {"setDelay", (PyCFunction) SCA_DelaySensor::sPySetDelay, METH_VARARGS, SetDelay_doc}, + {"setDuration", (PyCFunction) SCA_DelaySensor::sPySetDuration, METH_VARARGS, SetDuration_doc}, + {"setRepeat", (PyCFunction) SCA_DelaySensor::sPySetRepeat, METH_VARARGS, SetRepeat_doc}, + /* getProperty */ + {"getDelay", (PyCFunction) SCA_DelaySensor::sPyGetDelay, METH_NOARGS, GetDelay_doc}, + {"getDuration", (PyCFunction) SCA_DelaySensor::sPyGetDuration, METH_NOARGS, GetDuration_doc}, + {"getRepeat", (PyCFunction) SCA_DelaySensor::sPyGetRepeat, METH_NOARGS, GetRepeat_doc}, + {NULL,NULL} //Sentinel +}; + +PyObject* SCA_DelaySensor::_getattr(const STR_String& attr) { + _getattr_up(SCA_ISensor); +} + +char SCA_DelaySensor::SetDelay_doc[] = +"setDelay(delay)\n" +"\t- delay: length of the initial OFF period as number of frame\n" +"\t 0 for immediate trigger\n" +"\tSet the initial delay before the positive trigger\n"; +PyObject* SCA_DelaySensor::PySetDelay(PyObject* self, PyObject* args, PyObject* kwds) +{ + int delay; + + if(!PyArg_ParseTuple(args, "i", &delay)) { + return NULL; + } + if (delay < 0) { + PyErr_SetString(PyExc_ValueError, "Delay cannot be negative"); + return NULL; + } + m_delay = delay; + Py_Return; +} + +char SCA_DelaySensor::SetDuration_doc[] = +"setDuration(duration)\n" +"\t- duration: length of the ON period in number of frame after the initial off period\n" +"\t 0 for no ON period\n" +"\tSet the duration of the ON pulse after initial delay.\n" +"\tIf > 0, a negative trigger is fired at the end of the ON pulse.\n"; +PyObject* SCA_DelaySensor::PySetDuration(PyObject* self, PyObject* args, PyObject* kwds) +{ + int duration; + + if(!PyArg_ParseTuple(args, "i", &duration)) { + return NULL; + } + if (duration < 0) { + PyErr_SetString(PyExc_ValueError, "Duration cannot be negative"); + return NULL; + } + m_duration = duration; + Py_Return; +} + +char SCA_DelaySensor::SetRepeat_doc[] = +"setRepeat(repeat)\n" +"\t- repeat: 1 if the initial OFF-ON cycle should be repeated indefinately\n" +"\t 0 if the initial OFF-ON cycle should run only once\n" +"\tSet the sensor repeat mode\n"; +PyObject* SCA_DelaySensor::PySetRepeat(PyObject* self, PyObject* args, PyObject* kwds) +{ + int repeat; + + if(!PyArg_ParseTuple(args, "i", &repeat)) { + return NULL; + } + m_repeat = (repeat != 0); + Py_Return; +} + +char SCA_DelaySensor::GetDelay_doc[] = +"getDelay()\n" +"\tReturn the delay parameter value\n"; +PyObject* SCA_DelaySensor::PyGetDelay(PyObject* self) +{ + return PyInt_FromLong(m_delay); +} + +char SCA_DelaySensor::GetDuration_doc[] = +"getDuration()\n" +"\tReturn the duration parameter value\n"; +PyObject* SCA_DelaySensor::PyGetDuration(PyObject* self) +{ + return PyInt_FromLong(m_duration); +} + +char SCA_DelaySensor::GetRepeat_doc[] = +"getRepeat()\n" +"\tReturn the repeat parameter value\n"; +PyObject* SCA_DelaySensor::PyGetRepeat(PyObject* self) +{ + return BoolToPyArg(m_repeat); +} + +/* eof */ diff --git a/source/gameengine/GameLogic/SCA_DelaySensor.h b/source/gameengine/GameLogic/SCA_DelaySensor.h new file mode 100644 index 00000000000..a997fabe3cd --- /dev/null +++ b/source/gameengine/GameLogic/SCA_DelaySensor.h @@ -0,0 +1,77 @@ +/** + * SCA_DelaySensor.h + * + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef __KX_DELAYSENSOR +#define __KX_DELAYSENSOR +#include "SCA_ISensor.h" + +class SCA_DelaySensor : public SCA_ISensor +{ + Py_Header; + bool m_lastResult; + bool m_repeat; + int m_delay; + int m_duration; + int m_frameCount; + +public: + SCA_DelaySensor(class SCA_EventManager* eventmgr, + SCA_IObject* gameobj, + int delay, + int duration, + bool repeat, + PyTypeObject* T =&Type); + virtual ~SCA_DelaySensor(); + virtual CValue* GetReplica(); + virtual bool Evaluate(CValue* event); + virtual bool IsPositiveTrigger(); + virtual void Init(); + + + /* --------------------------------------------------------------------- */ + /* Python interface ---------------------------------------------------- */ + /* --------------------------------------------------------------------- */ + + virtual PyObject* _getattr(const STR_String& attr); + + /* setProperty */ + KX_PYMETHOD_DOC(SCA_DelaySensor,SetDelay); + KX_PYMETHOD_DOC(SCA_DelaySensor,SetDuration); + KX_PYMETHOD_DOC(SCA_DelaySensor,SetRepeat); + /* getProperty */ + KX_PYMETHOD_DOC_NOARGS(SCA_DelaySensor,GetDelay); + KX_PYMETHOD_DOC_NOARGS(SCA_DelaySensor,GetDuration); + KX_PYMETHOD_DOC_NOARGS(SCA_DelaySensor,GetRepeat); + +}; + +#endif //__KX_ALWAYSSENSOR + diff --git a/source/gameengine/GameLogic/SCA_IController.cpp b/source/gameengine/GameLogic/SCA_IController.cpp index 8f156cc63e7..0bd20117f31 100644 --- a/source/gameengine/GameLogic/SCA_IController.cpp +++ b/source/gameengine/GameLogic/SCA_IController.cpp @@ -188,6 +188,8 @@ void SCA_IController::ApplyState(unsigned int state) for (sensit = m_linkedsensors.begin();!(sensit==m_linkedsensors.end());++sensit) { (*sensit)->IncLink(); + // remember that this controller just activated that sensor + (*sensit)->AddNewController(this); } SetActive(true); } diff --git a/source/gameengine/GameLogic/SCA_ISensor.cpp b/source/gameengine/GameLogic/SCA_ISensor.cpp index 2dc49924062..c96eb82e29e 100644 --- a/source/gameengine/GameLogic/SCA_ISensor.cpp +++ b/source/gameengine/GameLogic/SCA_ISensor.cpp @@ -32,6 +32,8 @@ #include "SCA_ISensor.h" #include "SCA_EventManager.h" #include "SCA_LogicManager.h" +// needed for IsTriggered() +#include "SCA_PythonController.h" #ifdef HAVE_CONFIG_H #include <config.h> @@ -132,10 +134,8 @@ void SCA_ISensor::DecLink() { } if (!m_links) { - // sensor is detached from all controllers, initialize it so that it - // is fresh as at startup when it is reattached again. + // sensor is detached from all controllers, remove it from manager UnregisterToManager(); - Init(); } } @@ -168,7 +168,9 @@ PyParentObject SCA_ISensor::Parents[] = { }; PyMethodDef SCA_ISensor::Methods[] = { {"isPositive", (PyCFunction) SCA_ISensor::sPyIsPositive, - METH_VARARGS, IsPositive_doc}, + METH_NOARGS, IsPositive_doc}, + {"isTriggered", (PyCFunction) SCA_ISensor::sPyIsTriggered, + METH_VARARGS, IsTriggered_doc}, {"getUsePosPulseMode", (PyCFunction) SCA_ISensor::sPyGetUsePosPulseMode, METH_NOARGS, GetUsePosPulseMode_doc}, {"setUsePosPulseMode", (PyCFunction) SCA_ISensor::sPySetUsePosPulseMode, @@ -189,6 +191,8 @@ PyMethodDef SCA_ISensor::Methods[] = { METH_NOARGS, GetLevel_doc}, {"setLevel", (PyCFunction) SCA_ISensor::sPySetLevel, METH_VARARGS, SetLevel_doc}, + {"reset", (PyCFunction) SCA_ISensor::sPyReset, + METH_NOARGS, Reset_doc}, {NULL,NULL} //Sentinel }; @@ -202,6 +206,9 @@ SCA_ISensor::_getattr(const STR_String& attr) void SCA_ISensor::RegisterToManager() { + // sensor is just activated, initialize it + Init(); + m_newControllers.erase(m_newControllers.begin(), m_newControllers.end()); m_eventmgr->RegisterSensor(this); } @@ -247,19 +254,47 @@ void SCA_ISensor::Activate(class SCA_LogicManager* logicmgr, CValue* event) } } } + if (!m_newControllers.empty()) + { + if (!IsActive() && m_level) + { + // This level sensor is connected to at least one controller that was just made + // active but it did not generate an event yet, do it now to those controllers only + for (std::vector<SCA_IController*>::iterator ci=m_newControllers.begin(); + ci != m_newControllers.end(); ci++) + { + logicmgr->AddTriggeredController(*ci, this); + } + } + // clear the list. Instead of using clear, which also release the memory, + // use erase, which keeps the memory available for next time. + m_newControllers.erase(m_newControllers.begin(), m_newControllers.end()); + } } } /* Python functions: */ char SCA_ISensor::IsPositive_doc[] = "isPositive()\n" -"\tReturns whether the sensor is registered a positive event.\n"; -PyObject* SCA_ISensor::PyIsPositive(PyObject* self, PyObject* args, PyObject* kwds) +"\tReturns whether the sensor is in an active state.\n"; +PyObject* SCA_ISensor::PyIsPositive(PyObject* self) { int retval = IsPositiveTrigger(); return PyInt_FromLong(retval); } +char SCA_ISensor::IsTriggered_doc[] = +"isTriggered()\n" +"\tReturns whether the sensor has triggered the current controller.\n"; +PyObject* SCA_ISensor::PyIsTriggered(PyObject* self) +{ + // check with the current controller + int retval = 0; + if (SCA_PythonController::m_sCurrentController) + retval = SCA_PythonController::m_sCurrentController->IsTriggered(this); + return PyInt_FromLong(retval); +} + /** * getUsePulseMode: getter for the pulse mode (KX_TRUE = on) */ @@ -390,4 +425,15 @@ PyObject* SCA_ISensor::PySetUseNegPulseMode(PyObject* self, PyObject* args, PyOb Py_Return; } +char SCA_ISensor::Reset_doc[] = +"reset()\n" +"\tReset sensor internal state, effect depends on the type of sensor and settings.\n" +"\tThe sensor is put in its initial state as if it was just activated.\n"; +PyObject* SCA_ISensor::PyReset(PyObject* self) +{ + Init(); + Py_Return; +} + + /* eof */ diff --git a/source/gameengine/GameLogic/SCA_ISensor.h b/source/gameengine/GameLogic/SCA_ISensor.h index d5dabbce3ee..0d65270dc7b 100644 --- a/source/gameengine/GameLogic/SCA_ISensor.h +++ b/source/gameengine/GameLogic/SCA_ISensor.h @@ -34,6 +34,8 @@ #include "SCA_ILogicBrick.h" +#include <vector> + /** * Interface Class for all logic Sensors. Implements * pulsemode,pulsefrequency */ @@ -73,9 +75,9 @@ class SCA_ISensor : public SCA_ILogicBrick /** number of connections to controller */ int m_links; - /** Pass the activation on to the logic manager.*/ - void SignalActivation(class SCA_LogicManager* logicmgr); - + /** list of controllers that have just activated this sensor because of a state change */ + std::vector<class SCA_IController*> m_newControllers; + public: SCA_ISensor(SCA_IObject* gameobj, class SCA_EventManager* eventmgr, @@ -128,6 +130,8 @@ public: /** Resume sensing. */ void Resume(); + void AddNewController(class SCA_IController* controller) + { m_newControllers.push_back(controller); } void ClrLink() { m_links = 0; } void IncLink() @@ -137,7 +141,8 @@ public: { return !m_links; } /* Python functions: */ - KX_PYMETHOD_DOC(SCA_ISensor,IsPositive); + KX_PYMETHOD_DOC_NOARGS(SCA_ISensor,IsPositive); + KX_PYMETHOD_DOC_NOARGS(SCA_ISensor,IsTriggered); KX_PYMETHOD_DOC_NOARGS(SCA_ISensor,GetUsePosPulseMode); KX_PYMETHOD_DOC(SCA_ISensor,SetUsePosPulseMode); KX_PYMETHOD_DOC_NOARGS(SCA_ISensor,GetFrequency); @@ -148,6 +153,7 @@ public: KX_PYMETHOD_DOC(SCA_ISensor,SetInvert); KX_PYMETHOD_DOC_NOARGS(SCA_ISensor,GetLevel); KX_PYMETHOD_DOC(SCA_ISensor,SetLevel); + KX_PYMETHOD_DOC_NOARGS(SCA_ISensor,Reset); }; diff --git a/source/gameengine/GameLogic/SCA_KeyboardSensor.cpp b/source/gameengine/GameLogic/SCA_KeyboardSensor.cpp index a7a6fa93db4..fba1162993d 100644 --- a/source/gameengine/GameLogic/SCA_KeyboardSensor.cpp +++ b/source/gameengine/GameLogic/SCA_KeyboardSensor.cpp @@ -505,7 +505,7 @@ PyObject* SCA_KeyboardSensor::sPySetAllMode(PyObject* self, PyObject* kwds) { // printf("sPyIsPositive\n"); - return ((SCA_KeyboardSensor*) self)->PyIsPositive(self, args, kwds); + return ((SCA_KeyboardSensor*) self)->PyIsPositive(self); } diff --git a/source/gameengine/GameLogic/SCA_LogicManager.cpp b/source/gameengine/GameLogic/SCA_LogicManager.cpp index 91e66aea359..b584b37180f 100644 --- a/source/gameengine/GameLogic/SCA_LogicManager.cpp +++ b/source/gameengine/GameLogic/SCA_LogicManager.cpp @@ -33,6 +33,7 @@ #include "SCA_IController.h" #include "SCA_IActuator.h" #include "SCA_EventManager.h" +#include "SCA_PythonController.h" #include <set> #ifdef HAVE_CONFIG_H @@ -232,8 +233,6 @@ void SCA_LogicManager::BeginFrame(double curtime, double fixedtime) // for this frame, look up for activated sensors, and build the collection of triggered controllers // int numsensors = this->m_activatedsensors.size(); /*unused*/ - set<SmartControllerPtr> triggeredControllerSet; - for (vector<SCA_ISensor*>::const_iterator is=m_activatedsensors.begin(); !(is==m_activatedsensors.end());is++) { @@ -244,19 +243,28 @@ void SCA_LogicManager::BeginFrame(double curtime, double fixedtime) { SCA_IController* contr = *c;//controllerarray->at(c); if (contr->IsActive()) - triggeredControllerSet.insert(SmartControllerPtr(contr,0)); + { + m_triggeredControllerSet.insert(SmartControllerPtr(contr,0)); + // So that the controller knows which sensor has activited it. + // Only needed for the python controller though. + if (contr->GetType() == &SCA_PythonController::Type) + { + SCA_PythonController* pythonController = (SCA_PythonController*)contr; + pythonController->AddTriggeredSensor(sensor); + } + } } //sensor->SetActive(false); } // int numtriggered = triggeredControllerSet.size(); /*unused*/ - for (set<SmartControllerPtr>::iterator tit=triggeredControllerSet.begin(); - !(tit==triggeredControllerSet.end());tit++) + for (set<SmartControllerPtr>::iterator tit=m_triggeredControllerSet.begin(); + !(tit==m_triggeredControllerSet.end());tit++) { (*tit)->Trigger(this); } - triggeredControllerSet.clear(); + m_triggeredControllerSet.clear(); } @@ -382,6 +390,17 @@ void SCA_LogicManager::AddActivatedSensor(SCA_ISensor* sensor) } } +void SCA_LogicManager::AddTriggeredController(SCA_IController* controller, SCA_ISensor* sensor) +{ + m_triggeredControllerSet.insert(SmartControllerPtr(controller,0)); + // so that the controller knows which sensor has activited it + // only needed for python controller + if (controller->GetType() == &SCA_PythonController::Type) + { + SCA_PythonController* pythonController = (SCA_PythonController*)controller; + pythonController->AddTriggeredSensor(sensor); + } +} void SCA_LogicManager::AddActiveActuator(SCA_IActuator* actua,CValue* event) diff --git a/source/gameengine/GameLogic/SCA_LogicManager.h b/source/gameengine/GameLogic/SCA_LogicManager.h index e0d3d506702..50383879d8f 100644 --- a/source/gameengine/GameLogic/SCA_LogicManager.h +++ b/source/gameengine/GameLogic/SCA_LogicManager.h @@ -99,6 +99,7 @@ class SCA_LogicManager vector<class SCA_ISensor*> m_activatedsensors; set<class SmartActuatorPtr> m_activeActuators; + set<class SmartControllerPtr> m_triggeredControllerSet; map<SCA_ISensor*,controllerlist > m_sensorcontrollermapje; @@ -127,6 +128,7 @@ public: void EndFrame(); void AddActivatedSensor(SCA_ISensor* sensor); void AddActiveActuator(SCA_IActuator* sensor,class CValue* event); + void AddTriggeredController(SCA_IController* controller, SCA_ISensor* sensor); SCA_EventManager* FindEventManager(int eventmgrtype); void RemoveGameObject(const STR_String& gameobjname); diff --git a/source/gameengine/GameLogic/SCA_PythonController.cpp b/source/gameengine/GameLogic/SCA_PythonController.cpp index cd1b029fc34..e6f7b1dd143 100644 --- a/source/gameengine/GameLogic/SCA_PythonController.cpp +++ b/source/gameengine/GameLogic/SCA_PythonController.cpp @@ -35,6 +35,7 @@ #include "SCA_IActuator.h" #include "compile.h" #include "eval.h" +#include <algorithm> #ifdef HAVE_CONFIG_H #include <config.h> @@ -139,6 +140,14 @@ void SCA_PythonController::SetDictionary(PyObject* pythondictionary) m_pythondictionary = PyDict_Copy(pythondictionary); /* new reference */ } +int SCA_PythonController::IsTriggered(class SCA_ISensor* sensor) +{ + if (std::find(m_triggeredSensors.begin(), m_triggeredSensors.end(), sensor) != + m_triggeredSensors.end()) + return 1; + return 0; +} + #if 0 static char* sPyGetCurrentController__doc__; #endif @@ -248,7 +257,7 @@ void SCA_PythonController::Trigger(SCA_LogicManager* logicmgr) { // didn't compile, so instead of compile, complain // something is wrong, tell the user what went wrong - printf("PYTHON SCRIPT ERROR:\n"); + printf("Python compile error from controller \"%s\": \n", GetName().Ptr()); //PyRun_SimpleString(m_scriptText.Ptr()); PyErr_Print(); return; @@ -285,7 +294,7 @@ void SCA_PythonController::Trigger(SCA_LogicManager* logicmgr) else { // something is wrong, tell the user what went wrong - printf("PYTHON SCRIPT ERROR:\n"); + printf("Python script error from controller \"%s\": \n", GetName().Ptr()); PyErr_Print(); //PyRun_SimpleString(m_scriptText.Ptr()); } @@ -294,7 +303,7 @@ void SCA_PythonController::Trigger(SCA_LogicManager* logicmgr) // something in this dictionary and crash? PyDict_Clear(excdict); Py_DECREF(excdict); - + m_triggeredSensors.erase(m_triggeredSensors.begin(), m_triggeredSensors.end()); m_sCurrentController = NULL; } diff --git a/source/gameengine/GameLogic/SCA_PythonController.h b/source/gameengine/GameLogic/SCA_PythonController.h index 39b6c68c359..1b62e7ecb53 100644 --- a/source/gameengine/GameLogic/SCA_PythonController.h +++ b/source/gameengine/GameLogic/SCA_PythonController.h @@ -36,6 +36,8 @@ #include "SCA_LogicManager.h" #include "BoolValue.h" +#include <vector> + class SCA_IObject; class SCA_PythonController : public SCA_IController { @@ -47,6 +49,7 @@ class SCA_PythonController : public SCA_IController STR_String m_scriptText; STR_String m_scriptName; PyObject* m_pythondictionary; + std::vector<class SCA_ISensor*> m_triggeredSensors; public: static SCA_PythonController* m_sCurrentController; // protected !!! @@ -64,6 +67,9 @@ class SCA_PythonController : public SCA_IController void SetScriptText(const STR_String& text); void SetScriptName(const STR_String& name); void SetDictionary(PyObject* pythondictionary); + void AddTriggeredSensor(class SCA_ISensor* sensor) + { m_triggeredSensors.push_back(sensor); } + int IsTriggered(class SCA_ISensor* sensor); static char* sPyGetCurrentController__doc__; static PyObject* sPyGetCurrentController(PyObject* self); diff --git a/source/gameengine/GamePlayer/common/GPC_RenderTools.cpp b/source/gameengine/GamePlayer/common/GPC_RenderTools.cpp index 8b828393c67..a64c85f6c17 100644 --- a/source/gameengine/GamePlayer/common/GPC_RenderTools.cpp +++ b/source/gameengine/GamePlayer/common/GPC_RenderTools.cpp @@ -470,11 +470,11 @@ void GPC_RenderTools::SetClientObject(void* obj) } } -bool GPC_RenderTools::RayHit(KX_ClientObjectInfo* client, MT_Point3& hit_point, MT_Vector3& hit_normal, void * const data) +bool GPC_RenderTools::RayHit(KX_ClientObjectInfo* client, KX_RayCast* result, void * const data) { double* const oglmatrix = (double* const) data; - MT_Point3 resultpoint(hit_point); - MT_Vector3 resultnormal(hit_normal); + MT_Point3 resultpoint(result->m_hitPoint); + MT_Vector3 resultnormal(result->m_hitNormal); MT_Vector3 left(oglmatrix[0],oglmatrix[1],oglmatrix[2]); MT_Vector3 dir = -(left.cross(resultnormal)).safe_normalized(); left = (dir.cross(resultnormal)).safe_normalized(); @@ -563,9 +563,8 @@ void GPC_RenderTools::applyTransform(RAS_IRasterizer* rasty,double* oglmatrix,in if (parent) parent->Release(); - MT_Point3 resultpoint; - MT_Vector3 resultnormal; - if (!KX_RayCast::RayTest(physics_controller, physics_environment, frompoint, topoint, resultpoint, resultnormal, KX_RayCast::Callback<GPC_RenderTools>(this, oglmatrix))) + KX_RayCast::Callback<GPC_RenderTools> callback(this, physics_controller, oglmatrix); + if (!KX_RayCast::RayTest(physics_environment, frompoint, topoint, callback)) { // couldn't find something to cast the shadow on... glMultMatrixd(oglmatrix); diff --git a/source/gameengine/GamePlayer/common/GPC_RenderTools.h b/source/gameengine/GamePlayer/common/GPC_RenderTools.h index 8fae3d2b305..9f70f67caf2 100644 --- a/source/gameengine/GamePlayer/common/GPC_RenderTools.h +++ b/source/gameengine/GamePlayer/common/GPC_RenderTools.h @@ -41,7 +41,7 @@ #include "BMF_Api.h" struct KX_ClientObjectInfo; - +class KX_RayCast; class GPC_RenderTools : public RAS_IRenderTools { @@ -138,7 +138,8 @@ public: int applyLights(int objectlayer); - bool RayHit(KX_ClientObjectInfo* client, MT_Point3& hit_point, MT_Vector3& hit_normal, void * const data); + bool RayHit(KX_ClientObjectInfo* client, KX_RayCast* result, void * const data); + bool NeedRayCast(KX_ClientObjectInfo* client) { return true; } virtual void MotionBlur(RAS_IRasterizer* rasterizer); diff --git a/source/gameengine/GamePlayer/ghost/GPG_Application.cpp b/source/gameengine/GamePlayer/ghost/GPG_Application.cpp index 7be3b94d8ae..c56a6d0da23 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,33 @@ 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"); + } + Py_DECREF(gameLogic); + } 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_ConstraintActuator.cpp b/source/gameengine/Ketsji/KX_ConstraintActuator.cpp index e00ec68ad33..4b57b0e8c54 100644 --- a/source/gameengine/Ketsji/KX_ConstraintActuator.cpp +++ b/source/gameengine/Ketsji/KX_ConstraintActuator.cpp @@ -109,16 +109,11 @@ KX_ConstraintActuator::~KX_ConstraintActuator() // there's nothing to be done here, really.... } /* end of destructor */ -bool KX_ConstraintActuator::RayHit(KX_ClientObjectInfo* client, MT_Point3& hit_point, MT_Vector3& hit_normal, void * const data) +bool KX_ConstraintActuator::RayHit(KX_ClientObjectInfo* client, KX_RayCast* result, void * const data) { KX_GameObject* hitKXObj = client->m_gameobject; - if (client->m_type > KX_ClientObjectInfo::ACTOR) - { - // false hit - return false; - } bool bFound = false; if (m_property[0] == 0) @@ -139,8 +134,26 @@ bool KX_ConstraintActuator::RayHit(KX_ClientObjectInfo* client, MT_Point3& hit_p bFound = hitKXObj->GetProperty(m_property) != NULL; } } + // update the hit status + result->m_hitFound = bFound; + // stop looking + return true; +} - return bFound; +/* this function is used to pre-filter the object before casting the ray on them. + This is useful for "X-Ray" option when we want to see "through" unwanted object. + */ +bool KX_ConstraintActuator::NeedRayCast(KX_ClientObjectInfo* client) +{ + if (client->m_type > KX_ClientObjectInfo::ACTOR) + { + // Unknown type of object, skip it. + // Should not occur as the sensor objects are filtered in RayTest() + printf("Invalid client type %d found in ray casting\n", client->m_type); + return false; + } + // no X-Ray function yet + return true; } bool KX_ConstraintActuator::Update(double curtime, bool frame) @@ -287,8 +300,6 @@ bool KX_ConstraintActuator::Update(double curtime, bool frame) direction.normalize(); { MT_Point3 topoint = position + (m_maximumBound) * direction; - MT_Point3 resultpoint; - MT_Vector3 resultnormal; PHY_IPhysicsEnvironment* pe = obj->GetPhysicsEnvironment(); KX_IPhysicsController *spc = obj->GetPhysicsController(); @@ -304,9 +315,10 @@ bool KX_ConstraintActuator::Update(double curtime, bool frame) parent->Release(); } } - result = KX_RayCast::RayTest(spc, pe, position, topoint, resultpoint, resultnormal, KX_RayCast::Callback<KX_ConstraintActuator>(this)); - + KX_RayCast::Callback<KX_ConstraintActuator> callback(this,spc); + result = KX_RayCast::RayTest(pe, position, topoint, callback); if (result) { + MT_Vector3 newnormal = callback.m_hitNormal; // compute new position & orientation if ((m_option & (KX_ACT_CONSTRAINT_NORMAL|KX_ACT_CONSTRAINT_DISTANCE)) == 0) { // if none option is set, the actuator does nothing but detect ray @@ -316,27 +328,27 @@ bool KX_ConstraintActuator::Update(double curtime, bool frame) if (m_option & KX_ACT_CONSTRAINT_NORMAL) { // the new orientation must be so that the axis is parallel to normal if (sign) - resultnormal = -resultnormal; + newnormal = -newnormal; // apply damping on the direction if (m_rotDampTime) { MT_Scalar rotFilter = 1.0/(1.0+m_rotDampTime); - resultnormal = (-m_rotDampTime*rotFilter)*direction + rotFilter*resultnormal; + newnormal = (-m_rotDampTime*rotFilter)*direction + rotFilter*newnormal; } else if (m_posDampTime) { - resultnormal = -filter*direction + (1.0-filter)*resultnormal; + newnormal = -filter*direction + (1.0-filter)*newnormal; } - obj->AlignAxisToVect(resultnormal, axis); - direction = -resultnormal; + obj->AlignAxisToVect(newnormal, axis); + direction = -newnormal; } if (m_option & KX_ACT_CONSTRAINT_DISTANCE) { if (m_posDampTime) { - newdistance = filter*(position-resultpoint).length()+(1.0-filter)*m_minimumBound; + newdistance = filter*(position-callback.m_hitPoint).length()+(1.0-filter)*m_minimumBound; } else { newdistance = m_minimumBound; } } else { - newdistance = (position-resultpoint).length(); + newdistance = (position-callback.m_hitPoint).length(); } - newposition = resultpoint-newdistance*direction; + newposition = callback.m_hitPoint-newdistance*direction; } else if (m_option & KX_ACT_CONSTRAINT_PERMANENT) { // no contact but still keep running result = true; diff --git a/source/gameengine/Ketsji/KX_ConstraintActuator.h b/source/gameengine/Ketsji/KX_ConstraintActuator.h index d9f39124cac..6ec4de9aad9 100644 --- a/source/gameengine/Ketsji/KX_ConstraintActuator.h +++ b/source/gameengine/Ketsji/KX_ConstraintActuator.h @@ -37,6 +37,8 @@ #include "MT_Vector3.h" #include "KX_ClientObjectInfo.h" +class KX_RayCast; + class KX_ConstraintActuator : public SCA_IActuator { Py_Header; @@ -100,7 +102,8 @@ protected: KX_ACT_CONSTRAINT_DISTANCE = 512 }; bool IsValidMode(KX_CONSTRAINTTYPE m); - bool RayHit(KX_ClientObjectInfo* client, MT_Point3& hit_point, MT_Vector3& hit_normal, void * const data); + bool RayHit(KX_ClientObjectInfo* client, KX_RayCast* result, void * const data); + bool NeedRayCast(KX_ClientObjectInfo*); KX_ConstraintActuator(SCA_IObject* gameobj, int posDamptime, 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_GameObject.cpp b/source/gameengine/Ketsji/KX_GameObject.cpp index 700cc00e996..c1b228e8d26 100644 --- a/source/gameengine/Ketsji/KX_GameObject.cpp +++ b/source/gameengine/Ketsji/KX_GameObject.cpp @@ -51,6 +51,7 @@ typedef unsigned long uint_ptr; #include "KX_GameObject.h" #include "RAS_MeshObject.h" #include "KX_MeshProxy.h" +#include "KX_PolyProxy.h" #include <stdio.h> // printf #include "SG_Controller.h" #include "KX_IPhysicsController.h" @@ -84,6 +85,7 @@ KX_GameObject::KX_GameObject( m_bVisible(true), m_pPhysicsController1(NULL), m_pPhysicsEnvironment(NULL), + m_xray(false), m_pHitObject(NULL), m_isDeformable(false) { @@ -885,6 +887,8 @@ PyMethodDef KX_GameObject::Methods[] = { {"setPosition", (PyCFunction) KX_GameObject::sPySetPosition, METH_O}, {"getLinearVelocity", (PyCFunction) KX_GameObject::sPyGetLinearVelocity, METH_VARARGS}, {"setLinearVelocity", (PyCFunction) KX_GameObject::sPySetLinearVelocity, METH_VARARGS}, + {"getAngularVelocity", (PyCFunction) KX_GameObject::sPyGetAngularVelocity, METH_VARARGS}, + {"setAngularVelocity", (PyCFunction) KX_GameObject::sPySetAngularVelocity, METH_VARARGS}, {"getVelocity", (PyCFunction) KX_GameObject::sPyGetVelocity, METH_VARARGS}, {"getMass", (PyCFunction) KX_GameObject::sPyGetMass, METH_NOARGS}, {"getReactionForce", (PyCFunction) KX_GameObject::sPyGetReactionForce, METH_NOARGS}, @@ -1146,9 +1150,7 @@ int KX_GameObject::_setattr(const STR_String& attr, PyObject *value) // _setattr } -PyObject* KX_GameObject::PyGetLinearVelocity(PyObject* self, - PyObject* args, - PyObject* kwds) +PyObject* KX_GameObject::PyGetLinearVelocity(PyObject* self, PyObject* args) { // only can get the velocity if we have a physics object connected to us... int local = 0; @@ -1162,9 +1164,7 @@ PyObject* KX_GameObject::PyGetLinearVelocity(PyObject* self, } } -PyObject* KX_GameObject::PySetLinearVelocity(PyObject* self, - PyObject* args, - PyObject* kwds) +PyObject* KX_GameObject::PySetLinearVelocity(PyObject* self, PyObject* args) { int local = 0; PyObject* pyvect; @@ -1179,6 +1179,35 @@ PyObject* KX_GameObject::PySetLinearVelocity(PyObject* self, return NULL; } +PyObject* KX_GameObject::PyGetAngularVelocity(PyObject* self, PyObject* args) +{ + // only can get the velocity if we have a physics object connected to us... + int local = 0; + if (PyArg_ParseTuple(args,"|i",&local)) + { + return PyObjectFrom(GetAngularVelocity((local!=0))); + } + else + { + return NULL; + } +} + +PyObject* KX_GameObject::PySetAngularVelocity(PyObject* self, PyObject* args) +{ + int local = 0; + PyObject* pyvect; + + if (PyArg_ParseTuple(args,"O|i",&pyvect,&local)) { + MT_Vector3 velocity; + if (PyVecTo(pyvect, velocity)) { + setAngularVelocity(velocity, (local!=0)); + Py_RETURN_NONE; + } + } + return NULL; +} + PyObject* KX_GameObject::PySetVisible(PyObject* self, PyObject* value) { int visible = PyInt_AsLong(value); @@ -1228,9 +1257,7 @@ PyObject* KX_GameObject::PySetState(PyObject* self, PyObject* value) -PyObject* KX_GameObject::PyGetVelocity(PyObject* self, - PyObject* args, - PyObject* kwds) +PyObject* KX_GameObject::PyGetVelocity(PyObject* self, PyObject* args) { // only can get the velocity if we have a physics object connected to us... MT_Vector3 velocity(0.0,0.0,0.0); @@ -1362,9 +1389,7 @@ PyObject* KX_GameObject::PyGetChildrenRecursive(PyObject* self) return list; } -PyObject* KX_GameObject::PyGetMesh(PyObject* self, - PyObject* args, - PyObject* kwds) +PyObject* KX_GameObject::PyGetMesh(PyObject* self, PyObject* args) { int mesh = 0; @@ -1404,9 +1429,7 @@ PyObject* KX_GameObject::PySetCollisionMargin(PyObject* self, PyObject* value) -PyObject* KX_GameObject::PyApplyImpulse(PyObject* self, - PyObject* args, - PyObject* kwds) +PyObject* KX_GameObject::PyApplyImpulse(PyObject* self, PyObject* args) { PyObject* pyattach; PyObject* pyimpulse; @@ -1477,9 +1500,7 @@ PyObject* KX_GameObject::PySetOrientation(PyObject* self, PyObject* value) return NULL; } -PyObject* KX_GameObject::PyAlignAxisToVect(PyObject* self, - PyObject* args, - PyObject* kwds) +PyObject* KX_GameObject::PyAlignAxisToVect(PyObject* self, PyObject* args) { PyObject* pyvect; int axis = 2; //z axis is the default @@ -1609,25 +1630,45 @@ KX_PYMETHODDEF_DOC(KX_GameObject, getVectTo, return returnValue; } -bool KX_GameObject::RayHit(KX_ClientObjectInfo* client, MT_Point3& hit_point, MT_Vector3& hit_normal, void * const data) +bool KX_GameObject::RayHit(KX_ClientObjectInfo* client, KX_RayCast* result, void * const data) { + KX_GameObject* hitKXObj = client->m_gameobject; + + // if X-ray option is selected, the unwnted objects were not tested, so get here only with true hit + // if not, all objects were tested and the front one may not be the correct one. + if (m_xray || m_testPropName.Length() == 0 || hitKXObj->GetProperty(m_testPropName) != NULL) + { + m_pHitObject = hitKXObj; + return true; + } + // return true to stop RayCast::RayTest from looping, the above test was decisive + // We would want to loop only if we want to get more than one hit point + return true; +} +/* this function is used to pre-filter the object before casting the ray on them. + This is useful for "X-Ray" option when we want to see "through" unwanted object. + */ +bool KX_GameObject::NeedRayCast(KX_ClientObjectInfo* client) +{ KX_GameObject* hitKXObj = client->m_gameobject; if (client->m_type > KX_ClientObjectInfo::ACTOR) { - // false hit + // Unknown type of object, skip it. + // Should not occur as the sensor objects are filtered in RayTest() + printf("Invalid client type %d found in ray casting\n", client->m_type); return false; } - - if (m_testPropName.Length() == 0 || hitKXObj->GetProperty(m_testPropName) != NULL) + + // if X-Ray option is selected, skip object that don't match the criteria as we see through them + // if not, test all objects because we don't know yet which one will be on front + if (!m_xray || m_testPropName.Length() == 0 || hitKXObj->GetProperty(m_testPropName) != NULL) { - m_pHitObject = hitKXObj; return true; } - + // skip the object return false; - } KX_PYMETHODDEF_DOC(KX_GameObject, rayCastTo, @@ -1667,8 +1708,6 @@ KX_PYMETHODDEF_DOC(KX_GameObject, rayCastTo, toPoint = fromPoint + (dist) * toDir; } - MT_Point3 resultPoint; - MT_Vector3 resultNormal; PHY_IPhysicsEnvironment* pe = GetPhysicsEnvironment(); KX_IPhysicsController *spc = GetPhysicsController(); KX_GameObject *parent = GetParent(); @@ -1682,7 +1721,8 @@ KX_PYMETHODDEF_DOC(KX_GameObject, rayCastTo, m_testPropName = propName; else m_testPropName.SetLength(0); - KX_RayCast::RayTest(spc, pe, fromPoint, toPoint, resultPoint, resultNormal, KX_RayCast::Callback<KX_GameObject>(this)); + KX_RayCast::Callback<KX_GameObject> callback(this,spc); + KX_RayCast::RayTest(pe, fromPoint, toPoint, callback); if (m_pHitObject) { @@ -1693,13 +1733,24 @@ KX_PYMETHODDEF_DOC(KX_GameObject, rayCastTo, } KX_PYMETHODDEF_DOC(KX_GameObject, rayCast, - "rayCast(to,from,dist,prop): cast a ray and return tuple (object,hit,normal) of contact point with object within dist that matches prop or (None,None,None) tuple if no hit\n" -" prop = property name that object must have; can be omitted => detect any object\n" -" dist = max distance to look (can be negative => look behind); 0 or omitted => detect up to to\n" + "rayCast(to,from,dist,prop,face,xray,poly): cast a ray and return 3-tuple (object,hit,normal) or 4-tuple (object,hit,normal,polygon) of contact point with object within dist that matches prop.\n" + " If no hit, return (None,None,None) or (None,None,None,None).\n" +" to = 3-tuple or object reference for destination of ray (if object, use center of object)\n" " from = 3-tuple or object reference for origin of ray (if object, use center of object)\n" " Can be None or omitted => start from self object center\n" -" to = 3-tuple or object reference for destination of ray (if object, use center of object)\n" -"Note: the object on which you call this method matters: the ray will ignore it if it goes through it\n") +" dist = max distance to look (can be negative => look behind); 0 or omitted => detect up to to\n" +" prop = property name that object must have; can be omitted => detect any object\n" +" face = normal option: 1=>return face normal; 0 or omitted => normal is oriented towards origin\n" +" xray = X-ray option: 1=>skip objects that don't match prop; 0 or omitted => stop on first object\n" +" poly = polygon option: 1=>return value is a 4-tuple and the 4th element is a KX_PolyProxy object\n" +" which can be None if hit object has no mesh or if there is no hit\n" +" If 0 or omitted, return value is a 3-tuple\n" +"Note: The object on which you call this method matters: the ray will ignore it.\n" +" prop and xray option interact as follow:\n" +" prop off, xray off: return closest hit or no hit if there is no object on the full extend of the ray\n" +" prop off, xray on : idem\n" +" prop on, xray off: return closest hit if it matches prop, no hit otherwise\n" +" prop on, xray on : return closest hit matching prop or no hit if there is no object matching prop on the full extend of the ray\n") { MT_Point3 toPoint; MT_Point3 fromPoint; @@ -1708,8 +1759,9 @@ KX_PYMETHODDEF_DOC(KX_GameObject, rayCast, float dist = 0.0f; char *propName = NULL; KX_GameObject *other; + int face=0, xray=0, poly=0; - if (!PyArg_ParseTuple(args,"O|Ofs", &pyto, &pyfrom, &dist, &propName)) { + if (!PyArg_ParseTuple(args,"O|Ofsiii", &pyto, &pyfrom, &dist, &propName, &face, &xray, &poly)) { return NULL; // Python sets a simple error } @@ -1755,8 +1807,6 @@ KX_PYMETHODDEF_DOC(KX_GameObject, rayCast, return Py_BuildValue("OOO", Py_None, Py_None, Py_None); } - MT_Point3 resultPoint; - MT_Vector3 resultNormal; PHY_IPhysicsEnvironment* pe = GetPhysicsEnvironment(); KX_IPhysicsController *spc = GetPhysicsController(); KX_GameObject *parent = GetParent(); @@ -1770,20 +1820,41 @@ KX_PYMETHODDEF_DOC(KX_GameObject, rayCast, m_testPropName = propName; else m_testPropName.SetLength(0); - KX_RayCast::RayTest(spc, pe, fromPoint, toPoint, resultPoint, resultNormal, KX_RayCast::Callback<KX_GameObject>(this)); + m_xray = xray; + // to get the hit results + KX_RayCast::Callback<KX_GameObject> callback(this,spc,NULL,face); + KX_RayCast::RayTest(pe, fromPoint, toPoint, callback); - if (m_pHitObject) + if (m_pHitObject) { - PyObject* returnValue = PyTuple_New(3); + PyObject* returnValue = (poly) ? PyTuple_New(4) : PyTuple_New(3); if (returnValue) { // unlikely this would ever fail, if it does python sets an error PyTuple_SET_ITEM(returnValue, 0, m_pHitObject->AddRef()); - PyTuple_SET_ITEM(returnValue, 1, PyObjectFrom(resultPoint)); - PyTuple_SET_ITEM(returnValue, 2, PyObjectFrom(resultNormal)); + PyTuple_SET_ITEM(returnValue, 1, PyObjectFrom(callback.m_hitPoint)); + PyTuple_SET_ITEM(returnValue, 2, PyObjectFrom(callback.m_hitNormal)); + if (poly) + { + if (callback.m_hitMesh) + { + // if this field is set, then we can trust that m_hitPolygon is a valid polygon + RAS_Polygon* poly = callback.m_hitMesh->GetPolygon(callback.m_hitPolygon); + KX_PolyProxy* polyproxy = new KX_PolyProxy(callback.m_hitMesh, poly); + PyTuple_SET_ITEM(returnValue, 3, polyproxy); + } + else + { + Py_INCREF(Py_None); + PyTuple_SET_ITEM(returnValue, 3, Py_None); + } + } } return returnValue; } - return Py_BuildValue("OOO", Py_None, Py_None, Py_None); - //Py_RETURN_NONE; + // no hit + if (poly) + return Py_BuildValue("OOOO", Py_None, Py_None, Py_None, Py_None); + else + return Py_BuildValue("OOO", Py_None, Py_None, Py_None); } /* --------------------------------------------------------------------- diff --git a/source/gameengine/Ketsji/KX_GameObject.h b/source/gameengine/Ketsji/KX_GameObject.h index a7ac2d75a93..508bc7cdfd0 100644 --- a/source/gameengine/Ketsji/KX_GameObject.h +++ b/source/gameengine/Ketsji/KX_GameObject.h @@ -54,6 +54,7 @@ //Forward declarations. struct KX_ClientObjectInfo; +class KX_RayCast; class RAS_MeshObject; class KX_IPhysicsController; class PHY_IPhysicsEnvironment; @@ -88,6 +89,7 @@ protected: // used for ray casting PHY_IPhysicsEnvironment* m_pPhysicsEnvironment; STR_String m_testPropName; + bool m_xray; KX_GameObject* m_pHitObject; SG_Node* m_pSGNode; @@ -428,7 +430,8 @@ public: return (m_pSGNode && m_pSGNode->GetSGParent() && m_pSGNode->GetSGParent()->IsVertexParent()); } - bool RayHit(KX_ClientObjectInfo* client, MT_Point3& hit_point, MT_Vector3& hit_normal, void * const data); + bool RayHit(KX_ClientObjectInfo* client, KX_RayCast* result, void * const data); + bool NeedRayCast(KX_ClientObjectInfo* client); /** @@ -726,9 +729,11 @@ public: KX_PYMETHOD_NOARGS(KX_GameObject,GetPosition); KX_PYMETHOD_O(KX_GameObject,SetPosition); - KX_PYMETHOD(KX_GameObject,GetLinearVelocity); - KX_PYMETHOD(KX_GameObject,SetLinearVelocity); - KX_PYMETHOD(KX_GameObject,GetVelocity); + KX_PYMETHOD_VARARGS(KX_GameObject,GetLinearVelocity); + KX_PYMETHOD_VARARGS(KX_GameObject,SetLinearVelocity); + KX_PYMETHOD_VARARGS(KX_GameObject,GetAngularVelocity); + KX_PYMETHOD_VARARGS(KX_GameObject,SetAngularVelocity); + KX_PYMETHOD_VARARGS(KX_GameObject,GetVelocity); KX_PYMETHOD_NOARGS(KX_GameObject,GetMass); KX_PYMETHOD_NOARGS(KX_GameObject,GetReactionForce); KX_PYMETHOD_NOARGS(KX_GameObject,GetOrientation); @@ -737,20 +742,20 @@ public: KX_PYMETHOD_O(KX_GameObject,SetVisible); KX_PYMETHOD_NOARGS(KX_GameObject,GetState); KX_PYMETHOD_O(KX_GameObject,SetState); - KX_PYMETHOD(KX_GameObject,AlignAxisToVect); + KX_PYMETHOD_VARARGS(KX_GameObject,AlignAxisToVect); KX_PYMETHOD_O(KX_GameObject,GetAxisVect); KX_PYMETHOD_NOARGS(KX_GameObject,SuspendDynamics); KX_PYMETHOD_NOARGS(KX_GameObject,RestoreDynamics); KX_PYMETHOD_NOARGS(KX_GameObject,EnableRigidBody); KX_PYMETHOD_NOARGS(KX_GameObject,DisableRigidBody); - KX_PYMETHOD(KX_GameObject,ApplyImpulse); + KX_PYMETHOD_VARARGS(KX_GameObject,ApplyImpulse); KX_PYMETHOD_O(KX_GameObject,SetCollisionMargin); KX_PYMETHOD_NOARGS(KX_GameObject,GetParent); KX_PYMETHOD_O(KX_GameObject,SetParent); KX_PYMETHOD_NOARGS(KX_GameObject,RemoveParent); KX_PYMETHOD_NOARGS(KX_GameObject,GetChildren); KX_PYMETHOD_NOARGS(KX_GameObject,GetChildrenRecursive); - KX_PYMETHOD(KX_GameObject,GetMesh); + KX_PYMETHOD_VARARGS(KX_GameObject,GetMesh); KX_PYMETHOD_NOARGS(KX_GameObject,GetPhysicsId); KX_PYMETHOD_NOARGS(KX_GameObject,GetPropertyNames); KX_PYMETHOD_NOARGS(KX_GameObject,EndObject); diff --git a/source/gameengine/Ketsji/KX_IPO_SGController.cpp b/source/gameengine/Ketsji/KX_IPO_SGController.cpp index d3aa924665e..6223643f75a 100644 --- a/source/gameengine/Ketsji/KX_IPO_SGController.cpp +++ b/source/gameengine/Ketsji/KX_IPO_SGController.cpp @@ -143,7 +143,7 @@ bool KX_IpoSGController::Update(double currentTime) { if (m_ipo_as_force == true) { - if (m_game_object && ob) + if (m_game_object && ob && m_game_object->GetPhysicsController()) { m_game_object->GetPhysicsController()->ApplyForce(m_ipo_local ? ob->GetWorldOrientation() * m_ipo_xform.GetPosition() : diff --git a/source/gameengine/Ketsji/KX_MaterialIpoController.cpp b/source/gameengine/Ketsji/KX_MaterialIpoController.cpp index 2ce5d469380..85d514bd22f 100644 --- a/source/gameengine/Ketsji/KX_MaterialIpoController.cpp +++ b/source/gameengine/Ketsji/KX_MaterialIpoController.cpp @@ -3,6 +3,8 @@ #include "KX_ScalarInterpolator.h" #include "KX_GameObject.h" +#include "BLO_sys_types.h" // for intptr_t support + #ifdef HAVE_CONFIG_H #include <config.h> #endif @@ -76,10 +78,10 @@ SG_Controller* KX_MaterialIpoController::GetReplica(class SG_Node* destnode) iporeplica->AddInterpolator(copyipo); MT_Scalar* scaal = ((KX_ScalarInterpolator*)*i)->GetTarget(); - long orgbase = (long)this; - long orgloc = (long)scaal; - long offset = orgloc-orgbase; - long newaddrbase = (long)iporeplica + offset; + intptr_t orgbase = (intptr_t)this; + intptr_t orgloc = (intptr_t)scaal; + intptr_t offset = orgloc-orgbase; + intptr_t newaddrbase = (intptr_t)iporeplica + offset; MT_Scalar* blaptr = (MT_Scalar*) newaddrbase; copyipo->SetNewTarget((MT_Scalar*)blaptr); } diff --git a/source/gameengine/Ketsji/KX_MeshProxy.cpp b/source/gameengine/Ketsji/KX_MeshProxy.cpp index a0ac9cfd4ff..29842af7fb6 100644 --- a/source/gameengine/Ketsji/KX_MeshProxy.cpp +++ b/source/gameengine/Ketsji/KX_MeshProxy.cpp @@ -35,6 +35,7 @@ #include "RAS_MeshObject.h" #include "KX_VertexProxy.h" +#include "KX_PolyProxy.h" #include "KX_PolygonMaterial.h" #include "KX_BlenderMaterial.h" @@ -71,10 +72,12 @@ PyParentObject KX_MeshProxy::Parents[] = { PyMethodDef KX_MeshProxy::Methods[] = { {"getNumMaterials", (PyCFunction)KX_MeshProxy::sPyGetNumMaterials,METH_VARARGS}, +{"getNumPolygons", (PyCFunction)KX_MeshProxy::sPyGetNumPolygons,METH_NOARGS}, {"getMaterialName", (PyCFunction)KX_MeshProxy::sPyGetMaterialName,METH_VARARGS}, {"getTextureName", (PyCFunction)KX_MeshProxy::sPyGetTextureName,METH_VARARGS}, {"getVertexArrayLength", (PyCFunction)KX_MeshProxy::sPyGetVertexArrayLength,METH_VARARGS}, {"getVertex", (PyCFunction)KX_MeshProxy::sPyGetVertex,METH_VARARGS}, +{"getPolygon", (PyCFunction)KX_MeshProxy::sPyGetPolygon,METH_VARARGS}, KX_PYMETHODTABLE(KX_MeshProxy, reinstancePhysicsMesh), //{"getIndexArrayLength", (PyCFunction)KX_MeshProxy::sPyGetIndexArrayLength,METH_VARARGS}, @@ -146,6 +149,12 @@ PyObject* KX_MeshProxy::PyGetNumMaterials(PyObject* self, return PyInt_FromLong(num); } +PyObject* KX_MeshProxy::PyGetNumPolygons(PyObject* self) +{ + int num = m_meshobj->NumPolygons(); + return PyInt_FromLong(num); +} + PyObject* KX_MeshProxy::PyGetMaterialName(PyObject* self, PyObject* args, PyObject* kwds) @@ -234,6 +243,28 @@ PyObject* KX_MeshProxy::PyGetVertex(PyObject* self, } +PyObject* KX_MeshProxy::PyGetPolygon(PyObject* self, + PyObject* args, + PyObject* kwds) +{ + int polyindex= 1; + PyObject* polyob = NULL; + + if (!PyArg_ParseTuple(args,"i",&polyindex)) + return NULL; + + RAS_Polygon* polygon = m_meshobj->GetPolygon(polyindex); + if (polygon) + { + polyob = new KX_PolyProxy(m_meshobj, polygon); + } + else + { + PyErr_SetString(PyExc_AttributeError, "Invalid polygon index"); + } + return polyob; +} + KX_PYMETHODDEF_DOC(KX_MeshProxy, reinstancePhysicsMesh, "Reinstance the physics mesh.") { diff --git a/source/gameengine/Ketsji/KX_MeshProxy.h b/source/gameengine/Ketsji/KX_MeshProxy.h index 7c6202c15a4..3335c349673 100644 --- a/source/gameengine/Ketsji/KX_MeshProxy.h +++ b/source/gameengine/Ketsji/KX_MeshProxy.h @@ -57,10 +57,12 @@ public: KX_PYMETHOD(KX_MeshProxy,GetNumMaterials); KX_PYMETHOD(KX_MeshProxy,GetMaterialName); KX_PYMETHOD(KX_MeshProxy,GetTextureName); + KX_PYMETHOD_NOARGS(KX_MeshProxy,GetNumPolygons); // both take materialid (int) KX_PYMETHOD(KX_MeshProxy,GetVertexArrayLength); KX_PYMETHOD(KX_MeshProxy,GetVertex); + KX_PYMETHOD(KX_MeshProxy,GetPolygon); KX_PYMETHOD_DOC(KX_MeshProxy, reinstancePhysicsMesh); }; diff --git a/source/gameengine/Ketsji/KX_MouseFocusSensor.cpp b/source/gameengine/Ketsji/KX_MouseFocusSensor.cpp index db0bef8b7e1..3156f543ed5 100644 --- a/source/gameengine/Ketsji/KX_MouseFocusSensor.cpp +++ b/source/gameengine/Ketsji/KX_MouseFocusSensor.cpp @@ -122,16 +122,10 @@ bool KX_MouseFocusSensor::Evaluate(CValue* event) return result; } -bool KX_MouseFocusSensor::RayHit(KX_ClientObjectInfo* client_info, MT_Point3& hit_point, MT_Vector3& hit_normal, void * const data) +bool KX_MouseFocusSensor::RayHit(KX_ClientObjectInfo* client_info, KX_RayCast* result, void * const data) { KX_GameObject* hitKXObj = client_info->m_gameobject; - if (client_info->m_type > KX_ClientObjectInfo::ACTOR) - { - // false hit - return false; - } - /* Is this me? In the ray test, there are a lot of extra checks * for aliasing artefacts from self-hits. That doesn't happen * here, so a simple test suffices. Or does the camera also get @@ -142,8 +136,8 @@ bool KX_MouseFocusSensor::RayHit(KX_ClientObjectInfo* client_info, MT_Point3& hi if ((m_focusmode == 2) || hitKXObj == thisObj) { m_hitObject = hitKXObj; - m_hitPosition = hit_point; - m_hitNormal = hit_normal; + m_hitPosition = result->m_hitPoint; + m_hitNormal = result->m_hitNormal; return true; } @@ -158,8 +152,6 @@ bool KX_MouseFocusSensor::ParentObjectHasFocus(void) m_hitObject = 0; m_hitPosition = MT_Vector3(0,0,0); m_hitNormal = MT_Vector3(1,0,0); - MT_Point3 resultpoint; - MT_Vector3 resultnormal; /* All screen handling in the gameengine is done by GL, * specifically the model/view and projection parts. The viewport @@ -280,7 +272,8 @@ bool KX_MouseFocusSensor::ParentObjectHasFocus(void) bool result = false; - result = KX_RayCast::RayTest(physics_controller, physics_environment, frompoint3, topoint3, resultpoint, resultnormal, KX_RayCast::Callback<KX_MouseFocusSensor>(this)); + KX_RayCast::Callback<KX_MouseFocusSensor> callback(this,physics_controller); + KX_RayCast::RayTest(physics_environment, frompoint3, topoint3, callback); result = (m_hitObject!=0); diff --git a/source/gameengine/Ketsji/KX_MouseFocusSensor.h b/source/gameengine/Ketsji/KX_MouseFocusSensor.h index b011ebe1288..a6cc39d66eb 100644 --- a/source/gameengine/Ketsji/KX_MouseFocusSensor.h +++ b/source/gameengine/Ketsji/KX_MouseFocusSensor.h @@ -33,6 +33,8 @@ #include "SCA_MouseSensor.h" +class KX_RayCast; + /** * The mouse focus sensor extends the basic SCA_MouseSensor. It has * been placed in KX because it needs access to the rasterizer and @@ -76,7 +78,9 @@ class KX_MouseFocusSensor : public SCA_MouseSensor return result; }; - bool RayHit(KX_ClientObjectInfo* client, MT_Point3& hit_point, MT_Vector3& hit_normal, void * const data); + bool RayHit(KX_ClientObjectInfo* client, KX_RayCast* result, void * const data); + bool NeedRayCast(KX_ClientObjectInfo* client) { return true; } + /* --------------------------------------------------------------------- */ diff --git a/source/gameengine/Ketsji/KX_PolyProxy.cpp b/source/gameengine/Ketsji/KX_PolyProxy.cpp new file mode 100644 index 00000000000..658c8a98e4f --- /dev/null +++ b/source/gameengine/Ketsji/KX_PolyProxy.cpp @@ -0,0 +1,265 @@ +/** + * $Id$ + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "KX_PolyProxy.h" +#include "KX_MeshProxy.h" +#include "RAS_MeshObject.h" +#include "KX_BlenderMaterial.h" +#include "KX_PolygonMaterial.h" + +#include "KX_PyMath.h" + +PyTypeObject KX_PolyProxy::Type = { + PyObject_HEAD_INIT(&PyType_Type) + 0, + "KX_PolyProxy", + sizeof(KX_PolyProxy), + 0, + PyDestructor, + 0, + __getattr, + __setattr, + 0, //&MyPyCompare, + __repr, + 0, //&cvalue_as_number, + 0, + 0, + 0, + 0 +}; + +PyParentObject KX_PolyProxy::Parents[] = { + &KX_PolyProxy::Type, + &SCA_IObject::Type, + &CValue::Type, + NULL +}; + +PyMethodDef KX_PolyProxy::Methods[] = { + KX_PYMETHODTABLE_NOARG(KX_PolyProxy,getMaterialIndex), + KX_PYMETHODTABLE_NOARG(KX_PolyProxy,getNumVertex), + KX_PYMETHODTABLE_NOARG(KX_PolyProxy,isVisible), + KX_PYMETHODTABLE_NOARG(KX_PolyProxy,isCollider), + KX_PYMETHODTABLE_NOARG(KX_PolyProxy,getMaterialName), + KX_PYMETHODTABLE_NOARG(KX_PolyProxy,getTextureName), + KX_PYMETHODTABLE(KX_PolyProxy,getVertexIndex), + KX_PYMETHODTABLE_NOARG(KX_PolyProxy,getMesh), + KX_PYMETHODTABLE_NOARG(KX_PolyProxy,getMaterial), + {NULL,NULL} //Sentinel +}; + +PyObject* +KX_PolyProxy::_getattr(const STR_String& attr) +{ + if (attr == "matname") + { + return PyString_FromString(m_polygon->GetMaterial()->GetPolyMaterial()->GetMaterialName()); + } + if (attr == "texture") + { + return PyString_FromString(m_polygon->GetMaterial()->GetPolyMaterial()->GetTextureName()); + } + if (attr == "material") + { + RAS_IPolyMaterial *polymat = m_polygon->GetMaterial()->GetPolyMaterial(); + if(polymat->GetFlag() & RAS_BLENDERMAT) + { + KX_BlenderMaterial* mat = static_cast<KX_BlenderMaterial*>(polymat); + Py_INCREF(mat); + return mat; + } + else + { + KX_PolygonMaterial* mat = static_cast<KX_PolygonMaterial*>(polymat); + Py_INCREF(mat); + return mat; + } + } + if (attr == "matid") + { + // we'll have to scan through the material bucket of the mes and compare with + // the one of the polygon + RAS_MaterialBucket* polyBucket = m_polygon->GetMaterial(); + unsigned int matid; + for (matid=0; matid<m_mesh->NumMaterials(); matid++) + { + RAS_MaterialBucket* meshBucket = m_mesh->GetMaterialBucket(matid); + if (meshBucket == polyBucket) + // found it + break; + } + return PyInt_FromLong(matid); + } + if (attr == "v1") + { + return PyInt_FromLong(m_polygon->GetVertexIndexBase().m_indexarray[0]); + } + if (attr == "v2") + { + return PyInt_FromLong(m_polygon->GetVertexIndexBase().m_indexarray[1]); + } + if (attr == "v3") + { + return PyInt_FromLong(m_polygon->GetVertexIndexBase().m_indexarray[2]); + } + if (attr == "v4") + { + return PyInt_FromLong(((m_polygon->VertexCount()>3)?m_polygon->GetVertexIndexBase().m_indexarray[3]:0)); + } + if (attr == "visible") + { + return PyInt_FromLong(m_polygon->IsVisible()); + } + if (attr == "collide") + { + return PyInt_FromLong(m_polygon->IsCollider()); + } + _getattr_up(SCA_IObject); +} + +KX_PolyProxy::KX_PolyProxy(const RAS_MeshObject*mesh, RAS_Polygon* polygon) +: m_mesh((RAS_MeshObject*)mesh), + m_polygon(polygon) +{ +} + +KX_PolyProxy::~KX_PolyProxy() +{ +} + + +// stuff for cvalue related things +CValue* KX_PolyProxy::Calc(VALUE_OPERATOR, CValue *) { return NULL;} +CValue* KX_PolyProxy::CalcFinal(VALUE_DATA_TYPE, VALUE_OPERATOR, CValue *) { return NULL;} +STR_String sPolyName="polygone"; +const STR_String & KX_PolyProxy::GetText() {return sPolyName;}; +float KX_PolyProxy::GetNumber() { return -1;} +STR_String KX_PolyProxy::GetName() { return sPolyName;} +void KX_PolyProxy::SetName(STR_String) { }; +CValue* KX_PolyProxy::GetReplica() { return NULL;} +void KX_PolyProxy::ReplicaSetName(STR_String) {}; + + +// stuff for python integration + +KX_PYMETHODDEF_DOC_NOARG(KX_PolyProxy, getMaterialIndex, +"getMaterialIndex() : return the material index of the polygon in the mesh\n") +{ + RAS_MaterialBucket* polyBucket = m_polygon->GetMaterial(); + unsigned int matid; + for (matid=0; matid<m_mesh->NumMaterials(); matid++) + { + RAS_MaterialBucket* meshBucket = m_mesh->GetMaterialBucket(matid); + if (meshBucket == polyBucket) + // found it + break; + } + return PyInt_FromLong(matid); +} + +KX_PYMETHODDEF_DOC_NOARG(KX_PolyProxy, getNumVertex, +"getNumVertex() : returns the number of vertex of the polygon, 3 or 4\n") +{ + return PyInt_FromLong(m_polygon->VertexCount()); +} + +KX_PYMETHODDEF_DOC_NOARG(KX_PolyProxy, isVisible, +"isVisible() : returns whether the polygon is visible or not\n") +{ + return PyInt_FromLong(m_polygon->IsVisible()); +} + +KX_PYMETHODDEF_DOC_NOARG(KX_PolyProxy, isCollider, +"isCollider() : returns whether the polygon is receives collision or not\n") +{ + return PyInt_FromLong(m_polygon->IsCollider()); +} + +KX_PYMETHODDEF_DOC_NOARG(KX_PolyProxy, getMaterialName, +"getMaterialName() : returns the polygon material name, \"NoMaterial\" if no material\n") +{ + return PyString_FromString(m_polygon->GetMaterial()->GetPolyMaterial()->GetMaterialName()); +} + +KX_PYMETHODDEF_DOC_NOARG(KX_PolyProxy, getTextureName, +"getTexturelName() : returns the polygon texture name, \"NULL\" if no texture\n") +{ + return PyString_FromString(m_polygon->GetMaterial()->GetPolyMaterial()->GetTextureName()); +} + +KX_PYMETHODDEF_DOC(KX_PolyProxy, getVertexIndex, +"getVertexIndex(vertex) : returns the mesh vertex index of a polygon vertex\n" +"vertex: index of the vertex in the polygon: 0->3\n" +"return value can be used to retrieve the vertex details through mesh proxy\n" +"Note: getVertexIndex(3) on a triangle polygon returns 0\n") +{ + int index; + if (!PyArg_ParseTuple(args,"i",&index)) + { + return NULL; + } + if (index < 0 || index > 3) + { + PyErr_SetString(PyExc_AttributeError, "Valid range for index is 0-3"); + return NULL; + } + if (index < m_polygon->VertexCount()) + { + return PyInt_FromLong(m_polygon->GetVertexIndexBase().m_indexarray[index]); + } + return PyInt_FromLong(0); +} + +KX_PYMETHODDEF_DOC_NOARG(KX_PolyProxy, getMesh, +"getMesh() : returns a mesh proxy\n") +{ + KX_MeshProxy* meshproxy = new KX_MeshProxy((RAS_MeshObject*)m_mesh); + return meshproxy; +} + +KX_PYMETHODDEF_DOC_NOARG(KX_PolyProxy, getMaterial, +"getMaterial() : returns a material\n") +{ + RAS_IPolyMaterial *polymat = m_polygon->GetMaterial()->GetPolyMaterial(); + if(polymat->GetFlag() & RAS_BLENDERMAT) + { + KX_BlenderMaterial* mat = static_cast<KX_BlenderMaterial*>(polymat); + Py_INCREF(mat); + return mat; + } + else + { + KX_PolygonMaterial* mat = static_cast<KX_PolygonMaterial*>(polymat); + Py_INCREF(mat); + return mat; + } +} diff --git a/source/gameengine/Ketsji/KX_PolyProxy.h b/source/gameengine/Ketsji/KX_PolyProxy.h new file mode 100644 index 00000000000..506e2c2a656 --- /dev/null +++ b/source/gameengine/Ketsji/KX_PolyProxy.h @@ -0,0 +1,71 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ +#ifndef __KX_POLYROXY +#define __KX_POLYPROXY + +#include "SCA_IObject.h" + +class KX_PolyProxy : public SCA_IObject +{ + Py_Header; +protected: + class RAS_Polygon* m_polygon; + class RAS_MeshObject* m_mesh; +public: + KX_PolyProxy(const class RAS_MeshObject*mesh, class RAS_Polygon* polygon); + virtual ~KX_PolyProxy(); + + // stuff for cvalue related things + CValue* Calc(VALUE_OPERATOR op, CValue *val) ; + CValue* CalcFinal(VALUE_DATA_TYPE dtype, VALUE_OPERATOR op, CValue *val); + const STR_String & GetText(); + float GetNumber(); + STR_String GetName(); + void SetName(STR_String name); // Set the name of the value + void ReplicaSetName(STR_String name); + CValue* GetReplica(); + + +// stuff for python integration + virtual PyObject* _getattr(const STR_String& attr); + + KX_PYMETHOD_DOC_NOARGS(KX_PolyProxy,getMaterialIndex) + KX_PYMETHOD_DOC_NOARGS(KX_PolyProxy,getNumVertex) + KX_PYMETHOD_DOC_NOARGS(KX_PolyProxy,isVisible) + KX_PYMETHOD_DOC_NOARGS(KX_PolyProxy,isCollider) + KX_PYMETHOD_DOC_NOARGS(KX_PolyProxy,getMaterialName) + KX_PYMETHOD_DOC_NOARGS(KX_PolyProxy,getTextureName) + KX_PYMETHOD_DOC(KX_PolyProxy,getVertexIndex) + KX_PYMETHOD_DOC_NOARGS(KX_PolyProxy,getMesh) + KX_PYMETHOD_DOC_NOARGS(KX_PolyProxy,getMaterial) + +}; + +#endif //__KX_POLYPROXY + diff --git a/source/gameengine/Ketsji/KX_PythonInit.cpp b/source/gameengine/Ketsji/KX_PythonInit.cpp index 868439546c3..e9fb0278d76 100644 --- a/source/gameengine/Ketsji/KX_PythonInit.cpp +++ b/source/gameengine/Ketsji/KX_PythonInit.cpp @@ -30,7 +30,13 @@ #include "GL/glew.h" +// directory header for py function getBlendFileList #include <stdlib.h> +#ifndef WIN32 + #include <dirent.h> +#else + #include "BLI_winstuff.h" +#endif #ifdef WIN32 #pragma warning (disable : 4786) @@ -112,9 +118,7 @@ static PyObject* gPyGetRandomFloat(PyObject*) return PyFloat_FromDouble(MT_random()); } -static PyObject* gPySetGravity(PyObject*, - PyObject* args, - PyObject*) +static PyObject* gPySetGravity(PyObject*, PyObject* args) { MT_Vector3 vec = MT_Vector3(0., 0., 0.); if (PyVecArgTo(args, vec)) @@ -138,9 +142,7 @@ file to make a full path name (doesn't change during the game, even if you load\ other .blend).\n\ The function also converts the directory separator to the local file system format."; -static PyObject* gPyExpandPath(PyObject*, - PyObject* args, - PyObject*) +static PyObject* gPyExpandPath(PyObject*, PyObject* args) { char expanded[FILE_MAXDIR + FILE_MAXFILE]; char* filename; @@ -185,9 +187,7 @@ static PyObject* gPyGetSpectrum(PyObject*) -static PyObject* gPyStartDSP(PyObject*, - PyObject* args, - PyObject*) +static PyObject* gPyStartDSP(PyObject*, PyObject* args) { SND_IAudioDevice* audiodevice = SND_DeviceManager::Instance(); @@ -205,9 +205,7 @@ static PyObject* gPyStartDSP(PyObject*, -static PyObject* gPyStopDSP(PyObject*, - PyObject* args, - PyObject*) +static PyObject* gPyStopDSP(PyObject*, PyObject* args) { SND_IAudioDevice* audiodevice = SND_DeviceManager::Instance(); @@ -223,9 +221,7 @@ static PyObject* gPyStopDSP(PyObject*, return NULL; } -static PyObject* gPySetLogicTicRate(PyObject*, - PyObject* args, - PyObject*) +static PyObject* gPySetLogicTicRate(PyObject*, PyObject* args) { float ticrate; if (PyArg_ParseTuple(args, "f", &ticrate)) @@ -242,9 +238,7 @@ static PyObject* gPyGetLogicTicRate(PyObject*) return PyFloat_FromDouble(KX_KetsjiEngine::GetTicRate()); } -static PyObject* gPySetPhysicsTicRate(PyObject*, - PyObject* args, - PyObject*) +static PyObject* gPySetPhysicsTicRate(PyObject*, PyObject* args) { float ticrate; if (PyArg_ParseTuple(args, "f", &ticrate)) @@ -257,9 +251,7 @@ static PyObject* gPySetPhysicsTicRate(PyObject*, return NULL; } -static PyObject* gPySetPhysicsDebug(PyObject*, - PyObject* args, - PyObject*) +static PyObject* gPySetPhysicsDebug(PyObject*, PyObject* args) { int debugMode; if (PyArg_ParseTuple(args, "i", &debugMode)) @@ -278,6 +270,44 @@ static PyObject* gPyGetPhysicsTicRate(PyObject*) return PyFloat_FromDouble(PHY_GetActiveEnvironment()->getFixedTimeStep()); } +static PyObject* gPyGetBlendFileList(PyObject*, PyObject* args) +{ + char cpath[sizeof(G.sce)]; + char *searchpath = NULL; + PyObject* list; + + DIR *dp; + struct dirent *dirp; + + if (!PyArg_ParseTuple(args, "|s", &searchpath)) + return NULL; + + list = PyList_New(0); + + if (searchpath) { + BLI_strncpy(cpath, searchpath, FILE_MAXDIR + FILE_MAXFILE); + BLI_convertstringcode(cpath, G.sce); + } else { + /* Get the dir only */ + BLI_split_dirfile_basic(G.sce, cpath, NULL); + } + + if((dp = opendir(cpath)) == NULL) { + /* todo, show the errno, this shouldnt happen anyway if the blendfile is readable */ + fprintf(stderr, "Could not read directoty () failed, code %d (%s)\n", cpath, errno, strerror(errno)); + return list; + } + + while ((dirp = readdir(dp)) != NULL) { + if (BLI_testextensie(dirp->d_name, ".blend")) { + PyList_Append(list, PyString_FromString(dirp->d_name)); + } + } + + closedir(dp); + return list; +} + static STR_String gPyGetCurrentScene_doc = "getCurrentScene()\n" "Gets a reference to the current scene.\n"; @@ -377,14 +407,13 @@ static struct PyMethodDef game_methods[] = { {"setLogicTicRate", (PyCFunction) gPySetLogicTicRate, METH_VARARGS, "Sets the logic tic rate"}, {"getPhysicsTicRate", (PyCFunction) gPyGetPhysicsTicRate, METH_NOARGS, "Gets the physics tic rate"}, {"setPhysicsTicRate", (PyCFunction) gPySetPhysicsTicRate, METH_VARARGS, "Sets the physics tic rate"}, + {"getBlendFileList", (PyCFunction)gPyGetBlendFileList, METH_VARARGS, "Gets a list of blend files in the same directory as the current blend file"}, {"PrintGLInfo", (PyCFunction)pyPrintExt, METH_NOARGS, "Prints GL Extension Info"}, {NULL, (PyCFunction) NULL, 0, NULL } }; -static PyObject* gPyGetWindowHeight(PyObject*, - PyObject* args, - PyObject*) +static PyObject* gPyGetWindowHeight(PyObject*, PyObject* args) { int height = (gp_Canvas ? gp_Canvas->GetHeight() : 0); @@ -394,9 +423,7 @@ static PyObject* gPyGetWindowHeight(PyObject*, -static PyObject* gPyGetWindowWidth(PyObject*, - PyObject* args, - PyObject*) +static PyObject* gPyGetWindowWidth(PyObject*, PyObject* args) { @@ -411,9 +438,7 @@ static PyObject* gPyGetWindowWidth(PyObject*, // temporarility visibility thing, will be moved to rasterizer/renderer later bool gUseVisibilityTemp = false; -static PyObject* gPyEnableVisibility(PyObject*, - PyObject* args, - PyObject*) +static PyObject* gPyEnableVisibility(PyObject*, PyObject* args) { int visible; if (PyArg_ParseTuple(args,"i",&visible)) @@ -429,9 +454,7 @@ static PyObject* gPyEnableVisibility(PyObject*, -static PyObject* gPyShowMouse(PyObject*, - PyObject* args, - PyObject*) +static PyObject* gPyShowMouse(PyObject*, PyObject* args) { int visible; if (PyArg_ParseTuple(args,"i",&visible)) @@ -455,9 +478,7 @@ static PyObject* gPyShowMouse(PyObject*, -static PyObject* gPySetMousePosition(PyObject*, - PyObject* args, - PyObject*) +static PyObject* gPySetMousePosition(PyObject*, PyObject* args) { int x,y; if (PyArg_ParseTuple(args,"ii",&x,&y)) @@ -472,9 +493,7 @@ static PyObject* gPySetMousePosition(PyObject*, Py_Return; } -static PyObject* gPySetEyeSeparation(PyObject*, - PyObject* args, - PyObject*) +static PyObject* gPySetEyeSeparation(PyObject*, PyObject* args) { float sep; if (PyArg_ParseTuple(args, "f", &sep)) @@ -496,9 +515,7 @@ static PyObject* gPyGetEyeSeparation(PyObject*, PyObject*, PyObject*) return NULL; } -static PyObject* gPySetFocalLength(PyObject*, - PyObject* args, - PyObject*) +static PyObject* gPySetFocalLength(PyObject*, PyObject* args) { float focus; if (PyArg_ParseTuple(args, "f", &focus)) @@ -518,9 +535,7 @@ static PyObject* gPyGetFocalLength(PyObject*, PyObject*, PyObject*) return NULL; } -static PyObject* gPySetBackgroundColor(PyObject*, - PyObject* args, - PyObject*) +static PyObject* gPySetBackgroundColor(PyObject*, PyObject* args) { MT_Vector4 vec = MT_Vector4(0., 0., 0.3, 0.); @@ -538,9 +553,7 @@ static PyObject* gPySetBackgroundColor(PyObject*, -static PyObject* gPySetMistColor(PyObject*, - PyObject* args, - PyObject*) +static PyObject* gPySetMistColor(PyObject*, PyObject* args) { MT_Vector3 vec = MT_Vector3(0., 0., 0.); @@ -558,9 +571,7 @@ static PyObject* gPySetMistColor(PyObject*, -static PyObject* gPySetMistStart(PyObject*, - PyObject* args, - PyObject*) +static PyObject* gPySetMistStart(PyObject*, PyObject* args) { float miststart; @@ -579,9 +590,7 @@ static PyObject* gPySetMistStart(PyObject*, -static PyObject* gPySetMistEnd(PyObject*, - PyObject* args, - PyObject*) +static PyObject* gPySetMistEnd(PyObject*, PyObject* args) { float mistend; @@ -599,9 +608,7 @@ static PyObject* gPySetMistEnd(PyObject*, } -static PyObject* gPySetAmbientColor(PyObject*, - PyObject* args, - PyObject*) +static PyObject* gPySetAmbientColor(PyObject*, PyObject* args) { MT_Vector3 vec = MT_Vector3(0., 0., 0.); @@ -620,9 +627,7 @@ static PyObject* gPySetAmbientColor(PyObject*, -static PyObject* gPyMakeScreenshot(PyObject*, - PyObject* args, - PyObject*) +static PyObject* gPyMakeScreenshot(PyObject*, PyObject* args) { char* filename; if (PyArg_ParseTuple(args,"s",&filename)) @@ -638,9 +643,7 @@ static PyObject* gPyMakeScreenshot(PyObject*, Py_Return; } -static PyObject* gPyEnableMotionBlur(PyObject*, - PyObject* args, - PyObject*) +static PyObject* gPyEnableMotionBlur(PyObject*, PyObject* args) { float motionblurvalue; if (PyArg_ParseTuple(args,"f",&motionblurvalue)) @@ -656,9 +659,7 @@ static PyObject* gPyEnableMotionBlur(PyObject*, Py_Return; } -static PyObject* gPyDisableMotionBlur(PyObject*, - PyObject* args, - PyObject*) +static PyObject* gPyDisableMotionBlur(PyObject*, PyObject* args) { if(gp_Rasterizer) { @@ -733,6 +734,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); @@ -847,13 +852,30 @@ PyObject* initGameLogic(KX_Scene* scene) // quick hack to get gravity hook // override builtin functions import() and open() -PyObject *KXpy_open(PyObject *self, PyObject *args) -{ +PyObject *KXpy_open(PyObject *self, PyObject *args) { PyErr_SetString(PyExc_RuntimeError, "Sandbox: open() function disabled!\nGame Scripts should not use this function."); return NULL; } +PyObject *KXpy_reload(PyObject *self, PyObject *args) { + PyErr_SetString(PyExc_RuntimeError, "Sandbox: reload() function disabled!\nGame Scripts should not use this function."); + return NULL; +} + +PyObject *KXpy_file(PyObject *self, PyObject *args) { + PyErr_SetString(PyExc_RuntimeError, "Sandbox: file() function disabled!\nGame Scripts should not use this function."); + return NULL; +} + +PyObject *KXpy_execfile(PyObject *self, PyObject *args) { + PyErr_SetString(PyExc_RuntimeError, "Sandbox: execfile() function disabled!\nGame Scripts should not use this function."); + return NULL; +} +PyObject *KXpy_compile(PyObject *self, PyObject *args) { + PyErr_SetString(PyExc_RuntimeError, "Sandbox: compile() function disabled!\nGame Scripts should not use this function."); + return NULL; +} PyObject *KXpy_import(PyObject *self, PyObject *args) { @@ -890,19 +912,13 @@ PyObject *KXpy_import(PyObject *self, PyObject *args) } +static PyMethodDef meth_open[] = {{ "open", KXpy_open, METH_VARARGS, "(disabled)"}}; +static PyMethodDef meth_reload[] = {{ "reload", KXpy_reload, METH_VARARGS, "(disabled)"}}; +static PyMethodDef meth_file[] = {{ "file", KXpy_file, METH_VARARGS, "(disabled)"}}; +static PyMethodDef meth_execfile[] = {{ "execfile", KXpy_execfile, METH_VARARGS, "(disabled)"}}; +static PyMethodDef meth_compile[] = {{ "compile", KXpy_compile, METH_VARARGS, "(disabled)"}}; -static PyMethodDef meth_open[] = { - { "open", KXpy_open, METH_VARARGS, - "(disabled)"} -}; - - -static PyMethodDef meth_import[] = { - { "import", KXpy_import, METH_VARARGS, - "our own import"} -}; - - +static PyMethodDef meth_import[] = {{ "import", KXpy_import, METH_VARARGS, "our own import"}}; //static PyObject *g_oldopen = 0; //static PyObject *g_oldimport = 0; @@ -913,15 +929,21 @@ void setSandbox(TPythonSecurityLevel level) { PyObject *m = PyImport_AddModule("__builtin__"); PyObject *d = PyModule_GetDict(m); - PyObject *meth = PyCFunction_New(meth_open, NULL); switch (level) { case psl_Highest: //if (!g_security) { //g_oldopen = PyDict_GetItemString(d, "open"); - PyDict_SetItemString(d, "open", meth); - meth = PyCFunction_New(meth_import, NULL); - PyDict_SetItemString(d, "__import__", meth); + + // functions we cant trust + PyDict_SetItemString(d, "open", PyCFunction_New(meth_open, NULL)); + PyDict_SetItemString(d, "reload", PyCFunction_New(meth_reload, NULL)); + PyDict_SetItemString(d, "file", PyCFunction_New(meth_file, NULL)); + PyDict_SetItemString(d, "execfile", PyCFunction_New(meth_execfile, NULL)); + PyDict_SetItemString(d, "compile", PyCFunction_New(meth_compile, NULL)); + + // our own import + PyDict_SetItemString(d, "__import__", PyCFunction_New(meth_import, NULL)); //g_security = level; //} break; @@ -1026,9 +1048,38 @@ static char GameKeys_module_documentation[] = "This modules provides defines for key-codes" ; +static char gPyEventToString_doc[] = +"Take a valid event from the GameKeys module or Keyboard Sensor and return a name" +; +static PyObject* gPyEventToString(PyObject*, PyObject* value) +{ + PyObject* mod, *dict, *key, *val, *ret = NULL; + Py_ssize_t pos = 0; + + mod = PyImport_ImportModule( "GameKeys" ); + if (!mod) + return NULL; + + dict = PyModule_GetDict(mod); + + while (PyDict_Next(dict, &pos, &key, &val)) { + if (PyObject_Compare(value, val)==0) { + ret = key; + break; + } + } + + PyErr_Clear(); // incase there was an error clearing + Py_DECREF(mod); + if (!ret) PyErr_SetString(PyExc_ValueError, "expected a valid int keyboard event"); + else Py_INCREF(ret); + + return ret; +} static struct PyMethodDef gamekeys_methods[] = { + {"EventToString", (PyCFunction)gPyEventToString, METH_O, gPyEventToString_doc}, { NULL, (PyCFunction) NULL, 0, NULL } }; diff --git a/source/gameengine/Ketsji/KX_RayCast.cpp b/source/gameengine/Ketsji/KX_RayCast.cpp index 89e2d645d54..974d4b992a6 100644 --- a/source/gameengine/Ketsji/KX_RayCast.cpp +++ b/source/gameengine/Ketsji/KX_RayCast.cpp @@ -40,7 +40,21 @@ #include "PHY_IPhysicsEnvironment.h" #include "PHY_IPhysicsController.h" -bool KX_RayCast::RayTest(KX_IPhysicsController* ignore_controller, PHY_IPhysicsEnvironment* physics_environment, const MT_Point3& _frompoint, const MT_Point3& topoint, MT_Point3& result_point, MT_Vector3& result_normal, const KX_RayCast& callback) +KX_RayCast::KX_RayCast(KX_IPhysicsController* ignoreController, bool faceNormal) + :PHY_IRayCastFilterCallback(dynamic_cast<PHY_IPhysicsController*>(ignoreController), faceNormal) +{ +} + +void KX_RayCast::reportHit(PHY_RayCastResult* result) +{ + m_hitFound = true; + m_hitPoint.setValue((const float*)result->m_hitPoint); + m_hitNormal.setValue((const float*)result->m_hitNormal); + m_hitMesh = result->m_meshObject; + m_hitPolygon = result->m_polygon; +} + +bool KX_RayCast::RayTest(PHY_IPhysicsEnvironment* physics_environment, const MT_Point3& _frompoint, const MT_Point3& topoint, KX_RayCast& callback) { // Loops over all physics objects between frompoint and topoint, // calling callback.RayHit for each one. @@ -50,58 +64,51 @@ bool KX_RayCast::RayTest(KX_IPhysicsController* ignore_controller, PHY_IPhysicsE // returns true if an object was found, false if not. MT_Point3 frompoint(_frompoint); const MT_Vector3 todir( (topoint - frompoint).safe_normalized() ); + MT_Point3 prevpoint(_frompoint+todir*(-1.f)); PHY_IPhysicsController* hit_controller; - PHY__Vector3 phy_pos; - PHY__Vector3 phy_normal; - while((hit_controller = physics_environment->rayTest(dynamic_cast<PHY_IPhysicsController*>(ignore_controller), + while((hit_controller = physics_environment->rayTest(callback, frompoint.x(),frompoint.y(),frompoint.z(), - topoint.x(),topoint.y(),topoint.z(), - phy_pos[0],phy_pos[1],phy_pos[2], - phy_normal[0],phy_normal[1],phy_normal[2]))) + topoint.x(),topoint.y(),topoint.z())) != NULL) { - result_point = MT_Point3(phy_pos); - result_normal = MT_Vector3(phy_normal); KX_ClientObjectInfo* info = static_cast<KX_ClientObjectInfo*>(hit_controller->getNewClientInfo()); if (!info) { printf("no info!\n"); MT_assert(info && "Physics controller with no client object info"); - return false; + break; } - if (callback.RayHit(info, result_point, result_normal)) - return true; - - // There is a bug in the code below: the delta is computed with the wrong - // sign on the face opposite to the center, resulting in infinite looping. - // In Blender 2.45 this code was never executed because callback.RayHit() always - // returned true, causing the ray sensor to stop on the first object. - // To avoid changing the behaviour will simply return false here. - // It should be discussed if we want the ray sensor to "see" through objects - // that don't have the required property/material (condition to get here) - return false; - - // skip past the object and keep tracing - /* We add 0.01 of fudge, so that if the margin && radius == 0., we don't endless loop. */ - MT_Scalar marg = 0.01 + hit_controller->GetMargin(); - marg += 2.f * hit_controller->GetMargin(); + // The biggest danger to to endless loop, prevent this by checking that the + // hit point always progresses along the ray direction.. + prevpoint -= callback.m_hitPoint; + if (prevpoint.length2() < MT_EPSILON) + break; + + if (callback.RayHit(info)) + // caller may decide to stop the loop and still cancel the hit + return callback.m_hitFound; + + // Skip past the object and keep tracing. + // Note that retrieving in a single shot multiple hit points would be possible + // but it would require some change in Bullet. + prevpoint = callback.m_hitPoint; + /* We add 0.001 of fudge, so that if the margin && radius == 0., we don't endless loop. */ + MT_Scalar marg = 0.001 + hit_controller->GetMargin(); + marg *= 2.f; /* Calculate the other side of this object */ - PHY__Vector3 hitpos; - hit_controller->getPosition(hitpos); - MT_Point3 hitObjPos(hitpos); - - MT_Vector3 hitvector = hitObjPos - result_point; - if (hitvector.dot(hitvector) > MT_EPSILON) - { - hitvector.normalize(); - marg *= 2.*todir.dot(hitvector); - } - frompoint = result_point + marg * todir; + MT_Scalar h = MT_abs(todir.dot(callback.m_hitNormal)); + if (h <= 0.01) + // the normal is almost orthogonal to the ray direction, cannot compute the other side + break; + marg /= h; + frompoint = callback.m_hitPoint + marg * todir; + // verify that we are not passed the to point + if ((topoint - frompoint).dot(todir) < 0.f) + break; } - - return hit_controller; + return false; } diff --git a/source/gameengine/Ketsji/KX_RayCast.h b/source/gameengine/Ketsji/KX_RayCast.h index 607dabd8afc..c3084c997a1 100644 --- a/source/gameengine/Ketsji/KX_RayCast.h +++ b/source/gameengine/Ketsji/KX_RayCast.h @@ -30,12 +30,14 @@ #ifndef __KX_RAYCAST_H__ #define __KX_RAYCAST_H__ -class MT_Point3; -class MT_Vector3; -class KX_IPhysicsController; -class PHY_IPhysicsEnvironment; +#include "PHY_IPhysicsEnvironment.h" +#include "PHY_IPhysicsController.h" +#include "MT_Point3.h" +#include "MT_Vector3.h" +class RAS_MeshObject; struct KX_ClientObjectInfo; +class KX_IPhysicsController; /** * Defines a function for doing a ray cast. @@ -49,17 +51,27 @@ struct KX_ClientObjectInfo; * * Returns true if a client was accepted, false if nothing found. */ -class KX_RayCast +class KX_RayCast : public PHY_IRayCastFilterCallback { -protected: - KX_RayCast() {}; public: + bool m_hitFound; + MT_Point3 m_hitPoint; + MT_Vector3 m_hitNormal; + const RAS_MeshObject* m_hitMesh; + int m_hitPolygon; + + KX_RayCast(KX_IPhysicsController* ignoreController, bool faceNormal); virtual ~KX_RayCast() {} + /** + * The physic environment returns the ray casting result through this function + */ + virtual void reportHit(PHY_RayCastResult* result); + /** ray test callback. * either override this in your class, or use a callback wrapper. */ - virtual bool RayHit(KX_ClientObjectInfo* client, MT_Point3& hit_point, MT_Vector3& hit_normal) const = 0; + virtual bool RayHit(KX_ClientObjectInfo* client) = 0; /** * Callback wrapper. @@ -71,13 +83,11 @@ public: /// Public interface. /// Implement bool RayHit in your class to receive ray callbacks. - static bool RayTest(KX_IPhysicsController* physics_controller, + static bool RayTest( PHY_IPhysicsEnvironment* physics_environment, - const MT_Point3& _frompoint, + const MT_Point3& frompoint, const MT_Point3& topoint, - MT_Point3& result_point, - MT_Vector3& result_normal, - const KX_RayCast& callback); + KX_RayCast& callback); }; @@ -86,18 +96,32 @@ template<class T> class KX_RayCast::Callback : public KX_RayCast T *self; void *data; public: - Callback(T *_self, void *_data = NULL) - : self(_self), + Callback(T *_self, KX_IPhysicsController* controller=NULL, void *_data = NULL, bool faceNormal=false) + : KX_RayCast(controller, faceNormal), + self(_self), data(_data) { } ~Callback() {} - - virtual bool RayHit(KX_ClientObjectInfo* client, MT_Point3& hit_point, MT_Vector3& hit_normal) const + + virtual bool RayHit(KX_ClientObjectInfo* client) { - return self->RayHit(client, hit_point, hit_normal, data); + return self->RayHit(client, this, data); } + + virtual bool needBroadphaseRayCast(PHY_IPhysicsController* controller) + { + KX_ClientObjectInfo* info = static_cast<KX_ClientObjectInfo*>(controller->getNewClientInfo()); + + if (!info) + { + MT_assert(info && "Physics controller with no client object info"); + return false; + } + return self->NeedRayCast(info); + } + }; diff --git a/source/gameengine/Ketsji/KX_RaySensor.cpp b/source/gameengine/Ketsji/KX_RaySensor.cpp index a416c8c9f89..8dc22fe13c1 100644 --- a/source/gameengine/Ketsji/KX_RaySensor.cpp +++ b/source/gameengine/Ketsji/KX_RaySensor.cpp @@ -51,6 +51,7 @@ KX_RaySensor::KX_RaySensor(class SCA_EventManager* eventmgr, SCA_IObject* gameobj, const STR_String& propname, bool bFindMaterial, + bool bXRay, double distance, int axis, KX_Scene* ketsjiScene, @@ -58,6 +59,7 @@ KX_RaySensor::KX_RaySensor(class SCA_EventManager* eventmgr, : SCA_ISensor(gameobj,eventmgr, T), m_propertyname(propname), m_bFindMaterial(bFindMaterial), + m_bXRay(bXRay), m_distance(distance), m_scene(ketsjiScene), m_axis(axis) @@ -104,16 +106,10 @@ bool KX_RaySensor::IsPositiveTrigger() return result; } -bool KX_RaySensor::RayHit(KX_ClientObjectInfo* client, MT_Point3& hit_point, MT_Vector3& hit_normal, void * const data) +bool KX_RaySensor::RayHit(KX_ClientObjectInfo* client, KX_RayCast* result, void * const data) { KX_GameObject* hitKXObj = client->m_gameobject; - - if (client->m_type > KX_ClientObjectInfo::ACTOR) - { - // false hit - return false; - } bool bFound = false; if (m_propertyname.Length() == 0) @@ -139,16 +135,43 @@ bool KX_RaySensor::RayHit(KX_ClientObjectInfo* client, MT_Point3& hit_point, MT_ { m_rayHit = true; m_hitObject = hitKXObj; - m_hitPosition = hit_point; - m_hitNormal = hit_normal; + m_hitPosition = result->m_hitPoint; + m_hitNormal = result->m_hitNormal; } - - return bFound; - + // no multi-hit search yet + return true; } - +/* this function is used to pre-filter the object before casting the ray on them. + This is useful for "X-Ray" option when we want to see "through" unwanted object. + */ +bool KX_RaySensor::NeedRayCast(KX_ClientObjectInfo* client) +{ + if (client->m_type > KX_ClientObjectInfo::ACTOR) + { + // Unknown type of object, skip it. + // Should not occur as the sensor objects are filtered in RayTest() + printf("Invalid client type %d found ray casting\n", client->m_type); + return false; + } + if (m_bXRay && m_propertyname.Length() != 0) + { + if (m_bFindMaterial) + { + // not quite correct: an object may have multiple material + // should check all the material and not only the first one + if (!client->m_auxilary_info || (m_propertyname != ((char*)client->m_auxilary_info))) + return false; + } + else + { + if (client->m_gameobject->GetProperty(m_propertyname) == NULL) + return false; + } + } + return true; +} bool KX_RaySensor::Evaluate(CValue* event) { @@ -215,8 +238,6 @@ bool KX_RaySensor::Evaluate(CValue* event) m_rayDirection = todir; MT_Point3 topoint = frompoint + (m_distance) * todir; - MT_Point3 resultpoint; - MT_Vector3 resultnormal; PHY_IPhysicsEnvironment* pe = m_scene->GetPhysicsEnvironment(); if (!pe) @@ -238,7 +259,8 @@ bool KX_RaySensor::Evaluate(CValue* event) PHY_IPhysicsEnvironment* physics_environment = this->m_scene->GetPhysicsEnvironment(); - result = KX_RayCast::RayTest(spc, physics_environment, frompoint, topoint, resultpoint, resultnormal, KX_RayCast::Callback<KX_RaySensor>(this)); + KX_RayCast::Callback<KX_RaySensor> callback(this, spc); + KX_RayCast::RayTest(physics_environment, frompoint, topoint, callback); /* now pass this result to some controller */ @@ -265,6 +287,10 @@ bool KX_RaySensor::Evaluate(CValue* event) // notify logicsystem that ray JUST left the Object result = true; } + else + { + result = false; + } } if (reset) diff --git a/source/gameengine/Ketsji/KX_RaySensor.h b/source/gameengine/Ketsji/KX_RaySensor.h index f4305b053d1..02a755fedc1 100644 --- a/source/gameengine/Ketsji/KX_RaySensor.h +++ b/source/gameengine/Ketsji/KX_RaySensor.h @@ -36,12 +36,14 @@ #include "MT_Point3.h" struct KX_ClientObjectInfo; +class KX_RayCast; class KX_RaySensor : public SCA_ISensor { Py_Header; STR_String m_propertyname; bool m_bFindMaterial; + bool m_bXRay; double m_distance; class KX_Scene* m_scene; bool m_bTriggered; @@ -56,7 +58,8 @@ public: KX_RaySensor(class SCA_EventManager* eventmgr, SCA_IObject* gameobj, const STR_String& propname, - bool fFindMaterial, + bool bFindMaterial, + bool bXRay, double distance, int axis, class KX_Scene* ketsjiScene, @@ -68,7 +71,8 @@ public: virtual bool IsPositiveTrigger(); virtual void Init(); - bool RayHit(KX_ClientObjectInfo* client, MT_Point3& hit_point, MT_Vector3& hit_normal, void * const data); + bool RayHit(KX_ClientObjectInfo* client, KX_RayCast* result, void * const data); + bool NeedRayCast(KX_ClientObjectInfo* client); KX_PYMETHOD_DOC(KX_RaySensor,GetHitObject); KX_PYMETHOD_DOC(KX_RaySensor,GetHitPosition); diff --git a/source/gameengine/Ketsji/KX_SCA_AddObjectActuator.cpp b/source/gameengine/Ketsji/KX_SCA_AddObjectActuator.cpp index ca0106d64d9..a7330b9a20a 100644 --- a/source/gameengine/Ketsji/KX_SCA_AddObjectActuator.cpp +++ b/source/gameengine/Ketsji/KX_SCA_AddObjectActuator.cpp @@ -52,14 +52,20 @@ KX_SCA_AddObjectActuator::KX_SCA_AddObjectActuator(SCA_IObject *gameobj, int time, SCA_IScene* scene, const MT_Vector3& linvel, - bool local, + bool linv_local, + const MT_Vector3& angvel, + bool angv_local, PyTypeObject* T) : SCA_IActuator(gameobj, T), m_OriginalObject(original), m_scene(scene), + m_linear_velocity(linvel), - m_localFlag(local) + m_localLinvFlag(linv_local), + + m_angular_velocity(angvel), + m_localAngvFlag(angv_local) { if (m_OriginalObject) m_OriginalObject->RegisterActuator(this); @@ -181,13 +187,15 @@ PyParentObject KX_SCA_AddObjectActuator::Parents[] = { }; PyMethodDef KX_SCA_AddObjectActuator::Methods[] = { {"setObject", (PyCFunction) KX_SCA_AddObjectActuator::sPySetObject, METH_O, SetObject_doc}, - {"setTime", (PyCFunction) KX_SCA_AddObjectActuator::sPySetTime, METH_VARARGS, SetTime_doc}, + {"setTime", (PyCFunction) KX_SCA_AddObjectActuator::sPySetTime, METH_O, SetTime_doc}, {"getObject", (PyCFunction) KX_SCA_AddObjectActuator::sPyGetObject, METH_VARARGS, GetObject_doc}, - {"getTime", (PyCFunction) KX_SCA_AddObjectActuator::sPyGetTime, METH_VARARGS, GetTime_doc}, - {"getLinearVelocity", (PyCFunction) KX_SCA_AddObjectActuator::sPyGetLinearVelocity, METH_VARARGS, GetLinearVelocity_doc}, + {"getTime", (PyCFunction) KX_SCA_AddObjectActuator::sPyGetTime, METH_NOARGS, GetTime_doc}, + {"getLinearVelocity", (PyCFunction) KX_SCA_AddObjectActuator::sPyGetLinearVelocity, METH_NOARGS, GetLinearVelocity_doc}, {"setLinearVelocity", (PyCFunction) KX_SCA_AddObjectActuator::sPySetLinearVelocity, METH_VARARGS, SetLinearVelocity_doc}, - {"getLastCreatedObject", (PyCFunction) KX_SCA_AddObjectActuator::sPyGetLastCreatedObject, METH_VARARGS,"getLastCreatedObject() : get the object handle to the last created object\n"}, - {"instantAddObject", (PyCFunction) KX_SCA_AddObjectActuator::sPyInstantAddObject, METH_VARARGS,"instantAddObject() : immediately add object without delay\n"}, + {"getAngularVelocity", (PyCFunction) KX_SCA_AddObjectActuator::sPyGetAngularVelocity, METH_NOARGS, GetAngularVelocity_doc}, + {"setAngularVelocity", (PyCFunction) KX_SCA_AddObjectActuator::sPySetAngularVelocity, METH_VARARGS, SetAngularVelocity_doc}, + {"getLastCreatedObject", (PyCFunction) KX_SCA_AddObjectActuator::sPyGetLastCreatedObject, METH_NOARGS,"getLastCreatedObject() : get the object handle to the last created object\n"}, + {"instantAddObject", (PyCFunction) KX_SCA_AddObjectActuator::sPyInstantAddObject, METH_NOARGS,"instantAddObject() : immediately add object without delay\n"}, {NULL,NULL} //Sentinel }; @@ -231,19 +239,18 @@ char KX_SCA_AddObjectActuator::SetTime_doc[] = "\tIf the duration is negative, it is set to 0.\n"; -PyObject* KX_SCA_AddObjectActuator::PySetTime(PyObject* self, - PyObject* args, - PyObject* kwds) +PyObject* KX_SCA_AddObjectActuator::PySetTime(PyObject* self, PyObject* value) { - int deltatime; - - if (!PyArg_ParseTuple(args, "i", &deltatime)) + int deltatime = PyInt_AsLong(value); + if (deltatime==-1 && PyErr_Occurred()) { + PyErr_SetString(PyExc_TypeError, "expected an int"); return NULL; + } m_timeProp = deltatime; if (m_timeProp < 0) m_timeProp = 0; - Py_Return; + Py_RETURN_NONE; } @@ -254,9 +261,7 @@ char KX_SCA_AddObjectActuator::GetTime_doc[] = "\tReturns the lifetime of the object that will be added.\n"; -PyObject* KX_SCA_AddObjectActuator::PyGetTime(PyObject* self, - PyObject* args, - PyObject* kwds) +PyObject* KX_SCA_AddObjectActuator::PyGetTime(PyObject* self) { return PyInt_FromLong(m_timeProp); } @@ -290,17 +295,13 @@ char KX_SCA_AddObjectActuator::GetLinearVelocity_doc[] = "\tReturns the linear velocity that will be assigned to \n" "\tthe created object.\n"; - - -PyObject* KX_SCA_AddObjectActuator::PyGetLinearVelocity(PyObject* self, - PyObject* args, - PyObject* kwds) +PyObject* KX_SCA_AddObjectActuator::PyGetLinearVelocity(PyObject* self) { PyObject *retVal = PyList_New(3); - PyList_SetItem(retVal, 0, PyFloat_FromDouble(m_linear_velocity[0])); - PyList_SetItem(retVal, 1, PyFloat_FromDouble(m_linear_velocity[1])); - PyList_SetItem(retVal, 2, PyFloat_FromDouble(m_linear_velocity[2])); + PyList_SET_ITEM(retVal, 0, PyFloat_FromDouble(m_linear_velocity[0])); + PyList_SET_ITEM(retVal, 1, PyFloat_FromDouble(m_linear_velocity[1])); + PyList_SET_ITEM(retVal, 2, PyFloat_FromDouble(m_linear_velocity[2])); return retVal; } @@ -313,12 +314,10 @@ char KX_SCA_AddObjectActuator::SetLinearVelocity_doc[] = "\t- vx: float\n" "\t- vy: float\n" "\t- vz: float\n" +"\t- local: bool\n" "\tAssign this velocity to the created object. \n"; - -PyObject* KX_SCA_AddObjectActuator::PySetLinearVelocity(PyObject* self, - PyObject* args, - PyObject* kwds) +PyObject* KX_SCA_AddObjectActuator::PySetLinearVelocity(PyObject* self, PyObject* args) { float vecArg[3]; @@ -326,7 +325,46 @@ PyObject* KX_SCA_AddObjectActuator::PySetLinearVelocity(PyObject* self, return NULL; m_linear_velocity.setValue(vecArg); - Py_Return; + Py_RETURN_NONE; +} + +/* 7. getAngularVelocity */ +char KX_SCA_AddObjectActuator::GetAngularVelocity_doc[] = +"GetAngularVelocity()\n" +"\tReturns the angular velocity that will be assigned to \n" +"\tthe created object.\n"; + +PyObject* KX_SCA_AddObjectActuator::PyGetAngularVelocity(PyObject* self) +{ + PyObject *retVal = PyList_New(3); + + PyList_SET_ITEM(retVal, 0, PyFloat_FromDouble(m_angular_velocity[0])); + PyList_SET_ITEM(retVal, 1, PyFloat_FromDouble(m_angular_velocity[1])); + PyList_SET_ITEM(retVal, 2, PyFloat_FromDouble(m_angular_velocity[2])); + + return retVal; +} + + + +/* 8. setAngularVelocity */ +char KX_SCA_AddObjectActuator::SetAngularVelocity_doc[] = +"setAngularVelocity(vx, vy, vz)\n" +"\t- vx: float\n" +"\t- vy: float\n" +"\t- vz: float\n" +"\t- local: bool\n" +"\tAssign this angular velocity to the created object. \n"; + +PyObject* KX_SCA_AddObjectActuator::PySetAngularVelocity(PyObject* self, PyObject* args) +{ + + float vecArg[3]; + if (!PyArg_ParseTuple(args, "fff", &vecArg[0], &vecArg[1], &vecArg[2])) + return NULL; + + m_angular_velocity.setValue(vecArg); + Py_RETURN_NONE; } void KX_SCA_AddObjectActuator::InstantAddObject() @@ -337,8 +375,9 @@ void KX_SCA_AddObjectActuator::InstantAddObject() // Now it needs to be added to the current scene. SCA_IObject* replica = m_scene->AddReplicaObject(m_OriginalObject,GetParent(),m_timeProp ); KX_GameObject * game_obj = static_cast<KX_GameObject *>(replica); - game_obj->setLinearVelocity(m_linear_velocity,m_localFlag); - game_obj->ResolveCombinedVelocities(m_linear_velocity, MT_Vector3(0., 0., 0.), m_localFlag, false); + game_obj->setLinearVelocity(m_linear_velocity,m_localLinvFlag); + game_obj->setAngularVelocity(m_angular_velocity,m_localAngvFlag); + game_obj->ResolveCombinedVelocities(m_linear_velocity, m_angular_velocity, m_localLinvFlag, m_localAngvFlag); // keep a copy of the last object, to allow python scripters to change it if (m_lastCreatedObject) @@ -355,13 +394,11 @@ void KX_SCA_AddObjectActuator::InstantAddObject() } } -PyObject* KX_SCA_AddObjectActuator::PyInstantAddObject(PyObject* self, - PyObject* args, - PyObject* kwds) +PyObject* KX_SCA_AddObjectActuator::PyInstantAddObject(PyObject* self) { InstantAddObject(); - Py_Return; + Py_RETURN_NONE; } @@ -372,16 +409,17 @@ char KX_SCA_AddObjectActuator::GetLastCreatedObject_doc[] = "\tReturn the last created object. \n"; -PyObject* KX_SCA_AddObjectActuator::PyGetLastCreatedObject(PyObject* self, - PyObject* args, - PyObject* kwds) +PyObject* KX_SCA_AddObjectActuator::PyGetLastCreatedObject(PyObject* self) { SCA_IObject* result = this->GetLastCreatedObject(); - if (result) + + // if result->GetSGNode() is NULL + // it means the object has ended, The BGE python api crashes in many places if the object is returned. + if (result && (static_cast<KX_GameObject *>(result))->GetSGNode()) { result->AddRef(); return result; } // don't return NULL to python anymore, it gives trouble in the scripts - Py_Return; + Py_RETURN_NONE; } diff --git a/source/gameengine/Ketsji/KX_SCA_AddObjectActuator.h b/source/gameengine/Ketsji/KX_SCA_AddObjectActuator.h index e7fdb2fbfbc..278d4180284 100644 --- a/source/gameengine/Ketsji/KX_SCA_AddObjectActuator.h +++ b/source/gameengine/Ketsji/KX_SCA_AddObjectActuator.h @@ -60,9 +60,13 @@ class KX_SCA_AddObjectActuator : public SCA_IActuator /// Linear velocity upon creation of the object. MT_Vector3 m_linear_velocity; + + /// Angular velocity upon creation of the object. + MT_Vector3 m_angular_velocity; /// Apply the velocity locally - bool m_localFlag; + bool m_localLinvFlag; + bool m_localAngvFlag; SCA_IObject* m_lastCreatedObject; @@ -79,7 +83,9 @@ public: int time, SCA_IScene* scene, const MT_Vector3& linvel, - bool local, + bool linv_local, + const MT_Vector3& angvel, + bool angv_local, PyTypeObject* T=&Type ); @@ -115,19 +121,23 @@ public: /* 1. setObject */ KX_PYMETHOD_DOC_O(KX_SCA_AddObjectActuator,SetObject); /* 2. setTime */ - KX_PYMETHOD_DOC(KX_SCA_AddObjectActuator,SetTime); + KX_PYMETHOD_DOC_O(KX_SCA_AddObjectActuator,SetTime); /* 3. getTime */ - KX_PYMETHOD_DOC(KX_SCA_AddObjectActuator,GetTime); + KX_PYMETHOD_DOC_NOARGS(KX_SCA_AddObjectActuator,GetTime); /* 4. getObject */ KX_PYMETHOD_DOC_VARARGS(KX_SCA_AddObjectActuator,GetObject); /* 5. getLinearVelocity */ - KX_PYMETHOD_DOC(KX_SCA_AddObjectActuator,GetLinearVelocity); + KX_PYMETHOD_DOC_NOARGS(KX_SCA_AddObjectActuator,GetLinearVelocity); /* 6. setLinearVelocity */ - KX_PYMETHOD_DOC(KX_SCA_AddObjectActuator,SetLinearVelocity); - /* 7. getLastCreatedObject */ - KX_PYMETHOD_DOC(KX_SCA_AddObjectActuator,GetLastCreatedObject); - /* 8. instantAddObject*/ - KX_PYMETHOD_DOC(KX_SCA_AddObjectActuator,InstantAddObject); + KX_PYMETHOD_DOC_VARARGS(KX_SCA_AddObjectActuator,SetLinearVelocity); + /* 7. getAngularVelocity */ + KX_PYMETHOD_DOC_NOARGS(KX_SCA_AddObjectActuator,GetAngularVelocity); + /* 8. setAngularVelocity */ + KX_PYMETHOD_DOC_VARARGS(KX_SCA_AddObjectActuator,SetAngularVelocity); + /* 9. getLastCreatedObject */ + KX_PYMETHOD_DOC_NOARGS(KX_SCA_AddObjectActuator,GetLastCreatedObject); + /* 10. instantAddObject*/ + KX_PYMETHOD_DOC_NOARGS(KX_SCA_AddObjectActuator,InstantAddObject); }; /* end of class KX_SCA_AddObjectActuator : public KX_EditObjectActuator */ diff --git a/source/gameengine/Ketsji/KX_Scene.cpp b/source/gameengine/Ketsji/KX_Scene.cpp index 2828663c63d..1c37fcea77e 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; @@ -975,6 +944,8 @@ int KX_Scene::NewRemoveObject(class CValue* gameobj) newobj->RemoveMeshes(); ret = 1; + if (m_lightlist->RemoveValue(newobj)) // TODO - use newobj->IsLight() test when its merged in from apricot. - Campbell + ret = newobj->Release(); if (m_objectlist->RemoveValue(newobj)) ret = newobj->Release(); if (m_tempObjectList->RemoveValue(newobj)) 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/Ketsji/KX_SoundActuator.cpp b/source/gameengine/Ketsji/KX_SoundActuator.cpp index 34a3baec093..f75a1ee5c62 100644 --- a/source/gameengine/Ketsji/KX_SoundActuator.cpp +++ b/source/gameengine/Ketsji/KX_SoundActuator.cpp @@ -69,11 +69,11 @@ KX_SoundActuator::KX_SoundActuator(SCA_IObject* gameobj, KX_SoundActuator::~KX_SoundActuator() { - //m_soundScene->RemoveObject(this->m_soundObject); - //(this->m_soundObject)->DeleteWhenFinished(); - m_soundScene->RemoveActiveObject(m_soundObject); -// m_soundScene->DeleteObjectWhenFinished(m_soundObject); - m_soundScene->DeleteObject(m_soundObject); + if (m_soundObject) + { + m_soundScene->RemoveActiveObject(m_soundObject); + m_soundScene->DeleteObject(m_soundObject); + } } @@ -82,9 +82,12 @@ CValue* KX_SoundActuator::GetReplica() { KX_SoundActuator* replica = new KX_SoundActuator(*this); replica->ProcessReplica(); - SND_SoundObject* soundobj = new SND_SoundObject(*m_soundObject); - replica->setSoundObject(soundobj); - m_soundScene->AddObject(soundobj); + if (m_soundObject) + { + SND_SoundObject* soundobj = new SND_SoundObject(*m_soundObject); + replica->setSoundObject(soundobj); + m_soundScene->AddObject(soundobj); + } // this will copy properties and so on... CValue::AddDataToReplica(replica); @@ -104,6 +107,9 @@ bool KX_SoundActuator::Update(double curtime, bool frame) RemoveAllEvents(); + if (!m_soundObject) + return false; + if (m_pino) { bNegativeEvent = true; @@ -287,6 +293,10 @@ PyObject* KX_SoundActuator::PySetFilename(PyObject* self, PyObject* args, PyObje PyObject* KX_SoundActuator::PyGetFilename(PyObject* self, PyObject* args, PyObject* kwds) { + if (!m_soundObject) + { + return PyString_FromString(""); + } STR_String objectname = m_soundObject->GetObjectName(); char* name = objectname.Ptr(); @@ -301,7 +311,8 @@ PyObject* KX_SoundActuator::PyGetFilename(PyObject* self, PyObject* args, PyObje PyObject* KX_SoundActuator::PyStartSound(PyObject* self, PyObject* args, PyObject* kwds) { - m_soundObject->StartSound(); + if (m_soundObject) + m_soundObject->StartSound(); Py_Return; } @@ -309,7 +320,8 @@ PyObject* KX_SoundActuator::PyStartSound(PyObject* self, PyObject* args, PyObjec PyObject* KX_SoundActuator::PyPauseSound(PyObject* self, PyObject* args, PyObject* kwds) { - m_soundObject->PauseSound(); + if (m_soundObject) + m_soundObject->PauseSound(); Py_Return; } @@ -317,7 +329,8 @@ PyObject* KX_SoundActuator::PyPauseSound(PyObject* self, PyObject* args, PyObjec PyObject* KX_SoundActuator::PyStopSound(PyObject* self, PyObject* args, PyObject* kwds) { - m_soundObject->StopSound(); + if (m_soundObject) + m_soundObject->StopSound(); Py_Return; } @@ -329,7 +342,8 @@ PyObject* KX_SoundActuator::PySetGain(PyObject* self, PyObject* args, PyObject* if (!PyArg_ParseTuple(args, "f", &gain)) return NULL; - m_soundObject->SetGain(gain); + if (m_soundObject) + m_soundObject->SetGain(gain); Py_Return; } @@ -338,7 +352,7 @@ PyObject* KX_SoundActuator::PySetGain(PyObject* self, PyObject* args, PyObject* PyObject* KX_SoundActuator::PyGetGain(PyObject* self, PyObject* args, PyObject* kwds) { - float gain = m_soundObject->GetGain(); + float gain = (m_soundObject) ? m_soundObject->GetGain() : 1.0f; PyObject* result = PyFloat_FromDouble(gain); return result; @@ -352,7 +366,8 @@ PyObject* KX_SoundActuator::PySetPitch(PyObject* self, PyObject* args, PyObject* if (!PyArg_ParseTuple(args, "f", &pitch)) return NULL; - m_soundObject->SetPitch(pitch); + if (m_soundObject) + m_soundObject->SetPitch(pitch); Py_Return; } @@ -361,7 +376,7 @@ PyObject* KX_SoundActuator::PySetPitch(PyObject* self, PyObject* args, PyObject* PyObject* KX_SoundActuator::PyGetPitch(PyObject* self, PyObject* args, PyObject* kwds) { - float pitch = m_soundObject->GetPitch(); + float pitch = (m_soundObject) ? m_soundObject->GetPitch() : 1.0; PyObject* result = PyFloat_FromDouble(pitch); return result; @@ -375,7 +390,8 @@ PyObject* KX_SoundActuator::PySetRollOffFactor(PyObject* self, PyObject* args, P if (!PyArg_ParseTuple(args, "f", &rollofffactor)) return NULL; - m_soundObject->SetRollOffFactor(rollofffactor); + if (m_soundObject) + m_soundObject->SetRollOffFactor(rollofffactor); Py_Return; } @@ -384,7 +400,7 @@ PyObject* KX_SoundActuator::PySetRollOffFactor(PyObject* self, PyObject* args, P PyObject* KX_SoundActuator::PyGetRollOffFactor(PyObject* self, PyObject* args, PyObject* kwds) { - float rollofffactor = m_soundObject->GetRollOffFactor(); + float rollofffactor = (m_soundObject) ? m_soundObject->GetRollOffFactor() : 1.0; PyObject* result = PyFloat_FromDouble(rollofffactor); return result; @@ -398,7 +414,8 @@ PyObject* KX_SoundActuator::PySetLooping(PyObject* self, PyObject* args, PyObjec if (!PyArg_ParseTuple(args, "i", &looping)) return NULL; - m_soundObject->SetLoopMode(looping); + if (m_soundObject) + m_soundObject->SetLoopMode(looping); Py_Return; } @@ -407,7 +424,7 @@ PyObject* KX_SoundActuator::PySetLooping(PyObject* self, PyObject* args, PyObjec PyObject* KX_SoundActuator::PyGetLooping(PyObject* self, PyObject* args, PyObject* kwds) { - int looping = m_soundObject->GetLoopMode(); + int looping = (m_soundObject) ? m_soundObject->GetLoopMode() : SND_LOOP_OFF; PyObject* result = PyInt_FromLong(looping); return result; @@ -425,7 +442,8 @@ PyObject* KX_SoundActuator::PySetPosition(PyObject* self, PyObject* args, PyObje if (!PyArg_ParseTuple(args, "fff", &pos[0], &pos[1], &pos[2])) return NULL; - m_soundObject->SetPosition(pos); + if (m_soundObject) + m_soundObject->SetPosition(pos); Py_Return; } @@ -442,7 +460,8 @@ PyObject* KX_SoundActuator::PySetVelocity(PyObject* self, PyObject* args, PyObje if (!PyArg_ParseTuple(args, "fff", &vel[0], &vel[1], &vel[2])) return NULL; - m_soundObject->SetVelocity(vel); + if (m_soundObject) + m_soundObject->SetVelocity(vel); Py_Return; } @@ -465,7 +484,8 @@ PyObject* KX_SoundActuator::PySetOrientation(PyObject* self, PyObject* args, PyO if (!PyArg_ParseTuple(args, "fffffffff", &ori[0][0], &ori[0][1], &ori[0][2], &ori[1][0], &ori[1][1], &ori[1][2], &ori[2][0], &ori[2][1], &ori[2][2])) return NULL; - m_soundObject->SetOrientation(ori); + if (m_soundObject) + m_soundObject->SetOrientation(ori); Py_Return; } diff --git a/source/gameengine/Ketsji/Makefile b/source/gameengine/Ketsji/Makefile index 47a4855b00c..59cc6c8ca7e 100644 --- a/source/gameengine/Ketsji/Makefile +++ b/source/gameengine/Ketsji/Makefile @@ -38,7 +38,9 @@ CCFLAGS += $(LEVEL_1_CPP_WARNINGS) CPPFLAGS += $(OGL_CPPFLAGS) CPPFLAGS += -I$(NAN_GLEW)/include CPPFLAGS += -I$(OPENGL_HEADERS) -CPPFLAGS += -I$(NAN_PYTHON)/include/python$(NAN_PYTHON_VERSION) -I../../blender/python +CPPFLAGS += -I$(NAN_PYTHON)/include/python$(NAN_PYTHON_VERSION) +CPPFLAGS += -I../../blender/python +CPPFLAGS += -I../../blender/python/api2_2x CPPFLAGS += -I$(NAN_STRING)/include CPPFLAGS += -I$(NAN_SOUNDSYSTEM)/include CPPFLAGS += -I$(NAN_FUZZICS)/include -I$(NAN_SUMO) -I$(NAN_MOTO)/include diff --git a/source/gameengine/Physics/BlOde/OdePhysicsEnvironment.cpp b/source/gameengine/Physics/BlOde/OdePhysicsEnvironment.cpp index a04560aaf09..6d9b41e08d2 100644 --- a/source/gameengine/Physics/BlOde/OdePhysicsEnvironment.cpp +++ b/source/gameengine/Physics/BlOde/OdePhysicsEnvironment.cpp @@ -206,8 +206,7 @@ void ODEPhysicsEnvironment::removeConstraint(int constraintid) } } -PHY_IPhysicsController* ODEPhysicsEnvironment::rayTest(PHY_IPhysicsController* ignoreClient,float fromX,float fromY,float fromZ, float toX,float toY,float toZ, - float& hitX,float& hitY,float& hitZ,float& normalX,float& normalY,float& normalZ) +PHY_IPhysicsController* ODEPhysicsEnvironment::rayTest(PHY_IRayCastFilterCallback &filterCallback,float fromX,float fromY,float fromZ, float toX,float toY,float toZ) { //m_OdeWorld diff --git a/source/gameengine/Physics/BlOde/OdePhysicsEnvironment.h b/source/gameengine/Physics/BlOde/OdePhysicsEnvironment.h index 7c61902f8e2..dcc87d614c0 100644 --- a/source/gameengine/Physics/BlOde/OdePhysicsEnvironment.h +++ b/source/gameengine/Physics/BlOde/OdePhysicsEnvironment.h @@ -54,8 +54,7 @@ public: float axisX,float axisY,float axisZ); virtual void removeConstraint(void * constraintid); - virtual PHY_IPhysicsController* rayTest(PHY_IPhysicsController* ignoreClient,float fromX,float fromY,float fromZ, float toX,float toY,float toZ, - float& hitX,float& hitY,float& hitZ,float& normalX,float& normalY,float& normalZ); + virtual PHY_IPhysicsController* rayTest(PHY_IRayCastFilterCallback &filterCallback,float fromX,float fromY,float fromZ, float toX,float toY,float toZ); //gamelogic callbacks diff --git a/source/gameengine/Physics/Bullet/CMakeLists.txt b/source/gameengine/Physics/Bullet/CMakeLists.txt index b610fd1bbb0..6c733786caf 100644 --- a/source/gameengine/Physics/Bullet/CMakeLists.txt +++ b/source/gameengine/Physics/Bullet/CMakeLists.txt @@ -30,6 +30,10 @@ SET(INC . ../common ../../../../extern/bullet2/src + ../../../../intern/moto/include + ../../../kernel/gen_system + ../../../../intern/string + ../../Rasterizer ) BLENDERLIB(bf_bullet "${SRC}" "${INC}") diff --git a/source/gameengine/Physics/Bullet/CcdPhysicsController.cpp b/source/gameengine/Physics/Bullet/CcdPhysicsController.cpp index b872fae6138..2ec96c75a68 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,206 @@ 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(); + m_polygonIndexArray.clear(); + m_meshObject = NULL; + + 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); + m_polygonIndexArray.push_back(p2); + 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); + m_polygonIndexArray.push_back(p2); + numvalidpolys++; + } + } + } + } + + if (!numvalidpolys) + { + // should not happen + m_shapeType = PHY_SHAPE_NONE; + return false; + } + m_meshObject = meshobj; + 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..8a7f1062f53 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,81 @@ 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; + } + CcdShapeConstructionInfo* GetChildShape(int i) + { + CcdShapeConstructionInfo* shape = m_nextShape; + while (i > 0 && shape != NULL) + { + shape = shape->m_nextShape; + i--; + } + return shape; + } + + 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 + std::vector<int> m_polygonIndexArray; // Contains the array of polygon index in the + // original mesh that correspond to shape triangles. + // only set for concave mesh shape. + const RAS_MeshObject* m_meshObject; // Keep a pointer to the original mesh + +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 +141,7 @@ struct CcdConstructionInfo m_collisionFilterMask(AllFilter), m_collisionShape(0), m_MotionState(0), + m_shapeInfo(0), m_physicsEnv(0), m_inertiaFactor(1.f) { @@ -89,8 +166,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 +186,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 +220,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..d14ddf8f65c 100644 --- a/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp +++ b/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp @@ -53,6 +53,7 @@ void DrawRasterizerLine(const float* from,const float* to,int color); #include <stdio.h> +#include <string.h> // for memset #ifdef NEW_BULLET_VEHICLE_SUPPORT class WrapperVehicle : public PHY_IVehicle @@ -709,35 +710,51 @@ void CcdPhysicsEnvironment::removeConstraint(int constraintId) struct FilterClosestRayResultCallback : public btCollisionWorld::ClosestRayResultCallback { - PHY_IPhysicsController* m_ignoreClient; + PHY_IRayCastFilterCallback& m_phyRayFilter; + const btCollisionShape* m_hitTriangleShape; + int m_hitTriangleIndex; - FilterClosestRayResultCallback (PHY_IPhysicsController* ignoreClient,const btVector3& rayFrom,const btVector3& rayTo) + FilterClosestRayResultCallback (PHY_IRayCastFilterCallback& phyRayFilter,const btVector3& rayFrom,const btVector3& rayTo) : btCollisionWorld::ClosestRayResultCallback(rayFrom,rayTo), - m_ignoreClient(ignoreClient) + m_phyRayFilter(phyRayFilter), + m_hitTriangleShape(NULL), + m_hitTriangleIndex(0) { - } virtual ~FilterClosestRayResultCallback() { } + virtual bool NeedRayCast(btCollisionObject* object) + { + CcdPhysicsController* phyCtrl = static_cast<CcdPhysicsController*>(object->getUserPointer()); + if (phyCtrl != m_phyRayFilter.m_ignoreController) + { + return m_phyRayFilter.needBroadphaseRayCast(phyCtrl); + } + return false; + } + virtual float AddSingleResult( btCollisionWorld::LocalRayResult& rayResult) { CcdPhysicsController* curHit = static_cast<CcdPhysicsController*>(rayResult.m_collisionObject->getUserPointer()); - //ignore client... - if (curHit != m_ignoreClient) - { - //if valid - return ClosestRayResultCallback::AddSingleResult(rayResult); + // save shape information as ClosestRayResultCallback::AddSingleResult() does not do it + if (rayResult.m_localShapeInfo) + { + m_hitTriangleShape = rayResult.m_localShapeInfo->m_triangleShape; + m_hitTriangleIndex = rayResult.m_localShapeInfo->m_triangleIndex; + } else + { + m_hitTriangleShape = NULL; + m_hitTriangleIndex = 0; } - return m_closestHitFraction; + return ClosestRayResultCallback::AddSingleResult(rayResult); } }; -PHY_IPhysicsController* CcdPhysicsEnvironment::rayTest(PHY_IPhysicsController* ignoreClient, float fromX,float fromY,float fromZ, float toX,float toY,float toZ, - float& hitX,float& hitY,float& hitZ,float& normalX,float& normalY,float& normalZ) +PHY_IPhysicsController* CcdPhysicsEnvironment::rayTest(PHY_IRayCastFilterCallback &filterCallback, float fromX,float fromY,float fromZ, float toX,float toY,float toZ) { @@ -751,18 +768,21 @@ PHY_IPhysicsController* CcdPhysicsEnvironment::rayTest(PHY_IPhysicsController* i //Either Ray Cast with or without filtering //btCollisionWorld::ClosestRayResultCallback rayCallback(rayFrom,rayTo); - FilterClosestRayResultCallback rayCallback(ignoreClient,rayFrom,rayTo); + FilterClosestRayResultCallback rayCallback(filterCallback,rayFrom,rayTo); - PHY_IPhysicsController* nearestHit = 0; + PHY_RayCastResult result; + memset(&result, 0, sizeof(result)); + // don't collision with sensor object - m_dynamicsWorld->rayTest(rayFrom,rayTo,rayCallback, CcdConstructionInfo::AllFilter ^ CcdConstructionInfo::SensorFilter); + m_dynamicsWorld->rayTest(rayFrom,rayTo,rayCallback, CcdConstructionInfo::AllFilter ^ CcdConstructionInfo::SensorFilter,filterCallback.m_faceNormal); if (rayCallback.HasHit()) { - nearestHit = static_cast<CcdPhysicsController*>(rayCallback.m_collisionObject->getUserPointer()); - hitX = rayCallback.m_hitPointWorld.getX(); - hitY = rayCallback.m_hitPointWorld.getY(); - hitZ = rayCallback.m_hitPointWorld.getZ(); + CcdPhysicsController* controller = static_cast<CcdPhysicsController*>(rayCallback.m_collisionObject->getUserPointer()); + result.m_controller = controller; + result.m_hitPoint[0] = rayCallback.m_hitPointWorld.getX(); + result.m_hitPoint[1] = rayCallback.m_hitPointWorld.getY(); + result.m_hitPoint[2] = rayCallback.m_hitPointWorld.getZ(); if (rayCallback.m_hitNormalWorld.length2() > (SIMD_EPSILON*SIMD_EPSILON)) { @@ -771,14 +791,42 @@ PHY_IPhysicsController* CcdPhysicsEnvironment::rayTest(PHY_IPhysicsController* i { rayCallback.m_hitNormalWorld.setValue(1,0,0); } - normalX = rayCallback.m_hitNormalWorld.getX(); - normalY = rayCallback.m_hitNormalWorld.getY(); - normalZ = rayCallback.m_hitNormalWorld.getZ(); - + result.m_hitNormal[0] = rayCallback.m_hitNormalWorld.getX(); + result.m_hitNormal[1] = rayCallback.m_hitNormalWorld.getY(); + result.m_hitNormal[2] = rayCallback.m_hitNormalWorld.getZ(); + if (rayCallback.m_hitTriangleShape != NULL) + { + // identify the mesh polygon + CcdShapeConstructionInfo* shapeInfo = controller->m_shapeInfo; + if (shapeInfo) + { + btCollisionShape* shape = controller->GetRigidBody()->getCollisionShape(); + if (shape->isCompound()) + { + btCompoundShape* compoundShape = (btCompoundShape*)shape; + CcdShapeConstructionInfo* compoundShapeInfo = shapeInfo; + // need to search which sub-shape has been hit + for (int i=0; i<compoundShape->getNumChildShapes(); i++) + { + shapeInfo = compoundShapeInfo->GetChildShape(i); + shape=compoundShape->getChildShape(i); + if (shape == rayCallback.m_hitTriangleShape) + break; + } + } + if (shape == rayCallback.m_hitTriangleShape && + rayCallback.m_hitTriangleIndex < shapeInfo->m_polygonIndexArray.size()) + { + result.m_meshObject = shapeInfo->m_meshObject; + result.m_polygon = shapeInfo->m_polygonIndexArray.at(rayCallback.m_hitTriangleIndex); + } + } + } + filterCallback.reportHit(&result); } - return nearestHit; + return result.m_controller; } @@ -1370,8 +1418,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/CcdPhysicsEnvironment.h b/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.h index 825a5e525f2..667e310dcb3 100644 --- a/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.h +++ b/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.h @@ -157,8 +157,7 @@ protected: btTypedConstraint* getConstraintById(int constraintId); - virtual PHY_IPhysicsController* rayTest(PHY_IPhysicsController* ignoreClient, float fromX,float fromY,float fromZ, float toX,float toY,float toZ, - float& hitX,float& hitY,float& hitZ,float& normalX,float& normalY,float& normalZ); + virtual PHY_IPhysicsController* rayTest(PHY_IRayCastFilterCallback &filterCallback, float fromX,float fromY,float fromZ, float toX,float toY,float toZ); //Methods for gamelogic collision/physics callbacks diff --git a/source/gameengine/Physics/Bullet/Makefile b/source/gameengine/Physics/Bullet/Makefile index 49259d0a67c..d5570e75833 100644 --- a/source/gameengine/Physics/Bullet/Makefile +++ b/source/gameengine/Physics/Bullet/Makefile @@ -37,5 +37,10 @@ CCFLAGS += $(LEVEL_1_CPP_WARNINGS) CPPFLAGS += -I$(NAN_BULLET2)/include CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include +CPPFLAGS += -I$(NAN_STRING)/include +CPPFLAGS += -I$(NAN_MOTO)/include +CPPFLAGS += -I../../../kernel/gen_system CPPFLAGS += -I../../Physics/common CPPFLAGS += -I../../Physics/Dummy +CPPFLAGS += -I../../Rasterizer + 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/Dummy/DummyPhysicsEnvironment.cpp b/source/gameengine/Physics/Dummy/DummyPhysicsEnvironment.cpp index f512d44c9f2..d78958b746c 100644 --- a/source/gameengine/Physics/Dummy/DummyPhysicsEnvironment.cpp +++ b/source/gameengine/Physics/Dummy/DummyPhysicsEnvironment.cpp @@ -109,8 +109,7 @@ void DummyPhysicsEnvironment::removeConstraint(int constraintid) } } -PHY_IPhysicsController* DummyPhysicsEnvironment::rayTest(PHY_IPhysicsController* ignoreClient,float fromX,float fromY,float fromZ, float toX,float toY,float toZ, - float& hitX,float& hitY,float& hitZ,float& normalX,float& normalY,float& normalZ) +PHY_IPhysicsController* DummyPhysicsEnvironment::rayTest(PHY_IRayCastFilterCallback &filterCallback,float fromX,float fromY,float fromZ, float toX,float toY,float toZ) { //collision detection / raytesting return NULL; diff --git a/source/gameengine/Physics/Dummy/DummyPhysicsEnvironment.h b/source/gameengine/Physics/Dummy/DummyPhysicsEnvironment.h index b5a61f72e4a..975be84f2a7 100644 --- a/source/gameengine/Physics/Dummy/DummyPhysicsEnvironment.h +++ b/source/gameengine/Physics/Dummy/DummyPhysicsEnvironment.h @@ -69,8 +69,7 @@ public: return 0; } - virtual PHY_IPhysicsController* rayTest(PHY_IPhysicsController* ignoreClient, float fromX,float fromY,float fromZ, float toX,float toY,float toZ, - float& hitX,float& hitY,float& hitZ,float& normalX,float& normalY,float& normalZ); + virtual PHY_IPhysicsController* rayTest(PHY_IRayCastFilterCallback &filterCallback, float fromX,float fromY,float fromZ, float toX,float toY,float toZ); //gamelogic callbacks diff --git a/source/gameengine/Physics/Sumo/SumoPhysicsEnvironment.cpp b/source/gameengine/Physics/Sumo/SumoPhysicsEnvironment.cpp index 65018d2523e..80e4dc4044e 100644 --- a/source/gameengine/Physics/Sumo/SumoPhysicsEnvironment.cpp +++ b/source/gameengine/Physics/Sumo/SumoPhysicsEnvironment.cpp @@ -26,6 +26,7 @@ * * ***** END GPL LICENSE BLOCK ***** */ +#include <string.h> // memset #include "SumoPhysicsEnvironment.h" #include "PHY_IMotionState.h" #include "SumoPhysicsController.h" @@ -125,37 +126,35 @@ void SumoPhysicsEnvironment::removeConstraint(int constraintid) } } -PHY_IPhysicsController* SumoPhysicsEnvironment::rayTest(PHY_IPhysicsController* ignoreClientCtrl, +PHY_IPhysicsController* SumoPhysicsEnvironment::rayTest(PHY_IRayCastFilterCallback &filterCallback, float fromX,float fromY,float fromZ, - float toX,float toY,float toZ, - float& hitX,float& hitY,float& hitZ, - float& normalX,float& normalY,float& normalZ) + float toX,float toY,float toZ) { - SumoPhysicsController* ignoreCtr = static_cast<SumoPhysicsController*> (ignoreClientCtrl); + SumoPhysicsController* ignoreCtr = static_cast<SumoPhysicsController*> (filterCallback.m_ignoreController); //collision detection / raytesting MT_Point3 hit, normal; - PHY_IPhysicsController *ret = 0; + PHY_RayCastResult result; SM_Object* sm_ignore = 0; if (ignoreCtr) sm_ignore = ignoreCtr->GetSumoObject(); + memset(&result, 0, sizeof(result)); SM_Object* smOb = m_sumoScene->rayTest(sm_ignore,MT_Point3(fromX, fromY, fromZ),MT_Point3(toX, toY, toZ), hit, normal); if (smOb) { - ret = (PHY_IPhysicsController *) smOb->getPhysicsClientObject(); + result.m_controller = (PHY_IPhysicsController *) smOb->getPhysicsClientObject(); + result.m_hitPoint[0] = hit[0]; + result.m_hitPoint[1] = hit[1]; + result.m_hitPoint[2] = hit[2]; + result.m_hitNormal[0] = normal[0]; + result.m_hitNormal[1] = normal[1]; + result.m_hitNormal[2] = normal[2]; + filterCallback.reportHit(&result); } - hitX = hit[0]; - hitY = hit[1]; - hitZ = hit[2]; - - normalX = normal[0]; - normalY = normal[1]; - normalZ = normal[2]; - - return ret; + return result.m_controller; } //gamelogic callbacks void SumoPhysicsEnvironment::addSensor(PHY_IPhysicsController* ctrl) diff --git a/source/gameengine/Physics/Sumo/SumoPhysicsEnvironment.h b/source/gameengine/Physics/Sumo/SumoPhysicsEnvironment.h index 8b9fb463034..100adf969d5 100644 --- a/source/gameengine/Physics/Sumo/SumoPhysicsEnvironment.h +++ b/source/gameengine/Physics/Sumo/SumoPhysicsEnvironment.h @@ -75,8 +75,7 @@ public: return 0; } - virtual PHY_IPhysicsController* rayTest(PHY_IPhysicsController* ignoreClient,float fromX,float fromY,float fromZ, float toX,float toY,float toZ, - float& hitX,float& hitY,float& hitZ,float& normalX,float& normalY,float& normalZ); + virtual PHY_IPhysicsController* rayTest(PHY_IRayCastFilterCallback &filterCallback,float fromX,float fromY,float fromZ, float toX,float toY,float toZ); //gamelogic callbacks 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 diff --git a/source/gameengine/Physics/common/PHY_IPhysicsEnvironment.h b/source/gameengine/Physics/common/PHY_IPhysicsEnvironment.h index 5b275066665..98496fb7f9e 100644 --- a/source/gameengine/Physics/common/PHY_IPhysicsEnvironment.h +++ b/source/gameengine/Physics/common/PHY_IPhysicsEnvironment.h @@ -33,6 +33,50 @@ #include <vector> #include "PHY_DynamicTypes.h" class PHY_IVehicle; +class RAS_MeshObject; +class PHY_IPhysicsController; + +/** + * pass back information from rayTest + */ +struct PHY_RayCastResult +{ + PHY_IPhysicsController* m_controller; + PHY__Vector3 m_hitPoint; + PHY__Vector3 m_hitNormal; + const RAS_MeshObject* m_meshObject; // !=NULL for mesh object (only for Bullet controllers) + int m_polygon; // index of the polygon hit by the ray, + // only if m_meshObject != NULL +}; + +/** + * This class replaces the ignoreController parameter of rayTest function. + * It allows more sophisticated filtering on the physics controller before computing the ray intersection to save CPU. + * It is only used to its full extend by the Ccd physics environement (Bullet). + */ +class PHY_IRayCastFilterCallback +{ +public: + PHY_IPhysicsController* m_ignoreController; + bool m_faceNormal; + + virtual ~PHY_IRayCastFilterCallback() + { + } + + virtual bool needBroadphaseRayCast(PHY_IPhysicsController* controller) + { + return true; + } + + virtual void reportHit(PHY_RayCastResult* result) = 0; + + PHY_IRayCastFilterCallback(PHY_IPhysicsController* ignoreController, bool faceNormal=false) + :m_ignoreController(ignoreController), + m_faceNormal(faceNormal) + { + } +}; /** * Physics Environment takes care of stepping the simulation and is a container for physics entities (rigidbodies,constraints, materials etc.) @@ -94,8 +138,7 @@ class PHY_IPhysicsEnvironment //complex constraint for vehicles virtual PHY_IVehicle* getVehicleConstraint(int constraintId) =0; - virtual PHY_IPhysicsController* rayTest(PHY_IPhysicsController* ignoreClient, float fromX,float fromY,float fromZ, float toX,float toY,float toZ, - float& hitX,float& hitY,float& hitZ,float& normalX,float& normalY,float& normalZ)=0; + virtual PHY_IPhysicsController* rayTest(PHY_IRayCastFilterCallback &filterCallback, float fromX,float fromY,float fromZ, float toX,float toY,float toZ)=0; //Methods for gamelogic collision/physics callbacks diff --git a/source/gameengine/PyDoc/GameKeys.py b/source/gameengine/PyDoc/GameKeys.py index 268fb9cc172..1a0a737718e 100644 --- a/source/gameengine/PyDoc/GameKeys.py +++ b/source/gameengine/PyDoc/GameKeys.py @@ -164,3 +164,12 @@ Example:: # Activate Right! """ + +def EventToString(event): + """ + Return the string name of a key event. Will raise a ValueError error if its invalid. + + @type event: int + @param event: key event from GameKeys or the keyboard sensor. + @rtype: string + """ diff --git a/source/gameengine/PyDoc/GameLogic.py b/source/gameengine/PyDoc/GameLogic.py index 965c0522bd7..b65bc0f3ce8 100644 --- a/source/gameengine/PyDoc/GameLogic.py +++ b/source/gameengine/PyDoc/GameLogic.py @@ -14,8 +14,7 @@ Documentation for the GameLogic Module. Examples:: # To get a controller: - import GameLogic - co = GameLogic.getCurrentController() + co = GameLogic.getCurrentController() # GameLogic is automatically imported # To get the game object associated with this controller: obj = co.getOwner() @@ -42,6 +41,7 @@ Documentation for the GameLogic Module. - L{SCA_MouseSensor} - L{SCA_PropertySensor} - L{SCA_RandomSensor} + - L{SCA_DelaySensor} You can also access actuators linked to the controller:: # To get an actuator attached to the controller: @@ -236,3 +236,13 @@ def expandPath(path): @return: The converted string @rtype: string """ + +def getBlendFileList(path = "//"): + """ + Returns a list of blend files in the same directory as the open blend file, or from using the option argument. + + @param path: Optional directory argument, will be expanded (like expandPath) into the full path. + @type path: string + @return: A list of filenames, with no directory prefix + @rtype: list + """
\ No newline at end of file diff --git a/source/gameengine/PyDoc/KX_GameObject.py b/source/gameengine/PyDoc/KX_GameObject.py index a5ba5b1d634..2136ce54e30 100644 --- a/source/gameengine/PyDoc/KX_GameObject.py +++ b/source/gameengine/PyDoc/KX_GameObject.py @@ -135,6 +135,26 @@ class KX_GameObject: @param local: - False: you get the "global" velocity ie: relative to world orientation (default). - True: you get the "local" velocity ie: relative to object orientation. """ + def getAngularVelocity(local = 0): + """ + Gets the game object's angular velocity. + + @type local: boolean + @param local: - False: you get the "global" velocity ie: relative to world orientation (default). + - True: you get the "local" velocity ie: relative to object orientation. + @rtype: list [vx, vy, vz] + @return: the object's angular velocity. + """ + def setAngularVelocity(velocity, local = 0): + """ + Sets the game object's angular velocity. + + @type velocity: 3d vector. + @param velocity: angular velocity vector. + @type local: boolean + @param local: - False: you get the "global" velocity ie: relative to world orientation (default). + - True: you get the "local" velocity ie: relative to object orientation. + """ def getVelocity(point): """ Gets the game object's velocity at the specified point. @@ -280,10 +300,11 @@ class KX_GameObject: @rtype: L{KX_GameObject} @return: the first object hit or None if no object or object does not match prop """ - def rayCast(to,from,dist,prop): + def rayCast(to,from,dist,prop,face,xray,poly): """ Look from a point/object to another point/object and find first object hit within dist that matches prop. - Returns a 3-tuple with object reference, hit point and hit normal or (None,None,None) if no hit. + if poly is 0, returns a 3-tuple with object reference, hit point and hit normal or (None,None,None) if no hit. + if poly is 1, returns a 4-tuple with in addition a L{KX_PolyProxy} as 4th element. Ex: # shoot along the axis gun-gunAim (gunAim should be collision-free) ob,point,normal = gun.rayCast(gunAim,None,50) @@ -292,9 +313,18 @@ class KX_GameObject: Notes: The ray ignores the object on which the method is called. - If is casted from/to object center or explicit [x,y,z] points. - The ray does not have X-Ray capability: the first object hit (other than self object) stops the ray - If a property was specified and the first object hit does not have that property, there is no hit + It is casted from/to object center or explicit [x,y,z] points. + The face paremeter determines the orientation of the normal: + 0 => hit normal is always oriented towards the ray origin (as if you casted the ray from outside) + 1 => hit normal is the real face normal (only for mesh object, otherwise face has no effect) + The ray has X-Ray capability if xray parameter is 1, otherwise the first object hit (other than self object) stops the ray. + The prop and xray parameters interact as follow: + prop off, xray off: return closest hit or no hit if there is no object on the full extend of the ray. + prop off, xray on : idem. + prop on, xray off: return closest hit if it matches prop, no hit otherwise. + prop on, xray on : return closest hit matching prop or no hit if there is no object matching prop on the full extend of the ray. + The L{KX_PolyProxy} 4th element of the return tuple when poly=1 allows to retrieve information on the polygon hit by the ray. + If there is no hit or the hit object is not a static mesh, None is returned as 4th element. The ray ignores collision-free objects and faces that dont have the collision flag enabled, you can however use ghost objects. @param to: [x,y,z] or object to which the ray is casted @@ -305,8 +335,17 @@ class KX_GameObject: @type dist: float @param prop: property name that object must have; can be omitted => detect any object @type prop: string - @rtype: 3-tuple (L{KX_GameObject}, 3-tuple (x,y,z), 3-tuple (nx,ny,nz)) - @return: (object,hitpoint,hitnormal) or (None,None,None) + @param face: normal option: 1=>return face normal; 0 or omitted => normal is oriented towards origin + @type face: int + @param xray: X-ray option: 1=>skip objects that don't match prop; 0 or omitted => stop on first object + @type xray: int + @param poly: polygon option: 1=>return value is a 4-tuple and the 4th element is a L{KX_PolyProxy} + @type poly: int + @rtype: 3-tuple (L{KX_GameObject}, 3-tuple (x,y,z), 3-tuple (nx,ny,nz)) + or 4-tuple (L{KX_GameObject}, 3-tuple (x,y,z), 3-tuple (nx,ny,nz), L{KX_PolyProxy)) + @return: (object,hitpoint,hitnormal) or (object,hitpoint,hitnormal,polygon) + If no hit, returns (None,None,None) or (None,None,None,None) + If the object hit is not a static mesh, polygon is None """ diff --git a/source/gameengine/PyDoc/KX_MeshProxy.py b/source/gameengine/PyDoc/KX_MeshProxy.py index e43fa3598f0..03bc36b6ac1 100644 --- a/source/gameengine/PyDoc/KX_MeshProxy.py +++ b/source/gameengine/PyDoc/KX_MeshProxy.py @@ -95,6 +95,21 @@ class KX_MeshProxy: @rtype: L{KX_VertexProxy} @return: a vertex object. """ + def getNumPolygons(): + """ + Returns the number of polygon in the mesh. + + @rtype: integer + """ + def getPolygon(index): + """ + Gets the specified polygon from the mesh. + + @type index: integer + @param index: polygon number + @rtype: L{KX_PolyProxy} + @return: a polygon object. + """ def reinstancePhysicsMesh(): """ Updates the physics system with the changed mesh. diff --git a/source/gameengine/PyDoc/KX_PolyProxy.py b/source/gameengine/PyDoc/KX_PolyProxy.py new file mode 100644 index 00000000000..45ae30a13dd --- /dev/null +++ b/source/gameengine/PyDoc/KX_PolyProxy.py @@ -0,0 +1,100 @@ +# $Id$ +# Documentation for the polygon proxy class + +class KX_PolyProxy: + """ + A polygon holds the index of the vertex forming the poylgon. + + Note: + The polygon attributes are read-only, you need to retrieve the vertex proxy if you want + to change the vertex settings. + + @ivar matname: The name of polygon material, empty if no material. + @type matname: string + @ivar material: The material of the polygon + @type material: L{KX_PolygonMaterial} or KX_BlenderMaterial + @ivar texture: The texture name of the polygon. + @type texture: string + @ivar matid: The material index of the polygon, use this to retrieve vertex proxy from mesh proxy + @type matid: integer + @ivar v1: vertex index of the first vertex of the polygon, use this to retrieve vertex proxy from mesh proxy + @type v1: integer + @ivar v2: vertex index of the second vertex of the polygon, use this to retrieve vertex proxy from mesh proxy + @type v2: integer + @ivar v3: vertex index of the third vertex of the polygon, use this to retrieve vertex proxy from mesh proxy + @type v3: integer + @ivar v4: vertex index of the fourth vertex of the polygon, 0 if polygon has only 3 vertex + use this to retrieve vertex proxy from mesh proxy + @type v4: integer + @ivar visible: visible state of the polygon: 1=visible, 0=invisible + @type visible: integer + @ivar collide: collide state of the polygon: 1=receives collision, 0=collision free. + @type collide: integer + """ + + def getMaterialName(): + """ + Returns the polygon material name with MA prefix + + @rtype: string + @return: material name + """ + def getMaterial(): + """ + Returns the polygon material + + @rtype: L{KX_PolygonMaterial} or KX_BlenderMaterial + """ + def getTextureName(): + """ + Returns the polygon texture name + + @rtype: string + @return: texture name + """ + def getMaterialIndex(): + """ + Returns the material bucket index of the polygon. + This index and the ones returned by getVertexIndex() are needed to retrieve the vertex proxy from L{KX_MeshProxy}. + + @rtype: integer + @return: the material index in the mesh + + def getNumVertex(): + """ + Returns the number of vertex of the polygon. + + @rtype: integer + @return: number of vertex, 3 or 4. + """ + def isVisible(): + """ + Returns whether the polygon is visible or not + + @rtype: integer + @return: 0=invisible, 1=visible + """ + def isCollider(): + """ + Returns whether the polygon is receives collision or not + + @rtype: integer + @return: 0=collision free, 1=receives collision + """ + def getVertexIndex(vertex): + """ + Returns the mesh vertex index of a polygon vertex + This index and the one returned by getMaterialIndex() are needed to retrieve the vertex proxy from L{KX_MeshProxy}. + + @type vertex: integer + @param vertex: index of the vertex in the polygon: 0->3 + @rtype: integer + @return: mesh vertex index + """ + def getMesh(): + """ + Returns a mesh proxy + + @rtype: L{KX_MeshProxy} + @return: mesh proxy + """ diff --git a/source/gameengine/PyDoc/KX_SCA_AddObjectActuator.py b/source/gameengine/PyDoc/KX_SCA_AddObjectActuator.py index 4f2bf85bff3..c3b2e947ddb 100644 --- a/source/gameengine/PyDoc/KX_SCA_AddObjectActuator.py +++ b/source/gameengine/PyDoc/KX_SCA_AddObjectActuator.py @@ -66,6 +66,23 @@ class KX_SCA_AddObjectActuator(SCA_IActuator): @rtype: list [vx, vy, vz] """ + def setAngularVelocity(vx, vy, vz): + """ + Sets the initial angular velocity of added objects. + + @type vx: float + @param vx: the x component of the initial angular velocity. + @type vy: float + @param vy: the y component of the initial angular velocity. + @type vz: float + @param vz: the z component of the initial angular velocity. + """ + def getAngularVelocity(): + """ + Returns the initial angular velocity of added objects. + + @rtype: list [vx, vy, vz] + """ def getLastCreatedObject(): """ Returns the last object created by this actuator. diff --git a/source/gameengine/PyDoc/SCA_DelaySensor.py b/source/gameengine/PyDoc/SCA_DelaySensor.py new file mode 100644 index 00000000000..46b74f461a7 --- /dev/null +++ b/source/gameengine/PyDoc/SCA_DelaySensor.py @@ -0,0 +1,56 @@ +# $Id$ +# Documentation for SCA_DelaySensor +from SCA_IActuator import * + +class SCA_DelaySensor(SCA_ISensor): + """ + The Delay sensor generates positive and negative triggers at precise time, + expressed in number of frames. The delay parameter defines the length + of the initial OFF period. A positive trigger is generated at the end of this period. + The duration parameter defines the length of the ON period following the OFF period. + There is a negative trigger at the end of the ON period. If duration is 0, the sensor + stays ON and there is no negative trigger. + The sensor runs the OFF-ON cycle once unless the repeat option is set: the + OFF-ON cycle repeats indefinately (or the OFF cycle if duration is 0). + Use SCA_ISensor::reset() at any time to restart sensor. + """ + def setDelay(delay): + """ + Set the initial delay before the positive trigger. + + @param delay: length of the initial OFF period as number of frame, 0 for immediate trigger + @type delay: integer + """ + def setDuration(duration): + """ + Set the duration of the ON pulse after initial delay and the generation of the positive trigger. + If duration is greater than 0, a negative trigger is sent at the end of the ON pulse. + + @param duration: length of the ON period in number of frame after the initial OFF period + @type duration: integer + """ + def setRepeat(repeat): + """ + Set if the sensor repeat mode. + + @param repeat: 1 if the OFF-ON cycle should be repeated indefinately, 0 if it should run once. + @type repeat: integer + """ + def getDelay(): + """ + Return the delay parameter value. + + @rtype: integer + """ + def getDuration(): + """ + Return the duration parameter value + + @rtype: integer + """ + def getRepeat(): + """ + Return the repeat parameter value + + @rtype: KX_TRUE or KX_FALSE + """ diff --git a/source/gameengine/PyDoc/SCA_ISensor.py b/source/gameengine/PyDoc/SCA_ISensor.py index 0ebc2debb31..14858505e24 100644 --- a/source/gameengine/PyDoc/SCA_ISensor.py +++ b/source/gameengine/PyDoc/SCA_ISensor.py @@ -9,7 +9,12 @@ class SCA_ISensor(SCA_ILogicBrick): def isPositive(): """ - True if this sensor brick has been activated. + True if this sensor brick is in a positive state. + """ + + def isTriggered(): + """ + True if this sensor brick has triggered the current controller. """ def getUsePosPulseMode(): @@ -77,4 +82,10 @@ class SCA_ISensor(SCA_ILogicBrick): @param level: Detect level instead of edge? (KX_TRUE, KX_FALSE) @type level: boolean """ + def reset(): + """ + Reset sensor internal state, effect depends on the type of sensor and settings. + + The sensor is put in its initial state as if it was just activated. + """ diff --git a/source/gameengine/Rasterizer/RAS_MeshObject.cpp b/source/gameengine/Rasterizer/RAS_MeshObject.cpp index af5228e4c35..a4f7f3f01dd 100644 --- a/source/gameengine/Rasterizer/RAS_MeshObject.cpp +++ b/source/gameengine/Rasterizer/RAS_MeshObject.cpp @@ -134,7 +134,7 @@ int RAS_MeshObject::NumPolygons() -RAS_Polygon* RAS_MeshObject::GetPolygon(int num) +RAS_Polygon* RAS_MeshObject::GetPolygon(int num) const { return m_Polygons[num]; } diff --git a/source/gameengine/Rasterizer/RAS_MeshObject.h b/source/gameengine/Rasterizer/RAS_MeshObject.h index 99806666fa6..9a46d89c393 100644 --- a/source/gameengine/Rasterizer/RAS_MeshObject.h +++ b/source/gameengine/Rasterizer/RAS_MeshObject.h @@ -178,7 +178,7 @@ public: void UpdateMaterialList(); int NumPolygons(); - RAS_Polygon* GetPolygon(int num); + RAS_Polygon* GetPolygon(int num) const; virtual void Bucketize( double* oglmatrix, diff --git a/source/kernel/CMakeLists.txt b/source/kernel/CMakeLists.txt index 3d966152cc5..ac759393326 100644 --- a/source/kernel/CMakeLists.txt +++ b/source/kernel/CMakeLists.txt @@ -24,7 +24,7 @@ # # ***** END GPL LICENSE BLOCK ***** -SET(INC gen_messaging gen_system ../../intern/string ../../intern/moto/include) +SET(INC gen_messaging gen_system ../../intern/string ../../intern/moto/include ../../source/blender/blenloader ) FILE(GLOB SRC gen_messaging/intern/messaging.c diff --git a/source/kernel/SConscript b/source/kernel/SConscript index 9e678c041dc..8bd1a18f835 100644 --- a/source/kernel/SConscript +++ b/source/kernel/SConscript @@ -5,6 +5,6 @@ sources = 'gen_messaging/intern/messaging.c gen_system/GEN_HashedPtr.cpp' sources += ' gen_system/GEN_Matrix4x4.cpp gen_system/SYS_SingletonSystem.cpp' sources += ' gen_system/SYS_System.cpp' -incs = 'gen_messaging gen_system #/intern/string #/intern/moto/include' +incs = 'gen_messaging gen_system #/intern/string #/intern/moto/include #/source/blender/blenloader ' env.BlenderLib ( 'bf_kernel', Split(sources), Split(incs), [], libtype = ['common','game2', 'player'], priority = [15, 10, 150] ) diff --git a/source/kernel/gen_system/GEN_HashedPtr.cpp b/source/kernel/gen_system/GEN_HashedPtr.cpp index 49ccb252246..6dbed1fb7a8 100644 --- a/source/kernel/gen_system/GEN_HashedPtr.cpp +++ b/source/kernel/gen_system/GEN_HashedPtr.cpp @@ -33,6 +33,8 @@ #include <config.h> #endif +#include "BLO_sys_types.h" // for intptr_t support + // // Build hash index from pointer. Even though the final result // is a 32-bit integer, use all the bits of the pointer as long @@ -41,11 +43,7 @@ unsigned int GEN_Hash(void * inDWord) { -#if defined(_WIN64) - unsigned __int64 key = (unsigned __int64)inDWord; -#else - unsigned long key = (unsigned long)inDWord; -#endif + uintptr_t key = (uintptr_t)inDWord; key += ~(key << 16); key ^= (key >> 5); diff --git a/source/kernel/gen_system/Makefile b/source/kernel/gen_system/Makefile index 855af376615..31535ad2a97 100644 --- a/source/kernel/gen_system/Makefile +++ b/source/kernel/gen_system/Makefile @@ -37,4 +37,5 @@ CCFLAGS += $(LEVEL_2_CPP_WARNINGS) CPPFLAGS += -I$(NAN_MOTO)/include CPPFLAGS += -I$(NAN_STRING)/include +CPPFLAGS += -I../../../source/blender/blenloader diff --git a/source/nan_definitions.mk b/source/nan_definitions.mk index 9c1a28de999..6200d430dd4 100644 --- a/source/nan_definitions.mk +++ b/source/nan_definitions.mk @@ -287,7 +287,7 @@ endif export FREEDESKTOP ?= true export NAN_PYTHON ?= /usr/local - export NAN_PYTHON_VERSION ?= 2.3 + export NAN_PYTHON_VERSION ?= 2.5 export NAN_PYTHON_BINARY ?= $(NAN_PYTHON)/bin/python$(NAN_PYTHON_VERSION) export NAN_PYTHON_LIB ?= $(NAN_PYTHON)/lib/python$(NAN_PYTHON_VERSION)/config/libpython$(NAN_PYTHON_VERSION).a export NAN_OPENAL ?= /usr/local @@ -302,9 +302,9 @@ endif export NAN_NSPR ?= /usr/local export NAN_FREETYPE ?= $(LCGDIR)/freetype export NAN_GETTEXT ?= $(LCGDIR)/gettext - export NAN_SDL ?= $(shell sdl11-config --prefix) - export NAN_SDLLIBS ?= $(shell sdl11-config --libs) - export NAN_SDLCFLAGS ?= $(shell sdl11-config --cflags) + export NAN_SDL ?= $(shell sdl-config --prefix) + export NAN_SDLLIBS ?= $(shell sdl-config --libs) + export NAN_SDLCFLAGS ?= $(shell sdl-config --cflags) # Uncomment the following line to use Mozilla inplace of netscape # CPPFLAGS +=-DMOZ_NOT_NET |