State &GetState();
bool HasState() const noexcept;
+ Window &GetWindow() noexcept { return window; }
+ const Window &GetWindow() const noexcept { return window; }
+
+ graphics::Viewport &GetViewport() noexcept { return viewport; }
+ const graphics::Viewport &GetViewport() const noexcept { return viewport; }
+
/// Loop until states is empty.
void Run();
/// Evaluate a single frame of dt milliseconds.
#include "MasterState.hpp"
+#include "Application.hpp"
#include "../creature/Creature.hpp"
#include "../graphics/Viewport.hpp"
#include "../math/const.hpp"
}
void MasterState::OnMouseDown(const SDL_MouseButtonEvent &e) {
- if (e.button == SDL_BUTTON_RIGHT) {
+ if (e.button == SDL_BUTTON_RIGHT && cp.Shown()) {
SDL_SetRelativeMouseMode(SDL_TRUE);
cam_dragging = true;
}
}
void MasterState::OnMouseUp(const SDL_MouseButtonEvent &e) {
- if (e.button == SDL_BUTTON_RIGHT) {
+ if (e.button == SDL_BUTTON_LEFT) {
+ glm::dmat4 inverse(glm::inverse(cam.Projection() * cam.View()));
+ math::Ray ray(inverse * App().GetViewport().ShootPixel(e.x, e.y));
+ creature::Creature *closest = nullptr;
+ double closest_dist = 1.0e24;
+ for (creature::Creature *c : sim.LiveCreatures()) {
+ glm::dvec3 normal(0.0);
+ double dist = 0.0;
+ if (Intersect(ray, c->CollisionBox(), glm::dmat4(cam.Model(c->GetSituation().GetPlanet())) * c->CollisionTransform(), normal, dist)
+ && dist < closest_dist) {
+ closest = c;
+ closest_dist = dist;
+ }
+ }
+ if (closest) {
+ cp.Show(*closest);
+ } else {
+ cp.Hide();
+ }
+ } else if (e.button == SDL_BUTTON_RIGHT) {
SDL_SetRelativeMouseMode(SDL_FALSE);
cam_dragging = false;
}
using namespace blobs;
-namespace {
-
-struct SwitchPanel {
- SwitchPanel(world::Planet &p, app::Application &app, app::MasterState &state)
- : planet(p), app(app), state(state) { }
-
- void operator ()(creature::Creature &c) {
- if (planet.Creatures().empty()) {
- planet.GetSimulation().Log() << "no more creatures, game over" << std::endl;
- state.GetCreaturePanel().Hide();
- while (app.HasState()) {
- app.PopState();
- }
- } else {
- for (auto a : planet.Creatures()) {
- if (a != &c) {
- state.GetCreaturePanel().Show(*a);
- a->WhenDead([&](creature::Creature &b) { (*this)(b); });
- break;
- }
- }
- }
- }
-
- world::Planet &planet;
- app::Application &app;
- app::MasterState &state;
-};
-}
-
int main(int argc, char *argv[]) {
app::Init init(true, 8);
app::Assets assets;
state.GetTimePanel().SetBody(planet);
app::Application app(init.window, init.viewport);
- SwitchPanel swp(planet, app, state);
- blob->WhenDead([&](creature::Creature &c) { swp(c); });
app.PushState(&state);
app.Run();
#ifndef BLOBS_GRAPHICS_VIEWPORT_HPP_
#define BLOBS_GRAPHICS_VIEWPORT_HPP_
+#include "../math/geometry.hpp"
+
namespace blobs {
namespace graphics {
}
void Resize(int w, int h);
+ math::Ray ShootPixel(int x, int y) const noexcept {
+ return math::Ray({
+ ((double(x) / double(width)) * 2.0) - 1.0,
+ 1.0 - ((double(y) / double(height)) * 2.0),
+ -1.0 }, { 0.0, 0.0, 1.0 });
+ }
+
void Clear();
void ClearDepth();
#include "glm.hpp"
#include <algorithm>
+#include <ostream>
+#include <glm/gtx/io.hpp>
namespace blobs {
};
+inline std::ostream &operator <<(std::ostream &out, const AABB &b) {
+ return out << "AABB(" << b.min << ", " << b.max << ")";
+}
/// matrices must not scale
bool Intersect(
const AABB &a_box,
};
+inline Ray operator *(const glm::dmat4 &m, const Ray &r) noexcept {
+ glm::dvec4 o(m * glm::dvec4(r.Origin(), 1.0));
+ glm::dvec4 d(m * glm::dvec4(r.Origin() + r.Direction(), 1.0));
+ return Ray(glm::dvec3(o) / o.w, glm::normalize((glm::dvec3(d) / d.w) - (glm::dvec3(o) / o.w)));
+}
+
+inline std::ostream &operator <<(std::ostream &out, const Ray &r) {
+ return out << "Ray(" << r.Origin() << ", " << r.Direction() << ")";
+}
+
/// oriented ray/box intersection test
bool Intersect(
const Ray &,