#include #include #include #include #include #include #include #include namespace procgen { class prng_t { uint32_t state = 0; public: void seed(uint32_t seed); uint32_t next(void); float next_float(void); void unit_vec(float out[2]); }; class perlin_noise_t { size_t size; float (*table)[2] = nullptr; float table_dot(size_t nx, size_t ny, float dx, float dy); public: ~perlin_noise_t(); void generate(prng_t *prng, size_t size); float get(float x, float y, float scale); }; } namespace world { #define SECTOR_SIZE 8 class tile_t { public: char type; }; class sector_index_t { public: int64_t x, y; sector_index_t (); sector_index_t (int64_t x_, int64_t y_); sector_index_t (float x_, float y_); bool operator<(sector_index_t B) const; }; class entity_t; class sector_t { public: sector_index_t index; sf::FloatRect bounds; std::unordered_set ents; bool empty = true; tile_t tiles[SECTOR_SIZE * SECTOR_SIZE]; }; class world_t { procgen::prng_t prng; procgen::perlin_noise_t perlin; std::map sectors; void generate_tile(ssize_t lx, ssize_t ly, tile_t *tile); void generate(sector_t *sector, sector_index_t index); public: world_t(void); sector_t *get_sector(sector_index_t index); tile_t *get_tile(ssize_t x, ssize_t y); // FIXME: iterators instead of returning std::lists std::list get_sectors(sf::FloatRect rect); std::list get_entities(sf::FloatRect rect); void render(sf::RenderWindow *window); void debug_point(sf::Vector2f point); }; class entity_t { world_t *parent_world; std::vector parents; void link_to_sector(sector_t *sector); protected: friend world_t; size_t cookie = 0; public: sf::FloatRect bounds; void link(world_t *world); void unlink(); virtual void render(sf::RenderWindow *window) = 0; }; } namespace game { class state_t { public: world::world_t world; void start(void); void tick(void); void render(sf::RenderWindow *window_); }; class human_t : public world::entity_t { public: void render(sf::RenderWindow *window); }; } namespace interface { class state_t { sf::RenderWindow *window; game::state_t *game; struct { sf::Vector2f center; int target_zoom = 3; float zoom = 3.0f; bool dragging = false; sf::Vector2f drag_ref; } camera; public: state_t(sf::RenderWindow *window_, game::state_t *game); void tick(void); void render(void); }; } // Divide and round to minus infinity. template T divide_rmi(T x, T y, T *rem) { T rv; if (x >= 0) { *rem = x % y; return x / y; } rv = (x + 1) / y - 1; *rem = x - rv * y; return rv; } // Linear interpolation. template T lerp(T a, T b, T x) { return a * (1 - x) + b * x; } // Bilinear interpolation. template T bilerp(T a, T b, T c, T d, T x, T y) { T ab, cd; ab = lerp(a, b, x); cd = lerp(c, d, x); return lerp(ab, cd, y); }