]> git.mxchange.org Git - simgear.git/blob - simgear/scene/tgdb/SGVasiDrawable.cxx
Merge branch 'maint' into next
[simgear.git] / simgear / scene / tgdb / SGVasiDrawable.cxx
1 /* -*-c++-*-
2  *
3  * Copyright (C) 2006-2007 Mathias Froehlich 
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License as
7  * published by the Free Software Foundation; either version 2 of the
8  * License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18  * MA 02110-1301, USA.
19  *
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #  include <simgear_config.h>
24 #endif
25
26 #include <simgear/compiler.h>
27
28 #include "SGVasiDrawable.hxx"
29
30 struct SGVasiDrawable::LightData {
31   LightData(const SGVec3f& p, const SGVec3f& n, const SGVec3f& up) :
32     position(p),
33     normal(n),
34     horizontal(normalize(cross(up, n))),
35     normalCrossHorizontal(normalize(cross(n, horizontal)))
36   { }
37   
38   void draw(const SGVec4f& color) const
39   {
40     glBegin(GL_POINTS);
41     glColor4fv(color.data());
42     glNormal3fv(normal.data());
43     glVertex3fv(position.data());
44     glEnd();
45   }
46   
47   SGVec3f position;
48   SGVec3f normal;
49   SGVec3f horizontal;
50   SGVec3f normalCrossHorizontal;
51 };
52
53 SGVasiDrawable::SGVasiDrawable(const SGVasiDrawable& vd, const osg::CopyOp&) :
54   _lights(vd._lights),
55   _red(vd._red),
56   _white(vd._white)
57 {
58   setUseDisplayList(false);
59   setSupportsDisplayList(false);
60 }
61
62 SGVasiDrawable::SGVasiDrawable(const SGVec4f& red, const SGVec4f& white) :
63   _red(red),
64   _white(white)
65 {
66   setUseDisplayList(false);
67   setSupportsDisplayList(false);
68 }
69
70 void
71 SGVasiDrawable::addLight(const SGVec3f& position, const SGVec3f& normal,
72                          const SGVec3f& up, float azimutDeg)
73 {
74   SGVec3f horizontal(normalize(cross(up, normal)));
75   SGVec3f zeroGlideSlope = normalize(cross(horizontal, up));
76   SGQuatf rotation = SGQuatf::fromAngleAxisDeg(azimutDeg, horizontal);
77   SGVec3f azimutGlideSlope = rotation.transform(zeroGlideSlope);
78   addLight(position, azimutGlideSlope, up);
79 }
80
81 void
82 SGVasiDrawable::addLight(const SGVec3f& position, const SGVec3f& normal,
83                          const SGVec3f& up)
84 {
85   _lights.push_back(LightData(position, normal, up));
86 }
87
88 void
89 SGVasiDrawable::drawImplementation(osg::RenderInfo& renderInfo) const
90 {
91   // Make sure we have the current state set
92 //   renderInfo.getState()->apply();
93
94   // Retrieve the eye point in local coords
95   osg::Matrix m;
96   m.invert(renderInfo.getState()->getModelViewMatrix());
97   SGVec3f eyePoint(m.preMult(osg::Vec3(0, 0, 0)));
98   
99   // paint the points
100   for (unsigned i = 0; i < _lights.size(); ++i)
101     draw(eyePoint, _lights[i]);
102 }
103
104 osg::BoundingBox
105 SGVasiDrawable::computeBound() const
106 {
107   osg::BoundingBox bb;
108   for (unsigned i = 0; i < _lights.size(); ++i)
109     bb.expandBy(_lights[i].position.osg());
110   
111   // blow up to avoid being victim to small feature culling ...
112   bb.expandBy(bb._min - osg::Vec3(1, 1, 1));
113   bb.expandBy(bb._max + osg::Vec3(1, 1, 1));
114   return bb;
115 }
116
117 SGVec4f
118 SGVasiDrawable::getColor(float angleDeg) const
119 {
120   float transDeg = 0.05f;
121   if (angleDeg < -transDeg) {
122     return _red;
123   } else if (angleDeg < transDeg) {
124     float fac = angleDeg*0.5f/transDeg + 0.5f;
125     return _red + fac*(_white - _red);
126   } else {
127     return _white;
128   }
129 }
130
131 void
132 SGVasiDrawable::draw(const SGVec3f& eyePoint, const LightData& light) const
133 {
134   // vector pointing from the light position to the eye
135   SGVec3f lightToEye = eyePoint - light.position;
136   
137   // dont' draw, we are behind it
138   if (dot(lightToEye, light.normal) < SGLimitsf::min())
139     return;
140   
141   // Now project the eye point vector into the plane defined by the
142   // glideslope direction and the up direction
143   SGVec3f projLightToEye = lightToEye
144     - light.horizontal*dot(lightToEye, light.horizontal);
145   
146   // dont' draw, if we are to near, looks like we are already behind
147   float sqrProjLightToEyeLength = dot(projLightToEye, projLightToEye);
148   if (sqrProjLightToEyeLength < 1e-3*1e-3)
149     return;
150   
151   // the scalar product of the glide slope up direction with the eye vector
152   float dotProd = dot(projLightToEye, light.normalCrossHorizontal);
153   float sinAngle = dotProd/sqrt(sqrProjLightToEyeLength);
154   if (sinAngle < -1)
155     sinAngle = -1;
156   if (1 < sinAngle)
157     sinAngle = 1;
158   
159   float angleDeg = SGMiscf::rad2deg(asin(sinAngle));
160   light.draw(getColor(angleDeg));
161 }
162