void FaceSpatializeIndexed<BasicTraits>::CategoryGeneral::addData (OpenSGFaceBase<OpenSGTraits>* node, const FaceIterator& face)
{
   u32 offsetSize = m_offset.size();
   CategoryColor::addData(node, face);
   if (m_hasTex) {
      if (offsetSize < m_offset.size()) {
 	 m_offsetIt->second.tex1 = m_texCoord->size();
	 GeoTexCoords2f::StoredFieldType* t = m_texCoord->getFieldPtr();
	 GeoTexCoordsPtr faceT = m_original.getTexCoords();
	 for (u32 k=0; k<faceT->getSize(); ++k) {
	    t->addValue(faceT->getValue(k));
	 }
      }

      // set indices for TexCoords
      if (face.getLength() == 3) {
 	 u32 i = m_quadOffset - 3*m_indexStride + m_indexOffset.tex1;
	 for (u32 k=0; k<3; ++k) {
	    m_index->setValue(face.getTexCoordsIndex(k)+m_offsetIt->second.tex1, i);
	    assert(face.getTexCoordsIndex(k)+m_offsetIt->second.tex1 < m_texCoord->size());
	    i += m_indexStride;
	 }
      } else {
 	 u32 i = m_index->size() - 4*m_indexStride + m_indexOffset.tex1;
	 for (u32 k=0; k<4; ++k) {
	    m_index->setValue(face.getTexCoordsIndex(k)+m_offsetIt->second.tex1, i);
	    assert(face.getTexCoordsIndex(k)+m_offsetIt->second.tex1 < m_texCoord->size());
	    i += m_indexStride;
	 }
      }
   }
}
void FaceSpatializeIndexed<BasicTraits>::CategoryColor::addData (OpenSGFaceBase<OpenSGTraits>* node,
								 const FaceIterator&           face)
{
   u32 offsetSize = m_offset.size();
   CategoryRaw::addData(node, face);
   if (m_hasColor) { 
      if (offsetSize < m_offset.size()) {
 	 m_offsetIt->second.color = m_color->size();
	 GeoColors3f::StoredFieldType* c = m_color->getFieldPtr();
	 GeoColorsPtr faceC = m_original.getColors();
	 for (u32 k=0; k<faceC->getSize(); ++k) {
	    c->addValue(faceC->getValue(k));
	 }
      }

      // set indices for colors
      if (face.getLength() == 3) {
 	 u32 i = m_quadOffset - 3*m_indexStride + m_indexOffset.color;
	 for (u32 k=0; k<3; ++k) {
	    m_index->setValue(face.getColorIndex(k)+m_offsetIt->second.color, i);
	    assert(face.getColorIndex(k)+m_offsetIt->second.color < m_color->size());
	    i += m_indexStride;
	 }
      } else {
 	 u32 i = m_index->size() - 4*m_indexStride + m_indexOffset.color;
	 for (u32 k=0; k<4; ++k) {
	    m_index->setValue(face.getColorIndex(k)+m_offsetIt->second.color, i);
	    assert(face.getColorIndex(k)+m_offsetIt->second.color < m_color->size());
	    i += m_indexStride;
	 }
      }
   }
}
void FaceSpatializeIndexed<BasicTraits>::CategoryRaw::addData (OpenSGFaceBase<OpenSGTraits>* node, const FaceIterator& face)
{
   GeoPositions3f::StoredFieldType*  p = m_coord->getFieldPtr();
   GeoNormals3f::StoredFieldType*    n = m_normal->getFieldPtr();
   //GeoIndicesUI32::StoredFieldType*  i = m_index->getFieldPtr();

   // find offset of positions and normals in the new geometry
   u32 i, k;
   m_offsetIt = m_offset.find(face.getGeometry());
   if (m_offsetIt == m_offset.end()) {
      // insert new offsets entry into map
      HashMapPair offsetPair = 
	m_offset.insert(HashMap::value_type(face.getGeometry(), quad()));
      m_offsetIt = offsetPair.first;

      m_offsetIt->second.position = m_coord->size();
      GeoPositionsPtr faceP = m_original.getPositions();
      addRefCP(faceP);
      for (k=0; k<faceP->getSize(); ++k) {
	 p->addValue(faceP->getValue(k));
      }
      if (m_hasNormal) {
 	 m_offsetIt->second.normal = m_normal->size();
	 GeoNormalsPtr faceN = m_original.getNormals();
	 addRefCP(faceN);
	 for (k=0; k<faceN->getSize(); ++k) {
	    n->addValue(faceN->getValue(k));
	 }
	 subRefCP(faceN);
      }
      subRefCP(faceP);
   }

   // insert indices
   if (face.getLength() == 3) {
      for (k=0; k<3; ++k) {
	 m_index->insertValue(face.getPositionIndex(k)+m_offsetIt->second.position, m_quadOffset++);
	 i = 1;
	 if (m_hasNormal) {
	    m_index->insertValue(face.getNormalIndex(k)+m_offsetIt->second.normal,     m_quadOffset++);
	    ++i;
	 }
	 for (; i<m_indexStride; ++i) {
	    m_index->insertValue(0, m_quadOffset++);
	 }
      }
   } else {
      for (k=0; k<4; ++k) {
	 m_index->addValue(face.getPositionIndex(k)+m_offsetIt->second.position);
	 i = 1;
	 if (m_hasNormal) {
	    m_index->addValue(face.getNormalIndex(k)+m_offsetIt->second.normal);
	    ++i;
	 }
	 for (; i<m_indexStride; ++i) {
	    m_index->addValue(0);
	 }
      }
   }
}
void FaceSpatialize<BasicTraits>::CategoryGeneral::addData (OpenSGFaceBase<OpenSGTraits>* node,
							    const FaceIterator& face)
{
   CategoryColor::addData(node, face);
   if (m_hasTex) {
      GeoTexCoords2f::StoredFieldType* t = m_texCoord->getFieldPtr();
      for (u32 k=0; k<face.getLength(); ++k) {
	 t->addValue(face.getTexCoords(k));
      }
      assert(m_coord->getSize() == m_texCoord->getSize());
   }
}
void FaceSpatialize<BasicTraits>::CategoryColor::addData (OpenSGFaceBase<OpenSGTraits>* node,
							  const FaceIterator&           face)
{
   CategoryRaw::addData(node, face);
   if (m_hasColor) {
      GeoColors3f::StoredFieldType* c = m_color->getFieldPtr();
      for (u32 k=0; k<face.getLength(); ++k) {
	 c->addValue(face.getColor(k));
      }
      assert(m_coord->getSize() == m_color->getSize());
   }
}
void FaceSpatialize<BasicTraits>::CategoryRaw::addData (OpenSGFaceBase<OpenSGTraits>* node,
							const FaceIterator&           face)
{
   GeoPositions3f::StoredFieldType*  p = m_coord->getFieldPtr();
   GeoNormals3f::StoredFieldType*    n = m_normal->getFieldPtr();
   //GeoIndicesUI32::StoredFieldType*  i = m_index->getFieldPtr();

   GeoPositionsPtr faceP = node->getPositions();
   addRefCP(faceP);
   u32 k;
   for (k=0; k<faceP->getSize(); ++k) {
      p->addValue(faceP->getValue(k));
      if (face.getLength()==3) { 
	 m_index->insertValue(p->size()-1, m_quadOffset++);
      } else {
	 m_index->addValue(p->size()-1);
      }
   }
   if (!m_hasNormal) {
#if 1
      Vec3f p0(faceP->getValue(0));
      Vec3f p1(faceP->getValue(1));
      Vec3f p2(faceP->getValue(2));
      p2 -= p1; p0 -= p1; 
      if (m_ccw) {
	 p0.crossThis(p2); p0.normalize();
	 n->addValue(p0);
      } else {
	 p2.crossThis(p0); p2.normalize();
	 n->addValue(p2);
      }
#endif
   } else { // per-vertex normals or per-face normals
      GeoNormalsPtr faceN = node->getNormals();
      addRefCP(faceN);
      for (k=0; k<faceN->getSize(); ++k) {
	 n->addValue(faceN->getValue(k));
      }
      subRefCP(faceN);
   }
   subRefCP(faceP);
}
/*
  Aufruf dieser Funktion erfolgt bei Traversierung des Szenengraphen
  mittels OpenSG-Funktion traverse().
  Enthaelt ein Knoten verwertbare Geometrieinformation so tragen wir
  Zeiger auf seine Geometrie (OpenSG-Strukturen) im array gla_meshInfo_
  ein.
  Nebenbei bestimmen wir für die Geometrie auch noch die World-Space-
  Transformation (evtl. existiert eine OpenSG-Funktion um diese
  Information zu erhalten, der Autor hat keine in der OpenSG-API
  entdeckt).
*/
Action::ResultE enter(NodePtr &node)
{
    int             i, j, h;
    Pnt3f           v;
    int             numFaces, numFaceVertices, vId, size;

    MeshInfo        meshInfo;
    TinyMatrix      transf;
    FaceIterator    fit;
    int             numQuads;
    NamePtr         namePtr;
    char            name[255];

    namePtr = NamePtr::dcast(node->findAttachment(Name::getClassType().getGroupId()));
    if(namePtr == osg::NullFC)
        strcpy(name, "");
    else
    {
        strcpy(name, namePtr->getFieldPtr()->getValue().c_str());
    }

    SINFO << "Node name = '" << name << "'" << endl << endLog;

    GeometryPtr geo = GeometryPtr::dcast(node->getCore());

    if(geo != NullFC)
    {
        GeoPLengthsUI32Ptr  pLength = GeoPLengthsUI32Ptr::dcast(geo->getLengths());
        GeoPTypesUI8Ptr     pTypes = GeoPTypesUI8Ptr::dcast(geo->getTypes());

        /* pLength and pTypes should not be NullFC, however VRML Importer/Exporter
		  code is instable by now, so this can happen */
        if((pLength != NullFC) && (pTypes != NullFC))
        {
            GeoPLengthsUI32::StoredFieldType * pLengthField = pLength->getFieldPtr();
            GeoPTypesUI8::StoredFieldType * pTypeField = pTypes->getFieldPtr();

            size = pLengthField->size();

            for(h = 0; h < size; h++)
            {
                if(((*pTypeField)[h] == GL_TRIANGLES) ||
                   ((*pTypeField)[h] == GL_QUADS))
                {
                    /* may quads appear in GL_TRIANGLES ? */
                    /* check if all triangles have three vertices */
                    numQuads = 0;
                    fit = geo->beginFaces();
                    while(fit != geo->endFaces())
                    {
                        numFaceVertices = fit.getLength();
                        if(numFaceVertices == 4)
                            numQuads++;
                        if(numFaceVertices > 4)
                        {
                            SWARNING <<
                                "More than 4 vertices in face!" <<
                                endl <<
                                endLog;
                            return Action::Continue;

                            // exit(1);
                        }

                        ++fit;
                    }

                    if(numQuads > 0)
                    {
                        SWARNING << "Quad encountered" << endl << endLog;
                    }

                    if(gl_sga->nodeDepth_ > 0)
                    {
                        for(i = 0; i < gl_sga->nodeDepth_; i++)
                        {
                            meshInfo.transf = meshInfo.transf * gl_sga->transf_[i];
                        }
                    }
                    else
                        meshInfo.transf.identity();

                    /* access to vertices */
                    GeoPositions3fPtr   pPos = GeoPositions3fPtr::dcast(geo->getPositions());
                    GeoPositions3f::StoredFieldType * pPosField = pPos->getFieldPtr();

                    /* access to faces */
                    numFaces = 0;
                    fit = geo->beginFaces();
                    for(fit = geo->beginFaces(); fit != geo->endFaces(); ++fit)
                    {
                        numFaceVertices = fit.getLength();

                        for(j = 0; j < numFaceVertices; j++)
                        {
                            vId = fit.getPositionIndex(j);
                        }

                        numFaces++;
                    }                       /* for fit */

                    /* set other mesh attributes */
                    meshInfo.numQuads = numQuads;
                    meshInfo.geoPtr = geo;
                    meshInfo.vPtr = pPosField;
                    meshInfo.triangularFaces = (numQuads == 0);
                    meshInfo.numVertices = pPosField->size();
                    meshInfo.numFaces = numFaces;

                    gl_sga->meshInfo_.push_back(meshInfo);
                    gl_sga->numGeometryNodes_++;
                }
                else
                {
                    //			SWARNING << "Neither triangle nor quad. Field type = " <<
                    //				        (*pTypeField)[h] << endl << endLog;
                }
            }                               /* for h */
        }                                   /* if pLength!=NullFC */
    }
    else if(node->getCore()->getType().isDerivedFrom(Transform::getClassType()))
    {
        TransformPtr    t = TransformPtr::dcast(node->getCore());
        Matrix          ma;

        ma = t->getMatrix();

        SINFO <<
            "Node type derived from transform, skipping children" <<
            endl <<
            endLog;

        for(i = 0; i < 4; i++)
        {
            for(j = 0; j < 4; j++)
            {
                transf[i][j] = ma[j][i];    /* the matrix is stored as columns/rows ? */
            }
        }

        if(gl_sga->nodeDepth_ > gl_sga->maxNodeDepth_)
        {
            gl_sga->maxNodeDepth_ = gl_sga->nodeDepth_;
            gl_sga->transf_.push_back(transf);
        }
        else
        {
            gl_sga->transf_[gl_sga->nodeDepth_] = transf;
        }

        gl_sga->nodeDepth_++;
    }

    return Action::Continue;
}
/*
  Konvertierung des mit meshId bezeichneten IndexedFaceSets in ein Mesh
  vom Typ TriangleSet.
  Zu beachten:
  IndexedFaceSets, die Eckpunkte "shared", werden beim Parsen des
  Szenengraphen (Konstruktor) zu einem Teilmesh zusammengefasst
  (erhalten dieselbe ID).
  Bei der Konvertierung wird aus diesen ein Mesh generiert.
*/
int WmSceneGraphAccess::convertToTs(TriangleSet *ts, int *numQuadsFound,
                                    GEOMARK_BitArray **isQuadVertex, int meshId)
{
    int             i, j, k;
    int             offsetVertices, numVertices, numFaces, numFaceVertices;
    int             to, from;
    TinyVector      v;
    FaceIterator    fit;
    int             trVIds[3], quadVIds[4];
    GeometryPtr     geoPtr;
    BOOL            quadsPresent;
    int             numQuads;

    if(numMeshes_ < 1)
        return -1;

    offsetVertices = 0;
    *isQuadVertex = NULL;
    quadsPresent = FALSE;
    numQuads = 0;

    if(meshId == -1)
    {               /* generate single flat mesh */
        /* first pass */
        SINFO << "Generating single flat mesh" << endl << endLog;

        numVertices = 0;
        numFaces = 0;
        numQuads = 0;
        for(i = 0; i < numGeometryNodes_; i++)
        {
            if((i == 0) || (meshInfo_[i].meshId != meshInfo_[i - 1].meshId))
            {
                numVertices += meshInfo_[i].numVertices;
                SINFO <<
                    "mesh id = " <<
                    meshInfo_[i].meshId <<
                    endl <<
                    "# of vertices = " <<
                    meshInfo_[i].numVertices <<
                    endl <<
                    endLog;
            }

            numFaces += meshInfo_[i].numFaces;
            numQuads += meshInfo_[i].numQuads;
            if((!quadsPresent) && (meshInfo_[i].numQuads > 0))
                quadsPresent = TRUE;
        }

        if(quadsPresent)
        {
            *isQuadVertex = new GEOMARK_BitArray(numVertices);
            numFaces += numQuads;
        }

        SINFO << "# of faces = " << numFaces << endl << endLog;

        ts->init(numVertices, numFaces);

        /* second pass */
        numVertices = 0;
        numFaces = 0;

        for(i = 0; i < numGeometryNodes_; i++)
        {
            if((i > 0) && (meshInfo_[i].meshId != meshInfo_[i - 1].meshId))
            {
                offsetVertices += meshInfo_[i - 1].numVertices;
            }

            if((i == 0) || (meshInfo_[i].meshId != meshInfo_[i - 1].meshId))
            {
                /* set vertex data */
                for(j = 0; j < meshInfo_[i].vPtr->size(); j++)
                {
                    v[0] = (*meshInfo_[i].vPtr)[j][0];
                    v[1] = (*meshInfo_[i].vPtr)[j][1];
                    v[2] = (*meshInfo_[i].vPtr)[j][2];

                    /* transformation does matter for case of single flat mesh */
                    v = meshInfo_[i].transf * v;    /* transform into world space */

                    ts->setVertex(offsetVertices + j, v);
                }

                numVertices += meshInfo_[i].numVertices;
            }

            /* set face data */
            geoPtr = meshInfo_[i].geoPtr;

            for(fit = geoPtr->beginFaces(); fit != geoPtr->endFaces(); ++fit)
            {
                /* this should be always 3 */
                numFaceVertices = fit.getLength();
                if(numFaceVertices == 4)
                {
                    for(j = 0; j < 4; j++)
                    {
                        quadVIds[j] = fit.getPositionIndex(j);
                        (*isQuadVertex)->setBit(quadVIds[j], 1);
                    }

                    /* split quad into two triangles */
                    ts->setFace(numFaces, offsetVertices + quadVIds[0],
                                offsetVertices + quadVIds[1],
                                offsetVertices + quadVIds[2]);
                    numFaces++;
                    ts->setFace(numFaces, offsetVertices + quadVIds[2],
                                offsetVertices + quadVIds[3],
                                offsetVertices + quadVIds[0]);
                    numFaces++;
                }
                else
                {
                    if(numFaceVertices != 3)
                    {
                        printf("numFaceVertices=%d\n", numFaceVertices);

                        // exit(1);
                        return -1;
                    }

                    for(j = 0; j < 3; j++)
                    {
                        trVIds[j] = fit.getPositionIndex(j);
                    }

                    ts->setFace(numFaces, offsetVertices + trVIds[0],
                                offsetVertices + trVIds[1],
                                offsetVertices + trVIds[2]);
                    numFaces++;
                }
            }                               /* for fit */
        }                                   /* for i */

        ts->meshComplete();
    }
    else
    {
        /* generate triangleset for mesh meshId */
        from = 0;

        while((from < numGeometryNodes_) && (meshInfo_[from].meshId < meshId))
        {
            from++;
        }

        if((from < numGeometryNodes_) && (meshInfo_[from].meshId == meshId))
        {
            /* first pass: count vertices and faces  */
            numVertices = 0;
            numFaces = 0;
            offsetVertices = 0;             /* const 0 */
            i = from;
            numVertices = meshInfo_[i].numVertices;
            numQuads = 0;
            while((i < numGeometryNodes_) && (meshInfo_[i].meshId == meshId))
            {
                numFaces += meshInfo_[i].numFaces;
                numQuads += meshInfo_[i].numQuads;
                i++;
            }

            SINFO << "# of vertices = " << numVertices << endLog;
            SINFO << "# of quads = " << numQuads << endLog;
            SINFO << "# of faces = " << numFaces << endl << endLog;

            if(numQuads > 0)
            {
                *isQuadVertex = new GEOMARK_BitArray(numVertices);
                numFaces += numQuads;
            }

            ts->init(numVertices, numFaces);

            /* second pass */
            numVertices = 0;
            numFaces = 0;
            offsetVertices = 0;
            i = from;
            while((i < numGeometryNodes_) && (meshInfo_[i].meshId == meshId))
            {
                /* set vertex data */
                for(j = 0; j < meshInfo_[i].vPtr->size(); j++)
                {
                    v[0] = (*meshInfo_[i].vPtr)[j][0];
                    v[1] = (*meshInfo_[i].vPtr)[j][1];
                    v[2] = (*meshInfo_[i].vPtr)[j][2];

                    /* transformation does not matter for single IndexedFaceSets */
                    ts->setVertex(offsetVertices + j, v);
                }

                /* set face data */
                geoPtr = meshInfo_[i].geoPtr;

                for(fit = geoPtr->beginFaces(); fit != geoPtr->endFaces();
                    ++fit)
                {
                    numFaceVertices = fit.getLength();
                    if(numFaceVertices == 4)
                    {
                        SWARNING <<
                            "Quad found. Will be split" <<
                            endl <<
                            endLog;
                        for(j = 0; j < 4; j++)
                        {
                            quadVIds[j] = fit.getPositionIndex(j);
                            (*isQuadVertex)->setBit(quadVIds[j], 1);
                        }

                        /* split quad into two triangles */
                        ts->setFace(numFaces, offsetVertices + quadVIds[0],
                                    offsetVertices + quadVIds[1],
                                    offsetVertices + quadVIds[2]);
                        numFaces++;
                        ts->setFace(numFaces, offsetVertices + quadVIds[2],
                                    offsetVertices + quadVIds[3],
                                    offsetVertices + quadVIds[0]);
                        numFaces++;
                    }
                    else
                    {
                        if(numFaceVertices != 3)
                        {
                            SFATAL <<
                                "# of vertices for face = " <<
                                numFaceVertices <<
                                endl <<
                                endLog;
                            return 1;
                        }

                        for(j = 0; j < 3; j++)
                        {
                            trVIds[j] = fit.getPositionIndex(j);
                        }

                        ts->setFace(numFaces, offsetVertices + trVIds[0],
                                    offsetVertices + trVIds[1],
                                    offsetVertices + trVIds[2]);
                        numFaces++;
                    }
                }                           /* for fit */

                i++;
            }                               /* while i */

            SINFO << "# of faces = " << numFaces << endl << endLog;

            ts->meshComplete();
        }                                   /* if */
        else
        {
            SFATAL << "No mesh with id " << meshId << endl << endLog;
            return 1;
        }
    }                                       /* generate flat mesh from all nodes */

    *numQuadsFound = numQuads;

    return 0;
}