#Makefile
ARCH := $(shell uname -m)
# TODO: stb_truetype doesn't compile with some of these warnings.
-CXX = g++ -std=c++11 -g -Wall -Werror -Wshadow -pedantic -rdynamic
+CXX = g++ -std=c++0x -g -Wall -Werror -Wshadow -pedantic -rdynamic
MAIN = main.o
-OBJ = log.o real.o bezier.o document.o objectrenderer.o view.o screen.o graphicsbuffer.o framebuffer.o shaderprogram.o stb_truetype.o gl_core44.o path.o paranoidnumber.o quadtree.o debugscript.o
+OBJ = log.o real.o bezier.o objectrenderer.o view.o screen.o graphicsbuffer.o framebuffer.o shaderprogram.o stb_truetype.o gl_core44.o path.o document.o debugscript.o
QT_INCLUDE := -I/usr/share/qt4/mkspecs/linux-g++-64 -I. -I/usr/include/qt4/QtCore -I/usr/include/qt4/QtGui -I/usr/include/qt4 -I. -Itests -I.
QT_DEF := -DQT_NO_DEBUG -DQT_GUI_LIB -DQT_CORE_LIB
## Only link with things we care about
ifeq ($(QUADTREE),enabled)
- OBJ := $(OBJ)
+ OBJ := $(OBJ) quadtree.o
else
DEF := $(DEF) -DQUADTREE_DISABLED
endif
CFLAGS := $(CFLAGS) -I../contrib/iRRAM/include
endif
-
+ifeq ($(REALTYPE),8)
+ OBJ := $(OBJ) paranoidnumber.o
+endif
ifeq ($(REALTYPE),9)
LIB := $(LIB) -lgmp
namespace IPDF
{
-vector<Real> SolveQuadratic(const Real & a, const Real & b, const Real & c, const Real & min, const Real & max)
+vector<BReal> SolveQuadratic(const BReal & a, const BReal & b, const BReal & c, const BReal & min, const BReal & max)
{
- vector<Real> roots; roots.reserve(2);
+ vector<BReal> roots; roots.reserve(2);
if (a == 0 && b != 0)
{
roots.push_back(-c/b);
return roots;
}
- Real disc(b*b - Real(4)*a*c);
+ BReal disc(b*b - BReal(4)*a*c);
if (disc < 0)
{
return roots;
}
else if (disc == 0)
{
- Real x(-b/Real(2)*a);
+ BReal x(-b/BReal(2)*a);
if (x >= min && x <= max)
roots.push_back(x);
return roots;
}
- 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));
+ BReal x0((-b - Sqrt(b*b - BReal(4)*a*c))/(BReal(2)*a));
+ BReal x1((-b + Sqrt(b*b - BReal(4)*a*c))/(BReal(2)*a));
if (x0 > x1)
{
- Real tmp(x0);
+ BReal tmp(x0);
x0 = x1;
x1 = tmp;
}
* Finds the root (if it exists) in a monotonicly in(de)creasing segment of a Cubic
*/
-static void CubicSolveSegment(vector<Real> & roots, const Real & a, const Real & b, const Real & c, const Real & d, Real & tl, Real & tu, const Real & delta)
+static void CubicSolveSegment(vector<BReal> & roots, const BReal & a, const BReal & b, const BReal & c, const BReal & d, BReal & tl, BReal & tu, const BReal & delta)
{
- Real l = a*tl*tl*tl + b*tl*tl + c*tl + d;
- Real u = a*tu*tu*tu + b*tu*tu + c*tu + d;
+ BReal l = a*tl*tl*tl + b*tl*tl + c*tl + d;
+ BReal 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("%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);
+ BReal t(tu+tl);
t /= 2;
- Real m = a*t*t*t + b*t*t + c*t + d;
+ BReal m = a*t*t*t + b*t*t + c*t + d;
if (m > 0)
{
if (negative)
}
roots.push_back(tl);
}
-vector<Real> SolveCubic(const Real & a, const Real & b, const Real & c, const Real & d, const Real & min, const Real & max, const Real & delta)
+vector<BReal> SolveCubic(const BReal & a, const BReal & b, const BReal & c, const BReal & d, const BReal & min, const BReal & max, const BReal & delta)
{
- vector<Real> roots; roots.reserve(3);
- Real tu(max);
- Real tl(min);
- vector<Real> turns(SolveQuadratic(a*3, b*2, c));
+ vector<BReal> roots; roots.reserve(3);
+ BReal tu(max);
+ BReal tl(min);
+ vector<BReal> turns(SolveQuadratic(a*3, b*2, c));
//Debug("%u turning points", turns.size());
for (unsigned i = 1; i < turns.size(); ++i)
{
/**
* Bernstein Basis Polynomial
*/
-Real Bernstein(int k, int n, const Real & u)
+BReal Bernstein(int k, int n, const BReal & u)
{
- return Real(BinomialCoeff(n, k)) * Power(u, k) * Power(Real(1.0) - u, n-k);
+ return BReal(BinomialCoeff(n, k)) * Power(u, k) * Power(BReal(1.0) - u, n-k);
}
* In one coordinate direction
*/
-pair<Real, Real> BezierTurningPoints(const Real & p0, const Real & p1, const Real & p2, const Real & p3)
+pair<BReal, BReal> BezierTurningPoints(const BReal & p0, const BReal & p1, const BReal & p2, const BReal & p3)
{
// straight line
if (p1 == p2 && p2 == p3)
{
- return pair<Real,Real>(0, 1);
+ return pair<BReal,BReal>(0, 1);
}
- Real a = ((p1-p2)*3 + p3 - p0);
- Real b = (p2 - p1*2 + p0)*2;
- Real c = (p1-p0);
+ BReal a = ((p1-p2)*3 + p3 - p0);
+ BReal b = (p2 - p1*2 + p0)*2;
+ BReal c = (p1-p0);
if (a == 0)
{
if (b == 0)
- return pair<Real, Real>(0,1);
- Real t = -c/b;
+ return pair<BReal, BReal>(0,1);
+ BReal t = -c/b;
if (t > 1) t = 1;
if (t < 0) t = 0;
- return pair<Real, Real>(t, t);
+ return pair<BReal, BReal>(t, t);
}
//Debug("a, b, c are %f, %f, %f", Float(a), Float(b), Float(c));
if (b*b - a*c*4 < 0)
{
//Debug("No real roots");
- return pair<Real, Real>(0,1);
+ return pair<BReal, BReal>(0,1);
}
- vector<Real> tsols = SolveQuadratic(a, b, c);
+ vector<BReal> tsols = SolveQuadratic(a, b, c);
if (tsols.size() == 1)
- return pair<Real,Real>(tsols[0], tsols[0]);
+ return pair<BReal,BReal>(tsols[0], tsols[0]);
else if (tsols.size() == 0)
- return pair<Real, Real>(0,1);
+ return pair<BReal, BReal>(0,1);
- return pair<Real,Real>(tsols[0], tsols[1]);
+ return pair<BReal,BReal>(tsols[0], tsols[1]);
}
-inline bool CompRealByPtr(const Real * a, const Real * b)
+inline bool CompBRealByPtr(const BReal * a, const BReal * b)
{
return (*a) < (*b);
}
/**
* Get top most *point* on Bezier curve
*/
-pair<Real,Real> Bezier::GetTop() const
+pair<BReal,BReal> Bezier::GetTop() const
{
- pair<Real, Real> tsols = BezierTurningPoints(y0,y1,y2,y3);
- Real tx0; Real ty0;
- Real tx1; Real ty1;
+ pair<BReal, BReal> tsols = BezierTurningPoints(y0,y1,y2,y3);
+ BReal tx0; BReal ty0;
+ BReal tx1; BReal ty1;
Evaluate(tx0, ty0, tsols.first);
Evaluate(tx1, ty1, tsols.second);
- vector<const Real*> v(4);
+ vector<const BReal*> v(4);
v[0] = &y0;
v[1] = &y3;
v[2] = &ty0;
v[3] = &ty1;
- sort(v.begin(), v.end(), CompRealByPtr);
- pair<Real,Real> result;
+ sort(v.begin(), v.end(), CompBRealByPtr);
+ pair<BReal,BReal> result;
result.second = *v[0];
if (v[0] == &y0)
{
/**
* Get bottom most *point* on Bezier curve
*/
-pair<Real,Real> Bezier::GetBottom() const
+pair<BReal,BReal> Bezier::GetBottom() const
{
- pair<Real, Real> tsols = BezierTurningPoints(y0,y1,y2,y3);
- Real tx0; Real ty0;
- Real tx1; Real ty1;
+ pair<BReal, BReal> tsols = BezierTurningPoints(y0,y1,y2,y3);
+ BReal tx0; BReal ty0;
+ BReal tx1; BReal ty1;
Evaluate(tx0, ty0, tsols.first);
Evaluate(tx1, ty1, tsols.second);
- vector<const Real*> v(4);
+ vector<const BReal*> v(4);
v[0] = &y0;
v[1] = &y3;
v[2] = &ty0;
v[3] = &ty1;
- sort(v.begin(), v.end(), CompRealByPtr);
- pair<Real,Real> result;
+ sort(v.begin(), v.end(), CompBRealByPtr);
+ pair<BReal,BReal> result;
result.second = *v[3];
if (v[3] == &y0)
{
/**
* Get left most *point* on Bezier curve
*/
-pair<Real,Real> Bezier::GetLeft() const
+pair<BReal,BReal> Bezier::GetLeft() const
{
- pair<Real, Real> tsols = BezierTurningPoints(x0,x1,x2,x3);
- Real tx0; Real ty0;
- Real tx1; Real ty1;
+ pair<BReal, BReal> tsols = BezierTurningPoints(x0,x1,x2,x3);
+ BReal tx0; BReal ty0;
+ BReal tx1; BReal ty1;
Evaluate(tx0, ty0, tsols.first);
Evaluate(tx1, ty1, tsols.second);
- vector<const Real*> v(4);
+ vector<const BReal*> v(4);
v[0] = &x0;
v[1] = &x3;
v[2] = &tx0;
v[3] = &tx1;
- sort(v.begin(), v.end(), CompRealByPtr);
- pair<Real,Real> result;
+ sort(v.begin(), v.end(), CompBRealByPtr);
+ pair<BReal,BReal> result;
result.first = *v[0];
if (v[0] == &x0)
{
/**
* Get left most *point* on Bezier curve
*/
-pair<Real,Real> Bezier::GetRight() const
+pair<BReal,BReal> Bezier::GetRight() const
{
- pair<Real, Real> tsols = BezierTurningPoints(x0,x1,x2,x3);
- Real tx0; Real ty0;
- Real tx1; Real ty1;
+ pair<BReal, BReal> tsols = BezierTurningPoints(x0,x1,x2,x3);
+ BReal tx0; BReal ty0;
+ BReal tx1; BReal ty1;
Evaluate(tx0, ty0, tsols.first);
Evaluate(tx1, ty1, tsols.second);
- vector<const Real*> v(4);
+ vector<const BReal*> v(4);
v[0] = &x0;
v[1] = &x3;
v[2] = &tx0;
v[3] = &tx1;
- sort(v.begin(), v.end(), CompRealByPtr);
- pair<Real,Real> result;
+ sort(v.begin(), v.end(), CompBRealByPtr);
+ pair<BReal,BReal> result;
result.first = *v[3];
if (v[3] == &x0)
{
return result;
}
-vector<Real> Bezier::SolveXParam(const Real & x) const
+vector<BReal> Bezier::SolveXParam(const BReal & x) const
{
- Real d(x0 - x);
- Real c((x1 - x0)*Real(3));
- Real b((x2 - x1)*Real(3) - c);
- Real a(x3 -x0 - c - b);
- vector<Real> results(SolveCubic(a, b, c, d));
+ BReal d(x0 - x);
+ BReal c((x1 - x0)*BReal(3));
+ BReal b((x2 - x1)*BReal(3) - c);
+ BReal a(x3 -x0 - c - b);
+ vector<BReal> results(SolveCubic(a, b, c, d));
for (unsigned i = 0; i < results.size(); ++i)
{
Vec2 p;
}
-vector<Real> Bezier::SolveYParam(const Real & y) const
+vector<BReal> Bezier::SolveYParam(const BReal & y) const
{
- Real d(y0 - y);
- Real c((y1 - y0)*Real(3));
- Real b((y2 - y1)*Real(3) - c);
- Real a(y3 -y0 - c - b);
- vector<Real> results(SolveCubic(a, b, c, d));
+ BReal d(y0 - y);
+ BReal c((y1 - y0)*BReal(3));
+ BReal b((y2 - y1)*BReal(3) - c);
+ BReal a(y3 -y0 - c - b);
+ vector<BReal> results(SolveCubic(a, b, c, d));
for (unsigned i = 0; i < results.size(); ++i)
{
Vec2 p;
return results;
}
-vector<Vec2> Bezier::Evaluate(const vector<Real> & u) const
+vector<Vec2> Bezier::Evaluate(const vector<BReal> & u) const
{
vector<Vec2> result(u.size());
for (unsigned i = 0; i < u.size(); ++i)
/**
* Get Bounds Rectangle of Bezier
*/
-Rect Bezier::SolveBounds() const
+BRect Bezier::SolveBounds() const
{
- Rect result;
- pair<Real, Real> tsols = BezierTurningPoints(x0, x1, x2, x3);
+ BRect result;
+ pair<BReal, BReal> tsols = BezierTurningPoints(x0, x1, x2, x3);
- Real tp0; Real tp1; Real o;
+ BReal tp0; BReal tp1; BReal o;
Evaluate(tp0, o, tsols.first);
Evaluate(tp1, o, tsols.second);
//Debug("x: tp0 is %f tp1 is %f", Float(tp0), Float(tp1));
- vector<const Real*> v(4);
+ vector<const BReal*> 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);
+ sort(v.begin(), v.end(), CompBRealByPtr);
result.x = *(v[0]);
result.w = *(v[3]) - result.x;
v[1] = &y3;
v[2] = &tp0;
v[3] = &tp1;
- sort(v.begin(), v.end(), CompRealByPtr);
+ sort(v.begin(), v.end(), CompBRealByPtr);
result.y = *(v[0]);
result.h = *(v[3]) - result.y;
#include <vector>
#include <algorithm>
-
-#include "real.h"
#include "rect.h"
+#include "real.h"
namespace IPDF
{
+ typedef Real BReal;
+ typedef TRect<BReal> BRect;
+
extern int Factorial(int n);
extern int BinomialCoeff(int n, int k);
- extern Real Bernstein(int k, int n, const Real & u);
- extern std::pair<Real,Real> BezierTurningPoints(const Real & p0, const Real & p1, const Real & p2, const Real & p3);
+ extern BReal Bernstein(int k, int n, const BReal & u);
+ extern std::pair<BReal,BReal> BezierTurningPoints(const BReal & p0, const BReal & p1, const BReal & p2, const BReal & p3);
- extern std::vector<Real> SolveQuadratic(const Real & a, const Real & b, const Real & c, const Real & min = 0, const Real & max = 1);
+ extern std::vector<BReal> SolveQuadratic(const BReal & a, const BReal & b, const BReal & c, const BReal & min = 0, const BReal & max = 1);
- extern std::vector<Real> SolveCubic(const Real & a, const Real & b, const Real & c, const Real & d, const Real & min = 0, const Real & max = 1, const Real & delta = 1e-9);
+ extern std::vector<BReal> SolveCubic(const BReal & a, const BReal & b, const BReal & c, const BReal & d, const BReal & min = 0, const BReal & max = 1, const BReal & delta = 1e-9);
/** A _cubic_ bezier. **/
struct Bezier
{
- Real x0; Real y0;
- Real x1; Real y1;
- Real x2; Real y2;
- Real x3; Real y3;
+ BReal x0; BReal y0;
+ BReal x1; BReal y1;
+ BReal x2; BReal y2;
+ BReal x3; BReal y3;
typedef enum {UNKNOWN, LINE, QUADRATIC, CUSP, LOOP, SERPENTINE} Type;
Type type;
//Bezier() = default; // Needed so we can fread/fwrite this struct... for now.
- Bezier(Real _x0=0, Real _y0=0, Real _x1=0, Real _y1=0, Real _x2=0, Real _y2=0, Real _x3=0, Real _y3=0) : x0(_x0), y0(_y0), x1(_x1), y1(_y1), x2(_x2), y2(_y2), x3(_x3), y3(_y3), type(UNKNOWN)
+ Bezier(BReal _x0=0, BReal _y0=0, BReal _x1=0, BReal _y1=0, BReal _x2=0, BReal _y2=0, BReal _x3=0, BReal _y3=0) : x0(_x0), y0(_y0), x1(_x1), y1(_y1), x2(_x2), y2(_y2), x3(_x3), y3(_y3), type(UNKNOWN)
{
}
return type;
// From Loop-Blinn 2005, with w0 == w1 == w2 == w3 = 1
// Transformed control points: (a0 = x0, b0 = y0)
- Real a1 = (x1-x0)*Real(3);
- Real a2 = (x0- x1*Real(2) +x2)*Real(3);
- Real a3 = (x3 - x0 + (x1 - x2)*Real(3));
+ BReal a1 = (x1-x0)*BReal(3);
+ BReal a2 = (x0- x1*BReal(2) +x2)*BReal(3);
+ BReal a3 = (x3 - x0 + (x1 - x2)*BReal(3));
- Real b1 = (y1-y0)*Real(3);
- Real b2 = (y0- y1*Real(2) +y2)*Real(3);
- Real b3 = (y3 - y0 + (y1 - y2)*Real(3));
+ BReal b1 = (y1-y0)*BReal(3);
+ BReal b2 = (y0- y1*BReal(2) +y2)*BReal(3);
+ BReal b3 = (y3 - y0 + (y1 - y2)*BReal(3));
// d vector (d0 = 0 since all w = 1)
- Real d1 = a2*b3 - a3*b2;
- Real d2 = a3*b1 - a1*b3;
- Real d3 = a1*b2 - a2*b1;
+ BReal d1 = a2*b3 - a3*b2;
+ BReal d2 = a3*b1 - a1*b3;
+ BReal d3 = a1*b2 - a2*b1;
- if (Abs(d1+d2+d3) < Real(1e-6))
+ if (Abs(d1+d2+d3) < BReal(1e-6))
{
type = LINE;
//Debug("LINE %s", Str().c_str());
return type;
}
- Real delta1 = -(d1*d1);
- Real delta2 = d1*d2;
- Real delta3 = d1*d3 -(d2*d2);
- if (Abs(delta1+delta2+delta3) < Real(1e-6))
+ BReal delta1 = -(d1*d1);
+ BReal delta2 = d1*d2;
+ BReal delta3 = d1*d3 -(d2*d2);
+ if (Abs(delta1+delta2+delta3) < BReal(1e-6))
{
type = QUADRATIC;
return type;
}
- Real discriminant = d1*d3*Real(4) -d2*d2;
- if (Abs(discriminant) < Real(1e-6))
+ BReal discriminant = d1*d3*BReal(4) -d2*d2;
+ if (Abs(discriminant) < BReal(1e-6))
{
type = CUSP;
//Debug("CUSP %s", Str().c_str());
}
- else if (discriminant > Real(0))
+ else if (discriminant > BReal(0))
{
type = SERPENTINE;
//Debug("SERPENTINE %s", Str().c_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), type(cpy.type)
+ Bezier(const Bezier & cpy, const BRect & t = BRect(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), type(cpy.type)
{
x0 *= t.w;
y0 *= t.h;
y3 += t.y;
}
- Rect SolveBounds() const;
+ BRect SolveBounds() const;
- std::pair<Real,Real> GetTop() const;
- std::pair<Real,Real> GetBottom() const;
- std::pair<Real,Real> GetLeft() const;
- std::pair<Real,Real> GetRight() const;
+ std::pair<BReal,BReal> GetTop() const;
+ std::pair<BReal,BReal> GetBottom() const;
+ std::pair<BReal,BReal> GetLeft() const;
+ std::pair<BReal,BReal> GetRight() const;
- Bezier ToAbsolute(const Rect & bounds) const
+ Bezier ToAbsolute(const BRect & bounds) const
{
return Bezier(*this, 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 ToRelative(const Rect & bounds) const
+ Bezier ToRelative(const BRect & 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};
+ // BRect inverse = {-bounds.x/bounds.w, -bounds.y/bounds.h, BReal(1)/bounds.w, BReal(1)/bounds.h};
Bezier result;
- if (bounds.w == Real(0))
+ if (bounds.w == 0)
{
result.x0 = 0;
result.x1 = 0;
result.x3 = (x3 - bounds.x)/bounds.w;
}
- if (bounds.h == Real(0))
+ if (bounds.h == 0)
{
result.y0 = 0;
result.y1 = 0;
}
// Performs one round of De Casteljau subdivision and returns the [t,1] part.
- Bezier DeCasteljauSubdivideLeft(const Real& t)
+ Bezier DeCasteljauSubdivideLeft(const BReal& t)
{
- Real one_minus_t = Real(1) - t;
+ BReal one_minus_t = BReal(1) - t;
// X Coordinates
- Real x01 = x1*t + x0*one_minus_t;
- Real x12 = x2*t + x1*one_minus_t;
- Real x23 = x3*t + x2*one_minus_t;
+ BReal x01 = x1*t + x0*one_minus_t;
+ BReal x12 = x2*t + x1*one_minus_t;
+ BReal x23 = x3*t + x2*one_minus_t;
- Real x012 = x12*t + x01*one_minus_t;
- Real x123 = x23*t + x12*one_minus_t;
+ BReal x012 = x12*t + x01*one_minus_t;
+ BReal x123 = x23*t + x12*one_minus_t;
- Real x0123 = x123*t + x012*one_minus_t;
+ BReal x0123 = x123*t + x012*one_minus_t;
// Y Coordinates
- Real y01 = y1*t + y0*one_minus_t;
- Real y12 = y2*t + y1*one_minus_t;
- Real y23 = y3*t + y2*one_minus_t;
+ BReal y01 = y1*t + y0*one_minus_t;
+ BReal y12 = y2*t + y1*one_minus_t;
+ BReal y23 = y3*t + y2*one_minus_t;
- Real y012 = y12*t + y01*one_minus_t;
- Real y123 = y23*t + y12*one_minus_t;
+ BReal y012 = y12*t + y01*one_minus_t;
+ BReal y123 = y23*t + y12*one_minus_t;
- Real y0123 = y123*t + y012*one_minus_t;
+ BReal y0123 = y123*t + y012*one_minus_t;
return Bezier(x0, y0, x01, y01, x012, y012, x0123, y0123);
}
// Performs one round of De Casteljau subdivision and returns the [t,1] part.
- Bezier DeCasteljauSubdivideRight(const Real& t)
+ Bezier DeCasteljauSubdivideRight(const BReal& t)
{
- Real one_minus_t = Real(1) - t;
+ BReal one_minus_t = BReal(1) - t;
// X Coordinates
- Real x01 = x1*t + x0*one_minus_t;
- Real x12 = x2*t + x1*one_minus_t;
- Real x23 = x3*t + x2*one_minus_t;
+ BReal x01 = x1*t + x0*one_minus_t;
+ BReal x12 = x2*t + x1*one_minus_t;
+ BReal x23 = x3*t + x2*one_minus_t;
- Real x012 = x12*t + x01*one_minus_t;
- Real x123 = x23*t + x12*one_minus_t;
+ BReal x012 = x12*t + x01*one_minus_t;
+ BReal x123 = x23*t + x12*one_minus_t;
- Real x0123 = x123*t + x012*one_minus_t;
+ BReal x0123 = x123*t + x012*one_minus_t;
// Y Coordinates
- Real y01 = y1*t + y0*one_minus_t;
- Real y12 = y2*t + y1*one_minus_t;
- Real y23 = y3*t + y2*one_minus_t;
+ BReal y01 = y1*t + y0*one_minus_t;
+ BReal y12 = y2*t + y1*one_minus_t;
+ BReal y23 = y3*t + y2*one_minus_t;
- Real y012 = y12*t + y01*one_minus_t;
- Real y123 = y23*t + y12*one_minus_t;
+ BReal y012 = y12*t + y01*one_minus_t;
+ BReal y123 = y23*t + y12*one_minus_t;
- Real y0123 = y123*t + y012*one_minus_t;
+ BReal y0123 = y123*t + y012*one_minus_t;
return Bezier(x0123, y0123, x123, y123, x23, y23, x3, y3);
}
- Bezier ReParametrise(const Real& t0, const Real& t1)
+ Bezier ReParametrise(const BReal& t0, const BReal& t1)
{
//Debug("Reparametrise: %f -> %f",Double(t0),Double(t1));
Bezier new_bezier;
// Subdivide to get from [0,t1]
new_bezier = DeCasteljauSubdivideLeft(t1);
// Convert t0 from [0,1] range to [0, t1]
- Real new_t0 = t0 / t1;
+ BReal new_t0 = t0 / t1;
//Debug("New t0 = %f", Double(new_t0));
new_bezier = new_bezier.DeCasteljauSubdivideRight(new_t0);
return new_bezier;
}
- std::vector<Bezier> ClipToRectangle(const Rect& r)
+ std::vector<Bezier> ClipToRectangle(const BRect & r)
{
// Find points of intersection with the rectangle.
- Debug("Clipping Bezier to Rect %s", r.Str().c_str());
+ Debug("Clipping Bezier to BRect %s", r.Str().c_str());
// Find its roots.
- std::vector<Real> x_intersection = SolveXParam(r.x);
+ std::vector<BReal> x_intersection = SolveXParam(r.x);
//Debug("Found %d intersections on left edge", x_intersection.size());
// And for the other side.
- std::vector<Real> x_intersection_pt2 = SolveXParam(r.x + r.w);
+ std::vector<BReal> x_intersection_pt2 = SolveXParam(r.x + r.w);
x_intersection.insert(x_intersection.end(), x_intersection_pt2.begin(), x_intersection_pt2.end());
//Debug("Found %d intersections on right edge (total x: %d)", x_intersection_pt2.size(), x_intersection.size());
// Find its roots.
- std::vector<Real> y_intersection = SolveYParam(r.y);
+ std::vector<BReal> y_intersection = SolveYParam(r.y);
//Debug("Found %d intersections on top edge", y_intersection.size());
- std::vector<Real> y_intersection_pt2 = SolveYParam(r.y+r.h);
+ std::vector<BReal> y_intersection_pt2 = SolveYParam(r.y+r.h);
y_intersection.insert(y_intersection.end(), y_intersection_pt2.begin(), y_intersection_pt2.end());
//Debug("Found %d intersections on bottom edge (total y: %d)", y_intersection_pt2.size(), y_intersection.size());
// Merge and sort.
x_intersection.insert(x_intersection.end(), y_intersection.begin(), y_intersection.end());
- x_intersection.push_back(Real(0));
- x_intersection.push_back(Real(1));
+ x_intersection.push_back(BReal(0));
+ x_intersection.push_back(BReal(1));
std::sort(x_intersection.begin(), x_intersection.end());
//Debug("Found %d intersections.\n", x_intersection.size());
/*for(auto t : x_intersection)
{
- Real ptx, pty;
+ BReal ptx, pty;
Evaluate(ptx, pty, t);
Debug("Root: t = %f, (%f,%f)", Double(t), Double(ptx), Double(pty));
}*/
all_beziers.push_back(*this);
return all_beziers;
}
- Real t0 = *(x_intersection.begin());
+ BReal t0 = *(x_intersection.begin());
for (auto it = x_intersection.begin()+1; it != x_intersection.end(); ++it)
{
- Real t1 = *it;
+ BReal t1 = *it;
if (t1 == t0) continue;
- //Debug(" -- t0: %f to t1: %f: %f", Double(t0), Double(t1), Double((t1 + t0)/Real(2)));
- Real ptx, pty;
- Evaluate(ptx, pty, ((t1 + t0) / Real(2)));
+ //Debug(" -- t0: %f to t1: %f: %f", Double(t0), Double(t1), Double((t1 + t0)/BReal(2)));
+ BReal ptx, pty;
+ Evaluate(ptx, pty, ((t1 + t0) / BReal(2)));
if (r.PointIn(ptx, pty))
{
//Debug("Adding segment: (point at %f, %f)", Double(ptx), Double(pty));
}
/** Evaluate the Bezier at parametric parameter u, puts resultant point in (x,y) **/
- void Evaluate(Real & x, Real & y, const Real & u) const
+ void Evaluate(BReal & x, BReal & y, const BReal & u) const
{
- Real coeff[4];
+ BReal coeff[4];
for (unsigned i = 0; i < 4; ++i)
coeff[i] = Bernstein(i,3,u);
x = x0*coeff[0] + x1*coeff[1] + x2*coeff[2] + x3*coeff[3];
y = y0*coeff[0] + y1*coeff[1] + y2*coeff[2] + y3*coeff[3];
}
- std::vector<Vec2> Evaluate(const std::vector<Real> & u) const;
+ std::vector<Vec2> Evaluate(const std::vector<BReal> & u) const;
- std::vector<Real> SolveXParam(const Real & x) const;
- std::vector<Real> SolveYParam(const Real & x) const;
+ std::vector<BReal> SolveXParam(const BReal & x) const;
+ std::vector<BReal> SolveYParam(const BReal & x) const;
// Get points with same X
- inline std::vector<Vec2> SolveX(const Real & x) const
+ inline std::vector<Vec2> SolveX(const BReal & x) const
{
return Evaluate(SolveXParam(x));
}
// Get points with same Y
- inline std::vector<Vec2> SolveY(const Real & y) const
+ inline std::vector<Vec2> SolveY(const BReal & y) const
{
return Evaluate(SolveYParam(y));
}
}
-#undef Real
-
#endif //_BEZIER_H
currentAction.type = AT_Debug;
getline(inp,currentAction.textargs);
}
+ else if (actionType == "clear")
+ {
+ currentAction.type = AT_ClearDocument;
+ }
+ else if (actionType == "clearperf")
+ {
+ currentAction.type = AT_ClearPerformance;
+ }
+ else if (actionType == "printperf")
+ {
+ currentAction.type = AT_PrintPerformance;
+ }
+ else if (actionType == "recordperf")
+ {
+ currentAction.type = AT_RecordPerformance;
+ }
}
bool DebugScript::Execute(View *view, Screen *scr)
if (currentAction.textargs.size() > 0)
Debug("%s", currentAction.textargs.c_str());
break;
+ case AT_ClearDocument:
+ view->Doc().ClearObjects();
+ currentAction.loops = 1;
+ break;
+ case AT_ClearPerformance:
+ ClearPerformance(view, scr);
+ currentAction.loops = 1;
+ break;
+ case AT_PrintPerformance:
+ PrintPerformance(view, scr);
+ currentAction.loops = 1;
+ break;
+ case AT_RecordPerformance:
+ PrintPerformance(view, scr);
+ break;
default:
Fatal("Unknown script command in queue.");
}
currentAction.loops--;
return false;
}
+
+void DebugScript::ClearPerformance(View * view, Screen * scr)
+{
+ m_perf_start.clock = clock();
+ m_perf_start.object_count = view->Doc().ObjectCount();
+ m_perf_start.view_bounds = view->GetBounds();
+ m_perf_last = m_perf_start;
+}
+
+void DebugScript::PrintPerformance(View * view, Screen * scr)
+{
+ DebugScript::PerformanceData now;
+ now.clock = clock();
+ now.object_count = view->Doc().ObjectCount();
+ now.view_bounds = view->GetBounds();
+ // object_count delta clock delta x deltax y deltay w deltaw h deltah
+ printf("%d\t%d\t%lu\t%lu\t%e\t%e\t%e\t%e\t%e\t%e\t%e\t%e\n",
+ now.object_count, now.object_count - m_perf_last.object_count,
+ (uint64_t)now.clock, (uint64_t)(now.clock - m_perf_last.clock),
+ Double(now.view_bounds.x), Double(now.view_bounds.x - m_perf_last.view_bounds.x),
+ Double(now.view_bounds.y), Double(now.view_bounds.y - m_perf_last.view_bounds.y),
+ Double(now.view_bounds.w), Double(now.view_bounds.w - m_perf_last.view_bounds.w),
+ Double(now.view_bounds.h), Double(now.view_bounds.h - m_perf_last.view_bounds.h));
+ m_perf_last = now;
+}
AT_Label,
AT_Goto,
AT_Debug,
+ AT_ClearDocument,
+ AT_ClearPerformance,
+ AT_PrintPerformance,
+ AT_RecordPerformance,
AT_Quit
};
std::vector<Action> m_actions;
std::map<std::string, int> m_labels;
unsigned m_index;
+
+ struct PerformanceData
+ {
+ clock_t clock;
+ unsigned object_count;
+ Rect view_bounds;
+ };
+
+ PerformanceData m_perf_start;
+ PerformanceData m_perf_last;
+
+ void PrintPerformance(View * view, Screen * scr);
+ void ClearPerformance(View * view, Screen * scr);
+
void ParseAction();
};
#include <fstream>
#include "../contrib/pugixml-1.4/src/pugixml.cpp"
+#include "transformationtype.h"
#include "stb_truetype.h"
for (unsigned i = 0; i < m_objects.paths.size(); ++i)
{
Path & p = m_objects.paths[i];
- p.x += dx;
- p.y += dy;
+ p.m_bounds.x += dx;
+ p.m_bounds.y += dy;
}
return;
#endif
for (unsigned i = 0; i < m_objects.paths.size(); ++i)
{
Path & p = m_objects.paths[i];
- p.w /= scale_amount;
- p.h /= scale_amount;
- p.x -= x;
- p.x /= scale_amount;
- p.x += x;
- p.y -= y;
- p.y /= scale_amount;
- p.y += y;
+ p.m_bounds.w /= scale_amount;
+ p.m_bounds.h /= scale_amount;
+ p.m_bounds.x -= x;
+ p.m_bounds.x /= scale_amount;
+ p.m_bounds.x += x;
+ p.m_bounds.y -= y;
+ p.m_bounds.y /= scale_amount;
+ p.m_bounds.y += y;
}
return;
#endif
int ClipObjectToQuadChild(int object_id, QuadTreeNodeChildren type);
#endif
+ void ClearObjects()
+ {
+ m_count = 0;
+ m_objects.Clear();
+ }
+
+
private:
friend class View;
Objects m_objects;
# Test how well document scales back to original...
gpu
lazy
+clearperf
label start
+printperf
debug Add rabbit 1
loadsvg svg-tests/rabbit_simple.svg
loop 250 pxzoom 508 305 1
debug Add rabbit 3
loadsvg svg-tests/rabbit_simple.svg
loop 500 pxzoom 508 305 -1
-loop 250 pxzoom 508 305 1
-loop 1000 wait
-loop 250 pxzoom 508 305 1
+loop 500 pxzoom 508 305 1
debug Repeat
-#goto start
+clear
+goto start
wait
//operator int64_t() const {return mpq_get_si(m_op);}
//operator uint64_t() const {return mpq_get_ui(m_op);}
//operator double() const {return mpq_get_d(m_op);}
+ //operator float() const {return (float)ToDouble();}
double ToDouble() const {return mpq_get_d(m_op);}
std::string Str(int base = 10) const
{
private:
+ friend std::ostream& operator<<(std::ostream& os, const Gmprat & fith);
mpq_t m_op;
};
+std::ostream & operator<<(std::ostream & os, const Gmprat & fith)
+{
+ os << fith.Str();
+ return os;
+}
+
std::vector<Bezier> beziers; // bezier curves - look up by data_indices
/** Used by PATH only **/
std::vector<Path> paths;
+
+ void Clear()
+ {
+ types.clear();
+ bounds.clear();
+ data_indices.clear();
+ beziers.clear();
+ paths.clear();
+ }
};
class View;
}
-inline void MainLoop(Document & doc, Screen & scr, View & view, int max_frames = -1)
+void MainLoop(Document & doc, Screen & scr, View & view, int max_frames = -1)
{
// order is important... segfaults occur when screen (which inits GL) is not constructed first -_-
DebugScript script;
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();
+ m_bounds = SolveBounds(objects).Convert<PReal>();
#ifdef TRANSFORM_BEZIERS_TO_PATH
- x = m_left.x;
- y = m_top.y;
- w = m_right.x - m_left.x;
- h = m_bottom.y - m_top.y;
-
- 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]);
+ objects.bounds[i] = TransformRectCoordinates(m_bounds.Convert<Real>(), objects.bounds[i]);
//Debug("-> %s", objects.bounds[i].Str().c_str());
}
#endif
Rect Path::SolveBounds(const Objects & objects)
{
- #ifdef TRANSFORM_BEZIERS_TO_PATH
- return Rect(Real(x.ToDouble()), Real(y.ToDouble()), Real(w.ToDouble()), Real(h.ToDouble()));
- #else
- return Rect(m_left.x, m_top.y, m_right.x-m_left.x, m_bottom.y-m_top.y);
- #endif
+ 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)
{
- #ifdef TRANSFORM_BEZIERS_TO_PATH
- objects.bounds[m_index] = Rect(Real(x.ToDouble()), Real(y.ToDouble()), Real(w.ToDouble()), Real(h.ToDouble()));
- #endif
+ objects.bounds[m_index] = m_bounds.Convert<Real>();
return objects.bounds[m_index];
}
#ifndef _PATH_H
#define _PATH_H
+#include "transformationtype.h"
#include <vector>
#include <algorithm>
#include "rect.h"
#include "real.h"
-#ifdef QUADTREE_DISABLED
-
-#define TRANSFORM_BEZIERS_TO_PATH
#ifdef TRANSFORM_BEZIERS_TO_PATH
-#include "gmprat.h"
-#endif
+ #include "gmprat.h"
#endif
+
namespace IPDF
{
+ #ifdef TRANSFORM_BEZIERS_TO_PATH
+ typedef Gmprat PReal;
+ #else
+ typedef Real PReal;
+ #endif
+ typedef TRect<PReal> PRect;
struct Colour
{
std::vector<Vec2> m_fill_points;
- #ifdef TRANSFORM_BEZIERS_TO_PATH
- Gmprat x;
- Gmprat y;
- Gmprat w;
- Gmprat h;
- #endif
+ PRect m_bounds;
+
Colour m_fill; // colour to fill with
Colour m_stroke; // colour to outline with
#error "REALTYPE was not defined!"
#endif
+#define XSTR(x) STR(x)
+#define STR(x) #x
+#pragma message "REALTYPE = " XSTR(REALTYPE)
+
#if REALTYPE == REAL_VFPU
#include "vfpu.h"
#endif
#if REALTYPE == REAL_SINGLE
typedef float Real;
inline Real RealFromStr(const char * str) {return strtof(str, NULL);}
+ inline std::string Str(const Real & a) {std::stringstream s; s << a; return s.str();}
#elif REALTYPE == REAL_DOUBLE
typedef double Real;
inline Real RealFromStr(const char * str) {return strtod(str, NULL);}
+ inline std::string Str(const Real & a) {std::stringstream s; s << a; return s.str();}
#elif REALTYPE == REAL_LONG_DOUBLE
typedef long double Real;
inline Real RealFromStr(const char * str) {return strtold(str, NULL);}
+ inline std::string Str(const Real & a) {std::stringstream s; s << a; return s.str();}
#elif REALTYPE == REAL_VFPU
typedef VFPU::VFloat Real;
inline float Float(const Real & r) {return r.m_value;}
inline Real Sqrt(const Real & r) {return Real(sqrt(r.ToDouble()));}
inline Real RealFromStr(const char * str) {return Real(strtod(str, NULL));}
inline Real Abs(const Real & a) {return (a > Real(0)) ? a : Real(0)-a;}
+ inline std::string Str(const Real & a) {return a.Str();}
#else
#error "Type of Real unspecified."
inline double Double(long double f) {return (double)(f);}
inline double Sqrt(double f) {return sqrt(f);}
inline double Abs(double a) {return fabs(a);}
+
+
inline int64_t Int64(double a)
{
if (a < INT64_MIN)
#endif
#endif
}
-
}
#endif //_REAL_H
namespace IPDF
{
- struct Rect
+ template <class T = IPDF::Real>
+ struct TRect
{
- Real x; Real y; Real w; Real h;
- //Rect() = default; // Needed so we can fread/fwrite this struct
- Rect(Real _x=0, Real _y=0, Real _w=1, Real _h=1) : x(_x), y(_y), w(_w), h(_h) {}
+ T x; T y; T w; T h;
+ //TRect() = default; // Needed so we can fread/fwrite this struct
+ TRect(T _x=0, T _y=0, T _w=1, T _h=1) : x(_x), y(_y), w(_w), h(_h) {}
+
std::string Str() const
{
std::stringstream s;
// float conversion needed because it is fucking impossible to get ostreams working with template classes
- s << "{" << Float(x) << ", " << Float(y) << ", " << Float(x + w) << ", " << Float(y + h) << " (w: " << Float(w) <<", h: " << Float(h) <<")}";
+ s << "{" << x << ", " << y << ", " << (x + w) << ", " << (y + h) << " (w: " << w <<", h: " << h <<")}";
return s.str();
}
- inline bool PointIn(Real pt_x, Real pt_y) const
+ inline bool PointIn(T pt_x, T pt_y) const
{
if (pt_x <= x) return false;
if (pt_y <= y) return false;
return true;
}
- inline bool Intersects(const Rect& other) const
+ inline bool Intersects(const TRect& other) const
{
if (x + w < other.x) return false;
if (y + h < other.y) return false;
if (y > other.y + other.h) return false;
return true;
}
+
+ template <class B> TRect<B> Convert() {return TRect<B>(B(x), B(y), B(w), B(h));}
};
- inline Rect TransformRectCoordinates(const Rect& view, const Rect& r)
+
+
+ template <class T = IPDF::Real>
+ inline TRect<T> TransformRectCoordinates(const TRect<T> & view, const TRect<T> & r)
{
- Rect out;
- Real w = (view.w == Real(0))?Real(1):view.w;
- Real h = (view.h == Real(0))?Real(1):view.h;
+ TRect<T> out;
+ T w = (view.w == T(0))?T(1):view.w;
+ T h = (view.h == T(0))?T(1):view.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
return out;
}
- inline Vec2 TransformPointCoordinates(const Rect& view, const Vec2& v)
+
+ template <class T = IPDF::Real>
+ inline Vec2 TransformPointCoordinates(const TRect<T> & view, const Vec2& v)
{
Vec2 out;
out.x = (v.x - view.x) / view.w;
out.y = (v.y - view.y) / view.h;
return out;
}
-
+
+ typedef TRect<Real> Rect;
+
}
--- /dev/null
+#ifndef _TRANSFORMATIONTYPE_H
+#define _TRANSFORMATIONTYPE_H
+
+#ifdef QUADTREE_DISABLED
+#define TRANSFORM_OBJECTS_NOT_VIEW
+#define TRANSFORM_BEZIERS_TO_PATH
+#endif
+
+#endif
* @param bounds - Initial bounds of the View
* @param colour - Colour to use for rendering this view. TODO: Make sure this actually works, or just remove it
*/
-View::View(Document & document, Screen & screen, const Rect & bounds, const Colour & colour)
+View::View(Document & document, Screen & screen, const VRect & bounds, const Colour & colour)
: m_use_gpu_transform(USE_GPU_TRANSFORM), m_use_gpu_rendering(USE_GPU_RENDERING), m_bounds_dirty(true), m_buffer_dirty(true),
m_render_dirty(true), m_document(document), m_screen(screen), m_cached_display(), m_bounds(bounds), m_colour(colour), m_bounds_ubo(),
m_objbounds_vbo(), m_object_renderers(NUMBER_OF_OBJECT_TYPES), m_cpu_rendering_pixels(NULL),
* Translate the view
* @param x, y - Amount to translate
*/
-void View::Translate(Real x, Real y)
+void View::Translate(VReal x, VReal y)
{
if (!m_use_gpu_transform)
m_buffer_dirty = true;
#ifdef TRANSFORM_BEZIERS_TO_PATH
type = PATH;
#endif
- m_document.TranslateObjects(-x, -y, type);
+ m_document.TranslateObjects(-x.ToDouble(), -y.ToDouble(), type);
#endif
x *= m_bounds.w;
y *= m_bounds.h;
* @param x, y - Coordinates to scale at (eg: Mouse cursor position)
* @param scale_amount - Amount to scale by
*/
-void View::ScaleAroundPoint(Real x, Real y, Real scale_amount)
+void View::ScaleAroundPoint(VReal x, VReal y, VReal scale_amount)
{
// (x0, y0, w, h) -> (x*w - (x*w - x0)*s, y*h - (y*h - y0)*s, w*s, h*s)
x += m_bounds.x;
y += m_bounds.y;
- Real top = y - m_bounds.y;
- Real left = x - m_bounds.x;
+ VReal top = y - m_bounds.y;
+ VReal left = x - m_bounds.x;
top *= scale_amount;
left *= scale_amount;
#include "document.h"
#include "framebuffer.h"
#include "objectrenderer.h"
+#include "path.h"
+#include "transformationtype.h"
#define USE_GPU_TRANSFORM true
#define USE_GPU_RENDERING true
#define USE_SHADING !(USE_GPU_RENDERING) && true
-#ifdef QUADTREE_DISABLED
-
-#define TRANSFORM_OBJECTS_NOT_VIEW
-
+#ifdef TRANSFORM_BEZIERS_TO_PATH
+#include "gmprat.h"
#endif
namespace IPDF
{
+ #ifdef TRANSFORM_BEZIERS_TO_PATH
+ typedef Gmprat VReal;
+ #else
+ typedef Real VReal;
+ #endif
+ typedef TRect<VReal> VRect;
+
class Screen;
/**
* The View class manages a rectangular view into the document.
class View
{
public:
- View(Document & document, Screen & screen, const Rect & bounds = Rect(0,0,1,1), const Colour & colour = Colour(0.f,0.f,0.f,1.f));
+ View(Document & document, Screen & screen, const VRect & bounds = VRect(0,0,1,1), const Colour & colour = Colour(0.f,0.f,0.f,1.f));
virtual ~View();
void Render(int width = 0, int height = 0);
- void Translate(Real x, Real y);
- void ScaleAroundPoint(Real x, Real y, Real scale_amount);
+ void Translate(VReal x, VReal y);
+ void ScaleAroundPoint(VReal x, VReal y, VReal scale_amount);
void SetBounds(const Rect & new_bounds);
Rect TransformToViewCoords(const Rect& inp) const;
- const Rect& GetBounds() const { return m_bounds; }
+ const VRect& GetBounds() const { return m_bounds; }
const bool UsingGPUTransform() const { return m_use_gpu_transform; } // whether view transform calculated on CPU or GPU
Document & m_document;
Screen & m_screen;
FrameBuffer m_cached_display;
- Rect m_bounds;
+ VRect m_bounds;
Colour m_colour;
// Stores the view bounds.