mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-09 14:13: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;
|
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
|
* @class Paint
|
||||||
|
@ -1177,6 +1204,42 @@ public:
|
||||||
*/
|
*/
|
||||||
Result load(uint32_t* data, uint32_t w, uint32_t h, bool copy) noexcept;
|
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.
|
* @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)
|
bool GlRenderer::renderShape(RenderData data)
|
||||||
{
|
{
|
||||||
auto sdata = static_cast<GlShape*>(data);
|
auto sdata = static_cast<GlShape*>(data);
|
||||||
|
|
|
@ -35,6 +35,7 @@ public:
|
||||||
bool preRender() override;
|
bool preRender() override;
|
||||||
bool renderShape(RenderData data) override;
|
bool renderShape(RenderData data) override;
|
||||||
bool renderImage(RenderData data) override;
|
bool renderImage(RenderData data) override;
|
||||||
|
bool renderImageMesh(RenderData data) override;
|
||||||
bool postRender() override;
|
bool postRender() override;
|
||||||
bool dispose(RenderData data) override;;
|
bool dispose(RenderData data) override;;
|
||||||
RenderRegion region(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);
|
SwOutline* strokeExportOutline(SwStroke* stroke, SwMpool* mpool, unsigned tid);
|
||||||
void strokeFree(SwStroke* stroke);
|
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);
|
bool imageGenRle(SwImage* image, const SwBBox& renderRegion, bool antiAlias);
|
||||||
void imageDelOutline(SwImage* image, SwMpool* mpool, uint32_t tid);
|
void imageDelOutline(SwImage* image, SwMpool* mpool, uint32_t tid);
|
||||||
void imageReset(SwImage* image);
|
void imageReset(SwImage* image);
|
||||||
|
@ -351,6 +351,7 @@ bool rasterCompositor(SwSurface* surface);
|
||||||
bool rasterGradientShape(SwSurface* surface, SwShape* shape, unsigned id);
|
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 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 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 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 rasterGradientStroke(SwSurface* surface, SwShape* shape, unsigned id);
|
||||||
bool rasterClear(SwSurface* surface);
|
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);
|
image->outline = mpoolReqOutline(mpool, tid);
|
||||||
auto outline = image->outline;
|
auto outline = image->outline;
|
||||||
|
@ -51,10 +51,49 @@ static bool _genOutline(SwImage* image, const Matrix* transform, SwMpool* mpool,
|
||||||
outline->closed[0] = true;
|
outline->closed[0] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 };
|
||||||
|
|
||||||
|
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 w = static_cast<float>(image->w);
|
||||||
auto h = static_cast<float>(image->h);
|
auto h = static_cast<float>(image->h);
|
||||||
|
to[0] = {0, 0};
|
||||||
Point to[4] = {{0 ,0}, {w, 0}, {w, h}, {0, h}};
|
to[1] = {w, 0};
|
||||||
|
to[2] = {w, h};
|
||||||
|
to[3] = {0, h};
|
||||||
|
}
|
||||||
for (int i = 0; i < 4; i++) {
|
for (int i = 0; i < 4; i++) {
|
||||||
outline->pts[outline->ptsCnt] = mathTransform(&to[i], transform);
|
outline->pts[outline->ptsCnt] = mathTransform(&to[i], transform);
|
||||||
outline->types[outline->ptsCnt] = SW_CURVE_TYPE_POINT;
|
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 */
|
/* 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);
|
image->direct = _onlyShifted(transform);
|
||||||
|
|
||||||
|
@ -96,7 +135,7 @@ bool imagePrepare(SwImage* image, const Matrix* transform, const SwBBox& clipReg
|
||||||
else image->scaled = false;
|
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);
|
return mathUpdateOutlineBBox(image->outline, clipRegion, renderRegion, image->direct);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -687,6 +687,22 @@ static bool _transformedRGBAImage(SwSurface* surface, const SwImage* image, cons
|
||||||
return false;
|
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 */
|
/*Scaled RGBA Image */
|
||||||
|
@ -1556,3 +1572,15 @@ bool rasterImage(SwSurface* surface, SwImage* image, const Matrix* transform, co
|
||||||
//TODO: case: _rasterAlphaImage()
|
//TODO: case: _rasterAlphaImage()
|
||||||
return _rasterRGBAImage(surface, image, transform, bbox, opacity);
|
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.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct Vertex
|
|
||||||
{
|
|
||||||
Point pt;
|
|
||||||
Point uv;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Polygon
|
|
||||||
{
|
|
||||||
Vertex vertex[3];
|
|
||||||
};
|
|
||||||
|
|
||||||
struct AALine
|
struct AALine
|
||||||
{
|
{
|
||||||
int32_t x[2];
|
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
|
auto yStart = static_cast<int32_t>(ymin);
|
||||||
float ys = FLT_MAX, ye = -1.0f;
|
auto yEnd = static_cast<int32_t>(ymax);
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
if (!_arrange(image, region, yStart, yEnd)) return nullptr;
|
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[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)}};
|
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;
|
if (!aaSpans) return true;
|
||||||
|
|
||||||
Polygon polygon;
|
Polygon polygon;
|
||||||
|
@ -600,3 +587,61 @@ static bool _rasterTexmapPolygon(SwSurface* surface, const SwImage* image, const
|
||||||
|
|
||||||
return _apply(surface, aaSpans);
|
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
|
struct SwImageTask : SwTask
|
||||||
{
|
{
|
||||||
SwImage image;
|
SwImage image;
|
||||||
|
Polygon* triangles;
|
||||||
|
uint32_t triangleCount;
|
||||||
|
|
||||||
void run(unsigned tid) override
|
void run(unsigned tid) override
|
||||||
{
|
{
|
||||||
|
@ -191,9 +193,10 @@ struct SwImageTask : SwTask
|
||||||
imageReset(&image);
|
imageReset(&image);
|
||||||
if (!image.data || image.w == 0 || image.h == 0) goto end;
|
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 (!imageGenRle(&image, bbox, false)) goto end;
|
||||||
if (image.rle) {
|
if (image.rle) {
|
||||||
for (auto clip = clips.data; clip < (clips.data + clips.count); ++clip) {
|
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)
|
bool SwRenderer::renderShape(RenderData data)
|
||||||
{
|
{
|
||||||
auto task = static_cast<SwShapeTask*>(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
|
//prepare task
|
||||||
auto task = static_cast<SwImageTask*>(data);
|
auto task = static_cast<SwImageTask*>(data);
|
||||||
if (!task) {
|
if (!task) task = new SwImageTask;
|
||||||
task = new SwImageTask;
|
|
||||||
if (flags & RenderUpdateFlag::Image) {
|
if (flags & RenderUpdateFlag::Image) {
|
||||||
task->image.data = image->buffer;
|
task->image.data = image->buffer;
|
||||||
task->image.w = image->w;
|
task->image.w = image->w;
|
||||||
task->image.h = image->h;
|
task->image.h = image->h;
|
||||||
task->image.stride = image->stride;
|
task->image.stride = image->stride;
|
||||||
}
|
task->triangles = triangles;
|
||||||
|
task->triangleCount = triangleCount;
|
||||||
}
|
}
|
||||||
return prepareCommon(task, transform, opacity, clips, flags);
|
return prepareCommon(task, transform, opacity, clips, flags);
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,10 +36,11 @@ class SwRenderer : public RenderMethod
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
RenderData prepare(const Shape& shape, RenderData data, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags) override;
|
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 preRender() override;
|
||||||
bool renderShape(RenderData data) override;
|
bool renderShape(RenderData data) override;
|
||||||
bool renderImage(RenderData data) override;
|
bool renderImage(RenderData data) override;
|
||||||
|
bool renderImageMesh(RenderData data) override;
|
||||||
bool postRender() override;
|
bool postRender() override;
|
||||||
bool dispose(RenderData data) override;
|
bool dispose(RenderData data) override;
|
||||||
RenderRegion region(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;
|
if (pImpl->surface) return pImpl->surface->buffer;
|
||||||
else return nullptr;
|
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
|
Paint* paint = nullptr; //vector picture uses
|
||||||
Surface* surface = nullptr; //bitmap 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
|
void* rdata = nullptr; //engine data
|
||||||
float w = 0, h = 0;
|
float w = 0, h = 0;
|
||||||
bool resizing = false;
|
bool resizing = false;
|
||||||
|
@ -70,6 +72,7 @@ struct Picture::Impl
|
||||||
~Impl()
|
~Impl()
|
||||||
{
|
{
|
||||||
if (paint) delete(paint);
|
if (paint) delete(paint);
|
||||||
|
free(triangles);
|
||||||
free(surface);
|
free(surface);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -128,7 +131,7 @@ struct Picture::Impl
|
||||||
|
|
||||||
if (surface) {
|
if (surface) {
|
||||||
auto transform = resizeTransform(pTransform);
|
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) {
|
} else if (paint) {
|
||||||
if (resizing) {
|
if (resizing) {
|
||||||
loader->resize(paint, w, h);
|
loader->resize(paint, w, h);
|
||||||
|
@ -141,7 +144,10 @@ struct Picture::Impl
|
||||||
|
|
||||||
bool render(RenderMethod &renderer)
|
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);
|
else if (paint) return paint->pImpl->render(renderer);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -166,11 +172,42 @@ struct Picture::Impl
|
||||||
|
|
||||||
bool bounds(float* x, float* y, float* w, float* h)
|
bool bounds(float* x, float* y, float* w, float* 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 (x) *x = 0;
|
||||||
if (y) *y = 0;
|
if (y) *y = 0;
|
||||||
if (w) *w = this->w;
|
if (w) *w = this->w;
|
||||||
if (h) *h = this->h;
|
if (h) *h = this->h;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -220,6 +257,20 @@ struct Picture::Impl
|
||||||
return Result::Success;
|
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()
|
Paint* duplicate()
|
||||||
{
|
{
|
||||||
reload();
|
reload();
|
||||||
|
@ -238,6 +289,12 @@ struct Picture::Impl
|
||||||
dup->h = h;
|
dup->h = h;
|
||||||
dup->resizing = resizing;
|
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();
|
return ret.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -90,10 +90,11 @@ 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) = 0;
|
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 preRender() = 0;
|
||||||
virtual bool renderShape(RenderData data) = 0;
|
virtual bool renderShape(RenderData data) = 0;
|
||||||
virtual bool renderImage(RenderData data) = 0;
|
virtual bool renderImage(RenderData data) = 0;
|
||||||
|
virtual bool renderImageMesh(RenderData data) = 0;
|
||||||
virtual bool postRender() = 0;
|
virtual bool postRender() = 0;
|
||||||
virtual bool dispose(RenderData data) = 0;
|
virtual bool dispose(RenderData data) = 0;
|
||||||
virtual RenderRegion region(RenderData data) = 0;
|
virtual RenderRegion region(RenderData data) = 0;
|
||||||
|
|
Loading…
Add table
Reference in a new issue