Refactor vector/matrix2d code
This commit is contained in:
parent
369dadf81e
commit
b2328c41b5
69
src/Misc.cpp
69
src/Misc.cpp
@ -5,72 +5,6 @@
|
||||
#include <sys/types.h>
|
||||
#include <cmath>
|
||||
|
||||
matrix2d m2d_multiply_m2d(matrix2d m1, matrix2d m2)
|
||||
{
|
||||
matrix2d result = {
|
||||
m1.a*m2.a+m1.b*m2.c, m1.a*m2.b+m1.b*m2.d,
|
||||
m1.c*m2.a+m1.d*m2.c, m1.c*m2.b+m1.d*m2.d
|
||||
};
|
||||
return result;
|
||||
}
|
||||
|
||||
vector2d m2d_multiply_v2d(matrix2d m, vector2d v)
|
||||
{
|
||||
vector2d result = {
|
||||
m.a*v.x+m.b*v.y,
|
||||
m.c*v.x+m.d*v.y
|
||||
};
|
||||
return result;
|
||||
}
|
||||
|
||||
matrix2d m2d_multiply_float(matrix2d m, float s)
|
||||
{
|
||||
matrix2d result = {
|
||||
m.a*s, m.b*s,
|
||||
m.c*s, m.d*s,
|
||||
};
|
||||
return result;
|
||||
}
|
||||
|
||||
vector2d v2d_multiply_float(vector2d v, float s)
|
||||
{
|
||||
vector2d result = {
|
||||
v.x*s,
|
||||
v.y*s
|
||||
};
|
||||
return result;
|
||||
}
|
||||
|
||||
vector2d v2d_add(vector2d v1, vector2d v2)
|
||||
{
|
||||
vector2d result = {
|
||||
v1.x+v2.x,
|
||||
v1.y+v2.y
|
||||
};
|
||||
return result;
|
||||
}
|
||||
|
||||
vector2d v2d_sub(vector2d v1, vector2d v2)
|
||||
{
|
||||
vector2d result = {
|
||||
v1.x-v2.x,
|
||||
v1.y-v2.y
|
||||
};
|
||||
return result;
|
||||
}
|
||||
|
||||
matrix2d m2d_new(float me0, float me1, float me2, float me3)
|
||||
{
|
||||
matrix2d result = {me0,me1,me2,me3};
|
||||
return result;
|
||||
}
|
||||
|
||||
vector2d v2d_new(float x, float y)
|
||||
{
|
||||
vector2d result = {x, y};
|
||||
return result;
|
||||
}
|
||||
|
||||
void HSV_to_RGB(int h,int s,int v,int *r,int *g,int *b)//convert 0-255(0-360 for H) HSV values to 0-255 RGB
|
||||
{
|
||||
float hh, ss, vv, c, x;
|
||||
@ -152,9 +86,6 @@ void membwand(void * destv, void * srcv, size_t destsize, size_t srcsize)
|
||||
}
|
||||
}
|
||||
|
||||
vector2d v2d_zero = {0,0};
|
||||
matrix2d m2d_identity = {1,0,0,1};
|
||||
|
||||
bool byteStringEqualsString(const ByteString &str, const char *data, size_t size)
|
||||
{
|
||||
return str.size() == size && !memcmp(str.data(), data, size);
|
||||
|
29
src/Misc.h
29
src/Misc.h
@ -1,4 +1,5 @@
|
||||
#pragma once
|
||||
#include "common/Geometry.h"
|
||||
#include <cmath>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
@ -57,34 +58,6 @@ void HSV_to_RGB(int h,int s,int v,int *r,int *g,int *b);
|
||||
void RGB_to_HSV(int r,int g,int b,int *h,int *s,int *v);
|
||||
void membwand(void * dest, void * src, size_t destsize, size_t srcsize);
|
||||
|
||||
// a b
|
||||
// c d
|
||||
|
||||
struct matrix2d {
|
||||
float a,b,c,d;
|
||||
};
|
||||
typedef struct matrix2d matrix2d;
|
||||
|
||||
// column vector
|
||||
struct vector2d {
|
||||
float x,y;
|
||||
};
|
||||
typedef struct vector2d vector2d;
|
||||
|
||||
matrix2d m2d_multiply_m2d(matrix2d m1, matrix2d m2);
|
||||
vector2d m2d_multiply_v2d(matrix2d m, vector2d v);
|
||||
matrix2d m2d_multiply_float(matrix2d m, float s);
|
||||
vector2d v2d_multiply_float(vector2d v, float s);
|
||||
|
||||
vector2d v2d_add(vector2d v1, vector2d v2);
|
||||
vector2d v2d_sub(vector2d v1, vector2d v2);
|
||||
|
||||
matrix2d m2d_new(float me0, float me1, float me2, float me3);
|
||||
vector2d v2d_new(float x, float y);
|
||||
|
||||
extern vector2d v2d_zero;
|
||||
extern matrix2d m2d_identity;
|
||||
|
||||
class ByteString;
|
||||
|
||||
bool byteStringEqualsString(const ByteString &str, const char *data, size_t size);
|
||||
|
@ -1,4 +1,5 @@
|
||||
#pragma once
|
||||
#include "common/Geometry.h"
|
||||
#include <cstdint>
|
||||
|
||||
constexpr int MENUSIZE = 40;
|
||||
@ -11,15 +12,18 @@ constexpr int CELL = 4;
|
||||
constexpr int XCELLS = 153;
|
||||
constexpr int YCELLS = 96;
|
||||
constexpr int NCELL = XCELLS * YCELLS;
|
||||
constexpr Rect<int> CELLS = Rect<int>(Vec2<int>(0, 0), Vec2<int>(XCELLS - 1, YCELLS - 1));
|
||||
constexpr int XRES = XCELLS * CELL;
|
||||
constexpr int YRES = YCELLS * CELL;
|
||||
constexpr int NPART = XRES * YRES;
|
||||
constexpr Rect<int> RES = Rect<int>(Vec2<int>(0, 0), Vec2<int>(XRES - 1, YRES - 1));
|
||||
|
||||
constexpr int XCNTR = XRES / 2;
|
||||
constexpr int YCNTR = YRES / 2;
|
||||
|
||||
constexpr int WINDOWW = XRES + BARSIZE;
|
||||
constexpr int WINDOWH = YRES + MENUSIZE;
|
||||
constexpr Rect<int> WINDOW = Rect<int>(Vec2<int>(0, 0), Vec2<int>(WINDOWW - 1, WINDOWH - 1));
|
||||
|
||||
constexpr int MAXSIGNS = 16;
|
||||
|
||||
|
@ -22,16 +22,14 @@ static void CheckBsonFieldBool(bson_iterator iter, const char *field, bool *flag
|
||||
static void CheckBsonFieldInt(bson_iterator iter, const char *field, int *setting);
|
||||
static void CheckBsonFieldFloat(bson_iterator iter, const char *field, float *setting);
|
||||
|
||||
GameSave::GameSave(int width, int height)
|
||||
GameSave::GameSave(Vec2<int> blockDimen)
|
||||
{
|
||||
setSize(width, height);
|
||||
setSize(blockDimen);
|
||||
}
|
||||
|
||||
GameSave::GameSave(const std::vector<char> &data, bool newWantAuthors)
|
||||
{
|
||||
wantAuthors = newWantAuthors;
|
||||
blockWidth = 0;
|
||||
blockHeight = 0;
|
||||
|
||||
try
|
||||
{
|
||||
@ -77,21 +75,20 @@ void GameSave::Expand(const std::vector<char> &data)
|
||||
}
|
||||
}
|
||||
|
||||
void GameSave::setSize(int newWidth, int newHeight)
|
||||
void GameSave::setSize(Vec2<int> newDimen)
|
||||
{
|
||||
blockWidth = newWidth;
|
||||
blockHeight = newHeight;
|
||||
blockDimen = newDimen;
|
||||
|
||||
particlesCount = 0;
|
||||
particles = std::vector<Particle>(NPART);
|
||||
|
||||
blockMap = Plane<unsigned char>(blockWidth, blockHeight, 0);
|
||||
fanVelX = Plane<float>(blockWidth, blockHeight, 0.0f);
|
||||
fanVelY = Plane<float>(blockWidth, blockHeight, 0.0f);
|
||||
pressure = Plane<float>(blockWidth, blockHeight, 0.0f);
|
||||
velocityX = Plane<float>(blockWidth, blockHeight, 0.0f);
|
||||
velocityY = Plane<float>(blockWidth, blockHeight, 0.0f);
|
||||
ambientHeat = Plane<float>(blockWidth, blockHeight, 0.0f);
|
||||
blockMap = Plane<unsigned char>(blockDimen.X, blockDimen.Y, 0);
|
||||
fanVelX = Plane<float>(blockDimen.X, blockDimen.Y, 0.0f);
|
||||
fanVelY = Plane<float>(blockDimen.X, blockDimen.Y, 0.0f);
|
||||
pressure = Plane<float>(blockDimen.X, blockDimen.Y, 0.0f);
|
||||
velocityX = Plane<float>(blockDimen.X, blockDimen.Y, 0.0f);
|
||||
velocityY = Plane<float>(blockDimen.X, blockDimen.Y, 0.0f);
|
||||
ambientHeat = Plane<float>(blockDimen.X, blockDimen.Y, 0.0f);
|
||||
}
|
||||
|
||||
std::pair<bool, std::vector<char>> GameSave::Serialise() const
|
||||
@ -111,160 +108,130 @@ std::pair<bool, std::vector<char>> GameSave::Serialise() const
|
||||
return { false, {} };
|
||||
}
|
||||
|
||||
vector2d GameSave::Translate(vector2d translate)
|
||||
// round to nearest integer, half-points towards -inf
|
||||
inline Vec2<float> roundNegInf(Vec2<float> v)
|
||||
{
|
||||
float nx, ny;
|
||||
vector2d pos;
|
||||
vector2d translateReal = translate;
|
||||
float minx = 0, miny = 0, maxx = 0, maxy = 0;
|
||||
return (v + Vec2<float>(0.5f, 0.5f)).Floor();
|
||||
}
|
||||
|
||||
// ditto, but return an int
|
||||
inline Vec2<int> lroundNegInf(Vec2<float> v)
|
||||
{
|
||||
return Vec2<int>(roundNegInf(v));
|
||||
}
|
||||
|
||||
Vec2<float> GameSave::Translate(Vec2<float> translate)
|
||||
{
|
||||
Vec2<float> translateReal = translate;
|
||||
auto bounds = Rect<float>(Vec2<float>::Zero);
|
||||
|
||||
// determine minimum and maximum position of all particles / signs
|
||||
for (size_t i = 0; i < signs.size(); i++)
|
||||
{
|
||||
pos = v2d_new(float(signs[i].x), float(signs[i].y));
|
||||
pos = v2d_add(pos,translate);
|
||||
nx = floor(pos.x+0.5f);
|
||||
ny = floor(pos.y+0.5f);
|
||||
if (nx < minx)
|
||||
minx = nx;
|
||||
if (ny < miny)
|
||||
miny = ny;
|
||||
if (nx > maxx)
|
||||
maxx = nx;
|
||||
if (ny > maxy)
|
||||
maxy = ny;
|
||||
}
|
||||
for (auto &sign : signs)
|
||||
bounds |= Rect<float>(roundNegInf(Vec2<float>(sign.x, sign.y) + translate));
|
||||
|
||||
for (int i = 0; i < particlesCount; i++)
|
||||
{
|
||||
if (!particles[i].type) continue;
|
||||
pos = v2d_new(particles[i].x, particles[i].y);
|
||||
pos = v2d_add(pos,translate);
|
||||
nx = floor(pos.x+0.5f);
|
||||
ny = floor(pos.y+0.5f);
|
||||
if (nx < minx)
|
||||
minx = nx;
|
||||
if (ny < miny)
|
||||
miny = ny;
|
||||
if (nx > maxx)
|
||||
maxx = nx;
|
||||
if (ny > maxy)
|
||||
maxy = ny;
|
||||
bounds |= Rect<float>(roundNegInf(Vec2<float>(particles[i].x, particles[i].y) + translate));
|
||||
}
|
||||
// determine whether corrections are needed. If moving in this direction would delete stuff, expand the save
|
||||
vector2d backCorrection = v2d_new(
|
||||
(minx < 0) ? (-floor(minx / CELL)) : 0,
|
||||
(miny < 0) ? (-floor(miny / CELL)) : 0
|
||||
auto backCorrection = Vec2<float>(
|
||||
std::max(0.0f, -std::floor(bounds.TopLeft.X / CELL)),
|
||||
std::max(0.0f, -std::floor(bounds.TopLeft.Y / CELL))
|
||||
);
|
||||
int blockBoundsX = int(maxx / CELL) + 1, blockBoundsY = int(maxy / CELL) + 1;
|
||||
vector2d frontCorrection = v2d_new(
|
||||
float((blockBoundsX > blockWidth) ? (blockBoundsX - blockWidth) : 0),
|
||||
float((blockBoundsY > blockHeight) ? (blockBoundsY - blockHeight) : 0)
|
||||
auto frontCorrection = Vec2<float>(
|
||||
std::max(0, int(bounds.BottomRight.X / CELL) + 1 - blockDimen.X), // TODO: sus. std::floor?
|
||||
std::max(0, int(bounds.BottomRight.Y / CELL) + 1 - blockDimen.Y)
|
||||
);
|
||||
|
||||
// get new width based on corrections
|
||||
auto newWidth = int((blockWidth + backCorrection.x + frontCorrection.x) * CELL);
|
||||
auto newHeight = int((blockHeight + backCorrection.y + frontCorrection.y) * CELL);
|
||||
if (newWidth > XRES)
|
||||
frontCorrection.x = backCorrection.x = 0;
|
||||
if (newHeight > YRES)
|
||||
frontCorrection.y = backCorrection.y = 0;
|
||||
auto newDimen = [=]() {
|
||||
return Vec2<int>((Vec2<float>(blockDimen) + backCorrection + frontCorrection) * CELL);
|
||||
};
|
||||
if (newDimen().X > XRES)
|
||||
frontCorrection.X = backCorrection.X = 0;
|
||||
if (newDimen().Y > YRES)
|
||||
frontCorrection.Y = backCorrection.Y = 0;
|
||||
|
||||
// call Transform to do the transformation we wanted when calling this function
|
||||
translate = v2d_add(translate, v2d_multiply_float(backCorrection, CELL));
|
||||
Transform(m2d_identity, translate, translateReal,
|
||||
int((blockWidth + backCorrection.x + frontCorrection.x) * CELL),
|
||||
int((blockHeight + backCorrection.y + frontCorrection.y) * CELL)
|
||||
);
|
||||
translate += backCorrection * CELL;
|
||||
Transform(Mat2<float>::Identity, translate + backCorrection * CELL, translateReal, newDimen());
|
||||
|
||||
// return how much we corrected. This is used to offset the position of the current stamp
|
||||
// otherwise it would attempt to recenter it with the current size
|
||||
return v2d_add(v2d_multiply_float(backCorrection, -CELL), v2d_multiply_float(frontCorrection, CELL));
|
||||
return backCorrection * (-CELL) + frontCorrection * CELL;
|
||||
}
|
||||
|
||||
void GameSave::Transform(matrix2d transform, vector2d translate)
|
||||
|
||||
|
||||
void GameSave::Transform(Mat2<float> transform, Vec2<float> translate)
|
||||
{
|
||||
int width = blockWidth*CELL, height = blockHeight*CELL, newWidth, newHeight;
|
||||
vector2d tmp, ctl, cbr;
|
||||
vector2d cornerso[4];
|
||||
vector2d translateReal = translate;
|
||||
Vec2<float> cornerso[4] = {
|
||||
Vec2<float>(0, 0),
|
||||
Vec2<float>(blockDimen.X * CELL - 1, 0),
|
||||
Vec2<float>(0, blockDimen.Y * CELL - 1),
|
||||
Vec2<float>(blockDimen.X * CELL - 1, blockDimen.Y * CELL - 1),
|
||||
};
|
||||
// undo any translation caused by rotation
|
||||
cornerso[0] = v2d_new(0,0);
|
||||
cornerso[1] = v2d_new(float(width-1),0);
|
||||
cornerso[2] = v2d_new(0,float(height-1));
|
||||
cornerso[3] = v2d_new(float(width-1),float(height-1));
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
tmp = m2d_multiply_v2d(transform,cornerso[i]);
|
||||
if (i==0) ctl = cbr = tmp; // top left, bottom right corner
|
||||
if (tmp.x<ctl.x) ctl.x = tmp.x;
|
||||
if (tmp.y<ctl.y) ctl.y = tmp.y;
|
||||
if (tmp.x>cbr.x) cbr.x = tmp.x;
|
||||
if (tmp.y>cbr.y) cbr.y = tmp.y;
|
||||
}
|
||||
auto bounds = Rect<float>(transform * cornerso[0]);
|
||||
for (int i = 1; i < 4; i++)
|
||||
bounds |= Rect<float>(transform * cornerso[i]);
|
||||
// casting as int doesn't quite do what we want with negative numbers, so use floor()
|
||||
tmp = v2d_new(floor(ctl.x+0.5f),floor(ctl.y+0.5f));
|
||||
translate = v2d_sub(translate,tmp);
|
||||
newWidth = int(floor(cbr.x+0.5f))-int(floor(ctl.x+0.5f))+1;
|
||||
newHeight = int(floor(cbr.y+0.5f))-int(floor(ctl.y+0.5f))+1;
|
||||
Transform(transform, translate, translateReal, newWidth, newHeight);
|
||||
Vec2<float> translateReal = translate - roundNegInf(bounds.TopLeft);
|
||||
auto newBounds = lroundNegInf(bounds.BottomRight) - lroundNegInf(bounds.TopLeft) + Vec2<int>(1, 1);
|
||||
Transform(transform, translate, translateReal, newBounds);
|
||||
}
|
||||
|
||||
// transform is a matrix describing how we want to rotate this save
|
||||
// translate can vary depending on whether the save is bring rotated, or if a normal translate caused it to expand
|
||||
// translateReal is the original amount we tried to translate, used to calculate wall shifting
|
||||
void GameSave::Transform(matrix2d transform, vector2d translate, vector2d translateReal, int newWidth, int newHeight)
|
||||
void GameSave::Transform(Mat2<float> transform, Vec2<float> translate, Vec2<float> translateReal, Vec2<int> newDimen)
|
||||
{
|
||||
if (newWidth>XRES) newWidth = XRES;
|
||||
if (newHeight>YRES) newHeight = YRES;
|
||||
newDimen.X = std::min(newDimen.X, XRES);
|
||||
newDimen.Y = std::min(newDimen.Y, YRES);
|
||||
|
||||
int x, y, nx, ny, newBlockWidth = newWidth / CELL, newBlockHeight = newHeight / CELL;
|
||||
vector2d pos, vel;
|
||||
Vec2<int> newBlockDimen = newDimen / CELL;
|
||||
|
||||
Plane<unsigned char> blockMapNew(newBlockWidth, newBlockHeight, 0);
|
||||
Plane<float> fanVelXNew(newBlockWidth, newBlockHeight, 0.0f);
|
||||
Plane<float> fanVelYNew(newBlockWidth, newBlockHeight, 0.0f);
|
||||
Plane<float> pressureNew(newBlockWidth, newBlockHeight, 0.0f);
|
||||
Plane<float> velocityXNew(newBlockWidth, newBlockHeight, 0.0f);
|
||||
Plane<float> velocityYNew(newBlockWidth, newBlockHeight, 0.0f);
|
||||
Plane<float> ambientHeatNew(newBlockWidth, newBlockHeight, 0.0f);
|
||||
Plane<unsigned char> blockMapNew(newBlockDimen.X, newBlockDimen.Y, 0);
|
||||
Plane<float> fanVelXNew(newBlockDimen.X, newBlockDimen.Y, 0.0f);
|
||||
Plane<float> fanVelYNew(newBlockDimen.X, newBlockDimen.Y, 0.0f);
|
||||
Plane<float> pressureNew(newBlockDimen.X, newBlockDimen.Y, 0.0f);
|
||||
Plane<float> velocityXNew(newBlockDimen.X, newBlockDimen.Y, 0.0f);
|
||||
Plane<float> velocityYNew(newBlockDimen.X, newBlockDimen.Y, 0.0f);
|
||||
Plane<float> ambientHeatNew(newBlockDimen.X, newBlockDimen.Y, 0.0f);
|
||||
|
||||
// Match these up with the matrices provided in GameView::OnKeyPress.
|
||||
bool patchPipeR = transform.a == 0 && transform.b == 1 && transform.c == -1 && transform.d == 0;
|
||||
bool patchPipeH = transform.a == -1 && transform.b == 0 && transform.c == 0 && transform.d == 1;
|
||||
bool patchPipeV = transform.a == 1 && transform.b == 0 && transform.c == 0 && transform.d == -1;
|
||||
bool patchPipeR = transform == Mat2<float>::CW;
|
||||
bool patchPipeH = transform == Mat2<float>::MirrorX;
|
||||
bool patchPipeV = transform == Mat2<float>::MirrorY;
|
||||
|
||||
// rotate and translate signs, parts, walls
|
||||
for (size_t i = 0; i < signs.size(); i++)
|
||||
auto bounds = Rect<int>(Vec2<int>::Zero, newDimen - Vec2<int>(1, 1));
|
||||
for (auto &sign : signs)
|
||||
{
|
||||
pos = v2d_new(float(signs[i].x), float(signs[i].y));
|
||||
pos = v2d_add(m2d_multiply_v2d(transform,pos),translate);
|
||||
nx = int(floor(pos.x+0.5f));
|
||||
ny = int(floor(pos.y+0.5f));
|
||||
if (nx<0 || nx>=newWidth || ny<0 || ny>=newHeight)
|
||||
auto pos = lroundNegInf(transform * Vec2<float>(sign.x, sign.y) + translate);
|
||||
if (!bounds.Contains(pos))
|
||||
{
|
||||
signs[i].text[0] = 0;
|
||||
sign.text[0] = 0;
|
||||
continue;
|
||||
}
|
||||
signs[i].x = nx;
|
||||
signs[i].y = ny;
|
||||
sign.x = pos.X;
|
||||
sign.y = pos.Y;
|
||||
}
|
||||
for (int i = 0; i < particlesCount; i++)
|
||||
{
|
||||
if (!particles[i].type) continue;
|
||||
pos = v2d_new(particles[i].x, particles[i].y);
|
||||
pos = v2d_add(m2d_multiply_v2d(transform,pos),translate);
|
||||
nx = int(floor(pos.x+0.5f));
|
||||
ny = int(floor(pos.y+0.5f));
|
||||
if (nx<0 || nx>=newWidth || ny<0 || ny>=newHeight)
|
||||
auto pos = lroundNegInf(transform * Vec2<float>(particles[i].x, particles[i].y) + translate);
|
||||
if (!bounds.Contains(pos))
|
||||
{
|
||||
particles[i].type = PT_NONE;
|
||||
continue;
|
||||
}
|
||||
particles[i].x = float(nx);
|
||||
particles[i].y = float(ny);
|
||||
vel = v2d_new(particles[i].vx, particles[i].vy);
|
||||
vel = m2d_multiply_v2d(transform, vel);
|
||||
particles[i].vx = vel.x;
|
||||
particles[i].vy = vel.y;
|
||||
particles[i].x = pos.X;
|
||||
particles[i].y = pos.Y;
|
||||
auto vel = transform * Vec2<float>(particles[i].vx, particles[i].vy);
|
||||
particles[i].vx = vel.X;
|
||||
particles[i].vy = vel.Y;
|
||||
if (particles[i].type == PT_PIPE || particles[i].type == PT_PPIP)
|
||||
{
|
||||
if (patchPipeR)
|
||||
@ -286,49 +253,49 @@ void GameSave::Transform(matrix2d transform, vector2d translate, vector2d transl
|
||||
}
|
||||
|
||||
// translate walls and other grid items when the stamp is shifted more than 4 pixels in any direction
|
||||
int translateX = 0, translateY = 0;
|
||||
if (translateReal.x > 0 && ((int)translated.x%CELL == 3
|
||||
|| (translated.x < 0 && (int)translated.x%CELL == 0)))
|
||||
translateX = CELL;
|
||||
else if (translateReal.x < 0 && ((int)translated.x%CELL == -3
|
||||
|| (translated.x > 0 && (int)translated.x%CELL == 0)))
|
||||
translateX = -CELL;
|
||||
if (translateReal.y > 0 && ((int)translated.y%CELL == 3
|
||||
|| (translated.y < 0 && (int)translated.y%CELL == 0)))
|
||||
translateY = CELL;
|
||||
else if (translateReal.y < 0 && ((int)translated.y%CELL == -3
|
||||
|| (translated.y > 0 && (int)translated.y%CELL == 0)))
|
||||
translateY = -CELL;
|
||||
Vec2<int> blockTranslate = Vec2<int>::Zero;
|
||||
if (translateReal.X > 0 && ((int)translated.X%CELL == 3
|
||||
|| (translated.X < 0 && (int)translated.X%CELL == 0)))
|
||||
blockTranslate.X = CELL;
|
||||
else if (translateReal.X < 0 && ((int)translated.X%CELL == -3
|
||||
|| (translated.X > 0 && (int)translated.X%CELL == 0)))
|
||||
blockTranslate.X = -CELL;
|
||||
if (translateReal.Y > 0 && ((int)translated.Y%CELL == 3
|
||||
|| (translated.Y < 0 && (int)translated.Y%CELL == 0)))
|
||||
blockTranslate.Y = CELL;
|
||||
else if (translateReal.Y < 0 && ((int)translated.Y%CELL == -3
|
||||
|| (translated.Y > 0 && (int)translated.Y%CELL == 0)))
|
||||
blockTranslate.Y = -CELL;
|
||||
|
||||
for (y=0; y<blockHeight; y++)
|
||||
for (x=0; x<blockWidth; x++)
|
||||
auto blockBounds = Rect<int>(Vec2<int>::Zero, newBlockDimen - Vec2<int>(1, 1));
|
||||
for (int y=0; y<blockDimen.Y; y++)
|
||||
for (int x=0; x<blockDimen.X; x++)
|
||||
{
|
||||
pos = v2d_new(x*CELL+CELL*0.4f+translateX, y*CELL+CELL*0.4f+translateY);
|
||||
pos = v2d_add(m2d_multiply_v2d(transform,pos),translate);
|
||||
nx = int(pos.x/CELL);
|
||||
ny = int(pos.y/CELL);
|
||||
if (pos.x<0 || nx>=newBlockWidth || pos.y<0 || ny>=newBlockHeight)
|
||||
auto pos = Vec2<float>(x * CELL + CELL * 0.4f, y * CELL + CELL * 0.4f) + blockTranslate;
|
||||
pos = transform * pos + translate;
|
||||
auto ipos = Vec2<int>(pos / CELL);
|
||||
if (!blockBounds.Contains(ipos))
|
||||
continue;
|
||||
|
||||
int nx = ipos.X, ny = ipos.Y;
|
||||
if (blockMap[y][x])
|
||||
{
|
||||
blockMapNew[ny][nx] = blockMap[y][x];
|
||||
if (blockMap[y][x]==WL_FAN)
|
||||
{
|
||||
vel = v2d_new(fanVelX[y][x], fanVelY[y][x]);
|
||||
vel = m2d_multiply_v2d(transform, vel);
|
||||
fanVelXNew[ny][nx] = vel.x;
|
||||
fanVelYNew[ny][nx] = vel.y;
|
||||
auto vel = transform * Vec2<float>(fanVelX[y][x], fanVelY[y][x]);
|
||||
fanVelXNew[ny][nx] = vel.X;
|
||||
fanVelYNew[ny][nx] = vel.Y;
|
||||
}
|
||||
}
|
||||
pressureNew[ny][nx] = pressure[y][x];
|
||||
velocityXNew[ny][nx] = velocityX[y][x];
|
||||
velocityXNew[ny][nx] = velocityX[y][x]; // TODO: shouldn't this be transformed?
|
||||
velocityYNew[ny][nx] = velocityY[y][x];
|
||||
ambientHeatNew[ny][nx] = ambientHeat[y][x];
|
||||
}
|
||||
translated = v2d_add(m2d_multiply_v2d(transform, translated), translateReal);
|
||||
translated = transform * translated + translateReal;
|
||||
|
||||
blockWidth = newBlockWidth;
|
||||
blockHeight = newBlockHeight;
|
||||
blockDimen = newBlockDimen;
|
||||
|
||||
blockMap = blockMapNew;
|
||||
fanVelX = fanVelXNew;
|
||||
@ -451,7 +418,7 @@ void GameSave::readOPS(const std::vector<char> &data)
|
||||
if (blockX+blockW > XCELLS || blockY+blockH > YCELLS)
|
||||
throw ParseException(ParseException::InvalidDimensions, "Save too large");
|
||||
|
||||
setSize(blockW, blockH);
|
||||
setSize(Vec2<int>(blockW, blockH));
|
||||
|
||||
bsonDataLen = ((unsigned)inputData[8]);
|
||||
bsonDataLen |= ((unsigned)inputData[9]) << 8;
|
||||
@ -1322,7 +1289,7 @@ void GameSave::readPSv(const std::vector<char> &dataVec)
|
||||
default: throw ParseException(ParseException::Corrupt, String::Build("Cannot decompress: status ", int(status)));
|
||||
}
|
||||
|
||||
setSize(bw, bh);
|
||||
setSize(Vec2<int>(bw, bh));
|
||||
const auto *data = reinterpret_cast<unsigned char *>(&bsonData[0]);
|
||||
dataLength = bsonData.size();
|
||||
|
||||
@ -1920,20 +1887,20 @@ std::pair<bool, std::vector<char>> GameSave::serialiseOPS() const
|
||||
fullY = blockY*CELL;
|
||||
|
||||
//Original size + offset of original corner from snapped corner, rounded up by adding CELL-1
|
||||
blockW = blockWidth;//(blockWidth-fullX+CELL-1)/CELL;
|
||||
blockH = blockHeight;//(blockHeight-fullY+CELL-1)/CELL;
|
||||
blockW = blockDimen.X;//(blockDimen.X-fullX+CELL-1)/CELL;
|
||||
blockH = blockDimen.Y;//(blockDimen.Y-fullY+CELL-1)/CELL;
|
||||
fullW = blockW*CELL;
|
||||
fullH = blockH*CELL;
|
||||
|
||||
// Copy fan and wall data
|
||||
std::vector<unsigned char> wallData(blockWidth*blockHeight);
|
||||
std::vector<unsigned char> wallData(blockDimen.X*blockDimen.Y);
|
||||
bool hasWallData = false;
|
||||
std::vector<unsigned char> fanData(blockWidth*blockHeight*2);
|
||||
std::vector<unsigned char> pressData(blockWidth*blockHeight*2);
|
||||
std::vector<unsigned char> vxData(blockWidth*blockHeight*2);
|
||||
std::vector<unsigned char> vyData(blockWidth*blockHeight*2);
|
||||
std::vector<unsigned char> ambientData(blockWidth*blockHeight*2, 0);
|
||||
unsigned int wallDataLen = blockWidth*blockHeight, fanDataLen = 0, pressDataLen = 0, vxDataLen = 0, vyDataLen = 0, ambientDataLen = 0;
|
||||
std::vector<unsigned char> fanData(blockDimen.X*blockDimen.Y*2);
|
||||
std::vector<unsigned char> pressData(blockDimen.X*blockDimen.Y*2);
|
||||
std::vector<unsigned char> vxData(blockDimen.X*blockDimen.Y*2);
|
||||
std::vector<unsigned char> vyData(blockDimen.X*blockDimen.Y*2);
|
||||
std::vector<unsigned char> ambientData(blockDimen.X*blockDimen.Y*2, 0);
|
||||
unsigned int wallDataLen = blockDimen.X*blockDimen.Y, fanDataLen = 0, pressDataLen = 0, vxDataLen = 0, vyDataLen = 0, ambientDataLen = 0;
|
||||
|
||||
for (x = blockX; x < blockX+blockW; x++)
|
||||
{
|
||||
|
@ -2,7 +2,6 @@
|
||||
#include "common/String.h"
|
||||
#include "simulation/Sign.h"
|
||||
#include "simulation/Particle.h"
|
||||
#include "Misc.h"
|
||||
#include "SimulationConfig.h"
|
||||
#include <vector>
|
||||
#include <json/json.h>
|
||||
@ -78,14 +77,13 @@ struct Plane
|
||||
class GameSave
|
||||
{
|
||||
// number of pixels translated. When translating CELL pixels, shift all CELL grids
|
||||
vector2d translated = { 0, 0 };
|
||||
Vec2<float> translated = Vec2<float>::Zero;
|
||||
void readOPS(const std::vector<char> &data);
|
||||
void readPSv(const std::vector<char> &data);
|
||||
std::pair<bool, std::vector<char>> serialiseOPS() const;
|
||||
|
||||
public:
|
||||
int blockWidth = 0;
|
||||
int blockHeight = 0;
|
||||
Vec2<int> blockDimen = Vec2<int>::Zero;
|
||||
bool fromNewerVersion = false;
|
||||
int majorVersion = 0;
|
||||
int minorVersion = 0;
|
||||
@ -130,14 +128,14 @@ public:
|
||||
|
||||
int pmapbits = 8; // default to 8 bits for older saves
|
||||
|
||||
GameSave(int width, int height);
|
||||
GameSave(Vec2<int> blockDimen);
|
||||
GameSave(const std::vector<char> &data, bool newWantAuthors = true);
|
||||
void setSize(int width, int height);
|
||||
void setSize(Vec2<int> dimen);
|
||||
// return value is [ fakeFromNewerVersion, gameData ]
|
||||
std::pair<bool, std::vector<char>> Serialise() const;
|
||||
vector2d Translate(vector2d translate);
|
||||
void Transform(matrix2d transform, vector2d translate);
|
||||
void Transform(matrix2d transform, vector2d translate, vector2d translateReal, int newWidth, int newHeight);
|
||||
Vec2<float> Translate(Vec2<float> translate);
|
||||
void Transform(Mat2<float> transform, Vec2<float> translate);
|
||||
void Transform(Mat2<float> transform, Vec2<float> translate, Vec2<float> translateReal, Vec2<int> newDimen);
|
||||
|
||||
void Expand(const std::vector<char> &data);
|
||||
|
||||
|
212
src/common/Geometry.h
Normal file
212
src/common/Geometry.h
Normal file
@ -0,0 +1,212 @@
|
||||
#pragma once
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <utility>
|
||||
#include <type_traits>
|
||||
|
||||
template<typename T, typename = std::enable_if<std::is_arithmetic_v<T>, void>>
|
||||
struct Rect;
|
||||
|
||||
template<typename T, typename = std::enable_if<std::is_arithmetic_v<T>, void>>
|
||||
struct Vec2
|
||||
{
|
||||
T X, Y;
|
||||
|
||||
constexpr Vec2(T x, T y):
|
||||
X(x),
|
||||
Y(y)
|
||||
{
|
||||
}
|
||||
|
||||
template<typename S, typename = std::enable_if<std::is_constructible_v<T, S>, void>>
|
||||
constexpr explicit Vec2(Vec2<S> other):
|
||||
X(other.X),
|
||||
Y(other.Y)
|
||||
{
|
||||
}
|
||||
|
||||
inline bool operator==(Vec2<T> other) const
|
||||
{
|
||||
return X == other.X && Y == other.Y;
|
||||
}
|
||||
|
||||
inline bool operator!=(Vec2<T> other) const
|
||||
{
|
||||
return X != other.X || Y != other.Y;
|
||||
}
|
||||
|
||||
template<typename S>
|
||||
constexpr inline Vec2<decltype(std::declval<T>() + std::declval<S>())> operator+(Vec2<S> other) const
|
||||
{
|
||||
return Vec2(X + other.X, Y + other.Y);
|
||||
}
|
||||
|
||||
inline Vec2<T> operator-() const
|
||||
{
|
||||
return Vec2(-X, -Y);
|
||||
}
|
||||
|
||||
template<typename S>
|
||||
inline Vec2<decltype(std::declval<T>() - std::declval<S>())> operator-(Vec2<S> other) const
|
||||
{
|
||||
return Vec2(X - other.X, Y - other.Y);
|
||||
}
|
||||
|
||||
template<typename S, typename = std::enable_if<std::is_arithmetic_v<S>, void>>
|
||||
constexpr inline Vec2<decltype(std::declval<T>() * std::declval<S>())> operator*(S other) const
|
||||
{
|
||||
return Vec2(X * other, Y * other);
|
||||
}
|
||||
|
||||
template<typename S, typename = std::enable_if<std::is_arithmetic_v<S>, void>>
|
||||
inline Vec2<decltype(std::declval<T>() / std::declval<S>())> operator/(S other) const
|
||||
{
|
||||
return Vec2(X / other, Y / other);
|
||||
}
|
||||
|
||||
template<typename S>
|
||||
inline Vec2<T> &operator+=(Vec2<S> other)
|
||||
{
|
||||
return *this = *this + other;
|
||||
}
|
||||
|
||||
template<typename S>
|
||||
inline Vec2<T> &operator-=(Vec2<S> other)
|
||||
{
|
||||
return *this = *this - other;
|
||||
}
|
||||
|
||||
template<typename S>
|
||||
inline Vec2<T> &operator*=(Vec2<S> other)
|
||||
{
|
||||
return *this = *this * other;
|
||||
}
|
||||
|
||||
template<typename S>
|
||||
inline Vec2<T> &operator/=(Vec2<S> other)
|
||||
{
|
||||
return *this = *this / other;
|
||||
}
|
||||
|
||||
inline Vec2<T> Floor() const
|
||||
{
|
||||
return Vec2<T>(std::floor(X), std::floor(Y));
|
||||
}
|
||||
|
||||
// Return a rectangle starting at origin, whose dimensions match this vector
|
||||
template<typename = std::enable_if<std::is_integral_v<T>, void>>
|
||||
inline Rect<T> OriginRect() const
|
||||
{
|
||||
return RectSized(Vec2<T>::Zero, *this);
|
||||
}
|
||||
|
||||
constexpr static Vec2<T> Zero = Vec2<T>(0, 0);
|
||||
};
|
||||
|
||||
template<typename T, typename = std::enable_if<std::is_arithmetic_v<T>, void>>
|
||||
struct Mat2
|
||||
{
|
||||
// ⎛A B⎞
|
||||
// ⎝C D⎠, acting on column vectors
|
||||
T A, B, C, D;
|
||||
|
||||
constexpr Mat2(T a, T b, T c, T d):
|
||||
A(a),
|
||||
B(b),
|
||||
C(c),
|
||||
D(d)
|
||||
{
|
||||
}
|
||||
|
||||
inline bool operator==(Mat2<T> other) const
|
||||
{
|
||||
return A == other.A && B == other.B && C == other.C && D == other.D;
|
||||
}
|
||||
|
||||
inline bool operator!=(Mat2<T> other) const
|
||||
{
|
||||
return A != other.A || B != other.B || C != other.C || D != other.D;
|
||||
}
|
||||
|
||||
template<typename S>
|
||||
inline Vec2<decltype(std::declval<T>() * std::declval<S>())> operator*(Vec2<S> vec) const
|
||||
{
|
||||
return Vec2<decltype(std::declval<T>() * std::declval<S>())>(A * vec.X + B * vec.Y, C * vec.X + D * vec.Y);
|
||||
}
|
||||
|
||||
constexpr static Mat2<T> Identity = Mat2(1, 0, 0, 1);
|
||||
constexpr static Mat2<T> MirrorX = Mat2(-1, 0, 0, 1);
|
||||
constexpr static Mat2<T> MirrorY = Mat2(1, 0, 0, -1);
|
||||
constexpr static Mat2<T> CCW = Mat2(0, 1, -1, 0); // reminder: the Y axis points down
|
||||
};
|
||||
|
||||
template<typename T, typename = std::enable_if<std::is_arithmetic_v<T>, void>>
|
||||
static inline Rect<T> RectBetween(Vec2<T>, Vec2<T>);
|
||||
|
||||
template<typename T, typename>
|
||||
struct Rect
|
||||
{
|
||||
// Inclusive
|
||||
Vec2<T> TopLeft, BottomRight;
|
||||
|
||||
private:
|
||||
constexpr Rect(Vec2<T> topLeft, Vec2<T> bottomRight):
|
||||
TopLeft(topLeft),
|
||||
BottomRight(bottomRight)
|
||||
{
|
||||
}
|
||||
friend Rect<T> RectBetween<T>(Vec2<T>, Vec2<T>);
|
||||
|
||||
public:
|
||||
inline Rect<T> operator|(Rect<T> other) const
|
||||
{
|
||||
return Rect<T>(
|
||||
Vec2<T>(std::min(TopLeft.X, other.TopLeft.X), std::min(TopLeft.Y, other.TopLeft.Y)),
|
||||
Vec2<T>(std::max(BottomRight.X, other.BottomRight.X), std::max(BottomRight.Y, other.BottomRight.Y))
|
||||
);
|
||||
}
|
||||
|
||||
inline Rect<T> &operator|=(Rect<T> other)
|
||||
{
|
||||
return *this = *this | other;
|
||||
}
|
||||
|
||||
inline bool Contains(Vec2<T> point) const
|
||||
{
|
||||
return point.X >= TopLeft.X && point.X <= BottomRight.X && point.Y >= TopLeft.Y && point.Y <= BottomRight.Y;
|
||||
}
|
||||
|
||||
inline Vec2<T> Clamp(Vec2<T> point) const
|
||||
{
|
||||
return Vec2<T>(std::clamp(point.X, TopLeft.X, BottomRight.X), std::clamp(point.Y, TopLeft.Y, BottomRight.Y));
|
||||
}
|
||||
|
||||
inline Rect<T> Clamp(Rect<T> other) const
|
||||
{
|
||||
return Rect<T>(Clamp(other.TopLeft), Clamp(other.BottomRight));
|
||||
}
|
||||
|
||||
template<typename = std::enable_if<std::is_integral_v<T>, void>>
|
||||
inline Vec2<T> Size() const
|
||||
{
|
||||
return BottomRight - TopLeft + Vec2<T>(1, 1);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T, typename>
|
||||
static inline Rect<T> RectBetween(Vec2<T> topLeft, Vec2<T> bottomRight)
|
||||
{
|
||||
return Rect<T>(topLeft, bottomRight);
|
||||
}
|
||||
|
||||
template<typename T, typename = std::enable_if<std::is_arithmetic_v<T>, void>>
|
||||
static inline Rect<T> RectAt(Vec2<T> pos)
|
||||
{
|
||||
return RectBetween<T>(pos, pos);
|
||||
}
|
||||
|
||||
template<typename T, typename = std::enable_if<std::is_integral_v<T>, void>>
|
||||
static inline Rect<T> RectSized(Vec2<T> topLeft, Vec2<T> dimen)
|
||||
{
|
||||
return RectBetween<T>(topLeft, topLeft + dimen - Vec2<T>(1, 1));
|
||||
}
|
@ -422,18 +422,17 @@ void GameController::LoadStamp(GameSave *stamp)
|
||||
|
||||
void GameController::TranslateSave(ui::Point point)
|
||||
{
|
||||
vector2d translate = v2d_new(float(point.X), float(point.Y));
|
||||
vector2d translated = gameModel->GetPlaceSave()->Translate(translate);
|
||||
auto translate = Vec2<float>(point);
|
||||
auto translated = gameModel->GetPlaceSave()->Translate(translate);
|
||||
ui::Point currentPlaceSaveOffset = gameView->GetPlaceSaveOffset();
|
||||
// resets placeSaveOffset to 0, which is why we back it up first
|
||||
gameModel->SetPlaceSave(gameModel->GetPlaceSave());
|
||||
gameView->SetPlaceSaveOffset(ui::Point(int(translated.x), int(translated.y)) + currentPlaceSaveOffset);
|
||||
gameView->SetPlaceSaveOffset(ui::Point(translated) + currentPlaceSaveOffset);
|
||||
}
|
||||
|
||||
void GameController::TransformSave(matrix2d transform)
|
||||
void GameController::TransformSave(Mat2<float> transform)
|
||||
{
|
||||
vector2d translate = v2d_zero;
|
||||
gameModel->GetPlaceSave()->Transform(transform, translate);
|
||||
gameModel->GetPlaceSave()->Transform(transform, Vec2<float>::Zero);
|
||||
gameModel->SetPlaceSave(gameModel->GetPlaceSave());
|
||||
}
|
||||
|
||||
@ -928,7 +927,7 @@ void GameController::SetToolStrength(float value)
|
||||
|
||||
void GameController::SetZoomPosition(ui::Point position)
|
||||
{
|
||||
ui::Point zoomPosition = position-(gameModel->GetZoomSize()/2);
|
||||
ui::Point zoomPosition = position - ui::Point(1, 1) * gameModel->GetZoomSize() / 2;
|
||||
if(zoomPosition.X < 0)
|
||||
zoomPosition.X = 0;
|
||||
if(zoomPosition.Y < 0)
|
||||
|
@ -1,10 +1,10 @@
|
||||
#pragma once
|
||||
#include "client/ClientListener.h"
|
||||
#include "common/Geometry.h"
|
||||
#include "gui/interface/Point.h"
|
||||
#include "gui/interface/Colour.h"
|
||||
#include "simulation/Sign.h"
|
||||
#include "simulation/Particle.h"
|
||||
#include "Misc.h"
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
#include <memory>
|
||||
@ -153,7 +153,7 @@ public:
|
||||
void HideConsole();
|
||||
void FrameStep();
|
||||
void TranslateSave(ui::Point point);
|
||||
void TransformSave(matrix2d transform);
|
||||
void TransformSave(Mat2<float> transform);
|
||||
bool MouseInZoom(ui::Point position);
|
||||
ui::Point PointTranslate(ui::Point point);
|
||||
ui::Point PointTranslateNoClamp(ui::Point point);
|
||||
|
@ -1364,17 +1364,17 @@ void GameView::OnKeyPress(int key, int scan, bool repeat, bool shift, bool ctrl,
|
||||
if (ctrl && shift)
|
||||
{
|
||||
//Vertical flip
|
||||
c->TransformSave(m2d_new(1,0,0,-1));
|
||||
c->TransformSave(Mat2<float>::MirrorY);
|
||||
}
|
||||
else if (!ctrl && shift)
|
||||
{
|
||||
//Horizontal flip
|
||||
c->TransformSave(m2d_new(-1,0,0,1));
|
||||
c->TransformSave(Mat2<float>::MirrorX);
|
||||
}
|
||||
else
|
||||
{
|
||||
//Rotate 90deg
|
||||
c->TransformSave(m2d_new(0,1,-1,0));
|
||||
c->TransformSave(Mat2<float>::CW);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -113,7 +113,7 @@ void DirectionSelector::Draw(const ui::Point& screenPos)
|
||||
{
|
||||
Graphics * g = GetGraphics();
|
||||
auto handleTrackRadius = radius + handleRadius;
|
||||
ui::Point center = screenPos + handleTrackRadius;
|
||||
ui::Point center = screenPos + ui::Point(1, 1) * handleTrackRadius;
|
||||
|
||||
g->fillcircle(center.X, center.Y, handleTrackRadius, handleTrackRadius, backgroundColor.Red, backgroundColor.Green, backgroundColor.Blue, backgroundColor.Alpha);
|
||||
g->drawcircle(center.X, center.Y, handleTrackRadius, handleTrackRadius, borderColor.Red, borderColor.Green, borderColor.Blue, borderColor.Alpha);
|
||||
|
@ -1,142 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include "common/Geometry.h"
|
||||
|
||||
namespace ui
|
||||
{
|
||||
|
||||
//Lightweight 2D Int32/Float32 Point struct for UI
|
||||
struct Point
|
||||
{
|
||||
using POINT_T = int;
|
||||
|
||||
POINT_T X;
|
||||
POINT_T Y;
|
||||
|
||||
Point(POINT_T x, POINT_T y)
|
||||
: X(x)
|
||||
, Y(y)
|
||||
{
|
||||
}
|
||||
|
||||
inline Point operator - () const
|
||||
{
|
||||
return Point(-X, -Y);
|
||||
}
|
||||
|
||||
inline Point operator + (const Point& v) const
|
||||
{
|
||||
return Point(X + v.X, Y + v.Y);
|
||||
}
|
||||
|
||||
inline Point operator + (const int v) const
|
||||
{
|
||||
return Point(X + v, Y + v);
|
||||
}
|
||||
|
||||
inline Point operator - (const Point& v) const
|
||||
{
|
||||
return Point(X - v.X, Y - v.Y);
|
||||
}
|
||||
|
||||
inline Point operator - (const int v) const
|
||||
{
|
||||
return Point(X - v, Y - v);
|
||||
}
|
||||
|
||||
inline Point operator * (const Point& v) const
|
||||
{
|
||||
return Point(X * v.X, Y * v.Y);
|
||||
}
|
||||
|
||||
inline Point operator * (int v) const
|
||||
{
|
||||
return Point(X * static_cast<POINT_T>(v), Y * static_cast<POINT_T>(v));
|
||||
}
|
||||
|
||||
inline Point operator * (float v) const
|
||||
{
|
||||
return Point(X * static_cast<POINT_T>(v), Y * static_cast<POINT_T>(v));
|
||||
}
|
||||
|
||||
inline Point operator / (const Point& v) const
|
||||
{
|
||||
return Point(X / v.X, Y / v.Y);
|
||||
}
|
||||
|
||||
inline Point operator / (int v) const
|
||||
{
|
||||
return Point(X / static_cast<POINT_T>(v), Y / static_cast<POINT_T>(v));
|
||||
}
|
||||
|
||||
inline Point operator / (float v) const
|
||||
{
|
||||
return Point(X / static_cast<POINT_T>(v), Y / static_cast<POINT_T>(v));
|
||||
}
|
||||
|
||||
inline void operator += (const Point& v)
|
||||
{
|
||||
X += v.X;
|
||||
Y += v.Y;
|
||||
}
|
||||
|
||||
inline void operator -= (const Point& v)
|
||||
{
|
||||
X -= v.X;
|
||||
Y -= v.Y;
|
||||
}
|
||||
|
||||
inline void operator *= (const Point& v)
|
||||
{
|
||||
X *= v.X;
|
||||
Y *= v.Y;
|
||||
}
|
||||
|
||||
inline void operator *= (int v)
|
||||
{
|
||||
X *= static_cast<POINT_T>(v);
|
||||
Y *= static_cast<POINT_T>(v);
|
||||
}
|
||||
|
||||
inline void operator *= (float v)
|
||||
{
|
||||
X *= static_cast<POINT_T>(v);
|
||||
Y *= static_cast<POINT_T>(v);
|
||||
}
|
||||
|
||||
inline void operator /= (const Point& v)
|
||||
{
|
||||
X /= v.X;
|
||||
Y /= v.Y;
|
||||
}
|
||||
|
||||
inline void operator /= (int v)
|
||||
{
|
||||
X /= static_cast<POINT_T>(v);
|
||||
Y /= static_cast<POINT_T>(v);
|
||||
}
|
||||
|
||||
inline void operator /= (float v)
|
||||
{
|
||||
X /= static_cast<POINT_T>(v);
|
||||
Y /= static_cast<POINT_T>(v);
|
||||
}
|
||||
|
||||
inline bool operator == (const Point& v) const
|
||||
{
|
||||
return (X == v.X && Y == v.Y);
|
||||
}
|
||||
|
||||
inline bool operator != (const Point& v) const
|
||||
{
|
||||
return (X != v.X || Y != v.Y);
|
||||
}
|
||||
|
||||
inline Point operator = (const Point& v)
|
||||
{
|
||||
X = v.X;
|
||||
Y = v.Y;
|
||||
return Point(X, Y);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
using Point = Vec2<int>;
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
#include "Misc.h"
|
||||
#include "Simulation.h"
|
||||
#include "Sample.h"
|
||||
#include "SimTool.h"
|
||||
|
@ -35,8 +35,8 @@ VideoBuffer * SaveRenderer::Render(GameSave * save, bool decorations, bool fire,
|
||||
|
||||
int width, height;
|
||||
VideoBuffer * tempThumb = NULL;
|
||||
width = save->blockWidth;
|
||||
height = save->blockHeight;
|
||||
width = save->blockDimen.X;
|
||||
height = save->blockDimen.Y;
|
||||
|
||||
g->Clear();
|
||||
sim->clear_sim();
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "common/tpt-rand.h"
|
||||
#include "common/tpt-thread-local.h"
|
||||
#include "gui/game/Brush.h"
|
||||
#include "Misc.h"
|
||||
#include <iostream>
|
||||
#include <set>
|
||||
|
||||
@ -305,9 +306,9 @@ int Simulation::Load(const GameSave * originalSave, bool includePressure, int fu
|
||||
signs.push_back(tempSign);
|
||||
}
|
||||
}
|
||||
for(int saveBlockX = 0; saveBlockX < save->blockWidth; saveBlockX++)
|
||||
for(int saveBlockX = 0; saveBlockX < save->blockDimen.X; saveBlockX++)
|
||||
{
|
||||
for(int saveBlockY = 0; saveBlockY < save->blockHeight; saveBlockY++)
|
||||
for(int saveBlockY = 0; saveBlockY < save->blockDimen.Y; saveBlockY++)
|
||||
{
|
||||
if(save->blockMap[saveBlockY][saveBlockX])
|
||||
{
|
||||
@ -368,7 +369,7 @@ GameSave * Simulation::Save(bool includePressure, int fullX, int fullY, int full
|
||||
blockW = blockX2-blockX;
|
||||
blockH = blockY2-blockY;
|
||||
|
||||
GameSave * newSave = new GameSave(blockW, blockH);
|
||||
GameSave * newSave = new GameSave(Vec2<int>(blockW, blockH));
|
||||
auto &possiblyCarriesType = Particle::PossiblyCarriesType();
|
||||
auto &properties = Particle::GetProperties();
|
||||
|
||||
@ -457,9 +458,9 @@ GameSave * Simulation::Save(bool includePressure, int fullX, int fullY, int full
|
||||
}
|
||||
}
|
||||
|
||||
for(int saveBlockX = 0; saveBlockX < newSave->blockWidth; saveBlockX++)
|
||||
for(int saveBlockX = 0; saveBlockX < newSave->blockDimen.X; saveBlockX++)
|
||||
{
|
||||
for(int saveBlockY = 0; saveBlockY < newSave->blockHeight; saveBlockY++)
|
||||
for(int saveBlockY = 0; saveBlockY < newSave->blockDimen.Y; saveBlockY++)
|
||||
{
|
||||
if(bmap[saveBlockY+blockY][saveBlockX+blockX])
|
||||
{
|
||||
|
@ -23,8 +23,6 @@ class Snapshot;
|
||||
class SimTool;
|
||||
class Brush;
|
||||
class SimulationSample;
|
||||
struct matrix2d;
|
||||
struct vector2d;
|
||||
|
||||
class Simulation;
|
||||
class Renderer;
|
||||
|
Reference in New Issue
Block a user