{
public:
virtual ~PaintNode() {}
+ virtual int dispose(RasterMethod* engine) = 0;
virtual int update(RasterMethod* engine) = 0;
};
public:
~ShapeNode();
+ int dispose(RasterMethod* engine) noexcept override;
int update(RasterMethod* engine) noexcept override;
int clear() noexcept;
public:
~SceneNode();
+ int dispose(RasterMethod* engine) noexcept override;
int update(RasterMethod* engine) noexcept override;
int push(std::unique_ptr<ShapeNode> shape) noexcept;
#include "tvgCommon.h"
#include "tvgGlEngine.h"
+/************************************************************************/
+/* Internal Class Implementation */
+/************************************************************************/
-static GlEngine* pInst = nullptr;
+static RasterMethodInit engineInit;
struct GlShape
{
//TODO:
};
+/************************************************************************/
+/* External Class Implementation */
+/************************************************************************/
+
+void* GlEngine::dispose(const ShapeNode& shape, void *data)
+{
+ GlShape* sdata = static_cast<GlShape*>(data);
+ if (!sdata) return nullptr;
+ free(sdata);
+ return nullptr;
+}
+
void* GlEngine::prepare(const ShapeNode& shape, void* data, UpdateFlag flags)
{
sdata = static_cast<GlShape*>(calloc(1, sizeof(GlShape)));
assert(sdata);
}
-
return sdata;
}
int GlEngine::init()
{
- if (pInst) return -1;
- pInst = new GlEngine();
- assert(pInst);
-
- return 0;
+ return RasterMethodInit::init(engineInit, new GlEngine);
}
int GlEngine::term()
{
- if (!pInst) return -1;
- cout << "GlEngine(" << pInst << ") destroyed!" << endl;
- delete(pInst);
- pInst = nullptr;
- return 0;
+ return RasterMethodInit::term(engineInit);
+}
+
+
+size_t GlEngine::unref()
+{
+ return RasterMethodInit::unref(engineInit);
+}
+
+
+size_t GlEngine::ref()
+{
+ return RasterMethodInit::ref(engineInit);
}
GlEngine* GlEngine::inst()
{
- assert(pInst);
- return pInst;
+ return dynamic_cast<GlEngine*>(RasterMethodInit::inst(engineInit));
}
{
public:
void* prepare(const ShapeNode& shape, void* data, UpdateFlag flags) override;
+ void* dispose(const ShapeNode& shape, void *data) override;
+ size_t ref() override;
+ size_t unref() override;
+
static GlEngine* inst();
static int init();
static int term();
constexpr auto SW_CURVE_TAG_ON = 1;
constexpr auto SW_CURVE_TAG_CUBIC = 2;
+constexpr auto SW_OUTLINE_FILL_WINDING = 0;
+constexpr auto SW_OUTLINE_FILL_EVEN_ODD = 1;
using SwCoord = signed long;
size_t ptsCnt; //number of points in the glyph
size_t reservedPtsCnt;
char* tags; //the points flags
- size_t flags; //outline masks
+ uint8_t fillMode; //outline fill mode
};
struct SwSpan
{
- size_t x;
- size_t y;
- size_t len;
+ uint16_t x, y;
+ uint16_t len;
uint8_t coverage;
};
struct SwRleData
{
+ SwSpan *spans;
size_t alloc;
size_t size;
- SwSpan *spans;
};
struct SwBBox
{
- SwPoint min;
- SwPoint max;
+ SwPoint min, max;
};
struct SwShape
{
SwOutline* outline;
- SwRleData rle;
+ SwRleData* rle;
SwBBox bbox;
};
+void shapeReset(SwShape& sdata);
bool shapeGenOutline(const ShapeNode& shape, SwShape& sdata);
void shapeDelOutline(const ShapeNode& shape, SwShape& sdata);
bool shapeGenRle(const ShapeNode& shape, SwShape& sdata);
-void shapeDelRle(const ShapeNode& shape, SwShape& sdata);
bool shapeTransformOutline(const ShapeNode& shape, SwShape& sdata);
-bool rleRender(SwShape& sdata);
+SwRleData* rleRender(const SwShape& sdata);
#endif /* _TVG_SW_COMMON_H_ */
/* Internal Class Implementation */
/************************************************************************/
-static SwEngine* pInst = nullptr;
+static RasterMethodInit engineInit;
/************************************************************************/
/* External Class Implementation */
/************************************************************************/
+void* SwEngine::dispose(const ShapeNode& shape, void *data)
+{
+ SwShape* sdata = static_cast<SwShape*>(data);
+ if (!sdata) return nullptr;
+ shapeReset(*sdata);
+ free(sdata);
+ return nullptr;
+}
+
void* SwEngine::prepare(const ShapeNode& shape, void* data, UpdateFlag flags)
{
//prepare shape data
if (alpha == 0) return sdata;
if (flags & UpdateFlag::Path) {
+ shapeReset(*sdata);
if (!shapeGenOutline(shape, *sdata)) return sdata;
//TODO: From below sequence starts threading?
if (!shapeTransformOutline(shape, *sdata)) return sdata;
if (!shapeGenRle(shape, *sdata)) return sdata;
- shapeDelOutline(shape, *sdata);
}
return sdata;
int SwEngine::init()
{
- if (pInst) return -1;
- pInst = new SwEngine();
- assert(pInst);
-
- return 0;
+ return RasterMethodInit::init(engineInit, new SwEngine);
}
int SwEngine::term()
{
- if (!pInst) return -1;
- cout << "SwEngine(" << pInst << ") destroyed!" << endl;
- delete(pInst);
- pInst = nullptr;
- return 0;
+ return RasterMethodInit::term(engineInit);
+}
+
+
+size_t SwEngine::unref()
+{
+ return RasterMethodInit::unref(engineInit);
+}
+
+
+size_t SwEngine::ref()
+{
+ return RasterMethodInit::ref(engineInit);
}
SwEngine* SwEngine::inst()
{
- assert(pInst);
- return pInst;
+ return dynamic_cast<SwEngine*>(RasterMethodInit::inst(engineInit));
}
{
public:
void* prepare(const ShapeNode& shape, void* data, UpdateFlag flags) override;
+ void* dispose(const ShapeNode& shape, void *data) override;
+ size_t ref() override;
+ size_t unref() override;
+
static SwEngine* inst();
static int init();
static int term();
#include <setjmp.h>
#include <limits.h>
+#include <memory.h>
#include "tvgSwCommon.h"
/************************************************************************/
constexpr auto PIXEL_BITS = 8; //must be at least 6 bits!
constexpr auto ONE_PIXEL = (1L << PIXEL_BITS);
-
using Area = long;
struct Band
struct RleWorker
{
+ SwRleData* rle;
+
SwPoint cellPos;
SwPoint cellMin;
SwPoint cellMax;
static inline SwPoint TRUNC(const SwPoint& pt)
{
- return { pt.x >> PIXEL_BITS, pt.y >> PIXEL_BITS };
+ return {pt.x >> PIXEL_BITS, pt.y >> PIXEL_BITS};
+}
+
+
+static inline SwCoord TRUNC(const SwCoord x)
+{
+ return x >> PIXEL_BITS;
}
static inline SwPoint SUBPIXELS(const SwPoint& pt)
{
- return {pt.x << PIXEL_BITS, pt.y << PIXEL_BITS };
+ return {pt.x << PIXEL_BITS, pt.y << PIXEL_BITS};
}
return (x << PIXEL_BITS);
}
+/*
+ * Approximate sqrt(x*x+y*y) using the `alpha max plus beta min'
+ * algorithm. We use alpha = 1, beta = 3/8, giving us results with a
+ * largest error less than 7% compared to the exact value.
+ */
+static inline SwCoord HYPOT(SwPoint pt)
+{
+ if (pt.x < 0) pt.x = -pt.x;
+ if (pt.y < 0) pt.y = -pt.y;
+ return ((pt.x > pt.y) ? (pt.x + (3 * pt.y >> 3)) : (pt.y + (3 * pt.x >> 3)));
+}
-static void horizLine(RleWorker& rw, SwCoord x, SwCoord y, SwCoord area, SwCoord acount)
+static void _genSpan(SwRleData* rle, SwSpan* spans, size_t count)
{
- //TODO:
+ assert(rle && spans);
+
+ auto newSize = rle->size + count;
+
+ /* allocate enough memory for new spans */
+ /* alloc is required to prevent free and reallocation */
+ /* when the rle needs to be regenerated because of attribute change. */
+ if (rle->alloc < newSize) {
+ rle->spans = static_cast<SwSpan*>(realloc(rle->spans, newSize * sizeof(SwSpan)));
+ assert(rle->spans);
+ rle->alloc = newSize;
+ }
+
+ //copy the new spans to the allocated memory
+ SwSpan* lastSpan = rle->spans + rle->size;
+ assert(lastSpan);
+ memcpy(lastSpan, spans, count * sizeof(SwSpan));
+
+ rle->size = newSize;
}
-static void genSpan(RleWorker& rw)
+static void _horizLine(RleWorker& rw, SwCoord x, SwCoord y, SwCoord area, SwCoord acount)
{
- //TODO:
+ /* compute the coverage line's coverage, depending on the outline fill rule */
+ /* the coverage percentage is area/(PIXEL_BITS*PIXEL_BITS*2) */
+ auto coverage = static_cast<int>(area >> (PIXEL_BITS * 2 + 1 - 8)); //range 0 - 256
+
+ if (coverage < 0) coverage = -coverage;
+
+ if (rw.outline->fillMode == SW_OUTLINE_FILL_EVEN_ODD) {
+ coverage &= 511;
+ if (coverage > 256) coverage = 512 - coverage;
+ else if (coverage == 256) coverage = 255;
+ } else {
+ //normal non-zero winding rule
+ if (coverage >= 256) coverage = 255;
+ }
+
+ x += rw.cellMin.x;
+ y += rw.cellMin.y;
+
+ //span has ushort coordinates. check limit overflow
+ if (x >= SHRT_MAX) {
+ cout << "x(" << x << ") coordinate overflow!" << endl;
+ x = SHRT_MAX;
+ }
+ if (y >= SHRT_MAX) {
+ cout << "y(" << y << ") coordinate overflow!" << endl;
+ y = SHRT_MAX;
+ }
+
+ if (coverage) {
+ auto count = rw.spansCnt;
+ auto span = rw.spans + count - 1;
+ assert(span);
+
+ //see whether we can add this span to the current list
+ if ((count > 0) && (rw.ySpan == y) &&
+ (span->x + span->len == x) && (span->coverage == coverage)) {
+ span->len = span->len + acount;
+ return;
+ }
+
+ if (count >= MAX_SPANS) {
+ _genSpan(rw.rle, rw.spans, count);
+ rw.spansCnt = 0;
+ span = rw.spans;
+ assert(span);
+ } else {
+ ++span;
+ assert(span);
+ }
+
+ //add a span to the current list
+ span->x = x;
+ span->y = y;
+ span->len = acount;
+ span->coverage = coverage;
+ ++rw.spansCnt;
+ }
}
-static void sweep(RleWorker& rw)
+static void _sweep(RleWorker& rw)
{
if (rw.cellsCnt == 0) return;
while (cell) {
- horizLine(rw, x, y, cover * (ONE_PIXEL * 2), cell->x - x);
+ _horizLine(rw, x, y, cover * (ONE_PIXEL * 2), cell->x - x);
cover += cell->cover;
auto area = cover * (ONE_PIXEL * 2) - cell->area;
if (area != 0 && cell->x >= 0)
- horizLine(rw, cell->x, y, area, 1);
+ _horizLine(rw, cell->x, y, area, 1);
x = cell->x + 1;
cell = cell->next;
}
if (cover != 0)
- horizLine(rw, x, y, cover * (ONE_PIXEL * 2), rw.cellXCnt - x);
+ _horizLine(rw, x, y, cover * (ONE_PIXEL * 2), rw.cellXCnt - x);
}
- if (rw.spansCnt > 0) genSpan(rw);
+ if (rw.spansCnt > 0) _genSpan(rw.rle, rw.spans, rw.spansCnt);
}
-static Cell* findCell(RleWorker& rw)
+static Cell* _findCell(RleWorker& rw)
{
auto x = rw.cellPos.x;
if (x > rw.cellXCnt) x = rw.cellXCnt;
}
-static void recordCell(RleWorker& rw)
+static void _recordCell(RleWorker& rw)
{
if (rw.area | rw.cover) {
- auto cell = findCell(rw);
+ auto cell = _findCell(rw);
assert(cell);
cell->area += rw.area;
cell->cover += rw.cover;
}
}
-static void setCell(RleWorker& rw, SwPoint pos)
+
+static void _setCell(RleWorker& rw, SwPoint pos)
{
/* Move the cell pointer to a new position. We set the `invalid' */
/* flag to indicate that the cell isn't part of those we're interested */
//Are we moving to a different cell?
if (pos != rw.cellPos) {
- if (!rw.invalid) recordCell(rw);
+ if (!rw.invalid) _recordCell(rw);
}
rw.area = 0;
}
-static void startCell(RleWorker& rw, SwPoint pos)
+static void _startCell(RleWorker& rw, SwPoint pos)
{
if (pos.x > rw.cellMax.x) pos.x = rw.cellMax.x;
if (pos.x < rw.cellMin.x) pos.x = rw.cellMin.x;
rw.cellPos = pos - rw.cellMin;
rw.invalid = false;
- setCell(rw, pos);
+ _setCell(rw, pos);
}
-static void moveTo(RleWorker& rw, const SwPoint& to)
+static void _moveTo(RleWorker& rw, const SwPoint& to)
{
//record current cell, if any */
- if (!rw.invalid) recordCell(rw);
+ if (!rw.invalid) _recordCell(rw);
//start to a new position
- startCell(rw, TRUNC(to));
+ _startCell(rw, TRUNC(to));
rw.pos = to;
}
-static void lineTo(RleWorker& rw, const SwPoint& to)
+static void _lineTo(RleWorker& rw, const SwPoint& to)
{
#define SW_UDIV(a, b) \
static_cast<SwCoord>(((unsigned long)(a) * (unsigned long)(b)) >> \
//any horizontal line
} else if (diff.y == 0) {
e1.x = e2.x;
- setCell(rw, e1);
+ _setCell(rw, e1);
} else if (diff.x == 0) {
//vertical line up
if (diff.y > 0) {
rw.area += (f2.y - f1.y) * f1.x * 2;
f1.y = 0;
++e1.y;
- setCell(rw, e1);
+ _setCell(rw, e1);
} while(e1.y != e2.y);
//vertical line down
} else {
rw.area += (f2.y - f1.y) * f1.x * 2;
f1.y = ONE_PIXEL;
--e1.y;
- setCell(rw, e1);
+ _setCell(rw, e1);
} while(e1.y != e2.y);
}
//any other line
--e1.y;
}
- setCell(rw, e1);
+ _setCell(rw, e1);
} while(e1 != e2);
}
}
-static bool renderCubic(RleWorker& rw, SwPoint& ctrl1, SwPoint& ctrl2, SwPoint& to)
+static void _splitCubic(SwPoint* base)
{
- return true;
+ assert(base);
+
+ SwCoord a, b, c, d;
+
+ base[6].x = base[3].x;
+ c = base[1].x;
+ d = base[2].x;
+ base[1].x = a = (base[0].x + c) / 2;
+ base[5].x = b = (base[3].x + d) / 2;
+ c = (c + d) / 2;
+ base[2].x = a = (a + c) / 2;
+ base[4].x = b = (b + c) / 2;
+ base[3].x = (a + b) / 2;
+
+ base[6].y = base[3].y;
+ c = base[1].y;
+ d = base[2].y;
+ base[1].y = a = (base[0].y + c) / 2;
+ base[5].y = b = (base[3].y + d) / 2;
+ c = (c + d) / 2;
+ base[2].y = a = (a + c) / 2;
+ base[4].y = b = (b + c) / 2;
+ base[3].y = (a + b) / 2;
}
-static bool cubicTo(RleWorker& rw, SwPoint& ctrl1, SwPoint& ctrl2, SwPoint& to)
+static void _cubicTo(RleWorker& rw, const SwPoint& ctrl1, const SwPoint& ctrl2, const SwPoint& to)
{
- return renderCubic(rw, ctrl1, ctrl2, to);
+ auto arc = rw.bezStack;
+ assert(arc);
+
+ arc[0] = to;
+ arc[1] = ctrl2;
+ arc[2] = ctrl1;
+ arc[3] = rw.pos;
+
+ //Short-cut the arc that crosses the current band
+ auto min = arc[0].y;
+ auto max = arc[0].y;
+
+ SwCoord y;
+ for (auto i = 1; i < 4; ++i) {
+ y = arc[i].y;
+ if (y < min) min = y;
+ if (y > max) max = y;
+ }
+
+ if (TRUNC(min) >= rw.cellMax.y || TRUNC(max) < rw.cellMin.y) goto draw;
+
+ /* Decide whether to split or draw. See `Rapid Termination */
+ /* Evaluation for Recursive Subdivision of Bezier Curves' by Thomas */
+ /* F. Hain, at */
+ /* http://www.cis.southalabama.edu/~hain/general/Publications/Bezier/Camera-ready%20CISST02%202.pdf */
+ while (true) {
+ {
+ //diff is the P0 - P3 chord vector
+ auto diff = arc[3] - arc[0];
+ auto L = HYPOT(diff);
+
+ //avoid possible arithmetic overflow below by splitting
+ if (L > SHRT_MAX) goto split;
+
+ //max deviation may be as much as (s/L) * 3/4 (if Hain's v = 1)
+ auto sLimit = L * (ONE_PIXEL / 6);
+
+ auto diff1 = arc[1] - arc[0];
+ auto s = diff.y * diff1.x - diff.x * diff1.y;
+ if (s < 0) s = -s;
+ if (s > sLimit) goto split;
+
+ //s is L * the perpendicular distance from P2 to the line P0 - P3
+ auto diff2 = arc[2] - arc[0];
+ s = diff.y * diff2.x - diff.x * diff2.y;
+ if (s < 0) s = -s;
+ if (s > sLimit) goto split;
+
+ /* Split super curvy segments where the off points are so far
+ from the chord that the angles P0-P1-P3 or P0-P2-P3 become
+ acute as detected by appropriate dot products */
+ if (diff1.x * (diff1.x - diff.x) + diff1.y * (diff1.y - diff.y) > 0 ||
+ diff2.x * (diff2.x - diff.x) + diff2.y * (diff2.y - diff.y) > 0)
+ goto split;
+
+ //no reason to split
+ goto draw;
+ }
+ split:
+ _splitCubic(arc);
+ arc += 3;
+ continue;
+
+ draw:
+ _lineTo(rw, arc[0]);
+
+ if (arc == rw.bezStack) return;
+
+ arc -= 3;
+ }
}
-static bool decomposeOutline(RleWorker& rw)
+static bool _decomposeOutline(RleWorker& rw)
{
- // printf("decomposOutline\n");
auto outline = rw.outline;
assert(outline);
/* A contour cannot start with a cubic control point! */
if (tags[0] == SW_CURVE_TAG_CUBIC) goto invalid_outline;
- moveTo(rw, UPSCALE(outline->pts[first]));
+ _moveTo(rw, UPSCALE(outline->pts[first]));
while (pt < limit) {
assert(++pt);
//emit a single line_to
if (tags[0] == SW_CURVE_TAG_ON) {
- lineTo(rw, UPSCALE(*pt));
+ _lineTo(rw, UPSCALE(*pt));
//tag cubic
} else {
if (pt + 1 > limit || tags[1] != SW_CURVE_TAG_CUBIC)
tags += 2;
if (pt <= limit) {
- if (!cubicTo(rw, pt[-2], pt[-1], pt[0])) return false;
+ _cubicTo(rw, UPSCALE(pt[-2]), UPSCALE(pt[-1]), UPSCALE(pt[0]));
continue;
}
- if (!cubicTo(rw, pt[-2], pt[-1], outline->pts[first])) return false;
+ _cubicTo(rw, UPSCALE(pt[-2]), UPSCALE(pt[-1]), UPSCALE(outline->pts[first]));
goto close;
}
}
}
-static bool genRle(RleWorker& rw)
+static bool _genRle(RleWorker& rw)
{
bool ret = false;
if (setjmp(rw.jmpBuf) == 0) {
- ret = decomposeOutline(rw);
- if (!rw.invalid) recordCell(rw);
+ ret = _decomposeOutline(rw);
+ if (!rw.invalid) _recordCell(rw);
} else {
cout << "Memory Overflow" << endl;
}
/* External Class Implementation */
/************************************************************************/
-bool rleRender(SwShape& sdata)
+SwRleData* rleRender(const SwShape& sdata)
{
constexpr auto RENDER_POOL_SIZE = 16384L;
constexpr auto BAND_SIZE = 39;
auto outline = sdata.outline;
assert(outline);
- if (outline->ptsCnt == 0 || outline->cntrsCnt <= 0) return false;
+ if (outline->ptsCnt == 0 || outline->cntrsCnt <= 0) return nullptr;
assert(outline->cntrs && outline->pts);
assert(outline->ptsCnt == outline->cntrs[outline->cntrsCnt - 1] + 1);
rw.outline = outline;
rw.bandSize = rw.bufferSize / (sizeof(Cell) * 8); //bandSize: 64
rw.bandShoot = 0;
+ rw.rle = reinterpret_cast<SwRleData*>(calloc(1, sizeof(SwRleData)));
+ assert(rw.rle);
+
//printf("bufferSize = %d, bbox(%f %f %f %f), exCnt(%f), eyCnt(%f), bandSize(%d)\n", rw.bufferSize, rw.exMin, rw.eyMin, rw.exMax, rw.eyMax, rw.exCnt, rw.eyCnt, rw.bandSize);
//Generate RLE
rw.cellMax.y = band->max;
rw.cellYCnt = band->max - band->min;
- if (!genRle(rw)) return -1;
+ if (!_genRle(rw)) goto error;
- sweep(rw);
+ _sweep(rw);
--band;
continue;
/* This is too complex for a single scanline; there must
be some problems */
- if (middle == bottom) return -1;
+ if (middle == bottom) goto error;
if (bottom - top >= rw.bandSize) ++rw.bandShoot;
if (rw.bandShoot > 8 && rw.bandSize > 16)
rw.bandSize = (rw.bandSize >> 1);
- return true;
+ return rw.rle;
+
+error:
+ free(rw.rle);
+ rw.rle = nullptr;
+ return nullptr;
}
#endif /* _TVG_SW_RLE_H_ */
}
-static void growOutlineContour(SwOutline& outline, size_t n)
+static void _growOutlineContour(SwOutline& outline, size_t n)
{
if (n == 0) {
free(outline.cntrs);
}
if (outline.reservedCntrsCnt >= outline.cntrsCnt + n) return;
- cout << "Grow Cntrs: " << outline.reservedCntrsCnt << " -> " << outline.cntrsCnt + n << endl;;
+ //cout << "Grow Cntrs: " << outline.reservedCntrsCnt << " -> " << outline.cntrsCnt + n << endl;;
outline.reservedCntrsCnt = n;
outline.cntrs = static_cast<size_t*>(realloc(outline.cntrs, n * sizeof(size_t)));
assert(outline.cntrs);
}
-static void growOutlinePoint(SwOutline& outline, size_t n)
+static void _growOutlinePoint(SwOutline& outline, size_t n)
{
if (n == 0) {
free(outline.pts);
if (outline.reservedPtsCnt >= outline.ptsCnt + n) return;
- cout << "Grow Pts: " << outline.reservedPtsCnt << " -> " << outline.ptsCnt + n << endl;
+ //cout << "Grow Pts: " << outline.reservedPtsCnt << " -> " << outline.ptsCnt + n << endl;
outline.reservedPtsCnt = n;
outline.pts = static_cast<SwPoint*>(realloc(outline.pts, n * sizeof(SwPoint)));
assert(outline.pts);
}
-static void outlineEnd(SwOutline& outline)
+static void _outlineEnd(SwOutline& outline)
{
- growOutlineContour(outline, 1);
+ _growOutlineContour(outline, 1);
if (outline.ptsCnt > 0) {
outline.cntrs[outline.cntrsCnt] = outline.ptsCnt - 1;
++outline.cntrsCnt;
}
-static void outlineMoveTo(SwOutline& outline, const Point* to)
+static void _outlineMoveTo(SwOutline& outline, const Point* to)
{
assert(to);
- growOutlinePoint(outline, 1);
+ _growOutlinePoint(outline, 1);
outline.pts[outline.ptsCnt] = TO_SWPOINT(to);
outline.tags[outline.ptsCnt] = SW_CURVE_TAG_ON;
if (outline.ptsCnt > 0) {
- growOutlineContour(outline, 1);
+ _growOutlineContour(outline, 1);
outline.cntrs[outline.cntrsCnt] = outline.ptsCnt - 1;
++outline.cntrsCnt;
}
}
-static void outlineLineTo(SwOutline& outline, const Point* to)
+static void _outlineLineTo(SwOutline& outline, const Point* to)
{
assert(to);
- growOutlinePoint(outline, 1);
+ _growOutlinePoint(outline, 1);
outline.pts[outline.ptsCnt] = TO_SWPOINT(to);
outline.tags[outline.ptsCnt] = SW_CURVE_TAG_ON;
}
-static void outlineCubicTo(SwOutline& outline, const Point* ctrl1, const Point* ctrl2, const Point* to)
+static void _outlineCubicTo(SwOutline& outline, const Point* ctrl1, const Point* ctrl2, const Point* to)
{
assert(ctrl1 && ctrl2 && to);
- growOutlinePoint(outline, 3);
+ _growOutlinePoint(outline, 3);
outline.pts[outline.ptsCnt] = TO_SWPOINT(ctrl1);
outline.tags[outline.ptsCnt] = SW_CURVE_TAG_CUBIC;
}
-static bool outlineClose(SwOutline& outline)
+static bool _outlineClose(SwOutline& outline)
{
size_t i = 0;
if (outline.ptsCnt == i) return false;
//Close the path
- growOutlinePoint(outline, 1);
+ _growOutlinePoint(outline, 1);
outline.pts[outline.ptsCnt] = outline.pts[i];
outline.tags[outline.ptsCnt] = SW_CURVE_TAG_ON;
}
-static void initBBox(SwShape& sdata)
+static void _initBBox(SwShape& sdata)
{
sdata.bbox.min.x = sdata.bbox.min.y = 0;
sdata.bbox.max.x = sdata.bbox.max.y = 0;
}
-static bool updateBBox(SwShape& sdata)
+static bool _updateBBox(SwShape& sdata)
{
auto outline = sdata.outline;
assert(outline);
assert(pt);
if (outline->ptsCnt <= 0) {
- initBBox(sdata);
+ _initBBox(sdata);
return false;
}
}
+void _deleteRle(SwShape& sdata)
+{
+ if (sdata.rle) {
+ if (sdata.rle->spans) free(sdata.rle->spans);
+ free(sdata.rle);
+ }
+ sdata.rle = nullptr;
+}
+
+
+void _deleteOutline(SwShape& sdata)
+{
+ if (!sdata.outline) return;
+
+ SwOutline* outline = sdata.outline;
+ if (outline->cntrs) free(outline->cntrs);
+ if (outline->pts) free(outline->pts);
+ if (outline->tags) free(outline->tags);
+ free(outline);
+
+ sdata.outline = nullptr;
+}
+
/************************************************************************/
/* External Class Implementation */
/************************************************************************/
}
-void shapeDelRle(const ShapeNode& shape, SwShape& sdata)
-{
- if (sdata.rle.spans) free(sdata.rle.spans);
- sdata.rle.spans = nullptr;
-}
-
-
bool shapeGenRle(const ShapeNode& shape, SwShape& sdata)
{
- shapeDelRle(shape, sdata);
- if (!updateBBox(sdata)) return false;
- return rleRender(sdata);
+ if (!_updateBBox(sdata)) goto end;
+ sdata.rle = rleRender(sdata);
+ _deleteOutline(sdata);
+end:
+ if (sdata.rle) return true;
+ return false;
}
-void shapeDelOutline(const ShapeNode& shape, SwShape& sdata)
+void shapeReset(SwShape& sdata)
{
- if (!sdata.outline) return;
-
- SwOutline* outline = sdata.outline;
- if (outline->cntrs) free(outline->cntrs);
- if (outline->pts) free(outline->pts);
- if (outline->tags) free(outline->tags);
- free(outline);
-
- sdata.outline = nullptr;
+ _deleteOutline(sdata);
+ _deleteRle(sdata);
+ _initBBox(sdata);
}
bool shapeGenOutline(const ShapeNode& shape, SwShape& sdata)
{
- initBBox(sdata);
-
const PathCommand* cmds = nullptr;
auto cmdCnt = shape.pathCommands(&cmds);
//smart reservation
auto outlinePtsCnt = 0;
auto outlineCntrsCnt = 0;
-// auto closed = false;
for (auto i = 0; i < cmdCnt; ++i) {
switch(*(cmds + i)) {
}
//TODO: Probabry we can copy pts from shape directly.
- growOutlinePoint(*outline, outlinePtsCnt);
- growOutlineContour(*outline, outlineCntrsCnt);
+ _growOutlinePoint(*outline, outlinePtsCnt);
+ _growOutlineContour(*outline, outlineCntrsCnt);
//Generate Outlines
while (cmdCnt-- > 0) {
switch(*cmds) {
case PathCommand::Close: {
- outlineClose(*outline);
+ _outlineClose(*outline);
break;
}
case PathCommand::MoveTo: {
- outlineMoveTo(*outline, pts);
+ _outlineMoveTo(*outline, pts);
++pts;
break;
}
case PathCommand::LineTo: {
- outlineLineTo(*outline, pts);
+ _outlineLineTo(*outline, pts);
++pts;
break;
}
case PathCommand::CubicTo: {
- outlineCubicTo(*outline, pts, pts + 1, pts + 2);
+ _outlineCubicTo(*outline, pts, pts + 1, pts + 2);
pts += 3;
break;
}
++cmds;
}
- outlineEnd(*outline);
+ _outlineEnd(*outline);
//FIXME:
//outline->flags = SwOutline::FillRule::Winding;
CanvasBase(RasterMethod *pRaster):raster(pRaster)
{
-
+ raster->ref();
}
~CanvasBase()
{
clear();
+ raster->unref();
}
int reserve(size_t n)
int clear()
{
for (auto node : nodes) {
+ node->dispose(raster);
delete(node);
}
nodes.clear();
enum UpdateFlag { None = 0, Path = 1, Fill = 2, All = 3 };
virtual ~RasterMethod() {}
virtual void* prepare(const ShapeNode& shape, void* data, UpdateFlag flags) = 0;
+ virtual void* dispose(const ShapeNode& shape, void *data) = 0;
+ virtual size_t ref() = 0;
+ virtual size_t unref() = 0;
+};
+
+struct RasterMethodInit
+{
+ RasterMethod* pInst = nullptr;
+ size_t refCnt = 0;
+ bool initted = false;
+
+ static int init(RasterMethodInit& initter, RasterMethod* engine)
+ {
+ assert(engine);
+ if (initter.pInst || initter.refCnt > 0) return -1;
+ initter.pInst = engine;
+ initter.refCnt = 0;
+ initter.initted = true;
+ return 0;
+ }
+
+ static int term(RasterMethodInit& initter)
+ {
+ if (!initter.pInst || !initter.initted) return -1;
+
+ initter.initted = false;
+
+ //Still it's refered....
+ if (initter.refCnt > 0) return 0;
+ delete(initter.pInst);
+ initter.pInst = nullptr;
+
+ return 0;
+ }
+
+ static size_t unref(RasterMethodInit& initter)
+ {
+ assert(initter.refCnt > 0);
+ --initter.refCnt;
+
+ //engine has been requested to termination
+ if (!initter.initted && initter.refCnt == 0) {
+ if (initter.pInst) {
+ delete(initter.pInst);
+ initter.pInst = nullptr;
+ }
+ }
+ return initter.refCnt;
+ }
+
+ static RasterMethod* inst(RasterMethodInit& initter)
+ {
+ assert(initter.pInst);
+ return initter.pInst;
+ }
+
+ static size_t ref(RasterMethodInit& initter)
+ {
+ return ++initter.refCnt;
+ }
+
};
}
}
+int SceneNode :: dispose(RasterMethod* engine) noexcept
+{
+
+ return 0;
+}
+
+
int SceneNode :: update(RasterMethod* engine) noexcept
{
}
+int ShapeNode :: dispose(RasterMethod* engine) noexcept
+{
+ auto impl = pImpl.get();
+ assert(impl);
+
+ impl->edata = engine->dispose(*this, impl->edata);
+ if (impl->edata) return -1;
+ return 0;
+}
+
+
int ShapeNode :: update(RasterMethod* engine) noexcept
{
auto impl = pImpl.get();
SwCanvas::~SwCanvas()
{
- cout << "SwCanvas(" << this << ") destroyed!" << endl;
+ cout << "SwCanvas(" << this << ") destroyed!" << endl;
}