From f66cf28c8b4d80122896c87dba8af74ea1872eba Mon Sep 17 00:00:00 2001 From: Paweł Redman Date: Tue, 17 Oct 2017 16:39:13 +0200 Subject: New vectors. Start refactoring to use it. --- src/common.hpp | 19 ++--- src/game.cpp | 1 + src/math.hpp | 231 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/procgen.cpp | 15 ++-- src/render.cpp | 4 +- src/world.cpp | 111 +++++++++++++++------------ 6 files changed, 309 insertions(+), 72 deletions(-) create mode 100644 src/math.hpp diff --git a/src/common.hpp b/src/common.hpp index f458190..75dd17d 100644 --- a/src/common.hpp +++ b/src/common.hpp @@ -6,6 +6,7 @@ #include #include #include +#include "math.hpp" namespace procgen { class prng_t { @@ -29,7 +30,7 @@ namespace procgen { ~perlin_noise_t(); void generate(prng_t *prng, size_t size); - float get(float x, float y, float scale); + float get(v2f_t x, float scale); }; } @@ -43,15 +44,8 @@ namespace world { 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; - }; + typedef vec_t sector_index_t; + typedef vec_t tile_index_t; class entity_t; @@ -70,7 +64,7 @@ namespace world { procgen::perlin_noise_t perlin; std::map sectors; - void generate_tile(ssize_t lx, ssize_t ly, tile_t *tile); + void generate_tile(tile_t *tile, tile_index_t index); void generate(sector_t *sector, sector_index_t index); public: @@ -81,6 +75,7 @@ namespace world { // FIXME: iterators instead of returning std::lists std::list get_sectors(sf::FloatRect rect); std::list get_entities(sf::FloatRect rect); + std::list get_render_entities(sf::FloatRect rect); void render(sf::RenderWindow *window); @@ -98,7 +93,7 @@ namespace world { size_t cookie = 0; public: - sf::FloatRect bounds; + sf::FloatRect bounds, render_bounds; void link(world_t *world); void unlink(); diff --git a/src/game.cpp b/src/game.cpp index 0b3e8d6..2af7736 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -34,6 +34,7 @@ void state_t::start(void) human.bounds.top = 0; human.bounds.width = 0.66f; human.bounds.height = 1.0f; + human.render_bounds = human.bounds; human.link(&world); } } diff --git a/src/math.hpp b/src/math.hpp new file mode 100644 index 0000000..b958092 --- /dev/null +++ b/src/math.hpp @@ -0,0 +1,231 @@ +template +class vec_t { + template + void load_from_args(void) + { + static_assert(index < N + 1, "too many elements in the initializer"); + static_assert(index > N - 1, "too few elements in the initializer"); + } + + template + void load_from_args(T first, U... rest) + { + v[index] = first; + load_from_args(rest...); + } + +public: + T v[N]; + + // Basic operations + + vec_t() = default; + + template + vec_t(T first, U... rest) + { + load_from_args<0>(first, rest...); + } + + template + vec_t(vec_t b) + { + for (size_t i = 0; i < N; i++) + v[i] = (T)b[i]; + } + + T& operator[](size_t i) + { + return v[i]; + } + + const T& operator[](size_t i) const + { + return v[i]; + } + + // Comparison + + friend bool operator==(const vec_t &a, const vec_t &b) + { + for (size_t i = 0; i < N; i++) + if (a[i] != b[i]) + return false; + + return true; + } + + // Good enough for maps or sets. + friend bool operator<(const vec_t &a, const vec_t &b) + { + for (size_t i = 0; i < N; i++) { + if (a[i] < b[i]) + return true; + else if (a[i] > b[i]) + return false; + } + + return false; + } + + // Arithmetics + + friend vec_t operator+(const vec_t &v) + { + return v; + } + + friend vec_t operator+(const vec_t &a, const vec_t &b) + { + vec_t r; + + for (size_t i = 0; i < N; i++) + r[i] = a[i] + b[i]; + + return r; + } + + friend vec_t &operator+=(vec_t &v, const vec_t &b) + { + for (size_t i = 0; i < N; i++) + v[i] += b[i]; + + return v; + } + + friend vec_t operator-(const vec_t &v) + { + return -1 * v; + } + + friend vec_t operator-(const vec_t &a, const vec_t &b) + { + vec_t r; + + for (size_t i = 0; i < N; i++) + r[i] = a[i] - b[i]; + + return r; + } + + friend vec_t &operator-=(vec_t &v, const vec_t &b) + { + for (size_t i = 0; i < N; i++) + v[i] -= b[i]; + + return v; + } + + friend T operator*(const vec_t &a, const vec_t &b) + { + T r = (T)0; + + for (size_t i = 0; i < N; i++) + r += a[i] * b[i]; + + return r; + } + + friend vec_t operator*(const vec_t &a, const T &b) + { + vec_t r; + + for (size_t i = 0; i < N; i++) + r[i] = a[i] * b; + + return r; + } + + friend vec_t operator*(const T &b, const vec_t &a) + { + return a * b; + } + + friend vec_t &operator*=(vec_t &v, const T &b) + { + for (size_t i = 0; i < N; i++) + v[i] *= b; + + return v; + } + + friend vec_t operator/(const vec_t &a, const T &b) + { + vec_t r; + + for (size_t i = 0; i < N; i++) + r[i] = a[i] / b; + + return r; + } + + friend vec_t operator/(const T &b, const vec_t &a) + { + return a / b; + } + + friend vec_t &operator/=(vec_t &v, const T &b) + { + for (size_t i = 0; i < N; i++) + v[i] /= b; + + return v; + } + + // Compatibility with SFML + + template + operator sf::Vector2() const + { + static_assert(N == 2, "conversion of vec_t with N != 2 to sf::Vector2"); + return sf::Vector2((U)v[0], (U)v[1]); + } + + template + vec_t(sf::Vector2 b) + { + static_assert(N == 2, "conversion of sf::Vector2 to vec_t with N != 2"); + v[0] = b.x; + v[1] = b.y; + } + + // Compatibility with iostream + + friend std::ostream& operator<<(std::ostream& stream, vec_t v) + { + stream << "("; + for (size_t i = 0; i < N; i++) { + if (i) + stream << ", "; + stream << v.v[i]; + } + stream << ")"; + + return stream; + } +}; + +// Shorthands +typedef vec_t v2f_t; +typedef vec_t v2d_t; + +template +class rect_t { +public: + vec_t a, b; + + rect_t() = default; + + rect_t(vec_t a_, vec_t b_) + { + a = a_; + b = b_; + } + + friend std::ostream& operator<<(std::ostream& stream, rect_t r) + { + stream << "(" << r.a << ", " << r.b << ")"; + return stream; + } +}; + diff --git a/src/procgen.cpp b/src/procgen.cpp index b5e1d6f..bfff2c4 100644 --- a/src/procgen.cpp +++ b/src/procgen.cpp @@ -35,7 +35,7 @@ void prng_t::unit_vec(float out[2]) void perlin_noise_t::generate(prng_t *prng, size_t size_) { if (table) - delete table; + delete[] table; size = size_; table = new float[size * size][2]; @@ -55,22 +55,21 @@ static float smooth_step(float x) return 3 * x * x - 2 * x * x * x; } -float perlin_noise_t::get(float x, float y, float scale) +float perlin_noise_t::get(v2f_t x, float scale) { size_t nx, ny, nx1, ny1; float s, t, a, b, c, d; x /= scale; - y /= scale; - nx = (ssize_t)floor(x) & (size - 1); - ny = (ssize_t)floor(y) & (size - 1); + nx = (ssize_t)floor(x[0]) & (size - 1); + ny = (ssize_t)floor(x[1]) & (size - 1); nx1 = (nx == size - 1 ? 0 : nx + 1); ny1 = (ny == size - 1 ? 0 : ny + 1); - s = smooth_step(x - floor(x)); - t = smooth_step(y - floor(y)); + s = smooth_step(x[0] - floor(x[0])); + t = smooth_step(x[1] - floor(x[1])); a = table_dot(nx, ny, -s, -t); b = table_dot(nx1, ny, -s + 1.0f, -t); @@ -82,7 +81,7 @@ float perlin_noise_t::get(float x, float y, float scale) perlin_noise_t::~perlin_noise_t() { - delete table; + delete[] table; } } // namespace procgen diff --git a/src/render.cpp b/src/render.cpp index ee2e5b2..0353f97 100644 --- a/src/render.cpp +++ b/src/render.cpp @@ -45,12 +45,12 @@ static void draw_sector(sf::RenderWindow *window, world::sector_t *sector) sector->bounds.left + x, sector->bounds.top + y, sector->tiles + y * SECTOR_SIZE + x); - if ((sector->index.x & 2) ^ (sector->index.y & 2)) { + /*if ((sector->index.x & 2) ^ (sector->index.y & 2)) { wot_rect.setSize(sf::Vector2f(SECTOR_SIZE, SECTOR_SIZE)); wot_rect.setPosition(sf::Vector2f(sector->bounds.left, sector->bounds.top)); wot_rect.setFillColor(sf::Color(0, 0, 0, 50)); window->draw(wot_rect); - } + }*/ } void interface::state_t::render() diff --git a/src/world.cpp b/src/world.cpp index d340cc1..06369f6 100644 --- a/src/world.cpp +++ b/src/world.cpp @@ -2,31 +2,10 @@ namespace world { -sector_index_t::sector_index_t () +sector_index_t sector_index_at(v2f_t x) { -} - -sector_index_t::sector_index_t (int64_t x_, int64_t y_) -{ - x = x_; - y = y_; -} - -sector_index_t::sector_index_t (float x_, float y_) -{ - x = (int64_t)floor(x_ / SECTOR_SIZE); - y = (int64_t)floor(y_ / SECTOR_SIZE); -} - -bool sector_index_t::operator<(sector_index_t B) const -{ - if (x < B.x) - return true; - if (x > B.x) - return false; - if (y < B.y) - return true; - return false; + return sector_index_t(floor(x[0] / SECTOR_SIZE), + floor(x[1] / SECTOR_SIZE)); } world_t::world_t(void) @@ -35,17 +14,17 @@ world_t::world_t(void) perlin.generate(&prng, 32); } -void world_t::generate_tile(ssize_t x, ssize_t y, tile_t *tile) +void world_t::generate_tile(tile_t *tile, tile_index_t x) { float waterlevel, height; - waterlevel = perlin.get(x, y, 1000.0f) * 0.3f + - perlin.get(x, y, 500.0f) * 0.1f; + waterlevel = perlin.get(x, 1000.0f) * 0.3f + + perlin.get(x, 500.0f) * 0.1f; - height = perlin.get(x, y, 60.0f) * 0.6f + - perlin.get(x, y, 30.0f) * 0.25f + - perlin.get(x, y, 14.0f) * 0.1f + - perlin.get(x, y, 6.0f) * 0.05f; + height = perlin.get(x, 60.0f) * 0.6f + + perlin.get(x, 30.0f) * 0.25f + + perlin.get(x, 14.0f) * 0.1f + + perlin.get(x, 6.0f) * 0.05f; if (height < waterlevel - 0.2f) tile->type = -1; @@ -54,7 +33,7 @@ void world_t::generate_tile(ssize_t x, ssize_t y, tile_t *tile) else if (height < waterlevel + 0.05f) tile->type = 1; else { - if (perlin.get(x, y, 5.0f) > 0.0f) + if (perlin.get(x, 5.0f) > 0.0f) tile->type = 3; else tile->type = 2; @@ -64,18 +43,18 @@ void world_t::generate_tile(ssize_t x, ssize_t y, tile_t *tile) void world_t::generate(sector_t *sector, sector_index_t index) { sector->index = index; - sector->bounds.left = index.x * SECTOR_SIZE; - sector->bounds.top = index.y * SECTOR_SIZE; + sector->bounds.left = index[0] * SECTOR_SIZE; + sector->bounds.top = index[1] * SECTOR_SIZE; sector->bounds.width = SECTOR_SIZE; sector->bounds.height = SECTOR_SIZE; - std::cout << "generating (" << index.x << ", " << index.y << ")\n"; + std::cout << "generating " << index << "\n"; for (ssize_t ly = 0; ly < SECTOR_SIZE; ly++) for (ssize_t lx = 0; lx < SECTOR_SIZE; lx++) - generate_tile(index.x * SECTOR_SIZE + lx, - index.y * SECTOR_SIZE + ly, - sector->tiles + ly * SECTOR_SIZE + lx); + generate_tile(sector->tiles + ly * SECTOR_SIZE + lx, + tile_index_t(index[0] * SECTOR_SIZE + lx, + index[1] * SECTOR_SIZE + ly)); sector->empty = false; } @@ -98,8 +77,8 @@ tile_t *world_t::get_tile(ssize_t x, ssize_t y) sector_t *sector; ssize_t tx, ty; - index.x = divide_rmi(x, (ssize_t)SECTOR_SIZE, &tx); - index.y = divide_rmi(y, (ssize_t)SECTOR_SIZE, &ty); + index[0] = divide_rmi(x, (ssize_t)SECTOR_SIZE, &tx); + index[1] = divide_rmi(y, (ssize_t)SECTOR_SIZE, &ty); sector = get_sector(index); return sector->tiles + ty * SECTOR_SIZE + tx; @@ -107,12 +86,14 @@ tile_t *world_t::get_tile(ssize_t x, ssize_t y) std::list world_t::get_sectors(sf::FloatRect rect) { - sector_index_t base(rect.left, rect.top), - upper(rect.left + rect.width, rect.top + rect.height); + sector_index_t base, upper; std::list list; - for (int64_t y = base.y; y <= upper.y; y++) - for (int64_t x = base.x; x <= upper.x; x++) { + base = sector_index_at(v2f_t(rect.left, rect.top)); + upper = sector_index_at(v2f_t(rect.left + rect.width, rect.top + rect.height)); + + for (int64_t y = base[1]; y <= upper[1]; y++) + for (int64_t x = base[0]; x <= upper[0]; x++) { sector_index_t index(x, y); list.push_back(get_sector(index)); } @@ -120,6 +101,29 @@ std::list world_t::get_sectors(sf::FloatRect rect) return list; } +std::list world_t::get_render_entities(sf::FloatRect rect) +{ + static size_t cookie = 0; + std::list list; + + cookie++; + + for (sector_t *sector : get_sectors(rect)) + for (entity_t *ent : sector->ents) { + if (ent->cookie == cookie) + continue; + + if (!rect.intersects(ent->render_bounds)) + continue; + + ent->cookie = cookie; + + list.push_back(ent); + } + + return list; +} + std::list world_t::get_entities(sf::FloatRect rect) { static size_t cookie = 0; @@ -145,8 +149,8 @@ std::list world_t::get_entities(sf::FloatRect rect) void world_t::debug_point(sf::Vector2f point) { - sector_index_t index(point.x, point.y); - printf("sector (%zd, %zd)\n", index.x, index.y); + sector_index_t index = sector_index_at(point); + printf("sector (%zd, %zd)\n", index[0], index[1]); } void entity_t::link_to_sector(sector_t *sector) @@ -157,17 +161,24 @@ void entity_t::link_to_sector(sector_t *sector) void entity_t::link(world_t *world) { + //sf::FloatRect total_bounds; float fx, fy; sector_index_t base; float xlip, ylip; size_t xsecs, ysecs; + // TODO + //total.bounds.left = std::min(bounds.left, render_bounds.left); + //total.bounds.top = std::min(bounds.top, render_bounds.top); + //total.bounds.width = std::max(bounds.width, render_bounds.width); + //total.bounds.height = std::max(bounds.height, render_bounds.height); + fx = floor(bounds.left); fy = floor(bounds.top); - base = sector_index_t(fx, fy); - xlip = bounds.left + bounds.width - (base.x + 1) * SECTOR_SIZE; - ylip = bounds.top + bounds.height - (base.y + 1) * SECTOR_SIZE; + base = sector_index_at(v2f_t(fx, fy)); + xlip = bounds.left + bounds.width - (base[0] + 1) * SECTOR_SIZE; + ylip = bounds.top + bounds.height - (base[1] + 1) * SECTOR_SIZE; if (xlip > 0.0f) xsecs = ceil(xlip / SECTOR_SIZE) + 1; @@ -181,7 +192,7 @@ void entity_t::link(world_t *world) for (int64_t y = 0; y < (int64_t)ysecs; y++) for (int64_t x = 0; x < (int64_t)xsecs; x++) { - sector_index_t index(base.x + x, base.y + y); + sector_index_t index = sector_index_at(v2f_t(base[0] + x, base[1] + y)); sector_t *sector; sector = world->get_sector(index); -- cgit