Added support for dynamically-generated scenery objects. Set the
property /sim/rendering/dynamic-objects to true to enable them.
This commit is contained in:
parent
f04d342f6a
commit
84fcb479f6
5 changed files with 219 additions and 3 deletions
|
@ -51,6 +51,7 @@
|
|||
#include <Main/fg_props.hxx>
|
||||
#include <Scenery/tileentry.hxx>
|
||||
|
||||
#include "newmat.hxx"
|
||||
#include "matlib.hxx"
|
||||
|
||||
SG_USING_NAMESPACE(std);
|
||||
|
|
|
@ -48,8 +48,8 @@
|
|||
|
||||
#include <plib/ssg.h> // plib include
|
||||
|
||||
#include "newmat.hxx"
|
||||
|
||||
class FGNewMat;
|
||||
|
||||
SG_USING_STD(string);
|
||||
SG_USING_STD(map);
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue