Blender  V2.59
meshlaplacian.c
Go to the documentation of this file.
00001 /*
00002  * $Id: meshlaplacian.c 36276 2011-04-21 15:53:30Z campbellbarton $
00003  *
00004  * ***** BEGIN GPL LICENSE BLOCK *****
00005  *
00006  * This program is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU General Public License
00008  * as published by the Free Software Foundation; either version 2
00009  * of the License, or (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software Foundation,
00018  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00019  *
00020  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
00021  * All rights reserved.
00022  *
00023  * The Original Code is: all of this file.
00024  *
00025  * Contributor(s): none yet.
00026  *
00027  * ***** END GPL LICENSE BLOCK *****
00028  * meshlaplacian.c: Algorithms using the mesh laplacian.
00029  */
00030 
00036 #include <math.h>
00037 #include <string.h>
00038 
00039 #include "MEM_guardedalloc.h"
00040 
00041 #include "DNA_object_types.h"
00042 #include "DNA_mesh_types.h"
00043 #include "DNA_meshdata_types.h"
00044 #include "DNA_scene_types.h"
00045 
00046 #include "BLI_math.h"
00047 #include "BLI_edgehash.h"
00048 #include "BLI_memarena.h"
00049 #include "BLI_utildefines.h"
00050 
00051 #include "BKE_DerivedMesh.h"
00052 #include "BKE_modifier.h"
00053 
00054 
00055 #ifdef RIGID_DEFORM
00056 #include "BLI_editVert.h"
00057 #include "BLI_polardecomp.h"
00058 #endif
00059 
00060 #include "ONL_opennl.h"
00061 
00062 #include "BLO_sys_types.h" // for intptr_t support
00063 
00064 #include "ED_mesh.h"
00065 #include "ED_armature.h"
00066 
00067 #include "meshlaplacian.h"
00068 
00069 
00070 /* ************* XXX *************** */
00071 static void waitcursor(int UNUSED(val)) {}
00072 static void progress_bar(int UNUSED(dummy_val), const char *UNUSED(dummy)) {}
00073 static void start_progress_bar(void) {}
00074 static void end_progress_bar(void) {}
00075 static void error(const char *str) { printf("error: %s\n", str); }
00076 /* ************* XXX *************** */
00077 
00078 
00079 /************************** Laplacian System *****************************/
00080 
00081 struct LaplacianSystem {
00082         NLContext context;      /* opennl context */
00083 
00084         int totvert, totface;
00085 
00086         float **verts;                  /* vertex coordinates */
00087         float *varea;                   /* vertex weights for laplacian computation */
00088         char *vpinned;                  /* vertex pinning */
00089         int (*faces)[3];                /* face vertex indices */
00090         float (*fweights)[3];   /* cotangent weights per face */
00091 
00092         int areaweights;                /* use area in cotangent weights? */
00093         int storeweights;               /* store cotangent weights in fweights */
00094         int nlbegun;                    /* nlBegin(NL_SYSTEM/NL_MATRIX) done */
00095 
00096         EdgeHash *edgehash;             /* edge hash for construction */
00097 
00098         struct HeatWeighting {
00099                 MFace *mface;
00100                 int totvert;
00101                 int totface;
00102                 float (*verts)[3];      /* vertex coordinates */
00103                 float (*vnors)[3];      /* vertex normals */
00104 
00105                 float (*root)[3];       /* bone root */
00106                 float (*tip)[3];        /* bone tip */
00107                 float (*source)[3]; /* vertex source */
00108                 int numsource;
00109 
00110                 float *H;                       /* diagonal H matrix */
00111                 float *p;                       /* values from all p vectors */
00112                 float *mindist;         /* minimum distance to a bone for all vertices */
00113                 
00114                 BVHTree   *bvhtree;     /* ray tracing acceleration structure */
00115                 MFace     **vface;      /* a face that the vertex belongs to */
00116         } heat;
00117 
00118 #ifdef RIGID_DEFORM
00119         struct RigidDeformation {
00120                 EditMesh *mesh;
00121 
00122                 float (*R)[3][3];
00123                 float (*rhs)[3];
00124                 float (*origco)[3];
00125                 int thrownerror;
00126         } rigid;
00127 #endif
00128 };
00129 
00130 /* Laplacian matrix construction */
00131 
00132 /* Computation of these weights for the laplacian is based on:
00133    "Discrete Differential-Geometry Operators for Triangulated 2-Manifolds",
00134    Meyer et al, 2002. Section 3.5, formula (8).
00135    
00136    We do it a bit different by going over faces instead of going over each
00137    vertex and adjacent faces, since we don't store this adjacency. Also, the
00138    formulas are tweaked a bit to work for non-manifold meshes. */
00139 
00140 static void laplacian_increase_edge_count(EdgeHash *edgehash, int v1, int v2)
00141 {
00142         void **p = BLI_edgehash_lookup_p(edgehash, v1, v2);
00143 
00144         if(p)
00145                 *p = (void*)((intptr_t)*p + (intptr_t)1);
00146         else
00147                 BLI_edgehash_insert(edgehash, v1, v2, (void*)(intptr_t)1);
00148 }
00149 
00150 static int laplacian_edge_count(EdgeHash *edgehash, int v1, int v2)
00151 {
00152         return (int)(intptr_t)BLI_edgehash_lookup(edgehash, v1, v2);
00153 }
00154 
00155 static float cotan_weight(float *v1, float *v2, float *v3)
00156 {
00157         float a[3], b[3], c[3], clen;
00158 
00159         sub_v3_v3v3(a, v2, v1);
00160         sub_v3_v3v3(b, v3, v1);
00161         cross_v3_v3v3(c, a, b);
00162 
00163         clen = len_v3(c);
00164 
00165         if (clen == 0.0f)
00166                 return 0.0f;
00167         
00168         return dot_v3v3(a, b)/clen;
00169 }
00170 
00171 static void laplacian_triangle_area(LaplacianSystem *sys, int i1, int i2, int i3)
00172 {
00173         float t1, t2, t3, len1, len2, len3, area;
00174         float *varea= sys->varea, *v1, *v2, *v3;
00175         int obtuse = 0;
00176 
00177         v1= sys->verts[i1];
00178         v2= sys->verts[i2];
00179         v3= sys->verts[i3];
00180 
00181         t1= cotan_weight(v1, v2, v3);
00182         t2= cotan_weight(v2, v3, v1);
00183         t3= cotan_weight(v3, v1, v2);
00184 
00185         if(RAD2DEGF(angle_v3v3v3(v2, v1, v3)) > 90) obtuse= 1;
00186         else if(RAD2DEGF(angle_v3v3v3(v1, v2, v3)) > 90) obtuse= 2;
00187         else if(RAD2DEGF(angle_v3v3v3(v1, v3, v2)) > 90) obtuse= 3;
00188 
00189         if (obtuse > 0) {
00190                 area= area_tri_v3(v1, v2, v3);
00191 
00192                 varea[i1] += (obtuse == 1)? area: area*0.5f;
00193                 varea[i2] += (obtuse == 2)? area: area*0.5f;
00194                 varea[i3] += (obtuse == 3)? area: area*0.5f;
00195         }
00196         else {
00197                 len1= len_v3v3(v2, v3);
00198                 len2= len_v3v3(v1, v3);
00199                 len3= len_v3v3(v1, v2);
00200 
00201                 t1 *= len1*len1;
00202                 t2 *= len2*len2;
00203                 t3 *= len3*len3;
00204 
00205                 varea[i1] += (t2 + t3)*0.25f;
00206                 varea[i2] += (t1 + t3)*0.25f;
00207                 varea[i3] += (t1 + t2)*0.25f;
00208         }
00209 }
00210 
00211 static void laplacian_triangle_weights(LaplacianSystem *sys, int f, int i1, int i2, int i3)
00212 {
00213         float t1, t2, t3;
00214         float *varea= sys->varea, *v1, *v2, *v3;
00215 
00216         v1= sys->verts[i1];
00217         v2= sys->verts[i2];
00218         v3= sys->verts[i3];
00219 
00220         /* instead of *0.5 we divided by the number of faces of the edge, it still
00221            needs to be verified that this is indeed the correct thing to do! */
00222         t1= cotan_weight(v1, v2, v3)/laplacian_edge_count(sys->edgehash, i2, i3);
00223         t2= cotan_weight(v2, v3, v1)/laplacian_edge_count(sys->edgehash, i3, i1);
00224         t3= cotan_weight(v3, v1, v2)/laplacian_edge_count(sys->edgehash, i1, i2);
00225 
00226         nlMatrixAdd(i1, i1, (t2+t3)*varea[i1]);
00227         nlMatrixAdd(i2, i2, (t1+t3)*varea[i2]);
00228         nlMatrixAdd(i3, i3, (t1+t2)*varea[i3]);
00229 
00230         nlMatrixAdd(i1, i2, -t3*varea[i1]);
00231         nlMatrixAdd(i2, i1, -t3*varea[i2]);
00232 
00233         nlMatrixAdd(i2, i3, -t1*varea[i2]);
00234         nlMatrixAdd(i3, i2, -t1*varea[i3]);
00235 
00236         nlMatrixAdd(i3, i1, -t2*varea[i3]);
00237         nlMatrixAdd(i1, i3, -t2*varea[i1]);
00238 
00239         if(sys->storeweights) {
00240                 sys->fweights[f][0]= t1*varea[i1];
00241                 sys->fweights[f][1]= t2*varea[i2];
00242                 sys->fweights[f][2]= t3*varea[i3];
00243         }
00244 }
00245 
00246 static LaplacianSystem *laplacian_system_construct_begin(int totvert, int totface, int lsq)
00247 {
00248         LaplacianSystem *sys;
00249 
00250         sys= MEM_callocN(sizeof(LaplacianSystem), "LaplacianSystem");
00251 
00252         sys->verts= MEM_callocN(sizeof(float*)*totvert, "LaplacianSystemVerts");
00253         sys->vpinned= MEM_callocN(sizeof(char)*totvert, "LaplacianSystemVpinned");
00254         sys->faces= MEM_callocN(sizeof(int)*3*totface, "LaplacianSystemFaces");
00255 
00256         sys->totvert= 0;
00257         sys->totface= 0;
00258 
00259         sys->areaweights= 1;
00260         sys->storeweights= 0;
00261 
00262         /* create opennl context */
00263         nlNewContext();
00264         nlSolverParameteri(NL_NB_VARIABLES, totvert);
00265         if(lsq)
00266                 nlSolverParameteri(NL_LEAST_SQUARES, NL_TRUE);
00267 
00268         sys->context= nlGetCurrent();
00269 
00270         return sys;
00271 }
00272 
00273 void laplacian_add_vertex(LaplacianSystem *sys, float *co, int pinned)
00274 {
00275         sys->verts[sys->totvert]= co;
00276         sys->vpinned[sys->totvert]= pinned;
00277         sys->totvert++;
00278 }
00279 
00280 void laplacian_add_triangle(LaplacianSystem *sys, int v1, int v2, int v3)
00281 {
00282         sys->faces[sys->totface][0]= v1;
00283         sys->faces[sys->totface][1]= v2;
00284         sys->faces[sys->totface][2]= v3;
00285         sys->totface++;
00286 }
00287 
00288 static void laplacian_system_construct_end(LaplacianSystem *sys)
00289 {
00290         int (*face)[3];
00291         int a, totvert=sys->totvert, totface=sys->totface;
00292 
00293         laplacian_begin_solve(sys, 0);
00294 
00295         sys->varea= MEM_callocN(sizeof(float)*totvert, "LaplacianSystemVarea");
00296 
00297         sys->edgehash= BLI_edgehash_new();
00298         for(a=0, face=sys->faces; a<sys->totface; a++, face++) {
00299                 laplacian_increase_edge_count(sys->edgehash, (*face)[0], (*face)[1]);
00300                 laplacian_increase_edge_count(sys->edgehash, (*face)[1], (*face)[2]);
00301                 laplacian_increase_edge_count(sys->edgehash, (*face)[2], (*face)[0]);
00302         }
00303 
00304         if(sys->areaweights)
00305                 for(a=0, face=sys->faces; a<sys->totface; a++, face++)
00306                         laplacian_triangle_area(sys, (*face)[0], (*face)[1], (*face)[2]);
00307         
00308         for(a=0; a<totvert; a++) {
00309                 if(sys->areaweights) {
00310                         if(sys->varea[a] != 0.0f)
00311                                 sys->varea[a]= 0.5f/sys->varea[a];
00312                 }
00313                 else
00314                         sys->varea[a]= 1.0f;
00315 
00316                 /* for heat weighting */
00317                 if(sys->heat.H)
00318                         nlMatrixAdd(a, a, sys->heat.H[a]);
00319         }
00320 
00321         if(sys->storeweights)
00322                 sys->fweights= MEM_callocN(sizeof(float)*3*totface, "LaplacianFWeight");
00323         
00324         for(a=0, face=sys->faces; a<totface; a++, face++)
00325                 laplacian_triangle_weights(sys, a, (*face)[0], (*face)[1], (*face)[2]);
00326 
00327         MEM_freeN(sys->faces);
00328         sys->faces= NULL;
00329 
00330         if(sys->varea) {
00331                 MEM_freeN(sys->varea);
00332                 sys->varea= NULL;
00333         }
00334 
00335         BLI_edgehash_free(sys->edgehash, NULL);
00336         sys->edgehash= NULL;
00337 }
00338 
00339 static void laplacian_system_delete(LaplacianSystem *sys)
00340 {
00341         if(sys->verts) MEM_freeN(sys->verts);
00342         if(sys->varea) MEM_freeN(sys->varea);
00343         if(sys->vpinned) MEM_freeN(sys->vpinned);
00344         if(sys->faces) MEM_freeN(sys->faces);
00345         if(sys->fweights) MEM_freeN(sys->fweights);
00346 
00347         nlDeleteContext(sys->context);
00348         MEM_freeN(sys);
00349 }
00350 
00351 void laplacian_begin_solve(LaplacianSystem *sys, int index)
00352 {
00353         int a;
00354 
00355         if (!sys->nlbegun) {
00356                 nlBegin(NL_SYSTEM);
00357 
00358                 if(index >= 0) {
00359                         for(a=0; a<sys->totvert; a++) {
00360                                 if(sys->vpinned[a]) {
00361                                         nlSetVariable(0, a, sys->verts[a][index]);
00362                                         nlLockVariable(a);
00363                                 }
00364                         }
00365                 }
00366 
00367                 nlBegin(NL_MATRIX);
00368                 sys->nlbegun = 1;
00369         }
00370 }
00371 
00372 void laplacian_add_right_hand_side(LaplacianSystem *UNUSED(sys), int v, float value)
00373 {
00374         nlRightHandSideAdd(0, v, value);
00375 }
00376 
00377 int laplacian_system_solve(LaplacianSystem *sys)
00378 {
00379         nlEnd(NL_MATRIX);
00380         nlEnd(NL_SYSTEM);
00381         sys->nlbegun = 0;
00382 
00383         //nlPrintMatrix();
00384 
00385         return nlSolveAdvanced(NULL, NL_TRUE);
00386 }
00387 
00388 float laplacian_system_get_solution(int v)
00389 {
00390         return nlGetVariable(0, v);
00391 }
00392 
00393 /************************* Heat Bone Weighting ******************************/
00394 /* From "Automatic Rigging and Animation of 3D Characters"
00395                  Ilya Baran and Jovan Popovic, SIGGRAPH 2007 */
00396 
00397 #define C_WEIGHT                        1.0f
00398 #define WEIGHT_LIMIT_START      0.05f
00399 #define WEIGHT_LIMIT_END        0.025f
00400 #define DISTANCE_EPSILON        1e-4f
00401 
00402 typedef struct BVHCallbackUserData {
00403         float start[3];
00404         float vec[3];
00405         LaplacianSystem *sys;
00406 } BVHCallbackUserData;
00407 
00408 static void bvh_callback(void *userdata, int index, const BVHTreeRay *UNUSED(ray), BVHTreeRayHit *hit)
00409 {
00410         BVHCallbackUserData *data = (struct BVHCallbackUserData*)userdata;
00411         MFace *mf = data->sys->heat.mface + index;
00412         float (*verts)[3] = data->sys->heat.verts;
00413         float lambda, uv[2], n[3], dir[3];
00414 
00415         mul_v3_v3fl(dir, data->vec, hit->dist);
00416 
00417         if(isect_ray_tri_v3(data->start, dir, verts[mf->v1], verts[mf->v2], verts[mf->v3], &lambda, uv)) {
00418                 normal_tri_v3(n, verts[mf->v1], verts[mf->v2], verts[mf->v3]);
00419                 if(lambda < 1.0f && dot_v3v3(n, data->vec) < -1e-5f) {
00420                         hit->index = index;
00421                         hit->dist *= lambda;
00422                 }
00423         }
00424 
00425         mul_v3_v3fl(dir, data->vec, hit->dist);
00426 
00427         if(isect_ray_tri_v3(data->start, dir, verts[mf->v1], verts[mf->v3], verts[mf->v4], &lambda, uv)) {
00428                 normal_tri_v3(n, verts[mf->v1], verts[mf->v3], verts[mf->v4]);
00429                 if(lambda < 1.0f && dot_v3v3(n, data->vec) < -1e-5f) {
00430                         hit->index = index;
00431                         hit->dist *= lambda;
00432                 }
00433         }
00434 }
00435 
00436 /* Raytracing for vertex to bone/vertex visibility */
00437 static void heat_ray_tree_create(LaplacianSystem *sys)
00438 {
00439         MFace *mface = sys->heat.mface;
00440         float (*verts)[3] = sys->heat.verts;
00441         int totface = sys->heat.totface;
00442         int totvert = sys->heat.totvert;
00443         int a;
00444 
00445         sys->heat.bvhtree = BLI_bvhtree_new(totface, 0.0f, 4, 6);
00446         sys->heat.vface = MEM_callocN(sizeof(MFace*)*totvert, "HeatVFaces");
00447 
00448         for(a=0; a<totface; a++) {
00449                 MFace *mf = mface+a;
00450                 float bb[6];
00451 
00452                 INIT_MINMAX(bb, bb+3);
00453                 DO_MINMAX(verts[mf->v1], bb, bb+3);
00454                 DO_MINMAX(verts[mf->v2], bb, bb+3);
00455                 DO_MINMAX(verts[mf->v3], bb, bb+3);
00456                 if(mf->v4) {
00457                         DO_MINMAX(verts[mf->v4], bb, bb+3);
00458                 }
00459 
00460                 BLI_bvhtree_insert(sys->heat.bvhtree, a, bb, 2);
00461                 
00462                 //Setup inverse pointers to use on isect.orig
00463                 sys->heat.vface[mf->v1]= mf;
00464                 sys->heat.vface[mf->v2]= mf;
00465                 sys->heat.vface[mf->v3]= mf;
00466                 if(mf->v4) sys->heat.vface[mf->v4]= mf;
00467         }
00468 
00469         BLI_bvhtree_balance(sys->heat.bvhtree); 
00470 }
00471 
00472 static int heat_ray_source_visible(LaplacianSystem *sys, int vertex, int source)
00473 {
00474         BVHTreeRayHit hit;
00475         BVHCallbackUserData data;
00476         MFace *mface;
00477         float end[3];
00478         int visible;
00479 
00480         mface= sys->heat.vface[vertex];
00481         if(!mface)
00482                 return 1;
00483 
00484         data.sys= sys;
00485         copy_v3_v3(data.start, sys->heat.verts[vertex]);
00486 
00487         if(sys->heat.root) /* bone */
00488                 closest_to_line_segment_v3(end, data.start,
00489                         sys->heat.root[source], sys->heat.tip[source]);
00490         else /* vertex */
00491                 copy_v3_v3(end, sys->heat.source[source]);
00492 
00493         sub_v3_v3v3(data.vec, end, data.start);
00494         madd_v3_v3v3fl(data.start, data.start, data.vec, 1e-5);
00495         mul_v3_fl(data.vec, 1.0f - 2e-5f);
00496 
00497         /* pass normalized vec + distance to bvh */
00498         hit.index = -1;
00499         hit.dist = normalize_v3(data.vec);
00500 
00501         visible= BLI_bvhtree_ray_cast(sys->heat.bvhtree, data.start, data.vec, 0.0f, &hit, bvh_callback, (void*)&data) == -1;
00502 
00503         return visible;
00504 }
00505 
00506 static float heat_source_distance(LaplacianSystem *sys, int vertex, int source)
00507 {
00508         float closest[3], d[3], dist, cosine;
00509         
00510         /* compute euclidian distance */
00511         if(sys->heat.root) /* bone */
00512                 closest_to_line_segment_v3(closest, sys->heat.verts[vertex],
00513                         sys->heat.root[source], sys->heat.tip[source]);
00514         else /* vertex */
00515                 copy_v3_v3(closest, sys->heat.source[source]);
00516 
00517         sub_v3_v3v3(d, sys->heat.verts[vertex], closest);
00518         dist= normalize_v3(d);
00519 
00520         /* if the vertex normal does not point along the bone, increase distance */
00521         cosine= INPR(d, sys->heat.vnors[vertex]);
00522 
00523         return dist/(0.5f*(cosine + 1.001f));
00524 }
00525 
00526 static int heat_source_closest(LaplacianSystem *sys, int vertex, int source)
00527 {
00528         float dist;
00529 
00530         dist= heat_source_distance(sys, vertex, source);
00531 
00532         if(dist <= sys->heat.mindist[vertex]*(1.0f + DISTANCE_EPSILON))
00533                 if(heat_ray_source_visible(sys, vertex, source))
00534                         return 1;
00535                 
00536         return 0;
00537 }
00538 
00539 static void heat_set_H(LaplacianSystem *sys, int vertex)
00540 {
00541         float dist, mindist, h;
00542         int j, numclosest = 0;
00543 
00544         mindist= 1e10;
00545 
00546         /* compute minimum distance */
00547         for(j=0; j<sys->heat.numsource; j++) {
00548                 dist= heat_source_distance(sys, vertex, j);
00549 
00550                 if(dist < mindist)
00551                         mindist= dist;
00552         }
00553 
00554         sys->heat.mindist[vertex]= mindist;
00555 
00556         /* count number of sources with approximately this minimum distance */
00557         for(j=0; j<sys->heat.numsource; j++)
00558                 if(heat_source_closest(sys, vertex, j))
00559                         numclosest++;
00560 
00561         sys->heat.p[vertex]= (numclosest > 0)? 1.0f/numclosest: 0.0f;
00562 
00563         /* compute H entry */
00564         if(numclosest > 0) {
00565                 mindist= maxf(mindist, 1e-4f);
00566                 h= numclosest*C_WEIGHT/(mindist*mindist);
00567         }
00568         else
00569                 h= 0.0f;
00570         
00571         sys->heat.H[vertex]= h;
00572 }
00573 
00574 static void heat_calc_vnormals(LaplacianSystem *sys)
00575 {
00576         float fnor[3];
00577         int a, v1, v2, v3, (*face)[3];
00578 
00579         sys->heat.vnors= MEM_callocN(sizeof(float)*3*sys->totvert, "HeatVNors");
00580 
00581         for(a=0, face=sys->faces; a<sys->totface; a++, face++) {
00582                 v1= (*face)[0];
00583                 v2= (*face)[1];
00584                 v3= (*face)[2];
00585 
00586                 normal_tri_v3( fnor,sys->verts[v1], sys->verts[v2], sys->verts[v3]);
00587                 
00588                 add_v3_v3(sys->heat.vnors[v1], fnor);
00589                 add_v3_v3(sys->heat.vnors[v2], fnor);
00590                 add_v3_v3(sys->heat.vnors[v3], fnor);
00591         }
00592 
00593         for(a=0; a<sys->totvert; a++)
00594                 normalize_v3(sys->heat.vnors[a]);
00595 }
00596 
00597 static void heat_laplacian_create(LaplacianSystem *sys)
00598 {
00599         MFace *mface = sys->heat.mface, *mf;
00600         int totface= sys->heat.totface;
00601         int totvert= sys->heat.totvert;
00602         int a;
00603 
00604         /* heat specific definitions */
00605         sys->heat.mindist= MEM_callocN(sizeof(float)*totvert, "HeatMinDist");
00606         sys->heat.H= MEM_callocN(sizeof(float)*totvert, "HeatH");
00607         sys->heat.p= MEM_callocN(sizeof(float)*totvert, "HeatP");
00608 
00609         /* add verts and faces to laplacian */
00610         for(a=0; a<totvert; a++)
00611                 laplacian_add_vertex(sys, sys->heat.verts[a], 0);
00612 
00613         for(a=0, mf=mface; a<totface; a++, mf++) {
00614                 laplacian_add_triangle(sys, mf->v1, mf->v2, mf->v3);
00615                 if(mf->v4)
00616                         laplacian_add_triangle(sys, mf->v1, mf->v3, mf->v4);
00617         }
00618 
00619         /* for distance computation in set_H */
00620         heat_calc_vnormals(sys);
00621 
00622         for(a=0; a<totvert; a++)
00623                 heat_set_H(sys, a);
00624 }
00625 
00626 static void heat_system_free(LaplacianSystem *sys)
00627 {
00628         BLI_bvhtree_free(sys->heat.bvhtree);
00629         MEM_freeN(sys->heat.vface);
00630 
00631         MEM_freeN(sys->heat.mindist);
00632         MEM_freeN(sys->heat.H);
00633         MEM_freeN(sys->heat.p);
00634         MEM_freeN(sys->heat.vnors);
00635 }
00636 
00637 static float heat_limit_weight(float weight)
00638 {
00639         float t;
00640 
00641         if(weight < WEIGHT_LIMIT_END) {
00642                 return 0.0f;
00643         }
00644         else if(weight < WEIGHT_LIMIT_START) {
00645                 t= (weight - WEIGHT_LIMIT_END)/(WEIGHT_LIMIT_START - WEIGHT_LIMIT_END);
00646                 return t*WEIGHT_LIMIT_START;
00647         }
00648         else
00649                 return weight;
00650 }
00651 
00652 void heat_bone_weighting(Object *ob, Mesh *me, float (*verts)[3], int numsource, bDeformGroup **dgrouplist, bDeformGroup **dgroupflip, float (*root)[3], float (*tip)[3], int *selected, const char **err_str)
00653 {
00654         LaplacianSystem *sys;
00655         MFace *mface;
00656         float solution, weight;
00657         int *vertsflipped = NULL, *mask= NULL;
00658         int a, totface, j, bbone, firstsegment, lastsegment;
00659 
00660         *err_str= NULL;
00661 
00662         /* count triangles and create mask */
00663         if(me->editflag & ME_EDIT_PAINT_MASK)
00664                 mask= MEM_callocN(sizeof(int)*me->totvert, "heat_bone_weighting mask");
00665 
00666         for(totface=0, a=0, mface=me->mface; a<me->totface; a++, mface++) {
00667                 totface++;
00668                 if(mface->v4) totface++;
00669 
00670                 if(mask && (mface->flag & ME_FACE_SEL)) {
00671                         mask[mface->v1]= 1;
00672                         mask[mface->v2]= 1;
00673                         mask[mface->v3]= 1;
00674                         if(mface->v4)
00675                                 mask[mface->v4]= 1;
00676                 }
00677         }
00678 
00679         /* create laplacian */
00680         sys = laplacian_system_construct_begin(me->totvert, totface, 1);
00681 
00682         sys->heat.mface= me->mface;
00683         sys->heat.totface= me->totface;
00684         sys->heat.totvert= me->totvert;
00685         sys->heat.verts= verts;
00686         sys->heat.root= root;
00687         sys->heat.tip= tip;
00688         sys->heat.numsource= numsource;
00689 
00690         heat_ray_tree_create(sys);
00691         heat_laplacian_create(sys);
00692 
00693         laplacian_system_construct_end(sys);
00694 
00695         if(dgroupflip) {
00696                 vertsflipped = MEM_callocN(sizeof(int)*me->totvert, "vertsflipped");
00697                 for(a=0; a<me->totvert; a++)
00698                         vertsflipped[a] = mesh_get_x_mirror_vert(ob, a);
00699         }
00700 
00701         /* compute weights per bone */
00702         for(j=0; j<numsource; j++) {
00703                 if(!selected[j])
00704                         continue;
00705 
00706                 firstsegment= (j == 0 || dgrouplist[j-1] != dgrouplist[j]);
00707                 lastsegment= (j == numsource-1 || dgrouplist[j] != dgrouplist[j+1]);
00708                 bbone= !(firstsegment && lastsegment);
00709 
00710                 /* clear weights */
00711                 if(bbone && firstsegment) {
00712                         for(a=0; a<me->totvert; a++) {
00713                                 if(mask && !mask[a])
00714                                         continue;
00715 
00716                                 ED_vgroup_vert_remove(ob, dgrouplist[j], a);
00717                                 if(vertsflipped && dgroupflip[j] && vertsflipped[a] >= 0)
00718                                         ED_vgroup_vert_remove(ob, dgroupflip[j], vertsflipped[a]);
00719                         }
00720                 }
00721 
00722                 /* fill right hand side */
00723                 laplacian_begin_solve(sys, -1);
00724 
00725                 for(a=0; a<me->totvert; a++)
00726                         if(heat_source_closest(sys, a, j))
00727                                 laplacian_add_right_hand_side(sys, a,
00728                                         sys->heat.H[a]*sys->heat.p[a]);
00729 
00730                 /* solve */
00731                 if(laplacian_system_solve(sys)) {
00732                         /* load solution into vertex groups */
00733                         for(a=0; a<me->totvert; a++) {
00734                                 if(mask && !mask[a])
00735                                         continue;
00736 
00737                                 solution= laplacian_system_get_solution(a);
00738                                 
00739                                 if(bbone) {
00740                                         if(solution > 0.0f)
00741                                                 ED_vgroup_vert_add(ob, dgrouplist[j], a, solution,
00742                                                         WEIGHT_ADD);
00743                                 }
00744                                 else {
00745                                         weight= heat_limit_weight(solution);
00746                                         if(weight > 0.0f)
00747                                                 ED_vgroup_vert_add(ob, dgrouplist[j], a, weight,
00748                                                         WEIGHT_REPLACE);
00749                                         else
00750                                                 ED_vgroup_vert_remove(ob, dgrouplist[j], a);
00751                                 }
00752 
00753                                 /* do same for mirror */
00754                                 if(vertsflipped && dgroupflip[j] && vertsflipped[a] >= 0) {
00755                                         if(bbone) {
00756                                                 if(solution > 0.0f)
00757                                                         ED_vgroup_vert_add(ob, dgroupflip[j], vertsflipped[a],
00758                                                                 solution, WEIGHT_ADD);
00759                                         }
00760                                         else {
00761                                                 weight= heat_limit_weight(solution);
00762                                                 if(weight > 0.0f)
00763                                                         ED_vgroup_vert_add(ob, dgroupflip[j], vertsflipped[a],
00764                                                                 weight, WEIGHT_REPLACE);
00765                                                 else
00766                                                         ED_vgroup_vert_remove(ob, dgroupflip[j], vertsflipped[a]);
00767                                         }
00768                                 }
00769                         }
00770                 }
00771                 else if(*err_str == NULL) {
00772                         *err_str= "Bone Heat Weighting: failed to find solution for one or more bones";
00773                         break;
00774                 }
00775 
00776                 /* remove too small vertex weights */
00777                 if(bbone && lastsegment) {
00778                         for(a=0; a<me->totvert; a++) {
00779                                 if(mask && !mask[a])
00780                                         continue;
00781 
00782                                 weight= ED_vgroup_vert_weight(ob, dgrouplist[j], a);
00783                                 weight= heat_limit_weight(weight);
00784                                 if(weight <= 0.0f)
00785                                         ED_vgroup_vert_remove(ob, dgrouplist[j], a);
00786 
00787                                 if(vertsflipped && dgroupflip[j] && vertsflipped[a] >= 0) {
00788                                         weight= ED_vgroup_vert_weight(ob, dgroupflip[j], vertsflipped[a]);
00789                                         weight= heat_limit_weight(weight);
00790                                         if(weight <= 0.0f)
00791                                                 ED_vgroup_vert_remove(ob, dgroupflip[j], vertsflipped[a]);
00792                                 }
00793                         }
00794                 }
00795         }
00796 
00797         /* free */
00798         if(vertsflipped) MEM_freeN(vertsflipped);
00799         if(mask) MEM_freeN(mask);
00800 
00801         heat_system_free(sys);
00802 
00803         laplacian_system_delete(sys);
00804 }
00805 
00806 #ifdef RIGID_DEFORM
00807 /********************** As-Rigid-As-Possible Deformation ******************/
00808 /* From "As-Rigid-As-Possible Surface Modeling",
00809                 Olga Sorkine and Marc Alexa, ESGP 2007. */
00810 
00811 /* investigate:
00812    - transpose R in orthogonal
00813    - flipped normals and per face adding
00814    - move cancelling to transform, make origco pointer
00815 */
00816 
00817 static LaplacianSystem *RigidDeformSystem = NULL;
00818 
00819 static void rigid_add_half_edge_to_R(LaplacianSystem *sys, EditVert *v1, EditVert *v2, float w)
00820 {
00821         float e[3], e_[3];
00822         int i;
00823 
00824         sub_v3_v3v3(e, sys->rigid.origco[v1->tmp.l], sys->rigid.origco[v2->tmp.l]);
00825         sub_v3_v3v3(e_, v1->co, v2->co);
00826 
00827         /* formula (5) */
00828         for (i=0; i<3; i++) {
00829                 sys->rigid.R[v1->tmp.l][i][0] += w*e[0]*e_[i];
00830                 sys->rigid.R[v1->tmp.l][i][1] += w*e[1]*e_[i];
00831                 sys->rigid.R[v1->tmp.l][i][2] += w*e[2]*e_[i];
00832         }
00833 }
00834 
00835 static void rigid_add_edge_to_R(LaplacianSystem *sys, EditVert *v1, EditVert *v2, float w)
00836 {
00837         rigid_add_half_edge_to_R(sys, v1, v2, w);
00838         rigid_add_half_edge_to_R(sys, v2, v1, w);
00839 }
00840 
00841 static void rigid_orthogonalize_R(float R[][3])
00842 {
00843         HMatrix M, Q, S;
00844 
00845         copy_m4_m3(M, R);
00846         polar_decomp(M, Q, S);
00847         copy_m3_m4(R, Q);
00848 }
00849 
00850 static void rigid_add_half_edge_to_rhs(LaplacianSystem *sys, EditVert *v1, EditVert *v2, float w)
00851 {
00852         /* formula (8) */
00853         float Rsum[3][3], rhs[3];
00854 
00855         if (sys->vpinned[v1->tmp.l])
00856                 return;
00857 
00858         add_m3_m3m3(Rsum, sys->rigid.R[v1->tmp.l], sys->rigid.R[v2->tmp.l]);
00859         transpose_m3(Rsum);
00860 
00861         sub_v3_v3v3(rhs, sys->rigid.origco[v1->tmp.l], sys->rigid.origco[v2->tmp.l]);
00862         mul_m3_v3(Rsum, rhs);
00863         mul_v3_fl(rhs, 0.5f);
00864         mul_v3_fl(rhs, w);
00865 
00866         add_v3_v3(sys->rigid.rhs[v1->tmp.l], rhs);
00867 }
00868 
00869 static void rigid_add_edge_to_rhs(LaplacianSystem *sys, EditVert *v1, EditVert *v2, float w)
00870 {
00871         rigid_add_half_edge_to_rhs(sys, v1, v2, w);
00872         rigid_add_half_edge_to_rhs(sys, v2, v1, w);
00873 }
00874 
00875 void rigid_deform_iteration()
00876 {
00877         LaplacianSystem *sys= RigidDeformSystem;
00878         EditMesh *em;
00879         EditVert *eve;
00880         EditFace *efa;
00881         int a, i;
00882 
00883         if(!sys)
00884                 return;
00885         
00886         nlMakeCurrent(sys->context);
00887         em= sys->rigid.mesh;
00888 
00889         /* compute R */
00890         memset(sys->rigid.R, 0, sizeof(float)*3*3*sys->totvert);
00891         memset(sys->rigid.rhs, 0, sizeof(float)*3*sys->totvert);
00892 
00893         for(a=0, efa=em->faces.first; efa; efa=efa->next, a++) {
00894                 rigid_add_edge_to_R(sys, efa->v1, efa->v2, sys->fweights[a][2]);
00895                 rigid_add_edge_to_R(sys, efa->v2, efa->v3, sys->fweights[a][0]);
00896                 rigid_add_edge_to_R(sys, efa->v3, efa->v1, sys->fweights[a][1]);
00897 
00898                 if(efa->v4) {
00899                         a++;
00900                         rigid_add_edge_to_R(sys, efa->v1, efa->v3, sys->fweights[a][2]);
00901                         rigid_add_edge_to_R(sys, efa->v3, efa->v4, sys->fweights[a][0]);
00902                         rigid_add_edge_to_R(sys, efa->v4, efa->v1, sys->fweights[a][1]);
00903                 }
00904         }
00905 
00906         for(a=0, eve=em->verts.first; eve; eve=eve->next, a++) {
00907                 rigid_orthogonalize_R(sys->rigid.R[a]);
00908                 eve->tmp.l= a;
00909         }
00910         
00911         /* compute right hand sides for solving */
00912         for(a=0, efa=em->faces.first; efa; efa=efa->next, a++) {
00913                 rigid_add_edge_to_rhs(sys, efa->v1, efa->v2, sys->fweights[a][2]);
00914                 rigid_add_edge_to_rhs(sys, efa->v2, efa->v3, sys->fweights[a][0]);
00915                 rigid_add_edge_to_rhs(sys, efa->v3, efa->v1, sys->fweights[a][1]);
00916 
00917                 if(efa->v4) {
00918                         a++;
00919                         rigid_add_edge_to_rhs(sys, efa->v1, efa->v3, sys->fweights[a][2]);
00920                         rigid_add_edge_to_rhs(sys, efa->v3, efa->v4, sys->fweights[a][0]);
00921                         rigid_add_edge_to_rhs(sys, efa->v4, efa->v1, sys->fweights[a][1]);
00922                 }
00923         }
00924 
00925         /* solve for positions, for X,Y and Z separately */
00926         for(i=0; i<3; i++) {
00927                 laplacian_begin_solve(sys, i);
00928 
00929                 for(a=0; a<sys->totvert; a++)
00930                         if(!sys->vpinned[a])
00931                                 laplacian_add_right_hand_side(sys, a, sys->rigid.rhs[a][i]);
00932 
00933                 if(laplacian_system_solve(sys)) {
00934                         for(a=0, eve=em->verts.first; eve; eve=eve->next, a++)
00935                                 eve->co[i]= laplacian_system_get_solution(a);
00936                 }
00937                 else {
00938                         if(!sys->rigid.thrownerror) {
00939                                 error("RigidDeform: failed to find solution.");
00940                                 sys->rigid.thrownerror= 1;
00941                         }
00942                         break;
00943                 }
00944         }
00945 }
00946 
00947 static void rigid_laplacian_create(LaplacianSystem *sys)
00948 {
00949         EditMesh *em = sys->rigid.mesh;
00950         EditVert *eve;
00951         EditFace *efa;
00952         int a;
00953 
00954         /* add verts and faces to laplacian */
00955         for(a=0, eve=em->verts.first; eve; eve=eve->next, a++) {
00956                 laplacian_add_vertex(sys, eve->co, eve->pinned);
00957                 eve->tmp.l= a;
00958         }
00959 
00960         for(efa=em->faces.first; efa; efa=efa->next) {
00961                 laplacian_add_triangle(sys,
00962                         efa->v1->tmp.l, efa->v2->tmp.l, efa->v3->tmp.l);
00963                 if(efa->v4)
00964                         laplacian_add_triangle(sys,
00965                                 efa->v1->tmp.l, efa->v3->tmp.l, efa->v4->tmp.l);
00966         }
00967 }
00968 
00969 void rigid_deform_begin(EditMesh *em)
00970 {
00971         LaplacianSystem *sys;
00972         EditVert *eve;
00973         EditFace *efa;
00974         int a, totvert, totface;
00975 
00976         /* count vertices, triangles */
00977         for(totvert=0, eve=em->verts.first; eve; eve=eve->next)
00978                 totvert++;
00979 
00980         for(totface=0, efa=em->faces.first; efa; efa=efa->next) {
00981                 totface++;
00982                 if(efa->v4) totface++;
00983         }
00984 
00985         /* create laplacian */
00986         sys = laplacian_system_construct_begin(totvert, totface, 0);
00987 
00988         sys->rigid.mesh= em;
00989         sys->rigid.R = MEM_callocN(sizeof(float)*3*3*totvert, "RigidDeformR");
00990         sys->rigid.rhs = MEM_callocN(sizeof(float)*3*totvert, "RigidDeformRHS");
00991         sys->rigid.origco = MEM_callocN(sizeof(float)*3*totvert, "RigidDeformCo");
00992 
00993         for(a=0, eve=em->verts.first; eve; eve=eve->next, a++)
00994                 copy_v3_v3(sys->rigid.origco[a], eve->co);
00995 
00996         sys->areaweights= 0;
00997         sys->storeweights= 1;
00998 
00999         rigid_laplacian_create(sys);
01000 
01001         laplacian_system_construct_end(sys);
01002 
01003         RigidDeformSystem = sys;
01004 }
01005 
01006 void rigid_deform_end(int cancel)
01007 {
01008         LaplacianSystem *sys = RigidDeformSystem;
01009 
01010         if(sys) {
01011                 EditMesh *em = sys->rigid.mesh;
01012                 EditVert *eve;
01013                 int a;
01014 
01015                 if(cancel)
01016                         for(a=0, eve=em->verts.first; eve; eve=eve->next, a++)
01017                                 if(!eve->pinned)
01018                                         copy_v3_v3(eve->co, sys->rigid.origco[a]);
01019 
01020                 if(sys->rigid.R) MEM_freeN(sys->rigid.R);
01021                 if(sys->rigid.rhs) MEM_freeN(sys->rigid.rhs);
01022                 if(sys->rigid.origco) MEM_freeN(sys->rigid.origco);
01023 
01024                 /* free */
01025                 laplacian_system_delete(sys);
01026         }
01027 
01028         RigidDeformSystem = NULL;
01029 }
01030 #endif
01031 
01032 /************************** Harmonic Coordinates ****************************/
01033 /* From "Harmonic Coordinates for Character Articulation",
01034         Pushkar Joshi, Mark Meyer, Tony DeRose, Brian Green and Tom Sanocki,
01035         SIGGRAPH 2007. */
01036 
01037 #define EPSILON 0.0001f
01038 
01039 #define MESHDEFORM_TAG_UNTYPED  0
01040 #define MESHDEFORM_TAG_BOUNDARY 1
01041 #define MESHDEFORM_TAG_INTERIOR 2
01042 #define MESHDEFORM_TAG_EXTERIOR 3
01043 
01044 #define MESHDEFORM_LEN_THRESHOLD 1e-6f
01045 
01046 #define MESHDEFORM_MIN_INFLUENCE 0.0005f
01047 
01048 static int MESHDEFORM_OFFSET[7][3] =
01049                 {{0,0,0}, {1,0,0}, {-1,0,0}, {0,1,0}, {0,-1,0}, {0,0,1}, {0,0,-1}};
01050 
01051 typedef struct MDefBoundIsect {
01052         float co[3], uvw[4];
01053         int nvert, v[4], facing;
01054         float len;
01055 } MDefBoundIsect;
01056 
01057 typedef struct MDefBindInfluence {
01058         struct MDefBindInfluence *next;
01059         float weight;
01060         int vertex;
01061 } MDefBindInfluence;
01062 
01063 typedef struct MeshDeformBind {
01064         /* grid dimensions */
01065         float min[3], max[3];
01066         float width[3], halfwidth[3];
01067         int size, size3;
01068 
01069         /* meshes */
01070         DerivedMesh *cagedm;
01071         float (*cagecos)[3];
01072         float (*vertexcos)[3];
01073         int totvert, totcagevert;
01074 
01075         /* grids */
01076         MemArena *memarena;
01077         MDefBoundIsect *(*boundisect)[6];
01078         int *semibound;
01079         int *tag;
01080         float *phi, *totalphi;
01081 
01082         /* mesh stuff */
01083         int *inside;
01084         float *weights;
01085         MDefBindInfluence **dyngrid;
01086         float cagemat[4][4];
01087 
01088         /* direct solver */
01089         int *varidx;
01090 } MeshDeformBind;
01091 
01092 typedef struct MeshDeformIsect {
01093         float start[3];
01094         float vec[3];
01095         float labda;
01096 
01097         void *face;
01098         int isect;
01099         float u, v;
01100         
01101 } MeshDeformIsect;
01102 
01103 /* ray intersection */
01104 
01105 /* our own triangle intersection, so we can fully control the epsilons and
01106  * prevent corner case from going wrong*/
01107 static int meshdeform_tri_intersect(float orig[3], float end[3], float vert0[3],
01108         float vert1[3], float vert2[3], float *isectco, float *uvw)
01109 {
01110         float edge1[3], edge2[3], tvec[3], pvec[3], qvec[3];
01111         float det,inv_det, u, v, dir[3], isectdir[3];
01112 
01113         sub_v3_v3v3(dir, end, orig);
01114 
01115         /* find vectors for two edges sharing vert0 */
01116         sub_v3_v3v3(edge1, vert1, vert0);
01117         sub_v3_v3v3(edge2, vert2, vert0);
01118 
01119         /* begin calculating determinant - also used to calculate U parameter */
01120         cross_v3_v3v3(pvec, dir, edge2);
01121 
01122         /* if determinant is near zero, ray lies in plane of triangle */
01123         det = INPR(edge1, pvec);
01124 
01125         if (det == 0.0f)
01126                 return 0;
01127         inv_det = 1.0f / det;
01128 
01129         /* calculate distance from vert0 to ray origin */
01130         sub_v3_v3v3(tvec, orig, vert0);
01131 
01132         /* calculate U parameter and test bounds */
01133         u = INPR(tvec, pvec) * inv_det;
01134         if (u < -EPSILON || u > 1.0f+EPSILON)
01135                 return 0;
01136 
01137         /* prepare to test V parameter */
01138         cross_v3_v3v3(qvec, tvec, edge1);
01139 
01140         /* calculate V parameter and test bounds */
01141         v = INPR(dir, qvec) * inv_det;
01142         if (v < -EPSILON || u + v > 1.0f+EPSILON)
01143                 return 0;
01144 
01145         isectco[0]= (1.0f - u - v)*vert0[0] + u*vert1[0] + v*vert2[0];
01146         isectco[1]= (1.0f - u - v)*vert0[1] + u*vert1[1] + v*vert2[1];
01147         isectco[2]= (1.0f - u - v)*vert0[2] + u*vert1[2] + v*vert2[2];
01148 
01149         uvw[0]= 1.0f - u - v;
01150         uvw[1]= u;
01151         uvw[2]= v;
01152 
01153         /* check if it is within the length of the line segment */
01154         sub_v3_v3v3(isectdir, isectco, orig);
01155 
01156         if(INPR(dir, isectdir) < -EPSILON)
01157                 return 0;
01158         
01159         if(INPR(dir, dir) + EPSILON < INPR(isectdir, isectdir))
01160                 return 0;
01161 
01162         return 1;
01163 }
01164 
01165 static int meshdeform_intersect(MeshDeformBind *mdb, MeshDeformIsect *isec)
01166 {
01167         MFace *mface;
01168         float face[4][3], co[3], uvw[3], len, nor[3], end[3];
01169         int f, hit, is= 0, totface;
01170 
01171         isec->labda= 1e10;
01172 
01173         mface= mdb->cagedm->getFaceArray(mdb->cagedm);
01174         totface= mdb->cagedm->getNumFaces(mdb->cagedm);
01175 
01176         add_v3_v3v3(end, isec->start, isec->vec);
01177 
01178         for(f=0; f<totface; f++, mface++) {
01179                 copy_v3_v3(face[0], mdb->cagecos[mface->v1]);
01180                 copy_v3_v3(face[1], mdb->cagecos[mface->v2]);
01181                 copy_v3_v3(face[2], mdb->cagecos[mface->v3]);
01182 
01183                 if(mface->v4) {
01184                         copy_v3_v3(face[3], mdb->cagecos[mface->v4]);
01185                         hit = meshdeform_tri_intersect(isec->start, end, face[0], face[1], face[2], co, uvw);
01186 
01187                         if(hit) {
01188                                 normal_tri_v3( nor,face[0], face[1], face[2]);
01189                         }
01190                         else {
01191                                 hit= meshdeform_tri_intersect(isec->start, end, face[0], face[2], face[3], co, uvw);
01192                                 normal_tri_v3( nor,face[0], face[2], face[3]);
01193                         }
01194                 }
01195                 else {
01196                         hit= meshdeform_tri_intersect(isec->start, end, face[0], face[1], face[2], co, uvw);
01197                         normal_tri_v3( nor,face[0], face[1], face[2]);
01198                 }
01199 
01200                 if(hit) {
01201                         len= len_v3v3(isec->start, co)/len_v3v3(isec->start, end);
01202                         if(len < isec->labda) {
01203                                 isec->labda= len;
01204                                 isec->face = mface;
01205                                 isec->isect= (INPR(isec->vec, nor) <= 0.0f);
01206                                 is= 1;
01207                         }
01208                 }
01209         }
01210 
01211         return is;
01212 }
01213 
01214 static MDefBoundIsect *meshdeform_ray_tree_intersect(MeshDeformBind *mdb, float *co1, float *co2)
01215 {
01216         MDefBoundIsect *isect;
01217         MeshDeformIsect isec;
01218         float (*cagecos)[3];
01219         MFace *mface;
01220         float vert[4][3], len, end[3];
01221         static float epsilon[3]= {0, 0, 0}; //1e-4, 1e-4, 1e-4};
01222 
01223         /* setup isec */
01224         memset(&isec, 0, sizeof(isec));
01225         isec.labda= 1e10f;
01226 
01227         VECADD(isec.start, co1, epsilon);
01228         VECADD(end, co2, epsilon);
01229         sub_v3_v3v3(isec.vec, end, isec.start);
01230 
01231         if(meshdeform_intersect(mdb, &isec)) {
01232                 len= isec.labda;
01233                 mface=(MFace*)isec.face;
01234 
01235                 /* create MDefBoundIsect */
01236                 isect= BLI_memarena_alloc(mdb->memarena, sizeof(*isect));
01237 
01238                 /* compute intersection coordinate */
01239                 isect->co[0]= co1[0] + isec.vec[0]*len;
01240                 isect->co[1]= co1[1] + isec.vec[1]*len;
01241                 isect->co[2]= co1[2] + isec.vec[2]*len;
01242 
01243                 isect->len= len_v3v3(co1, isect->co);
01244                 if(isect->len < MESHDEFORM_LEN_THRESHOLD)
01245                         isect->len= MESHDEFORM_LEN_THRESHOLD;
01246 
01247                 isect->v[0]= mface->v1;
01248                 isect->v[1]= mface->v2;
01249                 isect->v[2]= mface->v3;
01250                 isect->v[3]= mface->v4;
01251                 isect->nvert= (mface->v4)? 4: 3;
01252 
01253                 isect->facing= isec.isect;
01254 
01255                 /* compute mean value coordinates for interpolation */
01256                 cagecos= mdb->cagecos;
01257                 copy_v3_v3(vert[0], cagecos[mface->v1]);
01258                 copy_v3_v3(vert[1], cagecos[mface->v2]);
01259                 copy_v3_v3(vert[2], cagecos[mface->v3]);
01260                 if(mface->v4) copy_v3_v3(vert[3], cagecos[mface->v4]);
01261                 interp_weights_poly_v3( isect->uvw,vert, isect->nvert, isect->co);
01262 
01263                 return isect;
01264         }
01265 
01266         return NULL;
01267 }
01268 
01269 static int meshdeform_inside_cage(MeshDeformBind *mdb, float *co)
01270 {
01271         MDefBoundIsect *isect;
01272         float outside[3], start[3], dir[3];
01273         int i;
01274 
01275         for(i=1; i<=6; i++) {
01276                 outside[0] = co[0] + (mdb->max[0] - mdb->min[0] + 1.0f)*MESHDEFORM_OFFSET[i][0];
01277                 outside[1] = co[1] + (mdb->max[1] - mdb->min[1] + 1.0f)*MESHDEFORM_OFFSET[i][1];
01278                 outside[2] = co[2] + (mdb->max[2] - mdb->min[2] + 1.0f)*MESHDEFORM_OFFSET[i][2];
01279 
01280                 copy_v3_v3(start, co);
01281                 sub_v3_v3v3(dir, outside, start);
01282                 normalize_v3(dir);
01283                 
01284                 isect = meshdeform_ray_tree_intersect(mdb, start, outside);
01285                 if(isect && !isect->facing)
01286                         return 1;
01287         }
01288 
01289         return 0;
01290 }
01291 
01292 /* solving */
01293 
01294 static int meshdeform_index(MeshDeformBind *mdb, int x, int y, int z, int n)
01295 {
01296         int size= mdb->size;
01297         
01298         x += MESHDEFORM_OFFSET[n][0];
01299         y += MESHDEFORM_OFFSET[n][1];
01300         z += MESHDEFORM_OFFSET[n][2];
01301 
01302         if(x < 0 || x >= mdb->size)
01303                 return -1;
01304         if(y < 0 || y >= mdb->size)
01305                 return -1;
01306         if(z < 0 || z >= mdb->size)
01307                 return -1;
01308 
01309         return x + y*size + z*size*size;
01310 }
01311 
01312 static void meshdeform_cell_center(MeshDeformBind *mdb, int x, int y, int z, int n, float *center)
01313 {
01314         x += MESHDEFORM_OFFSET[n][0];
01315         y += MESHDEFORM_OFFSET[n][1];
01316         z += MESHDEFORM_OFFSET[n][2];
01317 
01318         center[0]= mdb->min[0] + x*mdb->width[0] + mdb->halfwidth[0];
01319         center[1]= mdb->min[1] + y*mdb->width[1] + mdb->halfwidth[1];
01320         center[2]= mdb->min[2] + z*mdb->width[2] + mdb->halfwidth[2];
01321 }
01322 
01323 static void meshdeform_add_intersections(MeshDeformBind *mdb, int x, int y, int z)
01324 {
01325         MDefBoundIsect *isect;
01326         float center[3], ncenter[3];
01327         int i, a;
01328 
01329         a= meshdeform_index(mdb, x, y, z, 0);
01330         meshdeform_cell_center(mdb, x, y, z, 0, center);
01331 
01332         /* check each outgoing edge for intersection */
01333         for(i=1; i<=6; i++) {
01334                 if(meshdeform_index(mdb, x, y, z, i) == -1)
01335                         continue;
01336 
01337                 meshdeform_cell_center(mdb, x, y, z, i, ncenter);
01338 
01339                 isect= meshdeform_ray_tree_intersect(mdb, center, ncenter);
01340                 if(isect) {
01341                         mdb->boundisect[a][i-1]= isect;
01342                         mdb->tag[a]= MESHDEFORM_TAG_BOUNDARY;
01343                 }
01344         }
01345 }
01346 
01347 static void meshdeform_bind_floodfill(MeshDeformBind *mdb)
01348 {
01349         int *stack, *tag= mdb->tag;
01350         int a, b, i, xyz[3], stacksize, size= mdb->size;
01351 
01352         stack= MEM_callocN(sizeof(int)*mdb->size3, "MeshDeformBindStack");
01353 
01354         /* we know lower left corner is EXTERIOR because of padding */
01355         tag[0]= MESHDEFORM_TAG_EXTERIOR;
01356         stack[0]= 0;
01357         stacksize= 1;
01358 
01359         /* floodfill exterior tag */
01360         while(stacksize > 0) {
01361                 a= stack[--stacksize];
01362 
01363                 xyz[2]= a/(size*size);
01364                 xyz[1]= (a - xyz[2]*size*size)/size;
01365                 xyz[0]= a - xyz[1]*size - xyz[2]*size*size;
01366 
01367                 for(i=1; i<=6; i++) {
01368                         b= meshdeform_index(mdb, xyz[0], xyz[1], xyz[2], i);
01369 
01370                         if(b != -1) {
01371                                 if(tag[b] == MESHDEFORM_TAG_UNTYPED ||
01372                                    (tag[b] == MESHDEFORM_TAG_BOUNDARY && !mdb->boundisect[a][i-1])) {
01373                                         tag[b]= MESHDEFORM_TAG_EXTERIOR;
01374                                         stack[stacksize++]= b;
01375                                 }
01376                         }
01377                 }
01378         }
01379 
01380         /* other cells are interior */
01381         for(a=0; a<size*size*size; a++)
01382                 if(tag[a]==MESHDEFORM_TAG_UNTYPED)
01383                         tag[a]= MESHDEFORM_TAG_INTERIOR;
01384 
01385 #if 0
01386         {
01387                 int tb, ti, te, ts;
01388                 tb= ti= te= ts= 0;
01389                 for(a=0; a<size*size*size; a++)
01390                         if(tag[a]==MESHDEFORM_TAG_BOUNDARY)
01391                                 tb++;
01392                         else if(tag[a]==MESHDEFORM_TAG_INTERIOR)
01393                                 ti++;
01394                         else if(tag[a]==MESHDEFORM_TAG_EXTERIOR) {
01395                                 te++;
01396 
01397                                 if(mdb->semibound[a])
01398                                         ts++;
01399                         }
01400                 
01401                 printf("interior %d exterior %d boundary %d semi-boundary %d\n", ti, te, tb, ts);
01402         }
01403 #endif
01404 
01405         MEM_freeN(stack);
01406 }
01407 
01408 static float meshdeform_boundary_phi(MeshDeformBind *UNUSED(mdb), MDefBoundIsect *isect, int cagevert)
01409 {
01410         int a;
01411 
01412         for(a=0; a<isect->nvert; a++)
01413                 if(isect->v[a] == cagevert)
01414                         return isect->uvw[a];
01415         
01416         return 0.0f;
01417 }
01418 
01419 static float meshdeform_interp_w(MeshDeformBind *mdb, float *gridvec, float *UNUSED(vec), int UNUSED(cagevert))
01420 {
01421         float dvec[3], ivec[3], wx, wy, wz, result=0.0f;
01422         float weight, totweight= 0.0f;
01423         int i, a, x, y, z;
01424 
01425         for(i=0; i<3; i++) {
01426                 ivec[i]= (int)gridvec[i];
01427                 dvec[i]= gridvec[i] - ivec[i];
01428         }
01429 
01430         for(i=0; i<8; i++) {
01431                 if(i & 1) { x= ivec[0]+1; wx= dvec[0]; }
01432                 else { x= ivec[0]; wx= 1.0f-dvec[0]; } 
01433 
01434                 if(i & 2) { y= ivec[1]+1; wy= dvec[1]; }
01435                 else { y= ivec[1]; wy= 1.0f-dvec[1]; } 
01436 
01437                 if(i & 4) { z= ivec[2]+1; wz= dvec[2]; }
01438                 else { z= ivec[2]; wz= 1.0f-dvec[2]; } 
01439 
01440                 CLAMP(x, 0, mdb->size-1);
01441                 CLAMP(y, 0, mdb->size-1);
01442                 CLAMP(z, 0, mdb->size-1);
01443 
01444                 a= meshdeform_index(mdb, x, y, z, 0);
01445                 weight= wx*wy*wz;
01446                 result += weight*mdb->phi[a];
01447                 totweight += weight;
01448         }
01449 
01450         if(totweight > 0.0f)
01451                 result /= totweight;
01452 
01453         return result;
01454 }
01455 
01456 static void meshdeform_check_semibound(MeshDeformBind *mdb, int x, int y, int z)
01457 {
01458         int i, a;
01459 
01460         a= meshdeform_index(mdb, x, y, z, 0);
01461         if(mdb->tag[a] != MESHDEFORM_TAG_EXTERIOR)
01462                 return;
01463 
01464         for(i=1; i<=6; i++)
01465                 if(mdb->boundisect[a][i-1]) 
01466                         mdb->semibound[a]= 1;
01467 }
01468 
01469 static float meshdeform_boundary_total_weight(MeshDeformBind *mdb, int x, int y, int z)
01470 {
01471         float weight, totweight= 0.0f;
01472         int i, a;
01473 
01474         a= meshdeform_index(mdb, x, y, z, 0);
01475 
01476         /* count weight for neighbour cells */
01477         for(i=1; i<=6; i++) {
01478                 if(meshdeform_index(mdb, x, y, z, i) == -1)
01479                         continue;
01480 
01481                 if(mdb->boundisect[a][i-1])
01482                         weight= 1.0f/mdb->boundisect[a][i-1]->len;
01483                 else if(!mdb->semibound[a])
01484                         weight= 1.0f/mdb->width[0];
01485                 else
01486                         weight= 0.0f;
01487 
01488                 totweight += weight;
01489         }
01490 
01491         return totweight;
01492 }
01493 
01494 static void meshdeform_matrix_add_cell(MeshDeformBind *mdb, int x, int y, int z)
01495 {
01496         MDefBoundIsect *isect;
01497         float weight, totweight;
01498         int i, a, acenter;
01499 
01500         acenter= meshdeform_index(mdb, x, y, z, 0);
01501         if(mdb->tag[acenter] == MESHDEFORM_TAG_EXTERIOR)
01502                 return;
01503 
01504         nlMatrixAdd(mdb->varidx[acenter], mdb->varidx[acenter], 1.0f);
01505         
01506         totweight= meshdeform_boundary_total_weight(mdb, x, y, z);
01507         for(i=1; i<=6; i++) {
01508                 a= meshdeform_index(mdb, x, y, z, i);
01509                 if(a == -1 || mdb->tag[a] == MESHDEFORM_TAG_EXTERIOR)
01510                         continue;
01511 
01512                 isect= mdb->boundisect[acenter][i-1];
01513                 if (!isect) {
01514                         weight= (1.0f/mdb->width[0])/totweight;
01515                         nlMatrixAdd(mdb->varidx[acenter], mdb->varidx[a], -weight);
01516                 }
01517         }
01518 }
01519 
01520 static void meshdeform_matrix_add_rhs(MeshDeformBind *mdb, int x, int y, int z, int cagevert)
01521 {
01522         MDefBoundIsect *isect;
01523         float rhs, weight, totweight;
01524         int i, a, acenter;
01525 
01526         acenter= meshdeform_index(mdb, x, y, z, 0);
01527         if(mdb->tag[acenter] == MESHDEFORM_TAG_EXTERIOR)
01528                 return;
01529 
01530         totweight= meshdeform_boundary_total_weight(mdb, x, y, z);
01531         for(i=1; i<=6; i++) {
01532                 a= meshdeform_index(mdb, x, y, z, i);
01533                 if(a == -1)
01534                         continue;
01535 
01536                 isect= mdb->boundisect[acenter][i-1];
01537 
01538                 if (isect) {
01539                         weight= (1.0f/isect->len)/totweight;
01540                         rhs= weight*meshdeform_boundary_phi(mdb, isect, cagevert);
01541                         nlRightHandSideAdd(0, mdb->varidx[acenter], rhs);
01542                 }
01543         }
01544 }
01545 
01546 static void meshdeform_matrix_add_semibound_phi(MeshDeformBind *mdb, int x, int y, int z, int cagevert)
01547 {
01548         MDefBoundIsect *isect;
01549         float rhs, weight, totweight;
01550         int i, a;
01551 
01552         a= meshdeform_index(mdb, x, y, z, 0);
01553         if(!mdb->semibound[a])
01554                 return;
01555         
01556         mdb->phi[a]= 0.0f;
01557 
01558         totweight= meshdeform_boundary_total_weight(mdb, x, y, z);
01559         for(i=1; i<=6; i++) {
01560                 isect= mdb->boundisect[a][i-1];
01561 
01562                 if (isect) {
01563                         weight= (1.0f/isect->len)/totweight;
01564                         rhs= weight*meshdeform_boundary_phi(mdb, isect, cagevert);
01565                         mdb->phi[a] += rhs;
01566                 }
01567         }
01568 }
01569 
01570 static void meshdeform_matrix_add_exterior_phi(MeshDeformBind *mdb, int x, int y, int z, int UNUSED(cagevert))
01571 {
01572         float phi, totweight;
01573         int i, a, acenter;
01574 
01575         acenter= meshdeform_index(mdb, x, y, z, 0);
01576         if(mdb->tag[acenter] != MESHDEFORM_TAG_EXTERIOR || mdb->semibound[acenter])
01577                 return;
01578 
01579         phi= 0.0f;
01580         totweight= 0.0f;
01581         for(i=1; i<=6; i++) {
01582                 a= meshdeform_index(mdb, x, y, z, i);
01583 
01584                 if(a != -1 && mdb->semibound[a]) {
01585                         phi += mdb->phi[a];
01586                         totweight += 1.0f;
01587                 }
01588         }
01589 
01590         if(totweight != 0.0f)
01591                 mdb->phi[acenter]= phi/totweight;
01592 }
01593 
01594 static void meshdeform_matrix_solve(MeshDeformBind *mdb)
01595 {
01596         NLContext *context;
01597         float vec[3], gridvec[3];
01598         int a, b, x, y, z, totvar;
01599         char message[1024];
01600 
01601         /* setup variable indices */
01602         mdb->varidx= MEM_callocN(sizeof(int)*mdb->size3, "MeshDeformDSvaridx");
01603         for(a=0, totvar=0; a<mdb->size3; a++)
01604                 mdb->varidx[a]= (mdb->tag[a] == MESHDEFORM_TAG_EXTERIOR)? -1: totvar++;
01605 
01606         if(totvar == 0) {
01607                 MEM_freeN(mdb->varidx);
01608                 return;
01609         }
01610 
01611         progress_bar(0, "Starting mesh deform solve");
01612 
01613         /* setup opennl solver */
01614         nlNewContext();
01615         context= nlGetCurrent();
01616 
01617         nlSolverParameteri(NL_NB_VARIABLES, totvar);
01618         nlSolverParameteri(NL_NB_ROWS, totvar);
01619         nlSolverParameteri(NL_NB_RIGHT_HAND_SIDES, 1);
01620 
01621         nlBegin(NL_SYSTEM);
01622         nlBegin(NL_MATRIX);
01623 
01624         /* build matrix */
01625         for(z=0; z<mdb->size; z++)
01626                 for(y=0; y<mdb->size; y++)
01627                         for(x=0; x<mdb->size; x++)
01628                                 meshdeform_matrix_add_cell(mdb, x, y, z);
01629 
01630         /* solve for each cage vert */
01631         for(a=0; a<mdb->totcagevert; a++) {
01632                 if(a != 0) {
01633                         nlBegin(NL_SYSTEM);
01634                         nlBegin(NL_MATRIX);
01635                 }
01636 
01637                 /* fill in right hand side and solve */
01638                 for(z=0; z<mdb->size; z++)
01639                         for(y=0; y<mdb->size; y++)
01640                                 for(x=0; x<mdb->size; x++)
01641                                         meshdeform_matrix_add_rhs(mdb, x, y, z, a);
01642 
01643                 nlEnd(NL_MATRIX);
01644                 nlEnd(NL_SYSTEM);
01645 
01646 #if 0
01647                 nlPrintMatrix();
01648 #endif
01649 
01650                 if(nlSolveAdvanced(NULL, NL_TRUE)) {
01651                         for(z=0; z<mdb->size; z++)
01652                                 for(y=0; y<mdb->size; y++)
01653                                         for(x=0; x<mdb->size; x++)
01654                                                 meshdeform_matrix_add_semibound_phi(mdb, x, y, z, a);
01655 
01656                         for(z=0; z<mdb->size; z++)
01657                                 for(y=0; y<mdb->size; y++)
01658                                         for(x=0; x<mdb->size; x++)
01659                                                 meshdeform_matrix_add_exterior_phi(mdb, x, y, z, a);
01660 
01661                         for(b=0; b<mdb->size3; b++) {
01662                                 if(mdb->tag[b] != MESHDEFORM_TAG_EXTERIOR)
01663                                         mdb->phi[b]= nlGetVariable(0, mdb->varidx[b]);
01664                                 mdb->totalphi[b] += mdb->phi[b];
01665                         }
01666 
01667                         if(mdb->weights) {
01668                                 /* static bind : compute weights for each vertex */
01669                                 for(b=0; b<mdb->totvert; b++) {
01670                                         if(mdb->inside[b]) {
01671                                                 copy_v3_v3(vec, mdb->vertexcos[b]);
01672                                                 gridvec[0]= (vec[0] - mdb->min[0] - mdb->halfwidth[0])/mdb->width[0];
01673                                                 gridvec[1]= (vec[1] - mdb->min[1] - mdb->halfwidth[1])/mdb->width[1];
01674                                                 gridvec[2]= (vec[2] - mdb->min[2] - mdb->halfwidth[2])/mdb->width[2];
01675 
01676                                                 mdb->weights[b*mdb->totcagevert + a]= meshdeform_interp_w(mdb, gridvec, vec, a);
01677                                         }
01678                                 }
01679                         }
01680                         else {
01681                                 MDefBindInfluence *inf;
01682 
01683                                 /* dynamic bind */
01684                                 for(b=0; b<mdb->size3; b++) {
01685                                         if(mdb->phi[b] >= MESHDEFORM_MIN_INFLUENCE) {
01686                                                 inf= BLI_memarena_alloc(mdb->memarena, sizeof(*inf));
01687                                                 inf->vertex= a;
01688                                                 inf->weight= mdb->phi[b];
01689                                                 inf->next= mdb->dyngrid[b];
01690                                                 mdb->dyngrid[b]= inf;
01691                                         }
01692                                 }
01693                         }
01694                 }
01695                 else {
01696                         error("Mesh Deform: failed to find solution.");
01697                         break;
01698                 }
01699 
01700                 sprintf(message, "Mesh deform solve %d / %d       |||", a+1, mdb->totcagevert);
01701                 progress_bar((float)(a+1)/(float)(mdb->totcagevert), message);
01702         }
01703 
01704 #if 0
01705         /* sanity check */
01706         for(b=0; b<mdb->size3; b++)
01707                 if(mdb->tag[b] != MESHDEFORM_TAG_EXTERIOR)
01708                         if(fabs(mdb->totalphi[b] - 1.0f) > 1e-4)
01709                                 printf("totalphi deficiency [%s|%d] %d: %.10f\n",
01710                                         (mdb->tag[b] == MESHDEFORM_TAG_INTERIOR)? "interior": "boundary", mdb->semibound[b], mdb->varidx[b], mdb->totalphi[b]);
01711 #endif
01712         
01713         /* free */
01714         MEM_freeN(mdb->varidx);
01715 
01716         nlDeleteContext(context);
01717 }
01718 
01719 static void harmonic_coordinates_bind(Scene *UNUSED(scene), MeshDeformModifierData *mmd, MeshDeformBind *mdb)
01720 {
01721         MDefBindInfluence *inf;
01722         MDefInfluence *mdinf;
01723         MDefCell *cell;
01724         float center[3], vec[3], maxwidth, totweight;
01725         int a, b, x, y, z, totinside, offset;
01726 
01727         /* compute bounding box of the cage mesh */
01728         INIT_MINMAX(mdb->min, mdb->max);
01729 
01730         for(a=0; a<mdb->totcagevert; a++)
01731                 DO_MINMAX(mdb->cagecos[a], mdb->min, mdb->max);
01732 
01733         /* allocate memory */
01734         mdb->size= (2<<(mmd->gridsize-1)) + 2;
01735         mdb->size3= mdb->size*mdb->size*mdb->size;
01736         mdb->tag= MEM_callocN(sizeof(int)*mdb->size3, "MeshDeformBindTag");
01737         mdb->phi= MEM_callocN(sizeof(float)*mdb->size3, "MeshDeformBindPhi");
01738         mdb->totalphi= MEM_callocN(sizeof(float)*mdb->size3, "MeshDeformBindTotalPhi");
01739         mdb->boundisect= MEM_callocN(sizeof(*mdb->boundisect)*mdb->size3, "MDefBoundIsect");
01740         mdb->semibound= MEM_callocN(sizeof(int)*mdb->size3, "MDefSemiBound");
01741 
01742         mdb->inside= MEM_callocN(sizeof(int)*mdb->totvert, "MDefInside");
01743 
01744         if(mmd->flag & MOD_MDEF_DYNAMIC_BIND)
01745                 mdb->dyngrid= MEM_callocN(sizeof(MDefBindInfluence*)*mdb->size3, "MDefDynGrid");
01746         else
01747                 mdb->weights= MEM_callocN(sizeof(float)*mdb->totvert*mdb->totcagevert, "MDefWeights");
01748 
01749         mdb->memarena= BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "harmonic coords arena");
01750         BLI_memarena_use_calloc(mdb->memarena);
01751 
01752         /* make bounding box equal size in all directions, add padding, and compute
01753          * width of the cells */
01754         maxwidth = -1.0f;
01755         for(a=0; a<3; a++)
01756                 if(mdb->max[a]-mdb->min[a] > maxwidth)
01757                         maxwidth= mdb->max[a]-mdb->min[a];
01758 
01759         for(a=0; a<3; a++) {
01760                 center[a]= (mdb->min[a]+mdb->max[a])*0.5f;
01761                 mdb->min[a]= center[a] - maxwidth*0.5f;
01762                 mdb->max[a]= center[a] + maxwidth*0.5f;
01763 
01764                 mdb->width[a]= (mdb->max[a]-mdb->min[a])/(mdb->size-4);
01765                 mdb->min[a] -= 2.1f*mdb->width[a];
01766                 mdb->max[a] += 2.1f*mdb->width[a];
01767 
01768                 mdb->width[a]= (mdb->max[a]-mdb->min[a])/mdb->size;
01769                 mdb->halfwidth[a]= mdb->width[a]*0.5f;
01770         }
01771 
01772         progress_bar(0, "Setting up mesh deform system");
01773 
01774         totinside= 0;
01775         for(a=0; a<mdb->totvert; a++) {
01776                 copy_v3_v3(vec, mdb->vertexcos[a]);
01777                 mdb->inside[a]= meshdeform_inside_cage(mdb, vec);
01778                 if(mdb->inside[a])
01779                         totinside++;
01780         }
01781 
01782         /* free temporary MDefBoundIsects */
01783         BLI_memarena_free(mdb->memarena);
01784         mdb->memarena= BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "harmonic coords arena");
01785 
01786         /* start with all cells untyped */
01787         for(a=0; a<mdb->size3; a++)
01788                 mdb->tag[a]= MESHDEFORM_TAG_UNTYPED;
01789         
01790         /* detect intersections and tag boundary cells */
01791         for(z=0; z<mdb->size; z++)
01792                 for(y=0; y<mdb->size; y++)
01793                         for(x=0; x<mdb->size; x++)
01794                                 meshdeform_add_intersections(mdb, x, y, z);
01795 
01796         /* compute exterior and interior tags */
01797         meshdeform_bind_floodfill(mdb);
01798 
01799         for(z=0; z<mdb->size; z++)
01800                 for(y=0; y<mdb->size; y++)
01801                         for(x=0; x<mdb->size; x++)
01802                                 meshdeform_check_semibound(mdb, x, y, z);
01803 
01804         /* solve */
01805         meshdeform_matrix_solve(mdb);
01806 
01807         /* assign results */
01808         if(mmd->flag & MOD_MDEF_DYNAMIC_BIND) {
01809                 mmd->totinfluence= 0;
01810                 for(a=0; a<mdb->size3; a++)
01811                         for(inf=mdb->dyngrid[a]; inf; inf=inf->next)
01812                                 mmd->totinfluence++;
01813 
01814                 /* convert MDefBindInfluences to smaller MDefInfluences */
01815                 mmd->dyngrid= MEM_callocN(sizeof(MDefCell)*mdb->size3, "MDefDynGrid");
01816                 mmd->dyninfluences= MEM_callocN(sizeof(MDefInfluence)*mmd->totinfluence, "MDefInfluence");
01817                 offset= 0;
01818                 for(a=0; a<mdb->size3; a++) {
01819                         cell= &mmd->dyngrid[a];
01820                         cell->offset= offset;
01821 
01822                         totweight= 0.0f;
01823                         mdinf= mmd->dyninfluences + cell->offset;
01824                         for(inf=mdb->dyngrid[a]; inf; inf=inf->next, mdinf++) {
01825                                 mdinf->weight= inf->weight;
01826                                 mdinf->vertex= inf->vertex;
01827                                 totweight += mdinf->weight;
01828                                 cell->totinfluence++;
01829                         }
01830 
01831                         if(totweight > 0.0f) {
01832                                 mdinf= mmd->dyninfluences + cell->offset;
01833                                 for(b=0; b<cell->totinfluence; b++, mdinf++)
01834                                         mdinf->weight /= totweight;
01835                         }
01836 
01837                         offset += cell->totinfluence;
01838                 }
01839 
01840                 mmd->dynverts= mdb->inside;
01841                 mmd->dyngridsize= mdb->size;
01842                 copy_v3_v3(mmd->dyncellmin, mdb->min);
01843                 mmd->dyncellwidth= mdb->width[0];
01844                 MEM_freeN(mdb->dyngrid);
01845         }
01846         else {
01847                 mmd->bindweights= mdb->weights;
01848                 MEM_freeN(mdb->inside);
01849         }
01850 
01851         MEM_freeN(mdb->tag);
01852         MEM_freeN(mdb->phi);
01853         MEM_freeN(mdb->totalphi);
01854         MEM_freeN(mdb->boundisect);
01855         MEM_freeN(mdb->semibound);
01856         BLI_memarena_free(mdb->memarena);
01857 }
01858 
01859 #if 0
01860 static void heat_weighting_bind(Scene *scene, DerivedMesh *dm, MeshDeformModifierData *mmd, MeshDeformBind *mdb)
01861 {
01862         LaplacianSystem *sys;
01863         MFace *mface= dm->getFaceArray(dm), *mf;
01864         int totvert= dm->getNumVerts(dm);
01865         int totface= dm->getNumFaces(dm);
01866         float solution, weight;
01867         int a, tottri, j, thrownerror = 0;
01868 
01869         mdb->weights= MEM_callocN(sizeof(float)*mdb->totvert*mdb->totcagevert, "MDefWeights");
01870 
01871         /* count triangles */
01872         for(tottri=0, a=0, mf=mface; a<totface; a++, mf++) {
01873                 tottri++;
01874                 if(mf->v4) tottri++;
01875         }
01876 
01877         /* create laplacian */
01878         sys = laplacian_system_construct_begin(totvert, tottri, 1);
01879 
01880         sys->heat.mface= mface;
01881         sys->heat.totface= totface;
01882         sys->heat.totvert= totvert;
01883         sys->heat.verts= mdb->vertexcos;
01884         sys->heat.source = mdb->cagecos;
01885         sys->heat.numsource= mdb->totcagevert;
01886 
01887         heat_ray_tree_create(sys);
01888         heat_laplacian_create(sys);
01889 
01890         laplacian_system_construct_end(sys);
01891 
01892         /* compute weights per bone */
01893         for(j=0; j<mdb->totcagevert; j++) {
01894                 /* fill right hand side */
01895                 laplacian_begin_solve(sys, -1);
01896 
01897                 for(a=0; a<totvert; a++)
01898                         if(heat_source_closest(sys, a, j))
01899                                 laplacian_add_right_hand_side(sys, a,
01900                                         sys->heat.H[a]*sys->heat.p[a]);
01901 
01902                 /* solve */
01903                 if(laplacian_system_solve(sys)) {
01904                         /* load solution into vertex groups */
01905                         for(a=0; a<totvert; a++) {
01906                                 solution= laplacian_system_get_solution(a);
01907                                 
01908                                 weight= heat_limit_weight(solution);
01909                                 if(weight > 0.0f)
01910                                         mdb->weights[a*mdb->totcagevert + j] = weight;
01911                         }
01912                 }
01913                 else if(!thrownerror) {
01914                         error("Mesh Deform Heat Weighting:"
01915                                 " failed to find solution for one or more vertices");
01916                         thrownerror= 1;
01917                         break;
01918                 }
01919         }
01920 
01921         /* free */
01922         heat_system_free(sys);
01923         laplacian_system_delete(sys);
01924 
01925         mmd->bindweights= mdb->weights;
01926 }
01927 #endif
01928 
01929 void mesh_deform_bind(Scene *scene, MeshDeformModifierData *mmd, float *vertexcos, int totvert, float cagemat[][4])
01930 {
01931         MeshDeformBind mdb;
01932         MVert *mvert;
01933         int a;
01934 
01935         waitcursor(1);
01936         start_progress_bar();
01937 
01938         memset(&mdb, 0, sizeof(MeshDeformBind));
01939 
01940         /* get mesh and cage mesh */
01941         mdb.vertexcos= MEM_callocN(sizeof(float)*3*totvert, "MeshDeformCos");
01942         mdb.totvert= totvert;
01943         
01944         mdb.cagedm= mesh_create_derived_no_deform(scene, mmd->object, NULL, CD_MASK_BAREMESH);
01945         mdb.totcagevert= mdb.cagedm->getNumVerts(mdb.cagedm);
01946         mdb.cagecos= MEM_callocN(sizeof(*mdb.cagecos)*mdb.totcagevert, "MeshDeformBindCos");
01947         copy_m4_m4(mdb.cagemat, cagemat);
01948 
01949         mvert= mdb.cagedm->getVertArray(mdb.cagedm);
01950         for(a=0; a<mdb.totcagevert; a++)
01951                 copy_v3_v3(mdb.cagecos[a], mvert[a].co);
01952         for(a=0; a<mdb.totvert; a++)
01953                 mul_v3_m4v3(mdb.vertexcos[a], mdb.cagemat, vertexcos + a*3);
01954 
01955         /* solve */
01956 #if 0
01957         if(mmd->mode == MOD_MDEF_VOLUME)
01958                 harmonic_coordinates_bind(scene, mmd, &mdb);
01959         else
01960                 heat_weighting_bind(scene, dm, mmd, &mdb);
01961 #else
01962         harmonic_coordinates_bind(scene, mmd, &mdb);
01963 #endif
01964 
01965         /* assign bind variables */
01966         mmd->bindcagecos= (float*)mdb.cagecos;
01967         mmd->totvert= mdb.totvert;
01968         mmd->totcagevert= mdb.totcagevert;
01969         copy_m4_m4(mmd->bindmat, mmd->object->obmat);
01970 
01971         /* transform bindcagecos to world space */
01972         for(a=0; a<mdb.totcagevert; a++)
01973                 mul_m4_v3(mmd->object->obmat, mmd->bindcagecos+a*3);
01974 
01975         /* free */
01976         mdb.cagedm->release(mdb.cagedm);
01977         MEM_freeN(mdb.vertexcos);
01978 
01979         /* compact weights */
01980         modifier_mdef_compact_influences((ModifierData*)mmd);
01981 
01982         end_progress_bar();
01983         waitcursor(0);
01984 }
01985