1 // renderingpipeline.cxx -- description of the cameras needed by the Rembrandt renderer
3 // Written by Curtis Olson, started May 1997.
4 // This file contains parts of main.cxx prior to october 2004
6 // Copyright (C) 1997 - 2012 Curtis L. Olson - http://www.flightgear.org/~curt
8 // This program is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU General Public License as
10 // published by the Free Software Foundation; either version 2 of the
11 // License, or (at your option) any later version.
13 // This program is distributed in the hope that it will be useful, but
14 // WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 // General Public License for more details.
18 // You should have received a copy of the GNU General Public License
19 // along with this program; if not, write to the Free Software
20 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
30 #include <boost/lexical_cast.hpp>
33 #include <osg/FrameBufferObject> // For texture formats
35 #include <simgear/debug/logstream.hxx>
36 #include <simgear/scene/util/SGReaderWriterOptions.hxx>
37 #include <simgear/scene/model/modellib.hxx>
38 #include <simgear/scene/material/EffectBuilder.hxx>
39 #include <simgear/scene/material/EffectCullVisitor.hxx>
40 #include <simgear/props/props_io.hxx>
41 #include <simgear/structure/exception.hxx>
42 #include <simgear/math/SGMath.hxx>
44 #include "renderingpipeline.hxx"
45 #include "CameraGroup.hxx"
46 #include <Main/globals.hxx>
47 #include "renderer.hxx"
49 namespace flightgear {
51 FGRenderingPipeline* makeRenderingPipeline(const std::string& name,
52 const simgear::SGReaderWriterOptions* options)
54 std::string fileName = "Effects/" + name;
56 std::string absFileName
57 = simgear::SGModelLib::findDataFile(fileName, options);
58 if (absFileName.empty()) {
59 SG_LOG(SG_INPUT, SG_ALERT, "can't find \"" << fileName << "\"");
62 SGPropertyNode_ptr effectProps = new SGPropertyNode();
64 readProperties(absFileName, effectProps.ptr(), 0, true);
66 catch (sg_io_exception& e) {
67 SG_LOG(SG_INPUT, SG_ALERT, "error reading \"" << absFileName << "\": "
68 << e.getFormattedMessage());
72 osg::ref_ptr<FGRenderingPipeline> pipeline = new FGRenderingPipeline;
73 std::vector<SGPropertyNode_ptr> buffers = effectProps->getChildren("buffer");
74 for (int i = 0; i < (int)buffers.size(); ++i) {
75 pipeline->buffers.push_back(new FGRenderingPipeline::Buffer(buffers[i]));
78 std::vector<SGPropertyNode_ptr> stages = effectProps->getChildren("stage");
79 for (int i = 0; i < (int)stages.size(); ++i) {
80 pipeline->stages.push_back(new FGRenderingPipeline::Stage(stages[i]));
83 return pipeline.release();
89 FGRenderingPipeline::Conditionable::parseCondition(SGPropertyNode* prop)
91 const SGPropertyNode* predProp = prop->getChild("condition");
95 setAlwaysValid(false);
97 flightgear::PipelinePredParser parser;
98 SGExpressionb* validExp = dynamic_cast<SGExpressionb*>(parser.read(predProp->getChild(0)));
100 setValidExpression(validExp);
102 throw simgear::expression::ParseError("pipeline condition is not a boolean expression");
104 catch (simgear::expression::ParseError& except)
106 SG_LOG(SG_INPUT, SG_ALERT,
107 "parsing pipeline condition " << except.getMessage());
108 setAlwaysValid(false);
113 void FGRenderingPipeline::Conditionable::setValidExpression(SGExpressionb* exp)
115 _validExpression = exp;
118 bool FGRenderingPipeline::Conditionable::valid()
120 return _alwaysValid || _validExpression->getValue();
124 void findAttrOrHex(const simgear::effect::EffectPropertyMap<T>& pMap,
125 const SGPropertyNode* prop,
129 simgear::findAttr(pMap, prop, result);
130 } catch (simgear::effect::BuilderException&) {
131 std::string val = prop->getStringValue();
133 result = boost::lexical_cast<T>(val);
134 } catch (boost::bad_lexical_cast &) {
135 throw simgear::effect::BuilderException(std::string("findAttrOrHex: could not find attribute ")
141 const SGPropertyNode* getPropertyNode(const SGPropertyNode* prop)
145 if (prop->nChildren() > 0) {
146 const SGPropertyNode* propertyProp = prop->getChild("property");
149 return globals->get_props()->getNode(propertyProp->getStringValue());
154 const SGPropertyNode* getPropertyChild(const SGPropertyNode* prop,
157 const SGPropertyNode* child = prop->getChild(name);
161 return getPropertyNode(child);
164 simgear::effect::EffectNameValue<GLint> internalFormatInit[] =
167 { "rgba8", GL_RGBA8 },
168 { "rgb16", GL_RGB16 },
169 { "rgba16", GL_RGBA16 },
171 { "depth-component24", GL_DEPTH_COMPONENT24 },
172 { "depth-component32", GL_DEPTH_COMPONENT32 }
174 simgear::effect::EffectPropertyMap<GLint> internalFormats(internalFormatInit);
176 simgear::effect::EffectNameValue<GLenum> sourceFormatInit[] =
181 { "depth-component", GL_DEPTH_COMPONENT }
183 simgear::effect::EffectPropertyMap<GLenum> sourceFormats(sourceFormatInit);
185 simgear::effect::EffectNameValue<GLenum> sourceTypeInit[] =
187 { "unsigned-byte", GL_UNSIGNED_BYTE },
188 { "unsigned-short", GL_UNSIGNED_SHORT },
189 { "unsigned-int", GL_UNSIGNED_INT },
190 { "float", GL_FLOAT }
192 simgear::effect::EffectPropertyMap<GLenum> sourceTypes(sourceTypeInit);
194 simgear::effect::EffectNameValue<GLenum> wrapModesInit[] =
197 {"clamp-to-border", GL_CLAMP_TO_BORDER_ARB},
198 {"clamp-to-edge", GL_CLAMP_TO_EDGE},
199 {"mirror", GL_MIRRORED_REPEAT_IBM},
200 {"repeat", GL_REPEAT}
202 simgear::effect::EffectPropertyMap<GLenum> wrapModes(wrapModesInit);
204 FGRenderingPipeline::Buffer::Buffer(SGPropertyNode* prop)
206 SGPropertyNode_ptr nameProp = prop->getChild("name");
207 if (!nameProp.valid()) {
208 throw sg_exception("Buffer name is mandatory");
210 internalFormat = GL_RGBA8;
211 sourceFormat = GL_RGBA;
212 sourceType = GL_UNSIGNED_BYTE;
213 wrapMode = GL_CLAMP_TO_BORDER_ARB;
214 name = nameProp->getStringValue();
215 SGPropertyNode* internalFormatProp = prop->getChild("internal-format");
216 if (internalFormatProp)
217 findAttrOrHex(internalFormats, internalFormatProp, internalFormat);
218 SGPropertyNode* sourceFormatProp = prop->getChild("source-format");
219 if (sourceFormatProp)
220 findAttrOrHex(sourceFormats, sourceFormatProp, sourceFormat);
221 SGPropertyNode* sourceTypeProp = prop->getChild("source-type");
223 findAttrOrHex(sourceTypes, sourceTypeProp, sourceType);
224 SGPropertyNode* wrapModeProp = prop->getChild("wrap-mode");
226 findAttrOrHex(wrapModes, wrapModeProp, wrapMode);
227 SGConstPropertyNode_ptr widthProp = getPropertyChild(prop, "width");
228 if (!widthProp.valid())
230 else if (widthProp->getStringValue() == std::string("screen"))
233 width = widthProp->getIntValue();
235 SGConstPropertyNode_ptr heightProp = getPropertyChild(prop, "height");
236 if (!heightProp.valid())
238 else if (heightProp->getStringValue() == std::string("screen"))
241 height = heightProp->getIntValue();
243 scaleFactor = prop->getFloatValue("scale-factor", 1.f);
244 shadowComparison = prop->getBoolValue("shadow-comparison", false);
246 parseCondition(prop);
249 simgear::effect::EffectNameValue<osg::Camera::BufferComponent> componentsInit[] =
251 {"depth", osg::Camera::DEPTH_BUFFER},
252 {"stencil", osg::Camera::STENCIL_BUFFER},
253 {"packed-depth-stencil", osg::Camera::PACKED_DEPTH_STENCIL_BUFFER},
254 {"color0", osg::Camera::COLOR_BUFFER0},
255 {"color1", osg::Camera::COLOR_BUFFER1},
256 {"color2", osg::Camera::COLOR_BUFFER2},
257 {"color3", osg::Camera::COLOR_BUFFER3}
259 simgear::effect::EffectPropertyMap<osg::Camera::BufferComponent> components(componentsInit);
261 FGRenderingPipeline::Pass::Pass(SGPropertyNode* prop)
263 SGPropertyNode_ptr nameProp = prop->getChild("name");
264 if (!nameProp.valid()) {
265 throw sg_exception("Pass name is mandatory");
267 name = nameProp->getStringValue();
268 SGPropertyNode_ptr typeProp = prop->getChild("type");
269 if (!typeProp.valid()) {
270 type = nameProp->getStringValue();
272 type = typeProp->getStringValue();
275 orderNum = prop->getIntValue("order-num", -1);
276 effect = prop->getStringValue("effect", "");
277 debugProperty = prop->getStringValue("debug-property", "");
279 parseCondition(prop);
282 FGRenderingPipeline::Stage::Stage(SGPropertyNode* prop) : Pass(prop)
284 needsDuDv = prop->getBoolValue("needs-du-dv", false);
285 scaleFactor = prop->getFloatValue("scale-factor", 1.f);
287 std::vector<SGPropertyNode_ptr> attachments = prop->getChildren("attachment");
288 for (int i = 0; i < (int)attachments.size(); ++i) {
289 this->attachments.push_back(new FGRenderingPipeline::Attachment(attachments[i]));
292 std::vector<SGPropertyNode_ptr> passes = prop->getChildren("pass");
293 for (int i = 0; i < (int)passes.size(); ++i) {
294 this->passes.push_back(new FGRenderingPipeline::Pass(passes[i]));
298 FGRenderingPipeline::Attachment::Attachment(SGPropertyNode* prop)
300 simgear::findAttr(components, prop->getChild("component"), component);
301 SGPropertyNode_ptr bufferProp = prop->getChild("buffer");
302 if (!bufferProp.valid()) {
303 throw sg_exception("Attachment buffer is mandatory");
305 buffer = bufferProp->getStringValue();
307 parseCondition(prop);
310 FGRenderingPipeline::FGRenderingPipeline()
314 class FGStageCameraCullCallback : public osg::NodeCallback {
316 FGStageCameraCullCallback(FGRenderingPipeline::Stage* s, flightgear::CameraInfo* i) : stage(s), info(i) {}
317 virtual void operator()( osg::Node *n, osg::NodeVisitor *nv) {
318 simgear::EffectCullVisitor* cv = dynamic_cast<simgear::EffectCullVisitor*>(nv);
319 osg::Camera* camera = static_cast<osg::Camera*>(n);
321 cv->clearBufferList();
322 for (flightgear::RenderBufferMap::iterator ii = info->buffers.begin(); ii != info->buffers.end(); ++ii) {
323 cv->addBuffer(ii->first, ii->second.texture );
326 if ( !info->getRenderStageInfo(stage->name).fullscreen )
327 info->setMatrices( camera );
329 cv->traverse( *camera );
333 osg::ref_ptr<FGRenderingPipeline::Stage> stage;
334 flightgear::CameraInfo* info;