diff options
Diffstat (limited to 'source')
154 files changed, 5223 insertions, 2698 deletions
diff --git a/source/blender/blenkernel/BKE_DerivedMesh.h b/source/blender/blenkernel/BKE_DerivedMesh.h index f61b300f708..7dc10c53e22 100644 --- a/source/blender/blenkernel/BKE_DerivedMesh.h +++ b/source/blender/blenkernel/BKE_DerivedMesh.h @@ -437,5 +437,7 @@ void weight_to_rgb(float input, float *fr, float *fg, float *fb); /* determines required DerivedMesh data according to view and edit modes */ CustomDataMask get_viewedit_datamask(); +void DM_add_tangent_layer(DerivedMesh *dm); + #endif diff --git a/source/blender/blenkernel/BKE_blender.h b/source/blender/blenkernel/BKE_blender.h index f76cdbc64b7..d951c8401e3 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 246 -#define BLENDER_SUBVERSION 0 +#define BLENDER_SUBVERSION 1 #define BLENDER_MINVERSION 245 #define BLENDER_MINSUBVERSION 15 diff --git a/source/blender/blenkernel/BKE_bvhutils.h b/source/blender/blenkernel/BKE_bvhutils.h new file mode 100644 index 00000000000..dd9ea61f24b --- /dev/null +++ b/source/blender/blenkernel/BKE_bvhutils.h @@ -0,0 +1,98 @@ +/** + * + * $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) 2006 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): André Pinto + * + * ***** END GPL LICENSE BLOCK ***** + */ +#ifndef BKE_BVHUTILS_H +#define BKE_BVHUTILS_H + +#include "BLI_kdopbvh.h" + +/* + * This header encapsulates necessary code to buld a BVH + */ + +struct DerivedMesh; +struct MVert; +struct MFace; + +/* + * struct that kepts basic information about a BVHTree build from a mesh + */ +typedef struct BVHTreeFromMesh +{ + struct BVHTree *tree; + + /* default callbacks to bvh nearest and raycast */ + BVHTree_NearestPointCallback nearest_callback; + BVHTree_RayCastCallback raycast_callback; + + /* Mesh represented on this BVHTree */ + struct DerivedMesh *mesh; + + /* Vertex array, so that callbacks have instante access to data */ + struct MVert *vert; + struct MFace *face; + + /* radius for raycast */ + float sphere_radius; + +} BVHTreeFromMesh; + +/* + * Builds a bvh tree where nodes are the vertexs of the given mesh. + * Configures BVHTreeFromMesh. + * + * The tree is build in mesh space coordinates, this means special care must be made on queries + * so that the coordinates and rays are first translated on the mesh local coordinates. + * Reason for this is that later bvh_from_mesh_* might use a cache system and so it becames possible to reuse + * a BVHTree. + * + * free_bvhtree_from_mesh should be called when the tree is no longer needed. + */ +void bvhtree_from_mesh_verts(struct BVHTreeFromMesh *data, struct DerivedMesh *mesh, float epsilon, int tree_type, int axis); + +/* + * Builds a bvh tree where nodes are the faces of the given mesh. + * Configures BVHTreeFromMesh. + * + * The tree is build in mesh space coordinates, this means special care must be made on queries + * so that the coordinates and rays are first translated on the mesh local coordinates. + * Reason for this is that later bvh_from_mesh_* might use a cache system and so it becames possible to reuse + * a BVHTree. + * + * free_bvhtree_from_mesh should be called when the tree is no longer needed. + */ +void bvhtree_from_mesh_faces(struct BVHTreeFromMesh *data, struct DerivedMesh *mesh, float epsilon, int tree_type, int axis); + +/* + * Frees data allocated by a call to bvhtree_from_mesh_*. + */ +void free_bvhtree_from_mesh(struct BVHTreeFromMesh *data); + +#endif + diff --git a/source/blender/blenkernel/BKE_texture.h b/source/blender/blenkernel/BKE_texture.h index 78a8f60caeb..c162a04e055 100644 --- a/source/blender/blenkernel/BKE_texture.h +++ b/source/blender/blenkernel/BKE_texture.h @@ -62,6 +62,7 @@ struct Tex *copy_texture(struct Tex *tex); void make_local_texture(struct Tex *tex); void autotexname(struct Tex *tex); struct Tex *give_current_texture(struct Object *ob, int act); +struct Tex *give_current_world_texture(void); struct TexMapping *add_mapping(void); void init_mapping(struct TexMapping *texmap); @@ -72,6 +73,7 @@ void BKE_free_envmap(struct EnvMap *env); struct EnvMap *BKE_add_envmap(void); struct EnvMap *BKE_copy_envmap(struct EnvMap *env); +int BKE_texture_dependsOnTime(const struct Tex *texture); #endif diff --git a/source/blender/blenkernel/bad_level_call_stubs/stubs.c b/source/blender/blenkernel/bad_level_call_stubs/stubs.c index 3ad11a61de3..561d8d7c2a6 100644 --- a/source/blender/blenkernel/bad_level_call_stubs/stubs.c +++ b/source/blender/blenkernel/bad_level_call_stubs/stubs.c @@ -117,10 +117,14 @@ float BPY_pydriver_eval(struct IpoDriver *driver) { return 0; } + +/* int EXPP_dict_set_item_str(struct PyObject *dict, char *key, struct PyObject *value) { return 0; } +*/ + void Node_SetStack(struct BPy_Node *self, struct bNodeStack **stack, int type){} void InitNode(struct BPy_Node *self, struct bNode *node){} void Node_SetShi(struct BPy_Node *self, struct ShadeInput *shi){} diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c index bc55332a450..01381ac542b 100644 --- a/source/blender/blenkernel/intern/DerivedMesh.c +++ b/source/blender/blenkernel/intern/DerivedMesh.c @@ -59,6 +59,7 @@ #include "BLI_edgehash.h" #include "BLI_editVert.h" #include "BLI_linklist.h" +#include "BLI_memarena.h" #include "BKE_cdderivedmesh.h" #include "BKE_customdata.h" @@ -2759,6 +2760,127 @@ int editmesh_get_first_deform_matrices(float (**deformmats)[3][3], float (**defo return numleft; } +void DM_add_tangent_layer(DerivedMesh *dm) +{ + /* mesh vars */ + MTFace *mtface, *tf; + MFace *mface, *mf; + MVert *mvert, *v1, *v2, *v3, *v4; + MemArena *arena= NULL; + VertexTangent **vtangents= NULL; + float (*orco)[3]= NULL, (*tangent)[3]; + float *uv1, *uv2, *uv3, *uv4, *vtang; + float fno[3], tang[3], uv[4][2]; + int i, j, len, mf_vi[4], totvert, totface; + + if(CustomData_get_layer_index(&dm->faceData, CD_TANGENT) != -1) + return; + + /* check we have all the needed layers */ + totvert= dm->getNumVerts(dm); + totface= dm->getNumFaces(dm); + + mvert= dm->getVertArray(dm); + mface= dm->getFaceArray(dm); + mtface= dm->getFaceDataArray(dm, CD_MTFACE); + + if(!mtface) { + orco= dm->getVertDataArray(dm, CD_ORCO); + if(!orco) + return; + } + + /* create tangent layer */ + DM_add_face_layer(dm, CD_TANGENT, CD_CALLOC, NULL); + tangent= DM_get_face_data_layer(dm, CD_TANGENT); + + /* allocate some space */ + arena= BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE); + BLI_memarena_use_calloc(arena); + vtangents= MEM_callocN(sizeof(VertexTangent*)*totvert, "VertexTangent"); + + /* sum tangents at connected vertices */ + for(i=0, tf=mtface, mf=mface; i < totface; mf++, tf++, i++) { + v1= &mvert[mf->v1]; + v2= &mvert[mf->v2]; + v3= &mvert[mf->v3]; + + if (mf->v4) { + v4= &mvert[mf->v4]; + CalcNormFloat4(v4->co, v3->co, v2->co, v1->co, fno); + } + else { + v4= NULL; + CalcNormFloat(v3->co, v2->co, v1->co, fno); + } + + if(mtface) { + uv1= tf->uv[0]; + uv2= tf->uv[1]; + uv3= tf->uv[2]; + uv4= tf->uv[3]; + } + else { + uv1= uv[0]; uv2= uv[1]; uv3= uv[2]; uv4= uv[3]; + spheremap(orco[mf->v1][0], orco[mf->v1][1], orco[mf->v1][2], &uv[0][0], &uv[0][1]); + spheremap(orco[mf->v2][0], orco[mf->v2][1], orco[mf->v2][2], &uv[1][0], &uv[1][1]); + spheremap(orco[mf->v3][0], orco[mf->v3][1], orco[mf->v3][2], &uv[2][0], &uv[2][1]); + if(v4) + spheremap(orco[mf->v4][0], orco[mf->v4][1], orco[mf->v4][2], &uv[3][0], &uv[3][1]); + } + + tangent_from_uv(uv1, uv2, uv3, v1->co, v2->co, v3->co, fno, tang); + sum_or_add_vertex_tangent(arena, &vtangents[mf->v1], tang, uv1); + sum_or_add_vertex_tangent(arena, &vtangents[mf->v2], tang, uv2); + sum_or_add_vertex_tangent(arena, &vtangents[mf->v3], tang, uv3); + + if(mf->v4) { + v4= &mvert[mf->v4]; + + tangent_from_uv(uv1, uv3, uv4, v1->co, v3->co, v4->co, fno, tang); + sum_or_add_vertex_tangent(arena, &vtangents[mf->v1], tang, uv1); + sum_or_add_vertex_tangent(arena, &vtangents[mf->v3], tang, uv3); + sum_or_add_vertex_tangent(arena, &vtangents[mf->v4], tang, uv4); + } + } + + /* write tangent to layer */ + for(i=0, tf=mtface, mf=mface; i < totface; mf++, tf++, i++, tangent+=4) { + len= (mf->v4)? 4 : 3; + + if(mtface) { + uv1= tf->uv[0]; + uv2= tf->uv[1]; + uv3= tf->uv[2]; + uv4= tf->uv[3]; + } + else { + uv1= uv[0]; uv2= uv[1]; uv3= uv[2]; uv4= uv[3]; + spheremap(orco[mf->v1][0], orco[mf->v1][1], orco[mf->v1][2], &uv[0][0], &uv[0][1]); + spheremap(orco[mf->v2][0], orco[mf->v2][1], orco[mf->v2][2], &uv[1][0], &uv[1][1]); + spheremap(orco[mf->v3][0], orco[mf->v3][1], orco[mf->v3][2], &uv[2][0], &uv[2][1]); + if(len==4) + spheremap(orco[mf->v4][0], orco[mf->v4][1], orco[mf->v4][2], &uv[3][0], &uv[3][1]); + } + + mf_vi[0]= mf->v1; + mf_vi[1]= mf->v2; + mf_vi[2]= mf->v3; + mf_vi[3]= mf->v4; + + for(j=0; j<len; j++) { + vtang= find_vertex_tangent(vtangents[mf_vi[j]], mtface ? tf->uv[j] : uv[j]); + + VECCOPY(tangent[j], vtang); + Normalize(tangent[j]); + } + } + + BLI_memarena_free(arena); + MEM_freeN(vtangents); +} + + /* ************************* fluidsim bobj file handling **************************** */ #ifndef DISABLE_ELBEEM diff --git a/source/blender/blenkernel/intern/anim.c b/source/blender/blenkernel/intern/anim.c index 1f8dd74a6eb..1592c3e5504 100644 --- a/source/blender/blenkernel/intern/anim.c +++ b/source/blender/blenkernel/intern/anim.c @@ -734,9 +734,8 @@ static void new_particle_duplilist(ListBase *lb, ID *id, Object *par, float par_ ParticleCacheKey *cache; ParticleSystemModifierData *psmd; float ctime, pa_time, scale = 1.0f; - float tmat[4][4], mat[4][4], obrotmat[4][4], pamat[4][4], size=0.0; + float tmat[4][4], mat[4][4], pamat[4][4], size=0.0; float (*obmat)[4], (*oldobmat)[4]; - float xvec[3] = {-1.0, 0.0, 0.0}, q[4]; int lay, a, b, k, step_nbr = 0, counter, hair = 0; int totpart, totchild, totgroup=0, pa_num; @@ -898,14 +897,7 @@ static void new_particle_duplilist(ListBase *lb, ID *id, Object *par, float par_ /* to give ipos in object correct offset */ where_is_object_time(ob, ctime-pa_time); - if(!hair) { - vectoquat(xvec, ob->trackflag, ob->upflag, q); - QuatToMat4(q, obrotmat); - obrotmat[3][3]= 1.0f; - Mat4MulMat4(mat, obrotmat, pamat); - } - else - Mat4CpyMat4(mat, pamat); + Mat4CpyMat4(mat, pamat); Mat4MulMat4(tmat, obmat, mat); Mat4MulFloat3((float *)tmat, size*scale); diff --git a/source/blender/blenkernel/intern/bvhutils.c b/source/blender/blenkernel/intern/bvhutils.c new file mode 100644 index 00000000000..042e2afad53 --- /dev/null +++ b/source/blender/blenkernel/intern/bvhutils.c @@ -0,0 +1,577 @@ +/** + * + * $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) Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): André Pinto. + * + * ***** END GPL LICENSE BLOCK ***** + */ +#include <stdio.h> +#include <string.h> +#include <math.h> + +#include "BKE_bvhutils.h" + +#include "DNA_object_types.h" +#include "DNA_modifier_types.h" +#include "DNA_meshdata_types.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 "BLI_arithb.h" + +/* Math stuff for ray casting on mesh faces and for nearest surface */ + +static float ray_tri_intersection(const BVHTreeRay *ray, const float m_dist, const float *v0, const float *v1, const float *v2) +{ + float dist; + + if(RayIntersectsTriangle((float*)ray->origin, (float*)ray->direction, (float*)v0, (float*)v1, (float*)v2, &dist, NULL)) + return dist; + + return FLT_MAX; +} + +static float sphereray_tri_intersection(const BVHTreeRay *ray, float radius, const float m_dist, const float *v0, const float *v1, const float *v2) +{ + + float idist; + float p1[3]; + float plane_normal[3], hit_point[3]; + + CalcNormFloat((float*)v0, (float*)v1, (float*)v2, plane_normal); + + VECADDFAC( p1, ray->origin, ray->direction, m_dist); + if(SweepingSphereIntersectsTriangleUV((float*)ray->origin, p1, radius, (float*)v0, (float*)v1, (float*)v2, &idist, hit_point)) + { + return idist * m_dist; + } + + return FLT_MAX; +} + + +/* + * 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 ) +{ + float diff[3]; + float e0[3]; + float e1[3]; + float A00; + float A01; + float A11; + float B0; + float B1; + float C; + float Det; + float S; + float T; + float sqrDist; + int lv = -1, le = -1; + + VECSUB(diff, v0, p); + VECSUB(e0, v1, v0); + VECSUB(e1, v2, v0); + + A00 = INPR ( e0, e0 ); + A01 = INPR( e0, e1 ); + A11 = INPR ( e1, e1 ); + B0 = INPR( diff, e0 ); + B1 = INPR( diff, e1 ); + C = INPR( diff, diff ); + Det = fabs( A00 * A11 - A01 * A01 ); + S = A01 * B1 - A11 * B0; + T = A01 * B0 - A00 * B1; + + if ( S + T <= Det ) + { + if ( S < 0.0f ) + { + if ( T < 0.0f ) // Region 4 + { + if ( B0 < 0.0f ) + { + T = 0.0f; + if ( -B0 >= A00 ) + { + S = (float)1.0; + sqrDist = A00 + 2.0f * B0 + C; + lv = 1; + } + else + { + if(fabs(A00) > FLT_EPSILON) + S = -B0/A00; + else + S = 0.0f; + sqrDist = B0 * S + C; + le = 0; + } + } + else + { + S = 0.0f; + if ( B1 >= 0.0f ) + { + T = 0.0f; + sqrDist = C; + lv = 0; + } + else if ( -B1 >= A11 ) + { + T = 1.0f; + sqrDist = A11 + 2.0f * B1 + C; + lv = 2; + } + else + { + if(fabs(A11) > FLT_EPSILON) + T = -B1 / A11; + else + T = 0.0f; + sqrDist = B1 * T + C; + le = 1; + } + } + } + else // Region 3 + { + S = 0.0f; + if ( B1 >= 0.0f ) + { + T = 0.0f; + sqrDist = C; + lv = 0; + } + else if ( -B1 >= A11 ) + { + T = 1.0f; + sqrDist = A11 + 2.0f * B1 + C; + lv = 2; + } + else + { + if(fabs(A11) > FLT_EPSILON) + T = -B1 / A11; + else + T = 0.0; + sqrDist = B1 * T + C; + le = 1; + } + } + } + else if ( T < 0.0f ) // Region 5 + { + T = 0.0f; + if ( B0 >= 0.0f ) + { + S = 0.0f; + sqrDist = C; + lv = 0; + } + else if ( -B0 >= A00 ) + { + S = 1.0f; + sqrDist = A00 + 2.0f * B0 + C; + lv = 1; + } + else + { + if(fabs(A00) > FLT_EPSILON) + S = -B0 / A00; + else + S = 0.0f; + sqrDist = B0 * S + C; + le = 0; + } + } + else // Region 0 + { + // Minimum at interior lv + float invDet; + if(fabs(Det) > FLT_EPSILON) + invDet = 1.0f / Det; + else + invDet = 0.0f; + S *= invDet; + T *= invDet; + sqrDist = S * ( A00 * S + A01 * T + 2.0f * B0) + + T * ( A01 * S + A11 * T + 2.0f * B1 ) + C; + } + } + else + { + float tmp0, tmp1, numer, denom; + + if ( S < 0.0f ) // Region 2 + { + tmp0 = A01 + B0; + tmp1 = A11 + B1; + if ( tmp1 > tmp0 ) + { + numer = tmp1 - tmp0; + denom = A00 - 2.0f * A01 + A11; + if ( numer >= denom ) + { + S = 1.0f; + T = 0.0f; + sqrDist = A00 + 2.0f * B0 + C; + lv = 1; + } + else + { + if(fabs(denom) > FLT_EPSILON) + S = numer / denom; + else + S = 0.0f; + T = 1.0f - S; + sqrDist = S * ( A00 * S + A01 * T + 2.0f * B0 ) + + T * ( A01 * S + A11 * T + 2.0f * B1 ) + C; + le = 2; + } + } + else + { + S = 0.0f; + if ( tmp1 <= 0.0f ) + { + T = 1.0f; + sqrDist = A11 + 2.0f * B1 + C; + lv = 2; + } + else if ( B1 >= 0.0f ) + { + T = 0.0f; + sqrDist = C; + lv = 0; + } + else + { + if(fabs(A11) > FLT_EPSILON) + T = -B1 / A11; + else + T = 0.0f; + sqrDist = B1 * T + C; + le = 1; + } + } + } + else if ( T < 0.0f ) // Region 6 + { + tmp0 = A01 + B1; + tmp1 = A00 + B0; + if ( tmp1 > tmp0 ) + { + numer = tmp1 - tmp0; + denom = A00 - 2.0f * A01 + A11; + if ( numer >= denom ) + { + T = 1.0f; + S = 0.0f; + sqrDist = A11 + 2.0f * B1 + C; + lv = 2; + } + else + { + if(fabs(denom) > FLT_EPSILON) + T = numer / denom; + else + T = 0.0f; + S = 1.0f - T; + sqrDist = S * ( A00 * S + A01 * T + 2.0f * B0 ) + + T * ( A01 * S + A11 * T + 2.0f * B1 ) + C; + le = 2; + } + } + else + { + T = 0.0f; + if ( tmp1 <= 0.0f ) + { + S = 1.0f; + sqrDist = A00 + 2.0f * B0 + C; + lv = 1; + } + else if ( B0 >= 0.0f ) + { + S = 0.0f; + sqrDist = C; + lv = 0; + } + else + { + if(fabs(A00) > FLT_EPSILON) + S = -B0 / A00; + else + S = 0.0f; + sqrDist = B0 * S + C; + le = 0; + } + } + } + else // Region 1 + { + numer = A11 + B1 - A01 - B0; + if ( numer <= 0.0f ) + { + S = 0.0f; + T = 1.0f; + sqrDist = A11 + 2.0f * B1 + C; + lv = 2; + } + else + { + denom = A00 - 2.0f * A01 + A11; + if ( numer >= denom ) + { + S = 1.0f; + T = 0.0f; + sqrDist = A00 + 2.0f * B0 + C; + lv = 1; + } + else + { + if(fabs(denom) > FLT_EPSILON) + S = numer / denom; + else + S = 0.0f; + T = 1.0f - S; + sqrDist = S * ( A00 * S + A01 * T + 2.0f * B0 ) + + T * ( A01 * S + A11 * T + 2.0f * B1 ) + C; + le = 2; + } + } + } + } + + // Account for numerical round-off error + if ( sqrDist < FLT_EPSILON ) + sqrDist = 0.0f; + + { + float w[3], x[3], y[3], z[3]; + VECCOPY(w, v0); + VECCOPY(x, e0); + VecMulf(x, S); + VECCOPY(y, e1); + VecMulf(y, T); + VECADD(z, w, x); + VECADD(z, z, y); + VECSUB(d, p, z); + VECCOPY(nearest, z); + // d = p - ( v0 + S * e0 + T * e1 ); + } + *v = lv; + *e = le; + + return sqrDist; +} + + +/* + * BVH from meshs callbacks + */ + +// Callback to bvh tree nearest point. The tree must bust have been built using bvhtree_from_mesh_faces. +// userdata must be a BVHMeshCallbackUserdata built from the same mesh as the tree. +static void mesh_faces_nearest_point(void *userdata, int index, const float *co, BVHTreeNearest *nearest) +{ + const BVHTreeFromMesh *data = (BVHTreeFromMesh*) userdata; + MVert *vert = data->vert; + MFace *face = data->face + index; + + float *t0, *t1, *t2, *t3; + t0 = vert[ face->v1 ].co; + t1 = vert[ face->v2 ].co; + t2 = vert[ face->v3 ].co; + t3 = face->v4 ? vert[ face->v4].co : NULL; + + + do + { + float nearest_tmp[3], col_normal[3], dist; + int vertex, edge; + + dist = nearest_point_in_tri_surface(t0, t1, t2, co, &vertex, &edge, col_normal, nearest_tmp); + if(dist < nearest->dist) + { + nearest->index = index; + nearest->dist = dist; + VECCOPY(nearest->co, nearest_tmp); + VECCOPY(nearest->no, col_normal); + } + + t1 = t2; + t2 = t3; + t3 = NULL; + + } while(t2); +} + +// Callback to bvh tree raycast. The tree must bust have been built using bvhtree_from_mesh_faces. +// userdata must be a BVHMeshCallbackUserdata built from the same mesh as the tree. +static void mesh_faces_spherecast(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit) +{ + const BVHTreeFromMesh *data = (BVHTreeFromMesh*) userdata; + MVert *vert = data->vert; + MFace *face = data->face + index; + + float *t0, *t1, *t2, *t3; + t0 = vert[ face->v1 ].co; + t1 = vert[ face->v2 ].co; + t2 = vert[ face->v3 ].co; + t3 = face->v4 ? vert[ face->v4].co : NULL; + + + do + { + float dist; + if(data->sphere_radius == 0.0f) + dist = ray_tri_intersection(ray, hit->dist, t0, t1, t2); + else + dist = sphereray_tri_intersection(ray, data->sphere_radius, hit->dist, t0, t1, t2); + + if(dist >= 0 && dist < hit->dist) + { + hit->index = index; + hit->dist = dist; + VECADDFAC(hit->co, ray->origin, ray->direction, dist); + + CalcNormFloat(t0, t1, t2, hit->no); + } + + t1 = t2; + t2 = t3; + t3 = NULL; + + } while(t2); +} + +/* + * BVH builders + */ +// Builds a bvh tree.. where nodes are the vertexs of the given mesh +void bvhtree_from_mesh_verts(BVHTreeFromMesh *data, DerivedMesh *mesh, float epsilon, int tree_type, int axis) +{ + int i; + int numVerts= mesh->getNumVerts(mesh); + MVert *vert = mesh->getVertDataArray(mesh, CD_MVERT); + BVHTree *tree = NULL; + + memset(data, 0, sizeof(*data)); + + if(vert == NULL) + { + printf("bvhtree cant be build: cant get a vertex array"); + return; + } + + tree = BLI_bvhtree_new(numVerts, epsilon, tree_type, axis); + if(tree != NULL) + { + for(i = 0; i < numVerts; i++) + BLI_bvhtree_insert(tree, i, vert[i].co, 1); + + BLI_bvhtree_balance(tree); + + data->tree = tree; + + //a NULL nearest callback works fine + //remeber the min distance to point is the same as the min distance to BV of point + data->nearest_callback = NULL; + data->raycast_callback = NULL; + + data->mesh = mesh; + data->vert = mesh->getVertDataArray(mesh, CD_MVERT); + data->face = mesh->getFaceDataArray(mesh, CD_MFACE); + + data->sphere_radius = epsilon; + } +} + +// Builds a bvh tree.. where nodes are the faces of the given mesh. +void bvhtree_from_mesh_faces(BVHTreeFromMesh *data, DerivedMesh *mesh, float epsilon, int tree_type, int axis) +{ + int i; + int numFaces= mesh->getNumFaces(mesh); + MVert *vert = mesh->getVertDataArray(mesh, CD_MVERT); + MFace *face = mesh->getFaceDataArray(mesh, CD_MFACE); + BVHTree *tree = NULL; + + memset(data, 0, sizeof(*data)); + + if(vert == NULL && face == NULL) + { + printf("bvhtree cant be build: cant get a vertex/face array"); + return; + } + + /* Create a bvh-tree of the given target */ + tree = BLI_bvhtree_new(numFaces, epsilon, tree_type, axis); + if(tree != NULL) + { + for(i = 0; i < numFaces; i++) + { + float co[4][3]; + VECCOPY(co[0], vert[ face[i].v1 ].co); + VECCOPY(co[1], vert[ face[i].v2 ].co); + VECCOPY(co[2], vert[ face[i].v3 ].co); + if(face[i].v4) + VECCOPY(co[3], vert[ face[i].v4 ].co); + + BLI_bvhtree_insert(tree, i, co[0], face[i].v4 ? 4 : 3); + } + BLI_bvhtree_balance(tree); + + data->tree = tree; + data->nearest_callback = mesh_faces_nearest_point; + data->raycast_callback = mesh_faces_spherecast; + + data->mesh = mesh; + data->vert = mesh->getVertDataArray(mesh, CD_MVERT); + data->face = mesh->getFaceDataArray(mesh, CD_MFACE); + + data->sphere_radius = epsilon; + } +} + +// Frees data allocated by a call to bvhtree_from_mesh_*. +void free_bvhtree_from_mesh(struct BVHTreeFromMesh *data) +{ + if(data->tree) + { + BLI_bvhtree_free(data->tree); + memset( data, 0, sizeof(data) ); + } +} + + diff --git a/source/blender/blenkernel/intern/collision.c b/source/blender/blenkernel/intern/collision.c index 6dfb77504fb..cfcab54058d 100644 --- a/source/blender/blenkernel/intern/collision.c +++ b/source/blender/blenkernel/intern/collision.c @@ -1291,116 +1291,6 @@ int cloth_collision_moving ( ClothModifierData *clmd, CollisionModifierData *col return 1; } -int cloth_do_selfcollisions(ClothModifierData * clmd) -{ - int ret2 = 0, l; - Cloth *cloth = clmd->clothObject; - - if ( clmd->clothObject->bvhselftree ) - { - for(l = 0; l < clmd->coll_parms->self_loop_count; l++) - { - BVHTreeOverlap *overlap = NULL; - ClothVertex *verts = clmd->clothObject->verts; // needed for openMP - int k; - int ret = 0, result = 0; - - // search for overlapping collision pairs - overlap = BLI_bvhtree_overlap ( cloth->bvhselftree, cloth->bvhselftree, &result ); - -// #pragma omp parallel for private(k, i, j) schedule(static) - for ( k = 0; k < result; k++ ) - { - float temp[3]; - float length = 0; - float mindistance; - int i, j; - - i = overlap[k].indexA; - j = overlap[k].indexB; - - mindistance = clmd->coll_parms->selfepsilon* ( cloth->verts[i].avg_spring_len + cloth->verts[j].avg_spring_len ); - - if ( clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL ) - { - if ( ( cloth->verts [i].flags & CLOTH_VERT_FLAG_PINNED ) - && ( cloth->verts [j].flags & CLOTH_VERT_FLAG_PINNED ) ) - { - continue; - } - } - - VECSUB ( temp, verts[i].tx, verts[j].tx ); - - if ( ( ABS ( temp[0] ) > mindistance ) || ( ABS ( temp[1] ) > mindistance ) || ( ABS ( temp[2] ) > mindistance ) ) continue; - - // check for adjacent points (i must be smaller j) - if ( BLI_edgehash_haskey ( cloth->edgehash, MIN2(i, j), MAX2(i, j) ) ) - { - continue; - } - - length = Normalize ( temp ); - - if ( length < mindistance ) - { - float correction = mindistance - length; - - if ( cloth->verts [i].flags & CLOTH_VERT_FLAG_PINNED ) - { - VecMulf ( temp, -correction ); - VECADD ( verts[j].tx, verts[j].tx, temp ); - } - else if ( cloth->verts [j].flags & CLOTH_VERT_FLAG_PINNED ) - { - VecMulf ( temp, correction ); - VECADD ( verts[i].tx, verts[i].tx, temp ); - } - else - { - VecMulf ( temp, -correction*0.5 ); - VECADD ( verts[j].tx, verts[j].tx, temp ); - - VECSUB ( verts[i].tx, verts[i].tx, temp ); - } - ret = 1; - ret2 += ret; - } - else - { - // check for approximated time collisions - } - } - - if ( overlap ) - MEM_freeN ( overlap ); - - if(!ret) - break; - - } - //////////////////////////////////////////////////////////// - - //////////////////////////////////////////////////////////// - // SELFCOLLISIONS: update velocities - //////////////////////////////////////////////////////////// - if ( ret2 ) - { - int i; - ClothVertex *verts = clmd->clothObject->verts; // needed for openMP - - for ( i = 0; i < cloth->numverts; i++ ) - { - if ( ! ( verts [i].flags & CLOTH_VERT_FLAG_PINNED ) ) - { - VECSUB ( verts[i].tv, verts[i].tx, verts[i].txold ); - } - } - } - //////////////////////////////////////////////////////////// - } - return ret2; -} // return all collision objects in scene // collision object will exclude self @@ -1547,7 +1437,7 @@ int cloth_bvh_objcollision ( Object *ob, ClothModifierData * clmd, float step, f { Cloth *cloth=NULL; BVHTree *cloth_bvh=NULL; - long i=0, numfaces = 0, numverts = 0; + int i=0, numfaces = 0, numverts = 0, k, l, j; int rounds = 0; // result counts applied collisions; ic is for debug output; ClothVertex *verts = NULL; int ret = 0, ret2 = 0; @@ -1647,21 +1537,122 @@ int cloth_bvh_objcollision ( Object *ob, ClothModifierData * clmd, float step, f VECADD ( verts[i].tx, verts[i].txold, verts[i].tv ); } //////////////////////////////////////////////////////////// - + //////////////////////////////////////////////////////////// // Test on *simple* selfcollisions //////////////////////////////////////////////////////////// if ( clmd->coll_parms->flags & CLOTH_COLLSETTINGS_FLAG_SELF ) { - ret2 += cloth_do_selfcollisions(clmd); + for(l = 0; l < clmd->coll_parms->self_loop_count; l++) + { + // TODO: add coll quality rounds again + BVHTreeOverlap *overlap = NULL; + int result = 0; + + // collisions = 1; + verts = cloth->verts; // needed for openMP + + numfaces = clmd->clothObject->numfaces; + numverts = clmd->clothObject->numverts; + + verts = cloth->verts; + + if ( cloth->bvhselftree ) + { + // search for overlapping collision pairs + overlap = BLI_bvhtree_overlap ( cloth->bvhselftree, cloth->bvhselftree, &result ); + + // #pragma omp parallel for private(k, i, j) schedule(static) + for ( k = 0; k < result; k++ ) + { + float temp[3]; + float length = 0; + float mindistance; + + i = overlap[k].indexA; + j = overlap[k].indexB; + + mindistance = clmd->coll_parms->selfepsilon* ( cloth->verts[i].avg_spring_len + cloth->verts[j].avg_spring_len ); + + if ( clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL ) + { + if ( ( cloth->verts [i].flags & CLOTH_VERT_FLAG_PINNED ) + && ( cloth->verts [j].flags & CLOTH_VERT_FLAG_PINNED ) ) + { + continue; + } + } + + VECSUB ( temp, verts[i].tx, verts[j].tx ); + + if ( ( ABS ( temp[0] ) > mindistance ) || ( ABS ( temp[1] ) > mindistance ) || ( ABS ( temp[2] ) > mindistance ) ) continue; + + // check for adjacent points (i must be smaller j) + if ( BLI_edgehash_haskey ( cloth->edgehash, MIN2(i, j), MAX2(i, j) ) ) + { + continue; + } + + length = Normalize ( temp ); + + if ( length < mindistance ) + { + float correction = mindistance - length; + + if ( cloth->verts [i].flags & CLOTH_VERT_FLAG_PINNED ) + { + VecMulf ( temp, -correction ); + VECADD ( verts[j].tx, verts[j].tx, temp ); + } + else if ( cloth->verts [j].flags & CLOTH_VERT_FLAG_PINNED ) + { + VecMulf ( temp, correction ); + VECADD ( verts[i].tx, verts[i].tx, temp ); + } + else + { + VecMulf ( temp, -correction*0.5 ); + VECADD ( verts[j].tx, verts[j].tx, temp ); + + VECSUB ( verts[i].tx, verts[i].tx, temp ); + } + ret = 1; + ret2 += ret; + } + else + { + // check for approximated time collisions + } + } + + if ( overlap ) + MEM_freeN ( overlap ); + + } + } + //////////////////////////////////////////////////////////// + + //////////////////////////////////////////////////////////// + // SELFCOLLISIONS: update velocities + //////////////////////////////////////////////////////////// + if ( ret2 ) + { + for ( i = 0; i < cloth->numverts; i++ ) + { + if ( ! ( verts [i].flags & CLOTH_VERT_FLAG_PINNED ) ) + { + VECSUB ( verts[i].tv, verts[i].tx, verts[i].txold ); + } + } + } + //////////////////////////////////////////////////////////// } - //////////////////////////////////////////////////////////// } while ( ret2 && ( clmd->coll_parms->loop_count>rounds ) ); if(collobjs) - + MEM_freeN(collobjs); + MEM_freeN(collobjs); return MIN2 ( ret, 1 ); } diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c index 1e7bdea9e8e..744b1c97638 100644 --- a/source/blender/blenkernel/intern/customdata.c +++ b/source/blender/blenkernel/intern/customdata.c @@ -265,14 +265,34 @@ static void layerSwap_tface(void *data, int *corner_indices) { MTFace *tf = data; float uv[4][2]; + const static short pin_flags[4] = + { TF_PIN1, TF_PIN2, TF_PIN3, TF_PIN4 }; + const static char sel_flags[4] = + { TF_SEL1, TF_SEL2, TF_SEL3, TF_SEL4 }; + short unwrap = tf->unwrap & ~(TF_PIN1 | TF_PIN2 | TF_PIN3 | TF_PIN4); + char flag = tf->flag & ~(TF_SEL1 | TF_SEL2 | TF_SEL3 | TF_SEL4); int j; for(j = 0; j < 4; ++j) { - uv[j][0] = tf->uv[corner_indices[j]][0]; - uv[j][1] = tf->uv[corner_indices[j]][1]; + int source_index = corner_indices[j]; + + uv[j][0] = tf->uv[source_index][0]; + uv[j][1] = tf->uv[source_index][1]; + + // swap pinning flags around + if(tf->unwrap & pin_flags[source_index]) { + unwrap |= pin_flags[j]; + } + + // swap selection flags around + if(tf->flag & sel_flags[source_index]) { + flag |= sel_flags[j]; + } } memcpy(tf->uv, uv, sizeof(tf->uv)); + tf->unwrap = unwrap; + tf->flag = flag; } static void layerDefault_tface(void *data, int count) @@ -566,6 +586,7 @@ const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = { {sizeof(MTexPoly), "MTexPoly", 1, "Face Texture", NULL, NULL, NULL, NULL, NULL}, {sizeof(MLoopUV), "MLoopUV", 1, "UV coord", NULL, NULL, layerInterp_mloopuv, NULL, NULL}, {sizeof(MLoopCol), "MLoopCol", 1, "Col", NULL, NULL, layerInterp_mloopcol, NULL, layerDefault_mloopcol}, + {sizeof(float)*3*4, "", 0, NULL, NULL, NULL, NULL, NULL, NULL}, {sizeof(MDisps), "MDisps", 1, NULL, layerCopy_mdisps, layerFree_mdisps, NULL, NULL, NULL} }; @@ -573,8 +594,8 @@ const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = { const char *LAYERTYPENAMES[CD_NUMTYPES] = { "CDMVert", "CDMSticky", "CDMDeformVert", "CDMEdge", "CDMFace", "CDMTFace", "CDMCol", "CDOrigIndex", "CDNormal", "CDFlags","CDMFloatProperty", - "CDMIntProperty","CDMStringProperty", "CDOrigSpace", "CDOrco", "CDMTexPoly", - "CDMLoopUV", "CDMloopCol", "CDMDisps"}; + "CDMIntProperty","CDMStringProperty", "CDOrigSpace", "CDOrco", "CDMTexPoly", "CDMLoopUV", + "CDMloopCol", "CDTangent", "CDMDisps"}; const CustomDataMask CD_MASK_BAREMESH = CD_MASK_MVERT | CD_MASK_MEDGE | CD_MASK_MFACE; @@ -588,7 +609,7 @@ const CustomDataMask CD_MASK_EDITMESH = const CustomDataMask CD_MASK_DERIVEDMESH = CD_MASK_MSTICKY | CD_MASK_MDEFORMVERT | CD_MASK_MTFACE | CD_MASK_MCOL | CD_MASK_ORIGINDEX | CD_MASK_PROP_FLT | CD_MASK_PROP_INT | - CD_MASK_PROP_STR | CD_MASK_ORIGSPACE | CD_MASK_ORCO; + CD_MASK_PROP_STR | CD_MASK_ORIGSPACE | CD_MASK_ORCO | CD_MASK_TANGENT; const CustomDataMask CD_MASK_BMESH = CD_MASK_MSTICKY | CD_MASK_MDEFORMVERT | CD_MASK_PROP_FLT | CD_MASK_PROP_INT | CD_MASK_PROP_STR; const CustomDataMask CD_MASK_FACECORNERS = diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c index c64605ab0d9..a0ea2bd58a5 100644 --- a/source/blender/blenkernel/intern/modifier.c +++ b/source/blender/blenkernel/intern/modifier.c @@ -98,6 +98,7 @@ #include "BKE_material.h" #include "BKE_particle.h" #include "BKE_pointcache.h" +#include "BKE_texture.h" #include "BKE_utildefines.h" #include "depsgraph_private.h" #include "BKE_bmesh.h" @@ -1131,8 +1132,18 @@ static DerivedMesh *arrayModifier_doArray(ArrayModifierData *amd, mface[numFaces].v1 = vert_map[mface[numFaces].v1]; mface[numFaces].v2 = vert_map[mface[numFaces].v2]; mface[numFaces].v3 = vert_map[mface[numFaces].v3]; - if(mface[numFaces].v4) + if(mface[numFaces].v4) { mface[numFaces].v4 = vert_map[mface[numFaces].v4]; + + test_index_face(&mface[numFaces], &result->faceData, + numFaces, 4); + } + else + { + test_index_face(&mface[numFaces], &result->faceData, + numFaces, 3); + } + origindex[numFaces] = ORIGINDEX_NONE; numFaces++; @@ -1222,8 +1233,17 @@ static DerivedMesh *arrayModifier_doArray(ArrayModifierData *amd, mface[numFaces].v1 = vert_map[mface[numFaces].v1]; mface[numFaces].v2 = vert_map[mface[numFaces].v2]; mface[numFaces].v3 = vert_map[mface[numFaces].v3]; - if(mface[numFaces].v4) + if(mface[numFaces].v4) { mface[numFaces].v4 = vert_map[mface[numFaces].v4]; + + test_index_face(&mface[numFaces], &result->faceData, + numFaces, 4); + } + else + { + test_index_face(&mface[numFaces], &result->faceData, + numFaces, 3); + } origindex[numFaces] = ORIGINDEX_NONE; numFaces++; @@ -2981,6 +3001,20 @@ CustomDataMask displaceModifier_requiredDataMask(ModifierData *md) return dataMask; } +static int displaceModifier_dependsOnTime(ModifierData *md) +{ + DisplaceModifierData *dmd = (DisplaceModifierData *)md; + + if(dmd->texture) + { + return BKE_texture_dependsOnTime(dmd->texture); + } + else + { + return 0; + } +} + static void displaceModifier_foreachObjectLink(ModifierData *md, Object *ob, ObjectWalkFunc walk, void *userData) { @@ -7372,6 +7406,7 @@ ModifierTypeInfo *modifierType_getInfo(ModifierType type) mti->initData = displaceModifier_initData; mti->copyData = displaceModifier_copyData; mti->requiredDataMask = displaceModifier_requiredDataMask; + mti->dependsOnTime = displaceModifier_dependsOnTime; mti->foreachObjectLink = displaceModifier_foreachObjectLink; mti->foreachIDLink = displaceModifier_foreachIDLink; mti->updateDepgraph = displaceModifier_updateDepgraph; diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c index 24a3d348ae7..643f90637ad 100644 --- a/source/blender/blenkernel/intern/particle.c +++ b/source/blender/blenkernel/intern/particle.c @@ -3744,6 +3744,9 @@ int psys_get_particle_state(Object *ob, ParticleSystem *psys, int p, ParticleKey /* TODO: pa_clump vgroup */ do_clump(state,key1,t,part->clumpfac,part->clumppow,1.0); + + if(psys->lattice) + calc_latt_deform(state->co,1.0f); } else{ if (pa) { /* TODO PARTICLE - should this ever be NULL? - Campbell */ diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c index 7dca87d5c13..d1c0cdec71d 100644 --- a/source/blender/blenkernel/intern/particle_system.c +++ b/source/blender/blenkernel/intern/particle_system.c @@ -4653,7 +4653,7 @@ static void system_step(Object *ob, ParticleSystem *psys, ParticleSystemModifier PTCacheID pid; int totpart, oldtotpart, totchild, oldtotchild, p; float disp, *vg_vel= 0, *vg_tan= 0, *vg_rot= 0, *vg_size= 0; - int init= 0, distr= 0, alloc= 0, usecache= 0; + int init= 0, distr= 0, alloc= 0, usecache= 0, only_children_changed= 0; int framenr, framedelta, startframe, endframe; part= psys->part; @@ -4720,6 +4720,7 @@ static void system_step(Object *ob, ParticleSystem *psys, ParticleSystemModifier totchild = get_psys_tot_child(psys); if(oldtotpart != totpart || (psys->part->childtype && oldtotchild != totchild)) { + only_children_changed = (oldtotpart == totpart); realloc_particles(ob, psys, totpart); alloc = 1; distr= 1; @@ -4740,14 +4741,17 @@ static void system_step(Object *ob, ParticleSystem *psys, ParticleSystemModifier if((psys->part->type == PART_HAIR) && !(psys->flag & PSYS_HAIR_DONE)) /* don't generate children while growing hair - waste of time */ - psys_free_children(psys); - else if(get_psys_tot_child(psys)) - distribute_particles(ob, psys, PART_FROM_CHILD); + psys_free_children(psys); + else if(get_psys_tot_child(psys)) + distribute_particles(ob, psys, PART_FROM_CHILD); } - initialize_all_particles(ob, psys, psmd); - if(alloc) - reset_all_particles(ob, psys, psmd, 0.0, cfra, oldtotpart); + if(only_children_changed==0) { + initialize_all_particles(ob, psys, psmd); + + if(alloc) + reset_all_particles(ob, psys, psmd, 0.0, cfra, oldtotpart); + } /* flag for possible explode modifiers after this system */ psmd->flag |= eParticleSystemFlag_Pars; diff --git a/source/blender/blenkernel/intern/softbody.c b/source/blender/blenkernel/intern/softbody.c index d5b5ab6d63e..d465c058d30 100644 --- a/source/blender/blenkernel/intern/softbody.c +++ b/source/blender/blenkernel/intern/softbody.c @@ -69,6 +69,8 @@ variables on the UI for now #include "BLI_blenlib.h" #include "BLI_arithb.h" #include "BLI_ghash.h" +#include "BLI_threads.h" + #include "BKE_curve.h" #include "BKE_effect.h" #include "BKE_global.h" @@ -118,6 +120,20 @@ typedef struct SBScratch { float aabbmin[3],aabbmax[3]; }SBScratch; +typedef struct SB_thread_context{ + Object *ob; + float forcetime; + float timenow; + int ifirst; + int ilast; + ListBase *do_effector; + int do_deflector; + float fieldfactor; + float windfactor; + int nr; + int tot; +}SB_thread_context; + #define NLF_BUILD 1 #define NLF_SOLVE 2 @@ -1514,17 +1530,15 @@ int sb_detect_edge_collisionCached(float edge_v1[3],float edge_v2[3],float *damp -void scan_for_ext_spring_forces(Object *ob,float timenow) +void _scan_for_ext_spring_forces(Object *ob,float timenow,int ifirst,int ilast, struct ListBase *do_effector) { SoftBody *sb = ob->soft; - ListBase *do_effector; int a; float damp; float feedback[3]; - do_effector= pdInitEffectors(ob,NULL); if (sb && sb->totspring){ - for(a=0; a<sb->totspring; a++) { + for(a=ifirst; a<ilast; a++) { BodySpring *bs = &sb->bspring[a]; bs->ext_force[0]=bs->ext_force[1]=bs->ext_force[2]=0.0f; feedback[0]=feedback[1]=feedback[2]=0.0f; @@ -1584,9 +1598,88 @@ void scan_for_ext_spring_forces(Object *ob,float timenow) } } } - if(do_effector) - pdEndEffectors(do_effector); } + + +void scan_for_ext_spring_forces(Object *ob,float timenow) +{ + SoftBody *sb = ob->soft; + ListBase *do_effector= NULL; + do_effector= pdInitEffectors(ob,NULL); + if (sb){ + _scan_for_ext_spring_forces(ob,timenow,0,sb->totspring,do_effector); + } + if(do_effector) + pdEndEffectors(do_effector); +} + +void *exec_scan_for_ext_spring_forces(void *data) +{ + SB_thread_context *pctx = (SB_thread_context*)data; + _scan_for_ext_spring_forces(pctx->ob,pctx->timenow,pctx->ifirst,pctx->ilast,pctx->do_effector); + return 0; +} + +void sb_sfesf_threads_run(struct Object *ob, float timenow,int totsprings,int *ptr_to_break_func()) +{ + ListBase *do_effector = NULL; + ListBase threads; + SB_thread_context *sb_threads; + int i, totthread,left,dec; + int lowsprings =10; /* wild guess .. may increase with better thread management 'above' or even be UI option sb->spawn_cf_threads_nopts */ + + do_effector= pdInitEffectors(ob,NULL); + + /* figure the number of threads while preventing pretty pointless threading overhead */ + if(totsprings < lowsprings) {totthread=1;} + else{ + if(G.scene->r.mode & R_FIXED_THREADS) + totthread= G.scene->r.threads; + else + totthread= BLI_system_thread_count(); + } + /*left to do--> what if we got zillions of CPUs running but 'totsprings' tasks to spread*/ + + sb_threads= MEM_callocN(sizeof(SB_thread_context)*totthread, "SBSpringsThread"); + memset(sb_threads, 0, sizeof(SB_thread_context)*totthread); + left = totsprings; + dec = totsprings/totthread +1; + for(i=0; i<totthread; i++) { + sb_threads[i].ob = ob; + sb_threads[i].forcetime = 0.0; // not used here + sb_threads[i].timenow = timenow; + sb_threads[i].ilast = left; + left = left - dec; + if (left >0){ + sb_threads[i].ifirst = left; + } + else + sb_threads[i].ifirst = 0; + sb_threads[i].do_effector = do_effector; + sb_threads[i].do_deflector = 0;// not used here + sb_threads[i].fieldfactor = 0.0f;// not used here + sb_threads[i].windfactor = 0.0f;// not used here + sb_threads[i].nr= i; + sb_threads[i].tot= totthread; + } + if(totthread > 1) { + BLI_init_threads(&threads, exec_scan_for_ext_spring_forces, totthread); + + for(i=0; i<totthread; i++) + BLI_insert_thread(&threads, &sb_threads[i]); + + BLI_end_threads(&threads); + } + else + exec_scan_for_ext_spring_forces(&sb_threads[0]); + /* clean up */ + MEM_freeN(sb_threads); + + if(do_effector) + pdEndEffectors(do_effector); +} + + /* --- the spring external section*/ int choose_winner(float*w, float* pos,float*a,float*b,float*c,float*ca,float*cb,float*cc) @@ -2023,109 +2116,72 @@ static void sb_spring_force(Object *ob,int bpi,BodySpring *bs,float iks,float fo } -static void softbody_calc_forces(Object *ob, float forcetime, float timenow, int nl_flags) +/* since this is definitely the most CPU consuming task here .. try to spread it */ +/* core function _softbody_calc_forces_slice_in_a_thread */ +/* result is int to be able to flag user break */ +int _softbody_calc_forces_slice_in_a_thread(Object *ob, float forcetime, float timenow,int ifirst,int ilast,int *ptr_to_break_func(),ListBase *do_effector,int do_deflector,float fieldfactor, float windfactor) { -/* rule we never alter free variables :bp->vec bp->pos in here ! - * this will ruin adaptive stepsize AKA heun! (BM) - */ + float iks; + int bb,do_selfcollision,do_springcollision,do_aero; + int number_of_points_here = ilast - ifirst; SoftBody *sb= ob->soft; /* is supposed to be there */ BodyPoint *bp; - BodyPoint *bproot; - BodySpring *bs; - ListBase *do_effector; - float iks, ks, kd, gravity; - float fieldfactor = 1000.0f, windfactor = 250.0f; - float tune = sb->ballstiff; - int a, b, do_deflector,do_selfcollision,do_springcollision,do_aero; - - -/* jacobian - NLboolean success; - - if(nl_flags){ - nlBegin(NL_SYSTEM); - nlBegin(NL_MATRIX); - } -*/ - - - gravity = sb->grav * sb_grav_force_scale(ob); - + /* intitialize */ + if (sb) { /* check conditions for various options */ - do_deflector= query_external_colliders(ob); + /* +++ could be done on object level to squeeze out the last bits of it */ do_selfcollision=((ob->softflag & OB_SB_EDGES) && (sb->bspring)&& (ob->softflag & OB_SB_SELF)); do_springcollision=do_deflector && (ob->softflag & OB_SB_EDGES) &&(ob->softflag & OB_SB_EDGECOLL); do_aero=((sb->aeroedge)&& (ob->softflag & OB_SB_EDGES)); - - iks = 1.0f/(1.0f-sb->inspring)-1.0f ;/* inner spring constants function */ - bproot= sb->bpoint; /* need this for proper spring addressing */ - - if (do_springcollision || do_aero) scan_for_ext_spring_forces(ob,timenow); - /* after spring scan because it uses Effoctors too */ - do_effector= pdInitEffectors(ob,NULL); + /* --- could be done on object level to squeeze out the last bits of it */ + } + else { + printf("Error expected a SB here \n"); + return (999); + } - if (do_deflector) { - float defforce[3]; - do_deflector = sb_detect_aabb_collisionCached(defforce,ob->lay,ob,timenow); +/* debugerin */ + if (sb->totpoint < ifirst) { + printf("Aye 998"); + return (998); } +/* debugerin */ - for(a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) { + + bp = &sb->bpoint[ifirst]; + for(bb=number_of_points_here; bb>0; bb--, bp++) { /* clear forces accumulator */ bp->force[0]= bp->force[1]= bp->force[2]= 0.0; - if(nl_flags & NLF_BUILD){ - //int ia =3*(sb->totpoint-a); - //int op =3*sb->totpoint; - /* dF/dV = v */ - /* jacobioan - nlMatrixAdd(op+ia,ia,-forcetime); - nlMatrixAdd(op+ia+1,ia+1,-forcetime); - nlMatrixAdd(op+ia+2,ia+2,-forcetime); - - nlMatrixAdd(ia,ia,1); - nlMatrixAdd(ia+1,ia+1,1); - nlMatrixAdd(ia+2,ia+2,1); - - nlMatrixAdd(op+ia,op+ia,1); - nlMatrixAdd(op+ia+1,op+ia+1,1); - nlMatrixAdd(op+ia+2,op+ia+2,1); - */ - - - } - /* naive ball self collision */ /* needs to be done if goal snaps or not */ if(do_selfcollision){ int attached; BodyPoint *obp; + BodySpring *bs; int c,b; float velcenter[3],dvel[3],def[3]; float distance; float compare; + float bstune = sb->ballstiff; - for(c=sb->totpoint, obp= sb->bpoint; c>=a; c--, obp++) { - - //if ((bp->octantflag & obp->octantflag) == 0) continue; - + for(c=sb->totpoint, obp= sb->bpoint; c>=ifirst+bb; c--, obp++) { compare = (obp->colball + bp->colball); VecSubf(def, bp->pos, obp->pos); - /* rather check the AABBoxes before ever calulating the real distance */ /* mathematically it is completly nuts, but performace is pretty much (3) times faster */ if ((ABS(def[0]) > compare) || (ABS(def[1]) > compare) || (ABS(def[2]) > compare)) continue; - distance = Normalize(def); if (distance < compare ){ /* exclude body points attached with a spring */ attached = 0; for(b=obp->nofsprings;b>0;b--){ bs = sb->bspring + obp->springs[b-1]; - if (( sb->totpoint-a == bs->v2) || ( sb->totpoint-a == bs->v1)){ + if (( ilast-bb == bs->v2) || ( ilast-bb == bs->v1)){ attached=1; continue;} } if (!attached){ - float f = tune/(distance) + tune/(compare*compare)*distance - 2.0f*tune/compare ; + float f = bstune/(distance) + bstune/(compare*compare)*distance - 2.0f*bstune/compare ; VecMidf(velcenter, bp->vec, obp->vec); VecSubf(dvel,velcenter,bp->vec); @@ -2134,38 +2190,12 @@ static void softbody_calc_forces(Object *ob, float forcetime, float timenow, int Vec3PlusStVec(bp->force,f*(1.0f-sb->balldamp),def); Vec3PlusStVec(bp->force,sb->balldamp,dvel); - if(nl_flags & NLF_BUILD){ - //int ia =3*(sb->totpoint-a); - //int ic =3*(sb->totpoint-c); - //int op =3*sb->totpoint; - //float mvel = forcetime*sb->nodemass*sb->balldamp; - //float mpos = forcetime*tune*(1.0f-sb->balldamp); - /*some quick and dirty entries to the jacobian*/ - //dfdx_goal(ia,ia,op,mpos); - //dfdv_goal(ia,ia,mvel); - /* exploit force(a,b) == -force(b,a) part1/2 */ - //dfdx_goal(ic,ic,op,mpos); - //dfdv_goal(ic,ic,mvel); - - - /*TODO sit down an X-out the true jacobian entries*/ - /*well does not make to much sense because the eigenvalues - of the jacobian go negative; and negative eigenvalues - on a complex iterative system z(n+1)=A * z(n) - give imaginary roots in the charcateristic polynom - --> solutions that to z(t)=u(t)* exp ( i omega t) --> oscilations we don't want here - where u(t) is a unknown amplitude function (worst case rising fast) - */ - } - /* exploit force(a,b) == -force(b,a) part2/2 */ VecSubf(dvel,velcenter,obp->vec); VecMulf(dvel,sb->nodemass); Vec3PlusStVec(obp->force,sb->balldamp,dvel); Vec3PlusStVec(obp->force,-f*(1.0f-sb->balldamp),def); - - } } } @@ -2179,20 +2209,13 @@ static void softbody_calc_forces(Object *ob, float forcetime, float timenow, int /* do goal stuff */ if(ob->softflag & OB_SB_GOAL) { /* true elastic goal */ + float ks,kd; VecSubf(auxvect,bp->pos,bp->origT); ks = 1.0f/(1.0f- bp->goal*sb->goalspring)-1.0f ; bp->force[0]+= -ks*(auxvect[0]); bp->force[1]+= -ks*(auxvect[1]); bp->force[2]+= -ks*(auxvect[2]); - if(nl_flags & NLF_BUILD){ - //int ia =3*(sb->totpoint-a); - //int op =3*(sb->totpoint); - /* depending on my pos */ - //dfdx_goal(ia,ia,op,ks*forcetime); - } - - /* calulate damping forces generated by goals*/ VecSubf(velgoal,bp->origS, bp->origE); kd = sb->goalfrict * sb_fric_force_scale(ob) ; @@ -2202,13 +2225,6 @@ static void softbody_calc_forces(Object *ob, float forcetime, float timenow, int bp->force[0]-= kd * (auxvect[0]); bp->force[1]-= kd * (auxvect[1]); bp->force[2]-= kd * (auxvect[2]); - if(nl_flags & NLF_BUILD){ - //int ia =3*(sb->totpoint-a); - Normalize(auxvect); - /* depending on my vel */ - //dfdv_goal(ia,ia,kd*forcetime); - } - } else { bp->force[0]-= kd * (velgoal[0] - bp->vec[0]); @@ -2218,14 +2234,15 @@ static void softbody_calc_forces(Object *ob, float forcetime, float timenow, int } /* done goal stuff */ - /* gravitation */ + if (sb){ + float gravity = sb->grav * sb_grav_force_scale(ob); bp->force[2]-= gravity*sb->nodemass; /* individual mass of node here */ - //bp->force[1]-= gravity*sb->nodemass; /* individual mass of node here */ - + } /* particle field & vortex */ if(do_effector) { + float kd; float force[3]= {0.0f, 0.0f, 0.0f}; float speed[3]= {0.0f, 0.0f, 0.0f}; float eval_sb_fric_force_scale = sb_fric_force_scale(ob); /* just for calling function once */ @@ -2246,21 +2263,12 @@ static void softbody_calc_forces(Object *ob, float forcetime, float timenow, int } else { /* BP friction in media (not) moving*/ - kd= sb->mediafrict* sb_fric_force_scale(ob); + float kd = sb->mediafrict* sb_fric_force_scale(ob); /* assume it to be proportional to actual velocity */ bp->force[0]-= bp->vec[0]*kd; bp->force[1]-= bp->vec[1]*kd; bp->force[2]-= bp->vec[2]*kd; /* friction in media done */ - if(nl_flags & NLF_BUILD){ - //int ia =3*(sb->totpoint-a); - /* da/dv = */ - -// nlMatrixAdd(ia,ia,forcetime*kd); -// nlMatrixAdd(ia+1,ia+1,forcetime*kd); -// nlMatrixAdd(ia+2,ia+2,forcetime*kd); - } - } /* +++cached collision targets */ bp->choke = 0.0f; @@ -2268,44 +2276,25 @@ static void softbody_calc_forces(Object *ob, float forcetime, float timenow, int bp->flag &= ~SBF_DOFUZZY; if(do_deflector) { float cfforce[3],defforce[3] ={0.0f,0.0f,0.0f}, vel[3] = {0.0f,0.0f,0.0f}, facenormal[3], cf = 1.0f,intrusion; - kd = 1.0f; + float kd = 1.0f; if (sb_deflect_face(ob,bp->pos,facenormal,defforce,&cf,timenow,vel,&intrusion)){ - if ((!nl_flags)&&(intrusion < 0.0f)){ - /*bjornmose: uugh.. what an evil hack - violation of the 'don't touch bp->pos in here' rule - but works nice, like this--> - we predict the solution beeing out of the collider - in heun step No1 and leave the heun step No2 adapt to it - so we kind of introduced a implicit solver for this case - */ - Vec3PlusStVec(bp->pos,-intrusion,facenormal); - - sb->scratch->flag |= SBF_DOFUZZY; - bp->flag |= SBF_DOFUZZY; - bp->choke = sb->choke*0.01f; - } - else{ + VECSUB(cfforce,bp->vec,vel); Vec3PlusStVec(bp->force,-cf*50.0f,cfforce); - } - Vec3PlusStVec(bp->force,kd,defforce); - if (nl_flags & NLF_BUILD){ - // int ia =3*(sb->totpoint-a); - // int op =3*sb->totpoint; - //dfdx_goal(ia,ia,op,mpos); // don't do unless you know - //dfdv_goal(ia,ia,-cf); - - } - + + Vec3PlusStVec(bp->force,kd,defforce); } } /* ---cached collision targets */ /* +++springs */ + iks = 1.0f/(1.0f-sb->inspring)-1.0f ;/* inner spring constants function */ if(ob->softflag & OB_SB_EDGES) { if (sb->bspring){ /* spring list exists at all ? */ + int b; + BodySpring *bs; for(b=bp->nofsprings;b>0;b--){ bs = sb->bspring + bp->springs[b-1]; if (do_springcollision || do_aero){ @@ -2315,90 +2304,513 @@ static void softbody_calc_forces(Object *ob, float forcetime, float timenow, int } // sb_spring_force(Object *ob,int bpi,BodySpring *bs,float iks,float forcetime,int nl_flags) - sb_spring_force(ob,sb->totpoint-a,bs,iks,forcetime,nl_flags); + sb_spring_force(ob,ilast-bb,bs,iks,forcetime,0); }/* loop springs */ }/* existing spring list */ }/*any edges*/ /* ---springs */ }/*omit on snap */ }/*loop all bp's*/ +return 0; /*done fine*/ +} + +void *exec_softbody_calc_forces(void *data) +{ + SB_thread_context *pctx = (SB_thread_context*)data; + _softbody_calc_forces_slice_in_a_thread(pctx->ob,pctx->forcetime,pctx->timenow,pctx->ifirst,pctx->ilast,NULL,pctx->do_effector,pctx->do_deflector,pctx->fieldfactor,pctx->windfactor); + return 0; +} + +void sb_cf_threads_run(struct Object *ob, float forcetime, float timenow,int totpoint,int *ptr_to_break_func(),struct ListBase *do_effector,int do_deflector,float fieldfactor, float windfactor) +{ + ListBase threads; + SB_thread_context *sb_threads; + int i, totthread,left,dec; + int lowpoints =10; /* wild guess .. may increase with better thread management 'above' or even be UI option sb->spawn_cf_threads_nopts */ + + /* figure the number of threads while preventing pretty pointless threading overhead */ + if(totpoint < lowpoints) {totthread=1;} + else{ + if(G.scene->r.mode & R_FIXED_THREADS) + totthread= G.scene->r.threads; + else + totthread= BLI_system_thread_count(); + } + /*left to do--> what if we got zillions of CPUs running but 'totpoint' tasks to spread*/ + + sb_threads= MEM_callocN(sizeof(SB_thread_context)*totthread, "SBThread"); + memset(sb_threads, 0, sizeof(SB_thread_context)*totthread); + left = totpoint; + dec = totpoint/totthread +1; + for(i=0; i<totthread; i++) { + sb_threads[i].ob = ob; + sb_threads[i].forcetime = forcetime; + sb_threads[i].timenow = timenow; + sb_threads[i].ilast = left; + left = left - dec; + if (left >0){ + sb_threads[i].ifirst = left; + } + else + sb_threads[i].ifirst = 0; + sb_threads[i].do_effector = do_effector; + sb_threads[i].do_deflector = do_deflector; + sb_threads[i].fieldfactor = fieldfactor; + sb_threads[i].windfactor = windfactor; + sb_threads[i].nr= i; + sb_threads[i].tot= totthread; + } + + + if(totthread > 1) { + BLI_init_threads(&threads, exec_softbody_calc_forces, totthread); + + for(i=0; i<totthread; i++) + BLI_insert_thread(&threads, &sb_threads[i]); + + BLI_end_threads(&threads); + } + else + exec_softbody_calc_forces(&sb_threads[0]); + /* clean up */ + MEM_freeN(sb_threads); +} + +static void softbody_calc_forcesEx(Object *ob, float forcetime, float timenow, int nl_flags) +{ +/* rule we never alter free variables :bp->vec bp->pos in here ! + * this will ruin adaptive stepsize AKA heun! (BM) + */ + SoftBody *sb= ob->soft; /* is supposed to be there */ + BodyPoint *bproot; + ListBase *do_effector; + float iks, gravity; + float fieldfactor = 1000.0f, windfactor = 250.0f; + int do_deflector,do_selfcollision,do_springcollision,do_aero; + + gravity = sb->grav * sb_grav_force_scale(ob); + + /* check conditions for various options */ + do_deflector= query_external_colliders(ob); + do_selfcollision=((ob->softflag & OB_SB_EDGES) && (sb->bspring)&& (ob->softflag & OB_SB_SELF)); + do_springcollision=do_deflector && (ob->softflag & OB_SB_EDGES) &&(ob->softflag & OB_SB_EDGECOLL); + do_aero=((sb->aeroedge)&& (ob->softflag & OB_SB_EDGES)); + + iks = 1.0f/(1.0f-sb->inspring)-1.0f ;/* inner spring constants function */ + bproot= sb->bpoint; /* need this for proper spring addressing */ + + if (do_springcollision || do_aero) + sb_sfesf_threads_run(ob,timenow,sb->totspring,NULL); + + /* after spring scan because it uses Effoctors too */ + do_effector= pdInitEffectors(ob,NULL); + if (do_deflector) { + float defforce[3]; + do_deflector = sb_detect_aabb_collisionCached(defforce,ob->lay,ob,timenow); + } + + sb_cf_threads_run(ob,forcetime,timenow,sb->totpoint,NULL,do_effector,do_deflector,fieldfactor,windfactor); /* finally add forces caused by face collision */ if (ob->softflag & OB_SB_FACECOLL) scan_for_ext_face_forces(ob,timenow); /* finish matrix and solve */ -#if (0) // remove onl linking for now .. still i am not sure .. the jacobian can be usefull .. so keep that BM - if(nl_flags & NLF_SOLVE){ - //double sct,sst=PIL_check_seconds_timer(); - for(a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) { - int iv =3*(sb->totpoint-a); - int ip =3*(2*sb->totpoint-a); - int n; - for (n=0;n<3;n++) {nlRightHandSideSet(0, iv+n, bp->force[0+n]);} - for (n=0;n<3;n++) {nlRightHandSideSet(0, ip+n, bp->vec[0+n]);} + if(do_effector) pdEndEffectors(do_effector); +} + + + + +static void softbody_calc_forces(Object *ob, float forcetime, float timenow, int nl_flags) +{ + /* redirection to the new threaded Version */ + if (G.rt !=16){ + softbody_calc_forcesEx(ob, forcetime, timenow, nl_flags); + return; + } + else{ + /* so the following will die */ + /* |||||||||||||||||||||||||| */ + /* VVVVVVVVVVVVVVVVVVVVVVVVVV */ + + /* rule we never alter free variables :bp->vec bp->pos in here ! + * this will ruin adaptive stepsize AKA heun! (BM) + */ + SoftBody *sb= ob->soft; /* is supposed to be there */ + BodyPoint *bp; + BodyPoint *bproot; + BodySpring *bs; + ListBase *do_effector; + float iks, ks, kd, gravity; + float fieldfactor = 1000.0f, windfactor = 250.0f; + float tune = sb->ballstiff; + int a, b, do_deflector,do_selfcollision,do_springcollision,do_aero; + + + /* jacobian + NLboolean success; + + if(nl_flags){ + nlBegin(NL_SYSTEM); + nlBegin(NL_MATRIX); } - nlEnd(NL_MATRIX); - nlEnd(NL_SYSTEM); + */ + + + gravity = sb->grav * sb_grav_force_scale(ob); + + /* check conditions for various options */ + do_deflector= query_external_colliders(ob); + do_selfcollision=((ob->softflag & OB_SB_EDGES) && (sb->bspring)&& (ob->softflag & OB_SB_SELF)); + do_springcollision=do_deflector && (ob->softflag & OB_SB_EDGES) &&(ob->softflag & OB_SB_EDGECOLL); + do_aero=((sb->aeroedge)&& (ob->softflag & OB_SB_EDGES)); + + iks = 1.0f/(1.0f-sb->inspring)-1.0f ;/* inner spring constants function */ + bproot= sb->bpoint; /* need this for proper spring addressing */ - if ((G.rt >0) && (nl_flags & NLF_BUILD)) - { - printf("####MEE#####\n"); - nlPrintMatrix(); + if (do_springcollision || do_aero) scan_for_ext_spring_forces(ob,timenow); + /* after spring scan because it uses Effoctors too */ + do_effector= pdInitEffectors(ob,NULL); + + if (do_deflector) { + float defforce[3]; + do_deflector = sb_detect_aabb_collisionCached(defforce,ob->lay,ob,timenow); } - success= nlSolveAdvanced(NULL, 1); + for(a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) { + /* clear forces accumulator */ + bp->force[0]= bp->force[1]= bp->force[2]= 0.0; + if(nl_flags & NLF_BUILD){ + //int ia =3*(sb->totpoint-a); + //int op =3*sb->totpoint; + /* dF/dV = v */ + /* jacobioan + nlMatrixAdd(op+ia,ia,-forcetime); + nlMatrixAdd(op+ia+1,ia+1,-forcetime); + nlMatrixAdd(op+ia+2,ia+2,-forcetime); + + nlMatrixAdd(ia,ia,1); + nlMatrixAdd(ia+1,ia+1,1); + nlMatrixAdd(ia+2,ia+2,1); + + nlMatrixAdd(op+ia,op+ia,1); + nlMatrixAdd(op+ia+1,op+ia+1,1); + nlMatrixAdd(op+ia+2,op+ia+2,1); + */ - // nlPrintMatrix(); /* for debug purpose .. anyhow cropping B vector looks like working */ - if(success){ - float f; - int index =0; - /* for debug purpose .. anyhow cropping B vector looks like working */ - if (G.rt >0) - for(a=2*sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) { - f=nlGetVariable(0,index); - printf("(%f ",f);index++; - f=nlGetVariable(0,index); - printf("%f ",f);index++; - f=nlGetVariable(0,index); - printf("%f)",f);index++; + + } + + /* naive ball self collision */ + /* needs to be done if goal snaps or not */ + if(do_selfcollision){ + int attached; + BodyPoint *obp; + int c,b; + float velcenter[3],dvel[3],def[3]; + float distance; + float compare; + + for(c=sb->totpoint, obp= sb->bpoint; c>=a; c--, obp++) { + + //if ((bp->octantflag & obp->octantflag) == 0) continue; + + compare = (obp->colball + bp->colball); + VecSubf(def, bp->pos, obp->pos); + + /* rather check the AABBoxes before ever calulating the real distance */ + /* mathematically it is completly nuts, but performace is pretty much (3) times faster */ + if ((ABS(def[0]) > compare) || (ABS(def[1]) > compare) || (ABS(def[2]) > compare)) continue; + + distance = Normalize(def); + if (distance < compare ){ + /* exclude body points attached with a spring */ + attached = 0; + for(b=obp->nofsprings;b>0;b--){ + bs = sb->bspring + obp->springs[b-1]; + if (( sb->totpoint-a == bs->v2) || ( sb->totpoint-a == bs->v1)){ + attached=1; + continue;} + } + if (!attached){ + float f = tune/(distance) + tune/(compare*compare)*distance - 2.0f*tune/compare ; + + VecMidf(velcenter, bp->vec, obp->vec); + VecSubf(dvel,velcenter,bp->vec); + VecMulf(dvel,sb->nodemass); + + Vec3PlusStVec(bp->force,f*(1.0f-sb->balldamp),def); + Vec3PlusStVec(bp->force,sb->balldamp,dvel); + + if(nl_flags & NLF_BUILD){ + //int ia =3*(sb->totpoint-a); + //int ic =3*(sb->totpoint-c); + //int op =3*sb->totpoint; + //float mvel = forcetime*sb->nodemass*sb->balldamp; + //float mpos = forcetime*tune*(1.0f-sb->balldamp); + /*some quick and dirty entries to the jacobian*/ + //dfdx_goal(ia,ia,op,mpos); + //dfdv_goal(ia,ia,mvel); + /* exploit force(a,b) == -force(b,a) part1/2 */ + //dfdx_goal(ic,ic,op,mpos); + //dfdv_goal(ic,ic,mvel); + + + /*TODO sit down an X-out the true jacobian entries*/ + /*well does not make to much sense because the eigenvalues + of the jacobian go negative; and negative eigenvalues + on a complex iterative system z(n+1)=A * z(n) + give imaginary roots in the charcateristic polynom + --> solutions that to z(t)=u(t)* exp ( i omega t) --> oscilations we don't want here + where u(t) is a unknown amplitude function (worst case rising fast) + */ + } + + /* exploit force(a,b) == -force(b,a) part2/2 */ + VecSubf(dvel,velcenter,obp->vec); + VecMulf(dvel,sb->nodemass); + + Vec3PlusStVec(obp->force,sb->balldamp,dvel); + Vec3PlusStVec(obp->force,-f*(1.0f-sb->balldamp),def); + + + } + } } + } + /* naive ball self collision done */ - index =0; - for(a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) { + if(bp->goal < SOFTGOALSNAP){ /* ommit this bp when it snaps */ + float auxvect[3]; + float velgoal[3]; + + /* do goal stuff */ + if(ob->softflag & OB_SB_GOAL) { + /* true elastic goal */ + VecSubf(auxvect,bp->pos,bp->origT); + ks = 1.0f/(1.0f- bp->goal*sb->goalspring)-1.0f ; + bp->force[0]+= -ks*(auxvect[0]); + bp->force[1]+= -ks*(auxvect[1]); + bp->force[2]+= -ks*(auxvect[2]); + + if(nl_flags & NLF_BUILD){ + //int ia =3*(sb->totpoint-a); + //int op =3*(sb->totpoint); + /* depending on my pos */ + //dfdx_goal(ia,ia,op,ks*forcetime); + } + + + /* calulate damping forces generated by goals*/ + VecSubf(velgoal,bp->origS, bp->origE); + kd = sb->goalfrict * sb_fric_force_scale(ob) ; + VecAddf(auxvect,velgoal,bp->vec); + + if (forcetime > 0.0 ) { /* make sure friction does not become rocket motor on time reversal */ + bp->force[0]-= kd * (auxvect[0]); + bp->force[1]-= kd * (auxvect[1]); + bp->force[2]-= kd * (auxvect[2]); + if(nl_flags & NLF_BUILD){ + //int ia =3*(sb->totpoint-a); + Normalize(auxvect); + /* depending on my vel */ + //dfdv_goal(ia,ia,kd*forcetime); + } + + } + else { + bp->force[0]-= kd * (velgoal[0] - bp->vec[0]); + bp->force[1]-= kd * (velgoal[1] - bp->vec[1]); + bp->force[2]-= kd * (velgoal[2] - bp->vec[2]); + } + } + /* done goal stuff */ + + + /* gravitation */ + bp->force[2]-= gravity*sb->nodemass; /* individual mass of node here */ + //bp->force[1]-= gravity*sb->nodemass; /* individual mass of node here */ + + + /* particle field & vortex */ + if(do_effector) { + float force[3]= {0.0f, 0.0f, 0.0f}; + float speed[3]= {0.0f, 0.0f, 0.0f}; + float eval_sb_fric_force_scale = sb_fric_force_scale(ob); /* just for calling function once */ + + pdDoEffectors(do_effector, bp->pos, force, speed, (float)G.scene->r.cfra, 0.0f, PE_WIND_AS_SPEED); + + /* apply forcefield*/ + VecMulf(force,fieldfactor* eval_sb_fric_force_scale); + VECADD(bp->force, bp->force, force); + + /* BP friction in moving media */ + kd= sb->mediafrict* eval_sb_fric_force_scale; + bp->force[0] -= kd * (bp->vec[0] + windfactor*speed[0]/eval_sb_fric_force_scale); + bp->force[1] -= kd * (bp->vec[1] + windfactor*speed[1]/eval_sb_fric_force_scale); + bp->force[2] -= kd * (bp->vec[2] + windfactor*speed[2]/eval_sb_fric_force_scale); + /* now we'll have nice centrifugal effect for vortex */ + + } + else { + /* BP friction in media (not) moving*/ + kd= sb->mediafrict* sb_fric_force_scale(ob); + /* assume it to be proportional to actual velocity */ + bp->force[0]-= bp->vec[0]*kd; + bp->force[1]-= bp->vec[1]*kd; + bp->force[2]-= bp->vec[2]*kd; + /* friction in media done */ + if(nl_flags & NLF_BUILD){ + //int ia =3*(sb->totpoint-a); + /* da/dv = */ + + // nlMatrixAdd(ia,ia,forcetime*kd); + // nlMatrixAdd(ia+1,ia+1,forcetime*kd); + // nlMatrixAdd(ia+2,ia+2,forcetime*kd); + } + + } + /* +++cached collision targets */ + bp->choke = 0.0f; + bp->choke2 = 0.0f; + bp->flag &= ~SBF_DOFUZZY; + if(do_deflector) { + float cfforce[3],defforce[3] ={0.0f,0.0f,0.0f}, vel[3] = {0.0f,0.0f,0.0f}, facenormal[3], cf = 1.0f,intrusion; + kd = 1.0f; + + if (sb_deflect_face(ob,bp->pos,facenormal,defforce,&cf,timenow,vel,&intrusion)){ + if ((!nl_flags)&&(intrusion < 0.0f)){ + /*bjornmose: uugh.. what an evil hack + violation of the 'don't touch bp->pos in here' rule + but works nice, like this--> + we predict the solution beeing out of the collider + in heun step No1 and leave the heun step No2 adapt to it + so we kind of introduced a implicit solver for this case + */ + Vec3PlusStVec(bp->pos,-intrusion,facenormal); + + sb->scratch->flag |= SBF_DOFUZZY; + bp->flag |= SBF_DOFUZZY; + bp->choke = sb->choke*0.01f; + } + else{ + VECSUB(cfforce,bp->vec,vel); + Vec3PlusStVec(bp->force,-cf*50.0f,cfforce); + } + Vec3PlusStVec(bp->force,kd,defforce); + if (nl_flags & NLF_BUILD){ + // int ia =3*(sb->totpoint-a); + // int op =3*sb->totpoint; + //dfdx_goal(ia,ia,op,mpos); // don't do unless you know + //dfdv_goal(ia,ia,-cf); + + } + + } + + } + /* ---cached collision targets */ + + /* +++springs */ + if(ob->softflag & OB_SB_EDGES) { + if (sb->bspring){ /* spring list exists at all ? */ + for(b=bp->nofsprings;b>0;b--){ + bs = sb->bspring + bp->springs[b-1]; + if (do_springcollision || do_aero){ + VecAddf(bp->force,bp->force,bs->ext_force); + if (bs->flag & BSF_INTERSECT) + bp->choke = bs->cf; + + } + // sb_spring_force(Object *ob,int bpi,BodySpring *bs,float iks,float forcetime,int nl_flags) + // rather remove nl_falgs from code .. will make things a lot cleaner + sb_spring_force(ob,sb->totpoint-a,bs,iks,forcetime,0); + }/* loop springs */ + }/* existing spring list */ + }/*any edges*/ + /* ---springs */ + }/*omit on snap */ + }/*loop all bp's*/ + + + /* finally add forces caused by face collision */ + if (ob->softflag & OB_SB_FACECOLL) scan_for_ext_face_forces(ob,timenow); + + /* finish matrix and solve */ +#if (0) // remove onl linking for now .. still i am not sure .. the jacobian can be usefull .. so keep that BM + if(nl_flags & NLF_SOLVE){ + //double sct,sst=PIL_check_seconds_timer(); + for(a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) { + int iv =3*(sb->totpoint-a); + int ip =3*(2*sb->totpoint-a); + int n; + for (n=0;n<3;n++) {nlRightHandSideSet(0, iv+n, bp->force[0+n]);} + for (n=0;n<3;n++) {nlRightHandSideSet(0, ip+n, bp->vec[0+n]);} + } + nlEnd(NL_MATRIX); + nlEnd(NL_SYSTEM); + + if ((G.rt == 32) && (nl_flags & NLF_BUILD)) + { + printf("####MEE#####\n"); + nlPrintMatrix(); + } + + success= nlSolveAdvanced(NULL, 1); + + // nlPrintMatrix(); /* for debug purpose .. anyhow cropping B vector looks like working */ + if(success){ + float f; + int index =0; + /* for debug purpose .. anyhow cropping B vector looks like working */ + if (G.rt ==32) + for(a=2*sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) { + f=nlGetVariable(0,index); + printf("(%f ",f);index++; + f=nlGetVariable(0,index); + printf("%f ",f);index++; + f=nlGetVariable(0,index); + printf("%f)",f);index++; + } + + index =0; + for(a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) { + f=nlGetVariable(0,index); + bp->impdv[0] = f; index++; + f=nlGetVariable(0,index); + bp->impdv[1] = f; index++; + f=nlGetVariable(0,index); + bp->impdv[2] = f; index++; + } + /* + for(a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) { f=nlGetVariable(0,index); - bp->impdv[0] = f; index++; + bp->impdx[0] = f; index++; f=nlGetVariable(0,index); - bp->impdv[1] = f; index++; + bp->impdx[1] = f; index++; f=nlGetVariable(0,index); - bp->impdv[2] = f; index++; - } - /* + bp->impdx[2] = f; index++; + } + */ + } + else{ + printf("Matrix inversion failed \n"); for(a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) { - f=nlGetVariable(0,index); - bp->impdx[0] = f; index++; - f=nlGetVariable(0,index); - bp->impdx[1] = f; index++; - f=nlGetVariable(0,index); - bp->impdx[2] = f; index++; + VECCOPY(bp->impdv,bp->force); } - */ - } - else{ - printf("Matrix inversion failed \n"); - for(a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) { - VECCOPY(bp->impdv,bp->force); + } + //sct=PIL_check_seconds_timer(); + //if (sct-sst > 0.01f) printf(" implicit solver time %f %s \r",sct-sst,ob->id.name); } - - //sct=PIL_check_seconds_timer(); - //if (sct-sst > 0.01f) printf(" implicit solver time %f %s \r",sct-sst,ob->id.name); - } - /* cleanup */ + /* cleanup */ #endif - if(do_effector) pdEndEffectors(do_effector); + if(do_effector) pdEndEffectors(do_effector); + } } + static void softbody_apply_forces(Object *ob, float forcetime, int mode, float *err, int mid_flags) { /* time evolution */ @@ -2458,7 +2870,7 @@ static void softbody_apply_forces(Object *ob, float forcetime, int mode, float * /* x(t + dt) = x(t) + v(t~) * dt */ VecMulf(dx,forcetime); - /* the freezer */ + /* the freezer coming sooner or later */ /* if ((Inpf(dx,dx)<freezeloc )&&(Inpf(bp->force,bp->force)<freezeforce )){ bp->frozen /=2; @@ -3529,6 +3941,7 @@ static void softbody_step(Object *ob, SoftBody *sb, float dtime) * we don't want to lock up the system if physics fail */ int loops =0 ; + SoftHeunTol = sb->rklimit; /* humm .. this should be calculated from sb parameters and sizes */ if (sb->minloops > 0) forcetimemax = 1.0f / sb->minloops; @@ -3546,13 +3959,13 @@ static void softbody_step(Object *ob, SoftBody *sb, float dtime) sb->scratch->flag &= ~SBF_DOFUZZY; /* do predictive euler step */ softbody_calc_forces(ob, forcetime,timedone/dtime,0); - softbody_apply_forces(ob, forcetime, 1, NULL,mid_flags); + softbody_apply_forces(ob, forcetime, 1, NULL,mid_flags); /* crop new slope values to do averaged slope step */ softbody_calc_forces(ob, forcetime,timedone/dtime,0); - softbody_apply_forces(ob, forcetime, 2, &err,mid_flags); + softbody_apply_forces(ob, forcetime, 2, &err,mid_flags); softbody_apply_goalsnap(ob); if (err > SoftHeunTol) { /* error needs to be scaled to some quantity */ @@ -3603,7 +4016,7 @@ static void softbody_step(Object *ob, SoftBody *sb, float dtime) // if(G.f & G_DEBUG){ if(sb->solverflags & SBSO_MONITOR ){ if (loops > HEUNWARNLIMIT) /* monitor high loop counts */ - printf("\r needed %d steps/frame ",loops); + printf("\r needed %d steps/frame",loops); } } @@ -3627,7 +4040,7 @@ static void softbody_step(Object *ob, SoftBody *sb, float dtime) if(sb->solverflags & SBSO_MONITOR ){ sct=PIL_check_seconds_timer(); - if (sct-sst > 0.5f) printf(" solver time %f %s \r",sct-sst,ob->id.name); + if (sct-sst > 0.5f) printf(" solver time %f sec %s \n",sct-sst,ob->id.name); } } diff --git a/source/blender/blenkernel/intern/texture.c b/source/blender/blenkernel/intern/texture.c index 37804bf68ac..936381c85cc 100644 --- a/source/blender/blenkernel/intern/texture.c +++ b/source/blender/blenkernel/intern/texture.c @@ -53,6 +53,7 @@ #include "DNA_world_types.h" #include "DNA_brush_types.h" #include "DNA_node_types.h" +#include "DNA_scene_types.h" #include "IMB_imbuf_types.h" #include "IMB_imbuf.h" @@ -544,6 +545,8 @@ Tex *copy_texture(Tex *tex) if(texn->type==TEX_IMAGE) id_us_plus((ID *)texn->ima); else texn->ima= 0; + id_us_plus((ID *)texn->ipo); + if(texn->plugin) { texn->plugin= MEM_dupallocN(texn->plugin); open_plugin_tex(texn->plugin); @@ -731,7 +734,7 @@ Tex *give_current_texture(Object *ob, int act) bNode *node; if(ob==0) return 0; - if(ob->totcol==0) return 0; + if(ob->totcol==0 && !(ob->type==OB_LAMP)) return 0; if(ob->type==OB_LAMP) { la=(Lamp *)ob->data; @@ -775,6 +778,18 @@ Tex *give_current_texture(Object *ob, int act) return tex; } +Tex *give_current_world_texture(void) +{ + MTex *mtex = 0; + Tex *tex = 0; + + if(!(G.scene->world)) return 0; + + mtex= G.scene->world->mtex[(int)(G.scene->world->texact)]; + if(mtex) tex= mtex->tex; + + return tex; +} /* ------------------------------------------------------------------------- */ @@ -832,3 +847,19 @@ void BKE_free_envmap(EnvMap *env) } /* ------------------------------------------------------------------------- */ +int BKE_texture_dependsOnTime(const struct Tex *texture) +{ + if(texture->plugin) { + // assume all plugins depend on time + return 1; + } else if( texture->ima && + ELEM(texture->ima->source, IMA_SRC_SEQUENCE, IMA_SRC_MOVIE)) { + return 1; + } else if(texture->ipo) { + // assume any ipo means the texture is animated + return 1; + } + return 0; +} + +/* ------------------------------------------------------------------------- */ diff --git a/source/blender/blenlib/BLI_kdopbvh.h b/source/blender/blenlib/BLI_kdopbvh.h index b81ff0ee66f..6d9a17efebf 100644 --- a/source/blender/blenlib/BLI_kdopbvh.h +++ b/source/blender/blenlib/BLI_kdopbvh.h @@ -1,5 +1,7 @@ /** * + * $Id$ + * * ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or @@ -40,6 +42,35 @@ typedef struct BVHTreeOverlap { int indexB; } BVHTreeOverlap; +typedef struct BVHTreeNearest +{ + int index; /* the index of the nearest found (untouched if none is found within a dist radius from the given coordinates) */ + float co[3]; /* nearest coordinates (untouched it none is found within a dist radius from the given coordinates) */ + float no[3]; /* normal at nearest coordinates (untouched it none is found within a dist radius from the given coordinates) */ + float dist; /* squared distance to search arround */ +} BVHTreeNearest; + +typedef struct BVHTreeRay +{ + float origin[3]; /* ray origin */ + float direction[3]; /* ray direction */ +} BVHTreeRay; + +typedef struct BVHTreeRayHit +{ + int index; /* index of the tree node (untouched if no hit is found) */ + float co[3]; /* coordinates of the hit point */ + float no[3]; /* normal on hit point */ + float dist; /* distance to the hit point */ +} BVHTreeRayHit; + +/* callback must update nearest in case it finds a nearest result */ +typedef void (*BVHTree_NearestPointCallback) (void *userdata, int index, const float *co, BVHTreeNearest *nearest); + +/* callback must update hit in case it finds a nearest successful hit */ +typedef void (*BVHTree_RayCastCallback) (void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit); + + BVHTree *BLI_bvhtree_new(int maxsize, float epsilon, char tree_type, char axis); void BLI_bvhtree_free(BVHTree *tree); @@ -56,5 +87,10 @@ BVHTreeOverlap *BLI_bvhtree_overlap(BVHTree *tree1, BVHTree *tree2, int *result) float BLI_bvhtree_getepsilon(BVHTree *tree); +/* find nearest node to the given coordinates (if nearest is given it will only search nodes where square distance is smaller than nearest->dist) */ +int BLI_bvhtree_find_nearest(BVHTree *tree, const float *co, BVHTreeNearest *nearest, BVHTree_NearestPointCallback callback, void *userdata); + +int BLI_bvhtree_ray_cast(BVHTree *tree, const float *co, const float *dir, BVHTreeRayHit *hit, BVHTree_RayCastCallback callback, void *userdata); + #endif // BLI_KDOPBVH_H diff --git a/source/blender/blenlib/intern/BLI_kdopbvh.c b/source/blender/blenlib/intern/BLI_kdopbvh.c index a97b9ca6672..9671551a7f1 100644 --- a/source/blender/blenlib/intern/BLI_kdopbvh.c +++ b/source/blender/blenlib/intern/BLI_kdopbvh.c @@ -28,8 +28,9 @@ #include "math.h" #include <stdio.h> -#include <stdlib.h> +#include <stdlib.h> #include <string.h> +#include <assert.h> #include "MEM_guardedalloc.h" @@ -42,15 +43,17 @@ #include <omp.h> #endif + + +#define MAX_TREETYPE 32 + typedef struct BVHNode { - struct BVHNode **children; // max 8 children - struct BVHNode *parent; // needed for bottom - top update - float *bv; // Bounding volume of all nodes, max 13 axis - int index; /* face, edge, vertex index */ - char totnode; // how many nodes are used, used for speedup - char traversed; // how many nodes already traversed until this level? - char main_axis; + struct BVHNode **children; + float *bv; // Bounding volume of all nodes, max 13 axis + int index; // face, edge, vertex index + char totnode; // how many nodes are used, used for speedup + char main_axis; // Axis used to split this node } BVHNode; struct BVHTree @@ -72,8 +75,34 @@ typedef struct BVHOverlapData BVHTree *tree1, *tree2; BVHTreeOverlap *overlap; int i, max_overlap; /* i is number of overlaps */ + int start_axis, stop_axis; } BVHOverlapData; -//////////////////////////////////////// + +typedef struct BVHNearestData +{ + BVHTree *tree; + float *co; + BVHTree_NearestPointCallback callback; + void *userdata; + float proj[13]; //coordinates projection over axis + BVHTreeNearest nearest; + +} BVHNearestData; + +typedef struct BVHRayCastData +{ + BVHTree *tree; + + BVHTree_RayCastCallback callback; + void *userdata; + + + BVHTreeRay ray; + float ray_dot_axis[13]; + + BVHTreeRayHit hit; +} BVHRayCastData; +////////////////////////////////////////m //////////////////////////////////////////////////////////////////////// @@ -244,7 +273,7 @@ int partition_nth_element(BVHNode **a, int _begin, int _end, int n, int axis){ int begin = _begin, end = _end, cut; while(end-begin > 3) { - cut = bvh_partition(a, begin, end, bvh_medianof3(a, begin, (begin+end)/2, end-1, axis), axis ); + cut = bvh_partition(a, begin, end, bvh_medianof3(a, begin, (begin+end)/2, end-1, axis), axis ); if(cut <= n) begin = cut; else @@ -255,124 +284,15 @@ int partition_nth_element(BVHNode **a, int _begin, int _end, int n, int axis){ return n; } - ////////////////////////////////////////////////////////////////////////////////////////////////////// -void BLI_bvhtree_free(BVHTree *tree) -{ - if(tree) - { - MEM_freeN(tree->nodes); - MEM_freeN(tree->nodearray); - MEM_freeN(tree->nodebv); - MEM_freeN(tree->nodechild); - MEM_freeN(tree); - } -} - -BVHTree *BLI_bvhtree_new(int maxsize, float epsilon, char tree_type, char axis) -{ - BVHTree *tree; - int numbranches=0, i; - - // only support up to octree - if(tree_type > 8) - return NULL; - - tree = (BVHTree *)MEM_callocN(sizeof(BVHTree), "BVHTree"); - - if(tree) - { - tree->epsilon = epsilon; - tree->tree_type = tree_type; - tree->axis = axis; - - if(axis == 26) - { - tree->start_axis = 0; - tree->stop_axis = 13; - } - else if(axis == 18) - { - tree->start_axis = 7; - tree->stop_axis = 13; - } - else if(axis == 14) - { - tree->start_axis = 0; - tree->stop_axis = 7; - } - else if(axis == 8) // AABB - { - tree->start_axis = 0; - tree->stop_axis = 4; - } - else if(axis == 6) // OBB - { - tree->start_axis = 0; - tree->stop_axis = 3; - } - else - { - MEM_freeN(tree); - return NULL; - } - - - // calculate max number of branches, our bvh kdop is "almost perfect" - for(i = 1; i <= (int)ceil((float)((float)log(maxsize)/(float)log(tree_type))); i++) - numbranches += (pow(tree_type, i) / tree_type); - - tree->nodes = (BVHNode **)MEM_callocN(sizeof(BVHNode *)*(numbranches+maxsize + tree_type), "BVHNodes"); - - if(!tree->nodes) - { - MEM_freeN(tree); - return NULL; - } - - tree->nodebv = (float*)MEM_callocN(sizeof(float)* axis * (numbranches+maxsize + tree_type), "BVHNodeBV"); - if(!tree->nodebv) - { - MEM_freeN(tree->nodes); - MEM_freeN(tree); - } - - tree->nodechild = (BVHNode**)MEM_callocN(sizeof(BVHNode*) * tree_type * (numbranches+maxsize + tree_type), "BVHNodeBV"); - if(!tree->nodechild) - { - MEM_freeN(tree->nodebv); - MEM_freeN(tree->nodes); - MEM_freeN(tree); - } - - tree->nodearray = (BVHNode *)MEM_callocN(sizeof(BVHNode)*(numbranches+maxsize + tree_type), "BVHNodeArray"); - - if(!tree->nodearray) - { - MEM_freeN(tree->nodechild); - MEM_freeN(tree->nodebv); - MEM_freeN(tree->nodes); - MEM_freeN(tree); - return NULL; - } - - //link the dynamic bv and child links - for(i=0; i< numbranches+maxsize + tree_type; i++) - { - tree->nodearray[i].bv = tree->nodebv + i * axis; - tree->nodearray[i].children = tree->nodechild + i * tree_type; - } - - } - - return tree; -} - - +/* + * BVHTree bounding volumes functions + */ static void create_kdop_hull(BVHTree *tree, BVHNode *node, float *co, int numpoints, int moving) { float newminmax; + float *bv = node->bv; int i, k; // don't init boudings for the moving case @@ -380,8 +300,8 @@ static void create_kdop_hull(BVHTree *tree, BVHNode *node, float *co, int numpoi { for (i = tree->start_axis; i < tree->stop_axis; i++) { - node->bv[2*i] = FLT_MAX; - node->bv[2*i + 1] = -FLT_MAX; + bv[2*i] = FLT_MAX; + bv[2*i + 1] = -FLT_MAX; } } @@ -391,10 +311,10 @@ static void create_kdop_hull(BVHTree *tree, BVHNode *node, float *co, int numpoi for (i = tree->start_axis; i < tree->stop_axis; i++) { newminmax = INPR(&co[k * 3], KDOP_AXES[i]); - if (newminmax < node->bv[2 * i]) - node->bv[2 * i] = newminmax; - if (newminmax > node->bv[(2 * i) + 1]) - node->bv[(2 * i) + 1] = newminmax; + if (newminmax < bv[2 * i]) + bv[2 * i] = newminmax; + if (newminmax > bv[(2 * i) + 1]) + bv[(2 * i) + 1] = newminmax; } } } @@ -405,6 +325,7 @@ static void refit_kdop_hull(BVHTree *tree, BVHNode *node, int start, int end) float newmin,newmax; int i, j; float *bv = node->bv; + for (i = tree->start_axis; i < tree->stop_axis; i++) { @@ -426,37 +347,7 @@ static void refit_kdop_hull(BVHTree *tree, BVHNode *node, int start, int end) bv[(2 * i) + 1] = newmax; } } -} -int BLI_bvhtree_insert(BVHTree *tree, int index, float *co, int numpoints) -{ - BVHNode *node= NULL; - int i; - - // insert should only possible as long as tree->totbranch is 0 - if(tree->totbranch > 0) - return 0; - - if(tree->totleaf+1 >= MEM_allocN_len(tree->nodes)) - return 0; - - // TODO check if have enough nodes in array - - node = tree->nodes[tree->totleaf] = &(tree->nodearray[tree->totleaf]); - tree->totleaf++; - - create_kdop_hull(tree, node, co, numpoints, 0); - - // inflate the bv with some epsilon - for (i = tree->start_axis; i < tree->stop_axis; i++) - { - node->bv[(2 * i)] -= tree->epsilon; // minimum - node->bv[(2 * i) + 1] += tree->epsilon; // maximum - } - - node->index= index; - - return 1; } // only supports x,y,z axis in the moment @@ -484,46 +375,76 @@ static char get_largest_axis(float *bv) } } -static void bvh_div_nodes(BVHTree *tree, BVHNode *node, int start, int end, char lastaxis) +// bottom-up update of bvh node BV +// join the children on the parent BV +static void node_join(BVHTree *tree, BVHNode *node) { - char laxis; - int i, tend; - BVHNode *tnode; - int slice = (end-start+tree->tree_type-1)/tree->tree_type; //division rounded up + int i, j; - // Determine which axis to split along - laxis = get_largest_axis(node->bv); + for (i = tree->start_axis; i < tree->stop_axis; i++) + { + node->bv[2*i] = FLT_MAX; + node->bv[2*i + 1] = -FLT_MAX; + } - // split nodes along longest axis - for (i=0; start < end; start += slice, i++) //i counts the current child - { - tend = start + slice; - - if(tend > end) tend = end; - - if(tend-start == 1) // ok, we have 1 left for this node + for (i = 0; i < tree->tree_type; i++) + { + if (node->children[i]) { - node->children[i] = tree->nodes[start]; - node->children[i]->parent = node; + for (j = tree->start_axis; j < tree->stop_axis; j++) + { + // update minimum + if (node->children[i]->bv[(2 * j)] < node->bv[(2 * j)]) + node->bv[(2 * j)] = node->children[i]->bv[(2 * j)]; + + // update maximum + if (node->children[i]->bv[(2 * j) + 1] > node->bv[(2 * j) + 1]) + node->bv[(2 * j) + 1] = node->children[i]->bv[(2 * j) + 1]; + } } else - { - tnode = node->children[i] = tree->nodes[tree->totleaf + tree->totbranch] = &(tree->nodearray[tree->totbranch + tree->totleaf]); - tree->totbranch++; - tnode->parent = node; - - if(tend != end) - partition_nth_element(tree->nodes, start, end, tend, laxis); - refit_kdop_hull(tree, tnode, start, tend); - bvh_div_nodes(tree, tnode, start, tend, laxis); - } - node->totnode++; + break; } - - return; +} + +/* + * Debug and information functions + */ +static void bvhtree_print_tree(BVHTree *tree, BVHNode *node, int depth) +{ + int i; + for(i=0; i<depth; i++) printf(" "); + printf(" - %d (%d): ", node->index, node - tree->nodearray); + for(i=2*tree->start_axis; i<2*tree->stop_axis; i++) + printf("%.3f ", node->bv[i]); + printf("\n"); + + for(i=0; i<tree->tree_type; i++) + if(node->children[i]) + bvhtree_print_tree(tree, node->children[i], depth+1); +} + +static void bvhtree_info(BVHTree *tree) +{ + printf("BVHTree info\n"); + printf("tree_type = %d, axis = %d, epsilon = %f\n", tree->tree_type, tree->axis, tree->epsilon); + printf("nodes = %d, branches = %d, leafs = %d\n", tree->totbranch + tree->totleaf, tree->totbranch, tree->totleaf); + printf("Memory per node = %dbytes\n", sizeof(BVHNode) + sizeof(BVHNode*)*tree->tree_type + sizeof(float)*tree->axis); + printf("BV memory = %dbytes\n", MEM_allocN_len(tree->nodebv)); + + printf("Total memory = %dbytes\n", sizeof(BVHTree) + + MEM_allocN_len(tree->nodes) + + MEM_allocN_len(tree->nodearray) + + MEM_allocN_len(tree->nodechild) + + MEM_allocN_len(tree->nodebv) + ); + +// bvhtree_print_tree(tree, tree->nodes[tree->totleaf], 0); } #if 0 + + static void verify_tree(BVHTree *tree) { int i, j, check = 0; @@ -571,29 +492,445 @@ static void verify_tree(BVHTree *tree) printf("branches: %d, leafs: %d, total: %d\n", tree->totbranch, tree->totleaf, tree->totbranch + tree->totleaf); } #endif + +//Helper data and structures to build a min-leaf generalized implicit tree +//This code can be easily reduced (basicly this is only method to calculate pow(k, n) in O(1).. and stuff like that) +typedef struct BVHBuildHelper +{ + int tree_type; // + int totleafs; // + + int leafs_per_child [32]; //Min number of leafs that are archievable from a node at depth N + int branches_on_level[32]; //Number of nodes at depth N (tree_type^N) + + int remain_leafs; //Number of leafs that are placed on the level that is not 100% filled + +} BVHBuildHelper; + +static void build_implicit_tree_helper(BVHTree *tree, BVHBuildHelper *data) +{ + int depth = 0; + int remain; + int nnodes; + + data->totleafs = tree->totleaf; + data->tree_type= tree->tree_type; + + //Calculate the smallest tree_type^n such that tree_type^n >= num_leafs + for( + data->leafs_per_child[0] = 1; + data->leafs_per_child[0] < data->totleafs; + data->leafs_per_child[0] *= data->tree_type + ); + + data->branches_on_level[0] = 1; + + //We could stop the loop first (but I am lazy to find out when) + for(depth = 1; depth < 32; depth++) + { + data->branches_on_level[depth] = data->branches_on_level[depth-1] * data->tree_type; + data->leafs_per_child [depth] = data->leafs_per_child [depth-1] / data->tree_type; + } + + remain = data->totleafs - data->leafs_per_child[1]; + nnodes = (remain + data->tree_type - 2) / (data->tree_type - 1); + data->remain_leafs = remain + nnodes; +} + +// return the min index of all the leafs archivable with the given branch +static int implicit_leafs_index(BVHBuildHelper *data, int depth, int child_index) +{ + int min_leaf_index = child_index * data->leafs_per_child[depth-1]; + if(min_leaf_index <= data->remain_leafs) + return min_leaf_index; + else if(data->leafs_per_child[depth]) + return data->totleafs - (data->branches_on_level[depth-1] - child_index) * data->leafs_per_child[depth]; + else + return data->remain_leafs; +} + +/** + * Generalized implicit tree build + * + * An implicit tree is a tree where its structure is implied, thus there is no need to store child pointers or indexs. + * Its possible to find the position of the child or the parent with simple maths (multiplication and adittion). This type + * of tree is for example used on heaps.. where node N has its childs at indexs N*2 and N*2+1. + * + * Altought in this case the tree type is general.. and not know until runtime. + * tree_type stands for the maximum number of childs that a tree node can have. + * All tree types >= 2 are supported. + * + * Advantages of the used trees include: + * - No need to store child/parent relations (they are implicit); + * - Any node child always has an index greater than the parent; + * - Brother nodes are sequencial in memory; + * + * + * Some math relations derived for general implicit trees: + * + * K = tree_type, ( 2 <= K ) + * ROOT = 1 + * N child of node A = A * K + (2 - K) + N, (0 <= N < K) + * + * Util methods: + * TODO... + * (looping elements, knowing if its a leaf or not.. etc...) + */ + +// This functions returns the number of branches needed to have the requested number of leafs. +static int implicit_needed_branches(int tree_type, int leafs) +{ + return MAX2(1, (leafs + tree_type - 3) / (tree_type-1) ); +} + +/* + * This function handles the problem of "sorting" the leafs (along the split_axis). + * + * It arranges the elements in the given partitions such that: + * - any element in partition N is less or equal to any element in partition N+1. + * - if all elements are diferent all partition will get the same subset of elements + * as if the array was sorted. + * + * partition P is described as the elements in the range ( nth[P] , nth[P+1] ] + * + * TODO: This can be optimized a bit by doing a specialized nth_element instead of K nth_elements + */ +static void split_leafs(BVHNode **leafs_array, int *nth, int partitions, int split_axis) +{ + int i; + for(i=0; i < partitions-1; i++) + { + if(nth[i] >= nth[partitions]) + break; + + partition_nth_element(leafs_array, nth[i], nth[partitions], nth[i+1], split_axis); + } +} + +/* + * This functions builds an optimal implicit tree from the given leafs. + * Where optimal stands for: + * - The resulting tree will have the smallest number of branches; + * - At most only one branch will have NULL childs; + * - All leafs will be stored at level N or N+1. + * + * This function creates an implicit tree on branches_array, the leafs are given on the leafs_array. + * + * The tree is built per depth levels. First branchs at depth 1.. then branches at depth 2.. etc.. + * The reason is that we can build level N+1 from level N witouth any data dependencies.. thus it allows + * to use multithread building. + * + * To archieve this is necessary to find how much leafs are accessible from a certain branch, BVHBuildHelper + * implicit_needed_branches and implicit_leafs_index are auxiliar functions to solve that "optimal-split". + */ +static void non_recursive_bvh_div_nodes(BVHTree *tree, BVHNode *branches_array, BVHNode **leafs_array, int num_leafs) +{ + int i; + + const int tree_type = tree->tree_type; + const int tree_offset = 2 - tree->tree_type; //this value is 0 (on binary trees) and negative on the others + const int num_branches= implicit_needed_branches(tree_type, num_leafs); + + BVHBuildHelper data; + int depth; + + branches_array--; //Implicit trees use 1-based indexs + + build_implicit_tree_helper(tree, &data); + + //Loop tree levels (log N) loops + for(i=1, depth = 1; i <= num_branches; i = i*tree_type + tree_offset, depth++) + { + const int first_of_next_level = i*tree_type + tree_offset; + const int end_j = MIN2(first_of_next_level, num_branches + 1); //index of last branch on this level + int j; + + //Loop all branches on this level +#pragma omp parallel for private(j) schedule(static) + for(j = i; j < end_j; j++) + { + int k; + const int parent_level_index= j-i; + BVHNode* parent = branches_array + j; + int nth_positions[ MAX_TREETYPE + 1]; + char split_axis; + + int parent_leafs_begin = implicit_leafs_index(&data, depth, parent_level_index); + int parent_leafs_end = implicit_leafs_index(&data, depth, parent_level_index+1); + + //This calculates the bounding box of this branch + //and chooses the largest axis as the axis to divide leafs + refit_kdop_hull(tree, parent, parent_leafs_begin, parent_leafs_end); + split_axis = get_largest_axis(parent->bv); + + //Save split axis (this can be used on raytracing to speedup the query time) + parent->main_axis = split_axis / 2; + + //Split the childs along the split_axis, note: its not needed to sort the whole leafs array + //Only to assure that the elements are partioned on a way that each child takes the elements + //it would take in case the whole array was sorted. + //Split_leafs takes care of that "sort" problem. + nth_positions[ 0] = parent_leafs_begin; + nth_positions[tree_type] = parent_leafs_end; + for(k = 1; k < tree_type; k++) + { + int child_index = j * tree_type + tree_offset + k; + int child_level_index = child_index - first_of_next_level; //child level index + nth_positions[k] = implicit_leafs_index(&data, depth+1, child_level_index); + } + + split_leafs(leafs_array, nth_positions, tree_type, split_axis); + + + //Setup children and totnode counters + //Not really needed but currently most of BVH code relies on having an explicit children structure + for(k = 0; k < tree_type; k++) + { + int child_index = j * tree_type + tree_offset + k; + int child_level_index = child_index - first_of_next_level; //child level index + + int child_leafs_begin = implicit_leafs_index(&data, depth+1, child_level_index); + int child_leafs_end = implicit_leafs_index(&data, depth+1, child_level_index+1); + + if(child_leafs_end - child_leafs_begin > 1) + parent->children[k] = branches_array + child_index; + else if(child_leafs_end - child_leafs_begin == 1) + parent->children[k] = leafs_array[ child_leafs_begin ]; + else + break; + + parent->totnode = k+1; + } + } + } +} + + +/* + * BLI_bvhtree api + */ +BVHTree *BLI_bvhtree_new(int maxsize, float epsilon, char tree_type, char axis) +{ + BVHTree *tree; + int numnodes, i; + // theres not support for trees below binary-trees :P + if(tree_type < 2) + return NULL; + + if(tree_type > MAX_TREETYPE) + return NULL; + + tree = (BVHTree *)MEM_callocN(sizeof(BVHTree), "BVHTree"); + + if(tree) + { + tree->epsilon = epsilon; + tree->tree_type = tree_type; + tree->axis = axis; + + if(axis == 26) + { + tree->start_axis = 0; + tree->stop_axis = 13; + } + else if(axis == 18) + { + tree->start_axis = 7; + tree->stop_axis = 13; + } + else if(axis == 14) + { + tree->start_axis = 0; + tree->stop_axis = 7; + } + else if(axis == 8) // AABB + { + tree->start_axis = 0; + tree->stop_axis = 4; + } + else if(axis == 6) // OBB + { + tree->start_axis = 0; + tree->stop_axis = 3; + } + else + { + MEM_freeN(tree); + return NULL; + } + + + //Allocate arrays + numnodes = maxsize + implicit_needed_branches(tree_type, maxsize) + tree_type; + + tree->nodes = (BVHNode **)MEM_callocN(sizeof(BVHNode *)*numnodes, "BVHNodes"); + + if(!tree->nodes) + { + MEM_freeN(tree); + return NULL; + } + + tree->nodebv = (float*)MEM_callocN(sizeof(float)* axis * numnodes, "BVHNodeBV"); + if(!tree->nodebv) + { + MEM_freeN(tree->nodes); + MEM_freeN(tree); + } + + tree->nodechild = (BVHNode**)MEM_callocN(sizeof(BVHNode*) * tree_type * numnodes, "BVHNodeBV"); + if(!tree->nodechild) + { + MEM_freeN(tree->nodebv); + MEM_freeN(tree->nodes); + MEM_freeN(tree); + } + + tree->nodearray = (BVHNode *)MEM_callocN(sizeof(BVHNode)* numnodes, "BVHNodeArray"); + + if(!tree->nodearray) + { + MEM_freeN(tree->nodechild); + MEM_freeN(tree->nodebv); + MEM_freeN(tree->nodes); + MEM_freeN(tree); + return NULL; + } + + //link the dynamic bv and child links + for(i=0; i< numnodes; i++) + { + tree->nodearray[i].bv = tree->nodebv + i * axis; + tree->nodearray[i].children = tree->nodechild + i * tree_type; + } + + } + + return tree; +} + +void BLI_bvhtree_free(BVHTree *tree) +{ + if(tree) + { + MEM_freeN(tree->nodes); + MEM_freeN(tree->nodearray); + MEM_freeN(tree->nodebv); + MEM_freeN(tree->nodechild); + MEM_freeN(tree); + } +} + void BLI_bvhtree_balance(BVHTree *tree) { - BVHNode *node; + int i; + + BVHNode* branches_array = tree->nodearray + tree->totleaf; + BVHNode** leafs_array = tree->nodes; + + //This function should only be called once (some big bug goes here if its being called more than once per tree) + assert(tree->totbranch == 0); + + //Build the implicit tree + non_recursive_bvh_div_nodes(tree, branches_array, leafs_array, tree->totleaf); + + //current code expects the branches to be linked to the nodes array + //we perform that linkage here + tree->totbranch = implicit_needed_branches(tree->tree_type, tree->totleaf); + for(i = 0; i < tree->totbranch; i++) + tree->nodes[tree->totleaf + i] = branches_array + i; + + //bvhtree_info(tree); +} + +int BLI_bvhtree_insert(BVHTree *tree, int index, float *co, int numpoints) +{ + int i; + BVHNode *node = NULL; - if(tree->totleaf == 0) - return; + // insert should only possible as long as tree->totbranch is 0 + if(tree->totbranch > 0) + return 0; + + if(tree->totleaf+1 >= MEM_allocN_len(tree->nodes)/sizeof(*(tree->nodes))) + return 0; + + // TODO check if have enough nodes in array - // create root node node = tree->nodes[tree->totleaf] = &(tree->nodearray[tree->totleaf]); - tree->totbranch++; + tree->totleaf++; + + create_kdop_hull(tree, node, co, numpoints, 0); + node->index= index; + + // inflate the bv with some epsilon + for (i = tree->start_axis; i < tree->stop_axis; i++) + { + node->bv[(2 * i)] -= tree->epsilon; // minimum + node->bv[(2 * i) + 1] += tree->epsilon; // maximum + } + + return 1; +} + + +// call before BLI_bvhtree_update_tree() +int BLI_bvhtree_update_node(BVHTree *tree, int index, float *co, float *co_moving, int numpoints) +{ + int i; + BVHNode *node= NULL; + + // check if index exists + if(index > tree->totleaf) + return 0; - // refit root bvh node - refit_kdop_hull(tree, tree->nodes[tree->totleaf], 0, tree->totleaf); - // create + balance tree - bvh_div_nodes(tree, tree->nodes[tree->totleaf], 0, tree->totleaf, 0); + node = tree->nodearray + index; + + create_kdop_hull(tree, node, co, numpoints, 0); - // verify_tree(tree); + if(co_moving) + create_kdop_hull(tree, node, co_moving, numpoints, 1); + + // inflate the bv with some epsilon + for (i = tree->start_axis; i < tree->stop_axis; i++) + { + node->bv[(2 * i)] -= tree->epsilon; // minimum + node->bv[(2 * i) + 1] += tree->epsilon; // maximum + } + + return 1; +} + +// call BLI_bvhtree_update_node() first for every node/point/triangle +void BLI_bvhtree_update_tree(BVHTree *tree) +{ + //Update bottom=>top + //TRICKY: the way we build the tree all the childs have an index greater than the parent + //This allows us todo a bottom up update by starting on the biger numbered branch + + BVHNode** root = tree->nodes + tree->totleaf; + BVHNode** index = tree->nodes + tree->totleaf + tree->totbranch-1; + + for (; index >= root; index--) + node_join(tree, *index); } +float BLI_bvhtree_getepsilon(BVHTree *tree) +{ + return tree->epsilon; +} + + +/* + * BLI_bvhtree_overlap + */ // overlap - is it possbile for 2 bv's to collide ? -static int tree_overlap(float *bv1, float *bv2, int start_axis, int stop_axis) +static int tree_overlap(BVHNode *node1, BVHNode *node2, int start_axis, int stop_axis) { + float *bv1 = node1->bv; + float *bv2 = node2->bv; + float *bv1_end = bv1 + (stop_axis<<1); bv1 += start_axis<<1; @@ -613,7 +950,7 @@ static void traverse(BVHOverlapData *data, BVHNode *node1, BVHNode *node2) { int j; - if(tree_overlap(node1->bv, node2->bv, MIN2(data->tree1->start_axis, data->tree2->start_axis), MIN2(data->tree1->stop_axis, data->tree2->stop_axis))) + if(tree_overlap(node1, node2, data->start_axis, data->stop_axis)) { // check if node1 is a leaf if(!node1->totnode) @@ -679,7 +1016,7 @@ BVHTreeOverlap *BLI_bvhtree_overlap(BVHTree *tree1, BVHTree *tree2, int *result) return 0; // fast check root nodes for collision before doing big splitting + traversal - if(!tree_overlap(tree1->nodes[tree1->totleaf]->bv, tree2->nodes[tree2->totleaf]->bv, MIN2(tree1->start_axis, tree2->start_axis), MIN2(tree1->stop_axis, tree2->stop_axis))) + if(!tree_overlap(tree1->nodes[tree1->totleaf], tree2->nodes[tree2->totleaf], MIN2(tree1->start_axis, tree2->start_axis), MIN2(tree1->stop_axis, tree2->stop_axis))) return 0; data = MEM_callocN(sizeof(BVHOverlapData *)* tree1->tree_type, "BVHOverlapData_star"); @@ -694,6 +1031,8 @@ BVHTreeOverlap *BLI_bvhtree_overlap(BVHTree *tree1, BVHTree *tree2, int *result) data[j]->tree2 = tree2; data[j]->max_overlap = MAX2(tree1->totleaf, tree2->totleaf); data[j]->i = 0; + data[j]->start_axis = MIN2(tree1->start_axis, tree2->start_axis); + data[j]->stop_axis = MIN2(tree1->stop_axis, tree2->stop_axis ); } #pragma omp parallel for private(j) schedule(static) @@ -725,88 +1064,251 @@ BVHTreeOverlap *BLI_bvhtree_overlap(BVHTree *tree1, BVHTree *tree2, int *result) } -// bottom up update of bvh tree: -// join the 4 children here -static void node_join(BVHTree *tree, BVHNode *node) +/* + * Nearest neighbour - BLI_bvhtree_find_nearest + */ +static float squared_dist(const float *a, const float *b) { - int i, j; - - for (i = tree->start_axis; i < tree->stop_axis; i++) + float tmp[3]; + VECSUB(tmp, a, b); + return INPR(tmp, tmp); +} + +//Determines the nearest point of the given node BV. Returns the squared distance to that point. +static float calc_nearest_point(BVHNearestData *data, BVHNode *node, float *nearest) +{ + int i; + const float *bv = node->bv; + + //nearest on AABB hull + for(i=0; i != 3; i++, bv += 2) { - node->bv[2*i] = FLT_MAX; - node->bv[2*i + 1] = -FLT_MAX; + if(bv[0] > data->proj[i]) + nearest[i] = bv[0]; + else if(bv[1] < data->proj[i]) + nearest[i] = bv[1]; + else + nearest[i] = data->proj[i]; } - - for (i = 0; i < tree->tree_type; i++) + +/* + //nearest on a general hull + VECCOPY(nearest, data->co); + for(i = data->tree->start_axis; i != data->tree->stop_axis; i++, bv+=2) { - if (node->children[i]) + float proj = INPR( nearest, KDOP_AXES[i]); + float dl = bv[0] - proj; + float du = bv[1] - proj; + + if(dl > 0) { - for (j = tree->start_axis; j < tree->stop_axis; j++) - { - // update minimum - if (node->children[i]->bv[(2 * j)] < node->bv[(2 * j)]) - node->bv[(2 * j)] = node->children[i]->bv[(2 * j)]; - - // update maximum - if (node->children[i]->bv[(2 * j) + 1] > node->bv[(2 * j) + 1]) - node->bv[(2 * j) + 1] = node->children[i]->bv[(2 * j) + 1]; - } + VECADDFAC(nearest, nearest, KDOP_AXES[i], dl); + } + else if(du < 0) + { + VECADDFAC(nearest, nearest, KDOP_AXES[i], du); } + } +*/ + return squared_dist(data->co, nearest); +} + + +// TODO: use a priority queue to reduce the number of nodes looked on +static void dfs_find_nearest(BVHNearestData *data, BVHNode *node) +{ + int i; + float nearest[3], sdist; + + sdist = calc_nearest_point(data, node, nearest); + if(sdist >= data->nearest.dist) return; + + if(node->totnode == 0) + { + if(data->callback) + data->callback(data->userdata , node->index, data->co, &data->nearest); else - break; + { + data->nearest.index = node->index; + VECCOPY(data->nearest.co, nearest); + data->nearest.dist = sdist; + } + } + else + { + for(i=0; i != node->totnode; i++) + dfs_find_nearest(data, node->children[i]); } } -// call before BLI_bvhtree_update_tree() -int BLI_bvhtree_update_node(BVHTree *tree, int index, float *co, float *co_moving, int numpoints) +int BLI_bvhtree_find_nearest(BVHTree *tree, const float *co, BVHTreeNearest *nearest, BVHTree_NearestPointCallback callback, void *userdata) { - BVHNode *node= NULL; - int i = 0; - - // check if index exists - if(index > tree->totleaf) - return 0; - - node = tree->nodearray + index; - - create_kdop_hull(tree, node, co, numpoints, 0); - - if(co_moving) - create_kdop_hull(tree, node, co_moving, numpoints, 1); - - // inflate the bv with some epsilon - for (i = tree->start_axis; i < tree->stop_axis; i++) + int i; + + BVHNearestData data; + BVHNode* root = tree->nodes[tree->totleaf]; + + //init data to search + data.tree = tree; + data.co = co; + + data.callback = callback; + data.userdata = userdata; + + for(i = data.tree->start_axis; i != data.tree->stop_axis; i++) { - node->bv[(2 * i)] -= tree->epsilon; // minimum - node->bv[(2 * i) + 1] += tree->epsilon; // maximum + data.proj[i] = INPR(data.co, KDOP_AXES[i]); } - - return 1; + + if(nearest) + { + memcpy( &data.nearest , nearest, sizeof(*nearest) ); + } + else + { + data.nearest.index = -1; + data.nearest.dist = FLT_MAX; + } + + //dfs search + if(root) + dfs_find_nearest(&data, root); + + //copy back results + if(nearest) + { + memcpy(nearest, &data.nearest, sizeof(*nearest)); + } + + return data.nearest.index; } -// call BLI_bvhtree_update_node() first for every node/point/triangle -void BLI_bvhtree_update_tree(BVHTree *tree) + +/* + * Raycast - BLI_bvhtree_ray_cast + * + * raycast is done by performing a DFS on the BVHTree and saving the closest hit + */ + +//Determines the distance that the ray must travel to hit the bounding volume of the given node +static float ray_nearest_hit(BVHRayCastData *data, BVHNode *node) { - BVHNode *leaf, *parent; - - // reset tree traversing flag - for (leaf = tree->nodearray + tree->totleaf; leaf != tree->nodearray + tree->totleaf + tree->totbranch; leaf++) - leaf->traversed = 0; + int i; + const float *bv = node->bv; + + float low = 0, upper = data->hit.dist; + + for(i=0; i != 3; i++, bv += 2) + { + if(data->ray_dot_axis[i] == 0.0f) + { + //axis aligned ray + if(data->ray.origin[i] < bv[0] + || data->ray.origin[i] > bv[1]) + return FLT_MAX; + } + else + { + 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(ll > low) low = ll; + if(lu < upper) upper = lu; + } + else + { + if(lu > low) low = lu; + if(ll < upper) upper = ll; + } - for (leaf = tree->nodearray; leaf != tree->nodearray + tree->totleaf; leaf++) + if(low > upper) return FLT_MAX; + } + } + return low; +} + +static void dfs_raycast(BVHRayCastData *data, BVHNode *node) +{ + int i; + + //ray-bv is really fast.. and simple tests revealed its worth to test it + //before calling the ray-primitive functions + float dist = ray_nearest_hit(data, node); + if(dist >= data->hit.dist) return; + + if(node->totnode == 0) { - for (parent = leaf->parent; parent; parent = parent->parent) + if(data->callback) + data->callback(data->userdata, node->index, &data->ray, &data->hit); + else { - parent->traversed++; // we tried to go up in hierarchy - if (parent->traversed < parent->totnode) - break; // we do not need to check further - else - node_join(tree, parent); + data->hit.index = node->index; + data->hit.dist = dist; + VECADDFAC(data->hit.co, data->ray.origin, data->ray.direction, dist); + } + } + 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) + { + for(i=0; i != node->totnode; i++) + { + dfs_raycast(data, node->children[i]); + } + } + else + { + for(i=node->totnode-1; i >= 0; i--) + { + dfs_raycast(data, node->children[i]); + } } } } -float BLI_bvhtree_getepsilon(BVHTree *tree) +int BLI_bvhtree_ray_cast(BVHTree *tree, const float *co, const float *dir, BVHTreeRayHit *hit, BVHTree_RayCastCallback callback, void *userdata) { - return tree->epsilon; + int i; + BVHRayCastData data; + BVHNode * root = tree->nodes[tree->totleaf]; + + data.tree = tree; + + data.callback = callback; + data.userdata = userdata; + + VECCOPY(data.ray.origin, co); + VECCOPY(data.ray.direction, dir); + + Normalize(data.ray.direction); + + for(i=0; i<3; i++) + { + data.ray_dot_axis[i] = INPR( data.ray.direction, KDOP_AXES[i]); + + if(fabs(data.ray_dot_axis[i]) < 1e-7) + data.ray_dot_axis[i] = 0.0; + } + + + if(hit) + memcpy( &data.hit, hit, sizeof(*hit) ); + else + { + data.hit.index = -1; + data.hit.dist = FLT_MAX; + } + + if(root) + dfs_raycast(&data, root); + + + if(hit) + memcpy( hit, &data.hit, sizeof(*hit) ); + + return data.hit.index; } + diff --git a/source/blender/blenlib/intern/boxpack2d.c b/source/blender/blenlib/intern/boxpack2d.c index acd53e5d516..db7bae8a91d 100644 --- a/source/blender/blenlib/intern/boxpack2d.c +++ b/source/blender/blenlib/intern/boxpack2d.c @@ -42,6 +42,8 @@ #define TRF 2 #define TLF 4 #define BRF 8 +#define CORNERFLAGS (BLF|TRF|TLF|BRF) + #define BL 0 #define TR 1 #define TL 2 @@ -159,7 +161,7 @@ void boxPack2D(boxPack *boxarray, int len, float *tot_width, float *tot_height) vert->blb = vert->brb = vert->tlb =\ vert->isect_cache[0] = vert->isect_cache[1] =\ vert->isect_cache[2] = vert->isect_cache[3] = NULL; - vert->free = 15 &~ TRF; + vert->free = CORNERFLAGS &~ TRF; vert->trb = box; vert->index = i; i++; box->v[BL] = vert; vert++; @@ -167,7 +169,7 @@ void boxPack2D(boxPack *boxarray, int len, float *tot_width, float *tot_height) vert->trb= vert->brb = vert->tlb =\ vert->isect_cache[0] = vert->isect_cache[1] =\ vert->isect_cache[2] = vert->isect_cache[3] = NULL; - vert->free = 15 &~ BLF; + vert->free = CORNERFLAGS &~ BLF; vert->blb = box; vert->index = i; i++; box->v[TR] = vert; vert++; @@ -175,7 +177,7 @@ void boxPack2D(boxPack *boxarray, int len, float *tot_width, float *tot_height) vert->trb = vert->blb = vert->tlb =\ vert->isect_cache[0] = vert->isect_cache[1] =\ vert->isect_cache[2] = vert->isect_cache[3] = NULL; - vert->free = 15 &~ BRF; + vert->free = CORNERFLAGS &~ BRF; vert->brb = box; vert->index = i; i++; box->v[TL] = vert; vert++; @@ -183,7 +185,7 @@ void boxPack2D(boxPack *boxarray, int len, float *tot_width, float *tot_height) vert->trb = vert->blb = vert->brb =\ vert->isect_cache[0] = vert->isect_cache[1] =\ vert->isect_cache[2] = vert->isect_cache[3] = NULL; - vert->free = 15 &~ TLF; + vert->free = CORNERFLAGS &~ TLF; vert->tlb = box; vert->index = i; i++; box->v[BR] = vert; vert++; diff --git a/source/blender/blenlib/intern/freetypefont.c b/source/blender/blenlib/intern/freetypefont.c index 8b979f9ed23..74f152ac635 100644 --- a/source/blender/blenlib/intern/freetypefont.c +++ b/source/blender/blenlib/intern/freetypefont.c @@ -405,7 +405,7 @@ static VFontData *objfnt_to_ftvfontdata(PackedFile * pf) lcode = charcode; } - err = FT_Set_Charmap( face, (FT_CharMap) FT_ENCODING_UNICODE ); + err = FT_Select_Charmap( face, FT_ENCODING_UNICODE ); return vfd; } diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 62b15e51b35..ed9e2f079b1 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -4882,6 +4882,49 @@ void idproperties_fix_group_lengths(ListBase idlist) } } +void alphasort_version_246(FileData *fd, Library *lib, Mesh *me) +{ + Material *ma; + MFace *mf; + MTFace *tf; + int a, b, texalpha; + + /* verify we have a tface layer */ + for(b=0; b<me->fdata.totlayer; b++) + if(me->fdata.layers[b].type == CD_MTFACE) + break; + + if(b == me->fdata.totlayer) + return; + + /* if we do, set alpha sort if the game engine did it before */ + for(a=0, mf=me->mface; a<me->totface; a++, mf++) { + if(mf->mat_nr < me->totcol) { + ma= newlibadr(fd, lib, me->mat[mf->mat_nr]); + texalpha = 0; + + for(b=0; ma && b<MAX_MTEX; b++) + if(ma->mtex && ma->mtex[b] && ma->mtex[b]->mapto & MAP_ALPHA) + texalpha = 1; + } + else { + ma= NULL; + texalpha = 0; + } + + for(b=0; b<me->fdata.totlayer; b++) { + if(me->fdata.layers[b].type == CD_MTFACE) { + tf = ((MTFace*)me->fdata.layers[b].data) + a; + + tf->mode &= ~TF_ALPHASORT; + if(ma && (ma->mode & MA_ZTRA)) + if(ELEM(tf->transp, TF_ALPHA, TF_ADD) || (texalpha && (tf->transp != TF_CLIP))) + tf->mode |= TF_ALPHASORT; + } + } + } +} + static void do_versions(FileData *fd, Library *lib, Main *main) { /* WATCH IT!!!: pointers from libdata have not been converted */ @@ -7726,8 +7769,9 @@ static void do_versions(FileData *fd, Library *lib, Main *main) } /* sun/sky */ - if ((main->versionfile < 246) ){ + if(main->versionfile < 246) { Lamp *la; + for(la=main->lamp.first; la; la= la->id.next) { la->sun_effect_type = 0; la->horizon_brightness = 1.0; @@ -7743,6 +7787,13 @@ static void do_versions(FileData *fd, Library *lib, Main *main) } } + if(main->versionfile <= 246 && main->subversionfile < 1){ + Mesh *me; + + for(me=main->mesh.first; me; me= me->id.next) + alphasort_version_246(fd, lib, me); + } + /* TODO: should be moved into one of the version blocks once this branch moves to trunk and we can bump the version (or sub-version.) */ { @@ -7815,7 +7866,6 @@ static void do_versions(FileData *fd, Library *lib, Main *main) } } - /* WATCH IT!!!: pointers from libdata have not been converted yet here! */ /* WATCH IT 2!: Userdef struct init has to be in src/usiblender.c! */ diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index 5337ad98b36..1038ac053af 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -2270,7 +2270,7 @@ static int handle_append_runtime(int handle, char *exename, char **cause_r) { unsigned char buf[1024]; int count, progfd= -1; - if (!runtime) { + if (!BLI_exists(runtime)) { cause= "Unable to find runtime"; goto cleanup; } diff --git a/source/blender/imbuf/intern/anim.c b/source/blender/imbuf/intern/anim.c index 720f5b0f7c8..c0e84b73e47 100644 --- a/source/blender/imbuf/intern/anim.c +++ b/source/blender/imbuf/intern/anim.c @@ -612,6 +612,7 @@ static int startffmpeg(struct anim * anim) { av_free(anim->pFrameRGB); av_free(anim->pFrameDeinterlaced); av_free(anim->pFrame); + anim->pCodecCtx = NULL; return -1; } @@ -639,7 +640,19 @@ static int startffmpeg(struct anim * anim) { PIX_FMT_BGR32, SWS_FAST_BILINEAR | SWS_PRINT_INFO, NULL, NULL, NULL); - + + if (!anim->img_convert_ctx) { + fprintf (stderr, + "Can't transform color space??? Bailing out...\n"); + avcodec_close(anim->pCodecCtx); + av_close_input_file(anim->pFormatCtx); + av_free(anim->pFrameRGB); + av_free(anim->pFrameDeinterlaced); + av_free(anim->pFrame); + anim->pCodecCtx = NULL; + return -1; + } + return (0); } diff --git a/source/blender/include/BDR_gpencil.h b/source/blender/include/BDR_gpencil.h index d2fc7be29ea..eb749cf28ec 100644 --- a/source/blender/include/BDR_gpencil.h +++ b/source/blender/include/BDR_gpencil.h @@ -38,6 +38,15 @@ struct bGPdata; struct bGPDlayer; struct bGPDframe; +/* ------------- Grease-Pencil Helpers -------------- */ + +/* 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; + /* ------------ Grease-Pencil API ------------------ */ void free_gpencil_strokes(struct bGPDframe *gpf); diff --git a/source/blender/include/BIF_editarmature.h b/source/blender/include/BIF_editarmature.h index da98eb3d4f1..07fc8f08b4a 100644 --- a/source/blender/include/BIF_editarmature.h +++ b/source/blender/include/BIF_editarmature.h @@ -108,11 +108,13 @@ void mouse_armature(void); void remake_editArmature(void); void selectconnected_armature(void); void selectconnected_posearmature(void); -void select_bone_parent(void); +void armature_select_hierarchy(short direction, short add_to_sel); + void setflag_armature(short mode); void unique_editbone_name (struct ListBase *ebones, char *name); void auto_align_armature(short mode); +void switch_direction_armature(void); void create_vgroups_from_armature(struct Object *ob, struct Object *par); void add_verts_to_dgroups(struct Object *ob, struct Object *par, int heat, int mirror); @@ -134,7 +136,6 @@ void transform_armature_mirror_update(void); void hide_selected_armature_bones(void); void hide_unselected_armature_bones(void); void show_all_armature_bones(void); -void set_locks_armature_bones(short lock); #define BONESEL_ROOT 0x10000000 #define BONESEL_TIP 0x20000000 @@ -143,6 +144,14 @@ void set_locks_armature_bones(short lock); #define BONESEL_NOSEL 0x80000000 /* Indicates a negative number */ +/* useful macros */ +#define EBONE_VISIBLE(arm, ebone) ((arm->layer & ebone->layer) && !(ebone->flag & BONE_HIDDEN_A)) +#define EBONE_EDITABLE(ebone) ((ebone->flag & BONE_SELECTED) && !(ebone->flag & BONE_EDITMODE_LOCKED)) + +/* used in bone_select_hierachy() */ +#define BONE_SELECT_PARENT 0 +#define BONE_SELECT_CHILD 1 + #endif diff --git a/source/blender/include/BIF_editmesh.h b/source/blender/include/BIF_editmesh.h index ca9f3d6a378..9354a577ac1 100644 --- a/source/blender/include/BIF_editmesh.h +++ b/source/blender/include/BIF_editmesh.h @@ -132,7 +132,7 @@ extern int EM_check_backbuf(unsigned int index); extern void EM_free_backbuf(void); extern void EM_selectmode_menu(void); - +extern void EM_mesh_copy_face(short type); extern void vertexnoise(void); extern void vertexsmooth(void); diff --git a/source/blender/include/BIF_editview.h b/source/blender/include/BIF_editview.h index 4ed3d0df367..d2c6c56d01a 100644 --- a/source/blender/include/BIF_editview.h +++ b/source/blender/include/BIF_editview.h @@ -34,9 +34,12 @@ struct Base; struct Object; struct Camera; struct View3D; +struct rcti; 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); void borderselect(void); void circle_select(void); void deselectall(void); diff --git a/source/blender/include/BIF_poseobject.h b/source/blender/include/BIF_poseobject.h index 58c67ff102a..ab96f7ec03e 100644 --- a/source/blender/include/BIF_poseobject.h +++ b/source/blender/include/BIF_poseobject.h @@ -65,6 +65,8 @@ void pose_assign_to_posegroup(short active); void pose_remove_from_posegroups(void); void pgroup_operation_with_menu(void); +void pose_select_hierarchy(short direction, short add_to_sel); + void pose_select_grouped(short nr); void pose_select_grouped_menu(void); diff --git a/source/blender/include/butspace.h b/source/blender/include/butspace.h index c0542e3f34c..8e80f630cf2 100644 --- a/source/blender/include/butspace.h +++ b/source/blender/include/butspace.h @@ -593,7 +593,7 @@ void curvemap_buttons(struct uiBlock *block, struct CurveMapping *cumap, char la #define B_VPCOLSLI 2801 #define B_VPGAMMA 2802 - +#define B_COPY_TF_TRANSP 2803 #define B_COPY_TF_MODE 2804 #define B_COPY_TF_UV 2805 #define B_COPY_TF_COL 2806 diff --git a/source/blender/makesdna/DNA_customdata_types.h b/source/blender/makesdna/DNA_customdata_types.h index 95639db6ec4..433aeaafb37 100644 --- a/source/blender/makesdna/DNA_customdata_types.h +++ b/source/blender/makesdna/DNA_customdata_types.h @@ -71,8 +71,9 @@ typedef struct CustomData { #define CD_MTEXPOLY 15 #define CD_MLOOPUV 16 #define CD_MLOOPCOL 17 -#define CD_MDISPS 18 -#define CD_NUMTYPES 19 +#define CD_TANGENT 18 +#define CD_MDISPS 19 +#define CD_NUMTYPES 20 /* Bits for CustomDataMask */ #define CD_MASK_MVERT (1 << CD_MVERT) @@ -93,6 +94,7 @@ typedef struct CustomData { #define CD_MASK_MTEXPOLY (1 << CD_MTEXPOLY) #define CD_MASK_MLOOPUV (1 << CD_MLOOPUV) #define CD_MASK_MLOOPCOL (1 << CD_MLOOPCOL) +#define CD_MASK_TANGENT (1 << CD_TANGENT) #define CD_MASK_MDISPS (1 << CD_MDISPS) /* CustomData.flag */ diff --git a/source/blender/makesdna/DNA_gpencil_types.h b/source/blender/makesdna/DNA_gpencil_types.h index b88dd698c3f..dca4e28688d 100644 --- a/source/blender/makesdna/DNA_gpencil_types.h +++ b/source/blender/makesdna/DNA_gpencil_types.h @@ -125,7 +125,7 @@ typedef struct bGPdata { */ short sbuffer_size; /* number of elements currently in cache */ short sbuffer_sflag; /* flags for stroke that cache represents */ - bGPDspoint *sbuffer; /* stroke buffer (can hold GP_STROKE_BUFFER_MAX) */ + void *sbuffer; /* stroke buffer (can hold GP_STROKE_BUFFER_MAX) */ } bGPdata; /* bGPdata->flag */ diff --git a/source/blender/makesdna/DNA_meshdata_types.h b/source/blender/makesdna/DNA_meshdata_types.h index 1b8a7037724..7a9b32c1eb5 100644 --- a/source/blender/makesdna/DNA_meshdata_types.h +++ b/source/blender/makesdna/DNA_meshdata_types.h @@ -231,7 +231,7 @@ typedef struct PartialVisibility { /* mtface->mode */ #define TF_DYNAMIC 1 -#define TF_DEPRECATED 2 +#define TF_ALPHASORT 2 #define TF_TEX 4 #define TF_SHAREDVERT 8 #define TF_LIGHT 16 diff --git a/source/blender/python/BPY_interface.c b/source/blender/python/BPY_interface.c index 7120e97a62f..69bff059356 100644 --- a/source/blender/python/BPY_interface.c +++ b/source/blender/python/BPY_interface.c @@ -160,11 +160,10 @@ ScriptError g_script_error; * Function prototypes ***************************************************************************/ PyObject *RunPython( Text * text, PyObject * globaldict ); -char *GetName( Text * text ); PyObject *CreateGlobalDictionary( void ); void ReleaseGlobalDictionary( PyObject * dict ); void DoAllScriptsFromList( ListBase * list, short event ); -PyObject *importText( char *name ); +static PyObject *importText( char *name ); void init_ourImport( void ); void init_ourReload( void ); PyObject *blender_import( PyObject * self, PyObject * args ); @@ -651,7 +650,7 @@ int BPY_txt_do_python_Text( struct Text *text ) } /* Create a new script structure and initialize it: */ - script = alloc_libblock( &G.main->script, ID_SCRIPT, GetName( text ) ); + script = alloc_libblock( &G.main->script, ID_SCRIPT, text->id.name+2 ); if( !script ) { printf( "couldn't allocate memory for Script struct!" ); @@ -662,8 +661,7 @@ int BPY_txt_do_python_Text( struct Text *text ) * an error after it will call BPY_Err_Handle below, but the text struct * will have been deallocated already, so we need to copy its name here. */ - BLI_strncpy( textname, GetName( text ), - strlen( GetName( text ) ) + 1 ); + BLI_strncpy( textname, text->id.name+2, 21 ); script->id.us = 1; script->flags = SCRIPT_RUNNING; @@ -1106,12 +1104,10 @@ int BPY_menu_do_python( short menutype, int event ) *****************************************************************************/ void BPY_free_compiled_text( struct Text *text ) { - if( !text->compiled ) - return; - Py_DECREF( ( PyObject * ) text->compiled ); - text->compiled = NULL; - - return; + if( text->compiled ) { + Py_DECREF( ( PyObject * ) text->compiled ); + text->compiled = NULL; + } } /***************************************************************************** @@ -2724,8 +2720,7 @@ PyObject *RunPython( Text * text, PyObject * globaldict ) buf = txt_to_buf( text ); text->compiled = - Py_CompileString( buf, GetName( text ), - Py_file_input ); + Py_CompileString( buf, text->id.name+2, Py_file_input ); MEM_freeN( buf ); @@ -2740,15 +2735,6 @@ PyObject *RunPython( Text * text, PyObject * globaldict ) } /***************************************************************************** -* Description: This function returns the value of the name field of the -* given Text struct. -*****************************************************************************/ -char *GetName( Text * text ) -{ - return ( text->id.name + 2 ); -} - -/***************************************************************************** * Description: This function creates a new Python dictionary object. *****************************************************************************/ PyObject *CreateGlobalDictionary( void ) @@ -2792,49 +2778,38 @@ void DoAllScriptsFromList( ListBase * list, short event ) return; } -PyObject *importText( char *name ) +static PyObject *importText( char *name ) { Text *text; - char *txtname; + char txtname[22]; /* 21+NULL */ char *buf = NULL; int namelen = strlen( name ); - - txtname = malloc( namelen + 3 + 1 ); - if( !txtname ) - return NULL; - + + if (namelen>21-3) return NULL; /* we know this cant be importable, the name is too long for blender! */ + memcpy( txtname, name, namelen ); memcpy( &txtname[namelen], ".py", 4 ); - text = ( Text * ) & ( G.main->text.first ); - - while( text ) { - if( !strcmp( txtname, GetName( text ) ) ) + for(text = G.main->text.first; text; text = text->id.next) { + if( !strcmp( txtname, text->id.name+2 ) ) break; - text = text->id.next; } - if( !text ) { - free( txtname ); + if( !text ) return NULL; - } if( !text->compiled ) { buf = txt_to_buf( text ); - text->compiled = - Py_CompileString( buf, GetName( text ), - Py_file_input ); + text->compiled = Py_CompileString( buf, text->id.name+2, Py_file_input ); MEM_freeN( buf ); if( PyErr_Occurred( ) ) { PyErr_Print( ); BPY_free_compiled_text( text ); - free( txtname ); return NULL; } } - free( txtname ); return PyImport_ExecCodeModule( name, text->compiled ); } @@ -2905,7 +2880,7 @@ static PyObject *reimportText( PyObject *module ) /* look up the text object */ text = ( Text * ) & ( G.main->text.first ); while( text ) { - if( !strcmp( txtname, GetName( text ) ) ) + if( !strcmp( txtname, text->id.name+2 ) ) break; text = text->id.next; } @@ -2922,8 +2897,7 @@ static PyObject *reimportText( PyObject *module ) /* compile the buffer */ buf = txt_to_buf( text ); - text->compiled = Py_CompileString( buf, GetName( text ), - Py_file_input ); + text->compiled = Py_CompileString( buf, text->id.name+2, Py_file_input ); MEM_freeN( buf ); /* if compile failed.... return this error */ diff --git a/source/blender/python/api2_2x/Blender.c b/source/blender/python/api2_2x/Blender.c index 420d292cdce..2b190a6c828 100644 --- a/source/blender/python/api2_2x/Blender.c +++ b/source/blender/python/api2_2x/Blender.c @@ -1074,7 +1074,7 @@ void M_Blender_Init(void) PyDict_SetItemString(dict, "Material", Material_Init()); PyDict_SetItemString(dict, "Mesh", Mesh_Init()); PyDict_SetItemString(dict, "Metaball", Metaball_Init()); - PyDict_SetItemString(dict, "Mathutils", Mathutils_Init()); + PyDict_SetItemString(dict, "Mathutils", Mathutils_Init("Blender.Mathutils")); PyDict_SetItemString(dict, "Geometry", Geometry_Init()); PyDict_SetItemString(dict, "Modifier", Modifier_Init()); PyDict_SetItemString(dict, "NMesh", NMesh_Init()); diff --git a/source/blender/python/api2_2x/Constraint.c b/source/blender/python/api2_2x/Constraint.c index 8db6a49465e..a62a5ee7ed8 100644 --- a/source/blender/python/api2_2x/Constraint.c +++ b/source/blender/python/api2_2x/Constraint.c @@ -29,6 +29,7 @@ #include "Constraint.h" /*This must come first*/ +#include "DNA_armature_types.h" #include "DNA_object_types.h" #include "DNA_effect_types.h" #include "DNA_vec_types.h" @@ -43,6 +44,7 @@ #include "BKE_constraint.h" #include "BLI_blenlib.h" #include "BIF_editconstraint.h" +#include "BIF_poseobject.h" #include "BSE_editipo.h" #include "MEM_guardedalloc.h" #include "butspace.h" @@ -2286,19 +2288,32 @@ static PyObject *ConstraintSeq_moveDown( BPy_ConstraintSeq *self, BPy_Constraint static PyObject *ConstraintSeq_remove( BPy_ConstraintSeq *self, BPy_Constraint *value ) { - bConstraint *con = locate_constr( self, value ); + bConstraint *con = locate_constr(self, value); + bPoseChannel *active= NULL; /* if we can't locate the constraint, return (exception already set) */ - if( !con ) + if (!con) return (PyObject *)NULL; - /* do the actual removal */ - if( self->pchan ) - BLI_remlink( &self->pchan->constraints, con ); - else - BLI_remlink( &self->obj->constraints, con); + /* check if we need to set temporary 'active' flag for pchan */ + if (self->pchan) { + active= get_active_posechannel(self->obj); + + if (active != self->pchan) { + if (active) active->bone->flag &= ~BONE_ACTIVE; + self->pchan->bone->flag |= BONE_ACTIVE; + } + } + + /* del_constr_func() frees constraint + its data */ del_constr_func( self->obj, con ); + /* reset active pchan (if applicable) */ + if (self->pchan && self->pchan!=active) { + if (active) active->bone->flag |= BONE_ACTIVE; + self->pchan->bone->flag &= ~BONE_ACTIVE; + } + /* erase the link to the constraint */ value->con = NULL; diff --git a/source/blender/python/api2_2x/Material.c b/source/blender/python/api2_2x/Material.c index c36213950b0..ccd24a437b5 100644 --- a/source/blender/python/api2_2x/Material.c +++ b/source/blender/python/api2_2x/Material.c @@ -131,11 +131,11 @@ #define EXPP_MAT_RAYMIRRGLOSS_MIN 0.0 #define EXPP_MAT_RAYMIRRGLOSS_MAX 1.0 #define EXPP_MAT_RAYMIRRGLOSSSAMPLES_MIN 0 -#define EXPP_MAT_RAYMIRRGLOSSSAMPLES_MAX 255 +#define EXPP_MAT_RAYMIRRGLOSSSAMPLES_MAX 1024 #define EXPP_MAT_RAYTRANSPGLOSS_MIN 0.0 #define EXPP_MAT_RAYTRANSPGLOSS_MAX 1.0 #define EXPP_MAT_RAYTRANSPGLOSSSAMPLES_MIN 0 -#define EXPP_MAT_RAYTRANSPGLOSSSAMPLES_MAX 255 +#define EXPP_MAT_RAYTRANSPGLOSSSAMPLES_MAX 1024 #define EXPP_MAT_FILTER_MIN 0.0 #define EXPP_MAT_FILTER_MAX 1.0 #define EXPP_MAT_TRANSLUCENCY_MIN 0.0 @@ -738,8 +738,10 @@ static PyMethodDef BPy_Material_methods[] = { "() - Return fresnel power for refractions factor"}, {"getRayTransGloss", ( PyCFunction ) Material_getGlossTrans, METH_NOARGS, "() - Return amount refraction glossiness"}, + {"getRayTransGlossSamples", ( PyCFunction ) Material_getGlossTransSamples, METH_NOARGS, + "() - Return number of sampels for transparent glossiness"}, {"getRayMirrGlossSamples", ( PyCFunction ) Material_getGlossMirrSamples, METH_NOARGS, - "() - Return amount mirror glossiness"}, + "() - Return number of sampels for mirror glossiness"}, {"getFilter", ( PyCFunction ) Material_getFilter, METH_NOARGS, "() - Return the amount of filtering when transparent raytrace is enabled"}, {"getTranslucency", ( PyCFunction ) Material_getTranslucency, METH_NOARGS, @@ -847,8 +849,10 @@ static PyMethodDef BPy_Material_methods[] = { "(f) - Set blend fac for mirror fresnel - [1.0, 5.0]"}, {"setRayTransGloss", ( PyCFunction ) Material_setGlossTrans, METH_VARARGS, "(f) - Set amount refraction glossiness - [0.0, 1.0]"}, + {"setRayTransGlossSamples", ( PyCFunction ) Material_setGlossTransSamples, METH_VARARGS, + "(i) - Set number transparent gloss samples - [1, 1024]"}, {"setRayMirrGlossSamples", ( PyCFunction ) Material_setGlossMirrSamples, METH_VARARGS, - "(f) - Set amount mirror glossiness - [0.0, 1.0]"}, + "(i) - Set number mirror gloss samples - [1, 1024]"}, {"setFilter", ( PyCFunction ) Matr_oldsetFilter, METH_VARARGS, "(f) - Set the amount of filtering when transparent raytrace is enabled"}, {"setTranslucency", ( PyCFunction ) Matr_oldsetTranslucency, METH_VARARGS, diff --git a/source/blender/python/api2_2x/Mathutils.c b/source/blender/python/api2_2x/Mathutils.c index 85c56a61628..217e096060f 100644 --- a/source/blender/python/api2_2x/Mathutils.c +++ b/source/blender/python/api2_2x/Mathutils.c @@ -106,8 +106,9 @@ struct PyMethodDef M_Mathutils_methods[] = { {"Point", (PyCFunction) M_Mathutils_Point, METH_VARARGS, M_Mathutils_Point_doc}, {NULL, NULL, 0, NULL} }; -//----------------------------MODULE INIT------------------------- -PyObject *Mathutils_Init(void) +/*----------------------------MODULE INIT-------------------------*/ +/* from can be Blender.Mathutils or GameLogic.Mathutils for the BGE */ +PyObject *Mathutils_Init(char *from) { PyObject *submodule; @@ -125,8 +126,7 @@ PyObject *Mathutils_Init(void) if( PyType_Ready( &quaternion_Type ) < 0 ) return NULL; - submodule = Py_InitModule3("Blender.Mathutils", - M_Mathutils_methods, M_Mathutils_doc); + submodule = Py_InitModule3(from, M_Mathutils_methods, M_Mathutils_doc); return (submodule); } //-----------------------------METHODS---------------------------- diff --git a/source/blender/python/api2_2x/Mathutils.h b/source/blender/python/api2_2x/Mathutils.h index dd9aae2abed..76d53cb6c4c 100644 --- a/source/blender/python/api2_2x/Mathutils.h +++ b/source/blender/python/api2_2x/Mathutils.h @@ -38,7 +38,7 @@ #include "euler.h" #include "point.h" -PyObject *Mathutils_Init( void ); +PyObject *Mathutils_Init( char * from ); PyObject *row_vector_multiplication(VectorObject* vec, MatrixObject * mat); PyObject *column_vector_multiplication(MatrixObject * mat, VectorObject* vec); PyObject *row_point_multiplication(PointObject* pt, MatrixObject * mat); diff --git a/source/blender/python/api2_2x/Texture.c b/source/blender/python/api2_2x/Texture.c index 696c78f2bac..7ba8ad88ea6 100644 --- a/source/blender/python/api2_2x/Texture.c +++ b/source/blender/python/api2_2x/Texture.c @@ -105,6 +105,10 @@ #define EXPP_TEX_LACUNARITY_MAX 6.0f #define EXPP_TEX_OCTS_MIN 0.0f #define EXPP_TEX_OCTS_MAX 8.0f +#define EXPP_TEX_OFST_MIN 0.0f +#define EXPP_TEX_OFST_MAX 6.0f +#define EXPP_TEX_GAIN_MIN 0.0f +#define EXPP_TEX_GAIN_MAX 6.0f #define EXPP_TEX_ISCALE_MIN 0.0f #define EXPP_TEX_ISCALE_MAX 10.0f #define EXPP_TEX_EXP_MIN 0.010f @@ -430,6 +434,8 @@ GETFUNC( getNoiseDepth ); GETFUNC( getNoiseSize ); GETFUNC( getNoiseType ); GETFUNC( getOcts ); +GETFUNC( getOffset ); +GETFUNC( getGain ); GETFUNC( getRepeat ); GETFUNC( getRGBCol ); GETFUNC( getSType ); @@ -478,6 +484,8 @@ SETFUNC( setNoiseDepth ); SETFUNC( setNoiseSize ); SETFUNC( setNoiseType ); SETFUNC( setOcts ); +SETFUNC( setOffset ); +SETFUNC( setGain ); SETFUNC( setRepeat ); SETFUNC( setRGBCol ); SETFUNC( setSType ); @@ -646,6 +654,14 @@ static PyGetSetDef BPy_Texture_getseters[] = { (getter)Texture_getLacunarity, (setter)Texture_setLacunarity, "Gap between succesive frequencies (for Musgrave textures)", NULL}, + {"offset", + (getter)Texture_getOffset, (setter)Texture_setOffset, + "Fractal offset (for Musgrave textures)", + NULL}, + {"gain", + (getter)Texture_getGain, (setter)Texture_setGain, + "Gain multiplier (for Musgrave textures)", + NULL}, {"noiseBasis", (getter)Texture_getNoiseBasis, (setter)Texture_setNoiseBasis, "Noise basis type (wood, stucci, marble, clouds, Musgrave, distorted noise)", @@ -1837,6 +1853,20 @@ static int Texture_setLacunarity( BPy_Texture * self, PyObject * value ) EXPP_TEX_LACUNARITY_MAX ); } +static int Texture_setOffset( BPy_Texture * self, PyObject * value ) +{ + return EXPP_setFloatClamped ( value, &self->texture->mg_offset, + EXPP_TEX_OFST_MIN, + EXPP_TEX_OFST_MAX ); +} + +static int Texture_setGain( BPy_Texture * self, PyObject * value ) +{ + return EXPP_setFloatClamped ( value, &self->texture->mg_gain, + EXPP_TEX_GAIN_MIN, + EXPP_TEX_GAIN_MAX ); +} + static int Texture_setOcts( BPy_Texture * self, PyObject * value ) { return EXPP_setFloatClamped ( value, &self->texture->mg_octaves, @@ -2168,6 +2198,16 @@ static PyObject *Texture_getOcts( BPy_Texture *self ) return PyFloat_FromDouble( self->texture->mg_octaves ); } +static PyObject *Texture_getOffset( BPy_Texture *self ) +{ + return PyFloat_FromDouble( self->texture->mg_offset ); +} + +static PyObject *Texture_getGain( BPy_Texture *self ) +{ + return PyFloat_FromDouble( self->texture->mg_gain ); +} + static PyObject *Texture_getRepeat( BPy_Texture *self ) { return Py_BuildValue( "(i,i)", self->texture->xrepeat, diff --git a/source/blender/python/api2_2x/doc/Render.py b/source/blender/python/api2_2x/doc/Render.py index d4dc83e84a0..5300fdab808 100644 --- a/source/blender/python/api2_2x/doc/Render.py +++ b/source/blender/python/api2_2x/doc/Render.py @@ -170,17 +170,6 @@ def SetRenderWinPos(locationList): the location of the Render window on the screen. """ -def EnableEdgeShift(): - """ - Globally with the unified renderer enabled the outlines of the render - are shifted a bit. - """ - -def EnableEdgeAll(): - """ - Globally consider transparent faces for edge-rendering with the unified renderer. - """ - class RenderData: """ The RenderData object @@ -772,7 +761,7 @@ class RenderData: """ Get/set the starting frame for sequence rendering. @type frame: int (optional) - @param frame: must be between 1 - 18000 + @param frame: must be a valid Blender frame number. @rtype: int (if prototype is empty) @return: Current starting frame for the scene. """ @@ -781,7 +770,7 @@ class RenderData: """ Get/set the ending frame for sequence rendering. @type frame: int (optional) - @param frame: must be between 1 - 18000 + @param frame: must be a valid Blender frame number. @rtype: int (if prototype is empty) @return: Current ending frame for the scene. """ diff --git a/source/blender/python/api2_2x/doc/Texture.py b/source/blender/python/api2_2x/doc/Texture.py index 7f42d06240b..cebb7de7011 100644 --- a/source/blender/python/api2_2x/doc/Texture.py +++ b/source/blender/python/api2_2x/doc/Texture.py @@ -344,6 +344,12 @@ class Texture: @ivar octs: Number of frequencies (for Musgrave textures). Value is clamped to the range [0.0,8.0]. @type octs: float + @ivar offset: Fractal offset (for hetero terrain and multifractal Musgrave textures). + Value is clamped to the range [0.0,6.0]. + @type offset: float + @ivar gain: Gain multiplier (for multifractal Musgrave textures). + Value is clamped to the range [0.0,6.0]. + @type gain: float @ivar repeat: Repetition multiplier (for image textures). @type repeat: tuple of 2 ints @ivar rgbCol: RGB color tuple. diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c index 765a24409fa..ad4a6291266 100644 --- a/source/blender/render/intern/source/convertblender.c +++ b/source/blender/render/intern/source/convertblender.c @@ -1864,9 +1864,17 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem num= cpa->num; /* get orco */ - psys_particle_on_emitter(ob, psmd, - (part->childtype == PART_CHILD_FACES)? PART_FROM_FACE: PART_FROM_PARTICLE, - cpa->num,DMCACHE_ISCHILD,cpa->fuv,cpa->foffset,co,nor,0,0,orco,0); + if(part->childtype == PART_CHILD_FACES) { + psys_particle_on_emitter(ob, psmd, + PART_FROM_FACE, cpa->num,DMCACHE_ISCHILD, + cpa->fuv,cpa->foffset,co,nor,0,0,orco,0); + } + else { + ParticleData *par = psys->particles + cpa->parent; + psys_particle_on_emitter(ob, psmd, part->from, + par->num,DMCACHE_ISCHILD,par->fuv, + par->foffset,co,nor,0,0,orco,0); + } if(uvco){ if(part->from!=PART_FROM_PARTICLE && part->childtype==PART_CHILD_FACES){ diff --git a/source/blender/render/intern/source/rayshade.c b/source/blender/render/intern/source/rayshade.c index 1155d2ea817..c352a83d0f4 100644 --- a/source/blender/render/intern/source/rayshade.c +++ b/source/blender/render/intern/source/rayshade.c @@ -263,7 +263,12 @@ static void shade_ray(Isect *is, ShadeInput *shi, ShadeResult *shr) shade_input_set_shade_texco(shi); if(is->mode==RE_RAY_SHADOW_TRA) - shade_color(shi, shr); + if(shi->mat->nodetree && shi->mat->use_nodes) { + ntreeShaderExecTree(shi->mat->nodetree, shi, shr); + shi->mat= vlr->mat; /* shi->mat is being set in nodetree */ + } + else + shade_color(shi, shr); else { if(shi->mat->nodetree && shi->mat->use_nodes) { ntreeShaderExecTree(shi->mat->nodetree, shi, shr); diff --git a/source/blender/src/buttons_editing.c b/source/blender/src/buttons_editing.c index 5639e0116de..8fad9fc0a87 100644 --- a/source/blender/src/buttons_editing.c +++ b/source/blender/src/buttons_editing.c @@ -5704,13 +5704,9 @@ void sculptmode_draw_interface_textures(uiBlock *block, unsigned short cx, unsig void do_fpaintbuts(unsigned short event) { - Mesh *me; Object *ob; bDeformGroup *defGroup; - MTFace *activetf, *tf; - MFace *mf; - MCol *activemcol; - int a; + MTFace *activetf; SculptData *sd= &G.scene->sculptdata; ID *id, *idtest; extern VPaint Gwp; /* from vpaint */ @@ -5728,45 +5724,19 @@ void do_fpaintbuts(unsigned short event) vpaint_dogamma(); break; case B_COPY_TF_MODE: + EM_mesh_copy_face(4); /* todo, get rid of magic numbers */ + break; + case B_COPY_TF_TRANSP: + EM_mesh_copy_face(5); + break; case B_COPY_TF_UV: + EM_mesh_copy_face(3); + break; case B_COPY_TF_COL: + EM_mesh_copy_face(6); + break; case B_COPY_TF_TEX: - me= get_mesh(OBACT); - activetf= get_active_mtface(NULL, &activemcol, 0); - - if(me && activetf) { - for (a=0, tf=me->mtface, mf=me->mface; a < me->totface; a++, tf++, mf++) { - if(tf!=activetf && (mf->flag & ME_FACE_SEL)) { - if(event==B_COPY_TF_MODE) { - tf->mode= activetf->mode; - tf->transp= activetf->transp; - } - else if(event==B_COPY_TF_UV) { - memcpy(tf->uv, activetf->uv, sizeof(tf->uv)); - tf->tpage= activetf->tpage; - tf->tile= activetf->tile; - - if(activetf->mode & TF_TILES) tf->mode |= TF_TILES; - else tf->mode &= ~TF_TILES; - - } - else if(event==B_COPY_TF_TEX) { - tf->tpage= activetf->tpage; - tf->tile= activetf->tile; - - if(activetf->mode & TF_TILES) tf->mode |= TF_TILES; - else tf->mode &= ~TF_TILES; - } - else if(event==B_COPY_TF_COL && activemcol) - memcpy(&me->mcol[a*4], activemcol, sizeof(MCol)*4); - } - } - - DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA); - do_shared_vertexcol(me); - allqueue(REDRAWVIEW3D, 0); - allqueue(REDRAWIMAGE, 0); - } + EM_mesh_copy_face(2); break; case B_SET_VCOL: if(FACESEL_PAINT_TEST) @@ -6201,8 +6171,20 @@ static void editing_panel_mesh_texface(void) if(uiNewPanel(curarea, block, "Texture Face", "Editing", 960, 0, 318, 204)==0) return; tf = get_active_mtface(NULL, NULL, 0); + if(tf) { + uiDefBut(block, LABEL, B_NOP, "Active Face Mode", 600,185,300,19, NULL, 0.0, 0.0, 0, 0, "Face mode its used for TexFace display and the game engine "); + uiDefBut(block, BUT,B_COPY_TF_MODE, "Copy", 850,185,50,19, 0, 0, 0, 0, 0, "Copy active faces mode to other selected (View3D Ctrl+C)"); + + /* Other copy buttons, layout isnt that nice */ uiBlockBeginAlign(block); + uiDefBut(block, BUT,B_COPY_TF_UV, "CopyUV", 600,15,100,19, 0, 0, 0, 0, 0, "Copy active faces UVs to other selected (View3D Ctrl+C)"); + uiDefBut(block, BUT,B_COPY_TF_TEX, "CopyTex", 700,15,100,19, 0, 0, 0, 0, 0, "Copy active faces Texture to other selected (View3D Ctrl+C)"); + uiDefBut(block, BUT,B_COPY_TF_COL, "CopyColor", 800,15,100,19, 0, 0, 0, 0, 0, "Copy active faces Color to other selected (View3D Ctrl+C)"); + uiBlockEndAlign(block); + + uiBlockBeginAlign(block); + uiDefButBitS(block, TOG, TF_TEX, B_REDR_3D_IMA, "Tex", 600,160,60,19, &tf->mode, 0, 0, 0, 0, "Render face with texture"); uiDefButBitS(block, TOG, TF_TILES, B_REDR_3D_IMA, "Tiles", 660,160,60,19, &tf->mode, 0, 0, 0, 0, "Use tilemode for face"); uiDefButBitS(block, TOG, TF_LIGHT, REDRAWVIEW3D, "Light", 720,160,60,19, &tf->mode, 0, 0, 0, 0, "Use light for face"); @@ -6213,23 +6195,30 @@ static void editing_panel_mesh_texface(void) uiDefButBitS(block, TOG, TF_SHAREDCOL, REDRAWVIEW3D, "Shared", 600,135,60,19, &tf->mode, 0, 0, 0, 0, "Blend vertex colors across face when vertices are shared"); uiDefButBitS(block, TOG, TF_TWOSIDE, REDRAWVIEW3D, "Twoside",660,135,60,19, &tf->mode, 0, 0, 0, 0, "Render face twosided"); uiDefButBitS(block, TOG, TF_OBCOL, REDRAWVIEW3D, "ObColor",720,135,60,19, &tf->mode, 0, 0, 0, 0, "Use ObColor instead of vertex colors"); - - uiBlockBeginAlign(block); + uiBlockEndAlign(block); + uiBlockBeginAlign(block); uiDefButBitS(block, TOG, TF_BILLBOARD, B_TFACE_HALO, "Halo", 600,110,60,19, &tf->mode, 0, 0, 0, 0, "Screen aligned billboard"); uiDefButBitS(block, TOG, TF_BILLBOARD2, B_TFACE_BILLB, "Billboard",660,110,60,19, &tf->mode, 0, 0, 0, 0, "Billboard with Z-axis constraint"); uiDefButBitS(block, TOG, TF_SHADOW, REDRAWVIEW3D, "Shadow", 720,110,60,19, &tf->mode, 0, 0, 0, 0, "Face is used for shadow"); uiDefButBitS(block, TOG, TF_BMFONT, REDRAWVIEW3D, "Text", 780,110,60,19, &tf->mode, 0, 0, 0, 0, "Enable bitmap text on face"); - + uiDefButBitS(block, TOG, TF_ALPHASORT, REDRAWVIEW3D, "Sort", 840,110,60,19, &tf->mode, 0, 0, 0, 0, "Enable sorting of faces for correct alpha drawing (slow, use Clip Alpha instead when possible)"); + uiBlockEndAlign(block); + + uiDefBut(block, LABEL, B_NOP, "Active Face Alpha Blending (Transp)", 600,75,300,19, NULL, 0.0, 0.0, 0, 0, "Face mode its used for TexFace display and the game engine"); + uiDefBut(block, BUT,B_COPY_TF_TRANSP, "Copy", 850,75,50,19, 0, 0, 0, 0, 0, "Copy active faces transp to other selected (View3D Ctrl+C)"); + uiBlockBeginAlign(block); uiBlockSetCol(block, TH_BUT_SETTING1); - uiDefButC(block, ROW, REDRAWVIEW3D, "Opaque", 600,80,60,19, &tf->transp, 2.0, (float)TF_SOLID,0, 0, "Render color of textured face as color"); - uiDefButC(block, ROW, REDRAWVIEW3D, "Add", 660,80,60,19, &tf->transp, 2.0, (float)TF_ADD, 0, 0, "Render face transparent and add color of face"); - uiDefButC(block, ROW, REDRAWVIEW3D, "Alpha", 720,80,60,19, &tf->transp, 2.0, (float)TF_ALPHA,0, 0, "Render polygon transparent, depending on alpha channel of the texture"); - uiDefButC(block, ROW, REDRAWVIEW3D, "Clip Alpha", 780,80,80,19, &tf->transp, 2.0, (float)TF_CLIP,0, 0, "Use the images alpha values clipped with no blending (binary alpha)"); - } - else + uiDefButC(block, ROW, REDRAWVIEW3D, "Opaque", 600,50,60,19, &tf->transp, 2.0, (float)TF_SOLID,0, 0, "Render color of textured face as color"); + uiDefButC(block, ROW, REDRAWVIEW3D, "Add", 660,50,60,19, &tf->transp, 2.0, (float)TF_ADD, 0, 0, "Render face transparent and add color of face"); + uiDefButC(block, ROW, REDRAWVIEW3D, "Alpha", 720,50,60,19, &tf->transp, 2.0, (float)TF_ALPHA,0, 0, "Render polygon transparent, depending on alpha channel of the texture"); + uiDefButC(block, ROW, REDRAWVIEW3D, "Clip Alpha", 780,50,80,19, &tf->transp, 2.0, (float)TF_CLIP,0, 0, "Use the images alpha values clipped with no blending (binary alpha)"); + uiBlockEndAlign(block); + + } else { uiDefBut(block,LABEL,B_NOP, "(No Active Face)", 10,200,150,19,0,0,0,0,0,""); + } } diff --git a/source/blender/src/buttons_logic.c b/source/blender/src/buttons_logic.c index 498edc0dfed..5cf1958678e 100644 --- a/source/blender/src/buttons_logic.c +++ b/source/blender/src/buttons_logic.c @@ -1654,53 +1654,66 @@ static short draw_actuatorbuttons(Object *ob, bActuator *act, uiBlock *block, sh wval = (width-100)/3; if (oa->type == ACT_OBJECT_NORMAL) { - ysize= 175; - + if ( ob->gameflag & OB_DYNAMIC ) + { + ysize= 175; + } + else + { + ysize= 72; + } + glRects(xco, yco-ysize, xco+width, yco); uiEmboss((float)xco, (float)yco-ysize, (float)xco+width, (float)yco, 1); - uiDefBut(block, LABEL, 0, "Force", xco, yco-45, 55, 19, NULL, 0, 0, 0, 0, "Sets the force"); - uiDefButF(block, NUM, 0, "", xco+45, yco-45, wval, 19, oa->forceloc, -10000.0, 10000.0, 10, 0, ""); - uiDefButF(block, NUM, 0, "", xco+45+wval, yco-45, wval, 19, oa->forceloc+1, -10000.0, 10000.0, 10, 0, ""); - uiDefButF(block, NUM, 0, "", xco+45+2*wval, yco-45, wval, 19, oa->forceloc+2, -10000.0, 10000.0, 10, 0, ""); - - uiDefBut(block, LABEL, 0, "Torque", xco, yco-64, 55, 19, NULL, 0, 0, 0, 0, "Sets the torque"); - uiDefButF(block, NUM, 0, "", xco+45, yco-64, wval, 19, oa->forcerot, -10000.0, 10000.0, 10, 0, ""); - uiDefButF(block, NUM, 0, "", xco+45+wval, yco-64, wval, 19, oa->forcerot+1, -10000.0, 10000.0, 10, 0, ""); - uiDefButF(block, NUM, 0, "", xco+45+2*wval, yco-64, wval, 19, oa->forcerot+2, -10000.0, 10000.0, 10, 0, ""); + uiDefBut(block, LABEL, 0, "Loc", xco, yco-45, 45, 19, NULL, 0, 0, 0, 0, "Sets the location"); + uiDefButF(block, NUM, 0, "", xco+45, yco-45, wval, 19, oa->dloc, -10000.0, 10000.0, 10, 0, ""); + uiDefButF(block, NUM, 0, "", xco+45+wval, yco-45, wval, 19, oa->dloc+1, -10000.0, 10000.0, 10, 0, ""); + uiDefButF(block, NUM, 0, "", xco+45+2*wval, yco-45, wval, 19, oa->dloc+2, -10000.0, 10000.0, 10, 0, ""); - uiDefBut(block, LABEL, 0, "dLoc", xco, yco-87, 45, 19, NULL, 0, 0, 0, 0, "Sets the dLoc"); - uiDefButF(block, NUM, 0, "", xco+45, yco-87, wval, 19, oa->dloc, -10000.0, 10000.0, 10, 0, ""); - uiDefButF(block, NUM, 0, "", xco+45+wval, yco-87, wval, 19, oa->dloc+1, -10000.0, 10000.0, 10, 0, ""); - uiDefButF(block, NUM, 0, "", xco+45+2*wval, yco-87, wval, 19, oa->dloc+2, -10000.0, 10000.0, 10, 0, ""); - - uiDefBut(block, LABEL, 0, "dRot", xco, yco-106, 45, 19, NULL, 0, 0, 0, 0, "Sets the dRot"); - uiDefButF(block, NUM, 0, "", xco+45, yco-106, wval, 19, oa->drot, -10000.0, 10000.0, 10, 0, ""); - uiDefButF(block, NUM, 0, "", xco+45+wval, yco-106, wval, 19, oa->drot+1, -10000.0, 10000.0, 10, 0, ""); - uiDefButF(block, NUM, 0, "", xco+45+2*wval, yco-106, wval, 19, oa->drot+2, -10000.0, 10000.0, 10, 0, ""); + uiDefBut(block, LABEL, 0, "Rot", xco, yco-64, 45, 19, NULL, 0, 0, 0, 0, "Sets the rotation"); + uiDefButF(block, NUM, 0, "", xco+45, yco-64, wval, 19, oa->drot, -10000.0, 10000.0, 10, 0, ""); + uiDefButF(block, NUM, 0, "", xco+45+wval, yco-64, wval, 19, oa->drot+1, -10000.0, 10000.0, 10, 0, ""); + uiDefButF(block, NUM, 0, "", xco+45+2*wval, yco-64, wval, 19, oa->drot+2, -10000.0, 10000.0, 10, 0, ""); + + uiDefButBitS(block, TOG, ACT_DLOC_LOCAL, 0, "L", xco+45+3*wval, yco-45, 15, 19, &oa->flag, 0.0, 0.0, 0, 0, "Local transformation"); + uiDefButBitS(block, TOG, ACT_DROT_LOCAL, 0, "L", xco+45+3*wval, yco-64, 15, 19, &oa->flag, 0.0, 0.0, 0, 0, "Local transformation"); + + if ( ob->gameflag & OB_DYNAMIC ) + { + uiDefBut(block, LABEL, 0, "Force", xco, yco-87, 55, 19, NULL, 0, 0, 0, 0, "Sets the force"); + uiDefButF(block, NUM, 0, "", xco+45, yco-87, wval, 19, oa->forceloc, -10000.0, 10000.0, 10, 0, ""); + uiDefButF(block, NUM, 0, "", xco+45+wval, yco-87, wval, 19, oa->forceloc+1, -10000.0, 10000.0, 10, 0, ""); + uiDefButF(block, NUM, 0, "", xco+45+2*wval, yco-87, wval, 19, oa->forceloc+2, -10000.0, 10000.0, 10, 0, ""); - uiDefBut(block, LABEL, 0, "linV", xco, yco-129, 45, 19, NULL, 0, 0, 0, 0, "Sets the linear velocity"); - uiDefButF(block, NUM, 0, "", xco+45, yco-129, wval, 19, oa->linearvelocity, -10000.0, 10000.0, 10, 0, ""); - uiDefButF(block, NUM, 0, "", xco+45+wval, yco-129, wval, 19, oa->linearvelocity+1, -10000.0, 10000.0, 10, 0, ""); - uiDefButF(block, NUM, 0, "", xco+45+2*wval, yco-129, wval, 19, oa->linearvelocity+2, -10000.0, 10000.0, 10, 0, ""); + uiDefBut(block, LABEL, 0, "Torque", xco, yco-106, 55, 19, NULL, 0, 0, 0, 0, "Sets the torque"); + uiDefButF(block, NUM, 0, "", xco+45, yco-106, wval, 19, oa->forcerot, -10000.0, 10000.0, 10, 0, ""); + uiDefButF(block, NUM, 0, "", xco+45+wval, yco-106, wval, 19, oa->forcerot+1, -10000.0, 10000.0, 10, 0, ""); + uiDefButF(block, NUM, 0, "", xco+45+2*wval, yco-6106, wval, 19, oa->forcerot+2, -10000.0, 10000.0, 10, 0, ""); + } - uiDefBut(block, LABEL, 0, "angV", xco, yco-148, 45, 19, NULL, 0, 0, 0, 0, "Sets the angular velocity"); - uiDefButF(block, NUM, 0, "", xco+45, yco-148, wval, 19, oa->angularvelocity, -10000.0, 10000.0, 10, 0, ""); - uiDefButF(block, NUM, 0, "", xco+45+wval, yco-148, wval, 19, oa->angularvelocity+1, -10000.0, 10000.0, 10, 0, ""); - uiDefButF(block, NUM, 0, "", xco+45+2*wval, yco-148, wval, 19, oa->angularvelocity+2, -10000.0, 10000.0, 10, 0, ""); + if ( ob->gameflag & OB_DYNAMIC ) + { + uiDefBut(block, LABEL, 0, "LinV", xco, yco-129, 45, 19, NULL, 0, 0, 0, 0, "Sets the linear velocity"); + uiDefButF(block, NUM, 0, "", xco+45, yco-129, wval, 19, oa->linearvelocity, -10000.0, 10000.0, 10, 0, ""); + uiDefButF(block, NUM, 0, "", xco+45+wval, yco-129, wval, 19, oa->linearvelocity+1, -10000.0, 10000.0, 10, 0, ""); + uiDefButF(block, NUM, 0, "", xco+45+2*wval, yco-129, wval, 19, oa->linearvelocity+2, -10000.0, 10000.0, 10, 0, ""); - uiDefBut(block, LABEL, 0, "damp", xco, yco-171, 45, 19, NULL, 0, 0, 0, 0, "Number of frames to reach the target velocity"); - uiDefButS(block, NUM, 0, "", xco+45, yco-171, wval, 19, &oa->damping, 0.0, 1000.0, 100, 0, ""); - - uiDefButBitS(block, TOG, ACT_FORCE_LOCAL, 0, "L", xco+45+3*wval, yco-45, 15, 19, &oa->flag, 0.0, 0.0, 0, 0, "Local transformation"); - uiDefButBitS(block, TOG, ACT_TORQUE_LOCAL, 0, "L", xco+45+3*wval, yco-64, 15, 19, &oa->flag, 0.0, 0.0, 0, 0, "Local transformation"); - uiDefButBitS(block, TOG, ACT_DLOC_LOCAL, 0, "L", xco+45+3*wval, yco-87, 15, 19, &oa->flag, 0.0, 0.0, 0, 0, "Local transformation"); - uiDefButBitS(block, TOG, ACT_DROT_LOCAL, 0, "L", xco+45+3*wval, yco-106, 15, 19, &oa->flag, 0.0, 0.0, 0, 0, "Local transformation"); - uiDefButBitS(block, TOG, ACT_LIN_VEL_LOCAL, 0, "L", xco+45+3*wval, yco-129, 15, 19, &oa->flag, 0.0, 0.0, 0, 0, "Local transformation"); - uiDefButBitS(block, TOG, ACT_ANG_VEL_LOCAL, 0, "L", xco+45+3*wval, yco-148, 15, 19, &oa->flag, 0.0, 0.0, 0, 0, "Local transformation"); + uiDefBut(block, LABEL, 0, "AngV", xco, yco-148, 45, 19, NULL, 0, 0, 0, 0, "Sets the angular velocity"); + uiDefButF(block, NUM, 0, "", xco+45, yco-148, wval, 19, oa->angularvelocity, -10000.0, 10000.0, 10, 0, ""); + uiDefButF(block, NUM, 0, "", xco+45+wval, yco-148, wval, 19, oa->angularvelocity+1, -10000.0, 10000.0, 10, 0, ""); + uiDefButF(block, NUM, 0, "", xco+45+2*wval, yco-148, wval, 19, oa->angularvelocity+2, -10000.0, 10000.0, 10, 0, ""); - uiDefButBitS(block, TOG, ACT_ADD_LIN_VEL, 0, "add",xco+45+3*wval+15, yco-129, 35, 19, &oa->flag, 0.0, 0.0, 0, 0, "Toggles between ADD and SET linV"); + uiDefBut(block, LABEL, 0, "Damp", xco, yco-171, 45, 19, NULL, 0, 0, 0, 0, "Number of frames to reach the target velocity"); + uiDefButS(block, NUM, 0, "", xco+45, yco-171, wval, 19, &oa->damping, 0.0, 1000.0, 100, 0, ""); + + uiDefButBitS(block, TOG, ACT_FORCE_LOCAL, 0, "L", xco+45+3*wval, yco-87, 15, 19, &oa->flag, 0.0, 0.0, 0, 0, "Local transformation"); + uiDefButBitS(block, TOG, ACT_TORQUE_LOCAL, 0, "L", xco+45+3*wval, yco-106, 15, 19, &oa->flag, 0.0, 0.0, 0, 0, "Local transformation"); + uiDefButBitS(block, TOG, ACT_LIN_VEL_LOCAL, 0, "L", xco+45+3*wval, yco-129, 15, 19, &oa->flag, 0.0, 0.0, 0, 0, "Local transformation"); + uiDefButBitS(block, TOG, ACT_ANG_VEL_LOCAL, 0, "L", xco+45+3*wval, yco-148, 15, 19, &oa->flag, 0.0, 0.0, 0, 0, "Local transformation"); + uiDefButBitS(block, TOG, ACT_ADD_LIN_VEL, 0, "add",xco+45+3*wval+15, yco-129, 35, 19, &oa->flag, 0.0, 0.0, 0, 0, "Toggles between ADD and SET linV"); + } } else if (oa->type == ACT_OBJECT_SERVO) { ysize= 172; diff --git a/source/blender/src/buttons_object.c b/source/blender/src/buttons_object.c index 2c7802c3302..58f3bff09c8 100644 --- a/source/blender/src/buttons_object.c +++ b/source/blender/src/buttons_object.c @@ -173,6 +173,7 @@ static void constraint_active_func(void *ob_v, void *con_v) } lb= get_active_constraints(ob); + if (lb == NULL) return; for(con= lb->first; con; con= con->next) { if(con==con_v) con->flag |= CONSTRAINT_ACTIVE; @@ -307,7 +308,7 @@ void del_constr_func (void *ob_v, void *con_v) } /* remove constraint itself */ lb= get_active_constraints(ob_v); - free_constraint_data (con); + free_constraint_data(con); BLI_freelinkN(lb, con); constraint_active_func(ob_v, NULL); diff --git a/source/blender/src/buttons_scene.c b/source/blender/src/buttons_scene.c index 3b0167d673c..fb6a7636e16 100644 --- a/source/blender/src/buttons_scene.c +++ b/source/blender/src/buttons_scene.c @@ -763,7 +763,16 @@ static void seq_panel_input() } if (last_seq->type == SEQ_IMAGE) { - StripElem * se = give_stripelem(last_seq, CFRA); + int cfra = CFRA; + StripElem * se; + + if(last_seq->startdisp >cfra) { + cfra = last_seq->startdisp; + } else if (last_seq->enddisp <= cfra) { + cfra = last_seq->enddisp - 1; + } + + se = give_stripelem(last_seq, cfra); if (se) { uiDefBut(block, TEX, diff --git a/source/blender/src/drawgpencil.c b/source/blender/src/drawgpencil.c index e07dec90629..ee28049e2c0 100644 --- a/source/blender/src/drawgpencil.c +++ b/source/blender/src/drawgpencil.c @@ -280,11 +280,15 @@ short draw_gpencil_panel (uiBlock *block, bGPdata *gpd, ScrArea *sa) /* show override lmb-clicks button + painting lock */ uiBlockBeginAlign(block); - uiDefButBitI(block, TOG, GP_DATA_EDITPAINT, B_REDR, "Draw Mode", 170, 225, 130, 20, &gpd->flag, 0, 0, 0, 0, "Interpret LMB-click as new strokes (same as holding Shift-Key per stroke)"); - - uiBlockSetCol(block, TH_BUT_SETTING); - uiDefIconButBitI(block, ICONTOG, GP_DATA_LMBPLOCK, B_REDR, ICON_UNLOCKED, 300, 225, 20, 20, &gpd->flag, 0.0, 0.0, 0, 0, "Painting cannot occur with Shift-LMB (when making selections)"); - uiBlockSetCol(block, TH_AUTO); + if ((gpd->flag & GP_DATA_EDITPAINT)==0) { + uiDefButBitI(block, TOG, GP_DATA_EDITPAINT, B_REDR, "Draw Mode", 170, 225, 130, 20, &gpd->flag, 0, 0, 0, 0, "Interpret click-drag as new strokes"); + + uiBlockSetCol(block, TH_BUT_SETTING); + uiDefIconButBitI(block, ICONTOG, GP_DATA_LMBPLOCK, B_REDR, ICON_UNLOCKED, 300, 225, 20, 20, &gpd->flag, 0.0, 0.0, 0, 0, "Painting cannot occur with Shift-LMB (when making selections)"); + uiBlockSetCol(block, TH_AUTO); + } + else + uiDefButBitI(block, TOG, GP_DATA_EDITPAINT, B_REDR, "Draw Mode", 170, 225, 150, 20, &gpd->flag, 0, 0, 0, 0, "Interpret click-drag as new strokes"); uiBlockEndAlign(block); /* 'view align' button (naming depends on context) */ @@ -306,6 +310,8 @@ short draw_gpencil_panel (uiBlock *block, bGPdata *gpd, ScrArea *sa) /* ************************************************** */ /* GREASE PENCIL DRAWING */ +/* ----- General Defines ------ */ + /* flags for sflag */ enum { GP_DRAWDATA_NOSTATUS = (1<<0), /* don't draw status info */ @@ -313,115 +319,294 @@ enum { GP_DRAWDATA_ONLYV2D = (1<<2), /* only draw 'canvas' strokes */ }; -/* draw a given stroke */ -static void gp_draw_stroke (bGPDspoint *points, int totpoints, short thickness, short dflag, short sflag, short debug, int winx, int winy) +/* ----- Tool Buffer Drawing ------ */ + +/* draw stroke defined in buffer (simple ogl lines/points for now, as dotted lines) */ +static void gp_draw_stroke_buffer (tGPspoint *points, int totpoints, short thickness, short dflag, short sflag) { - bGPDspoint *pt; + tGPspoint *pt; int i; /* error checking */ if ((points == NULL) || (totpoints <= 0)) return; - /* check if stroke can be drawn */ - if ((dflag & GP_DRAWDATA_ONLY3D) && !(sflag & GP_STROKE_3DSPACE)) - return; - if (!(dflag & GP_DRAWDATA_ONLY3D) && (sflag & GP_STROKE_3DSPACE)) - return; - if ((dflag & GP_DRAWDATA_ONLYV2D) && !(sflag & GP_STROKE_2DSPACE)) - return; - if (!(dflag & GP_DRAWDATA_ONLYV2D) && (sflag & GP_STROKE_2DSPACE)) + /* check if buffer can be drawn */ + if (dflag & (GP_DRAWDATA_ONLY3D|GP_DRAWDATA_ONLYV2D)) return; - /* if drawing a single point, draw it larger */ + /* if drawing a single point, draw it larger */ if (totpoints == 1) { /* draw point */ - if (sflag & GP_STROKE_3DSPACE) { - glBegin(GL_POINTS); - 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); - - glBegin(GL_POINTS); - glVertex2f(x, y); - glEnd(); + glBegin(GL_POINTS); + glVertex2f(points->x, points->y); + 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); } else { float oldpressure = 0.0f; /* draw stroke curve */ + setlinestyle(2); + glBegin(GL_LINE_STRIP); for (i=0, pt=points; i < totpoints && pt; i++, pt++) { - float x, y, z; - - if (sflag & GP_STROKE_3DSPACE) { - x= pt->x; - y= pt->y; - z= pt->z; - } - else if (sflag & GP_STROKE_2DSPACE) { - x= pt->x; - y= pt->y; - z= 0; - } - else { - x= (pt->x / 1000 * winx); - y= (pt->y / 1000 * winy); - z= 0; - } - if (fabs(pt->pressure - oldpressure) > 0.2f) { glEnd(); glLineWidth(pt->pressure * thickness); glBegin(GL_LINE_STRIP); - if (sflag & GP_STROKE_3DSPACE) - glVertex3f(x, y, z); - else - glVertex2f(x, y); + glVertex2f(pt->x, pt->y); oldpressure = pt->pressure; } + else + glVertex2f(pt->x, pt->y); + } + glEnd(); + + 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) +{ + /* draw point */ + if (sflag & GP_STROKE_3DSPACE) { + glBegin(GL_POINTS); + 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); + + glBegin(GL_POINTS); + glVertex2f(x, y); + glEnd(); + } +} + +/* draw a given stroke in 3d (i.e. in 3d-space), using simple ogl lines */ +static void gp_draw_stroke_3d (bGPDspoint *points, int totpoints, short thickness, short dflag, short sflag, short debug, int winx, int winy) +{ + bGPDspoint *pt; + float oldpressure = 0.0f; + int i; + + /* draw stroke curve */ + glBegin(GL_LINE_STRIP); + for (i=0, pt=points; i < totpoints && pt; i++, pt++) { + if (fabs(pt->pressure - oldpressure) > 0.2f) { + glEnd(); + glLineWidth(pt->pressure * thickness); + glBegin(GL_LINE_STRIP); + + glVertex3f(pt->x, pt->y, pt->z); + + oldpressure = pt->pressure; + } + else + glVertex3f(pt->x, pt->y, pt->z); + } + glEnd(); + + /* draw debug points of curve on top? */ + if (debug) { + glBegin(GL_POINTS); + for (i=0, pt=points; i < totpoints && pt; i++, pt++) + glVertex3f(pt->x, pt->y, pt->z); + glEnd(); + } +} + +/* ----- Fancy 2D-Stroke Drawing ------ */ + +/* 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)) { + bGPDspoint *pt; + int i; + + glBegin(GL_LINE_STRIP); + for (i=0, pt=points; i < totpoints && pt; i++, pt++) { + if (sflag & GP_STROKE_2DSPACE) { + glVertex2f(pt->x, pt->y); + } else { - if (sflag & GP_STROKE_3DSPACE) - glVertex3f(x, y, z); - else - glVertex2f(x, y); + const float x= (pt->x / 1000 * winx); + const float y= (pt->y / 1000 * winy); + + glVertex2f(x, y); } } glEnd(); + } + else { /* tesselation code: currently only enabled with rt != 0 */ + bGPDspoint *pt1, *pt2; + float p0[2], p1[2], pm[2]; + int i; - /* draw debug points of curve on top? */ - if (debug) { - glBegin(GL_POINTS); - for (i=0, pt=points; i < totpoints && pt; i++, pt++) { - if (sflag & GP_STROKE_3DSPACE) { - glVertex3f(pt->x, pt->y, pt->z); - } - else if (sflag & GP_STROKE_2DSPACE) { - glVertex2f(pt->x, pt->y); - } - else { - const float x= (pt->x / 1000 * winx); - const float y= (pt->y / 1000 * winy); + glShadeModel(GL_FLAT); + glBegin(GL_QUAD_STRIP); + + 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 */ + + /* get x and y coordinates from points */ + if (sflag & GP_STROKE_2DSPACE) { + s0[0]= pt1->x; s0[1]= pt1->y; + s1[0]= pt2->x; s1[1]= pt2->y; + } + else { + s0[0]= (pt1->x / 1000 * winx); + s0[1]= (pt1->y / 1000 * winy); + s1[0]= (pt2->x / 1000 * winx); + s1[1]= (pt2->y / 1000 * winy); + } + + /* 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; + + /* if the first segment, initialise the first segment using segment's normal */ + if (i == 0) { + pthick= (pt1->pressure * thickness); + + // TODO: also draw/do a round end-cap first + + 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]); + + Vec2Copyf(pm, m1); + } + + /* 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]; + + /* 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) + */ + + /* find the closer vertex, and distance between startpoints */ + if (Vec2Lenf(p0, s1) > Vec2Lenf(p1, s1)) + Vec2Copyf(closep, p1); + else + Vec2Copyf(closep, p0); - glVertex2f(x, y); + /* 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]); } + + /* reset gl-states! */ + glEnd(); + glBegin(GL_QUAD_STRIP); } - glEnd(); + + /* 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 (i == totpoints-2) { + + } + + /* store current points for next segment to use */ + Vec2Copyf(p0, t0); + Vec2Copyf(p1, t1); + Vec2Copyf(pm, m1); } + + glEnd(); + } + + /* draw debug points of curve on top? (original stroke points) */ + if (debug) { + bGPDspoint *pt; + int i; + + glBegin(GL_POINTS); + for (i=0, pt=points; i < totpoints && pt; i++, pt++) { + if (sflag & GP_STROKE_2DSPACE) { + glVertex2f(pt->x, pt->y); + } + else { + const float x= (pt->x / 1000 * winx); + const float y= (pt->y / 1000 * winy); + + glVertex2f(x, y); + } + } + glEnd(); } } +/* ----- General Drawing ------ */ + /* draw a set of strokes */ static void gp_draw_strokes (bGPDframe *gpf, int winx, int winy, int dflag, short debug, short lthick, float color[4]) @@ -431,9 +616,26 @@ static void gp_draw_strokes (bGPDframe *gpf, int winx, int winy, int dflag, shor /* set color first (may need to reset it again later too) */ glColor4f(color[0], color[1], color[2], color[3]); - for (gps= gpf->strokes.first; gps; gps= gps->next) { - /* just draw the stroke once */ - gp_draw_stroke(gps->points, gps->totpoints, lthick, dflag, gps->flag, debug, winx, winy); + for (gps= gpf->strokes.first; gps; gps= gps->next) { + /* check if stroke can be drawn */ + if ((dflag & GP_DRAWDATA_ONLY3D) && !(gps->flag & GP_STROKE_3DSPACE)) + continue; + if (!(dflag & GP_DRAWDATA_ONLY3D) && (gps->flag & GP_STROKE_3DSPACE)) + continue; + if ((dflag & GP_DRAWDATA_ONLYV2D) && !(gps->flag & GP_STROKE_2DSPACE)) + continue; + if (!(dflag & GP_DRAWDATA_ONLYV2D) && (gps->flag & GP_STROKE_2DSPACE)) + 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); + 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) + gp_draw_stroke(gps->points, gps->totpoints, lthick, dflag, gps->flag, debug, winx, winy); } } @@ -489,8 +691,8 @@ static void gp_draw_data (bGPdata *gpd, int winx, int winy, int dflag) /* check if frame is drawable */ if ((gpf->framenum - gf->framenum) <= gpl->gstep) { /* alpha decreases with distance from curframe index */ - tcolor[3] = color[3] - (i * 0.7); - gp_draw_strokes(gpf, winx, winy, dflag, debug, lthick, tcolor); + tcolor[3] = color[3] - (i/gpl->gstep); + gp_draw_strokes(gf, winx, winy, dflag, debug, lthick, tcolor); } else break; @@ -501,8 +703,8 @@ static void gp_draw_data (bGPdata *gpd, int winx, int winy, int dflag) /* check if frame is drawable */ if ((gf->framenum - gpf->framenum) <= gpl->gstep) { /* alpha decreases with distance from curframe index */ - tcolor[3] = color[3] - (i * 0.7); - gp_draw_strokes(gpf, winx, winy, dflag, debug, lthick, tcolor); + tcolor[3] = color[3] - (i/gpl->gstep); + gp_draw_strokes(gf, winx, winy, dflag, debug, lthick, tcolor); } else break; @@ -515,12 +717,12 @@ static void gp_draw_data (bGPdata *gpd, int winx, int winy, int dflag) /* draw the strokes for the ghost frames (at half of the alpha set by user) */ if (gpf->prev) { tcolor[3] = (color[3] / 7); - gp_draw_strokes(gpf, winx, winy, dflag, debug, lthick, tcolor); + gp_draw_strokes(gpf->prev, winx, winy, dflag, debug, lthick, tcolor); } if (gpf->next) { tcolor[3] = (color[3] / 4); - gp_draw_strokes(gpf, winx, winy, dflag, debug, lthick, tcolor); + gp_draw_strokes(gpf->next, winx, winy, dflag, debug, lthick, tcolor); } /* restore alpha */ @@ -533,15 +735,13 @@ static void gp_draw_data (bGPdata *gpd, int winx, int winy, int dflag) gp_draw_strokes(gpf, winx, winy, dflag, debug, lthick, tcolor); /* Check if may need to draw the active stroke cache, only if this layer is the active layer - * that is being edited. (Stroke cache is currently stored in gp-data) + * that is being edited. (Stroke buffer is currently stored in gp-data) */ if ((G.f & G_GREASEPENCIL) && (gpl->flag & GP_LAYER_ACTIVE) && (gpf->flag & GP_FRAME_PAINT)) { /* Buffer stroke needs to be drawn with a different linestyle to help differentiate them from normal strokes. */ - setlinestyle(2); - gp_draw_stroke(gpd->sbuffer, gpd->sbuffer_size, lthick, dflag, gpd->sbuffer_sflag, debug, winx, winy); - setlinestyle(0); + gp_draw_stroke_buffer(gpd->sbuffer, gpd->sbuffer_size, lthick, dflag, gpd->sbuffer_sflag); } } @@ -594,7 +794,7 @@ static void gp_draw_data (bGPdata *gpd, int winx, int winy, int dflag) glColor4f(0, 0, 0, 1); } -/* ----------- */ +/* ----- Grease Pencil Sketches Drawing API ------ */ /* 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/drawseq.c b/source/blender/src/drawseq.c index cc431c73a2e..71a777c9056 100644 --- a/source/blender/src/drawseq.c +++ b/source/blender/src/drawseq.c @@ -98,7 +98,7 @@ int no_rightbox=0, no_leftbox= 0; static void draw_seq_handle(Sequence *seq, SpaceSeq *sseq, float pixelx, short direction); static void draw_seq_extensions(Sequence *seq, SpaceSeq *sseq); -static void draw_seq_text(Sequence *seq, float x1, float x2, float y1, float y2); +static void draw_seq_text(Sequence *seq, float x1, float x2, float y1, float y2, char *background_col); static void draw_shadedstrip(Sequence *seq, char *col, float x1, float y1, float x2, float y2); static void draw_seq_strip(struct Sequence *seq, struct ScrArea *sa, struct SpaceSeq *sseq, int outline_tint, float pixelx); @@ -604,7 +604,7 @@ static void draw_seq_extensions(Sequence *seq, SpaceSeq *sseq) } /* draw info text on a sequence strip */ -static void draw_seq_text(Sequence *seq, float x1, float x2, float y1, float y2) +static void draw_seq_text(Sequence *seq, float x1, float x2, float y1, float y2, char *background_col) { float v1[2], v2[2]; int len, size; @@ -670,8 +670,13 @@ static void draw_seq_text(Sequence *seq, float x1, float x2, float y1, float y2) mval[1]= 1; areamouseco_to_ipoco(G.v2d, mval, &x1, &x2); - if(seq->flag & SELECT) cpack(0xFFFFFF); - else cpack(0); + if(seq->flag & SELECT){ + cpack(0xFFFFFF); + }else if ((((int)background_col[0] + (int)background_col[1] + (int)background_col[2]) / 3) < 50){ + cpack(0x505050); /* use lighter text colour for dark background */ + }else{ + cpack(0); + } glRasterPos3f(x1, y1+SEQ_STRIP_OFSBOTTOM, 0.0); BMF_DrawString(G.font, strp); } @@ -740,7 +745,7 @@ so wave file sample drawing precission is zoom adjusted static void draw_seq_strip(Sequence *seq, ScrArea *sa, SpaceSeq *sseq, int outline_tint, float pixelx) { float x1, x2, y1, y2; - char col[3], is_single_image; + char col[3], background_col[3], is_single_image; /* we need to know if this is a single image/color or not for drawing */ is_single_image = (char)check_single_seq(seq); @@ -755,13 +760,14 @@ static void draw_seq_strip(Sequence *seq, ScrArea *sa, SpaceSeq *sseq, int outli /* get the correct color per strip type*/ - get_seq_color3ubv(seq, col); + //get_seq_color3ubv(seq, col); + get_seq_color3ubv(seq, background_col); /* draw the main strip body */ if (is_single_image) /* single image */ - draw_shadedstrip(seq, col, seq_tx_get_final_left(seq, 0), y1, seq_tx_get_final_right(seq, 0), y2); + draw_shadedstrip(seq, background_col, seq_tx_get_final_left(seq, 0), y1, seq_tx_get_final_right(seq, 0), y2); else /* normal operation */ - draw_shadedstrip(seq, col, x1, y1, x2, y2); + draw_shadedstrip(seq, background_col, x1, y1, x2, y2); /* draw additional info and controls */ if (seq->type == SEQ_RAM_SOUND) @@ -814,7 +820,7 @@ static void draw_seq_strip(Sequence *seq, ScrArea *sa, SpaceSeq *sseq, int outli /* nice text here would require changing the view matrix for texture text */ if( (x2-x1) / pixelx > 32) { - draw_seq_text(seq, x1, x2, y1, y2); + draw_seq_text(seq, x1, x2, y1, y2, background_col); } } diff --git a/source/blender/src/editarmature.c b/source/blender/src/editarmature.c index d0f44263fb7..35986fcff4a 100644 --- a/source/blender/src/editarmature.c +++ b/source/blender/src/editarmature.c @@ -854,6 +854,7 @@ static void separate_armature_bones (Object *ob, short sel) BLI_freelistN(&edbo); } +/* separate selected bones into their armature */ void separate_armature (void) { Object *oldob, *newob; @@ -1033,87 +1034,6 @@ static void *get_nearest_bone (short findunsel) return NULL; } -/* used by posemode and editmode */ -void select_bone_parent (void) -{ - Object *ob; - bArmature *arm; - - /* get data */ - if (G.obedit) - ob= G.obedit; - else if (OBACT) - ob= OBACT; - else - return; - arm= (bArmature *)ob->data; - - /* determine which mode armature is in */ - if ((!G.obedit) && (ob->flag & OB_POSEMODE)) { - /* deal with pose channels */ - /* channels are sorted on dependency, so the loop below won't result in a flood-select */ - bPoseChannel *pchan=NULL; - - for (pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) { - /* check if bone in original selection */ - if (pchan->bone->flag & BONE_SELECTED) { - bPoseChannel *chanpar= pchan->parent; - - /* check if any parent */ - if ((chanpar) && ((chanpar->bone->flag & BONE_SELECTED)==0)) { - chanpar->bone->flag |= BONE_SELECTED; - select_actionchannel_by_name (ob->action, pchan->name, 1); - } - } - } - } - else if (G.obedit) { - /* deal with editbones */ - EditBone *curbone, *parbone, *parpar; - - /* prevent floods */ - for (curbone= G.edbo.first; curbone; curbone= curbone->next) - curbone->temp= NULL; - - for (curbone= G.edbo.first; curbone; curbone= curbone->next) { - /* check if bone selected */ - if ((curbone->flag & BONE_SELECTED) && curbone->temp==NULL) { - parbone= curbone->parent; - - /* check if any parent */ - if ((parbone) && ((parbone->flag & BONE_SELECTED)==0)) { - /* select the parent bone */ - parbone->flag |= (BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL); - - /* check if parent has parent */ - parpar= parbone->parent; - - if ((parpar) && (parbone->flag & BONE_CONNECTED)) { - parpar->flag |= BONE_TIPSEL; - } - /* tag this bone to not flood selection */ - parbone->temp= parbone; - } - } - } - - /* to be sure... */ - for (curbone= G.edbo.first; curbone; curbone= curbone->next) - curbone->temp= NULL; - - } - - /* undo + redraw pushes */ - countall(); // flushes selection! - - allqueue (REDRAWVIEW3D, 0); - allqueue (REDRAWBUTSEDIT, 0); - allqueue(REDRAWBUTSOBJECT, 0); - allqueue(REDRAWOOPS, 0); - - BIF_undo_push("Select Parent"); -} - /* helper for setflag_sel_bone() */ static void bone_setflag (int *bone, int flag, short mode) { @@ -1139,6 +1059,90 @@ static void bone_setflag (int *bone, int flag, short mode) } } +/* Get the first available child of an editbone */ +static EditBone *editbone_get_child(EditBone *pabone, short use_visibility) +{ + Object *ob; + bArmature *arm; + EditBone *curbone, *chbone=NULL; + + if (!G.obedit) return NULL; + else ob= G.obedit; + arm= (bArmature *)ob->data; + + for (curbone= G.edbo.first; curbone; curbone= curbone->next) { + if (curbone->parent == pabone) { + if (use_visibility) { + if ((arm->layer & curbone->layer) && !(pabone->flag & BONE_HIDDEN_A)) + chbone = curbone; + } + else + chbone = curbone; + } + } + + return chbone; +} + +void armature_select_hierarchy(short direction, short add_to_sel) +{ + Object *ob; + bArmature *arm; + EditBone *curbone, *pabone, *chbone; + + if (!G.obedit) return; + else ob= G.obedit; + arm= (bArmature *)ob->data; + + for (curbone= G.edbo.first; curbone; curbone= curbone->next) { + if (EBONE_VISIBLE(arm, curbone)) { + if (curbone->flag & (BONE_ACTIVE)) { + if (direction == BONE_SELECT_PARENT) { + if (curbone->parent == NULL) continue; + else pabone = curbone->parent; + + if (EBONE_VISIBLE(arm, pabone)) { + pabone->flag |= (BONE_ACTIVE|BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL); + if (pabone->parent) pabone->parent->flag |= BONE_TIPSEL; + + if (!add_to_sel) curbone->flag &= ~(BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL); + curbone->flag &= ~BONE_ACTIVE; + break; + } + + } + else { // BONE_SELECT_CHILD + chbone = editbone_get_child(curbone, 1); + if (chbone == NULL) continue; + + if (EBONE_VISIBLE(arm, chbone)) { + chbone->flag |= (BONE_ACTIVE|BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL); + + if (!add_to_sel) { + curbone->flag &= ~(BONE_SELECTED|BONE_ROOTSEL); + if (curbone->parent) curbone->parent->flag &= ~BONE_TIPSEL; + } + curbone->flag &= ~BONE_ACTIVE; + break; + } + } + } + } + } + + countall(); // flushes selection! + + allqueue (REDRAWVIEW3D, 0); + allqueue (REDRAWBUTSEDIT, 0); + allqueue (REDRAWBUTSOBJECT, 0); + allqueue (REDRAWOOPS, 0); + + if (direction==BONE_SELECT_PARENT) + BIF_undo_push("Select edit bone parent"); + if (direction==BONE_SELECT_CHILD) + BIF_undo_push("Select edit bone child"); +} + /* used by posemode and editmode */ void setflag_armature (short mode) { @@ -1157,17 +1161,18 @@ void setflag_armature (short mode) /* get flag to set (sync these with the ones used in eBone_Flag */ if (mode == 2) - flag= pupmenu("Disable Setting%t|Draw Wire%x1|Deform%x2|Mult VG%x3|Hinge%x4|No Scale%x5"); + flag= pupmenu("Disable Setting%t|Draw Wire%x1|Deform%x2|Mult VG%x3|Hinge%x4|No Scale%x5|Locked%x6"); else if (mode == 1) - flag= pupmenu("Enable Setting%t|Draw Wire%x1|Deform%x2|Mult VG%x3|Hinge%x4|No Scale%x5"); + flag= pupmenu("Enable Setting%t|Draw Wire%x1|Deform%x2|Mult VG%x3|Hinge%x4|No Scale%x5|Locked%x6"); else - flag= pupmenu("Toggle Setting%t|Draw Wire%x1|Deform%x2|Mult VG%x3|Hinge%x4|No Scale%x5"); + flag= pupmenu("Toggle Setting%t|Draw Wire%x1|Deform%x2|Mult VG%x3|Hinge%x4|No Scale%x5|Locked%x6"); switch (flag) { case 1: flag = BONE_DRAWWIRE; break; case 2: flag = BONE_NO_DEFORM; break; case 3: flag = BONE_MULT_VG_ENV; break; case 4: flag = BONE_HINGE; break; case 5: flag = BONE_NO_SCALE; break; + case 6: flag = BONE_EDITMODE_LOCKED; break; default: return; } @@ -1723,12 +1728,12 @@ void auto_align_armature(short mode) float *cursor= give_cursor(); for (ebone = G.edbo.first; ebone; ebone=ebone->next) { - if (arm->layer & ebone->layer) { + if (EBONE_VISIBLE(arm, ebone)) { if (arm->flag & ARM_MIRROR_EDIT) flipbone = armature_bone_get_mirrored(ebone); if ((ebone->flag & BONE_SELECTED) || - (flipbone && flipbone->flag & BONE_SELECTED)) + (flipbone && (flipbone->flag & BONE_SELECTED))) { /* specific method used to calculate roll depends on mode */ if (mode == 1) { @@ -1973,7 +1978,7 @@ void addvert_armature(void) /* find the active or selected bone */ for (ebone = G.edbo.first; ebone; ebone=ebone->next) { - if (arm->layer & ebone->layer) { + if (EBONE_VISIBLE(arm, ebone)) { if (ebone->flag & (BONE_ACTIVE|BONE_TIPSEL)) break; } @@ -1981,7 +1986,7 @@ void addvert_armature(void) if (ebone==NULL) { for (ebone = G.edbo.first; ebone; ebone=ebone->next) { - if (arm->layer & ebone->layer) { + if (EBONE_VISIBLE(arm, ebone)) { if (ebone->flag & (BONE_ACTIVE|BONE_ROOTSEL)) break; } @@ -2064,11 +2069,12 @@ static EditBone *get_named_editbone(char *name) { EditBone *eBone; - if (name) + if (name) { for (eBone=G.edbo.first; eBone; eBone=eBone->next) { if (!strcmp(name, eBone->name)) return eBone; } + } return NULL; } @@ -2134,7 +2140,7 @@ void adduplicate_armature(void) /* Select mirrored bones */ if (arm->flag & ARM_MIRROR_EDIT) { for (curBone=G.edbo.first; curBone; curBone=curBone->next) { - if (arm->layer & curBone->layer) { + if (EBONE_VISIBLE(arm, curBone)) { if (curBone->flag & BONE_SELECTED) { eBone = armature_bone_get_mirrored(curBone); if (eBone) @@ -2146,13 +2152,13 @@ void adduplicate_armature(void) /* Find the selected bones and duplicate them as needed */ for (curBone=G.edbo.first; curBone && curBone!=firstDup; curBone=curBone->next) { - if (arm->layer & curBone->layer) { + if (EBONE_VISIBLE(arm, curBone)) { if (curBone->flag & BONE_SELECTED) { eBone=MEM_callocN(sizeof(EditBone), "addup_editbone"); eBone->flag |= BONE_SELECTED; /* Copy data from old bone to new bone */ - memcpy (eBone, curBone, sizeof(EditBone)); + memcpy(eBone, curBone, sizeof(EditBone)); curBone->temp = eBone; eBone->temp = curBone; @@ -2202,7 +2208,7 @@ void adduplicate_armature(void) /* Run though the list and fix the pointers */ for (curBone=G.edbo.first; curBone && curBone!=firstDup; curBone=curBone->next) { - if (arm->layer & curBone->layer) { + if (EBONE_VISIBLE(arm, curBone)) { if (curBone->flag & BONE_SELECTED) { eBone=(EditBone*) curBone->temp; @@ -2234,7 +2240,7 @@ void adduplicate_armature(void) /* Deselect the old bones and select the new ones */ for (curBone=G.edbo.first; curBone && curBone!=firstDup; curBone=curBone->next) { - if (arm->layer & curBone->layer) + if (EBONE_VISIBLE(arm, curBone)) curBone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL | BONE_ACTIVE); } @@ -2371,7 +2377,7 @@ void fill_bones_armature(void) /* loop over all bones, and only consider if visible */ for (ebo= G.edbo.first; ebo; ebo= ebo->next) { - if ((arm->layer & ebo->layer) && !(ebo->flag & BONE_HIDDEN_A)) { + if (EBONE_VISIBLE(arm, ebo)) { if (!(ebo->flag & BONE_CONNECTED) && (ebo->flag & BONE_ROOTSEL)) fill_add_joint(ebo, 0, &points); if (ebo->flag & BONE_TIPSEL) @@ -2606,7 +2612,7 @@ void merge_armature(void) /* only consider bones that are visible and selected */ for (ebo=chain->data; ebo; child=ebo, ebo=ebo->parent) { /* check if visible + selected */ - if ( (arm->layer & ebo->layer) && !(ebo->flag & BONE_HIDDEN_A) && + if ( EBONE_VISIBLE(arm, ebo) && ((ebo->flag & BONE_CONNECTED) || (ebo->parent==NULL)) && (ebo->flag & (BONE_SELECTED|BONE_ACTIVE)) ) { @@ -2657,7 +2663,7 @@ void hide_selected_armature_bones(void) EditBone *ebone; for (ebone = G.edbo.first; ebone; ebone=ebone->next) { - if (arm->layer & ebone->layer) { + if (EBONE_VISIBLE(arm, ebone)) { if (ebone->flag & (BONE_SELECTED)) { ebone->flag &= ~(BONE_TIPSEL|BONE_SELECTED|BONE_ROOTSEL|BONE_ACTIVE); ebone->flag |= BONE_HIDDEN_A; @@ -2676,7 +2682,7 @@ void hide_unselected_armature_bones(void) for (ebone = G.edbo.first; ebone; ebone=ebone->next) { bArmature *arm= G.obedit->data; - if (arm->layer & ebone->layer) { + if (EBONE_VISIBLE(arm, ebone)) { if (ebone->flag & (BONE_TIPSEL|BONE_SELECTED|BONE_ROOTSEL)); else { ebone->flag &= ~BONE_ACTIVE; @@ -2709,32 +2715,6 @@ void show_all_armature_bones(void) BIF_undo_push("Reveal Bones"); } -/* Sets editmode transform locks for bones (adds if lock==1, clears otherwise) */ -void set_locks_armature_bones(short lock) -{ - bArmature *arm= G.obedit->data; - EditBone *ebone; - - for (ebone = G.edbo.first; ebone; ebone=ebone->next) { - if (arm->layer & ebone->layer) { - if (ebone->flag & (BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL)) { - if (lock) - ebone->flag |= BONE_EDITMODE_LOCKED; - else - ebone->flag &= ~BONE_EDITMODE_LOCKED; - } - } - } - countall(); - allqueue(REDRAWVIEW3D, 0); - allqueue(REDRAWBUTSEDIT, 0); - - if (lock) - BIF_undo_push("Lock Bones"); - else - BIF_undo_push("Unlock Bones"); -} - /* check for null, before calling! */ static void bone_connect_to_existing_parent(EditBone *bone) { @@ -2801,7 +2781,7 @@ void make_bone_parent(void) /* find active bone to parent to */ for (actbone = G.edbo.first; actbone; actbone=actbone->next) { - if (arm->layer & actbone->layer) { + if (EBONE_VISIBLE(arm, actbone)) { if (actbone->flag & BONE_ACTIVE) break; } @@ -2813,7 +2793,7 @@ void make_bone_parent(void) /* find selected bones */ for (ebone = G.edbo.first; ebone; ebone=ebone->next) { - if (arm->layer & ebone->layer) { + if (EBONE_VISIBLE(arm, ebone)) { if ((ebone->flag & BONE_SELECTED) && (ebone != actbone)) { foundselbone++; if (ebone->parent != actbone) allchildbones= 1; @@ -2849,7 +2829,7 @@ void make_bone_parent(void) else { /* loop through all editbones, parenting all selected bones to the active bone */ for (selbone = G.edbo.first; selbone; selbone=selbone->next) { - if (arm->layer & selbone->layer) { + if (EBONE_VISIBLE(arm, selbone)) { if ((selbone->flag & BONE_SELECTED) && (selbone!=actbone)) { /* parent selbone to actbone */ bone_connect_to_new_parent(selbone, actbone, val); @@ -2907,7 +2887,7 @@ void clear_bone_parent(void) if (val<1) return; for (ebone = G.edbo.first; ebone; ebone=ebone->next) { - if (arm->layer & ebone->layer) { + if (EBONE_VISIBLE(arm, ebone)) { if (ebone->flag & BONE_SELECTED) { if (arm->flag & ARM_MIRROR_EDIT) flipbone = armature_bone_get_mirrored(ebone); @@ -2957,7 +2937,7 @@ void unique_editbone_name (ListBase *ebones, char *name) } for (number = 1; number <=999; number++) { - sprintf (tempname, "%s.%03d", name, number); + sprintf(tempname, "%s.%03d", name, number); if (!editbone_name_exists(ebones, tempname)) { BLI_strncpy(name, tempname, 32); return; @@ -2978,7 +2958,7 @@ void extrude_armature(int forked) /* since we allow root extrude too, we have to make sure selection is OK */ for (ebone = G.edbo.first; ebone; ebone=ebone->next) { - if (arm->layer & ebone->layer) { + if (EBONE_VISIBLE(arm, ebone)) { if (ebone->flag & BONE_ROOTSEL) { if (ebone->parent && (ebone->flag & BONE_CONNECTED)) { if (ebone->parent->flag & BONE_TIPSEL) @@ -2990,7 +2970,7 @@ void extrude_armature(int forked) /* Duplicate the necessary bones */ for (ebone = G.edbo.first; ((ebone) && (ebone!=first)); ebone=ebone->next) { - if (arm->layer & ebone->layer) { + if (EBONE_VISIBLE(arm, ebone)) { /* we extrude per definition the tip */ do_extrude= 0; if (ebone->flag & (BONE_TIPSEL|BONE_SELECTED)) @@ -3004,7 +2984,7 @@ void extrude_armature(int forked) if (do_extrude) { /* we re-use code for mirror editing... */ flipbone= NULL; - if(arm->flag & ARM_MIRROR_EDIT) { + if (arm->flag & ARM_MIRROR_EDIT) { flipbone= armature_bone_get_mirrored(ebone); if (flipbone) { forked= 0; // we extrude 2 different bones @@ -3034,7 +3014,7 @@ void extrude_armature(int forked) newbone->parent = ebone; newbone->flag = ebone->flag & BONE_TIPSEL; // copies it, in case mirrored bone - + if (newbone->parent) newbone->flag |= BONE_CONNECTED; } else { @@ -3044,7 +3024,7 @@ void extrude_armature(int forked) newbone->flag= BONE_TIPSEL; - if (newbone->parent && ebone->flag & BONE_CONNECTED) { + if (newbone->parent && (ebone->flag & BONE_CONNECTED)) { newbone->flag |= BONE_CONNECTED; } } @@ -3063,8 +3043,8 @@ void extrude_armature(int forked) BLI_strncpy (newbone->name, ebone->name, 32); if (flipbone && forked) { // only set if mirror edit - if(strlen(newbone->name)<30) { - if(a==0) strcat(newbone->name, "_L"); + if (strlen(newbone->name)<30) { + if (a==0) strcat(newbone->name, "_L"); else strcat(newbone->name, "_R"); } } @@ -3109,7 +3089,7 @@ void subdivide_armature(int numcuts) if (numcuts < 1) return; for (mbone = G.edbo.last; mbone; mbone= mbone->prev) { - if (arm->layer & mbone->layer) { + if (EBONE_VISIBLE(arm, mbone)) { if (mbone->flag & BONE_SELECTED) { for (i=numcuts+1; i>1; i--) { /* compute cut ratio first */ @@ -3174,6 +3154,59 @@ void subdivide_armature(int numcuts) else BIF_undo_push("Subdivide multi"); } +/* switch direction of bone chains */ +void switch_direction_armature (void) +{ + bArmature *arm= (G.obedit) ? G.obedit->data : NULL; + ListBase chains = {NULL, NULL}; + LinkData *chain; + + /* error checking paranoia */ + if (arm == NULL) + return; + + /* get chains of bones (ends on chains) */ + chains_find_tips(&chains); + if (chains.first == NULL) return; + + /* loop over chains, only considering selected and visible bones */ + for (chain= chains.first; chain; chain= chain->next) { + EditBone *ebo, *child=NULL, *parent=NULL; + + /* loop over bones in chain */ + for (ebo= chain->data; ebo; child= ebo, ebo=parent) { + parent= ebo->parent; + + /* only if selected and editable */ + if (EBONE_VISIBLE(arm, ebo) && EBONE_EDITABLE(ebo)) { + /* swap head and tail coordinates */ + SWAP(float, ebo->head[0], ebo->tail[0]); + SWAP(float, ebo->head[1], ebo->tail[1]); + SWAP(float, ebo->head[2], ebo->tail[2]); + + /* do parent swapping: + * - use 'child' as new parent + * - connected flag is only set if points are coincidental + */ + ebo->parent= child; + if ((child) && VecEqual(ebo->head, child->tail)) + ebo->flag |= BONE_CONNECTED; + else + ebo->flag &= ~BONE_CONNECTED; + + /* FIXME: other things that need fixing? + * i.e. roll? + */ + } + } + } + + /* free chains */ + BLI_freelistN(&chains); + + BIF_undo_push("Switch Direction"); +} + /* ***************** Pose tools ********************* */ void clear_armature(Object *ob, char mode) diff --git a/source/blender/src/editimasel.c b/source/blender/src/editimasel.c index 67e10d771e0..97ddc2e0f1d 100644 --- a/source/blender/src/editimasel.c +++ b/source/blender/src/editimasel.c @@ -1076,6 +1076,12 @@ void winqreadimaselspace(ScrArea *sa, void *spacedata, BWinEvent *evt) toggle_blockhandler(sa, IMASEL_HANDLER_IMAGE, UI_PNL_UNSTOW); scrarea_queue_winredraw(sa); break; + case HKEY: + simasel->flag ^= FILE_HIDE_DOT; + BIF_filelist_free(simasel->files); + do_draw= 1; + do_headdraw= 1; + break; case PKEY: if(G.qual & LR_SHIFTKEY) { extern char bprogname[]; /* usiblender.c */ diff --git a/source/blender/src/editipo.c b/source/blender/src/editipo.c index c5dd41e16d5..aa7787c5905 100644 --- a/source/blender/src/editipo.c +++ b/source/blender/src/editipo.c @@ -82,6 +82,7 @@ #include "BKE_group.h" #include "BKE_ipo.h" #include "BKE_key.h" +#include "BKE_main.h" #include "BKE_material.h" #include "BKE_particle.h" #include "BKE_texture.h" @@ -933,6 +934,9 @@ static void make_editipo(void) ob->ipowin= ID_TE; make_texture_editipo(G.sipo); } + else if(G.scene->world && give_current_world_texture()) { + make_texture_editipo(G.sipo); + } } else if(G.sipo->blocktype==ID_CA) { if (ob) { @@ -1120,6 +1124,11 @@ static void get_ipo_context(short blocktype, ID **from, Ipo **ipo, char *actname *from= (ID *)tex; if(tex) *ipo= tex->ipo; } + else if(G.scene->world) { + Tex *tex= give_current_world_texture(); + *from= (ID *)tex; + if(tex) *ipo= tex->ipo; + } } else if(blocktype==ID_MA) { if(ob) { diff --git a/source/blender/src/editmesh_mods.c b/source/blender/src/editmesh_mods.c index 448a1019d29..d1a4f77cd27 100644 --- a/source/blender/src/editmesh_mods.c +++ b/source/blender/src/editmesh_mods.c @@ -1429,361 +1429,398 @@ int mesh_layers_menu(CustomData *data, int type) { return ret; } -/* ctrl+c in mesh editmode */ -void mesh_copy_menu(void) +void EM_mesh_copy_edge(short type) { EditMesh *em = G.editMesh; EditSelection *ese; - short ret, change=0; + short change=0; + + EditEdge *eed, *eed_act; + float vec[3], vec_mid[3], eed_len, eed_len_act; if (!em) return; ese = em->selected.last; + if (!ese) return; - /* Faces can have a NULL ese, so dont return on a NULL ese here */ + eed_act = (EditEdge*)ese->data; - if(ese && ese->type == EDITVERT) { - - if (!ese) return; - /*EditVert *ev, *ev_act = (EditVert*)ese->data; - ret= pupmenu("");*/ - } else if(ese && ese->type == EDITEDGE) { - EditEdge *eed, *eed_act; - float vec[3], vec_mid[3], eed_len, eed_len_act; - - if (!ese) return; - - eed_act = (EditEdge*)ese->data; - - ret= pupmenu("Copy Active Edge to Selected%t|Crease%x1|Bevel Weight%x2|Length%x3"); - if (ret<1) return; - - eed_len_act = VecLenf(eed_act->v1->co, eed_act->v2->co); - - switch (ret) { - case 1: /* copy crease */ - for(eed=em->edges.first; eed; eed=eed->next) { - if (eed->f & SELECT && eed != eed_act && eed->crease != eed_act->crease) { - eed->crease = eed_act->crease; - change = 1; - } + switch (type) { + case 1: /* copy crease */ + for(eed=em->edges.first; eed; eed=eed->next) { + if (eed->f & SELECT && eed != eed_act && eed->crease != eed_act->crease) { + eed->crease = eed_act->crease; + change = 1; } - break; - case 2: /* copy bevel weight */ - for(eed=em->edges.first; eed; eed=eed->next) { - if (eed->f & SELECT && eed != eed_act && eed->bweight != eed_act->bweight) { - eed->bweight = eed_act->bweight; - change = 1; - } + } + break; + case 2: /* copy bevel weight */ + for(eed=em->edges.first; eed; eed=eed->next) { + if (eed->f & SELECT && eed != eed_act && eed->bweight != eed_act->bweight) { + eed->bweight = eed_act->bweight; + change = 1; } - break; - - case 3: /* copy length */ - - for(eed=em->edges.first; eed; eed=eed->next) { - if (eed->f & SELECT && eed != eed_act) { - - eed_len = VecLenf(eed->v1->co, eed->v2->co); - - if (eed_len == eed_len_act) continue; - /* if this edge is zero length we cont do anything with it*/ - if (eed_len == 0.0f) continue; - if (eed_len_act == 0.0f) { - VecAddf(vec_mid, eed->v1->co, eed->v2->co); - VecMulf(vec_mid, 0.5); - VECCOPY(eed->v1->co, vec_mid); - VECCOPY(eed->v2->co, vec_mid); - } else { - /* copy the edge length */ - VecAddf(vec_mid, eed->v1->co, eed->v2->co); - VecMulf(vec_mid, 0.5); - - /* SCALE 1 */ - VecSubf(vec, eed->v1->co, vec_mid); - VecMulf(vec, eed_len_act/eed_len); - VecAddf(eed->v1->co, vec, vec_mid); - - /* SCALE 2 */ - VecSubf(vec, eed->v2->co, vec_mid); - VecMulf(vec, eed_len_act/eed_len); - VecAddf(eed->v2->co, vec, vec_mid); - } - change = 1; + } + break; + + case 3: /* copy length */ + eed_len_act = VecLenf(eed_act->v1->co, eed_act->v2->co); + for(eed=em->edges.first; eed; eed=eed->next) { + if (eed->f & SELECT && eed != eed_act) { + + eed_len = VecLenf(eed->v1->co, eed->v2->co); + + if (eed_len == eed_len_act) continue; + /* if this edge is zero length we cont do anything with it*/ + if (eed_len == 0.0f) continue; + if (eed_len_act == 0.0f) { + VecAddf(vec_mid, eed->v1->co, eed->v2->co); + VecMulf(vec_mid, 0.5); + VECCOPY(eed->v1->co, vec_mid); + VECCOPY(eed->v2->co, vec_mid); + } else { + /* copy the edge length */ + VecAddf(vec_mid, eed->v1->co, eed->v2->co); + VecMulf(vec_mid, 0.5); + + /* SCALE 1 */ + VecSubf(vec, eed->v1->co, vec_mid); + VecMulf(vec, eed_len_act/eed_len); + VecAddf(eed->v1->co, vec, vec_mid); + + /* SCALE 2 */ + VecSubf(vec, eed->v2->co, vec_mid); + VecMulf(vec, eed_len_act/eed_len); + VecAddf(eed->v2->co, vec, vec_mid); } + change = 1; } - - if (change) - recalc_editnormals(); - - - break; } + + if (change) + recalc_editnormals(); + + break; + } + + if (change) { + DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA); + allqueue(REDRAWVIEW3D, 0); + allqueue(REDRAWBUTSEDIT, 0); - } else if(ese==NULL || ese->type == EDITFACE) { - EditFace *efa, *efa_act; - MTFace *tf, *tf_act = NULL; - MCol *mcol, *mcol_act = NULL; - - efa_act = EM_get_actFace(0); - - if (efa_act) { - ret= pupmenu( - "Copy Face Selected%t|" - "Active Material%x1|Active Image%x2|Active UV Coords%x3|" - "Active Mode%x4|Active Transp%x5|Active Vertex Colors%x6|%l|" - - "TexFace UVs from layer%x7|" - "TexFace Images from layer%x8|" - "TexFace All from layer%x9|" - "Vertex Colors from layer%x10"); - if (ret<1) return; - tf_act = CustomData_em_get(&em->fdata, efa_act->data, CD_MTFACE); - mcol_act = CustomData_em_get(&em->fdata, efa_act->data, CD_MCOL); - } else { - ret= pupmenu( - "Copy Face Selected%t|" - - /* Make sure these are always the same as above */ - "TexFace UVs from layer%x7|" - "TexFace Images from layer%x8|" - "TexFace All from layer%x9|" - "Vertex Colors from layer%x10"); - if (ret<1) return; + BIF_undo_push("Copy Edge Attribute"); + } +} + +void EM_mesh_copy_face(short type) +{ + EditMesh *em = G.editMesh; + short change=0; + + EditFace *efa, *efa_act; + MTFace *tf, *tf_act = NULL; + MCol *mcol, *mcol_act = NULL; + if (!em) return; + efa_act = EM_get_actFace(0); + + if (!efa_act) return; + + tf_act = CustomData_em_get(&em->fdata, efa_act->data, CD_MTFACE); + mcol_act = CustomData_em_get(&em->fdata, efa_act->data, CD_MCOL); + + switch (type) { + case 1: /* copy material */ + for(efa=em->faces.first; efa; efa=efa->next) { + if (efa->f & SELECT && efa->mat_nr != efa_act->mat_nr) { + efa->mat_nr = efa_act->mat_nr; + change = 1; + } } - - switch (ret) { - case 1: /* copy material */ - for(efa=em->faces.first; efa; efa=efa->next) { - if (efa->f & SELECT && efa->mat_nr != efa_act->mat_nr) { - efa->mat_nr = efa_act->mat_nr; - change = 1; + break; + case 2: /* copy image */ + if (!tf_act) { + error("mesh has no uv/image layers"); + return; + } + for(efa=em->faces.first; efa; efa=efa->next) { + if (efa->f & SELECT && efa != efa_act) { + tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); + if (tf_act->tpage) { + tf->tpage = tf_act->tpage; + tf->mode |= TF_TEX; + } else { + tf->tpage = NULL; + tf->mode &= ~TF_TEX; } + tf->tile= tf_act->tile; + change = 1; } - break; - case 2: /* copy image */ - if (!tf_act) { - error("mesh has no uv/image layers"); - return; + } + break; + + case 3: /* copy UV's */ + if (!tf_act) { + error("mesh has no uv/image layers"); + return; + } + for(efa=em->faces.first; efa; efa=efa->next) { + if (efa->f & SELECT && efa != efa_act) { + tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); + memcpy(tf->uv, tf_act->uv, sizeof(tf->uv)); + change = 1; } - for(efa=em->faces.first; efa; efa=efa->next) { - if (efa->f & SELECT && efa != efa_act) { - tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - if (tf_act->tpage) { - tf->tpage = tf_act->tpage; - tf->mode |= TF_TEX; - } else { - tf->tpage = NULL; - tf->mode &= ~TF_TEX; - } - tf->tile= tf_act->tile; - change = 1; - } + } + break; + case 4: /* mode's */ + if (!tf_act) { + error("mesh has no uv/image layers"); + return; + } + for(efa=em->faces.first; efa; efa=efa->next) { + if (efa->f & SELECT && efa != efa_act) { + tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); + tf->mode= tf_act->mode; + change = 1; } - break; - - case 3: /* copy UV's */ - if (!tf_act) { - error("mesh has no uv/image layers"); - return; + } + break; + case 5: /* copy transp's */ + if (!tf_act) { + error("mesh has no uv/image layers"); + return; + } + for(efa=em->faces.first; efa; efa=efa->next) { + if (efa->f & SELECT && efa != efa_act) { + tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); + tf->transp= tf_act->transp; + change = 1; } + } + break; + + case 6: /* copy vcols's */ + if (!mcol_act) { + error("mesh has no color layers"); + return; + } else { + /* guess the 4th color if needs be */ + float val =- 1; + + if (!efa_act->v4) { + /* guess the othe vale, we may need to use it + * + * Modifying the 4th value of the mcol is ok here since its not seen + * on a triangle + * */ + val = ((float)(mcol_act->r + (mcol_act+1)->r + (mcol_act+2)->r)) / 3; CLAMP(val, 0, 255); + (mcol_act+3)->r = (char)val; + + val = ((float)(mcol_act->g + (mcol_act+1)->g + (mcol_act+2)->g)) / 3; CLAMP(val, 0, 255); + (mcol_act+3)->g = (char)val; + + val = ((float)(mcol_act->b + (mcol_act+1)->b + (mcol_act+2)->b)) / 3; CLAMP(val, 0, 255); + (mcol_act+3)->b = (char)val; + } + + for(efa=em->faces.first; efa; efa=efa->next) { if (efa->f & SELECT && efa != efa_act) { - tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - memcpy(tf->uv, tf_act->uv, sizeof(tf->uv)); + /* TODO - make copy from tri to quad guess the 4th vert */ + mcol = CustomData_em_get(&em->fdata, efa->data, CD_MCOL); + memcpy(mcol, mcol_act, sizeof(MCol)*4); change = 1; } } - break; - case 4: /* mode's */ - if (!tf_act) { - error("mesh has no uv/image layers"); + } + break; + } + + if (change) { + DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA); + allqueue(REDRAWVIEW3D, 0); + allqueue(REDRAWBUTSEDIT, 0); + if (type==3) { + allqueue(REDRAWIMAGE, 0); + } + + BIF_undo_push("Copy Face Attribute"); + } +} + + +void EM_mesh_copy_face_layer(short type) +{ + EditMesh *em = G.editMesh; + short change=0; + + EditFace *efa; + MTFace *tf, *tf_from; + MCol *mcol, *mcol_from; + + if (!em) return; + + switch(type) { + case 7: + case 8: + case 9: + if (CustomData_number_of_layers(&em->fdata, CD_MTFACE)<2) { + error("mesh does not have multiple uv/image layers"); + return; + } else { + int layer_orig_idx, layer_idx; + + layer_idx = mesh_layers_menu(&em->fdata, CD_MTFACE); + if (layer_idx<0) return; + + /* warning, have not updated mesh pointers however this is not needed since we swicth back */ + layer_orig_idx = CustomData_get_active_layer(&em->fdata, CD_MTFACE); + if (layer_idx==layer_orig_idx) return; - } + + /* get the tfaces */ + CustomData_set_layer_active(&em->fdata, CD_MTFACE, (int)layer_idx); + /* store the tfaces in our temp */ for(efa=em->faces.first; efa; efa=efa->next) { - if (efa->f & SELECT && efa != efa_act) { - tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - tf->mode= tf_act->mode; - change = 1; - } + if (efa->f & SELECT) { + efa->tmp.p = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); + } } - break; - case 5: /* copy transp's */ - if (!tf_act) { - error("mesh has no uv/image layers"); + CustomData_set_layer_active(&em->fdata, CD_MTFACE, layer_orig_idx); + } + break; + + case 10: /* select vcol layers - make sure this stays in sync with above code */ + if (CustomData_number_of_layers(&em->fdata, CD_MCOL)<2) { + error("mesh does not have multiple color layers"); + return; + } else { + int layer_orig_idx, layer_idx; + + layer_idx = mesh_layers_menu(&em->fdata, CD_MCOL); + if (layer_idx<0) return; + + /* warning, have not updated mesh pointers however this is not needed since we swicth back */ + layer_orig_idx = CustomData_get_active_layer(&em->fdata, CD_MCOL); + if (layer_idx==layer_orig_idx) return; - } + + /* get the tfaces */ + CustomData_set_layer_active(&em->fdata, CD_MCOL, (int)layer_idx); + /* store the tfaces in our temp */ for(efa=em->faces.first; efa; efa=efa->next) { - if (efa->f & SELECT && efa != efa_act) { - tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - tf->transp= tf_act->transp; - change = 1; - } - } - break; - - case 6: /* copy vcols's */ - if (!mcol_act) { - error("mesh has no color layers"); - return; - } else { - /* guess the 4th color if needs be */ - float val =- 1; - - if (!efa_act->v4) { - /* guess the othe vale, we may need to use it - * - * Modifying the 4th value of the mcol is ok here since its not seen - * on a triangle - * */ - val = ((float)(mcol_act->r + (mcol_act+1)->r + (mcol_act+2)->r)) / 3; CLAMP(val, 0, 255); - (mcol_act+3)->r = (char)val; - - val = ((float)(mcol_act->g + (mcol_act+1)->g + (mcol_act+2)->g)) / 3; CLAMP(val, 0, 255); - (mcol_act+3)->g = (char)val; - - val = ((float)(mcol_act->b + (mcol_act+1)->b + (mcol_act+2)->b)) / 3; CLAMP(val, 0, 255); - (mcol_act+3)->b = (char)val; - } - - - for(efa=em->faces.first; efa; efa=efa->next) { - if (efa->f & SELECT && efa != efa_act) { - /* TODO - make copy from tri to quad guess the 4th vert */ - mcol = CustomData_em_get(&em->fdata, efa->data, CD_MCOL); - memcpy(mcol, mcol_act, sizeof(MCol)*4); - change = 1; - } - } - } - - break; - - /* Copy from layer - Warning! tf_act and mcol_act will be NULL here */ - case 7: - case 8: - case 9: - if (CustomData_number_of_layers(&em->fdata, CD_MTFACE)<2) { - error("mesh does not have multiple uv/image layers"); - return; - } else { - int layer_orig_idx, layer_idx; - - layer_idx = mesh_layers_menu(&em->fdata, CD_MTFACE); - if (layer_idx<0) return; - - /* warning, have not updated mesh pointers however this is not needed since we swicth back */ - layer_orig_idx = CustomData_get_active_layer(&em->fdata, CD_MTFACE); - if (layer_idx==layer_orig_idx) - return; - - /* get the tfaces */ - CustomData_set_layer_active(&em->fdata, CD_MTFACE, (int)layer_idx); - /* store the tfaces in our temp */ - for(efa=em->faces.first; efa; efa=efa->next) { - if (efa->f & SELECT) { - efa->tmp.p = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - } - } - CustomData_set_layer_active(&em->fdata, CD_MTFACE, layer_orig_idx); - } - break; - - case 10: /* select vcol layers - make sure this stays in sync with above code */ - if (CustomData_number_of_layers(&em->fdata, CD_MCOL)<2) { - error("mesh does not have multiple color layers"); - return; - } else { - int layer_orig_idx, layer_idx; - - layer_idx = mesh_layers_menu(&em->fdata, CD_MCOL); - if (layer_idx<0) return; - - /* warning, have not updated mesh pointers however this is not needed since we swicth back */ - layer_orig_idx = CustomData_get_active_layer(&em->fdata, CD_MCOL); - if (layer_idx==layer_orig_idx) - return; - - /* get the tfaces */ - CustomData_set_layer_active(&em->fdata, CD_MCOL, (int)layer_idx); - /* store the tfaces in our temp */ - for(efa=em->faces.first; efa; efa=efa->next) { - if (efa->f & SELECT) { - efa->tmp.p = CustomData_em_get(&em->fdata, efa->data, CD_MCOL); - } - } - CustomData_set_layer_active(&em->fdata, CD_MCOL, layer_orig_idx); - + if (efa->f & SELECT) { + efa->tmp.p = CustomData_em_get(&em->fdata, efa->data, CD_MCOL); + } } - break; + CustomData_set_layer_active(&em->fdata, CD_MCOL, layer_orig_idx); + } - - /* layer copy only - sanity checks done above */ - switch (ret) { - case 7: /* copy UV's only */ - for(efa=em->faces.first; efa; efa=efa->next) { - if (efa->f & SELECT) { - tf_act = (MTFace *)efa->tmp.p; /* not active but easier to use this way */ - tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - memcpy(tf->uv, tf_act->uv, sizeof(tf->uv)); - change = 1; - } + break; + } + + /* layer copy only - sanity checks done above */ + switch (type) { + case 7: /* copy UV's only */ + for(efa=em->faces.first; efa; efa=efa->next) { + if (efa->f & SELECT) { + tf_from = (MTFace *)efa->tmp.p; /* not active but easier to use this way */ + tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); + memcpy(tf->uv, tf_from->uv, sizeof(tf->uv)); + change = 1; } - break; - case 8: /* copy image settings only */ - for(efa=em->faces.first; efa; efa=efa->next) { - if (efa->f & SELECT) { - tf_act = (MTFace *)efa->tmp.p; /* not active but easier to use this way */ - tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - if (tf_act->tpage) { - tf->tpage = tf_act->tpage; - tf->mode |= TF_TEX; - } else { - tf->tpage = NULL; - tf->mode &= ~TF_TEX; - } - tf->tile= tf_act->tile; - change = 1; + } + break; + case 8: /* copy image settings only */ + for(efa=em->faces.first; efa; efa=efa->next) { + if (efa->f & SELECT) { + tf_from = (MTFace *)efa->tmp.p; /* not active but easier to use this way */ + tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); + if (tf_from->tpage) { + tf->tpage = tf_from->tpage; + tf->mode |= TF_TEX; + } else { + tf->tpage = NULL; + tf->mode &= ~TF_TEX; } + tf->tile= tf_from->tile; + change = 1; } - break; - case 9: /* copy all tface info */ - for(efa=em->faces.first; efa; efa=efa->next) { - if (efa->f & SELECT) { - tf_act = (MTFace *)efa->tmp.p; /* not active but easier to use this way */ - tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - memcpy(tf->uv, ((MTFace *)efa->tmp.p)->uv, sizeof(tf->uv)); - tf->tpage = tf_act->tpage; - tf->mode = tf_act->mode; - tf->transp = tf_act->transp; - change = 1; - } + } + break; + case 9: /* copy all tface info */ + for(efa=em->faces.first; efa; efa=efa->next) { + if (efa->f & SELECT) { + tf_from = (MTFace *)efa->tmp.p; /* not active but easier to use this way */ + tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); + memcpy(tf->uv, ((MTFace *)efa->tmp.p)->uv, sizeof(tf->uv)); + tf->tpage = tf_from->tpage; + tf->mode = tf_from->mode; + tf->transp = tf_from->transp; + change = 1; } - break; - case 10: - for(efa=em->faces.first; efa; efa=efa->next) { - if (efa->f & SELECT) { - mcol_act = (MCol *)efa->tmp.p; - mcol = CustomData_em_get(&em->fdata, efa->data, CD_MCOL); - memcpy(mcol, mcol_act, sizeof(MCol)*4); - change = 1; - } + } + break; + case 10: + for(efa=em->faces.first; efa; efa=efa->next) { + if (efa->f & SELECT) { + mcol_from = (MCol *)efa->tmp.p; + mcol = CustomData_em_get(&em->fdata, efa->data, CD_MCOL); + memcpy(mcol, mcol_from, sizeof(MCol)*4); + change = 1; } - break; } - + break; } - + if (change) { DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA); allqueue(REDRAWVIEW3D, 0); allqueue(REDRAWBUTSEDIT, 0); - if (ese==NULL || ese->type == EDITFACE) BIF_undo_push("Copy Face Attribute"); - else if ( ese->type == EDITEDGE) BIF_undo_push("Copy Edge Attribute"); - else if ( ese->type == EDITVERT) BIF_undo_push("Copy Vert Attribute"); - + BIF_undo_push("Copy Face Layer"); } +} + + +/* ctrl+c in mesh editmode */ +void mesh_copy_menu(void) +{ + EditMesh *em = G.editMesh; + EditSelection *ese; + int ret; + if (!em) return; + ese = em->selected.last; + + /* Faces can have a NULL ese, so dont return on a NULL ese here */ + + if(ese && ese->type == EDITVERT) { + /* EditVert *ev, *ev_act = (EditVert*)ese->data; + ret= pupmenu(""); */ + } else if(ese && ese->type == EDITEDGE) { + ret= pupmenu("Copy Active Edge to Selected%t|Crease%x1|Bevel Weight%x2|Length%x3"); + if (ret<1) return; + + EM_mesh_copy_edge(ret); + + } else if(ese==NULL || ese->type == EDITFACE) { + ret= pupmenu( + "Copy Face Selected%t|" + "Active Material%x1|Active Image%x2|Active UV Coords%x3|" + "Active Mode%x4|Active Transp%x5|Active Vertex Colors%x6|%l|" + + "TexFace UVs from layer%x7|" + "TexFace Images from layer%x8|" + "TexFace All from layer%x9|" + "Vertex Colors from layer%x10"); + if (ret<1) return; + + if (ret<=6) { + EM_mesh_copy_face(ret); + } else { + EM_mesh_copy_face_layer(ret); + } + } } diff --git a/source/blender/src/editobject.c b/source/blender/src/editobject.c index b2b66deeb8a..7da09aaac42 100644 --- a/source/blender/src/editobject.c +++ b/source/blender/src/editobject.c @@ -2757,7 +2757,7 @@ void special_editmenu(void) DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA); } else if(G.obedit->type==OB_ARMATURE) { - nr= pupmenu("Specials%t|Subdivide %x1|Subdivide Multi%x2|Flip Left-Right Names%x3|%l|AutoName Left-Right%x4|AutoName Front-Back%x5|AutoName Top-Bottom%x6|%l|Lock%x7|Unlock%x8"); + nr= pupmenu("Specials%t|Subdivide %x1|Subdivide Multi%x2|Switch Direction%x7|Flip Left-Right Names%x3|%l|AutoName Left-Right%x4|AutoName Front-Back%x5|AutoName Top-Bottom%x6"); if(nr==1) subdivide_armature(1); if(nr==2) { @@ -2770,10 +2770,8 @@ void special_editmenu(void) else if(ELEM3(nr, 4, 5, 6)) { armature_autoside_names(nr-4); } - else if(nr==7) - set_locks_armature_bones(1); - else if(nr==8) - set_locks_armature_bones(0); + else if(nr == 7) + switch_direction_armature(); } else if(G.obedit->type==OB_LATTICE) { static float weight= 1.0f; @@ -3503,6 +3501,17 @@ void copy_attr(short event) base->object->damping= ob->damping; base->object->rdamping= ob->rdamping; } + else if(event==11) { /* all physical attributes */ + base->object->gameflag = ob->gameflag; + base->object->inertia = ob->inertia; + base->object->formfactor = ob->formfactor; + base->object->damping= ob->damping; + base->object->rdamping= ob->rdamping; + base->object->mass= ob->mass; + if (ob->gameflag & OB_BOUNDS) { + base->object->boundtype = ob->boundtype; + } + } else if(event==17) { /* tex space */ copy_texture_space(base->object, ob); } @@ -3689,7 +3698,7 @@ void copy_attr_menu() * view3d_edit_object_copyattrmenu() and in toolbox.c */ - strcpy(str, "Copy Attributes %t|Location%x1|Rotation%x2|Size%x3|Draw Options%x4|Time Offset%x5|Dupli%x6|%l|Mass%x7|Damping%x8|Properties%x9|Logic Bricks%x10|Protected Transform%x29|%l"); + strcpy(str, "Copy Attributes %t|Location%x1|Rotation%x2|Size%x3|Draw Options%x4|Time Offset%x5|Dupli%x6|%l|Mass%x7|Damping%x8|All Physical Attributes%x11|Properties%x9|Logic Bricks%x10|Protected Transform%x29|%l"); strcat (str, "|Object Constraints%x22"); strcat (str, "|NLA Strips%x26"); diff --git a/source/blender/src/editseq.c b/source/blender/src/editseq.c index 12019a9dab9..e9d0b57a166 100644 --- a/source/blender/src/editseq.c +++ b/source/blender/src/editseq.c @@ -644,6 +644,7 @@ static int seq_is_parent(Sequence *par, Sequence *seq) static int seq_is_predecessor(Sequence *pred, Sequence *seq) { + if (!pred) return 0; if(pred == seq) return 0; else if(seq_is_parent(pred, seq)) return 1; else if(pred->seq1 && seq_is_predecessor(pred->seq1, seq)) return 1; diff --git a/source/blender/src/editview.c b/source/blender/src/editview.c index e3ec69975de..a3fcad7885c 100644 --- a/source/blender/src/editview.c +++ b/source/blender/src/editview.c @@ -298,7 +298,7 @@ int lasso_inside(short mcords[][2], short moves, short sx, short sy) } /* edge version for lasso select. we assume boundbox check was done */ -static int lasso_inside_edge(short mcords[][2], short moves, int x0, int y0, int x1, int y1) +int lasso_inside_edge(short mcords[][2], short moves, int x0, int y0, int x1, int y1) { short v1[2], v2[2]; int a; @@ -371,7 +371,7 @@ static void do_lasso_select_objects(short mcords[][2], short moves, short select } } -static void lasso_select_boundbox(rcti *rect, short mcords[][2], short moves) +void lasso_select_boundbox(rcti *rect, short mcords[][2], short moves) { short a; diff --git a/source/blender/src/gpencil.c b/source/blender/src/gpencil.c index 24ed6a7b0ba..eef21323a44 100644 --- a/source/blender/src/gpencil.c +++ b/source/blender/src/gpencil.c @@ -48,6 +48,7 @@ #include "DNA_screen_types.h" #include "DNA_space_types.h" #include "DNA_userdef_types.h" +#include "DNA_vec_types.h" #include "DNA_view3d_types.h" #include "BKE_global.h" @@ -57,6 +58,7 @@ #include "BIF_gl.h" #include "BIF_glutil.h" #include "BIF_butspace.h" +#include "BIF_editview.h" #include "BIF_graphics.h" #include "BIF_interface.h" #include "BIF_mywindow.h" @@ -683,7 +685,7 @@ typedef struct tGPsdata { bGPDframe *gpf; /* frame we're working on */ short status; /* current status of painting */ - short paintmode; /* mode for painting (L_MOUSE or R_MOUSE for now) */ + short paintmode; /* mode for painting */ } tGPsdata; /* values for tGPsdata->status */ @@ -693,6 +695,12 @@ enum { GP_STATUS_DONE /* painting done */ }; +/* values for tGPsdata->paintmode */ +enum { + GP_PAINTMODE_DRAW = 0, + GP_PAINTMODE_ERASER +}; + /* Return flags for adding points to stroke buffer */ enum { GP_STROKEADD_INVALID = -2, /* error occurred - insufficient info to do so */ @@ -710,9 +718,9 @@ static void gp_session_validatebuffer (tGPsdata *p) /* clear memory of buffer (or allocate it if starting a new session) */ if (gpd->sbuffer) - memset(gpd->sbuffer, 0, sizeof(bGPDspoint)*GP_STROKE_BUFFER_MAX); + memset(gpd->sbuffer, 0, sizeof(tGPspoint)*GP_STROKE_BUFFER_MAX); else - gpd->sbuffer= MEM_callocN(sizeof(bGPDspoint)*GP_STROKE_BUFFER_MAX, "gp_session_strokebuffer"); + gpd->sbuffer= MEM_callocN(sizeof(tGPspoint)*GP_STROKE_BUFFER_MAX, "gp_session_strokebuffer"); /* reset indices */ gpd->sbuffer_size = 0; @@ -850,6 +858,25 @@ static void gp_session_cleanup (tGPsdata *p) gpd->sbuffer_sflag= 0; } +/* check if the current mouse position is suitable for adding a new point */ +static short gp_stroke_filtermval (tGPsdata *p, short mval[2], short pmval[2]) +{ + short dx= abs(mval[0] - pmval[0]); + short dy= abs(mval[1] - pmval[1]); + + /* check if mouse moved at least certain distance on both axes (best case) */ + if ((dx > MIN_MANHATTEN_PX) && (dy > MIN_MANHATTEN_PX)) + return 1; + + /* check if the distance since the last point is significant enough */ + else if (sqrt(dx*dx + dy*dy) > MIN_EUCLIDEAN_PX) + return 1; + + /* mouse 'didn't move' */ + else + return 0; +} + /* convert screen-coordinates to buffer-coordinates */ static void gp_stroke_convertcoords (tGPsdata *p, short mval[], float out[]) { @@ -884,43 +911,24 @@ static void gp_stroke_convertcoords (tGPsdata *p, short mval[], float out[]) } } -/* check if the current mouse position is suitable for adding a new point */ -static short gp_stroke_filtermval (tGPsdata *p, short mval[2], short pmval[2]) -{ - short dx= abs(mval[0] - pmval[0]); - short dy= abs(mval[1] - pmval[1]); - - /* check if mouse moved at least certain distance on both axes (best case) */ - if ((dx > MIN_MANHATTEN_PX) && (dy > MIN_MANHATTEN_PX)) - return 1; - - /* check if the distance since the last point is significant enough */ - else if (sqrt(dx*dx + dy*dy) > MIN_EUCLIDEAN_PX) - return 1; - - /* mouse 'didn't move' */ - else - return 0; -} - /* add current stroke-point to buffer (returns whether point was successfully added) */ static short gp_stroke_addpoint (tGPsdata *p, short mval[2], float pressure) { bGPdata *gpd= p->gpd; - bGPDspoint *pt; + tGPspoint *pt; /* check if still room in buffer */ if (gpd->sbuffer_size >= GP_STROKE_BUFFER_MAX) return GP_STROKEADD_OVERFLOW; - /* get pointer to destination point */ - pt= gpd->sbuffer + gpd->sbuffer_size; + pt= ((tGPspoint *)(gpd->sbuffer) + gpd->sbuffer_size); - /* convert screen-coordinates to appropriate coordinates (and store them) */ - gp_stroke_convertcoords(p, mval, &pt->x); - - /* store other settings */ + /* 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 */ @@ -933,38 +941,13 @@ static short gp_stroke_addpoint (tGPsdata *p, short mval[2], float pressure) return GP_STROKEADD_NORMAL; } -/* smooth a stroke (in buffer) before storing it */ -static void gp_stroke_smooth (tGPsdata *p) -{ - bGPdata *gpd= p->gpd; - int i=0, cmx=gpd->sbuffer_size; - - // fixme: currently disabled as it damages too much sometimes - return; - - /* don't try if less than 2 points in buffer */ - if ((cmx <= 2) || (gpd->sbuffer == NULL)) - return; - - /* apply weighting-average (note doing this along path sequentially does introduce slight error) */ - for (i=0; i < gpd->sbuffer_size; i++) { - bGPDspoint *pc= (gpd->sbuffer + i); - bGPDspoint *pb= (i-1 > 0)?(pc-1):(pc); - bGPDspoint *pa= (i-2 > 0)?(pc-2):(pb); - bGPDspoint *pd= (i+1 < cmx)?(pc+1):(pc); - bGPDspoint *pe= (i+2 < cmx)?(pc+2):(pd); - - pc->x= (0.1*pa->x + 0.2*pb->x + 0.4*pc->x + 0.2*pd->x + 0.1*pe->x); - pc->y= (0.1*pa->y + 0.2*pb->y + 0.4*pc->y + 0.2*pd->y + 0.1*pe->y); - } -} - /* make a new stroke from the buffer data */ static void gp_stroke_newfrombuffer (tGPsdata *p) { bGPdata *gpd= p->gpd; bGPDstroke *gps; - bGPDspoint *pt, *ptc; + bGPDspoint *pt; + tGPspoint *ptc; int i, totelem; /* get total number of points to allocate space for */ @@ -990,7 +973,12 @@ static void gp_stroke_newfrombuffer (tGPsdata *p) /* copy points from the buffer to the stroke */ for (i=0, ptc=gpd->sbuffer; i < gpd->sbuffer_size && ptc; i++, ptc++) { - memcpy(pt, ptc, sizeof(bGPDspoint)); + /* convert screen-coordinates to appropriate coordinates (and store them) */ + gp_stroke_convertcoords(p, &ptc->x, &pt->x); + + /* copy pressure */ + pt->pressure= ptc->pressure; + pt++; } @@ -998,10 +986,220 @@ static void gp_stroke_newfrombuffer (tGPsdata *p) BLI_addtail(&p->gpf->strokes, gps); } +/* --- '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) +{ + bGPDspoint *pt_tmp= gps->points; + bGPDstroke *gsn = NULL; + + /* if stroke only had two points, get rid of stroke */ + if (gps->totpoints == 2) { + /* free stroke points, then stroke */ + MEM_freeN(pt_tmp); + BLI_freelinkN(&gpf->strokes, gps); + + /* nothing left in stroke, so stop */ + return 1; + } + + /* if last segment, just remove segment from the stroke */ + else if (i == gps->totpoints - 2) { + /* allocate new points array, and assign most of the old stroke there */ + gps->totpoints--; + gps->points= MEM_callocN(sizeof(bGPDspoint)*gps->totpoints, "gp_stroke_points"); + memcpy(gps->points, pt_tmp, sizeof(bGPDspoint)*gps->totpoints); + + /* free temp buffer */ + MEM_freeN(pt_tmp); + + /* nothing left in stroke, so stop */ + return 1; + } + + /* if first segment, just remove segment from the stroke */ + else if (i == 0) { + /* allocate new points array, and assign most of the old stroke there */ + gps->totpoints--; + gps->points= MEM_callocN(sizeof(bGPDspoint)*gps->totpoints, "gp_stroke_points"); + memcpy(gps->points, pt_tmp + 1, sizeof(bGPDspoint)*gps->totpoints); + + /* free temp buffer */ + MEM_freeN(pt_tmp); + + /* no break here, as there might still be stuff to remove in this stroke */ + return 0; + } + + /* segment occurs in 'middle' of stroke, so split */ + else { + /* duplicate stroke, and assign 'later' data to that stroke */ + gsn= MEM_dupallocN(gps); + gsn->prev= gsn->next= NULL; + BLI_insertlinkafter(&gpf->strokes, gps, gsn); + + gsn->totpoints= gps->totpoints - i; + gsn->points= MEM_callocN(sizeof(bGPDspoint)*gsn->totpoints, "gp_stroke_points"); + memcpy(gsn->points, pt_tmp + i, sizeof(bGPDspoint)*gsn->totpoints); + + /* adjust existing stroke */ + gps->totpoints= i; + gps->points= MEM_callocN(sizeof(bGPDspoint)*gps->totpoints, "gp_stroke_points"); + memcpy(gps->points, pt_tmp, sizeof(bGPDspoint)*i); + + /* free temp buffer */ + MEM_freeN(pt_tmp); + + /* nothing left in stroke, so stop */ + return 1; + } +} + +/* eraser tool - evaluation per stroke */ +static void gp_stroke_eraser_dostroke (tGPsdata *p, short mcoords[][2], short moves, rcti *rect, bGPDframe *gpf, bGPDstroke *gps) +{ + bGPDspoint *pt1, *pt2; + short x0=0, y0=0, x1=0, y1=0; + short xyval[2]; + int i; + + if (gps->totpoints == 0) { + /* just free stroke */ + if (gps->points) + MEM_freeN(gps->points); + BLI_freelinkN(&gpf->strokes, gps); + } + 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]; + } + else if (gps->flag & GP_STROKE_2DSPACE) { + ipoco_to_areaco_noclip(p->v2d, &gps->points->x, xyval); + x0= xyval[0]; + y0= xyval[1]; + } + else { + x0= (gps->points->x / 1000 * p->sa->winx); + y0= (gps->points->y / 1000 * p->sa->winy); + } + + /* do boundbox check first */ + if (BLI_in_rcti(rect, x0, y0)) { + /* only check if point is inside */ + if (lasso_inside(mcoords, moves, x0, y0)) { + /* free stroke */ + MEM_freeN(gps->points); + BLI_freelinkN(&gpf->strokes, gps); + } + } + } + else { + /* loop over the points in the stroke, checking for intersections + * - an intersection will require the stroke to be split + */ + for (i=0; (i+1) < gps->totpoints; i++) { + /* get points to work with */ + pt1= gps->points + i; + pt2= gps->points + i + 1; + + /* get coordinates */ + if (gps->flag & GP_STROKE_3DSPACE) { + // FIXME: may not be correct correction + project_short(&gps->points->x, xyval); + x0= xyval[0]; + x1= xyval[1]; + } + else if (gps->flag & GP_STROKE_2DSPACE) { + ipoco_to_areaco_noclip(p->v2d, &pt1->x, xyval); + x0= xyval[0]; + y0= xyval[1]; + + ipoco_to_areaco_noclip(p->v2d, &pt2->x, xyval); + x1= xyval[0]; + y1= xyval[1]; + } + else { + x0= (pt1->x / 1000 * p->sa->winx); + y0= (pt1->y / 1000 * p->sa->winy); + x1= (pt2->x / 1000 * p->sa->winx); + y1= (pt2->y / 1000 * p->sa->winy); + } + + /* check that point segment of the boundbox of the eraser stroke */ + if (BLI_in_rcti(rect, x0, y0) || BLI_in_rcti(rect, x1, y1)) { + /* 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 function returns true, break this loop (as no more point to check) */ + if (gp_stroke_eraser_splitdel(gpf, gps, i)) + break; + } + } + } + } +} + +/* -------- */ + +/* 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); + + /* 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); + } + + /* free mcoords array */ + MEM_freeN(mcoords); +} + /* ---------- 'Paint' Tool ------------ */ /* init new stroke */ -static void gp_paint_initstroke (tGPsdata *p, short mousebutton) +static void gp_paint_initstroke (tGPsdata *p, short paintmode) { /* get active layer (or add a new one if non-existent) */ p->gpl= gpencil_layer_getactive(p->gpd); @@ -1025,14 +1223,10 @@ static void gp_paint_initstroke (tGPsdata *p, short mousebutton) else p->gpf->flag |= GP_FRAME_PAINT; - /* set 'eraser' for this stroke if using eraser or right-mouse in action */ - if ( get_activedevice() == 2 || (mousebutton & R_MOUSE) ) { + /* set 'eraser' for this stroke if using eraser */ + p->paintmode= paintmode; + if (p->paintmode == GP_PAINTMODE_ERASER) p->gpd->sbuffer_sflag |= GP_STROKE_ERASER; - - // for now: eraser isn't ready for prime-time yet, so no painting available here yet - p->status= GP_STATUS_ERROR; - return; - } /* check if points will need to be made in view-aligned space */ if (p->gpd->flag & GP_DATA_VIEWALIGN) { @@ -1062,12 +1256,10 @@ static void gp_paint_initstroke (tGPsdata *p, short mousebutton) /* finish off a stroke (clears buffer, but doesn't finish the paint operation) */ static void gp_paint_strokeend (tGPsdata *p) { - /* sanitize stroke-points in buffer (remove jitter) */ - gp_stroke_smooth(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 { /* transfer stroke to frame */ @@ -1100,7 +1292,7 @@ static void gp_paint_cleanup (tGPsdata *p) /* -------- */ /* main call to paint a new stroke */ -short gpencil_paint (short mousebutton) +short gpencil_paint (short mousebutton, short paintmode) { tGPsdata p; short prevmval[2], mval[2]; @@ -1113,7 +1305,7 @@ short gpencil_paint (short mousebutton) gp_session_cleanup(&p); return 0; } - gp_paint_initstroke(&p, mousebutton); + gp_paint_initstroke(&p, paintmode); if (p.status == GP_STATUS_ERROR) { gp_session_cleanup(&p); return 0; @@ -1188,7 +1380,10 @@ short gpencil_paint (short mousebutton) setcursor_space(p.sa->spacetype, CURSOR_STD); /* check size of buffer before cleanup, to determine if anything happened here */ - ok= p.gpd->sbuffer_size; + if (paintmode == GP_PAINTMODE_ERASER) + ok= (p.gpd->sbuffer_size > 1); + else + ok= p.gpd->sbuffer_size; /* cleanup */ gp_paint_cleanup(&p); @@ -1202,7 +1397,7 @@ short gpencil_paint (short mousebutton) /* All event (loops) handling checking if stroke drawing should be initiated * should call this function. */ -short gpencil_do_paint (ScrArea *sa, short mousebutton) +short gpencil_do_paint (ScrArea *sa, short mbut) { bGPdata *gpd = gpencil_data_getactive(sa); short retval= 0; @@ -1211,18 +1406,43 @@ short gpencil_do_paint (ScrArea *sa, short mousebutton) if (gpd == NULL) return 0; - /* currently, we will only paint if: + /* currently, we will only 'paint' if: * 1. draw-mode on gpd is set (for accessibility reasons) * (single 'dots' are only available via this method) * 2. if shift-modifier is held + lmb -> 'quick paint' + * + * OR + * + * draw eraser stroke if: + * 1. using the eraser on a tablet + * 2. draw-mode on gpd is set (for accessiblity reasons) + * (eraser is mapped to right-mouse) + * 3. Alt + 'select' mouse-button + * i.e. if LMB = select: Alt-LMB + * if RMB = select: Alt-RMB */ - if (gpd->flag & GP_DATA_EDITPAINT) { - /* try to paint */ - retval = gpencil_paint(mousebutton); + if (get_activedevice() == 2) { + /* eraser on a tablet - always try to erase strokes */ + retval = gpencil_paint(mbut, GP_PAINTMODE_ERASER); + } + else if (gpd->flag & GP_DATA_EDITPAINT) { + /* try to paint/erase */ + if (mbut == L_MOUSE) + retval = gpencil_paint(mbut, GP_PAINTMODE_DRAW); + else if (mbut == R_MOUSE) + retval = gpencil_paint(mbut, GP_PAINTMODE_ERASER); } - else if (!(gpd->flag & GP_DATA_LMBPLOCK) && (G.qual == LR_SHIFTKEY)) { - /* try to paint */ - retval = gpencil_paint(mousebutton); + else if (!(gpd->flag & GP_DATA_LMBPLOCK)) { + /* try to paint/erase as not locked */ + if ((G.qual == LR_SHIFTKEY) && (mbut == L_MOUSE)) { + retval = gpencil_paint(mbut, GP_PAINTMODE_DRAW); + } + else if (G.qual == LR_ALTKEY) { + if ((U.flag & USER_LMOUSESELECT) && (mbut == L_MOUSE)) + retval = gpencil_paint(mbut, GP_PAINTMODE_ERASER); + else if (!(U.flag & USER_LMOUSESELECT) && (mbut == R_MOUSE)) + retval = gpencil_paint(mbut, GP_PAINTMODE_ERASER); + } } /* return result of trying to paint */ diff --git a/source/blender/src/header_info.c b/source/blender/src/header_info.c index dac7c7bc2c6..a9280d9dd19 100644 --- a/source/blender/src/header_info.c +++ b/source/blender/src/header_info.c @@ -540,6 +540,42 @@ static void check_packAll() } } +#ifdef _WIN32 +static void copy_game_dll(char *dll_filename, char *source_dir, char *dest_dir) +{ + char source_filename[FILE_MAX]; + char dest_filename[FILE_MAX]; + + strcpy( source_filename, source_dir ); + strcat( source_filename, dll_filename ); + + strcpy( dest_filename, dest_dir ); + strcat( dest_filename, dll_filename ); + + if(!BLI_exists(dest_filename)) { + BLI_copy_fileops( source_filename, dest_filename ); + } +} + +static void copy_all_game_dlls(char *str) +{ +#define GAME_DLL_COUNT 7 + char *game_dll_list[GAME_DLL_COUNT]={"gnu_gettext.dll", "libpng.dll", "libtiff.dll", "pthreadVC2.dll", "python25.dll", "SDL.dll", "zlib.dll"}; + + char dest_dir[FILE_MAX]; + char source_dir[FILE_MAX]; + int i; + + strcpy(source_dir, get_install_dir()); + strcat(source_dir, "\\"); + BLI_split_dirfile_basic(str, dest_dir, NULL); + + for (i= 0; i< GAME_DLL_COUNT; i++) { + copy_game_dll(game_dll_list[i], source_dir, dest_dir ); + }; +} +#endif + static int write_runtime(char *str, char *exename) { char *freestr= NULL; @@ -587,7 +623,14 @@ static void write_runtime_check(char *str) #endif write_runtime(str, player); + +#ifdef _WIN32 + // get a list of the .DLLs in the Blender folder and copy all of these to the destination folder if they don't exist + copy_all_game_dlls(str); +#endif } + + /* end keyed functions */ /************************** MAIN MENU *****************************/ @@ -1026,7 +1069,7 @@ static uiBlock *info_externalfiles(void *arg_unused) block= uiNewBlock(&curarea->uiblocks, "info_externalfiles", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin); uiBlockSetButmFunc(block, do_info_externalfiles, NULL); - uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Pack into Blend", 0, yco-=20, 160, 19, NULL, 0.0, 0.0, 1, 1, ""); + uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Pack into .blend file", 0, yco-=20, 160, 19, NULL, 0.0, 0.0, 1, 1, ""); #if 0 uiDefBut(block, BUTM, 1, "Unpack Data to current dir", 0, yco-=20, 160, 19, NULL, 0.0, 0.0, 1, 2, "Removes all packed files from the project and saves them to the current directory"); #endif @@ -1036,8 +1079,8 @@ static uiBlock *info_externalfiles(void *arg_unused) uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Make all Paths Relative", 0, yco-=20, 160, 19, NULL, 0.0, 0.0, 1, 10, ""); uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Make all Paths Absolute", 0, yco-=20, 160, 19, NULL, 0.0, 0.0, 1, 11, ""); - uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Report Missing Files", 0, yco-=20, 160, 19, NULL, 0.0, 0.0, 1, 12, ""); - uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Find Missing Files", 0, yco-=20, 160, 19, NULL, 0.0, 0.0, 1, 13, ""); + uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Report Missing Files...", 0, yco-=20, 160, 19, NULL, 0.0, 0.0, 1, 12, ""); + uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Find Missing Files...", 0, yco-=20, 160, 19, NULL, 0.0, 0.0, 1, 13, ""); uiBlockSetDirection(block, UI_RIGHT); uiTextBoundsBlock(block, 60); @@ -1078,9 +1121,9 @@ static uiBlock *info_filemenu(void *arg_unused) uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Screenshot Subwindow|Ctrl F3", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 24, ""); uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Screenshot All|Ctrl Shift F3", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 25, ""); #if GAMEBLENDER == 1 - uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Save Runtime...", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 22, ""); + uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Save Game As Runtime...", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 22, ""); #ifdef _WIN32 - uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Save Dynamic Runtime...", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 23, ""); +// uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Save Dynamic Runtime...", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 23, ""); #endif #endif uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, ""); diff --git a/source/blender/src/header_ipo.c b/source/blender/src/header_ipo.c index 15caf325ec6..59d542e72ec 100644 --- a/source/blender/src/header_ipo.c +++ b/source/blender/src/header_ipo.c @@ -970,7 +970,7 @@ static char *ipo_modeselect_pup(void) if(ob && ob->type==OB_LAMP) str += sprintf(str,formatstring, "Lamp",ID_LA, ICON_LAMP); - if(ob && give_current_texture(ob, ob->actcol)) + if((ob && give_current_texture(ob, ob->actcol))||(give_current_world_texture())) str += sprintf(str,formatstring, "Texture",ID_TE, ICON_TEXTURE); if(ob){ diff --git a/source/blender/src/header_view3d.c b/source/blender/src/header_view3d.c index 2b8da83dc1d..1b0500b15b3 100644 --- a/source/blender/src/header_view3d.c +++ b/source/blender/src/header_view3d.c @@ -165,9 +165,9 @@ void do_layer_buttons(short event) if(event==-1 && (G.qual & LR_CTRLKEY)) { G.vd->scenelock= !G.vd->scenelock; do_view3d_buttons(B_SCENELOCK); - } else if (event==-1) { + } else if (event<0) { if(G.vd->lay== (1<<20)-1) { - if(G.qual & LR_SHIFTKEY) G.vd->lay= oldlay; + if(event==-2 || G.qual & LR_SHIFTKEY) G.vd->lay= oldlay; } else { oldlay= G.vd->lay; @@ -604,6 +604,9 @@ static void do_view3d_viewmenu(void *arg, int event) case 21: /* Grease Pencil */ add_blockhandler(curarea, VIEW3D_HANDLER_GREASEPENCIL, UI_PNL_UNSTOW); break; + case 22: /* View all layers */ + do_layer_buttons(-2); + break; } allqueue(REDRAWVIEW3D, 1); } @@ -647,6 +650,11 @@ static uiBlock *view3d_viewmenu(void *arg_unused) uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, ""); + if(G.vd->lay== (1<<20)-1) uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Show Previous Layers|Shift ~", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 22, ""); + else uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Show All Layers| ~", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 22, ""); + + uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, ""); + if(G.vd->localview) uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Local View|NumPad /", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 7, ""); else uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "Local View|NumPad /", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 7, ""); if(!G.vd->localview) uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Global View|NumPad /", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 8, ""); @@ -725,6 +733,9 @@ void do_view3d_select_object_typemenu(void *arg, int event) case 10: /* Lamp */ selectall_type(OB_LAMP); break; + case 20: + do_layer_buttons(-2); + break; } allqueue(REDRAWVIEW3D, 0); } @@ -1313,12 +1324,21 @@ static void do_view3d_select_armaturemenu(void *arg, int event) case 2: /* Select/Deselect all */ deselectall_armature(1, 1); break; - case 3: /* Select Parent(s) */ - select_bone_parent(); - break; - case 4: /* Swap Select All */ + case 3: /* Swap Select All */ deselectall_armature(3, 1); break; + case 4: /* Select parent */ + armature_select_hierarchy(BONE_SELECT_PARENT, 0); + break; + case 5: /* Select child */ + armature_select_hierarchy(BONE_SELECT_CHILD, 0); + break; + case 6: /* Extend Select parent */ + armature_select_hierarchy(BONE_SELECT_PARENT, 1); + break; + case 7: /* Extend Select child */ + armature_select_hierarchy(BONE_SELECT_CHILD, 1); + break; } allqueue(REDRAWVIEW3D, 0); } @@ -1336,11 +1356,18 @@ static uiBlock *view3d_select_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, "Select/Deselect All|A", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, ""); + uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Inverse|Ctrl I", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 3, ""); + + uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, ""); - uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Swap Select All|Ctrl I", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 4, ""); + uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Select Parent|[", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 4, ""); + uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Select Child|]", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 5, ""); + + uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, ""); + + uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Extend Select Parent|Shift [", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 6, ""); + uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Extend Select Child|Shift ]", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 7, ""); - uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Select Parent(s)|P", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 3, ""); - if(curarea->headertype==HEADERTOP) { uiBlockSetDirection(block, UI_DOWN); } @@ -1367,12 +1394,21 @@ static void do_view3d_select_pose_armaturemenu(void *arg, int event) case 3: /* Select Target(s) of Constraint(s) */ pose_select_constraint_target(); break; - case 4: /* Select Bone's Parent */ - select_bone_parent(); - break; case 5: /* Swap Select All */ deselectall_posearmature(OBACT, 3, 1); break; + case 6: /* Select parent */ + pose_select_hierarchy(BONE_SELECT_PARENT, 0); + break; + case 7: /* Select child */ + pose_select_hierarchy(BONE_SELECT_CHILD, 0); + break; + case 8: /* Extend Select parent */ + pose_select_hierarchy(BONE_SELECT_PARENT, 1); + break; + case 9: /* Extend Select child */ + pose_select_hierarchy(BONE_SELECT_CHILD, 1); + break; } allqueue(REDRAWVIEW3D, 0); } @@ -1392,8 +1428,17 @@ static uiBlock *view3d_select_pose_armaturemenu(void *arg_unused) uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Select/Deselect All|A", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, ""); uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Swap Select All|Ctrl I", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 5, ""); uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Select Constraint Target|W", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 3, ""); - uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Select Parent(s)|P", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 4, ""); - + + uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, ""); + + uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Select Parent|[", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 6, ""); + uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Select Child|]", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 7, ""); + + uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, ""); + + uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Extend Select Parent|Shift [", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 8, ""); + uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Extend Select Child|Shift ]", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 9, ""); + if(curarea->headertype==HEADERTOP) { uiBlockSetDirection(block, UI_DOWN); } @@ -2195,6 +2240,7 @@ static uiBlock *view3d_edit_object_copyattrmenu(void *arg_unused) uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Mass|Ctrl C, 7", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 7, ""); uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Damping|Ctrl C, 8", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 8, ""); + uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "All Physical Attributes|Ctrl C, 11", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 11, ""); uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Properties|Ctrl C, 9", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 9, ""); uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Logic Bricks|Ctrl C, 10", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 10, ""); uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Protected Transform |Ctrl C", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 29, ""); @@ -2465,8 +2511,11 @@ static void do_view3d_edit_objectmenu(void *arg, int event) case 15: /* Object Panel */ add_blockhandler(curarea, VIEW3D_HANDLER_OBJECT, UI_PNL_UNSTOW); break; + case 16: /* make proxy object*/ + make_proxy(); + break; #ifdef WITH_VERSE - case 16: /* Share Object at Verse server */ + case 17: /* Share Object at Verse server */ if(session_list.first != session_list.last) session = session_menu(); else session = session_list.first; if(session) b_verse_push_object(session, ob); @@ -2491,7 +2540,7 @@ static uiBlock *view3d_edit_objectmenu(void *arg_unused) if (base) ob= base->object; if(ob && (ob->type == OB_MESH) && (!ob->vnode)) { - uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Share at Verse Server", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 16, ""); + uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Share at Verse Server", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 17, ""); uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, ""); } } @@ -2517,6 +2566,7 @@ static uiBlock *view3d_edit_objectmenu(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, "Make Proxy|Ctrl Alt P", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 16, ""); uiDefIconTextBlockBut(block, view3d_edit_object_makelinksmenu, NULL, ICON_RIGHTARROW_THIN, "Make Links", 0, yco-=20, 120, 19, ""); uiDefIconTextBlockBut(block, view3d_edit_object_singleusermenu, NULL, ICON_RIGHTARROW_THIN, "Make Single User", 0, yco-=20, 120, 19, ""); uiDefIconTextBlockBut(block, view3d_edit_object_makelocalmenu, NULL, ICON_RIGHTARROW_THIN, "Make Local", 0, yco-=20, 120, 19, ""); @@ -5084,7 +5134,7 @@ static char *snapmode_pup(void) static char string[512]; char *str = string; - str += sprintf(str, "%s", "Snap Mode: %t"); + str += sprintf(str, "%s", "Snap Element: %t"); str += sprintf(str, "%s", "|Vertex%x0"); str += sprintf(str, "%s", "|Edge%x1"); str += sprintf(str, "%s", "|Face%x2"); @@ -5722,7 +5772,7 @@ void view3d_buttons(void) xco+= XIC; uiDefIconTextButS(block, ICONTEXTROW,B_REDR, ICON_VERTEXSEL, snapmode_pup(), xco,0,XIC+10,YIC, &(G.scene->snap_mode), 0.0, 0.0, 0, 0, "Snapping mode"); xco+= XIC; - uiDefButS(block, MENU, B_NOP, "Mode%t|Closest%x0|Center%x1|Median%x2|Active%x3",xco,0,70,YIC, &G.scene->snap_target, 0, 0, 0, 0, "Snap Target Mode"); + uiDefButS(block, MENU, B_NOP, "Snap Mode%t|Closest%x0|Center%x1|Median%x2|Active%x3",xco,0,70,YIC, &G.scene->snap_target, 0, 0, 0, 0, "Snap Target Mode"); xco+= 70; } else { uiDefIconButBitS(block, TOG, SCE_SNAP, B_REDR, ICON_SNAP_GEAR,xco,0,XIC,YIC, &G.scene->snap_flag, 0, 0, 0, 0, "Snap while Ctrl is held during transform (Shift Tab)"); diff --git a/source/blender/src/meshlaplacian.c b/source/blender/src/meshlaplacian.c index 4d84672185a..60f569ecf0e 100644 --- a/source/blender/src/meshlaplacian.c +++ b/source/blender/src/meshlaplacian.c @@ -1281,9 +1281,9 @@ static int meshdeform_inside_cage(MeshDeformBind *mdb, float *co) outside[1] = co[1] + (mdb->max[1] - mdb->min[1] + 1.0f)*MESHDEFORM_OFFSET[i][1]; outside[2] = co[2] + (mdb->max[2] - mdb->min[2] + 1.0f)*MESHDEFORM_OFFSET[i][2]; + VECCOPY(start, co); VECSUB(dir, outside, start); Normalize(dir); - VECCOPY(start, co); isect = meshdeform_ray_tree_intersect(mdb, start, outside); if(isect && !isect->facing) diff --git a/source/blender/src/outliner.c b/source/blender/src/outliner.c index a8e864998b1..3f328a0cfb2 100644 --- a/source/blender/src/outliner.c +++ b/source/blender/src/outliner.c @@ -3718,13 +3718,6 @@ static void outliner_draw_restrictbuts(uiBlock *block, SpaceOops *soops, ListBas uiButSetFunc(bt, restrictbutton_modifier_cb, ob, NULL); uiButSetFlag(bt, UI_NO_HILITE); - /* - bt= uiDefIconButBitI(block, ICONTOGN, eModifierMode_Editmode, REDRAWALL, VICON_EDIT, - (int)soops->v2d.cur.xmax-OL_TOG_RESTRICT_SELECTX, te->ys, 17, OL_H-1, &(md->mode), 0, 0, 0, 0, "Restrict/Allow selection in the 3D View"); - uiButSetFunc(bt, restrictbutton_modifier_cb, ob, NULL); - uiButSetFlag(bt, UI_NO_HILITE); - */ - bt= uiDefIconButBitI(block, ICONTOGN, eModifierMode_Render, REDRAWALL, ICON_RESTRICT_RENDER_OFF, (int)soops->v2d.cur.xmax-OL_TOG_RESTRICT_RENDERX, te->ys, 17, OL_H-1, &(md->mode), 0, 0, 0, 0, "Restrict/Allow renderability"); uiButSetFunc(bt, restrictbutton_modifier_cb, ob, NULL); @@ -3733,24 +3726,20 @@ static void outliner_draw_restrictbuts(uiBlock *block, SpaceOops *soops, ListBas else if(tselem->type==TSE_POSE_CHANNEL) { bPoseChannel *pchan= (bPoseChannel *)te->directdata; Bone *bone = pchan->bone; - - ob = (Object *)tselem->id; - + uiBlockSetEmboss(block, UI_EMBOSSN); bt= uiDefIconButBitI(block, ICONTOG, BONE_HIDDEN_P, REDRAWALL, ICON_RESTRICT_VIEW_OFF, (int)soops->v2d.cur.xmax-OL_TOG_RESTRICT_VIEWX, te->ys, 17, OL_H-1, &(bone->flag), 0, 0, 0, 0, "Restrict/Allow visibility in the 3D View"); - uiButSetFunc(bt, restrictbutton_bone_cb, ob, NULL); + uiButSetFunc(bt, restrictbutton_bone_cb, NULL, NULL); uiButSetFlag(bt, UI_NO_HILITE); } else if(tselem->type==TSE_EBONE) { EditBone *ebone= (EditBone *)te->directdata; - - ob = (Object *)tselem->id; - + uiBlockSetEmboss(block, UI_EMBOSSN); bt= uiDefIconButBitI(block, ICONTOG, BONE_HIDDEN_A, REDRAWALL, ICON_RESTRICT_VIEW_OFF, (int)soops->v2d.cur.xmax-OL_TOG_RESTRICT_VIEWX, te->ys, 17, OL_H-1, &(ebone->flag), 0, 0, 0, 0, "Restrict/Allow visibility in the 3D View"); - uiButSetFunc(bt, restrictbutton_bone_cb, ob, NULL); + uiButSetFunc(bt, restrictbutton_bone_cb, NULL, NULL); uiButSetFlag(bt, UI_NO_HILITE); } } diff --git a/source/blender/src/poselib.c b/source/blender/src/poselib.c index fb2bfe5b605..6aeef7c75c2 100644 --- a/source/blender/src/poselib.c +++ b/source/blender/src/poselib.c @@ -312,7 +312,7 @@ void poselib_add_current_pose (Object *ob, int val) /* mode - add new or replace existing */ if (val == 0) { if ((ob->poselib) && (ob->poselib->markers.first)) { - val= pupmenu("PoseLib Add Current Pose%t|Add New%x1|Replace Existing%x2"); + val= pupmenu("PoseLib Add Current Pose%t|Add New%x1|Add New (Current Frame)%x3|Replace Existing%x2"); if (val <= 0) return; } else @@ -347,7 +347,10 @@ void poselib_add_current_pose (Object *ob, int val) act= poselib_validate(ob); /* get frame */ - frame= poselib_get_free_index(act); + if (val == 3) + frame= CFRA; + else /* if (val == 1) */ + frame= poselib_get_free_index(act); /* add pose to poselib - replaces any existing pose there */ for (marker= act->markers.first; marker; marker= marker->next) { diff --git a/source/blender/src/poseobject.c b/source/blender/src/poseobject.c index b054b435002..28b8729a247 100644 --- a/source/blender/src/poseobject.c +++ b/source/blender/src/poseobject.c @@ -479,6 +479,67 @@ void pose_select_constraint_target(void) } +void pose_select_hierarchy(short direction, short add_to_sel) +{ + Object *ob= OBACT; + bArmature *arm= ob->data; + bPoseChannel *pchan; + Bone *curbone, *pabone, *chbone; + + /* paranoia checks */ + if (!ob && !ob->pose) return; + if (ob==G.obedit || (ob->flag & OB_POSEMODE)==0) return; + + for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) { + curbone= pchan->bone; + + if (arm->layer & curbone->layer) { + if (curbone->flag & (BONE_ACTIVE)) { + if (direction == BONE_SELECT_PARENT) { + + if (pchan->parent == NULL) continue; + else pabone= pchan->parent->bone; + + if ((arm->layer & pabone->layer) && !(pabone->flag & BONE_HIDDEN_P)) { + + if (!add_to_sel) curbone->flag &= ~BONE_SELECTED; + curbone->flag &= ~BONE_ACTIVE; + pabone->flag |= (BONE_ACTIVE|BONE_SELECTED); + + select_actionchannel_by_name (ob->action, pchan->name, 0); + select_actionchannel_by_name (ob->action, pchan->parent->name, 1); + break; + } + } else { // BONE_SELECT_CHILD + + if (pchan->child == NULL) continue; + else chbone = pchan->child->bone; + + if ((arm->layer & chbone->layer) && !(chbone->flag & BONE_HIDDEN_P)) { + + if (!add_to_sel) curbone->flag &= ~BONE_SELECTED; + curbone->flag &= ~BONE_ACTIVE; + chbone->flag |= (BONE_ACTIVE|BONE_SELECTED); + + select_actionchannel_by_name (ob->action, pchan->name, 0); + select_actionchannel_by_name (ob->action, pchan->child->name, 1); + break; + } + } + } + } + } + + allqueue (REDRAWVIEW3D, 0); + allqueue (REDRAWBUTSOBJECT, 0); + allqueue (REDRAWOOPS, 0); + + if (direction==BONE_SELECT_PARENT) + BIF_undo_push("Select pose bone parent"); + if (direction==BONE_SELECT_CHILD) + BIF_undo_push("Select pose bone child"); +} + /* context: active channel */ void pose_special_editmenu(void) { diff --git a/source/blender/src/space.c b/source/blender/src/space.c index 400509012c6..b7e80e6eb68 100644 --- a/source/blender/src/space.c +++ b/source/blender/src/space.c @@ -2420,7 +2420,7 @@ static void winqreadview3dspace(ScrArea *sa, void *spacedata, BWinEvent *evt) else if(G.qual==LR_ALTKEY && G.obedit->type==OB_ARMATURE) clear_bone_parent(); else if((G.qual==0) && (G.obedit->type==OB_ARMATURE)) - select_bone_parent(); + armature_select_hierarchy(BONE_SELECT_PARENT, 1); // 1 = add to selection else if((G.qual==(LR_CTRLKEY|LR_ALTKEY)) && (G.obedit->type==OB_ARMATURE)) separate_armature(); else if((G.qual==0) && G.obedit->type==OB_MESH) @@ -2450,7 +2450,7 @@ static void winqreadview3dspace(ScrArea *sa, void *spacedata, BWinEvent *evt) start_RBSimulation(); } else if((G.qual==0) && (OBACT) && (OBACT->type==OB_ARMATURE) && (OBACT->flag & OB_POSEMODE)) - select_bone_parent(); + pose_select_hierarchy(BONE_SELECT_PARENT, 1); // 1 = add to selection else if((G.qual==0)) { start_game(); } @@ -2753,6 +2753,19 @@ static void winqreadview3dspace(ScrArea *sa, void *spacedata, BWinEvent *evt) scrarea_queue_winredraw(curarea); break; + case LEFTBRACKETKEY: + if ((G.obedit) && (G.obedit->type == OB_ARMATURE)) + armature_select_hierarchy(BONE_SELECT_PARENT, (G.qual == LR_SHIFTKEY)); + else if ((ob) && (ob->flag & OB_POSEMODE)) + pose_select_hierarchy(BONE_SELECT_PARENT, (G.qual == LR_SHIFTKEY)); + break; + case RIGHTBRACKETKEY: + if ((G.obedit) && (G.obedit->type == OB_ARMATURE)) + armature_select_hierarchy(BONE_SELECT_CHILD, (G.qual == LR_SHIFTKEY)); + if ((ob) && (ob->flag & OB_POSEMODE)) + pose_select_hierarchy(BONE_SELECT_CHILD, (G.qual == LR_SHIFTKEY)); + break; + case PADSLASHKEY: if(G.qual==0) { if(G.vd->localview) { @@ -5111,7 +5124,10 @@ static void winqreadseqspace(ScrArea *sa, void *spacedata, BWinEvent *evt) } } - if(doredraw) scrarea_queue_winredraw(curarea); + if(doredraw) { + scrarea_queue_winredraw(curarea); + scrarea_queue_headredraw(curarea); + } } diff --git a/source/blender/src/toolbox.c b/source/blender/src/toolbox.c index 94d38ee1635..8a8d7c8cec7 100644 --- a/source/blender/src/toolbox.c +++ b/source/blender/src/toolbox.c @@ -125,8 +125,6 @@ void asciitoraw(int ch, unsigned short *event, unsigned short *qual) { - if( isalpha(ch)==0 ) return; - if( isupper(ch) ) { *qual= LEFTSHIFTKEY; ch= tolower(ch); @@ -804,7 +802,10 @@ static void tb_do_hotkey(void *arg, int event) case 'd': key= PAGEDOWNKEY; break; } } - else asciitoraw(event, &key, &qual[3]); + else if (isalpha(event)) + asciitoraw(event, &key, &qual[3]); + else if (event == '~') + key = ACCENTGRAVEKEY; for (i=0;i<4;i++) { @@ -1213,6 +1214,8 @@ static TBitem tb_view[]= { { 0, "Ortho/Perspective|NumPad 5", TB_PAD|'5', NULL}, { 0, "Local/Global View|NumPad /", TB_PAD|'/', NULL}, { 0, "SEPR", 0, NULL}, +{ 0, "Show All Layers|Shift ~", TB_SHIFT|'~', NULL}, +{ 0, "SEPR", 0, NULL}, { 0, "Align View", 0, tb_view_alignview}, { 0, "SEPR", 0, NULL}, { 0, "View Selected|NumPad .", TB_PAD|'.', NULL}, diff --git a/source/blender/src/transform_conversions.c b/source/blender/src/transform_conversions.c index 8f83434e528..9f2f58d0cdb 100644 --- a/source/blender/src/transform_conversions.c +++ b/source/blender/src/transform_conversions.c @@ -913,8 +913,8 @@ static void createTransPose(TransInfo *t, Object *ob) if (arm==NULL || ob->pose==NULL) return; if (arm->flag & ARM_RESTPOS) { - if(t->mode!=TFM_BONESIZE) { - notice ("Pose edit not possible while Rest Position is enabled"); + if(ELEM(t->mode, TFM_DUMMY, TFM_BONESIZE)==0) { + notice("Pose edit not possible while Rest Position is enabled"); return; } } diff --git a/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp b/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp index b3a3a47152a..7de3056e382 100644 --- a/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp +++ b/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp @@ -335,7 +335,7 @@ extern "C" void StartKetsjiShell(struct ScrArea *area, PyDict_SetItemString(dictionaryobject, "GameLogic", gameLogic); // Same as importing the module. initGameKeys(); initPythonConstraintBinding(); - + initMathutils(); if (sceneconverter) { @@ -602,6 +602,7 @@ extern "C" void StartKetsjiShellSimulation(struct ScrArea *area, PyDict_SetItemString(dictionaryobject, "GameLogic", gameLogic); // Same as importing the module initGameKeys(); initPythonConstraintBinding(); + initMathutils(); if (sceneconverter) { diff --git a/source/gameengine/BlenderRoutines/KX_BlenderGL.cpp b/source/gameengine/BlenderRoutines/KX_BlenderGL.cpp index ed6ea7c5f6a..da52be56d1b 100644 --- a/source/gameengine/BlenderRoutines/KX_BlenderGL.cpp +++ b/source/gameengine/BlenderRoutines/KX_BlenderGL.cpp @@ -170,6 +170,7 @@ void BL_RenderText(int mode,const char* textstr,int textlen,struct MTFace* tface void DisableForText() { if(glIsEnabled(GL_BLEND)) glDisable(GL_BLEND); + if(glIsEnabled(GL_ALPHA_TEST)) glDisable(GL_ALPHA_TEST); if(glIsEnabled(GL_LIGHTING)) { glDisable(GL_LIGHTING); diff --git a/source/gameengine/BlenderRoutines/KX_BlenderPolyMaterial.cpp b/source/gameengine/BlenderRoutines/KX_BlenderPolyMaterial.cpp deleted file mode 100644 index d173b1c66d9..00000000000 --- a/source/gameengine/BlenderRoutines/KX_BlenderPolyMaterial.cpp +++ /dev/null @@ -1,114 +0,0 @@ -/** - * $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 ***** - */ - -#include "KX_BlenderPolyMaterial.h" -#include "BKE_mesh.h" - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif -#if 0 -KX_BlenderPolyMaterial::KX_BlenderPolyMaterial(const STR_String &texname, - bool ba, - const STR_String& matname, - int tile, - int tilexrep, - int tileyrep, - int mode, - bool transparant, - bool zsort, - int lightlayer, - bool bIsTriangle, - void* clientobject, - struct MTFace* tface) - : RAS_IPolyMaterial(texname, - false, - matname, - tile, - tilexrep, - tileyrep, - mode, - transparant, - zsort, - lightlayer, - bIsTriangle, - clientobject), - m_tface(tface) -{ -} - -void KX_BlenderPolyMaterial::Activate(RAS_IRasterizer* rasty, TCachingInfo& cachingInfo) const -{ - - - if (GetCachingInfo() != cachingInfo) - { - if (!cachingInfo) - { - set_tpage(NULL); - } - cachingInfo = GetCachingInfo(); - - if ((m_drawingmode & 4)&& (rasty->GetDrawingMode() == RAS_IRasterizer::KX_TEXTURED)) - { - update_realtime_texture((struct MTFace*) m_tface, rasty->GetTime()); - set_tpage(m_tface); - rasty->EnableTextures(true); - } - else - { - set_tpage(NULL); - rasty->EnableTextures(false); - } - - if(m_drawingmode & RAS_IRasterizer::KX_TWOSIDE) - { - rasty->SetCullFace(false); - } - else - { - rasty->SetCullFace(true); - } - - if (m_drawingmode & RAS_IRasterizer::KX_LINES) { - rasty->SetLines(true); - } - else { - rasty->SetLines(false); - } - } - - rasty->SetSpecularity(m_specular[0],m_specular[1],m_specular[2],m_specularity); - rasty->SetShinyness(m_shininess); - rasty->SetDiffuse(m_diffuse[0], m_diffuse[1],m_diffuse[2], 1.0); -} - - -#endif - - diff --git a/source/gameengine/BlenderRoutines/KX_BlenderPolyMaterial.h b/source/gameengine/BlenderRoutines/KX_BlenderPolyMaterial.h deleted file mode 100644 index 35823b2125b..00000000000 --- a/source/gameengine/BlenderRoutines/KX_BlenderPolyMaterial.h +++ /dev/null @@ -1,99 +0,0 @@ -/** - * $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_BLENDERPOLYMATERIAL -#define __KX_BLENDERPOLYMATERIAL - -#include "RAS_MaterialBucket.h" -#include "RAS_IRasterizer.h" - -struct MTFace; -extern "C" int set_tpage(MTFace* tface); /* Worst hack ever */ - -#if 0 -class KX_BlenderPolyMaterial : public RAS_IPolyMaterial -{ - /** Blender texture face structure. */ - MTFace* m_tface; - -public: - - KX_BlenderPolyMaterial(const STR_String &texname, - bool ba, - const STR_String& matname, - int tile, - int tilexrep, - int tileyrep, - int mode, - bool transparant, - bool zsort, - int lightlayer, - bool bIsTriangle, - void* clientobject, - struct MTFace* tface); - - /** - * Returns the caching information for this material, - * This can be used to speed up the rasterizing process. - * @return The caching information. - */ - virtual TCachingInfo GetCachingInfo(void) const; - - /** - * Activates the material in the (OpenGL) rasterizer. - * On entry, the cachingInfo contains info about the last activated material. - * On exit, the cachingInfo should contain updated info about this material. - * @param rasty The rasterizer in which the material should be active. - * @param cachingInfo The information about the material used to speed up rasterizing. - */ - virtual void Activate(RAS_IRasterizer* rasty, TCachingInfo& cachingInfo) const; - - /** - * Returns the Blender texture face structure that is used for this material. - * @return The material's texture face. - */ - MTFace* GetMTFace(void) const; -protected: -private: -}; - - -inline MTFace* KX_BlenderPolyMaterial::GetMTFace(void) const -{ - return m_tface; -} - -inline RAS_IPolyMaterial::TCachingInfo KX_BlenderPolyMaterial::GetCachingInfo(void) const -{ - return GetMTFace(); -} - -#endif - -#endif // __KX_BLENDERPOLYMATERIAL - diff --git a/source/gameengine/BlenderRoutines/KX_BlenderRenderTools.cpp b/source/gameengine/BlenderRoutines/KX_BlenderRenderTools.cpp index 220d174d464..e4eff163d5b 100644 --- a/source/gameengine/BlenderRoutines/KX_BlenderRenderTools.cpp +++ b/source/gameengine/BlenderRoutines/KX_BlenderRenderTools.cpp @@ -40,7 +40,6 @@ // it needs the gameobject and the sumo physics scene for a raycast #include "KX_GameObject.h" -#include "KX_BlenderPolyMaterial.h" #include "KX_PolygonMaterial.h" #include "KX_BlenderMaterial.h" diff --git a/source/gameengine/Converter/BL_ActionActuator.cpp b/source/gameengine/Converter/BL_ActionActuator.cpp index 5d6dd694765..2ee8b54a014 100644 --- a/source/gameengine/Converter/BL_ActionActuator.cpp +++ b/source/gameengine/Converter/BL_ActionActuator.cpp @@ -57,24 +57,12 @@ BL_ActionActuator::~BL_ActionActuator() { - - if (m_pose) { - free_pose_channels(m_pose); - MEM_freeN(m_pose); - m_pose = NULL; - }; - - if (m_userpose){ - free_pose_channels(m_userpose); - MEM_freeN(m_userpose); - m_userpose=NULL; - } - if (m_blendpose) { - free_pose_channels(m_blendpose); - MEM_freeN(m_blendpose); - m_blendpose = NULL; - }; - + if (m_pose) + free_pose(m_pose); + if (m_userpose) + free_pose(m_userpose); + if (m_blendpose) + free_pose(m_blendpose); } void BL_ActionActuator::ProcessReplica(){ diff --git a/source/gameengine/Converter/BL_ArmatureObject.cpp b/source/gameengine/Converter/BL_ArmatureObject.cpp index f73d5b42a01..09f1d9d4d87 100644 --- a/source/gameengine/Converter/BL_ArmatureObject.cpp +++ b/source/gameengine/Converter/BL_ArmatureObject.cpp @@ -82,10 +82,8 @@ void BL_ArmatureObject::ProcessReplica(BL_ArmatureObject *replica) BL_ArmatureObject::~BL_ArmatureObject() { - if (m_mrdPose){ - free_pose_channels(m_mrdPose); - MEM_freeN(m_mrdPose); - } + if (m_mrdPose) + free_pose(m_mrdPose); } /* note, you can only call this for exisiting Armature objects, and not mix it with other Armatures */ @@ -172,12 +170,13 @@ void BL_ArmatureObject::GetMRDPose(bPose **pose) // copy_pose (&m_mrdPose, m_pose, 0); //} - if (!*pose) + if (!*pose) { // must duplicate the constraints too otherwise we have corruption in free_pose_channels() // because it will free the blender constraints. // Ideally, blender should rememeber that the constraints were not copied so that // free_pose_channels() would not free them. copy_pose(pose, m_objArma->pose, 1); + } else extract_pose_from_pose(*pose, m_objArma->pose); diff --git a/source/gameengine/Converter/BL_BlenderDataConversion.cpp b/source/gameengine/Converter/BL_BlenderDataConversion.cpp index 31a055fc734..a6337403cd1 100644 --- a/source/gameengine/Converter/BL_BlenderDataConversion.cpp +++ b/source/gameengine/Converter/BL_BlenderDataConversion.cpp @@ -136,8 +136,12 @@ #include "BKE_mesh.h" #include "MT_Point3.h" +#include "BLI_arithb.h" + extern "C" { - #include "BKE_customdata.h" +#include "BKE_customdata.h" +#include "BKE_cdderivedmesh.h" +#include "BKE_DerivedMesh.h" } #include "BKE_material.h" /* give_current_material */ @@ -309,7 +313,6 @@ typedef struct MTF_localLayer // ------------------------------------ BL_Material* ConvertMaterial( - Mesh* mesh, Material *mat, MTFace* tface, const char *tfaceName, @@ -323,15 +326,16 @@ BL_Material* ConvertMaterial( //this needs some type of manager BL_Material *material = new BL_Material(); - int numchan = -1; + int numchan = -1, texalpha = 0; bool validmat = (mat!=0); - bool validface = (mesh->mtface && tface); + bool validface = (tface!=0); short type = 0; if( validmat ) type = 1; // material color material->IdMode = DEFAULT_BLENDER; + material->glslmat = (validmat)? glslmat: false; // -------------------------------- if(validmat) { @@ -367,12 +371,13 @@ BL_Material* ConvertMaterial( if(i==0 && facetex ) { Image*tmp = (Image*)(tface->tpage); + if(tmp) { material->img[i] = tmp; material->texname[i] = material->img[i]->id.name; material->flag[i] |= ( tface->transp &TF_ALPHA )?USEALPHA:0; material->flag[i] |= ( tface->transp &TF_ADD )?CALCALPHA:0; - material->ras_mode|= ( tface->transp &(TF_ADD | TF_ALPHA))?TRANSP:0; + if(material->img[i]->flag & IMA_REFLECT) material->mapping[i].mapping |= USEREFL; else @@ -430,6 +435,8 @@ BL_Material* ConvertMaterial( material->flag[i] |= ( mttmp->mapto & MAP_ALPHA )?TEXALPHA:0; material->flag[i] |= ( mttmp->texflag& MTEX_NEGATIVE )?TEXNEG:0; + if(!glslmat && (material->flag[i] & TEXALPHA)) + texalpha = 1; } } else if(mttmp->tex->type == TEX_ENVMAP) { @@ -546,17 +553,7 @@ BL_Material* ConvertMaterial( material->ref = mat->ref; material->amb = mat->amb; - // set alpha testing without z-sorting - if( ( validface && (!(tface->transp &~ TF_CLIP))) && mat->mode & MA_ZTRA) { - // sets the RAS_IPolyMaterial::m_flag |RAS_FORCEALPHA - // this is so we don't have the overhead of the z-sorting code - material->ras_mode|=ALPHA_TEST; - } - else{ - // use regular z-sorting - material->ras_mode |= ((mat->mode & MA_ZTRA) != 0)?ZSORT:0; - } - material->ras_mode |= ((mat->mode & MA_WIRE) != 0)?WIRE:0; + material->ras_mode |= (mat->mode & MA_WIRE)? WIRE: 0; } else { int valid = 0; @@ -574,7 +571,6 @@ BL_Material* ConvertMaterial( material->mapping[0].mapping |= ( (material->img[0]->flag & IMA_REFLECT)!=0 )?USEREFL:0; material->flag[0] |= ( tface->transp &TF_ALPHA )?USEALPHA:0; material->flag[0] |= ( tface->transp &TF_ADD )?CALCALPHA:0; - material->ras_mode|= ( tface->transp & (TF_ADD|TF_ALPHA))?TRANSP:0; valid++; } } @@ -607,10 +603,6 @@ BL_Material* ConvertMaterial( material->ras_mode |= ( (tface->mode & TF_DYNAMIC)!= 0 )?COLLIDER:0; material->transp = tface->transp; - - if(tface->transp&~TF_CLIP) - material->ras_mode |= TRANSP; - material->tile = tface->tile; material->mode = tface->mode; @@ -631,7 +623,16 @@ BL_Material* ConvertMaterial( material->tile = 0; } + // with ztransp enabled, enforce alpha blending mode + if(validmat && (mat->mode & MA_ZTRA) && (material->transp == TF_SOLID)) + material->transp = TF_ALPHA; + // always zsort alpha + add + if((material->transp == TF_ALPHA || material->transp == TF_ADD || texalpha) + && (material->transp != TF_CLIP)) { + material->ras_mode |= ALPHA; + material->ras_mode |= (material->mode & TF_ALPHASORT)? ZSORT: 0; + } // get uv sets if(validmat) @@ -711,132 +712,54 @@ BL_Material* ConvertMaterial( } -static void BL_ComputeTriTangentSpace(const MT_Vector3 &v1, const MT_Vector3 &v2, const MT_Vector3 &v3, - const MT_Vector2 &uv1, const MT_Vector2 &uv2, const MT_Vector2 &uv3, - MFace* mface, MT_Vector3 *tan1, MT_Vector3 *tan2) -{ - MT_Vector3 dx1(v2 - v1), dx2(v3 - v1); - MT_Vector2 duv1(uv2 - uv1), duv2(uv3 - uv1); - - MT_Scalar r = 1.0 / (duv1.x() * duv2.y() - duv2.x() * duv1.y()); - duv1 *= r; - duv2 *= r; - MT_Vector3 sdir(duv2.y() * dx1 - duv1.y() * dx2); - MT_Vector3 tdir(duv1.x() * dx2 - duv2.x() * dx1); - - tan1[mface->v1] += sdir; - tan1[mface->v2] += sdir; - tan1[mface->v3] += sdir; - - tan2[mface->v1] += tdir; - tan2[mface->v2] += tdir; - tan2[mface->v3] += tdir; -} - -static MT_Vector4* BL_ComputeMeshTangentSpace(Mesh* mesh) -{ - MFace* mface = static_cast<MFace*>(mesh->mface); - MTFace* tface = static_cast<MTFace*>(mesh->mtface); - - MT_Vector3 *tan1 = new MT_Vector3[mesh->totvert]; - MT_Vector3 *tan2 = new MT_Vector3[mesh->totvert]; - - int v; - for (v = 0; v < mesh->totvert; v++) - { - tan1[v] = MT_Vector3(0.0, 0.0, 0.0); - tan2[v] = MT_Vector3(0.0, 0.0, 0.0); - } - - for (int p = 0; p < mesh->totface; p++, mface++, tface++) - { - MT_Vector3 v1(mesh->mvert[mface->v1].co), - v2(mesh->mvert[mface->v2].co), - v3(mesh->mvert[mface->v3].co); - - MT_Vector2 uv1(tface->uv[0]), - uv2(tface->uv[1]), - uv3(tface->uv[2]); - - BL_ComputeTriTangentSpace(v1, v2, v3, uv1, uv2, uv3, mface, tan1, tan2); - if (mface->v4) - { - MT_Vector3 v4(mesh->mvert[mface->v4].co); - MT_Vector2 uv4(tface->uv[3]); - - BL_ComputeTriTangentSpace(v1, v3, v4, uv1, uv3, uv4, mface, tan1, tan2); - } - } - - MT_Vector4 *tangent = new MT_Vector4[mesh->totvert]; - for (v = 0; v < mesh->totvert; v++) - { - const MT_Vector3 no(mesh->mvert[v].no[0]/32767.0, - mesh->mvert[v].no[1]/32767.0, - mesh->mvert[v].no[2]/32767.0); - // Gram-Schmidt orthogonalize - MT_Vector3 t(tan1[v] - no.cross(no.cross(tan1[v]))); - if (!MT_fuzzyZero(t)) - t /= t.length(); - - tangent[v].x() = t.x(); - tangent[v].y() = t.y(); - tangent[v].z() = t.z(); - // Calculate handedness - tangent[v].w() = no.dot(tan1[v].cross(tan2[v])) < 0.0 ? -1.0 : 1.0; - } - - delete [] tan1; - delete [] tan2; - - return tangent; -} - RAS_MeshObject* BL_ConvertMesh(Mesh* mesh, Object* blenderobj, RAS_IRenderTools* rendertools, KX_Scene* scene, KX_BlenderSceneConverter *converter) { RAS_MeshObject *meshobj; - bool skinMesh = false; - + bool skinMesh = false; int lightlayer = blenderobj->lay; - - MFace* mface = static_cast<MFace*>(mesh->mface); - MTFace* tface = static_cast<MTFace*>(mesh->mtface); + + // Get DerivedMesh data + DerivedMesh *dm = CDDM_from_mesh(mesh, blenderobj); + + MVert *mvert = dm->getVertArray(dm); + int totvert = dm->getNumVerts(dm); + + MFace *mface = dm->getFaceArray(dm); + MTFace *tface = static_cast<MTFace*>(dm->getFaceDataArray(dm, CD_MTFACE)); + MCol *mcol = static_cast<MCol*>(dm->getFaceDataArray(dm, CD_MCOL)); + float (*tangent)[3] = NULL; + int totface = dm->getNumFaces(dm); const char *tfaceName = ""; - MCol* mmcol = mesh->mcol; - MT_assert(mface || mesh->totface == 0); + if(tface) { + DM_add_tangent_layer(dm); + tangent = (float(*)[3])dm->getFaceDataArray(dm, CD_TANGENT); + } // Determine if we need to make a skinned mesh - if (mesh->dvert || mesh->key){ + if (mesh->dvert || mesh->key) { meshobj = new BL_SkinMeshObject(mesh, lightlayer); skinMesh = true; } - else { + else meshobj = new RAS_MeshObject(mesh, lightlayer); - } - MT_Vector4 *tangent = 0; - if (tface) - tangent = BL_ComputeMeshTangentSpace(mesh); - // Extract avaiable layers MTF_localLayer *layers = new MTF_localLayer[MAX_MTFACE]; - for (int lay=0; lay<MAX_MTFACE; lay++) - { + for (int lay=0; lay<MAX_MTFACE; lay++) { layers[lay].face = 0; layers[lay].name = ""; } - int validLayers = 0; - for (int i=0; i<mesh->fdata.totlayer; i++) + for (int i=0; i<dm->faceData.totlayer; i++) { - if (mesh->fdata.layers[i].type == CD_MTFACE) + if (dm->faceData.layers[i].type == CD_MTFACE) { assert(validLayers <= 8); - layers[validLayers].face = (MTFace*)mesh->fdata.layers[i].data;; - layers[validLayers].name = mesh->fdata.layers[i].name; + layers[validLayers].face = (MTFace*)(dm->faceData.layers[i].data); + layers[validLayers].name = dm->faceData.layers[i].name; if(tface == layers[validLayers].face) tfaceName = layers[validLayers].name; validLayers++; @@ -844,271 +767,269 @@ RAS_MeshObject* BL_ConvertMesh(Mesh* mesh, Object* blenderobj, RAS_IRenderTools* } meshobj->SetName(mesh->id.name); - meshobj->m_xyz_index_to_vertex_index_mapping.resize(mesh->totvert); - for (int f=0;f<mesh->totface;f++,mface++) + meshobj->m_xyz_index_to_vertex_index_mapping.resize(totvert); + + for (int f=0;f<totface;f++,mface++) { - + Material* ma = 0; bool collider = true; - - // only add valid polygons - if (mface->v3) - { - MT_Point2 uv0(0.0,0.0),uv1(0.0,0.0),uv2(0.0,0.0),uv3(0.0,0.0); - MT_Point2 uv20(0.0,0.0),uv21(0.0,0.0),uv22(0.0,0.0),uv23(0.0,0.0); - // rgb3 is set from the adjoint face in a square - unsigned int rgb0,rgb1,rgb2,rgb3 = 0; - MT_Vector3 no0(mesh->mvert[mface->v1].no[0], mesh->mvert[mface->v1].no[1], mesh->mvert[mface->v1].no[2]), - no1(mesh->mvert[mface->v2].no[0], mesh->mvert[mface->v2].no[1], mesh->mvert[mface->v2].no[2]), - no2(mesh->mvert[mface->v3].no[0], mesh->mvert[mface->v3].no[1], mesh->mvert[mface->v3].no[2]), - no3(0.0, 0.0, 0.0); - MT_Point3 pt0(mesh->mvert[mface->v1].co), - pt1(mesh->mvert[mface->v2].co), - pt2(mesh->mvert[mface->v3].co), - pt3(0.0, 0.0, 0.0); - MT_Vector4 tan0(0.0, 0.0, 0.0, 0.0), - tan1(0.0, 0.0, 0.0, 0.0), - tan2(0.0, 0.0, 0.0, 0.0), - tan3(0.0, 0.0, 0.0, 0.0); - - no0 /= 32767.0; - no1 /= 32767.0; - no2 /= 32767.0; - if (mface->v4) - { - pt3 = MT_Point3(mesh->mvert[mface->v4].co); - no3 = MT_Vector3(mesh->mvert[mface->v4].no[0], mesh->mvert[mface->v4].no[1], mesh->mvert[mface->v4].no[2]); - no3 /= 32767.0; + MT_Point2 uv0(0.0,0.0),uv1(0.0,0.0),uv2(0.0,0.0),uv3(0.0,0.0); + MT_Point2 uv20(0.0,0.0),uv21(0.0,0.0),uv22(0.0,0.0),uv23(0.0,0.0); + unsigned int rgb0,rgb1,rgb2,rgb3 = 0; + + MT_Vector3 no0, no1, no2, no3; + MT_Point3 pt0, pt1, pt2, pt3; + MT_Vector4 tan0, tan1, tan2, tan3; + + /* get coordinates, normals and tangents */ + pt0 = MT_Point3(mvert[mface->v1].co); + pt1 = MT_Point3(mvert[mface->v2].co); + pt2 = MT_Point3(mvert[mface->v3].co); + pt3 = (mface->v4)? MT_Point3(mvert[mface->v4].co): MT_Point3(0.0, 0.0, 0.0); + + if(mface->flag & ME_SMOOTH) { + float n0[3], n1[3], n2[3], n3[3]; + + NormalShortToFloat(n0, mvert[mface->v1].no); + NormalShortToFloat(n1, mvert[mface->v2].no); + NormalShortToFloat(n2, mvert[mface->v3].no); + no0 = n0; + no1 = n1; + no2 = n2; + + if(mface->v4) { + NormalShortToFloat(n3, mvert[mface->v4].no); + no3 = n3; } + else + no3 = MT_Vector3(0.0, 0.0, 0.0); + } + else { + float fno[3]; + + if(mface->v4) + CalcNormFloat4(mvert[mface->v1].co, mvert[mface->v2].co, + mvert[mface->v3].co, mvert[mface->v4].co, fno); + else + CalcNormFloat(mvert[mface->v1].co, mvert[mface->v2].co, + mvert[mface->v3].co, fno); + + no0 = no1 = no2 = no3 = MT_Vector3(fno); + } + + if(tangent) { + tan0 = tangent[f*4 + 0]; + tan1 = tangent[f*4 + 1]; + tan2 = tangent[f*4 + 2]; + + if (mface->v4) + tan3 = tangent[f*4 + 3]; + } + + /* get material */ + ma = give_current_material(blenderobj, mface->mat_nr+1); - if(!(mface->flag & ME_SMOOTH)) - { - MT_Vector3 norm = ((pt1-pt0).cross(pt2-pt0)).safe_normalized(); - norm[0] = ((int) (10*norm[0]))/10.0; - norm[1] = ((int) (10*norm[1]))/10.0; - norm[2] = ((int) (10*norm[2]))/10.0; - no0=no1=no2=no3= norm; - + { + bool polyvisible = true; + RAS_IPolyMaterial* polymat = NULL; + BL_Material *bl_mat = NULL; + + if(converter->GetMaterials()) { + /* do Blender Multitexture and Blender GLSL materials */ + unsigned int rgb[4]; + MT_Point2 uv[4]; + + /* first is the BL_Material */ + bl_mat = ConvertMaterial(ma, tface, tfaceName, mface, mcol, + lightlayer, blenderobj, layers, converter->GetGLSLMaterials()); + + bl_mat->material_index = (int)mface->mat_nr; + + polyvisible = ((bl_mat->ras_mode & POLY_VIS)!=0); + collider = ((bl_mat->ras_mode & COLLIDER)!=0); + + /* vertex colors and uv's were stored in bl_mat temporarily */ + bl_mat->GetConversionRGB(rgb); + rgb0 = rgb[0]; rgb1 = rgb[1]; + rgb2 = rgb[2]; rgb3 = rgb[3]; + + bl_mat->GetConversionUV(uv); + uv0 = uv[0]; uv1 = uv[1]; + uv2 = uv[2]; uv3 = uv[3]; + + bl_mat->GetConversionUV2(uv); + uv20 = uv[0]; uv21 = uv[1]; + uv22 = uv[2]; uv23 = uv[3]; + + /* then the KX_BlenderMaterial */ + polymat = new KX_BlenderMaterial(scene, bl_mat, skinMesh, lightlayer, blenderobj ); } + else { + /* do Texture Face materials */ + Image* bima = (tface)? (Image*)tface->tpage: NULL; + STR_String imastr = (tface)? (bima? (bima)->id.name : "" ) : ""; - { - Material* ma = 0; - bool polyvisible = true; - RAS_IPolyMaterial* polymat = NULL; - BL_Material *bl_mat = NULL; - - if(converter->GetMaterials()) - { - if(mesh->totcol > 1) - ma = mesh->mat[mface->mat_nr]; - else - ma = give_current_material(blenderobj, 1); - - bl_mat = ConvertMaterial(mesh, ma, tface, tfaceName, mface, mmcol, lightlayer, blenderobj, layers, converter->GetGLSLMaterials()); - // set the index were dealing with - bl_mat->material_index = (int)mface->mat_nr; - - polyvisible = ((bl_mat->ras_mode & POLY_VIS)!=0); - collider = ((bl_mat->ras_mode & COLLIDER)!=0); + char transp=0; + short mode=0, tile=0; + int tilexrep=4,tileyrep = 4; + + if (bima) { + tilexrep = bima->xrep; + tileyrep = bima->yrep; + } + + /* get tface properties if available */ + if(tface) { + /* TF_DYNAMIC means the polygon is a collision face */ + collider = ((tface->mode & TF_DYNAMIC) != 0); + transp = tface->transp; + tile = tface->tile; + mode = tface->mode; - polymat = new KX_BlenderMaterial(scene, bl_mat, skinMesh, lightlayer, blenderobj ); + polyvisible = !((mface->flag & ME_HIDE)||(tface->mode & TF_INVISIBLE)); - unsigned int rgb[4]; - bl_mat->GetConversionRGB(rgb); - rgb0 = rgb[0]; rgb1 = rgb[1]; - rgb2 = rgb[2]; rgb3 = rgb[3]; - MT_Point2 uv[4]; - bl_mat->GetConversionUV(uv); - uv0 = uv[0]; uv1 = uv[1]; - uv2 = uv[2]; uv3 = uv[3]; - - bl_mat->GetConversionUV2(uv); - uv20 = uv[0]; uv21 = uv[1]; - uv22 = uv[2]; uv23 = uv[3]; - - if(tangent){ - tan0 = tangent[mface->v1]; - tan1 = tangent[mface->v2]; - tan2 = tangent[mface->v3]; - if (mface->v4) - tan3 = tangent[mface->v4]; - } + uv0 = MT_Point2(tface->uv[0]); + uv1 = MT_Point2(tface->uv[1]); + uv2 = MT_Point2(tface->uv[2]); + + if (mface->v4) + uv3 = MT_Point2(tface->uv[3]); + } + else { + /* no texfaces, set COLLSION true and everything else FALSE */ + mode = default_face_mode; + transp = TF_SOLID; + tile = 0; } - else - { - ma = give_current_material(blenderobj, 1); - Image* bima = ((mesh->mtface && tface) ? (Image*) tface->tpage : NULL); - - STR_String imastr = - ((mesh->mtface && tface) ? - (bima? (bima)->id.name : "" ) : "" ); - - char transp=0; - short mode=0, tile=0; - int tilexrep=4,tileyrep = 4; + /* get vertex colors */ + if (mcol) { + /* we have vertex colors */ + rgb0 = KX_Mcol2uint_new(mcol[0]); + rgb1 = KX_Mcol2uint_new(mcol[1]); + rgb2 = KX_Mcol2uint_new(mcol[2]); - if (bima) - { - tilexrep = bima->xrep; - tileyrep = bima->yrep; - - } + if (mface->v4) + rgb3 = KX_Mcol2uint_new(mcol[3]); + } + else { + /* no vertex colors, take from material, otherwise white */ + unsigned int color = 0xFFFFFFFFL; - if (mesh->mtface && tface) + if (ma) { - // Use texface colors if available - //TF_DYNAMIC means the polygon is a collision face - collider = ((tface->mode & TF_DYNAMIC) != 0); - transp = tface->transp &~ TF_CLIP; - tile = tface->tile; - mode = tface->mode; - - polyvisible = !((mface->flag & ME_HIDE)||(tface->mode & TF_INVISIBLE)); + union + { + unsigned char cp[4]; + unsigned int integer; + } col_converter; - uv0 = MT_Point2(tface->uv[0]); - uv1 = MT_Point2(tface->uv[1]); - uv2 = MT_Point2(tface->uv[2]); - - if (mface->v4) - uv3 = MT_Point2(tface->uv[3]); - } - else - { - // no texfaces, set COLLSION true and everything else FALSE + col_converter.cp[3] = (unsigned char) (ma->r*255.0); + col_converter.cp[2] = (unsigned char) (ma->g*255.0); + col_converter.cp[1] = (unsigned char) (ma->b*255.0); + col_converter.cp[0] = (unsigned char) (ma->alpha*255.0); - mode = default_face_mode; - transp = TF_SOLID; - tile = 0; + color = col_converter.integer; } - if (mmcol) - { - // Use vertex colors - rgb0 = KX_Mcol2uint_new(mmcol[0]); - rgb1 = KX_Mcol2uint_new(mmcol[1]); - rgb2 = KX_Mcol2uint_new(mmcol[2]); - - if (mface->v4) - rgb3 = KX_Mcol2uint_new(mmcol[3]); - } - else { - // no vertex colors: take from material if we have one, - // otherwise set to white - unsigned int color = 0xFFFFFFFFL; + rgb0 = KX_rgbaint2uint_new(color); + rgb1 = KX_rgbaint2uint_new(color); + rgb2 = KX_rgbaint2uint_new(color); + + if (mface->v4) + rgb3 = KX_rgbaint2uint_new(color); + } + + bool istriangle = (mface->v4==0); - if (ma) - { - union - { - unsigned char cp[4]; - unsigned int integer; - } col_converter; - - col_converter.cp[3] = (unsigned char) (ma->r*255.0); - col_converter.cp[2] = (unsigned char) (ma->g*255.0); - col_converter.cp[1] = (unsigned char) (ma->b*255.0); - col_converter.cp[0] = (unsigned char) (ma->alpha*255.0); - - color = col_converter.integer; - } + // only zsort alpha + add + bool alpha = (transp == TF_ALPHA || transp == TF_ADD); + bool zsort = (mode & TF_ALPHASORT)? alpha: 0; + + polymat = new KX_PolygonMaterial(imastr, ma, + tile, tilexrep, tileyrep, + mode, transp, alpha, zsort, lightlayer, istriangle, blenderobj, tface, (unsigned int*)mcol); - rgb0 = KX_rgbaint2uint_new(color); - rgb1 = KX_rgbaint2uint_new(color); - rgb2 = KX_rgbaint2uint_new(color); - - if (mface->v4) - rgb3 = KX_rgbaint2uint_new(color); - } - - bool istriangle = (mface->v4==0); - bool zsort = ma?(ma->mode & MA_ZTRA) != 0:false; - - polymat = new KX_PolygonMaterial(imastr, ma, - tile, tilexrep, tileyrep, - mode, transp, zsort, lightlayer, istriangle, blenderobj, tface, (unsigned int*)mmcol); - - if (ma) - { - polymat->m_specular = MT_Vector3(ma->specr, ma->specg, ma->specb)*ma->spec; - polymat->m_shininess = (float)ma->har/4.0; // 0 < ma->har <= 512 - polymat->m_diffuse = MT_Vector3(ma->r, ma->g, ma->b)*(ma->emit + ma->ref); + if (ma) { + polymat->m_specular = MT_Vector3(ma->specr, ma->specg, ma->specb)*ma->spec; + polymat->m_shininess = (float)ma->har/4.0; // 0 < ma->har <= 512 + polymat->m_diffuse = MT_Vector3(ma->r, ma->g, ma->b)*(ma->emit + ma->ref); + } + else { + polymat->m_specular = MT_Vector3(0.0f,0.0f,0.0f); + polymat->m_shininess = 35.0; + } + } - } else - { - polymat->m_specular = MT_Vector3(0.0f,0.0f,0.0f); - polymat->m_shininess = 35.0; - } + // see if a bucket was reused or a new one was created + // this way only one KX_BlenderMaterial object has to exist per bucket + bool bucketCreated; + RAS_MaterialBucket* bucket = scene->FindBucket(polymat, bucketCreated); + if (bucketCreated) { + // this is needed to free up memory afterwards + converter->RegisterPolyMaterial(polymat); + if(converter->GetMaterials()) { + converter->RegisterBlenderMaterial(bl_mat); } - - // see if a bucket was reused or a new one was created - // this way only one KX_BlenderMaterial object has to exist per bucket - bool bucketCreated; - RAS_MaterialBucket* bucket = scene->FindBucket(polymat, bucketCreated); - if (bucketCreated) { - // this is needed to free up memory afterwards - converter->RegisterPolyMaterial(polymat); - if(converter->GetMaterials()) { - converter->RegisterBlenderMaterial(bl_mat); - } - } else { - // delete the material objects since they are no longer needed - // from now on, use the polygon material from the material bucket - delete polymat; - if(converter->GetMaterials()) { - delete bl_mat; - } - polymat = bucket->GetPolyMaterial(); + } else { + // delete the material objects since they are no longer needed + // from now on, use the polygon material from the material bucket + delete polymat; + if(converter->GetMaterials()) { + delete bl_mat; } - - int nverts = mface->v4?4:3; - int vtxarray = meshobj->FindVertexArray(nverts,polymat); - RAS_Polygon* poly = new RAS_Polygon(bucket,polyvisible,nverts,vtxarray); + polymat = bucket->GetPolyMaterial(); + } + + int nverts = mface->v4?4:3; + int vtxarray = meshobj->FindVertexArray(nverts,polymat); + RAS_Polygon* poly = new RAS_Polygon(bucket,polyvisible,nverts,vtxarray); - bool flat; + bool flat; - if (skinMesh) { - /* If the face is set to solid, all fnors are the same */ - if (mface->flag & ME_SMOOTH) - flat = false; - else - flat = true; - } - else + if (skinMesh) { + /* If the face is set to solid, all fnors are the same */ + if (mface->flag & ME_SMOOTH) flat = false; + else + flat = true; + } + else + flat = false; - poly->SetVertex(0,meshobj->FindOrAddVertex(vtxarray,pt0,uv0,uv20,tan0,rgb0,no0,flat,polymat,mface->v1)); - poly->SetVertex(1,meshobj->FindOrAddVertex(vtxarray,pt1,uv1,uv21,tan1,rgb1,no1,flat,polymat,mface->v2)); - poly->SetVertex(2,meshobj->FindOrAddVertex(vtxarray,pt2,uv2,uv22,tan2,rgb2,no2,flat,polymat,mface->v3)); - if (nverts==4) - poly->SetVertex(3,meshobj->FindOrAddVertex(vtxarray,pt3,uv3,uv23,tan3,rgb3,no3,flat,polymat,mface->v4)); + poly->SetVertex(0,meshobj->FindOrAddVertex(vtxarray,pt0,uv0,uv20,tan0,rgb0,no0,flat,polymat,mface->v1)); + poly->SetVertex(1,meshobj->FindOrAddVertex(vtxarray,pt1,uv1,uv21,tan1,rgb1,no1,flat,polymat,mface->v2)); + poly->SetVertex(2,meshobj->FindOrAddVertex(vtxarray,pt2,uv2,uv22,tan2,rgb2,no2,flat,polymat,mface->v3)); + if (nverts==4) + poly->SetVertex(3,meshobj->FindOrAddVertex(vtxarray,pt3,uv3,uv23,tan3,rgb3,no3,flat,polymat,mface->v4)); - meshobj->AddPolygon(poly); - if (poly->IsCollider()) + meshobj->AddPolygon(poly); + if (poly->IsCollider()) + { + RAS_TriangleIndex idx; + idx.m_index[0] = mface->v1; + idx.m_index[1] = mface->v2; + idx.m_index[2] = mface->v3; + idx.m_collider = collider; + meshobj->m_triangle_indices.push_back(idx); + if (nverts==4) { - RAS_TriangleIndex idx; - idx.m_index[0] = mface->v1; - idx.m_index[1] = mface->v2; - idx.m_index[2] = mface->v3; - idx.m_collider = collider; - meshobj->m_triangle_indices.push_back(idx); - if (nverts==4) - { - idx.m_index[0] = mface->v1; - idx.m_index[1] = mface->v3; - idx.m_index[2] = mface->v4; - idx.m_collider = collider; - meshobj->m_triangle_indices.push_back(idx); - } + idx.m_index[0] = mface->v1; + idx.m_index[1] = mface->v3; + idx.m_index[2] = mface->v4; + idx.m_collider = collider; + meshobj->m_triangle_indices.push_back(idx); } - -// poly->SetVisibleWireframeEdges(mface->edcode); - poly->SetCollider(collider); } + +// poly->SetVisibleWireframeEdges(mface->edcode); + poly->SetCollider(collider); } + if (tface) tface++; - if (mmcol) - mmcol+=4; + if (mcol) + mcol+=4; for (int lay=0; lay<MAX_MTFACE; lay++) { @@ -1127,11 +1048,10 @@ RAS_MeshObject* BL_ConvertMesh(Mesh* mesh, Object* blenderobj, RAS_IRenderTools* (*mit)->GetPolyMaterial()->OnConstruction(); } - if(tangent) - delete [] tangent; - if (layers) delete []layers; + + dm->release(dm); return meshobj; } @@ -1819,7 +1739,7 @@ KX_GameObject* getGameOb(STR_String busc,CListValue* sumolist){ return 0; } -#include "BLI_arithb.h" + // convert blender objects into ketsji gameobjects void BL_ConvertBlenderObjects(struct Main* maggie, const STR_String& scenename, @@ -1937,7 +1857,7 @@ void BL_ConvertBlenderObjects(struct Main* maggie, if (converter->addInitFromFrame) if (!isInActiveLayer) addobj=false; - + if (gameobj&&addobj) { MT_Point3 posPrev; @@ -2019,7 +1939,17 @@ void BL_ConvertBlenderObjects(struct Main* maggie, float* fl = (float*) blenderobject->parentinv; MT_Transform parinvtrans(fl); parentinversenode->SetLocalPosition(parinvtrans.getOrigin()); - parentinversenode->SetLocalOrientation(parinvtrans.getBasis()); + // problem here: the parent inverse transform combines scaling and rotation + // in the basis but the scenegraph needs separate rotation and scaling. + // This is not important for OpenGL (it uses 4x4 matrix) but it is important + // for the physic engine that needs a separate scaling + //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])); parentinversenode->AddChild(gameobj->GetSGNode()); } @@ -2258,7 +2188,8 @@ void BL_ConvertBlenderObjects(struct Main* maggie, } } - if (blenderscene->camera) { + // non-camera objects not supported as camera currently + if (blenderscene->camera && blenderscene->camera->type == OB_CAMERA) { KX_Camera *gamecamera= (KX_Camera*) converter->FindGameObject(blenderscene->camera); if(gamecamera) @@ -2520,13 +2451,13 @@ void BL_ConvertBlenderObjects(struct Main* maggie, int layerMask = (groupobj.find(blenderobj) == groupobj.end()) ? activeLayerBitInfo : 0; bool isInActiveLayer = (blenderobj->lay & layerMask)!=0; BL_ConvertSensors(blenderobj,gameobj,logicmgr,kxscene,keydev,executePriority,layerMask,isInActiveLayer,canvas,converter); + // set the init state to all objects + gameobj->SetInitState((blenderobj->init_state)?blenderobj->init_state:blenderobj->state); } - // apply the initial state to controllers - for ( i=0;i<logicbrick_conversionlist->GetCount();i++) + // apply the initial state to controllers, only on the active objects as this registers the sensors + for ( i=0;i<objectlist->GetCount();i++) { - KX_GameObject* gameobj = static_cast<KX_GameObject*>(logicbrick_conversionlist->GetValue(i)); - struct Object* blenderobj = converter->FindBlenderObject(gameobj); - gameobj->SetInitState((blenderobj->init_state)?blenderobj->init_state:blenderobj->state); + KX_GameObject* gameobj = static_cast<KX_GameObject*>(objectlist->GetValue(i)); gameobj->ResetState(); } diff --git a/source/gameengine/Converter/KX_ConvertSensors.cpp b/source/gameengine/Converter/KX_ConvertSensors.cpp index 7c9df688d45..5e433bb821b 100644 --- a/source/gameengine/Converter/KX_ConvertSensors.cpp +++ b/source/gameengine/Converter/KX_ConvertSensors.cpp @@ -733,9 +733,9 @@ void BL_ConvertSensors(struct Object* blenderobject, gameobj->AddSensor(gamesensor); // only register to manager if it's in an active layer - - if (isInActiveLayer) - gamesensor->RegisterToManager(); + // Make registration dynamic: only when sensor is activated + //if (isInActiveLayer) + // gamesensor->RegisterToManager(); for (int i=0;i<sens->totlinks;i++) diff --git a/source/gameengine/Converter/KX_IpoConvert.cpp b/source/gameengine/Converter/KX_IpoConvert.cpp index 7410beecaf4..ce004fa0504 100644 --- a/source/gameengine/Converter/KX_IpoConvert.cpp +++ b/source/gameengine/Converter/KX_IpoConvert.cpp @@ -766,15 +766,18 @@ void BL_ConvertMaterialIpos( // if there is only one material attached to the mesh then set material_index in BL_ConvertMaterialIpos to NULL // --> this makes the UpdateMaterialData function in KX_GameObject.cpp use the old hack of using SetObjectColor // because this yields a better performance as not all the vertex colors need to be edited - if(mat) ConvertMaterialIpos(mat, NULL, gameobj, converter); + if(mat) ConvertMaterialIpos(mat, 0, gameobj, converter); } else { for (int material_index=1; material_index <= blenderobject->totcol; material_index++) { Material *mat = give_current_material(blenderobject, material_index); - STR_HashedString matname = mat->id.name; - if(mat) ConvertMaterialIpos(mat, matname.hash(), gameobj, converter); + STR_HashedString matname; + if(mat) { + matname= mat->id.name; + ConvertMaterialIpos(mat, matname.hash(), gameobj, converter); + } } } } diff --git a/source/gameengine/Expressions/Value.cpp b/source/gameengine/Expressions/Value.cpp index 48136eb9dc3..b4694740679 100644 --- a/source/gameengine/Expressions/Value.cpp +++ b/source/gameengine/Expressions/Value.cpp @@ -700,9 +700,7 @@ CValue* CValue::ConvertPythonToValue(PyObject* pyobj) CValue* vallie = NULL; - PyTypeObject* type = pyobj->ob_type; - - if (type == &PyList_Type) + if (PyList_Check(pyobj)) { CListValue* listval = new CListValue(); bool error = false; @@ -732,26 +730,25 @@ CValue* CValue::ConvertPythonToValue(PyObject* pyobj) } } else - if (type == &PyFloat_Type) + if (PyFloat_Check(pyobj)) { - float fl; - PyArg_Parse(pyobj,"f",&fl); - vallie = new CFloatValue(fl); + vallie = new CFloatValue( (float)PyFloat_AsDouble(pyobj) ); } else - if (type==&PyInt_Type) + if (PyInt_Check(pyobj)) { - int innie; - PyArg_Parse(pyobj,"i",&innie); - vallie = new CIntValue(innie); + vallie = new CIntValue( (int)PyInt_AS_LONG(pyobj) ); } else - - if (type==&PyString_Type) + if (PyString_Check(pyobj)) { vallie = new CStringValue(PyString_AsString(pyobj),""); } else - if (type==&CValue::Type || type==&CListValue::Type) + if (pyobj->ob_type==&CValue::Type || pyobj->ob_type==&CListValue::Type) { vallie = ((CValue*) pyobj)->AddRef(); + } else + { + /* return an error value from the caller */ + PyErr_SetString(PyExc_TypeError, "This python value could not be assigned to a game engine property"); } return vallie; @@ -778,6 +775,9 @@ int CValue::_setattr(const STR_String& attr,PyObject* pyobj) SetProperty(attr,vallie); } vallie->Release(); + } else + { + return 1; /* ConvertPythonToValue sets the error message */ } //PyObjectPlus::_setattr(attr,value); diff --git a/source/gameengine/GameLogic/SCA_ActuatorEventManager.cpp b/source/gameengine/GameLogic/SCA_ActuatorEventManager.cpp index 28ca1fd673f..768a3a45937 100644 --- a/source/gameengine/GameLogic/SCA_ActuatorEventManager.cpp +++ b/source/gameengine/GameLogic/SCA_ActuatorEventManager.cpp @@ -48,19 +48,10 @@ SCA_ActuatorEventManager::~SCA_ActuatorEventManager() } - - -void SCA_ActuatorEventManager::RegisterSensor(SCA_ISensor* sensor) -{ - m_sensors.push_back(sensor); -} - - - void SCA_ActuatorEventManager::NextFrame() { // check for changed actuator - for (vector<SCA_ISensor*>::const_iterator it = m_sensors.begin();!(it==m_sensors.end());it++) + for (set<SCA_ISensor*>::const_iterator it = m_sensors.begin();!(it==m_sensors.end());it++) { (*it)->Activate(m_logicmgr,NULL); } @@ -69,7 +60,7 @@ void SCA_ActuatorEventManager::NextFrame() void SCA_ActuatorEventManager::UpdateFrame() { // update the state of actuator before executing them - for (vector<SCA_ISensor*>::const_iterator it = m_sensors.begin();!(it==m_sensors.end());it++) + for (set<SCA_ISensor*>::const_iterator it = m_sensors.begin();!(it==m_sensors.end());it++) { ((SCA_ActuatorSensor*)(*it))->Update(); } diff --git a/source/gameengine/GameLogic/SCA_ActuatorEventManager.h b/source/gameengine/GameLogic/SCA_ActuatorEventManager.h index b5108764197..a7d61627c23 100644 --- a/source/gameengine/GameLogic/SCA_ActuatorEventManager.h +++ b/source/gameengine/GameLogic/SCA_ActuatorEventManager.h @@ -44,7 +44,6 @@ public: virtual ~SCA_ActuatorEventManager(); virtual void NextFrame(); virtual void UpdateFrame(); - virtual void RegisterSensor(SCA_ISensor* sensor); //SCA_LogicManager* GetLogicManager() { return m_logicmgr;} }; diff --git a/source/gameengine/GameLogic/SCA_AlwaysEventManager.cpp b/source/gameengine/GameLogic/SCA_AlwaysEventManager.cpp index ab3bc2cc4ee..4cd2dfba994 100644 --- a/source/gameengine/GameLogic/SCA_AlwaysEventManager.cpp +++ b/source/gameengine/GameLogic/SCA_AlwaysEventManager.cpp @@ -51,16 +51,9 @@ SCA_AlwaysEventManager::SCA_AlwaysEventManager(class SCA_LogicManager* logicmgr) void SCA_AlwaysEventManager::NextFrame() { - for (vector<class SCA_ISensor*>::const_iterator i= m_sensors.begin();!(i==m_sensors.end());i++) + for (set<class SCA_ISensor*>::const_iterator i= m_sensors.begin();!(i==m_sensors.end());i++) { - SCA_ISensor* sensor = *i; - sensor->Activate(m_logicmgr, NULL); + (*i)->Activate(m_logicmgr, NULL); } } - - -void SCA_AlwaysEventManager::RegisterSensor(SCA_ISensor* sensor) -{ - m_sensors.push_back(sensor); -} diff --git a/source/gameengine/GameLogic/SCA_AlwaysEventManager.h b/source/gameengine/GameLogic/SCA_AlwaysEventManager.h index 28c71512875..a619eecddd4 100644 --- a/source/gameengine/GameLogic/SCA_AlwaysEventManager.h +++ b/source/gameengine/GameLogic/SCA_AlwaysEventManager.h @@ -39,7 +39,6 @@ class SCA_AlwaysEventManager : public SCA_EventManager public: SCA_AlwaysEventManager(class SCA_LogicManager* logicmgr); virtual void NextFrame(); - virtual void RegisterSensor(SCA_ISensor* sensor); }; diff --git a/source/gameengine/GameLogic/SCA_EventManager.cpp b/source/gameengine/GameLogic/SCA_EventManager.cpp index 0169864a133..e4fd0379597 100644 --- a/source/gameengine/GameLogic/SCA_EventManager.cpp +++ b/source/gameengine/GameLogic/SCA_EventManager.cpp @@ -45,17 +45,14 @@ SCA_EventManager::~SCA_EventManager() { } - +void SCA_EventManager::RegisterSensor(class SCA_ISensor* sensor) +{ + m_sensors.insert(sensor); +} void SCA_EventManager::RemoveSensor(class SCA_ISensor* sensor) { - std::vector<SCA_ISensor*>::iterator i = - std::find(m_sensors.begin(), m_sensors.end(), sensor); - if (!(i == m_sensors.end())) - { - std::swap(*i, m_sensors.back()); - m_sensors.pop_back(); - } + m_sensors.erase(sensor); } void SCA_EventManager::NextFrame(double curtime, double fixedtime) diff --git a/source/gameengine/GameLogic/SCA_EventManager.h b/source/gameengine/GameLogic/SCA_EventManager.h index 9cc1718cd1e..9dbb5a6d24f 100644 --- a/source/gameengine/GameLogic/SCA_EventManager.h +++ b/source/gameengine/GameLogic/SCA_EventManager.h @@ -30,12 +30,14 @@ #define __KX_EVENTMANAGER #include <vector> +#include <set> #include <algorithm> class SCA_EventManager { protected: - std::vector <class SCA_ISensor*> m_sensors; + // use a set to speed-up insertion/removal + std::set <class SCA_ISensor*> m_sensors; public: enum EVENT_MANAGER_TYPE { @@ -61,7 +63,7 @@ public: virtual void NextFrame(); virtual void UpdateFrame(); virtual void EndFrame(); - virtual void RegisterSensor(class SCA_ISensor* sensor)=0; + virtual void RegisterSensor(class SCA_ISensor* sensor); int GetType(); protected: diff --git a/source/gameengine/GameLogic/SCA_IObject.cpp b/source/gameengine/GameLogic/SCA_IObject.cpp index 25b4af696ea..b0f8decee26 100644 --- a/source/gameengine/GameLogic/SCA_IObject.cpp +++ b/source/gameengine/GameLogic/SCA_IObject.cpp @@ -337,12 +337,31 @@ void SCA_IObject::Resume(void) void SCA_IObject::SetState(unsigned int state) { - m_state = state; - // update the status of the controllers + unsigned int tmpstate; SCA_ControllerList::iterator contit; - for (contit = m_controllers.begin(); contit != m_controllers.end(); contit++) + + // we will update the state in two steps: + // 1) set the new state bits that are 1 + // 2) clr the new state bits that are 0 + // This to ensure continuity if a sensor is attached to two states + // that are switching state: no need to deactive and reactive the sensor + + tmpstate = m_state | state; + if (tmpstate != m_state) + { + // update the status of the controllers + for (contit = m_controllers.begin(); contit != m_controllers.end(); contit++) + { + (*contit)->ApplyState(tmpstate); + } + } + m_state = state; + if (m_state != tmpstate) { - (*contit)->ApplyState(m_state); + for (contit = m_controllers.begin(); contit != m_controllers.end(); contit++) + { + (*contit)->ApplyState(m_state); + } } } diff --git a/source/gameengine/GameLogic/SCA_ISensor.cpp b/source/gameengine/GameLogic/SCA_ISensor.cpp index f11c8047fac..2dc49924062 100644 --- a/source/gameengine/GameLogic/SCA_ISensor.cpp +++ b/source/gameengine/GameLogic/SCA_ISensor.cpp @@ -41,7 +41,8 @@ void SCA_ISensor::ReParent(SCA_IObject* parent) { SCA_ILogicBrick::ReParent(parent); - m_eventmgr->RegisterSensor(this); + // will be done when the sensor is activated + //m_eventmgr->RegisterSensor(this); this->SetActive(false); } @@ -133,6 +134,7 @@ void SCA_ISensor::DecLink() { { // sensor is detached from all controllers, initialize it so that it // is fresh as at startup when it is reattached again. + UnregisterToManager(); Init(); } } @@ -203,6 +205,11 @@ void SCA_ISensor::RegisterToManager() m_eventmgr->RegisterSensor(this); } +void SCA_ISensor::UnregisterToManager() +{ + m_eventmgr->RemoveSensor(this); +} + void SCA_ISensor::Activate(class SCA_LogicManager* logicmgr, CValue* event) { diff --git a/source/gameengine/GameLogic/SCA_ISensor.h b/source/gameengine/GameLogic/SCA_ISensor.h index 51837755ba4..d5dabbce3ee 100644 --- a/source/gameengine/GameLogic/SCA_ISensor.h +++ b/source/gameengine/GameLogic/SCA_ISensor.h @@ -115,6 +115,8 @@ public: void SetLevel(bool lvl); void RegisterToManager(); + void UnregisterToManager(); + virtual float GetNumber(); /** Stop sensing for a while. */ @@ -129,7 +131,7 @@ public: void ClrLink() { m_links = 0; } void IncLink() - { m_links++; } + { if (!m_links++) RegisterToManager(); } void DecLink(); bool IsNoLink() const { return !m_links; } diff --git a/source/gameengine/GameLogic/SCA_JoystickManager.cpp b/source/gameengine/GameLogic/SCA_JoystickManager.cpp index 7bf2049e56e..8ff28ba0b51 100644 --- a/source/gameengine/GameLogic/SCA_JoystickManager.cpp +++ b/source/gameengine/GameLogic/SCA_JoystickManager.cpp @@ -52,9 +52,10 @@ SCA_JoystickManager::~SCA_JoystickManager() void SCA_JoystickManager::NextFrame(double curtime,double deltatime) { - for (unsigned int i = 0; i < m_sensors.size(); i++) + set<SCA_ISensor*>::iterator it; + for (it = m_sensors.begin(); it != m_sensors.end(); it++) { - SCA_JoystickSensor* joysensor = (SCA_JoystickSensor*) m_sensors[i]; + SCA_JoystickSensor* joysensor = (SCA_JoystickSensor*)(*it); if(!joysensor->IsSuspended()) { m_joystick->HandleEvents(); @@ -64,12 +65,6 @@ void SCA_JoystickManager::NextFrame(double curtime,double deltatime) } -void SCA_JoystickManager::RegisterSensor(SCA_ISensor* sensor) -{ - m_sensors.push_back(sensor); -} - - SCA_Joystick *SCA_JoystickManager::GetJoystickDevice() { /* diff --git a/source/gameengine/GameLogic/SCA_JoystickManager.h b/source/gameengine/GameLogic/SCA_JoystickManager.h index 3c4df64677e..f2bb27965fa 100644 --- a/source/gameengine/GameLogic/SCA_JoystickManager.h +++ b/source/gameengine/GameLogic/SCA_JoystickManager.h @@ -45,7 +45,6 @@ public: SCA_JoystickManager(class SCA_LogicManager* logicmgr); virtual ~SCA_JoystickManager(); virtual void NextFrame(double curtime,double deltatime); - virtual void RegisterSensor(SCA_ISensor* sensor); SCA_Joystick* GetJoystickDevice(void); }; diff --git a/source/gameengine/GameLogic/SCA_KeyboardManager.cpp b/source/gameengine/GameLogic/SCA_KeyboardManager.cpp index 259b06134d7..6a96442b124 100644 --- a/source/gameengine/GameLogic/SCA_KeyboardManager.cpp +++ b/source/gameengine/GameLogic/SCA_KeyboardManager.cpp @@ -62,23 +62,14 @@ void SCA_KeyboardManager::NextFrame() { //const SCA_InputEvent& event = GetEventValue(SCA_IInputDevice::KX_EnumInputs inputcode)=0; // cerr << "SCA_KeyboardManager::NextFrame"<< endl; - for (unsigned int i=0;i<m_sensors.size();i++) + set<SCA_ISensor*>::iterator it; + for (it=m_sensors.begin(); it != m_sensors.end(); it++) { - SCA_KeyboardSensor* keysensor = (SCA_KeyboardSensor*)m_sensors[i]; - keysensor->Activate(m_logicmanager,NULL); + (*it)->Activate(m_logicmanager,NULL); } } - - -void SCA_KeyboardManager::RegisterSensor(SCA_ISensor* keysensor) -{ - m_sensors.push_back(keysensor); -} - - - bool SCA_KeyboardManager::IsPressed(SCA_IInputDevice::KX_EnumInputs inputcode) { return false; diff --git a/source/gameengine/GameLogic/SCA_KeyboardManager.h b/source/gameengine/GameLogic/SCA_KeyboardManager.h index b4a50f56025..8f3cc0ab715 100644 --- a/source/gameengine/GameLogic/SCA_KeyboardManager.h +++ b/source/gameengine/GameLogic/SCA_KeyboardManager.h @@ -55,7 +55,6 @@ public: bool IsPressed(SCA_IInputDevice::KX_EnumInputs inputcode); virtual void NextFrame(); - virtual void RegisterSensor(class SCA_ISensor* sensor); SCA_IInputDevice* GetInputDevice(); }; diff --git a/source/gameengine/GameLogic/SCA_LogicManager.cpp b/source/gameengine/GameLogic/SCA_LogicManager.cpp index d1c5917f0ce..91e66aea359 100644 --- a/source/gameengine/GameLogic/SCA_LogicManager.cpp +++ b/source/gameengine/GameLogic/SCA_LogicManager.cpp @@ -176,12 +176,7 @@ void SCA_LogicManager::RemoveSensor(SCA_ISensor* sensor) (*c)->UnlinkSensor(sensor); } m_sensorcontrollermapje.erase(sensor); - - for (vector<SCA_EventManager*>::const_iterator ie=m_eventmanagers.begin(); - !(ie==m_eventmanagers.end());ie++) - { - (*ie)->RemoveSensor(sensor); - } + sensor->UnregisterToManager(); } void SCA_LogicManager::RemoveController(SCA_IController* controller) diff --git a/source/gameengine/GameLogic/SCA_MouseManager.cpp b/source/gameengine/GameLogic/SCA_MouseManager.cpp index b4251d8ab53..ca875dad07c 100644 --- a/source/gameengine/GameLogic/SCA_MouseManager.cpp +++ b/source/gameengine/GameLogic/SCA_MouseManager.cpp @@ -75,9 +75,10 @@ void SCA_MouseManager::NextFrame() { if (m_mousedevice) { - for (unsigned int i = 0; i < m_sensors.size(); i++) + set<SCA_ISensor*>::iterator it; + for (it=m_sensors.begin(); it!=m_sensors.end(); it++) { - SCA_MouseSensor* mousesensor = (SCA_MouseSensor*) m_sensors[i]; + SCA_MouseSensor* mousesensor = (SCA_MouseSensor*)(*it); // (0,0) is the Upper Left corner in our local window // coordinates if (!mousesensor->IsSuspended()) @@ -98,15 +99,6 @@ void SCA_MouseManager::NextFrame() } } - - -void SCA_MouseManager::RegisterSensor(SCA_ISensor* keysensor) -{ - m_sensors.push_back(keysensor); -} - - - bool SCA_MouseManager::IsPressed(SCA_IInputDevice::KX_EnumInputs inputcode) { /* We should guard for non-mouse events maybe? A rather silly side */ diff --git a/source/gameengine/GameLogic/SCA_MouseManager.h b/source/gameengine/GameLogic/SCA_MouseManager.h index bc8254486ad..efa4c639ce7 100644 --- a/source/gameengine/GameLogic/SCA_MouseManager.h +++ b/source/gameengine/GameLogic/SCA_MouseManager.h @@ -62,7 +62,6 @@ public: */ bool IsPressed(SCA_IInputDevice::KX_EnumInputs inputcode); virtual void NextFrame(); - virtual void RegisterSensor(class SCA_ISensor* sensor); SCA_IInputDevice* GetInputDevice(); }; diff --git a/source/gameengine/GameLogic/SCA_PropertyEventManager.cpp b/source/gameengine/GameLogic/SCA_PropertyEventManager.cpp index fc56d101728..e5e3f9cced5 100644 --- a/source/gameengine/GameLogic/SCA_PropertyEventManager.cpp +++ b/source/gameengine/GameLogic/SCA_PropertyEventManager.cpp @@ -47,19 +47,10 @@ SCA_PropertyEventManager::~SCA_PropertyEventManager() } - - -void SCA_PropertyEventManager::RegisterSensor(SCA_ISensor* sensor) -{ - m_sensors.push_back(sensor); -} - - - void SCA_PropertyEventManager::NextFrame() { // check for changed properties - for (vector<SCA_ISensor*>::const_iterator it = m_sensors.begin();!(it==m_sensors.end());it++) + for (set<SCA_ISensor*>::const_iterator it = m_sensors.begin();!(it==m_sensors.end());it++) { (*it)->Activate(m_logicmgr,NULL); } diff --git a/source/gameengine/GameLogic/SCA_PropertyEventManager.h b/source/gameengine/GameLogic/SCA_PropertyEventManager.h index aaa303a52c8..f166065b198 100644 --- a/source/gameengine/GameLogic/SCA_PropertyEventManager.h +++ b/source/gameengine/GameLogic/SCA_PropertyEventManager.h @@ -43,7 +43,6 @@ public: SCA_PropertyEventManager(class SCA_LogicManager* logicmgr); virtual ~SCA_PropertyEventManager(); virtual void NextFrame(); - virtual void RegisterSensor(SCA_ISensor* sensor); //SCA_LogicManager* GetLogicManager() { return m_logicmgr;} }; diff --git a/source/gameengine/GameLogic/SCA_PythonController.cpp b/source/gameengine/GameLogic/SCA_PythonController.cpp index 01ae4072335..cd1b029fc34 100644 --- a/source/gameengine/GameLogic/SCA_PythonController.cpp +++ b/source/gameengine/GameLogic/SCA_PythonController.cpp @@ -273,36 +273,16 @@ void SCA_PythonController::Trigger(SCA_LogicManager* logicmgr) * break it by hand, then DECREF (which in this case * should always ensure excdict is cleared). */ -/* PyObject *excdict= myPyDict_Copy(m_pythondictionary); - struct _object* resultobj = PyEval_EvalCode((PyCodeObject*)m_bytecode, - excdict, - excdict - ); - PyDict_Clear(excdict); - Py_DECREF(excdict);*/ - -#if 1 PyObject *excdict= PyDict_Copy(m_pythondictionary); PyObject* resultobj = PyEval_EvalCode((PyCodeObject*)m_bytecode, - excdict, - excdict - ); - PyDict_Clear(excdict); - Py_DECREF(excdict); -#else - - PyObject* resultobj = PyEval_EvalCode((PyCodeObject*)m_bytecode, - m_pythondictionary, - m_pythondictionary - ); - -#endif + excdict, excdict); if (resultobj) { Py_DECREF(resultobj); - } else + } + else { // something is wrong, tell the user what went wrong printf("PYTHON SCRIPT ERROR:\n"); @@ -310,6 +290,11 @@ void SCA_PythonController::Trigger(SCA_LogicManager* logicmgr) //PyRun_SimpleString(m_scriptText.Ptr()); } + // clear after PyErrPrint - seems it can be using + // something in this dictionary and crash? + PyDict_Clear(excdict); + Py_DECREF(excdict); + m_sCurrentController = NULL; } diff --git a/source/gameengine/GameLogic/SCA_RandomEventManager.cpp b/source/gameengine/GameLogic/SCA_RandomEventManager.cpp index 02020a52a17..156478d866d 100644 --- a/source/gameengine/GameLogic/SCA_RandomEventManager.cpp +++ b/source/gameengine/GameLogic/SCA_RandomEventManager.cpp @@ -50,16 +50,9 @@ SCA_RandomEventManager::SCA_RandomEventManager(class SCA_LogicManager* logicmgr) void SCA_RandomEventManager::NextFrame() { - for (vector<class SCA_ISensor*>::const_iterator i= m_sensors.begin();!(i==m_sensors.end());i++) + for (set<class SCA_ISensor*>::const_iterator i= m_sensors.begin();!(i==m_sensors.end());i++) { - SCA_ISensor *sensor = *i; - sensor->Activate(m_logicmgr, NULL); + (*i)->Activate(m_logicmgr, NULL); } } - - -void SCA_RandomEventManager::RegisterSensor(SCA_ISensor* sensor) -{ - m_sensors.push_back(sensor); -}; diff --git a/source/gameengine/GameLogic/SCA_RandomEventManager.h b/source/gameengine/GameLogic/SCA_RandomEventManager.h index 8c75ef665fa..79138c23c62 100644 --- a/source/gameengine/GameLogic/SCA_RandomEventManager.h +++ b/source/gameengine/GameLogic/SCA_RandomEventManager.h @@ -45,7 +45,6 @@ public: SCA_RandomEventManager(class SCA_LogicManager* logicmgr); virtual void NextFrame(); - virtual void RegisterSensor(SCA_ISensor* sensor); }; #endif //__KX_RANDOMEVENTMGR diff --git a/source/gameengine/GameLogic/SCA_TimeEventManager.cpp b/source/gameengine/GameLogic/SCA_TimeEventManager.cpp index 643f1247a52..b7fadd3d62c 100644 --- a/source/gameengine/GameLogic/SCA_TimeEventManager.cpp +++ b/source/gameengine/GameLogic/SCA_TimeEventManager.cpp @@ -65,6 +65,11 @@ void SCA_TimeEventManager::RegisterSensor(SCA_ISensor* sensor) // not yet } +void SCA_TimeEventManager::RemoveSensor(SCA_ISensor* sensor) +{ + // empty +} + void SCA_TimeEventManager::NextFrame(double curtime, double fixedtime) diff --git a/source/gameengine/GameLogic/SCA_TimeEventManager.h b/source/gameengine/GameLogic/SCA_TimeEventManager.h index 2fd39661a2d..bd57e12eb44 100644 --- a/source/gameengine/GameLogic/SCA_TimeEventManager.h +++ b/source/gameengine/GameLogic/SCA_TimeEventManager.h @@ -45,6 +45,7 @@ public: virtual void NextFrame(double curtime, double fixedtime); virtual void RegisterSensor(class SCA_ISensor* sensor); + virtual void RemoveSensor(class SCA_ISensor* sensor); void AddTimeProperty(CValue* timeval); void RemoveTimeProperty(CValue* timeval); }; diff --git a/source/gameengine/GamePlayer/common/windows/GPW_Canvas.h b/source/gameengine/GamePlayer/common/windows/GPW_Canvas.h index bb1abd71505..bf8cb720811 100644 --- a/source/gameengine/GamePlayer/common/windows/GPW_Canvas.h +++ b/source/gameengine/GamePlayer/common/windows/GPW_Canvas.h @@ -36,7 +36,7 @@ #include <iostream> #include <windows.h> -#include <gl/gl.h> +//#include <gl/gl.h> #include "GPC_Canvas.h" diff --git a/source/gameengine/GamePlayer/ghost/GPG_Application.cpp b/source/gameengine/GamePlayer/ghost/GPG_Application.cpp index b5ebffb9378..7be3b94d8ae 100644 --- a/source/gameengine/GamePlayer/ghost/GPG_Application.cpp +++ b/source/gameengine/GamePlayer/ghost/GPG_Application.cpp @@ -56,6 +56,7 @@ extern "C" #include "BLO_readfile.h" #include "BKE_global.h" #include "BKE_main.h" +#include "DNA_scene_types.h" #ifdef __cplusplus } #endif // __cplusplus @@ -647,7 +648,7 @@ bool GPG_Application::startEngine(void) PyDict_SetItemString(dictionaryobject, "GameLogic", initGameLogic(startscene)); // Same as importing the module initGameKeys(); initPythonConstraintBinding(); - + initMathutils(); @@ -669,6 +670,11 @@ bool GPG_Application::startEngine(void) m_ketsjiengine->StartEngine(true); m_engineRunning = true; + // Set the animation playback rate for ipo's and actions + // the framerate below should patch with FPS macro defined in blendef.h + // Could be in StartEngine set the framerate, we need the scene to do this + m_ketsjiengine->SetAnimFrameRate( (((double) G.scene->r.frs_sec) / G.scene->r.frs_sec_base) ); + } if (!m_engineRunning) diff --git a/source/gameengine/Ketsji/BL_BlenderShader.cpp b/source/gameengine/Ketsji/BL_BlenderShader.cpp index dd45d522b9f..a9a0771936c 100644 --- a/source/gameengine/Ketsji/BL_BlenderShader.cpp +++ b/source/gameengine/Ketsji/BL_BlenderShader.cpp @@ -1,6 +1,10 @@ #include "DNA_customdata_types.h" #include "DNA_material_types.h" +#include "DNA_scene_types.h" + +#include "BKE_global.h" +#include "BKE_main.h" #include "BL_BlenderShader.h" #include "BL_Material.h" @@ -10,30 +14,51 @@ #include "GPU_material.h" #endif +#include "RAS_BucketManager.h" #include "RAS_MeshObject.h" #include "RAS_IRasterizer.h" + + /* this is evil, but we need the scene to create materials with + * lights from the correct scene .. */ +static struct Scene *GetSceneForName(const STR_String& scenename) +{ + Scene *sce; + + for (sce= (Scene*)G.main->scene.first; sce; sce= (Scene*)sce->id.next) + if (scenename == (sce->id.name+2)) + return sce; -const bool BL_BlenderShader::Ok()const + return (Scene*)G.main->scene.first; +} + +bool BL_BlenderShader::Ok() { #ifdef BLENDER_GLSL - return (mGPUMat != 0); + VerifyShader(); + + return (mMat && mMat->gpumaterial); #else return 0; #endif } -BL_BlenderShader::BL_BlenderShader(struct Material *ma, int lightlayer) +BL_BlenderShader::BL_BlenderShader(KX_Scene *scene, struct Material *ma, int lightlayer) : #ifdef BLENDER_GLSL - mGPUMat(0), + mScene(scene), + mMat(ma), + mGPUMat(NULL), #endif mBound(false), mLightLayer(lightlayer) { #ifdef BLENDER_GLSL - if(ma) { - GPU_material_from_blender(ma); - mGPUMat = ma->gpumaterial; + mBlenderScene = GetSceneForName(scene->GetName()); + mBlendMode = GPU_BLEND_SOLID; + + if(mMat) { + GPU_material_from_blender(mBlenderScene, mMat); + mGPUMat = mMat->gpumaterial; } #endif } @@ -41,17 +66,29 @@ BL_BlenderShader::BL_BlenderShader(struct Material *ma, int lightlayer) BL_BlenderShader::~BL_BlenderShader() { #ifdef BLENDER_GLSL - if(mGPUMat) { - GPU_material_unbind(mGPUMat); - mGPUMat = 0; - } + if(mMat && mMat->gpumaterial) + GPU_material_unbind(mMat->gpumaterial); +#endif +} + +bool BL_BlenderShader::VerifyShader() +{ +#ifdef BLENDER_GLSL + if(mMat && !mMat->gpumaterial) + GPU_material_from_blender(mBlenderScene, mMat); + + mGPUMat = mMat->gpumaterial; + + return (mMat && mGPUMat); +#else + return false; #endif } void BL_BlenderShader::SetProg(bool enable) { #ifdef BLENDER_GLSL - if(mGPUMat) { + if(VerifyShader()) { if(enable) { GPU_material_bind(mGPUMat, mLightLayer); mBound = true; @@ -70,7 +107,7 @@ int BL_BlenderShader::GetAttribNum() GPUVertexAttribs attribs; int i, enabled = 0; - if(!mGPUMat) + if(!VerifyShader()) return enabled; GPU_material_vertex_attributes(mGPUMat, &attribs); @@ -96,7 +133,7 @@ void BL_BlenderShader::SetAttribs(RAS_IRasterizer* ras, const BL_Material *mat) ras->SetAttribNum(0); - if(!mGPUMat) + if(!VerifyShader()) return; if(ras->GetDrawingMode() == RAS_IRasterizer::KX_TEXTURED) { @@ -142,9 +179,11 @@ void BL_BlenderShader::SetAttribs(RAS_IRasterizer* ras, const BL_Material *mat) void BL_BlenderShader::Update( const KX_MeshSlot & ms, RAS_IRasterizer* rasty ) { #ifdef BLENDER_GLSL - float obmat[4][4], viewmat[4][4], viewinvmat[4][4]; + float obmat[4][4], viewmat[4][4], viewinvmat[4][4], obcol[4]; + + VerifyShader(); - if(!mGPUMat || !mBound) + if(!mGPUMat) // || !mBound) return; MT_Matrix4x4 model; @@ -158,10 +197,22 @@ void BL_BlenderShader::Update( const KX_MeshSlot & ms, RAS_IRasterizer* rasty ) view.invert(); view.getValue((float*)viewinvmat); - GPU_material_bind_uniforms(mGPUMat, obmat, viewmat, viewinvmat); + if(ms.m_bObjectColor) + ms.m_RGBAcolor.getValue((float*)obcol); + else + obcol[0]= obcol[1]= obcol[2]= obcol[3]= 1.0f; + + GPU_material_bind_uniforms(mGPUMat, obmat, viewmat, viewinvmat, obcol); + + mBlendMode = GPU_material_blend_mode(mGPUMat, obcol); #endif } +int BL_BlenderShader::GetBlendMode() +{ + return mBlendMode; +} + bool BL_BlenderShader::Equals(BL_BlenderShader *blshader) { #ifdef BLENDER_GLSL diff --git a/source/gameengine/Ketsji/BL_BlenderShader.h b/source/gameengine/Ketsji/BL_BlenderShader.h index b758d1a9cba..da9765dafa4 100644 --- a/source/gameengine/Ketsji/BL_BlenderShader.h +++ b/source/gameengine/Ketsji/BL_BlenderShader.h @@ -14,7 +14,10 @@ #include "RAS_IPolygonMaterial.h" +#include "KX_Scene.h" + struct Material; +struct Scene; class BL_Material; #define BL_MAX_ATTRIB 16 @@ -27,21 +30,28 @@ class BL_BlenderShader { private: #ifdef BLENDER_GLSL + KX_Scene *mScene; + struct Scene *mBlenderScene; + struct Material *mMat; GPUMaterial *mGPUMat; #endif bool mBound; int mLightLayer; + int mBlendMode; + + bool VerifyShader(); public: - BL_BlenderShader(struct Material *ma, int lightlayer); + BL_BlenderShader(KX_Scene *scene, struct Material *ma, int lightlayer); virtual ~BL_BlenderShader(); - const bool Ok()const; + bool Ok(); void SetProg(bool enable); int GetAttribNum(); void SetAttribs(class RAS_IRasterizer* ras, const BL_Material *mat); void Update(const class KX_MeshSlot & ms, class RAS_IRasterizer* rasty); + int GetBlendMode(); bool Equals(BL_BlenderShader *blshader); }; diff --git a/source/gameengine/Ketsji/BL_Material.h b/source/gameengine/Ketsji/BL_Material.h index 568f7e171de..dcb66ea2579 100644 --- a/source/gameengine/Ketsji/BL_Material.h +++ b/source/gameengine/Ketsji/BL_Material.h @@ -129,8 +129,7 @@ enum BL_flag TEXALPHA=8, // use alpha combiner functions TEXNEG=16, // negate blending HASIPO=32, - USENEGALPHA=64, - ALPHA_TEST=128 + USENEGALPHA=64 }; // BL_Material::ras_mode @@ -139,7 +138,7 @@ enum BL_ras_mode POLY_VIS=1, COLLIDER=2, ZSORT=4, - TRANSP=8, + ALPHA=8, TRIANGLE=16, USE_LIGHT=32, WIRE=64 diff --git a/source/gameengine/Ketsji/BL_Texture.cpp b/source/gameengine/Ketsji/BL_Texture.cpp index f24ef4322f0..f0ef84032f7 100644 --- a/source/gameengine/Ketsji/BL_Texture.cpp +++ b/source/gameengine/Ketsji/BL_Texture.cpp @@ -384,8 +384,6 @@ void BL_Texture::DisableUnit() void BL_Texture::DisableAllTextures() { - glDisable(GL_BLEND); - for(int i=0; i<MAXTEX; i++) { if(GLEW_ARB_multitexture) glActiveTextureARB(GL_TEXTURE0_ARB+i); diff --git a/source/gameengine/Ketsji/CMakeLists.txt b/source/gameengine/Ketsji/CMakeLists.txt index 3b907d8d530..be009d94701 100644 --- a/source/gameengine/Ketsji/CMakeLists.txt +++ b/source/gameengine/Ketsji/CMakeLists.txt @@ -25,6 +25,17 @@ # ***** END GPL LICENSE BLOCK ***** FILE(GLOB SRC *.cpp) +SET(SRC + ${SRC} + ../../../source/blender/python/api2_2x/Mathutils.c + ../../../source/blender/python/api2_2x/constant.c + ../../../source/blender/python/api2_2x/euler.c + ../../../source/blender/python/api2_2x/gen_utils.c + ../../../source/blender/python/api2_2x/matrix.c + ../../../source/blender/python/api2_2x/point.c + ../../../source/blender/python/api2_2x/quat.c + ../../../source/blender/python/api2_2x/vector.c +) SET(INC . @@ -39,7 +50,8 @@ SET(INC ../../../intern/moto/include ../../../source/gameengine/Ketsji ../../../source/blender/blenlib - ../../../source/blender/blenkernel + ../../../source/blender/blenkernel + ../../../source/blender/python/api2_2x ../../../source/blender ../../../source/blender/include ../../../source/blender/makesdna diff --git a/source/gameengine/Ketsji/KXNetwork/KX_NetworkEventManager.cpp b/source/gameengine/Ketsji/KXNetwork/KX_NetworkEventManager.cpp index 7b5b7fdf78c..eee8e9f6827 100644 --- a/source/gameengine/Ketsji/KXNetwork/KX_NetworkEventManager.cpp +++ b/source/gameengine/Ketsji/KXNetwork/KX_NetworkEventManager.cpp @@ -55,28 +55,13 @@ KX_NetworkEventManager::~KX_NetworkEventManager() //printf("KX_NetworkEventManager destructor\n"); } -void KX_NetworkEventManager::RegisterSensor(class SCA_ISensor* sensor) -{ - //printf("KX_NetworkEventManager RegisterSensor\n"); - m_sensors.push_back(sensor); -} - -void KX_NetworkEventManager::RemoveSensor(class SCA_ISensor* sensor) -{ - //printf("KX_NetworkEventManager RemoveSensor\n"); - // Network specific RemoveSensor stuff goes here - - // parent - SCA_EventManager::RemoveSensor(sensor); -} - void KX_NetworkEventManager::NextFrame() { // printf("KX_NetworkEventManager::proceed %.2f - %.2f\n", curtime, deltatime); // each frame, the logicmanager will call the network // eventmanager to look for network events, and process it's // 'network' sensors - vector<class SCA_ISensor*>::iterator it; + set<class SCA_ISensor*>::iterator it; for (it = m_sensors.begin(); !(it==m_sensors.end()); it++) { // printf("KX_NetworkEventManager::proceed sensor %.2f\n", curtime); diff --git a/source/gameengine/Ketsji/KXNetwork/KX_NetworkEventManager.h b/source/gameengine/Ketsji/KXNetwork/KX_NetworkEventManager.h index 0b097ba2ef6..ae88f1d4987 100644 --- a/source/gameengine/Ketsji/KXNetwork/KX_NetworkEventManager.h +++ b/source/gameengine/Ketsji/KXNetwork/KX_NetworkEventManager.h @@ -42,9 +42,6 @@ public: class NG_NetworkDeviceInterface *ndi); virtual ~KX_NetworkEventManager (); - virtual void RegisterSensor(class SCA_ISensor* sensor); - virtual void RemoveSensor(class SCA_ISensor* sensor); - virtual void NextFrame(); virtual void EndFrame(); diff --git a/source/gameengine/Ketsji/KX_BlenderMaterial.cpp b/source/gameengine/Ketsji/KX_BlenderMaterial.cpp index 0f445a9f32e..a67e5b26667 100644 --- a/source/gameengine/Ketsji/KX_BlenderMaterial.cpp +++ b/source/gameengine/Ketsji/KX_BlenderMaterial.cpp @@ -38,6 +38,7 @@ extern "C" { // ------------------------------------ #define spit(x) std::cout << x << std::endl; +BL_Shader *KX_BlenderMaterial::mLastShader = NULL; BL_BlenderShader *KX_BlenderMaterial::mLastBlenderShader = NULL; //static PyObject *gTextureDict = 0; @@ -58,7 +59,8 @@ KX_BlenderMaterial::KX_BlenderMaterial( data->tilexrep[0], data->tileyrep[0], data->mode, - ((data->ras_mode &TRANSP)!=0), + data->transp, + ((data->ras_mode &ALPHA)!=0), ((data->ras_mode &ZSORT)!=0), lightlayer, ((data->ras_mode &TRIANGLE)!=0), @@ -79,7 +81,6 @@ KX_BlenderMaterial::KX_BlenderMaterial( m_flag |=RAS_BLENDERMAT; m_flag |=(mMaterial->IdMode>=ONETEX)?RAS_MULTITEX:0; m_flag |=(mMaterial->ras_mode & USE_LIGHT)!=0?RAS_MULTILIGHT:0; - m_flag |=(mMaterial->ras_mode &ALPHA_TEST)!=0?RAS_FORCEALPHA:0; // figure max int enabled = mMaterial->num_enabled; @@ -158,12 +159,29 @@ void KX_BlenderMaterial::OnConstruction() mConstructed = true; } +void KX_BlenderMaterial::EndFrame() +{ + if(mLastBlenderShader) { + mLastBlenderShader->SetProg(false); + mLastBlenderShader = NULL; + } + + if(mLastShader) { + mLastShader->SetProg(false); + mLastShader = NULL; + } +} + void KX_BlenderMaterial::OnExit() { if( mShader ) { - //note, the shader here is allocated, per unique material - //and this function is called per face - mShader->SetProg(false); + //note, the shader here is allocated, per unique material + //and this function is called per face + if(mShader == mLastShader) { + mShader->SetProg(false); + mLastShader = NULL; + } + delete mShader; mShader = 0; } @@ -197,13 +215,19 @@ void KX_BlenderMaterial::setShaderData( bool enable, RAS_IRasterizer *ras) int i; if( !enable || !mShader->Ok() ) { // frame cleanup. - mShader->SetProg(false); + if(mShader == mLastShader) { + mShader->SetProg(false); + mLastShader = NULL; + } + + ras->SetBlendingMode(TF_SOLID); BL_Texture::DisableAllTextures(); return; } BL_Texture::DisableAllTextures(); mShader->SetProg(true); + mLastShader = mShader; BL_Texture::ActivateFirst(); @@ -217,9 +241,12 @@ void KX_BlenderMaterial::setShaderData( bool enable, RAS_IRasterizer *ras) } if(!mUserDefBlend) { - setDefaultBlending(); + ras->SetBlendingMode(mMaterial->transp); } else { + ras->SetBlendingMode(TF_SOLID); + ras->SetBlendingMode(-1); // indicates custom mode + // tested to be valid enums glEnable(GL_BLEND); glBlendFunc(mBlendFunc[0], mBlendFunc[1]); @@ -234,11 +261,14 @@ void KX_BlenderMaterial::setBlenderShaderData( bool enable, RAS_IRasterizer *ras mLastBlenderShader->SetProg(false); mLastBlenderShader= NULL; } + + ras->SetBlendingMode(TF_SOLID); BL_Texture::DisableAllTextures(); return; } if(!mBlenderShader->Equals(mLastBlenderShader)) { + ras->SetBlendingMode(mMaterial->transp); BL_Texture::DisableAllTextures(); if(mLastBlenderShader) @@ -251,17 +281,17 @@ void KX_BlenderMaterial::setBlenderShaderData( bool enable, RAS_IRasterizer *ras void KX_BlenderMaterial::setTexData( bool enable, RAS_IRasterizer *ras) { - if(GLEW_ARB_shader_objects && mShader) - mShader->SetProg(false); - BL_Texture::DisableAllTextures(); - if( !enable ) + + if( !enable ) { + ras->SetBlendingMode(TF_SOLID); return; + } BL_Texture::ActivateFirst(); if( mMaterial->IdMode == DEFAULT_BLENDER ) { - setDefaultBlending(); + ras->SetBlendingMode(mMaterial->transp); return; } @@ -271,7 +301,7 @@ void KX_BlenderMaterial::setTexData( bool enable, RAS_IRasterizer *ras) mTextures[0].ActivateTexture(); mTextures[0].setTexEnv(0, true); mTextures[0].SetMapping(mMaterial->mapping[0].mapping); - setDefaultBlending(); + ras->SetBlendingMode(mMaterial->transp); } return; } @@ -294,9 +324,12 @@ void KX_BlenderMaterial::setTexData( bool enable, RAS_IRasterizer *ras) } if(!mUserDefBlend) { - setDefaultBlending(); + ras->SetBlendingMode(mMaterial->transp); } else { + ras->SetBlendingMode(TF_SOLID); + ras->SetBlendingMode(-1); // indicates custom mode + glEnable(GL_BLEND); glBlendFunc(mBlendFunc[0], mBlendFunc[1]); } @@ -356,6 +389,11 @@ KX_BlenderMaterial::ActivateBlenderShaders( { KX_BlenderMaterial *tmp = const_cast<KX_BlenderMaterial*>(this); + if(mLastShader) { + mLastShader->SetProg(false); + mLastShader= NULL; + } + // reset... if(tmp->mMaterial->IsShared()) cachingInfo =0; @@ -402,6 +440,11 @@ KX_BlenderMaterial::ActivateMat( { KX_BlenderMaterial *tmp = const_cast<KX_BlenderMaterial*>(this); + if(mLastShader) { + mLastShader->SetProg(false); + mLastShader= NULL; + } + if(mLastBlenderShader) { mLastBlenderShader->SetProg(false); mLastBlenderShader= NULL; @@ -451,7 +494,10 @@ KX_BlenderMaterial::Activate( return dopass; } else { - mShader->SetProg(false); + if(mShader == mLastShader) { + mShader->SetProg(false); + mLastShader = NULL; + } mPass = 0; dopass = false; return dopass; @@ -499,10 +545,22 @@ bool KX_BlenderMaterial::UsesLighting(RAS_IRasterizer *rasty) const void KX_BlenderMaterial::ActivateMeshSlot(const KX_MeshSlot & ms, RAS_IRasterizer* rasty) const { - if(mShader && GLEW_ARB_shader_objects) + if(mShader && GLEW_ARB_shader_objects) { mShader->Update(ms, rasty); - else if(mBlenderShader && GLEW_ARB_shader_objects) + } + else if(mBlenderShader && GLEW_ARB_shader_objects) { + int blendmode; + mBlenderShader->Update(ms, rasty); + + /* we do blend modes here, because they can change per object + * with the same material due to obcolor */ + blendmode = mBlenderShader->GetBlendMode(); + if((blendmode == TF_SOLID || blendmode == TF_ALPHA) && mMaterial->transp != TF_SOLID) + blendmode = mMaterial->transp; + + rasty->SetBlendingMode(blendmode); + } } void KX_BlenderMaterial::ActivatGLMaterials( RAS_IRasterizer* rasty )const @@ -582,31 +640,6 @@ void KX_BlenderMaterial::ActivateTexGen(RAS_IRasterizer *ras) const ras->EnableTextures(false); } -bool KX_BlenderMaterial::setDefaultBlending() -{ - if( mMaterial->transp &TF_ADD) { - glEnable(GL_BLEND); - glBlendFunc(GL_ONE, GL_ONE); - glDisable ( GL_ALPHA_TEST ); - return true; - } - - if( mMaterial->transp & TF_ALPHA ) { - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glDisable ( GL_ALPHA_TEST ); - return true; - } - - if( mMaterial->transp & TF_CLIP ) { - glDisable(GL_BLEND); - glEnable ( GL_ALPHA_TEST ); - glAlphaFunc(GL_GREATER, 0.5f); - return false; - } - return false; -} - void KX_BlenderMaterial::setTexMatrixData(int i) { glMatrixMode(GL_TEXTURE); @@ -831,12 +864,14 @@ KX_PYMETHODDEF_DOC( KX_BlenderMaterial, getShader , "getShader()") void KX_BlenderMaterial::SetBlenderGLSLShader(void) { if(!mBlenderShader) - mBlenderShader = new BL_BlenderShader(mMaterial->material, m_lightlayer); + mBlenderShader = new BL_BlenderShader(mScene, mMaterial->material, m_lightlayer); if(!mBlenderShader->Ok()) { delete mBlenderShader; mBlenderShader = 0; } + else + m_flag |= RAS_BLENDERGLSL; } KX_PYMETHODDEF_DOC( KX_BlenderMaterial, getMaterialIndex, "getMaterialIndex()") diff --git a/source/gameengine/Ketsji/KX_BlenderMaterial.h b/source/gameengine/Ketsji/KX_BlenderMaterial.h index bf6d2095e7c..0d7657b8cdb 100644 --- a/source/gameengine/Ketsji/KX_BlenderMaterial.h +++ b/source/gameengine/Ketsji/KX_BlenderMaterial.h @@ -90,11 +90,13 @@ public: // -------------------------------- // pre calculate to avoid pops/lag at startup virtual void OnConstruction( ); + + static void EndFrame(); + private: BL_Material* mMaterial; BL_Shader* mShader; BL_BlenderShader* mBlenderShader; - static BL_BlenderShader *mLastBlenderShader; KX_Scene* mScene; BL_Texture mTextures[MAXTEX]; // texture array bool mUserDefBlend; @@ -114,7 +116,6 @@ private: void setBlenderShaderData( bool enable, RAS_IRasterizer *ras); void setShaderData( bool enable, RAS_IRasterizer *ras); - bool setDefaultBlending(); void setObjectMatrixData(int i, RAS_IRasterizer *ras); void setTexMatrixData(int i); @@ -123,6 +124,10 @@ private: // cleanup stuff void OnExit(); + // shader chacing + static BL_BlenderShader *mLastBlenderShader; + static BL_Shader *mLastShader; + mutable int mPass; }; diff --git a/source/gameengine/Ketsji/KX_GameObject.cpp b/source/gameengine/Ketsji/KX_GameObject.cpp index 3d9c7aafd70..989cdabd491 100644 --- a/source/gameengine/Ketsji/KX_GameObject.cpp +++ b/source/gameengine/Ketsji/KX_GameObject.cpp @@ -77,10 +77,10 @@ KX_GameObject::KX_GameObject( SCA_IObject(T), m_bDyna(false), m_layer(0), + m_pBlenderObject(NULL), m_bSuspendDynamics(false), m_bUseObjectColor(false), m_bIsNegativeScaling(false), - m_pBlenderObject(NULL), m_bVisible(true), m_pPhysicsController1(NULL), m_pPhysicsEnvironment(NULL), @@ -96,12 +96,9 @@ KX_GameObject::KX_GameObject( KX_NormalParentRelation * parent_relation = KX_NormalParentRelation::New(); m_pSGNode->SetParentRelation(parent_relation); - - }; - KX_GameObject::~KX_GameObject() { // is this delete somewhere ? @@ -165,6 +162,7 @@ STR_String KX_GameObject::GetName() void KX_GameObject::SetName(STR_String name) { m_name = name; + }; // Set the name of the value @@ -277,6 +275,7 @@ void KX_GameObject::ProcessReplica(KX_GameObject* replica) replica->m_pSGNode = NULL; replica->m_pClient_info = new KX_ClientObjectInfo(*m_pClient_info); replica->m_pClient_info->m_gameobject = replica; + replica->m_state = 0; } @@ -454,12 +453,13 @@ KX_GameObject::UpdateMaterialData( ) { int mesh = 0; + if (((unsigned int)mesh < m_meshes.size()) && mesh >= 0) { RAS_MaterialBucket::Set::iterator mit = m_meshes[mesh]->GetFirstMaterial(); for(; mit != m_meshes[mesh]->GetLastMaterial(); ++mit) { RAS_IPolyMaterial* poly = (*mit)->GetPolyMaterial(); - if(poly->GetFlag() & RAS_BLENDERMAT ) + if(poly->GetFlag() & RAS_BLENDERMAT) { KX_BlenderMaterial *m = static_cast<KX_BlenderMaterial*>(poly); @@ -467,7 +467,8 @@ KX_GameObject::UpdateMaterialData( { m->UpdateIPO(rgba, specrgb,hard,spec,ref,emit, alpha); // if mesh has only one material attached to it then use original hack with no need to edit vertices (better performance) - SetObjectColor(rgba); + if(!(poly->GetFlag() & RAS_BLENDERGLSL)) + SetObjectColor(rgba); } else { @@ -913,6 +914,7 @@ PyMethodDef KX_GameObject::Methods[] = { KX_PYMETHODTABLE(KX_GameObject, rayCastTo), KX_PYMETHODTABLE(KX_GameObject, rayCast), KX_PYMETHODTABLE(KX_GameObject, getDistanceTo), + KX_PYMETHODTABLE(KX_GameObject, getVectTo), {NULL,NULL} //Sentinel }; @@ -1366,14 +1368,15 @@ PyObject* KX_GameObject::PyGetMesh(PyObject* self, { int mesh = 0; - if (PyArg_ParseTuple(args, "|i", &mesh)) + if (!PyArg_ParseTuple(args, "|i", &mesh)) + return NULL; // python sets a simple error + + if (((unsigned int)mesh < m_meshes.size()) && mesh >= 0) { - if (((unsigned int)mesh < m_meshes.size()) && mesh >= 0) - { - KX_MeshProxy* meshproxy = new KX_MeshProxy(m_meshes[mesh]); - return meshproxy; - } + KX_MeshProxy* meshproxy = new KX_MeshProxy(m_meshes[mesh]); + return meshproxy; } + Py_RETURN_NONE; } @@ -1487,6 +1490,9 @@ PyObject* KX_GameObject::PyAlignAxisToVect(PyObject* self, MT_Vector3 vect; if (PyVecTo(pyvect, vect)) { + if (fac<=0.0) Py_RETURN_NONE; // Nothing to do. + if (fac> 1.0) fac= 1.0; + AlignAxisToVect(vect,axis,fac); NodeUpdateGS(0.f,true); Py_RETURN_NONE; @@ -1554,6 +1560,54 @@ KX_PYMETHODDEF_DOC(KX_GameObject, getDistanceTo, return NULL; } +KX_PYMETHODDEF_DOC(KX_GameObject, getVectTo, +"getVectTo(other): get vector and the distance to another point/KX_GameObject\n" +"Returns a 3-tuple with (distance,worldVector,localVector)\n") +{ + MT_Point3 toPoint, fromPoint; + MT_Vector3 toDir, locToDir; + MT_Scalar distance; + + PyObject *returnValue; + PyObject *pyother; + + if (!PyVecArgTo(args, toPoint)) + { + PyErr_Clear(); + if (PyArg_ParseTuple(args, "O!", &KX_GameObject::Type, &pyother)) + { + KX_GameObject *other = static_cast<KX_GameObject*>(pyother); + toPoint = other->NodeGetWorldPosition(); + }else + { + PyErr_SetString(PyExc_TypeError, "Expected a 3D Vector or GameObject type"); + return NULL; + } + } + + fromPoint = NodeGetWorldPosition(); + toDir = toPoint-fromPoint; + distance = toDir.length(); + + if (MT_fuzzyZero(distance)) + { + //cout << "getVectTo() Error: Null vector!\n"; + locToDir = toDir = MT_Vector3(0.0,0.0,0.0); + distance = 0.0; + } else { + toDir.normalize(); + locToDir = toDir * NodeGetWorldOrientation(); + } + + returnValue = PyTuple_New(3); + if (returnValue) { // very unlikely to fail, python sets a memory error here. + PyTuple_SET_ITEM(returnValue, 0, PyFloat_FromDouble(distance)); + PyTuple_SET_ITEM(returnValue, 1, PyObjectFrom(toDir)); + PyTuple_SET_ITEM(returnValue, 2, PyObjectFrom(locToDir)); + } + return returnValue; +} + bool KX_GameObject::RayHit(KX_ClientObjectInfo* client, MT_Point3& hit_point, MT_Vector3& hit_normal, void * const data) { @@ -1587,8 +1641,7 @@ KX_PYMETHODDEF_DOC(KX_GameObject, rayCastTo, char *propName = NULL; if (!PyArg_ParseTuple(args,"O|fs", &pyarg, &dist, &propName)) { - PyErr_SetString(PyExc_TypeError, "Invalid arguments"); - return NULL; + return NULL; // python sets simple error } if (!PyVecTo(pyarg, toPoint)) @@ -1653,8 +1706,7 @@ KX_PYMETHODDEF_DOC(KX_GameObject, rayCast, KX_GameObject *other; if (!PyArg_ParseTuple(args,"O|Ofs", &pyto, &pyfrom, &dist, &propName)) { - PyErr_SetString(PyExc_TypeError, "Invalid arguments"); - return NULL; + return NULL; // Python sets a simple error } if (!PyVecTo(pyto, toPoint)) @@ -1713,13 +1765,11 @@ KX_PYMETHODDEF_DOC(KX_GameObject, rayCast, if (m_pHitObject) { PyObject* returnValue = PyTuple_New(3); - if (!returnValue) { - PyErr_SetString(PyExc_TypeError, "PyTuple_New() failed"); - return NULL; + 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, 0, m_pHitObject->AddRef()); - PyTuple_SET_ITEM(returnValue, 1, PyObjectFrom(resultPoint)); - PyTuple_SET_ITEM(returnValue, 2, PyObjectFrom(resultNormal)); return returnValue; } 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 1d36798b12f..4e435e9ddf4 100644 --- a/source/gameengine/Ketsji/KX_GameObject.h +++ b/source/gameengine/Ketsji/KX_GameObject.h @@ -756,6 +756,7 @@ public: KX_PYMETHOD_DOC(KX_GameObject,rayCastTo); KX_PYMETHOD_DOC(KX_GameObject,rayCast); KX_PYMETHOD_DOC(KX_GameObject,getDistanceTo); + KX_PYMETHOD_DOC(KX_GameObject,getVectTo); private : diff --git a/source/gameengine/Ketsji/KX_KetsjiEngine.cpp b/source/gameengine/Ketsji/KX_KetsjiEngine.cpp index db099d56b55..1d6cc975ab5 100644 --- a/source/gameengine/Ketsji/KX_KetsjiEngine.cpp +++ b/source/gameengine/Ketsji/KX_KetsjiEngine.cpp @@ -118,7 +118,6 @@ KX_KetsjiEngine::KX_KetsjiEngine(KX_ISystem* system) m_bInitialized(false), m_activecam(0), m_bFixedTime(false), - m_game2ipo(false), m_firstframe(true), @@ -148,6 +147,8 @@ KX_KetsjiEngine::KX_KetsjiEngine(KX_ISystem* system) m_showBackground(false), m_show_debug_properties(false), + m_game2ipo(false), + // Default behavior is to hide the cursor every frame. m_hideCursor(false), diff --git a/source/gameengine/Ketsji/KX_NearSensor.cpp b/source/gameengine/Ketsji/KX_NearSensor.cpp index 89699d80031..140dd37f5c6 100644 --- a/source/gameengine/Ketsji/KX_NearSensor.cpp +++ b/source/gameengine/Ketsji/KX_NearSensor.cpp @@ -98,6 +98,14 @@ void KX_NearSensor::RegisterSumo(KX_TouchEventManager *touchman) } } +void KX_NearSensor::UnregisterSumo(KX_TouchEventManager* touchman) +{ + if (m_physCtrl) + { + touchman->GetPhysicsEnvironment()->removeSensor(m_physCtrl); + } +} + CValue* KX_NearSensor::GetReplica() { KX_NearSensor* replica = new KX_NearSensor(*this); diff --git a/source/gameengine/Ketsji/KX_NearSensor.h b/source/gameengine/Ketsji/KX_NearSensor.h index c6724caccc3..3f7078ef9fd 100644 --- a/source/gameengine/Ketsji/KX_NearSensor.h +++ b/source/gameengine/Ketsji/KX_NearSensor.h @@ -77,6 +77,7 @@ public: const PHY_CollData * coll_data); virtual bool BroadPhaseFilterCollision(void*obj1,void*obj2); virtual void RegisterSumo(KX_TouchEventManager *touchman); + virtual void UnregisterSumo(KX_TouchEventManager* touchman); virtual PyObject* _getattr(const STR_String& attr); diff --git a/source/gameengine/Ketsji/KX_PolygonMaterial.cpp b/source/gameengine/Ketsji/KX_PolygonMaterial.cpp index 93d6d5bb70d..144f74a1a4c 100644 --- a/source/gameengine/Ketsji/KX_PolygonMaterial.cpp +++ b/source/gameengine/Ketsji/KX_PolygonMaterial.cpp @@ -59,7 +59,8 @@ KX_PolygonMaterial::KX_PolygonMaterial(const STR_String &texname, int tilexrep, int tileyrep, int mode, - bool transparant, + int transp, + bool alpha, bool zsort, int lightlayer, bool bIsTriangle, @@ -74,7 +75,8 @@ KX_PolygonMaterial::KX_PolygonMaterial(const STR_String &texname, tilexrep, tileyrep, mode, - transparant, + transp, + alpha, zsort, lightlayer, bIsTriangle, @@ -245,7 +247,7 @@ PyObject* KX_PolygonMaterial::_getattr(const STR_String& attr) if (attr == "drawingmode") return PyInt_FromLong(m_drawingmode); if (attr == "transparent") - return PyInt_FromLong(m_transparant); + return PyInt_FromLong(m_alpha); if (attr == "zsort") return PyInt_FromLong(m_zsort); if (attr == "lightlayer") @@ -312,7 +314,7 @@ int KX_PolygonMaterial::_setattr(const STR_String &attr, PyObject *pyvalue) if (attr == "transparent") { - m_transparant = value; + m_alpha = value; return 0; } diff --git a/source/gameengine/Ketsji/KX_PolygonMaterial.h b/source/gameengine/Ketsji/KX_PolygonMaterial.h index 19015494e06..11c8baa8b1f 100644 --- a/source/gameengine/Ketsji/KX_PolygonMaterial.h +++ b/source/gameengine/Ketsji/KX_PolygonMaterial.h @@ -64,7 +64,8 @@ public: int tilexrep, int tileyrep, int mode, - bool transparant, + int transp, + bool alpha, bool zsort, int lightlayer, bool bIsTriangle, diff --git a/source/gameengine/Ketsji/KX_PythonInit.cpp b/source/gameengine/Ketsji/KX_PythonInit.cpp index b66c3e42606..db4793de23d 100644 --- a/source/gameengine/Ketsji/KX_PythonInit.cpp +++ b/source/gameengine/Ketsji/KX_PythonInit.cpp @@ -62,6 +62,10 @@ #include "KX_PyMath.h" +extern "C" { + #include "Mathutils.h" // Blender.Mathutils module copied here so the blenderlayer can use. +} + #include "PHY_IPhysicsEnvironment.h" // FIXME: Enable for access to blender python modules. This is disabled because // python has dependencies on a lot of other modules and is a pain to link. @@ -733,7 +737,7 @@ PyObject* initGameLogic(KX_Scene* scene) // quick hack to get gravity hook ErrorObject = PyString_FromString("GameLogic.error"); PyDict_SetItemString(d, "error", ErrorObject); - + // XXXX Add constants here /* To use logic bricks, we need some sort of constants. Here, we associate */ /* constants and sumbolic names. Add them to dictionary d. */ @@ -876,7 +880,7 @@ PyObject *KXpy_import(PyObject *self, PyObject *args) /* quick hack for GamePython modules TODO: register builtin modules properly by ExtendInittab */ if (!strcmp(name, "GameLogic") || !strcmp(name, "GameKeys") || !strcmp(name, "PhysicsConstraints") || - !strcmp(name, "Rasterizer")) { + !strcmp(name, "Rasterizer") || !strcmp(name, "Mathutils")) { return PyImport_ImportModuleEx(name, globals, locals, fromlist); } @@ -1169,6 +1173,11 @@ PyObject* initGameKeys() return d; } +PyObject* initMathutils() +{ + return Mathutils_Init("Mathutils"); // Use as a top level module in BGE +} + void PHY_SetActiveScene(class KX_Scene* scene) { gp_KetsjiScene = scene; diff --git a/source/gameengine/Ketsji/KX_PythonInit.h b/source/gameengine/Ketsji/KX_PythonInit.h index 41cf7fd67b3..f094a1ca575 100644 --- a/source/gameengine/Ketsji/KX_PythonInit.h +++ b/source/gameengine/Ketsji/KX_PythonInit.h @@ -44,6 +44,7 @@ PyObject* initGameLogic(class KX_Scene* ketsjiscene); PyObject* initGameKeys(); PyObject* initRasterizer(class RAS_IRasterizer* rasty,class RAS_ICanvas* canvas); PyObject* initGamePlayerPythonScripting(const STR_String& progname, TPythonSecurityLevel level); +PyObject* initMathutils(); void exitGamePlayerPythonScripting(); PyObject* initGamePythonScripting(const STR_String& progname, TPythonSecurityLevel level); void exitGamePythonScripting(); diff --git a/source/gameengine/Ketsji/KX_RadarSensor.cpp b/source/gameengine/Ketsji/KX_RadarSensor.cpp index de4979ac4c9..d371626b597 100644 --- a/source/gameengine/Ketsji/KX_RadarSensor.cpp +++ b/source/gameengine/Ketsji/KX_RadarSensor.cpp @@ -147,23 +147,23 @@ void KX_RadarSensor::SynchronizeTransform() }; case 3: // -X Axis { - MT_Quaternion rotquatje(MT_Vector3(0,0,1),MT_radians(90)); + MT_Quaternion rotquatje(MT_Vector3(0,0,1),MT_radians(-90)); trans.rotate(rotquatje); - trans.translate(MT_Vector3 (0, m_coneheight/2.0 ,0)); + trans.translate(MT_Vector3 (0, -m_coneheight/2.0 ,0)); break; }; case 4: // -Y Axis { - MT_Quaternion rotquatje(MT_Vector3(1,0,0),MT_radians(-180)); - trans.rotate(rotquatje); - trans.translate(MT_Vector3 (0, m_coneheight/2.0 ,0)); + //MT_Quaternion rotquatje(MT_Vector3(1,0,0),MT_radians(-180)); + //trans.rotate(rotquatje); + trans.translate(MT_Vector3 (0, -m_coneheight/2.0 ,0)); break; }; case 5: // -Z Axis { - MT_Quaternion rotquatje(MT_Vector3(1,0,0),MT_radians(-90)); + MT_Quaternion rotquatje(MT_Vector3(1,0,0),MT_radians(90)); trans.rotate(rotquatje); - trans.translate(MT_Vector3 (0, m_coneheight/2.0 ,0)); + trans.translate(MT_Vector3 (0, -m_coneheight/2.0 ,0)); break; }; default: diff --git a/source/gameengine/Ketsji/KX_RayEventManager.cpp b/source/gameengine/Ketsji/KX_RayEventManager.cpp index 4101c6b547e..1af29151adf 100644 --- a/source/gameengine/Ketsji/KX_RayEventManager.cpp +++ b/source/gameengine/Ketsji/KX_RayEventManager.cpp @@ -44,14 +44,9 @@ using namespace std; void KX_RayEventManager::NextFrame() { - for (vector<class SCA_ISensor*>::const_iterator i= m_sensors.begin();!(i==m_sensors.end());i++) + for (set<class SCA_ISensor*>::const_iterator i= m_sensors.begin();!(i==m_sensors.end());i++) { - SCA_ISensor *sensor = *i; - sensor->Activate(m_logicmgr, NULL); + (*i)->Activate(m_logicmgr, NULL); } } -void KX_RayEventManager::RegisterSensor(SCA_ISensor* sensor) -{ - m_sensors.push_back(sensor); -}; diff --git a/source/gameengine/Ketsji/KX_RayEventManager.h b/source/gameengine/Ketsji/KX_RayEventManager.h index 3630f9682b9..b816d4d5250 100644 --- a/source/gameengine/Ketsji/KX_RayEventManager.h +++ b/source/gameengine/Ketsji/KX_RayEventManager.h @@ -45,7 +45,6 @@ public: m_logicmgr(logicmgr) {} virtual void NextFrame(); - virtual void RegisterSensor(SCA_ISensor* sensor); }; #endif //__KX_RAYEVENTMGR diff --git a/source/gameengine/Ketsji/KX_Scene.cpp b/source/gameengine/Ketsji/KX_Scene.cpp index 2d84d8f035d..2828663c63d 100644 --- a/source/gameengine/Ketsji/KX_Scene.cpp +++ b/source/gameengine/Ketsji/KX_Scene.cpp @@ -37,6 +37,7 @@ #include "MT_assert.h" #include "KX_KetsjiEngine.h" +#include "KX_BlenderMaterial.h" #include "RAS_IPolygonMaterial.h" #include "ListValue.h" #include "SCA_LogicManager.h" @@ -92,6 +93,9 @@ void* KX_SceneReplicationFunc(SG_IObject* node,void* gameobj,void* scene) { KX_GameObject* replica = ((KX_Scene*)scene)->AddNodeReplicaObject(node,(KX_GameObject*)gameobj); + if(replica) + replica->Release(); + return (void*)replica; } @@ -116,13 +120,13 @@ KX_Scene::KX_Scene(class SCA_IInputDevice* keyboarddevice, PyObjectPlus(&KX_Scene::Type), m_keyboardmgr(NULL), m_mousemgr(NULL), + m_sceneConverter(NULL), m_physicsEnvironment(0), m_sceneName(sceneName), m_adi(adi), m_networkDeviceInterface(ndi), m_active_camera(NULL), - m_ueberExecutionPriority(0), - m_sceneConverter(NULL) + m_ueberExecutionPriority(0) { m_suspendedtime = 0.0; m_suspendeddelta = 0.0; @@ -657,7 +661,7 @@ void KX_Scene::DupliGroupRecurse(CValue* obj, int level) // Should not happen as dupli group are created automatically continue; } - if (blenderobj->lay & group->layer==0) + if ((blenderobj->lay & group->layer)==0) { // object is not visible in the 3D view, will not be instantiated continue; @@ -669,8 +673,12 @@ void KX_Scene::DupliGroupRecurse(CValue* obj, int level) for (oit=m_groupGameObjects.begin(); oit != m_groupGameObjects.end(); oit++) { gameobj = (KX_GameObject*)(*oit); - if (gameobj->GetParent() != NULL) + + KX_GameObject *parent = gameobj->GetParent(); + if (parent != NULL) { + parent->Release(); // GetParent() increased the refcount + // this object is not a top parent. Either it is the child of another // object in the group and it will be added automatically when the parent // is added. Or it is the child of an object outside the group and the group @@ -984,6 +992,7 @@ int KX_Scene::NewRemoveObject(class CValue* gameobj) //m_active_camera->Release(); m_active_camera = NULL; } + // in case this is a camera m_cameras.remove((KX_Camera*)newobj); @@ -1240,14 +1249,10 @@ void KX_Scene::MarkSubTreeVisible(SG_Tree *node, RAS_IRasterizer* rasty, bool vi if (visible) { int nummeshes = gameobj->GetMeshCount(); - MT_Transform t( cam->GetWorldToCamera() * gameobj->GetSGNode()->GetWorldTransform()); - + // this adds the vertices to the display list for (int m=0;m<nummeshes;m++) - { - // this adds the vertices to the display list - (gameobj->GetMesh(m))->SchedulePolygons(t, rasty->GetDrawingMode()); - } + (gameobj->GetMesh(m))->SchedulePolygons(rasty->GetDrawingMode()); } gameobj->MarkVisible(visible); } @@ -1304,12 +1309,11 @@ void KX_Scene::MarkVisible(RAS_IRasterizer* rasty, KX_GameObject* gameobj,KX_Cam if (vis) { int nummeshes = gameobj->GetMeshCount(); - MT_Transform t(cam->GetWorldToCamera() * gameobj->GetSGNode()->GetWorldTransform()); for (int m=0;m<nummeshes;m++) { // this adds the vertices to the display list - (gameobj->GetMesh(m))->SchedulePolygons(t, rasty->GetDrawingMode()); + (gameobj->GetMesh(m))->SchedulePolygons(rasty->GetDrawingMode()); } // Visibility/ non-visibility are marked // elsewhere now. @@ -1422,7 +1426,7 @@ void KX_Scene::UpdateParents(double curtime) RAS_MaterialBucket* KX_Scene::FindBucket(class RAS_IPolyMaterial* polymat, bool &bucketCreated) { - return m_bucketmanager->RAS_BucketManagerFindBucket(polymat, bucketCreated); + return m_bucketmanager->FindBucket(polymat, bucketCreated); } @@ -1432,10 +1436,9 @@ void KX_Scene::RenderBuckets(const MT_Transform & cameratransform, class RAS_IRenderTools* rendertools) { m_bucketmanager->Renderbuckets(cameratransform,rasty,rendertools); + KX_BlenderMaterial::EndFrame(); } - - void KX_Scene::UpdateObjectActivity(void) { if (m_activity_culling) { diff --git a/source/gameengine/Ketsji/KX_TouchEventManager.cpp b/source/gameengine/Ketsji/KX_TouchEventManager.cpp index 423543eef5c..48d4cf59a2b 100644 --- a/source/gameengine/Ketsji/KX_TouchEventManager.cpp +++ b/source/gameengine/Ketsji/KX_TouchEventManager.cpp @@ -100,16 +100,24 @@ bool KX_TouchEventManager::newBroadphaseResponse(void *client_data, void KX_TouchEventManager::RegisterSensor(SCA_ISensor* sensor) { KX_TouchSensor* touchsensor = static_cast<KX_TouchSensor*>(sensor); - m_sensors.push_back(touchsensor); + if (m_sensors.insert(touchsensor).second) + // the sensor was effectively inserted, register it + touchsensor->RegisterSumo(this); +} - touchsensor->RegisterSumo(this); +void KX_TouchEventManager::RemoveSensor(SCA_ISensor* sensor) +{ + KX_TouchSensor* touchsensor = static_cast<KX_TouchSensor*>(sensor); + if (m_sensors.erase(touchsensor)) + // the sensor was effectively removed, unregister it + touchsensor->UnregisterSumo(this); } void KX_TouchEventManager::EndFrame() { - vector<SCA_ISensor*>::iterator it; + set<SCA_ISensor*>::iterator it; for ( it = m_sensors.begin(); !(it==m_sensors.end());it++) { @@ -124,7 +132,7 @@ void KX_TouchEventManager::NextFrame() { if (m_sensors.size() > 0) { - vector<SCA_ISensor*>::iterator it; + set<SCA_ISensor*>::iterator it; for (it = m_sensors.begin();!(it==m_sensors.end());++it) static_cast<KX_TouchSensor*>(*it)->SynchronizeTransform(); @@ -157,20 +165,3 @@ void KX_TouchEventManager::NextFrame() (*it)->Activate(m_logicmgr,NULL); } } - - - -void KX_TouchEventManager::RemoveSensor(class SCA_ISensor* sensor) -{ - std::vector<SCA_ISensor*>::iterator i = - std::find(m_sensors.begin(), m_sensors.end(), sensor); - if (!(i == m_sensors.end())) - { - std::swap(*i, m_sensors.back()); - m_sensors.pop_back(); - } - - // remove the sensor forever :) - SCA_EventManager::RemoveSensor(sensor); -} - diff --git a/source/gameengine/Ketsji/KX_TouchEventManager.h b/source/gameengine/Ketsji/KX_TouchEventManager.h index 20ed6126bd0..cc77bccfc31 100644 --- a/source/gameengine/Ketsji/KX_TouchEventManager.h +++ b/source/gameengine/Ketsji/KX_TouchEventManager.h @@ -71,8 +71,8 @@ public: PHY_IPhysicsEnvironment* physEnv); virtual void NextFrame(); virtual void EndFrame(); - virtual void RemoveSensor(class SCA_ISensor* sensor); virtual void RegisterSensor(SCA_ISensor* sensor); + virtual void RemoveSensor(SCA_ISensor* sensor); SCA_LogicManager* GetLogicManager() { return m_logicmgr;} PHY_IPhysicsEnvironment *GetPhysicsEnvironment() { return m_physEnv; } diff --git a/source/gameengine/Ketsji/KX_TouchSensor.cpp b/source/gameengine/Ketsji/KX_TouchSensor.cpp index ce3aa1de2ef..60e1d87d318 100644 --- a/source/gameengine/Ketsji/KX_TouchSensor.cpp +++ b/source/gameengine/Ketsji/KX_TouchSensor.cpp @@ -153,6 +153,14 @@ void KX_TouchSensor::RegisterSumo(KX_TouchEventManager *touchman) } } +void KX_TouchSensor::UnregisterSumo(KX_TouchEventManager* touchman) +{ + if (m_physCtrl) + { + touchman->GetPhysicsEnvironment()->removeCollisionCallback(m_physCtrl); + } +} + bool KX_TouchSensor::NewHandleCollision(void*object1,void*object2,const PHY_CollData* colldata) { // KX_TouchEventManager* toucheventmgr = (KX_TouchEventManager*)m_eventmgr; diff --git a/source/gameengine/Ketsji/KX_TouchSensor.h b/source/gameengine/Ketsji/KX_TouchSensor.h index 056440ccd6c..b611d296939 100644 --- a/source/gameengine/Ketsji/KX_TouchSensor.h +++ b/source/gameengine/Ketsji/KX_TouchSensor.h @@ -76,6 +76,7 @@ public: virtual void ReParent(SCA_IObject* parent); virtual void RegisterSumo(KX_TouchEventManager* touchman); + virtual void UnregisterSumo(KX_TouchEventManager* touchman); // virtual DT_Bool HandleCollision(void* obj1,void* obj2, // const DT_CollData * coll_data); diff --git a/source/gameengine/Ketsji/KX_TrackToActuator.cpp b/source/gameengine/Ketsji/KX_TrackToActuator.cpp index d4bd109de1a..f5b463abf02 100644 --- a/source/gameengine/Ketsji/KX_TrackToActuator.cpp +++ b/source/gameengine/Ketsji/KX_TrackToActuator.cpp @@ -195,6 +195,8 @@ void KX_TrackToActuator::ProcessReplica() // the replica is tracking the same object => register it if (m_object) m_object->RegisterActuator(this); + if (m_parentobj) + m_parentobj->AddRef(); SCA_IActuator::ProcessReplica(); } @@ -219,6 +221,14 @@ void KX_TrackToActuator::Relink(GEN_Map<GEN_HashedPtr, void*> *obj_map) m_object = (SCA_IObject*)(*h_obj); m_object->RegisterActuator(this); } + + void **h_parobj = (*obj_map)[m_parentobj]; + if (h_parobj) { + if (m_parentobj) + m_parentobj->Release(); + m_parentobj= (KX_GameObject*)(*h_parobj); + m_parentobj->AddRef(); + } } diff --git a/source/gameengine/Ketsji/SConscript b/source/gameengine/Ketsji/SConscript index fdac5a71071..f6f744b199a 100644 --- a/source/gameengine/Ketsji/SConscript +++ b/source/gameengine/Ketsji/SConscript @@ -5,7 +5,21 @@ Import ('env') sources = env.Glob('*.cpp') -incs = '. #source/kernel/gen_system #intern/string #intern/guardedalloc' +# Mathutils C files. +sources.extend([\ + '#source/blender/python/api2_2x/Mathutils.c',\ + '#source/blender/python/api2_2x/constant.c',\ + '#source/blender/python/api2_2x/euler.c',\ + '#source/blender/python/api2_2x/gen_utils.c',\ + '#source/blender/python/api2_2x/matrix.c',\ + '#source/blender/python/api2_2x/point.c',\ + '#source/blender/python/api2_2x/quat.c',\ + '#source/blender/python/api2_2x/vector.c',\ +]) + +incs = '. #source/blender/python/api2_2x' # Only for Mathutils! - no other deps + +incs += ' #source/kernel/gen_system #intern/string #intern/guardedalloc' incs += ' #source/gameengine/Rasterizer/RAS_OpenGLRasterizer #intern/bmfont' incs += ' #intern/SoundSystem #intern/SoundSystem/include #intern/SoundSystem/openal' incs += ' #intern/SoundSystem/dummy #intern/SoundSystem/intern #source/gameengine/Converter' diff --git a/source/gameengine/Physics/BlOde/OdePhysicsEnvironment.h b/source/gameengine/Physics/BlOde/OdePhysicsEnvironment.h index ec1b7702ffd..7c61902f8e2 100644 --- a/source/gameengine/Physics/BlOde/OdePhysicsEnvironment.h +++ b/source/gameengine/Physics/BlOde/OdePhysicsEnvironment.h @@ -65,6 +65,7 @@ public: { } virtual void requestCollisionCallback(PHY_IPhysicsController* ctrl) {} + virtual void removeCollisionCallback(PHY_IPhysicsController* ctrl) {} virtual PHY_IPhysicsController* CreateSphereController(float radius,const PHY__Vector3& position) {return 0;} virtual PHY_IPhysicsController* CreateConeController(float coneradius,float coneheight) { return 0;} diff --git a/source/gameengine/Physics/Bullet/CcdPhysicsController.cpp b/source/gameengine/Physics/Bullet/CcdPhysicsController.cpp index 5c70b071661..b872fae6138 100644 --- a/source/gameengine/Physics/Bullet/CcdPhysicsController.cpp +++ b/source/gameengine/Physics/Bullet/CcdPhysicsController.cpp @@ -42,7 +42,8 @@ CcdPhysicsController::CcdPhysicsController (const CcdConstructionInfo& ci) { m_collisionDelay = 0; m_newClientInfo = 0; - + m_registerCount = 0; + m_MotionState = ci.m_MotionState; m_bulletMotionState = 0; @@ -217,7 +218,7 @@ void CcdPhysicsController::WriteDynamicsToMotionState() void CcdPhysicsController::PostProcessReplica(class PHY_IMotionState* motionstate,class PHY_IPhysicsController* parentctrl) { m_MotionState = motionstate; - + m_registerCount = 0; m_body = 0; diff --git a/source/gameengine/Physics/Bullet/CcdPhysicsController.h b/source/gameengine/Physics/Bullet/CcdPhysicsController.h index 64f1876e199..448e5622eff 100644 --- a/source/gameengine/Physics/Bullet/CcdPhysicsController.h +++ b/source/gameengine/Physics/Bullet/CcdPhysicsController.h @@ -110,12 +110,19 @@ class CcdPhysicsController : public PHY_IPhysicsController void* m_newClientInfo; - + int m_registerCount; // needed when multiple sensors use the same controller CcdConstructionInfo m_cci;//needed for replication void GetWorldOrientation(btMatrix3x3& mat); void CreateRigidbody(); + bool Register() { + return (m_registerCount++ == 0) ? true : false; + } + bool Unregister() { + return (--m_registerCount == 0) ? true : false; + } + protected: void setWorldOrientation(const btMatrix3x3& mat); diff --git a/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp b/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp index b773f40650b..dfbcf115fd7 100644 --- a/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp +++ b/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp @@ -368,7 +368,7 @@ void CcdPhysicsEnvironment::addCcdPhysicsController(CcdPhysicsController* ctrl) body->setUserPointer(ctrl); body->setGravity( m_gravity ); - m_controllers.push_back(ctrl); + m_controllers.insert(ctrl); //use explicit group/filter for finer control over collision in bullet => near/radar sensor m_dynamicsWorld->addRigidBody(body, ctrl->GetCollisionFilterGroup(), ctrl->GetCollisionFilterMask()); @@ -434,36 +434,16 @@ void CcdPhysicsEnvironment::addCcdPhysicsController(CcdPhysicsController* ctrl) void CcdPhysicsEnvironment::removeCcdPhysicsController(CcdPhysicsController* ctrl) { - //also remove constraint - - m_dynamicsWorld->removeRigidBody(ctrl->GetRigidBody()); + m_controllers.erase(ctrl); - - { - std::vector<CcdPhysicsController*>::iterator i = - std::find(m_controllers.begin(), m_controllers.end(), ctrl); - if (!(i == m_controllers.end())) - { - std::swap(*i, m_controllers.back()); - m_controllers.pop_back(); - } - } + if (ctrl->m_registerCount != 0) + printf("Warning: removing controller with non-zero m_registerCount: %d\n", ctrl->m_registerCount); //remove it from the triggers - { - std::vector<CcdPhysicsController*>::iterator i = - std::find(m_triggerControllers.begin(), m_triggerControllers.end(), ctrl); - if (!(i == m_triggerControllers.end())) - { - std::swap(*i, m_triggerControllers.back()); - m_triggerControllers.pop_back(); - } - } - - + m_triggerControllers.erase(ctrl); } void CcdPhysicsEnvironment::updateCcdPhysicsController(CcdPhysicsController* ctrl, btScalar newMass, int newCollisionFlags, short int newCollisionGroup, short int newCollisionMask) @@ -487,16 +467,22 @@ void CcdPhysicsEnvironment::updateCcdPhysicsController(CcdPhysicsController* ctr void CcdPhysicsEnvironment::enableCcdPhysicsController(CcdPhysicsController* ctrl) { - std::vector<CcdPhysicsController*>::iterator i = - std::find(m_controllers.begin(), m_controllers.end(), ctrl); - if (i == m_controllers.end()) + if (m_controllers.insert(ctrl).second) { btRigidBody* body = ctrl->GetRigidBody(); + body->setUserPointer(ctrl); m_dynamicsWorld->addCollisionObject(body, ctrl->GetCollisionFilterGroup(), ctrl->GetCollisionFilterMask()); } } +void CcdPhysicsEnvironment::disableCcdPhysicsController(CcdPhysicsController* ctrl) +{ + if (m_controllers.erase(ctrl)) + { + m_dynamicsWorld->removeRigidBody(ctrl->GetRigidBody()); + } +} void CcdPhysicsEnvironment::beginFrame() @@ -507,12 +493,12 @@ void CcdPhysicsEnvironment::beginFrame() bool CcdPhysicsEnvironment::proceedDeltaTime(double curTime,float timeStep) { + std::set<CcdPhysicsController*>::iterator it; + int i; - int i,numCtrl = GetNumControllers(); - for (i=0;i<numCtrl;i++) + for (it=m_controllers.begin(); it!=m_controllers.end(); it++) { - CcdPhysicsController* ctrl = GetPhysicsController(i); - ctrl->SynchronizeMotionStates(timeStep); + (*it)->SynchronizeMotionStates(timeStep); } float subStep = timeStep / float(m_numTimeSubSteps); @@ -521,11 +507,9 @@ bool CcdPhysicsEnvironment::proceedDeltaTime(double curTime,float timeStep) m_dynamicsWorld->stepSimulation(subStep,0);//perform always a full simulation step } - numCtrl = GetNumControllers(); - for (i=0;i<numCtrl;i++) + for (it=m_controllers.begin(); it!=m_controllers.end(); it++) { - CcdPhysicsController* ctrl = GetPhysicsController(i); - ctrl->SynchronizeMotionStates(timeStep); + (*it)->SynchronizeMotionStates(timeStep); } for (i=0;i<m_wrapperVehicles.size();i++) @@ -852,20 +836,6 @@ CcdPhysicsEnvironment::~CcdPhysicsEnvironment() } -int CcdPhysicsEnvironment::GetNumControllers() -{ - return m_controllers.size(); -} - - -CcdPhysicsController* CcdPhysicsEnvironment::GetPhysicsController( int index) -{ - return m_controllers[index]; -} - - - - void CcdPhysicsEnvironment::setConstraintParam(int constraintId,int param,float value0,float value1) { btTypedConstraint* typedConstraint = getConstraintById(constraintId); @@ -905,12 +875,14 @@ void CcdPhysicsEnvironment::addSensor(PHY_IPhysicsController* ctrl) { CcdPhysicsController* ctrl1 = (CcdPhysicsController* )ctrl; - std::vector<CcdPhysicsController*>::iterator i = - std::find(m_controllers.begin(), m_controllers.end(), ctrl); - if ((i == m_controllers.end())) - { - addCcdPhysicsController(ctrl1); - } + // addSensor() is a "light" function for bullet because it is used + // dynamically when the sensor is activated. Use enableCcdPhysicsController() instead + //if (m_controllers.insert(ctrl1).second) + //{ + // addCcdPhysicsController(ctrl1); + //} + enableCcdPhysicsController(ctrl1); + //Collision filter/mask is now set at the time of the creation of the controller //force collision detection with everything, including static objects (might hurt performance!) //ctrl1->GetRigidBody()->getBroadphaseHandle()->m_collisionFilterMask = btBroadphaseProxy::AllFilter ^ btBroadphaseProxy::SensorTrigger; @@ -923,21 +895,19 @@ void CcdPhysicsEnvironment::addSensor(PHY_IPhysicsController* ctrl) void CcdPhysicsEnvironment::removeCollisionCallback(PHY_IPhysicsController* ctrl) { - std::vector<CcdPhysicsController*>::iterator i = - std::find(m_triggerControllers.begin(), m_triggerControllers.end(), ctrl); - if (!(i == m_triggerControllers.end())) - { - std::swap(*i, m_triggerControllers.back()); - m_triggerControllers.pop_back(); - } + CcdPhysicsController* ccdCtrl = (CcdPhysicsController*)ctrl; + if (ccdCtrl->Unregister()) + m_triggerControllers.erase(ccdCtrl); } void CcdPhysicsEnvironment::removeSensor(PHY_IPhysicsController* ctrl) { removeCollisionCallback(ctrl); - //printf("removeSensor\n"); + + disableCcdPhysicsController((CcdPhysicsController*)ctrl); } + void CcdPhysicsEnvironment::addTouchCallback(int response_class, PHY_ResponseCallback callback, void *user) { /* printf("addTouchCallback\n(response class = %i)\n",response_class); @@ -974,11 +944,10 @@ void CcdPhysicsEnvironment::requestCollisionCallback(PHY_IPhysicsController* ctr { CcdPhysicsController* ccdCtrl = static_cast<CcdPhysicsController*>(ctrl); - //printf("requestCollisionCallback\n"); - m_triggerControllers.push_back(ccdCtrl); + if (ccdCtrl->Register()) + m_triggerControllers.insert(ccdCtrl); } - void CcdPhysicsEnvironment::CallbackTriggers() { @@ -987,13 +956,16 @@ void CcdPhysicsEnvironment::CallbackTriggers() if (m_triggerCallbacks[PHY_OBJECT_RESPONSE] || (m_debugDrawer && (m_debugDrawer->getDebugMode() & btIDebugDraw::DBG_DrawContactPoints))) { //walk over all overlapping pairs, and if one of the involved bodies is registered for trigger callback, perform callback - int numManifolds = m_dynamicsWorld->getDispatcher()->getNumManifolds(); + btDispatcher* dispatcher = m_dynamicsWorld->getDispatcher(); + int numManifolds = dispatcher->getNumManifolds(); for (int i=0;i<numManifolds;i++) { - btPersistentManifold* manifold = m_dynamicsWorld->getDispatcher()->getManifoldByIndexInternal(i); + btPersistentManifold* manifold = dispatcher->getManifoldByIndexInternal(i); int numContacts = manifold->getNumContacts(); if (numContacts) { + btRigidBody* rb0 = static_cast<btRigidBody*>(manifold->getBody0()); + btRigidBody* rb1 = static_cast<btRigidBody*>(manifold->getBody1()); if (m_debugDrawer && (m_debugDrawer->getDebugMode() & btIDebugDraw::DBG_DrawContactPoints)) { for (int j=0;j<numContacts;j++) @@ -1004,18 +976,17 @@ void CcdPhysicsEnvironment::CallbackTriggers() m_debugDrawer->drawContactPoint(cp.m_positionWorldOnB,cp.m_normalWorldOnB,cp.getDistance(),cp.getLifeTime(),color); } } - btRigidBody* obj0 = static_cast<btRigidBody* >(manifold->getBody0()); - btRigidBody* obj1 = static_cast<btRigidBody* >(manifold->getBody1()); + btRigidBody* obj0 = rb0; + btRigidBody* obj1 = rb1; //m_internalOwner is set in 'addPhysicsController' CcdPhysicsController* ctrl0 = static_cast<CcdPhysicsController*>(obj0->getUserPointer()); CcdPhysicsController* ctrl1 = static_cast<CcdPhysicsController*>(obj1->getUserPointer()); - std::vector<CcdPhysicsController*>::iterator i = - std::find(m_triggerControllers.begin(), m_triggerControllers.end(), ctrl0); + std::set<CcdPhysicsController*>::const_iterator i = m_triggerControllers.find(ctrl0); if (i == m_triggerControllers.end()) { - i = std::find(m_triggerControllers.begin(), m_triggerControllers.end(), ctrl1); + i = m_triggerControllers.find(ctrl1); } if (!(i == m_triggerControllers.end())) @@ -1023,6 +994,15 @@ void CcdPhysicsEnvironment::CallbackTriggers() m_triggerCallbacks[PHY_OBJECT_RESPONSE](m_triggerCallbacksUserPtrs[PHY_OBJECT_RESPONSE], ctrl0,ctrl1,0); } + // Bullet does not refresh the manifold contact point for object without contact response + // may need to remove this when a newer Bullet version is integrated + if (!dispatcher->needsResponse(rb0, rb1)) + { + // Refresh algorithm fails sometimes when there is penetration + // (usuall the case with ghost and sensor objects) + // Let's just clear the manifold, in any case, it is recomputed on each frame. + manifold->clearManifold(); //refreshContactPoints(rb0->getCenterOfMassTransform(),rb1->getCenterOfMassTransform()); + } } } @@ -1125,7 +1105,6 @@ PHY_IPhysicsController* CcdPhysicsEnvironment::CreateSphereController(float radi CcdPhysicsController* sphereController = new CcdPhysicsController(cinfo); - return sphereController; } diff --git a/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.h b/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.h index 453749b27b3..825a5e525f2 100644 --- a/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.h +++ b/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.h @@ -18,6 +18,7 @@ subject to the following restrictions: #include "PHY_IPhysicsEnvironment.h" #include <vector> +#include <set> class CcdPhysicsController; #include "LinearMath/btVector3.h" #include "LinearMath/btTransform.h" @@ -185,10 +186,7 @@ protected: void updateCcdPhysicsController(CcdPhysicsController* ctrl, btScalar newMass, int newCollisionFlags, short int newCollisionGroup, short int newCollisionMask); - void disableCcdPhysicsController(CcdPhysicsController* ctrl) - { - removeCcdPhysicsController(ctrl); - } + void disableCcdPhysicsController(CcdPhysicsController* ctrl); void enableCcdPhysicsController(CcdPhysicsController* ctrl); @@ -209,12 +207,6 @@ protected: } - int GetNumControllers(); - - CcdPhysicsController* GetPhysicsController( int index); - - - const btPersistentManifold* GetManifold(int index) const; @@ -229,9 +221,9 @@ protected: - std::vector<CcdPhysicsController*> m_controllers; + std::set<CcdPhysicsController*> m_controllers; - std::vector<CcdPhysicsController*> m_triggerControllers; + std::set<CcdPhysicsController*> m_triggerControllers; PHY_ResponseCallback m_triggerCallbacks[PHY_NUM_RESPONSE]; void* m_triggerCallbacksUserPtrs[PHY_NUM_RESPONSE]; diff --git a/source/gameengine/Physics/Dummy/DummyPhysicsEnvironment.h b/source/gameengine/Physics/Dummy/DummyPhysicsEnvironment.h index f0761618e4e..b5a61f72e4a 100644 --- a/source/gameengine/Physics/Dummy/DummyPhysicsEnvironment.h +++ b/source/gameengine/Physics/Dummy/DummyPhysicsEnvironment.h @@ -80,6 +80,7 @@ public: { } virtual void requestCollisionCallback(PHY_IPhysicsController* ctrl) {} + virtual void removeCollisionCallback(PHY_IPhysicsController* ctrl) {} virtual PHY_IPhysicsController* CreateSphereController(float radius,const PHY__Vector3& position) {return 0;} virtual PHY_IPhysicsController* CreateConeController(float coneradius,float coneheight) { return 0;} diff --git a/source/gameengine/Physics/Sumo/Fuzzics/src/SM_Scene.cpp b/source/gameengine/Physics/Sumo/Fuzzics/src/SM_Scene.cpp index b5bf67b14ea..f0791bbf89f 100644 --- a/source/gameengine/Physics/Sumo/Fuzzics/src/SM_Scene.cpp +++ b/source/gameengine/Physics/Sumo/Fuzzics/src/SM_Scene.cpp @@ -98,12 +98,17 @@ void SM_Scene::addTouchCallback(int response_class, DT_ResponseCallback callback void SM_Scene::addSensor(SM_Object& object) { - object.calcXform(); - m_objectList.push_back(&object); - DT_AddObject(m_scene, object.getObjectHandle()); - DT_SetResponseClass(m_respTable, object.getObjectHandle(), m_ResponseClass[SENSOR_RESPONSE]); - DT_SetResponseClass(m_secondaryRespTable, object.getObjectHandle(), m_secondaryResponseClass[SENSOR_RESPONSE]); - DT_SetResponseClass(m_fixRespTable, object.getObjectHandle(), m_fixResponseClass[SENSOR_RESPONSE]); + T_ObjectList::iterator i = + std::find(m_objectList.begin(), m_objectList.end(), &object); + if (i == m_objectList.end()) + { + object.calcXform(); + m_objectList.push_back(&object); + DT_AddObject(m_scene, object.getObjectHandle()); + DT_SetResponseClass(m_respTable, object.getObjectHandle(), m_ResponseClass[SENSOR_RESPONSE]); + DT_SetResponseClass(m_secondaryRespTable, object.getObjectHandle(), m_secondaryResponseClass [SENSOR_RESPONSE]); + DT_SetResponseClass(m_fixRespTable, object.getObjectHandle(), m_fixResponseClass[SENSOR_RESPONSE]); + } } void SM_Scene::add(SM_Object& object) { diff --git a/source/gameengine/Physics/Sumo/SumoPhysicsEnvironment.cpp b/source/gameengine/Physics/Sumo/SumoPhysicsEnvironment.cpp index 16ba45a0be5..65018d2523e 100644 --- a/source/gameengine/Physics/Sumo/SumoPhysicsEnvironment.cpp +++ b/source/gameengine/Physics/Sumo/SumoPhysicsEnvironment.cpp @@ -228,6 +228,12 @@ void SumoPhysicsEnvironment::requestCollisionCallback(PHY_IPhysicsController* ct m_sumoScene->requestCollisionCallback(*smObject); } } + +void SumoPhysicsEnvironment::removeCollisionCallback(PHY_IPhysicsController* ctrl) +{ + // intentionally empty +} + PHY_IPhysicsController* SumoPhysicsEnvironment::CreateSphereController(float radius,const PHY__Vector3& position) { DT_ShapeHandle shape = DT_NewSphere(0.0); diff --git a/source/gameengine/Physics/Sumo/SumoPhysicsEnvironment.h b/source/gameengine/Physics/Sumo/SumoPhysicsEnvironment.h index ce5cd70e8cc..8b9fb463034 100644 --- a/source/gameengine/Physics/Sumo/SumoPhysicsEnvironment.h +++ b/source/gameengine/Physics/Sumo/SumoPhysicsEnvironment.h @@ -84,6 +84,7 @@ public: virtual void removeSensor(PHY_IPhysicsController* ctrl); virtual void addTouchCallback(int response_class, PHY_ResponseCallback callback, void *user); virtual void requestCollisionCallback(PHY_IPhysicsController* ctrl); + virtual void removeCollisionCallback(PHY_IPhysicsController* ctrl); virtual PHY_IPhysicsController* CreateSphereController(float radius,const PHY__Vector3& position); virtual PHY_IPhysicsController* CreateConeController(float coneradius,float coneheight); diff --git a/source/gameengine/Physics/common/PHY_IPhysicsEnvironment.h b/source/gameengine/Physics/common/PHY_IPhysicsEnvironment.h index c148210903f..5b275066665 100644 --- a/source/gameengine/Physics/common/PHY_IPhysicsEnvironment.h +++ b/source/gameengine/Physics/common/PHY_IPhysicsEnvironment.h @@ -104,6 +104,7 @@ class PHY_IPhysicsEnvironment virtual void removeSensor(PHY_IPhysicsController* ctrl)=0; virtual void addTouchCallback(int response_class, PHY_ResponseCallback callback, void *user)=0; virtual void requestCollisionCallback(PHY_IPhysicsController* ctrl)=0; + virtual void removeCollisionCallback(PHY_IPhysicsController* ctrl)=0; //These two methods are *solely* used to create controllers for sensor! Don't use for anything else virtual PHY_IPhysicsController* CreateSphereController(float radius,const PHY__Vector3& position) =0; virtual PHY_IPhysicsController* CreateConeController(float coneradius,float coneheight)=0; diff --git a/source/gameengine/PyDoc/KX_GameObject.py b/source/gameengine/PyDoc/KX_GameObject.py index 8f17cf26f15..a5ba5b1d634 100644 --- a/source/gameengine/PyDoc/KX_GameObject.py +++ b/source/gameengine/PyDoc/KX_GameObject.py @@ -253,6 +253,16 @@ class KX_GameObject: @type other: L{KX_GameObject} or list [x, y, z] @rtype: float """ + def getVectTo(other): + """ + Returns the vector and the distance to another object or point. + The vector is normalized unless the distance is 0, in which a NULL vector is returned. + + @param other: a point or another L{KX_GameObject} to get the vector and distance to. + @type other: L{KX_GameObject} or list [x, y, z] + @rtype: 3-tuple (float, 3-tuple (x,y,z), 3-tuple (x,y,z)) + @return: (distance, globalVector(3), localVector(3)) + """ def rayCastTo(other,dist,prop): """ Look towards another point/object and find first object hit within dist that matches prop. diff --git a/source/gameengine/Rasterizer/RAS_BucketManager.cpp b/source/gameengine/Rasterizer/RAS_BucketManager.cpp index b4492ca03a9..82bdce44519 100644 --- a/source/gameengine/Rasterizer/RAS_BucketManager.cpp +++ b/source/gameengine/Rasterizer/RAS_BucketManager.cpp @@ -94,7 +94,6 @@ void RAS_BucketManager::RenderAlphaBuckets( const MT_Scalar cam_origin = cameratrans.getOrigin()[2]; for (bit = m_AlphaBuckets.begin(); bit != m_AlphaBuckets.end(); ++bit) { - (*bit)->ClearScheduledPolygons(); for (mit = (*bit)->msBegin(); mit != (*bit)->msEnd(); ++mit) { if ((*mit).m_bVisible) @@ -133,28 +132,15 @@ void RAS_BucketManager::Renderbuckets( rasty->ClearCachingInfo(); RAS_MaterialBucket::StartFrame(); - for (bucket = m_MaterialBuckets.begin(); bucket != m_MaterialBuckets.end(); ++bucket) - { - (*bucket)->ClearScheduledPolygons(); - } for (bucket = m_MaterialBuckets.begin(); bucket != m_MaterialBuckets.end(); ++bucket) - { - RAS_IPolyMaterial *tmp = (*bucket)->GetPolyMaterial(); - if(tmp->IsZSort() || tmp->GetFlag() &RAS_FORCEALPHA ) - rasty->SetAlphaTest(true); - else - rasty->SetAlphaTest(false); - (*bucket)->Render(cameratrans,rasty,rendertools); - } - rasty->SetAlphaTest(false); RenderAlphaBuckets(cameratrans, rasty, rendertools); RAS_MaterialBucket::EndFrame(); } -RAS_MaterialBucket* RAS_BucketManager::RAS_BucketManagerFindBucket(RAS_IPolyMaterial * material, bool &bucketCreated) +RAS_MaterialBucket* RAS_BucketManager::FindBucket(RAS_IPolyMaterial * material, bool &bucketCreated) { bucketCreated = false; BucketList::iterator it; @@ -172,7 +158,7 @@ RAS_MaterialBucket* RAS_BucketManager::RAS_BucketManagerFindBucket(RAS_IPolyMate RAS_MaterialBucket *bucket = new RAS_MaterialBucket(material); bucketCreated = true; - if (bucket->IsTransparant()) + if (bucket->IsAlpha()) m_AlphaBuckets.push_back(bucket); else m_MaterialBuckets.push_back(bucket); @@ -195,3 +181,28 @@ void RAS_BucketManager::RAS_BucketManagerClearAll() m_MaterialBuckets.clear(); m_AlphaBuckets.clear(); } + +void RAS_BucketManager::ReleaseDisplayLists() +{ + BucketList::iterator bit; + RAS_MaterialBucket::T_MeshSlotList::iterator mit; + + for (bit = m_MaterialBuckets.begin(); bit != m_MaterialBuckets.end(); ++bit) { + for (mit = (*bit)->msBegin(); mit != (*bit)->msEnd(); ++mit) { + if(mit->m_DisplayList) { + mit->m_DisplayList->Release(); + mit->m_DisplayList = NULL; + } + } + } + + for (bit = m_AlphaBuckets.begin(); bit != m_AlphaBuckets.end(); ++bit) { + for (mit = (*bit)->msBegin(); mit != (*bit)->msEnd(); ++mit) { + if(mit->m_DisplayList) { + mit->m_DisplayList->Release(); + mit->m_DisplayList = NULL; + } + } + } +} + diff --git a/source/gameengine/Rasterizer/RAS_BucketManager.h b/source/gameengine/Rasterizer/RAS_BucketManager.h index 010478b1d5b..08b67ed022f 100644 --- a/source/gameengine/Rasterizer/RAS_BucketManager.h +++ b/source/gameengine/Rasterizer/RAS_BucketManager.h @@ -58,8 +58,9 @@ public: RAS_IRasterizer* rasty, class RAS_IRenderTools* rendertools); - RAS_MaterialBucket* RAS_BucketManagerFindBucket(RAS_IPolyMaterial * material, bool &bucketCreated); + RAS_MaterialBucket* FindBucket(RAS_IPolyMaterial * material, bool &bucketCreated); + void ReleaseDisplayLists(); private: void RAS_BucketManagerClearAll(); diff --git a/source/gameengine/Rasterizer/RAS_CameraData.h b/source/gameengine/Rasterizer/RAS_CameraData.h index 0327a3f4763..e3af43fb839 100644 --- a/source/gameengine/Rasterizer/RAS_CameraData.h +++ b/source/gameengine/Rasterizer/RAS_CameraData.h @@ -42,7 +42,7 @@ struct RAS_CameraData int m_viewporttop; float m_focallength; - RAS_CameraData(float lens = 35., float clipstart = 0.1, float clipend = 100., bool perspective = true, + RAS_CameraData(float lens = 35.0, float clipstart = 0.1, float clipend = 5000.0, bool perspective = true, float focallength = 0.0f, bool viewport = false, int viewportleft = 0, int viewportbottom = 0, int viewportright = 0, int viewporttop = 0) : m_lens(lens), diff --git a/source/gameengine/Rasterizer/RAS_IPolygonMaterial.cpp b/source/gameengine/Rasterizer/RAS_IPolygonMaterial.cpp index 31bdd8638c2..4ee06d96603 100644 --- a/source/gameengine/Rasterizer/RAS_IPolygonMaterial.cpp +++ b/source/gameengine/Rasterizer/RAS_IPolygonMaterial.cpp @@ -39,7 +39,8 @@ RAS_IPolyMaterial::RAS_IPolyMaterial(const STR_String& texname, int tilexrep, int tileyrep, int mode, - bool transparant, + int transp, + bool alpha, bool zsort, int lightlayer, bool bIsTriangle, @@ -51,7 +52,8 @@ RAS_IPolyMaterial::RAS_IPolyMaterial(const STR_String& texname, m_tilexrep(tilexrep), m_tileyrep(tileyrep), m_drawingmode (mode), - m_transparant(transparant), + m_transp(transp), + m_alpha(alpha), m_zsort(zsort), m_lightlayer(lightlayer), m_bIsTriangle(bIsTriangle), @@ -74,6 +76,7 @@ bool RAS_IPolyMaterial::Equals(const RAS_IPolyMaterial& lhs) const this->m_multimode == lhs.m_multimode && this->m_flag == lhs.m_flag && this->m_drawingmode == lhs.m_drawingmode && + this->m_transp == lhs.m_transp && this->m_lightlayer == lhs.m_lightlayer && this->m_texturename.hash() == lhs.m_texturename.hash() && this->m_materialname.hash() == lhs.m_materialname.hash() @@ -85,7 +88,8 @@ bool RAS_IPolyMaterial::Equals(const RAS_IPolyMaterial& lhs) const this->m_tile == lhs.m_tile && this->m_tilexrep == lhs.m_tilexrep && this->m_tileyrep == lhs.m_tileyrep && - this->m_transparant == lhs.m_transparant && + this->m_transp == lhs.m_transp && + this->m_alpha == lhs.m_alpha && this->m_zsort == lhs.m_zsort && this->m_drawingmode == lhs.m_drawingmode && this->m_bIsTriangle == lhs.m_bIsTriangle && @@ -109,9 +113,9 @@ int RAS_IPolyMaterial::GetLightLayer() const return m_lightlayer; } -bool RAS_IPolyMaterial::IsTransparant() const +bool RAS_IPolyMaterial::IsAlpha() const { - return m_transparant; + return m_alpha || m_zsort; } bool RAS_IPolyMaterial::IsZSort() const diff --git a/source/gameengine/Rasterizer/RAS_IPolygonMaterial.h b/source/gameengine/Rasterizer/RAS_IPolygonMaterial.h index 6d90d260a23..8fc53e6b038 100644 --- a/source/gameengine/Rasterizer/RAS_IPolygonMaterial.h +++ b/source/gameengine/Rasterizer/RAS_IPolygonMaterial.h @@ -52,7 +52,7 @@ enum MaterialProps RAS_AUTOGEN =128, RAS_NORMAL =256, RAS_DEFMULTI =512, - RAS_FORCEALPHA =1024 + RAS_BLENDERGLSL =1024 }; /** @@ -67,7 +67,8 @@ protected: int m_tile; int m_tilexrep,m_tileyrep; int m_drawingmode; // tface->mode - bool m_transparant; + int m_transp; + bool m_alpha; bool m_zsort; int m_lightlayer; bool m_bIsTriangle; @@ -102,7 +103,8 @@ public: int tilexrep, int tileyrep, int mode, - bool transparant, + int transp, + bool alpha, bool zsort, int lightlayer, bool bIsTriangle, @@ -132,7 +134,7 @@ public: virtual bool Equals(const RAS_IPolyMaterial& lhs) const; bool Less(const RAS_IPolyMaterial& rhs) const; int GetLightLayer() const; - bool IsTransparant() const; + bool IsAlpha() const; bool IsZSort() const; bool UsesTriangles() const; unsigned int hash() const; diff --git a/source/gameengine/Rasterizer/RAS_IRasterizer.h b/source/gameengine/Rasterizer/RAS_IRasterizer.h index d4a9177a85d..9e03212283e 100644 --- a/source/gameengine/Rasterizer/RAS_IRasterizer.h +++ b/source/gameengine/Rasterizer/RAS_IRasterizer.h @@ -372,10 +372,6 @@ public: virtual void SetAmbientColor(float red, float green, float blue)=0; virtual void SetAmbient(float factor)=0; - /** - * Sets alpha testing - */ - virtual void SetAlphaTest(bool enable)=0; /** * Sets a polygon offset. z depth will be: z1 = mult*z0 + add @@ -398,8 +394,10 @@ public: virtual void DisableMotionBlur()=0; virtual float GetMotionBlurValue()=0; - virtual int GetMotionBlurState()=0; - virtual void SetMotionBlurState(int newstate)=0; + virtual int GetMotionBlurState()=0; + virtual void SetMotionBlurState(int newstate)=0; + + virtual void SetBlendingMode(int blendmode)=0; }; #endif //__RAS_IRASTERIZER diff --git a/source/gameengine/Rasterizer/RAS_MaterialBucket.cpp b/source/gameengine/Rasterizer/RAS_MaterialBucket.cpp index e295d69e48e..0015b6a251f 100644 --- a/source/gameengine/Rasterizer/RAS_MaterialBucket.cpp +++ b/source/gameengine/Rasterizer/RAS_MaterialBucket.cpp @@ -76,26 +76,11 @@ KX_MeshSlot::~KX_MeshSlot() RAS_MaterialBucket::RAS_MaterialBucket(RAS_IPolyMaterial* mat) :m_bModified(true) { - m_bScheduled=true; m_material = mat; } -void RAS_MaterialBucket::SchedulePolygons(int drawingmode) -{ - m_bScheduled = true; -} - - - -void RAS_MaterialBucket::ClearScheduledPolygons() -{ - m_bScheduled = false; -} - - - RAS_IPolyMaterial* RAS_MaterialBucket::GetPolyMaterial() const { return m_material; @@ -134,9 +119,14 @@ void RAS_MaterialBucket::MarkVisibleMeshSlot(KX_MeshSlot& ms, (*it).m_RGBAcolor= rgbavec; } -bool RAS_MaterialBucket::IsTransparant() const +bool RAS_MaterialBucket::IsAlpha() const +{ + return (m_material->IsAlpha()); +} + +bool RAS_MaterialBucket::IsZSort() const { - return (m_material->IsTransparant()); + return (m_material->IsZSort()); } diff --git a/source/gameengine/Rasterizer/RAS_MaterialBucket.h b/source/gameengine/Rasterizer/RAS_MaterialBucket.h index 13d8a53714a..4eef889c533 100644 --- a/source/gameengine/Rasterizer/RAS_MaterialBucket.h +++ b/source/gameengine/Rasterizer/RAS_MaterialBucket.h @@ -125,11 +125,9 @@ public: class RAS_IRasterizer* rasty, class RAS_IRenderTools* rendertools); - void SchedulePolygons(int drawingmode); - void ClearScheduledPolygons(); - RAS_IPolyMaterial* GetPolyMaterial() const; - bool IsTransparant() const; + bool IsAlpha() const; + bool IsZSort() const; static void StartFrame(); static void EndFrame(); @@ -162,7 +160,6 @@ public: private: T_MeshSlotList m_meshSlots; - bool m_bScheduled; bool m_bModified; RAS_IPolyMaterial* m_material; double* m_pOGLMatrix; diff --git a/source/gameengine/Rasterizer/RAS_MeshObject.cpp b/source/gameengine/Rasterizer/RAS_MeshObject.cpp index 5087f62500e..af5228e4c35 100644 --- a/source/gameengine/Rasterizer/RAS_MeshObject.cpp +++ b/source/gameengine/Rasterizer/RAS_MeshObject.cpp @@ -35,6 +35,8 @@ #include "MT_MinMax.h" #include "MT_Point3.h" +#include <algorithm> + STR_String RAS_MeshObject::s_emptyname = ""; @@ -203,7 +205,6 @@ void RAS_MeshObject::DebugColor(unsigned int abgr) void RAS_MeshObject::SetVertexColor(RAS_IPolyMaterial* mat,MT_Vector4 rgba) { - RAS_TexVert* vertex = NULL; const vecVertexArray & vertexvec = GetVertexCache(mat); for (vector<KX_VertexArray*>::const_iterator it = vertexvec.begin(); it != vertexvec.end(); ++it) @@ -220,22 +221,17 @@ void RAS_MeshObject::SchedulePoly(const KX_VertexIndex& idx, int numverts, RAS_IPolyMaterial* mat) { - //int indexpos = m_IndexArrayCount[idx.m_vtxarray]; - //m_IndexArrayCount[idx.m_vtxarray] = indexpos + 3; - KX_ArrayOptimizer* ao = GetArrayOptimizer(mat); + ao->m_IndexArrayCache1[idx.m_vtxarray]->push_back(idx.m_indexarray[0]); ao->m_IndexArrayCache1[idx.m_vtxarray]->push_back(idx.m_indexarray[1]); ao->m_IndexArrayCache1[idx.m_vtxarray]->push_back(idx.m_indexarray[2]); - if (!mat->UsesTriangles()) //if (!m_bUseTriangles) - { - //m_IndexArrayCount[idx.m_vtxarray] = indexpos+4; + + if (!mat->UsesTriangles()) ao->m_IndexArrayCache1[idx.m_vtxarray]->push_back(idx.m_indexarray[3]); - } } - void RAS_MeshObject::ScheduleWireframePoly(const KX_VertexIndex& idx, int numverts, int edgecode, @@ -422,7 +418,6 @@ void RAS_MeshObject::Bucketize(double* oglmatrix, for (RAS_MaterialBucket::Set::iterator it = m_materials.begin();it!=m_materials.end();++it) { RAS_MaterialBucket* bucket = *it; - bucket->SchedulePolygons(0); // KX_ArrayOptimizer* oa = GetArrayOptimizer(bucket->GetPolyMaterial()); bucket->SetMeshSlot(ms); } @@ -447,7 +442,6 @@ void RAS_MeshObject::MarkVisible(double* oglmatrix, for (RAS_MaterialBucket::Set::iterator it = m_materials.begin();it!=m_materials.end();++it) { RAS_MaterialBucket* bucket = *it; - bucket->SchedulePolygons(0); // KX_ArrayOptimizer* oa = GetArrayOptimizer(bucket->GetPolyMaterial()); bucket->MarkVisibleMeshSlot(ms,visible,useObjectColor,rgbavec); } @@ -466,7 +460,6 @@ void RAS_MeshObject::RemoveFromBuckets(double* oglmatrix, { RAS_MaterialBucket* bucket = *it; // RAS_IPolyMaterial* polymat = bucket->GetPolyMaterial(); - bucket->SchedulePolygons(0); //KX_ArrayOptimizer* oa = GetArrayOptimizer(polymat); bucket->RemoveMeshSlot(ms); } @@ -585,31 +578,36 @@ void RAS_MeshObject::UpdateMaterialList() struct RAS_MeshObject::polygonSlot { - float m_z; - RAS_Polygon *m_poly; - - polygonSlot(float z, RAS_Polygon* poly) : - m_z(z), - m_poly(poly) - {} - /** - * pnorm and pval form the plane equation that the distance from is used to - * sort against. - */ - polygonSlot(const MT_Vector3 &pnorm, const MT_Scalar &pval, RAS_MeshObject *mesh, RAS_Polygon* poly) : - m_poly(poly) + float m_z; + int m_index[4]; + + polygonSlot() {} + + /* pnorm is the normal from the plane equation that the distance from is + * used to sort again. */ + void get(const KX_VertexArray& vertexarray, const KX_IndexArray& indexarray, + int offset, int nvert, const MT_Vector3& pnorm) { - const KX_VertexIndex &base = m_poly->GetIndexBase(); - RAS_TexVert *vert = mesh->GetVertex(base.m_vtxarray, base.m_indexarray[0], poly->GetMaterial()->GetPolyMaterial()); - m_z = MT_dot(pnorm, vert->getLocalXYZ()) + pval; - - for(int i = 1; i < m_poly->VertexCount(); i++) - { - vert = mesh->GetVertex(base.m_vtxarray, base.m_indexarray[i], poly->GetMaterial()->GetPolyMaterial()); - float z = MT_dot(pnorm, vert->getLocalXYZ()) + pval; - m_z += z; + MT_Vector3 center(0, 0, 0); + int i; + + for(i=0; i<nvert; i++) { + m_index[i] = indexarray[offset+i]; + center += vertexarray[m_index[i]].getLocalXYZ(); } - m_z /= m_poly->VertexCount(); + + /* note we don't divide center by the number of vertices, since all + * polygons have the same number of vertices, and that we leave out + * the 4-th component of the plane equation since it is constant. */ + m_z = MT_dot(pnorm, center); + } + + void set(KX_IndexArray& indexarray, int offset, int nvert) + { + int i; + + for(i=0; i<nvert; i++) + indexarray[offset+i] = m_index[i]; } }; @@ -629,100 +627,100 @@ struct RAS_MeshObject::fronttoback } }; - void RAS_MeshObject::SortPolygons(const MT_Transform &transform) { + // Limitations: sorting is quite simple, and handles many + // cases wrong, partially due to polygons being sorted per + // bucket. + // + // a) mixed triangles/quads are sorted wrong + // b) mixed materials are sorted wrong + // c) more than 65k faces are sorted wrong + // d) intersecting objects are sorted wrong + // e) intersecting polygons are sorted wrong + // + // a) can be solved by making all faces either triangles or quads + // if they need to be z-sorted. c) could be solved by allowing + // larger buckets, b) and d) cannot be solved easily if we want + // to avoid excessive state changes while drawing. e) would + // require splitting polygons. + if (!m_zsort) return; - + // Extract camera Z plane... const MT_Vector3 pnorm(transform.getBasis()[2]); - const MT_Scalar pval = transform.getOrigin()[2]; - - unsigned int numpolys = m_Polygons.size(); - std::multiset<polygonSlot, backtofront> alphapolyset; - std::multiset<polygonSlot, fronttoback> solidpolyset; - - for (unsigned int p = 0; p < numpolys; p++) - { - RAS_Polygon* poly = m_Polygons[p]; - if (poly->IsVisible()) - { - if (poly->GetMaterial()->GetPolyMaterial()->IsTransparant()) - { - alphapolyset.insert(polygonSlot(pnorm, pval, this, poly)); - } else { - solidpolyset.insert(polygonSlot(pnorm, pval, this, poly)); - } - } - } - - // Clear current array data. + // unneeded: const MT_Scalar pval = transform.getOrigin()[2]; + for (RAS_MaterialBucket::Set::iterator it = m_materials.begin();it!=m_materials.end();++it) { - vector<KX_IndexArray*> *indexcache = &GetArrayOptimizer((*it)->GetPolyMaterial())->m_IndexArrayCache1; - for (vector<KX_IndexArray*>::iterator iit = indexcache->begin(); iit != indexcache->end(); ++iit) - (*iit)->clear(); - } + if(!(*it)->IsZSort()) + continue; - std::multiset<polygonSlot, fronttoback>::iterator sit = solidpolyset.begin(); - for (; sit != solidpolyset.end(); ++sit) - SchedulePoly((*sit).m_poly->GetVertexIndexBase(), (*sit).m_poly->VertexCount(), (*sit).m_poly->GetMaterial()->GetPolyMaterial()); - - std::multiset<polygonSlot, backtofront>::iterator ait = alphapolyset.begin(); - for (; ait != alphapolyset.end(); ++ait) - SchedulePoly((*ait).m_poly->GetVertexIndexBase(), (*ait).m_poly->VertexCount(), (*ait).m_poly->GetMaterial()->GetPolyMaterial()); + RAS_IPolyMaterial *mat = (*it)->GetPolyMaterial(); + KX_ArrayOptimizer* ao = GetArrayOptimizer(mat); + + vecIndexArrays& indexarrays = ao->m_IndexArrayCache1; + vecVertexArray& vertexarrays = ao->m_VertexArrayCache1; + unsigned int i, j, nvert = (mat->UsesTriangles())? 3: 4; + + for(i=0; i<indexarrays.size(); i++) { + KX_IndexArray& indexarray = *indexarrays[i]; + KX_VertexArray& vertexarray = *vertexarrays[i]; + + unsigned int totpoly = indexarray.size()/nvert; + vector<polygonSlot> slots(totpoly); + + /* get indices and z into temporary array */ + for(j=0; j<totpoly; j++) + slots[j].get(vertexarray, indexarray, j*nvert, nvert, pnorm); + + /* sort (stable_sort might be better, if flickering happens?) */ + std::sort(slots.begin(), slots.end(), backtofront()); + + /* get indices from temporary array again */ + for(j=0; j<totpoly; j++) + slots[j].set(indexarray, j*nvert, nvert); + } + } } -void RAS_MeshObject::SchedulePolygons(const MT_Transform &transform, int drawingmode) +void RAS_MeshObject::SchedulePolygons(int drawingmode) { -// int nummaterials = m_materials.size(); - int i; - if (m_bModified) { - for (RAS_MaterialBucket::Set::iterator it = m_materials.begin();it!=m_materials.end();++it) - { - RAS_MaterialBucket* bucket = *it; + int i, numpolys = m_Polygons.size(); - bucket->SchedulePolygons(drawingmode); - if (bucket->GetPolyMaterial()->IsZSort()) + for (RAS_MaterialBucket::Set::iterator it = m_materials.begin();it!=m_materials.end();++it) + if ((*it)->IsZSort()) m_zsort = true; - } - - int numpolys = m_Polygons.size(); - if ((drawingmode > RAS_IRasterizer::KX_BOUNDINGBOX) && - (drawingmode < RAS_IRasterizer::KX_SOLID)) + if (drawingmode == RAS_IRasterizer::KX_WIREFRAME) { for (i=0;i<numpolys;i++) { RAS_Polygon* poly = m_Polygons[i]; if (poly->IsVisible()) - ScheduleWireframePoly(poly->GetVertexIndexBase(),poly->VertexCount(),poly->GetEdgeCode() - ,poly->GetMaterial()->GetPolyMaterial()); + ScheduleWireframePoly(poly->GetVertexIndexBase(),poly->VertexCount(),poly->GetEdgeCode(), + poly->GetMaterial()->GetPolyMaterial()); } m_zsort = false; } else { - if (!m_zsort) + for (i=0;i<numpolys;i++) { - for (i=0;i<numpolys;i++) - { - RAS_Polygon* poly = m_Polygons[i]; - if (poly->IsVisible()) - { - SchedulePoly(poly->GetVertexIndexBase(),poly->VertexCount(),poly->GetMaterial()->GetPolyMaterial()); - } - } + RAS_Polygon* poly = m_Polygons[i]; + if (poly->IsVisible()) + SchedulePoly(poly->GetVertexIndexBase(),poly->VertexCount(), + poly->GetMaterial()->GetPolyMaterial()); } } m_bModified = false; - m_MeshMod = true; } } + diff --git a/source/gameengine/Rasterizer/RAS_MeshObject.h b/source/gameengine/Rasterizer/RAS_MeshObject.h index 44ad508d1e8..99806666fa6 100644 --- a/source/gameengine/Rasterizer/RAS_MeshObject.h +++ b/source/gameengine/Rasterizer/RAS_MeshObject.h @@ -137,6 +137,18 @@ class RAS_MeshObject struct backtofront; struct fronttoback; + void SchedulePoly( + const KX_VertexIndex& idx, + int numverts, + RAS_IPolyMaterial* mat + ); + + void ScheduleWireframePoly( + const KX_VertexIndex& idx, + int numverts, + int edgecode, + RAS_IPolyMaterial* mat + ); protected: enum { BUCKET_MAX_INDICES = 65535 };//2048};//8192}; @@ -196,10 +208,7 @@ public: */ void SortPolygons(const MT_Transform &transform); - void SchedulePolygons( - const MT_Transform &transform, - int drawingmode - ); + void SchedulePolygons(int drawingmode); void ClearArrayData(); @@ -216,19 +225,7 @@ public: int numverts, RAS_IPolyMaterial* polymat ); - - void SchedulePoly( - const KX_VertexIndex& idx, - int numverts, - RAS_IPolyMaterial* mat - ); - void ScheduleWireframePoly( - const KX_VertexIndex& idx, - int numverts, - int edgecode, - RAS_IPolyMaterial* mat - ); // find (and share) or add vertices // for some speedup, only the last 20 added vertices are searched for equality diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp index dcc36bf5a39..1dcc6e70934 100644 --- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp +++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp @@ -67,6 +67,7 @@ RAS_OpenGLRasterizer::RAS_OpenGLRasterizer(RAS_ICanvas* canvas) m_motionblurvalue(-1.0), m_texco_num(0), m_attrib_num(0), + m_last_blendmode(0), m_materialCachingInfo(0) { m_viewmatrix.Identity(); @@ -171,6 +172,8 @@ bool RAS_OpenGLRasterizer::Init() m_ambg = 0.0f; m_ambb = 0.0f; + SetBlendingMode(0); + glClearColor(m_redback,m_greenback,m_blueback,m_alphaback); glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); @@ -189,18 +192,6 @@ void RAS_OpenGLRasterizer::SetAmbientColor(float red, float green, float blue) } -void RAS_OpenGLRasterizer::SetAlphaTest(bool enable) -{ - if (enable) - { - glEnable(GL_ALPHA_TEST); - glAlphaFunc(GL_GREATER, 0.6f); - } - else glDisable(GL_ALPHA_TEST); -} - - - void RAS_OpenGLRasterizer::SetAmbient(float factor) { float ambient[] = { m_ambr*factor, m_ambg*factor, m_ambb*factor, 1.0f }; @@ -353,6 +344,8 @@ bool RAS_OpenGLRasterizer::BeginFrame(int drawingmode, double time) glEnable (GL_CULL_FACE); } + SetBlendingMode(0); + glShadeModel(GL_SMOOTH); m_2DCanvas->BeginFrame(); @@ -1389,3 +1382,34 @@ void RAS_OpenGLRasterizer::DisableMotionBlur() m_motionblur = 0; m_motionblurvalue = -1.0; } + +void RAS_OpenGLRasterizer::SetBlendingMode(int blendmode) +{ + if(blendmode == m_last_blendmode) + return; + + if(blendmode == 0) { + glDisable(GL_BLEND); + glDisable(GL_ALPHA_TEST); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } + else if(blendmode == 1) { + glBlendFunc(GL_ONE, GL_ONE); + glEnable(GL_BLEND); + glDisable(GL_ALPHA_TEST); + } + else if(blendmode == 2) { + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glEnable(GL_BLEND); + glEnable(GL_ALPHA_TEST); + glAlphaFunc(GL_GREATER, 0.0f); + } + else if(blendmode == 4) { + glDisable(GL_BLEND); + glEnable(GL_ALPHA_TEST); + glAlphaFunc(GL_GREATER, 0.5f); + } + + m_last_blendmode = blendmode; +} + diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.h b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.h index 0d54552db05..02056cce446 100644 --- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.h +++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.h @@ -99,6 +99,7 @@ protected: TexCoGen m_attrib[RAS_MAX_ATTRIB]; int m_texco_num; int m_attrib_num; + int m_last_blendmode; /** Stores the caching information for the last material activated. */ RAS_IPolyMaterial::TCachingInfo m_materialCachingInfo; @@ -142,8 +143,6 @@ public: virtual void SetFocalLength(const float focallength); virtual float GetFocalLength(); - virtual void SetAlphaTest(bool enable); - virtual void SwapBuffers(); virtual void IndexPrimitives( const vecVertexArray& vertexarrays, @@ -282,8 +281,8 @@ public: virtual void EnableMotionBlur(float motionblurvalue); virtual void DisableMotionBlur(); virtual float GetMotionBlurValue(){return m_motionblurvalue;}; - virtual int GetMotionBlurState(){return m_motionblur;}; - virtual void SetMotionBlurState(int newstate) + virtual int GetMotionBlurState(){return m_motionblur;}; + virtual void SetMotionBlurState(int newstate) { if(newstate<0) m_motionblur = 0; @@ -292,6 +291,8 @@ public: else m_motionblur = newstate; }; + + virtual void SetBlendingMode(int blendmode); }; #endif //__RAS_OPENGLRASTERIZER diff --git a/source/gameengine/Rasterizer/RAS_Polygon.cpp b/source/gameengine/Rasterizer/RAS_Polygon.cpp index 852c94def3f..b74cb9cfcac 100644 --- a/source/gameengine/Rasterizer/RAS_Polygon.cpp +++ b/source/gameengine/Rasterizer/RAS_Polygon.cpp @@ -37,24 +37,6 @@ #include "RAS_Polygon.h" -/* -RAS_TexVert* RAS_Polygon::GetVertex(int index) -{ - if (m_bucket) - return m_bucket->GetVertex(m_vertexindexbase.m_vtxarray, m_vertexindexbase.m_indexarray[index]); - else - return NULL; -} -*/ - -/*void RAS_Polygon::Bucketize(double* oglmatrix) -{ - //Transform(trans); - if (m_bucket) - m_bucket->AddPolygon(this,oglmatrix); -} -*/ - RAS_Polygon::RAS_Polygon(RAS_MaterialBucket* bucket, bool visible, int numverts, |