Blender V2.61 - r43446

meshlaplacian.c

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