📄 ac3d.cpp
字号:
// 30 Oct 2002// AC3D loader for models generated by the AC3D modeller (www.ac3d.org)// part of this source code were supplied by the AC3D project (Andy Colebourne)// eg the basic parsing of an AC3D file.// Conversion from AC3D scenegraph to OSG by GW Michel.#include <vector>#include <iostream>#include <osg/GL>#include <osg/GLU>#include <osg/Math>#include <osg/BlendFunc>#include <osg/CullFace>#include <osg/Geode>#include <osg/Group>#include <osg/Geometry>#include <osg/Light>#include <osg/LightSource>#include <osg/Material>#include <osg/Math>#include <osg/Texture2D>#include <osg/TexEnv>#include <osg/StateSet>#include <osg/ShadeModel>#include <osg/Math>#include <osg/Notify>#include <osgUtil/Tessellator>#include <osgDB/FileNameUtils>#include <osgDB/Registry>#include <osgDB/ReadFile>#include <osgDB/FileUtils>#include <osgDB/fstream>#include "Exception.h"#include "Geode.h"namespace ac3d {osg::Node*readFile(std::istream& stream, const osgDB::ReaderWriter::Options* options);}class geodeVisitor : public osg::NodeVisitor { // collects geodes from scene sub-graph attached to 'this' public: geodeVisitor(): osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) {} ~geodeVisitor() { _geodelist.clear();} // one apply for each type of Node that might be a user transform virtual void apply(osg::Geode& geode) { _geodelist.push_back(&geode); } virtual void apply(osg::Group& gp){ traverse(gp); // must continue subgraph traversal. } std::vector<const osg::Geode *> getGeodes() {return _geodelist;} protected: typedef std::vector<const osg::Geode *> Geodelist; Geodelist _geodelist;};class ReaderWriterAC : public osgDB::ReaderWriter{ public: ReaderWriterAC() { supportsExtension("ac","AC3D Database format"); } virtual const char* className() const { return "AC3D Database Reader"; } virtual ReadResult readNode(const std::string& file,const Options* options) const { std::string ext = osgDB::getFileExtension(file); if (!acceptsExtension(ext)) return ReadResult::FILE_NOT_HANDLED; // GWM added Dec 2003 - get full path name (change in osgDB handling of files). std::string fileName = osgDB::findDataFile( file, options ); osg::notify(osg::INFO) << "osgDB ac3d reader: starting reading \"" << fileName << "\"" << std::endl; // Anders Backmann - correct return if path not found if (fileName.empty()) return ReadResult::FILE_NOT_FOUND; // allocate per file data and start reading osgDB::ifstream fin; fin.open(fileName.c_str(), std::ios::in); if (!fin.is_open()) return ReadResult::FILE_NOT_FOUND; // code for setting up the database path so that internally referenced file are // searched for on relative paths. osg::ref_ptr<Options> local_opt; if (options) local_opt = static_cast<Options*>(options->clone(osg::CopyOp::DEEP_COPY_ALL)); else local_opt = new Options; local_opt->getDatabasePathList().push_back(osgDB::getFilePath(fileName)); ReadResult result = readNode(fin, local_opt.get()); if (result.validNode()) result.getNode()->setName(fileName); return result; } virtual ReadResult readNode(std::istream& fin, const Options* options) const { std::string header; fin >> header; if (header.substr(0, 4) != "AC3D") return osgDB::ReaderWriter::ReadResult::FILE_NOT_HANDLED; return ac3d::readFile(fin, options); } virtual WriteResult writeNode(const osg::Node& node,const std::string& fileName, const Options* /*options*/) const { std::string ext = osgDB::getFileExtension(fileName); if (!acceptsExtension(ext)) return WriteResult::FILE_NOT_HANDLED; geodeVisitor vs; // this collects geodes. std::vector<unsigned int>iNumMaterials; const_cast<osg::Node&>(node).accept(vs); // this parses the tree to streamd Geodes std::vector<const osg::Geode *> glist=vs.getGeodes(); osgDB::ofstream fout(fileName.c_str(), std::ios::out | std::ios::binary); // Write out the file header std::vector<const osg::Geode *>::iterator itr; fout << "AC3Db" << std::endl; // output the Materials int iNumGeodesWithGeometry = 0; for (itr=glist.begin();itr!= glist.end();itr++) { iNumMaterials.push_back(const_cast<ac3d::Geode*>(static_cast<const ac3d::Geode*>(*itr))->ProcessMaterial(fout,itr-glist.begin())); unsigned int iNumDrawables = (*itr)->getNumDrawables(); int iNumGeometries = 0; for (unsigned int i = 0; i < iNumDrawables; i++) { const osg::Drawable* pDrawable = (*itr)->getDrawable(i); if (NULL != pDrawable) { const osg::Geometry *pGeometry = pDrawable->asGeometry(); if (NULL != pGeometry) iNumGeometries++; } } if (iNumGeometries > 0) iNumGeodesWithGeometry++; } // output the Geometry unsigned int nfirstmat=0; fout << "OBJECT world" << std::endl; fout << "kids " << iNumGeodesWithGeometry << std::endl; for (itr=glist.begin();itr!= glist.end();itr++) { const_cast<ac3d::Geode*>(static_cast<const ac3d::Geode*>(*itr))->ProcessGeometry(fout,nfirstmat); nfirstmat+=iNumMaterials[itr-glist.begin()]; } fout.close(); return WriteResult::FILE_SAVED; } virtual WriteResult writeNode(const osg::Node& node,std::ostream& fout, const Options* opts) const { try { // write ac file. if(dynamic_cast<const osg::Group*>(&node)) { const osg::Group *gp=dynamic_cast<const osg::Group*>(&node); const unsigned int nch=gp->getNumChildren(); for (unsigned int i=0; i<nch; i++) { writeNode(*(gp->getChild(i)), fout, opts); } } else osg::notify(osg::WARN)<<"File must start with a geode "<<std::endl; fout.flush(); return WriteResult::FILE_SAVED; } catch(ac3d::Exception e) { osg::notify(osg::WARN)<<"Error parsing OSG tree: "<< e.getError() << std::endl; } return WriteResult::FILE_NOT_HANDLED; }private:};// now register with osg::Registry to instantiate the above// reader/writer.REGISTER_OSGPLUGIN(ac, ReaderWriterAC)namespace ac3d {enum { ObjectTypeNormal = 0, ObjectTypeGroup = 1, ObjectTypeLight = 2, SurfaceTypePolygon = 0, SurfaceTypeLineLoop = 1, SurfaceTypeLineStrip = 2, SurfaceShaded = 1<<4, SurfaceTwoSided = 1<<5};/// Returns a possibly quoted string given in the end of the current line in the streamstaticstd::stringreadString(std::istream& stream){ std::string s; stream >> std::ws; if (stream.peek() != '\"') { // Not quoted, just read the string stream >> s; } else { // look for quoted strings // throw away the quote stream.get(); // extract characters until either an error happens or a quote is found while (stream.good()) { std::istream::char_type c; stream.get(c); if (c == '\"') break; s += c; } } return s;}static voidsetTranslucent(osg::StateSet* stateSet){ osg::BlendFunc* blendFunc = new osg::BlendFunc; blendFunc->setDataVariance(osg::Object::STATIC); blendFunc->setSource(osg::BlendFunc::SRC_ALPHA); blendFunc->setDestination(osg::BlendFunc::ONE_MINUS_SRC_ALPHA); stateSet->setAttribute(blendFunc); stateSet->setMode(GL_BLEND, osg::StateAttribute::ON); stateSet->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);}// Just a container to store an ac3d materialclass MaterialData{ public: MaterialData() : mMaterial(new osg::Material), mColorArray(new osg::Vec4Array(1)) { mMaterial->setDataVariance(osg::Object::STATIC); mColorArray->setDataVariance(osg::Object::STATIC); } void readMaterial(std::istream& stream) { // note that this might be quoted std::string name = readString(stream); mMaterial->setName(name); std::string tmp; stream >> tmp; osg::Vec4 diffuse; stream >> diffuse[0] >> diffuse[1] >> diffuse[2]; mMaterial->setDiffuse(osg::Material::FRONT_AND_BACK, diffuse); stream >> tmp; osg::Vec4 ambient; stream >> ambient[0] >> ambient[1] >> ambient[2]; mMaterial->setAmbient(osg::Material::FRONT_AND_BACK, ambient); stream >> tmp; osg::Vec4 emmissive; stream >> emmissive[0] >> emmissive[1] >> emmissive[2]; mMaterial->setEmission(osg::Material::FRONT_AND_BACK, emmissive); stream >> tmp; osg::Vec4 specular; stream >> specular[0] >> specular[1] >> specular[2]; mMaterial->setSpecular(osg::Material::FRONT_AND_BACK, specular); stream >> tmp; float shininess; stream >> shininess; mMaterial->setShininess(osg::Material::FRONT_AND_BACK, shininess); stream >> tmp; float transparency; stream >> transparency; mMaterial->setTransparency(osg::Material::FRONT_AND_BACK, transparency); mTranslucent = 0 < transparency; // must correspond to the material we use for the color array below mMaterial->setColorMode(osg::Material::DIFFUSE); // this must be done past the transparency setting ... (*mColorArray)[0] = mMaterial->getDiffuse(osg::Material::FRONT_AND_BACK); } void toStateSet(osg::StateSet* stateSet) const { stateSet->setAttribute(mMaterial.get()); if (mTranslucent) setTranslucent(stateSet); } osg::Vec4Array* getColorArray() const { return mColorArray.get(); }private: osg::ref_ptr<osg::Material> mMaterial; osg::ref_ptr<osg::Vec4Array> mColorArray; bool mTranslucent;};class TextureData{ public: TextureData() : mTranslucent(false), mRepeat(true) { } bool setTexture(const std::string& name, const osgDB::ReaderWriter::Options* options, osg::TexEnv* modulateTexEnv) { mTexture2DRepeat = new osg::Texture2D; mTexture2DRepeat->setDataVariance(osg::Object::STATIC); mTexture2DRepeat->setWrap(osg::Texture2D::WRAP_S, osg::Texture2D::REPEAT); mTexture2DRepeat->setWrap(osg::Texture2D::WRAP_T, osg::Texture2D::REPEAT); mTexture2DClamp = new osg::Texture2D; mTexture2DClamp->setDataVariance(osg::Object::STATIC); mTexture2DClamp->setWrap(osg::Texture2D::WRAP_S, osg::Texture2D::CLAMP_TO_EDGE); mTexture2DClamp->setWrap(osg::Texture2D::WRAP_T, osg::Texture2D::CLAMP_TO_EDGE); std::string absFileName = osgDB::findDataFile(name, options); if (absFileName.empty())
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -