common picture: support image mesh feature

Tvg Picture newly provides mesh() api to support texture mapping.
These apis allows to have a coarse triangle list which have polygon coordinates
and texture uvs those are used for traditional polygon texture mapping.

Note that these apis are beta version.

@API Additions:

Result mesh(const Polygon* triangles, const uint32_t triangleCount) noexcept
uint32_t mesh(const Polygon** triangles) const noexcept

@Examples:

//Mapping with two polygons
Polygon polygon[2];

//First polygon
polygon[0].vertex[0].pt = {0, 0};
polygon[0].vertex[1].pt = {100, 0};
polygon[0].vertex[2].pt = {0, 100};
polygon[0].vertex[0].uv = {0, 0};
polygon[0].vertex[1].uv = {1, 0};
polygon[0].vertex[2].uv = {0, 1};

//Second polygon
polygon[1].vertex[0].pt = {100, 0};
polygon[1].vertex[1].pt = {100, 100};
polygon[1].vertex[2].pt = {0, 100};
polygon[1].vertex[0].uv = {1, 0};
polygon[1].vertex[1].uv = {1, 1};
polygon[1].vertex[2].uv = {0, 1};

//Apply polygons to the picture
picture->mesh(polygon, 2);

@Issues: https://github.com/Samsung/thorvg/issues/1218
This commit is contained in:
projectitis 2022-08-19 19:56:43 +12:00 committed by Hermet Park
parent 6687defc0b
commit 3dd65dfed0
12 changed files with 320 additions and 50 deletions

View file

@ -183,6 +183,33 @@ struct Matrix
float e31, e32, e33;
};
/**
* @brief A data structure representing a texture mesh vertex
*
* @param pt The vertex coordinate
* @param uv The normalized texture coordinate in the range (0.0..1.0, 0.0..1.0)
*
* @BETA_API
*/
struct Vertex
{
Point pt;
Point uv;
};
/**
* @brief A data structure representing a triange in a texture mesh
*
* @param vertex The three vertices that make up the polygon
*
* @BETA_API
*/
struct Polygon
{
Vertex vertex[3];
};
/**
* @class Paint
@ -1177,6 +1204,42 @@ public:
*/
Result load(uint32_t* data, uint32_t w, uint32_t h, bool copy) noexcept;
/**
* @brief Sets or removes the triangle mesh to deform the image.
*
* If a mesh is provided, the transform property of the Picture will apply to the triangle mesh, and the
* image data will be used as the texture.
*
* If triangles is null, or triangleCount is 0, the mesh will be removed.
*
* Only raster image types are supported at this time (png, jpg). Vector types like svg and tvg do not support
* mesh deformation. However, if required you should be able to render a vector image to a raster image and then apply a mesh.
*
* @param[in] triangles An array of Polygon objects (triangles) that make up the mesh, or null to remove the mesh
* @param[in] triangleCount The number of Polygon objects (triangles) provided, or 0 to remove the mesh
*
* @retval Result::Success When succeed.
* @retval Result::Unknown If fails
*
* @note The Polygons are copied internally, so modifying them after calling Mesh::mesh has no affect.
*
* @BETA_API
*/
Result mesh(const Polygon* triangles, const uint32_t triangleCount) noexcept;
/**
* @brief Return the number of triangles in the mesh, and optionally get a pointer to the array of triangles in the mesh.
*
* @param[out] triangles Optional. A pointer to the array of Polygons used by this mesh
*
* @return uint32_t The number of polygons in the array
*
* @note Modifying the triangles returned by this method will modify them directly within the mesh
*
* @BETA_API
*/
uint32_t mesh(const Polygon** triangles) const noexcept;
/**
* @brief Gets the position and the size of the loaded SVG picture.
*

View file

@ -129,6 +129,12 @@ bool GlRenderer::renderImage(TVG_UNUSED void* data)
}
bool GlRenderer::renderImageMesh(TVG_UNUSED void* data)
{
return false;
}
bool GlRenderer::renderShape(RenderData data)
{
auto sdata = static_cast<GlShape*>(data);

View file

@ -35,6 +35,7 @@ public:
bool preRender() override;
bool renderShape(RenderData data) override;
bool renderImage(RenderData data) override;
bool renderImageMesh(RenderData data) override;
bool postRender() override;
bool dispose(RenderData data) override;;
RenderRegion region(RenderData data) override;

View file

@ -321,7 +321,7 @@ bool strokeParseOutline(SwStroke* stroke, const SwOutline& outline);
SwOutline* strokeExportOutline(SwStroke* stroke, SwMpool* mpool, unsigned tid);
void strokeFree(SwStroke* stroke);
bool imagePrepare(SwImage* image, const Matrix* transform, const SwBBox& clipRegion, SwBBox& renderRegion, SwMpool* mpool, unsigned tid);
bool imagePrepare(SwImage* image, Polygon* triangles, uint32_t triangleCount, const Matrix* transform, const SwBBox& clipRegion, SwBBox& renderRegion, SwMpool* mpool, unsigned tid);
bool imageGenRle(SwImage* image, const SwBBox& renderRegion, bool antiAlias);
void imageDelOutline(SwImage* image, SwMpool* mpool, uint32_t tid);
void imageReset(SwImage* image);
@ -351,6 +351,7 @@ bool rasterCompositor(SwSurface* surface);
bool rasterGradientShape(SwSurface* surface, SwShape* shape, unsigned id);
bool rasterShape(SwSurface* surface, SwShape* shape, uint8_t r, uint8_t g, uint8_t b, uint8_t a);
bool rasterImage(SwSurface* surface, SwImage* image, const Matrix* transform, const SwBBox& bbox, uint32_t opacity);
bool rasterImageMesh(SwSurface* surface, SwImage* image, const Polygon* triangles, const uint32_t triangleCount, const Matrix* transform, const SwBBox& bbox, uint32_t opacity);
bool rasterStroke(SwSurface* surface, SwShape* shape, uint8_t r, uint8_t g, uint8_t b, uint8_t a);
bool rasterGradientStroke(SwSurface* surface, SwShape* shape, unsigned id);
bool rasterClear(SwSurface* surface);

View file

@ -33,7 +33,7 @@ static inline bool _onlyShifted(const Matrix* m)
}
static bool _genOutline(SwImage* image, const Matrix* transform, SwMpool* mpool, unsigned tid)
static bool _genOutline(SwImage* image, Polygon* triangles, uint32_t triangleCount, const Matrix* transform, SwMpool* mpool, unsigned tid)
{
image->outline = mpoolReqOutline(mpool, tid);
auto outline = image->outline;
@ -51,10 +51,49 @@ static bool _genOutline(SwImage* image, const Matrix* transform, SwMpool* mpool,
outline->closed[0] = true;
}
auto w = static_cast<float>(image->w);
auto h = static_cast<float>(image->h);
Point to[4];
if (triangleCount > 0) {
// TODO: Optimise me. We appear to calculate this exact min/max bounding area in multiple
// places. We should be able to re-use one we have already done? Also see:
// tvgPictureImpl.h --> bounds
// tvgSwRasterTexmap.h --> _rasterTexmapPolygonMesh
//
// TODO: Should we calculate the exact path(s) of the triangle mesh instead?
// i.e. copy tvgSwShape.capp -> _genOutline?
//
// TODO: Cntrs?
Point min = { triangles[0].vertex[0].pt.x, triangles[0].vertex[0].pt.y };
Point max = { triangles[0].vertex[0].pt.x, triangles[0].vertex[0].pt.y };
Point to[4] = {{0 ,0}, {w, 0}, {w, h}, {0, h}};
for (uint32_t i = 0; i < triangleCount; ++i) {
if (triangles[i].vertex[0].pt.x < min.x) min.x = triangles[i].vertex[0].pt.x;
else if (triangles[i].vertex[0].pt.x > max.x) max.x = triangles[i].vertex[0].pt.x;
if (triangles[i].vertex[0].pt.y < min.y) min.y = triangles[i].vertex[0].pt.y;
else if (triangles[i].vertex[0].pt.y > max.y) max.y = triangles[i].vertex[0].pt.y;
if (triangles[i].vertex[1].pt.x < min.x) min.x = triangles[i].vertex[1].pt.x;
else if (triangles[i].vertex[1].pt.x > max.x) max.x = triangles[i].vertex[1].pt.x;
if (triangles[i].vertex[1].pt.y < min.y) min.y = triangles[i].vertex[1].pt.y;
else if (triangles[i].vertex[1].pt.y > max.y) max.y = triangles[i].vertex[1].pt.y;
if (triangles[i].vertex[2].pt.x < min.x) min.x = triangles[i].vertex[2].pt.x;
else if (triangles[i].vertex[2].pt.x > max.x) max.x = triangles[i].vertex[2].pt.x;
if (triangles[i].vertex[2].pt.y < min.y) min.y = triangles[i].vertex[2].pt.y;
else if (triangles[i].vertex[2].pt.y > max.y) max.y = triangles[i].vertex[2].pt.y;
}
to[0] = {min.x, min.y};
to[1] = {max.x, min.y};
to[2] = {max.x, max.y};
to[3] = {min.x, max.y};
} else {
auto w = static_cast<float>(image->w);
auto h = static_cast<float>(image->h);
to[0] = {0, 0};
to[1] = {w, 0};
to[2] = {w, h};
to[3] = {0, h};
}
for (int i = 0; i < 4; i++) {
outline->pts[outline->ptsCnt] = mathTransform(&to[i], transform);
outline->types[outline->ptsCnt] = SW_CURVE_TYPE_POINT;
@ -78,7 +117,7 @@ static bool _genOutline(SwImage* image, const Matrix* transform, SwMpool* mpool,
/* External Class Implementation */
/************************************************************************/
bool imagePrepare(SwImage* image, const Matrix* transform, const SwBBox& clipRegion, SwBBox& renderRegion, SwMpool* mpool, unsigned tid)
bool imagePrepare(SwImage* image, Polygon* triangles, uint32_t triangleCount, const Matrix* transform, const SwBBox& clipRegion, SwBBox& renderRegion, SwMpool* mpool, unsigned tid)
{
image->direct = _onlyShifted(transform);
@ -96,7 +135,7 @@ bool imagePrepare(SwImage* image, const Matrix* transform, const SwBBox& clipReg
else image->scaled = false;
}
if (!_genOutline(image, transform, mpool, tid)) return false;
if (!_genOutline(image, triangles, triangleCount, transform, mpool, tid)) return false;
return mathUpdateOutlineBBox(image->outline, clipRegion, renderRegion, image->direct);
}

View file

@ -687,6 +687,22 @@ static bool _transformedRGBAImage(SwSurface* surface, const SwImage* image, cons
return false;
}
static bool _transformedRGBAImageMesh(SwSurface* surface, const SwImage* image, const Polygon* triangles, const uint32_t count, const Matrix* transform, const SwBBox* region, uint32_t opacity)
{
if (_compositing(surface)) {
if (surface->compositor->method == CompositeMethod::AlphaMask) {
return _rasterTexmapPolygonMesh(surface, image, triangles, count, transform, region, opacity, _alpha);
} else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
return _rasterTexmapPolygonMesh(surface, image, triangles, count, transform, region, opacity, _ialpha);
} else if (surface->compositor->method == CompositeMethod::LumaMask) {
return _rasterTexmapPolygonMesh(surface, image, triangles, count, transform, region, opacity, surface->blender.lumaValue);
}
} else {
return _rasterTexmapPolygonMesh(surface, image, triangles, count, transform, region, opacity, nullptr);
}
return false;
}
/************************************************************************/
/*Scaled RGBA Image */
@ -1556,3 +1572,15 @@ bool rasterImage(SwSurface* surface, SwImage* image, const Matrix* transform, co
//TODO: case: _rasterAlphaImage()
return _rasterRGBAImage(surface, image, transform, bbox, opacity);
}
bool rasterImageMesh(SwSurface* surface, SwImage* image, const Polygon* triangles, const uint32_t count, const Matrix* transform, const SwBBox& bbox, uint32_t opacity)
{
//Verify Boundary
if (bbox.max.x < 0 || bbox.max.y < 0 || bbox.min.x >= static_cast<SwCoord>(surface->w) || bbox.min.y >= static_cast<SwCoord>(surface->h)) return false;
//TOOD: switch (image->format)
//TODO: case: _rasterRGBImageMesh()
//TODO: case: _rasterGrayscaleImageMesh()
//TODO: case: _rasterAlphaImageMesh()
return _transformedRGBAImageMesh(surface, image, triangles, count, transform, &bbox, opacity);
}

View file

@ -20,17 +20,6 @@
* SOFTWARE.
*/
struct Vertex
{
Point pt;
Point uv;
};
struct Polygon
{
Vertex vertex[3];
};
struct AALine
{
int32_t x[2];
@ -287,18 +276,10 @@ static void _rasterPolygonImage(SwSurface* surface, const SwImage* image, const
}
static AASpans* _AASpans(const Vertex* vertices, const SwImage* image, const SwBBox* region)
static AASpans* _AASpans(float ymin, float ymax, const SwImage* image, const SwBBox* region)
{
//Initialize Y range
float ys = FLT_MAX, ye = -1.0f;
for (int i = 0; i < 4; i++) {
if (vertices[i].pt.y < ys) ys = vertices[i].pt.y;
if (vertices[i].pt.y > ye) ye = vertices[i].pt.y;
}
auto yStart = static_cast<int32_t>(ys);
auto yEnd = static_cast<int32_t>(ye);
auto yStart = static_cast<int32_t>(ymin);
auto yEnd = static_cast<int32_t>(ymax);
if (!_arrange(image, region, yStart, yEnd)) return nullptr;
@ -577,9 +558,15 @@ static bool _rasterTexmapPolygon(SwSurface* surface, const SwImage* image, const
vertices[2] = {{float(image->w), float(image->h)}, {float(image->w), float(image->h)}};
vertices[3] = {{0.0f, float(image->h)}, {0.0f, float(image->h)}};
for (int i = 0; i < 4; i++) mathMultiply(&vertices[i].pt, transform);
float ys = FLT_MAX, ye = -1.0f;
for (int i = 0; i < 4; i++) {
mathMultiply(&vertices[i].pt, transform);
auto aaSpans = _AASpans(vertices, image, region);
if (vertices[i].pt.y < ys) ys = vertices[i].pt.y;
if (vertices[i].pt.y > ye) ye = vertices[i].pt.y;
}
auto aaSpans = _AASpans(ys, ye, image, region);
if (!aaSpans) return true;
Polygon polygon;
@ -600,3 +587,61 @@ static bool _rasterTexmapPolygon(SwSurface* surface, const SwImage* image, const
return _apply(surface, aaSpans);
}
/*
Provide any number of triangles to draw a mesh using the supplied image.
Indexes are not used, so each triangle (Polygon) vertex has to be defined, even if they copy the previous one.
Example:
0 -- 1 0 -- 1 0
| / | --> | / / |
| / | | / / |
2 -- 3 2 1 -- 2
Should provide two Polygons, one for each triangle.
// TODO: region?
*/
static bool _rasterTexmapPolygonMesh(SwSurface* surface, const SwImage* image, const Polygon* triangles, const uint32_t triangleCount, const Matrix* transform, const SwBBox* region, uint32_t opacity, uint32_t (*blendMethod)(uint32_t))
{
//Exceptions: No dedicated drawing area?
if (!region && image->rle->size == 0) return false;
// Step polygons once to transform
auto transformedTris = (Polygon*)malloc(sizeof(Polygon) * triangleCount);
float ys = FLT_MAX, ye = -1.0f;
for (uint32_t i = 0; i < triangleCount; i++) {
transformedTris[i] = triangles[i];
mathMultiply(&transformedTris[i].vertex[0].pt, transform);
mathMultiply(&transformedTris[i].vertex[1].pt, transform);
mathMultiply(&transformedTris[i].vertex[2].pt, transform);
if (transformedTris[i].vertex[0].pt.y < ys) ys = transformedTris[i].vertex[0].pt.y;
else if (transformedTris[i].vertex[0].pt.y > ye) ye = transformedTris[i].vertex[0].pt.y;
if (transformedTris[i].vertex[1].pt.y < ys) ys = transformedTris[i].vertex[1].pt.y;
else if (transformedTris[i].vertex[1].pt.y > ye) ye = transformedTris[i].vertex[1].pt.y;
if (transformedTris[i].vertex[2].pt.y < ys) ys = transformedTris[i].vertex[2].pt.y;
else if (transformedTris[i].vertex[2].pt.y > ye) ye = transformedTris[i].vertex[2].pt.y;
// Convert normalized UV coordinates to image coordinates
transformedTris[i].vertex[0].uv.x *= (float)image->w;
transformedTris[i].vertex[0].uv.y *= (float)image->h;
transformedTris[i].vertex[1].uv.x *= (float)image->w;
transformedTris[i].vertex[1].uv.y *= (float)image->h;
transformedTris[i].vertex[2].uv.x *= (float)image->w;
transformedTris[i].vertex[2].uv.y *= (float)image->h;
}
// Get AA spans and step polygons again to draw
auto aaSpans = _AASpans(ys, ye, image, region);
if (aaSpans) {
for (uint32_t i = 0; i < triangleCount; i++) {
_rasterPolygonImage(surface, image, region, opacity, transformedTris[i], blendMethod, aaSpans);
}
// Apply to surface (note: frees the AA spans)
_apply(surface, aaSpans);
}
free(transformedTris);
return true;
}

View file

@ -181,6 +181,8 @@ struct SwShapeTask : SwTask
struct SwImageTask : SwTask
{
SwImage image;
Polygon* triangles;
uint32_t triangleCount;
void run(unsigned tid) override
{
@ -191,9 +193,10 @@ struct SwImageTask : SwTask
imageReset(&image);
if (!image.data || image.w == 0 || image.h == 0) goto end;
if (!imagePrepare(&image, transform, clipRegion, bbox, mpool, tid)) goto end;
if (!imagePrepare(&image, triangles, triangleCount, transform, clipRegion, bbox, mpool, tid)) goto end;
if (clips.count > 0) {
// TODO: How do we clip the triangle mesh? Only clip non-meshed images for now
if (triangleCount == 0 && clips.count > 0) {
if (!imageGenRle(&image, bbox, false)) goto end;
if (image.rle) {
for (auto clip = clips.data; clip < (clips.data + clips.count); ++clip) {
@ -356,6 +359,17 @@ bool SwRenderer::renderImage(RenderData data)
}
bool SwRenderer::renderImageMesh(RenderData data)
{
auto task = static_cast<SwImageTask*>(data);
task->done();
if (task->opacity == 0) return true;
return rasterImageMesh(surface, &task->image, task->triangles, task->triangleCount, task->transform, task->bbox, task->opacity);
}
bool SwRenderer::renderShape(RenderData data)
{
auto task = static_cast<SwShapeTask*>(data);
@ -610,18 +624,18 @@ void* SwRenderer::prepareCommon(SwTask* task, const RenderTransform* transform,
}
RenderData SwRenderer::prepare(Surface* image, RenderData data, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags)
RenderData SwRenderer::prepare(Surface* image, Polygon* triangles, uint32_t triangleCount, RenderData data, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags)
{
//prepare task
auto task = static_cast<SwImageTask*>(data);
if (!task) {
task = new SwImageTask;
if (flags & RenderUpdateFlag::Image) {
task->image.data = image->buffer;
task->image.w = image->w;
task->image.h = image->h;
task->image.stride = image->stride;
}
if (!task) task = new SwImageTask;
if (flags & RenderUpdateFlag::Image) {
task->image.data = image->buffer;
task->image.w = image->w;
task->image.h = image->h;
task->image.stride = image->stride;
task->triangles = triangles;
task->triangleCount = triangleCount;
}
return prepareCommon(task, transform, opacity, clips, flags);
}

View file

@ -36,10 +36,11 @@ class SwRenderer : public RenderMethod
{
public:
RenderData prepare(const Shape& shape, RenderData data, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags) override;
RenderData prepare(Surface* image, 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 renderShape(RenderData data) override;
bool renderImage(RenderData data) override;
bool renderImageMesh(RenderData data) override;
bool postRender() override;
bool dispose(RenderData data) override;
RenderRegion region(RenderData data) override;

View file

@ -119,3 +119,17 @@ const uint32_t* Picture::data(uint32_t* w, uint32_t* h) const noexcept
if (pImpl->surface) return pImpl->surface->buffer;
else return nullptr;
}
Result Picture::mesh(const Polygon* triangles, const uint32_t triangleCount) noexcept
{
if (pImpl->mesh(triangles, triangleCount)) return Result::Success;
return Result::Unknown;
}
uint32_t Picture::mesh(const Polygon** triangles) const noexcept
{
if (triangles) *triangles = pImpl->triangles;
return pImpl->triangleCount;
}

View file

@ -63,6 +63,8 @@ struct Picture::Impl
Paint* paint = nullptr; //vector picture uses
Surface* surface = nullptr; //bitmap picture uses
Polygon* triangles = nullptr; //mesh data
uint32_t triangleCount = 0; //mesh triangle count
void* rdata = nullptr; //engine data
float w = 0, h = 0;
bool resizing = false;
@ -70,6 +72,7 @@ struct Picture::Impl
~Impl()
{
if (paint) delete(paint);
free(triangles);
free(surface);
}
@ -128,7 +131,7 @@ struct Picture::Impl
if (surface) {
auto transform = resizeTransform(pTransform);
rdata = renderer.prepare(surface, rdata, &transform, opacity, clips, static_cast<RenderUpdateFlag>(pFlag | flag));
rdata = renderer.prepare(surface, triangles, triangleCount, rdata, &transform, opacity, clips, static_cast<RenderUpdateFlag>(pFlag | flag));
} else if (paint) {
if (resizing) {
loader->resize(paint, w, h);
@ -141,7 +144,10 @@ struct Picture::Impl
bool render(RenderMethod &renderer)
{
if (surface) return renderer.renderImage(rdata);
if (surface) {
if (triangles) return renderer.renderImageMesh(rdata);
else return renderer.renderImage(rdata);
}
else if (paint) return paint->pImpl->render(renderer);
return false;
}
@ -166,10 +172,41 @@ struct Picture::Impl
bool bounds(float* x, float* y, float* w, float* h)
{
if (x) *x = 0;
if (y) *y = 0;
if (w) *w = this->w;
if (h) *h = this->h;
if (triangleCount > 0) {
Point min = { triangles[0].vertex[0].pt.x, triangles[0].vertex[0].pt.y };
Point max = { triangles[0].vertex[0].pt.x, triangles[0].vertex[0].pt.y };
for (uint32_t i = 0; i < triangleCount; ++i) {
if (triangles[i].vertex[0].pt.x < min.x) min.x = triangles[i].vertex[0].pt.x;
else if (triangles[i].vertex[0].pt.x > max.x) max.x = triangles[i].vertex[0].pt.x;
if (triangles[i].vertex[0].pt.y < min.y) min.y = triangles[i].vertex[0].pt.y;
else if (triangles[i].vertex[0].pt.y > max.y) max.y = triangles[i].vertex[0].pt.y;
if (triangles[i].vertex[1].pt.x < min.x) min.x = triangles[i].vertex[1].pt.x;
else if (triangles[i].vertex[1].pt.x > max.x) max.x = triangles[i].vertex[1].pt.x;
if (triangles[i].vertex[1].pt.y < min.y) min.y = triangles[i].vertex[1].pt.y;
else if (triangles[i].vertex[1].pt.y > max.y) max.y = triangles[i].vertex[1].pt.y;
if (triangles[i].vertex[2].pt.x < min.x) min.x = triangles[i].vertex[2].pt.x;
else if (triangles[i].vertex[2].pt.x > max.x) max.x = triangles[i].vertex[2].pt.x;
if (triangles[i].vertex[2].pt.y < min.y) min.y = triangles[i].vertex[2].pt.y;
else if (triangles[i].vertex[2].pt.y > max.y) max.y = triangles[i].vertex[2].pt.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;
} else {
if (x) *x = 0;
if (y) *y = 0;
if (w) *w = this->w;
if (h) *h = this->h;
}
return true;
}
@ -220,6 +257,20 @@ struct Picture::Impl
return Result::Success;
}
bool mesh(const Polygon* triangles, const uint32_t triangleCount)
{
if (triangles && triangleCount > 0) {
this->triangleCount = triangleCount;
this->triangles = (Polygon*)malloc(sizeof(Polygon) * triangleCount);
for (uint32_t i = 0; i < triangleCount; i++) this->triangles[i] = triangles[i];
} else {
free(this->triangles);
this->triangles = nullptr;
this->triangleCount = 0;
}
return true;
}
Paint* duplicate()
{
reload();
@ -238,6 +289,12 @@ struct Picture::Impl
dup->h = h;
dup->resizing = resizing;
if (triangleCount > 0) {
dup->triangleCount = triangleCount;
dup->triangles = (Polygon*)malloc(sizeof(Polygon) * triangleCount);
for (uint32_t i = 0; i < triangleCount; i++) dup->triangles[i] = triangles[i];
}
return ret.release();
}

View file

@ -90,10 +90,11 @@ class RenderMethod
public:
virtual ~RenderMethod() {}
virtual RenderData prepare(const Shape& shape, RenderData data, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags) = 0;
virtual RenderData prepare(Surface* image, 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 renderShape(RenderData data) = 0;
virtual bool renderImage(RenderData data) = 0;
virtual bool renderImageMesh(RenderData data) = 0;
virtual bool postRender() = 0;
virtual bool dispose(RenderData data) = 0;
virtual RenderRegion region(RenderData data) = 0;