/* -*- c++ -*- * * Copyright (C) 2004, 2006 Mekensleep * * Mekensleep * 24 rue vieille du temple * 75004 Paris * licensing@mekensleep.com * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * * Authors: * Loic Dachary * Cedric Pinson * Igor Kravtchenko * */ // // This is an OpenSceneGraph IO plugin. In order to work as // expected, this code must be available using one of these three // methods: // // 1) It is dynamicaly or statically linked to the executable. // // 2) It is part of a dynamically loadable library named // libosgdb_osgchips.so (or something similar depending on the // operating system) and located in the plugin directory of // OpenSceneGraph (usually /usr/lib/osgPlugins on GNU/Linux). It will // be loaded when osgDB::ReadNodeFile or osgDB::WriteNodeFile save a // file using the OSG format and run into an osg::Node who claims to // belong to the osgchips library (as returned by the libraryName() // method). // // 3) It is part of dynamically loadable library named libosgchips.so // (or something similar depending on the operating system) and // located in the directories searched by the operating system // functions (LD_LIBRARY_PATH on GNU/Linux for instance). It will be // loaded when osgDB::WriteNodeFile tries to save an osg::Node who // claims to belong to the osgchips library (as returned by the // libraryName() method) or when osgDB::ReadNodFile is provided with // a filename whose extension is .osgchips. // // In all cases this plugin relies on static constructors and // destructors to hook themselves to the osgDB::Registry instance (all // objects whose name starts with static_). When the library is loaded // the constructors are called and register pointers to the code in // the registry. When the library is unloaded, the destructors are called // and deregister the pointers. // // This plugin will create from a cal3d .cfg file an osgCal::CoreModel object. // This object can be read with osg database features: // osg::Object* object = osgDB::readObjectFile( "file.cfg" ); // object is then dynamically casted into an osgCal::CoreModel instance. // See paladin demo in osgCal distribution for more details. // Author : Jerome Schmid #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifdef WIN32 #include #include #endif #ifdef USE_NPROFILE #include #else // USE_NPROFILE #define NPROFILE_SAMPLE(a) #endif // USE_NPROFILE #ifndef DATADIR #define DATADIR "." #endif // DATADIR #include #include #include #include #include #include #include #include #include #include #include #include #include #define LINE_BUFFER_SIZE 4096 #include #include #include #include #include #include #include #include #include #include #include #include "osgCal/CoreModel" static bool writeObjectXFG(const std::string& fileName, const osgCal::CoreModel& coreModel) { return true; } // // OSG interface to read/write from/to a file. // class ReaderWriterXFG : public osgDB::ReaderWriter { public: virtual const char* className() { return "osg Cal xfg object reader"; } bool parseSpecifications(CalCoreModel* calCoreModel, osgCal::CoreModel& coreModel, xmlXPathContextPtr xpathContext, const std::string& dir, const std::string& path, const osgDB::ReaderWriter::Options* options) const; virtual bool acceptsExtension(const std::string& extension) const { return osgDB::equalCaseInsensitive(extension, "xfg"); } bool readObjectXFG(const std::string& fileName, osgCal::CoreModel& coreModel, const osgDB::ReaderWriter::Options* options) const; void getNodeParameters(xmlNodePtr node,std::map& map) const { map.clear(); xmlAttr* attribute; for(attribute = node->properties; attribute; attribute = attribute->next) { const char* value = (const char*)xmlNodeGetContent((xmlNode*)attribute); const char* variable = (const char*)attribute->name; map[variable] = value; xmlFree((void*)value); } } virtual ReadResult readObject(const std::string& file, const osgDB::ReaderWriter::Options* options) const { std::string ext = osgDB::getLowerCaseFileExtension(file); if (!acceptsExtension(ext)) return ReadResult::FILE_NOT_HANDLED; osg::notify(osg::INFO) << "looking for file " << file << std::endl; std::string fileName = osgDB::findDataFile( file, options ); osg::notify(osg::INFO) << "found file " << fileName << std::endl; if (fileName.empty()) return ReadResult::FILE_NOT_FOUND; osg::notify(osg::INFO)<< "ReaderWriterXFG::readObject( "< coreModel = new osgCal::CoreModel; coreModel->setFilename(file); if(!readObjectXFG(fileName, *coreModel, options)) return ReadResult("failed to load correctly " + fileName); else return ReadResult(coreModel.get()); } virtual WriteResult writeObject(const osg::Object& object, const std::string& fileName, const Options* =NULL) { if(!::writeObjectXFG( fileName, static_cast(object) )) return WriteResult("failed to save coreModel in file " + fileName); else return WriteResult(WriteResult::FILE_SAVED); } }; bool ReaderWriterXFG::readObjectXFG(const std::string& fileName, osgCal::CoreModel& coreModel, const osgDB::ReaderWriter::Options* options) const { CalCoreModel* calCoreModel = coreModel.getCalCoreModel(); osg::notify(osg::INFO)<< "Loading cal3d character from "<getDatabasePathList(); if (fpl.size() > 0) dir = options->getDatabasePathList().front(); else { gchar *dirname = g_path_get_dirname(fileName.c_str()); dir = std::string(dirname); g_free(dirname); } } coreModel._configurable=true; bool result; { xmlDocPtr document = xmlParseFile(fileName.c_str()); xmlXPathContextPtr xpathContext = xmlXPathNewContext(document); if(xpathContext == NULL) osg::notify(osg::FATAL)<< "unable to create new XPath context " << std::endl; result = parseSpecifications(calCoreModel, coreModel, xpathContext, dir, fileName, options); if (!result) osg::notify(osg::FATAL)<< fileName << ": an error occur during parsing " << std::endl; xmlFreeDoc(document); xmlXPathFreeContext(xpathContext); } return result; } bool ReaderWriterXFG::parseSpecifications(CalCoreModel* calCoreModel, osgCal::CoreModel& coreModel, xmlXPathContextPtr xpathContext, const std::string& dir, const std::string& path, const osgDB::ReaderWriter::Options* options) const { const osgCal::IOOptions *specialOptions = dynamic_cast (options); osgCal::Monitor *mon = NULL; if (specialOptions) mon = specialOptions->getMonitor(); { char* xpath = "/cal3d"; xmlXPathObjectPtr xpathObj = xmlXPathEvalExpression((xmlChar*)xpath, xpathContext); if(xpathObj == NULL) osg::notify(osg::FATAL) << "LoadXML: eval " << xpath << " file in path " << path << std::endl; xmlNodeSetPtr nodes = xpathObj->nodesetval; if(nodes) { if(nodes->nodeNr == 1) { xmlNodePtr node = nodes->nodeTab[0]; switch(node->type) { case XML_ELEMENT_NODE: { xmlAttr* attribute; for(attribute = node->properties; attribute; attribute = attribute->next) { const char* value = (const char*)xmlNodeGetContent((xmlNode*)attribute); const char* variable = (const char*)attribute->name; if(variable == std::string("collision_default")) coreModel.setCollisionDefault(!strcmp(value, "yes")); if(variable == std::string("version")) coreModel.setVersion(atoi(value)); xmlFree((void*)value); } } break; default: osg::notify(osg::FATAL) << path << xpath << " expected ELEMENT node got " << node->type << std::endl; return false; break; } } else { osg::notify(osg::FATAL) << path << xpath << " expected exactly one ELEMENT node got " << nodes->nodeNr << " elements" << std::endl; } } else { osg::notify(osg::FATAL) << xpath << " not found in " << path << std::endl; return false; } xmlXPathFreeObject(xpathObj); } { char* xpath = "/cal3d/skeleton/@name"; xmlXPathObjectPtr xpathObj = xmlXPathEvalExpression((xmlChar*)xpath, xpathContext); if(xpathObj == NULL) osg::notify(osg::FATAL) << "LoadXML: eval " << xpath << " file in path " << path << std::endl; xmlNodeSetPtr nodes = xpathObj->nodesetval; if(nodes) { if(nodes->nodeNr == 1) { xmlNodePtr node = nodes->nodeTab[0]; switch(node->type) { case XML_ATTRIBUTE_NODE: { const char* name = (const char*)xmlNodeGetContent(node); std::string skeleton = dir + "/" + name; xmlFree((void*)name); osg::notify(osg::INFO) << " skeleton " << skeleton << std::endl; if(!calCoreModel->loadCoreSkeleton(skeleton)) osg::notify(osg::FATAL)<< " loadCoreSkeleton(" << skeleton << ") " << CalError::getLastErrorDescription() << " at " << xpath << " in " << path << std::endl; } break; default: osg::notify(osg::FATAL) << path << xpath << " expected ATTRIBUTE node got " << node->type << std::endl; return false; break; } } } else { osg::notify(osg::FATAL) << xpath << " not found in " << path << std::endl; return false; } xmlXPathFreeObject(xpathObj); } { char* xpath = "/cal3d/library/mesh"; xmlXPathObjectPtr xpathObj = xmlXPathEvalExpression((xmlChar*)xpath, xpathContext); if(xpathObj == NULL) osg::notify(osg::FATAL) << "LoadXML: eval " << xpath << " file in path " << path << std::endl; osgCal::CoreModel::Name2Filename meshName2Filename; xmlNodeSetPtr nodes = xpathObj->nodesetval; if(nodes && nodes->nodeNr >= 1) { for(int i = 0; i < nodes->nodeNr; i++) { std::string filename; std::string name; osgCal::CoreModel::MeshDescription mesh; xmlNodePtr node = nodes->nodeTab[i]; switch(node->type) { case XML_ELEMENT_NODE: { xmlAttr* attribute; for(attribute = node->properties; attribute; attribute = attribute->next) { const char* value = (const char*)xmlNodeGetContent((xmlNode*)attribute); const char* variable = (const char*)attribute->name; if(variable == std::string("file")) filename = dir + "/" + value; else if(variable == std::string("name")) name = value; else if(variable == std::string("version")) ; else if(variable == std::string("material0")) ; else if(variable == std::string("material1")) ; else if(variable == std::string("collision")) ; else if(variable == std::string("software")) ; else osg::notify(osg::FATAL) << "unexpected attribute " << variable << "=\"" << value << "\" at " << xpath << " in " << path << std::endl; xmlFree((void*)value); } getNodeParameters(node,mesh); } break; default: osg::notify(osg::FATAL) << path << xpath << " expected ELEMENT node got " <type << std::endl; return false; break; } if(filename == "") osg::notify(osg::FATAL) << "filename attribute not set or empty at occurence " << i << " of " << xpath << " in " <nodesetval; if(nodes && nodes->nodeNr >= 1) { for(int i = 0; i < nodes->nodeNr; i++) { std::string filename; std::string name; std::string targetmap; std::string transparency; std::string envmap; xmlNodePtr node = nodes->nodeTab[i]; switch(node->type) { case XML_ELEMENT_NODE: { xmlAttr* attribute; for(attribute = node->properties; attribute; attribute = attribute->next) { const char* value = (const char*)xmlNodeGetContent((xmlNode*)attribute); const char* variable = (const char*)attribute->name; if(variable == std::string("file")) filename = dir + "/" + value; else if(variable == std::string("name")) name = value; else if(variable == std::string("targetmap")) targetmap = value; else if(variable == std::string("transparency")) transparency = value; else if(variable == std::string("envmap")) envmap = value; else if(variable == std::string("version")) ; else osg::notify(osg::FATAL) << "unexpected attribute " << variable << "\"" << value << "\" at " << xpath << " in " << path << std::endl; xmlFree((void*)value); } } break; default: osg::notify(osg::FATAL) << path << xpath << " expected ELEMENT node got " << node->type << std::endl; return false; break; } if(filename == "") osg::notify(osg::FATAL) << "filename attribute not set or empty at occurence " << i << " of " << xpath << " in " << path << std::endl; if(name == "") osg::notify(osg::FATAL) << "name attribute not set or empty at occurence " << i << " of " << xpath << " in " << path << std::endl; osg::notify(osg::INFO) << " material " << filename << std::endl; int materialId = calCoreModel->loadCoreMaterial(filename, name); if(materialId < 0) { osg::notify(osg::FATAL) << "loadCoreMaterial(" << filename << "," << name << ") " << CalError::getLastErrorDescription() << " at " << xpath << " in " << path << std::endl; } else { osgCal::CoreModel::Material mat; mat.targetmap = targetmap; mat.transparency = transparency; if (envmap != "") mat.envmap = dir + "/" + envmap; coreModel._materials[ name ] = mat; char *dir2 = 0; dir2 = g_path_get_dirname(filename.c_str()); // create a single set (0), each material belongs to a single thread named after its // material id. calCoreModel->createCoreMaterialThread(materialId); calCoreModel->setCoreMaterialId(materialId, 0, materialId); CalCoreMaterial* material = calCoreModel->getCoreMaterial(materialId); for(std::vector::iterator i2 = material->getVectorMap().begin(); i2 != material->getVectorMap().end(); i2++) { i2->strFilename = std::string(dir2) + "/" + i2->strFilename; } g_free(dir2); } } } else { osg::notify(osg::FATAL) << xpath << " not found in " << path << std::endl; return false; } xmlXPathFreeObject(xpathObj); } { char* xpath = "/cal3d/library/animation"; xmlXPathObjectPtr xpathObj = xmlXPathEvalExpression((xmlChar*)xpath, xpathContext); if(xpathObj == NULL) { osg::notify(osg::FATAL) << "eval " << xpath << " file in " << path << std::endl; return false; } xmlNodeSetPtr nodes = xpathObj->nodesetval; if (mon) mon->setProgressLength( nodes->nodeNr ); if(nodes && nodes->nodeNr >= 1) { for(int i = 0; i < nodes->nodeNr; i++) { if (mon) mon->progress(); std::string filename; std::string name; xmlNodePtr node = nodes->nodeTab[i]; switch(node->type) { case XML_ELEMENT_NODE: { xmlAttr* attribute; for(attribute = node->properties; attribute; attribute = attribute->next) { const char* value = (const char*)xmlNodeGetContent((xmlNode*)attribute); const char* variable = (const char*)attribute->name; if(variable == std::string("file")) filename = dir + "/" + value; else if(variable == std::string("name")) name = value; else if(variable == std::string("version")) ; else osg::notify(osg::FATAL) << "unexpected attribute " << variable << "=\"" << value << "\" at " << xpath << " in " << path << std::endl; xmlFree((void*)value); } } break; default: osg::notify(osg::FATAL) << path << xpath << " expected ELEMENT node got " << node->type << std::endl; return false; break; } if(filename == "") osg::notify(osg::FATAL) << "filename attribute not set or empty at occurence " << i << " of " << xpath << " in " << path << std::endl; if(name == "") osg::notify(osg::FATAL) << "name attribute not set or empty at occurence " << i << " of " << xpath << " in " << path << std::endl; osg::notify(osg::INFO) << " animation " << filename<< std::endl; //CalLoaderAnimationOptions opts; //opts.bUseOneChunkForKeyframes = true; //char str[200]; //sprintf(str, "Load Animation \"%s\"", filename.c_str()); NPROFILE_SAMPLE("Load Animation"); int coreAnimationId = calCoreModel->loadCoreAnimation(filename, name); //int coreAnimationId = calCoreModel->loadCoreAnimation(filename, name, &opts); if(coreAnimationId < 0) osg::notify(osg::FATAL) << "loadCoreAnimation(" << filename << "," << name << ") " << CalError::getLastErrorDescription() << " at " << xpath << " in " << path << std::endl; CalCoreAnimation *anim = calCoreModel->getCoreAnimation(coreAnimationId); if (anim) { //CalSaverAnimationOptions opts; //opts.bCompressKeyframes = true; //CalSaver::saveCoreAnimation( anim->getFilename(), anim, &opts); } } } else { osg::notify(osg::FATAL) << xpath << " not found in " << path << std::endl; return false; } xmlXPathFreeObject(xpathObj); } //int animTime2 = timeGetTime(); //animTime2 -= animTime1; // char str[200]; //sprintf(str, "%ld", animTime2); //MessageBox(NULL, str, "hop", MB_OK); { char* xpath = "/cal3d/common/mesh"; xmlXPathObjectPtr xpathObj = xmlXPathEvalExpression((xmlChar*)xpath, xpathContext); if(xpathObj == NULL) { osg::notify(osg::FATAL) << "eval " << xpath << " file in " << path << std::endl; return false; } std::set duplicates; xmlNodeSetPtr nodes = xpathObj->nodesetval; if(nodes && nodes->nodeNr >= 1) { for(int i = 0; i < nodes->nodeNr; i++) { std::string line; xmlNodePtr node = nodes->nodeTab[i]; // for (xmlNodePtr snode=node;snode;snode=snode->next) { switch(node->type) { case XML_ELEMENT_NODE: { //std::string line; //osgCal::CoreModel::MeshDescription map; std::map map; getNodeParameters(node, map); std::string meshName = map["name"]; //line += "name" + std::string("=") + map["name"] + " "; if(meshName == "") { osg::notify(osg::FATAL) << "name attribute not set or empty " << xpath << " in " << path << std::endl; return false; } if(duplicates.find(meshName) != duplicates.end()) { osg::notify(osg::FATAL) << path << xpath << "duplicate mesh " << meshName << ", ignored" << std::endl; } else { duplicates.insert(meshName); coreModel._commonMeshes.push_back(meshName); } } break; case XML_TEXT_NODE: break; default: osg::notify(osg::FATAL) << path << xpath << " expected ELEMENT node got " << node->type << std::endl; return false; break; } } } xmlXPathFreeObject(xpathObj); } { char* xpath = "/cal3d/parameters/parameter"; xmlXPathObjectPtr xpathObj = xmlXPathEvalExpression((xmlChar*)xpath, xpathContext); if(xpathObj == NULL) { osg::notify(osg::FATAL) << "eval " << xpath << " file in " << path << std::endl; return false; } std::set duplicates; xmlNodeSetPtr nodes = xpathObj->nodesetval; if(nodes && nodes->nodeNr >= 1) { for(int i = 0; i < nodes->nodeNr; i++) { std::string line; xmlNodePtr node = nodes->nodeTab[i]; std::map map; getNodeParameters(node,map); if (map.find("id")==map.end()) { osg::notify(osg::FATAL) << "error no id for parameter " << xpath << std::endl; return false; } if (map.find("type")==map.end()) { osg::notify(osg::FATAL) << "error no type specified for parameter " << map["id"] << " at " << xpath << std::endl; return false; } if (duplicates.find(map["id"])!=duplicates.end()) { osg::notify(osg::FATAL) << path << xpath << " duplicate parameter " << map["id"] << " " << map["type"] << ", ignored" << std::endl; continue; } osgCal::CoreModel::ParameterDescription parameter; parameter._type=map["type"]; std::string parameterName=map["id"]; for (xmlNodePtr snode=node->children;snode;snode=snode->next) { switch(snode->type) { case XML_ELEMENT_NODE: { std::map smap; getNodeParameters(snode,smap); std::string nodeName=(const char*)snode->name; if (nodeName=="opacity") { if (smap.find("default")==smap.end()) { osg::notify(osg::FATAL) << "error parameter \"default\" not found in parameter " << parameterName << " at " << xpath << std::endl; return false; } if (smap.find("alterable")==smap.end()) { osg::notify(osg::FATAL) << "error parameter \"alterable\" not found in parameter " << parameterName << " at " << xpath << std::endl; return false; } parameter._opacity._opacity=atoi(smap["default"].c_str()); parameter._opacity._modifiable=(smap["alterable"]=="true"?true:false); if (smap.find("text")!=smap.end()) parameter._opacity._text=smap["text"]; } else if (nodeName=="hue_set") { if (smap.find("default")==smap.end()) { osg::notify(osg::FATAL) << "error parameter \"default\" not found in parameter " << parameterName << " at " << xpath << std::endl; return false; } if (smap.find("alterable")==smap.end()) { osg::notify(osg::FATAL) << "error parameter \"alterable\" not found in parameter " << parameterName << " at " << xpath << std::endl; return false; } std::string colorSelected=smap["default"]; parameter._colors._selected=atoi(colorSelected.c_str()); parameter._colors._modifiable=(smap["alterable"]=="true"?true:false); if (smap.find("text")!=smap.end()) parameter._colors._text=smap["text"]; for (xmlNodePtr cnode=snode->children;cnode;cnode=cnode->next) { switch(cnode->type) { case XML_ELEMENT_NODE: { std::map color; getNodeParameters(cnode,color); if (color.find("id")==color.end()) { osg::notify(osg::FATAL) << "error parameter \"id\" not found in hue from parameter " << parameterName << " at " << xpath << std::endl; return false; } if (color.find("h")==color.end()) { osg::notify(osg::FATAL) << "error parameter \"h\" not found in hue from parameter " << parameterName << " at " << xpath << std::endl; return false; } if (color.find("s")==color.end()) { osg::notify(osg::FATAL) << "error parameter \"s\" not found in hue from parameter " << parameterName << " at " << xpath << std::endl; return false; } if (color.find("l")==color.end()) { osg::notify(osg::FATAL) << "error parameter \"l\" not found in hue from parameter " << parameterName << " at " << xpath << std::endl; return false; } int index = atoi(color["id"].c_str()); osgCal::CoreModel::ParameterDescription::ColorElement colorDest; colorDest[0] = atoi(color["h"].c_str()); colorDest[1] = atoi(color["s"].c_str()); colorDest[2] = atoi(color["l"].c_str()); colorDest.tn[0] = atoi(color["tnr"].c_str()); colorDest.tn[1] = atoi(color["tng"].c_str()); colorDest.tn[2] = atoi(color["tnb"].c_str()); parameter._colors._colors[index] = colorDest; // parameter._colors._colors.insert(index,colorDest); } break; default: break; } } if (parameter._colors._colors.find(parameter._colors._selected)==parameter._colors._colors.end()) { osg::notify(osg::FATAL) << "error hue selected (" << parameterName << ") does not exist in the hue set at " << xpath << std::endl; return false; } } else if (nodeName=="color_set") { if (smap.find("default")==smap.end()) { osg::notify(osg::FATAL) << "error parameter \"default\" not found in parameter " << parameterName << " at " << xpath << std::endl; return false; } if (smap.find("alterable")==smap.end()) { osg::notify(osg::FATAL) << "error parameter \"alterable\" not found in parameter " << parameterName << " at " << xpath << std::endl; return false; } std::string colorSelected=smap["default"]; parameter._colors._selected=atoi(colorSelected.c_str()); parameter._colors._modifiable=(smap["alterable"]=="true"?true:false); if (smap.find("text")!=smap.end()) parameter._colors._text=smap["text"]; for (xmlNodePtr cnode=snode->children;cnode;cnode=cnode->next) { switch(cnode->type) { case XML_ELEMENT_NODE: { std::map color; getNodeParameters(cnode,color); if (color.find("id")==color.end()) { osg::notify(osg::FATAL) << "error parameter \"id\" not found in color from parameter " << parameterName << " at " << xpath << std::endl; return false; } if (color.find("r")==color.end()) { osg::notify(osg::FATAL) << "error parameter \"r\" not found in color from parameter " << parameterName << " at " << xpath << std::endl; return false; } if (color.find("g")==color.end()) { osg::notify(osg::FATAL) << "error parameter \"g\" not found in color from parameter " << parameterName << " at " << xpath << std::endl; return false; } if (color.find("b")==color.end()) { osg::notify(osg::FATAL) << "error parameter \"b\" not found in color from parameter " << parameterName << " at " << xpath << std::endl; return false; } int index = atoi(color["id"].c_str()); osgCal::CoreModel::ParameterDescription::ColorElement colorDest; colorDest[0] = atoi(color["r"].c_str()); colorDest[1] = atoi(color["g"].c_str()); colorDest[2] = atoi(color["b"].c_str()); colorDest.tn[0] = atoi(color["tnr"].c_str()); colorDest.tn[1] = atoi(color["tng"].c_str()); colorDest.tn[2] = atoi(color["tnb"].c_str()); parameter._colors._colors[index]=colorDest; // parameter._colors._colors.insert(index,colorDest); } break; default: break; } } if (parameter._colors._colors.find(parameter._colors._selected)==parameter._colors._colors.end()) { osg::notify(osg::FATAL) << "error color selected (" << parameterName << ") does not exist in the color set at " << xpath << std::endl; return false; } } else if (nodeName=="showin") { } else { osg::notify(osg::FATAL) << "error unknow node type " << nodeName << " at " << xpath << std::endl; assert(0); } } break; case XML_TEXT_NODE: break; default: osg::notify(osg::FATAL) << path << xpath << " expected ELEMENT node got " << snode->type << std::endl; return false; break; } } duplicates.insert(parameterName); coreModel._parameters[parameterName]=parameter; } } xmlXPathFreeObject(xpathObj); } { char* xpath = "/cal3d/layers/layer"; xmlXPathObjectPtr xpathObj = xmlXPathEvalExpression((xmlChar*)xpath, xpathContext); if(xpathObj == NULL) { osg::notify(osg::FATAL) << "eval " << xpath << " file in " << path << std::endl; return false; } std::set duplicates; xmlNodeSetPtr nodes = xpathObj->nodesetval; if (nodes && nodes->nodeNr >= 1) { for (int i = 0; i < nodes->nodeNr; i++) { xmlNodePtr node = nodes->nodeTab[i]; switch(node->type) { case XML_ELEMENT_NODE: { std::string line; std::map map; getNodeParameters(node,map); if (map.find("name")==map.end()) { osg::notify(osg::FATAL) << "error layer \"name\" not found at " << xpath << std::endl; return false; } if (map.find("filename")==map.end()) { osg::notify(osg::FATAL) << "error layer \"filename\" not found from " << map["name"] << " at " << xpath << std::endl; return false; } if (map.find("mode")==map.end()) { osg::notify(osg::FATAL) << "error layer \"mode\" not found from " << map["name"] << " at " << xpath << std::endl; return false; } std::string mode = map["mode"]; std::string name = map["name"]; if (mode!="normal" && mode!="additive" && mode!="multiply" && mode!="overlay") { osg::notify(osg::FATAL) << "error layer " << name << " has an unknown mode (" << mode << ")" << std::endl; return false; } if (duplicates.find(name) != duplicates.end()) osg::notify(osg::FATAL) << path << xpath << "duplicate layer " << name << ", ignored" << std::endl; else { std::string filename = dir + "/" + map["filename"]; duplicates.insert(name); osgCal::CoreModel::LayerDescription layer; layer._file = filename; layer._mode = mode; layer._suffix = osgDB::getLowerCaseFileExtension(filename); if (map.find("textureformat") == map.end()) layer._textureFormat = osgCal::CoreModel::LayerDescription::TEXTUREFORMAT_DXT5; else { const std::string &fmt = map["textureformat"]; if (fmt == "DXT1") layer._textureFormat = osgCal::CoreModel::LayerDescription::TEXTUREFORMAT_DXT1; else if (fmt == "DXT3") layer._textureFormat = osgCal::CoreModel::LayerDescription::TEXTUREFORMAT_DXT3; else if (fmt == "DXT5") layer._textureFormat = osgCal::CoreModel::LayerDescription::TEXTUREFORMAT_DXT5; else if (fmt == "RGB32") layer._textureFormat = osgCal::CoreModel::LayerDescription::TEXTUREFORMAT_RGB32; else if (fmt == "RGB16") layer._textureFormat = osgCal::CoreModel::LayerDescription::TEXTUREFORMAT_RGB16; } coreModel._layers[name] = layer; } } break; case XML_TEXT_NODE: break; default: osg::notify(osg::FATAL) << path << xpath << " expected ELEMENT node got " << node->type << std::endl; return false; break; } } } xmlXPathFreeObject(xpathObj); } { char* xpath = "/cal3d/uislots"; xmlXPathObjectPtr xpathObj = xmlXPathEvalExpression((xmlChar*)xpath, xpathContext); if(xpathObj == NULL) { osg::notify(osg::FATAL) << "eval " << xpath << " file in " << path << std::endl; return false; } xmlNodeSetPtr nodes = xpathObj->nodesetval; if(nodes && nodes->nodeNr >= 1) { for(int i = 0; i < nodes->nodeNr; i++) { std::set duplicates; std::string line; xmlNodePtr node = nodes->nodeTab[i]; std::map slotMap; getNodeParameters(node, slotMap); if (slotMap.find("type") == slotMap.end()) { osg::notify(osg::FATAL) << "error slot has no type from " << xpath << std::endl; return false; } std::string slotType = slotMap["type"]; for (xmlNodePtr snode=node->children;snode;snode=snode->next) { switch(snode->type) { case XML_ELEMENT_NODE: { std::map map; getNodeParameters(snode, map); if (map.find("name") == map.end()) { osg::notify(osg::FATAL) << "error slots type " << slotType << " has a slot with no name at " << xpath << std::endl; return false; } std::string slotName = map["name"]; if (duplicates.find(slotName) != duplicates.end()) { osg::notify(osg::FATAL) << path << xpath << "duplicate slot " << slotName << " from slot " << slotType <<", ignored" << std::endl; } else { std::string slotLine = slotType + "/" + slotName; osgCal::CoreModel::SlotDescription slot; std::set duplicatesMesh; std::set duplicatesTextures; for (xmlNodePtr ssnode = snode->children; ssnode; ssnode = ssnode->next) { switch(ssnode->type) { case XML_ELEMENT_NODE: { std::string nodeName = (const char*)ssnode->name; std::map smap; getNodeParameters(ssnode, smap); if (nodeName=="mesh") { if (smap.find("name") == smap.end()) { osg::notify(osg::FATAL) << "error mesh \"name\" missed from slot " << slotLine << " at " << xpath << std::endl; return false; } std::string meshName = smap["name"]; if (duplicatesMesh.find(meshName) != duplicatesMesh.end()) { osg::notify(osg::FATAL) << path << xpath << "duplicate mesh " << meshName << " from slot " << slotLine <<", ignored" << std::endl; } else { duplicatesMesh.insert(meshName); slot._meshes.push_back(meshName); } } else if (nodeName == "texture") { if (smap.find("targetmap") == smap.end()) { osg::notify(osg::FATAL) << "error mesh \"targetmap\" is missed from slot " << slotLine << " at " << xpath << std::endl; return false; } std::string targetName = smap["targetmap"]; //if (targetName == "hairmap" || targetName == "headmap" || targetName == "bodymap") { if (duplicatesTextures.find(targetName) != duplicatesTextures.end()) { osg::notify(osg::FATAL) << path << xpath << "duplicate texture " << targetName << " from slot " << slotLine <<", ignored" << std::endl; } else { duplicatesTextures.insert(targetName); if (smap.find("mask") != smap.end()) { if (smap["mask"] != "") slot._textures[targetName]._mask = dir + "/" + smap["mask"]; else slot._textures[targetName]._mask = ""; } if (smap.find("alpha") != smap.end()) { if (smap["alpha"] != "") slot._textures[targetName]._alpha = dir + "/" + smap["alpha"]; else slot._textures[targetName]._alpha = ""; } std::set duplicatesLayer; for (xmlNodePtr tnode = ssnode->children; tnode; tnode = tnode->next) { switch(tnode->type) { case XML_ELEMENT_NODE: { std::map tmap; getNodeParameters(tnode,tmap); if (tmap.find("name") == tmap.end()) { osg::notify(osg::FATAL) << "error layer \"name\" is missing from slot " << slotLine << " at " << xpath << std::endl; return false; } std::string layerName = tmap["name"]; if(coreModel._layers.find(layerName) == coreModel._layers.end()) { osg::notify(osg::FATAL) << path << xpath << " layer " << layerName << " as found at " << slotLine <<" was not defined as a layer, ignored" << std::endl; continue; } if(duplicatesLayer.find(layerName) != duplicatesLayer.end()) { osg::notify(osg::FATAL) << path << xpath << "duplicate layer " << layerName << " from slot " << slotLine <<", ignored" << std::endl; continue; } const osgCal::CoreModel::LayerDescription& layer = coreModel._layers[layerName]; osgCal::CoreModel::SlotDescription::LayerDescription ml; ml._layer = layerName; if(tmap.find("adjust_id") != tmap.end() && tmap["adjust_id"] != "") { ml._parameter = tmap["adjust_id"]; if(coreModel._parameters.find(ml._parameter) == coreModel._parameters.end()) { osg::notify(osg::FATAL) << path << xpath << " adjust_id " << ml._parameter << " as found at " << slotLine <<" was not defined as a parameter, ignored" << std::endl; continue; } const osgCal::CoreModel::ParameterDescription& parameter = coreModel._parameters[ml._parameter]; bool errors = false; if(parameter._type == "hue") { if(layer._suffix != "gif") { osg::notify(osg::FATAL) << path << xpath << " adjust_id " << ml._parameter << " as found at " << slotLine <<" of type hue but the layer " << layerName << " is not a gif, ignored" << std::endl; errors = true; } if(layer._mode != "normal") { osg::notify(osg::FATAL) << path << xpath << " adjust_id " << ml._parameter << " as found at " << slotLine <<" of type hue but the layer " << layerName << " is not in mode normal, ignored" << std::endl; errors = true; } } else if(parameter._type == "color") { if(layer._mode != "normal") { osg::notify(osg::FATAL) << path << xpath << " adjust_id " << ml._parameter << " as found at " << slotLine <<" of type color but the layer " << layerName << " is in mode " << layer._mode << " but should be in mode normal, ignored" << std::endl; errors = true; } } else if(parameter._type == "none" || parameter._type == "opacity") { } if(errors) continue; } duplicatesLayer.insert(layerName); slot._textures[targetName]._layers.push_back(ml); } break; default: break; } } } //} } else { std::string nodetype=(const char*)ssnode->name; osg::notify(osg::FATAL) << "error slot type " << slotLine << " has an unkown node (" << nodetype <<") at " << xpath << std::endl; return false; } } break; default: break; } } duplicates.insert(slotName); coreModel._slots[slotType][slotName] = slot; } } break; default: break; } } } } xmlXPathFreeObject(xpathObj); } return true; } osgDB::RegisterReaderWriterProxy static_readerWriter_XFG_Proxy;