@Override
  public ByteBuffer getTile(final int clipmapLevel, final Tile tile) throws Exception {
    final ByteBuffer data = tileDataPool.get();
    final int tileX = tile.getX();
    final int tileY = tile.getY();

    final int baseClipmapLevel = availableClipmapLevels - clipmapLevel - 1;

    textureLock.lock();
    try {
      for (int y = 0; y < tileSize; y++) {
        for (int x = 0; x < tileSize; x++) {
          if (Thread.interrupted()) {
            return null;
          }

          final int heightX = tileX * tileSize + x;
          final int heightY = tileY * tileSize + y;

          final double eval =
              function.eval(heightX << baseClipmapLevel, heightY << baseClipmapLevel, 0) * 0.4167f
                  + 0.5f;
          final byte colIndex = (byte) (eval * 255);

          final ReadOnlyColorRGBA c = terrainColors[colIndex & 0xFF];

          final int index = (x + y * tileSize) * 3;
          data.put(index, (byte) (c.getRed() * 255));
          data.put(index + 1, (byte) (c.getGreen() * 255));
          data.put(index + 2, (byte) (c.getBlue() * 255));
        }
      }
    } finally {
      textureLock.unlock();
    }
    return data;
  }
Example #2
0
  /**
   * Save a mesh to the given files.
   *
   * @param mesh mesh to export
   * @param objFile WaveFront OBJ file
   * @param mtlFile material file, optional
   * @param append indicates whether the data are written to the end of the OBJ file
   * @param firstVertexIndex first vertex index used for this mesh during the export
   * @param firstFiles indicates whether the couple of files is used for the first time, i.e there
   *     is nothing to append despite the value of <code>append</code>
   * @param materialList list of materials already exported in this material file
   * @param customTextureName texture name that overrides the one of the mesh, optional
   * @throws IOException
   */
  protected void save(
      final Mesh mesh,
      final File objFile,
      final File mtlFile,
      final boolean append,
      final int firstVertexIndex,
      final boolean firstFiles,
      final List<ObjMaterial> materialList,
      final String customTextureName)
      throws IOException {
    File parentDirectory = objFile.getParentFile();
    if (parentDirectory != null && !parentDirectory.exists()) {
      parentDirectory.mkdirs();
    }
    if (mtlFile != null) {
      parentDirectory = mtlFile.getParentFile();
      if (parentDirectory != null && !parentDirectory.exists()) {
        parentDirectory.mkdirs();
      }
    }
    PrintWriter objPw = null, mtlPw = null;
    try {
      // fills the MTL file
      final String mtlName;
      if (mtlFile != null) {
        final FileOutputStream mtlOs = new FileOutputStream(mtlFile, append);
        mtlPw = new PrintWriter(new BufferedOutputStream(mtlOs));
        // writes some comments
        if (firstFiles) {
          mtlPw.println("# Ardor3D 1.0 MTL file");
        }
        final ObjMaterial currentMtl = new ObjMaterial(null);
        final MaterialState mtlState = (MaterialState) mesh.getLocalRenderState(StateType.Material);
        if (mtlState != null) {
          final ReadOnlyColorRGBA ambientColor = mtlState.getAmbient();
          if (ambientColor != null) {
            currentMtl.d = ambientColor.getAlpha();
            currentMtl.Ka =
                new float[] {
                  ambientColor.getRed(),
                  ambientColor.getGreen(),
                  ambientColor.getBlue(),
                  ambientColor.getAlpha()
                };
          }
          final ReadOnlyColorRGBA diffuseColor = mtlState.getDiffuse();
          if (diffuseColor != null) {
            currentMtl.Kd =
                new float[] {
                  diffuseColor.getRed(),
                  diffuseColor.getGreen(),
                  diffuseColor.getBlue(),
                  diffuseColor.getAlpha()
                };
          }
          final ReadOnlyColorRGBA specularColor = mtlState.getSpecular();
          if (specularColor != null) {
            currentMtl.Ks =
                new float[] {
                  specularColor.getRed(),
                  specularColor.getGreen(),
                  specularColor.getBlue(),
                  specularColor.getAlpha()
                };
          }
          currentMtl.Ns = mtlState.getShininess();
        }
        if (customTextureName == null) {
          currentMtl.textureName = getLocalMeshTextureName(mesh);
        } else {
          currentMtl.textureName = customTextureName;
        }
        if (mesh.getSceneHints().getLightCombineMode() == LightCombineMode.Off) {
          // Color on and Ambient off
          currentMtl.illumType = 0;
        } else {
          // Color on and Ambient on
          currentMtl.illumType = 1;
        }
        ObjMaterial sameObjMtl = null;
        if (materialList != null && !materialList.isEmpty()) {
          for (final ObjMaterial mtl : materialList) {
            if (mtl.illumType == currentMtl.illumType
                && mtl.Ns == currentMtl.Ns
                && mtl.forceBlend == currentMtl.forceBlend
                && mtl.d == currentMtl.d
                && Arrays.equals(mtl.Ka, currentMtl.Ka)
                && Arrays.equals(mtl.Kd, currentMtl.Kd)
                && Arrays.equals(mtl.Ks, currentMtl.Ks)
                // && Objects.equals(mtl.textureName, currentMtl.textureName)) {
                && mtl.textureName.equals(currentMtl.textureName)) {
              sameObjMtl = mtl;
              break;
            }
          }
        }
        if (sameObjMtl == null) {
          // writes the new material library
          mtlName =
              mtlFile.getName().trim().replaceAll(" ", "")
                  + "_"
                  + (materialList == null ? 1 : materialList.size() + 1);
          if (materialList != null) {
            final ObjMaterial mtl = new ObjMaterial(mtlName);
            mtl.illumType = currentMtl.illumType;
            mtl.textureName = currentMtl.textureName;
            materialList.add(mtl);
          }
          mtlPw.println("newmtl " + mtlName);
          if (currentMtl.Ns != -1) {
            mtlPw.println("Ns " + currentMtl.Ns);
          }
          if (currentMtl.Ka != null) {
            mtlPw.print("Ka");
            for (final float KaCoef : currentMtl.Ka) {
              mtlPw.print(" " + KaCoef);
            }
            mtlPw.println();
          }
          if (currentMtl.Kd != null) {
            mtlPw.print("Kd");
            for (final float KdCoef : currentMtl.Kd) {
              mtlPw.print(" " + KdCoef);
            }
            mtlPw.println();
          }
          if (currentMtl.Ks != null) {
            mtlPw.print("Ks");
            for (final float KsCoef : currentMtl.Ks) {
              mtlPw.print(" " + KsCoef);
            }
            mtlPw.println();
          }
          if (currentMtl.d != -1) {
            mtlPw.println("d " + currentMtl.d);
          }
          mtlPw.println("illum " + currentMtl.illumType);
          if (currentMtl.textureName != null) {
            mtlPw.println("map_Kd " + currentMtl.textureName);
          }
        } else {
          mtlName = sameObjMtl.getName();
        }
      } else {
        mtlName = null;
      }

      final FileOutputStream objOs = new FileOutputStream(objFile, append);
      objPw = new PrintWriter(new BufferedOutputStream(objOs));
      // writes some comments
      if (firstFiles) {
        objPw.println("# Ardor3D 1.0 OBJ file");
        objPw.println("# www.ardor3d.com");
        // writes the material file name if any
        if (mtlFile != null) {
          final String mtlLibFilename = mtlFile.getName();
          objPw.println("mtllib " + mtlLibFilename);
        }
      }
      // writes the object name
      final String objName;
      String meshName = mesh.getName();
      // removes all spaces from the mesh name
      if (meshName != null && !meshName.isEmpty()) {
        meshName = meshName.trim().replaceAll(" ", "");
      }
      if (meshName != null && !meshName.isEmpty()) {
        objName = meshName;
      } else {
        objName = "obj_mesh" + mesh.hashCode();
      }
      objPw.println("o " + objName);
      final MeshData meshData = mesh.getMeshData();
      // writes the coordinates
      final FloatBufferData verticesData = meshData.getVertexCoords();
      if (verticesData == null) {
        throw new IllegalArgumentException("cannot export a mesh with no vertices");
      }
      final int expectedTupleCount = verticesData.getTupleCount();
      saveFloatBufferData(verticesData, objPw, "v", expectedTupleCount);
      final FloatBufferData texCoordsData = meshData.getTextureCoords(0);
      saveFloatBufferData(texCoordsData, objPw, "vt", expectedTupleCount);
      final FloatBufferData normalsData = meshData.getNormalCoords();
      saveFloatBufferData(normalsData, objPw, "vn", expectedTupleCount);
      // writes the used material library
      if (mtlFile != null) {
        objPw.println("usemtl " + mtlName);
      }
      // writes the faces
      for (int sectionIndex = 0; sectionIndex < meshData.getSectionCount(); sectionIndex++) {
        final IndexMode indexMode = meshData.getIndexMode(sectionIndex);
        final int[] indices = new int[indexMode.getVertexCount()];
        switch (indexMode) {
          case TriangleFan:
          case Triangles:
          case TriangleStrip:
          case Quads:
            for (int primIndex = 0, primCount = meshData.getPrimitiveCount(sectionIndex);
                primIndex < primCount;
                primIndex++) {
              meshData.getPrimitiveIndices(primIndex, sectionIndex, indices);
              objPw.print("f");
              for (int vertexIndex = 0; vertexIndex < indices.length; vertexIndex++) {
                // indices start at 1 in the WaveFront OBJ format whereas indices start at 0 in
                // Ardor3D
                final int shiftedIndex = indices[vertexIndex] + 1 + firstVertexIndex;
                // vertex index
                objPw.print(" " + shiftedIndex);
                // texture coordinate index
                if (texCoordsData != null) {
                  objPw.print("/" + shiftedIndex);
                }
                // normal coordinate index
                if (normalsData != null) {
                  objPw.print("/" + shiftedIndex);
                }
              }
              objPw.println();
            }
            break;
          default:
            throw new IllegalArgumentException("index mode " + indexMode + " not supported");
        }
      }
    } catch (final Throwable t) {
      throw new Error("Unable to save the mesh into an obj", t);
    } finally {
      if (objPw != null) {
        objPw.flush();
        objPw.close();
      }
      if (mtlPw != null) {
        mtlPw.flush();
        mtlPw.close();
      }
    }
  }