Hello Friends
I m creating a swing based application using java 3d API.
When I apply textures to single object and then loading is fine .
But problem is that I m not able to load the scene if i tried to apply textures from material file on multi objects.

private scenebase CreateScene() is the function where i am applying all the textures to scene and returning back for appearance.The code in red is the point where i m calling the function and scene is not getting dispalyed.
I m also providing the related code below:
/*
 
 
package print_canvas3d;
import com.sun.j3d.utils.universe.*;
import java.net.MalformedURLException;
import javax.media.j3d.*;
import javax.vecmath.*;
import java.awt.*;
import java.awt.GraphicsConfiguration;
import javax.swing.JPopupMenu;
 
import com.sun.j3d.loaders.objectfile.ObjectFile;
import com.sun.j3d.loaders.ParsingErrorException;
import com.sun.j3d.loaders.IncorrectFormatException;
import com.sun.j3d.loaders.Scene;
import java.awt.image.BufferedImage;
import java.io.*;
import com.sun.j3d.utils.behaviors.mouse.*;
import java.net.URL;
import com.sun.j3d.utils.scenegraph.io.SceneGraphFileReader;
 
import com.sun.j3d.utils.geometry.GeometryInfo;
import javax.media.j3d.GeometryArray;
import com.sun.j3d.utils.image.TextureLoader;
import javax.media.j3d.TexCoordGeneration;
import javax.media.j3d.Texture;
import javax.media.j3d.Texture2D;
import javax.media.j3d.TextureAttributes;
import javax.media.j3d.TextureUnitState;
import javax.media.j3d.WakeupOnElapsedFrames;
import java.util.Enumeration;
 
 import java.io.Reader;
import java.io.StreamTokenizer;
import java.io.StringReader;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.StringReader;
import javax.imageio.*;
import com.sun.j3d.loaders.SceneBase;
import com.sun.j3d.utils.geometry.NormalGenerator;
import java.util.*;
 
public class PrintCanvas3D extends javax.swing.JFrame {
 
    private static final boolean noTriangulate = false;
    private static final boolean noStripify = false;
    private static final double creaseAngle = 60.0;
    private Canvas3D onScreenCanvas3D;
    private OffScreenCanvas3D offScreenCanvas3D;
    private URL filename = null;
    private static final int OFF_SCREEN_SCALE = 3;
 
    private SimpleUniverse univ = null;
 
TransformGroup[] viewGroups;
 
    Hashtable hashtable;
     TextureUnitState[] tusArr;
      Appearance appearance;
    /** polygonAttributes will be changed at runtime **/
    PolygonAttributes polygonAttributes;
 
 
    int tsize=0;
    long tnormals=0;
    long tcoord=0;
      List<Point3f>           vertices;
     List<TexCoord2f>        textureCoodinates;
     List<Vector3f>          normals;
     Map<String, Group>      groups;
     Group                   currentGroup;
     String                  currentMaterial;
     Map<String, Appearance> appearances;
 private Map<String, Appearance> DEFAULT_APPEARANCES;
 
    //******************************************************
List<Point3f>           texvertices;
     List<TexCoord2f>        textextureCoodinates;
     List<Vector3f>          texnormals;
 
  private SceneGraphFileReader reader = null;
 
 
private java.net.URL texImage = null;
 
 
    private boolean allowNonPowerOfTwo = true;
    private boolean mipmap = true;
 
        // TextureUnitStates used in this application
    TextureUnitState tuLightMap;
    TextureUnitState tuDOT3NormalMap;
    TextureUnitState tuColor;
    Texture textureColor;
    Texture textureDOT3NormalMap;
    Texture2D textureLightMap;
    // needs for runtime updates on lightMap
    ImageComponent2D imageLightMap;
    Shape3D shape = null;
    // default texture names used
    String  textureColorName= "wood.jpg";
    String textureDOT3NormalMapName = "Java3Ddot3.jpg";
 
 
    public BranchGroup createSceneGraph(String args[]) {
	// Create the root of the branch graph
	BranchGroup objRoot = new BranchGroup();
 
	// Create a Transformgroup to scale all objects so they
	// appear in the scene.
	TransformGroup objScale = new TransformGroup();
	Transform3D t3d = new Transform3D();
	t3d.setScale(0.7);
	objScale.setTransform(t3d);
	objRoot.addChild(objScale);
 
	// Create the transform group node and initialize it to the
	// identity.  Enable the TRANSFORM_WRITE capability so that
	// our behavior code can modify it at runtime.  Add it to the
	// root of the subgraph.
	TransformGroup objTrans = new TransformGroup();
	objTrans.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
	objTrans.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
	objScale.addChild(objTrans);
 
 
 
 
	int flags = ObjectFile.RESIZE;
	if (!noTriangulate) flags |= ObjectFile.TRIANGULATE;
	if (!noStripify) flags |= ObjectFile.STRIPIFY;
	ObjectFile f =
	    new ObjectFile(flags, 
			   (float)(creaseAngle * Math.PI / 180.0));
	Scene scene = null;
 
 
 
 
 
 
 
 try {
                       String JAVA_3D_MATERIALS=readMaterial();
                DEFAULT_APPEARANCES = parseMaterialStream(new StringReader(JAVA_3D_MATERIALS), null);
 
 
                } catch (IOException ex) {
      // Can't happen because materials are read from a string
                throw new InternalError("Can't access to default materials");
                }
 
                try
                {
                //URL uname=new URL("d:\\Solidview");
                File fname=new File("d:\\Solidview\\MultipleObject.obj");
                Reader r=new FileReader(fname);
 
 
 
 
 
try {
	  [COLOR="Red"]  scene=load(r,fname.toURL()); //f.load(filename[/COLOR]);
 
            }
 
 
               objTrans.addChild(scene.getSceneGroup());
 
	}
	catch (FileNotFoundException e) {
	    System.err.println(e);
	    System.exit(1);
	}
	catch (ParsingErrorException e) {
	    System.err.println(e);
	    System.exit(1);
	}
	catch (IncorrectFormatException e) {
	    System.err.println(e);
	    System.exit(1);
	}
 
 
 
           //    BranchGroup resultedobject=obj.getSceneGroup();
 
              // objRoot.addChild(resultedobject);
              //  objRoot.compile();
                }catch(MalformedURLException ex)
                {
                ex.printStackTrace();
                }catch(FileNotFoundException fe)
                {
                    fe.printStackTrace();
                }catch(IOException ie)
                {
                    ie.printStackTrace();
                }
BoundingSphere bounds =
	    new BoundingSphere(new Point3d(0.0,20.0,0.0), 100.0);
 
        // Create the rotate behavior node
        MouseRotate behavior = new MouseRotate();
        behavior.setTransformGroup(objTrans);
        objTrans.addChild(behavior);
        behavior.setSchedulingBounds(bounds);
 
        // Create the zoom behavior node
        MouseZoom behavior2 = new MouseZoom();
        behavior2.setTransformGroup(objTrans);
        objTrans.addChild(behavior2);
        behavior2.setSchedulingBounds(bounds);
 
        // Create the translate behavior node
        MouseTranslate behavior3 = new MouseTranslate();
        behavior3.setTransformGroup(objTrans);
        objTrans.addChild(behavior3);
        behavior3.setSchedulingBounds(bounds);
 
 
	// Set up the background
	Color3f bgColor = new Color3f(0.05f, 0.05f, 0.5f);
	Background bgNode = new Background(bgColor);
	bgNode.setApplicationBounds(bounds);
	objRoot.addChild(bgNode);
 
	// Set up the ambient light
	Color3f ambientColor = new Color3f(0.1f, 0.1f, 0.1f);
	AmbientLight ambientLightNode = new AmbientLight(ambientColor);
	ambientLightNode.setInfluencingBounds(bounds);
 
	objRoot.addChild(ambientLightNode);
 
	// Set up the directional lights
	Color3f light1Color = new Color3f(1.0f, 1.0f, 0.9f);
	Vector3f light1Direction  = new Vector3f(4.0f, -7.0f, -12.0f);
	Color3f light2Color = new Color3f(0.3f, 0.3f, 0.4f);
	Vector3f light2Direction  = new Vector3f(-6.0f, -2.0f, -1.0f);
 
	DirectionalLight light1
	    = new DirectionalLight(light1Color, light1Direction);
	light1.setInfluencingBounds(bounds);
	objRoot.addChild(light1);
 
	DirectionalLight light2
	    = new DirectionalLight(light2Color, light2Direction);
	light2.setInfluencingBounds(bounds);
	objRoot.addChild(light2);
 
 
 
 
	//objTrans.addChild(scene.getSceneGroup());
       // objRoot=scene.getSceneGroup();
 
 
 
 
 
 
	return objRoot;
    }
 
    private void usage() {
	System.out.println("Usage: java PrintCanvas3D <.obj file>");
	System.exit(0);
    } // End of usage
 
    private OffScreenCanvas3D createOffScreenCanvas(Canvas3D onScreenCanvas3D) {
	// Create the off-screen Canvas3D object
	// request an offscreen Canvas3D with a single buffer configuration
	GraphicsConfigTemplate3D template = new GraphicsConfigTemplate3D();
	template.setDoubleBuffer(GraphicsConfigTemplate3D.UNNECESSARY);
	GraphicsConfiguration gc = 
                GraphicsEnvironment.getLocalGraphicsEnvironment().
                getDefaultScreenDevice().getBestConfiguration(template);
 
	offScreenCanvas3D = new OffScreenCanvas3D(gc, true);
	// Set the off-screen size based on a scale factor times the
	// on-screen size
	Screen3D sOn = onScreenCanvas3D.getScreen3D();
	Screen3D sOff = offScreenCanvas3D.getScreen3D();
	Dimension dim = sOn.getSize();
	dim.width *= OFF_SCREEN_SCALE;
	dim.height *= OFF_SCREEN_SCALE;
	sOff.setSize(dim);
	sOff.setPhysicalScreenWidth(sOn.getPhysicalScreenWidth() *
				    OFF_SCREEN_SCALE);
	sOff.setPhysicalScreenHeight(sOn.getPhysicalScreenHeight() *
				     OFF_SCREEN_SCALE);
 
	// attach the offscreen canvas to the view
	univ.getViewer().getView().addCanvas3D(offScreenCanvas3D);        
 
        return offScreenCanvas3D;
 
    }
 
    private Canvas3D createUniverse() {
	GraphicsConfiguration config =
	    SimpleUniverse.getPreferredConfiguration();
 
	Canvas3D c = new Canvas3D(config);
 
	univ = new SimpleUniverse(c);
 
	// This will move the ViewPlatform back a bit so the
	// objects in the scene can be viewed.
        univ.getViewingPlatform().setNominalViewingTransform();
 
	// Ensure at least 5 msec per frame (i.e., < 200Hz)
	univ.getViewer().getView().setMinimumFrameCycleTime(5);
 
	return c;
    }
 
    /**
     * Creates new form PrintCanvas3D
     */
    public PrintCanvas3D(String args[]) {
 
        System.out.println(args.length);
        if (args.length == 0) {
            //filename = getResource("resources/geometry/dinasaur.obj");
            //filename=getResource("ImagePrinter.java");
            try
            {
 
 
              File fname=new File("c:\\dinasaur.obj");
              filename=fname.toURL();
              }
            catch(MalformedURLException e)
            {
                e.printStackTrace();
            }
 
            if (filename == null) {
                System.out.println(filename.getFile());
                System.err.println("resources/geometry/beethoven.obj not found");
                System.exit(1);
            }
        } else {
            for (int i = 0 ; i < args.length ; i++) {
                if (args[i].startsWith("-")) {
                    System.err.println("Argument '" + args[i] + "' ignored.");
                } else {
                    try{
 
                        //filename = new URL(args[i]);
                        File fname=new File(args[i]);
                        filename=fname.toURL();
 
 
                        //filename=new URL()
                    }
                    catch (MalformedURLException e) {
                        System.out.println(args[i]);
                        System.err.println(e.getMessage());
                        System.exit(1);
                    }
                }
            }
        }
 
        if (filename == null) {
            usage();
        }
 
        // Initialize the GUI components
        JPopupMenu.setDefaultLightWeightPopupEnabled(false);
        initComponents();        
 
        // Create Canvas3D and SimpleUniverse; add canvas to drawing panel
        onScreenCanvas3D = createUniverse();
        drawingPanel.add(onScreenCanvas3D, java.awt.BorderLayout.CENTER);
 
        // Create the content branch and add it to the universe
 
 
 
        BranchGroup scene = createSceneGraph(args);
     //   BranchGroup scene =buildShape();
	// Create the off-screen Canvas3D object
 
 
       createOffScreenCanvas(onScreenCanvas3D);
 
        univ.addBranchGraph(scene);
    }
 
    // ----------------------------------------------------------------
 
    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    // <editor-fold defaultstate="collapsed" desc=" Generated Code ">//GEN-BEGIN:initComponents
    private void initComponents() {
        drawingPanel = new javax.swing.JPanel();
        jMenuBar1 = new javax.swing.JMenuBar();
        fileMenu = new javax.swing.JMenu();
        snapShotMenuItem = new javax.swing.JMenuItem();
        printMenuItem = new javax.swing.JMenuItem();
        exitMenuItem = new javax.swing.JMenuItem();
 
        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        setTitle("Window Title");
        drawingPanel.setLayout(new java.awt.BorderLayout());
 
        drawingPanel.setPreferredSize(new java.awt.Dimension(500, 500));
        getContentPane().add(drawingPanel, java.awt.BorderLayout.CENTER);
 
        fileMenu.setText("File");
        snapShotMenuItem.setText("Snapshot");
        snapShotMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                snapShotMenuItemActionPerformed(evt);
            }
        });
 
        fileMenu.add(snapShotMenuItem);
 
        printMenuItem.setText("Print");
        printMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                printMenuItemActionPerformed(evt);
            }
        });
 
        fileMenu.add(printMenuItem);
 
        exitMenuItem.setText("Exit");
        exitMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                exitMenuItemActionPerformed(evt);
            }
        });
 
        fileMenu.add(exitMenuItem);
 
        jMenuBar1.add(fileMenu);
 
        setJMenuBar(jMenuBar1);
 
        pack();
    }// </editor-fold>//GEN-END:initComponents
 
    private void printMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_printMenuItemActionPerformed
	Point loc = onScreenCanvas3D.getLocationOnScreen();
	offScreenCanvas3D.setOffScreenLocation(loc);
	Dimension dim = onScreenCanvas3D.getSize();
	dim.width *= OFF_SCREEN_SCALE;
	dim.height *= OFF_SCREEN_SCALE;
	BufferedImage bImage =
	    offScreenCanvas3D.doRender(dim.width, dim.height);
 
        new ImagePrinter(bImage).print();
 
    }//GEN-LAST:event_printMenuItemActionPerformed
 
    private void snapShotMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_snapShotMenuItemActionPerformed
	Point loc = onScreenCanvas3D.getLocationOnScreen();
	offScreenCanvas3D.setOffScreenLocation(loc);
	Dimension dim = onScreenCanvas3D.getSize();
	dim.width *= OFF_SCREEN_SCALE;
	dim.height *= OFF_SCREEN_SCALE;
	BufferedImage bImage =
	    offScreenCanvas3D.doRender(dim.width, dim.height);
 
	new ImageDisplayer(bImage);
 
 
    }//GEN-LAST:event_snapShotMenuItemActionPerformed
 
    private void exitMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_exitMenuItemActionPerformed
        System.exit(0);
    }//GEN-LAST:event_exitMenuItemActionPerformed
 
 
//     public static URL getResource(String filename) {
//         URL url = Resources.class.getResource(filename);
//         return url;
//    }
 
 
 public String readMaterial()
 {
     String mtlcontent="";
     String temp="";
     int i=0;
    File file = new File("d:\\SolidView\\MultipleObject.mtl");
    FileInputStream fis = null;
    BufferedInputStream bis = null;
    DataInputStream dis = null;
    try {
      fis = new FileInputStream(file);
 
      // Here BufferedInputStream is added for fast reading.
      bis = new BufferedInputStream(fis);
      dis = new DataInputStream(bis);
 
      // dis.available() returns 0 if the file does not have more lines.
      while (dis.available() != 0) {
 
      // this statement reads the line from the file and print it to
        // the console.
   //     System.out.println(dis.readLine());
          //temp=dis.readLine();
          if(i>2)
          {
          mtlcontent+=dis.readLine();
          mtlcontent+="\n";
          }
          else
          {
              dis.readLine();
              i++;
          }
 
      }
 
      // dispose all the resources after using them.
      fis.close();
      bis.close();
      dis.close();
 
    } catch (FileNotFoundException e) {
      e.printStackTrace();
    } catch (IOException e) {
      e.printStackTrace();
    }
    return mtlcontent;
 
 }
 
 /**
   * Parses a map of appearances parsed from the given stream.
   */
  private static Map<String, Appearance> parseMaterialStream(Reader reader,
                                                             URL baseUrl) throws IOException {
    Map<String, Appearance> appearances = new HashMap<String, Appearance>();
    Appearance              currentAppearance = null;
    StreamTokenizer tokenizer = createTokenizer(reader);
    while (tokenizer .nextToken() != StreamTokenizer.TT_EOF) {
      switch (tokenizer.ttype) {
        case StreamTokenizer.TT_WORD :
          currentAppearance = parseMaterialLine(tokenizer,
              appearances, currentAppearance, baseUrl);
 
          break;
        case StreamTokenizer.TT_EOL:
          break;
        default :
          throw new IncorrectFormatException("Unexpected token " + tokenizer.sval
              + " at row " + tokenizer.lineno());
      }
    }
    return appearances;
  }
  /**
   * Returns a new tokenizer for an OBJ or MTL stream.
   */
  private static StreamTokenizer createTokenizer(Reader reader) {
    StreamTokenizer tokenizer = new StreamTokenizer(reader);
    tokenizer.resetSyntax();
    tokenizer.eolIsSignificant(true);
 
    // All printable ASCII characters
    tokenizer.wordChars('!', '~');
    // Let's tolerate other ISO-8859-1 characters
    tokenizer.wordChars(0x80, 0xFF);
 
    tokenizer.whitespaceChars(' ', ' ');
    tokenizer.whitespaceChars('\n', '\n');
    tokenizer.whitespaceChars('\r', '\r');
    tokenizer.whitespaceChars('\t', '\t');
    return tokenizer;
  }
 
    /**
   * Parses the line starting with a word describing a material.
   */
  private static Appearance parseMaterialLine(StreamTokenizer tokenizer,
                                              Map<String, Appearance> appearances,
                                              Appearance currentAppearance,
                                              URL baseUrl) throws IOException {
    if ("newmtl".equals(tokenizer.sval)) {
      // Read material name newmtl name
      if (tokenizer.nextToken() == StreamTokenizer.TT_WORD) {
        currentAppearance = new Appearance();
        appearances.put(tokenizer.sval, currentAppearance);
      } else {
        throw new IncorrectFormatException("Expected material name at line " + tokenizer.lineno());
      }
    } else if ("Ka".equals(tokenizer.sval)) {
      // Read ambient color Ka r g b
      Color3f ambiantColor = new Color3f(parseNumber(tokenizer),
          parseNumber(tokenizer), parseNumber(tokenizer));
      if (currentAppearance != null) {
        Material material = getMaterial(currentAppearance);
        material.setAmbientColor(ambiantColor);
      }
    } else if ("Kd".equals(tokenizer.sval)) {
      // Read diffuse or emissive color Kd r g b
      Color3f diffuseColor = new Color3f(parseNumber(tokenizer),
          parseNumber(tokenizer), parseNumber(tokenizer));
      if (currentAppearance != null) {
        OBJMaterial material = getMaterial(currentAppearance);
        material.setDiffuseColor(diffuseColor);
        currentAppearance.setColoringAttributes(
            new ColoringAttributes(diffuseColor, ColoringAttributes.SHADE_GOURAUD));
      }
    } else if ("Ks".equals(tokenizer.sval)) {
      // Read specular color Ks r g b
      Color3f specularColor = new Color3f(parseNumber(tokenizer),
          parseNumber(tokenizer), parseNumber(tokenizer));
      if (currentAppearance != null) {
        OBJMaterial material = getMaterial(currentAppearance);
        if (!material.isIlluminationModelSet()
            || material.getIlluminationModel() >= 2) {
          material.setSpecularColor(specularColor);
        } else {
          material.setSpecularColor(0, 0, 0);
        }
      }
    } else if ("Ns".equals(tokenizer.sval)) {
      // Read shininess Ns val  with 0 <= val <= 1000
      float shininess = parseNumber(tokenizer);
      if (currentAppearance != null) {
        OBJMaterial material = getMaterial(currentAppearance);
        if (!material.isIlluminationModelSet()
            || material.getIlluminationModel() >= 2) {
          // Use shininess at a max value equal to 128
          material.setShininess(Math.max(1f, Math.min(shininess, 128f)));
        } else {
          material.setShininess(1f);
        }
      }
    } else if ("Ni".equals(tokenizer.sval)) {
      // Read optical density Ni val
      float opticalDensity = parseNumber(tokenizer);
      if (currentAppearance != null) {
        OBJMaterial material = getMaterial(currentAppearance);
        material.setOpticalDensity(opticalDensity);
      }
    } else if ("sharpness".equals(tokenizer.sval)) {
      // Read sharpness sharpness val
      float sharpness = parseNumber(tokenizer);
      if (currentAppearance != null) {
        OBJMaterial material = getMaterial(currentAppearance);
        material.setSharpness(sharpness);
      }
    } else if ("d".equals(tokenizer.sval)) {
      // Read transparency d val  with 0 <= val <= 1
      if (tokenizer.nextToken() == StreamTokenizer.TT_WORD) {
        if ("-halo".equals(tokenizer.sval)) {
          // Ignore halo transparency
          parseNumber(tokenizer);
        } else {
          tokenizer.pushBack();
          float transparency = parseNumber(tokenizer);
          if (currentAppearance != null) {
            if (transparency >= 1) {
              currentAppearance.setTransparencyAttributes(null);
            } else {
              currentAppearance.setTransparencyAttributes(new TransparencyAttributes(
                  TransparencyAttributes.NICEST, 1f - Math.max(0f, transparency)));
            }
          }
        }
      } else {
        throw new IncorrectFormatException("Expected transparency factor at line " + tokenizer.lineno());
      }
    } else if ("illum".equals(tokenizer.sval)) {
      // Read illumination setting illum n
      int illumination = parseInteger(tokenizer);
      if (currentAppearance != null) {
        OBJMaterial material = getMaterial(currentAppearance);
        material.setIlluminationModel(illumination);
        material.setLightingEnable(illumination >= 1);
        if (illumination <= 1) {
          material.setSpecularColor(0, 0, 0);
          material.setShininess(1f);
        }
      }
    } else if ("map_Kd".equals(tokenizer.sval)) {
      // Read material texture map_Kd name
      // Search last parameter that matches image file name
      String imageFileName = null;
      while (tokenizer.nextToken() != StreamTokenizer.TT_EOL) {
        if (tokenizer.ttype == StreamTokenizer.TT_WORD) {
          imageFileName = tokenizer.sval;
        }
      }
 
      if (imageFileName != null) {
        BufferedImage textureImage = null;
        try {
          textureImage = baseUrl != null
               ? ImageIO.read(new URL(baseUrl, imageFileName))
               : ImageIO.read(new File(imageFileName));
        } catch (IOException ex) {
          ex.printStackTrace();
            // Ignore images at other format
        }
        if (textureImage != null) {
          TextureLoader textureLoader = new TextureLoader(textureImage, TextureLoader.GENERATE_MIPMAP);
          currentAppearance.setTexture(textureLoader.getTexture());
          System.out.println(imageFileName);
        }
      } else {
        throw new IncorrectFormatException("Expected image file name at line " + tokenizer.lineno());
      }
      tokenizer.pushBack();
    } else {
      // Skip other lines (including comment lines starting by #)
      while (tokenizer.nextToken() != StreamTokenizer.TT_EOL) {
      }
      tokenizer.pushBack();
    }
 
    if (tokenizer.nextToken() != StreamTokenizer.TT_EOL) {
      throw new IncorrectFormatException("Expected end of line at line " + tokenizer.lineno());
    }
 
    return currentAppearance;
  }
 
    /**
   * Returns the material stored in the given <code>appearance</code>.
   */
  private static OBJMaterial getMaterial(Appearance appearance) {
    OBJMaterial material = (OBJMaterial)appearance.getMaterial();
    if (material == null) {
      material = new OBJMaterial();
      appearance.setMaterial(material);
    }
    return material;
  }
 
   /**
   * Returns the number contained in the next token.
   */
  private static float parseNumber(StreamTokenizer tokenizer) throws IOException {
    if (tokenizer.nextToken() != StreamTokenizer.TT_WORD) {
      throw new IncorrectFormatException("Expected a number at line " + tokenizer.lineno());
    } else {
      try {
        return Float.parseFloat(tokenizer.sval);
      } catch (NumberFormatException ex) {
        throw new IncorrectFormatException("Found " + tokenizer.sval +
            " instead of a number at line " + tokenizer.lineno());
      }
    }
  }
 
 
 /**
   * Returns the integer contained in the next token.
   */
  private static int parseInteger(StreamTokenizer tokenizer) throws IOException {
    if (tokenizer.nextToken() != StreamTokenizer.TT_WORD) {
      throw new IncorrectFormatException("Expected an integer at line " + tokenizer.lineno());
    } else {
      try {
        return Integer.parseInt(tokenizer.sval);
      } catch (NumberFormatException ex) {
        throw new IncorrectFormatException("Found " + tokenizer.sval +
            " instead of an integer at line " + tokenizer.lineno());
      }
    }
  }
 
 
  /**
   * Returns the appearance matching a given <code>material</code>.
   */
  private Appearance getAppearance(String material) {
    Appearance appearance = null;
    if (material != null) {
 
      appearance = this.appearances.get(material);
    }
    if (appearance == null) {
      appearance = DEFAULT_APPEARANCES.get("default");
    }
    return appearance;
  }
 
    private static class Face {
    private int [] vertexIndices;
    private int [] textureCoordinateIndices;
    private int [] normalIndices;
    private String material;
 
    public Face(List<Integer> vertexIndices,
                List<Integer> textureCoordinateIndices,
                List<Integer> normalIndices,
                String        material) {
      this.vertexIndices = new int [vertexIndices.size()];
      for (int i = 0; i < this.vertexIndices.length; i++) {
        this.vertexIndices [i] = vertexIndices.get(i);
      }
      if (textureCoordinateIndices.size() != 0) {
        this.textureCoordinateIndices = new int [textureCoordinateIndices.size()];
        for (int i = 0; i < this.textureCoordinateIndices.length; i++) {
          this.textureCoordinateIndices [i] = textureCoordinateIndices.get(i);
        }
      }
      if (normalIndices.size() != 0) {
        this.normalIndices = new int [normalIndices.size()];
        for (int i = 0; i < this.normalIndices.length; i++) {
          this.normalIndices [i] = normalIndices.get(i);
        }
      }
      this.material = material;
    }
 
    public int [] getVertexIndices() {
      return this.vertexIndices;
    }
 
    public int [] getTextureCoordinateIndices() {
      return this.textureCoordinateIndices;
    }
 
    public boolean hasTextureCoordinateIndices() {
      return this.textureCoordinateIndices != null
          && this.textureCoordinateIndices.length > 0;
    }
 
    public int [] getNormalIndices() {
      return this.normalIndices;
    }
 
    public boolean hasNormalIndices() {
      return this.normalIndices != null
          && this.normalIndices.length > 0;
    }
 
    public String getMaterial() {
      return this.material;
    }
  }
 
 
     private static class Group {
    private final String name;
    private boolean      smooth;
    private List<Face>   faces;
 
    public Group(String name) {
      this.name = name;
      this.faces = new ArrayList<Face>();
    }
 
    public String getName() {
      return this.name;
    }
 
    public void setSmooth(boolean smooth) {
      this.smooth = smooth;
    }
 
    public boolean isSmooth() {
      return this.smooth;
    }
 
    public void addFace(Face face) {
      this.faces.add(face);
    }
 
    public List<Face> getFaces() {
      return this.faces;
    }
  }
 
      /**
   * Returns the scene parsed from a stream.
   */
  private Scene parseObjectStream(Reader reader,
                                  URL baseUrl) throws IOException {
    this.vertices = new ArrayList<Point3f>();
    this.textureCoodinates = new ArrayList<TexCoord2f>();
    this.normals = new ArrayList<Vector3f>();
    this.groups = new LinkedHashMap<String, Group>();
    this.currentGroup = new Group("default");
    this.groups.put("default", this.currentGroup);
    this.currentMaterial = "default";
    this.appearances = new HashMap<String, Appearance>(DEFAULT_APPEARANCES);
 
 
    StreamTokenizer tokenizer = createTokenizer(reader);
    while (tokenizer.nextToken() != StreamTokenizer.TT_EOF) {
      switch (tokenizer.ttype) {
        case StreamTokenizer.TT_WORD :
          parseObjectLine(tokenizer, baseUrl);
          break;
        case StreamTokenizer.TT_EOL:
          break;
        default :
          throw new IncorrectFormatException("Unexpected token " + tokenizer.sval
              + " at row " + tokenizer.lineno());
      }
    }
 
    try {
       return createScene();
    } finally {
      this.vertices = null;
      this.textureCoodinates = null;
      this.normals = null;
      this.groups = null;
      this.appearances = null;
    }
  }
 
     /**
   * Parses the line starting with a word.
   */
  private void parseObjectLine(StreamTokenizer tokenizer,
                               URL baseUrl) throws IOException {
    if ("v".equals(tokenizer.sval)) {
      // Read vertex v x y z
      this.vertices.add(new Point3f(
          parseNumber(tokenizer), parseNumber(tokenizer), parseNumber(tokenizer)));
    } else if ("vn".equals(tokenizer.sval)) {
      // Read normal vn x y z
      this.normals.add(new Vector3f(
          parseNumber(tokenizer), parseNumber(tokenizer), parseNumber(tokenizer)));
    } else if ("vt".equals(tokenizer.sval)) {
      // Read texture coordinate vt x y
      //                       or vt x y z
      this.textureCoodinates.add(new TexCoord2f(
          parseNumber(tokenizer), parseNumber(tokenizer)));
      // Skip next number if it exists
      if (tokenizer.nextToken() == StreamTokenizer.TT_EOL) {
        tokenizer.pushBack();
      }
    } else if ("f".equals(tokenizer.sval)) {
      tokenizer.ordinaryChar('/');
      // Read face f v       v       v       ...
      //        or f v//vn   v//vn   v//vn   ...
      //        or f v/vt    v/vt    v/vt    ...
      //        or f v/vt/vn v/vt/vn v/vt/vn ...
      List<Integer> vertexIndices = new ArrayList<Integer>(4);
      List<Integer> textureCoordinateIndices = new ArrayList<Integer>(4);
      List<Integer> normalIndices = new ArrayList<Integer>(4);
      while (tokenizer.nextToken() != StreamTokenizer.TT_EOL) {
        tokenizer.pushBack();
        // Read vertex index
        int vertexIndex = parseInteger(tokenizer) - 1;
        if (vertexIndex < 0) {
          vertexIndex += this.vertices.size() + 1;
        }
        vertexIndices.add(vertexIndex);
 
        if (tokenizer.nextToken() != '/') {
          // f v
          tokenizer.pushBack();
        } else {
          if (tokenizer.nextToken() != '/') {
            // f v/vt : read texture coordinate index
            tokenizer.pushBack();
            int textureCoordinateIndex = parseInteger(tokenizer) - 1;
            if (textureCoordinateIndex < 0) {
              textureCoordinateIndex += this.textureCoodinates.size() + 1;
            }
            textureCoordinateIndices.add(textureCoordinateIndex);
            tokenizer.nextToken();
          }
          if (tokenizer.ttype == '/') {
            //    f v//vn
            // or f v/vt/vn : read normal index
            int normalIndex = parseInteger(tokenizer) - 1;
            if (normalIndex < 0) {
              normalIndex += this.normals.size() + 1;
            }
            normalIndices.add(normalIndex);
          } else {
            tokenizer.pushBack();
          }
        }
      }
      tokenizer.pushBack();
      tokenizer.wordChars('/', '/');
      if (textureCoordinateIndices.size() != 0
          && textureCoordinateIndices.size() != vertexIndices.size()) {
        // Ignore unconsistent texture coordinate
        textureCoordinateIndices.clear();
      }
      if (normalIndices.size() != 0
          && normalIndices.size() != vertexIndices.size()) {
        // Ignore unconsistent normals
        normalIndices.clear();
      }
      if (vertexIndices.size() > 2) {
        this.currentGroup.addFace(new Face(vertexIndices, textureCoordinateIndices, normalIndices,
            this.currentMaterial));
      }
    } else if ("g".equals(tokenizer.sval)
               || "o".equals(tokenizer.sval)) {
      // Read group name g name
      //  or object name o name
      boolean smoothingGroup = this.currentGroup.isSmooth();
      if (tokenizer.nextToken() == StreamTokenizer.TT_WORD) {
        this.currentGroup = this.groups.get(tokenizer.sval);
        if (this.currentGroup == null) {
          this.currentGroup = new Group(tokenizer.sval);
          this.groups.put(this.currentGroup.getName(), this.currentGroup);
        }
      } else if (tokenizer.ttype == StreamTokenizer.TT_EOL) {
        // Use default group
        this.currentGroup = this.groups.get("default");
        tokenizer.pushBack();
      } else {
        throw new IncorrectFormatException("Expected group or object name at line " + tokenizer.lineno());
      }
      this.currentGroup.setSmooth(smoothingGroup);
      // Skip other names
      while (tokenizer.nextToken() == StreamTokenizer.TT_WORD) {
      }
      tokenizer.pushBack();
    } else if ("s".equals(tokenizer.sval)) {
      // Read smoothing group s n
      //                   or s off
      if (tokenizer.nextToken() == StreamTokenizer.TT_WORD) {
        this.currentGroup.setSmooth(!"off".equals(tokenizer.sval));
      } else {
        throw new IncorrectFormatException("Expected smoothing group or off at line " + tokenizer.lineno());
      }
    } else if ("usemtl".equals(tokenizer.sval)) {
      // Read the material name usemtl name
      if (tokenizer.nextToken() == StreamTokenizer.TT_WORD) {
        this.currentMaterial = tokenizer.sval;
      } else {
        throw new IncorrectFormatException("Expected material name at line " + tokenizer.lineno());
      }
    } else if ("mtllib".equals(tokenizer.sval)) {
      int libCount = 0;
      do {
        if (tokenizer.nextToken() == StreamTokenizer.TT_WORD) {
          parseMaterial(tokenizer.sval, baseUrl);
          libCount++;
        }
      }
      while (tokenizer.nextToken() != StreamTokenizer.TT_EOL);
      if (libCount == 0) {
        throw new IncorrectFormatException("Expected material library at line " + tokenizer.lineno());
      }
      tokenizer.pushBack();
    } else {
      // Skip other lines (including comment lines starting by #)
      while (tokenizer.nextToken() != StreamTokenizer.TT_EOL) {
      }
      tokenizer.pushBack();
    }
 
    if (tokenizer.nextToken() != StreamTokenizer.TT_EOL) {
      throw new IncorrectFormatException("Expected end of line at line " + tokenizer.lineno());
    }
  }
 
    /**
   * Parses appearances from the given material file.
   */
  private void parseMaterial(String file, URL baseUrl) {
    InputStream in = null;
    try {
      if (baseUrl != null) {
        in = new URL(baseUrl, file).openStream();
      } else {
        in = new FileInputStream(file);
      }
    } catch (IOException ex) {
      // Ignore material files not found
    }
 
    if (in != null) {
      try {
        this.appearances.putAll(parseMaterialStream(
            new BufferedReader(new InputStreamReader(in, "ISO-8859-1")), baseUrl));
      } catch (IOException ex) {
        throw new ParsingErrorException(ex.getMessage());
      } finally {
        try {
          in.close();
        } catch (IOException ex) {
          throw new ParsingErrorException(ex.getMessage());
        }
      }
    }
  }
 
 
   private SceneBase createScene() {
 
 
 
 
 
    Point3f [] vertices = this.vertices.toArray(new Point3f [this.vertices.size()]);
    TexCoord2f [] textureCoodinates =
        this.textureCoodinates.toArray(new TexCoord2f [this.textureCoodinates.size()]);
    Vector3f [] normals = this.normals.toArray(new Vector3f [this.normals.size()]);
 
    SceneBase scene = new SceneBase();
    BranchGroup sceneRoot = new BranchGroup();
    scene.setSceneGroup(sceneRoot);
    System.out.println(this.groups.values());
    for (Group group : this.groups.values()) {
      List<Face> faces = group.getFaces();
      if (faces != null
          && !faces.isEmpty()) {
        int i = 0;
        while (i < faces.size()) {
          Face firstFace = faces.get(i);
          GeometryInfo geometry = new GeometryInfo(GeometryInfo.POLYGON_ARRAY);
          boolean firstFaceHasTextureCoordinateIndices = firstFace.hasTextureCoordinateIndices();
          boolean firstFaceHasNormalIndices = firstFace.hasNormalIndices();
 
          String firstFaceMaterial = firstFace.getMaterial();
          Appearance appearance = getAppearance(firstFaceMaterial);
          System.out.println(firstFaceMaterial);
          // Search how many faces share the same characteristics
          int max = i;
          while (++max < faces.size()) {
            Face face = faces.get(max);
            String material = face.getMaterial();
            if (material == null && firstFaceMaterial != null
                || material != null && getAppearance(material) != appearance
                || (firstFaceHasTextureCoordinateIndices ^ face.hasTextureCoordinateIndices())
                || (firstFaceHasNormalIndices ^ face.hasNormalIndices())) {
              break;
            }
          }
 
          // Create indices arrays for the faces with an index between i and max
          int faceCount = max - i;
          int indexCount = 0;
          for (int j = 0; j < faceCount; j++) {
            indexCount += faces.get(i + j).getVertexIndices().length;
          }
          int [] coordinatesIndices = new int [indexCount];
          int [] stripCounts = new int [faceCount];
          for (int j = 0, destIndex = 0; j < faceCount; j++) {
            int [] faceVertexIndices = faces.get(i + j).getVertexIndices();
            System.arraycopy(faceVertexIndices, 0, coordinatesIndices, destIndex, faceVertexIndices.length);
            stripCounts [j] = faceVertexIndices.length;
            destIndex += faceVertexIndices.length;
          }
          geometry.setCoordinates(vertices);
          geometry.setCoordinateIndices(coordinatesIndices);
          geometry.setStripCounts(stripCounts);
 
          if (firstFaceHasTextureCoordinateIndices) {
            int [] textureCoordinateIndices = new int [indexCount];
            for (int j = 0, destIndex = 0; j < faceCount; j++) {
              int [] faceTextureCoordinateIndices = faces.get(i + j).getTextureCoordinateIndices();
              System.arraycopy(faceTextureCoordinateIndices, 0, textureCoordinateIndices, destIndex, faceTextureCoordinateIndices.length);
              destIndex += faceTextureCoordinateIndices.length;
            }
            geometry.setTextureCoordinateParams(1, 2);
            geometry.setTextureCoordinates(0, textureCoodinates);
            geometry.setTextureCoordinateIndices(0, textureCoordinateIndices);
          }
 
          if (firstFaceHasNormalIndices) {
            int [] normalIndices = new int [indexCount];
            for (int j = 0, destIndex = 0; j < faceCount; j++) {
              int [] faceNormalIndices = faces.get(i + j).getNormalIndices();
              System.arraycopy(faceNormalIndices, 0, normalIndices, destIndex, faceNormalIndices.length);
              destIndex += faceNormalIndices.length;
            }
            geometry.setNormals(normals);
            geometry.setNormalIndices(normalIndices);
          } else {
            NormalGenerator normalGenerator = new NormalGenerator(Math.PI / 2);
            if (!group.isSmooth()) {
              normalGenerator.setCreaseAngle(0);
            }
            normalGenerator.generateNormals(geometry);
          }
 
          // Clone appearance to avoid sharing it
          if (appearance != null) {
            appearance = (Appearance)appearance.cloneNodeComponent(false);
            // Create texture coordinates if geometry doesn't define its own coordinates
            // and appearance contains a texture
            if (!firstFaceHasTextureCoordinateIndices
                && appearance.getTexture() != null) {
              appearance.setTexCoordGeneration(new TexCoordGeneration());
            }
          }
          Shape3D shape = new Shape3D(geometry.getGeometryArray(true, true, false), appearance);
          sceneRoot.addChild(shape);
          scene.addNamedObject(group.getName() + (i == 0 ? "" : String.valueOf(i)), shape);
 
          i = max;
        }
      }
    }
    return scene;
  }
 
 
private Scene load(Reader reader, URL baseUrl) throws FileNotFoundException {
    if (!(reader instanceof BufferedReader)) {
      reader = new BufferedReader(reader);
    }
    try {
      return parseObjectStream(reader, baseUrl);
    } catch (IOException ex) {
      throw new ParsingErrorException(ex.getMessage());
    } finally {
      try {
        reader.close();
      } catch (IOException ex) {
        throw new ParsingErrorException(ex.getMessage());
      }
    }
  }
 
 
 
 
 
    /**
     * @param args the command line arguments
     */
    public static void main(final String args[]) {
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                    new PrintCanvas3D(args).setVisible(true);
            }
        });
    }
 
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JPanel drawingPanel;
    private javax.swing.JMenuItem exitMenuItem;
    private javax.swing.JMenu fileMenu;
    private javax.swing.JMenuBar jMenuBar1;
    private javax.swing.JMenuItem printMenuItem;
    private javax.swing.JMenuItem snapShotMenuItem;
    // End of variables declaration//GEN-END:variables
 
}