1
0
Fork 0

Added support for dynamically-generated scenery objects. Set the

property /sim/rendering/dynamic-objects to true to enable them.
This commit is contained in:
david 2002-07-15 18:16:20 +00:00
parent f04d342f6a
commit 84fcb479f6
5 changed files with 219 additions and 3 deletions

View file

@ -51,6 +51,7 @@
#include <Main/fg_props.hxx>
#include <Scenery/tileentry.hxx>
#include "newmat.hxx"
#include "matlib.hxx"
SG_USING_NAMESPACE(std);

View file

@ -48,8 +48,8 @@
#include <plib/ssg.h> // plib include
#include "newmat.hxx"
class FGNewMat;
SG_USING_STD(string);
SG_USING_STD(map);

View file

@ -91,6 +91,8 @@ FGNewMat::FGNewMat (ssgSimpleState * s)
FGNewMat::~FGNewMat (void)
{
for (int i = 0; i < objects.size(); i++)
objects[i].model->deRef();
}
@ -140,6 +142,39 @@ FGNewMat::read_properties (const SGPropertyNode * props)
emission[1] = props->getDoubleValue("emissive/g", 0.0);
emission[2] = props->getDoubleValue("emissive/b", 0.0);
emission[3] = props->getDoubleValue("emissive/a", 0.0);
vector<SGPropertyNode_ptr> object_nodes =
((SGPropertyNode *)props)->getChildren("object");
for (int i = 0; i < object_nodes.size(); i++) {
const SGPropertyNode * object_node = object_nodes[i];
if (object_node->hasChild("path")) {
Object object;
SGPath path = globals->get_fg_root();
path.append(object_node->getStringValue("path"));
ssgTexturePath((char *)path.dir().c_str());
ssgEntity * model = ssgLoad((char *)path.c_str());
if (model != 0) {
float ranges[] = {0, object_node->getDoubleValue("range-m", 2000)};
object.model = new ssgRangeSelector;
((ssgRangeSelector *)object.model)->setRanges(ranges, 2);
if (object_node->getBoolValue("billboard", false)) {
ssgCutout * cutout = new ssgCutout(false);
cutout->addKid(model);
((ssgBranch *)object.model)->addKid(cutout);
} else {
((ssgBranch *)object.model)->addKid(model);
}
object.model->ref();
object.coverage = object_node->getDoubleValue("coverage", 100000);
object.group_lod = object_node->getDoubleValue("group-range-m", 5000);
objects.push_back(object);
} else {
SG_LOG(SG_INPUT, SG_ALERT, "Failed to load object " << path.str());
}
} else {
SG_LOG(SG_INPUT, SG_ALERT, "No path supplied for object");
}
}
}

View file

@ -147,6 +147,34 @@ public:
virtual inline double get_light_coverage () const { return light_coverage; }
/**
* Get the number of dynamic objects defined for this material.
*/
virtual int get_object_count () const { return objects.size(); }
/**
* Get a dynamic object for this material.
*/
virtual ssgEntity * get_object (int i) const { return objects[i].model; }
/**
* Get the average space for a dynamic object for this material.
*/
virtual double get_object_coverage (int i) const {
return objects[i].coverage;
}
/**
* Get the group LOD range for a dynamic object for this material.
*/
virtual double get_object_group_lod (int i) const {
return objects[i].group_lod;
}
/**
* Get the current state.
*/
@ -221,6 +249,15 @@ private:
// true if texture loading deferred, and not yet loaded
bool texture_loaded;
struct Object
{
ssgEntity * model;
double coverage;
double group_lod;
};
vector<Object> objects;
// ref count so we can properly delete if we have multiple
// pointers to this record
int refcount;

View file

@ -52,8 +52,10 @@
#include <Main/globals.hxx>
#include <Main/fg_props.hxx>
#include <Time/light.hxx>
#include <Scenery/tileentry.hxx>
#include "newmat.hxx"
#include "matlib.hxx"
#include "obj.hxx"
@ -69,6 +71,14 @@ typedef int_list::const_iterator int_point_list_iterator;
static double normals[FG_MAX_NODES][3];
static double tex_coords[FG_MAX_NODES*3][3];
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);
}
#define FG_TEX_CONSTANT 69.0
@ -303,6 +313,112 @@ static void gen_random_surface_points( ssgLeaf *leaf, ssgVertexArray *lights,
}
static void
gen_random_surface_objects (ssgLeaf *leaf,
ssgBranch *branch,
float lon_deg,
float lat_deg,
const string &material_name)
{
FGNewMat * mat = material_lib.find(material_name);
if (mat == 0) {
SG_LOG(SG_INPUT, SG_ALERT, "Unknown material " << material_name);
return;
}
int num = leaf->getNumTriangles();
float hdg_deg = 0.0; // do something here later
// The object will be aligned for the north pole. This code
// calculates a matrix to rotate it to for the surface of the
// earth in the current location.
sgVec3 obj_right, obj_up;
sgSetVec3(obj_right, 0.0, 1.0, 0.0); // Y axis
sgSetVec3(obj_up, 0.0, 0.0, 1.0); // Z axis
sgMat4 ROT_lon, ROT_lat, ROT_hdg;
sgMakeRotMat4(ROT_lon, lon_deg, obj_up);
sgMakeRotMat4(ROT_lat, 90 - lat_deg, obj_right);
sgMakeRotMat4(ROT_hdg, hdg_deg, obj_up);
sgMat4 ROT;
sgCopyMat4(ROT, ROT_hdg);
sgPostMultMat4(ROT, ROT_lat);
sgPostMultMat4(ROT, ROT_lon);
if ( num > 0 ) {
short int n1, n2, n3;
float *p1, *p2, *p3;
sgVec3 result;
// generate a repeatable random seed
p1 = leaf->getVertex( 0 );
unsigned int seed = (unsigned int)p1[0];
sg_srandom( seed );
int num_objects = mat->get_object_count();
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);
double area = sgTriArea( p1, p2, p3 );
// 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);
ssgTransform * location = new ssgTransform;
sgMat4 TRANS;
sgMakeTransMat4(TRANS, center);
location->setTransform(TRANS);
for (int j = 0; j < num_objects; j++) {
double num = area / mat->get_object_coverage(j);
float ranges[] = {0, mat->get_object_group_lod(j)};
ssgRangeSelector * lod = new ssgRangeSelector;
lod->setRanges(ranges, 2);
lod->addKid(location);
branch->addKid(lod);
// place an object each unit of area
while ( num > 1.0 ) {
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);
pos->addKid(mat->get_object(j));
location->addKid(pos);
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
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);
pos->addKid(mat->get_object(j));
location->addKid(pos);
}
}
}
}
}
}
// Load an Ascii obj file
ssgBranch *fgAsciiObjLoad( const string& path, FGTileEntry *t,
ssgVertexArray *lights, const bool is_base)
@ -902,6 +1018,8 @@ bool fgBinObjLoad( const string& path, const bool is_base,
ssgVertexArray *ground_lights )
{
SGBinObject obj;
bool use_dynamic_objects =
fgGetBool("/sim/rendering/dynamic-objects", false);
if ( ! obj.read_bin( path ) ) {
return false;
@ -909,10 +1027,22 @@ bool fgBinObjLoad( const string& path, const bool is_base,
geometry->setName( (char *)path.c_str() );
double geod_lon = 0.0, geod_lat = 0.0, geod_alt = 0.0,
geod_sl_radius = 0.0;
if ( is_base ) {
// reference point (center offset/bounding sphere)
*center = obj.get_gbs_center();
*bounding_radius = obj.get_gbs_radius();
// Calculate the geodetic centre of
// the tile, for aligning automatic
// objects.
Point3D geoc = sgCartToPolar3d(*center);
geod_lon = geoc.lon();
sgGeocToGeod(geoc.lat(), geoc.radius(),
&geod_lat, &geod_alt, &geod_sl_radius);
geod_lon *= SGD_RADIANS_TO_DEGREES;
geod_lat *= SGD_RADIANS_TO_DEGREES;
}
point_list nodes = obj.get_wgs84_nodes();
@ -950,7 +1080,12 @@ bool fgBinObjLoad( const string& path, const bool is_base,
false, ground_lights );
if ( is_lighting ) {
rwy_lights->addKid( leaf );
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);
} else {
geometry->addKid( leaf );
}
@ -971,6 +1106,9 @@ bool fgBinObjLoad( const string& path, const bool is_base,
vertex_index, normal_index, tex_index,
is_base, ground_lights );
if (use_dynamic_objects)
gen_random_surface_objects(leaf, geometry, geod_lon, geod_lat,
material);
geometry->addKid( leaf );
}
@ -989,6 +1127,9 @@ bool fgBinObjLoad( const string& path, const bool is_base,
vertex_index, normal_index, tex_index,
is_base, ground_lights );
if (use_dynamic_objects)
gen_random_surface_objects(leaf, geometry, geod_lon, geod_lat,
material);
geometry->addKid( leaf );
}
@ -1006,7 +1147,9 @@ bool fgBinObjLoad( const string& path, const bool is_base,
nodes, normals, texcoords,
vertex_index, normal_index, tex_index,
is_base, ground_lights );
if (use_dynamic_objects)
gen_random_surface_objects(leaf, geometry, geod_lon, geod_lat,
material);
geometry->addKid( leaf );
}