#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 TILE_COLORS_LUT[] = { #define X(_0, _1, color) bo(color), #include "x/tile_types.inc" #undef X }; static constexpr uint32_t FLUID_COLORS_LUT[] = { #define X(_0, _1, color) bo(color), #include "x/fluid_types.inc" #undef X }; uint32_t Tile::get_color() const { return TILE_COLORS_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::Ti_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::Ti_Air: break; case Tile::Ti_Rock: break; case Tile::Ti_Sand: { const auto below = self.gs(x, y - 1); if (below.so == Tile::Ti_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::Ti_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::Ti_Air) switch (at0.fl) { case Tile::Fl_Nothing: break; case Tile::Fl_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::Fl_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; } } // Update for (_y = y0; _y <= y1; ++_y) { for (_x = x0; _x <= x1; ++_x) { simulate_sand_tile(*this, _x, _y); } } dirty_writeto.bl -= Pt(1, 1); dirty_writeto.tr += Pt(1, 1); dirty_writeto = rect_intersect(dirty_writeto, Rect(0, 0, width - 1, height - 1)); ++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 // }