From Ulrich Hertlein, DirectX .x model loader plugin.

This commit is contained in:
Robert Osfield
2003-01-08 22:52:27 +00:00
parent f91e141e7a
commit ba2c3a187d
9 changed files with 1284 additions and 2 deletions

View File

@@ -0,0 +1,18 @@
#
# $Id$
#
TOPDIR = ../../..
include $(TOPDIR)/Make/makedefs
CXXFILES =\
ReaderWriterDirectX.cpp\
directx.cpp
LIBS += $(OSG_LIBS) $(OTHER_LIBS)
TARGET_BASENAME = x
include $(TOPDIR)/Make/cygwin_plugin_def
PLUGIN = $(PLUGIN_PREFIX)$(TARGET_BASENAME).$(PLUGIN_EXT)
include $(TOPDIR)/Make/makerules

View File

@@ -0,0 +1,295 @@
// -*-c++-*-
/*
* $Id$
*
* DirectX file converter for OpenSceneGraph.
* Copyright (c)2002 Ulrich Hertlein <u.hertlein@sandbox.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "directx.h"
#include <string>
#include <osg/TexEnv>
#include <osg/CullFace>
#include <osg/Geode>
#include <osg/Geometry>
#include <osg/Material>
#include <osg/Image>
#include <osg/Texture2D>
#include <osg/Notify>
#include <osgDB/Registry>
#include <osgDB/ReadFile>
#include <osgDB/FileNameUtils>
/**
* OpenSceneGraph plugin wrapper/converter.
*/
class ReaderWriterDirectX : public osgDB::ReaderWriter
{
public:
ReaderWriterDirectX() { }
virtual const char* className() {
return "DirectX Reader/Writer";
}
virtual bool acceptsExtension(const std::string& extension) {
return osgDB::equalCaseInsensitive(extension,"x") ? true : false;
}
virtual ReadResult readNode(const std::string& fileName,
const osgDB::ReaderWriter::Options* options);
private:
osg::Geode* convertFromDX(DX::Object& obj, bool flipTexture);
};
// Register with Registry to instantiate the above reader/writer.
osgDB::RegisterReaderWriterProxy<ReaderWriterDirectX> g_readerWriter_DirectX_Proxy;
// Read node
osgDB::ReaderWriter::ReadResult ReaderWriterDirectX::readNode(const std::string& fileName,
const osgDB::ReaderWriter::Options* options)
{
std::string ext = osgDB::getLowerCaseFileExtension(fileName);
if (!acceptsExtension(ext))
return ReadResult::FILE_NOT_HANDLED;
osg::notify(osg::INFO) << "ReaderWriterDirectX::readNode(" << fileName.c_str() << ")\n";
// Load DirectX mesh
DX::Object obj;
if (obj.load(fileName.c_str())) {
// Options?
bool flipTexture = true;
if (options) {
const std::string option = options->getOptionString();
cerr << option << endl;
if (option.find("flipTexture") != string::npos)
flipTexture = false;
}
// Convert to osg::Geode
osg::Geode* geode = convertFromDX(obj, flipTexture);
if (!geode)
return ReadResult::FILE_NOT_HANDLED;
return geode;
}
return ReadResult::FILE_NOT_HANDLED;
}
// Convert DirectX mesh to osg::Geode
osg::Geode* ReaderWriterDirectX::convertFromDX(DX::Object& obj, bool flipTexture)
{
// Fetch mesh
const DX::Mesh* mesh = obj.getMesh();
if (!mesh)
return NULL;
const DX::MeshMaterialList* meshMaterial = obj.getMeshMaterialList();
if (!meshMaterial)
return NULL;
const DX::MeshNormals* meshNormals = obj.getMeshNormals();
if (!meshNormals) {
obj.generateNormals();
meshNormals = obj.getMeshNormals();
}
if (!meshNormals)
return NULL;
const DX::MeshTextureCoords* meshTexCoords = obj.getMeshTextureCoords();
if (!meshTexCoords)
return NULL;
/*
* - MeshMaterialList contains a list of Material and a per-face
* information with Material is to be applied to which face.
* - Mesh contains a list of Vertices and a per-face information
* which vertices (three or four) belong to this face.
* - MeshNormals contains a list of Normals and a per-face information
* which normal is used by which vertex.
* - MeshTextureCoords contains a list of per-vertex texture coordinates.
*
* - Uses left-hand CS with Y-up, Z-into
* obj_x -> osg_x
* obj_y -> osg_z
* obj_z -> osg_y
*
* - Polys are CW oriented
*/
vector<osg::Geometry*> geomList;
unsigned int i;
for (i = 0; i < meshMaterial->material.size(); i++) {
const DX::Material& mtl = meshMaterial->material[i];
osg::StateSet* state = new osg::StateSet;
// Material
osg::Material* material = new osg::Material;
state->setAttributeAndModes(material);
float alpha = mtl.faceColor.alpha;
osg::Vec4 ambient(mtl.faceColor.red,
mtl.faceColor.green,
mtl.faceColor.blue,
alpha);
material->setAmbient(osg::Material::FRONT, ambient);
material->setDiffuse(osg::Material::FRONT, ambient);
material->setShininess(osg::Material::FRONT, mtl.power);
osg::Vec4 specular(mtl.specularColor.red,
mtl.specularColor.green,
mtl.specularColor.blue, alpha);
material->setSpecular(osg::Material::FRONT, specular);
osg::Vec4 emissive(mtl.emissiveColor.red,
mtl.emissiveColor.green,
mtl.emissiveColor.blue, alpha);
material->setEmission(osg::Material::FRONT, emissive);
// Transparency? Set render hint & blending
if (alpha < 1.0f) {
state->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
state->setMode(GL_BLEND, osg::StateAttribute::ON);
}
else
state->setMode(GL_BLEND, osg::StateAttribute::OFF);
unsigned int textureCount = mtl.texture.size();
for (unsigned int j = 0; j < textureCount; j++) {
// Load image
osg::Image* image = osgDB::readImageFile(mtl.texture[j]);
if (!image)
continue;
// Texture
osg::Texture2D* texture = new osg::Texture2D;
texture->setImage(image);
texture->setWrap(osg::Texture2D::WRAP_S, osg::Texture2D::REPEAT);
texture->setWrap(osg::Texture2D::WRAP_T, osg::Texture2D::REPEAT);
state->setTextureAttributeAndModes(j, texture);
}
// Geometry
osg::Geometry* geom = new osg::Geometry;
geomList.push_back(geom);
geom->setStateSet(state);
// Arrays to hold vertices, normals, and texcoords.
geom->setVertexArray(new osg::Vec3Array);
geom->setNormalArray(new osg::Vec3Array);
geom->setNormalBinding(osg::Geometry::BIND_PER_VERTEX);
if (textureCount) {
// All texture units share the same array
osg::Vec2Array* texCoords = new osg::Vec2Array;
for (unsigned int j = 0; j < textureCount; j++)
geom->setTexCoordArray(j, texCoords);
}
geom->addPrimitiveSet(new osg::DrawArrayLengths(osg::PrimitiveSet::POLYGON));
}
assert(mesh->faces.size() == meshMaterial->faceIndices.size());
// Add faces to Geometry
for (i = 0; i < meshMaterial->faceIndices.size(); i++) {
// Geometry for Material
unsigned int mi = meshMaterial->faceIndices[i];
osg::Geometry* geom = geomList[mi];
// #pts of this face
unsigned int np = mesh->faces[i].size();
((osg::DrawArrayLengths*) geom->getPrimitiveSet(0))->push_back(np);
assert(np == meshNormals->faceNormals[i].size());
osg::Vec3Array* vertexArray = (osg::Vec3Array*) geom->getVertexArray();
osg::Vec3Array* normalArray = (osg::Vec3Array*) geom->getNormalArray();
osg::Vec2Array* texCoordArray = (osg::Vec2Array*) geom->getTexCoordArray(0);
// Add vertices, normals, texcoords
for (unsigned int j = 0; j < np; j++) {
// Convert CW to CCW order
unsigned int jj = (j > 0 ? np - j : j);
// Vertices
unsigned int vi = mesh->faces[i][jj];
if (vertexArray) {
// Transform Xleft/Yup/Zinto to Xleft/Yinto/Zup
const DX::Vector& v = mesh->vertices[vi];
vertexArray->push_back(osg::Vec3(v.x,v.z,v.y));
}
// Normals
unsigned int ni = meshNormals->faceNormals[i][jj];
if (normalArray) {
// Transform Xleft/Yup/Zinto to Xleft/Yinto/Zup
const DX::Vector& n = meshNormals->normals[ni];
normalArray->push_back(osg::Vec3(n.x,n.z,n.y));
}
// TexCoords
if (texCoordArray) {
const DX::Coords2d& tc = (*meshTexCoords)[vi];
osg::Vec2 uv;
if (flipTexture)
uv.set(tc.u, 1.0f - tc.v); // Image is upside down
else
uv.set(tc.u, tc.v);
texCoordArray->push_back(uv);
}
}
}
// Add non-empty nodes to Geode
osg::Geode* geode = new osg::Geode;
for (i = 0; i < geomList.size(); i++) {
osg::Geometry* geom = geomList[i];
if (((osg::Vec3Array*) geom->getVertexArray())->size())
geode->addDrawable(geom);
}
// Back-face culling
osg::StateSet* state = new osg::StateSet;
geode->setStateSet(state);
osg::CullFace* cullFace = new osg::CullFace;
cullFace->setMode(osg::CullFace::BACK);
state->setAttributeAndModes(cullFace);
/*
* TODO:
* Smooth normals if we previously did a 'generateNormals'?
* (Would create a dependency on osgUtil.)
*/
return geode;
}

View File

@@ -0,0 +1,633 @@
// -*-c++-*-
/*
* $Id$
*
* Loader for DirectX .x files.
* Copyright (c)2002 Ulrich Hertlein <u.hertlein@sandbox.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "directx.h"
#include <iostream>
#include <sstream>
#include <math.h>
#include <assert.h>
using namespace DX;
using namespace std;
// Tokenize a string
void tokenize(const string& str, vector<string>& tokens,
const string& delimiters = " \t\r\n;,")
{
string::size_type lastPos = str.find_first_not_of(delimiters, 0);
string::size_type pos = str.find_first_of(delimiters, lastPos);
while (string::npos != pos || string::npos != lastPos) {
tokens.push_back(str.substr(lastPos, pos - lastPos));
lastPos = str.find_first_not_of(delimiters, pos);
pos = str.find_first_of(delimiters, lastPos);
}
}
// Constructor
Object::Object(const char* filename)
{
_textureCoords = NULL;
_materialList = NULL;
_normals = NULL;
_mesh = NULL;
load(filename);
}
// Destructor
Object::~Object()
{
clear();
}
// Clear object
void Object::clear()
{
if (_textureCoords) {
delete _textureCoords;
_textureCoords = NULL;
}
if (_materialList) {
delete _materialList;
_materialList = NULL;
}
if (_normals) {
delete _normals;
_normals = NULL;
}
if (_mesh) {
delete _mesh;
_mesh = NULL;
}
}
// Load
bool Object::load(const char* filename)
{
if (!filename)
return false;
// Delete previous
clear();
// Open
ifstream fin(filename);
if (fin.bad()) {
cerr << "Object::load: Unable to open: " << filename << endl;
return false;
}
// Parse
parseSection(fin);
fin.close();
return true;
}
/*
* Generate per-face normals
*/
bool Object::generateNormals()
{
if (!_mesh)
return false;
// Forget old normals
if (_normals) {
delete _normals;
_normals = NULL;
}
cerr << "*** GenerateNormals\n";
// Create normals
_normals = new MeshNormals;
// Loop over MeshFaces
unsigned int i, fi;
for (fi = 0; fi < _mesh->faces.size(); fi++) {
// Collect polygon vertices
vector<Vector> poly;
unsigned int n = _mesh->faces[fi].size();
if (n < 3)
continue;
for (i = 0; i < n; i++) {
unsigned int idx = _mesh->faces[fi][i];
poly.push_back(_mesh->vertices[idx]);
}
// Edge vectors
Vector e0;
e0.x = poly[1].x - poly[0].x;
e0.y = poly[1].y - poly[0].y;
e0.z = poly[1].z - poly[0].z;
Vector e1;
e1.x = poly[2].x - poly[0].x;
e1.y = poly[2].y - poly[0].y;
e1.z = poly[2].z - poly[0].z;
// Cross-product of e0,e1
Vector normal;
normal.x = e0.y * e1.z - e0.z * e1.y;
normal.y = e0.z * e1.x - e0.x * e1.z;
normal.z = e0.x * e1.y - e0.y * e1.x;
// Normalize
float len = sqrt(normal.x * normal.x + normal.y * normal.y + normal.z * normal.z);
normal.x /= len;
normal.y /= len;
normal.z /= len;
// Add normal index
unsigned int ni = _normals->normals.size();
_normals->normals.push_back(normal);
// All vertices of this face share this vertex
MeshFace mf;
mf.resize(n);
for (i = 0; i < n; i++)
mf[i] = ni;
_normals->faceNormals.push_back(mf);
}
return true;
}
/**********************************************************************
*
* Private
*
**********************************************************************/
// Read 'TextureFilename'
void Object::readTexFilename(ifstream& fin, TextureFilename& texture)
{
char buf[256];
vector<string> token;
cerr << "*** TexFilename\n";
while (fin.getline(buf, sizeof(buf))) {
// Tokenize
token.clear();
tokenize(buf, token);
if (token.size() == 0)
continue;
if (token[0] == "}")
break;
// Strip " if present
string line = buf;
size_t pos = line.find('"');
if (pos != string::npos) {
size_t end = line.rfind('"');
int len = (end != string::npos ? (end-pos-1) : (line.size()-pos));
texture = line.substr(pos+1, len);
}
else
texture = token[0];
//cerr << "tex=" << texture << endl;
}
}
// Parse 'Material'
void Object::parseMaterial(ifstream& fin, Material& material)
{
char buf[256];
vector<string> token;
unsigned int i = 0;
//cerr << "*** Material\n";
while (fin.getline(buf, sizeof(buf))) {
// Tokenize
token.clear();
tokenize(buf, token);
if (token.size() == 0)
continue;
if (token[0] == "}")
break;
if (token[0] == "TextureFilename") {
TextureFilename tf;
readTexFilename(fin, tf);
material.texture.push_back(tf);
//cerr << "num tex=" << material.texture.size() << endl;
}
else
switch (i) {
case 0: {
// ColorRGBA
material.faceColor.red = atof(token[0].c_str());
material.faceColor.green = atof(token[1].c_str());
material.faceColor.blue = atof(token[2].c_str());
material.faceColor.alpha = atof(token[3].c_str());
i++;
} break;
case 1: {
// Power
material.power = atof(token[0].c_str());
i++;
} break;
case 2: {
// ColorRGB
material.specularColor.red = atof(token[0].c_str());
material.specularColor.green = atof(token[1].c_str());
material.specularColor.blue = atof(token[2].c_str());
i++;
} break;
case 3: {
// ColorRGB
material.emissiveColor.red = atof(token[0].c_str());
material.emissiveColor.green = atof(token[1].c_str());
material.emissiveColor.blue = atof(token[2].c_str());
i++;
} break;
}
}
}
// Read 'Coords2d'
void Object::readCoords2d(ifstream& fin, vector<Coords2d>& v, unsigned int count)
{
char buf[256];
vector<string> token;
unsigned int i = 0;
cerr << "*** Coords2d\n";
while (i < count && fin.getline(buf, sizeof(buf))) {
// Tokenize
token.clear();
tokenize(buf, token);
if (token.size() == 0)
continue;
Coords2d c;
c.u = atof(token[0].c_str());
c.v = atof(token[1].c_str());
v.push_back(c);
i++;
}
}
// Read 'MeshTextureCoords'
void Object::readMeshTexCoords(ifstream& fin)
{
char buf[256];
vector<string> token;
unsigned int nTextureCoords = 0;
cerr << "*** MeshTextureCoords\n";
while (fin.getline(buf, sizeof(buf))) {
// Tokenize
token.clear();
tokenize(buf, token);
if (token.size() == 0)
continue;
if (strrchr(buf, '}') != 0)
break;
// Create MeshTextureCoords
if (!_textureCoords)
_textureCoords = new MeshTextureCoords;
// Texture coords
nTextureCoords = atoi(token[0].c_str());
readCoords2d(fin, *_textureCoords, nTextureCoords);
cerr << "nTextureCoords=" << nTextureCoords << "/" << _textureCoords->size() << endl;
assert(nTextureCoords == _textureCoords->size());
}
}
// Read index list
void Object::readIndexList(ifstream& fin, vector<unsigned int>& v, unsigned int count)
{
char buf[256];
vector<string> token;
unsigned int i = 0;
cerr << "*** IndexList\n";
while (i < count && fin.getline(buf, sizeof(buf))) {
// Tokenize
token.clear();
tokenize(buf, token);
if (token.size() == 0)
continue;
unsigned int idx = atoi(token[0].c_str());
v.push_back(idx);
i++;
}
}
// Parse 'MeshMaterialList'
void Object::parseMeshMaterialList(ifstream& fin)
{
char buf[256];
vector<string> token;
unsigned int nMaterials = 0, nFaceIndices = 0;
cerr << "*** MeshMaterialList\n";
while (fin.getline(buf, sizeof(buf))) {
// Tokenize
token.clear();
tokenize(buf, token);
if (token.size() == 0)
continue;
if (strrchr(buf, '}') != 0)
break;
else if (strrchr(buf, '{') != 0) {
if (token[0] == "Material") {
Material mm;
parseMaterial(fin, mm);
_materialList->material.push_back(mm);
//cerr << "num mat=" << _materialList->material.size() << endl;
}
else {
cerr << "!!! MeshMaterialList: Section " << token[0] << endl;
parseSection(fin);
}
}
else if (nMaterials == 0) {
// Create MeshMaterialList
if (!_materialList)
_materialList = new MeshMaterialList;
// Materials
nMaterials = atoi(token[0].c_str());
//cerr << "nMaterials=" << nMaterials << endl;
}
else if (nFaceIndices == 0) {
// Face indices
nFaceIndices = atoi(token[0].c_str());
readIndexList(fin, _materialList->faceIndices, nFaceIndices);
cerr << "nFaceIndices=" << nFaceIndices << "/" << _materialList->faceIndices.size() << endl;
assert(nFaceIndices == _materialList->faceIndices.size());
}
}
assert(nMaterials == _materialList->material.size());
}
// Read 'Vector'
void Object::readVector(ifstream& fin, vector<Vector>& v, unsigned int count)
{
char buf[256];
vector<string> token;
unsigned int i = 0;
cerr << "*** Vector\n";
while (i < count && fin.getline(buf, sizeof(buf))) {
// Tokenize
token.clear();
tokenize(buf, token);
if (token.size() == 0)
continue;
Vector vec;
vec.x = atof(token[0].c_str());
vec.y = atof(token[1].c_str());
vec.z = atof(token[2].c_str());
v.push_back(vec);
i++;
}
}
// Read 'MeshFace'
void Object::readMeshFace(ifstream& fin, vector<MeshFace>& v, unsigned int count)
{
char buf[256];
vector<string> token;
unsigned int i = 0;
cerr << "*** MeshFace\n";
while (i < count && fin.getline(buf, sizeof(buf))) {
// Tokenize
token.clear();
tokenize(buf, token);
if (token.size() == 0)
continue;
MeshFace mf;
unsigned int n = atoi(token[0].c_str());
for (unsigned int j = 0; j < n; j++) {
unsigned int idx = atoi(token[j+1].c_str());
mf.push_back(idx);
}
v.push_back(mf);
i++;
}
}
// Parse 'MeshNormals'
void Object::parseMeshNormals(ifstream& fin)
{
char buf[256];
vector<string> token;
unsigned int nNormals = 0, nFaceNormals = 0;
cerr << "*** MeshNormals\n";
while (fin.getline(buf, sizeof(buf))) {
// Tokenize
token.clear();
tokenize(buf, token);
if (token.size() == 0)
continue;
if (strrchr(buf, '}') != 0)
break;
else if (nNormals == 0) {
// Create MeshNormals
if (!_normals)
_normals = new MeshNormals;
// Normals
nNormals = atoi(token[0].c_str());
readVector(fin, _normals->normals, nNormals);
cerr << "nNormals=" << nNormals << "/" << _normals->normals.size() << endl;
#ifdef NORMALIZE_NORMALS
for (unsigned int i = 0; i < _normals->normals.size(); i++) {
DX::Vector vec = _normals->normals[i];
// Normalize
float len = sqrt(vec.x * vec.x + vec.y * vec.y + vec.z * vec.z);
vec.x /= len;
vec.y /= len;
vec.z /= len;
_normals->normals[i] = vec;
}
#endif
assert(nNormals == _normals->normals.size());
}
else if (nFaceNormals == 0) {
// Face normals
nFaceNormals = atoi(token[0].c_str());
readMeshFace(fin, _normals->faceNormals, nFaceNormals);
cerr << "nFaceNormals=" << nFaceNormals << "/" << _normals->faceNormals.size() << endl;
assert(nFaceNormals == _normals->faceNormals.size());
}
}
}
// Parse 'Mesh'
void Object::parseMesh(ifstream& fin)
{
char buf[256];
vector<string> token;
unsigned int nVertices = 0, nFaces = 0;
cerr << "*** Mesh\n";
while (fin.getline(buf, sizeof(buf))) {
// Tokenize
token.clear();
tokenize(buf, token);
if (token.size() == 0)
continue;
if (strrchr(buf, '}') != 0) {
break;
}
else if (strrchr(buf, '{') != 0) {
if (token[0] == "MeshMaterialList")
parseMeshMaterialList(fin);
else if (token[0] == "MeshNormals")
parseMeshNormals(fin);
else if (token[0] == "MeshTextureCoords")
readMeshTexCoords(fin);
else {
cerr << "!!! Mesh: Section " << token[0] << endl;
parseSection(fin);
}
}
else if (nVertices == 0) {
// Create mesh
if (!_mesh)
_mesh = new Mesh;
// Vertices
nVertices = atoi(token[0].c_str());
readVector(fin, _mesh->vertices, nVertices);
cerr << "nVertices=" << nVertices << "/" << _mesh->vertices.size() << endl;
assert(nVertices == _mesh->vertices.size());
}
else if (nFaces == 0) {
// Faces
nFaces = atoi(token[0].c_str());
readMeshFace(fin, _mesh->faces, nFaces);
cerr << "nFaces=" << nFaces << "/" << _mesh->faces.size() << endl;
assert(nFaces == _mesh->faces.size());
}
else
cerr << "!!! " << buf << endl;
}
}
// Parse section
void Object::parseSection(ifstream& fin)
{
char buf[256];
vector<string> token;
while (fin.getline(buf, sizeof(buf))) {
if (strrchr(buf, '}') != 0) {
//cerr << "!!! End section\n";
break;
}
else if (strrchr(buf, '{') != 0) {
// Tokenize
token.clear();
tokenize(buf, token);
if (token.size() == 0)
continue;
//cerr << "!!! Section " << token[0] << endl;
if (token[0] == "Mesh")
parseMesh(fin);
else
parseSection(fin);
}
}
}

View File

@@ -0,0 +1,195 @@
// -*-c++-*-
/*
* $Id$
*
* Loader for DirectX .x files.
* Copyright (c)2002 Ulrich Hertlein <u.hertlein@sandbox.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _DIRECTX_H_
#define _DIRECTX_H_
#include <string>
#include <vector>
#include <fstream>
namespace DX {
/*
* DirectX templates
* http://astronomy.swin.edu.au/~pbourke/geomformats/directx/
*/
// Vector
typedef struct {
float x,y,z;
} Vector;
// Coords2d
typedef struct {
float u,v;
} Coords2d;
// ColorRGBA
typedef struct {
float red,green,blue,alpha;
} ColorRGBA;
// ColorRGB
typedef struct {
float red,green,blue;
} ColorRGB;
// IndexedColor
typedef struct {
unsigned int index;
ColorRGBA indexColor;
} IndexedColor;
// TextureFilename
typedef std::string TextureFilename;
// Material (potentially with multiple textures)
typedef struct {
ColorRGBA faceColor;
float power;
ColorRGB specularColor;
ColorRGB emissiveColor;
std::vector<TextureFilename> texture;
} Material;
// MeshFace
typedef std::vector<unsigned int> MeshFace;
// MeshTextureCoords
typedef std::vector<Coords2d> MeshTextureCoords;
// MeshNormals
typedef struct {
std::vector<Vector> normals;
std::vector<MeshFace> faceNormals;
} MeshNormals;
// MeshVertexColors.
typedef std::vector<IndexedColor> MeshVertexColors;
// MeshMaterialList
typedef struct {
std::vector<unsigned int> faceIndices;
std::vector<Material> material;
} MeshMaterialList;
// Mesh
typedef struct {
std::vector<Vector> vertices;
std::vector<MeshFace> faces;
} Mesh;
/**
* DirectX object.
*/
class Object {
public:
/// Constructor; loads filename if non-NULL.
Object(const char* filename = NULL);
/// Destructor.
virtual ~Object();
/// Load from file; discards old data.
bool load(const char* filename);
/**
* Generate normals.
* This function generates face normals and binds them to
* every vertex of this face.
*/
bool generateNormals();
/// Get MeshTextureCoords.
inline const MeshTextureCoords* getMeshTextureCoords() const {
return _textureCoords;
}
/// Get MeshMaterialList.
inline const MeshMaterialList* getMeshMaterialList() const {
return _materialList;
}
/// Get MeshNormals.
inline const MeshNormals* getMeshNormals() const {
return _normals;
}
/// Get Mesh.
inline const Mesh* getMesh() const {
return _mesh;
}
private:
/// Texture coordinates (per-vertex).
MeshTextureCoords* _textureCoords;
/// Material list (per-face).
MeshMaterialList* _materialList;
/// Normals (per-face).
MeshNormals* _normals;
/// Mesh.
Mesh* _mesh;
/// Clear object.
void clear();
/// Read 'TextureFilename'.
void readTexFilename(std::ifstream& fin, TextureFilename& texture);
/// Parse 'Material'.
void parseMaterial(std::ifstream& fin, Material& material);
/// Read 'Coords2d'.
void readCoords2d(std::ifstream& fin, std::vector<Coords2d>& v, unsigned int count);
/// Read 'MeshTextureCoords'.
void readMeshTexCoords(std::ifstream& fin);
/// Read index list.
void readIndexList(ifstream& fin, std::vector<unsigned int>& v, unsigned int count);
/// Parse 'MeshMaterialList'.
void parseMeshMaterialList(std::ifstream& fin);
/// Read 'Vector'.
void readVector(ifstream& fin, std::vector<Vector>& v, unsigned int count);
/// Read 'MeshFace'.
void readMeshFace(ifstream& fin, std::vector<MeshFace>& v, unsigned int count);
/// Parse 'MeshNormals'.
void parseMeshNormals(std::ifstream& fin);
/// Parse 'Mesh'.
void parseMesh(std::ifstream& fin);
/// Parse section until '}'; recurse as needed.
void parseSection(std::ifstream& fin);
};
} // namespace
#endif