X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=simgear%2Fio%2Fsg_binobj.cxx;h=1c604a28b39fb7e2555324050b3197c026071cae;hb=8d93206dd33ed0079af6670a0ecd41a3b203d9a0;hp=3deaacc19972348f51d884b90ee6ab1ce663e383;hpb=f7a87789ab0a81cf95aae386ff5c1dd5001f09fe;p=simgear.git diff --git a/simgear/io/sg_binobj.cxx b/simgear/io/sg_binobj.cxx index 3deaacc1..1c604a28 100644 --- a/simgear/io/sg_binobj.cxx +++ b/simgear/io/sg_binobj.cxx @@ -43,6 +43,7 @@ #include #include #include +#include #include "lowlevel.hxx" #include "sg_binobj.hxx" @@ -57,9 +58,11 @@ enum sgObjectTypes { SG_BOUNDING_SPHERE = 0, SG_VERTEX_LIST = 1, - SG_COLOR_LIST = 4, SG_NORMAL_LIST = 2, SG_TEXCOORD_LIST = 3, + SG_COLOR_LIST = 4, + SG_VA_FLOAT_LIST = 5, + SG_VA_INTEGER_LIST = 6, SG_POINTS = 9, @@ -69,15 +72,32 @@ enum sgObjectTypes { }; enum sgIndexTypes { - SG_IDX_VERTICES = 0x01, - SG_IDX_NORMALS = 0x02, - SG_IDX_COLORS = 0x04, - SG_IDX_TEXCOORDS = 0x08 + SG_IDX_VERTICES = 0x01, + SG_IDX_NORMALS = 0x02, + SG_IDX_COLORS = 0x04, + SG_IDX_TEXCOORDS_0 = 0x08, + SG_IDX_TEXCOORDS_1 = 0x10, + SG_IDX_TEXCOORDS_2 = 0x20, + SG_IDX_TEXCOORDS_3 = 0x40, +}; + +enum sgVertexAttributeTypes { + // vertex attributes + SG_VA_INTEGER_0 = 0x00000001, + SG_VA_INTEGER_1 = 0x00000002, + SG_VA_INTEGER_2 = 0x00000004, + SG_VA_INTEGER_3 = 0x00000008, + + SG_VA_FLOAT_0 = 0x00000100, + SG_VA_FLOAT_1 = 0x00000200, + SG_VA_FLOAT_2 = 0x00000400, + SG_VA_FLOAT_3 = 0x00000800, }; enum sgPropertyTypes { SG_MATERIAL = 0, - SG_INDEX_TYPES = 1 + SG_INDEX_TYPES = 1, + SG_VERT_ATTRIBS = 2 }; @@ -129,6 +149,17 @@ public: } } + float readInt() + { + unsigned int* p = reinterpret_cast(ptr + offset); + if ( sgIsBigEndian() ) { + sgEndianSwap((uint32_t *) p); + } + + offset += sizeof(unsigned int); + return *p; + } + SGVec3d readVec3d() { double* p = reinterpret_cast(ptr + offset); @@ -201,15 +232,19 @@ template static void read_indices(char* buffer, size_t bytes, int indexMask, + int vaMask, int_list& vertices, int_list& normals, int_list& colors, - int_list& texCoords) + tci_list& texCoords, + vai_list& vas + ) { - const int indexSize = sizeof(T) * std::bitset<32>(indexMask).count(); - const int count = bytes / indexSize; + const int indexSize = sizeof(T) * std::bitset<32>((int)indexMask).count(); + const int vaSize = sizeof(T) * std::bitset<32>((int)vaMask).count(); + const int count = bytes / (indexSize + vaSize); -// fix endian-ness of the whole lot, if required + // fix endian-ness of the whole lot, if required if (sgIsBigEndian()) { int indices = bytes / sizeof(T); T* src = reinterpret_cast(buffer); @@ -223,8 +258,31 @@ static void read_indices(char* buffer, if (indexMask & SG_IDX_VERTICES) vertices.push_back(*src++); if (indexMask & SG_IDX_NORMALS) normals.push_back(*src++); if (indexMask & SG_IDX_COLORS) colors.push_back(*src++); - if (indexMask & SG_IDX_TEXCOORDS) texCoords.push_back(*src++); + if (indexMask & SG_IDX_TEXCOORDS_0) texCoords[0].push_back(*src++); + if (indexMask & SG_IDX_TEXCOORDS_1) texCoords[1].push_back(*src++); + if (indexMask & SG_IDX_TEXCOORDS_2) texCoords[2].push_back(*src++); + if (indexMask & SG_IDX_TEXCOORDS_3) texCoords[3].push_back(*src++); + + if ( vaMask ) { + if (vaMask & SG_VA_INTEGER_0) vas[0].push_back(*src++); + if (vaMask & SG_VA_INTEGER_1) vas[1].push_back(*src++); + if (vaMask & SG_VA_INTEGER_2) vas[2].push_back(*src++); + if (vaMask & SG_VA_INTEGER_3) vas[3].push_back(*src++); + if (vaMask & SG_VA_FLOAT_0) vas[4].push_back(*src++); + if (vaMask & SG_VA_FLOAT_1) vas[5].push_back(*src++); + if (vaMask & SG_VA_FLOAT_2) vas[6].push_back(*src++); + if (vaMask & SG_VA_FLOAT_3) vas[7].push_back(*src++); + } } // of elements in the index + + // WS2.0 fix : toss zero area triangles + if ( ( count == 3 ) && (indexMask & SG_IDX_VERTICES) ) { + if ( (vertices[0] == vertices[1]) || + (vertices[1] == vertices[2]) || + (vertices[2] == vertices[0]) ) { + vertices.clear(); + } + } } template @@ -248,15 +306,19 @@ void write_indice(gzFile fp, uint32_t value) template -void write_indices(gzFile fp, unsigned char indexMask, +void write_indices(gzFile fp, + unsigned char indexMask, + unsigned int vaMask, const int_list& vertices, const int_list& normals, const int_list& colors, - const int_list& texCoords) + const tci_list& texCoords, + const vai_list& vas ) { unsigned int count = vertices.size(); - const int indexSize = sizeof(T) * std::bitset<32>(indexMask).count(); - sgWriteUInt(fp, indexSize * count); + const int indexSize = sizeof(T) * std::bitset<32>((int)indexMask).count(); + const int vaSize = sizeof(T) * std::bitset<32>((int)vaMask).count(); + sgWriteUInt(fp, (indexSize + vaSize) * count); for (unsigned int i=0; i < count; ++i) { write_indice(fp, static_cast(vertices[i])); @@ -267,8 +329,45 @@ void write_indices(gzFile fp, unsigned char indexMask, if (indexMask & SG_IDX_COLORS) { write_indice(fp, static_cast(colors[i])); } - if (indexMask & SG_IDX_TEXCOORDS) { - write_indice(fp, static_cast(texCoords[i])); + if (indexMask & SG_IDX_TEXCOORDS_0) { + write_indice(fp, static_cast(texCoords[0][i])); + } + if (indexMask & SG_IDX_TEXCOORDS_1) { + write_indice(fp, static_cast(texCoords[1][i])); + } + if (indexMask & SG_IDX_TEXCOORDS_2) { + write_indice(fp, static_cast(texCoords[2][i])); + } + if (indexMask & SG_IDX_TEXCOORDS_3) { + write_indice(fp, static_cast(texCoords[3][i])); + } + + if (vaMask) { + if (vaMask & SG_VA_INTEGER_0) { + write_indice(fp, static_cast(vas[0][i])); + } + if (vaMask & SG_VA_INTEGER_1) { + write_indice(fp, static_cast(vas[1][i])); + } + if (vaMask & SG_VA_INTEGER_2) { + write_indice(fp, static_cast(vas[2][i])); + } + if (vaMask & SG_VA_INTEGER_3) { + write_indice(fp, static_cast(vas[3][i])); + } + + if (vaMask & SG_VA_FLOAT_0) { + write_indice(fp, static_cast(vas[4][i])); + } + if (vaMask & SG_VA_FLOAT_1) { + write_indice(fp, static_cast(vas[5][i])); + } + if (vaMask & SG_VA_FLOAT_2) { + write_indice(fp, static_cast(vas[6][i])); + } + if (vaMask & SG_VA_FLOAT_3) { + write_indice(fp, static_cast(vas[7][i])); + } } } } @@ -280,13 +379,15 @@ void SGBinObject::read_object( gzFile fp, int nproperties, int nelements, group_list& vertices, - group_list& normals, - group_list& colors, - group_list& texCoords, - string_list& materials) + group_list& normals, + group_list& colors, + group_tci_list& texCoords, + group_vai_list& vertexAttribs, + string_list& materials) { - unsigned int nbytes; + unsigned int nbytes; unsigned char idx_mask; + unsigned int vertex_attrib_mask; int j; sgSimpleBuffer buf( 32768 ); // 32 Kb char material[256]; @@ -295,39 +396,65 @@ void SGBinObject::read_object( gzFile fp, if ( obj_type == SG_POINTS ) { idx_mask = SG_IDX_VERTICES; } else { - idx_mask = (char)(SG_IDX_VERTICES | SG_IDX_TEXCOORDS); + idx_mask = (char)(SG_IDX_VERTICES | SG_IDX_TEXCOORDS_0); } - + vertex_attrib_mask = 0; + for ( j = 0; j < nproperties; ++j ) { 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; + + switch( prop_type ) + { + case SG_MATERIAL: + sgReadBytes( fp, nbytes, ptr ); + if (nbytes > 255) { + nbytes = 255; + } + strncpy( material, ptr, nbytes ); + material[nbytes] = '\0'; + break; + + case SG_INDEX_TYPES: + if (nbytes == 1) { + sgReadChar( fp, (char *)&idx_mask ); + } else { + sgReadBytes( fp, nbytes, ptr ); + } + break; + + case SG_VERT_ATTRIBS: + if (nbytes == 4) { + sgReadUInt( fp, &vertex_attrib_mask ); + } else { + sgReadBytes( fp, nbytes, ptr ); + } + break; + + default: + sgReadBytes( fp, nbytes, ptr ); + SG_LOG(SG_IO, SG_ALERT, "Found UNKNOWN property type with nbytes == " << nbytes << " mask is " << (int)idx_mask ); + break; } } if ( sgReadError() ) { - cout << "We detected an error reading object properties" << endl; - return; + throw sg_exception("Error reading object properties"); + } + + size_t indexCount = std::bitset<32>((int)idx_mask).count(); + if (indexCount == 0) { + throw sg_exception("object index mask has no bits set"); } for ( j = 0; j < nelements; ++j ) { sgReadUInt( fp, &nbytes ); if ( sgReadError() ) { - cout << "We detected an error reading element size for :" << j << endl; - return; + throw sg_exception("Error reading element size"); } buf.resize( nbytes ); @@ -335,25 +462,30 @@ void SGBinObject::read_object( gzFile fp, sgReadBytes( fp, nbytes, ptr ); if ( sgReadError() ) { - cout << "We detected an error reading object element:" << j << "bytes="<< nbytes << endl; - return; + throw sg_exception("Error reading element bytes"); } int_list vs; int_list ns; int_list cs; - int_list tcs; + tci_list tcs; + vai_list vas; + if (version >= 10) { - read_indices(ptr, nbytes, idx_mask, vs, ns, cs, tcs); + read_indices(ptr, nbytes, idx_mask, vertex_attrib_mask, vs, ns, cs, tcs, vas ); } else { - read_indices(ptr, nbytes, idx_mask, vs, ns, cs, tcs); + read_indices(ptr, nbytes, idx_mask, vertex_attrib_mask, vs, ns, cs, tcs, vas ); } - vertices.push_back( vs ); - normals.push_back( ns ); - colors.push_back( cs ); - texCoords.push_back( tcs ); - materials.push_back( material ); + // Fix for WS2.0 - ignore zero area triangles + if ( !vs.empty() ) { + vertices.push_back( vs ); + normals.push_back( ns ); + colors.push_back( cs ); + texCoords.push_back( tcs ); + vertexAttribs.push_back( vas ); + materials.push_back( material ); + } } // of element iteration } @@ -377,25 +509,29 @@ bool SGBinObject::read_bin( const string& file ) { pts_v.clear(); pts_n.clear(); pts_c.clear(); - pts_tc.clear(); + pts_tcs.clear(); + pts_vas.clear(); pt_materials.clear(); tris_v.clear(); tris_n.clear(); tris_c.clear(); - tris_tc.clear(); + tris_tcs.clear(); + tris_vas.clear(); tri_materials.clear(); strips_v.clear(); strips_n.clear(); strips_c.clear(); - strips_tc.clear(); + strips_tcs.clear(); + strips_vas.clear(); strip_materials.clear(); fans_v.clear(); fans_n.clear(); fans_c.clear(); - fans_tc.clear(); + fans_tcs.clear(); + fans_vas.clear(); fan_materials.clear(); gzFile fp; @@ -405,7 +541,7 @@ bool SGBinObject::read_bin( const string& file ) { SG_LOG( SG_EVENT, SG_ALERT, "ERROR: opening " << file << " or " << filegz << " for reading!"); - return false; + throw sg_io_exception("Error opening for reading (and .gz)", sg_location(file)); } } @@ -416,16 +552,13 @@ bool SGBinObject::read_bin( const string& file ) { 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; } else { // close the file before we return gzclose(fp); - SG_LOG( SG_EVENT, SG_ALERT, - "ERROR: " << file << "has bad header"); - return false; + throw sg_io_exception("Bad BTG magic/version", sg_location(file)); } // read creation time @@ -459,11 +592,10 @@ bool SGBinObject::read_bin( const string& file ) { nobjects = v; } - //cout << "Total objects to read = " << nobjects << endl; + SG_LOG(SG_IO, SG_DEBUG, "SGBinObject::read_bin Total objects to read = " << nobjects); if ( sgReadError() ) { - cout << "Error while reading header of file " << file << "(.gz)" << endl; - return false; + throw sg_io_exception("Error reading BTG file header", sg_location(file)); } // read in objects @@ -489,9 +621,10 @@ bool SGBinObject::read_bin( const string& file ) { nelements = v; } - //cout << "object " << i << " = " << (int)obj_type << " props = " - // << nproperties << " elements = " << nelements << endl; - + SG_LOG(SG_IO, SG_DEBUG, "SGBinObject::read_bin object " << i << + " = " << (int)obj_type << " props = " << nproperties << + " elements = " << nelements); + if ( obj_type == SG_BOUNDING_SPHERE ) { // read bounding sphere properties read_properties( fp, nproperties ); @@ -521,7 +654,7 @@ bool SGBinObject::read_bin( const string& file ) { wgs84_nodes.reserve( count ); for ( k = 0; k < count; ++k ) { SGVec3f v = buf.readVec3f(); - // extend from float to double, hmmm + // extend from float to double, hmmm wgs84_nodes.push_back( SGVec3d(v[0], v[1], v[2]) ); } } @@ -581,23 +714,60 @@ bool SGBinObject::read_bin( const string& file ) { texcoords.push_back( buf.readVec2f() ); } } + } else if ( obj_type == SG_VA_FLOAT_LIST ) { + // read vertex attribute (float) properties + read_properties( fp, nproperties ); + + // read vertex attribute 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)); + va_flt.reserve(count); + for ( k = 0; k < count; ++k ) { + va_flt.push_back( buf.readFloat() ); + } + } + } else if ( obj_type == SG_VA_INTEGER_LIST ) { + // read vertex attribute (integer) properties + read_properties( fp, nproperties ); + + // read vertex attribute 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(unsigned int)); + va_int.reserve(count); + for ( k = 0; k < count; ++k ) { + va_int.push_back( buf.readInt() ); + } + } } 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 ); + pts_v, pts_n, pts_c, pts_tcs, + pts_vas, 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 ); + tris_v, tris_n, tris_c, tris_tcs, + tris_vas, 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 ); + strips_v, strips_n, strips_c, strips_tcs, + strips_vas, 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 ); + fans_v, fans_n, fans_c, fans_tcs, + fans_vas, fan_materials ); } else { // unknown object type, just skip read_properties( fp, nproperties ); @@ -613,19 +783,13 @@ bool SGBinObject::read_bin( const string& file ) { } if ( sgReadError() ) { - cout << "Error while reading object:" << i << " in file " << file << "(.gz)" << endl; - return false; + throw sg_io_exception("Error while reading object", sg_location(file, i)); } } // close the file gzclose(fp); - if ( sgReadError() ) { - cout << "Error while reading file " << file << "(.gz)" << endl; - return false; - } - return true; } @@ -658,52 +822,95 @@ unsigned int SGBinObject::count_objects(const string_list& materials) 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) +void SGBinObject::write_objects(gzFile fp, int type, + const group_list& verts, + const group_list& normals, + const group_list& colors, + const group_tci_list& texCoords, + const group_vai_list& vertexAttribs, + const string_list& materials) { if (verts.empty()) { return; } - + unsigned int start = 0, end = 1; string m; int_list emptyList; while (start < materials.size()) { m = materials[start]; - // find range of objects with identical material, write out as a single object + // find range of objects with identical material, write out as a single object for (end = start+1; (end < materials.size()) && (m == materials[end]); ++end) {} + // calc the number of elements const int count = end - start; - write_header(fp, type, 2, count); + + // calc the number of properties + unsigned int va_mask = 0; + unsigned int va_count = vertexAttribs.size(); + for ( unsigned int va=0; va 0 ) { + if ( ! tris_v.empty() ) { fprintf(fp, "# triangle groups\n"); int start = 0; @@ -924,7 +1158,7 @@ bool SGBinObject::write_ascii( const string& base, const string& name, } // cout << "group = " << start << " to " << end - 1 << endl; - SGSphered d; + SGSphered d( SGVec3d(0.0, 0.0, 0.0), -1.0 ); for ( i = start; i < end; ++i ) { for ( j = 0; j < (int)tris_v[i].size(); ++j ) { d.expandBy(wgs84_nodes[ tris_v[i][j] ]); @@ -944,7 +1178,7 @@ bool SGBinObject::write_ascii( const string& base, const string& name, 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, " %d/%d", tris_v[i][j], tris_tcs[i][0][j] ); } fprintf(fp, "\n"); } @@ -955,7 +1189,7 @@ bool SGBinObject::write_ascii( const string& base, const string& name, } // dump triangle groups - if ( strips_v.size() > 0 ) { + if ( ! strips_v.empty() ) { fprintf(fp, "# triangle strips\n"); int start = 0; @@ -973,7 +1207,7 @@ bool SGBinObject::write_ascii( const string& base, const string& name, // cout << "group = " << start << " to " << end - 1 << endl; - SGSphered d; + SGSphered d( SGVec3d(0.0, 0.0, 0.0), -1.0 ); for ( i = start; i < end; ++i ) { for ( j = 0; j < (int)tris_v[i].size(); ++j ) { d.expandBy(wgs84_nodes[ tris_v[i][j] ]); @@ -993,7 +1227,7 @@ bool SGBinObject::write_ascii( const string& base, const string& name, 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, " %d/%d", strips_v[i][j], strips_tcs[i][0][j] ); } fprintf(fp, "\n"); } @@ -1033,3 +1267,27 @@ void SGBinObject::read_properties(gzFile fp, int nproperties) } } +bool SGBinObject::add_point( const SGBinObjectPoint& pt ) +{ + // add the point info + pt_materials.push_back( pt.material ); + + pts_v.push_back( pt.v_list ); + pts_n.push_back( pt.n_list ); + pts_c.push_back( pt.c_list ); + + return true; +} + +bool SGBinObject::add_triangle( const SGBinObjectTriangle& tri ) +{ + // add the triangle info and keep lists aligned + tri_materials.push_back( tri.material ); + tris_v.push_back( tri.v_list ); + tris_n.push_back( tri.n_list ); + tris_c.push_back( tri.c_list ); + tris_tcs.push_back( tri.tc_list ); + tris_vas.push_back( tri.va_list ); + + return true; +} \ No newline at end of file