diff --git a/c++/perspective/src/common.h b/c++/perspective/src/common.h index dedca83..b359255 100644 --- a/c++/perspective/src/common.h +++ b/c++/perspective/src/common.h @@ -20,6 +20,7 @@ using Glib::RefPtr; const Real real_precision = 1e-10; +const Real real_precision_sqr = real_precision * real_precision; class Shared { diff --git a/c++/perspective/src/generator.cpp b/c++/perspective/src/generator.cpp index 1e62fd4..41b76db 100644 --- a/c++/perspective/src/generator.cpp +++ b/c++/perspective/src/generator.cpp @@ -5,10 +5,73 @@ #include "generator.h" +void +Generator::GenSurface::reset() { + if (data) delete[] data; + data = nullptr; + w = h = 0; + m_offset = ULongIntVector2(); + m_step = 0; +} + +void +Generator::GenSurface::create(const ULongIntPair2 &bounds, ULongInt step) { + ULongIntPair2 b = bounds; + + reset(); + + assert(!(step & (step - 1))); + assert(b.p1.x != b.p0.x); + assert(b.p1.y != b.p0.y); + assert(b.p1.x - b.p0.x <= big); + assert(b.p1.y - b.p0.y <= big); + + b.p0.x = b.p0.x & ~(step - 1); + b.p0.y = b.p0.y & ~(step - 1); + if (!(b.p0.x & step)) b.p0.x -= step; + if (!(b.p0.y & step)) b.p0.y -= step; + + b.p1.x = ((b.p1.x - 1) & ~(step - 1)) + step; + b.p1.y = ((b.p1.y - 1) & ~(step - 1)) + step; + if (!(b.p1.x & step)) b.p1.x += step; + if (!(b.p1.y & step)) b.p1.y += step; + + w = (b.p1.x - b.p0.x)/step + 1; + h = (b.p1.y - b.p0.y)/step + 1; + + assert(w <= max_side); + assert(h <= max_side); + assert(w*h <= max_area); + + m_step = step; + m_offset = b.p0; + data = new Vector4[w*h]; + + assert(is_valid()); +} + +Generator::GenSurface& +Generator::GenSurface::operator= (const GenSurface &other) { + if (&other != this) { + reset(); + if (other.is_valid()) { + w = other.w; + h = other.h; + m_offset = other.m_offset; + m_step = other.m_step; + data = new Vector4[w*h]; + memcpy(data, other.data, sizeof(Vector4)*w*h); + assert(is_valid()); + } + } + return *this; +} + + + Generator::Generator(): Generator(random(time(NULL))) { } Generator::Generator(ULongInt seed): - one(1ull << 32), max_cache_count(4ll*1024*1024*1024/sizeof(CacheEntry)) { set_seed(seed); @@ -29,11 +92,13 @@ Generator::set_seed(ULongInt x) { Real Generator::random(const ULongIntVector2 &coord, int index) const { - ULongInt seed = random(random(coord.x) ^ seeds_x()[index]); - seed = random(seed ^ random(coord.y) ^ seeds_y()[index]); - const ULongInt x = seed = random(seed ^ random(coord.x) ^ random(coord.y)); - const ULongInt y = seed = random(seed); - return random_to_normal(x, y); + ULongInt rx = coord.x ^ seeds_x()[index]; + ULongInt ry = coord.y ^ seeds_y()[index]; + ULongInt seed = random(rx ^ random(ry)); + seed = random(seed ^ ry); + seed = random(seed ^ random(rx)); + return random_to_real(seed)*2 - 1; + //return random_to_normal(seed, random(seed)); } Vector4 @@ -96,9 +161,6 @@ Generator::generate(const ULongIntVector2 &coord, bool shrink_cache) const { + generate(ULongIntVector2(coord.x, coord.y + level)) )*0.25; } } - - for(int j = 0; j < 4; ++j) - value[j] = mirror_repeat(value[j]); } i->second.in_use = false; @@ -123,28 +185,249 @@ Generator::generate(const Vector2 &coord, const Vector2 &precision) const { } void +Generator::generate(GenSurface &target) const { + assert(target.is_valid()); + const ULongInt step = target.step(); + + if (step && step < one) { + ULongIntVector2 onev(one, one); + GenSurface surface(ULongIntPair2(target.p0() - onev, target.p1() + onev), one); + generate(surface); + generate(target, surface); + return; + } + + const ULongInt w = target.width(); + const ULongInt h = target.height(); + + const ULongInt report_count = 1ull*1024ull*1024ull; + std::cout << " generate base " << w << "x" << h << ": "; + ULongInt count = 0; + + const ULongIntVector2 p0 = target.p0(); + ULongIntVector2 p = p0; + for(ULongInt y = 0; y < h; ++y, p.x = p0.x, p.y += step) { + Vector4 *pixel = target[y]; + for(ULongInt x = 0; x < w; ++x, ++pixel, p.x += step) { + for(int j = 0; j < 4; ++j) + (*pixel)[j] = random(p, j); + } + if ((count += w) >= report_count) { std::cout << "."; count = 0; } + } + + std::cout << std::endl; +} + +void +Generator::generate(GenSurface &target, const GenSurface &source) const { + assert(target.is_valid()); + assert(source.is_valid()); + assert(target.step()); + assert(target.step() < one); + assert(source.step()); + assert(source.step() <= one); + assert(source.step() > target.step()); + + const ULongInt step = target.step(); + const ULongInt source_step = step << 1; + + if (source_step != source.step()) { + GenSurface surface(ULongIntPair2(target.p0(), target.p1()), source_step); + generate(surface, source); + generate(target, surface); + return; + } + + const ULongInt tw = target.width(); + const ULongInt th = target.height(); + + const ULongInt sw = source.width(); + const ULongInt sh = source.height(); + + const ULongIntVector2 target_offset = target.offset(); + + const ULongIntVector2 shift( + (target.offset().x - source.offset().x)/step, + (target.offset().y - source.offset().y)/step ); + assert(shift.x); + assert(shift.y); + assert(shift.x <= max_side << 1); + assert(shift.y <= max_side << 1); + + assert(sw > (tw - 1 + shift.x)/2 + 1); + assert(sh > (th - 1 + shift.y)/2 + 1); + + const Real deviation_base = 0.65; + Real deviation = 1; + for(ULongInt i = one; step < i; i >>= 1) + deviation *= deviation_base; + //const Real deviation = Real(step)/one; + + ULongIntVector2 coord, start; + + const ULongInt report_count = 2ull*1024ull*1024ull; + std::cout << " generate subs " << tw << "x" << th << ": "; + ULongInt count = 0; + + // copy + ULongInt x0 = 1, y0 = 1; + coord = start = target_offset + ULongIntVector2(x0, y0)*step; + for(ULongInt y = y0; y < th; y += 2, coord.x = start.x, coord.y += source_step) { + Vector4* tp = &target[y][x0]; + ULongInt sy = (y + shift.y)/2; + ULongInt sx0 = (x0 + shift.x)/2; + const Vector4* sp = &source[sy][sx0]; + for(ULongInt x = x0; x < tw; x += 2, coord.x += source_step, tp += 2, ++sp) + *tp = *sp; + if ((count += tw) >= report_count) { std::cout << "."; count = 0; } + } + + // square + x0 = 0, y0 = 0; + coord = start = target_offset + ULongIntVector2(x0, y0)*step; + for(ULongInt y = y0; y < th; y += 2, coord.x = start.x, coord.y += source_step) { + Vector4* tp = &target[y][x0]; + ULongInt sy = (y + shift.y)/2; + ULongInt sx0 = (x0 + shift.x)/2; + const Vector4* sp0 = &source[sy][sx0]; + const Vector4* sp1 = &source[sy + 1][sx0]; + for(ULongInt x = x0; x < tw; x += 2, coord.x += source_step, tp += 2, ++sp0, ++sp1) { + *tp = Vector4( + random(coord, 0), + random(coord, 1), + random(coord, 2), + random(coord, 3) )*deviation + + (sp0[0] + sp0[1] + sp1[0] + sp1[1])*0.25; + } + if ((count += tw) >= report_count) { std::cout << "."; count = 0; } + } + + // diamond 1 + x0 = 1, y0 = 0; + coord = start = target_offset + ULongIntVector2(x0, y0)*step; + for(ULongInt y = y0; y < th; y += 2, coord.x = start.x, coord.y += source_step) { + Vector4* tp = &target[y][x0]; + ULongInt sy = (y + shift.y)/2; + ULongInt sx0 = (x0 + shift.x)/2; + const Vector4* sp0 = &source[sy][sx0]; + const Vector4* sp1 = &source[sy + 1][sx0]; + for(ULongInt x = x0; x < tw; x += 2, coord.x += source_step, tp += 2, ++sp0, ++sp1) { + *tp = Vector4( + random(coord, 0), + random(coord, 1), + random(coord, 2), + random(coord, 3) )*deviation + + (*sp0 + *sp1 + *(tp-1) + *(tp+1))*0.25; + } + if ((count += tw) >= report_count) { std::cout << "."; count = 0; } + } + + // diamond 2 + x0 = 0, y0 = 1; + coord = start = target_offset + ULongIntVector2(x0, y0)*step; + for(ULongInt y = y0; y < th; y += 2, coord.x = start.x, coord.y += source_step) { + Vector4* tp = &target[y ][x0]; + Vector4* tp0 = &target[y-1][x0]; + Vector4* tp1 = &target[y+1][x0]; + ULongInt sy = (y + shift.y)/2; + ULongInt sx0 = (x0 + shift.x)/2; + const Vector4* sp = &source[sy][sx0]; + for(ULongInt x = x0; x < tw; x += 2, coord.x += source_step, tp += 2, tp0 += 2, tp1 += 2, ++sp) { + *tp = Vector4( + random(coord, 0), + random(coord, 1), + random(coord, 2), + random(coord, 3) )*deviation + + (sp[0] + sp[1] + *tp0 + *tp1)*0.25; + } + if ((count += tw) >= report_count) { std::cout << "."; count = 0; } + } + + std::cout << std::endl; +} + + +void Generator::generate(Surface &target, const Pair2 &bounds) const { if (target.empty()) return; + + const int w = target.width(); + const int h = target.height(); + + std::cout << "generate " << w << "x" << h << std::endl; + + assert(fabs(bounds.p0.x)*one < big); + assert(fabs(bounds.p0.y)*one < big); + assert(fabs(bounds.p1.x)*one < big); + assert(fabs(bounds.p1.y)*one < big); + Vector2 d = bounds.distance(); - d.x /= target.width(); - d.y /= target.height(); - Vector2 precision = d/2.0; + d.x /= w; + d.y /= h; + const Vector2 precision(fabs(d.x/2.0), fabs(d.x/2.0)); + const Real precision_max = std::max(precision.x, precision.y); - int percent = 0; - Real pk = Real(100)/target.height(); + Color gray(0.5, 0.5, 0.5, 0.5); + if (precision_max >= Real(gray1)/Real(one)) { + // fill target by gray color + std::cout << " gray" << std::endl; + for(int r = 0; r < h; ++r) { + Color *p = target[r]; + for(int c = 0; c < w; ++c, ++p) + *p = gray; + } + return; + } + + Real gray_alpha = 0; + if (precision_max > Real(gray0)/Real(one)) { + Real l0 = log(Real(gray0)/Real(one)); + Real l1 = log(Real(gray1)/Real(one)); + Real lp = log(precision_max); + gray_alpha = (lp - l0)/(l1 - l0); + } + Real alpha = 1.0 - gray_alpha; + gray *= gray_alpha; + + const ULongIntPair2 gen_bounds( + ULongIntVector2( ULongInt(floor(bounds.p0.x*one)) - 1, + ULongInt(floor(bounds.p0.y*one)) - 1 ), + ULongIntVector2( ULongInt(ceil (bounds.p1.x*one)) + 1, + ULongInt(ceil (bounds.p1.y*one)) + 1 )); + ULongInt step_x = 1, step_y = 1; + while(step_x < precision.x*one - real_precision && step_x < big) step_x <<= 1; + while(step_y < precision.y*one - real_precision && step_y < big) step_y <<= 1; + + const ULongInt step_max = std::max(step_x, step_y); + const ULongInt step_min = std::min(step_x, step_y); + const ULongInt step_diff = step_max / step_min; + assert(step_diff); + + const ULongInt step_base = step_max/std::min(step_diff, 1ull << 2); + GenSurface gen_surface(gen_bounds, step_base); + generate(gen_surface); + + std::cout << " convert" << std::endl; + const ULongInt step = gen_surface.step(); + const ULongIntVector2 offset( + gen_surface.offset().x - step/2, + gen_surface.offset().y - step/2 ); Vector2 p = bounds.p0; for(int r = 0; r < target.height(); ++r, p.x = bounds.p0.x, p.y += d.y) { - Real pr = r*pk; - while(percent < pr) - std::cout << (++percent) << "%" << std::endl; - Color *row = target[r]; - for(int c = 0; c < target.width(); ++c, p.x += d.x) { - Vector4 v = generate(p, precision); - row[c].r = flip_clamp(v.x); - row[c].g = flip_clamp(v.y); - row[c].b = flip_clamp(v.z); - row[c].a = flip_clamp(v.w); + Color *pixel = target[r]; + ULongInt rr = (ULongInt(round(p.y*one)) - offset.y)/step; + assert(rr < gen_surface.height()); + + for(int c = 0; c < target.width(); ++c, ++pixel, p.x += d.x) { + ULongInt cc = (ULongInt(round(p.x*one)) - offset.x)/step; + assert(cc < gen_surface.width()); + + const Vector4 &v = gen_surface[rr][cc]; + *pixel = Color( flip_clamp((v.x + 1)*0.5), + flip_clamp((v.y + 1)*0.5), + flip_clamp((v.z + 1)*0.5), + flip_clamp((v.w + 1)*0.5) )*alpha + gray; } } } diff --git a/c++/perspective/src/generator.h b/c++/perspective/src/generator.h index 92cfc77..8af0ef2 100644 --- a/c++/perspective/src/generator.h +++ b/c++/perspective/src/generator.h @@ -11,6 +11,15 @@ class Generator: public Shared { public: + enum { + gray0 = 1ull << 28, + one = 1ull << 32, + gray1 = 1ull << 36, + big = 1ull << 60, + max_side = 1ull << 16, + max_area = 1ull << 32, + }; + struct CacheEntry; typedef std::map Cache; @@ -20,44 +29,65 @@ public: Vector4 value; }; - static inline ULongInt random(ULongInt x) { - ++x; - x ^= x >> 2; - x ^= x << 3; - x ^= x >> 5; - x ^= x << 7; - x ^= x >> 11; - x ^= x << 13; - x ^= x >> 17; - x ^= x << 19; - x ^= x >> 23; - x ^= x << 29; - x ^= x >> 31; - x ^= x << 37; - x ^= x >> 41; - x ^= x << 43; - x ^= x >> 47; - x ^= x << 53; - x ^= x >> 59; - x ^= x << 61; - ++x; - return x; - } + class GenSurface { + private: + Vector4 *data; + ULongInt w, h; + ULongIntVector2 m_offset; + ULongInt m_step; + + public: + inline GenSurface(): + data(), w(), h(), m_step() { } + inline GenSurface(const ULongIntPair2 &bounds, ULongInt step): + GenSurface() { create(bounds, step); } + inline GenSurface(const GenSurface &other): + GenSurface() { *this = other; } + inline GenSurface(GenSurface &&other): + data(other.data), w(other.w), h(other.h), m_offset(other.m_offset), m_step(other.m_step) + { if (&other != this) other.data = nullptr; } + inline ~GenSurface() + { reset(); } + + void create(const ULongIntPair2 &bounds, ULongInt step); + void reset(); + GenSurface& operator= (const GenSurface &other); + + inline bool is_valid() const { + return data + && w < max_side + && h < max_side + && w*h < max_area + && w%2 && h%2 + && !(m_step & (m_step - 1)) + && !(m_offset.x & (m_step - 1)) + && !(m_offset.y & (m_step - 1)) + && m_offset.x & m_step + && m_offset.y & m_step; + } + + inline ULongInt width() const { return w; } + inline ULongInt height() const { return h; } + inline const ULongIntVector2& offset() const { return m_offset; } + inline ULongInt step() const { return m_step; } + + inline Vector4* operator[] (ULongInt row) { return data + row*w; } + inline const Vector4* operator[] (ULongInt row) const { return data + row*w; } + + inline ULongIntVector2 p0() const { return m_offset; } + inline ULongIntVector2 p1() const { return m_offset + ULongIntVector2(w-1, h-1)*m_step; } + }; + + + static inline ULongInt random(ULongInt x) + { return x*2862933555777941757ull + 3037000493ull; } static inline Real random_to_real(ULongInt x) { return Real(x)/Real(ULLONG_MAX); } static inline Real random_to_normal(ULongInt x, ULongInt y) { return sqrt(-2*log(random_to_real(x))) * sin(2*M_PI*random_to_real(y)); } - static inline Real mirror_repeat(Real x) { - x *= 0.5; - x -= floor(x); - x *= 2; - return x > 1 ? 2 - x : x; - } - private: - const ULongInt one; const int max_cache_count; mutable Cache m_cache; @@ -65,7 +95,7 @@ private: mutable int m_cache_count; ULongInt m_seeds[2][4]; - + public: Generator(); explicit Generator(ULongInt seed); @@ -76,9 +106,15 @@ public: void set_seed(ULongInt x); Real random(const ULongIntVector2 &coord, int index) const; + inline Vector4 random(const ULongIntVector2 &coord) const + { return Vector4(random(coord, 0), random(coord, 1), random(coord, 2), random(coord, 3)); } + Vector4 generate(const ULongIntVector2 &coord, bool shrink_cache = true) const; Vector4 generate(const Vector2 &coord, const Vector2 &precision) const; void generate(Surface &target, const Pair2 &bounds) const; + + void generate(GenSurface &target) const; + void generate(GenSurface &target, const GenSurface &source) const; }; diff --git a/c++/perspective/src/main.cpp b/c++/perspective/src/main.cpp index 93a5c19..cee302a 100644 --- a/c++/perspective/src/main.cpp +++ b/c++/perspective/src/main.cpp @@ -14,11 +14,11 @@ int main(int argc, char **argv) { argc, argv, "org.coolbug.lab.perspective"); std::cout << "create window" << std::endl; - //MainWindow window; - Gtk::Window window; + MainWindow window; + //Gtk::Window window; //window.add(*Gtk::manage(new PerspectiveSandBoxView())); - window.add(*Gtk::manage(new GeneratorSandBoxView())); - window.show_all(); + //window.add(*Gtk::manage(new GeneratorSandBoxView())); + //window.show_all(); std::cout << "run" << std::endl; int result = application->run(window); diff --git a/c++/perspective/src/mainwindow.cpp b/c++/perspective/src/mainwindow.cpp index 80afd6e..6537032 100644 --- a/c++/perspective/src/mainwindow.cpp +++ b/c++/perspective/src/mainwindow.cpp @@ -97,7 +97,7 @@ void MainWindow::update_src_surface() { std::cout << "update_src_surface() - begin" << std::endl; - Matrix4 transform = src_view.transform.inverted(); + Matrix4 transform = src_view.transform_from_pixels(); int w = src_view.get_width(); int h = src_view.get_height(); @@ -131,13 +131,13 @@ MainWindow::update_dst_surface() { return; Real kx = 1/src_dist.x; - Real ky = 1/src_dist.x; + Real ky = 1/src_dist.y; Real x0 = -src_bounds.p0.x*kx; - Real x1 = -src_bounds.p0.y*kx; + Real y0 = -src_bounds.p0.y*ky; Matrix3 src_matrix( Vector3(kx, 0, 0), Vector3( 0, ky, 0), - Vector3(x0, x1, 1) ); + Vector3(x0, y0, 1) ); // dst matrix const Matrix dst_transform = dst_view.transform_to_pixels(); @@ -175,7 +175,8 @@ MainWindow::update_dst_surface() { Perspective::create_layers( layers, matrix, - dst_bounds_pixels ); + dst_bounds_pixels, + 2.0 ); std::cout << Log::tab() << "created layers:" << std::endl; Perspective::print_layers(layers, Log::tab(2)); @@ -244,7 +245,7 @@ MainWindow::on_draw_src_view(const Cairo::RefPtr &context) { void MainWindow::on_draw_dst_view(const Cairo::RefPtr &context) { - const Real ps = src_view.get_pixel_size(); + const Real ps = dst_view.get_pixel_size(); context->save(); if (dst_surface) { diff --git a/c++/perspective/src/perspective.cpp b/c++/perspective/src/perspective.cpp index ad7f7d0..51a9438 100644 --- a/c++/perspective/src/perspective.cpp +++ b/c++/perspective/src/perspective.cpp @@ -14,6 +14,9 @@ namespace { const int max_area_width = 4096 - 2*border_width; const int max_area = max_area_width * max_area_width; + + const Real max_overscale = 1.0; + const Real max_overscale_sqr = max_overscale*max_overscale; } @@ -50,6 +53,21 @@ Perspective::make_matrix( } +Matrix3 +Perspective::normalize_matrix( + const Matrix3 &matrix ) +{ + Real k = matrix.get_col(2).length(); + if (k <= real_precision) + return matrix; + k = 1/k; + Matrix3 m = matrix; + for(int i = 0; i < 9; ++i) + m.a[i] *= k; + return m; +} + + int Perspective::truncate_line( Vector2 *out_points, @@ -112,17 +130,17 @@ Perspective::calc_optimal_resolution( const Real c = oy.x * oy.x; const Real d = oy.y * oy.y; Real e = fabs(ox.x*oy.y - ox.y*oy.x); - if (e < real_precision) + if (e < real_precision_sqr) return Vector2(); // paranoid check, e must be non-zero when matrix is invertible e = 1.0/e; const Real sum = a*d + b*c; Vector2 scale; - if (2*a*b + real_precision >= sum) { + if (2*a*b + real_precision_sqr >= sum) { scale.x = sqrt(2*b)*e; scale.y = sqrt(2*a)*e; } else - if (2*c*d + real_precision >= sum) { + if (2*c*d + real_precision_sqr >= sum) { scale.x = sqrt(2*d)*e; scale.y = sqrt(2*c)*e; } else { @@ -130,7 +148,7 @@ Perspective::calc_optimal_resolution( scale.x = sqrt(dif/(a - c))*e; scale.y = sqrt(dif/(d - b))*e; } - + return scale.x <= real_precision || scale.y <= real_precision ? Vector2() : scale; } @@ -160,6 +178,10 @@ Perspective::make_alpha_matrix( Real bw0, Real bw1, const Vector3 &w_col ) { + return Matrix3( + Vector3( 0, 0, 0 ), + Vector3( 0, 0, 0 ), + Vector3( 1, 1, 1 ) ); const Vector3 a_col = make_alpha_matrix_col(aw0, aw1, w_col); const Vector3 b_col = make_alpha_matrix_col(bw0, bw1, w_col); return Matrix3( @@ -175,7 +197,8 @@ Perspective::calc_raster_size( IntVector2 &out_raster_size, Matrix3 &out_raster_matrix, const Vector2 &resolution, - const Pair2 &bounds ) + const Pair2 &bounds, + const Vector2 &dst_size ) { const Vector2 offset = bounds.p0; const Vector2 raster_size_orig( @@ -183,13 +206,18 @@ Perspective::calc_raster_size( (bounds.p1.y - bounds.p0.y)*resolution.y ); Vector2 raster_size_float = raster_size_orig; + Real sqr = raster_size_float.square(); + Real sqr_max = dst_size.square() * max_overscale_sqr; + if (sqr_max > real_precision && sqr > sqr_max) + raster_size_float *= sqrt(sqr_max/sqr); if (raster_size_float.x > max_width) raster_size_float.x = max_width; if (raster_size_float.y > max_height) raster_size_float.y = max_height; + IntVector2 raster_size( - (int)ceil( raster_size_float.x - real_precision ), - (int)ceil( raster_size_float.y - real_precision ) ); + std::max(1, (int)ceil( raster_size_float.x - real_precision )), + std::max(1, (int)ceil( raster_size_float.y - real_precision )) ); if (raster_size.x * raster_size.y > max_area) { const Real k = sqrt(Real(max_area)/(raster_size.x * raster_size.y)); raster_size.x = std::max(1, (int)floor(raster_size.x*k + real_precision)); @@ -219,18 +247,10 @@ Perspective::create_layers( const Real step ) { bool is_invertible = false; - Matrix3 back_matrix = matrix.inverted(&is_invertible); + Matrix3 back_matrix = normalize_matrix(matrix).inverted(&is_invertible); if (!is_invertible) return; // matrix is collapsed - { // normalize matrix by w-column - Real k = back_matrix.get_col(2).length(); - if (k <= real_precision) - return; // matrix is (almost) not invertible - k = 1/k; - for(int i = 0; i < 9; ++i) back_matrix.a[i] *= k; - } - // calc src resolution const Vector2 resolution = calc_optimal_resolution( back_matrix.row_x().vec2(), @@ -276,7 +296,8 @@ Perspective::create_layers( layer.src_size, layer.back_matrix, resolution, - layer_src_bounds ); + layer_src_bounds, + Vector2(layer.dst_bounds.size()) ); layer.back_matrix *= back_matrix; layer.back_alpha_matrix = Matrix3( Vector3(0, 0, 0), @@ -365,7 +386,8 @@ Perspective::create_layers( layer.src_size, layer.back_matrix, resolution * w, - layer_src_bounds ); + layer_src_bounds, + Vector2(layer.dst_bounds.size()) ); layer.back_matrix *= back_matrix; layer.back_alpha_matrix = make_alpha_matrix( aw0, aw1, bw0, bw1, diff --git a/c++/perspective/src/perspective.h b/c++/perspective/src/perspective.h index 64c4fc5..5961840 100644 --- a/c++/perspective/src/perspective.h +++ b/c++/perspective/src/perspective.h @@ -29,6 +29,9 @@ public: const Vector2 &py, const Vector2 &p1 ); + static Matrix3 normalize_matrix( + const Matrix3 &matrix ); + static int truncate_line( Vector2 *out_points, const Pair2 &bounds, @@ -55,7 +58,8 @@ public: IntVector2 &out_raster_size, Matrix3 &out_raster_matrix, const Vector2 &resolution, - const Pair2 &bounds ); + const Pair2 &bounds, + const Vector2 &dst_size ); static void create_layers( LayerList &out_layers, diff --git a/c++/perspective/src/vector.h b/c++/perspective/src/vector.h index 9352fae..16e70b0 100644 --- a/c++/perspective/src/vector.h +++ b/c++/perspective/src/vector.h @@ -413,5 +413,9 @@ typedef PairT LongIntPair2; typedef PairT LongIntPair3; typedef PairT LongIntPair4; +typedef PairT ULongIntPair2; +typedef PairT ULongIntPair3; +typedef PairT ULongIntPair4; + #endif