mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-11 15:12:08 +00:00
common shape: code refactoring & data optimization.
re-design the shape data structure so that render backends are able to access them directly. This also let us remove tvgShape member data from the Shape::Impl. To achieve this, migrate shape/stroke/path from the canvas interface to the render interface.
This commit is contained in:
parent
110f4a5cc9
commit
919c90a97e
13 changed files with 400 additions and 409 deletions
|
@ -54,7 +54,7 @@ class GlGeometry;
|
||||||
|
|
||||||
struct GlShape
|
struct GlShape
|
||||||
{
|
{
|
||||||
const Shape* shape = nullptr;
|
const RenderShape* rshape = nullptr;
|
||||||
float viewWd;
|
float viewWd;
|
||||||
float viewHt;
|
float viewHt;
|
||||||
RenderUpdateFlag updateFlag = None;
|
RenderUpdateFlag updateFlag = None;
|
||||||
|
|
|
@ -43,13 +43,12 @@ const GlSize GlGeometry::getPrimitiveSize(const uint32_t primitiveIndex) const
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool GlGeometry::decomposeOutline(const Shape& shape)
|
bool GlGeometry::decomposeOutline(const RenderShape& rshape)
|
||||||
{
|
{
|
||||||
const PathCommand* cmds = nullptr;
|
auto cmds = rshape.path.cmds;
|
||||||
auto cmdCnt = shape.pathCommands(&cmds);
|
auto cmdCnt = rshape.path.cmdCnt;
|
||||||
|
auto pts = rshape.path.pts;
|
||||||
Point* pts = nullptr;
|
auto ptsCnt = rshape.path.ptsCnt;
|
||||||
auto ptsCnt = shape.pathCoords(const_cast<const Point**>(&pts));
|
|
||||||
|
|
||||||
//No actual shape data
|
//No actual shape data
|
||||||
if (cmdCnt == 0 || ptsCnt == 0) return false;
|
if (cmdCnt == 0 || ptsCnt == 0) return false;
|
||||||
|
@ -101,7 +100,7 @@ bool GlGeometry::decomposeOutline(const Shape& shape)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GlGeometry::generateAAPoints(TVG_UNUSED const Shape& shape, float strokeWd, RenderUpdateFlag flag)
|
bool GlGeometry::generateAAPoints(TVG_UNUSED const RenderShape& rshape, float strokeWd, RenderUpdateFlag flag)
|
||||||
{
|
{
|
||||||
for (auto& shapeGeometry : mPrimitives) {
|
for (auto& shapeGeometry : mPrimitives) {
|
||||||
vector<PointNormals> normalInfo;
|
vector<PointNormals> normalInfo;
|
||||||
|
@ -158,7 +157,7 @@ bool GlGeometry::generateAAPoints(TVG_UNUSED const Shape& shape, float strokeWd,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GlGeometry::tesselate(TVG_UNUSED const Shape& shape, float viewWd, float viewHt, RenderUpdateFlag flag)
|
bool GlGeometry::tesselate(TVG_UNUSED const RenderShape& rshape, float viewWd, float viewHt, RenderUpdateFlag flag)
|
||||||
{
|
{
|
||||||
for (auto& shapeGeometry : mPrimitives) {
|
for (auto& shapeGeometry : mPrimitives) {
|
||||||
constexpr float opaque = 1.0f;
|
constexpr float opaque = 1.0f;
|
||||||
|
|
|
@ -237,9 +237,9 @@ public:
|
||||||
|
|
||||||
uint32_t getPrimitiveCount();
|
uint32_t getPrimitiveCount();
|
||||||
const GlSize getPrimitiveSize(const uint32_t primitiveIndex) const;
|
const GlSize getPrimitiveSize(const uint32_t primitiveIndex) const;
|
||||||
bool decomposeOutline(const Shape& shape);
|
bool decomposeOutline(const RenderShape& rshape);
|
||||||
bool generateAAPoints(TVG_UNUSED const Shape& shape, float strokeWd, RenderUpdateFlag flag);
|
bool generateAAPoints(TVG_UNUSED const RenderShape& rshape, float strokeWd, RenderUpdateFlag flag);
|
||||||
bool tesselate(TVG_UNUSED const Shape &shape, float viewWd, float viewHt, RenderUpdateFlag flag);
|
bool tesselate(TVG_UNUSED const RenderShape& rshape, float viewWd, float viewHt, RenderUpdateFlag flag);
|
||||||
void disableVertex(uint32_t location);
|
void disableVertex(uint32_t location);
|
||||||
void draw(const uint32_t location, const uint32_t primitiveIndex, RenderUpdateFlag flag);
|
void draw(const uint32_t location, const uint32_t primitiveIndex, RenderUpdateFlag flag);
|
||||||
void updateTransform(const RenderTransform* transform, float w, float h);
|
void updateTransform(const RenderTransform* transform, float w, float h);
|
||||||
|
|
|
@ -150,16 +150,13 @@ bool GlRenderer::renderShape(RenderData data)
|
||||||
{
|
{
|
||||||
if (flags & (RenderUpdateFlag::Gradient | RenderUpdateFlag::Transform))
|
if (flags & (RenderUpdateFlag::Gradient | RenderUpdateFlag::Transform))
|
||||||
{
|
{
|
||||||
const Fill* gradient = sdata->shape->fill();
|
auto gradient = sdata->rshape->fill;
|
||||||
if (gradient != nullptr)
|
if (gradient) drawPrimitive(*sdata, gradient, i, RenderUpdateFlag::Gradient);
|
||||||
{
|
|
||||||
drawPrimitive(*sdata, gradient, i, RenderUpdateFlag::Gradient);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(flags & (RenderUpdateFlag::Color | RenderUpdateFlag::Transform))
|
if(flags & (RenderUpdateFlag::Color | RenderUpdateFlag::Transform))
|
||||||
{
|
{
|
||||||
sdata->shape->fillColor(&r, &g, &b, &a);
|
sdata->rshape->fillColor(&r, &g, &b, &a);
|
||||||
if (a > 0)
|
if (a > 0)
|
||||||
{
|
{
|
||||||
drawPrimitive(*sdata, r, g, b, a, i, RenderUpdateFlag::Color);
|
drawPrimitive(*sdata, r, g, b, a, i, RenderUpdateFlag::Color);
|
||||||
|
@ -168,7 +165,7 @@ bool GlRenderer::renderShape(RenderData data)
|
||||||
|
|
||||||
if (flags & (RenderUpdateFlag::Stroke | RenderUpdateFlag::Transform))
|
if (flags & (RenderUpdateFlag::Stroke | RenderUpdateFlag::Transform))
|
||||||
{
|
{
|
||||||
sdata->shape->strokeColor(&r, &g, &b, &a);
|
sdata->rshape->strokeColor(&r, &g, &b, &a);
|
||||||
if (a > 0)
|
if (a > 0)
|
||||||
{
|
{
|
||||||
drawPrimitive(*sdata, r, g, b, a, i, RenderUpdateFlag::Stroke);
|
drawPrimitive(*sdata, r, g, b, a, i, RenderUpdateFlag::Stroke);
|
||||||
|
@ -197,13 +194,13 @@ RenderData GlRenderer::prepare(TVG_UNUSED Surface* image, TVG_UNUSED Polygon* tr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
RenderData GlRenderer::prepare(const Shape& shape, RenderData data, const RenderTransform* transform, TVG_UNUSED uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags, TVG_UNUSED bool clipper)
|
RenderData GlRenderer::prepare(const RenderShape& rshape, RenderData data, const RenderTransform* transform, TVG_UNUSED uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags, TVG_UNUSED bool clipper)
|
||||||
{
|
{
|
||||||
//prepare shape data
|
//prepare shape data
|
||||||
GlShape* sdata = static_cast<GlShape*>(data);
|
GlShape* sdata = static_cast<GlShape*>(data);
|
||||||
if (!sdata) {
|
if (!sdata) {
|
||||||
sdata = new GlShape;
|
sdata = new GlShape;
|
||||||
sdata->shape = &shape;
|
sdata->rshape = &rshape;
|
||||||
}
|
}
|
||||||
|
|
||||||
sdata->viewWd = static_cast<float>(surface.w);
|
sdata->viewWd = static_cast<float>(surface.w);
|
||||||
|
@ -216,9 +213,9 @@ RenderData GlRenderer::prepare(const Shape& shape, RenderData data, const Render
|
||||||
|
|
||||||
//invisible?
|
//invisible?
|
||||||
uint8_t alphaF, alphaS;
|
uint8_t alphaF, alphaS;
|
||||||
shape.fillColor(nullptr, nullptr, nullptr, &alphaF);
|
rshape.fillColor(nullptr, nullptr, nullptr, &alphaF);
|
||||||
shape.strokeColor(nullptr, nullptr, nullptr, &alphaS);
|
rshape.strokeColor(nullptr, nullptr, nullptr, &alphaS);
|
||||||
auto strokeWd = shape.strokeWidth();
|
auto strokeWd = rshape.strokeWidth();
|
||||||
|
|
||||||
if ( ((sdata->updateFlag & RenderUpdateFlag::Gradient) == 0) &&
|
if ( ((sdata->updateFlag & RenderUpdateFlag::Gradient) == 0) &&
|
||||||
((sdata->updateFlag & RenderUpdateFlag::Color) && alphaF == 0) &&
|
((sdata->updateFlag & RenderUpdateFlag::Color) && alphaF == 0) &&
|
||||||
|
@ -231,9 +228,9 @@ RenderData GlRenderer::prepare(const Shape& shape, RenderData data, const Render
|
||||||
|
|
||||||
if (sdata->updateFlag & (RenderUpdateFlag::Color | RenderUpdateFlag::Stroke | RenderUpdateFlag::Gradient | RenderUpdateFlag::Transform) )
|
if (sdata->updateFlag & (RenderUpdateFlag::Color | RenderUpdateFlag::Stroke | RenderUpdateFlag::Gradient | RenderUpdateFlag::Transform) )
|
||||||
{
|
{
|
||||||
if (!sdata->geometry->decomposeOutline(shape)) return sdata;
|
if (!sdata->geometry->decomposeOutline(rshape)) return sdata;
|
||||||
if (!sdata->geometry->generateAAPoints(shape, static_cast<float>(strokeWd), sdata->updateFlag)) return sdata;
|
if (!sdata->geometry->generateAAPoints(rshape, static_cast<float>(strokeWd), sdata->updateFlag)) return sdata;
|
||||||
if (!sdata->geometry->tesselate(shape, sdata->viewWd, sdata->viewHt, sdata->updateFlag)) return sdata;
|
if (!sdata->geometry->tesselate(rshape, sdata->viewWd, sdata->viewHt, sdata->updateFlag)) return sdata;
|
||||||
}
|
}
|
||||||
return sdata;
|
return sdata;
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,7 @@ class GlRenderer : public RenderMethod
|
||||||
public:
|
public:
|
||||||
Surface surface = {nullptr, 0, 0, 0};
|
Surface surface = {nullptr, 0, 0, 0};
|
||||||
|
|
||||||
RenderData prepare(const Shape& shape, RenderData data, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags, bool clipper) override;
|
RenderData prepare(const RenderShape& rshape, RenderData data, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags, bool clipper) override;
|
||||||
RenderData prepare(Surface* image, Polygon* triangles, uint32_t triangleCnt, RenderData data, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags) override;
|
RenderData prepare(Surface* image, Polygon* triangles, uint32_t triangleCnt, RenderData data, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags) override;
|
||||||
bool preRender() override;
|
bool preRender() override;
|
||||||
bool renderShape(RenderData data) override;
|
bool renderShape(RenderData data) override;
|
||||||
|
|
|
@ -302,12 +302,12 @@ bool mathUpdateOutlineBBox(const SwOutline* outline, const SwBBox& clipRegion, S
|
||||||
bool mathClipBBox(const SwBBox& clipper, SwBBox& clipee);
|
bool mathClipBBox(const SwBBox& clipper, SwBBox& clipee);
|
||||||
|
|
||||||
void shapeReset(SwShape* shape);
|
void shapeReset(SwShape* shape);
|
||||||
bool shapePrepare(SwShape* shape, const Shape* sdata, const Matrix* transform, const SwBBox& clipRegion, SwBBox& renderRegion, SwMpool* mpool, unsigned tid, bool hasComposite);
|
bool shapePrepare(SwShape* shape, const RenderShape* rshape, const Matrix* transform, const SwBBox& clipRegion, SwBBox& renderRegion, SwMpool* mpool, unsigned tid, bool hasComposite);
|
||||||
bool shapePrepared(const SwShape* shape);
|
bool shapePrepared(const SwShape* shape);
|
||||||
bool shapeGenRle(SwShape* shape, const Shape* sdata, bool antiAlias);
|
bool shapeGenRle(SwShape* shape, const RenderShape* rshape, bool antiAlias);
|
||||||
void shapeDelOutline(SwShape* shape, SwMpool* mpool, uint32_t tid);
|
void shapeDelOutline(SwShape* shape, SwMpool* mpool, uint32_t tid);
|
||||||
void shapeResetStroke(SwShape* shape, const Shape* sdata, const Matrix* transform);
|
void shapeResetStroke(SwShape* shape, const RenderShape* rshape, const Matrix* transform);
|
||||||
bool shapeGenStrokeRle(SwShape* shape, const Shape* sdata, const Matrix* transform, const SwBBox& clipRegion, SwBBox& renderRegion, SwMpool* mpool, unsigned tid);
|
bool shapeGenStrokeRle(SwShape* shape, const RenderShape* rshape, const Matrix* transform, const SwBBox& clipRegion, SwBBox& renderRegion, SwMpool* mpool, unsigned tid);
|
||||||
void shapeFree(SwShape* shape);
|
void shapeFree(SwShape* shape);
|
||||||
void shapeDelStroke(SwShape* shape);
|
void shapeDelStroke(SwShape* shape);
|
||||||
bool shapeGenFillColors(SwShape* shape, const Fill* fill, const Matrix* transform, SwSurface* surface, uint32_t opacity, bool ctable);
|
bool shapeGenFillColors(SwShape* shape, const Fill* fill, const Matrix* transform, SwSurface* surface, uint32_t opacity, bool ctable);
|
||||||
|
@ -317,7 +317,7 @@ void shapeResetStrokeFill(SwShape* shape);
|
||||||
void shapeDelFill(SwShape* shape);
|
void shapeDelFill(SwShape* shape);
|
||||||
void shapeDelStrokeFill(SwShape* shape);
|
void shapeDelStrokeFill(SwShape* shape);
|
||||||
|
|
||||||
void strokeReset(SwStroke* stroke, const Shape* shape, const Matrix* transform);
|
void strokeReset(SwStroke* stroke, const RenderShape* shape, const Matrix* transform);
|
||||||
bool strokeParseOutline(SwStroke* stroke, const SwOutline& outline);
|
bool strokeParseOutline(SwStroke* stroke, const SwOutline& outline);
|
||||||
SwOutline* strokeExportOutline(SwStroke* stroke, SwMpool* mpool, unsigned tid);
|
SwOutline* strokeExportOutline(SwStroke* stroke, SwMpool* mpool, unsigned tid);
|
||||||
void strokeFree(SwStroke* stroke);
|
void strokeFree(SwStroke* stroke);
|
||||||
|
|
|
@ -72,7 +72,7 @@ struct SwTask : Task
|
||||||
struct SwShapeTask : SwTask
|
struct SwShapeTask : SwTask
|
||||||
{
|
{
|
||||||
SwShape shape;
|
SwShape shape;
|
||||||
const Shape* sdata = nullptr;
|
const RenderShape* rshape = nullptr;
|
||||||
bool cmpStroking = false;
|
bool cmpStroking = false;
|
||||||
bool clipper = false;
|
bool clipper = false;
|
||||||
|
|
||||||
|
@ -85,9 +85,9 @@ struct SwShapeTask : SwTask
|
||||||
bool visibleFill = false;
|
bool visibleFill = false;
|
||||||
auto clipRegion = bbox;
|
auto clipRegion = bbox;
|
||||||
|
|
||||||
if (HALF_STROKE(sdata->strokeWidth()) > 0) {
|
if (HALF_STROKE(rshape->strokeWidth()) > 0) {
|
||||||
sdata->strokeColor(nullptr, nullptr, nullptr, &strokeAlpha);
|
rshape->strokeColor(nullptr, nullptr, nullptr, &strokeAlpha);
|
||||||
visibleStroke = sdata->strokeFill() || (static_cast<uint32_t>(strokeAlpha * opacity / 255) > 0);
|
visibleStroke = rshape->strokeFill() || (static_cast<uint32_t>(strokeAlpha * opacity / 255) > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
//This checks also for the case, if the invisible shape turned to visible by alpha.
|
//This checks also for the case, if the invisible shape turned to visible by alpha.
|
||||||
|
@ -97,12 +97,12 @@ struct SwShapeTask : SwTask
|
||||||
//Shape
|
//Shape
|
||||||
if (flags & (RenderUpdateFlag::Path | RenderUpdateFlag::Transform) || prepareShape) {
|
if (flags & (RenderUpdateFlag::Path | RenderUpdateFlag::Transform) || prepareShape) {
|
||||||
uint8_t alpha = 0;
|
uint8_t alpha = 0;
|
||||||
sdata->fillColor(nullptr, nullptr, nullptr, &alpha);
|
rshape->fillColor(nullptr, nullptr, nullptr, &alpha);
|
||||||
alpha = static_cast<uint8_t>(static_cast<uint32_t>(alpha) * opacity / 255);
|
alpha = static_cast<uint8_t>(static_cast<uint32_t>(alpha) * opacity / 255);
|
||||||
visibleFill = (alpha > 0 || sdata->fill());
|
visibleFill = (alpha > 0 || rshape->fill);
|
||||||
if (visibleFill || visibleStroke || clipper) {
|
if (visibleFill || visibleStroke || clipper) {
|
||||||
shapeReset(&shape);
|
shapeReset(&shape);
|
||||||
if (!shapePrepare(&shape, sdata, transform, clipRegion, bbox, mpool, tid, clips.count > 0 ? true : false)) goto err;
|
if (!shapePrepare(&shape, rshape, transform, clipRegion, bbox, mpool, tid, clips.count > 0 ? true : false)) goto err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -117,11 +117,11 @@ struct SwShapeTask : SwTask
|
||||||
shape outline below stroke could be full covered by stroke drawing.
|
shape outline below stroke could be full covered by stroke drawing.
|
||||||
Thus it turns off antialising in that condition.
|
Thus it turns off antialising in that condition.
|
||||||
Also, it shouldn't be dash style. */
|
Also, it shouldn't be dash style. */
|
||||||
auto antiAlias = (strokeAlpha == 255 && sdata->strokeWidth() > 2 && sdata->strokeDash(nullptr) == 0) ? false : true;
|
auto antiAlias = (strokeAlpha == 255 && rshape->strokeWidth() > 2 && rshape->strokeDash(nullptr) == 0) ? false : true;
|
||||||
|
|
||||||
if (!shapeGenRle(&shape, sdata, antiAlias)) goto err;
|
if (!shapeGenRle(&shape, rshape, antiAlias)) goto err;
|
||||||
}
|
}
|
||||||
if (auto fill = sdata->fill()) {
|
if (auto fill = rshape->fill) {
|
||||||
auto ctable = (flags & RenderUpdateFlag::Gradient) ? true : false;
|
auto ctable = (flags & RenderUpdateFlag::Gradient) ? true : false;
|
||||||
if (ctable) shapeResetFill(&shape);
|
if (ctable) shapeResetFill(&shape);
|
||||||
if (!shapeGenFillColors(&shape, fill, transform, surface, cmpStroking ? 255 : opacity, ctable)) goto err;
|
if (!shapeGenFillColors(&shape, fill, transform, surface, cmpStroking ? 255 : opacity, ctable)) goto err;
|
||||||
|
@ -133,10 +133,10 @@ struct SwShapeTask : SwTask
|
||||||
//Stroke
|
//Stroke
|
||||||
if (flags & (RenderUpdateFlag::Stroke | RenderUpdateFlag::Transform)) {
|
if (flags & (RenderUpdateFlag::Stroke | RenderUpdateFlag::Transform)) {
|
||||||
if (visibleStroke) {
|
if (visibleStroke) {
|
||||||
shapeResetStroke(&shape, sdata, transform);
|
shapeResetStroke(&shape, rshape, transform);
|
||||||
if (!shapeGenStrokeRle(&shape, sdata, transform, clipRegion, bbox, mpool, tid)) goto err;
|
if (!shapeGenStrokeRle(&shape, rshape, transform, clipRegion, bbox, mpool, tid)) goto err;
|
||||||
|
|
||||||
if (auto fill = sdata->strokeFill()) {
|
if (auto fill = rshape->strokeFill()) {
|
||||||
auto ctable = (flags & RenderUpdateFlag::GradientStroke) ? true : false;
|
auto ctable = (flags & RenderUpdateFlag::GradientStroke) ? true : false;
|
||||||
if (ctable) shapeResetStrokeFill(&shape);
|
if (ctable) shapeResetStrokeFill(&shape);
|
||||||
if (!shapeGenStrokeFillColors(&shape, fill, transform, surface, cmpStroking ? 255 : opacity, ctable)) goto err;
|
if (!shapeGenStrokeFillColors(&shape, fill, transform, surface, cmpStroking ? 255 : opacity, ctable)) goto err;
|
||||||
|
@ -397,18 +397,18 @@ bool SwRenderer::renderShape(RenderData data)
|
||||||
//Main raster stage
|
//Main raster stage
|
||||||
uint8_t r, g, b, a;
|
uint8_t r, g, b, a;
|
||||||
|
|
||||||
if (auto fill = task->sdata->fill()) {
|
if (auto fill = task->rshape->fill) {
|
||||||
rasterGradientShape(surface, &task->shape, fill->identifier());
|
rasterGradientShape(surface, &task->shape, fill->identifier());
|
||||||
} else {
|
} else {
|
||||||
task->sdata->fillColor(&r, &g, &b, &a);
|
task->rshape->fillColor(&r, &g, &b, &a);
|
||||||
a = static_cast<uint8_t>((opacity * (uint32_t) a) / 255);
|
a = static_cast<uint8_t>((opacity * (uint32_t) a) / 255);
|
||||||
if (a > 0) rasterShape(surface, &task->shape, r, g, b, a);
|
if (a > 0) rasterShape(surface, &task->shape, r, g, b, a);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto strokeFill = task->sdata->strokeFill()) {
|
if (auto strokeFill = task->rshape->strokeFill()) {
|
||||||
rasterGradientStroke(surface, &task->shape, strokeFill->identifier());
|
rasterGradientStroke(surface, &task->shape, strokeFill->identifier());
|
||||||
} else {
|
} else {
|
||||||
if (task->sdata->strokeColor(&r, &g, &b, &a) == Result::Success) {
|
if (task->rshape->strokeColor(&r, &g, &b, &a)) {
|
||||||
a = static_cast<uint8_t>((opacity * (uint32_t) a) / 255);
|
a = static_cast<uint8_t>((opacity * (uint32_t) a) / 255);
|
||||||
if (a > 0) rasterStroke(surface, &task->shape, r, g, b, a);
|
if (a > 0) rasterStroke(surface, &task->shape, r, g, b, a);
|
||||||
}
|
}
|
||||||
|
@ -643,13 +643,13 @@ RenderData SwRenderer::prepare(Surface* image, Polygon* triangles, uint32_t tria
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
RenderData SwRenderer::prepare(const Shape& sdata, RenderData data, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags, bool clipper)
|
RenderData SwRenderer::prepare(const RenderShape& rshape, RenderData data, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags, bool clipper)
|
||||||
{
|
{
|
||||||
//prepare task
|
//prepare task
|
||||||
auto task = static_cast<SwShapeTask*>(data);
|
auto task = static_cast<SwShapeTask*>(data);
|
||||||
if (!task) {
|
if (!task) {
|
||||||
task = new SwShapeTask;
|
task = new SwShapeTask;
|
||||||
task->sdata = &sdata;
|
task->rshape = &rshape;
|
||||||
task->clipper = clipper;
|
task->clipper = clipper;
|
||||||
}
|
}
|
||||||
return prepareCommon(task, transform, opacity, clips, flags);
|
return prepareCommon(task, transform, opacity, clips, flags);
|
||||||
|
|
|
@ -36,7 +36,7 @@ namespace tvg
|
||||||
class SwRenderer : public RenderMethod
|
class SwRenderer : public RenderMethod
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
RenderData prepare(const Shape& shape, RenderData data, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags, bool clipper) override;
|
RenderData prepare(const RenderShape& rshape, RenderData data, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags, bool clipper) override;
|
||||||
RenderData prepare(Surface* image, Polygon* triangles, uint32_t triangleCnt, RenderData data, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags) override;
|
RenderData prepare(Surface* image, Polygon* triangles, uint32_t triangleCnt, RenderData data, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags) override;
|
||||||
bool preRender() override;
|
bool preRender() override;
|
||||||
bool renderShape(RenderData data) override;
|
bool renderShape(RenderData data) override;
|
||||||
|
|
|
@ -267,13 +267,13 @@ static void _dashCubicTo(SwDashStroke& dash, const Point* ctrl1, const Point* ct
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static SwOutline* _genDashOutline(const Shape* sdata, const Matrix* transform)
|
static SwOutline* _genDashOutline(const RenderShape* rshape, const Matrix* transform)
|
||||||
{
|
{
|
||||||
const PathCommand* cmds = nullptr;
|
const PathCommand* cmds = rshape->path.cmds;
|
||||||
auto cmdCnt = sdata->pathCommands(&cmds);
|
auto cmdCnt = rshape->path.cmdCnt;
|
||||||
|
|
||||||
const Point* pts = nullptr;
|
const Point* pts = rshape->path.pts;
|
||||||
auto ptsCnt = sdata->pathCoords(&pts);
|
auto ptsCnt = rshape->path.ptsCnt;
|
||||||
|
|
||||||
//No actual shape data
|
//No actual shape data
|
||||||
if (cmdCnt == 0 || ptsCnt == 0) return nullptr;
|
if (cmdCnt == 0 || ptsCnt == 0) return nullptr;
|
||||||
|
@ -286,7 +286,7 @@ static SwOutline* _genDashOutline(const Shape* sdata, const Matrix* transform)
|
||||||
dash.curOpGap = false;
|
dash.curOpGap = false;
|
||||||
|
|
||||||
const float* pattern;
|
const float* pattern;
|
||||||
dash.cnt = sdata->strokeDash(&pattern);
|
dash.cnt = rshape->strokeDash(&pattern);
|
||||||
if (dash.cnt == 0) return nullptr;
|
if (dash.cnt == 0) return nullptr;
|
||||||
|
|
||||||
//OPTMIZE ME: Use mempool???
|
//OPTMIZE ME: Use mempool???
|
||||||
|
@ -381,13 +381,13 @@ static bool _axisAlignedRect(const SwOutline* outline)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static bool _genOutline(SwShape* shape, const Shape* sdata, const Matrix* transform, SwMpool* mpool, unsigned tid, bool hasComposite)
|
static bool _genOutline(SwShape* shape, const RenderShape* rshape, const Matrix* transform, SwMpool* mpool, unsigned tid, bool hasComposite)
|
||||||
{
|
{
|
||||||
const PathCommand* cmds = nullptr;
|
const PathCommand* cmds = rshape->path.cmds;
|
||||||
auto cmdCnt = sdata->pathCommands(&cmds);
|
auto cmdCnt = rshape->path.cmdCnt;
|
||||||
|
|
||||||
const Point* pts = nullptr;
|
const Point* pts = rshape->path.pts;
|
||||||
auto ptsCnt = sdata->pathCoords(&pts);
|
auto ptsCnt = rshape->path.ptsCnt;
|
||||||
|
|
||||||
//No actual shape data
|
//No actual shape data
|
||||||
if (cmdCnt == 0 || ptsCnt == 0) return false;
|
if (cmdCnt == 0 || ptsCnt == 0) return false;
|
||||||
|
@ -467,7 +467,7 @@ static bool _genOutline(SwShape* shape, const Shape* sdata, const Matrix* transf
|
||||||
|
|
||||||
_outlineEnd(*outline);
|
_outlineEnd(*outline);
|
||||||
|
|
||||||
outline->fillRule = sdata->fillRule();
|
outline->fillRule = rshape->rule;
|
||||||
shape->outline = outline;
|
shape->outline = outline;
|
||||||
|
|
||||||
shape->fastTrack = (!hasComposite && _axisAlignedRect(shape->outline));
|
shape->fastTrack = (!hasComposite && _axisAlignedRect(shape->outline));
|
||||||
|
@ -479,9 +479,9 @@ static bool _genOutline(SwShape* shape, const Shape* sdata, const Matrix* transf
|
||||||
/* External Class Implementation */
|
/* External Class Implementation */
|
||||||
/************************************************************************/
|
/************************************************************************/
|
||||||
|
|
||||||
bool shapePrepare(SwShape* shape, const Shape* sdata, const Matrix* transform, const SwBBox& clipRegion, SwBBox& renderRegion, SwMpool* mpool, unsigned tid, bool hasComposite)
|
bool shapePrepare(SwShape* shape, const RenderShape* rshape, const Matrix* transform, const SwBBox& clipRegion, SwBBox& renderRegion, SwMpool* mpool, unsigned tid, bool hasComposite)
|
||||||
{
|
{
|
||||||
if (!_genOutline(shape, sdata, transform, mpool, tid, hasComposite)) return false;
|
if (!_genOutline(shape, rshape, transform, mpool, tid, hasComposite)) return false;
|
||||||
if (!mathUpdateOutlineBBox(shape->outline, clipRegion, renderRegion, shape->fastTrack)) return false;
|
if (!mathUpdateOutlineBBox(shape->outline, clipRegion, renderRegion, shape->fastTrack)) return false;
|
||||||
|
|
||||||
//Keep it for Rasterization Region
|
//Keep it for Rasterization Region
|
||||||
|
@ -504,7 +504,7 @@ bool shapePrepared(const SwShape* shape)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool shapeGenRle(SwShape* shape, TVG_UNUSED const Shape* sdata, bool antiAlias)
|
bool shapeGenRle(SwShape* shape, TVG_UNUSED const RenderShape* rshape, bool antiAlias)
|
||||||
{
|
{
|
||||||
//FIXME: Should we draw it?
|
//FIXME: Should we draw it?
|
||||||
//Case: Stroke Line
|
//Case: Stroke Line
|
||||||
|
@ -558,18 +558,18 @@ void shapeDelStroke(SwShape* shape)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void shapeResetStroke(SwShape* shape, const Shape* sdata, const Matrix* transform)
|
void shapeResetStroke(SwShape* shape, const RenderShape* rshape, const Matrix* transform)
|
||||||
{
|
{
|
||||||
if (!shape->stroke) shape->stroke = static_cast<SwStroke*>(calloc(1, sizeof(SwStroke)));
|
if (!shape->stroke) shape->stroke = static_cast<SwStroke*>(calloc(1, sizeof(SwStroke)));
|
||||||
auto stroke = shape->stroke;
|
auto stroke = shape->stroke;
|
||||||
if (!stroke) return;
|
if (!stroke) return;
|
||||||
|
|
||||||
strokeReset(stroke, sdata, transform);
|
strokeReset(stroke, rshape, transform);
|
||||||
rleReset(shape->strokeRle);
|
rleReset(shape->strokeRle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool shapeGenStrokeRle(SwShape* shape, const Shape* sdata, const Matrix* transform, const SwBBox& clipRegion, SwBBox& renderRegion, SwMpool* mpool, unsigned tid)
|
bool shapeGenStrokeRle(SwShape* shape, const RenderShape* rshape, const Matrix* transform, const SwBBox& clipRegion, SwBBox& renderRegion, SwMpool* mpool, unsigned tid)
|
||||||
{
|
{
|
||||||
SwOutline* shapeOutline = nullptr;
|
SwOutline* shapeOutline = nullptr;
|
||||||
SwOutline* strokeOutline = nullptr;
|
SwOutline* strokeOutline = nullptr;
|
||||||
|
@ -577,14 +577,14 @@ bool shapeGenStrokeRle(SwShape* shape, const Shape* sdata, const Matrix* transfo
|
||||||
bool ret = true;
|
bool ret = true;
|
||||||
|
|
||||||
//Dash Style Stroke
|
//Dash Style Stroke
|
||||||
if (sdata->strokeDash(nullptr) > 0) {
|
if (rshape->strokeDash(nullptr) > 0) {
|
||||||
shapeOutline = _genDashOutline(sdata, transform);
|
shapeOutline = _genDashOutline(rshape, transform);
|
||||||
if (!shapeOutline) return false;
|
if (!shapeOutline) return false;
|
||||||
freeOutline = true;
|
freeOutline = true;
|
||||||
//Normal Style stroke
|
//Normal Style stroke
|
||||||
} else {
|
} else {
|
||||||
if (!shape->outline) {
|
if (!shape->outline) {
|
||||||
if (!_genOutline(shape, sdata, transform, mpool, tid, false)) return false;
|
if (!_genOutline(shape, rshape, transform, mpool, tid, false)) return false;
|
||||||
}
|
}
|
||||||
shapeOutline = shape->outline;
|
shapeOutline = shape->outline;
|
||||||
}
|
}
|
||||||
|
|
|
@ -826,7 +826,7 @@ void strokeFree(SwStroke* stroke)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void strokeReset(SwStroke* stroke, const Shape* sdata, const Matrix* transform)
|
void strokeReset(SwStroke* stroke, const RenderShape* rshape, const Matrix* transform)
|
||||||
{
|
{
|
||||||
if (transform) {
|
if (transform) {
|
||||||
stroke->sx = sqrtf(powf(transform->e11, 2.0f) + powf(transform->e21, 2.0f));
|
stroke->sx = sqrtf(powf(transform->e11, 2.0f) + powf(transform->e21, 2.0f));
|
||||||
|
@ -835,11 +835,11 @@ void strokeReset(SwStroke* stroke, const Shape* sdata, const Matrix* transform)
|
||||||
stroke->sx = stroke->sy = 1.0f;
|
stroke->sx = stroke->sy = 1.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
stroke->width = HALF_STROKE(sdata->strokeWidth());
|
stroke->width = HALF_STROKE(rshape->strokeWidth());
|
||||||
stroke->cap = sdata->strokeCap();
|
stroke->cap = rshape->strokeCap();
|
||||||
|
|
||||||
//Save line join: it can be temporarily changed when stroking curves...
|
//Save line join: it can be temporarily changed when stroking curves...
|
||||||
stroke->joinSaved = stroke->join = sdata->strokeJoin();
|
stroke->joinSaved = stroke->join = rshape->strokeJoin();
|
||||||
|
|
||||||
stroke->borders[0].ptsCnt = 0;
|
stroke->borders[0].ptsCnt = 0;
|
||||||
stroke->borders[0].start = -1;
|
stroke->borders[0].start = -1;
|
||||||
|
|
|
@ -85,12 +85,107 @@ struct RenderTransform
|
||||||
RenderTransform(const RenderTransform* lhs, const RenderTransform* rhs);
|
RenderTransform(const RenderTransform* lhs, const RenderTransform* rhs);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct RenderStroke
|
||||||
|
{
|
||||||
|
float width = 0.0f;
|
||||||
|
uint8_t color[4] = {0, 0, 0, 0};
|
||||||
|
Fill *fill = nullptr;
|
||||||
|
float* dashPattern = nullptr;
|
||||||
|
uint32_t dashCnt = 0;
|
||||||
|
StrokeCap cap = StrokeCap::Square;
|
||||||
|
StrokeJoin join = StrokeJoin::Bevel;
|
||||||
|
|
||||||
|
~RenderStroke()
|
||||||
|
{
|
||||||
|
free(dashPattern);
|
||||||
|
if (fill) delete(fill);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct RenderShape
|
||||||
|
{
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
PathCommand* cmds = nullptr;
|
||||||
|
uint32_t cmdCnt = 0;
|
||||||
|
uint32_t reservedCmdCnt = 0;
|
||||||
|
|
||||||
|
Point *pts = nullptr;
|
||||||
|
uint32_t ptsCnt = 0;
|
||||||
|
uint32_t reservedPtsCnt = 0;
|
||||||
|
} path;
|
||||||
|
|
||||||
|
Fill *fill = nullptr;
|
||||||
|
RenderStroke *stroke = nullptr;
|
||||||
|
uint8_t color[4] = {0, 0, 0, 0}; //r, g, b, a
|
||||||
|
FillRule rule = FillRule::Winding;
|
||||||
|
|
||||||
|
~RenderShape()
|
||||||
|
{
|
||||||
|
free(path.cmds);
|
||||||
|
free(path.pts);
|
||||||
|
|
||||||
|
if (fill) delete(fill);
|
||||||
|
if (stroke) delete(stroke);
|
||||||
|
}
|
||||||
|
|
||||||
|
void fillColor(uint8_t* r, uint8_t* g, uint8_t* b, uint8_t* a) const
|
||||||
|
{
|
||||||
|
if (r) *r = color[0];
|
||||||
|
if (g) *g = color[1];
|
||||||
|
if (b) *b = color[2];
|
||||||
|
if (a) *a = color[3];
|
||||||
|
}
|
||||||
|
|
||||||
|
float strokeWidth() const
|
||||||
|
{
|
||||||
|
if (!stroke) return 0;
|
||||||
|
return stroke->width;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool strokeColor(uint8_t* r, uint8_t* g, uint8_t* b, uint8_t* a) const
|
||||||
|
{
|
||||||
|
if (!stroke) return false;
|
||||||
|
|
||||||
|
if (r) *r = stroke->color[0];
|
||||||
|
if (g) *g = stroke->color[1];
|
||||||
|
if (b) *b = stroke->color[2];
|
||||||
|
if (a) *a = stroke->color[3];
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Fill* strokeFill() const
|
||||||
|
{
|
||||||
|
if (!stroke) return nullptr;
|
||||||
|
return stroke->fill;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t strokeDash(const float** dashPattern) const
|
||||||
|
{
|
||||||
|
if (!stroke) return 0;
|
||||||
|
if (dashPattern) *dashPattern = stroke->dashPattern;
|
||||||
|
return stroke->dashCnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
StrokeCap strokeCap() const
|
||||||
|
{
|
||||||
|
if (!stroke) return StrokeCap::Square;
|
||||||
|
return stroke->cap;
|
||||||
|
}
|
||||||
|
|
||||||
|
StrokeJoin strokeJoin() const
|
||||||
|
{
|
||||||
|
if (!stroke) return StrokeJoin::Bevel;
|
||||||
|
return stroke->join;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
class RenderMethod
|
class RenderMethod
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual ~RenderMethod() {}
|
virtual ~RenderMethod() {}
|
||||||
virtual RenderData prepare(const Shape& shape, RenderData data, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags, bool clipper) = 0;
|
virtual RenderData prepare(const RenderShape& rshape, RenderData data, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags, bool clipper) = 0;
|
||||||
virtual RenderData prepare(Surface* image, Polygon* triangles, uint32_t triangleCnt, RenderData data, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags) = 0;
|
virtual RenderData prepare(Surface* image, Polygon* triangles, uint32_t triangleCnt, RenderData data, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags) = 0;
|
||||||
virtual bool preRender() = 0;
|
virtual bool preRender() = 0;
|
||||||
virtual bool renderShape(RenderData data) = 0;
|
virtual bool renderShape(RenderData data) = 0;
|
||||||
|
|
|
@ -32,7 +32,7 @@ constexpr auto PATH_KAPPA = 0.552284f;
|
||||||
/* External Class Implementation */
|
/* External Class Implementation */
|
||||||
/************************************************************************/
|
/************************************************************************/
|
||||||
|
|
||||||
Shape :: Shape() : pImpl(new Impl(this))
|
Shape :: Shape() : pImpl(new Impl())
|
||||||
{
|
{
|
||||||
Paint::pImpl->id = TVG_CLASS_ID_SHAPE;
|
Paint::pImpl->id = TVG_CLASS_ID_SHAPE;
|
||||||
Paint::pImpl->method(new PaintMethod<Shape::Impl>(pImpl));
|
Paint::pImpl->method(new PaintMethod<Shape::Impl>(pImpl));
|
||||||
|
@ -59,8 +59,7 @@ uint32_t Shape::identifier() noexcept
|
||||||
|
|
||||||
Result Shape::reset() noexcept
|
Result Shape::reset() noexcept
|
||||||
{
|
{
|
||||||
pImpl->path.reset();
|
pImpl->reset();
|
||||||
pImpl->flag = RenderUpdateFlag::Path;
|
|
||||||
|
|
||||||
return Result::Success;
|
return Result::Success;
|
||||||
}
|
}
|
||||||
|
@ -70,9 +69,9 @@ uint32_t Shape::pathCommands(const PathCommand** cmds) const noexcept
|
||||||
{
|
{
|
||||||
if (!cmds) return 0;
|
if (!cmds) return 0;
|
||||||
|
|
||||||
*cmds = pImpl->path.cmds;
|
*cmds = pImpl->rs.path.cmds;
|
||||||
|
|
||||||
return pImpl->path.cmdCnt;
|
return pImpl->rs.path.cmdCnt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -80,9 +79,9 @@ uint32_t Shape::pathCoords(const Point** pts) const noexcept
|
||||||
{
|
{
|
||||||
if (!pts) return 0;
|
if (!pts) return 0;
|
||||||
|
|
||||||
*pts = pImpl->path.pts;
|
*pts = pImpl->rs.path.pts;
|
||||||
|
|
||||||
return pImpl->path.ptsCnt;
|
return pImpl->rs.path.ptsCnt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -90,10 +89,8 @@ Result Shape::appendPath(const PathCommand *cmds, uint32_t cmdCnt, const Point*
|
||||||
{
|
{
|
||||||
if (cmdCnt == 0 || ptsCnt == 0 || !cmds || !pts) return Result::InvalidArguments;
|
if (cmdCnt == 0 || ptsCnt == 0 || !cmds || !pts) return Result::InvalidArguments;
|
||||||
|
|
||||||
pImpl->path.grow(cmdCnt, ptsCnt);
|
pImpl->grow(cmdCnt, ptsCnt);
|
||||||
pImpl->path.append(cmds, cmdCnt, pts, ptsCnt);
|
pImpl->append(cmds, cmdCnt, pts, ptsCnt);
|
||||||
|
|
||||||
pImpl->flag |= RenderUpdateFlag::Path;
|
|
||||||
|
|
||||||
return Result::Success;
|
return Result::Success;
|
||||||
}
|
}
|
||||||
|
@ -101,9 +98,7 @@ Result Shape::appendPath(const PathCommand *cmds, uint32_t cmdCnt, const Point*
|
||||||
|
|
||||||
Result Shape::moveTo(float x, float y) noexcept
|
Result Shape::moveTo(float x, float y) noexcept
|
||||||
{
|
{
|
||||||
pImpl->path.moveTo(x, y);
|
pImpl->moveTo(x, y);
|
||||||
|
|
||||||
pImpl->flag |= RenderUpdateFlag::Path;
|
|
||||||
|
|
||||||
return Result::Success;
|
return Result::Success;
|
||||||
}
|
}
|
||||||
|
@ -111,9 +106,7 @@ Result Shape::moveTo(float x, float y) noexcept
|
||||||
|
|
||||||
Result Shape::lineTo(float x, float y) noexcept
|
Result Shape::lineTo(float x, float y) noexcept
|
||||||
{
|
{
|
||||||
pImpl->path.lineTo(x, y);
|
pImpl->lineTo(x, y);
|
||||||
|
|
||||||
pImpl->flag |= RenderUpdateFlag::Path;
|
|
||||||
|
|
||||||
return Result::Success;
|
return Result::Success;
|
||||||
}
|
}
|
||||||
|
@ -121,9 +114,7 @@ Result Shape::lineTo(float x, float y) noexcept
|
||||||
|
|
||||||
Result Shape::cubicTo(float cx1, float cy1, float cx2, float cy2, float x, float y) noexcept
|
Result Shape::cubicTo(float cx1, float cy1, float cx2, float cy2, float x, float y) noexcept
|
||||||
{
|
{
|
||||||
pImpl->path.cubicTo(cx1, cy1, cx2, cy2, x, y);
|
pImpl->cubicTo(cx1, cy1, cx2, cy2, x, y);
|
||||||
|
|
||||||
pImpl->flag |= RenderUpdateFlag::Path;
|
|
||||||
|
|
||||||
return Result::Success;
|
return Result::Success;
|
||||||
}
|
}
|
||||||
|
@ -131,9 +122,7 @@ Result Shape::cubicTo(float cx1, float cy1, float cx2, float cy2, float x, float
|
||||||
|
|
||||||
Result Shape::close() noexcept
|
Result Shape::close() noexcept
|
||||||
{
|
{
|
||||||
pImpl->path.close();
|
pImpl->close();
|
||||||
|
|
||||||
pImpl->flag |= RenderUpdateFlag::Path;
|
|
||||||
|
|
||||||
return Result::Success;
|
return Result::Success;
|
||||||
}
|
}
|
||||||
|
@ -144,15 +133,13 @@ Result Shape::appendCircle(float cx, float cy, float rx, float ry) noexcept
|
||||||
auto rxKappa = rx * PATH_KAPPA;
|
auto rxKappa = rx * PATH_KAPPA;
|
||||||
auto ryKappa = ry * PATH_KAPPA;
|
auto ryKappa = ry * PATH_KAPPA;
|
||||||
|
|
||||||
pImpl->path.grow(6, 13);
|
pImpl->grow(6, 13);
|
||||||
pImpl->path.moveTo(cx, cy - ry);
|
pImpl->moveTo(cx, cy - ry);
|
||||||
pImpl->path.cubicTo(cx + rxKappa, cy - ry, cx + rx, cy - ryKappa, cx + rx, cy);
|
pImpl->cubicTo(cx + rxKappa, cy - ry, cx + rx, cy - ryKappa, cx + rx, cy);
|
||||||
pImpl->path.cubicTo(cx + rx, cy + ryKappa, cx + rxKappa, cy + ry, cx, cy + ry);
|
pImpl->cubicTo(cx + rx, cy + ryKappa, cx + rxKappa, cy + ry, cx, cy + ry);
|
||||||
pImpl->path.cubicTo(cx - rxKappa, cy + ry, cx - rx, cy + ryKappa, cx - rx, cy);
|
pImpl->cubicTo(cx - rxKappa, cy + ry, cx - rx, cy + ryKappa, cx - rx, cy);
|
||||||
pImpl->path.cubicTo(cx - rx, cy - ryKappa, cx - rxKappa, cy - ry, cx, cy - ry);
|
pImpl->cubicTo(cx - rx, cy - ryKappa, cx - rxKappa, cy - ry, cx, cy - ry);
|
||||||
pImpl->path.close();
|
pImpl->close();
|
||||||
|
|
||||||
pImpl->flag |= RenderUpdateFlag::Path;
|
|
||||||
|
|
||||||
return Result::Success;
|
return Result::Success;
|
||||||
}
|
}
|
||||||
|
@ -174,10 +161,10 @@ Result Shape::appendArc(float cx, float cy, float radius, float startAngle, floa
|
||||||
Point start = {radius * cosf(startAngle), radius * sinf(startAngle)};
|
Point start = {radius * cosf(startAngle), radius * sinf(startAngle)};
|
||||||
|
|
||||||
if (pie) {
|
if (pie) {
|
||||||
pImpl->path.moveTo(cx, cy);
|
pImpl->moveTo(cx, cy);
|
||||||
pImpl->path.lineTo(start.x + cx, start.y + cy);
|
pImpl->lineTo(start.x + cx, start.y + cy);
|
||||||
} else {
|
} else {
|
||||||
pImpl->path.moveTo(start.x + cx, start.y + cy);
|
pImpl->moveTo(start.x + cx, start.y + cy);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < nCurves; ++i) {
|
for (int i = 0; i < nCurves; ++i) {
|
||||||
|
@ -204,14 +191,12 @@ Result Shape::appendArc(float cx, float cy, float radius, float startAngle, floa
|
||||||
Point ctrl1 = {ax - k2 * ay + cx, ay + k2 * ax + cy};
|
Point ctrl1 = {ax - k2 * ay + cx, ay + k2 * ax + cy};
|
||||||
Point ctrl2 = {bx + k2 * by + cx, by - k2 * bx + cy};
|
Point ctrl2 = {bx + k2 * by + cx, by - k2 * bx + cy};
|
||||||
|
|
||||||
pImpl->path.cubicTo(ctrl1.x, ctrl1.y, ctrl2.x, ctrl2.y, end.x, end.y);
|
pImpl->cubicTo(ctrl1.x, ctrl1.y, ctrl2.x, ctrl2.y, end.x, end.y);
|
||||||
|
|
||||||
startAngle = endAngle;
|
startAngle = endAngle;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pie) pImpl->path.close();
|
if (pie) pImpl->close();
|
||||||
|
|
||||||
pImpl->flag |= RenderUpdateFlag::Path;
|
|
||||||
|
|
||||||
return Result::Success;
|
return Result::Success;
|
||||||
}
|
}
|
||||||
|
@ -228,48 +213,46 @@ Result Shape::appendRect(float x, float y, float w, float h, float rx, float ry)
|
||||||
|
|
||||||
//rectangle
|
//rectangle
|
||||||
if (rx == 0 && ry == 0) {
|
if (rx == 0 && ry == 0) {
|
||||||
pImpl->path.grow(5, 4);
|
pImpl->grow(5, 4);
|
||||||
pImpl->path.moveTo(x, y);
|
pImpl->moveTo(x, y);
|
||||||
pImpl->path.lineTo(x + w, y);
|
pImpl->lineTo(x + w, y);
|
||||||
pImpl->path.lineTo(x + w, y + h);
|
pImpl->lineTo(x + w, y + h);
|
||||||
pImpl->path.lineTo(x, y + h);
|
pImpl->lineTo(x, y + h);
|
||||||
pImpl->path.close();
|
pImpl->close();
|
||||||
//circle
|
//circle
|
||||||
} else if (mathEqual(rx, halfW) && mathEqual(ry, halfH)) {
|
} else if (mathEqual(rx, halfW) && mathEqual(ry, halfH)) {
|
||||||
return appendCircle(x + (w * 0.5f), y + (h * 0.5f), rx, ry);
|
return appendCircle(x + (w * 0.5f), y + (h * 0.5f), rx, ry);
|
||||||
} else {
|
} else {
|
||||||
auto hrx = rx * 0.5f;
|
auto hrx = rx * 0.5f;
|
||||||
auto hry = ry * 0.5f;
|
auto hry = ry * 0.5f;
|
||||||
pImpl->path.grow(10, 17);
|
pImpl->grow(10, 17);
|
||||||
pImpl->path.moveTo(x + rx, y);
|
pImpl->moveTo(x + rx, y);
|
||||||
pImpl->path.lineTo(x + w - rx, y);
|
pImpl->lineTo(x + w - rx, y);
|
||||||
pImpl->path.cubicTo(x + w - rx + hrx, y, x + w, y + ry - hry, x + w, y + ry);
|
pImpl->cubicTo(x + w - rx + hrx, y, x + w, y + ry - hry, x + w, y + ry);
|
||||||
pImpl->path.lineTo(x + w, y + h - ry);
|
pImpl->lineTo(x + w, y + h - ry);
|
||||||
pImpl->path.cubicTo(x + w, y + h - ry + hry, x + w - rx + hrx, y + h, x + w - rx, y + h);
|
pImpl->cubicTo(x + w, y + h - ry + hry, x + w - rx + hrx, y + h, x + w - rx, y + h);
|
||||||
pImpl->path.lineTo(x + rx, y + h);
|
pImpl->lineTo(x + rx, y + h);
|
||||||
pImpl->path.cubicTo(x + rx - hrx, y + h, x, y + h - ry + hry, x, y + h - ry);
|
pImpl->cubicTo(x + rx - hrx, y + h, x, y + h - ry + hry, x, y + h - ry);
|
||||||
pImpl->path.lineTo(x, y + ry);
|
pImpl->lineTo(x, y + ry);
|
||||||
pImpl->path.cubicTo(x, y + ry - hry, x + rx - hrx, y, x + rx, y);
|
pImpl->cubicTo(x, y + ry - hry, x + rx - hrx, y, x + rx, y);
|
||||||
pImpl->path.close();
|
pImpl->close();
|
||||||
}
|
}
|
||||||
|
|
||||||
pImpl->flag |= RenderUpdateFlag::Path;
|
|
||||||
|
|
||||||
return Result::Success;
|
return Result::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Result Shape::fill(uint8_t r, uint8_t g, uint8_t b, uint8_t a) noexcept
|
Result Shape::fill(uint8_t r, uint8_t g, uint8_t b, uint8_t a) noexcept
|
||||||
{
|
{
|
||||||
pImpl->color[0] = r;
|
pImpl->rs.color[0] = r;
|
||||||
pImpl->color[1] = g;
|
pImpl->rs.color[1] = g;
|
||||||
pImpl->color[2] = b;
|
pImpl->rs.color[2] = b;
|
||||||
pImpl->color[3] = a;
|
pImpl->rs.color[3] = a;
|
||||||
pImpl->flag |= RenderUpdateFlag::Color;
|
pImpl->flag |= RenderUpdateFlag::Color;
|
||||||
|
|
||||||
if (pImpl->fill) {
|
if (pImpl->rs.fill) {
|
||||||
delete(pImpl->fill);
|
delete(pImpl->rs.fill);
|
||||||
pImpl->fill = nullptr;
|
pImpl->rs.fill = nullptr;
|
||||||
pImpl->flag |= RenderUpdateFlag::Gradient;
|
pImpl->flag |= RenderUpdateFlag::Gradient;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -282,8 +265,8 @@ Result Shape::fill(unique_ptr<Fill> f) noexcept
|
||||||
auto p = f.release();
|
auto p = f.release();
|
||||||
if (!p) return Result::MemoryCorruption;
|
if (!p) return Result::MemoryCorruption;
|
||||||
|
|
||||||
if (pImpl->fill && pImpl->fill != p) delete(pImpl->fill);
|
if (pImpl->rs.fill && pImpl->rs.fill != p) delete(pImpl->rs.fill);
|
||||||
pImpl->fill = p;
|
pImpl->rs.fill = p;
|
||||||
pImpl->flag |= RenderUpdateFlag::Gradient;
|
pImpl->flag |= RenderUpdateFlag::Gradient;
|
||||||
|
|
||||||
return Result::Success;
|
return Result::Success;
|
||||||
|
@ -292,17 +275,15 @@ Result Shape::fill(unique_ptr<Fill> f) noexcept
|
||||||
|
|
||||||
Result Shape::fillColor(uint8_t* r, uint8_t* g, uint8_t* b, uint8_t* a) const noexcept
|
Result Shape::fillColor(uint8_t* r, uint8_t* g, uint8_t* b, uint8_t* a) const noexcept
|
||||||
{
|
{
|
||||||
if (r) *r = pImpl->color[0];
|
pImpl->rs.fillColor(r, g, b, a);
|
||||||
if (g) *g = pImpl->color[1];
|
|
||||||
if (b) *b = pImpl->color[2];
|
|
||||||
if (a) *a = pImpl->color[3];
|
|
||||||
|
|
||||||
return Result::Success;
|
return Result::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const Fill* Shape::fill() const noexcept
|
const Fill* Shape::fill() const noexcept
|
||||||
{
|
{
|
||||||
return pImpl->fill;
|
return pImpl->rs.fill;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -316,8 +297,7 @@ Result Shape::stroke(float width) noexcept
|
||||||
|
|
||||||
float Shape::strokeWidth() const noexcept
|
float Shape::strokeWidth() const noexcept
|
||||||
{
|
{
|
||||||
if (!pImpl->stroke) return 0;
|
return pImpl->rs.strokeWidth();
|
||||||
return pImpl->stroke->width;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -331,12 +311,7 @@ Result Shape::stroke(uint8_t r, uint8_t g, uint8_t b, uint8_t a) noexcept
|
||||||
|
|
||||||
Result Shape::strokeColor(uint8_t* r, uint8_t* g, uint8_t* b, uint8_t* a) const noexcept
|
Result Shape::strokeColor(uint8_t* r, uint8_t* g, uint8_t* b, uint8_t* a) const noexcept
|
||||||
{
|
{
|
||||||
if (!pImpl->stroke) return Result::InsufficientCondition;
|
if (!pImpl->rs.strokeColor(r, g, b, a)) return Result::InsufficientCondition;
|
||||||
|
|
||||||
if (r) *r = pImpl->stroke->color[0];
|
|
||||||
if (g) *g = pImpl->stroke->color[1];
|
|
||||||
if (b) *b = pImpl->stroke->color[2];
|
|
||||||
if (a) *a = pImpl->stroke->color[3];
|
|
||||||
|
|
||||||
return Result::Success;
|
return Result::Success;
|
||||||
}
|
}
|
||||||
|
@ -350,9 +325,7 @@ Result Shape::stroke(unique_ptr<Fill> f) noexcept
|
||||||
|
|
||||||
const Fill* Shape::strokeFill() const noexcept
|
const Fill* Shape::strokeFill() const noexcept
|
||||||
{
|
{
|
||||||
if (!pImpl->stroke) return nullptr;
|
return pImpl->rs.strokeFill();
|
||||||
|
|
||||||
return pImpl->stroke->fill;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -373,11 +346,7 @@ Result Shape::stroke(const float* dashPattern, uint32_t cnt) noexcept
|
||||||
|
|
||||||
uint32_t Shape::strokeDash(const float** dashPattern) const noexcept
|
uint32_t Shape::strokeDash(const float** dashPattern) const noexcept
|
||||||
{
|
{
|
||||||
if (!pImpl->stroke) return 0;
|
return pImpl->rs.strokeDash(dashPattern);
|
||||||
|
|
||||||
if (dashPattern) *dashPattern = pImpl->stroke->dashPattern;
|
|
||||||
|
|
||||||
return pImpl->stroke->dashCnt;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -399,23 +368,19 @@ Result Shape::stroke(StrokeJoin join) noexcept
|
||||||
|
|
||||||
StrokeCap Shape::strokeCap() const noexcept
|
StrokeCap Shape::strokeCap() const noexcept
|
||||||
{
|
{
|
||||||
if (!pImpl->stroke) return StrokeCap::Square;
|
return pImpl->rs.strokeCap();
|
||||||
|
|
||||||
return pImpl->stroke->cap;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
StrokeJoin Shape::strokeJoin() const noexcept
|
StrokeJoin Shape::strokeJoin() const noexcept
|
||||||
{
|
{
|
||||||
if (!pImpl->stroke) return StrokeJoin::Bevel;
|
return pImpl->rs.strokeJoin();
|
||||||
|
|
||||||
return pImpl->stroke->join;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Result Shape::fill(FillRule r) noexcept
|
Result Shape::fill(FillRule r) noexcept
|
||||||
{
|
{
|
||||||
pImpl->rule = r;
|
pImpl->rs.rule = r;
|
||||||
|
|
||||||
return Result::Success;
|
return Result::Success;
|
||||||
}
|
}
|
||||||
|
@ -423,5 +388,5 @@ Result Shape::fill(FillRule r) noexcept
|
||||||
|
|
||||||
FillRule Shape::fillRule() const noexcept
|
FillRule Shape::fillRule() const noexcept
|
||||||
{
|
{
|
||||||
return pImpl->rule;
|
return pImpl->rs.rule;
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,199 +30,12 @@
|
||||||
/* Internal Class Implementation */
|
/* Internal Class Implementation */
|
||||||
/************************************************************************/
|
/************************************************************************/
|
||||||
|
|
||||||
struct ShapeStroke
|
|
||||||
{
|
|
||||||
float width;
|
|
||||||
uint8_t color[4];
|
|
||||||
Fill *fill;
|
|
||||||
float* dashPattern;
|
|
||||||
uint32_t dashCnt;
|
|
||||||
StrokeCap cap;
|
|
||||||
StrokeJoin join;
|
|
||||||
|
|
||||||
void copy(const ShapeStroke* src)
|
|
||||||
{
|
|
||||||
width = src->width;
|
|
||||||
dashCnt = src->dashCnt;
|
|
||||||
cap = src->cap;
|
|
||||||
join = src->join;
|
|
||||||
|
|
||||||
memcpy(color, src->color, sizeof(color));
|
|
||||||
if (dashCnt > 0) {
|
|
||||||
dashPattern = static_cast<float*>(malloc(sizeof(float) * dashCnt));
|
|
||||||
memcpy(dashPattern, src->dashPattern, sizeof(float) * dashCnt);
|
|
||||||
}
|
|
||||||
if (src->fill) fill = src->fill->duplicate();
|
|
||||||
}
|
|
||||||
|
|
||||||
void clear()
|
|
||||||
{
|
|
||||||
if (dashPattern) free(dashPattern);
|
|
||||||
if (fill) delete(fill);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
struct ShapePath
|
|
||||||
{
|
|
||||||
PathCommand* cmds = nullptr;
|
|
||||||
uint32_t cmdCnt = 0;
|
|
||||||
uint32_t reservedCmdCnt = 0;
|
|
||||||
|
|
||||||
Point *pts = nullptr;
|
|
||||||
uint32_t ptsCnt = 0;
|
|
||||||
uint32_t reservedPtsCnt = 0;
|
|
||||||
|
|
||||||
~ShapePath()
|
|
||||||
{
|
|
||||||
if (cmds) free(cmds);
|
|
||||||
if (pts) free(pts);
|
|
||||||
}
|
|
||||||
|
|
||||||
ShapePath()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void duplicate(const ShapePath* src)
|
|
||||||
{
|
|
||||||
if (src->cmdCnt == 0 || src->ptsCnt == 0) return;
|
|
||||||
|
|
||||||
cmdCnt = src->cmdCnt;
|
|
||||||
reservedCmdCnt = src->reservedCmdCnt;
|
|
||||||
ptsCnt = src->ptsCnt;
|
|
||||||
reservedPtsCnt = src->reservedPtsCnt;
|
|
||||||
|
|
||||||
cmds = static_cast<PathCommand*>(malloc(sizeof(PathCommand) * reservedCmdCnt));
|
|
||||||
if (!cmds) return;
|
|
||||||
memcpy(cmds, src->cmds, sizeof(PathCommand) * cmdCnt);
|
|
||||||
|
|
||||||
pts = static_cast<Point*>(malloc(sizeof(Point) * reservedPtsCnt));
|
|
||||||
if (!pts) {
|
|
||||||
free(cmds);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
memcpy(pts, src->pts, sizeof(Point) * ptsCnt);
|
|
||||||
}
|
|
||||||
|
|
||||||
void reserveCmd(uint32_t cmdCnt)
|
|
||||||
{
|
|
||||||
if (cmdCnt <= reservedCmdCnt) return;
|
|
||||||
reservedCmdCnt = cmdCnt;
|
|
||||||
cmds = static_cast<PathCommand*>(realloc(cmds, sizeof(PathCommand) * reservedCmdCnt));
|
|
||||||
}
|
|
||||||
|
|
||||||
void reservePts(uint32_t ptsCnt)
|
|
||||||
{
|
|
||||||
if (ptsCnt <= reservedPtsCnt) return;
|
|
||||||
reservedPtsCnt = ptsCnt;
|
|
||||||
pts = static_cast<Point*>(realloc(pts, sizeof(Point) * reservedPtsCnt));
|
|
||||||
}
|
|
||||||
|
|
||||||
void grow(uint32_t cmdCnt, uint32_t ptsCnt)
|
|
||||||
{
|
|
||||||
reserveCmd(this->cmdCnt + cmdCnt);
|
|
||||||
reservePts(this->ptsCnt + ptsCnt);
|
|
||||||
}
|
|
||||||
|
|
||||||
void reset()
|
|
||||||
{
|
|
||||||
cmdCnt = 0;
|
|
||||||
ptsCnt = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void append(const PathCommand* cmds, uint32_t cmdCnt, const Point* pts, uint32_t ptsCnt)
|
|
||||||
{
|
|
||||||
memcpy(this->cmds + this->cmdCnt, cmds, sizeof(PathCommand) * cmdCnt);
|
|
||||||
memcpy(this->pts + this->ptsCnt, pts, sizeof(Point) * ptsCnt);
|
|
||||||
this->cmdCnt += cmdCnt;
|
|
||||||
this->ptsCnt += ptsCnt;
|
|
||||||
}
|
|
||||||
|
|
||||||
void moveTo(float x, float y)
|
|
||||||
{
|
|
||||||
if (cmdCnt + 1 > reservedCmdCnt) reserveCmd((cmdCnt + 1) * 2);
|
|
||||||
if (ptsCnt + 2 > reservedPtsCnt) reservePts((ptsCnt + 2) * 2);
|
|
||||||
|
|
||||||
cmds[cmdCnt++] = PathCommand::MoveTo;
|
|
||||||
pts[ptsCnt++] = {x, y};
|
|
||||||
}
|
|
||||||
|
|
||||||
void lineTo(float x, float y)
|
|
||||||
{
|
|
||||||
if (cmdCnt + 1 > reservedCmdCnt) reserveCmd((cmdCnt + 1) * 2);
|
|
||||||
if (ptsCnt + 2 > reservedPtsCnt) reservePts((ptsCnt + 2) * 2);
|
|
||||||
|
|
||||||
cmds[cmdCnt++] = PathCommand::LineTo;
|
|
||||||
pts[ptsCnt++] = {x, y};
|
|
||||||
}
|
|
||||||
|
|
||||||
void cubicTo(float cx1, float cy1, float cx2, float cy2, float x, float y)
|
|
||||||
{
|
|
||||||
if (cmdCnt + 1 > reservedCmdCnt) reserveCmd((cmdCnt + 1) * 2);
|
|
||||||
if (ptsCnt + 3 > reservedPtsCnt) reservePts((ptsCnt + 3) * 2);
|
|
||||||
|
|
||||||
cmds[cmdCnt++] = PathCommand::CubicTo;
|
|
||||||
pts[ptsCnt++] = {cx1, cy1};
|
|
||||||
pts[ptsCnt++] = {cx2, cy2};
|
|
||||||
pts[ptsCnt++] = {x, y};
|
|
||||||
}
|
|
||||||
|
|
||||||
void close()
|
|
||||||
{
|
|
||||||
if (cmdCnt > 0 && cmds[cmdCnt - 1] == PathCommand::Close) return;
|
|
||||||
|
|
||||||
if (cmdCnt + 1 > reservedCmdCnt) reserveCmd((cmdCnt + 1) * 2);
|
|
||||||
cmds[cmdCnt++] = PathCommand::Close;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool bounds(float* x, float* y, float* w, float* h) const
|
|
||||||
{
|
|
||||||
if (ptsCnt == 0) return false;
|
|
||||||
|
|
||||||
Point min = { pts[0].x, pts[0].y };
|
|
||||||
Point max = { pts[0].x, pts[0].y };
|
|
||||||
|
|
||||||
for (uint32_t i = 1; i < ptsCnt; ++i) {
|
|
||||||
if (pts[i].x < min.x) min.x = pts[i].x;
|
|
||||||
if (pts[i].y < min.y) min.y = pts[i].y;
|
|
||||||
if (pts[i].x > max.x) max.x = pts[i].x;
|
|
||||||
if (pts[i].y > max.y) max.y = pts[i].y;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (x) *x = min.x;
|
|
||||||
if (y) *y = min.y;
|
|
||||||
if (w) *w = max.x - min.x;
|
|
||||||
if (h) *h = max.y - min.y;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
struct Shape::Impl
|
struct Shape::Impl
|
||||||
{
|
{
|
||||||
ShapePath path;
|
RenderShape rs; //shape data
|
||||||
Fill *fill = nullptr;
|
|
||||||
ShapeStroke *stroke = nullptr;
|
|
||||||
uint8_t color[4] = {0, 0, 0, 0}; //r, g, b, a
|
|
||||||
FillRule rule = FillRule::Winding;
|
|
||||||
RenderData rdata = nullptr; //engine data
|
RenderData rdata = nullptr; //engine data
|
||||||
Shape *shape = nullptr;
|
|
||||||
uint32_t flag = RenderUpdateFlag::None;
|
uint32_t flag = RenderUpdateFlag::None;
|
||||||
|
|
||||||
Impl(Shape* s) : shape(s)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
~Impl()
|
|
||||||
{
|
|
||||||
if (fill) delete(fill);
|
|
||||||
if (stroke) {
|
|
||||||
stroke->clear();
|
|
||||||
free (stroke);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool dispose(RenderMethod& renderer)
|
bool dispose(RenderMethod& renderer)
|
||||||
{
|
{
|
||||||
auto ret = renderer.dispose(rdata);
|
auto ret = renderer.dispose(rdata);
|
||||||
|
@ -237,9 +50,9 @@ struct Shape::Impl
|
||||||
|
|
||||||
void* update(RenderMethod& renderer, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag pFlag, bool clipper)
|
void* update(RenderMethod& renderer, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag pFlag, bool clipper)
|
||||||
{
|
{
|
||||||
this->rdata = renderer.prepare(*shape, this->rdata, transform, opacity, clips, static_cast<RenderUpdateFlag>(pFlag | flag), clipper);
|
rdata = renderer.prepare(rs, rdata, transform, opacity, clips, static_cast<RenderUpdateFlag>(pFlag | flag), clipper);
|
||||||
flag = RenderUpdateFlag::None;
|
flag = RenderUpdateFlag::None;
|
||||||
return this->rdata;
|
return rdata;
|
||||||
}
|
}
|
||||||
|
|
||||||
RenderRegion bounds(RenderMethod& renderer)
|
RenderRegion bounds(RenderMethod& renderer)
|
||||||
|
@ -249,24 +62,123 @@ struct Shape::Impl
|
||||||
|
|
||||||
bool bounds(float* x, float* y, float* w, float* h)
|
bool bounds(float* x, float* y, float* w, float* h)
|
||||||
{
|
{
|
||||||
auto ret = path.bounds(x, y, w, h);
|
//Path bounding size
|
||||||
|
if (rs.path.ptsCnt > 0 ) {
|
||||||
|
Point min = { rs.path.pts[0].x, rs.path.pts[0].y };
|
||||||
|
Point max = { rs.path.pts[0].x, rs.path.pts[0].y };
|
||||||
|
|
||||||
|
for (uint32_t i = 1; i < rs.path.ptsCnt; ++i) {
|
||||||
|
if (rs.path.pts[i].x < min.x) min.x = rs.path.pts[i].x;
|
||||||
|
if (rs.path.pts[i].y < min.y) min.y = rs.path.pts[i].y;
|
||||||
|
if (rs.path.pts[i].x > max.x) max.x = rs.path.pts[i].x;
|
||||||
|
if (rs.path.pts[i].y > max.y) max.y = rs.path.pts[i].y;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (x) *x = min.x;
|
||||||
|
if (y) *y = min.y;
|
||||||
|
if (w) *w = max.x - min.x;
|
||||||
|
if (h) *h = max.y - min.y;
|
||||||
|
}
|
||||||
|
|
||||||
//Stroke feathering
|
//Stroke feathering
|
||||||
if (stroke) {
|
if (rs.stroke) {
|
||||||
if (x) *x -= stroke->width * 0.5f;
|
if (x) *x -= rs.stroke->width * 0.5f;
|
||||||
if (y) *y -= stroke->width * 0.5f;
|
if (y) *y -= rs.stroke->width * 0.5f;
|
||||||
if (w) *w += stroke->width;
|
if (w) *w += rs.stroke->width;
|
||||||
if (h) *h += stroke->width;
|
if (h) *h += rs.stroke->width;
|
||||||
}
|
}
|
||||||
return ret;
|
return rs.path.ptsCnt > 0 ? true : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void reserveCmd(uint32_t cmdCnt)
|
||||||
|
{
|
||||||
|
if (cmdCnt <= rs.path.reservedCmdCnt) return;
|
||||||
|
rs.path.reservedCmdCnt = cmdCnt;
|
||||||
|
rs.path.cmds = static_cast<PathCommand*>(realloc(rs.path.cmds, sizeof(PathCommand) * rs.path.reservedCmdCnt));
|
||||||
|
}
|
||||||
|
|
||||||
|
void reservePts(uint32_t ptsCnt)
|
||||||
|
{
|
||||||
|
if (ptsCnt <= rs.path.reservedPtsCnt) return;
|
||||||
|
rs.path.reservedPtsCnt = ptsCnt;
|
||||||
|
rs.path.pts = static_cast<Point*>(realloc(rs.path.pts, sizeof(Point) * rs.path.reservedPtsCnt));
|
||||||
|
}
|
||||||
|
|
||||||
|
void grow(uint32_t cmdCnt, uint32_t ptsCnt)
|
||||||
|
{
|
||||||
|
reserveCmd(rs.path.cmdCnt + cmdCnt);
|
||||||
|
reservePts(rs.path.ptsCnt + ptsCnt);
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset()
|
||||||
|
{
|
||||||
|
rs.path.cmdCnt = 0;
|
||||||
|
rs.path.ptsCnt = 0;
|
||||||
|
|
||||||
|
flag = RenderUpdateFlag::Path;
|
||||||
|
}
|
||||||
|
|
||||||
|
void append(const PathCommand* cmds, uint32_t cmdCnt, const Point* pts, uint32_t ptsCnt)
|
||||||
|
{
|
||||||
|
memcpy(rs.path.cmds + rs.path.cmdCnt, cmds, sizeof(PathCommand) * cmdCnt);
|
||||||
|
memcpy(rs.path.pts + rs.path.ptsCnt, pts, sizeof(Point) * ptsCnt);
|
||||||
|
rs.path.cmdCnt += cmdCnt;
|
||||||
|
rs.path.ptsCnt += ptsCnt;
|
||||||
|
|
||||||
|
flag |= RenderUpdateFlag::Path;
|
||||||
|
}
|
||||||
|
|
||||||
|
void moveTo(float x, float y)
|
||||||
|
{
|
||||||
|
if (rs.path.cmdCnt + 1 > rs.path.reservedCmdCnt) reserveCmd((rs.path.cmdCnt + 1) * 2);
|
||||||
|
if (rs.path.ptsCnt + 2 > rs.path.reservedPtsCnt) reservePts((rs.path.ptsCnt + 2) * 2);
|
||||||
|
|
||||||
|
rs.path.cmds[rs.path.cmdCnt++] = PathCommand::MoveTo;
|
||||||
|
rs.path.pts[rs.path.ptsCnt++] = {x, y};
|
||||||
|
|
||||||
|
flag |= RenderUpdateFlag::Path;
|
||||||
|
}
|
||||||
|
|
||||||
|
void lineTo(float x, float y)
|
||||||
|
{
|
||||||
|
if (rs.path.cmdCnt + 1 > rs.path.reservedCmdCnt) reserveCmd((rs.path.cmdCnt + 1) * 2);
|
||||||
|
if (rs.path.ptsCnt + 2 > rs.path.reservedPtsCnt) reservePts((rs.path.ptsCnt + 2) * 2);
|
||||||
|
|
||||||
|
rs.path.cmds[rs.path.cmdCnt++] = PathCommand::LineTo;
|
||||||
|
rs.path.pts[rs.path.ptsCnt++] = {x, y};
|
||||||
|
|
||||||
|
flag |= RenderUpdateFlag::Path;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cubicTo(float cx1, float cy1, float cx2, float cy2, float x, float y)
|
||||||
|
{
|
||||||
|
if (rs.path.cmdCnt + 1 > rs.path.reservedCmdCnt) reserveCmd((rs.path.cmdCnt + 1) * 2);
|
||||||
|
if (rs.path.ptsCnt + 3 > rs.path.reservedPtsCnt) reservePts((rs.path.ptsCnt + 3) * 2);
|
||||||
|
|
||||||
|
rs.path.cmds[rs.path.cmdCnt++] = PathCommand::CubicTo;
|
||||||
|
rs.path.pts[rs.path.ptsCnt++] = {cx1, cy1};
|
||||||
|
rs.path.pts[rs.path.ptsCnt++] = {cx2, cy2};
|
||||||
|
rs.path.pts[rs.path.ptsCnt++] = {x, y};
|
||||||
|
|
||||||
|
flag |= RenderUpdateFlag::Path;
|
||||||
|
}
|
||||||
|
|
||||||
|
void close()
|
||||||
|
{
|
||||||
|
if (rs.path.cmdCnt > 0 && rs.path.cmds[rs.path.cmdCnt - 1] == PathCommand::Close) return;
|
||||||
|
|
||||||
|
if (rs.path.cmdCnt + 1 > rs.path.reservedCmdCnt) reserveCmd((rs.path.cmdCnt + 1) * 2);
|
||||||
|
rs.path.cmds[rs.path.cmdCnt++] = PathCommand::Close;
|
||||||
|
|
||||||
|
flag |= RenderUpdateFlag::Path;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool strokeWidth(float width)
|
bool strokeWidth(float width)
|
||||||
{
|
{
|
||||||
//TODO: Size Exception?
|
//TODO: Size Exception?
|
||||||
|
|
||||||
if (!stroke) stroke = static_cast<ShapeStroke*>(calloc(sizeof(ShapeStroke), 1));
|
if (!rs.stroke) rs.stroke = new RenderStroke();
|
||||||
stroke->width = width;
|
rs.stroke->width = width;
|
||||||
flag |= RenderUpdateFlag::Stroke;
|
flag |= RenderUpdateFlag::Stroke;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -274,8 +186,8 @@ struct Shape::Impl
|
||||||
|
|
||||||
bool strokeCap(StrokeCap cap)
|
bool strokeCap(StrokeCap cap)
|
||||||
{
|
{
|
||||||
if (!stroke) stroke = static_cast<ShapeStroke*>(calloc(sizeof(ShapeStroke), 1));
|
if (!rs.stroke) rs.stroke = new RenderStroke();
|
||||||
stroke->cap = cap;
|
rs.stroke->cap = cap;
|
||||||
flag |= RenderUpdateFlag::Stroke;
|
flag |= RenderUpdateFlag::Stroke;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -283,8 +195,8 @@ struct Shape::Impl
|
||||||
|
|
||||||
bool strokeJoin(StrokeJoin join)
|
bool strokeJoin(StrokeJoin join)
|
||||||
{
|
{
|
||||||
if (!stroke) stroke = static_cast<ShapeStroke*>(calloc(sizeof(ShapeStroke), 1));
|
if (!rs.stroke) rs.stroke = new RenderStroke();
|
||||||
stroke->join = join;
|
rs.stroke->join = join;
|
||||||
flag |= RenderUpdateFlag::Stroke;
|
flag |= RenderUpdateFlag::Stroke;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -292,17 +204,17 @@ struct Shape::Impl
|
||||||
|
|
||||||
bool strokeColor(uint8_t r, uint8_t g, uint8_t b, uint8_t a)
|
bool strokeColor(uint8_t r, uint8_t g, uint8_t b, uint8_t a)
|
||||||
{
|
{
|
||||||
if (!stroke) stroke = static_cast<ShapeStroke*>(calloc(sizeof(ShapeStroke), 1));
|
if (!rs.stroke) rs.stroke = new RenderStroke();
|
||||||
if (stroke->fill) {
|
if (rs.stroke->fill) {
|
||||||
delete(stroke->fill);
|
delete(rs.stroke->fill);
|
||||||
stroke->fill = nullptr;
|
rs.stroke->fill = nullptr;
|
||||||
flag |= RenderUpdateFlag::GradientStroke;
|
flag |= RenderUpdateFlag::GradientStroke;
|
||||||
}
|
}
|
||||||
|
|
||||||
stroke->color[0] = r;
|
rs.stroke->color[0] = r;
|
||||||
stroke->color[1] = g;
|
rs.stroke->color[1] = g;
|
||||||
stroke->color[2] = b;
|
rs.stroke->color[2] = b;
|
||||||
stroke->color[3] = a;
|
rs.stroke->color[3] = a;
|
||||||
|
|
||||||
flag |= RenderUpdateFlag::Stroke;
|
flag |= RenderUpdateFlag::Stroke;
|
||||||
|
|
||||||
|
@ -314,9 +226,9 @@ struct Shape::Impl
|
||||||
auto p = f.release();
|
auto p = f.release();
|
||||||
if (!p) return Result::MemoryCorruption;
|
if (!p) return Result::MemoryCorruption;
|
||||||
|
|
||||||
if (!stroke) stroke = static_cast<ShapeStroke*>(calloc(sizeof(ShapeStroke), 1));
|
if (!rs.stroke) rs.stroke = new RenderStroke();
|
||||||
if (stroke->fill && stroke->fill != p) delete(stroke->fill);
|
if (rs.stroke->fill && rs.stroke->fill != p) delete(rs.stroke->fill);
|
||||||
stroke->fill = p;
|
rs.stroke->fill = p;
|
||||||
|
|
||||||
flag |= RenderUpdateFlag::Stroke;
|
flag |= RenderUpdateFlag::Stroke;
|
||||||
flag |= RenderUpdateFlag::GradientStroke;
|
flag |= RenderUpdateFlag::GradientStroke;
|
||||||
|
@ -328,23 +240,23 @@ struct Shape::Impl
|
||||||
{
|
{
|
||||||
//Reset dash
|
//Reset dash
|
||||||
if (!pattern && cnt == 0) {
|
if (!pattern && cnt == 0) {
|
||||||
free(stroke->dashPattern);
|
free(rs.stroke->dashPattern);
|
||||||
stroke->dashPattern = nullptr;
|
rs.stroke->dashPattern = nullptr;
|
||||||
} else {
|
} else {
|
||||||
if (!stroke) stroke = static_cast<ShapeStroke*>(calloc(sizeof(ShapeStroke), 1));
|
if (!rs.stroke) rs.stroke = new RenderStroke();
|
||||||
if (stroke->dashCnt != cnt) {
|
if (rs.stroke->dashCnt != cnt) {
|
||||||
free(stroke->dashPattern);
|
free(rs.stroke->dashPattern);
|
||||||
stroke->dashPattern = nullptr;
|
rs.stroke->dashPattern = nullptr;
|
||||||
}
|
}
|
||||||
if (!stroke->dashPattern) {
|
if (!rs.stroke->dashPattern) {
|
||||||
stroke->dashPattern = static_cast<float*>(malloc(sizeof(float) * cnt));
|
rs.stroke->dashPattern = static_cast<float*>(malloc(sizeof(float) * cnt));
|
||||||
if (!stroke->dashPattern) return false;
|
if (!rs.stroke->dashPattern) return false;
|
||||||
}
|
}
|
||||||
for (uint32_t i = 0; i < cnt; ++i) {
|
for (uint32_t i = 0; i < cnt; ++i) {
|
||||||
stroke->dashPattern[i] = pattern[i];
|
rs.stroke->dashPattern[i] = pattern[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
stroke->dashCnt = cnt;
|
rs.stroke->dashCnt = cnt;
|
||||||
flag |= RenderUpdateFlag::Stroke;
|
flag |= RenderUpdateFlag::Stroke;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -355,29 +267,52 @@ struct Shape::Impl
|
||||||
auto ret = Shape::gen();
|
auto ret = Shape::gen();
|
||||||
|
|
||||||
auto dup = ret.get()->pImpl;
|
auto dup = ret.get()->pImpl;
|
||||||
dup->rule = rule;
|
dup->rs.rule = rs.rule;
|
||||||
|
|
||||||
//Color
|
//Color
|
||||||
memcpy(dup->color, color, sizeof(color));
|
memcpy(dup->rs.color, rs.color, sizeof(rs.color));
|
||||||
dup->flag = RenderUpdateFlag::Color;
|
dup->flag = RenderUpdateFlag::Color;
|
||||||
|
|
||||||
//Path
|
//Path
|
||||||
dup->path.duplicate(&path);
|
if (rs.path.cmdCnt > 0 && rs.path.ptsCnt > 0) {
|
||||||
|
dup->rs.path.cmdCnt = rs.path.cmdCnt;
|
||||||
|
dup->rs.path.reservedCmdCnt = rs.path.reservedCmdCnt;
|
||||||
|
dup->rs.path.ptsCnt = rs.path.ptsCnt;
|
||||||
|
dup->rs.path.reservedPtsCnt = rs.path.reservedPtsCnt;
|
||||||
|
|
||||||
|
dup->rs.path.cmds = static_cast<PathCommand*>(malloc(sizeof(PathCommand) * dup->rs.path.reservedCmdCnt));
|
||||||
|
if (dup->rs.path.cmds) memcpy(dup->rs.path.cmds, rs.path.cmds, sizeof(PathCommand) * dup->rs.path.cmdCnt);
|
||||||
|
|
||||||
|
dup->rs.path.pts = static_cast<Point*>(malloc(sizeof(Point) * dup->rs.path.reservedPtsCnt));
|
||||||
|
if (dup->rs.path.pts) memcpy(dup->rs.path.pts, rs.path.pts, sizeof(Point) * dup->rs.path.ptsCnt);
|
||||||
|
}
|
||||||
dup->flag |= RenderUpdateFlag::Path;
|
dup->flag |= RenderUpdateFlag::Path;
|
||||||
|
|
||||||
//Stroke
|
//Stroke
|
||||||
if (stroke) {
|
if (rs.stroke) {
|
||||||
dup->stroke = static_cast<ShapeStroke*>(calloc(sizeof(ShapeStroke), 1));
|
dup->rs.stroke = new RenderStroke();
|
||||||
dup->stroke->copy(stroke);
|
dup->rs.stroke->width = rs.stroke->width;
|
||||||
|
dup->rs.stroke->dashCnt = rs.stroke->dashCnt;
|
||||||
|
dup->rs.stroke->cap = rs.stroke->cap;
|
||||||
|
dup->rs.stroke->join = rs.stroke->join;
|
||||||
|
memcpy(dup->rs.stroke->color, rs.stroke->color, sizeof(rs.stroke->color));
|
||||||
|
|
||||||
|
if (rs.stroke->dashCnt > 0) {
|
||||||
|
dup->rs.stroke->dashPattern = static_cast<float*>(malloc(sizeof(float) * rs.stroke->dashCnt));
|
||||||
|
memcpy(dup->rs.stroke->dashPattern, rs.stroke->dashPattern, sizeof(float) * rs.stroke->dashCnt);
|
||||||
|
}
|
||||||
|
|
||||||
dup->flag |= RenderUpdateFlag::Stroke;
|
dup->flag |= RenderUpdateFlag::Stroke;
|
||||||
|
|
||||||
if (stroke->fill)
|
if (rs.stroke->fill) {
|
||||||
|
dup->rs.stroke->fill = rs.stroke->fill->duplicate();
|
||||||
dup->flag |= RenderUpdateFlag::GradientStroke;
|
dup->flag |= RenderUpdateFlag::GradientStroke;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Fill
|
//Fill
|
||||||
if (fill) {
|
if (rs.fill) {
|
||||||
dup->fill = fill->duplicate();
|
dup->rs.fill = rs.fill->duplicate();
|
||||||
dup->flag |= RenderUpdateFlag::Gradient;
|
dup->flag |= RenderUpdateFlag::Gradient;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue