]> git.localhorst.tv Git - blank.git/blob - src/graphics/viewport.cpp
a475f3e796f1d4c8d2b2af82987db711d368beb5
[blank.git] / src / graphics / viewport.cpp
1 #include "Camera.hpp"
2 #include "Canvas.hpp"
3 #include "SkyBox.hpp"
4 #include "Viewport.hpp"
5
6 #include "../app/error.hpp"
7 #include "../geometry/const.hpp"
8
9 #include <GL/glew.h>
10 #include <glm/gtc/matrix_transform.hpp>
11 #include <glm/gtx/transform.hpp>
12 #include <SDL.h>
13
14
15 namespace blank {
16
17 Camera::Camera() noexcept
18 : fov(PI_0p25)
19 , aspect(1.0f)
20 , near(0.1f)
21 , far(256.0f)
22 , projection(glm::perspective(fov, aspect, near, far))
23 , view(1.0f) {
24
25 }
26
27
28 void Camera::FOV(float f) noexcept {
29         fov = f;
30         UpdateProjection();
31 }
32
33 void Camera::Aspect(float r) noexcept {
34         aspect = r;
35         UpdateProjection();
36 }
37
38 void Camera::Aspect(float w, float h) noexcept {
39         Aspect(w / h);
40 }
41
42 void Camera::Clip(float n, float f) noexcept {
43         near = n;
44         far = f;
45         UpdateProjection();
46 }
47
48 void Camera::View(const glm::mat4 &v) noexcept {
49         view = v;
50 }
51
52 void Camera::UpdateProjection() noexcept {
53         projection = glm::perspective(fov, aspect, near, far);
54 }
55
56
57 Canvas::Canvas() noexcept
58 : offset(0.0f, 0.0f)
59 , size(1.0f, 1.0f)
60 , near(100.0f)
61 , far(-100.0f)
62 , projection(glm::ortho(offset.x, size.x, size.y, offset.y, near, far))
63 , view(1.0f) {
64
65 }
66
67
68 void Canvas::Resize(float w, float h) noexcept {
69         size.x = w;
70         size.y = h;
71         UpdateProjection();
72 }
73
74
75 void Canvas::UpdateProjection() noexcept {
76         projection = glm::ortho(offset.x, size.x, size.y, offset.y, near, far);
77 }
78
79
80 SkyBox::SkyBox(CubeMap &&tex)
81 : texture(std::move(tex))
82 , mesh() {
83         mesh.LoadUnitBox();
84 }
85
86 void SkyBox::Render(Viewport &viewport) noexcept {
87         SkyBoxShader &prog = viewport.SkyBoxProgram();
88         prog.SetTexture(texture);
89         mesh.Draw();
90 }
91
92
93 Viewport::Viewport()
94 : cam()
95 , canv()
96 , cursor(1.0f)
97 , cam_offset(0.0f)
98 , chunk_prog()
99 , entity_prog()
100 , sky_prog()
101 , sprite_prog()
102 , active_prog(NONE) {
103         glClearColor(0.0, 0.0, 0.0, 1.0);
104 }
105
106 void Viewport::VSync(bool b) {
107         if (SDL_GL_SetSwapInterval(b) != 0) {
108                 throw SDLError("SDL_GL_SetSwapInterval");
109         }
110 }
111
112 void Viewport::EnableDepthTest() noexcept {
113         glEnable(GL_DEPTH_TEST);
114         glDepthFunc(GL_LESS);
115 }
116
117 void Viewport::EqualDepthTest() noexcept {
118         glEnable(GL_DEPTH_TEST);
119         glDepthFunc(GL_LEQUAL);
120 }
121
122 void Viewport::DisableDepthTest() noexcept {
123         glDisable(GL_DEPTH_TEST);
124 }
125
126 void Viewport::EnableBackfaceCulling() noexcept {
127         glEnable(GL_CULL_FACE);
128 }
129
130 void Viewport::DisableBackfaceCulling() noexcept {
131         glDisable(GL_CULL_FACE);
132 }
133
134 void Viewport::EnableAlphaBlending() noexcept {
135         glEnable(GL_BLEND);
136         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
137 }
138
139 void Viewport::EnableInvertBlending() noexcept {
140         glEnable(GL_BLEND);
141         glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ZERO);
142 }
143
144 void Viewport::DisableBlending() noexcept {
145         glDisable(GL_BLEND);
146 }
147
148 void Viewport::Resize(int w, int h) noexcept {
149         glViewport(0, 0, w, h);
150         float fw = w;
151         float fh = h;
152         cam.Aspect(fw, fh);
153         canv.Resize(fw, fh);
154
155         ChunkProgram().SetProjection(Perspective());
156         SkyBoxProgram().SetProjection(Perspective());
157         SpriteProgram().SetProjection(Ortho());
158 }
159
160 void Viewport::Clear() noexcept {
161         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
162 }
163
164 void Viewport::ClearDepth() noexcept {
165         glClear(GL_DEPTH_BUFFER_BIT);
166 }
167
168
169 glm::vec2 Viewport::GetPosition(const glm::vec2 &off, Gravity grav) const noexcept {
170         return align(grav, canv.Size(), off + canv.Offset());
171 }
172
173 void Viewport::SetCursor(const glm::vec3 &pos) noexcept {
174         cursor[3].x = pos.x;
175         cursor[3].y = pos.y;
176         cursor[3].z = pos.z;
177 }
178
179 void Viewport::SetCursor(const glm::vec3 &pos, Gravity grav) noexcept {
180         glm::vec2 p(GetPosition(glm::vec2(pos), grav));
181         cursor[3].x = p.x;
182         cursor[3].y = p.y;
183         cursor[3].z = pos.z;
184 }
185
186 void Viewport::MoveCursor(const glm::vec3 &d) noexcept {
187         cursor[3].x += d.x;
188         cursor[3].y += d.y;
189         cursor[3].z += d.z;
190 }
191
192
193 BlockLighting &Viewport::ChunkProgram() noexcept {
194         if (active_prog != CHUNK) {
195                 chunk_prog.Activate();
196                 EnableDepthTest();
197                 EnableBackfaceCulling();
198                 DisableBlending();
199                 active_prog = CHUNK;
200         }
201         return chunk_prog;
202 }
203
204 DirectionalLighting &Viewport::EntityProgram() noexcept {
205         if (active_prog != ENTITY) {
206                 entity_prog.Activate();
207                 EnableDepthTest();
208                 EnableBackfaceCulling();
209                 DisableBlending();
210                 entity_prog.SetVP(cam.View(), cam.Projection());
211                 active_prog = ENTITY;
212         }
213         return entity_prog;
214 }
215
216 DirectionalLighting &Viewport::HUDProgram() noexcept {
217         if (active_prog != HUD) {
218                 entity_prog.Activate();
219                 EnableDepthTest();
220                 EnableBackfaceCulling();
221                 entity_prog.SetVP(canv.View(), canv.Projection());
222                 active_prog = HUD;
223         }
224         return entity_prog;
225 }
226
227 PlainColor &Viewport::WorldColorProgram() noexcept {
228         if (active_prog != COLOR_WORLD) {
229                 color_prog.Activate();
230                 color_prog.SetVP(cam.View(), cam.Projection());
231                 active_prog = COLOR_WORLD;
232         }
233         return color_prog;
234 }
235
236 PlainColor &Viewport::HUDColorProgram() noexcept {
237         if (active_prog != COLOR_HUD) {
238                 color_prog.Activate();
239                 color_prog.SetVP(canv.View(), canv.Projection());
240                 active_prog = COLOR_HUD;
241         }
242         return color_prog;
243 }
244
245 SkyBoxShader &Viewport::SkyBoxProgram() noexcept {
246         if (active_prog != SKY_BOX) {
247                 sky_prog.Activate();
248                 DisableBlending();
249                 DisableBackfaceCulling();
250                 EqualDepthTest();
251                 active_prog = SKY_BOX;
252         }
253         return sky_prog;
254 }
255
256 BlendedSprite &Viewport::SpriteProgram() noexcept {
257         if (active_prog != SPRITE) {
258                 sprite_prog.Activate();
259                 EnableAlphaBlending();
260                 active_prog = SPRITE;
261         }
262         return sprite_prog;
263 }
264
265
266 void Viewport::WorldPosition(const glm::mat4 &t) noexcept {
267         cam.View(glm::translate(glm::inverse(t), glm::vec3(t * glm::vec4(cam_offset, 0.0f))));
268         ChunkProgram().SetView(cam.View());
269         sky_prog.Activate();
270         SkyBoxProgram().SetView(cam.View());
271 }
272
273 }