From: Sam Moore Date: Sat, 27 Sep 2014 14:10:06 +0000 (+0800) Subject: Define for Transformations on Path only, also fixed segfault due to GraphicsBuffer X-Git-Url: https://git.ucc.asn.au/?a=commitdiff_plain;h=2d12d37f1657d6aef9bb80d735b6c7022aecba6e;p=ipdf%2Fcode.git Define for Transformations on Path only, also fixed segfault due to GraphicsBuffer The "invalidated" is used to recycle memory in the GraphicsBuffer, but that can only be done if there is actually enough memory. This was causing a segfault if the document was initially empty and had things added to it. Can now remove the hack in main.cpp where documents started with a {0,0,0,0} RECT in them. We can now (ab)use the Path for transformations. The idea was that Arbitrary precision stuff might be faster if we only care about the bounds of the paths. Unfortunately the way Real was used everywhere will make it a bit difficult to actually use this. We need Beziers and their bounds to be stored with floats, but the Path bounds to be stored with GMPrat or some other arbitrary type. It probably won't help that much, but evaluating those Beziers with GMPrat really slows down the CPU renderer. It's also a giant hack because I still use BezierRenderer for GPU rendering but I now use PathRenderer for CPU rendering of Beziers. Le sigh. We can now store Bezier bounds relative to Path bounds and apply transformations only to the Path bounds. --- diff --git a/src/bezier.cpp b/src/bezier.cpp index cb92697..3c682a6 100644 --- a/src/bezier.cpp +++ b/src/bezier.cpp @@ -54,11 +54,13 @@ static void CubicSolveSegment(vector & roots, const Real & a, const Real & Real l = a*tl*tl*tl + b*tl*tl + c*tl + d; Real u = a*tu*tu*tu + b*tu*tu + c*tu + d; if ((l < 0 && u < 0) || (l > 0 && u > 0)) - Debug("Discarding segment (no roots) l = %f (%f), u = %f (%f)", Double(tl), Double(l), Double(tu), Double(u)); + { + //Debug("Discarding segment (no roots) l = %f (%f), u = %f (%f)", Double(tl), Double(l), Double(tu), Double(u)); //return; + } bool negative = (u < l); // lower point > 0, upper point < 0 - Debug("%ft^3 + %ft^2 + %ft + %f is negative (%f < %f) %d", Double(a),Double(b),Double(c),Double(d),Double(u),Double(l), negative); + //Debug("%ft^3 + %ft^2 + %ft + %f is negative (%f < %f) %d", Double(a),Double(b),Double(c),Double(d),Double(u),Double(l), negative); while (tu - tl > delta) { Real t(tu+tl); @@ -89,7 +91,7 @@ vector SolveCubic(const Real & a, const Real & b, const Real & c, const Re Real tu(max); Real tl(min); vector turns(SolveQuadratic(a*3, b*2, c)); - Debug("%u turning points", turns.size()); + //Debug("%u turning points", turns.size()); for (unsigned i = 1; i < turns.size(); ++i) { tu = turns[i]; diff --git a/src/bezier.h b/src/bezier.h index 01da922..cedf8d4 100644 --- a/src/bezier.h +++ b/src/bezier.h @@ -6,6 +6,8 @@ #include "real.h" #include "rect.h" + + namespace IPDF { extern int Factorial(int n); diff --git a/src/document.cpp b/src/document.cpp index 9b94ba2..4be3ee0 100644 --- a/src/document.cpp +++ b/src/document.cpp @@ -303,6 +303,7 @@ unsigned Document::AddPath(unsigned start_index, unsigned end_index, const Colou unsigned data_index = AddPathData(path); Rect bounds = path.SolveBounds(m_objects); unsigned result = Add(PATH, bounds,data_index); + m_objects.paths[data_index].m_index = result; //Debug("Added path %u -> %u (%u objects) colour {%u,%u,%u,%u}, stroke {%u,%u,%u,%u}", start_index, end_index, (end_index - start_index), fill.r, fill.g, fill.b, fill.a, stroke.r, stroke.g, stroke.b, stroke.a); return result; } @@ -1052,19 +1053,25 @@ void Document::TransformObjectBounds(const SVGMatrix & transform) } } -void Document::TranslateObjects(const Real & dx, const Real & dy) +void Document::TranslateObjects(const Real & dx, const Real & dy, ObjectType type) { for (unsigned i = 0; i < m_count; ++i) { - m_objects.bounds[i].x += dx; - m_objects.bounds[i].y += dy; + if (type == NUMBER_OF_OBJECT_TYPES || m_objects.types[i] == type) + { + m_objects.bounds[i].x += dx; + m_objects.bounds[i].y += dy; + } } } -void Document::ScaleObjectsAboutPoint(const Real & x, const Real & y, const Real & scale_amount) +void Document::ScaleObjectsAboutPoint(const Real & x, const Real & y, const Real & scale_amount, ObjectType type) { for (unsigned i = 0; i < m_count; ++i) { + if (type != NUMBER_OF_OBJECT_TYPES && m_objects.types[i] != type) + continue; + m_objects.bounds[i].w /= scale_amount; m_objects.bounds[i].h /= scale_amount; //m_objects.bounds[i].x = x + (m_objects.bounds[i].x-x)/scale_amount; @@ -1076,7 +1083,7 @@ void Document::ScaleObjectsAboutPoint(const Real & x, const Real & y, const Real m_objects.bounds[i].y -= y; m_objects.bounds[i].y /= scale_amount; m_objects.bounds[i].y += y; - - } - + } } + + diff --git a/src/document.h b/src/document.h index 0b095c3..57dbb9d 100644 --- a/src/document.h +++ b/src/document.h @@ -83,8 +83,8 @@ namespace IPDF void AddFontGlyphAtPoint(stbtt_fontinfo *font, int character, Real scale, Real x, Real y); void TransformObjectBounds(const SVGMatrix & transform); - void TranslateObjects(const Real & x, const Real & y); - void ScaleObjectsAboutPoint(const Real & x, const Real & y, const Real & scale_amount); + void TranslateObjects(const Real & x, const Real & y, ObjectType type = NUMBER_OF_OBJECT_TYPES); + void ScaleObjectsAboutPoint(const Real & x, const Real & y, const Real & scale_amount, ObjectType type = NUMBER_OF_OBJECT_TYPES); #ifndef QUADTREE_DISABLED inline const QuadTree& GetQuadTree() { if (m_quadtree.root_id == QUADTREE_EMPTY) { GenBaseQuadtree(); } return m_quadtree; } diff --git a/src/eye_of_the_rabbit.script b/src/eye_of_the_rabbit.script index 85d63a0..c94bccd 100644 --- a/src/eye_of_the_rabbit.script +++ b/src/eye_of_the_rabbit.script @@ -1,5 +1,5 @@ # Test how well document scales back to original... -gpu +cpu lazy label start debug Add rabbit 1 @@ -11,7 +11,9 @@ loop 200 pxzoom 508 305 1 debug Add rabbit 3 loadsvg svg-tests/rabbit_simple.svg loop 400 pxzoom 508 305 -1 -loop 400 pxzoom 508 305 1 +loop 200 pxzoom 508 305 1 +loop 1000 wait +loop 200 pxzoom 508 305 1 debug Repeat -goto start +#goto start wait diff --git a/src/graphicsbuffer.cpp b/src/graphicsbuffer.cpp index 217fa9a..8075453 100644 --- a/src/graphicsbuffer.cpp +++ b/src/graphicsbuffer.cpp @@ -224,7 +224,7 @@ void GraphicsBuffer::Upload(size_t length, const void* data) if (!RecreateBuffer(data)) { Bind(); - glBufferData(target, length, data, usage); + glBufferData(target, length+1, data, usage); } if (data != NULL) m_invalidated = false; @@ -243,7 +243,7 @@ void GraphicsBuffer::UploadRange(size_t length, intptr_t offset, const void* dat void GraphicsBuffer::Resize(size_t length) { - if (m_invalidated) + if (m_invalidated && m_buffer_size > length) { m_buffer_size = length; } diff --git a/src/main.cpp b/src/main.cpp index e20a7bf..e556fe4 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -184,10 +184,7 @@ int main(int argc, char ** argv) { doc.AddText(input_text, bounds.h/Real(2), bounds.x, bounds.y+bounds.h/Real(2)); } - else - { - doc.Add(RECT_OUTLINE, Rect(0,0,0,0),0); // hack to stop segfault if document is empty (:S) - } + #ifndef CONTROLPANEL_DISABLED diff --git a/src/main.h b/src/main.h index 5b9d263..b0c7a47 100644 --- a/src/main.h +++ b/src/main.h @@ -156,6 +156,12 @@ inline void MainLoop(Document & doc, Screen & scr, View & view, int max_frames = scr.DebugFontPrint("Doing coordinate transform on the CPU.\n"); } #endif + + #ifdef TRANSFORM_BEZIERS_TO_PATH + scr.DebugFontPrint("Beziers have been transformed to Path\n"); + #endif + + if (view.UsingGPURendering()) { scr.DebugFontPrint("Doing rendering using GPU.\n"); diff --git a/src/objectrenderer.cpp b/src/objectrenderer.cpp index cbceb3a..6a216bc 100644 --- a/src/objectrenderer.cpp +++ b/src/objectrenderer.cpp @@ -228,11 +228,12 @@ ObjectRenderer::PixelPoint ObjectRenderer::CPUPointLocation(const Vec2 & point, } -void BezierRenderer::RenderBezierOnCPU(unsigned i, Objects & objects, const View & view, const CPURenderTarget & target, const Colour & c) +void BezierRenderer::RenderBezierOnCPU(const Bezier & relative, const Rect & bounds, const View & view, const CPURenderTarget & target, const Colour & c) { - const Rect & bounds = objects.bounds[i]; + //const Rect & bounds = objects.bounds[i]; PixelBounds pix_bounds(CPURenderBounds(bounds,view,target)); - Bezier control(objects.beziers[objects.data_indices[i]].ToAbsolute(bounds),CPURenderBounds(Rect(0,0,1,1), view, target)); + //Bezier control(objects.beziers[objects.data_indices[i]].ToAbsolute(bounds),CPURenderBounds(Rect(0,0,1,1), view, target)); + Bezier control(relative.ToAbsolute(bounds), Rect(0,0,target.w, target.h)); if (view.ShowingBezierBounds()) { @@ -242,20 +243,21 @@ void BezierRenderer::RenderBezierOnCPU(unsigned i, Objects & objects, const View ObjectRenderer::RenderLineOnCPU(pix_bounds.x+pix_bounds.w, pix_bounds.y, pix_bounds.x+pix_bounds.w, pix_bounds.y+pix_bounds.h, target, Colour(0,255,0,0)); } - unsigned blen = target.w;//min(max(2U, (unsigned)Int64(Real(target.w)/view.GetBounds().w)), + unsigned blen = pix_bounds.w;//min(max(2U, (unsigned)Int64(Real(target.w)/view.GetBounds().w)), //min((unsigned)(pix_bounds.w+pix_bounds.h)/4 + 1, 100U)); // DeCasteljau Divide the Bezier + #ifdef BEZIER_CPU_DECASTELJAU queue divisions; divisions.push(control); while(divisions.size() < blen) { Bezier & current = divisions.front(); - if (current.GetType() == Bezier::LINE) - { - --blen; - continue; - } + //if (current.GetType() == Bezier::LINE) + //{ + // --blen; + // continue; + //} divisions.push(current.DeCasteljauSubdivideRight(Real(1)/Real(2))); divisions.push(current.DeCasteljauSubdivideLeft(Real(1)/Real(2))); divisions.pop(); @@ -266,6 +268,21 @@ void BezierRenderer::RenderBezierOnCPU(unsigned i, Objects & objects, const View RenderLineOnCPU(Int64(current.x0), Int64(current.y0), Int64(current.x3), Int64(current.y3), target, c); divisions.pop(); } + #else + Real invblen(1); invblen /= Real(blen); + + Real t(invblen); + Vec2 v0; + Vec2 v1; + control.Evaluate(v0.x, v0.y, 0); + for (int64_t j = 1; j <= blen; ++j) + { + control.Evaluate(v1.x, v1.y, t); + RenderLineOnCPU(v0.x, v0.y, v1.x, v1.y, target); + t += invblen; + v0 = v1; + } + #endif //BEZIER_CPU_DECASTELJAU } /** @@ -274,6 +291,9 @@ void BezierRenderer::RenderBezierOnCPU(unsigned i, Objects & objects, const View */ void BezierRenderer::RenderUsingCPU(Objects & objects, const View & view, const CPURenderTarget & target, unsigned first_obj_id, unsigned last_obj_id) { + #ifdef TRANSFORM_BEZIERS_TO_PATH + return; + #endif if (view.PerformingShading()) return; @@ -308,7 +328,9 @@ void BezierRenderer::RenderUsingCPU(Objects & objects, const View & view, const break; } } - RenderBezierOnCPU(m_indexes[i], objects, view, target, c); + Rect & bounds = objects.bounds[m_indexes[i]]; + Bezier & bez = objects.beziers[objects.data_indices[m_indexes[i]]]; + RenderBezierOnCPU(bez, bounds, view, target, c); } } @@ -319,11 +341,10 @@ void BezierRenderer::PrepareBezierGPUBuffer(Objects & objects) m_bezier_coeffs.Resize(objects.beziers.size()*sizeof(GPUBezierCoeffs)); BufferBuilder builder(m_bezier_coeffs.Map(false, true, true), m_bezier_coeffs.GetSize()); - + for (unsigned i = 0; i < objects.beziers.size(); ++i) { const Bezier & bez = objects.beziers[i]; - GPUBezierCoeffs coeffs = { Float(bez.x0), Float(bez.y0), Float(bez.x1), Float(bez.y1), @@ -332,6 +353,7 @@ void BezierRenderer::PrepareBezierGPUBuffer(Objects & objects) }; builder.Add(coeffs); } + m_bezier_coeffs.UnMap(); glGenTextures(1, &m_bezier_buffer_texture); glBindTexture(GL_TEXTURE_BUFFER, m_bezier_buffer_texture); @@ -350,6 +372,7 @@ void BezierRenderer::PrepareBezierGPUBuffer(Objects & objects) void BezierRenderer::RenderUsingGPU(unsigned first_obj_id, unsigned last_obj_id) { + if (!m_shader_program.Valid()) Warn("Shader is invalid (objects are of type %d)", m_type); @@ -400,13 +423,41 @@ void PathRenderer::RenderUsingCPU(Objects & objects, const View & view, const CP } } + #ifndef TRANSFORM_BEZIERS_TO_PATH if (!view.PerformingShading()) continue; - for (unsigned b = path.m_start; b <= path.m_end; ++b) { - BezierRenderer::RenderBezierOnCPU(b,objects,view,target,path.m_stroke); + Rect & bbounds = objects.bounds[b]; + Bezier & bez = objects.beziers[objects.data_indices[b]]; + BezierRenderer::RenderBezierOnCPU(bez,bbounds,view,target,path.m_stroke); } + #else + // Outlines still get drawn if using TRANSFORM_BEZIERS_TO_PATH + for (unsigned b = path.m_start; b <= path.m_end; ++b) + { + Colour stroke = (view.PerformingShading()) ? path.m_stroke : Colour(0,0,0,255); + // bezier's bounds are relative to this object's bounds, convert back to view bounds + Rect bbounds = objects.bounds[b]; + bbounds.x *= objects.bounds[m_indexes[i]].w; + bbounds.x += objects.bounds[m_indexes[i]].x; + bbounds.y *= objects.bounds[m_indexes[i]].h; + bbounds.y += objects.bounds[m_indexes[i]].y; + bbounds.w *= objects.bounds[m_indexes[i]].w; + bbounds.h *= objects.bounds[m_indexes[i]].h; + bbounds = view.TransformToViewCoords(bbounds); + //Debug("Bounds: %s", objects.bounds[m_indexes[i]].Str().c_str()); + //Debug("Relative Bez Bounds: %s", objects.bounds[b].Str().c_str()); + //Debug("Bez Bounds: %s", bbounds.Str().c_str()); + + Bezier & bez = objects.beziers[objects.data_indices[b]]; + + BezierRenderer::RenderBezierOnCPU(bez,bbounds,view,target, stroke); + } + if (!view.PerformingShading()) + continue; + #endif + if (pix_bounds.w*pix_bounds.h > 100) { @@ -443,6 +494,9 @@ void PathRenderer::RenderUsingCPU(Objects & objects, const View & view, const CP } } + + + /** * For debug, save pixels to bitmap */ @@ -464,6 +518,9 @@ void ObjectRenderer::SaveBMP(const CPURenderTarget & target, const char * filena SDL_FreeSurface(surf); } + + + /** * Bresenham's lines */ diff --git a/src/objectrenderer.h b/src/objectrenderer.h index 5a65363..9ea8a12 100644 --- a/src/objectrenderer.h +++ b/src/objectrenderer.h @@ -11,6 +11,7 @@ #include "shaderprogram.h" #include "bufferbuilder.h" +#define BEZIER_CPU_DECASTELJAU namespace IPDF { @@ -143,7 +144,7 @@ namespace IPDF virtual void RenderUsingCPU(Objects & objects, const View & view, const CPURenderTarget & target, unsigned first_obj_id, unsigned last_obj_id); void PrepareBezierGPUBuffer(Objects & objects); - static void RenderBezierOnCPU(unsigned index, Objects & objects, const View & view, const CPURenderTarget & target, const Colour & c=Colour(0,0,0,255)); + static void RenderBezierOnCPU(const Bezier & relative, const Rect & bounds, const View & view, const CPURenderTarget & target, const Colour & c=Colour(0,0,0,255)); private: GraphicsBuffer m_bezier_coeffs; @@ -165,11 +166,12 @@ namespace IPDF class PathRenderer : public ObjectRenderer { public: - PathRenderer() : ObjectRenderer(PATH, "shaders/rect_vert.glsl", "shaders/rect_frag.glsl", "shaders/rect_outline_geom.glsl") {} + PathRenderer() : ObjectRenderer(PATH, "shaders/rect_vert.glsl", "shaders/rect_frag.glsl", "shaders/bezier_texbug_geom.glsl") {} virtual ~PathRenderer() {} virtual void RenderUsingCPU(Objects & objects, const View & view, const CPURenderTarget & target, unsigned first_obj_id, unsigned last_obj_id); // do nothing on GPU virtual void RenderUsingGPU(unsigned first_obj_id, unsigned last_obj_id) {} + }; class FakeRenderer : public ObjectRenderer diff --git a/src/paranoidnumber.cpp b/src/paranoidnumber.cpp index 6b602c0..60802eb 100644 --- a/src/paranoidnumber.cpp +++ b/src/paranoidnumber.cpp @@ -32,7 +32,7 @@ ParanoidNumber::ParanoidNumber(const string & str) : m_value(0), m_next() m_size = 1; #endif #ifdef PARANOID_CACHE_RESULTS - m_cached_result = NAN; + m_cache_valid = false; #endif int dp = 0; @@ -85,8 +85,9 @@ ParanoidNumber & ParanoidNumber::operator=(const ParanoidNumber & a) #endif m_value = a.m_value; - #ifdef PARANOID_CACHE_RESULT + #ifdef PARANOID_CACHE_RESULTS m_cached_result = a.m_cached_result; + m_cache_valid = a.m_cache_valid; #endif for (int i = 0; i < NOP; ++i) { @@ -411,8 +412,9 @@ ParanoidNumber & ParanoidNumber::operator=(const digit_t & a) m_next[i].clear(); } m_value = a; - #ifdef PARANOID_CACHE_RESULT + #ifdef PARANOID_CACHE_RESULTS m_cached_result = a; + m_cache_valid = true; #endif #ifdef PARANOID_COMPARE_EPSILON @@ -427,7 +429,7 @@ ParanoidNumber * ParanoidNumber::OperationTerm(ParanoidNumber * b, Optype op, Pa { ////assert(b->SanityCheck()); #ifdef PARANOID_CACHE_RESULTS - m_cached_result = NAN; + m_cache_valid = false; #endif #ifdef PARANOID_SIZE_LIMIT if (m_size + b->m_size >= PARANOID_SIZE_LIMIT) @@ -438,7 +440,10 @@ ParanoidNumber * ParanoidNumber::OperationTerm(ParanoidNumber * b, Optype op, Pa else m_value -= b->Digit(); m_size = 1; - //Debug("Cut off %p", this); + #ifdef PARANOID_CACHE_RESULTS + m_cached_result = m_value; + m_cache_valid = true; + #endif return b; } //Debug("At size limit %d", m_size); @@ -561,7 +566,7 @@ ParanoidNumber * ParanoidNumber::OperationTerm(ParanoidNumber * b, Optype op, Pa ParanoidNumber * ParanoidNumber::OperationFactor(ParanoidNumber * b, Optype op, ParanoidNumber ** merge_point, Optype * merge_op) { #ifdef PARANOID_CACHE_RESULTS - m_cached_result = NAN; + m_cache_valid = false; #endif #ifdef PARANOID_SIZE_LIMIT if (m_size + b->m_size >= PARANOID_SIZE_LIMIT) @@ -572,7 +577,10 @@ ParanoidNumber * ParanoidNumber::OperationFactor(ParanoidNumber * b, Optype op, else m_value /= b->Digit(); m_size = 1; - + #ifdef PARANOID_CACHE_RESULTS + m_cached_result = m_value; + m_cache_valid = true; + #endif //Debug("Cut off %p", this); return b; @@ -838,10 +846,11 @@ ParanoidNumber::digit_t ParanoidNumber::Digit() const // Get around the absurd requirement that const correctness be observed. #ifdef PARANOID_CACHE_RESULTS + if (m_cache_valid) // le sigh ambiguous function compiler warnings + return m_cached_result; + digit_t & result = ((ParanoidNumber*)(this))->m_cached_result; - if (!isnan(float(result))) // le sigh ambiguous function compiler warnings - return result; #else digit_t result; #endif @@ -858,6 +867,10 @@ ParanoidNumber::digit_t ParanoidNumber::Digit() const result += add->Digit(); for (auto sub : m_next[SUBTRACT]) result -= sub->Digit(); + + #ifdef PARANOID_CACHE_RESULTS + ((ParanoidNumber*)(this))->m_cache_valid = true; + #endif return result; } @@ -932,6 +945,9 @@ void ParanoidNumber::Negate() { swap(m_next[ADD], m_next[SUBTRACT]); m_value = -m_value; + #ifdef PARANOID_CACHE_RESULTS + m_cached_result = -m_cached_result; + #endif } #ifdef PARANOID_USE_ARENA diff --git a/src/paranoidnumber.h b/src/paranoidnumber.h index 3a38286..a175ed5 100644 --- a/src/paranoidnumber.h +++ b/src/paranoidnumber.h @@ -19,11 +19,11 @@ //#define PARANOID_CACHE_RESULTS //#define PARANOID_USE_ARENA -#define PARANOID_SIZE_LIMIT 10 +//#define PARANOID_SIZE_LIMIT 3 // Define to compare all ops against double ops and check within epsilon -//#define PARANOID_COMPARE_EPSILON 1e- +//#define PARANOID_COMPARE_EPSILON 1e-6 #ifdef PARANOID_COMPARE_EPSILON #define CompareForSanity(...) ParanoidNumber::CompareForSanityEx(__func__, __FILE__, __LINE__, __VA_ARGS__) #endif @@ -93,6 +93,7 @@ namespace IPDF #endif #ifdef PARANOID_CACHE_RESULTS m_cached_result = value; + m_cache_valid = true; #endif } @@ -104,6 +105,7 @@ namespace IPDF #endif #ifdef PARANOID_CACHE_RESULTS m_cached_result = cpy.m_cached_result; + m_cache_valid = cpy.m_cache_valid; #endif for (int i = 0; i < NOP; ++i) { @@ -265,6 +267,7 @@ namespace IPDF digit_t m_value; #ifdef PARANOID_CACHE_RESULTS digit_t m_cached_result; + bool m_cache_valid; #endif std::vector m_next[4]; #ifdef PARANOID_SIZE_LIMIT @@ -275,7 +278,7 @@ namespace IPDF class Arena { public: - Arena(int64_t block_size = 10000000); + Arena(int64_t block_size = 10000); ~Arena(); void * allocate(size_t bytes); @@ -308,7 +311,7 @@ template T ParanoidNumber::Convert() const { #ifdef PARANOID_CACHE_RESULTS - if (!isnan((float(m_cached_result)))) + if (m_cache_valid) return (T)m_cached_result; #endif T value(m_value); diff --git a/src/path.cpp b/src/path.cpp index f12e2a7..04e537c 100644 --- a/src/path.cpp +++ b/src/path.cpp @@ -5,7 +5,7 @@ using namespace std; namespace IPDF { -Path::Path(const Objects & objects, unsigned start, unsigned end, const Colour & fill, const Colour & stroke) +Path::Path(Objects & objects, unsigned start, unsigned end, const Colour & fill, const Colour & stroke) : m_start(start), m_end(end), m_fill(fill), m_stroke(stroke) { Real xmin = 0; Real ymin = 0; @@ -53,6 +53,16 @@ Path::Path(const Objects & objects, unsigned start, unsigned end, const Colour & m_bottom = objects.beziers[objects.data_indices[bottom]].ToAbsolute(objects.bounds[bottom]).GetBottom(); m_left = objects.beziers[objects.data_indices[left]].ToAbsolute(objects.bounds[left]).GetLeft(); m_right = objects.beziers[objects.data_indices[right]].ToAbsolute(objects.bounds[right]).GetRight(); + + #ifdef TRANSFORM_BEZIERS_TO_PATH + Rect bounds = SolveBounds(objects); + for (unsigned i = m_start; i <= m_end; ++i) + { + //Debug("Transform %s -> %s", objects.bounds[i].Str().c_str(), bounds.Str().c_str()); + objects.bounds[i] = TransformRectCoordinates(bounds, objects.bounds[i]); + //Debug("-> %s", objects.bounds[i].Str().c_str()); + } + #endif } @@ -183,7 +193,12 @@ vector & Path::FillPoints(const Objects & objects, const View & view) Rect Path::SolveBounds(const Objects & objects) const { - return Rect(m_left.x, m_top.y, m_right.x-m_left.x, m_bottom.y-m_top.y); + return Rect(m_left.x, m_top.y, m_right.x-m_left.x, m_bottom.y-m_top.y); +} + +Rect & Path::GetBounds(Objects & objects) +{ + return objects.bounds[m_index]; } } diff --git a/src/path.h b/src/path.h index fa63cb4..7eb8dee 100644 --- a/src/path.h +++ b/src/path.h @@ -6,6 +6,13 @@ #include "rect.h" #include "real.h" +#ifdef QUADTREE_DISABLED + +#define TRANSFORM_BEZIERS_TO_PATH + + +#endif + namespace IPDF { @@ -26,9 +33,10 @@ namespace IPDF struct Path { - Path(const Objects & objects, unsigned _start, unsigned _end, const Colour & _fill = Colour(128,128,128,255), const Colour & _stroke = Colour(0,0,0,0)); + Path(Objects & objects, unsigned _start, unsigned _end, const Colour & _fill = Colour(128,128,128,255), const Colour & _stroke = Colour(0,0,0,0)); Rect SolveBounds(const Objects & objects) const; + Rect & GetBounds(Objects & objects); std::vector & FillPoints(const Objects & objects, const View & view); // Is point inside shape? diff --git a/src/rect.h b/src/rect.h index 5c600f3..b092fbe 100644 --- a/src/rect.h +++ b/src/rect.h @@ -42,10 +42,10 @@ namespace IPDF Rect out; Real w = (view.w == Real(0))?Real(1):view.w; Real h = (view.h == Real(0))?Real(1):view.h; - out.x = (r.x - view.x) / w; - out.y = (r.y - view.y) / h; - out.w = r.w / w; - out.h = r.h / h; + out.x = (r.x - view.x) / w; //r.x = out.x *w + view.x + out.y = (r.y - view.y) / h; // r.y = out.y*h + view.y + out.w = r.w / w; // r.w = out.w * w + out.h = r.h / h; // r.h = out.h * h return out; } diff --git a/src/svg-tests/paths.svg b/src/svg-tests/paths.svg index dd72201..2625fd9 100644 --- a/src/svg-tests/paths.svg +++ b/src/svg-tests/paths.svg @@ -7,22 +7,22 @@ width="400" height="400" > - - --> + - + transform="translate(227.32245,266.11266)" />--> diff --git a/src/tests/muldiv.cpp b/src/tests/muldiv.cpp index 19b1897..b89a5ad 100644 --- a/src/tests/muldiv.cpp +++ b/src/tests/muldiv.cpp @@ -10,9 +10,9 @@ int main(int argc, char ** argv) DebugRealInfo(); Debug("Repeated Multiplications and Divisions - Should give one"); - first_clock = clock(); - elapsed = 0; - for (int i = 1; i < 2; ++i) + clock_t first_clock = clock(); + clock_t elapsed = 0; + for (int i = 1; i < 100; ++i) { for (int j = 1; j < 100; ++j) { diff --git a/src/tests/realops.cpp b/src/tests/realops.cpp index 3c863a1..4669f59 100644 --- a/src/tests/realops.cpp +++ b/src/tests/realops.cpp @@ -4,6 +4,7 @@ #include "main.h" #include "real.h" +#include "progressbar.h" using namespace std; using namespace IPDF; @@ -27,8 +28,10 @@ int main(int argc, char ** argv) unsigned failures = 0; Real acumulate(0); double dacumulate = 0; + for (unsigned i = 0; i < TEST_CASES; ++i) { + ProgressBar(i, TEST_CASES, 50); //Debug("Test %u of %u", i, TEST_CASES); double da = (double)(rand() + 1) / (double)(rand() + 1); double db = (double)(rand() + 1) / (double)(rand() + 1); @@ -181,7 +184,6 @@ int main(int argc, char ** argv) Debug("\tStrings are a = %s, b = %s, aa = %s, bb = %s", a.Str().c_str(), b.Str().c_str(), aa.Str().c_str(), bb.Str().c_str()); #endif } - } Debug("Completed %u test cases with total of %u operations, %u failures", TEST_CASES, 18*TEST_CASES, failures); Debug("Total accumulated difference between Real and Double operations was %f", g_totalerror); diff --git a/src/view.cpp b/src/view.cpp index c96fb0a..9ad633c 100644 --- a/src/view.cpp +++ b/src/view.cpp @@ -7,6 +7,13 @@ #include "controlpanel.h" #endif //CONTROLPANEL_DISABLED + +#ifdef TRANSFORM_BEZIERS_TO_PATH + #ifndef TRANSFORM_OBJECTS_NOT_VIEW + //#error Cannot TRANSFORM_BEZIERS_TO_PATH _without_ TRANSFORM_OBJECTS_NOT_VIEW + #endif +#endif + using namespace IPDF; using namespace std; @@ -83,7 +90,11 @@ void View::Translate(Real x, Real y) m_buffer_dirty = true; m_bounds_dirty = true; #ifdef TRANSFORM_OBJECTS_NOT_VIEW - m_document.TranslateObjects(-x, -y); + ObjectType type = NUMBER_OF_OBJECT_TYPES; + #ifdef TRANSFORM_BEZIERS_TO_PATH + type = PATH; + #endif + m_document.TranslateObjects(-x, -y, type); #endif x *= m_bounds.w; y *= m_bounds.h; @@ -126,7 +137,11 @@ void View::ScaleAroundPoint(Real x, Real y, Real scale_amount) #ifdef TRANSFORM_OBJECTS_NOT_VIEW - m_document.ScaleObjectsAboutPoint(x, y, scale_amount); + ObjectType type = NUMBER_OF_OBJECT_TYPES; + #ifdef TRANSFORM_BEZIERS_TO_PATH + type = PATH; + #endif + m_document.ScaleObjectsAboutPoint(x, y, scale_amount, type); #endif x *= m_bounds.w; y *= m_bounds.h; @@ -159,12 +174,7 @@ Rect View::TransformToViewCoords(const Rect& inp) const #ifdef TRANSFORM_OBJECTS_NOT_VIEW return inp; #endif - Rect out; - out.x = (inp.x - m_bounds.x) / m_bounds.w; - out.y = (inp.y - m_bounds.y) / m_bounds.h; - out.w = inp.w / m_bounds.w; - out.h = inp.h / m_bounds.h; - return out; + return TransformRectCoordinates(m_bounds, inp); } /** @@ -486,6 +496,7 @@ void View::UpdateObjBoundsVBO(unsigned first_obj, unsigned last_obj) BufferBuilder obj_bounds_builder(m_objbounds_vbo.MapRange(first_obj*sizeof(GPUObjBounds), (last_obj-first_obj)*sizeof(GPUObjBounds), false, true, true), m_objbounds_vbo.GetSize()); + #ifndef TRANSFORM_BEZIERS_TO_PATH for (unsigned id = first_obj; id < last_obj; ++id) { Rect obj_bounds; @@ -505,8 +516,46 @@ void View::UpdateObjBoundsVBO(unsigned first_obj, unsigned last_obj) }; obj_bounds_builder.Add(gpu_bounds); - } + #else + for (unsigned i = 0; i < m_document.m_objects.paths.size(); ++i) + { + Path & path = m_document.m_objects.paths[i]; + Rect & pbounds = path.GetBounds(m_document.m_objects); // Not very efficient... + for (unsigned id = path.m_start; id <= path.m_end; ++id) + { + if (id < first_obj || id >= last_obj) + continue; + + Rect obj_bounds = m_document.m_objects.bounds[id]; + + obj_bounds.x *= pbounds.w; + obj_bounds.x += pbounds.x; + obj_bounds.y *= pbounds.h; + obj_bounds.y += pbounds.y; + obj_bounds.w *= pbounds.w; + obj_bounds.h *= pbounds.h; + + if (!m_use_gpu_transform) + obj_bounds = TransformToViewCoords(obj_bounds); + GPUObjBounds gpu_bounds = { + Float(obj_bounds.x), + Float(obj_bounds.y), + Float(obj_bounds.x + obj_bounds.w), + Float(obj_bounds.y + obj_bounds.h) + }; + obj_bounds_builder.Add(gpu_bounds); + //Debug("Path %d %s -> %s via %s", id, m_document.m_objects.bounds[id].Str().c_str(), obj_bounds.Str().c_str(), pbounds.Str().c_str()); + } + GPUObjBounds p_gpu_bounds = { + Float(pbounds.x), + Float(pbounds.y), + Float(pbounds.x + pbounds.w), + Float(pbounds.y + pbounds.h) + }; + obj_bounds_builder.Add(p_gpu_bounds); + } + #endif m_objbounds_vbo.UnMap(); } /** @@ -554,7 +603,9 @@ void View::PrepareRender() m_object_renderers[i]->FinaliseBuffers(); } if (UsingGPURendering()) + { dynamic_cast(m_object_renderers[BEZIER])->PrepareBezierGPUBuffer(m_document.m_objects); + } m_render_dirty = false; } diff --git a/src/view.h b/src/view.h index 5ea06a0..66ccee8 100644 --- a/src/view.h +++ b/src/view.h @@ -12,7 +12,7 @@ #ifdef QUADTREE_DISABLED -#define TRANSFORM_OBJECTS_NOT_VIEW +//#define TRANSFORM_OBJECTS_NOT_VIEW #endif