1 // sg_binobj.cxx -- routines to read and write low level flightgear 3d objects
3 // Written by Curtis Olson, started January 2000.
5 // Copyright (C) 2000 Curtis L. Olson - http://www.flightgear.org/~curt
7 // This program is free software; you can redistribute it and/or modify
8 // it under the terms of the GNU General Public License as published by
9 // the Free Software Foundation; either version 2 of the License, or
10 // (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU General Public License for more details.
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software
19 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26 # include <simgear_config.h>
29 #include <simgear/compiler.h>
30 #include <simgear/debug/logstream.hxx>
39 #include <simgear/bucket/newbucket.hxx>
40 #include <simgear/misc/sg_path.hxx>
41 #include <simgear/math/SGGeometry.hxx>
43 #include "lowlevel.hxx"
44 #include "sg_binobj.hxx"
53 SG_BOUNDING_SPHERE = 0,
62 SG_TRIANGLE_FACES = 10,
63 SG_TRIANGLE_STRIPS = 11,
68 SG_IDX_VERTICES = 0x01,
69 SG_IDX_NORMALS = 0x02,
71 SG_IDX_TEXCOORDS = 0x08
74 enum sgPropertyTypes {
80 class sgSimpleBuffer {
89 inline sgSimpleBuffer( unsigned int s )
95 SG_LOG(SG_EVENT, SG_DEBUG, "Creating a new buffer of size = " << size);
99 inline ~sgSimpleBuffer() {
103 inline unsigned int get_size() const { return size; }
104 inline char *get_ptr() const { return ptr; }
105 inline void resize( unsigned int s ) {
113 SG_LOG(SG_EVENT, SG_DEBUG, "resizing buffer to size = " << size);
114 ptr = new char[size];
119 // read object properties
120 static void read_object( gzFile fp,
124 group_list *vertices,
127 group_list *texcoords,
128 string_list *materials )
131 unsigned char idx_mask;
133 bool do_vertices, do_normals, do_colors, do_texcoords;
135 sgSimpleBuffer buf( 32768 ); // 32 Kb
139 if ( obj_type == SG_POINTS ) {
141 idx_mask = SG_IDX_VERTICES;
145 do_texcoords = false;
148 idx_mask = (char)(SG_IDX_VERTICES | SG_IDX_TEXCOORDS);
155 for ( j = 0; j < nproperties; ++j ) {
157 sgReadChar( fp, &prop_type );
159 sgReadUInt( fp, &nbytes );
160 // cout << "property size = " << nbytes << endl;
161 if ( nbytes > buf.get_size() ) { buf.resize( nbytes ); }
162 char *ptr = buf.get_ptr();
163 sgReadBytes( fp, nbytes, ptr );
164 if ( prop_type == SG_MATERIAL ) {
165 strncpy( material, ptr, nbytes );
166 material[nbytes] = '\0';
167 // cout << "material type = " << material << endl;
168 } else if ( prop_type == SG_INDEX_TYPES ) {
170 // cout << "idx_mask = " << (int)idx_mask << endl;
175 do_texcoords = false;
176 if ( idx_mask & SG_IDX_VERTICES ) {
180 if ( idx_mask & SG_IDX_NORMALS ) {
184 if ( idx_mask & SG_IDX_COLORS ) {
188 if ( idx_mask & SG_IDX_TEXCOORDS ) {
195 for ( j = 0; j < nelements; ++j ) {
196 sgReadUInt( fp, &nbytes );
197 // cout << "element size = " << nbytes << endl;
198 if ( nbytes > buf.get_size() ) { buf.resize( nbytes ); }
199 char *ptr = buf.get_ptr();
200 sgReadBytes( fp, nbytes, ptr );
201 int count = nbytes / (idx_size * sizeof(unsigned short));
202 unsigned short *sptr = (unsigned short *)ptr;
203 int_list vs; vs.clear();
204 int_list ns; ns.clear();
205 int_list cs; cs.clear();
206 int_list tcs; tcs.clear();
207 for ( k = 0; k < count; ++k ) {
208 if ( sgIsBigEndian() ) {
209 for ( idx = 0; idx < idx_size; ++idx ) {
210 sgEndianSwap( (uint16_t *)&(sptr[idx]) );
215 vs.push_back( sptr[idx++] );
218 ns.push_back( sptr[idx++] );
221 cs.push_back( sptr[idx++] );
223 if ( do_texcoords ) {
224 tcs.push_back( sptr[idx++] );
226 // cout << sptr[0] << " ";
230 vertices->push_back( vs );
231 normals->push_back( ns );
232 colors->push_back( cs );
233 texcoords->push_back( tcs );
234 materials->push_back( material );
239 // read a binary file and populate the provided structures.
240 bool SGBinObject::read_bin( const string& file ) {
244 sgSimpleBuffer buf( 32768 ); // 32 Kb
246 // zero out structures
247 gbs_center = SGVec3d(0, 0, 0);
258 pt_materials.clear();
264 tri_materials.clear();
270 strip_materials.clear();
276 fan_materials.clear();
279 if ( (fp = gzopen( file.c_str(), "rb" )) == NULL ) {
280 string filegz = file + ".gz";
281 if ( (fp = gzopen( filegz.c_str(), "rb" )) == NULL ) {
282 SG_LOG( SG_EVENT, SG_ALERT,
283 "ERROR: opening " << file << " or " << filegz << " for reading!");
293 sgReadUInt( fp, &header );
294 if ( ((header & 0xFF000000) >> 24) == 'S' &&
295 ((header & 0x00FF0000) >> 16) == 'G' ) {
296 // cout << "Good header" << endl;
298 version = (header & 0x0000FFFF);
299 // cout << "File version = " << version << endl;
301 // close the file before we return
307 // read creation time
308 unsigned int foo_calendar_time;
309 sgReadUInt( fp, &foo_calendar_time );
312 time_t calendar_time = foo_calendar_time;
313 // The following code has a global effect on the host application
314 // and can screws up the time elsewhere. It should be avoided
315 // unless you need this for debugging in which case you should
316 // disable it again once the debugging task is finished.
318 local_tm = localtime( &calendar_time );
320 strftime( time_str, 256, "%a %b %d %H:%M:%S %Z %Y", local_tm);
321 SG_LOG( SG_EVENT, SG_DEBUG, "File created on " << time_str);
324 // read number of top level objects
325 unsigned short nobjects;
326 if ( version >= 7 ) {
327 sgReadUShort( fp, &nobjects );
330 sgReadShort( fp, &tmp );
333 // cout << "Total objects to read = " << nobjects << endl;
336 for ( i = 0; i < nobjects; ++i ) {
337 // read object header
339 unsigned short nproperties, nelements;
340 sgReadChar( fp, &obj_type );
341 if ( version >= 7 ) {
342 sgReadUShort( fp, &nproperties );
343 sgReadUShort( fp, &nelements );
346 sgReadShort( fp, &tmp );
348 sgReadShort( fp, &tmp );
352 // cout << "object " << i << " = " << (int)obj_type << " props = "
353 // << nproperties << " elements = " << nelements << endl;
355 if ( obj_type == SG_BOUNDING_SPHERE ) {
356 // read bounding sphere properties
357 for ( j = 0; j < nproperties; ++j ) {
359 sgReadChar( fp, &prop_type );
361 sgReadUInt( fp, &nbytes );
362 // cout << "property size = " << nbytes << endl;
363 if ( nbytes > buf.get_size() ) { buf.resize( nbytes ); }
364 char *ptr = buf.get_ptr();
365 sgReadBytes( fp, nbytes, ptr );
368 // read bounding sphere elements
369 for ( j = 0; j < nelements; ++j ) {
370 sgReadUInt( fp, &nbytes );
371 // cout << "element size = " << nbytes << endl;
372 if ( nbytes > buf.get_size() ) { buf.resize( nbytes ); }
373 char *ptr = buf.get_ptr();
374 sgReadBytes( fp, nbytes, ptr );
376 double *dptr = (double *)ptr;
377 if ( sgIsBigEndian() ) {
378 sgEndianSwap( (uint64_t *)&(dptr[0]) );
379 sgEndianSwap( (uint64_t *)&(dptr[1]) );
380 sgEndianSwap( (uint64_t *)&(dptr[2]) );
382 gbs_center = SGVec3d( dptr[0], dptr[1], dptr[2] );
383 // cout << "Center = " << gbs_center << endl;
384 ptr += sizeof(double) * 3;
386 float *fptr = (float *)ptr;
387 if ( sgIsBigEndian() ) {
388 sgEndianSwap( (uint32_t *)fptr );
390 gbs_radius = fptr[0];
391 // cout << "Bounding radius = " << gbs_radius << endl;
393 } else if ( obj_type == SG_VERTEX_LIST ) {
394 // read vertex list properties
395 for ( j = 0; j < nproperties; ++j ) {
397 sgReadChar( fp, &prop_type );
399 sgReadUInt( fp, &nbytes );
400 // cout << "property size = " << nbytes << endl;
401 if ( nbytes > buf.get_size() ) { buf.resize( nbytes ); }
402 char *ptr = buf.get_ptr();
403 sgReadBytes( fp, nbytes, ptr );
406 // read vertex list elements
407 for ( j = 0; j < nelements; ++j ) {
408 sgReadUInt( fp, &nbytes );
409 // cout << "element size = " << nbytes << endl;
410 if ( nbytes > buf.get_size() ) { buf.resize( nbytes ); }
411 char *ptr = buf.get_ptr();
412 sgReadBytes( fp, nbytes, ptr );
413 int count = nbytes / (sizeof(float) * 3);
414 float *fptr = (float *)ptr;
415 wgs84_nodes.reserve( count );
416 for ( k = 0; k < count; ++k ) {
417 if ( sgIsBigEndian() ) {
418 sgEndianSwap( (uint32_t *)&(fptr[0]) );
419 sgEndianSwap( (uint32_t *)&(fptr[1]) );
420 sgEndianSwap( (uint32_t *)&(fptr[2]) );
422 wgs84_nodes.push_back( SGVec3d(fptr[0], fptr[1], fptr[2]) );
426 } else if ( obj_type == SG_COLOR_LIST ) {
427 // read color list properties
428 for ( j = 0; j < nproperties; ++j ) {
430 sgReadChar( fp, &prop_type );
432 sgReadUInt( fp, &nbytes );
433 // cout << "property size = " << nbytes << endl;
434 if ( nbytes > buf.get_size() ) { buf.resize( nbytes ); }
435 char *ptr = buf.get_ptr();
436 sgReadBytes( fp, nbytes, ptr );
439 // read color list elements
440 for ( j = 0; j < nelements; ++j ) {
441 sgReadUInt( fp, &nbytes );
442 // cout << "element size = " << nbytes << endl;
443 if ( nbytes > buf.get_size() ) { buf.resize( nbytes ); }
444 char *ptr = buf.get_ptr();
445 sgReadBytes( fp, nbytes, ptr );
446 int count = nbytes / (sizeof(float) * 4);
447 float *fptr = (float *)ptr;
448 colors.reserve(count);
449 for ( k = 0; k < count; ++k ) {
450 if ( sgIsBigEndian() ) {
451 sgEndianSwap( (uint32_t *)&(fptr[0]) );
452 sgEndianSwap( (uint32_t *)&(fptr[1]) );
453 sgEndianSwap( (uint32_t *)&(fptr[2]) );
454 sgEndianSwap( (uint32_t *)&(fptr[3]) );
456 SGVec4f color( fptr[0], fptr[1], fptr[2], fptr[3] );
457 colors.push_back( color );
461 } else if ( obj_type == SG_NORMAL_LIST ) {
462 // read normal list properties
463 for ( j = 0; j < nproperties; ++j ) {
465 sgReadChar( fp, &prop_type );
467 sgReadUInt( fp, &nbytes );
468 // cout << "property size = " << nbytes << endl;
469 if ( nbytes > buf.get_size() ) { buf.resize( nbytes ); }
470 char *ptr = buf.get_ptr();
471 sgReadBytes( fp, nbytes, ptr );
474 // read normal list elements
475 for ( j = 0; j < nelements; ++j ) {
476 sgReadUInt( fp, &nbytes );
477 // cout << "element size = " << nbytes << endl;
478 if ( nbytes > buf.get_size() ) { buf.resize( nbytes ); }
479 unsigned char *ptr = (unsigned char *)(buf.get_ptr());
480 sgReadBytes( fp, nbytes, ptr );
481 int count = nbytes / 3;
482 normals.reserve( count );
483 for ( k = 0; k < count; ++k ) {
484 SGVec3f normal((ptr[0]) / 127.5 - 1.0,
485 (ptr[1]) / 127.5 - 1.0,
486 (ptr[2]) / 127.5 - 1.0);
488 normals.push_back(normalize(normal));
492 } else if ( obj_type == SG_TEXCOORD_LIST ) {
493 // read texcoord list properties
494 for ( j = 0; j < nproperties; ++j ) {
496 sgReadChar( fp, &prop_type );
498 sgReadUInt( fp, &nbytes );
499 // cout << "property size = " << nbytes << endl;
500 if ( nbytes > buf.get_size() ) { buf.resize( nbytes ); }
501 char *ptr = buf.get_ptr();
502 sgReadBytes( fp, nbytes, ptr );
505 // read texcoord list elements
506 for ( j = 0; j < nelements; ++j ) {
507 sgReadUInt( fp, &nbytes );
508 // cout << "element size = " << nbytes << endl;
509 if ( nbytes > buf.get_size() ) { buf.resize( nbytes ); }
510 char *ptr = buf.get_ptr();
511 sgReadBytes( fp, nbytes, ptr );
512 int count = nbytes / (sizeof(float) * 2);
513 float *fptr = (float *)ptr;
514 texcoords.reserve(count);
515 for ( k = 0; k < count; ++k ) {
516 if ( sgIsBigEndian() ) {
517 sgEndianSwap( (uint32_t *)&(fptr[0]) );
518 sgEndianSwap( (uint32_t *)&(fptr[1]) );
520 texcoords.push_back( SGVec2f( fptr[0], fptr[1] ) );
524 } else if ( obj_type == SG_POINTS ) {
525 // read point elements
526 read_object( fp, SG_POINTS, nproperties, nelements,
527 &pts_v, &pts_n, &pts_c, &pts_tc, &pt_materials );
528 } else if ( obj_type == SG_TRIANGLE_FACES ) {
529 // read triangle face properties
530 read_object( fp, SG_TRIANGLE_FACES, nproperties, nelements,
531 &tris_v, &tris_n, &tris_c, &tris_tc, &tri_materials );
532 } else if ( obj_type == SG_TRIANGLE_STRIPS ) {
533 // read triangle strip properties
534 read_object( fp, SG_TRIANGLE_STRIPS, nproperties, nelements,
535 &strips_v, &strips_n, &strips_c, &strips_tc,
537 } else if ( obj_type == SG_TRIANGLE_FANS ) {
538 // read triangle fan properties
539 read_object( fp, SG_TRIANGLE_FANS, nproperties, nelements,
540 &fans_v, &fans_n, &fans_c, &fans_tc, &fan_materials );
542 // unknown object type, just skip
545 for ( j = 0; j < nproperties; ++j ) {
547 sgReadChar( fp, &prop_type );
549 sgReadUInt( fp, &nbytes );
550 // cout << "property size = " << nbytes << endl;
551 if ( nbytes > buf.get_size() ) { buf.resize( nbytes ); }
552 char *ptr = buf.get_ptr();
553 sgReadBytes( fp, nbytes, ptr );
557 for ( j = 0; j < nelements; ++j ) {
558 sgReadUInt( fp, &nbytes );
559 // cout << "element size = " << nbytes << endl;
560 if ( nbytes > buf.get_size() ) { buf.resize( nbytes ); }
561 char *ptr = buf.get_ptr();
562 sgReadBytes( fp, nbytes, ptr );
570 if ( sgReadError() ) {
571 cout << "We detected an error while reading the file." << endl;
579 // write out the structures to a binary file. We assume that the
580 // groups come to us sorted by material property. If not, things
581 // don't break, but the result won't be as optimal.
582 bool SGBinObject::write_bin( const string& base, const string& name,
586 unsigned char idx_mask;
589 SGPath file = base + "/" + b.gen_base_path() + "/" + name + ".gz";
590 file.create_dir( 0755 );
591 cout << "Output file = " << file.str() << endl;
594 if ( (fp = gzopen( file.c_str(), "wb9" )) == NULL ) {
595 cout << "ERROR: opening " << file.str() << " for writing!" << endl;
601 cout << "points size = " << pts_v.size() << " pt_materials = "
602 << pt_materials.size() << endl;
603 cout << "triangles size = " << tris_v.size() << " tri_materials = "
604 << tri_materials.size() << endl;
605 cout << "strips size = " << strips_v.size() << " strip_materials = "
606 << strip_materials.size() << endl;
607 cout << "fans size = " << fans_v.size() << " fan_materials = "
608 << fan_materials.size() << endl;
610 cout << "nodes = " << wgs84_nodes.size() << endl;
611 cout << "colors = " << colors.size() << endl;
612 cout << "normals = " << normals.size() << endl;
613 cout << "tex coords = " << texcoords.size() << endl;
615 // write header magic
616 sgWriteUInt( fp, SG_FILE_MAGIC_NUMBER );
617 time_t calendar_time = time(NULL);
618 sgWriteLong( fp, (int32_t)calendar_time );
620 // calculate and write number of top level objects
624 unsigned short nobjects = 0;
625 nobjects++; // for gbs
626 nobjects++; // for vertices
627 nobjects++; // for colors
628 nobjects++; // for normals
629 nobjects++; // for texcoords
632 unsigned short npts = 0;
634 while ( start < (int)pt_materials.size() ) {
635 material = pt_materials[start];
636 while ( (end < (int)pt_materials.size()) &&
637 (material == pt_materials[end]) ) {
641 start = end; end = start + 1;
646 unsigned short ntris = 0;
648 while ( start < (int)tri_materials.size() ) {
649 material = tri_materials[start];
650 while ( (end < (int)tri_materials.size()) &&
651 (material == tri_materials[end]) ) {
655 start = end; end = start + 1;
660 unsigned short nstrips = 0;
662 while ( start < (int)strip_materials.size() ) {
663 material = strip_materials[start];
664 while ( (end < (int)strip_materials.size()) &&
665 (material == strip_materials[end]) ) {
669 start = end; end = start + 1;
674 unsigned short nfans = 0;
676 while ( start < (int)fan_materials.size() ) {
677 material = fan_materials[start];
678 while ( (end < (int)fan_materials.size()) &&
679 (material == fan_materials[end]) ) {
683 start = end; end = start + 1;
687 cout << "total top level objects = " << nobjects << endl;
688 sgWriteUShort( fp, nobjects );
690 // write bounding sphere
691 sgWriteChar( fp, (char)SG_BOUNDING_SPHERE ); // type
692 sgWriteUShort( fp, 0 ); // nproperties
693 sgWriteUShort( fp, 1 ); // nelements
695 sgWriteUInt( fp, sizeof(double) * 3 + sizeof(float) ); // nbytes
697 sgdSetVec3( center, gbs_center.x(), gbs_center.y(), gbs_center.z() );
698 sgWritedVec3( fp, center );
699 sgWriteFloat( fp, gbs_radius );
702 sgWriteChar( fp, (char)SG_VERTEX_LIST ); // type
703 sgWriteUShort( fp, 0 ); // nproperties
704 sgWriteUShort( fp, 1 ); // nelements
705 sgWriteUInt( fp, wgs84_nodes.size() * sizeof(float) * 3 ); // nbytes
706 for ( i = 0; i < (int)wgs84_nodes.size(); ++i ) {
707 SGVec3f p = toVec3f(wgs84_nodes[i] - gbs_center);
708 sgWriteVec3( fp, p.data() );
711 // dump vertex color list
712 sgWriteChar( fp, (char)SG_COLOR_LIST ); // type
713 sgWriteUShort( fp, 0 ); // nproperties
714 sgWriteUShort( fp, 1 ); // nelements
715 sgWriteUInt( fp, colors.size() * sizeof(float) * 4 ); // nbytes
716 for ( i = 0; i < (int)colors.size(); ++i ) {
717 sgWriteVec4( fp, colors[i].data() );
720 // dump vertex normal list
721 sgWriteChar( fp, (char)SG_NORMAL_LIST ); // type
722 sgWriteUShort( fp, 0 ); // nproperties
723 sgWriteUShort( fp, 1 ); // nelements
724 sgWriteUInt( fp, normals.size() * 3 ); // nbytes
726 for ( i = 0; i < (int)normals.size(); ++i ) {
727 SGVec3f p = normals[i];
728 normal[0] = (unsigned char)((p.x() + 1.0) * 127.5);
729 normal[1] = (unsigned char)((p.y() + 1.0) * 127.5);
730 normal[2] = (unsigned char)((p.z() + 1.0) * 127.5);
731 sgWriteBytes( fp, 3, normal );
734 // dump texture coordinates
735 sgWriteChar( fp, (char)SG_TEXCOORD_LIST ); // type
736 sgWriteUShort( fp, 0 ); // nproperties
737 sgWriteUShort( fp, 1 ); // nelements
738 sgWriteUInt( fp, texcoords.size() * sizeof(float) * 2 ); // nbytes
739 for ( i = 0; i < (int)texcoords.size(); ++i ) {
740 sgWriteVec2( fp, texcoords[i].data() );
743 // dump point groups if they exist
744 if ( pts_v.size() > 0 ) {
748 while ( start < (int)pt_materials.size() ) {
750 material = pt_materials[start];
751 while ( (end < (int)pt_materials.size()) &&
752 (material == pt_materials[end]) )
754 // cout << "end = " << end << endl;
757 // cout << "group = " << start << " to " << end - 1 << endl;
759 // write group headers
760 sgWriteChar( fp, (char)SG_POINTS ); // type
761 sgWriteUShort( fp, 2 ); // nproperties
762 sgWriteUShort( fp, end - start ); // nelements
764 sgWriteChar( fp, (char)SG_MATERIAL ); // property
765 sgWriteUInt( fp, material.length() ); // nbytes
766 sgWriteBytes( fp, material.length(), material.c_str() );
770 if ( pts_v.size() ) { idx_mask |= SG_IDX_VERTICES; ++idx_size; }
771 if ( pts_n.size() ) { idx_mask |= SG_IDX_NORMALS; ++idx_size; }
772 if ( pts_c.size() ) { idx_mask |= SG_IDX_COLORS; ++idx_size; }
773 if ( pts_tc.size() ) { idx_mask |= SG_IDX_TEXCOORDS; ++idx_size; }
774 sgWriteChar( fp, (char)SG_INDEX_TYPES ); // property
775 sgWriteUInt( fp, 1 ); // nbytes
776 sgWriteChar( fp, idx_mask );
779 for ( i = start; i < end; ++i ) {
781 sgWriteUInt( fp, pts_v[i].size() * idx_size
782 * sizeof(unsigned short) );
783 for ( j = 0; j < (int)pts_v[i].size(); ++j ) {
784 if ( pts_v.size() ) {
785 sgWriteUShort( fp, (unsigned short)pts_v[i][j] );
787 if ( pts_n.size() ) {
788 sgWriteUShort( fp, (unsigned short)pts_n[i][j] );
790 if ( pts_c.size() ) {
791 sgWriteUShort( fp, (unsigned short)pts_c[i][j] );
793 if ( pts_tc.size() ) {
794 sgWriteUShort( fp, (unsigned short)pts_tc[i][j] );
804 // dump individual triangles if they exist
805 if ( tris_v.size() > 0 ) {
809 while ( start < (int)tri_materials.size() ) {
811 material = tri_materials[start];
812 while ( (end < (int)tri_materials.size()) &&
813 (material == tri_materials[end]) &&
814 3*(end-start) < 32760 )
816 // cout << "end = " << end << endl;
819 // cout << "group = " << start << " to " << end - 1 << endl;
821 // write group headers
822 sgWriteChar( fp, (char)SG_TRIANGLE_FACES ); // type
823 sgWriteUShort( fp, 2 ); // nproperties
824 sgWriteUShort( fp, 1 ); // nelements
826 sgWriteChar( fp, (char)SG_MATERIAL ); // property
827 sgWriteUInt( fp, material.length() ); // nbytes
828 sgWriteBytes( fp, material.length(), material.c_str() );
832 if ( tris_v.size() ) { idx_mask |= SG_IDX_VERTICES; ++idx_size; }
833 if ( tris_n.size() ) { idx_mask |= SG_IDX_NORMALS; ++idx_size; }
834 if ( tris_c.size() ) { idx_mask |= SG_IDX_COLORS; ++idx_size; }
835 if ( tris_tc.size() ) { idx_mask |= SG_IDX_TEXCOORDS; ++idx_size; }
836 sgWriteChar( fp, (char)SG_INDEX_TYPES ); // property
837 sgWriteUInt( fp, 1 ); // nbytes
838 sgWriteChar( fp, idx_mask );
841 sgWriteUInt( fp, (end - start) * 3 * idx_size
842 * sizeof(unsigned short) );
845 for ( i = start; i < end; ++i ) {
846 for ( j = 0; j < 3; ++j ) {
847 if ( tris_v.size() ) {
848 sgWriteUShort( fp, (unsigned short)tris_v[i][j] );
850 if ( tris_n.size() ) {
851 sgWriteUShort( fp, (unsigned short)tris_n[i][j] );
853 if ( tris_c.size() ) {
854 sgWriteUShort( fp, (unsigned short)tris_c[i][j] );
856 if ( tris_tc.size() ) {
857 sgWriteUShort( fp, (unsigned short)tris_tc[i][j] );
867 // dump triangle strips
868 if ( strips_v.size() > 0 ) {
872 while ( start < (int)strip_materials.size() ) {
874 material = strip_materials[start];
875 while ( (end < (int)strip_materials.size()) &&
876 (material == strip_materials[end]) )
878 // cout << "end = " << end << endl;
881 // cout << "group = " << start << " to " << end - 1 << endl;
883 // write group headers
884 sgWriteChar( fp, (char)SG_TRIANGLE_STRIPS ); // type
885 sgWriteUShort( fp, 2 ); // nproperties
886 sgWriteUShort( fp, end - start ); // nelements
888 sgWriteChar( fp, (char)SG_MATERIAL ); // property
889 sgWriteUInt( fp, material.length() ); // nbytes
890 sgWriteBytes( fp, material.length(), material.c_str() );
894 if ( strips_v.size() ) { idx_mask |= SG_IDX_VERTICES; ++idx_size; }
895 if ( strips_n.size() ) { idx_mask |= SG_IDX_NORMALS; ++idx_size; }
896 if ( strips_c.size() ) { idx_mask |= SG_IDX_COLORS; ++idx_size; }
897 if ( strips_tc.size() ) { idx_mask |= SG_IDX_TEXCOORDS; ++idx_size;}
898 sgWriteChar( fp, (char)SG_INDEX_TYPES ); // property
899 sgWriteUInt( fp, 1 ); // nbytes
900 sgWriteChar( fp, idx_mask );
903 for ( i = start; i < end; ++i ) {
905 sgWriteUInt( fp, strips_v[i].size() * idx_size
906 * sizeof(unsigned short));
907 for ( j = 0; j < (int)strips_v[i].size(); ++j ) {
908 if ( strips_v.size() ) {
909 sgWriteUShort( fp, (unsigned short)strips_v[i][j] );
911 if ( strips_n.size() ) {
912 sgWriteUShort( fp, (unsigned short)strips_n[i][j] );
914 if ( strips_c.size() ) {
915 sgWriteUShort( fp, (unsigned short)strips_c[i][j] );
917 if ( strips_tc.size() ) {
918 sgWriteUShort( fp, (unsigned short)strips_tc[i][j] );
928 // dump triangle fans
929 if ( fans_v.size() > 0 ) {
933 while ( start < (int)fan_materials.size() ) {
935 material = fan_materials[start];
936 while ( (end < (int)fan_materials.size()) &&
937 (material == fan_materials[end]) )
939 // cout << "end = " << end << endl;
942 // cout << "group = " << start << " to " << end - 1 << endl;
944 // write group headers
945 sgWriteChar( fp, (char)SG_TRIANGLE_FANS ); // type
946 sgWriteUShort( fp, 2 ); // nproperties
947 sgWriteUShort( fp, end - start ); // nelements
949 sgWriteChar( fp, (char)SG_MATERIAL ); // property
950 sgWriteUInt( fp, material.length() ); // nbytes
951 sgWriteBytes( fp, material.length(), material.c_str() );
955 if ( fans_v.size() ) { idx_mask |= SG_IDX_VERTICES; ++idx_size; }
956 if ( fans_n.size() ) { idx_mask |= SG_IDX_NORMALS; ++idx_size; }
957 if ( fans_c.size() ) { idx_mask |= SG_IDX_COLORS; ++idx_size; }
958 if ( fans_tc.size() ) { idx_mask |= SG_IDX_TEXCOORDS; ++idx_size; }
959 sgWriteChar( fp, (char)SG_INDEX_TYPES ); // property
960 sgWriteUInt( fp, 1 ); // nbytes
961 sgWriteChar( fp, idx_mask );
964 for ( i = start; i < end; ++i ) {
966 sgWriteUInt( fp, fans_v[i].size() * idx_size
967 * sizeof(unsigned short) );
968 for ( j = 0; j < (int)fans_v[i].size(); ++j ) {
969 if ( fans_v.size() ) {
970 sgWriteUShort( fp, (unsigned short)fans_v[i][j] );
972 if ( fans_n.size() ) {
973 sgWriteUShort( fp, (unsigned short)fans_n[i][j] );
975 if ( fans_c.size() ) {
976 sgWriteUShort( fp, (unsigned short)fans_c[i][j] );
978 if ( fans_tc.size() ) {
979 sgWriteUShort( fp, (unsigned short)fans_tc[i][j] );
992 if ( sgWriteError() ) {
993 cout << "We detected an error while writing the file." << endl;
1001 // write out the structures to an ASCII file. We assume that the
1002 // groups come to us sorted by material property. If not, things
1003 // don't break, but the result won't be as optimal.
1004 bool SGBinObject::write_ascii( const string& base, const string& name,
1009 SGPath file = base + "/" + b.gen_base_path() + "/" + name;
1010 file.create_dir( 0755 );
1011 cout << "Output file = " << file.str() << endl;
1014 if ( (fp = fopen( file.c_str(), "w" )) == NULL ) {
1015 cout << "ERROR: opening " << file.str() << " for writing!" << endl;
1019 cout << "triangles size = " << tris_v.size() << " tri_materials = "
1020 << tri_materials.size() << endl;
1021 cout << "strips size = " << strips_v.size() << " strip_materials = "
1022 << strip_materials.size() << endl;
1023 cout << "fans size = " << fans_v.size() << " fan_materials = "
1024 << fan_materials.size() << endl;
1026 cout << "points = " << wgs84_nodes.size() << endl;
1027 cout << "tex coords = " << texcoords.size() << endl;
1029 fprintf(fp, "# FGFS Scenery\n");
1030 fprintf(fp, "# Version %s\n", SG_SCENERY_FILE_FORMAT);
1032 time_t calendar_time = time(NULL);
1033 struct tm *local_tm;
1034 local_tm = localtime( &calendar_time );
1036 strftime( time_str, 256, "%a %b %d %H:%M:%S %Z %Y", local_tm);
1037 fprintf(fp, "# Created %s\n", time_str );
1040 // write bounding sphere
1041 fprintf(fp, "# gbs %.5f %.5f %.5f %.2f\n",
1042 gbs_center.x(), gbs_center.y(), gbs_center.z(), gbs_radius);
1046 fprintf(fp, "# vertex list\n");
1047 for ( i = 0; i < (int)wgs84_nodes.size(); ++i ) {
1048 SGVec3d p = wgs84_nodes[i] - gbs_center;
1050 fprintf(fp, "v %.5f %.5f %.5f\n", p.x(), p.y(), p.z() );
1054 fprintf(fp, "# vertex normal list\n");
1055 for ( i = 0; i < (int)normals.size(); ++i ) {
1056 SGVec3f p = normals[i];
1057 fprintf(fp, "vn %.5f %.5f %.5f\n", p.x(), p.y(), p.z() );
1061 // dump texture coordinates
1062 fprintf(fp, "# texture coordinate list\n");
1063 for ( i = 0; i < (int)texcoords.size(); ++i ) {
1064 SGVec2f p = texcoords[i];
1065 fprintf(fp, "vt %.5f %.5f\n", p.x(), p.y() );
1069 // dump individual triangles if they exist
1070 if ( tris_v.size() > 0 ) {
1071 fprintf(fp, "# triangle groups\n");
1076 while ( start < (int)tri_materials.size() ) {
1078 material = tri_materials[start];
1079 while ( (end < (int)tri_materials.size()) &&
1080 (material == tri_materials[end]) )
1082 // cout << "end = " << end << endl;
1085 // cout << "group = " << start << " to " << end - 1 << endl;
1088 for ( i = start; i < end; ++i ) {
1089 for ( j = 0; j < (int)tris_v[i].size(); ++j ) {
1090 d.expandBy(wgs84_nodes[ tris_v[i][j] ]);
1094 SGVec3d bs_center = d.getCenter();
1095 double bs_radius = d.getRadius();
1097 // write group headers
1099 fprintf(fp, "# usemtl %s\n", material.c_str());
1100 fprintf(fp, "# bs %.4f %.4f %.4f %.2f\n",
1101 bs_center.x(), bs_center.y(), bs_center.z(), bs_radius);
1104 for ( i = start; i < end; ++i ) {
1106 for ( j = 0; j < (int)tris_v[i].size(); ++j ) {
1107 fprintf(fp, " %d/%d", tris_v[i][j], tris_tc[i][j] );
1117 // dump triangle groups
1118 if ( strips_v.size() > 0 ) {
1119 fprintf(fp, "# triangle strips\n");
1124 while ( start < (int)strip_materials.size() ) {
1126 material = strip_materials[start];
1127 while ( (end < (int)strip_materials.size()) &&
1128 (material == strip_materials[end]) )
1130 // cout << "end = " << end << endl;
1133 // cout << "group = " << start << " to " << end - 1 << endl;
1137 for ( i = start; i < end; ++i ) {
1138 for ( j = 0; j < (int)tris_v[i].size(); ++j ) {
1139 d.expandBy(wgs84_nodes[ tris_v[i][j] ]);
1143 SGVec3d bs_center = d.getCenter();
1144 double bs_radius = d.getRadius();
1146 // write group headers
1148 fprintf(fp, "# usemtl %s\n", material.c_str());
1149 fprintf(fp, "# bs %.4f %.4f %.4f %.2f\n",
1150 bs_center.x(), bs_center.y(), bs_center.z(), bs_radius);
1153 for ( i = start; i < end; ++i ) {
1155 for ( j = 0; j < (int)strips_v[i].size(); ++j ) {
1156 fprintf(fp, " %d/%d", strips_v[i][j], strips_tc[i][j] );
1169 string command = "gzip --force --best " + file.str();
1170 system(command.c_str());