]> git.mxchange.org Git - simgear.git/blob - simgear/scene/model/placementtrans.cxx
Improove bounding volume building in the scenery loading process.
[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   _rotation(1, 0, 0, 0,
68             0, 1, 0, 0,
69             0, 0, 1, 0,
70             0, 0, 0, 1)
71 {
72   setUpdateCallback(new UpdateCallback);
73 }
74
75 SGPlacementTransform::SGPlacementTransform(const SGPlacementTransform& trans,
76                                            const osg::CopyOp& copyop):
77   osg::Transform(trans, copyop),
78   _placement_offset(trans._placement_offset),
79   _rotation(trans._rotation)
80 {
81   
82 }
83
84 SGPlacementTransform::~SGPlacementTransform(void)
85 {
86 }
87
88 bool
89 SGPlacementTransform::computeLocalToWorldMatrix(osg::Matrix& matrix,
90                                                 osg::NodeVisitor*) const
91 {
92   osg::Matrix t;
93   for (int i = 0; i < 3; ++i) {
94     for (int j = 0; j < 3; ++j) {
95       t(j, i) = _rotation(i, j);
96     }
97     t(3, i) = _placement_offset(i);
98   }
99   
100   if (_referenceFrame == RELATIVE_RF)
101     matrix.preMult(t);
102   else
103     matrix = t;
104   return true;
105 }
106
107 bool
108 SGPlacementTransform::computeWorldToLocalMatrix(osg::Matrix& matrix,
109                                                 osg::NodeVisitor*) const
110 {
111   osg::Matrix t;
112   for (int i = 0; i < 3; ++i) {
113     for (int j = 0; j < 3; ++j) {
114       t(j, i) = _rotation(i, j);
115     }
116     t(3, i) = _placement_offset(i);
117   }
118   t = osg::Matrix::inverse(t);
119
120   if (_referenceFrame == RELATIVE_RF)
121     matrix.postMult(t);
122   else
123     matrix = t;
124   return true;
125 }
126
127 // Functions to read / write SGPlacementTrans from / to a .osg file,
128 // mostly for debugging purposes.
129
130 namespace {
131
132 bool PlacementTrans_readLocalData(osg::Object& obj, osgDB::Input& fr)
133 {
134     SGPlacementTransform& trans = static_cast<SGPlacementTransform&>(obj);
135     SGMatrixd rotation(1, 0, 0, 0,
136                        0, 1, 0, 0,
137                        0, 0, 1, 0,
138                        0, 0, 0, 1);
139     SGVec3d placementOffset(0, 0, 0);
140     
141     if (fr[0].matchWord("rotation") && fr[1].isOpenBracket()) {
142         fr += 2;
143         for (int i = 0; i < 3; i++) {
144             SGVec3d scratch;
145             if (!fr.readSequence(scratch.osg()))
146                 return false;
147             fr += 3;
148             for (int j = 0; j < 3; j++)
149                 rotation(j, i) = scratch[j];
150         }
151         if (fr[0].isCloseBracket())
152             ++fr;
153         else
154             return false;
155     }
156     if (fr[0].matchWord("placement")) {
157         ++fr;
158         if (fr.readSequence(placementOffset.osg()))
159             fr += 3;
160         else
161             return false;
162     }
163     trans.setTransform(placementOffset, rotation);
164     return true;
165 }
166
167 bool PlacementTrans_writeLocalData(const osg::Object& obj, osgDB::Output& fw)
168 {
169     const SGPlacementTransform& trans
170         = static_cast<const SGPlacementTransform&>(obj);
171     const SGMatrixd& rotation = trans.getRotation();
172     const SGVec3d& placement = trans.getGlobalPos();
173     
174     fw.indent() << "rotation {" << std::endl;
175     fw.moveIn();
176     for (int i = 0; i < 3; i++) {
177         fw.indent();
178         for (int j = 0; j < 3; j++) {
179             fw << rotation(j, i) << " ";
180         }
181         fw << std::endl;
182     }
183     fw.moveOut();
184     fw.indent() << "}" << std::endl;
185     int prec = fw.precision();
186     fw.precision(15);
187     fw.indent() << "placement ";
188     for (int i = 0; i < 3; i++) {
189         fw << placement(i) << " ";
190     }
191     fw << std::endl;
192     fw.precision(prec);
193     return true;
194 }
195 }
196
197 osgDB::RegisterDotOsgWrapperProxy g_SGPlacementTransProxy
198 (
199     new SGPlacementTransform,
200     "SGPlacementTransform",
201     "Object Node Transform SGPlacementTransform Group",
202     &PlacementTrans_readLocalData,
203     &PlacementTrans_writeLocalData
204 );