diff --git a/src/RecastNavMesh.cpp b/src/RecastNavMesh.cpp
index 90de5b8..97e5e8d 100644
--- a/src/RecastNavMesh.cpp
+++ b/src/RecastNavMesh.cpp
@@ -102,9 +102,9 @@ void godot::RecastNavMesh::_bind_methods() {
   ADD_PROPERTY(PropertyInfo(Variant::INT, "partition_type", PROPERTY_HINT_ENUM, "Watershed,Monotone,Layers"), "set_partition_type", "get_partition_type");
 
   // Recast calls
-  ClassDB::bind_method(D_METHOD("clear_vertices"), &RecastNavMesh::clear_vertices);
+  ClassDB::bind_method(D_METHOD("get_walkable_triangles", "vertices", "indices", "areas"), &RecastNavMesh::get_walkable_triangles);
   ClassDB::bind_method(D_METHOD("add_vertices", "vertices", "area_id"), &RecastNavMesh::add_vertices);
-  ClassDB::bind_method(D_METHOD("recalculate_navmesh"), &RecastNavMesh::recalculate_navmesh);
+  ClassDB::bind_method(D_METHOD("build"), &RecastNavMesh::build);
   ClassDB::bind_method(D_METHOD("is_calculated"), &RecastNavMesh::is_calculated);
 }
 
@@ -138,20 +138,14 @@ void godot::RecastNavMesh::cleanup() {
     rcFreeContourSet(m_contour_set);
     m_contour_set = NULL;
   }
-  /*
-     rcFreeHeightField(m_solid);
-     m_solid = 0;
-     rcFreeCompactHeightfield(m_chf);
-     m_chf = 0;
-     rcFreeContourSet(m_cset);
-     m_cset = 0;
-     rcFreePolyMesh(m_pmesh);
-     m_pmesh = 0;
-     rcFreePolyMeshDetail(m_dmesh);
-     m_dmesh = 0;
-     dtFreeNavMesh(m_navMesh);
-     m_navMesh = 0;
-     */
+  if(m_poly_mesh) {
+    rcFreePolyMesh(m_poly_mesh);
+    m_poly_mesh = NULL;
+  }
+  if(m_poly_mesh_detail) {
+    rcFreePolyMeshDetail(m_poly_mesh_detail);
+    m_poly_mesh_detail = NULL;
+  }
 }
 
 void godot::RecastNavMesh::get_walkable_triangles(PackedFloat32Array vertices, PackedInt32Array indices, PackedByteArray areas) {
@@ -192,5 +186,88 @@ bool godot::RecastNavMesh::build() {
 
   rcFreeHeightField(m_heightfield);
   m_heightfield = NULL;
+
+  if (!rcErodeWalkableArea(this, config.walkableRadius, *m_compact_heightfield))
+  {
+    log(RC_LOG_ERROR, "buildNavigation: Could not erode.");
+    return false;
+  }
+
+  if (partition_type == WATERSHED)
+  {
+    // Prepare for region partitioning, by calculating distance field along the walkable surface.
+    if (!rcBuildDistanceField(this, *m_compact_heightfield))
+    {
+      log(RC_LOG_ERROR, "buildNavigation: Could not build distance field.");
+      return false;
+    }
+
+    // Partition the walkable surface into simple regions without holes.
+    if (!rcBuildRegions(this, *m_compact_heightfield, 0, config.minRegionArea, config.mergeRegionArea))
+    {
+      log(RC_LOG_ERROR, "buildNavigation: Could not build watershed regions.");
+      return false;
+    }
+  }
+  else if (partition_type == MONOTONE)
+  {
+    // Partition the walkable surface into simple regions without holes.
+    // Monotone partitioning does not need distancefield.
+    if (!rcBuildRegionsMonotone(this, *m_compact_heightfield, 0, config.minRegionArea, config.mergeRegionArea))
+    {
+      log(RC_LOG_ERROR, "buildNavigation: Could not build monotone regions.");
+      return false;
+    }
+  }
+  else // SAMPLE_PARTITION_LAYERS
+  {
+    // Partition the walkable surface into simple regions without holes.
+    if (!rcBuildLayerRegions(this, *m_compact_heightfield, 0, config.minRegionArea))
+    {
+      log(RC_LOG_ERROR, "buildNavigation: Could not build layer regions.");
+      return false;
+    }
+  }
+
+  m_contour_set = rcAllocContourSet();
+  if(!m_contour_set) {
+    log(RC_LOG_ERROR, "couldn't alloc contour set!");
+    return false;
+  }
+
+  if(!rcBuildContours(this, *m_compact_heightfield, config.maxSimplificationError, config.maxEdgeLen, *m_contour_set)) {
+    log(RC_LOG_ERROR, "couldn't build contours!");
+    return false;
+  }
+
+  m_poly_mesh = rcAllocPolyMesh();
+  if(!m_poly_mesh) {
+    log(RC_LOG_ERROR, "couldn't alloc poly mesh!");
+    return false;
+  }
+
+  if(!rcBuildPolyMesh(this, *m_contour_set, config.maxVertsPerPoly, *m_poly_mesh)) {
+    log(RC_LOG_ERROR, "couldn't build poly mesh!");
+    return false;
+  }
+
+  m_poly_mesh_detail = rcAllocPolyMeshDetail();
+  if(!m_poly_mesh_detail) {
+    log(RC_LOG_ERROR, "couldn't alloc detail mesh!");
+    return false;
+  }
+
+  if(!rcBuildPolyMeshDetail(this, *m_poly_mesh, *m_compact_heightfield, config.detailSampleDist, config.detailSampleMaxError, *m_poly_mesh_detail)) {
+    log(RC_LOG_ERROR, "couldn't build detail mesh!");
+    return false;
+  }
+
+  rcFreeCompactHeightfield(m_compact_heightfield);
+  m_compact_heightfield = NULL;
+  rcFreeContourSet(m_contour_set);
+  m_contour_set = NULL;
+
+  m_calculated = true;
+  return true;
 }