Blender V2.61 - r43446

mesh_navmesh.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) 2011 by Blender Foundation
00019  * All rights reserved.
00020  *
00021  * The Original Code is: all of this file.
00022  *
00023  * Contributor(s): Benoit Bolsee,
00024  *                 Nick Samarin
00025  *
00026  * ***** END GPL LICENSE BLOCK *****
00027  */
00028 
00029 #include <math.h>
00030 
00031 #include "MEM_guardedalloc.h"
00032 
00033 #include "DNA_scene_types.h"
00034 #include "DNA_object_types.h"
00035 #include "DNA_meshdata_types.h"
00036 #include "DNA_modifier_types.h"
00037 #include "DNA_ID.h"
00038 
00039 #include "BKE_library.h"
00040 #include "BKE_depsgraph.h"
00041 #include "BKE_context.h"
00042 #include "BKE_main.h"
00043 #include "BKE_mesh.h"
00044 #include "BKE_modifier.h"
00045 #include "BKE_scene.h"
00046 #include "BKE_DerivedMesh.h"
00047 #include "BKE_cdderivedmesh.h"
00048 #include "BKE_report.h"
00049 
00050 #include "BLI_editVert.h"
00051 #include "BLI_listbase.h"
00052 #include "BLI_utildefines.h"
00053 #include "BLI_math_vector.h"
00054 #include "BLI_linklist.h"
00055 
00056 #include "ED_object.h"
00057 #include "ED_mesh.h"
00058 #include "ED_screen.h"
00059 
00060 #include "RNA_access.h"
00061 
00062 #include "WM_api.h"
00063 #include "WM_types.h"
00064 
00065 #include "mesh_intern.h"
00066 #include "recast-capi.h"
00067 
00068 static void createVertsTrisData(bContext *C, LinkNode* obs, int *nverts_r, float **verts_r, int *ntris_r, int **tris_r)
00069 {
00070     MVert *mvert;
00071     int nfaces= 0, *tri, i, curnverts, basenverts, curnfaces;
00072     MFace *mface;
00073     float co[3], wco[3];
00074     Object *ob;
00075     LinkNode *oblink, *dmlink;
00076     DerivedMesh *dm;
00077     Scene* scene= CTX_data_scene(C);
00078     LinkNode* dms= NULL;
00079 
00080     int nverts, ntris, *tris;
00081     float *verts;
00082 
00083     nverts= 0;
00084     ntris= 0;
00085 
00086     /* calculate number of verts and tris */
00087     for(oblink= obs; oblink; oblink= oblink->next) {
00088         ob= (Object*) oblink->link;
00089         dm= mesh_create_derived_no_virtual(scene, ob, NULL, CD_MASK_MESH);
00090         BLI_linklist_append(&dms, (void*)dm);
00091 
00092         nverts+= dm->getNumVerts(dm);
00093         nfaces= dm->getNumFaces(dm);
00094         ntris+= nfaces;
00095 
00096         /* resolve quad faces */
00097         mface= dm->getFaceArray(dm);
00098         for(i= 0; i<nfaces; i++) {
00099             MFace* mf= &mface[i];
00100             if(mf->v4)
00101                 ntris+=1;
00102         }
00103     }
00104 
00105     /* create data */
00106     verts= MEM_mallocN(sizeof(float)*3*nverts, "createVertsTrisData verts");
00107     tris= MEM_mallocN(sizeof(int)*3*ntris, "createVertsTrisData faces");
00108 
00109     basenverts= 0;
00110     tri= tris;
00111     for(oblink= obs, dmlink= dms; oblink && dmlink;
00112             oblink= oblink->next, dmlink= dmlink->next) {
00113         ob= (Object*) oblink->link;
00114         dm= (DerivedMesh*) dmlink->link;
00115 
00116         curnverts= dm->getNumVerts(dm);
00117         mvert= dm->getVertArray(dm);
00118 
00119         /* copy verts */
00120         for(i= 0; i<curnverts; i++) {
00121             MVert *v= &mvert[i];
00122 
00123             copy_v3_v3(co, v->co);
00124             mul_v3_m4v3(wco, ob->obmat, co);
00125 
00126             verts[3*(basenverts+i)+0]= wco[0];
00127             verts[3*(basenverts+i)+1]= wco[2];
00128             verts[3*(basenverts+i)+2]= wco[1];
00129         }
00130 
00131         /* create tris */
00132         curnfaces= dm->getNumFaces(dm);
00133         mface= dm->getFaceArray(dm);
00134 
00135         for(i= 0; i<curnfaces; i++) {
00136             MFace* mf= &mface[i];
00137 
00138             tri[0]= basenverts + mf->v1;
00139             tri[1]= basenverts + mf->v3;
00140             tri[2]= basenverts + mf->v2;
00141             tri += 3;
00142 
00143             if(mf->v4) {
00144                 tri[0]= basenverts + mf->v1;
00145                 tri[1]= basenverts + mf->v4;
00146                 tri[2]= basenverts + mf->v3;
00147                 tri += 3;
00148             }
00149         }
00150 
00151         basenverts+= curnverts;
00152     }
00153 
00154     /* release derived mesh */
00155     for(dmlink= dms; dmlink; dmlink= dmlink->next) {
00156         dm= (DerivedMesh*) dmlink->link;
00157         dm->release(dm);
00158     }
00159 
00160     BLI_linklist_free(dms, NULL);
00161 
00162     *nverts_r= nverts;
00163     *verts_r= verts;
00164     *ntris_r= ntris;
00165     *tris_r= tris;
00166 }
00167 
00168 static int buildNavMesh(const RecastData *recastParams, int nverts, float *verts, int ntris, int *tris,
00169                                  struct recast_polyMesh **pmesh, struct recast_polyMeshDetail **dmesh)
00170 {
00171     float bmin[3], bmax[3];
00172     struct recast_heightfield *solid;
00173     unsigned char *triflags;
00174     struct recast_compactHeightfield* chf;
00175     struct recast_contourSet *cset;
00176     int width, height, walkableHeight, walkableClimb, walkableRadius;
00177     int minRegionArea, mergeRegionArea, maxEdgeLen;
00178     float detailSampleDist, detailSampleMaxError;
00179 
00180     recast_calcBounds(verts, nverts, bmin, bmax);
00181 
00182     /* ** Step 1. Initialize build config ** */
00183     walkableHeight= (int)ceilf(recastParams->agentheight/ recastParams->cellheight);
00184     walkableClimb= (int)floorf(recastParams->agentmaxclimb / recastParams->cellheight);
00185     walkableRadius= (int)ceilf(recastParams->agentradius / recastParams->cellsize);
00186     minRegionArea= (int)(recastParams->regionminsize * recastParams->regionminsize);
00187     mergeRegionArea= (int)(recastParams->regionmergesize * recastParams->regionmergesize);
00188     maxEdgeLen= (int)(recastParams->edgemaxlen/recastParams->cellsize);
00189     detailSampleDist= recastParams->detailsampledist< 0.9f ? 0 :
00190             recastParams->cellsize * recastParams->detailsampledist;
00191     detailSampleMaxError= recastParams->cellheight * recastParams->detailsamplemaxerror;
00192 
00193     /* Set the area where the navigation will be build. */
00194     recast_calcGridSize(bmin, bmax, recastParams->cellsize, &width, &height);
00195 
00196     /* ** Step 2: Rasterize input polygon soup ** */
00197     /* Allocate voxel heightfield where we rasterize our input data to */
00198     solid= recast_newHeightfield();
00199 
00200     if(!recast_createHeightfield(solid, width, height, bmin, bmax, recastParams->cellsize, recastParams->cellheight)) {
00201         recast_destroyHeightfield(solid);
00202 
00203         return 0;
00204     }
00205 
00206     /* Allocate array that can hold triangle flags */
00207     triflags= MEM_callocN(sizeof(unsigned char)*ntris, "buildNavMesh triflags");
00208 
00209     /* Find triangles which are walkable based on their slope and rasterize them */
00210     recast_markWalkableTriangles(RAD2DEG(recastParams->agentmaxslope), verts, nverts, tris, ntris, triflags);
00211     recast_rasterizeTriangles(verts, nverts, tris, triflags, ntris, solid);
00212     MEM_freeN(triflags);
00213 
00214     /* ** Step 3: Filter walkables surfaces ** */
00215     recast_filterLowHangingWalkableObstacles(walkableClimb, solid);
00216     recast_filterLedgeSpans(walkableHeight, walkableClimb, solid);
00217     recast_filterWalkableLowHeightSpans(walkableHeight, solid);
00218 
00219     /* ** Step 4: Partition walkable surface to simple regions ** */
00220 
00221     chf= recast_newCompactHeightfield();
00222     if(!recast_buildCompactHeightfield(walkableHeight, walkableClimb, solid, chf)) {
00223         recast_destroyHeightfield(solid);
00224         recast_destroyCompactHeightfield(chf);
00225 
00226         return 0;
00227     }
00228 
00229     recast_destroyHeightfield(solid);
00230     solid = NULL;
00231 
00232     if (!recast_erodeWalkableArea(walkableRadius, chf)) {
00233         recast_destroyCompactHeightfield(chf);
00234 
00235         return 0;
00236     }
00237 
00238     /* Prepare for region partitioning, by calculating distance field along the walkable surface */
00239     if(!recast_buildDistanceField(chf)) {
00240         recast_destroyCompactHeightfield(chf);
00241 
00242         return 0;
00243     }
00244 
00245     /* Partition the walkable surface into simple regions without holes */
00246     if(!recast_buildRegions(chf, 0, minRegionArea, mergeRegionArea)) {
00247         recast_destroyCompactHeightfield(chf);
00248 
00249         return 0;
00250     }
00251 
00252     /* ** Step 5: Trace and simplify region contours ** */
00253     /* Create contours */
00254     cset= recast_newContourSet();
00255 
00256     if(!recast_buildContours(chf, recastParams->edgemaxerror, maxEdgeLen, cset)) {
00257         recast_destroyCompactHeightfield(chf);
00258         recast_destroyContourSet(cset);
00259 
00260         return 0;
00261     }
00262 
00263     /* ** Step 6: Build polygons mesh from contours ** */
00264     *pmesh= recast_newPolyMesh();
00265     if(!recast_buildPolyMesh(cset, recastParams->vertsperpoly, *pmesh)) {
00266         recast_destroyCompactHeightfield(chf);
00267         recast_destroyContourSet(cset);
00268         recast_destroyPolyMesh(*pmesh);
00269 
00270         return 0;
00271     }
00272 
00273 
00274     /* ** Step 7: Create detail mesh which allows to access approximate height on each polygon ** */
00275 
00276     *dmesh= recast_newPolyMeshDetail();
00277     if(!recast_buildPolyMeshDetail(*pmesh, chf, detailSampleDist, detailSampleMaxError, *dmesh)) {
00278         recast_destroyCompactHeightfield(chf);
00279         recast_destroyContourSet(cset);
00280         recast_destroyPolyMesh(*pmesh);
00281         recast_destroyPolyMeshDetail(*dmesh);
00282 
00283         return 0;
00284     }
00285 
00286     recast_destroyCompactHeightfield(chf);
00287     recast_destroyContourSet(cset);
00288 
00289     return 1;
00290 }
00291 
00292 static Object* createRepresentation(bContext *C, struct recast_polyMesh *pmesh, struct recast_polyMeshDetail *dmesh, Base* base)
00293 {
00294     float co[3], rot[3];
00295     EditMesh *em;
00296     int i,j, k;
00297     unsigned short* v;
00298     int face[3];
00299     Scene *scene= CTX_data_scene(C);
00300     Object* obedit;
00301     int createob= base==NULL;
00302     int nverts, nmeshes, nvp;
00303     unsigned short *verts, *polys;
00304     unsigned int *meshes;
00305     float bmin[3], cs, ch, *dverts;
00306     unsigned char *tris;
00307 
00308     zero_v3(co);
00309     zero_v3(rot);
00310 
00311     if(createob) {
00312         /* create new object */
00313         obedit= ED_object_add_type(C, OB_MESH, co, rot, FALSE, 1);
00314     }
00315     else {
00316         obedit= base->object;
00317         scene_select_base(scene, base);
00318         copy_v3_v3(obedit->loc, co);
00319         copy_v3_v3(obedit->rot, rot);
00320     }
00321 
00322     ED_object_enter_editmode(C, EM_DO_UNDO|EM_IGNORE_LAYER);
00323     em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
00324 
00325     if(!createob) {
00326         /* clear */
00327         if(em->verts.first) free_vertlist(em, &em->verts);
00328         if(em->edges.first) free_edgelist(em, &em->edges);
00329         if(em->faces.first) free_facelist(em, &em->faces);
00330         if(em->selected.first) BLI_freelistN(&(em->selected));
00331     }
00332 
00333     /* create verts for polygon mesh */
00334     verts= recast_polyMeshGetVerts(pmesh, &nverts);
00335     recast_polyMeshGetBoundbox(pmesh, bmin, NULL);
00336     recast_polyMeshGetCell(pmesh, &cs, &ch);
00337 
00338     for(i= 0; i<nverts; i++) {
00339         v= &verts[3*i];
00340         co[0]= bmin[0] + v[0]*cs;
00341         co[1]= bmin[1] + v[1]*ch;
00342         co[2]= bmin[2] + v[2]*cs;
00343         SWAP(float, co[1], co[2]);
00344         addvertlist(em, co, NULL);
00345     }
00346 
00347     /* create custom data layer to save polygon idx */
00348     CustomData_add_layer_named(&em->fdata, CD_RECAST, CD_CALLOC, NULL, 0, "createRepresentation recastData");
00349 
00350     /* create verts and faces for detailed mesh */
00351     meshes= recast_polyMeshDetailGetMeshes(dmesh, &nmeshes);
00352     polys= recast_polyMeshGetPolys(pmesh, NULL, &nvp);
00353     dverts= recast_polyMeshDetailGetVerts(dmesh, NULL);
00354     tris= recast_polyMeshDetailGetTris(dmesh, NULL);
00355 
00356     for(i= 0; i<nmeshes; i++) {
00357         int uniquevbase= em->totvert;
00358         unsigned int vbase= meshes[4*i+0];
00359         unsigned short ndv= meshes[4*i+1];
00360         unsigned short tribase= meshes[4*i+2];
00361         unsigned short trinum= meshes[4*i+3];
00362         const unsigned short* p= &polys[i*nvp*2];
00363         int nv= 0;
00364 
00365         for(j= 0; j < nvp; ++j) {
00366             if(p[j]==0xffff) break;
00367             nv++;
00368         }
00369 
00370         /* create unique verts  */
00371         for(j= nv; j<ndv; j++) {
00372             copy_v3_v3(co, &dverts[3*(vbase + j)]);
00373             SWAP(float, co[1], co[2]);
00374             addvertlist(em, co, NULL);
00375         }
00376 
00377         EM_init_index_arrays(em, 1, 0, 0);
00378 
00379         /* create faces */
00380         for(j= 0; j<trinum; j++) {
00381             unsigned char* tri= &tris[4*(tribase+j)];
00382             EditFace* newFace;
00383             int* polygonIdx;
00384 
00385             for(k= 0; k<3; k++) {
00386                 if(tri[k]<nv)
00387                     face[k]= p[tri[k]]; /* shared vertex */
00388                 else
00389                     face[k]= uniquevbase+tri[k]-nv; /* unique vertex */
00390             }
00391             newFace= addfacelist(em, EM_get_vert_for_index(face[0]), EM_get_vert_for_index(face[2]),
00392                                     EM_get_vert_for_index(face[1]), NULL, NULL, NULL);
00393 
00394             /* set navigation polygon idx to the custom layer */
00395             polygonIdx= (int*)CustomData_em_get(&em->fdata, newFace->data, CD_RECAST);
00396             *polygonIdx= i+1; /* add 1 to avoid zero idx */
00397         }
00398         
00399         EM_free_index_arrays();
00400     }
00401 
00402     recast_destroyPolyMesh(pmesh);
00403     recast_destroyPolyMeshDetail(dmesh);
00404 
00405     BKE_mesh_end_editmesh((Mesh*)obedit->data, em);
00406     
00407     DAG_id_tag_update((ID*)obedit->data, OB_RECALC_DATA);
00408     WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
00409 
00410 
00411     ED_object_exit_editmode(C, EM_FREEDATA); 
00412     WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, obedit);
00413 
00414     if(createob) {
00415         obedit->gameflag&= ~OB_COLLISION;
00416         obedit->gameflag|= OB_NAVMESH;
00417         obedit->body_type= OB_BODY_TYPE_NAVMESH;
00418         rename_id((ID *)obedit, "Navmesh");
00419     }
00420 
00421     BKE_mesh_ensure_navmesh(obedit->data);
00422 
00423     return obedit;
00424 }
00425 
00426 static int create_navmesh_exec(bContext *C, wmOperator *op)
00427 {
00428     Scene* scene= CTX_data_scene(C);
00429     LinkNode* obs= NULL;
00430     Base* navmeshBase= NULL;
00431 
00432     CTX_DATA_BEGIN(C, Base*, base, selected_editable_bases) {
00433         if (base->object->type == OB_MESH) {
00434             if (base->object->body_type==OB_BODY_TYPE_NAVMESH) {
00435                 if (!navmeshBase || base == scene->basact) {
00436                     navmeshBase= base;
00437                 }
00438             }
00439             else {
00440                 BLI_linklist_append(&obs, (void*)base->object);
00441             }
00442         }
00443     }
00444     CTX_DATA_END;
00445 
00446     if (obs) {
00447         struct recast_polyMesh *pmesh= NULL;
00448         struct recast_polyMeshDetail *dmesh= NULL;
00449 
00450         int nverts= 0, ntris= 0;
00451         int *tris= 0;
00452         float *verts= NULL;
00453 
00454         createVertsTrisData(C, obs, &nverts, &verts, &ntris, &tris);
00455         BLI_linklist_free(obs, NULL);
00456         buildNavMesh(&scene->gm.recastData, nverts, verts, ntris, tris, &pmesh, &dmesh);
00457         createRepresentation(C, pmesh, dmesh, navmeshBase);
00458 
00459         MEM_freeN(verts);
00460         MEM_freeN(tris);
00461 
00462         return OPERATOR_FINISHED;
00463     }
00464     else {
00465         BKE_report(op->reports, RPT_ERROR, "No mesh objects found");
00466 
00467         return OPERATOR_CANCELLED;
00468     }
00469 }
00470 
00471 void MESH_OT_navmesh_make(wmOperatorType *ot)
00472 {
00473     /* identifiers */
00474     ot->name= "Create navigation mesh";
00475     ot->description= "Create navigation mesh for selected objects";
00476     ot->idname= "MESH_OT_navmesh_make";
00477 
00478     /* api callbacks */
00479     ot->exec= create_navmesh_exec;
00480 
00481     /* flags */
00482     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00483 }
00484 
00485 static int navmesh_face_copy_exec(bContext *C, wmOperator *op)
00486 {
00487     Object *obedit= CTX_data_edit_object(C);
00488     EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
00489 
00490     /* do work here */
00491     EditFace *efa_act= EM_get_actFace(em, 0);
00492 
00493     if(efa_act) {
00494         if(CustomData_has_layer(&em->fdata, CD_RECAST)) {
00495             EditFace *efa;
00496             int targetPolyIdx= *(int*)CustomData_em_get(&em->fdata, efa_act->data, CD_RECAST);
00497             targetPolyIdx= targetPolyIdx>=0? targetPolyIdx : -targetPolyIdx;
00498 
00499             if(targetPolyIdx > 0) {
00500                 /* set target poly idx to other selected faces */
00501                 for (efa= (EditFace *)em->faces.first; efa; efa= efa->next) {
00502                     if((efa->f & SELECT) && efa != efa_act)  {
00503                         int* recastDataBlock= (int*)CustomData_em_get(&em->fdata, efa->data, CD_RECAST);
00504                         *recastDataBlock= targetPolyIdx;
00505                     }
00506                 }
00507             }
00508             else {
00509                 BKE_report(op->reports, RPT_ERROR, "Active face has no index set");
00510             }
00511         }
00512     }
00513 
00514     DAG_id_tag_update((ID*)obedit->data, OB_RECALC_DATA);
00515     WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
00516 
00517     BKE_mesh_end_editmesh((Mesh*)obedit->data, em);
00518 
00519     return OPERATOR_FINISHED;
00520 }
00521 
00522 void MESH_OT_navmesh_face_copy(struct wmOperatorType *ot)
00523 {
00524     /* identifiers */
00525     ot->name= "NavMesh Copy Face Index";
00526     ot->description= "Copy the index from the active face";
00527     ot->idname= "MESH_OT_navmesh_face_copy";
00528 
00529     /* api callbacks */
00530     ot->poll= ED_operator_editmesh;
00531     ot->exec= navmesh_face_copy_exec;
00532 
00533     /* flags */
00534     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00535 }
00536 
00537 static int compare(const void * a, const void * b)
00538 {
00539     return ( *(int*)a - *(int*)b );
00540 }
00541 
00542 static int findFreeNavPolyIndex(EditMesh* em)
00543 {
00544     /* construct vector of indices */
00545     int numfaces= em->totface;
00546     int* indices= MEM_callocN(sizeof(int)*numfaces, "findFreeNavPolyIndex(indices)");
00547     EditFace* ef= (EditFace*)em->faces.last;
00548     int i, idx= 0, freeIdx= 1;
00549 
00550     while(ef) {
00551         int polyIdx= *(int*)CustomData_em_get(&em->fdata, ef->data, CD_RECAST);
00552         indices[idx]= polyIdx;
00553         idx++;
00554         ef= ef->prev;
00555     }
00556 
00557     qsort(indices, numfaces, sizeof(int), compare);
00558 
00559     /* search first free index */
00560     freeIdx= 1;
00561     for(i= 0; i<numfaces; i++) {
00562         if(indices[i]==freeIdx)
00563             freeIdx++;
00564         else if(indices[i]>freeIdx)
00565             break;
00566     }
00567 
00568     MEM_freeN(indices);
00569 
00570     return freeIdx;
00571 }
00572 
00573 static int navmesh_face_add_exec(bContext *C, wmOperator *UNUSED(op))
00574 {
00575     Object *obedit= CTX_data_edit_object(C);
00576     EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
00577     EditFace *ef;
00578 
00579     if(CustomData_has_layer(&em->fdata, CD_RECAST)) {
00580         int targetPolyIdx= findFreeNavPolyIndex(em);
00581 
00582         if(targetPolyIdx>0) {
00583             /* set target poly idx to selected faces */
00584             ef= (EditFace*)em->faces.last;
00585             while(ef) {
00586                 if(ef->f & SELECT) {
00587                     int *recastDataBlock= (int*)CustomData_em_get(&em->fdata, ef->data, CD_RECAST);
00588                     *recastDataBlock= targetPolyIdx;
00589                 }
00590                 ef= ef->prev;
00591             }
00592         }
00593     }
00594 
00595     DAG_id_tag_update((ID*)obedit->data, OB_RECALC_DATA);
00596     WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
00597 
00598     BKE_mesh_end_editmesh((Mesh*)obedit->data, em);
00599     return OPERATOR_FINISHED;
00600 }
00601 
00602 void MESH_OT_navmesh_face_add(struct wmOperatorType *ot)
00603 {
00604     /* identifiers */
00605     ot->name= "NavMesh New Face Index";
00606     ot->description= "Add a new index and assign it to selected faces";
00607     ot->idname= "MESH_OT_navmesh_face_add";
00608 
00609     /* api callbacks */
00610     ot->poll= ED_operator_editmesh;
00611     ot->exec= navmesh_face_add_exec;
00612 
00613     /* flags */
00614     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00615 }
00616 
00617 static int navmesh_obmode_data_poll(bContext *C)
00618 {
00619     Object *ob = ED_object_active_context(C);
00620     if (ob && (ob->mode == OB_MODE_OBJECT) && (ob->type == OB_MESH)) {
00621         Mesh *me= ob->data;
00622         return CustomData_has_layer(&me->fdata, CD_RECAST);
00623     }
00624     return FALSE;
00625 }
00626 
00627 static int navmesh_obmode_poll(bContext *C)
00628 {
00629     Object *ob = ED_object_active_context(C);
00630     if (ob && (ob->mode == OB_MODE_OBJECT) && (ob->type == OB_MESH)) {
00631         return TRUE;
00632     }
00633     return FALSE;
00634 }
00635 
00636 static int navmesh_reset_exec(bContext *C, wmOperator *UNUSED(op))
00637 {
00638     Object *ob = ED_object_active_context(C);
00639     Mesh *me= ob->data;
00640 
00641     CustomData_free_layers(&me->fdata, CD_RECAST, me->totface);
00642 
00643     BKE_mesh_ensure_navmesh(me);
00644 
00645     DAG_id_tag_update(&me->id, OB_RECALC_DATA);
00646     WM_event_add_notifier(C, NC_GEOM|ND_DATA, &me->id);
00647 
00648     return OPERATOR_FINISHED;
00649 }
00650 
00651 void MESH_OT_navmesh_reset(struct wmOperatorType *ot)
00652 {
00653     /* identifiers */
00654     ot->name= "NavMesh Reset Index Values";
00655     ot->description= "Assign a new index to every face";
00656     ot->idname= "MESH_OT_navmesh_reset";
00657 
00658     /* api callbacks */
00659     ot->poll= navmesh_obmode_poll;
00660     ot->exec= navmesh_reset_exec;
00661 
00662     /* flags */
00663     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00664 }
00665 
00666 static int navmesh_clear_exec(bContext *C, wmOperator *UNUSED(op))
00667 {
00668     Object *ob = ED_object_active_context(C);
00669     Mesh *me= ob->data;
00670 
00671     CustomData_free_layers(&me->fdata, CD_RECAST, me->totface);
00672 
00673     DAG_id_tag_update(&me->id, OB_RECALC_DATA);
00674     WM_event_add_notifier(C, NC_GEOM|ND_DATA, &me->id);
00675 
00676     return OPERATOR_FINISHED;
00677 }
00678 
00679 void MESH_OT_navmesh_clear(struct wmOperatorType *ot)
00680 {
00681     /* identifiers */
00682     ot->name= "NavMesh Clear Data";
00683     ot->description= "Remove navmesh data from this mesh";
00684     ot->idname= "MESH_OT_navmesh_clear";
00685 
00686     /* api callbacks */
00687     ot->poll= navmesh_obmode_data_poll;
00688     ot->exec= navmesh_clear_exec;
00689 
00690     /* flags */
00691     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00692 }