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