aboutsummaryrefslogtreecommitdiff
path: root/src/sandbox.cpp
blob: ccfde52d76e65f440d9622a6a29012c57f93fabd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
#include "sandbox.hpp"
#include "common.hpp"

#include <cstring>
#include <utility>

// 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))

static constexpr uint32_t MAT_COLOR_LUT[] = {
    0xffffff'ff, // AIR
    0xababab'ff, // SOLID
    0xfffca8'ff, // SAND
    0x435bf7'ff, // WATER
};

uint32_t Tile::get_color() const {
    return MAT_COLOR_LUT[std::to_underlying(so)];
}

Sandbox::Sandbox(int w, int h)
    : _bitmap(w * h)
    , _a(w * h)
    // TODO random seed
    , _pcg()
    , _wall_tile{ Tile::ROCK }
    , width{ w }
    , height{ h } //
{
    memset(_bitmap.data(), 0xff, _bitmap.size() * sizeof(_bitmap[0]));
    set_sand(10, 80, Tile{ .so = Tile::SAND });
}

static void simulate_sand_tile(Sandbox& self, int x, int y) {
    const auto at0 = self.gs(x, y);
    if (at0.updated) {
        // Clear update bit for next cycle
        self.gs(x, y).updated = false;
        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._pcg.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() {
    _x = 0;
    _y = height ;
    for (; _y >= 0; --_y) {
        for (; _x < width; ++_x) {
            simulate_sand_tile(*this, _x, _y);
        }
        _x = 0;
    }
    ++ncycle;
}

Tile& Sandbox::gs(int x, int y) {
    if (x < 0 || x >= width || y < 0 || y >= height)
        return _wall_tile;
    return _a[y * width + x];
}

void Sandbox::set_sand(int x, int y, Tile sand) {
    auto& target = _a[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();
}

// std::vector<uint32_t> Sandbox::to_bitmap() const {
//     // TODO
// }