@recast-navigation/generators 0.35.0 → 0.35.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1,2 +1,973 @@
1
- import{vec3 as e,recastConfigDefaults as t,Raw as i,RecastBuildContext as a,NavMesh as l,VerticesArray as o,TrianglesArray as r,createRcConfig as s,calcGridSize as n,allocHeightfield as h,createHeightfield as d,TriangleAreasArray as c,markWalkableTriangles as m,rasterizeTriangles as g,filterLowHangingWalkableObstacles as b,filterLedgeSpans as u,filterWalkableLowHeightSpans as f,allocCompactHeightfield as y,buildCompactHeightfield as w,freeHeightfield as S,erodeWalkableArea as p,buildDistanceField as M,buildRegions as R,allocContourSet as C,buildContours as x,Recast as v,allocPolyMesh as k,buildPolyMesh as _,allocPolyMeshDetail as z,buildPolyMeshDetail as A,freeCompactHeightfield as T,freeContourSet as E,NavMeshCreateParams as H,createNavMeshData as D,freePolyMesh as L,freePolyMeshDetail as P,TileCacheMeshProcess as F,TileCache as O,DetourTileCacheParams as I,NavMeshParams as $,RecastChunkyTriMesh as G,statusFailed as N,freeHeightfieldLayerSet as W,cloneRcConfig as B,ChunkIdsArray as j,allocHeightfieldLayerSet as K,buildHeightfieldLayers as U,TileCacheData as V,Detour as X,getHeightfieldLayerHeights as Y,getHeightfieldLayerAreas as Z,getHeightfieldLayerCons as q,buildTileCacheLayer as J,statusToReadableString as Q}from"@recast-navigation/core";const ee=(t,i)=>{const a={x:1/0,y:1/0,z:1/0},l={x:-1/0,y:-1/0,z:-1/0};for(let e=0;e<i.length;e++){const o=i[e],r=t[3*o],s=t[3*o+1],n=t[3*o+2];a.x=Math.min(a.x,r),a.y=Math.min(a.y,s),a.z=Math.min(a.z,n),l.x=Math.max(l.x,r),l.y=Math.max(l.y,s),l.z=Math.max(l.z,n)}return{bbMin:e.toArray(a),bbMax:e.toArray(l)}},te=e=>{let t=0,i=0;return t=Number(e>65535)<<4,e>>=t,i=Number(e>255)<<3,e>>=i,t|=i,i=Number(e>15)<<2,e>>=i,t|=i,i=Number(e>3)<<1,t|=i,t|=(e>>=i)>>1,t},ie=e=>(e--,e|=e>>1,e|=e>>2,e|=e>>4,e|=e>>8,e|=e>>16,++e),ae={...t},le=(e,t,F={},O=!1)=>{if(!i.Module)throw new Error('"init" must be called before using any recast-navigation-js APIs. See: https://github.com/isaac-mason/recast-navigation-js?tab=readme-ov-file#initialization');const I=new a,$={type:"solo",buildContext:I},G=new l,N=e=>(O||($.heightfield&&(S($.heightfield),$.heightfield=void 0),$.compactHeightfield&&(T($.compactHeightfield),$.compactHeightfield=void 0),$.contourSet&&(E($.contourSet),$.contourSet=void 0),$.polyMesh&&(L($.polyMesh),$.polyMesh=void 0),$.polyMeshDetail&&(P($.polyMeshDetail),$.polyMeshDetail=void 0)),G.destroy(),{navMesh:void 0,success:!1,intermediates:$,error:e}),W=e,B=t.length,j=new o;j.copy(W);const K=t,U=t.length/3,V=new r;V.copy(K);const{bbMin:X,bbMax:Y}=ee(e,t),Z=s({...ae,...F});Z.minRegionArea=Z.minRegionArea*Z.minRegionArea,Z.mergeRegionArea=Z.mergeRegionArea*Z.mergeRegionArea,Z.detailSampleDist=Z.detailSampleDist<.9?0:Z.cs*Z.detailSampleDist,Z.detailSampleMaxError=Z.ch*Z.detailSampleMaxError;const q=n(X,Y,Z.cs);Z.width=q.width,Z.height=q.height;const J=h();if($.heightfield=J,!d(I,J,Z.width,Z.height,X,Y,Z.cs,Z.ch))return N("Could not create heightfield");const Q=new c;if(Q.resize(U),m(I,Z.walkableSlopeAngle,j,B,V,U,Q),!g(I,j,B,V,Q,U,J,Z.walkableClimb))return N("Could not rasterize triangles");Q.destroy(),j.destroy(),V.destroy(),b(I,Z.walkableClimb,J),u(I,Z.walkableHeight,Z.walkableClimb,J),f(I,Z.walkableHeight,J);const te=y();if($.compactHeightfield=te,!w(I,Z.walkableHeight,Z.walkableClimb,J,te))return N("Failed to build compact data");if(O||(S(J),$.heightfield=void 0),!p(I,Z.walkableRadius,te))return N("Failed to erode walkable area");if(!M(I,te))return N("Failed to build distance field");if(!R(I,te,Z.borderSize,Z.minRegionArea,Z.mergeRegionArea))return N("Failed to build regions");const ie=C();if($.contourSet=ie,!x(I,te,Z.maxSimplificationError,Z.maxEdgeLen,ie,v.RC_CONTOUR_TESS_WALL_EDGES))return N("Failed to create contours");const le=k();if($.polyMesh=le,!_(I,ie,Z.maxVertsPerPoly,le))return N("Failed to triangulate contours");const oe=z();if($.polyMeshDetail=oe,!A(I,le,te,Z.detailSampleDist,Z.detailSampleMaxError,oe))return N("Failed to build detail mesh");O||(T(te),$.compactHeightfield=void 0,E(ie),$.contourSet=void 0);for(let e=0;e<le.npolys();e++)le.areas(e)==v.RC_WALKABLE_AREA&&le.setAreas(e,0),0==le.areas(e)&&le.setFlags(e,1);const re=new H;re.setPolyMeshCreateParams(le),re.setPolyMeshDetailCreateParams(oe),re.setWalkableHeight(Z.walkableHeight),re.setWalkableRadius(Z.walkableRadius),re.setWalkableClimb(Z.walkableClimb),re.setCellSize(Z.cs),re.setCellHeight(Z.ch),re.setBuildBvTree(!0),F.offMeshConnections&&re.setOffMeshConnections(F.offMeshConnections);const se=D(re);if(!se.success)return N("Failed to create Detour navmesh data");const{navMeshData:ne}=se;return G.initSolo(ne)?{success:!0,navMesh:G,intermediates:$}:N("Failed to create Detour navmesh")},oe={...t,tileSize:32,expectedLayersPerTile:4,maxObstacles:128},re=()=>new F(((e,t,i)=>{for(let a=0;a<e.polyCount();++a)t.set(a,0),i.set(a,1)})),se=(t,M,R={},C=!1)=>{if(!i.Module)throw new Error('"init" must be called before using any recast-navigation-js APIs. See: https://github.com/isaac-mason/recast-navigation-js?tab=readme-ov-file#initialization');const x=new a,k={type:"tilecache",buildContext:x,chunkyTriMesh:void 0,tileIntermediates:[]},_=new O,z=new l,A=t,E=M.length,H=new o;H.copy(A);const D=M,L=M.length/3,P=new r;P.copy(D);const{bbMin:F,bbMax:Q}=ee(t,M),{expectedLayersPerTile:ae,maxObstacles:le,...se}={...oe,...R},ne=()=>{if(H.destroy(),P.destroy(),!C)for(let e=0;e<k.tileIntermediates.length;e++){const t=k.tileIntermediates[e];t.heightfield&&(S(t.heightfield),t.heightfield=void 0),t.compactHeightfield&&(T(t.compactHeightfield),t.compactHeightfield=void 0),t.heightfieldLayerSet&&(W(t.heightfieldLayerSet),t.heightfieldLayerSet=void 0)}},he=e=>(ne(),_.destroy(),z.destroy(),{success:!1,navMesh:void 0,tileCache:void 0,intermediates:k,error:e}),de=s(se),ce=n(F,Q,de.cs);de.width=ce.width,de.height=ce.height,de.minRegionArea=de.minRegionArea*de.minRegionArea,de.mergeRegionArea=de.mergeRegionArea*de.mergeRegionArea,de.detailSampleDist=de.detailSampleDist<.9?0:de.cs*de.detailSampleDist,de.detailSampleMaxError=de.ch*de.detailSampleMaxError;const me=Math.floor(de.tileSize),ge=Math.floor((de.width+me-1)/me),be=Math.floor((de.height+me-1)/me);de.borderSize=de.walkableRadius+3,de.width=de.tileSize+2*de.borderSize,de.height=de.tileSize+2*de.borderSize;const ue=I.create({orig:F,cs:de.cs,ch:de.ch,width:de.tileSize,height:de.tileSize,walkableHeight:de.walkableHeight,walkableRadius:de.walkableRadius,walkableClimb:de.walkableClimb,maxSimplificationError:de.maxSimplificationError,maxTiles:ge*be*ae,maxObstacles:le}),fe=new i.RecastLinearAllocator(32e3),ye=new i.RecastFastLZCompressor,we=R.tileCacheMeshProcess??re();if(!_.init(ue,fe,ye,we))return he("Failed to initialize tile cache");const Se=e.fromArray(F);let pe=Math.min(Math.floor(te(ie(ge*be*ae))),14);pe>14&&(pe=14);const Me=1<<pe,Re=1<<22-pe,Ce=$.create({orig:Se,tileWidth:de.tileSize*de.cs,tileHeight:de.tileSize*de.cs,maxTiles:Me,maxPolys:Re});if(!z.initTiled(Ce))return he("Failed to initialize tiled navmesh");const xe=new G;if(k.chunkyTriMesh=xe,!xe.init(H,P,L,256))return he("Failed to build chunky triangle mesh");const ve=(e,t)=>{const a={tileX:e,tileY:t},l=de.tileSize*de.cs,o=B(de),r=[F[0]+e*l,F[1],F[2]+t*l],s=[F[0]+(e+1)*l,Q[1],F[2]+(t+1)*l];r[0]-=o.borderSize*o.cs,r[2]-=o.borderSize*o.cs,s[0]+=o.borderSize*o.cs,s[2]+=o.borderSize*o.cs,o.set_bmin(0,r[0]),o.set_bmin(1,r[1]),o.set_bmin(2,r[2]),o.set_bmax(0,s[0]),o.set_bmax(1,s[1]),o.set_bmax(2,s[2]);const n=h();if(a.heightfield=n,!d(x,n,o.width,o.height,r,s,o.cs,o.ch))return{n:0};const M=[r[0],r[2]],R=[s[0],s[2]],v=new j;v.resize(512);const _=xe.getChunksOverlappingRect(M,R,v,512);if(0===_)return{n:0};for(let e=0;e<_;++e){const t=v.get(e),i=xe.nodes(t).n,a=xe.getNodeTris(t),l=new c;l.resize(i),m(x,o.walkableSlopeAngle,H,E,a,i,l);const r=g(x,H,E,a,l,i,n,o.walkableClimb);if(l.destroy(),!r)return{n:0}}b(x,de.walkableClimb,n),u(x,de.walkableHeight,de.walkableClimb,n),f(x,de.walkableHeight,n);const z=y();if(!w(x,de.walkableHeight,de.walkableClimb,n,z))return{n:0};if(C||(S(a.heightfield),a.heightfield=void 0),!p(x,de.walkableRadius,z))return{n:0};const A=K();if(!U(x,z,de.borderSize,de.walkableHeight,A))return{n:0};C||(T(z),a.compactHeightfield=void 0);const D=[];for(let a=0;a<A.nlayers();a++){const l=new V,o=A.layers(a),r=new i.dtTileCacheLayerHeader;r.magic=X.DT_TILECACHE_MAGIC,r.version=X.DT_TILECACHE_VERSION,r.tx=e,r.ty=t,r.tlayer=a;const s=o.bmin(),n=o.bmax();r.set_bmin(0,s.x),r.set_bmin(1,s.y),r.set_bmin(2,s.z),r.set_bmax(0,n.x),r.set_bmax(1,n.y),r.set_bmax(2,n.z),r.width=o.width(),r.height=o.height(),r.minx=o.minx(),r.maxx=o.maxx(),r.miny=o.miny(),r.maxy=o.maxy(),r.hmin=o.hmin(),r.hmax=o.hmax();const h=Y(o),d=Z(o),c=q(o),m=J(ye,r,h,d,c,l);if(N(m))return{n:0};D.push(l)}return C||(W(A),a.heightfieldLayerSet=void 0),k.tileIntermediates.push(a),{n:D.length,tiles:D}};for(let e=0;e<be;++e)for(let t=0;t<ge;++t){const{n:i,tiles:a}=ve(t,e);if(i>0&&a)for(let l=0;l<i;l++){const i=a[l],o=_.addTile(i);N(o.status)&&x.log(v.RC_LOG_WARNING,`Failed to add tile to tile cache - tx: ${t}, ty: ${e}`)}}for(let e=0;e<be;e++)for(let t=0;t<ge;t++){const i=_.buildNavMeshTilesAt(t,e,z);if(N(i))return he(`Failed to build nav mesh tiles at ${t}, ${e}`)}return ne(),{success:!0,tileCache:_,navMesh:z,intermediates:k}},ne={...t},he=(t,F,O={},I=!1)=>{if(!i.Module)throw new Error('"init" must be called before using any recast-navigation-js APIs. See: https://github.com/isaac-mason/recast-navigation-js?tab=readme-ov-file#initialization');const W=new a,K={type:"tiled",buildContext:W,chunkyTriMesh:void 0,tileIntermediates:[]},U=new l,V=t,Y=F.length,Z=new o;Z.copy(V);const q=F,J=F.length/3,ae=new r;ae.copy(q);const le=()=>{if(Z.destroy(),ae.destroy(),!I){for(let e=0;e<K.tileIntermediates.length;e++){const t=K.tileIntermediates[e];t.compactHeightfield&&(T(t.compactHeightfield),t.compactHeightfield=void 0),t.heightfield&&(S(t.heightfield),t.heightfield=void 0),t.contourSet&&(E(t.contourSet),t.contourSet=void 0),t.polyMesh&&(L(t.polyMesh),t.polyMesh=void 0),t.polyMeshDetail&&(P(t.polyMeshDetail),t.polyMeshDetail=void 0)}K.chunkyTriMesh&&(K.chunkyTriMesh=void 0)}},oe=e=>(le(),U.destroy(),{success:!1,navMesh:void 0,intermediates:K,error:e}),re=s({...ne,...O}),{bbMin:se,bbMax:he}=ee(t,F),de=n(se,he,re.cs);re.width=de.width,re.height=de.height,re.minRegionArea=re.minRegionArea*re.minRegionArea,re.mergeRegionArea=re.mergeRegionArea*re.mergeRegionArea,re.tileSize=Math.floor(re.tileSize),re.borderSize=re.walkableRadius+3,re.width=re.tileSize+2*re.borderSize,re.height=re.tileSize+2*re.borderSize,re.detailSampleDist=re.detailSampleDist<.9?0:re.cs*re.detailSampleDist,re.detailSampleMaxError=re.ch*re.detailSampleMaxError;const ce=Math.floor(re.tileSize),me=Math.floor((de.width+ce-1)/ce),ge=Math.floor((de.height+ce-1)/ce),be=re.tileSize*re.cs,ue=e.fromArray(se);let fe=Math.min(Math.floor(te(ie(me*ge))),14);fe>14&&(fe=14);const ye=1<<fe,we=1<<22-fe,Se=$.create({orig:ue,tileWidth:re.tileSize*re.cs,tileHeight:re.tileSize*re.cs,maxTiles:ye,maxPolys:we});if(!U.initTiled(Se))return oe("Could not init nav mesh for tiled use");const pe=new G;if(K.chunkyTriMesh=pe,!pe.init(Z,ae,J,256))return oe("Failed to build chunky triangle mesh");const Me=(e,t,i,a)=>{const l=e=>(W.log(v.RC_LOG_ERROR,e),{success:!1,error:e}),o={tileX:e,tileY:t};K.tileIntermediates.push(o);const r=B(re),s=[...i],n=[...a];s[0]-=r.borderSize*r.cs,s[2]-=r.borderSize*r.cs,n[0]+=r.borderSize*r.cs,n[2]+=r.borderSize*r.cs,r.set_bmin(0,s[0]),r.set_bmin(1,s[1]),r.set_bmin(2,s[2]),r.set_bmax(0,n[0]),r.set_bmax(1,n[1]),r.set_bmax(2,n[2]),W.resetTimers(),W.startTimer(v.RC_TIMER_TOTAL),W.log(v.RC_LOG_PROGRESS,`Building tile ${K.tileIntermediates.length} at x: ${e}, y: ${t}`),W.log(v.RC_LOG_PROGRESS,` - ${re.width} x ${re.height} cells`),W.log(v.RC_LOG_PROGRESS,` - ${Y/1e3}fK verts, ${J/1e3}K tris`);const L=h();if(o.heightfield=L,!d(W,L,r.width,r.height,s,n,r.cs,r.ch))return l("Could not create heightfield");(new c).resize(pe.maxTrisPerChunk());const P=[s[0],s[2]],F=[n[0],n[2]],$=new j;$.resize(512);const G=pe.getChunksOverlappingRect(P,F,$,512);if(0===G)return{success:!0};for(let e=0;e<G;++e){const t=$.get(e),i=pe.nodes(t).n,a=pe.getNodeTris(t),o=new c;o.resize(i),m(W,r.walkableSlopeAngle,Z,Y,a,i,o);const s=g(W,Z,Y,a,o,i,L,r.walkableClimb);if(o.destroy(),!s)return l("Could not rasterize triangles")}b(W,r.walkableClimb,L),u(W,r.walkableHeight,r.walkableClimb,L),f(W,r.walkableHeight,L);const N=y();if(o.compactHeightfield=N,!w(W,r.walkableHeight,r.walkableClimb,L,N))return l("Could not build compact heightfield");if(I||(S(o.heightfield),o.heightfield=void 0),!p(W,r.walkableRadius,N))return l("Could not erode walkable area");if(!M(W,N))return l("Failed to build distance field");if(!R(W,N,r.borderSize,r.minRegionArea,r.mergeRegionArea))return l("Failed to build regions");const U=C();if(o.contourSet=U,!x(W,N,r.maxSimplificationError,r.maxEdgeLen,U,v.RC_CONTOUR_TESS_WALL_EDGES))return l("Failed to create contours");const V=k();if(o.polyMesh=V,!_(W,U,r.maxVertsPerPoly,V))return l("Failed to triangulate contours");const X=z();if(o.polyMeshDetail=X,!A(W,V,N,r.detailSampleDist,r.detailSampleMaxError,X))return l("Failed to build detail mesh");I||(T(N),o.compactHeightfield=void 0,E(U),o.contourSet=void 0);for(let e=0;e<V.npolys();e++)V.areas(e)==v.RC_WALKABLE_AREA&&V.setAreas(e,0),0==V.areas(e)&&V.setFlags(e,1);const q=new H;q.setPolyMeshCreateParams(V),q.setPolyMeshDetailCreateParams(X),q.setWalkableHeight(r.walkableHeight),q.setWalkableRadius(r.walkableRadius),q.setWalkableClimb(r.walkableClimb),q.setCellSize(r.cs),q.setCellHeight(r.ch),q.setBuildBvTree(!0),O.offMeshConnections&&q.setOffMeshConnections(O.offMeshConnections),q.setTileX(e),q.setTileY(t);const Q=D(q);return Q.success?(W.log(v.RC_LOG_PROGRESS,`>> Polymesh: ${V.nverts()} vertices ${V.npolys()} polygons`),{success:!0,data:Q.navMeshData}):l("Failed to create Detour navmesh data")};W.startTimer(v.RC_TIMER_TEMP);const Re=[0,0,0],Ce=[0,0,0];for(let e=0;e<ge;e++)for(let t=0;t<me;t++){Re[0]=se[0]+t*be,Re[1]=se[1],Re[2]=se[2]+e*be,Ce[0]=se[0]+(t+1)*be,Ce[1]=he[1],Ce[2]=se[2]+(e+1)*be;const i=Me(t,e,Re,Ce);if(i.success&&i.data){U.removeTile(U.getTileRefAt(t,e,0));const a=U.addTile(i.data,X.DT_TILE_FREE_DATA,0);N(a.status)&&(W.log(v.RC_LOG_WARNING,`Failed to add tile to nav mesh\n\ttx: ${t}, ty: ${e},status: ${Q(a.status)} (${a.status})`),i.data.destroy())}}return W.stopTimer(v.RC_TIMER_TEMP),I||le(),{success:!0,navMesh:U,intermediates:K}},de=e=>{const t=[],i=[],a={};let l=0;for(const{positions:o,indices:r}of e)for(let e=0;e<r.length;e++){const s=3*r[e],n=o[s],h=o[s+1],d=o[s+2],c=`${n}_${h}_${d}`;let m=a[c];m||(a[c]=m=l,t.push(n,h,d),l++),i.push(m)}return[Float32Array.from(t),Uint32Array.from(i)]};export{re as createDefaultTileCacheMeshProcess,te as dtIlog2,ie as dtNextPow2,le as generateSoloNavMesh,se as generateTileCache,he as generateTiledNavMesh,ee as getBoundingBox,de as mergePositionsAndIndices,ae as soloNavMeshGeneratorConfigDefaults,oe as tileCacheGeneratorConfigDefaults,ne as tiledNavMeshGeneratorConfigDefaults};
2
- //# sourceMappingURL=index.mjs.map
1
+ import { vec3, recastConfigDefaults, Raw, RecastBuildContext, NavMesh, VerticesArray, TrianglesArray, createRcConfig, calcGridSize, allocHeightfield, createHeightfield, TriangleAreasArray, markWalkableTriangles, rasterizeTriangles, filterLowHangingWalkableObstacles, filterLedgeSpans, filterWalkableLowHeightSpans, allocCompactHeightfield, buildCompactHeightfield, freeHeightfield, erodeWalkableArea, buildDistanceField, buildRegions, allocContourSet, buildContours, Recast, allocPolyMesh, buildPolyMesh, allocPolyMeshDetail, buildPolyMeshDetail, freeCompactHeightfield, freeContourSet, NavMeshCreateParams, createNavMeshData, freePolyMesh, freePolyMeshDetail, TileCacheMeshProcess, TileCache, DetourTileCacheParams, NavMeshParams, RecastChunkyTriMesh, statusFailed, freeHeightfieldLayerSet, cloneRcConfig, ChunkIdsArray, allocHeightfieldLayerSet, buildHeightfieldLayers, TileCacheData, Detour, getHeightfieldLayerHeights, getHeightfieldLayerAreas, getHeightfieldLayerCons, buildTileCacheLayer, statusToReadableString } from '@recast-navigation/core';
2
+
3
+ const getBoundingBox = (positions, indices) => {
4
+ const bbMin = {
5
+ x: Infinity,
6
+ y: Infinity,
7
+ z: Infinity
8
+ };
9
+ const bbMax = {
10
+ x: -Infinity,
11
+ y: -Infinity,
12
+ z: -Infinity
13
+ };
14
+ for (let i = 0; i < indices.length; i++) {
15
+ const ind = indices[i];
16
+ const x = positions[ind * 3];
17
+ const y = positions[ind * 3 + 1];
18
+ const z = positions[ind * 3 + 2];
19
+ bbMin.x = Math.min(bbMin.x, x);
20
+ bbMin.y = Math.min(bbMin.y, y);
21
+ bbMin.z = Math.min(bbMin.z, z);
22
+ bbMax.x = Math.max(bbMax.x, x);
23
+ bbMax.y = Math.max(bbMax.y, y);
24
+ bbMax.z = Math.max(bbMax.z, z);
25
+ }
26
+ return {
27
+ bbMin: vec3.toArray(bbMin),
28
+ bbMax: vec3.toArray(bbMax)
29
+ };
30
+ };
31
+ const dtIlog2 = v => {
32
+ let r = 0;
33
+ let shift = 0;
34
+ r = Number(v > 0xffff) << 4;
35
+ v >>= r;
36
+ shift = Number(v > 0xff) << 3;
37
+ v >>= shift;
38
+ r |= shift;
39
+ shift = Number(v > 0xf) << 2;
40
+ v >>= shift;
41
+ r |= shift;
42
+ shift = Number(v > 0x3) << 1;
43
+ v >>= shift;
44
+ r |= shift;
45
+ r |= v >> 1;
46
+ return r;
47
+ };
48
+ const dtNextPow2 = v => {
49
+ v--;
50
+ v |= v >> 1;
51
+ v |= v >> 2;
52
+ v |= v >> 4;
53
+ v |= v >> 8;
54
+ v |= v >> 16;
55
+ v++;
56
+ return v;
57
+ };
58
+
59
+ const soloNavMeshGeneratorConfigDefaults = {
60
+ ...recastConfigDefaults
61
+ };
62
+ /**
63
+ * Builds a Solo NavMesh from the given positions and indices.
64
+ * @param positions a flat array of positions
65
+ * @param indices a flat array of indices
66
+ * @param navMeshGeneratorConfig optional configuration for the NavMesh generator
67
+ * @param keepIntermediates if true intermediates will be returned
68
+ */
69
+ const generateSoloNavMesh = (positions, indices, navMeshGeneratorConfig = {}, keepIntermediates = false) => {
70
+ if (!Raw.Module) {
71
+ throw new Error('"init" must be called before using any recast-navigation-js APIs. See: https://github.com/isaac-mason/recast-navigation-js?tab=readme-ov-file#initialization');
72
+ }
73
+ const buildContext = new RecastBuildContext();
74
+ const intermediates = {
75
+ type: 'solo',
76
+ buildContext
77
+ };
78
+ const navMesh = new NavMesh();
79
+ const cleanup = () => {
80
+ if (keepIntermediates) return;
81
+ if (intermediates.heightfield) {
82
+ freeHeightfield(intermediates.heightfield);
83
+ intermediates.heightfield = undefined;
84
+ }
85
+ if (intermediates.compactHeightfield) {
86
+ freeCompactHeightfield(intermediates.compactHeightfield);
87
+ intermediates.compactHeightfield = undefined;
88
+ }
89
+ if (intermediates.contourSet) {
90
+ freeContourSet(intermediates.contourSet);
91
+ intermediates.contourSet = undefined;
92
+ }
93
+ if (intermediates.polyMesh) {
94
+ freePolyMesh(intermediates.polyMesh);
95
+ intermediates.polyMesh = undefined;
96
+ }
97
+ if (intermediates.polyMeshDetail) {
98
+ freePolyMeshDetail(intermediates.polyMeshDetail);
99
+ intermediates.polyMeshDetail = undefined;
100
+ }
101
+ };
102
+ const fail = error => {
103
+ cleanup();
104
+ navMesh.destroy();
105
+ return {
106
+ navMesh: undefined,
107
+ success: false,
108
+ intermediates,
109
+ error
110
+ };
111
+ };
112
+ /* input geometry */
113
+ const vertices = positions;
114
+ const numVertices = indices.length;
115
+ const verticesArray = new VerticesArray();
116
+ verticesArray.copy(vertices);
117
+ const triangles = indices;
118
+ const numTriangles = indices.length / 3;
119
+ const trianglesArray = new TrianglesArray();
120
+ trianglesArray.copy(triangles);
121
+ const {
122
+ bbMin,
123
+ bbMax
124
+ } = getBoundingBox(positions, indices);
125
+ //
126
+ // Step 1. Initialize build config.
127
+ //
128
+ const config = createRcConfig({
129
+ ...soloNavMeshGeneratorConfigDefaults,
130
+ ...navMeshGeneratorConfig
131
+ });
132
+ config.minRegionArea = config.minRegionArea * config.minRegionArea; // Note: area = size*size
133
+ config.mergeRegionArea = config.mergeRegionArea * config.mergeRegionArea; // Note: area = size*size
134
+ config.detailSampleDist = config.detailSampleDist < 0.9 ? 0 : config.cs * config.detailSampleDist;
135
+ config.detailSampleMaxError = config.ch * config.detailSampleMaxError;
136
+ const gridSize = calcGridSize(bbMin, bbMax, config.cs);
137
+ config.width = gridSize.width;
138
+ config.height = gridSize.height;
139
+ //
140
+ // Step 2. Rasterize input polygon soup.
141
+ //
142
+ // Allocate voxel heightfield where we rasterize our input data to.
143
+ const heightfield = allocHeightfield();
144
+ intermediates.heightfield = heightfield;
145
+ if (!createHeightfield(buildContext, heightfield, config.width, config.height, bbMin, bbMax, config.cs, config.ch)) {
146
+ return fail('Could not create heightfield');
147
+ }
148
+ // Find triangles which are walkable based on their slope and rasterize them.
149
+ // If your input data is multiple meshes, you can transform them here, calculate
150
+ // the are type for each of the meshes and rasterize them.
151
+ const triangleAreasArray = new TriangleAreasArray();
152
+ triangleAreasArray.resize(numTriangles);
153
+ markWalkableTriangles(buildContext, config.walkableSlopeAngle, verticesArray, numVertices, trianglesArray, numTriangles, triangleAreasArray);
154
+ if (!rasterizeTriangles(buildContext, verticesArray, numVertices, trianglesArray, triangleAreasArray, numTriangles, heightfield, config.walkableClimb)) {
155
+ return fail('Could not rasterize triangles');
156
+ }
157
+ triangleAreasArray.destroy();
158
+ verticesArray.destroy();
159
+ trianglesArray.destroy();
160
+ //
161
+ // Step 3. Filter walkables surfaces.
162
+ //
163
+ // Once all geoemtry is rasterized, we do initial pass of filtering to
164
+ // remove unwanted overhangs caused by the conservative rasterization
165
+ // as well as filter spans where the character cannot possibly stand.
166
+ filterLowHangingWalkableObstacles(buildContext, config.walkableClimb, heightfield);
167
+ filterLedgeSpans(buildContext, config.walkableHeight, config.walkableClimb, heightfield);
168
+ filterWalkableLowHeightSpans(buildContext, config.walkableHeight, heightfield);
169
+ //
170
+ // Step 4. Partition walkable surface to simple regions.
171
+ //
172
+ // Compact the heightfield so that it is faster to handle from now on.
173
+ // This will result more cache coherent data as well as the neighbours
174
+ // between walkable cells will be calculated.
175
+ const compactHeightfield = allocCompactHeightfield();
176
+ intermediates.compactHeightfield = compactHeightfield;
177
+ if (!buildCompactHeightfield(buildContext, config.walkableHeight, config.walkableClimb, heightfield, compactHeightfield)) {
178
+ return fail('Failed to build compact data');
179
+ }
180
+ if (!keepIntermediates) {
181
+ freeHeightfield(heightfield);
182
+ intermediates.heightfield = undefined;
183
+ }
184
+ // Erode the walkable area by agent radius.
185
+ if (!erodeWalkableArea(buildContext, config.walkableRadius, compactHeightfield)) {
186
+ return fail('Failed to erode walkable area');
187
+ }
188
+ // (Optional) Mark areas
189
+ // markConvexPolyArea(...)
190
+ // Prepare for region partitioning, by calculating Distance field along the walkable surface.
191
+ if (!buildDistanceField(buildContext, compactHeightfield)) {
192
+ return fail('Failed to build distance field');
193
+ }
194
+ // Partition the walkable surface into simple regions without holes.
195
+ if (!buildRegions(buildContext, compactHeightfield, config.borderSize, config.minRegionArea, config.mergeRegionArea)) {
196
+ return fail('Failed to build regions');
197
+ }
198
+ //
199
+ // Step 5. Trace and simplify region contours.
200
+ //
201
+ const contourSet = allocContourSet();
202
+ intermediates.contourSet = contourSet;
203
+ if (!buildContours(buildContext, compactHeightfield, config.maxSimplificationError, config.maxEdgeLen, contourSet, Recast.RC_CONTOUR_TESS_WALL_EDGES)) {
204
+ return fail('Failed to create contours');
205
+ }
206
+ //
207
+ // Step 6. Build polygons mesh from contours.
208
+ //
209
+ const polyMesh = allocPolyMesh();
210
+ intermediates.polyMesh = polyMesh;
211
+ if (!buildPolyMesh(buildContext, contourSet, config.maxVertsPerPoly, polyMesh)) {
212
+ return fail('Failed to triangulate contours');
213
+ }
214
+ //
215
+ // Step 7. Create detail mesh which allows to access approximate height on each polygon.
216
+ //
217
+ const polyMeshDetail = allocPolyMeshDetail();
218
+ intermediates.polyMeshDetail = polyMeshDetail;
219
+ if (!buildPolyMeshDetail(buildContext, polyMesh, compactHeightfield, config.detailSampleDist, config.detailSampleMaxError, polyMeshDetail)) {
220
+ return fail('Failed to build detail mesh');
221
+ }
222
+ if (!keepIntermediates) {
223
+ freeCompactHeightfield(compactHeightfield);
224
+ intermediates.compactHeightfield = undefined;
225
+ freeContourSet(contourSet);
226
+ intermediates.contourSet = undefined;
227
+ }
228
+ //
229
+ // Step 8. Create Detour data from Recast poly mesh.
230
+ //
231
+ for (let i = 0; i < polyMesh.npolys(); i++) {
232
+ if (polyMesh.areas(i) == Recast.RC_WALKABLE_AREA) {
233
+ polyMesh.setAreas(i, 0);
234
+ }
235
+ if (polyMesh.areas(i) == 0) {
236
+ polyMesh.setFlags(i, 1);
237
+ }
238
+ }
239
+ const navMeshCreateParams = new NavMeshCreateParams();
240
+ navMeshCreateParams.setPolyMeshCreateParams(polyMesh);
241
+ navMeshCreateParams.setPolyMeshDetailCreateParams(polyMeshDetail);
242
+ navMeshCreateParams.setWalkableHeight(config.walkableHeight);
243
+ navMeshCreateParams.setWalkableRadius(config.walkableRadius);
244
+ navMeshCreateParams.setWalkableClimb(config.walkableClimb);
245
+ navMeshCreateParams.setCellSize(config.cs);
246
+ navMeshCreateParams.setCellHeight(config.ch);
247
+ navMeshCreateParams.setBuildBvTree(true);
248
+ if (navMeshGeneratorConfig.offMeshConnections) {
249
+ navMeshCreateParams.setOffMeshConnections(navMeshGeneratorConfig.offMeshConnections);
250
+ }
251
+ const createNavMeshDataResult = createNavMeshData(navMeshCreateParams);
252
+ if (!createNavMeshDataResult.success) {
253
+ return fail('Failed to create Detour navmesh data');
254
+ }
255
+ const {
256
+ navMeshData
257
+ } = createNavMeshDataResult;
258
+ if (!navMesh.initSolo(navMeshData)) {
259
+ return fail('Failed to create Detour navmesh');
260
+ }
261
+ return {
262
+ success: true,
263
+ navMesh,
264
+ intermediates
265
+ };
266
+ };
267
+
268
+ const tileCacheGeneratorConfigDefaults = {
269
+ ...recastConfigDefaults,
270
+ tileSize: 32,
271
+ expectedLayersPerTile: 4,
272
+ maxObstacles: 128
273
+ };
274
+ const createDefaultTileCacheMeshProcess = () => new TileCacheMeshProcess((navMeshCreateParams, polyAreas, polyFlags) => {
275
+ for (let i = 0; i < navMeshCreateParams.polyCount(); ++i) {
276
+ polyAreas.set(i, 0);
277
+ polyFlags.set(i, 1);
278
+ }
279
+ });
280
+ /**
281
+ * Builds a TileCache and NavMesh from the given positions and indices.
282
+ * TileCache assumes small tiles (around 32-64 squared) and does some tricks to make the update fast.
283
+ * @param positions a flat array of positions
284
+ * @param indices a flat array of indices
285
+ * @param navMeshConfig optional configuration for the NavMesh
286
+ * @param keepIntermediates if true intermediates will be returned
287
+ */
288
+ const generateTileCache = (positions, indices, navMeshGeneratorConfig = {}, keepIntermediates = false) => {
289
+ if (!Raw.Module) {
290
+ throw new Error('"init" must be called before using any recast-navigation-js APIs. See: https://github.com/isaac-mason/recast-navigation-js?tab=readme-ov-file#initialization');
291
+ }
292
+ const buildContext = new RecastBuildContext();
293
+ const intermediates = {
294
+ type: 'tilecache',
295
+ buildContext,
296
+ chunkyTriMesh: undefined,
297
+ tileIntermediates: []
298
+ };
299
+ const tileCache = new TileCache();
300
+ const navMesh = new NavMesh();
301
+ /* input geometry */
302
+ const vertices = positions;
303
+ const numVertices = indices.length;
304
+ const verticesArray = new VerticesArray();
305
+ verticesArray.copy(vertices);
306
+ const triangles = indices;
307
+ const numTriangles = indices.length / 3;
308
+ const trianglesArray = new TrianglesArray();
309
+ trianglesArray.copy(triangles);
310
+ const {
311
+ bbMin,
312
+ bbMax
313
+ } = getBoundingBox(positions, indices);
314
+ const {
315
+ expectedLayersPerTile,
316
+ maxObstacles,
317
+ ...recastConfig
318
+ } = {
319
+ ...tileCacheGeneratorConfigDefaults,
320
+ ...navMeshGeneratorConfig
321
+ };
322
+ const cleanup = () => {
323
+ verticesArray.destroy();
324
+ trianglesArray.destroy();
325
+ if (!keepIntermediates) {
326
+ for (let i = 0; i < intermediates.tileIntermediates.length; i++) {
327
+ const tileIntermediate = intermediates.tileIntermediates[i];
328
+ if (tileIntermediate.heightfield) {
329
+ freeHeightfield(tileIntermediate.heightfield);
330
+ tileIntermediate.heightfield = undefined;
331
+ }
332
+ if (tileIntermediate.compactHeightfield) {
333
+ freeCompactHeightfield(tileIntermediate.compactHeightfield);
334
+ tileIntermediate.compactHeightfield = undefined;
335
+ }
336
+ if (tileIntermediate.heightfieldLayerSet) {
337
+ freeHeightfieldLayerSet(tileIntermediate.heightfieldLayerSet);
338
+ tileIntermediate.heightfieldLayerSet = undefined;
339
+ }
340
+ }
341
+ }
342
+ };
343
+ const fail = error => {
344
+ cleanup();
345
+ tileCache.destroy();
346
+ navMesh.destroy();
347
+ return {
348
+ success: false,
349
+ navMesh: undefined,
350
+ tileCache: undefined,
351
+ intermediates,
352
+ error
353
+ };
354
+ };
355
+ //
356
+ // Step 1. Initialize build config.
357
+ //
358
+ const config = createRcConfig(recastConfig);
359
+ const gridSize = calcGridSize(bbMin, bbMax, config.cs);
360
+ config.width = gridSize.width;
361
+ config.height = gridSize.height;
362
+ config.minRegionArea = config.minRegionArea * config.minRegionArea; // Note: area = size*size
363
+ config.mergeRegionArea = config.mergeRegionArea * config.mergeRegionArea; // Note: area = size*size
364
+ config.detailSampleDist = config.detailSampleDist < 0.9 ? 0 : config.cs * config.detailSampleDist;
365
+ config.detailSampleMaxError = config.ch * config.detailSampleMaxError;
366
+ const tileSize = Math.floor(config.tileSize);
367
+ const tileWidth = Math.floor((config.width + tileSize - 1) / tileSize);
368
+ const tileHeight = Math.floor((config.height + tileSize - 1) / tileSize);
369
+ // Generation params
370
+ config.borderSize = config.walkableRadius + 3; // Reserve enough padding.
371
+ config.width = config.tileSize + config.borderSize * 2;
372
+ config.height = config.tileSize + config.borderSize * 2;
373
+ // Tile cache params
374
+ const tileCacheParams = DetourTileCacheParams.create({
375
+ orig: bbMin,
376
+ cs: config.cs,
377
+ ch: config.ch,
378
+ width: config.tileSize,
379
+ height: config.tileSize,
380
+ walkableHeight: config.walkableHeight,
381
+ walkableRadius: config.walkableRadius,
382
+ walkableClimb: config.walkableClimb,
383
+ maxSimplificationError: config.maxSimplificationError,
384
+ maxTiles: tileWidth * tileHeight * expectedLayersPerTile,
385
+ maxObstacles
386
+ });
387
+ const allocator = new Raw.RecastLinearAllocator(32000);
388
+ const compressor = new Raw.RecastFastLZCompressor();
389
+ const tileCacheMeshProcess = navMeshGeneratorConfig.tileCacheMeshProcess ?? createDefaultTileCacheMeshProcess();
390
+ if (!tileCache.init(tileCacheParams, allocator, compressor, tileCacheMeshProcess)) {
391
+ return fail('Failed to initialize tile cache');
392
+ }
393
+ const orig = vec3.fromArray(bbMin);
394
+ // Max tiles and max polys affect how the tile IDs are caculated.
395
+ // There are 22 bits available for identifying a tile and a polygon.
396
+ let tileBits = Math.min(Math.floor(dtIlog2(dtNextPow2(tileWidth * tileHeight * expectedLayersPerTile))), 14);
397
+ if (tileBits > 14) {
398
+ tileBits = 14;
399
+ }
400
+ const polyBits = 22 - tileBits;
401
+ const maxTiles = 1 << tileBits;
402
+ const maxPolysPerTile = 1 << polyBits;
403
+ const navMeshParams = NavMeshParams.create({
404
+ orig,
405
+ tileWidth: config.tileSize * config.cs,
406
+ tileHeight: config.tileSize * config.cs,
407
+ maxTiles,
408
+ maxPolys: maxPolysPerTile
409
+ });
410
+ if (!navMesh.initTiled(navMeshParams)) {
411
+ return fail('Failed to initialize tiled navmesh');
412
+ }
413
+ const chunkyTriMesh = new RecastChunkyTriMesh();
414
+ intermediates.chunkyTriMesh = chunkyTriMesh;
415
+ if (!chunkyTriMesh.init(verticesArray, trianglesArray, numTriangles, 256)) {
416
+ return fail('Failed to build chunky triangle mesh');
417
+ }
418
+ const rasterizeTileLayers = (tileX, tileY) => {
419
+ // Tile intermediates
420
+ const tileIntermediates = {
421
+ tileX,
422
+ tileY
423
+ };
424
+ // Tile bounds
425
+ const tcs = config.tileSize * config.cs;
426
+ const tileConfig = cloneRcConfig(config);
427
+ const tileBoundsMin = [bbMin[0] + tileX * tcs, bbMin[1], bbMin[2] + tileY * tcs];
428
+ const tileBoundsMax = [bbMin[0] + (tileX + 1) * tcs, bbMax[1], bbMin[2] + (tileY + 1) * tcs];
429
+ tileBoundsMin[0] -= tileConfig.borderSize * tileConfig.cs;
430
+ tileBoundsMin[2] -= tileConfig.borderSize * tileConfig.cs;
431
+ tileBoundsMax[0] += tileConfig.borderSize * tileConfig.cs;
432
+ tileBoundsMax[2] += tileConfig.borderSize * tileConfig.cs;
433
+ tileConfig.set_bmin(0, tileBoundsMin[0]);
434
+ tileConfig.set_bmin(1, tileBoundsMin[1]);
435
+ tileConfig.set_bmin(2, tileBoundsMin[2]);
436
+ tileConfig.set_bmax(0, tileBoundsMax[0]);
437
+ tileConfig.set_bmax(1, tileBoundsMax[1]);
438
+ tileConfig.set_bmax(2, tileBoundsMax[2]);
439
+ // Allocate voxel heightfield where we rasterize our input data to.
440
+ const heightfield = allocHeightfield();
441
+ tileIntermediates.heightfield = heightfield;
442
+ if (!createHeightfield(buildContext, heightfield, tileConfig.width, tileConfig.height, tileBoundsMin, tileBoundsMax, tileConfig.cs, tileConfig.ch)) {
443
+ return {
444
+ n: 0
445
+ };
446
+ }
447
+ const tbmin = [tileBoundsMin[0], tileBoundsMin[2]];
448
+ const tbmax = [tileBoundsMax[0], tileBoundsMax[2]];
449
+ // TODO: Make grow when returning too many items.
450
+ const maxChunkIds = 512;
451
+ const chunkIdsArray = new ChunkIdsArray();
452
+ chunkIdsArray.resize(maxChunkIds);
453
+ const nChunksOverlapping = chunkyTriMesh.getChunksOverlappingRect(tbmin, tbmax, chunkIdsArray, maxChunkIds);
454
+ if (nChunksOverlapping === 0) {
455
+ return {
456
+ n: 0
457
+ };
458
+ }
459
+ for (let i = 0; i < nChunksOverlapping; ++i) {
460
+ const nodeId = chunkIdsArray.get(i);
461
+ const node = chunkyTriMesh.nodes(nodeId);
462
+ const nNodeTris = node.n;
463
+ const nodeTrianglesArray = chunkyTriMesh.getNodeTris(nodeId);
464
+ const triangleAreasArray = new TriangleAreasArray();
465
+ triangleAreasArray.resize(nNodeTris);
466
+ // Find triangles which are walkable based on their slope and rasterize them.
467
+ // If your input data is multiple meshes, you can transform them here, calculate
468
+ // the are type for each of the meshes and rasterize them.
469
+ markWalkableTriangles(buildContext, tileConfig.walkableSlopeAngle, verticesArray, numVertices, nodeTrianglesArray, nNodeTris, triangleAreasArray);
470
+ const success = rasterizeTriangles(buildContext, verticesArray, numVertices, nodeTrianglesArray, triangleAreasArray, nNodeTris, heightfield, tileConfig.walkableClimb);
471
+ triangleAreasArray.destroy();
472
+ if (!success) {
473
+ return {
474
+ n: 0
475
+ };
476
+ }
477
+ }
478
+ // Once all geometry is rasterized, we do initial pass of filtering to
479
+ // remove unwanted overhangs caused by the conservative rasterization
480
+ // as well as filter spans where the character cannot possibly stand.
481
+ filterLowHangingWalkableObstacles(buildContext, config.walkableClimb, heightfield);
482
+ filterLedgeSpans(buildContext, config.walkableHeight, config.walkableClimb, heightfield);
483
+ filterWalkableLowHeightSpans(buildContext, config.walkableHeight, heightfield);
484
+ const compactHeightfield = allocCompactHeightfield();
485
+ if (!buildCompactHeightfield(buildContext, config.walkableHeight, config.walkableClimb, heightfield, compactHeightfield)) {
486
+ return {
487
+ n: 0
488
+ };
489
+ }
490
+ if (!keepIntermediates) {
491
+ freeHeightfield(tileIntermediates.heightfield);
492
+ tileIntermediates.heightfield = undefined;
493
+ }
494
+ // Erode the walkable area by agent radius
495
+ if (!erodeWalkableArea(buildContext, config.walkableRadius, compactHeightfield)) {
496
+ return {
497
+ n: 0
498
+ };
499
+ }
500
+ const heightfieldLayerSet = allocHeightfieldLayerSet();
501
+ if (!buildHeightfieldLayers(buildContext, compactHeightfield, config.borderSize, config.walkableHeight, heightfieldLayerSet)) {
502
+ return {
503
+ n: 0
504
+ };
505
+ }
506
+ if (!keepIntermediates) {
507
+ freeCompactHeightfield(compactHeightfield);
508
+ tileIntermediates.compactHeightfield = undefined;
509
+ }
510
+ const tiles = [];
511
+ for (let i = 0; i < heightfieldLayerSet.nlayers(); i++) {
512
+ const tile = new TileCacheData();
513
+ const heightfieldLayer = heightfieldLayerSet.layers(i);
514
+ // Store header
515
+ const header = new Raw.dtTileCacheLayerHeader();
516
+ header.magic = Detour.DT_TILECACHE_MAGIC;
517
+ header.version = Detour.DT_TILECACHE_VERSION;
518
+ // Tile layer location in the navmesh
519
+ header.tx = tileX;
520
+ header.ty = tileY;
521
+ header.tlayer = i;
522
+ const heightfieldLayerBin = heightfieldLayer.bmin();
523
+ const heightfieldLayerBmax = heightfieldLayer.bmax();
524
+ header.set_bmin(0, heightfieldLayerBin.x);
525
+ header.set_bmin(1, heightfieldLayerBin.y);
526
+ header.set_bmin(2, heightfieldLayerBin.z);
527
+ header.set_bmax(0, heightfieldLayerBmax.x);
528
+ header.set_bmax(1, heightfieldLayerBmax.y);
529
+ header.set_bmax(2, heightfieldLayerBmax.z);
530
+ // Tile info
531
+ header.width = heightfieldLayer.width();
532
+ header.height = heightfieldLayer.height();
533
+ header.minx = heightfieldLayer.minx();
534
+ header.maxx = heightfieldLayer.maxx();
535
+ header.miny = heightfieldLayer.miny();
536
+ header.maxy = heightfieldLayer.maxy();
537
+ header.hmin = heightfieldLayer.hmin();
538
+ header.hmax = heightfieldLayer.hmax();
539
+ const heights = getHeightfieldLayerHeights(heightfieldLayer);
540
+ const areas = getHeightfieldLayerAreas(heightfieldLayer);
541
+ const cons = getHeightfieldLayerCons(heightfieldLayer);
542
+ const status = buildTileCacheLayer(compressor, header, heights, areas, cons, tile);
543
+ if (statusFailed(status)) {
544
+ return {
545
+ n: 0
546
+ };
547
+ }
548
+ tiles.push(tile);
549
+ }
550
+ if (!keepIntermediates) {
551
+ freeHeightfieldLayerSet(heightfieldLayerSet);
552
+ tileIntermediates.heightfieldLayerSet = undefined;
553
+ }
554
+ intermediates.tileIntermediates.push(tileIntermediates);
555
+ return {
556
+ n: tiles.length,
557
+ tiles
558
+ };
559
+ };
560
+ // Preprocess tiles
561
+ for (let y = 0; y < tileHeight; ++y) {
562
+ for (let x = 0; x < tileWidth; ++x) {
563
+ const {
564
+ n,
565
+ tiles: newTiles
566
+ } = rasterizeTileLayers(x, y);
567
+ if (n > 0 && newTiles) {
568
+ for (let i = 0; i < n; i++) {
569
+ const tileCacheData = newTiles[i];
570
+ const addResult = tileCache.addTile(tileCacheData);
571
+ if (statusFailed(addResult.status)) {
572
+ buildContext.log(Recast.RC_LOG_WARNING, `Failed to add tile to tile cache - tx: ${x}, ty: ${y}`);
573
+ continue;
574
+ }
575
+ }
576
+ }
577
+ }
578
+ }
579
+ // Build initial meshes
580
+ for (let y = 0; y < tileHeight; y++) {
581
+ for (let x = 0; x < tileWidth; x++) {
582
+ const dtStatus = tileCache.buildNavMeshTilesAt(x, y, navMesh);
583
+ if (statusFailed(dtStatus)) {
584
+ return fail(`Failed to build nav mesh tiles at ${x}, ${y}`);
585
+ }
586
+ }
587
+ }
588
+ cleanup();
589
+ return {
590
+ success: true,
591
+ tileCache,
592
+ navMesh,
593
+ intermediates
594
+ };
595
+ };
596
+
597
+ const tiledNavMeshGeneratorConfigDefaults = {
598
+ ...recastConfigDefaults
599
+ };
600
+ /**
601
+ * Builds a Tiled NavMesh
602
+ * @param positions a flat array of positions
603
+ * @param indices a flat array of indices
604
+ * @param navMeshGeneratorConfig optional configuration for the NavMesh generator
605
+ * @param keepIntermediates if true intermediates will be returned
606
+ */
607
+ const generateTiledNavMesh = (positions, indices, navMeshGeneratorConfig = {}, keepIntermediates = false) => {
608
+ if (!Raw.Module) {
609
+ throw new Error('"init" must be called before using any recast-navigation-js APIs. See: https://github.com/isaac-mason/recast-navigation-js?tab=readme-ov-file#initialization');
610
+ }
611
+ const buildContext = new RecastBuildContext();
612
+ const intermediates = {
613
+ type: 'tiled',
614
+ buildContext,
615
+ chunkyTriMesh: undefined,
616
+ tileIntermediates: []
617
+ };
618
+ const navMesh = new NavMesh();
619
+ /* input geometry */
620
+ const vertices = positions;
621
+ const numVertices = indices.length;
622
+ const verticesArray = new VerticesArray();
623
+ verticesArray.copy(vertices);
624
+ const triangles = indices;
625
+ const numTriangles = indices.length / 3;
626
+ const trianglesArray = new TrianglesArray();
627
+ trianglesArray.copy(triangles);
628
+ const cleanup = () => {
629
+ verticesArray.destroy();
630
+ trianglesArray.destroy();
631
+ if (keepIntermediates) return;
632
+ for (let i = 0; i < intermediates.tileIntermediates.length; i++) {
633
+ const tileIntermediate = intermediates.tileIntermediates[i];
634
+ if (tileIntermediate.compactHeightfield) {
635
+ freeCompactHeightfield(tileIntermediate.compactHeightfield);
636
+ tileIntermediate.compactHeightfield = undefined;
637
+ }
638
+ if (tileIntermediate.heightfield) {
639
+ freeHeightfield(tileIntermediate.heightfield);
640
+ tileIntermediate.heightfield = undefined;
641
+ }
642
+ if (tileIntermediate.contourSet) {
643
+ freeContourSet(tileIntermediate.contourSet);
644
+ tileIntermediate.contourSet = undefined;
645
+ }
646
+ if (tileIntermediate.polyMesh) {
647
+ freePolyMesh(tileIntermediate.polyMesh);
648
+ tileIntermediate.polyMesh = undefined;
649
+ }
650
+ if (tileIntermediate.polyMeshDetail) {
651
+ freePolyMeshDetail(tileIntermediate.polyMeshDetail);
652
+ tileIntermediate.polyMeshDetail = undefined;
653
+ }
654
+ }
655
+ if (intermediates.chunkyTriMesh) {
656
+ intermediates.chunkyTriMesh = undefined;
657
+ }
658
+ };
659
+ const fail = error => {
660
+ cleanup();
661
+ navMesh.destroy();
662
+ return {
663
+ success: false,
664
+ navMesh: undefined,
665
+ intermediates,
666
+ error
667
+ };
668
+ };
669
+ //
670
+ // Initialize build config.
671
+ //
672
+ const config = createRcConfig({
673
+ ...tiledNavMeshGeneratorConfigDefaults,
674
+ ...navMeshGeneratorConfig
675
+ });
676
+ /* get input bounding box */
677
+ const {
678
+ bbMin,
679
+ bbMax
680
+ } = getBoundingBox(positions, indices);
681
+ /* grid size */
682
+ const gridSize = calcGridSize(bbMin, bbMax, config.cs);
683
+ config.width = gridSize.width;
684
+ config.height = gridSize.height;
685
+ config.minRegionArea = config.minRegionArea * config.minRegionArea; // Note: area = size*size
686
+ config.mergeRegionArea = config.mergeRegionArea * config.mergeRegionArea; // Note: area = size*size
687
+ config.tileSize = Math.floor(config.tileSize);
688
+ config.borderSize = config.walkableRadius + 3; // Reserve enough padding.
689
+ config.width = config.tileSize + config.borderSize * 2;
690
+ config.height = config.tileSize + config.borderSize * 2;
691
+ config.detailSampleDist = config.detailSampleDist < 0.9 ? 0 : config.cs * config.detailSampleDist;
692
+ config.detailSampleMaxError = config.ch * config.detailSampleMaxError;
693
+ // tile size
694
+ const tileSize = Math.floor(config.tileSize);
695
+ const tileWidth = Math.floor((gridSize.width + tileSize - 1) / tileSize);
696
+ const tileHeight = Math.floor((gridSize.height + tileSize - 1) / tileSize);
697
+ const tcs = config.tileSize * config.cs;
698
+ /* Create dtNavMeshParams, initialise nav mesh for tiled use */
699
+ const orig = vec3.fromArray(bbMin);
700
+ // Max tiles and max polys affect how the tile IDs are caculated.
701
+ // There are 22 bits available for identifying a tile and a polygon.
702
+ let tileBits = Math.min(Math.floor(dtIlog2(dtNextPow2(tileWidth * tileHeight))), 14);
703
+ if (tileBits > 14) tileBits = 14;
704
+ const polyBits = 22 - tileBits;
705
+ const maxTiles = 1 << tileBits;
706
+ const maxPolysPerTile = 1 << polyBits;
707
+ const navMeshParams = NavMeshParams.create({
708
+ orig,
709
+ tileWidth: config.tileSize * config.cs,
710
+ tileHeight: config.tileSize * config.cs,
711
+ maxTiles,
712
+ maxPolys: maxPolysPerTile
713
+ });
714
+ if (!navMesh.initTiled(navMeshParams)) {
715
+ return fail('Could not init nav mesh for tiled use');
716
+ }
717
+ /* create chunky tri mesh */
718
+ const chunkyTriMesh = new RecastChunkyTriMesh();
719
+ intermediates.chunkyTriMesh = chunkyTriMesh;
720
+ if (!chunkyTriMesh.init(verticesArray, trianglesArray, numTriangles, 256)) {
721
+ return fail('Failed to build chunky triangle mesh');
722
+ }
723
+ /** @internal */
724
+ const buildTileMesh = (tileX, tileY, tileBoundsMin, tileBoundsMax) => {
725
+ const failTileMesh = error => {
726
+ buildContext.log(Recast.RC_LOG_ERROR, error);
727
+ return {
728
+ success: false,
729
+ error
730
+ };
731
+ };
732
+ const tileIntermediate = {
733
+ tileX,
734
+ tileY
735
+ };
736
+ intermediates.tileIntermediates.push(tileIntermediate);
737
+ const tileConfig = cloneRcConfig(config);
738
+ // Expand the heightfield bounding box by border size to find the extents of geometry we need to build this tile.
739
+ //
740
+ // This is done in order to make sure that the navmesh tiles connect correctly at the borders,
741
+ // and the obstacles close to the border work correctly with the dilation process.
742
+ // No polygons (or contours) will be created on the border area.
743
+ //
744
+ // IMPORTANT!
745
+ //
746
+ // :''''''''':
747
+ // : +-----+ :
748
+ // : | | :
749
+ // : | |<--- tile to build
750
+ // : | | :
751
+ // : +-----+ :<-- geometry needed
752
+ // :.........:
753
+ //
754
+ // You should use this bounding box to query your input geometry.
755
+ //
756
+ // For example if you build a navmesh for terrain, and want the navmesh tiles to match the terrain tile size
757
+ // you will need to pass in data from neighbour terrain tiles too! In a simple case, just pass in all the 8 neighbours,
758
+ // or use the bounding box below to only pass in a sliver of each of the 8 neighbours.
759
+ const expandedTileBoundsMin = [...tileBoundsMin];
760
+ const expandedTileBoundsMax = [...tileBoundsMax];
761
+ expandedTileBoundsMin[0] -= tileConfig.borderSize * tileConfig.cs;
762
+ expandedTileBoundsMin[2] -= tileConfig.borderSize * tileConfig.cs;
763
+ expandedTileBoundsMax[0] += tileConfig.borderSize * tileConfig.cs;
764
+ expandedTileBoundsMax[2] += tileConfig.borderSize * tileConfig.cs;
765
+ tileConfig.set_bmin(0, expandedTileBoundsMin[0]);
766
+ tileConfig.set_bmin(1, expandedTileBoundsMin[1]);
767
+ tileConfig.set_bmin(2, expandedTileBoundsMin[2]);
768
+ tileConfig.set_bmax(0, expandedTileBoundsMax[0]);
769
+ tileConfig.set_bmax(1, expandedTileBoundsMax[1]);
770
+ tileConfig.set_bmax(2, expandedTileBoundsMax[2]);
771
+ // Reset build timer
772
+ buildContext.resetTimers();
773
+ // Start the build process
774
+ buildContext.startTimer(Recast.RC_TIMER_TOTAL);
775
+ buildContext.log(Recast.RC_LOG_PROGRESS, `Building tile ${intermediates.tileIntermediates.length} at x: ${tileX}, y: ${tileY}`);
776
+ buildContext.log(Recast.RC_LOG_PROGRESS, ` - ${config.width} x ${config.height} cells`);
777
+ buildContext.log(Recast.RC_LOG_PROGRESS, ` - ${numVertices / 1000}fK verts, ${numTriangles / 1000}K tris`);
778
+ // Allocate voxel heightfield where we rasterize our input data to.
779
+ const heightfield = allocHeightfield();
780
+ tileIntermediate.heightfield = heightfield;
781
+ if (!createHeightfield(buildContext, heightfield, tileConfig.width, tileConfig.height, expandedTileBoundsMin, expandedTileBoundsMax, tileConfig.cs, tileConfig.ch)) {
782
+ return failTileMesh('Could not create heightfield');
783
+ }
784
+ // Allocate array that can hold triangle flags.
785
+ // If you have multiple meshes you need to process, allocate
786
+ // and array which can hold the max number of triangles you need to process.
787
+ const triAreas = new TriangleAreasArray();
788
+ triAreas.resize(chunkyTriMesh.maxTrisPerChunk());
789
+ const tbmin = [expandedTileBoundsMin[0], expandedTileBoundsMin[2]];
790
+ const tbmax = [expandedTileBoundsMax[0], expandedTileBoundsMax[2]];
791
+ // TODO: Make grow when returning too many items.
792
+ const maxChunkIds = 512;
793
+ const chunkIdsArray = new ChunkIdsArray();
794
+ chunkIdsArray.resize(maxChunkIds);
795
+ const nChunksOverlapping = chunkyTriMesh.getChunksOverlappingRect(tbmin, tbmax, chunkIdsArray, maxChunkIds);
796
+ if (nChunksOverlapping === 0) {
797
+ return {
798
+ success: true
799
+ };
800
+ }
801
+ for (let i = 0; i < nChunksOverlapping; ++i) {
802
+ const nodeId = chunkIdsArray.get(i);
803
+ const node = chunkyTriMesh.nodes(nodeId);
804
+ const nNodeTris = node.n;
805
+ const nodeTrianglesArray = chunkyTriMesh.getNodeTris(nodeId);
806
+ const triangleAreasArray = new TriangleAreasArray();
807
+ triangleAreasArray.resize(nNodeTris);
808
+ // Find triangles which are walkable based on their slope and rasterize them.
809
+ // If your input data is multiple meshes, you can transform them here, calculate
810
+ // the are type for each of the meshes and rasterize them.
811
+ markWalkableTriangles(buildContext, tileConfig.walkableSlopeAngle, verticesArray, numVertices, nodeTrianglesArray, nNodeTris, triangleAreasArray);
812
+ const success = rasterizeTriangles(buildContext, verticesArray, numVertices, nodeTrianglesArray, triangleAreasArray, nNodeTris, heightfield, tileConfig.walkableClimb);
813
+ triangleAreasArray.destroy();
814
+ if (!success) {
815
+ return failTileMesh('Could not rasterize triangles');
816
+ }
817
+ }
818
+ // Once all geometry is rasterized, we do initial pass of filtering to
819
+ // remove unwanted overhangs caused by the conservative rasterization
820
+ // as well as filter spans where the character cannot possibly stand.
821
+ filterLowHangingWalkableObstacles(buildContext, tileConfig.walkableClimb, heightfield);
822
+ filterLedgeSpans(buildContext, tileConfig.walkableHeight, tileConfig.walkableClimb, heightfield);
823
+ filterWalkableLowHeightSpans(buildContext, tileConfig.walkableHeight, heightfield);
824
+ // Compact the heightfield so that it is faster to handle from now on.
825
+ // This will result more cache coherent data as well as the neighbours
826
+ // between walkable cells will be calculated.
827
+ const compactHeightfield = allocCompactHeightfield();
828
+ tileIntermediate.compactHeightfield = compactHeightfield;
829
+ if (!buildCompactHeightfield(buildContext, tileConfig.walkableHeight, tileConfig.walkableClimb, heightfield, compactHeightfield)) {
830
+ return failTileMesh('Could not build compact heightfield');
831
+ }
832
+ if (!keepIntermediates) {
833
+ freeHeightfield(tileIntermediate.heightfield);
834
+ tileIntermediate.heightfield = undefined;
835
+ }
836
+ // Erode the walkable area by agent radius
837
+ if (!erodeWalkableArea(buildContext, tileConfig.walkableRadius, compactHeightfield)) {
838
+ return failTileMesh('Could not erode walkable area');
839
+ }
840
+ // (Optional) Mark areas
841
+ // markConvexPolyArea(...)
842
+ // Prepare for region partitioning, by calculating Distance field along the walkable surface.
843
+ if (!buildDistanceField(buildContext, compactHeightfield)) {
844
+ return failTileMesh('Failed to build distance field');
845
+ }
846
+ // Partition the walkable surface into simple regions without holes.
847
+ if (!buildRegions(buildContext, compactHeightfield, tileConfig.borderSize, tileConfig.minRegionArea, tileConfig.mergeRegionArea)) {
848
+ return failTileMesh('Failed to build regions');
849
+ }
850
+ //
851
+ // Trace and simplify region contours.
852
+ //
853
+ const contourSet = allocContourSet();
854
+ tileIntermediate.contourSet = contourSet;
855
+ if (!buildContours(buildContext, compactHeightfield, tileConfig.maxSimplificationError, tileConfig.maxEdgeLen, contourSet, Recast.RC_CONTOUR_TESS_WALL_EDGES)) {
856
+ return failTileMesh('Failed to create contours');
857
+ }
858
+ //
859
+ // Build polygons mesh from contours.
860
+ //
861
+ const polyMesh = allocPolyMesh();
862
+ tileIntermediate.polyMesh = polyMesh;
863
+ if (!buildPolyMesh(buildContext, contourSet, tileConfig.maxVertsPerPoly, polyMesh)) {
864
+ return failTileMesh('Failed to triangulate contours');
865
+ }
866
+ //
867
+ // Create detail mesh which allows to access approximate height on each polygon.
868
+ //
869
+ const polyMeshDetail = allocPolyMeshDetail();
870
+ tileIntermediate.polyMeshDetail = polyMeshDetail;
871
+ if (!buildPolyMeshDetail(buildContext, polyMesh, compactHeightfield, tileConfig.detailSampleDist, tileConfig.detailSampleMaxError, polyMeshDetail)) {
872
+ return failTileMesh('Failed to build detail mesh');
873
+ }
874
+ if (!keepIntermediates) {
875
+ freeCompactHeightfield(compactHeightfield);
876
+ tileIntermediate.compactHeightfield = undefined;
877
+ freeContourSet(contourSet);
878
+ tileIntermediate.contourSet = undefined;
879
+ }
880
+ // Update poly flags from areas.
881
+ for (let i = 0; i < polyMesh.npolys(); i++) {
882
+ if (polyMesh.areas(i) == Recast.RC_WALKABLE_AREA) {
883
+ polyMesh.setAreas(i, 0);
884
+ }
885
+ if (polyMesh.areas(i) == 0) {
886
+ polyMesh.setFlags(i, 1);
887
+ }
888
+ }
889
+ const navMeshCreateParams = new NavMeshCreateParams();
890
+ navMeshCreateParams.setPolyMeshCreateParams(polyMesh);
891
+ navMeshCreateParams.setPolyMeshDetailCreateParams(polyMeshDetail);
892
+ navMeshCreateParams.setWalkableHeight(tileConfig.walkableHeight);
893
+ navMeshCreateParams.setWalkableRadius(tileConfig.walkableRadius);
894
+ navMeshCreateParams.setWalkableClimb(tileConfig.walkableClimb);
895
+ navMeshCreateParams.setCellSize(tileConfig.cs);
896
+ navMeshCreateParams.setCellHeight(tileConfig.ch);
897
+ navMeshCreateParams.setBuildBvTree(true);
898
+ if (navMeshGeneratorConfig.offMeshConnections) {
899
+ navMeshCreateParams.setOffMeshConnections(navMeshGeneratorConfig.offMeshConnections);
900
+ }
901
+ navMeshCreateParams.setTileX(tileX);
902
+ navMeshCreateParams.setTileY(tileY);
903
+ const createNavMeshDataResult = createNavMeshData(navMeshCreateParams);
904
+ if (!createNavMeshDataResult.success) {
905
+ return failTileMesh('Failed to create Detour navmesh data');
906
+ }
907
+ buildContext.log(Recast.RC_LOG_PROGRESS, `>> Polymesh: ${polyMesh.nverts()} vertices ${polyMesh.npolys()} polygons`);
908
+ return {
909
+ success: true,
910
+ data: createNavMeshDataResult.navMeshData
911
+ };
912
+ };
913
+ buildContext.startTimer(Recast.RC_TIMER_TEMP);
914
+ const lastBuiltTileBmin = [0, 0, 0];
915
+ const lastBuiltTileBmax = [0, 0, 0];
916
+ for (let y = 0; y < tileHeight; y++) {
917
+ for (let x = 0; x < tileWidth; x++) {
918
+ lastBuiltTileBmin[0] = bbMin[0] + x * tcs;
919
+ lastBuiltTileBmin[1] = bbMin[1];
920
+ lastBuiltTileBmin[2] = bbMin[2] + y * tcs;
921
+ lastBuiltTileBmax[0] = bbMin[0] + (x + 1) * tcs;
922
+ lastBuiltTileBmax[1] = bbMax[1];
923
+ lastBuiltTileBmax[2] = bbMin[2] + (y + 1) * tcs;
924
+ const result = buildTileMesh(x, y, lastBuiltTileBmin, lastBuiltTileBmax);
925
+ if (result.success && result.data) {
926
+ navMesh.removeTile(navMesh.getTileRefAt(x, y, 0));
927
+ const addTileResult = navMesh.addTile(result.data, Detour.DT_TILE_FREE_DATA, 0);
928
+ if (statusFailed(addTileResult.status)) {
929
+ buildContext.log(Recast.RC_LOG_WARNING, `Failed to add tile to nav mesh` + '\n\t' + `tx: ${x}, ty: ${y},` + `status: ${statusToReadableString(addTileResult.status)} (${addTileResult.status})`);
930
+ result.data.destroy();
931
+ }
932
+ }
933
+ }
934
+ }
935
+ buildContext.stopTimer(Recast.RC_TIMER_TEMP);
936
+ if (!keepIntermediates) {
937
+ cleanup();
938
+ }
939
+ return {
940
+ success: true,
941
+ navMesh,
942
+ intermediates
943
+ };
944
+ };
945
+
946
+ const mergePositionsAndIndices = meshes => {
947
+ const mergedPositions = [];
948
+ const mergedIndices = [];
949
+ const positionToIndex = {};
950
+ let indexCounter = 0;
951
+ for (const {
952
+ positions,
953
+ indices
954
+ } of meshes) {
955
+ for (let i = 0; i < indices.length; i++) {
956
+ const pt = indices[i] * 3;
957
+ const x = positions[pt];
958
+ const y = positions[pt + 1];
959
+ const z = positions[pt + 2];
960
+ const key = `${x}_${y}_${z}`;
961
+ let idx = positionToIndex[key];
962
+ if (!idx) {
963
+ positionToIndex[key] = idx = indexCounter;
964
+ mergedPositions.push(x, y, z);
965
+ indexCounter++;
966
+ }
967
+ mergedIndices.push(idx);
968
+ }
969
+ }
970
+ return [Float32Array.from(mergedPositions), Uint32Array.from(mergedIndices)];
971
+ };
972
+
973
+ export { createDefaultTileCacheMeshProcess, dtIlog2, dtNextPow2, generateSoloNavMesh, generateTileCache, generateTiledNavMesh, getBoundingBox, mergePositionsAndIndices, soloNavMeshGeneratorConfigDefaults, tileCacheGeneratorConfigDefaults, tiledNavMeshGeneratorConfigDefaults };
package/package.json CHANGED
@@ -6,7 +6,7 @@
6
6
  "email": "isaac@isaacmason.com",
7
7
  "url": "https://isaacmason.com/"
8
8
  },
9
- "version": "0.35.0",
9
+ "version": "0.35.2",
10
10
  "license": "MIT",
11
11
  "homepage": "https://github.com/isaac-mason/recast-navigation-js",
12
12
  "bugs": {
@@ -27,8 +27,8 @@
27
27
  "lint": "eslint src"
28
28
  },
29
29
  "dependencies": {
30
- "@recast-navigation/core": "0.35.0",
31
- "@recast-navigation/wasm": "0.35.0"
30
+ "@recast-navigation/core": "0.35.2",
31
+ "@recast-navigation/wasm": "0.35.2"
32
32
  },
33
33
  "devDependencies": {
34
34
  "@babel/core": "^7.24.5",
@@ -38,7 +38,6 @@
38
38
  "@rollup/plugin-babel": "^6.0.4",
39
39
  "@rollup/plugin-commonjs": "^25.0.7",
40
40
  "@rollup/plugin-node-resolve": "^15.0.1",
41
- "@rollup/plugin-terser": "^0.4.3",
42
41
  "@rollup/plugin-typescript": "^11.1.6",
43
42
  "eslint": "^9.6.0",
44
43
  "prettier": "^3.1.0",
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.mjs","sources":["../src/generators/common.ts","../src/generators/generate-solo-nav-mesh.ts","../src/generators/generate-tile-cache.ts","../src/generators/generate-tiled-nav-mesh.ts","../src/generators/merge-positions-and-indices.ts"],"sourcesContent":[null,null,null,null,null],"names":["getBoundingBox","positions","indices","bbMin","x","Infinity","y","z","bbMax","i","length","ind","Math","min","max","vec3","toArray","dtIlog2","v","r","shift","Number","dtNextPow2","soloNavMeshGeneratorConfigDefaults","recastConfigDefaults","generateSoloNavMesh","navMeshGeneratorConfig","keepIntermediates","Raw","Module","Error","buildContext","RecastBuildContext","intermediates","type","navMesh","NavMesh","fail","error","heightfield","freeHeightfield","undefined","compactHeightfield","freeCompactHeightfield","contourSet","freeContourSet","polyMesh","freePolyMesh","polyMeshDetail","freePolyMeshDetail","destroy","success","vertices","numVertices","verticesArray","VerticesArray","copy","triangles","numTriangles","trianglesArray","TrianglesArray","config","createRcConfig","minRegionArea","mergeRegionArea","detailSampleDist","cs","detailSampleMaxError","ch","gridSize","calcGridSize","width","height","allocHeightfield","createHeightfield","triangleAreasArray","TriangleAreasArray","resize","markWalkableTriangles","walkableSlopeAngle","rasterizeTriangles","walkableClimb","filterLowHangingWalkableObstacles","filterLedgeSpans","walkableHeight","filterWalkableLowHeightSpans","allocCompactHeightfield","buildCompactHeightfield","erodeWalkableArea","walkableRadius","buildDistanceField","buildRegions","borderSize","allocContourSet","buildContours","maxSimplificationError","maxEdgeLen","Recast","RC_CONTOUR_TESS_WALL_EDGES","allocPolyMesh","buildPolyMesh","maxVertsPerPoly","allocPolyMeshDetail","buildPolyMeshDetail","npolys","areas","RC_WALKABLE_AREA","setAreas","setFlags","navMeshCreateParams","NavMeshCreateParams","setPolyMeshCreateParams","setPolyMeshDetailCreateParams","setWalkableHeight","setWalkableRadius","setWalkableClimb","setCellSize","setCellHeight","setBuildBvTree","offMeshConnections","setOffMeshConnections","createNavMeshDataResult","createNavMeshData","navMeshData","initSolo","tileCacheGeneratorConfigDefaults","tileSize","expectedLayersPerTile","maxObstacles","createDefaultTileCacheMeshProcess","TileCacheMeshProcess","polyAreas","polyFlags","polyCount","set","generateTileCache","chunkyTriMesh","tileIntermediates","tileCache","TileCache","recastConfig","cleanup","tileIntermediate","heightfieldLayerSet","freeHeightfieldLayerSet","floor","tileWidth","tileHeight","tileCacheParams","DetourTileCacheParams","create","orig","maxTiles","allocator","RecastLinearAllocator","compressor","RecastFastLZCompressor","tileCacheMeshProcess","init","fromArray","tileBits","maxPolysPerTile","navMeshParams","NavMeshParams","maxPolys","initTiled","RecastChunkyTriMesh","rasterizeTileLayers","tileX","tileY","tcs","tileConfig","cloneRcConfig","tileBoundsMin","tileBoundsMax","set_bmin","set_bmax","n","tbmin","tbmax","chunkIdsArray","ChunkIdsArray","nChunksOverlapping","getChunksOverlappingRect","nodeId","get","nNodeTris","nodes","nodeTrianglesArray","getNodeTris","allocHeightfieldLayerSet","buildHeightfieldLayers","tiles","nlayers","tile","TileCacheData","heightfieldLayer","layers","header","dtTileCacheLayerHeader","magic","Detour","DT_TILECACHE_MAGIC","version","DT_TILECACHE_VERSION","tx","ty","tlayer","heightfieldLayerBin","bmin","heightfieldLayerBmax","bmax","minx","maxx","miny","maxy","hmin","hmax","heights","getHeightfieldLayerHeights","getHeightfieldLayerAreas","cons","getHeightfieldLayerCons","status","buildTileCacheLayer","statusFailed","push","newTiles","tileCacheData","addResult","addTile","log","RC_LOG_WARNING","dtStatus","buildNavMeshTilesAt","tiledNavMeshGeneratorConfigDefaults","generateTiledNavMesh","buildTileMesh","failTileMesh","RC_LOG_ERROR","expandedTileBoundsMin","expandedTileBoundsMax","resetTimers","startTimer","RC_TIMER_TOTAL","RC_LOG_PROGRESS","maxTrisPerChunk","setTileX","setTileY","nverts","data","RC_TIMER_TEMP","lastBuiltTileBmin","lastBuiltTileBmax","result","removeTile","getTileRefAt","addTileResult","DT_TILE_FREE_DATA","statusToReadableString","stopTimer","mergePositionsAndIndices","meshes","mergedPositions","mergedIndices","positionToIndex","indexCounter","pt","key","idx","Float32Array","from","Uint32Array"],"mappings":"qvCAEaA,GAAiBA,CAC5BC,EACAC,KAEA,MAAMC,EAAQ,CAAEC,EAAGC,IAAUC,EAAGD,IAAUE,EAAGF,KACvCG,EAAQ,CAAEJ,GAAIC,IAAUC,GAAID,IAAUE,GAAIF,KAEhD,IAAK,IAAII,EAAI,EAAGA,EAAIP,EAAQQ,OAAQD,IAAK,CACvC,MAAME,EAAMT,EAAQO,GAEdL,EAAIH,EAAgB,EAANU,GACdL,EAAIL,EAAgB,EAANU,EAAU,GACxBJ,EAAIN,EAAgB,EAANU,EAAU,GAE9BR,EAAMC,EAAIQ,KAAKC,IAAIV,EAAMC,EAAGA,GAC5BD,EAAMG,EAAIM,KAAKC,IAAIV,EAAMG,EAAGA,GAC5BH,EAAMI,EAAIK,KAAKC,IAAIV,EAAMI,EAAGA,GAE5BC,EAAMJ,EAAIQ,KAAKE,IAAIN,EAAMJ,EAAGA,GAC5BI,EAAMF,EAAIM,KAAKE,IAAIN,EAAMF,EAAGA,GAC5BE,EAAMD,EAAIK,KAAKE,IAAIN,EAAMD,EAAGA,EAC9B,CAEA,MAAO,CACLJ,MAAOY,EAAKC,QAAQb,GACpBK,MAAOO,EAAKC,QAAQR,GACrB,EAGUS,GAAWC,IACtB,IAAIC,EAAI,EACJC,EAAQ,EAkBZ,OAhBAD,EAAIE,OAAOH,EAAI,QAAW,EAC1BA,IAAMC,EAENC,EAAQC,OAAOH,EAAI,MAAS,EAC5BA,IAAME,EACND,GAAKC,EAELA,EAAQC,OAAOH,EAAI,KAAQ,EAC3BA,IAAME,EACND,GAAKC,EAELA,EAAQC,OAAOH,EAAI,IAAQ,EAE3BC,GAAKC,EACLD,IAFAD,IAAME,IAEI,EAEHD,CAAC,EAGGG,GAAcJ,IACzBA,IACAA,GAAKA,GAAK,EACVA,GAAKA,GAAK,EACVA,GAAKA,GAAK,EACVA,GAAKA,GAAK,EACVA,GAAKA,GAAK,KACVA,GCXWK,GAAiE,IACzEC,GAqCQC,GAAsBA,CACjCxB,EACAC,EACAwB,EAA8D,CAAE,EAChEC,GAAoB,KAEpB,IAAKC,EAAIC,OACP,MAAM,IAAIC,MACR,gKAIJ,MAAMC,EAAe,IAAIC,EAEnBC,EAAmD,CACvDC,KAAM,OACNH,gBAGII,EAAU,IAAIC,EA+BdC,EAAQC,IA5BRX,IAEAM,EAAcM,cAChBC,EAAgBP,EAAcM,aAC9BN,EAAcM,iBAAcE,GAG1BR,EAAcS,qBAChBC,EAAuBV,EAAcS,oBACrCT,EAAcS,wBAAqBD,GAGjCR,EAAcW,aAChBC,EAAeZ,EAAcW,YAC7BX,EAAcW,gBAAaH,GAGzBR,EAAca,WAChBC,EAAad,EAAca,UAC3Bb,EAAca,cAAWL,GAGvBR,EAAce,iBAChBC,EAAmBhB,EAAce,gBACjCf,EAAce,oBAAiBP,IAOjCN,EAAQe,UAED,CACLf,aAASM,EACTU,SAAS,EACTlB,gBACAK,UAKEc,EAAWnD,EACXoD,EAAcnD,EAAQQ,OACtB4C,EAAgB,IAAIC,EAC1BD,EAAcE,KAAKJ,GAEnB,MAAMK,EAAYvD,EACZwD,EAAexD,EAAQQ,OAAS,EAChCiD,EAAiB,IAAIC,EAC3BD,EAAeH,KAAKC,GAEpB,MAAMtD,MAAEA,EAAKK,MAAEA,GAAUR,GAAeC,EAAWC,GAK7C2D,EAASC,EAAe,IACzBvC,MACAG,IAGLmC,EAAOE,cAAgBF,EAAOE,cAAgBF,EAAOE,cACrDF,EAAOG,gBAAkBH,EAAOG,gBAAkBH,EAAOG,gBACzDH,EAAOI,iBACLJ,EAAOI,iBAAmB,GAAM,EAAIJ,EAAOK,GAAKL,EAAOI,iBACzDJ,EAAOM,qBAAuBN,EAAOO,GAAKP,EAAOM,qBAEjD,MAAME,EAAWC,EAAanE,EAAOK,EAAOqD,EAAOK,IACnDL,EAAOU,MAAQF,EAASE,MACxBV,EAAOW,OAASH,EAASG,OAMzB,MAAMjC,EAAckC,IAGpB,GAFAxC,EAAcM,YAAcA,GAGzBmC,EACC3C,EACAQ,EACAsB,EAAOU,MACPV,EAAOW,OACPrE,EACAK,EACAqD,EAAOK,GACPL,EAAOO,IAGT,OAAO/B,EAAK,gCAMd,MAAMsC,EAAqB,IAAIC,EAa/B,GAZAD,EAAmBE,OAAOnB,GAE1BoB,EACE/C,EACA8B,EAAOkB,mBACPzB,EACAD,EACAM,EACAD,EACAiB,IAICK,EACCjD,EACAuB,EACAD,EACAM,EACAgB,EACAjB,EACAnB,EACAsB,EAAOoB,eAGT,OAAO5C,EAAK,iCAGdsC,EAAmBzB,UACnBI,EAAcJ,UACdS,EAAeT,UAQfgC,EACEnD,EACA8B,EAAOoB,cACP1C,GAEF4C,EACEpD,EACA8B,EAAOuB,eACPvB,EAAOoB,cACP1C,GAEF8C,EACEtD,EACA8B,EAAOuB,eACP7C,GASF,MAAMG,GAAqB4C,IAG3B,GAFArD,EAAcS,mBAAqBA,IAGhC6C,EACCxD,EACA8B,EAAOuB,eACPvB,EAAOoB,cACP1C,EACAG,IAGF,OAAOL,EAAK,gCASd,GANKV,IACHa,EAAgBD,GAChBN,EAAcM,iBAAcE,IAK3B+C,EAAkBzD,EAAc8B,EAAO4B,eAAgB/C,IAExD,OAAOL,EAAK,iCAOd,IAAKqD,EAAmB3D,EAAcW,IACpC,OAAOL,EAAK,kCAId,IACGsD,EACC5D,EACAW,GACAmB,EAAO+B,WACP/B,EAAOE,cACPF,EAAOG,iBAGT,OAAO3B,EAAK,2BAMd,MAAMO,GAAaiD,IAGnB,GAFA5D,EAAcW,WAAaA,IAGxBkD,EACC/D,EACAW,GACAmB,EAAOkC,uBACPlC,EAAOmC,WACPpD,GACAqD,EAAOC,4BAGT,OAAO7D,EAAK,6BAMd,MAAMS,GAAWqD,IAEjB,GADAlE,EAAca,SAAWA,IAEtBsD,EAAcrE,EAAca,GAAYiB,EAAOwC,gBAAiBvD,IAEjE,OAAOT,EAAK,kCAMd,MAAMW,GAAiBsD,IAEvB,GADArE,EAAce,eAAiBA,IAE5BuD,EACCxE,EACAe,GACAJ,GACAmB,EAAOI,iBACPJ,EAAOM,qBACPnB,IAGF,OAAOX,EAAK,+BAGTV,IACHgB,EAAuBD,IACvBT,EAAcS,wBAAqBD,EAEnCI,EAAeD,IACfX,EAAcW,gBAAaH,GAM7B,IAAK,IAAIhC,EAAI,EAAGA,EAAIqC,GAAS0D,SAAU/F,IACjCqC,GAAS2D,MAAMhG,IAAMwF,EAAOS,kBAC9B5D,GAAS6D,SAASlG,EAAG,GAEE,GAArBqC,GAAS2D,MAAMhG,IACjBqC,GAAS8D,SAASnG,EAAG,GAIzB,MAAMoG,GAAsB,IAAIC,EAEhCD,GAAoBE,wBAAwBjE,IAC5C+D,GAAoBG,8BAA8BhE,IAElD6D,GAAoBI,kBAAkBpD,EAAOuB,gBAC7CyB,GAAoBK,kBAAkBrD,EAAO4B,gBAC7CoB,GAAoBM,iBAAiBtD,EAAOoB,eAE5C4B,GAAoBO,YAAYvD,EAAOK,IACvC2C,GAAoBQ,cAAcxD,EAAOO,IAEzCyC,GAAoBS,gBAAe,GAE/B5F,EAAuB6F,oBACzBV,GAAoBW,sBAClB9F,EAAuB6F,oBAI3B,MAAME,GAA0BC,EAAkBb,IAElD,IAAKY,GAAwBtE,QAC3B,OAAOd,EAAK,wCAGd,MAAMsF,YAAEA,IAAgBF,GAExB,OAAKtF,EAAQyF,SAASD,IAIf,CACLxE,SAAS,EACThB,UACAF,iBANOI,EAAK,kCAOb,ECzVUwF,GAA6D,IACrErG,EACHsG,SAAU,GACVC,sBAAuB,EACvBC,aAAc,KAqCHC,GAAoCA,IAC/C,IAAIC,GAAqB,CAACrB,EAAqBsB,EAAWC,KACxD,IAAK,IAAI3H,EAAI,EAAGA,EAAIoG,EAAoBwB,cAAe5H,EACrD0H,EAAUG,IAAI7H,EAAG,GACjB2H,EAAUE,IAAI7H,EAAG,EACnB,IAWS8H,GAAoBA,CAC/BtI,EACAC,EACAwB,EAA4D,CAAE,EAC9DC,GAAoB,KAEpB,IAAKC,EAAIC,OACP,MAAM,IAAIC,MACR,gKAIJ,MAAMC,EAAe,IAAIC,EAEnBC,EAAiD,CACrDC,KAAM,YACNH,eACAyG,mBAAe/F,EACfgG,kBAAmB,IAGfC,EAAY,IAAIC,EAChBxG,EAAU,IAAIC,EAGdgB,EAAWnD,EACXoD,EAAcnD,EAAQQ,OACtB4C,EAAgB,IAAIC,EAC1BD,EAAcE,KAAKJ,GAEnB,MAAMK,EAAYvD,EACZwD,EAAexD,EAAQQ,OAAS,EAChCiD,EAAiB,IAAIC,EAC3BD,EAAeH,KAAKC,GAEpB,MAAMtD,MAAEA,EAAKK,MAAEA,GAAUR,GAAeC,EAAWC,IAE7C6H,sBAAEA,GAAqBC,aAAEA,MAAiBY,IAAiB,IAC5Df,MACAnG,GAGCmH,GAAUA,KAId,GAHAvF,EAAcJ,UACdS,EAAeT,WAEVvB,EACH,IAAK,IAAIlB,EAAI,EAAGA,EAAIwB,EAAcwG,kBAAkB/H,OAAQD,IAAK,CAC/D,MAAMqI,EAAmB7G,EAAcwG,kBAAkBhI,GAErDqI,EAAiBvG,cACnBC,EAAgBsG,EAAiBvG,aACjCuG,EAAiBvG,iBAAcE,GAG7BqG,EAAiBpG,qBACnBC,EAAuBmG,EAAiBpG,oBACxCoG,EAAiBpG,wBAAqBD,GAGpCqG,EAAiBC,sBACnBC,EAAwBF,EAAiBC,qBACzCD,EAAiBC,yBAAsBtG,EAE3C,CACF,EAGIJ,GAAQC,IACZuG,KAEAH,EAAUxF,UACVf,EAAQe,UAED,CACLC,SAAS,EACThB,aAASM,EACTiG,eAAWjG,EACXR,gBACAK,UAOEuB,GAASC,EAAe8E,IAExBvE,GAAWC,EAAanE,EAAOK,EAAOqD,GAAOK,IACnDL,GAAOU,MAAQF,GAASE,MACxBV,GAAOW,OAASH,GAASG,OAEzBX,GAAOE,cAAgBF,GAAOE,cAAgBF,GAAOE,cACrDF,GAAOG,gBAAkBH,GAAOG,gBAAkBH,GAAOG,gBACzDH,GAAOI,iBACLJ,GAAOI,iBAAmB,GAAM,EAAIJ,GAAOK,GAAKL,GAAOI,iBACzDJ,GAAOM,qBAAuBN,GAAOO,GAAKP,GAAOM,qBAEjD,MAAM2D,GAAWlH,KAAKqI,MAAMpF,GAAOiE,UAC7BoB,GAAYtI,KAAKqI,OAAOpF,GAAOU,MAAQuD,GAAW,GAAKA,IACvDqB,GAAavI,KAAKqI,OAAOpF,GAAOW,OAASsD,GAAW,GAAKA,IAG/DjE,GAAO+B,WAAa/B,GAAO4B,eAAiB,EAC5C5B,GAAOU,MAAQV,GAAOiE,SAA+B,EAApBjE,GAAO+B,WACxC/B,GAAOW,OAASX,GAAOiE,SAA+B,EAApBjE,GAAO+B,WAGzC,MAAMwD,GAAkBC,EAAsBC,OAAO,CACnDC,KAAMpJ,EACN+D,GAAIL,GAAOK,GACXE,GAAIP,GAAOO,GACXG,MAAOV,GAAOiE,SACdtD,OAAQX,GAAOiE,SACf1C,eAAgBvB,GAAOuB,eACvBK,eAAgB5B,GAAO4B,eACvBR,cAAepB,GAAOoB,cACtBc,uBAAwBlC,GAAOkC,uBAC/ByD,SAAUN,GAAYC,GAAapB,GACnCC,kBAGIyB,GAAY,IAAI7H,EAAI8H,sBAAsB,MAC1CC,GAAa,IAAI/H,EAAIgI,uBAErBC,GACJnI,EAAuBmI,sBACvB5B,KAEF,IACGS,EAAUoB,KACTV,GACAK,GACAE,GACAE,IAGF,OAAOxH,GAAK,mCAGd,MAAMkH,GAAOxI,EAAKgJ,UAAU5J,GAI5B,IAAI6J,GAAWpJ,KAAKC,IAClBD,KAAKqI,MACHhI,GAAQK,GAAW4H,GAAYC,GAAapB,MAE9C,IAEEiC,GAAW,KACbA,GAAW,IAEb,MAEMR,GAAW,GAAKQ,GAChBC,GAAkB,GAHP,GAAKD,GAKhBE,GAAgBC,EAAcb,OAAO,CACzCC,QACAL,UAAWrF,GAAOiE,SAAWjE,GAAOK,GACpCiF,WAAYtF,GAAOiE,SAAWjE,GAAOK,GACrCsF,YACAY,SAAUH,KAGZ,IAAK9H,EAAQkI,UAAUH,IACrB,OAAO7H,GAAK,sCAGd,MAAMmG,GAAgB,IAAI8B,EAG1B,GAFArI,EAAcuG,cAAgBA,IAEzBA,GAAcsB,KAAKxG,EAAeK,EAAgBD,EAAc,KACnE,OAAOrB,GAAK,wCAGd,MAAMkI,GAAsBA,CAACC,EAAeC,KAE1C,MAAMhC,EAAyD,CAC7D+B,QACAC,SAIIC,EAAM7G,GAAOiE,SAAWjE,GAAOK,GAE/ByG,EAAaC,EAAc/G,IAE3BgH,EAA8B,CAClC1K,EAAM,GAAKqK,EAAQE,EACnBvK,EAAM,GACNA,EAAM,GAAKsK,EAAQC,GAGfI,EAA8B,CAClC3K,EAAM,IAAMqK,EAAQ,GAAKE,EACzBlK,EAAM,GACNL,EAAM,IAAMsK,EAAQ,GAAKC,GAG3BG,EAAc,IAAMF,EAAW/E,WAAa+E,EAAWzG,GACvD2G,EAAc,IAAMF,EAAW/E,WAAa+E,EAAWzG,GACvD4G,EAAc,IAAMH,EAAW/E,WAAa+E,EAAWzG,GACvD4G,EAAc,IAAMH,EAAW/E,WAAa+E,EAAWzG,GAEvDyG,EAAWI,SAAS,EAAGF,EAAc,IACrCF,EAAWI,SAAS,EAAGF,EAAc,IACrCF,EAAWI,SAAS,EAAGF,EAAc,IAErCF,EAAWK,SAAS,EAAGF,EAAc,IACrCH,EAAWK,SAAS,EAAGF,EAAc,IACrCH,EAAWK,SAAS,EAAGF,EAAc,IAGrC,MAAMvI,EAAckC,IAGpB,GAFAgE,EAAkBlG,YAAcA,GAG7BmC,EACC3C,EACAQ,EACAoI,EAAWpG,MACXoG,EAAWnG,OACXqG,EACAC,EACAH,EAAWzG,GACXyG,EAAWvG,IAGb,MAAO,CAAE6G,EAAG,GAGd,MAAMC,EAAsB,CAACL,EAAc,GAAIA,EAAc,IACvDM,EAAsB,CAACL,EAAc,GAAIA,EAAc,IAIvDM,EAAgB,IAAIC,EAC1BD,EAAcvG,OAFM,KAIpB,MAAMyG,EAAqB9C,GAAc+C,yBACvCL,EACAC,EACAC,EAPkB,KAWpB,GAA2B,IAAvBE,EACF,MAAO,CAAEL,EAAG,GAGd,IAAK,IAAIxK,EAAI,EAAGA,EAAI6K,IAAsB7K,EAAG,CAC3C,MAAM+K,EAASJ,EAAcK,IAAIhL,GAE3BiL,EADOlD,GAAcmD,MAAMH,GACVP,EAEjBW,EAAqBpD,GAAcqD,YAAYL,GAE/C7G,EAAqB,IAAIC,EAC/BD,EAAmBE,OAAO6G,GAK1B5G,EACE/C,EACA4I,EAAW5F,mBACXzB,EACAD,EACAuI,EACAF,EACA/G,GAGF,MAAMxB,EAAU6B,EACdjD,EACAuB,EACAD,EACAuI,EACAjH,EACA+G,EACAnJ,EACAoI,EAAW1F,eAKb,GAFAN,EAAmBzB,WAEdC,EACH,MAAO,CAAE8H,EAAG,EAEhB,CAKA/F,EACEnD,EACA8B,GAAOoB,cACP1C,GAEF4C,EACEpD,EACA8B,GAAOuB,eACPvB,GAAOoB,cACP1C,GAEF8C,EACEtD,EACA8B,GAAOuB,eACP7C,GAGF,MAAMG,EAAqB4C,IAC3B,IACGC,EACCxD,EACA8B,GAAOuB,eACPvB,GAAOoB,cACP1C,EACAG,GAGF,MAAO,CAAEuI,EAAG,GASd,GANKtJ,IACHa,EAAgBiG,EAAkBlG,aAClCkG,EAAkBlG,iBAAcE,IAK/B+C,EACCzD,EACA8B,GAAO4B,eACP/C,GAGF,MAAO,CAAEuI,EAAG,GAGd,MAAMlC,EAAsB+C,IAC5B,IACGC,EACChK,EACAW,EACAmB,GAAO+B,WACP/B,GAAOuB,eACP2D,GAGF,MAAO,CAAEkC,EAAG,GAGTtJ,IACHgB,EAAuBD,GACvB+F,EAAkB/F,wBAAqBD,GAGzC,MAAMuJ,EAA6B,GAEnC,IAAK,IAAIvL,EAAI,EAAGA,EAAIsI,EAAoBkD,UAAWxL,IAAK,CACtD,MAAMyL,EAAO,IAAIC,EACXC,EAAmBrD,EAAoBsD,OAAO5L,GAG9C6L,EAAS,IAAI1K,EAAI2K,uBACvBD,EAAOE,MAAQC,EAAOC,mBACtBJ,EAAOK,QAAUF,EAAOG,qBAGxBN,EAAOO,GAAKrC,EACZ8B,EAAOQ,GAAKrC,EACZ6B,EAAOS,OAAStM,EAEhB,MAAMuM,EAAsBZ,EAAiBa,OACvCC,EAAuBd,EAAiBe,OAC9Cb,EAAOvB,SAAS,EAAGiC,EAAoB5M,GACvCkM,EAAOvB,SAAS,EAAGiC,EAAoB1M,GACvCgM,EAAOvB,SAAS,EAAGiC,EAAoBzM,GAEvC+L,EAAOtB,SAAS,EAAGkC,EAAqB9M,GACxCkM,EAAOtB,SAAS,EAAGkC,EAAqB5M,GACxCgM,EAAOtB,SAAS,EAAGkC,EAAqB3M,GAGxC+L,EAAO/H,MAAQ6H,EAAiB7H,QAChC+H,EAAO9H,OAAS4H,EAAiB5H,SACjC8H,EAAOc,KAAOhB,EAAiBgB,OAC/Bd,EAAOe,KAAOjB,EAAiBiB,OAC/Bf,EAAOgB,KAAOlB,EAAiBkB,OAC/BhB,EAAOiB,KAAOnB,EAAiBmB,OAC/BjB,EAAOkB,KAAOpB,EAAiBoB,OAC/BlB,EAAOmB,KAAOrB,EAAiBqB,OAE/B,MAAMC,EAAUC,EAA2BvB,GACrC3F,EAAQmH,EAAyBxB,GACjCyB,EAAOC,EAAwB1B,GAE/B2B,EAASC,EACbrE,GACA2C,EACAoB,EACAjH,EACAoH,EACA3B,GAGF,GAAI+B,EAAaF,GACf,MAAO,CAAE9C,EAAG,GAGde,EAAMkC,KAAKhC,EACb,CASA,OAPKvK,IACHqH,EAAwBD,GACxBN,EAAkBM,yBAAsBtG,GAG1CR,EAAcwG,kBAAkByF,KAAKzF,GAE9B,CAAEwC,EAAGe,EAAMtL,OAAQsL,QAAO,EAInC,IAAK,IAAI1L,EAAI,EAAGA,EAAI6I,KAAc7I,EAChC,IAAK,IAAIF,EAAI,EAAGA,EAAI8I,KAAa9I,EAAG,CAClC,MAAM6K,EAAEA,EAAGe,MAAOmC,GAAa5D,GAAoBnK,EAAGE,GAEtD,GAAI2K,EAAI,GAAKkD,EACX,IAAK,IAAI1N,EAAI,EAAGA,EAAIwK,EAAGxK,IAAK,CAC1B,MAAM2N,EAAgBD,EAAS1N,GAEzB4N,EAAY3F,EAAU4F,QAAQF,GAEhCH,EAAaI,EAAUN,SACzBhM,EAAawM,IACXtI,EAAOuI,eACP,0CAA0CpO,UAAUE,IAI1D,CAEJ,CAIF,IAAK,IAAIA,EAAI,EAAGA,EAAI6I,GAAY7I,IAC9B,IAAK,IAAIF,EAAI,EAAGA,EAAI8I,GAAW9I,IAAK,CAClC,MAAMqO,EAAW/F,EAAUgG,oBAAoBtO,EAAGE,EAAG6B,GAErD,GAAI8L,EAAaQ,GACf,OAAOpM,GAAK,qCAAqCjC,MAAME,IAE3D,CAKF,OAFAuI,KAEO,CACL1F,SAAS,EACTuF,YACAvG,UACAF,gBACD,ECrhBU0M,GACX,IACKnN,GA4CMoN,GAAuBA,CAClC3O,EACAC,EACAwB,EAA+D,CAAE,EACjEC,GAAoB,KAEpB,IAAKC,EAAIC,OACP,MAAM,IAAIC,MACR,gKAIJ,MAAMC,EAAe,IAAIC,EAEnBC,EAAoD,CACxDC,KAAM,QACNH,eACAyG,mBAAe/F,EACfgG,kBAAmB,IAGftG,EAAU,IAAIC,EAGdgB,EAAWnD,EACXoD,EAAcnD,EAAQQ,OACtB4C,EAAgB,IAAIC,EAC1BD,EAAcE,KAAKJ,GAEnB,MAAMK,EAAYvD,EACZwD,EAAexD,EAAQQ,OAAS,EAChCiD,GAAiB,IAAIC,EAC3BD,GAAeH,KAAKC,GAEpB,MAAMoF,GAAUA,KAId,GAHAvF,EAAcJ,UACdS,GAAeT,WAEXvB,EAAJ,CAEA,IAAK,IAAIlB,EAAI,EAAGA,EAAIwB,EAAcwG,kBAAkB/H,OAAQD,IAAK,CAC/D,MAAMqI,EAAmB7G,EAAcwG,kBAAkBhI,GAErDqI,EAAiBpG,qBACnBC,EAAuBmG,EAAiBpG,oBACxCoG,EAAiBpG,wBAAqBD,GAGpCqG,EAAiBvG,cACnBC,EAAgBsG,EAAiBvG,aACjCuG,EAAiBvG,iBAAcE,GAG7BqG,EAAiBlG,aACnBC,EAAeiG,EAAiBlG,YAChCkG,EAAiBlG,gBAAaH,GAG5BqG,EAAiBhG,WACnBC,EAAa+F,EAAiBhG,UAC9BgG,EAAiBhG,cAAWL,GAG1BqG,EAAiB9F,iBACnBC,EAAmB6F,EAAiB9F,gBACpC8F,EAAiB9F,oBAAiBP,EAEtC,CAEIR,EAAcuG,gBAChBvG,EAAcuG,mBAAgB/F,EAhCT,CAiCvB,EAGIJ,GAAQC,IACZuG,KAEA1G,EAAQe,UAED,CACLC,SAAS,EACThB,aAASM,EACTR,gBACAK,UAOEuB,GAASC,EAAe,IACzB6K,MACAjN,KAICvB,MAAEA,GAAKK,MAAEA,IAAUR,GAAeC,EAAWC,GAG7CmE,GAAWC,EAAanE,GAAOK,GAAOqD,GAAOK,IACnDL,GAAOU,MAAQF,GAASE,MACxBV,GAAOW,OAASH,GAASG,OAEzBX,GAAOE,cAAgBF,GAAOE,cAAgBF,GAAOE,cACrDF,GAAOG,gBAAkBH,GAAOG,gBAAkBH,GAAOG,gBACzDH,GAAOiE,SAAWlH,KAAKqI,MAAMpF,GAAOiE,UACpCjE,GAAO+B,WAAa/B,GAAO4B,eAAiB,EAC5C5B,GAAOU,MAAQV,GAAOiE,SAA+B,EAApBjE,GAAO+B,WACxC/B,GAAOW,OAASX,GAAOiE,SAA+B,EAApBjE,GAAO+B,WACzC/B,GAAOI,iBACLJ,GAAOI,iBAAmB,GAAM,EAAIJ,GAAOK,GAAKL,GAAOI,iBACzDJ,GAAOM,qBAAuBN,GAAOO,GAAKP,GAAOM,qBAGjD,MAAM2D,GAAWlH,KAAKqI,MAAMpF,GAAOiE,UAC7BoB,GAAYtI,KAAKqI,OAAO5E,GAASE,MAAQuD,GAAW,GAAKA,IACzDqB,GAAavI,KAAKqI,OAAO5E,GAASG,OAASsD,GAAW,GAAKA,IAC3D4C,GAAM7G,GAAOiE,SAAWjE,GAAOK,GAG/BqF,GAAOxI,EAAKgJ,UAAU5J,IAI5B,IAAI6J,GAAWpJ,KAAKC,IAClBD,KAAKqI,MAAMhI,GAAQK,GAAW4H,GAAYC,MAC1C,IAEEa,GAAW,KAAIA,GAAW,IAC9B,MAEMR,GAAW,GAAKQ,GAChBC,GAAkB,GAHP,GAAKD,GAKhBE,GAAgBC,EAAcb,OAAO,CACzCC,QACAL,UAAWrF,GAAOiE,SAAWjE,GAAOK,GACpCiF,WAAYtF,GAAOiE,SAAWjE,GAAOK,GACrCsF,YACAY,SAAUH,KAGZ,IAAK9H,EAAQkI,UAAUH,IACrB,OAAO7H,GAAK,yCAId,MAAMmG,GAAgB,IAAI8B,EAG1B,GAFArI,EAAcuG,cAAgBA,IAEzBA,GAAcsB,KAAKxG,EAAeK,GAAgBD,EAAc,KACnE,OAAOrB,GAAK,wCAId,MAAMwM,GAAgBA,CACpBrE,EACAC,EACAI,EACAC,KAIA,MAAMgE,EAAgBxM,IACpBP,EAAawM,IAAItI,EAAO8I,aAAczM,GAE/B,CAAEa,SAAS,EAAgBb,UAG9BwG,EAAsC,CAAE0B,QAAOC,SAErDxI,EAAcwG,kBAAkByF,KAAKpF,GAErC,MAAM6B,EAAaC,EAAc/G,IAwB3BmL,EAAwB,IAAInE,GAC5BoE,EAAwB,IAAInE,GAElCkE,EAAsB,IAAMrE,EAAW/E,WAAa+E,EAAWzG,GAC/D8K,EAAsB,IAAMrE,EAAW/E,WAAa+E,EAAWzG,GAE/D+K,EAAsB,IAAMtE,EAAW/E,WAAa+E,EAAWzG,GAC/D+K,EAAsB,IAAMtE,EAAW/E,WAAa+E,EAAWzG,GAE/DyG,EAAWI,SAAS,EAAGiE,EAAsB,IAC7CrE,EAAWI,SAAS,EAAGiE,EAAsB,IAC7CrE,EAAWI,SAAS,EAAGiE,EAAsB,IAE7CrE,EAAWK,SAAS,EAAGiE,EAAsB,IAC7CtE,EAAWK,SAAS,EAAGiE,EAAsB,IAC7CtE,EAAWK,SAAS,EAAGiE,EAAsB,IAG7ClN,EAAamN,cAGbnN,EAAaoN,WAAWlJ,EAAOmJ,gBAE/BrN,EAAawM,IACXtI,EAAOoJ,gBACP,iBAAiBpN,EAAcwG,kBAAkB/H,gBAAgB8J,SAAaC,KAEhF1I,EAAawM,IACXtI,EAAOoJ,gBACP,MAAMxL,GAAOU,WAAWV,GAAOW,gBAEjCzC,EAAawM,IACXtI,EAAOoJ,gBACP,MAAMhM,EAAc,gBAAiBK,EAAe,aAItD,MAAMnB,EAAckC,IAGpB,GAFAqE,EAAiBvG,YAAcA,GAG5BmC,EACC3C,EACAQ,EACAoI,EAAWpG,MACXoG,EAAWnG,OACXwK,EACAC,EACAtE,EAAWzG,GACXyG,EAAWvG,IAGb,OAAO0K,EAAa,iCAML,IAAIlK,GACZC,OAAO2D,GAAc8G,mBAE9B,MAAMpE,EAAsB,CAC1B8D,EAAsB,GACtBA,EAAsB,IAElB7D,EAAsB,CAC1B8D,EAAsB,GACtBA,EAAsB,IAKlB7D,EAAgB,IAAIC,EAC1BD,EAAcvG,OAFM,KAIpB,MAAMyG,EAAqB9C,GAAc+C,yBACvCL,EACAC,EACAC,EAPkB,KAWpB,GAA2B,IAAvBE,EACF,MAAO,CAAEnI,SAAS,GAGpB,IAAK,IAAI1C,EAAI,EAAGA,EAAI6K,IAAsB7K,EAAG,CAC3C,MAAM+K,EAASJ,EAAcK,IAAIhL,GAE3BiL,EADOlD,GAAcmD,MAAMH,GACVP,EAEjBW,EAAqBpD,GAAcqD,YAAYL,GAE/C7G,EAAqB,IAAIC,EAC/BD,EAAmBE,OAAO6G,GAK1B5G,EACE/C,EACA4I,EAAW5F,mBACXzB,EACAD,EACAuI,EACAF,EACA/G,GAGF,MAAMxB,EAAU6B,EACdjD,EACAuB,EACAD,EACAuI,EACAjH,EACA+G,EACAnJ,EACAoI,EAAW1F,eAKb,GAFAN,EAAmBzB,WAEdC,EACH,OAAO2L,EAAa,gCAExB,CAKA5J,EACEnD,EACA4I,EAAW1F,cACX1C,GAEF4C,EACEpD,EACA4I,EAAWvF,eACXuF,EAAW1F,cACX1C,GAEF8C,EACEtD,EACA4I,EAAWvF,eACX7C,GAMF,MAAMG,EAAqB4C,IAG3B,GAFAwD,EAAiBpG,mBAAqBA,GAGnC6C,EACCxD,EACA4I,EAAWvF,eACXuF,EAAW1F,cACX1C,EACAG,GAGF,OAAOoM,EAAa,uCAStB,GANKnN,IACHa,EAAgBsG,EAAiBvG,aACjCuG,EAAiBvG,iBAAcE,IAK9B+C,EACCzD,EACA4I,EAAWlF,eACX/C,GAGF,OAAOoM,EAAa,iCAOtB,IAAKpJ,EAAmB3D,EAAcW,GACpC,OAAOoM,EAAa,kCAItB,IACGnJ,EACC5D,EACAW,EACAiI,EAAW/E,WACX+E,EAAW5G,cACX4G,EAAW3G,iBAGb,OAAO8K,EAAa,2BAMtB,MAAMlM,EAAaiD,IAGnB,GAFAiD,EAAiBlG,WAAaA,GAG3BkD,EACC/D,EACAW,EACAiI,EAAW5E,uBACX4E,EAAW3E,WACXpD,EACAqD,EAAOC,4BAGT,OAAO4I,EAAa,6BAMtB,MAAMhM,EAAWqD,IAEjB,GADA2C,EAAiBhG,SAAWA,GAEzBsD,EACCrE,EACAa,EACA+H,EAAWtE,gBACXvD,GAGF,OAAOgM,EAAa,kCAMtB,MAAM9L,EAAiBsD,IAEvB,GADAwC,EAAiB9F,eAAiBA,GAE/BuD,EACCxE,EACAe,EACAJ,EACAiI,EAAW1G,iBACX0G,EAAWxG,qBACXnB,GAGF,OAAO8L,EAAa,+BAGjBnN,IACHgB,EAAuBD,GACvBoG,EAAiBpG,wBAAqBD,EAEtCI,EAAeD,GACfkG,EAAiBlG,gBAAaH,GAIhC,IAAK,IAAIhC,EAAI,EAAGA,EAAIqC,EAAS0D,SAAU/F,IACjCqC,EAAS2D,MAAMhG,IAAMwF,EAAOS,kBAC9B5D,EAAS6D,SAASlG,EAAG,GAEE,GAArBqC,EAAS2D,MAAMhG,IACjBqC,EAAS8D,SAASnG,EAAG,GAIzB,MAAMoG,EAAsB,IAAIC,EAEhCD,EAAoBE,wBAAwBjE,GAC5C+D,EAAoBG,8BAA8BhE,GAElD6D,EAAoBI,kBAAkB0D,EAAWvF,gBACjDyB,EAAoBK,kBAAkByD,EAAWlF,gBACjDoB,EAAoBM,iBAAiBwD,EAAW1F,eAEhD4B,EAAoBO,YAAYuD,EAAWzG,IAC3C2C,EAAoBQ,cAAcsD,EAAWvG,IAE7CyC,EAAoBS,gBAAe,GAE/B5F,EAAuB6F,oBACzBV,EAAoBW,sBAClB9F,EAAuB6F,oBAI3BV,EAAoB0I,SAAS/E,GAC7B3D,EAAoB2I,SAAS/E,GAE7B,MAAMhD,EAA0BC,EAAkBb,GAElD,OAAKY,EAAwBtE,SAI7BpB,EAAawM,IACXtI,EAAOoJ,gBACP,gBAAgBvM,EAAS2M,sBAAsB3M,EAAS0D,qBAGnD,CAAErD,SAAS,EAAMuM,KAAMjI,EAAwBE,cAR7CmH,EAAa,uCAQ6C,EAGrE/M,EAAaoN,WAAWlJ,EAAO0J,eAE/B,MAAMC,GAAkC,CAAC,EAAG,EAAG,GACzCC,GAAkC,CAAC,EAAG,EAAG,GAE/C,IAAK,IAAIvP,EAAI,EAAGA,EAAI6I,GAAY7I,IAC9B,IAAK,IAAIF,EAAI,EAAGA,EAAI8I,GAAW9I,IAAK,CAClCwP,GAAkB,GAAKzP,GAAM,GAAKC,EAAIsK,GACtCkF,GAAkB,GAAKzP,GAAM,GAC7ByP,GAAkB,GAAKzP,GAAM,GAAKG,EAAIoK,GAEtCmF,GAAkB,GAAK1P,GAAM,IAAMC,EAAI,GAAKsK,GAC5CmF,GAAkB,GAAKrP,GAAM,GAC7BqP,GAAkB,GAAK1P,GAAM,IAAMG,EAAI,GAAKoK,GAE5C,MAAMoF,EAASjB,GAAczO,EAAGE,EAAGsP,GAAmBC,IAEtD,GAAIC,EAAO3M,SAAW2M,EAAOJ,KAAM,CACjCvN,EAAQ4N,WAAW5N,EAAQ6N,aAAa5P,EAAGE,EAAG,IAE9C,MAAM2P,EAAgB9N,EAAQmM,QAC5BwB,EAAOJ,KACPjD,EAAOyD,kBACP,GAGEjC,EAAagC,EAAclC,UAC7BhM,EAAawM,IACXtI,EAAOuI,eAGL,yCAAOpO,UAAUE,aACN6P,EAAuBF,EAAclC,YAC9CkC,EAAclC,WAIpB+B,EAAOJ,KAAKxM,UAEhB,CACF,CASF,OANAnB,EAAaqO,UAAUnK,EAAO0J,eAEzBhO,GACHkH,KAGK,CACL1F,SAAS,EACThB,UACAF,gBACD,EChqBUoO,GACXC,IAKA,MAAMC,EAA4B,GAC5BC,EAA0B,GAE1BC,EAA8C,CAAA,EACpD,IAAIC,EAAe,EAEnB,IAAK,MAAMzQ,UAAEA,EAASC,QAAEA,KAAaoQ,EACnC,IAAK,IAAI7P,EAAI,EAAGA,EAAIP,EAAQQ,OAAQD,IAAK,CACvC,MAAMkQ,EAAkB,EAAbzQ,EAAQO,GAEbL,EAAIH,EAAU0Q,GACdrQ,EAAIL,EAAU0Q,EAAK,GACnBpQ,EAAIN,EAAU0Q,EAAK,GAEnBC,EAAM,GAAGxQ,KAAKE,KAAKC,IACzB,IAAIsQ,EAAMJ,EAAgBG,GAErBC,IACHJ,EAAgBG,GAAOC,EAAMH,EAC7BH,EAAgBrC,KAAK9N,EAAGE,EAAGC,GAC3BmQ,KAGFF,EAActC,KAAK2C,EACrB,CAGF,MAAO,CAACC,aAAaC,KAAKR,GAAkBS,YAAYD,KAAKP,GAAe"}