common picture: support image mesh feature 54/289554/1
authorprojectitis <peter@projectitis.com>
Fri, 19 Aug 2022 07:56:43 +0000 (19:56 +1200)
committerPatryk Kaczmarek <patryk.k@partner.samsung.com>
Thu, 9 Mar 2023 12:19:15 +0000 (13:19 +0100)
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

Change-Id: I8400a654b392d1d01e01727e0bc0d829cd155080

12 files changed:
inc/thorvg.h
src/lib/gl_engine/tvgGlRenderer.cpp
src/lib/gl_engine/tvgGlRenderer.h
src/lib/sw_engine/tvgSwCommon.h
src/lib/sw_engine/tvgSwImage.cpp
src/lib/sw_engine/tvgSwRaster.cpp
src/lib/sw_engine/tvgSwRasterTexmap.h
src/lib/sw_engine/tvgSwRenderer.cpp
src/lib/sw_engine/tvgSwRenderer.h
src/lib/tvgPicture.cpp
src/lib/tvgPictureImpl.h
src/lib/tvgRender.h

index 7e8988a..efba938 100644 (file)
@@ -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
@@ -1178,6 +1205,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.
      *
      * @warning Please do not use it, this API is not official one. It could be modified in the next version.
      * @brief Gets the position and the size of the loaded SVG picture.
      *
      * @warning Please do not use it, this API is not official one. It could be modified in the next version.
index 4384d52..8fbcd39 100644 (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);
 bool GlRenderer::renderShape(RenderData data)
 {
     auto sdata = static_cast<GlShape*>(data);
index e0e8cce..7767a62 100644 (file)
@@ -35,6 +35,7 @@ public:
     bool preRender() override;
     bool renderShape(RenderData data) override;
     bool renderImage(RenderData data) 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;
     bool postRender() override;
     bool dispose(RenderData data) override;;
     RenderRegion region(RenderData data) override;
index 47b0cb8..888f4fd 100644 (file)
@@ -321,7 +321,7 @@ bool strokeParseOutline(SwStroke* stroke, const SwOutline& outline);
 SwOutline* strokeExportOutline(SwStroke* stroke, SwMpool* mpool, unsigned tid);
 void strokeFree(SwStroke* stroke);
 
 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);
 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 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);
 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);
index c02e28b..a1b8960 100644 (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;
 {
     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;
     }
 
         outline->closed[0] = true;
     }
 
-    auto w = static_cast<float>(image->w);
-    auto h = static_cast<float>(image->h);
-
-    Point to[4] = {{0 ,0}, {w, 0}, {w, h}, {0, 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 };
+
+        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;
     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                                        */
 /************************************************************************/
 
 /* 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);
 }
 
index 14e26e4..7512efc 100644 (file)
@@ -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()
     return _rasterRGBAImage(surface, image, transform, bbox, opacity);
 }
     //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);
+}
\ No newline at end of file
index abb57d7..32a772e 100644 (file)
  * SOFTWARE.
  */
 
  * SOFTWARE.
  */
 
-struct Vertex
-{
-   Point pt;
-   Point uv;
-};
-
-struct Polygon
-{
-   Vertex vertex[3];
-};
-
 struct AALine
 {
    int32_t x[2];
 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;
 
 
     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)}};
 
     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);
+
+        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(vertices, image, region);
+    auto aaSpans = _AASpans(ys, ye, image, region);
     if (!aaSpans) return true;
 
     Polygon polygon;
     if (!aaSpans) return true;
 
     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;
+}
index c3872f3..692d592 100644 (file)
@@ -181,6 +181,8 @@ struct SwShapeTask : SwTask
 struct SwImageTask : SwTask
 {
     SwImage image;
 struct SwImageTask : SwTask
 {
     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);
             if (!image.data || image.w == 0 || image.h == 0) goto end;
 
             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) {
                 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);
 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);
 {
     //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);
 }
     }
     return prepareCommon(task, transform, opacity, clips, flags);
 }
index 574d9d4..9bc1c83 100644 (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;
 {
 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 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;
     bool postRender() override;
     bool dispose(RenderData data) override;
     RenderRegion region(RenderData data) override;
index 1e04e25..4449d2d 100644 (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;
 }
     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;
+}
index b2e097d..d8aaec0 100644 (file)
@@ -63,6 +63,8 @@ struct Picture::Impl
 
     Paint* paint = nullptr;           //vector picture uses
     Surface* surface = nullptr;       //bitmap picture uses
 
     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;
     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);
     ~Impl()
     {
         if (paint) delete(paint);
+        free(triangles);
         free(surface);
     }
 
         free(surface);
     }
 
@@ -128,7 +131,7 @@ struct Picture::Impl
 
         if (surface) {
             auto transform = resizeTransform(pTransform);
 
         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);
         } else if (paint) {
             if (resizing) {
                 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);
         return false;
     }
         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)
     {
 
     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;
     }
  
         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()
     {
         reload();
     Paint* duplicate()
     {
         reload();
@@ -238,6 +289,12 @@ struct Picture::Impl
         dup->h = h;
         dup->resizing = resizing;
 
         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();
     }
 
         return ret.release();
     }
 
index ed66f39..54ca524 100644 (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;
 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 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;
     virtual bool postRender() = 0;
     virtual bool dispose(RenderData data) = 0;
     virtual RenderRegion region(RenderData data) = 0;