diff options
author | Nicholas Bishop <nicholasbishop@gmail.com> | 2008-08-14 05:36:55 +0400 |
---|---|---|
committer | Nicholas Bishop <nicholasbishop@gmail.com> | 2008-08-14 05:36:55 +0400 |
commit | 860975969364667a262a7d7ca7de20c31e746154 (patch) | |
tree | 77d62c9363e18a3c8347619cdaaca6df832fc0fe /source/blender | |
parent | e0c83d03ba3200c704d82fb1ae175914ef514f44 (diff) | |
parent | d2750f7bda1e5e4e43df330ab49e677105e00d4f (diff) |
Merge with r16081
Diffstat (limited to 'source/blender')
66 files changed, 4143 insertions, 1481 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; } } |