]> git.localhorst.tv Git - blobs.git/blob - src/graphics/viewport.cpp
6137eb2620d6f463445f45f80091088f62beb5ea
[blobs.git] / src / graphics / viewport.cpp
1 #include "Camera.hpp"
2 #include "Viewport.hpp"
3
4 #include "../creature/Creature.hpp"
5 #include "../math/const.hpp"
6 #include "../world/Body.hpp"
7 #include "../world/Planet.hpp"
8
9 #include <cmath>
10 #include <GL/glew.h>
11 #include <glm/gtx/euler_angles.hpp>
12 #include <glm/gtx/rotate_vector.hpp>
13 #include <glm/gtx/transform.hpp>
14
15
16 namespace blobs {
17 namespace graphics {
18
19 Camera::Camera(const world::Body &r) noexcept
20 : fov(PI_0p25)
21 , aspect(1.0f)
22 , near(0.1f)
23 , far(12560.0f)
24 , projection(glm::perspective(fov, aspect, near, far))
25 , view(1.0f)
26 , ref(&r)
27 , track_orient(false) {
28
29 }
30
31 Camera::~Camera() noexcept {
32 }
33
34 Camera &Camera::FOV(float f) noexcept {
35         fov = f;
36         UpdateProjection();
37         return *this;
38 }
39
40 Camera &Camera::Aspect(float r) noexcept {
41         aspect = r;
42         UpdateProjection();
43         return *this;
44 }
45
46 Camera &Camera::Aspect(float w, float h) noexcept {
47         Aspect(w / h);
48         return *this;
49 }
50
51 Camera &Camera::Clip(float n, float f) noexcept {
52         near = n;
53         far = f;
54         UpdateProjection();
55         return *this;
56 }
57
58 Camera &Camera::Reference(const world::Body &r) noexcept {
59         ref = &r;
60         return *this;
61 }
62
63 Camera &Camera::FirstPerson(int srf, const glm::vec3 &pos, const glm::vec3 &at) noexcept {
64         track_orient = true;
65
66         float dir = srf < 3 ? 1.0f : -1.0f;
67
68         glm::vec3 position;
69         position[(srf + 0) % 3] = pos.x;
70         position[(srf + 1) % 3] = pos.y;
71         position[(srf + 2) % 3] = dir * (pos.z + Reference().Radius());
72
73         glm::vec3 up(world::Planet::SurfaceNormal(srf));
74
75         glm::vec3 target;
76         target[(srf + 0) % 3] = at.x;
77         target[(srf + 1) % 3] = at.y;
78         target[(srf + 2) % 3] = dir * (at.z + Reference().Radius());
79
80         view = glm::lookAt(position, target, up);
81
82         return *this;
83 }
84
85 Camera &Camera::MapView(int srf, const glm::vec3 &pos, float roll) noexcept {
86         track_orient = true;
87
88         float dir = srf < 3 ? 1.0f : -1.0f;
89
90         glm::vec3 up(0.0f);
91         up[(srf + 0) % 3] = std::sin(roll);
92         up[(srf + 1) % 3] = std::cos(roll);
93         up[(srf + 2) % 3] = 0.0f;
94
95         glm::vec3 target = pos;
96         target[(srf + 2) % 3] -= dir;
97
98         view = glm::lookAt(pos, target, up);
99
100         return *this;
101 }
102
103 Camera &Camera::Orbital(const glm::vec3 &pos) noexcept {
104         track_orient = false;
105         view = glm::lookAt(pos, glm::vec3(0.0f), glm::vec3(0.0f, 1.0f, 0.0f));
106         return *this;
107 }
108
109 Camera &Camera::TopDown(const creature::Creature &c, double distance, double roll) {
110         const creature::Situation &s = c.GetSituation();
111         if (s.OnSurface()) {
112                 int srf = s.Surface();
113                 glm::vec3 pos(s.Position() + (world::Planet::SurfaceNormal(srf) * distance));
114                 Reference(s.GetPlanet());
115                 return MapView(srf, pos, roll);
116         } else {
117                 glm::vec3 pos(s.Position());
118                 pos += glm::normalize(pos) * float(distance);
119                 return Orbital(pos);
120         }
121 }
122
123 Camera &Camera::Radial(const creature::Creature &c, double distance, const glm::dvec3 &angle) {
124         const creature::Situation &s = c.GetSituation();
125         glm::dvec3 pos(s.Position());
126         glm::dvec3 up(0.0);
127         glm::dvec3 dir(0.0, 0.0, -distance);
128         if (s.OnSurface()) {
129                 Reference(s.GetPlanet());
130                 track_orient = true;
131                 int srf = s.Surface();
132                 up = world::Planet::SurfaceNormal(srf);
133                 dir =
134                         world::Planet::SurfaceOrientation(srf)
135                         * glm::dmat3(glm::eulerAngleYX(angle.y, -angle.x))
136                         * dir;
137         } else {
138                 up.y = 1.0;
139                 dir = glm::dmat3(glm::eulerAngleYX(angle.y, -angle.x)) * dir;
140         }
141         pos += up * (c.Size() * 0.5);
142         up = glm::rotate(up, angle.z, glm::normalize(-dir));
143         view = glm::lookAt(pos - dir, pos, up);
144         return *this;
145 }
146
147 glm::mat4 Camera::Model(const world::Body &b) const noexcept {
148         if (&b == ref) {
149                 return track_orient ? glm::mat4(1.0f) : glm::mat4(ref->LocalTransform());
150         } else if (b.HasParent() && &b.Parent() == ref) {
151                 return track_orient
152                         ? ref->InverseTransform() * b.FromParent() * b.LocalTransform()
153                         : b.FromParent() * b.LocalTransform();
154         } else if (ref->HasParent() && &ref->Parent() == &b) {
155                 return track_orient
156                         ? ref->InverseTransform() * ref->ToParent() * b.LocalTransform()
157                         : ref->ToParent() * b.LocalTransform();
158         } else {
159                 return track_orient
160                         ? ref->InverseTransform() * ref->ToUniverse() * b.FromUniverse() * b.LocalTransform()
161                         : ref->ToUniverse() * b.FromUniverse() * b.LocalTransform();
162         }
163 }
164
165 void Camera::UpdateProjection() noexcept {
166         projection = glm::perspective(fov, aspect, near, far);
167 }
168
169
170 Viewport::Viewport(int w, int h)
171 : width(w)
172 , height(h) {
173         Resize(w, h);
174         glClearColor(0.0, 0.0, 0.0, 1.0);
175 }
176
177 Viewport::~Viewport() {
178 }
179
180
181 void Viewport::Resize(int w, int h) {
182         width = w;
183         height = h;
184         glViewport(0, 0, w, h);
185 }
186
187 void Viewport::Clear() {
188         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
189 }
190
191 void Viewport::ClearDepth() {
192         glClear(GL_DEPTH_BUFFER_BIT);
193 }
194
195 }
196 }