1
0
Fork 0

Substantial rewrite of FGNewMat, the material class. Most of the

material-specific logic is now removed from the material library and
encapsulated in the material class itself, and materials are loaded
from $FG_ROOT/materials.xml rather than $FG_ROOT/materials.  This also
removes a nasty bug in the old material-loading code that caused a
floating-point exception.
This commit is contained in:
david 2001-12-28 23:33:32 +00:00
parent 1fa4c88d0e
commit d4aea05246
5 changed files with 301 additions and 321 deletions

View file

@ -529,7 +529,7 @@ bool fgInitSubsystems( void ) {
////////////////////////////////////////////////////////////////////
SGPath mpath( globals->get_fg_root() );
mpath.append( "materials" );
mpath.append( "materials.xml" );
if ( material_lib.load( mpath.str() ) ) {
} else {
SG_LOG( SG_GENERAL, SG_ALERT, "Error loading material lib!" );

View file

@ -37,6 +37,7 @@
#include <GL/gl.h>
#include <simgear/compiler.h>
#include <simgear/misc/exception.hxx>
#include <string.h>
#include STL_STRING
@ -65,105 +66,37 @@ FGMaterialLib::FGMaterialLib ( void ) {
}
static bool local_file_exists( const string& path ) {
sg_gzifstream in( path );
if ( ! in.is_open() ) {
return false;
} else {
return true;
}
}
// Load a library of material properties
bool FGMaterialLib::load( const string& mpath ) {
string material_name;
sg_gzifstream in( mpath );
if ( ! in.is_open() ) {
SG_LOG( SG_GENERAL, SG_ALERT, "Cannot open file: " << mpath );
exit(-1);
}
#ifndef __MWERKS__
while ( ! in.eof() ) {
#else
char c = '\0';
while ( in.get(c) && c != '\0' ) {
in.putback(c);
#endif
// printf("%s", line);
// strip leading white space and comments
in >> skipcomment;
// set to zero to prevent its value accidently being '{'
// after a failed >> operation.
char token = 0;
in >> material_name;
if ( material_name == "alias" ) {
string src_mat, dst_mat;
in >> dst_mat >> src_mat;
SG_LOG( SG_GENERAL, SG_INFO, " Material alias: " << dst_mat <<
" mapped to " << src_mat );
FGNewMat *m = matlib[src_mat];
if ( m != NULL ) {
matlib[dst_mat] = m;
m->ref();
} else {
SG_LOG( SG_GENERAL, SG_ALERT,
"Bad material alias pointing to nonexistant material" );
}
} else {
in >> token;
if ( token == '{' ) {
// Read the data into a temporary but stack allocated
// copy of the structure
FGNewMat tmp;
in >> tmp;
// create a pointer to a heap allocated copy of the structure
FGNewMat *m = new FGNewMat;
*m = tmp;
m->ref();
// build the ssgSimpleState
SGPath tex_path( globals->get_fg_root() );
tex_path.append( "Textures.high" );
tex_path.append( m->get_texture_name() );
if ( ! local_file_exists(tex_path.str())
|| general.get_glMaxTexSize() < 512 ) {
tex_path = SGPath( globals->get_fg_root() );
tex_path.append( "Textures" );
tex_path.append( m->get_texture_name() );
}
SG_LOG( SG_TERRAIN, SG_INFO, " Loading material "
<< material_name << " (" << tex_path.c_str() << ")");
GLenum shade_model = GL_SMOOTH;
if ( fgGetBool("/sim/rendering/shading") ) {
shade_model = GL_SMOOTH;
} else {
shade_model = GL_FLAT;
}
m->set_texture_name( tex_path.str() );
m->build_ssg_state( shade_model,
fgGetBool("/sim/rendering/textures"),
false );
#if EXTRA_DEBUG
m->dump_info();
#endif
matlib[material_name] = m;
}
}
SGPropertyNode materials;
cout << "Reading materials from " << mpath << endl;
try {
readProperties(mpath, &materials);
} catch (const sg_exception &ex) {
SG_LOG(SG_INPUT, SG_ALERT, "Error reading materials: " << ex.getMessage());
throw ex;
}
int nMaterials = materials.nChildren();
for (int i = 0; i < nMaterials; i++) {
const SGPropertyNode * node = materials.getChild(i);
if (node->getName() == "material") {
FGNewMat * m = new FGNewMat(node);
vector<const SGPropertyNode *>names = node->getChildren("name");
for (int j = 0; j < names.size(); j++) {
m->ref();
matlib[names[j]->getStringValue()] = m;
SG_LOG( SG_TERRAIN, SG_INFO, " Loading material "
<< names[j]->getStringValue());
}
} else {
SG_LOG(SG_INPUT, SG_ALERT,
"Skipping bad material entry " << node->getName());
}
}
// hard coded light state
ssgSimpleState *lights = new ssgSimpleState;
@ -178,9 +111,7 @@ bool FGMaterialLib::load( const string& mpath ) {
lights->disable( GL_ALPHA_TEST );
lights->disable( GL_LIGHTING );
FGNewMat *m = new FGNewMat;
m->set_ssg_state( lights );
matlib["LIGHTS"] = m;
matlib["LIGHTS"] = new FGNewMat(lights);
return true;
}
@ -204,27 +135,10 @@ bool FGMaterialLib::add_item ( const string &mat_name, const string &full_path )
string tex_name = full_path.substr( pos + 1 );
string tex_path = full_path.substr( 0, pos );
FGNewMat *m = new FGNewMat( mat_name, full_path );
SG_LOG( SG_TERRAIN, SG_INFO, " Loading material "
<< mat_name << " (" << full_path << ")");
#if EXTRA_DEBUG
m->dump_info();
#endif
GLenum shade_model = GL_SMOOTH;
if ( fgGetBool("/sim/rendering/shading") ) {
shade_model = GL_SMOOTH;
} else {
shade_model = GL_FLAT;
}
m->build_ssg_state( shade_model,
fgGetBool("/sim/rendering/textures"),
true );
material_lib.matlib[mat_name] = m;
material_lib.matlib[mat_name] = new FGNewMat(full_path);
return true;
}
@ -233,16 +147,11 @@ bool FGMaterialLib::add_item ( const string &mat_name, const string &full_path )
// Load a library of material properties
bool FGMaterialLib::add_item ( const string &mat_name, ssgSimpleState *state )
{
FGNewMat *m = new FGNewMat( mat_name );
m->set_ssg_state( state );
FGNewMat *m = new FGNewMat(state);
SG_LOG( SG_TERRAIN, SG_INFO, " Loading material given a premade "
<< "ssgSimpleState = " << mat_name );
#if EXTRA_DEBUG
m->dump_info();
#endif
material_lib.matlib[mat_name] = m;
return true;
@ -304,18 +213,7 @@ void FGMaterialLib::load_next_deferred() {
for ( material_map_iterator it = begin(); it != end(); it++ ) {
const string &key = it->first;
FGNewMat *slot = it->second;
// SG_LOG( SG_GENERAL, SG_INFO, "slot = " << slot );
if ( ! slot->get_texture_loaded() ) {
SG_LOG( SG_GENERAL, SG_INFO, "Loading deferred texture for "
<< key );
#ifdef PLIB_1_2_X
slot->get_textured()->
setTexture( (char *)slot->get_texture_name_c_str(), 0, 0 );
#else
slot->get_textured()->
setTexture( (char *)slot->get_texture_name_c_str(), 0, 0, 1 );
#endif
slot->set_texture_loaded( true );
}
if (slot->load_texture())
return;
}
}

View file

@ -88,8 +88,9 @@ public:
void set_step (int step);
int get_step ();
// Load one pending "deferred" texture. Return true if a texture
// loaded successfully, false if no pending, or error.
/**
* Load the next deferred texture, if there is any.
*/
void load_next_deferred();
material_map_iterator begin() { return matlib.begin(); }

View file

@ -35,46 +35,87 @@
#include <simgear/misc/sg_path.hxx>
#include <simgear/misc/sgstream.hxx>
#include <Main/globals.hxx>
#include <Main/fg_props.hxx>
#include "newmat.hxx"
// Constructor
FGNewMat::FGNewMat ( void ) {
wrapu = wrapv = 1;
mipmap = 1;
light_coverage = -1.0;
refcount = 0;
static bool
local_file_exists( const string& path ) {
sg_gzifstream in( path );
if ( ! in.is_open() ) {
return false;
} else {
return true;
}
}
// Constructor
FGNewMat::FGNewMat ( const string &name )
FGNewMat::FGNewMat ()
: texture_path(""),
state(0),
textured(0),
nontextured(0),
alpha(false),
xsize(0),
ysize(0),
wrapu(true),
wrapv(true),
mipmap(true),
texture_loaded(false),
refcount(0)
{
FGNewMat( name, name );
for (int i = 0; i < 4; i++)
ambient[i] = diffuse[i] = specular[i] = emission[i] = 0.0;
}
FGNewMat::FGNewMat (const SGPropertyNode * props)
{
FGNewMat();
read_properties(props);
build_ssg_state(false);
}
FGNewMat::FGNewMat (const string &texture_path)
{
FGNewMat();
build_ssg_state(true);
}
FGNewMat::FGNewMat (ssgSimpleState * s)
{
FGNewMat();
set_ssg_state(s);
}
// Constructor
FGNewMat::FGNewMat ( const string &mat_name, const string &tex_name )
bool
FGNewMat::load_texture ()
{
material_name = mat_name;
texture_name = tex_name;
xsize = ysize = 0;
wrapu = wrapv = 1;
mipmap = 1;
alpha = 0;
ambient[0] = ambient[1] = ambient[2] = ambient[3] = 1.0;
diffuse[0] = diffuse[1] = diffuse[2] = diffuse[3] = 1.0;
specular[0] = specular[1] = specular[2] = specular[3] = 1.0;
emission[0] = emission[1] = emission[2] = emission[3] = 1.0;
light_coverage = -1.0;
refcount = 0;
if (texture_loaded) {
return false;
} else {
SG_LOG( SG_GENERAL, SG_INFO, "Loading deferred texture " << texture_path );
#ifdef PLIB_1_2_X
textured->setTexture((char *)texture_path.c_str(), wrapu, wrapv );
#else
textured->setTexture((char *)texture_path.c_str(), wrapu, wrapv, mipmap );
#endif
texture_loaded = true;
return true;
}
}
void FGNewMat::build_ssg_state( GLenum shade_model, bool texture_default,
bool defer_tex_load )
void FGNewMat::build_ssg_state( bool defer_tex_load )
{
GLenum shade_model =
(fgGetBool("/sim/rendering/shading") ? GL_SMOOTH : GL_FLAT);
bool texture_default = fgGetBool("/sim/rendering/textures");
state = new ssgStateSelector(2);
state->ref();
@ -92,12 +133,11 @@ void FGNewMat::build_ssg_state( GLenum shade_model, bool texture_default,
textured->disable( GL_BLEND );
textured->disable( GL_ALPHA_TEST );
if ( !defer_tex_load ) {
textured->setTexture( (char *)texture_name.c_str(), wrapu, wrapv );
textured->setTexture( (char *)texture_path.c_str(), wrapu, wrapv );
texture_loaded = true;
} else {
texture_loaded = false;
}
// cout << "wrap u = " << wrapu << " wrapv = " << wrapv << endl;
textured->enable( GL_COLOR_MATERIAL );
textured->setColourMaterial( GL_AMBIENT_AND_DIFFUSE );
textured->setMaterial( GL_EMISSION, 0, 0, 0, 1 );
@ -112,8 +152,6 @@ void FGNewMat::build_ssg_state( GLenum shade_model, bool texture_default,
nontextured->disable( GL_ALPHA_TEST );
nontextured->disable( GL_COLOR_MATERIAL );
/* cout << "ambient = " << ambient[0] << "," << ambient[1]
<< "," << ambient[2] << endl; */
nontextured->setMaterial ( GL_AMBIENT,
ambient[0], ambient[1],
ambient[2], ambient[3] ) ;
@ -180,75 +218,50 @@ void FGNewMat::set_ssg_state( ssgSimpleState *s ) {
}
void FGNewMat::dump_info () {
SG_LOG( SG_TERRAIN, SG_INFO, "{" << endl << " texture = "
<< texture_name );
SG_LOG( SG_TERRAIN, SG_INFO, " xsize = " << xsize );
SG_LOG( SG_TERRAIN, SG_INFO, " ysize = " << ysize );
SG_LOG( SG_TERRAIN, SG_INFO, " ambient = " << ambient[0] << " "
<< ambient[1] <<" "<< ambient[2] <<" "<< ambient[3] );
SG_LOG( SG_TERRAIN, SG_INFO, " diffuse = " << diffuse[0] << " "
<< diffuse[1] << " " << diffuse[2] << " " << diffuse[3] );
SG_LOG( SG_TERRAIN, SG_INFO, " specular = " << specular[0] << " "
<< specular[1] << " " << specular[2] << " " << specular[3]);
SG_LOG( SG_TERRAIN, SG_INFO, " emission = " << emission[0] << " "
<< emission[1] << " " << emission[2] << " " << emission[3]);
SG_LOG( SG_TERRAIN, SG_INFO, " alpha = " << alpha << endl <<"}" );
}
// Destructor
FGNewMat::~FGNewMat ( void ) {
}
istream&
operator >> ( istream& in, FGNewMat& m )
void
FGNewMat::read_properties (const SGPropertyNode * props)
{
string token;
// Get the path to the texture
string tname = props->getStringValue("texture", "unknown.rgb");
SGPath tpath(globals->get_fg_root());
tpath.append("Textures.high");
tpath.append(tname);
if (!local_file_exists(tpath.str())) {
tpath = SGPath(globals->get_fg_root());
tpath.append("Textures");
tpath.append(tname);
}
texture_path = tpath.str();
for (;;) {
in >> token;
if ( token == "texture" ) {
in >> token >> m.texture_name;
} else if ( token == "xsize" ) {
in >> token >> m.xsize;
} else if ( token == "ysize" ) {
in >> token >> m.ysize;
} else if ( token == "wrapu" ) {
in >> token >> m.wrapu;
} else if ( token == "wrapv" ) {
in >> token >> m.wrapv;
} else if ( token == "mipmap" ) {
in >> token >> m.mipmap;
} else if ( token == "ambient" ) {
in >> token >> m.ambient[0] >> m.ambient[1]
>> m.ambient[2] >> m.ambient[3];
} else if ( token == "diffuse" ) {
in >> token >> m.diffuse[0] >> m.diffuse[1]
>> m.diffuse[2] >> m.diffuse[3];
} else if ( token == "specular" ) {
in >> token >> m.specular[0] >> m.specular[1]
>> m.specular[2] >> m.specular[3];
} else if ( token == "emission" ) {
in >> token >> m.emission[0] >> m.emission[1]
>> m.emission[2] >> m.emission[3];
} else if ( token == "alpha" ) {
in >> token >> token;
if ( token == "yes" ) {
m.alpha = 1;
} else if ( token == "no" ) {
m.alpha = 0;
} else {
SG_LOG( SG_TERRAIN, SG_INFO, "Bad alpha value " << token );
}
} else if ( token == "light-coverage" ) {
in >> token >> m.light_coverage;
} else if ( token[0] == '}' ) {
break;
}
}
xsize = props->getDoubleValue("xsize", 0.0);
ysize = props->getDoubleValue("ysize", 0.0);
wrapu = props->getBoolValue("wrapu", true);
wrapv = props->getBoolValue("wrapv", true);
mipmap = props->getBoolValue("mipmap", true);
light_coverage = props->getDoubleValue("light-coverage");
return in;
ambient[0] = props->getDoubleValue("ambient/r", 0.0);
ambient[1] = props->getDoubleValue("ambient/g", 0.0);
ambient[2] = props->getDoubleValue("ambient/b", 0.0);
ambient[3] = props->getDoubleValue("ambient/a", 0.0);
diffuse[0] = props->getDoubleValue("diffuse/r", 0.0);
diffuse[1] = props->getDoubleValue("diffuse/g", 0.0);
diffuse[2] = props->getDoubleValue("diffuse/b", 0.0);
diffuse[3] = props->getDoubleValue("diffuse/a", 0.0);
specular[0] = props->getDoubleValue("specular/r", 0.0);
specular[1] = props->getDoubleValue("specular/g", 0.0);
specular[2] = props->getDoubleValue("specular/b", 0.0);
specular[3] = props->getDoubleValue("specular/a", 0.0);
emission[0] = props->getDoubleValue("emissive/r", 0.0);
emission[1] = props->getDoubleValue("emissive/g", 0.0);
emission[2] = props->getDoubleValue("emissive/b", 0.0);
emission[3] = props->getDoubleValue("emissive/a", 0.0);
}

View file

@ -1,6 +1,8 @@
// newmat.hxx -- class to handle material properties
// newmat.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 - 2000 Curtis L. Olson - curt@flightgear.org
//
@ -24,7 +26,6 @@
#ifndef _NEWMAT_HXX
#define _NEWMAT_HXX
#ifndef __cplusplus
# error This library requires C++
#endif
@ -41,6 +42,7 @@
#include <plib/ssg.h>
#include <simgear/compiler.h>
#include <simgear/misc/props.hxx>
#include <GL/glut.h>
@ -49,113 +51,179 @@
SG_USING_STD(string);
// MSVC++ 6.0 kuldge - Need forward declaration of friends.
class FGNewMat;
istream& operator >> ( istream& in, FGNewMat& m );
// Material property class
/**
* A material in the scene graph.
*
* A material represents information about a single surface type
* in the 3D scene graph, including texture, colour, lighting,
* tiling, and so on; most of the materials in FlightGear are
* defined in the $FG_ROOT/materials.xml file, and can be changed
* at runtime.
*/
class FGNewMat {
private:
// names
string material_name;
string texture_name;
// pointers to ssg states
ssgStateSelector *state;
ssgSimpleState *textured;
ssgSimpleState *nontextured;
// alpha texture?
int alpha;
// texture size
double xsize, ysize;
// wrap texture?
int wrapu, wrapv;
// use mipmapping?
int mipmap;
// coverage of night lighting. This number is specifically the
// amount of area coverage we give a single light. The size of a
// triangle is divided by this number and that is the number of
// lights assigned to that triangle. Lower numbers mean more
// dense light ocverage.
double light_coverage;
// material properties
sgVec4 ambient, diffuse, specular, emission;
// true if texture loading deferred, and not yet loaded
bool texture_loaded;
// ref count so we can properly delete if we have multiple
// pointers to this record
int refcount;
public:
// Constructor
FGNewMat ( void );
FGNewMat ( const string& name );
FGNewMat ( const string &mat_name, const string &tex_name );
////////////////////////////////////////////////////////////////////
// Public Constructors.
////////////////////////////////////////////////////////////////////
// Destructor
~FGNewMat ( void );
/**
* Construct a material from a set of properties.
*
* @param props A property node containing subnodes with the
* state information for the material. This node is usually
* loaded from the $FG_ROOT/materials.xml file.
*/
FGNewMat (const SGPropertyNode * props);
friend istream& operator >> ( istream& in, FGNewMat& m );
// void load_texture( const string& root );
void build_ssg_state( GLenum shade_model, bool texture_default,
bool defer_tex_load = false );
void set_ssg_state( ssgSimpleState *s );
/**
* Construct a material from an absolute texture path.
*
* @param texture_path A string containing an absolute path
* to a texture file (usually RGB).
*/
FGNewMat (const string &texture_path);
inline string get_material_name() const { return material_name; }
inline void set_material_name( const string& n ) { material_name = n; }
inline string get_texture_name() const { return texture_name; }
inline const char *get_texture_name_c_str() const {
return texture_name.c_str();
}
inline void set_texture_name( const string& n ) { texture_name = n; }
/**
* Construct a material around an existing SSG state.
*
* This constructor allows the application to create a custom,
* low-level state for the scene graph and wrap a material around
* it. Note: the pointer ownership is transferred to the material.
*
* @param s The SSG state for this material.
*/
FGNewMat (ssgSimpleState * s);
inline ssgSimpleState *get_textured() { return textured; }
/**
* Destructor.
*/
virtual ~FGNewMat ( void );
inline double get_xsize() const { return xsize; }
inline double get_ysize() const { return ysize; }
inline void set_xsize( double x ) { xsize = x; }
inline void set_ysize( double y ) { ysize = y; }
inline float *get_ambient() { return ambient; }
inline float *get_diffuse() { return diffuse; }
inline float *get_specular() { return specular; }
inline float *get_emission() { return emission; }
inline void set_ambient( sgVec4 a ) { sgCopyVec4( ambient, a ); }
inline void set_diffuse( sgVec4 d ) { sgCopyVec4( diffuse, d ); }
inline void set_specular( sgVec4 s ) { sgCopyVec4( specular, s ); }
inline void set_emission( sgVec4 e ) { sgCopyVec4( emission, e ); }
////////////////////////////////////////////////////////////////////
// Public methods.
////////////////////////////////////////////////////////////////////
inline bool get_texture_loaded() const { return texture_loaded; }
inline void set_texture_loaded( bool val ) { texture_loaded = val; }
/**
* Force the texture to load if it hasn't already.
*
* @return true if the texture loaded, false if it was loaded
* already.
*/
virtual bool load_texture ();
inline double get_light_coverage () const { return light_coverage; }
inline void set_light_coverage (double coverage) {
light_coverage = coverage;
}
inline ssgStateSelector *get_state() const { return state; }
/**
* Get the textured state.
*/
virtual inline ssgSimpleState *get_textured () { return textured; }
inline void ref() { refcount++; }
inline void deRef() { refcount--; }
inline int getRef() const { return refcount; }
void dump_info();
/**
* Get the xsize of the texture, in meters.
*/
virtual inline double get_xsize() const { return xsize; }
/**
* Get the ysize of the texture, in meters.
*/
virtual inline double get_ysize() const { return ysize; }
/**
* Get the light coverage.
*
* A smaller number means more generated night lighting.
*
* @return The area (m^2?) covered by each light.
*/
virtual inline double get_light_coverage () const { return light_coverage; }
/**
* Get the current state.
*/
virtual inline ssgStateSelector *get_state() const { return state; }
/**
* Add a reference to the texture.
*/
virtual inline void ref() { refcount++; }
/**
* Remove a reference from the texture.
*/
virtual inline void deRef() { refcount--; }
/**
* Get the number of references to the texture.
*/
virtual inline int getRef() const { return refcount; }
private:
////////////////////////////////////////////////////////////////////
// Internal state.
////////////////////////////////////////////////////////////////////
// names
string texture_path;
// pointers to ssg states
ssgStateSelector *state;
ssgSimpleState *textured;
ssgSimpleState *nontextured;
// alpha texture?
bool alpha;
// texture size
double xsize, ysize;
// wrap texture?
bool wrapu, wrapv;
// use mipmapping?
int mipmap;
// coverage of night lighting.
double light_coverage;
// material properties
sgVec4 ambient, diffuse, specular, emission;
// true if texture loading deferred, and not yet loaded
bool texture_loaded;
// ref count so we can properly delete if we have multiple
// pointers to this record
int refcount;
////////////////////////////////////////////////////////////////////
// Internal constructors and methods.
////////////////////////////////////////////////////////////////////
FGNewMat ();
FGNewMat (const FGNewMat &mat); // unimplemented
void read_properties (const SGPropertyNode * props);
void build_ssg_state(bool defer_tex_load = false);
void set_ssg_state( ssgSimpleState *s );
};
#endif // _NEWMAT_HXX