591 {
592
593 char tileString[20];
594 sprintf(tileString, "[Map %03i] [%02i,%02i]: ", mapID, tileX, tileY);
595 printf("%s Building movemap tiles...\n", tileString);
596
597 IntermediateValues iv;
598
599 float* tVerts = meshData.solidVerts.getCArray();
600 int tVertCount = meshData.solidVerts.size() / 3;
601 int* tTris = meshData.solidTris.getCArray();
602 int tTriCount = meshData.solidTris.size() / 3;
603
604 float* lVerts = meshData.liquidVerts.getCArray();
605 int lVertCount = meshData.liquidVerts.size() / 3;
606 int* lTris = meshData.liquidTris.getCArray();
607 int lTriCount = meshData.liquidTris.size() / 3;
608 uint8* lTriFlags = meshData.liquidType.getCArray();
609
612 float baseUnitDim = cfg.baseUnitDim;
613
615
616
617 rcCalcGridSize(config.bmin, config.bmax, config.cs, &config.width, &config.height);
618
619
620 Tile* tiles = new Tile[tilesPerMap * tilesPerMap];
621
622
623 rcConfig tileCfg = config;
624 tileCfg.width = config.tileSize + config.borderSize * 2;
625 tileCfg.height = config.tileSize + config.borderSize * 2;
626
627
628 rcPolyMesh** pmmerge = new rcPolyMesh*[tilesPerMap * tilesPerMap];
629 rcPolyMeshDetail** dmmerge = new rcPolyMeshDetail*[tilesPerMap * tilesPerMap];
630 int nmerge = 0;
631
632
633 for (int y = 0; y < tilesPerMap; ++y)
634 {
635 for (int x = 0; x < tilesPerMap; ++x)
636 {
637 Tile& tile = tiles[x + y * tilesPerMap];
638
639
640 tileCfg.bmin[0] = config.bmin[0] + x * float(config.tileSize * config.cs);
641 tileCfg.bmin[2] = config.bmin[2] + y * float(config.tileSize * config.cs);
642 tileCfg.bmax[0] = config.bmin[0] + (x + 1) * float(config.tileSize * config.cs);
643 tileCfg.bmax[2] = config.bmin[2] + (y + 1) * float(config.tileSize * config.cs);
644
645 tileCfg.bmin[0] -= tileCfg.borderSize * tileCfg.cs;
646 tileCfg.bmin[2] -= tileCfg.borderSize * tileCfg.cs;
647 tileCfg.bmax[0] += tileCfg.borderSize * tileCfg.cs;
648 tileCfg.bmax[2] += tileCfg.borderSize * tileCfg.cs;
649
650
651 tile.solid = rcAllocHeightfield();
652 if (!tile.solid || !rcCreateHeightfield(
m_rcContext, *tile.solid, tileCfg.width, tileCfg.height, tileCfg.bmin, tileCfg.bmax, tileCfg.cs, tileCfg.ch))
653 {
654 printf("%s Failed building heightfield! \n", tileString);
655 continue;
656 }
657
658
659
660 unsigned char* triFlags = new unsigned char[tTriCount];
661 memset(triFlags,
NAV_GROUND, tTriCount *
sizeof(
unsigned char));
662 rcClearUnwalkableTriangles(
m_rcContext, tileCfg.walkableSlopeAngle, tVerts, tVertCount, tTris, tTriCount, triFlags);
663 rcRasterizeTriangles(
m_rcContext, tVerts, tVertCount, tTris, triFlags, tTriCount, *tile.solid, config.walkableClimb);
664 delete[] triFlags;
665
666 rcFilterLowHangingWalkableObstacles(
m_rcContext, config.walkableClimb, *tile.solid);
667 rcFilterLedgeSpans(
m_rcContext, tileCfg.walkableHeight, tileCfg.walkableClimb, *tile.solid);
668 rcFilterWalkableLowHeightSpans(
m_rcContext, tileCfg.walkableHeight, *tile.solid);
669
670
671 rcRasterizeTriangles(
m_rcContext, lVerts, lVertCount, lTris, lTriFlags, lTriCount, *tile.solid, config.walkableClimb);
672
673
674 tile.chf = rcAllocCompactHeightfield();
675 if (!tile.chf || !rcBuildCompactHeightfield(
m_rcContext, tileCfg.walkableHeight, tileCfg.walkableClimb, *tile.solid, *tile.chf))
676 {
677 printf("%s Failed compacting heightfield! \n", tileString);
678 continue;
679 }
680
681
682 if (!rcErodeWalkableArea(
m_rcContext, config.walkableRadius, *tile.chf))
683 {
684 printf("%s Failed eroding area! \n", tileString);
685 continue;
686 }
687
689 {
690 printf("%s Failed building distance field! \n", tileString);
691 continue;
692 }
693
694 if (!rcBuildRegions(
m_rcContext, *tile.chf, tileCfg.borderSize, tileCfg.minRegionArea, tileCfg.mergeRegionArea))
695 {
696 printf("%s Failed building regions! \n", tileString);
697 continue;
698 }
699
700 tile.cset = rcAllocContourSet();
701 if (!tile.cset || !rcBuildContours(
m_rcContext, *tile.chf, tileCfg.maxSimplificationError, tileCfg.maxEdgeLen, *tile.cset))
702 {
703 printf("%s Failed building contours! \n", tileString);
704 continue;
705 }
706
707
708 tile.pmesh = rcAllocPolyMesh();
709 if (!tile.pmesh || !rcBuildPolyMesh(
m_rcContext, *tile.cset, tileCfg.maxVertsPerPoly, *tile.pmesh))
710 {
711 printf("%s Failed building polymesh! \n", tileString);
712 continue;
713 }
714
715 tile.dmesh = rcAllocPolyMeshDetail();
716 if (!tile.dmesh || !rcBuildPolyMeshDetail(
m_rcContext, *tile.pmesh, *tile.chf, tileCfg.detailSampleDist, tileCfg.detailSampleMaxError, *tile.dmesh))
717 {
718 printf("%s Failed building polymesh detail! \n", tileString);
719 continue;
720 }
721
722
723
724
725 rcFreeHeightField(tile.solid);
726 tile.solid = nullptr;
727 rcFreeCompactHeightfield(tile.chf);
728 tile.chf = nullptr;
729 rcFreeContourSet(tile.cset);
730 tile.cset = nullptr;
731
732 pmmerge[nmerge] = tile.pmesh;
733 dmmerge[nmerge] = tile.dmesh;
734 nmerge++;
735 }
736 }
737
738 iv.polyMesh = rcAllocPolyMesh();
739 if (!iv.polyMesh)
740 {
741 printf("%s alloc iv.polyMesh FAILED!\n", tileString);
742 delete[] pmmerge;
743 delete[] dmmerge;
744 delete[] tiles;
745 return;
746 }
747 rcMergePolyMeshes(
m_rcContext, pmmerge, nmerge, *iv.polyMesh);
748
749 iv.polyMeshDetail = rcAllocPolyMeshDetail();
750 if (!iv.polyMeshDetail)
751 {
752 printf("%s alloc m_dmesh FAILED!\n", tileString);
753 delete[] pmmerge;
754 delete[] dmmerge;
755 delete[] tiles;
756 return;
757 }
758 rcMergePolyMeshDetails(
m_rcContext, dmmerge, nmerge, *iv.polyMeshDetail);
759
760
761 delete[] pmmerge;
762 delete[] dmmerge;
763 delete[] tiles;
764
765
767 for (int i = 0; i < iv.polyMesh->npolys; ++i)
768 if (iv.polyMesh->areas[i] & RC_WALKABLE_AREA)
769 iv.polyMesh->flags[i] = iv.polyMesh->areas[i];
770
771
772 dtNavMeshCreateParams params;
773 memset(¶ms, 0, sizeof(params));
774 params.verts = iv.polyMesh->verts;
775 params.vertCount = iv.polyMesh->nverts;
776 params.polys = iv.polyMesh->polys;
777 params.polyAreas = iv.polyMesh->areas;
778 params.polyFlags = iv.polyMesh->flags;
779 params.polyCount = iv.polyMesh->npolys;
780 params.nvp = iv.polyMesh->nvp;
781 params.detailMeshes = iv.polyMeshDetail->meshes;
782 params.detailVerts = iv.polyMeshDetail->verts;
783 params.detailVertsCount = iv.polyMeshDetail->nverts;
784 params.detailTris = iv.polyMeshDetail->tris;
785 params.detailTriCount = iv.polyMeshDetail->ntris;
786
787 params.offMeshConVerts = meshData.offMeshConnections.getCArray();
788 params.offMeshConCount = meshData.offMeshConnections.size() / 6;
789 params.offMeshConRad = meshData.offMeshConnectionRads.getCArray();
790 params.offMeshConDir = meshData.offMeshConnectionDirs.getCArray();
791 params.offMeshConAreas = meshData.offMeshConnectionsAreas.getCArray();
792 params.offMeshConFlags = meshData.offMeshConnectionsFlags.getCArray();
793
794 params.walkableHeight = baseUnitDim * config.walkableHeight;
795 params.walkableRadius = baseUnitDim * config.walkableRadius;
796 params.walkableClimb = baseUnitDim * config.walkableClimb;
797 params.tileX = (((bmin[0] + bmax[0]) / 2) - navMesh->getParams()->orig[0]) /
GRID_SIZE;
798 params.tileY = (((bmin[2] + bmax[2]) / 2) - navMesh->getParams()->orig[2]) /
GRID_SIZE;
799 rcVcopy(params.bmin, bmin);
800 rcVcopy(params.bmax, bmax);
801 params.cs = config.cs;
802 params.ch = config.ch;
803 params.tileLayer = 0;
804 params.buildBvTree = true;
805
806
807 unsigned char* navData = nullptr;
808 int navDataSize = 0;
809
810 do
811 {
812
813
814 if (params.nvp > DT_VERTS_PER_POLYGON)
815 {
816 printf("%s Invalid verts-per-polygon value! \n", tileString);
817 break;
818 }
819 if (params.vertCount >= 0xffff)
820 {
821 printf("%s Too many vertices! \n", tileString);
822 break;
823 }
824 if (!params.vertCount || !params.verts)
825 {
826
827
828
829
830 printf("%sNo vertices to build tile! \n", tileString);
831 break;
832 }
833 if (!params.polyCount || !params.polys)
834 {
835
836
837 printf("%s No polygons to build on tile! \n", tileString);
838 break;
839 }
840 if (!params.detailMeshes || !params.detailVerts || !params.detailTris)
841 {
842 printf("%s No detail mesh to build tile! \n", tileString);
843 break;
844 }
845
846 printf("%s Building navmesh tile...\n", tileString);
847 if (!dtCreateNavMeshData(¶ms, &navData, &navDataSize))
848 {
849 printf("%s Failed building navmesh tile! \n", tileString);
850 break;
851 }
852
853 dtTileRef tileRef = 0;
854 printf("%s Adding tile to navmesh...\n", tileString);
855
856
857 dtStatus dtResult = navMesh->addTile(navData, navDataSize, DT_TILE_FREE_DATA, 0, &tileRef);
858 if (!tileRef || dtResult != DT_SUCCESS)
859 {
860 printf("%s Failed adding tile to navmesh! \n", tileString);
861 break;
862 }
863
864
868 mapID, tileY, tileX
869 );
870
871 FILE* file = fopen(fileName.c_str(), "wb");
872 if (!file)
873 {
874 char message[1024];
875 sprintf(message, "[Map %03i] Failed to open %s for writing!\n", mapID, fileName.c_str());
876 perror(message);
877 navMesh->removeTile(tileRef, nullptr, nullptr);
878 break;
879 }
880
881 printf("%s Writing to file...\n", tileString);
882
883
889
890
891 fwrite(navData, sizeof(unsigned char), navDataSize, file);
892 fclose(file);
893
894
895 navMesh->removeTile(tileRef, nullptr, nullptr);
896 } while (false);
897
899 {
900
901 for (int i = 0; i < iv.polyMesh->nverts; ++i)
902 {
903 unsigned short* v = &iv.polyMesh->verts[i * 3];
904 v[0] += (unsigned short)config.borderSize;
905 v[2] += (unsigned short)config.borderSize;
906 }
907
910 }
911 }
std::uint8_t uint8
Definition Define.h:109
std::uint32_t uint32
Definition Define.h:107
@ NAV_GROUND
Definition MapDefines.h:91
ResolvedMeshConfig GetConfigForTile(uint32 mapID, uint32 tileX, uint32 tileY) const
Definition Config.cpp:75
rcConfig getRecastConfig(const ResolvedMeshConfig &cfg, float bmin[3], float bmax[3]) const
Definition MapBuilder.cpp:1063
bool usesLiquids() const
Definition TerrainBuilder.h:88
std::string StringFormat(FormatString< Args... > fmt, Args &&... args)
Default AC string format function.
Definition StringFormat.h:34
static const float GRID_SIZE
Definition TerrainBuilder.h:48
static char const *const TILE_FILE_NAME_FORMAT
Definition MMapMgr.h:43
int tilesPerMapEdge
Definition Config.h:51