From 238ff8eda6d86002826d3dd670cfe989274514ab Mon Sep 17 00:00:00 2001 From: Hparty <420024556@qq.com> Date: Wed, 11 Dec 2024 17:26:41 +0800 Subject: [PATCH] LayerStyle supports deferred rendering. (#2607) Co-authored-by: libpag --- src/rendering/caches/RenderCache.cpp | 8 +- src/rendering/caches/RenderCache.h | 2 - src/rendering/filters/Filter.h | 2 +- src/rendering/filters/LayerFilter.cpp | 24 - src/rendering/filters/LayerFilter.h | 2 - src/rendering/filters/LayerStylesFilter.cpp | 55 +- src/rendering/filters/LayerStylesFilter.h | 13 +- src/rendering/filters/RuntimeFilter.cpp | 220 +++ src/rendering/filters/RuntimeFilter.h | 101 + .../layerstyle/AlphaEdgeDetectFilter.cpp | 23 +- .../layerstyle/AlphaEdgeDetectFilter.h | 35 +- .../filters/layerstyle/DropShadowFilter.cpp | 186 +- .../filters/layerstyle/DropShadowFilter.h | 50 +- .../GradientOverlayFilter.cpp | 54 +- .../{ => layerstyle}/GradientOverlayFilter.h | 19 +- .../filters/layerstyle/LayerStyleFilter.cpp | 51 + .../filters/layerstyle/LayerStyleFilter.h | 40 + .../filters/layerstyle/OuterGlowFilter.cpp | 180 +- .../filters/layerstyle/OuterGlowFilter.h | 48 +- .../filters/layerstyle/SolidStrokeFilter.cpp | 136 +- .../filters/layerstyle/SolidStrokeFilter.h | 116 +- .../filters/layerstyle/StrokeFilter.cpp | 133 +- .../filters/layerstyle/StrokeFilter.h | 39 +- src/rendering/filters/utils/FilterHelper.cpp | 23 +- src/rendering/filters/utils/FilterHelper.h | 6 + src/rendering/renderers/FilterRenderer.cpp | 8 +- test/baseline/version.json | 1630 ++++++++--------- 27 files changed, 1700 insertions(+), 1504 deletions(-) create mode 100644 src/rendering/filters/RuntimeFilter.cpp create mode 100644 src/rendering/filters/RuntimeFilter.h rename src/rendering/filters/{ => layerstyle}/GradientOverlayFilter.cpp (61%) rename src/rendering/filters/{ => layerstyle}/GradientOverlayFilter.h (65%) create mode 100644 src/rendering/filters/layerstyle/LayerStyleFilter.cpp create mode 100644 src/rendering/filters/layerstyle/LayerStyleFilter.h diff --git a/src/rendering/caches/RenderCache.cpp b/src/rendering/caches/RenderCache.cpp index 4009fea409..fc90059c71 100644 --- a/src/rendering/caches/RenderCache.cpp +++ b/src/rendering/caches/RenderCache.cpp @@ -568,12 +568,6 @@ void RenderCache::clearSequenceCache(ID uniqueID) { //===================================== filter caches ===================================== -LayerFilter* RenderCache::getFilterCache(LayerStyle* layerStyle) { - return getLayerFilterCache(layerStyle->uniqueID, [=]() -> LayerFilter* { - return LayerFilter::Make(layerStyle).release(); - }); -} - LayerFilter* RenderCache::getFilterCache(Effect* effect) { return getLayerFilterCache(effect->uniqueID, [=]() -> LayerFilter* { return LayerFilter::Make(effect).release(); }); @@ -620,7 +614,7 @@ LayerStylesFilter* RenderCache::getLayerStylesFilter(Layer* layer) { LayerStylesFilter* filter = nullptr; auto result = filterCaches.find(layer->uniqueID); if (result == filterCaches.end()) { - filter = new LayerStylesFilter(this); + filter = new LayerStylesFilter(); if (initFilter(filter)) { filterCaches.insert(std::make_pair(layer->uniqueID, filter)); } else { diff --git a/src/rendering/caches/RenderCache.h b/src/rendering/caches/RenderCache.h index e718ea987c..0952e3e419 100644 --- a/src/rendering/caches/RenderCache.h +++ b/src/rendering/caches/RenderCache.h @@ -153,8 +153,6 @@ class RenderCache : public Performance { std::shared_ptr getSequenceImage(std::shared_ptr sequence, Frame targetFrame); - LayerFilter* getFilterCache(LayerStyle* layerStyle); - LayerFilter* getFilterCache(Effect* effect); MotionBlurFilter* getMotionBlurFilter(); diff --git a/src/rendering/filters/Filter.h b/src/rendering/filters/Filter.h index 71ce2762a2..8b86df7aa4 100644 --- a/src/rendering/filters/Filter.h +++ b/src/rendering/filters/Filter.h @@ -19,7 +19,7 @@ #pragma once #include -#include "tgfx/core/Matrix.h" +#include "tgfx/core/Point.h" #include "tgfx/gpu/Backend.h" #include "tgfx/gpu/Context.h" diff --git a/src/rendering/filters/LayerFilter.cpp b/src/rendering/filters/LayerFilter.cpp index 4762bce3f2..5c4bdbd929 100644 --- a/src/rendering/filters/LayerFilter.cpp +++ b/src/rendering/filters/LayerFilter.cpp @@ -21,7 +21,6 @@ #include "BulgeFilter.h" #include "CornerPinFilter.h" #include "DisplacementMapFilter.h" -#include "GradientOverlayFilter.h" #include "HueSaturationFilter.h" #include "LevelsIndividualFilter.h" #include "MosaicFilter.h" @@ -30,8 +29,6 @@ #include "rendering/filters/gaussianblur/GaussianBlurFilter.h" #include "rendering/filters/glow/GlowFilter.h" #include "rendering/filters/layerstyle/DropShadowFilter.h" -#include "rendering/filters/layerstyle/OuterGlowFilter.h" -#include "rendering/filters/layerstyle/StrokeFilter.h" #include "rendering/filters/utils/FilterHelper.h" namespace pag { @@ -116,27 +113,6 @@ void FilterProgram::onReleaseGPU() { } } -std::unique_ptr LayerFilter::Make(LayerStyle* layerStyle) { - LayerFilter* filter = nullptr; - switch (layerStyle->type()) { - case LayerStyleType::DropShadow: - filter = new DropShadowFilter(reinterpret_cast(layerStyle)); - break; - case LayerStyleType::OuterGlow: - filter = new OuterGlowFilter(reinterpret_cast(layerStyle)); - break; - case LayerStyleType::Stroke: - filter = new StrokeFilter(reinterpret_cast(layerStyle)); - break; - case LayerStyleType::GradientOverlay: - filter = new GradientOverlayFilter(reinterpret_cast(layerStyle)); - break; - default: - break; - } - return std::unique_ptr(filter); -} - std::unique_ptr LayerFilter::Make(Effect* effect) { LayerFilter* filter = nullptr; switch (effect->type()) { diff --git a/src/rendering/filters/LayerFilter.h b/src/rendering/filters/LayerFilter.h index a2aad7c139..fb57a69922 100644 --- a/src/rendering/filters/LayerFilter.h +++ b/src/rendering/filters/LayerFilter.h @@ -47,8 +47,6 @@ class FilterProgram : public tgfx::GLResource { class LayerFilter : public Filter { public: - static std::unique_ptr Make(LayerStyle* layerStyle); - static std::unique_ptr Make(Effect* effect); bool initialize(tgfx::Context* context) override; diff --git a/src/rendering/filters/LayerStylesFilter.cpp b/src/rendering/filters/LayerStylesFilter.cpp index 2559c47e20..c7cfc90426 100644 --- a/src/rendering/filters/LayerStylesFilter.cpp +++ b/src/rendering/filters/LayerStylesFilter.cpp @@ -17,8 +17,10 @@ ///////////////////////////////////////////////////////////////////////////////////////////////// #include "LayerStylesFilter.h" +#include "layerstyle/LayerStyleFilter.h" #include "rendering/caches/RenderCache.h" #include "rendering/renderers/FilterRenderer.h" +#include "tgfx/core/Surface.h" namespace pag { void LayerStylesFilter::TransformBounds(tgfx::Rect* bounds, const FilterList* filterList) { @@ -31,55 +33,60 @@ void LayerStylesFilter::TransformBounds(tgfx::Rect* bounds, const FilterList* fi } } -LayerStylesFilter::LayerStylesFilter(RenderCache* renderCache) : renderCache(renderCache) { - drawFilter = new LayerFilter(); +bool LayerStylesFilter::initialize(tgfx::Context*) { + return true; } -LayerStylesFilter::~LayerStylesFilter() { - delete drawFilter; -} - -bool LayerStylesFilter::initialize(tgfx::Context* context) { - return drawFilter->initialize(context); -} - -void LayerStylesFilter::update(const FilterList* list, const tgfx::Rect& inputBounds, - const tgfx::Rect& outputBounds, const tgfx::Point& extraScale) { +void LayerStylesFilter::update(const FilterList* list, const tgfx::Point& extraScale) { filterList = list; - contentBounds = inputBounds; - transformedBounds = outputBounds; filterScale = extraScale; } void LayerStylesFilter::draw(tgfx::Context* context, const FilterSource* source, const FilterTarget* target) { + tgfx::BackendTexture backendTexture = {source->sampler, source->width, source->height}; + auto sourceMatrix = ToMatrix(source->textureMatrix); + auto origin = tgfx::ImageOrigin::TopLeft; + if (!sourceMatrix.isIdentity()) { + origin = tgfx::ImageOrigin::BottomLeft; + } + auto sourceImage = tgfx::Image::MakeFrom(context, backendTexture, origin); + if (sourceImage == nullptr) { + return; + } + + tgfx::BackendRenderTarget renderTarget = {target->frameBuffer, target->width, target->height}; + auto surface = tgfx::Surface::MakeFrom(context, renderTarget, tgfx::ImageOrigin::TopLeft); + if (surface == nullptr) { + return; + } + auto canvas = surface->getCanvas(); + canvas->concat(ToMatrix(target)); for (auto& layerStyle : filterList->layerStyles) { if (layerStyle->drawPosition() == LayerStylePosition::Blow) { - auto filter = renderCache->getFilterCache(layerStyle); + auto filter = LayerStyleFilter::Make(layerStyle); if (filter) { - filter->update(filterList->layerFrame, contentBounds, transformedBounds, filterScale); - filter->draw(context, source, target); + filter->update(filterList->layerFrame, filterScale, source->scale); + filter->draw(canvas, sourceImage); } } } - // The above layer style is only GradientOverlayFilter, and the GradientOverlayFilter has drawn - // the source with blend. + // The filter above source will draw the source with blend. bool drawSource = true; for (auto& layerStyle : filterList->layerStyles) { if (layerStyle->drawPosition() == LayerStylePosition::Above) { - auto filter = renderCache->getFilterCache(layerStyle); + auto filter = LayerStyleFilter::Make(layerStyle); if (filter) { - filter->update(filterList->layerFrame, contentBounds, transformedBounds, filterScale); - filter->draw(context, source, target); + filter->update(filterList->layerFrame, filterScale, source->scale); + filter->draw(canvas, sourceImage); drawSource = false; } } } if (drawSource) { - drawFilter->update(filterList->layerFrame, contentBounds, contentBounds, filterScale); - drawFilter->draw(context, source, target); + canvas->drawImage(sourceImage); } } } // namespace pag diff --git a/src/rendering/filters/LayerStylesFilter.h b/src/rendering/filters/LayerStylesFilter.h index cd4f83322a..228818367f 100644 --- a/src/rendering/filters/LayerStylesFilter.h +++ b/src/rendering/filters/LayerStylesFilter.h @@ -23,32 +23,21 @@ #include "rendering/filters/LayerFilter.h" namespace pag { -class RenderCache; - struct FilterList; class LayerStylesFilter : public Filter { public: static void TransformBounds(tgfx::Rect* bounds, const FilterList* filterList); - explicit LayerStylesFilter(RenderCache* renderCache); - - ~LayerStylesFilter() override; - bool initialize(tgfx::Context* context) override; - void update(const FilterList* filterList, const tgfx::Rect& contentBounds, - const tgfx::Rect& transformedBounds, const tgfx::Point& filterScale); + void update(const FilterList* filterList, const tgfx::Point& filterScale); void draw(tgfx::Context* context, const FilterSource* source, const FilterTarget* target) override; private: const FilterList* filterList = nullptr; - RenderCache* renderCache = nullptr; - LayerFilter* drawFilter = nullptr; - tgfx::Rect contentBounds = {}; - tgfx::Rect transformedBounds = {}; tgfx::Point filterScale = {}; }; } // namespace pag diff --git a/src/rendering/filters/RuntimeFilter.cpp b/src/rendering/filters/RuntimeFilter.cpp new file mode 100644 index 0000000000..ff01972c4b --- /dev/null +++ b/src/rendering/filters/RuntimeFilter.cpp @@ -0,0 +1,220 @@ +///////////////////////////////////////////////////////////////////////////////////////////////// +// +// Tencent is pleased to support the open source community by making libpag available. +// +// Copyright (C) 2024 THL A29 Limited, a Tencent company. 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. +// +///////////////////////////////////////////////////////////////////////////////////////////////// + +#include "RuntimeFilter.h" +#include "rendering/filters/utils/FilterHelper.h" +#include "tgfx/core/Canvas.h" + +namespace pag { +static constexpr char VERTEX_SHADER[] = R"( + #version 100 + attribute vec2 aPosition; + attribute vec2 aTextureCoord; + varying vec2 vertexColor; + void main() { + vec3 position = vec3(aPosition, 1); + gl_Position = vec4(position.xy, 0, 1); + vertexColor = aTextureCoord; + } +)"; + +static constexpr char FRAGMENT_SHADER[] = R"( + #version 100 + precision mediump float; + varying vec2 vertexColor; + uniform sampler2D sTexture; + + void main() { + gl_FragColor = texture2D(sTexture, vertexColor); + } +)"; + +std::unique_ptr RuntimeProgram::Make(tgfx::Context* context, + const std::string& vertex, + const std::string& fragment) { + auto gl = tgfx::GLFunctions::Get(context); + auto program = CreateGLProgram(context, vertex, fragment); + if (program == 0) { + return nullptr; + } + auto filterProgram = std::unique_ptr(new RuntimeProgram(context)); + filterProgram->program = program; + if (gl->bindVertexArray != nullptr) { + gl->genVertexArrays(1, &filterProgram->vertexArray); + } + gl->genBuffers(1, &filterProgram->vertexBuffer); + return filterProgram; +} + +void RuntimeProgram::onReleaseGPU() { + auto gl = tgfx::GLFunctions::Get(getContext()); + if (program > 0) { + gl->deleteProgram(program); + program = 0; + } + if (vertexArray > 0) { + gl->deleteVertexArrays(1, &vertexArray); + vertexArray = 0; + } + if (vertexBuffer > 0) { + gl->deleteBuffers(1, &vertexBuffer); + vertexBuffer = 0; + } +} + +std::unique_ptr RuntimeFilter::onCreateProgram(tgfx::Context* context) const { + // 防止前面产生的GLError,导致后面CheckGLError逻辑返回错误结果 + CheckGLError(context); + + auto vertex = onBuildVertexShader(); + auto fragment = onBuildFragmentShader(); + auto filterProgram = RuntimeProgram::Make(context, vertex, fragment); + if (filterProgram == nullptr) { + return nullptr; + } + filterProgram->uniforms = onPrepareProgram(context, filterProgram->program); + if (!CheckGLError(context)) { + return nullptr; + } + return filterProgram; +} + +std::string RuntimeFilter::onBuildVertexShader() const { + return VERTEX_SHADER; +} + +std::string RuntimeFilter::onBuildFragmentShader() const { + return FRAGMENT_SHADER; +} + +std::unique_ptr RuntimeFilter::onPrepareProgram(tgfx::Context* context, + unsigned program) const { + return std::make_unique(context, program); +} + +void RuntimeFilter::onUpdateParams(tgfx::Context*, const RuntimeProgram*, + const std::vector&) const { +} + +static void EnableMultisample(tgfx::Context* context, bool usesMSAA) { + if (usesMSAA && context->caps()->multisampleDisableSupport) { + auto gl = tgfx::GLFunctions::Get(context); + gl->enable(GL_MULTISAMPLE); + } +} + +static void DisableMultisample(tgfx::Context* context, bool usesMSAA) { + if (usesMSAA && context->caps()->multisampleDisableSupport) { + auto gl = tgfx::GLFunctions::Get(context); + gl->disable(GL_MULTISAMPLE); + } +} + +bool RuntimeFilter::onDraw(const tgfx::RuntimeProgram* program, + const std::vector& sources, + const tgfx::BackendRenderTarget& target, + const tgfx::Point& offset) const { + if (sources.empty() || !target.isValid() || program == nullptr || + sources[0].backend() != tgfx::Backend::OPENGL || target.backend() != tgfx::Backend::OPENGL) { + LOGE( + "LayerFilter::draw() can not draw filter, " + "because the argument(source/target) is null"); + return false; + } + tgfx::GLFrameBufferInfo targetInfo; + target.getGLFramebufferInfo(&targetInfo); + auto context = program->getContext(); + // Clear the previously generated GLError + CheckGLError(context); + auto needsMSAA = sampleCount() > 1; + EnableMultisample(context, needsMSAA); + auto gl = tgfx::GLFunctions::Get(context); + auto filterProgram = static_cast(program); + gl->useProgram(filterProgram->program); + gl->disable(GL_SCISSOR_TEST); + gl->enable(GL_BLEND); + gl->blendEquation(GL_FUNC_ADD); + gl->blendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + gl->bindFramebuffer(GL_FRAMEBUFFER, targetInfo.id); + gl->viewport(0, 0, target.width(), target.height()); + for (size_t i = 0; i < sources.size(); i++) { + tgfx::GLTextureInfo sourceInfo; + sources[i].getGLTextureInfo(&sourceInfo); + ActiveGLTexture(context, static_cast(i), &sourceInfo); + } + onUpdateParams(context, filterProgram, sources); + auto vertices = computeVertices(sources, target, offset); + bindVertices(context, filterProgram, vertices); + gl->drawArrays(GL_TRIANGLE_STRIP, 0, 4); + if (filterProgram->vertexArray > 0) { + gl->bindVertexArray(0); + } + DisableMultisample(context, needsMSAA); + return CheckGLError(context); +} + +std::vector RuntimeFilter::computeVertices(const std::vector& sources, + const tgfx::BackendRenderTarget& target, + const tgfx::Point& offset) const { + std::vector vertices = {}; + auto textureWidth = static_cast(sources[0].width()); + auto textureHeight = static_cast(sources[0].height()); + auto targetWidth = static_cast(target.width()); + auto targetHeight = static_cast(target.height()); + tgfx::Point contentPoint[4] = {{0, targetHeight}, + {targetWidth, targetHeight}, + {0, 0}, + {targetWidth, 0}}; + tgfx::Point texturePoints[4] = {{0.0f, textureHeight}, + {textureWidth, textureHeight}, + {0.0f, 0.0f}, + {textureWidth, 0.0f}}; + + for (size_t i = 0; i < 4; i++) { + auto vertexPoint = ToGLVertexPoint(target, contentPoint[i] + offset); + vertices.push_back(vertexPoint.x); + vertices.push_back(vertexPoint.y); + auto texturePoint = ToGLTexturePoint(&sources[0], texturePoints[i]); + vertices.push_back(texturePoint.x); + vertices.push_back(texturePoint.y); + } + return vertices; +} + +void RuntimeFilter::bindVertices(tgfx::Context* context, const RuntimeProgram* filterProgram, + const std::vector& points) const { + + auto gl = tgfx::GLFunctions::Get(context); + auto uniform = filterProgram->uniforms.get(); + if (filterProgram->vertexArray > 0) { + gl->bindVertexArray(filterProgram->vertexArray); + } + gl->bindBuffer(GL_ARRAY_BUFFER, filterProgram->vertexBuffer); + gl->bufferData(GL_ARRAY_BUFFER, static_cast(points.size() * sizeof(float)), + points.data(), GL_STREAM_DRAW); + gl->vertexAttribPointer(static_cast(uniform->positionHandle), 2, GL_FLOAT, GL_FALSE, + 4 * sizeof(float), static_cast(0)); + gl->enableVertexAttribArray(static_cast(uniform->positionHandle)); + + gl->vertexAttribPointer(uniform->textureCoordHandle, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), + reinterpret_cast(2 * sizeof(float))); + gl->enableVertexAttribArray(uniform->textureCoordHandle); + gl->bindBuffer(GL_ARRAY_BUFFER, 0); +} + +} // namespace pag diff --git a/src/rendering/filters/RuntimeFilter.h b/src/rendering/filters/RuntimeFilter.h new file mode 100644 index 0000000000..ce2dcdcf0e --- /dev/null +++ b/src/rendering/filters/RuntimeFilter.h @@ -0,0 +1,101 @@ +///////////////////////////////////////////////////////////////////////////////////////////////// +// +// Tencent is pleased to support the open source community by making libpag available. +// +// Copyright (C) 2024 THL A29 Limited, a Tencent company. 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. +// +///////////////////////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "tgfx/gpu/RuntimeEffect.h" +#include "tgfx/gpu/RuntimeProgram.h" +#include "tgfx/gpu/opengl/GLFunctions.h" +namespace pag { + +class Uniforms { + public: + Uniforms(tgfx::Context* context, unsigned program) { + auto gl = tgfx::GLFunctions::Get(context); + positionHandle = gl->getAttribLocation(program, "aPosition"); + textureCoordHandle = gl->getAttribLocation(program, "aTextureCoord"); + } + + virtual ~Uniforms() = default; + + int positionHandle = -1; + int textureCoordHandle = -1; +}; + +class RuntimeProgram : public tgfx::RuntimeProgram { + public: + static std::unique_ptr Make(tgfx::Context* context, const std::string& vertex, + const std::string& fragment); + + unsigned program = 0; + unsigned int vertexArray = 0; + unsigned int vertexBuffer = 0; + + std::unique_ptr uniforms = nullptr; + + protected: + void onReleaseGPU() override; + + private: + explicit RuntimeProgram(tgfx::Context* context) : tgfx::RuntimeProgram(context) { + } +}; + +class RuntimeFilter : public tgfx::RuntimeEffect { + public: + explicit RuntimeFilter(tgfx::UniqueType type, + const std::vector>& extraInputs = {}) + : RuntimeEffect(std::move(type), extraInputs) { + } + + std::unique_ptr onCreateProgram(tgfx::Context* context) const override; + + protected: + bool onDraw(const tgfx::RuntimeProgram* program, const std::vector& sources, + const tgfx::BackendRenderTarget& target, const tgfx::Point& offset) const override; + + virtual std::string onBuildVertexShader() const; + + virtual std::string onBuildFragmentShader() const; + + virtual std::unique_ptr onPrepareProgram(tgfx::Context* context, + unsigned program) const; + + /** + * filter的给shader上传数据接口 + */ + virtual void onUpdateParams(tgfx::Context* context, const RuntimeProgram* program, + const std::vector& sources) const; + + /** + * filter的收集顶点数据的接口 + * 如果顶点数据和普通滤镜不一致,需要需重载该接口。 + * @param sources : 滤镜输入的纹理 + * @param target : 滤镜输出的纹理 + * @param offset : 滤镜输出的纹理的偏移量 + * @return : 返回所有顶点数据 + */ + virtual std::vector computeVertices(const std::vector& sources, + const tgfx::BackendRenderTarget& target, + const tgfx::Point& offset) const; + + void bindVertices(tgfx::Context* context, const RuntimeProgram* program, + const std::vector& points) const; +}; + +} // namespace pag diff --git a/src/rendering/filters/layerstyle/AlphaEdgeDetectFilter.cpp b/src/rendering/filters/layerstyle/AlphaEdgeDetectFilter.cpp index 80d389a63b..eec5a1dae8 100644 --- a/src/rendering/filters/layerstyle/AlphaEdgeDetectFilter.cpp +++ b/src/rendering/filters/layerstyle/AlphaEdgeDetectFilter.cpp @@ -44,23 +44,22 @@ static const char FRAGMENT_SHADER[] = R"( } )"; -AlphaEdgeDetectFilter::AlphaEdgeDetectFilter() { -} - -std::string AlphaEdgeDetectFilter::onBuildFragmentShader() { +std::string AlphaEdgeDetectLayerEffect::onBuildFragmentShader() const { return FRAGMENT_SHADER; } -void AlphaEdgeDetectFilter::onPrepareProgram(tgfx::Context* context, unsigned int program) { - auto gl = tgfx::GLFunctions::Get(context); - horizontalStepHandle = gl->getUniformLocation(program, "mHorizontalStep"); - verticalStepHandle = gl->getUniformLocation(program, "mVerticalStep"); +std::unique_ptr AlphaEdgeDetectLayerEffect::onPrepareProgram(tgfx::Context* context, + unsigned program) const { + return std::make_unique(context, program); } -void AlphaEdgeDetectFilter::onUpdateParams(tgfx::Context* context, const tgfx::Rect& contentBounds, - const tgfx::Point&) { +void AlphaEdgeDetectLayerEffect::onUpdateParams( + tgfx::Context* context, const RuntimeProgram* program, + const std::vector& sources) const { + auto uniforms = static_cast(program->uniforms.get()); auto gl = tgfx::GLFunctions::Get(context); - gl->uniform1f(horizontalStepHandle, 1.0f / contentBounds.width()); - gl->uniform1f(verticalStepHandle, 1.0f / contentBounds.height()); + gl->uniform1f(uniforms->horizontalStepHandle, 1.0f / sources[0].width()); + gl->uniform1f(uniforms->verticalStepHandle, 1.0f / sources[0].height()); } + } // namespace pag diff --git a/src/rendering/filters/layerstyle/AlphaEdgeDetectFilter.h b/src/rendering/filters/layerstyle/AlphaEdgeDetectFilter.h index 950103386b..9bb613af33 100644 --- a/src/rendering/filters/layerstyle/AlphaEdgeDetectFilter.h +++ b/src/rendering/filters/layerstyle/AlphaEdgeDetectFilter.h @@ -19,24 +19,35 @@ #pragma once #include "rendering/filters/LayerFilter.h" +#include "rendering/filters/RuntimeFilter.h" namespace pag { -class AlphaEdgeDetectFilter : public LayerFilter { + +class AlphaEdgeDetectEffectUniforms : public Uniforms { public: - explicit AlphaEdgeDetectFilter(); - ~AlphaEdgeDetectFilter() override = default; + AlphaEdgeDetectEffectUniforms(tgfx::Context* context, unsigned program) + : Uniforms(context, program) { + auto gl = tgfx::GLFunctions::Get(context); + horizontalStepHandle = gl->getUniformLocation(program, "mHorizontalStep"); + verticalStepHandle = gl->getUniformLocation(program, "mVerticalStep"); + } + int horizontalStepHandle = -1; + int verticalStepHandle = -1; +}; - protected: - std::string onBuildFragmentShader() override; +class AlphaEdgeDetectLayerEffect : public RuntimeFilter { + public: + DEFINE_RUNTIME_EFFECT_TYPE; + explicit AlphaEdgeDetectLayerEffect() : RuntimeFilter(Type()) { + } - void onPrepareProgram(tgfx::Context* context, unsigned program) override; + std::string onBuildFragmentShader() const override; - void onUpdateParams(tgfx::Context* context, const tgfx::Rect& contentBounds, - const tgfx::Point& filterScale) override; + std::unique_ptr onPrepareProgram(tgfx::Context* context, + unsigned program) const override; - private: - // Handle - int horizontalStepHandle = -1; - int verticalStepHandle = -1; + void onUpdateParams(tgfx::Context* context, const RuntimeProgram* program, + const std::vector& sources) const override; }; + } // namespace pag diff --git a/src/rendering/filters/layerstyle/DropShadowFilter.cpp b/src/rendering/filters/layerstyle/DropShadowFilter.cpp index 45b3e1e574..4476810eed 100644 --- a/src/rendering/filters/layerstyle/DropShadowFilter.cpp +++ b/src/rendering/filters/layerstyle/DropShadowFilter.cpp @@ -19,171 +19,81 @@ #include "DropShadowFilter.h" #include "base/utils/MathUtil.h" #include "base/utils/TGFXCast.h" +#include "rendering/filters/layerstyle/SolidStrokeFilter.h" #include "rendering/filters/utils/BlurTypes.h" #include "rendering/filters/utils/FilterHelper.h" +#include "tgfx/core/Canvas.h" #include "tgfx/core/ImageFilter.h" namespace pag { DropShadowFilter::DropShadowFilter(DropShadowStyle* layerStyle) : layerStyle(layerStyle) { - strokeFilter = new SolidStrokeFilter(SolidStrokeMode::Normal); - strokeThickFilter = new SolidStrokeFilter(SolidStrokeMode::Thick); } -DropShadowFilter::~DropShadowFilter() { - delete strokeFilter; - delete strokeThickFilter; -} - -bool DropShadowFilter::initialize(tgfx::Context* context) { - if (!strokeFilter->initialize(context) || !strokeThickFilter->initialize(context)) { - return false; - } - return true; -} - -void DropShadowFilter::update(Frame frame, const tgfx::Rect& contentBounds, - const tgfx::Rect& transformedBounds, const tgfx::Point& filterScale) { - LayerFilter::update(frame, contentBounds, transformedBounds, filterScale); - +void DropShadowFilter::update(Frame layerFrame, const tgfx::Point& filterScale, + const tgfx::Point& sourceScale) { + auto totalScale = tgfx::Point::Make(filterScale.x * sourceScale.x, filterScale.y * sourceScale.y); spread = layerStyle->spread->getValueAt(layerFrame); + spread *= (spread == 1.f) ? 1.f : 0.8f; color = ToTGFX(layerStyle->color->getValueAt(layerFrame)); - opacity = ToAlpha(layerStyle->opacity->getValueAt(layerFrame)); + alpha = ToAlpha(layerStyle->opacity->getValueAt(layerFrame)); auto size = layerStyle->size->getValueAt(layerFrame); - spread *= (spread == 1.f) ? 1.f : 0.8f; - spreadSize = size * spread; - auto blurSize = size * (1.f - spread) * 2.f; - blurXSize = blurSize * filterScale.x; - blurYSize = blurSize * filterScale.y; + sizeX = size * totalScale.x; + sizeY = size * totalScale.y; + mode = size * spread < STROKE_SPREAD_MIN_THICK_SIZE ? SolidStrokeMode::Normal + : SolidStrokeMode::Thick; auto distance = layerStyle->distance->getValueAt(layerFrame); if (distance > 0.f) { auto angle = layerStyle->angle->getValueAt(layerFrame); auto radians = DegreesToRadians(angle - 180.f); - offsetX = cosf(radians) * distance * filterScale.x; - offsetY = -sinf(radians) * distance * filterScale.y; - } - - strokeOption = SolidStrokeOption(); - strokeOption.color = layerStyle->color->getValueAt(layerFrame); - strokeOption.opacity = layerStyle->opacity->getValueAt(layerFrame); - strokeOption.spreadSize = spreadSize; - - filtersBounds.clear(); - filtersBounds.emplace_back(contentBounds); - if (spread == 1.f) { - updateParamModeFullSpread(contentBounds); - } else if (spread != 0.f) { - updateParamModeNotFullSpread(contentBounds); + offsetX = cosf(radians) * distance * totalScale.x; + offsetY = -sinf(radians) * distance * totalScale.y; + } else { + offsetX = 0.f; + offsetY = 0.f; } } -void DropShadowFilter::draw(tgfx::Context* context, const FilterSource* source, - const FilterTarget* target) { - if (source == nullptr || target == nullptr) { - return; - } +bool DropShadowFilter::draw(tgfx::Canvas* canvas, std::shared_ptr image) { + std::shared_ptr filter = nullptr; if (spread == 0.f) { - onDrawModeNotSpread(context, source, target); + filter = getDropShadowFilter(); } else if (spread == 1.f) { - onDrawModeFullSpread(context, source, target); - } else { - onDrawModeNotFullSpread(context, source, target); - } -} - -void DropShadowFilter::updateParamModeNotFullSpread(const tgfx::Rect& contentBounds) { - auto filterBounds = contentBounds; - filterBounds.outset(spreadSize * filterScale.x, spreadSize * filterScale.y); - filterBounds.roundOut(); - if (spreadSize < STROKE_SPREAD_MIN_THICK_SIZE) { - strokeFilter->onUpdateOption(strokeOption); - strokeFilter->update(layerFrame, contentBounds, filterBounds, filterScale); + filter = getStrokeFilter(); } else { - strokeThickFilter->onUpdateOption(strokeOption); - strokeThickFilter->update(layerFrame, contentBounds, filterBounds, filterScale); + auto strokeFilter = getStrokeFilter(); + if (strokeFilter == nullptr) { + return false; + } + auto dropShadowFilter = getDropShadowFilter(); + if (dropShadowFilter == nullptr) { + return false; + } + filter = tgfx::ImageFilter::Compose(strokeFilter, dropShadowFilter); } - filtersBounds.emplace_back(filterBounds); -} - -void DropShadowFilter::updateParamModeFullSpread(const tgfx::Rect& contentBounds) { - auto filterBounds = contentBounds; - filterBounds.outset(spreadSize * filterScale.x, spreadSize * filterScale.y); - filterBounds.offset(offsetX, offsetY); - filterBounds.roundOut(); - if (spreadSize < STROKE_SPREAD_MIN_THICK_SIZE) { - strokeFilter->onUpdateOption(strokeOption); - strokeFilter->update(layerFrame, contentBounds, filterBounds, filterScale); - } else { - strokeThickFilter->onUpdateOption(strokeOption); - strokeThickFilter->update(layerFrame, contentBounds, filterBounds, filterScale); + if (!filter) { + return false; } -} - -void DropShadowFilter::onDrawModeNotSpread(tgfx::Context* context, const FilterSource* source, - const FilterTarget* target) { - tgfx::BackendRenderTarget renderTarget = {target->frameBuffer, target->width, target->height}; - auto targetSurface = tgfx::Surface::MakeFrom(context, renderTarget, tgfx::ImageOrigin::TopLeft); - auto targetCanvas = targetSurface->getCanvas(); - tgfx::BackendTexture backendTexture = {source->sampler, source->width, source->height}; - auto image = tgfx::Image::MakeFrom(context, backendTexture); - targetCanvas->setMatrix(ToMatrix(target)); tgfx::Paint paint; - paint.setImageFilter(tgfx::ImageFilter::DropShadowOnly( - offsetX * source->scale.x, offsetY * source->scale.y, blurXSize * source->scale.x, - blurYSize * source->scale.y, color)); - paint.setAlpha(opacity); - targetCanvas->drawImage(std::move(image), &paint); - context->flush(); + paint.setImageFilter(filter); + paint.setAlpha(alpha); + canvas->drawImage(std::move(image), &paint); + return true; } -void DropShadowFilter::onDrawModeNotFullSpread(tgfx::Context* context, const FilterSource* source, - const FilterTarget* target) { - auto contentBounds = filtersBounds[0]; - auto filterBounds = filtersBounds[1]; - auto targetWidth = static_cast(ceilf(filterBounds.width() * source->scale.x)); - auto targetHeight = static_cast(ceilf(filterBounds.height() * source->scale.y)); - if (solidStrokeFilterBuffer == nullptr || solidStrokeFilterBuffer->width() != targetWidth || - solidStrokeFilterBuffer->height() != targetHeight) { - solidStrokeFilterBuffer = FilterBuffer::Make(context, targetWidth, targetHeight); - } - if (solidStrokeFilterBuffer == nullptr) { - return; - } - solidStrokeFilterBuffer->clearColor(); - auto offsetMatrix = tgfx::Matrix::MakeTrans((contentBounds.left - filterBounds.left), - (contentBounds.top - filterBounds.top)); - auto targetSpread = solidStrokeFilterBuffer->toFilterTarget(offsetMatrix); - if (spreadSize < STROKE_SPREAD_MIN_THICK_SIZE) { - strokeFilter->draw(context, source, targetSpread.get()); - } else { - strokeThickFilter->draw(context, source, targetSpread.get()); - } - - auto sourceV = solidStrokeFilterBuffer->toFilterSource(source->scale); - - tgfx::BackendRenderTarget renderTarget = {target->frameBuffer, target->width, target->height}; - auto targetSurface = tgfx::Surface::MakeFrom(context, renderTarget, tgfx::ImageOrigin::TopLeft); - auto targetCanvas = targetSurface->getCanvas(); - tgfx::BackendTexture backendTexture = {sourceV->sampler, sourceV->width, sourceV->height}; - auto image = tgfx::Image::MakeFrom(context, backendTexture); - targetCanvas->setMatrix(ToMatrix(target)); - targetCanvas->concat( - tgfx::Matrix::MakeTrans(static_cast((source->width - sourceV->width)) * 0.5f, - static_cast((source->height - sourceV->height)) * 0.5f)); - tgfx::Paint paint; - paint.setImageFilter(tgfx::ImageFilter::DropShadowOnly( - offsetX * source->scale.x, offsetY * source->scale.y, blurXSize * source->scale.x, - blurYSize * source->scale.y, color)); - paint.setAlpha(opacity); - targetCanvas->drawImage(std::move(image), &paint); - context->flush(); +std::shared_ptr DropShadowFilter::getStrokeFilter() const { + auto strokeOption = SolidStrokeOption(); + strokeOption.color = color; + strokeOption.spreadSizeX = sizeX * spread; + strokeOption.spreadSizeY = sizeY * spread; + strokeOption.offsetX = offsetX; + strokeOption.offsetY = offsetY; + return SolidStrokeFilter::CreateFilter(strokeOption, mode); } -void DropShadowFilter::onDrawModeFullSpread(tgfx::Context* context, const FilterSource* source, - const FilterTarget* target) { - if (spreadSize < STROKE_SPREAD_MIN_THICK_SIZE) { - strokeFilter->draw(context, source, target); - } else { - strokeThickFilter->draw(context, source, target); - } +std::shared_ptr DropShadowFilter::getDropShadowFilter() const { + float blurSizeX = sizeX * (1.f - spread) * 2.f; + float blurSizeY = sizeY * (1.f - spread) * 2.f; + return tgfx::ImageFilter::DropShadowOnly(offsetX, offsetY, blurSizeX, blurSizeY, color); } + } // namespace pag diff --git a/src/rendering/filters/layerstyle/DropShadowFilter.h b/src/rendering/filters/layerstyle/DropShadowFilter.h index 4410ad57c0..37c3d44f30 100644 --- a/src/rendering/filters/layerstyle/DropShadowFilter.h +++ b/src/rendering/filters/layerstyle/DropShadowFilter.h @@ -18,12 +18,11 @@ #pragma once -#include "SolidStrokeFilter.h" -#include "rendering/filters/LayerFilter.h" -#include "rendering/filters/utils/FilterBuffer.h" +#include "LayerStyleFilter.h" +#include "rendering/filters/layerstyle/SolidStrokeFilter.h" namespace pag { -class DropShadowFilter : public LayerFilter { +class DropShadowFilter : public LayerStyleFilter { public: explicit DropShadowFilter(DropShadowStyle* layerStyle); @@ -31,43 +30,24 @@ class DropShadowFilter : public LayerFilter { DropShadowFilter(DropShadowFilter&&) = delete; - ~DropShadowFilter() override; + void update(Frame layerFrame, const tgfx::Point& filterScale, + const tgfx::Point& sourceScale) override; - bool initialize(tgfx::Context* context) override; - - void update(Frame frame, const tgfx::Rect& contentBounds, const tgfx::Rect& transformedBounds, - const tgfx::Point& filterScale) override; - - void draw(tgfx::Context* context, const FilterSource* source, - const FilterTarget* target) override; + bool draw(tgfx::Canvas* canvas, std::shared_ptr image) override; private: - void updateParamModeNotFullSpread(const tgfx::Rect& contentBounds); - void updateParamModeFullSpread(const tgfx::Rect& contentBounds); + std::shared_ptr getStrokeFilter() const; - void onDrawModeNotSpread(tgfx::Context* context, const FilterSource* source, - const FilterTarget* target); - void onDrawModeNotFullSpread(tgfx::Context* context, const FilterSource* source, - const FilterTarget* target); - void onDrawModeFullSpread(tgfx::Context* context, const FilterSource* source, - const FilterTarget* target); + std::shared_ptr getDropShadowFilter() const; DropShadowStyle* layerStyle = nullptr; - - std::shared_ptr solidStrokeFilterBuffer = nullptr; - - SolidStrokeOption strokeOption; - SolidStrokeFilter* strokeFilter = nullptr; - SolidStrokeFilter* strokeThickFilter = nullptr; - tgfx::Color color = tgfx::Color::Black(); - float spread = 0.f; - float spreadSize = 0.f; - float opacity = 1.0f; - float blurXSize = 0.f; - float blurYSize = 0.f; - float offsetX = 0.f; - float offsetY = 0.f; - std::vector filtersBounds = {}; + float alpha = 1.0f; + SolidStrokeMode mode = SolidStrokeMode::Normal; + float sizeX = 0; + float sizeY = 0; + Percent spread = 0; + float offsetX = 0; + float offsetY = 0; }; } // namespace pag diff --git a/src/rendering/filters/GradientOverlayFilter.cpp b/src/rendering/filters/layerstyle/GradientOverlayFilter.cpp similarity index 61% rename from src/rendering/filters/GradientOverlayFilter.cpp rename to src/rendering/filters/layerstyle/GradientOverlayFilter.cpp index 65b256f2ac..313b79a873 100644 --- a/src/rendering/filters/GradientOverlayFilter.cpp +++ b/src/rendering/filters/layerstyle/GradientOverlayFilter.cpp @@ -27,23 +27,22 @@ GradientOverlayFilter::GradientOverlayFilter(GradientOverlayStyle* layerStyle) : layerStyle(layerStyle) { } -bool GradientOverlayFilter::initialize(tgfx::Context*) { - return true; +void GradientOverlayFilter::update(Frame layerFrame, const tgfx::Point& filterScale, + const tgfx::Point&) { + opacity = layerStyle->opacity->getValueAt(layerFrame); + colors = layerStyle->colors->getValueAt(layerFrame); + angle = layerStyle->angle->getValueAt(layerFrame); + gradStyle = layerStyle->style->getValueAt(layerFrame); + reverse = layerStyle->reverse->getValueAt(layerFrame); + scale = layerStyle->scale->getValueAt(layerFrame) / 100.f; + offset = layerStyle->offset->getValueAt(layerFrame); + blendMode = layerStyle->blendMode->getValueAt(layerFrame); + _filterScale = filterScale; } -void GradientOverlayFilter::draw(tgfx::Context* context, const FilterSource* source, - const FilterTarget* target) { - auto* gradStyle = static_cast(layerStyle); - auto opacity = gradStyle->opacity->getValueAt(layerFrame); - auto colors = gradStyle->colors->getValueAt(layerFrame); - auto angle = gradStyle->angle->getValueAt(layerFrame); - auto style = gradStyle->style->getValueAt(layerFrame); - auto reverse = gradStyle->reverse->getValueAt(layerFrame); - auto scale = gradStyle->scale->getValueAt(layerFrame) / 100.f; - auto offset = gradStyle->offset->getValueAt(layerFrame); - - auto width = static_cast(source->width); - auto height = static_cast(source->height); +bool GradientOverlayFilter::draw(tgfx::Canvas* canvas, std::shared_ptr source) { + auto width = static_cast(source->width()); + auto height = static_cast(source->height()); angle = fmodf(angle, 360.f); auto diagonalAngle = RadiansToDegrees(std::atan(height / width)); @@ -69,32 +68,25 @@ void GradientOverlayFilter::draw(tgfx::Context* context, const FilterSource* sou matrix.postRotate(360.f - angle, centerX, centerY); matrix.postTranslate(offset.x * 0.01f * width, offset.y * 0.01f * height); - auto gradient = GradientPaint(style, startPoint, endPoint, colors, matrix, reverse); + auto gradient = GradientPaint(gradStyle, startPoint, endPoint, colors, matrix, reverse); auto shader = gradient.getShader(); - if (opacity != 255) { shader = tgfx::Shader::MakeBlend( tgfx::BlendMode::DstIn, shader, tgfx::Shader::MakeColorShader(tgfx::Color::FromRGBA(0, 0, 0, opacity))); } - tgfx::BackendRenderTarget renderTarget = {target->frameBuffer, target->width, target->height}; - auto targetSurface = tgfx::Surface::MakeFrom(context, renderTarget, tgfx::ImageOrigin::TopLeft); - auto targetCanvas = targetSurface->getCanvas(); - tgfx::BackendTexture backendTexture = {source->sampler, source->width, source->height}; - auto image = tgfx::Image::MakeFrom(context, backendTexture); - auto imageShader = tgfx::Shader::MakeImageShader(image); + auto imageShader = tgfx::Shader::MakeImageShader(source); shader = tgfx::Shader::MakeBlend(tgfx::BlendMode::DstIn, shader, imageShader); - shader = tgfx::Shader::MakeBlend(ToTGFXBlend(gradStyle->blendMode->getValueAt(layerFrame)), - imageShader, shader); + shader = tgfx::Shader::MakeBlend(ToTGFXBlend(blendMode), imageShader, shader); tgfx::Paint paint; paint.setShader(shader); - targetCanvas->save(); - targetCanvas->setMatrix(ToMatrix(target)); - targetCanvas->concat(tgfx::Matrix::MakeScale(1.f / filterScale.x, 1.f / filterScale.y)); auto rect = tgfx::Rect::MakeWH(width, height); - targetCanvas->drawRect(rect, paint); - targetCanvas->restore(); - context->flush(); + canvas->save(); + canvas->scale(1.f / _filterScale.x, 1.f / _filterScale.y); + canvas->drawRect(rect, paint); + canvas->restore(); + return true; } + } // namespace pag diff --git a/src/rendering/filters/GradientOverlayFilter.h b/src/rendering/filters/layerstyle/GradientOverlayFilter.h similarity index 65% rename from src/rendering/filters/GradientOverlayFilter.h rename to src/rendering/filters/layerstyle/GradientOverlayFilter.h index 67dfb6adcc..e6e72a1173 100644 --- a/src/rendering/filters/GradientOverlayFilter.h +++ b/src/rendering/filters/layerstyle/GradientOverlayFilter.h @@ -18,19 +18,28 @@ #pragma once -#include "LayerFilter.h" +#include "LayerStyleFilter.h" namespace pag { -class GradientOverlayFilter : public LayerFilter { +class GradientOverlayFilter : public LayerStyleFilter { public: explicit GradientOverlayFilter(GradientOverlayStyle* layerStyle); - bool initialize(tgfx::Context* context) override; + void update(Frame layerFrame, const tgfx::Point& filterScale, + const tgfx::Point& sourceScale) override; - void draw(tgfx::Context* context, const FilterSource* source, - const FilterTarget* target) override; + bool draw(tgfx::Canvas* canvas, std::shared_ptr source) override; private: GradientOverlayStyle* layerStyle = nullptr; + Enum blendMode = 0; // BlendMode + Opacity opacity = 255; + GradientColorHandle colors = nullptr; + float angle = 0; + Enum gradStyle = 0; // GradientFillType + bool reverse = false; + float scale = 1.0; + Point offset = Point::Zero(); + tgfx::Point _filterScale = tgfx::Point::Make(1.0f, 1.0f); }; } // namespace pag diff --git a/src/rendering/filters/layerstyle/LayerStyleFilter.cpp b/src/rendering/filters/layerstyle/LayerStyleFilter.cpp new file mode 100644 index 0000000000..923da6fcbc --- /dev/null +++ b/src/rendering/filters/layerstyle/LayerStyleFilter.cpp @@ -0,0 +1,51 @@ +///////////////////////////////////////////////////////////////////////////////////////////////// +// +// Tencent is pleased to support the open source community by making libpag available. +// +// Copyright (C) 2023 THL A29 Limited, a Tencent company. 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. +// +///////////////////////////////////////////////////////////////////////////////////////////////// + +#include "LayerStyleFilter.h" +#include "rendering/filters/layerstyle/DropShadowFilter.h" +#include "rendering/filters/layerstyle/GradientOverlayFilter.h" +#include "rendering/filters/layerstyle/OuterGlowFilter.h" +#include "rendering/filters/layerstyle/StrokeFilter.h" + +namespace pag { + +std::unique_ptr LayerStyleFilter::Make(LayerStyle* layerStyle) { + LayerStyleFilter* filter = nullptr; + switch (layerStyle->type()) { + case LayerStyleType::DropShadow: + filter = new DropShadowFilter(reinterpret_cast(layerStyle)); + break; + case LayerStyleType::OuterGlow: + filter = new OuterGlowFilter(reinterpret_cast(layerStyle)); + break; + case LayerStyleType::Stroke: + filter = new StrokeFilter(reinterpret_cast(layerStyle)); + break; + case LayerStyleType::GradientOverlay: + filter = new GradientOverlayFilter(reinterpret_cast(layerStyle)); + break; + default: + break; + } + if (!filter) { + return nullptr; + } + return std::unique_ptr(filter); +} + +} // namespace pag \ No newline at end of file diff --git a/src/rendering/filters/layerstyle/LayerStyleFilter.h b/src/rendering/filters/layerstyle/LayerStyleFilter.h new file mode 100644 index 0000000000..e385fab28e --- /dev/null +++ b/src/rendering/filters/layerstyle/LayerStyleFilter.h @@ -0,0 +1,40 @@ +///////////////////////////////////////////////////////////////////////////////////////////////// +// +// Tencent is pleased to support the open source community by making libpag available. +// +// Copyright (C) 2023 THL A29 Limited, a Tencent company. 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. +// +///////////////////////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "pag/file.h" +#include "pag/pag.h" +#include "rendering/filters/utils/FilterHelper.h" +#include "tgfx/gpu/RuntimeEffect.h" + +namespace pag { + +class LayerStyleFilter { + public: + virtual ~LayerStyleFilter() = default; + + static std::unique_ptr Make(LayerStyle* layerStyle); + + virtual void update(Frame layerFrame, const tgfx::Point& filterScale, + const tgfx::Point& sourceScale) = 0; + + virtual bool draw(tgfx::Canvas* canvas, std::shared_ptr image) = 0; +}; + +} // namespace pag diff --git a/src/rendering/filters/layerstyle/OuterGlowFilter.cpp b/src/rendering/filters/layerstyle/OuterGlowFilter.cpp index 2c2b379ee9..acc05d8ace 100644 --- a/src/rendering/filters/layerstyle/OuterGlowFilter.cpp +++ b/src/rendering/filters/layerstyle/OuterGlowFilter.cpp @@ -17,167 +17,69 @@ ///////////////////////////////////////////////////////////////////////////////////////////////// #include "OuterGlowFilter.h" -#include "base/utils/MathUtil.h" #include "base/utils/TGFXCast.h" +#include "rendering/filters/layerstyle/SolidStrokeFilter.h" #include "rendering/filters/utils/BlurTypes.h" -#include "rendering/filters/utils/FilterHelper.h" +#include "tgfx/core/Canvas.h" #include "tgfx/core/ImageFilter.h" namespace pag { OuterGlowFilter::OuterGlowFilter(OuterGlowStyle* layerStyle) : layerStyle(layerStyle) { - strokeFilter = new SolidStrokeFilter(SolidStrokeMode::Normal); - strokeThickFilter = new SolidStrokeFilter(SolidStrokeMode::Thick); } -OuterGlowFilter::~OuterGlowFilter() { - delete strokeFilter; - delete strokeThickFilter; -} - -bool OuterGlowFilter::initialize(tgfx::Context* context) { - if (!strokeFilter->initialize(context) || !strokeThickFilter->initialize(context)) { - return false; - } - return true; -} - -void OuterGlowFilter::update(Frame frame, const tgfx::Rect& contentBounds, - const tgfx::Rect& transformedBounds, const tgfx::Point& filterScale) { - LayerFilter::update(frame, contentBounds, transformedBounds, filterScale); - +void OuterGlowFilter::update(Frame layerFrame, const tgfx::Point& filterScale, + const tgfx::Point& sourceScale) { + auto totalScale = tgfx::Point::Make(filterScale.x * sourceScale.x, filterScale.y * sourceScale.y); spread = layerStyle->spread->getValueAt(layerFrame); + spread *= (spread == 1.f) ? 1.f : 0.8f; color = ToTGFX(layerStyle->color->getValueAt(layerFrame)); - opacity = ToAlpha(layerStyle->opacity->getValueAt(layerFrame)); + alpha = ToAlpha(layerStyle->opacity->getValueAt(layerFrame)); auto size = layerStyle->size->getValueAt(layerFrame); - auto range = layerStyle->range->getValueAt(layerFrame); - spread *= (spread == 1.f) ? 1.f : 0.8f; - spreadSize = size * spread / range; - auto blurSize = size * (1.f - spread) * 2.f / range; - blurXSize = blurSize * filterScale.x; - blurYSize = blurSize * filterScale.y; - - strokeOption = SolidStrokeOption(); - strokeOption.color = layerStyle->color->getValueAt(layerFrame); - strokeOption.opacity = layerStyle->opacity->getValueAt(layerFrame); - strokeOption.spreadSize = spreadSize; - - filtersBounds.clear(); - filtersBounds.emplace_back(contentBounds); - if (spread == 1.f) { - updateParamModeFullSpread(contentBounds); - } else if (spread != 0.f) { - updateParamModeNotFullSpread(contentBounds); - } + sizeX = size * totalScale.x; + sizeY = size * totalScale.y; + mode = size < STROKE_SPREAD_MIN_THICK_SIZE ? SolidStrokeMode::Normal : SolidStrokeMode::Thick; + range = layerStyle->range->getValueAt(layerFrame); } -void OuterGlowFilter::draw(tgfx::Context* context, const FilterSource* source, - const FilterTarget* target) { - if (source == nullptr || target == nullptr) { - return; - } +bool OuterGlowFilter::draw(tgfx::Canvas* canvas, std::shared_ptr image) { + std::shared_ptr filter = nullptr; if (spread == 0.f) { - onDrawModeNotSpread(context, source, target); + filter = getDropShadowFilter(); } else if (spread == 1.f) { - onDrawModeFullSpread(context, source, target); - } else { - onDrawModeNotFullSpread(context, source, target); - } -} - -void OuterGlowFilter::updateParamModeNotFullSpread(const tgfx::Rect& contentBounds) { - auto filterBounds = contentBounds; - filterBounds.outset(spreadSize * filterScale.x, spreadSize * filterScale.y); - filterBounds.roundOut(); - if (spreadSize < STROKE_SPREAD_MIN_THICK_SIZE) { - strokeFilter->onUpdateOption(strokeOption); - strokeFilter->update(layerFrame, contentBounds, filterBounds, filterScale); + filter = getStrokeFilter(); } else { - strokeThickFilter->onUpdateOption(strokeOption); - strokeThickFilter->update(layerFrame, contentBounds, filterBounds, filterScale); + auto strokeFilter = getStrokeFilter(); + if (strokeFilter == nullptr) { + return false; + } + auto dropShadowFilter = getDropShadowFilter(); + if (dropShadowFilter == nullptr) { + return false; + } + filter = tgfx::ImageFilter::Compose(strokeFilter, dropShadowFilter); } - filtersBounds.emplace_back(filterBounds); -} - -void OuterGlowFilter::updateParamModeFullSpread(const tgfx::Rect& contentBounds) { - auto filterBounds = contentBounds; - filterBounds.outset(spreadSize * filterScale.x, spreadSize * filterScale.y); - filterBounds.offset(offsetX, offsetY); - filterBounds.roundOut(); - if (spreadSize < STROKE_SPREAD_MIN_THICK_SIZE) { - strokeFilter->onUpdateOption(strokeOption); - strokeFilter->update(layerFrame, contentBounds, filterBounds, filterScale); - } else { - strokeThickFilter->onUpdateOption(strokeOption); - strokeThickFilter->update(layerFrame, contentBounds, filterBounds, filterScale); + if (!filter) { + return false; } -} - -void OuterGlowFilter::onDrawModeNotSpread(tgfx::Context* context, const FilterSource* source, - const FilterTarget* target) { - tgfx::BackendRenderTarget renderTarget = {target->frameBuffer, target->width, target->height}; - auto targetSurface = tgfx::Surface::MakeFrom(context, renderTarget, tgfx::ImageOrigin::TopLeft); - auto targetCanvas = targetSurface->getCanvas(); - tgfx::BackendTexture backendTexture = {source->sampler, source->width, source->height}; - auto image = tgfx::Image::MakeFrom(context, backendTexture); - targetCanvas->setMatrix(ToMatrix(target)); tgfx::Paint paint; - paint.setImageFilter(tgfx::ImageFilter::DropShadowOnly( - offsetX * source->scale.x, offsetY * source->scale.y, blurXSize * source->scale.x, - blurYSize * source->scale.y, color)); - paint.setAlpha(opacity); - targetCanvas->drawImage(std::move(image), &paint); - context->flush(); + paint.setImageFilter(filter); + paint.setAlpha(alpha); + canvas->drawImage(std::move(image), &paint); + return true; } -void OuterGlowFilter::onDrawModeNotFullSpread(tgfx::Context* context, const FilterSource* source, - const FilterTarget* target) { - auto contentBounds = filtersBounds[0]; - auto filterBounds = filtersBounds[1]; - auto targetWidth = static_cast(ceilf(filterBounds.width() * source->scale.x)); - auto targetHeight = static_cast(ceilf(filterBounds.height() * source->scale.y)); - if (solidStrokeFilterBuffer == nullptr || solidStrokeFilterBuffer->width() != targetWidth || - solidStrokeFilterBuffer->height() != targetHeight) { - solidStrokeFilterBuffer = FilterBuffer::Make(context, targetWidth, targetHeight); - } - if (solidStrokeFilterBuffer == nullptr) { - return; - } - solidStrokeFilterBuffer->clearColor(); - auto offsetMatrix = tgfx::Matrix::MakeTrans((contentBounds.left - filterBounds.left), - (contentBounds.top - filterBounds.top)); - auto targetSpread = solidStrokeFilterBuffer->toFilterTarget(offsetMatrix); - if (spreadSize < STROKE_SPREAD_MIN_THICK_SIZE) { - strokeFilter->draw(context, source, targetSpread.get()); - } else { - strokeThickFilter->draw(context, source, targetSpread.get()); - } - - auto sourceV = solidStrokeFilterBuffer->toFilterSource(source->scale); - - tgfx::BackendRenderTarget renderTarget = {target->frameBuffer, target->width, target->height}; - auto targetSurface = tgfx::Surface::MakeFrom(context, renderTarget, tgfx::ImageOrigin::TopLeft); - auto targetCanvas = targetSurface->getCanvas(); - tgfx::BackendTexture backendTexture = {sourceV->sampler, sourceV->width, sourceV->height}; - auto image = tgfx::Image::MakeFrom(context, backendTexture); - targetCanvas->setMatrix(ToMatrix(target)); - targetCanvas->concat( - tgfx::Matrix::MakeTrans(static_cast((source->width - sourceV->width)) * 0.5f, - static_cast((source->height - sourceV->height)) * 0.5f)); - tgfx::Paint paint; - paint.setImageFilter(tgfx::ImageFilter::DropShadowOnly( - offsetX * source->scale.x, offsetY * source->scale.y, blurXSize * source->scale.x, - blurYSize * source->scale.y, color)); - paint.setAlpha(opacity); - targetCanvas->drawImage(std::move(image), &paint); - context->flush(); +std::shared_ptr OuterGlowFilter::getStrokeFilter() const { + auto strokeOption = SolidStrokeOption(); + strokeOption.color = color; + strokeOption.spreadSizeX = spread * sizeX / range; + strokeOption.spreadSizeY = spread * sizeY / range; + return SolidStrokeFilter::CreateFilter(strokeOption, mode); } -void OuterGlowFilter::onDrawModeFullSpread(tgfx::Context* context, const FilterSource* source, - const FilterTarget* target) { - if (spreadSize < STROKE_SPREAD_MIN_THICK_SIZE) { - strokeFilter->draw(context, source, target); - } else { - strokeThickFilter->draw(context, source, target); - } +std::shared_ptr OuterGlowFilter::getDropShadowFilter() const { + auto blurSizeX = sizeX * (1.f - spread) * 2.f / range; + auto blurSizeY = sizeY * (1.f - spread) * 2.f / range; + return tgfx::ImageFilter::DropShadowOnly(0, 0, blurSizeX, blurSizeY, color); } + } // namespace pag diff --git a/src/rendering/filters/layerstyle/OuterGlowFilter.h b/src/rendering/filters/layerstyle/OuterGlowFilter.h index 118f2d7653..4eb4f42f23 100644 --- a/src/rendering/filters/layerstyle/OuterGlowFilter.h +++ b/src/rendering/filters/layerstyle/OuterGlowFilter.h @@ -18,12 +18,11 @@ #pragma once -#include "SolidStrokeFilter.h" -#include "rendering/filters/LayerFilter.h" -#include "rendering/filters/utils/FilterBuffer.h" +#include "LayerStyleFilter.h" +#include "rendering/filters/layerstyle/SolidStrokeFilter.h" namespace pag { -class OuterGlowFilter : public LayerFilter { +class OuterGlowFilter : public LayerStyleFilter { public: explicit OuterGlowFilter(OuterGlowStyle* layerStyle); @@ -31,43 +30,24 @@ class OuterGlowFilter : public LayerFilter { OuterGlowFilter(OuterGlowFilter&&) = delete; - ~OuterGlowFilter() override; + void update(Frame layerFrame, const tgfx::Point& filterScale, + const tgfx::Point& sourceScale) override; - bool initialize(tgfx::Context* context) override; - - void update(Frame frame, const tgfx::Rect& contentBounds, const tgfx::Rect& transformedBounds, - const tgfx::Point& filterScale) override; - - void draw(tgfx::Context* context, const FilterSource* source, - const FilterTarget* target) override; + bool draw(tgfx::Canvas* canvas, std::shared_ptr image) override; private: - void updateParamModeNotFullSpread(const tgfx::Rect& contentBounds); - void updateParamModeFullSpread(const tgfx::Rect& contentBounds); + std::shared_ptr getStrokeFilter() const; - void onDrawModeNotSpread(tgfx::Context* context, const FilterSource* source, - const FilterTarget* target); - void onDrawModeNotFullSpread(tgfx::Context* context, const FilterSource* source, - const FilterTarget* target); - void onDrawModeFullSpread(tgfx::Context* context, const FilterSource* source, - const FilterTarget* target); + std::shared_ptr getDropShadowFilter() const; OuterGlowStyle* layerStyle = nullptr; - std::shared_ptr solidStrokeFilterBuffer = nullptr; - - SolidStrokeOption strokeOption; - SolidStrokeFilter* strokeFilter = nullptr; - SolidStrokeFilter* strokeThickFilter = nullptr; - tgfx::Color color = tgfx::Color::Black(); - float spread = 0.f; - float spreadSize = 0.f; - float opacity = 1.0f; - float blurXSize = 0.f; - float blurYSize = 0.f; - float offsetX = 0.f; - float offsetY = 0.f; - std::vector filtersBounds = {}; + float alpha = 1.0f; + float sizeX = 0; + float sizeY = 0; + SolidStrokeMode mode = SolidStrokeMode::Normal; + Percent spread = 0; + Percent range = 1.0f; }; } // namespace pag diff --git a/src/rendering/filters/layerstyle/SolidStrokeFilter.cpp b/src/rendering/filters/layerstyle/SolidStrokeFilter.cpp index 351f678879..f242cc8211 100644 --- a/src/rendering/filters/layerstyle/SolidStrokeFilter.cpp +++ b/src/rendering/filters/layerstyle/SolidStrokeFilter.cpp @@ -19,6 +19,7 @@ #include "SolidStrokeFilter.h" #include "base/utils/TGFXCast.h" #include "rendering/filters/utils/BlurTypes.h" +#include "tgfx/core/ImageFilter.h" namespace pag { static const char SOLID_STROKE_FRAGMENT_SHADER[] = R"( @@ -27,7 +28,6 @@ static const char SOLID_STROKE_FRAGMENT_SHADER[] = R"( uniform sampler2D uTextureInput; uniform sampler2D uOriginalTextureInput; uniform vec3 uColor; - uniform float uAlpha; uniform vec2 uSize; uniform float uIsUseOriginalTexture; uniform float uIsOutside; @@ -58,14 +58,13 @@ static const char SOLID_STROKE_FRAGMENT_SHADER[] = R"( point = vertexColor + vec2(measureX, -measureY); alphaSum += texture2D(uTextureInput, point).a * check(point); } - + vec4 srcColor = (uIsUseOriginalTexture == 1.0) ? texture2D(uOriginalTextureInput, vertexColor) : inputColor; - - vec4 result = (alphaSum > 0.0) ? vec4(uColor * uAlpha, uAlpha) : vec4(0.0); + + vec4 result = (alphaSum > 0.0) ? vec4(uColor, 1.0) : vec4(0.0); result = (uIsOutside == 1.0 && srcColor.a > threshold) ? srcColor : result; result = (uIsCenter == 1.0 && result.a < threshold) ? srcColor : result; result = (uIsInside == 1.0 && (result.a < threshold || srcColor.a < threshold)) ? srcColor : result; - gl_FragColor = result; } )"; @@ -76,7 +75,6 @@ static const char SOLID_STROKE_THICK_FRAGMENT_SHADER[] = R"( uniform sampler2D uTextureInput; uniform sampler2D uOriginalTextureInput; uniform vec3 uColor; - uniform float uAlpha; uniform vec2 uSize; uniform float uIsUseOriginalTexture; uniform float uIsOutside; @@ -111,95 +109,121 @@ static const char SOLID_STROKE_THICK_FRAGMENT_SHADER[] = R"( point = vertexColor + vec2(measureX / 2.0, -measureY / 2.0); alphaSum += texture2D(uTextureInput, point).a * check(point); } - + vec4 srcColor = (uIsUseOriginalTexture == 1.0) ? texture2D(uOriginalTextureInput, vertexColor) : inputColor; - - vec4 result = (alphaSum > 0.0) ? vec4(uColor * uAlpha, uAlpha) : vec4(0.0); + + vec4 result = (alphaSum > 0.0) ? vec4(uColor, 1.0) : vec4(0.0); result = (uIsOutside == 1.0 && srcColor.a > threshold) ? srcColor : result; result = (uIsCenter == 1.0 && result.a < threshold) ? srcColor : result; result = (uIsInside == 1.0 && (result.a < threshold || srcColor.a < threshold)) ? srcColor : result; - + gl_FragColor = result; } )"; -SolidStrokeFilter::SolidStrokeFilter(SolidStrokeMode mode) : styleMode(mode) { +std::shared_ptr SolidStrokeFilter::CreateFilter( + const SolidStrokeOption& option, SolidStrokeMode mode, std::shared_ptr source) { + if (!option.valid()) { + return nullptr; + } + std::shared_ptr effect; + if (mode == SolidStrokeMode::Normal) { + effect = SolidStrokeNormalFilter::Make(option, std::move(source)); + } else { + effect = SolidStrokeThickFilter::Make(option, std::move(source)); + } + return tgfx::ImageFilter::Runtime(effect); } -std::string SolidStrokeFilter::onBuildFragmentShader() { - if (styleMode == SolidStrokeMode::Thick) { - return SOLID_STROKE_THICK_FRAGMENT_SHADER; +std::shared_ptr SolidStrokeNormalFilter::Make( + SolidStrokeOption option, std::shared_ptr originalImage) { + if (originalImage) { + return std::make_shared(option, std::move(originalImage)); + } else { + return std::make_shared(option); } - return SOLID_STROKE_FRAGMENT_SHADER; } -void SolidStrokeFilter::onPrepareProgram(tgfx::Context* context, unsigned program) { - auto gl = tgfx::GLFunctions::Get(context); - originalTextureHandle = gl->getUniformLocation(program, "uOriginalTextureInput"); - isUseOriginalTextureHandle = gl->getUniformLocation(program, "uIsUseOriginalTexture"); - colorHandle = gl->getUniformLocation(program, "uColor"); - alphaHandle = gl->getUniformLocation(program, "uAlpha"); - sizeHandle = gl->getUniformLocation(program, "uSize"); - isOutsideHandle = gl->getUniformLocation(program, "uIsOutside"); - isCenterHandle = gl->getUniformLocation(program, "uIsCenter"); - isInsideHandle = gl->getUniformLocation(program, "uIsInside"); +std::shared_ptr SolidStrokeThickFilter::Make( + SolidStrokeOption option, std::shared_ptr originalImage) { + if (originalImage) { + return std::make_shared(option, std::move(originalImage)); + } else { + return std::make_shared(option); + } +} + +std::string SolidStrokeNormalFilter::onBuildFragmentShader() const { + return SOLID_STROKE_FRAGMENT_SHADER; } -void SolidStrokeFilter::onUpdateOption(SolidStrokeOption newOption) { - option = newOption; +std::string SolidStrokeThickFilter::onBuildFragmentShader() const { + return SOLID_STROKE_THICK_FRAGMENT_SHADER; } -void SolidStrokeFilter::onUpdateOriginalTexture(const tgfx::GLTextureInfo* sampler) { - originalSampler = {sampler->id, sampler->target, sampler->format}; +std::unique_ptr SolidStrokeFilter::onPrepareProgram(tgfx::Context* context, + unsigned program) const { + return std::make_unique(context, program); } -void SolidStrokeFilter::onUpdateParams(tgfx::Context* context, const tgfx::Rect& contentBounds, - const tgfx::Point& filterScale) { - auto color = ToTGFX(option.color); - auto alpha = ToAlpha(option.opacity); +void SolidStrokeFilter::onUpdateParams(tgfx::Context* context, const RuntimeProgram* program, + const std::vector& sources) const { - auto spreadSizeX = option.spreadSize * filterScale.x; - auto spreadSizeY = option.spreadSize * filterScale.y; + auto color = option.color; + auto spreadSizeX = option.spreadSizeX; + auto spreadSizeY = option.spreadSizeY; spreadSizeX = std::min(spreadSizeX, STROKE_MAX_SPREAD_SIZE); spreadSizeY = std::min(spreadSizeY, STROKE_MAX_SPREAD_SIZE); + auto uniforms = static_cast(program->uniforms.get()); auto gl = tgfx::GLFunctions::Get(context); - if (originalSampler.id != 0) { - ActiveGLTexture(context, 1, &originalSampler); - gl->uniform1i(originalTextureHandle, 1); - gl->uniform1f(isUseOriginalTextureHandle, 1.0); + if (hasOriginalImage) { + gl->uniform1i(uniforms->originalTextureHandle, 1); + gl->uniform1f(uniforms->isUseOriginalTextureHandle, 1.0); } else { - gl->uniform1f(isUseOriginalTextureHandle, 0.0); + gl->uniform1f(uniforms->isUseOriginalTextureHandle, 0.0); } - gl->uniform3f(colorHandle, color.red, color.green, color.blue); - gl->uniform1f(alphaHandle, alpha); - gl->uniform2f(sizeHandle, spreadSizeX / contentBounds.width(), - spreadSizeY / contentBounds.height()); - gl->uniform1f(isOutsideHandle, option.position == StrokePosition::Outside); - gl->uniform1f(isCenterHandle, option.position == StrokePosition::Center); - gl->uniform1f(isInsideHandle, option.position == StrokePosition::Inside); + gl->uniform3f(uniforms->colorHandle, color.red, color.green, color.blue); + gl->uniform2f(uniforms->sizeHandle, spreadSizeX / sources[0].width(), + spreadSizeY / sources[0].height()); + gl->uniform1f(uniforms->isOutsideHandle, option.position == StrokePosition::Outside); + gl->uniform1f(uniforms->isCenterHandle, option.position == StrokePosition::Center); + gl->uniform1f(uniforms->isInsideHandle, option.position == StrokePosition::Inside); } -std::vector SolidStrokeFilter::computeVertices(const tgfx::Rect&, - const tgfx::Rect& outputBounds, - const tgfx::Point& filterScale) { - std::vector vertices = {}; +std::vector SolidStrokeFilter::computeVertices( + const std::vector& sources, const tgfx::BackendRenderTarget& target, + const tgfx::Point&) const { + auto outputBounds = tgfx::Rect::MakeWH(target.width(), target.height()); + std::vector vertices = {}; tgfx::Point contentPoint[4] = {{outputBounds.left, outputBounds.bottom}, {outputBounds.right, outputBounds.bottom}, {outputBounds.left, outputBounds.top}, {outputBounds.right, outputBounds.top}}; - auto deltaX = -option.spreadSize * filterScale.x; - auto deltaY = -option.spreadSize * filterScale.y; + auto deltaX = -option.spreadSizeX; + auto deltaY = -option.spreadSizeY; tgfx::Point texturePoints[4] = { {deltaX, (outputBounds.height() + deltaY)}, {(outputBounds.width() + deltaX), (outputBounds.height() + deltaY)}, {deltaX, deltaY}, {(outputBounds.width() + deltaX), deltaY}}; - for (int ii = 0; ii < 4; ii++) { - vertices.push_back(contentPoint[ii]); - vertices.push_back(texturePoints[ii]); + + for (size_t i = 0; i < 4; i++) { + auto vertexPoint = ToGLVertexPoint(target, contentPoint[i]); + vertices.push_back(vertexPoint.x); + vertices.push_back(vertexPoint.y); + auto texturePoint = ToGLTexturePoint(&sources[0], texturePoints[i]); + vertices.push_back(texturePoint.x); + vertices.push_back(texturePoint.y); } return vertices; } + +tgfx::Rect SolidStrokeFilter::filterBounds(const tgfx::Rect& srcRect) const { + auto desRect = srcRect.makeOutset(option.spreadSizeX, option.spreadSizeY); + desRect.offset(option.offsetX, option.offsetY); + return desRect; +} + } // namespace pag diff --git a/src/rendering/filters/layerstyle/SolidStrokeFilter.h b/src/rendering/filters/layerstyle/SolidStrokeFilter.h index 628b706e0c..83c9e93d36 100644 --- a/src/rendering/filters/layerstyle/SolidStrokeFilter.h +++ b/src/rendering/filters/layerstyle/SolidStrokeFilter.h @@ -18,51 +18,111 @@ #pragma once -#include "rendering/filters/LayerFilter.h" +#include +#include "rendering/filters/RuntimeFilter.h" +#include "rendering/filters/utils/FilterHelper.h" +#include "tgfx/core/Color.h" namespace pag { enum class SolidStrokeMode { Normal, Thick }; struct SolidStrokeOption { Enum position = -1; - Color color = Black; - float opacity = 0.0f; - float spreadSize = 0.0f; + tgfx::Color color = tgfx::Color::Black(); + float spreadSizeX = 0.0f; + float spreadSizeY = 0.0f; + float offsetX = 0.0f; + float offsetY = 0.0f; + + bool valid() const { + return spreadSizeX != 0 || spreadSizeY != 0 || offsetX != 0 || offsetY != 0; + } }; -class SolidStrokeFilter : public LayerFilter { +class SolidStrokeUniforms : public Uniforms { public: - explicit SolidStrokeFilter(SolidStrokeMode mode); - ~SolidStrokeFilter() override = default; + SolidStrokeUniforms(tgfx::Context* context, unsigned program) : Uniforms(context, program) { + auto gl = tgfx::GLFunctions::Get(context); + originalTextureHandle = gl->getUniformLocation(program, "uOriginalTextureInput"); + isUseOriginalTextureHandle = gl->getUniformLocation(program, "uIsUseOriginalTexture"); + colorHandle = gl->getUniformLocation(program, "uColor"); + sizeHandle = gl->getUniformLocation(program, "uSize"); + isOutsideHandle = gl->getUniformLocation(program, "uIsOutside"); + isCenterHandle = gl->getUniformLocation(program, "uIsCenter"); + isInsideHandle = gl->getUniformLocation(program, "uIsInside"); + CheckGLError(context); + } + int colorHandle = -1; + int sizeHandle = -1; + int originalTextureHandle = -1; + int isUseOriginalTextureHandle = -1; + int isOutsideHandle = -1; + int isCenterHandle = -1; + int isInsideHandle = -1; +}; + +class SolidStrokeFilter : public RuntimeFilter { + public: + static std::shared_ptr CreateFilter( + const SolidStrokeOption& option, SolidStrokeMode mode, + std::shared_ptr source = nullptr); - void onUpdateOption(SolidStrokeOption option); + SolidStrokeFilter(tgfx::UniqueType type, const SolidStrokeOption& option) + : RuntimeFilter(std::move(type)), option(option) { + } - void onUpdateOriginalTexture(const tgfx::GLTextureInfo* sampler); + SolidStrokeFilter(tgfx::UniqueType type, const SolidStrokeOption& option, + std::shared_ptr originalImage) + : RuntimeFilter(std::move(type), {std::move(originalImage)}), option(option), + hasOriginalImage(true) { + } - protected: - std::string onBuildFragmentShader() override; + std::unique_ptr onPrepareProgram(tgfx::Context* context, + unsigned program) const override; - void onPrepareProgram(tgfx::Context* context, unsigned program) override; + void onUpdateParams(tgfx::Context* context, const RuntimeProgram* program, + const std::vector& sources) const override; - void onUpdateParams(tgfx::Context* context, const tgfx::Rect& contentBounds, - const tgfx::Point& filterScale) override; + std::vector computeVertices(const std::vector& sources, + const tgfx::BackendRenderTarget& target, + const tgfx::Point& offset) const override; - std::vector computeVertices(const tgfx::Rect& contentBounds, - const tgfx::Rect& transformedBounds, - const tgfx::Point& filterScale) override; + tgfx::Rect filterBounds(const tgfx::Rect& srcRect) const override; - private: SolidStrokeOption option; - SolidStrokeMode styleMode; - tgfx::GLTextureInfo originalSampler; - int colorHandle = -1; - int alphaHandle = -1; - int sizeHandle = -1; - int originalTextureHandle = -1; - int isUseOriginalTextureHandle = -1; - int isOutsideHandle = -1; - int isCenterHandle = -1; - int isInsideHandle = -1; + bool hasOriginalImage = false; +}; + +class SolidStrokeNormalFilter : public SolidStrokeFilter { + public: + DEFINE_RUNTIME_EFFECT_TYPE + static std::shared_ptr Make(SolidStrokeOption option, + std::shared_ptr originalImage); + explicit SolidStrokeNormalFilter(SolidStrokeOption option) : SolidStrokeFilter(Type(), option) { + } + SolidStrokeNormalFilter(SolidStrokeOption option, std::shared_ptr originalImage) + : SolidStrokeFilter(Type(), option, std::move(originalImage)) { + } + + std::string onBuildFragmentShader() const override; }; + +class SolidStrokeThickFilter : public SolidStrokeFilter { + public: + DEFINE_RUNTIME_EFFECT_TYPE + + static std::shared_ptr Make(SolidStrokeOption option, + std::shared_ptr originalImage); + + explicit SolidStrokeThickFilter(SolidStrokeOption option) : SolidStrokeFilter(Type(), option) { + } + + SolidStrokeThickFilter(SolidStrokeOption option, std::shared_ptr originalImage) + : SolidStrokeFilter(Type(), option, std::move(originalImage)) { + } + + std::string onBuildFragmentShader() const override; +}; + } // namespace pag diff --git a/src/rendering/filters/layerstyle/StrokeFilter.cpp b/src/rendering/filters/layerstyle/StrokeFilter.cpp index cff9953aa1..541aa112eb 100644 --- a/src/rendering/filters/layerstyle/StrokeFilter.cpp +++ b/src/rendering/filters/layerstyle/StrokeFilter.cpp @@ -17,111 +17,66 @@ ///////////////////////////////////////////////////////////////////////////////////////////////// #include "StrokeFilter.h" -#include "base/utils/MathUtil.h" -#include "base/utils/TGFXCast.h" +#include "rendering/filters/layerstyle/AlphaEdgeDetectFilter.h" +#include "rendering/filters/layerstyle/SolidStrokeFilter.h" #include "rendering/filters/utils/BlurTypes.h" -#include "rendering/filters/utils/FilterHelper.h" +#include "tgfx/core/Canvas.h" #include "tgfx/core/ImageFilter.h" +#include "tgfx/core/Paint.h" namespace pag { StrokeFilter::StrokeFilter(StrokeStyle* layerStyle) : layerStyle(layerStyle) { - strokeFilter = new SolidStrokeFilter(SolidStrokeMode::Normal); - strokeThickFilter = new SolidStrokeFilter(SolidStrokeMode::Thick); - alphaEdgeDetectFilter = new AlphaEdgeDetectFilter(); } -StrokeFilter::~StrokeFilter() { - delete strokeFilter; - delete strokeThickFilter; - delete alphaEdgeDetectFilter; -} - -bool StrokeFilter::initialize(tgfx::Context* context) { - if (!strokeFilter->initialize(context) || !strokeThickFilter->initialize(context) || - !alphaEdgeDetectFilter->initialize(context)) { - return false; - } - return true; -} - -void StrokeFilter::update(Frame frame, const tgfx::Rect& contentBounds, - const tgfx::Rect& transformedBounds, const tgfx::Point& filterScale) { - LayerFilter::update(frame, contentBounds, transformedBounds, filterScale); - - strokePosition = layerStyle->position->getValueAt(layerFrame); - spreadSize = layerStyle->size->getValueAt(layerFrame); - +void StrokeFilter::update(Frame layerFrame, const tgfx::Point& filterScale, + const tgfx::Point& sourceScale) { + auto totalScale = tgfx::Point::Make(filterScale.x * sourceScale.x, filterScale.y * sourceScale.y); strokeOption = SolidStrokeOption(); - strokeOption.color = layerStyle->color->getValueAt(layerFrame); - strokeOption.opacity = layerStyle->opacity->getValueAt(layerFrame); - strokeOption.spreadSize = spreadSize; - strokeOption.position = strokePosition; + auto spreadSize = layerStyle->size->getValueAt(layerFrame); + mode = + spreadSize < STROKE_SPREAD_MIN_THICK_SIZE ? SolidStrokeMode::Normal : SolidStrokeMode::Thick; + auto sizeX = spreadSize * totalScale.x; + ; + auto sizeY = spreadSize * totalScale.y; + auto color = ToTGFX(layerStyle->color->getValueAt(layerFrame)); + auto position = layerStyle->position->getValueAt(layerFrame); + strokeOption.color = color; + strokeOption.spreadSizeX = sizeX; + strokeOption.spreadSizeY = sizeY; + strokeOption.position = position; - if (strokePosition == StrokePosition::Center) { - strokeOption.spreadSize *= 0.4; - } else if (strokePosition == StrokePosition::Inside) { - strokeOption.spreadSize *= 0.8; + if (position == StrokePosition::Center) { + strokeOption.spreadSizeX *= 0.4; + strokeOption.spreadSizeY *= 0.4; + } else if (position == StrokePosition::Inside) { + strokeOption.spreadSizeX *= 0.8; + strokeOption.spreadSizeY *= 0.8; } - auto filterBounds = contentBounds; - filterBounds.outset(spreadSize * filterScale.x, spreadSize * filterScale.y); - filterBounds.roundOut(); - alphaEdgeDetectFilter->update(layerFrame, contentBounds, contentBounds, filterScale); - if (spreadSize < STROKE_SPREAD_MIN_THICK_SIZE) { - strokeFilter->onUpdateOption(strokeOption); - strokeFilter->update(layerFrame, contentBounds, filterBounds, filterScale); - } else { - strokeThickFilter->onUpdateOption(strokeOption); - strokeThickFilter->update(layerFrame, contentBounds, filterBounds, filterScale); - } + alpha = ToAlpha(layerStyle->opacity->getValueAt(layerFrame)); } -void StrokeFilter::draw(tgfx::Context* context, const FilterSource* source, - const FilterTarget* target) { - if (source == nullptr || target == nullptr) { - return; - } - if (strokePosition == StrokePosition::Outside) { - onDrawPositionOutside(context, source, target); - } else { - onDrawPositionInsideOrCenter(context, source, target); - } -} +bool StrokeFilter::draw(tgfx::Canvas* canvas, std::shared_ptr image) { -void StrokeFilter::onDrawPositionOutside(tgfx::Context* context, const FilterSource* source, - const FilterTarget* target) { - if (spreadSize < STROKE_SPREAD_MIN_THICK_SIZE) { - strokeFilter->draw(context, source, target); + std::shared_ptr filter = nullptr; + if (strokeOption.position == StrokePosition::Outside) { + filter = SolidStrokeFilter::CreateFilter(strokeOption, mode, nullptr); } else { - strokeThickFilter->draw(context, source, target); - } -} - -void StrokeFilter::onDrawPositionInsideOrCenter(tgfx::Context* context, const FilterSource* source, - const FilterTarget* target) { - auto targetWidth = source->width; - auto targetHeight = source->height; - if (alphaEdgeDetectFilterBuffer == nullptr || - alphaEdgeDetectFilterBuffer->width() != targetWidth || - alphaEdgeDetectFilterBuffer->height() != targetHeight) { - alphaEdgeDetectFilterBuffer = FilterBuffer::Make(context, targetWidth, targetHeight); - } - if (alphaEdgeDetectFilterBuffer == nullptr) { - return; + auto strokeFilter = SolidStrokeFilter::CreateFilter(strokeOption, mode, image); + if (strokeFilter == nullptr) { + return false; + } + auto alphaEdgeDetectFilter = + tgfx::ImageFilter::Runtime(std::make_shared()); + filter = tgfx::ImageFilter::Compose(alphaEdgeDetectFilter, strokeFilter); } - - alphaEdgeDetectFilterBuffer->clearColor(); - auto alphaEdgeDetectTarget = alphaEdgeDetectFilterBuffer->toFilterTarget(tgfx::Matrix::I()); - alphaEdgeDetectFilter->draw(context, source, alphaEdgeDetectTarget.get()); - - auto newSource = alphaEdgeDetectFilterBuffer->toFilterSource(source->scale); - - if (spreadSize < STROKE_SPREAD_MIN_THICK_SIZE) { - strokeFilter->onUpdateOriginalTexture(&source->sampler); - strokeFilter->draw(context, newSource.get(), target); - } else { - strokeThickFilter->onUpdateOriginalTexture(&source->sampler); - strokeThickFilter->draw(context, newSource.get(), target); + if (filter == nullptr) { + return false; } + tgfx::Paint paint; + paint.setImageFilter(filter); + paint.setAlpha(alpha); + canvas->drawImage(image, &paint); + return true; } } // namespace pag diff --git a/src/rendering/filters/layerstyle/StrokeFilter.h b/src/rendering/filters/layerstyle/StrokeFilter.h index 7db125fb44..2d90426f96 100644 --- a/src/rendering/filters/layerstyle/StrokeFilter.h +++ b/src/rendering/filters/layerstyle/StrokeFilter.h @@ -17,14 +17,10 @@ ///////////////////////////////////////////////////////////////////////////////////////////////// #pragma once - -#include "AlphaEdgeDetectFilter.h" -#include "SolidStrokeFilter.h" -#include "rendering/filters/LayerFilter.h" -#include "rendering/filters/utils/FilterBuffer.h" - +#include "LayerStyleFilter.h" +#include "rendering/filters/layerstyle/SolidStrokeFilter.h" namespace pag { -class StrokeFilter : public LayerFilter { +class StrokeFilter : public LayerStyleFilter { public: explicit StrokeFilter(StrokeStyle* layerStyle); @@ -32,34 +28,15 @@ class StrokeFilter : public LayerFilter { StrokeFilter(StrokeFilter&&) = delete; - ~StrokeFilter() override; - - bool initialize(tgfx::Context* context) override; + void update(Frame layerFrame, const tgfx::Point& filterScale, + const tgfx::Point& sourceScale) override; - void update(Frame frame, const tgfx::Rect& contentBounds, const tgfx::Rect& transformedBounds, - const tgfx::Point& filterScale) override; - - void draw(tgfx::Context* context, const FilterSource* source, - const FilterTarget* target) override; + bool draw(tgfx::Canvas* canvas, std::shared_ptr image) override; private: - void onDrawPositionOutside(tgfx::Context* context, const FilterSource* source, - const FilterTarget* target); - void onDrawPositionInsideOrCenter(tgfx::Context* context, const FilterSource* source, - const FilterTarget* target); - StrokeStyle* layerStyle = nullptr; - - std::shared_ptr alphaEdgeDetectFilterBuffer = nullptr; - - Enum strokePosition; - SolidStrokeOption strokeOption; - SolidStrokeFilter* strokeFilter = nullptr; - SolidStrokeFilter* strokeThickFilter = nullptr; - AlphaEdgeDetectFilter* alphaEdgeDetectFilter = nullptr; - - tgfx::Color color = tgfx::Color::Black(); - float spreadSize = 0.f; + SolidStrokeMode mode = SolidStrokeMode::Normal; + float alpha = 1.0f; }; } // namespace pag diff --git a/src/rendering/filters/utils/FilterHelper.cpp b/src/rendering/filters/utils/FilterHelper.cpp index 6131f0a2f0..2678254ffb 100644 --- a/src/rendering/filters/utils/FilterHelper.cpp +++ b/src/rendering/filters/utils/FilterHelper.cpp @@ -49,6 +49,9 @@ std::array ToGLVertexMatrix(const tgfx::Matrix& matrix, int width, int std::array ToGLTextureMatrix(const tgfx::Matrix& matrix, int width, int height, tgfx::ImageOrigin origin) { + if (matrix.isIdentity() && origin == tgfx::ImageOrigin::TopLeft) { + return ToGLMatrix(matrix); + } auto result = matrix; tgfx::Matrix convertMatrix = {}; convertMatrix.setScale(static_cast(width), static_cast(height)); @@ -64,9 +67,7 @@ std::array ToGLTextureMatrix(const tgfx::Matrix& matrix, int width, in } tgfx::Matrix ToMatrix(const FilterTarget* target, bool flipY) { - tgfx::Matrix matrix = {}; - auto values = target->vertexMatrix; - matrix.setAll(values[0], values[3], values[6], values[1], values[4], values[7]); + tgfx::Matrix matrix = ToMatrix(target->vertexMatrix); if (flipY) { matrix.postScale(1.0f, -1.0f); } @@ -83,6 +84,12 @@ tgfx::Matrix ToMatrix(const FilterTarget* target, bool flipY) { return matrix; } +tgfx::Matrix ToMatrix(const std::array& values) { + tgfx::Matrix result = {}; + result.setAll(values[0], values[3], values[6], values[1], values[4], values[7]); + return result; +} + std::unique_ptr ToFilterSource(const tgfx::BackendTexture& backendTexture, tgfx::ImageOrigin origin, const tgfx::Point& scale) { if (!backendTexture.isValid()) { @@ -126,6 +133,16 @@ tgfx::Point ToGLVertexPoint(const FilterTarget* target, const FilterSource* sour 2.0f * vertexPoint.y / static_cast(target->height) - 1.0f}; } +tgfx::Point ToGLTexturePoint(const tgfx::BackendTexture* source, const tgfx::Point& texturePoint) { + return {texturePoint.x / static_cast(source->width()), + texturePoint.y / static_cast(source->height())}; +} + +tgfx::Point ToGLVertexPoint(const tgfx::BackendRenderTarget& target, const tgfx::Point& point) { + return {2.0f * point.x / static_cast(target.width()) - 1.0f, + 2.0f * point.y / static_cast(target.height()) - 1.0f}; +} + static unsigned LoadGLShader(tgfx::Context* context, unsigned shaderType, const std::string& source) { auto gl = tgfx::GLFunctions::Get(context); diff --git a/src/rendering/filters/utils/FilterHelper.h b/src/rendering/filters/utils/FilterHelper.h index 5d004e0319..ca544dc6e4 100644 --- a/src/rendering/filters/utils/FilterHelper.h +++ b/src/rendering/filters/utils/FilterHelper.h @@ -36,6 +36,8 @@ std::array ToGLTextureMatrix(const tgfx::Matrix& matrix, int width, in tgfx::Matrix ToMatrix(const FilterTarget* target, bool flipY = false); +tgfx::Matrix ToMatrix(const std::array& matrix); + std::unique_ptr ToFilterSource(const tgfx::BackendTexture& texture, tgfx::ImageOrigin origin, const tgfx::Point& scale); @@ -47,6 +49,10 @@ tgfx::Point ToGLTexturePoint(const FilterSource* source, const tgfx::Point& text tgfx::Point ToGLVertexPoint(const FilterTarget* target, const FilterSource* source, const tgfx::Rect& contentBounds, const tgfx::Point& contentPoint); +tgfx::Point ToGLTexturePoint(const tgfx::BackendTexture* source, const tgfx::Point& texturePoint); + +tgfx::Point ToGLVertexPoint(const tgfx::BackendRenderTarget& target, const tgfx::Point& point); + unsigned CreateGLProgram(tgfx::Context* context, const std::string& vertex, const std::string& fragment); diff --git a/src/rendering/renderers/FilterRenderer.cpp b/src/rendering/renderers/FilterRenderer.cpp index 5b9463c055..4c2f457d1a 100644 --- a/src/rendering/renderers/FilterRenderer.cpp +++ b/src/rendering/renderers/FilterRenderer.cpp @@ -162,13 +162,12 @@ static bool MakeLayerStyleNode(std::vector& filterNodes, tgfx::Rect& return false; } auto layerStyleScale = filterList->layerStyleScale; - auto oldBounds = filterBounds; LayerStylesFilter::TransformBounds(&filterBounds, filterList); filterBounds.roundOut(); - filter->update(filterList, oldBounds, filterBounds, layerStyleScale); if (!filterBounds.intersect(clipBounds)) { return false; } + filter->update(filterList, layerStyleScale); filterNodes.emplace_back(filter, filterBounds); } return true; @@ -200,7 +199,7 @@ bool FilterRenderer::MakeEffectNode(std::vector& filterNodes, tgfx:: int clipIndex) { auto effectIndex = 0; for (auto& effect : filterList->effects) { - auto filter = renderCache->getFilterCache(effect); + auto filter = static_cast(renderCache->getFilterCache(effect)); if (filter) { auto oldBounds = filterBounds; effect->transformBounds(ToPAG(&filterBounds), ToPAG(effectScale), filterList->layerFrame); @@ -471,9 +470,10 @@ void FilterRenderer::DrawWithFilter(Canvas* parentCanvas, const FilterModifier* // 必须要flush,要不然framebuffer还没真正画到canvas,就被其他图层的filter串改了该framebuffer context->flush(); ApplyFilters(context, filterNodes, contentBounds, filterSource.get(), filterTarget.get()); + // contentSurface在函数结束时析构,防止filter仍然使用contentSurface,需要在最后flush一下 + context->flush(); // Reset the GL states stored in the context, they may be modified during the filter being applied. context->resetState(); - if (targetSurface) { tgfx::Matrix drawingMatrix = {}; auto targetCanvas = targetSurface->getCanvas(); diff --git a/test/baseline/version.json b/test/baseline/version.json index 7329de4c65..98f754c74c 100644 --- a/test/baseline/version.json +++ b/test/baseline/version.json @@ -755,126 +755,126 @@ "0000": "b434229f" }, "data_vector.pag": { - "0000": "b434229f", - "0001": "b434229f", - "0002": "b434229f", - "0003": "b434229f", - "0004": "b434229f", - "0005": "b434229f", - "0006": "b434229f", - "0007": "b434229f", - "0008": "b434229f", - "0009": "b434229f", - "0010": "b434229f", - "0011": "b434229f", - "0012": "b434229f", - "0013": "b434229f", - "0014": "b434229f", - "0015": "b434229f", - "0016": "b434229f", - "0017": "b434229f", - "0018": "b434229f", - "0019": "b434229f", - "0020": "b434229f", - "0021": "b434229f", - "0022": "b434229f", - "0023": "b434229f", - "0024": "b434229f", - "0025": "b434229f", - "0026": "b434229f", - "0027": "b434229f", - "0028": "b434229f", - "0029": "b434229f", - "0030": "b434229f", - "0031": "b434229f", - "0032": "b434229f", - "0033": "b434229f", - "0034": "b434229f", - "0035": "b434229f", - "0036": "b434229f", - "0037": "b434229f", - "0038": "b434229f", - "0039": "b434229f", - "0040": "b434229f", - "0041": "b434229f", - "0042": "b434229f", - "0043": "b434229f", - "0044": "b434229f", - "0045": "b434229f", - "0046": "b434229f", - "0047": "b434229f", - "0048": "b434229f", - "0049": "b434229f", - "0050": "b434229f", - "0051": "b434229f", - "0052": "b434229f", - "0053": "b434229f", - "0054": "b434229f", - "0055": "b434229f", - "0056": "b434229f", - "0057": "b434229f", - "0058": "b434229f", - "0059": "b434229f", - "0060": "b434229f", - "0061": "b434229f", - "0062": "b434229f", - "0063": "b434229f", - "0064": "b434229f", - "0065": "b434229f", - "0066": "b434229f", - "0067": "b434229f", - "0068": "b434229f", - "0069": "b434229f", - "0070": "b434229f", - "0071": "b434229f", - "0072": "b434229f", - "0073": "b434229f", - "0074": "b434229f", - "0075": "b434229f", - "0076": "b434229f", - "0077": "b434229f", - "0078": "b434229f", - "0079": "b434229f", - "0080": "b434229f", - "0081": "b434229f", - "0082": "b434229f", - "0083": "b434229f", - "0084": "b434229f", - "0085": "b434229f", - "0086": "b434229f", - "0087": "b434229f", - "0088": "b434229f", - "0089": "b434229f", - "0090": "b434229f", - "0091": "b434229f", - "0092": "b434229f", - "0093": "b434229f", - "0094": "b434229f", - "0095": "b434229f", - "0096": "b434229f", - "0097": "b434229f", - "0098": "b434229f", - "0099": "b434229f", - "0100": "b434229f", - "0101": "b434229f", - "0102": "b434229f", - "0103": "b434229f", - "0104": "b434229f", - "0105": "b434229f", - "0106": "b434229f", - "0107": "b434229f", - "0108": "b434229f", - "0109": "b434229f", - "0110": "b434229f", - "0111": "b434229f", - "0112": "b434229f", - "0113": "b434229f", - "0114": "b434229f", - "0115": "b434229f", - "0116": "b434229f", - "0117": "b434229f", - "0118": "b434229f", - "0119": "b434229f" + "0000": "2925cbf0", + "0001": "2925cbf0", + "0002": "2925cbf0", + "0003": "2925cbf0", + "0004": "2925cbf0", + "0005": "2925cbf0", + "0006": "2925cbf0", + "0007": "2925cbf0", + "0008": "2925cbf0", + "0009": "2925cbf0", + "0010": "2925cbf0", + "0011": "2925cbf0", + "0012": "2925cbf0", + "0013": "2925cbf0", + "0014": "2925cbf0", + "0015": "2925cbf0", + "0016": "2925cbf0", + "0017": "2925cbf0", + "0018": "2925cbf0", + "0019": "2925cbf0", + "0020": "2925cbf0", + "0021": "2925cbf0", + "0022": "2925cbf0", + "0023": "2925cbf0", + "0024": "2925cbf0", + "0025": "2925cbf0", + "0026": "2925cbf0", + "0027": "2925cbf0", + "0028": "2925cbf0", + "0029": "2925cbf0", + "0030": "2925cbf0", + "0031": "2925cbf0", + "0032": "2925cbf0", + "0033": "2925cbf0", + "0034": "2925cbf0", + "0035": "2925cbf0", + "0036": "2925cbf0", + "0037": "2925cbf0", + "0038": "2925cbf0", + "0039": "2925cbf0", + "0040": "2925cbf0", + "0041": "2925cbf0", + "0042": "2925cbf0", + "0043": "2925cbf0", + "0044": "2925cbf0", + "0045": "2925cbf0", + "0046": "2925cbf0", + "0047": "2925cbf0", + "0048": "2925cbf0", + "0049": "2925cbf0", + "0050": "2925cbf0", + "0051": "2925cbf0", + "0052": "2925cbf0", + "0053": "2925cbf0", + "0054": "2925cbf0", + "0055": "2925cbf0", + "0056": "2925cbf0", + "0057": "2925cbf0", + "0058": "2925cbf0", + "0059": "2925cbf0", + "0060": "2925cbf0", + "0061": "2925cbf0", + "0062": "2925cbf0", + "0063": "2925cbf0", + "0064": "2925cbf0", + "0065": "2925cbf0", + "0066": "2925cbf0", + "0067": "2925cbf0", + "0068": "2925cbf0", + "0069": "2925cbf0", + "0070": "2925cbf0", + "0071": "2925cbf0", + "0072": "2925cbf0", + "0073": "2925cbf0", + "0074": "2925cbf0", + "0075": "2925cbf0", + "0076": "2925cbf0", + "0077": "2925cbf0", + "0078": "2925cbf0", + "0079": "2925cbf0", + "0080": "2925cbf0", + "0081": "2925cbf0", + "0082": "2925cbf0", + "0083": "2925cbf0", + "0084": "2925cbf0", + "0085": "2925cbf0", + "0086": "2925cbf0", + "0087": "2925cbf0", + "0088": "2925cbf0", + "0089": "2925cbf0", + "0090": "2925cbf0", + "0091": "2925cbf0", + "0092": "2925cbf0", + "0093": "2925cbf0", + "0094": "2925cbf0", + "0095": "2925cbf0", + "0096": "2925cbf0", + "0097": "2925cbf0", + "0098": "2925cbf0", + "0099": "2925cbf0", + "0100": "2925cbf0", + "0101": "2925cbf0", + "0102": "2925cbf0", + "0103": "2925cbf0", + "0104": "2925cbf0", + "0105": "2925cbf0", + "0106": "2925cbf0", + "0107": "2925cbf0", + "0108": "2925cbf0", + "0109": "2925cbf0", + "0110": "2925cbf0", + "0111": "2925cbf0", + "0112": "2925cbf0", + "0113": "2925cbf0", + "0114": "2925cbf0", + "0115": "2925cbf0", + "0116": "2925cbf0", + "0117": "2925cbf0", + "0118": "2925cbf0", + "0119": "2925cbf0" }, "displacement_map_shape.pag": { "0000": "30dab356", @@ -2654,9 +2654,9 @@ "0360": "088c7e93", "0361": "088c7e93", "0362": "088c7e93", - "0363": "088c7e93", - "0364": "088c7e93", - "0365": "088c7e93", + "0363": "7619ec91", + "0364": "7619ec91", + "0365": "7619ec91", "0366": "088c7e93", "0367": "088c7e93", "0368": "088c7e93", @@ -2715,64 +2715,64 @@ "0433": "088c7e93", "0434": "088c7e93", "0435": "088c7e93", - "0436": "088c7e93", - "0437": "088c7e93", - "0438": "088c7e93", - "0439": "088c7e93", - "0440": "088c7e93", - "0441": "088c7e93", - "0442": "088c7e93", - "0443": "088c7e93", - "0444": "088c7e93", - "0445": "088c7e93", - "0446": "088c7e93", - "0447": "088c7e93", - "0448": "088c7e93", - "0449": "088c7e93", - "0450": "088c7e93", - "0451": "088c7e93", - "0452": "088c7e93", - "0453": "088c7e93", - "0454": "088c7e93", - "0455": "088c7e93", - "0456": "088c7e93", - "0457": "088c7e93", - "0458": "088c7e93", - "0459": "088c7e93", - "0460": "088c7e93", - "0461": "088c7e93", - "0462": "088c7e93", - "0463": "088c7e93", - "0464": "088c7e93", - "0465": "088c7e93", - "0466": "088c7e93", - "0467": "088c7e93", - "0468": "088c7e93", - "0469": "088c7e93", - "0470": "088c7e93", - "0471": "088c7e93", - "0472": "088c7e93", - "0473": "088c7e93", - "0474": "088c7e93", - "0475": "4b7f3114", - "0476": "088c7e93", - "0477": "088c7e93", - "0478": "4b7f3114", - "0479": "4b7f3114", - "0480": "4b7f3114", - "0481": "088c7e93", - "0482": "088c7e93", - "0483": "088c7e93", - "0484": "4b7f3114", - "0485": "4b7f3114", - "0486": "088c7e93", - "0487": "4b7f3114", - "0488": "088c7e93", - "0489": "4b7f3114", - "0490": "4b7f3114", - "0491": "4b7f3114", - "0492": "4b7f3114", - "0493": "4b7f3114", + "0436": "52a195f3", + "0437": "52a195f3", + "0438": "52a195f3", + "0439": "52a195f3", + "0440": "52a195f3", + "0441": "52a195f3", + "0442": "52a195f3", + "0443": "c4014ba2", + "0444": "52a195f3", + "0445": "52a195f3", + "0446": "2925cbf0", + "0447": "52a195f3", + "0448": "52a195f3", + "0449": "52a195f3", + "0450": "52a195f3", + "0451": "52a195f3", + "0452": "c4014ba2", + "0453": "c4014ba2", + "0454": "c4014ba2", + "0455": "c4014ba2", + "0456": "c4014ba2", + "0457": "2925cbf0", + "0458": "c4014ba2", + "0459": "c4014ba2", + "0460": "c4014ba2", + "0461": "c4014ba2", + "0462": "c4014ba2", + "0463": "c4014ba2", + "0464": "c4014ba2", + "0465": "c4014ba2", + "0466": "c4014ba2", + "0467": "c4014ba2", + "0468": "c4014ba2", + "0469": "c4014ba2", + "0470": "c4014ba2", + "0471": "52a195f3", + "0472": "52a195f3", + "0473": "52a195f3", + "0474": "52a195f3", + "0475": "52a195f3", + "0476": "52a195f3", + "0477": "52a195f3", + "0478": "52a195f3", + "0479": "52a195f3", + "0480": "52a195f3", + "0481": "52a195f3", + "0482": "52a195f3", + "0483": "52a195f3", + "0484": "52a195f3", + "0485": "52a195f3", + "0486": "52a195f3", + "0487": "52a195f3", + "0488": "52a195f3", + "0489": "52a195f3", + "0490": "52a195f3", + "0491": "52a195f3", + "0492": "52a195f3", + "0493": "52a195f3", "0494": "088c7e93", "0495": "088c7e93", "0508": "088c7e93", @@ -2786,9 +2786,9 @@ "0516": "2b9d541c", "0517": "088c7e93", "0518": "088c7e93", - "0519": "088c7e93", + "0519": "7619ec91", "0520": "088c7e93", - "0521": "2b9d541c", + "0521": "7619ec91", "0522": "088c7e93", "0523": "088c7e93", "0524": "088c7e93", @@ -2830,30 +2830,30 @@ "0577": "088c7e93", "0578": "088c7e93", "0590": "b434229f", - "0591": "b434229f", - "0592": "b434229f", - "0593": "b434229f", - "0594": "b434229f", - "0595": "b434229f", - "0596": "b434229f", - "0597": "b434229f", - "0598": "b434229f", - "0599": "b434229f", - "0600": "b434229f", - "0601": "b434229f", - "0602": "b434229f", + "0591": "7619ec91", + "0592": "7619ec91", + "0593": "7619ec91", + "0594": "7619ec91", + "0595": "7619ec91", + "0596": "7619ec91", + "0597": "7619ec91", + "0598": "7619ec91", + "0599": "7619ec91", + "0600": "7619ec91", + "0601": "7619ec91", + "0602": "7619ec91", "0603": "b434229f", "0604": "b434229f", "0605": "b434229f", "0606": "b434229f", "0607": "b434229f", "0608": "b434229f", - "0609": "b434229f", + "0609": "7619ec91", "0610": "b434229f", "0611": "b434229f", "0612": "b434229f", - "0613": "b434229f", - "0614": "b434229f", + "0613": "7619ec91", + "0614": "7619ec91", "0615": "b434229f", "0616": "b434229f", "0617": "b434229f", @@ -2954,8 +2954,8 @@ "0712": "088c7e93", "0713": "088c7e93", "0714": "088c7e93", - "0715": "088c7e93", - "0716": "088c7e93", + "0715": "7619ec91", + "0716": "7619ec91", "0717": "088c7e93", "0718": "088c7e93", "0719": "088c7e93", @@ -3069,155 +3069,155 @@ "0827": "088c7e93", "0828": "088c7e93", "0829": "088c7e93", - "0830": "b434229f", - "0831": "b434229f", - "0832": "b434229f", - "0833": "b434229f", - "0834": "b434229f", - "0835": "b434229f", - "0836": "b434229f", - "0837": "b434229f", - "0838": "b434229f", - "0839": "b434229f", - "0840": "b434229f", - "0841": "b434229f", - "0842": "b434229f", - "0843": "b434229f", - "0844": "b434229f", - "0845": "b434229f", - "0846": "b434229f", - "0847": "b434229f", - "0848": "b434229f", - "0849": "b434229f", - "0850": "b434229f", - "0851": "b434229f", - "0852": "b434229f", - "0853": "b434229f", - "0854": "b434229f", - "0855": "b434229f", - "0856": "b434229f", - "0857": "b434229f", - "0858": "b434229f", - "0859": "b434229f", - "0860": "b434229f", - "0861": "b434229f", - "0862": "b434229f", - "0863": "b434229f", - "0864": "b434229f", - "0865": "b434229f", - "0866": "b434229f", - "0867": "b434229f", - "0868": "b434229f", - "0869": "b434229f", - "0870": "b434229f", - "0871": "b434229f", - "0872": "b434229f", - "0873": "b434229f", - "0874": "b434229f", - "0875": "b434229f", - "0876": "b434229f", - "0877": "b434229f", - "0878": "b434229f", - "0879": "b434229f", - "0880": "b434229f", - "0881": "b434229f", - "0882": "b434229f", - "0883": "b434229f", - "0884": "b434229f", - "0885": "b434229f", - "0886": "b434229f", - "0887": "b434229f", - "0888": "b434229f", - "0889": "b434229f", - "0890": "b434229f", - "0891": "b434229f", - "0892": "b434229f", - "0893": "b434229f", - "0894": "b434229f", - "0895": "b434229f", - "0896": "b434229f", - "0897": "b434229f", - "0898": "b434229f", - "0899": "b434229f", - "0900": "b434229f", - "0901": "b434229f", - "0902": "b434229f", - "0903": "b434229f", - "0904": "b434229f", - "0905": "b434229f", - "0906": "b434229f", - "0907": "b434229f", - "0908": "b434229f", - "0909": "b434229f", - "0910": "b434229f", - "0911": "b434229f", - "0912": "b434229f", - "0913": "b434229f", - "0914": "b434229f", - "0915": "b434229f", - "0916": "b434229f", - "0917": "b434229f", - "0918": "b434229f", - "0919": "b434229f", - "0920": "b434229f", - "0921": "b434229f", - "0922": "b434229f", - "0923": "b434229f", - "0924": "b434229f", - "0925": "b434229f", - "0926": "b434229f", - "0927": "b434229f", - "0928": "b434229f", - "0929": "b434229f", - "0930": "b434229f", - "0931": "b434229f", - "0932": "b434229f", - "0933": "b434229f", - "0934": "b434229f", - "0935": "b434229f", - "0936": "b434229f", - "0937": "b434229f", - "0938": "b434229f", - "0939": "b434229f", - "0940": "b434229f", - "0941": "b434229f", - "0942": "b434229f", - "0943": "b434229f", - "0944": "b434229f", - "0945": "b434229f", - "0946": "b434229f", - "0947": "b434229f", - "0948": "b434229f", - "0949": "b434229f", - "0950": "b434229f", - "0951": "b434229f", - "0952": "b434229f", - "0953": "b434229f", - "0954": "b434229f", - "0955": "b434229f", - "0956": "b434229f", - "0957": "b434229f", - "0958": "b434229f", - "0959": "b434229f", - "0960": "b434229f", - "0961": "b434229f", - "0962": "b434229f", - "0963": "b434229f", - "0964": "b434229f", - "0965": "b434229f", - "0966": "b434229f", - "0967": "b434229f", - "0968": "b434229f", - "0969": "b434229f", - "0970": "b434229f", - "0971": "b434229f", - "0972": "b434229f", - "0973": "b434229f", - "0974": "b434229f", - "0975": "b434229f", - "0976": "b434229f", - "0977": "b434229f", - "0978": "b434229f", + "0830": "2925cbf0", + "0831": "2925cbf0", + "0832": "2925cbf0", + "0833": "2925cbf0", + "0834": "2925cbf0", + "0835": "2925cbf0", + "0836": "2925cbf0", + "0837": "2925cbf0", + "0838": "2925cbf0", + "0839": "2925cbf0", + "0840": "2925cbf0", + "0841": "2925cbf0", + "0842": "2925cbf0", + "0843": "2925cbf0", + "0844": "2925cbf0", + "0845": "2925cbf0", + "0846": "2925cbf0", + "0847": "2925cbf0", + "0848": "2925cbf0", + "0849": "2925cbf0", + "0850": "2925cbf0", + "0851": "2925cbf0", + "0852": "2925cbf0", + "0853": "2925cbf0", + "0854": "2925cbf0", + "0855": "2925cbf0", + "0856": "2925cbf0", + "0857": "2925cbf0", + "0858": "2925cbf0", + "0859": "2925cbf0", + "0860": "2925cbf0", + "0861": "2925cbf0", + "0862": "2925cbf0", + "0863": "2925cbf0", + "0864": "2925cbf0", + "0865": "2925cbf0", + "0866": "2925cbf0", + "0867": "2925cbf0", + "0868": "2925cbf0", + "0869": "2925cbf0", + "0870": "2925cbf0", + "0871": "2925cbf0", + "0872": "2925cbf0", + "0873": "2925cbf0", + "0874": "2925cbf0", + "0875": "2925cbf0", + "0876": "2925cbf0", + "0877": "2925cbf0", + "0878": "2925cbf0", + "0879": "2925cbf0", + "0880": "2925cbf0", + "0881": "2925cbf0", + "0882": "2925cbf0", + "0883": "2925cbf0", + "0884": "2925cbf0", + "0885": "2925cbf0", + "0886": "2925cbf0", + "0887": "2925cbf0", + "0888": "2925cbf0", + "0889": "2925cbf0", + "0890": "2925cbf0", + "0891": "2925cbf0", + "0892": "2925cbf0", + "0893": "2925cbf0", + "0894": "2925cbf0", + "0895": "2925cbf0", + "0896": "2925cbf0", + "0897": "2925cbf0", + "0898": "2925cbf0", + "0899": "2925cbf0", + "0900": "2925cbf0", + "0901": "2925cbf0", + "0902": "2925cbf0", + "0903": "2925cbf0", + "0904": "2925cbf0", + "0905": "2925cbf0", + "0906": "2925cbf0", + "0907": "2925cbf0", + "0908": "2925cbf0", + "0909": "2925cbf0", + "0910": "2925cbf0", + "0911": "2925cbf0", + "0912": "2925cbf0", + "0913": "2925cbf0", + "0914": "2925cbf0", + "0915": "2925cbf0", + "0916": "2925cbf0", + "0917": "2925cbf0", + "0918": "2925cbf0", + "0919": "2925cbf0", + "0920": "2925cbf0", + "0921": "2925cbf0", + "0922": "2925cbf0", + "0923": "2925cbf0", + "0924": "2925cbf0", + "0925": "2925cbf0", + "0926": "2925cbf0", + "0927": "2925cbf0", + "0928": "2925cbf0", + "0929": "2925cbf0", + "0930": "2925cbf0", + "0931": "2925cbf0", + "0932": "2925cbf0", + "0933": "2925cbf0", + "0934": "2925cbf0", + "0935": "2925cbf0", + "0936": "2925cbf0", + "0937": "2925cbf0", + "0938": "2925cbf0", + "0939": "2925cbf0", + "0940": "2925cbf0", + "0941": "2925cbf0", + "0942": "2925cbf0", + "0943": "2925cbf0", + "0944": "2925cbf0", + "0945": "2925cbf0", + "0946": "2925cbf0", + "0947": "2925cbf0", + "0948": "2925cbf0", + "0949": "2925cbf0", + "0950": "2925cbf0", + "0951": "2925cbf0", + "0952": "2925cbf0", + "0953": "2925cbf0", + "0954": "2925cbf0", + "0955": "2925cbf0", + "0956": "2925cbf0", + "0957": "2925cbf0", + "0958": "2925cbf0", + "0959": "2925cbf0", + "0960": "2925cbf0", + "0961": "2925cbf0", + "0962": "2925cbf0", + "0963": "2925cbf0", + "0964": "2925cbf0", + "0965": "2925cbf0", + "0966": "2925cbf0", + "0967": "2925cbf0", + "0968": "2925cbf0", + "0969": "2925cbf0", + "0970": "2925cbf0", + "0971": "2925cbf0", + "0972": "2925cbf0", + "0973": "2925cbf0", + "0974": "2925cbf0", + "0975": "2925cbf0", + "0976": "2925cbf0", + "0977": "2925cbf0", + "0978": "2925cbf0", "0979": "b434229f", "0980": "b434229f", "0981": "b434229f", @@ -3266,145 +3266,145 @@ "1024": "b434229f", "1025": "b434229f", "1026": "b434229f", - "1027": "b434229f", - "1028": "b434229f", - "1029": "b434229f", - "1030": "b434229f", - "1031": "b434229f", - "1032": "b434229f", - "1033": "b434229f", - "1034": "b434229f", - "1035": "b434229f", - "1036": "b434229f", - "1037": "b434229f", - "1038": "b434229f", - "1039": "b434229f", - "1040": "b434229f", - "1041": "b434229f", - "1042": "b434229f", - "1043": "b434229f", - "1044": "b434229f", - "1045": "b434229f", - "1046": "b434229f", - "1047": "b434229f", - "1048": "b434229f", - "1049": "b434229f", - "1050": "b434229f", - "1051": "b434229f", - "1052": "b434229f", - "1053": "b434229f", - "1054": "b434229f", - "1055": "b434229f", - "1056": "b434229f", - "1057": "b434229f", - "1058": "b434229f", - "1059": "b434229f", - "1060": "b434229f", - "1061": "b434229f", - "1062": "b434229f", - "1063": "b434229f", - "1064": "b434229f", - "1065": "b434229f", - "1066": "b434229f", - "1067": "b434229f", - "1068": "b434229f", - "1069": "b434229f", - "1070": "b434229f", - "1071": "b434229f", - "1072": "b434229f", - "1073": "b434229f", - "1074": "b434229f", - "1075": "b434229f", - "1076": "b434229f", - "1077": "b434229f", - "1078": "b434229f", - "1079": "b434229f", - "1080": "b434229f", - "1081": "b434229f", - "1082": "b434229f", - "1083": "b434229f", - "1084": "b434229f", - "1085": "b434229f", - "1086": "b434229f", - "1087": "b434229f", - "1088": "b434229f", - "1089": "b434229f", - "1090": "b434229f", - "1091": "b434229f", - "1092": "b434229f", - "1093": "b434229f", - "1094": "b434229f", - "1095": "b434229f", - "1096": "b434229f", - "1097": "b434229f", - "1098": "b434229f", - "1099": "b434229f", - "1100": "b434229f", - "1101": "b434229f", - "1102": "b434229f", - "1103": "b434229f", - "1104": "b434229f", - "1105": "b434229f", - "1106": "b434229f", - "1107": "b434229f", - "1108": "b434229f", - "1109": "b434229f", - "1110": "b434229f", - "1111": "b434229f", - "1112": "b434229f", - "1113": "b434229f", - "1114": "b434229f", - "1115": "b434229f", - "1116": "b434229f", - "1117": "b434229f", - "1118": "b434229f", - "1119": "b434229f", - "1120": "b434229f", - "1121": "b434229f", - "1122": "b434229f", - "1123": "b434229f", - "1124": "b434229f", - "1125": "b434229f", - "1126": "b434229f", - "1127": "b434229f", - "1128": "b434229f", - "1129": "b434229f", - "1130": "b434229f", - "1131": "b434229f", - "1132": "b434229f", - "1133": "b434229f", - "1134": "b434229f", - "1135": "b434229f", - "1136": "b434229f", - "1137": "b434229f", - "1138": "b434229f", - "1139": "b434229f", - "1140": "b434229f", - "1141": "b434229f", - "1142": "b434229f", - "1143": "b434229f", - "1144": "b434229f", - "1145": "b434229f", - "1146": "b434229f", - "1147": "b434229f", - "1148": "b434229f", - "1149": "b434229f", - "1150": "b434229f", - "1151": "b434229f", - "1152": "b434229f", - "1153": "b434229f", - "1154": "b434229f", - "1155": "b434229f", - "1156": "b434229f", - "1157": "b434229f", - "1158": "b434229f", - "1159": "b434229f", - "1160": "b434229f", - "1161": "b434229f", - "1162": "b434229f", - "1163": "b434229f", - "1164": "b434229f", - "1165": "b434229f", + "1027": "2925cbf0", + "1028": "2925cbf0", + "1029": "2925cbf0", + "1030": "2925cbf0", + "1031": "2925cbf0", + "1032": "2925cbf0", + "1033": "2925cbf0", + "1034": "2925cbf0", + "1035": "2925cbf0", + "1036": "2925cbf0", + "1037": "2925cbf0", + "1038": "2925cbf0", + "1039": "2925cbf0", + "1040": "2925cbf0", + "1041": "2925cbf0", + "1042": "2925cbf0", + "1043": "2925cbf0", + "1044": "2925cbf0", + "1045": "2925cbf0", + "1046": "2925cbf0", + "1047": "2925cbf0", + "1048": "2925cbf0", + "1049": "2925cbf0", + "1050": "2925cbf0", + "1051": "2925cbf0", + "1052": "2925cbf0", + "1053": "2925cbf0", + "1054": "2925cbf0", + "1055": "2925cbf0", + "1056": "2925cbf0", + "1057": "2925cbf0", + "1058": "2925cbf0", + "1059": "2925cbf0", + "1060": "2925cbf0", + "1061": "2925cbf0", + "1062": "2925cbf0", + "1063": "2925cbf0", + "1064": "2925cbf0", + "1065": "2925cbf0", + "1066": "2925cbf0", + "1067": "2925cbf0", + "1068": "2925cbf0", + "1069": "2925cbf0", + "1070": "2925cbf0", + "1071": "2925cbf0", + "1072": "2925cbf0", + "1073": "2925cbf0", + "1074": "2925cbf0", + "1075": "2925cbf0", + "1076": "2925cbf0", + "1077": "2925cbf0", + "1078": "2925cbf0", + "1079": "2925cbf0", + "1080": "2925cbf0", + "1081": "2925cbf0", + "1082": "2925cbf0", + "1083": "2925cbf0", + "1084": "2925cbf0", + "1085": "2925cbf0", + "1086": "2925cbf0", + "1087": "2925cbf0", + "1088": "2925cbf0", + "1089": "2925cbf0", + "1090": "2925cbf0", + "1091": "2925cbf0", + "1092": "2925cbf0", + "1093": "2925cbf0", + "1094": "2925cbf0", + "1095": "2925cbf0", + "1096": "2925cbf0", + "1097": "2925cbf0", + "1098": "2925cbf0", + "1099": "2925cbf0", + "1100": "2925cbf0", + "1101": "2925cbf0", + "1102": "2925cbf0", + "1103": "2925cbf0", + "1104": "2925cbf0", + "1105": "2925cbf0", + "1106": "2925cbf0", + "1107": "2925cbf0", + "1108": "2925cbf0", + "1109": "2925cbf0", + "1110": "2925cbf0", + "1111": "2925cbf0", + "1112": "2925cbf0", + "1113": "2925cbf0", + "1114": "2925cbf0", + "1115": "2925cbf0", + "1116": "2925cbf0", + "1117": "2925cbf0", + "1118": "2925cbf0", + "1119": "2925cbf0", + "1120": "2925cbf0", + "1121": "2925cbf0", + "1122": "2925cbf0", + "1123": "2925cbf0", + "1124": "2925cbf0", + "1125": "2925cbf0", + "1126": "2925cbf0", + "1127": "2925cbf0", + "1128": "2925cbf0", + "1129": "2925cbf0", + "1130": "2925cbf0", + "1131": "2925cbf0", + "1132": "2925cbf0", + "1133": "2925cbf0", + "1134": "2925cbf0", + "1135": "2925cbf0", + "1136": "2925cbf0", + "1137": "2925cbf0", + "1138": "2925cbf0", + "1139": "2925cbf0", + "1140": "2925cbf0", + "1141": "2925cbf0", + "1142": "2925cbf0", + "1143": "2925cbf0", + "1144": "2925cbf0", + "1145": "2925cbf0", + "1146": "2925cbf0", + "1147": "2925cbf0", + "1148": "2925cbf0", + "1149": "2925cbf0", + "1150": "2925cbf0", + "1151": "2925cbf0", + "1152": "2925cbf0", + "1153": "2925cbf0", + "1154": "2925cbf0", + "1155": "2925cbf0", + "1156": "2925cbf0", + "1157": "2925cbf0", + "1158": "2925cbf0", + "1159": "2925cbf0", + "1160": "2925cbf0", + "1161": "2925cbf0", + "1162": "2925cbf0", + "1163": "2925cbf0", + "1164": "2925cbf0", + "1165": "2925cbf0", "1166": "48a897dd" }, "gradient_overlay.pag": { @@ -3531,45 +3531,45 @@ }, "guide_hand_drag.pag": { "0000": "48a897dd", - "0001": "b434229f", - "0002": "b434229f", - "0003": "b434229f", - "0004": "b434229f", - "0005": "b434229f", - "0006": "b434229f", - "0007": "b434229f", - "0008": "b434229f", - "0009": "b434229f", - "0010": "b434229f", - "0011": "b434229f", - "0012": "b434229f", - "0013": "b434229f", - "0019": "b434229f", - "0020": "b434229f", - "0021": "b434229f", - "0022": "b434229f", - "0023": "b434229f", - "0024": "b434229f", - "0025": "b434229f", - "0026": "b434229f", - "0027": "b434229f", - "0028": "b434229f", - "0029": "b434229f", - "0030": "b434229f", - "0031": "b434229f", - "0032": "b434229f", - "0033": "b434229f", - "0034": "b434229f", - "0035": "b434229f", - "0036": "b434229f", - "0037": "b434229f", - "0038": "b434229f", - "0039": "b434229f", - "0040": "b434229f", - "0041": "b434229f", - "0042": "b434229f", - "0043": "b434229f", - "0044": "b434229f" + "0001": "2925cbf0", + "0002": "2925cbf0", + "0003": "2925cbf0", + "0004": "2925cbf0", + "0005": "2925cbf0", + "0006": "2925cbf0", + "0007": "2925cbf0", + "0008": "2925cbf0", + "0009": "2925cbf0", + "0010": "2925cbf0", + "0011": "2925cbf0", + "0012": "2925cbf0", + "0013": "2925cbf0", + "0019": "2925cbf0", + "0020": "2925cbf0", + "0021": "2925cbf0", + "0022": "2925cbf0", + "0023": "2925cbf0", + "0024": "2925cbf0", + "0025": "2925cbf0", + "0026": "2925cbf0", + "0027": "2925cbf0", + "0028": "2925cbf0", + "0029": "2925cbf0", + "0030": "2925cbf0", + "0031": "2925cbf0", + "0032": "2925cbf0", + "0033": "2925cbf0", + "0034": "2925cbf0", + "0035": "2925cbf0", + "0036": "2925cbf0", + "0037": "2925cbf0", + "0038": "2925cbf0", + "0039": "2925cbf0", + "0040": "2925cbf0", + "0041": "2925cbf0", + "0042": "2925cbf0", + "0043": "2925cbf0", + "0044": "2925cbf0" }, "hb_lianaishouji.pag": { "0000": "088c7e93", @@ -3954,61 +3954,61 @@ "0053": "b434229f", "0054": "088c7e93", "0055": "b434229f", - "0056": "b434229f", - "0057": "b434229f", - "0058": "b434229f", - "0059": "b434229f", - "0060": "b434229f", - "0061": "b434229f", - "0062": "b434229f", - "0063": "b434229f", - "0064": "b434229f", - "0065": "b434229f", - "0066": "b434229f", - "0067": "b434229f", - "0068": "b434229f", - "0069": "b434229f", - "0070": "b434229f", - "0071": "b434229f", - "0072": "b434229f", - "0073": "b434229f", - "0074": "b434229f", - "0075": "b434229f", - "0076": "b434229f", - "0077": "b434229f", - "0078": "b434229f", - "0079": "b434229f", - "0080": "b434229f", - "0081": "b434229f", - "0082": "b434229f", - "0083": "b434229f", - "0084": "b434229f", - "0085": "b434229f", - "0086": "b434229f", - "0087": "b434229f", - "0088": "b434229f", - "0089": "b434229f", - "0090": "b434229f", - "0091": "b434229f", - "0092": "b434229f", - "0093": "b434229f", - "0094": "b434229f", - "0095": "b434229f", - "0096": "b434229f", - "0097": "b434229f", - "0098": "b434229f", - "0099": "b434229f", - "0100": "b434229f", - "0101": "b434229f", - "0102": "b434229f", - "0103": "b434229f", - "0104": "b434229f", - "0105": "b434229f", - "0106": "b434229f", - "0107": "b434229f", - "0108": "b434229f", - "0109": "b434229f", - "0110": "b434229f", + "0056": "2925cbf0", + "0057": "2925cbf0", + "0058": "2925cbf0", + "0059": "2925cbf0", + "0060": "2925cbf0", + "0061": "2925cbf0", + "0062": "2925cbf0", + "0063": "2925cbf0", + "0064": "2925cbf0", + "0065": "2925cbf0", + "0066": "2925cbf0", + "0067": "2925cbf0", + "0068": "2925cbf0", + "0069": "2925cbf0", + "0070": "2925cbf0", + "0071": "2925cbf0", + "0072": "2925cbf0", + "0073": "2925cbf0", + "0074": "2925cbf0", + "0075": "2925cbf0", + "0076": "2925cbf0", + "0077": "2925cbf0", + "0078": "2925cbf0", + "0079": "2925cbf0", + "0080": "2925cbf0", + "0081": "2925cbf0", + "0082": "2925cbf0", + "0083": "2925cbf0", + "0084": "2925cbf0", + "0085": "2925cbf0", + "0086": "2925cbf0", + "0087": "2925cbf0", + "0088": "2925cbf0", + "0089": "2925cbf0", + "0090": "2925cbf0", + "0091": "2925cbf0", + "0092": "2925cbf0", + "0093": "2925cbf0", + "0094": "2925cbf0", + "0095": "2925cbf0", + "0096": "2925cbf0", + "0097": "2925cbf0", + "0098": "2925cbf0", + "0099": "2925cbf0", + "0100": "2925cbf0", + "0101": "2925cbf0", + "0102": "2925cbf0", + "0103": "2925cbf0", + "0104": "2925cbf0", + "0105": "2925cbf0", + "0106": "2925cbf0", + "0107": "2925cbf0", + "0108": "2925cbf0", + "0109": "2925cbf0", + "0110": "2925cbf0", "0111": "b434229f", "0112": "088c7e93", "0113": "088c7e93", @@ -4083,71 +4083,71 @@ "0182": "088c7e93", "0183": "088c7e93", "0184": "088c7e93", - "0185": "b434229f", - "0186": "b434229f", - "0187": "b434229f", - "0188": "b434229f", - "0189": "b434229f", - "0190": "b434229f", - "0191": "b434229f", - "0192": "b434229f", - "0193": "b434229f", - "0194": "b434229f", - "0195": "b434229f", - "0196": "b434229f", - "0197": "b434229f", - "0198": "b434229f", - "0199": "b434229f", - "0200": "b434229f", - "0201": "b434229f", - "0202": "b434229f", - "0203": "b434229f", - "0204": "b434229f", - "0205": "b434229f", - "0206": "b434229f", - "0207": "b434229f", - "0208": "b434229f", - "0209": "b434229f", - "0210": "b434229f", - "0211": "b434229f", - "0212": "b434229f", - "0213": "b434229f", - "0214": "b434229f", - "0215": "b434229f", - "0216": "b434229f", - "0217": "b434229f", - "0218": "b434229f", - "0219": "b434229f", - "0220": "b434229f", - "0221": "b434229f", - "0222": "b434229f", - "0223": "b434229f", - "0224": "b434229f", - "0225": "b434229f", - "0226": "b434229f", - "0227": "b434229f", - "0228": "b434229f", - "0229": "b434229f", - "0230": "b434229f", - "0231": "b434229f", - "0232": "b434229f", - "0233": "b434229f", - "0234": "b434229f", - "0235": "b434229f", - "0236": "b434229f", - "0237": "b434229f", - "0238": "b434229f", - "0239": "b434229f", - "0240": "b434229f", - "0241": "b434229f", - "0242": "b434229f", - "0243": "b434229f", - "0244": "b434229f", - "0245": "b434229f", - "0246": "b434229f", - "0247": "b434229f", - "0248": "b434229f", - "0249": "b434229f", + "0185": "2925cbf0", + "0186": "2925cbf0", + "0187": "2925cbf0", + "0188": "2925cbf0", + "0189": "2925cbf0", + "0190": "2925cbf0", + "0191": "2925cbf0", + "0192": "2925cbf0", + "0193": "2925cbf0", + "0194": "2925cbf0", + "0195": "2925cbf0", + "0196": "2925cbf0", + "0197": "2925cbf0", + "0198": "2925cbf0", + "0199": "2925cbf0", + "0200": "2925cbf0", + "0201": "2925cbf0", + "0202": "2925cbf0", + "0203": "2925cbf0", + "0204": "2925cbf0", + "0205": "2925cbf0", + "0206": "2925cbf0", + "0207": "2925cbf0", + "0208": "2925cbf0", + "0209": "2925cbf0", + "0210": "2925cbf0", + "0211": "2925cbf0", + "0212": "2925cbf0", + "0213": "2925cbf0", + "0214": "2925cbf0", + "0215": "2925cbf0", + "0216": "2925cbf0", + "0217": "2925cbf0", + "0218": "2925cbf0", + "0219": "2925cbf0", + "0220": "2925cbf0", + "0221": "2925cbf0", + "0222": "2925cbf0", + "0223": "2925cbf0", + "0224": "2925cbf0", + "0225": "2925cbf0", + "0226": "2925cbf0", + "0227": "2925cbf0", + "0228": "2925cbf0", + "0229": "2925cbf0", + "0230": "2925cbf0", + "0231": "2925cbf0", + "0232": "2925cbf0", + "0233": "2925cbf0", + "0234": "2925cbf0", + "0235": "2925cbf0", + "0236": "2925cbf0", + "0237": "2925cbf0", + "0238": "2925cbf0", + "0239": "2925cbf0", + "0240": "2925cbf0", + "0241": "2925cbf0", + "0242": "2925cbf0", + "0243": "2925cbf0", + "0244": "2925cbf0", + "0245": "2925cbf0", + "0246": "2925cbf0", + "0247": "2925cbf0", + "0248": "2925cbf0", + "0249": "2925cbf0", "0250": "4b7f3114", "0251": "088c7e93", "0252": "088c7e93", @@ -4857,7 +4857,7 @@ "0008": "b434229f", "0009": "b434229f", "0010": "b434229f", - "0011": "b434229f", + "0011": "2925cbf0", "0012": "b434229f", "0013": "5ad579ad", "0014": "b434229f", @@ -5263,30 +5263,30 @@ "0059": "0e678d2f" }, "video_composition_filter.pag": { - "0000": "4b7f3114", - "0001": "4b7f3114", - "0002": "4b7f3114", - "0003": "4b7f3114", - "0004": "4b7f3114", - "0005": "4b7f3114", - "0006": "4b7f3114", - "0007": "4b7f3114", - "0008": "4b7f3114", - "0009": "4b7f3114", - "0010": "4b7f3114", - "0011": "4b7f3114", - "0012": "4b7f3114", - "0013": "4b7f3114", - "0014": "4b7f3114", - "0015": "4b7f3114", - "0016": "4b7f3114", - "0017": "4b7f3114", - "0018": "4b7f3114", - "0019": "4b7f3114", - "0020": "4b7f3114", - "0021": "4b7f3114", - "0022": "4b7f3114", - "0023": "4b7f3114" + "0000": "2925cbf0", + "0001": "2925cbf0", + "0002": "2925cbf0", + "0003": "2925cbf0", + "0004": "2925cbf0", + "0005": "2925cbf0", + "0006": "2925cbf0", + "0007": "2925cbf0", + "0008": "2925cbf0", + "0009": "2925cbf0", + "0010": "2925cbf0", + "0011": "2925cbf0", + "0012": "2925cbf0", + "0013": "2925cbf0", + "0014": "2925cbf0", + "0015": "2925cbf0", + "0016": "2925cbf0", + "0017": "2925cbf0", + "0018": "2925cbf0", + "0019": "2925cbf0", + "0020": "2925cbf0", + "0021": "2925cbf0", + "0022": "2925cbf0", + "0023": "2925cbf0" }, "vt_chaokulama.pag": { "0000": "088c7e93", @@ -5458,58 +5458,58 @@ "0185": "088c7e93", "0186": "088c7e93", "0187": "088c7e93", - "0188": "088c7e93", - "0189": "088c7e93", - "0190": "088c7e93", - "0191": "088c7e93", - "0192": "088c7e93", - "0193": "088c7e93", - "0194": "088c7e93", - "0195": "088c7e93", - "0196": "088c7e93", - "0197": "088c7e93", - "0198": "088c7e93", - "0199": "088c7e93", - "0200": "4b7f3114", - "0201": "4b7f3114", - "0202": "4b7f3114", - "0203": "4b7f3114", - "0204": "088c7e93", - "0205": "4b7f3114", - "0206": "4b7f3114", - "0207": "4b7f3114", - "0208": "4b7f3114", - "0209": "4b7f3114", - "0210": "4b7f3114", - "0211": "4b7f3114", - "0212": "4b7f3114", - "0213": "4b7f3114", - "0214": "4b7f3114", - "0215": "4b7f3114", - "0216": "4b7f3114", - "0217": "4b7f3114", - "0218": "4b7f3114", - "0219": "4b7f3114", - "0220": "4b7f3114", - "0221": "4b7f3114", - "0222": "4b7f3114", - "0223": "4b7f3114", - "0224": "4b7f3114", - "0225": "4b7f3114", - "0233": "4b7f3114", - "0236": "4b7f3114", - "0237": "088c7e93", - "0238": "088c7e93", - "0239": "088c7e93", - "0240": "088c7e93", - "0241": "088c7e93", - "0242": "2b9d541c", - "0243": "088c7e93", - "0244": "088c7e93", - "0245": "2b9d541c", - "0246": "2b9d541c", - "0247": "2b9d541c", - "0248": "088c7e93", + "0188": "c4014ba2", + "0189": "c4014ba2", + "0190": "c4014ba2", + "0191": "c4014ba2", + "0192": "c4014ba2", + "0193": "c4014ba2", + "0194": "c4014ba2", + "0195": "c4014ba2", + "0196": "c4014ba2", + "0197": "c4014ba2", + "0198": "c4014ba2", + "0199": "c4014ba2", + "0200": "52a195f3", + "0201": "52a195f3", + "0202": "52a195f3", + "0203": "52a195f3", + "0204": "52a195f3", + "0205": "52a195f3", + "0206": "52a195f3", + "0207": "52a195f3", + "0208": "52a195f3", + "0209": "52a195f3", + "0210": "52a195f3", + "0211": "52a195f3", + "0212": "52a195f3", + "0213": "52a195f3", + "0214": "52a195f3", + "0215": "52a195f3", + "0216": "52a195f3", + "0217": "52a195f3", + "0218": "52a195f3", + "0219": "52a195f3", + "0220": "52a195f3", + "0221": "52a195f3", + "0222": "52a195f3", + "0223": "52a195f3", + "0224": "52a195f3", + "0225": "52a195f3", + "0233": "52a195f3", + "0236": "52a195f3", + "0237": "c4014ba2", + "0238": "c4014ba2", + "0239": "c4014ba2", + "0240": "c4014ba2", + "0241": "c4014ba2", + "0242": "c4014ba2", + "0243": "c4014ba2", + "0244": "c4014ba2", + "0245": "c4014ba2", + "0246": "c4014ba2", + "0247": "c4014ba2", + "0248": "c4014ba2", "0249": "088c7e93", "0250": "088c7e93", "0251": "088c7e93", @@ -6503,85 +6503,85 @@ "0557": "bd2ee44f", "0558": "bd2ee44f", "0559": "bd2ee44f", - "0560": "088c7e93", - "0561": "088c7e93", - "0562": "088c7e93", - "0563": "2b9d541c", - "0564": "088c7e93", - "0565": "24feb8aa", - "0566": "088c7e93", - "0567": "088c7e93", - "0568": "2b9d541c", - "0569": "088c7e93", - "0570": "088c7e93", - "0571": "2b9d541c", - "0572": "088c7e93", - "0573": "088c7e93", - "0574": "088c7e93", - "0575": "088c7e93", - "0576": "2b9d541c", - "0577": "2b9d541c", - "0578": "088c7e93", - "0579": "088c7e93", - "0580": "4b7f3114", - "0581": "4b7f3114", - "0582": "4b7f3114", - "0583": "4b7f3114", - "0584": "4b7f3114", - "0585": "4b7f3114", - "0586": "4b7f3114", - "0587": "4b7f3114", - "0588": "4b7f3114", - "0589": "4b7f3114", - "0590": "4b7f3114", - "0591": "4b7f3114", - "0592": "4b7f3114", - "0593": "4b7f3114", - "0594": "4b7f3114", - "0595": "4b7f3114", - "0596": "4b7f3114", - "0597": "4b7f3114", - "0598": "4b7f3114", - "0599": "4b7f3114", - "0600": "4b7f3114", - "0601": "4b7f3114", - "0602": "4b7f3114", - "0603": "4b7f3114", - "0604": "4b7f3114", - "0605": "4b7f3114", - "0606": "4b7f3114", - "0607": "4b7f3114", - "0608": "4b7f3114", - "0609": "4b7f3114", - "0610": "4b7f3114", - "0611": "4b7f3114", - "0612": "4b7f3114", - "0613": "4b7f3114", - "0614": "4b7f3114", - "0615": "4b7f3114", - "0616": "4b7f3114", - "0617": "4b7f3114", - "0618": "4b7f3114", - "0619": "4b7f3114", - "0620": "4b7f3114", - "0621": "4b7f3114", - "0622": "4b7f3114", - "0623": "4b7f3114", - "0624": "4b7f3114", - "0625": "4b7f3114", - "0626": "4b7f3114", - "0627": "4b7f3114", - "0628": "4b7f3114", - "0629": "4b7f3114", - "0630": "4b7f3114", - "0631": "4b7f3114", - "0632": "4b7f3114", - "0633": "4b7f3114", - "0634": "4b7f3114", - "0635": "4b7f3114", - "0636": "4b7f3114", - "0637": "4b7f3114", - "0638": "4b7f3114", + "0560": "52a195f3", + "0561": "52a195f3", + "0562": "52a195f3", + "0563": "52a195f3", + "0564": "52a195f3", + "0565": "52a195f3", + "0566": "52a195f3", + "0567": "52a195f3", + "0568": "52a195f3", + "0569": "52a195f3", + "0570": "52a195f3", + "0571": "52a195f3", + "0572": "52a195f3", + "0573": "52a195f3", + "0574": "52a195f3", + "0575": "52a195f3", + "0576": "52a195f3", + "0577": "52a195f3", + "0578": "52a195f3", + "0579": "52a195f3", + "0580": "52a195f3", + "0581": "52a195f3", + "0582": "52a195f3", + "0583": "52a195f3", + "0584": "52a195f3", + "0585": "52a195f3", + "0586": "52a195f3", + "0587": "52a195f3", + "0588": "52a195f3", + "0589": "52a195f3", + "0590": "52a195f3", + "0591": "52a195f3", + "0592": "52a195f3", + "0593": "52a195f3", + "0594": "52a195f3", + "0595": "52a195f3", + "0596": "52a195f3", + "0597": "52a195f3", + "0598": "52a195f3", + "0599": "52a195f3", + "0600": "52a195f3", + "0601": "52a195f3", + "0602": "52a195f3", + "0603": "52a195f3", + "0604": "52a195f3", + "0605": "52a195f3", + "0606": "52a195f3", + "0607": "52a195f3", + "0608": "52a195f3", + "0609": "52a195f3", + "0610": "52a195f3", + "0611": "52a195f3", + "0612": "52a195f3", + "0613": "52a195f3", + "0614": "52a195f3", + "0615": "52a195f3", + "0616": "52a195f3", + "0617": "52a195f3", + "0618": "52a195f3", + "0619": "52a195f3", + "0620": "52a195f3", + "0621": "52a195f3", + "0622": "52a195f3", + "0623": "52a195f3", + "0624": "52a195f3", + "0625": "52a195f3", + "0626": "52a195f3", + "0627": "52a195f3", + "0628": "52a195f3", + "0629": "52a195f3", + "0630": "52a195f3", + "0631": "52a195f3", + "0632": "52a195f3", + "0633": "52a195f3", + "0634": "52a195f3", + "0635": "52a195f3", + "0636": "52a195f3", + "0637": "52a195f3", + "0638": "52a195f3", "0639": "088c7e93", "0640": "088c7e93", "0641": "088c7e93", @@ -8309,7 +8309,7 @@ "RectToPath": "30dab356", "RoundRectToPath": "b434229f", "SetStartTime": "e9d152c6", - "ShapeType": "b434229f" + "ShapeType": "2925cbf0" }, "PAGFileTimeStretchTest": { "Repeat_1": "6a420423", @@ -8323,11 +8323,11 @@ "Bulge": "48a897dd", "CornerPin": "24feb8aa", "CornerPinScale": "24feb8aa", - "DefaultFeatherMask": "4b7f3114", + "DefaultFeatherMask": "2925cbf0", "DisplacementMap": "5a7c08b9", "DisplacementMap_Scale": "088c7e93", - "DropShadow": "4b7f3114", - "FeatherMask": "b434229f", + "DropShadow": "52a195f3", + "FeatherMask": "2925cbf0", "GaussBlur_FastBlur": "24feb8aa", "GaussBlur_FastBlur_NoRepeat": "4b7f3114", "GaussBlur_Static": "5eacc039", @@ -8337,16 +8337,16 @@ "GradientOverlayFilter_Star": "b434229f", "HueSaturation": "4429f09f", "LevelsIndividualFilter": "bd2ee44f", - "LogoMipmap": "b434229f", + "LogoMipmap": "2925cbf0", "Mosaic": "48a897dd", "MotionBlur_200000": "28826fb2", "MotionBlur_600000": "c75e4d74", "MotionTile": "6a420423", - "MultiFilter_CornerPin_Bulge": "24feb8aa", + "MultiFilter_CornerPin_Bulge": "7619ec91", "MultiFilter_Motiontile_Blur": "24feb8aa", - "OuterGlow": "4b7f3114", + "OuterGlow": "52a195f3", "RadialBlur": "6a420423", - "Stroke": "7f7435d6f" + "Stroke": "52a195f3" }, "PAGFontTest": { "0000": "3bd38676", @@ -8444,11 +8444,11 @@ "PAGSurfaceTest": { "BottomLeftScissor": "b434229f", "FromTexture": "6a420423", - "Mask": "b434229f" + "Mask": "2925cbf0" }, "PAGTextLayerTest": { - "Emoji": "4b0f60e7", - "NormalEmoji": "b434229f", + "Emoji": "52a195f3", + "NormalEmoji": "2925cbf0", "PositionAnimator": "b434229f", "RangeSelectorTriangleHighLow": "5c3b8bc5", "SmallFontSizeScale": "5ad579ad", @@ -8463,7 +8463,7 @@ "TextPathForceAlignment2": "7f7435d6f", "TextPathNotPerpendicular": "7f7435d6f", "TextPathReversed": "30dab356", - "TextReplacement": "b434229f", + "TextReplacement": "2925cbf0", "fillColor": "3bd38676", "strokeColor": "3bd38676", "textAnimatorMode": "b434229f",