]> git.mxchange.org Git - flightgear.git/blob - src/Main/ViewPartitionNode.cxx
Changed ViewPartition to use two cameras instead of three.
[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(2), 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                                         & ~CullSettings::CULL_MASK);
46     int i = 1;
47     for (CameraList::iterator iter = cameras.begin();
48          iter != cameras.end();
49          ++iter, ++i) {
50         Camera* camera = new Camera;
51         camera->setReferenceFrame(Transform::RELATIVE_RF);
52         camera->setInheritanceMask(inheritanceMask);
53         camera->setComputeNearFarMode(CullSettings::DO_NOT_COMPUTE_NEAR_FAR);
54         camera->setCullingMode(CullSettings::VIEW_FRUSTUM_CULLING);
55         camera->setRenderOrder(Camera::POST_RENDER, i);
56         *iter = camera;
57     }
58
59     cameras[NEAR_CAMERA]->setClearMask(GL_DEPTH_BUFFER_BIT);
60     // Background camera will have cleared the buffers and doesn't
61     // touch the depth buffer
62     cameras[FAR_CAMERA]->setClearMask(GL_DEPTH_BUFFER_BIT);
63     // near camera shouldn't render the background.
64     cameras[NEAR_CAMERA]->setCullMask(cameras[NEAR_CAMERA]->getCullMask()
65                                       & ~simgear::BACKGROUND_BIT);
66 }
67
68 ViewPartitionNode::ViewPartitionNode(const ViewPartitionNode& rhs,
69                                      const CopyOp& copyop):
70 cameras(2), visibility(rhs.visibility)
71 {
72     for (int i = 0; i < 2; i++)
73         cameras[i] = static_cast<Camera*>(copyop(rhs.cameras[i].get()));
74 }
75
76 void ViewPartitionNode::traverse(NodeVisitor& nv)
77 {
78     osgUtil::CullVisitor* cv = dynamic_cast<osgUtil::CullVisitor*>(&nv);
79     if(!cv) { 
80         Group::traverse(nv);
81         return; 
82     }
83     RefMatrix& modelview = *(cv->getModelViewMatrix());
84     RefMatrix& projection = *(cv->getProjectionMatrix());
85     // Get the frustum of the enclosing camera. The ViewPartitionNode
86     // will divide up the frustum between that camera's near and far
87     // planes i.e., parentNear and ParentFar.
88     double left, right, bottom, top, parentNear, parentFar;
89     projection.getFrustum(left, right, bottom, top, parentNear, parentFar);
90     double nearPlanes[2], farPlanes[2];
91     nearPlanes[0] = nearCameraFar;
92     farPlanes[0] = parentFar;
93     nearPlanes[1] = parentNear;
94     farPlanes[1] = nearCameraFar;
95     
96     for (int i = 0; i < 2; ++i) {
97         if (farPlanes[i] >0.0) {
98             ref_ptr<RefMatrix> newProj = new RefMatrix();
99             makeNewProjMat(projection, nearPlanes[i], farPlanes[i],
100                            *newProj.get());
101             cv->pushProjectionMatrix(newProj.get());
102             cameras[i]->accept(nv);
103             cv->popProjectionMatrix();
104         }
105     }
106 }
107
108 bool ViewPartitionNode::addChild(osg::Node *child)
109 {
110     return insertChild(_children.size(), child);
111 }
112
113 bool ViewPartitionNode::insertChild(unsigned int index, osg::Node *child)
114 {
115     if(!Group::insertChild(index, child))
116         return false;
117     // Insert child into each Camera
118
119     for (CameraList::iterator iter = cameras.begin();
120          iter != cameras.end();
121          ++iter) {
122         (*iter)->insertChild(index, child);
123     }
124     return true;
125 }
126
127 bool ViewPartitionNode::removeChildren(unsigned int pos, unsigned int numRemove)
128 {
129     if (!Group::removeChildren(pos, numRemove))
130         return false;
131
132     // Remove child from each Camera
133
134     for (CameraList::iterator iter = cameras.begin();
135          iter != cameras.end();
136          ++iter) {
137         (*iter)->removeChildren(pos, numRemove);
138     }
139     return true;
140 }
141
142 bool ViewPartitionNode::setChild(unsigned int i, osg::Node *node)
143 {
144     if(!Group::setChild(i, node)) return false; // Set child
145
146     // Set child for each Camera
147     for (CameraList::iterator iter = cameras.begin();
148          iter != cameras.end();
149          ++iter) {
150         (*iter)->setChild(i, node);
151     }
152     return true;
153 }
154
155 // Given a projection matrix, return a new one with the same frustum
156 // sides and new near / far values.
157
158 void ViewPartitionNode::makeNewProjMat(Matrixd& oldProj, double znear,
159                                        double zfar, Matrixd& projection)
160 {
161     projection = oldProj;
162     // Slightly inflate the near & far planes to avoid objects at the
163     // extremes being clipped out.
164     znear *= 0.999;
165     zfar *= 1.001;
166
167     // Clamp the projection matrix z values to the range (near, far)
168     double epsilon = 1.0e-6;
169     if (fabs(projection(0,3)) < epsilon &&
170         fabs(projection(1,3)) < epsilon &&
171         fabs(projection(2,3)) < epsilon) {
172         // Projection is Orthographic
173         epsilon = -1.0/(zfar - znear); // Used as a temp variable
174         projection(2,2) = 2.0*epsilon;
175         projection(3,2) = (zfar + znear)*epsilon;
176     } else {
177         // Projection is Perspective
178         double trans_near = (-znear*projection(2,2) + projection(3,2)) /
179             (-znear*projection(2,3) + projection(3,3));
180         double trans_far = (-zfar*projection(2,2) + projection(3,2)) /
181             (-zfar*projection(2,3) + projection(3,3));
182         double ratio = fabs(2.0/(trans_near - trans_far));
183         double center = -0.5*(trans_near + trans_far);
184
185         projection.postMult(osg::Matrixd(1.0, 0.0, 0.0, 0.0,
186                                          0.0, 1.0, 0.0, 0.0,
187                                          0.0, 0.0, ratio, 0.0,
188                                          0.0, 0.0, center*ratio, 1.0));
189     }
190
191 }
192
193 namespace
194 {
195 bool ViewPartitionNode_readLocalData(osg::Object& obj, osgDB::Input& fr)
196 {
197     ViewPartitionNode& node = static_cast<ViewPartitionNode&>(obj);
198     if (fr[0].matchWord("visibility")) {
199         ++fr;
200         double visibility;
201         if (fr[0].getFloat(visibility))
202             ++fr;
203         else
204             return false;
205         node.setVisibility(visibility);
206     }
207     return true;
208 }
209
210 bool ViewPartitionNode_writeLocalData(const Object& obj, osgDB::Output& fw)
211 {
212     const ViewPartitionNode& node = static_cast<const ViewPartitionNode&>(obj);
213     fw.indent() << "visibility " << node.getVisibility() << std::endl;
214     return true;
215 }
216
217 osgDB::RegisterDotOsgWrapperProxy viewPartitionNodeProxy
218 (
219     new ViewPartitionNode,
220     "ViewPartitionNode",
221     "Object Node ViewPartitionNode Group",
222     &ViewPartitionNode_readLocalData,
223     &ViewPartitionNode_writeLocalData
224     );
225 }