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.
|
|
|
|
|
|
|
|
|
|
|
|
#include <stdio.h>
|
2003-04-03 16:14:49 +08:00
|
|
|
#ifdef __DARWIN_OSX__
|
|
|
|
#include <sys/malloc.h>
|
|
|
|
#else
|
2002-10-31 20:51:09 +08:00
|
|
|
#include <malloc.h>
|
2003-04-03 16:14:49 +08:00
|
|
|
#endif
|
2002-10-31 20:51:09 +08:00
|
|
|
#include <math.h>
|
|
|
|
|
|
|
|
#include <osg/CullFace>
|
|
|
|
#include <osg/Geode>
|
|
|
|
#include <osg/Group>
|
|
|
|
#include <osg/Geometry> //Set>
|
|
|
|
#include <osg/Light>
|
|
|
|
#include <osg/LightSource>
|
|
|
|
#include <osg/Material>
|
|
|
|
#include <osg/Texture2D>
|
|
|
|
#include <osg/TexEnv>
|
|
|
|
#include <osg/StateSet>
|
|
|
|
#include <osg/Notify>
|
|
|
|
#include <osg/Texture2D>
|
|
|
|
|
|
|
|
|
|
|
|
#include <osgDB/FileNameUtils>
|
|
|
|
#include <osgDB/Registry>
|
|
|
|
#include <osgDB/ReadFile>
|
|
|
|
#include <osgDB/FileUtils>
|
|
|
|
|
|
|
|
#include <osgUtil/Tesselator>
|
|
|
|
#include <osgUtil/SmoothingVisitor>
|
|
|
|
|
|
|
|
#include "osgac3d.h"
|
2003-10-12 23:20:09 +08:00
|
|
|
#include "Exception.h"
|
|
|
|
#include "Geode.h"
|
|
|
|
|
|
|
|
using namespace osg;
|
|
|
|
using namespace osgDB;
|
|
|
|
|
|
|
|
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(osgAction::ActionHeader& ah);
|
|
|
|
// virtual void apply(osg::Drawable& dr);
|
|
|
|
virtual void apply(osg::Geode& geode) {
|
|
|
|
_geodelist.push_back(&geode);
|
|
|
|
}
|
|
|
|
// virtual void apply(osg::Billboard& geode);
|
|
|
|
virtual void apply(osg::Group& gp){
|
|
|
|
traverse(gp); // must continue subgraph traversal.
|
|
|
|
}
|
|
|
|
// virtual void apply(osg::Switch& sw);
|
|
|
|
// virtual void apply(osg::Transform& transform);
|
|
|
|
std::vector<const osg::Geode *> getGeodes() {return _geodelist;}
|
|
|
|
protected:
|
|
|
|
|
|
|
|
typedef std::vector<const osg::Geode *> Geodelist;
|
|
|
|
Geodelist _geodelist;
|
|
|
|
};
|
2002-10-31 20:51:09 +08:00
|
|
|
|
|
|
|
class ReaderWriterAC : public osgDB::ReaderWriter
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
virtual const char* className() { return "AC3D Database Reader"; }
|
|
|
|
|
|
|
|
virtual bool acceptsExtension(const std::string& extension)
|
|
|
|
{
|
|
|
|
return osgDB::equalCaseInsensitive(extension,"ac");
|
|
|
|
}
|
|
|
|
virtual ReadResult readNode(const std::string& fileName,const osgDB::ReaderWriter::Options*)
|
|
|
|
{
|
|
|
|
osg::Group *grp; // holder for all loaded objects
|
|
|
|
grp=ac_load_ac3d(fileName.c_str());
|
|
|
|
return grp;
|
|
|
|
};
|
2003-10-12 23:20:09 +08:00
|
|
|
virtual WriteResult writeNode(const Node& node,const std::string& fileName, const osgDB::ReaderWriter::Options* /*options*/)
|
|
|
|
{
|
|
|
|
std::string ext = getFileExtension(fileName);
|
|
|
|
if (!acceptsExtension(ext)) return WriteResult::FILE_NOT_HANDLED;
|
|
|
|
geodeVisitor vs; // this collects geodes.
|
|
|
|
Node *nd=(Node *)(&node);
|
|
|
|
std::vector<unsigned int>iNumMaterials;
|
|
|
|
nd->accept(vs); // this parses the tree to find Geodes
|
|
|
|
std::vector<const osg::Geode *> glist=vs.getGeodes();
|
|
|
|
std::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
|
|
|
|
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()));
|
|
|
|
}
|
|
|
|
// output the Geometry
|
|
|
|
unsigned int nfirstmat=0;
|
|
|
|
fout << "OBJECT world" << std::endl;
|
|
|
|
fout << "kids " << (glist.end()-glist.begin()) << 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 Node& node,std::ostream& fout, const osgDB::ReaderWriter::Options* opts)
|
|
|
|
{
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//const_cast<ac3d::Group*>(static_cast<const ac3d::Group*>(&node))->Process(fout, options);
|
|
|
|
// else if(dynamic_cast<const osg::Geode*>(&node))
|
|
|
|
// const_cast<ac3d::Geode*>(static_cast<const ac3d::Geode*>(&node))->Process(fout);
|
|
|
|
else
|
|
|
|
std::cout<<"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;
|
|
|
|
|
|
|
|
}
|
2002-10-31 20:51:09 +08:00
|
|
|
private:
|
|
|
|
};
|
|
|
|
|
|
|
|
static int line = 0;
|
|
|
|
static char buff[255];
|
|
|
|
|
|
|
|
|
|
|
|
|
2003-10-12 23:20:09 +08:00
|
|
|
static std::vector<osg::Material*> palette; // change to dynamic array
|
|
|
|
//static int num_palette = 0;
|
2002-10-31 20:51:09 +08:00
|
|
|
static int startmatindex = 0;
|
|
|
|
|
|
|
|
|
|
|
|
osg::Material*ac_palette_get_material(int id)
|
|
|
|
{
|
|
|
|
return(palette[id]);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Boolean read_line(FILE *f)
|
|
|
|
{
|
|
|
|
fgets(buff, 255, f); line++;
|
|
|
|
return(TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int tokc = 0;
|
|
|
|
char *tokv[30];
|
|
|
|
|
|
|
|
Prototype int get_tokens(char *s, int *argc, char *argv[])
|
|
|
|
/** bung '\0' chars at the end of tokens and set up the array (tokv) and count (tokc)
|
|
|
|
like argv argc **/
|
|
|
|
{
|
|
|
|
char *p = s;
|
|
|
|
char *st;
|
|
|
|
char c;
|
|
|
|
//int n;
|
|
|
|
int tc;
|
|
|
|
|
|
|
|
tc = 0;
|
|
|
|
while ((c = *p))
|
|
|
|
{
|
|
|
|
if ((c != ' ') && (c != '\t') && (c != '\n') && ( c != 13))
|
|
|
|
{
|
|
|
|
if (c == '"')
|
|
|
|
{
|
|
|
|
c = *p++;
|
|
|
|
st = p;
|
|
|
|
while ((c = *p) && ((c != '"')&&(c != '\n')&& ( c != 13)) )
|
|
|
|
{
|
|
|
|
if (c == '\\')
|
|
|
|
strcpy(p, p+1);
|
|
|
|
p++;
|
|
|
|
}
|
|
|
|
*p=0;
|
|
|
|
argv[tc++] = st;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
st = p;
|
|
|
|
while ((c = *p) && ((c != ' ') && (c != '\t') && (c != '\n') && ( c != 13)) )
|
|
|
|
p++;
|
|
|
|
*p=0;
|
|
|
|
argv[tc++] = st;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
p++;
|
|
|
|
}
|
|
|
|
|
|
|
|
*argc = tc;
|
|
|
|
return(tc);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void initobject(ACObject *ob)
|
|
|
|
{
|
|
|
|
ob->loc[0] = ob->loc[1] = ob->loc[2] = 0.0;
|
|
|
|
ob->name = ob->url = NULL;
|
|
|
|
ob->data = NULL;
|
|
|
|
ob->num_vert = 0;
|
|
|
|
ob->num_surf = 0;
|
|
|
|
ob->texture = NULL;
|
|
|
|
ob->texture_repeat_x = ob->texture_repeat_y = 1.0;
|
|
|
|
ob->texture_offset_x = ob->texture_offset_y = 0.0;
|
|
|
|
ob->kids = NULL;
|
|
|
|
ob->num_kids = 0;
|
|
|
|
ob->matrix[0] = 1;
|
|
|
|
ob->matrix[1] = 0;
|
|
|
|
ob->matrix[2] = 0;
|
|
|
|
ob->matrix[3] = 0;
|
|
|
|
ob->matrix[4] = 1;
|
|
|
|
ob->matrix[5] = 0;
|
|
|
|
ob->matrix[6] = 0;
|
|
|
|
ob->matrix[7] = 0;
|
|
|
|
ob->matrix[8] = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void init_surface(ACSurface *s)
|
|
|
|
{
|
|
|
|
s->num_vertref = 0;
|
|
|
|
s->flags = 0;
|
|
|
|
s->mat = 0;
|
|
|
|
// s->normal.x = 0.0; s->normal.z = 0.0; s->normal.z = 0.0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void osgtri_calc_normal(osg::Vec3 &v1, osg::Vec3 &v2, osg::Vec3 &v3, osg::Vec3 &n)
|
|
|
|
{
|
|
|
|
osg::Vec3 side1=v2-v1;
|
|
|
|
osg::Vec3 side2=v3-v2;
|
|
|
|
n=side1^side2;
|
|
|
|
n.normalize();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
ACSurface *read_surface(FILE *f, ACSurface *s,osg::UShortArray *nusidx,
|
|
|
|
osg::Vec2Array *tcs)
|
|
|
|
{
|
|
|
|
char t[20];
|
|
|
|
init_surface(s);
|
|
|
|
|
|
|
|
while (!feof(f))
|
|
|
|
{
|
|
|
|
read_line(f);
|
|
|
|
sscanf(buff, "%s", t);
|
|
|
|
|
|
|
|
if (streq(t, "SURF"))
|
|
|
|
{
|
|
|
|
int flgs;
|
|
|
|
|
|
|
|
if (get_tokens(buff, &tokc, tokv) != 2)
|
|
|
|
{
|
|
|
|
printf("SURF should be followed by one flags argument\n");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
flgs = strtol(tokv[1], NULL, 0);
|
|
|
|
s->flags = flgs;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
if (streq(t, "mat"))
|
|
|
|
{
|
|
|
|
int mindx;
|
|
|
|
|
|
|
|
sscanf(buff, "%s %d", t, &mindx);
|
|
|
|
s->mat = mindx+startmatindex;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
if (streq(t, "refs"))
|
|
|
|
{
|
|
|
|
int num, n;
|
|
|
|
int ind;
|
|
|
|
osg::Vec2 tx;
|
|
|
|
|
|
|
|
sscanf(buff, "%s %d", t, &num);
|
|
|
|
|
|
|
|
s->num_vertref = num;
|
|
|
|
|
|
|
|
for (n = 0; n < num; n++)
|
|
|
|
{
|
|
|
|
fscanf(f, "%d %f %f\n", &ind, &tx[0], &tx[1]); line++;
|
|
|
|
nusidx->push_back(ind);
|
|
|
|
if (tcs) tcs->push_back(tx);
|
|
|
|
}
|
|
|
|
|
|
|
|
return(s);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
printf("ignoring %s\n", t);
|
|
|
|
|
|
|
|
}
|
|
|
|
return(NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*void ac_object_calc_vertex_normals(ACObject *ob)
|
|
|
|
{
|
|
|
|
int s, v, vr;
|
|
|
|
|
|
|
|
/ ** for each vertex in this object ** /
|
|
|
|
for (v = 0; v < ob->num_vert; v++)
|
|
|
|
{
|
|
|
|
ACNormal n = {0, 0, 0};
|
|
|
|
int found = 0;
|
|
|
|
|
|
|
|
/ ** go through each surface ** /
|
|
|
|
for (s = 0; s < ob->num_surf; s++)
|
|
|
|
{
|
|
|
|
ACSurface *surf = &ob->surfaces[s];
|
|
|
|
|
|
|
|
/ ** check if this vertex is used in this surface ** /
|
|
|
|
/ ** if it is, use it to create an average normal ** /
|
|
|
|
for (vr = 0; vr < surf->num_vertref; vr++)
|
|
|
|
if (surf->vertref[vr] == v)
|
|
|
|
{
|
|
|
|
n.x+=surf->normal.x;
|
|
|
|
n.y+=surf->normal.y;
|
|
|
|
n.z+=surf->normal.z;
|
|
|
|
found++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (found > 0)
|
|
|
|
{
|
|
|
|
n.x /= found;
|
|
|
|
n.y /= found;
|
|
|
|
n.z /= found;
|
|
|
|
}
|
|
|
|
ob->vertices[v].normal = n;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
} */
|
|
|
|
|
|
|
|
|
|
|
|
int string_to_objecttype(char *s)
|
|
|
|
{
|
|
|
|
if (streq("world", s))
|
|
|
|
return(OBJECT_WORLD);
|
|
|
|
if (streq("poly", s))
|
|
|
|
return(OBJECT_NORMAL);
|
|
|
|
if (streq("group", s))
|
|
|
|
return(OBJECT_GROUP);
|
|
|
|
if (streq("light", s))
|
|
|
|
return(OBJECT_LIGHT);
|
|
|
|
return(OBJECT_NORMAL);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
protate(osg::Vec3 p, float m[9])
|
|
|
|
{ // p-> m*p, m is 3.3 matrix
|
|
|
|
osg::Vec3 t=p;
|
|
|
|
p[0]=m[0]*t[0]+m[1]*t[1]+m[2]*t[3];
|
|
|
|
p[1]=m[3]*t[0]+m[4]*t[1]+m[5]*t[3];
|
|
|
|
p[2]=m[6]*t[0]+m[7]*t[1]+m[8]*t[3];
|
|
|
|
}
|
|
|
|
|
|
|
|
osg::Group *ac_load_object(FILE *f,const ACObject *parent)
|
|
|
|
{
|
2003-10-12 23:20:09 +08:00
|
|
|
// most of this logic came from Andy Colebourne (developer of the AC3D editor) so it had better be right!
|
|
|
|
char t[20];
|
|
|
|
osg::Group *gp=NULL;
|
|
|
|
osg::Geode *geode=NULL;
|
|
|
|
osg::Vec3Array *normals = NULL; // new osg::Vec3Array; // NULL;
|
|
|
|
|
|
|
|
ACObject ob; // local storage for stuff taken from AC's loader
|
|
|
|
osg::Vec3Array *vertpool = new osg::Vec3Array;
|
|
|
|
|
|
|
|
if (parent)
|
|
|
|
ob.loc=parent->loc; // copy loc
|
|
|
|
while (!feof(f))
|
|
|
|
{
|
|
|
|
read_line(f);
|
|
|
|
|
|
|
|
sscanf(buff, "%s", t);
|
|
|
|
|
|
|
|
if (streq(t, "MATERIAL"))
|
|
|
|
{
|
|
|
|
if (get_tokens(buff, &tokc, tokv) != 22)
|
|
|
|
{
|
|
|
|
printf("expected 21 params after \"MATERIAL\" - line %d\n", line);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
osg::Material *numat=new osg::Material();
|
|
|
|
osg::Vec4 cdiff((float)atof(tokv[3]), (float)atof(tokv[4]),
|
|
|
|
(float)atof(tokv[5]), 1.0-(float)atof(tokv[21]));
|
|
|
|
numat->setDiffuse(osg::Material::FRONT_AND_BACK,cdiff);
|
|
|
|
osg::Vec4 camb((float)atof(tokv[7]),(float)atof(tokv[8]),
|
|
|
|
(float)atof(tokv[9]),1.0-(float)atof(tokv[21]));
|
|
|
|
numat->setAmbient(osg::Material::FRONT_AND_BACK,camb);
|
|
|
|
osg::Vec4 cspec((float)atof(tokv[15]), (float)atof(tokv[16]),
|
|
|
|
(float)atof(tokv[17]),1.0-(float)atof(tokv[21]));
|
|
|
|
numat->setSpecular(osg::Material::FRONT_AND_BACK,cspec);
|
2003-11-03 04:10:04 +08:00
|
|
|
// addition 1 Nov 2003 - use shininess (was defaulted)
|
|
|
|
float shininess=atof(tokv[19]);
|
|
|
|
numat->setShininess(osg::Material::FRONT_AND_BACK,shininess);
|
2003-10-12 23:20:09 +08:00
|
|
|
osg::Vec4 cemm((float)atof(tokv[11]),(float)atof(tokv[12]),(float)atof(tokv[13]),1.0-(float)atof(tokv[21]));
|
2003-11-03 04:10:04 +08:00
|
|
|
// correction 1 Nov 2003 - from Marcio Ferraz - use emission colour for emission
|
|
|
|
numat->setEmission(osg::Material::FRONT_AND_BACK,cemm);
|
2003-10-12 23:20:09 +08:00
|
|
|
//numat->setTransparency(osg::Material::FRONT_AND_BACK, 1.0-(float)atof(tokv[21]));
|
|
|
|
|
|
|
|
palette.push_back(numat); // [num_palette++] = numat;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (streq(t, "OBJECT"))
|
|
|
|
{
|
|
|
|
char type[20];
|
|
|
|
char str[20];
|
|
|
|
osg::Vec3 loc=ob.loc;
|
|
|
|
if (!gp) gp = new osg::Group();
|
|
|
|
initobject(&ob); // rezero data for object
|
|
|
|
ob.loc=loc;
|
|
|
|
|
|
|
|
sscanf(buff, "%s %s", str, type);
|
|
|
|
|
|
|
|
ob.type = string_to_objecttype(type);
|
|
|
|
}
|
|
|
|
else if (streq(t, "data"))
|
|
|
|
{
|
|
|
|
if (get_tokens(buff, &tokc, tokv) != 2)
|
|
|
|
printf("expected 'data <number>' at line %d\n", line);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
char *str;
|
|
|
|
int len;
|
|
|
|
|
|
|
|
len = atoi(tokv[1]);
|
|
|
|
if (len > 0)
|
|
|
|
{
|
|
|
|
str = (char *)myalloc(len+1);
|
|
|
|
fread(str, len, 1, f);
|
|
|
|
str[len] = 0;
|
|
|
|
fscanf(f, "\n"); line++;
|
|
|
|
ob.data = STRING(str);
|
|
|
|
myfree(str);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (streq(t, "name"))
|
|
|
|
{
|
|
|
|
int numtok = get_tokens(buff, &tokc, tokv);
|
|
|
|
if (numtok != 2)
|
|
|
|
{
|
|
|
|
printf("expected quoted name at line %d (got %d tokens)\n", line, numtok);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
if (gp) gp->setName(tokv[1]);
|
|
|
|
}
|
|
|
|
else if (streq(t, "texture"))
|
|
|
|
{
|
|
|
|
if (get_tokens(buff, &tokc, tokv) != 2)
|
|
|
|
printf("expected quoted texture name at line %d\n", line);
|
|
|
|
|
|
|
|
else
|
|
|
|
{
|
|
|
|
osg::Image *ctx= osgDB::readImageFile(tokv[1]);
|
|
|
|
if (ctx)
|
|
|
|
{ // image coukd be read
|
|
|
|
ob.texture = new osg::Texture2D;// ac_load_texture(tokv[1]);
|
|
|
|
ob.texture->setImage(ctx);
|
|
|
|
ob.texture->setWrap(osg::Texture2D::WRAP_S, osg::Texture2D::REPEAT);
|
|
|
|
ob.texture->setWrap(osg::Texture2D::WRAP_T, osg::Texture2D::REPEAT);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (streq(t, "texrep"))
|
|
|
|
{
|
|
|
|
if (get_tokens(buff, &tokc, tokv) != 3)
|
|
|
|
printf("expected 'texrep <float> <float>' at line %d\n", line);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ob.texture_repeat_x = atof(tokv[1]);
|
|
|
|
ob.texture_repeat_y = atof(tokv[2]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (streq(t, "texoff"))
|
|
|
|
{
|
|
|
|
if (get_tokens(buff, &tokc, tokv) != 3)
|
|
|
|
printf("expected 'texoff <float> <float>' at line %d\n", line);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ob.texture_offset_x = atof(tokv[1]);
|
|
|
|
ob.texture_offset_y = atof(tokv[2]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (streq(t, "rot"))
|
|
|
|
{
|
|
|
|
float r[9];
|
|
|
|
char str2[5];
|
|
|
|
int n;
|
|
|
|
|
|
|
|
sscanf(buff, "%s %f %f %f %f %f %f %f %f %f", str2, &r[0], &r[1], &r[2], &r[3], &r[4], &r[5], &r[6], &r[7], &r[8] );
|
|
|
|
|
|
|
|
for (n = 0; n < 9; n++)
|
|
|
|
ob.matrix[n] = r[n];
|
|
|
|
|
|
|
|
}
|
|
|
|
else if (streq(t, "loc"))
|
|
|
|
{
|
|
|
|
char str[5];
|
|
|
|
osg::Vec3 loc;
|
|
|
|
sscanf(buff, "%s %f %f %f", str, &loc[0], &loc[1], &loc[2]);
|
|
|
|
ob.loc+=loc;
|
|
|
|
}
|
|
|
|
else if (streq(t, "url"))
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
if ((ret = get_tokens(buff, &tokc, tokv)) != 2)
|
|
|
|
printf("expected one arg to url at line %d (got %d)\n", line, ret);
|
|
|
|
else
|
|
|
|
ob.url = STRING(tokv[1]);
|
|
|
|
}
|
|
|
|
else if (streq(t, "numvert"))
|
|
|
|
{
|
|
|
|
int num, n;
|
|
|
|
char str[10];
|
|
|
|
if (ob.type == OBJECT_GROUP || ob.type == OBJECT_WORLD)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
else if (ob.type == OBJECT_NORMAL)
|
|
|
|
{
|
|
|
|
if (geode)
|
|
|
|
{
|
|
|
|
osgUtil::Tesselator tesselator;
|
|
|
|
for(unsigned int i=0;i<geode->getNumDrawables();++i)
|
|
|
|
{
|
|
|
|
osg::Geometry* geom = dynamic_cast<osg::Geometry*>(geode->getDrawable(i));
|
|
|
|
if (geom) tesselator.retesselatePolygons(*geom);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
geode = new osg::Geode();
|
|
|
|
gp->addChild(geode);
|
|
|
|
geode->setName(gp->getName());
|
|
|
|
normals = new osg::Vec3Array;
|
|
|
|
}
|
|
|
|
|
|
|
|
sscanf(buff, "%s %d", str, &num);
|
|
|
|
|
|
|
|
if (num > 0)
|
|
|
|
{
|
|
|
|
ob.num_vert = num;
|
|
|
|
|
|
|
|
for (n = 0; n < num; n++)
|
|
|
|
{
|
|
|
|
osg::Vec3 p;
|
|
|
|
fscanf(f, "%f %f %f\n", &p[0], &p[1], &p[2]); line++;
|
|
|
|
protate(p, ob.matrix);
|
|
|
|
vertpool->push_back(p+ob.loc);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (streq(t, "numsurf"))
|
|
|
|
{
|
|
|
|
int num, n;
|
|
|
|
char str[10];
|
|
|
|
// this is not obvious (what is?). Each set of surfaces can have different material on each surface.
|
|
|
|
// so I set up a set of 'bins' for
|
|
|
|
// the primitives (geometry list, geomlist)
|
|
|
|
// the coords array of each geometry (Vec3Array list, vertslist)
|
|
|
|
// the tx coords array for each geometry (Vec2Array list, texslist)
|
|
|
|
// then I add a new geometry to the current Geode for each new material as it is found.
|
|
|
|
|
|
|
|
std::vector<int> ia; // list of materials required- generate one geode per material
|
|
|
|
typedef std::vector<osg::Geometry *> geomlist;
|
|
|
|
geomlist glist;
|
|
|
|
typedef std::vector<osg::Vec3Array *> vertslist;
|
|
|
|
vertslist vlists; // list of vertices for each glist element
|
|
|
|
typedef std::vector<osg::Vec2Array *> texslist;
|
|
|
|
texslist txlists; // list of texture coords for each glist element
|
|
|
|
|
|
|
|
sscanf(buff, "%s %d", str, &num);
|
|
|
|
if (num > 0)
|
|
|
|
{
|
|
|
|
int needSmooth=0; // flat shaded
|
|
|
|
ob.num_surf = num;
|
|
|
|
|
|
|
|
for (n = 0; n < num; n++)
|
|
|
|
{
|
|
|
|
osg::Geometry *geom=NULL; // the surface will be addded to this geometry
|
|
|
|
osg::Vec3Array *vgeom=NULL; // vertices corresponding to geom taken from vertexpool
|
|
|
|
osg::Vec2Array *tgeom=NULL; // texture coords corresponding to geom taken from vertexpool
|
|
|
|
ACSurface asurf;
|
|
|
|
osg::UShortArray *nusidx = new osg::UShortArray; // indices into the vertices
|
|
|
|
osg::Vec2Array *tcs=new osg::Vec2Array; // texture coordinates for this object
|
|
|
|
ACSurface *news = read_surface(f, &asurf, nusidx, tcs);
|
|
|
|
if (news == NULL)
|
|
|
|
{
|
|
|
|
printf("error whilst reading surface at line: %d\n", line);
|
|
|
|
return(NULL);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
int i=0;
|
|
|
|
for (std::vector<int>::iterator itr= ia.begin(); itr<ia.end(); itr++, i++)
|
|
|
|
{
|
|
|
|
if ((*itr)==asurf.mat)
|
|
|
|
{
|
|
|
|
geom=glist[i];
|
|
|
|
vgeom=vlists[i];
|
|
|
|
tgeom=txlists[i]; // what is current texture array
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!geom)
|
|
|
|
{ // then we need a new geometry
|
|
|
|
osg::Vec3Array *verts = new osg::Vec3Array;
|
|
|
|
|
|
|
|
osg::Vec2Array *tcrds=new osg::Vec2Array; // texture coordinates for this object
|
|
|
|
vgeom=verts;
|
|
|
|
tgeom=tcrds; // what is current texture array
|
|
|
|
vlists.push_back(verts);
|
|
|
|
txlists.push_back(tcrds);
|
|
|
|
geom=new osg::Geometry();
|
|
|
|
geom->setNormalBinding(osg::Geometry::BIND_PER_PRIMITIVE);
|
|
|
|
geom->setNormalArray(normals);
|
|
|
|
geom->setVertexArray(verts);
|
|
|
|
if (ob.texture.valid())
|
|
|
|
{
|
|
|
|
geom->setTexCoordArray(0,tgeom); // share same set of TexCoords
|
|
|
|
}
|
|
|
|
osg::Material*mat=ac_palette_get_material(asurf.mat);
|
|
|
|
osg::StateSet *dstate = new osg::StateSet;
|
|
|
|
dstate->setMode( GL_LIGHTING, osg::StateAttribute::ON );
|
|
|
|
dstate->setAttribute(mat);
|
|
|
|
const osg::Vec4 cdiff =mat->getDiffuse(osg::Material::FRONT_AND_BACK);
|
|
|
|
if (cdiff[3]<0.99)
|
|
|
|
{
|
|
|
|
dstate->setMode(GL_BLEND,osg::StateAttribute::ON);
|
|
|
|
dstate->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
dstate->setMode(GL_BLEND,osg::StateAttribute::OFF);
|
|
|
|
}
|
|
|
|
if (ob.texture.valid()) dstate->setTextureMode(0,GL_TEXTURE_2D,osg::StateAttribute::OFF);
|
|
|
|
if (ob.texture.valid())
|
|
|
|
{
|
|
|
|
osg::TexEnv* texenv = new osg::TexEnv;
|
|
|
|
texenv->setMode(osg::TexEnv::MODULATE);
|
|
|
|
dstate->setTextureAttribute(0, texenv );
|
|
|
|
dstate->setTextureAttributeAndModes(0,ob.texture.get(),osg::StateAttribute::ON);
|
|
|
|
}
|
|
|
|
if (asurf.flags & SURFACE_TWOSIDED)
|
|
|
|
dstate->setMode( GL_CULL_FACE, osg::StateAttribute::OFF );
|
|
|
|
else
|
|
|
|
dstate->setMode( GL_CULL_FACE, osg::StateAttribute::ON );
|
|
|
|
|
|
|
|
geom->setStateSet( dstate );
|
|
|
|
glist.push_back(geom);
|
|
|
|
geode->addDrawable(geom);
|
|
|
|
ia.push_back(asurf.mat);
|
|
|
|
}
|
|
|
|
|
|
|
|
osg::Vec3Array* normals = geom->getNormalArray();
|
|
|
|
/** calc surface normal **/
|
|
|
|
if (asurf.num_vertref >= 3)
|
|
|
|
{
|
|
|
|
osg::Vec3 norm;
|
|
|
|
unsigned short i1=(*nusidx)[0];
|
|
|
|
unsigned short i2=(*nusidx)[1];
|
|
|
|
unsigned short i3=(*nusidx)[2];
|
|
|
|
osgtri_calc_normal((*vertpool)[i1],
|
|
|
|
(*vertpool)[i2],
|
|
|
|
(*vertpool)[i3], norm);
|
|
|
|
normals->push_back(norm);
|
|
|
|
}
|
|
|
|
int nstart=(*vgeom).size();
|
|
|
|
for (i=0; i<asurf.num_vertref; i++)
|
|
|
|
{
|
|
|
|
osg::Vec2 TextureCoordinate;
|
|
|
|
|
|
|
|
int i1=(*nusidx)[i];
|
|
|
|
(*vgeom).push_back((*vertpool)[i1]);
|
|
|
|
TextureCoordinate = (*tcs)[i];
|
|
|
|
TextureCoordinate._v[0] = ob.texture_offset_x + TextureCoordinate._v[0] * ob.texture_repeat_x;
|
|
|
|
TextureCoordinate._v[1] = ob.texture_offset_y + TextureCoordinate._v[1] * ob.texture_repeat_y;
|
|
|
|
(*tgeom).push_back(TextureCoordinate);
|
|
|
|
// (*tgeom).push_back((*tcs)[i]);
|
|
|
|
}
|
|
|
|
GLenum poltype=osg::PrimitiveSet::POLYGON;
|
|
|
|
if (asurf.flags & SURFACE_TYPE_CLOSEDLINE) poltype=osg::PrimitiveSet::LINE_LOOP;
|
|
|
|
if (asurf.flags & SURFACE_TYPE_LINE) poltype=osg::PrimitiveSet::LINE_STRIP;
|
|
|
|
geom->addPrimitiveSet(new osg::DrawArrays(poltype,nstart,asurf.num_vertref));
|
|
|
|
if (asurf.flags & 0x10) needSmooth++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (geomlist::iterator itr= glist.begin(); itr<glist.end(); itr++)
|
|
|
|
{
|
|
|
|
osgUtil::Tesselator tesselator;
|
|
|
|
if (*itr) tesselator.retesselatePolygons(**itr);
|
|
|
|
if (needSmooth)
|
|
|
|
{
|
|
|
|
osgUtil::SmoothingVisitor smoother;
|
|
|
|
smoother.smooth(**itr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (streq(t, "kids")) /** 'kids' is the last token in an object **/
|
|
|
|
{
|
|
|
|
int num, n;
|
|
|
|
|
|
|
|
sscanf(buff, "%s %d", t, &num);
|
|
|
|
|
|
|
|
if (num != 0)
|
|
|
|
{
|
|
|
|
// ob.kids = (ACObject **)myalloc(num * sizeof(ACObject *) );
|
|
|
|
ob.num_kids = num;
|
|
|
|
|
|
|
|
for (n = 0; n < num; n++)
|
|
|
|
{
|
|
|
|
osg::Group *k = ac_load_object(f,&ob); //, ob);
|
|
|
|
if (k == NULL)
|
|
|
|
{
|
|
|
|
printf("error reading expected child object %d of %d at line: %d\n", n+1, num, line);
|
|
|
|
return(gp);
|
|
|
|
}
|
2003-11-03 04:10:04 +08:00
|
|
|
else {
|
|
|
|
osg::LightSource *ls=dynamic_cast<osg::LightSource*>(k);
|
|
|
|
if (ls) {
|
|
|
|
osg::StateSet* lightStateSet = gp->getOrCreateStateSet();
|
|
|
|
gp->setStateSet(lightStateSet);
|
|
|
|
gp->setCullingActive(false);
|
|
|
|
ls->setStateSetModes(*lightStateSet,osg::StateAttribute::ON);
|
|
|
|
}
|
|
|
|
|
2003-10-12 23:20:09 +08:00
|
|
|
gp->addChild(k);
|
2003-11-03 04:10:04 +08:00
|
|
|
}
|
2003-10-12 23:20:09 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
if (geode)
|
|
|
|
{
|
|
|
|
osgUtil::Tesselator tesselator;
|
|
|
|
for(unsigned int i=0;i<geode->getNumDrawables();++i)
|
|
|
|
{
|
|
|
|
osg::Geometry* geom = dynamic_cast<osg::Geometry*>(geode->getDrawable(i));
|
|
|
|
if (geom) tesselator.retesselatePolygons(*geom);
|
|
|
|
}
|
|
|
|
}
|
2003-11-03 04:10:04 +08:00
|
|
|
else if (ob.type == OBJECT_LIGHT)
|
|
|
|
{ // add a light source to the scene 1 Nov 2003
|
|
|
|
static int nlight=1;
|
|
|
|
osg::Light* ac3dLight = new osg::Light;
|
|
|
|
ac3dLight->setLightNum(nlight++);
|
|
|
|
ac3dLight->setPosition(osg::Vec4(ob.loc[0],ob.loc[1],ob.loc[2],0.0f));
|
|
|
|
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);
|
|
|
|
ac3dLightSource->setLocalStateSetModes(osg::StateAttribute::ON);
|
|
|
|
|
|
|
|
// for some mad reason, you need to set this so that the light works. WHY?
|
|
|
|
return ac3dLightSource;
|
|
|
|
}
|
2003-10-12 23:20:09 +08:00
|
|
|
return(gp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (geode)
|
|
|
|
{
|
|
|
|
osgUtil::Tesselator tesselator;
|
|
|
|
for(unsigned int i=0;i<geode->getNumDrawables();++i)
|
|
|
|
{
|
|
|
|
osg::Geometry* geom = dynamic_cast<osg::Geometry*>(geode->getDrawable(i));
|
|
|
|
if (geom) tesselator.retesselatePolygons(*geom);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return(gp);
|
2002-10-31 20:51:09 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*void ac_calc_vertex_normals(ACObject *ob)
|
|
|
|
{
|
|
|
|
int n;
|
|
|
|
|
|
|
|
ac_object_calc_vertex_normals(ob);
|
|
|
|
if (ob->num_kids)
|
|
|
|
for (n = 0; n < ob->num_kids; n++)
|
|
|
|
ac_calc_vertex_normals(ob->kids[n]);
|
|
|
|
}*/
|
|
|
|
|
|
|
|
|
|
|
|
osg::Group *ac_load_ac3d(const char *fname)
|
|
|
|
{
|
|
|
|
FILE *f = fopen(fname, "r");
|
|
|
|
|
|
|
|
osg::Group *ret = NULL;
|
|
|
|
|
|
|
|
if (f == NULL)
|
|
|
|
{
|
|
|
|
printf("can't open %s\n", fname);
|
|
|
|
return(NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
read_line(f);
|
|
|
|
|
|
|
|
if (strncmp(buff, "AC3D", 4))
|
|
|
|
{
|
|
|
|
printf("ac_load_ac '%s' is not a valid AC3D file.", fname);
|
|
|
|
fclose(f);
|
|
|
|
return(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-10-12 23:20:09 +08:00
|
|
|
startmatindex = palette.size(); //num_palette;
|
2002-10-31 20:51:09 +08:00
|
|
|
|
|
|
|
|
|
|
|
ret = ac_load_object(f,NULL); //, NULL);
|
|
|
|
|
|
|
|
|
|
|
|
fclose(f);
|
|
|
|
|
|
|
|
// ac_calc_vertex_normals(ret);
|
|
|
|
// here I need to calculate nromals for this object
|
|
|
|
|
|
|
|
return(ret);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void ac_dump(ACObject *ob)
|
|
|
|
{ // not yet finished option ot output AC3D file from OSG scene.
|
|
|
|
int n;
|
|
|
|
|
|
|
|
printf("OBJECT name %s\nloc %f %f %f\nnum_vert %d\nnum_surf %d\n",
|
|
|
|
ob->name, ob->loc[0], ob->loc[1], ob->loc[2], ob->num_vert, ob->num_surf);
|
|
|
|
|
|
|
|
|
|
|
|
// for (n=0; n < ob->num_vert; n++)
|
|
|
|
// printf("\tv %f %f %f\n", ob->vertices[n].x, ob->vertices[n].y, ob->vertices[n].z);
|
|
|
|
|
|
|
|
for (n=0; n < ob->num_surf; n++)
|
|
|
|
{
|
|
|
|
//// ACSurface *s = &ob->surfaces[n];
|
|
|
|
// printf("surface %d, %d refs, mat %d\n", n, s->num_vertref, s->mat);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* this structure not used in OSG
|
|
|
|
if (ob->num_kids)
|
|
|
|
for (n = 0; n < ob->num_kids; n++)
|
|
|
|
ac_dump(ob->kids[n]);
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// now register with osg::Registry to instantiate the above
|
|
|
|
// reader/writer.
|
|
|
|
osgDB::RegisterReaderWriterProxy<ReaderWriterAC> g_readerWriter_AC_Proxy;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|