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 #include <simgear/scene/util/OsgMath.hxx>
31
32 struct SGVasiDrawable::LightData {
LightDataSGVasiDrawable::LightData33 LightData(const SGVec3f& p, const SGVec3f& n, const SGVec3f& up) :
34 position(p),
35 normal(n),
36 horizontal(normalize(cross(up, n))),
37 normalCrossHorizontal(normalize(cross(n, horizontal)))
38 { }
39
drawSGVasiDrawable::LightData40 void draw(const SGVec4f& color) const
41 {
42 glBegin(GL_POINTS);
43 glColor4fv(color.data());
44 glNormal3fv(normal.data());
45 glVertex3fv(position.data());
46 glEnd();
47 }
48
49 SGVec3f position;
50 SGVec3f normal;
51 SGVec3f horizontal;
52 SGVec3f normalCrossHorizontal;
53 };
54
SGVasiDrawable(const SGVasiDrawable & vd,const osg::CopyOp &)55 SGVasiDrawable::SGVasiDrawable(const SGVasiDrawable& vd, const osg::CopyOp&) :
56 _lights(vd._lights),
57 _red(vd._red),
58 _white(vd._white)
59 {
60 setUseDisplayList(false);
61 setSupportsDisplayList(false);
62 }
63
SGVasiDrawable(const SGVec4f & red,const SGVec4f & white)64 SGVasiDrawable::SGVasiDrawable(const SGVec4f& red, const SGVec4f& white) :
65 _red(red),
66 _white(white)
67 {
68 setUseDisplayList(false);
69 setSupportsDisplayList(false);
70 }
71
72 void
addLight(const SGVec3f & position,const SGVec3f & normal,const SGVec3f & up,float azimutDeg)73 SGVasiDrawable::addLight(const SGVec3f& position, const SGVec3f& normal,
74 const SGVec3f& up, float azimutDeg)
75 {
76 SGVec3f horizontal(normalize(cross(up, normal)));
77 SGVec3f zeroGlideSlope = normalize(cross(horizontal, up));
78 SGQuatf rotation = SGQuatf::fromAngleAxisDeg(azimutDeg, horizontal);
79 SGVec3f azimutGlideSlope = rotation.transform(zeroGlideSlope);
80 addLight(position, azimutGlideSlope, up);
81 }
82
83 void
addLight(const SGVec3f & position,const SGVec3f & normal,const SGVec3f & up)84 SGVasiDrawable::addLight(const SGVec3f& position, const SGVec3f& normal,
85 const SGVec3f& up)
86 {
87 _lights.push_back(LightData(position, normal, up));
88 }
89
90 void
drawImplementation(osg::RenderInfo & renderInfo) const91 SGVasiDrawable::drawImplementation(osg::RenderInfo& renderInfo) const
92 {
93 // Make sure we have the current state set
94 // renderInfo.getState()->apply();
95
96 // Retrieve the eye point in local coords
97 osg::Matrix m;
98 m.invert(renderInfo.getState()->getModelViewMatrix());
99 SGVec3f eyePoint(toSG(m.preMult(osg::Vec3(0, 0, 0))));
100
101 // paint the points
102 for (unsigned i = 0; i < _lights.size(); ++i)
103 draw(eyePoint, _lights[i]);
104 }
105
106 osg::BoundingBox
107 #if OSG_VERSION_LESS_THAN(3,3,2)
computeBound() const108 SGVasiDrawable::computeBound()
109 #else
110 SGVasiDrawable::computeBoundingBox()
111 #endif
112 const
113 {
114 osg::BoundingBox bb;
115 for (unsigned i = 0; i < _lights.size(); ++i)
116 bb.expandBy(toOsg(_lights[i].position));
117
118 // blow up to avoid being victim to small feature culling ...
119 bb.expandBy(bb._min - osg::Vec3(1, 1, 1));
120 bb.expandBy(bb._max + osg::Vec3(1, 1, 1));
121 return bb;
122 }
123
124 SGVec4f
getColor(float angleDeg) const125 SGVasiDrawable::getColor(float angleDeg) const
126 {
127 float transDeg = 0.05f;
128 if (angleDeg < -transDeg) {
129 return _red;
130 } else if (angleDeg < transDeg) {
131 float fac = angleDeg*0.5f/transDeg + 0.5f;
132 return _red + fac*(_white - _red);
133 } else {
134 return _white;
135 }
136 }
137
138 void
draw(const SGVec3f & eyePoint,const LightData & light) const139 SGVasiDrawable::draw(const SGVec3f& eyePoint, const LightData& light) const
140 {
141 // vector pointing from the light position to the eye
142 SGVec3f lightToEye = eyePoint - light.position;
143
144 // dont' draw, we are behind it
145 if (dot(lightToEye, light.normal) < SGLimitsf::min())
146 return;
147
148 // Now project the eye point vector into the plane defined by the
149 // glideslope direction and the up direction
150 SGVec3f projLightToEye = lightToEye
151 - light.horizontal*dot(lightToEye, light.horizontal);
152
153 // dont' draw, if we are to near, looks like we are already behind
154 float sqrProjLightToEyeLength = dot(projLightToEye, projLightToEye);
155 if (sqrProjLightToEyeLength < 1e-3*1e-3)
156 return;
157
158 // the scalar product of the glide slope up direction with the eye vector
159 float dotProd = dot(projLightToEye, light.normalCrossHorizontal);
160 float sinAngle = dotProd/sqrt(sqrProjLightToEyeLength);
161 if (sinAngle < -1)
162 sinAngle = -1;
163 if (1 < sinAngle)
164 sinAngle = 1;
165
166 float angleDeg = SGMiscf::rad2deg(asin(sinAngle));
167 light.draw(getColor(angleDeg));
168 }
169
170