// importer.C: import filter template

/*
   include all necessary include files
*/
#include "importer.H"

#include "xrml.H"
#include "IndexedFaceSet.H"
#include "Group.H"
#include "Material.H"
#include "Appearance.H"
#include "Transform.H"
#include "Shape.H"
#include "world.H"

namespace toy {
  using namespace xrml;  // so we can omit the xrml:: name space prefix

xrml::importer* toy::importer::instantiate(class xrml::file* file_handle)
{
  if (!file_handle)
    // simply return a new instance
    return new toy::importer;

  // This is the place to check the file name extension of a file being
  // parsed, or possibly the first bytes, in order to see if the input
  // really is something that we can handle.

  // The xrml::file class is declared in file.H and contains a lot 
  // of information about the file to be parsed, ready for us to use. 
  // Note that the file handle can also describe input from a pipe or
  // from stdin and not only regular files!

  // We don't do any checking here and always assume that we can handle 
  // the (irrelevant for this example) input.
  return new toy::importer;

  // In case we couldn't handle the input, we should have returned 0
}

bool importer::parse(class world* world, char **strpool)
{
  // builds up an example scenegraph for the specified world
  // this example only creates 2 gray triangles, but already shows 
  // most of the important things....

  // The world object being passed has a sceneGraph MFNode array
  // (declared in xrml.H and derived from xrml::array in Array.H).
  MFNode *sg = world->sceneGraph;

  // If you care, you can set the global variables indicating the
  // file name and line number at which a node is parser. This
  // information can be used for error reporting later on.
  xrml::current_filename = "blabla";
  xrml::current_linenr = 1;
  // Of course, this is not very meaningful for this example.
  
  /*
    generally, for having 2 gray triangles, we basically
    need an indexedfaceset to specify the geometry for the triangles,
    and some gray material for them.
    in order to apply the material to the triangles, we have to pool them 
    in a shape node. 
  */
  
  /*
    generate the material that is to be used in the appearance node 
    values are always assigned to fields of a vrml-node by calling
    node->assign_<fieldname> with the appropriate values
  */
  Material *material = new Material; // create a new material
  SFColor gray(.6,.6,.6); // get a color to assign
  material->assign_ambientIntensity(SFFloat(.6));
  material->assign_diffuseColor(gray); // set the diffuse color to gray
  material->assign_emissiveColor(gray);// set the emissive color to gray

  /*
    now, put this material in an appearance node
    materials can only be applied to geometry through appearance nodes...
  */
  Appearance *appearance = new Appearance; // create a new appearance node
  appearance->assign_material(material);   // ... and assign our gray material

  /*
    after having generated the appearance, we're generating the geometry.
    first, we specify the vertices of our triangles.
  */
  SFVec3f verts[4] = {
    SFVec3f(0,0,0),
    SFVec3f(0,1,0),
    SFVec3f(1,0,0),
    SFVec3f(1,1,1)
  };
  MFVec3f coords(4, verts);

  /*
    create a coordinate node that can hold the vertex positions
    the coords can not be assigned directly, but only through a coordinate
    class. the same applies for normals, texturecoords aso...
  */
  Coordinate *coord = new Coordinate;
  coord->assign_point(coords); // assign our array or vertex positions

  /*
    after having the vertex positions, we have to generate the index-array for the
    faces in basically the same way. specify a MFInt32 field and assign the indices 
  */
  SFInt32 indices[8] = { 0, 1, 2, -1, 1, 2, 3, -1 };
  MFInt32 index(8, indices);

  /*
     There are various ways of constructing MFxxx (array) objects. See
     the Array.H include file and the TOOLS/testarrayassign.C code
     fragment.
  */

  /* 
     after having both the index array and the coordinate node,
     we can put them together in a new indexedfaceset
  */
  IndexedFaceSet *ifs = new IndexedFaceSet; // create a new indexedfaceset
  ifs->assign_coord(coord);                 // assing our coordinates
  ifs->assign_coordIndex(index);            // assign the index-array

  /* 
     now that we have both the appearance and the geometry (the indexedfaceset,
     which is a subclass of geometry), we can put them together with a shape-node.
     basically a shape node is the only way how to bring geometry and materials together...
  */
  Shape *shape = new Shape;             // generate a new shape
  shape->assign_appearance(appearance); // take our previously defined appearance
  shape->assign_geometry(ifs);          // assign our indexedfaceset-geometry

  /* 
     we're almost done : just add the newly created shape (our two-triangle-indexfaceset 
     with a gray-material-appearance) to the scenegraph...
  */
  sg->append(shape);

  return true;
}

} // namespace toy
