--- /dev/null
+#ifndef BLOBS_APP_APPLICATION_HPP_
+#define BLOBS_APP_APPLICATION_HPP_
+
+#include <stack>
+
+
+namespace blobs {
+namespace app {
+
+class State;
+
+class Application {
+
+public:
+ Application();
+ ~Application();
+
+ Application(const Application &) = delete;
+ Application &operator =(const Application &) = delete;
+
+ Application(Application &&) = delete;
+ Application &operator =(Application &&) = delete;
+
+public:
+ void PushState(State *);
+ State *PopState();
+ State *SwitchState(State *);
+ State &GetState();
+ bool HasState() const noexcept;
+
+ /// Loop until states is empty.
+ void Run();
+ /// Evaluate a single frame of dt milliseconds.
+ void Loop(int dt);
+ /// Process all events in queue.
+ void HandleEvents();
+
+private:
+ std::stack<State *> states;
+
+};
+
+}
+}
+
+#endif
--- /dev/null
+#ifndef BLOBS_APP_STATE_HPP_
+#define BLOBS_APP_STATE_HPP_
+
+#include <SDL.h>
+
+
+namespace blobs {
+namespace app {
+
+class Application;
+
+class State {
+
+ friend class Application;
+
+ void Handle(const SDL_Event &);
+ void Handle(const SDL_WindowEvent &);
+ void Update(int dt);
+ void Render();
+
+ virtual void OnEnter() { }
+ virtual void OnResume() { }
+ virtual void OnPause() { }
+ virtual void OnExit() { }
+
+ virtual void OnFocus() { }
+ virtual void OnBlur() { }
+ virtual void OnResize() { }
+
+ virtual void OnEvent(const SDL_Event &);
+ virtual void OnUpdate(int dt);
+ virtual void OnRender();
+
+ int ref_count = 0;
+
+};
+
+}
+}
+
+#endif
--- /dev/null
+#include "Application.hpp"
+#include "State.hpp"
+
+#include <SDL.h>
+
+
+namespace blobs {
+namespace app {
+
+Application::Application()
+: states() {
+}
+
+Application::~Application() {
+}
+
+
+void Application::PushState(State *s) {
+ if (!states.empty()) {
+ states.top()->OnPause();
+ }
+ states.emplace(s);
+ ++s->ref_count;
+ if (s->ref_count == 1) {
+ s->OnEnter();
+ }
+ s->OnResume();
+}
+
+State *Application::PopState() {
+ State *s = states.top();
+ states.pop();
+ s->OnPause();
+ s->OnExit();
+ if (!states.empty()) {
+ states.top()->OnResume();
+ }
+ return s;
+}
+
+State *Application::SwitchState(State *s_new) {
+ State *s_old = states.top();
+ states.top() = s_new;
+ --s_old->ref_count;
+ ++s_new->ref_count;
+ s_old->OnPause();
+ if (s_old->ref_count == 0) {
+ s_old->OnExit();
+ }
+ if (s_new->ref_count == 1) {
+ s_new->OnEnter();
+ }
+ s_new->OnResume();
+ return s_old;
+}
+
+State &Application::GetState() {
+ return *states.top();
+}
+
+bool Application::HasState() const noexcept {
+ return !states.empty();
+}
+
+
+void Application::Run() {
+ Uint32 last = SDL_GetTicks();
+ while (HasState()) {
+ Uint32 now = SDL_GetTicks();
+ int delta = now - last;
+ Loop(delta);
+ last = now;
+ }
+}
+
+void Application::Loop(int dt) {
+ HandleEvents();
+ if (!HasState()) return;
+ GetState().Update(dt);
+ if (!HasState()) return;
+ GetState().Render();
+}
+
+void Application::HandleEvents() {
+ SDL_Event event;
+ while (HasState() && SDL_PollEvent(&event)) {
+ GetState().Handle(event);
+ }
+}
+
+void State::Handle(const SDL_Event &event) {
+ switch (event.type) {
+ case SDL_WINDOWEVENT:
+ Handle(event.window);
+ break;
+ default:
+ OnEvent(event);
+ break;
+ }
+}
+
+void State::Handle(const SDL_WindowEvent &event) {
+ switch (event.event) {
+ case SDL_WINDOWEVENT_FOCUS_GAINED:
+ OnFocus();
+ break;
+ case SDL_WINDOWEVENT_FOCUS_LOST:
+ OnBlur();
+ break;
+ case SDL_WINDOWEVENT_RESIZED:
+ //env.viewport.Resize(event.data1, event.data2);
+ OnResize();
+ break;
+ default:
+ break;
+ }
+}
+
+void State::Update(int dt) {
+ OnUpdate(dt);
+}
+
+void State::Render() {
+ OnRender();
+}
+
+}
+}
}
namespace blobs {
+namespace app {
AlutError::AlutError(ALenum num)
: std::runtime_error(alutGetErrorString(num)) {
}
}
+}
namespace blobs {
+namespace app {
class AlutError
: public std::runtime_error {
};
+}
}
#endif
+#include "app/Application.hpp"
#include "app/init.hpp"
+#include "world/Planet.hpp"
#include <exception>
#include <iostream>
+
using namespace blobs;
int main(int argc, char *argv[]) {
- Init init;
+ app::Init init;
+ world::Planet planet(1); // r=1 should be a 3³
+
+ app::Application app;
}
--- /dev/null
+#ifndef BLOBS_WORLD_PLANET_HPP_
+#define BLOBS_WORLD_PLANET_HPP_
+
+#include "Tile.hpp"
+
+#include <cassert>
+#include <memory>
+
+
+namespace blobs {
+namespace world {
+
+struct Tile;
+
+/// A planet has six surfaces, numbered 0 to 5, each with tiles from
+/// +radius to -radius.
+class Planet {
+
+public:
+ explicit Planet(int radius);
+ ~Planet();
+
+ Planet(Planet &&);
+ Planet &operator =(Planet &&);
+
+ Planet(const Planet &) = delete;
+ Planet &operator =(const Planet &) = delete;
+
+public:
+ /// Get the tile at given surface and coordinates.
+ Tile &TileAt(int surface, int x, int y) {
+ return tiles[IndexOf(surface, x, y)];
+ }
+ const Tile &TileAt(int surface, int x, int y) const {
+ return tiles[IndexOf(surface, x, y)];
+ }
+
+ /// Convert coordinates into a tile index.
+ int IndexOf(int surface, int x, int y) const {
+ assert(0 <= surface && surface <= 5);
+ assert(-radius <= x && x <= radius);
+ assert(-radius <= y && y <= radius);
+ return surface * SurfaceArea() + ToOffset(y) * SideLength() + ToOffset(x);
+ }
+ /// Convert coordinate into offset
+ int ToOffset(int c) const {
+ return c + radius;
+ }
+ /// The "radius" of the planet.
+ int Radius() const {
+ return radius;
+ }
+ /// The length of the side of each surface.
+ int SideLength() const {
+ return 2 * radius + 1;
+ }
+ /// The area (or number of tiles) of one surface
+ int SurfaceArea() const {
+ return SideLength() * SideLength();
+ }
+ /// Total area of all surfaces combined.
+ int TotalArea() const {
+ return 6 * SurfaceArea();
+ }
+
+private:
+ int radius;
+ std::unique_ptr<Tile []> tiles;
+
+};
+
+void GenerateTest(Planet &);
+
+}
+}
+
+#endif
--- /dev/null
+#ifndef BLOBS_WORLD_TILE_HPP_
+#define BLOBS_WORLD_TILE_HPP_
+
+#include <cstdint>
+
+
+namespace blobs {
+namespace world {
+
+struct Tile {
+
+ std::uint16_t type;
+
+};
+
+}
+}
+
+#endif
--- /dev/null
+#include "Planet.hpp"
+#include "Tile.hpp"
+
+#include <algorithm>
+
+
+namespace blobs {
+namespace world {
+
+Planet::Planet(int radius)
+: radius(radius)
+, tiles(new Tile[TotalArea()]) {
+
+}
+
+Planet::~Planet() {
+}
+
+Planet::Planet(Planet &&other)
+: radius(other.radius)
+, tiles(other.tiles.release()) {
+}
+
+Planet &Planet::operator =(Planet &&other) {
+ radius = other.radius;
+ std::swap(tiles, other.tiles);
+ return *this;
+}
+
+
+void GenerateTest(Planet &p) {
+ for (int surface = 0; surface <= 5; ++surface) {
+ for (int y = -p.Radius(); y <= p.Radius(); ++y) {
+ for (int x = -p.Radius(); x <= p.Radius(); ++x) {
+ p.TileAt(surface, x, y).type = (x == 0) + (y == 0);
+ }
+ }
+ }
+}
+
+}
+}