// --------------------------------------------------------------------------- // Includes for all the program files to see // --------------------------------------------------------------------------- #include #include #include using namespace std; #include // --------------------------------------------------------------------------- // Includes // --------------------------------------------------------------------------- #include #include #include // --------------------------------------------------------------------------- // Includes // --------------------------------------------------------------------------- #include #include #include #include "X3dParser.h" #include "X3dParserXerces.h" #include "Mesh.h" #include "SceneGraph.h" #include "Triangle3.h" #include "ViewCellsManager.h" // --------------------------------------------------------------------------- // Local data // // doNamespaces // Indicates whether namespace processing should be enabled or not. // The default is no, but -n overrides that. // // doSchema // Indicates whether schema processing should be enabled or not. // The default is no, but -s overrides that. // // schemaFullChecking // Indicates whether full schema constraint checking should be enabled or not. // The default is no, but -s overrides that. // // valScheme // Indicates what validation scheme to use. It defaults to 'auto', but // can be set via the -v= command. // --------------------------------------------------------------------------- static bool doNamespaces = false; static bool doSchema = false; static bool schemaFullChecking = false; static SAXParser::ValSchemes valScheme = SAXParser::Val_Auto; #define ROTATE_SCENE 0 static void RotateMesh(Mesh *mesh) { VertexContainer::iterator it, it_end = mesh->mVertices.end(); const float angle = 30.0f * PI / 180.0f; const Matrix4x4 rot = RotationYMatrix(angle); for (it = mesh->mVertices.begin(); it != it_end; ++ it) { (*it) = rot * (*it); } } // --------------------------------------------------------------------------- // StdInParseHandlers: Constructors and Destructor // --------------------------------------------------------------------------- X3dParseHandlers::X3dParseHandlers(SceneGraphNode *root, const bool loadPolygonsAsMeshes): mElementCount(0) , mAttrCount(0) , mCharacterCount(0) , mSpaceCount(0) , mLoadPolygonsAsMeshes(loadPolygonsAsMeshes) { mCurrentNode = root; // this matrix should never be removed from stack //mTransformations.push(IdentityMatrix()); } X3dParseHandlers::~X3dParseHandlers() { if (!mTransformations.empty()) cout << "error: transformation stack size: " << (int)mTransformations.size() << endl; } // --------------------------------------------------------------------------- // StdInParseHandlers: Implementation of the SAX DocumentHandler interface // --------------------------------------------------------------------------- void X3dParseHandlers::endElement(const XMLCh* const name) { StrX lname(name); string element(lname.LocalForm()); // only create new mesh instance if define mechanism was not used if (element == "Shape") EndShape(); if (element == "Transform") EndTransform(); } void X3dParseHandlers::ApplyTransformation(Mesh *mesh, const Matrix4x4 &m) const { VertexContainer::iterator it, it_end = mesh->mVertices.end(); for (it = mesh->mVertices.begin(); it != it_end; ++ it) { (*it) = m * (*it); } } void X3dParseHandlers::ApplyTransformations(TrafoStack trafos, Mesh *mesh) const { while (!trafos.empty()) { const Matrix4x4 m = trafos.top(); trafos.pop(); ApplyTransformation(mesh, m); } } void X3dParseHandlers::StartTransform(AttributeList& attributes) { Matrix4x4 currentTransform = IdentityMatrix(); const int len = attributes.getLength(); Matrix4x4 *rotm = NULL; Matrix4x4 *scalem = NULL; Matrix4x4 *translm = NULL; for (int i = 0; i < len; ++ i) { string attrName(StrX(attributes.getName(i)).LocalForm()); StrX attrValue(attributes.getValue(i)); const char *ptr = attrValue.LocalForm(); if (attrName == "rotation") { Vector3 axis; float angle; if (sscanf(ptr, "%f %f %f %f", &axis.x, &axis.y, &axis.z, &angle) == 4) { rotm = new Matrix4x4(RotationAxisMatrix(axis, angle)); } } else if (attrName == "translation") { Vector3 transl; if (sscanf(ptr, "%f %f %f %f", &transl.x, &transl.y, &transl.z) == 3) { translm = new Matrix4x4(TranslationMatrix(transl)); } } else if (attrName == "scale") { Vector3 scale; if (sscanf(ptr, "%f %f %f %f", &scale.x, &scale.y, &scale.z) == 3) { scalem = new Matrix4x4(ScaleMatrix(scale.x, scale.y, scale.z)); } } // todo: scale orientation } if (scalem) currentTransform *= (*scalem); if (rotm) currentTransform *= (*rotm); if (translm) currentTransform *= (*translm); DEL_PTR(scalem); DEL_PTR(rotm); DEL_PTR(translm); mTransformations.push(currentTransform); } void X3dParseHandlers::EndTransform() { mTransformations.pop(); } void X3dParseHandlers::EndShape() { // this shape is a definition => don't create mesh instance if (mIsMeshDefinition) { mMeshDefinitions[mCurrentMeshName.c_str()] = mCurrentMesh; //cout << "new definition: " << mCurrentMeshName << endl; return; } // each polygon is one single mesh if (mLoadPolygonsAsMeshes) { /*vector::const_iterator it, it_end = mCurrentVertexIndices.end(); for (it = mCurrentVertexIndices.begin(); it != it_end; ++ it) { // only one face per mesh Mesh *mesh = new Mesh(); VertexIndexContainer vc; // add vertices for (int i = 0; i < (int)(*it).size(); ++ i) { mesh->mVertices.push_back(mCurrentVertices[(*it)[i]]); vc.push_back(i); } mesh->mFaces.push_back(new Face(vc)); // NOTE: should rather be written into trafo of mesh instance ApplyTransformations(mTransformations, mesh); mesh->Preprocess(); // make an instance of this mesh MeshInstance *mi = new MeshInstance(mesh); mCurrentNode->mGeometry.push_back(mi); }*/ //if (mCurrentMesh->mFaces.empty()) cout << "error!" << endl; FaceContainer::const_iterator fit, fit_end = mCurrentMesh->mFaces.end(); cout << "m"; //cout << "m: " << mCurrentMesh->mFaces.size() << endl; for (fit = mCurrentMesh->mFaces.begin(); fit != fit_end; ++ fit) { cout << "f"; Face *face = *fit; // only one face per mesh Mesh *mesh = new Mesh(); VertexIndexContainer vc; VertexIndexContainer::const_iterator vit, vit_end = face->mVertexIndices.end(); int i = 0; for (vit = face->mVertexIndices.begin(); vit != vit_end; ++ vit, ++ i) { cout << "i"; int index = (*vit); // add vertices mesh->mVertices.push_back(mCurrentMesh->mVertices[index]); vc.push_back(i); } mesh->mFaces.push_back(new Face(vc)); // NOTE: should rather be written into trafo of mesh instance ApplyTransformations(mTransformations, mesh); mesh->Preprocess(); // make an instance of this mesh MeshInstance *mi = new MeshInstance(mesh); mCurrentNode->mGeometry.push_back(mi); } // LEAK!! TODO: delete if not defd if (!mUsingMeshDefinition) delete mCurrentMesh; //mCurrentVertices.clear(); //mCurrentVertexIndices.clear(); } else { if (!mCurrentMesh->mFaces.empty()) { // should rather be written into the transformation // of a mesh instance ApplyTransformations(mTransformations, mCurrentMesh); mCurrentMesh->Preprocess(); // make an instance of this mesh MeshInstance *mi = new MeshInstance(mCurrentMesh); mCurrentNode->mGeometry.push_back(mi); // set the object id to a unique value //mi->SetId(mCurrentObjectId ++); } else { // empty mesh => discard cout<<"X"; delete mCurrentMesh; } mCurrentMesh = NULL; } } void X3dParseHandlers::StartIndexedFaceSet(AttributeList& attributes) { int len = attributes.getLength(); int i; VertexIndexContainer vertices; mIsMeshDefinition = false; mUsingMeshDefinition = false; for (i = 0; i < len; ++ i) { string attrName(StrX(attributes.getName(i)).LocalForm()); // this is a definition of a mesh if (attrName == "DEF") { mIsMeshDefinition = true; StrX attrValue(attributes.getValue(i)); const char *ptr = attrValue.LocalForm(); mCurrentMeshName = ptr; cout << "d"; } // we use an already defined mesh if (attrName == "USE") { StrX attrValue(attributes.getValue(i)); // discard new mesh and assign defined mesh DEL_PTR(mCurrentMesh); const char *ptr = attrValue.LocalForm(); mCurrentMesh = mMeshDefinitions[ptr]; mUsingMeshDefinition = true; cout << "u"; } if (attrName == "coordIndex") { StrX attrValue(attributes.getValue(i)); // handle coordIndex vertices.clear(); const char *ptr = attrValue.LocalForm(); char *endptr; while (1) { int index = strtol(ptr, &endptr, 10); if (ptr == endptr || index == -1) { if (vertices.size() > 2) { Face *face = new Face(vertices); mCurrentMesh->mFaces.push_back(face); } vertices.clear(); if (ptr == endptr) break; } else { vertices.push_back(index); } ptr = endptr; } } } } void X3dParseHandlers::StartMaterial( AttributeList& attributes) { int len = attributes.getLength(); int i; if (!mCurrentMesh->mMaterial) mCurrentMesh->mMaterial = new Material; for (i=0; i < len; i++) { string attrName(StrX(attributes.getName(i)).LocalForm()); StrX attrValue(attributes.getValue(i)); const char *ptr = attrValue.LocalForm(); if (attrName == "diffuseColor") { float r, g, b; if (sscanf(ptr, "%f %f %f", &r, &g, &b) == 3) mCurrentMesh->mMaterial->mDiffuseColor = RgbColor(r, g, b); } } } void X3dParseHandlers::StartCoordinate( AttributeList& attributes) { int len = attributes.getLength(); int i; VertexContainer vertices; for (i=0; i < len; i++) { string attrName(StrX(attributes.getName(i)).LocalForm()); if (attrName == "point") { StrX attrValue(attributes.getValue(i)); const char *ptr = attrValue.LocalForm(); char *endptr; while (1) { float x = (float)strtod(ptr, &endptr); if (ptr == endptr) break; ptr = endptr; float y = (float)strtod(ptr, &endptr); if (ptr == endptr) break; ptr = endptr; float z = (float)strtod(ptr, &endptr); if (ptr == endptr) break; ptr = endptr; if (*ptr == ',') ptr ++; Vector3 v(x, y, z); vertices.push_back(v); } mCurrentMesh->mVertices = vertices; } } } void X3dParseHandlers::startElement(const XMLCh* const name, AttributeList& attributes) { StrX lname(name); string element(lname.LocalForm()); if (element == "IndexedFaceSet") { // create a new mesh node in the scene graph StartIndexedFaceSet(attributes); } if (element == "Shape") { cout << "+"; mCurrentMesh = new Mesh; } if (element == "Coordinate") { if (mCurrentMesh) StartCoordinate(attributes); } if (element == "Material") { StartMaterial(attributes); } if (element == "Transform") { StartTransform(attributes); } mElementCount++; mAttrCount += attributes.getLength(); } void X3dParseHandlers::characters(const XMLCh* const chars, const unsigned int length) { mCharacterCount += length; } void X3dParseHandlers::ignorableWhitespace(const XMLCh* const chars, const unsigned int length) { mSpaceCount += length; } void X3dParseHandlers::resetDocument() { mAttrCount = 0; mCharacterCount = 0; mElementCount = 0; mSpaceCount = 0; } // --------------------------------------------------------------------------- // StdInParseHandlers: Overrides of the SAX ErrorHandler interface // --------------------------------------------------------------------------- void X3dParseHandlers::error(const SAXParseException& e) { XERCES_STD_QUALIFIER cerr << "\nError at (file " << StrX(e.getSystemId()) << ", line " << e.getLineNumber() << ", char " << e.getColumnNumber() << "): " << StrX(e.getMessage()) << XERCES_STD_QUALIFIER endl; } void X3dParseHandlers::fatalError(const SAXParseException& e) { XERCES_STD_QUALIFIER cerr << "\nFatal Error at (file " << StrX(e.getSystemId()) << ", line " << e.getLineNumber() << ", char " << e.getColumnNumber() << "): " << StrX(e.getMessage()) << XERCES_STD_QUALIFIER endl; } void X3dParseHandlers::warning(const SAXParseException& e) { XERCES_STD_QUALIFIER cerr << "\nWarning at (file " << StrX(e.getSystemId()) << ", line " << e.getLineNumber() << ", char " << e.getColumnNumber() << "): " << StrX(e.getMessage()) << XERCES_STD_QUALIFIER endl; } bool X3dParser::ParseFile(const string filename, SceneGraphNode **root, const bool loadPolygonsAsMeshes) { // Initialize the XML4C system try { XMLPlatformUtils::Initialize(); } catch (const XMLException& toCatch) { XERCES_STD_QUALIFIER cerr << "Error during initialization! Message:\n" << StrX(toCatch.getMessage()) << XERCES_STD_QUALIFIER endl; return false; } // // Create a SAX parser object. Then, according to what we were told on // the command line, set the options. // SAXParser* parser = new SAXParser; parser->setValidationScheme(valScheme); parser->setDoNamespaces(doNamespaces); parser->setDoSchema(doSchema); parser->setValidationSchemaFullChecking(schemaFullChecking); // // Create our SAX handler object and install it on the parser, as the // document and error handler. We are responsible for cleaning them // up, but since its just stack based here, there's nothing special // to do. // *root = new SceneGraphNode; X3dParseHandlers handler(*root, loadPolygonsAsMeshes); parser->setDocumentHandler(&handler); parser->setErrorHandler(&handler); unsigned long duration; int errorCount = 0; // create a faux scope so that 'src' destructor is called before // XMLPlatformUtils::Terminate { // // Kick off the parse and catch any exceptions. Create a standard // input input source and tell the parser to parse from that. // // StdInInputSource src; try { const unsigned long startMillis = XMLPlatformUtils::getCurrentMillis(); parser->parse(filename.c_str()); const unsigned long endMillis = XMLPlatformUtils::getCurrentMillis(); duration = endMillis - startMillis; errorCount = parser->getErrorCount(); } catch (const OutOfMemoryException&) { XERCES_STD_QUALIFIER cerr << "OutOfMemoryException" << XERCES_STD_QUALIFIER endl; errorCount = 2; return false; } catch (const XMLException& e) { XERCES_STD_QUALIFIER cerr << "\nError during parsing: \n" << StrX(e.getMessage()) << "\n" << XERCES_STD_QUALIFIER endl; errorCount = 1; return false; } // Print out the stats that we collected and time taken if (!errorCount) { XERCES_STD_QUALIFIER cout << filename << ": " << duration << " ms (" << handler.GetElementCount() << " elems, " << handler.GetAttrCount() << " attrs, " << handler.GetSpaceCount() << " spaces, " << handler.GetCharacterCount() << " chars)" << XERCES_STD_QUALIFIER endl; } } // // Delete the parser itself. Must be done prior to calling Terminate, below. // delete parser; XMLPlatformUtils::Terminate(); if (errorCount > 0) return false; else return true; } /************************************************************************/ /* class X3dViewCellsParseHandlers implementation */ /************************************************************************/ // --------------------------------------------------------------------------- // StdInParseHandlers: Constructors and Destructor // --------------------------------------------------------------------------- X3dViewCellsParseHandlers::X3dViewCellsParseHandlers(ViewCellsManager *viewCellsManager, const float viewCellHeight): mElementCount(0), mAttrCount(0), mCharacterCount(0), mSpaceCount(0), mViewCellsManager(viewCellsManager), mViewCellHeight(viewCellHeight) { } X3dViewCellsParseHandlers::~X3dViewCellsParseHandlers() { } // --------------------------------------------------------------------------- // StdInParseHandlers: Implementation of the SAX DocumentHandler interface // --------------------------------------------------------------------------- void X3dViewCellsParseHandlers::endElement(const XMLCh* const name) { StrX lname(name); string element(lname.LocalForm()); if (element == "Shape") EndShape(); } void X3dViewCellsParseHandlers::EndShape() { // currently processing no shape } void X3dViewCellsParseHandlers::StartIndexedFaceSet( AttributeList& attributes) { int len = attributes.getLength(); int i; // clear previous vertex indices mCurrentVertexIndices.clear(); for (i=0; i < len; i++) { string attrName(StrX(attributes.getName(i)).LocalForm()); if (attrName == "coordIndex") { StrX attrValue(attributes.getValue(i)); // handle coordIndex const char *ptr = attrValue.LocalForm(); char *endptr; while (1) { int index = strtol(ptr, &endptr, 10); if (ptr == endptr) break; if (index != -1) { mCurrentVertexIndices.push_back(index); } ptr = endptr; } } } } void X3dViewCellsParseHandlers::StartCoordinate(AttributeList& attributes) { int len = attributes.getLength(); VertexContainer vertices; int i; for (i=0; i < len; i++) { string attrName(StrX(attributes.getName(i)).LocalForm()); if (attrName == "point") { StrX attrValue(attributes.getValue(i)); const char *ptr = attrValue.LocalForm(); char *endptr; while (1) { float x = (float)strtod(ptr, &endptr); if (ptr == endptr) break; ptr = endptr; float y = (float)(float)strtod(ptr, &endptr); if (ptr == endptr) break; ptr = endptr; float z = (float)(float)strtod(ptr, &endptr); if (ptr == endptr) break; ptr = endptr; if (*ptr == ',') ptr++; Vector3 v(x, y, z); vertices.push_back(v); } } } for (i = 0; i < mCurrentVertexIndices.size(); i += 3) { Triangle3 baseTri(vertices[mCurrentVertexIndices[i + 0]], vertices[mCurrentVertexIndices[i + 1]], vertices[mCurrentVertexIndices[i + 2]]); // create view cell from base triangle mViewCellsManager->AddViewCell( mViewCellsManager->ExtrudeViewCell(baseTri, mViewCellHeight)); } } void X3dViewCellsParseHandlers::startElement(const XMLCh* const name, AttributeList& attributes) { StrX lname(name); string element(lname.LocalForm()); if (element == "IndexedFaceSet") { // create the viewcells from individual triangles StartIndexedFaceSet(attributes); } if (element == "Coordinate") { // add coordinates to the triangles StartCoordinate(attributes); } // do nothing //if (element == "Shape") {} // ignore material //if (element == "Material") {} ++ mElementCount; mAttrCount += attributes.getLength(); } void X3dViewCellsParseHandlers::characters(const XMLCh* const chars, const unsigned int length) { mCharacterCount += length; } void X3dViewCellsParseHandlers::ignorableWhitespace(const XMLCh* const chars, const unsigned int length) { mSpaceCount += length; } void X3dViewCellsParseHandlers::resetDocument() { mAttrCount = 0; mCharacterCount = 0; mElementCount = 0; mSpaceCount = 0; } // --------------------------------------------------------------------------- // StdInParseHandlers: Overrides of the SAX ErrorHandler interface // --------------------------------------------------------------------------- void X3dViewCellsParseHandlers::error(const SAXParseException& e) { XERCES_STD_QUALIFIER cerr << "\nError at (file " << StrX(e.getSystemId()) << ", line " << e.getLineNumber() << ", char " << e.getColumnNumber() << "): " << StrX(e.getMessage()) << XERCES_STD_QUALIFIER endl; } void X3dViewCellsParseHandlers::fatalError(const SAXParseException& e) { XERCES_STD_QUALIFIER cerr << "\nFatal Error at (file " << StrX(e.getSystemId()) << ", line " << e.getLineNumber() << ", char " << e.getColumnNumber() << "): " << StrX(e.getMessage()) << XERCES_STD_QUALIFIER endl; } void X3dViewCellsParseHandlers::warning(const SAXParseException& e) { XERCES_STD_QUALIFIER cerr << "\nWarning at (file " << StrX(e.getSystemId()) << ", line " << e.getLineNumber() << ", char " << e.getColumnNumber() << "): " << StrX(e.getMessage()) << XERCES_STD_QUALIFIER endl; } bool X3dParser::ParseFile(const string filename, ViewCellsManager &viewCells) { // Initialize the XML4C system try { XMLPlatformUtils::Initialize(); } catch (const XMLException& toCatch) { XERCES_STD_QUALIFIER cerr << "Error during initialization! Message:\n" << StrX(toCatch.getMessage()) << XERCES_STD_QUALIFIER endl; return false; } // // Create a SAX parser object. Then, according to what we were told on // the command line, set the options. // SAXParser* parser = new SAXParser; parser->setValidationScheme(valScheme); parser->setDoNamespaces(doNamespaces); parser->setDoSchema(doSchema); parser->setValidationSchemaFullChecking(schemaFullChecking); // // Create our SAX handler object and install it on the parser, as the // document and error handler. We are responsible for cleaning them // up, but since its just stack based here, there's nothing special // to do. // X3dViewCellsParseHandlers handler(&viewCells, mViewCellHeight); parser->setDocumentHandler(&handler); parser->setErrorHandler(&handler); unsigned long duration; int errorCount = 0; // create a faux scope so that 'src' destructor is called before // XMLPlatformUtils::Terminate { // // Kick off the parse and catch any exceptions. Create a standard // input input source and tell the parser to parse from that. // // StdInInputSource src; try { const unsigned long startMillis = XMLPlatformUtils::getCurrentMillis(); parser->parse(filename.c_str()); const unsigned long endMillis = XMLPlatformUtils::getCurrentMillis(); duration = endMillis - startMillis; errorCount = parser->getErrorCount(); } catch (const OutOfMemoryException&) { XERCES_STD_QUALIFIER cerr << "OutOfMemoryException" << XERCES_STD_QUALIFIER endl; errorCount = 2; return false; } catch (const XMLException& e) { XERCES_STD_QUALIFIER cerr << "\nError during parsing: \n" << StrX(e.getMessage()) << "\n" << XERCES_STD_QUALIFIER endl; errorCount = 1; return false; } // Print out the stats that we collected and time taken if (!errorCount) { XERCES_STD_QUALIFIER cout << filename << ": " << duration << " ms (" << handler.GetElementCount() << " elems, " << handler.GetAttrCount() << " attrs, " << handler.GetSpaceCount() << " spaces, " << handler.GetCharacterCount() << " chars)" << XERCES_STD_QUALIFIER endl; } } // // Delete the parser itself. Must be done prior to calling Terminate, below. // delete parser; XMLPlatformUtils::Terminate(); if (errorCount > 0) return false; else return true; }