Package org.osm2world.core.target.obj

Source Code of org.osm2world.core.target.obj.ObjTarget

package org.osm2world.core.target.obj;

import static java.awt.Color.WHITE;
import static java.lang.Math.max;
import static java.util.Collections.nCopies;
import static org.osm2world.core.target.common.material.Material.multiplyColor;

import java.awt.Color;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.osm2world.core.map_data.data.MapArea;
import org.osm2world.core.map_data.data.MapElement;
import org.osm2world.core.map_data.data.MapNode;
import org.osm2world.core.map_data.data.MapWaySegment;
import org.osm2world.core.math.TriangleXYZ;
import org.osm2world.core.math.TriangleXYZWithNormals;
import org.osm2world.core.math.VectorXYZ;
import org.osm2world.core.math.VectorXZ;
import org.osm2world.core.osm.data.OSMElement;
import org.osm2world.core.target.common.FaceTarget;
import org.osm2world.core.target.common.TextureData;
import org.osm2world.core.target.common.material.Material;
import org.osm2world.core.target.common.material.Materials;
import org.osm2world.core.world.data.WorldObject;

public class ObjTarget extends FaceTarget<RenderableToObj> {

  private final PrintStream objStream;
  private final PrintStream mtlStream;
 
  private final Map<VectorXYZ, Integer> vertexIndexMap = new HashMap<VectorXYZ, Integer>();
  private final Map<VectorXYZ, Integer> normalsIndexMap = new HashMap<VectorXYZ, Integer>();
  private final Map<VectorXZ, Integer> texCoordsIndexMap = new HashMap<VectorXZ, Integer>();
  private final Map<Material, String> materialMap = new HashMap<Material, String>();
 
  private Class<? extends WorldObject> currentWOGroup = null;
  private int anonymousWOCounter = 0;
 
  private Material currentMaterial = null;
  private int currentMaterialLayer = 0;
  private static int anonymousMaterialCounter = 0;
 
  // this is approximatly one millimeter
  private static final double SMALL_OFFSET = 1e-3;
 
  public ObjTarget(PrintStream objStream, PrintStream mtlStream) {
   
    this.objStream = objStream;
    this.mtlStream = mtlStream;
       
  }
 
  @Override
  public Class<RenderableToObj> getRenderableType() {
    return RenderableToObj.class;
  }
 
  @Override
  public void render(RenderableToObj renderable) {
    renderable.renderTo(this);
  }
 
  @Override
  public boolean reconstructFaces() {
    return config != null && config.getBoolean("reconstructFaces", false);
  }

  @Override
  public void beginObject(WorldObject object) {
   
    if (object == null) {
     
      currentWOGroup = null;
      objStream.println("g null");
      objStream.println("o null");
     
    } else {
     
      /* maybe start a group depending on the object's class */
     
      if (!object.getClass().equals(currentWOGroup)) {
        currentWOGroup = object.getClass();
        objStream.println("g " + currentWOGroup.getSimpleName());
      }
     
      /* start an object with the object's class
       * and the underlying OSM element's name/ref tags */
     
      MapElement element = object.getPrimaryMapElement();
      OSMElement osmElement;
      if (element instanceof MapNode) {
        osmElement = ((MapNode) element).getOsmNode();
      } else if (element instanceof MapWaySegment) {
        osmElement = ((MapWaySegment) element).getOsmWay();
      } else if (element instanceof MapArea) {
        osmElement = ((MapArea) element).getOsmObject();
      } else {
        osmElement = null;
      }
     
      if (osmElement != null && osmElement.tags.containsKey("name")) {
        objStream.println("o " + object.getClass().getSimpleName() + " " + osmElement.tags.getValue("name"));
      } else if (osmElement != null && osmElement.tags.containsKey("ref")) {
        objStream.println("o " + object.getClass().getSimpleName() + " " + osmElement.tags.getValue("ref"));
      } else {
        objStream.println("o " + object.getClass().getSimpleName() + anonymousWOCounter ++);
      }
     
    }
   
  }
 
  @Override
  public void drawFace(Material material, List<VectorXYZ> vs,
      List<VectorXYZ> normals, List<List<VectorXZ>> texCoordLists) {

    int[] normalIndices = null;
    if (normals != null) {
      normalIndices = normalsToIndices(normals);
    }
   
    VectorXYZ faceNormal = new TriangleXYZ(vs.get(0), vs.get(1), vs.get(2)).getNormal();
   
    for (int layer = 0; layer < max(1, material.getNumTextureLayers()); layer++) {
     
      useMaterial(material, layer);
   
      int[] texCoordIndices = null;
      if (texCoordLists != null && !texCoordLists.isEmpty()) {
        texCoordIndices = texCoordsToIndices(texCoordLists.get(layer));
      }
     
      writeFace(verticesToIndices((layer == 0)? vs : offsetVertices(vs, nCopies(vs.size(), faceNormal), layer * SMALL_OFFSET)),
          normalIndices, texCoordIndices);
    }
  }

  @Override
  public void drawTrianglesWithNormals(Material material,
      Collection<? extends TriangleXYZWithNormals> triangles,
      List<List<VectorXZ>> texCoordLists) {
   
    for (int layer = 0; layer < max(1, material.getNumTextureLayers()); layer++) {
     
      useMaterial(material, layer);

      int triangleNumber = 0;
      for (TriangleXYZWithNormals t : triangles) {
     
        int[] texCoordIndices = null;
        if (texCoordLists != null && !texCoordLists.isEmpty()) {
          List<VectorXZ> texCoords = texCoordLists.get(layer);
          texCoordIndices = texCoordsToIndices(
              texCoords.subList(3*triangleNumber, 3*triangleNumber + 3));
        }
       
        writeFace(verticesToIndices((layer == 0)? t.getVertices() : offsetVertices(t.getVertices(), t.getNormals(), layer * SMALL_OFFSET)),
            normalsToIndices(t.getNormals()), texCoordIndices);
     
        triangleNumber ++;
      }
     
    }
   
  }

  private void useMaterial(Material material, int layer) {
    if (!material.equals(currentMaterial) || (layer != currentMaterialLayer)) {
     
      String name = materialMap.get(material);
      if (name == null) {
        name = Materials.getUniqueName(material);
        if (name == null) {
          name = "MAT_" + anonymousMaterialCounter;
          anonymousMaterialCounter += 1;
        }
        materialMap.put(material, name);
        writeMaterial(material, name);
      }
     
      objStream.println("usemtl " + name + "_" + layer);
     
      currentMaterial = material;
      currentMaterialLayer = layer;
    }
  }
 
  private List<? extends VectorXYZ> offsetVertices(List<? extends VectorXYZ> vs, List<VectorXYZ> directions, double offset) {
   
    List<VectorXYZ> result = new ArrayList<VectorXYZ>(vs.size());
   
    for (int i = 0; i < vs.size(); i++) {
      result.add(vs.get(i).add(directions.get(i).mult(offset)));
    }
   
    return result;
  }
 
  private int[] verticesToIndices(List<? extends VectorXYZ> vs) {
    return vectorsToIndices(vertexIndexMap, "v ", vs);
  }

  private int[] normalsToIndices(List<? extends VectorXYZ> normals) {
    return vectorsToIndices(normalsIndexMap, "vn ", normals);
  }

  private int[] texCoordsToIndices(List<VectorXZ> texCoords) {
    return vectorsToIndices(texCoordsIndexMap, "vt ", texCoords);
  }
 
  private <V> int[] vectorsToIndices(Map<V, Integer> indexMap,
      String objLineStart, List<? extends V> vectors) {
   
    int[] indices = new int[vectors.size()];
   
    for (int i=0; i<vectors.size(); i++) {
      final V v = vectors.get(i);
      Integer index = indexMap.get(v);
      if (index == null) {
        index = indexMap.size();
        objStream.println(objLineStart + " " + formatVector(v));
        indexMap.put(v, index);
      }
      indices[i] = index;
    }
   
    return indices;
   
  }
 
  private String formatVector(Object v) {
   
    if (v instanceof VectorXYZ) {
      VectorXYZ vXYZ = (VectorXYZ)v;
      return vXYZ.x + " " + vXYZ.y + " " + (-vXYZ.z);
    } else {
      VectorXZ vXZ = (VectorXZ)v;
      return vXZ.x + " " + vXZ.z;
    }
   
  }

  private void writeFace(int[] vertexIndices, int[] normalIndices,
      int[] texCoordIndices) {

    assert normalIndices == null
        || vertexIndices.length == normalIndices.length;

    objStream.print("f");

    for (int i = 0; i < vertexIndices.length; i++) {

      objStream.print(" " + (vertexIndices[i]+1));

      if (texCoordIndices != null && normalIndices == null) {
        objStream.print("/" + (texCoordIndices[i]+1));
      } else if (texCoordIndices == null && normalIndices != null) {
        objStream.print("//" + (normalIndices[i]+1));
      } else if (texCoordIndices != null && normalIndices != null) {
        objStream.print("/" + (texCoordIndices[i]+1)
            + "/" + (normalIndices[i]+1));
      }

    }

    objStream.println();
  }
 
  private void writeMaterial(Material material, String name) {

    for (int i = 0; i < max(1, material.getNumTextureLayers()); i++) {
     
      TextureData textureData = null;
      if (material.getNumTextureLayers() > 0) {
        textureData = material.getTextureDataList().get(i);
      }
   
      mtlStream.println("newmtl " + name + "_" + i);
     
      if (textureData == null || textureData.colorable) {
        writeColorLine("Ka", material.ambientColor());
        writeColorLine("Kd", material.diffuseColor());
        //Ks
        //Ns
      } else {
        writeColorLine("Ka", multiplyColor(WHITE, material.getAmbientFactor()));
        writeColorLine("Kd", multiplyColor(WHITE, 1 - material.getAmbientFactor()));
        //Ks
        //Ns
      }
   
      if (textureData != null) {
        mtlStream.println("map_Ka " + textureData.file);
        mtlStream.println("map_Kd " + textureData.file);
      }
      mtlStream.println();
    }
  }
 
  private void writeColorLine(String lineStart, Color color) {
   
    mtlStream.println(lineStart
        + " " + color.getRed() / 255f
        + " " + color.getGreen() / 255f
        + " " + color.getBlue() / 255f);
   
  }

}
TOP

Related Classes of org.osm2world.core.target.obj.ObjTarget

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.