From d9a281c493cac5bef5db95672aef5983beefa4d7 Mon Sep 17 00:00:00 2001 From: James Turner Date: Tue, 4 Oct 2011 14:04:59 +0100 Subject: [PATCH] Support for 32-bit vertex indices in BTG files --- simgear/io/sg_binobj.cxx | 1419 +++++++++++++++++--------------------- simgear/io/sg_binobj.hxx | 39 +- 2 files changed, 662 insertions(+), 796 deletions(-) diff --git a/simgear/io/sg_binobj.cxx b/simgear/io/sg_binobj.cxx index 5f7a34d2..7a58321f 100644 --- a/simgear/io/sg_binobj.cxx +++ b/simgear/io/sg_binobj.cxx @@ -33,10 +33,12 @@ #include #include #include // for system() +#include #include #include #include +#include #include #include @@ -85,163 +87,282 @@ private: char *ptr; unsigned int size; - + size_t offset; public: - inline sgSimpleBuffer( unsigned int s ) + sgSimpleBuffer( unsigned int s = 0) : + ptr(NULL), + size(0), + offset(0) { - size = 1; - while ( size < s ) { - size *= 2; - } - SG_LOG(SG_EVENT, SG_DEBUG, "Creating a new buffer of size = " << size); - ptr = new char[size]; + resize(s); } - inline ~sgSimpleBuffer() { - delete [] ptr; + ~sgSimpleBuffer() + { + delete [] ptr; } - inline unsigned int get_size() const { return size; } - inline char *get_ptr() const { return ptr; } - inline void resize( unsigned int s ) { - if ( s > size ) { - if ( ptr != NULL ) { - delete [] ptr; - } - while ( size < s ) { - size *= 2; - } - SG_LOG(SG_EVENT, SG_DEBUG, "resizing buffer to size = " << size); - ptr = new char[size]; - } + unsigned int get_size() const { return size; } + char *get_ptr() const { return ptr; } + + void reset() + { + offset = 0; + } + + void resize( unsigned int s ) + { + if ( s > size ) { + if ( ptr != NULL ) { + delete [] ptr; + } + + if ( size == 0) { + size = 16; + } + + while ( size < s ) { + size = size << 1; + } + ptr = new char[size]; + } + } + + SGVec3d readVec3d() + { + double* p = reinterpret_cast(ptr + offset); + + if ( sgIsBigEndian() ) { + sgEndianSwap((uint64_t *) p + 0); + sgEndianSwap((uint64_t *) p + 1); + sgEndianSwap((uint64_t *) p + 2); + } + + offset += 3 * sizeof(double); + return SGVec3d(p); + } + + float readFloat() + { + float* p = reinterpret_cast(ptr + offset); + if ( sgIsBigEndian() ) { + sgEndianSwap((uint32_t *) p); + } + + offset += sizeof(float); + return *p; + } + + SGVec2f readVec2f() + { + float* p = reinterpret_cast(ptr + offset); + + if ( sgIsBigEndian() ) { + sgEndianSwap((uint32_t *) p + 0); + sgEndianSwap((uint32_t *) p + 1); + } + + offset += 2 * sizeof(float); + return SGVec2f(p); + } + + SGVec3f readVec3f() + { + float* p = reinterpret_cast(ptr + offset); + + if ( sgIsBigEndian() ) { + sgEndianSwap((uint32_t *) p + 0); + sgEndianSwap((uint32_t *) p + 1); + sgEndianSwap((uint32_t *) p + 2); + } + + offset += 3 * sizeof(float); + return SGVec3f(p); + } + + SGVec4f readVec4f() + { + float* p = reinterpret_cast(ptr + offset); + + if ( sgIsBigEndian() ) { + sgEndianSwap((uint32_t *) p + 0); + sgEndianSwap((uint32_t *) p + 1); + sgEndianSwap((uint32_t *) p + 2); + sgEndianSwap((uint32_t *) p + 3); + } + + offset += 4 * sizeof(float); + return SGVec4f(p); } }; +template +static void read_indices(char* buffer, + size_t bytes, + int indexMask, + int_list& vertices, + int_list& normals, + int_list& colors, + int_list& texCoords) +{ + const int indexSize = sizeof(T) * std::bitset<32>(indexMask).count(); + const int count = bytes / indexSize; + +// fix endian-ness of the whole lot, if required + if (sgIsBigEndian()) { + int indices = bytes / sizeof(T); + T* src = reinterpret_cast(buffer); + for (int i=0; i(buffer); + for (int i=0; i +void write_indice(gzFile fp, T value) +{ + sgWriteBytes(fp, sizeof(T), &value); +} + +// specialize template to call endian-aware conversion methods +template <> +void write_indice(gzFile fp, uint16_t value) +{ + sgWriteUShort(fp, value); +} + +template <> +void write_indice(gzFile fp, uint32_t value) +{ + sgWriteUInt(fp, value); +} + + +template +void write_indices(gzFile fp, unsigned char indexMask, + const int_list& vertices, + const int_list& normals, + const int_list& colors, + const int_list& texCoords) +{ + unsigned int count = vertices.size(); + const int indexSize = sizeof(T) * std::bitset<32>(indexMask).count(); + sgWriteUInt(fp, indexSize * count); + + for (unsigned int i=0; i < count; ++i) { + write_indice(fp, static_cast(vertices[i])); + + if (!normals.empty()) { + write_indice(fp, static_cast(normals[i])); + } + if (!colors.empty()) { + write_indice(fp, static_cast(colors[i])); + } + if (!texCoords.empty()) { + write_indice(fp, static_cast(texCoords[i])); + } + } +} + + // read object properties -static void read_object( gzFile fp, - int obj_type, - int nproperties, - int nelements, - group_list *vertices, - group_list *normals, - group_list *colors, - group_list *texcoords, - string_list *materials ) +void SGBinObject::read_object( gzFile fp, + int obj_type, + int nproperties, + int nelements, + group_list& vertices, + group_list& normals, + group_list& colors, + group_list& texCoords, + string_list& materials) { unsigned int nbytes; unsigned char idx_mask; - int idx_size; - bool do_vertices, do_normals, do_colors, do_texcoords; - int j, k, idx; + int j; sgSimpleBuffer buf( 32768 ); // 32 Kb char material[256]; // default values if ( obj_type == SG_POINTS ) { - idx_size = 1; - idx_mask = SG_IDX_VERTICES; - do_vertices = true; - do_normals = false; - do_colors = false; - do_texcoords = false; + idx_mask = SG_IDX_VERTICES; } else { - idx_size = 2; - idx_mask = (char)(SG_IDX_VERTICES | SG_IDX_TEXCOORDS); - do_vertices = true; - do_normals = false; - do_colors = false; - do_texcoords = true; + idx_mask = (char)(SG_IDX_VERTICES | SG_IDX_TEXCOORDS); } for ( j = 0; j < nproperties; ++j ) { - char prop_type; - sgReadChar( fp, &prop_type ); - - sgReadUInt( fp, &nbytes ); - // cout << "property size = " << nbytes << endl; - if ( nbytes > buf.get_size() ) { buf.resize( nbytes ); } - char *ptr = buf.get_ptr(); - sgReadBytes( fp, nbytes, ptr ); - if ( prop_type == SG_MATERIAL ) { - strncpy( material, ptr, nbytes ); - material[nbytes] = '\0'; - // cout << "material type = " << material << endl; - } else if ( prop_type == SG_INDEX_TYPES ) { - idx_mask = ptr[0]; - // cout << "idx_mask = " << (int)idx_mask << endl; - idx_size = 0; - do_vertices = false; - do_normals = false; - do_colors = false; - do_texcoords = false; - if ( idx_mask & SG_IDX_VERTICES ) { - do_vertices = true; - ++idx_size; - } - if ( idx_mask & SG_IDX_NORMALS ) { - do_normals = true; - ++idx_size; - } - if ( idx_mask & SG_IDX_COLORS ) { - do_colors = true; - ++idx_size; - } - if ( idx_mask & SG_IDX_TEXCOORDS ) { - do_texcoords = true; - ++idx_size; - } - } + char prop_type; + sgReadChar( fp, &prop_type ); + sgReadUInt( fp, &nbytes ); + buf.resize(nbytes); + char *ptr = buf.get_ptr(); + sgReadBytes( fp, nbytes, ptr ); + if ( prop_type == SG_MATERIAL ) { + if (nbytes > 255) { + nbytes = 255; + } + strncpy( material, ptr, nbytes ); + material[nbytes] = '\0'; + // cout << "material type = " << material << endl; + } else if ( prop_type == SG_INDEX_TYPES ) { + idx_mask = ptr[0]; + //cout << std::hex << "index mask:" << idx_mask << std::dec << endl; + } } + if ( sgReadError() ) { + cout << "We detected an error reading object properties" << endl; + return; + } + for ( j = 0; j < nelements; ++j ) { - sgReadUInt( fp, &nbytes ); - // cout << "element size = " << nbytes << endl; - if ( nbytes > buf.get_size() ) { buf.resize( nbytes ); } - char *ptr = buf.get_ptr(); - sgReadBytes( fp, nbytes, ptr ); - int count = nbytes / (idx_size * sizeof(unsigned short)); - unsigned short *sptr = (unsigned short *)ptr; - int_list vs; vs.clear(); - int_list ns; ns.clear(); - int_list cs; cs.clear(); - int_list tcs; tcs.clear(); - for ( k = 0; k < count; ++k ) { - if ( sgIsBigEndian() ) { - for ( idx = 0; idx < idx_size; ++idx ) { - sgEndianSwap( (uint16_t *)&(sptr[idx]) ); - } - } - idx = 0; - if ( do_vertices ) { - vs.push_back( sptr[idx++] ); - } - if ( do_normals ) { - ns.push_back( sptr[idx++] ); - } - if ( do_colors ) { - cs.push_back( sptr[idx++] ); - } - if ( do_texcoords ) { - tcs.push_back( sptr[idx++] ); - } - // cout << sptr[0] << " "; - sptr += idx_size; - } - // cout << endl; - vertices->push_back( vs ); - normals->push_back( ns ); - colors->push_back( cs ); - texcoords->push_back( tcs ); - materials->push_back( material ); - } + sgReadUInt( fp, &nbytes ); + if ( sgReadError() ) { + cout << "We detected an error reading element size for :" << j << endl; + return; + } + + buf.resize( nbytes ); + char *ptr = buf.get_ptr(); + sgReadBytes( fp, nbytes, ptr ); + + if ( sgReadError() ) { + cout << "We detected an error reading object element:" << j << "bytes="<< nbytes << endl; + return; + } + + int_list vs; + int_list ns; + int_list cs; + int_list tcs; + if (version >= 10) { + read_indices(ptr, nbytes, idx_mask, vs, ns, cs, tcs); + } else { + read_indices(ptr, nbytes, idx_mask, vs, ns, cs, tcs); + } + + vertices.push_back( vs ); + normals.push_back( ns ); + colors.push_back( cs ); + texCoords.push_back( tcs ); + materials.push_back( material ); + } // of element iteration } // read a binary file and populate the provided structures. bool SGBinObject::read_bin( const string& file ) { SGVec3d p; - int i, j, k; + int i, k; + size_t j; unsigned int nbytes; sgSimpleBuffer buf( 32768 ); // 32 Kb @@ -279,13 +400,13 @@ bool SGBinObject::read_bin( const string& file ) { gzFile fp; if ( (fp = gzopen( file.c_str(), "rb" )) == NULL ) { - string filegz = file + ".gz"; - if ( (fp = gzopen( filegz.c_str(), "rb" )) == NULL ) { + string filegz = file + ".gz"; + if ( (fp = gzopen( filegz.c_str(), "rb" )) == NULL ) { SG_LOG( SG_EVENT, SG_ALERT, "ERROR: opening " << file << " or " << filegz << " for reading!"); - return false; - } + return false; + } } sgClearReadError(); @@ -294,16 +415,16 @@ bool SGBinObject::read_bin( const string& file ) { unsigned int header; sgReadUInt( fp, &header ); if ( ((header & 0xFF000000) >> 24) == 'S' && - ((header & 0x00FF0000) >> 16) == 'G' ) { - // cout << "Good header" << endl; - // read file version - version = (header & 0x0000FFFF); - // cout << "File version = " << version << endl; + ((header & 0x00FF0000) >> 16) == 'G' ) { + // cout << "Good header" << endl; + // read file version + version = (header & 0x0000FFFF); + // cout << "File version = " << version << endl; } else { - // close the file before we return - gzclose(fp); + // close the file before we return + gzclose(fp); - return false; + return false; } // read creation time @@ -324,673 +445,383 @@ bool SGBinObject::read_bin( const string& file ) { #endif // read number of top level objects - unsigned short nobjects; - if ( version >= 7 ) { - sgReadUShort( fp, &nobjects ); + int nobjects; + if ( version >= 10) { // version 10 extends everything to be 32-bit + sgReadInt( fp, &nobjects ); + } else if ( version >= 7 ) { + uint16_t v; + sgReadUShort( fp, &v ); + nobjects = v; } else { - short tmp; - sgReadShort( fp, &tmp ); - nobjects = tmp; + int16_t v; + sgReadShort( fp, &v ); + nobjects = v; } - // cout << "Total objects to read = " << nobjects << endl; + + //cout << "Total objects to read = " << nobjects << endl; + if ( sgReadError() ) { + cout << "We detected an error while reading the file header" << endl; + return false; + } + // read in objects for ( i = 0; i < nobjects; ++i ) { - // read object header - char obj_type; - unsigned short nproperties, nelements; - sgReadChar( fp, &obj_type ); - if ( version >= 7 ) { - sgReadUShort( fp, &nproperties ); - sgReadUShort( fp, &nelements ); + // read object header + char obj_type; + uint32_t nproperties, nelements; + sgReadChar( fp, &obj_type ); + if ( version >= 10 ) { + sgReadUInt( fp, &nproperties ); + sgReadUInt( fp, &nelements ); + } else if ( version >= 7 ) { + uint16_t v; + sgReadUShort( fp, &v ); + nproperties = v; + sgReadUShort( fp, &v ); + nelements = v; } else { - short tmp; - sgReadShort( fp, &tmp ); - nproperties = tmp; - sgReadShort( fp, &tmp ); - nelements = tmp; + int16_t v; + sgReadShort( fp, &v ); + nproperties = v; + sgReadShort( fp, &v ); + nelements = v; } - // cout << "object " << i << " = " << (int)obj_type << " props = " - // << nproperties << " elements = " << nelements << endl; - - if ( obj_type == SG_BOUNDING_SPHERE ) { - // read bounding sphere properties - for ( j = 0; j < nproperties; ++j ) { - char prop_type; - sgReadChar( fp, &prop_type ); + //cout << "object " << i << " = " << (int)obj_type << " props = " + // << nproperties << " elements = " << nelements << endl; + + if ( obj_type == SG_BOUNDING_SPHERE ) { + // read bounding sphere properties + read_properties( fp, nproperties ); + + // read bounding sphere elements + for ( j = 0; j < nelements; ++j ) { + sgReadUInt( fp, &nbytes ); + buf.resize( nbytes ); + buf.reset(); + char *ptr = buf.get_ptr(); + sgReadBytes( fp, nbytes, ptr ); + gbs_center = buf.readVec3d(); + gbs_radius = buf.readFloat(); + } + } else if ( obj_type == SG_VERTEX_LIST ) { + // read vertex list properties + read_properties( fp, nproperties ); - sgReadUInt( fp, &nbytes ); - // cout << "property size = " << nbytes << endl; - if ( nbytes > buf.get_size() ) { buf.resize( nbytes ); } - char *ptr = buf.get_ptr(); - sgReadBytes( fp, nbytes, ptr ); - } + // read vertex list elements + for ( j = 0; j < nelements; ++j ) { + sgReadUInt( fp, &nbytes ); + buf.resize( nbytes ); + buf.reset(); + char *ptr = buf.get_ptr(); + sgReadBytes( fp, nbytes, ptr ); + int count = nbytes / (sizeof(float) * 3); + wgs84_nodes.reserve( count ); + for ( k = 0; k < count; ++k ) { + SGVec3f v = buf.readVec3f(); + // extend from float to double, hmmm + wgs84_nodes.push_back( SGVec3d(v[0], v[1], v[2]) ); + } + } + } else if ( obj_type == SG_COLOR_LIST ) { + // read color list properties + read_properties( fp, nproperties ); - // read bounding sphere elements - for ( j = 0; j < nelements; ++j ) { - sgReadUInt( fp, &nbytes ); - // cout << "element size = " << nbytes << endl; - if ( nbytes > buf.get_size() ) { buf.resize( nbytes ); } - char *ptr = buf.get_ptr(); - sgReadBytes( fp, nbytes, ptr ); + // read color list elements + for ( j = 0; j < nelements; ++j ) { + sgReadUInt( fp, &nbytes ); + buf.resize( nbytes ); + buf.reset(); + char *ptr = buf.get_ptr(); + sgReadBytes( fp, nbytes, ptr ); + int count = nbytes / (sizeof(float) * 4); + colors.reserve(count); + for ( k = 0; k < count; ++k ) { + colors.push_back( buf.readVec4f() ); + } + } + } else if ( obj_type == SG_NORMAL_LIST ) { + // read normal list properties + read_properties( fp, nproperties ); - double *dptr = (double *)ptr; - if ( sgIsBigEndian() ) { - sgEndianSwap( (uint64_t *)&(dptr[0]) ); - sgEndianSwap( (uint64_t *)&(dptr[1]) ); - sgEndianSwap( (uint64_t *)&(dptr[2]) ); - } - gbs_center = SGVec3d( dptr[0], dptr[1], dptr[2] ); - // cout << "Center = " << gbs_center << endl; - ptr += sizeof(double) * 3; - - float *fptr = (float *)ptr; - if ( sgIsBigEndian() ) { - sgEndianSwap( (uint32_t *)fptr ); - } - gbs_radius = fptr[0]; - // cout << "Bounding radius = " << gbs_radius << endl; - } - } else if ( obj_type == SG_VERTEX_LIST ) { - // read vertex list properties - for ( j = 0; j < nproperties; ++j ) { - char prop_type; - sgReadChar( fp, &prop_type ); + // read normal list elements + for ( j = 0; j < nelements; ++j ) { + sgReadUInt( fp, &nbytes ); + buf.resize( nbytes ); + buf.reset(); + unsigned char *ptr = (unsigned char *)(buf.get_ptr()); + sgReadBytes( fp, nbytes, ptr ); + int count = nbytes / 3; + normals.reserve( count ); + + for ( k = 0; k < count; ++k ) { + SGVec3f normal( (ptr[0]) / 127.5 - 1.0, + (ptr[1]) / 127.5 - 1.0, + (ptr[2]) / 127.5 - 1.0); + normals.push_back(normalize(normal)); + ptr += 3; + } + } + } else if ( obj_type == SG_TEXCOORD_LIST ) { + // read texcoord list properties + read_properties( fp, nproperties ); - sgReadUInt( fp, &nbytes ); - // cout << "property size = " << nbytes << endl; - if ( nbytes > buf.get_size() ) { buf.resize( nbytes ); } - char *ptr = buf.get_ptr(); - sgReadBytes( fp, nbytes, ptr ); - } + // read texcoord list elements + for ( j = 0; j < nelements; ++j ) { + sgReadUInt( fp, &nbytes ); + buf.resize( nbytes ); + buf.reset(); + char *ptr = buf.get_ptr(); + sgReadBytes( fp, nbytes, ptr ); + int count = nbytes / (sizeof(float) * 2); + texcoords.reserve(count); + for ( k = 0; k < count; ++k ) { + texcoords.push_back( buf.readVec2f() ); + } + } + } else if ( obj_type == SG_POINTS ) { + // read point elements + read_object( fp, SG_POINTS, nproperties, nelements, + pts_v, pts_n, pts_c, pts_tc, pt_materials ); + } else if ( obj_type == SG_TRIANGLE_FACES ) { + // read triangle face properties + read_object( fp, SG_TRIANGLE_FACES, nproperties, nelements, + tris_v, tris_n, tris_c, tris_tc, tri_materials ); + } else if ( obj_type == SG_TRIANGLE_STRIPS ) { + // read triangle strip properties + read_object( fp, SG_TRIANGLE_STRIPS, nproperties, nelements, + strips_v, strips_n, strips_c, strips_tc, + strip_materials ); + } else if ( obj_type == SG_TRIANGLE_FANS ) { + // read triangle fan properties + read_object( fp, SG_TRIANGLE_FANS, nproperties, nelements, + fans_v, fans_n, fans_c, fans_tc, fan_materials ); + } else { + // unknown object type, just skip + read_properties( fp, nproperties ); - // read vertex list elements - for ( j = 0; j < nelements; ++j ) { - sgReadUInt( fp, &nbytes ); - // cout << "element size = " << nbytes << endl; - if ( nbytes > buf.get_size() ) { buf.resize( nbytes ); } - char *ptr = buf.get_ptr(); - sgReadBytes( fp, nbytes, ptr ); - int count = nbytes / (sizeof(float) * 3); - float *fptr = (float *)ptr; - wgs84_nodes.reserve( count ); - for ( k = 0; k < count; ++k ) { - if ( sgIsBigEndian() ) { - sgEndianSwap( (uint32_t *)&(fptr[0]) ); - sgEndianSwap( (uint32_t *)&(fptr[1]) ); - sgEndianSwap( (uint32_t *)&(fptr[2]) ); - } - wgs84_nodes.push_back( SGVec3d(fptr[0], fptr[1], fptr[2]) ); - fptr += 3; - } - } - } else if ( obj_type == SG_COLOR_LIST ) { - // read color list properties - for ( j = 0; j < nproperties; ++j ) { - char prop_type; - sgReadChar( fp, &prop_type ); - - sgReadUInt( fp, &nbytes ); - // cout << "property size = " << nbytes << endl; - if ( nbytes > buf.get_size() ) { buf.resize( nbytes ); } - char *ptr = buf.get_ptr(); - sgReadBytes( fp, nbytes, ptr ); - } - - // read color list elements - for ( j = 0; j < nelements; ++j ) { - sgReadUInt( fp, &nbytes ); - // cout << "element size = " << nbytes << endl; - if ( nbytes > buf.get_size() ) { buf.resize( nbytes ); } - char *ptr = buf.get_ptr(); - sgReadBytes( fp, nbytes, ptr ); - int count = nbytes / (sizeof(float) * 4); - float *fptr = (float *)ptr; - colors.reserve(count); - for ( k = 0; k < count; ++k ) { - if ( sgIsBigEndian() ) { - sgEndianSwap( (uint32_t *)&(fptr[0]) ); - sgEndianSwap( (uint32_t *)&(fptr[1]) ); - sgEndianSwap( (uint32_t *)&(fptr[2]) ); - sgEndianSwap( (uint32_t *)&(fptr[3]) ); - } - SGVec4f color( fptr[0], fptr[1], fptr[2], fptr[3] ); - colors.push_back( color ); - fptr += 4; - } - } - } else if ( obj_type == SG_NORMAL_LIST ) { - // read normal list properties - for ( j = 0; j < nproperties; ++j ) { - char prop_type; - sgReadChar( fp, &prop_type ); - - sgReadUInt( fp, &nbytes ); - // cout << "property size = " << nbytes << endl; - if ( nbytes > buf.get_size() ) { buf.resize( nbytes ); } - char *ptr = buf.get_ptr(); - sgReadBytes( fp, nbytes, ptr ); - } - - // read normal list elements - for ( j = 0; j < nelements; ++j ) { - sgReadUInt( fp, &nbytes ); - // cout << "element size = " << nbytes << endl; - if ( nbytes > buf.get_size() ) { buf.resize( nbytes ); } - unsigned char *ptr = (unsigned char *)(buf.get_ptr()); - sgReadBytes( fp, nbytes, ptr ); - int count = nbytes / 3; - normals.reserve( count ); - for ( k = 0; k < count; ++k ) { - SGVec3f normal((ptr[0]) / 127.5 - 1.0, - (ptr[1]) / 127.5 - 1.0, - (ptr[2]) / 127.5 - 1.0); - - normals.push_back(normalize(normal)); - ptr += 3; - } - } - } else if ( obj_type == SG_TEXCOORD_LIST ) { - // read texcoord list properties - for ( j = 0; j < nproperties; ++j ) { - char prop_type; - sgReadChar( fp, &prop_type ); - - sgReadUInt( fp, &nbytes ); - // cout << "property size = " << nbytes << endl; - if ( nbytes > buf.get_size() ) { buf.resize( nbytes ); } - char *ptr = buf.get_ptr(); - sgReadBytes( fp, nbytes, ptr ); - } - - // read texcoord list elements - for ( j = 0; j < nelements; ++j ) { - sgReadUInt( fp, &nbytes ); - // cout << "element size = " << nbytes << endl; - if ( nbytes > buf.get_size() ) { buf.resize( nbytes ); } - char *ptr = buf.get_ptr(); - sgReadBytes( fp, nbytes, ptr ); - int count = nbytes / (sizeof(float) * 2); - float *fptr = (float *)ptr; - texcoords.reserve(count); - for ( k = 0; k < count; ++k ) { - if ( sgIsBigEndian() ) { - sgEndianSwap( (uint32_t *)&(fptr[0]) ); - sgEndianSwap( (uint32_t *)&(fptr[1]) ); - } - texcoords.push_back( SGVec2f( fptr[0], fptr[1] ) ); - fptr += 2; - } - } - } else if ( obj_type == SG_POINTS ) { - // read point elements - read_object( fp, SG_POINTS, nproperties, nelements, - &pts_v, &pts_n, &pts_c, &pts_tc, &pt_materials ); - } else if ( obj_type == SG_TRIANGLE_FACES ) { - // read triangle face properties - read_object( fp, SG_TRIANGLE_FACES, nproperties, nelements, - &tris_v, &tris_n, &tris_c, &tris_tc, &tri_materials ); - } else if ( obj_type == SG_TRIANGLE_STRIPS ) { - // read triangle strip properties - read_object( fp, SG_TRIANGLE_STRIPS, nproperties, nelements, - &strips_v, &strips_n, &strips_c, &strips_tc, - &strip_materials ); - } else if ( obj_type == SG_TRIANGLE_FANS ) { - // read triangle fan properties - read_object( fp, SG_TRIANGLE_FANS, nproperties, nelements, - &fans_v, &fans_n, &fans_c, &fans_tc, &fan_materials ); - } else { - // unknown object type, just skip - - // read properties - for ( j = 0; j < nproperties; ++j ) { - char prop_type; - sgReadChar( fp, &prop_type ); - - sgReadUInt( fp, &nbytes ); - // cout << "property size = " << nbytes << endl; - if ( nbytes > buf.get_size() ) { buf.resize( nbytes ); } - char *ptr = buf.get_ptr(); - sgReadBytes( fp, nbytes, ptr ); - } - - // read elements - for ( j = 0; j < nelements; ++j ) { - sgReadUInt( fp, &nbytes ); - // cout << "element size = " << nbytes << endl; - if ( nbytes > buf.get_size() ) { buf.resize( nbytes ); } - char *ptr = buf.get_ptr(); - sgReadBytes( fp, nbytes, ptr ); - } - } + // read elements + for ( j = 0; j < nelements; ++j ) { + sgReadUInt( fp, &nbytes ); + // cout << "element size = " << nbytes << endl; + if ( nbytes > buf.get_size() ) { buf.resize( nbytes ); } + char *ptr = buf.get_ptr(); + sgReadBytes( fp, nbytes, ptr ); + } + } + + if ( sgReadError() ) { + cout << "We detected an error while reading object:" << i << endl; + return false; + } } // close the file gzclose(fp); if ( sgReadError() ) { - cout << "We detected an error while reading the file." << endl; - return false; + cout << "We detected an error while reading the file." << endl; + return false; } return true; } +void SGBinObject::write_header(gzFile fp, int type, int nProps, int nElements) +{ + sgWriteChar(fp, (unsigned char) type); + if (version == 7) { + sgWriteUShort(fp, nProps); + sgWriteUShort(fp, nElements); + } else { + sgWriteUInt(fp, nProps); + sgWriteUInt(fp, nElements); + } +} + +unsigned int SGBinObject::count_objects(const string_list& materials) +{ + unsigned int result = 0; + unsigned int start = 0, end = 1; + unsigned int count = materials.size(); + string m; + + while ( start < count ) { + m = materials[start]; + for (end = start+1; (end < count) && (m == materials[end]); ++end) { } + ++result; + start = end; + } + + return result; +} + +void SGBinObject::write_objects(gzFile fp, int type, const group_list& verts, + const group_list& normals, const group_list& colors, + const group_list& texCoords, const string_list& materials) +{ + if (verts.empty()) { + return; + } + + unsigned int start = 0, end = 1; + string m; + while (start < materials.size()) { + m = materials[start]; + // find range of objects with identical material, write out as a single object + for (end = start+1; (end < materials.size()) && (m == materials[end]); ++end) {} + + const int count = end - start; + write_header(fp, type, 2, count); + + // properties + sgWriteChar( fp, (char)SG_MATERIAL ); // property + sgWriteUInt( fp, m.length() ); // nbytes + sgWriteBytes( fp, m.length(), m.c_str() ); + + unsigned char idx_mask = 0; + if ( !verts.empty() && !verts.front().empty()) idx_mask |= SG_IDX_VERTICES; + if ( !normals.empty() && !normals.front().empty()) idx_mask |= SG_IDX_NORMALS; + if ( !colors.empty() && !colors.front().empty()) idx_mask |= SG_IDX_COLORS; + if ( !texCoords.empty() && !texCoords.front().empty()) idx_mask |= SG_IDX_TEXCOORDS; + sgWriteChar( fp, (char)SG_INDEX_TYPES ); // property + sgWriteUInt( fp, 1 ); // nbytes + sgWriteChar( fp, idx_mask ); + +// cout << "material:" << m << ", count =" << count << endl; + // elements + for (unsigned int i=start; i < end; ++i) { + if (version == 7) { + write_indices(fp, idx_mask, verts[i], normals[i], colors[i], texCoords[i]); + } else { + write_indices(fp, idx_mask, verts[i], normals[i], colors[i], texCoords[i]); + } + } + + start = end; + } // of materials iteration +} // write out the structures to a binary file. We assume that the // groups come to us sorted by material property. If not, things // don't break, but the result won't be as optimal. bool SGBinObject::write_bin( const string& base, const string& name, - const SGBucket& b ) + const SGBucket& b ) { - int i, j; - unsigned char idx_mask; - int idx_size; SGPath file = base + "/" + b.gen_base_path() + "/" + name + ".gz"; - file.create_dir( 0755 ); + return write_bin_file(file); +} + +bool SGBinObject::write_bin_file(const SGPath& file) +{ + int i; + + SGPath file2(file); + file2.create_dir( 0755 ); cout << "Output file = " << file.str() << endl; gzFile fp; if ( (fp = gzopen( file.c_str(), "wb9" )) == NULL ) { - cout << "ERROR: opening " << file.str() << " for writing!" << endl; - return false; + cout << "ERROR: opening " << file.str() << " for writing!" << endl; + return false; } sgClearWriteError(); cout << "points size = " << pts_v.size() << " pt_materials = " - << pt_materials.size() << endl; + << pt_materials.size() << endl; cout << "triangles size = " << tris_v.size() << " tri_materials = " - << tri_materials.size() << endl; + << tri_materials.size() << endl; cout << "strips size = " << strips_v.size() << " strip_materials = " - << strip_materials.size() << endl; + << strip_materials.size() << endl; cout << "fans size = " << fans_v.size() << " fan_materials = " - << fan_materials.size() << endl; + << fan_materials.size() << endl; cout << "nodes = " << wgs84_nodes.size() << endl; cout << "colors = " << colors.size() << endl; cout << "normals = " << normals.size() << endl; cout << "tex coords = " << texcoords.size() << endl; + version = 10; + if (wgs84_nodes.size() < 0xffff) { + version = 7; // use smaller indices if possible + } + // write header magic + + /** Magic Number for our file format */ + #define SG_FILE_MAGIC_NUMBER ( ('S'<<24) + ('G'<<16) + version ) + sgWriteUInt( fp, SG_FILE_MAGIC_NUMBER ); time_t calendar_time = time(NULL); sgWriteLong( fp, (int32_t)calendar_time ); // calculate and write number of top level objects - string material; - int start; - int end; - unsigned short nobjects = 0; - nobjects++; // for gbs - nobjects++; // for vertices - nobjects++; // for colors - nobjects++; // for normals - nobjects++; // for texcoords - - // points - unsigned short npts = 0; - start = 0; end = 1; - while ( start < (int)pt_materials.size() ) { - material = pt_materials[start]; - while ( (end < (int)pt_materials.size()) && - (material == pt_materials[end]) ) { - end++; - } - npts++; - start = end; end = start + 1; - } - nobjects += npts; - - // tris - unsigned short ntris = 0; - start = 0; end = 1; - while ( start < (int)tri_materials.size() ) { - material = tri_materials[start]; - while ( (end < (int)tri_materials.size()) && - (material == tri_materials[end]) ) { - end++; - } - ntris++; - start = end; end = start + 1; - } - nobjects += ntris; - - // strips - unsigned short nstrips = 0; - start = 0; end = 1; - while ( start < (int)strip_materials.size() ) { - material = strip_materials[start]; - while ( (end < (int)strip_materials.size()) && - (material == strip_materials[end]) ) { - end++; - } - nstrips++; - start = end; end = start + 1; - } - nobjects += nstrips; - - // fans - unsigned short nfans = 0; - start = 0; end = 1; - while ( start < (int)fan_materials.size() ) { - material = fan_materials[start]; - while ( (end < (int)fan_materials.size()) && - (material == fan_materials[end]) ) { - end++; - } - nfans++; - start = end; end = start + 1; - } - nobjects += nfans; + int nobjects = 5; // gbs, vertices, colors, normals, texcoords + nobjects += count_objects(pt_materials); + nobjects += count_objects(tri_materials); + nobjects += count_objects(strip_materials); + nobjects += count_objects(fan_materials); cout << "total top level objects = " << nobjects << endl; - sgWriteUShort( fp, nobjects ); - + if (version == 7) { + sgWriteUShort( fp, (uint16_t) nobjects ); + } else { + sgWriteInt( fp, nobjects ); + } + // write bounding sphere - sgWriteChar( fp, (char)SG_BOUNDING_SPHERE ); // type - sgWriteUShort( fp, 0 ); // nproperties - sgWriteUShort( fp, 1 ); // nelements - + write_header( fp, SG_BOUNDING_SPHERE, 0, 1); sgWriteUInt( fp, sizeof(double) * 3 + sizeof(float) ); // nbytes sgWritedVec3( fp, gbs_center ); sgWriteFloat( fp, gbs_radius ); // dump vertex list - sgWriteChar( fp, (char)SG_VERTEX_LIST ); // type - sgWriteUShort( fp, 0 ); // nproperties - sgWriteUShort( fp, 1 ); // nelements + write_header( fp, SG_VERTEX_LIST, 0, 1); sgWriteUInt( fp, wgs84_nodes.size() * sizeof(float) * 3 ); // nbytes for ( i = 0; i < (int)wgs84_nodes.size(); ++i ) { sgWriteVec3( fp, toVec3f(wgs84_nodes[i] - gbs_center)); } // dump vertex color list - sgWriteChar( fp, (char)SG_COLOR_LIST ); // type - sgWriteUShort( fp, 0 ); // nproperties - sgWriteUShort( fp, 1 ); // nelements + write_header( fp, SG_COLOR_LIST, 0, 1); sgWriteUInt( fp, colors.size() * sizeof(float) * 4 ); // nbytes for ( i = 0; i < (int)colors.size(); ++i ) { sgWriteVec4( fp, colors[i]); } // dump vertex normal list - sgWriteChar( fp, (char)SG_NORMAL_LIST ); // type - sgWriteUShort( fp, 0 ); // nproperties - sgWriteUShort( fp, 1 ); // nelements + write_header( fp, SG_NORMAL_LIST, 0, 1); sgWriteUInt( fp, normals.size() * 3 ); // nbytes char normal[3]; for ( i = 0; i < (int)normals.size(); ++i ) { SGVec3f p = normals[i]; - normal[0] = (unsigned char)((p.x() + 1.0) * 127.5); - normal[1] = (unsigned char)((p.y() + 1.0) * 127.5); - normal[2] = (unsigned char)((p.z() + 1.0) * 127.5); - sgWriteBytes( fp, 3, normal ); + normal[0] = (unsigned char)((p.x() + 1.0) * 127.5); + normal[1] = (unsigned char)((p.y() + 1.0) * 127.5); + normal[2] = (unsigned char)((p.z() + 1.0) * 127.5); + sgWriteBytes( fp, 3, normal ); } // dump texture coordinates - sgWriteChar( fp, (char)SG_TEXCOORD_LIST ); // type - sgWriteUShort( fp, 0 ); // nproperties - sgWriteUShort( fp, 1 ); // nelements + write_header( fp, SG_TEXCOORD_LIST, 0, 1); sgWriteUInt( fp, texcoords.size() * sizeof(float) * 2 ); // nbytes for ( i = 0; i < (int)texcoords.size(); ++i ) { sgWriteVec2( fp, texcoords[i]); } - // dump point groups if they exist - if ( pts_v.size() > 0 ) { - int start = 0; - int end = 1; - string material; - while ( start < (int)pt_materials.size() ) { - // find next group - material = pt_materials[start]; - while ( (end < (int)pt_materials.size()) && - (material == pt_materials[end]) ) - { - // cout << "end = " << end << endl; - end++; - } - // cout << "group = " << start << " to " << end - 1 << endl; - - // write group headers - sgWriteChar( fp, (char)SG_POINTS ); // type - sgWriteUShort( fp, 2 ); // nproperties - sgWriteUShort( fp, end - start ); // nelements - - sgWriteChar( fp, (char)SG_MATERIAL ); // property - sgWriteUInt( fp, material.length() ); // nbytes - sgWriteBytes( fp, material.length(), material.c_str() ); - - idx_mask = 0; - idx_size = 0; - if ( pts_v.size() ) { idx_mask |= SG_IDX_VERTICES; ++idx_size; } - if ( pts_n.size() ) { idx_mask |= SG_IDX_NORMALS; ++idx_size; } - if ( pts_c.size() ) { idx_mask |= SG_IDX_COLORS; ++idx_size; } - if ( pts_tc.size() ) { idx_mask |= SG_IDX_TEXCOORDS; ++idx_size; } - sgWriteChar( fp, (char)SG_INDEX_TYPES ); // property - sgWriteUInt( fp, 1 ); // nbytes - sgWriteChar( fp, idx_mask ); - - // write strips - for ( i = start; i < end; ++i ) { - // nbytes - sgWriteUInt( fp, pts_v[i].size() * idx_size - * sizeof(unsigned short) ); - for ( j = 0; j < (int)pts_v[i].size(); ++j ) { - if ( pts_v.size() ) { - sgWriteUShort( fp, (unsigned short)pts_v[i][j] ); - } - if ( pts_n.size() ) { - sgWriteUShort( fp, (unsigned short)pts_n[i][j] ); - } - if ( pts_c.size() ) { - sgWriteUShort( fp, (unsigned short)pts_c[i][j] ); - } - if ( pts_tc.size() ) { - sgWriteUShort( fp, (unsigned short)pts_tc[i][j] ); - } - } - } - - start = end; - end = start + 1; - } - } - - // dump individual triangles if they exist - if ( tris_v.size() > 0 ) { - int start = 0; - int end = 1; - string material; - while ( start < (int)tri_materials.size() ) { - // find next group - material = tri_materials[start]; - while ( (end < (int)tri_materials.size()) && - (material == tri_materials[end]) && - 3*(end-start) < 32760 ) - { - // cout << "end = " << end << endl; - end++; - } - // cout << "group = " << start << " to " << end - 1 << endl; - - // write group headers - sgWriteChar( fp, (char)SG_TRIANGLE_FACES ); // type - sgWriteUShort( fp, 2 ); // nproperties - sgWriteUShort( fp, 1 ); // nelements - - sgWriteChar( fp, (char)SG_MATERIAL ); // property - sgWriteUInt( fp, material.length() ); // nbytes - sgWriteBytes( fp, material.length(), material.c_str() ); - - idx_mask = 0; - idx_size = 0; - if ( tris_v.size() ) { idx_mask |= SG_IDX_VERTICES; ++idx_size; } - if ( tris_n.size() ) { idx_mask |= SG_IDX_NORMALS; ++idx_size; } - if ( tris_c.size() ) { idx_mask |= SG_IDX_COLORS; ++idx_size; } - if ( tris_tc.size() ) { idx_mask |= SG_IDX_TEXCOORDS; ++idx_size; } - sgWriteChar( fp, (char)SG_INDEX_TYPES ); // property - sgWriteUInt( fp, 1 ); // nbytes - sgWriteChar( fp, idx_mask ); - - // nbytes - sgWriteUInt( fp, (end - start) * 3 * idx_size - * sizeof(unsigned short) ); - - // write group - for ( i = start; i < end; ++i ) { - for ( j = 0; j < 3; ++j ) { - if ( tris_v.size() ) { - sgWriteUShort( fp, (unsigned short)tris_v[i][j] ); - } - if ( tris_n.size() ) { - sgWriteUShort( fp, (unsigned short)tris_n[i][j] ); - } - if ( tris_c.size() ) { - sgWriteUShort( fp, (unsigned short)tris_c[i][j] ); - } - if ( tris_tc.size() ) { - sgWriteUShort( fp, (unsigned short)tris_tc[i][j] ); - } - } - } - - start = end; - end = start + 1; - } - } - - // dump triangle strips - if ( strips_v.size() > 0 ) { - int start = 0; - int end = 1; - string material; - while ( start < (int)strip_materials.size() ) { - // find next group - material = strip_materials[start]; - while ( (end < (int)strip_materials.size()) && - (material == strip_materials[end]) ) - { - // cout << "end = " << end << endl; - end++; - } - // cout << "group = " << start << " to " << end - 1 << endl; - - // write group headers - sgWriteChar( fp, (char)SG_TRIANGLE_STRIPS ); // type - sgWriteUShort( fp, 2 ); // nproperties - sgWriteUShort( fp, end - start ); // nelements - - sgWriteChar( fp, (char)SG_MATERIAL ); // property - sgWriteUInt( fp, material.length() ); // nbytes - sgWriteBytes( fp, material.length(), material.c_str() ); - - idx_mask = 0; - idx_size = 0; - if ( strips_v.size() ) { idx_mask |= SG_IDX_VERTICES; ++idx_size; } - if ( strips_n.size() ) { idx_mask |= SG_IDX_NORMALS; ++idx_size; } - if ( strips_c.size() ) { idx_mask |= SG_IDX_COLORS; ++idx_size; } - if ( strips_tc.size() ) { idx_mask |= SG_IDX_TEXCOORDS; ++idx_size;} - sgWriteChar( fp, (char)SG_INDEX_TYPES ); // property - sgWriteUInt( fp, 1 ); // nbytes - sgWriteChar( fp, idx_mask ); - - // write strips - for ( i = start; i < end; ++i ) { - // nbytes - sgWriteUInt( fp, strips_v[i].size() * idx_size - * sizeof(unsigned short)); - for ( j = 0; j < (int)strips_v[i].size(); ++j ) { - if ( strips_v.size() ) { - sgWriteUShort( fp, (unsigned short)strips_v[i][j] ); - } - if ( strips_n.size() ) { - sgWriteUShort( fp, (unsigned short)strips_n[i][j] ); - } - if ( strips_c.size() ) { - sgWriteUShort( fp, (unsigned short)strips_c[i][j] ); - } - if ( strips_tc.size() ) { - sgWriteUShort( fp, (unsigned short)strips_tc[i][j] ); - } - } - } - - start = end; - end = start + 1; - } - } - - // dump triangle fans - if ( fans_v.size() > 0 ) { - int start = 0; - int end = 1; - string material; - while ( start < (int)fan_materials.size() ) { - // find next group - material = fan_materials[start]; - while ( (end < (int)fan_materials.size()) && - (material == fan_materials[end]) ) - { - // cout << "end = " << end << endl; - end++; - } - // cout << "group = " << start << " to " << end - 1 << endl; - - // write group headers - sgWriteChar( fp, (char)SG_TRIANGLE_FANS ); // type - sgWriteUShort( fp, 2 ); // nproperties - sgWriteUShort( fp, end - start ); // nelements - - sgWriteChar( fp, (char)SG_MATERIAL ); // property - sgWriteUInt( fp, material.length() ); // nbytes - sgWriteBytes( fp, material.length(), material.c_str() ); - - idx_mask = 0; - idx_size = 0; - if ( fans_v.size() ) { idx_mask |= SG_IDX_VERTICES; ++idx_size; } - if ( fans_n.size() ) { idx_mask |= SG_IDX_NORMALS; ++idx_size; } - if ( fans_c.size() ) { idx_mask |= SG_IDX_COLORS; ++idx_size; } - if ( fans_tc.size() ) { idx_mask |= SG_IDX_TEXCOORDS; ++idx_size; } - sgWriteChar( fp, (char)SG_INDEX_TYPES ); // property - sgWriteUInt( fp, 1 ); // nbytes - sgWriteChar( fp, idx_mask ); - - // write fans - for ( i = start; i < end; ++i ) { - // nbytes - sgWriteUInt( fp, fans_v[i].size() * idx_size - * sizeof(unsigned short) ); - for ( j = 0; j < (int)fans_v[i].size(); ++j ) { - if ( fans_v.size() ) { - sgWriteUShort( fp, (unsigned short)fans_v[i][j] ); - } - if ( fans_n.size() ) { - sgWriteUShort( fp, (unsigned short)fans_n[i][j] ); - } - if ( fans_c.size() ) { - sgWriteUShort( fp, (unsigned short)fans_c[i][j] ); - } - if ( fans_tc.size() ) { - sgWriteUShort( fp, (unsigned short)fans_tc[i][j] ); - } - } - } - - start = end; - end = start + 1; - } - } - + write_objects(fp, SG_POINTS, pts_v, pts_n, pts_c, pts_tc, pt_materials); + write_objects(fp, SG_TRIANGLE_FACES, tris_v, tris_n, tris_c, tris_tc, tri_materials); + write_objects(fp, SG_TRIANGLE_STRIPS, strips_v, strips_n, strips_c, strips_tc, strip_materials); + write_objects(fp, SG_TRIANGLE_FANS, fans_v, fans_n, fans_c, fans_tc, fan_materials); + // close the file gzclose(fp); if ( sgWriteError() ) { - cout << "We detected an error while writing the file." << endl; - return false; + cout << "We detected an error while writing the file." << endl; + return false; } return true; @@ -1001,7 +832,7 @@ bool SGBinObject::write_bin( const string& base, const string& name, // groups come to us sorted by material property. If not, things // don't break, but the result won't be as optimal. bool SGBinObject::write_ascii( const string& base, const string& name, - const SGBucket& b ) + const SGBucket& b ) { int i, j; @@ -1011,16 +842,16 @@ bool SGBinObject::write_ascii( const string& base, const string& name, FILE *fp; if ( (fp = fopen( file.c_str(), "w" )) == NULL ) { - cout << "ERROR: opening " << file.str() << " for writing!" << endl; - return false; + cout << "ERROR: opening " << file.str() << " for writing!" << endl; + return false; } cout << "triangles size = " << tris_v.size() << " tri_materials = " - << tri_materials.size() << endl; + << tri_materials.size() << endl; cout << "strips size = " << strips_v.size() << " strip_materials = " - << strip_materials.size() << endl; + << strip_materials.size() << endl; cout << "fans size = " << fans_v.size() << " fan_materials = " - << fan_materials.size() << endl; + << fan_materials.size() << endl; cout << "points = " << wgs84_nodes.size() << endl; cout << "tex coords = " << texcoords.size() << endl; @@ -1038,22 +869,22 @@ bool SGBinObject::write_ascii( const string& base, const string& name, // write bounding sphere fprintf(fp, "# gbs %.5f %.5f %.5f %.2f\n", - gbs_center.x(), gbs_center.y(), gbs_center.z(), gbs_radius); + gbs_center.x(), gbs_center.y(), gbs_center.z(), gbs_radius); fprintf(fp, "\n"); // dump vertex list fprintf(fp, "# vertex list\n"); for ( i = 0; i < (int)wgs84_nodes.size(); ++i ) { SGVec3d p = wgs84_nodes[i] - gbs_center; - - fprintf(fp, "v %.5f %.5f %.5f\n", p.x(), p.y(), p.z() ); + + fprintf(fp, "v %.5f %.5f %.5f\n", p.x(), p.y(), p.z() ); } fprintf(fp, "\n"); fprintf(fp, "# vertex normal list\n"); for ( i = 0; i < (int)normals.size(); ++i ) { SGVec3f p = normals[i]; - fprintf(fp, "vn %.5f %.5f %.5f\n", p.x(), p.y(), p.z() ); + fprintf(fp, "vn %.5f %.5f %.5f\n", p.x(), p.y(), p.z() ); } fprintf(fp, "\n"); @@ -1061,27 +892,27 @@ bool SGBinObject::write_ascii( const string& base, const string& name, fprintf(fp, "# texture coordinate list\n"); for ( i = 0; i < (int)texcoords.size(); ++i ) { SGVec2f p = texcoords[i]; - fprintf(fp, "vt %.5f %.5f\n", p.x(), p.y() ); + fprintf(fp, "vt %.5f %.5f\n", p.x(), p.y() ); } fprintf(fp, "\n"); // dump individual triangles if they exist if ( tris_v.size() > 0 ) { - fprintf(fp, "# triangle groups\n"); + fprintf(fp, "# triangle groups\n"); - int start = 0; - int end = 1; - string material; - while ( start < (int)tri_materials.size() ) { - // find next group - material = tri_materials[start]; - while ( (end < (int)tri_materials.size()) && - (material == tri_materials[end]) ) - { - // cout << "end = " << end << endl; - end++; - } - // cout << "group = " << start << " to " << end - 1 << endl; + int start = 0; + int end = 1; + string material; + while ( start < (int)tri_materials.size() ) { + // find next group + material = tri_materials[start]; + while ( (end < (int)tri_materials.size()) && + (material == tri_materials[end]) ) + { + // cout << "end = " << end << endl; + end++; + } + // cout << "group = " << start << " to " << end - 1 << endl; SGSphered d; for ( i = start; i < end; ++i ) { @@ -1092,44 +923,44 @@ bool SGBinObject::write_ascii( const string& base, const string& name, SGVec3d bs_center = d.getCenter(); double bs_radius = d.getRadius(); - - // write group headers - fprintf(fp, "\n"); - fprintf(fp, "# usemtl %s\n", material.c_str()); - fprintf(fp, "# bs %.4f %.4f %.4f %.2f\n", - bs_center.x(), bs_center.y(), bs_center.z(), bs_radius); + + // write group headers + fprintf(fp, "\n"); + fprintf(fp, "# usemtl %s\n", material.c_str()); + fprintf(fp, "# bs %.4f %.4f %.4f %.2f\n", + bs_center.x(), bs_center.y(), bs_center.z(), bs_radius); - // write groups - for ( i = start; i < end; ++i ) { - fprintf(fp, "f"); - for ( j = 0; j < (int)tris_v[i].size(); ++j ) { - fprintf(fp, " %d/%d", tris_v[i][j], tris_tc[i][j] ); - } - fprintf(fp, "\n"); - } + // write groups + for ( i = start; i < end; ++i ) { + fprintf(fp, "f"); + for ( j = 0; j < (int)tris_v[i].size(); ++j ) { + fprintf(fp, " %d/%d", tris_v[i][j], tris_tc[i][j] ); + } + fprintf(fp, "\n"); + } - start = end; - end = start + 1; - } + start = end; + end = start + 1; + } } // dump triangle groups if ( strips_v.size() > 0 ) { - fprintf(fp, "# triangle strips\n"); + fprintf(fp, "# triangle strips\n"); - int start = 0; - int end = 1; - string material; - while ( start < (int)strip_materials.size() ) { - // find next group - material = strip_materials[start]; - while ( (end < (int)strip_materials.size()) && - (material == strip_materials[end]) ) - { - // cout << "end = " << end << endl; - end++; - } - // cout << "group = " << start << " to " << end - 1 << endl; + int start = 0; + int end = 1; + string material; + while ( start < (int)strip_materials.size() ) { + // find next group + material = strip_materials[start]; + while ( (end < (int)strip_materials.size()) && + (material == strip_materials[end]) ) + { + // cout << "end = " << end << endl; + end++; + } + // cout << "group = " << start << " to " << end - 1 << endl; SGSphered d; @@ -1142,24 +973,24 @@ bool SGBinObject::write_ascii( const string& base, const string& name, SGVec3d bs_center = d.getCenter(); double bs_radius = d.getRadius(); - // write group headers - fprintf(fp, "\n"); - fprintf(fp, "# usemtl %s\n", material.c_str()); - fprintf(fp, "# bs %.4f %.4f %.4f %.2f\n", - bs_center.x(), bs_center.y(), bs_center.z(), bs_radius); + // write group headers + fprintf(fp, "\n"); + fprintf(fp, "# usemtl %s\n", material.c_str()); + fprintf(fp, "# bs %.4f %.4f %.4f %.2f\n", + bs_center.x(), bs_center.y(), bs_center.z(), bs_radius); - // write groups - for ( i = start; i < end; ++i ) { - fprintf(fp, "ts"); - for ( j = 0; j < (int)strips_v[i].size(); ++j ) { - fprintf(fp, " %d/%d", strips_v[i][j], strips_tc[i][j] ); - } - fprintf(fp, "\n"); - } - - start = end; - end = start + 1; - } + // write groups + for ( i = start; i < end; ++i ) { + fprintf(fp, "ts"); + for ( j = 0; j < (int)strips_v[i].size(); ++j ) { + fprintf(fp, " %d/%d", strips_v[i][j], strips_tc[i][j] ); + } + fprintf(fp, "\n"); + } + + start = end; + end = start + 1; + } } // close the file @@ -1170,3 +1001,21 @@ bool SGBinObject::write_ascii( const string& base, const string& name, return true; } + +void SGBinObject::read_properties(gzFile fp, int nproperties) +{ + sgSimpleBuffer buf; + uint32_t nbytes; + + // read properties + for ( int j = 0; j < nproperties; ++j ) { + char prop_type; + sgReadChar( fp, &prop_type ); + sgReadUInt( fp, &nbytes ); + // cout << "property size = " << nbytes << endl; + if ( nbytes > buf.get_size() ) { buf.resize( nbytes ); } + char *ptr = buf.get_ptr(); + sgReadBytes( fp, nbytes, ptr ); + } +} + diff --git a/simgear/io/sg_binobj.hxx b/simgear/io/sg_binobj.hxx index 7f672640..d594113d 100644 --- a/simgear/io/sg_binobj.hxx +++ b/simgear/io/sg_binobj.hxx @@ -27,29 +27,24 @@ #ifndef _SG_BINOBJ_HXX #define _SG_BINOBJ_HXX +#include // for gzFile #include #include #include -#include +#include -#include -#include - -#include +#include #include - - /** STL Structure used to store object information */ typedef std::vector < int_list > group_list; typedef group_list::iterator group_list_iterator; typedef group_list::const_iterator const_group_list_iterator; - -/** Magic Number for our file format */ -#define SG_FILE_MAGIC_NUMBER ( ('S'<<24) + ('G'<<16) + SG_BINOBJ_VERSION ) - +// forward decls +class SGBucket; +class SGPath; /** * A class to manipulate the simgear 3d object format. @@ -85,6 +80,7 @@ typedef group_list::const_iterator const_group_list_iterator; * - vertex: FLOAT, FLOAT, FLOAT */ class SGBinObject { +private: unsigned short version; SGVec3d gbs_center; @@ -119,6 +115,24 @@ class SGBinObject { group_list fans_tc; // fans texture coordinate index string_list fan_materials; // fans materials + void read_properties(gzFile fp, int nproperties); + + void read_object( gzFile fp, + int obj_type, + int nproperties, + int nelements, + group_list& vertices, + group_list& normals, + group_list& colors, + group_list& texCoords, + string_list& materials); + + void write_header(gzFile fp, int type, int nProps, int nElements); + void write_objects(gzFile fp, int type, const group_list& verts, + const group_list& normals, const group_list& colors, + const group_list& texCoords, const string_list& materials); + + unsigned int count_objects(const string_list& materials); public: inline unsigned short get_version() const { return version; } @@ -207,6 +221,9 @@ public: */ bool write_bin( const std::string& base, const std::string& name, const SGBucket& b ); + + bool write_bin_file(const SGPath& file); + /** * Write out the structures to an ASCII file. We assume that the * groups come to us sorted by material property. If not, things