Camera tracking: improvements of track preview widget
[blender.git] / source / blender / editors / mesh / mesh_navmesh.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2011 by Blender Foundation
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): Benoit Bolsee,
24  *                 Nick Samarin
25  *
26  * ***** END GPL LICENSE BLOCK *****
27  */
28
29 #include <math.h>
30
31 #include "MEM_guardedalloc.h"
32
33 #include "DNA_scene_types.h"
34 #include "DNA_object_types.h"
35 #include "DNA_meshdata_types.h"
36 #include "DNA_modifier_types.h"
37 #include "DNA_ID.h"
38
39 #include "BKE_library.h"
40 #include "BKE_depsgraph.h"
41 #include "BKE_context.h"
42 #include "BKE_main.h"
43 #include "BKE_mesh.h"
44 #include "BKE_modifier.h"
45 #include "BKE_scene.h"
46 #include "BKE_DerivedMesh.h"
47 #include "BKE_cdderivedmesh.h"
48 #include "BKE_report.h"
49
50 #include "BLI_editVert.h"
51 #include "BLI_listbase.h"
52 #include "BLI_utildefines.h"
53 #include "BLI_math_vector.h"
54 #include "BLI_linklist.h"
55
56 #include "ED_object.h"
57 #include "ED_mesh.h"
58 #include "ED_screen.h"
59
60 #include "RNA_access.h"
61
62 #include "WM_api.h"
63 #include "WM_types.h"
64
65 #include "mesh_intern.h"
66 #include "recast-capi.h"
67
68 static void createVertsTrisData(bContext *C, LinkNode* obs, int *nverts_r, float **verts_r, int *ntris_r, int **tris_r)
69 {
70         MVert *mvert;
71         int nfaces= 0, *tri, i, curnverts, basenverts, curnfaces;
72         MFace *mface;
73         float co[3], wco[3];
74         Object *ob;
75         LinkNode *oblink, *dmlink;
76         DerivedMesh *dm;
77         Scene* scene= CTX_data_scene(C);
78         LinkNode* dms= NULL;
79
80         int nverts, ntris, *tris;
81         float *verts;
82
83         nverts= 0;
84         ntris= 0;
85
86         /* calculate number of verts and tris */
87         for(oblink= obs; oblink; oblink= oblink->next) {
88                 ob= (Object*) oblink->link;
89                 dm= mesh_create_derived_no_virtual(scene, ob, NULL, CD_MASK_MESH);
90                 BLI_linklist_append(&dms, (void*)dm);
91
92                 nverts+= dm->getNumVerts(dm);
93                 nfaces= dm->getNumFaces(dm);
94                 ntris+= nfaces;
95
96                 /* resolve quad faces */
97                 mface= dm->getFaceArray(dm);
98                 for(i= 0; i<nfaces; i++) {
99                         MFace* mf= &mface[i];
100                         if(mf->v4)
101                                 ntris+=1;
102                 }
103         }
104
105         /* create data */
106         verts= MEM_mallocN(sizeof(float)*3*nverts, "createVertsTrisData verts");
107         tris= MEM_mallocN(sizeof(int)*3*ntris, "createVertsTrisData faces");
108
109         basenverts= 0;
110         tri= tris;
111         for(oblink= obs, dmlink= dms; oblink && dmlink;
112                         oblink= oblink->next, dmlink= dmlink->next) {
113                 ob= (Object*) oblink->link;
114                 dm= (DerivedMesh*) dmlink->link;
115
116                 curnverts= dm->getNumVerts(dm);
117                 mvert= dm->getVertArray(dm);
118
119                 /* copy verts */
120                 for(i= 0; i<curnverts; i++) {
121                         MVert *v= &mvert[i];
122
123                         copy_v3_v3(co, v->co);
124                         mul_v3_m4v3(wco, ob->obmat, co);
125
126                         verts[3*(basenverts+i)+0]= wco[0];
127                         verts[3*(basenverts+i)+1]= wco[2];
128                         verts[3*(basenverts+i)+2]= wco[1];
129                 }
130
131                 /* create tris */
132                 curnfaces= dm->getNumFaces(dm);
133                 mface= dm->getFaceArray(dm);
134
135                 for(i= 0; i<curnfaces; i++) {
136                         MFace* mf= &mface[i];
137
138                         tri[0]= basenverts + mf->v1;
139                         tri[1]= basenverts + mf->v3;
140                         tri[2]= basenverts + mf->v2;
141                         tri += 3;
142
143                         if(mf->v4) {
144                                 tri[0]= basenverts + mf->v1;
145                                 tri[1]= basenverts + mf->v4;
146                                 tri[2]= basenverts + mf->v3;
147                                 tri += 3;
148                         }
149                 }
150
151                 basenverts+= curnverts;
152         }
153
154         /* release derived mesh */
155         for(dmlink= dms; dmlink; dmlink= dmlink->next) {
156                 dm= (DerivedMesh*) dmlink->link;
157                 dm->release(dm);
158         }
159
160         BLI_linklist_free(dms, NULL);
161
162         *nverts_r= nverts;
163         *verts_r= verts;
164         *ntris_r= ntris;
165         *tris_r= tris;
166 }
167
168 static int buildNavMesh(const RecastData *recastParams, int nverts, float *verts, int ntris, int *tris,
169                                                                  struct recast_polyMesh **pmesh, struct recast_polyMeshDetail **dmesh)
170 {
171         float bmin[3], bmax[3];
172         struct recast_heightfield *solid;
173         unsigned char *triflags;
174         struct recast_compactHeightfield* chf;
175         struct recast_contourSet *cset;
176         int width, height, walkableHeight, walkableClimb, walkableRadius;
177         int minRegionArea, mergeRegionArea, maxEdgeLen;
178         float detailSampleDist, detailSampleMaxError;
179
180         recast_calcBounds(verts, nverts, bmin, bmax);
181
182         /* ** Step 1. Initialize build config ** */
183         walkableHeight= (int)ceilf(recastParams->agentheight/ recastParams->cellheight);
184         walkableClimb= (int)floorf(recastParams->agentmaxclimb / recastParams->cellheight);
185         walkableRadius= (int)ceilf(recastParams->agentradius / recastParams->cellsize);
186         minRegionArea= (int)(recastParams->regionminsize * recastParams->regionminsize);
187         mergeRegionArea= (int)(recastParams->regionmergesize * recastParams->regionmergesize);
188         maxEdgeLen= (int)(recastParams->edgemaxlen/recastParams->cellsize);
189         detailSampleDist= recastParams->detailsampledist< 0.9f ? 0 :
190                         recastParams->cellsize * recastParams->detailsampledist;
191         detailSampleMaxError= recastParams->cellheight * recastParams->detailsamplemaxerror;
192
193         /* Set the area where the navigation will be build. */
194         recast_calcGridSize(bmin, bmax, recastParams->cellsize, &width, &height);
195
196         /* ** Step 2: Rasterize input polygon soup ** */
197         /* Allocate voxel heightfield where we rasterize our input data to */
198         solid= recast_newHeightfield();
199
200         if(!recast_createHeightfield(solid, width, height, bmin, bmax, recastParams->cellsize, recastParams->cellheight)) {
201                 recast_destroyHeightfield(solid);
202
203                 return 0;
204         }
205
206         /* Allocate array that can hold triangle flags */
207         triflags= MEM_callocN(sizeof(unsigned char)*ntris, "buildNavMesh triflags");
208
209         /* Find triangles which are walkable based on their slope and rasterize them */
210         recast_markWalkableTriangles(RAD2DEG(recastParams->agentmaxslope), verts, nverts, tris, ntris, triflags);
211         recast_rasterizeTriangles(verts, nverts, tris, triflags, ntris, solid);
212         MEM_freeN(triflags);
213
214         /* ** Step 3: Filter walkables surfaces ** */
215         recast_filterLowHangingWalkableObstacles(walkableClimb, solid);
216         recast_filterLedgeSpans(walkableHeight, walkableClimb, solid);
217         recast_filterWalkableLowHeightSpans(walkableHeight, solid);
218
219         /* ** Step 4: Partition walkable surface to simple regions ** */
220
221         chf= recast_newCompactHeightfield();
222         if(!recast_buildCompactHeightfield(walkableHeight, walkableClimb, solid, chf)) {
223                 recast_destroyHeightfield(solid);
224                 recast_destroyCompactHeightfield(chf);
225
226                 return 0;
227         }
228
229         recast_destroyHeightfield(solid);
230         solid = NULL;
231
232         if (!recast_erodeWalkableArea(walkableRadius, chf)) {
233                 recast_destroyCompactHeightfield(chf);
234
235                 return 0;
236         }
237
238         /* Prepare for region partitioning, by calculating distance field along the walkable surface */
239         if(!recast_buildDistanceField(chf)) {
240                 recast_destroyCompactHeightfield(chf);
241
242                 return 0;
243         }
244
245         /* Partition the walkable surface into simple regions without holes */
246         if(!recast_buildRegions(chf, 0, minRegionArea, mergeRegionArea)) {
247                 recast_destroyCompactHeightfield(chf);
248
249                 return 0;
250         }
251
252         /* ** Step 5: Trace and simplify region contours ** */
253         /* Create contours */
254         cset= recast_newContourSet();
255
256         if(!recast_buildContours(chf, recastParams->edgemaxerror, maxEdgeLen, cset)) {
257                 recast_destroyCompactHeightfield(chf);
258                 recast_destroyContourSet(cset);
259
260                 return 0;
261         }
262
263         /* ** Step 6: Build polygons mesh from contours ** */
264         *pmesh= recast_newPolyMesh();
265         if(!recast_buildPolyMesh(cset, recastParams->vertsperpoly, *pmesh)) {
266                 recast_destroyCompactHeightfield(chf);
267                 recast_destroyContourSet(cset);
268                 recast_destroyPolyMesh(*pmesh);
269
270                 return 0;
271         }
272
273
274         /* ** Step 7: Create detail mesh which allows to access approximate height on each polygon ** */
275
276         *dmesh= recast_newPolyMeshDetail();
277         if(!recast_buildPolyMeshDetail(*pmesh, chf, detailSampleDist, detailSampleMaxError, *dmesh)) {
278                 recast_destroyCompactHeightfield(chf);
279                 recast_destroyContourSet(cset);
280                 recast_destroyPolyMesh(*pmesh);
281                 recast_destroyPolyMeshDetail(*dmesh);
282
283                 return 0;
284         }
285
286         recast_destroyCompactHeightfield(chf);
287         recast_destroyContourSet(cset);
288
289         return 1;
290 }
291
292 static Object* createRepresentation(bContext *C, struct recast_polyMesh *pmesh, struct recast_polyMeshDetail *dmesh, Base* base)
293 {
294         float co[3], rot[3];
295         EditMesh *em;
296         int i,j, k;
297         unsigned short* v;
298         int face[3];
299         Scene *scene= CTX_data_scene(C);
300         Object* obedit;
301         int createob= base==NULL;
302         int nverts, nmeshes, nvp;
303         unsigned short *verts, *polys;
304         unsigned int *meshes;
305         float bmin[3], cs, ch, *dverts;
306         unsigned char *tris;
307
308         zero_v3(co);
309         zero_v3(rot);
310
311         if(createob) {
312                 /* create new object */
313                 obedit= ED_object_add_type(C, OB_MESH, co, rot, FALSE, 1);
314         }
315         else {
316                 obedit= base->object;
317                 scene_select_base(scene, base);
318                 copy_v3_v3(obedit->loc, co);
319                 copy_v3_v3(obedit->rot, rot);
320         }
321
322         ED_object_enter_editmode(C, EM_DO_UNDO|EM_IGNORE_LAYER);
323         em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
324
325         if(!createob) {
326                 /* clear */
327                 if(em->verts.first) free_vertlist(em, &em->verts);
328                 if(em->edges.first) free_edgelist(em, &em->edges);
329                 if(em->faces.first) free_facelist(em, &em->faces);
330                 if(em->selected.first) BLI_freelistN(&(em->selected));
331         }
332
333         /* create verts for polygon mesh */
334         verts= recast_polyMeshGetVerts(pmesh, &nverts);
335         recast_polyMeshGetBoundbox(pmesh, bmin, NULL);
336         recast_polyMeshGetCell(pmesh, &cs, &ch);
337
338         for(i= 0; i<nverts; i++) {
339                 v= &verts[3*i];
340                 co[0]= bmin[0] + v[0]*cs;
341                 co[1]= bmin[1] + v[1]*ch;
342                 co[2]= bmin[2] + v[2]*cs;
343                 SWAP(float, co[1], co[2]);
344                 addvertlist(em, co, NULL);
345         }
346
347         /* create custom data layer to save polygon idx */
348         CustomData_add_layer_named(&em->fdata, CD_RECAST, CD_CALLOC, NULL, 0, "createRepresentation recastData");
349
350         /* create verts and faces for detailed mesh */
351         meshes= recast_polyMeshDetailGetMeshes(dmesh, &nmeshes);
352         polys= recast_polyMeshGetPolys(pmesh, NULL, &nvp);
353         dverts= recast_polyMeshDetailGetVerts(dmesh, NULL);
354         tris= recast_polyMeshDetailGetTris(dmesh, NULL);
355
356         for(i= 0; i<nmeshes; i++) {
357                 int uniquevbase= em->totvert;
358                 unsigned int vbase= meshes[4*i+0];
359                 unsigned short ndv= meshes[4*i+1];
360                 unsigned short tribase= meshes[4*i+2];
361                 unsigned short trinum= meshes[4*i+3];
362                 const unsigned short* p= &polys[i*nvp*2];
363                 int nv= 0;
364
365                 for(j= 0; j < nvp; ++j) {
366                         if(p[j]==0xffff) break;
367                         nv++;
368                 }
369
370                 /* create unique verts  */
371                 for(j= nv; j<ndv; j++) {
372                         copy_v3_v3(co, &dverts[3*(vbase + j)]);
373                         SWAP(float, co[1], co[2]);
374                         addvertlist(em, co, NULL);
375                 }
376
377                 EM_init_index_arrays(em, 1, 0, 0);
378
379                 /* create faces */
380                 for(j= 0; j<trinum; j++) {
381                         unsigned char* tri= &tris[4*(tribase+j)];
382                         EditFace* newFace;
383                         int* polygonIdx;
384
385                         for(k= 0; k<3; k++) {
386                                 if(tri[k]<nv)
387                                         face[k]= p[tri[k]]; /* shared vertex */
388                                 else
389                                         face[k]= uniquevbase+tri[k]-nv; /* unique vertex */
390                         }
391                         newFace= addfacelist(em, EM_get_vert_for_index(face[0]), EM_get_vert_for_index(face[2]),
392                                                                         EM_get_vert_for_index(face[1]), NULL, NULL, NULL);
393
394                         /* set navigation polygon idx to the custom layer */
395                         polygonIdx= (int*)CustomData_em_get(&em->fdata, newFace->data, CD_RECAST);
396                         *polygonIdx= i+1; /* add 1 to avoid zero idx */
397                 }
398                 
399                 EM_free_index_arrays();
400         }
401
402         recast_destroyPolyMesh(pmesh);
403         recast_destroyPolyMeshDetail(dmesh);
404
405         BKE_mesh_end_editmesh((Mesh*)obedit->data, em);
406         
407         DAG_id_tag_update((ID*)obedit->data, OB_RECALC_DATA);
408         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
409
410
411         ED_object_exit_editmode(C, EM_FREEDATA); 
412         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, obedit);
413
414         if(createob) {
415                 obedit->gameflag&= ~OB_COLLISION;
416                 obedit->gameflag|= OB_NAVMESH;
417                 obedit->body_type= OB_BODY_TYPE_NAVMESH;
418                 rename_id((ID *)obedit, "Navmesh");
419         }
420
421         BKE_mesh_ensure_navmesh(obedit->data);
422
423         return obedit;
424 }
425
426 static int create_navmesh_exec(bContext *C, wmOperator *op)
427 {
428         Scene* scene= CTX_data_scene(C);
429         LinkNode* obs= NULL;
430         Base* navmeshBase= NULL;
431
432         CTX_DATA_BEGIN(C, Base*, base, selected_editable_bases) {
433                 if (base->object->type == OB_MESH) {
434                         if (base->object->body_type==OB_BODY_TYPE_NAVMESH) {
435                                 if (!navmeshBase || base == scene->basact) {
436                                         navmeshBase= base;
437                                 }
438                         }
439                         else {
440                                 BLI_linklist_append(&obs, (void*)base->object);
441                         }
442                 }
443         }
444         CTX_DATA_END;
445
446         if (obs) {
447                 struct recast_polyMesh *pmesh= NULL;
448                 struct recast_polyMeshDetail *dmesh= NULL;
449
450                 int nverts= 0, ntris= 0;
451                 int *tris= 0;
452                 float *verts= NULL;
453
454                 createVertsTrisData(C, obs, &nverts, &verts, &ntris, &tris);
455                 BLI_linklist_free(obs, NULL);
456                 buildNavMesh(&scene->gm.recastData, nverts, verts, ntris, tris, &pmesh, &dmesh);
457                 createRepresentation(C, pmesh, dmesh, navmeshBase);
458
459                 MEM_freeN(verts);
460                 MEM_freeN(tris);
461
462                 return OPERATOR_FINISHED;
463         }
464         else {
465                 BKE_report(op->reports, RPT_ERROR, "No mesh objects found");
466
467                 return OPERATOR_CANCELLED;
468         }
469 }
470
471 void MESH_OT_navmesh_make(wmOperatorType *ot)
472 {
473         /* identifiers */
474         ot->name= "Create navigation mesh";
475         ot->description= "Create navigation mesh for selected objects";
476         ot->idname= "MESH_OT_navmesh_make";
477
478         /* api callbacks */
479         ot->exec= create_navmesh_exec;
480
481         /* flags */
482         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
483 }
484
485 static int navmesh_face_copy_exec(bContext *C, wmOperator *op)
486 {
487         Object *obedit= CTX_data_edit_object(C);
488         EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
489
490         /* do work here */
491         EditFace *efa_act= EM_get_actFace(em, 0);
492
493         if(efa_act) {
494                 if(CustomData_has_layer(&em->fdata, CD_RECAST)) {
495                         EditFace *efa;
496                         int targetPolyIdx= *(int*)CustomData_em_get(&em->fdata, efa_act->data, CD_RECAST);
497                         targetPolyIdx= targetPolyIdx>=0? targetPolyIdx : -targetPolyIdx;
498
499                         if(targetPolyIdx > 0) {
500                                 /* set target poly idx to other selected faces */
501                                 for (efa= (EditFace *)em->faces.first; efa; efa= efa->next) {
502                                         if((efa->f & SELECT) && efa != efa_act)  {
503                                                 int* recastDataBlock= (int*)CustomData_em_get(&em->fdata, efa->data, CD_RECAST);
504                                                 *recastDataBlock= targetPolyIdx;
505                                         }
506                                 }
507                         }
508                         else {
509                                 BKE_report(op->reports, RPT_ERROR, "Active face has no index set");
510                         }
511                 }
512         }
513
514         DAG_id_tag_update((ID*)obedit->data, OB_RECALC_DATA);
515         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
516
517         BKE_mesh_end_editmesh((Mesh*)obedit->data, em);
518
519         return OPERATOR_FINISHED;
520 }
521
522 void MESH_OT_navmesh_face_copy(struct wmOperatorType *ot)
523 {
524         /* identifiers */
525         ot->name= "NavMesh Copy Face Index";
526         ot->description= "Copy the index from the active face";
527         ot->idname= "MESH_OT_navmesh_face_copy";
528
529         /* api callbacks */
530         ot->poll= ED_operator_editmesh;
531         ot->exec= navmesh_face_copy_exec;
532
533         /* flags */
534         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
535 }
536
537 static int compare(const void * a, const void * b)
538 {
539         return ( *(int*)a - *(int*)b );
540 }
541
542 static int findFreeNavPolyIndex(EditMesh* em)
543 {
544         /* construct vector of indices */
545         int numfaces= em->totface;
546         int* indices= MEM_callocN(sizeof(int)*numfaces, "findFreeNavPolyIndex(indices)");
547         EditFace* ef= (EditFace*)em->faces.last;
548         int i, idx= 0, freeIdx= 1;
549
550         while(ef) {
551                 int polyIdx= *(int*)CustomData_em_get(&em->fdata, ef->data, CD_RECAST);
552                 indices[idx]= polyIdx;
553                 idx++;
554                 ef= ef->prev;
555         }
556
557         qsort(indices, numfaces, sizeof(int), compare);
558
559         /* search first free index */
560         freeIdx= 1;
561         for(i= 0; i<numfaces; i++) {
562                 if(indices[i]==freeIdx)
563                         freeIdx++;
564                 else if(indices[i]>freeIdx)
565                         break;
566         }
567
568         MEM_freeN(indices);
569
570         return freeIdx;
571 }
572
573 static int navmesh_face_add_exec(bContext *C, wmOperator *UNUSED(op))
574 {
575         Object *obedit= CTX_data_edit_object(C);
576         EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
577         EditFace *ef;
578
579         if(CustomData_has_layer(&em->fdata, CD_RECAST)) {
580                 int targetPolyIdx= findFreeNavPolyIndex(em);
581
582                 if(targetPolyIdx>0) {
583                         /* set target poly idx to selected faces */
584                         ef= (EditFace*)em->faces.last;
585                         while(ef) {
586                                 if(ef->f & SELECT) {
587                                         int *recastDataBlock= (int*)CustomData_em_get(&em->fdata, ef->data, CD_RECAST);
588                                         *recastDataBlock= targetPolyIdx;
589                                 }
590                                 ef= ef->prev;
591                         }
592                 }
593         }
594
595         DAG_id_tag_update((ID*)obedit->data, OB_RECALC_DATA);
596         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
597
598         BKE_mesh_end_editmesh((Mesh*)obedit->data, em);
599         return OPERATOR_FINISHED;
600 }
601
602 void MESH_OT_navmesh_face_add(struct wmOperatorType *ot)
603 {
604         /* identifiers */
605         ot->name= "NavMesh New Face Index";
606         ot->description= "Add a new index and assign it to selected faces";
607         ot->idname= "MESH_OT_navmesh_face_add";
608
609         /* api callbacks */
610         ot->poll= ED_operator_editmesh;
611         ot->exec= navmesh_face_add_exec;
612
613         /* flags */
614         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
615 }
616
617 static int navmesh_obmode_data_poll(bContext *C)
618 {
619         Object *ob = ED_object_active_context(C);
620         if (ob && (ob->mode == OB_MODE_OBJECT) && (ob->type == OB_MESH)) {
621                 Mesh *me= ob->data;
622                 return CustomData_has_layer(&me->fdata, CD_RECAST);
623         }
624         return FALSE;
625 }
626
627 static int navmesh_obmode_poll(bContext *C)
628 {
629         Object *ob = ED_object_active_context(C);
630         if (ob && (ob->mode == OB_MODE_OBJECT) && (ob->type == OB_MESH)) {
631                 return TRUE;
632         }
633         return FALSE;
634 }
635
636 static int navmesh_reset_exec(bContext *C, wmOperator *UNUSED(op))
637 {
638         Object *ob = ED_object_active_context(C);
639         Mesh *me= ob->data;
640
641         CustomData_free_layers(&me->fdata, CD_RECAST, me->totface);
642
643         BKE_mesh_ensure_navmesh(me);
644
645         DAG_id_tag_update(&me->id, OB_RECALC_DATA);
646         WM_event_add_notifier(C, NC_GEOM|ND_DATA, &me->id);
647
648         return OPERATOR_FINISHED;
649 }
650
651 void MESH_OT_navmesh_reset(struct wmOperatorType *ot)
652 {
653         /* identifiers */
654         ot->name= "NavMesh Reset Index Values";
655         ot->description= "Assign a new index to every face";
656         ot->idname= "MESH_OT_navmesh_reset";
657
658         /* api callbacks */
659         ot->poll= navmesh_obmode_poll;
660         ot->exec= navmesh_reset_exec;
661
662         /* flags */
663         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
664 }
665
666 static int navmesh_clear_exec(bContext *C, wmOperator *UNUSED(op))
667 {
668         Object *ob = ED_object_active_context(C);
669         Mesh *me= ob->data;
670
671         CustomData_free_layers(&me->fdata, CD_RECAST, me->totface);
672
673         DAG_id_tag_update(&me->id, OB_RECALC_DATA);
674         WM_event_add_notifier(C, NC_GEOM|ND_DATA, &me->id);
675
676         return OPERATOR_FINISHED;
677 }
678
679 void MESH_OT_navmesh_clear(struct wmOperatorType *ot)
680 {
681         /* identifiers */
682         ot->name= "NavMesh Clear Data";
683         ot->description= "Remove navmesh data from this mesh";
684         ot->idname= "MESH_OT_navmesh_clear";
685
686         /* api callbacks */
687         ot->poll= navmesh_obmode_data_poll;
688         ot->exec= navmesh_clear_exec;
689
690         /* flags */
691         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
692 }