2002-10-31 20:51:09 +08:00
|
|
|
// 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.
|
|
|
|
|
2006-11-15 00:37:07 +08:00
|
|
|
#include <vector>
|
|
|
|
#include <iostream>
|
2002-10-31 20:51:09 +08:00
|
|
|
|
2006-11-15 00:37:07 +08:00
|
|
|
#include <osg/GL>
|
|
|
|
#include <osg/GLU>
|
2002-10-31 20:51:09 +08:00
|
|
|
|
2006-11-15 00:37:07 +08:00
|
|
|
#include <osg/Math>
|
|
|
|
#include <osg/BlendFunc>
|
2002-10-31 20:51:09 +08:00
|
|
|
#include <osg/CullFace>
|
|
|
|
#include <osg/Geode>
|
|
|
|
#include <osg/Group>
|
2006-11-15 00:37:07 +08:00
|
|
|
#include <osg/Geometry>
|
2002-10-31 20:51:09 +08:00
|
|
|
#include <osg/Light>
|
|
|
|
#include <osg/LightSource>
|
|
|
|
#include <osg/Material>
|
2006-11-15 00:37:07 +08:00
|
|
|
#include <osg/Math>
|
2002-10-31 20:51:09 +08:00
|
|
|
#include <osg/Texture2D>
|
|
|
|
#include <osg/TexEnv>
|
|
|
|
#include <osg/StateSet>
|
2006-11-15 00:37:07 +08:00
|
|
|
#include <osg/ShadeModel>
|
|
|
|
#include <osg/Math>
|
2002-10-31 20:51:09 +08:00
|
|
|
#include <osg/Notify>
|
|
|
|
|
2007-01-08 19:23:52 +08:00
|
|
|
#include <osgUtil/Tessellator>
|
2002-10-31 20:51:09 +08:00
|
|
|
|
|
|
|
#include <osgDB/FileNameUtils>
|
|
|
|
#include <osgDB/Registry>
|
|
|
|
#include <osgDB/ReadFile>
|
|
|
|
#include <osgDB/FileUtils>
|
|
|
|
|
2003-10-12 23:20:09 +08:00
|
|
|
#include "Exception.h"
|
|
|
|
#include "Geode.h"
|
|
|
|
|
2006-11-15 00:37:07 +08:00
|
|
|
namespace ac3d {
|
2003-10-12 23:20:09 +08:00
|
|
|
|
2006-11-15 00:37:07 +08:00
|
|
|
osg::Node*
|
|
|
|
readFile(std::istream& stream, const osgDB::ReaderWriter::Options* options);
|
|
|
|
|
|
|
|
}
|
2005-04-30 21:54:21 +08:00
|
|
|
|
2003-10-12 23:20:09 +08:00
|
|
|
class geodeVisitor : public osg::NodeVisitor { // collects geodes from scene sub-graph attached to 'this'
|
|
|
|
public:
|
|
|
|
geodeVisitor():
|
|
|
|
osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) {}
|
|
|
|
|
2004-01-09 05:39:14 +08:00
|
|
|
~geodeVisitor() { _geodelist.clear();}
|
2003-10-12 23:20:09 +08:00
|
|
|
|
2006-11-15 00:37:07 +08:00
|
|
|
// one apply for each type of Node that might be a user transform
|
2003-10-12 23:20:09 +08:00
|
|
|
virtual void apply(osg::Geode& geode) {
|
2004-01-09 05:39:14 +08:00
|
|
|
_geodelist.push_back(&geode);
|
|
|
|
}
|
2003-10-12 23:20:09 +08:00
|
|
|
virtual void apply(osg::Group& gp){
|
2004-01-09 05:39:14 +08:00
|
|
|
traverse(gp); // must continue subgraph traversal.
|
|
|
|
}
|
|
|
|
std::vector<const osg::Geode *> getGeodes() {return _geodelist;}
|
2003-10-12 23:20:09 +08:00
|
|
|
protected:
|
|
|
|
|
|
|
|
typedef std::vector<const osg::Geode *> Geodelist;
|
|
|
|
Geodelist _geodelist;
|
|
|
|
};
|
2002-10-31 20:51:09 +08:00
|
|
|
|
|
|
|
class ReaderWriterAC : public osgDB::ReaderWriter
|
|
|
|
{
|
|
|
|
public:
|
2004-10-26 18:26:43 +08:00
|
|
|
virtual const char* className() const { return "AC3D Database Reader"; }
|
2002-10-31 20:51:09 +08:00
|
|
|
|
2004-11-23 23:29:52 +08:00
|
|
|
virtual bool acceptsExtension(const std::string& extension) const
|
2002-10-31 20:51:09 +08:00
|
|
|
{
|
|
|
|
return osgDB::equalCaseInsensitive(extension,"ac");
|
|
|
|
}
|
2006-11-15 00:37:07 +08:00
|
|
|
virtual ReadResult readNode(const std::string& file,const Options* options) const
|
2002-10-31 20:51:09 +08:00
|
|
|
{
|
2006-11-15 00:37:07 +08:00
|
|
|
std::string ext = osgDB::getFileExtension(file);
|
2005-01-03 19:20:21 +08:00
|
|
|
if (!acceptsExtension(ext)) return ReadResult::FILE_NOT_HANDLED;
|
|
|
|
|
2004-01-09 05:39:14 +08:00
|
|
|
// GWM added Dec 2003 - get full path name (change in osgDB handling of files).
|
2004-11-23 07:54:45 +08:00
|
|
|
std::string fileName = osgDB::findDataFile( file, options );
|
2006-11-15 00:37:07 +08:00
|
|
|
osg::notify(osg::INFO) << "osgDB ac3d reader: starting reading \"" << fileName << "\"" << std::endl;
|
2004-01-09 05:39:14 +08:00
|
|
|
|
|
|
|
// Anders Backmann - correct return if path not found
|
|
|
|
if (fileName.empty()) return ReadResult::FILE_NOT_FOUND;
|
|
|
|
|
2006-11-15 00:37:07 +08:00
|
|
|
// allocate per file data and start reading
|
|
|
|
std::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;
|
2008-01-21 22:42:52 +08:00
|
|
|
local_opt->getDatabasePathList().push_back(osgDB::getFilePath(fileName));
|
2004-11-23 18:46:37 +08:00
|
|
|
|
2006-11-15 00:37:07 +08:00
|
|
|
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
|
2003-10-12 23:20:09 +08:00
|
|
|
{
|
2006-11-15 00:37:07 +08:00
|
|
|
std::string ext = osgDB::getFileExtension(fileName);
|
2003-10-12 23:20:09 +08:00
|
|
|
if (!acceptsExtension(ext)) return WriteResult::FILE_NOT_HANDLED;
|
2004-01-09 05:39:14 +08:00
|
|
|
geodeVisitor vs; // this collects geodes.
|
|
|
|
std::vector<unsigned int>iNumMaterials;
|
2006-11-15 00:37:07 +08:00
|
|
|
const_cast<osg::Node&>(node).accept(vs); // this parses the tree to streamd Geodes
|
2004-01-09 05:39:14 +08:00
|
|
|
std::vector<const osg::Geode *> glist=vs.getGeodes();
|
2003-10-12 23:20:09 +08:00
|
|
|
std::ofstream fout(fileName.c_str(), std::ios::out | std::ios::binary);
|
2004-01-09 05:39:14 +08:00
|
|
|
// Write out the file header
|
|
|
|
std::vector<const osg::Geode *>::iterator itr;
|
|
|
|
fout << "AC3Db" << std::endl;
|
|
|
|
// output the Materials
|
2007-06-06 19:34:19 +08:00
|
|
|
int iNumGeodesWithGeometry = 0;
|
|
|
|
for (itr=glist.begin();itr!= glist.end();itr++)
|
|
|
|
{
|
2003-10-12 23:20:09 +08:00
|
|
|
iNumMaterials.push_back(const_cast<ac3d::Geode*>(static_cast<const ac3d::Geode*>(*itr))->ProcessMaterial(fout,itr-glist.begin()));
|
2007-06-06 19:34:19 +08:00
|
|
|
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++;
|
|
|
|
}
|
|
|
|
}
|
2007-06-30 00:00:53 +08:00
|
|
|
if (iNumGeometries > 0)
|
|
|
|
iNumGeodesWithGeometry++;
|
2004-01-09 05:39:14 +08:00
|
|
|
}
|
|
|
|
// output the Geometry
|
|
|
|
unsigned int nfirstmat=0;
|
|
|
|
fout << "OBJECT world" << std::endl;
|
2007-06-06 19:34:19 +08:00
|
|
|
|
|
|
|
fout << "kids " << iNumGeodesWithGeometry << std::endl;
|
2004-01-09 05:39:14 +08:00
|
|
|
for (itr=glist.begin();itr!= glist.end();itr++) {
|
2003-10-12 23:20:09 +08:00
|
|
|
const_cast<ac3d::Geode*>(static_cast<const ac3d::Geode*>(*itr))->ProcessGeometry(fout,nfirstmat);
|
2004-01-09 05:39:14 +08:00
|
|
|
nfirstmat+=iNumMaterials[itr-glist.begin()];
|
|
|
|
}
|
2003-10-12 23:20:09 +08:00
|
|
|
fout.close();
|
|
|
|
return WriteResult::FILE_SAVED;
|
|
|
|
}
|
|
|
|
|
2006-11-15 00:37:07 +08:00
|
|
|
virtual WriteResult writeNode(const osg::Node& node,std::ostream& fout, const Options* opts) const
|
2003-10-12 23:20:09 +08:00
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
// write ac file.
|
|
|
|
if(dynamic_cast<const osg::Group*>(&node)) {
|
2004-01-09 05:39:14 +08:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
2003-10-12 23:20:09 +08:00
|
|
|
else
|
2004-03-03 21:27:21 +08:00
|
|
|
osg::notify(osg::WARN)<<"File must start with a geode "<<std::endl;
|
2003-10-12 23:20:09 +08:00
|
|
|
fout.flush();
|
|
|
|
return WriteResult::FILE_SAVED;
|
|
|
|
}
|
|
|
|
catch(ac3d::Exception e)
|
|
|
|
{
|
2004-01-09 05:39:14 +08:00
|
|
|
osg::notify(osg::WARN)<<"Error parsing OSG tree: "<< e.getError() << std::endl;
|
2003-10-12 23:20:09 +08:00
|
|
|
}
|
|
|
|
return WriteResult::FILE_NOT_HANDLED;
|
|
|
|
|
|
|
|
}
|
2002-10-31 20:51:09 +08:00
|
|
|
private:
|
|
|
|
};
|
|
|
|
|
2006-11-15 00:37:07 +08:00
|
|
|
// now register with osg::Registry to instantiate the above
|
|
|
|
// reader/writer.
|
2007-07-06 21:54:26 +08:00
|
|
|
REGISTER_OSGPLUGIN(ac, ReaderWriterAC)
|
2006-11-15 00:37:07 +08:00
|
|
|
|
|
|
|
|
|
|
|
namespace ac3d {
|
2005-04-30 21:54:21 +08:00
|
|
|
|
2006-11-15 00:37:07 +08:00
|
|
|
enum {
|
|
|
|
ObjectTypeNormal = 0,
|
|
|
|
ObjectTypeGroup = 1,
|
|
|
|
ObjectTypeLight = 2,
|
2002-10-31 20:51:09 +08:00
|
|
|
|
2006-11-15 00:37:07 +08:00
|
|
|
SurfaceTypePolygon = 0,
|
|
|
|
SurfaceTypeLineLoop = 1,
|
|
|
|
SurfaceTypeLineStrip = 2,
|
2002-10-31 20:51:09 +08:00
|
|
|
|
2006-11-15 00:37:07 +08:00
|
|
|
SurfaceShaded = 1<<4,
|
2007-04-06 23:36:13 +08:00
|
|
|
SurfaceTwoSided = 1<<5
|
2006-11-15 00:37:07 +08:00
|
|
|
};
|
2002-10-31 20:51:09 +08:00
|
|
|
|
2006-11-15 00:37:07 +08:00
|
|
|
/// Returns a possibly quoted string given in the end of the current line in the stream
|
|
|
|
static
|
|
|
|
std::string
|
|
|
|
readString(std::istream& stream)
|
2002-10-31 20:51:09 +08:00
|
|
|
{
|
2006-11-15 00:37:07 +08:00
|
|
|
std::string s;
|
|
|
|
stream >> std::ws;
|
2002-10-31 20:51:09 +08:00
|
|
|
|
2006-11-15 00:37:07 +08:00
|
|
|
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;
|
|
|
|
}
|
2002-10-31 20:51:09 +08:00
|
|
|
|
2006-11-15 00:37:07 +08:00
|
|
|
static void
|
|
|
|
setTranslucent(osg::StateSet* stateSet)
|
2002-10-31 20:51:09 +08:00
|
|
|
{
|
2006-11-15 00:37:07 +08:00
|
|
|
osg::BlendFunc* blendFunc = new osg::BlendFunc;
|
|
|
|
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);
|
2002-10-31 20:51:09 +08:00
|
|
|
}
|
|
|
|
|
2006-11-15 00:37:07 +08:00
|
|
|
// Just a container to store an ac3d material
|
|
|
|
class MaterialData
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
MaterialData() :
|
|
|
|
mMaterial(new osg::Material),
|
|
|
|
mColorArray(new osg::Vec4Array(1))
|
|
|
|
{ }
|
2002-10-31 20:51:09 +08:00
|
|
|
|
2006-11-15 00:37:07 +08:00
|
|
|
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);
|
|
|
|
}
|
2007-05-04 16:45:21 +08:00
|
|
|
|
2006-11-15 00:37:07 +08:00
|
|
|
void toStateSet(osg::StateSet* stateSet) const
|
|
|
|
{
|
|
|
|
stateSet->setAttribute(mMaterial.get());
|
|
|
|
if (mTranslucent)
|
|
|
|
setTranslucent(stateSet);
|
|
|
|
}
|
2002-10-31 20:51:09 +08:00
|
|
|
|
2006-11-15 00:37:07 +08:00
|
|
|
osg::Vec4Array* getColorArray() const
|
|
|
|
{
|
|
|
|
return mColorArray.get();
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
osg::ref_ptr<osg::Material> mMaterial;
|
|
|
|
osg::ref_ptr<osg::Vec4Array> mColorArray;
|
|
|
|
bool mTranslucent;
|
|
|
|
};
|
2002-10-31 20:51:09 +08:00
|
|
|
|
2006-11-15 00:37:07 +08:00
|
|
|
class TextureData
|
2002-10-31 20:51:09 +08:00
|
|
|
{
|
2006-11-15 00:37:07 +08:00
|
|
|
public:
|
|
|
|
TextureData() :
|
|
|
|
mTranslucent(false)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
bool setTexture(const std::string& name, const osgDB::ReaderWriter::Options* options)
|
2004-07-06 21:00:14 +08:00
|
|
|
{
|
2006-11-15 00:37:07 +08:00
|
|
|
mTexture2D = new osg::Texture2D;
|
|
|
|
mTexture2D->setWrap(osg::Texture2D::WRAP_S, osg::Texture2D::REPEAT);
|
|
|
|
mTexture2D->setWrap(osg::Texture2D::WRAP_T, osg::Texture2D::REPEAT);
|
|
|
|
|
|
|
|
std::string absFileName = osgDB::findDataFile(name, options);
|
|
|
|
if (absFileName.empty())
|
2002-10-31 20:51:09 +08:00
|
|
|
{
|
2006-11-15 00:37:07 +08:00
|
|
|
osg::notify(osg::FATAL) << "osgDB ac3d reader: could not find texture \"" << name << "\"" << std::endl;
|
|
|
|
return false;
|
2002-10-31 20:51:09 +08:00
|
|
|
}
|
2006-11-15 00:37:07 +08:00
|
|
|
mImage = osgDB::readImageFile(absFileName, options);
|
|
|
|
if (!mImage.valid())
|
|
|
|
{
|
|
|
|
osg::notify(osg::FATAL) << "osgDB ac3d reader: could not read texture \"" << name << "\"" << std::endl;
|
|
|
|
return false;
|
|
|
|
}
|
2006-11-15 03:19:15 +08:00
|
|
|
mTexture2D->setImage(mImage.get());
|
2006-11-15 00:37:07 +08:00
|
|
|
mTranslucent = mImage->isImageTranslucent();
|
|
|
|
return true;
|
2004-07-06 21:00:14 +08:00
|
|
|
}
|
2006-11-15 00:37:07 +08:00
|
|
|
bool valid() const
|
|
|
|
{
|
|
|
|
return mImage.valid();
|
|
|
|
}
|
|
|
|
std::string getFileName() const
|
|
|
|
{
|
|
|
|
if (!mImage.valid())
|
|
|
|
return std::string();
|
|
|
|
return mImage->getFileName();
|
|
|
|
}
|
|
|
|
void toTextureStateSet(osg::StateSet* stateSet) const
|
|
|
|
{
|
2007-05-04 16:45:21 +08:00
|
|
|
if (!valid())
|
|
|
|
return;
|
2006-11-15 00:37:07 +08:00
|
|
|
osg::TexEnv* texEnv = new osg::TexEnv;
|
|
|
|
texEnv->setMode(osg::TexEnv::MODULATE);
|
|
|
|
stateSet->setTextureAttribute(0, texEnv);
|
|
|
|
stateSet->setTextureAttribute(0, mTexture2D.get());
|
|
|
|
stateSet->setTextureMode(0, GL_TEXTURE_2D, osg::StateAttribute::ON);
|
|
|
|
if (mTranslucent)
|
|
|
|
setTranslucent(stateSet);
|
|
|
|
}
|
|
|
|
private:
|
|
|
|
osg::ref_ptr<osg::Texture2D> mTexture2D;
|
|
|
|
osg::ref_ptr<osg::Image> mImage;
|
|
|
|
bool mTranslucent;
|
|
|
|
};
|
2002-10-31 20:51:09 +08:00
|
|
|
|
2006-11-15 00:37:07 +08:00
|
|
|
class FileData
|
2002-10-31 20:51:09 +08:00
|
|
|
{
|
2006-11-15 00:37:07 +08:00
|
|
|
public:
|
|
|
|
FileData(const osgDB::ReaderWriter::Options* options) :
|
|
|
|
mOptions(options),
|
|
|
|
mLightIndex(1)
|
|
|
|
{ }
|
2002-10-31 20:51:09 +08:00
|
|
|
|
2007-05-04 16:45:21 +08:00
|
|
|
TextureData toTextureData(const std::string& texName)
|
2006-11-15 00:37:07 +08:00
|
|
|
{
|
2007-05-04 16:45:21 +08:00
|
|
|
TextureDataMap::iterator i = mTextureStates.find(texName);
|
|
|
|
if (i == mTextureStates.end())
|
|
|
|
mTextureStates[texName].setTexture(texName, mOptions.get());
|
|
|
|
return mTextureStates[texName];
|
2006-11-15 00:37:07 +08:00
|
|
|
}
|
2002-10-31 20:51:09 +08:00
|
|
|
|
2006-11-15 00:37:07 +08:00
|
|
|
osg::Light* getNextLight()
|
|
|
|
{
|
|
|
|
osg::Light* light = new osg::Light;
|
|
|
|
light->setLightNum(mLightIndex++);
|
|
|
|
return light;
|
|
|
|
}
|
2002-10-31 20:51:09 +08:00
|
|
|
|
2006-11-15 00:37:07 +08:00
|
|
|
void addMaterial(const MaterialData& material)
|
|
|
|
{
|
|
|
|
mMaterials.push_back(material);
|
|
|
|
}
|
|
|
|
unsigned getNumMaterials() const
|
|
|
|
{
|
|
|
|
return mMaterials.size();
|
|
|
|
}
|
|
|
|
const MaterialData& getMaterial(unsigned idx) const
|
|
|
|
{
|
|
|
|
return mMaterials[idx];
|
|
|
|
}
|
2002-10-31 20:51:09 +08:00
|
|
|
|
2006-11-15 00:37:07 +08:00
|
|
|
private:
|
|
|
|
/// Stores the ac3d file reader options, only used for reading texture files
|
|
|
|
osg::ref_ptr<osgDB::ReaderWriter::Options const> mOptions;
|
2002-10-31 20:51:09 +08:00
|
|
|
|
2006-11-15 00:37:07 +08:00
|
|
|
/// The list of ac3d MATERIALS
|
|
|
|
std::vector<MaterialData> mMaterials;
|
2002-10-31 20:51:09 +08:00
|
|
|
|
2006-11-15 00:37:07 +08:00
|
|
|
/// Local per model texture attribute cache.
|
|
|
|
/// ... images are usualy cached in the registries object cache
|
2007-05-04 16:45:21 +08:00
|
|
|
typedef std::map<std::string, TextureData> TextureDataMap;
|
|
|
|
TextureDataMap mTextureStates;
|
2002-10-31 20:51:09 +08:00
|
|
|
|
2006-11-15 00:37:07 +08:00
|
|
|
/// Hack to include light nodes from ac3d into the scenegraph
|
|
|
|
unsigned mLightIndex;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct RefData {
|
|
|
|
RefData(const osg::Vec3& _weightedNormal, const osg::Vec2& _texCoord, bool _smooth) :
|
|
|
|
weightedFlatNormal(_weightedNormal),
|
|
|
|
weightedFlatNormalLength(_weightedNormal.length()),
|
|
|
|
texCoord(_texCoord),
|
|
|
|
smooth(_smooth)
|
|
|
|
{ }
|
|
|
|
// weighted flat surface normal
|
|
|
|
osg::Vec3 weightedFlatNormal;
|
|
|
|
float weightedFlatNormalLength;
|
|
|
|
osg::Vec2 texCoord;
|
|
|
|
// resulting vertex normal
|
|
|
|
osg::Vec3 finalNormal;
|
|
|
|
// if zero no need to smooth
|
|
|
|
unsigned smooth;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct VertexData {
|
|
|
|
VertexData(const osg::Vec3& vertex) : _vertex(vertex) {}
|
|
|
|
unsigned addRefData(const RefData& refData)
|
2002-10-31 20:51:09 +08:00
|
|
|
{
|
2006-11-15 00:37:07 +08:00
|
|
|
unsigned index = _refs.size();
|
|
|
|
_refs.push_back(refData);
|
|
|
|
return index;
|
|
|
|
}
|
2002-10-31 20:51:09 +08:00
|
|
|
|
2006-11-15 00:37:07 +08:00
|
|
|
void collect(float cosCreaseAngle, const RefData& ref)
|
|
|
|
{
|
|
|
|
unsigned size = _refs.size();
|
|
|
|
for (unsigned i = 0; i < size; ++i)
|
2002-10-31 20:51:09 +08:00
|
|
|
{
|
2006-11-15 00:37:07 +08:00
|
|
|
if (_refs[i].smooth == ~0u)
|
|
|
|
{
|
|
|
|
float dot = _refs[i].weightedFlatNormal*ref.weightedFlatNormal;
|
|
|
|
float lengths = _refs[i].weightedFlatNormalLength*ref.weightedFlatNormalLength;
|
|
|
|
if (cosCreaseAngle*lengths <= dot)
|
|
|
|
{
|
|
|
|
// Ok put that into the current set
|
|
|
|
_refs[i].smooth = ref.smooth;
|
|
|
|
collect(cosCreaseAngle, _refs[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2002-10-31 20:51:09 +08:00
|
|
|
|
2006-11-15 00:37:07 +08:00
|
|
|
void smoothNormals(float cosCreaseAngle)
|
|
|
|
{
|
|
|
|
// compute sets of vertices smoothed to the same normal
|
|
|
|
// if smooth is zero we do not need to smooth
|
|
|
|
// in a first pass mark all refs not yet in a set to ~0u
|
|
|
|
unsigned size = _refs.size();
|
|
|
|
for (unsigned i = 0; i < size; ++i)
|
|
|
|
{
|
|
|
|
if (_refs[i].smooth)
|
2002-10-31 20:51:09 +08:00
|
|
|
{
|
2006-11-15 00:37:07 +08:00
|
|
|
_refs[i].smooth = ~0u;
|
2002-10-31 20:51:09 +08:00
|
|
|
}
|
2006-11-15 00:37:07 +08:00
|
|
|
}
|
|
|
|
// Now collect the sets
|
|
|
|
unsigned currentSet = 1;
|
|
|
|
for (unsigned i = 0; i < size; ++i)
|
|
|
|
{
|
|
|
|
if (_refs[i].smooth == ~0u)
|
2002-10-31 20:51:09 +08:00
|
|
|
{
|
2006-11-15 00:37:07 +08:00
|
|
|
_refs[i].smooth = currentSet++;
|
|
|
|
collect(cosCreaseAngle, _refs[i]);
|
2002-10-31 20:51:09 +08:00
|
|
|
}
|
|
|
|
}
|
2006-11-15 00:37:07 +08:00
|
|
|
// smooth and normalize the sets
|
|
|
|
for (--currentSet; 0 < currentSet; --currentSet)
|
2002-10-31 20:51:09 +08:00
|
|
|
{
|
2006-11-15 00:37:07 +08:00
|
|
|
osg::Vec3 normal(0, 0, 0);
|
|
|
|
for (unsigned i = 0; i < size; ++i)
|
|
|
|
{
|
|
|
|
if (_refs[i].smooth == currentSet)
|
|
|
|
{
|
|
|
|
normal += _refs[i].weightedFlatNormal;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
normal.normalize();
|
|
|
|
for (unsigned i = 0; i < size; ++i)
|
|
|
|
{
|
|
|
|
if (_refs[i].smooth == currentSet)
|
|
|
|
{
|
|
|
|
_refs[i].finalNormal = normal;
|
|
|
|
}
|
|
|
|
}
|
2002-10-31 20:51:09 +08:00
|
|
|
}
|
2006-11-15 00:37:07 +08:00
|
|
|
|
|
|
|
// normalize the ones which do not need smoothing
|
|
|
|
for (unsigned i = 0; i < size; ++i)
|
2002-10-31 20:51:09 +08:00
|
|
|
{
|
2006-11-15 00:37:07 +08:00
|
|
|
if (_refs[i].smooth == 0)
|
|
|
|
{
|
|
|
|
_refs[i].finalNormal = _refs[i].weightedFlatNormal;
|
|
|
|
_refs[i].finalNormal.normalize();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
osg::Vec3 _vertex;
|
|
|
|
std::vector<RefData> _refs;
|
|
|
|
};
|
|
|
|
struct VertexIndex {
|
|
|
|
VertexIndex(unsigned _vertexIndex = 0, unsigned _refIndex = 0) :
|
|
|
|
vertexIndex(_vertexIndex), refIndex(_refIndex)
|
|
|
|
{ }
|
|
|
|
unsigned vertexIndex;
|
|
|
|
unsigned refIndex;
|
|
|
|
};
|
2002-10-31 20:51:09 +08:00
|
|
|
|
2006-11-15 00:37:07 +08:00
|
|
|
class VertexSet : public osg::Referenced {
|
|
|
|
public:
|
|
|
|
VertexSet() : _dirty(true)
|
|
|
|
{ }
|
|
|
|
void reserve(unsigned n)
|
|
|
|
{
|
|
|
|
_vertices.reserve(n);
|
|
|
|
}
|
|
|
|
unsigned size() const
|
|
|
|
{
|
|
|
|
return _vertices.size();
|
|
|
|
}
|
|
|
|
void setCreaseAngle(float crease)
|
|
|
|
{
|
|
|
|
_dirty = true;
|
|
|
|
if (crease <= 0)
|
|
|
|
_cosCreaseAngle = 1;
|
|
|
|
else if (180 <= crease)
|
|
|
|
_cosCreaseAngle = -1;
|
|
|
|
else
|
|
|
|
_cosCreaseAngle = cosf(osg::DegreesToRadians(crease));
|
|
|
|
}
|
|
|
|
void addVertex(const osg::Vec3& vertex)
|
|
|
|
{
|
|
|
|
_dirty = true;
|
|
|
|
_vertices.push_back(vertex);
|
|
|
|
}
|
|
|
|
const osg::Vec3& getVertex(unsigned index)
|
|
|
|
{
|
|
|
|
return _vertices[index]._vertex;
|
|
|
|
}
|
|
|
|
const osg::Vec3& getVertex(const VertexIndex& vertexIndex)
|
|
|
|
{
|
|
|
|
return _vertices[vertexIndex.vertexIndex]._vertex;
|
|
|
|
}
|
|
|
|
const osg::Vec3& getNormal(const VertexIndex& vertexIndex)
|
|
|
|
{
|
|
|
|
if (_dirty)
|
|
|
|
smoothNormals();
|
|
|
|
return _vertices[vertexIndex.vertexIndex]._refs[vertexIndex.refIndex].finalNormal;
|
|
|
|
}
|
|
|
|
const osg::Vec2& getTexCoord(const VertexIndex& vertexIndex)
|
|
|
|
{
|
|
|
|
return _vertices[vertexIndex.vertexIndex]._refs[vertexIndex.refIndex].texCoord;
|
|
|
|
}
|
2002-10-31 20:51:09 +08:00
|
|
|
|
2006-11-15 00:37:07 +08:00
|
|
|
VertexIndex addRefData(unsigned i, const RefData& refData)
|
|
|
|
{
|
2006-11-15 18:08:09 +08:00
|
|
|
if (_vertices.size() <= i)
|
|
|
|
{
|
|
|
|
osg::notify(osg::FATAL) << "osgDB ac3d reader: internal error, got invalid vertex index!" << std::endl;
|
|
|
|
return VertexIndex(0, 0);
|
|
|
|
}
|
2006-11-15 00:37:07 +08:00
|
|
|
_dirty = true;
|
|
|
|
return VertexIndex(i, _vertices[i].addRefData(refData));
|
|
|
|
}
|
2002-10-31 20:51:09 +08:00
|
|
|
|
2006-11-15 00:37:07 +08:00
|
|
|
private:
|
|
|
|
void smoothNormals()
|
|
|
|
{
|
|
|
|
std::vector<VertexData>::iterator i;
|
|
|
|
for (i = _vertices.begin(); i != _vertices.end(); ++i)
|
|
|
|
{
|
|
|
|
i->smoothNormals(_cosCreaseAngle);
|
2002-10-31 20:51:09 +08:00
|
|
|
}
|
2006-11-15 00:37:07 +08:00
|
|
|
_dirty = false;
|
2002-10-31 20:51:09 +08:00
|
|
|
}
|
|
|
|
|
2006-11-15 00:37:07 +08:00
|
|
|
std::vector<VertexData> _vertices;
|
|
|
|
float _cosCreaseAngle;
|
|
|
|
bool _dirty;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class PrimitiveBin : public osg::Referenced
|
2002-10-31 20:51:09 +08:00
|
|
|
{
|
2006-11-15 00:37:07 +08:00
|
|
|
public:
|
|
|
|
PrimitiveBin(unsigned flags, VertexSet* vertexSet) :
|
2007-05-16 03:45:46 +08:00
|
|
|
_geode(new osg::Geode),
|
2006-11-15 00:37:07 +08:00
|
|
|
_vertexSet(vertexSet),
|
|
|
|
_flags(flags)
|
|
|
|
{ }
|
2002-10-31 20:51:09 +08:00
|
|
|
|
2006-11-15 00:37:07 +08:00
|
|
|
virtual bool beginPrimitive(unsigned nRefs) = 0;
|
|
|
|
virtual bool vertex(unsigned vertexIndex, const osg::Vec2& texCoord) = 0;
|
|
|
|
virtual bool endPrimitive() = 0;
|
|
|
|
|
2007-05-16 03:45:46 +08:00
|
|
|
virtual osg::Geode* finalize(const MaterialData& material, const TextureData& textureData) = 0;
|
2006-11-15 00:37:07 +08:00
|
|
|
|
|
|
|
protected:
|
|
|
|
bool isLineLoop() const
|
|
|
|
{
|
2007-05-17 18:59:05 +08:00
|
|
|
return (_flags & SurfaceTypeLineLoop)!=0;
|
2006-11-15 00:37:07 +08:00
|
|
|
}
|
|
|
|
bool isLineStrip() const
|
|
|
|
{
|
2007-05-17 18:59:05 +08:00
|
|
|
return (_flags & SurfaceTypeLineStrip)!=0;
|
2006-11-15 00:37:07 +08:00
|
|
|
}
|
|
|
|
bool isTwoSided() const
|
|
|
|
{
|
2007-05-17 18:59:05 +08:00
|
|
|
return (_flags & SurfaceTwoSided)!=0;
|
2006-11-15 00:37:07 +08:00
|
|
|
}
|
|
|
|
bool isSmooth() const
|
|
|
|
{
|
2007-05-17 18:59:05 +08:00
|
|
|
return (_flags & SurfaceShaded)!=0;
|
2006-11-15 00:37:07 +08:00
|
|
|
}
|
|
|
|
|
2007-05-16 03:45:46 +08:00
|
|
|
osg::ref_ptr<osg::Geode> _geode;
|
2006-11-15 00:37:07 +08:00
|
|
|
osg::ref_ptr<VertexSet> _vertexSet;
|
2002-10-31 20:51:09 +08:00
|
|
|
|
2006-11-15 00:37:07 +08:00
|
|
|
private:
|
|
|
|
unsigned _flags;
|
|
|
|
};
|
|
|
|
|
|
|
|
class LineBin : public PrimitiveBin
|
2002-10-31 20:51:09 +08:00
|
|
|
{
|
2006-11-15 00:37:07 +08:00
|
|
|
private:
|
2007-05-16 03:45:46 +08:00
|
|
|
osg::ref_ptr<osg::Geometry> _geometry;
|
2006-11-15 00:37:07 +08:00
|
|
|
osg::ref_ptr<osg::Vec3Array> _vertices;
|
|
|
|
osg::ref_ptr<osg::Vec2Array> _texCoords;
|
|
|
|
struct Ref {
|
|
|
|
osg::Vec2 texCoord;
|
|
|
|
unsigned index;
|
|
|
|
};
|
|
|
|
std::vector<Ref> _refs;
|
|
|
|
|
|
|
|
public:
|
|
|
|
LineBin(unsigned flags, VertexSet* vertexSet) :
|
|
|
|
PrimitiveBin(flags, vertexSet),
|
2007-05-16 03:45:46 +08:00
|
|
|
_geometry(new osg::Geometry),
|
|
|
|
_vertices(new osg::Vec3Array),
|
|
|
|
_texCoords(new osg::Vec2Array)
|
2006-11-15 00:37:07 +08:00
|
|
|
{
|
|
|
|
_geometry->setVertexArray(_vertices.get());
|
|
|
|
_geometry->setTexCoordArray(0, _texCoords.get());
|
2007-05-16 03:45:46 +08:00
|
|
|
osg::StateSet* stateSet = _geode->getOrCreateStateSet();
|
2006-11-15 00:37:07 +08:00
|
|
|
stateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
|
|
|
|
}
|
2004-01-09 05:39:14 +08:00
|
|
|
|
2006-11-15 00:37:07 +08:00
|
|
|
virtual bool beginPrimitive(unsigned nRefs)
|
|
|
|
{
|
|
|
|
// Check if we have enough for a line or someting broken ...
|
|
|
|
if (nRefs < 2) {
|
|
|
|
osg::notify(osg::WARN) << "osgDB ac3d reader: detected line with less than 2 vertices!" << std::endl;
|
|
|
|
return false;
|
|
|
|
}
|
2004-01-09 05:39:14 +08:00
|
|
|
|
2006-11-15 00:37:07 +08:00
|
|
|
_refs.reserve(nRefs);
|
|
|
|
_refs.resize(0);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
virtual bool vertex(unsigned vertexIndex, const osg::Vec2& texCoord)
|
|
|
|
{
|
|
|
|
Ref ref;
|
|
|
|
ref.index = vertexIndex;
|
|
|
|
ref.texCoord = texCoord;
|
|
|
|
_refs.push_back(ref);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
virtual bool endPrimitive()
|
2004-01-09 05:39:14 +08:00
|
|
|
{
|
2006-11-15 00:37:07 +08:00
|
|
|
GLint type;
|
|
|
|
if (isLineLoop())
|
|
|
|
type = osg::PrimitiveSet::LINE_LOOP;
|
|
|
|
else if (isLineStrip())
|
|
|
|
type = osg::PrimitiveSet::LINE_STRIP;
|
|
|
|
else {
|
|
|
|
osg::notify(osg::FATAL) << "osgDB ac3d reader: non surface flags in surface bin!" << std::endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
unsigned nRefs = _refs.size();
|
|
|
|
unsigned start = _vertices->size();
|
|
|
|
for (unsigned i = 0; i < nRefs; ++i) {
|
|
|
|
osg::Vec3 vertex = _vertexSet->getVertex(_refs[i].index);
|
|
|
|
_vertices->push_back(vertex);
|
|
|
|
_texCoords->push_back(_refs[i].texCoord);
|
|
|
|
}
|
|
|
|
_geometry->addPrimitiveSet(new osg::DrawArrays(type, start, nRefs));
|
2004-01-09 05:39:14 +08:00
|
|
|
|
2006-11-15 00:37:07 +08:00
|
|
|
return true;
|
|
|
|
}
|
2004-01-09 05:39:14 +08:00
|
|
|
|
2007-05-16 03:45:46 +08:00
|
|
|
virtual osg::Geode* finalize(const MaterialData& material, const TextureData& textureData)
|
2006-11-15 00:37:07 +08:00
|
|
|
{
|
2007-05-16 03:45:46 +08:00
|
|
|
_geode->addDrawable(_geometry.get());
|
|
|
|
material.toStateSet(_geode->getOrCreateStateSet());
|
2006-11-15 00:37:07 +08:00
|
|
|
_geometry->setColorArray(material.getColorArray());
|
|
|
|
_geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
|
|
|
|
_geometry->setNormalBinding(osg::Geometry::BIND_OFF);
|
2007-05-16 03:45:46 +08:00
|
|
|
return _geode.get();
|
2006-11-15 00:37:07 +08:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class SurfaceBin : public PrimitiveBin {
|
|
|
|
private:
|
|
|
|
struct Ref {
|
|
|
|
osg::Vec2 texCoord;
|
|
|
|
unsigned index;
|
|
|
|
};
|
|
|
|
std::vector<Ref> _refs;
|
|
|
|
|
|
|
|
struct TriangleData {
|
|
|
|
VertexIndex index[3];
|
|
|
|
};
|
|
|
|
std::vector<TriangleData> _triangles;
|
|
|
|
|
|
|
|
struct QuadData {
|
|
|
|
VertexIndex index[4];
|
|
|
|
};
|
|
|
|
std::vector<QuadData> _quads;
|
|
|
|
|
|
|
|
struct PolygonData {
|
|
|
|
std::vector<VertexIndex> index;
|
|
|
|
};
|
|
|
|
std::vector<PolygonData> _polygons;
|
2007-01-09 05:29:49 +08:00
|
|
|
std::vector<PolygonData> _toTessellatePolygons;
|
2006-11-15 00:37:07 +08:00
|
|
|
|
|
|
|
public:
|
|
|
|
SurfaceBin(unsigned flags, VertexSet *vertexSet) :
|
|
|
|
PrimitiveBin(flags, vertexSet)
|
|
|
|
{ }
|
|
|
|
|
|
|
|
virtual bool beginPrimitive(unsigned nRefs)
|
|
|
|
{
|
|
|
|
_refs.reserve(nRefs);
|
|
|
|
_refs.clear();
|
|
|
|
|
|
|
|
// Check if we have enough for a line or someting broken ...
|
|
|
|
if (nRefs < 3) {
|
|
|
|
osg::notify(osg::WARN) << "osgDB ac3d reader: detected surface with less than 3 vertices!" << std::endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
virtual bool vertex(unsigned vertexIndex, const osg::Vec2& texCoord)
|
|
|
|
{
|
|
|
|
Ref ref;
|
|
|
|
ref.index = vertexIndex;
|
|
|
|
ref.texCoord = texCoord;
|
|
|
|
_refs.push_back(ref);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
virtual bool endPrimitive()
|
|
|
|
{
|
|
|
|
unsigned nRefs = _refs.size();
|
|
|
|
|
|
|
|
// Compute the normal times the enclosed area.
|
|
|
|
// During that check if the surface is convex. If so, put in the surface as such.
|
2007-01-09 05:29:49 +08:00
|
|
|
bool needTessellation = false;
|
2006-12-20 01:30:22 +08:00
|
|
|
osg::Vec3 prevEdgeNormal;
|
2006-11-15 00:37:07 +08:00
|
|
|
osg::Vec3 weightedNormal(0, 0, 0);
|
|
|
|
osg::Vec3 v0 = _vertexSet->getVertex(_refs[0].index);
|
|
|
|
for (unsigned i = 2; i < nRefs; ++i) {
|
|
|
|
osg::Vec3 side1 = _vertexSet->getVertex(_refs[i-1].index) - v0;
|
|
|
|
osg::Vec3 side2 = _vertexSet->getVertex(_refs[i].index) - v0;
|
|
|
|
osg::Vec3 newNormal = side1^side2;
|
2007-01-09 05:29:49 +08:00
|
|
|
if (!needTessellation)
|
2004-01-09 05:39:14 +08:00
|
|
|
{
|
2006-12-20 01:30:22 +08:00
|
|
|
if (3 < nRefs && newNormal*weightedNormal < 0)
|
|
|
|
{
|
2007-01-09 05:29:49 +08:00
|
|
|
needTessellation = true;
|
2006-12-20 01:30:22 +08:00
|
|
|
}
|
|
|
|
if (i < 3)
|
|
|
|
{
|
|
|
|
prevEdgeNormal = newNormal;
|
|
|
|
}
|
|
|
|
else // if (3 <= i) // due to the for loop
|
|
|
|
{
|
|
|
|
osg::Vec3 sideim1 = _vertexSet->getVertex(_refs[i-1].index) - _vertexSet->getVertex(_refs[i-2].index);
|
|
|
|
osg::Vec3 sidei = _vertexSet->getVertex(_refs[i].index) - _vertexSet->getVertex(_refs[i-2].index);
|
|
|
|
osg::Vec3 edgeNormal = sideim1^sidei;
|
|
|
|
if (edgeNormal*prevEdgeNormal < 0)
|
|
|
|
{
|
2007-01-09 05:29:49 +08:00
|
|
|
needTessellation = true;
|
2006-12-20 01:30:22 +08:00
|
|
|
}
|
|
|
|
prevEdgeNormal = edgeNormal;
|
|
|
|
}
|
2004-01-09 05:39:14 +08:00
|
|
|
}
|
|
|
|
|
2006-11-15 00:37:07 +08:00
|
|
|
weightedNormal += newNormal;
|
|
|
|
}
|
|
|
|
|
2007-01-09 05:29:49 +08:00
|
|
|
if (needTessellation)
|
2006-11-15 00:37:07 +08:00
|
|
|
{
|
2007-01-09 05:29:49 +08:00
|
|
|
unsigned polygonIndex = _toTessellatePolygons.size();
|
|
|
|
_toTessellatePolygons.resize(polygonIndex + 1);
|
2006-11-15 00:37:07 +08:00
|
|
|
for (unsigned i = 0; i < nRefs; ++i) {
|
|
|
|
RefData refData(weightedNormal, _refs[i].texCoord, isSmooth());
|
|
|
|
VertexIndex vertexIndex = _vertexSet->addRefData(_refs[i].index, refData);
|
2007-01-09 05:29:49 +08:00
|
|
|
_toTessellatePolygons[polygonIndex].index.push_back(vertexIndex);
|
2004-01-09 05:39:14 +08:00
|
|
|
}
|
|
|
|
}
|
2006-11-15 00:37:07 +08:00
|
|
|
else if (nRefs == 3)
|
2004-01-09 05:39:14 +08:00
|
|
|
{
|
2006-11-15 00:37:07 +08:00
|
|
|
unsigned triangleIndex = _triangles.size();
|
|
|
|
_triangles.resize(triangleIndex + 1);
|
|
|
|
for (unsigned i = 0; i < 3; ++i) {
|
|
|
|
RefData refData(weightedNormal, _refs[i].texCoord, isSmooth());
|
|
|
|
VertexIndex vertexIndex = _vertexSet->addRefData(_refs[i].index, refData);
|
|
|
|
_triangles[triangleIndex].index[i] = vertexIndex;
|
2006-03-08 23:16:59 +08:00
|
|
|
}
|
2006-11-15 00:37:07 +08:00
|
|
|
}
|
|
|
|
else if (nRefs == 4)
|
|
|
|
{
|
|
|
|
unsigned quadIndex = _quads.size();
|
|
|
|
_quads.resize(quadIndex + 1);
|
|
|
|
for (unsigned i = 0; i < 4; ++i) {
|
|
|
|
RefData refData(weightedNormal, _refs[i].texCoord, isSmooth());
|
|
|
|
VertexIndex vertexIndex = _vertexSet->addRefData(_refs[i].index, refData);
|
|
|
|
_quads[quadIndex].index[i] = vertexIndex;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
unsigned polygonIndex = _polygons.size();
|
|
|
|
_polygons.resize(polygonIndex + 1);
|
|
|
|
for (unsigned i = 0; i < nRefs; ++i) {
|
|
|
|
RefData refData(weightedNormal, _refs[i].texCoord, isSmooth());
|
|
|
|
VertexIndex vertexIndex = _vertexSet->addRefData(_refs[i].index, refData);
|
|
|
|
_polygons[polygonIndex].index.push_back(vertexIndex);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
2004-01-09 05:39:14 +08:00
|
|
|
|
2006-11-15 00:37:07 +08:00
|
|
|
void pushVertex(const VertexIndex& vertexIndex, osg::Vec3Array* vertexArray,
|
|
|
|
osg::Vec3Array* normalArray, osg::Vec2Array* texcoordArray)
|
|
|
|
{
|
|
|
|
vertexArray->push_back(_vertexSet->getVertex(vertexIndex));
|
|
|
|
normalArray->push_back(_vertexSet->getNormal(vertexIndex));
|
2007-05-16 03:45:46 +08:00
|
|
|
if (texcoordArray)
|
|
|
|
texcoordArray->push_back(_vertexSet->getTexCoord(vertexIndex));
|
2006-11-15 00:37:07 +08:00
|
|
|
}
|
2004-01-09 05:39:14 +08:00
|
|
|
|
2007-05-16 03:45:46 +08:00
|
|
|
virtual osg::Geode* finalize(const MaterialData& material, const TextureData& textureData)
|
2006-11-15 00:37:07 +08:00
|
|
|
{
|
2007-05-16 03:45:46 +08:00
|
|
|
osg::StateSet* stateSet = _geode->getOrCreateStateSet();
|
2006-11-15 00:37:07 +08:00
|
|
|
material.toStateSet(stateSet);
|
2007-05-04 16:45:21 +08:00
|
|
|
textureData.toTextureStateSet(stateSet);
|
2006-11-15 00:37:07 +08:00
|
|
|
stateSet->setMode(GL_LIGHTING, osg::StateAttribute::ON);
|
|
|
|
|
|
|
|
// Single- or doublesided culling
|
|
|
|
if (isTwoSided()) {
|
|
|
|
stateSet->setMode(GL_CULL_FACE, osg::StateAttribute::OFF);
|
|
|
|
} else {
|
|
|
|
osg::CullFace* cullFace = new osg::CullFace;
|
|
|
|
cullFace->setMode(osg::CullFace::BACK);
|
|
|
|
stateSet->setAttribute(cullFace);
|
|
|
|
stateSet->setMode(GL_CULL_FACE, osg::StateAttribute::ON);
|
2004-01-09 05:39:14 +08:00
|
|
|
}
|
2006-11-15 00:37:07 +08:00
|
|
|
|
|
|
|
// Flat or smooth shading
|
|
|
|
osg::ShadeModel* shadeModel = new osg::ShadeModel;
|
|
|
|
if (isSmooth())
|
|
|
|
shadeModel->setMode(osg::ShadeModel::SMOOTH);
|
|
|
|
else
|
|
|
|
shadeModel->setMode(osg::ShadeModel::FLAT);
|
|
|
|
stateSet->setAttribute(shadeModel);
|
|
|
|
|
|
|
|
// Set up the arrays, allways store texture coords, may be we need them later ...
|
2007-05-16 03:45:46 +08:00
|
|
|
osg::Geometry* geometry = new osg::Geometry;
|
|
|
|
_geode->addDrawable(geometry);
|
|
|
|
geometry->setColorArray(material.getColorArray());
|
|
|
|
geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
|
|
|
|
geometry->setNormalBinding(osg::Geometry::BIND_PER_VERTEX);
|
2006-11-15 00:37:07 +08:00
|
|
|
osg::Vec3Array* normalArray = new osg::Vec3Array;
|
2007-05-16 03:45:46 +08:00
|
|
|
geometry->setNormalArray(normalArray);
|
2006-11-15 00:37:07 +08:00
|
|
|
osg::Vec3Array* vertexArray = new osg::Vec3Array;
|
2007-05-16 03:45:46 +08:00
|
|
|
geometry->setVertexArray(vertexArray);
|
|
|
|
osg::Vec2Array* texcoordArray = 0;
|
|
|
|
if (textureData.valid())
|
|
|
|
{
|
|
|
|
texcoordArray = new osg::Vec2Array;
|
|
|
|
geometry->setTexCoordArray(0, texcoordArray);
|
|
|
|
}
|
2006-11-15 00:37:07 +08:00
|
|
|
|
2007-01-09 05:29:49 +08:00
|
|
|
// At first handle the the polygons to tessellate, fix them and append the other polygons later
|
|
|
|
if (!_toTessellatePolygons.empty())
|
2004-01-09 05:39:14 +08:00
|
|
|
{
|
2007-05-16 03:45:46 +08:00
|
|
|
unsigned start = vertexArray->size();
|
|
|
|
osg::DrawArrayLengths* drawArrayLengths = new osg::DrawArrayLengths(osg::PrimitiveSet::POLYGON, start);
|
|
|
|
drawArrayLengths->reserve(_toTessellatePolygons.size());
|
2007-01-09 05:29:49 +08:00
|
|
|
for (unsigned i = 0; i < _toTessellatePolygons.size(); ++i)
|
2004-01-09 05:39:14 +08:00
|
|
|
{
|
2007-01-09 05:29:49 +08:00
|
|
|
for (unsigned j = 0; j < _toTessellatePolygons[i].index.size(); ++j)
|
2004-01-09 05:39:14 +08:00
|
|
|
{
|
2007-01-09 05:29:49 +08:00
|
|
|
pushVertex(_toTessellatePolygons[i].index[j], vertexArray, normalArray, texcoordArray);
|
2004-01-09 05:39:14 +08:00
|
|
|
}
|
2007-05-16 03:45:46 +08:00
|
|
|
drawArrayLengths->push_back(_toTessellatePolygons[i].index.size());
|
2004-01-09 05:39:14 +08:00
|
|
|
}
|
2007-05-16 03:45:46 +08:00
|
|
|
geometry->addPrimitiveSet(drawArrayLengths);
|
2006-11-15 00:37:07 +08:00
|
|
|
|
2007-01-09 05:29:49 +08:00
|
|
|
osgUtil::Tessellator Tessellator;
|
2007-05-16 03:45:46 +08:00
|
|
|
Tessellator.retessellatePolygons(*geometry);
|
2004-01-09 05:39:14 +08:00
|
|
|
}
|
2006-11-15 00:37:07 +08:00
|
|
|
|
|
|
|
// handle triangles
|
|
|
|
if (!_triangles.empty())
|
2004-01-09 05:39:14 +08:00
|
|
|
{
|
2006-11-15 00:37:07 +08:00
|
|
|
unsigned start = vertexArray->size();
|
|
|
|
for (unsigned i = 0; i < _triangles.size(); ++i)
|
2004-01-09 05:39:14 +08:00
|
|
|
{
|
2006-11-15 00:37:07 +08:00
|
|
|
for (unsigned j = 0; j < 3; ++j)
|
|
|
|
{
|
|
|
|
pushVertex(_triangles[i].index[j], vertexArray, normalArray, texcoordArray);
|
2005-04-30 21:54:21 +08:00
|
|
|
}
|
|
|
|
}
|
2006-11-15 00:37:07 +08:00
|
|
|
osg::DrawArrays* drawArray = new osg::DrawArrays(osg::PrimitiveSet::TRIANGLES, start, 3*_triangles.size());
|
2007-05-16 03:45:46 +08:00
|
|
|
geometry->addPrimitiveSet(drawArray);
|
2004-01-09 05:39:14 +08:00
|
|
|
}
|
|
|
|
|
2006-11-15 00:37:07 +08:00
|
|
|
// handle quads
|
|
|
|
if (!_quads.empty())
|
|
|
|
{
|
|
|
|
unsigned start = vertexArray->size();
|
|
|
|
for (unsigned i = 0; i < _quads.size(); ++i)
|
2004-01-09 05:39:14 +08:00
|
|
|
{
|
2006-11-15 00:37:07 +08:00
|
|
|
for (unsigned j = 0; j < 4; ++j)
|
2005-04-30 21:54:21 +08:00
|
|
|
{
|
2006-11-15 00:37:07 +08:00
|
|
|
pushVertex(_quads[i].index[j], vertexArray, normalArray, texcoordArray);
|
2005-04-30 21:54:21 +08:00
|
|
|
}
|
2006-11-15 00:37:07 +08:00
|
|
|
}
|
|
|
|
osg::DrawArrays* drawArray = new osg::DrawArrays(osg::PrimitiveSet::QUADS, start, 4*_quads.size());
|
2007-05-16 03:45:46 +08:00
|
|
|
geometry->addPrimitiveSet(drawArray);
|
2006-11-15 00:37:07 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// handle polygons
|
|
|
|
if (!_polygons.empty())
|
|
|
|
{
|
2007-05-16 03:45:46 +08:00
|
|
|
unsigned start = vertexArray->size();
|
|
|
|
osg::DrawArrayLengths* drawArrayLengths = new osg::DrawArrayLengths(osg::PrimitiveSet::POLYGON, start);
|
|
|
|
drawArrayLengths->reserve(_polygons.size());
|
2006-11-15 00:37:07 +08:00
|
|
|
for (unsigned i = 0; i < _polygons.size(); ++i)
|
|
|
|
{
|
|
|
|
for (unsigned j = 0; j < _polygons[i].index.size(); ++j)
|
2005-04-30 21:54:21 +08:00
|
|
|
{
|
2006-11-15 00:37:07 +08:00
|
|
|
pushVertex(_polygons[i].index[j], vertexArray, normalArray, texcoordArray);
|
2004-01-09 05:39:14 +08:00
|
|
|
}
|
2007-05-16 03:45:46 +08:00
|
|
|
drawArrayLengths->push_back(_polygons[i].index.size());
|
2004-01-09 05:39:14 +08:00
|
|
|
}
|
2007-05-16 03:45:46 +08:00
|
|
|
geometry->addPrimitiveSet(drawArrayLengths);
|
2004-01-09 05:39:14 +08:00
|
|
|
}
|
2006-11-15 00:37:07 +08:00
|
|
|
|
2007-05-16 03:45:46 +08:00
|
|
|
return _geode.get();
|
2006-11-15 00:37:07 +08:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
struct Bins
|
|
|
|
{
|
|
|
|
PrimitiveBin* getOrCreatePrimitiveBin(unsigned flags, VertexSet* vertexSet)
|
|
|
|
{
|
|
|
|
if ((flags & SurfaceTypeLineLoop) || (flags & SurfaceTypeLineStrip))
|
2004-01-09 05:39:14 +08:00
|
|
|
{
|
2006-11-15 00:37:07 +08:00
|
|
|
if (!lineBin.valid())
|
|
|
|
{
|
|
|
|
lineBin = new LineBin(flags, vertexSet);
|
|
|
|
}
|
|
|
|
return lineBin.get();
|
|
|
|
}
|
|
|
|
else if (flags & SurfaceShaded)
|
|
|
|
{
|
|
|
|
if (flags & SurfaceTwoSided)
|
|
|
|
{
|
|
|
|
if (!smoothDoubleSurfaceBin.valid())
|
|
|
|
{
|
|
|
|
smoothDoubleSurfaceBin = new SurfaceBin(flags, vertexSet);
|
|
|
|
}
|
|
|
|
return smoothDoubleSurfaceBin.get();
|
|
|
|
}
|
2004-01-09 05:39:14 +08:00
|
|
|
else
|
|
|
|
{
|
2006-11-15 00:37:07 +08:00
|
|
|
if (!smoothSingleSurfaceBin.valid())
|
|
|
|
{
|
|
|
|
smoothSingleSurfaceBin = new SurfaceBin(flags, vertexSet);
|
|
|
|
}
|
|
|
|
return smoothSingleSurfaceBin.get();
|
2004-01-09 05:39:14 +08:00
|
|
|
}
|
|
|
|
}
|
2006-11-15 00:37:07 +08:00
|
|
|
else
|
2004-01-09 05:39:14 +08:00
|
|
|
{
|
2006-11-15 00:37:07 +08:00
|
|
|
if (flags & SurfaceTwoSided)
|
|
|
|
{
|
|
|
|
if (!flatDoubleSurfaceBin.valid())
|
|
|
|
{
|
|
|
|
flatDoubleSurfaceBin = new SurfaceBin(flags, vertexSet);
|
|
|
|
}
|
|
|
|
return flatDoubleSurfaceBin.get();
|
|
|
|
}
|
2004-01-09 05:39:14 +08:00
|
|
|
else
|
|
|
|
{
|
2006-11-15 00:37:07 +08:00
|
|
|
if (!flatSingleSurfaceBin.valid())
|
|
|
|
{
|
|
|
|
flatSingleSurfaceBin = new SurfaceBin(flags, vertexSet);
|
|
|
|
}
|
|
|
|
return flatSingleSurfaceBin.get();
|
2004-01-09 05:39:14 +08:00
|
|
|
}
|
|
|
|
}
|
2006-11-15 00:37:07 +08:00
|
|
|
}
|
2007-05-16 03:45:46 +08:00
|
|
|
void finalize(osg::Group* group, const MaterialData& material, const TextureData& textureData)
|
2006-11-15 00:37:07 +08:00
|
|
|
{
|
|
|
|
if (lineBin.valid())
|
2004-01-09 05:39:14 +08:00
|
|
|
{
|
2007-05-16 03:45:46 +08:00
|
|
|
group->addChild(lineBin->finalize(material, textureData));
|
2004-01-09 05:39:14 +08:00
|
|
|
}
|
2006-11-15 00:37:07 +08:00
|
|
|
if (smoothDoubleSurfaceBin.valid())
|
2004-01-09 05:39:14 +08:00
|
|
|
{
|
2007-05-16 03:45:46 +08:00
|
|
|
group->addChild(smoothDoubleSurfaceBin->finalize(material, textureData));
|
2004-01-09 05:39:14 +08:00
|
|
|
}
|
2006-11-15 00:37:07 +08:00
|
|
|
if (smoothSingleSurfaceBin.valid())
|
2004-01-09 05:39:14 +08:00
|
|
|
{
|
2007-05-16 03:45:46 +08:00
|
|
|
group->addChild(smoothSingleSurfaceBin->finalize(material, textureData));
|
2004-01-09 05:39:14 +08:00
|
|
|
}
|
2006-11-15 00:37:07 +08:00
|
|
|
if (flatDoubleSurfaceBin.valid())
|
2004-01-09 05:39:14 +08:00
|
|
|
{
|
2007-05-16 03:45:46 +08:00
|
|
|
group->addChild(flatDoubleSurfaceBin->finalize(material, textureData));
|
2006-11-15 00:37:07 +08:00
|
|
|
}
|
|
|
|
if (flatSingleSurfaceBin.valid())
|
|
|
|
{
|
2007-05-16 03:45:46 +08:00
|
|
|
group->addChild(flatSingleSurfaceBin->finalize(material, textureData));
|
2006-11-15 00:37:07 +08:00
|
|
|
}
|
|
|
|
}
|
2004-01-09 05:39:14 +08:00
|
|
|
|
2006-11-15 00:37:07 +08:00
|
|
|
private:
|
|
|
|
osg::ref_ptr<LineBin> lineBin;
|
|
|
|
osg::ref_ptr<SurfaceBin> flatDoubleSurfaceBin;
|
|
|
|
osg::ref_ptr<SurfaceBin> flatSingleSurfaceBin;
|
|
|
|
osg::ref_ptr<SurfaceBin> smoothDoubleSurfaceBin;
|
|
|
|
osg::ref_ptr<SurfaceBin> smoothSingleSurfaceBin;
|
|
|
|
};
|
2004-01-09 05:39:14 +08:00
|
|
|
|
2006-11-15 00:37:07 +08:00
|
|
|
osg::Node*
|
2007-05-04 16:45:21 +08:00
|
|
|
readObject(std::istream& stream, FileData& fileData, const osg::Matrix& parentTransform, TextureData textureData)
|
2006-11-15 00:37:07 +08:00
|
|
|
{
|
|
|
|
// most of this logic came from Andy Colebourne (developer of the AC3D editor) so it had better be right!
|
2004-01-09 05:39:14 +08:00
|
|
|
|
2006-11-15 00:37:07 +08:00
|
|
|
// The transform configured in this current object level
|
|
|
|
osg::Matrix transform;
|
|
|
|
// The vertex pool in this object
|
|
|
|
osg::ref_ptr<VertexSet> vertexSet = new VertexSet;
|
|
|
|
osg::ref_ptr<osg::Group> group = new osg::Group;
|
|
|
|
osg::Vec2 textureOffset(0, 0);
|
|
|
|
osg::Vec2 textureRepeat(1, 1);
|
|
|
|
float creaseAngle = 61;
|
|
|
|
unsigned objectType = ObjectTypeGroup;
|
|
|
|
|
|
|
|
while (!stream.eof() && stream.good()) {
|
|
|
|
std::string token;
|
|
|
|
stream >> token;
|
|
|
|
|
|
|
|
if (token == "MATERIAL") {
|
|
|
|
MaterialData mat;
|
|
|
|
mat.readMaterial(stream);
|
|
|
|
fileData.addMaterial(mat);
|
|
|
|
}
|
|
|
|
else if (token == "OBJECT") {
|
|
|
|
std::string type;
|
|
|
|
stream >> type;
|
|
|
|
|
|
|
|
if (type == "group")
|
|
|
|
objectType = ObjectTypeGroup;
|
|
|
|
else if (type == "light")
|
|
|
|
objectType = ObjectTypeLight;
|
|
|
|
else if (type == "world")
|
|
|
|
objectType = ObjectTypeGroup;
|
|
|
|
else
|
|
|
|
objectType = ObjectTypeNormal;
|
|
|
|
}
|
|
|
|
else if (token == "crease") {
|
|
|
|
stream >> creaseAngle;
|
|
|
|
}
|
|
|
|
else if (token == "data") {
|
|
|
|
int len;
|
|
|
|
stream >> len;
|
|
|
|
std::vector<char> tmp(len);
|
|
|
|
stream.read(&(tmp[0]), len);
|
|
|
|
}
|
|
|
|
else if (token == "name") {
|
|
|
|
group->setName(readString(stream));
|
|
|
|
}
|
|
|
|
else if (token == "texture") {
|
|
|
|
// read the texture name
|
|
|
|
std::string texname = readString(stream);
|
|
|
|
|
|
|
|
// strip the path to the texture, just look in the directory we read the ac file
|
|
|
|
std::string::size_type p = texname.rfind('\\');
|
|
|
|
if (p != std::string::npos)
|
|
|
|
texname = texname.substr(p+1, std::string::npos);
|
|
|
|
p = texname.rfind('/');
|
|
|
|
if (p != std::string::npos)
|
|
|
|
texname = texname.substr(p+1, std::string::npos);
|
|
|
|
|
2007-05-04 16:45:21 +08:00
|
|
|
textureData = fileData.toTextureData(texname);
|
2006-11-15 00:37:07 +08:00
|
|
|
}
|
|
|
|
else if (token == "texrep") {
|
|
|
|
stream >> textureRepeat[0] >> textureRepeat[1];
|
|
|
|
}
|
|
|
|
else if (token == "texoff") {
|
|
|
|
stream >> textureOffset[0] >> textureOffset[1];
|
|
|
|
}
|
|
|
|
else if (token == "rot") {
|
|
|
|
for (unsigned n = 0; n < 3; ++n)
|
|
|
|
for (unsigned m = 0; m < 3; ++m)
|
|
|
|
stream >> transform(m, n);
|
|
|
|
}
|
|
|
|
else if (token == "loc") {
|
|
|
|
for (unsigned n = 0; n < 3; ++n)
|
|
|
|
stream >> transform(3, n);
|
|
|
|
}
|
|
|
|
else if (token == "url") {
|
|
|
|
std::string url;
|
|
|
|
stream >> url;
|
|
|
|
group->addDescription(url);
|
|
|
|
}
|
|
|
|
else if (token == "numvert") {
|
|
|
|
osg::Matrix currentTransform = transform*parentTransform;
|
|
|
|
|
|
|
|
unsigned num;
|
|
|
|
stream >> num;
|
|
|
|
if (num != 0) {
|
|
|
|
vertexSet->reserve(num);
|
|
|
|
|
|
|
|
for (unsigned n = 0; n < num; ++n) {
|
2004-01-09 05:39:14 +08:00
|
|
|
osg::Vec3 p;
|
2006-11-15 00:37:07 +08:00
|
|
|
stream >> p[0] >> p[1] >> p[2];
|
|
|
|
vertexSet->addVertex(currentTransform.preMult(p));
|
2004-01-09 05:39:14 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2006-11-15 00:37:07 +08:00
|
|
|
else if (token == "numsurf") {
|
|
|
|
unsigned num;
|
|
|
|
stream >> num;
|
|
|
|
if (0 < num) {
|
|
|
|
// list of materials required- generate one geode per material
|
|
|
|
std::vector<Bins> primitiveBins(fileData.getNumMaterials());
|
|
|
|
vertexSet->setCreaseAngle(creaseAngle);
|
|
|
|
|
|
|
|
for (unsigned n = 0; n < num; ++n) {
|
|
|
|
std::string token;
|
|
|
|
stream >> token;
|
|
|
|
|
|
|
|
if (token != "SURF") {
|
|
|
|
osg::notify(osg::FATAL) << "osgDB ac3d reader: expected SURF line while reading object \""
|
|
|
|
<< group->getName() << "\"!" << std::endl;
|
|
|
|
return group.release();
|
2004-01-09 05:39:14 +08:00
|
|
|
}
|
2006-11-15 00:37:07 +08:00
|
|
|
|
|
|
|
stream >> token;
|
|
|
|
unsigned flags = strtol(token.c_str(), NULL, 0);
|
|
|
|
|
|
|
|
stream >> token;
|
|
|
|
if (token != "mat") {
|
|
|
|
osg::notify(osg::FATAL) << "osgDB ac3d reader: expected mat line while reading object \""
|
|
|
|
<< group->getName() << "\"!" << std::endl;
|
|
|
|
return group.release();
|
|
|
|
}
|
|
|
|
|
|
|
|
// read the material index
|
|
|
|
unsigned matIdx;
|
|
|
|
stream >> matIdx;
|
|
|
|
if (primitiveBins.size() <= matIdx) {
|
|
|
|
osg::notify(osg::FATAL) << "osgDB ac3d reader: invalid material number while reading object \""
|
|
|
|
<< group->getName() << "\"" << std::endl;
|
|
|
|
return group.release();
|
|
|
|
}
|
|
|
|
|
|
|
|
// now get the correct PrimitiveBin
|
|
|
|
PrimitiveBin* primitiveBin = 0;
|
|
|
|
primitiveBin = primitiveBins[matIdx].getOrCreatePrimitiveBin(flags, vertexSet.get());
|
|
|
|
if (!primitiveBin) {
|
|
|
|
osg::notify(osg::FATAL) << "osgDB ac3d reader: unexpected primitive flags while reading object \""
|
|
|
|
<< group->getName() << "\"" << std::endl;
|
|
|
|
return group.release();
|
|
|
|
}
|
|
|
|
|
|
|
|
// read the refs
|
|
|
|
stream >> token;
|
|
|
|
if (token != "refs") {
|
|
|
|
osg::notify(osg::FATAL) << "osgDB ac3d reader: expected refs line while reading object \""
|
|
|
|
<< group->getName() << "\"" << std::endl;
|
|
|
|
return group.release();
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned nRefs = 0;
|
|
|
|
stream >> nRefs;
|
|
|
|
if (!stream) {
|
|
|
|
osg::notify(osg::FATAL) << "osgDB ac3d reader: could not read number of refs while reading object \""
|
|
|
|
<< group->getName() << "\"" << std::endl;
|
|
|
|
return group.release();
|
|
|
|
}
|
|
|
|
|
|
|
|
// in case this is an invalid refs count for this primitive
|
|
|
|
// read further, but do not store that primitive
|
|
|
|
bool acceptPrimitive = primitiveBin->beginPrimitive(nRefs);
|
|
|
|
for (unsigned i = 0; i < nRefs; ++i) {
|
|
|
|
// Read the vertex index
|
|
|
|
unsigned index;
|
|
|
|
stream >> index;
|
|
|
|
if (vertexSet->size() <= index)
|
2004-01-09 05:39:14 +08:00
|
|
|
{
|
2006-11-15 00:37:07 +08:00
|
|
|
osg::notify(osg::FATAL) << "osgDB ac3d reader: invalid ref vertex index while reading object \""
|
|
|
|
<< group->getName() << "\"" << std::endl;
|
|
|
|
return group.release();
|
2004-01-09 05:39:14 +08:00
|
|
|
}
|
2006-11-15 00:37:07 +08:00
|
|
|
|
|
|
|
// Read the texture corrdinates
|
|
|
|
osg::Vec2 texCoord;
|
|
|
|
stream >> texCoord[0] >> texCoord[1];
|
|
|
|
if (!stream) {
|
|
|
|
osg::notify(osg::WARN) << "osgDB ac3d reader: could not parse texture coords while reading object \""
|
|
|
|
<< group->getName() << "\" setting to (0,0)" << std::endl;
|
|
|
|
stream.clear();
|
|
|
|
std::string dummy;
|
|
|
|
std::getline(stream, dummy);
|
2004-01-09 05:39:14 +08:00
|
|
|
}
|
2006-11-15 00:37:07 +08:00
|
|
|
|
|
|
|
if (acceptPrimitive)
|
2004-01-09 05:39:14 +08:00
|
|
|
{
|
2006-11-15 00:37:07 +08:00
|
|
|
texCoord[0] = textureOffset[0] + texCoord[0]*textureRepeat[0];
|
|
|
|
texCoord[1] = textureOffset[1] + texCoord[1]*textureRepeat[1];
|
|
|
|
|
|
|
|
if (!primitiveBin->vertex(index, texCoord))
|
2005-07-05 23:57:53 +08:00
|
|
|
{
|
2006-11-15 00:37:07 +08:00
|
|
|
return group.release();
|
2005-07-05 23:57:53 +08:00
|
|
|
}
|
2004-01-09 05:39:14 +08:00
|
|
|
}
|
|
|
|
}
|
2006-11-15 00:37:07 +08:00
|
|
|
if (acceptPrimitive)
|
2004-01-09 05:39:14 +08:00
|
|
|
{
|
2006-11-15 00:37:07 +08:00
|
|
|
if (!primitiveBin->endPrimitive())
|
|
|
|
{
|
|
|
|
return group.release();
|
|
|
|
}
|
2004-01-09 05:39:14 +08:00
|
|
|
}
|
|
|
|
}
|
2006-11-15 00:37:07 +08:00
|
|
|
|
|
|
|
for (unsigned i = 0; i < primitiveBins.size(); ++i)
|
2007-05-16 03:45:46 +08:00
|
|
|
primitiveBins[i].finalize(group.get(), fileData.getMaterial(i), textureData);
|
2004-01-09 05:39:14 +08:00
|
|
|
}
|
|
|
|
}
|
2006-11-15 00:37:07 +08:00
|
|
|
else if (token == "kids") {
|
|
|
|
unsigned num;
|
|
|
|
stream >> num;
|
|
|
|
if (num != 0) {
|
|
|
|
for (unsigned n = 0; n < num; n++) {
|
2007-05-04 16:45:21 +08:00
|
|
|
osg::Node *k = readObject(stream, fileData, transform*parentTransform, textureData);
|
2006-11-15 00:37:07 +08:00
|
|
|
if (k == 0) {
|
|
|
|
osg::notify(osg::FATAL) << "osgDB ac3d reader: error reading child object" << std::endl;
|
|
|
|
return group.release();
|
2004-01-09 05:39:14 +08:00
|
|
|
}
|
|
|
|
else {
|
2006-11-15 00:37:07 +08:00
|
|
|
osg::LightSource *ls = dynamic_cast<osg::LightSource*>(k);
|
2004-01-09 05:39:14 +08:00
|
|
|
if (ls) {
|
2006-11-15 00:37:07 +08:00
|
|
|
osg::StateSet* lightStateSet = group->getOrCreateStateSet();
|
|
|
|
group->setStateSet(lightStateSet);
|
|
|
|
group->setCullingActive(false);
|
|
|
|
ls->setStateSetModes(*lightStateSet, osg::StateAttribute::ON);
|
2004-01-09 05:39:14 +08:00
|
|
|
}
|
|
|
|
|
2006-11-15 00:37:07 +08:00
|
|
|
group->addChild(k);
|
2004-01-09 05:39:14 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2006-11-15 00:37:07 +08:00
|
|
|
else if (objectType == ObjectTypeLight) { // add a light source to the scene 1 Nov 2003
|
|
|
|
osg::Light* ac3dLight = fileData.getNextLight();
|
|
|
|
osg::Matrix tt = transform*parentTransform;
|
|
|
|
ac3dLight->setPosition(osg::Vec4(tt(3, 0), tt(3, 1), tt(3, 2), 1));
|
|
|
|
ac3dLight->setDirection(osg::Matrix::transform3x3(osg::Vec3(0.0f, 0.0f, -1.0f), tt));
|
2004-01-09 05:39:14 +08:00
|
|
|
ac3dLight->setAmbient(osg::Vec4(0.5f,0.5f,0.5f,1.0f));
|
|
|
|
ac3dLight->setDiffuse(osg::Vec4(0.5f,0.5f,0.5f,1.0f));
|
|
|
|
ac3dLight->setSpecular(osg::Vec4(1.0f,1.0f,0.5f,1.0f));
|
|
|
|
|
|
|
|
osg::LightSource* ac3dLightSource = new osg::LightSource;
|
|
|
|
ac3dLightSource->setLight(ac3dLight);
|
2006-11-15 00:37:07 +08:00
|
|
|
ac3dLightSource->setLocalStateSetModes(osg::StateAttribute::ON);
|
2004-01-09 05:39:14 +08:00
|
|
|
|
|
|
|
// for some mad reason, you need to set this so that the light works. WHY?
|
|
|
|
return ac3dLightSource;
|
|
|
|
}
|
2006-11-15 00:37:07 +08:00
|
|
|
return group.release();
|
2004-01-09 05:39:14 +08:00
|
|
|
}
|
|
|
|
}
|
2006-11-15 00:37:07 +08:00
|
|
|
|
|
|
|
return group.release();
|
2002-10-31 20:51:09 +08:00
|
|
|
}
|
|
|
|
|
2006-11-15 00:37:07 +08:00
|
|
|
osg::Node*
|
|
|
|
readFile(std::istream& stream, const osgDB::ReaderWriter::Options* options)
|
2002-10-31 20:51:09 +08:00
|
|
|
{
|
2006-11-15 00:37:07 +08:00
|
|
|
FileData fileData(options);
|
|
|
|
osg::Matrix idetityTransform;
|
2007-05-04 16:45:21 +08:00
|
|
|
osg::Node* node = readObject(stream, fileData, idetityTransform, TextureData());
|
2006-11-15 00:37:07 +08:00
|
|
|
if (node)
|
|
|
|
node->setName("World");
|
|
|
|
return node;
|
2002-10-31 20:51:09 +08:00
|
|
|
}
|
|
|
|
|
2006-11-15 00:37:07 +08:00
|
|
|
} // namespace ac3d
|