Browse Source

emscipten build

master
alistair 9 months ago
parent
commit
4516dcbd70
  1. 18
      Makefile
  2. 434
      game.cpp
  3. 878
      particles.cpp
  4. 213
      particles.h
  5. 65
      shell_minimal.html

18
Makefile

@ -1,6 +1,16 @@
all: test:
g++ -fsanitize=address -c particles.cpp -lSDL2 -g -o particles.o $(CXX) -fsanitize=address -c particles.cpp -lSDL2 -g -o particles.o
g++ -fsanitize=address -c game.cpp -lSDL2 -g -o game.o $(CXX) -fsanitize=address -c game.cpp -lSDL2 -g -o game.o
g++ -fsanitize=address -lSDL2 -g particles.o game.o -o main $(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

434
game.cpp

@ -1,3 +1,4 @@
#include <SDL2/SDL.h>
#include <SDL2/SDL_events.h> #include <SDL2/SDL_events.h>
#include <SDL2/SDL_pixels.h> #include <SDL2/SDL_pixels.h>
#include <SDL2/SDL_render.h> #include <SDL2/SDL_render.h>
@ -5,236 +6,281 @@
#include <SDL2/SDL_surface.h> #include <SDL2/SDL_surface.h>
#include <SDL2/SDL_timer.h> #include <SDL2/SDL_timer.h>
#include <SDL2/SDL_video.h> #include <SDL2/SDL_video.h>
#include <SDL2/SDL_image.h>
#include <SDL2/SDL_ttf.h>
#include <string>
#include <deque> #include <deque>
#include <iostream> #include <iostream>
#include <string>
#include <vector> #include <vector>
#ifdef __EMSCRIPTEN__
#include <emscripten.h>
#include <emscripten/html5.h>
#endif
#include "particles.h" #include "particles.h"
namespace pengine { namespace pengine {
class GameWindow { class GameWindow {
private: private:
struct SDL_Window *window; std::string name;
std::string name;
public: public:
struct SDL_Renderer *renderer; struct SDL_Window *window;
struct SDL_Renderer *renderer;
GameWindow(int width, int height, std::string name) {
SDL_Init(SDL_INIT_EVERYTHING); GameWindow(int width, int height, std::string name) {
this->name = name; SDL_Init(SDL_INIT_VIDEO);
window = SDL_CreateWindow(name.c_str(), this->name = name;
SDL_WINDOWPOS_CENTERED, // SDL_SetHint(SDL_HINT_EMSCRIPTEN_KEYBOARD_ELEMENT, "#canvas");
SDL_WINDOWPOS_CENTERED, window = SDL_CreateWindow(name.c_str(), SDL_WINDOWPOS_CENTERED,
width, height, SDL_WINDOWPOS_CENTERED, width, height,
SDL_WINDOW_RESIZABLE); SDL_WINDOW_BORDERLESS);
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED renderer = SDL_CreateRenderer(
| SDL_RENDERER_PRESENTVSYNC); window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
} }
~GameWindow() { ~GameWindow() {
SDL_DestroyRenderer(renderer); SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window); SDL_DestroyWindow(window);
SDL_Quit(); SDL_Quit();
} }
}; };
enum MouseAction { NONE, LEFT, RIGHT };
class PaintTool { class PaintTool {
public: public:
int particle_selected = 0; int particle_selected = 0;
int size = 1; int size = 1;
int mouse_state = 0; MouseAction mouse_state = NONE;
bool paused = false; bool paused = false;
}; };
class Game { class Game {
GameWindow win; GameWindow win;
Grid grid; Grid grid;
SDL_Texture *grid_texture; SDL_Texture *grid_texture;
SDL_Renderer *ren; SDL_Renderer *ren;
int internal_sz[2]; int internal_sz[2];
int window_sz[2]; int window_sz[2];
struct su_pair {int x; int y;} coord; struct su_pair {
int x;
std::vector<Particle *>particles = std::vector<Particle *>(); int y;
PaintTool tool = PaintTool(); } coord;
public: std::vector<Particle *> particles = std::vector<Particle *>();
PaintTool tool = PaintTool();
Game(int x, int y, int gx, int gy):
win{GameWindow {x,y,"game"}}, public:
grid{Grid{gx, gy}} Game(int x, int y, int gx, int gy)
{ : win{GameWindow{x, y, "sand"}}, grid{Grid{gx, gy}} {
ren = win.renderer; ren = win.renderer;
/* texture for drawing particles into */ /* texture for drawing particles into */
grid_texture = SDL_CreateTexture(ren, SDL_PIXELFORMAT_ARGB8888, grid_texture = SDL_CreateTexture(ren, SDL_PIXELFORMAT_ARGB8888,
SDL_TEXTUREACCESS_STATIC, gx,gy); SDL_TEXTUREACCESS_STATIC, gx, gy);
internal_sz[0] = gx; internal_sz[0] = gx;
internal_sz[1] = gy; internal_sz[1] = gy;
window_sz[0] = x; window_sz[0] = x;
window_sz[1] = y; window_sz[1] = y;
particles.push_back(new Sand()); particles.push_back(new Sand());
particles.push_back(new Water()); particles.push_back(new Water());
particles.push_back(new Steam()); particles.push_back(new Steam());
particles.push_back(new Lava()); 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() { for (int i = coord.x - tool.size / 2; i < coord.x + tool.size / 2; i++) {
SDL_DestroyTexture(grid_texture); for (int j = coord.y - tool.size / 2; j < coord.y + tool.size / 2; j++) {
for (auto p : particles) { if (grid.inside_grid(i, j)) {
delete p; 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() { for (int i = coord.x - tool.size / 2; i < coord.x + tool.size / 2; i++) {
if (tool.size == 1) { for (int j = coord.y - tool.size / 2; j < coord.y + tool.size / 2; j++) {
int i = coord.x; if (grid.inside_grid(i, j)) {
int j = coord.y; grid.erase_particle_at(i, 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();
}
return;
} }
}
}
}
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 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++) { for (int j = coord.y - tool.size / 2; j < coord.y + tool.size / 2; j++) {
if (grid.inside_grid(i, j)) { if (grid.inside_grid(i, j)) {
auto colour = PixelColour(grid.pixels[i + j * grid.xsize]); grid.add_particle_at(i, j, particles[tool.particle_selected]->id);
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 add_particles() {
if (tool.size <= 1) { void draw() {
if (grid.inside_grid(coord.x, coord.y)) { SDL_SetRenderDrawColor(ren, 40, 40, 40, 255);
grid.add_particle_at(coord.x, coord.y,
particles[tool.particle_selected]->id); SDL_RenderClear(ren);
}
return; 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;
} }
if (event.key.keysym.scancode == SDL_SCANCODE_P) {
for (int i = coord.x - tool.size / 2; i < coord.x + tool.size / 2; i++) { tool.paused = !tool.paused;
for (int j = coord.y - tool.size / 2; j < coord.y + tool.size / 2; j++) { }
if (grid.inside_grid(i, j)) { if (event.key.keysym.scancode == SDL_SCANCODE_C) {
grid.add_particle_at(i, j, particles[tool.particle_selected]->id); 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;
}
} }
if (tool.mouse_state == LEFT) {
void draw() { add_particles();
SDL_SetRenderDrawColor(ren, 40, 40, 40, 255); } else if (tool.mouse_state == RIGHT) {
SDL_RenderClear(ren); remove_particles();
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.paused) {
struct su_pair get_click_location_in_grid(int x, int y) { update();
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();
}
} }
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(); int main(int argc, char **argv) {
if (error) {
std::cout << error;
}
pengine::Game game {pengine::Game(500,500, 80,80)};
game.run();
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;
} }

878
particles.cpp

@ -3,514 +3,506 @@
namespace pengine { namespace pengine {
Uint8 part_colours[][3] = { Uint8 part_colours[][3] = {
{255,255,255}, // BASIC {255, 255, 255}, // BASIC
{252,250,148}, // SAND {252, 250, 148}, // SAND
{70,90,255}, // WATER {70, 90, 255}, // WATER
{200,220,255}, // STEAM {200, 220, 255}, // STEAM
{200,20,20}, // LAVA {200, 20, 20}, // LAVA
{140,111,71}, // ROCK {140, 111, 71}, // ROCK
{200,20,20}, // LIQUID QUARTZ {200, 20, 20}, // LIQUID QUARTZ
{20,80,40}, // QUARTZ {20, 80, 40}, // QUARTZ
}; };
std::string part_names[] = { std::string part_names[] = {"default", "Sand", "Water",
"default", "Steam", "Lava", "Rock"};
"Sand",
"Water", struct particle_data BasicParticle::default_data(ParticleID id) {
"Steam", struct particle_data datap;
"Lava", switch (id) {
"Rock" case ParticleID::WATER:
}; datap = {.density = 10,
.liquid = true,
struct particle_data BasicParticle::default_data(ParticleID id) .temperature = 20,
{ .boiling_point = 100,
struct particle_data datap; .gas_state = ParticleID::STEAM};
switch (id) { break;
case ParticleID::WATER: case ParticleID::LAVA:
datap = {.density=10, datap = {.density = 20,
.liquid = true, .liquid = true,
.temperature=20, .temperature = 5000,
.boiling_point = 100, .boiling_point = 10000,
.gas_state = ParticleID::STEAM .freezing_point = 200,
}; .solid_state = ParticleID::ROCK};
break; break;
case ParticleID::LAVA: case ParticleID::STEAM:
datap = {.density=20, .liquid = true, .temperature=5000, datap = {.density = 0,
.boiling_point = 10000,.freezing_point=200, .solid_state=ParticleID::ROCK}; .liquid = false,
break; .temperature = 150,
case ParticleID::STEAM: .liquid_state = ParticleID::WATER};
datap = {.density=0, .liquid = false, .temperature=150, break;
.liquid_state = ParticleID::WATER}; case ParticleID::SAND:
break; datap = {.density = 100, .liquid = false, .temperature = 20};
case ParticleID::SAND: break;
datap = {.density=100, .liquid = false, .temperature=20}; case ParticleID::ROCK:
break; datap = {.density = 150,
case ParticleID::ROCK: .liquid = false,
datap = {.density=150, .liquid = false, .temperature=20, .temperature = 20,
.melting_point = 700, .liquid_state=ParticleID::LAVA}; .melting_point = 700,
break; .liquid_state = ParticleID::LAVA};
default: break;
datap = {.temperature = 0}; default:
break; datap = {.temperature = 0};
} break;
return datap; }
} 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;
}
PixelColour::PixelColour(short r, short g, short b) { BasicParticle::BasicParticle(ParticleID id) : Particle(id) {
this->r = r; this->id = id;
this->g = g; data = default_data(id);
this->b = b; };
this->a = 255;
} 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) { Particle *get_new_particle(ParticleID p) {
this->r = c.r;
this->g = c.g; switch (p) {
this->b = c.b; case ParticleID::SAND:
this->a = c.a; 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() { PixelColour::PixelColour(short r, short g, short b) {
SDL_Color c; this->r = r;
c.r = r; this->g = g;
c.b = b; this->b = b;
c.g = g; this->a = 255;
c.a = a; }
return c;
}
Uint32 PixelColour::get_pixelcol() { PixelColour::PixelColour(SDL_Color c) {
return pixel; this->r = c.r;
} this->g = c.g;
this->b = c.b;
this->a = c.a;
}
Grid::Grid(int xs, int ys) { PixelColour::PixelColour(const Uint8 p[3]) : PixelColour(p[0], p[1], p[2]) {}
xsize = xs;
ysize = ys;
grid = new Particle *[xs * ys] {}; SDL_Color PixelColour::get_sdlcol() {
pixels = new Uint32[xs * ys] {}; 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++) { Uint32 PixelColour::get_pixelcol() { return pixel; }
grid[i] = 0;
pixels[i] = 0;
}
}
Grid::~Grid() Grid::Grid(int xs, int ys) {
{ xsize = xs;
for (int i = 0; i < xsize * ysize; i++) { ysize = ys;
if (grid[i])
delete grid[i];
}
delete[] grid;
delete[] pixels;
}
void Grid::update() grid = new Particle *[xs * ys] {};
{ pixels = new Uint32[xs * ys]{};
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;
}
}
}
}
}
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) grid = new Particle *[xsize * ysize] {};
{ pixels = new Uint32[xsize * ysize]{};
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[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) { void Grid::clear() {
if (!inside_grid(x,y)) { for (int i = 0; i < xsize * ysize; i++) {
return nullptr; 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() { while (done) {
PixelColour defaultcol = PixelColour(0,0,0,0); done = false;
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) { for (int i = 0; i < xsize; i++) {
if (x >= xsize || y >= ysize || x < 0 || y < 0) { for (int j = 0; j < ysize; j++) {
return false; 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)) { void Grid::erase_particle_at(int x, int y) {
return false; 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)) { grid[x + y * xsize] = 0;
return false; }
}
if ((get_particle(xa,ya) != nullptr) && (get_particle(xb,yb) == nullptr)) { void Grid::add_particle_at(int x, int y, ParticleID p) {
grid[xb + yb * xsize] = grid[xa + ya * xsize]; if (x >= xsize || y >= ysize || x < 0 || y < 0) {
grid[xa + ya * xsize] = nullptr; std::cout << "invalid position " << x << " " << y << std::endl;
return true; throw "invalid boundaries";
} }
return false;
}
int Grid::swap_particle(int xa, int ya, int xb, int yb) { if (grid[x + y * xsize]) {
return;
}
if (!inside_grid(xb, yb)) { grid[x + y * xsize] = get_new_particle(p);
return 0; }
}
if (!inside_grid(xa, ya)) { Particle *Grid::get_particle(int x, int y) {
return 0; if (!inside_grid(x, y)) {
} return nullptr;
}
int num = 0; return grid[x + xsize * y];
if (get_particle(xa,ya) != nullptr) { }
num++;
}
if (get_particle(xb,yb) != nullptr) {
num++;
}
if (num > 0) { void Grid::update_texture() {
Particle *temp = grid[xb + yb * xsize]; PixelColour defaultcol = PixelColour(0, 0, 0, 0);
grid[xb + yb * xsize] = grid[xa + ya * xsize]; for (int i = 0; i < xsize; i++) {
grid[xa + ya * xsize] = temp; for (int j = 0; j < ysize; j++) {
return num; int p = j * xsize + i;
} if (grid[p] != nullptr) {
return 0; //: 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) { return true;
auto p = get_particle(x, y); }
if (!p) {
return;
}
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)) { void Grid::replace_particle(int x, int y, Particle *new_particle) {
return; auto p = get_particle(x, y);
}
Particle *p; if (!p) {
if(g->move_particle(x, y, x, y+1)) { return;
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); delete p;
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;
}
}
p = g->get_particle(x-1, y+1); grid[x + y * xsize] = new_particle;
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;
}
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;
} }
} else {
BasicParticle::BasicParticle() : Particle(ParticleID::BASIC) {} if (g->swap_particle(x, y, x, y + 1)) {
return;
void BasicParticle::update(Grid * const g, int x, int y) {
return;
} }
}
PixelColour BasicParticle::get_colour() { p = g->get_particle(x - 1, y + 1);
return PixelColour {part_colours[((int)this->id)]}; if (p != nullptr) {
if (p->data.density < data.density || p->data.liquid) {
g->swap_particle(x, y, x - 1, y + 1);
return;
} }
} else {
std::string BasicParticle::get_name() { if (g->swap_particle(x, y, x - 1, y + 1))
return part_names[((int)this->id)]; 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) BasicParticle::BasicParticle() : Particle(ParticleID::BASIC) {}
{
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 */
if (get_state() != State::GAS && data.temperature > data.boiling_point) { void BasicParticle::update(Grid *const g, int x, int y) { return; }
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 PixelColour BasicParticle::get_colour() {
&& data.temperature > data.freezing_point) { return PixelColour{part_colours[((int)this->id)]};
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;
}
}
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) { /* apply state transition */
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;
}
}
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) { if (get_state() != State::SOLID && data.temperature < data.freezing_point) {
Particle *p = g->get_particle(x,y-1); if (data.solid_state != ParticleID::BASIC) {
if (g->move_particle(x, y, x, y-1)) { auto gas = get_new_particle(data.solid_state);
return; g->replace_particle(x, y, gas);
} return true;
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) {}; 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) { p = g->get_particle(x + 1, y + 1);
Water::update(g,x,y); 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) { p = g->get_particle(x + 1, y);
Sand::update(g,x,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

213
particles.h

@ -6,148 +6,141 @@
#include <SDL2/SDL_pixels.h> #include <SDL2/SDL_pixels.h>
#include <SDL2/SDL_render.h> #include <SDL2/SDL_render.h>
#include <SDL2/SDL_surface.h> #include <SDL2/SDL_surface.h>
#include <SDL2/SDL_video.h>
#include <SDL2/SDL_image.h>
#include <SDL2/SDL_ttf.h>
#include <vector>
#include <string>
#include <memory> #include <memory>
#include <string>
#include <vector>
namespace pengine { namespace pengine {
enum class ParticleID enum class ParticleID {
{ BASIC = 0,
BASIC = 0, SAND = 1,
SAND = 1, WATER = 2,
WATER = 2, STEAM = 3,
STEAM = 3, LAVA = 4,
LAVA = 4, ROCK = 5
ROCK = 5
}; };
class PixelColour { class PixelColour {
public: public:
union { union {
struct { struct {
Uint8 b; Uint8 b;
Uint8 g; Uint8 g;
Uint8 r; Uint8 r;
Uint8 a; Uint8 a;
};
Uint32 pixel;
}; };
Uint32 get_pixelcol(); Uint32 pixel;
SDL_Color get_sdlcol(); };
PixelColour(short r, short g, short b, short a); Uint32 get_pixelcol();
PixelColour(short r, short g, short b); SDL_Color get_sdlcol();
PixelColour(const Uint8[3]); PixelColour(short r, short g, short b, short a);
PixelColour(SDL_Color c); PixelColour(short r, short g, short b);
PixelColour(Uint32 c); PixelColour(const Uint8[3]);
PixelColour(SDL_Color c);
PixelColour(Uint32 c);
}; };
enum class State { enum class State { SOLID, LIQUID, GAS };
SOLID,
LIQUID,
GAS
};
struct particle_data { struct particle_data {
double density; double density;
bool liquid; bool liquid;
double temperature; double temperature;
double boiling_point; double boiling_point;
double melting_point; double melting_point;
double freezing_point; double freezing_point;
ParticleID gas_state; ParticleID gas_state;
ParticleID liquid_state; ParticleID liquid_state;
ParticleID solid_state; ParticleID solid_state;
}; };
class Particle; class Particle;
class Grid { class Grid {
public: public:
Particle **grid; Particle **grid;
Uint32 *pixels; Uint32 *pixels;
int xsize; int xsize;
int ysize; int ysize;
Grid(int xs, int ys); Grid(int xs, int ys);
virtual ~Grid(); virtual ~Grid();
Grid &operator=(Grid o);
void update();
void update_texture(); void update();
void add_particle_at(int x, int y, ParticleID p); void clear();
void update_texture();
bool move_particle(int xa, int ya, int xb, int yb); void add_particle_at(int x, int y, ParticleID p);
int swap_particle(int xa, int ya, int xb, int yb); void erase_particle_at(int x, int y);
bool inside_grid(int x, int y);
Particle *get_particle(int x, int y); bool move_particle(int xa, int ya, int xb, int yb);
void replace_particle(int x, int y, Particle *new_particle); int swap_particle(int xa, int ya, int xb, int yb);
// std::vector<Particle *> get_particles_near(int x, int y); 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<Particle *> get_particles_near(int x, int y);
}; };
class Particle class Particle {
{ public:
public: struct particle_data data;
struct particle_data data;
bool updated = false;
bool updated = false; enum ParticleID id;
enum ParticleID id; virtual void update(Grid *const, int x, int y) = 0;
virtual void update(Grid *const, int x, int y) = 0; virtual PixelColour get_colour() = 0;
virtual PixelColour get_colour() = 0; Particle(ParticleID id) : id{id} {};
Particle(ParticleID id) : id{id} {}; virtual std::string get_name() = 0;
virtual std::string get_name() = 0; virtual ~Particle() = default;
virtual ~Particle() = default;
}; };
class BasicParticle : public Particle class BasicParticle : public Particle {
{ protected:
protected: bool update_temperature(Grid *const g, int x, int y);
bool update_temperature(Grid * const g, int x, int y); State get_state();
State get_state();
public: public:
BasicParticle(); BasicParticle();
BasicParticle(ParticleID id); BasicParticle(ParticleID id);
struct particle_data default_data(ParticleID id); struct particle_data default_data(ParticleID id);
void update(Grid *const, int x, int y) override; void update(Grid *const, int x, int y) override;
PixelColour get_colour() override; PixelColour get_colour() override;
std::string get_name() override; std::string get_name() override;
}; };
class Sand:public BasicParticle { class Sand : public BasicParticle {
public: public:
void update(Grid *const, int x, int y) override; void update(Grid *const, int x, int y) override;
Sand() : BasicParticle(ParticleID::SAND){}; Sand() : BasicParticle(ParticleID::SAND){};
Sand(ParticleID id) : BasicParticle(id) {}; Sand(ParticleID id) : BasicParticle(id){};
}; };
class Water:public BasicParticle { class Water : public BasicParticle {
public: public:
void update(Grid *const, int x, int y) override; void update(Grid *const, int x, int y) override;
Water() : BasicParticle(ParticleID::WATER) {}; Water() : BasicParticle(ParticleID::WATER){};
Water(ParticleID id) : BasicParticle(id) {}; Water(ParticleID id) : BasicParticle(id){};
}; };
class Steam:public BasicParticle { class Steam : public BasicParticle {
public: public:
void update(Grid *const, int x, int y) override; void update(Grid *const, int x, int y) override;
Steam() : BasicParticle(ParticleID::STEAM) {}; Steam() : BasicParticle(ParticleID::STEAM){};
}; };
class Lava:public Water { class Lava : public Water {
public: public:
void update(Grid *const, int x, int y) override; void update(Grid *const, int x, int y) override;
Lava(); Lava();
}; };
class Rock: public Sand { class Rock : public Sand {
public: public:
void update(Grid *const, int x, int y) override; void update(Grid *const, int x, int y) override;
Rock(); Rock();
}; };
} } // namespace pengine
#endif #endif

65
shell_minimal.html

@ -0,0 +1,65 @@
<!doctype html>
<html lang="en-us">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no"/>
<title>@HELLO_IMGUI_ICON_DISPLAY_NAME@</title>
<style>
body { margin: 0; background-color: black }
.emscripten {
position: absolute;
top: 0px;
left: 0px;
margin: 0px;
border: 0;
width: 100%;
height: 100%;
overflow: hidden;
display: block;
image-rendering: optimizeSpeed;
image-rendering: -moz-crisp-edges;
image-rendering: -o-crisp-edges;
image-rendering: -webkit-optimize-contrast;
image-rendering: optimize-contrast;
image-rendering: crisp-edges;
image-rendering: pixelated;
-ms-interpolation-mode: nearest-neighbor;
}
</style>
</head>
<body>
<canvas class="emscripten" id="canvas" oncontextmenu="event.preventDefault()"></canvas>
<script type='text/javascript'>
var Module = {
preRun: [],
postRun: [],
print: (function() {
return function(text) {
text = Array.prototype.slice.call(arguments).join(' ');
console.log(text);
};
})(),
printErr: function(text) {
text = Array.prototype.slice.call(arguments).join(' ');
console.error(text);
},
canvas: (function() {
var canvas = document.getElementById('canvas');
//canvas.addEventListener("webglcontextlost", function(e) { alert('FIXME: WebGL context lost, please reload the page'); e.preventDefault(); }, false);
return canvas;
})(),
setStatus: function(text) {
console.log("status: " + text);
},
monitorRunDependencies: function(left) {
// no run dependencies to log
}
};
window.onerror = function() {
console.log("onerror: " + event);
};
</script>
{{{ SCRIPT }}}
</body>
</html>
Loading…
Cancel
Save