Hi,
here's a simple class that lets you create AC3D .ac files. The input is generated as if you were draing the model/world with OpenGL. So, if you can draw it, now you can save it
It's just a header in std C++, so it should compile pretty much anywhere.
Code:
#ifndef AC3D_H_INC
#define AC3D_H_INC
// a AC3D export/creation class
// very handy for exporting 3D data from anywhere.
// Written by Gernot Frisch : www.glbasic.com
// this file is public domain, do whatever you want with it.
#if 0
useage:
GF_AC3D ac3d;
// texture if you want some
ac3d.glBindTexture("test.bmp");
// new "object"
ac3d.glBegin(GL_TRIANGLE_STIP); // all OpenGL modes supported!
// surfaces
ac3d.glColor(); // color
ac3d.glTexCoo();// texture coordiante
ac3d.glVertex();// vertex position
...
ac3d.glEnd(); // end + store object
ac3d.Write("out.ac"); // save world
ac3d.clear();
#endif
// VC6 gives funny warnings ;)
#pragma warning(disable:4710)
#pragma warning(disable:4100)
#pragma warning(disable:4786)
#include <vector>
#include <string>
#include <fstream>
#include <map>
class GF_AC3D
{
public:
void clear()
{
m_cur_col = COLO();
m_cur_uv[0]=0; m_cur_uv[1] = 0;
m_gl_texname="";
m_gl_nodes.clear();
m_objects.clear();
}
bool Write(const char* filename)
{
std::ofstream os(filename);
if(!os.good()) return false;
os << "AC3Db" << std::endl;
int o;
std::map<COLO> mats;
int ncolo=0;
for(o=0; o<(int)m_objects.size(); ++o)
{
OBJ& ob = m_objects[o];
if(mats.find(ob.rgb) == mats.end() )
mats[ob.rgb] = ncolo++;
}
for(std::map<COLO>::iterator it = mats.begin(); it!=mats.end(); ++it)
{
const COLO& ob = it->first;
os << "MATERIAL \"\" rgb " <<ob.r<<" " <<ob.g<<" "<<ob.b<<" amb 0.2 0.2 0.2 emis 0 0 0 spec 0.5 0.5 0.5 shi 10 trans 0"<<std::endl;
}
os << "OBJECT world" << std::endl;
os << "kids "<< (int)m_objects.size()<< std::endl;
for(o=0; o<(int)m_objects.size(); ++o)
{
OBJ& ob = m_objects[o];
os << "OBJECT poly" << std::endl;
if (ob.texture.length())
{
os << "texture " << ob.texture << std::endl;
}
os << "numvert " << ob.triangles.size() * 3 << std::endl;
int i;
char tmp[1024];
for(i=0; i<(int)ob.triangles.size(); ++i)
{
for(int j=0; j<3; ++j)
{
sprintf(tmp, "%.2f %.2f %.2f", ob.triangles[i].nodes[j].pos[0], ob.triangles[i].nodes[j].pos[1],ob.triangles[i].nodes[j].pos[2]);
os << tmp <<std::endl;
}
}
os << "numsurf " << ob.triangles.size() << std::endl;
for(i=0; i<(int)ob.triangles.size(); ++i)
{
os << "SURF 0x20" <<std::endl;
os << "mat " << (int)mats[ob.rgb] << std::endl;
os << "refs 3"<< std::endl;
int first = i*3;
for(int j=0; j<3; ++j)
{
os << (first+j) << " " << ob.triangles[i].nodes[j].uv[0] << " " << ob.triangles[i].nodes[j].uv[1] << std::endl;
}
}
os << "kids 0"<< std::endl;
}
return true;
}
class COLO
{
public:
COLO() {r=g=b=1.0f;}
COLO(const COLO& c) {*this = c;}
COLO& operator=(const COLO& c) {r=c.r; g=c.g; b=c.b;return *this;}
bool operator<(const COLO& c) const {return r*100000+g*1000+b < c.r*100000+c.g*1000+c.b ? true:false;}
float r,g,b;
};
class NODE
{
public:
NODE() {pos[0]=pos[1]=pos[2]=0; uv[0]=uv[1]=0;}
NODE(const NODE& t) {*this = t;}
NODE& operator=(const NODE& t) {pos[0]=t.pos[0]; pos[1]=t.pos[1]; pos[2]=t.pos[2]; uv[0]=t.uv[0]; uv[1]=t.uv[1]; return *this;}
float pos[3];
float uv[2];
};
class TRI
{
public:
TRI() {}
TRI(const TRI& t) {*this = t;}
TRI& operator=(const TRI& t) {nodes[0]=t.nodes[0]; nodes[1]=t.nodes[1]; nodes[2]=t.nodes[2]; return *this;}
NODE nodes[3];
};
class OBJ
{
public:
OBJ() {imat=0;}
OBJ(const OBJ& o){*this=o;}
OBJ& operator=(const OBJ& o) {rgb=o.rgb; triangles=o.triangles; texture = o.texture; return *this;}
COLO rgb;
int imat;
std::vector<TRI> triangles;
std::string texture;
};
std::vector<OBJ> m_objects;
// OpenGL-Style Interface
int m_glmode;
COLO m_cur_col;
std::vector<NODE> m_gl_nodes;
float m_cur_uv[2];
std::string m_gl_texname;
bool m_gl_good;
void glBindTexture(const char* filename)
{
m_gl_texname=filename;
}
void glColor(float r, float g, float b)
{
m_cur_col.r = r; m_cur_col.g=g; m_cur_col.b = b;
}
void glBegin(int mode)
{
m_gl_good=true;
m_glmode = mode;
}
void glTexCoo(float u, float v)
{
m_cur_uv[0] = u; m_cur_uv[1]=v;
}
void glVertex(float x, float y, float z)
{
#define GF_GL_MAX 10000
if(x>GF_GL_MAX || y>GF_GL_MAX || z>GF_GL_MAX || x<-GF_GL_MAX || y<-GF_GL_MAX || z<-GF_GL_MAX)
{
m_gl_good=false;
}
else
{
NODE n;
n.pos[0] = x; n.pos[1] = y; n.pos[2] = z;
n.uv[0] = m_cur_uv[0]; n.uv[1] = m_cur_uv[1];
m_gl_nodes.push_back(n);
}
}
void glEnd()
{
#define GF_GL_POINTS 0x0000
#define GF_GL_LINES 0x0001
#define GF_GL_LINE_LOOP 0x0002
#define GF_GL_LINE_STRIP 0x0003
#define GF_GL_TRIANGLES 0x0004
#define GF_GL_TRIANGLE_STRIP 0x0005
#define GF_GL_TRIANGLE_FAN 0x0006
#define GF_GL_QUADS 0x0007
#define GF_GL_QUAD_STRIP 0x0008
#define GF_GL_POLYGON 0x0009
OBJ o;
int num_tri=0;
switch(m_glmode)
{
case GF_GL_TRIANGLES:
num_tri = m_gl_nodes.size()/3; break;
case GF_GL_TRIANGLE_STRIP:
num_tri = m_gl_nodes.size()-2; break;
case GF_GL_TRIANGLE_FAN:
case GF_GL_POLYGON:
num_tri = m_gl_nodes.size()-2; break;
// case GF_GL_QUADS:
// num_tri = (m_gl_nodes.size()/4) * 2; break;
}
if(num_tri && m_gl_good)
{
for(int n=0; n<num_tri; ++n)
{
int a,b,c;
switch(m_glmode)
{
case GF_GL_TRIANGLES:
a=3*n+2; b=3*n+1; c=3*n; break;
case GF_GL_TRIANGLE_STRIP:
if(n%2)
{
a=n+1; b=n; c=n+2;
}
else
{
a=n; b=n+1; c=n+2;
}
break;
case GF_GL_TRIANGLE_FAN:
case GF_GL_POLYGON:
a=0; b=n+1; c=n+2;
break;
case GF_GL_QUADS:
if(n%2)
{
a=4*n; b=4*n-1; c=4*n;
}
else
{
a=3+4*n; b=3+4*n-3; c=3+4*n-1;
}
break;
}
TRI t;
t.nodes[0] = m_gl_nodes[a];
t.nodes[1] = m_gl_nodes[b];
t.nodes[2] = m_gl_nodes[c];
NODE n1, n2, n3;
n1 = m_gl_nodes[a];
n2 = m_gl_nodes[b];
n3 = m_gl_nodes[c];
o.triangles.push_back(t);
}
o.texture = m_gl_texname;
o.rgb=m_cur_col;
m_objects.push_back(o);
}
m_gl_nodes.clear();
}
};
#endif // AC3D_H_INC