1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2019 Google Inc. 3cb93a386Sopenharmony_ci * 4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci * found in the LICENSE file. 6cb93a386Sopenharmony_ci */ 7cb93a386Sopenharmony_ci 8cb93a386Sopenharmony_ci#include "modules/skottie/src/Composition.h" 9cb93a386Sopenharmony_ci 10cb93a386Sopenharmony_ci#include "include/core/SkCanvas.h" 11cb93a386Sopenharmony_ci#include "include/private/SkTPin.h" 12cb93a386Sopenharmony_ci#include "modules/skottie/src/Camera.h" 13cb93a386Sopenharmony_ci#include "modules/skottie/src/SkottieJson.h" 14cb93a386Sopenharmony_ci#include "modules/skottie/src/SkottiePriv.h" 15cb93a386Sopenharmony_ci#include "modules/sksg/include/SkSGGroup.h" 16cb93a386Sopenharmony_ci 17cb93a386Sopenharmony_ci#include <algorithm> 18cb93a386Sopenharmony_ci 19cb93a386Sopenharmony_cinamespace skottie { 20cb93a386Sopenharmony_cinamespace internal { 21cb93a386Sopenharmony_ci 22cb93a386Sopenharmony_ciAnimationBuilder::ScopedAssetRef::ScopedAssetRef(const AnimationBuilder* abuilder, 23cb93a386Sopenharmony_ci const skjson::ObjectValue& jlayer) { 24cb93a386Sopenharmony_ci const auto refId = ParseDefault<SkString>(jlayer["refId"], SkString()); 25cb93a386Sopenharmony_ci if (refId.isEmpty()) { 26cb93a386Sopenharmony_ci abuilder->log(Logger::Level::kError, nullptr, "Layer missing refId."); 27cb93a386Sopenharmony_ci return; 28cb93a386Sopenharmony_ci } 29cb93a386Sopenharmony_ci 30cb93a386Sopenharmony_ci const auto* asset_info = abuilder->fAssets.find(refId); 31cb93a386Sopenharmony_ci if (!asset_info) { 32cb93a386Sopenharmony_ci abuilder->log(Logger::Level::kError, nullptr, "Asset not found: '%s'.", refId.c_str()); 33cb93a386Sopenharmony_ci return; 34cb93a386Sopenharmony_ci } 35cb93a386Sopenharmony_ci 36cb93a386Sopenharmony_ci if (asset_info->fIsAttaching) { 37cb93a386Sopenharmony_ci abuilder->log(Logger::Level::kError, nullptr, 38cb93a386Sopenharmony_ci "Asset cycle detected for: '%s'", refId.c_str()); 39cb93a386Sopenharmony_ci return; 40cb93a386Sopenharmony_ci } 41cb93a386Sopenharmony_ci 42cb93a386Sopenharmony_ci asset_info->fIsAttaching = true; 43cb93a386Sopenharmony_ci 44cb93a386Sopenharmony_ci fInfo = asset_info; 45cb93a386Sopenharmony_ci} 46cb93a386Sopenharmony_ci 47cb93a386Sopenharmony_ciCompositionBuilder::CompositionBuilder(const AnimationBuilder& abuilder, 48cb93a386Sopenharmony_ci const SkSize& size, 49cb93a386Sopenharmony_ci const skjson::ObjectValue& jcomp) 50cb93a386Sopenharmony_ci : fSize(size) { 51cb93a386Sopenharmony_ci 52cb93a386Sopenharmony_ci // Optional motion blur params. 53cb93a386Sopenharmony_ci if (const skjson::ObjectValue* jmb = jcomp["mb"]) { 54cb93a386Sopenharmony_ci static constexpr size_t kMaxSamplesPerFrame = 64; 55cb93a386Sopenharmony_ci fMotionBlurSamples = std::min(ParseDefault<size_t>((*jmb)["spf"], 1ul), 56cb93a386Sopenharmony_ci kMaxSamplesPerFrame); 57cb93a386Sopenharmony_ci fMotionBlurAngle = SkTPin(ParseDefault((*jmb)["sa"], 0.0f), 0.0f, 720.0f); 58cb93a386Sopenharmony_ci fMotionBlurPhase = SkTPin(ParseDefault((*jmb)["sp"], 0.0f), -360.0f, 360.0f); 59cb93a386Sopenharmony_ci } 60cb93a386Sopenharmony_ci 61cb93a386Sopenharmony_ci int camera_builder_index = -1; 62cb93a386Sopenharmony_ci 63cb93a386Sopenharmony_ci // Prepare layer builders. 64cb93a386Sopenharmony_ci if (const skjson::ArrayValue* jlayers = jcomp["layers"]) { 65cb93a386Sopenharmony_ci fLayerBuilders.reserve(SkToInt(jlayers->size())); 66cb93a386Sopenharmony_ci for (const skjson::ObjectValue* jlayer : *jlayers) { 67cb93a386Sopenharmony_ci if (!jlayer) continue; 68cb93a386Sopenharmony_ci 69cb93a386Sopenharmony_ci const auto lbuilder_index = fLayerBuilders.size(); 70cb93a386Sopenharmony_ci fLayerBuilders.emplace_back(*jlayer, fSize); 71cb93a386Sopenharmony_ci const auto& lbuilder = fLayerBuilders.back(); 72cb93a386Sopenharmony_ci 73cb93a386Sopenharmony_ci fLayerIndexMap.set(lbuilder.index(), lbuilder_index); 74cb93a386Sopenharmony_ci 75cb93a386Sopenharmony_ci // Keep track of the camera builder. 76cb93a386Sopenharmony_ci if (lbuilder.isCamera()) { 77cb93a386Sopenharmony_ci // We only support one (first) camera for now. 78cb93a386Sopenharmony_ci if (camera_builder_index < 0) { 79cb93a386Sopenharmony_ci camera_builder_index = SkToInt(lbuilder_index); 80cb93a386Sopenharmony_ci } else { 81cb93a386Sopenharmony_ci abuilder.log(Logger::Level::kWarning, jlayer, 82cb93a386Sopenharmony_ci "Ignoring duplicate camera layer."); 83cb93a386Sopenharmony_ci } 84cb93a386Sopenharmony_ci } 85cb93a386Sopenharmony_ci } 86cb93a386Sopenharmony_ci } 87cb93a386Sopenharmony_ci 88cb93a386Sopenharmony_ci // Attach a camera transform upfront, if needed (required to build 89cb93a386Sopenharmony_ci // all other 3D transform chains). 90cb93a386Sopenharmony_ci if (camera_builder_index >= 0) { 91cb93a386Sopenharmony_ci // Explicit camera. 92cb93a386Sopenharmony_ci fCameraTransform = fLayerBuilders[camera_builder_index].buildTransform(abuilder, this); 93cb93a386Sopenharmony_ci } else if (ParseDefault<int>(jcomp["ddd"], 0)) { 94cb93a386Sopenharmony_ci // Default/implicit camera when 3D layers are present. 95cb93a386Sopenharmony_ci fCameraTransform = CameraAdaper::DefaultCameraTransform(fSize); 96cb93a386Sopenharmony_ci } 97cb93a386Sopenharmony_ci} 98cb93a386Sopenharmony_ci 99cb93a386Sopenharmony_ciCompositionBuilder::~CompositionBuilder() = default; 100cb93a386Sopenharmony_ci 101cb93a386Sopenharmony_ciLayerBuilder* CompositionBuilder::layerBuilder(int layer_index) { 102cb93a386Sopenharmony_ci if (layer_index < 0) { 103cb93a386Sopenharmony_ci return nullptr; 104cb93a386Sopenharmony_ci } 105cb93a386Sopenharmony_ci 106cb93a386Sopenharmony_ci if (const auto* idx = fLayerIndexMap.find(layer_index)) { 107cb93a386Sopenharmony_ci return &fLayerBuilders[SkToInt(*idx)]; 108cb93a386Sopenharmony_ci } 109cb93a386Sopenharmony_ci 110cb93a386Sopenharmony_ci return nullptr; 111cb93a386Sopenharmony_ci} 112cb93a386Sopenharmony_ci 113cb93a386Sopenharmony_cisk_sp<sksg::RenderNode> CompositionBuilder::build(const AnimationBuilder& abuilder) { 114cb93a386Sopenharmony_ci // First pass - transitively attach layer transform chains. 115cb93a386Sopenharmony_ci for (auto& lbuilder : fLayerBuilders) { 116cb93a386Sopenharmony_ci lbuilder.buildTransform(abuilder, this); 117cb93a386Sopenharmony_ci } 118cb93a386Sopenharmony_ci 119cb93a386Sopenharmony_ci // Second pass - attach actual layer contents and finalize the layer render tree. 120cb93a386Sopenharmony_ci std::vector<sk_sp<sksg::RenderNode>> layers; 121cb93a386Sopenharmony_ci layers.reserve(fLayerBuilders.size()); 122cb93a386Sopenharmony_ci 123cb93a386Sopenharmony_ci LayerBuilder* prev_layer = nullptr; 124cb93a386Sopenharmony_ci for (auto& lbuilder : fLayerBuilders) { 125cb93a386Sopenharmony_ci if (auto layer = lbuilder.buildRenderTree(abuilder, this, prev_layer)) { 126cb93a386Sopenharmony_ci layers.push_back(std::move(layer)); 127cb93a386Sopenharmony_ci } 128cb93a386Sopenharmony_ci prev_layer = &lbuilder; 129cb93a386Sopenharmony_ci } 130cb93a386Sopenharmony_ci 131cb93a386Sopenharmony_ci if (layers.empty()) { 132cb93a386Sopenharmony_ci return nullptr; 133cb93a386Sopenharmony_ci } 134cb93a386Sopenharmony_ci 135cb93a386Sopenharmony_ci if (layers.size() == 1) { 136cb93a386Sopenharmony_ci return std::move(layers[0]); 137cb93a386Sopenharmony_ci } 138cb93a386Sopenharmony_ci 139cb93a386Sopenharmony_ci // Layers are painted in bottom->top order. 140cb93a386Sopenharmony_ci std::reverse(layers.begin(), layers.end()); 141cb93a386Sopenharmony_ci layers.shrink_to_fit(); 142cb93a386Sopenharmony_ci 143cb93a386Sopenharmony_ci return sksg::Group::Make(std::move(layers)); 144cb93a386Sopenharmony_ci} 145cb93a386Sopenharmony_ci 146cb93a386Sopenharmony_ci} // namespace internal 147cb93a386Sopenharmony_ci} // namespace skottie 148