mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-08 13:43:43 +00:00
common shape: introduce transformation matrix
Paint supports translate, rotate, scale functions for transformation The origin of these transformation is center of the paint, thus you have to consider the center-aligned vertices if you'd like to use these transformation functions. This policy has been considered for scene transformation. Change-Id: I78b63d7965faec0ec5b9a98a7776993744534b54
This commit is contained in:
parent
17af011eae
commit
b08d144dc9
13 changed files with 144 additions and 91 deletions
|
@ -79,10 +79,9 @@ public:
|
|||
|
||||
virtual int rotate(float degree) = 0;
|
||||
virtual int scale(float factor) = 0;
|
||||
virtual int translate(float x, float y) = 0;
|
||||
|
||||
virtual int bounds(float&x, float& y, float& w, float& h) const = 0;
|
||||
virtual float scale() const = 0;
|
||||
virtual float rotate() const = 0;
|
||||
};
|
||||
|
||||
|
||||
|
@ -141,13 +140,12 @@ public:
|
|||
|
||||
int rotate(float degree) noexcept override;
|
||||
int scale(float factor) noexcept override;
|
||||
int translate(float x, float y) noexcept override;
|
||||
|
||||
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;
|
||||
|
||||
|
@ -175,10 +173,9 @@ public:
|
|||
|
||||
int rotate(float degree) noexcept override;
|
||||
int scale(float factor) noexcept override;
|
||||
int translate(float x, float y) 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;
|
||||
|
||||
|
|
|
@ -65,7 +65,7 @@ bool GlRenderer::dispose(const Shape& shape, void *data)
|
|||
}
|
||||
|
||||
|
||||
void* GlRenderer::prepare(const Shape& shape, void* data, RenderUpdateFlag flags)
|
||||
void* GlRenderer::prepare(const Shape& shape, void* data, const RenderTransform* transform, RenderUpdateFlag flags)
|
||||
{
|
||||
//prepare shape data
|
||||
GlShape* sdata = static_cast<GlShape*>(data);
|
||||
|
@ -74,6 +74,14 @@ void* GlRenderer::prepare(const Shape& shape, void* data, RenderUpdateFlag flags
|
|||
assert(sdata);
|
||||
}
|
||||
|
||||
if (RenderUpdateFlag::Path) {
|
||||
//TODO: Updated Vertices
|
||||
}
|
||||
|
||||
if (RenderUpdateFlag::Transform) {
|
||||
//TODO: Updated Transform
|
||||
}
|
||||
|
||||
//TODO:
|
||||
|
||||
return sdata;
|
||||
|
|
|
@ -23,7 +23,7 @@ namespace tvg
|
|||
class GlRenderer : public RenderMethod
|
||||
{
|
||||
public:
|
||||
void* prepare(const Shape& shape, void* data, RenderUpdateFlag flags) override;
|
||||
void* prepare(const Shape& shape, void* data, const RenderTransform* transform, RenderUpdateFlag flags) override;
|
||||
bool dispose(const Shape& shape, void *data) override;
|
||||
bool render(const Shape& shape, void *data) override;
|
||||
bool clear() override;
|
||||
|
|
|
@ -96,7 +96,7 @@ void shapeReset(SwShape& sdata);
|
|||
bool shapeGenOutline(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);
|
||||
void shapeTransformOutline(const Shape& shape, SwShape& sdata, const RenderTransform& transform);
|
||||
SwRleData* rleRender(const SwShape& sdata, const SwSize& clip);
|
||||
|
||||
bool rasterShape(Surface& surface, SwShape& sdata, uint8_t r, uint8_t g, uint8_t b, uint8_t a);
|
||||
|
|
|
@ -81,7 +81,7 @@ bool SwRenderer::dispose(const Shape& shape, void *data)
|
|||
return true;
|
||||
}
|
||||
|
||||
void* SwRenderer::prepare(const Shape& shape, void* data, RenderUpdateFlag flags)
|
||||
void* SwRenderer::prepare(const Shape& shape, void* data, const RenderTransform* transform, RenderUpdateFlag flags)
|
||||
{
|
||||
//prepare shape data
|
||||
SwShape* sdata = static_cast<SwShape*>(data);
|
||||
|
@ -98,10 +98,10 @@ void* SwRenderer::prepare(const Shape& shape, void* data, RenderUpdateFlag flags
|
|||
if (alpha == 0) return sdata;
|
||||
|
||||
//TODO: Threading
|
||||
if (flags & (RenderUpdateFlag::Path | RenderUpdateFlag::Transform)) {
|
||||
if (flags & RenderUpdateFlag::Path || RenderUpdateFlag::Transform) {
|
||||
shapeReset(*sdata);
|
||||
if (!shapeGenOutline(shape, *sdata)) return sdata;
|
||||
if (!shapeTransformOutline(shape, *sdata)) return sdata;
|
||||
if (transform) shapeTransformOutline(shape, *sdata, *transform);
|
||||
|
||||
SwSize clip = {static_cast<SwCoord>(surface.w), static_cast<SwCoord>(surface.h)};
|
||||
if (!shapeGenRle(shape, *sdata, clip)) return sdata;
|
||||
|
|
|
@ -22,7 +22,7 @@ class SwRenderer : public RenderMethod
|
|||
public:
|
||||
Surface surface;
|
||||
|
||||
void* prepare(const Shape& shape, void* data, RenderUpdateFlag flags) override;
|
||||
void* prepare(const Shape& shape, void* data, const RenderTransform* transform, 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);
|
||||
|
|
|
@ -215,54 +215,19 @@ void _deleteRle(SwShape& sdata)
|
|||
/* External Class Implementation */
|
||||
/************************************************************************/
|
||||
|
||||
bool shapeTransformOutline(const Shape& shape, SwShape& sdata)
|
||||
void shapeTransformOutline(const Shape& shape, SwShape& sdata, const RenderTransform& transform)
|
||||
{
|
||||
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};
|
||||
auto dx = static_cast<float>(outline->pts[i].x >> 6);
|
||||
auto dy = static_cast<float>(outline->pts[i].y >> 6);
|
||||
auto tx = dx * transform.e11 + dy * transform.e12 + transform.e13;
|
||||
auto ty = dx * transform.e21 + dy * transform.e22 + transform.e23;
|
||||
auto pt = Point{tx + transform.e31, ty + transform.e32};
|
||||
outline->pts[i] = TO_SWPOINT(&pt);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -30,11 +30,87 @@ struct Surface
|
|||
|
||||
enum RenderUpdateFlag {None = 0, Path = 1, Fill = 2, Transform = 4, All = 8};
|
||||
|
||||
struct RenderTransform
|
||||
{
|
||||
float e11, e12, e13;
|
||||
float e21, e22, e23;
|
||||
float e31, e32, e33;
|
||||
|
||||
void identity()
|
||||
{
|
||||
e11 = 1.0f;
|
||||
e12 = 0.0f;
|
||||
e13 = 0.0f;
|
||||
e21 = 0.0f;
|
||||
e22 = 1.0f;
|
||||
e23 = 0.0f;
|
||||
e31 = 0.0f;
|
||||
e32 = 0.0f;
|
||||
e33 = 1.0f;
|
||||
}
|
||||
|
||||
void rotate(float degree)
|
||||
{
|
||||
constexpr auto PI = 3.141592f;
|
||||
|
||||
if (fabsf(degree) <= FLT_EPSILON) return;
|
||||
|
||||
auto radian = degree / 180.0f * PI;
|
||||
auto cosVal = cosf(radian);
|
||||
auto sinVal = sinf(radian);
|
||||
|
||||
auto t11 = e11 * cosVal + e12 * sinVal;
|
||||
auto t12 = e11 * -sinVal + e12 * cosVal;
|
||||
auto t21 = e21 * cosVal + e22 * sinVal;
|
||||
auto t22 = e21 * -sinVal + e22 * cosVal;
|
||||
auto t31 = e31 * cosVal + e32 * sinVal;
|
||||
auto t32 = e31 * -sinVal + e32 * cosVal;
|
||||
|
||||
e11 = t11;
|
||||
e12 = t12;
|
||||
e21 = t21;
|
||||
e22 = t22;
|
||||
e31 = t31;
|
||||
e32 = t32;
|
||||
}
|
||||
|
||||
void translate(float x, float y)
|
||||
{
|
||||
e31 += x;
|
||||
e32 += y;
|
||||
}
|
||||
|
||||
void scale(float factor)
|
||||
{
|
||||
e11 *= factor;
|
||||
e22 *= factor;
|
||||
e33 *= factor;
|
||||
}
|
||||
|
||||
RenderTransform& operator*=(const RenderTransform rhs)
|
||||
{
|
||||
e11 = e11 * rhs.e11 + e12 * rhs.e21 + e13 * rhs.e31;
|
||||
e12 = e11 * rhs.e12 + e12 * rhs.e22 + e13 * rhs.e32;
|
||||
e13 = e11 * rhs.e13 + e12 * rhs.e23 + e13 * rhs.e33;
|
||||
|
||||
e21 = e21 * rhs.e11 + e22 * rhs.e21 + e23 * rhs.e31;
|
||||
e22 = e21 * rhs.e12 + e22 * rhs.e22 + e23 * rhs.e32;
|
||||
e23 = e21 * rhs.e13 + e22 * rhs.e23 + e23 * rhs.e33;
|
||||
|
||||
e31 = e31 * rhs.e11 + e32 * rhs.e21 + e33 * rhs.e31;
|
||||
e32 = e31 * rhs.e12 + e32 * rhs.e22 + e33 * rhs.e32;
|
||||
e33 = e31 * rhs.e13 + e32 * rhs.e23 + e33 * rhs.e33;
|
||||
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class RenderMethod
|
||||
{
|
||||
public:
|
||||
virtual ~RenderMethod() {}
|
||||
virtual void* prepare(const Shape& shape, void* data, RenderUpdateFlag flags) = 0;
|
||||
virtual void* prepare(const Shape& shape, void* data, const RenderTransform* transform, 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;
|
||||
|
|
|
@ -76,6 +76,12 @@ int Scene::rotate(float degree) noexcept
|
|||
}
|
||||
|
||||
|
||||
int Scene::translate(float x, float y) noexcept
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int Scene::bounds(float& x, float& y, float& w, float& h) const noexcept
|
||||
{
|
||||
auto impl = pImpl.get();
|
||||
|
@ -91,16 +97,4 @@ int Scene::bounds(float& x, float& y, float& w, float& h) const noexcept
|
|||
return 0;
|
||||
}
|
||||
|
||||
|
||||
float Scene::scale() const noexcept
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
float Scene::rotate() const noexcept
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* _TVG_SCENE_CPP_ */
|
|
@ -247,7 +247,7 @@ int Shape::scale(float factor) noexcept
|
|||
auto impl = pImpl.get();
|
||||
assert(impl);
|
||||
|
||||
if (fabsf(factor) < FLT_EPSILON || fabsf(factor - impl->scale) <= FLT_EPSILON) return -1;
|
||||
if (fabsf(factor - impl->scale) <= FLT_EPSILON) return -1;
|
||||
|
||||
impl->scale = factor;
|
||||
impl->flag |= RenderUpdateFlag::Transform;
|
||||
|
@ -270,6 +270,21 @@ int Shape::rotate(float degree) noexcept
|
|||
}
|
||||
|
||||
|
||||
int Shape::translate(float x, float y) noexcept
|
||||
{
|
||||
auto impl = pImpl.get();
|
||||
assert(impl);
|
||||
|
||||
if (fabsf(x - impl->x) <= FLT_EPSILON && fabsf(y - impl->y) <= FLT_EPSILON) return -1;
|
||||
|
||||
impl->x = x;
|
||||
impl->y = y;
|
||||
impl->flag |= RenderUpdateFlag::Transform;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int Shape::bounds(float& x, float& y, float& w, float& h) const noexcept
|
||||
{
|
||||
auto impl = pImpl.get();
|
||||
|
@ -281,21 +296,4 @@ int Shape::bounds(float& x, float& y, float& w, float& h) const noexcept
|
|||
}
|
||||
|
||||
|
||||
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_
|
||||
|
|
|
@ -41,6 +41,8 @@ struct Shape::Impl
|
|||
uint8_t color[4] = {0, 0, 0, 0}; //r, g, b, a
|
||||
float scale = 1;
|
||||
float rotate = 0;
|
||||
float x = 0;
|
||||
float y = 0;
|
||||
void *edata = nullptr; //engine data
|
||||
size_t flag = RenderUpdateFlag::None;
|
||||
|
||||
|
@ -67,8 +69,19 @@ struct Shape::Impl
|
|||
|
||||
bool update(Shape& shape, RenderMethod& renderer)
|
||||
{
|
||||
edata = renderer.prepare(shape, edata, static_cast<RenderUpdateFlag>(flag));
|
||||
if (flag & RenderUpdateFlag::Transform) {
|
||||
RenderTransform transform;
|
||||
transform.identity();
|
||||
transform.rotate(rotate);
|
||||
transform.scale(scale);
|
||||
transform.translate(x, y);
|
||||
edata = renderer.prepare(shape, edata, &transform, static_cast<RenderUpdateFlag>(flag));
|
||||
} else {
|
||||
edata = renderer.prepare(shape, edata, nullptr, static_cast<RenderUpdateFlag>(flag));
|
||||
}
|
||||
|
||||
flag = RenderUpdateFlag::None;
|
||||
|
||||
if (edata) return true;
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -23,11 +23,12 @@ void tvgtest()
|
|||
instead, you should consider not to interrupt this pointer life-cycle. */
|
||||
pShape = shape.get();
|
||||
|
||||
shape->appendRect(0, 0, 200, 200, 0);
|
||||
shape->appendRect(100, 100, 300, 300, 100);
|
||||
shape->appendCircle(400, 400, 100, 100);
|
||||
shape->appendCircle(400, 500, 170, 100);
|
||||
shape->appendRect(-285, -300, 200, 200, 0);
|
||||
shape->appendRect(-185, -200, 300, 300, 100);
|
||||
shape->appendCircle(115, 100, 100, 100);
|
||||
shape->appendCircle(115, 200, 170, 100);
|
||||
shape->fill(255, 255, 255, 255);
|
||||
shape->translate(285, 300);
|
||||
|
||||
canvas->push(move(shape));
|
||||
|
||||
|
|
|
@ -33,8 +33,9 @@ void transit_cb(Elm_Transit_Effect *effect, Elm_Transit* transit, double progres
|
|||
|
||||
//Shape
|
||||
auto shape = tvg::Shape::gen();
|
||||
shape->appendRect(-100 + (800 * progress), -100 + (800 * progress), 200, 200, (100 * progress));
|
||||
shape->appendRect(-100, -100, 200, 200, (100 * progress));
|
||||
shape->fill(rand()%255, rand()%255, rand()%255, 255);
|
||||
shape->translate(800 * progress, 800 * progress);
|
||||
shape->scale(1 - 0.75 * progress);
|
||||
shape->rotate(360 * progress);
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue