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