From 53579b1a949fa3e4e193f8dfba2064edbb123f57 Mon Sep 17 00:00:00 2001 From: Sam Moore Date: Thu, 14 Aug 2014 12:21:31 +0800 Subject: [PATCH] Bezier bounds rectangles are calculated correctly CPU rendering and SVG parsing uses absolute coordinates. GPU rendering uses relative coordinates (relative to the bounding box). The Objects struct stores the absolute bounding boxes now. Previously it was just using {0,0,1,1} (and thus the GPU's relative coordinates were equivelant to the CPU's absolute coordinates). I might have fixed some other things but I can't remember. --- src/bezier.cpp | 91 ++++++++++++++++++++++++++++++++++++ src/bezier.h | 65 ++++++++++++++++++++++++-- src/document.cpp | 52 ++++++++++++++------- src/document.h | 6 ++- src/ipdf.h | 14 +++--- src/main.cpp | 25 +--------- src/objectrenderer.cpp | 50 +++++++++++++------- src/objectrenderer.h | 10 ++++ src/real.h | 4 ++ src/svg-tests/circlepath.svg | 18 +++++++ src/view.cpp | 1 + 11 files changed, 269 insertions(+), 67 deletions(-) create mode 100644 src/svg-tests/circlepath.svg diff --git a/src/bezier.cpp b/src/bezier.cpp index f0e1f4d..a30a20a 100644 --- a/src/bezier.cpp +++ b/src/bezier.cpp @@ -2,6 +2,7 @@ #include #include +#include using namespace std; @@ -45,4 +46,94 @@ Real Bernstein(int k, int n, const Real & u) return Real(BinomialCoeff(n, k)) * Power(u, k) * Power(Real(1.0) - u, n-k); } + +/** + * Returns the parametric parameter at the turning point(s) + * In one coordinate direction + */ + +static pair BezierTurningPoints(const Real & p0, const Real & p1, const Real & p2, const Real & p3) +{ + // straight line + if (p1 == p2 && p2 == p3) + { + return pair(0, 1); + } + Real a = (p1- p0 - 2*(p2-p1) + p3-p2); + Real b = (p1-p0 - (p2-p1))*(p1-p0); + Real c = (p1-p0); + if (a == 0) + { + if (b == 0) + return pair(0,1); + Real t = -c/b; + if (t > 1) t = 1; + if (t < 0) t = 0; + return pair(t, t); + } + Debug("a, b, c are %f, %f, %f", Float(a), Float(b), Float(c)); + if (b*b - 4*a*c < 0) + { + return pair(0,1); + } + pair tsols = SolveQuadratic(a, b, c); + if (tsols.first > 1) tsols.first = 1; + if (tsols.first < 0) tsols.first = 0; + if (tsols.second > 1) tsols.second = 1; + if (tsols.second < 0) tsols.second = 0; + return tsols; } + +inline bool CompRealByPtr(const Real * a, const Real * b) +{ + return (*a) < (*b); +} + +/** + * Get Bounds Rectangle of Bezier + */ +Rect Bezier::SolveBounds() const +{ + Rect result; + pair tsols = BezierTurningPoints(x0, x1, x2, x3); + + Real tp0; Real tp1; Real o; + Evaluate(tp0, o, tsols.first); + Evaluate(tp1, o, tsols.second); + + Debug("x: tp0 is %f tp1 is %f", Float(tp0), Float(tp1)); + + vector v(4); + v[0] = &x0; + v[1] = &x3; + v[2] = &tp0; + v[3] = &tp1; + + // Not using a lambda to keep this compiling on cabellera + sort(v.begin(), v.end(), CompRealByPtr); + + result.x = *(v[0]); + result.w = *(v[3]) - result.x; + + // Do the same thing for y component (wow this is a mess) + tsols = BezierTurningPoints(y0, y1, y2, y3); + Evaluate(o, tp0, tsols.first); + Evaluate(o, tp1, tsols.second); + + + Debug("y: tp0 is %f tp1 is %f", Float(tp0), Float(tp1)); + + v[0] = &y0; + v[1] = &y3; + v[2] = &tp0; + v[3] = &tp1; + sort(v.begin(), v.end(), CompRealByPtr); + + result.y = *(v[0]); + result.h = *(v[3]) - result.y; + + Debug("Solved Bezier %s bounds as %s", Str().c_str(), result.Str().c_str()); + return result; +} + +} // end namespace diff --git a/src/bezier.h b/src/bezier.h index 0e9217f..449d7bd 100644 --- a/src/bezier.h +++ b/src/bezier.h @@ -8,6 +8,13 @@ namespace IPDF extern int Factorial(int n); extern int BinomialCoeff(int n, int k); extern Real Bernstein(int k, int n, const Real & u); + + 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)); + return std::pair(x0,x1); + } /** A _cubic_ bezier. **/ struct Bezier @@ -17,7 +24,10 @@ namespace IPDF Real x2; Real y2; Real x3; Real y3; Bezier() = default; // Needed so we can fread/fwrite this struct... for now. - Bezier(Real _x0, Real _y0, Real _x1, Real _y1, Real _x2, Real _y2, Real _x3, Real _y3) : x0(_x0), y0(_y0), x1(_x1), y1(_y1), x2(_x2), y2(_y2), x3(_x3), y3(_y3) {} + Bezier(Real _x0, Real _y0, Real _x1, Real _y1, Real _x2, Real _y2, Real _x3, Real _y3) : x0(_x0), y0(_y0), x1(_x1), y1(_y1), x2(_x2), y2(_y2), x3(_x3), y3(_y3) + { + + } Bezier(Real _x0, Real _y0, Real _x1, Real _y1, Real _x2, Real _y2) : x0(_x0), y0(_y0), x1(_x1), y1(_y1), x2(_x2), y2(_y2), x3(_x2), y3(_y2) {} @@ -27,6 +37,11 @@ namespace IPDF s << "Bezier{" << Float(x0) << "," << Float(y0) << " -> " << Float(x1) << "," << Float(y1) << " -> " << Float(x2) << "," << Float(y2) << " -> " << Float(x3) << "," << Float(y3) << "}"; return s.str(); } + + /** + * Construct absolute control points using relative control points to a bounding rectangle + * ie: If cpy is relative to bounds rectangle, this will be absolute + */ Bezier(const Bezier & cpy, const Rect & t = Rect(0,0,1,1)) : x0(cpy.x0), y0(cpy.y0), x1(cpy.x1), y1(cpy.y1), x2(cpy.x2),y2(cpy.y2), x3(cpy.x3), y3(cpy.y3) { x0 *= t.w; @@ -47,10 +62,54 @@ namespace IPDF y3 += t.y; } - Rect ToRect() {return Rect(x0,y0,x3-x0,y3-y0);} + Rect SolveBounds() const; + + /** Convert absolute control points to control points relative to bounds + * (This basically does the opposite of the Copy constructor) + * ie: If this is absolute, the returned Bezier will be relative to the bounds rectangle + */ + Bezier CopyInverse(const Rect & bounds) const + { + // x' <- (x - x0)/w etc + // special cases when w or h = 0 + // (So can't just use the Copy constructor on the inverse of bounds) + // Rect inverse = {-bounds.x/bounds.w, -bounds.y/bounds.h, Real(1)/bounds.w, Real(1)/bounds.h}; + Bezier result; + if (bounds.w == 0) + { + result.x0 = 0; + result.x1 = 0; + result.x2 = 0; + result.x3 = 0; + } + else + { + result.x0 = (x0 - bounds.x)/bounds.w; + result.x1 = (x1 - bounds.x)/bounds.w; + result.x2 = (x2 - bounds.x)/bounds.w; + result.x3 = (x3 - bounds.x)/bounds.w; + } + + if (bounds.h == 0) + { + result.y0 = 0; + result.y1 = 0; + result.y2 = 0; + result.y3 = 0; + } + else + { + result.y0 = (y0 - bounds.y)/bounds.h; + result.y1 = (y1 - bounds.y)/bounds.h; + result.y2 = (y2 - bounds.y)/bounds.h; + result.y3 = (y3 - bounds.y)/bounds.h; + } + return result; + } + /** Evaluate the Bezier at parametric parameter u, puts resultant point in (x,y) **/ - void Evaluate(Real & x, Real & y, const Real & u) + void Evaluate(Real & x, Real & y, const Real & u) const { Real coeff[4]; for (unsigned i = 0; i < 4; ++i) diff --git a/src/document.cpp b/src/document.cpp index dab0868..65a07ec 100644 --- a/src/document.cpp +++ b/src/document.cpp @@ -254,6 +254,11 @@ void Document::Load(const string & filename) Debug("Bezier data..."); LoadStructVector(file, chunk_size/sizeof(Bezier), m_objects.beziers); break; + + case CT_OBJGROUPS: + Debug("Group data..."); + Warn("Not handled because lazy"); + break; } } Debug("Successfully loaded %u objects from \"%s\"", ObjectCount(), filename.c_str()); @@ -265,12 +270,28 @@ void Document::Load(const string & filename) #endif } -void Document::Add(ObjectType type, const Rect & bounds, unsigned data_index) +unsigned Document::AddGroup(unsigned start_index, unsigned end_index) +{ + //TODO: Set bounds rect? + unsigned result = Add(GROUP, Rect(0,0,1,1),0); + m_objects.groups[m_count-1].first = start_index; + m_objects.groups[m_count-1].second = end_index; + return result; +} + +unsigned Document::AddBezier(const Bezier & bezier) +{ + unsigned index = AddBezierData(bezier); + return Add(BEZIER, bezier.SolveBounds(), index); +} + +unsigned Document::Add(ObjectType type, const Rect & bounds, unsigned data_index) { m_objects.types.push_back(type); m_objects.bounds.push_back(bounds); m_objects.data_indices.push_back(data_index); - ++m_count; // Why can't we just use the size of types or something? + m_objects.groups.push_back(pair(data_index, data_index)); + return (m_count++); // Why can't we just use the size of types or something? } unsigned Document::AddBezierData(const Bezier & bezier) @@ -440,7 +461,9 @@ void Document::ParseSVGNode(pugi::xml_node & root, SVGMatrix & parent_transform) { string d = child.attribute("d").as_string(); Debug("Path data attribute is \"%s\"", d.c_str()); - ParseSVGPathData(d, transform); + pair range = ParseSVGPathData(d, transform); + AddGroup(range.first, range.second); + } else if (strcmp(child.name(), "line") == 0) { @@ -450,8 +473,7 @@ void Document::ParseSVGNode(pugi::xml_node & root, SVGMatrix & parent_transform) Real y1(child.attribute("y2").as_float()); TransformXYPair(x0,y0,transform); TransformXYPair(x1,y1,transform); - unsigned index = AddBezierData(Bezier(x0,y0,x1,y1,x1,y1,x1,y1)); - Add(BEZIER, Rect(0,0,1,1), index); + AddBezier(Bezier(x0,y0,x1,y1,x1,y1,x1,y1)); } else if (strcmp(child.name(), "rect") == 0) { @@ -524,7 +546,7 @@ void Document::LoadSVG(const string & filename, const Rect & bounds) // Fear the wrath of the tokenizing svg data // Seriously this isn't really very DOM-like at all is it? -void Document::ParseSVGPathData(const string & d, const SVGMatrix & transform) +pair Document::ParseSVGPathData(const string & d, const SVGMatrix & transform) { Real x[4] = {0,0,0,0}; Real y[4] = {0,0,0,0}; @@ -540,7 +562,10 @@ void Document::ParseSVGPathData(const string & d, const SVGMatrix & transform) bool start = false; + static string delims("()[],{}<>;:=LlHhVvmMqQzZcC"); + + pair range(m_count, m_count); while (i < d.size() && GetToken(d, token, i, delims).size() > 0) { @@ -609,9 +634,7 @@ void Document::ParseSVGPathData(const string & d, const SVGMatrix & transform) for (int j = 0; j < 4; ++j) TransformXYPair(x[j],y[j], transform); - unsigned index = AddBezierData(Bezier(x[0],y[0],x[1],y[1],x[2],y[2],x[3],y[3])); - Add(BEZIER,Rect(0,0,1,1),index); - + range.second = AddBezier(Bezier(x[0],y[0],x[1],y[1],x[2],y[2],x[3],y[3])); //Debug("[%u] curveto %f,%f %f,%f %f,%f", index, Float(x[1]),Float(y[1]),Float(x[2]),Float(y[2]),Float(x[3]),Float(y[3])); @@ -654,8 +677,7 @@ void Document::ParseSVGPathData(const string & d, const SVGMatrix & transform) TransformXYPair(x[1],y[1],transform); - unsigned index = AddBezierData(Bezier(x[0],y[0],x[1],y[1],x[1],y[1],x[1],y[1])); - Add(BEZIER,Rect(0,0,1,1),index); + range.second = AddBezier(Bezier(x[0],y[0],x[1],y[1],x[1],y[1],x[1],y[1])); //Debug("[%u] lineto %f,%f %f,%f", index, Float(x[0]),Float(y[0]),Float(x[1]),Float(y[1])); @@ -678,9 +700,7 @@ void Document::ParseSVGPathData(const string & d, const SVGMatrix & transform) for (int j = 0; j < 4; ++j) TransformXYPair(x[j],y[j], transform); - unsigned index = AddBezierData(Bezier(x[0],y[0],x[1],y[1],x[2],y[2],x[3],y[3])); - Add(BEZIER,Rect(0,0,1,1),index); - + range.second = AddBezier(Bezier(x[0],y[0],x[1],y[1],x[2],y[2],x[3],y[3])); //Debug("[%u] returnto %f,%f %f,%f", index, Float(x[0]),Float(y[0]),Float(x[1]),Float(y[1])); x[0] = x3; @@ -701,6 +721,7 @@ void Document::ParseSVGPathData(const string & d, const SVGMatrix & transform) } prev_i = i; } + return range; } void Document::SetFont(const string & font_filename) @@ -804,9 +825,8 @@ 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) - bezier_index = AddBezierData(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, + bezier_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)); - Add(BEZIER,Rect(0,0,1,1),bezier_index); break; } } diff --git a/src/document.h b/src/document.h index 76e3b7f..6592f4b 100644 --- a/src/document.h +++ b/src/document.h @@ -50,7 +50,9 @@ namespace IPDF bool operator==(const Document & equ) const; bool operator!=(const Document & equ) const {return !(this->operator==(equ));} - void Add(ObjectType type, const Rect & bounds, unsigned data_index = 0); + unsigned AddGroup(unsigned start_index, unsigned end_index); + unsigned AddBezier(const Bezier & bezier); + unsigned Add(ObjectType type, const Rect & bounds, unsigned data_index = 0); unsigned AddBezierData(const Bezier & bezier); @@ -67,7 +69,7 @@ namespace IPDF /** Parse an SVG node or SVG-group node, adding children to the document **/ void ParseSVGNode(pugi::xml_node & root, SVGMatrix & transform); /** Parse an SVG path with string **/ - void ParseSVGPathData(const std::string & d, const SVGMatrix & transform); + std::pair ParseSVGPathData(const std::string & d, const SVGMatrix & transform); /** Modify an SVG transformation matrix **/ static void ParseSVGTransform(const std::string & s, SVGMatrix & transform); diff --git a/src/ipdf.h b/src/ipdf.h index cd6ef6f..ff31533 100644 --- a/src/ipdf.h +++ b/src/ipdf.h @@ -29,6 +29,7 @@ namespace IPDF RECT_FILLED, RECT_OUTLINE, BEZIER, + GROUP, NUMBER_OF_OBJECT_TYPES } ObjectType; @@ -38,8 +39,8 @@ namespace IPDF CT_OBJTYPES, CT_OBJBOUNDS, CT_OBJINDICES, - CT_OBJBEZIERS - //CT_OBJGROUPS + CT_OBJBEZIERS, + CT_OBJGROUPS }; @@ -52,11 +53,10 @@ namespace IPDF Colour() = default; Colour(float _r, float _g, float _b, float _a) : r(_r), g(_g), b(_b), a(_a) {} }; - - struct ObjectData + + struct Group { - Colour colour; - + Colour shading; }; struct Objects @@ -70,6 +70,8 @@ namespace IPDF /** Used by BEZIER only **/ std::vector beziers; // bezier curves - look up by data_indices + + std::vector > groups; }; class View; diff --git a/src/main.cpp b/src/main.cpp index 8942a9c..718361f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -82,29 +82,8 @@ int main(int argc, char ** argv) } else { -/* doc.AddBezierData(Bezier(0,0,0,1,1,0)); - doc.AddBezierData(Bezier(0,0,1,0,0,1)); - doc.AddBezierData(Bezier(0,0,1,1,1,0)); - doc.AddBezierData(Bezier(0,1,1,0,0,1));*/ - - - - doc.AddText("abcde", 0.5, Real(0), Real(1)); - - for(int x = 0; x < 8; ++x) - { - - for (int y = 0; y < 8; ++y) - { - //doc.Add(static_cast((x^y)%3), Rect(0.2+x-4.0,0.2+y-4.0,0.6,0.6)); - //doc.Add(BEZIER, Rect(0.2+x-4.0, 0.2+y-4.0, 0.6,0.6), (x^y)%3); - } - } - /* doc.Add(BEZIER, Rect(0.1,0.1,0.8,0.8), 0); - doc.Add(BEZIER, Rect(0.1,0.1,0.8,0.8), 1); - doc.Add(BEZIER, Rect(0.1,0.1,0.8,0.8), 2); - doc.Add(BEZIER, Rect(0.1,0.1,0.8,0.8), 3);*/ - //doc.Add(CIRCLE_FILLED, Rect(0.1,0.1,0.8,0.8), 0); + //doc.AddBezier(Bezier(0,0, 1,0.5, 0.5,1, 1,1)); + doc.AddText("c",1,0,0); } Debug("Start!"); Rect bounds(b[0],b[1],b[2],b[3]); diff --git a/src/objectrenderer.cpp b/src/objectrenderer.cpp index 76aba52..4b77f00 100644 --- a/src/objectrenderer.cpp +++ b/src/objectrenderer.cpp @@ -42,7 +42,7 @@ void ObjectRenderer::RenderUsingGPU(unsigned first_obj_id, unsigned last_obj_id) m_shader_program.Use(); m_ibo.Bind(); - glDrawElements(GL_LINES, (last_index-first_index)*2, GL_UNSIGNED_INT, (GLvoid*)(2*first_index*sizeof(uint32_t))); + glDrawElements(GL_LINES, (last_index-first_index)*2, GL_UNSIGNED_INT, (GLvoid*)(first_index*sizeof(uint32_t))); } @@ -72,7 +72,6 @@ void ObjectRenderer::PrepareBuffers(unsigned max_objects) m_ibo.Invalidate(); m_ibo.SetUsage(GraphicsBuffer::BufferUsageStaticDraw); m_ibo.SetType(GraphicsBuffer::BufferTypeIndex); - m_ibo.SetName("m_ibo: ObjectRenderer GPU indices"); m_ibo.Resize(max_objects * 2 * sizeof(uint32_t)); // BufferBuilder is used to construct the ibo m_buffer_builder = new BufferBuilder(m_ibo.Map(false, true, true), m_ibo.GetSize()); // new matches delete in ObjectRenderer::FinaliseBuffers @@ -225,14 +224,13 @@ void BezierRenderer::RenderUsingCPU(const Objects & objects, const View & view, Rect bounds(CPURenderBounds(objects.bounds[m_indexes[i]], view, target)); PixelBounds pix_bounds(bounds); - - Bezier control(objects.beziers[objects.data_indices[m_indexes[i]]], bounds); + Bezier control(objects.beziers[objects.data_indices[m_indexes[i]]],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 coord transforms - //ObjectRenderer::RenderLineOnCPU(pix_bounds.x, pix_bounds.y, pix_bounds.x+pix_bounds.w, pix_bounds.y, target); - //ObjectRenderer::RenderLineOnCPU(pix_bounds.x, pix_bounds.y+pix_bounds.h, pix_bounds.x+pix_bounds.w, pix_bounds.y+pix_bounds.h, target); - //ObjectRenderer::RenderLineOnCPU(pix_bounds.x, pix_bounds.y, pix_bounds.x, pix_bounds.y+pix_bounds.h, target); - //ObjectRenderer::RenderLineOnCPU(pix_bounds.x+pix_bounds.w, pix_bounds.y, pix_bounds.x+pix_bounds.w, pix_bounds.y+pix_bounds.h, target); + // 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(0,0,1,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(1,0,1,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); @@ -278,17 +276,20 @@ void BezierRenderer::PrepareBezierGPUBuffer(const Objects& objects) { m_bezier_coeffs.SetType(GraphicsBuffer::BufferTypeTexture); m_bezier_coeffs.SetUsage(GraphicsBuffer::BufferUsageDynamicDraw); - m_bezier_coeffs.SetName("m_bezier_coeffs: Bezier coefficients"); m_bezier_coeffs.Resize(objects.beziers.size()*sizeof(GPUBezierCoeffs)); BufferBuilder builder(m_bezier_coeffs.Map(false, true, true), m_bezier_coeffs.GetSize()); - for (auto bez = objects.beziers.begin(); bez != objects.beziers.end(); ++bez) + + for (unsigned i = 0; i < objects.types.size(); ++i) { + if (objects.types[i] != BEZIER) continue; + Bezier bez = objects.beziers[objects.data_indices[i]].CopyInverse(objects.bounds[i]); + GPUBezierCoeffs coeffs = { - Float(bez->x0), Float(bez->y0), - Float(bez->x1), Float(bez->y1), - Float(bez->x2), Float(bez->y2), - Float(bez->x3), Float(bez->y3) + Float(bez.x0), Float(bez.y0), + Float(bez.x1), Float(bez.y1), + Float(bez.x2), Float(bez.y2), + Float(bez.x3), Float(bez.y3) }; builder.Add(coeffs); } @@ -299,7 +300,6 @@ void BezierRenderer::PrepareBezierGPUBuffer(const Objects& objects) m_bezier_ids.SetType(GraphicsBuffer::BufferTypeTexture); m_bezier_ids.SetUsage(GraphicsBuffer::BufferUsageDynamicDraw); - m_bezier_ids.SetName("m_bezier_ids: object data_indices"); m_bezier_ids.Upload(objects.data_indices.size() * sizeof(uint32_t), &objects.data_indices[0]); glGenTextures(1, &m_bezier_id_buffer_texture); @@ -328,7 +328,23 @@ void BezierRenderer::RenderUsingGPU(unsigned first_obj_id, unsigned last_obj_id) glUniform1i(m_shader_program.GetUniformLocation("bezier_buffer_texture"), 0); glUniform1i(m_shader_program.GetUniformLocation("bezier_id_buffer_texture"), 1); m_ibo.Bind(); - glDrawElements(GL_LINES, (last_index-first_index)*2, GL_UNSIGNED_INT, (GLvoid*)(2*first_index*sizeof(uint32_t))); + glDrawElements(GL_LINES, (last_index-first_index)*2, GL_UNSIGNED_INT, (GLvoid*)(first_index*sizeof(uint32_t))); +} + +/** + * Render Group (shading) + */ +void GroupRenderer::RenderUsingCPU(const Objects & objects, const View & view, const CPURenderTarget & target, unsigned first_obj_id, unsigned last_obj_id) +{ + for (unsigned i = 0; i < m_indexes.size(); ++i) + { + if (m_indexes[i] < first_obj_id) continue; + if (m_indexes[i] >= last_obj_id) continue; + + //pair range = objects.groups[m_indexes[i]]; + + + } } /** diff --git a/src/objectrenderer.h b/src/objectrenderer.h index 697cf5b..e3872b0 100644 --- a/src/objectrenderer.h +++ b/src/objectrenderer.h @@ -128,6 +128,16 @@ namespace IPDF GLuint m_bezier_id_buffer_texture; }; + + /** Renderer for filled circles **/ + class GroupRenderer : public ObjectRenderer + { + public: + 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); + }; + } #endif //_OBJECT_RENDERER_H diff --git a/src/real.h b/src/real.h index 8021ada..406cb8e 100644 --- a/src/real.h +++ b/src/real.h @@ -2,6 +2,7 @@ #define _REAL_H #include "common.h" +#include #define REAL_SINGLE 0 @@ -67,6 +68,7 @@ namespace IPDF inline double Double(float f) {return (double)f;} inline double Double(double f) {return (double)f;} inline double Double(long double f) {return (double)(f);} + inline double Sqrt(double f) {return sqrt(f);} inline Real Power(const Real & a, int n) { @@ -80,6 +82,8 @@ namespace IPDF return r; } + + } #endif //_REAL_H diff --git a/src/svg-tests/circlepath.svg b/src/svg-tests/circlepath.svg new file mode 100644 index 0000000..6b483eb --- /dev/null +++ b/src/svg-tests/circlepath.svg @@ -0,0 +1,18 @@ + + + + + + + + diff --git a/src/view.cpp b/src/view.cpp index 8b1857d..e0efce9 100644 --- a/src/view.cpp +++ b/src/view.cpp @@ -28,6 +28,7 @@ View::View(Document & document, Screen & screen, const Rect & bounds, const Colo m_object_renderers[RECT_OUTLINE] = new RectOutlineRenderer(); m_object_renderers[CIRCLE_FILLED] = new CircleFilledRenderer(); m_object_renderers[BEZIER] = new BezierRenderer(); + m_object_renderers[GROUP] = new GroupRenderer(); // To add rendering for a new type of object; // 1. Add enum to ObjectType in ipdf.h -- 2.20.1