Exemple #1
0
  public static PolyMesh copyPolyMesh(Context ctx, PolyMesh src) {
    PolyMesh dst = new PolyMesh();

    dst.nverts = src.nverts;
    dst.npolys = src.npolys;
    dst.maxpolys = src.npolys;
    dst.nvp = src.nvp;
    RecastVectors.copy(dst.bmin, src.bmin, 0);
    RecastVectors.copy(dst.bmax, src.bmax, 0);
    dst.cs = src.cs;
    dst.ch = src.ch;
    dst.borderSize = src.borderSize;

    dst.verts = new int[src.nverts * 3];
    System.arraycopy(src.verts, 0, dst.verts, 0, dst.verts.length);
    dst.polys = new int[src.npolys * 2 * src.nvp];
    System.arraycopy(src.polys, 0, dst.polys, 0, dst.polys.length);
    dst.regs = new int[src.npolys];
    System.arraycopy(src.regs, 0, dst.regs, 0, dst.regs.length);
    dst.areas = new int[src.npolys];
    System.arraycopy(src.areas, 0, dst.areas, 0, dst.areas.length);
    dst.flags = new int[src.npolys];
    System.arraycopy(src.flags, 0, dst.flags, 0, dst.flags.length);
    return dst;
  }
Exemple #2
0
  /// @par
  ///
  /// @note If the mesh data is to be used to construct a Detour navigation mesh, then the upper
  /// limit must be retricted to <= #DT_VERTS_PER_POLYGON.
  ///
  /// @see rcAllocPolyMesh, rcContourSet, rcPolyMesh, rcConfig
  public static PolyMesh buildPolyMesh(Context ctx, ContourSet cset, int nvp) {
    ctx.startTimer("BUILD_POLYMESH");
    PolyMesh mesh = new PolyMesh();
    RecastVectors.copy(mesh.bmin, cset.bmin, 0);
    RecastVectors.copy(mesh.bmax, cset.bmax, 0);
    mesh.cs = cset.cs;
    mesh.ch = cset.ch;
    mesh.borderSize = cset.borderSize;

    int maxVertices = 0;
    int maxTris = 0;
    int maxVertsPerCont = 0;
    for (int i = 0; i < cset.conts.size(); ++i) {
      // Skip null contours.
      if (cset.conts.get(i).nverts < 3) continue;
      maxVertices += cset.conts.get(i).nverts;
      maxTris += cset.conts.get(i).nverts - 2;
      maxVertsPerCont = Math.max(maxVertsPerCont, cset.conts.get(i).nverts);
    }
    if (maxVertices >= 0xfffe) {
      throw new RuntimeException("rcBuildPolyMesh: Too many vertices " + maxVertices);
    }
    int[] vflags = new int[maxVertices];

    mesh.verts = new int[maxVertices * 3];
    mesh.polys = new int[maxTris * nvp * 2];
    Arrays.fill(mesh.polys, RC_MESH_NULL_IDX);
    mesh.regs = new int[maxTris];
    mesh.areas = new int[maxTris];

    mesh.nverts = 0;
    mesh.npolys = 0;
    mesh.nvp = nvp;
    mesh.maxpolys = maxTris;

    int[] nextVert = new int[maxVertices];

    int[] firstVert = new int[VERTEX_BUCKET_COUNT];
    for (int i = 0; i < VERTEX_BUCKET_COUNT; ++i) firstVert[i] = -1;

    int[] indices = new int[maxVertsPerCont];
    int[] tris = new int[maxVertsPerCont * 3];
    int[] polys = new int[(maxVertsPerCont + 1) * nvp];

    int tmpPoly = maxVertsPerCont * nvp;

    for (int i = 0; i < cset.conts.size(); ++i) {
      Contour cont = cset.conts.get(i);

      // Skip null contours.
      if (cont.nverts < 3) continue;

      // Triangulate contour
      for (int j = 0; j < cont.nverts; ++j) indices[j] = j;
      int ntris = triangulate(cont.nverts, cont.verts, indices, tris);
      if (ntris <= 0) {
        // Bad triangulation, should not happen.
        ctx.warn("buildPolyMesh: Bad triangulation Contour " + i + ".");
        ntris = -ntris;
      }

      // Add and merge vertices.
      for (int j = 0; j < cont.nverts; ++j) {
        int v = j * 4;
        int[] inv =
            addVertex(
                cont.verts[v + 0],
                cont.verts[v + 1],
                cont.verts[v + 2],
                mesh.verts,
                firstVert,
                nextVert,
                mesh.nverts);
        indices[j] = inv[0];
        mesh.nverts = inv[1];
        if ((cont.verts[v + 3] & RC_BORDER_VERTEX) != 0) {
          // This vertex should be removed.
          vflags[indices[j]] = 1;
        }
      }

      // Build initial polygons.
      int npolys = 0;
      Arrays.fill(polys, RC_MESH_NULL_IDX);
      for (int j = 0; j < ntris; ++j) {
        int t = j * 3;
        if (tris[t + 0] != tris[t + 1]
            && tris[t + 0] != tris[t + 2]
            && tris[t + 1] != tris[t + 2]) {
          polys[npolys * nvp + 0] = indices[tris[t + 0]];
          polys[npolys * nvp + 1] = indices[tris[t + 1]];
          polys[npolys * nvp + 2] = indices[tris[t + 2]];
          npolys++;
        }
      }
      if (npolys == 0) continue;

      // Merge polygons.
      if (nvp > 3) {
        for (; ; ) {
          // Find best polygons to merge.
          int bestMergeVal = 0;
          int bestPa = 0, bestPb = 0, bestEa = 0, bestEb = 0;

          for (int j = 0; j < npolys - 1; ++j) {
            int pj = j * nvp;
            for (int k = j + 1; k < npolys; ++k) {
              int pk = k * nvp;
              int[] veaeb = getPolyMergeValue(polys, pj, pk, mesh.verts, nvp);
              int v = veaeb[0];
              int ea = veaeb[1];
              int eb = veaeb[2];
              if (v > bestMergeVal) {
                bestMergeVal = v;
                bestPa = j;
                bestPb = k;
                bestEa = ea;
                bestEb = eb;
              }
            }
          }

          if (bestMergeVal > 0) {
            // Found best, merge.
            int pa = bestPa * nvp;
            int pb = bestPb * nvp;
            mergePolys(polys, pa, pb, bestEa, bestEb, tmpPoly, nvp);
            int lastPoly = (npolys - 1) * nvp;
            if (pb != lastPoly) {
              System.arraycopy(polys, lastPoly, polys, pb, nvp);
            }
            npolys--;
          } else {
            // Could not merge any polygons, stop.
            break;
          }
        }
      }

      // Store polygons.
      for (int j = 0; j < npolys; ++j) {
        int p = mesh.npolys * nvp * 2;
        int q = j * nvp;
        for (int k = 0; k < nvp; ++k) mesh.polys[p + k] = polys[q + k];
        mesh.regs[mesh.npolys] = cont.reg;
        mesh.areas[mesh.npolys] = cont.area;
        mesh.npolys++;
        if (mesh.npolys > maxTris) {
          throw new RuntimeException(
              "rcBuildPolyMesh: Too many polygons " + mesh.npolys + " (max:" + maxTris + ").");
        }
      }
    }

    // Remove edge vertices.
    for (int i = 0; i < mesh.nverts; ++i) {
      if (vflags[i] != 0) {
        if (!canRemoveVertex(ctx, mesh, i)) continue;
        removeVertex(ctx, mesh, i, maxTris);
        // Remove vertex
        // Note: mesh.nverts is already decremented inside removeVertex()!
        // Fixup vertex flags
        for (int j = i; j < mesh.nverts; ++j) vflags[j] = vflags[j + 1];
        --i;
      }
    }

    // Calculate adjacency.
    buildMeshAdjacency(mesh.polys, mesh.npolys, mesh.nverts, nvp);

    // Find portal edges
    if (mesh.borderSize > 0) {
      int w = cset.width;
      int h = cset.height;
      for (int i = 0; i < mesh.npolys; ++i) {
        int p = i * 2 * nvp;
        for (int j = 0; j < nvp; ++j) {
          if (mesh.polys[p + j] == RC_MESH_NULL_IDX) break;
          // Skip connected edges.
          if (mesh.polys[p + nvp + j] != RC_MESH_NULL_IDX) continue;
          int nj = j + 1;
          if (nj >= nvp || mesh.polys[p + nj] == RC_MESH_NULL_IDX) nj = 0;
          int va = mesh.polys[p + j] * 3;
          int vb = mesh.polys[p + nj] * 3;

          if (mesh.verts[va + 0] == 0 && mesh.verts[vb + 0] == 0)
            mesh.polys[p + nvp + j] = 0x8000 | 0;
          else if (mesh.verts[va + 2] == h && mesh.verts[vb + 2] == h)
            mesh.polys[p + nvp + j] = 0x8000 | 1;
          else if (mesh.verts[va + 0] == w && mesh.verts[vb + 0] == w)
            mesh.polys[p + nvp + j] = 0x8000 | 2;
          else if (mesh.verts[va + 2] == 0 && mesh.verts[vb + 2] == 0)
            mesh.polys[p + nvp + j] = 0x8000 | 3;
        }
      }
    }

    // Just allocate the mesh flags array. The user is resposible to fill it.
    mesh.flags = new int[mesh.npolys];

    if (mesh.nverts > 0xffff) {
      throw new RuntimeException(
          "rcBuildPolyMesh: The resulting mesh has too many vertices "
              + mesh.nverts
              + " (max "
              + 0xffff
              + "). Data can be corrupted.");
    }
    if (mesh.npolys > 0xffff) {
      throw new RuntimeException(
          "rcBuildPolyMesh: The resulting mesh has too many polygons "
              + mesh.npolys
              + " (max "
              + 0xffff
              + "). Data can be corrupted.");
    }

    ctx.stopTimer("BUILD_POLYMESH");
    return mesh;
  }
Exemple #3
0
  /// @see rcAllocPolyMesh, rcPolyMesh
  public static PolyMesh mergePolyMeshes(Context ctx, PolyMesh[] meshes, int nmeshes) {

    if (nmeshes == 0 || meshes == null) return null;

    ctx.startTimer("MERGE_POLYMESH");
    PolyMesh mesh = new PolyMesh();
    mesh.nvp = meshes[0].nvp;
    mesh.cs = meshes[0].cs;
    mesh.ch = meshes[0].ch;
    RecastVectors.copy(mesh.bmin, meshes[0].bmin, 0);
    RecastVectors.copy(mesh.bmax, meshes[0].bmax, 0);

    int maxVerts = 0;
    int maxPolys = 0;
    int maxVertsPerMesh = 0;
    for (int i = 0; i < nmeshes; ++i) {
      RecastVectors.min(mesh.bmin, meshes[i].bmin, 0);
      RecastVectors.max(mesh.bmax, meshes[i].bmax, 0);
      maxVertsPerMesh = Math.max(maxVertsPerMesh, meshes[i].nverts);
      maxVerts += meshes[i].nverts;
      maxPolys += meshes[i].npolys;
    }

    mesh.nverts = 0;
    mesh.verts = new int[maxVerts * 3];

    mesh.npolys = 0;
    mesh.polys = new int[maxPolys * 2 * mesh.nvp];
    Arrays.fill(mesh.polys, 0, mesh.polys.length, RC_MESH_NULL_IDX);
    mesh.regs = new int[maxPolys];
    mesh.areas = new int[maxPolys];
    mesh.flags = new int[maxPolys];

    int[] nextVert = new int[maxVerts];

    int[] firstVert = new int[VERTEX_BUCKET_COUNT];
    for (int i = 0; i < VERTEX_BUCKET_COUNT; ++i) firstVert[i] = -1;

    int[] vremap = new int[maxVertsPerMesh];

    for (int i = 0; i < nmeshes; ++i) {
      PolyMesh pmesh = meshes[i];

      int ox = (int) Math.floor((pmesh.bmin[0] - mesh.bmin[0]) / mesh.cs + 0.5f);
      int oz = (int) Math.floor((pmesh.bmin[2] - mesh.bmin[2]) / mesh.cs + 0.5f);

      boolean isMinX = (ox == 0);
      boolean isMinZ = (oz == 0);
      boolean isMaxX = (Math.floor((mesh.bmax[0] - pmesh.bmax[0]) / mesh.cs + 0.5f)) == 0;
      boolean isMaxZ = (Math.floor((mesh.bmax[2] - pmesh.bmax[2]) / mesh.cs + 0.5f)) == 0;
      boolean isOnBorder = (isMinX || isMinZ || isMaxX || isMaxZ);

      for (int j = 0; j < pmesh.nverts; ++j) {
        int v = j * 3;
        int[] inv =
            addVertex(
                pmesh.verts[v + 0] + ox,
                pmesh.verts[v + 1],
                pmesh.verts[v + 2] + oz,
                mesh.verts,
                firstVert,
                nextVert,
                mesh.nverts);

        vremap[j] = inv[0];
        mesh.nverts = inv[1];
      }

      for (int j = 0; j < pmesh.npolys; ++j) {
        int tgt = mesh.npolys * 2 * mesh.nvp;
        int src = j * 2 * mesh.nvp;
        mesh.regs[mesh.npolys] = pmesh.regs[j];
        mesh.areas[mesh.npolys] = pmesh.areas[j];
        mesh.flags[mesh.npolys] = pmesh.flags[j];
        mesh.npolys++;
        for (int k = 0; k < mesh.nvp; ++k) {
          if (pmesh.polys[src + k] == RC_MESH_NULL_IDX) break;
          mesh.polys[tgt + k] = vremap[pmesh.polys[src + k]];
        }

        if (isOnBorder) {
          for (int k = mesh.nvp; k < mesh.nvp * 2; ++k) {
            if ((pmesh.polys[src + k] & 0x8000) != 0 && pmesh.polys[src + k] != 0xffff) {
              int dir = pmesh.polys[src + k] & 0xf;
              switch (dir) {
                case 0: // Portal x-
                  if (isMinX) mesh.polys[tgt + k] = pmesh.polys[src + k];
                  break;
                case 1: // Portal z+
                  if (isMaxZ) mesh.polys[tgt + k] = pmesh.polys[src + k];
                  break;
                case 2: // Portal x+
                  if (isMaxX) mesh.polys[tgt + k] = pmesh.polys[src + k];
                  break;
                case 3: // Portal z-
                  if (isMinZ) mesh.polys[tgt + k] = pmesh.polys[src + k];
                  break;
              }
            }
          }
        }
      }
    }

    // Calculate adjacency.
    buildMeshAdjacency(mesh.polys, mesh.npolys, mesh.nverts, mesh.nvp);
    if (mesh.nverts > 0xffff) {
      throw new RuntimeException(
          "rcBuildPolyMesh: The resulting mesh has too many vertices "
              + mesh.nverts
              + " (max "
              + 0xffff
              + "). Data can be corrupted.");
    }
    if (mesh.npolys > 0xffff) {
      throw new RuntimeException(
          "rcBuildPolyMesh: The resulting mesh has too many polygons "
              + mesh.npolys
              + " (max "
              + 0xffff
              + "). Data can be corrupted.");
    }

    ctx.stopTimer("MERGE_POLYMESH");

    return mesh;
  }