]> git.localhorst.tv Git - blobs.git/blob - src/app/states.cpp
track a few things
[blobs.git] / src / app / states.cpp
1 #include "MasterState.hpp"
2
3 #include "../creature/Creature.hpp"
4 #include "../graphics/Viewport.hpp"
5 #include "../math/const.hpp"
6 #include "../world/Body.hpp"
7 #include "../world/Planet.hpp"
8 #include "../world/Simulation.hpp"
9 #include "../world/Sun.hpp"
10
11 #include <glm/gtx/transform.hpp>
12
13
14 namespace blobs {
15 namespace app {
16
17 MasterState::MasterState(Assets &assets, world::Simulation &sim) noexcept
18 : State()
19 , assets(assets)
20 , sim(sim)
21 , cam(sim.Root())
22 , cam_dist(5.0)
23 , cam_tgt_dist(5.0)
24 , cam_orient(PI * 0.375, PI * 0.25, 0.0)
25 , cam_dragging(false)
26 , cp(assets)
27 , rp(sim)
28 , tp(sim)
29 , remain(0)
30 , thirds(0)
31 , paused(false) {
32 }
33
34 MasterState::~MasterState() noexcept {
35 }
36
37
38 void MasterState::OnResize(int w, int h) {
39         assets.shaders.canvas.Activate();
40         assets.shaders.canvas.Resize(float(w), float(h));
41         assets.shaders.alpha_sprite.Activate();
42         assets.shaders.alpha_sprite.SetVP(glm::mat4(1.0f), glm::ortho(0.0f, float(w), float(h), 0.0f, 1.0e4f, -1.0e4f));
43
44         cam.Aspect(float(w), float(h));
45         assets.shaders.planet_surface.Activate();
46         assets.shaders.planet_surface.SetVP(cam.View(), cam.Projection());
47         assets.shaders.sun_surface.Activate();
48         assets.shaders.sun_surface.SetVP(cam.View(), cam.Projection());
49         assets.shaders.creature_skin.Activate();
50         assets.shaders.creature_skin.SetVP(cam.View(), cam.Projection());
51 }
52
53 void MasterState::OnUpdate(int dt) {
54         remain += dt;
55 #ifdef NDEBUG
56         int max_tick = 10;
57 #else
58         // one tick per frame when debugging so pausing execution doesn't result in more ticks
59         int max_tick = 1;
60 #endif
61         while (remain >= FrameMS() && max_tick > 0) {
62                 Tick();
63                 --max_tick;
64         }
65 }
66
67 void MasterState::Tick() {
68         constexpr double dt = 0.01666666666666666666666666666666;
69         if (!paused) {
70                 sim.Tick(dt);
71         }
72         remain -= FrameMS();
73         thirds = (thirds + 1) % 3;
74
75         double cam_diff = cam_tgt_dist - cam_dist;
76         if (std::abs(cam_diff) > 0.001) {
77                 cam_dist += cam_diff * 0.25;
78         } else {
79                 cam_dist = cam_tgt_dist;
80         }
81 }
82
83 int MasterState::FrameMS() const noexcept {
84         return thirds == 0 ? 16 : 17;
85 }
86
87
88 void MasterState::OnKeyDown(const SDL_KeyboardEvent &e) {
89         if (e.keysym.sym == SDLK_p) {
90                 paused = !paused;
91         }
92 }
93
94 void MasterState::OnMouseDown(const SDL_MouseButtonEvent &e) {
95         if (e.button == SDL_BUTTON_RIGHT) {
96                 SDL_SetRelativeMouseMode(SDL_TRUE);
97                 cam_dragging = true;
98         }
99 }
100
101 void MasterState::OnMouseUp(const SDL_MouseButtonEvent &e) {
102         if (e.button == SDL_BUTTON_RIGHT) {
103                 SDL_SetRelativeMouseMode(SDL_FALSE);
104                 cam_dragging = false;
105         }
106 }
107
108 void MasterState::OnMouseMotion(const SDL_MouseMotionEvent &e) {
109         constexpr double pitch_scale = PI * 0.001;
110         constexpr double yaw_scale = PI * 0.002;
111         if (cam_dragging) {
112                 cam_orient.x = glm::clamp(cam_orient.x + double(e.yrel) * pitch_scale, 0.0, PI * 0.5);
113                 cam_orient.y = std::fmod(cam_orient.y + double(e.xrel) * yaw_scale, PI * 2.0);
114         }
115 }
116
117 void MasterState::OnMouseWheel(const SDL_MouseWheelEvent &e) {
118         constexpr double roll_scale = PI * 0.0625;
119         constexpr double zoom_scale = -1.0;
120         constexpr double zoom_base = 1.125;
121         cam_orient.z = glm::clamp(cam_orient.z + double(e.x) * roll_scale, PI * -0.5, PI * 0.5);
122         cam_tgt_dist = std::max(cp.GetCreature().Size() * 2.0, cam_tgt_dist * std::pow(zoom_base, double(e.y) * zoom_scale));
123 }
124
125 void MasterState::OnRender(graphics::Viewport &viewport) {
126         if (cp.Shown()) {
127                 cam.Radial(cp.GetCreature(), cam_dist, cam_orient);
128                 assets.shaders.planet_surface.Activate();
129                 assets.shaders.planet_surface.SetV(cam.View());
130                 assets.shaders.sun_surface.Activate();
131                 assets.shaders.sun_surface.SetV(cam.View());
132                 assets.shaders.creature_skin.Activate();
133                 assets.shaders.creature_skin.SetV(cam.View());
134         }
135
136         int num_lights = 0;
137         for (auto sun : sim.Suns()) {
138                 // TODO: source sun's light color and strength
139                 glm::vec3 pos(cam.View() * cam.Model(*sun)[3]);
140                 glm::vec3 col(1.0f, 1.0f, 1.0f);
141                 float str = 1.0e6f;
142                 assets.shaders.planet_surface.Activate();
143                 assets.shaders.planet_surface.SetLight(num_lights, pos, col, str);
144                 assets.shaders.creature_skin.Activate();
145                 assets.shaders.creature_skin.SetLight(num_lights, pos, col, str);
146                 ++num_lights;
147                 if (num_lights >= graphics::PlanetSurface::MAX_LIGHTS || num_lights >= graphics::CreatureSkin::MAX_LIGHTS) {
148                         break;
149                 }
150         }
151         for (auto planet : sim.Planets()) {
152                 // TODO: indirect light from planets, calculate strength and get color somehow
153                 glm::vec3 pos(cam.View() * cam.Model(*planet)[3]);
154                 glm::vec3 col(1.0f, 1.0f, 1.0f);
155                 float str = 10.0f;
156                 assets.shaders.planet_surface.Activate();
157                 assets.shaders.planet_surface.SetLight(num_lights, pos, col, str);
158                 assets.shaders.creature_skin.Activate();
159                 assets.shaders.creature_skin.SetLight(num_lights, pos, col, str);
160                 ++num_lights;
161                 if (num_lights >= graphics::PlanetSurface::MAX_LIGHTS || num_lights >= graphics::CreatureSkin::MAX_LIGHTS) {
162                         break;
163                 }
164         }
165         assets.shaders.planet_surface.Activate();
166         assets.shaders.planet_surface.SetNumLights(num_lights);
167         assets.shaders.creature_skin.Activate();
168         assets.shaders.creature_skin.SetNumLights(num_lights);
169
170         assets.shaders.planet_surface.Activate();
171         assets.shaders.planet_surface.SetTexture(assets.textures.tiles);
172         for (auto planet : sim.Planets()) {
173                 assets.shaders.planet_surface.SetM(cam.Model(*planet));
174                 planet->Draw(assets, viewport);
175         }
176
177         assets.shaders.sun_surface.Activate();
178         for (auto sun : sim.Suns()) {
179                 double sun_radius = sun->Radius();
180                 assets.shaders.sun_surface.SetM(
181                         cam.Model(*sun) * glm::scale(glm::vec3(sun_radius, sun_radius, sun_radius)));
182                 assets.shaders.sun_surface.SetLight(glm::vec3(1.0f, 1.0f, 1.0f), 1.0e6f);
183                 assets.shaders.sun_surface.Draw();
184         }
185
186         assets.shaders.creature_skin.Activate();
187         assets.shaders.creature_skin.SetTexture(assets.textures.skins);
188         // TODO: extend to nearby bodies as well
189         for (auto c : cam.Reference().Creatures()) {
190                 assets.shaders.creature_skin.SetM(cam.Model(cam.Reference()) * glm::mat4(c->LocalTransform()));
191                 assets.shaders.creature_skin.SetBaseColor(c->BaseColor());
192                 assets.shaders.creature_skin.SetHighlightColor(c->HighlightColor());
193                 c->Draw(viewport);
194         }
195
196         viewport.ClearDepth();
197         cp.Draw(viewport);
198         rp.Draw(viewport);
199         tp.Draw(viewport);
200 }
201
202 }
203 }