diff --git a/blooblib/blooblib.vcxproj b/blooblib/blooblib.vcxproj
index bdbfeb2..2d5b8a1 100644
--- a/blooblib/blooblib.vcxproj
+++ b/blooblib/blooblib.vcxproj
@@ -19,6 +19,7 @@
+
@@ -42,6 +43,7 @@
+
diff --git a/blooblib/blooblib.vcxproj.filters b/blooblib/blooblib.vcxproj.filters
index 13723f1..c522456 100644
--- a/blooblib/blooblib.vcxproj.filters
+++ b/blooblib/blooblib.vcxproj.filters
@@ -42,6 +42,9 @@
Source Files
+
+ Source Files
+
@@ -83,6 +86,9 @@
Header Files
+
+ Header Files
+
diff --git a/blooblib/blooblib.vcxproj.user b/blooblib/blooblib.vcxproj.user
index 5df420f..966b4ff 100644
--- a/blooblib/blooblib.vcxproj.user
+++ b/blooblib/blooblib.vcxproj.user
@@ -1,6 +1,6 @@
- false
+ true
\ No newline at end of file
diff --git a/blooblib/include/bloob.h b/blooblib/include/bloob.h
index 97d7621..0b61299 100644
--- a/blooblib/include/bloob.h
+++ b/blooblib/include/bloob.h
@@ -4,6 +4,7 @@
#include "game.h"
#include "image.h"
#include "ini.h"
+#include "math_util.h"
#include "rect.h"
#include "resource.h"
#include "resource_manager.h"
@@ -12,8 +13,6 @@
#include "util.h"
#include "vec2.h"
-const double PI = 3.141592653589793238462643383279502884197169399375105820974944592307816406286;
-const double TAU = PI * 2;
/*
diff --git a/blooblib/include/game.hpp b/blooblib/include/game.hpp
deleted file mode 100644
index e69de29..0000000
diff --git a/blooblib/include/image.h b/blooblib/include/image.h
index 2da655c..1eb96b2 100644
--- a/blooblib/include/image.h
+++ b/blooblib/include/image.h
@@ -10,6 +10,12 @@
using color = uint32_t;
struct ini;
+enum class upscaler {
+ none, scale2x, scale3x, lcd3x, rgb3x, bilinear3x, hatch3x
+};
+
+int upscaler_scale(upscaler upscaler);
+
struct image : resource {
image(resource_manager& rm, ini_category const* ini, std::string const& path, std::vector const& data);
image(image const& other);
@@ -23,6 +29,7 @@ struct image : resource {
color* raw_pointer() const;
color get(vec2i pos) const;
+ color get_safe(vec2i pos) const;
void clear(color color);
@@ -30,11 +37,19 @@ struct image : resource {
void draw(image const* image, vec2i pos, recti src_rect);
void draw(image const* image, vec2i pos, color color);
void draw(image const* image, vec2i pos, color color, recti src_rect);
- void draw_upscaled(image const* image);
+ //void draw_upscaled(image const* image);
+
+ void draw_rot(image const* image, vec2i pos, double rot);
+ void draw_rot(image const* image, vec2i pos, recti src_rect, double rot);
+
+ void draw_upscaled(image const* image, upscaler upscaler);
+ void draw_upscaled(image const* image, std::vector upscalers);
+ image const* upscale_eagle_2x() const;
void draw(std::string const& str, vec2i pos, font const* font, color color);
void draw(std::string const& str, vec2i pos, font const* font, color color1, color color2);
private:
+ void draw_upscaled(image const* image, vec2i size, upscaler upscaler);
bool _alpha;
bool _borrowed_pointer; //to know if to free or not
color* _data; //not a vector so can wrap sdl surfaces
diff --git a/blooblib/include/math_util.h b/blooblib/include/math_util.h
new file mode 100644
index 0000000..6f8246e
--- /dev/null
+++ b/blooblib/include/math_util.h
@@ -0,0 +1,5 @@
+#pragma once
+
+
+const double PI = 3.141592653589793238462643383279502884197169399375105820974944592307816406286;
+const double TAU = (PI * 2);
\ No newline at end of file
diff --git a/blooblib/include/vec2.ipp b/blooblib/include/vec2.ipp
deleted file mode 100644
index e69de29..0000000
diff --git a/blooblib/src/draw/draw_image.cpp b/blooblib/src/draw/draw_image.cpp
index db93855..a1f6534 100644
--- a/blooblib/src/draw/draw_image.cpp
+++ b/blooblib/src/draw/draw_image.cpp
@@ -1,4 +1,5 @@
#include "image.h"
+#include "math_util.h"
void image::draw(image const* image, vec2i pos) {
draw(image, pos, image->bounds());
@@ -22,16 +23,12 @@ void image::draw(image const* image, vec2i pos, recti src_rect) {
}
}
} else {
-//#pragma omp parallel for
for(int y = start.y; y <= end.y; ++y) {
- std::memcpy(_data + (y * _bounds.size.x), image->_data - start.x + src_off.x + (y-start.y + src_off.y) * image->_bounds.size.x, (end.x - start.x + 1)*4);
-/* for(int x = start.x; x <= end.x; ++x) {
- auto color = image->_data[
- x - start.x + src_off.x + (y - start.y + src_off.y) * image->_bounds.size.x
- ];
- _data[x + y * _bounds.size.x] = color;
- }
- */
+ std::memcpy(
+ _data + (y * _bounds.size.x),
+ image->_data - start.x + src_off.x + (y-start.y + src_off.y) * image->_bounds.size.x,
+ (end.x - start.x + 1)*4
+ );
}
}
}
@@ -59,7 +56,7 @@ void image::draw(image const* image, vec2i pos, color color, recti src_rect) {
}
}
-
+/*
void image::draw_upscaled(image const* image) {
if(image->bounds() == bounds()) {
std::memcpy(_data, image->_data, bounds().size.size() * 4);
@@ -101,3 +98,64 @@ void image::draw_upscaled(image const* image) {
}
}
}
+*/
+
+void image::draw_rot(image const* image, vec2i pos, double rot) {
+ draw_rot(image, pos, image->bounds(), rot);
+}
+
+void image::draw_rot(image const* image, vec2i pos, recti src_rect, double rot) {
+ src_rect = recti::intersection(src_rect, image->bounds());
+ //auto crop = recti::intersection(bounds(), recti(pos, image->bounds().size));
+ //crop = recti::intersection(crop, recti(crop.pos, src_rect.size));
+ //todo: crop to screen...
+ //todo: fmod the rot?
+ //rot = rot/2;
+ //if(rot >= 0.5)
+ // rot = 0.5 - rot;
+ rot /= 2;
+ if(rot >= 0.25)
+ rot = 0.25 - (rot - 0.25);
+ rot -= 0.125;
+ auto crop = recti::intersection(recti(pos, src_rect.size), recti(pos, image->bounds().size));
+ auto src_off = crop.pos - pos + src_rect.pos;
+ auto start = crop.pos;
+ auto end = crop.pos2();
+
+ auto xshear = -std::tan(rot * TAU / 2.0) *crop.size.x;
+ auto yshear = std::sin(rot * TAU) * crop.size.y;
+ //auto xshear = (std::cos(rot * TAU) - 1) / sin(rot * TAU);
+
+ std::vector xshears;
+ for(int y = start.y; y <= end.y; ++y) {
+ auto yf = static_cast(y - crop.pos.y) / crop.size.y * 2 - 0.5;
+ xshears.push_back(static_cast(xshear * yf));
+ }
+
+ for(int y = 0; y <= end.y - start.y; ++y) {
+ auto yf = static_cast(y) / crop.size.y * 2 - 1;
+ for(int x = 0; x <= end.x - start.x; ++x) {
+ double xf, yf;
+ int nx, ny;
+ nx = x;
+ ny = y;
+
+ yf = (static_cast(ny) / crop.size.y * 1 - 0.5);
+ nx = nx + yf * xshear;
+ //int nxt = x;
+
+ xf = (static_cast(nx) / crop.size.x * 1 - 0.5);
+ ny = ny + xf * yshear;
+
+ yf = (static_cast(ny) / crop.size.y * 1 - 0.5);
+ nx = nx + yf * xshear;
+
+
+ auto color = image->_data[
+ x + src_off.x + (y + src_off.y) * image->_bounds.size.x
+ ];
+ if(color & 0xff000000)
+ _data[nx + start.x + (ny+start.y) * _bounds.size.x] = color;
+ }
+ }
+}
diff --git a/blooblib/src/draw/upscale.cpp b/blooblib/src/draw/upscale.cpp
new file mode 100644
index 0000000..53cab33
--- /dev/null
+++ b/blooblib/src/draw/upscale.cpp
@@ -0,0 +1,199 @@
+#include "image.h"
+
+#define UPSCALE_1X \
+for(int y = 0; y < s.y; ++y) {\
+ for(int x = 0; x < s.x; ++x) {\
+ color in, out;\
+ in = img->get(vec2i(x, y));
+
+#define UPSCALE_1X_END \
+ _data[x + y * size().x] = out;\
+ }\
+}\
+break;
+
+#define UPSCALE_2X \
+for(int y = 0; y < s.y; ++y) {\
+ for(int x = 0; x < s.x; ++x) {\
+ color in_t, in_b, in_l, in_r, in_m;\
+ color in_tl, in_tr, in_bl, in_br;\
+ color out_tl, out_tr, out_bl, out_br;\
+ in_t = img->get_safe(vec2i(x, y - 1));\
+ in_b = img->get_safe(vec2i(x, y + 1));\
+ in_l = img->get_safe(vec2i(x - 1, y));\
+ in_r = img->get_safe(vec2i(x + 1, y));\
+ in_tl = img->get_safe(vec2i(x - 1, y - 1));\
+ in_tr = img->get_safe(vec2i(x + 1, y - 1));\
+ in_bl = img->get_safe(vec2i(x - 1, y + 1));\
+ in_br = img->get_safe(vec2i(x + 1, y + 1));\
+ in_m = img->get(vec2i(x, y));
+
+#define UPSCALE_2X_END \
+ _data[(x * 2 + 0) + (y * 2 + 0) * size().x] = out_tl;\
+ _data[(x * 2 + 1) + (y * 2 + 0) * size().x] = out_tr;\
+ _data[(x * 2 + 0) + (y * 2 + 1) * size().x] = out_bl;\
+ _data[(x * 2 + 1) + (y * 2 + 1) * size().x] = out_br;\
+ }\
+}\
+break;
+
+#define UPSCALE_3X \
+for(int y = 0; y < s.y; ++y) {\
+ for(int x = 0; x < s.x; ++x) {\
+ color in_t, in_b, in_l, in_r, in_m;\
+ color in_tl, in_tr, in_bl, in_br;\
+ color out_t, out_b, out_l, out_r, out_m;\
+ color out_tl, out_tr, out_bl, out_br;\
+ in_t = img->get_safe(vec2i(x, y - 1));\
+ in_b = img->get_safe(vec2i(x, y + 1));\
+ in_l = img->get_safe(vec2i(x - 1, y));\
+ in_r = img->get_safe(vec2i(x + 1, y));\
+ in_tl = img->get_safe(vec2i(x - 1, y - 1));\
+ in_tr = img->get_safe(vec2i(x + 1, y - 1));\
+ in_bl = img->get_safe(vec2i(x - 1, y + 1));\
+ in_br = img->get_safe(vec2i(x + 1, y + 1));\
+ in_m = img->get(vec2i(x, y));
+
+#define UPSCALE_3X_END \
+ _data[(x * 3 + 0) + (y * 3 + 0) * size().x] = out_tl;\
+ _data[(x * 3 + 1) + (y * 3 + 0) * size().x] = out_t;\
+ _data[(x * 3 + 2) + (y * 3 + 0) * size().x] = out_tr;\
+ _data[(x * 3 + 0) + (y * 3 + 1) * size().x] = out_l;\
+ _data[(x * 3 + 1) + (y * 3 + 1) * size().x] = out_m;\
+ _data[(x * 3 + 2) + (y * 3 + 1) * size().x] = out_r;\
+ _data[(x * 3 + 0) + (y * 3 + 2) * size().x] = out_bl;\
+ _data[(x * 3 + 1) + (y * 3 + 2) * size().x] = out_b;\
+ _data[(x * 3 + 2) + (y * 3 + 2) * size().x] = out_br;\
+ }\
+}\
+break;
+
+int upscaler_scale(upscaler upscaler) {
+ switch(upscaler) {
+ case upscaler::none: return 1;
+ case upscaler::scale2x: return 2;
+ case upscaler::scale3x: return 3;
+ case upscaler::lcd3x: return 3;
+ case upscaler::rgb3x: return 3;
+ case upscaler::bilinear3x: return 3;
+ case upscaler::hatch3x: return 3;
+ }
+}
+
+
+void image::draw_upscaled(image const* img, upscaler upscaler) {
+ draw_upscaled(img, img->size(), upscaler);
+}
+
+static std::vector scale_buffers;
+
+void image::draw_upscaled(image const* img, std::vector upscalers) {
+ if(upscalers.size() > scale_buffers.size() + 1)
+ scale_buffers.resize(upscalers.size() - 1, nullptr);
+ auto src = img;
+ auto size = img->size();
+ for(int i = 0; i + 1 < upscalers.size(); ++i) {
+ auto osize = size * upscaler_scale(upscalers[i]);
+ if(!scale_buffers[i] || scale_buffers[i]->size().x < osize.x || scale_buffers[i]->size().y < osize.y) {
+ delete scale_buffers[i];
+ scale_buffers[i] = new image(osize);
+ }
+ scale_buffers[i]->draw_upscaled(src, size, upscalers[i]);
+ src = scale_buffers[i];
+ size = osize;
+ }
+ this->draw_upscaled(src, size, upscalers.back());
+}
+
+
+void image::draw_upscaled(image const* img, vec2i s, upscaler upscaler) {
+ switch(upscaler) {
+ case upscaler::none:
+ UPSCALE_1X
+ out = in;
+ UPSCALE_1X_END
+ case upscaler::scale2x:
+ UPSCALE_2X
+ out_tl = in_l == in_t && in_t != in_r && in_l != in_b ? in_l : in_m;
+ out_tr = in_t == in_r && in_t != in_l && in_r != in_b ? in_r : in_m;
+ out_bl = in_l == in_b && in_l != in_t && in_b != in_r ? in_l : in_m;
+ out_br = in_b == in_r && in_l != in_b && in_t != in_r ? in_r : in_m;
+ UPSCALE_2X_END
+ case upscaler::scale3x:
+ UPSCALE_3X
+ out_tl = in_l == in_t && in_l != in_b && in_t != in_r ? in_l : in_m;
+ out_t = (in_l == in_t && in_l != in_b && in_t != in_r && in_m != in_tr) ||
+ (in_t == in_r && in_t != in_l && in_r != in_b && in_m != in_tl) ? in_t : in_m;
+ out_tr = in_t == in_r && in_t != in_l && in_r != in_b ? in_r : in_m;
+ out_l = (in_b == in_l && in_b != in_r && in_l != in_t && in_m != in_tl) ||
+ (in_l == in_t && in_l != in_b && in_t != in_r && in_m != in_bl) ? in_l : in_m;
+ out_m = in_m;
+ out_r = (in_t == in_r && in_t != in_l && in_r != in_b && in_m != in_br) ||
+ (in_r == in_b && in_r != in_t && in_b != in_l && in_m != in_tr) ? in_r : in_m;
+ out_bl = in_b == in_l && in_b != in_r && in_l != in_t ? in_l : in_m;
+ out_b = (in_r == in_b && in_r != in_t && in_b != in_l && in_m != in_bl) ||
+ (in_b == in_l && in_b != in_r && in_l != in_t && in_m != in_br) ? in_b : in_m;
+ out_br = in_r == in_b && in_r != in_t && in_b != in_l ? in_r : in_m;
+ UPSCALE_3X_END
+ case upscaler::lcd3x:
+ UPSCALE_3X
+ out_tl = out_t = out_l = out_m = in_m;
+ out_tr = out_r = out_br = out_b = out_bl = (in_m & 0xfefefe) >> 1;
+ UPSCALE_3X_END
+ case upscaler::rgb3x:
+ UPSCALE_3X
+ out_tl = out_l = out_bl = in_m & 0xff0000;
+ out_t = out_m = out_b = in_m & 0x00ff00;
+ out_tr = out_r = out_br = in_m & 0x0000ff;
+ UPSCALE_3X_END
+ case upscaler::bilinear3x:
+ UPSCALE_3X
+ out_m = in_m;
+ out_l = ((in_m & 0xfefefe) >> 1) + ((in_l & 0xfefefe) >> 1);
+ out_r = ((in_m & 0xfefefe) >> 1) + ((in_r & 0xfefefe) >> 1);
+ out_t = ((in_m & 0xfefefe) >> 1) + ((in_t & 0xfefefe) >> 1);
+ out_b = ((in_m & 0xfefefe) >> 1) + ((in_b & 0xfefefe) >> 1);
+ out_tl = ((in_m & 0xfcfcfc) >> 2) + ((in_t & 0xfcfcfc) >> 2) + ((in_l & 0xfcfcfc) >> 2) + ((in_tl & 0xfcfcfc) >> 2);
+ out_tr = ((in_m & 0xfcfcfc) >> 2) + ((in_t & 0xfcfcfc) >> 2) + ((in_r & 0xfcfcfc) >> 2) + ((in_tr & 0xfcfcfc) >> 2);
+ out_bl = ((in_m & 0xfcfcfc) >> 2) + ((in_b & 0xfcfcfc) >> 2) + ((in_l & 0xfcfcfc) >> 2) + ((in_bl & 0xfcfcfc) >> 2);
+ out_br = ((in_m & 0xfcfcfc) >> 2) + ((in_b & 0xfcfcfc) >> 2) + ((in_r & 0xfcfcfc) >> 2) + ((in_br & 0xfcfcfc) >> 2);
+ UPSCALE_3X_END
+ case upscaler::hatch3x:
+ UPSCALE_3X
+ out_m = in_m;
+ out_l = in_l;
+ out_r = in_r;
+ out_t = in_t;
+ out_b = in_b;
+ out_tl = in_tl;
+ out_tr = in_tr;
+ out_bl = in_bl;
+ out_br = in_br;
+ UPSCALE_3X_END
+ }
+}
+
+image const* image::upscale_eagle_2x() const {
+ auto img = new image(size() * 2);
+ for(int y = 0; y < size().y; ++y) {
+ for(int x = 0; x < size().x; ++x) {
+ color in_t, in_b, in_l, in_r, in_m, out_tl, out_tr, out_bl, out_br;
+ in_t = get_safe(vec2i(x, y - 1));
+ in_b = get_safe(vec2i(x, y + 1));
+ in_l = get_safe(vec2i(x - 1, y));
+ in_r = get_safe(vec2i(x + 1, y));
+ in_m = get(vec2i(x, y));
+
+ out_tl = in_l == in_t && in_t != in_r && in_l != in_b ? in_l : in_m;
+ out_tr = in_t == in_r && in_t != in_l && in_r != in_b ? in_r : in_m;
+ out_bl = in_l == in_b && in_l != in_t && in_b != in_r ? in_l : in_m;
+ out_br = in_b == in_r && in_l != in_b && in_t != in_r ? in_r : in_m;
+
+ img->_data[(x * 2 + 0) + (y * 2 + 0) * img->size().x] = out_tl;
+ img->_data[(x * 2 + 1) + (y * 2 + 0) * img->size().x] = out_tr;
+ img->_data[(x * 2 + 0) + (y * 2 + 1) * img->size().x] = out_bl;
+ img->_data[(x * 2 + 1) + (y * 2 + 1) * img->size().x] = out_br;
+ }
+ }
+ return img;
+}
diff --git a/blooblib/src/game.cpp b/blooblib/src/game.cpp
index 2b56218..0d92b77 100644
--- a/blooblib/src/game.cpp
+++ b/blooblib/src/game.cpp
@@ -96,7 +96,13 @@ void game::run() {
screen.draw(_cursor, _mouse_pos);
auto p = screen.raw_pointer();
if(screen.bounds() != window_image.bounds()) {
- window_image.draw_upscaled(&screen);
+ //window_image.draw_upscaled(&screen);
+ std::vector scalers;
+ //scalers.push_back(upscaler::scale3x);
+ //scalers.push_back(upscaler::scale3x);
+ scalers.push_back(upscaler::lcd3x);
+ //scalers.push_back(upscaler::hatch3x);
+ window_image.draw_upscaled(&screen, scalers);
p = window_image.raw_pointer();
}
diff --git a/blooblib/src/image.cpp b/blooblib/src/image.cpp
index c945a69..7a8c9e9 100644
--- a/blooblib/src/image.cpp
+++ b/blooblib/src/image.cpp
@@ -66,6 +66,12 @@ color image::get(vec2i pos) const {
return _data[pos.x + pos.y * _bounds.size.x];
}
+color image::get_safe(vec2i pos) const {
+ if(pos.x < 0 || pos.y < 0 || pos.x >= _bounds.size.x || pos.y >= _bounds.size.y)
+ return 0x00000000;
+ return _data[pos.x + pos.y * _bounds.size.x];
+}
+
void image::clear(color color) {
std::fill(_data, _data + size().size(), color);
}
diff --git a/blooblib/src/ini.cpp b/blooblib/src/ini.cpp
index b088349..eaf3b1a 100644
--- a/blooblib/src/ini.cpp
+++ b/blooblib/src/ini.cpp
@@ -7,7 +7,7 @@ std::string const& ini_category::get_string(std::string const& entry) const {
if(_data.contains(entry))
return _data.at(entry);
- return "";
+ return std::string("");
}
ini::ini(resource_manager& rm, ini_category const* ini, std::string const& path, std::vector data) {
diff --git a/test/assets/slime.png b/test/assets/slime.png
new file mode 100644
index 0000000..973e1ae
Binary files /dev/null and b/test/assets/slime.png differ
diff --git a/test/test.cpp b/test/test.cpp
index 90678d9..b0c48af 100644
--- a/test/test.cpp
+++ b/test/test.cpp
@@ -7,6 +7,7 @@ struct my_game : game {
void render(image& target);
image const* img;
+ image const* slime;
ini const* ini;
@@ -16,28 +17,36 @@ struct my_game : game {
};
void my_game::init(settings& settings) {
- settings.target_fps = 60000;
- settings.scale = 1;
- settings.size = vec2i(1920, 1080);
+ settings.target_fps = 6000;
+ time = 0.0;
+ settings.scale = 3;
+ settings.size = vec2i(1920/3, 1080/3);
img = get("test.png");
+ slime = get("slime.png");
+ //slime = slime->upscale_2x();
+ //slime = slime->upscale_2x();
+ //slime = slime->upscale_2x();
//ini = get<::ini>("test.ini");
font = get<::font>("_/default-font-prop.png");
//cursor(&font['\\']);
}
void my_game::update() {
- time += 1.0 / 60.0;
+ time = std::fmod(time + 1.0 / 60.0, 1.0);
}
void my_game::render(image& target) {
target.clear(0xffdddd);
auto pos = vec2i(std::sin(time * TAU / 4) * 100, std::cos(time * TAU / 4) * 100);
//target.draw(img, vec2i(320, 180) + pos, recti(vec2i(8, 14), vec2i(8 * 4, 14 * 4)));
- for(int i = 0; i < 1; ++i)
- target.draw(img, vec2i::zero);
+ //for(int i = 0; i < 1; ++i)
+ // target.draw(img, vec2i::zero);
+
+ //target.draw_rot(slime, vec2i(200, 200), time);
+ target.draw(slime, vec2i(40, 40));
//target.draw(tileset[0xda], vec2i(320, 180) + pos, 0xff00ff);
auto str = "Can only be played if\nthere are no card in\nyour draw pile.\nDeal 50 damage to ALL\nenemies.";
- target.draw(str, vec2i(100, 100) + pos, font, 0xffffff, 0);
+ //target.draw(str, vec2i(100, 100) + pos, font, 0xffffff, 0);
target.draw(std::format("FPS: {}", fps()), vec2i(10, 10), font, 0xffffff, 0);
//target.draw("\\", mouse_pos(), font, 0xffffff, 0);
}