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