]> git.mxchange.org Git - flightgear.git/blob - src/Objects/obj.cxx
Lighting/ssgSimpleState fixes.
[flightgear.git] / src / Objects / obj.cxx
1 // obj.cxx -- routines to handle "sorta" WaveFront .obj format files.
2 //
3 // Written by Curtis Olson, started October 1997.
4 //
5 // Copyright (C) 1997  Curtis L. Olson  - curt@infoplane.com
6 //
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License as
9 // published by the Free Software Foundation; either version 2 of the
10 // License, or (at your option) any later version.
11 //
12 // This program is distributed in the hope that it will be useful, but
13 // WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 // General Public License for more details.
16 //
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., 675 Mass Ave, Cambridge, MA 02139, USA.
20 //
21 // $Id$
22
23
24 #ifdef HAVE_CONFIG_H
25 #  include <config.h>
26 #endif
27
28 #ifdef FG_MATH_EXCEPTION_CLASH
29 #  include <math.h>
30 #endif
31
32 #include <stdio.h>
33 #include <string.h>
34
35 // #if defined ( __sun__ )
36 // extern "C" void *memmove(void *, const void *, size_t);
37 // extern "C" void *memset(void *, int, size_t);
38 // #endif
39
40 #include <Include/compiler.h>
41
42 #include STL_STRING
43 #include <map>                  // STL
44 #include <vector>               // STL
45 #include <ctype.h>              // isdigit()
46
47 #include <Debug/logstream.hxx>
48 #include <Misc/fgstream.hxx>
49 #include <Include/fg_constants.h>
50 #include <Main/options.hxx>
51 #include <Math/mat3.h>
52 #include <Math/fg_geodesy.hxx>
53 #include <Math/fg_random.h>
54 #include <Math/point3d.hxx>
55 #include <Math/polar3d.hxx>
56 #include <Misc/stopwatch.hxx>
57 #include <Scenery/tileentry.hxx>
58
59 #include "materialmgr.hxx"
60 #include "obj.hxx"
61
62 FG_USING_STD(string);
63 FG_USING_STD(vector);
64
65
66 typedef vector < int > int_list;
67 typedef int_list::iterator int_list_iterator;
68 typedef int_list::const_iterator int_point_list_iterator;
69
70
71 static double normals[FG_MAX_NODES][3];
72 static double tex_coords[FG_MAX_NODES*3][3];
73
74
75 // given three points defining a triangle, calculate the normal
76 static void calc_normal(Point3D p1, Point3D p2, 
77                         Point3D p3, double normal[3])
78 {
79     double v1[3], v2[3];
80     double temp;
81
82     v1[0] = p2[0] - p1[0]; v1[1] = p2[1] - p1[1]; v1[2] = p2[2] - p1[2];
83     v2[0] = p3[0] - p1[0]; v2[1] = p3[1] - p1[1]; v2[2] = p3[2] - p1[2];
84
85     MAT3cross_product(normal, v1, v2);
86     MAT3_NORMALIZE_VEC(normal,temp);
87
88     // fgPrintf( FG_TERRAIN, FG_DEBUG, "  Normal = %.2f %.2f %.2f\n", 
89     //           normal[0], normal[1], normal[2]);
90 }
91
92
93 #define FG_TEX_CONSTANT 69.0
94
95
96 // Calculate texture coordinates for a given point.
97 static Point3D calc_tex_coords(const Point3D& node, const Point3D& ref) {
98     Point3D cp;
99     Point3D pp;
100     // double tmplon, tmplat;
101
102     // cout << "-> " << node[0] << " " << node[1] << " " << node[2] << endl;
103     // cout << "-> " << ref.x() << " " << ref.y() << " " << ref.z() << endl;
104
105     cp = Point3D( node[0] + ref.x(),
106                   node[1] + ref.y(),
107                   node[2] + ref.z() );
108
109     pp = fgCartToPolar3d(cp);
110
111     // tmplon = pp.lon() * RAD_TO_DEG;
112     // tmplat = pp.lat() * RAD_TO_DEG;
113     // cout << tmplon << " " << tmplat << endl;
114
115     pp.setx( fmod(RAD_TO_DEG * FG_TEX_CONSTANT * pp.x(), 11.0) );
116     pp.sety( fmod(RAD_TO_DEG * FG_TEX_CONSTANT * pp.y(), 11.0) );
117
118     if ( pp.x() < 0.0 ) {
119         pp.setx( pp.x() + 11.0 );
120     }
121
122     if ( pp.y() < 0.0 ) {
123         pp.sety( pp.y() + 11.0 );
124     }
125
126     // cout << pp << endl;
127
128     return(pp);
129 }
130
131
132 // Generate a generic ocean tile on the fly
133 ssgBranch *fgGenTile( const string& path, FGTileEntry *t) {
134     fgFRAGMENT fragment;
135     fragment.init();
136     fragment.tile_ptr = t;
137
138     ssgSimpleState *state = NULL;
139
140     ssgBranch *tile = new ssgBranch () ;
141     tile -> setName ( (char *)path.c_str() ) ;
142
143     // find Ocean material in the properties list
144     if ( ! material_mgr.find( "Ocean", fragment.material_ptr )) {
145         FG_LOG( FG_TERRAIN, FG_ALERT, 
146                 "Ack! unknown usemtl name = " << "Ocean" 
147                 << " in " << path );
148     }
149
150     // set the texture width and height values for this
151     // material
152     FGMaterial m = fragment.material_ptr->get_m();
153     double tex_width = m.get_xsize();
154     double tex_height = m.get_ysize();
155
156     // set ssgState
157     state = fragment.material_ptr->get_state();
158
159     // Calculate center point
160     FGBucket b = t->tile_bucket;
161     double clon = b.get_center_lon();
162     double clat = b.get_center_lat();
163     double height = b.get_height();
164     double width = b.get_width();
165
166     Point3D center = fgGeodToCart(Point3D(clon*DEG_TO_RAD,clat*DEG_TO_RAD,0.0));
167     t->center = center;
168     fragment.center = center;
169     // cout << "center = " << center << endl;;
170     
171     // Caculate corner vertices
172     Point3D geod[4];
173     geod[0] = Point3D( clon - width/2.0, clat - height/2.0, 0.0 );
174     geod[1] = Point3D( clon + width/2.0, clat - height/2.0, 0.0 );
175     geod[2] = Point3D( clon + width/2.0, clat + height/2.0, 0.0 );
176     geod[3] = Point3D( clon - width/2.0, clat + height/2.0, 0.0 );
177
178     Point3D rad[4];
179     for ( int i = 0; i < 4; ++i ) {
180         rad[i] = Point3D( geod[i].x() * DEG_TO_RAD, geod[i].y() * DEG_TO_RAD,
181                           geod[i].z() );
182     }
183
184     Point3D cart[4], rel[4];
185     for ( int i = 0; i < 4; ++i ) {
186         cart[i] = fgGeodToCart(rad[i]);
187         rel[i] = cart[i] - center;
188         t->nodes.push_back( rel[i] );
189         // cout << "corner " << i << " = " << cart[i] << endl;
190     }
191
192     t->ncount = 4;
193
194     // Calculate bounding radius
195     t->bounding_radius = center.distance3D( cart[0] );
196     fragment.bounding_radius = t->bounding_radius;
197     // cout << "bounding radius = " << t->bounding_radius << endl;
198
199     // Calculate normals
200     Point3D normals[4];
201     for ( int i = 0; i < 4; ++i ) {
202         normals[i] = cart[i];
203         double length = normals[i].distance3D( Point3D(0.0) );
204         normals[i] /= length;
205         // cout << "normal = " << normals[i] << endl;
206     }
207
208     // Calculate texture coordinates
209     Point3D texs[4];
210     for ( int i = 0; i < 4; ++i ) {
211         texs[i] = calc_tex_coords( rel[i], center );
212         // cout << "texture coordinate = " << texs[i] << endl;
213     }
214
215     // Build flight gear structure
216     fragment.add_face(1, 2, 3);
217     fragment.add_face(1, 3, 4);
218     t->fragment_list.push_back(fragment);
219
220     // Build ssg structure
221     t->vtlist = new sgVec3 [ 4 ];
222     t->vnlist = new sgVec3 [ 4 ];
223     t->tclist = new sgVec2 [ 4 ];
224
225     for ( int i = 0; i < 4; ++i ) {
226         sgSetVec3( t->vtlist[i], 
227                    rel[i].x(), rel[i].y(), rel[i].z() );
228         sgSetVec3( t->vnlist[i], 
229                    normals[i].x(), normals[i].y(), normals[i].z() );
230         sgSetVec2( t->tclist[i], texs[i].x(), texs[i].y() );
231     }
232     
233     unsigned short *vindex = new unsigned short [ 4 ];
234     unsigned short *tindex = new unsigned short [ 4 ];
235     for ( int i = 0; i < 4; ++i ) {
236         vindex[i] = i;
237         tindex[i] = i;
238     }
239
240     ssgLeaf *leaf = 
241         new ssgVTable ( GL_TRIANGLE_FAN,
242                         4, vindex, t->vtlist,
243                         4, vindex, t->vnlist,
244                         4, tindex, t->tclist,
245                         0, NULL, NULL ) ;
246     leaf->setState( state );
247
248     tile->addKid( leaf );
249
250     return tile;
251 }
252
253
254 // Load a .obj file and build the fragment list
255 ssgBranch *fgObjLoad( const string& path, FGTileEntry *t) {
256     fgFRAGMENT fragment;
257     Point3D pp;
258     double approx_normal[3] /*, normal[3], scale = 0.0 */;
259     // double x, y, z, xmax, xmin, ymax, ymin, zmax, zmin;
260     // GLfloat sgenparams[] = { 1.0, 0.0, 0.0, 0.0 };
261     // GLint display_list = 0;
262     int shading;
263     bool in_fragment = false, in_faces = false;
264     int vncount, vtcount;
265     int n1 = 0, n2 = 0, n3 = 0, n4 = 0;
266     int tex;
267     int last1 = 0, last2 = 0, odd = 0;
268     point_list nodes;
269     Point3D node;
270     Point3D center;
271     double tex_width = 1000.0, tex_height = 1000.0;
272     bool shared_done = false;
273     int_list fan_vertices;
274     int_list fan_tex_coords;
275     int i;
276     ssgSimpleState *state = NULL;
277
278     ssgBranch *tile = new ssgBranch () ;
279     tile -> setName ( (char *)path.c_str() ) ;
280
281     // Attempt to open "path.gz" or "path"
282     fg_gzifstream in( path );
283     if ( ! in.is_open() ) {
284         FG_LOG( FG_TERRAIN, FG_ALERT, "Cannot open file: " << path );
285         FG_LOG( FG_TERRAIN, FG_ALERT, "default to ocean tile: " << path );
286
287         return fgGenTile( path, t );
288     }
289
290     shading = current_options.get_shading();
291
292     in_fragment = false;
293     t->ncount = 0;
294     vncount = 0;
295     vtcount = 0;
296     t->bounding_radius = 0.0;
297     center = t->center;
298
299     StopWatch stopwatch;
300     stopwatch.start();
301
302     // ignore initial comments and blank lines. (priming the pump)
303     // in >> skipcomment;
304     // string line;
305
306     string token;
307     char c;
308
309 #ifdef __MWERKS__
310     while ( in.get(c) && c  != '\0' ) {
311         in.putback(c);
312 #else
313     while ( ! in.eof() ) {
314 #endif
315
316 #if defined( MACOS )
317         in >> ::skipws;
318 #else
319         in >> skipws;
320 #endif
321
322         if ( in.get( c ) && c == '#' ) {
323             // process a comment line
324
325             // getline( in, line );
326             // cout << "comment = " << line << endl;
327
328             in >> token;
329
330             if ( token == "gbs" ) {
331                 // reference point (center offset)
332                 in >> t->center >> t->bounding_radius;
333                 center = t->center;
334                 // cout << "center = " << center 
335                 //      << " radius = " << t->bounding_radius << endl;
336             } else if ( token == "bs" ) {
337                 // reference point (center offset)
338                 in >> fragment.center;
339                 in >> fragment.bounding_radius;
340
341                 // cout << "center = " << fragment.center 
342                 //      << " radius = " << fragment.bounding_radius << endl;
343             } else if ( token == "usemtl" ) {
344                 // material property specification
345
346                 // if first usemtl with shared_done = false, then set
347                 // shared_done true and build the ssg shared lists
348                 if ( ! shared_done ) {
349                     // sanity check
350                     if ( (int)nodes.size() != vncount ) {
351                         FG_LOG( FG_TERRAIN, FG_ALERT, 
352                                 "Tile has mismatched nodes and normals: " 
353                                 << path );
354                         // exit(-1);
355                     }
356                     shared_done = true;
357
358                     t->vtlist = new sgVec3 [ nodes.size() ];
359                     t->vnlist = new sgVec3 [ vncount ];
360                     t->tclist = new sgVec2 [ vtcount ];
361
362                     for ( i = 0; i < (int)nodes.size(); ++i ) {
363                         sgSetVec3( t->vtlist[i], 
364                                    nodes[i][0], nodes[i][1], nodes[i][2] );
365                     }
366                     for ( i = 0; i < vncount; ++i ) {
367                         sgSetVec3( t->vnlist[i], 
368                                    normals[i][0], 
369                                    normals[i][1],
370                                    normals[i][2] );
371                     }
372                     for ( i = 0; i < vtcount; ++i ) {
373                         sgSetVec2( t->tclist[i],
374                                    tex_coords[i][0], tex_coords[i][1] );
375                     }
376                 }
377
378                 // series of individual triangles
379                 // if ( in_faces ) {
380                 //     xglEnd();
381                 // }
382
383                 // this also signals the start of a new fragment
384                 if ( in_fragment ) {
385                     // close out the previous structure and start the next
386                     // xglEndList();
387                     // printf("xglEnd(); xglEndList();\n");
388
389                     // update fragment
390                     // fragment.display_list = display_list;
391
392                     // push this fragment onto the tile's object list
393                     t->fragment_list.push_back(fragment);
394                 } else {
395                     in_fragment = true;
396                 }
397
398                 // printf("start of fragment (usemtl)\n");
399
400                 // display_list = xglGenLists(1);
401                 // xglNewList(display_list, GL_COMPILE);
402                 // printf("xglGenLists(); xglNewList();\n");
403                 in_faces = false;
404
405                 // reset the existing face list
406                 // printf("cleaning a fragment with %d faces\n", 
407                 //        fragment.faces.size());
408                 fragment.init();
409                 
410                 // scan the material line
411                 string material;
412                 in >> material;
413                 fragment.tile_ptr = t;
414                 
415                 // find this material in the properties list
416                 if ( ! material_mgr.find( material, fragment.material_ptr )) {
417                     FG_LOG( FG_TERRAIN, FG_ALERT, 
418                             "Ack! unknown usemtl name = " << material 
419                             << " in " << path );
420                 }
421
422                 // set the texture width and height values for this
423                 // material
424                 FGMaterial m = fragment.material_ptr->get_m();
425                 tex_width = m.get_xsize();
426                 tex_height = m.get_ysize();
427                 state = fragment.material_ptr->get_state();
428                 // cout << "(w) = " << tex_width << " (h) = " 
429                 //      << tex_width << endl;
430
431                 // initialize the fragment transformation matrix
432                 /*
433                  for ( i = 0; i < 16; i++ ) {
434                    fragment.matrix[i] = 0.0;
435                  }
436                  fragment.matrix[0] = fragment.matrix[5] =
437                  fragment.matrix[10] = fragment.matrix[15] = 1.0;
438                 */
439             } else {
440                 // unknown comment, just gobble the input untill the
441                 // end of line
442
443                 in >> skipeol;
444             }
445         } else {
446             in.putback( c );
447         
448             in >> token;
449
450             // cout << "token = " << token << endl;
451
452             if ( token == "vn" ) {
453                 // vertex normal
454                 if ( vncount < FG_MAX_NODES ) {
455                     in >> normals[vncount][0]
456                        >> normals[vncount][1]
457                        >> normals[vncount][2];
458                     vncount++;
459                 } else {
460                     FG_LOG( FG_TERRAIN, FG_ALERT, 
461                             "Read too many vertex normals in " << path 
462                             << " ... dying :-(" );
463                     exit(-1);
464                 }
465             } else if ( token == "vt" ) {
466                 // vertex texture coordinate
467                 if ( vtcount < FG_MAX_NODES*3 ) {
468                     in >> tex_coords[vtcount][0]
469                        >> tex_coords[vtcount][1];
470                     vtcount++;
471                 } else {
472                     FG_LOG( FG_TERRAIN, FG_ALERT, 
473                             "Read too many vertex texture coords in " << path
474                             << " ... dying :-("
475                             );
476                     exit(-1);
477                 }
478             } else if ( token == "v" ) {
479                 // node (vertex)
480                 if ( t->ncount < FG_MAX_NODES ) {
481                     /* in >> nodes[t->ncount][0]
482                        >> nodes[t->ncount][1]
483                        >> nodes[t->ncount][2]; */
484                     in >> node;
485                     nodes.push_back(node);
486                     t->ncount++;
487                 } else {
488                     FG_LOG( FG_TERRAIN, FG_ALERT, 
489                             "Read too many nodes in " << path 
490                             << " ... dying :-(");
491                     exit(-1);
492                 }
493             } else if ( token == "t" ) {
494                 // start a new triangle strip
495
496                 n1 = n2 = n3 = n4 = 0;
497
498                 // fgPrintf( FG_TERRAIN, FG_DEBUG, 
499                 //           "    new tri strip = %s", line);
500                 in >> n1 >> n2 >> n3;
501                 fragment.add_face(n1, n2, n3);
502
503                 // fgPrintf( FG_TERRAIN, FG_DEBUG, "(t) = ");
504
505                 // xglBegin(GL_TRIANGLE_STRIP);
506                 // printf("xglBegin(tristrip) %d %d %d\n", n1, n2, n3);
507
508                 odd = 1; 
509                 // scale = 1.0;
510
511                 if ( shading ) {
512                     // Shading model is "GL_SMOOTH" so use precalculated
513                     // (averaged) normals
514                     // MAT3_SCALE_VEC(normal, normals[n1], scale);
515                     // xglNormal3dv(normal);
516                     pp = calc_tex_coords(nodes[n1], center);
517                     // xglTexCoord2f(pp.lon(), pp.lat());
518                     // xglVertex3dv(nodes[n1].get_n());         
519
520                     // MAT3_SCALE_VEC(normal, normals[n2], scale);
521                     // xglNormal3dv(normal);
522                     pp = calc_tex_coords(nodes[n2], center);
523                     // xglTexCoord2f(pp.lon(), pp.lat());
524                     // xglVertex3dv(nodes[n2].get_n());                         
525
526                     // MAT3_SCALE_VEC(normal, normals[n3], scale);
527                     // xglNormal3dv(normal);
528                     pp = calc_tex_coords(nodes[n3], center);
529                     // xglTexCoord2f(pp.lon(), pp.lat());
530                     // xglVertex3dv(nodes[n3].get_n());
531                 } else {
532                     // Shading model is "GL_FLAT" so calculate per face
533                     // normals on the fly.
534                     if ( odd ) {
535                         calc_normal(nodes[n1], nodes[n2], 
536                                     nodes[n3], approx_normal);
537                     } else {
538                         calc_normal(nodes[n2], nodes[n1], 
539                                     nodes[n3], approx_normal);
540                     }
541                     // MAT3_SCALE_VEC(normal, approx_normal, scale);
542                     // xglNormal3dv(normal);
543
544                     pp = calc_tex_coords(nodes[n1], center);
545                     // xglTexCoord2f(pp.lon(), pp.lat());
546                     // xglVertex3dv(nodes[n1].get_n());         
547
548                     pp = calc_tex_coords(nodes[n2], center);
549                     // xglTexCoord2f(pp.lon(), pp.lat());
550                     // xglVertex3dv(nodes[n2].get_n());         
551                     
552                     pp = calc_tex_coords(nodes[n3], center);
553                     // xglTexCoord2f(pp.lon(), pp.lat());
554                     // xglVertex3dv(nodes[n3].get_n());         
555                 }
556                 // printf("some normals, texcoords, and vertices\n");
557
558                 odd = 1 - odd;
559                 last1 = n2;
560                 last2 = n3;
561
562                 // There can be three or four values 
563                 char c;
564                 while ( in.get(c) ) {
565                     if ( c == '\n' ) {
566                         break; // only the one
567                     }
568                     if ( isdigit(c) ){
569                         in.putback(c);
570                         in >> n4;
571                         break;
572                     }
573                 }
574
575                 if ( n4 > 0 ) {
576                     fragment.add_face(n3, n2, n4);
577
578                     if ( shading ) {
579                         // Shading model is "GL_SMOOTH"
580                         // MAT3_SCALE_VEC(normal, normals[n4], scale);
581                     } else {
582                         // Shading model is "GL_FLAT"
583                         calc_normal(nodes[n3], nodes[n2], nodes[n4], 
584                                     approx_normal);
585                         // MAT3_SCALE_VEC(normal, approx_normal, scale);
586                     }
587                     // xglNormal3dv(normal);
588                     pp = calc_tex_coords(nodes[n4], center);
589                     // xglTexCoord2f(pp.lon(), pp.lat());
590                     // xglVertex3dv(nodes[n4].get_n());         
591                     
592                     odd = 1 - odd;
593                     last1 = n3;
594                     last2 = n4;
595                     // printf("a normal, texcoord, and vertex (4th)\n");
596                 }
597             } else if ( token == "tf" ) {
598                 // triangle fan
599                 // fgPrintf( FG_TERRAIN, FG_DEBUG, "new fan");
600
601                 fan_vertices.clear();
602                 fan_tex_coords.clear();
603
604                 // xglBegin(GL_TRIANGLE_FAN);
605
606                 in >> n1;
607                 fan_vertices.push_back( n1 );
608                 // xglNormal3dv(normals[n1]);
609                 if ( in.get( c ) && c == '/' ) {
610                     in >> tex;
611                     fan_tex_coords.push_back( tex );
612                     pp.setx( tex_coords[tex][0] * (1000.0 / tex_width) );
613                     pp.sety( tex_coords[tex][1] * (1000.0 / tex_height) );
614                 } else {
615                     in.putback( c );
616                     pp = calc_tex_coords(nodes[n1], center);
617                 }
618                 // xglTexCoord2f(pp.x(), pp.y());
619                 // xglVertex3dv(nodes[n1].get_n());
620
621                 in >> n2;
622                 fan_vertices.push_back( n2 );
623                 // xglNormal3dv(normals[n2]);
624                 if ( in.get( c ) && c == '/' ) {
625                     in >> tex;
626                     fan_tex_coords.push_back( tex );
627                     pp.setx( tex_coords[tex][0] * (1000.0 / tex_width) );
628                     pp.sety( tex_coords[tex][1] * (1000.0 / tex_height) );
629                 } else {
630                     in.putback( c );
631                     pp = calc_tex_coords(nodes[n2], center);
632                 }
633                 // xglTexCoord2f(pp.x(), pp.y());
634                 // xglVertex3dv(nodes[n2].get_n());
635                 
636                 // read all subsequent numbers until next thing isn't a number
637                 while ( true ) {
638 #if defined( MACOS )
639                     in >> ::skipws;
640 #else
641                     in >> skipws;
642 #endif
643
644                     char c;
645                     in.get(c);
646                     in.putback(c);
647                     if ( ! isdigit(c) || in.eof() ) {
648                         break;
649                     }
650
651                     in >> n3;
652                     fan_vertices.push_back( n3 );
653                     // cout << "  triangle = " 
654                     //      << n1 << "," << n2 << "," << n3 
655                     //      << endl;
656                     // xglNormal3dv(normals[n3]);
657                     if ( in.get( c ) && c == '/' ) {
658                         in >> tex;
659                         fan_tex_coords.push_back( tex );
660                         pp.setx( tex_coords[tex][0] * (1000.0 / tex_width) );
661                         pp.sety( tex_coords[tex][1] * (1000.0 / tex_height) );
662                     } else {
663                         in.putback( c );
664                         pp = calc_tex_coords(nodes[n3], center);
665                     }
666                     // xglTexCoord2f(pp.x(), pp.y());
667                     // xglVertex3dv(nodes[n3].get_n());
668
669                     fragment.add_face(n1, n2, n3);
670                     n2 = n3;
671                 }
672
673                 // xglEnd();
674
675                 // build the ssg entity
676                 unsigned short *vindex = 
677                     new unsigned short [ fan_vertices.size() ];
678                 unsigned short *tindex = 
679                     new unsigned short [ fan_tex_coords.size() ];
680                 for ( i = 0; i < (int)fan_vertices.size(); ++i ) {
681                     vindex[i] = fan_vertices[i];
682                 }
683                 for ( i = 0; i < (int)fan_tex_coords.size(); ++i ) {
684                     tindex[i] = fan_tex_coords[i];
685                 }
686                 ssgLeaf *leaf = 
687                     new ssgVTable ( GL_TRIANGLE_FAN,
688                                     fan_vertices.size(), vindex, t->vtlist,
689                                     fan_vertices.size(), vindex, t->vnlist,
690                                     fan_tex_coords.size(), tindex, t->tclist,
691                                     0, NULL, NULL ) ;
692                 leaf->setState( state );
693
694                 tile->addKid( leaf );
695
696             } else if ( token == "f" ) {
697                 // unoptimized face
698
699                 if ( !in_faces ) {
700                     // xglBegin(GL_TRIANGLES);
701                     // printf("xglBegin(triangles)\n");
702                     in_faces = true;
703                 }
704
705                 // fgPrintf( FG_TERRAIN, FG_DEBUG, "new triangle = %s", line);*/
706                 in >> n1 >> n2 >> n3;
707                 fragment.add_face(n1, n2, n3);
708
709                 // xglNormal3d(normals[n1][0], normals[n1][1], normals[n1][2]);
710                 // xglNormal3dv(normals[n1]);
711                 pp = calc_tex_coords(nodes[n1], center);
712                 // xglTexCoord2f(pp.lon(), pp.lat());
713                 // xglVertex3dv(nodes[n1].get_n());
714
715                 // xglNormal3dv(normals[n2]);
716                 pp = calc_tex_coords(nodes[n2], center);
717                 // xglTexCoord2f(pp.lon(), pp.lat());
718                 // xglVertex3dv(nodes[n2].get_n());
719                 
720                 // xglNormal3dv(normals[n3]);
721                 pp = calc_tex_coords(nodes[n3], center);
722                 // xglTexCoord2f(pp.lon(), pp.lat());
723                 // xglVertex3dv(nodes[n3].get_n());
724                 // printf("some normals, texcoords, and vertices (tris)\n");
725             } else if ( token == "q" ) {
726                 // continue a triangle strip
727                 n1 = n2 = 0;
728
729                 // fgPrintf( FG_TERRAIN, FG_DEBUG, "continued tri strip = %s ", 
730                 //           line);
731                 in >> n1;
732
733                 // There can be one or two values 
734                 char c;
735                 while ( in.get(c) ) {
736                     if ( c == '\n' ) {
737                         break; // only the one
738                     }
739
740                     if ( isdigit(c) ) {
741                         in.putback(c);
742                         in >> n2;
743                         break;
744                     }
745                 }
746                 // fgPrintf( FG_TERRAIN, FG_DEBUG, "read %d %d\n", n1, n2);
747
748                 if ( odd ) {
749                     fragment.add_face(last1, last2, n1);
750                 } else {
751                     fragment.add_face(last2, last1, n1);
752                 }
753
754                 if ( shading ) {
755                     // Shading model is "GL_SMOOTH"
756                     // MAT3_SCALE_VEC(normal, normals[n1], scale);
757                 } else {
758                     // Shading model is "GL_FLAT"
759                     if ( odd ) {
760                         calc_normal(nodes[last1], nodes[last2], 
761                                     nodes[n1], approx_normal);
762                     } else {
763                         calc_normal(nodes[last2], nodes[last1], 
764                                     nodes[n1], approx_normal);
765                     }
766                     // MAT3_SCALE_VEC(normal, approx_normal, scale);
767                 }
768                 // xglNormal3dv(normal);
769
770                 pp = calc_tex_coords(nodes[n1], center);
771                 // xglTexCoord2f(pp.lon(), pp.lat());
772                 // xglVertex3dv(nodes[n1].get_n());
773                 // printf("a normal, texcoord, and vertex (4th)\n");
774    
775                 odd = 1 - odd;
776                 last1 = last2;
777                 last2 = n1;
778
779                 if ( n2 > 0 ) {
780                     // fgPrintf( FG_TERRAIN, FG_DEBUG, " (cont)\n");
781
782                     if ( odd ) {
783                         fragment.add_face(last1, last2, n2);
784                     } else {
785                         fragment.add_face(last2, last1, n2);
786                     }
787
788                     if ( shading ) {
789                         // Shading model is "GL_SMOOTH"
790                         // MAT3_SCALE_VEC(normal, normals[n2], scale);
791                     } else {
792                         // Shading model is "GL_FLAT"
793                         if ( odd ) {
794                             calc_normal(nodes[last1], nodes[last2], 
795                                         nodes[n2], approx_normal);
796                         } else {
797                             calc_normal(nodes[last2], nodes[last1], 
798                                         nodes[n2], approx_normal);
799                         }
800                         // MAT3_SCALE_VEC(normal, approx_normal, scale);
801                     }
802                     // xglNormal3dv(normal);
803                 
804                     pp = calc_tex_coords(nodes[n2], center);
805                     // xglTexCoord2f(pp.lon(), pp.lat());
806                     // xglVertex3dv(nodes[n2].get_n());         
807                     // printf("a normal, texcoord, and vertex (4th)\n");
808
809                     odd = 1 -odd;
810                     last1 = last2;
811                     last2 = n2;
812                 }
813             } else {
814                 FG_LOG( FG_TERRAIN, FG_WARN, "Unknown token in " 
815                         << path << " = " << token );
816             }
817
818             // eat white space before start of while loop so if we are
819             // done with useful input it is noticed before hand.
820 #if defined( MACOS )
821             in >> ::skipws;
822 #else
823             in >> skipws;
824 #endif
825         }
826     }
827
828     if ( in_fragment ) {
829         // close out the previous structure and start the next
830         // xglEnd();
831         // xglEndList();
832         // printf("xglEnd(); xglEndList();\n");
833         
834         // update fragment
835         // fragment.display_list = display_list;
836         
837         // push this fragment onto the tile's object list
838         t->fragment_list.push_back(fragment);
839     }
840
841 #if 0
842     // Draw normal vectors (for visually verifying normals)
843     xglBegin(GL_LINES);
844     xglColor3f(0.0, 0.0, 0.0);
845     for ( i = 0; i < t->ncount; i++ ) {
846         xglVertex3d(nodes[i][0],
847                     nodes[i][1] ,
848                     nodes[i][2]);
849         xglVertex3d(nodes[i][0] + 500*normals[i][0],
850                     nodes[i][1] + 500*normals[i][1],
851                     nodes[i][2] + 500*normals[i][2]);
852     } 
853     xglEnd();
854 #endif
855
856     t->nodes = nodes;
857
858     stopwatch.stop();
859     FG_LOG( FG_TERRAIN, FG_INFO, 
860             "Loaded " << path << " in " 
861             << stopwatch.elapsedSeconds() << " seconds" );
862     
863     return tile;
864 }
865
866