]> git.mxchange.org Git - simgear.git/blob - simgear/scene/model/placementtrans.cxx
Merge branch 'topic/cloudz' into next
[simgear.git] / simgear / scene / model / placementtrans.cxx
1 // placementtrans.hxx -- class for carrying transforms for placing models in the world
2 //
3 // Written by Mathias Froehlich, started April 2005.
4 //
5 // Copyright (C) 2005 Mathias Froehlich
6 //
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License as
9 // published by the Free Software Foundation; either version 2 of the
10 // License, or (at your option) any later version.
11 //
12 // This program is distributed in the hope that it will be useful, but
13 // WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 // General Public License for more details.
16 //
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software
19 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
20 //
21
22 #ifdef HAVE_CONFIG_H
23 #  include <simgear_config.h>
24 #endif
25
26 #ifndef __cplusplus
27 # error This library requires C++
28 #endif
29
30 #include <osgDB/Registry>
31 #include <osgDB/Input>
32 #include <osgDB/Output>
33
34 #include <simgear/compiler.h>
35 #include <simgear/constants.h>
36
37 #include "placementtrans.hxx"
38
39 #include <simgear/scene/util/SGUpdateVisitor.hxx>
40
41 class SGPlacementTransform::UpdateCallback : public osg::NodeCallback {
42 public:
43   virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
44   {
45     // short circuit updates if the model we place with that branch
46     // out of sight.
47     // Note that the transform is still correct.
48     SGUpdateVisitor* updateVisitor = dynamic_cast<SGUpdateVisitor*>(nv);
49     if (updateVisitor) {
50       SGPlacementTransform* placementTransform;
51       placementTransform = static_cast<SGPlacementTransform*>(node);
52       double dist2 = distSqr(updateVisitor->getGlobalEyePos(),
53                              placementTransform->getGlobalPos());
54       if (updateVisitor->getSqrVisibility() < dist2)
55         return;
56     }
57     // note, callback is responsible for scenegraph traversal so
58     // should always include call traverse(node,nv) to ensure 
59     // that the rest of cullbacks and the scene graph are traversed.
60     traverse(node, nv);
61   }
62 };
63
64
65 SGPlacementTransform::SGPlacementTransform(void) :
66   _placement_offset(0, 0, 0),
67   _scenery_center(0, 0, 0),
68   _rotation(1, 0, 0, 0,
69             0, 1, 0, 0,
70             0, 0, 1, 0,
71             0, 0, 0, 1)
72 {
73   setUpdateCallback(new UpdateCallback);
74 }
75
76 SGPlacementTransform::SGPlacementTransform(const SGPlacementTransform& trans,
77                                            const osg::CopyOp& copyop):
78   osg::Transform(trans, copyop),
79   _placement_offset(trans._placement_offset),
80   _scenery_center(trans._scenery_center),
81   _rotation(trans._rotation)
82 {
83   
84 }
85
86 SGPlacementTransform::~SGPlacementTransform(void)
87 {
88 }
89
90 bool
91 SGPlacementTransform::computeLocalToWorldMatrix(osg::Matrix& matrix,
92                                                 osg::NodeVisitor*) const
93 {
94   osg::Matrix t;
95   for (int i = 0; i < 3; ++i) {
96     for (int j = 0; j < 3; ++j) {
97       t(j, i) = _rotation(i, j);
98     }
99     t(3, i) = _placement_offset(i) - _scenery_center(i);
100   }
101   
102   if (_referenceFrame == RELATIVE_RF)
103     matrix.preMult(t);
104   else
105     matrix = t;
106   return true;
107 }
108
109 bool
110 SGPlacementTransform::computeWorldToLocalMatrix(osg::Matrix& matrix,
111                                                 osg::NodeVisitor*) const
112 {
113   osg::Matrix t;
114   for (int i = 0; i < 3; ++i) {
115     for (int j = 0; j < 3; ++j) {
116       t(j, i) = _rotation(i, j);
117     }
118     t(3, i) = _placement_offset(i) - _scenery_center(i);
119   }
120   t = osg::Matrix::inverse(t);
121
122   if (_referenceFrame == RELATIVE_RF)
123     matrix.postMult(t);
124   else
125     matrix = t;
126   return true;
127 }
128
129 // Functions to read / write SGPlacementTrans from / to a .osg file,
130 // mostly for debugging purposes.
131
132 namespace {
133
134 bool PlacementTrans_readLocalData(osg::Object& obj, osgDB::Input& fr)
135 {
136     SGPlacementTransform& trans = static_cast<SGPlacementTransform&>(obj);
137     SGMatrixd rotation(1, 0, 0, 0,
138                        0, 1, 0, 0,
139                        0, 0, 1, 0,
140                        0, 0, 0, 1);
141     SGVec3d placementOffset(0, 0, 0);
142     SGVec3d sceneryCenter(0, 0, 0);
143     
144     if (fr[0].matchWord("rotation") && fr[1].isOpenBracket()) {
145         fr += 2;
146         for (int i = 0; i < 3; i++) {
147             SGVec3d scratch;
148             if (!fr.readSequence(scratch.osg()))
149                 return false;
150             fr += 3;
151             for (int j = 0; j < 3; j++)
152                 rotation(j, i) = scratch[j];
153         }
154         if (fr[0].isCloseBracket())
155             ++fr;
156         else
157             return false;
158     }
159     if (fr[0].matchWord("placement")) {
160         ++fr;
161         if (fr.readSequence(placementOffset.osg()))
162             fr += 3;
163         else
164             return false;
165     }
166     if (fr[0].matchWord("sceneryCenter")) {
167         ++fr;
168         if (fr.readSequence(sceneryCenter.osg()))
169             fr += 3;
170         else
171             return false;
172     }
173     trans.setTransform(placementOffset, rotation);
174     trans.setSceneryCenter(sceneryCenter);
175     return true;
176 }
177
178 bool PlacementTrans_writeLocalData(const osg::Object& obj, osgDB::Output& fw)
179 {
180     const SGPlacementTransform& trans
181         = static_cast<const SGPlacementTransform&>(obj);
182     const SGMatrixd& rotation = trans.getRotation();
183     const SGVec3d& placement = trans.getGlobalPos();
184     const SGVec3d& sceneryCenter = trans.getSceneryCenter();
185     
186     fw.indent() << "rotation {" << std::endl;
187     fw.moveIn();
188     for (int i = 0; i < 3; i++) {
189         fw.indent();
190         for (int j = 0; j < 3; j++) {
191             fw << rotation(j, i) << " ";
192         }
193         fw << std::endl;
194     }
195     fw.moveOut();
196     fw.indent() << "}" << std::endl;
197     int prec = fw.precision();
198     fw.precision(15);
199     fw.indent() << "placement ";
200     for (int i = 0; i < 3; i++) {
201         fw << placement(i) << " ";
202     }
203     fw << std::endl;
204     fw.indent() << "sceneryCenter ";
205     for (int i = 0; i < 3; i++) {
206         fw << sceneryCenter(i) << " ";
207     }
208     fw << std::endl;
209     fw.precision(prec);
210     return true;
211 }
212 }
213
214 osgDB::RegisterDotOsgWrapperProxy g_SGPlacementTransProxy
215 (
216     new SGPlacementTransform,
217     "SGPlacementTransform",
218     "Object Node Transform SGPlacementTransform Group",
219     &PlacementTrans_readLocalData,
220     &PlacementTrans_writeLocalData
221 );