Browse Source

emscipten build

master
alistair 8 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 @@ @@ -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

434
game.cpp

@ -1,3 +1,4 @@ @@ -1,3 +1,4 @@
#include <SDL2/SDL.h>
#include <SDL2/SDL_events.h>
#include <SDL2/SDL_pixels.h>
#include <SDL2/SDL_render.h>
@ -5,236 +6,281 @@ @@ -5,236 +6,281 @@
#include <SDL2/SDL_surface.h>
#include <SDL2/SDL_timer.h>
#include <SDL2/SDL_video.h>
#include <SDL2/SDL_image.h>
#include <SDL2/SDL_ttf.h>
#include <string>
#include <deque>
#include <iostream>
#include <string>
#include <vector>
#ifdef __EMSCRIPTEN__
#include <emscripten.h>
#include <emscripten/html5.h>
#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::vector<Particle *>particles = std::vector<Particle *>();
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<Particle *> particles = std::vector<Particle *>();
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;
}

878
particles.cpp

@ -3,514 +3,506 @@ @@ -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

213
particles.h

@ -6,148 +6,141 @@ @@ -6,148 +6,141 @@
#include <SDL2/SDL_pixels.h>
#include <SDL2/SDL_render.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 <string>
#include <vector>
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<Particle *> 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<Particle *> 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

65
shell_minimal.html

@ -0,0 +1,65 @@ @@ -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