package glmodel; import java.io.*; import java.util.ArrayList; import java.util.StringTokenizer; import glapp.*; /** * Loads a library of materials from a .mtl file into an array of GLMaterial objects. */ public class GLMaterialLib { // path to the .mtl file (loadMaterial() will set these) // we'll load texture images from same folder as material file public String filepath = ""; public String filename = ""; // array of materials loaded from .mtl file GLMaterial[] materials; public GLMaterialLib(String mtlFilename) { if (mtlFilename != null && mtlFilename.length() > 0) { materials = loadMaterials(mtlFilename); } } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * functions to load and save materials (from/to .mtl file) * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ public GLMaterial[] loadMaterials(String mtlFilename) { GLMaterial[] mtls = null; // Separate leading path from filename (we'll load textures from same folder) String[] pathParts = GLApp.getPathAndFile(mtlFilename); filepath = pathParts[0]; filename = pathParts[1]; // read the mtl file try { mtls = loadMaterials(new BufferedReader(new InputStreamReader(GLApp.getInputStream(mtlFilename)))); } catch (Exception e) { System.out.println("GLMaterialLib.loadMaterials(): Exception when loading " + mtlFilename + ": " + e); } return mtls; } /** * MTL file format in a nutshell: * *
     * 		newmtl white          // begin material and specify name
     * 		Kd 1.0 1.0 1.0        // diffuse rgb
     * 		Ka 0.2 0.2 0.2        // ambient rgb
     * 		Ks 0.6 0.6 0.6        // specular rgb
     * 		Ns 300                // shininess 0-1000
     *      d 0.5                 // alpha 0-1
     *      map_Kd texture.jpg    // texture file
     *                            // blank line ends material definition
     * 
*/ public GLMaterial[] loadMaterials(BufferedReader br) { ArrayList mtlslist = new ArrayList(); GLMaterial material = null; String line = ""; float[] rgb; try { while ((line = br.readLine()) != null) { // remove extra whitespace line = line.trim(); if (line.length() > 0) { if (line.startsWith("#")) { // ignore comments } else if (line.startsWith("newmtl")) { // newmtl some_name material = new GLMaterial(); // start new material material.setName(line.substring(7)); mtlslist.add(material); // add to list } else if (line.startsWith("Kd")) { // Kd 1.0 0.0 0.5 if ((rgb = read3Floats(line)) != null) { material.setDiffuse(rgb); } } else if (line.startsWith("Ka")) { // Ka 1.0 0.0 0.5 if ((rgb = read3Floats(line)) != null) { material.setAmbient(rgb); } } else if (line.startsWith("Ks")) { // Ks 1.0 0.0 0.5 if ((rgb = read3Floats(line)) != null) { material.setSpecular(rgb); } } else if (line.startsWith("Ns")) { // Ns 500.5 // shininess in mtl file is 0-1000 if ((rgb = read3Floats(line)) != null) { // convert to opengl 0-127 int shininessValue = (int) ((rgb[0] / 1000f) * 127f); material.setShininess( shininessValue ); } } else if (line.startsWith("d")) { // d 1.0 // alpha value of material 0=transparent 1=opaque if ((rgb = read3Floats(line)) != null) { material.setAlpha( rgb[0] ); } } else if (line.startsWith("illum")) { // illum (0, 1, or 2) // lighting for material 0=disable, 1=ambient & diffuse (specular is black), 2 for full lighting. if ((rgb = read3Floats(line)) != null) { // not yet } } else if (line.startsWith("map_Kd")) { // map_Kd filename // add a texture to the material String textureFile = line.substring(7); if (textureFile != null && !textureFile.equals("")) { int textureHandle = 0; try { textureHandle = GLApp.makeTexture(filepath + textureFile); } catch (Exception e) { System.out.println("GLMaterialLib.loadMaterials(): could not load texture file (" +line+ ")" + e); } material.setTextureFile(textureFile); material.setTexture(textureHandle); } } } } } catch (Exception e) { System.out.println("GLMaterialLib.loadMaterials() failed at line: " + line); } // debug: System.out.println("GLMaterialLib.loadMaterials(): loaded " + mtlslist.size() + " materials "); // return array of materials GLMaterial[] mtls = new GLMaterial[ mtlslist.size() ]; mtlslist.toArray(mtls); return mtls; } // always return array of four floats (usually containing RGBA, but // in some cases contains only one value at pos 0). private float[] read3Floats(String line) { try { StringTokenizer st = new StringTokenizer(line, " "); st.nextToken(); // throw out line identifier (Ka, Kd, etc.) if (st.countTokens() == 1) { return new float[] {Float.parseFloat(st.nextToken()), 0f, 0f, 0f}; } else if (st.countTokens() == 3) { // RGBA (force A to 1) return new float[] {Float.parseFloat(st.nextToken()), Float.parseFloat(st.nextToken()), Float.parseFloat(st.nextToken()), 1f }; } } catch (Exception e) { System.out.println("GLMaterialLib.read3Floats(): error on line '" + line + "', " + e); } return null; } /** * Write an array of GLMaterial objects to a .mtl file. * @param mtls array of materials to write to file * @param filename name of .mtl file */ public void writeLibe(GLMaterial[] mtls, String filename) { try { PrintWriter mtlfile = new PrintWriter(new FileWriter(filename)); writeLibe(mtls, mtlfile); mtlfile.close(); } catch (IOException e) { System.out.println("GLMaterialLib.writeLibe(): IOException:" + e); } } public void writeLibe(GLMaterial[] mtls, PrintWriter out) { if (out != null) { out.println("#"); out.println("# Wavefront material file for use with OBJ file"); out.println("# Created by GLMaterialLib.java"); out.println("#"); out.println(""); for (int i = 0; i < mtls.length; i++) { write(out, mtls[i]); } } } /** * Write one material. */ public void write(PrintWriter out, GLMaterial mtl) { if (out != null) { out.println("newmtl " + mtl.mtlname); out.println("Ka " + mtl.ambient.get(0) + " " + mtl.ambient.get(1) + " " + mtl.ambient.get(2)); out.println("Kd " + mtl.diffuse.get(0) + " " + mtl.diffuse.get(1) + " " + mtl.diffuse.get(2)); out.println("Ks " + mtl.specular.get(0) + " " + mtl.specular.get(1) + " " + mtl.specular.get(2)); out.println("Ns " + ( (mtl.shininess.get(0) / 128.0) * 1000.0)); if (mtl.textureFile != null && !mtl.textureFile.equals("")) { out.println("map_Kd " + mtl.textureFile); } if (mtl.getAlpha() != 1f) { out.println("d " + mtl.getAlpha()); } out.println(""); } } /** * return a duplicate of this material. all values are duplicated except * the texture, which is passed by reference to the clone (to prevent * multiple copies of the same texture). * * @return the cloned material */ public GLMaterial getClone(GLMaterial mtl) { GLMaterial clone = new GLMaterial(); clone.setDiffuse( new float[] {mtl.diffuse.get(0),mtl.diffuse.get(1),mtl.diffuse.get(2),mtl.diffuse.get(3)} ); clone.setAmbient( new float[] {mtl.ambient.get(0),mtl.ambient.get(1),mtl.ambient.get(2),mtl.ambient.get(3)} ); clone.setSpecular( new float[] {mtl.specular.get(0),mtl.specular.get(1),mtl.specular.get(2),mtl.specular.get(3)} ); clone.setGlowColor( new float[] {mtl.emission.get(0),mtl.emission.get(1),mtl.emission.get(2),mtl.emission.get(3)} ); clone.setShininess( mtl.shininess.get(0) ); // set the texture filename and handle in the clone (clones share 1 texture) clone.textureFile = mtl.textureFile; clone.textureHandle = mtl.textureHandle; clone.setName( mtl.mtlname + "-copy"); return clone; } /** * find a material by name in an array of GLMaterial objects */ public GLMaterial find(String materialName) { int mtl_idx = findID(materialName); if (mtl_idx >= 0) { return materials[mtl_idx]; } return null; } /** * find a material by name in an array of GLMaterial objects * return the array index of the material */ public int findID(String materialName) { if (materials != null && materialName != null) { for (int m=0; m < materials.length; m++) { if (materials[m].mtlname.equals(materialName)) { return m; } } } return -1; } }