1 #include "MasterState.hpp"
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"
12 #include <glm/gtx/transform.hpp>
18 MasterState::MasterState(Assets &assets, world::Simulation &sim) noexcept
25 , cam_orient(PI * 0.375, PI * 0.25, 0.0)
35 MasterState::~MasterState() noexcept {
39 void MasterState::OnResize(int w, int h) {
40 assets.shaders.canvas.Activate();
41 assets.shaders.canvas.Resize(float(w), float(h));
42 assets.shaders.alpha_sprite.Activate();
43 assets.shaders.alpha_sprite.SetVP(glm::mat4(1.0f), glm::ortho(0.0f, float(w), float(h), 0.0f, 1.0e4f, -1.0e4f));
45 cam.Aspect(float(w), float(h));
46 assets.shaders.planet_surface.Activate();
47 assets.shaders.planet_surface.SetVP(cam.View(), cam.Projection());
48 assets.shaders.sun_surface.Activate();
49 assets.shaders.sun_surface.SetVP(cam.View(), cam.Projection());
50 assets.shaders.creature_skin.Activate();
51 assets.shaders.creature_skin.SetVP(cam.View(), cam.Projection());
54 void MasterState::OnUpdate(int dt) {
59 // one tick per frame when debugging so pausing execution doesn't result in more ticks
62 while (remain >= FrameMS() && max_tick > 0) {
68 void MasterState::Tick() {
69 constexpr double dt = 0.01666666666666666666666666666666;
74 thirds = (thirds + 1) % 3;
76 double cam_diff = cam_tgt_dist - cam_dist;
77 if (std::abs(cam_diff) > 0.001) {
78 cam_dist += cam_diff * 0.25;
80 cam_dist = cam_tgt_dist;
84 int MasterState::FrameMS() const noexcept {
85 return thirds == 0 ? 16 : 17;
89 void MasterState::OnKeyDown(const SDL_KeyboardEvent &e) {
90 if (e.keysym.sym == SDLK_p) {
95 void MasterState::OnMouseDown(const SDL_MouseButtonEvent &e) {
96 if (e.button == SDL_BUTTON_RIGHT && cp.Shown()) {
97 SDL_SetRelativeMouseMode(SDL_TRUE);
102 void MasterState::OnMouseUp(const SDL_MouseButtonEvent &e) {
103 if (e.button == SDL_BUTTON_LEFT) {
104 glm::dmat4 inverse(glm::inverse(cam.Projection() * cam.View()));
105 math::Ray ray(inverse * App().GetViewport().ShootPixel(e.x, e.y));
106 creature::Creature *closest = nullptr;
107 double closest_dist = 1.0e24;
108 for (creature::Creature *c : sim.LiveCreatures()) {
109 glm::dvec3 normal(0.0);
111 if (Intersect(ray, c->CollisionBox(), glm::dmat4(cam.Model(c->GetSituation().GetPlanet())) * c->CollisionTransform(), normal, dist)
112 && dist < closest_dist) {
122 } else if (e.button == SDL_BUTTON_RIGHT) {
123 SDL_SetRelativeMouseMode(SDL_FALSE);
124 cam_dragging = false;
128 void MasterState::OnMouseMotion(const SDL_MouseMotionEvent &e) {
129 constexpr double pitch_scale = PI * 0.001;
130 constexpr double yaw_scale = PI * 0.002;
132 cam_orient.x = glm::clamp(cam_orient.x + double(e.yrel) * pitch_scale, 0.0, PI * 0.499);
133 cam_orient.y = std::fmod(cam_orient.y + double(e.xrel) * yaw_scale, PI * 2.0);
137 void MasterState::OnMouseWheel(const SDL_MouseWheelEvent &e) {
138 constexpr double roll_scale = PI * 0.0625;
139 constexpr double zoom_scale = -1.0;
140 constexpr double zoom_base = 1.125;
141 cam_orient.z = glm::clamp(cam_orient.z + double(e.x) * roll_scale, PI * -0.5, PI * 0.5);
142 cam_tgt_dist = std::max(cp.GetCreature().Size() * 2.0, cam_tgt_dist * std::pow(zoom_base, double(e.y) * zoom_scale));
145 void MasterState::OnRender(graphics::Viewport &viewport) {
147 cam.Radial(cp.GetCreature(), cam_dist, cam_orient);
148 assets.shaders.planet_surface.Activate();
149 assets.shaders.planet_surface.SetV(cam.View());
150 assets.shaders.sun_surface.Activate();
151 assets.shaders.sun_surface.SetV(cam.View());
152 assets.shaders.creature_skin.Activate();
153 assets.shaders.creature_skin.SetV(cam.View());
157 for (auto sun : sim.Suns()) {
158 // TODO: source sun's light color and strength
159 glm::vec3 pos(cam.View() * cam.Model(*sun)[3]);
160 glm::vec3 col(1.0f, 1.0f, 1.0f);
162 assets.shaders.planet_surface.Activate();
163 assets.shaders.planet_surface.SetLight(num_lights, pos, col, str);
164 assets.shaders.creature_skin.Activate();
165 assets.shaders.creature_skin.SetLight(num_lights, pos, col, str);
167 if (num_lights >= graphics::PlanetSurface::MAX_LIGHTS || num_lights >= graphics::CreatureSkin::MAX_LIGHTS) {
171 for (auto planet : sim.Planets()) {
172 // TODO: indirect light from planets, calculate strength and get color somehow
173 glm::vec3 pos(cam.View() * cam.Model(*planet)[3]);
174 glm::vec3 col(1.0f, 1.0f, 1.0f);
176 assets.shaders.planet_surface.Activate();
177 assets.shaders.planet_surface.SetLight(num_lights, pos, col, str);
178 assets.shaders.creature_skin.Activate();
179 assets.shaders.creature_skin.SetLight(num_lights, pos, col, str);
181 if (num_lights >= graphics::PlanetSurface::MAX_LIGHTS || num_lights >= graphics::CreatureSkin::MAX_LIGHTS) {
185 assets.shaders.planet_surface.Activate();
186 assets.shaders.planet_surface.SetNumLights(num_lights);
187 assets.shaders.creature_skin.Activate();
188 assets.shaders.creature_skin.SetNumLights(num_lights);
190 assets.shaders.planet_surface.Activate();
191 assets.shaders.planet_surface.SetTexture(assets.textures.tiles);
192 for (auto planet : sim.Planets()) {
193 assets.shaders.planet_surface.SetM(cam.Model(*planet));
194 planet->Draw(assets, viewport);
197 assets.shaders.sun_surface.Activate();
198 for (auto sun : sim.Suns()) {
199 double sun_radius = sun->Radius();
200 assets.shaders.sun_surface.SetM(
201 cam.Model(*sun) * glm::scale(glm::vec3(sun_radius, sun_radius, sun_radius)));
202 assets.shaders.sun_surface.SetLight(glm::vec3(1.0f, 1.0f, 1.0f), 1.0e6f);
203 assets.shaders.sun_surface.Draw();
206 assets.shaders.creature_skin.Activate();
207 assets.shaders.creature_skin.SetTexture(assets.textures.skins);
208 // TODO: extend to nearby bodies as well
209 for (auto c : cam.Reference().Creatures()) {
210 assets.shaders.creature_skin.SetM(cam.Model(cam.Reference()) * glm::mat4(c->LocalTransform()));
211 assets.shaders.creature_skin.SetBaseColor(glm::vec3(c->BaseColor()));
212 assets.shaders.creature_skin.SetHighlightColor(glm::vec4(c->HighlightColor()));
216 viewport.ClearDepth();