diff --git a/acinclude.m4 b/acinclude.m4 index d79f3f0b2..7822c2a4d 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -650,7 +650,7 @@ if test "x$want_boost" = "xyes"; then if test "$_version" = "0" ; then AC_MSG_ERROR([[We could not detect the boost libraries (version $boost_lib_version_req_shorten or higher). If you have a staged boost library (still not installed) please specify \$BOOST_ROOT in your environment and do not give a PATH to --with-boost option. If you are sure you have boost installed, then check your version number looking in . See http://randspringer.de/boost for more documentation.]]) else - AC_MSG_NOTICE([Your boost libraries seems to old (version $_version).]) + AC_MSG_ERROR([Your boost libraries seems to old (version $_version).]) fi else AC_SUBST(BOOST_CPPFLAGS) diff --git a/configure.ac b/configure.ac index c1be73cf0..6ae6d7438 100644 --- a/configure.ac +++ b/configure.ac @@ -20,7 +20,7 @@ AC_PROG_CXX AC_PROG_RANLIB AC_PROG_INSTALL AC_PROG_LN_S -AX_BOOST_BASE([1.34.0]) +AX_BOOST_BASE([1.37.0]) if test "x$BOOST_CPPFLAGS" != "x-I/usr/include" ; then CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS" diff --git a/docs-mini/README.effects b/docs-mini/README.effects index 60b30386a..f6d2b3159 100644 --- a/docs-mini/README.effects +++ b/docs-mini/README.effects @@ -1,3 +1,6 @@ +Effects +------- + Effects describe the graphical appearance of 3d objects and scenery in FlightGear. The main motivation for effects is to support OpenGL shaders and to provide different implementations for graphics hardware @@ -10,13 +13,16 @@ values. Effects are read from files with a ".eff" extension or can be created on-the-fly by FlightGear at runtime. An effect consists of a "parameters" section followed by "technique" descriptions. The "parameters" section is a tree of values that describe, abstractly, -the graphical appearence of objects that use the effect. Techniques +the graphical characteristics of objects that use the effect. Techniques refer to these parameters and use them to set OpenGL state or to set -parameters for shader programs. +parameters for shader programs. The names of properties in the +parameter section can be whatever the effects author chooses, although +some standard parameters are set by FlightGear itself. On the other +hand, the properties in the techniques section are all defined by the +FlightGear. -Parameters can be declared to have a dynamic variance, which means -that if their value is changed the corresponding value in the -technique will be changed too. [TO BE IMPLEMENTED] +Techniques +---------- A technique can contain a predicate that describes the OpenGL functionality required to support the technique. The first @@ -29,22 +35,131 @@ and, or, equal, less, less-equal glversion - returns the version number of OpenGL extension-supported - returns true if an OpenGL extension is supported property - returns the boolean value of a property +shader-language - returns the version of GLSL supported, or 0 if there is none. + +The proper way to test whether to enable a shader-based technique is: + + + /sim/rendering/shader-effects + + 1.0 + + + + + A technique can consist of several passes. A pass is basically an Open Scene Graph StateSet. Ultimately all OpenGL and OSG modes and state -attributes will be setable in a technique. The following are -are currently implemented: -lighting - true, false -shade-model - flat, smooth +attributes will be accessable in techniques. State attributes -- that +is, technique properties that have children and are not just boolean +modes -- have an parameter which enables or disables the +attribute. In this way a technique can declare parameters it needs, +but not enable the attribute at all if it is not needed; the decision +can be based on a parameter in the parameters section of the +effect. For example, effects that support transparent and opaque +geometry could have as part of a technique: + + + blend/active + src-alpha + one-minus-src-alpha + + +So if the blend/active parameter is true blending will be activated +using the usual blending equation; otherwise blending is disabled. + +Values of Technique Attributes +------------------------------ + +Values are assigned to technique properties in several ways: + + * They can appear directly in the techniques section as a + constant. For example: + + ColorsTex + sampler-1d + 2 + + * The name of a property in the parameters section can be + referenced using a "use" clause. For example, in the technique + section: + + material/ambient + + Then, in the parameters section of the effect: + + + + 0.2 .2 0.2 1.0 + + + + + It's worth pointing out that the "material" property in a + technique specifies part of OpenGL's state, whereas "material" + in the parameters section is just a name, part of a + hierarchical namespace. + + * A property in the parameters section doesn't need to contain + a constant value; it can also contain a "use" property. Here + the value of the use clause is the name of a node in an + external property tree which will be used as the source of a + value. If the name begins with '/', the node is in + FlightGear's global property tree; otherwise, it is in a local + property tree, usually belonging to a model [NOT IMPLEMENTED + YET]. For example: + + /rendering/scene/chrome-light + + The type is determined by what is expected by the technique + attribute that will ultimately receive the value. [There is + no way to get vector values out of the main property system + yet; this will be fixed shortly.] Values that are declared + this way are dynamically updated if the property node + changes. + +OpenGL Attributes +----------------- + +The following attributes are currently implemented in techiques: +alpha-test - children: active, comparison, reference + Valid values for comparision: + never, less, equal, lequal, greater, notequal, gequal, + always + +blend - children: active, source, destination, source-rgb, + source-alpha, destination-rgb, destination-alpha + Each operand can have the following values: + dst-alpha, dst-color, one, one-minus-dst-alpha, + one-minus-dst-color, one-minus-src-alpha, + one-minus-src-color, src-alpha, src-alpha-saturate, + src-color, constant-color, one-minus-constant-color, + constant-alpha, one-minus-constant-alpha, zero + cull-face - front, back, front-back + +lighting - true, false + +material - children: active, ambient, ambient-front, ambient-back, diffuse, + diffuse-front, diffuse-back, specular, specular-front, + specular-back, emissive, emissive-front, emissive-back, shininess, + shininess-front, shininess-back, color-mode + +polygon-mode - children: front, back + Valid values: + fill, line, point + +program + vertex-shader + fragment-shader + +render-bin - (OSG) children: bin-number, bin-name + rendering-hint - (OSG) opaque, transparent -render-bin - children: bin-number, bin-name -material - children: ambient, ambient-front, ambient-back, diffuse, -diffuse-front, diffuse-back, specular, specular-front, -specular-back, emissive, emissive-front, emissive-back, shininess, -shininess-front, shininess-back, color-mode -blend - true, false -alpha-test - true, false + +shade-model - flat, smooth + texture-unit - has several child properties: unit - The number of an OpenGL texture unit type - This is either an OpenGL texture type or the name of a @@ -62,16 +177,17 @@ texture-unit - has several child properties: environment mode color -program - vertex-shader - fragment-shader uniform name type - float, float-vec3, float-vec4, sampler-1d, sampler-2d, sampler-3d -polygon-mode -front - fill, line, point -back - fill, line, point + +vertex-program-two-side - true, false + +vertex-program-point-size - true, false + +Inheritance +----------- One feature not fully illustrated in the sample below is that effects can inherit from each other. The parent effect is listed in @@ -83,164 +199,64 @@ precedence. This means that effects that inherit from the example effect below could be very short, listing just new parameters and adding nothing to the techniques section; alternatively, a technique could be altered or customized in a -child, listing (for example) a different shader program. Terrain -materials work in this way: for each material type in materials.xml -an effect is created that inherits from a single default terrain -effect. The parameters section of the effect is filled in using the -ambient, diffuse, specular, emissive, shininess, and transparent -fields of the material. Seperate effects are created for each texture +child, listing (for example) a different shader program. An example +showing inheritance Effects/crop.eff, which inherits some if its +values from Effects/terrain-default.eff. + +FlightGear directly uses effects inheritance to assign effects to 3D +models and terrain. As described below, at runtime small effects are +created that contain material and texture values in a "parameters" +section. These effects inherit from another effect which references +those parameters in its "techniques" section. The derived effect +overrides any default values that might be in the base effect's +parameters section. + +Default Effects in Terrain Materials and Models +--------------------------------------- + +Effects for terrain work in this way: for each material type in +materials.xml an effect is created that inherits from a single default +terrain effect, Effects/terrain-default.eff. The parameters section of +the effect is filled in using the ambient, diffuse, specular, +emissive, shininess, and transparent fields of the material. The +parameters image, filter, wrap-s, and wrap-t are also initialized from +the material xml. Seperate effects are created for each texture variant of a material. +Model effects are created by walking the OpenSceneGraph scene graph +for a model and replacing nodes (osg::Geode) that have state sets with +node that uses an effect instead. Again, a small effect is created +with parameters extracted from OSG objects; this effect inherits, by +default, from Effects/model-default.eff. A larger set of parameters is +created for model effects than for terrain because there is more +variation possible from the OSG model loaders than from the terrain +system. The parameters created are: + + * material active, ambient, diffuse, specular, emissive, + shininess, color mode + * blend active, source, destination + * shade-model + * cull-face + * rendering-hint + * texture type, image, filter, wrap-s, wrap-t + +Specifying Custom Effects +------------------------- + +You can specify the effects that will be used by FlightGear as the +base effect when it creates terrain and model effects. + +In the terrain materials.xml, an "effect" property specifies the name +of the model to use. + +In model .xml files, A richer syntax is supported. [TO BE DETERMINED] + Material animations will be implemented by creating a new effect that inherits from one in a model, overriding the parameters that will be animated. +Examples +-------- - - - city - - - - - 0.0 0.0 0.0 1.0 - - - .5 .5 .5 1.0 - - - 0.3 0.3 0.3 1.0 - - - 0.0 0.0 0.0 1.0 - - 1.2 - - - city.png - linear-mipmap-linear - - clamp - clamp-to-edge - - - normalized - - - detail.png - linear-mipmap-linear - - clamp - clamp-to-edge - - - normalized - - .05 - 0 0 1 1.5708 - - - - - - - 2.0 - - - - GL_ARB_shader_objects - GL_ARB_shading_language_100 - GL_ARB_vertex_shader - GL_ARB_fragment_shader - - - - - true - - material/ambient - material/diffuse - material/specular - material/shininess - - - 0 - texture[0]/image - texture[0]/filter - texture[0]/wrap-s - texture[0]/wrap-t - - texture[0]/internal-format - - - - 1 - texture[1]/image - texture[1]/filter - texture[1]/wrap-s - texture[1]/wrap-t - - texture[1]/internal-format - - - - bumpHeight - float - bump-height - - - patternRotation - float-vec4 - pattern-rotation - - - baseTexture - sampler-2d - 0 - - - detailTexture - sampler-2d - 1 - - - - - "Shaders/util.vert" - - - "Shaders/foo.vert" - - - "Shaders/foo.frag" - - - - - - - - true - - material/ambient - material/diffuse - material/specular - - - 0 - texture[0]/image - texture[0]/filter - texture[0]/wrap-s - texture[0]/wrap-t - - texture[0]/internal-format - - - - - - +The Effects directory contains the effects definitions; look there for +examples. Effects/crop.eff is a good example of a complex effect. diff --git a/src/Main/main.cxx b/src/Main/main.cxx index 281da283f..dac1bd432 100644 --- a/src/Main/main.cxx +++ b/src/Main/main.cxx @@ -47,6 +47,7 @@ #include #include #include +#include #include #include #include @@ -166,7 +167,7 @@ void fgUpdateTimeDepCalcs() { // normal playback replay_time->setDoubleValue( replay_time->getDoubleValue() + ( delta_time_sec - * fgGetInt("/sim/speed-up") ) ); + * fgGetInt("/sim/speed-up") ) ); } else if ( replay_state->getIntValue() == 2 ) { // paused playback (don't advance replay time) } @@ -343,14 +344,14 @@ static void fgMainLoop( void ) { // probably move eventually /* printf("Before - ground = %.2f runway = %.2f alt = %.2f\n", - scenery.get_cur_elev(), - cur_fdm_state->get_Runway_altitude() * SG_FEET_TO_METER, - cur_fdm_state->get_Altitude() * SG_FEET_TO_METER); */ + scenery.get_cur_elev(), + cur_fdm_state->get_Runway_altitude() * SG_FEET_TO_METER, + cur_fdm_state->get_Altitude() * SG_FEET_TO_METER); */ /* printf("Adjustment - ground = %.2f runway = %.2f alt = %.2f\n", - scenery.get_cur_elev(), - cur_fdm_state->get_Runway_altitude() * SG_FEET_TO_METER, - cur_fdm_state->get_Altitude() * SG_FEET_TO_METER); */ + scenery.get_cur_elev(), + cur_fdm_state->get_Runway_altitude() * SG_FEET_TO_METER, + cur_fdm_state->get_Altitude() * SG_FEET_TO_METER); */ // cout << "Warp = " << globals->get_warp() << endl; @@ -422,7 +423,7 @@ static void fgMainLoop( void ) { general.set_frame_rate( frames ); fgSetInt("/sim/frame-rate", frames); SG_LOG( SG_ALL, SG_DEBUG, - "--> Frame rate is = " << general.get_frame_rate() ); + "--> Frame rate is = " << general.get_frame_rate() ); frames = 0; } last_time = t->get_cur_time(); @@ -451,7 +452,7 @@ static void fgMainLoop( void ) { fgUpdateTimeDepCalcs(); } else { SG_LOG( SG_ALL, SG_DEBUG, - "Elapsed time is zero ... we're zinging" ); + "Elapsed time is zero ... we're zinging" ); } globals->get_subsystem_mgr()->update(delta_time_sec); @@ -514,7 +515,7 @@ static void fgMainLoop( void ) { globals->get_props()->tie("/sim/sound/devices/name", SGRawValueFunctions(0, fgSetNewSoundDevice), false); } - + simgear::AtomicChangeListener::fireChangeListeners(); fgRequestRedraw(); SG_LOG( SG_ALL, SG_DEBUG, "" ); diff --git a/src/Main/renderer.cxx b/src/Main/renderer.cxx index ece25ec32..cfe5f29a3 100644 --- a/src/Main/renderer.cxx +++ b/src/Main/renderer.cxx @@ -47,6 +47,7 @@ #include #include #include +#include #include #include @@ -552,6 +553,10 @@ FGRenderer::init( void ) // as the rest of the scene. This may not be true in practice. mRealRoot->addChild(thesky->getCloudRoot()); mRealRoot->addChild(FGCreateRedoutNode()); + // Attach empty program to the scene root so that shader programs + // don't leak into state sets (effects) that shouldn't have one. + stateSet = mRealRoot->getOrCreateStateSet(); + stateSet->setAttributeAndModes(new osg::Program, osg::StateAttribute::ON); } diff --git a/src/Scenery/scenery.cxx b/src/Scenery/scenery.cxx index 73c53733a..cfa0eb72a 100644 --- a/src/Scenery/scenery.cxx +++ b/src/Scenery/scenery.cxx @@ -33,9 +33,6 @@ #include #include #include -#include -#include -#include #include #include #include @@ -253,47 +250,3 @@ SceneryPager* FGScenery::getPagerSingleton() return pager.get(); } -// Effect initialization stuff - -class PropertyExpression : public SGExpression -{ -public: - PropertyExpression(SGPropertyNode* pnode) : _pnode(pnode) {} - - void eval(bool& value, const expression::Binding*) const - { - value = _pnode->getValue(); - } -protected: - SGPropertyNode_ptr _pnode; -}; - -class EffectPropertyListener : public SGPropertyChangeListener -{ -public: - EffectPropertyListener(Technique* tniq) : _tniq(tniq) {} - - void valueChanged(SGPropertyNode* node) - { - _tniq->refreshValidity(); - } -protected: - osg::ref_ptr _tniq; -}; - -Expression* propertyExpressionParser(const SGPropertyNode* exp, - expression::Parser* parser) -{ - SGPropertyNode_ptr pnode = fgGetNode(exp->getStringValue(), true); - PropertyExpression* pexp = new PropertyExpression(pnode); - TechniquePredParser* predParser - = dynamic_cast(parser); - if (predParser) - pnode->addChangeListener(new EffectPropertyListener(predParser - ->getTechnique())); - return pexp; -} - -expression::ExpParserRegistrar propertyRegistrar("property", - propertyExpressionParser); - diff --git a/src/Time/light.cxx b/src/Time/light.cxx index ba835932f..cb5469a7f 100644 --- a/src/Time/light.cxx +++ b/src/Time/light.cxx @@ -69,6 +69,7 @@ FGLight::FGLight () _scene_ambient(0, 0, 0, 0), _scene_diffuse(0, 0, 0, 0), _scene_specular(0, 0, 0, 0), + _scene_chrome(0, 0, 0, 0), _sky_color(0, 0, 0, 0), _fog_color(0, 0, 0, 0), _cloud_color(0, 0, 0, 0), @@ -151,6 +152,15 @@ void FGLight::bind () { prop->tie("/rendering/dome/fog/red",SGRawValuePointer(&_fog_color[0])); prop->tie("/rendering/dome/fog/green",SGRawValuePointer(&_fog_color[1])); prop->tie("/rendering/dome/fog/blue",SGRawValuePointer(&_fog_color[2])); + // Properties used directly by effects + _chromeProps[0] = prop->getNode("/rendering/scene/chrome-light/red", true); + _chromeProps[1] = prop->getNode("/rendering/scene/chrome-light/green", + true); + _chromeProps[2] = prop->getNode("/rendering/scene/chrome-light/blue", true); + _chromeProps[3] = prop->getNode("/rendering/scene/chrome-light/alpha", + true); + for (int i = 0; i < 4; ++i) + _chromeProps[i]->setValue(0.0); } void FGLight::unbind () { @@ -265,6 +275,14 @@ void FGLight::update_sky_color () { _scene_diffuse[3] = 1.0; gamma_correct_rgb( _scene_diffuse.data() ); + SGVec4f chrome = _scene_ambient * .4f + _scene_diffuse; + chrome[3] = 1.0f; + if (chrome != _scene_chrome) { + _scene_chrome = chrome; + for (int i = 0; i < 4; ++i) + _chromeProps[i]->setValue(static_cast(_scene_chrome[i])); + } + color = thesky->get_sun_color(); _scene_specular[0] = color[0] * specular; _scene_specular[1] = color[1] * specular; diff --git a/src/Time/light.hxx b/src/Time/light.hxx index 6a7500c9a..f3ecb32e1 100644 --- a/src/Time/light.hxx +++ b/src/Time/light.hxx @@ -36,6 +36,7 @@ #include +#include #include #include @@ -85,6 +86,7 @@ private: SGVec4f _scene_ambient; SGVec4f _scene_diffuse; SGVec4f _scene_specular; + SGVec4f _scene_chrome; // clear sky, fog and cloud color SGVec4f _sky_color; @@ -100,6 +102,9 @@ private: void update_sky_color (); void update_adj_fog_color (); + // properties for chrome light; not a tie because I want to fire + // property listeners when the values change. + SGPropertyNode_ptr _chromeProps[4]; public: FGLight (); @@ -117,6 +122,7 @@ public: inline const SGVec4f& scene_ambient () const { return _scene_ambient; } inline const SGVec4f& scene_diffuse () const { return _scene_diffuse; } inline const SGVec4f& scene_specular () const { return _scene_specular; } + inline const SGVec4f& scene_chrome () const { return _scene_chrome; } inline const SGVec4f& sky_color () const { return _sky_color; } inline const SGVec4f& cloud_color () const { return _cloud_color; } diff --git a/src/Traffic/TrafficMgr.cxx b/src/Traffic/TrafficMgr.cxx index 13bf1cc1b..899685e93 100644 --- a/src/Traffic/TrafficMgr.cxx +++ b/src/Traffic/TrafficMgr.cxx @@ -42,6 +42,7 @@ #include #include +#include #include #include @@ -70,6 +71,7 @@ #include "TrafficMgr.hxx" using std::sort; +using std::strcmp; /****************************************************************************** * TrafficManager @@ -376,62 +378,60 @@ void FGTrafficManager::startElement (const char * name, const XMLAttributes &at void FGTrafficManager::endElement (const char * name) { //cout << "End element " << name << endl; - string element(name); - string value = elementValueStack.back(); - elementValueStack.pop_back(); + const string& value = elementValueStack.back(); - if (element == string("model")) + if (!strcmp(name, "model")) mdl = value; - else if (element == string("livery")) + else if (!strcmp(name, "livery")) livery = value; - else if (element == string("home-port")) + else if (!strcmp(name, "home-port")) homePort = value; - else if (element == string("registration")) + else if (!strcmp(name, "registration")) registration = value; - else if (element == string("airline")) + else if (!strcmp(name, "airline")) airline = value; - else if (element == string("actype")) + else if (!strcmp(name, "actype")) acType = value; - else if (element == string("required-aircraft")) + else if (!strcmp(name, "required-aircraft")) requiredAircraft = value; - else if (element == string("flighttype")) + else if (!strcmp(name, "flighttype")) flighttype = value; - else if (element == string("radius")) + else if (!strcmp(name, "radius")) radius = atoi(value.c_str()); - else if (element == string("offset")) + else if (!strcmp(name, "offset")) offset = atoi(value.c_str()); - else if (element == string("performance-class")) + else if (!strcmp(name, "performance-class")) m_class = value; - else if (element == string("heavy")) + else if (!strcmp(name, "heavy")) { if(value == string("true")) heavy = true; else heavy = false; } - else if (element == string("callsign")) + else if (!strcmp(name, "callsign")) callsign = value; - else if (element == string("fltrules")) + else if (!strcmp(name, "fltrules")) fltrules = value; - else if (element == string("port")) + else if (!strcmp(name, "port")) port = value; - else if (element == string("time")) + else if (!strcmp(name, "time")) timeString = value; - else if (element == string("departure")) + else if (!strcmp(name, "departure")) { departurePort = port; departureTime = timeString; } - else if (element == string("cruise-alt")) + else if (!strcmp(name, "cruise-alt")) cruiseAlt = atoi(value.c_str()); - else if (element == string("arrival")) + else if (!strcmp(name, "arrival")) { arrivalPort = port; arrivalTime = timeString; } - else if (element == string("repeat")) + else if (!strcmp(name, "repeat")) repeat = value; - else if (element == string("flight")) + else if (!strcmp(name, "flight")) { // We have loaded and parsed all the information belonging to this flight // so we temporarily store it. @@ -477,7 +477,7 @@ void FGTrafficManager::endElement (const char * name) { requiredAircraft)); requiredAircraft = ""; } - else if (element == string("aircraft")) + else if (!strcmp(name, "aircraft")) { int proportion = (int) (fgGetDouble("/sim/traffic-manager/proportion") * 100); int randval = rand() & 100; @@ -533,6 +533,7 @@ void FGTrafficManager::endElement (const char * name) { << score); score = 0; } + elementValueStack.pop_back(); } void FGTrafficManager::data (const char * s, int len) {