mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-08 13:43:43 +00:00
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:
parent
6687defc0b
commit
3dd65dfed0
12 changed files with 320 additions and 50 deletions
63
inc/thorvg.h
63
inc/thorvg.h
|
@ -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.
|
||||
*
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Add table
Reference in a new issue