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