diff options
author | Kae <80987908+Novaenia@users.noreply.github.com> | 2023-06-20 14:33:09 +1000 |
---|---|---|
committer | Kae <80987908+Novaenia@users.noreply.github.com> | 2023-06-20 14:33:09 +1000 |
commit | 6352e8e3196f78388b6c771073f9e03eaa612673 (patch) | |
tree | e23772f79a7fbc41bc9108951e9e136857484bf4 /source/core/StarRandomPoint.hpp | |
parent | 6741a057e5639280d85d0f88ba26f000baa58f61 (diff) |
everything everywhere
all at once
Diffstat (limited to 'source/core/StarRandomPoint.hpp')
-rw-r--r-- | source/core/StarRandomPoint.hpp | 79 |
1 files changed, 79 insertions, 0 deletions
diff --git a/source/core/StarRandomPoint.hpp b/source/core/StarRandomPoint.hpp new file mode 100644 index 0000000..ff7d354 --- /dev/null +++ b/source/core/StarRandomPoint.hpp @@ -0,0 +1,79 @@ +#ifndef STAR_RANDOM_POINT_HPP +#define STAR_RANDOM_POINT_HPP + +#include "StarRandom.hpp" +#include "StarPoly.hpp" +#include "StarTtlCache.hpp" + +namespace Star { + +// An "infinite" generator of points on a 2d plane, generated cell by cell with +// an upper and lower cell density range. Each point is generated in a +// predictable way sector by sector, as long as the generator function is +// predictable and uses the RandomSource in a predictable way. Useful for +// things like starfields, fields of debris, random object placement, etc. + +template <typename PointData> +class Random2dPointGenerator { +public: + typedef List<pair<Vec2F, PointData>> PointSet; + + Random2dPointGenerator(uint64_t seed, float cellSize, Vec2I const& densityRange); + + // Each point will in the area will be generated in a predictable order, and + // if the callback uses the RandomSource in a predictable way, will generate + // the same field for every call. + template <typename PointCallback> + PointSet generate(PolyF const& area, PointCallback callback); + +private: + HashTtlCache<Vec2F, PointSet> m_cache; + + uint64_t m_seed; + float m_cellSize; + Vec2I m_densityRange; +}; + +template <typename PointData> +inline Random2dPointGenerator<PointData>::Random2dPointGenerator(uint64_t seed, float cellSize, Vec2I const& densityRange) + : m_seed(seed), m_cellSize(cellSize), m_densityRange(densityRange) {} + +template <typename PointData> +template <typename PointCallback> +auto Random2dPointGenerator<PointData>::generate(PolyF const& area, PointCallback callback) -> PointSet { + auto bound = area.boundBox(); + int64_t sectorXMin = std::floor(bound.xMin() / m_cellSize); + int64_t sectorYMin = std::floor(bound.yMin() / m_cellSize); + int64_t sectorXMax = std::ceil(bound.xMax() / m_cellSize); + int64_t sectorYMax = std::ceil(bound.yMax() / m_cellSize); + + PointSet finalResult; + + for (int64_t x = sectorXMin; x <= sectorXMax; ++x) { + for (int64_t y = sectorYMin; y <= sectorYMax; ++y) { + auto sector = RectF::withSize({x * m_cellSize, y * m_cellSize}, Vec2F::filled(m_cellSize)); + if (!area.intersects(PolyF(sector))) + continue; + + finalResult.appendAll(m_cache.get(Vec2F(x, y), [&](Vec2F const&) { + PointSet sectorResult; + + RandomSource sectorRandomness(staticRandomU64(m_seed, x, y)); + + unsigned max = sectorRandomness.randInt(m_densityRange[0], m_densityRange[1]); + for (unsigned i = 0; i < max; ++i) { + Vec2F pointPos = Vec2F(x + sectorRandomness.randf(), y + sectorRandomness.randf()) * m_cellSize; + sectorResult.append(pair<Vec2F, PointData>(pointPos, callback(sectorRandomness))); + } + + return sectorResult; + })); + } + } + + return finalResult; +} + +} + +#endif |