// renderingpipeline.cxx -- description of the cameras needed by the Rembrandt renderer // // Written by Curtis Olson, started May 1997. // This file contains parts of main.cxx prior to october 2004 // // Copyright (C) 1997 - 2012 Curtis L. Olson - http://www.flightgear.org/~curt // // 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #ifdef HAVE_CONFIG_H # include #endif #ifdef HAVE_WINDOWS_H # include #endif #include #include #include // For texture formats #include #include #include #include #include #include #include #include #include "renderingpipeline.hxx" #include "CameraGroup.hxx" #include
#include "renderer.hxx" namespace flightgear { FGRenderingPipeline* makeRenderingPipeline(const std::string& name, const simgear::SGReaderWriterOptions* options) { std::string fileName = "Effects/" + name; fileName += ".xml"; std::string absFileName = simgear::SGModelLib::findDataFile(fileName, options); if (absFileName.empty()) { SG_LOG(SG_INPUT, SG_ALERT, "can't find \"" << fileName << "\""); return 0; } SGPropertyNode_ptr effectProps = new SGPropertyNode(); try { readProperties(absFileName, effectProps.ptr(), 0, true); } catch (sg_io_exception& e) { SG_LOG(SG_INPUT, SG_ALERT, "error reading \"" << absFileName << "\": " << e.getFormattedMessage()); return 0; } osg::ref_ptr pipeline = new FGRenderingPipeline; std::vector buffers = effectProps->getChildren("buffer"); for (int i = 0; i < (int)buffers.size(); ++i) { pipeline->buffers.push_back(new FGRenderingPipeline::Buffer(buffers[i])); } std::vector stages = effectProps->getChildren("stage"); for (int i = 0; i < (int)stages.size(); ++i) { pipeline->stages.push_back(new FGRenderingPipeline::Stage(stages[i])); } return pipeline.release(); } } void FGRenderingPipeline::Conditionable::parseCondition(SGPropertyNode* prop) { const SGPropertyNode* predProp = prop->getChild("condition"); if (!predProp) { setAlwaysValid(true); } else { setAlwaysValid(false); try { flightgear::PipelinePredParser parser; SGExpressionb* validExp = dynamic_cast(parser.read(predProp->getChild(0))); if (validExp) setValidExpression(validExp); else throw simgear::expression::ParseError("pipeline condition is not a boolean expression"); } catch (simgear::expression::ParseError& except) { SG_LOG(SG_INPUT, SG_ALERT, "parsing pipeline condition " << except.getMessage()); setAlwaysValid(false); } } } void FGRenderingPipeline::Conditionable::setValidExpression(SGExpressionb* exp) { _validExpression = exp; } bool FGRenderingPipeline::Conditionable::valid() { return _alwaysValid || _validExpression->getValue(); } template void findAttrOrHex(const simgear::effect::EffectPropertyMap& pMap, const SGPropertyNode* prop, T& result) { try { simgear::findAttr(pMap, prop, result); } catch (simgear::effect::BuilderException&) { std::string val = prop->getStringValue(); try { result = boost::lexical_cast(val); } catch (boost::bad_lexical_cast &) { throw simgear::effect::BuilderException(std::string("findAttrOrHex: could not find attribute ") + std::string(val)); } } } const SGPropertyNode* getPropertyNode(const SGPropertyNode* prop) { if (!prop) return 0; if (prop->nChildren() > 0) { const SGPropertyNode* propertyProp = prop->getChild("property"); if (!propertyProp) return prop; return globals->get_props()->getNode(propertyProp->getStringValue()); } return prop; } const SGPropertyNode* getPropertyChild(const SGPropertyNode* prop, const char* name) { const SGPropertyNode* child = prop->getChild(name); if (!child) return 0; else return getPropertyNode(child); } simgear::effect::EffectNameValue internalFormatInit[] = { { "rgb8", GL_RGB8 }, { "rgba8", GL_RGBA8 }, { "rgb16", GL_RGB16 }, { "rgba16", GL_RGBA16 }, { "rg16", 0x822C }, { "depth-component24", GL_DEPTH_COMPONENT24 }, { "depth-component32", GL_DEPTH_COMPONENT32 } }; simgear::effect::EffectPropertyMap internalFormats(internalFormatInit); simgear::effect::EffectNameValue sourceFormatInit[] = { { "rg", 0x8227 }, { "rgb", GL_RGB }, { "rgba", GL_RGBA }, { "depth-component", GL_DEPTH_COMPONENT } }; simgear::effect::EffectPropertyMap sourceFormats(sourceFormatInit); simgear::effect::EffectNameValue sourceTypeInit[] = { { "unsigned-byte", GL_UNSIGNED_BYTE }, { "unsigned-short", GL_UNSIGNED_SHORT }, { "unsigned-int", GL_UNSIGNED_INT }, { "float", GL_FLOAT } }; simgear::effect::EffectPropertyMap sourceTypes(sourceTypeInit); simgear::effect::EffectNameValue wrapModesInit[] = { {"clamp", GL_CLAMP}, {"clamp-to-border", GL_CLAMP_TO_BORDER_ARB}, {"clamp-to-edge", GL_CLAMP_TO_EDGE}, {"mirror", GL_MIRRORED_REPEAT_IBM}, {"repeat", GL_REPEAT} }; simgear::effect::EffectPropertyMap wrapModes(wrapModesInit); FGRenderingPipeline::Buffer::Buffer(SGPropertyNode* prop) { SGPropertyNode_ptr nameProp = prop->getChild("name"); if (!nameProp.valid()) { throw sg_exception("Buffer name is mandatory"); } internalFormat = GL_RGBA8; sourceFormat = GL_RGBA; sourceType = GL_UNSIGNED_BYTE; wrapMode = GL_CLAMP_TO_BORDER_ARB; name = nameProp->getStringValue(); SGPropertyNode* internalFormatProp = prop->getChild("internal-format"); if (internalFormatProp) findAttrOrHex(internalFormats, internalFormatProp, internalFormat); SGPropertyNode* sourceFormatProp = prop->getChild("source-format"); if (sourceFormatProp) findAttrOrHex(sourceFormats, sourceFormatProp, sourceFormat); SGPropertyNode* sourceTypeProp = prop->getChild("source-type"); if (sourceTypeProp) findAttrOrHex(sourceTypes, sourceTypeProp, sourceType); SGPropertyNode* wrapModeProp = prop->getChild("wrap-mode"); if (wrapModeProp) findAttrOrHex(wrapModes, wrapModeProp, wrapMode); SGConstPropertyNode_ptr widthProp = getPropertyChild(prop, "width"); if (!widthProp.valid()) width = -1; else if (widthProp->getStringValue() == std::string("screen")) width = -1; else { width = widthProp->getIntValue(); } SGConstPropertyNode_ptr heightProp = getPropertyChild(prop, "height"); if (!heightProp.valid()) height = -1; else if (heightProp->getStringValue() == std::string("screen")) height = -1; else height = heightProp->getIntValue(); scaleFactor = prop->getFloatValue("scale-factor", 1.f); shadowComparison = prop->getBoolValue("shadow-comparison", false); parseCondition(prop); } simgear::effect::EffectNameValue componentsInit[] = { {"depth", osg::Camera::DEPTH_BUFFER}, {"stencil", osg::Camera::STENCIL_BUFFER}, {"packed-depth-stencil", osg::Camera::PACKED_DEPTH_STENCIL_BUFFER}, {"color0", osg::Camera::COLOR_BUFFER0}, {"color1", osg::Camera::COLOR_BUFFER1}, {"color2", osg::Camera::COLOR_BUFFER2}, {"color3", osg::Camera::COLOR_BUFFER3} }; simgear::effect::EffectPropertyMap components(componentsInit); FGRenderingPipeline::Pass::Pass(SGPropertyNode* prop) { SGPropertyNode_ptr nameProp = prop->getChild("name"); if (!nameProp.valid()) { throw sg_exception("Pass name is mandatory"); } name = nameProp->getStringValue(); SGPropertyNode_ptr typeProp = prop->getChild("type"); if (!typeProp.valid()) { type = nameProp->getStringValue(); } else { type = typeProp->getStringValue(); } orderNum = prop->getIntValue("order-num", -1); effect = prop->getStringValue("effect", ""); debugProperty = prop->getStringValue("debug-property", ""); parseCondition(prop); } FGRenderingPipeline::Stage::Stage(SGPropertyNode* prop) : Pass(prop) { needsDuDv = prop->getBoolValue("needs-du-dv", false); scaleFactor = prop->getFloatValue("scale-factor", 1.f); std::vector attachments = prop->getChildren("attachment"); for (int i = 0; i < (int)attachments.size(); ++i) { this->attachments.push_back(new FGRenderingPipeline::Attachment(attachments[i])); } std::vector passes = prop->getChildren("pass"); for (int i = 0; i < (int)passes.size(); ++i) { this->passes.push_back(new FGRenderingPipeline::Pass(passes[i])); } } FGRenderingPipeline::Attachment::Attachment(SGPropertyNode* prop) { simgear::findAttr(components, prop->getChild("component"), component); SGPropertyNode_ptr bufferProp = prop->getChild("buffer"); if (!bufferProp.valid()) { throw sg_exception("Attachment buffer is mandatory"); } buffer = bufferProp->getStringValue(); parseCondition(prop); } FGRenderingPipeline::FGRenderingPipeline() { } class FGStageCameraCullCallback : public osg::NodeCallback { public: FGStageCameraCullCallback(FGRenderingPipeline::Stage* s, flightgear::CameraInfo* i) : stage(s), info(i) {} virtual void operator()( osg::Node *n, osg::NodeVisitor *nv) { simgear::EffectCullVisitor* cv = dynamic_cast(nv); osg::Camera* camera = static_cast(n); cv->clearBufferList(); for (flightgear::RenderBufferMap::iterator ii = info->buffers.begin(); ii != info->buffers.end(); ++ii) { cv->addBuffer(ii->first, ii->second.texture ); } if ( !info->getRenderStageInfo(stage->name).fullscreen ) info->setMatrices( camera ); cv->traverse( *camera ); } private: osg::ref_ptr stage; flightgear::CameraInfo* info; };