]> git.mxchange.org Git - simgear.git/blob - simgear/scene/model/placementtrans.cxx
Clean up placementtrans a bit.
[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(SGQuatd::unit())
68 {
69   setUpdateCallback(new UpdateCallback);
70 }
71
72 SGPlacementTransform::SGPlacementTransform(const SGPlacementTransform& trans,
73                                            const osg::CopyOp& copyop):
74   osg::Transform(trans, copyop),
75   _placement_offset(trans._placement_offset),
76   _rotation(trans._rotation)
77 {
78   
79 }
80
81 SGPlacementTransform::~SGPlacementTransform(void)
82 {
83 }
84
85 bool
86 SGPlacementTransform::computeLocalToWorldMatrix(osg::Matrix& matrix,
87                                                 osg::NodeVisitor*) const
88 {
89   if (_referenceFrame == RELATIVE_RF) {
90     matrix.preMultTranslate(_placement_offset.osg());
91     matrix.preMultRotate(_rotation.osg());
92   } else {
93     matrix.makeRotate(_rotation.osg());
94     matrix.postMultTranslate(_placement_offset.osg());
95   }
96   return true;
97 }
98
99 bool
100 SGPlacementTransform::computeWorldToLocalMatrix(osg::Matrix& matrix,
101                                                 osg::NodeVisitor*) const
102 {
103   if (_referenceFrame == RELATIVE_RF) {
104     matrix.postMultTranslate(-_placement_offset.osg());
105     matrix.postMultRotate(inverse(_rotation).osg());
106   } else {
107     matrix.makeRotate(inverse(_rotation).osg());
108     matrix.preMultTranslate(-_placement_offset.osg());
109   }
110   return true;
111 }
112
113 // Functions to read / write SGPlacementTrans from / to a .osg file,
114 // mostly for debugging purposes.
115
116 namespace {
117
118 bool PlacementTrans_readLocalData(osg::Object& obj, osgDB::Input& fr)
119 {
120     SGPlacementTransform& trans = static_cast<SGPlacementTransform&>(obj);
121     SGQuatd rotation = SGQuatd::unit();
122     SGVec3d placementOffset(0, 0, 0);
123     
124     if (fr[0].matchWord("rotation")) {
125         ++fr;
126         osg::Vec4d vec4;
127         if (fr.readSequence(vec4)) {
128             rotation = SGQuatd(vec4[0], vec4[1], vec4[2], vec4[3]);
129             fr += 4;
130         } else
131             return false;
132     }
133     if (fr[0].matchWord("placement")) {
134         ++fr;
135         if (fr.readSequence(placementOffset.osg()))
136             fr += 3;
137         else
138             return false;
139     }
140     trans.setTransform(placementOffset, rotation);
141     return true;
142 }
143
144 bool PlacementTrans_writeLocalData(const osg::Object& obj, osgDB::Output& fw)
145 {
146     const SGPlacementTransform& trans
147         = static_cast<const SGPlacementTransform&>(obj);
148     const SGQuatd& rotation = trans.getRotation();
149     const SGVec3d& placement = trans.getGlobalPos();
150     
151     fw.indent() << "rotation ";
152     for (int i = 0; i < 4; i++) {
153         fw << rotation(i) << " ";
154     }
155     fw << std::endl;
156     int prec = fw.precision();
157     fw.precision(15);
158     fw.indent() << "placement ";
159     for (int i = 0; i < 3; i++) {
160         fw << placement(i) << " ";
161     }
162     fw << std::endl;
163     fw.precision(prec);
164     return true;
165 }
166 }
167
168 osgDB::RegisterDotOsgWrapperProxy g_SGPlacementTransProxy
169 (
170     new SGPlacementTransform,
171     "SGPlacementTransform",
172     "Object Node Transform SGPlacementTransform Group",
173     &PlacementTrans_readLocalData,
174     &PlacementTrans_writeLocalData
175 );