4 * ***** BEGIN GPL LICENSE BLOCK *****
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 * The Original Code is Copyright (C) 2011 by Blender Foundation
21 * All rights reserved.
23 * The Original Code is: all of this file.
25 * Contributor(s): Benoit Bolsee,
28 * ***** END GPL LICENSE BLOCK *****
33 #include "MEM_guardedalloc.h"
35 #include "DNA_scene_types.h"
36 #include "DNA_object_types.h"
37 #include "DNA_meshdata_types.h"
38 #include "DNA_modifier_types.h"
41 #include "BKE_library.h"
42 #include "BKE_depsgraph.h"
43 #include "BKE_context.h"
46 #include "BKE_modifier.h"
47 #include "BKE_scene.h"
48 #include "BKE_DerivedMesh.h"
49 #include "BKE_cdderivedmesh.h"
51 #include "BLI_editVert.h"
52 #include "BLI_listbase.h"
53 #include "BLI_utildefines.h"
54 #include "BLI_math_vector.h"
56 #include "ED_object.h"
58 #include "ED_screen.h"
60 #include "RNA_access.h"
65 #include "mesh_intern.h"
66 #include "recast-capi.h"
68 static void createVertsTrisData(bContext *C, LinkNode* obs, int *nverts_r, float **verts_r, int *ntris_r, int **tris_r)
71 int nfaces= 0, *tri, i, curnverts, basenverts, curnfaces;
75 LinkNode *oblink, *dmlink;
77 Scene* scene= CTX_data_scene(C);
80 int nverts, ntris, *tris;
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(scene, ob, NULL, CD_MASK_MESH);
90 BLI_linklist_append(&dms, (void*)dm);
92 nverts+= dm->getNumVerts(dm);
93 nfaces= dm->getNumFaces(dm);
96 /* resolve quad faces */
97 mface= dm->getFaceArray(dm);
98 for(i= 0; i<nfaces; i++) {
106 verts= MEM_mallocN(sizeof(float)*3*nverts, "createVertsTrisData verts");
107 tris= MEM_mallocN(sizeof(int)*3*ntris, "createVertsTrisData faces");
111 for(oblink= obs, dmlink= dms; oblink && dmlink;
112 oblink= oblink->next, dmlink= dmlink->next) {
113 ob= (Object*) oblink->link;
114 dm= (DerivedMesh*) dmlink->link;
116 curnverts= dm->getNumVerts(dm);
117 mvert= dm->getVertArray(dm);
120 for(i= 0; i<curnverts; i++) {
123 copy_v3_v3(co, v->co);
124 mul_v3_m4v3(wco, ob->obmat, co);
126 verts[3*(basenverts+i)+0]= wco[0];
127 verts[3*(basenverts+i)+1]= wco[2];
128 verts[3*(basenverts+i)+2]= wco[1];
132 curnfaces= dm->getNumFaces(dm);
133 mface= dm->getFaceArray(dm);
135 for(i= 0; i<curnfaces; i++) {
136 MFace* mf= &mface[i];
138 tri[0]= basenverts + mf->v1;
139 tri[1]= basenverts + mf->v3;
140 tri[2]= basenverts + mf->v2;
144 tri[0]= basenverts + mf->v1;
145 tri[1]= basenverts + mf->v4;
146 tri[2]= basenverts + mf->v3;
151 basenverts+= curnverts;
154 /* release derived mesh */
155 for(dmlink= dms; dmlink; dmlink= dmlink->next) {
156 dm= (DerivedMesh*) dmlink->link;
160 BLI_linklist_free(dms, NULL);
168 static int buildNavMesh(const RecastData *recastParams, int nverts, float *verts, int ntris, int *tris,
169 struct recast_polyMesh **pmesh, struct recast_polyMeshDetail **dmesh)
171 float bmin[3], bmax[3];
172 struct recast_heightfield *solid;
173 unsigned char *triflags;
174 struct recast_compactHeightfield* chf;
175 struct recast_contourSet *cset;
176 int width, height, walkableHeight, walkableClimb, walkableRadius;
177 int minRegionArea, mergeRegionArea, maxEdgeLen;
178 float detailSampleDist, detailSampleMaxError;
180 recast_calcBounds(verts, nverts, bmin, bmax);
182 /* ** Step 1. Initialize build config ** */
183 walkableHeight= (int)ceilf(recastParams->agentheight/ recastParams->cellheight);
184 walkableClimb= (int)floorf(recastParams->agentmaxclimb / recastParams->cellheight);
185 walkableRadius= (int)ceilf(recastParams->agentradius / recastParams->cellsize);
186 minRegionArea= (int)(recastParams->regionminsize * recastParams->regionminsize);
187 mergeRegionArea= (int)(recastParams->regionmergesize * recastParams->regionmergesize);
188 maxEdgeLen= (int)(recastParams->edgemaxlen/recastParams->cellsize);
189 detailSampleDist= recastParams->detailsampledist< 0.9f ? 0 :
190 recastParams->cellsize * recastParams->detailsampledist;
191 detailSampleMaxError= recastParams->cellheight * recastParams->detailsamplemaxerror;
193 /* Set the area where the navigation will be build. */
194 recast_calcGridSize(bmin, bmax, recastParams->cellsize, &width, &height);
196 /* ** Step 2: Rasterize input polygon soup ** */
197 /* Allocate voxel heightfield where we rasterize our input data to */
198 solid= recast_newHeightfield();
200 if(!recast_createHeightfield(solid, width, height, bmin, bmax, recastParams->cellsize, recastParams->cellheight)) {
201 recast_destroyHeightfield(solid);
206 /* Allocate array that can hold triangle flags */
207 triflags= MEM_callocN(sizeof(unsigned char)*ntris, "buildNavMesh triflags");
209 /* Find triangles which are walkable based on their slope and rasterize them */
210 recast_markWalkableTriangles(RAD2DEG(recastParams->agentmaxslope), verts, nverts, tris, ntris, triflags);
211 recast_rasterizeTriangles(verts, nverts, tris, triflags, ntris, solid);
214 /* ** Step 3: Filter walkables surfaces ** */
215 recast_filterLowHangingWalkableObstacles(walkableClimb, solid);
216 recast_filterLedgeSpans(walkableHeight, walkableClimb, solid);
217 recast_filterWalkableLowHeightSpans(walkableHeight, solid);
219 /* ** Step 4: Partition walkable surface to simple regions ** */
221 chf= recast_newCompactHeightfield();
222 if(!recast_buildCompactHeightfield(walkableHeight, walkableClimb, solid, chf)) {
223 recast_destroyHeightfield(solid);
224 recast_destroyCompactHeightfield(chf);
229 recast_destroyHeightfield(solid);
232 if (!recast_erodeWalkableArea(walkableRadius, chf)) {
233 recast_destroyCompactHeightfield(chf);
238 /* Prepare for region partitioning, by calculating distance field along the walkable surface */
239 if(!recast_buildDistanceField(chf)) {
240 recast_destroyCompactHeightfield(chf);
245 /* Partition the walkable surface into simple regions without holes */
246 if(!recast_buildRegions(chf, 0, minRegionArea, mergeRegionArea)) {
247 recast_destroyCompactHeightfield(chf);
252 /* ** Step 5: Trace and simplify region contours ** */
253 /* Create contours */
254 cset= recast_newContourSet();
256 if(!recast_buildContours(chf, recastParams->edgemaxerror, maxEdgeLen, cset)) {
257 recast_destroyCompactHeightfield(chf);
258 recast_destroyContourSet(cset);
263 /* ** Step 6: Build polygons mesh from contours ** */
264 *pmesh= recast_newPolyMesh();
265 if(!recast_buildPolyMesh(cset, recastParams->vertsperpoly, *pmesh)) {
266 recast_destroyCompactHeightfield(chf);
267 recast_destroyContourSet(cset);
268 recast_destroyPolyMesh(*pmesh);
274 /* ** Step 7: Create detail mesh which allows to access approximate height on each polygon ** */
276 *dmesh= recast_newPolyMeshDetail();
277 if(!recast_buildPolyMeshDetail(*pmesh, chf, detailSampleDist, detailSampleMaxError, *dmesh)) {
278 recast_destroyCompactHeightfield(chf);
279 recast_destroyContourSet(cset);
280 recast_destroyPolyMesh(*pmesh);
281 recast_destroyPolyMeshDetail(*dmesh);
286 recast_destroyCompactHeightfield(chf);
287 recast_destroyContourSet(cset);
292 static Object* createRepresentation(bContext *C, struct recast_polyMesh *pmesh, struct recast_polyMeshDetail *dmesh, Base* base)
299 Main *bmain= CTX_data_main(C);
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;
314 /* create new object */
315 obedit= ED_object_add_type(C, OB_MESH, co, rot, FALSE, 1);
318 obedit= base->object;
319 scene_select_base(scene, base);
320 copy_v3_v3(obedit->loc, co);
321 copy_v3_v3(obedit->rot, rot);
324 ED_object_enter_editmode(C, EM_DO_UNDO|EM_IGNORE_LAYER);
325 em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
329 if(em->verts.first) free_vertlist(em, &em->verts);
330 if(em->edges.first) free_edgelist(em, &em->edges);
331 if(em->faces.first) free_facelist(em, &em->faces);
332 if(em->selected.first) BLI_freelistN(&(em->selected));
335 /* create verts for polygon mesh */
336 verts= recast_polyMeshGetVerts(pmesh, &nverts);
337 recast_polyMeshGetBoundbox(pmesh, bmin, NULL);
338 recast_polyMeshGetCell(pmesh, &cs, &ch);
340 for(i= 0; i<nverts; i++) {
342 co[0]= bmin[0] + v[0]*cs;
343 co[1]= bmin[1] + v[1]*ch;
344 co[2]= bmin[2] + v[2]*cs;
345 SWAP(float, co[1], co[2]);
346 addvertlist(em, co, NULL);
349 /* create custom data layer to save polygon idx */
350 CustomData_add_layer_named(&em->fdata, CD_RECAST, CD_CALLOC, NULL, 0, "createRepresentation recastData");
352 /* create verts and faces for detailed mesh */
353 meshes= recast_polyMeshDetailGetMeshes(dmesh, &nmeshes);
354 polys= recast_polyMeshGetPolys(pmesh, NULL, &nvp);
355 dverts= recast_polyMeshDetailGetVerts(dmesh, NULL);
356 tris= recast_polyMeshDetailGetTris(dmesh, NULL);
358 for(i= 0; i<nmeshes; i++) {
359 int uniquevbase= em->totvert;
360 unsigned int vbase= meshes[4*i+0];
361 unsigned short ndv= meshes[4*i+1];
362 unsigned short tribase= meshes[4*i+2];
363 unsigned short trinum= meshes[4*i+3];
364 const unsigned short* p= &polys[i*nvp*2];
367 for(j= 0; j < nvp; ++j) {
368 if(p[j]==0xffff) break;
372 /* create unique verts */
373 for(j= nv; j<ndv; j++) {
374 copy_v3_v3(co, &dverts[3*(vbase + j)]);
375 SWAP(float, co[1], co[2]);
376 addvertlist(em, co, NULL);
379 EM_init_index_arrays(em, 1, 0, 0);
382 for(j= 0; j<trinum; j++) {
383 unsigned char* tri= &tris[4*(tribase+j)];
387 for(k= 0; k<3; k++) {
389 face[k]= p[tri[k]]; /* shared vertex */
391 face[k]= uniquevbase+tri[k]-nv; /* unique vertex */
393 newFace= addfacelist(em, EM_get_vert_for_index(face[0]), EM_get_vert_for_index(face[2]),
394 EM_get_vert_for_index(face[1]), NULL, NULL, NULL);
396 /* set navigation polygon idx to the custom layer */
397 polygonIdx= (int*)CustomData_em_get(&em->fdata, newFace->data, CD_RECAST);
398 *polygonIdx= i+1; /* add 1 to avoid zero idx */
401 EM_free_index_arrays();
404 recast_destroyPolyMesh(pmesh);
405 recast_destroyPolyMeshDetail(dmesh);
407 BKE_mesh_end_editmesh((Mesh*)obedit->data, em);
409 DAG_id_tag_update((ID*)obedit->data, OB_RECALC_DATA);
410 WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
413 ED_object_exit_editmode(C, EM_FREEDATA);
414 WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, obedit);
417 obedit->gameflag&= ~OB_COLLISION;
418 obedit->gameflag|= OB_NAVMESH;
419 obedit->body_type= OB_BODY_TYPE_NAVMESH;
420 rename_id((ID *)obedit, "Navmesh");
423 md= modifiers_findByType(obedit, eModifierType_NavMesh);
425 ED_object_modifier_add(NULL, bmain, scene, obedit, NULL, eModifierType_NavMesh);
431 static int create_navmesh_exec(bContext *C, wmOperator *UNUSED(op))
433 Scene* scene= CTX_data_scene(C);
434 int nverts= 0, ntris= 0;
437 struct recast_polyMesh *pmesh= NULL;
438 struct recast_polyMeshDetail *dmesh= NULL;
440 Base* navmeshBase= NULL;
442 CTX_DATA_BEGIN(C, Base*, base, selected_editable_bases) {
443 if(base->object->body_type==OB_BODY_TYPE_NAVMESH) {
444 if(!navmeshBase || base==CTX_data_active_base(C))
448 BLI_linklist_append(&obs, (void*)base->object);
452 createVertsTrisData(C, obs, &nverts, &verts, &ntris, &tris);
453 BLI_linklist_free(obs, NULL);
454 buildNavMesh(&scene->gm.recastData, nverts, verts, ntris, tris, &pmesh, &dmesh);
455 createRepresentation(C, pmesh, dmesh, navmeshBase);
460 return OPERATOR_FINISHED;
463 void MESH_OT_create_navmesh(wmOperatorType *ot)
466 ot->name= "Create navigation mesh";
467 ot->description= "Create navigation mesh for selected objects";
468 ot->idname= "MESH_OT_create_navmesh";
471 ot->exec= create_navmesh_exec;
474 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
477 static int assign_navpolygon_exec(bContext *C, wmOperator *UNUSED(op))
479 Object *obedit= CTX_data_edit_object(C);
480 EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
483 int targetPolyIdx= -1;
485 efa= EM_get_actFace(em, 0);
488 if(CustomData_has_layer(&em->fdata, CD_RECAST)) {
489 targetPolyIdx= *(int*)CustomData_em_get(&em->fdata, efa->data, CD_RECAST);
490 targetPolyIdx= targetPolyIdx>=0? targetPolyIdx : -targetPolyIdx;
492 if(targetPolyIdx>0) {
493 /* set target poly idx to other selected faces */
494 ef= (EditFace*)em->faces.last;
496 if((ef->f & SELECT )&& ef!=efa) {
497 int* recastDataBlock= (int*)CustomData_em_get(&em->fdata, ef->data, CD_RECAST);
498 *recastDataBlock= targetPolyIdx;
506 DAG_id_tag_update((ID*)obedit->data, OB_RECALC_DATA);
507 WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
509 BKE_mesh_end_editmesh((Mesh*)obedit->data, em);
511 return OPERATOR_FINISHED;
514 void MESH_OT_assign_navpolygon(struct wmOperatorType *ot)
517 ot->name= "Assign polygon index";
518 ot->description= "Assign polygon index to face by active face";
519 ot->idname= "MESH_OT_assign_navpolygon";
522 ot->poll= ED_operator_editmesh;
523 ot->exec= assign_navpolygon_exec;
526 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
529 static int compare(const void * a, const void * b){
530 return ( *(int*)a - *(int*)b );
533 static int findFreeNavPolyIndex(EditMesh* em)
535 /* construct vector of indices */
536 int numfaces= em->totface;
537 int* indices= MEM_callocN(sizeof(int)*numfaces, "findFreeNavPolyIndex(indices)");
538 EditFace* ef= (EditFace*)em->faces.last;
539 int i, idx= 0, freeIdx= 1;
542 int polyIdx= *(int*)CustomData_em_get(&em->fdata, ef->data, CD_RECAST);
543 indices[idx]= polyIdx;
548 qsort(indices, numfaces, sizeof(int), compare);
550 /* search first free index */
552 for(i= 0; i<numfaces; i++) {
553 if(indices[i]==freeIdx)
555 else if(indices[i]>freeIdx)
564 static int assign_new_navpolygon_exec(bContext *C, wmOperator *UNUSED(op))
566 Object *obedit= CTX_data_edit_object(C);
567 EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
570 if(CustomData_has_layer(&em->fdata, CD_RECAST)) {
571 int targetPolyIdx= findFreeNavPolyIndex(em);
573 if(targetPolyIdx>0) {
574 /* set target poly idx to selected faces */
575 ef= (EditFace*)em->faces.last;
578 int *recastDataBlock= (int*)CustomData_em_get(&em->fdata, ef->data, CD_RECAST);
579 *recastDataBlock= targetPolyIdx;
586 DAG_id_tag_update((ID*)obedit->data, OB_RECALC_DATA);
587 WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
589 BKE_mesh_end_editmesh((Mesh*)obedit->data, em);
590 return OPERATOR_FINISHED;
593 void MESH_OT_assign_new_navpolygon(struct wmOperatorType *ot)
596 ot->name= "Assign new polygon index";
597 ot->description= "Assign new polygon index to face";
598 ot->idname= "MESH_OT_assign_new_navpolygon";
601 ot->poll= ED_operator_editmesh;
602 ot->exec= assign_new_navpolygon_exec;
605 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;