]> git.mxchange.org Git - flightgear.git/blob - src/Viewer/renderingpipeline.cxx
Begin to implement configurable rendering pipeline
[flightgear.git] / src / Viewer / renderingpipeline.cxx
1 // renderingpipeline.cxx -- description of the cameras needed by the Rembrandt renderer
2 //
3 // Written by Curtis Olson, started May 1997.
4 // This file contains parts of main.cxx prior to october 2004
5 //
6 // Copyright (C) 1997 - 2012  Curtis L. Olson  - http://www.flightgear.org/~curt
7 //
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.
12 //
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.
17 //
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.
21
22 #ifdef HAVE_CONFIG_H
23 #  include <config.h>
24 #endif
25
26 #ifdef HAVE_WINDOWS_H
27 #  include <windows.h>
28 #endif
29
30 #include <boost/lexical_cast.hpp>
31
32 #include <osg/GL>
33 #include <osg/FrameBufferObject> // For texture formats
34
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>
43
44 #include "renderingpipeline.hxx"
45 #include "CameraGroup.hxx"
46 #include <Main/globals.hxx>
47 #include "renderer.hxx"
48
49 namespace flightgear {
50
51 FGRenderingPipeline* makeRenderingPipeline(const std::string& name,
52                    const simgear::SGReaderWriterOptions* options)
53 {
54     std::string fileName(name);
55     fileName += ".xml";
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 << "\"");
60         return 0;
61     }
62     SGPropertyNode_ptr effectProps = new SGPropertyNode();
63     try {
64         readProperties(absFileName, effectProps.ptr(), 0, true);
65     }
66     catch (sg_io_exception& e) {
67         SG_LOG(SG_INPUT, SG_ALERT, "error reading \"" << absFileName << "\": "
68                << e.getFormattedMessage());
69         return 0;
70     }
71
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]));
76     }
77
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]));
81     }
82
83     return pipeline.release();
84 }
85
86 }
87
88 template<typename T>
89 void findAttrOrHex(const simgear::effect::EffectPropertyMap<T>& pMap,
90               const SGPropertyNode* prop,
91               T& result)
92 {
93     try {
94         simgear::findAttr(pMap, prop, result);
95     } catch (simgear::effect::BuilderException&) {
96         std::string val = prop->getStringValue();
97         try {
98             result = boost::lexical_cast<T>(val);
99         } catch (boost::bad_lexical_cast &) {
100             throw simgear::effect::BuilderException(string("findAttrOrHex: could not find attribute ")
101                                    + string(val));
102         }
103     }
104 }
105
106 simgear::effect::EffectNameValue<GLint> internalFormatInit[] =
107 {
108     { "rgb8", GL_RGB8 },
109     { "rgba8", GL_RGBA8 },
110     { "rgb16", GL_RGB16 },
111     { "rgba16", GL_RGBA16 },
112     { "rg16", 0x822C },
113     { "depth-component24", GL_DEPTH_COMPONENT24 },
114     { "depth-component32", GL_DEPTH_COMPONENT32 }
115 };
116 simgear::effect::EffectPropertyMap<GLint> internalFormats(internalFormatInit);
117
118 simgear::effect::EffectNameValue<GLenum> sourceFormatInit[] =
119 {
120     { "rg", 0x8227 },
121     { "rgb", GL_RGB },
122     { "rgba", GL_RGBA },
123     { "depth-component", GL_DEPTH_COMPONENT }
124 };
125 simgear::effect::EffectPropertyMap<GLenum> sourceFormats(sourceFormatInit);
126
127 simgear::effect::EffectNameValue<GLenum> sourceTypeInit[] =
128 {
129     { "unsigned-byte", GL_UNSIGNED_BYTE },
130     { "unsigned-short", GL_UNSIGNED_SHORT },
131     { "unsigned-int", GL_UNSIGNED_INT },
132     { "float", GL_FLOAT }
133 };
134 simgear::effect::EffectPropertyMap<GLenum> sourceTypes(sourceTypeInit);
135
136 simgear::effect::EffectNameValue<GLenum> wrapModesInit[] =
137 {
138     {"clamp", GL_CLAMP},
139     {"clamp-to-border", GL_CLAMP_TO_BORDER_ARB},
140     {"clamp-to-edge", GL_CLAMP_TO_EDGE},
141     {"mirror", GL_MIRRORED_REPEAT_IBM},
142     {"repeat", GL_REPEAT}
143 };
144 simgear::effect::EffectPropertyMap<GLenum> wrapModes(wrapModesInit);
145
146 FGRenderingPipeline::Buffer::Buffer(SGPropertyNode* prop)
147 {
148     SGPropertyNode_ptr nameProp = prop->getChild("name");
149     if (!nameProp.valid()) {
150         throw sg_exception("Buffer name is mandatory");
151     }
152     name = nameProp->getStringValue();
153     findAttrOrHex(internalFormats, prop->getChild("internal-format"), internalFormat);
154     findAttrOrHex(sourceFormats, prop->getChild("source-format"), sourceFormat);
155     findAttrOrHex(sourceTypes, prop->getChild("source-type"), sourceType);
156     findAttrOrHex(sourceTypes, prop->getChild("wrap-mode"), wrapMode);
157     SGPropertyNode_ptr widthProp = prop->getChild("width");
158     if (!widthProp.valid())
159         width = -1;
160     else if (widthProp->getStringValue() == std::string("screen"))
161         width = -1;
162     else
163         width = widthProp->getIntValue();
164     SGPropertyNode_ptr heightProp = prop->getChild("height");
165     if (!heightProp.valid())
166         height = -1;
167     else if (heightProp->getStringValue() == std::string("screen"))
168         height = -1;
169     else
170         height = heightProp->getIntValue();
171
172     scaleFactor = prop->getFloatValue("scale-factor", 1.f);
173     shadowComparison = prop->getBoolValue("shadow-comparison", false);
174 }
175
176 FGRenderingPipeline::Stage::Stage(SGPropertyNode* prop)
177 {
178     SGPropertyNode_ptr nameProp = prop->getChild("name");
179     if (!nameProp.valid()) {
180         throw sg_exception("Stage name is mandatory");
181     }
182     name = nameProp->getStringValue();
183     SGPropertyNode_ptr typeProp = prop->getChild("type");
184     if (!typeProp.valid()) {
185         throw sg_exception("Stage type is mandatory");
186     }
187     type = typeProp->getStringValue();
188 }
189
190 FGRenderingPipeline::FGRenderingPipeline()
191 {
192 }
193
194 flightgear::CameraInfo* FGRenderingPipeline::buildCamera(flightgear::CameraGroup* cgroup, unsigned flags, osg::Camera* camera,
195                                     const osg::Matrix& view, const osg::Matrix& projection, osg::GraphicsContext* gc)
196 {
197     flightgear::CameraInfo* info = new flightgear::CameraInfo(flags);
198     buildBuffers( info );
199     
200     for (size_t i = 0; i < stages.size(); ++i) {
201         osg::ref_ptr<Stage> stage = stages[i];
202         buildStage(info, stage, cgroup, camera, view, projection, gc);
203     }
204
205     return 0;
206 }
207
208 osg::Texture2D* buildDeferredBuffer(GLint internalFormat, GLenum sourceFormat, GLenum sourceType, GLenum wrapMode, bool shadowComparison)
209 {
210     osg::Texture2D* tex = new osg::Texture2D;
211     tex->setResizeNonPowerOfTwoHint( false );
212     tex->setInternalFormat( internalFormat );
213     tex->setShadowComparison(shadowComparison);
214     if (shadowComparison) {
215         tex->setShadowTextureMode(osg::Texture2D::LUMINANCE);
216         tex->setBorderColor(osg::Vec4(1.0f,1.0f,1.0f,1.0f));
217     }
218     tex->setSourceFormat(sourceFormat);
219     tex->setSourceType(sourceType);
220     tex->setFilter( osg::Texture2D::MIN_FILTER, osg::Texture2D::LINEAR );
221     tex->setFilter( osg::Texture2D::MAG_FILTER, osg::Texture2D::LINEAR );
222     tex->setWrap( osg::Texture::WRAP_S, (osg::Texture::WrapMode)wrapMode );
223     tex->setWrap( osg::Texture::WRAP_T, (osg::Texture::WrapMode)wrapMode );
224         return tex;
225 }
226
227 void FGRenderingPipeline::buildBuffers( flightgear::CameraInfo* info )
228 {
229     for (size_t i = 0; i < buffers.size(); ++i) {
230         osg::ref_ptr<Buffer> buffer = buffers[i];
231         info->addBuffer(buffer->name, buildDeferredBuffer( buffer->internalFormat,
232                                                             buffer->sourceFormat,
233                                                             buffer->sourceType,
234                                                             buffer->wrapMode,
235                                                             buffer->shadowComparison) );
236     }
237 }
238
239 class FGStageCameraCullCallback : public osg::NodeCallback {
240 public:
241     FGStageCameraCullCallback(FGRenderingPipeline::Stage* s, flightgear::CameraInfo* i) : stage(s), info(i) {}
242     virtual void operator()( osg::Node *n, osg::NodeVisitor *nv) {
243         simgear::EffectCullVisitor* cv = dynamic_cast<simgear::EffectCullVisitor*>(nv);
244         osg::Camera* camera = static_cast<osg::Camera*>(n);
245
246         cv->clearBufferList();
247         for (flightgear::RenderBufferMap::iterator ii = info->buffers.begin(); ii != info->buffers.end(); ++ii) {
248             cv->addBuffer(ii->first, ii->second.texture );
249         }
250
251                 if ( !info->getRenderStageInfo(stage->name).fullscreen )
252                         info->setMatrices( camera );
253
254         cv->traverse( *camera );
255     }
256
257 private:
258     osg::ref_ptr<FGRenderingPipeline::Stage> stage;
259     flightgear::CameraInfo* info;
260 };
261
262 void FGRenderingPipeline::buildStage(flightgear::CameraInfo* info,
263                                         Stage* stage,
264                                         flightgear::CameraGroup* cgroup,
265                                         osg::Camera* camera,
266                                         const osg::Matrix& view,
267                                         const osg::Matrix& projection,
268                                         osg::GraphicsContext* gc)
269 {
270     osg::ref_ptr<osg::Camera> stageCamera;
271     if (stage->type == "main-camera")
272         stageCamera = camera;
273     else
274         stageCamera = new osg::Camera;
275
276     stageCamera->setName(stage->name);
277     stageCamera->setGraphicsContext(gc);
278     stageCamera->setCullCallback(new FGStageCameraCullCallback(stage, info));
279     if (stage->type != "main-camera")
280         stageCamera->setRenderTargetImplementation( osg::Camera::FRAME_BUFFER_OBJECT );
281 }
282
283 void FGRenderingPipeline::buildMainCamera(flightgear::CameraInfo* info,
284                                         Stage* stage,
285                                         flightgear::CameraGroup* cgroup,
286                                         osg::Camera* camera,
287                                         const osg::Matrix& view,
288                                         const osg::Matrix& projection,
289                                         osg::GraphicsContext* gc)
290 {
291 }