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