Package ca.eandb.jmist.framework.loader.obj

Source Code of ca.eandb.jmist.framework.loader.obj.WavefrontObjectReader$LineInterpreter

/**
* Java Modular Image Synthesis Toolkit (JMIST)
* Copyright (C) 2008-2013 Bradley W. Kimmel
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
package ca.eandb.jmist.framework.loader.obj;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.LineNumberReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import ca.eandb.jmist.framework.Material;
import ca.eandb.jmist.framework.SceneElement;
import ca.eandb.jmist.framework.Shader;
import ca.eandb.jmist.framework.color.ColorModel;
import ca.eandb.jmist.framework.geometry.primitive.PolyhedronGeometry;
import ca.eandb.jmist.framework.scene.AppearanceMapSceneElement;
import ca.eandb.jmist.framework.scene.RangeSceneElement;
import ca.eandb.jmist.math.Point2;
import ca.eandb.jmist.math.Point3;
import ca.eandb.jmist.math.Vector3;

/**
* @author Brad Kimmel
*
*/
public final class WavefrontObjectReader {

  public synchronized SceneElement read(File in, ColorModel cm) throws IOException {
    return read(in, 1.0, cm);
  }

  public synchronized SceneElement read(File in, double scale, ColorModel cm) throws IOException {
    return read(in, new HashMap<String, Material>(), scale, cm);
  }

  public synchronized SceneElement read(File in, Map<String, Material> materials, double scale, ColorModel cm) throws IOException {
    return read(in, materials, scale, cm, null);
  }

  public synchronized SceneElement read(File in, ColorModel cm, Map<String, SceneElement> groups) throws IOException {
    return read(in, 1.0, cm, groups);
  }

  public synchronized SceneElement read(File in, double scale, ColorModel cm, Map<String, SceneElement> groups) throws IOException {
    return read(in, new HashMap<String, Material>(), scale, cm, groups);
  }

  public synchronized SceneElement read(File in, Map<String, Material> materials, double scale, ColorModel cm, Map<String, SceneElement> groups) throws IOException {

    FileInputStream stream = new FileInputStream(in);
    LineNumberReader reader = new LineNumberReader(new InputStreamReader(stream));
    State state = new State(in.getParentFile(), scale, cm, groups);

    for (Map.Entry<String, Appearance> entry : this.appearance.entrySet()) {
      Appearance a = entry.getValue();
      state.addAppearance(entry.getKey(), a.material, a.shader);
    }

    while (true) {

      String line = reader.readLine();
      if (line == null) {
        break;
      }
      while (line.endsWith("\\")) {
        line = line.substring(0, line.length() - 1) + " " + reader.readLine();
      }
      line = line.replaceAll("#.*$", "");

      String[] args = line.split("\\s+");
      if (args.length > 0) {
        LineInterpreter interp = getLineInterpreter(args[0]);
        try {
          interp.process(args, state);
        } catch (Exception e) {
          System.err.println("Error occurred on line " + Integer.toString(reader.getLineNumber()));
          e.printStackTrace();
          return null;
        }
      }

    }

    state.endGroup();
    return state.result;

  }

  public void addMaterial(String name, Material material) {
    this.addAppearance(name, material, null);
  }

  public void addAppearance(String name, Material material, Shader shader) {
    Appearance a = new Appearance();
    a.material = material;
    a.shader = shader;
    appearance.put(name, a);
  }

  private static final class Appearance {
    public Material material;
    public Shader shader;
  };

  private final Map<String, Appearance> appearance = new HashMap<String, Appearance>();

  private static void checkArgs(String[] args, State state, int min, int max) {
    int count = args.length - 1;
    if (!(min <= count && count <= max)) {
      if (min == max) {
        state.addErrorMessage(String.format("Expected %d arguments, but got %d.", min, count));
      } else if (max == Integer.MAX_VALUE) {
        state.addErrorMessage(String.format("Expected at least %d arguments, but got %d.", min, count));
      } else {
        state.addErrorMessage(String.format("Expected between %d and %d arguments, but got %d.", min, max, count));
      }
    }
  }

  private static void checkArgs(String[] args, State state, int count) {
    checkArgs(args, state, count, count);
  }


  private static class State {

    /**
     * @param geometry
     */
    public State(File directory, double scale, ColorModel colorModel, Map<String, SceneElement> groups) {
      this.directory = directory;
      this.scale = scale;
      this.colorModel = colorModel;
      this.groups = groups;
    }

    public void addErrorMessage(String format) {
      // TODO Auto-generated method stub

    }

    public void addWarningMessage(String format) {
      // TODO Auto-generated method stub

    }

    public void endGroup() {
      if (groups != null) {
        int fi = geometry.getNumPrimitives();
        if (groupOffset >= 0) {
          groups.put(groupName, new RangeSceneElement(groupOffset, fi - groupOffset, result));
        }
        groupOffset = -1;
        groupName = "";
      }
    }

    public void beginGroup(String name) {
      if (groups != null) {
        int fi = geometry.getNumPrimitives();
        if (groupOffset >= 0) {
          groups.put(groupName, new RangeSceneElement(groupOffset, fi - groupOffset, result));
        }
        groupOffset = fi;
        groupName = name;
      }
    }

    public void addFace(int[] vi, int[] vti, int[] vni) {
      canonicalize(vi, vs.size());
      canonicalize(vti, vts.size());
      canonicalize(vni, vns.size());

      int fi = geometry.getNumPrimitives();
      geometry.addFace(vi, vti, vni);

      if (activeMaterialName != null) {
        appearance.setAppearance(fi, activeMaterialName);
      }
    }

    private void canonicalize(int[] indices, int size) {
      if (indices != null) {
        for (int i = 0; i < indices.length; i++) {
          indices[i] = (indices[i] >= 0) ? indices[i] - 1 : indices[i] + size;
          if (indices[i] < 0 || indices[i] >= size) {
            throw new IndexOutOfBoundsException();
          }
        }
      }
    }

    public void addAppearance(String name, Material material, Shader shader) {
      ensureAppearanceMap();
      appearance.addAppearance(name, material, shader);
      appearanceNames.add(name);
    }

    public boolean hasAppearance(String name) {
      return appearanceNames.contains(name);
    }

    public void addVertex(Point3 p, double w) {
      this.vs.add(new Point3(p.x() * scale, p.y() * scale, p.z() * scale));
      this.weights.add(w);
    }

    public void addTexCoord(Point2 p) {
      this.vts.add(p);
    }

    public void addNormal(Vector3 v) {
      this.vns.add(v);
    }

    public void setActiveMaterial(String name) {
      activeMaterialName = name;
      ensureAppearanceMap();
    }

    private void ensureAppearanceMap() {
      if (appearance == null) {
        appearance = new AppearanceMapSceneElement(geometry);
        result = appearance;
      }
    }

    //private final Map<String, Material> materials = new HashMap<String, Material>();
    private final List<Point3> vs = new ArrayList<Point3>();
    private final List<Point2> vts = new ArrayList<Point2>();
    private final List<Vector3> vns = new ArrayList<Vector3>();
    private final List<Double> weights = new ArrayList<Double>();
    private final Set<String> appearanceNames = new HashSet<String>();

    private String activeMaterialName = null;

    private int groupOffset = -1;
    private String groupName = "";

    private final PolyhedronGeometry geometry = new PolyhedronGeometry(vs, vts, vns);
    private AppearanceMapSceneElement appearance = null;

    private SceneElement result = geometry;

    private final double scale;

    private final File directory;

    private final ColorModel colorModel;

    private final Map<String, SceneElement> groups;

  }

  private static interface LineInterpreter {

    void process(String[] args, State state);

  }

  private LineInterpreter getLineInterpreter(String key) {
    if (lineInterpreters == null) {
      initialize();
    }
    return lineInterpreters.containsKey(key) ? lineInterpreters.get(key) : LI_DEFAULT;
  }

  private static void initialize() {
    lineInterpreters = new HashMap<String, LineInterpreter>();

    lineInterpreters.put("v", LI_V);
    lineInterpreters.put("vt", LI_VT);
    lineInterpreters.put("vn", LI_VN);
    lineInterpreters.put("f", LI_F);
    lineInterpreters.put("usemtl", LI_USEMTL);
    lineInterpreters.put("mtllib", LI_MTLLIB);
    lineInterpreters.put("g", LI_G);
  }

  private static Map<String, LineInterpreter> lineInterpreters = null;

  private static LineInterpreter LI_DEFAULT = new LineInterpreter() {

    public void process(String[] args, State state) {
      state.addWarningMessage(String.format("Unrecognized command: `%s'", args[0]));
    }

  };

  private static LineInterpreter LI_V = new LineInterpreter() {

    public void process(String[] args, State state) {
      checkArgs(args, state, 3, 4);

      state.addVertex(
          new Point3(
              Double.parseDouble(args[1]),
              Double.parseDouble(args[2]),
              Double.parseDouble(args[3])
          ),
          args.length > 4 ? Double.parseDouble(args[4]) : 1.0
      );

    }

  };

  private static LineInterpreter LI_VT = new LineInterpreter() {

    public void process(String[] args, State state) {
      checkArgs(args, state, 2, 3);

      state.addTexCoord(
          new Point2(
              Double.parseDouble(args[1]),
              Double.parseDouble(args[2])));
    }

  };

  private static LineInterpreter LI_VN = new LineInterpreter() {

    public void process(String[] args, State state) {
      checkArgs(args, state, 3, 3);

      state.addNormal(
          new Vector3(
              Double.parseDouble(args[1]),
              Double.parseDouble(args[2]),
              Double.parseDouble(args[3])));
    }

  };

  private static LineInterpreter LI_F = new LineInterpreter() {

    public void process(String[] args, State state) {
      checkArgs(args, state, 3, Integer.MAX_VALUE);

      List<Integer> vertexIndexList = new ArrayList<Integer>();
      List<Integer> textureIndexList = new ArrayList<Integer>();
      List<Integer> normalIndexList = new ArrayList<Integer>();

      for (int i = 1; i < args.length; i++) {
        String[] indices = args[i].split("/", 3);

        vertexIndexList.add(Integer.parseInt(indices[0]));
        if (indices.length > 1 && !indices[1].equals("")) {
          textureIndexList.add(Integer.parseInt(indices[1]));
        }
        if (indices.length > 2 && !indices[2].equals("")) {
          normalIndexList.add(Integer.parseInt(indices[2]));
        }
      }

      int[] vertexIndices = !vertexIndexList.isEmpty() ? new int[vertexIndexList.size()] : null;
      for (int i = 0; i < vertexIndexList.size(); i++) {
        vertexIndices[i] = vertexIndexList.get(i);
      }

      int[] textureIndices = !textureIndexList.isEmpty() ? new int[textureIndexList.size()] : null;
      for (int i = 0; i < textureIndexList.size(); i++) {
        textureIndices[i] = textureIndexList.get(i);
      }

      int[] normalIndices = !normalIndexList.isEmpty() ? new int[normalIndexList.size()] : null;
      for (int i = 0; i < normalIndexList.size(); i++) {
        normalIndices[i] = normalIndexList.get(i);
      }

      state.addFace(vertexIndices, textureIndices, normalIndices);
    }

  };

  private static LineInterpreter LI_USEMTL = new LineInterpreter() {

    public void process(String[] args, State state) {
      checkArgs(args, state, 1);
      state.setActiveMaterial(args[1]);
    }

  };

  private static LineInterpreter LI_MTLLIB = new LineInterpreter() {

    public void process(String[] args, final State state) {

      WavefrontMaterialReader reader = new WavefrontMaterialReader();
      for (int i = 1; i < args.length; i++) {
        File file = new File(state.directory, args[i]);
        try {
          reader.read(file, state.colorModel, new AppearanceVisitor() {
            public void visit(String name, Material material,
                Shader shader) {
              if (!state.hasAppearance(name)) {
                state.addAppearance(name, material, shader);
              }
            }
          });
        } catch (FileNotFoundException e) {
          state.addErrorMessage("File not found: " + args[i]);
          e.printStackTrace();
        } catch (IOException e) {
          state.addErrorMessage("Could not read file: " + args[i]);
          e.printStackTrace();
        }

      }

    }

  };
  private static LineInterpreter LI_G = new LineInterpreter() {

    public void process(String[] args, State state) {
      checkArgs(args, state, 1);
      state.beginGroup(args[1]);
    }

  };


}
TOP

Related Classes of ca.eandb.jmist.framework.loader.obj.WavefrontObjectReader$LineInterpreter

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.