mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-07 21:23:32 +00:00
sw_engine: implement line and curve raster
Change-Id: I22a77892544cd510cfe646aee60093cebb848806
This commit is contained in:
parent
de242b018b
commit
c8d800f6c6
13 changed files with 461 additions and 138 deletions
|
@ -73,6 +73,7 @@ class TIZENVG_EXPORT PaintNode
|
|||
{
|
||||
public:
|
||||
virtual ~PaintNode() {}
|
||||
virtual int dispose(RasterMethod* engine) = 0;
|
||||
virtual int update(RasterMethod* engine) = 0;
|
||||
};
|
||||
|
||||
|
@ -90,6 +91,7 @@ class TIZENVG_EXPORT ShapeNode final : public PaintNode
|
|||
public:
|
||||
~ShapeNode();
|
||||
|
||||
int dispose(RasterMethod* engine) noexcept override;
|
||||
int update(RasterMethod* engine) noexcept override;
|
||||
int clear() noexcept;
|
||||
|
||||
|
@ -121,6 +123,7 @@ class TIZENVG_EXPORT SceneNode final : public PaintNode
|
|||
public:
|
||||
~SceneNode();
|
||||
|
||||
int dispose(RasterMethod* engine) noexcept override;
|
||||
int update(RasterMethod* engine) noexcept override;
|
||||
|
||||
int push(std::unique_ptr<ShapeNode> shape) noexcept;
|
||||
|
|
|
@ -20,14 +20,29 @@
|
|||
#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)
|
||||
{
|
||||
|
@ -37,35 +52,37 @@ 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));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -24,6 +24,10 @@ class GlEngine : public RasterMethod
|
|||
{
|
||||
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();
|
||||
|
|
|
@ -23,6 +23,8 @@ using namespace tvg;
|
|||
|
||||
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;
|
||||
|
||||
|
@ -56,43 +58,41 @@ struct SwOutline
|
|||
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_ */
|
||||
|
|
|
@ -24,13 +24,22 @@
|
|||
/* 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
|
||||
|
@ -48,11 +57,11 @@ void* SwEngine::prepare(const ShapeNode& shape, void* data, UpdateFlag flags)
|
|||
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;
|
||||
|
@ -61,28 +70,31 @@ void* SwEngine::prepare(const ShapeNode& shape, void* data, UpdateFlag flags)
|
|||
|
||||
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));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -21,6 +21,10 @@ class SwEngine : public RasterMethod
|
|||
{
|
||||
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();
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
#include <setjmp.h>
|
||||
#include <limits.h>
|
||||
#include <memory.h>
|
||||
#include "tvgSwCommon.h"
|
||||
|
||||
/************************************************************************/
|
||||
|
@ -29,7 +30,6 @@ constexpr auto MAX_SPANS = 256;
|
|||
constexpr auto PIXEL_BITS = 8; //must be at least 6 bits!
|
||||
constexpr auto ONE_PIXEL = (1L << PIXEL_BITS);
|
||||
|
||||
|
||||
using Area = long;
|
||||
|
||||
struct Band
|
||||
|
@ -47,6 +47,8 @@ struct Cell
|
|||
|
||||
struct RleWorker
|
||||
{
|
||||
SwRleData* rle;
|
||||
|
||||
SwPoint cellPos;
|
||||
SwPoint cellMin;
|
||||
SwPoint cellMax;
|
||||
|
@ -100,13 +102,19 @@ static inline SwPoint DOWNSCALE(const SwPoint& pt)
|
|||
|
||||
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};
|
||||
}
|
||||
|
||||
|
||||
|
@ -115,20 +123,105 @@ static inline SwCoord SUBPIXELS(const SwCoord x)
|
|||
return (x << PIXEL_BITS);
|
||||
}
|
||||
|
||||
|
||||
static void horizLine(RleWorker& rw, SwCoord x, SwCoord y, SwCoord area, SwCoord acount)
|
||||
/*
|
||||
* 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)
|
||||
{
|
||||
//TODO:
|
||||
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 _genSpan(SwRleData* rle, SwSpan* spans, size_t count)
|
||||
{
|
||||
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;
|
||||
|
||||
|
@ -142,26 +235,26 @@ static void sweep(RleWorker& rw)
|
|||
|
||||
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;
|
||||
|
@ -190,17 +283,18 @@ static Cell* findCell(RleWorker& rw)
|
|||
}
|
||||
|
||||
|
||||
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 */
|
||||
|
@ -222,7 +316,7 @@ static void setCell(RleWorker& rw, SwPoint pos)
|
|||
|
||||
//Are we moving to a different cell?
|
||||
if (pos != rw.cellPos) {
|
||||
if (!rw.invalid) recordCell(rw);
|
||||
if (!rw.invalid) _recordCell(rw);
|
||||
}
|
||||
|
||||
rw.area = 0;
|
||||
|
@ -232,7 +326,7 @@ static void setCell(RleWorker& rw, SwPoint pos)
|
|||
}
|
||||
|
||||
|
||||
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;
|
||||
|
@ -242,23 +336,23 @@ static void startCell(RleWorker& rw, SwPoint pos)
|
|||
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)) >> \
|
||||
|
@ -284,7 +378,7 @@ static void lineTo(RleWorker& rw, const SwPoint& to)
|
|||
//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) {
|
||||
|
@ -294,7 +388,7 @@ static void lineTo(RleWorker& rw, const SwPoint& to)
|
|||
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 {
|
||||
|
@ -304,7 +398,7 @@ static void lineTo(RleWorker& rw, const SwPoint& to)
|
|||
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
|
||||
|
@ -357,7 +451,7 @@ static void lineTo(RleWorker& rw, const SwPoint& to)
|
|||
--e1.y;
|
||||
}
|
||||
|
||||
setCell(rw, e1);
|
||||
_setCell(rw, e1);
|
||||
|
||||
} while(e1 != e2);
|
||||
}
|
||||
|
@ -369,21 +463,111 @@ static void lineTo(RleWorker& rw, const SwPoint& to)
|
|||
}
|
||||
|
||||
|
||||
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);
|
||||
|
||||
|
@ -402,7 +586,7 @@ static bool decomposeOutline(RleWorker& rw)
|
|||
/* 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);
|
||||
|
@ -410,7 +594,7 @@ static bool decomposeOutline(RleWorker& rw)
|
|||
|
||||
//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)
|
||||
|
@ -420,10 +604,10 @@ static bool decomposeOutline(RleWorker& rw)
|
|||
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;
|
||||
}
|
||||
}
|
||||
|
@ -442,13 +626,13 @@ invalid_outline:
|
|||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -460,7 +644,7 @@ static bool genRle(RleWorker& rw)
|
|||
/* External Class Implementation */
|
||||
/************************************************************************/
|
||||
|
||||
bool rleRender(SwShape& sdata)
|
||||
SwRleData* rleRender(const SwShape& sdata)
|
||||
{
|
||||
constexpr auto RENDER_POOL_SIZE = 16384L;
|
||||
constexpr auto BAND_SIZE = 39;
|
||||
|
@ -468,7 +652,7 @@ bool rleRender(SwShape& sdata)
|
|||
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);
|
||||
|
@ -494,6 +678,9 @@ bool rleRender(SwShape& sdata)
|
|||
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
|
||||
|
@ -547,9 +734,9 @@ bool rleRender(SwShape& sdata)
|
|||
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;
|
||||
|
||||
|
@ -561,7 +748,7 @@ bool rleRender(SwShape& sdata)
|
|||
|
||||
/* 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;
|
||||
|
||||
|
@ -576,7 +763,12 @@ bool rleRender(SwShape& sdata)
|
|||
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_ */
|
||||
|
|
|
@ -29,7 +29,7 @@ static inline SwPoint TO_SWPOINT(const Point* pt)
|
|||
}
|
||||
|
||||
|
||||
static void growOutlineContour(SwOutline& outline, size_t n)
|
||||
static void _growOutlineContour(SwOutline& outline, size_t n)
|
||||
{
|
||||
if (n == 0) {
|
||||
free(outline.cntrs);
|
||||
|
@ -40,14 +40,14 @@ static void growOutlineContour(SwOutline& outline, size_t n)
|
|||
}
|
||||
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);
|
||||
|
@ -61,7 +61,7 @@ static void growOutlinePoint(SwOutline& outline, size_t n)
|
|||
|
||||
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);
|
||||
|
@ -70,9 +70,9 @@ static void growOutlinePoint(SwOutline& outline, size_t n)
|
|||
}
|
||||
|
||||
|
||||
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;
|
||||
|
@ -80,17 +80,17 @@ static void outlineEnd(SwOutline& outline)
|
|||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -99,11 +99,11 @@ static void outlineMoveTo(SwOutline& outline, const Point* to)
|
|||
}
|
||||
|
||||
|
||||
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;
|
||||
|
@ -112,11 +112,11 @@ static void outlineLineTo(SwOutline& outline, const Point* to)
|
|||
}
|
||||
|
||||
|
||||
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;
|
||||
|
@ -132,7 +132,7 @@ static void outlineCubicTo(SwOutline& outline, const Point* ctrl1, const Point*
|
|||
}
|
||||
|
||||
|
||||
static bool outlineClose(SwOutline& outline)
|
||||
static bool _outlineClose(SwOutline& outline)
|
||||
{
|
||||
size_t i = 0;
|
||||
|
||||
|
@ -146,7 +146,7 @@ static bool outlineClose(SwOutline& outline)
|
|||
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;
|
||||
|
@ -156,14 +156,14 @@ static bool outlineClose(SwOutline& outline)
|
|||
}
|
||||
|
||||
|
||||
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);
|
||||
|
@ -172,7 +172,7 @@ static bool updateBBox(SwShape& sdata)
|
|||
assert(pt);
|
||||
|
||||
if (outline->ptsCnt <= 0) {
|
||||
initBBox(sdata);
|
||||
_initBBox(sdata);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -201,33 +201,17 @@ static bool updateBBox(SwShape& sdata)
|
|||
}
|
||||
|
||||
|
||||
/************************************************************************/
|
||||
/* External Class Implementation */
|
||||
/************************************************************************/
|
||||
|
||||
bool shapeTransformOutline(const ShapeNode& shape, SwShape& sdata)
|
||||
void _deleteRle(SwShape& sdata)
|
||||
{
|
||||
//TODO:
|
||||
return true;
|
||||
if (sdata.rle) {
|
||||
if (sdata.rle->spans) free(sdata.rle->spans);
|
||||
free(sdata.rle);
|
||||
}
|
||||
sdata.rle = nullptr;
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
void shapeDelOutline(const ShapeNode& shape, SwShape& sdata)
|
||||
void _deleteOutline(SwShape& sdata)
|
||||
{
|
||||
if (!sdata.outline) return;
|
||||
|
||||
|
@ -240,11 +224,38 @@ void shapeDelOutline(const ShapeNode& shape, SwShape& sdata)
|
|||
sdata.outline = nullptr;
|
||||
}
|
||||
|
||||
/************************************************************************/
|
||||
/* External Class Implementation */
|
||||
/************************************************************************/
|
||||
|
||||
bool shapeTransformOutline(const ShapeNode& shape, SwShape& sdata)
|
||||
{
|
||||
//TODO:
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool shapeGenRle(const ShapeNode& shape, SwShape& sdata)
|
||||
{
|
||||
if (!_updateBBox(sdata)) goto end;
|
||||
sdata.rle = rleRender(sdata);
|
||||
_deleteOutline(sdata);
|
||||
end:
|
||||
if (sdata.rle) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void shapeReset(SwShape& sdata)
|
||||
{
|
||||
_deleteOutline(sdata);
|
||||
_deleteRle(sdata);
|
||||
_initBBox(sdata);
|
||||
}
|
||||
|
||||
|
||||
bool shapeGenOutline(const ShapeNode& shape, SwShape& sdata)
|
||||
{
|
||||
initBBox(sdata);
|
||||
|
||||
const PathCommand* cmds = nullptr;
|
||||
auto cmdCnt = shape.pathCommands(&cmds);
|
||||
|
||||
|
@ -257,7 +268,6 @@ bool shapeGenOutline(const ShapeNode& shape, SwShape& sdata)
|
|||
//smart reservation
|
||||
auto outlinePtsCnt = 0;
|
||||
auto outlineCntrsCnt = 0;
|
||||
// auto closed = false;
|
||||
|
||||
for (auto i = 0; i < cmdCnt; ++i) {
|
||||
switch(*(cmds + i)) {
|
||||
|
@ -294,28 +304,28 @@ bool shapeGenOutline(const ShapeNode& shape, SwShape& sdata)
|
|||
}
|
||||
|
||||
//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;
|
||||
}
|
||||
|
@ -323,7 +333,7 @@ bool shapeGenOutline(const ShapeNode& shape, SwShape& sdata)
|
|||
++cmds;
|
||||
}
|
||||
|
||||
outlineEnd(*outline);
|
||||
_outlineEnd(*outline);
|
||||
|
||||
//FIXME:
|
||||
//outline->flags = SwOutline::FillRule::Winding;
|
||||
|
|
|
@ -30,12 +30,13 @@ struct CanvasBase
|
|||
|
||||
CanvasBase(RasterMethod *pRaster):raster(pRaster)
|
||||
{
|
||||
|
||||
raster->ref();
|
||||
}
|
||||
|
||||
~CanvasBase()
|
||||
{
|
||||
clear();
|
||||
raster->unref();
|
||||
}
|
||||
|
||||
int reserve(size_t n)
|
||||
|
@ -48,6 +49,7 @@ struct CanvasBase
|
|||
int clear()
|
||||
{
|
||||
for (auto node : nodes) {
|
||||
node->dispose(raster);
|
||||
delete(node);
|
||||
}
|
||||
nodes.clear();
|
||||
|
|
|
@ -35,6 +35,67 @@ public:
|
|||
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;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -58,6 +58,13 @@ int SceneNode :: push(unique_ptr<ShapeNode> shape) noexcept
|
|||
}
|
||||
|
||||
|
||||
int SceneNode :: dispose(RasterMethod* engine) noexcept
|
||||
{
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int SceneNode :: update(RasterMethod* engine) noexcept
|
||||
{
|
||||
|
||||
|
|
|
@ -84,6 +84,17 @@ unique_ptr<ShapeNode> ShapeNode::gen() 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();
|
||||
|
|
|
@ -89,7 +89,7 @@ SwCanvas::SwCanvas() : pImpl(make_unique<Impl>())
|
|||
|
||||
SwCanvas::~SwCanvas()
|
||||
{
|
||||
cout << "SwCanvas(" << this << ") destroyed!" << endl;
|
||||
cout << "SwCanvas(" << this << ") destroyed!" << endl;
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue