From Marco Jez, updates to the LWO loader.

This commit is contained in:
Robert Osfield
2004-01-03 15:20:33 +00:00
parent 249eddb3d8
commit c0f2730d99
34 changed files with 4686 additions and 21 deletions

View File

@@ -53,7 +53,7 @@ BSC32=bscmake.exe
# 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_lwo.dll" /libpath:"../../../lib"
# ADD LINK32 glu32.lib /nologo /dll /pdb:none /machine:I386 /nodefaultlib:"LIBC" /out:"../../../bin/osgdb_lwo.dll" /libpath:"../../../lib"
# SUBTRACT LINK32 /nodefaultlib
!ELSEIF "$(CFG)" == "osgPlugin lwo - Win32 Debug"
@@ -80,7 +80,7 @@ BSC32=bscmake.exe
# 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_lwod.dll" /pdbtype:sept /libpath:"../../../lib"
# ADD LINK32 glu32.lib /nologo /dll /debug /machine:I386 /nodefaultlib:"LIBC" /out:"../../../bin/osgdb_lwod.dll" /pdbtype:sept /libpath:"../../../lib"
# SUBTRACT LINK32 /pdb:none
!ENDIF
@@ -94,36 +94,136 @@ LINK32=link.exe
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
# Begin Source File
SOURCE=..\..\..\src\osgPlugins\lwo\lw.cpp
SOURCE=..\..\..\src\osgPlugins\lwo\Block.cpp
# End Source File
# Begin Source File
SOURCE=..\..\..\src\osgPlugins\lwo\Clip.cpp
# End Source File
# Begin Source File
SOURCE=..\..\..\src\osgPlugins\lwo\Converter.cpp
# End Source File
# Begin Source File
SOURCE=..\..\..\src\osgPlugins\lwo\Object.cpp
# End Source File
# Begin Source File
SOURCE=..\..\..\src\osgPlugins\lwo\Polygon.cpp
# End Source File
# Begin Source File
SOURCE=..\..\..\src\osgPlugins\lwo\Surface.cpp
# End Source File
# Begin Source File
SOURCE=..\..\..\src\osgPlugins\lwo\Tessellator.cpp
# End Source File
# Begin Source File
SOURCE=..\..\..\src\osgPlugins\lwo\Unit.cpp
# End Source File
# Begin Source File
SOURCE=..\..\..\src\osgPlugins\lwo\VertexMap.cpp
# End Source File
# Begin Source File
SOURCE=..\..\..\src\osgPlugins\lwo\ReaderWriterLWO.cpp
# End Source File
# Begin Source File
SOURCE=..\..\..\src\osgPlugins\lwo\Lwo2.cpp
SOURCE=..\..\..\src\osgPlugins\lwo\old_lw.cpp
# End Source File
# Begin Source File
SOURCE=..\..\..\src\osgPlugins\lwo\Lwo2Layer.cpp
SOURCE=..\..\..\src\osgPlugins\lwo\old_Lwo2.cpp
# End Source File
# Begin Source File
SOURCE=..\..\..\src\osgPlugins\lwo\old_Lwo2Layer.cpp
# End Source File
# End Group
# Begin Group "Header Files"
# PROP Default_Filter ""
# Begin Source File
SOURCE=..\..\..\Src\osgPlugins\lwo\lw.h
SOURCE=..\..\..\Src\osgPlugins\lwo\Block.h
# End Source File
# Begin Source File
SOURCE=..\..\..\Src\osgPlugins\lwo\Lwo2Layer.h
SOURCE=..\..\..\Src\osgPlugins\lwo\Clip.h
# End Source File
# Begin Source File
SOURCE=..\..\..\Src\osgPlugins\lwo\Lwo2.h
SOURCE=..\..\..\Src\osgPlugins\lwo\Converter.h
# End Source File
# Begin Source File
SOURCE=..\..\..\Src\osgPlugins\lwo\iffparser.h
# End Source File
# Begin Source File
SOURCE=..\..\..\Src\osgPlugins\lwo\Layer.h
# End Source File
# Begin Source File
SOURCE=..\..\..\Src\osgPlugins\lwo\lwo2chunks.h
# End Source File
# Begin Source File
SOURCE=..\..\..\Src\osgPlugins\lwo\lwo2parser.h
# End Source File
# Begin Source File
SOURCE=..\..\..\Src\osgPlugins\lwo\lwo2read.h
# End Source File
# Begin Source File
SOURCE=..\..\..\Src\osgPlugins\lwo\lwo2types.h
# End Source File
# Begin Source File
SOURCE=..\..\..\Src\osgPlugins\lwo\Object.h
# End Source File
# Begin Source File
SOURCE=..\..\..\Src\osgPlugins\lwo\Polygon.h
# End Source File
# Begin Source File
SOURCE=..\..\..\Src\osgPlugins\lwo\Surface.h
# End Source File
# Begin Source File
SOURCE=..\..\..\Src\osgPlugins\lwo\Tessellator.h
# End Source File
# Begin Source File
SOURCE=..\..\..\Src\osgPlugins\lwo\Unit.h
# End Source File
# Begin Source File
SOURCE=..\..\..\Src\osgPlugins\lwo\VertexMap.h
# End Source File
# Begin Source File
SOURCE=..\..\..\Src\osgPlugins\lwo\old_lw.h
# End Source File
# Begin Source File
SOURCE=..\..\..\Src\osgPlugins\lwo\old_Lwo2Layer.h
# End Source File
# Begin Source File
SOURCE=..\..\..\Src\osgPlugins\lwo\old_Lwo2.h
# End Source File
# End Group
# End Target
# Begin Group "Header Files No. 1"

View File

@@ -0,0 +1,147 @@
/*******************************************************
Lightwave Object Loader for OSG
Copyright (C) 2004 Marco Jez <marco.jez@poste.it>
OpenSceneGraph is (C) 2004 Robert Osfield
********************************************************/
#include "Block.h"
#include <osg/Notify>
#include <osg/Matrix>
using namespace lwosg;
Block::Block(const lwo2::FORM::SURF::BLOK *blok)
: enabled_(true),
opacity_type_(ADDITIVE),
opacity_amount_(1)
{
if (blok) {
compile(blok);
}
}
void Block::read_common_attributes(const iff::Chunk_list &subchunks)
{
for (iff::Chunk_list::const_iterator i=subchunks.begin(); i!=subchunks.end(); ++i) {
const lwo2::FORM::SURF::BLOK::CHAN *chan = dynamic_cast<const lwo2::FORM::SURF::BLOK::CHAN *>(*i);
if (chan) {
channel_ = std::string(chan->texture_channel.id, 4);
}
const lwo2::FORM::SURF::BLOK::ENAB *enab = dynamic_cast<const lwo2::FORM::SURF::BLOK::ENAB *>(*i);
if (enab) {
enabled_ = enab->enable != 0;
}
const lwo2::FORM::SURF::BLOK::OPAC *opac = dynamic_cast<const lwo2::FORM::SURF::BLOK::OPAC *>(*i);
if (opac) {
opacity_type_ = static_cast<Opacity_type>(opac->type);
opacity_amount_ = opac->opacity.fraction;
}
const lwo2::FORM::SURF::BLOK::AXIS *axis = dynamic_cast<const lwo2::FORM::SURF::BLOK::AXIS *>(*i);
if (axis) {
displacement_axis_ = static_cast<Axis_type>(axis->displacement_axis);
}
}
}
void Block::compile(const lwo2::FORM::SURF::BLOK *blok)
{
const lwo2::FORM::SURF::BLOK::IMAP *imap = dynamic_cast<const lwo2::FORM::SURF::BLOK::IMAP *>(blok->header);
if (imap) {
type_ = "IMAP";
ordinal_ = imap->ordinal;
// read common parameters
read_common_attributes(imap->block_attributes);
// read imagemap-related attributes
for (iff::Chunk_list::const_iterator i=blok->attributes.begin(); i!=blok->attributes.end(); ++i) {
const lwo2::FORM::SURF::BLOK::IMAP::TMAP *tmap = dynamic_cast<const lwo2::FORM::SURF::BLOK::IMAP::TMAP *>(*i);
if (tmap) {
Texture_mapping mapping;
for (iff::Chunk_list::const_iterator i=tmap->attributes.begin(); i!=tmap->attributes.end(); ++i) {
const lwo2::FORM::SURF::BLOK::IMAP::TMAP::CNTR *cntr = dynamic_cast<const lwo2::FORM::SURF::BLOK::IMAP::TMAP::CNTR *>(*i);
if (cntr) {
mapping.center_ = osg::Vec3(cntr->vector.X, cntr->vector.Y, cntr->vector.Z);
}
const lwo2::FORM::SURF::BLOK::IMAP::TMAP::SIZE *size = dynamic_cast<const lwo2::FORM::SURF::BLOK::IMAP::TMAP::SIZE *>(*i);
if (size) {
mapping.size_ = osg::Vec3(size->vector.X, size->vector.Y, size->vector.Z);
}
const lwo2::FORM::SURF::BLOK::IMAP::TMAP::ROTA *rota = dynamic_cast<const lwo2::FORM::SURF::BLOK::IMAP::TMAP::ROTA *>(*i);
if (rota) {
mapping.rotation_ = osg::Vec3(rota->vector.X, rota->vector.Y, rota->vector.Z);
}
const lwo2::FORM::SURF::BLOK::IMAP::TMAP::CSYS *csys = dynamic_cast<const lwo2::FORM::SURF::BLOK::IMAP::TMAP::CSYS *>(*i);
if (csys) {
mapping.csys_ = static_cast<Texture_mapping::Coordinate_system_type>(csys->type);
}
}
imap_.mapping = mapping;
}
const lwo2::FORM::SURF::BLOK::IMAP::PROJ *proj = dynamic_cast<const lwo2::FORM::SURF::BLOK::IMAP::PROJ *>(*i);
if (proj) {
imap_.projection = static_cast<Image_map::Projection_mode>(proj->projection_mode);
}
const lwo2::FORM::SURF::BLOK::IMAP::AXIS *axis = dynamic_cast<const lwo2::FORM::SURF::BLOK::IMAP::AXIS *>(*i);
if (axis) {
imap_.axis = static_cast<Image_map::Axis_type>(axis->texture_axis);
}
const lwo2::FORM::SURF::BLOK::IMAP::IMAG *imag = dynamic_cast<const lwo2::FORM::SURF::BLOK::IMAP::IMAG *>(*i);
if (imag) {
imap_.image_map = imag->texture_image.index;
}
const lwo2::FORM::SURF::BLOK::IMAP::WRAP *wrap = dynamic_cast<const lwo2::FORM::SURF::BLOK::IMAP::WRAP *>(*i);
if (wrap) {
imap_.width_wrap = static_cast<Image_map::Wrap_type>(wrap->width_wrap);
imap_.height_wrap = static_cast<Image_map::Wrap_type>(wrap->height_wrap);
}
const lwo2::FORM::SURF::BLOK::IMAP::WRPW *wrpw = dynamic_cast<const lwo2::FORM::SURF::BLOK::IMAP::WRPW *>(*i);
if (wrpw) {
imap_.wrap_amount_w = wrpw->cycles.fraction;
}
const lwo2::FORM::SURF::BLOK::IMAP::WRPH *wrph = dynamic_cast<const lwo2::FORM::SURF::BLOK::IMAP::WRPH *>(*i);
if (wrph) {
imap_.wrap_amount_h = wrph->cycles.fraction;
}
const lwo2::FORM::SURF::BLOK::IMAP::VMAP *vmap = dynamic_cast<const lwo2::FORM::SURF::BLOK::IMAP::VMAP *>(*i);
if (vmap) {
imap_.uv_map = vmap->txuv_map_name;
}
const lwo2::FORM::SURF::BLOK::IMAP::TAMP *tamp = dynamic_cast<const lwo2::FORM::SURF::BLOK::IMAP::TAMP *>(*i);
if (tamp) {
imap_.texture_amplitude = tamp->amplitude.fraction;
}
}
} else {
osg::notify(osg::WARN) << "Warning: lwosg::Block: only IMAP (image map) block types are supported, this block will be ignored" << std::endl;
}
}
osg::Vec3 Block::setup_texture_point(const osg::Vec3 &P) const
{
osg::Vec3 Q = P;
const osg::Vec3 &ypr = imap_.mapping.rotation_;
Q -= imap_.mapping.center_;
Q = Q * osg::Matrix::rotate(ypr.z(), osg::Vec3(0, 0, -1));
Q = Q * osg::Matrix::rotate(ypr.x(), osg::Vec3(0, 1, 0));
Q = Q * osg::Matrix::rotate(ypr.y(), osg::Vec3(-1, 0, 0));
if (imap_.projection != Image_map::SPHERICAL) {
Q.x() *= 1/imap_.mapping.size_.x();
Q.y() *= 1/imap_.mapping.size_.y();
Q.z() *= 1/imap_.mapping.size_.z();
}
return Q;
}

144
src/osgPlugins/lwo/Block.h Normal file
View File

@@ -0,0 +1,144 @@
/*******************************************************
Lightwave Object Loader for OSG
Copyright (C) 2004 Marco Jez <marco.jez@poste.it>
OpenSceneGraph is (C) 2004 Robert Osfield
********************************************************/
#ifndef LWOSG_BLOCK_
#define LWOSG_BLOCK_
#include "lwo2chunks.h"
#include <osg/Vec3>
#ifdef DIFFERENCE
#undef DIFFERENCE
#endif
namespace lwosg
{
class Clip;
struct Texture_mapping {
enum Coordinate_system_type {
OBJECT = 0,
WORLD = 1
};
osg::Vec3 center_;
osg::Vec3 size_;
osg::Vec3 rotation_;
// missing: OREF, FALL
Coordinate_system_type csys_;
Texture_mapping()
: size_(1, 1, 1),
csys_(OBJECT)
{}
};
struct Image_map {
enum Axis_type {
X = 0,
Y = 1,
Z = 2
};
enum Projection_mode {
PLANAR = 0,
CYLINDRICAL = 1,
SPHERICAL = 2,
CUBIC = 3,
FRONT_PROJECTION = 4,
UV = 5
};
enum Wrap_type {
RESET = 0,
REPEAT = 1,
MIRROR = 2,
EDGE = 3
};
Texture_mapping mapping;
Projection_mode projection;
Axis_type axis;
int image_map;
const Clip *clip; // is filled by Surface::compile()
Wrap_type width_wrap;
Wrap_type height_wrap;
float wrap_amount_w;
float wrap_amount_h;
std::string uv_map;
// missing: AAST, PIXB, STCK
float texture_amplitude;
Image_map()
: image_map(-1),
clip(0),
width_wrap(REPEAT),
height_wrap(REPEAT),
wrap_amount_w(1),
wrap_amount_h(1),
texture_amplitude(1)
{}
};
class Block {
public:
enum Axis_type {
X = 0,
Y = 1,
Z = 2
};
enum Opacity_type {
NORMAL = 0,
SUBTRACTIVE = 1,
DIFFERENCE = 2,
MULTIPLY = 3,
DIVIDE = 4,
ALPHA = 5,
TEXTURE_DISPLACEMENT = 6,
ADDITIVE = 7
};
Block(const lwo2::FORM::SURF::BLOK *blok = 0);
void compile(const lwo2::FORM::SURF::BLOK *blok = 0);
inline const std::string &get_type() const { return type_; }
inline const std::string &get_ordinal() const { return ordinal_; }
inline const std::string &get_channel() const { return channel_; }
inline bool enabled() const { return enabled_; }
inline Opacity_type get_opacity_type() const { return opacity_type_; }
inline float get_opacity_amount() const { return opacity_amount_; }
inline Axis_type get_displacement_axis() const { return displacement_axis_; }
inline const Image_map &get_image_map() const { return imap_; }
inline Image_map &get_image_map() { return imap_; }
osg::Vec3 setup_texture_point(const osg::Vec3 &P) const;
protected:
void read_common_attributes(const iff::Chunk_list &subchunks);
private:
std::string type_;
std::string ordinal_;
std::string channel_;
bool enabled_;
Opacity_type opacity_type_;
float opacity_amount_;
Axis_type displacement_axis_;
Image_map imap_;
};
}
#endif

View File

@@ -0,0 +1,25 @@
/*******************************************************
Lightwave Object Loader for OSG
Copyright (C) 2004 Marco Jez <marco.jez@poste.it>
OpenSceneGraph is (C) 2004 Robert Osfield
********************************************************/
#include "Clip.h"
using namespace lwosg;
Clip::Clip(const lwo2::FORM::CLIP *clip)
{
if (clip) {
compile(clip);
}
}
void Clip::compile(const lwo2::FORM::CLIP *clip)
{
for (iff::Chunk_list::const_iterator j=clip->attributes.begin(); j!=clip->attributes.end(); ++j) {
const lwo2::FORM::CLIP::STIL *stil = dynamic_cast<const lwo2::FORM::CLIP::STIL *>(*j);
if (stil) still_filename_ = stil->name.name;
}
}

35
src/osgPlugins/lwo/Clip.h Normal file
View File

@@ -0,0 +1,35 @@
/*******************************************************
Lightwave Object Loader for OSG
Copyright (C) 2004 Marco Jez <marco.jez@poste.it>
OpenSceneGraph is (C) 2004 Robert Osfield
********************************************************/
#ifndef LWOSG_CLIP_
#define LWOSG_CLIP_
#include "lwo2chunks.h"
#include <string>
#include <map>
namespace lwosg
{
class Clip {
public:
Clip(const lwo2::FORM::CLIP *clip = 0);
void compile(const lwo2::FORM::CLIP *clip);
inline const std::string &get_still_filename() const { return still_filename_; }
private:
std::string still_filename_;
};
typedef std::map<int, Clip> Clip_map;
}
#endif

View File

@@ -0,0 +1,283 @@
/*******************************************************
Lightwave Object Loader for OSG
Copyright (C) 2004 Marco Jez <marco.jez@poste.it>
OpenSceneGraph is (C) 2004 Robert Osfield
********************************************************/
#include "Converter.h"
#include "Tessellator.h"
#include <osg/Notify>
#include <osg/Geode>
#include <osg/Geometry>
#include <osg/CullFace>
#include <osg/LightModel>
#include <osgDB/FileUtils>
#include "lwo2parser.h"
#include <fstream>
using namespace lwosg;
namespace
{
struct GeometryBin {
osg::ref_ptr<osg::DrawElementsUInt> deui_points;
osg::ref_ptr<osg::DrawElementsUInt> deui_lines;
osg::ref_ptr<osg::DrawElementsUInt> deui_triangles;
GeometryBin()
: deui_points(new osg::DrawElementsUInt(GL_POINTS)),
deui_lines(new osg::DrawElementsUInt(GL_LINES)),
deui_triangles(new osg::DrawElementsUInt(GL_TRIANGLES))
{}
};
}
Converter::Converter()
: root_(new osg::Group)
{
}
Converter::Converter(const Options &options)
: root_(new osg::Group),
options_(options)
{
}
osg::Group *Converter::convert(Object &obj)
{
if (root_->getNumChildren() > 0) {
root_->removeChild(0, root_->getNumChildren());
}
osg::notify(osg::INFO) << "INFO: lwosg::Converter: flattening per-polygon vertex maps\n";
for (Object::Layer_map::iterator i=obj.layers().begin(); i!=obj.layers().end(); ++i) {
for (Layer::Unit_list::iterator j=i->second.units().begin(); j!=i->second.units().end(); ++j) {
j->flatten_maps();
}
}
osg::notify(osg::INFO) << "INFO: lwosg::Converter: creating scene graph\n";
build_scene_graph(obj);
return root_.get();
}
void Converter::build_scene_graph(Object &obj)
{
// generate layer structure
typedef std::map<int, osg::ref_ptr<osg::Group> > Layer_group_map;
Layer_group_map lymap;
osg::notify(osg::DEBUG_INFO) << "DEBUG INFO: lwosg::Converter: creating layer structure\n";
// create a flat layer structure, no parenting since it's handled in scene files
for (Object::Layer_map::const_iterator i=obj.layers().begin(); i!=obj.layers().end(); ++i) {
const Layer &layer = i->second;
osg::ref_ptr<osg::Group> new_group = new osg::Group;
lymap[layer.number()] = new_group.get();
if (layer.get_layer_chunk()) {
new_group->setName(layer.get_layer_chunk()->name);
if (layer.get_layer_chunk()->flags & 1) {
new_group->setNodeMask(0);
}
} else {
new_group->setName("Default_layer");
}
root_->addChild(new_group.get());
}
for (Object::Layer_map::iterator li=obj.layers().begin(); li!=obj.layers().end(); ++li) {
Layer &layer = li->second;
osg::Group *layer_group = lymap[layer.number()].get();
osg::notify(osg::DEBUG_INFO) << "DEBUG INFO: lwosg::Converter: processing layer '" << layer_group->getName() << "'\n";
for (Layer::Unit_list::iterator j=layer.units().begin(); j!=layer.units().end(); ++j) {
osg::notify(osg::DEBUG_INFO) << "DEBUG INFO: lwosg::Converter: \tcreating primitives\n";
int tess_success = 0;
int tess_fail = 0;
typedef std::map<const Surface *, GeometryBin> GeometryBin_map;
GeometryBin_map bins;
typedef std::map<const Surface *, Unit::Index_list> Remapping_map;
Remapping_map remappings;
// compute remapping map for default surface
j->compute_vertex_remapping(0, remappings[0]);
// compute remapping maps for other surfaces
for (Object::Surface_map::const_iterator h=obj.surfaces().begin(); h!=obj.surfaces().end(); ++h) {
j->compute_vertex_remapping(&h->second, remappings[&h->second]);
}
// create primitive sets, taking into account remapping maps
for (unsigned k=0; k<j->polygons().size(); ++k) {
const Polygon &poly = j->polygons()[k];
GeometryBin &bin = bins[poly.get_surface()];
const Unit::Index_list &remapping = remappings[poly.get_surface()];
if (poly.indices().size() == 1) {
bin.deui_points->push_back(remapping[poly.indices()[0]]);
}
if (poly.indices().size() == 2) {
bin.deui_lines->push_back(remapping[poly.indices()[0]]);
bin.deui_lines->push_back(remapping[poly.indices()[1]]);
}
if (poly.indices().size() == 3) {
bin.deui_triangles->push_back(remapping[poly.indices()[0]]);
bin.deui_triangles->push_back(remapping[poly.indices()[1]]);
bin.deui_triangles->push_back(remapping[poly.indices()[2]]);
}
if (poly.indices().size() >= 4) {
Tessellator tess;
if (tess.tessellate(poly, j->points(), bin.deui_triangles.get(), &remapping)) {
++tess_success;
} else {
++tess_fail;
}
}
}
if (tess_success > 0) {
osg::notify(osg::DEBUG_INFO) << "DEBUG INFO: lwosg::Converter: " << tess_success << " polygons have been tessellated correctly\n";
}
if (tess_fail > 0) {
osg::notify(osg::WARN) << "Warning: lwosg::Converter: could not tessellate " << tess_fail << " polygons correctly. This is probably due to self-intersecting polygons being used, try to Triple them in Lightwave and restart the conversion" << std::endl;
}
// create normal array
osg::ref_ptr<osg::Vec3Array> normals = j->normals()->asVec3Array(j->points()->size());
for (GeometryBin_map::iterator i=bins.begin(); i!=bins.end(); ++i) {
const Surface *surface = i->first;
GeometryBin &bin = i->second;
const Unit::Index_list &remapping = remappings[surface];
// clean up points and normals according to remapping map
osg::notify(osg::DEBUG_INFO) << "DEBUG INFO: lwosg::Converter: \tcleaning up redundant vertices and vertex attributes for surface '" << (surface ? surface->get_name() : std::string("anonymous")) << "'\n";
osg::ref_ptr<osg::Vec3Array> new_points = new osg::Vec3Array;
osg::ref_ptr<osg::Vec3Array> new_normals = new osg::Vec3Array;
for (unsigned pi=0; pi<j->points()->size(); ++pi) {
if (remapping[pi] != -1) {
new_points->push_back((*j->points())[pi]);
new_normals->push_back((*normals)[pi]);
}
}
osg::notify(osg::DEBUG_INFO) << "DEBUG INFO: lwosg::Converter: \tcreating geometry for surface '" << (surface ? surface->get_name() : std::string("anonymous")) << "'\n";
osg::ref_ptr<osg::Geode> geode = new osg::Geode;
osg::ref_ptr<osg::Geometry> geo = new osg::Geometry;
geode->addDrawable(geo.get());
geo->setVertexArray(new_points.get());
geo->setNormalArray(new_normals.get());
geo->setNormalBinding(osg::Geometry::BIND_PER_VERTEX);
if (surface) {
geode->setName(surface->get_name());
// apply surface parameters and texture/color maps according to remapping map
osg::ref_ptr<VertexMap_map> rm_texture_maps = j->texture_maps()->remap(remapping);
osg::ref_ptr<VertexMap_map> rm_rgb_maps = j->rgb_maps()->remap(remapping);
osg::ref_ptr<VertexMap_map> rm_rgba_maps = j->rgba_maps()->remap(remapping);
osg::Group *sgrp = surface->apply(geo.get(),
rm_texture_maps.get(),
rm_rgb_maps.get(),
rm_rgba_maps.get(),
options_.max_tex_units,
options_.use_osgfx,
options_.force_arb_compression);
if (sgrp) {
sgrp->addChild(geode.get());
layer_group->addChild(sgrp);
} else {
layer_group->addChild(geode.get());
}
} else {
layer_group->addChild(geode.get());
}
// add primitive sets to geometry
if (!bin.deui_points->empty()) geo->addPrimitiveSet(bin.deui_points.get());
if (!bin.deui_lines->empty()) geo->addPrimitiveSet(bin.deui_lines.get());
if (!bin.deui_triangles->empty()) geo->addPrimitiveSet(bin.deui_triangles.get());
}
}
osg::ref_ptr<osg::CullFace> cf = new osg::CullFace;
cf->setMode(osg::CullFace::BACK);
root_->getOrCreateStateSet()->setAttributeAndModes(cf.get());
if (options_.apply_light_model) {
osg::ref_ptr<osg::LightModel> lm = new osg::LightModel;
lm->setTwoSided(true);
lm->setColorControl(osg::LightModel::SEPARATE_SPECULAR_COLOR);
lm->setAmbientIntensity(osg::Vec4(0, 0, 0, 0));
lm->setLocalViewer(true);
root_->getOrCreateStateSet()->setAttributeAndModes(lm.get());
}
}
}
osg::Group *Converter::convert(const iff::Chunk_list &data)
{
Object obj(data);
obj.set_coordinate_system_fixer(options_.csf.get());
return convert(obj);
}
osg::Group *Converter::convert(const std::string &filename)
{
std::string file = osgDB::findDataFile(filename);
if (file.empty()) return 0;
std::ifstream ifs(file.c_str(), std::ios_base::in | std::ios_base::binary);
if (!ifs.is_open()) return 0;
std::vector<char> buffer;
char c;
while (ifs.get(c)) buffer.push_back(c);
lwo2::Parser<std::vector<char>::const_iterator > parser(osg::notify(osg::DEBUG_INFO));
try
{
parser.parse(buffer.begin(), buffer.end());
}
catch(lwo2::parser_error &e)
{
std::cerr << e.what() << std::endl;
return 0;
}
for (iff::Chunk_list::const_iterator i=parser.chunks().begin(); i!=parser.chunks().end(); ++i) {
const lwo2::FORM *form = dynamic_cast<const lwo2::FORM *>(*i);
if (form) {
Object obj(form->data);
obj.set_coordinate_system_fixer(options_.csf.get());
if (!convert(obj)) {
return 0;
}
root_->setName(file);
return root_.get();
}
}
return 0;
}

View File

@@ -0,0 +1,59 @@
/*******************************************************
Lightwave Object Loader for OSG
Copyright (C) 2004 Marco Jez <marco.jez@poste.it>
OpenSceneGraph is (C) 2004 Robert Osfield
********************************************************/
#ifndef LWOSG_CONVERTER_
#define LWOSG_CONVERTER_
#include "Object.h"
#include "iffparser.h"
#include <osg/ref_ptr>
#include <osg/Group>
#include <string>
namespace lwosg
{
class Converter {
public:
struct Options {
osg::ref_ptr<CoordinateSystemFixer> csf;
int max_tex_units;
bool apply_light_model;
bool use_osgfx;
bool force_arb_compression;
Options(): csf(new LwoCoordFixer), max_tex_units(0), apply_light_model(true), use_osgfx(false), force_arb_compression(false) {}
};
Converter();
Converter(const Options &options);
osg::Group *convert(Object &obj);
osg::Group *convert(const iff::Chunk_list &data);
osg::Group *convert(const std::string &filename);
inline osg::Group *get_root() { return root_.get(); }
inline const osg::Group *get_root() const { return root_.get(); }
inline const Options &get_options() const { return options_; }
inline Options &get_options() { return options_; }
inline void set_options(const Options &options) { options_ = options; }
protected:
void build_scene_graph(Object &obj);
private:
osg::ref_ptr<osg::Group> root_;
Options options_;
};
}
#endif

View File

@@ -2,15 +2,24 @@ TOPDIR = ../../..
include $(TOPDIR)/Make/makedefs
CXXFILES =\
lw.cpp\
Lwo2.cpp\
Lwo2Layer.cpp\
old_lw.cpp\
old_Lwo2.cpp\
old_Lwo2Layer.cpp\
Block.cpp\
Clip.cpp\
Converter.cpp\
Object.cpp\
Polygon.cpp\
Surface.cpp\
Tessellator.cpp\
Unit.cpp\
VertexMap.cpp\
ReaderWriterLWO.cpp\
INC += -I$(THISDIR)
LIBS += $(OSG_LIBS) $(OTHER_LIBS)
LIBS += $(OSG_LIBS) $(OTHER_LIBS) $(GL_LIBS)
TARGET_BASENAME = lwo
include $(TOPDIR)/Make/cygwin_plugin_def

View File

@@ -0,0 +1,84 @@
/*******************************************************
Lightwave Object Loader for OSG
Copyright (C) 2004 Marco Jez <marco.jez@poste.it>
OpenSceneGraph is (C) 2004 Robert Osfield
********************************************************/
#ifndef LWOSG_LAYER_
#define LWOSG_LAYER_
#include "lwo2chunks.h"
#include "Unit.h"
namespace lwosg
{
class Layer {
public:
typedef std::vector<Unit> Unit_list;
inline Layer();
inline const lwo2::FORM::LAYR *get_layer_chunk() const;
inline void set_layer_chunk(const lwo2::FORM::LAYR *layr);
inline int number() const;
inline Unit_list &units();
inline const Unit_list &units() const;
inline osg::Vec3 pivot() const;
private:
const lwo2::FORM::LAYR *layr_;
Unit_list units_;
};
// INLINE METHODS
inline Layer::Layer()
: layr_(0)
{
}
inline Layer::Unit_list &Layer::units()
{
return units_;
}
inline const Layer::Unit_list &Layer::units() const
{
return units_;
}
inline osg::Vec3 Layer::pivot() const
{
if (layr_) {
return osg::Vec3(layr_->pivot.X, layr_->pivot.Y, layr_->pivot.Z);
}
return osg::Vec3(0, 0, 0);
}
inline const lwo2::FORM::LAYR *Layer::get_layer_chunk() const
{
return layr_;
}
inline void Layer::set_layer_chunk(const lwo2::FORM::LAYR *layr)
{
layr_ = layr;
}
inline int Layer::number() const
{
if (layr_) {
return layr_->number;
}
return -1;
}
}
#endif

View File

@@ -0,0 +1,461 @@
/*******************************************************
Lightwave Object Loader for OSG
Copyright (C) 2004 Marco Jez <marco.jez@poste.it>
OpenSceneGraph is (C) 2004 Robert Osfield
********************************************************/
#include "Object.h"
#include <osg/Notify>
#include <vector>
#include <string>
#include <sstream>
using namespace lwosg;
namespace
{
bool triangle_is_clockwise(const osg::Vec3Array *points, int a, int b, int c)
{
const osg::Vec3 &A = (*points)[a];
const osg::Vec3 &B = (*points)[b];
const osg::Vec3 &C = (*points)[c];
float area2 = 0;
area2 += A.x() * B.y() - B.x() * A.y();
area2 += B.x() * C.y() - C.x() * B.y();
area2 += C.x() * A.y() - A.x() * C.y();
return area2 < 0;
}
float cylindrical_angle(float x, float y)
{
float r = sqrtf(x*x+y*y);
if (r == 0) return 0;
x /= r;
float a;
if (x < 0 && y >= 0) a = osg::PI_2 - acosf(-x);
if (x < 0 && y < 0) a = acosf(-x) + osg::PI_2;
if (x >= 0 && y >= 0) a = acosf(x) + 3 * osg::PI_2;
if (x >= 0 && y < 0) a = 3 * osg::PI_2 - acosf(x);
return a/osg::PI/2;
}
}
Object::Object()
: csf_(new LwoCoordFixer)
{
}
Object::Object(const iff::Chunk_list &data)
: csf_(new LwoCoordFixer)
{
build(data);
}
void Object::build(const iff::Chunk_list &data)
{
clips_.clear();
surfaces_.clear();
layers_.clear();
comment_.clear();
description_.clear();
osg::notify(osg::INFO) << "INFO: lwosg::Object: scanning clips\n";
scan_clips(data);
osg::notify(osg::INFO) << "INFO: lwosg::Object: scanning surfaces\n";
scan_surfaces(data);
osg::notify(osg::INFO) << "INFO: lwosg::Object: parsing LWO2 chunks and building object\n";
parse(data);
osg::notify(osg::INFO) << "INFO: lwosg::Object: generating normals\n";
generate_normals();
osg::notify(osg::INFO) << "INFO: lwosg::Object: generating automatic texture maps\n";
generate_auto_texture_maps();
}
void Object::scan_clips(const iff::Chunk_list &data)
{
for (iff::Chunk_list::const_iterator i=data.begin(); i!=data.end(); ++i) {
const lwo2::FORM::CLIP *clip = dynamic_cast<const lwo2::FORM::CLIP *>(*i);
if (clip) {
clips_[clip->index] = Clip(clip);
}
}
}
void Object::scan_surfaces(const iff::Chunk_list &data)
{
for (iff::Chunk_list::const_iterator i=data.begin(); i!=data.end(); ++i) {
const lwo2::FORM::SURF *surf = dynamic_cast<const lwo2::FORM::SURF *>(*i);
if (surf) {
surfaces_[surf->name] = Surface(surf, clips_);
}
}
}
void Object::parse(const iff::Chunk_list &data)
{
typedef std::vector<std::string> String_list;
String_list tag_strings;
Layer current_layer;
for (iff::Chunk_list::const_iterator i=data.begin(); i!=data.end(); ++i) {
const lwo2::FORM::LAYR *layr = dynamic_cast<const lwo2::FORM::LAYR *>(*i);
if (layr) {
if (!current_layer.units().empty() || current_layer.get_layer_chunk()) {
layers_[current_layer.number()] = current_layer;
}
current_layer.set_layer_chunk(layr);
current_layer.units().clear();
}
const lwo2::FORM::PNTS *pnts = dynamic_cast<const lwo2::FORM::PNTS *>(*i);
if (pnts) {
Unit new_unit;
for (lwo2::FORM::PNTS::Point_list::const_iterator i=pnts->point_location.begin(); i!=pnts->point_location.end(); ++i) {
new_unit.points()->push_back(csf_->fix_point(osg::Vec3(i->X, i->Y, i->Z) /*+ current_layer.pivot()*/));
}
new_unit.shares().assign(new_unit.points()->size(), Unit::Index_list());
current_layer.units().push_back(new_unit);
}
const lwo2::FORM::VMAP *vmap = dynamic_cast<const lwo2::FORM::VMAP *>(*i);
if (vmap && !current_layer.units().empty()) {
std::string type(vmap->type.id, 4);
if (type == "WGHT") {
if (vmap->dimension != 1) {
osg::notify(osg::WARN) << "Warning: Lwo2Object: invalid " << type << " vertex map dimension: " << vmap->dimension << std::endl;
continue;
}
VertexMap *new_map = current_layer.units().back().weight_maps()->getOrCreate(vmap->name);
for (lwo2::FORM::VMAP::Mapping_list::const_iterator i=vmap->mapping.begin(); i!=vmap->mapping.end(); ++i) {
(*new_map)[i->vert.index] = osg::Vec4(i->value.at(0), 0, 0, 0);
}
}
if (type == "MNVW") {
if (vmap->dimension != 1) {
osg::notify(osg::WARN) << "Warning: Lwo2Object: invalid " << type << " vertex map dimension: " << vmap->dimension << std::endl;
continue;
}
VertexMap *new_map = current_layer.units().back().subpatch_weight_maps()->getOrCreate(vmap->name);
for (lwo2::FORM::VMAP::Mapping_list::const_iterator i=vmap->mapping.begin(); i!=vmap->mapping.end(); ++i) {
(*new_map)[i->vert.index] = osg::Vec4(i->value.at(0), 0, 0, 0);
}
}
if (type == "TXUV") {
if (vmap->dimension != 2) {
osg::notify(osg::WARN) << "Warning: Lwo2Object: invalid " << type << " vertex map dimension: " << vmap->dimension << std::endl;
continue;
}
VertexMap *new_map = current_layer.units().back().texture_maps()->getOrCreate(vmap->name);
for (lwo2::FORM::VMAP::Mapping_list::const_iterator i=vmap->mapping.begin(); i!=vmap->mapping.end(); ++i) {
(*new_map)[i->vert.index] = osg::Vec4(i->value.at(0), i->value.at(1), 0, 0);
}
}
if (type == "RGB ") {
if (vmap->dimension != 3) {
osg::notify(osg::WARN) << "Warning: Lwo2Object: invalid " << type << " vertex map dimension: " << vmap->dimension << std::endl;
continue;
}
VertexMap *new_map = current_layer.units().back().rgb_maps()->getOrCreate(vmap->name);
for (lwo2::FORM::VMAP::Mapping_list::const_iterator i=vmap->mapping.begin(); i!=vmap->mapping.end(); ++i) {
(*new_map)[i->vert.index] = osg::Vec4(i->value.at(0), i->value.at(1), i->value.at(2), 1);
}
}
if (type == "RGBA") {
if (vmap->dimension != 4) {
osg::notify(osg::WARN) << "Warning: Lwo2Object: invalid " << type << " vertex map dimension: " << vmap->dimension << std::endl;
continue;
}
VertexMap *new_map = current_layer.units().back().rgba_maps()->getOrCreate(vmap->name);
for (lwo2::FORM::VMAP::Mapping_list::const_iterator i=vmap->mapping.begin(); i!=vmap->mapping.end(); ++i) {
(*new_map)[i->vert.index] = osg::Vec4(i->value.at(0), i->value.at(1), i->value.at(2), i->value.at(3));
}
}
if (type == "MORF") {
if (vmap->dimension != 3) {
osg::notify(osg::WARN) << "Warning: Lwo2Object: invalid " << type << " vertex map dimension: " << vmap->dimension << std::endl;
continue;
}
VertexMap *new_map = current_layer.units().back().displacement_maps()->getOrCreate(vmap->name);
for (lwo2::FORM::VMAP::Mapping_list::const_iterator i=vmap->mapping.begin(); i!=vmap->mapping.end(); ++i) {
(*new_map)[i->vert.index] = osg::Vec4(i->value.at(0), i->value.at(1), i->value.at(2), 0);
}
}
if (type == "SPOT") {
if (vmap->dimension != 3) {
osg::notify(osg::WARN) << "Warning: Lwo2Object: invalid " << type << " vertex map dimension: " << vmap->dimension << std::endl;
continue;
}
VertexMap *new_map = current_layer.units().back().spot_maps()->getOrCreate(vmap->name);
for (lwo2::FORM::VMAP::Mapping_list::const_iterator i=vmap->mapping.begin(); i!=vmap->mapping.end(); ++i) {
(*new_map)[i->vert.index] = osg::Vec4(csf_->fix_point(osg::Vec3(i->value.at(0), i->value.at(1), i->value.at(2))), 0);
}
}
}
const lwo2::FORM::POLS *pols = dynamic_cast<const lwo2::FORM::POLS *>(*i);
if (pols && !current_layer.units().empty()) {
std::string type(pols->type.id, 4);
if (type != "FACE") {
osg::notify(osg::INFO) << "INFO: Lwo2Object: polygon list of type " << type << " not supported, rendering may be inaccurate" << std::endl;
}
for (lwo2::FORM::POLS::Polygon_list::const_iterator i=pols->polygons.begin(); i!=pols->polygons.end(); ++i) {
Polygon polygon;
bool must_invert_winding = csf_->invert_winding();
// FIX FOR A LIGHTWAVE BUG? MAYBE IT IS A FEATURE, I DON'T KNOW...
// if the first vertex is at a concave corner, we must invert the winding of the polygon
// beacuse it appears as flipped in Lighwave. Also, we tell the polygon to invert its normal.
// (not implemented yet)
/*if (i->vert.size() >= 4) {
if (must_invert_winding == triangle_is_clockwise(current_layer.units().back().points(), i->vert.front().index, i->vert.back().index, i->vert[1].index)) {
must_invert_winding = !must_invert_winding;
polygon.set_invert_normal(true);
}
}*/
if (must_invert_winding) {
for (unsigned j=0; j<i->numvert; ++j) {
int index = i->vert.at((i->numvert-j)%i->numvert).index;
polygon.indices().push_back(index);
current_layer.units().back().shares().at(index).push_back(current_layer.units().back().polygons().size());
}
} else {
for (unsigned j=0; j<i->numvert; ++j) {
int index = i->vert.at(j).index;
polygon.indices().push_back(index);
current_layer.units().back().shares().at(index).push_back(current_layer.units().back().polygons().size());
}
}
current_layer.units().back().polygons().push_back(polygon);
}
}
const lwo2::FORM::TAGS *tags = dynamic_cast<const lwo2::FORM::TAGS *>(*i);
if (tags) {
tag_strings = tags->tag_string;
}
const lwo2::FORM::PTAG *ptag = dynamic_cast<const lwo2::FORM::PTAG *>(*i);
if (ptag && !current_layer.units().empty()) {
std::string type(ptag->type.id, 4);
if (type == "SURF") {
for (lwo2::FORM::PTAG::Mapping_list::const_iterator i=ptag->mapping.begin(); i!=ptag->mapping.end(); ++i) {
current_layer.units().back().polygons().at(i->poly.index).set_surface(&surfaces_[tag_strings.at(i->tag)]);
}
}
if (type == "PART") {
for (lwo2::FORM::PTAG::Mapping_list::const_iterator i=ptag->mapping.begin(); i!=ptag->mapping.end(); ++i) {
current_layer.units().back().polygons().at(i->poly.index).set_part_name(tag_strings.at(i->tag));
}
}
if (type == "SMGP") {
for (lwo2::FORM::PTAG::Mapping_list::const_iterator i=ptag->mapping.begin(); i!=ptag->mapping.end(); ++i) {
current_layer.units().back().polygons().at(i->poly.index).set_smoothing_group(tag_strings.at(i->tag));
}
}
}
const lwo2::FORM::VMAD *vmad = dynamic_cast<const lwo2::FORM::VMAD *>(*i);
if (vmad && !current_layer.units().empty()) {
std::string type(vmad->type.id, 4);
if (type == "WGHT") {
if (vmad->dimension != 1) {
osg::notify(osg::WARN) << "Warning: Lwo2Object: invalid " << type << " discontinuous vertex map dimension: " << vmad->dimension << std::endl;
continue;
}
for (lwo2::FORM::VMAD::Mapping_list::const_iterator i=vmad->mapping.begin(); i!=vmad->mapping.end(); ++i) {
VertexMap *this_map = current_layer.units().back().polygons().at(i->poly.index).weight_maps()->getOrCreate(vmad->name);
(*this_map)[i->vert.index] = osg::Vec4(i->value.at(0), 0, 0, 0);
}
}
if (type == "TXUV") {
if (vmad->dimension != 2) {
osg::notify(osg::WARN) << "Warning: Lwo2Object: invalid " << type << " discontinuous vertex map dimension: " << vmad->dimension << std::endl;
continue;
}
for (lwo2::FORM::VMAD::Mapping_list::const_iterator i=vmad->mapping.begin(); i!=vmad->mapping.end(); ++i) {
VertexMap *this_map = current_layer.units().back().polygons().at(i->poly.index).texture_maps()->getOrCreate(vmad->name);
(*this_map)[i->vert.index] = osg::Vec4(i->value.at(0), i->value.at(1), 0, 0);
}
}
if (type == "RGB ") {
if (vmad->dimension != 3) {
osg::notify(osg::WARN) << "Warning: Lwo2Object: invalid " << type << " discontinuous vertex map dimension: " << vmad->dimension << std::endl;
continue;
}
for (lwo2::FORM::VMAD::Mapping_list::const_iterator i=vmad->mapping.begin(); i!=vmad->mapping.end(); ++i) {
VertexMap *this_map = current_layer.units().back().polygons().at(i->poly.index).rgb_maps()->getOrCreate(vmad->name);
(*this_map)[i->vert.index] = osg::Vec4(i->value.at(0), i->value.at(1), i->value.at(2), 1);
}
}
if (type == "RGBA") {
if (vmad->dimension != 4) {
osg::notify(osg::WARN) << "Warning: Lwo2Object: invalid " << type << " discontinuous vertex map dimension: " << vmad->dimension << std::endl;
continue;
}
for (lwo2::FORM::VMAD::Mapping_list::const_iterator i=vmad->mapping.begin(); i!=vmad->mapping.end(); ++i) {
VertexMap *this_map = current_layer.units().back().polygons().at(i->poly.index).rgba_maps()->getOrCreate(vmad->name);
(*this_map)[i->vert.index] = osg::Vec4(i->value.at(0), i->value.at(1), i->value.at(2), i->value.at(3));
}
}
}
const lwo2::FORM::DESC *desc = dynamic_cast<const lwo2::FORM::DESC *>(*i);
if (desc) {
description_ = desc->description_line;
}
const lwo2::FORM::TEXT *text = dynamic_cast<const lwo2::FORM::TEXT *>(*i);
if (text) {
comment_ = text->comment;
}
}
if (!current_layer.units().empty() || current_layer.get_layer_chunk()) {
layers_[current_layer.number()] = current_layer;
}
}
void Object::generate_normals()
{
for (Layer_map::iterator i=layers_.begin(); i!=layers_.end(); ++i) {
for (Layer::Unit_list::iterator j=i->second.units().begin(); j!=i->second.units().end(); ++j) {
j->generate_normals();
}
}
}
void Object::generate_auto_texture_maps()
{
for (Surface_map::iterator i=surfaces_.begin(); i!=surfaces_.end(); ++i) {
for (Surface::Block_map::iterator j=i->second.blocks().begin(); j!=i->second.blocks().end(); ++j) {
Block &block = j->second;
if (block.get_type() == "IMAP") {
if (block.get_image_map().projection == Image_map::UV) continue;
Image_map::Axis_type axis = block.get_image_map().axis;
std::ostringstream oss;
oss << "Auto_map_" << &block;
std::string map_name = oss.str();
osg::notify(osg::DEBUG_INFO) << "DEBUG INFO: lwosg::Object: creating automatic texture map '" << map_name << "'\n";
for (Layer_map::iterator k=layers_.begin(); k!=layers_.end(); ++k) {
for (Layer::Unit_list::iterator h=k->second.units().begin(); h!=k->second.units().end(); ++h) {
osg::ref_ptr<VertexMap> new_map = new VertexMap;
(*h->texture_maps())[map_name] = new_map.get();
if (block.get_image_map().projection == Image_map::FRONT_PROJECTION) {
osg::notify(osg::WARN) << "Warning: lwosg::Object: front projection is not supported" << std::endl;
}
if (block.get_image_map().projection == Image_map::CUBIC) {
for (Unit::Polygon_list::iterator p=h->polygons().begin(); p!=h->polygons().end(); ++p) {
Polygon &poly = *p;
osg::ref_ptr<VertexMap> local_uv_map = poly.texture_maps()->getOrCreate(map_name);
osg::Vec3 N = csf_->fix_vector(poly.face_normal(h->points()));
Image_map::Axis_type axis = Image_map::X;
if (N.y() > N.x() && N.y() > N.z()) axis = Image_map::Y;
if (-N.y() > N.x() && -N.y() > N.z()) axis = Image_map::Y;
if (N.z() > N.x() && N.z() > N.y()) axis = Image_map::Z;
if (-N.z() > N.x() && -N.z() > N.y()) axis = Image_map::Z;
for (Polygon::Index_list::iterator i=poly.indices().begin(); i!=poly.indices().end(); ++i) {
// fetch vertex
osg::Vec3 P = csf_->fix_point((*h->points())[*i]);
// setup scale/translation/rotation
P = block.setup_texture_point(P);
osg::Vec2 uv;
switch (axis) {
case Image_map::X: uv.set(P.z(), P.y()); break;
case Image_map::Y: uv.set(P.x(), P.z()); break;
case Image_map::Z: uv.set(P.x(), P.y()); break;
default: ;
}
uv += osg::Vec2(0.5f, 0.5f);
osg::Vec4 map_value(uv.x(), uv.y(), 0, 0);
if ((new_map->find(*i) != new_map->end()) && (map_value != (*new_map.get())[*i])) {
(*local_uv_map.get())[*i] = map_value;
} else {
(*new_map.get())[*i] = map_value;
}
}
}
} else {
for (unsigned p=0; p<h->points()->size(); ++p) {
// fetch vertex
osg::Vec3 P = csf_->fix_point((*h->points())[p]);
// setup scale/translation/rotation
P = block.setup_texture_point(P);
osg::Vec2 uv;
if (block.get_image_map().projection == Image_map::PLANAR) {
switch (axis) {
case Image_map::X: uv.set(P.z(), P.y()); break;
case Image_map::Y: uv.set(P.x(), P.z()); break;
case Image_map::Z: uv.set(P.x(), P.y()); break;
default: ;
}
uv += osg::Vec2(0.5f, 0.5f);
}
if (block.get_image_map().projection == Image_map::CYLINDRICAL) {
switch (axis) {
case Image_map::X: uv.set(cylindrical_angle(-P.z(), -P.y()), P.x()); break;
case Image_map::Y: uv.set(cylindrical_angle(P.x(), P.z()), P.y()); break;
case Image_map::Z: uv.set(cylindrical_angle(P.x(), -P.y()), P.z()); break;
default: ;
}
uv.x() *= block.get_image_map().wrap_amount_w;
uv += osg::Vec2(0, 0.5f);
}
if (block.get_image_map().projection == Image_map::SPHERICAL) {
float r = P.length();
if (r != 0) {
switch (axis) {
case Image_map::X: uv.set(cylindrical_angle(-P.z(), -P.y()), (asinf(P.x()/r) + osg::PI_2) / osg::PI); break;
case Image_map::Y: uv.set(cylindrical_angle(P.x(), P.z()), (asinf(P.y()/r) + osg::PI_2) / osg::PI); break;
case Image_map::Z: uv.set(cylindrical_angle(P.x(), -P.y()), (asinf(P.z()/r) + osg::PI_2) / osg::PI); break;
default: ;
}
}
uv.x() *= block.get_image_map().wrap_amount_w;
uv.y() *= block.get_image_map().wrap_amount_h;
}
(*new_map.get())[p] = osg::Vec4(uv.x(), uv.y(), 0, 0);
}
}
}
}
block.get_image_map().uv_map = map_name;
block.get_image_map().projection = Image_map::UV;
}
}
}
}

126
src/osgPlugins/lwo/Object.h Normal file
View File

@@ -0,0 +1,126 @@
/*******************************************************
Lightwave Object Loader for OSG
Copyright (C) 2004 Marco Jez <marco.jez@poste.it>
OpenSceneGraph is (C) 2004 Robert Osfield
********************************************************/
#ifndef LWOSG_OBJECT_
#define LWOSG_OBJECT_
#include "Layer.h"
#include "Surface.h"
#include "Clip.h"
#include "Unit.h"
#include "iffparser.h"
#include <osg/Referenced>
#include <osg/ref_ptr>
#include <string>
#include <vector>
#include <map>
namespace lwosg
{
class CoordinateSystemFixer: public osg::Referenced {
public:
virtual osg::Vec3 fix_point(const osg::Vec3 &P) const = 0;
virtual osg::Vec4 fix_point(const osg::Vec4 &P) const = 0;
virtual osg::Vec3 fix_vector(const osg::Vec3 &V) const = 0;
virtual osg::Vec4 fix_vector(const osg::Vec4 &V) const = 0;
virtual inline bool invert_winding() const { return false; }
protected:
virtual ~CoordinateSystemFixer() {}
CoordinateSystemFixer &operator=(const CoordinateSystemFixer &) { return *this; }
};
class LwoCoordFixer: public CoordinateSystemFixer {
public:
inline osg::Vec3 fix_point(const osg::Vec3 &P) const;
inline osg::Vec4 fix_point(const osg::Vec4 &P) const;
inline osg::Vec3 fix_vector(const osg::Vec3 &V) const;
inline osg::Vec4 fix_vector(const osg::Vec4 &V) const;
inline bool invert_winding() const { return true; }
protected:
virtual ~LwoCoordFixer() {}
LwoCoordFixer &operator=(const LwoCoordFixer &) { return *this; }
};
class Object {
public:
typedef std::map<int, Layer> Layer_map;
typedef std::map<std::string, Surface> Surface_map;
Object();
Object(const iff::Chunk_list &data);
inline CoordinateSystemFixer *get_coordinate_system_fixer() { return csf_.get(); }
inline const CoordinateSystemFixer *get_coordinate_system_fixer() const { return csf_.get(); }
inline void set_coordinate_system_fixer(CoordinateSystemFixer *csf) { csf_ = csf; }
void build(const iff::Chunk_list &data);
inline Layer_map &layers() { return layers_; }
inline const Layer_map &layers() const { return layers_; }
inline Surface_map &surfaces() { return surfaces_; }
inline const Surface_map &surfaces() const { return surfaces_; }
inline const std::string &get_comment() const { return comment_; }
inline const std::string &get_description() const { return description_; }
protected:
void scan_clips(const iff::Chunk_list &data);
void scan_surfaces(const iff::Chunk_list &data);
void parse(const iff::Chunk_list &data);
void generate_normals();
void generate_auto_texture_maps();
private:
Layer_map layers_;
typedef std::map<int, Clip> Clip_map;
Clip_map clips_;
Surface_map surfaces_;
std::string comment_;
std::string description_;
osg::ref_ptr<CoordinateSystemFixer> csf_;
};
// INLINE METHODS
inline osg::Vec3 LwoCoordFixer::fix_point(const osg::Vec3 &P) const
{
return osg::Vec3(P.x(), P.z(), P.y());
}
inline osg::Vec4 LwoCoordFixer::fix_point(const osg::Vec4 &P) const
{
return osg::Vec4(fix_point(osg::Vec3(P.x(), P.y(), P.z())), P.w());
}
inline osg::Vec3 LwoCoordFixer::fix_vector(const osg::Vec3 &V) const
{
return fix_point(V);
}
inline osg::Vec4 LwoCoordFixer::fix_vector(const osg::Vec4 &V) const
{
return fix_point(V);
}
}
#endif

View File

@@ -0,0 +1,22 @@
/*******************************************************
Lightwave Object Loader for OSG
Copyright (C) 2004 Marco Jez <marco.jez@poste.it>
OpenSceneGraph is (C) 2004 Robert Osfield
********************************************************/
#include "Polygon.h"
using namespace lwosg;
Polygon::Polygon()
: surf_(0),
local_normals_(new VertexMap),
weight_maps_(new VertexMap_map),
texture_maps_(new VertexMap_map),
rgb_maps_(new VertexMap_map),
rgba_maps_(new VertexMap_map),
invert_normal_(false),
last_used_points_(0)
{
}

View File

@@ -0,0 +1,118 @@
/*******************************************************
Lightwave Object Loader for OSG
Copyright (C) 2004 Marco Jez <marco.jez@poste.it>
OpenSceneGraph is (C) 2004 Robert Osfield
********************************************************/
#ifndef LWOSG_POLYGON_
#define LWOSG_POLYGON_
#include "lwo2chunks.h"
#include "Surface.h"
#include "VertexMap.h"
#include <osg/Vec3>
#include <osg/Array>
#include <string>
#include <map>
namespace lwosg
{
class Polygon {
public:
typedef std::vector<int> Index_list;
typedef std::map<int, int> Duplication_map;
Polygon();
inline void set_invert_normal(bool v = true) { invert_normal_ = v; }
inline const Index_list &indices() const { return indices_; }
inline Index_list &indices() { dirty_normal(); return indices_; }
inline const Duplication_map &dup_vertices() const { return dup_vertices_; }
inline Duplication_map &dup_vertices() { return dup_vertices_; }
inline const VertexMap *local_normals() const { return local_normals_.get(); }
inline VertexMap *local_normals() { return local_normals_.get(); }
inline const VertexMap_map *weight_maps() const { return weight_maps_.get(); }
inline VertexMap_map *weight_maps() { return weight_maps_.get(); }
inline const VertexMap_map *texture_maps() const { return texture_maps_.get(); }
inline VertexMap_map *texture_maps() { return texture_maps_.get(); }
inline const VertexMap_map *rgb_maps() const { return rgb_maps_.get(); }
inline VertexMap_map *rgb_maps() { return rgb_maps_.get(); }
inline const VertexMap_map *rgba_maps() const { return rgba_maps_.get(); }
inline VertexMap_map *rgba_maps() { return rgba_maps_.get(); }
inline bool has_surface() const { return surf_ != 0; }
inline const Surface *get_surface() const { return surf_; }
inline void set_surface(const Surface *s) { surf_ = s; }
inline bool has_part() const { return !part_.empty(); }
inline const std::string &get_part_name() const { return part_; }
inline void set_part_name(const std::string &n) { part_ = n; }
inline bool has_smoothing_group() const { return !smoothing_group_.empty(); }
inline const std::string &get_smoothing_group() const { return smoothing_group_; }
inline void set_smoothing_group(const std::string &n) { smoothing_group_ = n; }
inline const osg::Vec3 &face_normal(const osg::Vec3Array *points) const;
protected:
inline void dirty_normal() { last_used_points_ = 0; }
private:
Index_list indices_;
Duplication_map dup_vertices_;
const Surface *surf_;
std::string part_;
std::string smoothing_group_;
osg::ref_ptr<VertexMap> local_normals_;
osg::ref_ptr<VertexMap_map> weight_maps_;
osg::ref_ptr<VertexMap_map> texture_maps_;
osg::ref_ptr<VertexMap_map> rgb_maps_;
osg::ref_ptr<VertexMap_map> rgba_maps_;
bool invert_normal_;
mutable const osg::Vec3Array *last_used_points_;
mutable osg::Vec3 normal_;
};
// INLINE METHODS
inline const osg::Vec3 &Polygon::face_normal(const osg::Vec3Array *points) const
{
if (last_used_points_ != points) {
normal_.set(0, 0, 0);
if (indices_.size() >= 3) {
const osg::Vec3 &A = points->at(indices_.front());
const osg::Vec3 &B = points->at(indices_[1]);
const osg::Vec3 &C = points->at(indices_.back());
if (invert_normal_) {
normal_ = (C - A) ^ (B - A);
} else {
normal_ = (B - A) ^ (C - A);
}
float len = normal_.length();
if (len != 0) {
normal_ /= len;
}
}
last_used_points_ = points;
}
return normal_;
}
}
#endif

View File

@@ -0,0 +1,51 @@
LIGHTWAVE (LWO2) PLUGIN INTRODUCTION
------------------------------------------------------------------------------
This is the plugin version of my LWO2->OSG converter. It has all the
features (and drawbacks) of the original converter but it doesn't replace
it completely.
I'm planning to further enhance the stand-alone converter by adding osgNV
compatibility and I can't do this on the plugin version because I'm not going
to introduce a dependancy to osgNV into OSG.
There is also a LWS plugin which reads Lightwave scene files; make sure you
only read scene files that point to LWO2 (not LWO1) objects, otherwise you may
experience problems (the LWO1 plugin doesn't convert the coordinate system
correctly).
PLUGIN OPTIONS
------------------------------------------------------------------------------
USE_OLD_READER pass control to the old LWO/LWO2 reader plugin
(all other options ignored)
FORCE_ARB_COMPRESSION create compressed textures
USE_OSGFX use osgFX effects to improve visual appearance
NO_LIGHTMODEL_ATTRIBUTE prevent the plugin from creating a LightModel
state attribute; using this option may result in
visual artifacts
MAX_TEXTURE_UNITS <n> set the maximum number of texture units to be
used when creating multi-textured surfaces
NOTES
------------------------------------------------------------------------------
NOTE_1: this plugin works fine in reading LWO2 files but it's not well
optimized,so you can expect slowness and large memory usage.
NOTE_2: the LWS (scene) support is a quick-and-dirty work, it's there
only because I needed it. Do not pretend too much from it, at least until
I improve it somehow.
NOTE_3: the osgFX support is still limited, only osgFX::SpecularHighlights
is used to improve the specularity effects on materials that have a specular
component. Future enhancements will allow osgFX to be used more widely to
give a better visual matching between the original LWO2 model and OSG.
Marco Jez <marco.jez@poste.it>
January 2004

View File

@@ -4,6 +4,7 @@
* Lightwave Object loader for Open Scene Graph
*
* Copyright (C) 2001 Ulrich Hertlein <u.hertlein@web.de>
* Improved LWO2 reader is (C) 2003-2004 Marco Jez <marco.jez@poste.it>
*
* The Open Scene Graph (OSG) is a cross platform C++/OpenGL library for
* real-time rendering of large 3D photo-realistic models.
@@ -15,6 +16,7 @@
#endif
#include <string>
#include <sstream>
#include <algorithm>
#include <osg/Notify>
@@ -34,8 +36,10 @@
#include <osgUtil/SmoothingVisitor>
#include <osgUtil/Tesselator>
#include "lw.h"
#include "Lwo2.h"
#include "Converter.h"
#include "old_lw.h"
#include "old_Lwo2.h"
class ReaderWriterLWO : public osgDB::ReaderWriter
{
@@ -49,7 +53,7 @@ public:
virtual ReadResult readNode(const std::string& file, const osgDB::ReaderWriter::Options* options)
{
std::string ext = osgDB::getLowerCaseFileExtension(file);
std::string ext = osgDB::getLowerCaseFileExtension(file);
if (!acceptsExtension(ext)) return ReadResult::FILE_NOT_HANDLED;
std::string fileName = osgDB::findDataFile( file );
@@ -58,10 +62,18 @@ public:
ReadResult result = readNode_LWO1(fileName,options);
if (result.success()) return result;
return readNode_LWO2(fileName,options);
if (!options || options->getOptionString() != "USE_OLD_READER") {
ReadResult result = readNode_LWO2(fileName, options);
if (result.success()) return result;
}
return readNode_old_LWO2(fileName, options);
}
lwosg::Converter::Options parse_options(const Options *options) const;
virtual ReadResult readNode_LWO2(const std::string& fileName, const osgDB::ReaderWriter::Options*);
virtual ReadResult readNode_old_LWO2(const std::string& fileName, const osgDB::ReaderWriter::Options*);
virtual ReadResult readNode_LWO1(const std::string& fileName, const osgDB::ReaderWriter::Options*);
protected:
@@ -70,12 +82,48 @@ protected:
};
lwosg::Converter::Options ReaderWriterLWO::parse_options(const Options *options) const
{
lwosg::Converter::Options conv_options;
if (options) {
std::istringstream iss(options->getOptionString());
std::string opt;
while (iss >> opt) {
if (opt == "FORCE_ARB_COMPRESSION") conv_options.force_arb_compression = true;
if (opt == "USE_OSGFX") conv_options.use_osgfx = true;
if (opt == "NO_LIGHTMODEL_ATTRIBUTE") conv_options.apply_light_model = false;
if (opt == "MAX_TEXTURE_UNITS") {
int n;
if (iss >> n) {
conv_options.max_tex_units = n;
}
}
}
}
return conv_options;
}
// register with Registry to instantiate the above reader/writer.
osgDB::RegisterReaderWriterProxy<ReaderWriterLWO> g_lwoReaderWriterProxy;
osgDB::ReaderWriter::ReadResult ReaderWriterLWO::readNode_LWO2(const std::string &fileName, const osgDB::ReaderWriter::Options *options)
{
lwosg::Converter::Options conv_options = parse_options(options);
osgDB::ReaderWriter::ReadResult ReaderWriterLWO::readNode_LWO2(const std::string& fileName, const osgDB::ReaderWriter::Options*)
lwosg::Converter converter(conv_options);
osg::ref_ptr<osg::Node> node = converter.convert(fileName);
if (node.valid()) {
return node.take();
}
return ReadResult::FILE_NOT_HANDLED;
}
osgDB::ReaderWriter::ReadResult ReaderWriterLWO::readNode_old_LWO2(const std::string& fileName, const osgDB::ReaderWriter::Options*)
{
std::auto_ptr<Lwo2> lwo2(new Lwo2());
if (lwo2->ReadFile(fileName))

View File

@@ -0,0 +1,329 @@
/*******************************************************
Lightwave Object Loader for OSG
Copyright (C) 2004 Marco Jez <marco.jez@poste.it>
OpenSceneGraph is (C) 2004 Robert Osfield
********************************************************/
#include "Surface.h"
#include <osg/Material>
#include <osg/CullFace>
#include <osg/Texture2D>
#include <osg/TexEnvCombine>
#include <osg/TexGen>
#include <osg/BlendFunc>
#include <osg/Notify>
#include <osgFX/SpecularHighlights>
#include <osgDB/ReadFile>
using namespace lwosg;
namespace
{
osg::Texture::WrapMode osg_wrap_mode(Image_map::Wrap_type w)
{
switch (w) {
case Image_map::RESET: return osg::Texture::CLAMP;
case Image_map::REPEAT: return osg::Texture::REPEAT;
case Image_map::MIRROR: return osg::Texture::MIRROR;
case Image_map::EDGE: return osg::Texture::CLAMP_TO_EDGE;
default: return osg::Texture::REPEAT;
};
}
}
Surface::Surface()
: base_color_(0.784f, 0.784f, 0.784f),
diffuse_(1.0f),
luminosity_(0),
specularity_(0),
reflection_(0),
transparency_(0),
translucency_(0),
glossiness_(0.4f),
sidedness_(FRONT_ONLY),
max_smoothing_angle_(0)
{
}
Surface::Surface(const lwo2::FORM::SURF *surf, const Clip_map &clips)
: base_color_(0.784f, 0.784f, 0.784f),
diffuse_(1.0f),
luminosity_(0),
specularity_(0),
reflection_(0),
transparency_(0),
translucency_(0),
glossiness_(0.4f),
sidedness_(FRONT_ONLY),
max_smoothing_angle_(0)
{
compile(surf, clips);
}
void Surface::compile(const lwo2::FORM::SURF *surf, const Clip_map &clips)
{
// invalidate the stateset so it will be rebuilt
stateset_ = 0;
name_ = surf->name;
for (iff::Chunk_list::const_iterator j=surf->attributes.begin(); j!=surf->attributes.end(); ++j) {
const lwo2::FORM::SURF::COLR *colr = dynamic_cast<const lwo2::FORM::SURF::COLR *>(*j);
if (colr) base_color_ = osg::Vec3(colr->base_color.red, colr->base_color.green, colr->base_color.blue);
const lwo2::FORM::SURF::DIFF *diff = dynamic_cast<const lwo2::FORM::SURF::DIFF *>(*j);
if (diff) diffuse_ = diff->intensity.fraction;
const lwo2::FORM::SURF::LUMI *lumi = dynamic_cast<const lwo2::FORM::SURF::LUMI *>(*j);
if (lumi) luminosity_ = lumi->intensity.fraction;
const lwo2::FORM::SURF::SPEC *spec = dynamic_cast<const lwo2::FORM::SURF::SPEC *>(*j);
if (spec) specularity_ = spec->intensity.fraction;
const lwo2::FORM::SURF::REFL *refl = dynamic_cast<const lwo2::FORM::SURF::REFL *>(*j);
if (refl) reflection_ = refl->intensity.fraction;
const lwo2::FORM::SURF::TRAN *tran = dynamic_cast<const lwo2::FORM::SURF::TRAN *>(*j);
if (tran) transparency_ = tran->intensity.fraction;
const lwo2::FORM::SURF::TRNL *trnl = dynamic_cast<const lwo2::FORM::SURF::TRNL *>(*j);
if (trnl) translucency_ = trnl->intensity.fraction;
const lwo2::FORM::SURF::GLOS *glos = dynamic_cast<const lwo2::FORM::SURF::GLOS *>(*j);
if (glos) glossiness_ = glos->glossiness.fraction;
const lwo2::FORM::SURF::SIDE *side = dynamic_cast<const lwo2::FORM::SURF::SIDE *>(*j);
if (side) sidedness_ = static_cast<Sidedness>(side->sidedness);
const lwo2::FORM::SURF::SMAN *sman = dynamic_cast<const lwo2::FORM::SURF::SMAN *>(*j);
if (sman) max_smoothing_angle_ = sman->max_smoothing_angle.radians;
const lwo2::FORM::SURF::VCOL *vcol = dynamic_cast<const lwo2::FORM::SURF::VCOL *>(*j);
if (vcol) {
color_map_intensity_ = vcol->intensity.fraction;
color_map_type_ = std::string(vcol->vmap_type.id, 4);
color_map_name_ = vcol->name;
}
const lwo2::FORM::SURF::BLOK *blok = dynamic_cast<const lwo2::FORM::SURF::BLOK *>(*j);
if (blok) {
Block new_block(blok);
if (new_block.get_type() == "IMAP") {
Clip_map::const_iterator i = clips.find(new_block.get_image_map().image_map);
if (i != clips.end()) {
new_block.get_image_map().clip = &i->second;
} else {
osg::notify(osg::WARN) << "Warning: lwosg::Surface: cannot find clip number " << new_block.get_image_map().image_map << std::endl;
}
}
blocks_.insert(std::make_pair(new_block.get_ordinal(), new_block));
}
}
}
void Surface::generate_stateset(int max_tex_units, bool force_arb_compression) const
{
if (!stateset_.valid()) {
stateset_ = new osg::StateSet;
osg::ref_ptr<osg::Material> material = new osg::Material;
material->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4(base_color_ * diffuse_, 1-transparency_));
material->setAmbient(osg::Material::FRONT_AND_BACK, material->getDiffuse(osg::Material::FRONT_AND_BACK));
material->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4(specularity_, specularity_, specularity_, 1));
material->setShininess(osg::Material::FRONT_AND_BACK, powf(2, 10 * glossiness_ + 2));
material->setEmission(osg::Material::FRONT_AND_BACK, osg::Vec4(base_color_ * luminosity_, 1-transparency_));
stateset_->setAttributeAndModes(material.get());
if (!color_map_name_.empty()) {
material->setColorMode(osg::Material::AMBIENT_AND_DIFFUSE);
}
if (transparency_ > 0) {
osg::ref_ptr<osg::BlendFunc> bf = new osg::BlendFunc;
bf->setFunction(osg::BlendFunc::SRC_ALPHA, osg::BlendFunc::ONE_MINUS_SRC_ALPHA);
stateset_->setAttributeAndModes(bf.get());
stateset_->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
}
if (sidedness_ == FRONT_AND_BACK) {
stateset_->setMode(GL_CULL_FACE, osg::StateAttribute::OFF);
} else {
osg::ref_ptr<osg::CullFace> cf = new osg::CullFace;
switch (sidedness_) {
case NONE: cf->setMode(osg::CullFace::FRONT_AND_BACK); break;
case FRONT_ONLY: cf->setMode(osg::CullFace::BACK); break;
case BACK_ONLY: cf->setMode(osg::CullFace::FRONT); break;
default: ;
}
stateset_->setAttributeAndModes(cf.get());
}
int unit = 0;
for (Block_map::const_iterator i=blocks_.begin(); i!=blocks_.end(); ++i) {
const Block &block = i->second;
if (!block.enabled()) {
continue;
}
if (block.get_type() == "IMAP") {
if (block.get_channel() == "COLR") {
if (block.get_image_map().clip) {
std::string image_file = block.get_image_map().clip->get_still_filename();
if (!image_file.empty()) {
if (unit >= max_tex_units && max_tex_units > 0) {
osg::notify(osg::WARN) << "Warning: lwosg::Surface: maximum number of texture units (" << max_tex_units << ") has been reached, skipping incoming blocks" << std::endl;
break;
}
osg::ref_ptr<osg::Texture2D> texture = new osg::Texture2D;
if (force_arb_compression)
texture->setInternalFormatMode(osg::Texture::USE_ARB_COMPRESSION);
texture->setImage(osgDB::readImageFile(image_file));
texture->setWrap(osg::Texture::WRAP_S, osg_wrap_mode(block.get_image_map().width_wrap));
texture->setWrap(osg::Texture::WRAP_T, osg_wrap_mode(block.get_image_map().height_wrap));
texture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR_MIPMAP_LINEAR);
texture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR);
stateset_->setTextureAttributeAndModes(unit, texture.get());
osg::ref_ptr<osg::TexEnvCombine> tec = new osg::TexEnvCombine;
switch (block.get_opacity_type()) {
case Block::NORMAL:
{
float s = block.get_opacity_amount();
if (unit == 0) {
tec->setCombine_RGB(osg::TexEnvCombine::MODULATE);
osg::Vec3 color(diffuse_, diffuse_, diffuse_);
color = color * s + base_color_ * (1 - s);
material->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4(color, 1-transparency_));
material->setAmbient(osg::Material::FRONT_AND_BACK, material->getDiffuse(osg::Material::FRONT_AND_BACK));
material->setColorMode(osg::Material::OFF);
} else {
tec->setCombine_RGB(osg::TexEnvCombine::INTERPOLATE);
tec->setConstantColor(osg::Vec4(s, s, s, s));
}
}
break;
case Block::ADDITIVE:
tec->setCombine_RGB(osg::TexEnvCombine::ADD);
break;
case Block::SUBTRACTIVE:
osg::notify(osg::WARN) << "Warning: lwosg::Surface: 'Subtractive' blending mode is not supported, falling back to 'Difference' mode" << std::endl;
case Block::DIFFERENCE:
tec->setCombine_RGB(osg::TexEnvCombine::SUBTRACT);
break;
case Block::MULTIPLY:
tec->setCombine_RGB(osg::TexEnvCombine::MODULATE);
break;
case Block::DIVIDE:
osg::notify(osg::WARN) << "Warning: lwosg::Surface: 'Divide' blending mode is not supported" << std::endl;
break;
case Block::ALPHA:
osg::notify(osg::WARN) << "Warning: lwosg::Surface: 'Alpha' blending mode is not supported" << std::endl;
break;
case Block::TEXTURE_DISPLACEMENT:
osg::notify(osg::WARN) << "Warning: lwosg::Surface: 'Texture Displacement' blending mode is not supported" << std::endl;
break;
default: ;
};
stateset_->setTextureAttributeAndModes(unit, tec.get());
++unit;
}
}
} else {
osg::notify(osg::WARN) << "Warning: lwosg::Surface: texture channels of type '" << block.get_channel() << "' are not supported, this block will be ignored" << std::endl;
}
}
}
}
}
osg::Group *Surface::apply(osg::Geometry *geo, const VertexMap_map *texture_maps, const VertexMap_map *rgb_maps, const VertexMap_map *rgba_maps, int max_tex_units, bool use_osgfx, bool force_arb_compression) const
{
int num_points = 0;
if (geo->getVertexArray()) {
num_points = static_cast<int>(geo->getVertexArray()->getNumElements());
}
generate_stateset(max_tex_units, force_arb_compression);
geo->setStateSet(stateset_.get());
int unit = 0;
for (Block_map::const_iterator i=blocks_.begin(); i!=blocks_.end(); ++i) {
const Block &block = i->second;
if (block.get_type() == "IMAP" && block.get_channel() == "COLR" && block.get_image_map().clip) {
std::string image_file = block.get_image_map().clip->get_still_filename();
if (!image_file.empty()) {
if (block.get_image_map().projection == Image_map::UV) {
VertexMap_map::const_iterator i = texture_maps->find(block.get_image_map().uv_map);
if (i != texture_maps->end()) {
geo->setTexCoordArray(unit, i->second->asVec2Array(num_points));
} else {
osg::notify(osg::WARN) << "Warning: lwosg::Surface: surface '" << name_ << "' needs texture map named '" << block.get_image_map().uv_map << "' but I can't find it" << std::endl;
}
}
++unit;
}
}
}
osg::Vec4 color = osg::Vec4(base_color_, 1-transparency_);
const VertexMap_map *color_maps = 0;
if (color_map_type_ == "RGB ") {
color_maps = rgb_maps;
}
if (color_map_type_ == "RGBA") {
color_maps = rgba_maps;
}
if (color_maps) {
VertexMap_map::const_iterator i = color_maps->find(color_map_name_);
if (i != color_maps->end() && !i->second->empty()) {
geo->setColorArray(i->second->asVec4Array(num_points, color * color_map_intensity_, color * color_map_intensity_));
geo->setColorBinding(osg::Geometry::BIND_PER_VERTEX);
} else {
osg::notify(osg::WARN) << "Warning: lwosg::Surface: surface '" << name_ << "' needs color map named '" << color_map_name_ << "' but I can't find it" << std::endl;
}
}
// create osgFX specularity if needed
if (use_osgfx && glossiness_ > 0 && specularity_ > 0) {
if (unit >= max_tex_units && max_tex_units > 0) {
osg::notify(osg::WARN) << "Warning: lwosg::Surface: can't apply osgFX specular lighting: maximum number of texture units (" << max_tex_units << ") has been reached" << std::endl;
} else {
osg::ref_ptr<osgFX::SpecularHighlights> sh = new osgFX::SpecularHighlights;
sh->setTextureUnit(unit);
osg::Material *material = dynamic_cast<osg::Material *>(stateset_->getAttribute(osg::StateAttribute::MATERIAL));
if (material) {
sh->setSpecularColor(material->getSpecular(osg::Material::FRONT_AND_BACK));
sh->setSpecularExponent(powf(2, 10 * glossiness_ + 2));
material->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4(0, 0, 0, 0));
material->setShininess(osg::Material::FRONT_AND_BACK, 0);
}
return sh.take();
}
}
return 0;
}

View File

@@ -0,0 +1,105 @@
/*******************************************************
Lightwave Object Loader for OSG
Copyright (C) 2004 Marco Jez <marco.jez@poste.it>
OpenSceneGraph is (C) 2004 Robert Osfield
********************************************************/
#ifndef LWOSG_SURFACE_
#define LWOSG_SURFACE_
#include "lwo2chunks.h"
#include "VertexMap.h"
#include "Block.h"
#include "Clip.h"
#include <osg/ref_ptr>
#include <osg/Vec3>
#include <osg/StateSet>
#include <osg/Geometry>
#include <string>
#include <map>
namespace lwosg
{
class Surface {
public:
enum Sidedness {
NONE = 0,
FRONT_ONLY = 1,
BACK_ONLY = 2,
FRONT_AND_BACK = 3
};
typedef std::multimap<std::string, Block> Block_map;
Surface();
Surface(const lwo2::FORM::SURF *surf, const Clip_map &clips);
void compile(const lwo2::FORM::SURF *surf, const Clip_map &clips);
osg::Group *apply(osg::Geometry *geo, const VertexMap_map *texture_maps, const VertexMap_map *rgb_maps, const VertexMap_map *rgba_maps, int max_tex_units = 0, bool use_osgfx = false, bool force_arb_compression = false) const;
void generate_stateset(int max_tex_units = 0, bool force_arb_compression = false) const;
inline const std::string &get_name() const { return name_; }
inline void set_name(const std::string &n) { name_ = n; }
inline const osg::Vec3 &get_base_color() const { return base_color_; }
inline float get_diffuse() const { return diffuse_; }
inline float get_luminosity() const { return luminosity_; }
inline float get_specularity() const { return specularity_; }
inline float get_reflection() const { return reflection_; }
inline float get_transparency() const { return transparency_; }
inline float get_translucency() const { return translucency_; }
inline float get_glossiness() const { return glossiness_; }
inline Sidedness get_sidedness() const { return sidedness_; }
inline float get_max_smoothing_angle() const { return max_smoothing_angle_; }
inline const std::string &get_color_map_type() const { return color_map_type_; }
inline const std::string &get_color_map_name() const { return color_map_name_; }
inline float get_color_map_intensity() const { return color_map_intensity_; }
inline Block_map &blocks() { return blocks_; }
inline const Block_map &blocks() const { return blocks_; }
/*
inline const std::string &get_uv_map_name() const { return uv_map_name_; }
inline bool has_clip() const { return clip_ != 0; }
inline const Clip *get_clip() const { return clip_; }
inline void set_clip(const Clip *c) { clip_ = c; }
*/
private:
std::string name_;
osg::Vec3 base_color_;
float diffuse_;
float luminosity_;
float specularity_;
float reflection_;
float transparency_;
float translucency_;
float glossiness_;
Sidedness sidedness_;
float max_smoothing_angle_;
std::string color_map_type_;
std::string color_map_name_;
float color_map_intensity_;
Block_map blocks_;
/*
std::string uv_map_name_;
const Clip *clip_;
*/
mutable osg::ref_ptr<osg::StateSet> stateset_;
};
}
#endif

View File

@@ -0,0 +1,121 @@
/*******************************************************
Lightwave Object Loader for OSG
Copyright (C) 2004 Marco Jez <marco.jez@poste.it>
OpenSceneGraph is (C) 2004 Robert Osfield
********************************************************/
#include "Tessellator.h"
using namespace lwosg;
namespace lwosg
{
void CALLBACK cb_begin_data(GLenum type, void *data)
{
Tessellator *tess = static_cast<Tessellator *>(data);
tess->prim_type_ = type;
tess->incoming_.clear();
}
void CALLBACK cb_vertex_data(void *vertex_data, void *data)
{
Tessellator *tess = static_cast<Tessellator *>(data);
tess->incoming_.push_back(*static_cast<int *>(vertex_data));
}
void CALLBACK cb_end_data(void *data)
{
Tessellator *tess = static_cast<Tessellator *>(data);
tess->finalize_primitive();
}
void CALLBACK cb_error_data(GLenum error, void *data)
{
Tessellator *tess = static_cast<Tessellator *>(data);
tess->last_error_ = error;
}
}
bool Tessellator::tessellate(const Polygon &poly, const osg::Vec3Array *points, osg::DrawElementsUInt *out, const std::vector<int> *remap)
{
out_ = out;
last_error_ = 0;
GLUtesselator *tess = gluNewTess();
gluTessCallback(tess, GLU_TESS_BEGIN_DATA, reinterpret_cast<void (CALLBACK *)()>(cb_begin_data));
gluTessCallback(tess, GLU_TESS_VERTEX_DATA, reinterpret_cast<void (CALLBACK *)()>(cb_vertex_data));
gluTessCallback(tess, GLU_TESS_END_DATA, reinterpret_cast<void (CALLBACK *)()>(cb_end_data));
gluTessCallback(tess, GLU_TESS_ERROR_DATA, reinterpret_cast<void (CALLBACK *)()>(cb_error_data));
gluTessBeginPolygon(tess, this);
gluTessBeginContour(tess);
double *vertices = new double[poly.indices().size() * 3];
int *indices = new int[poly.indices().size()];
double *v = vertices;
int *x = indices;
for (Polygon::Index_list::const_iterator i=poly.indices().begin(); i!=poly.indices().end(); ++i, v+=3, ++x) {
const osg::Vec3 &P = (*points)[*i];
v[0] = P.x();
v[1] = P.y();
v[2] = P.z();
if (remap) {
*x = (*remap)[*i];
} else {
*x = *i;
}
gluTessVertex(tess, v, x);
}
gluTessEndContour(tess);
gluTessEndPolygon(tess);
gluDeleteTess(tess);
delete[] vertices;
delete[] indices;
return last_error_ == 0;
}
Tessellator::~Tessellator()
{
}
void Tessellator::finalize_primitive()
{
if (incoming_.size() < 3) return;
if (prim_type_ == GL_TRIANGLES) {
for (Index_list::const_iterator i=incoming_.begin(); i!=incoming_.end(); ++i) {
out_->push_back(*i);
}
}
if (prim_type_ == GL_TRIANGLE_FAN) {
for (Index_list::const_iterator i=incoming_.begin()+1; (i+1)!=incoming_.end(); ++i) {
out_->push_back(incoming_.front());
out_->push_back(*i);
out_->push_back(*(i+1));
}
}
if (prim_type_ == GL_TRIANGLE_STRIP) {
int j = 0;
for (Index_list::const_iterator i=incoming_.begin(); (i+2)!=incoming_.end(); ++i, ++j) {
if ((j % 2) == 0) {
out_->push_back(*i);
out_->push_back(*(i+1));
out_->push_back(*(i+2));
} else {
out_->push_back(*i);
out_->push_back(*(i+2));
out_->push_back(*(i+1));
}
}
}
}

View File

@@ -0,0 +1,53 @@
/*******************************************************
Lightwave Object Loader for OSG
Copyright (C) 2004 Marco Jez <marco.jez@poste.it>
OpenSceneGraph is (C) 2004 Robert Osfield
********************************************************/
#ifndef LWOSG_TESSELLATOR_
#define LWOSG_TESSELLATOR_
#include "Polygon.h"
#include <osg/ref_ptr>
#include <osg/Array>
#include <osg/PrimitiveSet>
#include <osg/GLU>
#include <vector>
#ifndef CALLBACK
#define CALLBACK
#endif
namespace lwosg
{
class Tessellator {
public:
bool tessellate(const Polygon &poly, const osg::Vec3Array *points, osg::DrawElementsUInt *out, const std::vector<int> *remap = 0);
~Tessellator();
protected:
void finalize_primitive();
private:
friend void CALLBACK cb_begin_data(GLenum, void *);
friend void CALLBACK cb_vertex_data(void *, void *);
friend void CALLBACK cb_end_data(void *);
friend void CALLBACK cb_error_data(GLenum, void *);
osg::ref_ptr<osg::DrawElementsUInt> out_;
GLenum prim_type_;
GLenum last_error_;
typedef std::vector<int> Index_list;
Index_list incoming_;
};
}
#endif

242
src/osgPlugins/lwo/Unit.cpp Normal file
View File

@@ -0,0 +1,242 @@
/*******************************************************
Lightwave Object Loader for OSG
Copyright (C) 2004 Marco Jez <marco.jez@poste.it>
OpenSceneGraph is (C) 2004 Robert Osfield
********************************************************/
#include "Unit.h"
using namespace lwosg;
Unit::Unit()
: points_(new osg::Vec3Array),
normals_(new VertexMap),
weight_maps_(new VertexMap_map),
subpatch_weight_maps_(new VertexMap_map),
texture_maps_(new VertexMap_map),
rgb_maps_(new VertexMap_map),
rgba_maps_(new VertexMap_map),
displacement_maps_(new VertexMap_map),
spot_maps_(new VertexMap_map)
{
}
float Unit::angle_between_polygons(const Polygon &p1, const Polygon &p2) const
{
float a = p1.face_normal(points_.get()) * p2.face_normal(points_.get());
if (a > 1) return 0;
if (a < -1) return osg::PI;
return acosf(a);
}
void Unit::find_shared_polygons(int vertex_index, std::vector<int> &poly_indices)
{
int k = 0;
for (Polygon_list::const_iterator i=polygons_.begin(); i!=polygons_.end(); ++i, ++k) {
for (Polygon::Index_list::const_iterator j=i->indices().begin(); j!=i->indices().end(); ++j) {
if (*j == vertex_index) {
poly_indices.push_back(k);
break;
}
}
}
}
void Unit::generate_normals()
{
// create smoothed normals
for (Polygon_list::iterator i=polygons_.begin(); i!=polygons_.end(); ++i) {
osg::Vec4 N = osg::Vec4(i->face_normal(points_.get()), 0);
for (Polygon::Index_list::iterator j=i->indices().begin(); j!=i->indices().end(); ++j) {
(*normals_.get())[*j] += N;
}
}
// normalize smoothed normals
for (VertexMap::iterator ni=normals_->begin(); ni!=normals_->end(); ++ni) {
float l = ni->second.length();
if (l != 0) ni->second /= l;
}
// compute per-polygon normals
int pn = 0;
for (Polygon_list::iterator pi=polygons_.begin(); pi!=polygons_.end(); ++pi, ++pn) {
Polygon &poly = *pi;
float max_smoothing_angle = 0;
if (poly.has_surface()) {
max_smoothing_angle = poly.get_surface()->get_max_smoothing_angle();
}
for (Polygon::Index_list::const_iterator j=poly.indices().begin(); j!=poly.indices().end(); ++j) {
osg::Vec4 N(poly.face_normal(points_.get()), 0);
unsigned num_smoothed = 1;
const Index_list &shared_polys = shares_.at(*j);
for (unsigned k=0; k<shared_polys.size(); ++k) {
if (shared_polys[k] != pn) {
const Polygon &shared_poly = polygons_.at(shared_polys[k]);
float angle = angle_between_polygons(poly, shared_poly);
if (angle <= max_smoothing_angle && (poly.get_smoothing_group() == shared_poly.get_smoothing_group())) {
N += osg::Vec4(shared_poly.face_normal(points_.get()), 0);
++num_smoothed;
}
}
}
if (num_smoothed != shared_polys.size()) {
float l = N.length();
if (l != 0) N /= l;
(*poly.local_normals())[*j] = N;
}
}
}
}
void Unit::flatten_maps()
{
for (Polygon_list::iterator i=polygons().begin(); i!=polygons().end(); ++i) {
// flatten normal map
flatten_map(*i, i->local_normals(), normals_.get());
i->local_normals()->clear();
VertexMap_map::const_iterator j;
// flatten weight maps
while (!i->weight_maps()->empty()) {
VertexMap_map::iterator j = i->weight_maps()->begin();
flatten_map(*i, j->second.get(), weight_maps_->getOrCreate(j->first));
i->weight_maps()->erase(j);
}
// flatten texture maps
while (!i->texture_maps()->empty()) {
VertexMap_map::iterator j = i->texture_maps()->begin();
flatten_map(*i, j->second.get(), texture_maps_->getOrCreate(j->first));
i->texture_maps()->erase(j);
}
// flatten rgb maps
while (!i->rgb_maps()->empty()) {
VertexMap_map::iterator j = i->rgb_maps()->begin();
flatten_map(*i, j->second.get(), rgb_maps_->getOrCreate(j->first));
i->rgb_maps()->erase(j);
}
// flatten rgba maps
while (!i->rgba_maps()->empty()) {
VertexMap_map::iterator j = i->rgba_maps()->begin();
flatten_map(*i, j->second.get(), rgba_maps_->getOrCreate(j->first));
i->rgba_maps()->erase(j);
}
}
}
void Unit::flatten_map(Polygon &poly, const VertexMap *local_map, VertexMap *global_map)
{
int j = 0;
for (Polygon::Index_list::iterator i=poly.indices().begin(); i!=poly.indices().end(); ++i, ++j) {
// try original vertex index
VertexMap::const_iterator k = local_map->find(*i);
// try duplicated vertex index
if (k == local_map->end()) {
k = local_map->find(poly.dup_vertices()[j]);
}
if (k != local_map->end()) {
// duplication may be needed!
if (poly.dup_vertices()[j] == 0) {
// duplicate point
points_->push_back(points_->at(*i));
int new_index = static_cast<int>(points_->size())-1;
// duplicate normal
(*normals_.get())[new_index] = (*normals_.get())[*i];
// duplicate share
shares_.push_back(shares_.at(*i));
VertexMap_map::iterator vm;
// duplicate weights
for (vm=weight_maps()->begin(); vm!=weight_maps()->end(); ++vm) {
if (vm->second->find(*i) != vm->second->end())
(*vm->second.get())[new_index] = (*vm->second.get())[*i];
}
// duplicate subpatch weights
for (vm=subpatch_weight_maps()->begin(); vm!=subpatch_weight_maps()->end(); ++vm) {
if (vm->second->find(*i) != vm->second->end())
(*vm->second.get())[new_index] = (*vm->second.get())[*i];
}
// duplicate texture UVs
for (vm=texture_maps()->begin(); vm!=texture_maps()->end(); ++vm) {
if (vm->second->find(*i) != vm->second->end())
(*vm->second.get())[new_index] = (*vm->second.get())[*i];
}
// duplicate RGBs
for (vm=rgb_maps()->begin(); vm!=rgb_maps()->end(); ++vm) {
if (vm->second->find(*i) != vm->second->end())
(*vm->second.get())[new_index] = (*vm->second.get())[*i];
}
// duplicate RGBAs
for (vm=rgba_maps()->begin(); vm!=rgba_maps()->end(); ++vm) {
if (vm->second->find(*i) != vm->second->end())
(*vm->second.get())[new_index] = (*vm->second.get())[*i];
}
// duplicate displacements
for (vm=displacement_maps()->begin(); vm!=displacement_maps()->end(); ++vm) {
if (vm->second->find(*i) != vm->second->end())
(*vm->second.get())[new_index] = (*vm->second.get())[*i];
}
// duplicate spots
for (vm=spot_maps()->begin(); vm!=spot_maps()->end(); ++vm) {
if (vm->second->find(*i) != vm->second->end())
(*vm->second.get())[new_index] = (*vm->second.get())[*i];
}
// update vertex index
poly.dup_vertices()[j] = *i;
*i = new_index;
}
(*global_map)[*i] = k->second;
}
}
}
void Unit::compute_vertex_remapping(const Surface *surf, Index_list &remap) const
{
remap.assign(points_->size(), -1);
for (Polygon_list::const_iterator i=polygons_.begin(); i!=polygons_.end(); ++i) {
if (i->get_surface() == surf) {
for (Polygon::Index_list::const_iterator j=i->indices().begin(); j!=i->indices().end(); ++j) {
remap[*j] = *j;
}
}
}
int offset = 0;
for (Index_list::iterator j=remap.begin(); j!=remap.end(); ++j) {
if (*j == -1) {
++offset;
} else {
*j -= offset;
}
}
}

91
src/osgPlugins/lwo/Unit.h Normal file
View File

@@ -0,0 +1,91 @@
/*******************************************************
Lightwave Object Loader for OSG
Copyright (C) 2004 Marco Jez <marco.jez@poste.it>
OpenSceneGraph is (C) 2004 Robert Osfield
********************************************************/
#ifndef LWOSG_UNIT_
#define LWOSG_UNIT_
#include "Polygon.h"
#include "VertexMap.h"
#include <osg/ref_ptr>
#include <osg/Array>
#include <vector>
namespace lwosg
{
class Unit {
public:
typedef std::vector<Polygon> Polygon_list;
typedef std::vector<int> Index_list;
typedef std::vector<Index_list> Sharing_list;
Unit();
inline osg::Vec3Array *points() { return points_.get(); }
inline const osg::Vec3Array *points() const { return points_.get(); }
inline VertexMap *normals() { return normals_.get(); }
inline const VertexMap *normals() const { return normals_.get(); }
inline Polygon_list &polygons() { return polygons_; }
inline const Polygon_list &polygons() const { return polygons_; }
inline Sharing_list &shares() { return shares_; }
inline const Sharing_list &shares() const { return shares_; }
inline const VertexMap_map *weight_maps() const { return weight_maps_.get(); }
inline VertexMap_map *weight_maps() { return weight_maps_.get(); }
inline const VertexMap_map *subpatch_weight_maps() const { return subpatch_weight_maps_.get(); }
inline VertexMap_map *subpatch_weight_maps() { return subpatch_weight_maps_.get(); }
inline const VertexMap_map *texture_maps() const { return texture_maps_.get(); }
inline VertexMap_map *texture_maps() { return texture_maps_.get(); }
inline const VertexMap_map *rgb_maps() const { return rgb_maps_.get(); }
inline VertexMap_map *rgb_maps() { return rgb_maps_.get(); }
inline const VertexMap_map *rgba_maps() const { return rgba_maps_.get(); }
inline VertexMap_map *rgba_maps() { return rgba_maps_.get(); }
inline const VertexMap_map *displacement_maps() const { return displacement_maps_.get(); }
inline VertexMap_map *displacement_maps() { return displacement_maps_.get(); }
inline const VertexMap_map *spot_maps() const { return spot_maps_.get(); }
inline VertexMap_map *spot_maps() { return spot_maps_.get(); }
void flatten_maps();
void generate_normals();
void compute_vertex_remapping(const Surface *surf, Index_list &remap) const;
protected:
float angle_between_polygons(const Polygon &p1, const Polygon &p2) const;
void find_shared_polygons(int vertex_index, std::vector<int> &poly_indices);
void flatten_map(Polygon &poly, const VertexMap *local_map, VertexMap *global_map);
private:
osg::ref_ptr<osg::Vec3Array> points_;
Polygon_list polygons_;
Sharing_list shares_;
osg::ref_ptr<VertexMap> normals_;
osg::ref_ptr<VertexMap_map> weight_maps_;
osg::ref_ptr<VertexMap_map> subpatch_weight_maps_;
osg::ref_ptr<VertexMap_map> texture_maps_;
osg::ref_ptr<VertexMap_map> rgb_maps_;
osg::ref_ptr<VertexMap_map> rgba_maps_;
osg::ref_ptr<VertexMap_map> displacement_maps_;
osg::ref_ptr<VertexMap_map> spot_maps_;
};
}
#endif

View File

@@ -0,0 +1,81 @@
/*******************************************************
Lightwave Object Loader for OSG
Copyright (C) 2004 Marco Jez <marco.jez@poste.it>
OpenSceneGraph is (C) 2004 Robert Osfield
********************************************************/
#include "VertexMap.h"
#include <osg/Notify>
using namespace lwosg;
osg::Vec4Array *VertexMap::asVec4Array(int num_vertices, const osg::Vec4 &default_value, const osg::Vec4 &modulator) const
{
osg::ref_ptr<osg::Vec4Array> array = new osg::Vec4Array;
array->assign(num_vertices, default_value);
for (VertexMap::const_iterator i=begin(); i!=end(); ++i) {
osg::Vec4 value = i->second;
value.x() *= modulator.x();
value.y() *= modulator.y();
value.z() *= modulator.z();
value.w() *= modulator.w();
array->at(i->first) = value;
}
return array.take();
}
osg::Vec2Array *VertexMap::asVec2Array(int num_vertices, const osg::Vec2 &default_value, const osg::Vec2 &modulator) const
{
osg::ref_ptr<osg::Vec2Array> array = new osg::Vec2Array;
array->assign(num_vertices, default_value);
for (VertexMap::const_iterator i=begin(); i!=end(); ++i) {
osg::Vec4 value = i->second;
value.x() *= modulator.x();
value.y() *= modulator.y();
array->at(i->first) = osg::Vec2(value.x(), value.y());
}
return array.take();
}
osg::Vec3Array *VertexMap::asVec3Array(int num_vertices, const osg::Vec3 &default_value, const osg::Vec3 &modulator) const
{
osg::ref_ptr<osg::Vec3Array> array = new osg::Vec3Array;
array->assign(num_vertices, default_value);
for (VertexMap::const_iterator i=begin(); i!=end(); ++i) {
osg::Vec4 value = i->second;
value.x() *= modulator.x();
value.y() *= modulator.y();
value.z() *= modulator.z();
array->at(i->first) = osg::Vec3(value.x(), value.y(), value.z());
}
return array.take();
}
VertexMap *VertexMap::remap(const std::vector<int> &remapping) const
{
osg::ref_ptr<VertexMap> result = new VertexMap;
for (VertexMap::const_iterator i=begin(); i!=end(); ++i) {
if (i->first >= static_cast<int>(remapping.size())) {
osg::notify(osg::WARN) << "Warning: lwosg::remap(): remapping index not found for vertex " << i->first << " (map size " << remapping.size() << ")" << std::endl;
} else {
int new_index = remapping[i->first];
if (new_index != -1) {
(*result.get())[new_index] = i->second;
}
}
}
return result.take();
}
VertexMap_map *VertexMap_map::remap(const std::vector<int> &remapping) const
{
osg::ref_ptr<VertexMap_map> result = new VertexMap_map;
for (VertexMap_map::const_iterator i=begin(); i!=end(); ++i) {
(*result.get())[i->first] = i->second->remap(remapping);
}
return result.take();
}

View File

@@ -0,0 +1,74 @@
/*******************************************************
Lightwave Object Loader for OSG
Copyright (C) 2004 Marco Jez <marco.jez@poste.it>
OpenSceneGraph is (C) 2004 Robert Osfield
********************************************************/
#ifndef LWOSG_VERTEXMAP_
#define LWOSG_VERTEXMAP_
#include <osg/Vec2>
#include <osg/Vec3>
#include <osg/Vec4>
#include <osg/Array>
#include <osg/Referenced>
#include <string>
#include <map>
#include <vector>
namespace lwosg
{
/////////////////////////////////////////////////////////////////////////
// VERTEX MAP
typedef std::map<int, osg::Vec4> VertexMap_impl;
class VertexMap: public VertexMap_impl, public osg::Referenced {
public:
VertexMap(): VertexMap_impl(), osg::Referenced() {}
osg::Vec2Array *asVec2Array(int num_vertices, const osg::Vec2 &default_value = osg::Vec2(0, 0), const osg::Vec2 &modulator = osg::Vec2(1, 1)) const;
osg::Vec3Array *asVec3Array(int num_vertices, const osg::Vec3 &default_value = osg::Vec3(0, 0, 0), const osg::Vec3 &modulator = osg::Vec3(1, 1, 1)) const;
osg::Vec4Array *asVec4Array(int num_vertices, const osg::Vec4 &default_value = osg::Vec4(0, 0, 0, 0), const osg::Vec4 &modulator = osg::Vec4(1, 1, 1, 1)) const;
VertexMap *remap(const std::vector<int> &remapping) const;
protected:
virtual ~VertexMap() {}
VertexMap &operator=(const VertexMap &) { return *this; }
};
/////////////////////////////////////////////////////////////////////////
// VERTEX MAP MAP
typedef std::map<std::string, osg::ref_ptr<VertexMap> > VertexMap_map_impl;
class VertexMap_map: public VertexMap_map_impl, public osg::Referenced {
public:
VertexMap_map(): VertexMap_map_impl(), osg::Referenced() {}
VertexMap *getOrCreate(const std::string &name)
{
osg::ref_ptr<VertexMap> &vmap = operator[](name);
if (!vmap.valid()) {
vmap = new VertexMap;
}
return vmap.get();
}
VertexMap_map *remap(const std::vector<int> &remapping) const;
protected:
virtual ~VertexMap_map() {}
VertexMap_map &operator=(const VertexMap_map &) { return *this; }
private:
};
}
#endif

View File

@@ -0,0 +1,114 @@
/*******************************************************
Lightwave Object Loader for OSG
Copyright (C) 2004 Marco Jez <marco.jez@poste.it>
OpenSceneGraph is (C) 2004 Robert Osfield
********************************************************/
#ifndef IFFPARSER_
#define IFFPARSER_
#include <vector>
#include <iostream>
namespace iff
{
typedef std::vector<struct Chunk *> Chunk_list;
struct Chunk {
virtual ~Chunk()
{
Chunk_list *fod = free_on_destroy();
if (fod) {
for (Chunk_list::iterator i=fod->begin(); i!=fod->end(); ++i) {
delete *i;
}
}
}
virtual Chunk_list *free_on_destroy() { return 0; }
};
template<typename Iter>
class GenericParser {
public:
GenericParser();
GenericParser(std::ostream &os);
virtual ~GenericParser();
void clear();
void parse(Iter begin, Iter end);
inline const Chunk_list &chunks() const;
protected:
virtual Chunk *parse_chunk_data(const std::string &tag, const std::string &context, Iter it, Iter end) = 0;
Chunk *parse_chunk(Iter &it, const std::string &context);
inline std::ostream &os() { return os_; }
private:
Chunk_list chunks_;
std::ostream &os_;
};
/////////////////////////////////////////////////////////////////////////
// IMPLEMENTATION OF TEMPLATE FUNCTIONS
# define IP_TMP template<class Iter>
IP_TMP GenericParser<Iter>::GenericParser()
: os_(std::cout)
{
}
IP_TMP GenericParser<Iter>::GenericParser(std::ostream &os)
: os_(os)
{
}
IP_TMP GenericParser<Iter>::~GenericParser()
{
}
IP_TMP void GenericParser<Iter>::clear()
{
chunks_.clear();
}
IP_TMP void GenericParser<Iter>::parse(Iter begin, Iter end)
{
Iter it = begin;
while (it < end) {
Chunk *chk = parse_chunk(it, "");
if (chk) chunks_.push_back(chk);
}
}
IP_TMP Chunk *GenericParser<Iter>::parse_chunk(Iter &it, const std::string &context)
{
std::string tag;
for (int i=0; i<4; ++i) tag.push_back(*(it++));
unsigned int len = ((static_cast<unsigned int>(*(it++)) & 0xFF) << 24) |
((static_cast<unsigned int>(*(it++)) & 0xFF) << 16) |
((static_cast<unsigned int>(*(it++)) & 0xFF) << 8) |
(static_cast<unsigned int>(*(it++)) & 0xFF);
os_ << "DEBUG INFO: iffparser: reading chunk " << tag << ", length = " << len << ", context = " << context << "\n";
Chunk *chk = parse_chunk_data(tag, context, it, it+len);
if (!chk) os_ << "DEBUG INFO: iffparser: \tprevious chunk not handled\n";
it += len;
if ((len % 2) != 0) ++it;
return chk;
}
IP_TMP const Chunk_list &GenericParser<Iter>::chunks() const
{
return chunks_;
}
}
#endif

View File

@@ -0,0 +1,623 @@
/****************************************************************************
Chunk definitions for the LWO2 file format
Copyright (C) 2002 by Marco Jez
****************************************************************************/
#ifndef LWO2CHUNKS_
#define LWO2CHUNKS_
#ifdef _MSC_VER
# pragma warning ( disable : 4786 )
#endif
#include <vector>
#include "iffparser.h"
#include "lwo2types.h"
#define CHUNK(name) struct name: public iff::Chunk
#define SUBCHUNK CHUNK
#define FREE_ON_DESTROY(list) iff::Chunk_list *free_on_destroy() { return &list; }
namespace lwo2
{
typedef iff::Chunk SubChunk;
CHUNK (FORM) {
ID4 type;
iff::Chunk_list data;
FREE_ON_DESTROY(data);
CHUNK (LAYR) {
U2 number;
U2 flags;
VEC12 pivot;
S0 name;
I2 parent;
};
CHUNK (PNTS) {
typedef std::vector<VEC12> Point_list;
Point_list point_location;
};
CHUNK (VMAP) {
ID4 type;
U2 dimension;
S0 name;
struct mapping_type {
VX vert;
std::vector<F4> value;
};
typedef std::vector<mapping_type> Mapping_list;
Mapping_list mapping;
};
CHUNK (POLS) {
ID4 type;
struct polygon_type {
U2 numvert;
U2 flags;
std::vector<VX> vert;
};
typedef std::vector<polygon_type> Polygon_list;
Polygon_list polygons;
};
CHUNK (TAGS) {
typedef std::vector<S0> String_list;
String_list tag_string;
};
CHUNK (PTAG) {
ID4 type;
struct mapping_type {
VX poly;
U2 tag;
};
typedef std::vector<mapping_type> Mapping_list;
Mapping_list mapping;
};
CHUNK (VMAD) {
ID4 type;
U2 dimension;
S0 name;
struct mapping_type {
VX vert;
VX poly;
std::vector<F4> value;
};
typedef std::vector<mapping_type> Mapping_list;
Mapping_list mapping;
};
CHUNK (ENVL) {
VX index;
iff::Chunk_list attributes;
FREE_ON_DESTROY(attributes);
SUBCHUNK (TYPE) {
U1 user_format;
U1 type;
};
SUBCHUNK (PRE) {
U2 type;
};
SUBCHUNK (POST) {
U2 type;
};
SUBCHUNK (KEY) {
F4 time;
F4 value;
};
SUBCHUNK (SPAN) {
ID4 type;
std::vector<F4> parameters;
};
SUBCHUNK (CHAN) {
S0 server_name;
U2 flags;
std::vector<U1> data;
};
SUBCHUNK (NAME) {
S0 channel_name;
};
};
CHUNK (CLIP) {
U4 index;
iff::Chunk_list attributes;
FREE_ON_DESTROY(attributes);
SUBCHUNK (STIL) {
FNAM0 name;
};
SUBCHUNK (ISEQ) {
U1 num_digits;
U1 flags;
I2 offset;
U2 reserved;
I2 start;
I2 end;
FNAM0 prefix;
S0 suffix;
};
SUBCHUNK (ANIM) {
FNAM0 filename;
S0 server_name;
U2 flags;
std::vector<U1> data;
};
SUBCHUNK (XREF) {
U4 index;
S0 string;
};
SUBCHUNK (STCC) {
I2 lo;
I2 hi;
FNAM0 name;
};
SUBCHUNK (TIME) {
FP4 start_time;
FP4 duration;
FP4 frame_rate;
};
SUBCHUNK (CONT) {
FP4 contrast_delta;
VX envelope;
};
SUBCHUNK (BRIT) {
FP4 brightness_delta;
VX envelope;
};
SUBCHUNK (SATR) {
FP4 saturation_delta;
VX envelope;
};
SUBCHUNK (HUE) {
FP4 hue_rotation;
VX envelope;
};
SUBCHUNK (GAMM) {
F4 gamma;
VX envelope;
};
SUBCHUNK (NEGA) {
U2 enable;
};
SUBCHUNK (IFLT) {
S0 server_name;
U2 flags;
std::vector<U1> data;
};
SUBCHUNK (PFLT) {
S0 server_name;
U2 flags;
std::vector<U1> data;
};
};
CHUNK (SURF) {
S0 name;
S0 source;
iff::Chunk_list attributes;
FREE_ON_DESTROY(attributes);
SUBCHUNK (COLR) {
COL12 base_color;
VX envelope;
};
SUBCHUNK (DIFF) {
FP4 intensity;
VX envelope;
};
SUBCHUNK (LUMI) {
FP4 intensity;
VX envelope;
};
SUBCHUNK (SPEC) {
FP4 intensity;
VX envelope;
};
SUBCHUNK (REFL) {
FP4 intensity;
VX envelope;
};
SUBCHUNK (TRAN) {
FP4 intensity;
VX envelope;
};
SUBCHUNK (TRNL) {
FP4 intensity;
VX envelope;
};
SUBCHUNK (GLOS) {
FP4 glossiness;
VX envelope;
};
SUBCHUNK (SHRP) {
FP4 sharpness;
VX envelope;
};
SUBCHUNK (BUMP) {
FP4 strength;
VX envelope;
};
SUBCHUNK (SIDE) {
U2 sidedness;
};
SUBCHUNK (SMAN) {
ANG4 max_smoothing_angle;
};
SUBCHUNK (RFOP) {
U2 reflection_options;
};
SUBCHUNK (RIMG) {
VX image;
};
SUBCHUNK (RSAN) {
ANG4 seam_angle;
VX envelope;
};
SUBCHUNK (RBLR) {
FP4 blur_percentage;
VX envelope;
};
SUBCHUNK (RIND) {
F4 refractive_index;
VX envelope;
};
SUBCHUNK (TROP) {
U2 transparency_options;
};
SUBCHUNK (TIMG) {
VX image;
};
SUBCHUNK (TBLR) {
FP4 blur_percentage;
VX envelope;
};
SUBCHUNK (CLRH) {
FP4 color_highlights;
VX envelope;
};
SUBCHUNK (CLRF) {
FP4 color_filter;
VX envelope;
};
SUBCHUNK (ADTR) {
FP4 additive;
VX envelope;
};
SUBCHUNK (GLOW) {
U2 type;
F4 intensity;
VX intensity_envelope;
F4 size;
VX size_envelope;
};
SUBCHUNK (LINE) {
U2 flags;
F4 size;
VX size_envelope;
COL12 color;
VX color_envelope;
};
SUBCHUNK (ALPH) {
U2 mode;
FP4 value;
};
SUBCHUNK (VCOL) {
FP4 intensity;
VX envelope;
ID4 vmap_type;
S0 name;
};
// surface blocks
SUBCHUNK (BLOK) {
SubChunk *header;
iff::Chunk_list attributes;
FREE_ON_DESTROY(attributes);
// block headers
SUBCHUNK (IMAP) {
S0 ordinal;
iff::Chunk_list block_attributes; // common attributes (see above)
FREE_ON_DESTROY(block_attributes);
// attributes specific to IMAP and PROC
SUBCHUNK (TMAP) {
iff::Chunk_list attributes;
FREE_ON_DESTROY(attributes);
SUBCHUNK (CNTR) {
VEC12 vector;
VX envelope;
};
SUBCHUNK (SIZE) {
VEC12 vector;
VX envelope;
};
SUBCHUNK (ROTA) {
VEC12 vector;
VX envelope;
};
SUBCHUNK (OREF) {
S0 object_name;
};
SUBCHUNK (FALL) {
U2 type;
VEC12 vector;
VX envelope;
};
SUBCHUNK (CSYS) {
U2 type;
};
};
// attributes specific to image maps
SUBCHUNK (PROJ) {
U2 projection_mode;
};
SUBCHUNK (AXIS) {
U2 texture_axis;
};
SUBCHUNK (IMAG) {
VX texture_image;
};
SUBCHUNK (WRAP) {
U2 width_wrap;
U2 height_wrap;
};
SUBCHUNK (WRPW) {
FP4 cycles;
VX envelope;
};
SUBCHUNK (WRPH) {
FP4 cycles;
VX envelope;
};
SUBCHUNK (VMAP) {
S0 txuv_map_name;
};
SUBCHUNK (AAST) {
U2 flags;
FP4 antialiasing_strength;
};
SUBCHUNK (PIXB) {
U2 flags;
};
SUBCHUNK (STCK) {
U2 on_off;
FP4 time;
};
SUBCHUNK (TAMP) {
FP4 amplitude;
VX envelope;
};
};
SUBCHUNK (PROC) {
S0 ordinal;
iff::Chunk_list block_attributes;
FREE_ON_DESTROY(block_attributes);
typedef IMAP::TMAP TMAP;
// attributes specific to procedural textures
SUBCHUNK (AXIS) {
U2 axis;
};
SUBCHUNK (VALU) {
std::vector<FP4> value;
};
SUBCHUNK (FUNC) {
S0 algorithm_name;
std::vector<U1> data;
};
};
SUBCHUNK (GRAD) {
S0 ordinal;
iff::Chunk_list block_attributes;
FREE_ON_DESTROY(block_attributes);
// attributes specific to gradient textures
SUBCHUNK (PNAM) {
S0 parameter;
};
SUBCHUNK (INAM) {
S0 item_name;
};
SUBCHUNK (GRST) {
FP4 input_range;
};
SUBCHUNK (GREN) {
FP4 input_range;
};
SUBCHUNK (GRPT) {
U2 repeat_mode;
};
SUBCHUNK (FKEY) {
struct value_type {
FP4 input;
FP4 output[4];
};
typedef std::vector<value_type> Value_list;
Value_list values;
};
SUBCHUNK (IKEY) {
std::vector<U2> interpolation;
};
};
SUBCHUNK (SHDR) {
S0 ordinal;
iff::Chunk_list block_attributes;
FREE_ON_DESTROY(block_attributes);
// attributes specific to shaders
SUBCHUNK (FUNC) {
S0 algorithm_name;
std::vector<U1> data;
};
};
// attributes common to all header types
SUBCHUNK (CHAN) {
ID4 texture_channel;
};
SUBCHUNK (ENAB) {
U2 enable;
};
SUBCHUNK (OPAC) {
U2 type;
FP4 opacity;
VX envelope;
};
SUBCHUNK (AXIS) {
U2 displacement_axis;
};
};
};
CHUNK (BBOX) {
VEC12 min;
VEC12 max;
};
CHUNK (DESC) {
S0 description_line;
};
CHUNK (TEXT) {
S0 comment;
};
CHUNK (ICON) {
U2 encoding;
U2 width;
std::vector<U1> data;
};
};
}
#endif

View File

@@ -0,0 +1,908 @@
/*******************************************************
Lightwave Object Loader for OSG
Copyright (C) 2004 Marco Jez <marco.jez@poste.it>
OpenSceneGraph is (C) 2004 Robert Osfield
********************************************************/
#ifndef LWO2PARSER_
#define LWO2PARSER_
#include "iffparser.h"
#include "lwo2chunks.h"
#include "lwo2read.h"
#include <stdexcept>
#include <vector>
namespace lwo2
{
class parser_error: public std::runtime_error {
public:
parser_error(const std::string &message): std::runtime_error("[LWO2 parser error] " + message) {}
};
template<typename Iter>
class Parser: public iff::GenericParser<Iter> {
public:
Parser();
Parser(std::ostream &os);
virtual ~Parser();
protected:
virtual iff::Chunk *parse_chunk_data(const std::string &tag, const std::string &context, Iter it, Iter end);
iff::Chunk *parse_subchunk(Iter &it, const std::string &context);
};
/////////////////////////////////////////////////////////////////////////
// IMPLEMENTATION OF TEMPLATE FUNCTIONS
# define LP_TMP template<class Iter>
LP_TMP Parser<Iter>::Parser()
: iff::GenericParser<Iter>()
{
}
LP_TMP Parser<Iter>::Parser(std::ostream &os)
: iff::GenericParser<Iter>(os)
{
}
LP_TMP Parser<Iter>::~Parser()
{
}
LP_TMP iff::Chunk *Parser<Iter>::parse_chunk_data(const std::string &tag, const std::string &context, Iter it, Iter end)
{
// GLOBAL CONTEXT
if (context.empty()) {
if (tag == "FORM") {
FORM *chk = new FORM;
chk->type = read_ID4(it);
if (std::string(chk->type.id, 4) != "LWO2") {
throw parser_error("invalid file format");
}
while (it < end)
chk->data.push_back(parse_chunk(it, "FORM"));
return chk;
}
}
// FORM CONTEXT
if (context == "FORM") {
if (tag == "LAYR") {
FORM::LAYR *chk = new FORM::LAYR;
chk->number = read_U2(it);
chk->flags = read_U2(it);
chk->pivot = read_VEC12(it);
chk->name = read_S0(it);
if (it < end) {
chk->parent = read_I2(it);
} else {
chk->parent = -1;
}
return chk;
}
if (tag == "PNTS") {
FORM::PNTS *chk = new FORM::PNTS;
while (it < end) {
chk->point_location.push_back(read_VEC12(it));
}
return chk;
}
if (tag == "VMAP") {
FORM::VMAP *chk = new FORM::VMAP;
chk->type = read_ID4(it);
chk->dimension = read_U2(it);
chk->name = read_S0(it);
while (it < end) {
FORM::VMAP::mapping_type mp;
mp.vert = read_VX(it);
for (int i=0; i<chk->dimension; ++i) {
mp.value.push_back(read_F4(it));
}
chk->mapping.push_back(mp);
}
return chk;
}
if (tag == "POLS") {
FORM::POLS *chk = new FORM::POLS;
chk->type = read_ID4(it);
while (it < end) {
FORM::POLS::polygon_type pl;
U2 nvf = read_U2(it);
pl.flags = nvf >> 10;
pl.numvert = nvf & 0x03FF;
for (int i=0; i<pl.numvert; ++i)
pl.vert.push_back(read_VX(it));
chk->polygons.push_back(pl);
}
return chk;
}
if (tag == "TAGS") {
FORM::TAGS *chk = new FORM::TAGS;
while (it < end) {
std::string tags = read_S0(it);
chk->tag_string.push_back(tags);
}
return chk;
}
if (tag == "PTAG") {
FORM::PTAG *chk = new FORM::PTAG;
chk->type = read_ID4(it);
while (it < end) {
FORM::PTAG::mapping_type mp;
mp.poly = read_VX(it);
mp.tag = read_U2(it);
chk->mapping.push_back(mp);
}
return chk;
}
if (tag == "VMAD") {
FORM::VMAD *chk = new FORM::VMAD;
chk->type = read_ID4(it);
chk->dimension = read_U2(it);
chk->name = read_S0(it);
while (it < end) {
FORM::VMAD::mapping_type mp;
mp.vert = read_VX(it);
mp.poly = read_VX(it);
for (int i=0; i<chk->dimension; ++i)
mp.value.push_back(read_F4(it));
chk->mapping.push_back(mp);
}
return chk;
}
if (tag == "ENVL") {
FORM::ENVL *chk = new FORM::ENVL;
chk->index = read_VX(it);
while (it < end) {
chk->attributes.push_back(parse_subchunk(it, "FORM::ENVL"));
}
return chk;
}
if (tag == "CLIP") {
FORM::CLIP *chk = new FORM::CLIP;
chk->index = read_U4(it);
while (it < end) {
chk->attributes.push_back(parse_subchunk(it, "FORM::CLIP"));
}
return chk;
}
if (tag == "SURF") {
FORM::SURF *chk = new FORM::SURF;
chk->name = read_S0(it);
chk->source = read_S0(it);
while (it < end) {
chk->attributes.push_back(parse_subchunk(it, "FORM::SURF"));
}
return chk;
}
if (tag == "BBOX") {
FORM::BBOX *chk = new FORM::BBOX;
chk->min = read_VEC12(it);
chk->max = read_VEC12(it);
return chk;
}
if (tag == "DESC") {
FORM::DESC *chk = new FORM::DESC;
chk->description_line = read_S0(it);
return chk;
}
if (tag == "TEXT") {
FORM::TEXT *chk = new FORM::TEXT;
chk->comment = read_S0(it);
return chk;
}
if (tag == "ICON") {
FORM::ICON *chk = new FORM::ICON;
chk->encoding = read_U2(it);
chk->width = read_U2(it);
while (it < end) chk->data.push_back(read_U1(it));
return chk;
}
}
// ENVELOPE CONTEXT
if (context == "FORM::ENVL") {
if (tag == "TYPE") {
FORM::ENVL::TYPE *chk = new FORM::ENVL::TYPE;
chk->user_format = read_U1(it);
chk->type = read_U1(it);
return chk;
}
if (tag == "PRE ") {
FORM::ENVL::PRE *chk = new FORM::ENVL::PRE;
chk->type = read_U2(it);
return chk;
}
if (tag == "POST") {
FORM::ENVL::POST *chk = new FORM::ENVL::POST;
chk->type = read_U2(it);
return chk;
}
if (tag == "KEY ") {
FORM::ENVL::KEY *chk = new FORM::ENVL::KEY;
chk->time = read_F4(it);
chk->value = read_F4(it);
return chk;
}
if (tag == "SPAN") {
FORM::ENVL::SPAN *chk = new FORM::ENVL::SPAN;
chk->type = read_ID4(it);
while (it < end) chk->parameters.push_back(read_F4(it));
return chk;
}
if (tag == "CHAN") {
FORM::ENVL::CHAN *chk = new FORM::ENVL::CHAN;
chk->server_name = read_S0(it);
chk->flags = read_U2(it);
while (it < end) chk->data.push_back(read_U1(it));
return chk;
}
if (tag == "NAME") {
FORM::ENVL::NAME *chk = new FORM::ENVL::NAME;
chk->channel_name = read_S0(it);
return chk;
}
}
// CLIP CONTEXT
if (context == "FORM::CLIP") {
if (tag == "STIL") {
FORM::CLIP::STIL *chk = new FORM::CLIP::STIL;
chk->name = read_FNAM0(it);
return chk;
}
if (tag == "ISEQ") {
FORM::CLIP::ISEQ *chk = new FORM::CLIP::ISEQ;
chk->num_digits = read_U1(it);
chk->flags = read_U1(it);
chk->offset = read_I2(it);
chk->reserved = read_U2(it);
chk->start = read_I2(it);
chk->end = read_I2(it);
chk->prefix = read_FNAM0(it);
chk->suffix = read_S0(it);
return chk;
}
if (tag == "ANIM") {
FORM::CLIP::ANIM *chk = new FORM::CLIP::ANIM;
chk->filename = read_FNAM0(it);
chk->server_name = read_S0(it);
chk->flags = read_U2(it);
while (it < end) chk->data.push_back(read_U1(it));
return chk;
}
if (tag == "XREF") {
FORM::CLIP::XREF *chk = new FORM::CLIP::XREF;
chk->index = read_U4(it);
chk->string = read_S0(it);
return chk;
}
if (tag == "STCC") {
FORM::CLIP::STCC *chk = new FORM::CLIP::STCC;
chk->lo = read_I2(it);
chk->hi = read_I2(it);
chk->name = read_FNAM0(it);
}
if (tag == "TIME") {
FORM::CLIP::TIME *chk = new FORM::CLIP::TIME;
chk->start_time = read_FP4(it);
chk->duration = read_FP4(it);
chk->frame_rate = read_FP4(it);
return chk;
}
if (tag == "CONT") {
FORM::CLIP::CONT *chk = new FORM::CLIP::CONT;
chk->contrast_delta = read_FP4(it);
chk->envelope = read_VX(it);
return chk;
}
if (tag == "BRIT") {
FORM::CLIP::BRIT *chk = new FORM::CLIP::BRIT;
chk->brightness_delta = read_FP4(it);
chk->envelope = read_VX(it);
return chk;
}
if (tag == "SATR") {
FORM::CLIP::SATR *chk = new FORM::CLIP::SATR;
chk->saturation_delta = read_FP4(it);
chk->envelope = read_VX(it);
return chk;
}
if (tag == "HUE ") {
FORM::CLIP::HUE *chk = new FORM::CLIP::HUE;
chk->hue_rotation = read_FP4(it);
chk->envelope = read_VX(it);
return chk;
}
if (tag == "GAMM") {
FORM::CLIP::GAMM *chk = new FORM::CLIP::GAMM;
chk->gamma = read_F4(it);
chk->envelope = read_VX(it);
return chk;
}
if (tag == "NEGA") {
FORM::CLIP::NEGA *chk = new FORM::CLIP::NEGA;
chk->enable = read_U2(it);
return chk;
}
if (tag == "IFLT") {
FORM::CLIP::IFLT *chk = new FORM::CLIP::IFLT;
chk->server_name = read_S0(it);
chk->flags = read_U2(it);
while (it < end) chk->data.push_back(read_U1(it));
return chk;
}
if (tag == "PFLT") {
FORM::CLIP::PFLT *chk = new FORM::CLIP::PFLT;
chk->server_name = read_S0(it);
chk->flags = read_U2(it);
while (it < end) chk->data.push_back(read_U1(it));
return chk;
}
}
// SURFACE CONTEXT
if (context == "FORM::SURF") {
if (tag == "COLR") {
FORM::SURF::COLR *chk = new FORM::SURF::COLR;
chk->base_color = read_COL12(it);
chk->envelope = read_VX(it);
return chk;
}
if (tag == "DIFF") {
FORM::SURF::DIFF *chk = new FORM::SURF::DIFF;
chk->intensity = read_FP4(it);
chk->envelope = read_VX(it);
return chk;
}
if (tag == "LUMI") {
FORM::SURF::LUMI *chk = new FORM::SURF::LUMI;
chk->intensity = read_FP4(it);
chk->envelope = read_VX(it);
return chk;
}
if (tag == "SPEC") {
FORM::SURF::SPEC *chk = new FORM::SURF::SPEC;
chk->intensity = read_FP4(it);
chk->envelope = read_VX(it);
return chk;
}
if (tag == "REFL") {
FORM::SURF::REFL *chk = new FORM::SURF::REFL;
chk->intensity = read_FP4(it);
chk->envelope = read_VX(it);
return chk;
}
if (tag == "TRAN") {
FORM::SURF::TRAN *chk = new FORM::SURF::TRAN;
chk->intensity = read_FP4(it);
chk->envelope = read_VX(it);
return chk;
}
if (tag == "TRNL") {
FORM::SURF::TRNL *chk = new FORM::SURF::TRNL;
chk->intensity = read_FP4(it);
chk->envelope = read_VX(it);
return chk;
}
if (tag == "GLOS") {
FORM::SURF::GLOS *chk = new FORM::SURF::GLOS;
chk->glossiness = read_FP4(it);
chk->envelope = read_VX(it);
return chk;
}
if (tag == "SHRP") {
FORM::SURF::SHRP *chk = new FORM::SURF::SHRP;
chk->sharpness = read_FP4(it);
chk->envelope = read_VX(it);
return chk;
}
if (tag == "BUMP") {
FORM::SURF::BUMP *chk = new FORM::SURF::BUMP;
chk->strength = read_FP4(it);
chk->envelope = read_VX(it);
return chk;
}
if (tag == "SIDE") {
FORM::SURF::SIDE *chk = new FORM::SURF::SIDE;
chk->sidedness = read_U2(it);
return chk;
}
if (tag == "SMAN") {
FORM::SURF::SMAN *chk = new FORM::SURF::SMAN;
chk->max_smoothing_angle = read_ANG4(it);
return chk;
}
if (tag == "RFOP") {
FORM::SURF::RFOP *chk = new FORM::SURF::RFOP;
chk->reflection_options = read_U2(it);
return chk;
}
if (tag == "RIMG") {
FORM::SURF::RIMG *chk = new FORM::SURF::RIMG;
chk->image = read_VX(it);
return chk;
}
if (tag == "RSAN") {
FORM::SURF::RSAN *chk = new FORM::SURF::RSAN;
chk->seam_angle = read_ANG4(it);
chk->envelope = read_VX(it);
return chk;
}
if (tag == "RBLR") {
FORM::SURF::RBLR *chk = new FORM::SURF::RBLR;
chk->blur_percentage = read_FP4(it);
chk->envelope = read_VX(it);
return chk;
}
if (tag == "RIND") {
FORM::SURF::RIND *chk = new FORM::SURF::RIND;
chk->refractive_index = read_F4(it);
chk->envelope = read_VX(it);
return chk;
}
if (tag == "TROP") {
FORM::SURF::TROP *chk = new FORM::SURF::TROP;
chk->transparency_options = read_U2(it);
return chk;
}
if (tag == "TIMG") {
FORM::SURF::TIMG *chk = new FORM::SURF::TIMG;
chk->image = read_VX(it);
return chk;
}
if (tag == "TBLR") {
FORM::SURF::TBLR *chk = new FORM::SURF::TBLR;
chk->blur_percentage = read_FP4(it);
chk->envelope = read_VX(it);
return chk;
}
if (tag == "CLRH") {
FORM::SURF::CLRH *chk = new FORM::SURF::CLRH;
chk->color_highlights = read_FP4(it);
chk->envelope = read_VX(it);
return chk;
}
if (tag == "CLRF") {
FORM::SURF::CLRF *chk = new FORM::SURF::CLRF;
chk->color_filter = read_FP4(it);
chk->envelope = read_VX(it);
return chk;
}
if (tag == "ADTR") {
FORM::SURF::ADTR *chk = new FORM::SURF::ADTR;
chk->additive = read_FP4(it);
chk->envelope = read_VX(it);
return chk;
}
if (tag == "GLOW") {
FORM::SURF::GLOW *chk = new FORM::SURF::GLOW;
chk->type = read_U2(it);
chk->intensity = read_F4(it);
chk->intensity_envelope = read_VX(it);
chk->size = read_F4(it);
chk->size_envelope = read_VX(it);
return chk;
}
if (tag == "LINE") {
FORM::SURF::LINE *chk = new FORM::SURF::LINE;
chk->flags = read_U2(it);
if (it < end) {
chk->size = read_F4(it);
chk->size_envelope = read_VX(it);
if (it < end) {
chk->color = read_COL12(it);
chk->color_envelope = read_VX(it);
}
}
return chk;
}
if (tag == "ALPH") {
FORM::SURF::ALPH *chk = new FORM::SURF::ALPH;
chk->mode = read_U2(it);
chk->value = read_FP4(it);
return chk;
}
if (tag == "VCOL") {
FORM::SURF::VCOL *chk = new FORM::SURF::VCOL;
chk->intensity = read_FP4(it);
chk->envelope = read_VX(it);
chk->vmap_type = read_ID4(it);
chk->name = read_S0(it);
return chk;
}
// surface blocks
if (tag == "BLOK") {
FORM::SURF::BLOK *chk = new FORM::SURF::BLOK;
std::string hid;
for (Iter tempit=it; tempit<(it+4); ++tempit) hid.push_back(*tempit);
chk->header = parse_subchunk(it, "FORM::SURF::BLOK");
while (it < end) {
chk->attributes.push_back(parse_subchunk(it, "FORM::SURF::BLOK::" + hid));
}
return chk;
}
}
if (context == "FORM::SURF::BLOK") { // block headers
if (tag == "IMAP") {
FORM::SURF::BLOK::IMAP *chk = new FORM::SURF::BLOK::IMAP;
chk->ordinal = read_S0(it);
while (it < end) {
chk->block_attributes.push_back(parse_subchunk(it, "FORM::SURF::BLOK"));
}
return chk;
}
if (tag == "PROC") {
FORM::SURF::BLOK::PROC *chk = new FORM::SURF::BLOK::PROC;
chk->ordinal = read_S0(it);
while (it < end) {
chk->block_attributes.push_back(parse_subchunk(it, "FORM::SURF::BLOK"));
}
return chk;
}
if (tag == "GRAD") {
FORM::SURF::BLOK::GRAD *chk = new FORM::SURF::BLOK::GRAD;
chk->ordinal = read_S0(it);
while (it < end) {
chk->block_attributes.push_back(parse_subchunk(it, "FORM::SURF::BLOK"));
}
return chk;
}
if (tag == "SHDR") {
FORM::SURF::BLOK::SHDR *chk = new FORM::SURF::BLOK::SHDR;
chk->ordinal = read_S0(it);
while (it < end) {
chk->block_attributes.push_back(parse_subchunk(it, "FORM::SURF::BLOK"));
}
return chk;
}
}
if (context == "FORM::SURF::BLOK") { // attributes common to all block headers
if (tag == "CHAN") {
FORM::SURF::BLOK::CHAN *chk = new FORM::SURF::BLOK::CHAN;
chk->texture_channel = read_ID4(it);
return chk;
}
if (tag == "ENAB") {
FORM::SURF::BLOK::ENAB *chk = new FORM::SURF::BLOK::ENAB;
chk->enable = read_U2(it);
return chk;
}
if (tag == "OPAC") {
FORM::SURF::BLOK::OPAC *chk = new FORM::SURF::BLOK::OPAC;
chk->type = read_U2(it);
chk->opacity = read_FP4(it);
chk->envelope = read_VX(it);
return chk;
}
if (tag == "AXIS") {
FORM::SURF::BLOK::AXIS *chk = new FORM::SURF::BLOK::AXIS;
chk->displacement_axis = read_U2(it);
return chk;
}
}
if (context == "FORM::SURF::BLOK::IMAP" || context == "FORM::SURF::BLOK::PROC") {
if (tag == "TMAP") {
FORM::SURF::BLOK::IMAP::TMAP *chk = new FORM::SURF::BLOK::IMAP::TMAP;
while (it < end) chk->attributes.push_back(parse_subchunk(it, "FORM::SURF::BLOK::IMAP/PROC::TMAP"));
return chk;
}
}
if (context == "FORM::SURF::BLOK::IMAP/PROC::TMAP") {
if (tag == "CNTR") {
FORM::SURF::BLOK::IMAP::TMAP::CNTR *chk = new FORM::SURF::BLOK::IMAP::TMAP::CNTR;
chk->vector = read_VEC12(it);
chk->envelope = read_VX(it);
return chk;
}
if (tag == "SIZE") {
FORM::SURF::BLOK::IMAP::TMAP::SIZE *chk = new FORM::SURF::BLOK::IMAP::TMAP::SIZE;
chk->vector = read_VEC12(it);
chk->envelope = read_VX(it);
return chk;
}
if (tag == "ROTA") {
FORM::SURF::BLOK::IMAP::TMAP::ROTA *chk = new FORM::SURF::BLOK::IMAP::TMAP::ROTA;
chk->vector = read_VEC12(it);
chk->envelope = read_VX(it);
return chk;
}
if (tag == "OREF") {
FORM::SURF::BLOK::IMAP::TMAP::OREF *chk = new FORM::SURF::BLOK::IMAP::TMAP::OREF;
chk->object_name = read_S0(it);
return chk;
}
if (tag == "FALL") {
FORM::SURF::BLOK::IMAP::TMAP::FALL *chk = new FORM::SURF::BLOK::IMAP::TMAP::FALL;
chk->type = read_U2(it);
chk->vector = read_VEC12(it);
chk->envelope = read_VX(it);
return chk;
}
if (tag == "CSYS") {
FORM::SURF::BLOK::IMAP::TMAP::CSYS *chk = new FORM::SURF::BLOK::IMAP::TMAP::CSYS;
chk->type = read_U2(it);
return chk;
}
}
if (context == "FORM::SURF::BLOK::IMAP") {
if (tag == "PROJ") {
FORM::SURF::BLOK::IMAP::PROJ *chk = new FORM::SURF::BLOK::IMAP::PROJ;
chk->projection_mode = read_U2(it);
return chk;
}
if (tag == "AXIS") {
FORM::SURF::BLOK::IMAP::AXIS *chk = new FORM::SURF::BLOK::IMAP::AXIS;
chk->texture_axis = read_U2(it);
return chk;
}
if (tag == "IMAG") {
FORM::SURF::BLOK::IMAP::IMAG *chk = new FORM::SURF::BLOK::IMAP::IMAG;
chk->texture_image = read_VX(it);
return chk;
}
if (tag == "WRAP") {
FORM::SURF::BLOK::IMAP::WRAP *chk = new FORM::SURF::BLOK::IMAP::WRAP;
chk->width_wrap = read_U2(it);
chk->height_wrap = read_U2(it);
return chk;
}
if (tag == "WRPW") {
FORM::SURF::BLOK::IMAP::WRPW *chk = new FORM::SURF::BLOK::IMAP::WRPW;
chk->cycles = read_FP4(it);
chk->envelope = read_VX(it);
return chk;
}
if (tag == "WRPH") {
FORM::SURF::BLOK::IMAP::WRPH *chk = new FORM::SURF::BLOK::IMAP::WRPH;
chk->cycles = read_FP4(it);
chk->envelope = read_VX(it);
return chk;
}
if (tag == "VMAP") {
FORM::SURF::BLOK::IMAP::VMAP *chk = new FORM::SURF::BLOK::IMAP::VMAP;
chk->txuv_map_name = read_S0(it);
return chk;
}
if (tag == "AAST") {
FORM::SURF::BLOK::IMAP::AAST *chk = new FORM::SURF::BLOK::IMAP::AAST;
chk->flags = read_U2(it);
chk->antialiasing_strength = read_FP4(it);
return chk;
}
if (tag == "PIXB") {
FORM::SURF::BLOK::IMAP::PIXB *chk = new FORM::SURF::BLOK::IMAP::PIXB;
chk->flags = read_U2(it);
return chk;
}
if (tag == "STCK") {
FORM::SURF::BLOK::IMAP::STCK *chk = new FORM::SURF::BLOK::IMAP::STCK;
chk->on_off = read_U2(it);
chk->time = read_FP4(it);
return chk;
}
if (tag == "TAMP") {
FORM::SURF::BLOK::IMAP::TAMP *chk = new FORM::SURF::BLOK::IMAP::TAMP;
chk->amplitude = read_FP4(it);
chk->envelope = read_VX(it);
return chk;
}
}
if (context == "FORM::SURF::BLOK::PROC") {
if (tag == "AXIS") {
FORM::SURF::BLOK::PROC::AXIS *chk = new FORM::SURF::BLOK::PROC::AXIS;
chk->axis = read_U2(it);
return chk;
}
if (tag == "VALU") {
FORM::SURF::BLOK::PROC::VALU *chk = new FORM::SURF::BLOK::PROC::VALU;
while (it < end) chk->value.push_back(read_FP4(it));
return chk;
}
if (tag == "FUNC") {
FORM::SURF::BLOK::PROC::FUNC *chk = new FORM::SURF::BLOK::PROC::FUNC;
chk->algorithm_name = read_S0(it);
while (it < end) chk->data.push_back(read_U1(it));
return chk;
}
}
if (context == "FORM::SURF::BLOK::GRAD") {
if (tag == "PNAM") {
FORM::SURF::BLOK::GRAD::PNAM *chk = new FORM::SURF::BLOK::GRAD::PNAM;
chk->parameter = read_S0(it);
return chk;
}
if (tag == "INAM") {
FORM::SURF::BLOK::GRAD::INAM *chk = new FORM::SURF::BLOK::GRAD::INAM;
chk->item_name = read_S0(it);
return chk;
}
if (tag == "GRST") {
FORM::SURF::BLOK::GRAD::GRST *chk = new FORM::SURF::BLOK::GRAD::GRST;
chk->input_range = read_FP4(it);
return chk;
}
if (tag == "GREN") {
FORM::SURF::BLOK::GRAD::GREN *chk = new FORM::SURF::BLOK::GRAD::GREN;
chk->input_range = read_FP4(it);
return chk;
}
if (tag == "GRPT") {
FORM::SURF::BLOK::GRAD::GRPT *chk = new FORM::SURF::BLOK::GRAD::GRPT;
chk->repeat_mode = read_U2(it);
return chk;
}
if (tag == "FKEY") {
FORM::SURF::BLOK::GRAD::FKEY *chk = new FORM::SURF::BLOK::GRAD::FKEY;
while (it < end) {
FORM::SURF::BLOK::GRAD::FKEY::value_type val;
val.input = read_FP4(it);
for (int i=0; i<4; ++i) val.output[i] = read_FP4(it);
chk->values.push_back(val);
}
return chk;
}
if (tag == "IKEY") {
FORM::SURF::BLOK::GRAD::IKEY *chk = new FORM::SURF::BLOK::GRAD::IKEY;
while (it < end) chk->interpolation.push_back(read_U2(it));
return chk;
}
}
if (context == "FORM::SURF::BLOK::SHDR") {
if (tag == "FUNC") {
FORM::SURF::BLOK::SHDR::FUNC *chk = new FORM::SURF::BLOK::SHDR::FUNC;
chk->algorithm_name = read_S0(it);
while (it < end) chk->data.push_back(read_U1(it));
return chk;
}
}
return 0;
}
LP_TMP iff::Chunk *Parser<Iter>::parse_subchunk(Iter &it, const std::string &context)
{
std::string tag;
for (int i=0; i<4; ++i) tag.push_back(*(it++));
unsigned int len = ((static_cast<unsigned int>(*(it++)) & 0xFF) << 8) |
(static_cast<unsigned int>(*(it++)) & 0xFF);
os() << "DEBUG INFO: lwo2parser: reading subchunk " << tag << ", length = " << len << ", context = " << context << "\n";
iff::Chunk *chk = parse_chunk_data(tag, context, it, it+len);
if (!chk) os() << "DEBUG INFO: lwo2parser: \tprevious subchunk not handled\n";
it += len;
if ((len % 2) != 0) ++it;
return chk;
}
}
#endif

View File

@@ -0,0 +1,147 @@
/****************************************************************************
Functions for reading basic data types from LWO2 files
Copyright (C) 2002 by Marco Jez
****************************************************************************/
#ifndef LWO2READ_
#define LWO2READ_
#include "lwo2types.h"
namespace lwo2
{
template<class Iter>
I1 read_I1(Iter &it)
{
return static_cast<I1>(*(it++));
}
template<class Iter>
I2 read_I2(Iter &it)
{
return ((static_cast<I2>(*(it++)) & 0xFF) << 8) |
(static_cast<I2>(*(it++)) & 0xFF);
}
template<class Iter>
I4 read_I4(Iter &it)
{
return ((static_cast<I4>(*(it++)) & 0xFF) << 24) |
((static_cast<I4>(*(it++)) & 0xFF) << 16) |
((static_cast<I4>(*(it++)) & 0xFF) << 8) |
(static_cast<I4>(*(it++)) & 0xFF);
}
template<class Iter>
U1 read_U1(Iter &it)
{
return static_cast<U1>(*(it++));
}
template<class Iter>
U2 read_U2(Iter &it)
{
return ((static_cast<U2>(*(it++)) & 0xFF) << 8) |
(static_cast<U2>(*(it++)) & 0xFF);
}
template<class Iter>
U4 read_U4(Iter &it)
{
return ((static_cast<U4>(*(it++)) & 0xFF) << 24) |
((static_cast<U4>(*(it++)) & 0xFF) << 16) |
((static_cast<U4>(*(it++)) & 0xFF) << 8) |
(static_cast<U4>(*(it++)) & 0xFF);
}
template<class Iter>
F4 read_F4(Iter &it)
{
U4 u4 = read_U4(it);
return *reinterpret_cast<F4 *>(&u4);
}
template<class Iter>
ID4 read_ID4(Iter &it)
{
ID4 value;
for (int i=0; i<4; ++i) value.id[i] = *(it++);
return value;
}
template<class Iter>
S0 read_S0(Iter &it)
{
S0 value;
while (*it) {
value.push_back(*(it++));
}
++it;
if (value.length() % 2 == 0) ++it;
return value;
}
template<class Iter>
VX read_VX(Iter &it)
{
VX vx;
if ((*it & 0xFF) == 0xFF) {
vx.index = read_U4(it) & 0x00FFFFFF;
} else {
vx.index = static_cast<U4>(read_U2(it));
}
return vx;
}
template<class Iter>
COL12 read_COL12(Iter &it)
{
COL12 value;
value.red = read_F4(it);
value.green = read_F4(it);
value.blue = read_F4(it);
return value;
}
template<class Iter>
VEC12 read_VEC12(Iter &it)
{
VEC12 value;
value.X = read_F4(it);
value.Y = read_F4(it);
value.Z = read_F4(it);
return value;
}
template<class Iter>
FP4 read_FP4(Iter &it)
{
FP4 value;
value.fraction = read_F4(it);
return value;
}
template<class Iter>
ANG4 read_ANG4(Iter &it)
{
ANG4 value;
value.radians = read_F4(it);
return value;
}
template<class Iter>
FNAM0 read_FNAM0(Iter &it)
{
FNAM0 value;
value.name = read_S0(it);
return value;
}
}
#endif

View File

@@ -0,0 +1,65 @@
/****************************************************************************
Basic data types used in LWO2 files
Copyright (C) 2002-2003 Marco Jez
****************************************************************************/
#ifndef LWO2TYPES_
#define LWO2TYPES_
#include <string>
namespace lwo2
{
// basic types
struct ID4 {
char id[4];
};
typedef signed char I1;
typedef signed short int I2;
typedef signed int I4;
typedef unsigned char U1;
typedef unsigned short int U2;
typedef unsigned int U4;
typedef float F4;
typedef std::string S0;
// composite types
struct VX {
U4 index;
};
struct COL12 {
F4 red;
F4 green;
F4 blue;
};
struct VEC12 {
F4 X;
F4 Y;
F4 Z;
};
struct FP4 {
F4 fraction;
};
struct ANG4 {
F4 radians;
};
struct FNAM0 {
S0 name;
};
}
#endif

View File

@@ -37,8 +37,8 @@
#include <iostream>
#include <fstream>
#include "Lwo2.h"
#include "Lwo2Layer.h"
#include "old_Lwo2.h"
#include "old_Lwo2Layer.h"
Lwo2::Lwo2():
_current_layer(0),

View File

@@ -23,7 +23,7 @@
* The OSG homepage is http://www.openscenegraph.org/
*/
#include "Lwo2Layer.h"
#include "old_Lwo2Layer.h"
Lwo2Layer::Lwo2Layer():
_number(0),

View File

@@ -16,7 +16,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "lw.h"
#include "old_lw.h"
#include <stdio.h>
#include <math.h>
#include <stdlib.h>