#include "sandbox.hpp" #include "common.hpp" #include #include // Copied from IM_COL32 #define COL_U32(r, g, b, a) (((uint32_t)(A) << IM_COL32_A_SHIFT) | ((uint32_t)(B) << IM_COL32_B_SHIFT) | ((uint32_t)(G) << IM_COL32_G_SHIFT) | ((uint32_t)(R) << IM_COL32_R_SHIFT)) // Correct byte order for this platform constexpr uint32_t bo(uint32_t n) { if (std::endian::native == std::endian::little) return std::byteswap(n); return n; } static constexpr uint32_t material_color_lut[] = { bo(0xffffff'ff), // AIR bo(0xababab'ff), // SOLID bo(0xe3dd24'ff), // SAND bo(0x435bf7'ff), // WATER }; uint32_t Tile::get_color() const { return material_color_lut[std::to_underlying(so)]; } Sandbox::Sandbox(int w, int h, RandomState rand) : bitmap(new uint32_t[w * h]) , tiles(new Tile[w * h]) , _rand(std::move(rand)) , _wall_tile{ Tile::ROCK } , width{ w } , height{ h } // { memset(bitmap, 0xff, (w * h) * sizeof(bitmap[0])); } Sandbox::~Sandbox() { delete[] bitmap; delete[] tiles; } static void simulate_sand_tile(Sandbox& self, int x, int y) { const auto at0 = self.gs(x, y); if (at0.updated) { return; } switch (at0.so) { case Tile::AIR: break; case Tile::ROCK: break; case Tile::SAND: { const auto below = self.gs(x, y - 1); if (below.so == Tile::AIR) { self.set_sand(x, y, below); self.set_sand(x, y - 1, at0); } else { Pt loc1[]{ Pt(x - 1, y - 1), Pt(x + 1, y - 1) }; auto bound = 2; auto which = self._rand.next_u32(bound); for (int i = 0; i < bound; ++i) { // Try going to a side auto at1 = self.gs(loc1[i].x, loc1[i].y); if (at1.so == Tile::AIR) { self.set_sand(x, y, at1); self.set_sand(loc1[i].x, loc1[i].y, at0); } which = (which + 1) % bound; } } } break; } if (at0.so == Tile::AIR) switch (at0.fl) { case Tile::NOTHING: break; case Tile::WATER: { // Pt neighs[]{ Pt(x - 1, y), Pt(x + 1, y), Pt(x, y + 1), Pt(x, y - 1) }; // int max_pressure = 0; // for (auto [x1, y1] : neighs) { // auto& neigh = self.gs(x1, y1); // if (neigh.fl == Tile::WATER) { // auto p = neigh.fmass; // max_pressure = max_pressure > p ? max_pressure : p; // } // } } break; } } void Sandbox::simulate_step() { dirty_curr = dirty_writeto; dirty_writeto = {}; const auto [x0, y0] = dirty_curr.bl; const auto [x1, y1] = dirty_curr.tr; // Clear update bit for this cycle for (_y = y0; _y <= y1; ++_y) { for (_x = x0; _x <= x1; ++_x) { gs(_x, _y).updated = false; } } for (_y = y0; _y <= y1; ++_y) { for (_x = x0; _x <= x1; ++_x) { simulate_sand_tile(*this, _x, _y); } } ++ncycle; } Tile& Sandbox::gs(int x, int y) { if (x < 0 || x >= width || y < 0 || y >= height) return _wall_tile; return tiles[y * width + x]; } void Sandbox::set_sand(int x, int y, Tile sand) { auto& target = tiles[y * width + x]; target = sand; // Set update bit if the target is after cursor if (y < _y || x > _x) target.updated = true; bitmap[y * width + x] = sand.get_color(); if (dirty_writeto == Rect()) dirty_writeto = Rect(x, y, x, y); else dirty_writeto = rect_union(dirty_writeto, Pt(x, y)); } // std::vector Sandbox::to_bitmap() const { // // TODO // }