virtual int scale(float factor) = 0;
virtual int bounds(float&x, float& y, float& w, float& h) const = 0;
+ virtual float scale() const = 0;
+ virtual float rotate() const = 0;
};
int rotate(float degree) noexcept override;
int scale(float factor) noexcept override;
- int pathCommands(const PathCommand** cmds) const noexcept;
- int pathCoords(const Point** pts) const noexcept;
+ size_t pathCommands(const PathCommand** cmds) const noexcept;
+ size_t pathCoords(const Point** pts) const noexcept;
int fill(size_t* r, size_t* g, size_t* b, size_t* a) const noexcept;
int bounds(float&x, float& y, float& w, float& h) const noexcept override;
+ float scale() const noexcept override;
+ float rotate() const noexcept override;
static std::unique_ptr<Shape> gen() noexcept;
int scale(float factor) noexcept override;
int bounds(float&x, float& y, float& w, float& h) const noexcept override;
+ float scale() const noexcept override;
+ float rotate() const noexcept override;
static std::unique_ptr<Scene> gen() noexcept;
}
-void* GlRenderer::prepare(const Shape& shape, void* data, UpdateFlag flags)
+void* GlRenderer::prepare(const Shape& shape, void* data, RenderUpdateFlag flags)
{
//prepare shape data
GlShape* sdata = static_cast<GlShape*>(data);
class GlRenderer : public RenderMethod
{
public:
- void* prepare(const Shape& shape, void* data, UpdateFlag flags) override;
+ void* prepare(const Shape& shape, void* data, RenderUpdateFlag flags) override;
bool dispose(const Shape& shape, void *data) override;
bool render(const Shape& shape, void *data) override;
bool clear() override;
void shapeReset(SwShape& sdata);
bool shapeGenOutline(const Shape& shape, SwShape& sdata);
-void shapeDelOutline(const Shape& shape, SwShape& sdata);
+void shapeDelOutline(SwShape& sdata);
bool shapeGenRle(const Shape& shape, SwShape& sdata, const SwSize& clip);
bool shapeTransformOutline(const Shape& shape, SwShape& sdata);
SwRleData* rleRender(const SwShape& sdata, const SwSize& clip);
return true;
}
-void* SwRenderer::prepare(const Shape& shape, void* data, UpdateFlag flags)
+void* SwRenderer::prepare(const Shape& shape, void* data, RenderUpdateFlag flags)
{
//prepare shape data
SwShape* sdata = static_cast<SwShape*>(data);
assert(sdata);
}
- if (flags == UpdateFlag::None) return nullptr;
+ if (flags == RenderUpdateFlag::None) return sdata;
//invisible?
size_t alpha;
if (alpha == 0) return sdata;
//TODO: Threading
- if (flags & UpdateFlag::Path) {
+ if (flags & (RenderUpdateFlag::Path | RenderUpdateFlag::Transform)) {
shapeReset(*sdata);
if (!shapeGenOutline(shape, *sdata)) return sdata;
if (!shapeTransformOutline(shape, *sdata)) return sdata;
SwSize clip = {static_cast<SwCoord>(surface.w), static_cast<SwCoord>(surface.h)};
if (!shapeGenRle(shape, *sdata, clip)) return sdata;
+ shapeDelOutline(*sdata);
}
return sdata;
public:
Surface surface;
- void* prepare(const Shape& shape, void* data, UpdateFlag flags) override;
+ void* prepare(const Shape& shape, void* data, RenderUpdateFlag flags) override;
bool dispose(const Shape& shape, void *data) override;
bool render(const Shape& shape, void *data) override;
bool target(uint32_t* buffer, size_t stride, size_t w, size_t h);
}
-void _deleteOutline(SwShape& sdata)
-{
- if (!sdata.outline) return;
-
- SwOutline* outline = sdata.outline;
- if (outline->cntrs) free(outline->cntrs);
- if (outline->pts) free(outline->pts);
- if (outline->types) free(outline->types);
- free(outline);
-
- sdata.outline = nullptr;
-}
-
/************************************************************************/
/* External Class Implementation */
/************************************************************************/
bool shapeTransformOutline(const Shape& shape, SwShape& sdata)
{
- //TODO:
+ constexpr auto PI = 3.141592f;
+
+ auto degree = shape.rotate();
+ auto scale = shape.scale();
+ bool rotateOn = false;
+ bool scaleOn = false;
+
+ if (fabsf(degree) > FLT_EPSILON) rotateOn = true;
+ if (fabsf(scale - 1) > FLT_EPSILON) scaleOn = true;
+
+ if (!rotateOn && !scaleOn) return true;
+
+ auto outline = sdata.outline;
+ assert(outline);
+
+ float x, y, w, h;
+ shape.bounds(x, y, w, h);
+
+ auto cx = x + w * 0.5f;
+ auto cy = y + h * 0.5f;
+
+ float radian, cosVal, sinVal;
+ if (rotateOn) {
+ radian = degree / 180.0f * PI;
+ cosVal = cosf(radian);
+ sinVal = sinf(radian);
+ }
+
+ for(size_t i = 0; i < outline->ptsCnt; ++i) {
+ auto dx = static_cast<float>(outline->pts[i].x >> 6) - cx;
+ auto dy = static_cast<float>(outline->pts[i].y >> 6) - cy;
+ if (rotateOn) {
+ auto tx = (cosVal * dx - sinVal * dy);
+ auto ty = (sinVal * dx + cosVal * dy);
+ dx = tx;
+ dy = ty;
+ }
+ if (scaleOn) {
+ dx *= scale;
+ dy *= scale;
+ }
+ auto pt = Point{dx + cx, dy + cy};
+ outline->pts[i] = TO_SWPOINT(&pt);
+ }
+
return true;
}
(sdata.bbox.min.y + sdata.bbox.max.y < 0)) goto end;
sdata.rle = rleRender(sdata, clip);
- _deleteOutline(sdata);
end:
if (sdata.rle) return true;
}
+void shapeDelOutline(SwShape& sdata)
+{
+ if (!sdata.outline) return;
+
+ SwOutline* outline = sdata.outline;
+ if (outline->cntrs) free(outline->cntrs);
+ if (outline->pts) free(outline->pts);
+ if (outline->types) free(outline->types);
+ free(outline);
+
+ sdata.outline = nullptr;
+}
+
+
void shapeReset(SwShape& sdata)
{
- _deleteOutline(sdata);
+ shapeDelOutline(sdata);
_deleteRle(sdata);
_initBBox(sdata);
}
auto outlinePtsCnt = 0;
auto outlineCntrsCnt = 0;
- for (auto i = 0; i < cmdCnt; ++i) {
+ for (size_t i = 0; i < cmdCnt; ++i) {
switch(*(cmds + i)) {
case PathCommand::Close: {
++outlinePtsCnt;
cout << "Outline was already allocated? How?" << endl;
}
- //TODO: Probabry we can copy pts from shape directly.
_growOutlinePoint(*outline, outlinePtsCnt);
_growOutlineContour(*outline, outlineCntrsCnt);
size_t w, h;
};
+enum RenderUpdateFlag {None = 0, Path = 1, Fill = 2, Transform = 4, All = 8};
+
class RenderMethod
{
public:
- enum UpdateFlag { None = 0, Path = 1, Fill = 2, All = 3 };
virtual ~RenderMethod() {}
- virtual void* prepare(const Shape& shape, void* data, UpdateFlag flags) = 0;
+ virtual void* prepare(const Shape& shape, void* data, RenderUpdateFlag flags) = 0;
virtual bool dispose(const Shape& shape, void *data) = 0;
virtual bool render(const Shape& shape, void *data) = 0;
virtual bool clear() = 0;
return 0;
}
+
+float Scene::scale() const noexcept
+{
+ return 0;
+}
+
+
+float Scene::rotate() const noexcept
+{
+ return 0;
+}
+
#endif /* _TVG_SCENE_CPP_ */
\ No newline at end of file
float scale = 1;
float rotate = 0;
void *edata = nullptr; //engine data
+ size_t flag = RenderUpdateFlag::None;
Impl() : path(new ShapePath)
{
if (stroke) delete(stroke);
if (fill) delete(fill);
}
-
- bool update()
- {
- if (path->scale(scale)) scale = 1;
- if (path->rotate(rotate)) rotate = 0;
-
- return true;
- }
};
auto impl = pImpl.get();
assert(impl);
- if (!impl->update()) return -1;
- impl->edata = engine->prepare(*this, impl->edata, RenderMethod::UpdateFlag::All);
+ impl->edata = engine->prepare(*this, impl->edata, static_cast<RenderUpdateFlag>(impl->flag));
+ impl->flag = RenderUpdateFlag::None;
if (impl->edata) return 0;
- return - 1;
+ return -1;
}
impl->path->reset();
+ impl->flag |= RenderUpdateFlag::Path;
+
return 0;
}
-int Shape::pathCommands(const PathCommand** cmds) const noexcept
+size_t Shape::pathCommands(const PathCommand** cmds) const noexcept
{
auto impl = pImpl.get();
assert(impl && impl->path && cmds);
}
-int Shape::pathCoords(const Point** pts) const noexcept
+size_t Shape::pathCoords(const Point** pts) const noexcept
{
auto impl = pImpl.get();
assert(impl && impl->path && pts);
impl->path->grow(cmdCnt, ptsCnt);
impl->path->append(cmds, cmdCnt, pts, ptsCnt);
+ impl->flag |= RenderUpdateFlag::Path;
+
return 0;
}
impl->path->moveTo(x, y);
+ impl->flag |= RenderUpdateFlag::Path;
+
return 0;
}
impl->path->lineTo(x, y);
+ impl->flag |= RenderUpdateFlag::Path;
+
return 0;
}
impl->path->cubicTo(cx1, cy1, cx2, cy2, x, y);
+ impl->flag |= RenderUpdateFlag::Path;
+
return 0;
}
impl->path->close();
+ impl->flag |= RenderUpdateFlag::Path;
+
return 0;
}
impl->path->cubicTo(cx - radiusW, cy - halfKappaH, cx - halfKappaW, cy - radiusH, cx, cy - radiusH);
impl->path->close();
+ impl->flag |= RenderUpdateFlag::Path;
+
return 0;
}
impl->path->close();
}
+ impl->flag |= RenderUpdateFlag::Path;
+
return 0;
}
impl->color[1] = g;
impl->color[2] = b;
impl->color[3] = a;
+ impl->flag |= RenderUpdateFlag::Fill;
return 0;
}
int Shape::scale(float factor) noexcept
{
- if (factor < FLT_EPSILON || fabsf(factor - 1) <= FLT_EPSILON) return -1;
-
auto impl = pImpl.get();
assert(impl);
- impl->scale *= factor;
+ if (fabsf(factor) < FLT_EPSILON || fabsf(factor - impl->scale) <= FLT_EPSILON) return -1;
+
+ impl->scale = factor;
+ impl->flag |= RenderUpdateFlag::Transform;
return 0;
}
int Shape::rotate(float degree) noexcept
{
- if (fabsf(degree) <= FLT_EPSILON) return -1;
-
auto impl = pImpl.get();
assert(impl);
- impl->rotate += degree;
+ if (fabsf(degree - impl->rotate) <= FLT_EPSILON) return -1;
+
+ impl->rotate = degree;
+ impl->flag |= RenderUpdateFlag::Transform;
return 0;
}
return 0;
}
+
+float Shape::scale() const noexcept
+{
+ auto impl = pImpl.get();
+ assert(impl);
+
+ return impl->scale;
+}
+
+
+float Shape::rotate() const noexcept
+{
+ auto impl = pImpl.get();
+ assert(impl);
+
+ return impl->rotate;
+}
+
#endif //_TVG_SHAPE_CPP_
return true;
}
-
- bool rotate(float degree)
- {
- constexpr auto PI = 3.141592f;
-
- if (fabsf(degree) <= FLT_EPSILON) return false;
-
- float x, y, w, h;
- if (!bounds(x, y, w, h)) return false;
-
- auto radian = degree / 180.0f * PI;
- auto cx = x + w * 0.5f;
- auto cy = y + h * 0.5f;
- auto cosVal = cosf(radian);
- auto sinVal = sinf(radian);
-
- for(size_t i = 0; i < ptsCnt; ++i) {
- auto dx = pts[i].x - cx;
- auto dy = pts[i].y - cy;
- pts[i].x = (cosVal * dx - sinVal * dy) + cx;
- pts[i].y = (sinVal * dx + cosVal * dy) + cy;
- }
-
- return true;
- }
-
- bool scale(float factor)
- {
- if (fabsf(factor - 1) <= FLT_EPSILON) return false;
-
- float x, y, w, h;
- if (!bounds(x, y, w, h)) return false;
-
- auto cx = x + w * 0.5f;
- auto cy = y + h * 0.5f;
-
- for(size_t i = 0; i < ptsCnt; ++i) {
- pts[i].x = (pts[i].x - cx) * factor + cx;
- pts[i].y = (pts[i].y - cy) * factor + cy;
- }
-
- return true;
- }
};
#endif //_TVG_SHAPE_PATH_CPP_
pShape = shape.get();
shape->appendRect(-100, -100, 200, 200, 0);
+
+ //fill and rotate properties will be retained
shape->fill(127, 255, 255, 255);
shape->rotate(45);
canvas->push(move(shape));
pShape->reset(); //reset path
pShape->appendRect(-100 + (800 * progress), -100 + (800 * progress), 200, 200, (100 * progress));
-
- /* rotate, scale won't be retained, when you call reset() for the shape, these values will be reset as well.
- These are working in fire & forget method, it actually modify the path data for avoiding compuatation every frames.
- Thus user needs to keep the last values to understand the final accumulated values. */
- pShape->rotate(45);
pShape->scale(1 - 0.75 * progress);
//Update shape for drawing (this may work asynchronously)