From Ulrich Hertlein, DirectX .x model loader plugin.
This commit is contained in:
parent
f91e141e7a
commit
ba2c3a187d
2
AUTHORS
2
AUTHORS
@ -64,7 +64,7 @@ Ulrich Hertlein <u.hertlein@bit-side.com>
|
||||
- support for texture subloading in osg::Texture
|
||||
- osg::Sequence support.
|
||||
- improvements to the pfb loader.
|
||||
- .lwo and .obj plugins.
|
||||
- .lwo, .obj and .x (DirectX model) plugins.
|
||||
|
||||
Axel Volley <volley@acm.org>
|
||||
- support for OBJECT_LINEAR and EYE_LINEAR TexGen modes.
|
||||
|
@ -29,6 +29,7 @@ PLUGIN_DIRS = \
|
||||
rgb\
|
||||
ac3d\
|
||||
lib3ds\
|
||||
directx\
|
||||
flt\
|
||||
geo\
|
||||
iv\
|
||||
|
7
NEWS
7
NEWS
@ -1,4 +1,5 @@
|
||||
|
||||
|
||||
OSG News (most significant items from ChangeLog)
|
||||
================================================
|
||||
|
||||
@ -29,12 +30,16 @@ OSG News (most significant items from ChangeLog)
|
||||
|
||||
Support added for reading and writing of callbacks in the .osg format.
|
||||
|
||||
Support added for reading and writing of osg::Shapes in the .osg format.
|
||||
|
||||
Support added for reading OpenFlight comment records into osg::Node description
|
||||
fields.
|
||||
|
||||
Improvements to the GEO loaders.
|
||||
|
||||
Support for encoded text types in osgText.
|
||||
From Tree, Support for encoded text types in osgText.
|
||||
|
||||
From Ulrich Hertlein, new DirectX .x model loader.
|
||||
|
||||
|
||||
13th November 2002 - OpenSceneGraph-0.9.2.tar.gz
|
||||
|
@ -1398,6 +1398,24 @@ Package=<4>
|
||||
|
||||
###############################################################################
|
||||
|
||||
Project: "osgPlugin directx"=.\osgPlugins\directx\directx.dsp - Package Owner=<4>
|
||||
|
||||
Package=<5>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
Package=<4>
|
||||
{{{
|
||||
Begin Project Dependency
|
||||
Project_Dep_Name Core osg
|
||||
End Project Dependency
|
||||
Begin Project Dependency
|
||||
Project_Dep_Name Core osgDB
|
||||
End Project Dependency
|
||||
}}}
|
||||
|
||||
###############################################################################
|
||||
|
||||
Project: "osgPlugin osg"=.\osgPlugins\osg\dot_osg.dsp - Package Owner=<4>
|
||||
|
||||
Package=<5>
|
||||
|
117
VisualStudio/osgPlugins/directx/directx.dsp
Normal file
117
VisualStudio/osgPlugins/directx/directx.dsp
Normal file
@ -0,0 +1,117 @@
|
||||
# Microsoft Developer Studio Project File - Name="osgPlugin directx" - Package Owner=<4>
|
||||
# Microsoft Developer Studio Generated Build File, Format Version 6.00
|
||||
# ** DO NOT EDIT **
|
||||
|
||||
# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
|
||||
|
||||
CFG=osgPlugin directx - Win32 Release
|
||||
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
|
||||
!MESSAGE use the Export Makefile command and run
|
||||
!MESSAGE
|
||||
!MESSAGE NMAKE /f "directx.mak".
|
||||
!MESSAGE
|
||||
!MESSAGE You can specify a configuration when running NMAKE
|
||||
!MESSAGE by defining the macro CFG on the command line. For example:
|
||||
!MESSAGE
|
||||
!MESSAGE NMAKE /f "directx.mak" CFG="osgPlugin directx - Win32 Release"
|
||||
!MESSAGE
|
||||
!MESSAGE Possible choices for configuration are:
|
||||
!MESSAGE
|
||||
!MESSAGE "osgPlugin directx - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
|
||||
!MESSAGE "osgPlugin directx - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
|
||||
!MESSAGE
|
||||
|
||||
# Begin Project
|
||||
# PROP AllowPerConfigDependencies 0
|
||||
# PROP Scc_ProjName ""
|
||||
# PROP Scc_LocalPath ""
|
||||
CPP=cl.exe
|
||||
MTL=midl.exe
|
||||
RSC=rc.exe
|
||||
|
||||
!IF "$(CFG)" == "osgPlugin directx - Win32 Release"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 0
|
||||
# PROP BASE Output_Dir "Release"
|
||||
# PROP BASE Intermediate_Dir "Release"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 0
|
||||
# PROP Output_Dir "../../../lib"
|
||||
# PROP Intermediate_Dir "Release"
|
||||
# PROP Ignore_Export_Lib 0
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /YX /FD /c
|
||||
# ADD CPP /nologo /MD /W3 /GR /GX /O2 /I "../../../include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /YX /FD /c
|
||||
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
|
||||
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
|
||||
# ADD BASE RSC /l 0x809 /d "NDEBUG"
|
||||
# ADD RSC /l 0x809 /d "NDEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
LINK32=link.exe
|
||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
|
||||
# ADD LINK32 /nologo /dll /pdb:none /machine:I386 /nodefaultlib:"LIBC" /out:"../../../bin/osgdb_x.dll" /libpath:"../../../lib"
|
||||
# SUBTRACT LINK32 /nodefaultlib
|
||||
|
||||
!ELSEIF "$(CFG)" == "osgPlugin directx - Win32 Debug"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 1
|
||||
# PROP BASE Output_Dir "Debug"
|
||||
# PROP BASE Intermediate_Dir "Debug"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 1
|
||||
# PROP Output_Dir "../../../lib"
|
||||
# PROP Intermediate_Dir "Debug"
|
||||
# PROP Ignore_Export_Lib 0
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /YX /FD /GZ /c
|
||||
# ADD CPP /nologo /MDd /W3 /Gm /vmg /vd0 /GR /GX /Zi /Od /I "../../../include" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "WIN32" /D "_DEBUG" /YX /FD /GZ /c
|
||||
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
|
||||
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
|
||||
# ADD BASE RSC /l 0x809 /d "_DEBUG"
|
||||
# ADD RSC /l 0x809 /d "_DEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
LINK32=link.exe
|
||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
|
||||
# ADD LINK32 /nologo /dll /debug /machine:I386 /nodefaultlib:"LIBC" /out:"../../../bin/osgdb_xd.dll" /pdbtype:sept /libpath:"../../../lib"
|
||||
# SUBTRACT LINK32 /nodefaultlib
|
||||
|
||||
!ENDIF
|
||||
|
||||
# Begin Target
|
||||
|
||||
# Name "osgPlugin directx - Win32 Release"
|
||||
# Name "osgPlugin directx - Win32 Debug"
|
||||
# Begin Group "Source Files"
|
||||
|
||||
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\..\src\osgPlugins\directx\directx.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\..\src\osgPlugins\directx\ReaderWriterDirectX.cpp
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "Header Files"
|
||||
|
||||
# PROP Default_Filter "h;hpp;hxx;hm;inl"
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\..\Src\osgPlugins\directx\directx.h
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "Resource Files"
|
||||
|
||||
# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
|
||||
# End Group
|
||||
# End Target
|
||||
# End Project
|
18
src/osgPlugins/directx/Makefile
Normal file
18
src/osgPlugins/directx/Makefile
Normal 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
|
295
src/osgPlugins/directx/ReaderWriterDirectX.cpp
Normal file
295
src/osgPlugins/directx/ReaderWriterDirectX.cpp
Normal 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;
|
||||
}
|
633
src/osgPlugins/directx/directx.cpp
Normal file
633
src/osgPlugins/directx/directx.cpp
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
195
src/osgPlugins/directx/directx.h
Normal file
195
src/osgPlugins/directx/directx.h
Normal 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
|
Loading…
Reference in New Issue
Block a user