diff --git a/Makefile b/Makefile index bbbafe8..6beccab 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,16 @@ -all: - g++ -fsanitize=address -c particles.cpp -lSDL2 -g -o particles.o - g++ -fsanitize=address -c game.cpp -lSDL2 -g -o game.o - g++ -fsanitize=address -lSDL2 -g particles.o game.o -o main +test: + $(CXX) -fsanitize=address -c particles.cpp -lSDL2 -g -o particles.o + $(CXX) -fsanitize=address -c game.cpp -lSDL2 -g -o game.o + $(CXX) -fsanitize=address -lSDL2 -g particles.o game.o -o main + +pub: + $(CXX) -O2 -c particles.cpp -lSDL2 -o particles.o + $(CXX) -O2 -c game.cpp -lSDL2 -o game.o + $(CXX) -O2 -lSDL2 particles.o game.o -o main + + +web: + $(CXX) -O2 -lSDL2 -s USE_SDL=2 particles.cpp game.cpp -o index.html --shell-file shell_minimal.html -s ALLOW_MEMORY_GROWTH=1 + diff --git a/game.cpp b/game.cpp index a2306fc..aacd4e0 100644 --- a/game.cpp +++ b/game.cpp @@ -1,3 +1,4 @@ +#include #include #include #include @@ -5,236 +6,281 @@ #include #include #include -#include -#include -#include #include #include +#include #include +#ifdef __EMSCRIPTEN__ +#include +#include +#endif #include "particles.h" namespace pengine { class GameWindow { - private: - struct SDL_Window *window; - std::string name; - public: - struct SDL_Renderer *renderer; - - GameWindow(int width, int height, std::string name) { - SDL_Init(SDL_INIT_EVERYTHING); - this->name = name; - window = SDL_CreateWindow(name.c_str(), - SDL_WINDOWPOS_CENTERED, - SDL_WINDOWPOS_CENTERED, - width, height, - SDL_WINDOW_RESIZABLE); - renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED - | SDL_RENDERER_PRESENTVSYNC); - } - - ~GameWindow() { - SDL_DestroyRenderer(renderer); - SDL_DestroyWindow(window); - SDL_Quit(); - } - +private: + std::string name; + +public: + struct SDL_Window *window; + struct SDL_Renderer *renderer; + + GameWindow(int width, int height, std::string name) { + SDL_Init(SDL_INIT_VIDEO); + this->name = name; + // SDL_SetHint(SDL_HINT_EMSCRIPTEN_KEYBOARD_ELEMENT, "#canvas"); + window = SDL_CreateWindow(name.c_str(), SDL_WINDOWPOS_CENTERED, + SDL_WINDOWPOS_CENTERED, width, height, + SDL_WINDOW_BORDERLESS); + renderer = SDL_CreateRenderer( + window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC); + } + + ~GameWindow() { + SDL_DestroyRenderer(renderer); + SDL_DestroyWindow(window); + SDL_Quit(); + } }; +enum MouseAction { NONE, LEFT, RIGHT }; + class PaintTool { - public: - int particle_selected = 0; - int size = 1; - int mouse_state = 0; - bool paused = false; +public: + int particle_selected = 0; + int size = 1; + MouseAction mouse_state = NONE; + bool paused = false; }; - class Game { - GameWindow win; - Grid grid; - SDL_Texture *grid_texture; - SDL_Renderer *ren; - int internal_sz[2]; - int window_sz[2]; - struct su_pair {int x; int y;} coord; - - std::vectorparticles = std::vector(); - PaintTool tool = PaintTool(); - - public: - - Game(int x, int y, int gx, int gy): - win{GameWindow {x,y,"game"}}, - grid{Grid{gx, gy}} - { - ren = win.renderer; - - /* texture for drawing particles into */ - grid_texture = SDL_CreateTexture(ren, SDL_PIXELFORMAT_ARGB8888, - SDL_TEXTUREACCESS_STATIC, gx,gy); - - internal_sz[0] = gx; - internal_sz[1] = gy; - window_sz[0] = x; - window_sz[1] = y; - - particles.push_back(new Sand()); - particles.push_back(new Water()); - particles.push_back(new Steam()); - particles.push_back(new Lava()); - + GameWindow win; + Grid grid; + SDL_Texture *grid_texture; + SDL_Renderer *ren; + int internal_sz[2]; + int window_sz[2]; + struct su_pair { + int x; + int y; + } coord; + + std::vector particles = std::vector(); + PaintTool tool = PaintTool(); + +public: + Game(int x, int y, int gx, int gy) + : win{GameWindow{x, y, "sand"}}, grid{Grid{gx, gy}} { + ren = win.renderer; + + /* texture for drawing particles into */ + grid_texture = SDL_CreateTexture(ren, SDL_PIXELFORMAT_ARGB8888, + SDL_TEXTUREACCESS_STATIC, gx, gy); + + internal_sz[0] = gx; + internal_sz[1] = gy; + window_sz[0] = x; + window_sz[1] = y; + + particles.push_back(new Sand()); + particles.push_back(new Water()); + particles.push_back(new Steam()); + particles.push_back(new Lava()); + } + + ~Game() { + SDL_DestroyTexture(grid_texture); + for (auto p : particles) { + delete p; + } + } + + void update() { grid.update(); } + + void draw_tool() { + if (tool.size == 1) { + int i = coord.x; + int j = coord.y; + if (grid.inside_grid(i, j)) { + auto colour = PixelColour(grid.pixels[i + j * grid.xsize]); + colour.r = 255 - colour.r; + colour.g = 255 - colour.g; + colour.b = 255 - colour.b; + grid.pixels[i + j * grid.xsize] = colour.get_pixelcol(); + } + return; } - ~Game() { - SDL_DestroyTexture(grid_texture); - for (auto p : particles) { - delete p; + for (int i = coord.x - tool.size / 2; i < coord.x + tool.size / 2; i++) { + for (int j = coord.y - tool.size / 2; j < coord.y + tool.size / 2; j++) { + if (grid.inside_grid(i, j)) { + auto colour = PixelColour(grid.pixels[i + j * grid.xsize]); + colour.r = 255 - colour.r; + colour.g = 255 - colour.g; + colour.b = 255 - colour.b; + grid.pixels[i + j * grid.xsize] = colour.get_pixelcol(); } + } } - - void update() { - grid.update(); + } + + void remove_particles() { + if (tool.size <= 1) { + if (grid.inside_grid(coord.x, coord.y)) { + grid.erase_particle_at(coord.x, coord.y); + } + return; } - void draw_tool() { - if (tool.size == 1) { - int i = coord.x; - int j = coord.y; - if (grid.inside_grid(i, j)) { - auto colour = PixelColour(grid.pixels[i + j * grid.xsize]); - colour.r = 255 - colour.r; - colour.g = 255 - colour.g; - colour.b = 255 - colour.b; - grid.pixels[i + j * grid.xsize] = colour.get_pixelcol(); - } - return; + for (int i = coord.x - tool.size / 2; i < coord.x + tool.size / 2; i++) { + for (int j = coord.y - tool.size / 2; j < coord.y + tool.size / 2; j++) { + if (grid.inside_grid(i, j)) { + grid.erase_particle_at(i, j); } + } + } + } + + void add_particles() { + if (tool.size <= 1) { + if (grid.inside_grid(coord.x, coord.y)) { + grid.add_particle_at(coord.x, coord.y, + particles[tool.particle_selected]->id); + } + return; + } - for (int i = coord.x - tool.size / 2; i < coord.x + tool.size / 2; i++) { - for (int j = coord.y - tool.size / 2; j < coord.y + tool.size / 2; j++) { - if (grid.inside_grid(i, j)) { - auto colour = PixelColour(grid.pixels[i + j * grid.xsize]); - colour.r = 255 - colour.r; - colour.g = 255 - colour.g; - colour.b = 255 - colour.b; - grid.pixels[i + j * grid.xsize] = colour.get_pixelcol(); - } - } + for (int i = coord.x - tool.size / 2; i < coord.x + tool.size / 2; i++) { + for (int j = coord.y - tool.size / 2; j < coord.y + tool.size / 2; j++) { + if (grid.inside_grid(i, j)) { + grid.add_particle_at(i, j, particles[tool.particle_selected]->id); } + } } - - void add_particles() { - if (tool.size <= 1) { - if (grid.inside_grid(coord.x, coord.y)) { - grid.add_particle_at(coord.x, coord.y, - particles[tool.particle_selected]->id); - } - return; + } + + void draw() { + SDL_SetRenderDrawColor(ren, 40, 40, 40, 255); + + SDL_RenderClear(ren); + + grid.update_texture(); + draw_tool(); + + SDL_UpdateTexture(grid_texture, NULL, grid.pixels, + grid.xsize * sizeof(Uint32)); + SDL_RenderCopy(ren, grid_texture, NULL, NULL); + SDL_RenderPresent(ren); + } + + struct su_pair get_click_location_in_grid(int x, int y) { + struct su_pair p; + p.x = (internal_sz[0] * x / window_sz[0]) % internal_sz[0]; + p.y = (internal_sz[1] * y / window_sz[1]) % internal_sz[1]; + return p; + } + + bool run() { + SDL_Event event; + while (SDL_PollEvent(&event)) { + switch (event.type) { + case SDL_QUIT: + return true; + case SDL_WINDOWEVENT_RESIZED: + SDL_GetWindowSize(win.window, internal_sz, internal_sz + 1); + break; + case SDL_KEYDOWN: + + if (event.key.keysym.scancode == SDL_SCANCODE_ESCAPE) { + tool.paused = !tool.paused; } - - for (int i = coord.x - tool.size / 2; i < coord.x + tool.size / 2; i++) { - for (int j = coord.y - tool.size / 2; j < coord.y + tool.size / 2; j++) { - if (grid.inside_grid(i, j)) { - grid.add_particle_at(i, j, particles[tool.particle_selected]->id); - } - } + if (event.key.keysym.scancode == SDL_SCANCODE_P) { + tool.paused = !tool.paused; + } + if (event.key.keysym.scancode == SDL_SCANCODE_C) { + grid.clear(); } + if (event.key.keysym.scancode == SDL_SCANCODE_1) { + tool.particle_selected = 0; + }; + if (event.key.keysym.scancode == SDL_SCANCODE_2) { + tool.particle_selected = 1; + }; + if (event.key.keysym.scancode == SDL_SCANCODE_3) { + tool.particle_selected = 2; + }; + if (event.key.keysym.scancode == SDL_SCANCODE_4) { + tool.particle_selected = 3; + }; + + break; + case SDL_MOUSEMOTION: + coord = get_click_location_in_grid(event.motion.x, event.motion.y); + break; + case SDL_KEYUP: + break; + case SDL_MOUSEBUTTONDOWN: + if (event.button.button == 1) { + tool.mouse_state = LEFT; + } else if (event.button.button == 3) { + tool.mouse_state = RIGHT; + } + break; + case SDL_MOUSEBUTTONUP: + tool.mouse_state = NONE; + break; + case SDL_MOUSEWHEEL: + tool.size += event.wheel.y; + break; + } } - - void draw() { - SDL_SetRenderDrawColor(ren, 40, 40, 40, 255); - SDL_RenderClear(ren); - - grid.update_texture(); - draw_tool(); - - SDL_UpdateTexture(grid_texture, NULL, grid.pixels, grid.xsize * sizeof(Uint32)); - SDL_RenderCopy(ren, grid_texture, NULL, NULL); - SDL_RenderPresent(ren); + if (tool.mouse_state == LEFT) { + add_particles(); + } else if (tool.mouse_state == RIGHT) { + remove_particles(); } - - struct su_pair get_click_location_in_grid(int x, int y) { - struct su_pair p; - p.x = (internal_sz[0] * x/window_sz[0]) % internal_sz[0]; - p.y = (internal_sz[1] * y / window_sz[1]) % internal_sz[1]; - return p; - } - - void run() { - while (true) { - SDL_Event event; - while(SDL_PollEvent(&event)) { - switch (event.type) { - case SDL_QUIT: - return; - case SDL_KEYDOWN: - - if (event.key.keysym.scancode == SDL_SCANCODE_ESCAPE) { - tool.paused = !tool.paused; - } - - if (event.key.keysym.scancode == SDL_SCANCODE_1) { - tool.particle_selected = 0; - }; - if (event.key.keysym.scancode == SDL_SCANCODE_2) { - tool.particle_selected = 1; - }; - if (event.key.keysym.scancode == SDL_SCANCODE_3) { - tool.particle_selected = 2; - }; - if (event.key.keysym.scancode == SDL_SCANCODE_4) { - tool.particle_selected = 3; - }; - - break; - case SDL_MOUSEMOTION: - coord = get_click_location_in_grid(event.motion.x, event.motion.y); - break; - case SDL_KEYUP: - break; - case SDL_MOUSEBUTTONDOWN: - tool.mouse_state = 1; - break; - case SDL_MOUSEBUTTONUP: - tool.mouse_state = 0; - break; - case SDL_MOUSEWHEEL: - tool.size += event.wheel.y; - break; - } - } - - if (tool.mouse_state) { - add_particles(); - } - - if (!tool.paused) { - update(); - } - - draw(); - } + if (!tool.paused) { + update(); } + draw(); + return false; + } }; -} +} // namespace pengine -int main(int argc, char **argv) { +pengine::Game *g_game; +void main_loop() { g_game->run(); } - const char *error = SDL_GetError(); - if (error) { - std::cout << error; - } - - pengine::Game game {pengine::Game(500,500, 80,80)}; - game.run(); +int main(int argc, char **argv) { - return 0; + const char *error = SDL_GetError(); + if (error) { + std::cout << error; + } + bool quit = false; + + int x = 500; + int y = 500; +#ifdef __EMSCRIPTEN__ + EMSCRIPTEN_RESULT res = emscripten_get_canvas_element_size("#canvas", &x, &y); +#endif + + pengine::Game game{pengine::Game(x, y, x, y)}; + g_game = &game; + +#ifdef __EMSCRIPTEN__ + emscripten_set_main_loop(main_loop, 0, true); +#else + while (!quit) { + quit = game.run(); + } +#endif + + return 0; } - diff --git a/particles.cpp b/particles.cpp index f5c1455..ed64516 100644 --- a/particles.cpp +++ b/particles.cpp @@ -3,514 +3,506 @@ namespace pengine { - Uint8 part_colours[][3] = { - {255,255,255}, // BASIC - {252,250,148}, // SAND - {70,90,255}, // WATER - {200,220,255}, // STEAM - {200,20,20}, // LAVA - {140,111,71}, // ROCK - {200,20,20}, // LIQUID QUARTZ - {20,80,40}, // QUARTZ - }; - - std::string part_names[] = { - "default", - "Sand", - "Water", - "Steam", - "Lava", - "Rock" - }; - - struct particle_data BasicParticle::default_data(ParticleID id) - { - struct particle_data datap; - switch (id) { - case ParticleID::WATER: - datap = {.density=10, - .liquid = true, - .temperature=20, - .boiling_point = 100, - .gas_state = ParticleID::STEAM - }; - break; - case ParticleID::LAVA: - datap = {.density=20, .liquid = true, .temperature=5000, - .boiling_point = 10000,.freezing_point=200, .solid_state=ParticleID::ROCK}; - break; - case ParticleID::STEAM: - datap = {.density=0, .liquid = false, .temperature=150, - .liquid_state = ParticleID::WATER}; - break; - case ParticleID::SAND: - datap = {.density=100, .liquid = false, .temperature=20}; - break; - case ParticleID::ROCK: - datap = {.density=150, .liquid = false, .temperature=20, - .melting_point = 700, .liquid_state=ParticleID::LAVA}; - break; - default: - datap = {.temperature = 0}; - break; - } - return datap; - } - - BasicParticle::BasicParticle(ParticleID id) : Particle(id) - { - this->id = id; - data = default_data(id); - }; - - - State - BasicParticle::get_state() - { - switch(id) { - case (ParticleID::STEAM): - return State::GAS; - - case (ParticleID::WATER): - case (ParticleID::LAVA): - return State::LIQUID; - - case (ParticleID::ROCK): - case (ParticleID::SAND): - return State::SOLID; - default: - return State::SOLID; - } - } - - Particle * - get_new_particle(ParticleID p) - { - - switch (p) { - case ParticleID::SAND: - return new Sand(); - case ParticleID::WATER: - return new Water(); - case ParticleID::BASIC: - return new BasicParticle(); - case ParticleID::STEAM: - return new Steam(); - case ParticleID::LAVA: - return new Lava(); - case ParticleID::ROCK: - return new Rock(); - default: - std::cout << "Unknown particle create\n"; - throw "unknown particle"; - } - } - - - PixelColour::PixelColour(short r, short g, short b, short a) { - this->r = r; - this->g = g; - this->b = b; - this->a = a; - } - - PixelColour::PixelColour(Uint32 c) { - pixel = c; - } +Uint8 part_colours[][3] = { + {255, 255, 255}, // BASIC + {252, 250, 148}, // SAND + {70, 90, 255}, // WATER + {200, 220, 255}, // STEAM + {200, 20, 20}, // LAVA + {140, 111, 71}, // ROCK + {200, 20, 20}, // LIQUID QUARTZ + {20, 80, 40}, // QUARTZ +}; + +std::string part_names[] = {"default", "Sand", "Water", + "Steam", "Lava", "Rock"}; + +struct particle_data BasicParticle::default_data(ParticleID id) { + struct particle_data datap; + switch (id) { + case ParticleID::WATER: + datap = {.density = 10, + .liquid = true, + .temperature = 20, + .boiling_point = 100, + .gas_state = ParticleID::STEAM}; + break; + case ParticleID::LAVA: + datap = {.density = 20, + .liquid = true, + .temperature = 5000, + .boiling_point = 10000, + .freezing_point = 200, + .solid_state = ParticleID::ROCK}; + break; + case ParticleID::STEAM: + datap = {.density = 0, + .liquid = false, + .temperature = 150, + .liquid_state = ParticleID::WATER}; + break; + case ParticleID::SAND: + datap = {.density = 100, .liquid = false, .temperature = 20}; + break; + case ParticleID::ROCK: + datap = {.density = 150, + .liquid = false, + .temperature = 20, + .melting_point = 700, + .liquid_state = ParticleID::LAVA}; + break; + default: + datap = {.temperature = 0}; + break; + } + return datap; +} - PixelColour::PixelColour(short r, short g, short b) { - this->r = r; - this->g = g; - this->b = b; - this->a = 255; - } +BasicParticle::BasicParticle(ParticleID id) : Particle(id) { + this->id = id; + data = default_data(id); +}; + +State BasicParticle::get_state() { + switch (id) { + case (ParticleID::STEAM): + return State::GAS; + + case (ParticleID::WATER): + case (ParticleID::LAVA): + return State::LIQUID; + + case (ParticleID::ROCK): + case (ParticleID::SAND): + return State::SOLID; + default: + return State::SOLID; + } +} - PixelColour::PixelColour(SDL_Color c) { - this->r = c.r; - this->g = c.g; - this->b = c.b; - this->a = c.a; - } +Particle *get_new_particle(ParticleID p) { + + switch (p) { + case ParticleID::SAND: + return new Sand(); + case ParticleID::WATER: + return new Water(); + case ParticleID::BASIC: + return new BasicParticle(); + case ParticleID::STEAM: + return new Steam(); + case ParticleID::LAVA: + return new Lava(); + case ParticleID::ROCK: + return new Rock(); + default: + std::cout << "Unknown particle create\n"; + throw "unknown particle"; + } +} - PixelColour::PixelColour(const Uint8 p[3]) : PixelColour (p[0], p[1], p[2]) {} +PixelColour::PixelColour(short r, short g, short b, short a) { + this->r = r; + this->g = g; + this->b = b; + this->a = a; +} +PixelColour::PixelColour(Uint32 c) { pixel = c; } - SDL_Color PixelColour::get_sdlcol() { - SDL_Color c; - c.r = r; - c.b = b; - c.g = g; - c.a = a; - return c; - } +PixelColour::PixelColour(short r, short g, short b) { + this->r = r; + this->g = g; + this->b = b; + this->a = 255; +} - Uint32 PixelColour::get_pixelcol() { - return pixel; - } +PixelColour::PixelColour(SDL_Color c) { + this->r = c.r; + this->g = c.g; + this->b = c.b; + this->a = c.a; +} - Grid::Grid(int xs, int ys) { - xsize = xs; - ysize = ys; +PixelColour::PixelColour(const Uint8 p[3]) : PixelColour(p[0], p[1], p[2]) {} - grid = new Particle *[xs * ys] {}; - pixels = new Uint32[xs * ys] {}; +SDL_Color PixelColour::get_sdlcol() { + SDL_Color c; + c.r = r; + c.b = b; + c.g = g; + c.a = a; + return c; +} - for (int i = 0; i < xs * ys; i++) { - grid[i] = 0; - pixels[i] = 0; - } - } +Uint32 PixelColour::get_pixelcol() { return pixel; } - Grid::~Grid() - { - for (int i = 0; i < xsize * ysize; i++) { - if (grid[i]) - delete grid[i]; - } - delete[] grid; - delete[] pixels; - } +Grid::Grid(int xs, int ys) { + xsize = xs; + ysize = ys; - void Grid::update() - { - static bool updated = false; - bool done = true; - - while (done) { - done = false; - - for (int i = 0; i < xsize; i++) { - for (int j = 0; j < ysize; j++) { - int p = j * xsize + i; - if (grid[p]) { - if (grid[p]->updated != updated) { - grid[p]->updated = updated; - grid[p]->update(this, i, j); - done = true; - } - } - } - } - } + grid = new Particle *[xs * ys] {}; + pixels = new Uint32[xs * ys]{}; - updated = !updated; + clear(); +} - } +Grid::~Grid() { + for (int i = 0; i < xsize * ysize; i++) { + if (grid[i]) + delete grid[i]; + } + delete[] grid; + delete[] pixels; +} +Grid &Grid::operator=(Grid o) { + xsize = o.xsize; + ysize = o.ysize; - void Grid::add_particle_at(int x, int y, ParticleID p) - { - if (x >= xsize || y >= ysize || x < 0 || y < 0) { - std::cout << "invalid position " << x << " " << y << std::endl; - throw "invalid boundaries"; - } - - if (grid[x + y * xsize]) { - return; - } + grid = new Particle *[xsize * ysize] {}; + pixels = new Uint32[xsize * ysize]{}; - grid[x + y * xsize] = get_new_particle(p); - } + for (int i = 0; i < xsize * ysize; i++) { + grid[i] = o.grid[i]; + pixels[i] = o.pixels[i]; + } + return *this; +} - Particle * Grid::get_particle(int x, int y) { - if (!inside_grid(x,y)) { - return nullptr; - } +void Grid::clear() { + for (int i = 0; i < xsize * ysize; i++) { + grid[i] = 0; + pixels[i] = 0; + } +} - return grid[x + xsize * y]; - } +void Grid::update() { + static bool updated = false; + bool done = true; - void Grid::update_texture() { - PixelColour defaultcol = PixelColour(0,0,0,0); - for (int i = 0; i < xsize; i++) { - for (int j = 0; j < ysize; j++) { - int p = j * xsize + i; - if (grid[p] != nullptr) { -//:w pixels[p] = defaultcoll.pixel; - pixels[p] = grid[p]->get_colour().get_pixelcol(); - } else { - pixels[p] = defaultcol.get_pixelcol(); - } - } - } - } + while (done) { + done = false; - bool Grid::inside_grid(int x, int y) { - if (x >= xsize || y >= ysize || x < 0 || y < 0) { - return false; + for (int i = 0; i < xsize; i++) { + for (int j = 0; j < ysize; j++) { + int p = j * xsize + i; + if (grid[p]) { + if (grid[p]->updated != updated) { + grid[p]->updated = updated; + grid[p]->update(this, i, j); + done = true; + } } - - return true; + } } + } - bool Grid::move_particle(int xa, int ya, int xb, int yb) { + updated = !updated; +} - if (!inside_grid(xb, yb)) { - return false; - } +void Grid::erase_particle_at(int x, int y) { + if (x >= xsize || y >= ysize || x < 0 || y < 0) { + std::cout << "invalid position " << x << " " << y << std::endl; + throw "invalid boundaries"; + } - if (!inside_grid(xa, ya)) { - return false; - } + grid[x + y * xsize] = 0; +} - if ((get_particle(xa,ya) != nullptr) && (get_particle(xb,yb) == nullptr)) { - grid[xb + yb * xsize] = grid[xa + ya * xsize]; - grid[xa + ya * xsize] = nullptr; - return true; - } - return false; - } +void Grid::add_particle_at(int x, int y, ParticleID p) { + if (x >= xsize || y >= ysize || x < 0 || y < 0) { + std::cout << "invalid position " << x << " " << y << std::endl; + throw "invalid boundaries"; + } - int Grid::swap_particle(int xa, int ya, int xb, int yb) { + if (grid[x + y * xsize]) { + return; + } - if (!inside_grid(xb, yb)) { - return 0; - } + grid[x + y * xsize] = get_new_particle(p); +} - if (!inside_grid(xa, ya)) { - return 0; - } +Particle *Grid::get_particle(int x, int y) { + if (!inside_grid(x, y)) { + return nullptr; + } - int num = 0; - if (get_particle(xa,ya) != nullptr) { - num++; - } - if (get_particle(xb,yb) != nullptr) { - num++; - } + return grid[x + xsize * y]; +} - if (num > 0) { - Particle *temp = grid[xb + yb * xsize]; - grid[xb + yb * xsize] = grid[xa + ya * xsize]; - grid[xa + ya * xsize] = temp; - return num; - } - return 0; +void Grid::update_texture() { + PixelColour defaultcol = PixelColour(0, 0, 0, 0); + for (int i = 0; i < xsize; i++) { + for (int j = 0; j < ysize; j++) { + int p = j * xsize + i; + if (grid[p] != nullptr) { + //: w pixels[p] = defaultcoll.pixel; + pixels[p] = grid[p]->get_colour().get_pixelcol(); + } else { + pixels[p] = defaultcol.get_pixelcol(); + } } + } +} +bool Grid::inside_grid(int x, int y) { + if (x >= xsize || y >= ysize || x < 0 || y < 0) { + return false; + } - void Grid::replace_particle(int x, int y, Particle *new_particle) { - auto p = get_particle(x, y); - - if (!p) { - return; - } + return true; +} - delete p; +bool Grid::move_particle(int xa, int ya, int xb, int yb) { - grid[x + y * xsize] = new_particle; - } + if (!inside_grid(xb, yb)) { + return false; + } + if (!inside_grid(xa, ya)) { + return false; + } + if ((get_particle(xa, ya) != nullptr) && (get_particle(xb, yb) == nullptr)) { + grid[xb + yb * xsize] = grid[xa + ya * xsize]; + grid[xa + ya * xsize] = nullptr; + return true; + } + return false; +} - void Sand::update(Grid * const g, int x, int y) { +int Grid::swap_particle(int xa, int ya, int xb, int yb) { + + if (!inside_grid(xb, yb)) { + return 0; + } + + if (!inside_grid(xa, ya)) { + return 0; + } + + int num = 0; + if (get_particle(xa, ya) != nullptr) { + num++; + } + if (get_particle(xb, yb) != nullptr) { + num++; + } + + if (num > 0) { + Particle *temp = grid[xb + yb * xsize]; + grid[xb + yb * xsize] = grid[xa + ya * xsize]; + grid[xa + ya * xsize] = temp; + return num; + } + return 0; +} - if (update_temperature(g, x, y)) { - return; - } +void Grid::replace_particle(int x, int y, Particle *new_particle) { + auto p = get_particle(x, y); - Particle *p; - if(g->move_particle(x, y, x, y+1)) { - return; - } - if (g->move_particle(x, y, x-1, y+1)) { - return; - } - if (g->move_particle(x, y, x+1, y+1)) { - return; - } + if (!p) { + return; + } - p = g->get_particle(x, y+1); - if (p != nullptr) { - if (p->data.density < data.density || p->data.liquid) { - g->swap_particle(x, y, x, y+1); - return; - } - } else { - if (g->swap_particle(x, y, x, y+1)) { - return; - } - } + delete p; - p = g->get_particle(x-1, y+1); - if (p != nullptr) { - if (p->data.density < data.density || p->data.liquid) { - g->swap_particle(x, y, x-1, y+1); - return; - } - } else { - if - (g->swap_particle(x, y, x-1, y+1)) - return; - } - - p = g->get_particle(x+1, y+1); - if (p != nullptr) { - if (p->data.density < data.density || p->data.liquid) { - g->swap_particle(x, y, x+1, y+1); - return; - } - } else { - if (g->swap_particle(x, y, x+1, y+1)) - return; - } + grid[x + y * xsize] = new_particle; +} +void Sand::update(Grid *const g, int x, int y) { + + if (update_temperature(g, x, y)) { + return; + } + + Particle *p; + if (g->move_particle(x, y, x, y + 1)) { + return; + } + if (g->move_particle(x, y, x - 1, y + 1)) { + return; + } + if (g->move_particle(x, y, x + 1, y + 1)) { + return; + } + + p = g->get_particle(x, y + 1); + if (p != nullptr) { + if (p->data.density < data.density || p->data.liquid) { + g->swap_particle(x, y, x, y + 1); + return; } - - BasicParticle::BasicParticle() : Particle(ParticleID::BASIC) {} - - - void BasicParticle::update(Grid * const g, int x, int y) { - return; + } else { + if (g->swap_particle(x, y, x, y + 1)) { + return; } + } - PixelColour BasicParticle::get_colour() { - return PixelColour {part_colours[((int)this->id)]}; + p = g->get_particle(x - 1, y + 1); + if (p != nullptr) { + if (p->data.density < data.density || p->data.liquid) { + g->swap_particle(x, y, x - 1, y + 1); + return; } - - std::string BasicParticle::get_name() { - return part_names[((int)this->id)]; + } else { + if (g->swap_particle(x, y, x - 1, y + 1)) + return; + } + + p = g->get_particle(x + 1, y + 1); + if (p != nullptr) { + if (p->data.density < data.density || p->data.liquid) { + g->swap_particle(x, y, x + 1, y + 1); + return; } + } else { + if (g->swap_particle(x, y, x + 1, y + 1)) + return; + } +} - bool BasicParticle::update_temperature(Grid * const g, int x, int y) - { - for (int i = -1; i <= 1; i++) { - for (int j = -1; j <= 1; j++) { - int xa = x + i; - int ya = y + j; - auto p = g->get_particle(xa,ya); - if (p) { - data.temperature += (p->data.temperature - data.temperature) / 5; - } - } - } - - /* apply state transition */ +BasicParticle::BasicParticle() : Particle(ParticleID::BASIC) {} - if (get_state() != State::GAS && data.temperature > data.boiling_point) { - if (data.gas_state != ParticleID::BASIC){ - auto gas = get_new_particle(data.gas_state); - g->replace_particle(x,y,gas); - return true; - } - } +void BasicParticle::update(Grid *const g, int x, int y) { return; } - if (get_state() != State::LIQUID && data.temperature < data.boiling_point - && data.temperature > data.freezing_point) { - if (data.liquid_state != ParticleID::BASIC){ - auto liquid = get_new_particle(data.liquid_state); - g->replace_particle(x,y,liquid); - return true; - } - } - - if (get_state() != State::SOLID && data.temperature < data.freezing_point) { - if (data.solid_state != ParticleID::BASIC){ - auto gas = get_new_particle(data.solid_state); - g->replace_particle(x,y,gas); - return true; - } - } +PixelColour BasicParticle::get_colour() { + return PixelColour{part_colours[((int)this->id)]}; +} - return false; +std::string BasicParticle::get_name() { return part_names[((int)this->id)]; } + +bool BasicParticle::update_temperature(Grid *const g, int x, int y) { + for (int i = -1; i <= 1; i++) { + for (int j = -1; j <= 1; j++) { + int xa = x + i; + int ya = y + j; + auto p = g->get_particle(xa, ya); + if (p) { + data.temperature += (p->data.temperature - data.temperature) / 5; + } } + } - void Water::update(Grid * const g, int x, int y) { - if (update_temperature(g,x,y)) { - return; - } - - auto p = g->get_particle(x,y+1); - if (p && p->data.liquid && p->id != id && this->data.density > p->data.density) { - if (g->swap_particle(x, y, x, y+1)) - return; - } - - p = g->get_particle(x-1,y+1); - if ((p && p->data.liquid && p->id != id && data.density > p->data.density)) { - if (g->swap_particle(x, y, x-1, y+1)) { - return; - } - } - - p = g->get_particle(x+1,y+1); - if ((p && p->data.liquid && p->id != id && data.density > p->data.density)) { - if (g->swap_particle(x, y, x+1, y+1)) { - return; - } - } - - if(g->move_particle(x, y, x, y+1)) { - return; - } - if (g->move_particle(x, y, x-1, y+1)) { - return; - } - if (g->move_particle(x, y, x+1, y+1)) { - return; - } - - /* laksjdlaj */ - - if (g->move_particle(x, y, x-1, y)) { - return; - } - if (g->move_particle(x, y, x+1, y)) { - return; - } - - - p = g->get_particle(x-1,y); - if ((p && p->data.liquid)) { - if (g->swap_particle(x, y, x-1, y)) { - return; - } - } - - p = g->get_particle(x+1,y); - if ((p && p->data.liquid)) { - if (g->swap_particle(x, y, x+1, y)) { - return; - } - } + /* apply state transition */ + if (get_state() != State::GAS && data.temperature > data.boiling_point) { + if (data.gas_state != ParticleID::BASIC) { + auto gas = get_new_particle(data.gas_state); + g->replace_particle(x, y, gas); + return true; } + } + + if (get_state() != State::LIQUID && data.temperature < data.boiling_point && + data.temperature > data.freezing_point) { + if (data.liquid_state != ParticleID::BASIC) { + auto liquid = get_new_particle(data.liquid_state); + g->replace_particle(x, y, liquid); + return true; + } + } - void Steam::update(Grid *const g, int x, int y) { - Particle *p = g->get_particle(x,y-1); - if (g->move_particle(x, y, x, y-1)) { - return; - } - p = g->get_particle(x-1,y-1); - if (g->move_particle(x, y, x-1, y-1)) { - return; - } - p = g->get_particle(x+1,y-1); - if (g->move_particle(x, y, x+1, y-1)) { - return; - } - p = g->get_particle(x+1,y); - if (g->move_particle(x, y, x+1, y)) { - return; - } - p = g->get_particle(x-1,y); - if (g->move_particle(x, y, x-1, y)) { - return; - } + if (get_state() != State::SOLID && data.temperature < data.freezing_point) { + if (data.solid_state != ParticleID::BASIC) { + auto gas = get_new_particle(data.solid_state); + g->replace_particle(x, y, gas); + return true; } + } - Lava::Lava() : Water(ParticleID::LAVA) {}; + return false; +} - Rock::Rock() : Sand(ParticleID::ROCK) {}; +void Water::update(Grid *const g, int x, int y) { + if (update_temperature(g, x, y)) { + return; + } + + auto p = g->get_particle(x, y + 1); + if (p && p->data.liquid && p->id != id && + this->data.density > p->data.density) { + if (g->swap_particle(x, y, x, y + 1)) + return; + } + + p = g->get_particle(x - 1, y + 1); + if ((p && p->data.liquid && p->id != id && data.density > p->data.density)) { + if (g->swap_particle(x, y, x - 1, y + 1)) { + return; + } + } - void Lava::update(Grid *const g, int x, int y) { - Water::update(g,x,y); + p = g->get_particle(x + 1, y + 1); + if ((p && p->data.liquid && p->id != id && data.density > p->data.density)) { + if (g->swap_particle(x, y, x + 1, y + 1)) { + return; + } + } + + if (g->move_particle(x, y, x, y + 1)) { + return; + } + if (g->move_particle(x, y, x - 1, y + 1)) { + return; + } + if (g->move_particle(x, y, x + 1, y + 1)) { + return; + } + + /* laksjdlaj */ + + if (g->move_particle(x, y, x - 1, y)) { + return; + } + if (g->move_particle(x, y, x + 1, y)) { + return; + } + + p = g->get_particle(x - 1, y); + if ((p && p->data.liquid)) { + if (g->swap_particle(x, y, x - 1, y)) { + return; } + } - void Rock::update(Grid *const g, int x, int y) { - Sand::update(g,x,y); + p = g->get_particle(x + 1, y); + if ((p && p->data.liquid)) { + if (g->swap_particle(x, y, x + 1, y)) { + return; } - + } +} + +void Steam::update(Grid *const g, int x, int y) { + Particle *p = g->get_particle(x, y - 1); + if (g->move_particle(x, y, x, y - 1)) { + return; + } + p = g->get_particle(x - 1, y - 1); + if (g->move_particle(x, y, x - 1, y - 1)) { + return; + } + p = g->get_particle(x + 1, y - 1); + if (g->move_particle(x, y, x + 1, y - 1)) { + return; + } + p = g->get_particle(x + 1, y); + if (g->move_particle(x, y, x + 1, y)) { + return; + } + p = g->get_particle(x - 1, y); + if (g->move_particle(x, y, x - 1, y)) { + return; + } } +Lava::Lava() : Water(ParticleID::LAVA){}; + +Rock::Rock() : Sand(ParticleID::ROCK){}; + +void Lava::update(Grid *const g, int x, int y) { Water::update(g, x, y); } +void Rock::update(Grid *const g, int x, int y) { Sand::update(g, x, y); } +} // namespace pengine diff --git a/particles.h b/particles.h index e8ce19a..187efcd 100644 --- a/particles.h +++ b/particles.h @@ -6,148 +6,141 @@ #include #include #include -#include -#include -#include -#include -#include #include +#include +#include namespace pengine { -enum class ParticleID -{ - BASIC = 0, - SAND = 1, - WATER = 2, - STEAM = 3, - LAVA = 4, - ROCK = 5 +enum class ParticleID { + BASIC = 0, + SAND = 1, + WATER = 2, + STEAM = 3, + LAVA = 4, + ROCK = 5 }; class PixelColour { - public: - union { - struct { - Uint8 b; - Uint8 g; - Uint8 r; - Uint8 a; - }; - Uint32 pixel; +public: + union { + struct { + Uint8 b; + Uint8 g; + Uint8 r; + Uint8 a; }; - Uint32 get_pixelcol(); - SDL_Color get_sdlcol(); - PixelColour(short r, short g, short b, short a); - PixelColour(short r, short g, short b); - PixelColour(const Uint8[3]); - PixelColour(SDL_Color c); - PixelColour(Uint32 c); + Uint32 pixel; + }; + Uint32 get_pixelcol(); + SDL_Color get_sdlcol(); + PixelColour(short r, short g, short b, short a); + PixelColour(short r, short g, short b); + PixelColour(const Uint8[3]); + PixelColour(SDL_Color c); + PixelColour(Uint32 c); }; -enum class State { - SOLID, - LIQUID, - GAS -}; +enum class State { SOLID, LIQUID, GAS }; struct particle_data { - double density; - bool liquid; - double temperature; - double boiling_point; - double melting_point; - double freezing_point; - ParticleID gas_state; - ParticleID liquid_state; - ParticleID solid_state; + double density; + bool liquid; + double temperature; + double boiling_point; + double melting_point; + double freezing_point; + ParticleID gas_state; + ParticleID liquid_state; + ParticleID solid_state; }; class Particle; - class Grid { - public: - Particle **grid; - Uint32 *pixels; - int xsize; - int ysize; - - Grid(int xs, int ys); - virtual ~Grid(); - - void update(); - void update_texture(); - void add_particle_at(int x, int y, ParticleID p); - - bool move_particle(int xa, int ya, int xb, int yb); - int swap_particle(int xa, int ya, int xb, int yb); - bool inside_grid(int x, int y); - Particle *get_particle(int x, int y); - void replace_particle(int x, int y, Particle *new_particle); - // std::vector get_particles_near(int x, int y); +public: + Particle **grid; + Uint32 *pixels; + int xsize; + int ysize; + + Grid(int xs, int ys); + virtual ~Grid(); + Grid &operator=(Grid o); + + void update(); + void clear(); + void update_texture(); + void add_particle_at(int x, int y, ParticleID p); + void erase_particle_at(int x, int y); + + bool move_particle(int xa, int ya, int xb, int yb); + int swap_particle(int xa, int ya, int xb, int yb); + bool inside_grid(int x, int y); + Particle *get_particle(int x, int y); + void replace_particle(int x, int y, Particle *new_particle); + // std::vector get_particles_near(int x, int y); }; -class Particle -{ - public: - struct particle_data data; - - bool updated = false; - enum ParticleID id; - virtual void update(Grid *const, int x, int y) = 0; - virtual PixelColour get_colour() = 0; - Particle(ParticleID id) : id{id} {}; - virtual std::string get_name() = 0; - virtual ~Particle() = default; +class Particle { +public: + struct particle_data data; + + bool updated = false; + enum ParticleID id; + virtual void update(Grid *const, int x, int y) = 0; + virtual PixelColour get_colour() = 0; + Particle(ParticleID id) : id{id} {}; + virtual std::string get_name() = 0; + virtual ~Particle() = default; }; -class BasicParticle : public Particle -{ - protected: - bool update_temperature(Grid * const g, int x, int y); - State get_state(); - public: - BasicParticle(); - BasicParticle(ParticleID id); - struct particle_data default_data(ParticleID id); - void update(Grid *const, int x, int y) override; - PixelColour get_colour() override; - std::string get_name() override; +class BasicParticle : public Particle { +protected: + bool update_temperature(Grid *const g, int x, int y); + State get_state(); + +public: + BasicParticle(); + BasicParticle(ParticleID id); + struct particle_data default_data(ParticleID id); + void update(Grid *const, int x, int y) override; + PixelColour get_colour() override; + std::string get_name() override; }; -class Sand:public BasicParticle { +class Sand : public BasicParticle { - public: - void update(Grid *const, int x, int y) override; - Sand() : BasicParticle(ParticleID::SAND){}; - Sand(ParticleID id) : BasicParticle(id) {}; +public: + void update(Grid *const, int x, int y) override; + Sand() : BasicParticle(ParticleID::SAND){}; + Sand(ParticleID id) : BasicParticle(id){}; }; -class Water:public BasicParticle { - public: - void update(Grid *const, int x, int y) override; - Water() : BasicParticle(ParticleID::WATER) {}; - Water(ParticleID id) : BasicParticle(id) {}; +class Water : public BasicParticle { +public: + void update(Grid *const, int x, int y) override; + Water() : BasicParticle(ParticleID::WATER){}; + Water(ParticleID id) : BasicParticle(id){}; }; -class Steam:public BasicParticle { - public: - void update(Grid *const, int x, int y) override; - Steam() : BasicParticle(ParticleID::STEAM) {}; +class Steam : public BasicParticle { +public: + void update(Grid *const, int x, int y) override; + Steam() : BasicParticle(ParticleID::STEAM){}; }; -class Lava:public Water { - public: - void update(Grid *const, int x, int y) override; - Lava(); +class Lava : public Water { +public: + void update(Grid *const, int x, int y) override; + Lava(); }; -class Rock: public Sand { - public: - void update(Grid *const, int x, int y) override; - Rock(); +class Rock : public Sand { +public: + void update(Grid *const, int x, int y) override; + Rock(); }; -} +} // namespace pengine #endif diff --git a/shell_minimal.html b/shell_minimal.html new file mode 100644 index 0000000..f11184c --- /dev/null +++ b/shell_minimal.html @@ -0,0 +1,65 @@ + + + + + + @HELLO_IMGUI_ICON_DISPLAY_NAME@ + + + + + +{{{ SCRIPT }}} + + +