]> git.mxchange.org Git - simgear.git/blob - simgear/scene/tgdb/obj.cxx
Clean up a class renaming mistake.
[simgear.git] / simgear / scene / tgdb / obj.cxx
1 // obj.cxx -- routines to handle loading scenery and building the plib
2 //            scene graph.
3 //
4 // Written by Curtis Olson, started October 1997.
5 //
6 // Copyright (C) 1997  Curtis L. Olson  - curt@infoplane.com
7 //
8 // This program is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU General Public License as
10 // published by the Free Software Foundation; either version 2 of the
11 // License, or (at your option) any later version.
12 //
13 // This program is distributed in the hope that it will be useful, but
14 // WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 // General Public License for more details.
17 //
18 // You should have received a copy of the GNU General Public License
19 // along with this program; if not, write to the Free Software
20 // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 //
22 // $Id$
23
24
25 // #ifdef HAVE_CONFIG_H
26 // #  include <config.h>
27 // #endif
28
29 #include <simgear/compiler.h>
30
31 #include STL_STRING
32
33 #include <simgear/bucket/newbucket.hxx>
34 #include <simgear/io/sg_binobj.hxx>
35 #include <simgear/math/sg_geodesy.hxx>
36 #include <simgear/math/sg_types.hxx>
37 #include <simgear/misc/texcoord.hxx>
38 #include <simgear/scene/material/mat.hxx>
39 #include <simgear/scene/material/matlib.hxx>
40 #include <simgear/scene/tgdb/leaf.hxx>
41 #include <simgear/scene/tgdb/pt_lights.hxx>
42 #include <simgear/scene/tgdb/userdata.hxx>
43
44 #include "obj.hxx"
45
46 SG_USING_STD(string);
47
48
49 // Generate an ocean tile
50 bool sgGenTile( const string& path, SGBucket b,
51                 Point3D *center, double *bounding_radius,
52                 SGMaterialLib *matlib, ssgBranch* geometry )
53 {
54     ssgSimpleState *state = NULL;
55
56     geometry->setName( (char *)path.c_str() );
57
58     double tex_width = 1000.0;
59     // double tex_height;
60
61     // find Ocean material in the properties list
62     SGMaterial *mat = matlib->find( "Ocean" );
63     if ( mat != NULL ) {
64         // set the texture width and height values for this
65         // material
66         tex_width = mat->get_xsize();
67         // tex_height = newmat->get_ysize();
68         
69         // set ssgState
70         state = mat->get_state();
71     } else {
72         SG_LOG( SG_TERRAIN, SG_ALERT, 
73                 "Ack! unknown usemtl name = " << "Ocean" 
74                 << " in " << path );
75     }
76
77     // Calculate center point
78     double clon = b.get_center_lon();
79     double clat = b.get_center_lat();
80     double height = b.get_height();
81     double width = b.get_width();
82
83     *center = sgGeodToCart( Point3D(clon*SGD_DEGREES_TO_RADIANS,
84                                     clat*SGD_DEGREES_TO_RADIANS,
85                                     0.0) );
86     // cout << "center = " << center << endl;;
87     
88     // Caculate corner vertices
89     Point3D geod[4];
90     geod[0] = Point3D( clon - width/2.0, clat - height/2.0, 0.0 );
91     geod[1] = Point3D( clon + width/2.0, clat - height/2.0, 0.0 );
92     geod[2] = Point3D( clon + width/2.0, clat + height/2.0, 0.0 );
93     geod[3] = Point3D( clon - width/2.0, clat + height/2.0, 0.0 );
94
95     Point3D rad[4];
96     int i;
97     for ( i = 0; i < 4; ++i ) {
98         rad[i] = Point3D( geod[i].x() * SGD_DEGREES_TO_RADIANS,
99                           geod[i].y() * SGD_DEGREES_TO_RADIANS,
100                           geod[i].z() );
101     }
102
103     Point3D cart[4], rel[4];
104     for ( i = 0; i < 4; ++i ) {
105         cart[i] = sgGeodToCart(rad[i]);
106         rel[i] = cart[i] - *center;
107         // cout << "corner " << i << " = " << cart[i] << endl;
108     }
109
110     // Calculate bounding radius
111     *bounding_radius = center->distance3D( cart[0] );
112     // cout << "bounding radius = " << t->bounding_radius << endl;
113
114     // Calculate normals
115     Point3D normals[4];
116     for ( i = 0; i < 4; ++i ) {
117         double length = cart[i].distance3D( Point3D(0.0) );
118         normals[i] = cart[i] / length;
119         // cout << "normal = " << normals[i] << endl;
120     }
121
122     // Calculate texture coordinates
123     point_list geod_nodes;
124     geod_nodes.clear();
125     geod_nodes.reserve(4);
126     int_list rectangle;
127     rectangle.clear();
128     rectangle.reserve(4);
129     for ( i = 0; i < 4; ++i ) {
130         geod_nodes.push_back( geod[i] );
131         rectangle.push_back( i );
132     }
133     point_list texs = calc_tex_coords( b, geod_nodes, rectangle, 
134                                        1000.0 / tex_width );
135
136     // Allocate ssg structure
137     ssgVertexArray   *vl = new ssgVertexArray( 4 );
138     ssgNormalArray   *nl = new ssgNormalArray( 4 );
139     ssgTexCoordArray *tl = new ssgTexCoordArray( 4 );
140     ssgColourArray   *cl = new ssgColourArray( 1 );
141
142     sgVec4 color;
143     sgSetVec4( color, 1.0, 1.0, 1.0, 1.0 );
144     cl->add( color );
145
146     // sgVec3 *vtlist = new sgVec3 [ 4 ];
147     // t->vec3_ptrs.push_back( vtlist );
148     // sgVec3 *vnlist = new sgVec3 [ 4 ];
149     // t->vec3_ptrs.push_back( vnlist );
150     // sgVec2 *tclist = new sgVec2 [ 4 ];
151     // t->vec2_ptrs.push_back( tclist );
152
153     sgVec2 tmp2;
154     sgVec3 tmp3;
155     for ( i = 0; i < 4; ++i ) {
156         sgSetVec3( tmp3, 
157                    rel[i].x(), rel[i].y(), rel[i].z() );
158         vl->add( tmp3 );
159
160         sgSetVec3( tmp3, 
161                    normals[i].x(), normals[i].y(), normals[i].z() );
162         nl->add( tmp3 );
163
164         sgSetVec2( tmp2, texs[i].x(), texs[i].y());
165         tl->add( tmp2 );
166     }
167     
168     ssgLeaf *leaf = 
169         new ssgVtxTable ( GL_TRIANGLE_FAN, vl, nl, tl, cl );
170
171     leaf->setState( state );
172
173     geometry->addKid( leaf );
174
175     return true;
176 }
177
178
179 /**
180  * SSG callback for an in-range leaf of randomly-placed objects.
181  *
182  * This pretraversal callback is attached to a branch that is
183  * traversed only when a leaf is in range.  If the leaf is not
184  * currently prepared to be populated with randomly-placed objects,
185  * this callback will prepare it (actual population is handled by
186  * the tri_in_range_callback for individual triangles).
187  *
188  * @param entity The entity to which the callback is attached (not used).
189  * @param mask The entity's traversal mask (not used).
190  * @return Always 1, to allow traversal and culling to continue.
191  */
192 static int
193 leaf_in_range_callback (ssgEntity * entity, int mask)
194 {
195   SGLeafUserData * data = (SGLeafUserData *)entity->getUserData();
196
197   if (!data->is_filled_in) {
198                                 // Iterate through all the triangles
199                                 // and populate them.
200     int num_tris = data->leaf->getNumTriangles();
201     for ( int i = 0; i < num_tris; ++i ) {
202             data->setup_triangle(i);
203     }
204     data->is_filled_in = true;
205   }
206   return 1;
207 }
208
209
210 /**
211  * SSG callback for an out-of-range leaf of randomly-placed objects.
212  *
213  * This pretraversal callback is attached to a branch that is
214  * traversed only when a leaf is out of range.  If the leaf is
215  * currently prepared to be populated with randomly-placed objects (or
216  * is actually populated), the objects will be removed.
217  *
218  * @param entity The entity to which the callback is attached (not used).
219  * @param mask The entity's traversal mask (not used).
220  * @return Always 0, to prevent any further traversal or culling.
221  */
222 static int
223 leaf_out_of_range_callback (ssgEntity * entity, int mask)
224 {
225   SGLeafUserData * data = (SGLeafUserData *)entity->getUserData();
226   if (data->is_filled_in) {
227     data->branch->removeAllKids();
228     data->is_filled_in = false;
229   }
230   return 0;
231 }
232
233
234 /**
235  * Randomly place objects on a surface.
236  *
237  * The leaf node provides the geometry of the surface, while the
238  * material provides the objects and placement density.  Latitude
239  * and longitude are required so that the objects can be rotated
240  * to the world-up vector.  This function does not actually add
241  * any objects; instead, it attaches an ssgRangeSelector to the
242  * branch with callbacks to generate the objects when needed.
243  *
244  * @param leaf The surface where the objects should be placed.
245  * @param branch The branch that will hold the randomly-placed objects.
246  * @param center The center of the leaf in FlightGear coordinates.
247  * @param material_name The name of the surface's material.
248  */
249 static void
250 gen_random_surface_objects (ssgLeaf *leaf,
251                             ssgBranch *branch,
252                             Point3D *center,
253                             SGMaterial *mat )
254 {
255                                 // If the surface has no triangles, return
256                                 // now.
257     int num_tris = leaf->getNumTriangles();
258     if (num_tris < 1)
259         return;
260
261                                 // If the material has no randomly-placed
262                                 // objects, return now.
263     if (mat->get_object_group_count() < 1)
264         return;
265
266                                 // Calculate the geodetic centre of
267                                 // the tile, for aligning automatic
268                                 // objects.
269     double lon_deg, lat_rad, lat_deg, alt_m, sl_radius_m;
270     Point3D geoc = sgCartToPolar3d(*center);
271     lon_deg = geoc.lon() * SGD_RADIANS_TO_DEGREES;
272     sgGeocToGeod(geoc.lat(), geoc.radius(),
273                  &lat_rad, &alt_m, &sl_radius_m);
274     lat_deg = lat_rad * SGD_RADIANS_TO_DEGREES;
275
276                                 // LOD for the leaf
277                                 // max random object range: 20000m
278     float ranges[] = { 0, 20000, 1000000 };
279     ssgRangeSelector * lod = new ssgRangeSelector;
280     lod->setRanges(ranges, 3);
281     branch->addKid(lod);
282
283                                 // Create the in-range and out-of-range
284                                 // branches.
285     ssgBranch * in_range = new ssgBranch;
286     ssgBranch * out_of_range = new ssgBranch;
287     lod->addKid(in_range);
288     lod->addKid(out_of_range);
289
290     SGLeafUserData * data = new SGLeafUserData;
291     data->is_filled_in = false;
292     data->leaf = leaf;
293     data->mat = mat;
294     data->branch = in_range;
295     data->sin_lat = sin(lat_deg * SGD_DEGREES_TO_RADIANS);
296     data->cos_lat = cos(lat_deg * SGD_DEGREES_TO_RADIANS);
297     data->sin_lon = sin(lon_deg * SGD_DEGREES_TO_RADIANS);
298     data->cos_lon = cos(lon_deg * SGD_DEGREES_TO_RADIANS);
299
300     in_range->setUserData(data);
301     in_range->setTravCallback(SSG_CALLBACK_PRETRAV, leaf_in_range_callback);
302     out_of_range->setUserData(data);
303     out_of_range->setTravCallback(SSG_CALLBACK_PRETRAV,
304                                    leaf_out_of_range_callback);
305     out_of_range
306       ->addKid(new SGDummyBSphereEntity(leaf->getBSphere()->getRadius()));
307 }
308
309
310 \f
311 ////////////////////////////////////////////////////////////////////////
312 // Scenery loaders.
313 ////////////////////////////////////////////////////////////////////////
314
315 // Load an Binary obj file
316 bool sgBinObjLoad( const string& path, const bool is_base,
317                    Point3D *center,
318                    double *bounding_radius,
319                    SGMaterialLib *matlib,
320                    bool use_random_objects,
321                    ssgBranch* geometry,
322                    ssgBranch* rwy_lights,
323                    ssgBranch* taxi_lights,
324                    ssgVertexArray *ground_lights )
325 {
326     SGBinObject obj;
327
328     if ( ! obj.read_bin( path ) ) {
329         return false;
330     }
331
332     geometry->setName( (char *)path.c_str() );
333
334     // reference point (center offset/bounding sphere)
335     *center = obj.get_gbs_center();
336     *bounding_radius = obj.get_gbs_radius();
337
338     point_list const& nodes = obj.get_wgs84_nodes();
339     // point_list const& colors = obj.get_colors();
340     point_list const& normals = obj.get_normals();
341     point_list const& texcoords = obj.get_texcoords();
342
343     string material;
344     int_list tex_index;
345
346     group_list::size_type i;
347
348     // generate points
349     string_list const& pt_materials = obj.get_pt_materials();
350     group_list const& pts_v = obj.get_pts_v();
351     group_list const& pts_n = obj.get_pts_n();
352     for ( i = 0; i < pts_v.size(); ++i ) {
353         // cout << "pts_v.size() = " << pts_v.size() << endl;
354         if ( pt_materials[i].substr(0, 3) == "RWY" ) {
355             sgVec3 up;
356             sgSetVec3( up, center->x(), center->y(), center->z() );
357             // returns a transform -> lod -> leaf structure
358             ssgBranch *branch = sgMakeDirectionalLights( nodes, normals,
359                                                          pts_v[i], pts_n[i],
360                                                          matlib,
361                                                          pt_materials[i], up );
362             if ( pt_materials[i].substr(0, 16) == "RWY_BLUE_TAXIWAY" ) {
363                 taxi_lights->addKid( branch );
364             } else {
365                 rwy_lights->addKid( branch );
366             }
367         } else {
368             material = pt_materials[i];
369             tex_index.clear();
370             ssgLeaf *leaf = sgMakeLeaf( path, GL_POINTS, matlib, material,
371                                         nodes, normals, texcoords,
372                                         pts_v[i], pts_n[i], tex_index,
373                                         false, ground_lights );
374             geometry->addKid( leaf );
375         }
376     }
377
378     // Put all randomly-placed objects under a separate branch
379     // (actually an ssgRangeSelector) named "random-models".
380     ssgBranch * random_object_branch = 0;
381     if (use_random_objects) {
382         float ranges[] = { 0, 20000 }; // Maximum 20km range for random objects
383         ssgRangeSelector * object_lod = new ssgRangeSelector;
384         object_lod->setRanges(ranges, 2);
385         object_lod->setName("random-models");
386         geometry->addKid(object_lod);
387         random_object_branch = new ssgBranch;
388         object_lod->addKid(random_object_branch);
389     }
390
391     // generate triangles
392     string_list const& tri_materials = obj.get_tri_materials();
393     group_list const& tris_v = obj.get_tris_v();
394     group_list const& tris_n = obj.get_tris_n();
395     group_list const& tris_tc = obj.get_tris_tc();
396     for ( i = 0; i < tris_v.size(); ++i ) {
397         ssgLeaf *leaf = sgMakeLeaf( path, GL_TRIANGLES, matlib,
398                                     tri_materials[i],
399                                     nodes, normals, texcoords,
400                                     tris_v[i], tris_n[i], tris_tc[i],
401                                     is_base, ground_lights );
402
403         if ( use_random_objects ) {
404             SGMaterial *mat = matlib->find( tri_materials[i] );
405             if ( mat == NULL ) {
406                 SG_LOG( SG_INPUT, SG_ALERT,
407                         "Unknown material for random surface objects = "
408                         << tri_materials[i] );
409             } else {
410                 gen_random_surface_objects( leaf, random_object_branch,
411                                             center, mat );
412             }
413         }
414         geometry->addKid( leaf );
415     }
416
417     // generate strips
418     string_list const& strip_materials = obj.get_strip_materials();
419     group_list const& strips_v = obj.get_strips_v();
420     group_list const& strips_n = obj.get_strips_n();
421     group_list const& strips_tc = obj.get_strips_tc();
422     for ( i = 0; i < strips_v.size(); ++i ) {
423         ssgLeaf *leaf = sgMakeLeaf( path, GL_TRIANGLE_STRIP,
424                                     matlib, strip_materials[i],
425                                     nodes, normals, texcoords,
426                                     strips_v[i], strips_n[i], strips_tc[i],
427                                     is_base, ground_lights );
428
429         if ( use_random_objects ) {
430             SGMaterial *mat = matlib->find( strip_materials[i] );
431             if ( mat == NULL ) {
432                 SG_LOG( SG_INPUT, SG_ALERT,
433                         "Unknown material for random surface objects = "
434                         << strip_materials[i] );
435             } else {
436                 gen_random_surface_objects( leaf, random_object_branch,
437                                             center, mat );
438             }
439         }
440         geometry->addKid( leaf );
441     }
442
443     // generate fans
444     string_list const& fan_materials = obj.get_fan_materials();
445     group_list const& fans_v = obj.get_fans_v();
446     group_list const& fans_n = obj.get_fans_n();
447     group_list const& fans_tc = obj.get_fans_tc();
448     for ( i = 0; i < fans_v.size(); ++i ) {
449         ssgLeaf *leaf = sgMakeLeaf( path, GL_TRIANGLE_FAN,
450                                     matlib, fan_materials[i],
451                                     nodes, normals, texcoords,
452                                     fans_v[i], fans_n[i], fans_tc[i],
453                                     is_base, ground_lights );
454         if ( use_random_objects ) {
455             SGMaterial *mat = matlib->find( fan_materials[i] );
456             if ( mat == NULL ) {
457                 SG_LOG( SG_INPUT, SG_ALERT,
458                         "Unknown material for random surface objects = "
459                         << fan_materials[i] );
460             } else {
461                 gen_random_surface_objects( leaf, random_object_branch,
462                                             center, mat );
463             }
464         }
465
466         geometry->addKid( leaf );
467     }
468
469     return true;
470 }