From c0f2730d9925d2f8382b3336654e2a7a3b7585a9 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Sat, 3 Jan 2004 15:20:33 +0000 Subject: [PATCH] From Marco Jez, updates to the LWO loader. --- VisualStudio/osgPlugins/lwo/lwo.dsp | 116 ++- src/osgPlugins/lwo/Block.cpp | 147 +++ src/osgPlugins/lwo/Block.h | 144 +++ src/osgPlugins/lwo/Clip.cpp | 25 + src/osgPlugins/lwo/Clip.h | 35 + src/osgPlugins/lwo/Converter.cpp | 283 ++++++ src/osgPlugins/lwo/Converter.h | 59 ++ src/osgPlugins/lwo/GNUmakefile | 17 +- src/osgPlugins/lwo/Layer.h | 84 ++ src/osgPlugins/lwo/Object.cpp | 461 +++++++++ src/osgPlugins/lwo/Object.h | 126 +++ src/osgPlugins/lwo/Polygon.cpp | 22 + src/osgPlugins/lwo/Polygon.h | 118 +++ src/osgPlugins/lwo/README.txt | 51 + src/osgPlugins/lwo/ReaderWriterLWO.cpp | 58 +- src/osgPlugins/lwo/Surface.cpp | 329 +++++++ src/osgPlugins/lwo/Surface.h | 105 ++ src/osgPlugins/lwo/Tessellator.cpp | 121 +++ src/osgPlugins/lwo/Tessellator.h | 53 + src/osgPlugins/lwo/Unit.cpp | 242 +++++ src/osgPlugins/lwo/Unit.h | 91 ++ src/osgPlugins/lwo/VertexMap.cpp | 81 ++ src/osgPlugins/lwo/VertexMap.h | 74 ++ src/osgPlugins/lwo/iffparser.h | 114 +++ src/osgPlugins/lwo/lwo2chunks.h | 623 ++++++++++++ src/osgPlugins/lwo/lwo2parser.h | 908 ++++++++++++++++++ src/osgPlugins/lwo/lwo2read.h | 147 +++ src/osgPlugins/lwo/lwo2types.h | 65 ++ src/osgPlugins/lwo/{Lwo2.cpp => old_Lwo2.cpp} | 4 +- src/osgPlugins/lwo/{Lwo2.h => old_Lwo2.h} | 0 .../lwo/{Lwo2Layer.cpp => old_Lwo2Layer.cpp} | 2 +- .../lwo/{Lwo2Layer.h => old_Lwo2Layer.h} | 0 src/osgPlugins/lwo/{lw.cpp => old_lw.cpp} | 2 +- src/osgPlugins/lwo/{lw.h => old_lw.h} | 0 34 files changed, 4686 insertions(+), 21 deletions(-) create mode 100644 src/osgPlugins/lwo/Block.cpp create mode 100644 src/osgPlugins/lwo/Block.h create mode 100644 src/osgPlugins/lwo/Clip.cpp create mode 100644 src/osgPlugins/lwo/Clip.h create mode 100644 src/osgPlugins/lwo/Converter.cpp create mode 100644 src/osgPlugins/lwo/Converter.h create mode 100644 src/osgPlugins/lwo/Layer.h create mode 100644 src/osgPlugins/lwo/Object.cpp create mode 100644 src/osgPlugins/lwo/Object.h create mode 100644 src/osgPlugins/lwo/Polygon.cpp create mode 100644 src/osgPlugins/lwo/Polygon.h create mode 100644 src/osgPlugins/lwo/README.txt create mode 100644 src/osgPlugins/lwo/Surface.cpp create mode 100644 src/osgPlugins/lwo/Surface.h create mode 100644 src/osgPlugins/lwo/Tessellator.cpp create mode 100644 src/osgPlugins/lwo/Tessellator.h create mode 100644 src/osgPlugins/lwo/Unit.cpp create mode 100644 src/osgPlugins/lwo/Unit.h create mode 100644 src/osgPlugins/lwo/VertexMap.cpp create mode 100644 src/osgPlugins/lwo/VertexMap.h create mode 100644 src/osgPlugins/lwo/iffparser.h create mode 100644 src/osgPlugins/lwo/lwo2chunks.h create mode 100644 src/osgPlugins/lwo/lwo2parser.h create mode 100644 src/osgPlugins/lwo/lwo2read.h create mode 100644 src/osgPlugins/lwo/lwo2types.h rename src/osgPlugins/lwo/{Lwo2.cpp => old_Lwo2.cpp} (99%) rename src/osgPlugins/lwo/{Lwo2.h => old_Lwo2.h} (100%) rename src/osgPlugins/lwo/{Lwo2Layer.cpp => old_Lwo2Layer.cpp} (99%) rename src/osgPlugins/lwo/{Lwo2Layer.h => old_Lwo2Layer.h} (100%) rename src/osgPlugins/lwo/{lw.cpp => old_lw.cpp} (99%) rename src/osgPlugins/lwo/{lw.h => old_lw.h} (100%) diff --git a/VisualStudio/osgPlugins/lwo/lwo.dsp b/VisualStudio/osgPlugins/lwo/lwo.dsp index 1947a8d76..3e18d8ce3 100644 --- a/VisualStudio/osgPlugins/lwo/lwo.dsp +++ b/VisualStudio/osgPlugins/lwo/lwo.dsp @@ -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" diff --git a/src/osgPlugins/lwo/Block.cpp b/src/osgPlugins/lwo/Block.cpp new file mode 100644 index 000000000..190669b82 --- /dev/null +++ b/src/osgPlugins/lwo/Block.cpp @@ -0,0 +1,147 @@ +/******************************************************* + Lightwave Object Loader for OSG + + Copyright (C) 2004 Marco Jez + OpenSceneGraph is (C) 2004 Robert Osfield +********************************************************/ + +#include "Block.h" + +#include +#include + +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(*i); + if (chan) { + channel_ = std::string(chan->texture_channel.id, 4); + } + const lwo2::FORM::SURF::BLOK::ENAB *enab = dynamic_cast(*i); + if (enab) { + enabled_ = enab->enable != 0; + } + const lwo2::FORM::SURF::BLOK::OPAC *opac = dynamic_cast(*i); + if (opac) { + opacity_type_ = static_cast(opac->type); + opacity_amount_ = opac->opacity.fraction; + } + const lwo2::FORM::SURF::BLOK::AXIS *axis = dynamic_cast(*i); + if (axis) { + displacement_axis_ = static_cast(axis->displacement_axis); + } + } +} + +void Block::compile(const lwo2::FORM::SURF::BLOK *blok) +{ + const lwo2::FORM::SURF::BLOK::IMAP *imap = dynamic_cast(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(*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(*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(*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(*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(*i); + if (csys) { + mapping.csys_ = static_cast(csys->type); + } + } + imap_.mapping = mapping; + } + + const lwo2::FORM::SURF::BLOK::IMAP::PROJ *proj = dynamic_cast(*i); + if (proj) { + imap_.projection = static_cast(proj->projection_mode); + } + + const lwo2::FORM::SURF::BLOK::IMAP::AXIS *axis = dynamic_cast(*i); + if (axis) { + imap_.axis = static_cast(axis->texture_axis); + } + + const lwo2::FORM::SURF::BLOK::IMAP::IMAG *imag = dynamic_cast(*i); + if (imag) { + imap_.image_map = imag->texture_image.index; + } + + const lwo2::FORM::SURF::BLOK::IMAP::WRAP *wrap = dynamic_cast(*i); + if (wrap) { + imap_.width_wrap = static_cast(wrap->width_wrap); + imap_.height_wrap = static_cast(wrap->height_wrap); + } + + const lwo2::FORM::SURF::BLOK::IMAP::WRPW *wrpw = dynamic_cast(*i); + if (wrpw) { + imap_.wrap_amount_w = wrpw->cycles.fraction; + } + + const lwo2::FORM::SURF::BLOK::IMAP::WRPH *wrph = dynamic_cast(*i); + if (wrph) { + imap_.wrap_amount_h = wrph->cycles.fraction; + } + + const lwo2::FORM::SURF::BLOK::IMAP::VMAP *vmap = dynamic_cast(*i); + if (vmap) { + imap_.uv_map = vmap->txuv_map_name; + } + + const lwo2::FORM::SURF::BLOK::IMAP::TAMP *tamp = dynamic_cast(*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; +} diff --git a/src/osgPlugins/lwo/Block.h b/src/osgPlugins/lwo/Block.h new file mode 100644 index 000000000..c43ad2683 --- /dev/null +++ b/src/osgPlugins/lwo/Block.h @@ -0,0 +1,144 @@ +/******************************************************* + Lightwave Object Loader for OSG + + Copyright (C) 2004 Marco Jez + OpenSceneGraph is (C) 2004 Robert Osfield +********************************************************/ + +#ifndef LWOSG_BLOCK_ +#define LWOSG_BLOCK_ + +#include "lwo2chunks.h" + +#include + +#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 diff --git a/src/osgPlugins/lwo/Clip.cpp b/src/osgPlugins/lwo/Clip.cpp new file mode 100644 index 000000000..5ad64c398 --- /dev/null +++ b/src/osgPlugins/lwo/Clip.cpp @@ -0,0 +1,25 @@ +/******************************************************* + Lightwave Object Loader for OSG + + Copyright (C) 2004 Marco Jez + 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(*j); + if (stil) still_filename_ = stil->name.name; + } +} diff --git a/src/osgPlugins/lwo/Clip.h b/src/osgPlugins/lwo/Clip.h new file mode 100644 index 000000000..455a559a0 --- /dev/null +++ b/src/osgPlugins/lwo/Clip.h @@ -0,0 +1,35 @@ +/******************************************************* + Lightwave Object Loader for OSG + + Copyright (C) 2004 Marco Jez + OpenSceneGraph is (C) 2004 Robert Osfield +********************************************************/ + +#ifndef LWOSG_CLIP_ +#define LWOSG_CLIP_ + +#include "lwo2chunks.h" + +#include +#include + +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 Clip_map; + +} + +#endif diff --git a/src/osgPlugins/lwo/Converter.cpp b/src/osgPlugins/lwo/Converter.cpp new file mode 100644 index 000000000..a13ab3a90 --- /dev/null +++ b/src/osgPlugins/lwo/Converter.cpp @@ -0,0 +1,283 @@ +/******************************************************* + Lightwave Object Loader for OSG + + Copyright (C) 2004 Marco Jez + OpenSceneGraph is (C) 2004 Robert Osfield +********************************************************/ + +#include "Converter.h" +#include "Tessellator.h" + +#include +#include +#include +#include +#include + +#include + +#include "lwo2parser.h" + +#include + +using namespace lwosg; + +namespace +{ + + struct GeometryBin { + osg::ref_ptr deui_points; + osg::ref_ptr deui_lines; + osg::ref_ptr 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 > 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 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 GeometryBin_map; + GeometryBin_map bins; + + typedef std::map 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; kpolygons().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 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 new_points = new osg::Vec3Array; + osg::ref_ptr new_normals = new osg::Vec3Array; + for (unsigned pi=0; pipoints()->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 geode = new osg::Geode; + + osg::ref_ptr 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 rm_texture_maps = j->texture_maps()->remap(remapping); + osg::ref_ptr rm_rgb_maps = j->rgb_maps()->remap(remapping); + osg::ref_ptr 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 cf = new osg::CullFace; + cf->setMode(osg::CullFace::BACK); + root_->getOrCreateStateSet()->setAttributeAndModes(cf.get()); + + if (options_.apply_light_model) { + osg::ref_ptr 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 buffer; + char c; + while (ifs.get(c)) buffer.push_back(c); + + lwo2::Parser::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(*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; +} diff --git a/src/osgPlugins/lwo/Converter.h b/src/osgPlugins/lwo/Converter.h new file mode 100644 index 000000000..aa4e179e2 --- /dev/null +++ b/src/osgPlugins/lwo/Converter.h @@ -0,0 +1,59 @@ +/******************************************************* + Lightwave Object Loader for OSG + + Copyright (C) 2004 Marco Jez + OpenSceneGraph is (C) 2004 Robert Osfield +********************************************************/ + +#ifndef LWOSG_CONVERTER_ +#define LWOSG_CONVERTER_ + +#include "Object.h" +#include "iffparser.h" + +#include +#include + +#include + +namespace lwosg +{ + + class Converter { + public: + + struct Options { + osg::ref_ptr 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 root_; + Options options_; + }; + +} + +#endif diff --git a/src/osgPlugins/lwo/GNUmakefile b/src/osgPlugins/lwo/GNUmakefile index 958fd4371..41979eb0e 100644 --- a/src/osgPlugins/lwo/GNUmakefile +++ b/src/osgPlugins/lwo/GNUmakefile @@ -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 diff --git a/src/osgPlugins/lwo/Layer.h b/src/osgPlugins/lwo/Layer.h new file mode 100644 index 000000000..f848a9b82 --- /dev/null +++ b/src/osgPlugins/lwo/Layer.h @@ -0,0 +1,84 @@ +/******************************************************* + Lightwave Object Loader for OSG + + Copyright (C) 2004 Marco Jez + 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_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 diff --git a/src/osgPlugins/lwo/Object.cpp b/src/osgPlugins/lwo/Object.cpp new file mode 100644 index 000000000..1e5aad885 --- /dev/null +++ b/src/osgPlugins/lwo/Object.cpp @@ -0,0 +1,461 @@ +/******************************************************* + Lightwave Object Loader for OSG + + Copyright (C) 2004 Marco Jez + OpenSceneGraph is (C) 2004 Robert Osfield +********************************************************/ + +#include "Object.h" + +#include + +#include +#include +#include + +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(*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(*i); + if (surf) { + surfaces_[surf->name] = Surface(surf, clips_); + } + } +} + +void Object::parse(const iff::Chunk_list &data) +{ + typedef std::vector 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(*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(*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(*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(*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; jnumvert; ++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; jnumvert; ++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(*i); + if (tags) { + tag_strings = tags->tag_string; + } + + const lwo2::FORM::PTAG *ptag = dynamic_cast(*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(*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(*i); + if (desc) { + description_ = desc->description_line; + } + + const lwo2::FORM::TEXT *text = dynamic_cast(*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_" << █ + 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 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 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; ppoints()->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; + } + } + } +} diff --git a/src/osgPlugins/lwo/Object.h b/src/osgPlugins/lwo/Object.h new file mode 100644 index 000000000..5fc624ec1 --- /dev/null +++ b/src/osgPlugins/lwo/Object.h @@ -0,0 +1,126 @@ +/******************************************************* + Lightwave Object Loader for OSG + + Copyright (C) 2004 Marco Jez + 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 +#include + +#include +#include +#include + +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 Layer_map; + typedef std::map 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 Clip_map; + Clip_map clips_; + + Surface_map surfaces_; + + std::string comment_; + std::string description_; + + osg::ref_ptr 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 diff --git a/src/osgPlugins/lwo/Polygon.cpp b/src/osgPlugins/lwo/Polygon.cpp new file mode 100644 index 000000000..9daf0d472 --- /dev/null +++ b/src/osgPlugins/lwo/Polygon.cpp @@ -0,0 +1,22 @@ +/******************************************************* + Lightwave Object Loader for OSG + + Copyright (C) 2004 Marco Jez + 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) +{ +} diff --git a/src/osgPlugins/lwo/Polygon.h b/src/osgPlugins/lwo/Polygon.h new file mode 100644 index 000000000..134547995 --- /dev/null +++ b/src/osgPlugins/lwo/Polygon.h @@ -0,0 +1,118 @@ +/******************************************************* + Lightwave Object Loader for OSG + + Copyright (C) 2004 Marco Jez + OpenSceneGraph is (C) 2004 Robert Osfield +********************************************************/ + +#ifndef LWOSG_POLYGON_ +#define LWOSG_POLYGON_ + +#include "lwo2chunks.h" +#include "Surface.h" +#include "VertexMap.h" + +#include +#include + +#include +#include + +namespace lwosg +{ + + class Polygon { + public: + typedef std::vector Index_list; + typedef std::map 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 local_normals_; + osg::ref_ptr weight_maps_; + osg::ref_ptr texture_maps_; + osg::ref_ptr rgb_maps_; + osg::ref_ptr 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 diff --git a/src/osgPlugins/lwo/README.txt b/src/osgPlugins/lwo/README.txt new file mode 100644 index 000000000..bcc8d0690 --- /dev/null +++ b/src/osgPlugins/lwo/README.txt @@ -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 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 + January 2004 diff --git a/src/osgPlugins/lwo/ReaderWriterLWO.cpp b/src/osgPlugins/lwo/ReaderWriterLWO.cpp index 25feb1d26..f9afea313 100644 --- a/src/osgPlugins/lwo/ReaderWriterLWO.cpp +++ b/src/osgPlugins/lwo/ReaderWriterLWO.cpp @@ -4,6 +4,7 @@ * Lightwave Object loader for Open Scene Graph * * Copyright (C) 2001 Ulrich Hertlein + * Improved LWO2 reader is (C) 2003-2004 Marco Jez * * 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 +#include #include #include @@ -34,8 +36,10 @@ #include #include -#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 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 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(new Lwo2()); if (lwo2->ReadFile(fileName)) diff --git a/src/osgPlugins/lwo/Surface.cpp b/src/osgPlugins/lwo/Surface.cpp new file mode 100644 index 000000000..7e4cdd088 --- /dev/null +++ b/src/osgPlugins/lwo/Surface.cpp @@ -0,0 +1,329 @@ +/******************************************************* + Lightwave Object Loader for OSG + + Copyright (C) 2004 Marco Jez + OpenSceneGraph is (C) 2004 Robert Osfield +********************************************************/ + +#include "Surface.h" + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +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(*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(*j); + if (diff) diffuse_ = diff->intensity.fraction; + + const lwo2::FORM::SURF::LUMI *lumi = dynamic_cast(*j); + if (lumi) luminosity_ = lumi->intensity.fraction; + + const lwo2::FORM::SURF::SPEC *spec = dynamic_cast(*j); + if (spec) specularity_ = spec->intensity.fraction; + + const lwo2::FORM::SURF::REFL *refl = dynamic_cast(*j); + if (refl) reflection_ = refl->intensity.fraction; + + const lwo2::FORM::SURF::TRAN *tran = dynamic_cast(*j); + if (tran) transparency_ = tran->intensity.fraction; + + const lwo2::FORM::SURF::TRNL *trnl = dynamic_cast(*j); + if (trnl) translucency_ = trnl->intensity.fraction; + + const lwo2::FORM::SURF::GLOS *glos = dynamic_cast(*j); + if (glos) glossiness_ = glos->glossiness.fraction; + + const lwo2::FORM::SURF::SIDE *side = dynamic_cast(*j); + if (side) sidedness_ = static_cast(side->sidedness); + + const lwo2::FORM::SURF::SMAN *sman = dynamic_cast(*j); + if (sman) max_smoothing_angle_ = sman->max_smoothing_angle.radians; + + const lwo2::FORM::SURF::VCOL *vcol = dynamic_cast(*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(*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 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 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 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 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 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(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 sh = new osgFX::SpecularHighlights; + sh->setTextureUnit(unit); + osg::Material *material = dynamic_cast(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; +} diff --git a/src/osgPlugins/lwo/Surface.h b/src/osgPlugins/lwo/Surface.h new file mode 100644 index 000000000..e81d4973e --- /dev/null +++ b/src/osgPlugins/lwo/Surface.h @@ -0,0 +1,105 @@ +/******************************************************* + Lightwave Object Loader for OSG + + Copyright (C) 2004 Marco Jez + 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 +#include +#include +#include + +#include +#include + +namespace lwosg +{ + + class Surface { + public: + + enum Sidedness { + NONE = 0, + FRONT_ONLY = 1, + BACK_ONLY = 2, + FRONT_AND_BACK = 3 + }; + + typedef std::multimap 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 stateset_; + }; + +} + +#endif diff --git a/src/osgPlugins/lwo/Tessellator.cpp b/src/osgPlugins/lwo/Tessellator.cpp new file mode 100644 index 000000000..51c4ac226 --- /dev/null +++ b/src/osgPlugins/lwo/Tessellator.cpp @@ -0,0 +1,121 @@ +/******************************************************* + Lightwave Object Loader for OSG + + Copyright (C) 2004 Marco Jez + 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(data); + tess->prim_type_ = type; + tess->incoming_.clear(); + } + + void CALLBACK cb_vertex_data(void *vertex_data, void *data) + { + Tessellator *tess = static_cast(data); + tess->incoming_.push_back(*static_cast(vertex_data)); + } + + void CALLBACK cb_end_data(void *data) + { + Tessellator *tess = static_cast(data); + tess->finalize_primitive(); + } + + void CALLBACK cb_error_data(GLenum error, void *data) + { + Tessellator *tess = static_cast(data); + tess->last_error_ = error; + } + +} + +bool Tessellator::tessellate(const Polygon &poly, const osg::Vec3Array *points, osg::DrawElementsUInt *out, const std::vector *remap) +{ + out_ = out; + last_error_ = 0; + + GLUtesselator *tess = gluNewTess(); + + gluTessCallback(tess, GLU_TESS_BEGIN_DATA, reinterpret_cast(cb_begin_data)); + gluTessCallback(tess, GLU_TESS_VERTEX_DATA, reinterpret_cast(cb_vertex_data)); + gluTessCallback(tess, GLU_TESS_END_DATA, reinterpret_cast(cb_end_data)); + gluTessCallback(tess, GLU_TESS_ERROR_DATA, reinterpret_cast(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)); + } + } + } +} diff --git a/src/osgPlugins/lwo/Tessellator.h b/src/osgPlugins/lwo/Tessellator.h new file mode 100644 index 000000000..2e81fc8f5 --- /dev/null +++ b/src/osgPlugins/lwo/Tessellator.h @@ -0,0 +1,53 @@ +/******************************************************* + Lightwave Object Loader for OSG + + Copyright (C) 2004 Marco Jez + OpenSceneGraph is (C) 2004 Robert Osfield +********************************************************/ + +#ifndef LWOSG_TESSELLATOR_ +#define LWOSG_TESSELLATOR_ + +#include "Polygon.h" + +#include +#include +#include +#include + +#include + +#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 *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 out_; + + GLenum prim_type_; + GLenum last_error_; + + typedef std::vector Index_list; + Index_list incoming_; + }; + +} + +#endif diff --git a/src/osgPlugins/lwo/Unit.cpp b/src/osgPlugins/lwo/Unit.cpp new file mode 100644 index 000000000..6f619abaa --- /dev/null +++ b/src/osgPlugins/lwo/Unit.cpp @@ -0,0 +1,242 @@ +/******************************************************* + Lightwave Object Loader for OSG + + Copyright (C) 2004 Marco Jez + 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 &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; klocal_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(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; + } + } +} diff --git a/src/osgPlugins/lwo/Unit.h b/src/osgPlugins/lwo/Unit.h new file mode 100644 index 000000000..88d228894 --- /dev/null +++ b/src/osgPlugins/lwo/Unit.h @@ -0,0 +1,91 @@ +/******************************************************* + Lightwave Object Loader for OSG + + Copyright (C) 2004 Marco Jez + OpenSceneGraph is (C) 2004 Robert Osfield +********************************************************/ + +#ifndef LWOSG_UNIT_ +#define LWOSG_UNIT_ + +#include "Polygon.h" +#include "VertexMap.h" + +#include +#include + +#include + +namespace lwosg +{ + + class Unit { + public: + + typedef std::vector Polygon_list; + typedef std::vector Index_list; + typedef std::vector 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 &poly_indices); + void flatten_map(Polygon &poly, const VertexMap *local_map, VertexMap *global_map); + + private: + osg::ref_ptr points_; + Polygon_list polygons_; + Sharing_list shares_; + + osg::ref_ptr normals_; + osg::ref_ptr weight_maps_; + osg::ref_ptr subpatch_weight_maps_; + osg::ref_ptr texture_maps_; + osg::ref_ptr rgb_maps_; + osg::ref_ptr rgba_maps_; + osg::ref_ptr displacement_maps_; + osg::ref_ptr spot_maps_; + }; + +} + +#endif diff --git a/src/osgPlugins/lwo/VertexMap.cpp b/src/osgPlugins/lwo/VertexMap.cpp new file mode 100644 index 000000000..71d09fe68 --- /dev/null +++ b/src/osgPlugins/lwo/VertexMap.cpp @@ -0,0 +1,81 @@ +/******************************************************* + Lightwave Object Loader for OSG + + Copyright (C) 2004 Marco Jez + OpenSceneGraph is (C) 2004 Robert Osfield +********************************************************/ + +#include "VertexMap.h" + +#include + +using namespace lwosg; + +osg::Vec4Array *VertexMap::asVec4Array(int num_vertices, const osg::Vec4 &default_value, const osg::Vec4 &modulator) const +{ + osg::ref_ptr 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 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 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 &remapping) const +{ + osg::ref_ptr result = new VertexMap; + + for (VertexMap::const_iterator i=begin(); i!=end(); ++i) { + if (i->first >= static_cast(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 &remapping) const +{ + osg::ref_ptr 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(); +} diff --git a/src/osgPlugins/lwo/VertexMap.h b/src/osgPlugins/lwo/VertexMap.h new file mode 100644 index 000000000..4d9699cc2 --- /dev/null +++ b/src/osgPlugins/lwo/VertexMap.h @@ -0,0 +1,74 @@ +/******************************************************* + Lightwave Object Loader for OSG + + Copyright (C) 2004 Marco Jez + OpenSceneGraph is (C) 2004 Robert Osfield +********************************************************/ + +#ifndef LWOSG_VERTEXMAP_ +#define LWOSG_VERTEXMAP_ + +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace lwosg +{ + + ///////////////////////////////////////////////////////////////////////// + // VERTEX MAP + + typedef std::map 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 &remapping) const; + + protected: + virtual ~VertexMap() {} + VertexMap &operator=(const VertexMap &) { return *this; } + }; + + + ///////////////////////////////////////////////////////////////////////// + // VERTEX MAP MAP + + typedef std::map > 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 &vmap = operator[](name); + if (!vmap.valid()) { + vmap = new VertexMap; + } + return vmap.get(); + } + + VertexMap_map *remap(const std::vector &remapping) const; + + protected: + virtual ~VertexMap_map() {} + VertexMap_map &operator=(const VertexMap_map &) { return *this; } + + private: + }; + +} + +#endif diff --git a/src/osgPlugins/lwo/iffparser.h b/src/osgPlugins/lwo/iffparser.h new file mode 100644 index 000000000..c4cb27bd3 --- /dev/null +++ b/src/osgPlugins/lwo/iffparser.h @@ -0,0 +1,114 @@ +/******************************************************* + Lightwave Object Loader for OSG + + Copyright (C) 2004 Marco Jez + OpenSceneGraph is (C) 2004 Robert Osfield +********************************************************/ + +#ifndef IFFPARSER_ +#define IFFPARSER_ + +#include +#include + +namespace iff +{ + + typedef std::vector 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 + 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 + + IP_TMP GenericParser::GenericParser() + : os_(std::cout) + { + } + + IP_TMP GenericParser::GenericParser(std::ostream &os) + : os_(os) + { + } + + IP_TMP GenericParser::~GenericParser() + { + } + + IP_TMP void GenericParser::clear() + { + chunks_.clear(); + } + + IP_TMP void GenericParser::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::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(*(it++)) & 0xFF) << 24) | + ((static_cast(*(it++)) & 0xFF) << 16) | + ((static_cast(*(it++)) & 0xFF) << 8) | + (static_cast(*(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::chunks() const + { + return chunks_; + } + +} + +#endif diff --git a/src/osgPlugins/lwo/lwo2chunks.h b/src/osgPlugins/lwo/lwo2chunks.h new file mode 100644 index 000000000..329158a39 --- /dev/null +++ b/src/osgPlugins/lwo/lwo2chunks.h @@ -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 + +#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 Point_list; + Point_list point_location; + }; + + CHUNK (VMAP) { + ID4 type; + U2 dimension; + S0 name; + + struct mapping_type { + VX vert; + std::vector value; + }; + + typedef std::vector Mapping_list; + Mapping_list mapping; + }; + + CHUNK (POLS) { + ID4 type; + + struct polygon_type { + U2 numvert; + U2 flags; + std::vector vert; + }; + + typedef std::vector Polygon_list; + Polygon_list polygons; + }; + + CHUNK (TAGS) { + typedef std::vector String_list; + String_list tag_string; + }; + + CHUNK (PTAG) { + ID4 type; + + struct mapping_type { + VX poly; + U2 tag; + }; + + typedef std::vector Mapping_list; + Mapping_list mapping; + }; + + CHUNK (VMAD) { + ID4 type; + U2 dimension; + S0 name; + + struct mapping_type { + VX vert; + VX poly; + std::vector value; + }; + + typedef std::vector 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 parameters; + }; + + SUBCHUNK (CHAN) { + S0 server_name; + U2 flags; + std::vector 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 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 data; + }; + + SUBCHUNK (PFLT) { + S0 server_name; + U2 flags; + std::vector 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 value; + }; + + SUBCHUNK (FUNC) { + S0 algorithm_name; + std::vector 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_list; + Value_list values; + }; + + SUBCHUNK (IKEY) { + std::vector 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 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 data; + }; + + }; + + +} + +#endif diff --git a/src/osgPlugins/lwo/lwo2parser.h b/src/osgPlugins/lwo/lwo2parser.h new file mode 100644 index 000000000..e2b41f367 --- /dev/null +++ b/src/osgPlugins/lwo/lwo2parser.h @@ -0,0 +1,908 @@ +/******************************************************* + Lightwave Object Loader for OSG + + Copyright (C) 2004 Marco Jez + OpenSceneGraph is (C) 2004 Robert Osfield +********************************************************/ + +#ifndef LWO2PARSER_ +#define LWO2PARSER_ + +#include "iffparser.h" +#include "lwo2chunks.h" +#include "lwo2read.h" + +#include +#include + +namespace lwo2 +{ + + class parser_error: public std::runtime_error { + public: + parser_error(const std::string &message): std::runtime_error("[LWO2 parser error] " + message) {} + }; + + template + class Parser: public iff::GenericParser { + 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 + + LP_TMP Parser::Parser() + : iff::GenericParser() + { + } + + LP_TMP Parser::Parser(std::ostream &os) + : iff::GenericParser(os) + { + } + + LP_TMP Parser::~Parser() + { + } + + LP_TMP iff::Chunk *Parser::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; idimension; ++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; ipolygons.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; idimension; ++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::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(*(it++)) & 0xFF) << 8) | + (static_cast(*(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 diff --git a/src/osgPlugins/lwo/lwo2read.h b/src/osgPlugins/lwo/lwo2read.h new file mode 100644 index 000000000..b2a9a79b2 --- /dev/null +++ b/src/osgPlugins/lwo/lwo2read.h @@ -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 +I1 read_I1(Iter &it) +{ + return static_cast(*(it++)); +} + +template +I2 read_I2(Iter &it) +{ + return ((static_cast(*(it++)) & 0xFF) << 8) | + (static_cast(*(it++)) & 0xFF); +} + +template +I4 read_I4(Iter &it) +{ + return ((static_cast(*(it++)) & 0xFF) << 24) | + ((static_cast(*(it++)) & 0xFF) << 16) | + ((static_cast(*(it++)) & 0xFF) << 8) | + (static_cast(*(it++)) & 0xFF); +} + +template +U1 read_U1(Iter &it) +{ + return static_cast(*(it++)); +} + +template +U2 read_U2(Iter &it) +{ + return ((static_cast(*(it++)) & 0xFF) << 8) | + (static_cast(*(it++)) & 0xFF); +} + +template +U4 read_U4(Iter &it) +{ + return ((static_cast(*(it++)) & 0xFF) << 24) | + ((static_cast(*(it++)) & 0xFF) << 16) | + ((static_cast(*(it++)) & 0xFF) << 8) | + (static_cast(*(it++)) & 0xFF); +} + +template +F4 read_F4(Iter &it) +{ + U4 u4 = read_U4(it); + return *reinterpret_cast(&u4); +} + +template +ID4 read_ID4(Iter &it) +{ + ID4 value; + for (int i=0; i<4; ++i) value.id[i] = *(it++); + return value; +} + +template +S0 read_S0(Iter &it) +{ + S0 value; + while (*it) { + value.push_back(*(it++)); + } + ++it; + if (value.length() % 2 == 0) ++it; + return value; +} + +template +VX read_VX(Iter &it) +{ + VX vx; + if ((*it & 0xFF) == 0xFF) { + vx.index = read_U4(it) & 0x00FFFFFF; + } else { + vx.index = static_cast(read_U2(it)); + } + return vx; +} + +template +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 +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 +FP4 read_FP4(Iter &it) +{ + FP4 value; + value.fraction = read_F4(it); + return value; +} + +template +ANG4 read_ANG4(Iter &it) +{ + ANG4 value; + value.radians = read_F4(it); + return value; +} + +template +FNAM0 read_FNAM0(Iter &it) +{ + FNAM0 value; + value.name = read_S0(it); + return value; +} + +} + +#endif diff --git a/src/osgPlugins/lwo/lwo2types.h b/src/osgPlugins/lwo/lwo2types.h new file mode 100644 index 000000000..c35f0a602 --- /dev/null +++ b/src/osgPlugins/lwo/lwo2types.h @@ -0,0 +1,65 @@ + +/**************************************************************************** + + Basic data types used in LWO2 files + + Copyright (C) 2002-2003 Marco Jez + +****************************************************************************/ + +#ifndef LWO2TYPES_ +#define LWO2TYPES_ + +#include + +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 diff --git a/src/osgPlugins/lwo/Lwo2.cpp b/src/osgPlugins/lwo/old_Lwo2.cpp similarity index 99% rename from src/osgPlugins/lwo/Lwo2.cpp rename to src/osgPlugins/lwo/old_Lwo2.cpp index 0eeb9ad02..35cd02e14 100644 --- a/src/osgPlugins/lwo/Lwo2.cpp +++ b/src/osgPlugins/lwo/old_Lwo2.cpp @@ -37,8 +37,8 @@ #include #include -#include "Lwo2.h" -#include "Lwo2Layer.h" +#include "old_Lwo2.h" +#include "old_Lwo2Layer.h" Lwo2::Lwo2(): _current_layer(0), diff --git a/src/osgPlugins/lwo/Lwo2.h b/src/osgPlugins/lwo/old_Lwo2.h similarity index 100% rename from src/osgPlugins/lwo/Lwo2.h rename to src/osgPlugins/lwo/old_Lwo2.h diff --git a/src/osgPlugins/lwo/Lwo2Layer.cpp b/src/osgPlugins/lwo/old_Lwo2Layer.cpp similarity index 99% rename from src/osgPlugins/lwo/Lwo2Layer.cpp rename to src/osgPlugins/lwo/old_Lwo2Layer.cpp index ddf14ab3f..b6fd8308d 100644 --- a/src/osgPlugins/lwo/Lwo2Layer.cpp +++ b/src/osgPlugins/lwo/old_Lwo2Layer.cpp @@ -23,7 +23,7 @@ * The OSG homepage is http://www.openscenegraph.org/ */ -#include "Lwo2Layer.h" +#include "old_Lwo2Layer.h" Lwo2Layer::Lwo2Layer(): _number(0), diff --git a/src/osgPlugins/lwo/Lwo2Layer.h b/src/osgPlugins/lwo/old_Lwo2Layer.h similarity index 100% rename from src/osgPlugins/lwo/Lwo2Layer.h rename to src/osgPlugins/lwo/old_Lwo2Layer.h diff --git a/src/osgPlugins/lwo/lw.cpp b/src/osgPlugins/lwo/old_lw.cpp similarity index 99% rename from src/osgPlugins/lwo/lw.cpp rename to src/osgPlugins/lwo/old_lw.cpp index 963afe34c..cdfab8a28 100644 --- a/src/osgPlugins/lwo/lw.cpp +++ b/src/osgPlugins/lwo/old_lw.cpp @@ -16,7 +16,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "lw.h" +#include "old_lw.h" #include #include #include diff --git a/src/osgPlugins/lwo/lw.h b/src/osgPlugins/lwo/old_lw.h similarity index 100% rename from src/osgPlugins/lwo/lw.h rename to src/osgPlugins/lwo/old_lw.h