1 /*
2 * Copyright (C) 2010-2011 Dmitry Marakasov
3 *
4 * This file is part of glosm.
5 *
6 * glosm is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * glosm is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with glosm. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include <glosm/FirstPersonViewer.hh>
21
22 #include <glosm/Math.hh>
23 #include <glosm/Projection.hh>
24 #include <glosm/geomath.h>
25
26 #include "mglu.h"
27
28 #include "glosm/util/gl.h"
29
30 #include <stdio.h>
31
FirstPersonViewer()32 FirstPersonViewer::FirstPersonViewer(): pos_(), yaw_(0), pitch_(0), fov_(90.0), aspect_(1.0) {
33 }
34
FirstPersonViewer(const Vector3i & pos)35 FirstPersonViewer::FirstPersonViewer(const Vector3i& pos): pos_(pos), yaw_(0), pitch_(0), fov_(90.0), aspect_(1.0) {
36 }
37
FirstPersonViewer(const Vector3i & pos,float yaw,float pitch)38 FirstPersonViewer::FirstPersonViewer(const Vector3i& pos, float yaw, float pitch): pos_(pos), yaw_(yaw), pitch_(pitch), fov_(90.0), aspect_(1.0) {
39 }
40
SetupViewerMatrix(const Projection & projection) const41 void FirstPersonViewer::SetupViewerMatrix(const Projection& projection) const {
42 glMatrixMode(GL_PROJECTION);
43 glLoadIdentity();
44
45 /* length of a meter in local units */
46 float meterlen = projection.Project(pos_.Flattened() + Vector3i(0, 0, GEOM_UNITSINMETER), pos_.Flattened()).z;
47
48 /* viewer height in meters */
49 float height = pos_.z / (float)GEOM_UNITSINMETER;
50 if (height < 100.0f)
51 height = 100.0f;
52
53 /* viewing distances is [1meter..100km] at under 100m height
54 * and increases linearly with going higher */
55 float znear = 0.01f * height * meterlen;
56 float zfar = 1000.0f * height * meterlen;
57
58 mgluPerspective(fov_ / M_PI * 180.0f, aspect_, znear, zfar);
59
60 glMatrixMode(GL_MODELVIEW);
61 glLoadIdentity();
62
63 Vector3f dir = GetDirection();
64 Vector3f up = Vector3f(0.0f, 0.0f, 1.0f);
65
66 mgluLookAt(0.0f, 0.0f, 0.0f, dir.x, dir.y, dir.z, up.x, up.y, up.z);
67 }
68
GetPos(const Projection &) const69 Vector3i FirstPersonViewer::GetPos(const Projection& /* unused*/) const {
70 return pos_;
71 }
72
SetFov(float fov)73 void FirstPersonViewer::SetFov(float fov) {
74 fov_ = fov;
75 }
76
SetAspect(float aspect)77 void FirstPersonViewer::SetAspect(float aspect) {
78 aspect_ = aspect;
79 }
80
GetDirection() const81 Vector3f FirstPersonViewer::GetDirection() const {
82 return Vector3f::FromYawPitch(yaw_, pitch_);
83 }
84
SetPos(Vector3i pos)85 void FirstPersonViewer::SetPos(Vector3i pos) {
86 pos_ = pos;
87 }
88
Move(int flags,float speed,float time)89 void FirstPersonViewer::Move(int flags, float speed, float time) {
90 /* 1 meter direction-collinear vector in OSM coordinate space */
91 Vector3f dirbasis = Vector3f(
92 GEOM_LONSPAN / WGS84_EARTH_EQ_LENGTH / cos(pos_.y * GEOM_DEG_TO_RAD),
93 GEOM_LONSPAN / WGS84_EARTH_EQ_LENGTH,
94 GEOM_UNITSINMETER
95 );
96
97 Vector3f dir = GetDirection();
98 Vector3f worldup = Vector3f(0.0f, 0.0f, 1.0f);
99 Vector3f right = dir.CrossProduct(worldup).Normalized();
100 Vector3f relup = right.CrossProduct(dir).Normalized();
101
102 if (flags & FORWARD)
103 pos_ += dirbasis * dir * speed * time;
104 if (flags & BACKWARD)
105 pos_ -= dirbasis * dir * speed * time;
106 if (flags & LEFT)
107 pos_ -= dirbasis * right * speed * time;
108 if (flags & RIGHT)
109 pos_ += dirbasis * right * speed * time;
110 if (flags & UP)
111 pos_ += dirbasis * relup * speed * time;
112 if (flags & DOWN)
113 pos_ -= dirbasis * relup * speed * time;
114 if (flags & HIGHER)
115 pos_ += dirbasis * worldup * speed * time;
116 if (flags & LOWER)
117 pos_ -= dirbasis * worldup * speed * time;
118
119 /* Wrap around */
120 if (pos_.x > GEOM_MAXLON)
121 pos_.x -= GEOM_LONSPAN;
122 if (pos_.x < GEOM_MINLON)
123 pos_.x += GEOM_LONSPAN;
124
125 /* Limit poles */
126 if (pos_.y > GEOM_MERCATOR_MAXLAT)
127 pos_.y = GEOM_MERCATOR_MAXLAT;
128 if (pos_.y < GEOM_MERCATOR_MINLAT)
129 pos_.y = GEOM_MERCATOR_MINLAT;
130
131 /* Limit height */
132 if (pos_.z < 0.0)
133 pos_.z = 0.0;
134 if (pos_.z > std::numeric_limits<osmint_t>::max())
135 pos_.z = std::numeric_limits<osmint_t>::max();
136 }
137
FixRotation()138 void FirstPersonViewer::FixRotation() {
139 static const float PitchLimit = M_PI/2.0*0.9;
140
141 if (pitch_ > PitchLimit)
142 pitch_ = PitchLimit;
143 if (pitch_ < -PitchLimit)
144 pitch_ = -PitchLimit;
145 if (yaw_ > M_PI)
146 yaw_ -= M_PI*2.0;
147 if (yaw_ < -M_PI)
148 yaw_ += M_PI*2.0;
149 }
150
SetRotation(float yaw,float pitch)151 void FirstPersonViewer::SetRotation(float yaw, float pitch) {
152 yaw_ = yaw;
153 pitch_ = pitch;
154
155 FixRotation();
156 }
157
Rotate(float yawspeed,float pitchspeed,float time)158 void FirstPersonViewer::Rotate(float yawspeed, float pitchspeed, float time) {
159 yaw_ += yawspeed * time;
160 pitch_ += pitchspeed * time;
161
162 FixRotation();
163 }
164
GetYaw() const165 float FirstPersonViewer::GetYaw() const {
166 return yaw_;
167 }
168
GetPitch() const169 float FirstPersonViewer::GetPitch() const {
170 return pitch_;
171 }
172
GetFov() const173 float FirstPersonViewer::GetFov() const {
174 return fov_;
175 }
176
GetAspect() const177 float FirstPersonViewer::GetAspect() const {
178 return aspect_;
179 }
180
MutablePos()181 Vector3d& FirstPersonViewer::MutablePos() {
182 return pos_;
183 }
184