Browse Source

*** empty log message ***

David Rose 25 years ago
parent
commit
2b0b4b7dad
49 changed files with 2571 additions and 0 deletions
  1. 51 0
      pandatool/src/lwo/Sources.pp
  2. 42 0
      pandatool/src/lwo/config_lwo.cxx
  3. 11 0
      pandatool/src/lwo/config_lwo.h
  4. 34 0
      pandatool/src/lwo/iffChunk.I
  5. 43 0
      pandatool/src/lwo/iffChunk.cxx
  6. 67 0
      pandatool/src/lwo/iffChunk.h
  7. 34 0
      pandatool/src/lwo/iffGenericChunk.I
  8. 42 0
      pandatool/src/lwo/iffGenericChunk.cxx
  9. 57 0
      pandatool/src/lwo/iffGenericChunk.h
  10. 96 0
      pandatool/src/lwo/iffId.I
  11. 6 0
      pandatool/src/lwo/iffId.cxx
  12. 46 0
      pandatool/src/lwo/iffId.h
  13. 63 0
      pandatool/src/lwo/iffInputFile.I
  14. 374 0
      pandatool/src/lwo/iffInputFile.cxx
  15. 93 0
      pandatool/src/lwo/iffInputFile.h
  16. 4 0
      pandatool/src/lwo/lwoChunk.I
  17. 8 0
      pandatool/src/lwo/lwoChunk.cxx
  18. 46 0
      pandatool/src/lwo/lwoChunk.h
  19. 4 0
      pandatool/src/lwo/lwoDiscontinuousVertexMap.I
  20. 104 0
      pandatool/src/lwo/lwoDiscontinuousVertexMap.cxx
  21. 61 0
      pandatool/src/lwo/lwoDiscontinuousVertexMap.h
  22. 4 0
      pandatool/src/lwo/lwoGroupChunk.I
  23. 68 0
      pandatool/src/lwo/lwoGroupChunk.cxx
  24. 57 0
      pandatool/src/lwo/lwoGroupChunk.h
  25. 16 0
      pandatool/src/lwo/lwoHeader.I
  26. 43 0
      pandatool/src/lwo/lwoHeader.cxx
  27. 50 0
      pandatool/src/lwo/lwoHeader.h
  28. 4 0
      pandatool/src/lwo/lwoInputFile.I
  29. 129 0
      pandatool/src/lwo/lwoInputFile.cxx
  30. 54 0
      pandatool/src/lwo/lwoInputFile.h
  31. 4 0
      pandatool/src/lwo/lwoLayer.I
  32. 54 0
      pandatool/src/lwo/lwoLayer.cxx
  33. 61 0
      pandatool/src/lwo/lwoLayer.h
  34. 4 0
      pandatool/src/lwo/lwoPoints.I
  35. 65 0
      pandatool/src/lwo/lwoPoints.cxx
  36. 55 0
      pandatool/src/lwo/lwoPoints.h
  37. 4 0
      pandatool/src/lwo/lwoPolygonTags.I
  38. 81 0
      pandatool/src/lwo/lwoPolygonTags.cxx
  39. 57 0
      pandatool/src/lwo/lwoPolygonTags.h
  40. 4 0
      pandatool/src/lwo/lwoPolygons.I
  41. 77 0
      pandatool/src/lwo/lwoPolygons.cxx
  42. 72 0
      pandatool/src/lwo/lwoPolygons.h
  43. 4 0
      pandatool/src/lwo/lwoTags.I
  44. 76 0
      pandatool/src/lwo/lwoTags.cxx
  45. 56 0
      pandatool/src/lwo/lwoTags.h
  46. 4 0
      pandatool/src/lwo/lwoVertexMap.I
  47. 90 0
      pandatool/src/lwo/lwoVertexMap.cxx
  48. 60 0
      pandatool/src/lwo/lwoVertexMap.h
  49. 32 0
      pandatool/src/lwo/test_lwo.cxx

+ 51 - 0
pandatool/src/lwo/Sources.pp

@@ -0,0 +1,51 @@
+#define LOCAL_LIBS pandatoolbase
+#define OTHER_LIBS \
+  mathutil:c linmath:c putil:c express:c panda:m dtoolconfig dtool
+#define UNIX_SYS_LIBS \
+  m
+
+#begin ss_lib_target
+  #define TARGET lwo
+
+  #define SOURCES \
+    config_lwo.cxx config_lwo.h iffChunk.I iffChunk.cxx iffChunk.h \
+    iffGenericChunk.I iffGenericChunk.cxx iffGenericChunk.h iffId.I \
+    iffId.cxx iffId.h iffInputFile.I iffInputFile.cxx iffInputFile.h \
+    lwoChunk.I lwoChunk.cxx lwoChunk.h \
+    lwoDiscontinuousVertexMap.I lwoDiscontinuousVertexMap.cxx lwoDiscontinuousVertexMap.h \
+    lwoGroupChunk.I lwoGroupChunk.cxx lwoGroupChunk.h \
+    lwoHeader.I lwoHeader.cxx \
+    lwoHeader.h lwoInputFile.I lwoInputFile.cxx lwoInputFile.h \
+    lwoLayer.h lwoLayer.I lwoLayer.cxx \
+    lwoPoints.h lwoPoints.I lwoPoints.cxx \
+    lwoPolygons.h lwoPolygons.I lwoPolygons.cxx \
+    lwoPolygonTags.h lwoPolygonTags.I lwoPolygonTags.cxx \
+    lwoTags.h lwoTags.I lwoTags.cxx \
+    lwoVertexMap.h lwoVertexMap.I lwoVertexMap.cxx
+
+  #define INSTALL_HEADERS \
+    iffChunk.I iffChunk.h iffGenericChunk.I iffGenericChunk.h iffId.I \
+    iffId.h iffInputFile.I iffInputFile.h \
+    lwoChunk.I lwoChunk.h \
+    lwoDiscontinuousVertexMap.I lwoDiscontinuousVertexMap.h \
+    lwoGroupChunk.I lwoGroupChunk.h \
+    lwoHeader.I lwoHeader.h \
+    lwoInputFile.I lwoInputFile.h \
+    lwoLayer.I lwoLayer.h \
+    lwoPoints.I lwoPoints.h \
+    lwoPolygons.I lwoPolygons.h \
+    lwoPolygonTags.I lwoPolygonTags.h \
+    lwoTags.I lwoTags.h \
+    lwoVertexMap.I lwoVertexMap.h
+
+#end ss_lib_target
+
+#begin test_bin_target
+  #define TARGET test_lwo
+  #define LOCAL_LIBS lwo $[LOCAL_LIBS]
+  #define OTHER_LIBS $[OTHER_LIBS] pystub:c
+
+  #define SOURCES \
+    test_lwo.cxx
+
+#end test_bin_target

+ 42 - 0
pandatool/src/lwo/config_lwo.cxx

@@ -0,0 +1,42 @@
+// Filename: config_lwo.cxx
+// Created by:  drose (23Apr01)
+// 
+////////////////////////////////////////////////////////////////////
+
+#include "config_lwo.h"
+#include "iffChunk.h"
+#include "iffGenericChunk.h"
+#include "iffInputFile.h"
+#include "lwoChunk.h"
+#include "lwoDiscontinuousVertexMap.h"
+#include "lwoGroupChunk.h"
+#include "lwoHeader.h"
+#include "lwoInputFile.h"
+#include "lwoLayer.h"
+#include "lwoPoints.h"
+#include "lwoPolygons.h"
+#include "lwoPolygonTags.h"
+#include "lwoTags.h"
+#include "lwoVertexMap.h"
+
+#include <dconfig.h>
+
+Configure(config_lwo);
+
+ConfigureFn(config_lwo) {
+  IffChunk::init_type();
+  IffGenericChunk::init_type();
+  IffInputFile::init_type();
+  LwoChunk::init_type();
+  LwoDiscontinuousVertexMap::init_type();
+  LwoGroupChunk::init_type();
+  LwoHeader::init_type();
+  LwoInputFile::init_type();
+  LwoLayer::init_type();
+  LwoPoints::init_type();
+  LwoPolygons::init_type();
+  LwoPolygonTags::init_type();
+  LwoTags::init_type();
+  LwoVertexMap::init_type();
+}
+

+ 11 - 0
pandatool/src/lwo/config_lwo.h

@@ -0,0 +1,11 @@
+// Filename: config_lwo.h
+// Created by:  drose (23Apr01)
+// 
+////////////////////////////////////////////////////////////////////
+
+#ifndef CONFIG_LWO_H
+#define CONFIG_LWO_H
+
+#include <pandatoolbase.h>
+
+#endif

+ 34 - 0
pandatool/src/lwo/iffChunk.I

@@ -0,0 +1,34 @@
+// Filename: iffChunk.I
+// Created by:  drose (23Apr01)
+// 
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: IffChunk::Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE IffChunk::
+IffChunk() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: IffChunk::get_id
+//       Access: Public
+//  Description: Returns the ID associated with this chunk.
+////////////////////////////////////////////////////////////////////
+INLINE IffId IffChunk::
+get_id() const {
+  return _id;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: IffChunk::set_id
+//       Access: Public
+//  Description: Changes the ID associated with this chunk.
+////////////////////////////////////////////////////////////////////
+INLINE void IffChunk::
+set_id(IffId id) {
+  _id = id;
+}

+ 43 - 0
pandatool/src/lwo/iffChunk.cxx

@@ -0,0 +1,43 @@
+// Filename: iffChunk.cxx
+// Created by:  drose (23Apr01)
+// 
+////////////////////////////////////////////////////////////////////
+
+#include "iffChunk.h"
+#include "iffInputFile.h"
+
+#include <indent.h>
+
+TypeHandle IffChunk::_type_handle;
+
+////////////////////////////////////////////////////////////////////
+//     Function: IffChunk::output
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void IffChunk::
+output(ostream &out) const {
+  out << _id << " (" << get_type() << ")";
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: IffChunk::write
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void IffChunk::
+write(ostream &out, int indent_level) const {
+  indent(out, indent_level) << _id << " { ... }\n";
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: IffChunk::make_new_chunk
+//       Access: Public, Virtual
+//  Description: Allocates and returns a new chunk of the appropriate
+//               type based on the given ID, according to the context
+//               given by this chunk itself.
+////////////////////////////////////////////////////////////////////
+IffChunk *IffChunk::
+make_new_chunk(IffInputFile *in, IffId id) {
+  return in->make_new_chunk(id);
+}

+ 67 - 0
pandatool/src/lwo/iffChunk.h

@@ -0,0 +1,67 @@
+// Filename: iffChunk.h
+// Created by:  drose (23Apr01)
+// 
+////////////////////////////////////////////////////////////////////
+
+#ifndef IFFCHUNK_H
+#define IFFCHUNK_H
+
+#include <pandatoolbase.h>
+
+#include "iffId.h"
+
+#include <typeHandle.h>
+#include <typedReferenceCount.h>
+
+class IffInputFile;
+
+////////////////////////////////////////////////////////////////////
+// 	 Class : IffChunk
+// Description : The basic kind of record in an EA "IFF" file, which
+//               the LightWave object file is based on.
+////////////////////////////////////////////////////////////////////
+class IffChunk : public TypedReferenceCount {
+public:
+  INLINE IffChunk();
+
+  INLINE IffId get_id() const;
+  INLINE void set_id(IffId id);
+
+  virtual bool read_iff(IffInputFile *in, size_t stop_at)=0;
+
+  virtual void output(ostream &out) const;
+  virtual void write(ostream &out, int indent_level = 0) const;
+
+  virtual IffChunk *make_new_chunk(IffInputFile *in, IffId id);
+
+private:
+  IffId _id;
+
+public:
+  virtual TypeHandle get_type() const {
+    return get_class_type();
+  }
+  virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    TypedReferenceCount::init_type();
+    register_type(_type_handle, "IffChunk",
+		  TypedReferenceCount::get_class_type());
+  }
+
+private:
+  static TypeHandle _type_handle;
+};
+
+#include "iffChunk.I"
+
+INLINE ostream &operator << (ostream &out, const IffChunk &chunk) {
+  chunk.output(out);
+  return out;
+}
+
+#endif
+
+  

+ 34 - 0
pandatool/src/lwo/iffGenericChunk.I

@@ -0,0 +1,34 @@
+// Filename: iffGenericChunk.I
+// Created by:  drose (23Apr01)
+// 
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: IffGenericChunk::Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE IffGenericChunk::
+IffGenericChunk() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: IffGenericChunk::get_data
+//       Access: Public
+//  Description: Returns the data in the chunk.
+////////////////////////////////////////////////////////////////////
+INLINE const Datagram &IffGenericChunk::
+get_data() const {
+  return _data;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: IffGenericChunk::set_data
+//       Access: Public
+//  Description: Changes the data in the chunk
+////////////////////////////////////////////////////////////////////
+INLINE void IffGenericChunk::
+set_data(const Datagram &data) {
+  _data = data;
+}

+ 42 - 0
pandatool/src/lwo/iffGenericChunk.cxx

@@ -0,0 +1,42 @@
+// Filename: iffGenericChunk.cxx
+// Created by:  drose (23Apr01)
+// 
+////////////////////////////////////////////////////////////////////
+
+#include "iffGenericChunk.h"
+#include "iffInputFile.h"
+
+#include <indent.h>
+
+TypeHandle IffGenericChunk::_type_handle;
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: IffGenericChunk::read_iff
+//       Access: Public, Virtual
+//  Description: Reads the data of the chunk in from the given input
+//               file, if possible.  The ID and length of the chunk
+//               have already been read.  stop_at is the byte position
+//               of the file to stop at (based on the current position
+//               at in->get_bytes_read()).  Returns true on success,
+//               false otherwise.
+////////////////////////////////////////////////////////////////////
+bool IffGenericChunk::
+read_iff(IffInputFile *in, size_t stop_at) {
+  size_t length = stop_at - in->get_bytes_read();
+  bool result = in->read_bytes(_data, length);
+  in->align();
+  return result;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: IffGenericChunk::write
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void IffGenericChunk::
+write(ostream &out, int indent_level) const {
+  indent(out, indent_level)
+    << get_id() << " { " << _data.get_length() << " bytes }\n";
+}
+

+ 57 - 0
pandatool/src/lwo/iffGenericChunk.h

@@ -0,0 +1,57 @@
+// Filename: iffGenericChunk.h
+// Created by:  drose (23Apr01)
+// 
+////////////////////////////////////////////////////////////////////
+
+#ifndef IFFGENERICCHUNK_H
+#define IFFGENERICCHUNK_H
+
+#include <pandatoolbase.h>
+
+#include "iffChunk.h"
+
+#include <datagram.h>
+
+
+////////////////////////////////////////////////////////////////////
+// 	 Class : IffGenericChunk
+// Description : A class for a generic kind of IffChunk that is not
+//               understood by a particular IffReader.  It remembers
+//               its entire contents.
+////////////////////////////////////////////////////////////////////
+class IffGenericChunk : public IffChunk {
+public:
+  INLINE IffGenericChunk();
+
+  INLINE const Datagram &get_data() const;
+  INLINE void set_data(const Datagram &data);
+
+  virtual bool read_iff(IffInputFile *in, size_t stop_at);
+  virtual void write(ostream &out, int indent_level = 0) const;
+
+private:
+  Datagram _data;
+
+public:
+  virtual TypeHandle get_type() const {
+    return get_class_type();
+  }
+  virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    IffChunk::init_type();
+    register_type(_type_handle, "IffGenericChunk",
+		  IffChunk::get_class_type());
+  }
+
+private:
+  static TypeHandle _type_handle;
+};
+
+#include "iffGenericChunk.I"
+
+#endif
+
+  

+ 96 - 0
pandatool/src/lwo/iffId.I

@@ -0,0 +1,96 @@
+// Filename: iffId.I
+// Created by:  drose (23Apr01)
+// 
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: IffId::Default Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE IffId::
+IffId() {
+  _id._c[0] = 0;
+  _id._c[1] = 0;
+  _id._c[2] = 0;
+  _id._c[3] = 0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: IffId::Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE IffId::
+IffId(const char id[4]) {
+  _id._c[0] = id[0];
+  _id._c[1] = id[1];
+  _id._c[2] = id[2];
+  _id._c[3] = id[3];
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: IffId::Copy Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE IffId::
+IffId(const IffId &copy) {
+  _id._n = copy._id._n;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: IffId::Copy Assignment Operator
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE void IffId::
+operator = (const IffId &copy) {
+  _id._n = copy._id._n;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: IffId::Equivalence Operator
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE bool IffId::
+operator == (const IffId &other) const {
+  return (_id._n == other._id._n);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: IffId::Nonequivalence Operator
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE bool IffId::
+operator != (const IffId &other) const {
+  return (_id._n != other._id._n);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: IffId::Ordering Operator
+//       Access: Public
+//  Description: The ordering is arbitrary, and may not even be
+//               consistent between different architectures
+//               (e.g. big-endian and little-endian).  It is useful
+//               mainly for putting IffId's into a sorted container,
+//               like sets and maps.
+////////////////////////////////////////////////////////////////////
+INLINE bool IffId::
+operator < (const IffId &other) const {
+  return (_id._n < other._id._n);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: IffId::get_name
+//       Access: Public
+//  Description: Returns the four-character name of the Id, for
+//               outputting.
+////////////////////////////////////////////////////////////////////
+INLINE string IffId::
+get_name() const {
+  return string(_id._c, 4);
+}

+ 6 - 0
pandatool/src/lwo/iffId.cxx

@@ -0,0 +1,6 @@
+// Filename: iffId.cxx
+// Created by:  drose (23Apr01)
+// 
+////////////////////////////////////////////////////////////////////
+
+#include "iffId.h"

+ 46 - 0
pandatool/src/lwo/iffId.h

@@ -0,0 +1,46 @@
+// Filename: iffId.h
+// Created by:  drose (23Apr01)
+// 
+////////////////////////////////////////////////////////////////////
+
+#ifndef IFFID_H
+#define IFFID_H
+
+#include <pandatoolbase.h>
+
+#include <numeric_types.h>
+
+////////////////////////////////////////////////////////////////////
+// 	 Class : IffId
+// Description : A four-byte chunk ID appearing in an "IFF" file.
+//               This is used to identify the meaning of each chunk,
+//               and can be treated either as a concrete object or as
+//               a string, something like a TypeHandle.
+////////////////////////////////////////////////////////////////////
+class IffId {
+public:
+  INLINE IffId();
+  INLINE IffId(const char id[4]);
+  INLINE IffId(const IffId &copy);
+  INLINE void operator = (const IffId &copy);
+
+  INLINE bool operator == (const IffId &other) const;
+  INLINE bool operator != (const IffId &other) const;
+  INLINE bool operator < (const IffId &other) const;
+
+  INLINE string get_name() const;
+  
+private:
+  union {
+    PN_uint32 _n;
+    char _c[4];
+  } _id;
+};
+
+#include "iffId.I"
+
+INLINE ostream &operator << (ostream &out, const IffId &id) {
+  return out << id.get_name();
+}
+ 
+#endif

+ 63 - 0
pandatool/src/lwo/iffInputFile.I

@@ -0,0 +1,63 @@
+// Filename: iffInputFile.I
+// Created by:  drose (24Apr01)
+// 
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: IffInputFile::set_filename
+//       Access: Public
+//  Description: Indicates the filename that the InputFile is
+//               currently opened on.
+////////////////////////////////////////////////////////////////////
+INLINE void IffInputFile::
+set_filename(const Filename &filename) {
+  _filename = filename;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: IffInputFile::get_filename
+//       Access: Public
+//  Description: Returns the filename that the InputFile is
+//               currently opened on, if available.
+////////////////////////////////////////////////////////////////////
+INLINE const Filename &IffInputFile::
+get_filename() const {
+  return _filename;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: IffInputFile::is_eof
+//       Access: Public
+//  Description: Returns true if the last read operation failed
+//               because of reaching EOF, false otherwise.
+////////////////////////////////////////////////////////////////////
+INLINE bool IffInputFile::
+is_eof() const {
+  return _eof;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: IffInputFile::get_bytes_read
+//       Access: Public
+//  Description: Returns the number of bytes read so far from the
+//               input file.
+////////////////////////////////////////////////////////////////////
+INLINE size_t IffInputFile::
+get_bytes_read() const {
+  return _bytes_read;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: IffInputFile::align
+//       Access: Public
+//  Description: If the current file pointer is not positioned on an
+//               even-byte boundary, reads and discards one byte so
+//               that it is.
+////////////////////////////////////////////////////////////////////
+INLINE void IffInputFile::
+align() {
+  if ((_bytes_read & 1) != 0) {
+    get_int8();
+  }
+}

+ 374 - 0
pandatool/src/lwo/iffInputFile.cxx

@@ -0,0 +1,374 @@
+// Filename: iffInputFile.cxx
+// Created by:  drose (24Apr01)
+// 
+////////////////////////////////////////////////////////////////////
+
+#include "iffInputFile.h"
+#include "iffGenericChunk.h"
+
+#include <datagram.h>
+#include <datagramIterator.h>
+
+TypeHandle IffInputFile::_type_handle;
+
+////////////////////////////////////////////////////////////////////
+//     Function: IffInputFile::Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+IffInputFile::
+IffInputFile() {
+  _input = (istream *)NULL;
+  _owns_istream = false;
+  _eof = true;
+  _bytes_read = 0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: IffInputFile::Destructor
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+IffInputFile::
+~IffInputFile() {
+  if (_owns_istream) {
+    delete _input;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: IffInputFile::open_read
+//       Access: Public
+//  Description: Attempts to open the indicated filename for reading.
+//               Returns true if successful, false otherwise.
+////////////////////////////////////////////////////////////////////
+bool IffInputFile::
+open_read(Filename filename) {
+  filename.set_binary();
+  ifstream *in = new ifstream;
+  if (filename.open_read(*in)) {
+    set_input(in, true);
+    set_filename(filename);
+    return true;
+  }
+
+  return false;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: IffInputFile::set_input
+//       Access: Public
+//  Description: Sets up the input to use an arbitrary istream.  If
+//               owns_istream is true, the istream will be deleted
+//               when the IffInputFile destructs.
+////////////////////////////////////////////////////////////////////
+void IffInputFile::
+set_input(istream *input, bool owns_istream) {
+  if (_owns_istream) {
+    delete _input;
+  }
+  _input = input;
+  _owns_istream = owns_istream;
+  _eof = false;
+  _bytes_read = 0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: IffInputFile::get_int8
+//       Access: Public
+//  Description: Extracts a signed 8-bit integer.
+////////////////////////////////////////////////////////////////////
+PN_int8 IffInputFile::
+get_int8() {
+  Datagram dg;
+  if (!read_bytes(dg, 1)) {
+    return 0;
+  }
+  DatagramIterator dgi(dg);
+  return dgi.get_int8();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: IffInputFile::get_uint8
+//       Access: Public
+//  Description: Extracts an unsigned 8-bit integer.
+////////////////////////////////////////////////////////////////////
+PN_uint8 IffInputFile::
+get_uint8() {
+  Datagram dg;
+  if (!read_bytes(dg, 1)) {
+    return 0;
+  }
+  DatagramIterator dgi(dg);
+  return dgi.get_int8();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: IffInputFile::get_be_int16
+//       Access: Public
+//  Description: Extracts a signed 16-bit big-endian integer.
+////////////////////////////////////////////////////////////////////
+PN_int16 IffInputFile::
+get_be_int16() {
+  Datagram dg;
+  if (!read_bytes(dg, 2)) {
+    return 0;
+  }
+  DatagramIterator dgi(dg);
+  return dgi.get_be_int16();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: IffInputFile::get_be_int32
+//       Access: Public
+//  Description: Extracts a signed 32-bit big-endian integer.
+////////////////////////////////////////////////////////////////////
+PN_int32 IffInputFile::
+get_be_int32() {
+  Datagram dg;
+  if (!read_bytes(dg, 4)) {
+    return 0;
+  }
+  DatagramIterator dgi(dg);
+  return dgi.get_be_int32();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: IffInputFile::get_be_uint16
+//       Access: Public
+//  Description: Extracts an unsigned 16-bit big-endian integer.
+////////////////////////////////////////////////////////////////////
+PN_uint16 IffInputFile::
+get_be_uint16() {
+  Datagram dg;
+  if (!read_bytes(dg, 2)) {
+    return 0;
+  }
+  DatagramIterator dgi(dg);
+  return dgi.get_be_uint16();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: IffInputFile::get_be_uint32
+//       Access: Public
+//  Description: Extracts an unsigned 32-bit big-endian integer.
+////////////////////////////////////////////////////////////////////
+PN_uint32 IffInputFile::
+get_be_uint32() {
+  Datagram dg;
+  if (!read_bytes(dg, 4)) {
+    return 0;
+  }
+  DatagramIterator dgi(dg);
+  return dgi.get_be_uint32();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: IffInputFile::get_be_float32
+//       Access: Public
+//  Description: Extracts a 32-bit big-endian single-precision
+//               floating-point number.
+////////////////////////////////////////////////////////////////////
+float IffInputFile::
+get_be_float32() {
+  Datagram dg;
+  if (!read_bytes(dg, 4)) {
+    return 0;
+  }
+  DatagramIterator dgi(dg);
+  return dgi.get_be_float32();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: IffInputFile::get_string
+//       Access: Public
+//  Description: Extracts a null-terminated string.
+////////////////////////////////////////////////////////////////////
+string IffInputFile::
+get_string() {
+  string result;
+  char byte;
+  while (read_byte(byte)) {
+    if (byte == 0) {
+      break;
+    }
+    result += byte;
+  }
+
+  align();
+  return result;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: IffInputFile::get_id
+//       Access: Public
+//  Description: Extracts a 4-character IFF ID.
+////////////////////////////////////////////////////////////////////
+IffId IffInputFile::
+get_id() {
+  Datagram dg;
+  if (!read_bytes(dg, 4)) {
+    return IffId();
+  }
+  const char *id = (const char *)dg.get_data();
+  return IffId(id);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: IffInputFile::get_chunk
+//       Access: Public
+//  Description: Reads a single IffChunk, determining its type based
+//               on its ID.  Allocates and returns a new IffChunk
+//               object of the appropriate type.  Returns NULL if EOF
+//               is reached before the chunk can be read completely,
+//               or if there is some other error in reading the chunk.
+////////////////////////////////////////////////////////////////////
+PT(IffChunk) IffInputFile::
+get_chunk() {
+  IffId id = get_id();
+  PN_uint32 length = get_be_uint32();
+
+  if (!is_eof()) {
+    PT(IffChunk) chunk = make_new_chunk(id);
+    chunk->set_id(id);
+
+    size_t start_point = get_bytes_read();
+    size_t end_point = start_point + length;
+
+    if (chunk->read_iff(this, end_point)) {
+      size_t num_bytes_read = get_bytes_read() - start_point;
+      if (num_bytes_read > length) {
+	nout << *chunk << " read " << num_bytes_read
+	     << " instead of " << length << " bytes.\n";
+	return (IffChunk *)NULL;
+
+      } else if (num_bytes_read < length) {
+	size_t skip_count = length - num_bytes_read;
+	nout << "Ignoring " << skip_count << " bytes at the end of "
+	     << *chunk << "\n";
+	skip_bytes(skip_count);
+      }	
+      return chunk;
+    }
+  }
+
+  return (IffChunk *)NULL;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: IffInputFile::get_sub_chunk
+//       Access: Public
+//  Description: Similar to get_chunk(), except the chunk size is only
+//               a 16-bit number instead of 32-bit, and it takes a
+//               context, which is the chunk in which this chunk is
+//               encountered.  The parent chunk may (or may not)
+//               decide what kind of chunk is meant by the various
+//               id's encountered.
+////////////////////////////////////////////////////////////////////
+PT(IffChunk) IffInputFile::
+get_sub_chunk(IffChunk *context) {
+  IffId id = get_id();
+  PN_uint16 length = get_be_uint16();
+
+  if (!is_eof()) {
+    PT(IffChunk) chunk = context->make_new_chunk(this, id);
+    chunk->set_id(id);
+
+    size_t start_point = get_bytes_read();
+    size_t end_point = start_point + length;
+
+    if (chunk->read_iff(this, end_point)) {
+      size_t num_bytes_read = get_bytes_read() - start_point;
+      if (num_bytes_read > length) {
+	nout << *chunk << " read " << num_bytes_read
+	     << " instead of " << length << " bytes.\n";
+	return (IffChunk *)NULL;
+
+      } else if (num_bytes_read < length) {
+	size_t skip_count = length - num_bytes_read;
+	nout << "Ignoring " << skip_count << " bytes at the end of "
+	     << *chunk << "\n";
+	skip_bytes(skip_count);
+      }	
+      return chunk;
+    }
+  }
+
+  return (IffChunk *)NULL;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: IffInputFile::read_byte
+//       Access: Public
+//  Description: Reads a single byte.  Returns true if successful,
+//               false otherwise.
+////////////////////////////////////////////////////////////////////
+bool IffInputFile::
+read_byte(char &byte) {
+  if (is_eof()) {
+    return false;
+  }
+
+  _input->get(byte);
+  _bytes_read++;
+  _eof = _input->eof() || _input->fail();
+  return !is_eof();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: IffInputFile::read_bytes
+//       Access: Public
+//  Description: Reads a series of bytes, and stores them in the
+//               indicated Datagram.  Returns true if successful,
+//               false otherwise.
+////////////////////////////////////////////////////////////////////
+bool IffInputFile::
+read_bytes(Datagram &datagram, size_t length) {
+  if (is_eof()) {
+    return false;
+  }
+
+  char *buffer = new char[length];
+  _input->read(buffer, length);
+  _eof = (_input->gcount() != length);
+  if (is_eof()) {
+    return false;
+  }
+
+  _bytes_read += length;
+  datagram = Datagram(buffer, length);
+  delete[] buffer;
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: IffInputFile::skip_bytes
+//       Access: Public
+//  Description: Reads a series of bytes, but does not store them.
+//               Returns true if successful, false otherwise.
+////////////////////////////////////////////////////////////////////
+bool IffInputFile::
+skip_bytes(size_t length) {
+  if (is_eof()) {
+    return false;
+  }
+
+  char byte;
+  while (length > 0 && !is_eof()) {
+    read_byte(byte);
+    length--;
+  }
+
+  return !is_eof();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: IffInputFile::make_new_chunk
+//       Access: Protected, Virtual
+//  Description: Allocates and returns a new chunk of the appropriate
+//               type based on the given ID.
+////////////////////////////////////////////////////////////////////
+IffChunk *IffInputFile::
+make_new_chunk(IffId) {
+  return new IffGenericChunk;
+}

+ 93 - 0
pandatool/src/lwo/iffInputFile.h

@@ -0,0 +1,93 @@
+// Filename: iffInputFile.h
+// Created by:  drose (24Apr01)
+// 
+////////////////////////////////////////////////////////////////////
+
+#ifndef IFFINPUTFILE_H
+#define IFFINPUTFILE_H
+
+#include <pandatoolbase.h>
+
+#include "iffId.h"
+#include "iffChunk.h"
+
+#include <typeHandle.h>
+#include <pointerTo.h>
+
+class Datagram;
+
+////////////////////////////////////////////////////////////////////
+// 	 Class : IffInputFile
+// Description : A wrapper around an istream used for reading an IFF
+//               file.
+////////////////////////////////////////////////////////////////////
+class IffInputFile : public TypedObject {
+public:
+  IffInputFile();
+  virtual ~IffInputFile();
+
+  bool open_read(Filename filename);
+  void set_input(istream *input, bool owns_istream);
+
+  INLINE void set_filename(const Filename &filename);
+  INLINE const Filename &get_filename() const;
+
+  INLINE bool is_eof() const;
+  INLINE size_t get_bytes_read() const;
+
+  INLINE void align();
+
+  PN_int8 get_int8();
+  PN_uint8 get_uint8();
+
+  PN_int16 get_be_int16();
+  PN_int32 get_be_int32();
+  PN_uint16 get_be_uint16();
+  PN_uint32 get_be_uint32();
+  float get_be_float32();
+
+  string get_string();
+
+  IffId get_id();
+
+  PT(IffChunk) get_chunk(); 
+  PT(IffChunk) get_sub_chunk(IffChunk *context); 
+
+  bool read_byte(char &byte);
+  bool read_bytes(Datagram &datagram, size_t length);
+  bool skip_bytes(size_t length);
+
+protected:
+  virtual IffChunk *make_new_chunk(IffId id);
+
+  istream *_input;
+  Filename _filename;
+  bool _owns_istream;
+  bool _eof;
+  size_t _bytes_read;
+
+public:
+  virtual TypeHandle get_type() const {
+    return get_class_type();
+  }
+  virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    TypedObject::init_type();
+    register_type(_type_handle, "IffInputFile",
+		  TypedObject::get_class_type());
+  }
+
+private:
+  static TypeHandle _type_handle;
+
+  friend IffChunk;
+};
+
+#include "iffInputFile.I"
+
+#endif
+
+  

+ 4 - 0
pandatool/src/lwo/lwoChunk.I

@@ -0,0 +1,4 @@
+// Filename: lwoChunk.I
+// Created by:  drose (24Apr01)
+// 
+////////////////////////////////////////////////////////////////////

+ 8 - 0
pandatool/src/lwo/lwoChunk.cxx

@@ -0,0 +1,8 @@
+// Filename: lwoChunk.cxx
+// Created by:  drose (24Apr01)
+// 
+////////////////////////////////////////////////////////////////////
+
+#include "lwoChunk.h"
+
+TypeHandle LwoChunk::_type_handle;

+ 46 - 0
pandatool/src/lwo/lwoChunk.h

@@ -0,0 +1,46 @@
+// Filename: lwoChunk.h
+// Created by:  drose (24Apr01)
+// 
+////////////////////////////////////////////////////////////////////
+
+#ifndef LWOCHUNK_H
+#define LWOCHUNK_H
+
+#include <pandatoolbase.h>
+
+#include "iffChunk.h"
+
+////////////////////////////////////////////////////////////////////
+// 	 Class : LwoChunk
+// Description : A specialization of IffChunk for Lightwave Object
+//               files.  Each kind of chunk that is specific to a
+//               Lightwave file should inherit directly or indirectly
+//               from LwoChunk.
+////////////////////////////////////////////////////////////////////
+class LwoChunk : public IffChunk {
+public:
+  // No particular interface here.
+
+public:
+  virtual TypeHandle get_type() const {
+    return get_class_type();
+  }
+  virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    IffChunk::init_type();
+    register_type(_type_handle, "LwoChunk",
+		  IffChunk::get_class_type());
+  }
+
+private:
+  static TypeHandle _type_handle;
+};
+
+#include "lwoChunk.I"
+
+#endif
+
+  

+ 4 - 0
pandatool/src/lwo/lwoDiscontinuousVertexMap.I

@@ -0,0 +1,4 @@
+// Filename: lwoDiscontinuousVertexMap.I
+// Created by:  drose (24Apr01)
+// 
+////////////////////////////////////////////////////////////////////

+ 104 - 0
pandatool/src/lwo/lwoDiscontinuousVertexMap.cxx

@@ -0,0 +1,104 @@
+// Filename: lwoDiscontinuousVertexMap.cxx
+// Created by:  drose (24Apr01)
+// 
+////////////////////////////////////////////////////////////////////
+
+#include "lwoDiscontinuousVertexMap.h"
+#include "lwoInputFile.h"
+
+#include <indent.h>
+
+TypeHandle LwoDiscontinuousVertexMap::_type_handle;
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: LwoDiscontinuousVertexMap::has_value
+//       Access: Public
+//  Description: Returns true if the map has a value associated with
+//               the given index, false otherwise.
+////////////////////////////////////////////////////////////////////
+bool LwoDiscontinuousVertexMap::
+has_value(int polygon_index, int vertex_index) const {
+  VMad::const_iterator di;
+  di = _vmad.find(polygon_index);
+  if (di != _vmad.end()) {
+    const VMap &vmap = (*di).second;
+    return (vmap.count(vertex_index) != 0);
+  }
+
+  return false;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: LwoDiscontinuousVertexMap::get_value
+//       Access: Public
+//  Description: Returns the mapping value associated with the given
+//               index, or an empty PTA_float if there is no mapping
+//               value associated.
+////////////////////////////////////////////////////////////////////
+PTA_float LwoDiscontinuousVertexMap::
+get_value(int polygon_index, int vertex_index) const {
+  VMad::const_iterator di;
+  di = _vmad.find(polygon_index);
+  if (di != _vmad.end()) {
+    const VMap &vmap = (*di).second;
+    VMap::const_iterator vi;
+    vi = vmap.find(vertex_index);
+    if (vi != vmap.end()) {
+      return (*vi).second;
+    }
+  }
+
+  return PTA_float();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: LwoDiscontinuousVertexMap::read_iff
+//       Access: Public, Virtual
+//  Description: Reads the data of the chunk in from the given input
+//               file, if possible.  The ID and length of the chunk
+//               have already been read.  stop_at is the byte position
+//               of the file to stop at (based on the current position
+//               at in->get_bytes_read()).  Returns true on success,
+//               false otherwise.
+////////////////////////////////////////////////////////////////////
+bool LwoDiscontinuousVertexMap::
+read_iff(IffInputFile *in, size_t stop_at) {
+  LwoInputFile *lin = DCAST(LwoInputFile, in);
+
+  _map_type = lin->get_id();
+  _dimension = lin->get_be_uint16();
+  _name = lin->get_string();
+
+  while (lin->get_bytes_read() < stop_at && !lin->is_eof()) {
+    int vertex_index = lin->get_vx();
+    int polygon_index = lin->get_vx();
+
+    PTA_float value;
+    for (int i = 0; i < _dimension; i++) {
+      value.push_back(lin->get_be_float32());
+    }
+
+    bool inserted = _vmad[polygon_index].insert(VMap::value_type(vertex_index, value)).second;
+    if (!inserted) {
+      nout << "Duplicate pair " << polygon_index << ", " << vertex_index
+	   << " in map.\n";
+    }
+  }
+
+  return (lin->get_bytes_read() == stop_at);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: LwoDiscontinuousVertexMap::write
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void LwoDiscontinuousVertexMap::
+write(ostream &out, int indent_level) const {
+  indent(out, indent_level)
+    << get_id() << " { map_type = " << _map_type 
+    << ", dimension = " << _dimension
+    << ", name = \"" << _name << "\", "
+    << _vmad.size() << " polygons }\n";
+}

+ 61 - 0
pandatool/src/lwo/lwoDiscontinuousVertexMap.h

@@ -0,0 +1,61 @@
+// Filename: lwoDiscontinuousVertexMap.h
+// Created by:  drose (24Apr01)
+// 
+////////////////////////////////////////////////////////////////////
+
+#ifndef LWODISCONTINUOUSVERTEXMAP_H
+#define LWODISCONTINUOUSVERTEXMAP_H
+
+#include <pandatoolbase.h>
+
+#include "lwoChunk.h"
+
+#include <pta_float.h>
+
+////////////////////////////////////////////////////////////////////
+// 	 Class : LwoDiscontinuousVertexMap
+// Description : A mapping of floating-point values per integer index.
+//               The meaning of these values is determined by the
+//               mapping type code and/or its name.
+////////////////////////////////////////////////////////////////////
+class LwoDiscontinuousVertexMap : public LwoChunk {
+public:
+  bool has_value(int polygon_index, int vertex_index) const;
+  PTA_float get_value(int polygon_index, int vertex_index) const;
+
+  IffId _map_type;
+  int _dimension;
+  string _name;
+
+public:
+  virtual bool read_iff(IffInputFile *in, size_t stop_at);
+  virtual void write(ostream &out, int indent_level = 0) const;
+
+private:
+  typedef map<int, PTA_float> VMap;
+  typedef map<int, VMap> VMad;
+  VMad _vmad;
+  
+public:
+  virtual TypeHandle get_type() const {
+    return get_class_type();
+  }
+  virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    LwoChunk::init_type();
+    register_type(_type_handle, "LwoDiscontinuousVertexMap",
+		  LwoChunk::get_class_type());
+  }
+
+private:
+  static TypeHandle _type_handle;
+};
+
+#include "lwoDiscontinuousVertexMap.I"
+
+#endif
+
+  

+ 4 - 0
pandatool/src/lwo/lwoGroupChunk.I

@@ -0,0 +1,4 @@
+// Filename: lwoGroupChunk.I
+// Created by:  drose (24Apr01)
+// 
+////////////////////////////////////////////////////////////////////

+ 68 - 0
pandatool/src/lwo/lwoGroupChunk.cxx

@@ -0,0 +1,68 @@
+// Filename: lwoGroupChunk.cxx
+// Created by:  drose (24Apr01)
+// 
+////////////////////////////////////////////////////////////////////
+
+#include "lwoGroupChunk.h"
+#include "lwoInputFile.h"
+
+#include <notify.h>
+
+TypeHandle LwoGroupChunk::_type_handle;
+
+////////////////////////////////////////////////////////////////////
+//     Function: LwoGroupChunk::get_num_children
+//       Access: Public
+//  Description: Returns the number of child chunks of this group.
+////////////////////////////////////////////////////////////////////
+int LwoGroupChunk::
+get_num_children() const {
+  return _children.size();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: LwoGroupChunk::get_child
+//       Access: Public
+//  Description: Returns the nth child chunk of this group.
+////////////////////////////////////////////////////////////////////
+IffChunk *LwoGroupChunk::
+get_child(int n) const {
+  nassertr(n >= 0 && n < (int)_children.size(), (IffChunk *)NULL);
+  return _children[n];
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: LwoGroupChunk::read_children_iff
+//       Access: Public
+//  Description: Reads a sequence of child chunks, until byte stop_at
+//               has been been reached, and stores them as the
+//               children.  Returns true if successful (and exactly
+//               the correct number of bytes were read), or false
+//               otherwise.
+////////////////////////////////////////////////////////////////////
+bool LwoGroupChunk::
+read_children_iff(IffInputFile *in, size_t stop_at) {
+  while (in->get_bytes_read() < stop_at && !in->is_eof()) {
+    PT(IffChunk) chunk = in->get_chunk();
+    if (chunk == (IffChunk *)NULL) {
+      return false;
+    }
+    _children.push_back(chunk);
+  }
+
+  return (in->get_bytes_read() == stop_at);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: LwoGroupChunk::write_children
+//       Access: Public
+//  Description: Formats the list of children for output to the user
+//               (primarily for debugging), one per line.
+////////////////////////////////////////////////////////////////////
+void LwoGroupChunk::
+write_children(ostream &out, int indent_level) const {
+  Children::const_iterator ci;
+  for (ci = _children.begin(); ci != _children.end(); ++ci) {
+    (*ci)->write(out, indent_level);
+  }
+}

+ 57 - 0
pandatool/src/lwo/lwoGroupChunk.h

@@ -0,0 +1,57 @@
+// Filename: lwoGroupChunk.h
+// Created by:  drose (24Apr01)
+// 
+////////////////////////////////////////////////////////////////////
+
+#ifndef LWOGROUPCHUNK_H
+#define LWOGROUPCHUNK_H
+
+#include <pandatoolbase.h>
+
+#include "lwoChunk.h"
+#include "iffChunk.h"
+
+#include <pointerTo.h>
+
+#include <vector>
+
+////////////////////////////////////////////////////////////////////
+// 	 Class : LwoGroupChunk
+// Description : A particular kind of LwoChunk that is expected to
+//               contain an arbitrary number of child chunks.
+////////////////////////////////////////////////////////////////////
+class LwoGroupChunk : public LwoChunk {
+public:
+  int get_num_children() const;
+  IffChunk *get_child(int n) const;
+
+protected:
+  bool read_children_iff(IffInputFile *in, size_t stop_at);
+  void write_children(ostream &out, int indent_level) const;
+
+  typedef vector< PT(IffChunk) > Children;
+  Children _children;
+
+public:
+  virtual TypeHandle get_type() const {
+    return get_class_type();
+  }
+  virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    LwoChunk::init_type();
+    register_type(_type_handle, "LwoGroupChunk",
+		  LwoChunk::get_class_type());
+  }
+
+private:
+  static TypeHandle _type_handle;
+};
+
+#include "lwoGroupChunk.I"
+
+#endif
+
+  

+ 16 - 0
pandatool/src/lwo/lwoHeader.I

@@ -0,0 +1,16 @@
+// Filename: lwoHeader.I
+// Created by:  drose (24Apr01)
+// 
+////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////
+//     Function: LwoHeader::get_lwid
+//       Access: Public
+//  Description: Returns the Lightwave ID of the file.  This is the
+//               first ID read within the header, and indicates the
+//               version of the Lightwave file in some mysterious way.
+////////////////////////////////////////////////////////////////////
+IffId LwoHeader::
+get_lwid() const {
+  return _lwid;
+}

+ 43 - 0
pandatool/src/lwo/lwoHeader.cxx

@@ -0,0 +1,43 @@
+// Filename: lwoHeader.cxx
+// Created by:  drose (24Apr01)
+// 
+////////////////////////////////////////////////////////////////////
+
+#include "lwoHeader.h"
+#include "iffInputFile.h"
+
+#include <indent.h>
+
+TypeHandle LwoHeader::_type_handle;
+
+////////////////////////////////////////////////////////////////////
+//     Function: LwoHeader::read_iff
+//       Access: Public, Virtual
+//  Description: Reads the data of the chunk in from the given input
+//               file, if possible.  The ID and length of the chunk
+//               have already been read.  stop_at is the byte position
+//               of the file to stop at (based on the current position
+//               at in->get_bytes_read()).  Returns true on success,
+//               false otherwise.
+////////////////////////////////////////////////////////////////////
+bool LwoHeader::
+read_iff(IffInputFile *in, size_t stop_at) {
+  _lwid = in->get_id();
+  return read_children_iff(in, stop_at);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: LwoHeader::write
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void LwoHeader::
+write(ostream &out, int indent_level) const {
+  indent(out, indent_level)
+    << get_id() << " {\n";
+  indent(out, indent_level + 2)
+    << _lwid << "\n";
+  write_children(out, indent_level + 2);
+  indent(out, indent_level)
+    << "}\n";
+}

+ 50 - 0
pandatool/src/lwo/lwoHeader.h

@@ -0,0 +1,50 @@
+// Filename: lwoHeader.h
+// Created by:  drose (24Apr01)
+// 
+////////////////////////////////////////////////////////////////////
+
+#ifndef LWOHEADER_H
+#define LWOHEADER_H
+
+#include <pandatoolbase.h>
+
+#include "lwoGroupChunk.h"
+
+////////////////////////////////////////////////////////////////////
+// 	 Class : LwoHeader
+// Description : The first chunk in a Lightwave Object file.
+////////////////////////////////////////////////////////////////////
+class LwoHeader : public LwoGroupChunk {
+public:
+  INLINE IffId get_lwid() const;
+
+public:
+  virtual bool read_iff(IffInputFile *in, size_t stop_at);
+  virtual void write(ostream &out, int indent_level = 0) const;
+
+private:
+  IffId _lwid;
+  
+public:
+  virtual TypeHandle get_type() const {
+    return get_class_type();
+  }
+  virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    LwoGroupChunk::init_type();
+    register_type(_type_handle, "LwoHeader",
+		  LwoGroupChunk::get_class_type());
+  }
+
+private:
+  static TypeHandle _type_handle;
+};
+
+#include "lwoHeader.I"
+
+#endif
+
+  

+ 4 - 0
pandatool/src/lwo/lwoInputFile.I

@@ -0,0 +1,4 @@
+// Filename: lwoInputFile.I
+// Created by:  drose (24Apr01)
+// 
+////////////////////////////////////////////////////////////////////

+ 129 - 0
pandatool/src/lwo/lwoInputFile.cxx

@@ -0,0 +1,129 @@
+// Filename: lwoInputFile.cxx
+// Created by:  drose (24Apr01)
+// 
+////////////////////////////////////////////////////////////////////
+
+#include "lwoInputFile.h"
+#include "lwoDiscontinuousVertexMap.h"
+#include "lwoHeader.h"
+#include "lwoLayer.h"
+#include "lwoPoints.h"
+#include "lwoPolygons.h"
+#include "lwoPolygonTags.h"
+#include "lwoVertexMap.h"
+#include "lwoTags.h"
+
+TypeHandle LwoInputFile::_type_handle;
+
+////////////////////////////////////////////////////////////////////
+//     Function: LwoInputFile::Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+LwoInputFile::
+LwoInputFile() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: LwoInputFile::Destructor
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+LwoInputFile::
+~LwoInputFile() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: LwoInputFile::get_vx
+//       Access: Public
+//  Description: Reads a Lightwave variable-length index.  This is
+//               either a 2-byte or 4-byte integer.
+////////////////////////////////////////////////////////////////////
+int LwoInputFile::
+get_vx() {
+  PN_uint16 top = get_be_uint16();
+  if ((top & 0xff00) == 0xff00) {
+    // The first byte is 0xff, which indicates we have a 4-byte
+    // integer.
+    PN_uint16 bottom = get_be_uint16();
+    return ((int)(top & 0xff) << 16) | bottom;
+  }
+
+  // The first byte is not 0xff, which indicates we have a 2-byte
+  // integer.
+  return top;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: LwoInputFile::get_vec3
+//       Access: Public
+//  Description: Reads a three-component vector of floats.
+////////////////////////////////////////////////////////////////////
+LVecBase3f LwoInputFile::
+get_vec3() {
+  LVecBase3f result;
+  result[0] = get_be_float32();
+  result[1] = get_be_float32();
+  result[2] = get_be_float32();
+  return result;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: LwoInputFile::get_filename
+//       Access: Public
+//  Description: Reads a Lightwave platform-neutral filename and
+//               converts it to a Panda platform-neutral filename.
+////////////////////////////////////////////////////////////////////
+Filename LwoInputFile::
+get_filename() {
+  string name = get_string();
+  size_t colon = name.find(':');
+  if (colon == string::npos) {
+    // No colon; it's just a relative path.
+    return Filename(name);
+  }
+
+  // The colon separates the device and the path.
+  string device = name.substr(0, colon);
+  string path = name.substr(colon + 1);
+
+  nout << "Ignoring filename device " << device << "\n";
+  return Filename("/", path);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: LwoInputFile::make_new_chunk
+//       Access: Protected, Virtual
+//  Description: Allocates and returns a new chunk of the appropriate
+//               type based on the given ID.
+////////////////////////////////////////////////////////////////////
+IffChunk *LwoInputFile::
+make_new_chunk(IffId id) {
+  if (id == IffId("FORM")) {
+    return new LwoHeader;
+
+  } else if (id == IffId("LAYR")) {
+    return new LwoLayer;
+
+  } else if (id == IffId("PNTS")) {
+    return new LwoPoints;
+
+  } else if (id == IffId("VMAP")) {
+    return new LwoVertexMap;
+
+  } else if (id == IffId("VMAD")) {
+    return new LwoDiscontinuousVertexMap;
+
+  } else if (id == IffId("POLS")) {
+    return new LwoPolygons;
+
+  } else if (id == IffId("TAGS")) {
+    return new LwoTags;
+
+  } else if (id == IffId("PTAG")) {
+    return new LwoPolygonTags;
+
+  } else {
+    return IffInputFile::make_new_chunk(id);
+  }
+}

+ 54 - 0
pandatool/src/lwo/lwoInputFile.h

@@ -0,0 +1,54 @@
+// Filename: lwoInputFile.h
+// Created by:  drose (24Apr01)
+// 
+////////////////////////////////////////////////////////////////////
+
+#ifndef LWOINPUTFILE_H
+#define LWOINPUTFILE_H
+
+#include <pandatoolbase.h>
+
+#include "iffInputFile.h"
+
+#include <luse.h>
+
+////////////////////////////////////////////////////////////////////
+// 	 Class : LwoInputFile
+// Description : A specialization of IffInputFile to handle reading a
+//               Lightwave Object file.
+////////////////////////////////////////////////////////////////////
+class LwoInputFile : public IffInputFile {
+public:
+  LwoInputFile();
+  ~LwoInputFile();
+
+  int get_vx();
+  LVecBase3f get_vec3();
+  Filename get_filename();
+
+protected:
+  virtual IffChunk *make_new_chunk(IffId id);
+
+public:
+  virtual TypeHandle get_type() const {
+    return get_class_type();
+  }
+  virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    IffInputFile::init_type();
+    register_type(_type_handle, "LwoInputFile",
+		  IffInputFile::get_class_type());
+  }
+
+private:
+  static TypeHandle _type_handle;
+};
+
+#include "lwoInputFile.I"
+
+#endif
+
+  

+ 4 - 0
pandatool/src/lwo/lwoLayer.I

@@ -0,0 +1,4 @@
+// Filename: lwoLayer.I
+// Created by:  drose (24Apr01)
+// 
+////////////////////////////////////////////////////////////////////

+ 54 - 0
pandatool/src/lwo/lwoLayer.cxx

@@ -0,0 +1,54 @@
+// Filename: lwoLayer.cxx
+// Created by:  drose (24Apr01)
+// 
+////////////////////////////////////////////////////////////////////
+
+#include "lwoLayer.h"
+#include "lwoInputFile.h"
+
+#include <indent.h>
+
+TypeHandle LwoLayer::_type_handle;
+
+////////////////////////////////////////////////////////////////////
+//     Function: LwoLayer::read_iff
+//       Access: Public, Virtual
+//  Description: Reads the data of the chunk in from the given input
+//               file, if possible.  The ID and length of the chunk
+//               have already been read.  stop_at is the byte position
+//               of the file to stop at (based on the current position
+//               at in->get_bytes_read()).  Returns true on success,
+//               false otherwise.
+////////////////////////////////////////////////////////////////////
+bool LwoLayer::
+read_iff(IffInputFile *in, size_t stop_at) {
+  LwoInputFile *lin = DCAST(LwoInputFile, in);
+  _number = lin->get_be_uint16();
+  _flags = lin->get_be_uint16();
+  _pivot = lin->get_vec3();
+  _name = lin->get_string();
+
+  if (lin->get_bytes_read() >= stop_at) {
+    _parent = -1;
+  } else {
+    _parent = lin->get_be_uint16();
+    if (_parent == 0xffff) {
+      _parent = -1;
+    }
+  }
+
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: LwoLayer::write
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void LwoLayer::
+write(ostream &out, int indent_level) const {
+  indent(out, indent_level)
+    << get_id() << " { number = " << _number << ", flags = 0x" 
+    << hex << _flags << dec << ", pivot = " << _pivot
+    << ", _name = \"" << _name << "\", _parent = " << _parent << " }\n";
+}

+ 61 - 0
pandatool/src/lwo/lwoLayer.h

@@ -0,0 +1,61 @@
+// Filename: lwoLayer.h
+// Created by:  drose (24Apr01)
+// 
+////////////////////////////////////////////////////////////////////
+
+#ifndef LWOLAYER_H
+#define LWOLAYER_H
+
+#include <pandatoolbase.h>
+
+#include "lwoChunk.h"
+
+#include <luse.h>
+
+////////////////////////////////////////////////////////////////////
+// 	 Class : LwoLayer
+// Description : Signals the start of a new layer.  All the data
+//               chunks which follow will be included in this layer
+//               until another layer chunk is encountered.  If data is
+//               encountered before a layer chunk, it goes into an
+//               arbitrary layer.
+////////////////////////////////////////////////////////////////////
+class LwoLayer : public LwoChunk {
+public:
+  enum Flags {
+    F_hidden   = 0x0001
+  };
+
+  int _number;
+  int _flags;
+  LPoint3f _pivot;
+  string _name;
+  int _parent;
+
+public:
+  virtual bool read_iff(IffInputFile *in, size_t stop_at);
+  virtual void write(ostream &out, int indent_level = 0) const;
+  
+public:
+  virtual TypeHandle get_type() const {
+    return get_class_type();
+  }
+  virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    LwoChunk::init_type();
+    register_type(_type_handle, "LwoLayer",
+		  LwoChunk::get_class_type());
+  }
+
+private:
+  static TypeHandle _type_handle;
+};
+
+#include "lwoLayer.I"
+
+#endif
+
+  

+ 4 - 0
pandatool/src/lwo/lwoPoints.I

@@ -0,0 +1,4 @@
+// Filename: lwoPoints.I
+// Created by:  drose (24Apr01)
+// 
+////////////////////////////////////////////////////////////////////

+ 65 - 0
pandatool/src/lwo/lwoPoints.cxx

@@ -0,0 +1,65 @@
+// Filename: lwoPoints.cxx
+// Created by:  drose (24Apr01)
+// 
+////////////////////////////////////////////////////////////////////
+
+#include "lwoPoints.h"
+#include "lwoInputFile.h"
+
+#include <indent.h>
+
+TypeHandle LwoPoints::_type_handle;
+
+////////////////////////////////////////////////////////////////////
+//     Function: LwoPoints::get_num_points
+//       Access: Public
+//  Description: Returns the number of points of this group.
+////////////////////////////////////////////////////////////////////
+int LwoPoints::
+get_num_points() const {
+  return _points.size();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: LwoPoints::get_point
+//       Access: Public
+//  Description: Returns the nth point of this group.
+////////////////////////////////////////////////////////////////////
+const LPoint3f &LwoPoints::
+get_point(int n) const {
+  nassertr(n >= 0 && n < (int)_points.size(), LPoint3f::zero());
+  return _points[n];
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: LwoPoints::read_iff
+//       Access: Public, Virtual
+//  Description: Reads the data of the chunk in from the given input
+//               file, if possible.  The ID and length of the chunk
+//               have already been read.  stop_at is the byte position
+//               of the file to stop at (based on the current position
+//               at in->get_bytes_read()).  Returns true on success,
+//               false otherwise.
+////////////////////////////////////////////////////////////////////
+bool LwoPoints::
+read_iff(IffInputFile *in, size_t stop_at) {
+  LwoInputFile *lin = DCAST(LwoInputFile, in);
+
+  while (lin->get_bytes_read() < stop_at && !lin->is_eof()) {
+    LPoint3f point = lin->get_vec3();
+    _points.push_back(point);
+  }
+
+  return (lin->get_bytes_read() == stop_at);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: LwoPoints::write
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void LwoPoints::
+write(ostream &out, int indent_level) const {
+  indent(out, indent_level)
+    << get_id() << " { " << _points.size() << " points }\n";
+}

+ 55 - 0
pandatool/src/lwo/lwoPoints.h

@@ -0,0 +1,55 @@
+// Filename: lwoPoints.h
+// Created by:  drose (24Apr01)
+// 
+////////////////////////////////////////////////////////////////////
+
+#ifndef LWOPOINTS_H
+#define LWOPOINTS_H
+
+#include <pandatoolbase.h>
+
+#include "lwoChunk.h"
+
+#include <luse.h>
+
+////////////////////////////////////////////////////////////////////
+// 	 Class : LwoPoints
+// Description : An array of points that will be referenced by later
+//               chunks.
+////////////////////////////////////////////////////////////////////
+class LwoPoints : public LwoChunk {
+public:
+  int get_num_points() const;
+  const LPoint3f &get_point(int n) const;
+
+public:
+  virtual bool read_iff(IffInputFile *in, size_t stop_at);
+  virtual void write(ostream &out, int indent_level = 0) const;
+
+private:
+  typedef vector<LPoint3f> Points;
+  Points _points;
+  
+public:
+  virtual TypeHandle get_type() const {
+    return get_class_type();
+  }
+  virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    LwoChunk::init_type();
+    register_type(_type_handle, "LwoPoints",
+		  LwoChunk::get_class_type());
+  }
+
+private:
+  static TypeHandle _type_handle;
+};
+
+#include "lwoPoints.I"
+
+#endif
+
+  

+ 4 - 0
pandatool/src/lwo/lwoPolygonTags.I

@@ -0,0 +1,4 @@
+// Filename: lwoPolygonTags.I
+// Created by:  drose (24Apr01)
+// 
+////////////////////////////////////////////////////////////////////

+ 81 - 0
pandatool/src/lwo/lwoPolygonTags.cxx

@@ -0,0 +1,81 @@
+// Filename: lwoPolygonTags.cxx
+// Created by:  drose (24Apr01)
+// 
+////////////////////////////////////////////////////////////////////
+
+#include "lwoPolygonTags.h"
+#include "lwoInputFile.h"
+
+#include <indent.h>
+
+TypeHandle LwoPolygonTags::_type_handle;
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: LwoPolygonTags::has_tag
+//       Access: Public
+//  Description: Returns true if the map has a tag associated with
+//               the given polygon index, false otherwise.
+////////////////////////////////////////////////////////////////////
+bool LwoPolygonTags::
+has_tag(int polygon_index) const {
+  return (_tmap.count(polygon_index) != 0);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: LwoPolygonTags::get_tag
+//       Access: Public
+//  Description: Returns the tag associated with the given polygon
+//               index, or -1 if there is no tag associated.
+////////////////////////////////////////////////////////////////////
+int LwoPolygonTags::
+get_tag(int polygon_index) const {
+  TMap::const_iterator ti;
+  ti = _tmap.find(polygon_index);
+  if (ti != _tmap.end()) {
+    return (*ti).second;
+  }
+
+  return -1;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: LwoPolygonTags::read_iff
+//       Access: Public, Virtual
+//  Description: Reads the data of the chunk in from the given input
+//               file, if possible.  The ID and length of the chunk
+//               have already been read.  stop_at is the byte position
+//               of the file to stop at (based on the current position
+//               at in->get_bytes_read()).  Returns true on success,
+//               false otherwise.
+////////////////////////////////////////////////////////////////////
+bool LwoPolygonTags::
+read_iff(IffInputFile *in, size_t stop_at) {
+  LwoInputFile *lin = DCAST(LwoInputFile, in);
+
+  _tag_type = lin->get_id();
+
+  while (lin->get_bytes_read() < stop_at && !lin->is_eof()) {
+    int polygon_index = lin->get_vx();
+    int tag = lin->get_be_int16();
+
+    bool inserted = _tmap.insert(TMap::value_type(polygon_index, tag)).second;
+    if (!inserted) {
+      nout << "Duplicate index " << index << " in map.\n";
+    }
+  }
+
+  return (lin->get_bytes_read() == stop_at);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: LwoPolygonTags::write
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void LwoPolygonTags::
+write(ostream &out, int indent_level) const {
+  indent(out, indent_level)
+    << get_id() << " { tag_type = " << _tag_type << ", "
+    << _tmap.size() << " values }\n";
+}

+ 57 - 0
pandatool/src/lwo/lwoPolygonTags.h

@@ -0,0 +1,57 @@
+// Filename: lwoPolygonTags.h
+// Created by:  drose (24Apr01)
+// 
+////////////////////////////////////////////////////////////////////
+
+#ifndef LWOPOLYGONTAGS_H
+#define LWOPOLYGONTAGS_H
+
+#include <pandatoolbase.h>
+
+#include "lwoChunk.h"
+
+////////////////////////////////////////////////////////////////////
+// 	 Class : LwoPolygonTags
+// Description : An association of polygons defined in the most recent
+//               LwoPolygons chunk to tag ids defined in the most
+//               recent LwoTags chunk.  This associated properties
+//               with the polygons, depending on the tag_type.
+////////////////////////////////////////////////////////////////////
+class LwoPolygonTags : public LwoChunk {
+public:
+  bool has_tag(int polygon_index) const;
+  int get_tag(int polygon_index) const;
+
+  IffId _tag_type;
+
+public:
+  virtual bool read_iff(IffInputFile *in, size_t stop_at);
+  virtual void write(ostream &out, int indent_level = 0) const;
+
+private:
+  typedef map<int, int> TMap;
+  TMap _tmap;
+  
+public:
+  virtual TypeHandle get_type() const {
+    return get_class_type();
+  }
+  virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    LwoChunk::init_type();
+    register_type(_type_handle, "LwoPolygonTags",
+		  LwoChunk::get_class_type());
+  }
+
+private:
+  static TypeHandle _type_handle;
+};
+
+#include "lwoPolygonTags.I"
+
+#endif
+
+  

+ 4 - 0
pandatool/src/lwo/lwoPolygons.I

@@ -0,0 +1,4 @@
+// Filename: lwoPolygons.I
+// Created by:  drose (24Apr01)
+// 
+////////////////////////////////////////////////////////////////////

+ 77 - 0
pandatool/src/lwo/lwoPolygons.cxx

@@ -0,0 +1,77 @@
+// Filename: lwoPolygons.cxx
+// Created by:  drose (24Apr01)
+// 
+////////////////////////////////////////////////////////////////////
+
+#include "lwoPolygons.h"
+#include "lwoInputFile.h"
+
+#include <indent.h>
+
+TypeHandle LwoPolygons::_type_handle;
+
+////////////////////////////////////////////////////////////////////
+//     Function: LwoPolygons::get_num_polygons
+//       Access: Public
+//  Description: Returns the number of polygons of this group.
+////////////////////////////////////////////////////////////////////
+int LwoPolygons::
+get_num_polygons() const {
+  return _polygons.size();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: LwoPolygons::get_polygon
+//       Access: Public
+//  Description: Returns the nth polygon of this group.
+////////////////////////////////////////////////////////////////////
+LwoPolygons::Polygon *LwoPolygons::
+get_polygon(int n) const {
+  nassertr(n >= 0 && n < (int)_polygons.size(), (Polygon *)NULL);
+  return _polygons[n];
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: LwoPolygons::read_iff
+//       Access: Public, Virtual
+//  Description: Reads the data of the chunk in from the given input
+//               file, if possible.  The ID and length of the chunk
+//               have already been read.  stop_at is the byte position
+//               of the file to stop at (based on the current position
+//               at in->get_bytes_read()).  Returns true on success,
+//               false otherwise.
+////////////////////////////////////////////////////////////////////
+bool LwoPolygons::
+read_iff(IffInputFile *in, size_t stop_at) {
+  LwoInputFile *lin = DCAST(LwoInputFile, in);
+
+  _polygon_type = lin->get_id();
+
+  while (lin->get_bytes_read() < stop_at && !lin->is_eof()) {
+    int nf = lin->get_be_int16();
+    int num_vertices = nf & PF_numverts_mask;
+
+    PT(Polygon) poly = new Polygon;
+    poly->_flags = nf & ~PF_numverts_mask;
+
+    for (int i = 0; i < num_vertices; i++) {
+      poly->_vertices.push_back(lin->get_vx());
+    }
+
+    _polygons.push_back(poly);
+  }
+
+  return (lin->get_bytes_read() == stop_at);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: LwoPolygons::write
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void LwoPolygons::
+write(ostream &out, int indent_level) const {
+  indent(out, indent_level)
+    << get_id() << " { polygon_type = " << _polygon_type
+    << ", " << _polygons.size() << " polygons }\n";
+}

+ 72 - 0
pandatool/src/lwo/lwoPolygons.h

@@ -0,0 +1,72 @@
+// Filename: lwoPolygons.h
+// Created by:  drose (24Apr01)
+// 
+////////////////////////////////////////////////////////////////////
+
+#ifndef LWOPOLYGONS_H
+#define LWOPOLYGONS_H
+
+#include <pandatoolbase.h>
+
+#include "lwoChunk.h"
+
+#include <luse.h>
+#include <vector_int.h>
+#include <referenceCount.h>
+#include <pointerTo.h>
+
+////////////////////////////////////////////////////////////////////
+// 	 Class : LwoPolygons
+// Description : An array of polygons that will be referenced by later
+//               chunks.
+////////////////////////////////////////////////////////////////////
+class LwoPolygons : public LwoChunk {
+public:
+  enum PolygonFlags {
+    PF_continuity_1    = 0x0400,
+    PF_continuity_2    = 0x0800,
+    PF_numverts_mask   = 0x03ff
+  };
+
+  class Polygon : public ReferenceCount {
+  public:
+    int _flags;
+    vector_int _vertices;
+  };
+
+  int get_num_polygons() const;
+  Polygon *get_polygon(int n) const;
+
+  IffId _polygon_type;
+
+public:
+  virtual bool read_iff(IffInputFile *in, size_t stop_at);
+  virtual void write(ostream &out, int indent_level = 0) const;
+
+private:
+  typedef vector< PT(Polygon) > Polygons;
+  Polygons _polygons;
+  
+public:
+  virtual TypeHandle get_type() const {
+    return get_class_type();
+  }
+  virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    LwoChunk::init_type();
+    register_type(_type_handle, "LwoPolygons",
+		  LwoChunk::get_class_type());
+  }
+
+private:
+  static TypeHandle _type_handle;
+};
+
+#include "lwoPolygons.I"
+
+#endif
+
+  

+ 4 - 0
pandatool/src/lwo/lwoTags.I

@@ -0,0 +1,4 @@
+// Filename: lwoTags.I
+// Created by:  drose (24Apr01)
+// 
+////////////////////////////////////////////////////////////////////

+ 76 - 0
pandatool/src/lwo/lwoTags.cxx

@@ -0,0 +1,76 @@
+// Filename: lwoTags.cxx
+// Created by:  drose (24Apr01)
+// 
+////////////////////////////////////////////////////////////////////
+
+#include "lwoTags.h"
+#include "lwoInputFile.h"
+
+#include <indent.h>
+
+TypeHandle LwoTags::_type_handle;
+
+////////////////////////////////////////////////////////////////////
+//     Function: LwoTags::get_num_tags
+//       Access: Public
+//  Description: Returns the number of tags of this group.
+////////////////////////////////////////////////////////////////////
+int LwoTags::
+get_num_tags() const {
+  return _tags.size();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: LwoTags::get_tag
+//       Access: Public
+//  Description: Returns the nth tag of this group.
+////////////////////////////////////////////////////////////////////
+string LwoTags::
+get_tag(int n) const {
+  nassertr(n >= 0 && n < (int)_tags.size(), string());
+  return _tags[n];
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: LwoTags::read_iff
+//       Access: Public, Virtual
+//  Description: Reads the data of the chunk in from the given input
+//               file, if possible.  The ID and length of the chunk
+//               have already been read.  stop_at is the byte position
+//               of the file to stop at (based on the current position
+//               at in->get_bytes_read()).  Returns true on success,
+//               false otherwise.
+////////////////////////////////////////////////////////////////////
+bool LwoTags::
+read_iff(IffInputFile *in, size_t stop_at) {
+  LwoInputFile *lin = DCAST(LwoInputFile, in);
+
+  while (lin->get_bytes_read() < stop_at && !lin->is_eof()) {
+    string tag = lin->get_string();
+    _tags.push_back(tag);
+  }
+
+  return (lin->get_bytes_read() == stop_at);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: LwoTags::write
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void LwoTags::
+write(ostream &out, int indent_level) const {
+  indent(out, indent_level)
+    << get_id() << " { ";
+
+  if (!_tags.empty()) {
+    Tags::const_iterator ti = _tags.begin();
+    out << *ti;
+    ++ti;
+    while (ti != _tags.end()) {
+      out << ", " << *ti;
+      ++ti;
+    }
+  }
+  out << " }\n";
+}

+ 56 - 0
pandatool/src/lwo/lwoTags.h

@@ -0,0 +1,56 @@
+// Filename: lwoTags.h
+// Created by:  drose (24Apr01)
+// 
+////////////////////////////////////////////////////////////////////
+
+#ifndef LWOTAGS_H
+#define LWOTAGS_H
+
+#include <pandatoolbase.h>
+
+#include "lwoChunk.h"
+
+#include <luse.h>
+#include <vector_string.h>
+
+////////////////////////////////////////////////////////////////////
+// 	 Class : LwoTags
+// Description : An array of tag strings that will be referenced by
+//               later chunks.
+////////////////////////////////////////////////////////////////////
+class LwoTags : public LwoChunk {
+public:
+  int get_num_tags() const;
+  string get_tag(int n) const;
+
+public:
+  virtual bool read_iff(IffInputFile *in, size_t stop_at);
+  virtual void write(ostream &out, int indent_level = 0) const;
+
+private:
+  typedef vector_string Tags;
+  Tags _tags;
+  
+public:
+  virtual TypeHandle get_type() const {
+    return get_class_type();
+  }
+  virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    LwoChunk::init_type();
+    register_type(_type_handle, "LwoTags",
+		  LwoChunk::get_class_type());
+  }
+
+private:
+  static TypeHandle _type_handle;
+};
+
+#include "lwoTags.I"
+
+#endif
+
+  

+ 4 - 0
pandatool/src/lwo/lwoVertexMap.I

@@ -0,0 +1,4 @@
+// Filename: lwoVertexMap.I
+// Created by:  drose (24Apr01)
+// 
+////////////////////////////////////////////////////////////////////

+ 90 - 0
pandatool/src/lwo/lwoVertexMap.cxx

@@ -0,0 +1,90 @@
+// Filename: lwoVertexMap.cxx
+// Created by:  drose (24Apr01)
+// 
+////////////////////////////////////////////////////////////////////
+
+#include "lwoVertexMap.h"
+#include "lwoInputFile.h"
+
+#include <indent.h>
+
+TypeHandle LwoVertexMap::_type_handle;
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: LwoVertexMap::has_value
+//       Access: Public
+//  Description: Returns true if the map has a value associated with
+//               the given index, false otherwise.
+////////////////////////////////////////////////////////////////////
+bool LwoVertexMap::
+has_value(int index) const {
+  return (_vmap.count(index) != 0);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: LwoVertexMap::get_value
+//       Access: Public
+//  Description: Returns the mapping value associated with the given
+//               index, or an empty PTA_float if there is no mapping
+//               value associated.
+////////////////////////////////////////////////////////////////////
+PTA_float LwoVertexMap::
+get_value(int index) const {
+  VMap::const_iterator vi;
+  vi = _vmap.find(index);
+  if (vi != _vmap.end()) {
+    return (*vi).second;
+  }
+
+  return PTA_float();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: LwoVertexMap::read_iff
+//       Access: Public, Virtual
+//  Description: Reads the data of the chunk in from the given input
+//               file, if possible.  The ID and length of the chunk
+//               have already been read.  stop_at is the byte position
+//               of the file to stop at (based on the current position
+//               at in->get_bytes_read()).  Returns true on success,
+//               false otherwise.
+////////////////////////////////////////////////////////////////////
+bool LwoVertexMap::
+read_iff(IffInputFile *in, size_t stop_at) {
+  LwoInputFile *lin = DCAST(LwoInputFile, in);
+
+  _map_type = lin->get_id();
+  _dimension = lin->get_be_uint16();
+  _name = lin->get_string();
+
+  while (lin->get_bytes_read() < stop_at && !lin->is_eof()) {
+    int index = lin->get_vx();
+
+    PTA_float value;
+    for (int i = 0; i < _dimension; i++) {
+      value.push_back(lin->get_be_float32());
+    }
+
+    bool inserted = _vmap.insert(VMap::value_type(index, value)).second;
+    if (!inserted) {
+      nout << "Duplicate index " << index << " in map.\n";
+    }
+  }
+
+  return (lin->get_bytes_read() == stop_at);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: LwoVertexMap::write
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void LwoVertexMap::
+write(ostream &out, int indent_level) const {
+  indent(out, indent_level)
+    << get_id() << " { map_type = " << _map_type 
+    << ", dimension = " << _dimension
+    << ", name = \"" << _name << "\", "
+    << _vmap.size() << " values }\n";
+}

+ 60 - 0
pandatool/src/lwo/lwoVertexMap.h

@@ -0,0 +1,60 @@
+// Filename: lwoVertexMap.h
+// Created by:  drose (24Apr01)
+// 
+////////////////////////////////////////////////////////////////////
+
+#ifndef LWOVERTEXMAP_H
+#define LWOVERTEXMAP_H
+
+#include <pandatoolbase.h>
+
+#include "lwoChunk.h"
+
+#include <pta_float.h>
+
+////////////////////////////////////////////////////////////////////
+// 	 Class : LwoVertexMap
+// Description : A mapping of floating-point values per integer index.
+//               The meaning of these values is determined by the
+//               mapping type code and/or its name.
+////////////////////////////////////////////////////////////////////
+class LwoVertexMap : public LwoChunk {
+public:
+  bool has_value(int index) const;
+  PTA_float get_value(int index) const;
+
+  IffId _map_type;
+  int _dimension;
+  string _name;
+
+public:
+  virtual bool read_iff(IffInputFile *in, size_t stop_at);
+  virtual void write(ostream &out, int indent_level = 0) const;
+
+private:
+  typedef map<int, PTA_float> VMap;
+  VMap _vmap;
+  
+public:
+  virtual TypeHandle get_type() const {
+    return get_class_type();
+  }
+  virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    LwoChunk::init_type();
+    register_type(_type_handle, "LwoVertexMap",
+		  LwoChunk::get_class_type());
+  }
+
+private:
+  static TypeHandle _type_handle;
+};
+
+#include "lwoVertexMap.I"
+
+#endif
+
+  

+ 32 - 0
pandatool/src/lwo/test_lwo.cxx

@@ -0,0 +1,32 @@
+// Filename: test_lwo.cxx
+// Created by:  drose (24Apr01)
+// 
+////////////////////////////////////////////////////////////////////
+
+#include "lwoInputFile.h"
+#include "lwoChunk.h"
+
+int
+main(int argc, char *argv[]) {
+  if (argc != 2) {
+    cerr << "test_lwo file.lwo\n";
+    exit(1);
+  }
+
+  LwoInputFile in;
+  if (!in.open_read(argv[1])) {
+    cerr << "Unable to open " << argv[1] << "\n";
+    exit(1);
+  }
+
+  PT(IffChunk) chunk = in.get_chunk();
+  while (chunk != (IffChunk *)NULL) {
+    cerr << "Got chunk type " << chunk->get_type() << ":\n";
+    chunk->write(cerr, 2);
+    chunk = in.get_chunk();
+  }
+
+  cerr << "EOF = " << in.is_eof() << "\n";
+
+  return (0);
+}