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