From 2a1715c907ba3ccfb952e9630c3fe305655637e0 Mon Sep 17 00:00:00 2001 From: Sam Moore Date: Fri, 15 Aug 2014 04:20:37 +0800 Subject: [PATCH] Attempt Shading + Bezier Bounds (hopefully) correct Turns out I can't do high school calculus despite 4 years of Physics study. The shading algorithm I envisioned has several rather hilarious things wrong with it... Although that 'j' does look damn good if you set the zoom *just* right... --- src/bezier.cpp | 5 +- src/bezier.h | 4 +- src/document.cpp | 27 ++++---- src/objectrenderer.cpp | 40 +++++++++++- src/objectrenderer.h | 2 + src/screen.cpp | 4 +- src/svg-tests/cubicbeziers.svg | 108 +++++++++++++++++++++++++++++++ src/svg-tests/shape_pathonly.svg | 18 ++++++ 8 files changed, 191 insertions(+), 17 deletions(-) create mode 100644 src/svg-tests/cubicbeziers.svg create mode 100644 src/svg-tests/shape_pathonly.svg diff --git a/src/bezier.cpp b/src/bezier.cpp index a30a20a..da65336 100644 --- a/src/bezier.cpp +++ b/src/bezier.cpp @@ -59,8 +59,8 @@ static pair BezierTurningPoints(const Real & p0, const Real & p1, co { return pair(0, 1); } - Real a = (p1- p0 - 2*(p2-p1) + p3-p2); - Real b = (p1-p0 - (p2-p1))*(p1-p0); + Real a = (3*(p1-p2) + p3 - p0); + Real b = 2*(p2 - 2*p1 + p0); Real c = (p1-p0); if (a == 0) { @@ -74,6 +74,7 @@ static pair BezierTurningPoints(const Real & p0, const Real & p1, co Debug("a, b, c are %f, %f, %f", Float(a), Float(b), Float(c)); if (b*b - 4*a*c < 0) { + Debug("No real roots"); return pair(0,1); } pair tsols = SolveQuadratic(a, b, c); diff --git a/src/bezier.h b/src/bezier.h index 722ed57..f3df458 100644 --- a/src/bezier.h +++ b/src/bezier.h @@ -11,8 +11,8 @@ namespace IPDF inline std::pair SolveQuadratic(const Real & a, const Real & b, const Real & c) { - Real x0((b + Sqrt(b*b - Real(4)*a*c))/(Real(2)*a)); - Real x1((b - Sqrt(b*b - Real(4)*a*c))/(Real(2)*a)); + Real x0((-b + Sqrt(b*b - Real(4)*a*c))/(Real(2)*a)); + Real x1((-b - Sqrt(b*b - Real(4)*a*c))/(Real(2)*a)); return std::pair(x0,x1); } diff --git a/src/document.cpp b/src/document.cpp index 4cf6c40..16cb8f9 100644 --- a/src/document.cpp +++ b/src/document.cpp @@ -389,7 +389,7 @@ static void TransformXYPair(Real & x, Real & y, const SVGMatrix & transform) void Document::ParseSVGTransform(const string & s, SVGMatrix & transform) { - Debug("Parsing transform %s", s.c_str()); + //Debug("Parsing transform %s", s.c_str()); string token; string command; unsigned i = 0; @@ -404,7 +404,7 @@ void Document::ParseSVGTransform(const string & s, SVGMatrix & transform) else return; } - Debug("Token is \"%s\"", command.c_str()); + //Debug("Token is \"%s\"", command.c_str()); SVGMatrix delta = {1,0,0,0,1,0}; @@ -443,8 +443,8 @@ void Document::ParseSVGTransform(const string & s, SVGMatrix & transform) Warn("Unrecognised transform \"%s\", using identity", command.c_str()); } - Debug("Old transform is {%f,%f,%f,%f,%f,%f}", transform.a, transform.b, transform.c, transform.d,transform.e,transform.f); - Debug("Delta transform is {%f,%f,%f,%f,%f,%f}", delta.a, delta.b, delta.c, delta.d,delta.e,delta.f); + //Debug("Old transform is {%f,%f,%f,%f,%f,%f}", transform.a, transform.b, transform.c, transform.d,transform.e,transform.f); + //Debug("Delta transform is {%f,%f,%f,%f,%f,%f}", delta.a, delta.b, delta.c, delta.d,delta.e,delta.f); SVGMatrix old(transform); transform.a = old.a * delta.a + old.c * delta.b; @@ -455,13 +455,13 @@ void Document::ParseSVGTransform(const string & s, SVGMatrix & transform) transform.d = old.b * delta.c + old.d * delta.d; transform.f = old.b * delta.e + old.d * delta.f + old.f; - Debug("New transform is {%f,%f,%f,%f,%f,%f}", transform.a, transform.b, transform.c, transform.d,transform.e,transform.f); + //Debug("New transform is {%f,%f,%f,%f,%f,%f}", transform.a, transform.b, transform.c, transform.d,transform.e,transform.f); } } void Document::ParseSVGNode(pugi::xml_node & root, SVGMatrix & parent_transform) { - Debug("Parse node <%s>", root.name()); + //Debug("Parse node <%s>", root.name()); for (pugi::xml_node child = root.first_child(); child; child = child.next_sibling()) @@ -818,7 +818,8 @@ void Document::AddFontGlyphAtPoint(stbtt_fontinfo *font, int character, Real sca int num_instructions = stbtt_GetGlyphShape(font, glyph_index, &instructions); Real current_x(0), current_y(0); - + unsigned start_index = m_count; + unsigned end_index = m_count; for (int i = 0; i < num_instructions; ++i) { // TTF uses 16-bit signed ints for coordinates: @@ -831,7 +832,7 @@ void Document::AddFontGlyphAtPoint(stbtt_fontinfo *font, int character, Real sca Real old_x(current_x), old_y(current_y); current_x = inst_x; current_y = inst_y; - //unsigned bezier_index; + switch(instructions[i].type) { // Move To @@ -839,8 +840,7 @@ void Document::AddFontGlyphAtPoint(stbtt_fontinfo *font, int character, Real sca break; // Line To case STBTT_vline: - AddBezier(Bezier(old_x + x, old_y + y, old_x + x, old_y + y, current_x + x, current_y + y, current_x + x, current_y + y)); - //Add(BEZIER,Rect(0,0,1,1),bezier_index); + end_index = AddBezier(Bezier(old_x + x, old_y + y, old_x + x, old_y + y, current_x + x, current_y + y, current_x + x, current_y + y)); break; // Quadratic Bezier To: case STBTT_vcurve: @@ -848,11 +848,16 @@ void Document::AddFontGlyphAtPoint(stbtt_fontinfo *font, int character, Real sca // - Endpoints are the same. // - cubic1 = quad0+(2/3)*(quad1-quad0) // - cubic2 = quad2+(2/3)*(quad1-quad2) - AddBezier(Bezier(old_x + x, old_y + y, old_x + Real(2)*(inst_cx-old_x)/Real(3) + x, old_y + Real(2)*(inst_cy-old_y)/Real(3) + y, + end_index = AddBezier(Bezier(old_x + x, old_y + y, old_x + Real(2)*(inst_cx-old_x)/Real(3) + x, old_y + Real(2)*(inst_cy-old_y)/Real(3) + y, current_x + Real(2)*(inst_cx-current_x)/Real(3) + x, current_y + Real(2)*(inst_cy-current_y)/Real(3) + y, current_x + x, current_y + y)); break; } } + + if (start_index < m_count && end_index < m_count) + { + AddGroup(start_index, end_index); + } stbtt_FreeShape(font, instructions); } diff --git a/src/objectrenderer.cpp b/src/objectrenderer.cpp index 7a0f8cd..ed4db41 100644 --- a/src/objectrenderer.cpp +++ b/src/objectrenderer.cpp @@ -227,11 +227,12 @@ void BezierRenderer::RenderUsingCPU(const Objects & objects, const View & view, Bezier control(objects.beziers[objects.data_indices[m_indexes[i]]].ToAbsolute(bounds),CPURenderBounds(Rect(0,0,1,1), view, target)); //Debug("%s -> %s via %s", objects.beziers[objects.data_indices[m_indexes[i]]].Str().c_str(), control.Str().c_str(), bounds.Str().c_str()); // Draw a rectangle around the bezier for debugging the bounds rectangle calculations + /* ObjectRenderer::RenderLineOnCPU(pix_bounds.x, pix_bounds.y, pix_bounds.x+pix_bounds.w, pix_bounds.y, target, Colour(1,0,0,1)); ObjectRenderer::RenderLineOnCPU(pix_bounds.x, pix_bounds.y+pix_bounds.h, pix_bounds.x+pix_bounds.w, pix_bounds.y+pix_bounds.h, target, Colour(0,1,0,1)); ObjectRenderer::RenderLineOnCPU(pix_bounds.x, pix_bounds.y, pix_bounds.x, pix_bounds.y+pix_bounds.h, target, Colour(1,0,0,1)); 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,1,0,1)); - + */ // Draw lines between the control points for debugging //ObjectRenderer::RenderLineOnCPU((int64_t)control.x0, (int64_t)control.y0, (int64_t)control.x1, (int64_t)control.y1,target); //ObjectRenderer::RenderLineOnCPU((int64_t)control.x1, (int64_t)control.y1, (int64_t)control.x2, (int64_t)control.y2,target); @@ -341,15 +342,52 @@ void GroupRenderer::RenderUsingCPU(const Objects & objects, const View & view, c if (m_indexes[i] < first_obj_id) continue; if (m_indexes[i] >= last_obj_id) continue; + Rect bounds(CPURenderBounds(objects.bounds[m_indexes[i]], view, target)); PixelBounds pix_bounds(bounds); Colour c(0.5,0.5,1,1); + // make the bounds just a little bit bigger + pix_bounds.x--; + pix_bounds.w++; + pix_bounds.y--; + pix_bounds.h++; + /* ObjectRenderer::RenderLineOnCPU(pix_bounds.x, pix_bounds.y, pix_bounds.x+pix_bounds.w, pix_bounds.y, target, c); ObjectRenderer::RenderLineOnCPU(pix_bounds.x, pix_bounds.y+pix_bounds.h, pix_bounds.x+pix_bounds.w, pix_bounds.y+pix_bounds.h, target, c); ObjectRenderer::RenderLineOnCPU(pix_bounds.x, pix_bounds.y, pix_bounds.x, pix_bounds.y+pix_bounds.h, target, c); ObjectRenderer::RenderLineOnCPU(pix_bounds.x+pix_bounds.w, pix_bounds.y, pix_bounds.x+pix_bounds.w, pix_bounds.y+pix_bounds.h, target, c); + */ + // Attempt to shade the region + // Assumes the outline has been drawn first... + for (int64_t y = max((int64_t)0, pix_bounds.y); y <= min(pix_bounds.y+pix_bounds.h, target.h-1); ++y) + { + bool inside = false; + bool online = false; + for (int64_t x = max((int64_t)0, pix_bounds.x); x <= min(pix_bounds.x+pix_bounds.w, target.w-1); ++x) + { + int64_t index = (x+target.w*y)*4; + if (target.pixels[index+0] == 0 && target.pixels[index+1] == 0 && target.pixels[index+2] == 0 && target.pixels[index+3] == 255) + { + online = true; + continue; + } + else if (online) + { + inside = !inside; + online = false; + } + + if (inside) + { + target.pixels[index+0] = c.r*255; + target.pixels[index+1] = c.g*255; + target.pixels[index+2] = c.b*255; + target.pixels[index+3] = c.a*255; + } + } + } } diff --git a/src/objectrenderer.h b/src/objectrenderer.h index e3872b0..70339e7 100644 --- a/src/objectrenderer.h +++ b/src/objectrenderer.h @@ -136,6 +136,8 @@ namespace IPDF GroupRenderer() : ObjectRenderer(GROUP, "shaders/rect_vert.glsl", "shaders/rect_frag.glsl", "shaders/rect_outline_geom.glsl") {} virtual ~GroupRenderer() {} virtual void RenderUsingCPU(const 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) {} }; } diff --git a/src/screen.cpp b/src/screen.cpp index 27675d5..f075684 100644 --- a/src/screen.cpp +++ b/src/screen.cpp @@ -18,7 +18,9 @@ static void opengl_debug_callback(GLenum source, GLenum type, GLuint id, GLenum { // Don't print out gl Errors we generated. if (source == GL_DEBUG_SOURCE_APPLICATION) return; - Error("OpenGL Error (%d): %s", id, msg); + //Error("OpenGL Error (%d): %s", id, msg); + // Spams this message on fglrx, disabling for now because it's damn annoying. + // ERROR: opengl_debug_callback (screen.cpp:21) - OpenGL Error (1011): glObjectLabel failed because (depending on the operation) a referenced binding point is empty; a referenced name is not the name of an object; or the given name is otherwise not valid to this operation (GL_INVALID_VALUE) } diff --git a/src/svg-tests/cubicbeziers.svg b/src/svg-tests/cubicbeziers.svg new file mode 100644 index 0000000..9597357 --- /dev/null +++ b/src/svg-tests/cubicbeziers.svg @@ -0,0 +1,108 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + diff --git a/src/svg-tests/shape_pathonly.svg b/src/svg-tests/shape_pathonly.svg new file mode 100644 index 0000000..0306a61 --- /dev/null +++ b/src/svg-tests/shape_pathonly.svg @@ -0,0 +1,18 @@ + + + + + + + -- 2.20.1