1998-08-25 16:51:22 +00:00
|
|
|
|
// obj.cxx -- routines to handle "sorta" WaveFront .obj format files.
|
|
|
|
|
//
|
|
|
|
|
// Written by Curtis Olson, started October 1997.
|
|
|
|
|
//
|
|
|
|
|
// Copyright (C) 1997 Curtis L. Olson - curt@infoplane.com
|
|
|
|
|
//
|
|
|
|
|
// This program is free software; you can redistribute it and/or
|
|
|
|
|
// modify it under the terms of the GNU General Public License as
|
|
|
|
|
// published by the Free Software Foundation; either version 2 of the
|
|
|
|
|
// License, or (at your option) any later version.
|
|
|
|
|
//
|
|
|
|
|
// This program is distributed in the hope that it will be useful, but
|
|
|
|
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
|
// General Public License for more details.
|
|
|
|
|
//
|
|
|
|
|
// You should have received a copy of the GNU General Public License
|
|
|
|
|
// along with this program; if not, write to the Free Software
|
|
|
|
|
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
|
|
|
//
|
|
|
|
|
// $Id$
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
|
# include <config.h>
|
|
|
|
|
#endif
|
|
|
|
|
|
2001-03-23 22:42:49 +00:00
|
|
|
|
#ifdef SG_MATH_EXCEPTION_CLASH
|
1999-05-08 02:33:13 +00:00
|
|
|
|
# include <math.h>
|
|
|
|
|
#endif
|
|
|
|
|
|
1998-08-25 16:51:22 +00:00
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
|
2000-02-15 03:30:01 +00:00
|
|
|
|
#include <simgear/compiler.h>
|
2002-07-20 19:23:44 +00:00
|
|
|
|
#include <simgear/sg_inlines.h>
|
2001-01-05 01:07:10 +00:00
|
|
|
|
#include <simgear/io/sg_binobj.hxx>
|
1998-08-25 16:51:22 +00:00
|
|
|
|
|
1999-02-26 22:08:34 +00:00
|
|
|
|
#include STL_STRING
|
1999-06-28 00:02:52 +00:00
|
|
|
|
#include <map> // STL
|
|
|
|
|
#include <vector> // STL
|
|
|
|
|
#include <ctype.h> // isdigit()
|
1998-08-25 16:51:22 +00:00
|
|
|
|
|
2000-02-15 03:30:01 +00:00
|
|
|
|
#include <simgear/constants.h>
|
2000-02-16 23:01:03 +00:00
|
|
|
|
#include <simgear/debug/logstream.hxx>
|
|
|
|
|
#include <simgear/math/point3d.hxx>
|
|
|
|
|
#include <simgear/math/polar3d.hxx>
|
2000-09-27 20:16:22 +00:00
|
|
|
|
#include <simgear/math/sg_geodesy.hxx>
|
2000-12-04 05:23:06 +00:00
|
|
|
|
#include <simgear/math/sg_random.h>
|
2001-03-25 14:20:12 +00:00
|
|
|
|
#include <simgear/misc/sgstream.hxx>
|
2000-02-16 23:01:03 +00:00
|
|
|
|
#include <simgear/misc/stopwatch.hxx>
|
|
|
|
|
#include <simgear/misc/texcoord.hxx>
|
2000-02-15 03:30:01 +00:00
|
|
|
|
|
2000-10-19 21:24:43 +00:00
|
|
|
|
#include <Main/globals.hxx>
|
2001-01-13 22:06:39 +00:00
|
|
|
|
#include <Main/fg_props.hxx>
|
2002-07-15 18:16:20 +00:00
|
|
|
|
#include <Time/light.hxx>
|
1999-06-12 21:11:21 +00:00
|
|
|
|
#include <Scenery/tileentry.hxx>
|
1998-08-25 16:51:22 +00:00
|
|
|
|
|
2002-07-15 18:16:20 +00:00
|
|
|
|
#include "newmat.hxx"
|
2000-06-23 00:30:04 +00:00
|
|
|
|
#include "matlib.hxx"
|
1998-08-25 16:51:22 +00:00
|
|
|
|
#include "obj.hxx"
|
|
|
|
|
|
2001-03-23 22:59:18 +00:00
|
|
|
|
SG_USING_STD(string);
|
|
|
|
|
SG_USING_STD(vector);
|
1999-06-28 00:02:52 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
typedef vector < int > int_list;
|
|
|
|
|
typedef int_list::iterator int_list_iterator;
|
|
|
|
|
typedef int_list::const_iterator int_point_list_iterator;
|
1999-03-02 01:02:31 +00:00
|
|
|
|
|
1998-08-25 16:51:22 +00:00
|
|
|
|
|
1999-05-03 11:41:09 +00:00
|
|
|
|
static double normals[FG_MAX_NODES][3];
|
1999-05-12 02:07:21 +00:00
|
|
|
|
static double tex_coords[FG_MAX_NODES*3][3];
|
1998-08-25 16:51:22 +00:00
|
|
|
|
|
2002-07-15 18:16:20 +00:00
|
|
|
|
static int
|
|
|
|
|
runway_lights_predraw (ssgEntity * e)
|
|
|
|
|
{
|
|
|
|
|
// Turn on lights only at night
|
|
|
|
|
float sun_angle = cur_light_params.sun_angle * SGD_RADIANS_TO_DEGREES;
|
|
|
|
|
return int(sun_angle > 90.0);
|
|
|
|
|
}
|
|
|
|
|
|
1998-08-25 16:51:22 +00:00
|
|
|
|
|
1998-10-20 18:33:55 +00:00
|
|
|
|
#define FG_TEX_CONSTANT 69.0
|
1998-08-25 16:51:22 +00:00
|
|
|
|
|
|
|
|
|
// Calculate texture coordinates for a given point.
|
1999-10-27 00:51:42 +00:00
|
|
|
|
static Point3D local_calc_tex_coords(const Point3D& node, const Point3D& ref) {
|
1998-10-16 00:51:46 +00:00
|
|
|
|
Point3D cp;
|
|
|
|
|
Point3D pp;
|
1998-10-20 18:33:55 +00:00
|
|
|
|
// double tmplon, tmplat;
|
|
|
|
|
|
|
|
|
|
// cout << "-> " << node[0] << " " << node[1] << " " << node[2] << endl;
|
|
|
|
|
// cout << "-> " << ref.x() << " " << ref.y() << " " << ref.z() << endl;
|
1998-08-25 16:51:22 +00:00
|
|
|
|
|
1998-10-18 01:17:16 +00:00
|
|
|
|
cp = Point3D( node[0] + ref.x(),
|
|
|
|
|
node[1] + ref.y(),
|
|
|
|
|
node[2] + ref.z() );
|
1998-08-25 16:51:22 +00:00
|
|
|
|
|
2000-09-27 20:16:22 +00:00
|
|
|
|
pp = sgCartToPolar3d(cp);
|
1998-08-25 16:51:22 +00:00
|
|
|
|
|
2001-03-24 04:48:44 +00:00
|
|
|
|
// tmplon = pp.lon() * SGD_RADIANS_TO_DEGREES;
|
|
|
|
|
// tmplat = pp.lat() * SGD_RADIANS_TO_DEGREES;
|
1998-10-20 18:33:55 +00:00
|
|
|
|
// cout << tmplon << " " << tmplat << endl;
|
1998-10-18 01:17:16 +00:00
|
|
|
|
|
2001-03-24 04:48:44 +00:00
|
|
|
|
pp.setx( fmod(SGD_RADIANS_TO_DEGREES * FG_TEX_CONSTANT * pp.x(), 11.0) );
|
|
|
|
|
pp.sety( fmod(SGD_RADIANS_TO_DEGREES * FG_TEX_CONSTANT * pp.y(), 11.0) );
|
1998-08-25 16:51:22 +00:00
|
|
|
|
|
1998-10-16 00:51:46 +00:00
|
|
|
|
if ( pp.x() < 0.0 ) {
|
1998-10-20 18:33:55 +00:00
|
|
|
|
pp.setx( pp.x() + 11.0 );
|
1998-09-15 01:35:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
1998-10-16 00:51:46 +00:00
|
|
|
|
if ( pp.y() < 0.0 ) {
|
1998-10-20 18:33:55 +00:00
|
|
|
|
pp.sety( pp.y() + 11.0 );
|
1998-09-15 01:35:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
1998-10-20 18:33:55 +00:00
|
|
|
|
// cout << pp << endl;
|
|
|
|
|
|
1998-08-25 16:51:22 +00:00
|
|
|
|
return(pp);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2002-03-03 20:29:31 +00:00
|
|
|
|
// Generate an ocean tile
|
|
|
|
|
bool fgGenTile( const string& path, SGBucket b,
|
|
|
|
|
Point3D *center,
|
|
|
|
|
double *bounding_radius,
|
|
|
|
|
ssgBranch* geometry )
|
|
|
|
|
{
|
2000-06-23 00:30:04 +00:00
|
|
|
|
FGNewMat *newmat;
|
1999-08-31 23:23:04 +00:00
|
|
|
|
|
|
|
|
|
ssgSimpleState *state = NULL;
|
|
|
|
|
|
2002-03-03 20:29:31 +00:00
|
|
|
|
geometry -> setName ( (char *)path.c_str() ) ;
|
1999-08-31 23:23:04 +00:00
|
|
|
|
|
2000-06-23 00:30:04 +00:00
|
|
|
|
double tex_width = 1000.0;
|
|
|
|
|
// double tex_height;
|
|
|
|
|
|
1999-08-31 23:23:04 +00:00
|
|
|
|
// find Ocean material in the properties list
|
2000-06-23 00:30:04 +00:00
|
|
|
|
newmat = material_lib.find( "Ocean" );
|
|
|
|
|
if ( newmat != NULL ) {
|
|
|
|
|
// set the texture width and height values for this
|
|
|
|
|
// material
|
|
|
|
|
tex_width = newmat->get_xsize();
|
|
|
|
|
// tex_height = newmat->get_ysize();
|
|
|
|
|
|
|
|
|
|
// set ssgState
|
|
|
|
|
state = newmat->get_state();
|
|
|
|
|
} else {
|
2001-03-24 06:03:11 +00:00
|
|
|
|
SG_LOG( SG_TERRAIN, SG_ALERT,
|
1999-08-31 23:23:04 +00:00
|
|
|
|
"Ack! unknown usemtl name = " << "Ocean"
|
|
|
|
|
<< " in " << path );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Calculate center point
|
|
|
|
|
double clon = b.get_center_lon();
|
|
|
|
|
double clat = b.get_center_lat();
|
|
|
|
|
double height = b.get_height();
|
|
|
|
|
double width = b.get_width();
|
|
|
|
|
|
2002-03-03 20:29:31 +00:00
|
|
|
|
*center = sgGeodToCart( Point3D(clon*SGD_DEGREES_TO_RADIANS,
|
|
|
|
|
clat*SGD_DEGREES_TO_RADIANS,
|
|
|
|
|
0.0) );
|
1999-08-31 23:23:04 +00:00
|
|
|
|
// cout << "center = " << center << endl;;
|
|
|
|
|
|
|
|
|
|
// Caculate corner vertices
|
|
|
|
|
Point3D geod[4];
|
|
|
|
|
geod[0] = Point3D( clon - width/2.0, clat - height/2.0, 0.0 );
|
|
|
|
|
geod[1] = Point3D( clon + width/2.0, clat - height/2.0, 0.0 );
|
|
|
|
|
geod[2] = Point3D( clon + width/2.0, clat + height/2.0, 0.0 );
|
|
|
|
|
geod[3] = Point3D( clon - width/2.0, clat + height/2.0, 0.0 );
|
|
|
|
|
|
|
|
|
|
Point3D rad[4];
|
1999-09-28 22:44:08 +00:00
|
|
|
|
int i;
|
|
|
|
|
for ( i = 0; i < 4; ++i ) {
|
2002-02-28 00:10:35 +00:00
|
|
|
|
rad[i] = Point3D( geod[i].x() * SGD_DEGREES_TO_RADIANS,
|
|
|
|
|
geod[i].y() * SGD_DEGREES_TO_RADIANS,
|
|
|
|
|
geod[i].z() );
|
1999-08-31 23:23:04 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Point3D cart[4], rel[4];
|
1999-09-28 22:44:08 +00:00
|
|
|
|
for ( i = 0; i < 4; ++i ) {
|
2000-09-27 20:16:22 +00:00
|
|
|
|
cart[i] = sgGeodToCart(rad[i]);
|
2002-03-03 20:29:31 +00:00
|
|
|
|
rel[i] = cart[i] - *center;
|
1999-08-31 23:23:04 +00:00
|
|
|
|
// cout << "corner " << i << " = " << cart[i] << endl;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Calculate bounding radius
|
2002-03-03 20:29:31 +00:00
|
|
|
|
*bounding_radius = center->distance3D( cart[0] );
|
1999-08-31 23:23:04 +00:00
|
|
|
|
// cout << "bounding radius = " << t->bounding_radius << endl;
|
|
|
|
|
|
|
|
|
|
// Calculate normals
|
|
|
|
|
Point3D normals[4];
|
1999-09-28 22:44:08 +00:00
|
|
|
|
for ( i = 0; i < 4; ++i ) {
|
2002-02-28 00:10:35 +00:00
|
|
|
|
double length = cart[i].distance3D( Point3D(0.0) );
|
|
|
|
|
normals[i] = cart[i] / length;
|
1999-08-31 23:23:04 +00:00
|
|
|
|
// cout << "normal = " << normals[i] << endl;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Calculate texture coordinates
|
1999-10-27 00:51:42 +00:00
|
|
|
|
point_list geod_nodes;
|
|
|
|
|
geod_nodes.clear();
|
|
|
|
|
int_list rectangle;
|
|
|
|
|
rectangle.clear();
|
1999-09-28 22:44:08 +00:00
|
|
|
|
for ( i = 0; i < 4; ++i ) {
|
2002-02-28 00:10:35 +00:00
|
|
|
|
geod_nodes.push_back( geod[i] );
|
1999-10-27 00:51:42 +00:00
|
|
|
|
rectangle.push_back( i );
|
1999-08-31 23:23:04 +00:00
|
|
|
|
}
|
1999-10-27 00:51:42 +00:00
|
|
|
|
point_list texs = calc_tex_coords( b, geod_nodes, rectangle,
|
|
|
|
|
1000.0 / tex_width );
|
1999-08-31 23:23:04 +00:00
|
|
|
|
|
1999-10-27 00:51:42 +00:00
|
|
|
|
// Allocate ssg structure
|
2000-02-20 05:19:15 +00:00
|
|
|
|
ssgVertexArray *vl = new ssgVertexArray( 4 );
|
|
|
|
|
ssgNormalArray *nl = new ssgNormalArray( 4 );
|
|
|
|
|
ssgTexCoordArray *tl = new ssgTexCoordArray( 4 );
|
2000-03-17 06:16:15 +00:00
|
|
|
|
ssgColourArray *cl = new ssgColourArray( 1 );
|
|
|
|
|
|
|
|
|
|
sgVec4 color;
|
|
|
|
|
sgSetVec4( color, 1.0, 1.0, 1.0, 1.0 );
|
|
|
|
|
cl->add( color );
|
2000-02-20 05:19:15 +00:00
|
|
|
|
|
|
|
|
|
// sgVec3 *vtlist = new sgVec3 [ 4 ];
|
|
|
|
|
// t->vec3_ptrs.push_back( vtlist );
|
|
|
|
|
// sgVec3 *vnlist = new sgVec3 [ 4 ];
|
|
|
|
|
// t->vec3_ptrs.push_back( vnlist );
|
|
|
|
|
// sgVec2 *tclist = new sgVec2 [ 4 ];
|
|
|
|
|
// t->vec2_ptrs.push_back( tclist );
|
|
|
|
|
|
|
|
|
|
sgVec2 tmp2;
|
|
|
|
|
sgVec3 tmp3;
|
1999-09-28 22:44:08 +00:00
|
|
|
|
for ( i = 0; i < 4; ++i ) {
|
2000-02-20 05:19:15 +00:00
|
|
|
|
sgSetVec3( tmp3,
|
1999-08-31 23:23:04 +00:00
|
|
|
|
rel[i].x(), rel[i].y(), rel[i].z() );
|
2000-02-20 05:19:15 +00:00
|
|
|
|
vl->add( tmp3 );
|
|
|
|
|
|
|
|
|
|
sgSetVec3( tmp3,
|
1999-08-31 23:23:04 +00:00
|
|
|
|
normals[i].x(), normals[i].y(), normals[i].z() );
|
2000-02-20 05:19:15 +00:00
|
|
|
|
nl->add( tmp3 );
|
|
|
|
|
|
|
|
|
|
sgSetVec2( tmp2, texs[i].x(), texs[i].y());
|
|
|
|
|
tl->add( tmp2 );
|
1999-08-31 23:23:04 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ssgLeaf *leaf =
|
2000-03-17 06:16:15 +00:00
|
|
|
|
new ssgVtxTable ( GL_TRIANGLE_FAN, vl, nl, tl, cl );
|
2000-02-20 05:19:15 +00:00
|
|
|
|
|
1999-08-31 23:23:04 +00:00
|
|
|
|
leaf->setState( state );
|
|
|
|
|
|
2002-03-03 20:29:31 +00:00
|
|
|
|
geometry->addKid( leaf );
|
1999-08-31 23:23:04 +00:00
|
|
|
|
|
2002-03-03 20:29:31 +00:00
|
|
|
|
return true;
|
1999-08-31 23:23:04 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2000-12-04 22:35:38 +00:00
|
|
|
|
static void random_pt_inside_tri( float *res,
|
|
|
|
|
float *n1, float *n2, float *n3 )
|
|
|
|
|
{
|
2000-12-04 05:23:06 +00:00
|
|
|
|
sgVec3 p1, p2, p3;
|
|
|
|
|
|
2000-12-04 22:35:38 +00:00
|
|
|
|
double a = sg_random();
|
|
|
|
|
double b = sg_random();
|
|
|
|
|
if ( a + b > 1.0 ) {
|
|
|
|
|
a = 1.0 - a;
|
|
|
|
|
b = 1.0 - b;
|
|
|
|
|
}
|
|
|
|
|
double c = 1 - a - b;
|
2000-12-04 05:23:06 +00:00
|
|
|
|
|
2000-12-04 22:35:38 +00:00
|
|
|
|
sgScaleVec3( p1, n1, a );
|
|
|
|
|
sgScaleVec3( p2, n2, b );
|
|
|
|
|
sgScaleVec3( p3, n3, c );
|
|
|
|
|
|
|
|
|
|
sgAddVec3( res, p1, p2 );
|
|
|
|
|
sgAddVec3( res, p3 );
|
|
|
|
|
}
|
2000-12-04 05:23:06 +00:00
|
|
|
|
|
|
|
|
|
|
2000-12-04 22:35:38 +00:00
|
|
|
|
static void gen_random_surface_points( ssgLeaf *leaf, ssgVertexArray *lights,
|
|
|
|
|
double factor ) {
|
|
|
|
|
int num = leaf->getNumTriangles();
|
2000-12-06 22:16:12 +00:00
|
|
|
|
if ( num > 0 ) {
|
|
|
|
|
short int n1, n2, n3;
|
|
|
|
|
float *p1, *p2, *p3;
|
|
|
|
|
sgVec3 result;
|
|
|
|
|
|
|
|
|
|
// generate a repeatable random seed
|
|
|
|
|
p1 = leaf->getVertex( 0 );
|
2001-07-08 23:38:16 +00:00
|
|
|
|
unsigned int seed = (unsigned int)p1[0];
|
|
|
|
|
sg_srandom( seed );
|
2000-12-06 22:16:12 +00:00
|
|
|
|
|
|
|
|
|
for ( int i = 0; i < num; ++i ) {
|
|
|
|
|
leaf->getTriangle( i, &n1, &n2, &n3 );
|
|
|
|
|
p1 = leaf->getVertex(n1);
|
|
|
|
|
p2 = leaf->getVertex(n2);
|
|
|
|
|
p3 = leaf->getVertex(n3);
|
2001-07-08 23:38:16 +00:00
|
|
|
|
double area = sgTriArea( p1, p2, p3 );
|
2000-12-06 22:16:12 +00:00
|
|
|
|
double num = area / factor;
|
|
|
|
|
|
|
|
|
|
// generate a light point for each unit of area
|
|
|
|
|
while ( num > 1.0 ) {
|
2000-12-04 22:35:38 +00:00
|
|
|
|
random_pt_inside_tri( result, p1, p2, p3 );
|
|
|
|
|
lights->add( result );
|
2000-12-06 22:16:12 +00:00
|
|
|
|
num -= 1.0;
|
|
|
|
|
}
|
|
|
|
|
// for partial units of area, use a zombie door method to
|
|
|
|
|
// create the proper random chance of a light being created
|
|
|
|
|
// for this triangle
|
|
|
|
|
if ( num > 0.0 ) {
|
|
|
|
|
if ( sg_random() <= num ) {
|
|
|
|
|
// a zombie made it through our door
|
|
|
|
|
random_pt_inside_tri( result, p1, p2, p3 );
|
|
|
|
|
lights->add( result );
|
|
|
|
|
}
|
2000-12-04 22:35:38 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2000-12-04 05:23:06 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
Randomly-place object overhaul and enhancements
-----------------------------------------------
Fixed a segfault on exit.
Changed the radius of the dummy bounding sphere from 10m to 1000m to
ensure that FOV culling doesn't leave anything out.
Allow an object to have more than one variant model, which will be
chosen randomly. Simply repeat the <path>...</path> property.
Removed the <billboard> property and replaced it with <heading-type>,
which can be set to "fixed" (leave the model oriented as it is),
"random" (give the model a random heading between 0 and 359 deg), or
"billboard" (always turn the model to face the camera). The default
is "fixed". Models look much better when they are not all facing the
same direction.
Allow the user to group models with the same visual range, so that
there can be *many* fewer nodes in the scene graph when the models are
not visible. This causes an XML-format change, so that instead of
<object>
<range-m>...</range-m>
...
</object>
<object>
<range-m>...</range-m>
...
</object>
...
we now have
<object-group>
<range-m>...</range-m>
<object>
...
</object>
<object>
...
</object>
...
</object-group>
Every object in a group can still have its own model(s), coverage, and
heading-type, but they all share the same range selector.
This change should already help users with tight memory constraints,
but it will matter much more when we add more object types -- for
example, we can now add dozens of different urban building types
without bloating the scene graph or slowing down the LOD tests for
tris that are out of range (i.e. most of them).
2002-07-20 14:56:37 +00:00
|
|
|
|
/**
|
|
|
|
|
* Create a rotation matrix to align an object for the current lat/lon.
|
|
|
|
|
*
|
|
|
|
|
* By default, objects are aligned for the north pole. This code
|
|
|
|
|
* calculates a matrix to rotate them for the surface of the earth in
|
|
|
|
|
* the current location.
|
|
|
|
|
*
|
|
|
|
|
* TODO: there should be a single version of this method somewhere
|
|
|
|
|
* for all of SimGear.
|
|
|
|
|
*
|
|
|
|
|
* @param ROT The resulting rotation matrix.
|
|
|
|
|
* @param hdg_deg The object heading in degrees.
|
|
|
|
|
* @param lon_deg The longitude in degrees.
|
|
|
|
|
* @param lat_deg The latitude in degrees.
|
|
|
|
|
*/
|
|
|
|
|
static void
|
|
|
|
|
makeWorldUpRotationMatrix (sgMat4 ROT, double hdg_deg,
|
|
|
|
|
double lon_deg, double lat_deg)
|
|
|
|
|
{
|
|
|
|
|
SGfloat sin_lat = sin( lat_deg * SGD_DEGREES_TO_RADIANS );
|
|
|
|
|
SGfloat cos_lat = cos( lat_deg * SGD_DEGREES_TO_RADIANS );
|
|
|
|
|
SGfloat sin_lon = sin( lon_deg * SGD_DEGREES_TO_RADIANS );
|
|
|
|
|
SGfloat cos_lon = cos( lon_deg * SGD_DEGREES_TO_RADIANS );
|
|
|
|
|
SGfloat sin_hdg = sin( hdg_deg * SGD_DEGREES_TO_RADIANS ) ;
|
|
|
|
|
SGfloat cos_hdg = cos( hdg_deg * SGD_DEGREES_TO_RADIANS ) ;
|
|
|
|
|
|
|
|
|
|
ROT[0][0] = cos_hdg * sin_lat * cos_lon - sin_hdg * sin_lon;
|
|
|
|
|
ROT[0][1] = cos_hdg * sin_lat * sin_lon + sin_hdg * cos_lon;
|
|
|
|
|
ROT[0][2] = -cos_hdg * cos_lat;
|
|
|
|
|
ROT[0][3] = SG_ZERO;
|
|
|
|
|
|
|
|
|
|
ROT[1][0] = -sin_hdg * sin_lat * cos_lon - cos_hdg * sin_lon;
|
|
|
|
|
ROT[1][1] = -sin_hdg * sin_lat * sin_lon + cos_hdg * cos_lon;
|
|
|
|
|
ROT[1][2] = sin_hdg * cos_lat;
|
|
|
|
|
ROT[1][3] = SG_ZERO;
|
|
|
|
|
|
|
|
|
|
ROT[2][0] = cos_lat * cos_lon;
|
|
|
|
|
ROT[2][1] = cos_lat * sin_lon;
|
|
|
|
|
ROT[2][2] = sin_lat;
|
|
|
|
|
ROT[2][3] = SG_ZERO;
|
|
|
|
|
|
|
|
|
|
ROT[3][0] = SG_ZERO;
|
|
|
|
|
ROT[3][1] = SG_ZERO;
|
|
|
|
|
ROT[3][2] = SG_ZERO;
|
|
|
|
|
ROT[3][3] = SG_ONE ;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2002-07-16 23:39:53 +00:00
|
|
|
|
/**
|
|
|
|
|
* Add an object to a random location inside a triangle.
|
|
|
|
|
*
|
|
|
|
|
* @param p1 The first vertex of the triangle.
|
|
|
|
|
* @param p2 The second vertex of the triangle.
|
|
|
|
|
* @param p3 The third vertex of the triangle.
|
|
|
|
|
* @param center The center of the triangle.
|
Randomly-place object overhaul and enhancements
-----------------------------------------------
Fixed a segfault on exit.
Changed the radius of the dummy bounding sphere from 10m to 1000m to
ensure that FOV culling doesn't leave anything out.
Allow an object to have more than one variant model, which will be
chosen randomly. Simply repeat the <path>...</path> property.
Removed the <billboard> property and replaced it with <heading-type>,
which can be set to "fixed" (leave the model oriented as it is),
"random" (give the model a random heading between 0 and 359 deg), or
"billboard" (always turn the model to face the camera). The default
is "fixed". Models look much better when they are not all facing the
same direction.
Allow the user to group models with the same visual range, so that
there can be *many* fewer nodes in the scene graph when the models are
not visible. This causes an XML-format change, so that instead of
<object>
<range-m>...</range-m>
...
</object>
<object>
<range-m>...</range-m>
...
</object>
...
we now have
<object-group>
<range-m>...</range-m>
<object>
...
</object>
<object>
...
</object>
...
</object-group>
Every object in a group can still have its own model(s), coverage, and
heading-type, but they all share the same range selector.
This change should already help users with tight memory constraints,
but it will matter much more when we add more object types -- for
example, we can now add dozens of different urban building types
without bloating the scene graph or slowing down the LOD tests for
tris that are out of range (i.e. most of them).
2002-07-20 14:56:37 +00:00
|
|
|
|
* @param lon_deg The longitude of the surface center, in degrees.
|
|
|
|
|
* @param lat_deg The latitude of the surface center, in degrees.
|
|
|
|
|
* @param object The randomly-placed object.
|
2002-07-16 23:39:53 +00:00
|
|
|
|
* @param branch The branch where the object should be added to the
|
|
|
|
|
* scene graph.
|
|
|
|
|
*/
|
|
|
|
|
static void
|
|
|
|
|
add_object_to_triangle (sgVec3 p1, sgVec3 p2, sgVec3 p3, sgVec3 center,
|
Randomly-place object overhaul and enhancements
-----------------------------------------------
Fixed a segfault on exit.
Changed the radius of the dummy bounding sphere from 10m to 1000m to
ensure that FOV culling doesn't leave anything out.
Allow an object to have more than one variant model, which will be
chosen randomly. Simply repeat the <path>...</path> property.
Removed the <billboard> property and replaced it with <heading-type>,
which can be set to "fixed" (leave the model oriented as it is),
"random" (give the model a random heading between 0 and 359 deg), or
"billboard" (always turn the model to face the camera). The default
is "fixed". Models look much better when they are not all facing the
same direction.
Allow the user to group models with the same visual range, so that
there can be *many* fewer nodes in the scene graph when the models are
not visible. This causes an XML-format change, so that instead of
<object>
<range-m>...</range-m>
...
</object>
<object>
<range-m>...</range-m>
...
</object>
...
we now have
<object-group>
<range-m>...</range-m>
<object>
...
</object>
<object>
...
</object>
...
</object-group>
Every object in a group can still have its own model(s), coverage, and
heading-type, but they all share the same range selector.
This change should already help users with tight memory constraints,
but it will matter much more when we add more object types -- for
example, we can now add dozens of different urban building types
without bloating the scene graph or slowing down the LOD tests for
tris that are out of range (i.e. most of them).
2002-07-20 14:56:37 +00:00
|
|
|
|
double lon_deg, double lat_deg,
|
|
|
|
|
FGNewMat::Object * object, ssgBranch * branch)
|
2002-07-16 23:39:53 +00:00
|
|
|
|
{
|
Randomly-place object overhaul and enhancements
-----------------------------------------------
Fixed a segfault on exit.
Changed the radius of the dummy bounding sphere from 10m to 1000m to
ensure that FOV culling doesn't leave anything out.
Allow an object to have more than one variant model, which will be
chosen randomly. Simply repeat the <path>...</path> property.
Removed the <billboard> property and replaced it with <heading-type>,
which can be set to "fixed" (leave the model oriented as it is),
"random" (give the model a random heading between 0 and 359 deg), or
"billboard" (always turn the model to face the camera). The default
is "fixed". Models look much better when they are not all facing the
same direction.
Allow the user to group models with the same visual range, so that
there can be *many* fewer nodes in the scene graph when the models are
not visible. This causes an XML-format change, so that instead of
<object>
<range-m>...</range-m>
...
</object>
<object>
<range-m>...</range-m>
...
</object>
...
we now have
<object-group>
<range-m>...</range-m>
<object>
...
</object>
<object>
...
</object>
...
</object-group>
Every object in a group can still have its own model(s), coverage, and
heading-type, but they all share the same range selector.
This change should already help users with tight memory constraints,
but it will matter much more when we add more object types -- for
example, we can now add dozens of different urban building types
without bloating the scene graph or slowing down the LOD tests for
tris that are out of range (i.e. most of them).
2002-07-20 14:56:37 +00:00
|
|
|
|
// Set up the random heading if required.
|
|
|
|
|
double hdg_deg = 0;
|
|
|
|
|
if (object->get_heading_type() == FGNewMat::Object::HEADING_RANDOM)
|
|
|
|
|
hdg_deg = sg_random() * 360;
|
|
|
|
|
|
2002-07-16 23:39:53 +00:00
|
|
|
|
sgVec3 result;
|
|
|
|
|
|
Randomly-place object overhaul and enhancements
-----------------------------------------------
Fixed a segfault on exit.
Changed the radius of the dummy bounding sphere from 10m to 1000m to
ensure that FOV culling doesn't leave anything out.
Allow an object to have more than one variant model, which will be
chosen randomly. Simply repeat the <path>...</path> property.
Removed the <billboard> property and replaced it with <heading-type>,
which can be set to "fixed" (leave the model oriented as it is),
"random" (give the model a random heading between 0 and 359 deg), or
"billboard" (always turn the model to face the camera). The default
is "fixed". Models look much better when they are not all facing the
same direction.
Allow the user to group models with the same visual range, so that
there can be *many* fewer nodes in the scene graph when the models are
not visible. This causes an XML-format change, so that instead of
<object>
<range-m>...</range-m>
...
</object>
<object>
<range-m>...</range-m>
...
</object>
...
we now have
<object-group>
<range-m>...</range-m>
<object>
...
</object>
<object>
...
</object>
...
</object-group>
Every object in a group can still have its own model(s), coverage, and
heading-type, but they all share the same range selector.
This change should already help users with tight memory constraints,
but it will matter much more when we add more object types -- for
example, we can now add dozens of different urban building types
without bloating the scene graph or slowing down the LOD tests for
tris that are out of range (i.e. most of them).
2002-07-20 14:56:37 +00:00
|
|
|
|
sgMat4 ROT;
|
|
|
|
|
makeWorldUpRotationMatrix(ROT, hdg_deg, lon_deg, lat_deg);
|
|
|
|
|
|
2002-07-16 23:39:53 +00:00
|
|
|
|
random_pt_inside_tri(result, p1, p2, p3);
|
|
|
|
|
sgSubVec3(result, center);
|
|
|
|
|
sgMat4 OBJ_pos, OBJ;
|
|
|
|
|
sgMakeTransMat4(OBJ_pos, result);
|
|
|
|
|
sgCopyMat4(OBJ, ROT);
|
|
|
|
|
sgPostMultMat4(OBJ, OBJ_pos);
|
|
|
|
|
ssgTransform * pos = new ssgTransform;
|
|
|
|
|
pos->setTransform(OBJ);
|
Randomly-place object overhaul and enhancements
-----------------------------------------------
Fixed a segfault on exit.
Changed the radius of the dummy bounding sphere from 10m to 1000m to
ensure that FOV culling doesn't leave anything out.
Allow an object to have more than one variant model, which will be
chosen randomly. Simply repeat the <path>...</path> property.
Removed the <billboard> property and replaced it with <heading-type>,
which can be set to "fixed" (leave the model oriented as it is),
"random" (give the model a random heading between 0 and 359 deg), or
"billboard" (always turn the model to face the camera). The default
is "fixed". Models look much better when they are not all facing the
same direction.
Allow the user to group models with the same visual range, so that
there can be *many* fewer nodes in the scene graph when the models are
not visible. This causes an XML-format change, so that instead of
<object>
<range-m>...</range-m>
...
</object>
<object>
<range-m>...</range-m>
...
</object>
...
we now have
<object-group>
<range-m>...</range-m>
<object>
...
</object>
<object>
...
</object>
...
</object-group>
Every object in a group can still have its own model(s), coverage, and
heading-type, but they all share the same range selector.
This change should already help users with tight memory constraints,
but it will matter much more when we add more object types -- for
example, we can now add dozens of different urban building types
without bloating the scene graph or slowing down the LOD tests for
tris that are out of range (i.e. most of them).
2002-07-20 14:56:37 +00:00
|
|
|
|
pos->addKid(object->get_random_model());
|
2002-07-16 23:39:53 +00:00
|
|
|
|
branch->addKid(pos);
|
|
|
|
|
}
|
|
|
|
|
|
2002-07-25 17:32:31 +00:00
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* User data for populating triangles when they come in range.
|
|
|
|
|
*/
|
|
|
|
|
class TriUserData : public ssgBase
|
2002-07-18 01:04:08 +00:00
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
bool is_filled_in;
|
|
|
|
|
float * p1;
|
|
|
|
|
float * p2;
|
|
|
|
|
float * p3;
|
Randomly-place object overhaul and enhancements
-----------------------------------------------
Fixed a segfault on exit.
Changed the radius of the dummy bounding sphere from 10m to 1000m to
ensure that FOV culling doesn't leave anything out.
Allow an object to have more than one variant model, which will be
chosen randomly. Simply repeat the <path>...</path> property.
Removed the <billboard> property and replaced it with <heading-type>,
which can be set to "fixed" (leave the model oriented as it is),
"random" (give the model a random heading between 0 and 359 deg), or
"billboard" (always turn the model to face the camera). The default
is "fixed". Models look much better when they are not all facing the
same direction.
Allow the user to group models with the same visual range, so that
there can be *many* fewer nodes in the scene graph when the models are
not visible. This causes an XML-format change, so that instead of
<object>
<range-m>...</range-m>
...
</object>
<object>
<range-m>...</range-m>
...
</object>
...
we now have
<object-group>
<range-m>...</range-m>
<object>
...
</object>
<object>
...
</object>
...
</object-group>
Every object in a group can still have its own model(s), coverage, and
heading-type, but they all share the same range selector.
This change should already help users with tight memory constraints,
but it will matter much more when we add more object types -- for
example, we can now add dozens of different urban building types
without bloating the scene graph or slowing down the LOD tests for
tris that are out of range (i.e. most of them).
2002-07-20 14:56:37 +00:00
|
|
|
|
FGNewMat::ObjectGroup * object_group;
|
2002-07-18 01:04:08 +00:00
|
|
|
|
ssgBranch * branch;
|
Randomly-place object overhaul and enhancements
-----------------------------------------------
Fixed a segfault on exit.
Changed the radius of the dummy bounding sphere from 10m to 1000m to
ensure that FOV culling doesn't leave anything out.
Allow an object to have more than one variant model, which will be
chosen randomly. Simply repeat the <path>...</path> property.
Removed the <billboard> property and replaced it with <heading-type>,
which can be set to "fixed" (leave the model oriented as it is),
"random" (give the model a random heading between 0 and 359 deg), or
"billboard" (always turn the model to face the camera). The default
is "fixed". Models look much better when they are not all facing the
same direction.
Allow the user to group models with the same visual range, so that
there can be *many* fewer nodes in the scene graph when the models are
not visible. This causes an XML-format change, so that instead of
<object>
<range-m>...</range-m>
...
</object>
<object>
<range-m>...</range-m>
...
</object>
...
we now have
<object-group>
<range-m>...</range-m>
<object>
...
</object>
<object>
...
</object>
...
</object-group>
Every object in a group can still have its own model(s), coverage, and
heading-type, but they all share the same range selector.
This change should already help users with tight memory constraints,
but it will matter much more when we add more object types -- for
example, we can now add dozens of different urban building types
without bloating the scene graph or slowing down the LOD tests for
tris that are out of range (i.e. most of them).
2002-07-20 14:56:37 +00:00
|
|
|
|
double lon_deg;
|
|
|
|
|
double lat_deg;
|
2002-07-25 20:30:51 +00:00
|
|
|
|
unsigned int seed;
|
2002-07-18 01:04:08 +00:00
|
|
|
|
};
|
|
|
|
|
|
2002-07-16 23:39:53 +00:00
|
|
|
|
|
2002-07-17 22:11:13 +00:00
|
|
|
|
/**
|
2002-07-18 01:04:08 +00:00
|
|
|
|
* Fill in a triangle with randomly-placed objects.
|
2002-07-17 22:11:13 +00:00
|
|
|
|
*
|
2002-07-18 01:04:08 +00:00
|
|
|
|
* This method is invoked by a callback when the triangle is in range
|
|
|
|
|
* but not yet populated.
|
|
|
|
|
*
|
|
|
|
|
* @param p1 The first vertex of the triangle.
|
|
|
|
|
* @param p2 The second vertex of the triangle.
|
|
|
|
|
* @param p3 The third vertex of the triangle.
|
|
|
|
|
* @param mat The triangle's material.
|
|
|
|
|
* @param object_index The index of the random object in the triangle.
|
|
|
|
|
* @param branch The branch where the objects should be added.
|
Randomly-place object overhaul and enhancements
-----------------------------------------------
Fixed a segfault on exit.
Changed the radius of the dummy bounding sphere from 10m to 1000m to
ensure that FOV culling doesn't leave anything out.
Allow an object to have more than one variant model, which will be
chosen randomly. Simply repeat the <path>...</path> property.
Removed the <billboard> property and replaced it with <heading-type>,
which can be set to "fixed" (leave the model oriented as it is),
"random" (give the model a random heading between 0 and 359 deg), or
"billboard" (always turn the model to face the camera). The default
is "fixed". Models look much better when they are not all facing the
same direction.
Allow the user to group models with the same visual range, so that
there can be *many* fewer nodes in the scene graph when the models are
not visible. This causes an XML-format change, so that instead of
<object>
<range-m>...</range-m>
...
</object>
<object>
<range-m>...</range-m>
...
</object>
...
we now have
<object-group>
<range-m>...</range-m>
<object>
...
</object>
<object>
...
</object>
...
</object-group>
Every object in a group can still have its own model(s), coverage, and
heading-type, but they all share the same range selector.
This change should already help users with tight memory constraints,
but it will matter much more when we add more object types -- for
example, we can now add dozens of different urban building types
without bloating the scene graph or slowing down the LOD tests for
tris that are out of range (i.e. most of them).
2002-07-20 14:56:37 +00:00
|
|
|
|
* @param lon_deg The longitude of the surface center, in degrees.
|
|
|
|
|
* @param lat_deg The latitude of the surface center, in degrees.
|
2002-07-18 01:04:08 +00:00
|
|
|
|
*/
|
|
|
|
|
static void
|
2002-07-20 01:51:27 +00:00
|
|
|
|
fill_in_triangle (float * p1, float * p2, float * p3,
|
Randomly-place object overhaul and enhancements
-----------------------------------------------
Fixed a segfault on exit.
Changed the radius of the dummy bounding sphere from 10m to 1000m to
ensure that FOV culling doesn't leave anything out.
Allow an object to have more than one variant model, which will be
chosen randomly. Simply repeat the <path>...</path> property.
Removed the <billboard> property and replaced it with <heading-type>,
which can be set to "fixed" (leave the model oriented as it is),
"random" (give the model a random heading between 0 and 359 deg), or
"billboard" (always turn the model to face the camera). The default
is "fixed". Models look much better when they are not all facing the
same direction.
Allow the user to group models with the same visual range, so that
there can be *many* fewer nodes in the scene graph when the models are
not visible. This causes an XML-format change, so that instead of
<object>
<range-m>...</range-m>
...
</object>
<object>
<range-m>...</range-m>
...
</object>
...
we now have
<object-group>
<range-m>...</range-m>
<object>
...
</object>
<object>
...
</object>
...
</object-group>
Every object in a group can still have its own model(s), coverage, and
heading-type, but they all share the same range selector.
This change should already help users with tight memory constraints,
but it will matter much more when we add more object types -- for
example, we can now add dozens of different urban building types
without bloating the scene graph or slowing down the LOD tests for
tris that are out of range (i.e. most of them).
2002-07-20 14:56:37 +00:00
|
|
|
|
FGNewMat::ObjectGroup * object_group, ssgBranch * branch,
|
2002-07-25 20:30:51 +00:00
|
|
|
|
double lon_deg, double lat_deg, unsigned int seed)
|
2002-07-18 01:04:08 +00:00
|
|
|
|
{
|
2002-07-25 17:32:31 +00:00
|
|
|
|
// generate a repeatable random seed
|
2002-07-25 20:30:51 +00:00
|
|
|
|
sg_srandom(seed);
|
2002-07-25 17:32:31 +00:00
|
|
|
|
|
Randomly-place object overhaul and enhancements
-----------------------------------------------
Fixed a segfault on exit.
Changed the radius of the dummy bounding sphere from 10m to 1000m to
ensure that FOV culling doesn't leave anything out.
Allow an object to have more than one variant model, which will be
chosen randomly. Simply repeat the <path>...</path> property.
Removed the <billboard> property and replaced it with <heading-type>,
which can be set to "fixed" (leave the model oriented as it is),
"random" (give the model a random heading between 0 and 359 deg), or
"billboard" (always turn the model to face the camera). The default
is "fixed". Models look much better when they are not all facing the
same direction.
Allow the user to group models with the same visual range, so that
there can be *many* fewer nodes in the scene graph when the models are
not visible. This causes an XML-format change, so that instead of
<object>
<range-m>...</range-m>
...
</object>
<object>
<range-m>...</range-m>
...
</object>
...
we now have
<object-group>
<range-m>...</range-m>
<object>
...
</object>
<object>
...
</object>
...
</object-group>
Every object in a group can still have its own model(s), coverage, and
heading-type, but they all share the same range selector.
This change should already help users with tight memory constraints,
but it will matter much more when we add more object types -- for
example, we can now add dozens of different urban building types
without bloating the scene graph or slowing down the LOD tests for
tris that are out of range (i.e. most of them).
2002-07-20 14:56:37 +00:00
|
|
|
|
int nObjects = object_group->get_object_count();
|
|
|
|
|
for (int i = 0; i < nObjects; i++) {
|
|
|
|
|
FGNewMat::Object * object = object_group->get_object(i);
|
|
|
|
|
sgVec3 center;
|
|
|
|
|
sgSetVec3(center,
|
|
|
|
|
(p1[0] + p2[0] + p3[0]) / 3.0,
|
|
|
|
|
(p1[1] + p2[1] + p3[1]) / 3.0,
|
|
|
|
|
(p1[2] + p2[2] + p3[2]) / 3.0);
|
|
|
|
|
double area = sgTriArea(p1, p2, p3);
|
|
|
|
|
double num = area / object->get_coverage_m2();
|
|
|
|
|
|
|
|
|
|
// place an object each unit of area
|
|
|
|
|
while ( num > 1.0 ) {
|
|
|
|
|
add_object_to_triangle(p1, p2, p3, center, lon_deg, lat_deg,
|
|
|
|
|
object, branch);
|
|
|
|
|
num -= 1.0;
|
|
|
|
|
}
|
|
|
|
|
// for partial units of area, use a zombie door method to
|
|
|
|
|
// create the proper random chance of an object being created
|
|
|
|
|
// for this triangle
|
|
|
|
|
if ( num > 0.0 ) {
|
|
|
|
|
if ( sg_random() <= num ) {
|
|
|
|
|
// a zombie made it through our door
|
|
|
|
|
add_object_to_triangle(p1, p2, p3, center, lon_deg, lat_deg,
|
|
|
|
|
object, branch);
|
|
|
|
|
}
|
2002-07-18 01:04:08 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* SSG callback for an in-range triangle of randomly-placed objects.
|
|
|
|
|
*
|
|
|
|
|
* This pretraversal callback is attached to a branch that is traversed
|
|
|
|
|
* only when a triangle is in range. If the triangle is not currently
|
|
|
|
|
* populated with randomly-placed objects, this callback will populate
|
|
|
|
|
* it.
|
|
|
|
|
*
|
|
|
|
|
* @param entity The entity to which the callback is attached (not used).
|
|
|
|
|
* @param mask The entity's traversal mask (not used).
|
|
|
|
|
* @return Always 1, to allow traversal and culling to continue.
|
|
|
|
|
*/
|
|
|
|
|
static int
|
2002-07-25 17:32:31 +00:00
|
|
|
|
tri_in_range_callback (ssgEntity * entity, int mask)
|
2002-07-18 01:04:08 +00:00
|
|
|
|
{
|
2002-07-25 17:32:31 +00:00
|
|
|
|
TriUserData * data = (TriUserData *)entity->getUserData();
|
2002-07-18 01:04:08 +00:00
|
|
|
|
if (!data->is_filled_in) {
|
Randomly-place object overhaul and enhancements
-----------------------------------------------
Fixed a segfault on exit.
Changed the radius of the dummy bounding sphere from 10m to 1000m to
ensure that FOV culling doesn't leave anything out.
Allow an object to have more than one variant model, which will be
chosen randomly. Simply repeat the <path>...</path> property.
Removed the <billboard> property and replaced it with <heading-type>,
which can be set to "fixed" (leave the model oriented as it is),
"random" (give the model a random heading between 0 and 359 deg), or
"billboard" (always turn the model to face the camera). The default
is "fixed". Models look much better when they are not all facing the
same direction.
Allow the user to group models with the same visual range, so that
there can be *many* fewer nodes in the scene graph when the models are
not visible. This causes an XML-format change, so that instead of
<object>
<range-m>...</range-m>
...
</object>
<object>
<range-m>...</range-m>
...
</object>
...
we now have
<object-group>
<range-m>...</range-m>
<object>
...
</object>
<object>
...
</object>
...
</object-group>
Every object in a group can still have its own model(s), coverage, and
heading-type, but they all share the same range selector.
This change should already help users with tight memory constraints,
but it will matter much more when we add more object types -- for
example, we can now add dozens of different urban building types
without bloating the scene graph or slowing down the LOD tests for
tris that are out of range (i.e. most of them).
2002-07-20 14:56:37 +00:00
|
|
|
|
fill_in_triangle(data->p1, data->p2, data->p3, data->object_group,
|
2002-07-25 20:30:51 +00:00
|
|
|
|
data->branch, data->lon_deg, data->lat_deg,
|
|
|
|
|
data->seed);
|
2002-07-18 01:04:08 +00:00
|
|
|
|
data->is_filled_in = true;
|
|
|
|
|
}
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* SSG callback for an out-of-range triangle of randomly-placed objects.
|
|
|
|
|
*
|
|
|
|
|
* This pretraversal callback is attached to a branch that is traversed
|
|
|
|
|
* only when a triangle is out of range. If the triangle is currently
|
|
|
|
|
* populated with randomly-placed objects, the objects will be removed.
|
|
|
|
|
*
|
|
|
|
|
*
|
|
|
|
|
* @param entity The entity to which the callback is attached (not used).
|
|
|
|
|
* @param mask The entity's traversal mask (not used).
|
|
|
|
|
* @return Always 0, to prevent any further traversal or culling.
|
|
|
|
|
*/
|
|
|
|
|
static int
|
2002-07-25 17:32:31 +00:00
|
|
|
|
tri_out_of_range_callback (ssgEntity * entity, int mask)
|
2002-07-18 01:04:08 +00:00
|
|
|
|
{
|
2002-07-25 17:32:31 +00:00
|
|
|
|
TriUserData * data = (TriUserData *)entity->getUserData();
|
2002-07-18 01:04:08 +00:00
|
|
|
|
if (data->is_filled_in) {
|
|
|
|
|
data->branch->removeAllKids();
|
|
|
|
|
data->is_filled_in = false;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2002-07-26 19:06:29 +00:00
|
|
|
|
* ssgEntity with a dummy bounding sphere, to fool culling.
|
2002-07-18 01:04:08 +00:00
|
|
|
|
*
|
2002-07-18 13:23:29 +00:00
|
|
|
|
* This forces the in-range and out-of-range branches to be visited
|
|
|
|
|
* when appropriate, even if they have no children. It's ugly, but
|
|
|
|
|
* it works and seems fairly efficient (since branches can still
|
|
|
|
|
* be culled when they're out of the view frustum).
|
|
|
|
|
*/
|
|
|
|
|
class DummyBSphereEntity : public ssgEntity
|
|
|
|
|
{
|
|
|
|
|
public:
|
2002-07-26 19:06:29 +00:00
|
|
|
|
DummyBSphereEntity (float radius)
|
|
|
|
|
{
|
|
|
|
|
bsphere.setCenter(0, 0, 0);
|
|
|
|
|
bsphere.setRadius(radius);
|
|
|
|
|
}
|
2002-07-18 13:23:29 +00:00
|
|
|
|
virtual ~DummyBSphereEntity () {}
|
|
|
|
|
virtual void recalcBSphere () { bsphere_is_invalid = false; }
|
|
|
|
|
virtual void cull (sgFrustum *f, sgMat4 m, int test_needed) {}
|
|
|
|
|
virtual void isect (sgSphere *s, sgMat4 m, int test_needed) {}
|
|
|
|
|
virtual void hot (sgVec3 s, sgMat4 m, int test_needed) {}
|
|
|
|
|
virtual void los (sgVec3 s, sgMat4 m, int test_needed) {}
|
2002-07-26 19:06:29 +00:00
|
|
|
|
static ssgEntity * get_tri_entity ();
|
|
|
|
|
static ssgEntity * get_tile_entity ();
|
2002-07-18 13:23:29 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
2002-07-18 19:16:47 +00:00
|
|
|
|
/**
|
|
|
|
|
* Calculate the bounding radius of a triangle from its center.
|
|
|
|
|
*
|
|
|
|
|
* @param center The triangle center.
|
|
|
|
|
* @param p1 The first point in the triangle.
|
|
|
|
|
* @param p2 The second point in the triangle.
|
|
|
|
|
* @param p3 The third point in the triangle.
|
|
|
|
|
* @return The greatest distance any point lies from the center.
|
|
|
|
|
*/
|
2002-07-20 19:23:44 +00:00
|
|
|
|
static inline float
|
|
|
|
|
get_bounding_radius( sgVec3 center, float *p1, float *p2, float *p3)
|
2002-07-18 19:16:47 +00:00
|
|
|
|
{
|
2002-07-20 19:23:44 +00:00
|
|
|
|
return sqrt( SG_MAX3( sgDistanceSquaredVec3(center, p1),
|
|
|
|
|
sgDistanceSquaredVec3(center, p2),
|
|
|
|
|
sgDistanceSquaredVec3(center, p3) ) );
|
2002-07-18 19:16:47 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2002-07-18 01:04:08 +00:00
|
|
|
|
/**
|
|
|
|
|
* Set up a triangle for randomly-placed objects.
|
|
|
|
|
*
|
|
|
|
|
* No objects will be added unless the triangle comes into range.
|
2002-07-17 22:11:13 +00:00
|
|
|
|
*
|
|
|
|
|
* @param leaf The leaf containing the data for the terrain surface.
|
|
|
|
|
* @param tri_index The index of the triangle in the leaf.
|
|
|
|
|
* @param mat The material data for the triangle.
|
|
|
|
|
* @param branch The branch to which the randomly-placed objects
|
|
|
|
|
* should be added.
|
Randomly-place object overhaul and enhancements
-----------------------------------------------
Fixed a segfault on exit.
Changed the radius of the dummy bounding sphere from 10m to 1000m to
ensure that FOV culling doesn't leave anything out.
Allow an object to have more than one variant model, which will be
chosen randomly. Simply repeat the <path>...</path> property.
Removed the <billboard> property and replaced it with <heading-type>,
which can be set to "fixed" (leave the model oriented as it is),
"random" (give the model a random heading between 0 and 359 deg), or
"billboard" (always turn the model to face the camera). The default
is "fixed". Models look much better when they are not all facing the
same direction.
Allow the user to group models with the same visual range, so that
there can be *many* fewer nodes in the scene graph when the models are
not visible. This causes an XML-format change, so that instead of
<object>
<range-m>...</range-m>
...
</object>
<object>
<range-m>...</range-m>
...
</object>
...
we now have
<object-group>
<range-m>...</range-m>
<object>
...
</object>
<object>
...
</object>
...
</object-group>
Every object in a group can still have its own model(s), coverage, and
heading-type, but they all share the same range selector.
This change should already help users with tight memory constraints,
but it will matter much more when we add more object types -- for
example, we can now add dozens of different urban building types
without bloating the scene graph or slowing down the LOD tests for
tris that are out of range (i.e. most of them).
2002-07-20 14:56:37 +00:00
|
|
|
|
* @param lon_deg The longitude of the surface center, in degrees.
|
|
|
|
|
* @param lat_deg The latitude of the surface center, in degrees.
|
2002-07-17 22:11:13 +00:00
|
|
|
|
*/
|
|
|
|
|
static void
|
2002-07-18 01:04:08 +00:00
|
|
|
|
setup_triangle (float * p1, float * p2, float * p3,
|
Randomly-place object overhaul and enhancements
-----------------------------------------------
Fixed a segfault on exit.
Changed the radius of the dummy bounding sphere from 10m to 1000m to
ensure that FOV culling doesn't leave anything out.
Allow an object to have more than one variant model, which will be
chosen randomly. Simply repeat the <path>...</path> property.
Removed the <billboard> property and replaced it with <heading-type>,
which can be set to "fixed" (leave the model oriented as it is),
"random" (give the model a random heading between 0 and 359 deg), or
"billboard" (always turn the model to face the camera). The default
is "fixed". Models look much better when they are not all facing the
same direction.
Allow the user to group models with the same visual range, so that
there can be *many* fewer nodes in the scene graph when the models are
not visible. This causes an XML-format change, so that instead of
<object>
<range-m>...</range-m>
...
</object>
<object>
<range-m>...</range-m>
...
</object>
...
we now have
<object-group>
<range-m>...</range-m>
<object>
...
</object>
<object>
...
</object>
...
</object-group>
Every object in a group can still have its own model(s), coverage, and
heading-type, but they all share the same range selector.
This change should already help users with tight memory constraints,
but it will matter much more when we add more object types -- for
example, we can now add dozens of different urban building types
without bloating the scene graph or slowing down the LOD tests for
tris that are out of range (i.e. most of them).
2002-07-20 14:56:37 +00:00
|
|
|
|
FGNewMat * mat, ssgBranch * branch,
|
|
|
|
|
double lon_deg, double lat_deg)
|
2002-07-17 22:11:13 +00:00
|
|
|
|
{
|
|
|
|
|
// Set up a single center point for LOD
|
|
|
|
|
sgVec3 center;
|
|
|
|
|
sgSetVec3(center,
|
|
|
|
|
(p1[0] + p2[0] + p3[0]) / 3.0,
|
|
|
|
|
(p1[1] + p2[1] + p3[1]) / 3.0,
|
|
|
|
|
(p1[2] + p2[2] + p3[2]) / 3.0);
|
|
|
|
|
|
2002-07-18 19:16:47 +00:00
|
|
|
|
// maximum radius of an object from center.
|
|
|
|
|
double bounding_radius = get_bounding_radius(center, p1, p2, p3);
|
|
|
|
|
|
2002-07-17 22:11:13 +00:00
|
|
|
|
// Set up a transformation to the center
|
|
|
|
|
// point, so that everything else can
|
|
|
|
|
// be specified relative to it.
|
|
|
|
|
ssgTransform * location = new ssgTransform;
|
|
|
|
|
sgMat4 TRANS;
|
|
|
|
|
sgMakeTransMat4(TRANS, center);
|
|
|
|
|
location->setTransform(TRANS);
|
|
|
|
|
branch->addKid(location);
|
|
|
|
|
|
2002-07-18 01:04:08 +00:00
|
|
|
|
// Iterate through all the object types.
|
Randomly-place object overhaul and enhancements
-----------------------------------------------
Fixed a segfault on exit.
Changed the radius of the dummy bounding sphere from 10m to 1000m to
ensure that FOV culling doesn't leave anything out.
Allow an object to have more than one variant model, which will be
chosen randomly. Simply repeat the <path>...</path> property.
Removed the <billboard> property and replaced it with <heading-type>,
which can be set to "fixed" (leave the model oriented as it is),
"random" (give the model a random heading between 0 and 359 deg), or
"billboard" (always turn the model to face the camera). The default
is "fixed". Models look much better when they are not all facing the
same direction.
Allow the user to group models with the same visual range, so that
there can be *many* fewer nodes in the scene graph when the models are
not visible. This causes an XML-format change, so that instead of
<object>
<range-m>...</range-m>
...
</object>
<object>
<range-m>...</range-m>
...
</object>
...
we now have
<object-group>
<range-m>...</range-m>
<object>
...
</object>
<object>
...
</object>
...
</object-group>
Every object in a group can still have its own model(s), coverage, and
heading-type, but they all share the same range selector.
This change should already help users with tight memory constraints,
but it will matter much more when we add more object types -- for
example, we can now add dozens of different urban building types
without bloating the scene graph or slowing down the LOD tests for
tris that are out of range (i.e. most of them).
2002-07-20 14:56:37 +00:00
|
|
|
|
int num_groups = mat->get_object_group_count();
|
|
|
|
|
for (int i = 0; i < num_groups; i++) {
|
2002-07-20 01:51:27 +00:00
|
|
|
|
// Look up the random object.
|
Randomly-place object overhaul and enhancements
-----------------------------------------------
Fixed a segfault on exit.
Changed the radius of the dummy bounding sphere from 10m to 1000m to
ensure that FOV culling doesn't leave anything out.
Allow an object to have more than one variant model, which will be
chosen randomly. Simply repeat the <path>...</path> property.
Removed the <billboard> property and replaced it with <heading-type>,
which can be set to "fixed" (leave the model oriented as it is),
"random" (give the model a random heading between 0 and 359 deg), or
"billboard" (always turn the model to face the camera). The default
is "fixed". Models look much better when they are not all facing the
same direction.
Allow the user to group models with the same visual range, so that
there can be *many* fewer nodes in the scene graph when the models are
not visible. This causes an XML-format change, so that instead of
<object>
<range-m>...</range-m>
...
</object>
<object>
<range-m>...</range-m>
...
</object>
...
we now have
<object-group>
<range-m>...</range-m>
<object>
...
</object>
<object>
...
</object>
...
</object-group>
Every object in a group can still have its own model(s), coverage, and
heading-type, but they all share the same range selector.
This change should already help users with tight memory constraints,
but it will matter much more when we add more object types -- for
example, we can now add dozens of different urban building types
without bloating the scene graph or slowing down the LOD tests for
tris that are out of range (i.e. most of them).
2002-07-20 14:56:37 +00:00
|
|
|
|
FGNewMat::ObjectGroup * group = mat->get_object_group(i);
|
2002-07-18 01:04:08 +00:00
|
|
|
|
|
2002-07-18 19:16:47 +00:00
|
|
|
|
// Set up the range selector for the entire
|
|
|
|
|
// triangle; note that we use the object
|
|
|
|
|
// range plus the bounding radius here, to
|
|
|
|
|
// allow for objects far from the center.
|
|
|
|
|
float ranges[] = {0,
|
Randomly-place object overhaul and enhancements
-----------------------------------------------
Fixed a segfault on exit.
Changed the radius of the dummy bounding sphere from 10m to 1000m to
ensure that FOV culling doesn't leave anything out.
Allow an object to have more than one variant model, which will be
chosen randomly. Simply repeat the <path>...</path> property.
Removed the <billboard> property and replaced it with <heading-type>,
which can be set to "fixed" (leave the model oriented as it is),
"random" (give the model a random heading between 0 and 359 deg), or
"billboard" (always turn the model to face the camera). The default
is "fixed". Models look much better when they are not all facing the
same direction.
Allow the user to group models with the same visual range, so that
there can be *many* fewer nodes in the scene graph when the models are
not visible. This causes an XML-format change, so that instead of
<object>
<range-m>...</range-m>
...
</object>
<object>
<range-m>...</range-m>
...
</object>
...
we now have
<object-group>
<range-m>...</range-m>
<object>
...
</object>
<object>
...
</object>
...
</object-group>
Every object in a group can still have its own model(s), coverage, and
heading-type, but they all share the same range selector.
This change should already help users with tight memory constraints,
but it will matter much more when we add more object types -- for
example, we can now add dozens of different urban building types
without bloating the scene graph or slowing down the LOD tests for
tris that are out of range (i.e. most of them).
2002-07-20 14:56:37 +00:00
|
|
|
|
group->get_range_m() + bounding_radius,
|
2002-07-25 17:32:31 +00:00
|
|
|
|
SG_MAX};
|
2002-07-17 22:11:13 +00:00
|
|
|
|
ssgRangeSelector * lod = new ssgRangeSelector;
|
2002-07-18 01:04:08 +00:00
|
|
|
|
lod->setRanges(ranges, 3);
|
2002-07-17 22:11:13 +00:00
|
|
|
|
location->addKid(lod);
|
2002-07-18 01:04:08 +00:00
|
|
|
|
|
|
|
|
|
// Create the in-range and out-of-range
|
|
|
|
|
// branches.
|
|
|
|
|
ssgBranch * in_range = new ssgBranch;
|
|
|
|
|
ssgBranch * out_of_range = new ssgBranch;
|
|
|
|
|
|
|
|
|
|
// Set up the user data for if/when
|
|
|
|
|
// the random objects in this triangle
|
|
|
|
|
// are filled in.
|
2002-07-25 17:32:31 +00:00
|
|
|
|
TriUserData * data = new TriUserData;
|
2002-07-18 01:04:08 +00:00
|
|
|
|
data->is_filled_in = false;
|
|
|
|
|
data->p1 = p1;
|
|
|
|
|
data->p2 = p2;
|
|
|
|
|
data->p3 = p3;
|
Randomly-place object overhaul and enhancements
-----------------------------------------------
Fixed a segfault on exit.
Changed the radius of the dummy bounding sphere from 10m to 1000m to
ensure that FOV culling doesn't leave anything out.
Allow an object to have more than one variant model, which will be
chosen randomly. Simply repeat the <path>...</path> property.
Removed the <billboard> property and replaced it with <heading-type>,
which can be set to "fixed" (leave the model oriented as it is),
"random" (give the model a random heading between 0 and 359 deg), or
"billboard" (always turn the model to face the camera). The default
is "fixed". Models look much better when they are not all facing the
same direction.
Allow the user to group models with the same visual range, so that
there can be *many* fewer nodes in the scene graph when the models are
not visible. This causes an XML-format change, so that instead of
<object>
<range-m>...</range-m>
...
</object>
<object>
<range-m>...</range-m>
...
</object>
...
we now have
<object-group>
<range-m>...</range-m>
<object>
...
</object>
<object>
...
</object>
...
</object-group>
Every object in a group can still have its own model(s), coverage, and
heading-type, but they all share the same range selector.
This change should already help users with tight memory constraints,
but it will matter much more when we add more object types -- for
example, we can now add dozens of different urban building types
without bloating the scene graph or slowing down the LOD tests for
tris that are out of range (i.e. most of them).
2002-07-20 14:56:37 +00:00
|
|
|
|
data->object_group = group;
|
2002-07-18 01:04:08 +00:00
|
|
|
|
data->branch = in_range;
|
Randomly-place object overhaul and enhancements
-----------------------------------------------
Fixed a segfault on exit.
Changed the radius of the dummy bounding sphere from 10m to 1000m to
ensure that FOV culling doesn't leave anything out.
Allow an object to have more than one variant model, which will be
chosen randomly. Simply repeat the <path>...</path> property.
Removed the <billboard> property and replaced it with <heading-type>,
which can be set to "fixed" (leave the model oriented as it is),
"random" (give the model a random heading between 0 and 359 deg), or
"billboard" (always turn the model to face the camera). The default
is "fixed". Models look much better when they are not all facing the
same direction.
Allow the user to group models with the same visual range, so that
there can be *many* fewer nodes in the scene graph when the models are
not visible. This causes an XML-format change, so that instead of
<object>
<range-m>...</range-m>
...
</object>
<object>
<range-m>...</range-m>
...
</object>
...
we now have
<object-group>
<range-m>...</range-m>
<object>
...
</object>
<object>
...
</object>
...
</object-group>
Every object in a group can still have its own model(s), coverage, and
heading-type, but they all share the same range selector.
This change should already help users with tight memory constraints,
but it will matter much more when we add more object types -- for
example, we can now add dozens of different urban building types
without bloating the scene graph or slowing down the LOD tests for
tris that are out of range (i.e. most of them).
2002-07-20 14:56:37 +00:00
|
|
|
|
data->lon_deg = lon_deg;
|
|
|
|
|
data->lat_deg = lat_deg;
|
2002-07-25 20:30:51 +00:00
|
|
|
|
data->seed = (unsigned int)(p1[0] * i);
|
2002-07-18 01:04:08 +00:00
|
|
|
|
|
|
|
|
|
// Set up the in-range node.
|
|
|
|
|
in_range->setUserData(data);
|
|
|
|
|
in_range->setTravCallback(SSG_CALLBACK_PRETRAV,
|
2002-07-25 17:32:31 +00:00
|
|
|
|
tri_in_range_callback);
|
2002-07-18 01:04:08 +00:00
|
|
|
|
lod->addKid(in_range);
|
|
|
|
|
|
|
|
|
|
// Set up the out-of-range node.
|
|
|
|
|
out_of_range->setUserData(data);
|
|
|
|
|
out_of_range->setTravCallback(SSG_CALLBACK_PRETRAV,
|
2002-07-25 17:32:31 +00:00
|
|
|
|
tri_out_of_range_callback);
|
2002-07-26 19:06:29 +00:00
|
|
|
|
out_of_range->addKid(new DummyBSphereEntity(bounding_radius));
|
2002-07-18 01:04:08 +00:00
|
|
|
|
lod->addKid(out_of_range);
|
2002-07-17 22:11:13 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2002-07-25 17:32:31 +00:00
|
|
|
|
/**
|
|
|
|
|
* User data for populating tiles when they come in range.
|
|
|
|
|
*/
|
|
|
|
|
class TileUserData : public ssgBase
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
bool is_filled_in;
|
|
|
|
|
ssgLeaf * leaf;
|
|
|
|
|
FGNewMat * mat;
|
|
|
|
|
ssgBranch * branch;
|
|
|
|
|
double lon_deg;
|
|
|
|
|
double lat_deg;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* SSG callback for an in-range tile of randomly-placed objects.
|
|
|
|
|
*
|
|
|
|
|
* This pretraversal callback is attached to a branch that is
|
|
|
|
|
* traversed only when a tile is in range. If the tile is not
|
|
|
|
|
* currently prepared to be populated with randomly-placed objects,
|
|
|
|
|
* this callback will prepare it (actual population is handled by
|
|
|
|
|
* the tri_in_range_callback for individual triangles).
|
|
|
|
|
*
|
|
|
|
|
* @param entity The entity to which the callback is attached (not used).
|
|
|
|
|
* @param mask The entity's traversal mask (not used).
|
|
|
|
|
* @return Always 1, to allow traversal and culling to continue.
|
|
|
|
|
*/
|
|
|
|
|
static int
|
|
|
|
|
tile_in_range_callback (ssgEntity * entity, int mask)
|
|
|
|
|
{
|
|
|
|
|
TileUserData * data = (TileUserData *)entity->getUserData();
|
|
|
|
|
|
|
|
|
|
if (!data->is_filled_in) {
|
|
|
|
|
// Iterate through all the triangles
|
|
|
|
|
// and populate them.
|
|
|
|
|
int num_tris = data->leaf->getNumTriangles();
|
|
|
|
|
for ( int i = 0; i < num_tris; ++i ) {
|
|
|
|
|
short n1, n2, n3;
|
|
|
|
|
data->leaf->getTriangle(i, &n1, &n2, &n3);
|
|
|
|
|
setup_triangle(data->leaf->getVertex(n1),
|
|
|
|
|
data->leaf->getVertex(n2),
|
|
|
|
|
data->leaf->getVertex(n3),
|
|
|
|
|
data->mat, data->branch, data->lon_deg, data->lat_deg);
|
|
|
|
|
}
|
|
|
|
|
data->is_filled_in = true;
|
|
|
|
|
}
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* SSG callback for an out-of-range tile of randomly-placed objects.
|
|
|
|
|
*
|
|
|
|
|
* This pretraversal callback is attached to a branch that is
|
|
|
|
|
* traversed only when a tile is out of range. If the tile is
|
|
|
|
|
* currently prepared to be populated with randomly-placed objects (or
|
|
|
|
|
* is actually populated), the objects will be removed.
|
|
|
|
|
*
|
|
|
|
|
* @param entity The entity to which the callback is attached (not used).
|
|
|
|
|
* @param mask The entity's traversal mask (not used).
|
|
|
|
|
* @return Always 0, to prevent any further traversal or culling.
|
|
|
|
|
*/
|
|
|
|
|
static int
|
|
|
|
|
tile_out_of_range_callback (ssgEntity * entity, int mask)
|
|
|
|
|
{
|
|
|
|
|
TileUserData * data = (TileUserData *)entity->getUserData();
|
|
|
|
|
if (data->is_filled_in) {
|
|
|
|
|
data->branch->removeAllKids();
|
|
|
|
|
data->is_filled_in = false;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2002-07-17 22:11:13 +00:00
|
|
|
|
/**
|
|
|
|
|
* Randomly place objects on a surface.
|
|
|
|
|
*
|
|
|
|
|
* The leaf node provides the geometry of the surface, while the
|
|
|
|
|
* material provides the objects and placement density. Latitude
|
|
|
|
|
* and longitude are required so that the objects can be rotated
|
2002-07-25 17:32:31 +00:00
|
|
|
|
* to the world-up vector. This function does not actually add
|
|
|
|
|
* any objects; instead, it attaches an ssgRangeSelector to the
|
|
|
|
|
* branch with callbacks to generate the objects when needed.
|
2002-07-17 22:11:13 +00:00
|
|
|
|
*
|
|
|
|
|
* @param leaf The surface where the objects should be placed.
|
|
|
|
|
* @param branch The branch that will hold the randomly-placed objects.
|
2002-07-25 17:32:31 +00:00
|
|
|
|
* @param center The center of the tile in FlightGear coordinates.
|
2002-07-17 22:11:13 +00:00
|
|
|
|
* @param lon_deg The longitude of the surface center, in degrees.
|
|
|
|
|
* @param lat_deg The latitude of the surface center, in degrees.
|
|
|
|
|
* @param material_name The name of the surface's material.
|
|
|
|
|
*/
|
2002-07-15 18:16:20 +00:00
|
|
|
|
static void
|
|
|
|
|
gen_random_surface_objects (ssgLeaf *leaf,
|
|
|
|
|
ssgBranch *branch,
|
2002-07-25 17:32:31 +00:00
|
|
|
|
Point3D * center,
|
2002-07-15 18:16:20 +00:00
|
|
|
|
const string &material_name)
|
|
|
|
|
{
|
2002-07-25 17:32:31 +00:00
|
|
|
|
// If the surface has no triangles, return
|
|
|
|
|
// now.
|
|
|
|
|
int num_tris = leaf->getNumTriangles();
|
|
|
|
|
if (num_tris < 1)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
// Get the material for this surface.
|
2002-07-15 18:16:20 +00:00
|
|
|
|
FGNewMat * mat = material_lib.find(material_name);
|
|
|
|
|
if (mat == 0) {
|
|
|
|
|
SG_LOG(SG_INPUT, SG_ALERT, "Unknown material " << material_name);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2002-07-17 21:00:54 +00:00
|
|
|
|
// If the material has no randomly-placed
|
|
|
|
|
// objects, return now.
|
Randomly-place object overhaul and enhancements
-----------------------------------------------
Fixed a segfault on exit.
Changed the radius of the dummy bounding sphere from 10m to 1000m to
ensure that FOV culling doesn't leave anything out.
Allow an object to have more than one variant model, which will be
chosen randomly. Simply repeat the <path>...</path> property.
Removed the <billboard> property and replaced it with <heading-type>,
which can be set to "fixed" (leave the model oriented as it is),
"random" (give the model a random heading between 0 and 359 deg), or
"billboard" (always turn the model to face the camera). The default
is "fixed". Models look much better when they are not all facing the
same direction.
Allow the user to group models with the same visual range, so that
there can be *many* fewer nodes in the scene graph when the models are
not visible. This causes an XML-format change, so that instead of
<object>
<range-m>...</range-m>
...
</object>
<object>
<range-m>...</range-m>
...
</object>
...
we now have
<object-group>
<range-m>...</range-m>
<object>
...
</object>
<object>
...
</object>
...
</object-group>
Every object in a group can still have its own model(s), coverage, and
heading-type, but they all share the same range selector.
This change should already help users with tight memory constraints,
but it will matter much more when we add more object types -- for
example, we can now add dozens of different urban building types
without bloating the scene graph or slowing down the LOD tests for
tris that are out of range (i.e. most of them).
2002-07-20 14:56:37 +00:00
|
|
|
|
if (mat->get_object_group_count() < 1)
|
2002-07-17 21:00:54 +00:00
|
|
|
|
return;
|
2002-07-15 18:16:20 +00:00
|
|
|
|
|
2002-07-25 17:32:31 +00:00
|
|
|
|
// Calculate the geodetic centre of
|
|
|
|
|
// the tile, for aligning automatic
|
|
|
|
|
// objects.
|
|
|
|
|
double lon_deg, lat_rad, lat_deg, alt_m, sl_radius_m;
|
|
|
|
|
Point3D geoc = sgCartToPolar3d(*center);
|
|
|
|
|
lon_deg = geoc.lon() * SGD_RADIANS_TO_DEGREES;
|
|
|
|
|
sgGeocToGeod(geoc.lat(), geoc.radius(),
|
|
|
|
|
&lat_rad, &alt_m, &sl_radius_m);
|
|
|
|
|
lat_deg = lat_rad * SGD_RADIANS_TO_DEGREES;
|
|
|
|
|
|
|
|
|
|
// LOD for the tile
|
|
|
|
|
// max random object range: 20000m
|
|
|
|
|
float ranges[] = {0, 20000, 1000000};
|
|
|
|
|
ssgRangeSelector * lod = new ssgRangeSelector;
|
|
|
|
|
lod->setRanges(ranges, 3);
|
|
|
|
|
branch->addKid(lod);
|
2002-07-15 18:16:20 +00:00
|
|
|
|
|
2002-07-25 17:32:31 +00:00
|
|
|
|
// Create the in-range and out-of-range
|
|
|
|
|
// branches.
|
|
|
|
|
ssgBranch * in_range = new ssgBranch;
|
|
|
|
|
ssgBranch * out_of_range = new ssgBranch;
|
|
|
|
|
lod->addKid(in_range);
|
|
|
|
|
lod->addKid(out_of_range);
|
2002-07-17 21:00:54 +00:00
|
|
|
|
|
2002-07-25 17:32:31 +00:00
|
|
|
|
TileUserData * data = new TileUserData;
|
|
|
|
|
data->is_filled_in = false;
|
|
|
|
|
data->leaf = leaf;
|
|
|
|
|
data->mat = mat;
|
|
|
|
|
data->branch = in_range;
|
|
|
|
|
data->lon_deg = lon_deg;
|
|
|
|
|
data->lat_deg = lat_deg;
|
|
|
|
|
|
|
|
|
|
in_range->setUserData(data);
|
|
|
|
|
in_range->setTravCallback(SSG_CALLBACK_PRETRAV, tile_in_range_callback);
|
|
|
|
|
out_of_range->setUserData(data);
|
|
|
|
|
out_of_range->setTravCallback(SSG_CALLBACK_PRETRAV,
|
|
|
|
|
tile_out_of_range_callback);
|
2002-07-26 19:06:29 +00:00
|
|
|
|
out_of_range
|
|
|
|
|
->addKid(new DummyBSphereEntity(leaf->getBSphere()->getRadius()));
|
2002-07-15 18:16:20 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2002-07-16 23:39:53 +00:00
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
|
// Scenery loaders.
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
|
2001-01-05 01:07:10 +00:00
|
|
|
|
// Load an Ascii obj file
|
2001-03-29 01:42:31 +00:00
|
|
|
|
ssgBranch *fgAsciiObjLoad( const string& path, FGTileEntry *t,
|
2002-03-03 20:29:31 +00:00
|
|
|
|
ssgVertexArray *lights, const bool is_base)
|
2000-12-04 22:35:38 +00:00
|
|
|
|
{
|
2000-12-05 20:53:14 +00:00
|
|
|
|
FGNewMat *newmat = NULL;
|
2000-12-04 22:35:38 +00:00
|
|
|
|
string material;
|
2000-12-05 20:53:14 +00:00
|
|
|
|
float coverage = -1;
|
1998-10-16 00:51:46 +00:00
|
|
|
|
Point3D pp;
|
2000-06-23 00:30:04 +00:00
|
|
|
|
// sgVec3 approx_normal;
|
2000-02-19 14:29:27 +00:00
|
|
|
|
// double normal[3], scale = 0.0;
|
1998-08-25 16:51:22 +00:00
|
|
|
|
// double x, y, z, xmax, xmin, ymax, ymin, zmax, zmin;
|
|
|
|
|
// GLfloat sgenparams[] = { 1.0, 0.0, 0.0, 0.0 };
|
1999-08-07 18:27:29 +00:00
|
|
|
|
// GLint display_list = 0;
|
1998-08-25 16:51:22 +00:00
|
|
|
|
int shading;
|
2000-06-23 00:30:04 +00:00
|
|
|
|
bool in_faces = false;
|
1999-06-28 00:02:52 +00:00
|
|
|
|
int vncount, vtcount;
|
2000-06-23 00:30:04 +00:00
|
|
|
|
int n1 = 0, n2 = 0, n3 = 0;
|
1999-05-12 02:07:21 +00:00
|
|
|
|
int tex;
|
2000-06-23 00:30:04 +00:00
|
|
|
|
// int last1 = 0, last2 = 0;
|
1999-10-18 14:57:38 +00:00
|
|
|
|
bool odd = false;
|
1999-06-12 21:11:21 +00:00
|
|
|
|
point_list nodes;
|
|
|
|
|
Point3D node;
|
1998-10-16 00:51:46 +00:00
|
|
|
|
Point3D center;
|
1999-10-10 16:49:29 +00:00
|
|
|
|
double scenery_version = 0.0;
|
1999-05-13 02:24:55 +00:00
|
|
|
|
double tex_width = 1000.0, tex_height = 1000.0;
|
1999-06-28 00:02:52 +00:00
|
|
|
|
bool shared_done = false;
|
|
|
|
|
int_list fan_vertices;
|
|
|
|
|
int_list fan_tex_coords;
|
|
|
|
|
int i;
|
|
|
|
|
ssgSimpleState *state = NULL;
|
1999-10-27 00:51:42 +00:00
|
|
|
|
sgVec3 *vtlist, *vnlist;
|
|
|
|
|
sgVec2 *tclist;
|
1998-08-25 16:51:22 +00:00
|
|
|
|
|
1999-06-30 00:26:43 +00:00
|
|
|
|
ssgBranch *tile = new ssgBranch () ;
|
1999-10-26 03:45:33 +00:00
|
|
|
|
|
1999-08-12 21:08:37 +00:00
|
|
|
|
tile -> setName ( (char *)path.c_str() ) ;
|
1998-09-03 21:27:03 +00:00
|
|
|
|
|
1998-09-01 19:02:53 +00:00
|
|
|
|
// Attempt to open "path.gz" or "path"
|
2001-03-25 14:20:12 +00:00
|
|
|
|
sg_gzifstream in( path );
|
1999-06-02 22:22:47 +00:00
|
|
|
|
if ( ! in.is_open() ) {
|
2001-03-24 06:03:11 +00:00
|
|
|
|
SG_LOG( SG_TERRAIN, SG_DEBUG, "Cannot open file: " << path );
|
|
|
|
|
SG_LOG( SG_TERRAIN, SG_DEBUG, "default to ocean tile: " << path );
|
1999-08-31 23:23:04 +00:00
|
|
|
|
|
2002-02-28 00:10:35 +00:00
|
|
|
|
delete tile;
|
|
|
|
|
|
2001-01-05 01:07:10 +00:00
|
|
|
|
return NULL;
|
1998-08-25 16:51:22 +00:00
|
|
|
|
}
|
|
|
|
|
|
2001-01-13 22:06:39 +00:00
|
|
|
|
shading = fgGetBool("/sim/rendering/shading");
|
1998-08-25 16:51:22 +00:00
|
|
|
|
|
1999-11-03 20:59:34 +00:00
|
|
|
|
if ( is_base ) {
|
|
|
|
|
t->ncount = 0;
|
|
|
|
|
}
|
1999-03-27 05:36:03 +00:00
|
|
|
|
vncount = 0;
|
1999-05-12 02:07:21 +00:00
|
|
|
|
vtcount = 0;
|
1999-11-03 20:59:34 +00:00
|
|
|
|
if ( is_base ) {
|
|
|
|
|
t->bounding_radius = 0.0;
|
|
|
|
|
}
|
1998-10-16 00:51:46 +00:00
|
|
|
|
center = t->center;
|
1998-08-25 16:51:22 +00:00
|
|
|
|
|
2002-02-28 00:10:35 +00:00
|
|
|
|
// StopWatch stopwatch;
|
|
|
|
|
// stopwatch.start();
|
1998-09-03 21:27:03 +00:00
|
|
|
|
|
|
|
|
|
// ignore initial comments and blank lines. (priming the pump)
|
1999-03-27 05:36:03 +00:00
|
|
|
|
// in >> skipcomment;
|
1999-08-07 18:24:49 +00:00
|
|
|
|
// string line;
|
1998-09-01 19:02:53 +00:00
|
|
|
|
|
1999-08-07 18:24:49 +00:00
|
|
|
|
string token;
|
|
|
|
|
char c;
|
|
|
|
|
|
|
|
|
|
#ifdef __MWERKS__
|
|
|
|
|
while ( in.get(c) && c != '\0' ) {
|
|
|
|
|
in.putback(c);
|
|
|
|
|
#else
|
1999-03-27 05:36:03 +00:00
|
|
|
|
while ( ! in.eof() ) {
|
1999-08-07 18:24:49 +00:00
|
|
|
|
#endif
|
1999-03-27 05:36:03 +00:00
|
|
|
|
|
1999-06-02 22:22:47 +00:00
|
|
|
|
in >> ::skipws;
|
1999-03-27 05:36:03 +00:00
|
|
|
|
|
|
|
|
|
if ( in.get( c ) && c == '#' ) {
|
|
|
|
|
// process a comment line
|
|
|
|
|
|
|
|
|
|
// getline( in, line );
|
|
|
|
|
// cout << "comment = " << line << endl;
|
|
|
|
|
|
|
|
|
|
in >> token;
|
|
|
|
|
|
1999-10-10 17:08:46 +00:00
|
|
|
|
if ( token == "Version" ) {
|
1999-10-10 16:49:29 +00:00
|
|
|
|
// read scenery versions number
|
|
|
|
|
in >> scenery_version;
|
|
|
|
|
// cout << "scenery_version = " << scenery_version << endl;
|
2001-01-03 19:00:55 +00:00
|
|
|
|
if ( scenery_version > 0.4 ) {
|
2001-03-24 06:03:11 +00:00
|
|
|
|
SG_LOG( SG_TERRAIN, SG_ALERT,
|
2001-01-03 19:00:55 +00:00
|
|
|
|
"\nYou are attempting to load a tile format that\n"
|
|
|
|
|
<< "is newer than this version of flightgear can\n"
|
|
|
|
|
<< "handle. You should upgrade your copy of\n"
|
|
|
|
|
<< "FlightGear to the newest version. For\n"
|
|
|
|
|
<< "details, please see:\n"
|
|
|
|
|
<< "\n http://www.flightgear.org\n" );
|
|
|
|
|
exit(-1);
|
|
|
|
|
}
|
1999-10-10 16:49:29 +00:00
|
|
|
|
} else if ( token == "gbs" ) {
|
1999-03-27 05:36:03 +00:00
|
|
|
|
// reference point (center offset)
|
1999-11-03 20:59:34 +00:00
|
|
|
|
if ( is_base ) {
|
|
|
|
|
in >> t->center >> t->bounding_radius;
|
|
|
|
|
} else {
|
|
|
|
|
Point3D junk1;
|
|
|
|
|
double junk2;
|
|
|
|
|
in >> junk1 >> junk2;
|
|
|
|
|
}
|
1999-03-27 05:36:03 +00:00
|
|
|
|
center = t->center;
|
|
|
|
|
// cout << "center = " << center
|
|
|
|
|
// << " radius = " << t->bounding_radius << endl;
|
|
|
|
|
} else if ( token == "bs" ) {
|
|
|
|
|
// reference point (center offset)
|
2000-06-23 00:30:04 +00:00
|
|
|
|
// (skip past this)
|
|
|
|
|
Point3D junk1;
|
|
|
|
|
double junk2;
|
|
|
|
|
in >> junk1 >> junk2;
|
1999-03-27 05:36:03 +00:00
|
|
|
|
} else if ( token == "usemtl" ) {
|
|
|
|
|
// material property specification
|
|
|
|
|
|
1999-06-28 00:02:52 +00:00
|
|
|
|
// if first usemtl with shared_done = false, then set
|
|
|
|
|
// shared_done true and build the ssg shared lists
|
|
|
|
|
if ( ! shared_done ) {
|
1999-07-03 04:03:59 +00:00
|
|
|
|
// sanity check
|
1999-08-07 18:27:29 +00:00
|
|
|
|
if ( (int)nodes.size() != vncount ) {
|
2001-03-24 06:03:11 +00:00
|
|
|
|
SG_LOG( SG_TERRAIN, SG_ALERT,
|
2000-11-23 15:48:21 +00:00
|
|
|
|
"Tile has mismatched nodes = " << nodes.size()
|
|
|
|
|
<< " and normals = " << vncount << " : "
|
1999-07-03 04:03:59 +00:00
|
|
|
|
<< path );
|
1999-07-04 07:33:29 +00:00
|
|
|
|
// exit(-1);
|
1999-07-03 04:03:59 +00:00
|
|
|
|
}
|
1999-06-28 00:02:52 +00:00
|
|
|
|
shared_done = true;
|
|
|
|
|
|
1999-10-27 00:51:42 +00:00
|
|
|
|
vtlist = new sgVec3 [ nodes.size() ];
|
|
|
|
|
t->vec3_ptrs.push_back( vtlist );
|
|
|
|
|
vnlist = new sgVec3 [ vncount ];
|
|
|
|
|
t->vec3_ptrs.push_back( vnlist );
|
|
|
|
|
tclist = new sgVec2 [ vtcount ];
|
|
|
|
|
t->vec2_ptrs.push_back( tclist );
|
1999-06-28 00:02:52 +00:00
|
|
|
|
|
|
|
|
|
for ( i = 0; i < (int)nodes.size(); ++i ) {
|
1999-10-27 00:51:42 +00:00
|
|
|
|
sgSetVec3( vtlist[i],
|
1999-06-28 00:02:52 +00:00
|
|
|
|
nodes[i][0], nodes[i][1], nodes[i][2] );
|
|
|
|
|
}
|
|
|
|
|
for ( i = 0; i < vncount; ++i ) {
|
1999-10-27 00:51:42 +00:00
|
|
|
|
sgSetVec3( vnlist[i],
|
1999-06-28 00:02:52 +00:00
|
|
|
|
normals[i][0],
|
|
|
|
|
normals[i][1],
|
|
|
|
|
normals[i][2] );
|
|
|
|
|
}
|
|
|
|
|
for ( i = 0; i < vtcount; ++i ) {
|
1999-10-27 00:51:42 +00:00
|
|
|
|
sgSetVec2( tclist[i],
|
1999-10-10 16:49:29 +00:00
|
|
|
|
tex_coords[i][0],
|
|
|
|
|
tex_coords[i][1] );
|
1999-06-28 00:02:52 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
1999-08-07 18:27:29 +00:00
|
|
|
|
// display_list = xglGenLists(1);
|
|
|
|
|
// xglNewList(display_list, GL_COMPILE);
|
1999-03-27 05:36:03 +00:00
|
|
|
|
// printf("xglGenLists(); xglNewList();\n");
|
1999-06-28 00:02:52 +00:00
|
|
|
|
in_faces = false;
|
1998-08-25 16:51:22 +00:00
|
|
|
|
|
1999-03-27 05:36:03 +00:00
|
|
|
|
// scan the material line
|
|
|
|
|
in >> material;
|
|
|
|
|
|
|
|
|
|
// find this material in the properties list
|
2000-06-23 00:30:04 +00:00
|
|
|
|
|
|
|
|
|
newmat = material_lib.find( material );
|
|
|
|
|
if ( newmat == NULL ) {
|
2000-06-02 23:37:40 +00:00
|
|
|
|
// see if this is an on the fly texture
|
|
|
|
|
string file = path;
|
|
|
|
|
int pos = file.rfind( "/" );
|
|
|
|
|
file = file.substr( 0, pos );
|
2002-03-16 05:12:26 +00:00
|
|
|
|
// cout << "current file = " << file << endl;
|
2000-06-02 23:37:40 +00:00
|
|
|
|
file += "/";
|
|
|
|
|
file += material;
|
2002-03-16 05:12:26 +00:00
|
|
|
|
// cout << "current file = " << file << endl;
|
2000-06-23 00:30:04 +00:00
|
|
|
|
if ( ! material_lib.add_item( file ) ) {
|
2001-03-24 06:03:11 +00:00
|
|
|
|
SG_LOG( SG_TERRAIN, SG_ALERT,
|
2000-06-02 23:37:40 +00:00
|
|
|
|
"Ack! unknown usemtl name = " << material
|
|
|
|
|
<< " in " << path );
|
|
|
|
|
} else {
|
|
|
|
|
// locate our newly created material
|
2000-06-23 00:30:04 +00:00
|
|
|
|
newmat = material_lib.find( material );
|
|
|
|
|
if ( newmat == NULL ) {
|
2001-03-24 06:03:11 +00:00
|
|
|
|
SG_LOG( SG_TERRAIN, SG_ALERT,
|
2000-06-02 23:37:40 +00:00
|
|
|
|
"Ack! bad on the fly materia create = "
|
|
|
|
|
<< material << " in " << path );
|
|
|
|
|
}
|
|
|
|
|
}
|
1999-03-27 05:36:03 +00:00
|
|
|
|
}
|
1999-05-13 02:24:55 +00:00
|
|
|
|
|
2000-06-23 00:30:04 +00:00
|
|
|
|
if ( newmat != NULL ) {
|
|
|
|
|
// set the texture width and height values for this
|
|
|
|
|
// material
|
|
|
|
|
tex_width = newmat->get_xsize();
|
|
|
|
|
tex_height = newmat->get_ysize();
|
|
|
|
|
state = newmat->get_state();
|
2000-12-05 20:53:14 +00:00
|
|
|
|
coverage = newmat->get_light_coverage();
|
2002-03-16 05:12:26 +00:00
|
|
|
|
// cout << "(w) = " << tex_width << " (h) = "
|
|
|
|
|
// << tex_width << endl;
|
2000-12-05 20:53:14 +00:00
|
|
|
|
} else {
|
|
|
|
|
coverage = -1;
|
2000-06-23 00:30:04 +00:00
|
|
|
|
}
|
1999-03-27 05:36:03 +00:00
|
|
|
|
} else {
|
2000-12-05 20:53:14 +00:00
|
|
|
|
// unknown comment, just gobble the input until the
|
1999-03-27 05:36:03 +00:00
|
|
|
|
// end of line
|
1998-08-25 16:51:22 +00:00
|
|
|
|
|
1999-03-27 05:36:03 +00:00
|
|
|
|
in >> skipeol;
|
1998-08-25 16:51:22 +00:00
|
|
|
|
}
|
1999-03-27 05:36:03 +00:00
|
|
|
|
} else {
|
|
|
|
|
in.putback( c );
|
|
|
|
|
|
|
|
|
|
in >> token;
|
1998-08-25 16:51:22 +00:00
|
|
|
|
|
2002-03-16 05:12:26 +00:00
|
|
|
|
// cout << "token = " << token << endl;
|
|
|
|
|
|
1999-03-27 05:36:03 +00:00
|
|
|
|
if ( token == "vn" ) {
|
|
|
|
|
// vertex normal
|
1999-05-03 11:41:09 +00:00
|
|
|
|
if ( vncount < FG_MAX_NODES ) {
|
1999-03-27 05:36:03 +00:00
|
|
|
|
in >> normals[vncount][0]
|
|
|
|
|
>> normals[vncount][1]
|
|
|
|
|
>> normals[vncount][2];
|
|
|
|
|
vncount++;
|
|
|
|
|
} else {
|
2001-03-24 06:03:11 +00:00
|
|
|
|
SG_LOG( SG_TERRAIN, SG_ALERT,
|
1999-05-19 20:01:15 +00:00
|
|
|
|
"Read too many vertex normals in " << path
|
|
|
|
|
<< " ... dying :-(" );
|
1999-03-27 05:36:03 +00:00
|
|
|
|
exit(-1);
|
|
|
|
|
}
|
1999-05-12 02:07:21 +00:00
|
|
|
|
} else if ( token == "vt" ) {
|
|
|
|
|
// vertex texture coordinate
|
|
|
|
|
if ( vtcount < FG_MAX_NODES*3 ) {
|
|
|
|
|
in >> tex_coords[vtcount][0]
|
|
|
|
|
>> tex_coords[vtcount][1];
|
|
|
|
|
vtcount++;
|
|
|
|
|
} else {
|
2001-03-24 06:03:11 +00:00
|
|
|
|
SG_LOG( SG_TERRAIN, SG_ALERT,
|
1999-05-19 20:01:15 +00:00
|
|
|
|
"Read too many vertex texture coords in " << path
|
|
|
|
|
<< " ... dying :-("
|
1999-05-12 02:07:21 +00:00
|
|
|
|
);
|
|
|
|
|
exit(-1);
|
|
|
|
|
}
|
1999-03-30 23:48:24 +00:00
|
|
|
|
} else if ( token == "v" ) {
|
1999-03-27 05:36:03 +00:00
|
|
|
|
// node (vertex)
|
1999-05-03 11:41:09 +00:00
|
|
|
|
if ( t->ncount < FG_MAX_NODES ) {
|
1999-06-12 21:11:21 +00:00
|
|
|
|
/* in >> nodes[t->ncount][0]
|
|
|
|
|
>> nodes[t->ncount][1]
|
|
|
|
|
>> nodes[t->ncount][2]; */
|
|
|
|
|
in >> node;
|
|
|
|
|
nodes.push_back(node);
|
1999-11-03 20:59:34 +00:00
|
|
|
|
if ( is_base ) {
|
|
|
|
|
t->ncount++;
|
|
|
|
|
}
|
1999-03-27 05:36:03 +00:00
|
|
|
|
} else {
|
2001-03-24 06:03:11 +00:00
|
|
|
|
SG_LOG( SG_TERRAIN, SG_ALERT,
|
1999-05-19 20:01:15 +00:00
|
|
|
|
"Read too many nodes in " << path
|
|
|
|
|
<< " ... dying :-(");
|
1999-03-27 05:36:03 +00:00
|
|
|
|
exit(-1);
|
|
|
|
|
}
|
2000-06-06 00:33:30 +00:00
|
|
|
|
} else if ( (token == "tf") || (token == "ts") || (token == "f") ) {
|
|
|
|
|
// triangle fan, strip, or individual face
|
2001-03-24 06:03:11 +00:00
|
|
|
|
// SG_LOG( SG_TERRAIN, SG_INFO, "new fan or strip");
|
1999-03-30 23:48:24 +00:00
|
|
|
|
|
1999-06-28 00:02:52 +00:00
|
|
|
|
fan_vertices.clear();
|
|
|
|
|
fan_tex_coords.clear();
|
1999-10-18 14:57:38 +00:00
|
|
|
|
odd = true;
|
1999-06-28 00:02:52 +00:00
|
|
|
|
|
1999-08-07 18:27:29 +00:00
|
|
|
|
// xglBegin(GL_TRIANGLE_FAN);
|
1999-03-30 23:48:24 +00:00
|
|
|
|
|
|
|
|
|
in >> n1;
|
1999-06-28 00:02:52 +00:00
|
|
|
|
fan_vertices.push_back( n1 );
|
1999-08-07 18:27:29 +00:00
|
|
|
|
// xglNormal3dv(normals[n1]);
|
1999-05-12 02:07:21 +00:00
|
|
|
|
if ( in.get( c ) && c == '/' ) {
|
|
|
|
|
in >> tex;
|
1999-06-28 00:02:52 +00:00
|
|
|
|
fan_tex_coords.push_back( tex );
|
1999-10-10 16:49:29 +00:00
|
|
|
|
if ( scenery_version >= 0.4 ) {
|
1999-10-18 04:55:58 +00:00
|
|
|
|
if ( tex_width > 0 ) {
|
1999-10-27 00:51:42 +00:00
|
|
|
|
tclist[tex][0] *= (1000.0 / tex_width);
|
1999-10-18 04:55:58 +00:00
|
|
|
|
}
|
|
|
|
|
if ( tex_height > 0 ) {
|
1999-10-27 00:51:42 +00:00
|
|
|
|
tclist[tex][1] *= (1000.0 / tex_height);
|
1999-10-18 04:55:58 +00:00
|
|
|
|
}
|
1999-10-10 16:49:29 +00:00
|
|
|
|
}
|
1999-05-13 02:24:55 +00:00
|
|
|
|
pp.setx( tex_coords[tex][0] * (1000.0 / tex_width) );
|
|
|
|
|
pp.sety( tex_coords[tex][1] * (1000.0 / tex_height) );
|
1999-05-12 02:07:21 +00:00
|
|
|
|
} else {
|
|
|
|
|
in.putback( c );
|
1999-10-27 00:51:42 +00:00
|
|
|
|
pp = local_calc_tex_coords(nodes[n1], center);
|
1999-05-12 02:07:21 +00:00
|
|
|
|
}
|
1999-08-07 18:27:29 +00:00
|
|
|
|
// xglTexCoord2f(pp.x(), pp.y());
|
|
|
|
|
// xglVertex3dv(nodes[n1].get_n());
|
1999-03-30 23:48:24 +00:00
|
|
|
|
|
|
|
|
|
in >> n2;
|
1999-06-28 00:02:52 +00:00
|
|
|
|
fan_vertices.push_back( n2 );
|
1999-08-07 18:27:29 +00:00
|
|
|
|
// xglNormal3dv(normals[n2]);
|
1999-05-12 02:07:21 +00:00
|
|
|
|
if ( in.get( c ) && c == '/' ) {
|
|
|
|
|
in >> tex;
|
1999-06-28 00:02:52 +00:00
|
|
|
|
fan_tex_coords.push_back( tex );
|
1999-10-10 16:49:29 +00:00
|
|
|
|
if ( scenery_version >= 0.4 ) {
|
1999-10-18 04:55:58 +00:00
|
|
|
|
if ( tex_width > 0 ) {
|
1999-10-27 00:51:42 +00:00
|
|
|
|
tclist[tex][0] *= (1000.0 / tex_width);
|
1999-10-18 04:55:58 +00:00
|
|
|
|
}
|
|
|
|
|
if ( tex_height > 0 ) {
|
1999-10-27 00:51:42 +00:00
|
|
|
|
tclist[tex][1] *= (1000.0 / tex_height);
|
1999-10-18 04:55:58 +00:00
|
|
|
|
}
|
1999-10-10 16:49:29 +00:00
|
|
|
|
}
|
1999-05-13 02:24:55 +00:00
|
|
|
|
pp.setx( tex_coords[tex][0] * (1000.0 / tex_width) );
|
|
|
|
|
pp.sety( tex_coords[tex][1] * (1000.0 / tex_height) );
|
1999-05-12 02:07:21 +00:00
|
|
|
|
} else {
|
|
|
|
|
in.putback( c );
|
1999-10-27 00:51:42 +00:00
|
|
|
|
pp = local_calc_tex_coords(nodes[n2], center);
|
1999-05-12 02:07:21 +00:00
|
|
|
|
}
|
1999-08-07 18:27:29 +00:00
|
|
|
|
// xglTexCoord2f(pp.x(), pp.y());
|
|
|
|
|
// xglVertex3dv(nodes[n2].get_n());
|
1999-03-30 23:48:24 +00:00
|
|
|
|
|
|
|
|
|
// read all subsequent numbers until next thing isn't a number
|
|
|
|
|
while ( true ) {
|
1999-06-02 22:22:47 +00:00
|
|
|
|
in >> ::skipws;
|
1999-03-30 23:48:24 +00:00
|
|
|
|
|
|
|
|
|
char c;
|
|
|
|
|
in.get(c);
|
|
|
|
|
in.putback(c);
|
|
|
|
|
if ( ! isdigit(c) || in.eof() ) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
in >> n3;
|
1999-06-28 00:02:52 +00:00
|
|
|
|
fan_vertices.push_back( n3 );
|
2002-03-16 05:12:26 +00:00
|
|
|
|
// cout << " triangle = "
|
|
|
|
|
// << n1 << "," << n2 << "," << n3
|
|
|
|
|
// << endl;
|
|
|
|
|
// xglNormal3dv(normals[n3]);
|
1999-05-12 02:07:21 +00:00
|
|
|
|
if ( in.get( c ) && c == '/' ) {
|
|
|
|
|
in >> tex;
|
1999-06-28 00:02:52 +00:00
|
|
|
|
fan_tex_coords.push_back( tex );
|
1999-10-10 16:49:29 +00:00
|
|
|
|
if ( scenery_version >= 0.4 ) {
|
1999-10-18 04:55:58 +00:00
|
|
|
|
if ( tex_width > 0 ) {
|
1999-10-27 00:51:42 +00:00
|
|
|
|
tclist[tex][0] *= (1000.0 / tex_width);
|
1999-10-18 04:55:58 +00:00
|
|
|
|
}
|
|
|
|
|
if ( tex_height > 0 ) {
|
1999-10-27 00:51:42 +00:00
|
|
|
|
tclist[tex][1] *= (1000.0 / tex_height);
|
1999-10-18 04:55:58 +00:00
|
|
|
|
}
|
1999-10-10 16:49:29 +00:00
|
|
|
|
}
|
1999-05-13 02:24:55 +00:00
|
|
|
|
pp.setx( tex_coords[tex][0] * (1000.0 / tex_width) );
|
|
|
|
|
pp.sety( tex_coords[tex][1] * (1000.0 / tex_height) );
|
1999-05-12 02:07:21 +00:00
|
|
|
|
} else {
|
|
|
|
|
in.putback( c );
|
1999-10-27 00:51:42 +00:00
|
|
|
|
pp = local_calc_tex_coords(nodes[n3], center);
|
1999-05-12 02:07:21 +00:00
|
|
|
|
}
|
1999-08-07 18:27:29 +00:00
|
|
|
|
// xglTexCoord2f(pp.x(), pp.y());
|
|
|
|
|
// xglVertex3dv(nodes[n3].get_n());
|
1999-03-30 23:48:24 +00:00
|
|
|
|
|
2000-06-06 00:33:30 +00:00
|
|
|
|
if ( (token == "tf") || (token == "f") ) {
|
1999-10-19 20:34:58 +00:00
|
|
|
|
// triangle fan
|
|
|
|
|
n2 = n3;
|
1999-10-18 14:57:38 +00:00
|
|
|
|
} else {
|
1999-10-19 20:34:58 +00:00
|
|
|
|
// triangle strip
|
|
|
|
|
odd = !odd;
|
|
|
|
|
n1 = n2;
|
|
|
|
|
n2 = n3;
|
1999-10-18 14:57:38 +00:00
|
|
|
|
}
|
1999-03-30 23:48:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
1999-08-07 18:27:29 +00:00
|
|
|
|
// xglEnd();
|
1999-06-28 00:02:52 +00:00
|
|
|
|
|
|
|
|
|
// build the ssg entity
|
2000-02-20 05:19:15 +00:00
|
|
|
|
int size = (int)fan_vertices.size();
|
|
|
|
|
ssgVertexArray *vl = new ssgVertexArray( size );
|
|
|
|
|
ssgNormalArray *nl = new ssgNormalArray( size );
|
|
|
|
|
ssgTexCoordArray *tl = new ssgTexCoordArray( size );
|
2000-03-17 06:16:15 +00:00
|
|
|
|
ssgColourArray *cl = new ssgColourArray( 1 );
|
|
|
|
|
|
|
|
|
|
sgVec4 color;
|
|
|
|
|
sgSetVec4( color, 1.0, 1.0, 1.0, 1.0 );
|
|
|
|
|
cl->add( color );
|
2000-02-20 05:19:15 +00:00
|
|
|
|
|
|
|
|
|
sgVec2 tmp2;
|
|
|
|
|
sgVec3 tmp3;
|
|
|
|
|
for ( i = 0; i < size; ++i ) {
|
|
|
|
|
sgCopyVec3( tmp3, vtlist[ fan_vertices[i] ] );
|
|
|
|
|
vl -> add( tmp3 );
|
|
|
|
|
|
|
|
|
|
sgCopyVec3( tmp3, vnlist[ fan_vertices[i] ] );
|
|
|
|
|
nl -> add( tmp3 );
|
|
|
|
|
|
|
|
|
|
sgCopyVec2( tmp2, tclist[ fan_tex_coords[i] ] );
|
|
|
|
|
tl -> add( tmp2 );
|
1999-06-28 00:02:52 +00:00
|
|
|
|
}
|
2000-02-20 05:19:15 +00:00
|
|
|
|
|
2000-06-06 00:33:30 +00:00
|
|
|
|
ssgLeaf *leaf = NULL;
|
1999-10-18 04:55:58 +00:00
|
|
|
|
if ( token == "tf" ) {
|
|
|
|
|
// triangle fan
|
|
|
|
|
leaf =
|
2000-03-17 06:16:15 +00:00
|
|
|
|
new ssgVtxTable ( GL_TRIANGLE_FAN, vl, nl, tl, cl );
|
2000-06-06 00:33:30 +00:00
|
|
|
|
} else if ( token == "ts" ) {
|
1999-10-18 04:55:58 +00:00
|
|
|
|
// triangle strip
|
|
|
|
|
leaf =
|
2000-03-17 06:16:15 +00:00
|
|
|
|
new ssgVtxTable ( GL_TRIANGLE_STRIP, vl, nl, tl, cl );
|
2000-06-06 00:33:30 +00:00
|
|
|
|
} else if ( token == "f" ) {
|
|
|
|
|
// triangle
|
|
|
|
|
leaf =
|
|
|
|
|
new ssgVtxTable ( GL_TRIANGLES, vl, nl, tl, cl );
|
1999-10-18 04:55:58 +00:00
|
|
|
|
}
|
1999-11-24 14:15:10 +00:00
|
|
|
|
// leaf->makeDList();
|
1999-06-28 00:02:52 +00:00
|
|
|
|
leaf->setState( state );
|
|
|
|
|
|
|
|
|
|
tile->addKid( leaf );
|
2000-12-04 05:23:06 +00:00
|
|
|
|
|
|
|
|
|
if ( is_base ) {
|
2000-12-05 20:53:14 +00:00
|
|
|
|
if ( coverage > 0.0 ) {
|
|
|
|
|
if ( coverage < 10000.0 ) {
|
2001-03-24 06:03:11 +00:00
|
|
|
|
SG_LOG(SG_INPUT, SG_ALERT, "Light coverage is "
|
2000-12-05 20:53:14 +00:00
|
|
|
|
<< coverage << ", pushing up to 10000");
|
|
|
|
|
coverage = 10000;
|
|
|
|
|
}
|
|
|
|
|
gen_random_surface_points(leaf, lights, coverage);
|
2000-12-04 22:35:38 +00:00
|
|
|
|
}
|
2000-12-04 05:23:06 +00:00
|
|
|
|
}
|
1999-03-27 05:36:03 +00:00
|
|
|
|
} else {
|
2001-03-24 06:03:11 +00:00
|
|
|
|
SG_LOG( SG_TERRAIN, SG_WARN, "Unknown token in "
|
1999-03-27 05:36:03 +00:00
|
|
|
|
<< path << " = " << token );
|
1998-08-25 16:51:22 +00:00
|
|
|
|
}
|
1998-09-03 21:27:03 +00:00
|
|
|
|
|
1999-03-27 05:36:03 +00:00
|
|
|
|
// eat white space before start of while loop so if we are
|
|
|
|
|
// done with useful input it is noticed before hand.
|
1999-06-02 22:22:47 +00:00
|
|
|
|
in >> ::skipws;
|
1999-03-27 05:36:03 +00:00
|
|
|
|
}
|
1998-08-25 16:51:22 +00:00
|
|
|
|
}
|
|
|
|
|
|
1999-11-03 20:59:34 +00:00
|
|
|
|
if ( is_base ) {
|
|
|
|
|
t->nodes = nodes;
|
|
|
|
|
}
|
1999-06-12 21:11:21 +00:00
|
|
|
|
|
2002-02-28 00:10:35 +00:00
|
|
|
|
// stopwatch.stop();
|
|
|
|
|
// SG_LOG( SG_TERRAIN, SG_DEBUG,
|
|
|
|
|
// "Loaded " << path << " in "
|
|
|
|
|
// << stopwatch.elapsedSeconds() << " seconds" );
|
1999-10-22 00:27:49 +00:00
|
|
|
|
|
1999-06-28 00:02:52 +00:00
|
|
|
|
return tile;
|
1998-08-25 16:51:22 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2001-07-12 15:03:09 +00:00
|
|
|
|
ssgLeaf *gen_leaf( const string& path,
|
|
|
|
|
const GLenum ty, const string& material,
|
|
|
|
|
const point_list& nodes, const point_list& normals,
|
|
|
|
|
const point_list& texcoords,
|
|
|
|
|
const int_list node_index,
|
2002-03-13 06:03:37 +00:00
|
|
|
|
const int_list normal_index,
|
2001-07-12 15:03:09 +00:00
|
|
|
|
const int_list& tex_index,
|
|
|
|
|
const bool calc_lights, ssgVertexArray *lights )
|
2001-01-05 01:07:10 +00:00
|
|
|
|
{
|
|
|
|
|
double tex_width = 1000.0, tex_height = 1000.0;
|
|
|
|
|
ssgSimpleState *state = NULL;
|
|
|
|
|
float coverage = -1;
|
|
|
|
|
|
|
|
|
|
FGNewMat *newmat = material_lib.find( material );
|
|
|
|
|
if ( newmat == NULL ) {
|
|
|
|
|
// see if this is an on the fly texture
|
|
|
|
|
string file = path;
|
|
|
|
|
int pos = file.rfind( "/" );
|
|
|
|
|
file = file.substr( 0, pos );
|
2002-03-16 05:12:26 +00:00
|
|
|
|
// cout << "current file = " << file << endl;
|
2001-01-05 01:07:10 +00:00
|
|
|
|
file += "/";
|
|
|
|
|
file += material;
|
2002-03-16 05:12:26 +00:00
|
|
|
|
// cout << "current file = " << file << endl;
|
2001-01-05 01:07:10 +00:00
|
|
|
|
if ( ! material_lib.add_item( file ) ) {
|
2001-03-24 06:03:11 +00:00
|
|
|
|
SG_LOG( SG_TERRAIN, SG_ALERT,
|
2001-01-05 01:07:10 +00:00
|
|
|
|
"Ack! unknown usemtl name = " << material
|
|
|
|
|
<< " in " << path );
|
|
|
|
|
} else {
|
|
|
|
|
// locate our newly created material
|
|
|
|
|
newmat = material_lib.find( material );
|
|
|
|
|
if ( newmat == NULL ) {
|
2001-03-24 06:03:11 +00:00
|
|
|
|
SG_LOG( SG_TERRAIN, SG_ALERT,
|
2001-05-19 16:59:43 +00:00
|
|
|
|
"Ack! bad on the fly material create = "
|
2001-01-05 01:07:10 +00:00
|
|
|
|
<< material << " in " << path );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( newmat != NULL ) {
|
|
|
|
|
// set the texture width and height values for this
|
|
|
|
|
// material
|
|
|
|
|
tex_width = newmat->get_xsize();
|
|
|
|
|
tex_height = newmat->get_ysize();
|
|
|
|
|
state = newmat->get_state();
|
|
|
|
|
coverage = newmat->get_light_coverage();
|
2002-03-16 05:12:26 +00:00
|
|
|
|
// cout << "(w) = " << tex_width << " (h) = "
|
|
|
|
|
// << tex_width << endl;
|
2001-01-05 01:07:10 +00:00
|
|
|
|
} else {
|
|
|
|
|
coverage = -1;
|
|
|
|
|
}
|
|
|
|
|
|
2001-01-29 04:36:46 +00:00
|
|
|
|
sgVec2 tmp2;
|
|
|
|
|
sgVec3 tmp3;
|
2002-02-28 00:10:35 +00:00
|
|
|
|
sgVec4 tmp4;
|
2001-01-29 04:36:46 +00:00
|
|
|
|
int i;
|
2002-02-28 00:10:35 +00:00
|
|
|
|
|
|
|
|
|
// vertices
|
|
|
|
|
int size = node_index.size();
|
|
|
|
|
if ( size < 1 ) {
|
|
|
|
|
SG_LOG( SG_TERRAIN, SG_ALERT, "Woh! node list size < 1" );
|
|
|
|
|
exit(-1);
|
|
|
|
|
}
|
|
|
|
|
ssgVertexArray *vl = new ssgVertexArray( size );
|
|
|
|
|
Point3D node;
|
2001-01-29 04:36:46 +00:00
|
|
|
|
for ( i = 0; i < size; ++i ) {
|
2002-02-28 00:10:35 +00:00
|
|
|
|
node = nodes[ node_index[i] ];
|
2001-01-29 04:36:46 +00:00
|
|
|
|
sgSetVec3( tmp3, node[0], node[1], node[2] );
|
|
|
|
|
vl -> add( tmp3 );
|
2002-02-28 00:10:35 +00:00
|
|
|
|
}
|
2001-01-29 04:36:46 +00:00
|
|
|
|
|
2002-02-28 00:10:35 +00:00
|
|
|
|
// normals
|
|
|
|
|
Point3D normal;
|
|
|
|
|
ssgNormalArray *nl = new ssgNormalArray( size );
|
2002-03-13 06:03:37 +00:00
|
|
|
|
if ( normal_index.size() ) {
|
|
|
|
|
// object file specifies normal indices (i.e. normal indices
|
|
|
|
|
// aren't 'implied'
|
2002-02-28 00:10:35 +00:00
|
|
|
|
for ( i = 0; i < size; ++i ) {
|
2002-03-13 06:03:37 +00:00
|
|
|
|
normal = normals[ normal_index[i] ];
|
2002-02-28 00:10:35 +00:00
|
|
|
|
sgSetVec3( tmp3, normal[0], normal[1], normal[2] );
|
|
|
|
|
nl -> add( tmp3 );
|
|
|
|
|
}
|
2002-03-13 06:03:37 +00:00
|
|
|
|
} else {
|
|
|
|
|
// use implied normal indices. normal index = vertex index.
|
|
|
|
|
for ( i = 0; i < size; ++i ) {
|
|
|
|
|
normal = normals[ node_index[i] ];
|
|
|
|
|
sgSetVec3( tmp3, normal[0], normal[1], normal[2] );
|
|
|
|
|
nl -> add( tmp3 );
|
|
|
|
|
}
|
2002-02-28 00:10:35 +00:00
|
|
|
|
}
|
2001-01-29 04:36:46 +00:00
|
|
|
|
|
2002-03-13 06:03:37 +00:00
|
|
|
|
// colors
|
|
|
|
|
ssgColourArray *cl = new ssgColourArray( 1 );
|
|
|
|
|
sgSetVec4( tmp4, 1.0, 1.0, 1.0, 1.0 );
|
|
|
|
|
cl->add( tmp4 );
|
|
|
|
|
|
2002-02-28 00:10:35 +00:00
|
|
|
|
// texture coordinates
|
|
|
|
|
size = tex_index.size();
|
|
|
|
|
Point3D texcoord;
|
|
|
|
|
ssgTexCoordArray *tl = new ssgTexCoordArray( size );
|
|
|
|
|
if ( size == 1 ) {
|
|
|
|
|
texcoord = texcoords[ tex_index[0] ];
|
|
|
|
|
sgSetVec2( tmp2, texcoord[0], texcoord[1] );
|
2001-01-29 04:36:46 +00:00
|
|
|
|
sgSetVec2( tmp2, texcoord[0], texcoord[1] );
|
|
|
|
|
if ( tex_width > 0 ) {
|
|
|
|
|
tmp2[0] *= (1000.0 / tex_width);
|
|
|
|
|
}
|
|
|
|
|
if ( tex_height > 0 ) {
|
|
|
|
|
tmp2[1] *= (1000.0 / tex_height);
|
|
|
|
|
}
|
|
|
|
|
tl -> add( tmp2 );
|
2002-02-28 00:10:35 +00:00
|
|
|
|
} else if ( size > 1 ) {
|
|
|
|
|
for ( i = 0; i < size; ++i ) {
|
|
|
|
|
texcoord = texcoords[ tex_index[i] ];
|
|
|
|
|
sgSetVec2( tmp2, texcoord[0], texcoord[1] );
|
|
|
|
|
if ( tex_width > 0 ) {
|
|
|
|
|
tmp2[0] *= (1000.0 / tex_width);
|
|
|
|
|
}
|
|
|
|
|
if ( tex_height > 0 ) {
|
|
|
|
|
tmp2[1] *= (1000.0 / tex_height);
|
|
|
|
|
}
|
|
|
|
|
tl -> add( tmp2 );
|
|
|
|
|
}
|
2001-01-29 04:36:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ssgLeaf *leaf = new ssgVtxTable ( ty, vl, nl, tl, cl );
|
|
|
|
|
|
|
|
|
|
// lookup the state record
|
|
|
|
|
|
2001-01-05 01:07:10 +00:00
|
|
|
|
leaf->setState( state );
|
|
|
|
|
|
|
|
|
|
if ( calc_lights ) {
|
|
|
|
|
if ( coverage > 0.0 ) {
|
|
|
|
|
if ( coverage < 10000.0 ) {
|
2001-03-24 06:03:11 +00:00
|
|
|
|
SG_LOG(SG_INPUT, SG_ALERT, "Light coverage is "
|
2001-01-05 01:07:10 +00:00
|
|
|
|
<< coverage << ", pushing up to 10000");
|
|
|
|
|
coverage = 10000;
|
|
|
|
|
}
|
|
|
|
|
gen_random_surface_points(leaf, lights, coverage);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return leaf;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Load an Binary obj file
|
2002-03-03 20:29:31 +00:00
|
|
|
|
bool fgBinObjLoad( const string& path, const bool is_base,
|
|
|
|
|
Point3D *center,
|
|
|
|
|
double *bounding_radius,
|
|
|
|
|
ssgBranch* geometry,
|
|
|
|
|
ssgBranch* rwy_lights,
|
|
|
|
|
ssgVertexArray *ground_lights )
|
2001-01-05 01:07:10 +00:00
|
|
|
|
{
|
2001-01-06 05:09:40 +00:00
|
|
|
|
SGBinObject obj;
|
2002-07-20 23:11:27 +00:00
|
|
|
|
bool use_random_objects =
|
|
|
|
|
fgGetBool("/sim/rendering/random-objects", true);
|
2001-01-05 01:07:10 +00:00
|
|
|
|
|
2002-03-11 22:50:23 +00:00
|
|
|
|
if ( ! obj.read_bin( path ) ) {
|
2002-03-03 20:29:31 +00:00
|
|
|
|
return false;
|
2001-01-05 01:07:10 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-03-03 20:29:31 +00:00
|
|
|
|
geometry->setName( (char *)path.c_str() );
|
2001-01-05 01:07:10 +00:00
|
|
|
|
|
2002-03-03 20:29:31 +00:00
|
|
|
|
if ( is_base ) {
|
2001-01-05 01:07:10 +00:00
|
|
|
|
// reference point (center offset/bounding sphere)
|
2002-03-03 20:29:31 +00:00
|
|
|
|
*center = obj.get_gbs_center();
|
|
|
|
|
*bounding_radius = obj.get_gbs_radius();
|
2002-07-15 18:16:20 +00:00
|
|
|
|
|
2001-01-05 01:07:10 +00:00
|
|
|
|
}
|
|
|
|
|
|
2001-01-06 05:09:40 +00:00
|
|
|
|
point_list nodes = obj.get_wgs84_nodes();
|
2002-02-28 00:10:35 +00:00
|
|
|
|
point_list colors = obj.get_colors();
|
2001-01-06 05:09:40 +00:00
|
|
|
|
point_list normals = obj.get_normals();
|
|
|
|
|
point_list texcoords = obj.get_texcoords();
|
|
|
|
|
|
2002-03-03 23:20:55 +00:00
|
|
|
|
string material, tmp_mat;
|
2001-01-06 05:09:40 +00:00
|
|
|
|
int_list vertex_index;
|
2002-03-13 06:03:37 +00:00
|
|
|
|
int_list normal_index;
|
2001-01-06 05:09:40 +00:00
|
|
|
|
int_list tex_index;
|
|
|
|
|
|
2002-03-03 20:29:31 +00:00
|
|
|
|
int i;
|
2002-03-03 23:20:55 +00:00
|
|
|
|
bool is_lighting = false;
|
2002-03-03 20:29:31 +00:00
|
|
|
|
|
2002-02-28 00:10:35 +00:00
|
|
|
|
// generate points
|
|
|
|
|
string_list pt_materials = obj.get_pt_materials();
|
|
|
|
|
group_list pts_v = obj.get_pts_v();
|
2002-03-13 06:03:37 +00:00
|
|
|
|
group_list pts_n = obj.get_pts_n();
|
2002-02-28 00:10:35 +00:00
|
|
|
|
for ( i = 0; i < (int)pts_v.size(); ++i ) {
|
2002-03-16 05:12:26 +00:00
|
|
|
|
// cout << "pts_v.size() = " << pts_v.size() << endl;
|
2002-03-03 23:20:55 +00:00
|
|
|
|
tmp_mat = pt_materials[i];
|
|
|
|
|
if ( tmp_mat.substr(0, 3) == "RWY" ) {
|
|
|
|
|
material = "LIGHTS";
|
|
|
|
|
is_lighting = true;
|
|
|
|
|
} else {
|
|
|
|
|
material = tmp_mat;
|
|
|
|
|
}
|
2002-02-28 00:10:35 +00:00
|
|
|
|
vertex_index = pts_v[i];
|
2002-03-26 16:10:53 +00:00
|
|
|
|
normal_index = pts_n[i];
|
2002-02-28 00:10:35 +00:00
|
|
|
|
tex_index.clear();
|
|
|
|
|
ssgLeaf *leaf = gen_leaf( path, GL_POINTS, material,
|
|
|
|
|
nodes, normals, texcoords,
|
2002-03-13 06:03:37 +00:00
|
|
|
|
vertex_index, normal_index, tex_index,
|
2002-03-03 20:29:31 +00:00
|
|
|
|
false, ground_lights );
|
2002-02-28 00:10:35 +00:00
|
|
|
|
|
2002-03-03 23:20:55 +00:00
|
|
|
|
if ( is_lighting ) {
|
2002-07-15 18:16:20 +00:00
|
|
|
|
float ranges[] = { 0, 12000 };
|
|
|
|
|
leaf->setCallback(SSG_CALLBACK_PREDRAW, runway_lights_predraw);
|
|
|
|
|
ssgRangeSelector * lod = new ssgRangeSelector;
|
|
|
|
|
lod->setRanges(ranges, 2);
|
|
|
|
|
lod->addKid(leaf);
|
|
|
|
|
rwy_lights->addKid(lod);
|
2002-03-03 23:20:55 +00:00
|
|
|
|
} else {
|
|
|
|
|
geometry->addKid( leaf );
|
|
|
|
|
}
|
2002-02-28 00:10:35 +00:00
|
|
|
|
}
|
|
|
|
|
|
2001-01-05 01:07:10 +00:00
|
|
|
|
// generate triangles
|
2001-01-12 22:47:41 +00:00
|
|
|
|
string_list tri_materials = obj.get_tri_materials();
|
|
|
|
|
group_list tris_v = obj.get_tris_v();
|
2002-03-13 06:03:37 +00:00
|
|
|
|
group_list tris_n = obj.get_tris_n();
|
2001-01-12 22:47:41 +00:00
|
|
|
|
group_list tris_tc = obj.get_tris_tc();
|
|
|
|
|
for ( i = 0; i < (int)tris_v.size(); ++i ) {
|
|
|
|
|
material = tri_materials[i];
|
|
|
|
|
vertex_index = tris_v[i];
|
2002-03-13 06:03:37 +00:00
|
|
|
|
normal_index = tris_n[i];
|
2001-01-12 22:47:41 +00:00
|
|
|
|
tex_index = tris_tc[i];
|
2001-01-06 05:09:40 +00:00
|
|
|
|
ssgLeaf *leaf = gen_leaf( path, GL_TRIANGLES, material,
|
|
|
|
|
nodes, normals, texcoords,
|
2002-03-13 06:03:37 +00:00
|
|
|
|
vertex_index, normal_index, tex_index,
|
2002-03-03 20:29:31 +00:00
|
|
|
|
is_base, ground_lights );
|
2001-01-05 01:07:10 +00:00
|
|
|
|
|
2002-07-20 23:11:27 +00:00
|
|
|
|
if (use_random_objects)
|
2002-07-25 17:32:31 +00:00
|
|
|
|
gen_random_surface_objects(leaf, geometry, center, material);
|
2002-03-03 20:29:31 +00:00
|
|
|
|
geometry->addKid( leaf );
|
2001-01-05 01:07:10 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// generate strips
|
2001-01-12 22:47:41 +00:00
|
|
|
|
string_list strip_materials = obj.get_strip_materials();
|
|
|
|
|
group_list strips_v = obj.get_strips_v();
|
2002-03-13 06:03:37 +00:00
|
|
|
|
group_list strips_n = obj.get_strips_n();
|
2001-01-12 22:47:41 +00:00
|
|
|
|
group_list strips_tc = obj.get_strips_tc();
|
|
|
|
|
for ( i = 0; i < (int)strips_v.size(); ++i ) {
|
|
|
|
|
material = strip_materials[i];
|
|
|
|
|
vertex_index = strips_v[i];
|
2002-03-13 06:03:37 +00:00
|
|
|
|
normal_index = strips_n[i];
|
2001-01-12 22:47:41 +00:00
|
|
|
|
tex_index = strips_tc[i];
|
2001-01-06 05:09:40 +00:00
|
|
|
|
ssgLeaf *leaf = gen_leaf( path, GL_TRIANGLE_STRIP, material,
|
|
|
|
|
nodes, normals, texcoords,
|
2002-03-13 06:03:37 +00:00
|
|
|
|
vertex_index, normal_index, tex_index,
|
2002-03-03 20:29:31 +00:00
|
|
|
|
is_base, ground_lights );
|
2001-01-05 01:07:10 +00:00
|
|
|
|
|
2002-07-20 23:11:27 +00:00
|
|
|
|
if (use_random_objects)
|
2002-07-25 17:32:31 +00:00
|
|
|
|
gen_random_surface_objects(leaf, geometry, center, material);
|
2002-03-03 20:29:31 +00:00
|
|
|
|
geometry->addKid( leaf );
|
2001-01-05 01:07:10 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// generate fans
|
2001-01-12 22:47:41 +00:00
|
|
|
|
string_list fan_materials = obj.get_fan_materials();
|
|
|
|
|
group_list fans_v = obj.get_fans_v();
|
2002-03-13 06:03:37 +00:00
|
|
|
|
group_list fans_n = obj.get_fans_n();
|
2001-01-12 22:47:41 +00:00
|
|
|
|
group_list fans_tc = obj.get_fans_tc();
|
|
|
|
|
for ( i = 0; i < (int)fans_v.size(); ++i ) {
|
|
|
|
|
material = fan_materials[i];
|
|
|
|
|
vertex_index = fans_v[i];
|
2002-03-13 06:03:37 +00:00
|
|
|
|
normal_index = fans_n[i];
|
2001-01-12 22:47:41 +00:00
|
|
|
|
tex_index = fans_tc[i];
|
2001-01-06 05:09:40 +00:00
|
|
|
|
ssgLeaf *leaf = gen_leaf( path, GL_TRIANGLE_FAN, material,
|
|
|
|
|
nodes, normals, texcoords,
|
2002-03-13 06:03:37 +00:00
|
|
|
|
vertex_index, normal_index, tex_index,
|
2002-03-03 20:29:31 +00:00
|
|
|
|
is_base, ground_lights );
|
2002-07-20 23:11:27 +00:00
|
|
|
|
if (use_random_objects)
|
2002-07-25 17:32:31 +00:00
|
|
|
|
gen_random_surface_objects(leaf, geometry, center, material);
|
2002-03-03 20:29:31 +00:00
|
|
|
|
geometry->addKid( leaf );
|
2001-01-05 01:07:10 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-03-03 20:29:31 +00:00
|
|
|
|
return true;
|
2001-01-05 01:07:10 +00:00
|
|
|
|
}
|