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