Separate out the SGMaterial::Object{,Group} code into it's own source file.
This commit is contained in:
@@ -6,10 +6,12 @@ noinst_HEADERS =
|
||||
|
||||
include_HEADERS = \
|
||||
mat.hxx \
|
||||
matlib.hxx
|
||||
matlib.hxx \
|
||||
matobj.hxx
|
||||
|
||||
libsgmaterial_a_SOURCES = \
|
||||
mat.cxx \
|
||||
matlib.cxx
|
||||
matlib.cxx \
|
||||
matobj.cxx
|
||||
|
||||
INCLUDES = -I$(top_srcdir)
|
||||
|
||||
@@ -66,187 +66,6 @@ local_file_exists( const string& path ) {
|
||||
}
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Implementation of SGMaterial::Object.
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SGMaterial::Object::Object (const SGPropertyNode * node, double range_m)
|
||||
: _models_loaded(false),
|
||||
_coverage_m2(node->getDoubleValue("coverage-m2", 1000000)),
|
||||
_range_m(range_m)
|
||||
{
|
||||
// Sanity check
|
||||
if (_coverage_m2 < 1000) {
|
||||
SG_LOG(SG_INPUT, SG_ALERT, "Random object coverage " << _coverage_m2
|
||||
<< " is too small, forcing, to 1000");
|
||||
_coverage_m2 = 1000;
|
||||
}
|
||||
|
||||
// Note all the model paths
|
||||
vector <SGPropertyNode_ptr> path_nodes = node->getChildren("path");
|
||||
for (unsigned int i = 0; i < path_nodes.size(); i++)
|
||||
_paths.push_back(path_nodes[i]->getStringValue());
|
||||
|
||||
// Note the heading type
|
||||
string hdg = node->getStringValue("heading-type", "fixed");
|
||||
if (hdg == "fixed") {
|
||||
_heading_type = HEADING_FIXED;
|
||||
} else if (hdg == "billboard") {
|
||||
_heading_type = HEADING_BILLBOARD;
|
||||
} else if (hdg == "random") {
|
||||
_heading_type = HEADING_RANDOM;
|
||||
} else {
|
||||
_heading_type = HEADING_FIXED;
|
||||
SG_LOG(SG_INPUT, SG_ALERT, "Unknown heading type: " << hdg
|
||||
<< "; using 'fixed' instead.");
|
||||
}
|
||||
|
||||
// uncomment to preload models
|
||||
// load_models();
|
||||
}
|
||||
|
||||
SGMaterial::Object::~Object ()
|
||||
{
|
||||
for (unsigned int i = 0; i < _models.size(); i++) {
|
||||
if (_models[i] != 0) {
|
||||
_models[i]->deRef();
|
||||
_models[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
SGMaterial::Object::get_model_count( SGModelLoader *loader,
|
||||
const string &fg_root,
|
||||
SGPropertyNode *prop_root,
|
||||
double sim_time_sec )
|
||||
{
|
||||
load_models( loader, fg_root, prop_root, sim_time_sec );
|
||||
return _models.size();
|
||||
}
|
||||
|
||||
inline void
|
||||
SGMaterial::Object::load_models ( SGModelLoader *loader,
|
||||
const string &fg_root,
|
||||
SGPropertyNode *prop_root,
|
||||
double sim_time_sec )
|
||||
{
|
||||
// Load model only on demand
|
||||
if (!_models_loaded) {
|
||||
for (unsigned int i = 0; i < _paths.size(); i++) {
|
||||
ssgEntity *entity = loader->load_model( fg_root, _paths[i],
|
||||
prop_root, sim_time_sec );
|
||||
if (entity != 0) {
|
||||
// FIXME: this stuff can be handled
|
||||
// in the XML wrapper as well (at least,
|
||||
// the billboarding should be handled
|
||||
// there).
|
||||
float ranges[] = {0, _range_m};
|
||||
ssgRangeSelector * lod = new ssgRangeSelector;
|
||||
lod->ref();
|
||||
lod->setRanges(ranges, 2);
|
||||
if (_heading_type == HEADING_BILLBOARD) {
|
||||
ssgCutout * cutout = new ssgCutout(false);
|
||||
cutout->addKid(entity);
|
||||
lod->addKid(cutout);
|
||||
} else {
|
||||
lod->addKid(entity);
|
||||
}
|
||||
_models.push_back(lod);
|
||||
} else {
|
||||
SG_LOG(SG_INPUT, SG_ALERT, "Failed to load object " << _paths[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
_models_loaded = true;
|
||||
}
|
||||
|
||||
ssgEntity *
|
||||
SGMaterial::Object::get_model( int index,
|
||||
SGModelLoader *loader,
|
||||
const string &fg_root,
|
||||
SGPropertyNode *prop_root,
|
||||
double sim_time_sec )
|
||||
{
|
||||
load_models( loader, fg_root, prop_root, sim_time_sec ); // comment this out if preloading models
|
||||
return _models[index];
|
||||
}
|
||||
|
||||
ssgEntity *
|
||||
SGMaterial::Object::get_random_model( SGModelLoader *loader,
|
||||
const string &fg_root,
|
||||
SGPropertyNode *prop_root,
|
||||
double sim_time_sec )
|
||||
{
|
||||
load_models( loader, fg_root, prop_root, sim_time_sec ); // comment this out if preloading models
|
||||
int nModels = _models.size();
|
||||
int index = int(sg_random() * nModels);
|
||||
if (index >= nModels)
|
||||
index = 0;
|
||||
return _models[index];
|
||||
}
|
||||
|
||||
double
|
||||
SGMaterial::Object::get_coverage_m2 () const
|
||||
{
|
||||
return _coverage_m2;
|
||||
}
|
||||
|
||||
SGMaterial::Object::HeadingType
|
||||
SGMaterial::Object::get_heading_type () const
|
||||
{
|
||||
return _heading_type;
|
||||
}
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Implementation of SGMaterial::ObjectGroup.
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SGMaterial::ObjectGroup::ObjectGroup (SGPropertyNode * node)
|
||||
: _range_m(node->getDoubleValue("range-m", 2000))
|
||||
{
|
||||
// Load the object subnodes
|
||||
vector<SGPropertyNode_ptr> object_nodes =
|
||||
((SGPropertyNode *)node)->getChildren("object");
|
||||
for (unsigned int i = 0; i < object_nodes.size(); i++) {
|
||||
const SGPropertyNode * object_node = object_nodes[i];
|
||||
if (object_node->hasChild("path"))
|
||||
_objects.push_back(new Object(object_node, _range_m));
|
||||
else
|
||||
SG_LOG(SG_INPUT, SG_ALERT, "No path supplied for object");
|
||||
}
|
||||
}
|
||||
|
||||
SGMaterial::ObjectGroup::~ObjectGroup ()
|
||||
{
|
||||
for (unsigned int i = 0; i < _objects.size(); i++) {
|
||||
delete _objects[i];
|
||||
_objects[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
double
|
||||
SGMaterial::ObjectGroup::get_range_m () const
|
||||
{
|
||||
return _range_m;
|
||||
}
|
||||
|
||||
int
|
||||
SGMaterial::ObjectGroup::get_object_count () const
|
||||
{
|
||||
return _objects.size();
|
||||
}
|
||||
|
||||
SGMaterial::Object *
|
||||
SGMaterial::ObjectGroup::get_object (int index) const
|
||||
{
|
||||
return _objects[index];
|
||||
}
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Constructors and destructor.
|
||||
@@ -334,7 +153,7 @@ SGMaterial::read_properties( const string &fg_root, const SGPropertyNode * props
|
||||
vector<SGPropertyNode_ptr> object_group_nodes =
|
||||
((SGPropertyNode *)props)->getChildren("object-group");
|
||||
for (unsigned int i = 0; i < object_group_nodes.size(); i++)
|
||||
object_groups.push_back(new ObjectGroup(object_group_nodes[i]));
|
||||
object_groups.push_back(new SGMatObjectGroup(object_group_nodes[i]));
|
||||
}
|
||||
|
||||
|
||||
@@ -429,4 +248,4 @@ void SGMaterial::set_ssg_state( ssgSimpleState *s )
|
||||
texture_loaded = true;
|
||||
}
|
||||
|
||||
// end of newmat.cxx
|
||||
// end of mat.cxx
|
||||
|
||||
@@ -40,6 +40,8 @@
|
||||
#include <simgear/props/props.hxx>
|
||||
#include <simgear/scene/model/loader.hxx>
|
||||
|
||||
#include "matobj.hxx"
|
||||
|
||||
SG_USING_STD(string);
|
||||
|
||||
|
||||
@@ -56,169 +58,6 @@ class SGMaterial {
|
||||
|
||||
public:
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Inner classes.
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
class ObjectGroup;
|
||||
|
||||
/**
|
||||
* A randomly-placeable object.
|
||||
*
|
||||
* SGMaterial uses this class to keep track of the model(s) and
|
||||
* parameters for a single instance of a randomly-placeable object.
|
||||
* The object can have more than one variant model (i.e. slightly
|
||||
* different shapes of trees), but they are considered equivalent
|
||||
* and interchangeable.
|
||||
*/
|
||||
class Object
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* The heading type for a randomly-placed object.
|
||||
*/
|
||||
enum HeadingType {
|
||||
HEADING_FIXED,
|
||||
HEADING_BILLBOARD,
|
||||
HEADING_RANDOM
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the number of variant models available for the object.
|
||||
*
|
||||
* @return The number of variant models.
|
||||
*/
|
||||
int get_model_count( SGModelLoader *loader,
|
||||
const string &fg_root,
|
||||
SGPropertyNode *prop_root,
|
||||
double sim_time_sec );
|
||||
|
||||
|
||||
/**
|
||||
* Get a specific variant model for the object.
|
||||
*
|
||||
* @param index The index of the model.
|
||||
* @return The model.
|
||||
*/
|
||||
ssgEntity *get_model( int index,
|
||||
SGModelLoader *loader,
|
||||
const string &fg_root,
|
||||
SGPropertyNode *prop_root,
|
||||
double sim_time_sec );
|
||||
|
||||
|
||||
/**
|
||||
* Get a randomly-selected variant model for the object.
|
||||
*
|
||||
* @return A randomly select model from the variants.
|
||||
*/
|
||||
ssgEntity *get_random_model( SGModelLoader *loader,
|
||||
const string &fg_root,
|
||||
SGPropertyNode *prop_root,
|
||||
double sim_time_sec );
|
||||
|
||||
|
||||
/**
|
||||
* Get the average number of meters^2 occupied by each instance.
|
||||
*
|
||||
* @return The coverage in meters^2.
|
||||
*/
|
||||
double get_coverage_m2 () const;
|
||||
|
||||
|
||||
/**
|
||||
* Get the heading type for the object.
|
||||
*
|
||||
* @return The heading type.
|
||||
*/
|
||||
HeadingType get_heading_type () const;
|
||||
|
||||
protected:
|
||||
|
||||
friend class ObjectGroup;
|
||||
|
||||
Object (const SGPropertyNode * node, double range_m);
|
||||
|
||||
virtual ~Object ();
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
* Actually load the models.
|
||||
*
|
||||
* This class uses lazy loading so that models won't be held
|
||||
* in memory for materials that are never referenced.
|
||||
*/
|
||||
void load_models( SGModelLoader *loader,
|
||||
const string &fg_root,
|
||||
SGPropertyNode *prop_root,
|
||||
double sim_time_sec );
|
||||
|
||||
vector<string> _paths;
|
||||
mutable vector<ssgEntity *> _models;
|
||||
mutable bool _models_loaded;
|
||||
double _coverage_m2;
|
||||
double _range_m;
|
||||
HeadingType _heading_type;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A collection of related objects with the same visual range.
|
||||
*
|
||||
* Grouping objects with the same range together significantly
|
||||
* reduces the memory requirements of randomly-placed objects.
|
||||
* Each SGMaterial instance keeps a (possibly-empty) list of
|
||||
* object groups for placing randomly on the scenery.
|
||||
*/
|
||||
class ObjectGroup
|
||||
{
|
||||
public:
|
||||
virtual ~ObjectGroup ();
|
||||
|
||||
|
||||
/**
|
||||
* Get the visual range of the object in meters.
|
||||
*
|
||||
* @return The visual range.
|
||||
*/
|
||||
double get_range_m () const;
|
||||
|
||||
|
||||
/**
|
||||
* Get the number of objects in the group.
|
||||
*
|
||||
* @return The number of objects.
|
||||
*/
|
||||
int get_object_count () const;
|
||||
|
||||
|
||||
/**
|
||||
* Get a specific object.
|
||||
*
|
||||
* @param index The object's index, zero-based.
|
||||
* @return The object selected.
|
||||
*/
|
||||
Object * get_object (int index) const;
|
||||
|
||||
protected:
|
||||
|
||||
friend class SGMaterial;
|
||||
|
||||
ObjectGroup (SGPropertyNode * node);
|
||||
|
||||
private:
|
||||
|
||||
double _range_m;
|
||||
vector<Object *> _objects;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Public Constructors.
|
||||
@@ -311,7 +150,7 @@ public:
|
||||
/**
|
||||
* Get a randomly-placed object for this material.
|
||||
*/
|
||||
virtual ObjectGroup * get_object_group (int index) const {
|
||||
virtual SGMatObjectGroup * get_object_group (int index) const {
|
||||
return object_groups[index];
|
||||
}
|
||||
|
||||
@@ -383,7 +222,7 @@ private:
|
||||
// true if texture loading deferred, and not yet loaded
|
||||
bool texture_loaded;
|
||||
|
||||
vector<ObjectGroup *> object_groups;
|
||||
vector<SGMatObjectGroup *> object_groups;
|
||||
|
||||
// ref count so we can properly delete if we have multiple
|
||||
// pointers to this record
|
||||
|
||||
250
simgear/scene/material/matobj.cxx
Normal file
250
simgear/scene/material/matobj.cxx
Normal file
@@ -0,0 +1,250 @@
|
||||
// matobj.cxx -- class to handle material properties
|
||||
//
|
||||
// Written by Curtis Olson, started May 1998.
|
||||
//
|
||||
// Copyright (C) 1998 - 2003 Curtis L. Olson - curt@flightgear.org
|
||||
//
|
||||
// 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 <simgear_config.h>
|
||||
#endif
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
|
||||
#include <map>
|
||||
SG_USING_STD(map);
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
|
||||
#ifdef SG_MATH_EXCEPTION_CLASH
|
||||
# include <math.h>
|
||||
#endif
|
||||
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
#include <simgear/math/sg_random.h>
|
||||
#include <simgear/misc/sg_path.hxx>
|
||||
#include <simgear/misc/sgstream.hxx>
|
||||
#include <simgear/scene/model/loader.hxx>
|
||||
|
||||
#include "matobj.hxx"
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Local static functions.
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Internal method to test whether a file exists.
|
||||
*
|
||||
* TODO: this should be moved to a SimGear library of local file
|
||||
* functions.
|
||||
*/
|
||||
static inline bool
|
||||
local_file_exists( const string& path ) {
|
||||
sg_gzifstream in( path );
|
||||
if ( ! in.is_open() ) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Implementation of SGMatObject.
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SGMatObject::SGMatObject (const SGPropertyNode * node, double range_m)
|
||||
: _models_loaded(false),
|
||||
_coverage_m2(node->getDoubleValue("coverage-m2", 1000000)),
|
||||
_range_m(range_m)
|
||||
{
|
||||
// Sanity check
|
||||
if (_coverage_m2 < 1000) {
|
||||
SG_LOG(SG_INPUT, SG_ALERT, "Random object coverage " << _coverage_m2
|
||||
<< " is too small, forcing, to 1000");
|
||||
_coverage_m2 = 1000;
|
||||
}
|
||||
|
||||
// Note all the model paths
|
||||
vector <SGPropertyNode_ptr> path_nodes = node->getChildren("path");
|
||||
for (unsigned int i = 0; i < path_nodes.size(); i++)
|
||||
_paths.push_back(path_nodes[i]->getStringValue());
|
||||
|
||||
// Note the heading type
|
||||
string hdg = node->getStringValue("heading-type", "fixed");
|
||||
if (hdg == "fixed") {
|
||||
_heading_type = HEADING_FIXED;
|
||||
} else if (hdg == "billboard") {
|
||||
_heading_type = HEADING_BILLBOARD;
|
||||
} else if (hdg == "random") {
|
||||
_heading_type = HEADING_RANDOM;
|
||||
} else {
|
||||
_heading_type = HEADING_FIXED;
|
||||
SG_LOG(SG_INPUT, SG_ALERT, "Unknown heading type: " << hdg
|
||||
<< "; using 'fixed' instead.");
|
||||
}
|
||||
|
||||
// uncomment to preload models
|
||||
// load_models();
|
||||
}
|
||||
|
||||
SGMatObject::~SGMatObject ()
|
||||
{
|
||||
for (unsigned int i = 0; i < _models.size(); i++) {
|
||||
if (_models[i] != 0) {
|
||||
_models[i]->deRef();
|
||||
_models[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
SGMatObject::get_model_count( SGModelLoader *loader,
|
||||
const string &fg_root,
|
||||
SGPropertyNode *prop_root,
|
||||
double sim_time_sec )
|
||||
{
|
||||
load_models( loader, fg_root, prop_root, sim_time_sec );
|
||||
return _models.size();
|
||||
}
|
||||
|
||||
inline void
|
||||
SGMatObject::load_models ( SGModelLoader *loader,
|
||||
const string &fg_root,
|
||||
SGPropertyNode *prop_root,
|
||||
double sim_time_sec )
|
||||
{
|
||||
// Load model only on demand
|
||||
if (!_models_loaded) {
|
||||
for (unsigned int i = 0; i < _paths.size(); i++) {
|
||||
ssgEntity *entity = loader->load_model( fg_root, _paths[i],
|
||||
prop_root, sim_time_sec );
|
||||
if (entity != 0) {
|
||||
// FIXME: this stuff can be handled
|
||||
// in the XML wrapper as well (at least,
|
||||
// the billboarding should be handled
|
||||
// there).
|
||||
float ranges[] = {0, _range_m};
|
||||
ssgRangeSelector * lod = new ssgRangeSelector;
|
||||
lod->ref();
|
||||
lod->setRanges(ranges, 2);
|
||||
if (_heading_type == HEADING_BILLBOARD) {
|
||||
ssgCutout * cutout = new ssgCutout(false);
|
||||
cutout->addKid(entity);
|
||||
lod->addKid(cutout);
|
||||
} else {
|
||||
lod->addKid(entity);
|
||||
}
|
||||
_models.push_back(lod);
|
||||
} else {
|
||||
SG_LOG(SG_INPUT, SG_ALERT, "Failed to load object " << _paths[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
_models_loaded = true;
|
||||
}
|
||||
|
||||
ssgEntity *
|
||||
SGMatObject::get_model( int index,
|
||||
SGModelLoader *loader,
|
||||
const string &fg_root,
|
||||
SGPropertyNode *prop_root,
|
||||
double sim_time_sec )
|
||||
{
|
||||
load_models( loader, fg_root, prop_root, sim_time_sec ); // comment this out if preloading models
|
||||
return _models[index];
|
||||
}
|
||||
|
||||
ssgEntity *
|
||||
SGMatObject::get_random_model( SGModelLoader *loader,
|
||||
const string &fg_root,
|
||||
SGPropertyNode *prop_root,
|
||||
double sim_time_sec )
|
||||
{
|
||||
load_models( loader, fg_root, prop_root, sim_time_sec ); // comment this out if preloading models
|
||||
int nModels = _models.size();
|
||||
int index = int(sg_random() * nModels);
|
||||
if (index >= nModels)
|
||||
index = 0;
|
||||
return _models[index];
|
||||
}
|
||||
|
||||
double
|
||||
SGMatObject::get_coverage_m2 () const
|
||||
{
|
||||
return _coverage_m2;
|
||||
}
|
||||
|
||||
SGMatObject::HeadingType
|
||||
SGMatObject::get_heading_type () const
|
||||
{
|
||||
return _heading_type;
|
||||
}
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Implementation of SGMatObjectGroup.
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SGMatObjectGroup::SGMatObjectGroup (SGPropertyNode * node)
|
||||
: _range_m(node->getDoubleValue("range-m", 2000))
|
||||
{
|
||||
// Load the object subnodes
|
||||
vector<SGPropertyNode_ptr> object_nodes =
|
||||
((SGPropertyNode *)node)->getChildren("object");
|
||||
for (unsigned int i = 0; i < object_nodes.size(); i++) {
|
||||
const SGPropertyNode * object_node = object_nodes[i];
|
||||
if (object_node->hasChild("path"))
|
||||
_objects.push_back(new SGMatObject(object_node, _range_m));
|
||||
else
|
||||
SG_LOG(SG_INPUT, SG_ALERT, "No path supplied for object");
|
||||
}
|
||||
}
|
||||
|
||||
SGMatObjectGroup::~SGMatObjectGroup ()
|
||||
{
|
||||
for (unsigned int i = 0; i < _objects.size(); i++) {
|
||||
delete _objects[i];
|
||||
_objects[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
double
|
||||
SGMatObjectGroup::get_range_m () const
|
||||
{
|
||||
return _range_m;
|
||||
}
|
||||
|
||||
int
|
||||
SGMatObjectGroup::get_object_count () const
|
||||
{
|
||||
return _objects.size();
|
||||
}
|
||||
|
||||
SGMatObject *
|
||||
SGMatObjectGroup::get_object (int index) const
|
||||
{
|
||||
return _objects[index];
|
||||
}
|
||||
|
||||
|
||||
// end of matobj.cxx
|
||||
205
simgear/scene/material/matobj.hxx
Normal file
205
simgear/scene/material/matobj.hxx
Normal file
@@ -0,0 +1,205 @@
|
||||
// matobj.hxx -- a material in the scene graph.
|
||||
// TODO: this class needs to be renamed.
|
||||
//
|
||||
// Written by Curtis Olson, started May 1998.
|
||||
// Overhauled by David Megginson, December 2001
|
||||
//
|
||||
// Copyright (C) 1998 - 2003 Curtis L. Olson - curt@flightgear.org
|
||||
//
|
||||
// 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$
|
||||
|
||||
|
||||
#ifndef _SG_MAT_OBJ_HXX
|
||||
#define _SG_MAT_OBJ_HXX
|
||||
|
||||
#ifndef __cplusplus
|
||||
# error This library requires C++
|
||||
#endif
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
|
||||
#include STL_STRING // Standard C++ string library
|
||||
|
||||
#include <plib/sg.h>
|
||||
#include <plib/ssg.h>
|
||||
|
||||
#include <simgear/props/props.hxx>
|
||||
#include <simgear/scene/model/loader.hxx>
|
||||
|
||||
SG_USING_STD(string);
|
||||
|
||||
|
||||
class SGMatObjectGroup;
|
||||
|
||||
|
||||
/**
|
||||
* A randomly-placeable object.
|
||||
*
|
||||
* SGMaterial uses this class to keep track of the model(s) and
|
||||
* parameters for a single instance of a randomly-placeable object.
|
||||
* The object can have more than one variant model (i.e. slightly
|
||||
* different shapes of trees), but they are considered equivalent
|
||||
* and interchangeable.
|
||||
*/
|
||||
class SGMatObject {
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* The heading type for a randomly-placed object.
|
||||
*/
|
||||
enum HeadingType {
|
||||
HEADING_FIXED,
|
||||
HEADING_BILLBOARD,
|
||||
HEADING_RANDOM
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the number of variant models available for the object.
|
||||
*
|
||||
* @return The number of variant models.
|
||||
*/
|
||||
int get_model_count( SGModelLoader *loader,
|
||||
const string &fg_root,
|
||||
SGPropertyNode *prop_root,
|
||||
double sim_time_sec );
|
||||
|
||||
|
||||
/**
|
||||
* Get a specific variant model for the object.
|
||||
*
|
||||
* @param index The index of the model.
|
||||
* @return The model.
|
||||
*/
|
||||
ssgEntity *get_model( int index,
|
||||
SGModelLoader *loader,
|
||||
const string &fg_root,
|
||||
SGPropertyNode *prop_root,
|
||||
double sim_time_sec );
|
||||
|
||||
|
||||
/**
|
||||
* Get a randomly-selected variant model for the object.
|
||||
*
|
||||
* @return A randomly select model from the variants.
|
||||
*/
|
||||
ssgEntity *get_random_model( SGModelLoader *loader,
|
||||
const string &fg_root,
|
||||
SGPropertyNode *prop_root,
|
||||
double sim_time_sec );
|
||||
|
||||
|
||||
/**
|
||||
* Get the average number of meters^2 occupied by each instance.
|
||||
*
|
||||
* @return The coverage in meters^2.
|
||||
*/
|
||||
double get_coverage_m2 () const;
|
||||
|
||||
|
||||
/**
|
||||
* Get the heading type for the object.
|
||||
*
|
||||
* @return The heading type.
|
||||
*/
|
||||
HeadingType get_heading_type () const;
|
||||
|
||||
protected:
|
||||
|
||||
friend class SGMatObjectGroup;
|
||||
|
||||
SGMatObject (const SGPropertyNode * node, double range_m);
|
||||
|
||||
virtual ~SGMatObject ();
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
* Actually load the models.
|
||||
*
|
||||
* This class uses lazy loading so that models won't be held
|
||||
* in memory for materials that are never referenced.
|
||||
*/
|
||||
void load_models( SGModelLoader *loader,
|
||||
const string &fg_root,
|
||||
SGPropertyNode *prop_root,
|
||||
double sim_time_sec );
|
||||
|
||||
vector<string> _paths;
|
||||
mutable vector<ssgEntity *> _models;
|
||||
mutable bool _models_loaded;
|
||||
double _coverage_m2;
|
||||
double _range_m;
|
||||
HeadingType _heading_type;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A collection of related objects with the same visual range.
|
||||
*
|
||||
* Grouping objects with the same range together significantly
|
||||
* reduces the memory requirements of randomly-placed objects.
|
||||
* Each SGMaterial instance keeps a (possibly-empty) list of
|
||||
* object groups for placing randomly on the scenery.
|
||||
*/
|
||||
class SGMatObjectGroup {
|
||||
|
||||
public:
|
||||
|
||||
virtual ~SGMatObjectGroup ();
|
||||
|
||||
|
||||
/**
|
||||
* Get the visual range of the object in meters.
|
||||
*
|
||||
* @return The visual range.
|
||||
*/
|
||||
double get_range_m () const;
|
||||
|
||||
|
||||
/**
|
||||
* Get the number of objects in the group.
|
||||
*
|
||||
* @return The number of objects.
|
||||
*/
|
||||
int get_object_count () const;
|
||||
|
||||
|
||||
/**
|
||||
* Get a specific object.
|
||||
*
|
||||
* @param index The object's index, zero-based.
|
||||
* @return The object selected.
|
||||
*/
|
||||
SGMatObject * get_object (int index) const;
|
||||
|
||||
protected:
|
||||
|
||||
friend class SGMaterial;
|
||||
|
||||
SGMatObjectGroup (SGPropertyNode * node);
|
||||
|
||||
private:
|
||||
|
||||
double _range_m;
|
||||
vector<SGMatObject *> _objects;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif // _SG_MAT_OBJ_HXX
|
||||
Reference in New Issue
Block a user