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); }