From 32e520d5a1d5697dcd682253f84bd21967afcdf7 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Tue, 11 Dec 2007 16:42:10 +0000 Subject: [PATCH] From Brede Johnansen, support for continuation records. --- src/osgPlugins/OpenFlight/DataInputStream.cpp | 96 +++++++++++++------ src/osgPlugins/OpenFlight/DataInputStream.h | 6 +- src/osgPlugins/OpenFlight/PaletteRecords.cpp | 9 +- src/osgPlugins/OpenFlight/ReaderWriterFLT.cpp | 79 ++++++++++++++- .../OpenFlight/RecordInputStream.cpp | 81 +++------------- src/osgPlugins/OpenFlight/RecordInputStream.h | 25 ++--- src/osgPlugins/OpenFlight/VertexRecords.cpp | 8 +- 7 files changed, 176 insertions(+), 128 deletions(-) diff --git a/src/osgPlugins/OpenFlight/DataInputStream.cpp b/src/osgPlugins/OpenFlight/DataInputStream.cpp index c6172777f..4afa7a903 100644 --- a/src/osgPlugins/OpenFlight/DataInputStream.cpp +++ b/src/osgPlugins/OpenFlight/DataInputStream.cpp @@ -1,7 +1,7 @@ // // OpenFlightŪ loader for OpenSceneGraph // -// Copyright (C) 2005-2006 Brede Johansen +// Copyright (C) 2005-2007 Brede Johansen // #include "DataInputStream.h" @@ -18,92 +18,131 @@ DataInputStream::DataInputStream(std::streambuf* sb): _byteswap = osg::getCpuByteOrder() == osg::LittleEndian; } + int8 DataInputStream::readInt8(int8 def) { - int8 d=def; - vread((char*)&d, sizeof(int8)); + int8 d; + read((char*)&d, sizeof(int8)); + + if (!good()) + return def; + return d; } uint8 DataInputStream::readUInt8(uint8 def) { - uint8 d=def; - vread((char*)&d, sizeof(uint8)); + uint8 d; + read((char*)&d, sizeof(uint8)); + + if (!good()) + return def; + return d; } int16 DataInputStream::readInt16(int16 def) { - int16 d=def; - vread((char*)&d, sizeof(int16)); - if (_byteswap && good()) + int16 d; + read((char*)&d, sizeof(int16)); + + if (!good()) + return def; + + if (_byteswap) osg::swapBytes2((char *)&d); + return d; } uint16 DataInputStream::readUInt16(uint16 def) { - uint16 d=def; - vread((char*)&d, sizeof(uint16)); - if (_byteswap && good()) + uint16 d; + read((char*)&d, sizeof(uint16)); + + if (!good()) + return def; + + if (_byteswap) osg::swapBytes2((char *)&d); + return d; } int32 DataInputStream::readInt32(int32 def) { - int32 d=def; - vread((char*)&d, sizeof(int32)); - if (_byteswap && good()) + int32 d; + read((char*)&d, sizeof(int32)); + + if (!good()) + return def; + + if (_byteswap) osg::swapBytes4((char *)&d); + return d; } uint32 DataInputStream::readUInt32(uint32 def) { - uint32 d=def; - vread((char*)&d, sizeof(uint32)); - if (_byteswap && good()) + uint32 d; + read((char*)&d, sizeof(uint32)); + + if (!good()) + return def; + + if (_byteswap) osg::swapBytes4((char *)&d); + return d; } float32 DataInputStream::readFloat32(float32 def) { - float32 d=def; - vread((char*)&d, sizeof(float32)); - if (_byteswap && good()) + float32 d; + read((char*)&d, sizeof(float32)); + + if (!good()) + return def; + + if (_byteswap) osg::swapBytes4((char*)&d); + return d; } float64 DataInputStream::readFloat64(float64 def) { - float64 d=def; - vread((char*)&d, sizeof(float64)); - if (_byteswap && good()) + float64 d; + read((char*)&d, sizeof(float64)); + + if (!good()) + return def; + + if (_byteswap) osg::swapBytes8((char*)&d); + return d; } void DataInputStream::readCharArray(char* data, int size) { - vread(data,size); + read(data,size); } std::string DataInputStream::readString(int size) { char* buf = new char[size+1]; - vread(buf,size); + read(buf,size); buf[size] = '\0'; std::string str = buf; delete [] buf; @@ -188,10 +227,11 @@ int16 DataInputStream::peekInt16() std::istream& DataInputStream::forward(std::istream::off_type off) { - return vforward(off); + //return vforward(off); + return seekg(off, std::ios_base::cur); } - +#if 0 std::istream& DataInputStream::vread(char_type *str, std::streamsize count) { return read(str,count); @@ -202,4 +242,4 @@ std::istream& DataInputStream::vforward(std::istream::off_type off) { return seekg(off, std::ios_base::cur); } - +#endif diff --git a/src/osgPlugins/OpenFlight/DataInputStream.h b/src/osgPlugins/OpenFlight/DataInputStream.h index c580f3ace..d6308aa2d 100644 --- a/src/osgPlugins/OpenFlight/DataInputStream.h +++ b/src/osgPlugins/OpenFlight/DataInputStream.h @@ -1,13 +1,12 @@ // // OpenFlightŪ loader for OpenSceneGraph // -// Copyright (C) 2005-2006 Brede Johansen +// Copyright (C) 2005-2007 Brede Johansen // #ifndef FLT_DATAINPUTSTREAM #define FLT_DATAINPUTSTREAM 1 -//#include // for ifstream #include #include #include @@ -47,9 +46,6 @@ class DataInputStream : public std::istream protected: - virtual std::istream& vread(char_type *str, std::streamsize count); - virtual std::istream& vforward(std::istream::off_type off); - bool _byteswap; }; diff --git a/src/osgPlugins/OpenFlight/PaletteRecords.cpp b/src/osgPlugins/OpenFlight/PaletteRecords.cpp index c6cb59ea0..01c113c73 100644 --- a/src/osgPlugins/OpenFlight/PaletteRecords.cpp +++ b/src/osgPlugins/OpenFlight/PaletteRecords.cpp @@ -34,10 +34,15 @@ protected: virtual void readRecord(RecordInputStream& in, Document& document) { uint32 paletteSize = in.readUInt32(); - in.moveToStartOfRecord(); + + // Enteries in vertex pool found by offset from start of this record. + const int RECORD_HEADER_SIZE = 4; + const int OFFSET = RECORD_HEADER_SIZE+sizeof(paletteSize); std::string buffer(paletteSize,'\0'); - in.read(&(*buffer.begin()),paletteSize); + in.read(&buffer[OFFSET], paletteSize-OFFSET); + + // Keep a copy of the vertex pool in memory for later reference. document.setVertexPool(new VertexPool(buffer)); } }; diff --git a/src/osgPlugins/OpenFlight/ReaderWriterFLT.cpp b/src/osgPlugins/OpenFlight/ReaderWriterFLT.cpp index f499d269d..3e47fb4c9 100644 --- a/src/osgPlugins/OpenFlight/ReaderWriterFLT.cpp +++ b/src/osgPlugins/OpenFlight/ReaderWriterFLT.cpp @@ -1,7 +1,7 @@ // // OpenFlight loader for OpenSceneGraph // -// Copyright (C) 2005-2006 Brede Johansen +// Copyright (C) 2005-2007 Brede Johansen // #include @@ -229,12 +229,81 @@ class FLTReaderWriter : public ReaderWriter } } + const int RECORD_HEADER_SIZE = 4; + opcode_type continuationOpcode = -1; + std::string continuationBuffer; + + while (fin.good() && !document.done()) { - // read records - flt::RecordInputStream recordStream(fin.rdbuf()); - while (recordStream.good() && !document.done()) + // The continuation record complicates things a bit. + + // Get current read position in stream. + std::istream::pos_type pos = fin.tellg(); + + // get opcode and size + flt::DataInputStream dataStream(fin.rdbuf()); + opcode_type opcode = (opcode_type)dataStream.readUInt16(); + size_type size = (size_type)dataStream.readUInt16(); + + // variable length record complete? + if (!continuationBuffer.empty() && opcode!=CONTINUATION_OP) { - recordStream.readRecord(document); + // parse variable length record + std::stringbuf sb(continuationBuffer); + flt::RecordInputStream recordStream(&sb); + recordStream.readRecordBody(continuationOpcode, continuationBuffer.length(), document); + + continuationOpcode = -1; + continuationBuffer.clear(); + } + + // variable length record use continuation buffer in case next + // record is a continuation record. + if (opcode==EXTENSION_OP || + opcode==NAME_TABLE_OP || + opcode==LOCAL_VERTEX_POOL_OP || + opcode==MESH_PRIMITIVE_OP) + { + continuationOpcode = opcode; + + if (size > RECORD_HEADER_SIZE) + { + // Put record in buffer. + std::string buffer((std::string::size_type)size-RECORD_HEADER_SIZE,'\0'); + fin.read(&buffer[0], size-RECORD_HEADER_SIZE); + + // Can't parse it until we know we have the complete record. + continuationBuffer = buffer; + } + } + else if (opcode==CONTINUATION_OP) + { + if (size > RECORD_HEADER_SIZE) + { + std::string buffer((std::string::size_type)size-RECORD_HEADER_SIZE,'\0'); + fin.read(&buffer[0], size-RECORD_HEADER_SIZE); + + // The record continues. + continuationBuffer.append(buffer); + } + } + else if (opcode==VERTEX_PALETTE_OP) + { + // Vertex Palette needs the file stream as it reads beyond the current record. + flt::RecordInputStream recordStream(fin.rdbuf()); + recordStream.readRecordBody(opcode, size, document); + } + else // normal (fixed size) record. + { + // Put record in buffer. + std::string buffer((std::string::size_type)size,'\0'); + if (size > RECORD_HEADER_SIZE) + fin.read(&buffer[0], size-RECORD_HEADER_SIZE); + + // Parse buffer. + std::stringbuf sb(buffer); + flt::RecordInputStream recordStream(&sb); + recordStream.readRecordBody(opcode, size, document); } } diff --git a/src/osgPlugins/OpenFlight/RecordInputStream.cpp b/src/osgPlugins/OpenFlight/RecordInputStream.cpp index 0a007d69e..c5a2cceaf 100644 --- a/src/osgPlugins/OpenFlight/RecordInputStream.cpp +++ b/src/osgPlugins/OpenFlight/RecordInputStream.cpp @@ -1,7 +1,7 @@ // // OpenFlightŪ loader for OpenSceneGraph // -// Copyright (C) 2005-2006 Brede Johansen +// Copyright (C) 2005-2007 Brede Johansen // #include @@ -16,48 +16,19 @@ using namespace std; RecordInputStream::RecordInputStream(std::streambuf* sb): DataInputStream(sb), - _recordSize(0), - _recordOffset(0) + _recordSize(0) {} - -std::istream& RecordInputStream::vread(char_type *str, std::streamsize count) -{ - if ((_recordSize>0) && (_recordOffset+count > _recordSize)) - { - setstate(ios::failbit); // end-of-record (EOR) - return *this; - } - - _recordOffset += count; - return DataInputStream::vread(str,count); -} - - -std::istream& RecordInputStream::vforward(std::istream::off_type off) -{ - if ((_recordSize>0) && (_recordOffset+off > _recordSize)) - { - setstate(ios::failbit); // end-of-record (EOR) - return *this; - } - - _recordOffset += off; - return DataInputStream::vforward(off); -} - - bool RecordInputStream::readRecord(Document& document) { - // Get current read position in stream. - _start = tellg(); - _recordOffset = 0; + opcode_type opcode = (opcode_type)readUInt16(); + size_type size = (size_type)readUInt16(); - // Get record header without bounds check. - _recordSize = 0; // disable boundary check - uint16 opcode = readUInt16(); - int size = (int)readUInt16(); + return readRecordBody(opcode, size, document); +} +bool RecordInputStream::readRecordBody(opcode_type opcode, size_type size, Document& document) +{ // Correct endian error in Creator v2.5 gallery models. // Last pop level record in little-endian. const uint16 LITTLE_ENDIAN_POP_LEVEL_OP = 0x0B00; @@ -70,29 +41,12 @@ bool RecordInputStream::readRecord(Document& document) _recordSize = size; - // Update end-of-record - _end = _start + (std::istream::pos_type)size; - -#if 0 - // TODO: Peek at next opcode looking for continuation record. - seekg(_end, std::ios_base::beg); - if (_istream->fail()) - return false; - - int16 nextOpcode = readUInt16(); - seekg(_start+(std::istream::pos_type)4, std::ios_base::beg); - if (nextOpcode == CONTINUATION_OP) - { - - } -#endif - // Get prototype record Record* prototype = Registry::instance()->getPrototype((int)opcode); if (prototype) { -#if 0 //def _DEBUG +#if 0 // for debuging { for (int i=0; i record = prototype->cloneType(); - { - // Create from prototype. - osg::ref_ptr record = prototype->cloneType(); - - // Read record - record->read(*this,document); - } - - // Clear failbit, it's used for end-of-record testing. - clear(rdstate() & ~std::ios::failbit); + // Read record + record->read(*this,document); } else // prototype not found { @@ -121,8 +69,5 @@ bool RecordInputStream::readRecord(Document& document) Registry::instance()->addPrototype(opcode,new DummyRecord); } - // Move to beginning of next record - seekg(_end, std::ios_base::beg); - return good(); } diff --git a/src/osgPlugins/OpenFlight/RecordInputStream.h b/src/osgPlugins/OpenFlight/RecordInputStream.h index 3f593aba0..039050da7 100644 --- a/src/osgPlugins/OpenFlight/RecordInputStream.h +++ b/src/osgPlugins/OpenFlight/RecordInputStream.h @@ -1,7 +1,7 @@ // // OpenFlightŪ loader for OpenSceneGraph // -// Copyright (C) 2005-2006 Brede Johansen +// Copyright (C) 2005-2007 Brede Johansen // #ifndef FLT_RECORDINPUTSTREAM_H @@ -14,31 +14,24 @@ namespace flt { class Document; +typedef int opcode_type; +typedef std::streamsize size_type; + class RecordInputStream : public DataInputStream { public: explicit RecordInputStream(std::streambuf* sb); - bool readRecord(Document& data); + bool readRecord(Document&); + bool readRecordBody(opcode_type, size_type, Document&); - inline std::istream::pos_type getStartOfRecord() const { return _start; } - inline std::istream::pos_type getEndOfRecord() const { return _end; } - inline std::streamsize getRecordSize() const { return _end-_start; } - inline std::streamsize getRecordBodySize() const { return getRecordSize()-(std::streamsize)4; } - - inline void moveToStartOfRecord() { seekg(_start /*,std::ios_base::beg*/); } - inline void setEndOfRecord(std::istream::pos_type pos) { _end=pos; } + inline std::streamsize getRecordSize() const { return _recordSize; } + inline std::streamsize getRecordBodySize() const { return _recordSize-(std::streamsize)4; } protected: - virtual std::istream& vread(char_type *str, std::streamsize count); - virtual std::istream& vforward(std::istream::off_type off); - - int _recordSize; - int _recordOffset; - std::istream::pos_type _start; // start of record - std::istream::pos_type _end; // end of record + std::streamsize _recordSize; }; } // end namespace diff --git a/src/osgPlugins/OpenFlight/VertexRecords.cpp b/src/osgPlugins/OpenFlight/VertexRecords.cpp index 48364677e..12a34aabc 100644 --- a/src/osgPlugins/OpenFlight/VertexRecords.cpp +++ b/src/osgPlugins/OpenFlight/VertexRecords.cpp @@ -1,7 +1,7 @@ // // OpenFlightŪ loader for OpenSceneGraph // -// Copyright (C) 2005-2006 Brede Johansen +// Copyright (C) 2005-2007 Brede Johansen // #include "Record.h" @@ -228,7 +228,7 @@ class AbsoluteVertex : public Record vertex.setCoord(osg::Vec3(x,y,z) * document.unitScale()); // optional texture coordinates - if (in.tellg() < in.getEndOfRecord()) + if (in.getRecordBodySize() > (4+4+4)) { osg::Vec2f uv = in.readVec2f(); vertex.setUV(0,uv); @@ -276,7 +276,7 @@ class ShadedVertex : public Record vertex.setColor(getColorFromPool(colorIndex, document.getColorPool())); // Color from pool // optional texture coordinates - if (in.tellg() < in.getEndOfRecord()) + if (in.getRecordBodySize() > (4+4+4+1+1+2)) { osg::Vec2f uv = in.readVec2f(); vertex.setUV(0,uv); @@ -324,7 +324,7 @@ class NormalVertex : public Record vertex.setColor(getColorFromPool(colorIndex, document.getColorPool())); // Color from pool // optional texture coordinates - if (in.tellg() < in.getEndOfRecord()) + if (in.getRecordBodySize() > (4+4+4+1+1+2+3*8)) { osg::Vec2f uv = in.readVec2f(); vertex.setUV(0,uv);