2 * ***** BEGIN GPL LICENSE BLOCK *****
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.
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.
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.
18 * The Original Code is Copyright (C) 2011 by Blender Foundation
19 * All rights reserved.
21 * The Original Code is: all of this file.
23 * Contributor(s): Benoit Bolsee,
26 * ***** END GPL LICENSE BLOCK *****
31 #include "MEM_guardedalloc.h"
33 #include "DNA_scene_types.h"
34 #include "DNA_object_types.h"
35 #include "DNA_meshdata_types.h"
36 #include "DNA_modifier_types.h"
39 #include "BKE_library.h"
40 #include "BKE_depsgraph.h"
41 #include "BKE_context.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"
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"
57 #include "ED_object.h"
59 #include "ED_screen.h"
61 #include "RNA_access.h"
66 #include "mesh_intern.h"
67 #include "recast-capi.h"
69 static void createVertsTrisData(bContext *C, LinkNode* obs, int *nverts_r, float **verts_r, int *ntris_r, int **tris_r)
72 int nfaces= 0, *tri, i, curnverts, basenverts, curnfaces;
76 LinkNode *oblink, *dmlink;
78 Scene* scene= CTX_data_scene(C);
81 int nverts, ntris, *tris;
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);
93 nverts+= dm->getNumVerts(dm);
94 nfaces= dm->getNumTessFaces(dm);
97 /* resolve quad faces */
98 mface= dm->getTessFaceArray(dm);
99 for(i= 0; i<nfaces; i++) {
100 MFace* mf= &mface[i];
107 verts= MEM_mallocN(sizeof(float)*3*nverts, "createVertsTrisData verts");
108 tris= MEM_mallocN(sizeof(int)*3*ntris, "createVertsTrisData faces");
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;
117 curnverts= dm->getNumVerts(dm);
118 mvert= dm->getVertArray(dm);
121 for(i= 0; i<curnverts; i++) {
124 copy_v3_v3(co, v->co);
125 mul_v3_m4v3(wco, ob->obmat, co);
127 verts[3*(basenverts+i)+0]= wco[0];
128 verts[3*(basenverts+i)+1]= wco[2];
129 verts[3*(basenverts+i)+2]= wco[1];
133 curnfaces= dm->getNumTessFaces(dm);
134 mface= dm->getTessFaceArray(dm);
136 for(i= 0; i<curnfaces; i++) {
137 MFace* mf= &mface[i];
139 tri[0]= basenverts + mf->v1;
140 tri[1]= basenverts + mf->v3;
141 tri[2]= basenverts + mf->v2;
145 tri[0]= basenverts + mf->v1;
146 tri[1]= basenverts + mf->v4;
147 tri[2]= basenverts + mf->v3;
152 basenverts+= curnverts;
155 /* release derived mesh */
156 for(dmlink= dms; dmlink; dmlink= dmlink->next) {
157 dm= (DerivedMesh*) dmlink->link;
161 BLI_linklist_free(dms, NULL);
169 static int buildNavMesh(const RecastData *recastParams, int nverts, float *verts, int ntris, int *tris,
170 struct recast_polyMesh **pmesh, struct recast_polyMeshDetail **dmesh)
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;
181 recast_calcBounds(verts, nverts, bmin, bmax);
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;
194 /* Set the area where the navigation will be build. */
195 recast_calcGridSize(bmin, bmax, recastParams->cellsize, &width, &height);
197 /* ** Step 2: Rasterize input polygon soup ** */
198 /* Allocate voxel heightfield where we rasterize our input data to */
199 solid= recast_newHeightfield();
201 if(!recast_createHeightfield(solid, width, height, bmin, bmax, recastParams->cellsize, recastParams->cellheight)) {
202 recast_destroyHeightfield(solid);
207 /* Allocate array that can hold triangle flags */
208 triflags= MEM_callocN(sizeof(unsigned char)*ntris, "buildNavMesh triflags");
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);
215 /* ** Step 3: Filter walkables surfaces ** */
216 recast_filterLowHangingWalkableObstacles(walkableClimb, solid);
217 recast_filterLedgeSpans(walkableHeight, walkableClimb, solid);
218 recast_filterWalkableLowHeightSpans(walkableHeight, solid);
220 /* ** Step 4: Partition walkable surface to simple regions ** */
222 chf= recast_newCompactHeightfield();
223 if(!recast_buildCompactHeightfield(walkableHeight, walkableClimb, solid, chf)) {
224 recast_destroyHeightfield(solid);
225 recast_destroyCompactHeightfield(chf);
230 recast_destroyHeightfield(solid);
233 if (!recast_erodeWalkableArea(walkableRadius, chf)) {
234 recast_destroyCompactHeightfield(chf);
239 /* Prepare for region partitioning, by calculating distance field along the walkable surface */
240 if(!recast_buildDistanceField(chf)) {
241 recast_destroyCompactHeightfield(chf);
246 /* Partition the walkable surface into simple regions without holes */
247 if(!recast_buildRegions(chf, 0, minRegionArea, mergeRegionArea)) {
248 recast_destroyCompactHeightfield(chf);
253 /* ** Step 5: Trace and simplify region contours ** */
254 /* Create contours */
255 cset= recast_newContourSet();
257 if(!recast_buildContours(chf, recastParams->edgemaxerror, maxEdgeLen, cset)) {
258 recast_destroyCompactHeightfield(chf);
259 recast_destroyContourSet(cset);
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);
275 /* ** Step 7: Create detail mesh which allows to access approximate height on each polygon ** */
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);
287 recast_destroyCompactHeightfield(chf);
288 recast_destroyContourSet(cset);
293 static Object* createRepresentation(bContext *C, struct recast_polyMesh *pmesh, struct recast_polyMeshDetail *dmesh, Base* base)
300 Scene *scene= CTX_data_scene(C);
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;
313 /* create new object */
314 obedit= ED_object_add_type(C, OB_MESH, co, rot, FALSE, 1);
317 obedit= base->object;
318 scene_select_base(scene, base);
319 copy_v3_v3(obedit->loc, co);
320 copy_v3_v3(obedit->rot, rot);
323 ED_object_enter_editmode(C, EM_DO_UNDO|EM_IGNORE_LAYER);
324 em= (((Mesh *)obedit->data))->edit_btmesh;
331 /* create verts for polygon mesh */
332 verts= recast_polyMeshGetVerts(pmesh, &nverts);
333 recast_polyMeshGetBoundbox(pmesh, bmin, NULL);
334 recast_polyMeshGetCell(pmesh, &cs, &ch);
336 for(i= 0; i<nverts; 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_Make_Vert(em->bm, co, NULL);
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");
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);
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];
363 for(j= 0; j < nvp; ++j) {
364 if(p[j]==0xffff) break;
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_Make_Vert(em->bm, co, NULL);
375 EDBM_init_index_arrays(em, 1, 0, 0);
378 for(j= 0; j<trinum; j++) {
379 unsigned char* tri= &tris[4*(tribase+j)];
383 for(k= 0; k<3; k++) {
385 face[k]= p[tri[k]]; /* shared vertex */
387 face[k]= uniquevbase+tri[k]-nv; /* unique vertex */
389 newFace= BM_Make_QuadTri(em->bm, EDBM_get_vert_for_index(em, face[0]), EDBM_get_vert_for_index(em, face[2]),
390 EDBM_get_vert_for_index(em, face[1]), NULL, NULL, 0);
392 /* set navigation polygon idx to the custom layer */
393 polygonIdx= (int*)CustomData_bmesh_get(&em->bm->pdata, newFace->head.data, CD_RECAST);
394 *polygonIdx= i+1; /* add 1 to avoid zero idx */
397 EDBM_free_index_arrays(em);
400 recast_destroyPolyMesh(pmesh);
401 recast_destroyPolyMeshDetail(dmesh);
403 DAG_id_tag_update((ID*)obedit->data, OB_RECALC_DATA);
404 WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
407 ED_object_exit_editmode(C, EM_FREEDATA);
408 WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, obedit);
411 obedit->gameflag&= ~OB_COLLISION;
412 obedit->gameflag|= OB_NAVMESH;
413 obedit->body_type= OB_BODY_TYPE_NAVMESH;
414 rename_id((ID *)obedit, "Navmesh");
417 BKE_mesh_ensure_navmesh(obedit->data);
422 static int create_navmesh_exec(bContext *C, wmOperator *op)
424 Scene* scene= CTX_data_scene(C);
426 Base* navmeshBase= NULL;
428 CTX_DATA_BEGIN(C, Base*, base, selected_editable_bases) {
429 if (base->object->type == OB_MESH) {
430 if (base->object->body_type==OB_BODY_TYPE_NAVMESH) {
431 if (!navmeshBase || base == scene->basact) {
436 BLI_linklist_append(&obs, (void*)base->object);
443 struct recast_polyMesh *pmesh= NULL;
444 struct recast_polyMeshDetail *dmesh= NULL;
446 int nverts= 0, ntris= 0;
450 createVertsTrisData(C, obs, &nverts, &verts, &ntris, &tris);
451 BLI_linklist_free(obs, NULL);
452 buildNavMesh(&scene->gm.recastData, nverts, verts, ntris, tris, &pmesh, &dmesh);
453 createRepresentation(C, pmesh, dmesh, navmeshBase);
458 return OPERATOR_FINISHED;
461 BKE_report(op->reports, RPT_ERROR, "No mesh objects found");
463 return OPERATOR_CANCELLED;
467 void MESH_OT_navmesh_make(wmOperatorType *ot)
470 ot->name= "Create navigation mesh";
471 ot->description= "Create navigation mesh for selected objects";
472 ot->idname= "MESH_OT_navmesh_make";
475 ot->exec= create_navmesh_exec;
478 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
481 static int navmesh_face_copy_exec(bContext *C, wmOperator *op)
483 Object *obedit= CTX_data_edit_object(C);
484 BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
487 BMFace *efa_act= BM_get_actFace(em->bm, 0);
490 if(CustomData_has_layer(&em->bm->pdata, CD_RECAST)) {
493 int targetPolyIdx= *(int*)CustomData_bmesh_get(&em->bm->pdata, efa_act->head.data, CD_RECAST);
494 targetPolyIdx= targetPolyIdx>=0? targetPolyIdx : -targetPolyIdx;
496 if(targetPolyIdx > 0) {
497 /* set target poly idx to other selected faces */
498 BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
499 if(BM_TestHFlag(efa, BM_SELECT) && efa != efa_act) {
500 int* recastDataBlock= (int*)CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_RECAST);
501 *recastDataBlock= targetPolyIdx;
506 BKE_report(op->reports, RPT_ERROR, "Active face has no index set");
511 DAG_id_tag_update((ID*)obedit->data, OB_RECALC_DATA);
512 WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
514 return OPERATOR_FINISHED;
517 void MESH_OT_navmesh_face_copy(struct wmOperatorType *ot)
520 ot->name= "NavMesh Copy Face Index";
521 ot->description= "Copy the index from the active face";
522 ot->idname= "MESH_OT_navmesh_face_copy";
525 ot->poll= ED_operator_editmesh;
526 ot->exec= navmesh_face_copy_exec;
529 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
532 static int compare(const void * a, const void * b){
533 return ( *(int*)a - *(int*)b );
536 static int findFreeNavPolyIndex(BMEditMesh* em)
538 /* construct vector of indices */
539 int numfaces= em->bm->totface;
540 int* indices= MEM_callocN(sizeof(int)*numfaces, "findFreeNavPolyIndex(indices)");
543 int i, idx= em->bm->totface-1, freeIdx= 1;
545 /*XXX this originally went last to first, but that isn't possible anymore*/
546 BM_ITER(ef, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
547 int polyIdx= *(int*)CustomData_bmesh_get(&em->bm->pdata, ef->head.data, CD_RECAST);
548 indices[idx]= polyIdx;
552 qsort(indices, numfaces, sizeof(int), compare);
554 /* search first free index */
556 for(i= 0; i<numfaces; i++) {
557 if(indices[i]==freeIdx)
559 else if(indices[i]>freeIdx)
568 static int navmesh_face_add_exec(bContext *C, wmOperator *UNUSED(op))
570 Object *obedit= CTX_data_edit_object(C);
571 BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
575 if(CustomData_has_layer(&em->bm->pdata, CD_RECAST)) {
576 int targetPolyIdx= findFreeNavPolyIndex(em);
578 if(targetPolyIdx>0) {
579 /* set target poly idx to selected faces */
580 /*XXX this originally went last to first, but that isn't possible anymore*/
582 BM_ITER(ef, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
583 if(BM_TestHFlag(ef, BM_SELECT)) {
584 int *recastDataBlock= (int*)CustomData_bmesh_get(&em->bm->pdata, ef->head.data, CD_RECAST);
585 *recastDataBlock= targetPolyIdx;
591 DAG_id_tag_update((ID*)obedit->data, OB_RECALC_DATA);
592 WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
594 return OPERATOR_FINISHED;
597 void MESH_OT_navmesh_face_add(struct wmOperatorType *ot)
600 ot->name= "NavMesh New Face Index";
601 ot->description= "Add a new index and assign it to selected faces";
602 ot->idname= "MESH_OT_navmesh_face_add";
605 ot->poll= ED_operator_editmesh;
606 ot->exec= navmesh_face_add_exec;
609 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
612 static int navmesh_obmode_data_poll(bContext *C)
614 Object *ob = ED_object_active_context(C);
615 if (ob && (ob->mode == OB_MODE_OBJECT) && (ob->type == OB_MESH)) {
617 return CustomData_has_layer(&me->fdata, CD_RECAST);
622 static int navmesh_obmode_poll(bContext *C)
624 Object *ob = ED_object_active_context(C);
625 if (ob && (ob->mode == OB_MODE_OBJECT) && (ob->type == OB_MESH)) {
631 static int navmesh_reset_exec(bContext *C, wmOperator *UNUSED(op))
633 Object *ob = ED_object_active_context(C);
636 CustomData_free_layers(&me->fdata, CD_RECAST, me->totface);
638 BKE_mesh_ensure_navmesh(me);
640 DAG_id_tag_update(&me->id, OB_RECALC_DATA);
641 WM_event_add_notifier(C, NC_GEOM|ND_DATA, &me->id);
643 return OPERATOR_FINISHED;
646 void MESH_OT_navmesh_reset(struct wmOperatorType *ot)
649 ot->name= "NavMesh Reset Index Values";
650 ot->description= "Assign a new index to every face";
651 ot->idname= "MESH_OT_navmesh_reset";
654 ot->poll= navmesh_obmode_poll;
655 ot->exec= navmesh_reset_exec;
658 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
661 static int navmesh_clear_exec(bContext *C, wmOperator *UNUSED(op))
663 Object *ob = ED_object_active_context(C);
666 CustomData_free_layers(&me->fdata, CD_RECAST, me->totface);
668 DAG_id_tag_update(&me->id, OB_RECALC_DATA);
669 WM_event_add_notifier(C, NC_GEOM|ND_DATA, &me->id);
671 return OPERATOR_FINISHED;
674 void MESH_OT_navmesh_clear(struct wmOperatorType *ot)
677 ot->name= "NavMesh Clear Data";
678 ot->description= "Remove navmesh data from this mesh";
679 ot->idname= "MESH_OT_navmesh_clear";
682 ot->poll= navmesh_obmode_data_poll;
683 ot->exec= navmesh_clear_exec;
686 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;