Blender V2.61 - r43446
|
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) Blender Foundation. 00019 * All rights reserved. 00020 * 00021 * The Original Code is: all of this file. 00022 * 00023 * Contributor(s): Andr Pinto. 00024 * 00025 * ***** END GPL LICENSE BLOCK ***** 00026 */ 00027 00032 #include <stdio.h> 00033 #include <string.h> 00034 #include <math.h> 00035 #include <assert.h> 00036 00037 #include "DNA_meshdata_types.h" 00038 00039 #include "BLI_editVert.h" 00040 #include "BLI_utildefines.h" 00041 #include "BLI_linklist.h" 00042 00043 #include "BKE_DerivedMesh.h" 00044 00045 00046 #include "BLI_math.h" 00047 #include "MEM_guardedalloc.h" 00048 00049 /* Math stuff for ray casting on mesh faces and for nearest surface */ 00050 00051 float bvhtree_ray_tri_intersection(const BVHTreeRay *ray, const float UNUSED(m_dist), const float v0[3], const float v1[3], const float v2[3]) 00052 { 00053 float dist; 00054 00055 if(isect_ray_tri_epsilon_v3(ray->origin, ray->direction, v0, v1, v2, &dist, NULL, FLT_EPSILON)) 00056 return dist; 00057 00058 return FLT_MAX; 00059 } 00060 00061 static float sphereray_tri_intersection(const BVHTreeRay *ray, float radius, const float m_dist, const float v0[3], const float v1[3], const float v2[3]) 00062 { 00063 00064 float idist; 00065 float p1[3]; 00066 float plane_normal[3], hit_point[3]; 00067 00068 normal_tri_v3(plane_normal, v0, v1, v2); 00069 00070 madd_v3_v3v3fl(p1, ray->origin, ray->direction, m_dist); 00071 if(isect_sweeping_sphere_tri_v3(ray->origin, p1, radius, v0, v1, v2, &idist, hit_point)) 00072 { 00073 return idist * m_dist; 00074 } 00075 00076 return FLT_MAX; 00077 } 00078 00079 00080 /* 00081 * Function adapted from David Eberly's distance tools (LGPL) 00082 * http://www.geometrictools.com/LibFoundation/Distance/Distance.html 00083 */ 00084 float nearest_point_in_tri_surface(const float v0[3], const float v1[3], const float v2[3], const float p[3], int *v, int *e, float nearest[3]) 00085 { 00086 float diff[3]; 00087 float e0[3]; 00088 float e1[3]; 00089 float A00; 00090 float A01; 00091 float A11; 00092 float B0; 00093 float B1; 00094 float C; 00095 float Det; 00096 float S; 00097 float T; 00098 float sqrDist; 00099 int lv = -1, le = -1; 00100 00101 sub_v3_v3v3(diff, v0, p); 00102 sub_v3_v3v3(e0, v1, v0); 00103 sub_v3_v3v3(e1, v2, v0); 00104 00105 A00 = dot_v3v3(e0, e0); 00106 A01 = dot_v3v3(e0, e1 ); 00107 A11 = dot_v3v3(e1, e1 ); 00108 B0 = dot_v3v3(diff, e0 ); 00109 B1 = dot_v3v3(diff, e1 ); 00110 C = dot_v3v3(diff, diff ); 00111 Det = fabs( A00 * A11 - A01 * A01 ); 00112 S = A01 * B1 - A11 * B0; 00113 T = A01 * B0 - A00 * B1; 00114 00115 if ( S + T <= Det ) 00116 { 00117 if ( S < 0.0f ) 00118 { 00119 if ( T < 0.0f ) // Region 4 00120 { 00121 if ( B0 < 0.0f ) 00122 { 00123 T = 0.0f; 00124 if ( -B0 >= A00 ) 00125 { 00126 S = 1.0f; 00127 sqrDist = A00 + 2.0f * B0 + C; 00128 lv = 1; 00129 } 00130 else 00131 { 00132 if(fabsf(A00) > FLT_EPSILON) 00133 S = -B0/A00; 00134 else 00135 S = 0.0f; 00136 sqrDist = B0 * S + C; 00137 le = 0; 00138 } 00139 } 00140 else 00141 { 00142 S = 0.0f; 00143 if ( B1 >= 0.0f ) 00144 { 00145 T = 0.0f; 00146 sqrDist = C; 00147 lv = 0; 00148 } 00149 else if ( -B1 >= A11 ) 00150 { 00151 T = 1.0f; 00152 sqrDist = A11 + 2.0f * B1 + C; 00153 lv = 2; 00154 } 00155 else 00156 { 00157 if(fabsf(A11) > FLT_EPSILON) 00158 T = -B1 / A11; 00159 else 00160 T = 0.0f; 00161 sqrDist = B1 * T + C; 00162 le = 1; 00163 } 00164 } 00165 } 00166 else // Region 3 00167 { 00168 S = 0.0f; 00169 if ( B1 >= 0.0f ) 00170 { 00171 T = 0.0f; 00172 sqrDist = C; 00173 lv = 0; 00174 } 00175 else if ( -B1 >= A11 ) 00176 { 00177 T = 1.0f; 00178 sqrDist = A11 + 2.0f * B1 + C; 00179 lv = 2; 00180 } 00181 else 00182 { 00183 if(fabsf(A11) > FLT_EPSILON) 00184 T = -B1 / A11; 00185 else 00186 T = 0.0; 00187 sqrDist = B1 * T + C; 00188 le = 1; 00189 } 00190 } 00191 } 00192 else if ( T < 0.0f ) // Region 5 00193 { 00194 T = 0.0f; 00195 if ( B0 >= 0.0f ) 00196 { 00197 S = 0.0f; 00198 sqrDist = C; 00199 lv = 0; 00200 } 00201 else if ( -B0 >= A00 ) 00202 { 00203 S = 1.0f; 00204 sqrDist = A00 + 2.0f * B0 + C; 00205 lv = 1; 00206 } 00207 else 00208 { 00209 if(fabsf(A00) > FLT_EPSILON) 00210 S = -B0 / A00; 00211 else 00212 S = 0.0f; 00213 sqrDist = B0 * S + C; 00214 le = 0; 00215 } 00216 } 00217 else // Region 0 00218 { 00219 // Minimum at interior lv 00220 float invDet; 00221 if(fabsf(Det) > FLT_EPSILON) 00222 invDet = 1.0f / Det; 00223 else 00224 invDet = 0.0f; 00225 S *= invDet; 00226 T *= invDet; 00227 sqrDist = S * ( A00 * S + A01 * T + 2.0f * B0) + 00228 T * ( A01 * S + A11 * T + 2.0f * B1 ) + C; 00229 } 00230 } 00231 else 00232 { 00233 float tmp0, tmp1, numer, denom; 00234 00235 if ( S < 0.0f ) // Region 2 00236 { 00237 tmp0 = A01 + B0; 00238 tmp1 = A11 + B1; 00239 if ( tmp1 > tmp0 ) 00240 { 00241 numer = tmp1 - tmp0; 00242 denom = A00 - 2.0f * A01 + A11; 00243 if ( numer >= denom ) 00244 { 00245 S = 1.0f; 00246 T = 0.0f; 00247 sqrDist = A00 + 2.0f * B0 + C; 00248 lv = 1; 00249 } 00250 else 00251 { 00252 if(fabsf(denom) > FLT_EPSILON) 00253 S = numer / denom; 00254 else 00255 S = 0.0f; 00256 T = 1.0f - S; 00257 sqrDist = S * ( A00 * S + A01 * T + 2.0f * B0 ) + 00258 T * ( A01 * S + A11 * T + 2.0f * B1 ) + C; 00259 le = 2; 00260 } 00261 } 00262 else 00263 { 00264 S = 0.0f; 00265 if ( tmp1 <= 0.0f ) 00266 { 00267 T = 1.0f; 00268 sqrDist = A11 + 2.0f * B1 + C; 00269 lv = 2; 00270 } 00271 else if ( B1 >= 0.0f ) 00272 { 00273 T = 0.0f; 00274 sqrDist = C; 00275 lv = 0; 00276 } 00277 else 00278 { 00279 if(fabsf(A11) > FLT_EPSILON) 00280 T = -B1 / A11; 00281 else 00282 T = 0.0f; 00283 sqrDist = B1 * T + C; 00284 le = 1; 00285 } 00286 } 00287 } 00288 else if ( T < 0.0f ) // Region 6 00289 { 00290 tmp0 = A01 + B1; 00291 tmp1 = A00 + B0; 00292 if ( tmp1 > tmp0 ) 00293 { 00294 numer = tmp1 - tmp0; 00295 denom = A00 - 2.0f * A01 + A11; 00296 if ( numer >= denom ) 00297 { 00298 T = 1.0f; 00299 S = 0.0f; 00300 sqrDist = A11 + 2.0f * B1 + C; 00301 lv = 2; 00302 } 00303 else 00304 { 00305 if(fabsf(denom) > FLT_EPSILON) 00306 T = numer / denom; 00307 else 00308 T = 0.0f; 00309 S = 1.0f - T; 00310 sqrDist = S * ( A00 * S + A01 * T + 2.0f * B0 ) + 00311 T * ( A01 * S + A11 * T + 2.0f * B1 ) + C; 00312 le = 2; 00313 } 00314 } 00315 else 00316 { 00317 T = 0.0f; 00318 if ( tmp1 <= 0.0f ) 00319 { 00320 S = 1.0f; 00321 sqrDist = A00 + 2.0f * B0 + C; 00322 lv = 1; 00323 } 00324 else if ( B0 >= 0.0f ) 00325 { 00326 S = 0.0f; 00327 sqrDist = C; 00328 lv = 0; 00329 } 00330 else 00331 { 00332 if(fabsf(A00) > FLT_EPSILON) 00333 S = -B0 / A00; 00334 else 00335 S = 0.0f; 00336 sqrDist = B0 * S + C; 00337 le = 0; 00338 } 00339 } 00340 } 00341 else // Region 1 00342 { 00343 numer = A11 + B1 - A01 - B0; 00344 if ( numer <= 0.0f ) 00345 { 00346 S = 0.0f; 00347 T = 1.0f; 00348 sqrDist = A11 + 2.0f * B1 + C; 00349 lv = 2; 00350 } 00351 else 00352 { 00353 denom = A00 - 2.0f * A01 + A11; 00354 if ( numer >= denom ) 00355 { 00356 S = 1.0f; 00357 T = 0.0f; 00358 sqrDist = A00 + 2.0f * B0 + C; 00359 lv = 1; 00360 } 00361 else 00362 { 00363 if(fabsf(denom) > FLT_EPSILON) 00364 S = numer / denom; 00365 else 00366 S = 0.0f; 00367 T = 1.0f - S; 00368 sqrDist = S * ( A00 * S + A01 * T + 2.0f * B0 ) + 00369 T * ( A01 * S + A11 * T + 2.0f * B1 ) + C; 00370 le = 2; 00371 } 00372 } 00373 } 00374 } 00375 00376 // Account for numerical round-off error 00377 if ( sqrDist < FLT_EPSILON ) 00378 sqrDist = 0.0f; 00379 00380 { 00381 float w[3], x[3], y[3], z[3]; 00382 copy_v3_v3(w, v0); 00383 copy_v3_v3(x, e0); 00384 mul_v3_fl(x, S); 00385 copy_v3_v3(y, e1); 00386 mul_v3_fl(y, T); 00387 add_v3_v3v3(z, w, x); 00388 add_v3_v3v3(z, z, y); 00389 //sub_v3_v3v3(d, p, z); 00390 copy_v3_v3(nearest, z); 00391 // d = p - ( v0 + S * e0 + T * e1 ); 00392 } 00393 *v = lv; 00394 *e = le; 00395 00396 return sqrDist; 00397 } 00398 00399 00400 /* 00401 * BVH from meshs callbacks 00402 */ 00403 00404 // Callback to bvh tree nearest point. The tree must bust have been built using bvhtree_from_mesh_faces. 00405 // userdata must be a BVHMeshCallbackUserdata built from the same mesh as the tree. 00406 static void mesh_faces_nearest_point(void *userdata, int index, const float co[3], BVHTreeNearest *nearest) 00407 { 00408 const BVHTreeFromMesh *data = (BVHTreeFromMesh*) userdata; 00409 MVert *vert = data->vert; 00410 MFace *face = data->face + index; 00411 00412 float *t0, *t1, *t2, *t3; 00413 t0 = vert[ face->v1 ].co; 00414 t1 = vert[ face->v2 ].co; 00415 t2 = vert[ face->v3 ].co; 00416 t3 = face->v4 ? vert[ face->v4].co : NULL; 00417 00418 00419 do 00420 { 00421 float nearest_tmp[3], dist; 00422 int vertex, edge; 00423 00424 dist = nearest_point_in_tri_surface(t0, t1, t2, co, &vertex, &edge, nearest_tmp); 00425 if(dist < nearest->dist) 00426 { 00427 nearest->index = index; 00428 nearest->dist = dist; 00429 copy_v3_v3(nearest->co, nearest_tmp); 00430 normal_tri_v3( nearest->no,t0, t1, t2); 00431 } 00432 00433 t1 = t2; 00434 t2 = t3; 00435 t3 = NULL; 00436 00437 } while(t2); 00438 } 00439 00440 // Callback to bvh tree raycast. The tree must bust have been built using bvhtree_from_mesh_faces. 00441 // userdata must be a BVHMeshCallbackUserdata built from the same mesh as the tree. 00442 static void mesh_faces_spherecast(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit) 00443 { 00444 const BVHTreeFromMesh *data = (BVHTreeFromMesh*) userdata; 00445 MVert *vert = data->vert; 00446 MFace *face = data->face + index; 00447 00448 float *t0, *t1, *t2, *t3; 00449 t0 = vert[ face->v1 ].co; 00450 t1 = vert[ face->v2 ].co; 00451 t2 = vert[ face->v3 ].co; 00452 t3 = face->v4 ? vert[ face->v4].co : NULL; 00453 00454 00455 do 00456 { 00457 float dist; 00458 if(data->sphere_radius == 0.0f) 00459 dist = bvhtree_ray_tri_intersection(ray, hit->dist, t0, t1, t2); 00460 else 00461 dist = sphereray_tri_intersection(ray, data->sphere_radius, hit->dist, t0, t1, t2); 00462 00463 if(dist >= 0 && dist < hit->dist) 00464 { 00465 hit->index = index; 00466 hit->dist = dist; 00467 madd_v3_v3v3fl(hit->co, ray->origin, ray->direction, dist); 00468 00469 normal_tri_v3( hit->no,t0, t1, t2); 00470 } 00471 00472 t1 = t2; 00473 t2 = t3; 00474 t3 = NULL; 00475 00476 } while(t2); 00477 } 00478 00479 // Callback to bvh tree nearest point. The tree must bust have been built using bvhtree_from_mesh_edges. 00480 // userdata must be a BVHMeshCallbackUserdata built from the same mesh as the tree. 00481 static void mesh_edges_nearest_point(void *userdata, int index, const float co[3], BVHTreeNearest *nearest) 00482 { 00483 const BVHTreeFromMesh *data = (BVHTreeFromMesh*) userdata; 00484 MVert *vert = data->vert; 00485 MEdge *edge = data->edge + index; 00486 float nearest_tmp[3], dist; 00487 00488 float *t0, *t1; 00489 t0 = vert[ edge->v1 ].co; 00490 t1 = vert[ edge->v2 ].co; 00491 00492 closest_to_line_segment_v3(nearest_tmp, co, t0, t1); 00493 dist = len_squared_v3v3(nearest_tmp, co); 00494 00495 if(dist < nearest->dist) 00496 { 00497 nearest->index = index; 00498 nearest->dist = dist; 00499 copy_v3_v3(nearest->co, nearest_tmp); 00500 sub_v3_v3v3(nearest->no, t0, t1); 00501 normalize_v3(nearest->no); 00502 } 00503 } 00504 00505 /* 00506 * BVH builders 00507 */ 00508 // Builds a bvh tree.. where nodes are the vertexs of the given mesh 00509 BVHTree* bvhtree_from_mesh_verts(BVHTreeFromMesh *data, DerivedMesh *mesh, float epsilon, int tree_type, int axis) 00510 { 00511 BVHTree *tree = bvhcache_find(&mesh->bvhCache, BVHTREE_FROM_VERTICES); 00512 00513 //Not in cache 00514 if(tree == NULL) 00515 { 00516 int i; 00517 int numVerts= mesh->getNumVerts(mesh); 00518 MVert *vert = mesh->getVertDataArray(mesh, CD_MVERT); 00519 00520 if(vert != NULL) 00521 { 00522 tree = BLI_bvhtree_new(numVerts, epsilon, tree_type, axis); 00523 00524 if(tree != NULL) 00525 { 00526 for(i = 0; i < numVerts; i++) 00527 BLI_bvhtree_insert(tree, i, vert[i].co, 1); 00528 00529 BLI_bvhtree_balance(tree); 00530 00531 //Save on cache for later use 00532 // printf("BVHTree built and saved on cache\n"); 00533 bvhcache_insert(&mesh->bvhCache, tree, BVHTREE_FROM_VERTICES); 00534 } 00535 } 00536 } 00537 else 00538 { 00539 // printf("BVHTree is already build, using cached tree\n"); 00540 } 00541 00542 00543 //Setup BVHTreeFromMesh 00544 memset(data, 0, sizeof(*data)); 00545 data->tree = tree; 00546 00547 if(data->tree) 00548 { 00549 data->cached = TRUE; 00550 00551 //a NULL nearest callback works fine 00552 //remeber the min distance to point is the same as the min distance to BV of point 00553 data->nearest_callback = NULL; 00554 data->raycast_callback = NULL; 00555 00556 data->mesh = mesh; 00557 data->vert = mesh->getVertDataArray(mesh, CD_MVERT); 00558 data->face = mesh->getFaceDataArray(mesh, CD_MFACE); 00559 00560 data->sphere_radius = epsilon; 00561 } 00562 00563 return data->tree; 00564 } 00565 00566 // Builds a bvh tree.. where nodes are the faces of the given mesh. 00567 BVHTree* bvhtree_from_mesh_faces(BVHTreeFromMesh *data, DerivedMesh *mesh, float epsilon, int tree_type, int axis) 00568 { 00569 BVHTree *tree = bvhcache_find(&mesh->bvhCache, BVHTREE_FROM_FACES); 00570 00571 //Not in cache 00572 if(tree == NULL) 00573 { 00574 int i; 00575 int numFaces= mesh->getNumFaces(mesh); 00576 MVert *vert = mesh->getVertDataArray(mesh, CD_MVERT); 00577 MFace *face = mesh->getFaceDataArray(mesh, CD_MFACE); 00578 00579 if(vert != NULL && face != NULL) 00580 { 00581 /* Create a bvh-tree of the given target */ 00582 tree = BLI_bvhtree_new(numFaces, epsilon, tree_type, axis); 00583 if(tree != NULL) 00584 { 00585 /* XXX, for snap only, em & dm are assumed to be aligned, since dm is the em's cage */ 00586 EditMesh *em= data->em_evil; 00587 if(em) { 00588 EditFace *efa= em->faces.first; 00589 for(i = 0; i < numFaces; i++, efa= efa->next) { 00590 if(!(efa->f & 1) && efa->h==0 && !((efa->v1->f&1)+(efa->v2->f&1)+(efa->v3->f&1)+(efa->v4?efa->v4->f&1:0))) { 00591 float co[4][3]; 00592 copy_v3_v3(co[0], vert[ face[i].v1 ].co); 00593 copy_v3_v3(co[1], vert[ face[i].v2 ].co); 00594 copy_v3_v3(co[2], vert[ face[i].v3 ].co); 00595 if(face[i].v4) 00596 copy_v3_v3(co[3], vert[ face[i].v4 ].co); 00597 00598 BLI_bvhtree_insert(tree, i, co[0], face[i].v4 ? 4 : 3); 00599 } 00600 } 00601 } 00602 else { 00603 for(i = 0; i < numFaces; i++) { 00604 float co[4][3]; 00605 copy_v3_v3(co[0], vert[ face[i].v1 ].co); 00606 copy_v3_v3(co[1], vert[ face[i].v2 ].co); 00607 copy_v3_v3(co[2], vert[ face[i].v3 ].co); 00608 if(face[i].v4) 00609 copy_v3_v3(co[3], vert[ face[i].v4 ].co); 00610 00611 BLI_bvhtree_insert(tree, i, co[0], face[i].v4 ? 4 : 3); 00612 } 00613 } 00614 BLI_bvhtree_balance(tree); 00615 00616 //Save on cache for later use 00617 // printf("BVHTree built and saved on cache\n"); 00618 bvhcache_insert(&mesh->bvhCache, tree, BVHTREE_FROM_FACES); 00619 } 00620 } 00621 } 00622 else 00623 { 00624 // printf("BVHTree is already build, using cached tree\n"); 00625 } 00626 00627 00628 //Setup BVHTreeFromMesh 00629 memset(data, 0, sizeof(*data)); 00630 data->tree = tree; 00631 00632 if(data->tree) 00633 { 00634 data->cached = TRUE; 00635 00636 data->nearest_callback = mesh_faces_nearest_point; 00637 data->raycast_callback = mesh_faces_spherecast; 00638 00639 data->mesh = mesh; 00640 data->vert = mesh->getVertDataArray(mesh, CD_MVERT); 00641 data->face = mesh->getFaceDataArray(mesh, CD_MFACE); 00642 00643 data->sphere_radius = epsilon; 00644 } 00645 return data->tree; 00646 00647 } 00648 00649 // Builds a bvh tree.. where nodes are the faces of the given mesh. 00650 BVHTree* bvhtree_from_mesh_edges(BVHTreeFromMesh *data, DerivedMesh *mesh, float epsilon, int tree_type, int axis) 00651 { 00652 BVHTree *tree = bvhcache_find(&mesh->bvhCache, BVHTREE_FROM_EDGES); 00653 00654 //Not in cache 00655 if(tree == NULL) 00656 { 00657 int i; 00658 int numEdges= mesh->getNumEdges(mesh); 00659 MVert *vert = mesh->getVertDataArray(mesh, CD_MVERT); 00660 MEdge *edge = mesh->getEdgeDataArray(mesh, CD_MEDGE); 00661 00662 if(vert != NULL && edge != NULL) 00663 { 00664 /* Create a bvh-tree of the given target */ 00665 tree = BLI_bvhtree_new(numEdges, epsilon, tree_type, axis); 00666 if(tree != NULL) 00667 { 00668 for(i = 0; i < numEdges; i++) 00669 { 00670 float co[4][3]; 00671 copy_v3_v3(co[0], vert[ edge[i].v1 ].co); 00672 copy_v3_v3(co[1], vert[ edge[i].v2 ].co); 00673 00674 BLI_bvhtree_insert(tree, i, co[0], 2); 00675 } 00676 BLI_bvhtree_balance(tree); 00677 00678 //Save on cache for later use 00679 // printf("BVHTree built and saved on cache\n"); 00680 bvhcache_insert(&mesh->bvhCache, tree, BVHTREE_FROM_EDGES); 00681 } 00682 } 00683 } 00684 else 00685 { 00686 // printf("BVHTree is already build, using cached tree\n"); 00687 } 00688 00689 00690 //Setup BVHTreeFromMesh 00691 memset(data, 0, sizeof(*data)); 00692 data->tree = tree; 00693 00694 if(data->tree) 00695 { 00696 data->cached = TRUE; 00697 00698 data->nearest_callback = mesh_edges_nearest_point; 00699 data->raycast_callback = NULL; 00700 00701 data->mesh = mesh; 00702 data->vert = mesh->getVertDataArray(mesh, CD_MVERT); 00703 data->edge = mesh->getEdgeDataArray(mesh, CD_MEDGE); 00704 00705 data->sphere_radius = epsilon; 00706 } 00707 return data->tree; 00708 00709 } 00710 00711 // Frees data allocated by a call to bvhtree_from_mesh_*. 00712 void free_bvhtree_from_mesh(struct BVHTreeFromMesh *data) 00713 { 00714 if(data->tree) 00715 { 00716 if(!data->cached) 00717 BLI_bvhtree_free(data->tree); 00718 00719 memset( data, 0, sizeof(*data) ); 00720 } 00721 } 00722 00723 00724 /* BVHCache */ 00725 typedef struct BVHCacheItem 00726 { 00727 int type; 00728 BVHTree *tree; 00729 00730 } BVHCacheItem; 00731 00732 static void bvhcacheitem_set_if_match(void *_cached, void *_search) 00733 { 00734 BVHCacheItem * cached = (BVHCacheItem *)_cached; 00735 BVHCacheItem * search = (BVHCacheItem *)_search; 00736 00737 if(search->type == cached->type) 00738 { 00739 search->tree = cached->tree; 00740 } 00741 } 00742 00743 BVHTree *bvhcache_find(BVHCache *cache, int type) 00744 { 00745 BVHCacheItem item; 00746 item.type = type; 00747 item.tree = NULL; 00748 00749 BLI_linklist_apply(*cache, bvhcacheitem_set_if_match, &item); 00750 return item.tree; 00751 } 00752 00753 void bvhcache_insert(BVHCache *cache, BVHTree *tree, int type) 00754 { 00755 BVHCacheItem *item = NULL; 00756 00757 assert( tree != NULL ); 00758 assert( bvhcache_find(cache, type) == NULL ); 00759 00760 item = MEM_mallocN(sizeof(BVHCacheItem), "BVHCacheItem"); 00761 assert( item != NULL ); 00762 00763 item->type = type; 00764 item->tree = tree; 00765 00766 BLI_linklist_prepend( cache, item ); 00767 } 00768 00769 00770 void bvhcache_init(BVHCache *cache) 00771 { 00772 *cache = NULL; 00773 } 00774 00775 static void bvhcacheitem_free(void *_item) 00776 { 00777 BVHCacheItem *item = (BVHCacheItem *)_item; 00778 00779 BLI_bvhtree_free(item->tree); 00780 MEM_freeN(item); 00781 } 00782 00783 00784 void bvhcache_free(BVHCache *cache) 00785 { 00786 BLI_linklist_free(*cache, (LinkNodeFreeFP)bvhcacheitem_free); 00787 *cache = NULL; 00788 } 00789 00790