Merge pull request #96167 from akien-mga/thorvg-0.14.7
thorvg: Update to 0.14.7
This commit is contained in:
commit
fe024443e3
|
@ -909,7 +909,7 @@ instead of `miniz.h` as an external dependency.
|
|||
## thorvg
|
||||
|
||||
- Upstream: https://github.com/thorvg/thorvg
|
||||
- Version: 0.14.2 (f6c4d8a94e0b2194fe911d6e19a550683055dd50, 2024)
|
||||
- Version: 0.14.7 (e3a6bf5229a9671c385ee78bc33e6e6b611a9729, 2024)
|
||||
- License: MIT
|
||||
|
||||
Files extracted from upstream source:
|
||||
|
|
|
@ -15,5 +15,5 @@
|
|||
// For internal debugging:
|
||||
//#define THORVG_LOG_ENABLED
|
||||
|
||||
#define THORVG_VERSION_STRING "0.14.2"
|
||||
#define THORVG_VERSION_STRING "0.14.7"
|
||||
#endif
|
||||
|
|
|
@ -157,7 +157,7 @@ enum class FillRule
|
|||
enum class CompositeMethod
|
||||
{
|
||||
None = 0, ///< No composition is applied.
|
||||
ClipPath, ///< The intersection of the source and the target is determined and only the resulting pixels from the source are rendered.
|
||||
ClipPath, ///< The intersection of the source and the target is determined and only the resulting pixels from the source are rendered. Note that ClipPath only supports the Shape type.
|
||||
AlphaMask, ///< Alpha Masking using the compositing target's pixels as an alpha value.
|
||||
InvAlphaMask, ///< Alpha Masking using the complement to the compositing target's pixels as an alpha value.
|
||||
LumaMask, ///< Alpha Masking using the grayscale (0.2125R + 0.7154G + 0.0721*B) of the compositing target's pixels. @since 0.9
|
||||
|
@ -165,7 +165,9 @@ enum class CompositeMethod
|
|||
AddMask, ///< Combines the target and source objects pixels using target alpha. (T * TA) + (S * (255 - TA)) (Experimental API)
|
||||
SubtractMask, ///< Subtracts the source color from the target color while considering their respective target alpha. (T * TA) - (S * (255 - TA)) (Experimental API)
|
||||
IntersectMask, ///< Computes the result by taking the minimum value between the target alpha and the source alpha and multiplies it with the target color. (T * min(TA, SA)) (Experimental API)
|
||||
DifferenceMask ///< Calculates the absolute difference between the target color and the source color multiplied by the complement of the target alpha. abs(T - S * (255 - TA)) (Experimental API)
|
||||
DifferenceMask, ///< Calculates the absolute difference between the target color and the source color multiplied by the complement of the target alpha. abs(T - S * (255 - TA)) (Experimental API)
|
||||
LightenMask, ///< Where multiple masks intersect, the highest transparency value is used. (Experimental API)
|
||||
DarkenMask ///< Where multiple masks intersect, the lowest transparency value is used. (Experimental API)
|
||||
};
|
||||
|
||||
|
||||
|
@ -232,34 +234,6 @@ struct Matrix
|
|||
};
|
||||
|
||||
|
||||
/**
|
||||
* @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)
|
||||
*
|
||||
* @note Experimental 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
|
||||
*
|
||||
* @note Experimental API
|
||||
*/
|
||||
struct Polygon
|
||||
{
|
||||
Vertex vertex[3];
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @class Paint
|
||||
*
|
||||
|
@ -361,7 +335,7 @@ public:
|
|||
*
|
||||
* @note Experimental API
|
||||
*/
|
||||
Result blend(BlendMethod method) const noexcept;
|
||||
Result blend(BlendMethod method) noexcept;
|
||||
|
||||
/**
|
||||
* @deprecated Use bounds(float* x, float* y, float* w, float* h, bool transformed) instead
|
||||
|
@ -371,15 +345,16 @@ public:
|
|||
/**
|
||||
* @brief Gets the axis-aligned bounding box of the paint object.
|
||||
*
|
||||
* In case @p transform is @c true, all object's transformations are applied first, and then the bounding box is established. Otherwise, the bounding box is determined before any transformations.
|
||||
*
|
||||
* @param[out] x The x coordinate of the upper left corner of the object.
|
||||
* @param[out] y The y coordinate of the upper left corner of the object.
|
||||
* @param[out] x The x-coordinate of the upper-left corner of the object.
|
||||
* @param[out] y The y-coordinate of the upper-left corner of the object.
|
||||
* @param[out] w The width of the object.
|
||||
* @param[out] h The height of the object.
|
||||
* @param[in] transformed If @c true, the paint's transformations are taken into account, otherwise they aren't.
|
||||
* @param[in] transformed If @c true, the paint's transformations are taken into account in the scene it belongs to. Otherwise they aren't.
|
||||
*
|
||||
* @note This is useful when you need to figure out the bounding box of the paint in the canvas space.
|
||||
* @note The bounding box doesn't indicate the actual drawing region. It's the smallest rectangle that encloses the object.
|
||||
* @note If @p transformed is @c true, the paint needs to be pushed into a canvas and updated before this api is called.
|
||||
* @see Canvas::update()
|
||||
*/
|
||||
Result bounds(float* x, float* y, float* w, float* h, bool transformed) const noexcept;
|
||||
|
||||
|
@ -411,9 +386,9 @@ public:
|
|||
CompositeMethod composite(const Paint** target) const noexcept;
|
||||
|
||||
/**
|
||||
* @brief Gets the blending method of the object.
|
||||
* @brief Retrieves the current blending method applied to the paint object.
|
||||
*
|
||||
* @return The blending method
|
||||
* @return The currently set blending method.
|
||||
*
|
||||
* @note Experimental API
|
||||
*/
|
||||
|
@ -428,6 +403,15 @@ public:
|
|||
*/
|
||||
uint32_t identifier() const noexcept;
|
||||
|
||||
/**
|
||||
* @brief Unique ID of this instance.
|
||||
*
|
||||
* This is reserved to specify an paint instance in a scene.
|
||||
*
|
||||
* @since Experimental API
|
||||
*/
|
||||
uint32_t id = 0;
|
||||
|
||||
_TVG_DECLARE_PRIVATE(Paint);
|
||||
};
|
||||
|
||||
|
@ -675,7 +659,8 @@ public:
|
|||
* @param[in] x2 The horizontal coordinate of the second point used to determine the gradient bounds.
|
||||
* @param[in] y2 The vertical coordinate of the second point used to determine the gradient bounds.
|
||||
*
|
||||
* @note In case the first and the second points are equal, an object filled with such a gradient fill is not rendered.
|
||||
* @note In case the first and the second points are equal, an object is filled with a single color using the last color specified in the colorStops().
|
||||
* @see Fill::colorStops()
|
||||
*/
|
||||
Result linear(float x1, float y1, float x2, float y2) noexcept;
|
||||
|
||||
|
@ -734,6 +719,8 @@ public:
|
|||
* @param[in] radius The radius of the bounding circle.
|
||||
*
|
||||
* @retval Result::InvalidArguments in case the @p radius value is zero or less.
|
||||
*
|
||||
* @note In case the @p radius is zero, an object is filled with a single color using the last color specified in the colorStops().
|
||||
*/
|
||||
Result radial(float cx, float cy, float radius) noexcept;
|
||||
|
||||
|
@ -990,7 +977,7 @@ public:
|
|||
/**
|
||||
* @brief Sets the trim of the stroke along the defined path segment, allowing control over which part of the stroke is visible.
|
||||
*
|
||||
* The values of the arguments @p begin, @p end, and @p offset are in the range of 0.0 to 1.0, representing the beginning of the path and the end, respectively.
|
||||
* If the values of the arguments @p begin and @p end exceed the 0-1 range, they are wrapped around in a manner similar to angle wrapping, effectively treating the range as circular.
|
||||
*
|
||||
* @param[in] begin Specifies the start of the segment to display along the path.
|
||||
* @param[in] end Specifies the end of the segment to display along the path.
|
||||
|
@ -1076,7 +1063,6 @@ public:
|
|||
* @param[out] b The blue color channel value in the range [0 ~ 255].
|
||||
* @param[out] a The alpha channel value in the range [0 ~ 255], where 0 is completely transparent and 255 is opaque.
|
||||
*
|
||||
* @return Result::Success when succeed.
|
||||
*/
|
||||
Result fillColor(uint8_t* r, uint8_t* g, uint8_t* b, uint8_t* a = nullptr) const noexcept;
|
||||
|
||||
|
@ -1219,7 +1205,7 @@ public:
|
|||
* when the @p copy has @c false. This means that loading the same data again will not result in duplicate operations
|
||||
* for the sharable @p data. Instead, ThorVG will reuse the previously loaded picture data.
|
||||
*
|
||||
* @param[in] data A pointer to a memory location where the content of the picture file is stored.
|
||||
* @param[in] data A pointer to a memory location where the content of the picture file is stored. A null-terminated string is expected for non-binary data if @p copy is @c false.
|
||||
* @param[in] size The size in bytes of the memory occupied by the @p data.
|
||||
* @param[in] mimeType Mimetype or extension of data such as "jpg", "jpeg", "lottie", "svg", "svg+xml", "png", etc. In case an empty string or an unknown type is provided, the loaders will be tried one by one.
|
||||
* @param[in] copy If @c true the data are copied into the engine local buffer, otherwise they are not.
|
||||
|
@ -1256,7 +1242,7 @@ public:
|
|||
Result size(float* w, float* h) const noexcept;
|
||||
|
||||
/**
|
||||
* @brief Loads a raw data from a memory block with a given size.
|
||||
* @brief Loads raw data in ARGB8888 format from a memory block of the given size.
|
||||
*
|
||||
* ThorVG efficiently caches the loaded data using the specified @p data address as a key
|
||||
* when the @p copy has @c false. This means that loading the same data again will not result in duplicate operations
|
||||
|
@ -1265,47 +1251,27 @@ public:
|
|||
* @param[in] data A pointer to a memory location where the content of the picture raw data is stored.
|
||||
* @param[in] w The width of the image @p data in pixels.
|
||||
* @param[in] h The height of the image @p data in pixels.
|
||||
* @param[in] premultiplied If @c true, the given image data is alpha-premultiplied.
|
||||
* @param[in] copy If @c true the data are copied into the engine local buffer, otherwise they are not.
|
||||
*
|
||||
* @note It expects premultiplied alpha data.
|
||||
* @since 0.9
|
||||
*/
|
||||
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.
|
||||
* @brief Retrieve a paint object from the Picture scene by its Unique ID.
|
||||
*
|
||||
* 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.
|
||||
* This function searches for a paint object within the Picture scene that matches the provided @p id.
|
||||
*
|
||||
* If @p triangles is @c nullptr, or @p triangleCnt is 0, the mesh will be removed.
|
||||
* @param[in] id The Unique ID of the paint object.
|
||||
*
|
||||
* 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.
|
||||
* @return A pointer to the paint object that matches the given identifier, or @c nullptr if no matching paint object is found.
|
||||
*
|
||||
* @param[in] triangles An array of Polygons(triangles) that make up the mesh, or null to remove the mesh.
|
||||
* @param[in] triangleCnt The number of Polygons(triangles) provided, or 0 to remove the mesh.
|
||||
*
|
||||
* @note The Polygons are copied internally, so modifying them after calling Mesh::mesh has no affect.
|
||||
* @warning Please do not use it, this API is not official one. It could be modified in the next version.
|
||||
* @see Accessor::id()
|
||||
*
|
||||
* @note Experimental API
|
||||
*/
|
||||
Result mesh(const Polygon* triangles, uint32_t triangleCnt) 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 The number of polygons in the array.
|
||||
*
|
||||
* @note Modifying the triangles returned by this method will modify them directly within the mesh.
|
||||
* @warning Please do not use it, this API is not official one. It could be modified in the next version.
|
||||
*
|
||||
* @note Experimental API
|
||||
*/
|
||||
uint32_t mesh(const Polygon** triangles) const noexcept;
|
||||
const Paint* paint(uint32_t id) noexcept;
|
||||
|
||||
/**
|
||||
* @brief Creates a new Picture object.
|
||||
|
@ -1454,8 +1420,6 @@ public:
|
|||
* @param[in] g The green color channel value in the range [0 ~ 255]. The default value is 0.
|
||||
* @param[in] b The blue color channel value in the range [0 ~ 255]. The default value is 0.
|
||||
*
|
||||
* @retval Result::InsufficientCondition when the font has not been set up prior to this operation.
|
||||
*
|
||||
* @see Text::font()
|
||||
*
|
||||
* @note Experimental API
|
||||
|
@ -1469,8 +1433,6 @@ public:
|
|||
*
|
||||
* @param[in] f The unique pointer to the gradient fill.
|
||||
*
|
||||
* @retval Result::InsufficientCondition when the font has not been set up prior to this operation.
|
||||
*
|
||||
* @note Either a solid color or a gradient fill is applied, depending on what was set as last.
|
||||
* @note Experimental API
|
||||
*
|
||||
|
@ -1781,6 +1743,19 @@ public:
|
|||
*/
|
||||
static Result term(CanvasEngine engine) noexcept;
|
||||
|
||||
/**
|
||||
* @brief Retrieves the version of the TVG engine.
|
||||
*
|
||||
* @param[out] major A major version number.
|
||||
* @param[out] minor A minor version number.
|
||||
* @param[out] micro A micro version number.
|
||||
*
|
||||
* @return The version of the engine in the format major.minor.micro, or a @p nullptr in case of an internal error.
|
||||
*
|
||||
* @note Experimental API
|
||||
*/
|
||||
static const char* version(uint32_t* major, uint32_t* minor, uint32_t* micro) noexcept;
|
||||
|
||||
_TVG_DISABLE_CTOR(Initializer);
|
||||
};
|
||||
|
||||
|
@ -1879,7 +1854,7 @@ public:
|
|||
* @retval Result::InsufficientCondition In case the animation is not loaded.
|
||||
* @retval Result::NonSupport When it's not animatable.
|
||||
*
|
||||
* @note Range from 0.0~1.0
|
||||
* @note Animation allows a range from 0.0 to 1.0. @p end should not be higher than @p begin.
|
||||
* @note If a marker has been specified, its range will be disregarded.
|
||||
* @see LottieAnimation::segment(const char* marker)
|
||||
* @note Experimental API
|
||||
|
@ -2030,17 +2005,36 @@ class TVG_API Accessor final
|
|||
public:
|
||||
~Accessor();
|
||||
|
||||
TVG_DEPRECATED std::unique_ptr<Picture> set(std::unique_ptr<Picture> picture, std::function<bool(const Paint* paint)> func) noexcept;
|
||||
|
||||
/**
|
||||
* @brief Set the access function for traversing the Picture scene tree nodes.
|
||||
*
|
||||
* @param[in] picture The picture node to traverse the internal scene-tree.
|
||||
* @param[in] func The callback function calling for every paint nodes of the Picture.
|
||||
*
|
||||
* @return Return the given @p picture instance.
|
||||
* @param[in] data Data passed to the @p func as its argument.
|
||||
*
|
||||
* @note The bitmap based picture might not have the scene-tree.
|
||||
*
|
||||
* @note Experimental API
|
||||
*/
|
||||
std::unique_ptr<Picture> set(std::unique_ptr<Picture> picture, std::function<bool(const Paint* paint)> func) noexcept;
|
||||
Result set(const Picture* picture, std::function<bool(const Paint* paint, void* data)> func, void* data) noexcept;
|
||||
|
||||
/**
|
||||
* @brief Generate a unique ID (hash key) from a given name.
|
||||
*
|
||||
* This function computes a unique identifier value based on the provided string.
|
||||
* You can use this to assign a unique ID to the Paint object.
|
||||
*
|
||||
* @param[in] name The input string to generate the unique identifier from.
|
||||
*
|
||||
* @return The generated unique identifier value.
|
||||
*
|
||||
* @see Paint::id
|
||||
*
|
||||
* @note Experimental API
|
||||
*/
|
||||
static uint32_t id(const char* name) noexcept;
|
||||
|
||||
/**
|
||||
* @brief Creates a new Accessor object.
|
||||
|
|
|
@ -59,7 +59,7 @@ struct Array
|
|||
data[count++] = element;
|
||||
}
|
||||
|
||||
void push(Array<T>& rhs)
|
||||
void push(const Array<T>& rhs)
|
||||
{
|
||||
if (rhs.count == 0) return;
|
||||
grow(rhs.count);
|
||||
|
|
|
@ -478,6 +478,8 @@ size_t b64Decode(const char* encoded, const size_t len, char** decoded)
|
|||
|
||||
unsigned long djb2Encode(const char* str)
|
||||
{
|
||||
if (!str) return 0;
|
||||
|
||||
unsigned long hash = 5381;
|
||||
int c;
|
||||
|
||||
|
|
|
@ -100,7 +100,7 @@ struct Inlist
|
|||
if (element == tail) tail = element->prev;
|
||||
}
|
||||
|
||||
bool empty()
|
||||
bool empty() const
|
||||
{
|
||||
return head ? false : true;
|
||||
}
|
||||
|
|
|
@ -79,7 +79,7 @@ float _bezAt(const Bezier& bz, float at, float length, LengthFunc lineLengthFunc
|
|||
Bezier left;
|
||||
bezSplitLeft(right, t, left);
|
||||
length = _bezLength(left, lineLengthFunc);
|
||||
if (fabsf(length - at) < BEZIER_EPSILON || fabsf(smallest - biggest) < BEZIER_EPSILON) {
|
||||
if (fabsf(length - at) < BEZIER_EPSILON || fabsf(smallest - biggest) < 1e-3f) {
|
||||
break;
|
||||
}
|
||||
if (length < at) {
|
||||
|
|
|
@ -25,8 +25,6 @@
|
|||
|
||||
#ifdef THORVG_THREAD_SUPPORT
|
||||
|
||||
#define _DISABLE_CONSTEXPR_MUTEX_CONSTRUCTOR
|
||||
|
||||
#include <mutex>
|
||||
#include "tvgTaskScheduler.h"
|
||||
|
||||
|
|
|
@ -78,17 +78,17 @@ bool mathIdentity(const Matrix* m);
|
|||
Matrix operator*(const Matrix& lhs, const Matrix& rhs);
|
||||
bool operator==(const Matrix& lhs, const Matrix& rhs);
|
||||
|
||||
static inline bool mathRightAngle(const Matrix* m)
|
||||
static inline bool mathRightAngle(const Matrix& m)
|
||||
{
|
||||
auto radian = fabsf(mathAtan2(m->e21, m->e11));
|
||||
auto radian = fabsf(mathAtan2(m.e21, m.e11));
|
||||
if (radian < FLOAT_EPSILON || mathEqual(radian, MATH_PI2) || mathEqual(radian, MATH_PI)) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
static inline bool mathSkewed(const Matrix* m)
|
||||
static inline bool mathSkewed(const Matrix& m)
|
||||
{
|
||||
return !mathZero(m->e21 + m->e12);
|
||||
return !mathZero(m.e21 + m.e12);
|
||||
}
|
||||
|
||||
|
||||
|
@ -233,6 +233,17 @@ static inline Point operator/(const Point& lhs, const float rhs)
|
|||
}
|
||||
|
||||
|
||||
static inline Point mathNormal(const Point& p1, const Point& p2)
|
||||
{
|
||||
auto dir = p2 - p1;
|
||||
auto len = mathLength(dir);
|
||||
if (mathZero(len)) return {};
|
||||
|
||||
auto unitDir = dir / len;
|
||||
return {-unitDir.y, unitDir.x};
|
||||
}
|
||||
|
||||
|
||||
static inline void mathLog(const Point& pt)
|
||||
{
|
||||
TVGLOG("COMMON", "Point: [%f %f]", pt.x, pt.y);
|
||||
|
|
|
@ -710,15 +710,16 @@ static bool _toColor(const char* str, uint8_t* r, uint8_t* g, uint8_t* b, char**
|
|||
return true;
|
||||
} else if (len >= 10 && (str[0] == 'h' || str[0] == 'H') && (str[1] == 's' || str[1] == 'S') && (str[2] == 'l' || str[2] == 'L') && str[3] == '(' && str[len - 1] == ')') {
|
||||
float th, ts, tb;
|
||||
const char *content, *hue, *saturation, *brightness;
|
||||
content = str + 4;
|
||||
content = _skipSpace(content, nullptr);
|
||||
const char* content = _skipSpace(str + 4, nullptr);
|
||||
const char* hue = nullptr;
|
||||
if (_parseNumber(&content, &hue, &th) && hue) {
|
||||
const char* saturation = nullptr;
|
||||
th = float(uint32_t(th) % 360);
|
||||
hue = _skipSpace(hue, nullptr);
|
||||
hue = (char*)_skipComma(hue);
|
||||
hue = _skipSpace(hue, nullptr);
|
||||
if (_parseNumber(&hue, &saturation, &ts) && saturation && *saturation == '%') {
|
||||
const char* brightness = nullptr;
|
||||
ts /= 100.0f;
|
||||
saturation = _skipSpace(saturation + 1, nullptr);
|
||||
saturation = (char*)_skipComma(saturation);
|
||||
|
|
|
@ -134,7 +134,6 @@ struct SwFill
|
|||
{
|
||||
struct SwLinear {
|
||||
float dx, dy;
|
||||
float len;
|
||||
float offset;
|
||||
};
|
||||
|
||||
|
@ -154,6 +153,7 @@ struct SwFill
|
|||
uint32_t* ctable;
|
||||
FillSpread spread;
|
||||
|
||||
bool solid = false; //solid color fill with the last color from colorStops
|
||||
bool translucent;
|
||||
};
|
||||
|
||||
|
@ -301,8 +301,8 @@ static inline uint32_t JOIN(uint8_t c0, uint8_t c1, uint8_t c2, uint8_t c3)
|
|||
|
||||
static inline uint32_t ALPHA_BLEND(uint32_t c, uint32_t a)
|
||||
{
|
||||
return (((((c >> 8) & 0x00ff00ff) * a + 0x00ff00ff) & 0xff00ff00) +
|
||||
((((c & 0x00ff00ff) * a + 0x00ff00ff) >> 8) & 0x00ff00ff));
|
||||
++a;
|
||||
return (((((c >> 8) & 0x00ff00ff) * a) & 0xff00ff00) + ((((c & 0x00ff00ff) * a) >> 8) & 0x00ff00ff));
|
||||
}
|
||||
|
||||
static inline uint32_t INTERPOLATE(uint32_t s, uint32_t d, uint8_t a)
|
||||
|
@ -494,38 +494,39 @@ SwFixed mathDiff(SwFixed angle1, SwFixed angle2);
|
|||
SwFixed mathLength(const SwPoint& pt);
|
||||
bool mathSmallCubic(const SwPoint* base, SwFixed& angleIn, SwFixed& angleMid, SwFixed& angleOut);
|
||||
SwFixed mathMean(SwFixed angle1, SwFixed angle2);
|
||||
SwPoint mathTransform(const Point* to, const Matrix* transform);
|
||||
SwPoint mathTransform(const Point* to, const Matrix& transform);
|
||||
bool mathUpdateOutlineBBox(const SwOutline* outline, const SwBBox& clipRegion, SwBBox& renderRegion, bool fastTrack);
|
||||
bool mathClipBBox(const SwBBox& clipper, SwBBox& clipee);
|
||||
|
||||
void shapeReset(SwShape* shape);
|
||||
bool shapePrepare(SwShape* shape, const RenderShape* rshape, const Matrix* transform, const SwBBox& clipRegion, SwBBox& renderRegion, SwMpool* mpool, unsigned tid, bool hasComposite);
|
||||
bool shapePrepare(SwShape* shape, const RenderShape* rshape, const Matrix& transform, const SwBBox& clipRegion, SwBBox& renderRegion, SwMpool* mpool, unsigned tid, bool hasComposite);
|
||||
bool shapePrepared(const SwShape* shape);
|
||||
bool shapeGenRle(SwShape* shape, const RenderShape* rshape, bool antiAlias);
|
||||
void shapeDelOutline(SwShape* shape, SwMpool* mpool, uint32_t tid);
|
||||
void shapeResetStroke(SwShape* shape, const RenderShape* rshape, const Matrix* transform);
|
||||
bool shapeGenStrokeRle(SwShape* shape, const RenderShape* rshape, const Matrix* transform, const SwBBox& clipRegion, SwBBox& renderRegion, SwMpool* mpool, unsigned tid);
|
||||
void shapeResetStroke(SwShape* shape, const RenderShape* rshape, const Matrix& transform);
|
||||
bool shapeGenStrokeRle(SwShape* shape, const RenderShape* rshape, const Matrix& transform, const SwBBox& clipRegion, SwBBox& renderRegion, SwMpool* mpool, unsigned tid);
|
||||
void shapeFree(SwShape* shape);
|
||||
void shapeDelStroke(SwShape* shape);
|
||||
bool shapeGenFillColors(SwShape* shape, const Fill* fill, const Matrix* transform, SwSurface* surface, uint8_t opacity, bool ctable);
|
||||
bool shapeGenStrokeFillColors(SwShape* shape, const Fill* fill, const Matrix* transform, SwSurface* surface, uint8_t opacity, bool ctable);
|
||||
bool shapeGenFillColors(SwShape* shape, const Fill* fill, const Matrix& transform, SwSurface* surface, uint8_t opacity, bool ctable);
|
||||
bool shapeGenStrokeFillColors(SwShape* shape, const Fill* fill, const Matrix& transform, SwSurface* surface, uint8_t opacity, bool ctable);
|
||||
void shapeResetFill(SwShape* shape);
|
||||
void shapeResetStrokeFill(SwShape* shape);
|
||||
void shapeDelFill(SwShape* shape);
|
||||
void shapeDelStrokeFill(SwShape* shape);
|
||||
|
||||
void strokeReset(SwStroke* stroke, const RenderShape* shape, const Matrix* transform);
|
||||
void strokeReset(SwStroke* stroke, const RenderShape* shape, const Matrix& transform);
|
||||
bool strokeParseOutline(SwStroke* stroke, const SwOutline& outline);
|
||||
SwOutline* strokeExportOutline(SwStroke* stroke, SwMpool* mpool, unsigned tid);
|
||||
void strokeFree(SwStroke* stroke);
|
||||
|
||||
bool imagePrepare(SwImage* image, const RenderMesh* mesh, const Matrix* transform, const SwBBox& clipRegion, SwBBox& renderRegion, SwMpool* mpool, unsigned tid);
|
||||
bool imagePrepare(SwImage* image, 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);
|
||||
void imageFree(SwImage* image);
|
||||
|
||||
bool fillGenColorTable(SwFill* fill, const Fill* fdata, const Matrix* transform, SwSurface* surface, uint8_t opacity, bool ctable);
|
||||
bool fillGenColorTable(SwFill* fill, const Fill* fdata, const Matrix& transform, SwSurface* surface, uint8_t opacity, bool ctable);
|
||||
const Fill::ColorStop* fillFetchSolid(const SwFill* fill, const Fill* fdata);
|
||||
void fillReset(SwFill* fill);
|
||||
void fillFree(SwFill* fill);
|
||||
|
||||
|
@ -561,11 +562,11 @@ SwOutline* mpoolReqDashOutline(SwMpool* mpool, unsigned idx);
|
|||
void mpoolRetDashOutline(SwMpool* mpool, unsigned idx);
|
||||
|
||||
bool rasterCompositor(SwSurface* surface);
|
||||
bool rasterGradientShape(SwSurface* surface, SwShape* shape, unsigned id);
|
||||
bool rasterGradientShape(SwSurface* surface, SwShape* shape, const Fill* fdata, uint8_t opacity);
|
||||
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 RenderMesh* mesh, const Matrix* transform, const SwBBox& bbox, uint8_t opacity);
|
||||
bool rasterImage(SwSurface* surface, SwImage* image, const Matrix& transform, const SwBBox& bbox, uint8_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 rasterGradientStroke(SwSurface* surface, SwShape* shape, const Fill* fdata, uint8_t opacity);
|
||||
bool rasterClear(SwSurface* surface, uint32_t x, uint32_t y, uint32_t w, uint32_t h);
|
||||
void rasterPixel32(uint32_t *dst, uint32_t val, uint32_t offset, int32_t len);
|
||||
void rasterGrayscale8(uint8_t *dst, uint8_t val, uint32_t offset, int32_t len);
|
||||
|
|
|
@ -58,7 +58,7 @@ static void _calculateCoefficients(const SwFill* fill, uint32_t x, uint32_t y, f
|
|||
auto deltaDeltaRr = 2.0f * (radial->a11 * radial->a11 + radial->a21 * radial->a21) * radial->invA;
|
||||
|
||||
det = b * b + (rr - radial->fr * radial->fr) * radial->invA;
|
||||
deltaDet = 2.0f * b * deltaB + deltaB * deltaB + deltaRr + deltaDeltaRr;
|
||||
deltaDet = 2.0f * b * deltaB + deltaB * deltaB + deltaRr + deltaDeltaRr * 0.5f;
|
||||
deltaDeltaDet = 2.0f * deltaB * deltaB + deltaDeltaRr;
|
||||
}
|
||||
|
||||
|
@ -125,6 +125,8 @@ static void _applyAA(const SwFill* fill, uint32_t begin, uint32_t end)
|
|||
|
||||
static bool _updateColorTable(SwFill* fill, const Fill* fdata, const SwSurface* surface, uint8_t opacity)
|
||||
{
|
||||
if (fill->solid) return true;
|
||||
|
||||
if (!fill->ctable) {
|
||||
fill->ctable = static_cast<uint32_t*>(malloc(GRADIENT_STOP_SIZE * sizeof(uint32_t)));
|
||||
if (!fill->ctable) return false;
|
||||
|
@ -205,28 +207,33 @@ static bool _updateColorTable(SwFill* fill, const Fill* fdata, const SwSurface*
|
|||
}
|
||||
|
||||
|
||||
bool _prepareLinear(SwFill* fill, const LinearGradient* linear, const Matrix* transform)
|
||||
bool _prepareLinear(SwFill* fill, const LinearGradient* linear, const Matrix& transform)
|
||||
{
|
||||
float x1, x2, y1, y2;
|
||||
if (linear->linear(&x1, &y1, &x2, &y2) != Result::Success) return false;
|
||||
|
||||
fill->linear.dx = x2 - x1;
|
||||
fill->linear.dy = y2 - y1;
|
||||
fill->linear.len = fill->linear.dx * fill->linear.dx + fill->linear.dy * fill->linear.dy;
|
||||
auto len = fill->linear.dx * fill->linear.dx + fill->linear.dy * fill->linear.dy;
|
||||
|
||||
if (fill->linear.len < FLOAT_EPSILON) return true;
|
||||
if (len < FLOAT_EPSILON) {
|
||||
if (mathZero(fill->linear.dx) && mathZero(fill->linear.dy)) {
|
||||
fill->solid = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
fill->linear.dx /= fill->linear.len;
|
||||
fill->linear.dy /= fill->linear.len;
|
||||
fill->linear.dx /= len;
|
||||
fill->linear.dy /= len;
|
||||
fill->linear.offset = -fill->linear.dx * x1 - fill->linear.dy * y1;
|
||||
|
||||
auto gradTransform = linear->transform();
|
||||
bool isTransformation = !mathIdentity((const Matrix*)(&gradTransform));
|
||||
|
||||
if (isTransformation) {
|
||||
if (transform) gradTransform = *transform * gradTransform;
|
||||
} else if (transform) {
|
||||
gradTransform = *transform;
|
||||
gradTransform = transform * gradTransform;
|
||||
} else {
|
||||
gradTransform = transform;
|
||||
isTransformation = true;
|
||||
}
|
||||
|
||||
|
@ -239,15 +246,13 @@ bool _prepareLinear(SwFill* fill, const LinearGradient* linear, const Matrix* tr
|
|||
auto dx = fill->linear.dx;
|
||||
fill->linear.dx = dx * invTransform.e11 + fill->linear.dy * invTransform.e21;
|
||||
fill->linear.dy = dx * invTransform.e12 + fill->linear.dy * invTransform.e22;
|
||||
|
||||
fill->linear.len = fill->linear.dx * fill->linear.dx + fill->linear.dy * fill->linear.dy;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool _prepareRadial(SwFill* fill, const RadialGradient* radial, const Matrix* transform)
|
||||
bool _prepareRadial(SwFill* fill, const RadialGradient* radial, const Matrix& transform)
|
||||
{
|
||||
auto cx = P(radial)->cx;
|
||||
auto cy = P(radial)->cy;
|
||||
|
@ -256,7 +261,10 @@ bool _prepareRadial(SwFill* fill, const RadialGradient* radial, const Matrix* tr
|
|||
auto fy = P(radial)->fy;
|
||||
auto fr = P(radial)->fr;
|
||||
|
||||
if (r < FLOAT_EPSILON) return true;
|
||||
if (mathZero(r)) {
|
||||
fill->solid = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
fill->radial.dr = r - fr;
|
||||
fill->radial.dx = cx - fx;
|
||||
|
@ -289,12 +297,10 @@ bool _prepareRadial(SwFill* fill, const RadialGradient* radial, const Matrix* tr
|
|||
auto gradTransform = radial->transform();
|
||||
bool isTransformation = !mathIdentity((const Matrix*)(&gradTransform));
|
||||
|
||||
if (transform) {
|
||||
if (isTransformation) gradTransform = *transform * gradTransform;
|
||||
else {
|
||||
gradTransform = *transform;
|
||||
isTransformation = true;
|
||||
}
|
||||
if (isTransformation) gradTransform = transform * gradTransform;
|
||||
else {
|
||||
gradTransform = transform;
|
||||
isTransformation = true;
|
||||
}
|
||||
|
||||
if (isTransformation) {
|
||||
|
@ -816,25 +822,32 @@ void fillLinear(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint3
|
|||
}
|
||||
|
||||
|
||||
bool fillGenColorTable(SwFill* fill, const Fill* fdata, const Matrix* transform, SwSurface* surface, uint8_t opacity, bool ctable)
|
||||
bool fillGenColorTable(SwFill* fill, const Fill* fdata, const Matrix& transform, SwSurface* surface, uint8_t opacity, bool ctable)
|
||||
{
|
||||
if (!fill) return false;
|
||||
|
||||
fill->spread = fdata->spread();
|
||||
|
||||
if (ctable) {
|
||||
if (!_updateColorTable(fill, fdata, surface, opacity)) return false;
|
||||
}
|
||||
|
||||
if (fdata->identifier() == TVG_CLASS_ID_LINEAR) {
|
||||
return _prepareLinear(fill, static_cast<const LinearGradient*>(fdata), transform);
|
||||
if (!_prepareLinear(fill, static_cast<const LinearGradient*>(fdata), transform)) return false;
|
||||
} else if (fdata->identifier() == TVG_CLASS_ID_RADIAL) {
|
||||
return _prepareRadial(fill, static_cast<const RadialGradient*>(fdata), transform);
|
||||
if (!_prepareRadial(fill, static_cast<const RadialGradient*>(fdata), transform)) return false;
|
||||
}
|
||||
|
||||
//LOG: What type of gradient?!
|
||||
if (ctable) return _updateColorTable(fill, fdata, surface, opacity);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
const Fill::ColorStop* fillFetchSolid(const SwFill* fill, const Fill* fdata)
|
||||
{
|
||||
if (!fill->solid) return nullptr;
|
||||
|
||||
const Fill::ColorStop* colors;
|
||||
auto cnt = fdata->colorStops(&colors);
|
||||
if (cnt == 0 || !colors) return nullptr;
|
||||
|
||||
return colors + cnt - 1;
|
||||
}
|
||||
|
||||
|
||||
|
@ -845,6 +858,7 @@ void fillReset(SwFill* fill)
|
|||
fill->ctable = nullptr;
|
||||
}
|
||||
fill->translucent = false;
|
||||
fill->solid = false;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -27,14 +27,14 @@
|
|||
/* Internal Class Implementation */
|
||||
/************************************************************************/
|
||||
|
||||
static inline bool _onlyShifted(const Matrix* m)
|
||||
static inline bool _onlyShifted(const Matrix& m)
|
||||
{
|
||||
if (mathEqual(m->e11, 1.0f) && mathEqual(m->e22, 1.0f) && mathZero(m->e12) && mathZero(m->e21)) return true;
|
||||
if (mathEqual(m.e11, 1.0f) && mathEqual(m.e22, 1.0f) && mathZero(m.e12) && mathZero(m.e21)) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
static bool _genOutline(SwImage* image, const RenderMesh* mesh, const Matrix* transform, SwMpool* mpool, unsigned tid)
|
||||
static bool _genOutline(SwImage* image, const Matrix& transform, SwMpool* mpool, unsigned tid)
|
||||
{
|
||||
image->outline = mpoolReqOutline(mpool, tid);
|
||||
auto outline = image->outline;
|
||||
|
@ -45,48 +45,12 @@ static bool _genOutline(SwImage* image, const RenderMesh* mesh, const Matrix* tr
|
|||
outline->closed.reserve(1);
|
||||
|
||||
Point to[4];
|
||||
if (mesh->triangleCnt > 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:
|
||||
// tvgPicture.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?
|
||||
auto triangles = mesh->triangles;
|
||||
auto min = triangles[0].vertex[0].pt;
|
||||
auto max = triangles[0].vertex[0].pt;
|
||||
|
||||
for (uint32_t i = 0; i < mesh->triangleCnt; ++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};
|
||||
}
|
||||
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.push(mathTransform(&to[i], transform));
|
||||
|
@ -108,25 +72,25 @@ static bool _genOutline(SwImage* image, const RenderMesh* mesh, const Matrix* tr
|
|||
/* External Class Implementation */
|
||||
/************************************************************************/
|
||||
|
||||
bool imagePrepare(SwImage* image, const RenderMesh* mesh, const Matrix* transform, const SwBBox& clipRegion, SwBBox& renderRegion, SwMpool* mpool, unsigned tid)
|
||||
bool imagePrepare(SwImage* image, const Matrix& transform, const SwBBox& clipRegion, SwBBox& renderRegion, SwMpool* mpool, unsigned tid)
|
||||
{
|
||||
image->direct = _onlyShifted(transform);
|
||||
|
||||
//Fast track: Non-transformed image but just shifted.
|
||||
if (image->direct) {
|
||||
image->ox = -static_cast<int32_t>(nearbyint(transform->e13));
|
||||
image->oy = -static_cast<int32_t>(nearbyint(transform->e23));
|
||||
image->ox = -static_cast<int32_t>(nearbyint(transform.e13));
|
||||
image->oy = -static_cast<int32_t>(nearbyint(transform.e23));
|
||||
//Figure out the scale factor by transform matrix
|
||||
} else {
|
||||
auto scaleX = sqrtf((transform->e11 * transform->e11) + (transform->e21 * transform->e21));
|
||||
auto scaleY = sqrtf((transform->e22 * transform->e22) + (transform->e12 * transform->e12));
|
||||
auto scaleX = sqrtf((transform.e11 * transform.e11) + (transform.e21 * transform.e21));
|
||||
auto scaleY = sqrtf((transform.e22 * transform.e22) + (transform.e12 * transform.e12));
|
||||
image->scale = (fabsf(scaleX - scaleY) > 0.01f) ? 1.0f : scaleX;
|
||||
|
||||
if (mathZero(transform->e12) && mathZero(transform->e21)) image->scaled = true;
|
||||
if (mathZero(transform.e12) && mathZero(transform.e21)) image->scaled = true;
|
||||
else image->scaled = false;
|
||||
}
|
||||
|
||||
if (!_genOutline(image, mesh, transform, mpool, tid)) return false;
|
||||
if (!_genOutline(image, transform, mpool, tid)) return false;
|
||||
return mathUpdateOutlineBBox(image->outline, clipRegion, renderRegion, image->direct);
|
||||
}
|
||||
|
||||
|
|
|
@ -254,12 +254,10 @@ SwFixed mathDiff(SwFixed angle1, SwFixed angle2)
|
|||
}
|
||||
|
||||
|
||||
SwPoint mathTransform(const Point* to, const Matrix* transform)
|
||||
SwPoint mathTransform(const Point* to, const Matrix& transform)
|
||||
{
|
||||
if (!transform) return {TO_SWCOORD(to->x), TO_SWCOORD(to->y)};
|
||||
|
||||
auto tx = to->x * transform->e11 + to->y * transform->e12 + transform->e13;
|
||||
auto ty = to->x * transform->e21 + to->y * transform->e22 + transform->e23;
|
||||
auto tx = to->x * transform.e11 + to->y * transform.e12 + transform.e13;
|
||||
auto ty = to->x * transform.e21 + to->y * transform.e22 + transform.e23;
|
||||
|
||||
return {TO_SWCOORD(tx), TO_SWCOORD(ty)};
|
||||
}
|
||||
|
|
|
@ -194,10 +194,21 @@ static inline uint8_t _opMaskDifference(uint8_t s, uint8_t d, uint8_t a)
|
|||
}
|
||||
|
||||
|
||||
static inline uint8_t _opMaskLighten(uint8_t s, uint8_t d, uint8_t a)
|
||||
{
|
||||
return (s > d) ? s : d;
|
||||
}
|
||||
|
||||
|
||||
static inline uint8_t _opMaskDarken(uint8_t s, uint8_t d, uint8_t a)
|
||||
{
|
||||
return (s < d) ? s : d;
|
||||
}
|
||||
|
||||
|
||||
static inline bool _direct(CompositeMethod method)
|
||||
{
|
||||
//subtract & Intersect allows the direct composition
|
||||
if (method == CompositeMethod::SubtractMask || method == CompositeMethod::IntersectMask) return true;
|
||||
if (method == CompositeMethod::SubtractMask || method == CompositeMethod::IntersectMask || method == CompositeMethod::DarkenMask) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -209,6 +220,8 @@ static inline SwMask _getMaskOp(CompositeMethod method)
|
|||
case CompositeMethod::SubtractMask: return _opMaskSubtract;
|
||||
case CompositeMethod::DifferenceMask: return _opMaskDifference;
|
||||
case CompositeMethod::IntersectMask: return _opMaskIntersect;
|
||||
case CompositeMethod::LightenMask: return _opMaskLighten;
|
||||
case CompositeMethod::DarkenMask: return _opMaskDarken;
|
||||
default: return nullptr;
|
||||
}
|
||||
}
|
||||
|
@ -832,7 +845,7 @@ static bool _rasterScaledRleImage(SwSurface* surface, const SwImage* image, cons
|
|||
}
|
||||
|
||||
|
||||
static bool _scaledRleImage(SwSurface* surface, const SwImage* image, const Matrix* transform, const SwBBox& region, uint8_t opacity)
|
||||
static bool _scaledRleImage(SwSurface* surface, const SwImage* image, const Matrix& transform, const SwBBox& region, uint8_t opacity)
|
||||
{
|
||||
if (surface->channelSize == sizeof(uint8_t)) {
|
||||
TVGERR("SW_ENGINE", "Not supported scaled rle image!");
|
||||
|
@ -841,9 +854,7 @@ static bool _scaledRleImage(SwSurface* surface, const SwImage* image, const Matr
|
|||
|
||||
Matrix itransform;
|
||||
|
||||
if (transform) {
|
||||
if (!mathInverse(transform, &itransform)) return false;
|
||||
} else mathIdentity(&itransform);
|
||||
if (!mathInverse(&transform, &itransform)) return true;
|
||||
|
||||
if (_compositing(surface)) {
|
||||
if (_matting(surface)) return _rasterScaledMattedRleImage(surface, image, &itransform, region, opacity);
|
||||
|
@ -1197,13 +1208,11 @@ static bool _rasterScaledImage(SwSurface* surface, const SwImage* image, const M
|
|||
}
|
||||
|
||||
|
||||
static bool _scaledImage(SwSurface* surface, const SwImage* image, const Matrix* transform, const SwBBox& region, uint8_t opacity)
|
||||
static bool _scaledImage(SwSurface* surface, const SwImage* image, const Matrix& transform, const SwBBox& region, uint8_t opacity)
|
||||
{
|
||||
Matrix itransform;
|
||||
|
||||
if (transform) {
|
||||
if (!mathInverse(transform, &itransform)) return false;
|
||||
} else mathIdentity(&itransform);
|
||||
if (!mathInverse(&transform, &itransform)) return true;
|
||||
|
||||
if (_compositing(surface)) {
|
||||
if (_matting(surface)) return _rasterScaledMattedImage(surface, image, &itransform, region, opacity);
|
||||
|
@ -1389,29 +1398,45 @@ static bool _rasterDirectBlendingImage(SwSurface* surface, const SwImage* image,
|
|||
|
||||
static bool _rasterDirectImage(SwSurface* surface, const SwImage* image, const SwBBox& region, uint8_t opacity)
|
||||
{
|
||||
if (surface->channelSize == sizeof(uint8_t)) {
|
||||
TVGERR("SW_ENGINE", "Not supported grayscale image!");
|
||||
return false;
|
||||
}
|
||||
|
||||
auto dbuffer = &surface->buf32[region.min.y * surface->stride + region.min.x];
|
||||
auto sbuffer = image->buf32 + (region.min.y + image->oy) * image->stride + (region.min.x + image->ox);
|
||||
|
||||
for (auto y = region.min.y; y < region.max.y; ++y) {
|
||||
auto dst = dbuffer;
|
||||
auto src = sbuffer;
|
||||
if (opacity == 255) {
|
||||
for (auto x = region.min.x; x < region.max.x; x++, dst++, src++) {
|
||||
*dst = *src + ALPHA_BLEND(*dst, IA(*src));
|
||||
//32bits channels
|
||||
if (surface->channelSize == sizeof(uint32_t)) {
|
||||
auto dbuffer = &surface->buf32[region.min.y * surface->stride + region.min.x];
|
||||
|
||||
for (auto y = region.min.y; y < region.max.y; ++y) {
|
||||
auto dst = dbuffer;
|
||||
auto src = sbuffer;
|
||||
if (opacity == 255) {
|
||||
for (auto x = region.min.x; x < region.max.x; x++, dst++, src++) {
|
||||
*dst = *src + ALPHA_BLEND(*dst, IA(*src));
|
||||
}
|
||||
} else {
|
||||
for (auto x = region.min.x; x < region.max.x; ++x, ++dst, ++src) {
|
||||
auto tmp = ALPHA_BLEND(*src, opacity);
|
||||
*dst = tmp + ALPHA_BLEND(*dst, IA(tmp));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (auto x = region.min.x; x < region.max.x; ++x, ++dst, ++src) {
|
||||
auto tmp = ALPHA_BLEND(*src, opacity);
|
||||
*dst = tmp + ALPHA_BLEND(*dst, IA(tmp));
|
||||
dbuffer += surface->stride;
|
||||
sbuffer += image->stride;
|
||||
}
|
||||
//8bits grayscale
|
||||
} else if (surface->channelSize == sizeof(uint8_t)) {
|
||||
auto dbuffer = &surface->buf8[region.min.y * surface->stride + region.min.x];
|
||||
|
||||
for (auto y = region.min.y; y < region.max.y; ++y, dbuffer += surface->stride, sbuffer += image->stride) {
|
||||
auto dst = dbuffer;
|
||||
auto src = sbuffer;
|
||||
if (opacity == 255) {
|
||||
for (auto x = region.min.x; x < region.max.x; ++x, ++dst, ++src) {
|
||||
*dst = *src + MULTIPLY(*dst, ~*src);
|
||||
}
|
||||
} else {
|
||||
for (auto x = region.min.x; x < region.max.x; ++x, ++dst, ++src) {
|
||||
*dst = INTERPOLATE8(*src, *dst, opacity);
|
||||
}
|
||||
}
|
||||
}
|
||||
dbuffer += surface->stride;
|
||||
sbuffer += image->stride;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -1433,7 +1458,7 @@ static bool _directImage(SwSurface* surface, const SwImage* image, const SwBBox&
|
|||
|
||||
|
||||
//Blenders for the following scenarios: [RLE / Whole] * [Direct / Scaled / Transformed]
|
||||
static bool _rasterImage(SwSurface* surface, SwImage* image, const Matrix* transform, const SwBBox& region, uint8_t opacity)
|
||||
static bool _rasterImage(SwSurface* surface, SwImage* image, const Matrix& transform, const SwBBox& region, uint8_t opacity)
|
||||
{
|
||||
//RLE Image
|
||||
if (image->rle) {
|
||||
|
@ -1574,8 +1599,6 @@ static bool _rasterSolidGradientRect(SwSurface* surface, const SwBBox& region, c
|
|||
|
||||
static bool _rasterLinearGradientRect(SwSurface* surface, const SwBBox& region, const SwFill* fill)
|
||||
{
|
||||
if (fill->linear.len < FLOAT_EPSILON) return false;
|
||||
|
||||
if (_compositing(surface)) {
|
||||
if (_matting(surface)) return _rasterGradientMattedRect<FillLinear>(surface, region, fill);
|
||||
else return _rasterGradientMaskedRect<FillLinear>(surface, region, fill);
|
||||
|
@ -1902,10 +1925,16 @@ void rasterPremultiply(Surface* surface)
|
|||
}
|
||||
|
||||
|
||||
bool rasterGradientShape(SwSurface* surface, SwShape* shape, unsigned id)
|
||||
bool rasterGradientShape(SwSurface* surface, SwShape* shape, const Fill* fdata, uint8_t opacity)
|
||||
{
|
||||
if (!shape->fill) return false;
|
||||
|
||||
if (auto color = fillFetchSolid(shape->fill, fdata)) {
|
||||
auto a = MULTIPLY(color->a, opacity);
|
||||
return a > 0 ? rasterShape(surface, shape, color->r, color->g, color->b, a) : true;
|
||||
}
|
||||
|
||||
auto id = fdata->identifier();
|
||||
if (shape->fastTrack) {
|
||||
if (id == TVG_CLASS_ID_LINEAR) return _rasterLinearGradientRect(surface, shape->bbox, shape->fill);
|
||||
else if (id == TVG_CLASS_ID_RADIAL)return _rasterRadialGradientRect(surface, shape->bbox, shape->fill);
|
||||
|
@ -1917,10 +1946,16 @@ bool rasterGradientShape(SwSurface* surface, SwShape* shape, unsigned id)
|
|||
}
|
||||
|
||||
|
||||
bool rasterGradientStroke(SwSurface* surface, SwShape* shape, unsigned id)
|
||||
bool rasterGradientStroke(SwSurface* surface, SwShape* shape, const Fill* fdata, uint8_t opacity)
|
||||
{
|
||||
if (!shape->stroke || !shape->stroke->fill || !shape->strokeRle) return false;
|
||||
|
||||
if (auto color = fillFetchSolid(shape->stroke->fill, fdata)) {
|
||||
auto a = MULTIPLY(color->a, opacity);
|
||||
return a > 0 ? rasterStroke(surface, shape, color->r, color->g, color->b, a) : true;
|
||||
}
|
||||
|
||||
auto id = fdata->identifier();
|
||||
if (id == TVG_CLASS_ID_LINEAR) return _rasterLinearGradientRle(surface, shape->strokeRle, shape->stroke->fill);
|
||||
else if (id == TVG_CLASS_ID_RADIAL) return _rasterRadialGradientRle(surface, shape->strokeRle, shape->stroke->fill);
|
||||
|
||||
|
@ -1952,13 +1987,12 @@ bool rasterStroke(SwSurface* surface, SwShape* shape, uint8_t r, uint8_t g, uint
|
|||
}
|
||||
|
||||
|
||||
bool rasterImage(SwSurface* surface, SwImage* image, const RenderMesh* mesh, const Matrix* transform, const SwBBox& bbox, uint8_t opacity)
|
||||
bool rasterImage(SwSurface* surface, SwImage* image, const Matrix& transform, const SwBBox& bbox, uint8_t opacity)
|
||||
{
|
||||
//Outside of the viewport, skip the rendering
|
||||
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 true;
|
||||
|
||||
if (mesh && mesh->triangleCnt > 0) return _rasterTexmapPolygonMesh(surface, image, mesh, transform, &bbox, opacity);
|
||||
else return _rasterImage(surface, image, transform, bbox, opacity);
|
||||
return _rasterImage(surface, image, transform, bbox, opacity);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -53,12 +53,10 @@ static bool _arrange(const SwImage* image, const SwBBox* region, int& yStart, in
|
|||
regionBottom = image->rle->spans[image->rle->size - 1].y;
|
||||
}
|
||||
|
||||
if (yStart >= regionBottom) return false;
|
||||
|
||||
if (yStart < regionTop) yStart = regionTop;
|
||||
if (yEnd > regionBottom) yEnd = regionBottom;
|
||||
|
||||
return true;
|
||||
return yEnd > yStart;
|
||||
}
|
||||
|
||||
|
||||
|
@ -868,10 +866,8 @@ static void _calcVertCoverage(AALine *lines, int32_t eidx, int32_t y, int32_t re
|
|||
|
||||
static void _calcHorizCoverage(AALine *lines, int32_t eidx, int32_t y, int32_t x, int32_t x2)
|
||||
{
|
||||
if (lines[y].length[eidx] < abs(x - x2)) {
|
||||
lines[y].length[eidx] = abs(x - x2);
|
||||
lines[y].coverage[eidx] = (255 / (lines[y].length[eidx] + 1));
|
||||
}
|
||||
lines[y].length[eidx] = abs(x - x2);
|
||||
lines[y].coverage[eidx] = (255 / (lines[y].length[eidx] + 1));
|
||||
}
|
||||
|
||||
|
||||
|
@ -897,9 +893,14 @@ static void _calcAAEdge(AASpans *aaSpans, int32_t eidx)
|
|||
ptx[1] = tx[1]; \
|
||||
} while (0)
|
||||
|
||||
struct Point
|
||||
{
|
||||
int32_t x, y;
|
||||
};
|
||||
|
||||
int32_t y = 0;
|
||||
SwPoint pEdge = {-1, -1}; //previous edge point
|
||||
SwPoint edgeDiff = {0, 0}; //temporary used for point distance
|
||||
Point pEdge = {-1, -1}; //previous edge point
|
||||
Point edgeDiff = {0, 0}; //temporary used for point distance
|
||||
|
||||
/* store bigger to tx[0] between prev and current edge's x positions. */
|
||||
int32_t tx[2] = {0, 0};
|
||||
|
@ -1024,6 +1025,7 @@ static void _calcAAEdge(AASpans *aaSpans, int32_t eidx)
|
|||
|
||||
static bool _apply(SwSurface* surface, AASpans* aaSpans)
|
||||
{
|
||||
auto end = surface->buf32 + surface->h * surface->stride;
|
||||
auto y = aaSpans->yStart;
|
||||
uint32_t pixel;
|
||||
uint32_t* dst;
|
||||
|
@ -1044,8 +1046,13 @@ static bool _apply(SwSurface* surface, AASpans* aaSpans)
|
|||
dst = surface->buf32 + (offset + line->x[0]);
|
||||
if (line->x[0] > 1) pixel = *(dst - 1);
|
||||
else pixel = *dst;
|
||||
|
||||
pos = 1;
|
||||
|
||||
//exceptional handling. out of memory bound.
|
||||
if (dst + line->length[0] >= end) {
|
||||
pos += (dst + line->length[0] - end);
|
||||
}
|
||||
|
||||
while (pos <= line->length[0]) {
|
||||
*dst = INTERPOLATE(*dst, pixel, line->coverage[0] * pos);
|
||||
++dst;
|
||||
|
@ -1053,17 +1060,21 @@ static bool _apply(SwSurface* surface, AASpans* aaSpans)
|
|||
}
|
||||
|
||||
//Right edge
|
||||
dst = surface->buf32 + (offset + line->x[1] - 1);
|
||||
dst = surface->buf32 + offset + line->x[1] - 1;
|
||||
|
||||
if (line->x[1] < (int32_t)(surface->w - 1)) pixel = *(dst + 1);
|
||||
else pixel = *dst;
|
||||
pos = line->length[1];
|
||||
|
||||
pos = width;
|
||||
while ((int32_t)(width - line->length[1]) < pos) {
|
||||
*dst = INTERPOLATE(*dst, pixel, 255 - (line->coverage[1] * (line->length[1] - (width - pos))));
|
||||
//exceptional handling. out of memory bound.
|
||||
if (dst - pos < surface->buf32) --pos;
|
||||
|
||||
while (pos > 0) {
|
||||
*dst = INTERPOLATE(*dst, pixel, 255 - (line->coverage[1] * pos));
|
||||
--dst;
|
||||
--pos;
|
||||
}
|
||||
}
|
||||
}
|
||||
y++;
|
||||
}
|
||||
|
||||
|
@ -1084,7 +1095,7 @@ static bool _apply(SwSurface* surface, AASpans* aaSpans)
|
|||
| / |
|
||||
3 -- 2
|
||||
*/
|
||||
static bool _rasterTexmapPolygon(SwSurface* surface, const SwImage* image, const Matrix* transform, const SwBBox* region, uint8_t opacity)
|
||||
static bool _rasterTexmapPolygon(SwSurface* surface, const SwImage* image, const Matrix& transform, const SwBBox* region, uint8_t opacity)
|
||||
{
|
||||
if (surface->channelSize == sizeof(uint8_t)) {
|
||||
TVGERR("SW_ENGINE", "Not supported grayscale Textmap polygon!");
|
||||
|
@ -1092,7 +1103,7 @@ static bool _rasterTexmapPolygon(SwSurface* surface, const SwImage* image, const
|
|||
}
|
||||
|
||||
//Exceptions: No dedicated drawing area?
|
||||
if ((!image->rle && !region) || (image->rle && image->rle->size == 0)) return false;
|
||||
if ((!image->rle && !region) || (image->rle && image->rle->size == 0)) return true;
|
||||
|
||||
/* Prepare vertices.
|
||||
shift XY coordinates to match the sub-pixeling technique. */
|
||||
|
@ -1104,7 +1115,7 @@ static bool _rasterTexmapPolygon(SwSurface* surface, const SwImage* image, const
|
|||
|
||||
float ys = FLT_MAX, ye = -1.0f;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (transform) vertices[i].pt *= *transform;
|
||||
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;
|
||||
}
|
||||
|
@ -1135,68 +1146,3 @@ static bool _rasterTexmapPolygon(SwSurface* surface, const SwImage* image, const
|
|||
#endif
|
||||
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 RenderMesh* mesh, const Matrix* transform, const SwBBox* region, uint8_t opacity)
|
||||
{
|
||||
if (surface->channelSize == sizeof(uint8_t)) {
|
||||
TVGERR("SW_ENGINE", "Not supported grayscale Textmap polygon mesh!");
|
||||
return false;
|
||||
}
|
||||
|
||||
//Exceptions: No dedicated drawing area?
|
||||
if ((!image->rle && !region) || (image->rle && image->rle->size == 0)) return false;
|
||||
|
||||
// Step polygons once to transform
|
||||
auto transformedTris = (Polygon*)malloc(sizeof(Polygon) * mesh->triangleCnt);
|
||||
float ys = FLT_MAX, ye = -1.0f;
|
||||
for (uint32_t i = 0; i < mesh->triangleCnt; i++) {
|
||||
transformedTris[i] = mesh->triangles[i];
|
||||
transformedTris[i].vertex[0].pt *= *transform;
|
||||
transformedTris[i].vertex[1].pt *= *transform;
|
||||
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
|
||||
if (auto aaSpans = _AASpans(ys, ye, image, region)) {
|
||||
for (uint32_t i = 0; i < mesh->triangleCnt; i++) {
|
||||
_rasterPolygonImage(surface, image, region, transformedTris[i], aaSpans, opacity);
|
||||
}
|
||||
#if 0
|
||||
if (_compositing(surface) && _masking(surface) && !_direct(surface->compositor->method)) {
|
||||
_compositeMaskImage(surface, &surface->compositor->image, surface->compositor->bbox);
|
||||
}
|
||||
#endif
|
||||
_apply(surface, aaSpans);
|
||||
}
|
||||
free(transformedTris);
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@ struct SwTask : Task
|
|||
SwSurface* surface = nullptr;
|
||||
SwMpool* mpool = nullptr;
|
||||
SwBBox bbox = {{0, 0}, {0, 0}}; //Whole Rendering Region
|
||||
Matrix* transform = nullptr;
|
||||
Matrix transform;
|
||||
Array<RenderData> clips;
|
||||
RenderUpdateFlag flags = RenderUpdateFlag::None;
|
||||
uint8_t opacity;
|
||||
|
@ -68,10 +68,7 @@ struct SwTask : Task
|
|||
virtual bool clip(SwRleData* target) = 0;
|
||||
virtual SwRleData* rle() = 0;
|
||||
|
||||
virtual ~SwTask()
|
||||
{
|
||||
free(transform);
|
||||
}
|
||||
virtual ~SwTask() {}
|
||||
};
|
||||
|
||||
|
||||
|
@ -100,8 +97,7 @@ struct SwShapeTask : SwTask
|
|||
if (!rshape->stroke->fill && (MULTIPLY(rshape->stroke->color[3], opacity) == 0)) return 0.0f;
|
||||
if (mathZero(rshape->stroke->trim.begin - rshape->stroke->trim.end)) return 0.0f;
|
||||
|
||||
if (transform) return (width * sqrt(transform->e11 * transform->e11 + transform->e12 * transform->e12));
|
||||
else return width;
|
||||
return (width * sqrt(transform.e11 * transform.e11 + transform.e12 * transform.e12));
|
||||
}
|
||||
|
||||
|
||||
|
@ -203,64 +199,10 @@ struct SwShapeTask : SwTask
|
|||
};
|
||||
|
||||
|
||||
struct SwSceneTask : SwTask
|
||||
{
|
||||
Array<RenderData> scene; //list of paints render data (SwTask)
|
||||
SwRleData* sceneRle = nullptr;
|
||||
|
||||
bool clip(SwRleData* target) override
|
||||
{
|
||||
//Only one shape
|
||||
if (scene.count == 1) {
|
||||
return static_cast<SwTask*>(*scene.data)->clip(target);
|
||||
}
|
||||
|
||||
//More than one shapes
|
||||
if (sceneRle) rleClipPath(target, sceneRle);
|
||||
else TVGLOG("SW_ENGINE", "No clippers in a scene?");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
SwRleData* rle() override
|
||||
{
|
||||
return sceneRle;
|
||||
}
|
||||
|
||||
void run(unsigned tid) override
|
||||
{
|
||||
//TODO: Skip the run if the scene hans't changed.
|
||||
if (!sceneRle) sceneRle = static_cast<SwRleData*>(calloc(1, sizeof(SwRleData)));
|
||||
else rleReset(sceneRle);
|
||||
|
||||
//Merge shapes if it has more than one shapes
|
||||
if (scene.count > 1) {
|
||||
//Merge first two clippers
|
||||
auto clipper1 = static_cast<SwTask*>(*scene.data);
|
||||
auto clipper2 = static_cast<SwTask*>(*(scene.data + 1));
|
||||
|
||||
rleMerge(sceneRle, clipper1->rle(), clipper2->rle());
|
||||
|
||||
//Unify the remained clippers
|
||||
for (auto rd = scene.begin() + 2; rd < scene.end(); ++rd) {
|
||||
auto clipper = static_cast<SwTask*>(*rd);
|
||||
rleMerge(sceneRle, sceneRle, clipper->rle());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void dispose() override
|
||||
{
|
||||
rleFree(sceneRle);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct SwImageTask : SwTask
|
||||
{
|
||||
SwImage image;
|
||||
Surface* source; //Image source
|
||||
const RenderMesh* mesh = nullptr; //Should be valid ptr in action
|
||||
|
||||
bool clip(SwRleData* target) override
|
||||
{
|
||||
|
@ -293,10 +235,9 @@ struct SwImageTask : SwTask
|
|||
imageReset(&image);
|
||||
if (!image.data || image.w == 0 || image.h == 0) goto end;
|
||||
|
||||
if (!imagePrepare(&image, mesh, transform, clipRegion, bbox, mpool, tid)) goto end;
|
||||
if (!imagePrepare(&image, transform, clipRegion, bbox, mpool, tid)) goto end;
|
||||
|
||||
// TODO: How do we clip the triangle mesh? Only clip non-meshed images for now
|
||||
if (mesh->triangleCnt == 0 && clips.count > 0) {
|
||||
if (clips.count > 0) {
|
||||
if (!imageGenRle(&image, bbox, false)) goto end;
|
||||
if (image.rle) {
|
||||
//Clear current task memorypool here if the clippers would use the same memory pool
|
||||
|
@ -336,7 +277,7 @@ static void _renderFill(SwShapeTask* task, SwSurface* surface, uint8_t opacity)
|
|||
{
|
||||
uint8_t r, g, b, a;
|
||||
if (auto fill = task->rshape->fill) {
|
||||
rasterGradientShape(surface, &task->shape, fill->identifier());
|
||||
rasterGradientShape(surface, &task->shape, fill, opacity);
|
||||
} else {
|
||||
task->rshape->fillColor(&r, &g, &b, &a);
|
||||
a = MULTIPLY(opacity, a);
|
||||
|
@ -348,7 +289,7 @@ static void _renderStroke(SwShapeTask* task, SwSurface* surface, uint8_t opacity
|
|||
{
|
||||
uint8_t r, g, b, a;
|
||||
if (auto strokeFill = task->rshape->strokeFill()) {
|
||||
rasterGradientStroke(surface, &task->shape, strokeFill->identifier());
|
||||
rasterGradientStroke(surface, &task->shape, strokeFill, opacity);
|
||||
} else {
|
||||
if (task->rshape->strokeColor(&r, &g, &b, &a)) {
|
||||
a = MULTIPLY(opacity, a);
|
||||
|
@ -480,7 +421,7 @@ bool SwRenderer::renderImage(RenderData data)
|
|||
|
||||
if (task->opacity == 0) return true;
|
||||
|
||||
return rasterImage(surface, &task->image, task->mesh, task->transform, task->bbox, task->opacity);
|
||||
return rasterImage(surface, &task->image, task->transform, task->bbox, task->opacity);
|
||||
}
|
||||
|
||||
|
||||
|
@ -688,7 +629,8 @@ bool SwRenderer::endComposite(Compositor* cmp)
|
|||
|
||||
//Default is alpha blending
|
||||
if (p->method == CompositeMethod::None) {
|
||||
return rasterImage(surface, &p->image, nullptr, nullptr, p->bbox, p->opacity);
|
||||
Matrix m = {1, 0, 0, 0, 1, 0, 0, 0, 1};
|
||||
return rasterImage(surface, &p->image, m, p->bbox, p->opacity);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -714,7 +656,7 @@ void SwRenderer::dispose(RenderData data)
|
|||
}
|
||||
|
||||
|
||||
void* SwRenderer::prepareCommon(SwTask* task, const RenderTransform* transform, const Array<RenderData>& clips, uint8_t opacity, RenderUpdateFlag flags)
|
||||
void* SwRenderer::prepareCommon(SwTask* task, const Matrix& transform, const Array<RenderData>& clips, uint8_t opacity, RenderUpdateFlag flags)
|
||||
{
|
||||
if (!surface) return task;
|
||||
if (flags == RenderUpdateFlag::None) return task;
|
||||
|
@ -727,20 +669,11 @@ void* SwRenderer::prepareCommon(SwTask* task, const RenderTransform* transform,
|
|||
}
|
||||
|
||||
task->clips = clips;
|
||||
|
||||
if (transform) {
|
||||
if (!task->transform) task->transform = static_cast<Matrix*>(malloc(sizeof(Matrix)));
|
||||
*task->transform = transform->m;
|
||||
} else {
|
||||
if (task->transform) free(task->transform);
|
||||
task->transform = nullptr;
|
||||
}
|
||||
|
||||
task->transform = transform;
|
||||
|
||||
//zero size?
|
||||
if (task->transform) {
|
||||
if (task->transform->e11 == 0.0f && task->transform->e12 == 0.0f) return task; //zero width
|
||||
if (task->transform->e21 == 0.0f && task->transform->e22 == 0.0f) return task; //zero height
|
||||
}
|
||||
if (task->transform.e11 == 0.0f && task->transform.e12 == 0.0f) return task; //zero width
|
||||
if (task->transform.e21 == 0.0f && task->transform.e22 == 0.0f) return task; //zero height
|
||||
|
||||
task->opacity = opacity;
|
||||
task->surface = surface;
|
||||
|
@ -762,7 +695,7 @@ void* SwRenderer::prepareCommon(SwTask* task, const RenderTransform* transform,
|
|||
}
|
||||
|
||||
|
||||
RenderData SwRenderer::prepare(Surface* surface, const RenderMesh* mesh, RenderData data, const RenderTransform* transform, Array<RenderData>& clips, uint8_t opacity, RenderUpdateFlag flags)
|
||||
RenderData SwRenderer::prepare(Surface* surface, RenderData data, const Matrix& transform, Array<RenderData>& clips, uint8_t opacity, RenderUpdateFlag flags)
|
||||
{
|
||||
//prepare task
|
||||
auto task = static_cast<SwImageTask*>(data);
|
||||
|
@ -770,33 +703,12 @@ RenderData SwRenderer::prepare(Surface* surface, const RenderMesh* mesh, RenderD
|
|||
else task->done();
|
||||
|
||||
task->source = surface;
|
||||
task->mesh = mesh;
|
||||
|
||||
return prepareCommon(task, transform, clips, opacity, flags);
|
||||
}
|
||||
|
||||
|
||||
RenderData SwRenderer::prepare(const Array<RenderData>& scene, RenderData data, const RenderTransform* transform, Array<RenderData>& clips, uint8_t opacity, RenderUpdateFlag flags)
|
||||
{
|
||||
//prepare task
|
||||
auto task = static_cast<SwSceneTask*>(data);
|
||||
if (!task) task = new SwSceneTask;
|
||||
else task->done();
|
||||
|
||||
task->scene = scene;
|
||||
|
||||
//TODO: Failed threading them. It would be better if it's possible.
|
||||
//See: https://github.com/thorvg/thorvg/issues/1409
|
||||
//Guarantee composition targets get ready.
|
||||
for (auto task = scene.begin(); task < scene.end(); ++task) {
|
||||
static_cast<SwTask*>(*task)->done();
|
||||
}
|
||||
|
||||
return prepareCommon(task, transform, clips, opacity, flags);
|
||||
}
|
||||
|
||||
|
||||
RenderData SwRenderer::prepare(const RenderShape& rshape, RenderData data, const RenderTransform* transform, Array<RenderData>& clips, uint8_t opacity, RenderUpdateFlag flags, bool clipper)
|
||||
RenderData SwRenderer::prepare(const RenderShape& rshape, RenderData data, const Matrix& transform, Array<RenderData>& clips, uint8_t opacity, RenderUpdateFlag flags, bool clipper)
|
||||
{
|
||||
//prepare task
|
||||
auto task = static_cast<SwShapeTask*>(data);
|
||||
|
|
|
@ -36,9 +36,8 @@ namespace tvg
|
|||
class SwRenderer : public RenderMethod
|
||||
{
|
||||
public:
|
||||
RenderData prepare(const RenderShape& rshape, RenderData data, const RenderTransform* transform, Array<RenderData>& clips, uint8_t opacity, RenderUpdateFlag flags, bool clipper) override;
|
||||
RenderData prepare(const Array<RenderData>& scene, RenderData data, const RenderTransform* transform, Array<RenderData>& clips, uint8_t opacity, RenderUpdateFlag flags) override;
|
||||
RenderData prepare(Surface* surface, const RenderMesh* mesh, RenderData data, const RenderTransform* transform, Array<RenderData>& clips, uint8_t opacity, RenderUpdateFlag flags) override;
|
||||
RenderData prepare(const RenderShape& rshape, RenderData data, const Matrix& transform, Array<RenderData>& clips, uint8_t opacity, RenderUpdateFlag flags, bool clipper) override;
|
||||
RenderData prepare(Surface* surface, RenderData data, const Matrix& transform, Array<RenderData>& clips, uint8_t opacity, RenderUpdateFlag flags) override;
|
||||
bool preRender() override;
|
||||
bool renderShape(RenderData data) override;
|
||||
bool renderImage(RenderData data) override;
|
||||
|
@ -77,7 +76,7 @@ private:
|
|||
SwRenderer();
|
||||
~SwRenderer();
|
||||
|
||||
RenderData prepareCommon(SwTask* task, const RenderTransform* transform, const Array<RenderData>& clips, uint8_t opacity, RenderUpdateFlag flags);
|
||||
RenderData prepareCommon(SwTask* task, const Matrix& transform, const Array<RenderData>& clips, uint8_t opacity, RenderUpdateFlag flags);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -358,7 +358,7 @@ static void _horizLine(RleWorker& rw, SwCoord x, SwCoord y, SwCoord area, SwCoor
|
|||
rle->spans = static_cast<SwSpan*>(realloc(rle->spans, rle->alloc * sizeof(SwSpan)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//Clip x range
|
||||
SwCoord xOver = 0;
|
||||
if (x + acount >= rw.cellMax.x) xOver -= (x + acount - rw.cellMax.x);
|
||||
|
@ -822,46 +822,6 @@ static SwSpan* _intersectSpansRect(const SwBBox *bbox, const SwRleData *targetRl
|
|||
}
|
||||
|
||||
|
||||
static SwSpan* _mergeSpansRegion(const SwRleData *clip1, const SwRleData *clip2, SwSpan *outSpans)
|
||||
{
|
||||
auto out = outSpans;
|
||||
auto spans1 = clip1->spans;
|
||||
auto end1 = clip1->spans + clip1->size;
|
||||
auto spans2 = clip2->spans;
|
||||
auto end2 = clip2->spans + clip2->size;
|
||||
|
||||
//list two spans up in y order
|
||||
//TODO: Remove duplicated regions?
|
||||
while (spans1 < end1 && spans2 < end2) {
|
||||
while (spans1 < end1 && spans1->y <= spans2->y) {
|
||||
*out = *spans1;
|
||||
++spans1;
|
||||
++out;
|
||||
}
|
||||
if (spans1 >= end1) break;
|
||||
while (spans2 < end2 && spans2->y <= spans1->y) {
|
||||
*out = *spans2;
|
||||
++spans2;
|
||||
++out;
|
||||
}
|
||||
}
|
||||
|
||||
//Leftovers
|
||||
while (spans1 < end1) {
|
||||
*out = *spans1;
|
||||
++spans1;
|
||||
++out;
|
||||
}
|
||||
while (spans2 < end2) {
|
||||
*out = *spans2;
|
||||
++spans2;
|
||||
++out;
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
void _replaceClipSpan(SwRleData *rle, SwSpan* clippedSpans, uint32_t size)
|
||||
{
|
||||
free(rle->spans);
|
||||
|
@ -1030,45 +990,6 @@ void rleFree(SwRleData* rle)
|
|||
}
|
||||
|
||||
|
||||
void rleMerge(SwRleData* rle, SwRleData* clip1, SwRleData* clip2)
|
||||
{
|
||||
if (!rle || (!clip1 && !clip2)) return;
|
||||
if (clip1 && clip1->size == 0 && clip2 && clip2->size == 0) return;
|
||||
|
||||
TVGLOG("SW_ENGINE", "Unifying Rle!");
|
||||
|
||||
//clip1 is empty, just copy clip2
|
||||
if (!clip1 || clip1->size == 0) {
|
||||
if (clip2) {
|
||||
auto spans = static_cast<SwSpan*>(malloc(sizeof(SwSpan) * (clip2->size)));
|
||||
memcpy(spans, clip2->spans, clip2->size);
|
||||
_replaceClipSpan(rle, spans, clip2->size);
|
||||
} else {
|
||||
_replaceClipSpan(rle, nullptr, 0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
//clip2 is empty, just copy clip1
|
||||
if (!clip2 || clip2->size == 0) {
|
||||
if (clip1) {
|
||||
auto spans = static_cast<SwSpan*>(malloc(sizeof(SwSpan) * (clip1->size)));
|
||||
memcpy(spans, clip1->spans, clip1->size);
|
||||
_replaceClipSpan(rle, spans, clip1->size);
|
||||
} else {
|
||||
_replaceClipSpan(rle, nullptr, 0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
auto spanCnt = clip1->size + clip2->size;
|
||||
auto spans = static_cast<SwSpan*>(malloc(sizeof(SwSpan) * spanCnt));
|
||||
auto spansEnd = _mergeSpansRegion(clip1, clip2, spans);
|
||||
|
||||
_replaceClipSpan(rle, spans, spansEnd - spans);
|
||||
}
|
||||
|
||||
|
||||
void rleClipPath(SwRleData *rle, const SwRleData *clip)
|
||||
{
|
||||
if (rle->size == 0 || clip->size == 0) return;
|
||||
|
|
|
@ -49,7 +49,7 @@ static bool _outlineEnd(SwOutline& outline)
|
|||
}
|
||||
|
||||
|
||||
static bool _outlineMoveTo(SwOutline& outline, const Point* to, const Matrix* transform, bool closed = false)
|
||||
static bool _outlineMoveTo(SwOutline& outline, const Point* to, const Matrix& transform, bool closed = false)
|
||||
{
|
||||
//make it a contour, if the last contour is not closed yet.
|
||||
if (!closed) _outlineEnd(outline);
|
||||
|
@ -60,14 +60,14 @@ static bool _outlineMoveTo(SwOutline& outline, const Point* to, const Matrix* tr
|
|||
}
|
||||
|
||||
|
||||
static void _outlineLineTo(SwOutline& outline, const Point* to, const Matrix* transform)
|
||||
static void _outlineLineTo(SwOutline& outline, const Point* to, const Matrix& transform)
|
||||
{
|
||||
outline.pts.push(mathTransform(to, transform));
|
||||
outline.types.push(SW_CURVE_TYPE_POINT);
|
||||
}
|
||||
|
||||
|
||||
static void _outlineCubicTo(SwOutline& outline, const Point* ctrl1, const Point* ctrl2, const Point* to, const Matrix* transform)
|
||||
static void _outlineCubicTo(SwOutline& outline, const Point* ctrl1, const Point* ctrl2, const Point* to, const Matrix& transform)
|
||||
{
|
||||
outline.pts.push(mathTransform(ctrl1, transform));
|
||||
outline.types.push(SW_CURVE_TYPE_CUBIC);
|
||||
|
@ -99,7 +99,7 @@ static bool _outlineClose(SwOutline& outline)
|
|||
}
|
||||
|
||||
|
||||
static void _dashLineTo(SwDashStroke& dash, const Point* to, const Matrix* transform)
|
||||
static void _dashLineTo(SwDashStroke& dash, const Point* to, const Matrix& transform)
|
||||
{
|
||||
Line cur = {dash.ptCur, *to};
|
||||
auto len = lineLength(cur.pt1, cur.pt2);
|
||||
|
@ -160,7 +160,7 @@ static void _dashLineTo(SwDashStroke& dash, const Point* to, const Matrix* trans
|
|||
}
|
||||
|
||||
|
||||
static void _dashCubicTo(SwDashStroke& dash, const Point* ctrl1, const Point* ctrl2, const Point* to, const Matrix* transform)
|
||||
static void _dashCubicTo(SwDashStroke& dash, const Point* ctrl1, const Point* ctrl2, const Point* to, const Matrix& transform)
|
||||
{
|
||||
Bezier cur = {dash.ptCur, *ctrl1, *ctrl2, *to};
|
||||
auto len = bezLength(cur);
|
||||
|
@ -221,7 +221,7 @@ static void _dashCubicTo(SwDashStroke& dash, const Point* ctrl1, const Point* ct
|
|||
}
|
||||
|
||||
|
||||
static void _dashClose(SwDashStroke& dash, const Matrix* transform)
|
||||
static void _dashClose(SwDashStroke& dash, const Matrix& transform)
|
||||
{
|
||||
_dashLineTo(dash, &dash.ptStart, transform);
|
||||
}
|
||||
|
@ -245,10 +245,10 @@ static void _dashMoveTo(SwDashStroke& dash, uint32_t offIdx, float offset, const
|
|||
}
|
||||
|
||||
|
||||
static void _trimPattern(SwDashStroke* dash, const RenderShape* rshape, float length)
|
||||
static void _trimPattern(SwDashStroke* dash, const RenderShape* rshape, float length, float trimBegin, float trimEnd)
|
||||
{
|
||||
auto begin = length * rshape->stroke->trim.begin;
|
||||
auto end = length * rshape->stroke->trim.end;
|
||||
auto begin = length * trimBegin;
|
||||
auto end = length * trimEnd;
|
||||
|
||||
//default
|
||||
if (end > begin) {
|
||||
|
@ -324,7 +324,7 @@ static float _outlineLength(const RenderShape* rshape, uint32_t shiftPts, uint32
|
|||
}
|
||||
|
||||
|
||||
static SwOutline* _genDashOutline(const RenderShape* rshape, const Matrix* transform, bool trimmed, SwMpool* mpool, unsigned tid)
|
||||
static SwOutline* _genDashOutline(const RenderShape* rshape, const Matrix& transform, bool trimmed, SwMpool* mpool, unsigned tid)
|
||||
{
|
||||
const PathCommand* cmds = rshape->path.cmds.data;
|
||||
auto cmdCnt = rshape->path.cmds.count;
|
||||
|
@ -341,6 +341,8 @@ static SwOutline* _genDashOutline(const RenderShape* rshape, const Matrix* trans
|
|||
auto offset = 0.0f;
|
||||
dash.cnt = rshape->strokeDash((const float**)&dash.pattern, &offset);
|
||||
auto simultaneous = rshape->stroke->trim.simultaneous;
|
||||
float trimBegin = 0.0f, trimEnd = 1.0f;
|
||||
if (trimmed) rshape->stroke->strokeTrim(trimBegin, trimEnd);
|
||||
|
||||
if (dash.cnt == 0) {
|
||||
if (trimmed) dash.pattern = (float*)malloc(sizeof(float) * 4);
|
||||
|
@ -372,7 +374,7 @@ static SwOutline* _genDashOutline(const RenderShape* rshape, const Matrix* trans
|
|||
|
||||
//must begin with moveTo
|
||||
if (cmds[0] == PathCommand::MoveTo) {
|
||||
if (trimmed) _trimPattern(&dash, rshape, _outlineLength(rshape, 0, 0, simultaneous));
|
||||
if (trimmed) _trimPattern(&dash, rshape, _outlineLength(rshape, 0, 0, simultaneous), trimBegin, trimEnd);
|
||||
_dashMoveTo(dash, offIdx, offset, pts);
|
||||
cmds++;
|
||||
pts++;
|
||||
|
@ -387,7 +389,7 @@ static SwOutline* _genDashOutline(const RenderShape* rshape, const Matrix* trans
|
|||
case PathCommand::MoveTo: {
|
||||
if (trimmed) {
|
||||
if (simultaneous) {
|
||||
_trimPattern(&dash, rshape, _outlineLength(rshape, pts - startPts, cmds - startCmds, true));
|
||||
_trimPattern(&dash, rshape, _outlineLength(rshape, pts - startPts, cmds - startCmds, true), trimBegin, trimEnd);
|
||||
_dashMoveTo(dash, offIdx, offset, pts);
|
||||
} else _dashMoveTo(dash, pts);
|
||||
} else _dashMoveTo(dash, offIdx, offset, pts);
|
||||
|
@ -436,7 +438,7 @@ static bool _axisAlignedRect(const SwOutline* outline)
|
|||
}
|
||||
|
||||
|
||||
static bool _genOutline(SwShape* shape, const RenderShape* rshape, const Matrix* transform, SwMpool* mpool, unsigned tid, bool hasComposite)
|
||||
static bool _genOutline(SwShape* shape, const RenderShape* rshape, const Matrix& transform, SwMpool* mpool, unsigned tid, bool hasComposite)
|
||||
{
|
||||
const PathCommand* cmds = rshape->path.cmds.data;
|
||||
auto cmdCnt = rshape->path.cmds.count;
|
||||
|
@ -492,7 +494,7 @@ static bool _genOutline(SwShape* shape, const RenderShape* rshape, const Matrix*
|
|||
/* External Class Implementation */
|
||||
/************************************************************************/
|
||||
|
||||
bool shapePrepare(SwShape* shape, const RenderShape* rshape, const Matrix* transform, const SwBBox& clipRegion, SwBBox& renderRegion, SwMpool* mpool, unsigned tid, bool hasComposite)
|
||||
bool shapePrepare(SwShape* shape, const RenderShape* rshape, const Matrix& transform, const SwBBox& clipRegion, SwBBox& renderRegion, SwMpool* mpool, unsigned tid, bool hasComposite)
|
||||
{
|
||||
if (!_genOutline(shape, rshape, transform, mpool, tid, hasComposite)) return false;
|
||||
if (!mathUpdateOutlineBBox(shape->outline, clipRegion, renderRegion, shape->fastTrack)) return false;
|
||||
|
@ -575,7 +577,7 @@ void shapeDelStroke(SwShape* shape)
|
|||
}
|
||||
|
||||
|
||||
void shapeResetStroke(SwShape* shape, const RenderShape* rshape, const Matrix* transform)
|
||||
void shapeResetStroke(SwShape* shape, const RenderShape* rshape, const Matrix& transform)
|
||||
{
|
||||
if (!shape->stroke) shape->stroke = static_cast<SwStroke*>(calloc(1, sizeof(SwStroke)));
|
||||
auto stroke = shape->stroke;
|
||||
|
@ -586,7 +588,7 @@ void shapeResetStroke(SwShape* shape, const RenderShape* rshape, const Matrix* t
|
|||
}
|
||||
|
||||
|
||||
bool shapeGenStrokeRle(SwShape* shape, const RenderShape* rshape, const Matrix* transform, const SwBBox& clipRegion, SwBBox& renderRegion, SwMpool* mpool, unsigned tid)
|
||||
bool shapeGenStrokeRle(SwShape* shape, const RenderShape* rshape, const Matrix& transform, const SwBBox& clipRegion, SwBBox& renderRegion, SwMpool* mpool, unsigned tid)
|
||||
{
|
||||
SwOutline* shapeOutline = nullptr;
|
||||
SwOutline* strokeOutline = nullptr;
|
||||
|
@ -629,13 +631,13 @@ clear:
|
|||
}
|
||||
|
||||
|
||||
bool shapeGenFillColors(SwShape* shape, const Fill* fill, const Matrix* transform, SwSurface* surface, uint8_t opacity, bool ctable)
|
||||
bool shapeGenFillColors(SwShape* shape, const Fill* fill, const Matrix& transform, SwSurface* surface, uint8_t opacity, bool ctable)
|
||||
{
|
||||
return fillGenColorTable(shape->fill, fill, transform, surface, opacity, ctable);
|
||||
}
|
||||
|
||||
|
||||
bool shapeGenStrokeFillColors(SwShape* shape, const Fill* fill, const Matrix* transform, SwSurface* surface, uint8_t opacity, bool ctable)
|
||||
bool shapeGenStrokeFillColors(SwShape* shape, const Fill* fill, const Matrix& transform, SwSurface* surface, uint8_t opacity, bool ctable)
|
||||
{
|
||||
return fillGenColorTable(shape->stroke->fill, fill, transform, surface, opacity, ctable);
|
||||
}
|
||||
|
|
|
@ -805,15 +805,10 @@ void strokeFree(SwStroke* stroke)
|
|||
}
|
||||
|
||||
|
||||
void strokeReset(SwStroke* stroke, const RenderShape* rshape, const Matrix* transform)
|
||||
void strokeReset(SwStroke* stroke, const RenderShape* rshape, const Matrix& transform)
|
||||
{
|
||||
if (transform) {
|
||||
stroke->sx = sqrtf(powf(transform->e11, 2.0f) + powf(transform->e21, 2.0f));
|
||||
stroke->sy = sqrtf(powf(transform->e12, 2.0f) + powf(transform->e22, 2.0f));
|
||||
} else {
|
||||
stroke->sx = stroke->sy = 1.0f;
|
||||
}
|
||||
|
||||
stroke->sx = sqrtf(powf(transform.e11, 2.0f) + powf(transform.e21, 2.0f));
|
||||
stroke->sy = sqrtf(powf(transform.e12, 2.0f) + powf(transform.e22, 2.0f));
|
||||
stroke->width = HALF_STROKE(rshape->strokeWidth());
|
||||
stroke->cap = rshape->strokeCap();
|
||||
stroke->miterlimit = static_cast<SwFixed>(rshape->strokeMiterlimit() * 65536.0f);
|
||||
|
|
|
@ -21,20 +21,21 @@
|
|||
*/
|
||||
|
||||
#include "tvgIteratorAccessor.h"
|
||||
#include "tvgCompressor.h"
|
||||
|
||||
/************************************************************************/
|
||||
/* Internal Class Implementation */
|
||||
/************************************************************************/
|
||||
|
||||
static bool accessChildren(Iterator* it, function<bool(const Paint* paint)> func)
|
||||
static bool accessChildren(Iterator* it, function<bool(const Paint* paint, void* data)> func, void* data)
|
||||
{
|
||||
while (auto child = it->next()) {
|
||||
//Access the child
|
||||
if (!func(child)) return false;
|
||||
if (!func(child, data)) return false;
|
||||
|
||||
//Access the children of the child
|
||||
if (auto it2 = IteratorAccessor::iterator(child)) {
|
||||
if (!accessChildren(it2, func)) {
|
||||
if (!accessChildren(it2, func, data)) {
|
||||
delete(it2);
|
||||
return false;
|
||||
}
|
||||
|
@ -44,26 +45,46 @@ static bool accessChildren(Iterator* it, function<bool(const Paint* paint)> func
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
/************************************************************************/
|
||||
/* External Class Implementation */
|
||||
/************************************************************************/
|
||||
|
||||
unique_ptr<Picture> Accessor::set(unique_ptr<Picture> picture, function<bool(const Paint* paint)> func) noexcept
|
||||
TVG_DEPRECATED unique_ptr<Picture> Accessor::set(unique_ptr<Picture> picture, function<bool(const Paint* paint)> func) noexcept
|
||||
{
|
||||
auto p = picture.get();
|
||||
if (!p || !func) return picture;
|
||||
auto backward = [](const tvg::Paint* paint, void* data) -> bool
|
||||
{
|
||||
auto func = reinterpret_cast<function<bool(const Paint* paint)>*>(data);
|
||||
if (!(*func)(paint)) return false;
|
||||
return true;
|
||||
};
|
||||
|
||||
set(picture.get(), backward, reinterpret_cast<void*>(&func));
|
||||
return picture;
|
||||
}
|
||||
|
||||
|
||||
Result Accessor::set(const Picture* picture, function<bool(const Paint* paint, void* data)> func, void* data) noexcept
|
||||
{
|
||||
if (!picture || !func) return Result::InvalidArguments;
|
||||
|
||||
//Use the Preorder Tree-Search
|
||||
|
||||
//Root
|
||||
if (!func(p)) return picture;
|
||||
if (!func(picture, data)) return Result::Success;
|
||||
|
||||
//Children
|
||||
if (auto it = IteratorAccessor::iterator(p)) {
|
||||
accessChildren(it, func);
|
||||
if (auto it = IteratorAccessor::iterator(picture)) {
|
||||
accessChildren(it, func, data);
|
||||
delete(it);
|
||||
}
|
||||
return picture;
|
||||
return Result::Success;
|
||||
}
|
||||
|
||||
|
||||
uint32_t Accessor::id(const char* name) noexcept
|
||||
{
|
||||
return djb2Encode(name);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -95,7 +95,7 @@ float Animation::duration() const noexcept
|
|||
|
||||
Result Animation::segment(float begin, float end) noexcept
|
||||
{
|
||||
if (begin < 0.0 || end > 1.0 || begin >= end) return Result::InvalidArguments;
|
||||
if (begin < 0.0 || end > 1.0 || begin > end) return Result::InvalidArguments;
|
||||
|
||||
auto loader = pImpl->picture->pImpl->loader;
|
||||
if (!loader) return Result::InsufficientCondition;
|
||||
|
|
|
@ -93,11 +93,13 @@ struct Canvas::Impl
|
|||
auto flag = RenderUpdateFlag::None;
|
||||
if (status == Status::Damanged || force) flag = RenderUpdateFlag::All;
|
||||
|
||||
auto m = Matrix{1, 0, 0, 0, 1, 0, 0, 0, 1};
|
||||
|
||||
if (paint) {
|
||||
paint->pImpl->update(renderer, nullptr, clips, 255, flag);
|
||||
paint->pImpl->update(renderer, m, clips, 255, flag);
|
||||
} else {
|
||||
for (auto paint : paints) {
|
||||
paint->pImpl->update(renderer, nullptr, clips, 255, flag);
|
||||
paint->pImpl->update(renderer, m, clips, 255, flag);
|
||||
}
|
||||
}
|
||||
status = Status::Updating;
|
||||
|
|
|
@ -54,36 +54,30 @@ static constexpr bool operator &(CanvasEngine a, CanvasEngine b)
|
|||
return int(a) & int(b);
|
||||
}
|
||||
|
||||
static bool _buildVersionInfo()
|
||||
static bool _buildVersionInfo(uint32_t* major, uint32_t* minor, uint32_t* micro)
|
||||
{
|
||||
auto SRC = THORVG_VERSION_STRING; //ex) 0.3.99
|
||||
auto p = SRC;
|
||||
auto VER = THORVG_VERSION_STRING;
|
||||
auto p = VER;
|
||||
const char* x;
|
||||
|
||||
char major[3];
|
||||
x = strchr(p, '.');
|
||||
if (!x) return false;
|
||||
memcpy(major, p, x - p);
|
||||
major[x - p] = '\0';
|
||||
if (!(x = strchr(p, '.'))) return false;
|
||||
uint32_t majorVal = atoi(p);
|
||||
p = x + 1;
|
||||
|
||||
char minor[3];
|
||||
x = strchr(p, '.');
|
||||
if (!x) return false;
|
||||
memcpy(minor, p, x - p);
|
||||
minor[x - p] = '\0';
|
||||
if (!(x = strchr(p, '.'))) return false;
|
||||
uint32_t minorVal = atoi(p);
|
||||
p = x + 1;
|
||||
|
||||
char micro[3];
|
||||
x = SRC + strlen(THORVG_VERSION_STRING);
|
||||
memcpy(micro, p, x - p);
|
||||
micro[x - p] = '\0';
|
||||
uint32_t microVal = atoi(p);
|
||||
|
||||
char sum[7];
|
||||
snprintf(sum, sizeof(sum), "%s%s%s", major, minor, micro);
|
||||
|
||||
snprintf(sum, sizeof(sum), "%d%02d%02d", majorVal, minorVal, microVal);
|
||||
_version = atoi(sum);
|
||||
|
||||
if (major) *major = majorVal;
|
||||
if (minor) *minor = minorVal;
|
||||
if (micro) *micro = microVal;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -122,7 +116,7 @@ Result Initializer::init(CanvasEngine engine, uint32_t threads) noexcept
|
|||
|
||||
if (_initCnt++ > 0) return Result::Success;
|
||||
|
||||
if (!_buildVersionInfo()) return Result::Unknown;
|
||||
if (!_buildVersionInfo(nullptr, nullptr, nullptr)) return Result::Unknown;
|
||||
|
||||
if (!LoaderMgr::init()) return Result::Unknown;
|
||||
|
||||
|
@ -172,8 +166,14 @@ Result Initializer::term(CanvasEngine engine) noexcept
|
|||
}
|
||||
|
||||
|
||||
const char* Initializer::version(uint32_t* major, uint32_t* minor, uint32_t* micro) noexcept
|
||||
{
|
||||
if ((!major && ! minor && !micro) || _buildVersionInfo(major, minor, micro)) return THORVG_VERSION_STRING;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
uint16_t THORVG_VERSION_NUMBER()
|
||||
{
|
||||
return _version;
|
||||
}
|
||||
|
||||
|
|
|
@ -41,7 +41,7 @@
|
|||
}
|
||||
|
||||
|
||||
static Result _clipRect(RenderMethod* renderer, const Point* pts, const RenderTransform* pTransform, RenderTransform* rTransform, RenderRegion& before)
|
||||
static Result _clipRect(RenderMethod* renderer, const Point* pts, const Matrix& pm, const Matrix& rm, RenderRegion& before)
|
||||
{
|
||||
//sorting
|
||||
Point tmp[4];
|
||||
|
@ -50,8 +50,8 @@ static Result _clipRect(RenderMethod* renderer, const Point* pts, const RenderTr
|
|||
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
tmp[i] = pts[i];
|
||||
if (rTransform) tmp[i] *= rTransform->m;
|
||||
if (pTransform) tmp[i] *= pTransform->m;
|
||||
tmp[i] *= rm;
|
||||
tmp[i] *= pm;
|
||||
if (tmp[i].x < min.x) min.x = tmp[i].x;
|
||||
if (tmp[i].x > max.x) max.x = tmp[i].x;
|
||||
if (tmp[i].y < min.y) min.y = tmp[i].y;
|
||||
|
@ -73,7 +73,7 @@ static Result _clipRect(RenderMethod* renderer, const Point* pts, const RenderTr
|
|||
}
|
||||
|
||||
|
||||
static Result _compFastTrack(RenderMethod* renderer, Paint* cmpTarget, const RenderTransform* pTransform, RenderTransform* rTransform, RenderRegion& before)
|
||||
static Result _compFastTrack(RenderMethod* renderer, Paint* cmpTarget, const Matrix& pm, RenderRegion& before)
|
||||
{
|
||||
/* Access Shape class by Paint is bad... but it's ok still it's an internal usage. */
|
||||
auto shape = static_cast<Shape*>(cmpTarget);
|
||||
|
@ -84,18 +84,17 @@ static Result _compFastTrack(RenderMethod* renderer, Paint* cmpTarget, const Ren
|
|||
|
||||
//nothing to clip
|
||||
if (ptsCnt == 0) return Result::InvalidArguments;
|
||||
|
||||
if (ptsCnt != 4) return Result::InsufficientCondition;
|
||||
|
||||
if (rTransform && (cmpTarget->pImpl->renderFlag & RenderUpdateFlag::Transform)) rTransform->update();
|
||||
auto& rm = P(cmpTarget)->transform();
|
||||
|
||||
//No rotation and no skewing, still can try out clipping the rect region.
|
||||
auto tryClip = false;
|
||||
|
||||
if (pTransform && (!mathRightAngle(&pTransform->m) || mathSkewed(&pTransform->m))) tryClip = true;
|
||||
if (rTransform && (!mathRightAngle(&rTransform->m) || mathSkewed(&rTransform->m))) tryClip = true;
|
||||
if ((!mathRightAngle(pm) || mathSkewed(pm))) tryClip = true;
|
||||
if ((!mathRightAngle(rm) || mathSkewed(rm))) tryClip = true;
|
||||
|
||||
if (tryClip) return _clipRect(renderer, pts, pTransform, rTransform, before);
|
||||
if (tryClip) return _clipRect(renderer, pts, pm, rm, before);
|
||||
|
||||
//Perpendicular Rectangle?
|
||||
auto pt1 = pts + 0;
|
||||
|
@ -110,16 +109,10 @@ static Result _compFastTrack(RenderMethod* renderer, Paint* cmpTarget, const Ren
|
|||
|
||||
auto v1 = *pt1;
|
||||
auto v2 = *pt3;
|
||||
|
||||
if (rTransform) {
|
||||
v1 *= rTransform->m;
|
||||
v2 *= rTransform->m;
|
||||
}
|
||||
|
||||
if (pTransform) {
|
||||
v1 *= pTransform->m;
|
||||
v2 *= pTransform->m;
|
||||
}
|
||||
v1 *= rm;
|
||||
v2 *= rm;
|
||||
v1 *= pm;
|
||||
v2 *= pm;
|
||||
|
||||
//sorting
|
||||
if (v1.x > v2.x) std::swap(v1.x, v2.x);
|
||||
|
@ -158,17 +151,15 @@ Iterator* Paint::Impl::iterator()
|
|||
}
|
||||
|
||||
|
||||
Paint* Paint::Impl::duplicate()
|
||||
Paint* Paint::Impl::duplicate(Paint* ret)
|
||||
{
|
||||
Paint* ret;
|
||||
PAINT_METHOD(ret, duplicate());
|
||||
if (ret) ret->composite(nullptr, CompositeMethod::None);
|
||||
|
||||
PAINT_METHOD(ret, duplicate(ret));
|
||||
|
||||
//duplicate Transform
|
||||
if (rTransform) {
|
||||
ret->pImpl->rTransform = new RenderTransform();
|
||||
*ret->pImpl->rTransform = *rTransform;
|
||||
ret->pImpl->renderFlag |= RenderUpdateFlag::Transform;
|
||||
}
|
||||
ret->pImpl->tr = tr;
|
||||
ret->pImpl->renderFlag |= RenderUpdateFlag::Transform;
|
||||
|
||||
ret->pImpl->opacity = opacity;
|
||||
|
||||
|
@ -180,14 +171,9 @@ Paint* Paint::Impl::duplicate()
|
|||
|
||||
bool Paint::Impl::rotate(float degree)
|
||||
{
|
||||
if (rTransform) {
|
||||
if (rTransform->overriding) return false;
|
||||
if (mathEqual(degree, rTransform->degree)) return true;
|
||||
} else {
|
||||
if (mathZero(degree)) return true;
|
||||
rTransform = new RenderTransform();
|
||||
}
|
||||
rTransform->degree = degree;
|
||||
if (tr.overriding) return false;
|
||||
if (mathEqual(degree, tr.degree)) return true;
|
||||
tr.degree = degree;
|
||||
renderFlag |= RenderUpdateFlag::Transform;
|
||||
|
||||
return true;
|
||||
|
@ -196,14 +182,9 @@ bool Paint::Impl::rotate(float degree)
|
|||
|
||||
bool Paint::Impl::scale(float factor)
|
||||
{
|
||||
if (rTransform) {
|
||||
if (rTransform->overriding) return false;
|
||||
if (mathEqual(factor, rTransform->scale)) return true;
|
||||
} else {
|
||||
if (mathEqual(factor, 1.0f)) return true;
|
||||
rTransform = new RenderTransform();
|
||||
}
|
||||
rTransform->scale = factor;
|
||||
if (tr.overriding) return false;
|
||||
if (mathEqual(factor, tr.scale)) return true;
|
||||
tr.scale = factor;
|
||||
renderFlag |= RenderUpdateFlag::Transform;
|
||||
|
||||
return true;
|
||||
|
@ -212,15 +193,10 @@ bool Paint::Impl::scale(float factor)
|
|||
|
||||
bool Paint::Impl::translate(float x, float y)
|
||||
{
|
||||
if (rTransform) {
|
||||
if (rTransform->overriding) return false;
|
||||
if (mathEqual(x, rTransform->m.e13) && mathEqual(y, rTransform->m.e23)) return true;
|
||||
} else {
|
||||
if (mathZero(x) && mathZero(y)) return true;
|
||||
rTransform = new RenderTransform();
|
||||
}
|
||||
rTransform->m.e13 = x;
|
||||
rTransform->m.e23 = y;
|
||||
if (tr.overriding) return false;
|
||||
if (mathEqual(x, tr.m.e13) && mathEqual(y, tr.m.e23)) return true;
|
||||
tr.m.e13 = x;
|
||||
tr.m.e23 = y;
|
||||
renderFlag |= RenderUpdateFlag::Transform;
|
||||
|
||||
return true;
|
||||
|
@ -229,6 +205,8 @@ bool Paint::Impl::translate(float x, float y)
|
|||
|
||||
bool Paint::Impl::render(RenderMethod* renderer)
|
||||
{
|
||||
if (opacity == 0) return true;
|
||||
|
||||
Compositor* cmp = nullptr;
|
||||
|
||||
/* Note: only ClipPath is processed in update() step.
|
||||
|
@ -258,7 +236,7 @@ bool Paint::Impl::render(RenderMethod* renderer)
|
|||
}
|
||||
|
||||
|
||||
RenderData Paint::Impl::update(RenderMethod* renderer, const RenderTransform* pTransform, Array<RenderData>& clips, uint8_t opacity, RenderUpdateFlag pFlag, bool clipper)
|
||||
RenderData Paint::Impl::update(RenderMethod* renderer, const Matrix& pm, Array<RenderData>& clips, uint8_t opacity, RenderUpdateFlag pFlag, bool clipper)
|
||||
{
|
||||
if (this->renderer != renderer) {
|
||||
if (this->renderer) TVGERR("RENDERER", "paint's renderer has been changed!");
|
||||
|
@ -266,7 +244,7 @@ RenderData Paint::Impl::update(RenderMethod* renderer, const RenderTransform* pT
|
|||
this->renderer = renderer;
|
||||
}
|
||||
|
||||
if (renderFlag & RenderUpdateFlag::Transform) rTransform->update();
|
||||
if (renderFlag & RenderUpdateFlag::Transform) tr.update();
|
||||
|
||||
/* 1. Composition Pre Processing */
|
||||
RenderData trd = nullptr; //composite target render data
|
||||
|
@ -277,7 +255,7 @@ RenderData Paint::Impl::update(RenderMethod* renderer, const RenderTransform* pT
|
|||
if (compData) {
|
||||
auto target = compData->target;
|
||||
auto method = compData->method;
|
||||
target->pImpl->ctxFlag &= ~ContextFlag::FastTrack; //reset
|
||||
P(target)->ctxFlag &= ~ContextFlag::FastTrack; //reset
|
||||
|
||||
/* If the transformation has no rotational factors and the ClipPath/Alpha(InvAlpha)Masking involves a simple rectangle,
|
||||
we can optimize by using the viewport instead of the regular ClipPath/AlphaMasking sequence for improved performance. */
|
||||
|
@ -296,14 +274,14 @@ RenderData Paint::Impl::update(RenderMethod* renderer, const RenderTransform* pT
|
|||
}
|
||||
if (tryFastTrack) {
|
||||
viewport = renderer->viewport();
|
||||
if ((compFastTrack = _compFastTrack(renderer, target, pTransform, target->pImpl->rTransform, viewport)) == Result::Success) {
|
||||
target->pImpl->ctxFlag |= ContextFlag::FastTrack;
|
||||
if ((compFastTrack = _compFastTrack(renderer, target, pm, viewport)) == Result::Success) {
|
||||
P(target)->ctxFlag |= ContextFlag::FastTrack;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (compFastTrack == Result::InsufficientCondition) {
|
||||
childClipper = compData->method == CompositeMethod::ClipPath ? true : false;
|
||||
trd = target->pImpl->update(renderer, pTransform, clips, 255, pFlag, childClipper);
|
||||
trd = P(target)->update(renderer, pm, clips, 255, pFlag, childClipper);
|
||||
if (childClipper) clips.push(trd);
|
||||
}
|
||||
}
|
||||
|
@ -314,8 +292,9 @@ RenderData Paint::Impl::update(RenderMethod* renderer, const RenderTransform* pT
|
|||
opacity = MULTIPLY(opacity, this->opacity);
|
||||
|
||||
RenderData rd = nullptr;
|
||||
RenderTransform outTransform(pTransform, rTransform);
|
||||
PAINT_METHOD(rd, update(renderer, &outTransform, clips, opacity, newFlag, clipper));
|
||||
|
||||
tr.cm = pm * tr.m;
|
||||
PAINT_METHOD(rd, update(renderer, tr.cm, clips, opacity, newFlag, clipper));
|
||||
|
||||
/* 3. Composition Post Processing */
|
||||
if (compFastTrack == Result::Success) renderer->viewport(viewport);
|
||||
|
@ -325,13 +304,13 @@ RenderData Paint::Impl::update(RenderMethod* renderer, const RenderTransform* pT
|
|||
}
|
||||
|
||||
|
||||
bool Paint::Impl::bounds(float* x, float* y, float* w, float* h, bool transformed, bool stroking)
|
||||
bool Paint::Impl::bounds(float* x, float* y, float* w, float* h, bool transformed, bool stroking, bool origin)
|
||||
{
|
||||
Matrix* m = nullptr;
|
||||
bool ret;
|
||||
const auto& m = this->transform(origin);
|
||||
|
||||
//Case: No transformed, quick return!
|
||||
if (!transformed || !(m = this->transform())) {
|
||||
if (!transformed || mathIdentity(&m)) {
|
||||
PAINT_METHOD(ret, bounds(x, y, w, h, stroking));
|
||||
return ret;
|
||||
}
|
||||
|
@ -355,7 +334,7 @@ bool Paint::Impl::bounds(float* x, float* y, float* w, float* h, bool transforme
|
|||
|
||||
//Compute the AABB after transformation
|
||||
for (int i = 0; i < 4; i++) {
|
||||
pt[i] *= *m;
|
||||
pt[i] *= m;
|
||||
|
||||
if (pt[i].x < x1) x1 = pt[i].x;
|
||||
if (pt[i].x > x2) x2 = pt[i].x;
|
||||
|
@ -372,6 +351,26 @@ bool Paint::Impl::bounds(float* x, float* y, float* w, float* h, bool transforme
|
|||
}
|
||||
|
||||
|
||||
void Paint::Impl::reset()
|
||||
{
|
||||
if (compData) {
|
||||
if (P(compData->target)->unref() == 0) delete(compData->target);
|
||||
free(compData);
|
||||
compData = nullptr;
|
||||
}
|
||||
mathIdentity(&tr.m);
|
||||
tr.degree = 0.0f;
|
||||
tr.scale = 1.0f;
|
||||
tr.overriding = false;
|
||||
|
||||
blendMethod = BlendMethod::Normal;
|
||||
renderFlag = RenderUpdateFlag::None;
|
||||
ctxFlag = ContextFlag::Invalid;
|
||||
opacity = 255;
|
||||
paint->id = 0;
|
||||
}
|
||||
|
||||
|
||||
/************************************************************************/
|
||||
/* External Class Implementation */
|
||||
/************************************************************************/
|
||||
|
@ -417,9 +416,7 @@ Result Paint::transform(const Matrix& m) noexcept
|
|||
|
||||
Matrix Paint::transform() noexcept
|
||||
{
|
||||
auto pTransform = pImpl->transform();
|
||||
if (pTransform) return *pTransform;
|
||||
return {1, 0, 0, 0, 1, 0, 0, 0, 1};
|
||||
return pImpl->transform();
|
||||
}
|
||||
|
||||
|
||||
|
@ -429,9 +426,9 @@ TVG_DEPRECATED Result Paint::bounds(float* x, float* y, float* w, float* h) cons
|
|||
}
|
||||
|
||||
|
||||
Result Paint::bounds(float* x, float* y, float* w, float* h, bool transform) const noexcept
|
||||
Result Paint::bounds(float* x, float* y, float* w, float* h, bool transformed) const noexcept
|
||||
{
|
||||
if (pImpl->bounds(x, y, w, h, transform, true)) return Result::Success;
|
||||
if (pImpl->bounds(x, y, w, h, transformed, true, transformed)) return Result::Success;
|
||||
return Result::InsufficientCondition;
|
||||
}
|
||||
|
||||
|
@ -444,6 +441,11 @@ Paint* Paint::duplicate() const noexcept
|
|||
|
||||
Result Paint::composite(std::unique_ptr<Paint> target, CompositeMethod method) noexcept
|
||||
{
|
||||
if (method == CompositeMethod::ClipPath && target && target->identifier() != TVG_CLASS_ID_SHAPE) {
|
||||
TVGERR("RENDERER", "ClipPath only allows the Shape!");
|
||||
return Result::NonSupport;
|
||||
}
|
||||
|
||||
auto p = target.release();
|
||||
if (pImpl->composite(this, p, method)) return Result::Success;
|
||||
delete(p);
|
||||
|
@ -486,7 +488,7 @@ uint32_t Paint::identifier() const noexcept
|
|||
}
|
||||
|
||||
|
||||
Result Paint::blend(BlendMethod method) const noexcept
|
||||
Result Paint::blend(BlendMethod method) noexcept
|
||||
{
|
||||
if (pImpl->blendMethod != method) {
|
||||
pImpl->blendMethod = method;
|
||||
|
|
|
@ -48,17 +48,40 @@ namespace tvg
|
|||
struct Paint::Impl
|
||||
{
|
||||
Paint* paint = nullptr;
|
||||
RenderTransform* rTransform = nullptr;
|
||||
Composite* compData = nullptr;
|
||||
RenderMethod* renderer = nullptr;
|
||||
BlendMethod blendMethod = BlendMethod::Normal; //uint8_t
|
||||
uint8_t renderFlag = RenderUpdateFlag::None;
|
||||
uint8_t ctxFlag = ContextFlag::Invalid;
|
||||
uint8_t id;
|
||||
uint8_t opacity = 255;
|
||||
uint8_t refCnt = 0; //reference count
|
||||
struct {
|
||||
Matrix m; //input matrix
|
||||
Matrix cm; //multipled parents matrix
|
||||
float degree; //rotation degree
|
||||
float scale; //scale factor
|
||||
bool overriding; //user transform?
|
||||
|
||||
Impl(Paint* pnt) : paint(pnt) {}
|
||||
void update()
|
||||
{
|
||||
if (overriding) return;
|
||||
m.e11 = 1.0f;
|
||||
m.e12 = 0.0f;
|
||||
m.e21 = 0.0f;
|
||||
m.e22 = 1.0f;
|
||||
m.e31 = 0.0f;
|
||||
m.e32 = 0.0f;
|
||||
m.e33 = 1.0f;
|
||||
mathScale(&m, scale, scale);
|
||||
mathRotate(&m, degree);
|
||||
}
|
||||
} tr;
|
||||
BlendMethod blendMethod;
|
||||
uint8_t renderFlag;
|
||||
uint8_t ctxFlag;
|
||||
uint8_t opacity;
|
||||
uint8_t refCnt = 0; //reference count
|
||||
uint8_t id; //TODO: deprecated, remove it
|
||||
|
||||
Impl(Paint* pnt) : paint(pnt)
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
~Impl()
|
||||
{
|
||||
|
@ -66,7 +89,6 @@ namespace tvg
|
|||
if (P(compData->target)->unref() == 0) delete(compData->target);
|
||||
free(compData);
|
||||
}
|
||||
delete(rTransform);
|
||||
if (renderer && (renderer->unref() == 0)) delete(renderer);
|
||||
}
|
||||
|
||||
|
@ -84,23 +106,19 @@ namespace tvg
|
|||
|
||||
bool transform(const Matrix& m)
|
||||
{
|
||||
if (!rTransform) {
|
||||
if (mathIdentity(&m)) return true;
|
||||
rTransform = new RenderTransform();
|
||||
}
|
||||
rTransform->override(m);
|
||||
tr.m = m;
|
||||
tr.overriding = true;
|
||||
renderFlag |= RenderUpdateFlag::Transform;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Matrix* transform()
|
||||
Matrix& transform(bool origin = false)
|
||||
{
|
||||
if (rTransform) {
|
||||
if (renderFlag & RenderUpdateFlag::Transform) rTransform->update();
|
||||
return &rTransform->m;
|
||||
}
|
||||
return nullptr;
|
||||
//update transform
|
||||
if (renderFlag & RenderUpdateFlag::Transform) tr.update();
|
||||
if (origin) return tr.cm;
|
||||
return tr.m;
|
||||
}
|
||||
|
||||
bool composite(Paint* source, Paint* target, CompositeMethod method)
|
||||
|
@ -135,10 +153,11 @@ namespace tvg
|
|||
bool rotate(float degree);
|
||||
bool scale(float factor);
|
||||
bool translate(float x, float y);
|
||||
bool bounds(float* x, float* y, float* w, float* h, bool transformed, bool stroking);
|
||||
RenderData update(RenderMethod* renderer, const RenderTransform* pTransform, Array<RenderData>& clips, uint8_t opacity, RenderUpdateFlag pFlag, bool clipper = false);
|
||||
bool bounds(float* x, float* y, float* w, float* h, bool transformed, bool stroking, bool origin = false);
|
||||
RenderData update(RenderMethod* renderer, const Matrix& pm, Array<RenderData>& clips, uint8_t opacity, RenderUpdateFlag pFlag, bool clipper = false);
|
||||
bool render(RenderMethod* renderer);
|
||||
Paint* duplicate();
|
||||
Paint* duplicate(Paint* ret = nullptr);
|
||||
void reset();
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -104,21 +104,6 @@ RenderRegion Picture::Impl::bounds(RenderMethod* renderer)
|
|||
}
|
||||
|
||||
|
||||
RenderTransform Picture::Impl::resizeTransform(const RenderTransform* pTransform)
|
||||
{
|
||||
//Overriding Transformation by the desired image size
|
||||
auto sx = w / loader->w;
|
||||
auto sy = h / loader->h;
|
||||
auto scale = sx < sy ? sx : sy;
|
||||
|
||||
RenderTransform tmp;
|
||||
tmp.m = {scale, 0, 0, 0, scale, 0, 0, 0, 1};
|
||||
|
||||
if (!pTransform) return tmp;
|
||||
else return RenderTransform(pTransform, &tmp);
|
||||
}
|
||||
|
||||
|
||||
Result Picture::Impl::load(ImageLoader* loader)
|
||||
{
|
||||
//Same resource has been loaded.
|
||||
|
@ -215,18 +200,24 @@ Result Picture::size(float* w, float* h) const noexcept
|
|||
}
|
||||
|
||||
|
||||
Result Picture::mesh(const Polygon* triangles, uint32_t triangleCnt) noexcept
|
||||
const Paint* Picture::paint(uint32_t id) noexcept
|
||||
{
|
||||
if (!triangles && triangleCnt > 0) return Result::InvalidArguments;
|
||||
if (triangles && triangleCnt == 0) return Result::InvalidArguments;
|
||||
struct Value
|
||||
{
|
||||
uint32_t id;
|
||||
const Paint* ret;
|
||||
} value = {id, nullptr};
|
||||
|
||||
pImpl->mesh(triangles, triangleCnt);
|
||||
return Result::Success;
|
||||
}
|
||||
|
||||
|
||||
uint32_t Picture::mesh(const Polygon** triangles) const noexcept
|
||||
{
|
||||
if (triangles) *triangles = pImpl->rm.triangles;
|
||||
return pImpl->rm.triangleCnt;
|
||||
auto cb = [](const tvg::Paint* paint, void* data) -> bool
|
||||
{
|
||||
auto p = static_cast<Value*>(data);
|
||||
if (p->id == paint->id) {
|
||||
p->ret = paint;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
tvg::Accessor::gen()->set(this, cb, &value);
|
||||
return value.ret;
|
||||
}
|
||||
|
|
|
@ -63,12 +63,10 @@ struct Picture::Impl
|
|||
Surface* surface = nullptr; //bitmap picture uses
|
||||
RenderData rd = nullptr; //engine data
|
||||
float w = 0, h = 0;
|
||||
RenderMesh rm; //mesh data
|
||||
Picture* picture = nullptr;
|
||||
bool resizing = false;
|
||||
bool needComp = false; //need composition
|
||||
|
||||
RenderTransform resizeTransform(const RenderTransform* pTransform);
|
||||
bool needComposition(uint8_t opacity);
|
||||
bool render(RenderMethod* renderer);
|
||||
bool size(float w, float h);
|
||||
|
@ -90,58 +88,37 @@ struct Picture::Impl
|
|||
delete(paint);
|
||||
}
|
||||
|
||||
RenderData update(RenderMethod* renderer, const RenderTransform* pTransform, Array<RenderData>& clips, uint8_t opacity, RenderUpdateFlag pFlag, bool clipper)
|
||||
RenderData update(RenderMethod* renderer, const Matrix& transform, Array<RenderData>& clips, uint8_t opacity, RenderUpdateFlag pFlag, TVG_UNUSED bool clipper)
|
||||
{
|
||||
auto flag = static_cast<RenderUpdateFlag>(pFlag | load());
|
||||
|
||||
if (surface) {
|
||||
if (flag == RenderUpdateFlag::None) return rd;
|
||||
auto transform = resizeTransform(pTransform);
|
||||
rd = renderer->prepare(surface, &rm, rd, &transform, clips, opacity, flag);
|
||||
|
||||
//Overriding Transformation by the desired image size
|
||||
auto sx = w / loader->w;
|
||||
auto sy = h / loader->h;
|
||||
auto scale = sx < sy ? sx : sy;
|
||||
auto m = transform * Matrix{scale, 0, 0, 0, scale, 0, 0, 0, 1};
|
||||
|
||||
rd = renderer->prepare(surface, rd, m, clips, opacity, flag);
|
||||
} else if (paint) {
|
||||
if (resizing) {
|
||||
loader->resize(paint, w, h);
|
||||
resizing = false;
|
||||
}
|
||||
needComp = needComposition(opacity) ? true : false;
|
||||
rd = paint->pImpl->update(renderer, pTransform, clips, opacity, flag, clipper);
|
||||
rd = paint->pImpl->update(renderer, transform, clips, opacity, flag, false);
|
||||
}
|
||||
return rd;
|
||||
}
|
||||
|
||||
bool bounds(float* x, float* y, float* w, float* h, bool stroking)
|
||||
{
|
||||
if (rm.triangleCnt > 0) {
|
||||
auto triangles = rm.triangles;
|
||||
auto min = triangles[0].vertex[0].pt;
|
||||
auto max = triangles[0].vertex[0].pt;
|
||||
|
||||
for (uint32_t i = 0; i < rm.triangleCnt; ++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;
|
||||
}
|
||||
if (x) *x = 0;
|
||||
if (y) *y = 0;
|
||||
if (w) *w = this->w;
|
||||
if (h) *h = this->h;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -176,32 +153,21 @@ struct Picture::Impl
|
|||
return load(loader);
|
||||
}
|
||||
|
||||
void mesh(const Polygon* triangles, const uint32_t triangleCnt)
|
||||
Paint* duplicate(Paint* ret)
|
||||
{
|
||||
if (triangles && triangleCnt > 0) {
|
||||
this->rm.triangleCnt = triangleCnt;
|
||||
this->rm.triangles = (Polygon*)malloc(sizeof(Polygon) * triangleCnt);
|
||||
memcpy(this->rm.triangles, triangles, sizeof(Polygon) * triangleCnt);
|
||||
} else {
|
||||
free(this->rm.triangles);
|
||||
this->rm.triangles = nullptr;
|
||||
this->rm.triangleCnt = 0;
|
||||
}
|
||||
}
|
||||
if (ret) TVGERR("RENDERER", "TODO: duplicate()");
|
||||
|
||||
Paint* duplicate()
|
||||
{
|
||||
load();
|
||||
|
||||
auto ret = Picture::gen().release();
|
||||
auto dup = ret->pImpl;
|
||||
auto picture = Picture::gen().release();
|
||||
auto dup = picture->pImpl;
|
||||
|
||||
if (paint) dup->paint = paint->duplicate();
|
||||
|
||||
if (loader) {
|
||||
dup->loader = loader;
|
||||
++dup->loader->sharing;
|
||||
PP(ret)->renderFlag |= RenderUpdateFlag::Image;
|
||||
PP(picture)->renderFlag |= RenderUpdateFlag::Image;
|
||||
}
|
||||
|
||||
dup->surface = surface;
|
||||
|
@ -209,13 +175,7 @@ struct Picture::Impl
|
|||
dup->h = h;
|
||||
dup->resizing = resizing;
|
||||
|
||||
if (rm.triangleCnt > 0) {
|
||||
dup->rm.triangleCnt = rm.triangleCnt;
|
||||
dup->rm.triangles = (Polygon*)malloc(sizeof(Polygon) * rm.triangleCnt);
|
||||
memcpy(dup->rm.triangles, rm.triangles, sizeof(Polygon) * rm.triangleCnt);
|
||||
}
|
||||
|
||||
return ret;
|
||||
return picture;
|
||||
}
|
||||
|
||||
Iterator* iterator()
|
||||
|
|
|
@ -46,41 +46,6 @@ uint32_t RenderMethod::unref()
|
|||
}
|
||||
|
||||
|
||||
void RenderTransform::override(const Matrix& m)
|
||||
{
|
||||
this->m = m;
|
||||
overriding = true;
|
||||
}
|
||||
|
||||
|
||||
void RenderTransform::update()
|
||||
{
|
||||
if (overriding) return;
|
||||
|
||||
m.e11 = 1.0f;
|
||||
m.e12 = 0.0f;
|
||||
|
||||
m.e21 = 0.0f;
|
||||
m.e22 = 1.0f;
|
||||
|
||||
m.e31 = 0.0f;
|
||||
m.e32 = 0.0f;
|
||||
m.e33 = 1.0f;
|
||||
|
||||
mathScale(&m, scale, scale);
|
||||
mathRotate(&m, degree);
|
||||
}
|
||||
|
||||
|
||||
RenderTransform::RenderTransform(const RenderTransform* lhs, const RenderTransform* rhs)
|
||||
{
|
||||
if (lhs && rhs) m = lhs->m * rhs->m;
|
||||
else if (lhs) m = lhs->m;
|
||||
else if (rhs) m = rhs->m;
|
||||
else mathIdentity(&m);
|
||||
}
|
||||
|
||||
|
||||
void RenderRegion::intersect(const RenderRegion& rhs)
|
||||
{
|
||||
auto x1 = x + w;
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#ifndef _TVG_RENDER_H_
|
||||
#define _TVG_RENDER_H_
|
||||
|
||||
#include <math.h>
|
||||
#include "tvgCommon.h"
|
||||
#include "tvgArray.h"
|
||||
#include "tvgLock.h"
|
||||
|
@ -85,15 +86,15 @@ struct Compositor
|
|||
uint8_t opacity;
|
||||
};
|
||||
|
||||
struct RenderMesh
|
||||
struct Vertex
|
||||
{
|
||||
Polygon* triangles = nullptr;
|
||||
uint32_t triangleCnt = 0;
|
||||
Point pt;
|
||||
Point uv;
|
||||
};
|
||||
|
||||
~RenderMesh()
|
||||
{
|
||||
free(triangles);
|
||||
}
|
||||
struct Polygon
|
||||
{
|
||||
Vertex vertex[3];
|
||||
};
|
||||
|
||||
struct RenderRegion
|
||||
|
@ -110,24 +111,6 @@ struct RenderRegion
|
|||
}
|
||||
};
|
||||
|
||||
struct RenderTransform
|
||||
{
|
||||
Matrix m;
|
||||
float degree = 0.0f; //rotation degree
|
||||
float scale = 1.0f; //scale factor
|
||||
bool overriding = false; //user transform?
|
||||
|
||||
void update();
|
||||
void override(const Matrix& m);
|
||||
|
||||
RenderTransform()
|
||||
{
|
||||
m.e13 = m.e23 = 0.0f;
|
||||
}
|
||||
|
||||
RenderTransform(const RenderTransform* lhs, const RenderTransform* rhs);
|
||||
};
|
||||
|
||||
struct RenderStroke
|
||||
{
|
||||
float width = 0.0f;
|
||||
|
@ -147,6 +130,57 @@ struct RenderStroke
|
|||
bool simultaneous = true;
|
||||
} trim;
|
||||
|
||||
void operator=(const RenderStroke& rhs)
|
||||
{
|
||||
width = rhs.width;
|
||||
|
||||
memcpy(color, rhs.color, sizeof(color));
|
||||
|
||||
delete(fill);
|
||||
if (rhs.fill) fill = rhs.fill->duplicate();
|
||||
else fill = nullptr;
|
||||
|
||||
free(dashPattern);
|
||||
if (rhs.dashCnt > 0) {
|
||||
dashPattern = static_cast<float*>(malloc(sizeof(float) * rhs.dashCnt));
|
||||
memcpy(dashPattern, rhs.dashPattern, sizeof(float) * rhs.dashCnt);
|
||||
} else {
|
||||
dashPattern = nullptr;
|
||||
}
|
||||
dashCnt = rhs.dashCnt;
|
||||
miterlimit = rhs.miterlimit;
|
||||
cap = rhs.cap;
|
||||
join = rhs.join;
|
||||
strokeFirst = rhs.strokeFirst;
|
||||
trim = rhs.trim;
|
||||
}
|
||||
|
||||
bool strokeTrim(float& begin, float& end) const
|
||||
{
|
||||
begin = trim.begin;
|
||||
end = trim.end;
|
||||
|
||||
if (fabsf(end - begin) >= 1.0f) {
|
||||
begin = 0.0f;
|
||||
end = 1.0f;
|
||||
return false;
|
||||
}
|
||||
|
||||
auto loop = true;
|
||||
|
||||
if (begin > 1.0f && end > 1.0f) loop = false;
|
||||
if (begin < 0.0f && end < 0.0f) loop = false;
|
||||
if (begin >= 0.0f && begin <= 1.0f && end >= 0.0f && end <= 1.0f) loop = false;
|
||||
|
||||
if (begin > 1.0f) begin -= 1.0f;
|
||||
if (begin < 0.0f) begin += 1.0f;
|
||||
if (end > 1.0f) end -= 1.0f;
|
||||
if (end < 0.0f) end += 1.0f;
|
||||
|
||||
if ((loop && begin < end) || (!loop && begin > end)) std::swap(begin, end);
|
||||
return true;
|
||||
}
|
||||
|
||||
~RenderStroke()
|
||||
{
|
||||
free(dashPattern);
|
||||
|
@ -191,7 +225,7 @@ struct RenderShape
|
|||
{
|
||||
if (!stroke) return false;
|
||||
if (stroke->trim.begin == 0.0f && stroke->trim.end == 1.0f) return false;
|
||||
if (stroke->trim.begin == 1.0f && stroke->trim.end == 0.0f) return false;
|
||||
if (fabsf(stroke->trim.end - stroke->trim.begin) >= 1.0f) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -252,9 +286,8 @@ public:
|
|||
uint32_t unref();
|
||||
|
||||
virtual ~RenderMethod() {}
|
||||
virtual RenderData prepare(const RenderShape& rshape, RenderData data, const RenderTransform* transform, Array<RenderData>& clips, uint8_t opacity, RenderUpdateFlag flags, bool clipper) = 0;
|
||||
virtual RenderData prepare(const Array<RenderData>& scene, RenderData data, const RenderTransform* transform, Array<RenderData>& clips, uint8_t opacity, RenderUpdateFlag flags) = 0;
|
||||
virtual RenderData prepare(Surface* surface, const RenderMesh* mesh, RenderData data, const RenderTransform* transform, Array<RenderData>& clips, uint8_t opacity, RenderUpdateFlag flags) = 0;
|
||||
virtual RenderData prepare(const RenderShape& rshape, RenderData data, const Matrix& transform, Array<RenderData>& clips, uint8_t opacity, RenderUpdateFlag flags, bool clipper) = 0;
|
||||
virtual RenderData prepare(Surface* surface, RenderData data, const Matrix& transform, Array<RenderData>& clips, uint8_t opacity, RenderUpdateFlag flags) = 0;
|
||||
virtual bool preRender() = 0;
|
||||
virtual bool renderShape(RenderData data) = 0;
|
||||
virtual bool renderImage(RenderData data) = 0;
|
||||
|
@ -288,6 +321,8 @@ static inline bool MASK_REGION_MERGING(CompositeMethod method)
|
|||
//these might expand the rendering region
|
||||
case CompositeMethod::AddMask:
|
||||
case CompositeMethod::DifferenceMask:
|
||||
case CompositeMethod::LightenMask:
|
||||
case CompositeMethod::DarkenMask:
|
||||
return true;
|
||||
default:
|
||||
TVGERR("RENDERER", "Unsupported Composite Method! = %d", (int)method);
|
||||
|
@ -321,6 +356,8 @@ static inline ColorSpace COMPOSITE_TO_COLORSPACE(RenderMethod* renderer, Composi
|
|||
case CompositeMethod::DifferenceMask:
|
||||
case CompositeMethod::SubtractMask:
|
||||
case CompositeMethod::IntersectMask:
|
||||
case CompositeMethod::LightenMask:
|
||||
case CompositeMethod::DarkenMask:
|
||||
return ColorSpace::Grayscale8;
|
||||
//TODO: Optimize Luma/InvLuma colorspace to Grayscale8
|
||||
case CompositeMethod::LumaMask:
|
||||
|
|
|
@ -101,7 +101,7 @@ struct Scene::Impl
|
|||
return true;
|
||||
}
|
||||
|
||||
RenderData update(RenderMethod* renderer, const RenderTransform* transform, Array<RenderData>& clips, uint8_t opacity, RenderUpdateFlag flag, bool clipper)
|
||||
RenderData update(RenderMethod* renderer, const Matrix& transform, Array<RenderData>& clips, uint8_t opacity, RenderUpdateFlag flag, TVG_UNUSED bool clipper)
|
||||
{
|
||||
if ((needComp = needComposition(opacity))) {
|
||||
/* Overriding opacity value. If this scene is half-translucent,
|
||||
|
@ -109,20 +109,10 @@ struct Scene::Impl
|
|||
this->opacity = opacity;
|
||||
opacity = 255;
|
||||
}
|
||||
|
||||
if (clipper) {
|
||||
Array<RenderData> rds(paints.size());
|
||||
for (auto paint : paints) {
|
||||
rds.push(paint->pImpl->update(renderer, transform, clips, opacity, flag, true));
|
||||
}
|
||||
rd = renderer->prepare(rds, rd, transform, clips, opacity, flag);
|
||||
return rd;
|
||||
} else {
|
||||
for (auto paint : paints) {
|
||||
paint->pImpl->update(renderer, transform, clips, opacity, flag, false);
|
||||
}
|
||||
return nullptr;
|
||||
for (auto paint : paints) {
|
||||
paint->pImpl->update(renderer, transform, clips, opacity, flag, false);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool render(RenderMethod* renderer)
|
||||
|
@ -198,10 +188,12 @@ struct Scene::Impl
|
|||
return true;
|
||||
}
|
||||
|
||||
Paint* duplicate()
|
||||
Paint* duplicate(Paint* ret)
|
||||
{
|
||||
auto ret = Scene::gen().release();
|
||||
auto dup = ret->pImpl;
|
||||
if (ret) TVGERR("RENDERER", "TODO: duplicate()");
|
||||
|
||||
auto scene = Scene::gen().release();
|
||||
auto dup = scene->pImpl;
|
||||
|
||||
for (auto paint : paints) {
|
||||
auto cdup = paint->duplicate();
|
||||
|
@ -209,7 +201,7 @@ struct Scene::Impl
|
|||
dup->paints.push_back(cdup);
|
||||
}
|
||||
|
||||
return ret;
|
||||
return scene;
|
||||
}
|
||||
|
||||
void clear(bool free)
|
||||
|
|
|
@ -34,6 +34,7 @@ struct Shape::Impl
|
|||
RenderData rd = nullptr; //engine data
|
||||
Shape* shape;
|
||||
uint8_t flag = RenderUpdateFlag::None;
|
||||
|
||||
uint8_t opacity; //for composition
|
||||
bool needComp = false; //composite or not
|
||||
|
||||
|
@ -95,7 +96,7 @@ struct Shape::Impl
|
|||
return true;
|
||||
}
|
||||
|
||||
RenderData update(RenderMethod* renderer, const RenderTransform* transform, Array<RenderData>& clips, uint8_t opacity, RenderUpdateFlag pFlag, bool clipper)
|
||||
RenderData update(RenderMethod* renderer, const Matrix& transform, Array<RenderData>& clips, uint8_t opacity, RenderUpdateFlag pFlag, bool clipper)
|
||||
{
|
||||
if (static_cast<RenderUpdateFlag>(pFlag | flag) == RenderUpdateFlag::None) return rd;
|
||||
|
||||
|
@ -216,23 +217,6 @@ struct Shape::Impl
|
|||
if (mathEqual(rs.stroke->trim.begin, begin) && mathEqual(rs.stroke->trim.end, end) &&
|
||||
rs.stroke->trim.simultaneous == simultaneous) return;
|
||||
|
||||
auto loop = true;
|
||||
|
||||
if (begin > 1.0f && end > 1.0f) loop = false;
|
||||
if (begin < 0.0f && end < 0.0f) loop = false;
|
||||
if (begin >= 0.0f && begin <= 1.0f && end >= 0.0f && end <= 1.0f) loop = false;
|
||||
|
||||
if (begin > 1.0f) begin -= 1.0f;
|
||||
if (begin < 0.0f) begin += 1.0f;
|
||||
if (end > 1.0f) end -= 1.0f;
|
||||
if (end < 0.0f) end += 1.0f;
|
||||
|
||||
if ((loop && begin < end) || (!loop && begin > end)) {
|
||||
auto tmp = begin;
|
||||
begin = end;
|
||||
end = tmp;
|
||||
}
|
||||
|
||||
rs.stroke->trim.begin = begin;
|
||||
rs.stroke->trim.end = end;
|
||||
rs.stroke->trim.simultaneous = simultaneous;
|
||||
|
@ -359,47 +343,56 @@ struct Shape::Impl
|
|||
this->flag |= flag;
|
||||
}
|
||||
|
||||
Paint* duplicate()
|
||||
Paint* duplicate(Paint* ret)
|
||||
{
|
||||
auto ret = Shape::gen().release();
|
||||
auto dup = ret->pImpl;
|
||||
auto shape = static_cast<Shape*>(ret);
|
||||
if (shape) shape->reset();
|
||||
else shape = Shape::gen().release();
|
||||
|
||||
auto dup = shape->pImpl;
|
||||
delete(dup->rs.fill);
|
||||
|
||||
//Default Properties
|
||||
dup->flag = RenderUpdateFlag::All;
|
||||
dup->rs.rule = rs.rule;
|
||||
|
||||
//Color
|
||||
memcpy(dup->rs.color, rs.color, sizeof(rs.color));
|
||||
dup->flag = RenderUpdateFlag::Color;
|
||||
|
||||
//Path
|
||||
if (rs.path.cmds.count > 0 && rs.path.pts.count > 0) {
|
||||
dup->rs.path.cmds = rs.path.cmds;
|
||||
dup->rs.path.pts = rs.path.pts;
|
||||
dup->flag |= RenderUpdateFlag::Path;
|
||||
}
|
||||
dup->rs.path.cmds.push(rs.path.cmds);
|
||||
dup->rs.path.pts.push(rs.path.pts);
|
||||
|
||||
//Stroke
|
||||
if (rs.stroke) {
|
||||
dup->rs.stroke = new RenderStroke();
|
||||
if (!dup->rs.stroke) dup->rs.stroke = new RenderStroke;
|
||||
*dup->rs.stroke = *rs.stroke;
|
||||
memcpy(dup->rs.stroke->color, rs.stroke->color, sizeof(rs.stroke->color));
|
||||
if (rs.stroke->dashCnt > 0) {
|
||||
dup->rs.stroke->dashPattern = static_cast<float*>(malloc(sizeof(float) * rs.stroke->dashCnt));
|
||||
memcpy(dup->rs.stroke->dashPattern, rs.stroke->dashPattern, sizeof(float) * rs.stroke->dashCnt);
|
||||
}
|
||||
if (rs.stroke->fill) {
|
||||
dup->rs.stroke->fill = rs.stroke->fill->duplicate();
|
||||
dup->flag |= RenderUpdateFlag::GradientStroke;
|
||||
}
|
||||
dup->flag |= RenderUpdateFlag::Stroke;
|
||||
} else {
|
||||
delete(dup->rs.stroke);
|
||||
dup->rs.stroke = nullptr;
|
||||
}
|
||||
|
||||
//Fill
|
||||
if (rs.fill) {
|
||||
dup->rs.fill = rs.fill->duplicate();
|
||||
dup->flag |= RenderUpdateFlag::Gradient;
|
||||
}
|
||||
if (rs.fill) dup->rs.fill = rs.fill->duplicate();
|
||||
else dup->rs.fill = nullptr;
|
||||
|
||||
return ret;
|
||||
return shape;
|
||||
}
|
||||
|
||||
void reset()
|
||||
{
|
||||
PP(shape)->reset();
|
||||
rs.path.cmds.clear();
|
||||
rs.path.pts.clear();
|
||||
|
||||
rs.color[3] = 0;
|
||||
rs.rule = FillRule::Winding;
|
||||
|
||||
delete(rs.stroke);
|
||||
rs.stroke = nullptr;
|
||||
|
||||
delete(rs.fill);
|
||||
rs.fill = nullptr;
|
||||
}
|
||||
|
||||
Iterator* iterator()
|
||||
|
|
|
@ -23,8 +23,6 @@
|
|||
#ifndef _TVG_TASK_SCHEDULER_H_
|
||||
#define _TVG_TASK_SCHEDULER_H_
|
||||
|
||||
#define _DISABLE_CONSTEXPR_MUTEX_CONSTRUCTOR
|
||||
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
/************************************************************************/
|
||||
|
||||
|
||||
Text::Text() : pImpl(new Impl)
|
||||
Text::Text() : pImpl(new Impl(this))
|
||||
{
|
||||
Paint::pImpl->id = TVG_CLASS_ID_TEXT;
|
||||
}
|
||||
|
@ -95,20 +95,13 @@ Result Text::unload(const std::string& path) noexcept
|
|||
|
||||
Result Text::fill(uint8_t r, uint8_t g, uint8_t b) noexcept
|
||||
{
|
||||
if (!pImpl->paint) return Result::InsufficientCondition;
|
||||
|
||||
return pImpl->fill(r, g, b);
|
||||
return pImpl->shape->fill(r, g, b);
|
||||
}
|
||||
|
||||
|
||||
Result Text::fill(unique_ptr<Fill> f) noexcept
|
||||
{
|
||||
if (!pImpl->paint) return Result::InsufficientCondition;
|
||||
|
||||
auto p = f.release();
|
||||
if (!p) return Result::MemoryCorruption;
|
||||
|
||||
return pImpl->fill(p);
|
||||
return pImpl->shape->fill(std::move(f));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -36,27 +36,22 @@
|
|||
struct Text::Impl
|
||||
{
|
||||
FontLoader* loader = nullptr;
|
||||
Shape* paint = nullptr;
|
||||
Text* paint;
|
||||
Shape* shape;
|
||||
char* utf8 = nullptr;
|
||||
float fontSize;
|
||||
bool italic = false;
|
||||
bool changed = false;
|
||||
|
||||
Impl(Text* p) : paint(p), shape(Shape::gen().release())
|
||||
{
|
||||
}
|
||||
|
||||
~Impl()
|
||||
{
|
||||
free(utf8);
|
||||
LoaderMgr::retrieve(loader);
|
||||
delete(paint);
|
||||
}
|
||||
|
||||
Result fill(uint8_t r, uint8_t g, uint8_t b)
|
||||
{
|
||||
return paint->fill(r, g, b);
|
||||
}
|
||||
|
||||
Result fill(Fill* f)
|
||||
{
|
||||
return paint->fill(cast<Fill>(f));
|
||||
delete(shape);
|
||||
}
|
||||
|
||||
Result text(const char* utf8)
|
||||
|
@ -83,8 +78,6 @@ struct Text::Impl
|
|||
}
|
||||
this->loader = static_cast<FontLoader*>(loader);
|
||||
|
||||
if (!paint) paint = Shape::gen().release();
|
||||
|
||||
fontSize = size;
|
||||
if (style && strstr(style, "italic")) italic = true;
|
||||
changed = true;
|
||||
|
@ -93,14 +86,12 @@ struct Text::Impl
|
|||
|
||||
RenderRegion bounds(RenderMethod* renderer)
|
||||
{
|
||||
if (paint) return P(paint)->bounds(renderer);
|
||||
else return {0, 0, 0, 0};
|
||||
return P(shape)->bounds(renderer);
|
||||
}
|
||||
|
||||
bool render(RenderMethod* renderer)
|
||||
{
|
||||
if (paint) return PP(paint)->render(renderer);
|
||||
return true;
|
||||
return PP(shape)->render(renderer);
|
||||
}
|
||||
|
||||
bool load()
|
||||
|
@ -109,24 +100,20 @@ struct Text::Impl
|
|||
|
||||
//reload
|
||||
if (changed) {
|
||||
loader->request(paint, utf8, italic);
|
||||
loader->request(shape, utf8, italic);
|
||||
loader->read();
|
||||
changed = false;
|
||||
}
|
||||
if (paint) {
|
||||
loader->resize(paint, fontSize, fontSize);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return loader->resize(shape, fontSize, fontSize);
|
||||
}
|
||||
|
||||
RenderData update(RenderMethod* renderer, const RenderTransform* transform, Array<RenderData>& clips, uint8_t opacity, RenderUpdateFlag pFlag, bool clipper)
|
||||
RenderData update(RenderMethod* renderer, const Matrix& transform, Array<RenderData>& clips, uint8_t opacity, RenderUpdateFlag pFlag, TVG_UNUSED bool clipper)
|
||||
{
|
||||
if (!load()) return nullptr;
|
||||
|
||||
//transform the gradient coordinates based on the final scaled font.
|
||||
if (P(paint)->flag & RenderUpdateFlag::Gradient) {
|
||||
auto fill = P(paint)->rs.fill;
|
||||
auto fill = P(shape)->rs.fill;
|
||||
if (fill && P(shape)->flag & RenderUpdateFlag::Gradient) {
|
||||
auto scale = 1.0f / loader->scale;
|
||||
if (fill->identifier() == TVG_CLASS_ID_LINEAR) {
|
||||
P(static_cast<LinearGradient*>(fill))->x1 *= scale;
|
||||
|
@ -142,23 +129,25 @@ struct Text::Impl
|
|||
P(static_cast<RadialGradient*>(fill))->fr *= scale;
|
||||
}
|
||||
}
|
||||
return PP(paint)->update(renderer, transform, clips, opacity, pFlag, clipper);
|
||||
return PP(shape)->update(renderer, transform, clips, opacity, pFlag, false);
|
||||
}
|
||||
|
||||
bool bounds(float* x, float* y, float* w, float* h, TVG_UNUSED bool stroking)
|
||||
{
|
||||
if (!load() || !paint) return false;
|
||||
paint->bounds(x, y, w, h, true);
|
||||
if (!load()) return false;
|
||||
PP(shape)->bounds(x, y, w, h, true, true, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
Paint* duplicate()
|
||||
Paint* duplicate(Paint* ret)
|
||||
{
|
||||
if (ret) TVGERR("RENDERER", "TODO: duplicate()");
|
||||
|
||||
load();
|
||||
|
||||
auto ret = Text::gen().release();
|
||||
auto dup = ret->pImpl;
|
||||
if (paint) dup->paint = static_cast<Shape*>(paint->duplicate());
|
||||
auto text = Text::gen().release();
|
||||
auto dup = text->pImpl;
|
||||
P(shape)->duplicate(dup->shape);
|
||||
|
||||
if (loader) {
|
||||
dup->loader = loader;
|
||||
|
@ -169,7 +158,7 @@ struct Text::Impl
|
|||
dup->italic = italic;
|
||||
dup->fontSize = fontSize;
|
||||
|
||||
return ret;
|
||||
return text;
|
||||
}
|
||||
|
||||
Iterator* iterator()
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#!/bin/bash -e
|
||||
|
||||
VERSION=0.14.2
|
||||
VERSION=0.14.7
|
||||
|
||||
cd thirdparty/thorvg/ || true
|
||||
rm -rf AUTHORS LICENSE inc/ src/ *.zip *.tar.gz tmp/
|
||||
|
|
Loading…
Reference in New Issue