]> git.mxchange.org Git - simgear.git/commitdiff
Additions to the binary file format to make it *much* more flexible.
authorcurt <curt>
Sun, 10 Mar 2002 22:49:01 +0000 (22:49 +0000)
committercurt <curt>
Sun, 10 Mar 2002 22:49:01 +0000 (22:49 +0000)
For each major primative type: points, triangles, fans, and strips, you
can specify an index list of vertices, normals, colors, and texture
coordinates.  You can skip any of these you like to save on space.

Note that the work for this has only been done in the file format reader
and writer.  The FlightGear loader for instance still needs to have
support for this built in.

This is is one more small step towards runway lighting.

simgear/io/lowtest.cxx
simgear/io/sg_binobj.cxx
simgear/io/sg_binobj.hxx

index 843c13f9756d9d40a513dcd40176a58c8c29fa34..8562035734f88ce586d7c23200ad89ef13a49a65 100644 (file)
@@ -23,6 +23,8 @@ int main() {
     }
     cout << "endian" << endl;
 
+    cout << "sizeof(short) = " << sizeof(short) << endl;
+
     short s = 1111;
     cout << "short s = " << s << endl;
     sgEndianSwap((unsigned short *)&s);
index 4e7d2b266689e85537dd907a97c64bb4002b28ba..01141d4528c7cfd29b524dc62a62ae9796ccf783 100644 (file)
@@ -58,11 +58,20 @@ enum {
     SG_TRIANGLE_FACES = 10,
     SG_TRIANGLE_STRIPS = 11,
     SG_TRIANGLE_FANS = 12
-} tgObjectTypes;
+} sgObjectTypes;
 
 enum {
-    SG_MATERIAL = 0
-} tgPropertyTypes;
+    SG_IDX_VERTICES =  0x0001,
+    SG_IDX_NORMALS =   0x0010,
+    SG_IDX_COLORS =    0x0100,
+    SG_IDX_TEXCOORDS = 0x1000
+} sgIndexTypes;
+
+enum {
+    SG_MATERIAL = 0,
+    SG_INDEX_TYPES = 1
+} sgPropertyTypes;
+
 
 
 class sgSimpleBuffer {
@@ -148,11 +157,130 @@ double sgCalcBoundingRadius( Point3D center, point_list& wgs84_nodes ) {
 }
 
 
+
+// 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 )
+{
+    unsigned int nbytes;
+    char idx_mask;
+    int idx_size;
+    bool do_vertices, do_normals, do_colors, do_texcoords;
+    int j, k, idx;
+    static 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;
+    } 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;
+    }
+
+    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];
+           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;
+           }
+       }
+    }
+
+    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(short));
+       short *sptr = (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( (unsigned short *)&(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 );
+    }
+}
+
+
 // read a binary file and populate the provided structures.
 bool SGBinObject::read_bin( const string& file ) {
     Point3D p;
     int i, j, k;
-    char material[256];
     unsigned int nbytes;
     static sgSimpleBuffer buf( 32768 );  // 32 Kb
 
@@ -165,17 +293,26 @@ bool SGBinObject::read_bin( const string& file ) {
     texcoords.clear();
 
     pts_v.clear();
+    pts_n.clear();
+    pts_c.clear();
+    pts_tc.clear();
     pt_materials.clear();
 
     tris_v.clear();
+    tris_n.clear();
+    tris_c.clear();
     tris_tc.clear();
     tri_materials.clear();
 
     strips_v.clear();
+    strips_n.clear();
+    strips_c.clear();
     strips_tc.clear();
     strip_materials.clear();
 
     fans_v.clear();
+    fans_n.clear();
+    fans_c.clear();
     fans_tc.clear();
     fan_materials.clear();
    
@@ -417,92 +554,27 @@ bool SGBinObject::read_bin( const string& file ) {
                }
            }
        } else if ( obj_type == SG_POINTS ) {
-           // read points 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 );
-               if ( prop_type == SG_MATERIAL ) {
-                   strncpy( material, ptr, nbytes );
-                   material[nbytes] = '\0';
-                   // cout << "material type = " << material << endl;
-               }
-           }
-
            // read point 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(short);
-               short *sptr = (short *)ptr;
-               int_list vs;
-               vs.clear();
-               for ( k = 0; k < count; ++k ) {
-                   if ( sgIsBigEndian() ) {
-                       sgEndianSwap( (unsigned short *)&(sptr[0]) );
-                   }
-                   vs.push_back( sptr[0] );
-                   // cout << sptr[0] << " ";
-                   ++sptr;
-               }
-               // cout << endl;
-               pts_v.push_back( vs );
-               pt_materials.push_back( material );
-           }
+           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
-           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;
-               }
-           }
-
-           // read triangle face 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(short) * 2);
-               short *sptr = (short *)ptr;
-               int_list vs, tcs;
-               vs.clear(); tcs.clear();
-               for ( k = 0; k < count; ++k ) {
-                   if ( sgIsBigEndian() ) {
-                       sgEndianSwap( (unsigned short *)&(sptr[0]) );
-                       sgEndianSwap( (unsigned short *)&(sptr[1]) );
-                   }
-                   vs.push_back( sptr[0] );
-                   tcs.push_back( sptr[1] );
-                   // cout << sptr[0] << "/" << sptr[1] << " ";
-                   sptr += 2;
-               }
-               // cout << endl;
-               tris_v.push_back( vs );
-               tris_tc.push_back( tcs );
-               tri_materials.push_back( material );
-           }
+           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 );
+#if 0
+           // default values
+           idx_size = 2;
+           idx_mask = (char)(SG_IDX_VERTICES | SG_IDX_TEXCOORDS);
+           do_vertices = true;
+           do_normals = false;
+           do_colors = false;
+           do_texcoords = true;
+
            for ( j = 0; j < nproperties; ++j ) {
                char prop_type;
                sgReadChar( fp, &prop_type );
@@ -538,15 +610,27 @@ bool SGBinObject::read_bin( const string& file ) {
                    vs.push_back( sptr[0] );
                    tcs.push_back( sptr[1] );
                    // cout << sptr[0] << "/" << sptr[1] << " ";
-                   sptr += 2;
+                   sptr += idx_size;
                }
                // cout << endl;
                strips_v.push_back( vs );
                strips_tc.push_back( tcs );
                strip_materials.push_back( material );
            }
+#endif
        } 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 );
+#if 0
+           // default values
+           idx_size = 2;
+           idx_mask = (char)(SG_IDX_VERTICES | SG_IDX_TEXCOORDS);
+           do_vertices = true;
+           do_normals = false;
+           do_colors = false;
+           do_texcoords = true;
+
            for ( j = 0; j < nproperties; ++j ) {
                char prop_type;
                sgReadChar( fp, &prop_type );
@@ -582,13 +666,14 @@ bool SGBinObject::read_bin( const string& file ) {
                    vs.push_back( sptr[0] );
                    tcs.push_back( sptr[1] );
                    // cout << sptr[0] << "/" << sptr[1] << " ";
-                   sptr += 2;
+                   sptr += idx_size;
                }
                // cout << endl;
                fans_v.push_back( vs );
                fans_tc.push_back( tcs );
                fan_materials.push_back( material );
            }
+#endif
        } else {
            // unknown object type, just skip
 
@@ -638,6 +723,8 @@ bool SGBinObject::write_bin( const string& base, const string& name,
     sgVec3 pt;
     sgVec4 color;
     int i, j;
+    char idx_mask;
+    int idx_size;
 
     string dir = base + "/" + b.gen_base_path();
     string command = "mkdir -p " + dir;
@@ -826,19 +913,40 @@ bool SGBinObject::write_bin( const string& base, const string& name,
 
            // write group headers
            sgWriteChar( fp, (char)SG_POINTS );          // type
-           sgWriteShort( fp, 1 );                       // nproperties
+           sgWriteShort( fp, 2 );                       // nproperties
            sgWriteShort( 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() * sizeof(short) );
+               sgWriteUInt( fp, pts_v[i].size() * idx_size * sizeof(short) );
                for ( j = 0; j < (int)pts_v[i].size(); ++j ) {
-                   sgWriteShort( fp, (short)pts_v[i][j] );
+                   if ( pts_v.size() ) { 
+                       sgWriteShort( fp, (short)pts_v[i][j] );
+                   }
+                   if ( pts_n.size() ) { 
+                       sgWriteShort( fp, (short)pts_n[i][j] );
+                   }
+                   if ( pts_c.size() ) { 
+                       sgWriteShort( fp, (short)pts_c[i][j] );
+                   }
+                   if ( pts_tc.size() ) { 
+                       sgWriteShort( fp, (short)pts_tc[i][j] );
+                   }
                }
            }
            
@@ -865,20 +973,41 @@ bool SGBinObject::write_bin( const string& base, const string& name,
 
            // write group headers
            sgWriteChar( fp, (char)SG_TRIANGLE_FACES ); // type
-           sgWriteShort( fp, 1 );                      // nproperties
+           sgWriteShort( fp, 2 );                      // nproperties
            sgWriteShort( fp, 1 );                      // nelements
 
            sgWriteChar( fp, (char)SG_MATERIAL );       // property
            sgWriteUInt( fp, material.length() );        // nbytes
            sgWriteBytes( fp, material.length(), material.c_str() );
 
-           sgWriteUInt( fp, (end - start) * 3 * 2 * sizeof(short) ); // nbytes
+           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(short) );
 
            // write group
            for ( i = start; i < end; ++i ) {
                for ( j = 0; j < 3; ++j ) {
-                   sgWriteShort( fp, (short)tris_v[i][j] );
-                   sgWriteShort( fp, (short)tris_tc[i][j] );
+                   if ( tris_v.size() ) {
+                       sgWriteShort( fp, (short)tris_v[i][j] );
+                   }
+                   if ( tris_n.size() ) {
+                       sgWriteShort( fp, (short)tris_n[i][j] );
+                   }
+                   if ( tris_c.size() ) {
+                       sgWriteShort( fp, (short)tris_c[i][j] );
+                   }
+                   if ( tris_tc.size() ) {
+                       sgWriteShort( fp, (short)tris_tc[i][j] );
+                   }
                }
            }
 
@@ -905,20 +1034,40 @@ bool SGBinObject::write_bin( const string& base, const string& name,
 
            // write group headers
            sgWriteChar( fp, (char)SG_TRIANGLE_STRIPS ); // type
-           sgWriteShort( fp, 1 );                       // nproperties
+           sgWriteShort( fp, 2 );                       // nproperties
            sgWriteShort( 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() * 2 * sizeof(short) );
+               sgWriteUInt( fp, strips_v[i].size() * idx_size * sizeof(short));
                for ( j = 0; j < (int)strips_v[i].size(); ++j ) {
-                   sgWriteShort( fp, (short)strips_v[i][j] );
-                   sgWriteShort( fp, (short)strips_tc[i][j] );
+                   if ( strips_v.size() ) { 
+                       sgWriteShort( fp, (short)strips_v[i][j] );
+                   }
+                   if ( strips_n.size() ) { 
+                       sgWriteShort( fp, (short)strips_n[i][j] );
+                   }
+                   if ( strips_c.size() ) { 
+                       sgWriteShort( fp, (short)strips_c[i][j] );
+                   }
+                   if ( strips_tc.size() ) { 
+                       sgWriteShort( fp, (short)strips_tc[i][j] );
+                   }
                }
            }
            
@@ -945,20 +1094,40 @@ bool SGBinObject::write_bin( const string& base, const string& name,
 
            // write group headers
            sgWriteChar( fp, (char)SG_TRIANGLE_FANS );   // type
-           sgWriteShort( fp, 1 );                       // nproperties
+           sgWriteShort( fp, 2 );                       // nproperties
            sgWriteShort( 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() * 2 * sizeof(short) );
+               sgWriteUInt( fp, fans_v[i].size() * idx_size * sizeof(short) );
                for ( j = 0; j < (int)fans_v[i].size(); ++j ) {
-                   sgWriteShort( fp, (short)fans_v[i][j] );
-                   sgWriteShort( fp, (short)fans_tc[i][j] );
+                   if ( fans_v.size() ) {
+                       sgWriteShort( fp, (short)fans_v[i][j] );
+                   }
+                   if ( fans_n.size() ) {
+                       sgWriteShort( fp, (short)fans_n[i][j] );
+                   }
+                   if ( fans_c.size() ) {
+                       sgWriteShort( fp, (short)fans_c[i][j] );
+                   }
+                   if ( fans_tc.size() ) {
+                       sgWriteShort( fp, (short)fans_tc[i][j] );
+                   }
                }
            }
            
index b8f181ad6d9efe0ea982963d626b41b3984dcc1e..edd80f9c93c850283f477780c4c5660462aae768 100644 (file)
@@ -91,21 +91,35 @@ class SGBinObject {
 
     Point3D gbs_center;
     float gbs_radius;
-    point_list wgs84_nodes;
-    point_list colors;
-    point_list normals;
-    point_list texcoords;
-    group_list pts_v;
-    string_list pt_materials;
-    group_list tris_v;
-    group_list tris_tc; 
-    string_list tri_materials;
-    group_list strips_v;
-    group_list strips_tc; 
-    string_list strip_materials;
-    group_list fans_v;
-    group_list fans_tc;
-    string_list fan_materials;
+
+    point_list wgs84_nodes;    // vertex list
+    point_list colors;         // color list
+    point_list normals;                // normal list
+    point_list texcoords;      // texture coordinate list
+
+    group_list pts_v;          // points vertex index
+    group_list pts_n;          // points normal index
+    group_list pts_c;          // points color index
+    group_list pts_tc;         // points texture coordinate index
+    string_list pt_materials;  // points materials
+
+    group_list tris_v;         // triangles vertex index
+    group_list tris_n;         // triangles normal index
+    group_list tris_c;         // triangles color index
+    group_list tris_tc;                // triangles texture coordinate index
+    string_list tri_materials; // triangles materials
+
+    group_list strips_v;       // tristrips vertex index
+    group_list strips_n;       // tristrips normal index
+    group_list strips_c;       // tristrips color index
+    group_list strips_tc;      // tristrips texture coordinate index
+    string_list strip_materials;// tristrips materials
+
+    group_list fans_v;         // fans vertex index
+    group_list fans_n;         // fans normal index
+    group_list fans_c;         // fans color index
+    group_list fans_tc;                // fans texture coordinate index
+    string_list fan_materials; // fans materials
 
 public:
 
@@ -131,11 +145,21 @@ public:
 
     inline group_list get_pts_v() const { return pts_v; }
     inline void set_pts_v( group_list g ) { pts_v = g; }
+    inline group_list get_pts_n() const { return pts_n; }
+    inline void set_pts_n( group_list g ) { pts_n = g; }
+    inline group_list get_pts_c() const { return pts_c; }
+    inline void set_pts_c( group_list g ) { pts_c = g; }
+    inline group_list get_pts_tc() const { return pts_tc; }
+    inline void set_pts_tc( group_list g ) { pts_tc = g; }
     inline string_list get_pt_materials() const { return pt_materials; }
     inline void set_pt_materials( string_list s ) { pt_materials = s; }
 
     inline group_list get_tris_v() const { return tris_v; }
     inline void set_tris_v( group_list g ) { tris_v = g; }
+    inline group_list get_tris_n() const { return tris_n; }
+    inline void set_tris_n( group_list g ) { tris_n = g; }
+    inline group_list get_tris_c() const { return tris_c; }
+    inline void set_tris_c( group_list g ) { tris_c = g; }
     inline group_list get_tris_tc() const { return tris_tc; }
     inline void set_tris_tc( group_list g ) { tris_tc = g; }
     inline string_list get_tri_materials() const { return tri_materials; }
@@ -143,6 +167,10 @@ public:
     
     inline group_list get_strips_v() const { return strips_v; }
     inline void set_strips_v( group_list g ) { strips_v = g; }
+    inline group_list get_strips_n() const { return strips_n; }
+    inline void set_strips_n( group_list g ) { strips_n = g; }
+    inline group_list get_strips_c() const { return strips_c; }
+    inline void set_strips_c( group_list g ) { strips_c = g; }
     inline group_list get_strips_tc() const { return strips_tc; }
     inline void set_strips_tc( group_list g ) { strips_tc = g; }
     inline string_list get_strip_materials() const { return strip_materials; }
@@ -150,6 +178,10 @@ public:
     
     inline group_list get_fans_v() const { return fans_v; }
     inline void set_fans_v( group_list g ) { fans_v = g; }
+    inline group_list get_fans_n() const { return fans_n; }
+    inline void set_fans_n( group_list g ) { fans_n = g; }
+    inline group_list get_fans_c() const { return fans_c; }
+    inline void set_fans_c( group_list g ) { fans_c = g; }
     inline group_list get_fans_tc() const { return fans_tc; }
     inline void set_fans_tc( group_list g ) { fans_tc = g; }
     inline string_list get_fan_materials() const { return fan_materials; }