]> git.mxchange.org Git - flightgear.git/blob - src/Main/ViewPartitionNode.cxx
remove redundant --airport-id option (OK'ed by Curt, no longer used by fgrun)
[flightgear.git] / src / Main / ViewPartitionNode.cxx
1 // Copyright (C) 2008 Tim Moore
2 //
3 // Much of this file was copied directly from the osgdepthpartition
4 // example in the OpenSceneGraph distribution, so I feel it is right
5 // to preserve the license in that code:
6 /*
7 *  Permission is hereby granted, free of charge, to any person obtaining a copy
8 *  of this software and associated documentation files (the "Software"), to deal
9 *  in the Software without restriction, including without limitation the rights
10 *  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 *  copies of the Software, and to permit persons to whom the Software is
12 *  furnished to do so, subject to the following conditions:
13 *
14 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 *  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 *  THE SOFTWARE.
21 */
22
23 #include <osg/CullSettings>
24 #include <osg/Depth>
25 #include <osg/StateSet>
26 #include <osgUtil/CullVisitor>
27 // For DotOsgWrapperProxy
28 #include <osgDB/Registry>
29 #include <osgDB/Input>
30 #include <osgDB/Output>
31
32 #include <simgear/scene/util/RenderConstants.hxx>
33 #include "ViewPartitionNode.hxx"
34
35 using namespace osg;
36
37 const double ViewPartitionNode::nearCameraFar = 100.0;
38 ViewPartitionNode::ViewPartitionNode():
39     cameras(3), visibility(40000.0)
40 {
41     const GLbitfield inheritanceMask = (CullSettings::ALL_VARIABLES
42                                         & ~CullSettings::COMPUTE_NEAR_FAR_MODE
43                                         & ~CullSettings::NEAR_FAR_RATIO
44                                         & ~CullSettings::CULLING_MODE);
45     int i = 1;
46     for (CameraList::iterator iter = cameras.begin();
47          iter != cameras.end();
48          ++iter, ++i) {
49         Camera* camera = new Camera;
50         camera->setReferenceFrame(Transform::RELATIVE_RF);
51         camera->setInheritanceMask(inheritanceMask);
52         camera->setComputeNearFarMode(CullSettings::DO_NOT_COMPUTE_NEAR_FAR);
53         camera->setCullingMode(CullSettings::VIEW_FRUSTUM_CULLING);
54         camera->setRenderOrder(Camera::POST_RENDER, i);
55         *iter = camera;
56     }
57     Camera* backgroundCamera = cameras[BACKGROUND_CAMERA].get();
58     backgroundCamera->setClearMask(GL_DEPTH_BUFFER_BIT);
59     // Turn off depth test for the background
60     Depth* depth = new Depth(Depth::LESS, 0.0, 1.0, false);
61     StateSet* backgroundSS = new StateSet;
62     backgroundSS->setAttribute(depth);
63     backgroundSS->setMode(GL_DEPTH_TEST, StateAttribute::OFF);
64     backgroundCamera->setStateSet(backgroundSS);
65     backgroundCamera->setInheritanceMask(backgroundCamera->getInheritanceMask()
66                                          & ~CullSettings::CULL_MASK);
67     backgroundCamera->setCullMask(simgear::BACKGROUND_BIT);
68     cameras[NEAR_CAMERA]->setClearMask(GL_DEPTH_BUFFER_BIT);
69     // Background camera will have cleared the buffers and doesn't
70     // touch the depth buffer
71     cameras[FAR_CAMERA]->setClearMask(0);
72 }
73
74 ViewPartitionNode::ViewPartitionNode(const ViewPartitionNode& rhs,
75                                      const CopyOp& copyop):
76 cameras(3), visibility(rhs.visibility)
77 {
78     for (int i = 0; i < 3; i++)
79         cameras[i] = static_cast<Camera*>(copyop(rhs.cameras[i].get()));
80 }
81
82 void ViewPartitionNode::traverse(NodeVisitor& nv)
83 {
84     osgUtil::CullVisitor* cv = dynamic_cast<osgUtil::CullVisitor*>(&nv);
85     if(!cv) { 
86         Group::traverse(nv);
87         return; 
88     }
89     RefMatrix& modelview = *(cv->getModelViewMatrix());
90     RefMatrix& projection = *(cv->getProjectionMatrix());
91     double left, right, bottom, top, parentNear, parentFar;
92     projection.getFrustum(left, right, bottom, top, parentNear, parentFar);
93     double farCameraFar = visibility + 1000.0;
94     double nearPlanes[3], farPlanes[3];
95     nearPlanes[0] = farCameraFar;  farPlanes[0] = parentFar;
96     nearPlanes[2] = parentNear;
97     // If visibility is low, only use two cameras
98     if (farCameraFar < nearCameraFar) {
99         nearPlanes[1] = farPlanes[1] = 0.0;
100         farPlanes[2] = farCameraFar;
101     } else {
102         nearPlanes[1] = farPlanes[2] = nearCameraFar;
103         farPlanes[1] = farCameraFar;
104         farPlanes[2] = nearCameraFar;
105         
106     }
107     for (int i = 0; i < 3; ++i) {
108         if (farPlanes[i] >0.0) {
109             ref_ptr<RefMatrix> newProj = new RefMatrix();
110             makeNewProjMat(projection, nearPlanes[i], farPlanes[i],
111                            *newProj.get());
112             cv->pushProjectionMatrix(newProj.get());
113             cameras[i]->accept(nv);
114             cv->popProjectionMatrix();
115         }
116     }
117 }
118
119 bool ViewPartitionNode::addChild(osg::Node *child)
120 {
121     return insertChild(_children.size(), child);
122 }
123
124 bool ViewPartitionNode::insertChild(unsigned int index, osg::Node *child)
125 {
126     if(!Group::insertChild(index, child))
127         return false;
128     // Insert child into each Camera
129
130     for (CameraList::iterator iter = cameras.begin();
131          iter != cameras.end();
132          ++iter) {
133         (*iter)->insertChild(index, child);
134     }
135     return true;
136 }
137
138 bool ViewPartitionNode::removeChildren(unsigned int pos, unsigned int numRemove)
139 {
140     if (!Group::removeChildren(pos, numRemove))
141         return false;
142
143     // Remove child from each Camera
144
145     for (CameraList::iterator iter = cameras.begin();
146          iter != cameras.end();
147          ++iter) {
148         (*iter)->removeChildren(pos, numRemove);
149     }
150     return true;
151 }
152
153 bool ViewPartitionNode::setChild(unsigned int i, osg::Node *node)
154 {
155     if(!Group::setChild(i, node)) return false; // Set child
156
157     // Set child for each Camera
158     for (CameraList::iterator iter = cameras.begin();
159          iter != cameras.end();
160          ++iter) {
161         (*iter)->setChild(i, node);
162     }
163     return true;
164 }
165
166 // Given a projection matrix, return a new one with the same frustum
167 // sides and new near / far values.
168
169 void ViewPartitionNode::makeNewProjMat(Matrixd& oldProj, double znear,
170                                        double zfar, Matrixd& projection)
171 {
172     projection = oldProj;
173     // Slightly inflate the near & far planes to avoid objects at the
174     // extremes being clipped out.
175     znear *= 0.999;
176     zfar *= 1.001;
177
178     // Clamp the projection matrix z values to the range (near, far)
179     double epsilon = 1.0e-6;
180     if (fabs(projection(0,3)) < epsilon &&
181         fabs(projection(1,3)) < epsilon &&
182         fabs(projection(2,3)) < epsilon) {
183         // Projection is Orthographic
184         epsilon = -1.0/(zfar - znear); // Used as a temp variable
185         projection(2,2) = 2.0*epsilon;
186         projection(3,2) = (zfar + znear)*epsilon;
187     } else {
188         // Projection is Perspective
189         double trans_near = (-znear*projection(2,2) + projection(3,2)) /
190             (-znear*projection(2,3) + projection(3,3));
191         double trans_far = (-zfar*projection(2,2) + projection(3,2)) /
192             (-zfar*projection(2,3) + projection(3,3));
193         double ratio = fabs(2.0/(trans_near - trans_far));
194         double center = -0.5*(trans_near + trans_far);
195
196         projection.postMult(osg::Matrixd(1.0, 0.0, 0.0, 0.0,
197                                          0.0, 1.0, 0.0, 0.0,
198                                          0.0, 0.0, ratio, 0.0,
199                                          0.0, 0.0, center*ratio, 1.0));
200     }
201
202 }
203
204 namespace
205 {
206 bool ViewPartitionNode_readLocalData(osg::Object& obj, osgDB::Input& fr)
207 {
208     ViewPartitionNode& node = static_cast<ViewPartitionNode&>(obj);
209     if (fr[0].matchWord("visibility")) {
210         ++fr;
211         double visibility;
212         if (fr[0].getFloat(visibility))
213             ++fr;
214         else
215             return false;
216         node.setVisibility(visibility);
217     }
218     return true;
219 }
220
221 bool ViewPartitionNode_writeLocalData(const Object& obj, osgDB::Output& fw)
222 {
223     const ViewPartitionNode& node = static_cast<const ViewPartitionNode&>(obj);
224     fw.indent() << "visibility " << node.getVisibility() << std::endl;
225     return true;
226 }
227
228 osgDB::RegisterDotOsgWrapperProxy viewPartitionNodeProxy
229 (
230     new ViewPartitionNode,
231     "ViewPartitionNode",
232     "Object Node ViewPartitionNode Group",
233     &ViewPartitionNode_readLocalData,
234     &ViewPartitionNode_writeLocalData
235     );
236 }