ThorVG: update from v0.11.2 to v0.11.6
https://github.com/thorvg/thorvg/releases/tag/v0.11.6
Godot related:
+ [Renderer] Improved the internal structure for compact
scene-hierarchy traversing.
+ [SwEngine] Improved trigonometric & image scaler performance.
+ [SwEngine] Fixed a loss of image pixels during image down-scaling.
+ [Renderer/Engine] Improved safety measures.
+ [SwEngine] Resolved a bug causing strokes to be improperly
invisible due to clipping.
thorvg/thorvg#1785
+ [Renderer] Rectified the precision of rounded rectangle corners.
thorvg/thorvg#1824
+ [Portability] Resolved compiler shadowing warnings.
thorvg/thorvg#1811
Fixes godotengine#85465 Clipped strokes from outside the canvas.
Fixes godotengine#86012 Rounded rectangles in SVG files rendering incorrectly.
(cherry picked from commit 74ed6d63bf
)
This commit is contained in:
parent
50eaeec2f7
commit
7827a3945b
|
@ -825,7 +825,7 @@ instead of `miniz.h` as an external dependency.
|
|||
## thorvg
|
||||
|
||||
- Upstream: https://github.com/thorvg/thorvg
|
||||
- Version: 0.11.2 (b01fe9bf4461146304d3520d6dc699cf580a3744, 2023)
|
||||
- Version: 0.11.6 (3dba4f12f8f05f86acbc51096ca3a15f5d96bc06, 2023)
|
||||
- License: MIT
|
||||
|
||||
Files extracted from upstream source:
|
||||
|
|
|
@ -9,5 +9,5 @@
|
|||
// For internal debugging:
|
||||
//#define THORVG_LOG_ENABLED
|
||||
|
||||
#define THORVG_VERSION_STRING "0.11.2"
|
||||
#define THORVG_VERSION_STRING "0.11.6"
|
||||
#endif
|
||||
|
|
|
@ -1664,14 +1664,14 @@ public:
|
|||
* @param[in] no The index of the animation frame to be displayed. The index should be less than the totalFrame().
|
||||
*
|
||||
* @retval Result::Success Successfully set the frame.
|
||||
* @retval Result::InsufficientCondition No animatable data loaded from the Picture.
|
||||
* @retval Result::NonSupport The Picture data does not support animations.
|
||||
* @retval Result::InsufficientCondition if the given @p no is the same as the current frame value.
|
||||
* @retval Result::NonSupport The current Picture data does not support animations.
|
||||
*
|
||||
* @see totalFrame()
|
||||
*
|
||||
* @BETA_API
|
||||
*/
|
||||
Result frame(uint32_t no) noexcept;
|
||||
Result frame(float no) noexcept;
|
||||
|
||||
/**
|
||||
* @brief Retrieves a picture instance associated with this animation instance.
|
||||
|
@ -1695,12 +1695,12 @@ public:
|
|||
*
|
||||
* @note If the Picture is not properly configured, this function will return 0.
|
||||
*
|
||||
* @see Animation::frame(uint32_t no)
|
||||
* @see Animation::frame(float no)
|
||||
* @see Animation::totalFrame()
|
||||
*
|
||||
* @BETA_API
|
||||
*/
|
||||
uint32_t curFrame() const noexcept;
|
||||
float curFrame() const noexcept;
|
||||
|
||||
/**
|
||||
* @brief Retrieves the total number of frames in the animation.
|
||||
|
@ -1712,7 +1712,7 @@ public:
|
|||
*
|
||||
* @BETA_API
|
||||
*/
|
||||
uint32_t totalFrame() const noexcept;
|
||||
float totalFrame() const noexcept;
|
||||
|
||||
/**
|
||||
* @brief Retrieves the duration of the animation in seconds.
|
||||
|
@ -1784,6 +1784,31 @@ public:
|
|||
*/
|
||||
Result save(std::unique_ptr<Paint> paint, const std::string& path, bool compress = true) noexcept;
|
||||
|
||||
/**
|
||||
* @brief Export the provided animation data to the specified file path.
|
||||
*
|
||||
* This function exports the given animation data to the provided file path. You can also specify the desired frame rate in frames per second (FPS) by providing the fps parameter.
|
||||
*
|
||||
* @param[in] animation The animation to be saved, including all associated properties.
|
||||
* @param[in] path The path to the file where the animation will be saved.
|
||||
* @param[in] quality The encoded quality level. @c 0 is the minimum, @c 100 is the maximum value(recommended).
|
||||
* @param[in] fps The desired frames per second (FPS). For example, to encode data at 60 FPS, pass 60. Pass 0 to keep the original frame data.
|
||||
*
|
||||
* @return Result::Success if the export succeeds.
|
||||
* @return Result::InsufficientCondition if there are ongoing resource-saving operations.
|
||||
* @return Result::NonSupport if an attempt is made to save the file with an unknown extension or in an unsupported format.
|
||||
* @return Result::MemoryCorruption in case of an internal error.
|
||||
* @return Result::Unknown if attempting to save an empty paint.
|
||||
*
|
||||
* @note A higher frames per second (FPS) would result in a larger file size. It is recommended to use the default value.
|
||||
* @note Saving can be asynchronous if the assigned thread number is greater than zero. To guarantee the saving is done, call sync() afterwards.
|
||||
*
|
||||
* @see Saver::sync()
|
||||
*
|
||||
* @note: Experimental API
|
||||
*/
|
||||
Result save(std::unique_ptr<Animation> animation, const std::string& path, uint32_t quality = 100, uint32_t fps = 0) noexcept;
|
||||
|
||||
/**
|
||||
* @brief Guarantees that the saving task is finished.
|
||||
*
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
|
||||
#include <memory.h>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
|
||||
namespace tvg
|
||||
{
|
||||
|
|
|
@ -107,9 +107,9 @@ unique_ptr<Surface> PngLoader::bitmap()
|
|||
//TODO: It's better to keep this surface instance in the loader side
|
||||
auto surface = new Surface;
|
||||
surface->buf32 = content;
|
||||
surface->stride = w;
|
||||
surface->w = w;
|
||||
surface->h = h;
|
||||
surface->stride = (uint32_t)w;
|
||||
surface->w = (uint32_t)w;
|
||||
surface->h = (uint32_t)h;
|
||||
surface->cs = cs;
|
||||
surface->channelSize = sizeof(uint32_t);
|
||||
surface->owner = true;
|
||||
|
|
|
@ -1456,7 +1456,11 @@ void jpeg_decoder::locate_sof_marker()
|
|||
int c = process_markers();
|
||||
|
||||
switch (c) {
|
||||
case M_SOF2: m_progressive_flag = true;
|
||||
case M_SOF2: {
|
||||
m_progressive_flag = true;
|
||||
read_sof_marker();
|
||||
break;
|
||||
}
|
||||
case M_SOF0: /* baseline DCT */
|
||||
case M_SOF1: { /* extended sequential DCT */
|
||||
read_sof_marker();
|
||||
|
|
|
@ -43,11 +43,16 @@ static double timeStamp()
|
|||
#define SW_ANGLE_PI (180L << 16)
|
||||
#define SW_ANGLE_2PI (SW_ANGLE_PI << 1)
|
||||
#define SW_ANGLE_PI2 (SW_ANGLE_PI >> 1)
|
||||
#define SW_ANGLE_PI4 (SW_ANGLE_PI >> 2)
|
||||
|
||||
using SwCoord = signed long;
|
||||
using SwFixed = signed long long;
|
||||
|
||||
|
||||
static inline float TO_FLOAT(SwCoord val)
|
||||
{
|
||||
return static_cast<float>(val) / 64.0f;
|
||||
}
|
||||
|
||||
struct SwPoint
|
||||
{
|
||||
SwCoord x, y;
|
||||
|
@ -92,6 +97,10 @@ struct SwPoint
|
|||
else return false;
|
||||
}
|
||||
|
||||
Point toPoint() const
|
||||
{
|
||||
return {TO_FLOAT(x), TO_FLOAT(y)};
|
||||
}
|
||||
};
|
||||
|
||||
struct SwSize
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include "tvgMath.h"
|
||||
#include "tvgSwCommon.h"
|
||||
|
||||
|
||||
|
@ -28,173 +28,9 @@
|
|||
/* Internal Class Implementation */
|
||||
/************************************************************************/
|
||||
|
||||
//clz: count leading zero’s
|
||||
#if defined(_MSC_VER) && !defined(__clang__)
|
||||
#include <intrin.h>
|
||||
static uint32_t __inline _clz(uint32_t value)
|
||||
static float TO_RADIAN(SwFixed angle)
|
||||
{
|
||||
unsigned long leadingZero = 0;
|
||||
if (_BitScanReverse(&leadingZero, value)) return 31 - leadingZero;
|
||||
else return 32;
|
||||
}
|
||||
#else
|
||||
#define _clz(x) __builtin_clz((x))
|
||||
#endif
|
||||
|
||||
|
||||
constexpr SwFixed CORDIC_FACTOR = 0xDBD95B16UL; //the Cordic shrink factor 0.858785336480436 * 2^32
|
||||
|
||||
//this table was generated for SW_FT_PI = 180L << 16, i.e. degrees
|
||||
constexpr static auto ATAN_MAX = 23;
|
||||
constexpr static SwFixed ATAN_TBL[] = {
|
||||
1740967L, 919879L, 466945L, 234379L, 117304L, 58666L, 29335L,
|
||||
14668L, 7334L, 3667L, 1833L, 917L, 458L, 229L, 115L,
|
||||
57L, 29L, 14L, 7L, 4L, 2L, 1L};
|
||||
|
||||
static inline SwCoord SATURATE(const SwCoord x)
|
||||
{
|
||||
return (x >> (sizeof(SwCoord) * 8 - 1));
|
||||
}
|
||||
|
||||
|
||||
static inline SwFixed PAD_ROUND(const SwFixed x, int32_t n)
|
||||
{
|
||||
return (((x) + ((n)/2)) & ~((n)-1));
|
||||
}
|
||||
|
||||
|
||||
static SwCoord _downscale(SwFixed x)
|
||||
{
|
||||
//multiply a give value by the CORDIC shrink factor
|
||||
auto s = abs(x);
|
||||
int64_t t = (s * static_cast<int64_t>(CORDIC_FACTOR)) + 0x100000000UL;
|
||||
s = static_cast<SwFixed>(t >> 32);
|
||||
if (x < 0) s = -s;
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
static int32_t _normalize(SwPoint& pt)
|
||||
{
|
||||
/* the highest bit in overflow-safe vector components
|
||||
MSB of 0.858785336480436 * sqrt(0.5) * 2^30 */
|
||||
constexpr auto SAFE_MSB = 29;
|
||||
|
||||
auto v = pt;
|
||||
|
||||
//High order bit(MSB)
|
||||
int32_t shift = 31 - _clz(abs(v.x) | abs(v.y));
|
||||
|
||||
if (shift <= SAFE_MSB) {
|
||||
shift = SAFE_MSB - shift;
|
||||
pt.x = static_cast<SwCoord>((unsigned long)v.x << shift);
|
||||
pt.y = static_cast<SwCoord>((unsigned long)v.y << shift);
|
||||
} else {
|
||||
shift -= SAFE_MSB;
|
||||
pt.x = v.x >> shift;
|
||||
pt.y = v.y >> shift;
|
||||
shift = -shift;
|
||||
}
|
||||
return shift;
|
||||
}
|
||||
|
||||
|
||||
static void _polarize(SwPoint& pt)
|
||||
{
|
||||
auto v = pt;
|
||||
SwFixed theta;
|
||||
|
||||
//Get the vector into [-PI/4, PI/4] sector
|
||||
if (v.y > v.x) {
|
||||
if (v.y > -v.x) {
|
||||
auto tmp = v.y;
|
||||
v.y = -v.x;
|
||||
v.x = tmp;
|
||||
theta = SW_ANGLE_PI2;
|
||||
} else {
|
||||
theta = v.y > 0 ? SW_ANGLE_PI : -SW_ANGLE_PI;
|
||||
v.x = -v.x;
|
||||
v.y = -v.y;
|
||||
}
|
||||
} else {
|
||||
if (v.y < -v.x) {
|
||||
theta = -SW_ANGLE_PI2;
|
||||
auto tmp = -v.y;
|
||||
v.y = v.x;
|
||||
v.x = tmp;
|
||||
} else {
|
||||
theta = 0;
|
||||
}
|
||||
}
|
||||
|
||||
auto atan = ATAN_TBL;
|
||||
uint32_t i;
|
||||
SwFixed j;
|
||||
|
||||
//Pseudorotations. with right shifts
|
||||
for (i = 1, j = 1; i < ATAN_MAX; j <<= 1, ++i) {
|
||||
if (v.y > 0) {
|
||||
auto tmp = v.x + ((v.y + j) >> i);
|
||||
v.y = v.y - ((v.x + j) >> i);
|
||||
v.x = tmp;
|
||||
theta += *atan++;
|
||||
} else {
|
||||
auto tmp = v.x - ((v.y + j) >> i);
|
||||
v.y = v.y + ((v.x + j) >> i);
|
||||
v.x = tmp;
|
||||
theta -= *atan++;
|
||||
}
|
||||
}
|
||||
|
||||
//round theta
|
||||
if (theta >= 0) theta = PAD_ROUND(theta, 32);
|
||||
else theta = -PAD_ROUND(-theta, 32);
|
||||
|
||||
pt.x = v.x;
|
||||
pt.y = theta;
|
||||
}
|
||||
|
||||
|
||||
static void _rotate(SwPoint& pt, SwFixed theta)
|
||||
{
|
||||
SwFixed x = pt.x;
|
||||
SwFixed y = pt.y;
|
||||
|
||||
//Rotate inside [-PI/4, PI/4] sector
|
||||
while (theta < -SW_ANGLE_PI4) {
|
||||
auto tmp = y;
|
||||
y = -x;
|
||||
x = tmp;
|
||||
theta += SW_ANGLE_PI2;
|
||||
}
|
||||
|
||||
while (theta > SW_ANGLE_PI4) {
|
||||
auto tmp = -y;
|
||||
y = x;
|
||||
x = tmp;
|
||||
theta -= SW_ANGLE_PI2;
|
||||
}
|
||||
|
||||
auto atan = ATAN_TBL;
|
||||
uint32_t i;
|
||||
SwFixed j;
|
||||
|
||||
for (i = 1, j = 1; i < ATAN_MAX; j <<= 1, ++i) {
|
||||
if (theta < 0) {
|
||||
auto tmp = x + ((y + j) >> i);
|
||||
y = y - ((x + j) >> i);
|
||||
x = tmp;
|
||||
theta += *atan++;
|
||||
} else {
|
||||
auto tmp = x - ((y + j) >> i);
|
||||
y = y + ((x + j) >> i);
|
||||
x = tmp;
|
||||
theta -= *atan++;
|
||||
}
|
||||
}
|
||||
|
||||
pt.x = static_cast<SwCoord>(x);
|
||||
pt.y = static_cast<SwCoord>(y);
|
||||
return (float(angle) / 65536.0f) * (MATH_PI / 180.0f);
|
||||
}
|
||||
|
||||
|
||||
|
@ -214,11 +50,17 @@ bool mathSmallCubic(const SwPoint* base, SwFixed& angleIn, SwFixed& angleMid, Sw
|
|||
auto d2 = base[1] - base[2];
|
||||
auto d3 = base[0] - base[1];
|
||||
|
||||
if (d1 == d2 || d2 == d3) {
|
||||
if (d3.small()) angleIn = angleMid = angleOut = 0;
|
||||
else angleIn = angleMid = angleOut = mathAtan(d3);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (d1.small()) {
|
||||
if (d2.small()) {
|
||||
if (d3.small()) {
|
||||
//basically a point.
|
||||
//do nothing to retain original direction
|
||||
angleIn = angleMid = angleOut = 0;
|
||||
return true;
|
||||
} else {
|
||||
angleIn = angleMid = angleOut = mathAtan(d3);
|
||||
}
|
||||
|
@ -320,77 +162,63 @@ int64_t mathMulDiv(int64_t a, int64_t b, int64_t c)
|
|||
|
||||
void mathRotate(SwPoint& pt, SwFixed angle)
|
||||
{
|
||||
if (angle == 0 || (pt.x == 0 && pt.y == 0)) return;
|
||||
if (angle == 0 || pt.zero()) return;
|
||||
|
||||
auto v = pt;
|
||||
auto shift = _normalize(v);
|
||||
Point v = pt.toPoint();
|
||||
|
||||
auto theta = angle;
|
||||
_rotate(v, theta);
|
||||
auto radian = TO_RADIAN(angle);
|
||||
auto cosv = cosf(radian);
|
||||
auto sinv = sinf(radian);
|
||||
|
||||
v.x = _downscale(v.x);
|
||||
v.y = _downscale(v.y);
|
||||
|
||||
if (shift > 0) {
|
||||
auto half = static_cast<int32_t>(1L << (shift - 1));
|
||||
pt.x = (v.x + half + SATURATE(v.x)) >> shift;
|
||||
pt.y = (v.y + half + SATURATE(v.y)) >> shift;
|
||||
} else {
|
||||
shift = -shift;
|
||||
pt.x = static_cast<SwCoord>((unsigned long)v.x << shift);
|
||||
pt.y = static_cast<SwCoord>((unsigned long)v.y << shift);
|
||||
}
|
||||
pt.x = SwCoord(roundf((v.x * cosv - v.y * sinv) * 64.0f));
|
||||
pt.y = SwCoord(roundf((v.x * sinv + v.y * cosv) * 64.0f));
|
||||
}
|
||||
|
||||
|
||||
SwFixed mathTan(SwFixed angle)
|
||||
{
|
||||
SwPoint v = {CORDIC_FACTOR >> 8, 0};
|
||||
_rotate(v, angle);
|
||||
return mathDivide(v.y, v.x);
|
||||
if (angle == 0) return 0;
|
||||
return SwFixed(tanf(TO_RADIAN(angle)) * 65536.0f);
|
||||
}
|
||||
|
||||
|
||||
SwFixed mathAtan(const SwPoint& pt)
|
||||
{
|
||||
if (pt.x == 0 && pt.y == 0) return 0;
|
||||
|
||||
auto v = pt;
|
||||
_normalize(v);
|
||||
_polarize(v);
|
||||
|
||||
return v.y;
|
||||
if (pt.zero()) return 0;
|
||||
return SwFixed(atan2f(TO_FLOAT(pt.y), TO_FLOAT(pt.x)) * (180.0f / MATH_PI) * 65536.0f);
|
||||
}
|
||||
|
||||
|
||||
SwFixed mathSin(SwFixed angle)
|
||||
{
|
||||
if (angle == 0) return 0;
|
||||
return mathCos(SW_ANGLE_PI2 - angle);
|
||||
}
|
||||
|
||||
|
||||
SwFixed mathCos(SwFixed angle)
|
||||
{
|
||||
SwPoint v = {CORDIC_FACTOR >> 8, 0};
|
||||
_rotate(v, angle);
|
||||
return (v.x + 0x80L) >> 8;
|
||||
return SwFixed(cosf(TO_RADIAN(angle)) * 65536.0f);
|
||||
}
|
||||
|
||||
|
||||
SwFixed mathLength(const SwPoint& pt)
|
||||
{
|
||||
auto v = pt;
|
||||
if (pt.zero()) return 0;
|
||||
|
||||
//trivial case
|
||||
if (v.x == 0) return abs(v.y);
|
||||
if (v.y == 0) return abs(v.x);
|
||||
if (pt.x == 0) return abs(pt.y);
|
||||
if (pt.y == 0) return abs(pt.x);
|
||||
|
||||
//general case
|
||||
auto shift = _normalize(v);
|
||||
_polarize(v);
|
||||
v.x = _downscale(v.x);
|
||||
auto v = pt.toPoint();
|
||||
//return static_cast<SwFixed>(sqrtf(v.x * v.x + v.y * v.y) * 65536.0f);
|
||||
|
||||
if (shift > 0) return (v.x + (static_cast<SwFixed>(1) << (shift -1))) >> shift;
|
||||
return static_cast<SwFixed>((uint32_t)v.x << -shift);
|
||||
/* approximate sqrt(x*x + y*y) using alpha max plus beta min algorithm.
|
||||
With alpha = 1, beta = 3/8, giving results with the largest error less
|
||||
than 7% compared to the exact value. */
|
||||
if (v.x < 0) v.x = -v.x;
|
||||
if (v.y < 0) v.y = -v.y;
|
||||
return static_cast<SwFixed>((v.x > v.y) ? (v.x + v.y * 0.375f) : (v.y + v.x * 0.375f));
|
||||
}
|
||||
|
||||
|
||||
|
@ -401,22 +229,22 @@ void mathSplitCubic(SwPoint* base)
|
|||
base[6].x = base[3].x;
|
||||
c = base[1].x;
|
||||
d = base[2].x;
|
||||
base[1].x = a = (base[0].x + c) / 2;
|
||||
base[5].x = b = (base[3].x + d) / 2;
|
||||
c = (c + d) / 2;
|
||||
base[2].x = a = (a + c) / 2;
|
||||
base[4].x = b = (b + c) / 2;
|
||||
base[3].x = (a + b) / 2;
|
||||
base[1].x = a = (base[0].x + c) >> 1;
|
||||
base[5].x = b = (base[3].x + d) >> 1;
|
||||
c = (c + d) >> 1;
|
||||
base[2].x = a = (a + c) >> 1;
|
||||
base[4].x = b = (b + c) >> 1;
|
||||
base[3].x = (a + b) >> 1;
|
||||
|
||||
base[6].y = base[3].y;
|
||||
c = base[1].y;
|
||||
d = base[2].y;
|
||||
base[1].y = a = (base[0].y + c) / 2;
|
||||
base[5].y = b = (base[3].y + d) / 2;
|
||||
c = (c + d) / 2;
|
||||
base[2].y = a = (a + c) / 2;
|
||||
base[4].y = b = (b + c) / 2;
|
||||
base[3].y = (a + b) / 2;
|
||||
base[1].y = a = (base[0].y + c) >> 1;
|
||||
base[5].y = b = (base[3].y + d) >> 1;
|
||||
c = (c + d) >> 1;
|
||||
base[2].y = a = (a + c) >> 1;
|
||||
base[4].y = b = (b + c) >> 1;
|
||||
base[3].y = (a + b) >> 1;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -248,17 +248,17 @@ static inline uint32_t _sampleSize(float scale)
|
|||
|
||||
//Bilinear Interpolation
|
||||
//OPTIMIZE_ME: Skip the function pointer access
|
||||
static uint32_t _interpUpScaler(const uint32_t *img, TVG_UNUSED uint32_t stride, uint32_t w, uint32_t h, float sx, float sy, TVG_UNUSED uint32_t n, TVG_UNUSED uint32_t n2)
|
||||
static uint32_t _interpUpScaler(const uint32_t *img, TVG_UNUSED uint32_t stride, uint32_t w, uint32_t h, float sx, float sy, TVG_UNUSED int32_t miny, TVG_UNUSED int32_t maxy, TVG_UNUSED int32_t n)
|
||||
{
|
||||
auto rx = (uint32_t)(sx);
|
||||
auto ry = (uint32_t)(sy);
|
||||
auto rx = (size_t)(sx);
|
||||
auto ry = (size_t)(sy);
|
||||
auto rx2 = rx + 1;
|
||||
if (rx2 >= w) rx2 = w - 1;
|
||||
auto ry2 = ry + 1;
|
||||
if (ry2 >= h) ry2 = h - 1;
|
||||
|
||||
auto dx = static_cast<uint32_t>((sx - rx) * 255.0f);
|
||||
auto dy = static_cast<uint32_t>((sy - ry) * 255.0f);
|
||||
auto dx = static_cast<size_t>((sx - rx) * 255.0f);
|
||||
auto dy = static_cast<size_t>((sy - ry) * 255.0f);
|
||||
|
||||
auto c1 = img[rx + ry * w];
|
||||
auto c2 = img[rx2 + ry * w];
|
||||
|
@ -271,18 +271,21 @@ static uint32_t _interpUpScaler(const uint32_t *img, TVG_UNUSED uint32_t stride,
|
|||
|
||||
//2n x 2n Mean Kernel
|
||||
//OPTIMIZE_ME: Skip the function pointer access
|
||||
static uint32_t _interpDownScaler(const uint32_t *img, uint32_t stride, uint32_t w, uint32_t h, float sx, float sy, uint32_t n, uint32_t n2)
|
||||
static uint32_t _interpDownScaler(const uint32_t *img, uint32_t stride, uint32_t w, uint32_t h, float sx, TVG_UNUSED float sy, int32_t miny, int32_t maxy, int32_t n)
|
||||
{
|
||||
uint32_t rx = lroundf(sx);
|
||||
uint32_t ry = lroundf(sy);
|
||||
uint32_t c[4] = {0, 0, 0, 0};
|
||||
auto src = img + rx - n + (ry - n) * stride;
|
||||
size_t c[4] = {0, 0, 0, 0};
|
||||
|
||||
for (auto y = ry - n; y < ry + n; ++y) {
|
||||
if (y >= h) continue;
|
||||
int32_t minx = (int32_t)sx - n;
|
||||
if (minx < 0) minx = 0;
|
||||
|
||||
int32_t maxx = (int32_t)sx + n;
|
||||
if (maxx >= (int32_t)w) maxx = w;
|
||||
|
||||
auto src = img + minx + miny * stride;
|
||||
|
||||
for (auto y = miny; y < maxy; ++y) {
|
||||
auto p = src;
|
||||
for (auto x = rx - n; x < rx + n; ++x, ++p) {
|
||||
if (x >= w) continue;
|
||||
for (auto x = minx; x < maxx; ++x, ++p) {
|
||||
c[0] += *p >> 24;
|
||||
c[1] += (*p >> 16) & 0xff;
|
||||
c[2] += (*p >> 8) & 0xff;
|
||||
|
@ -290,9 +293,14 @@ static uint32_t _interpDownScaler(const uint32_t *img, uint32_t stride, uint32_t
|
|||
}
|
||||
src += stride;
|
||||
}
|
||||
for (auto i = 0; i < 4; ++i) {
|
||||
c[i] = (c[i] >> 2) / n2;
|
||||
}
|
||||
|
||||
n = (maxy - miny) * (maxx - minx);
|
||||
|
||||
c[0] /= n;
|
||||
c[1] /= n;
|
||||
c[2] /= n;
|
||||
c[3] /= n;
|
||||
|
||||
return (c[0] << 24) | (c[1] << 16) | (c[2] << 8) | c[3];
|
||||
}
|
||||
|
||||
|
@ -660,35 +668,40 @@ static bool _rasterRle(SwSurface* surface, SwRleData* rle, uint8_t r, uint8_t g,
|
|||
/* RLE Scaled Image */
|
||||
/************************************************************************/
|
||||
|
||||
#define SCALED_IMAGE_RANGE_Y(y) \
|
||||
auto sy = (y) * itransform->e22 + itransform->e23; \
|
||||
auto my = (int32_t)round(sy); \
|
||||
if (my < 0 || (uint32_t)sy >= image->h) continue; \
|
||||
if (scaleMethod == _interpDownScaler) { \
|
||||
miny = my - (int32_t)sampleSize; \
|
||||
if (miny < 0) miny = 0; \
|
||||
maxy = my + (int32_t)sampleSize; \
|
||||
if (maxy >= (int32_t)image->h) maxy = (int32_t)image->h; \
|
||||
}
|
||||
|
||||
#define SCALED_IMAGE_RANGE_X \
|
||||
auto sx = x * itransform->e11 + itransform->e13; \
|
||||
if ((int32_t)round(sx) < 0 || (uint32_t) sx >= image->w) continue;
|
||||
|
||||
|
||||
#if 0 //Enable it when GRAYSCALE image is supported
|
||||
static bool _rasterCompositeScaledMaskedRleImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, SwMask maskOp, uint8_t opacity)
|
||||
{
|
||||
auto scaleMethod = image->scale < DOWN_SCALE_TOLERANCE ? _interpDownScaler : _interpUpScaler;
|
||||
auto sampleSize = _sampleSize(image->scale);
|
||||
auto sampleSize2 = sampleSize * sampleSize;
|
||||
auto span = image->rle->spans;
|
||||
int32_t miny = 0, maxy = 0;
|
||||
|
||||
for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
|
||||
auto sy = span->y * itransform->e22 + itransform->e23;
|
||||
if ((uint32_t)sy >= image->h) continue;
|
||||
SCALED_IMAGE_RANGE_Y(span->y)
|
||||
auto cmp = &surface->compositor->image.buf8[span->y * surface->compositor->image.stride + span->x];
|
||||
auto a = MULTIPLY(span->coverage, opacity);
|
||||
if (a == 255) {
|
||||
for (uint32_t x = static_cast<uint32_t>(span->x); x < static_cast<uint32_t>(span->x) + span->len; ++x, ++cmp) {
|
||||
auto sx = x * itransform->e11 + itransform->e13;
|
||||
if ((uint32_t)sx >= image->w) continue;
|
||||
auto src = scaleMethod(image->buf8, image->stride, image->w, image->h, sx, sy, sampleSize, sampleSize2);
|
||||
SCALED_IMAGE_RANGE_X
|
||||
auto src = scaleMethod(image->buf8, image->stride, image->w, image->h, sx, sy, miny, maxy, sampleSize);
|
||||
if (a < 255) src = MULTIPLY(src, a);
|
||||
*cmp = maskOp(src, *cmp, ~src);
|
||||
}
|
||||
} else {
|
||||
for (uint32_t x = static_cast<uint32_t>(span->x); x < static_cast<uint32_t>(span->x) + span->len; ++x, ++cmp) {
|
||||
auto sx = x * itransform->e11 + itransform->e13;
|
||||
if ((uint32_t)sx >= image->w) continue;
|
||||
auto src = scaleMethod(image->buf8, image->stride, image->w, image->h, sx, sy, sampleSize, sampleSize2);
|
||||
auto tmp = MULTIPLY(src, a);
|
||||
*cmp = maskOp(tmp, *cmp, ~tmp);
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -698,31 +711,20 @@ static bool _rasterDirectScaledMaskedRleImage(SwSurface* surface, const SwImage*
|
|||
{
|
||||
auto scaleMethod = image->scale < DOWN_SCALE_TOLERANCE ? _interpDownScaler : _interpUpScaler;
|
||||
auto sampleSize = _sampleSize(image->scale);
|
||||
auto sampleSize2 = sampleSize * sampleSize;
|
||||
auto span = image->rle->spans;
|
||||
int32_t miny = 0, maxy = 0;
|
||||
|
||||
for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
|
||||
auto sy = span->y * itransform->e22 + itransform->e23;
|
||||
if ((uint32_t)sy >= image->h) continue;
|
||||
SCALED_IMAGE_RANGE_Y(span->y)
|
||||
auto cmp = &surface->compositor->image.buf8[span->y * surface->compositor->image.stride + span->x];
|
||||
auto dst = &surface->buf8[span->y * surface->stride + span->x];
|
||||
auto a = MULTIPLY(span->coverage, opacity);
|
||||
if (a == 255) {
|
||||
for (uint32_t x = static_cast<uint32_t>(span->x); x < static_cast<uint32_t>(span->x) + span->len; ++x, ++cmp, ++dst) {
|
||||
auto sx = x * itransform->e11 + itransform->e13;
|
||||
if ((uint32_t)sx >= image->w) continue;
|
||||
auto src = scaleMethod(image->buf8, image->stride, image->w, image->h, sx, sy, sampleSize, sampleSize2);
|
||||
auto tmp = maskOp(src, *cmp, 0); //not use alpha
|
||||
*dst = tmp + MULTIPLY(*dst, ~tmp);
|
||||
}
|
||||
} else {
|
||||
for (uint32_t x = static_cast<uint32_t>(span->x); x < static_cast<uint32_t>(span->x) + span->len; ++x, ++cmp, ++dst) {
|
||||
auto sx = x * itransform->e11 + itransform->e13;
|
||||
if ((uint32_t)sx >= image->w) continue;
|
||||
auto src = scaleMethod(image->buf8, image->stride, image->w, image->h, sx, sy, sampleSize, sampleSize2);
|
||||
auto tmp = maskOp(MULTIPLY(src, a), *cmp, 0); //not use alpha
|
||||
*dst = tmp + MULTIPLY(*dst, ~tmp);
|
||||
}
|
||||
SCALED_IMAGE_RANGE_X
|
||||
auto src = scaleMethod(image->buf8, image->stride, image->w, image->h, sx, sy, miny, maxy, sampleSize);
|
||||
if (a < 255) src = MULTIPLY(src, a);
|
||||
src = maskOp(src, *cmp, 0); //not use alpha
|
||||
*dst = src + MULTIPLY(*dst, ~src);
|
||||
}
|
||||
}
|
||||
return _compositeMaskImage(surface, &surface->compositor->image, surface->compositor->bbox);
|
||||
|
@ -752,32 +754,20 @@ static bool _rasterScaledMattedRleImage(SwSurface* surface, const SwImage* image
|
|||
auto span = image->rle->spans;
|
||||
auto csize = surface->compositor->image.channelSize;
|
||||
auto alpha = surface->alpha(surface->compositor->method);
|
||||
|
||||
auto scaleMethod = image->scale < DOWN_SCALE_TOLERANCE ? _interpDownScaler : _interpUpScaler;
|
||||
auto sampleSize = _sampleSize(image->scale);
|
||||
auto sampleSize2 = sampleSize * sampleSize;
|
||||
int32_t miny = 0, maxy = 0;
|
||||
|
||||
for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
|
||||
auto sy = span->y * itransform->e22 + itransform->e23;
|
||||
if ((uint32_t)sy >= image->h) continue;
|
||||
SCALED_IMAGE_RANGE_Y(span->y)
|
||||
auto dst = &surface->buf32[span->y * surface->stride + span->x];
|
||||
auto cmp = &surface->compositor->image.buf8[(span->y * surface->compositor->image.stride + span->x) * csize];
|
||||
auto a = MULTIPLY(span->coverage, opacity);
|
||||
if (a == 255) {
|
||||
for (uint32_t x = static_cast<uint32_t>(span->x); x < static_cast<uint32_t>(span->x) + span->len; ++x, ++dst, cmp += csize) {
|
||||
auto sx = x * itransform->e11 + itransform->e13;
|
||||
if ((uint32_t)sx >= image->w) continue;
|
||||
auto tmp = ALPHA_BLEND(scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, sampleSize, sampleSize2), alpha(cmp));
|
||||
*dst = tmp + ALPHA_BLEND(*dst, IA(tmp));
|
||||
}
|
||||
} else {
|
||||
for (uint32_t x = static_cast<uint32_t>(span->x); x < static_cast<uint32_t>(span->x) + span->len; ++x, ++dst, cmp += csize) {
|
||||
auto sx = x * itransform->e11 + itransform->e13;
|
||||
if ((uint32_t)sx >= image->w) continue;
|
||||
auto src = scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, sampleSize, sampleSize2);
|
||||
auto tmp = ALPHA_BLEND(src, MULTIPLY(alpha(cmp), a));
|
||||
*dst = tmp + ALPHA_BLEND(*dst, IA(tmp));
|
||||
}
|
||||
SCALED_IMAGE_RANGE_X
|
||||
auto src = scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, miny, maxy, sampleSize);
|
||||
src = ALPHA_BLEND(src, (a == 255) ? alpha(cmp) : MULTIPLY(alpha(cmp), a));
|
||||
*dst = src + ALPHA_BLEND(*dst, IA(src));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -790,34 +780,24 @@ static bool _rasterScaledBlendingRleImage(SwSurface* surface, const SwImage* ima
|
|||
auto span = image->rle->spans;
|
||||
auto scaleMethod = image->scale < DOWN_SCALE_TOLERANCE ? _interpDownScaler : _interpUpScaler;
|
||||
auto sampleSize = _sampleSize(image->scale);
|
||||
auto sampleSize2 = sampleSize * sampleSize;
|
||||
int32_t miny = 0, maxy = 0;
|
||||
|
||||
for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
|
||||
auto sy = span->y * itransform->e22 + itransform->e23;
|
||||
if ((uint32_t)sy >= image->h) continue;
|
||||
SCALED_IMAGE_RANGE_Y(span->y)
|
||||
auto dst = &surface->buf32[span->y * surface->stride + span->x];
|
||||
auto alpha = MULTIPLY(span->coverage, opacity);
|
||||
if (alpha == 255) {
|
||||
for (uint32_t x = static_cast<uint32_t>(span->x); x < static_cast<uint32_t>(span->x) + span->len; ++x, ++dst) {
|
||||
auto sx = x * itransform->e11 + itransform->e13;
|
||||
if ((uint32_t)sx >= image->w) continue;
|
||||
auto src = scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, sampleSize, sampleSize2);
|
||||
SCALED_IMAGE_RANGE_X
|
||||
auto src = scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, miny, maxy, sampleSize);
|
||||
auto tmp = surface->blender(src, *dst, 255);
|
||||
*dst = INTERPOLATE(tmp, *dst, A(src));
|
||||
}
|
||||
} else if (opacity == 255) {
|
||||
for (uint32_t x = static_cast<uint32_t>(span->x); x < static_cast<uint32_t>(span->x) + span->len; ++x, ++dst) {
|
||||
auto sx = x * itransform->e11 + itransform->e13;
|
||||
if ((uint32_t)sx >= image->w) continue;
|
||||
auto src = scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, sampleSize, sampleSize2);
|
||||
auto tmp = surface->blender(src, *dst, 255);
|
||||
*dst = INTERPOLATE(tmp, *dst, MULTIPLY(span->coverage, A(src)));
|
||||
}
|
||||
} else {
|
||||
for (uint32_t x = static_cast<uint32_t>(span->x); x < static_cast<uint32_t>(span->x) + span->len; ++x, ++dst) {
|
||||
auto sx = x * itransform->e11 + itransform->e13;
|
||||
if ((uint32_t)sx >= image->w) continue;
|
||||
auto src = ALPHA_BLEND(scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, sampleSize, sampleSize2), opacity);
|
||||
SCALED_IMAGE_RANGE_X
|
||||
auto src = scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, miny, maxy, sampleSize);
|
||||
if (opacity < 255) src = ALPHA_BLEND(src, opacity);
|
||||
auto tmp = surface->blender(src, *dst, 255);
|
||||
*dst = INTERPOLATE(tmp, *dst, MULTIPLY(span->coverage, A(src)));
|
||||
}
|
||||
|
@ -832,28 +812,18 @@ static bool _rasterScaledRleImage(SwSurface* surface, const SwImage* image, cons
|
|||
auto span = image->rle->spans;
|
||||
auto scaleMethod = image->scale < DOWN_SCALE_TOLERANCE ? _interpDownScaler : _interpUpScaler;
|
||||
auto sampleSize = _sampleSize(image->scale);
|
||||
auto sampleSize2 = sampleSize * sampleSize;
|
||||
int32_t miny = 0, maxy = 0;
|
||||
|
||||
for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
|
||||
auto sy = span->y * itransform->e22 + itransform->e23;
|
||||
if ((uint32_t)sy >= image->h) continue;
|
||||
SCALED_IMAGE_RANGE_Y(span->y)
|
||||
auto dst = &surface->buf32[span->y * surface->stride + span->x];
|
||||
auto alpha = MULTIPLY(span->coverage, opacity);
|
||||
if (alpha == 255) {
|
||||
for (uint32_t x = static_cast<uint32_t>(span->x); x < static_cast<uint32_t>(span->x) + span->len; ++x, ++dst) {
|
||||
auto sx = x * itransform->e11 + itransform->e13;
|
||||
if ((uint32_t)sx >= image->w) continue;
|
||||
auto src = scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, sampleSize, sampleSize2);
|
||||
SCALED_IMAGE_RANGE_X
|
||||
auto src = scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, miny, maxy, sampleSize);
|
||||
if (alpha < 255) src = ALPHA_BLEND(src, alpha);
|
||||
*dst = src + ALPHA_BLEND(*dst, IA(src));
|
||||
}
|
||||
} else {
|
||||
for (uint32_t x = static_cast<uint32_t>(span->x); x < static_cast<uint32_t>(span->x) + span->len; ++x, ++dst) {
|
||||
auto sx = x * itransform->e11 + itransform->e13;
|
||||
if ((uint32_t)sx >= image->w) continue;
|
||||
auto src = ALPHA_BLEND(scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, sampleSize, sampleSize2), alpha);
|
||||
*dst = src + ALPHA_BLEND(*dst, IA(src));
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -1067,30 +1037,19 @@ static bool _rasterCompositeScaledMaskedImage(SwSurface* surface, const SwImage*
|
|||
{
|
||||
auto scaleMethod = image->scale < DOWN_SCALE_TOLERANCE ? _interpDownScaler : _interpUpScaler;
|
||||
auto sampleSize = _sampleSize(image->scale);
|
||||
auto sampleSize2 = sampleSize * sampleSize;
|
||||
auto cstride = surface->compositor->image.stride;
|
||||
auto cbuffer = surface->compositor->image.buf8 + (region.min.y * cstride + region.min.x);
|
||||
int32_t miny = 0, maxy = 0;
|
||||
|
||||
for (auto y = region.min.y; y < region.max.y; ++y) {
|
||||
auto sy = y * itransform->e22 + itransform->e23;
|
||||
if ((uint32_t)sy >= image->h) continue;
|
||||
SCALED_IMAGE_RANGE_Y(y)
|
||||
auto cmp = cbuffer;
|
||||
if (opacity == 255) {
|
||||
for (auto x = region.min.x; x < region.max.x; ++x, ++cmp) {
|
||||
auto sx = x * itransform->e11 + itransform->e13;
|
||||
if ((uint32_t)sx >= image->w) continue;
|
||||
auto src = scaleMethod(image->buf8, image->stride, image->w, image->h, sx, sy, sampleSize, sampleSize2);
|
||||
SCALED_IMAGE_RANGE_X
|
||||
auto src = scaleMethod(image->buf8, image->stride, image->w, image->h, sx, sy, miny, maxy, sampleSize);
|
||||
if (opacity < 255) src = MULTIPLY(src, opacity);
|
||||
*cmp = maskOp(src, *cmp, ~src);
|
||||
}
|
||||
} else {
|
||||
for (auto x = region.min.x; x < region.max.x; ++x, ++cmp) {
|
||||
auto sx = x * itransform->e11 + itransform->e13;
|
||||
if ((uint32_t)sx >= image->w) continue;
|
||||
auto src = scaleMethod(image->buf8, image->stride, image->w, image->h, sx, sy, sampleSize, sampleSize2);
|
||||
auto tmp = MULTIPLY(src, opacity);
|
||||
*cmp = maskOp(tmp, *cmp, ~tmp);
|
||||
}
|
||||
}
|
||||
cbuffer += cstride;
|
||||
}
|
||||
return _compositeMaskImage(surface, &surface->compositor->image, surface->compositor->bbox);
|
||||
|
@ -1101,33 +1060,21 @@ static bool _rasterDirectScaledMaskedImage(SwSurface* surface, const SwImage* im
|
|||
{
|
||||
auto scaleMethod = image->scale < DOWN_SCALE_TOLERANCE ? _interpDownScaler : _interpUpScaler;
|
||||
auto sampleSize = _sampleSize(image->scale);
|
||||
auto sampleSize2 = sampleSize * sampleSize;
|
||||
auto cstride = surface->compositor->image.stride;
|
||||
auto cbuffer = surface->compositor->image.buf8 + (region.min.y * cstride + region.min.x);
|
||||
auto dbuffer = surface->buf8 + (region.min.y * surface->stride + region.min.x);
|
||||
int32_t miny = 0, maxy = 0;
|
||||
|
||||
for (auto y = region.min.y; y < region.max.y; ++y) {
|
||||
auto sy = y * itransform->e22 + itransform->e23;
|
||||
if ((uint32_t)sy >= image->h) continue;
|
||||
SCALED_IMAGE_RANGE_Y(y)
|
||||
auto cmp = cbuffer;
|
||||
auto dst = dbuffer;
|
||||
if (opacity == 255) {
|
||||
for (auto x = region.min.x; x < region.max.x; ++x, ++cmp, ++dst) {
|
||||
auto sx = x * itransform->e11 + itransform->e13;
|
||||
if ((uint32_t)sx >= image->w) continue;
|
||||
auto src = scaleMethod(image->buf8, image->stride, image->w, image->h, sx, sy, sampleSize, sampleSize2);
|
||||
auto tmp = maskOp(src, *cmp, 0); //not use alpha
|
||||
*dst = tmp + MULTIPLY(*dst, ~tmp);
|
||||
}
|
||||
} else {
|
||||
for (auto x = region.min.x; x < region.max.x; ++x, ++cmp, ++dst) {
|
||||
auto sx = x * itransform->e11 + itransform->e13;
|
||||
if ((uint32_t)sx >= image->w) continue;
|
||||
auto src = scaleMethod(image->buf8, image->stride, image->w, image->h, sx, sy, sampleSize, sampleSize2);
|
||||
auto tmp = MULTIPLY(src, opacity);
|
||||
auto tmp2 = maskOp(tmp, *cmp, 0); //not use alpha
|
||||
*dst = tmp2 + MULTIPLY(*dst, ~tmp2);
|
||||
}
|
||||
SCALED_IMAGE_RANGE_X
|
||||
auto src = scaleMethod(image->buf8, image->stride, image->w, image->h, sx, sy, miny, maxy, sampleSize);
|
||||
if (opacity < 255) src = MULTIPLY(src, opacity);
|
||||
src = maskOp(src, *cmp, 0); //not use alpha
|
||||
*dst = src + MULTIPLY(*dst, ~src);
|
||||
}
|
||||
cbuffer += cstride;
|
||||
dbuffer += surface->stride;
|
||||
|
@ -1160,29 +1107,17 @@ static bool _rasterScaledMattedImage(SwSurface* surface, const SwImage* image, c
|
|||
|
||||
auto scaleMethod = image->scale < DOWN_SCALE_TOLERANCE ? _interpDownScaler : _interpUpScaler;
|
||||
auto sampleSize = _sampleSize(image->scale);
|
||||
auto sampleSize2 = sampleSize * sampleSize;
|
||||
int32_t miny = 0, maxy = 0;
|
||||
|
||||
for (auto y = region.min.y; y < region.max.y; ++y) {
|
||||
auto sy = y * itransform->e22 + itransform->e23;
|
||||
if ((uint32_t)sy >= image->h) continue;
|
||||
SCALED_IMAGE_RANGE_Y(y)
|
||||
auto dst = dbuffer;
|
||||
auto cmp = cbuffer;
|
||||
if (opacity == 255) {
|
||||
for (auto x = region.min.x; x < region.max.x; ++x, ++dst, cmp += csize) {
|
||||
auto sx = x * itransform->e11 + itransform->e13;
|
||||
if ((uint32_t)sx >= image->w) continue;
|
||||
auto src = scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, sampleSize, sampleSize2);
|
||||
auto temp = ALPHA_BLEND(src, alpha(cmp));
|
||||
*dst = temp + ALPHA_BLEND(*dst, IA(temp));
|
||||
}
|
||||
} else {
|
||||
for (auto x = region.min.x; x < region.max.x; ++x, ++dst, cmp += csize) {
|
||||
auto sx = x * itransform->e11 + itransform->e13;
|
||||
if ((uint32_t)sx >= image->w) continue;
|
||||
auto src = scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, sampleSize, sampleSize2);
|
||||
auto temp = ALPHA_BLEND(src, MULTIPLY(opacity, alpha(cmp)));
|
||||
*dst = temp + ALPHA_BLEND(*dst, IA(temp));
|
||||
}
|
||||
SCALED_IMAGE_RANGE_X
|
||||
auto src = scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, miny, maxy, sampleSize);
|
||||
auto tmp = ALPHA_BLEND(src, opacity == 255 ? alpha(cmp) : MULTIPLY(opacity, alpha(cmp)));
|
||||
*dst = tmp + ALPHA_BLEND(*dst, IA(tmp));
|
||||
}
|
||||
dbuffer += surface->stride;
|
||||
cbuffer += surface->compositor->image.stride * csize;
|
||||
|
@ -1196,29 +1131,18 @@ static bool _rasterScaledBlendingImage(SwSurface* surface, const SwImage* image,
|
|||
auto dbuffer = surface->buf32 + (region.min.y * surface->stride + region.min.x);
|
||||
auto scaleMethod = image->scale < DOWN_SCALE_TOLERANCE ? _interpDownScaler : _interpUpScaler;
|
||||
auto sampleSize = _sampleSize(image->scale);
|
||||
auto sampleSize2 = sampleSize * sampleSize;
|
||||
int32_t miny = 0, maxy = 0;
|
||||
|
||||
for (auto y = region.min.y; y < region.max.y; ++y, dbuffer += surface->stride) {
|
||||
auto sy = y * itransform->e22 + itransform->e23;
|
||||
if ((uint32_t)sy >= image->h) continue;
|
||||
SCALED_IMAGE_RANGE_Y(y)
|
||||
auto dst = dbuffer;
|
||||
if (opacity == 255) {
|
||||
for (auto x = region.min.x; x < region.max.x; ++x, ++dst) {
|
||||
auto sx = x * itransform->e11 + itransform->e13;
|
||||
if ((uint32_t)sx >= image->w) continue;
|
||||
auto src = scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, sampleSize, sampleSize2);
|
||||
SCALED_IMAGE_RANGE_X
|
||||
auto src = scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, miny, maxy, sampleSize);
|
||||
if (opacity < 255) ALPHA_BLEND(src, opacity);
|
||||
auto tmp = surface->blender(src, *dst, 255);
|
||||
*dst = INTERPOLATE(tmp, *dst, A(src));
|
||||
}
|
||||
} else {
|
||||
for (auto x = region.min.x; x < region.max.x; ++x, ++dst) {
|
||||
auto sx = x * itransform->e11 + itransform->e13;
|
||||
if ((uint32_t)sx >= image->w) continue;
|
||||
auto src = ALPHA_BLEND(scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, sampleSize, sampleSize2), opacity);
|
||||
auto tmp = surface->blender(src, *dst, 255);
|
||||
*dst = INTERPOLATE(tmp, *dst, A(src));
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -1229,27 +1153,17 @@ static bool _rasterScaledImage(SwSurface* surface, const SwImage* image, const M
|
|||
auto dbuffer = surface->buf32 + (region.min.y * surface->stride + region.min.x);
|
||||
auto scaleMethod = image->scale < DOWN_SCALE_TOLERANCE ? _interpDownScaler : _interpUpScaler;
|
||||
auto sampleSize = _sampleSize(image->scale);
|
||||
auto sampleSize2 = sampleSize * sampleSize;
|
||||
int32_t miny = 0, maxy = 0;
|
||||
|
||||
for (auto y = region.min.y; y < region.max.y; ++y, dbuffer += surface->stride) {
|
||||
auto sy = y * itransform->e22 + itransform->e23;
|
||||
if ((uint32_t)sy >= image->h) continue;
|
||||
SCALED_IMAGE_RANGE_Y(y)
|
||||
auto dst = dbuffer;
|
||||
if (opacity == 255) {
|
||||
for (auto x = region.min.x; x < region.max.x; ++x, ++dst) {
|
||||
auto sx = x * itransform->e11 + itransform->e13;
|
||||
if ((uint32_t)sx >= image->w) continue;
|
||||
auto src = scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, sampleSize, sampleSize2);
|
||||
SCALED_IMAGE_RANGE_X
|
||||
auto src = scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, miny, maxy, sampleSize);
|
||||
if (opacity < 255) src = ALPHA_BLEND(src, opacity);
|
||||
*dst = src + ALPHA_BLEND(*dst, IA(src));
|
||||
}
|
||||
} else {
|
||||
for (auto x = region.min.x; x < region.max.x; ++x, ++dst) {
|
||||
auto sx = x * itransform->e11 + itransform->e13;
|
||||
if ((uint32_t)sx >= image->w) continue;
|
||||
auto src = ALPHA_BLEND(scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, sampleSize, sampleSize2), opacity);
|
||||
*dst = src + ALPHA_BLEND(*dst, IA(src));
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -139,7 +139,9 @@ struct SwShapeTask : SwTask
|
|||
visibleFill = (alpha > 0 || rshape->fill);
|
||||
if (visibleFill || clipper) {
|
||||
shapeReset(&shape);
|
||||
if (!shapePrepare(&shape, rshape, transform, clipRegion, bbox, mpool, tid, clips.count > 0 ? true : false)) goto err;
|
||||
if (!shapePrepare(&shape, rshape, transform, clipRegion, bbox, mpool, tid, clips.count > 0 ? true : false)) {
|
||||
visibleFill = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
//Fill
|
||||
|
|
|
@ -558,11 +558,15 @@ void shapeReset(SwShape* shape)
|
|||
void shapeFree(SwShape* shape)
|
||||
{
|
||||
rleFree(shape->rle);
|
||||
shape->rle = nullptr;
|
||||
|
||||
shapeDelFill(shape);
|
||||
|
||||
if (shape->stroke) {
|
||||
rleFree(shape->strokeRle);
|
||||
shape->strokeRle = nullptr;
|
||||
strokeFree(shape->stroke);
|
||||
shape->stroke = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -62,7 +62,7 @@ Animation::Animation() : pImpl(new Impl)
|
|||
}
|
||||
|
||||
|
||||
Result Animation::frame(uint32_t no) noexcept
|
||||
Result Animation::frame(float no) noexcept
|
||||
{
|
||||
auto loader = pImpl->picture->pImpl->loader.get();
|
||||
|
||||
|
@ -80,7 +80,7 @@ Picture* Animation::picture() const noexcept
|
|||
}
|
||||
|
||||
|
||||
uint32_t Animation::curFrame() const noexcept
|
||||
float Animation::curFrame() const noexcept
|
||||
{
|
||||
auto loader = pImpl->picture->pImpl->loader.get();
|
||||
|
||||
|
@ -91,7 +91,7 @@ uint32_t Animation::curFrame() const noexcept
|
|||
}
|
||||
|
||||
|
||||
uint32_t Animation::totalFrame() const noexcept
|
||||
float Animation::totalFrame() const noexcept
|
||||
{
|
||||
auto loader = pImpl->picture->pImpl->loader.get();
|
||||
|
||||
|
|
|
@ -63,9 +63,9 @@ Result Canvas::clear(bool free) noexcept
|
|||
|
||||
Result Canvas::draw() noexcept
|
||||
{
|
||||
TVGLOG("COMMON", "Draw S. -------------------------------- Canvas(%p)", this);
|
||||
TVGLOG("RENDERER", "Draw S. -------------------------------- Canvas(%p)", this);
|
||||
auto ret = pImpl->draw();
|
||||
TVGLOG("COMMON", "Draw E. -------------------------------- Canvas(%p)", this);
|
||||
TVGLOG("RENDERER", "Draw E. -------------------------------- Canvas(%p)", this);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -73,9 +73,9 @@ Result Canvas::draw() noexcept
|
|||
|
||||
Result Canvas::update(Paint* paint) noexcept
|
||||
{
|
||||
TVGLOG("COMMON", "Update S. ------------------------------ Canvas(%p)", this);
|
||||
TVGLOG("RENDERER", "Update S. ------------------------------ Canvas(%p)", this);
|
||||
auto ret = pImpl->update(paint, false);
|
||||
TVGLOG("COMMON", "Update E. ------------------------------ Canvas(%p)", this);
|
||||
TVGLOG("RENDERER", "Update E. ------------------------------ Canvas(%p)", this);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -62,7 +62,7 @@ using namespace tvg;
|
|||
#define TVG_CLASS_ID_LINEAR 4
|
||||
#define TVG_CLASS_ID_RADIAL 5
|
||||
|
||||
enum class FileType { Tvg = 0, Svg, Lottie, Raw, Png, Jpg, Webp, Unknown };
|
||||
enum class FileType { Tvg = 0, Svg, Lottie, Raw, Png, Jpg, Webp, Gif, Unknown };
|
||||
|
||||
using Size = Point;
|
||||
|
||||
|
|
|
@ -33,10 +33,9 @@ class FrameModule: public LoadModule
|
|||
public:
|
||||
virtual ~FrameModule() {}
|
||||
|
||||
virtual bool frame(uint32_t frameNo) = 0; //set the current frame number
|
||||
|
||||
virtual uint32_t totalFrame() = 0; //return the total frame count
|
||||
virtual uint32_t curFrame() = 0; //return the current frame number
|
||||
virtual bool frame(float no) = 0; //set the current frame number
|
||||
virtual float totalFrame() = 0; //return the total frame count
|
||||
virtual float curFrame() = 0; //return the current frame number
|
||||
virtual float duration() = 0; //return the animation duration in seconds
|
||||
|
||||
virtual bool animatable() override { return true; }
|
||||
|
|
|
@ -136,7 +136,7 @@ static LoadModule* _find(FileType type)
|
|||
break;
|
||||
}
|
||||
}
|
||||
TVGLOG("LOADER", "%s format is not supported", format);
|
||||
TVGLOG("RENDERER", "%s format is not supported", format);
|
||||
#endif
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -170,7 +170,7 @@ static LoadModule* _findByType(const string& mimeType)
|
|||
else if (mimeType == "jpg" || mimeType == "jpeg") type = FileType::Jpg;
|
||||
else if (mimeType == "webp") type = FileType::Webp;
|
||||
else {
|
||||
TVGLOG("LOADER", "Given mimetype is unknown = \"%s\".", mimeType.c_str());
|
||||
TVGLOG("RENDERER", "Given mimetype is unknown = \"%s\".", mimeType.c_str());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
|
|
@ -22,11 +22,22 @@
|
|||
|
||||
#include "tvgMath.h"
|
||||
#include "tvgPaint.h"
|
||||
#include "tvgShape.h"
|
||||
#include "tvgPicture.h"
|
||||
#include "tvgScene.h"
|
||||
|
||||
/************************************************************************/
|
||||
/* Internal Class Implementation */
|
||||
/************************************************************************/
|
||||
|
||||
#define PAINT_METHOD(ret, METHOD) \
|
||||
switch (id) { \
|
||||
case TVG_CLASS_ID_SHAPE: ret = P((Shape*)paint)->METHOD; break; \
|
||||
case TVG_CLASS_ID_SCENE: ret = P((Scene*)paint)->METHOD; break; \
|
||||
case TVG_CLASS_ID_PICTURE: ret = P((Picture*)paint)->METHOD; break; \
|
||||
default: ret = {}; \
|
||||
}
|
||||
|
||||
|
||||
static bool _compFastTrack(Paint* cmpTarget, const RenderTransform* pTransform, RenderTransform* rTransform, RenderRegion& viewport)
|
||||
{
|
||||
|
@ -93,9 +104,36 @@ static bool _compFastTrack(Paint* cmpTarget, const RenderTransform* pTransform,
|
|||
}
|
||||
|
||||
|
||||
RenderRegion Paint::Impl::bounds(RenderMethod& renderer) const
|
||||
{
|
||||
RenderRegion ret;
|
||||
PAINT_METHOD(ret, bounds(renderer));
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
bool Paint::Impl::dispose(RenderMethod& renderer)
|
||||
{
|
||||
if (compData) compData->target->pImpl->dispose(renderer);
|
||||
|
||||
bool ret;
|
||||
PAINT_METHOD(ret, dispose(renderer));
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
Iterator* Paint::Impl::iterator()
|
||||
{
|
||||
Iterator* ret;
|
||||
PAINT_METHOD(ret, iterator());
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
Paint* Paint::Impl::duplicate()
|
||||
{
|
||||
auto ret = smethod->duplicate();
|
||||
Paint* ret;
|
||||
PAINT_METHOD(ret, duplicate());
|
||||
|
||||
//duplicate Transform
|
||||
if (rTransform) {
|
||||
|
@ -165,8 +203,10 @@ bool Paint::Impl::render(RenderMethod& renderer)
|
|||
/* Note: only ClipPath is processed in update() step.
|
||||
Create a composition image. */
|
||||
if (compData && compData->method != CompositeMethod::ClipPath && !(compData->target->pImpl->ctxFlag & ContextFlag::FastTrack)) {
|
||||
auto region = smethod->bounds(renderer);
|
||||
if (MASK_REGION_MERGING(compData->method)) region.add(compData->target->pImpl->smethod->bounds(renderer));
|
||||
RenderRegion region;
|
||||
PAINT_METHOD(region, bounds(renderer));
|
||||
|
||||
if (MASK_REGION_MERGING(compData->method)) region.add(P(compData->target)->bounds(renderer));
|
||||
if (region.w == 0 || region.h == 0) return true;
|
||||
cmp = renderer.target(region, COMPOSITE_TO_COLORSPACE(renderer, compData->method));
|
||||
if (renderer.beginComposite(cmp, CompositeMethod::None, 255)) {
|
||||
|
@ -177,7 +217,9 @@ bool Paint::Impl::render(RenderMethod& renderer)
|
|||
if (cmp) renderer.beginComposite(cmp, compData->method, compData->target->pImpl->opacity);
|
||||
|
||||
renderer.blend(blendMethod);
|
||||
auto ret = smethod->render(renderer);
|
||||
|
||||
bool ret;
|
||||
PAINT_METHOD(ret, render(renderer));
|
||||
|
||||
if (cmp) renderer.endComposite(cmp);
|
||||
|
||||
|
@ -189,10 +231,7 @@ RenderData Paint::Impl::update(RenderMethod& renderer, const RenderTransform* pT
|
|||
{
|
||||
if (renderFlag & RenderUpdateFlag::Transform) {
|
||||
if (!rTransform) return nullptr;
|
||||
if (!rTransform->update()) {
|
||||
delete(rTransform);
|
||||
rTransform = nullptr;
|
||||
}
|
||||
rTransform->update();
|
||||
}
|
||||
|
||||
/* 1. Composition Pre Processing */
|
||||
|
@ -239,18 +278,13 @@ RenderData Paint::Impl::update(RenderMethod& renderer, const RenderTransform* pT
|
|||
}
|
||||
|
||||
/* 2. Main Update */
|
||||
RenderData rd = nullptr;
|
||||
auto newFlag = static_cast<RenderUpdateFlag>(pFlag | renderFlag);
|
||||
renderFlag = RenderUpdateFlag::None;
|
||||
opacity = MULTIPLY(opacity, this->opacity);
|
||||
|
||||
if (rTransform && pTransform) {
|
||||
RenderData rd = nullptr;
|
||||
RenderTransform outTransform(pTransform, rTransform);
|
||||
rd = smethod->update(renderer, &outTransform, clips, opacity, newFlag, clipper);
|
||||
} else {
|
||||
auto outTransform = pTransform ? pTransform : rTransform;
|
||||
rd = smethod->update(renderer, outTransform, clips, opacity, newFlag, clipper);
|
||||
}
|
||||
PAINT_METHOD(rd, update(renderer, &outTransform, clips, opacity, newFlag, clipper));
|
||||
|
||||
/* 3. Composition Post Processing */
|
||||
if (compFastTrack) renderer.viewport(viewport);
|
||||
|
@ -263,9 +297,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)
|
||||
{
|
||||
Matrix* m = nullptr;
|
||||
bool ret;
|
||||
|
||||
//Case: No transformed, quick return!
|
||||
if (!transformed || !(m = this->transform())) return smethod->bounds(x, y, w, h, stroking);
|
||||
if (!transformed || !(m = this->transform())) {
|
||||
PAINT_METHOD(ret, bounds(x, y, w, h, stroking));
|
||||
return ret;
|
||||
}
|
||||
|
||||
//Case: Transformed
|
||||
auto tx = 0.0f;
|
||||
|
@ -273,7 +311,7 @@ bool Paint::Impl::bounds(float* x, float* y, float* w, float* h, bool transforme
|
|||
auto tw = 0.0f;
|
||||
auto th = 0.0f;
|
||||
|
||||
auto ret = smethod->bounds(&tx, &ty, &tw, &th, stroking);
|
||||
PAINT_METHOD(ret, bounds(&tx, &ty, &tw, &th, stroking));
|
||||
|
||||
//Get vertices
|
||||
Point pt[4] = {{tx, ty}, {tx + tw, ty}, {tx + tw, ty + th}, {tx, ty + th}};
|
||||
|
@ -307,7 +345,7 @@ bool Paint::Impl::bounds(float* x, float* y, float* w, float* h, bool transforme
|
|||
/* External Class Implementation */
|
||||
/************************************************************************/
|
||||
|
||||
Paint :: Paint() : pImpl(new Impl())
|
||||
Paint :: Paint() : pImpl(new Impl(this))
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -419,7 +457,10 @@ uint32_t Paint::identifier() const noexcept
|
|||
|
||||
Result Paint::blend(BlendMethod method) const noexcept
|
||||
{
|
||||
if (pImpl->blendMethod != method) {
|
||||
pImpl->blendMethod = method;
|
||||
pImpl->renderFlag |= RenderUpdateFlag::Blend;
|
||||
}
|
||||
|
||||
return Result::Success;
|
||||
}
|
||||
|
|
|
@ -38,19 +38,6 @@ namespace tvg
|
|||
virtual void begin() = 0;
|
||||
};
|
||||
|
||||
struct StrategyMethod
|
||||
{
|
||||
virtual ~StrategyMethod() {}
|
||||
|
||||
virtual bool dispose(RenderMethod& renderer) = 0; //return true if the deletion is allowed.
|
||||
virtual void* update(RenderMethod& renderer, const RenderTransform* transform, Array<RenderData>& clips, uint8_t opacity, RenderUpdateFlag pFlag, bool clipper) = 0; //Return engine data if it has.
|
||||
virtual bool render(RenderMethod& renderer) = 0;
|
||||
virtual bool bounds(float* x, float* y, float* w, float* h, bool stroking) = 0;
|
||||
virtual RenderRegion bounds(RenderMethod& renderer) const = 0;
|
||||
virtual Paint* duplicate() = 0;
|
||||
virtual Iterator* iterator() = 0;
|
||||
};
|
||||
|
||||
struct Composite
|
||||
{
|
||||
Paint* target;
|
||||
|
@ -60,7 +47,7 @@ namespace tvg
|
|||
|
||||
struct Paint::Impl
|
||||
{
|
||||
StrategyMethod* smethod = nullptr;
|
||||
Paint* paint = nullptr;
|
||||
RenderTransform* rTransform = nullptr;
|
||||
Composite* compData = nullptr;
|
||||
BlendMethod blendMethod = BlendMethod::Normal; //uint8_t
|
||||
|
@ -70,13 +57,16 @@ namespace tvg
|
|||
uint8_t opacity = 255;
|
||||
uint8_t refCnt = 0;
|
||||
|
||||
Impl(Paint* pnt) : paint(pnt)
|
||||
{
|
||||
}
|
||||
|
||||
~Impl()
|
||||
{
|
||||
if (compData) {
|
||||
delete(compData->target);
|
||||
if (P(compData->target)->unref() == 0) delete(compData->target);
|
||||
free(compData);
|
||||
}
|
||||
delete(smethod);
|
||||
delete(rTransform);
|
||||
}
|
||||
|
||||
|
@ -92,11 +82,6 @@ namespace tvg
|
|||
return (--refCnt);
|
||||
}
|
||||
|
||||
void method(StrategyMethod* method)
|
||||
{
|
||||
smethod = method;
|
||||
}
|
||||
|
||||
bool transform(const Matrix& m)
|
||||
{
|
||||
if (!rTransform) {
|
||||
|
@ -119,29 +104,16 @@ namespace tvg
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
RenderRegion bounds(RenderMethod& renderer) const
|
||||
{
|
||||
return smethod->bounds(renderer);
|
||||
}
|
||||
|
||||
bool dispose(RenderMethod& renderer)
|
||||
{
|
||||
if (compData) compData->target->pImpl->dispose(renderer);
|
||||
return smethod->dispose(renderer);
|
||||
}
|
||||
|
||||
Iterator* iterator()
|
||||
{
|
||||
return smethod->iterator();
|
||||
}
|
||||
|
||||
bool composite(Paint* source, Paint* target, CompositeMethod method)
|
||||
{
|
||||
//Invalid case
|
||||
if ((!target && method != CompositeMethod::None) || (target && method == CompositeMethod::None)) return false;
|
||||
|
||||
if (compData) {
|
||||
P(compData->target)->unref();
|
||||
if ((compData->target != target) && P(compData->target)->refCnt == 0) {
|
||||
delete(compData->target);
|
||||
}
|
||||
//Reset scenario
|
||||
if (!target && method == CompositeMethod::None) {
|
||||
free(compData);
|
||||
|
@ -152,12 +124,16 @@ namespace tvg
|
|||
if (!target && method == CompositeMethod::None) return true;
|
||||
compData = static_cast<Composite*>(calloc(1, sizeof(Composite)));
|
||||
}
|
||||
P(target)->ref();
|
||||
compData->target = target;
|
||||
compData->source = source;
|
||||
compData->method = method;
|
||||
return true;
|
||||
}
|
||||
|
||||
RenderRegion bounds(RenderMethod& renderer) const;
|
||||
bool dispose(RenderMethod& renderer);
|
||||
Iterator* iterator();
|
||||
bool rotate(float degree);
|
||||
bool scale(float factor);
|
||||
bool translate(float x, float y);
|
||||
|
@ -166,51 +142,6 @@ namespace tvg
|
|||
bool render(RenderMethod& renderer);
|
||||
Paint* duplicate();
|
||||
};
|
||||
|
||||
|
||||
template<class T>
|
||||
struct PaintMethod : StrategyMethod
|
||||
{
|
||||
T* inst = nullptr;
|
||||
|
||||
PaintMethod(T* _inst) : inst(_inst) {}
|
||||
~PaintMethod() {}
|
||||
|
||||
bool bounds(float* x, float* y, float* w, float* h, bool stroking) override
|
||||
{
|
||||
return inst->bounds(x, y, w, h, stroking);
|
||||
}
|
||||
|
||||
RenderRegion bounds(RenderMethod& renderer) const override
|
||||
{
|
||||
return inst->bounds(renderer);
|
||||
}
|
||||
|
||||
bool dispose(RenderMethod& renderer) override
|
||||
{
|
||||
return inst->dispose(renderer);
|
||||
}
|
||||
|
||||
RenderData update(RenderMethod& renderer, const RenderTransform* transform, Array<RenderData>& clips, uint8_t opacity, RenderUpdateFlag renderFlag, bool clipper) override
|
||||
{
|
||||
return inst->update(renderer, transform, clips, opacity, renderFlag, clipper);
|
||||
}
|
||||
|
||||
bool render(RenderMethod& renderer) override
|
||||
{
|
||||
return inst->render(renderer);
|
||||
}
|
||||
|
||||
Paint* duplicate() override
|
||||
{
|
||||
return inst->duplicate();
|
||||
}
|
||||
|
||||
Iterator* iterator() override
|
||||
{
|
||||
return inst->iterator();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif //_TVG_PAINT_H_
|
||||
|
|
|
@ -62,7 +62,6 @@ RenderUpdateFlag Picture::Impl::load()
|
|||
Picture::Picture() : pImpl(new Impl(this))
|
||||
{
|
||||
Paint::pImpl->id = TVG_CLASS_ID_PICTURE;
|
||||
Paint::pImpl->method(new PaintMethod<Picture::Impl>(pImpl));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -39,12 +39,9 @@ void RenderTransform::override(const Matrix& m)
|
|||
}
|
||||
|
||||
|
||||
bool RenderTransform::update()
|
||||
void RenderTransform::update()
|
||||
{
|
||||
if (overriding) return true;
|
||||
|
||||
//Init Status
|
||||
if (mathZero(x) && mathZero(y) && mathZero(degree) && mathEqual(scale, 1)) return false;
|
||||
if (overriding) return;
|
||||
|
||||
mathIdentity(&m);
|
||||
|
||||
|
@ -53,17 +50,13 @@ bool RenderTransform::update()
|
|||
if (!mathZero(degree)) mathRotate(&m, degree);
|
||||
|
||||
mathTranslate(&m, x, y);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
RenderTransform::RenderTransform()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
RenderTransform::RenderTransform(const RenderTransform* lhs, const RenderTransform* rhs)
|
||||
{
|
||||
m = mathMultiply(&lhs->m, &rhs->m);
|
||||
if (lhs && rhs) m = mathMultiply(&lhs->m, &rhs->m);
|
||||
else if (lhs) m = lhs->m;
|
||||
else if (rhs) m = rhs->m;
|
||||
else mathIdentity(&m);
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ namespace tvg
|
|||
using RenderData = void*;
|
||||
using pixel_t = uint32_t;
|
||||
|
||||
enum RenderUpdateFlag : uint8_t {None = 0, Path = 1, Color = 2, Gradient = 4, Stroke = 8, Transform = 16, Image = 32, GradientStroke = 64, All = 255};
|
||||
enum RenderUpdateFlag : uint8_t {None = 0, Path = 1, Color = 2, Gradient = 4, Stroke = 8, Transform = 16, Image = 32, GradientStroke = 64, Blend = 128, All = 255};
|
||||
|
||||
struct Surface;
|
||||
|
||||
|
@ -123,10 +123,10 @@ struct RenderTransform
|
|||
float scale = 1.0f; //scale factor
|
||||
bool overriding = false; //user transform?
|
||||
|
||||
bool update();
|
||||
void update();
|
||||
void override(const Matrix& m);
|
||||
|
||||
RenderTransform();
|
||||
RenderTransform() {}
|
||||
RenderTransform(const RenderTransform* lhs, const RenderTransform* rhs);
|
||||
};
|
||||
|
||||
|
|
|
@ -34,6 +34,7 @@ public:
|
|||
virtual ~SaveModule() {}
|
||||
|
||||
virtual bool save(Paint* paint, const string& path, bool compress) = 0;
|
||||
virtual bool save(Animation* animation, const string& path, uint32_t quality, uint32_t fps) = 0;
|
||||
virtual bool close() = 0;
|
||||
};
|
||||
|
||||
|
|
|
@ -26,6 +26,9 @@
|
|||
#ifdef THORVG_TVG_SAVER_SUPPORT
|
||||
#include "tvgTvgSaver.h"
|
||||
#endif
|
||||
#ifdef THORVG_GIF_SAVER_SUPPORT
|
||||
#include "tvgGifSaver.h"
|
||||
#endif
|
||||
|
||||
/************************************************************************/
|
||||
/* Internal Class Implementation */
|
||||
|
@ -47,6 +50,12 @@ static SaveModule* _find(FileType type)
|
|||
case FileType::Tvg: {
|
||||
#ifdef THORVG_TVG_SAVER_SUPPORT
|
||||
return new TvgSaver;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case FileType::Gif: {
|
||||
#ifdef THORVG_GIF_SAVER_SUPPORT
|
||||
return new GifSaver;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
@ -62,12 +71,16 @@ static SaveModule* _find(FileType type)
|
|||
format = "TVG";
|
||||
break;
|
||||
}
|
||||
case FileType::Gif: {
|
||||
format = "GIF";
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
format = "???";
|
||||
break;
|
||||
}
|
||||
}
|
||||
TVGLOG("SAVER", "%s format is not supported", format);
|
||||
TVGLOG("RENDERER", "%s format is not supported", format);
|
||||
#endif
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -78,6 +91,8 @@ static SaveModule* _find(const string& path)
|
|||
auto ext = path.substr(path.find_last_of(".") + 1);
|
||||
if (!ext.compare("tvg")) {
|
||||
return _find(FileType::Tvg);
|
||||
} else if (!ext.compare("gif")) {
|
||||
return _find(FileType::Gif);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -124,6 +139,37 @@ Result Saver::save(std::unique_ptr<Paint> paint, const string& path, bool compre
|
|||
}
|
||||
|
||||
|
||||
Result Saver::save(std::unique_ptr<Animation> animation, const string& path, uint32_t quality, uint32_t fps) noexcept
|
||||
{
|
||||
auto a = animation.release();
|
||||
if (!a) return Result::MemoryCorruption;
|
||||
|
||||
if (mathZero(a->totalFrame())) {
|
||||
delete(a);
|
||||
return Result::InsufficientCondition;
|
||||
}
|
||||
|
||||
//Already on saving an other resource.
|
||||
if (pImpl->saveModule) {
|
||||
delete(a);
|
||||
return Result::InsufficientCondition;
|
||||
}
|
||||
|
||||
if (auto saveModule = _find(path)) {
|
||||
if (saveModule->save(a, path, quality, fps)) {
|
||||
pImpl->saveModule = saveModule;
|
||||
return Result::Success;
|
||||
} else {
|
||||
delete(a);
|
||||
delete(saveModule);
|
||||
return Result::Unknown;
|
||||
}
|
||||
}
|
||||
delete(a);
|
||||
return Result::NonSupport;
|
||||
}
|
||||
|
||||
|
||||
Result Saver::sync() noexcept
|
||||
{
|
||||
if (!pImpl->saveModule) return Result::InsufficientCondition;
|
||||
|
|
|
@ -29,7 +29,6 @@
|
|||
Scene::Scene() : pImpl(new Impl(this))
|
||||
{
|
||||
Paint::pImpl->id = TVG_CLASS_ID_SCENE;
|
||||
Paint::pImpl->method(new PaintMethod<Scene::Impl>(pImpl));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -66,7 +66,7 @@ struct Scene::Impl
|
|||
RenderData rd = nullptr;
|
||||
Scene* scene = nullptr;
|
||||
uint8_t opacity; //for composition
|
||||
bool needComp; //composite or not
|
||||
bool needComp = false; //composite or not
|
||||
|
||||
Impl(Scene* s) : scene(s)
|
||||
{
|
||||
|
@ -75,7 +75,7 @@ struct Scene::Impl
|
|||
~Impl()
|
||||
{
|
||||
for (auto paint : paints) {
|
||||
if (paint->pImpl->unref() == 0) delete(paint);
|
||||
if (P(paint)->unref() == 0) delete(paint);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -148,6 +148,7 @@ struct Scene::Impl
|
|||
if (needComp) {
|
||||
cmp = renderer.target(bounds(renderer), renderer.colorSpace());
|
||||
renderer.beginComposite(cmp, CompositeMethod::None, opacity);
|
||||
needComp = false;
|
||||
}
|
||||
|
||||
for (auto paint : paints) {
|
||||
|
|
|
@ -35,7 +35,6 @@ constexpr auto PATH_KAPPA = 0.552284f;
|
|||
Shape :: Shape() : pImpl(new Impl(this))
|
||||
{
|
||||
Paint::pImpl->id = TVG_CLASS_ID_SHAPE;
|
||||
Paint::pImpl->method(new PaintMethod<Shape::Impl>(pImpl));
|
||||
}
|
||||
|
||||
|
||||
|
@ -62,7 +61,7 @@ Result Shape::reset() noexcept
|
|||
pImpl->rs.path.cmds.clear();
|
||||
pImpl->rs.path.pts.clear();
|
||||
|
||||
pImpl->flag = RenderUpdateFlag::Path;
|
||||
pImpl->flag |= RenderUpdateFlag::Path;
|
||||
|
||||
return Result::Success;
|
||||
}
|
||||
|
@ -70,18 +69,14 @@ Result Shape::reset() noexcept
|
|||
|
||||
uint32_t Shape::pathCommands(const PathCommand** cmds) const noexcept
|
||||
{
|
||||
if (!cmds) return 0;
|
||||
|
||||
*cmds = pImpl->rs.path.cmds.data;
|
||||
if (cmds) *cmds = pImpl->rs.path.cmds.data;
|
||||
return pImpl->rs.path.cmds.count;
|
||||
}
|
||||
|
||||
|
||||
uint32_t Shape::pathCoords(const Point** pts) const noexcept
|
||||
{
|
||||
if (!pts) return 0;
|
||||
|
||||
*pts = pImpl->rs.path.pts.data;
|
||||
if (pts) *pts = pImpl->rs.path.pts.data;
|
||||
return pImpl->rs.path.pts.count;
|
||||
}
|
||||
|
||||
|
@ -224,8 +219,8 @@ Result Shape::appendRect(float x, float y, float w, float h, float rx, float ry)
|
|||
} else if (mathEqual(rx, halfW) && mathEqual(ry, halfH)) {
|
||||
return appendCircle(x + (w * 0.5f), y + (h * 0.5f), rx, ry);
|
||||
} else {
|
||||
auto hrx = rx * 0.5f;
|
||||
auto hry = ry * 0.5f;
|
||||
auto hrx = rx * PATH_KAPPA;
|
||||
auto hry = ry * PATH_KAPPA;
|
||||
pImpl->grow(10, 17);
|
||||
pImpl->moveTo(x + rx, y);
|
||||
pImpl->lineTo(x + w - rx, y);
|
||||
|
|
|
@ -38,7 +38,7 @@ struct Shape::Impl
|
|||
Shape* shape;
|
||||
uint8_t flag = RenderUpdateFlag::None;
|
||||
uint8_t opacity; //for composition
|
||||
bool needComp; //composite or not
|
||||
bool needComp = false; //composite or not
|
||||
|
||||
Impl(Shape* s) : shape(s)
|
||||
{
|
||||
|
@ -59,6 +59,7 @@ struct Shape::Impl
|
|||
if (needComp) {
|
||||
cmp = renderer.target(bounds(renderer), renderer.colorSpace());
|
||||
renderer.beginComposite(cmp, CompositeMethod::None, opacity);
|
||||
needComp = false;
|
||||
}
|
||||
ret = renderer.renderShape(rd);
|
||||
if (cmp) renderer.endComposite(cmp);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#!/bin/bash -e
|
||||
|
||||
VERSION=0.11.2
|
||||
VERSION=0.11.6
|
||||
|
||||
cd thirdparty/thorvg/ || true
|
||||
rm -rf AUTHORS LICENSE inc/ src/ *.zip *.tar.gz tmp/
|
||||
|
@ -56,9 +56,8 @@ rm -rfv ../src/renderer/gl_engine
|
|||
# Enabled embedded loaders: raw, JPEG, PNG.
|
||||
mkdir ../src/loaders
|
||||
cp -rv src/loaders/svg src/loaders/raw ../src/loaders/
|
||||
cp -rv src/loaders/svg src/loaders/jpg ../src/loaders/
|
||||
cp -rv src/loaders/svg src/loaders/png ../src/loaders/
|
||||
cp -rv src/loaders/svg src/loaders/external_png ../src/loaders/
|
||||
cp -rv src/loaders/jpg ../src/loaders/
|
||||
cp -rv src/loaders/png src/loaders/external_png ../src/loaders/
|
||||
|
||||
popd
|
||||
rm -rf tmp
|
||||
|
|
Loading…
Reference in New Issue