From f3afd2a636f48dacbd369d5d4976cced1ec25d7f Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Thu, 11 Jun 2020 14:27:20 +0900 Subject: [PATCH 01/16] common fill: added spread mode. Change-Id: I95d47bc492d5a22326a745a591d243e56a26bae4 --- inc/tizenvg.h | 6 +++++- src/lib/sw_engine/tvgSwRenderer.cpp | 1 + src/lib/tvgFill.cpp | 21 +++++++++++++++++++++ 3 files changed, 27 insertions(+), 1 deletion(-) diff --git a/inc/tizenvg.h b/inc/tizenvg.h index b089387..85d8e27 100644 --- a/inc/tizenvg.h +++ b/inc/tizenvg.h @@ -72,6 +72,7 @@ enum class TVG_EXPORT Result { Success = 0, InvalidArguments, InsufficientCondit enum class TVG_EXPORT PathCommand { Close = 0, MoveTo, LineTo, CubicTo }; enum class TVG_EXPORT StrokeCap { Square = 0, Round, Butt }; enum class TVG_EXPORT StrokeJoin { Bevel = 0, Round, Miter }; +enum class TVG_EXPORT FillSpread { Pad = 0, Reflect, Repeat }; struct Point @@ -117,14 +118,17 @@ class TVG_EXPORT Fill public: struct ColorStop { - float pos; + float offset; uint8_t r, g, b, a; }; virtual ~Fill(); Result colorStops(const ColorStop* colorStops, uint32_t cnt) noexcept; + Result spread(FillSpread s) noexcept; + uint32_t colorStops(const ColorStop** colorStops) const noexcept; + FillSpread spread() const noexcept; _TVG_DECALRE_IDENTIFIER(); _TVG_DECLARE_PRIVATE(Fill); diff --git a/src/lib/sw_engine/tvgSwRenderer.cpp b/src/lib/sw_engine/tvgSwRenderer.cpp index 59c4910..43c2628 100644 --- a/src/lib/sw_engine/tvgSwRenderer.cpp +++ b/src/lib/sw_engine/tvgSwRenderer.cpp @@ -82,6 +82,7 @@ bool SwRenderer::dispose(const Shape& shape, void *data) return true; } + void* SwRenderer::prepare(const Shape& sdata, void* data, const RenderTransform* transform, RenderUpdateFlag flags) { //prepare shape data diff --git a/src/lib/tvgFill.cpp b/src/lib/tvgFill.cpp index 13001c8..bfef7a6 100644 --- a/src/lib/tvgFill.cpp +++ b/src/lib/tvgFill.cpp @@ -28,6 +28,7 @@ struct Fill::Impl { ColorStop* colorStops = nullptr; uint32_t cnt = 0; + FillSpread spread; ~Impl() { @@ -85,4 +86,24 @@ uint32_t Fill::colorStops(const ColorStop** colorStops) const noexcept return impl->cnt; } + +Result Fill::spread(FillSpread s) noexcept +{ + auto impl = pImpl.get(); + if (!impl) return Result::MemoryCorruption; + + impl->spread = s; + + return Result::Success; +} + + +FillSpread Fill::spread() const noexcept +{ + auto impl = pImpl.get(); + assert(impl); + + return impl->spread; +} + #endif /* _TVG_FILL_CPP_ */ \ No newline at end of file -- 2.7.4 From 5c988d01a5f4c2568673eb33087730c5a15946c0 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Thu, 11 Jun 2020 15:06:17 +0900 Subject: [PATCH 02/16] sw_engine: implement linear gradient feature also added testLinearGradient Change-Id: I9cce74b9fc40c4ebd978939ee50955e44e7f44f2 --- inc/tizenvg.h | 12 +- src/lib/sw_engine/meson.build | 1 + src/lib/sw_engine/tvgSwCommon.h | 72 ++++++++-- src/lib/sw_engine/tvgSwFill.cpp | 262 ++++++++++++++++++++++++++++++++++++ src/lib/sw_engine/tvgSwMath.cpp | 24 ++-- src/lib/sw_engine/tvgSwRaster.cpp | 138 +++++++++++-------- src/lib/sw_engine/tvgSwRenderer.cpp | 41 ++++-- src/lib/sw_engine/tvgSwShape.cpp | 54 ++++++-- src/lib/sw_engine/tvgSwStroke.cpp | 22 +-- src/lib/tvgCanvasImpl.h | 8 +- src/lib/tvgLinearGradient.cpp | 2 +- src/lib/tvgRadialGradient.cpp | 2 +- src/lib/tvgScene.cpp | 2 +- src/lib/tvgSceneImpl.h | 8 +- src/lib/tvgShape.cpp | 2 +- test/testLinearGradient.cpp | 42 +++--- 16 files changed, 543 insertions(+), 149 deletions(-) create mode 100644 src/lib/sw_engine/tvgSwFill.cpp diff --git a/inc/tizenvg.h b/inc/tizenvg.h index 85d8e27..044cdfe 100644 --- a/inc/tizenvg.h +++ b/inc/tizenvg.h @@ -51,14 +51,10 @@ protected: \ #define _TVG_DECLARE_ACCESSOR(A) \ friend A -#define _TVG_DECLARE_ACCESSORS(A, B) \ - friend A; \ - friend B - #define _TVG_DECALRE_IDENTIFIER() \ + auto id() const { return _id; } \ protected: \ - unsigned id - + unsigned _id namespace tvg { @@ -101,7 +97,6 @@ public: virtual Result bounds(float* x, float* y, float* w, float* h) const = 0; _TVG_DECALRE_IDENTIFIER(); - _TVG_DECLARE_ACCESSORS(Canvas, Scene); }; @@ -264,7 +259,8 @@ public: static std::unique_ptr gen() noexcept; _TVG_DECLARE_PRIVATE(Shape); - _TVG_DECLARE_ACCESSORS(Canvas, Scene); + _TVG_DECLARE_ACCESSOR(Canvas); + _TVG_DECLARE_ACCESSOR(Scene); }; diff --git a/src/lib/sw_engine/meson.build b/src/lib/sw_engine/meson.build index f4998f4..f96fe97 100644 --- a/src/lib/sw_engine/meson.build +++ b/src/lib/sw_engine/meson.build @@ -1,5 +1,6 @@ source_file = [ 'tvgSwCommon.h', + 'tvgSwFill.cpp', 'tvgSwMath.cpp', 'tvgSwRenderer.h', 'tvgSwRaster.cpp', diff --git a/src/lib/sw_engine/tvgSwCommon.h b/src/lib/sw_engine/tvgSwCommon.h index e6f432d..7a0bd41 100644 --- a/src/lib/sw_engine/tvgSwCommon.h +++ b/src/lib/sw_engine/tvgSwCommon.h @@ -21,11 +21,14 @@ using namespace tvg; -constexpr auto SW_CURVE_TYPE_POINT = 0; -constexpr auto SW_CURVE_TYPE_CUBIC = 1; - -constexpr auto SW_OUTLINE_FILL_WINDING = 0; -constexpr auto SW_OUTLINE_FILL_EVEN_ODD = 1; +#define SW_CURVE_TYPE_POINT 0 +#define SW_CURVE_TYPE_CUBIC 1 +#define SW_OUTLINE_FILL_WINDING 0 +#define SW_OUTLINE_FILL_EVEN_ODD 1 +#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; @@ -153,22 +156,28 @@ struct SwDashStroke bool curOpGap; }; +struct SwFill +{ + uint32_t* ctable; + float x1, y1, x2, y2; + float dx, dy; + float len; + float offset; + FillSpread spread; + bool translucent; +}; + struct SwShape { SwOutline* outline; SwStroke* stroke; + SwFill* fill; SwRleData* rle; SwRleData* strokeRle; SwBBox bbox; }; -constexpr static SwFixed ANGLE_PI = (180L << 16); -constexpr static SwFixed ANGLE_2PI = (ANGLE_PI << 1); -constexpr static SwFixed ANGLE_PI2 = (ANGLE_PI >> 1); -constexpr static SwFixed ANGLE_PI4 = (ANGLE_PI >> 2); - - static inline SwPoint TO_SWPOINT(const Point* pt) { return {SwCoord(pt->x * 64), SwCoord(pt->y * 64)}; @@ -181,6 +190,33 @@ static inline SwCoord TO_SWCOORD(float val) } +static inline uint32_t COLOR_ALPHA(uint32_t rgba) +{ + return (rgba >> 24) & 0xff; +} + + +static inline uint32_t COLOR_ALPHA_BLEND(uint32_t rgba, uint32_t alpha) +{ + return (((((rgba >> 8) & 0x00ff00ff) * alpha) & 0xff00ff00) + + ((((rgba & 0x00ff00ff) * alpha) >> 8) & 0x00ff00ff)); +} + + +static inline uint32_t COLOR_INTERPOLATE(uint32_t rgba1, uint32_t a, uint32_t rgba2, uint32_t b) +{ + auto t = (((rgba1 & 0xff00ff) * a + (rgba2 & 0xff00ff) * b) >> 8) & 0xff00ff; + rgba1 = (((rgba1 >> 8) & 0xff00ff) * a + ((rgba2 >> 8) & 0xff00ff) * b) & 0xff00ff00; + return (rgba1 |= t); +} + + +static inline uint32_t COLOR_ARGB_JOIN(uint8_t r, uint8_t g, uint8_t b, uint8_t a) +{ + return (a << 24 | r << 16 | g << 8 | b); +} + + int64_t mathMultiply(int64_t a, int64_t b); int64_t mathDivide(int64_t a, int64_t b); int64_t mathMulDiv(int64_t a, int64_t b, int64_t c); @@ -202,16 +238,26 @@ void shapeDelOutline(SwShape& shape); void shapeResetStroke(SwShape& shape, const Shape& sdata); bool shapeGenStrokeRle(SwShape& shape, const Shape& sdata, const SwSize& clip); void shapeFree(SwShape* shape); +void shapeDelStroke(SwShape& shape); +bool shapeGenFillColors(SwShape& shape, const Fill* fill); +void shapeResetFill(SwShape& shape, const Fill* fill); +void shapeDelFill(SwShape& shape); void strokeReset(SwStroke& stroke, const Shape& shape); bool strokeParseOutline(SwStroke& stroke, const SwOutline& outline); SwOutline* strokeExportOutline(SwStroke& stroke); void strokeFree(SwStroke* stroke); +bool fillGenColorTable(SwFill* fill, const Fill* fdata); +void fillReset(SwFill* fill, const Fill* fdata); +void fillFree(SwFill* fill); +void fillFetch(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len); + SwRleData* rleRender(const SwOutline* outline, const SwBBox& bbox, const SwSize& clip); void rleFree(SwRleData* rle); -bool rasterShape(Surface& surface, SwShape& sdata, uint8_t r, uint8_t g, uint8_t b, uint8_t a); -bool rasterStroke(Surface& surface, SwShape& sdata, uint8_t r, uint8_t g, uint8_t b, uint8_t a); +bool rasterGradientShape(Surface& surface, SwShape& shape); +bool rasterSolidShape(Surface& surface, SwShape& shape, uint8_t r, uint8_t g, uint8_t b, uint8_t a); +bool rasterStroke(Surface& surface, SwShape& shape, uint8_t r, uint8_t g, uint8_t b, uint8_t a); #endif /* _TVG_SW_COMMON_H_ */ diff --git a/src/lib/sw_engine/tvgSwFill.cpp b/src/lib/sw_engine/tvgSwFill.cpp new file mode 100644 index 0000000..9c4927b --- /dev/null +++ b/src/lib/sw_engine/tvgSwFill.cpp @@ -0,0 +1,262 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#ifndef _TVG_SW_FILL_CPP_ +#define _TVG_SW_FILL_CPP_ + +#include "tvgSwCommon.h" + + +/************************************************************************/ +/* Internal Class Implementation */ +/************************************************************************/ + +#define GRADIENT_STOP_SIZE 1024 +#define FIXPT_BITS 8 +#define FIXPT_SIZE (1<ctable) { + fill->ctable = static_cast(malloc(GRADIENT_STOP_SIZE * sizeof(uint32_t))); + assert(fill->ctable); + } + + const Fill::ColorStop* colors; + auto cnt = linear->colorStops(&colors); + if (cnt == 0 || !colors) return false; + + auto pColors = colors; + + if (pColors->a < 255) fill->translucent = true; + + auto rgba = COLOR_ARGB_JOIN(pColors->r, pColors->g, pColors->b, pColors->a); + auto inc = 1.0f / static_cast(GRADIENT_STOP_SIZE); + auto pos = 1.5f * inc; + uint32_t i = 0; + + fill->ctable[i++] = rgba; + + while (pos <= pColors->offset) { + fill->ctable[i] = fill->ctable[i - 1]; + ++i; + pos += inc; + } + + for (uint32_t j = 0; j < cnt - 1; ++j) { + auto curr = colors + j; + auto next = curr + 1; + assert(curr && next); + auto delta = 1.0f / (next->offset - curr->offset); + if (next->a < 255) fill->translucent = true; + auto rgba2 = COLOR_ARGB_JOIN(next->r, next->g, next->b, next->a); + + while (pos < next->offset && i < GRADIENT_STOP_SIZE) { + auto t = (pos - curr->offset) * delta; + auto dist = static_cast(256 * t); + auto dist2 = 256 - dist; + fill->ctable[i] = COLOR_INTERPOLATE(rgba, dist2, rgba2, dist); + ++i; + pos += inc; + } + rgba = rgba2; + } + + for (; i < GRADIENT_STOP_SIZE; ++i) + fill->ctable[i] = rgba; + + //Make sure the lat color stop is represented at the end of the table + fill->ctable[GRADIENT_STOP_SIZE - 1] = rgba; + + return true; +} + + +bool _prepareLinear(SwFill* fill, const LinearGradient* linear) +{ + assert(fill && linear); + + if (linear->linear(&fill->x1, &fill->y1, &fill->x2, &fill->y2) != Result::Success) return false; + + fill->dx = fill->x2 - fill->x1; + fill->dy = fill->y2 - fill->y1; + fill->len = fill->dx * fill->dx + fill->dy * fill->dy; + fill->offset = 0; + + if (fill->len < FLT_EPSILON) return true; + + fill->dx /= fill->len; + fill->dy /= fill->len; + fill->offset = -fill->dx * fill->x1 - fill->dy * fill->y1; + + return _updateColorTable(fill, linear); +} + + +bool _prepareRadial(SwFill* fill, const RadialGradient* radial) +{ + assert(fill && radial); + + return true; +} + + +static inline uint32_t _clamp(const SwFill* fill, uint32_t pos) +{ + switch (fill->spread) { + case FillSpread::Pad: { + if (pos >= GRADIENT_STOP_SIZE) pos = GRADIENT_STOP_SIZE - 1; + break; + } + case FillSpread::Repeat: { + pos = pos % GRADIENT_STOP_SIZE; + break; + } + case FillSpread::Reflect: { + auto limit = GRADIENT_STOP_SIZE * 2; + pos = pos % limit; + if (pos >= GRADIENT_STOP_SIZE) pos = (limit - pos - 1); + break; + } + } + return pos; +} + + +static inline uint32_t _fixedPixel(const SwFill* fill, uint32_t pos) +{ + auto i = (pos + (FIXPT_SIZE / 2)) >> FIXPT_BITS; + return fill->ctable[_clamp(fill, i)]; +} + + +static inline uint32_t _pixel(const SwFill* fill, float pos) +{ + auto i = static_cast(pos * (GRADIENT_STOP_SIZE - 1) + 0.5f); + return fill->ctable[_clamp(fill, i)]; +} + + +static inline void _write(uint32_t *dst, uint32_t val, uint32_t len) +{ + if (len <= 0) return; + + // Cute hack to align future memcopy operation + // and do unroll the loop a bit. Not sure it is + // the most efficient, but will do for now. + auto n = (len + 7) / 8; + + switch (len & 0x07) { + case 0: do { *dst++ = val; + case 7: *dst++ = val; + case 6: *dst++ = val; + case 5: *dst++ = val; + case 4: *dst++ = val; + case 3: *dst++ = val; + case 2: *dst++ = val; + case 1: *dst++ = val; + } while (--n > 0); + } +} + + +/************************************************************************/ +/* External Class Implementation */ +/************************************************************************/ + +void fillFetch(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len) +{ + assert(fill->len > 0); + + //TODO: Rotation??? + auto rx = x + 0.5f; + auto ry = y + 0.5f; + auto t = (fill->dx * rx + fill->dy * ry + fill->offset) * (GRADIENT_STOP_SIZE - 1); + auto inc = (fill->dx) * (GRADIENT_STOP_SIZE - 1); + + if (fabsf(inc) < FLT_EPSILON) { + auto color = _fixedPixel(fill, static_cast(t * FIXPT_SIZE)); + _write(dst, color, len); + return; + } + + auto vMax = static_cast(INT32_MAX >> (FIXPT_BITS + 1)); + auto vMin = -vMax; + auto v = t + (inc * len); + + //we can use fixed point math + if (v < vMax && v > vMin) { + auto t2 = static_cast(t * FIXPT_SIZE); + auto inc2 = static_cast(inc * FIXPT_SIZE); + for (uint32_t j = 0; j < len; ++j) { + *dst = _fixedPixel(fill, t2); + ++dst; + t2 += inc2; + } + //we have to fallback to float math + } else { + while (dst < dst + len) { + *dst = _pixel(fill, t / GRADIENT_STOP_SIZE); + ++dst; + t += inc; + } + } +} + + +bool fillGenColorTable(SwFill* fill, const Fill* fdata) +{ + if (!fill) return false; + + assert(fdata); + + fill->spread = fdata->spread(); + + if (fdata->id() == FILL_ID_LINEAR) { + return _prepareLinear(fill, static_cast(fdata)); + } else if (fdata->id() == FILL_ID_RADIAL) { + return _prepareRadial(fill, static_cast(fdata)); + } + + cout << "What type of gradient?!" << endl; + + return false; +} + + +void fillReset(SwFill* fill, const Fill* fdata) +{ + if (fill->ctable) { + free(fill->ctable); + fill->ctable = nullptr; + } + fill->translucent = false; +} + + +void fillFree(SwFill* fill) +{ + if (!fill) return; + + if (fill->ctable) free(fill->ctable); + + free(fill); +} + +#endif /* _TVG_SW_FILL_CPP_ */ \ No newline at end of file diff --git a/src/lib/sw_engine/tvgSwMath.cpp b/src/lib/sw_engine/tvgSwMath.cpp index a0a0ea1..53cc8ce 100644 --- a/src/lib/sw_engine/tvgSwMath.cpp +++ b/src/lib/sw_engine/tvgSwMath.cpp @@ -93,15 +93,15 @@ static void _polarize(SwPoint& pt) auto tmp = v.y; v.y = -v.x; v.x = tmp; - theta = ANGLE_PI2; + theta = SW_ANGLE_PI2; } else { - theta = v.y > 0 ? ANGLE_PI : -ANGLE_PI; + 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 = -ANGLE_PI2; + theta = -SW_ANGLE_PI2; auto tmp = -v.y; v.y = v.x; v.x = tmp; @@ -144,18 +144,18 @@ static void _rotate(SwPoint& pt, SwFixed theta) SwFixed y = pt.y; //Rotate inside [-PI/4, PI/4] sector - while (theta < -ANGLE_PI4) { + while (theta < -SW_ANGLE_PI4) { auto tmp = y; y = -x; x = tmp; - theta += ANGLE_PI2; + theta += SW_ANGLE_PI2; } - while (theta > ANGLE_PI4) { + while (theta > SW_ANGLE_PI4) { auto tmp = -y; y = x; x = tmp; - theta -= ANGLE_PI2; + theta -= SW_ANGLE_PI2; } auto atan = ATAN_TBL; @@ -236,7 +236,7 @@ bool mathSmallCubic(SwPoint* base, SwFixed& angleIn, SwFixed& angleMid, SwFixed& auto theta1 = abs(mathDiff(angleIn, angleMid)); auto theta2 = abs(mathDiff(angleMid, angleOut)); - if ((theta1 < (ANGLE_PI / 8)) && (theta2 < (ANGLE_PI / 8))) return true; + if ((theta1 < (SW_ANGLE_PI / 8)) && (theta2 < (SW_ANGLE_PI / 8))) return true; else return false; } @@ -346,7 +346,7 @@ SwFixed mathAtan(const SwPoint& pt) SwFixed mathSin(SwFixed angle) { - return mathCos(ANGLE_PI2 - angle); + return mathCos(SW_ANGLE_PI2 - angle); } @@ -408,9 +408,9 @@ SwFixed mathDiff(SwFixed angle1, SwFixed angle2) { auto delta = angle2 - angle1; - delta %= ANGLE_2PI; - if (delta < 0) delta += ANGLE_2PI; - if (delta > ANGLE_PI) delta -= ANGLE_2PI; + delta %= SW_ANGLE_2PI; + if (delta < 0) delta += SW_ANGLE_2PI; + if (delta > SW_ANGLE_PI) delta -= SW_ANGLE_2PI; return delta; } diff --git a/src/lib/sw_engine/tvgSwRaster.cpp b/src/lib/sw_engine/tvgSwRaster.cpp index 78d507b..581f8b7 100644 --- a/src/lib/sw_engine/tvgSwRaster.cpp +++ b/src/lib/sw_engine/tvgSwRaster.cpp @@ -24,77 +24,95 @@ /* Internal Class Implementation */ /************************************************************************/ -static inline uint32_t COLOR_ALPHA(uint32_t color) +static bool _rasterTranslucentRle(Surface& surface, SwRleData* rle, uint32_t color) { - return (color >> 24) & 0xff; -} - - -static inline uint32_t COLOR_ALPHA_BLEND(uint32_t color, uint32_t alpha) -{ - return (((((color >> 8) & 0x00ff00ff) * alpha) & 0xff00ff00) + - ((((color & 0x00ff00ff) * alpha) >> 8) & 0x00ff00ff)); -} + if (!rle) return false; + auto span = rle->spans; + auto stride = surface.stride; + uint32_t tmp; -static inline uint32_t COLOR_ARGB_JOIN(uint8_t r, uint8_t g, uint8_t b, uint8_t a) -{ - return (a << 24 | r << 16 | g << 8 | b); + for (uint32_t i = 0; i < rle->size; ++i) { + auto dst = &surface.buffer[span->y * stride + span->x]; + if (span->coverage < 255) tmp = COLOR_ALPHA_BLEND(color, span->coverage); + else tmp = color; + for (uint32_t i = 0; i < span->len; ++i) { + dst[i] = tmp + COLOR_ALPHA_BLEND(dst[i], 255 - COLOR_ALPHA(tmp)); + } + ++span; + } + return true; } -static void -_rasterTranslucent(uint32_t* dst, uint32_t len, uint32_t color, uint32_t cov) +static bool _rasterSolidRle(Surface& surface, SwRleData* rle, uint32_t color) { - //OPTIMIZE ME: SIMD - - if (cov < 255) color = COLOR_ALPHA_BLEND(color, cov); - auto ialpha = 255 - COLOR_ALPHA(color); - - for (uint32_t i = 0; i < len; ++i) { - dst[i] = color + COLOR_ALPHA_BLEND(dst[i], ialpha); - } -} - + if (!rle) return false; -static void -_rasterSolid(uint32_t* dst, uint32_t len, uint32_t color, uint32_t cov) -{ - //OPTIMIZE ME: SIMD + auto span = rle->spans; + auto stride = surface.stride; - //Fully Opaque - if (cov == 255) { - for (uint32_t i = 0; i < len; ++i) { - dst[i] = color; - } - } else { - auto ialpha = 255 - cov; - for (uint32_t i = 0; i < len; ++i) { - dst[i] = COLOR_ALPHA_BLEND(color, cov) + COLOR_ALPHA_BLEND(dst[i], ialpha); + for (uint32_t i = 0; i < rle->size; ++i) { + auto dst = &surface.buffer[span->y * stride + span->x]; + if (span->coverage == 255) { + for (uint32_t i = 0; i < span->len; ++i) { + dst[i] = color; + } + } else { + for (uint32_t i = 0; i < span->len; ++i) { + dst[i] = COLOR_ALPHA_BLEND(color, span->coverage) + COLOR_ALPHA_BLEND(dst[i], 255 - span->coverage); + } + } + ++span; } - } + return true; } -static bool -_rasterRle(Surface& surface, SwRleData* rle, uint32_t color, uint8_t a) +static bool _rasterGradientRle(Surface& surface, SwRleData* rle, const SwFill* fill) { - if (!rle) return false; + if (!rle || !fill) return false; + + auto buf = static_cast(alloca(surface.w * sizeof(uint32_t))); + if (!buf) return false; auto span = rle->spans; auto stride = surface.stride; - for (uint32_t i = 0; i < rle->size; ++i) { - assert(span); - - auto dst = &surface.buffer[span->y * stride + span->x]; - - if (a == 255) _rasterSolid(dst, span->len, color, span->coverage); - else _rasterTranslucent(dst, span->len, color, span->coverage); - - ++span; + //Translucent Gradient + if (fill->translucent) { + uint32_t tmp; + for (uint32_t i = 0; i < rle->size; ++i) { + auto dst = &surface.buffer[span->y * stride + span->x]; + fillFetch(fill, buf, span->y, span->x, span->len); + if (span->coverage == 255) { + for (uint32_t i = 0; i < span->len; ++i) { + dst[i] = buf[i] + COLOR_ALPHA_BLEND(dst[i], 255 - COLOR_ALPHA(buf[i])); + } + } else { + for (uint32_t i = 0; i < span->len; ++i) { + tmp = COLOR_ALPHA_BLEND(buf[i], span->coverage); + dst[i] = tmp + COLOR_ALPHA_BLEND(dst[i], 255 - COLOR_ALPHA(tmp)); + } + } + ++span; + } + //Opaque Gradient + } else { + for (uint32_t i = 0; i < rle->size; ++i) { + auto dst = &surface.buffer[span->y * stride + span->x]; + if (span->coverage == 255) { + fillFetch(fill, dst, span->y, span->x, span->len); + } else { + fillFetch(fill, buf, span->y, span->x, span->len); + auto ialpha = 255 - span->coverage; + for (uint32_t i = 0; i < span->len; ++i) { + dst[i] = COLOR_ALPHA_BLEND(buf[i], span->coverage) + COLOR_ALPHA_BLEND(dst[i], ialpha); + } + } + ++span; + } } - return true; } @@ -103,15 +121,23 @@ _rasterRle(Surface& surface, SwRleData* rle, uint32_t color, uint8_t a) /* External Class Implementation */ /************************************************************************/ -bool rasterShape(Surface& surface, SwShape& sdata, uint8_t r, uint8_t g, uint8_t b, uint8_t a) +bool rasterGradientShape(Surface& surface, SwShape& shape) +{ + return _rasterGradientRle(surface, shape.rle, shape.fill); +} + + +bool rasterSolidShape(Surface& surface, SwShape& shape, uint8_t r, uint8_t g, uint8_t b, uint8_t a) { - return _rasterRle(surface, sdata.rle, COLOR_ARGB_JOIN(r, g, b, a), a); + if (a == 255) return _rasterSolidRle(surface, shape.rle, COLOR_ARGB_JOIN(r, g, b, a)); + return _rasterTranslucentRle(surface, shape.rle, COLOR_ARGB_JOIN(r, g, b, a)); } -bool rasterStroke(Surface& surface, SwShape& sdata, uint8_t r, uint8_t g, uint8_t b, uint8_t a) +bool rasterStroke(Surface& surface, SwShape& shape, uint8_t r, uint8_t g, uint8_t b, uint8_t a) { - return _rasterRle(surface, sdata.strokeRle, COLOR_ARGB_JOIN(r, g, b, a), a); + if (a == 255) return _rasterSolidRle(surface, shape.strokeRle, COLOR_ARGB_JOIN(r, g, b, a)); + return _rasterTranslucentRle(surface, shape.strokeRle, COLOR_ARGB_JOIN(r, g, b, a)); } diff --git a/src/lib/sw_engine/tvgSwRenderer.cpp b/src/lib/sw_engine/tvgSwRenderer.cpp index 43c2628..e99bf38 100644 --- a/src/lib/sw_engine/tvgSwRenderer.cpp +++ b/src/lib/sw_engine/tvgSwRenderer.cpp @@ -57,28 +57,32 @@ bool SwRenderer::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t return true; } -bool SwRenderer::render(const Shape& shape, void *data) +bool SwRenderer::render(const Shape& sdata, void *data) { - SwShape* sdata = static_cast(data); - if (!sdata) return false; + SwShape* shape = static_cast(data); + if (!shape) return false; uint8_t r, g, b, a; - shape.fill(&r, &g, &b, &a); - if (a > 0) rasterShape(surface, *sdata, r, g, b, a); + if (sdata.fill()) { + rasterGradientShape(surface, *shape); + } else { + sdata.fill(&r, &g, &b, &a); + if (a > 0) rasterSolidShape(surface, *shape, r, g, b, a); + } - shape.strokeColor(&r, &g, &b, &a); - if (a > 0) rasterStroke(surface, *sdata, r, g, b, a); + sdata.strokeColor(&r, &g, &b, &a); + if (a > 0) rasterStroke(surface, *shape, r, g, b, a); return true; } -bool SwRenderer::dispose(const Shape& shape, void *data) +bool SwRenderer::dispose(const Shape& sdata, void *data) { - auto sdata = static_cast(data); - if (!sdata) return true; - shapeFree(sdata); + auto shape = static_cast(data); + if (!shape) return true; + shapeFree(shape); return true; } @@ -103,11 +107,22 @@ void* SwRenderer::prepare(const Shape& sdata, void* data, const RenderTransform* shapeReset(*shape); uint8_t alpha = 0; sdata.fill(nullptr, nullptr, nullptr, &alpha); - if (alpha > 0) { + if (alpha > 0 || sdata.fill()) { if (!shapeGenRle(*shape, sdata, clip, transform)) return shape; } } + //Fill + if (flags & (RenderUpdateFlag::Gradient)) { + auto fill = sdata.fill(); + if (fill) { + shapeResetFill(*shape, fill); + if (!shapeGenFillColors(*shape, fill)) return shape; + } else { + shapeDelFill(*shape); + } + } + //Stroke if (flags & (RenderUpdateFlag::Stroke | RenderUpdateFlag::Transform)) { if (sdata.strokeWidth() > 0.5) { @@ -117,6 +132,8 @@ void* SwRenderer::prepare(const Shape& sdata, void* data, const RenderTransform* if (alpha > 0) { if (!shapeGenStrokeRle(*shape, sdata, clip)) return shape; } + } else { + shapeDelStroke(*shape); } } diff --git a/src/lib/sw_engine/tvgSwShape.cpp b/src/lib/sw_engine/tvgSwShape.cpp index dcb57c7..4dcf210 100644 --- a/src/lib/sw_engine/tvgSwShape.cpp +++ b/src/lib/sw_engine/tvgSwShape.cpp @@ -666,19 +666,29 @@ bool shapeGenOutline(SwShape& shape, const Shape& sdata) } -void shapeFree(SwShape* sdata) +void shapeFree(SwShape* shape) { - assert(sdata); + assert(shape); - shapeDelOutline(*sdata); - rleFree(sdata->rle); + shapeDelOutline(*shape); + rleFree(shape->rle); - if (sdata->stroke) { - rleFree(sdata->strokeRle); - strokeFree(sdata->stroke); + if (shape->stroke) { + rleFree(shape->strokeRle); + strokeFree(shape->stroke); } - free(sdata); + free(shape); +} + + +void shapeDelStroke(SwShape& shape) +{ + if (!shape.stroke) return; + rleFree(shape.strokeRle); + shape.strokeRle = nullptr; + strokeFree(shape.stroke); + shape.stroke = nullptr; } @@ -730,4 +740,32 @@ bool shapeGenStrokeRle(SwShape& shape, const Shape& sdata, const SwSize& clip) } +bool shapeGenFillColors(SwShape& shape, const Fill* fill) +{ + assert(fill); + + fillGenColorTable(shape.fill, fill); + return true; +} + + +void shapeResetFill(SwShape& shape, const Fill* fill) +{ + assert(fill); + + if (!shape.fill) shape.fill = static_cast(calloc(1, sizeof(SwFill))); + assert(shape.fill); + + fillReset(shape.fill, fill); +} + + +void shapeDelFill(SwShape& shape) +{ + if (!shape.fill) return; + fillFree(shape.fill); + shape.fill = nullptr; +} + + #endif /* _TVG_SW_SHAPE_H_ */ diff --git a/src/lib/sw_engine/tvgSwStroke.cpp b/src/lib/sw_engine/tvgSwStroke.cpp index fdc8cae..8b6f1ce 100644 --- a/src/lib/sw_engine/tvgSwStroke.cpp +++ b/src/lib/sw_engine/tvgSwStroke.cpp @@ -30,7 +30,7 @@ static constexpr auto SW_STROKE_TAG_END = 8; static inline SwFixed SIDE_TO_ROTATE(const int32_t s) { - return (ANGLE_PI2 - (s) * ANGLE_PI); + return (SW_ANGLE_PI2 - (s) * SW_ANGLE_PI); } @@ -134,14 +134,14 @@ static void _borderCubicTo(SwStrokeBorder* border, SwPoint& ctrl1, SwPoint& ctrl static void _borderArcTo(SwStrokeBorder* border, SwPoint& center, SwFixed radius, SwFixed angleStart, SwFixed angleDiff) { - constexpr SwFixed ARC_CUBIC_ANGLE = ANGLE_PI / 2; + constexpr SwFixed ARC_CUBIC_ANGLE = SW_ANGLE_PI / 2; SwPoint a = {radius, 0}; mathRotate(a, angleStart); a += center; auto total = angleDiff; auto angle = angleStart; - auto rotate = (angleDiff >= 0) ? ANGLE_PI2 : -ANGLE_PI2; + auto rotate = (angleDiff >= 0) ? SW_ANGLE_PI2 : -SW_ANGLE_PI2; while (total != 0) { auto step = total; @@ -222,7 +222,7 @@ static void _arcTo(SwStroke& stroke, int32_t side) auto border = stroke.borders + side; auto rotate = SIDE_TO_ROTATE(side); auto total = mathDiff(stroke.angleIn, stroke.angleOut); - if (total == ANGLE_PI) total = -rotate * 2; + if (total == SW_ANGLE_PI) total = -rotate * 2; _borderArcTo(border, stroke.center, stroke.width, stroke.angleIn + rotate, total); border->movable = false; @@ -249,7 +249,7 @@ static void _outside(SwStroke& stroke, int32_t side, SwFixed lineLength) if (!bevel) { auto theta = mathDiff(stroke.angleIn, stroke.angleOut); - if (theta == ANGLE_PI) { + if (theta == SW_ANGLE_PI) { theta = rotate; phi = stroke.angleIn; } else { @@ -354,7 +354,7 @@ void _processCorner(SwStroke& stroke, SwFixed lineLength) void _firstSubPath(SwStroke& stroke, SwFixed startAngle, SwFixed lineLength) { SwPoint delta = {stroke.width, 0}; - mathRotate(delta, startAngle + ANGLE_PI2); + mathRotate(delta, startAngle + SW_ANGLE_PI2); auto pt = stroke.center + delta; auto border = stroke.borders; @@ -384,7 +384,7 @@ static void _lineTo(SwStroke& stroke, const SwPoint& to) auto angle = mathAtan(delta); delta = {stroke.width, 0}; - mathRotate(delta, angle + ANGLE_PI2); + mathRotate(delta, angle + SW_ANGLE_PI2); //process corner if necessary if (stroke.firstPt) { @@ -460,7 +460,7 @@ static void _cubicTo(SwStroke& stroke, const SwPoint& ctrl1, const SwPoint& ctrl stroke.angleOut = angleIn; _processCorner(stroke, 0); } - } else if (abs(mathDiff(stroke.angleIn, angleIn)) > (ANGLE_PI / 8)) { + } else if (abs(mathDiff(stroke.angleIn, angleIn)) > (SW_ANGLE_PI / 8)) { //if the deviation from one arc to the next is too great add a round corner stroke.center = arc[3]; stroke.angleOut = angleIn; @@ -515,7 +515,7 @@ static void _cubicTo(SwStroke& stroke, const SwPoint& ctrl1, const SwPoint& ctrl auto alpha1 = mathAtan(_end - _start); //is the direction of the border arc opposite to that of the original arc? - if (abs(mathDiff(alpha0, alpha1)) > ANGLE_PI / 2) { + if (abs(mathDiff(alpha0, alpha1)) > SW_ANGLE_PI / 2) { //use the sine rule to find the intersection point auto beta = mathAtan(arc[3] - _start); @@ -583,7 +583,7 @@ static void _addCap(SwStroke& stroke, SwFixed angle, int32_t side) } else if (stroke.cap == StrokeCap::Round) { stroke.angleIn = angle; - stroke.angleOut = angle + ANGLE_PI; + stroke.angleOut = angle + SW_ANGLE_PI; _arcTo(stroke, side); return; @@ -692,7 +692,7 @@ static void _endSubPath(SwStroke& stroke) //now add the final cap stroke.center = stroke.ptStartSubPath; - _addCap(stroke, stroke.subPathAngle + ANGLE_PI, 0); + _addCap(stroke, stroke.subPathAngle + SW_ANGLE_PI, 0); /* now end the right subpath accordingly. The left one is rewind and deosn't need further processing */ diff --git a/src/lib/tvgCanvasImpl.h b/src/lib/tvgCanvasImpl.h index c6dc073..42cf470 100644 --- a/src/lib/tvgCanvasImpl.h +++ b/src/lib/tvgCanvasImpl.h @@ -53,7 +53,7 @@ struct Canvas::Impl assert(renderer); for (auto paint : paints) { - if (paint->id == PAINT_ID_SCENE) { + if (paint->id() == PAINT_ID_SCENE) { //We know renderer type, avoid dynamic_cast for performance. auto scene = static_cast(paint); if (!SCENE_IMPL->clear(*renderer)) return Result::InsufficientCondition; @@ -73,7 +73,7 @@ struct Canvas::Impl assert(renderer); for(auto paint: paints) { - if (paint->id == PAINT_ID_SCENE) { + if (paint->id() == PAINT_ID_SCENE) { //We know renderer type, avoid dynamic_cast for performance. auto scene = static_cast(paint); if (!SCENE_IMPL->update(*renderer, nullptr)) return Result::InsufficientCondition; @@ -89,7 +89,7 @@ struct Canvas::Impl { assert(renderer); - if (paint->id == PAINT_ID_SCENE) { + if (paint->id() == PAINT_ID_SCENE) { //We know renderer type, avoid dynamic_cast for performance. auto scene = static_cast(paint); if (!SCENE_IMPL->update(*renderer)) return Result::InsufficientCondition; @@ -108,7 +108,7 @@ struct Canvas::Impl if (!renderer->clear()) return Result::InsufficientCondition; for(auto paint: paints) { - if (paint->id == PAINT_ID_SCENE) { + if (paint->id() == PAINT_ID_SCENE) { //We know renderer type, avoid dynamic_cast for performance. auto scene = static_cast(paint); if(!SCENE_IMPL->render(*renderer)) return Result::InsufficientCondition; diff --git a/src/lib/tvgLinearGradient.cpp b/src/lib/tvgLinearGradient.cpp index 9ea803d..4499454 100644 --- a/src/lib/tvgLinearGradient.cpp +++ b/src/lib/tvgLinearGradient.cpp @@ -35,7 +35,7 @@ struct LinearGradient::Impl LinearGradient::LinearGradient():pImpl(make_unique()) { - id = FILL_ID_LINEAR; + _id = FILL_ID_LINEAR; } diff --git a/src/lib/tvgRadialGradient.cpp b/src/lib/tvgRadialGradient.cpp index 2447e6f..895cccb 100644 --- a/src/lib/tvgRadialGradient.cpp +++ b/src/lib/tvgRadialGradient.cpp @@ -35,7 +35,7 @@ struct RadialGradient::Impl RadialGradient::RadialGradient():pImpl(make_unique()) { - id = FILL_ID_RADIAL; + _id = FILL_ID_RADIAL; } diff --git a/src/lib/tvgScene.cpp b/src/lib/tvgScene.cpp index ac2ae82..1ce0ada 100644 --- a/src/lib/tvgScene.cpp +++ b/src/lib/tvgScene.cpp @@ -25,7 +25,7 @@ Scene::Scene() : pImpl(make_unique()) { - id = PAINT_ID_SCENE; + _id = PAINT_ID_SCENE; } diff --git a/src/lib/tvgSceneImpl.h b/src/lib/tvgSceneImpl.h index 8596292..2c92d5b 100644 --- a/src/lib/tvgSceneImpl.h +++ b/src/lib/tvgSceneImpl.h @@ -39,7 +39,7 @@ struct Scene::Impl bool clear(RenderMethod& renderer) { for (auto paint : paints) { - if (paint->id == PAINT_ID_SCENE) { + if (paint->id() == PAINT_ID_SCENE) { //We know renderer type, avoid dynamic_cast for performance. auto scene = static_cast(paint); if (!SCENE_IMPL->clear(renderer)) return false; @@ -57,7 +57,7 @@ struct Scene::Impl bool updateInternal(RenderMethod &renderer, const RenderTransform* transform, uint32_t flag) { for(auto paint: paints) { - if (paint->id == PAINT_ID_SCENE) { + if (paint->id() == PAINT_ID_SCENE) { //We know renderer type, avoid dynamic_cast for performance. auto scene = static_cast(paint); if (!SCENE_IMPL->update(renderer, transform, flag)) return false; @@ -97,7 +97,7 @@ struct Scene::Impl bool render(RenderMethod &renderer) { for(auto paint: paints) { - if (paint->id == PAINT_ID_SCENE) { + if (paint->id() == PAINT_ID_SCENE) { //We know renderer type, avoid dynamic_cast for performance. auto scene = static_cast(paint); if(!SCENE_IMPL->render(renderer)) return false; @@ -122,7 +122,7 @@ struct Scene::Impl auto w2 = 0.0f; auto h2 = 0.0f; - if (paint->id == PAINT_ID_SCENE) { + if (paint->id() == PAINT_ID_SCENE) { //We know renderer type, avoid dynamic_cast for performance. auto scene = static_cast(paint); if (!SCENE_IMPL->bounds(&x2, &y2, &w2, &h2)) return false; diff --git a/src/lib/tvgShape.cpp b/src/lib/tvgShape.cpp index 012fcb1..aabd5bd 100644 --- a/src/lib/tvgShape.cpp +++ b/src/lib/tvgShape.cpp @@ -32,7 +32,7 @@ constexpr auto PATH_KAPPA = 0.552284f; Shape :: Shape() : pImpl(make_unique()) { - id = PAINT_ID_SHAPE; + _id = PAINT_ID_SHAPE; } diff --git a/test/testLinearGradient.cpp b/test/testLinearGradient.cpp index 4f87cad..33536c4 100644 --- a/test/testLinearGradient.cpp +++ b/test/testLinearGradient.cpp @@ -18,37 +18,39 @@ void tvgtest() canvas->target(buffer, WIDTH, WIDTH, HEIGHT); canvas->reserve(3); //reserve 3 shape nodes (optional) - //Linear Gradient Color Stops - tvg::Fill::ColorStop colorStops[3]; - colorStops[0] = {0, 255, 0, 0, 255}; - colorStops[1] = {0.5, 255, 255, 255, 255}; - colorStops[2] = {1, 0, 0, 255, 255}; - //Prepare Round Rectangle auto shape1 = tvg::Shape::gen(); - shape1->appendRect(0, 0, 400, 400, 50); //x, y, w, h, cornerRadius - shape1->stroke(255, 255, 255, 255); - shape1->stroke(2); + shape1->appendRect(0, 0, 400, 400, 0); //x, y, w, h, cornerRadius //LinearGradient auto fill = tvg::LinearGradient::gen(); fill->linear(0, 0, 400, 400); - fill->colorStops(colorStops, 3); + + //Linear Gradient Color Stops + tvg::Fill::ColorStop colorStops[2]; + colorStops[0] = {0, 0, 0, 0, 255}; + colorStops[1] = {1, 255, 255, 255, 255}; + + fill->colorStops(colorStops, 2); shape1->fill(move(fill)); canvas->push(move(shape1)); - //Prepare Circle auto shape2 = tvg::Shape::gen(); shape2->appendCircle(400, 400, 200, 200); //cx, cy, radiusW, radiusH - shape2->stroke(255, 255, 255, 255); - shape2->stroke(2); //LinearGradient auto fill2 = tvg::LinearGradient::gen(); fill2->linear(400, 200, 400, 600); - fill2->colorStops(colorStops, 3); + + //Linear Gradient Color Stops + tvg::Fill::ColorStop colorStops2[3]; + colorStops2[0] = {0, 255, 0, 0, 255}; + colorStops2[1] = {0.5, 255, 255, 0, 255}; + colorStops2[2] = {1, 255, 255, 255, 255}; + + fill2->colorStops(colorStops2, 3); shape2->fill(move(fill2)); canvas->push(move(shape2)); @@ -57,13 +59,19 @@ void tvgtest() //Prepare Ellipse auto shape3 = tvg::Shape::gen(); shape3->appendCircle(600, 600, 150, 100); //cx, cy, radiusW, radiusH - shape3->stroke(255, 255, 255, 255); - shape3->stroke(2); //LinearGradient auto fill3 = tvg::LinearGradient::gen(); fill3->linear(450, 600, 750, 600); - fill3->colorStops(colorStops, 3); + + //Linear Gradient Color Stops + tvg::Fill::ColorStop colorStops3[4]; + colorStops3[0] = {0, 0, 127, 0, 127}; + colorStops3[1] = {0.25, 0, 170, 170, 170}; + colorStops3[2] = {0.5, 200, 0, 200, 200}; + colorStops3[3] = {1, 255, 255, 255, 255}; + + fill3->colorStops(colorStops3, 4); shape3->fill(move(fill3)); canvas->push(move(shape3)); -- 2.7.4 From 7366e8949bbae8a4cb201ef2dbc2df2b84e232dc Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Sun, 14 Jun 2020 17:53:29 +0900 Subject: [PATCH 03/16] sw_engine: implement gradial gradient feature also added testRadialGradient Change-Id: If4a278cb4667c38c7842ad30edf5aa2fdd56fff7 --- .gitignore | 1 + src/lib/sw_engine/tvgSwCommon.h | 26 ++++++-- src/lib/sw_engine/tvgSwFill.cpp | 65 ++++++++++++++------ src/lib/sw_engine/tvgSwRaster.cpp | 63 +++++++++++++++++--- src/lib/sw_engine/tvgSwRenderer.cpp | 4 +- test/makefile | 1 + test/testRadialGradient.cpp | 115 ++++++++++++++++++++++++++++++++++++ 7 files changed, 242 insertions(+), 33 deletions(-) create mode 100644 test/testRadialGradient.cpp diff --git a/.gitignore b/.gitignore index b9cdf24..f108357 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,4 @@ testSceneTransform testStroke testStrokeLine testLinearGradient +testRadialGradient diff --git a/src/lib/sw_engine/tvgSwCommon.h b/src/lib/sw_engine/tvgSwCommon.h index 7a0bd41..21a1705 100644 --- a/src/lib/sw_engine/tvgSwCommon.h +++ b/src/lib/sw_engine/tvgSwCommon.h @@ -158,11 +158,24 @@ struct SwDashStroke struct SwFill { + struct SwLinear { + float dx, dy; + float len; + float offset; + }; + + struct SwRadial { + float cx, cy; + float a; + float inv2a; + }; + + union { + SwLinear linear; + SwRadial radial; + }; + uint32_t* ctable; - float x1, y1, x2, y2; - float dx, dy; - float len; - float offset; FillSpread spread; bool translucent; }; @@ -251,12 +264,13 @@ void strokeFree(SwStroke* stroke); bool fillGenColorTable(SwFill* fill, const Fill* fdata); void fillReset(SwFill* fill, const Fill* fdata); void fillFree(SwFill* fill); -void fillFetch(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len); +void fillFetchLinear(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len); +void fillFetchRadial(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len); SwRleData* rleRender(const SwOutline* outline, const SwBBox& bbox, const SwSize& clip); void rleFree(SwRleData* rle); -bool rasterGradientShape(Surface& surface, SwShape& shape); +bool rasterGradientShape(Surface& surface, SwShape& shape, unsigned id); bool rasterSolidShape(Surface& surface, SwShape& shape, uint8_t r, uint8_t g, uint8_t b, uint8_t a); bool rasterStroke(Surface& surface, SwShape& shape, uint8_t r, uint8_t g, uint8_t b, uint8_t a); diff --git a/src/lib/sw_engine/tvgSwFill.cpp b/src/lib/sw_engine/tvgSwFill.cpp index 9c4927b..1fcafa3 100644 --- a/src/lib/sw_engine/tvgSwFill.cpp +++ b/src/lib/sw_engine/tvgSwFill.cpp @@ -29,9 +29,9 @@ #define FIXPT_SIZE (1<ctable) { fill->ctable = static_cast(malloc(GRADIENT_STOP_SIZE * sizeof(uint32_t))); @@ -39,7 +39,7 @@ static bool _updateColorTable(SwFill* fill, const LinearGradient* linear) } const Fill::ColorStop* colors; - auto cnt = linear->colorStops(&colors); + auto cnt = fdata->colorStops(&colors); if (cnt == 0 || !colors) return false; auto pColors = colors; @@ -92,18 +92,18 @@ bool _prepareLinear(SwFill* fill, const LinearGradient* linear) { assert(fill && linear); - if (linear->linear(&fill->x1, &fill->y1, &fill->x2, &fill->y2) != Result::Success) return false; + float x1, x2, y1, y2; + if (linear->linear(&x1, &y1, &x2, &y2) != Result::Success) return false; - fill->dx = fill->x2 - fill->x1; - fill->dy = fill->y2 - fill->y1; - fill->len = fill->dx * fill->dx + fill->dy * fill->dy; - fill->offset = 0; + 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; - if (fill->len < FLT_EPSILON) return true; + if (fill->linear.len < FLT_EPSILON) return true; - fill->dx /= fill->len; - fill->dy /= fill->len; - fill->offset = -fill->dx * fill->x1 - fill->dy * fill->y1; + fill->linear.dx /= fill->linear.len; + fill->linear.dy /= fill->linear.len; + fill->linear.offset = -fill->linear.dx * x1 - fill->linear.dy * y1; return _updateColorTable(fill, linear); } @@ -113,7 +113,14 @@ bool _prepareRadial(SwFill* fill, const RadialGradient* radial) { assert(fill && radial); - return true; + float radius; + if (radial->radial(&fill->radial.cx, &fill->radial.cy, &radius) != Result::Success) return false; + if (radius < FLT_EPSILON) return true; + + fill->radial.a = radius * radius; + fill->radial.inv2a = pow(1 / (2 * fill->radial.a), 2); + + return _updateColorTable(fill, radial); } @@ -180,15 +187,39 @@ static inline void _write(uint32_t *dst, uint32_t val, uint32_t len) /* External Class Implementation */ /************************************************************************/ -void fillFetch(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len) +void fillFetchRadial(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len) +{ + if (fill->radial.a < FLT_EPSILON) return; + + //TODO: Rotation??? + auto rx = x + 0.5f - fill->radial.cx; + auto ry = y + 0.5f - fill->radial.cy; + auto inv2a = fill->radial.inv2a; + auto rxy = rx * rx + ry * ry; + auto rxryPlus = 2 * rx; + auto det = (-4 * fill->radial.a * -rxy) * inv2a; + auto detDelta = (4 * fill->radial.a * (rxryPlus + 1.0f)) * inv2a; + auto detDelta2 = (4 * fill->radial.a * 2.0f) * inv2a; + + for (uint32_t i = 0 ; i < len ; ++i) + { + *dst = _pixel(fill, sqrt(det)); + ++dst; + det += detDelta; + detDelta += detDelta2; + } +} + + +void fillFetchLinear(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len) { - assert(fill->len > 0); + if (fill->linear.len < FLT_EPSILON) return; //TODO: Rotation??? auto rx = x + 0.5f; auto ry = y + 0.5f; - auto t = (fill->dx * rx + fill->dy * ry + fill->offset) * (GRADIENT_STOP_SIZE - 1); - auto inc = (fill->dx) * (GRADIENT_STOP_SIZE - 1); + auto t = (fill->linear.dx * rx + fill->linear.dy * ry + fill->linear.offset) * (GRADIENT_STOP_SIZE - 1); + auto inc = (fill->linear.dx) * (GRADIENT_STOP_SIZE - 1); if (fabsf(inc) < FLT_EPSILON) { auto color = _fixedPixel(fill, static_cast(t * FIXPT_SIZE)); diff --git a/src/lib/sw_engine/tvgSwRaster.cpp b/src/lib/sw_engine/tvgSwRaster.cpp index 581f8b7..05f23e6 100644 --- a/src/lib/sw_engine/tvgSwRaster.cpp +++ b/src/lib/sw_engine/tvgSwRaster.cpp @@ -69,7 +69,7 @@ static bool _rasterSolidRle(Surface& surface, SwRleData* rle, uint32_t color) } -static bool _rasterGradientRle(Surface& surface, SwRleData* rle, const SwFill* fill) +static bool _rasterLinearGradientRle(Surface& surface, SwRleData* rle, const SwFill* fill) { if (!rle || !fill) return false; @@ -81,17 +81,16 @@ static bool _rasterGradientRle(Surface& surface, SwRleData* rle, const SwFill* f //Translucent Gradient if (fill->translucent) { - uint32_t tmp; for (uint32_t i = 0; i < rle->size; ++i) { auto dst = &surface.buffer[span->y * stride + span->x]; - fillFetch(fill, buf, span->y, span->x, span->len); + fillFetchLinear(fill, buf, span->y, span->x, span->len); if (span->coverage == 255) { for (uint32_t i = 0; i < span->len; ++i) { dst[i] = buf[i] + COLOR_ALPHA_BLEND(dst[i], 255 - COLOR_ALPHA(buf[i])); } } else { for (uint32_t i = 0; i < span->len; ++i) { - tmp = COLOR_ALPHA_BLEND(buf[i], span->coverage); + auto tmp = COLOR_ALPHA_BLEND(buf[i], span->coverage); dst[i] = tmp + COLOR_ALPHA_BLEND(dst[i], 255 - COLOR_ALPHA(tmp)); } } @@ -102,9 +101,56 @@ static bool _rasterGradientRle(Surface& surface, SwRleData* rle, const SwFill* f for (uint32_t i = 0; i < rle->size; ++i) { auto dst = &surface.buffer[span->y * stride + span->x]; if (span->coverage == 255) { - fillFetch(fill, dst, span->y, span->x, span->len); + fillFetchLinear(fill, dst, span->y, span->x, span->len); } else { - fillFetch(fill, buf, span->y, span->x, span->len); + fillFetchLinear(fill, buf, span->y, span->x, span->len); + auto ialpha = 255 - span->coverage; + for (uint32_t i = 0; i < span->len; ++i) { + dst[i] = COLOR_ALPHA_BLEND(buf[i], span->coverage) + COLOR_ALPHA_BLEND(dst[i], ialpha); + } + } + ++span; + } + } + return true; +} + + +static bool _rasterRadialGradientRle(Surface& surface, SwRleData* rle, const SwFill* fill) +{ + if (!rle || !fill) return false; + + auto buf = static_cast(alloca(surface.w * sizeof(uint32_t))); + if (!buf) return false; + + auto span = rle->spans; + auto stride = surface.stride; + + //Translucent Gradient + if (fill->translucent) { + for (uint32_t i = 0; i < rle->size; ++i) { + auto dst = &surface.buffer[span->y * stride + span->x]; + fillFetchRadial(fill, buf, span->y, span->x, span->len); + if (span->coverage == 255) { + for (uint32_t i = 0; i < span->len; ++i) { + dst[i] = buf[i] + COLOR_ALPHA_BLEND(dst[i], 255 - COLOR_ALPHA(buf[i])); + } + } else { + for (uint32_t i = 0; i < span->len; ++i) { + auto tmp = COLOR_ALPHA_BLEND(buf[i], span->coverage); + dst[i] = tmp + COLOR_ALPHA_BLEND(dst[i], 255 - COLOR_ALPHA(tmp)); + } + } + ++span; + } + //Opaque Gradient + } else { + for (uint32_t i = 0; i < rle->size; ++i) { + auto dst = &surface.buffer[span->y * stride + span->x]; + if (span->coverage == 255) { + fillFetchRadial(fill, dst, span->y, span->x, span->len); + } else { + fillFetchRadial(fill, buf, span->y, span->x, span->len); auto ialpha = 255 - span->coverage; for (uint32_t i = 0; i < span->len; ++i) { dst[i] = COLOR_ALPHA_BLEND(buf[i], span->coverage) + COLOR_ALPHA_BLEND(dst[i], ialpha); @@ -121,9 +167,10 @@ static bool _rasterGradientRle(Surface& surface, SwRleData* rle, const SwFill* f /* External Class Implementation */ /************************************************************************/ -bool rasterGradientShape(Surface& surface, SwShape& shape) +bool rasterGradientShape(Surface& surface, SwShape& shape, unsigned id) { - return _rasterGradientRle(surface, shape.rle, shape.fill); + if (id == FILL_ID_LINEAR) return _rasterLinearGradientRle(surface, shape.rle, shape.fill); + return _rasterRadialGradientRle(surface, shape.rle, shape.fill); } diff --git a/src/lib/sw_engine/tvgSwRenderer.cpp b/src/lib/sw_engine/tvgSwRenderer.cpp index e99bf38..35a3122 100644 --- a/src/lib/sw_engine/tvgSwRenderer.cpp +++ b/src/lib/sw_engine/tvgSwRenderer.cpp @@ -64,8 +64,8 @@ bool SwRenderer::render(const Shape& sdata, void *data) uint8_t r, g, b, a; - if (sdata.fill()) { - rasterGradientShape(surface, *shape); + if (auto fill = sdata.fill()) { + rasterGradientShape(surface, *shape, fill->id()); } else { sdata.fill(&r, &g, &b, &a); if (a > 0) rasterSolidShape(surface, *shape, r, g, b, a); diff --git a/test/makefile b/test/makefile index 353d7b8..b041e6d 100644 --- a/test/makefile +++ b/test/makefile @@ -13,3 +13,4 @@ all: gcc -o testStroke testStroke.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` gcc -o testStrokeLine testStrokeLine.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` gcc -o testLinearGradient testLinearGradient.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` + gcc -o testRadialGradient testRadialGradient.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` diff --git a/test/testRadialGradient.cpp b/test/testRadialGradient.cpp new file mode 100644 index 0000000..e3e7e6e --- /dev/null +++ b/test/testRadialGradient.cpp @@ -0,0 +1,115 @@ +#include +#include + +using namespace std; + +#define WIDTH 800 +#define HEIGHT 800 + +static uint32_t buffer[WIDTH * HEIGHT]; + +void tvgtest() +{ + //Initialize TizenVG Engine + tvg::Engine::init(); + + //Create a Canvas + auto canvas = tvg::SwCanvas::gen(); + canvas->target(buffer, WIDTH, WIDTH, HEIGHT); + canvas->reserve(3); //reserve 3 shape nodes (optional) + + //Prepare Round Rectangle + auto shape1 = tvg::Shape::gen(); + shape1->appendRect(0, 0, 400, 400, 0); //x, y, w, h, cornerRadius + + //RadialGradient + auto fill = tvg::RadialGradient::gen(); + fill->radial(200, 200, 200); + + //Linear Gradient Color Stops + tvg::Fill::ColorStop colorStops[2]; + colorStops[0] = {0, 255, 255, 255, 255}; + colorStops[1] = {1, 0, 0, 0, 255}; + + fill->colorStops(colorStops, 2); + + shape1->fill(move(fill)); + canvas->push(move(shape1)); + + //Prepare Circle + auto shape2 = tvg::Shape::gen(); + shape2->appendCircle(400, 400, 200, 200); //cx, cy, radiusW, radiusH + + //RadialGradient + auto fill2 = tvg::RadialGradient::gen(); + fill2->radial(400, 400, 200); + + //Linear Gradient Color Stops + tvg::Fill::ColorStop colorStops2[3]; + colorStops2[0] = {0, 255, 0, 0, 255}; + colorStops2[1] = {0.5, 255, 255, 0, 255}; + colorStops2[2] = {1, 255, 255, 255, 255}; + + fill2->colorStops(colorStops2, 3); + + shape2->fill(move(fill2)); + canvas->push(move(shape2)); + + + //Prepare Ellipse + auto shape3 = tvg::Shape::gen(); + shape3->appendCircle(600, 600, 150, 100); //cx, cy, radiusW, radiusH + + //RadialGradient + auto fill3 = tvg::RadialGradient::gen(); + fill3->radial(600, 600, 150); + + //Linear Gradient Color Stops + tvg::Fill::ColorStop colorStops3[4]; + colorStops3[0] = {0, 0, 127, 0, 127}; + colorStops3[1] = {0.25, 0, 170, 170, 170}; + colorStops3[2] = {0.5, 200, 0, 200, 200}; + colorStops3[3] = {1, 255, 255, 255, 255}; + + fill3->colorStops(colorStops3, 4); + + shape3->fill(move(fill3)); + canvas->push(move(shape3)); + + //Draw the Shapes onto the Canvas + canvas->draw(); + canvas->sync(); + + //Terminate TizenVG Engine + tvg::Engine::term(); +} + +void +win_del(void *data, Evas_Object *o, void *ev) +{ + elm_exit(); +} + +int main(int argc, char **argv) +{ + tvgtest(); + + //Show the result using EFL... + elm_init(argc, argv); + + Eo* win = elm_win_util_standard_add(NULL, "TizenVG Test"); + evas_object_smart_callback_add(win, "delete,request", win_del, 0); + + Eo* img = evas_object_image_filled_add(evas_object_evas_get(win)); + evas_object_image_size_set(img, WIDTH, HEIGHT); + evas_object_image_data_set(img, buffer); + evas_object_size_hint_weight_set(img, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_show(img); + + elm_win_resize_object_add(win, img); + evas_object_geometry_set(win, 0, 0, WIDTH, HEIGHT); + evas_object_show(win); + + elm_run(); + elm_shutdown(); +} -- 2.7.4 From 81de016492014538c58e1ef3a6d57136a71e12d5 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Mon, 15 Jun 2020 18:10:24 +0900 Subject: [PATCH 04/16] test: updated trivial comments. Change-Id: If44643d51d9acd3e3042118e39ca3e8f07c148da --- test/testLinearGradient.cpp | 6 +++--- test/testRadialGradient.cpp | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/test/testLinearGradient.cpp b/test/testLinearGradient.cpp index 33536c4..08cdb66 100644 --- a/test/testLinearGradient.cpp +++ b/test/testLinearGradient.cpp @@ -26,7 +26,7 @@ void tvgtest() auto fill = tvg::LinearGradient::gen(); fill->linear(0, 0, 400, 400); - //Linear Gradient Color Stops + //Gradient Color Stops tvg::Fill::ColorStop colorStops[2]; colorStops[0] = {0, 0, 0, 0, 255}; colorStops[1] = {1, 255, 255, 255, 255}; @@ -44,7 +44,7 @@ void tvgtest() auto fill2 = tvg::LinearGradient::gen(); fill2->linear(400, 200, 400, 600); - //Linear Gradient Color Stops + //Gradient Color Stops tvg::Fill::ColorStop colorStops2[3]; colorStops2[0] = {0, 255, 0, 0, 255}; colorStops2[1] = {0.5, 255, 255, 0, 255}; @@ -64,7 +64,7 @@ void tvgtest() auto fill3 = tvg::LinearGradient::gen(); fill3->linear(450, 600, 750, 600); - //Linear Gradient Color Stops + //Gradient Color Stops tvg::Fill::ColorStop colorStops3[4]; colorStops3[0] = {0, 0, 127, 0, 127}; colorStops3[1] = {0.25, 0, 170, 170, 170}; diff --git a/test/testRadialGradient.cpp b/test/testRadialGradient.cpp index e3e7e6e..f9ed87d 100644 --- a/test/testRadialGradient.cpp +++ b/test/testRadialGradient.cpp @@ -26,7 +26,7 @@ void tvgtest() auto fill = tvg::RadialGradient::gen(); fill->radial(200, 200, 200); - //Linear Gradient Color Stops + //Gradient Color Stops tvg::Fill::ColorStop colorStops[2]; colorStops[0] = {0, 255, 255, 255, 255}; colorStops[1] = {1, 0, 0, 0, 255}; @@ -44,7 +44,7 @@ void tvgtest() auto fill2 = tvg::RadialGradient::gen(); fill2->radial(400, 400, 200); - //Linear Gradient Color Stops + //Gradient Color Stops tvg::Fill::ColorStop colorStops2[3]; colorStops2[0] = {0, 255, 0, 0, 255}; colorStops2[1] = {0.5, 255, 255, 0, 255}; @@ -64,7 +64,7 @@ void tvgtest() auto fill3 = tvg::RadialGradient::gen(); fill3->radial(600, 600, 150); - //Linear Gradient Color Stops + //Gradient Color Stops tvg::Fill::ColorStop colorStops3[4]; colorStops3[0] = {0, 0, 127, 0, 127}; colorStops3[1] = {0.25, 0, 170, 170, 170}; -- 2.7.4 From 7435b5b414f2dd2f098bf8998cc9fa88c738e6d7 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Mon, 15 Jun 2020 19:54:52 +0900 Subject: [PATCH 05/16] sw_engine: support gradient transformation properly added testGradientTransform Change-Id: I29037d08ce951e5ceb2eef31cb414efc25296417 --- .gitignore | 1 + src/lib/sw_engine/tvgSwCommon.h | 4 +- src/lib/sw_engine/tvgSwFill.cpp | 39 +++++++-- src/lib/sw_engine/tvgSwRenderer.cpp | 7 +- src/lib/sw_engine/tvgSwShape.cpp | 10 +-- test/makefile | 1 + test/testGradientTransform.cpp | 170 ++++++++++++++++++++++++++++++++++++ 7 files changed, 215 insertions(+), 17 deletions(-) create mode 100644 test/testGradientTransform.cpp diff --git a/.gitignore b/.gitignore index f108357..bc11501 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,4 @@ testStroke testStrokeLine testLinearGradient testRadialGradient +testGradientTransform diff --git a/src/lib/sw_engine/tvgSwCommon.h b/src/lib/sw_engine/tvgSwCommon.h index 21a1705..eedaf9d 100644 --- a/src/lib/sw_engine/tvgSwCommon.h +++ b/src/lib/sw_engine/tvgSwCommon.h @@ -252,7 +252,7 @@ void shapeResetStroke(SwShape& shape, const Shape& sdata); bool shapeGenStrokeRle(SwShape& shape, const Shape& sdata, const SwSize& clip); void shapeFree(SwShape* shape); void shapeDelStroke(SwShape& shape); -bool shapeGenFillColors(SwShape& shape, const Fill* fill); +bool shapeGenFillColors(SwShape& shape, const Fill* fill, const RenderTransform* transform, bool ctable); void shapeResetFill(SwShape& shape, const Fill* fill); void shapeDelFill(SwShape& shape); @@ -261,7 +261,7 @@ bool strokeParseOutline(SwStroke& stroke, const SwOutline& outline); SwOutline* strokeExportOutline(SwStroke& stroke); void strokeFree(SwStroke* stroke); -bool fillGenColorTable(SwFill* fill, const Fill* fdata); +bool fillGenColorTable(SwFill* fill, const Fill* fdata, const RenderTransform* transform, bool ctable); void fillReset(SwFill* fill, const Fill* fdata); void fillFree(SwFill* fill); void fillFetchLinear(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len); diff --git a/src/lib/sw_engine/tvgSwFill.cpp b/src/lib/sw_engine/tvgSwFill.cpp index 1fcafa3..f609183 100644 --- a/src/lib/sw_engine/tvgSwFill.cpp +++ b/src/lib/sw_engine/tvgSwFill.cpp @@ -88,13 +88,26 @@ static bool _updateColorTable(SwFill* fill, const Fill* fdata) } -bool _prepareLinear(SwFill* fill, const LinearGradient* linear) +bool _prepareLinear(SwFill* fill, const LinearGradient* linear, const RenderTransform* transform) { assert(fill && linear); float x1, x2, y1, y2; if (linear->linear(&x1, &y1, &x2, &y2) != Result::Success) return false; + if (transform) { + auto cx = (x2 - x1) * 0.5f + x1; + auto cy = (y2 - y1) * 0.5f + y1; + auto dx = x1 - cx; + auto dy = y1 - cy; + x1 = dx * transform->e11 + dy * transform->e12 + transform->e31; + y1 = dx * transform->e21 + dy * transform->e22 + transform->e32; + dx = x2 - cx; + dy = y2 - cy; + x2 = dx * transform->e11 + dy * transform->e12 + transform->e31; + y2 = dx * transform->e21 + dy * transform->e22 + transform->e32; + } + 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; @@ -105,11 +118,11 @@ bool _prepareLinear(SwFill* fill, const LinearGradient* linear) fill->linear.dy /= fill->linear.len; fill->linear.offset = -fill->linear.dx * x1 - fill->linear.dy * y1; - return _updateColorTable(fill, linear); + return true; } -bool _prepareRadial(SwFill* fill, const RadialGradient* radial) +bool _prepareRadial(SwFill* fill, const RadialGradient* radial, const RenderTransform* transform) { assert(fill && radial); @@ -117,10 +130,18 @@ bool _prepareRadial(SwFill* fill, const RadialGradient* radial) if (radial->radial(&fill->radial.cx, &fill->radial.cy, &radius) != Result::Success) return false; if (radius < FLT_EPSILON) return true; + if (transform) { + auto tx = fill->radial.cx * transform->e11 + fill->radial.cy * transform->e12 + transform->e31; + auto ty = fill->radial.cx * transform->e21 + fill->radial.cy * transform->e22 + transform->e32; + fill->radial.cx = tx; + fill->radial.cy = ty; + radius *= transform->e33; + } + fill->radial.a = radius * radius; fill->radial.inv2a = pow(1 / (2 * fill->radial.a), 2); - return _updateColorTable(fill, radial); + return true; } @@ -251,7 +272,7 @@ void fillFetchLinear(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, } -bool fillGenColorTable(SwFill* fill, const Fill* fdata) +bool fillGenColorTable(SwFill* fill, const Fill* fdata, const RenderTransform* transform, bool ctable) { if (!fill) return false; @@ -259,10 +280,14 @@ bool fillGenColorTable(SwFill* fill, const Fill* fdata) fill->spread = fdata->spread(); + if (ctable) { + if (!_updateColorTable(fill, fdata)) return false; + } + if (fdata->id() == FILL_ID_LINEAR) { - return _prepareLinear(fill, static_cast(fdata)); + return _prepareLinear(fill, static_cast(fdata), transform); } else if (fdata->id() == FILL_ID_RADIAL) { - return _prepareRadial(fill, static_cast(fdata)); + return _prepareRadial(fill, static_cast(fdata), transform); } cout << "What type of gradient?!" << endl; diff --git a/src/lib/sw_engine/tvgSwRenderer.cpp b/src/lib/sw_engine/tvgSwRenderer.cpp index 35a3122..1246eab 100644 --- a/src/lib/sw_engine/tvgSwRenderer.cpp +++ b/src/lib/sw_engine/tvgSwRenderer.cpp @@ -113,11 +113,12 @@ void* SwRenderer::prepare(const Shape& sdata, void* data, const RenderTransform* } //Fill - if (flags & (RenderUpdateFlag::Gradient)) { + if (flags & (RenderUpdateFlag::Gradient | RenderUpdateFlag::Transform)) { auto fill = sdata.fill(); if (fill) { - shapeResetFill(*shape, fill); - if (!shapeGenFillColors(*shape, fill)) return shape; + auto ctable = (flags & RenderUpdateFlag::Gradient) ? true : false; + if (ctable) shapeResetFill(*shape, fill); + if (!shapeGenFillColors(*shape, fill, transform, ctable)) return shape; } else { shapeDelFill(*shape); } diff --git a/src/lib/sw_engine/tvgSwShape.cpp b/src/lib/sw_engine/tvgSwShape.cpp index 4dcf210..4d3c44e 100644 --- a/src/lib/sw_engine/tvgSwShape.cpp +++ b/src/lib/sw_engine/tvgSwShape.cpp @@ -347,9 +347,9 @@ static void _transformOutline(SwOutline* outline, const RenderTransform* transfo for(uint32_t i = 0; i < outline->ptsCnt; ++i) { auto dx = static_cast(outline->pts[i].x >> 6); auto dy = static_cast(outline->pts[i].y >> 6); - auto tx = dx * transform->e11 + dy * transform->e12 + transform->e13; - auto ty = dx * transform->e21 + dy * transform->e22 + transform->e23; - auto pt = Point{tx + transform->e31, ty + transform->e32}; + auto tx = dx * transform->e11 + dy * transform->e12 + transform->e31; + auto ty = dx * transform->e21 + dy * transform->e22 + transform->e32; + auto pt = Point{tx, ty}; outline->pts[i] = TO_SWPOINT(&pt); } } @@ -740,11 +740,11 @@ bool shapeGenStrokeRle(SwShape& shape, const Shape& sdata, const SwSize& clip) } -bool shapeGenFillColors(SwShape& shape, const Fill* fill) +bool shapeGenFillColors(SwShape& shape, const Fill* fill, const RenderTransform* transform, bool ctable) { assert(fill); - fillGenColorTable(shape.fill, fill); + fillGenColorTable(shape.fill, fill, transform, ctable); return true; } diff --git a/test/makefile b/test/makefile index b041e6d..431fa66 100644 --- a/test/makefile +++ b/test/makefile @@ -14,3 +14,4 @@ all: gcc -o testStrokeLine testStrokeLine.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` gcc -o testLinearGradient testLinearGradient.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` gcc -o testRadialGradient testRadialGradient.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` + gcc -o testGradientTransform testGradientTransform.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` diff --git a/test/testGradientTransform.cpp b/test/testGradientTransform.cpp new file mode 100644 index 0000000..0b4b677 --- /dev/null +++ b/test/testGradientTransform.cpp @@ -0,0 +1,170 @@ +#include +#include + +using namespace std; + +#define WIDTH 800 +#define HEIGHT 800 + +static uint32_t buffer[WIDTH * HEIGHT]; +unique_ptr canvas = nullptr; +tvg::Shape* pShape = nullptr; +tvg::Shape* pShape2 = nullptr; +tvg::Shape* pShape3 = nullptr; + +void tvgtest() +{ + //Create a Canvas + canvas = tvg::SwCanvas::gen(); + canvas->target(buffer, WIDTH, WIDTH, HEIGHT); + + //Shape1 + auto shape = tvg::Shape::gen(); + + /* Acquire shape pointer to access it again. + instead, you should consider not to interrupt this pointer life-cycle. */ + pShape = shape.get(); + + shape->appendRect(-285, -300, 200, 200, 0); + shape->appendRect(-185, -200, 300, 300, 100); + shape->appendCircle(115, 100, 100, 100); + shape->appendCircle(115, 200, 170, 100); + + //LinearGradient + auto fill = tvg::LinearGradient::gen(); + fill->linear(-285, -300, 285, 300); + + //Gradient Color Stops + tvg::Fill::ColorStop colorStops[3]; + colorStops[0] = {0, 255, 0, 0, 255}; + colorStops[1] = {0.5, 255, 255, 0, 255}; + colorStops[2] = {1, 255, 255, 255, 255}; + + fill->colorStops(colorStops, 3); + shape->fill(move(fill)); + shape->translate(385, 400); + canvas->push(move(shape)); + + //Shape2 + auto shape2 = tvg::Shape::gen(); + pShape2 = shape2.get(); + shape2->appendRect(-50, -50, 100, 100, 0); + shape2->translate(400, 400); + + //LinearGradient + auto fill2 = tvg::LinearGradient::gen(); + fill2->linear(-50, -50, 50, 50); + + //Gradient Color Stops + tvg::Fill::ColorStop colorStops2[2]; + colorStops2[0] = {0, 0, 0, 0, 255}; + colorStops2[1] = {1, 255, 255, 255, 255}; + + fill2->colorStops(colorStops2, 2); + shape2->fill(move(fill2)); + canvas->push(move(shape2)); + + //Shape3 + auto shape3 = tvg::Shape::gen(); + pShape3 = shape3.get(); + + /* Look, how shape3's origin is different with shape2 + The center of the shape is the anchor point for transformation. */ + shape3->appendRect(100, 100, 150, 100, 20); + + //RadialGradient + auto fill3 = tvg::RadialGradient::gen(); + fill3->radial(175, 150, 75); + + //Gradient Color Stops + tvg::Fill::ColorStop colorStops3[4]; + colorStops3[0] = {0, 0, 127, 0, 127}; + colorStops3[1] = {0.25, 0, 170, 170, 170}; + colorStops3[2] = {0.5, 200, 0, 200, 200}; + colorStops3[3] = {1, 255, 255, 255, 255}; + + fill3->colorStops(colorStops3, 4); + + shape3->fill(move(fill3)); + shape3->translate(400, 400); + canvas->push(move(shape3)); + + //Draw first frame + canvas->draw(); + canvas->sync(); +} + +void transit_cb(Elm_Transit_Effect *effect, Elm_Transit* transit, double progress) +{ + /* Update shape directly. + You can update only necessary properties of this shape, + while retaining other properties. */ + + //Update Shape1 + pShape->scale(1 - 0.75 * progress); + pShape->rotate(360 * progress); + + //Update shape for drawing (this may work asynchronously) + canvas->update(pShape); + + //Update Shape2 + pShape2->rotate(360 * progress); + pShape2->translate(400 + progress * 300, 400); + canvas->update(pShape2); + + //Update Shape3 + pShape3->rotate(-360 * progress); + pShape3->scale(0.5 + progress); + canvas->update(pShape3); + + //Draw Next frames + canvas->draw(); + canvas->sync(); + + //Update Efl Canvas + Eo* img = (Eo*) effect; + evas_object_image_data_update_add(img, 0, 0, WIDTH, HEIGHT); +} + +void +win_del(void *data, Evas_Object *o, void *ev) +{ + elm_exit(); +} + +int main(int argc, char **argv) +{ + //Initialize TizenVG Engine + tvg::Engine::init(); + + tvgtest(); + + //Show the result using EFL... + elm_init(argc, argv); + + Eo* win = elm_win_util_standard_add(NULL, "TizenVG Test"); + evas_object_smart_callback_add(win, "delete,request", win_del, 0); + + Eo* img = evas_object_image_filled_add(evas_object_evas_get(win)); + evas_object_image_size_set(img, WIDTH, HEIGHT); + evas_object_image_data_set(img, buffer); + evas_object_size_hint_weight_set(img, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_show(img); + + elm_win_resize_object_add(win, img); + evas_object_geometry_set(win, 0, 0, WIDTH, HEIGHT); + evas_object_show(win); + + Elm_Transit *transit = elm_transit_add(); + elm_transit_effect_add(transit, transit_cb, img, nullptr); + elm_transit_duration_set(transit, 2); + elm_transit_repeat_times_set(transit, -1); + elm_transit_auto_reverse_set(transit, EINA_TRUE); + elm_transit_go(transit); + + elm_run(); + elm_shutdown(); + + //Terminate TizenVG Engine + tvg::Engine::term(); +} -- 2.7.4 From fb208defedd896619b5ab1781a33311c9ef58656 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Mon, 15 Jun 2020 20:55:55 +0900 Subject: [PATCH 06/16] common engine: manage engine initializing context. Change-Id: Ida3997fd7cc9ee0916d48290168cdb884e946833 --- src/lib/tvgEngine.cpp | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/lib/tvgEngine.cpp b/src/lib/tvgEngine.cpp index 40b1308..5038cb8 100644 --- a/src/lib/tvgEngine.cpp +++ b/src/lib/tvgEngine.cpp @@ -24,6 +24,8 @@ /************************************************************************/ /* Internal Class Implementation */ /************************************************************************/ +static bool initialized = false; + /************************************************************************/ @@ -32,11 +34,13 @@ Result Engine::init() noexcept { + if (initialized) return Result::InsufficientCondition; + //TODO: Initialize Raster engines by configuration. + SwRenderer::init(); + GlRenderer::init(); - int ret = 0; - ret |= SwRenderer::init(); - ret |= GlRenderer::init(); + initialized = true; return Result::Success; } @@ -44,9 +48,13 @@ Result Engine::init() noexcept Result Engine::term() noexcept { - int ret = 0; - ret |= SwRenderer::term(); - ret |= GlRenderer::term(); + if (!initialized) return Result::InsufficientCondition; + + //TODO: Terminate only allowed engines. + SwRenderer::term(); + GlRenderer::term(); + + initialized = false; return Result::Success; } -- 2.7.4 From f62767988247f3a61948b72a1679e3bc5044ec58 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Mon, 15 Jun 2020 21:01:46 +0900 Subject: [PATCH 07/16] common initializer: replace engine class with intializer This initializer will take over the global environments of tvg engines. Change-Id: I7b99973dafaea57ddd3134800bd442ef4dc319ae --- inc/tizenvg.h | 67 ++++++++++++++------------- src/lib/meson.build | 2 +- src/lib/{tvgEngine.cpp => tvgInitializer.cpp} | 43 +++++++++-------- src/lib/tvgRenderCommon.h | 14 +++--- test/testBlending.cpp | 4 +- test/testBoundary.cpp | 4 +- test/testComposition.cpp | 4 +- test/testDirectUpdate.cpp | 4 +- test/testGradient.cpp | 4 +- test/testGradientTransform.cpp | 4 +- test/testLinearGradient.cpp | 4 +- test/testMultiShapes.cpp | 4 +- test/testPath.cpp | 4 +- test/testPathCopy.cpp | 4 +- test/testRadialGradient.cpp | 4 +- test/testScene.cpp | 4 +- test/testSceneTransform.cpp | 4 +- test/testShape.cpp | 4 +- test/testStroke.cpp | 4 +- test/testStrokeLine.cpp | 4 +- test/testTransform.cpp | 4 +- test/testUpdate.cpp | 4 +- 22 files changed, 102 insertions(+), 96 deletions(-) rename src/lib/{tvgEngine.cpp => tvgInitializer.cpp} (58%) diff --git a/inc/tizenvg.h b/inc/tizenvg.h index 044cdfe..abb08d6 100644 --- a/inc/tizenvg.h +++ b/inc/tizenvg.h @@ -69,7 +69,7 @@ enum class TVG_EXPORT PathCommand { Close = 0, MoveTo, LineTo, CubicTo }; enum class TVG_EXPORT StrokeCap { Square = 0, Round, Butt }; enum class TVG_EXPORT StrokeJoin { Bevel = 0, Round, Miter }; enum class TVG_EXPORT FillSpread { Pad = 0, Reflect, Repeat }; - +enum class TVG_EXPORT CanvasEngine { Sw = 0, Gl }; struct Point { @@ -131,6 +131,34 @@ public: /** + * @class Canvas + * + * @ingroup TizenVG + * + * @brief description... + * + */ +class TVG_EXPORT Canvas +{ +public: + Canvas(RenderMethod*); + virtual ~Canvas(); + + Result reserve(uint32_t n) noexcept; + virtual Result push(std::unique_ptr paint) noexcept; + virtual Result clear() noexcept; + virtual Result update() noexcept; + virtual Result update(Paint* paint) noexcept; + virtual Result draw(bool async = true) noexcept; + virtual Result sync() = 0; + + _TVG_DECLARE_ACCESSOR(Scene); + _TVG_DECLARE_PRIVATE(Canvas); +}; + + + +/** * @class LinearGradient * * @ingroup TizenVG @@ -174,32 +202,6 @@ public: }; -/** - * @class Canvas - * - * @ingroup TizenVG - * - * @brief description... - * - */ -class TVG_EXPORT Canvas -{ -public: - Canvas(RenderMethod*); - virtual ~Canvas(); - - Result reserve(uint32_t n) noexcept; - virtual Result push(std::unique_ptr paint) noexcept; - virtual Result clear() noexcept; - virtual Result update() noexcept; - virtual Result update(Paint* paint) noexcept; - virtual Result draw(bool async = true) noexcept; - virtual Result sync() = 0; - - _TVG_DECLARE_ACCESSOR(Scene); - _TVG_DECLARE_PRIVATE(Canvas); -}; - /** * @class Shape @@ -277,7 +279,7 @@ class TVG_EXPORT Scene final : public Paint public: ~Scene(); - Result push(std::unique_ptr shape) noexcept; + Result push(std::unique_ptr paint) noexcept; Result reserve(uint32_t size) noexcept; Result rotate(float degree) noexcept override; @@ -347,9 +349,10 @@ public: * @brief description... * */ -class TVG_EXPORT Engine final +class TVG_EXPORT Initializer final { public: + /** * @brief ... * @@ -361,10 +364,10 @@ public: * * @see ... */ - static Result init() noexcept; - static Result term() noexcept; + static Result init(CanvasEngine engine) noexcept; + static Result term(CanvasEngine engine) noexcept; - _TVG_DISABLE_CTOR(Engine); + _TVG_DISABLE_CTOR(Initializer); }; } //namespace diff --git a/src/lib/meson.build b/src/lib/meson.build index 5aba9bb..c936501 100644 --- a/src/lib/meson.build +++ b/src/lib/meson.build @@ -9,9 +9,9 @@ source_file = [ 'tvgShapePath.h', 'tvgShapeImpl.h', 'tvgCanvas.cpp', - 'tvgEngine.cpp', 'tvgFill.cpp', 'tvgGlCanvas.cpp', + 'tvgInitializer.cpp', 'tvgLinearGradient.cpp', 'tvgRadialGradient.cpp', 'tvgScene.cpp', diff --git a/src/lib/tvgEngine.cpp b/src/lib/tvgInitializer.cpp similarity index 58% rename from src/lib/tvgEngine.cpp rename to src/lib/tvgInitializer.cpp index 5038cb8..ac6ce3a 100644 --- a/src/lib/tvgEngine.cpp +++ b/src/lib/tvgInitializer.cpp @@ -14,8 +14,8 @@ * limitations under the License. * */ -#ifndef _TVG_ENGINE_CPP_ -#define _TVG_ENGINE_CPP_ +#ifndef _TVG_INITIALIZER_CPP_ +#define _TVG_INITIALIZER_CPP_ #include "tvgCommon.h" #include "tvgSwRenderer.h" @@ -24,39 +24,42 @@ /************************************************************************/ /* Internal Class Implementation */ /************************************************************************/ -static bool initialized = false; - - /************************************************************************/ /* External Class Implementation */ /************************************************************************/ -Result Engine::init() noexcept +Result Initializer::init(CanvasEngine engine) noexcept { - if (initialized) return Result::InsufficientCondition; + if (engine == CanvasEngine::Sw) { + if (!SwRenderer::init()) return Result::InsufficientCondition; + } else if (engine == CanvasEngine::Gl) { + if (!GlRenderer::init()) return Result::InsufficientCondition; + } else { + return Result::InvalidArguments; + } - //TODO: Initialize Raster engines by configuration. - SwRenderer::init(); - GlRenderer::init(); - - initialized = true; + //TODO: check modules then enable them + //1. TVG + //2. SVG return Result::Success; } -Result Engine::term() noexcept +Result Initializer::term(CanvasEngine engine) noexcept { - if (!initialized) return Result::InsufficientCondition; - - //TODO: Terminate only allowed engines. - SwRenderer::term(); - GlRenderer::term(); + //TODO: deinitialize modules - initialized = false; + if (engine == CanvasEngine::Sw) { + if (!SwRenderer::term()) return Result::InsufficientCondition; + } else if (engine == CanvasEngine::Gl) { + if (!GlRenderer::term()) return Result::InsufficientCondition; + } else { + return Result::InvalidArguments; + } return Result::Success; } -#endif /* _TVG_ENGINE_CPP_ */ +#endif /* _TVG_INITIALIZER_CPP_ */ diff --git a/src/lib/tvgRenderCommon.h b/src/lib/tvgRenderCommon.h index f89d949..a581067 100644 --- a/src/lib/tvgRenderCommon.h +++ b/src/lib/tvgRenderCommon.h @@ -136,28 +136,28 @@ struct RenderInitializer uint32_t refCnt = 0; bool initialized = false; - static int init(RenderInitializer& renderInit, RenderMethod* engine) + static bool init(RenderInitializer& renderInit, RenderMethod* engine) { assert(engine); - if (renderInit.pInst || renderInit.refCnt > 0) return -1; + if (renderInit.pInst || renderInit.refCnt > 0) return false; renderInit.pInst = engine; renderInit.refCnt = 0; renderInit.initialized = true; - return 0; + return true; } - static int term(RenderInitializer& renderInit) + static bool term(RenderInitializer& renderInit) { - if (!renderInit.pInst || !renderInit.initialized) return -1; + if (!renderInit.pInst || !renderInit.initialized) return false; renderInit.initialized = false; //Still it's refered.... - if (renderInit.refCnt > 0) return 0; + if (renderInit.refCnt > 0) return true; delete(renderInit.pInst); renderInit.pInst = nullptr; - return 0; + return true; } static uint32_t unref(RenderInitializer& renderInit) diff --git a/test/testBlending.cpp b/test/testBlending.cpp index 58ae025..a5559d4 100644 --- a/test/testBlending.cpp +++ b/test/testBlending.cpp @@ -11,7 +11,7 @@ static uint32_t buffer[WIDTH * HEIGHT]; void tvgtest() { //Initialize TizenVG Engine - tvg::Engine::init(); + tvg::Initializer::init(tvg::CanvasEngine::Sw); //Create a Canvas auto canvas = tvg::SwCanvas::gen(); @@ -63,7 +63,7 @@ void tvgtest() canvas->sync(); //Terminate TizenVG Engine - tvg::Engine::term(); + tvg::Initializer::term(tvg::CanvasEngine::Sw); } void diff --git a/test/testBoundary.cpp b/test/testBoundary.cpp index c5d39f6..701bb84 100644 --- a/test/testBoundary.cpp +++ b/test/testBoundary.cpp @@ -11,7 +11,7 @@ static uint32_t buffer[WIDTH * HEIGHT]; void tvgtest() { //Initialize TizenVG Engine - tvg::Engine::init(); + tvg::Initializer::init(tvg::CanvasEngine::Sw); //Create a Canvas auto canvas = tvg::SwCanvas::gen(); @@ -53,7 +53,7 @@ void tvgtest() canvas->sync(); //Terminate TizenVG Engine - tvg::Engine::term(); + tvg::Initializer::term(tvg::CanvasEngine::Sw); } void diff --git a/test/testComposition.cpp b/test/testComposition.cpp index 57a8e43..d8ca979 100644 --- a/test/testComposition.cpp +++ b/test/testComposition.cpp @@ -10,7 +10,7 @@ static uint32_t buffer[WIDTH * HEIGHT]; int main(int argc, char **argv) { //Initialize TizenVG Engine - tvg::Engine::init(); + tvg::Initializer::init(tvg::CanvasEngine::Sw); //Create a Composition Source Canvas auto canvas1 = tvg::SwCanvas::gen(buffer, WIDTH, HEIGHT); @@ -31,5 +31,5 @@ int main(int argc, char **argv) canvas2->sync(); //Terminate TizenVG Engine - tvg::Engine::term(); + tvg::Initializer::term(tvg::CanvasEngine::Sw); } diff --git a/test/testDirectUpdate.cpp b/test/testDirectUpdate.cpp index e1a4c60..eb3a9dc 100644 --- a/test/testDirectUpdate.cpp +++ b/test/testDirectUpdate.cpp @@ -69,7 +69,7 @@ win_del(void *data, Evas_Object *o, void *ev) int main(int argc, char **argv) { //Initialize TizenVG Engine - tvg::Engine::init(); + tvg::Initializer::init(tvg::CanvasEngine::Sw); tvgtest(); @@ -100,5 +100,5 @@ int main(int argc, char **argv) elm_shutdown(); //Terminate TizenVG Engine - tvg::Engine::term(); + tvg::Initializer::term(tvg::CanvasEngine::Sw); } diff --git a/test/testGradient.cpp b/test/testGradient.cpp index 6a7b6ba..cf33a1e 100644 --- a/test/testGradient.cpp +++ b/test/testGradient.cpp @@ -10,7 +10,7 @@ static uint32_t buffer[WIDTH * HEIGHT]; int main(int argc, char **argv) { //Initialize TizenVG Engine - tvg::Engine::init(); + tvg::Initializer::init(tvg::CanvasEngine::Sw); //Create a Canvas auto canvas = tvg::SwCanvas::gen(buffer, WIDTH, HEIGHT); @@ -48,5 +48,5 @@ int main(int argc, char **argv) canvas->sync(); //Terminate TizenVG Engine - tvg::Engine::term(); + tvg::Initializer::term(tvg::CanvasEngine::Sw); } diff --git a/test/testGradientTransform.cpp b/test/testGradientTransform.cpp index 0b4b677..90fab16 100644 --- a/test/testGradientTransform.cpp +++ b/test/testGradientTransform.cpp @@ -135,7 +135,7 @@ win_del(void *data, Evas_Object *o, void *ev) int main(int argc, char **argv) { //Initialize TizenVG Engine - tvg::Engine::init(); + tvg::Initializer::init(tvg::CanvasEngine::Sw); tvgtest(); @@ -166,5 +166,5 @@ int main(int argc, char **argv) elm_shutdown(); //Terminate TizenVG Engine - tvg::Engine::term(); + tvg::Initializer::term(tvg::CanvasEngine::Sw); } diff --git a/test/testLinearGradient.cpp b/test/testLinearGradient.cpp index 08cdb66..decf263 100644 --- a/test/testLinearGradient.cpp +++ b/test/testLinearGradient.cpp @@ -11,7 +11,7 @@ static uint32_t buffer[WIDTH * HEIGHT]; void tvgtest() { //Initialize TizenVG Engine - tvg::Engine::init(); + tvg::Initializer::init(tvg::CanvasEngine::Sw); //Create a Canvas auto canvas = tvg::SwCanvas::gen(); @@ -81,7 +81,7 @@ void tvgtest() canvas->sync(); //Terminate TizenVG Engine - tvg::Engine::term(); + tvg::Initializer::term(tvg::CanvasEngine::Sw); } void diff --git a/test/testMultiShapes.cpp b/test/testMultiShapes.cpp index 2539382..e6db3bb 100644 --- a/test/testMultiShapes.cpp +++ b/test/testMultiShapes.cpp @@ -11,7 +11,7 @@ static uint32_t buffer[WIDTH * HEIGHT]; void tvgtest() { //Initialize TizenVG Engine - tvg::Engine::init(); + tvg::Initializer::init(tvg::CanvasEngine::Sw); //Create a Canvas auto canvas = tvg::SwCanvas::gen(); @@ -41,7 +41,7 @@ void tvgtest() canvas->sync(); //Terminate TizenVG Engine - tvg::Engine::term(); + tvg::Initializer::term(tvg::CanvasEngine::Sw); } void diff --git a/test/testPath.cpp b/test/testPath.cpp index c2ca875..3d52003 100644 --- a/test/testPath.cpp +++ b/test/testPath.cpp @@ -11,7 +11,7 @@ static uint32_t buffer[WIDTH * HEIGHT]; void tvgtest() { //Initialize TizenVG Engine - tvg::Engine::init(); + tvg::Initializer::init(tvg::CanvasEngine::Sw); //Create a Canvas auto canvas = tvg::SwCanvas::gen(); @@ -56,7 +56,7 @@ void tvgtest() canvas->sync(); //Terminate TizenVG Engine - tvg::Engine::term(); + tvg::Initializer::term(tvg::CanvasEngine::Sw); } void diff --git a/test/testPathCopy.cpp b/test/testPathCopy.cpp index 28d19eb..8ce33c3 100644 --- a/test/testPathCopy.cpp +++ b/test/testPathCopy.cpp @@ -11,7 +11,7 @@ static uint32_t buffer[WIDTH * HEIGHT]; void tvgtest() { //Initialize TizenVG Engine - tvg::Engine::init(); + tvg::Initializer::init(tvg::CanvasEngine::Sw); //Create a Canvas auto canvas = tvg::SwCanvas::gen(); @@ -96,7 +96,7 @@ void tvgtest() canvas->sync(); //Terminate TizenVG Engine - tvg::Engine::term(); + tvg::Initializer::term(tvg::CanvasEngine::Sw); } void diff --git a/test/testRadialGradient.cpp b/test/testRadialGradient.cpp index f9ed87d..b50204b 100644 --- a/test/testRadialGradient.cpp +++ b/test/testRadialGradient.cpp @@ -11,7 +11,7 @@ static uint32_t buffer[WIDTH * HEIGHT]; void tvgtest() { //Initialize TizenVG Engine - tvg::Engine::init(); + tvg::Initializer::init(tvg::CanvasEngine::Sw); //Create a Canvas auto canvas = tvg::SwCanvas::gen(); @@ -81,7 +81,7 @@ void tvgtest() canvas->sync(); //Terminate TizenVG Engine - tvg::Engine::term(); + tvg::Initializer::term(tvg::CanvasEngine::Sw); } void diff --git a/test/testScene.cpp b/test/testScene.cpp index f7c9ea5..e134237 100644 --- a/test/testScene.cpp +++ b/test/testScene.cpp @@ -11,7 +11,7 @@ static uint32_t buffer[WIDTH * HEIGHT]; void tvgtest() { //Initialize TizenVG Engine - tvg::Engine::init(); + tvg::Initializer::init(tvg::CanvasEngine::Sw); //Create a Canvas auto canvas = tvg::SwCanvas::gen(); @@ -87,7 +87,7 @@ void tvgtest() canvas->sync(); //Terminate TizenVG Engine - tvg::Engine::term(); + tvg::Initializer::term(tvg::CanvasEngine::Sw); } void diff --git a/test/testSceneTransform.cpp b/test/testSceneTransform.cpp index 975f4fa..11dade0 100644 --- a/test/testSceneTransform.cpp +++ b/test/testSceneTransform.cpp @@ -129,7 +129,7 @@ win_del(void *data, Evas_Object *o, void *ev) int main(int argc, char **argv) { //Initialize TizenVG Engine - tvg::Engine::init(); + tvg::Initializer::init(tvg::CanvasEngine::Sw); tvgtest(); @@ -159,5 +159,5 @@ int main(int argc, char **argv) elm_shutdown(); //Terminate TizenVG Engine - tvg::Engine::term(); + tvg::Initializer::term(tvg::CanvasEngine::Sw); } diff --git a/test/testShape.cpp b/test/testShape.cpp index 8cff17d..16fc1a0 100644 --- a/test/testShape.cpp +++ b/test/testShape.cpp @@ -11,7 +11,7 @@ static uint32_t buffer[WIDTH * HEIGHT]; void tvgtest() { //Initialize TizenVG Engine - tvg::Engine::init(); + tvg::Initializer::init(tvg::CanvasEngine::Sw); //Create a Canvas auto canvas = tvg::SwCanvas::gen(); @@ -35,7 +35,7 @@ void tvgtest() canvas->sync(); //Terminate TizenVG Engine - tvg::Engine::term(); + tvg::Initializer::term(tvg::CanvasEngine::Sw); } void diff --git a/test/testStroke.cpp b/test/testStroke.cpp index b17c3a1..a7ae5d0 100644 --- a/test/testStroke.cpp +++ b/test/testStroke.cpp @@ -12,7 +12,7 @@ static uint32_t buffer[WIDTH * HEIGHT]; void tvgtest() { //Initialize TizenVG Engine - tvg::Engine::init(); + tvg::Initializer::init(tvg::CanvasEngine::Sw); //Create a Canvas auto canvas = tvg::SwCanvas::gen(); @@ -80,7 +80,7 @@ void tvgtest() canvas->sync(); //Terminate TizenVG Engine - tvg::Engine::term(); + tvg::Initializer::term(tvg::CanvasEngine::Sw); } void diff --git a/test/testStrokeLine.cpp b/test/testStrokeLine.cpp index 1288c07..61e035e 100644 --- a/test/testStrokeLine.cpp +++ b/test/testStrokeLine.cpp @@ -11,7 +11,7 @@ static uint32_t buffer[WIDTH * HEIGHT]; void tvgtest() { //Initialize TizenVG Engine - tvg::Engine::init(); + tvg::Initializer::init(tvg::CanvasEngine::Sw); //Create a Canvas auto canvas = tvg::SwCanvas::gen(); @@ -116,7 +116,7 @@ void tvgtest() canvas->sync(); //Terminate TizenVG Engine - tvg::Engine::term(); + tvg::Initializer::term(tvg::CanvasEngine::Sw); } void diff --git a/test/testTransform.cpp b/test/testTransform.cpp index 0a126cc..a99708d 100644 --- a/test/testTransform.cpp +++ b/test/testTransform.cpp @@ -98,7 +98,7 @@ win_del(void *data, Evas_Object *o, void *ev) int main(int argc, char **argv) { //Initialize TizenVG Engine - tvg::Engine::init(); + tvg::Initializer::init(tvg::CanvasEngine::Sw); tvgtest(); @@ -129,5 +129,5 @@ int main(int argc, char **argv) elm_shutdown(); //Terminate TizenVG Engine - tvg::Engine::term(); + tvg::Initializer::term(tvg::CanvasEngine::Sw); } diff --git a/test/testUpdate.cpp b/test/testUpdate.cpp index 453b47c..0ee9412 100644 --- a/test/testUpdate.cpp +++ b/test/testUpdate.cpp @@ -59,7 +59,7 @@ win_del(void *data, Evas_Object *o, void *ev) int main(int argc, char **argv) { //Initialize TizenVG Engine - tvg::Engine::init(); + tvg::Initializer::init(tvg::CanvasEngine::Sw); tvgtest(); @@ -90,5 +90,5 @@ int main(int argc, char **argv) elm_shutdown(); //Terminate TizenVG Engine - tvg::Engine::term(); + tvg::Initializer::term(tvg::CanvasEngine::Sw); } -- 2.7.4 From c235b7b81d0ab87a989da91738eef2f55a8d1d5e Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Tue, 16 Jun 2020 15:28:43 +0900 Subject: [PATCH 08/16] common scene: design load()/save() interfaces these interfaces will perform for vector resources such as svg/tvg/etc ... see testSvg examples Change-Id: Icec0a4682301a13646868bd7c3bfc1771ae7db2c --- .gitignore | 2 ++ inc/tizenvg.h | 4 +++ src/lib/tvgScene.cpp | 23 +++++++++++++++++ src/lib/tvgSceneImpl.h | 10 ++++++++ test/makefile | 2 ++ test/testSvg.cpp | 63 +++++++++++++++++++++++++++++++++++++++++++++++ test/testSvg2.cpp | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 171 insertions(+) create mode 100644 test/testSvg.cpp create mode 100644 test/testSvg2.cpp diff --git a/.gitignore b/.gitignore index bc11501..3b90d3a 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,5 @@ testStrokeLine testLinearGradient testRadialGradient testGradientTransform +testSvg +testSvg2 diff --git a/inc/tizenvg.h b/inc/tizenvg.h index abb08d6..c62dda2 100644 --- a/inc/tizenvg.h +++ b/inc/tizenvg.h @@ -71,6 +71,7 @@ enum class TVG_EXPORT StrokeJoin { Bevel = 0, Round, Miter }; enum class TVG_EXPORT FillSpread { Pad = 0, Reflect, Repeat }; enum class TVG_EXPORT CanvasEngine { Sw = 0, Gl }; + struct Point { float x, y; @@ -282,6 +283,9 @@ public: Result push(std::unique_ptr paint) noexcept; Result reserve(uint32_t size) noexcept; + Result load(const std::string& path, float w, float h, bool lazy = false) noexcept; + Result save(const std::string& path) noexcept; + Result rotate(float degree) noexcept override; Result scale(float factor) noexcept override; Result translate(float x, float y) noexcept override; diff --git a/src/lib/tvgScene.cpp b/src/lib/tvgScene.cpp index 1ce0ada..c093933 100644 --- a/src/lib/tvgScene.cpp +++ b/src/lib/tvgScene.cpp @@ -107,4 +107,27 @@ Result Scene::bounds(float* x, float* y, float* w, float* h) const noexcept return Result::Success; } + +Result Scene::load(const std::string& path, float w, float h, bool lazy) noexcept +{ + if (path.empty()) return Result::InvalidArguments; + + auto impl = pImpl.get(); + if (!impl) return Result::MemoryCorruption; + + return impl->load(path, w, h, lazy); +} + + +Result Scene::save(const std::string& path) noexcept +{ + if (path.empty()) return Result::InvalidArguments; + + auto impl = pImpl.get(); + if (!impl) return Result::MemoryCorruption; + + return impl->save(path); +} + + #endif /* _TVG_SCENE_CPP_ */ \ No newline at end of file diff --git a/src/lib/tvgSceneImpl.h b/src/lib/tvgSceneImpl.h index 2c92d5b..5ba8d51 100644 --- a/src/lib/tvgSceneImpl.h +++ b/src/lib/tvgSceneImpl.h @@ -191,6 +191,16 @@ struct Scene::Impl return true; } + + Result load(const string& path, float w, float h, bool lazy) + { + return Result::Success; + } + + Result save(const string& path) + { + return Result::Success; + } }; #endif //_TVG_SCENE_IMPL_H_ \ No newline at end of file diff --git a/test/makefile b/test/makefile index 431fa66..8dce9e9 100644 --- a/test/makefile +++ b/test/makefile @@ -15,3 +15,5 @@ all: gcc -o testLinearGradient testLinearGradient.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` gcc -o testRadialGradient testRadialGradient.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` gcc -o testGradientTransform testGradientTransform.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` + gcc -o testSvg testSvg.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` + gcc -o testSvg2 testSvg2.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` diff --git a/test/testSvg.cpp b/test/testSvg.cpp new file mode 100644 index 0000000..dea96a2 --- /dev/null +++ b/test/testSvg.cpp @@ -0,0 +1,63 @@ +#include +#include + +using namespace std; + +#define WIDTH 800 +#define HEIGHT 800 + +static uint32_t buffer[WIDTH * HEIGHT]; + +void tvgtest() +{ + //Initialize TizenVG Engine + tvg::Initializer::init(tvg::CanvasEngine::Sw); + + //Create a Canvas + auto canvas = tvg::SwCanvas::gen(); + canvas->target(buffer, WIDTH, WIDTH, HEIGHT); + + /* Create a SVG scene, keep original size, + You can pass 0 x 0 size for lazying loading in this case. + scene->load("sample.svg", 0, 0, true); */ + auto scene = tvg::Scene::gen(); + scene->load("sample.svg"); + canvas->push(move(scene)); + + canvas->draw(); + canvas->sync(); + + //Terminate TizenVG Engine + tvg::Initializer::term(tvg::CanvasEngine::Sw); +} + +void +win_del(void *data, Evas_Object *o, void *ev) +{ + elm_exit(); +} + + +int main(int argc, char **argv) +{ + tvgtest(); + + //Show the result using EFL... + elm_init(argc, argv); + + Eo* win = elm_win_util_standard_add(NULL, "TizenVG Test"); + evas_object_smart_callback_add(win, "delete,request", win_del, 0); + + Eo* img = evas_object_image_filled_add(evas_object_evas_get(win)); + evas_object_image_size_set(img, WIDTH, HEIGHT); + evas_object_image_data_set(img, buffer); + evas_object_size_hint_weight_set(img, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_show(img); + + elm_win_resize_object_add(win, img); + evas_object_geometry_set(win, 0, 0, WIDTH, HEIGHT); + evas_object_show(win); + + elm_run(); + elm_shutdown(); +} diff --git a/test/testSvg2.cpp b/test/testSvg2.cpp new file mode 100644 index 0000000..4714db6 --- /dev/null +++ b/test/testSvg2.cpp @@ -0,0 +1,67 @@ +#include +#include + +using namespace std; + +#define WIDTH 800 +#define HEIGHT 800 + +static uint32_t buffer[WIDTH * HEIGHT]; + +void tvgtest() +{ + //Initialize TizenVG Engine + tvg::Initializer::init(tvg::CanvasEngine::Sw); + + //Create a Canvas + auto canvas = tvg::SwCanvas::gen(); + canvas->target(buffer, WIDTH, WIDTH, HEIGHT); + + //Create a SVG scene, keep aspect ratio to width/2 with lazy loading + auto scene = tvg::Scene::gen(); + scene->load("sample.svg", WIDTH/2, 0, true); + canvas->push(move(scene)); + + //Create a SVG scene, keep aspect ratio to height/2 with lazy loading + auto scene2 = tvg::Scene::gen(); + scene2->load("sample.svg", 0, HEIGHT/2, true); + scene2->translate(WIDTH/2, HEIGHT/2); + canvas->push(move(scene2)); + + canvas->draw(); + canvas->sync(); + + //Terminate TizenVG Engine + tvg::Initializer::term(tvg::CanvasEngine::Sw); +} + +void +win_del(void *data, Evas_Object *o, void *ev) +{ + elm_exit(); +} + + +int main(int argc, char **argv) +{ + tvgtest(); + + //Show the result using EFL... + elm_init(argc, argv); + + Eo* win = elm_win_util_standard_add(NULL, "TizenVG Test"); + evas_object_smart_callback_add(win, "delete,request", win_del, 0); + + Eo* img = evas_object_image_filled_add(evas_object_evas_get(win)); + evas_object_image_size_set(img, WIDTH, HEIGHT); + evas_object_image_data_set(img, buffer); + evas_object_size_hint_weight_set(img, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_show(img); + + elm_win_resize_object_add(win, img); + evas_object_geometry_set(win, 0, 0, WIDTH, HEIGHT); + evas_object_show(win); + + elm_run(); + elm_shutdown(); +} -- 2.7.4 From ec03afa83a319a2390aeba24f4d3bca30dd5d9ec Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Thu, 18 Jun 2020 10:41:58 +0900 Subject: [PATCH 09/16] sw_engine renderer: accept stroke less 1 width size. Change-Id: I5fe6a0993ab5c1abc79d89834ea04c25b059c320 --- src/lib/sw_engine/tvgSwRenderer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/sw_engine/tvgSwRenderer.cpp b/src/lib/sw_engine/tvgSwRenderer.cpp index 1246eab..adeb738 100644 --- a/src/lib/sw_engine/tvgSwRenderer.cpp +++ b/src/lib/sw_engine/tvgSwRenderer.cpp @@ -126,7 +126,7 @@ void* SwRenderer::prepare(const Shape& sdata, void* data, const RenderTransform* //Stroke if (flags & (RenderUpdateFlag::Stroke | RenderUpdateFlag::Transform)) { - if (sdata.strokeWidth() > 0.5) { + if (sdata.strokeWidth() > FLT_EPSILON) { shapeResetStroke(*shape, sdata); uint8_t alpha = 0; sdata.strokeColor(nullptr, nullptr, nullptr, &alpha); -- 2.7.4 From 968286df57bdc712a09351160c0c3a23697a0da5 Mon Sep 17 00:00:00 2001 From: Pranay Kumar Samanta Date: Wed, 10 Jun 2020 18:14:42 +0530 Subject: [PATCH 10/16] gl_engine: implement gl infrastructure interfaces & test Gl shape sample Change-Id: Ie142616bf02f9bd50ac8e88e31ed9f782dd6324b Signed-off-by: Pranay Kumar Samanta --- .gitignore | 1 + src/lib/gl_engine/meson.build | 6 + src/lib/gl_engine/tvgGlCommon.h | 26 ++- src/lib/gl_engine/tvgGlGeometry.cpp | 319 +++++++++++++++++++++++++++++++++++ src/lib/gl_engine/tvgGlGeometry.h | 44 +++-- src/lib/gl_engine/tvgGlGpuBuffer.cpp | 32 ++++ src/lib/gl_engine/tvgGlGpuBuffer.h | 4 +- src/lib/gl_engine/tvgGlProgram.cpp | 144 ++++++++++++++++ src/lib/gl_engine/tvgGlProgram.h | 13 +- src/lib/gl_engine/tvgGlRenderer.cpp | 107 ++++++++++-- src/lib/gl_engine/tvgGlRenderer.h | 20 +-- src/lib/gl_engine/tvgGlShader.cpp | 77 +++++++++ src/lib/gl_engine/tvgGlShader.h | 5 +- src/lib/gl_engine/tvgGlShaderSrc.cpp | 22 +++ src/lib/gl_engine/tvgGlShaderSrc.h | 7 + src/lib/tvgGlCanvas.cpp | 4 + src/lib/tvgRenderCommon.h | 0 src/lib/tvgShape.cpp | 0 test/makefile | 5 +- test/testGlShape.cpp | 113 +++++++++++++ 20 files changed, 893 insertions(+), 56 deletions(-) mode change 100644 => 100755 src/lib/gl_engine/meson.build mode change 100644 => 100755 src/lib/gl_engine/tvgGlCommon.h create mode 100755 src/lib/gl_engine/tvgGlGeometry.cpp mode change 100644 => 100755 src/lib/gl_engine/tvgGlGeometry.h create mode 100755 src/lib/gl_engine/tvgGlGpuBuffer.cpp mode change 100644 => 100755 src/lib/gl_engine/tvgGlGpuBuffer.h create mode 100755 src/lib/gl_engine/tvgGlProgram.cpp mode change 100644 => 100755 src/lib/gl_engine/tvgGlProgram.h mode change 100644 => 100755 src/lib/gl_engine/tvgGlRenderer.cpp mode change 100644 => 100755 src/lib/gl_engine/tvgGlRenderer.h create mode 100755 src/lib/gl_engine/tvgGlShader.cpp mode change 100644 => 100755 src/lib/gl_engine/tvgGlShader.h create mode 100755 src/lib/gl_engine/tvgGlShaderSrc.cpp create mode 100755 src/lib/gl_engine/tvgGlShaderSrc.h mode change 100644 => 100755 src/lib/tvgGlCanvas.cpp mode change 100644 => 100755 src/lib/tvgRenderCommon.h mode change 100644 => 100755 src/lib/tvgShape.cpp mode change 100644 => 100755 test/makefile create mode 100755 test/testGlShape.cpp diff --git a/.gitignore b/.gitignore index 3b90d3a..af30a22 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,4 @@ testRadialGradient testGradientTransform testSvg testSvg2 +testGlShape diff --git a/src/lib/gl_engine/meson.build b/src/lib/gl_engine/meson.build old mode 100644 new mode 100755 index 5494f69..a5409a7 --- a/src/lib/gl_engine/meson.build +++ b/src/lib/gl_engine/meson.build @@ -5,7 +5,13 @@ source_file = [ 'tvgGlProgram.h', 'tvgGlRenderer.h', 'tvgGlShader.h', + 'tvgGlShaderSrc.h', + 'tvgGlGeometry.cpp', + 'tvgGlGpuBuffer.cpp', + 'tvgGlProgram.cpp', 'tvgGlRenderer.cpp', + 'tvgGlShader.cpp', + 'tvgGlShaderSrc.cpp', ] glraster_dep = declare_dependency( diff --git a/src/lib/gl_engine/tvgGlCommon.h b/src/lib/gl_engine/tvgGlCommon.h old mode 100644 new mode 100755 index f68666a..c596954 --- a/src/lib/gl_engine/tvgGlCommon.h +++ b/src/lib/gl_engine/tvgGlCommon.h @@ -2,11 +2,31 @@ #define _TVG_GL_COMMON_H_ #include "tvgCommon.h" -#include "tvgGlProgram.h" -#include "tvgGlShader.h" -#include "tvgGlGeometry.h" +#define GL_CHECK(x) \ + x; \ + do { \ + GLenum glError = glGetError(); \ + if(glError != GL_NO_ERROR) { \ + printf("glGetError() = %i (0x%.8x) at line %s : %i\n", glError, glError, __FILE__, __LINE__); \ + assert(0); \ + } \ + } while(0) + +#define EGL_CHECK(x) \ + x; \ + do { \ + EGLint eglError = eglGetError(); \ + if(eglError != EGL_SUCCESS) { \ + printf("eglGetError() = %i (0x%.8x) at line %s : %i\n", eglError, eglError, __FILE__, __LINE__); \ + assert(0); \ + } \ + } while(0) + + +class GlGeometry; + struct GlShape { float viewWd; diff --git a/src/lib/gl_engine/tvgGlGeometry.cpp b/src/lib/gl_engine/tvgGlGeometry.cpp new file mode 100755 index 0000000..59b730b --- /dev/null +++ b/src/lib/gl_engine/tvgGlGeometry.cpp @@ -0,0 +1,319 @@ +#include "tvgGlGpuBuffer.h" +#include "tvgGlGeometry.h" +#include "tvgGlCommon.h" + +#include + + +uint32_t GlGeometry::getPrimitiveCount() +{ + return mPrimitives.size(); +} + + +bool GlGeometry::decomposeOutline(const Shape &shape) +{ + const PathCommand *cmds = nullptr; + auto cmdCnt = shape.pathCommands(&cmds); + + Point *pts = nullptr; + auto ptsCnt = shape.pathCoords(const_cast(&pts)); + + //No actual shape data + if (cmdCnt == 0 || ptsCnt == 0) + return false; + + GlPrimitive* curPrimitive = nullptr; + for (size_t i = 0; i < cmdCnt; ++i) + { + switch (*(cmds + i)) + { + case PathCommand::Close: + { + if (curPrimitive && curPrimitive->mAAPoints.size() > 0 && + (curPrimitive->mAAPoints[0].orgPt != curPrimitive->mAAPoints.back().orgPt) ) + { + curPrimitive->mAAPoints.push_back(curPrimitive->mAAPoints[0].orgPt); + } + break; + } + case PathCommand::MoveTo: + mPrimitives.push_back(GlPrimitive()); + curPrimitive = &mPrimitives.back(); + case PathCommand::LineTo: + { + if (curPrimitive) + { + addPoint(*curPrimitive, pts[0]); + } + pts++; + break; + } + case PathCommand::CubicTo: + { + if (curPrimitive) + { + decomposeCubicCurve(*curPrimitive, curPrimitive->mAAPoints.back().orgPt, pts[0], pts[1], pts[2]); + } + pts += 3; + break; + } + } + } + return true; +} + +bool GlGeometry::generateAAPoints(const Shape &shape, float strokeWd, RenderUpdateFlag flag) +{ + for (auto& shapeGeometry : mPrimitives) + { + std::vector normalInfo; + constexpr float blurDir = -1.0f; + float antiAliasWidth = 1.0f; + vector& aaPts = shapeGeometry.mAAPoints; + + const float stroke = (strokeWd > 1) ? strokeWd - antiAliasWidth : strokeWd; + + size_t nPoints = aaPts.size(); + if (nPoints < 2) + { + return false; + } + + normalInfo.resize(nPoints); + + size_t fPoint = 0; + size_t sPoint = 1; + for (size_t i = 0; i < nPoints - 1; ++i) + { + fPoint = i; + sPoint = i + 1; + if (sPoint == nPoints - 1) + sPoint = 0; + + GlPoint normal = getNormal(aaPts[fPoint].orgPt, aaPts[sPoint].orgPt); + + normalInfo[fPoint].normal1 = normal; + normalInfo[sPoint].normal2 = normal; + } + normalInfo[nPoints - 1].normal1 = normalInfo[0].normal1; + normalInfo[nPoints - 1].normal2 = normalInfo[0].normal2; + + for (uint32_t i = 0; i < nPoints; ++i) + { + normalInfo[i].normalF = normalInfo[i].normal1 + normalInfo[i].normal2; + normalInfo[i].normalF.normalize(); + + float angle = dotProduct(normalInfo[i].normal2, normalInfo[i].normalF); + if (angle != 0) + normalInfo[i].normalF = normalInfo[i].normalF / angle; + else + normalInfo[i].normalF = GlPoint(0, 0); + + if (flag & RenderUpdateFlag::Color) + { + aaPts[i].fillOuterBlur = extendEdge(aaPts[i].orgPt, normalInfo[i].normalF, blurDir * stroke); + aaPts[i].fillOuter = extendEdge(aaPts[i].fillOuterBlur, normalInfo[i].normalF, blurDir*antiAliasWidth); + } + if (flag & RenderUpdateFlag::Stroke) + { + aaPts[i].strokeOuterBlur = aaPts[i].orgPt; + aaPts[i].strokeOuter = extendEdge(aaPts[i].strokeOuterBlur, normalInfo[i].normalF, blurDir*antiAliasWidth); + aaPts[i].strokeInner = extendEdge(aaPts[i].strokeOuter, normalInfo[i].normalF, blurDir * stroke); + aaPts[i].strokeInnerBlur = extendEdge(aaPts[i].strokeInner, normalInfo[i].normalF, blurDir*antiAliasWidth); + } + } + } + + return true; +} + +bool GlGeometry::tesselate(const Shape &shape, float viewWd, float viewHt, RenderUpdateFlag flag) +{ + for (auto& shapeGeometry : mPrimitives) + { + constexpr float opaque = 1.0f; + constexpr float transparent = 0.0f; + vector& aaPts = shapeGeometry.mAAPoints; + VertexDataArray& fill = shapeGeometry.mFill; + VertexDataArray& stroke = shapeGeometry.mStroke; + + if (flag & RenderUpdateFlag::Color) + { + uint32_t i = 0; + for (size_t pt = 0; pt < aaPts.size(); ++pt) + { + addGeometryPoint(fill, aaPts[pt].fillOuter, viewWd, viewHt, opaque); + if (i > 1) + { + addTriangleFanIndices(i, fill.indices); + } + ++i; + } + for (size_t pt = 1; pt < aaPts.size(); ++pt) + { + addGeometryPoint(fill, aaPts[pt - 1].fillOuterBlur, viewWd, viewHt, transparent); + addGeometryPoint(fill, aaPts[pt - 1].fillOuter, viewWd, viewHt, opaque); + addGeometryPoint(fill, aaPts[pt].fillOuterBlur, viewWd, viewHt, transparent); + addGeometryPoint(fill, aaPts[pt].fillOuter, viewWd, viewHt, opaque); + addQuadIndices(i, fill.indices); + } + } + if (flag & RenderUpdateFlag::Stroke) + { + uint32_t i = 0; + for (size_t pt = 1; pt < aaPts.size(); ++pt) + { + addGeometryPoint(stroke, aaPts[pt - 1].strokeOuter, viewWd, viewHt, opaque); + addGeometryPoint(stroke, aaPts[pt - 1].strokeInner, viewWd, viewHt, opaque); + addGeometryPoint(stroke, aaPts[pt].strokeOuter, viewWd, viewHt, opaque); + addGeometryPoint(stroke, aaPts[pt].strokeInner, viewWd, viewHt, opaque); + addQuadIndices(i, stroke.indices); + } + for (size_t pt = 1; pt < aaPts.size(); ++pt) + { + addGeometryPoint(stroke, aaPts[pt - 1].strokeOuterBlur, viewWd, viewHt, transparent); + addGeometryPoint(stroke, aaPts[pt - 1].strokeOuter, viewWd, viewHt, opaque); + addGeometryPoint(stroke, aaPts[pt].strokeOuterBlur, viewWd, viewHt, transparent); + addGeometryPoint(stroke, aaPts[pt].strokeOuter, viewWd, viewHt, opaque); + addQuadIndices(i, stroke.indices); + } + for (size_t pt = 1; pt < aaPts.size(); ++pt) + { + addGeometryPoint(stroke, aaPts[pt - 1].strokeInner, viewWd, viewHt, opaque); + addGeometryPoint(stroke, aaPts[pt - 1].strokeInnerBlur, viewWd, viewHt, transparent); + addGeometryPoint(stroke, aaPts[pt].strokeInner, viewWd, viewHt, opaque); + addGeometryPoint(stroke, aaPts[pt].strokeInnerBlur, viewWd, viewHt, transparent); + addQuadIndices(i, stroke.indices); + } + } + aaPts.clear(); + } + return true; +} + + +void GlGeometry::disableVertex(uint32_t location) +{ + GL_CHECK(glDisableVertexAttribArray(location)); + mGpuBuffer->unbind(GlGpuBuffer::Target::ARRAY_BUFFER); +} + + +void GlGeometry::draw(const uint32_t location, const uint32_t primitiveIndex, RenderUpdateFlag flag) +{ + if (primitiveIndex >= mPrimitives.size()) + { + return; + } + VertexDataArray& geometry = (flag == RenderUpdateFlag::Color) ? mPrimitives[primitiveIndex].mFill : mPrimitives[primitiveIndex].mStroke; + + updateBuffer(location, geometry); + GL_CHECK(glDrawElements(GL_TRIANGLES, geometry.indices.size(), GL_UNSIGNED_INT, geometry.indices.data())); +} + + +void GlGeometry::updateBuffer(uint32_t location, const VertexDataArray& vertexArray) +{ + if (mGpuBuffer.get() == nullptr) + { + mGpuBuffer = make_unique(); + } + mGpuBuffer->updateBufferData(GlGpuBuffer::Target::ARRAY_BUFFER, vertexArray.vertices.size() * sizeof(VertexData), vertexArray.vertices.data()); + GL_CHECK(glVertexAttribPointer(location, 3, GL_FLOAT, GL_FALSE, sizeof(VertexData), 0)); + GL_CHECK(glEnableVertexAttribArray(location)); +} + + +GlPoint GlGeometry::normalizePoint(const GlPoint &pt, float viewWd, float viewHt) +{ + GlPoint p; + p.x = (pt.x * 2.0f / viewWd) - 1.0f; + p.y = -1.0f * ((pt.y * 2.0f / viewHt) - 1.0f); + return p; +} + +void GlGeometry::addGeometryPoint(VertexDataArray &geometry, const GlPoint &pt, float viewWd, float viewHt, float opacity) +{ + VertexData tv = { normalizePoint(pt, viewWd, viewHt), opacity}; + geometry.vertices.push_back(tv); +} + +GlPoint GlGeometry::getNormal(const GlPoint &p1, const GlPoint &p2) +{ + GlPoint normal = p1 - p2; + normal.normalize(); + return GlPoint(-normal.y, normal.x); +} + +float GlGeometry::dotProduct(const GlPoint &p1, const GlPoint &p2) +{ + return (p1.x * p2.x + p1.y * p2.y); +} + +GlPoint GlGeometry::extendEdge(const GlPoint &pt, const GlPoint &normal, float scalar) +{ + GlPoint tmp = (normal * scalar); + return (pt + tmp); +} + +void GlGeometry::addPoint(GlPrimitive& primitve, const GlPoint &pt) +{ + primitve.mAAPoints.push_back(GlPoint(pt.x, pt.y)); +} + +void GlGeometry::addTriangleFanIndices(uint32_t &curPt, std::vector &indices) +{ + indices.push_back(0); + indices.push_back(curPt - 1); + indices.push_back(curPt); +} + +void GlGeometry::addQuadIndices(uint32_t &curPt, std::vector &indices) +{ + indices.push_back(curPt); + indices.push_back(curPt + 1); + indices.push_back(curPt + 2); + indices.push_back(curPt + 1); + indices.push_back(curPt + 3); + indices.push_back(curPt + 2); + curPt += 4; +} + +bool GlGeometry::isBezierFlat(const GlPoint &p1, const GlPoint &c1, const GlPoint &c2, const GlPoint &p2) +{ + GlPoint diff1 = (c1 * 3.0f) - (p1 * 2.0f) - p2; + GlPoint diff2 = (c2 * 3.0f) - (p2 * 2.0f) - p1; + + diff1.mod(); + diff2.mod(); + if (diff1.x < diff2.x) + diff1.x = diff2.x; + if (diff1.y < diff2.y) + diff1.y = diff2.y; + + if (diff1.x + diff1.y <= 0.5f) + return true; + return false; +} + +void GlGeometry::decomposeCubicCurve(GlPrimitive& primitve, const GlPoint &pt1, const GlPoint &cpt1, const GlPoint &cpt2, const GlPoint &pt2) +{ + if (isBezierFlat(pt1, cpt1, cpt2, pt2)) + { + addPoint(primitve, pt2); + return; + } + GlPoint p12 = (pt1 + cpt1) * 0.5f; + GlPoint p23 = (cpt1 + cpt2) * 0.5f; + GlPoint p34 = (cpt2 + pt2) * 0.5f; + + GlPoint p123 = (p12 + p23) * 0.5f; + GlPoint p234 = (p23 + p34) * 0.5f; + + GlPoint p1234 = (p123 + p234) * 0.5f; + + decomposeCubicCurve(primitve, pt1, p12, p123, p1234); + decomposeCubicCurve(primitve, p1234, p234, p34, pt2); +} + diff --git a/src/lib/gl_engine/tvgGlGeometry.h b/src/lib/gl_engine/tvgGlGeometry.h old mode 100644 new mode 100755 index 8f7cc61..9f87efa --- a/src/lib/gl_engine/tvgGlGeometry.h +++ b/src/lib/gl_engine/tvgGlGeometry.h @@ -1,7 +1,7 @@ #ifndef _TVG_GL_GEOMETRY_H_ #define _TVG_GL_GEOMETRY_H_ -#include "tvgGlGpuBuffer.h" +#include "tvgGlCommon.h" class GlPoint { @@ -9,6 +9,8 @@ public: float x = 0.0f; float y = 0.0f; + GlPoint() = default; + GlPoint(float pX, float pY):x(pX), y(pY) {} @@ -145,36 +147,42 @@ struct VertexDataArray vector indices; }; +struct GlPrimitive +{ + vector mAAPoints; + VertexDataArray mFill; + VertexDataArray mStroke; +}; + +class GlGpuBuffer; + class GlGeometry { public: - GlGeometry(); - void reset(); - void updateBuffer(const uint32_t location, const VertexDataArray& geometry); - void draw(const VertexDataArray& geometry); + + uint32_t getPrimitiveCount(); bool decomposeOutline(const Shape& shape); bool generateAAPoints(const Shape& shape, float strokeWd, RenderUpdateFlag flag); bool tesselate(const Shape &shape, float viewWd, float viewHt, RenderUpdateFlag flag); - - const VertexDataArray& getFill(); - const VertexDataArray& getStroke(); + void disableVertex(uint32_t location); + void draw(const uint32_t location, const uint32_t primitiveIndex, RenderUpdateFlag flag); private: - GlPoint normalizePoint(GlPoint &pt, float viewWd, float viewHt); - void addGeometryPoint(VertexDataArray &geometry, GlPoint &pt, float viewWd, float viewHt, float opacity); - GlPoint getNormal(GlPoint &p1, GlPoint &p2); - float dotProduct(GlPoint &p1, GlPoint &p2); - GlPoint extendEdge(GlPoint &pt, GlPoint &normal, float scalar); - void addPoint(const GlPoint &pt); + GlPoint normalizePoint(const GlPoint &pt, float viewWd, float viewHt); + void addGeometryPoint(VertexDataArray &geometry, const GlPoint &pt, float viewWd, float viewHt, float opacity); + GlPoint getNormal(const GlPoint &p1, const GlPoint &p2); + float dotProduct(const GlPoint &p1, const GlPoint &p2); + GlPoint extendEdge(const GlPoint &pt, const GlPoint &normal, float scalar); + + void addPoint(GlPrimitive& primitve, const GlPoint &pt); void addTriangleFanIndices(uint32_t &curPt, vector &indices); void addQuadIndices(uint32_t &curPt, vector &indices); bool isBezierFlat(const GlPoint &p1, const GlPoint &c1, const GlPoint &c2, const GlPoint &p2); - void decomposeCubicCurve(const GlPoint &pt1, const GlPoint &cpt1, const GlPoint &cpt2, const GlPoint &pt2); + void decomposeCubicCurve(GlPrimitive& primitve, const GlPoint &pt1, const GlPoint &cpt1, const GlPoint &cpt2, const GlPoint &pt2); + void updateBuffer(const uint32_t location, const VertexDataArray& vertexArray); unique_ptr mGpuBuffer; - vector mAAPoints; - VertexDataArray mFill; - VertexDataArray mStroke; + vector mPrimitives; }; #endif /* _TVG_GL_GEOMETRY_H_ */ diff --git a/src/lib/gl_engine/tvgGlGpuBuffer.cpp b/src/lib/gl_engine/tvgGlGpuBuffer.cpp new file mode 100755 index 0000000..2aaba19 --- /dev/null +++ b/src/lib/gl_engine/tvgGlGpuBuffer.cpp @@ -0,0 +1,32 @@ +#include "tvgGlCommon.h" +#include "tvgGlGpuBuffer.h" + +#include + +GlGpuBuffer::GlGpuBuffer() +{ + GL_CHECK(glGenBuffers(1, &mGlBufferId)); + assert(mGlBufferId != GL_INVALID_VALUE); +} + + +GlGpuBuffer::~GlGpuBuffer() +{ + if (mGlBufferId) + { + GL_CHECK(glDeleteBuffers(1, &mGlBufferId)); + } +} + + +void GlGpuBuffer::updateBufferData(Target target, uint32_t size, const void* data) +{ + GL_CHECK(glBindBuffer(static_cast(target), mGlBufferId)); + GL_CHECK(glBufferData(static_cast(target), size, data, GL_STATIC_DRAW)); +} + + +void GlGpuBuffer::unbind(Target target) +{ + GL_CHECK(glBindBuffer(static_cast(target), 0)); +} \ No newline at end of file diff --git a/src/lib/gl_engine/tvgGlGpuBuffer.h b/src/lib/gl_engine/tvgGlGpuBuffer.h old mode 100644 new mode 100755 index 79dd26d..3116001 --- a/src/lib/gl_engine/tvgGlGpuBuffer.h +++ b/src/lib/gl_engine/tvgGlGpuBuffer.h @@ -15,8 +15,8 @@ public: GlGpuBuffer(); ~GlGpuBuffer(); - void updateBufferData(Target target, uint32_t size, void* data); - + void updateBufferData(Target target, uint32_t size, const void* data); + void unbind(Target target); private: uint32_t mGlBufferId = 0; diff --git a/src/lib/gl_engine/tvgGlProgram.cpp b/src/lib/gl_engine/tvgGlProgram.cpp new file mode 100755 index 0000000..dbf8762 --- /dev/null +++ b/src/lib/gl_engine/tvgGlProgram.cpp @@ -0,0 +1,144 @@ +#include "tvgGlCommon.h" +#include "tvgGlProgram.h" + +#include + + +static std::vector gStdAttributes = { + "aLocation" +}; + +static std::vector gStdUniforms = { + "uColor" +}; + +uint32_t GlProgram::mCurrentProgram = 0; +map GlProgram::mAttributeBuffer; +map GlProgram::mUniformBuffer; + + +unique_ptr GlProgram::gen(std::shared_ptr shader) +{ + return make_unique(shader); +} + + +GlProgram::GlProgram(std::shared_ptr shader) +{ + linkProgram(shader); + load(); + + for (auto name : gStdAttributes) + { + getAttributeLocation(name.c_str()); + } + for (auto name : gStdUniforms) + { + getUniformLocation(name.c_str()); + } + +} + + +GlProgram::~GlProgram() +{ + if (mCurrentProgram == mProgramObj) + { + unload(); + } + glDeleteProgram(mProgramObj); +} + + +void GlProgram::load() +{ + if (mCurrentProgram == mProgramObj) + { + return; + } + + mCurrentProgram = mProgramObj; + GL_CHECK(glUseProgram(mProgramObj)); + +} + + +void GlProgram::unload() +{ + mCurrentProgram = 0; +} + + +int32_t GlProgram::getAttributeLocation(const char* name) +{ + if (mAttributeBuffer.find(name) != mAttributeBuffer.end()) + { + return mAttributeBuffer[name]; + } + GL_CHECK(int32_t location = glGetAttribLocation(mCurrentProgram, name)); + if (location != -1) + { + mAttributeBuffer[name] = location; + } + return location; +} + + +int32_t GlProgram::getUniformLocation(const char* name) +{ + if (mUniformBuffer.find(name) != mUniformBuffer.end()) + { + return mUniformBuffer[name]; + } + GL_CHECK(int32_t location = glGetUniformLocation(mCurrentProgram, name)); + if (location != -1) + { + mUniformBuffer[name] = location; + } + return location; + +} + + +void GlProgram::setUniformValue(int32_t location, float r, float g, float b, float a) +{ + glUniform4f(location, r, g, b, a); +} + + +void GlProgram::linkProgram(std::shared_ptr shader) +{ + GLint linked; + + // Create the program object + uint32_t progObj = glCreateProgram(); + assert(progObj); + + glAttachShader(progObj, shader->getVertexShader()); + glAttachShader(progObj, shader->getFragmentShader()); + + // Link the program + glLinkProgram(progObj); + + // Check the link status + glGetProgramiv(progObj, GL_LINK_STATUS, &linked); + + if (!linked) + { + GLint infoLen = 0; + glGetProgramiv(progObj, GL_INFO_LOG_LENGTH, &infoLen); + if (infoLen > 0) + { + char* infoLog = new char[infoLen]; + glGetProgramInfoLog(progObj, infoLen, NULL, infoLog); + std::cout << "Error linking shader: " << infoLog << std::endl; + delete[] infoLog; + + } + glDeleteProgram(progObj); + progObj = 0; + assert(0); + } + mProgramObj = progObj; +} + diff --git a/src/lib/gl_engine/tvgGlProgram.h b/src/lib/gl_engine/tvgGlProgram.h old mode 100644 new mode 100755 index d485d3d..5df0e4f --- a/src/lib/gl_engine/tvgGlProgram.h +++ b/src/lib/gl_engine/tvgGlProgram.h @@ -3,22 +3,25 @@ #include "tvgGlShader.h" +#include #include - class GlProgram { public: - GlProgram(shared_ptr shader); - void create(); + static std::unique_ptr gen(std::shared_ptr shader); + GlProgram(std::shared_ptr shader); + ~GlProgram(); + void load(); + void unload(); int32_t getAttributeLocation(const char* name); int32_t getUniformLocation(const char* name); void setUniformValue(int32_t location, float r, float g, float b, float a); private: - void linkProgram(); - std::shared_ptr mShader; + + void linkProgram(std::shared_ptr shader); uint32_t mProgramObj; static uint32_t mCurrentProgram; diff --git a/src/lib/gl_engine/tvgGlRenderer.cpp b/src/lib/gl_engine/tvgGlRenderer.cpp old mode 100644 new mode 100755 index 1ca9588..ecabf6a --- a/src/lib/gl_engine/tvgGlRenderer.cpp +++ b/src/lib/gl_engine/tvgGlRenderer.cpp @@ -17,7 +17,10 @@ #ifndef _TVG_GL_RENDERER_CPP_ #define _TVG_GL_RENDERER_CPP_ -#include "tvgCommon.h" +#include "tvgGlShaderSrc.h" +#include "tvgGlGpuBuffer.h" +#include "tvgGlGeometry.h" +#include "tvgGlCommon.h" #include "tvgGlRenderer.h" /************************************************************************/ @@ -33,16 +36,55 @@ static RenderInitializer renderInit; bool GlRenderer::clear() { //TODO: (Request) to clear target + // Will be adding glClearColor for input buffer + return true; +} + + +bool GlRenderer::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h) +{ + assert(w > 0 && h > 0); + + surface.stride = stride; + surface.w = w; + surface.h = h; return true; } + +void GlRenderer::flush() +{ + GL_CHECK(glFinish()); + mColorProgram->unload(); +} + + bool GlRenderer::render(const Shape& shape, void *data) { GlShape* sdata = static_cast(data); if (!sdata) return false; - //TODO: + uint8_t r, g, b, a; + size_t flags = static_cast(sdata->updateFlag); + + GL_CHECK(glViewport(0, 0, sdata->viewWd, sdata->viewHt)); + + uint32_t geometryCnt = sdata->geometry->getPrimitiveCount(); + for (uint32_t i = 0; i < geometryCnt; ++i) + { + mColorProgram->load(); + if (flags & RenderUpdateFlag::Color) + { + shape.fill(&r, &g, &b, &a); + drawPrimitive(*(sdata->geometry), (float)r / 255.0f, (float)g / 255.0f, (float)b / 255.0f, (float)a / 255.0f, i, RenderUpdateFlag::Color); + } + if (flags & RenderUpdateFlag::Stroke) + { + shape.strokeColor(&r, &g, &b, &a); + drawPrimitive(*(sdata->geometry), (float)r / 255.0f, (float)g / 255.0f, (float)b / 255.0f, (float)a / 255.0f, i, RenderUpdateFlag::Stroke); + } + } return true; } @@ -53,9 +95,7 @@ bool GlRenderer::dispose(const Shape& shape, void *data) GlShape* sdata = static_cast(data); if (!sdata) return false; - //TODO: - - free(sdata); + delete sdata; return true; } @@ -64,21 +104,35 @@ void* GlRenderer::prepare(const Shape& shape, void* data, const RenderTransform* { //prepare shape data GlShape* sdata = static_cast(data); - if (!sdata) { - sdata = static_cast(calloc(1, sizeof(GlShape))); + if (!sdata) + { + sdata = new GlShape; assert(sdata); } + sdata->viewWd = static_cast(surface.w); + sdata->viewHt = static_cast(surface.h); + sdata->updateFlag = flags; - if (flags & RenderUpdateFlag::Path) { - //TODO: Updated Vertices - } + if (sdata->updateFlag == RenderUpdateFlag::None) return nullptr; - if (flags & RenderUpdateFlag::Transform) { - //TODO: Updated Transform - } + initShaders(); + + sdata->geometry = make_unique(); - //TODO: + //invisible? + uint8_t alphaF, alphaS; + shape.fill(nullptr, nullptr, nullptr, &alphaF); + shape.strokeColor(nullptr, nullptr, nullptr, &alphaS); + auto strokeWd = shape.strokeWidth(); + if (alphaF == 0 && alphaS == 0) return sdata; + + if (sdata->updateFlag & (RenderUpdateFlag::Color | RenderUpdateFlag::Stroke) ) + { + if (!sdata->geometry->decomposeOutline(shape)) return sdata; + if (!sdata->geometry->generateAAPoints(shape, static_cast(strokeWd), sdata->updateFlag)) return sdata; + if (!sdata->geometry->tesselate(shape, sdata->viewWd, sdata->viewHt, sdata->updateFlag)) return sdata; + } return sdata; } @@ -91,6 +145,10 @@ int GlRenderer::init() int GlRenderer::term() { + if (inst()->mColorProgram.get()) + { + inst()->mColorProgram.reset(nullptr); + } return RenderInitializer::term(renderInit); } @@ -114,4 +172,25 @@ GlRenderer* GlRenderer::inst() } +void GlRenderer::initShaders() +{ + if (!mColorProgram.get()) + { + shared_ptr shader = GlShader::gen(COLOR_VERT_SHADER, COLOR_FRAG_SHADER); + mColorProgram = GlProgram::gen(shader); + } + mColorProgram->load(); + mColorUniformLoc = mColorProgram->getUniformLocation("uColor"); + mVertexAttrLoc = mColorProgram->getAttributeLocation("aLocation"); +} + + +void GlRenderer::drawPrimitive(GlGeometry& geometry, float r, float g, float b, float a, uint32_t primitiveIndex, RenderUpdateFlag flag) +{ + mColorProgram->setUniformValue(mColorUniformLoc, r, g, b, a); + geometry.draw(mVertexAttrLoc, primitiveIndex, flag); + geometry.disableVertex(mVertexAttrLoc); + +} + #endif /* _TVG_GL_RENDERER_CPP_ */ diff --git a/src/lib/gl_engine/tvgGlRenderer.h b/src/lib/gl_engine/tvgGlRenderer.h old mode 100644 new mode 100755 index 3ef0ee9..5214a63 --- a/src/lib/gl_engine/tvgGlRenderer.h +++ b/src/lib/gl_engine/tvgGlRenderer.h @@ -18,9 +18,8 @@ #define _TVG_GL_RENDERER_H_ #include "tvgGlCommon.h" +#include "tvgGlProgram.h" -namespace tvg -{ class GlRenderer : public RenderMethod { @@ -30,10 +29,8 @@ public: void* prepare(const Shape& shape, void* data, const RenderTransform* transform, RenderUpdateFlag flags) override; bool dispose(const Shape& shape, void *data) override; bool render(const Shape& shape, void *data) override; - bool target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h) - { - return 0; - }; + bool target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h); + void flush(); bool clear() override; uint32_t ref() override; uint32_t unref() override; @@ -46,11 +43,12 @@ private: GlRenderer(){}; ~GlRenderer(){}; - std::unique_ptr mColorProgram; - int32_t mColorUniform; - uint32_t mVertexAttrID; -}; + void initShaders(); + void drawPrimitive(GlGeometry& geometry, float r, float g, float b, float a, uint32_t primitiveIndex, RenderUpdateFlag flag); -} + unique_ptr mColorProgram; + int32_t mColorUniformLoc; + uint32_t mVertexAttrLoc; +}; #endif /* _TVG_GL_RENDERER_H_ */ diff --git a/src/lib/gl_engine/tvgGlShader.cpp b/src/lib/gl_engine/tvgGlShader.cpp new file mode 100755 index 0000000..a655159 --- /dev/null +++ b/src/lib/gl_engine/tvgGlShader.cpp @@ -0,0 +1,77 @@ +#include "tvgGlCommon.h" +#include "tvgGlShader.h" + +#include + + +shared_ptr GlShader::gen(const char * vertSrc, const char * fragSrc) +{ + shared_ptr shader = make_shared(); + shader->createShader(vertSrc, fragSrc); + return shader; +} + + +GlShader::~GlShader() +{ + glDeleteShader(mVtShader); + glDeleteShader(mFrShader); +} + +uint32_t GlShader::getVertexShader() +{ + return mVtShader; +} + + +uint32_t GlShader::getFragmentShader() +{ + return mFrShader; +} + + +void GlShader::createShader(const char* vertSrc, const char* fragSrc) +{ + mVtShader = complileShader(GL_VERTEX_SHADER, const_cast(vertSrc)); + mFrShader = complileShader(GL_FRAGMENT_SHADER, const_cast(fragSrc)); +} + + +uint32_t GlShader::complileShader(uint32_t type, char* shaderSrc) +{ + GLuint shader; + GLint compiled; + + // Create the shader object + shader = glCreateShader(type); + assert(shader); + + // Load the shader source + glShaderSource(shader, 1, &shaderSrc, NULL); + + // Compile the shader + glCompileShader(shader); + + // Check the compile status + glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled); + + if (!compiled) + { + GLint infoLen = 0; + + glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen); + + if (infoLen > 0) + { + char* infoLog = new char[infoLen]; + glGetShaderInfoLog(shader, infoLen, NULL, infoLog); + std::cout << "Error compiling shader: " << infoLog << std::endl; + delete[] infoLog; + } + glDeleteShader(shader); + assert(0); + } + + return shader; +} + diff --git a/src/lib/gl_engine/tvgGlShader.h b/src/lib/gl_engine/tvgGlShader.h old mode 100644 new mode 100755 index 36b125a..85bf116 --- a/src/lib/gl_engine/tvgGlShader.h +++ b/src/lib/gl_engine/tvgGlShader.h @@ -1,10 +1,13 @@ #ifndef _TVG_GL_SHADER_H_ #define _TVG_GL_SHADER_H_ +#include + class GlShader { public: - static shared_ptr gen(const char * vertSrc, const char * fragSrc); + static std::shared_ptr gen(const char * vertSrc, const char * fragSrc); + ~GlShader(); uint32_t getVertexShader(); uint32_t getFragmentShader(); diff --git a/src/lib/gl_engine/tvgGlShaderSrc.cpp b/src/lib/gl_engine/tvgGlShaderSrc.cpp new file mode 100755 index 0000000..cdd25f0 --- /dev/null +++ b/src/lib/gl_engine/tvgGlShaderSrc.cpp @@ -0,0 +1,22 @@ +#include "tvgGlShaderSrc.h" + +const char* COLOR_VERT_SHADER = +"attribute highp vec4 aLocation; \n" +"uniform highp vec4 uColor; \n" +"varying highp vec4 vcolor; \n" +"varying highp float vOpacity; \n" +"void main() \n" +"{ \n" +" gl_Position = vec4(aLocation.xy, 0.0, 1.0); \n" +" vcolor = uColor; \n" +" vOpacity = aLocation.z; \n" +"} \n"; + +const char* COLOR_FRAG_SHADER = +"varying highp vec4 vcolor; \n" +"varying highp float vOpacity; \n" +"void main() \n" +"{ \n" +" gl_FragColor = vec4(vcolor.xyz, vcolor.w*vOpacity); \n" +"} \n"; + diff --git a/src/lib/gl_engine/tvgGlShaderSrc.h b/src/lib/gl_engine/tvgGlShaderSrc.h new file mode 100755 index 0000000..e6d3b91 --- /dev/null +++ b/src/lib/gl_engine/tvgGlShaderSrc.h @@ -0,0 +1,7 @@ +#ifndef _TVG_GL_SHADERSRC_H_ +#define _TVG_GL_SHADERSRC_H_ + +extern const char* COLOR_VERT_SHADER; +extern const char* COLOR_FRAG_SHADER; + +#endif /* _TVG_GL_SHADERSRC_H_ */ diff --git a/src/lib/tvgGlCanvas.cpp b/src/lib/tvgGlCanvas.cpp old mode 100644 new mode 100755 index 7d3903c..80a0017 --- a/src/lib/tvgGlCanvas.cpp +++ b/src/lib/tvgGlCanvas.cpp @@ -59,6 +59,10 @@ Result GlCanvas::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t Result GlCanvas::sync() noexcept { + auto renderer = dynamic_cast(Canvas::pImpl.get()->renderer); + assert(renderer); + + renderer->flush(); return Result::Success; } diff --git a/src/lib/tvgRenderCommon.h b/src/lib/tvgRenderCommon.h old mode 100644 new mode 100755 diff --git a/src/lib/tvgShape.cpp b/src/lib/tvgShape.cpp old mode 100644 new mode 100755 diff --git a/test/makefile b/test/makefile old mode 100644 new mode 100755 index 8dce9e9..aca250b --- a/test/makefile +++ b/test/makefile @@ -15,5 +15,6 @@ all: gcc -o testLinearGradient testLinearGradient.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` gcc -o testRadialGradient testRadialGradient.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` gcc -o testGradientTransform testGradientTransform.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` - gcc -o testSvg testSvg.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` - gcc -o testSvg2 testSvg2.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` +# gcc -o testSvg testSvg.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` +# gcc -o testSvg2 testSvg2.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` + gcc -o testGlShape testGlShape.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` diff --git a/test/testGlShape.cpp b/test/testGlShape.cpp new file mode 100755 index 0000000..077057e --- /dev/null +++ b/test/testGlShape.cpp @@ -0,0 +1,113 @@ +#include +#include + +using namespace std; + +#define WIDTH 800 +#define HEIGHT 800 +#define BPP 4 +static Evas_GL_API *glapi; +static unique_ptr canvas; + +static void +tvgtest() +{ + //Initialize TizenVG Engine + tvg::Initializer::init(tvg::CanvasEngine::Gl); + + + //Create a Canvas + canvas = tvg::GlCanvas::gen(); + canvas->target(nullptr, WIDTH * BPP, WIDTH, HEIGHT); + + //Prepare a Shape (Rectangle + Rectangle + Circle + Circle) + auto shape1 = tvg::Shape::gen(); + shape1->appendRect(0, 0, 200, 200, 0); //x, y, w, h, cornerRadius + shape1->appendRect(100, 100, 300, 300, 100); //x, y, w, h, cornerRadius + shape1->appendCircle(400, 400, 100, 100); //cx, cy, radiusW, radiusH + shape1->appendCircle(400, 500, 170, 100); //cx, cy, radiusW, radiusH + shape1->fill(255, 255, 0, 255); //r, g, b, a + shape1->stroke(255, 0, 0, 255); //r, g, b, a + shape1->stroke(10.0f); + + /* Push the shape into the Canvas drawing list + When this shape is into the canvas list, the shape could update & prepare + internal data asynchronously for coming rendering. + Canvas keeps this shape node unless user call canvas->clear() */ + canvas->push(move(shape1)); +} + +static void +init_gl(Evas_Object *obj) +{ + tvgtest(); +} + +static void +del_gl(Evas_Object *obj) +{ + //Terminate TizenVG Engine + tvg::Initializer::term(tvg::CanvasEngine::Gl); +} + +static void +draw_gl(Evas_Object *obj) +{ + Evas_GL_API *gl = elm_glview_gl_api_get(obj); + int w, h; + elm_glview_size_get(obj, &w, &h); + gl->glViewport(0, 0, w, h); + gl->glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + gl->glClear(GL_COLOR_BUFFER_BIT); + gl->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + gl->glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE); + gl->glEnable(GL_BLEND); + + canvas->draw(); + canvas->sync(); +} + +void +win_del(void *data, Evas_Object *o, void *ev) +{ + elm_exit(); +} + +int main(int argc, char **argv) +{ + //Show the result using EFL... + elm_init(argc, argv); + + Eo* win = elm_win_util_standard_add(nullptr, "TizenVG Test"); + evas_object_smart_callback_add(win, "delete,request", win_del, 0); + + // create a new glview object + Eo* gl = elm_glview_add(win); + glapi = elm_glview_gl_api_get(gl); + evas_object_size_hint_align_set(gl, EVAS_HINT_FILL, EVAS_HINT_FILL); + evas_object_size_hint_weight_set(gl, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + + elm_glview_mode_set(gl, ELM_GLVIEW_ALPHA); + elm_glview_resize_policy_set(gl, ELM_GLVIEW_RESIZE_POLICY_RECREATE); + elm_glview_render_policy_set(gl, ELM_GLVIEW_RENDER_POLICY_ON_DEMAND); + + evas_object_resize(gl, WIDTH, HEIGHT); + + // initialize callback function gets registered here + elm_glview_init_func_set(gl, init_gl); + // delete callback function gets registered here + elm_glview_del_func_set(gl, del_gl); + elm_glview_render_func_set(gl, draw_gl); + + evas_object_show(gl); + + elm_object_focus_set(gl, EINA_TRUE); + + evas_object_geometry_set(win, 0, 0, WIDTH, HEIGHT); + evas_object_show(win); + + elm_run(); + elm_shutdown(); + + return 0; +} -- 2.7.4 From 9f82ea86a84a5713d2dad6ff1ef3ba185c8072c2 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Thu, 18 Jun 2020 18:41:10 +0900 Subject: [PATCH 11/16] test: revise glShape sample. turn on gl window for testing. Change-Id: I8a965f820d4a09697bc4145147cb0940672933be --- test/testGlShape.cpp | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/test/testGlShape.cpp b/test/testGlShape.cpp index 077057e..3ff4a33 100755 --- a/test/testGlShape.cpp +++ b/test/testGlShape.cpp @@ -12,10 +12,6 @@ static unique_ptr canvas; static void tvgtest() { - //Initialize TizenVG Engine - tvg::Initializer::init(tvg::CanvasEngine::Gl); - - //Create a Canvas canvas = tvg::GlCanvas::gen(); canvas->target(nullptr, WIDTH * BPP, WIDTH, HEIGHT); @@ -40,6 +36,9 @@ tvgtest() static void init_gl(Evas_Object *obj) { + //Initialize TizenVG Engine + tvg::Initializer::init(tvg::CanvasEngine::Gl); + tvgtest(); } @@ -78,10 +77,12 @@ int main(int argc, char **argv) //Show the result using EFL... elm_init(argc, argv); + elm_config_accel_preference_set("gl"); + Eo* win = elm_win_util_standard_add(nullptr, "TizenVG Test"); evas_object_smart_callback_add(win, "delete,request", win_del, 0); - // create a new glview object + //Create a new glview object Eo* gl = elm_glview_add(win); glapi = elm_glview_gl_api_get(gl); evas_object_size_hint_align_set(gl, EVAS_HINT_FILL, EVAS_HINT_FILL); @@ -93,16 +94,14 @@ int main(int argc, char **argv) evas_object_resize(gl, WIDTH, HEIGHT); - // initialize callback function gets registered here + //Initialize callback function gets registered here elm_glview_init_func_set(gl, init_gl); - // delete callback function gets registered here + //Delete callback function gets registered here elm_glview_del_func_set(gl, del_gl); elm_glview_render_func_set(gl, draw_gl); evas_object_show(gl); - elm_object_focus_set(gl, EINA_TRUE); - evas_object_geometry_set(win, 0, 0, WIDTH, HEIGHT); evas_object_show(win); -- 2.7.4 From 0e25879d1285e748b1e94d89ab7b0c8e4dad28d4 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Thu, 18 Jun 2020 18:44:52 +0900 Subject: [PATCH 12/16] correct unmatched files permission. Please keep file permission 664. Change-Id: I90bdfa76b4f94a06d3b560df42509f30e59111a4 --- src/lib/gl_engine/meson.build | 0 src/lib/gl_engine/tvgGlCommon.h | 0 src/lib/gl_engine/tvgGlGeometry.cpp | 0 src/lib/gl_engine/tvgGlGeometry.h | 0 src/lib/gl_engine/tvgGlGpuBuffer.cpp | 0 src/lib/gl_engine/tvgGlGpuBuffer.h | 0 src/lib/gl_engine/tvgGlProgram.cpp | 0 src/lib/gl_engine/tvgGlProgram.h | 0 src/lib/gl_engine/tvgGlRenderer.cpp | 0 src/lib/gl_engine/tvgGlRenderer.h | 0 src/lib/gl_engine/tvgGlShader.cpp | 0 src/lib/gl_engine/tvgGlShader.h | 0 src/lib/gl_engine/tvgGlShaderSrc.cpp | 0 src/lib/gl_engine/tvgGlShaderSrc.h | 0 src/lib/tvgGlCanvas.cpp | 0 src/lib/tvgRenderCommon.h | 0 src/lib/tvgShape.cpp | 0 test/testGlShape.cpp | 0 18 files changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 src/lib/gl_engine/meson.build mode change 100755 => 100644 src/lib/gl_engine/tvgGlCommon.h mode change 100755 => 100644 src/lib/gl_engine/tvgGlGeometry.cpp mode change 100755 => 100644 src/lib/gl_engine/tvgGlGeometry.h mode change 100755 => 100644 src/lib/gl_engine/tvgGlGpuBuffer.cpp mode change 100755 => 100644 src/lib/gl_engine/tvgGlGpuBuffer.h mode change 100755 => 100644 src/lib/gl_engine/tvgGlProgram.cpp mode change 100755 => 100644 src/lib/gl_engine/tvgGlProgram.h mode change 100755 => 100644 src/lib/gl_engine/tvgGlRenderer.cpp mode change 100755 => 100644 src/lib/gl_engine/tvgGlRenderer.h mode change 100755 => 100644 src/lib/gl_engine/tvgGlShader.cpp mode change 100755 => 100644 src/lib/gl_engine/tvgGlShader.h mode change 100755 => 100644 src/lib/gl_engine/tvgGlShaderSrc.cpp mode change 100755 => 100644 src/lib/gl_engine/tvgGlShaderSrc.h mode change 100755 => 100644 src/lib/tvgGlCanvas.cpp mode change 100755 => 100644 src/lib/tvgRenderCommon.h mode change 100755 => 100644 src/lib/tvgShape.cpp mode change 100755 => 100644 test/testGlShape.cpp diff --git a/src/lib/gl_engine/meson.build b/src/lib/gl_engine/meson.build old mode 100755 new mode 100644 diff --git a/src/lib/gl_engine/tvgGlCommon.h b/src/lib/gl_engine/tvgGlCommon.h old mode 100755 new mode 100644 diff --git a/src/lib/gl_engine/tvgGlGeometry.cpp b/src/lib/gl_engine/tvgGlGeometry.cpp old mode 100755 new mode 100644 diff --git a/src/lib/gl_engine/tvgGlGeometry.h b/src/lib/gl_engine/tvgGlGeometry.h old mode 100755 new mode 100644 diff --git a/src/lib/gl_engine/tvgGlGpuBuffer.cpp b/src/lib/gl_engine/tvgGlGpuBuffer.cpp old mode 100755 new mode 100644 diff --git a/src/lib/gl_engine/tvgGlGpuBuffer.h b/src/lib/gl_engine/tvgGlGpuBuffer.h old mode 100755 new mode 100644 diff --git a/src/lib/gl_engine/tvgGlProgram.cpp b/src/lib/gl_engine/tvgGlProgram.cpp old mode 100755 new mode 100644 diff --git a/src/lib/gl_engine/tvgGlProgram.h b/src/lib/gl_engine/tvgGlProgram.h old mode 100755 new mode 100644 diff --git a/src/lib/gl_engine/tvgGlRenderer.cpp b/src/lib/gl_engine/tvgGlRenderer.cpp old mode 100755 new mode 100644 diff --git a/src/lib/gl_engine/tvgGlRenderer.h b/src/lib/gl_engine/tvgGlRenderer.h old mode 100755 new mode 100644 diff --git a/src/lib/gl_engine/tvgGlShader.cpp b/src/lib/gl_engine/tvgGlShader.cpp old mode 100755 new mode 100644 diff --git a/src/lib/gl_engine/tvgGlShader.h b/src/lib/gl_engine/tvgGlShader.h old mode 100755 new mode 100644 diff --git a/src/lib/gl_engine/tvgGlShaderSrc.cpp b/src/lib/gl_engine/tvgGlShaderSrc.cpp old mode 100755 new mode 100644 diff --git a/src/lib/gl_engine/tvgGlShaderSrc.h b/src/lib/gl_engine/tvgGlShaderSrc.h old mode 100755 new mode 100644 diff --git a/src/lib/tvgGlCanvas.cpp b/src/lib/tvgGlCanvas.cpp old mode 100755 new mode 100644 diff --git a/src/lib/tvgRenderCommon.h b/src/lib/tvgRenderCommon.h old mode 100755 new mode 100644 diff --git a/src/lib/tvgShape.cpp b/src/lib/tvgShape.cpp old mode 100755 new mode 100644 diff --git a/test/testGlShape.cpp b/test/testGlShape.cpp old mode 100755 new mode 100644 -- 2.7.4 From 01e52c7c7aaeeeb4018022023ff53673d7a2114d Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Fri, 19 Jun 2020 14:49:07 +0900 Subject: [PATCH 13/16] common loader: build up loader infrastructure. Change-Id: I62aaed43015301ec39e414833f37d6c5485d8043 --- .gitignore | 1 - inc/tizenvg.h | 5 +-- src/lib/gl_engine/meson.build | 2 +- src/lib/meson.build | 3 ++ src/lib/sw_engine/meson.build | 2 +- src/lib/tvgCommon.h | 2 + src/lib/tvgInitializer.cpp | 7 +-- src/lib/tvgLoader.h | 36 +++++++++++++++ src/lib/tvgLoaderMgr.cpp | 52 +++++++++++++++++++++ src/lib/tvgLoaderMgr.h | 27 +++++++++++ src/lib/tvgScene.cpp | 16 +------ src/lib/tvgSceneImpl.h | 21 ++++++--- src/loaders/meson.build | 1 + src/loaders/svg_loader/meson.build | 9 ++++ src/loaders/svg_loader/tvgSvgLoader.cpp | 80 +++++++++++++++++++++++++++++++++ src/loaders/svg_loader/tvgSvgLoader.h | 38 ++++++++++++++++ src/meson.build | 6 ++- test/makefile | 3 +- test/testSvg.cpp | 4 +- test/testSvg2.cpp | 67 --------------------------- 20 files changed, 279 insertions(+), 103 deletions(-) create mode 100644 src/lib/tvgLoader.h create mode 100644 src/lib/tvgLoaderMgr.cpp create mode 100644 src/lib/tvgLoaderMgr.h create mode 100644 src/loaders/meson.build create mode 100644 src/loaders/svg_loader/meson.build create mode 100644 src/loaders/svg_loader/tvgSvgLoader.cpp create mode 100644 src/loaders/svg_loader/tvgSvgLoader.h delete mode 100644 test/testSvg2.cpp diff --git a/.gitignore b/.gitignore index af30a22..7aa8bd7 100644 --- a/.gitignore +++ b/.gitignore @@ -18,5 +18,4 @@ testLinearGradient testRadialGradient testGradientTransform testSvg -testSvg2 testGlShape diff --git a/inc/tizenvg.h b/inc/tizenvg.h index c62dda2..bc541b3 100644 --- a/inc/tizenvg.h +++ b/inc/tizenvg.h @@ -64,7 +64,7 @@ class Scene; class Canvas; -enum class TVG_EXPORT Result { Success = 0, InvalidArguments, InsufficientCondition, FailedAllocation, MemoryCorruption, Unknown }; +enum class TVG_EXPORT Result { Success = 0, InvalidArguments, InsufficientCondition, FailedAllocation, MemoryCorruption, NonSupport, Unknown }; enum class TVG_EXPORT PathCommand { Close = 0, MoveTo, LineTo, CubicTo }; enum class TVG_EXPORT StrokeCap { Square = 0, Round, Butt }; enum class TVG_EXPORT StrokeJoin { Bevel = 0, Round, Miter }; @@ -283,8 +283,7 @@ public: Result push(std::unique_ptr paint) noexcept; Result reserve(uint32_t size) noexcept; - Result load(const std::string& path, float w, float h, bool lazy = false) noexcept; - Result save(const std::string& path) noexcept; + Result load(const std::string& path) noexcept; Result rotate(float degree) noexcept override; Result scale(float factor) noexcept override; diff --git a/src/lib/gl_engine/meson.build b/src/lib/gl_engine/meson.build index a5409a7..943fb06 100644 --- a/src/lib/gl_engine/meson.build +++ b/src/lib/gl_engine/meson.build @@ -14,7 +14,7 @@ source_file = [ 'tvgGlShaderSrc.cpp', ] -glraster_dep = declare_dependency( +glengine_dep = declare_dependency( include_directories : include_directories('.'), sources : source_file ) diff --git a/src/lib/meson.build b/src/lib/meson.build index c936501..32db5f1 100644 --- a/src/lib/meson.build +++ b/src/lib/meson.build @@ -4,6 +4,8 @@ subdir('gl_engine') source_file = [ 'tvgCanvasImpl.h', 'tvgCommon.h', + 'tvgLoader.h', + 'tvgLoaderMgr.h', 'tvgRenderCommon.h', 'tvgSceneImpl.h', 'tvgShapePath.h', @@ -13,6 +15,7 @@ source_file = [ 'tvgGlCanvas.cpp', 'tvgInitializer.cpp', 'tvgLinearGradient.cpp', + 'tvgLoaderMgr.cpp', 'tvgRadialGradient.cpp', 'tvgScene.cpp', 'tvgShape.cpp', diff --git a/src/lib/sw_engine/meson.build b/src/lib/sw_engine/meson.build index f96fe97..8b06258 100644 --- a/src/lib/sw_engine/meson.build +++ b/src/lib/sw_engine/meson.build @@ -10,7 +10,7 @@ source_file = [ 'tvgSwStroke.cpp', ] -swraster_dep = declare_dependency( +swengine_dep = declare_dependency( include_directories : include_directories('.'), sources : source_file ) diff --git a/src/lib/tvgCommon.h b/src/lib/tvgCommon.h index 49c3f96..d147521 100644 --- a/src/lib/tvgCommon.h +++ b/src/lib/tvgCommon.h @@ -37,6 +37,8 @@ using namespace tvg; #define FILL_ID_LINEAR 0 #define FILL_ID_RADIAL 1 +#include "tvgLoader.h" +#include "tvgLoaderMgr.h" #include "tvgRenderCommon.h" #include "tvgShapePath.h" #include "tvgShapeImpl.h" diff --git a/src/lib/tvgInitializer.cpp b/src/lib/tvgInitializer.cpp index ac6ce3a..857698d 100644 --- a/src/lib/tvgInitializer.cpp +++ b/src/lib/tvgInitializer.cpp @@ -20,6 +20,7 @@ #include "tvgCommon.h" #include "tvgSwRenderer.h" #include "tvgGlRenderer.h" +#include "tvgLoaderMgr.h" /************************************************************************/ /* Internal Class Implementation */ @@ -39,9 +40,7 @@ Result Initializer::init(CanvasEngine engine) noexcept return Result::InvalidArguments; } - //TODO: check modules then enable them - //1. TVG - //2. SVG + if (!LoaderMgr::init()) return Result::Unknown; return Result::Success; } @@ -59,6 +58,8 @@ Result Initializer::term(CanvasEngine engine) noexcept return Result::InvalidArguments; } + if (!LoaderMgr::term()) return Result::Unknown; + return Result::Success; } diff --git a/src/lib/tvgLoader.h b/src/lib/tvgLoader.h new file mode 100644 index 0000000..8a1c918 --- /dev/null +++ b/src/lib/tvgLoader.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#ifndef _TVG_LOADER_H_ +#define _TVG_LOADER_H_ + +namespace tvg +{ + +class Loader +{ +public: + virtual ~Loader() {} + + virtual bool open(const char* path) = 0; + virtual bool read() = 0; + virtual bool close() = 0; + virtual unique_ptr data() = 0; +}; + +} + +#endif //_TVG_LOADER_H_ \ No newline at end of file diff --git a/src/lib/tvgLoaderMgr.cpp b/src/lib/tvgLoaderMgr.cpp new file mode 100644 index 0000000..a99838b --- /dev/null +++ b/src/lib/tvgLoaderMgr.cpp @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#ifndef _TVG_LOADER_MGR_CPP_ +#define _TVG_LOADER_MGR_CPP_ + +#include "tvgCommon.h" +#include "tvgSvgLoader.h" + + +static int initCnt = 0; + +bool LoaderMgr::init() +{ + if (initCnt > 0) return true; + ++initCnt; + + //TODO: + + return true; +} + +bool LoaderMgr::term() +{ + --initCnt; + if (initCnt > 0) return true; + + //TODO: + + return true; +} + +unique_ptr LoaderMgr::loader(const char* path) +{ + //TODO: + return unique_ptr(new SvgLoader); +} + +#endif //_TVG_LOADER_MGR_CPP_ \ No newline at end of file diff --git a/src/lib/tvgLoaderMgr.h b/src/lib/tvgLoaderMgr.h new file mode 100644 index 0000000..0d37012 --- /dev/null +++ b/src/lib/tvgLoaderMgr.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#ifndef _TVG_LOADER_MGR_H_ +#define _TVG_LOADER_MGR_H_ + +struct LoaderMgr +{ + static bool init(); + static bool term(); + static unique_ptr loader(const char* path); +}; + +#endif //_TVG_LOADER_MGR_H_ \ No newline at end of file diff --git a/src/lib/tvgScene.cpp b/src/lib/tvgScene.cpp index c093933..41620a0 100644 --- a/src/lib/tvgScene.cpp +++ b/src/lib/tvgScene.cpp @@ -108,26 +108,14 @@ Result Scene::bounds(float* x, float* y, float* w, float* h) const noexcept } -Result Scene::load(const std::string& path, float w, float h, bool lazy) noexcept +Result Scene::load(const std::string& path) noexcept { if (path.empty()) return Result::InvalidArguments; auto impl = pImpl.get(); if (!impl) return Result::MemoryCorruption; - return impl->load(path, w, h, lazy); + return impl->load(path); } - -Result Scene::save(const std::string& path) noexcept -{ - if (path.empty()) return Result::InvalidArguments; - - auto impl = pImpl.get(); - if (!impl) return Result::MemoryCorruption; - - return impl->save(path); -} - - #endif /* _TVG_SCENE_CPP_ */ \ No newline at end of file diff --git a/src/lib/tvgSceneImpl.h b/src/lib/tvgSceneImpl.h index 5ba8d51..5e67a66 100644 --- a/src/lib/tvgSceneImpl.h +++ b/src/lib/tvgSceneImpl.h @@ -28,6 +28,7 @@ struct Scene::Impl vector paints; RenderTransform *transform = nullptr; uint32_t flag = RenderUpdateFlag::None; + unique_ptr loader = nullptr; ~Impl() { @@ -71,6 +72,15 @@ struct Scene::Impl bool update(RenderMethod &renderer, const RenderTransform* pTransform = nullptr, uint32_t pFlag = 0) { + if (loader) { + auto scene = loader->data(); + auto p = scene.release(); + if (!p) return false; + paints.push_back(p); + loader->close(); + loader.reset(nullptr); + } + if (flag & RenderUpdateFlag::Transform) { if (!transform) return false; if (!transform->update()) { @@ -192,13 +202,12 @@ struct Scene::Impl return true; } - Result load(const string& path, float w, float h, bool lazy) - { - return Result::Success; - } - - Result save(const string& path) + Result load(const string& path) { + if (loader) loader->close(); + loader = LoaderMgr::loader(path.c_str()); + if (!loader || !loader->open(path.c_str())) return Result::NonSupport; + if (!loader->read()) return Result::Unknown; return Result::Success; } }; diff --git a/src/loaders/meson.build b/src/loaders/meson.build new file mode 100644 index 0000000..53186dd --- /dev/null +++ b/src/loaders/meson.build @@ -0,0 +1 @@ +subdir('svg_loader') diff --git a/src/loaders/svg_loader/meson.build b/src/loaders/svg_loader/meson.build new file mode 100644 index 0000000..1bd40c1 --- /dev/null +++ b/src/loaders/svg_loader/meson.build @@ -0,0 +1,9 @@ +source_file = [ + 'tvgSvgLoader.h', + 'tvgSvgLoader.cpp', +] + +svgloader_dep = declare_dependency( + include_directories : include_directories('.'), + sources : source_file +) diff --git a/src/loaders/svg_loader/tvgSvgLoader.cpp b/src/loaders/svg_loader/tvgSvgLoader.cpp new file mode 100644 index 0000000..f4b8f43 --- /dev/null +++ b/src/loaders/svg_loader/tvgSvgLoader.cpp @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#ifndef _TVG_SVG_LOADER_CPP_ +#define _TVG_SVG_LOADER_CPP_ + +#include "tvgSvgLoader.h" + + +/************************************************************************/ +/* Internal Class Implementation */ +/************************************************************************/ + + + +/************************************************************************/ +/* External Class Implementation */ +/************************************************************************/ + +SvgLoader::SvgLoader() +{ + cout << "SvgLoader()" << endl; +} + + +SvgLoader::~SvgLoader() +{ + cout << "~SvgLoader()" << endl; +} + + +bool SvgLoader::open(const char* path) +{ + //TODO: + cout << "SvgLoader::open()" << endl; + + return false; +} + + +bool SvgLoader::read() +{ + //TODO: + cout << "SvgLoader::read()" << endl; + + return false; +} + + +bool SvgLoader::close() +{ + //TODO: + cout << "SvgLoader::close()" << endl; + + return false; +} + + +unique_ptr SvgLoader::data() +{ + //TODO: + cout << "SvgLoader::data()" << endl; + + return nullptr; +} + +#endif //_TVG_SVG_LOADER_CPP_ \ No newline at end of file diff --git a/src/loaders/svg_loader/tvgSvgLoader.h b/src/loaders/svg_loader/tvgSvgLoader.h new file mode 100644 index 0000000..2b4d8b1 --- /dev/null +++ b/src/loaders/svg_loader/tvgSvgLoader.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#ifndef _TVG_SVG_LOADER_H_ +#define _TVG_SVG_LOADER_H_ + +#include "tvgCommon.h" + +class SvgLoader : public Loader +{ +private: + //TODO: + +public: + SvgLoader(); + ~SvgLoader(); + + bool open(const char* path) override; + bool read() override; + bool close() override; + unique_ptr data() override; +}; + + +#endif //_TVG_SVG_LOADER_H_ \ No newline at end of file diff --git a/src/meson.build b/src/meson.build index a0ef37d..e49c9a0 100644 --- a/src/meson.build +++ b/src/meson.build @@ -1,12 +1,14 @@ compiler_flags = ['-DTVG_BUILD'] subdir('lib') +subdir('loaders') subdir('examples') + m_dep = meson.get_compiler('cpp').find_library('m') egl_dep = meson.get_compiler('cpp').find_library('EGL') -gl_dep = meson.get_compiler('cpp').find_library('GLESv2') +gles_dep = meson.get_compiler('cpp').find_library('GLESv2') -tizenvg_lib_dep = [ src_dep, swraster_dep, glraster_dep, m_dep, egl_dep, gl_dep] +tizenvg_lib_dep = [ src_dep, swengine_dep, glengine_dep, m_dep, egl_dep, gles_dep, svgloader_dep] tizenvg_lib = library( diff --git a/test/makefile b/test/makefile index aca250b..501eef5 100755 --- a/test/makefile +++ b/test/makefile @@ -15,6 +15,5 @@ all: gcc -o testLinearGradient testLinearGradient.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` gcc -o testRadialGradient testRadialGradient.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` gcc -o testGradientTransform testGradientTransform.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` -# gcc -o testSvg testSvg.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` -# gcc -o testSvg2 testSvg2.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` + gcc -o testSvg testSvg.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` gcc -o testGlShape testGlShape.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` diff --git a/test/testSvg.cpp b/test/testSvg.cpp index dea96a2..e918902 100644 --- a/test/testSvg.cpp +++ b/test/testSvg.cpp @@ -17,9 +17,7 @@ void tvgtest() auto canvas = tvg::SwCanvas::gen(); canvas->target(buffer, WIDTH, WIDTH, HEIGHT); - /* Create a SVG scene, keep original size, - You can pass 0 x 0 size for lazying loading in this case. - scene->load("sample.svg", 0, 0, true); */ + // Create a SVG scene, request the original size, auto scene = tvg::Scene::gen(); scene->load("sample.svg"); canvas->push(move(scene)); diff --git a/test/testSvg2.cpp b/test/testSvg2.cpp deleted file mode 100644 index 4714db6..0000000 --- a/test/testSvg2.cpp +++ /dev/null @@ -1,67 +0,0 @@ -#include -#include - -using namespace std; - -#define WIDTH 800 -#define HEIGHT 800 - -static uint32_t buffer[WIDTH * HEIGHT]; - -void tvgtest() -{ - //Initialize TizenVG Engine - tvg::Initializer::init(tvg::CanvasEngine::Sw); - - //Create a Canvas - auto canvas = tvg::SwCanvas::gen(); - canvas->target(buffer, WIDTH, WIDTH, HEIGHT); - - //Create a SVG scene, keep aspect ratio to width/2 with lazy loading - auto scene = tvg::Scene::gen(); - scene->load("sample.svg", WIDTH/2, 0, true); - canvas->push(move(scene)); - - //Create a SVG scene, keep aspect ratio to height/2 with lazy loading - auto scene2 = tvg::Scene::gen(); - scene2->load("sample.svg", 0, HEIGHT/2, true); - scene2->translate(WIDTH/2, HEIGHT/2); - canvas->push(move(scene2)); - - canvas->draw(); - canvas->sync(); - - //Terminate TizenVG Engine - tvg::Initializer::term(tvg::CanvasEngine::Sw); -} - -void -win_del(void *data, Evas_Object *o, void *ev) -{ - elm_exit(); -} - - -int main(int argc, char **argv) -{ - tvgtest(); - - //Show the result using EFL... - elm_init(argc, argv); - - Eo* win = elm_win_util_standard_add(NULL, "TizenVG Test"); - evas_object_smart_callback_add(win, "delete,request", win_del, 0); - - Eo* img = evas_object_image_filled_add(evas_object_evas_get(win)); - evas_object_image_size_set(img, WIDTH, HEIGHT); - evas_object_image_data_set(img, buffer); - evas_object_size_hint_weight_set(img, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); - evas_object_show(img); - - elm_win_resize_object_add(win, img); - evas_object_geometry_set(win, 0, 0, WIDTH, HEIGHT); - evas_object_show(win); - - elm_run(); - elm_shutdown(); -} -- 2.7.4 From 538254a32d83a49e65565ab50c5af5eaeb3dd812 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Mon, 22 Jun 2020 16:30:18 +0900 Subject: [PATCH 14/16] common render: code refactoring. just replace the filename. Change-Id: I6b18520d33c7db3ac9d6c44b10dd693b204495e5 --- src/lib/{tvgRenderCommon.h => tvgRender.h} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/lib/{tvgRenderCommon.h => tvgRender.h} (100%) diff --git a/src/lib/tvgRenderCommon.h b/src/lib/tvgRender.h similarity index 100% rename from src/lib/tvgRenderCommon.h rename to src/lib/tvgRender.h -- 2.7.4 From f56a3b791c0f8a229c84fba232b4f35975abc36c Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Mon, 22 Jun 2020 16:44:11 +0900 Subject: [PATCH 15/16] comon render: split declaration and body. Change-Id: I39eb1dfb929b7811fab82956aedbb15f001390e7 --- src/lib/meson.build | 3 +- src/lib/tvgCommon.h | 2 +- src/lib/tvgRender.cpp | 109 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/lib/tvgRender.h | 81 +++---------------------------------- 4 files changed, 118 insertions(+), 77 deletions(-) create mode 100644 src/lib/tvgRender.cpp diff --git a/src/lib/meson.build b/src/lib/meson.build index 32db5f1..9675206 100644 --- a/src/lib/meson.build +++ b/src/lib/meson.build @@ -6,7 +6,7 @@ source_file = [ 'tvgCommon.h', 'tvgLoader.h', 'tvgLoaderMgr.h', - 'tvgRenderCommon.h', + 'tvgRender.h', 'tvgSceneImpl.h', 'tvgShapePath.h', 'tvgShapeImpl.h', @@ -17,6 +17,7 @@ source_file = [ 'tvgLinearGradient.cpp', 'tvgLoaderMgr.cpp', 'tvgRadialGradient.cpp', + 'tvgRender.cpp', 'tvgScene.cpp', 'tvgShape.cpp', 'tvgSwCanvas.cpp', diff --git a/src/lib/tvgCommon.h b/src/lib/tvgCommon.h index d147521..2b0e9c1 100644 --- a/src/lib/tvgCommon.h +++ b/src/lib/tvgCommon.h @@ -39,7 +39,7 @@ using namespace tvg; #include "tvgLoader.h" #include "tvgLoaderMgr.h" -#include "tvgRenderCommon.h" +#include "tvgRender.h" #include "tvgShapePath.h" #include "tvgShapeImpl.h" #include "tvgSceneImpl.h" diff --git a/src/lib/tvgRender.cpp b/src/lib/tvgRender.cpp new file mode 100644 index 0000000..4b4afc3 --- /dev/null +++ b/src/lib/tvgRender.cpp @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#ifndef _TVG_RENDER_CPP_ +#define _TVG_RENDER_CPP_ + +#include "tvgCommon.h" +#include "tvgRender.h" + + +/************************************************************************/ +/* Internal Class Implementation */ +/************************************************************************/ + + +/************************************************************************/ +/* External Class Implementation */ +/************************************************************************/ + +bool RenderTransform::update() +{ + constexpr auto PI = 3.141592f; + + //Init Status + if (fabsf(x) <= FLT_EPSILON && fabsf(y) <= FLT_EPSILON && + fabsf(degree) <= FLT_EPSILON && fabsf(factor - 1) <= FLT_EPSILON) { + return false; + } + + //identity + e11 = 1.0f; + e12 = 0.0f; + e13 = 0.0f; + e21 = 0.0f; + e22 = 1.0f; + e23 = 0.0f; + e31 = 0.0f; + e32 = 0.0f; + e33 = 1.0f; + + //scale + e11 *= factor; + e22 *= factor; + e33 *= factor; + + //rotation + if (fabsf(degree) > FLT_EPSILON) { + auto radian = degree / 180.0f * PI; + auto cosVal = cosf(radian); + auto sinVal = sinf(radian); + + auto t11 = e11 * cosVal + e12 * sinVal; + auto t12 = e11 * -sinVal + e12 * cosVal; + auto t21 = e21 * cosVal + e22 * sinVal; + auto t22 = e21 * -sinVal + e22 * cosVal; + auto t31 = e31 * cosVal + e32 * sinVal; + auto t32 = e31 * -sinVal + e32 * cosVal; + + e11 = t11; + e12 = t12; + e21 = t21; + e22 = t22; + e31 = t31; + e32 = t32; + } + + e31 += x; + e32 += y; + + return true; +} + + +RenderTransform::RenderTransform() +{ +} + + +RenderTransform::RenderTransform(const RenderTransform* lhs, const RenderTransform* rhs) +{ + assert(lhs && rhs); + + auto dx = rhs->x * lhs->factor; + auto dy = rhs->y * lhs->factor; + auto tx = dx * lhs->e11 + dy * lhs->e12 + lhs->e13; + auto ty = dx * lhs->e21 + dy * lhs->e22 + lhs->e23; + + x = lhs->x + tx; + y = lhs->y + ty; + degree = lhs->degree + rhs->degree; + factor = lhs->factor * rhs->factor; + + update(); +} + +#endif //_TVG_RENDER_CPP_ diff --git a/src/lib/tvgRender.h b/src/lib/tvgRender.h index a581067..74feb77 100644 --- a/src/lib/tvgRender.h +++ b/src/lib/tvgRender.h @@ -14,8 +14,8 @@ * limitations under the License. * */ -#ifndef _TVG_RENDER_COMMON_H_ -#define _TVG_RENDER_COMMON_H_ +#ifndef _TVG_RENDER_H_ +#define _TVG_RENDER_H_ namespace tvg { @@ -42,79 +42,10 @@ struct RenderTransform float degree = 0.0f; //rotation degree float factor = 1.0f; //scale factor - bool update() - { - constexpr auto PI = 3.141592f; - - //Init Status - if (fabsf(x) <= FLT_EPSILON && fabsf(y) <= FLT_EPSILON && - fabsf(degree) <= FLT_EPSILON && fabsf(factor - 1) <= FLT_EPSILON) { - return false; - } - - //identity - e11 = 1.0f; - e12 = 0.0f; - e13 = 0.0f; - e21 = 0.0f; - e22 = 1.0f; - e23 = 0.0f; - e31 = 0.0f; - e32 = 0.0f; - e33 = 1.0f; - - //scale - e11 *= factor; - e22 *= factor; - e33 *= factor; - - //rotation - if (fabsf(degree) > FLT_EPSILON) { - auto radian = degree / 180.0f * PI; - auto cosVal = cosf(radian); - auto sinVal = sinf(radian); - - auto t11 = e11 * cosVal + e12 * sinVal; - auto t12 = e11 * -sinVal + e12 * cosVal; - auto t21 = e21 * cosVal + e22 * sinVal; - auto t22 = e21 * -sinVal + e22 * cosVal; - auto t31 = e31 * cosVal + e32 * sinVal; - auto t32 = e31 * -sinVal + e32 * cosVal; - - e11 = t11; - e12 = t12; - e21 = t21; - e22 = t22; - e31 = t31; - e32 = t32; - } - - e31 += x; - e32 += y; - - return true; - } + bool update(); - RenderTransform() - { - } - - RenderTransform(const RenderTransform* lhs, const RenderTransform* rhs) - { - assert(lhs && rhs); - - auto dx = rhs->x * lhs->factor; - auto dy = rhs->y * lhs->factor; - auto tx = dx * lhs->e11 + dy * lhs->e12 + lhs->e13; - auto ty = dx * lhs->e21 + dy * lhs->e22 + lhs->e23; - - x = lhs->x + tx; - y = lhs->y + ty; - degree = lhs->degree + rhs->degree; - factor = lhs->factor * rhs->factor; - - update(); - } + RenderTransform(); + RenderTransform(const RenderTransform* lhs, const RenderTransform* rhs); }; @@ -190,4 +121,4 @@ struct RenderInitializer } -#endif //_TVG_RENDER_COMMON_H_ +#endif //_TVG_RENDER_H_ \ No newline at end of file -- 2.7.4 From ab5c1bc44180a256c6b9f02f26fcff40e7f0bf16 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Mon, 22 Jun 2020 17:06:53 +0900 Subject: [PATCH 16/16] common bezier: code refactoring. Organize bezier functions for internal share. this bezier can be used in svg loader. Change-Id: I78acd3273c0528688ca46ff7c29d78607bd729bd --- src/lib/meson.build | 2 + src/lib/sw_engine/tvgSwShape.cpp | 109 +---------------------------- src/lib/tvgBezier.cpp | 144 +++++++++++++++++++++++++++++++++++++++ src/lib/tvgBezier.h | 39 +++++++++++ src/lib/tvgCommon.h | 1 + src/lib/tvgRender.cpp | 2 - 6 files changed, 188 insertions(+), 109 deletions(-) create mode 100644 src/lib/tvgBezier.cpp create mode 100644 src/lib/tvgBezier.h diff --git a/src/lib/meson.build b/src/lib/meson.build index 9675206..53c9a19 100644 --- a/src/lib/meson.build +++ b/src/lib/meson.build @@ -4,12 +4,14 @@ subdir('gl_engine') source_file = [ 'tvgCanvasImpl.h', 'tvgCommon.h', + 'tvgBezier.h', 'tvgLoader.h', 'tvgLoaderMgr.h', 'tvgRender.h', 'tvgSceneImpl.h', 'tvgShapePath.h', 'tvgShapeImpl.h', + 'tvgBezier.cpp', 'tvgCanvas.cpp', 'tvgFill.cpp', 'tvgGlCanvas.cpp', diff --git a/src/lib/sw_engine/tvgSwShape.cpp b/src/lib/sw_engine/tvgSwShape.cpp index 4d3c44e..ee599df 100644 --- a/src/lib/sw_engine/tvgSwShape.cpp +++ b/src/lib/sw_engine/tvgSwShape.cpp @@ -30,15 +30,6 @@ struct Line }; -struct Bezier -{ - Point start; - Point ctrl1; - Point ctrl2; - Point end; -}; - - static float _lineLength(const Point& pt1, const Point& pt2) { /* approximate sqrt(x*x + y*y) using alpha max plus beta min algorithm. @@ -64,102 +55,6 @@ static void _lineSplitAt(const Line& cur, float at, Line& left, Line& right) } -static void _bezSplit(const Bezier&cur, Bezier& left, Bezier& right) -{ - auto c = (cur.ctrl1.x + cur.ctrl2.x) * 0.5f; - left.ctrl1.x = (cur.start.x + cur.ctrl1.x) * 0.5f; - right.ctrl2.x = (cur.ctrl2.x + cur.end.x) * 0.5f; - left.start.x = cur.start.x; - right.end.x = cur.end.x; - left.ctrl2.x = (left.ctrl1.x + c) * 0.5f; - right.ctrl1.x = (right.ctrl2.x + c) * 0.5f; - left.end.x = right.start.x = (left.ctrl2.x + right.ctrl1.x) * 0.5f; - - c = (cur.ctrl1.y + cur.ctrl2.y) * 0.5f; - left.ctrl1.y = (cur.start.y + cur.ctrl1.y) * 0.5f; - right.ctrl2.y = (cur.ctrl2.y + cur.end.y) * 0.5f; - left.start.y = cur.start.y; - right.end.y = cur.end.y; - left.ctrl2.y = (left.ctrl1.y + c) * 0.5f; - right.ctrl1.y = (right.ctrl2.y + c) * 0.5f; - left.end.y = right.start.y = (left.ctrl2.y + right.ctrl1.y) * 0.5f; -} - - -static float _bezLength(const Bezier& cur) -{ - Bezier left, right; - auto len = _lineLength(cur.start, cur.ctrl1) + _lineLength(cur.ctrl1, cur.ctrl2) + _lineLength(cur.ctrl2, cur.end); - auto chord = _lineLength(cur.start, cur.end); - - if (fabs(len - chord) > FLT_EPSILON) { - _bezSplit(cur, left, right); - return _bezLength(left) + _bezLength(right); - } - return len; -} - - -static void _bezSplitLeft(Bezier& cur, float at, Bezier& left) -{ - left.start = cur.start; - - left.ctrl1.x = cur.start.x + at * (cur.ctrl1.x - cur.start.x); - left.ctrl1.y = cur.start.y + at * (cur.ctrl1.y - cur.start.y); - - left.ctrl2.x = cur.ctrl1.x + at * (cur.ctrl2.x - cur.ctrl1.x); // temporary holding spot - left.ctrl2.y = cur.ctrl1.y + at * (cur.ctrl2.y - cur.ctrl1.y); // temporary holding spot - - cur.ctrl2.x = cur.ctrl2.x + at * (cur.end.x - cur.ctrl2.x); - cur.ctrl2.y = cur.ctrl2.y + at * (cur.end.y - cur.ctrl2.y); - - cur.ctrl1.x = left.ctrl2.x + at * (cur.ctrl2.x - left.ctrl2.x); - cur.ctrl1.y = left.ctrl2.y + at * (cur.ctrl2.y - left.ctrl2.y); - - left.ctrl2.x = left.ctrl1.x + at * (left.ctrl2.x - left.ctrl1.x); - left.ctrl2.y = left.ctrl1.y + at * (left.ctrl2.y - left.ctrl1.y); - - left.end.x = cur.start.x = left.ctrl2.x + at * (cur.ctrl1.x - left.ctrl2.x); - left.end.y = cur.start.y = left.ctrl2.y + at * (cur.ctrl1.y - left.ctrl2.y); -} - - -static float _bezAt(const Bezier& bz, float at) -{ - auto len = _bezLength(bz); - auto biggest = 1.0f; - - if (at >= len) return 1.0f; - - at *= 0.5f; - - while (true) { - auto right = bz; - Bezier left; - _bezSplitLeft(right, at, left); - auto len2 = _bezLength(left); - - if (fabs(len2 - len) < FLT_EPSILON) break; - - if (len2 < len) { - at += (biggest - at) * 0.5f; - } else { - biggest = at; - at -= (at * 0.5f); - } - } - return at; -} - - -static void _bezSplitAt(const Bezier& cur, float at, Bezier& left, Bezier& right) -{ - right = cur; - auto t = _bezAt(right, at); - _bezSplitLeft(right, t, left); -} - - static void _growOutlineContour(SwOutline& outline, uint32_t n) { if (outline.reservedCntrsCnt >= outline.cntrsCnt + n) return; @@ -407,7 +302,7 @@ static void _dashCubicTo(SwDashStroke& dash, const Point* ctrl1, const Point* ct _growOutlineContour(*dash.outline, dash.outline->cntrsCnt >> 1); Bezier cur = { dash.ptCur, *ctrl1, *ctrl2, *to}; - auto len = _bezLength(cur); + auto len = bezLength(cur); if (len < dash.curLen) { dash.curLen -= len; @@ -419,7 +314,7 @@ static void _dashCubicTo(SwDashStroke& dash, const Point* ctrl1, const Point* ct while (len > dash.curLen) { Bezier left, right; len -= dash.curLen; - _bezSplitAt(cur, dash.curLen, left, right); + bezSplitAt(cur, dash.curLen, left, right); dash.curIdx = (dash.curIdx + 1) % dash.cnt; if (!dash.curOpGap) { _outlineMoveTo(*dash.outline, &left.start); diff --git a/src/lib/tvgBezier.cpp b/src/lib/tvgBezier.cpp new file mode 100644 index 0000000..1aa2dab --- /dev/null +++ b/src/lib/tvgBezier.cpp @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#ifndef _TVG_BEZIER_CPP_ +#define _TVG_BEZIER_CPP_ + +#include "tvgCommon.h" + + +/************************************************************************/ +/* Internal Class Implementation */ +/************************************************************************/ + +static float _lineLength(const Point& pt1, const Point& pt2) +{ + /* 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. */ + Point diff = {pt2.x - pt1.x, pt2.y - pt1.y}; + if (diff.x < 0) diff.x = -diff.x; + if (diff.y < 0) diff.y = -diff.y; + return (diff.x > diff.y) ? (diff.x + diff.y * 0.375f) : (diff.y + diff.x * 0.375f); +} + + +/************************************************************************/ +/* External Class Implementation */ +/************************************************************************/ + +namespace tvg +{ + +void bezSplit(const Bezier&cur, Bezier& left, Bezier& right) +{ + auto c = (cur.ctrl1.x + cur.ctrl2.x) * 0.5f; + left.ctrl1.x = (cur.start.x + cur.ctrl1.x) * 0.5f; + right.ctrl2.x = (cur.ctrl2.x + cur.end.x) * 0.5f; + left.start.x = cur.start.x; + right.end.x = cur.end.x; + left.ctrl2.x = (left.ctrl1.x + c) * 0.5f; + right.ctrl1.x = (right.ctrl2.x + c) * 0.5f; + left.end.x = right.start.x = (left.ctrl2.x + right.ctrl1.x) * 0.5f; + + c = (cur.ctrl1.y + cur.ctrl2.y) * 0.5f; + left.ctrl1.y = (cur.start.y + cur.ctrl1.y) * 0.5f; + right.ctrl2.y = (cur.ctrl2.y + cur.end.y) * 0.5f; + left.start.y = cur.start.y; + right.end.y = cur.end.y; + left.ctrl2.y = (left.ctrl1.y + c) * 0.5f; + right.ctrl1.y = (right.ctrl2.y + c) * 0.5f; + left.end.y = right.start.y = (left.ctrl2.y + right.ctrl1.y) * 0.5f; +} + + +float bezLength(const Bezier& cur) +{ + Bezier left, right; + auto len = _lineLength(cur.start, cur.ctrl1) + _lineLength(cur.ctrl1, cur.ctrl2) + _lineLength(cur.ctrl2, cur.end); + auto chord = _lineLength(cur.start, cur.end); + + if (fabs(len - chord) > FLT_EPSILON) { + bezSplit(cur, left, right); + return bezLength(left) + bezLength(right); + } + return len; +} + + +void bezSplitLeft(Bezier& cur, float at, Bezier& left) +{ + left.start = cur.start; + + left.ctrl1.x = cur.start.x + at * (cur.ctrl1.x - cur.start.x); + left.ctrl1.y = cur.start.y + at * (cur.ctrl1.y - cur.start.y); + + left.ctrl2.x = cur.ctrl1.x + at * (cur.ctrl2.x - cur.ctrl1.x); // temporary holding spot + left.ctrl2.y = cur.ctrl1.y + at * (cur.ctrl2.y - cur.ctrl1.y); // temporary holding spot + + cur.ctrl2.x = cur.ctrl2.x + at * (cur.end.x - cur.ctrl2.x); + cur.ctrl2.y = cur.ctrl2.y + at * (cur.end.y - cur.ctrl2.y); + + cur.ctrl1.x = left.ctrl2.x + at * (cur.ctrl2.x - left.ctrl2.x); + cur.ctrl1.y = left.ctrl2.y + at * (cur.ctrl2.y - left.ctrl2.y); + + left.ctrl2.x = left.ctrl1.x + at * (left.ctrl2.x - left.ctrl1.x); + left.ctrl2.y = left.ctrl1.y + at * (left.ctrl2.y - left.ctrl1.y); + + left.end.x = cur.start.x = left.ctrl2.x + at * (cur.ctrl1.x - left.ctrl2.x); + left.end.y = cur.start.y = left.ctrl2.y + at * (cur.ctrl1.y - left.ctrl2.y); +} + + +float bezAt(const Bezier& bz, float at) +{ + auto len = bezLength(bz); + auto biggest = 1.0f; + + if (at >= len) return 1.0f; + + at *= 0.5f; + + while (true) { + auto right = bz; + Bezier left; + bezSplitLeft(right, at, left); + auto len2 = bezLength(left); + + if (fabs(len2 - len) < FLT_EPSILON) break; + + if (len2 < len) { + at += (biggest - at) * 0.5f; + } else { + biggest = at; + at -= (at * 0.5f); + } + } + return at; +} + + +void bezSplitAt(const Bezier& cur, float at, Bezier& left, Bezier& right) +{ + right = cur; + auto t = bezAt(right, at); + bezSplitLeft(right, t, left); +} + + +} + +#endif //_TVG_BEZIER_CPP_ diff --git a/src/lib/tvgBezier.h b/src/lib/tvgBezier.h new file mode 100644 index 0000000..aa7d77f --- /dev/null +++ b/src/lib/tvgBezier.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#ifndef _TVG_BEZIER_H_ +#define _TVG_BEZIER_H_ + +namespace tvg +{ + +struct Bezier +{ + Point start; + Point ctrl1; + Point ctrl2; + Point end; +}; + +void bezSplit(const Bezier&cur, Bezier& left, Bezier& right); +float bezLength(const Bezier& cur); +void bezSplitLeft(Bezier& cur, float at, Bezier& left); +float bezAt(const Bezier& bz, float at); +void bezSplitAt(const Bezier& cur, float at, Bezier& left, Bezier& right); + +} + +#endif //_TVG_BEZIER_H_ \ No newline at end of file diff --git a/src/lib/tvgCommon.h b/src/lib/tvgCommon.h index 2b0e9c1..302f4e9 100644 --- a/src/lib/tvgCommon.h +++ b/src/lib/tvgCommon.h @@ -37,6 +37,7 @@ using namespace tvg; #define FILL_ID_LINEAR 0 #define FILL_ID_RADIAL 1 +#include "tvgBezier.h" #include "tvgLoader.h" #include "tvgLoaderMgr.h" #include "tvgRender.h" diff --git a/src/lib/tvgRender.cpp b/src/lib/tvgRender.cpp index 4b4afc3..bffbe40 100644 --- a/src/lib/tvgRender.cpp +++ b/src/lib/tvgRender.cpp @@ -18,8 +18,6 @@ #define _TVG_RENDER_CPP_ #include "tvgCommon.h" -#include "tvgRender.h" - /************************************************************************/ /* Internal Class Implementation */ -- 2.7.4