1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2020 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/Camera.h" 9cb93a386Sopenharmony_ci 10cb93a386Sopenharmony_ci#include "modules/skottie/src/SkottieJson.h" 11cb93a386Sopenharmony_ci#include "modules/skottie/src/SkottiePriv.h" 12cb93a386Sopenharmony_ci#include "modules/sksg/include/SkSGTransform.h" 13cb93a386Sopenharmony_ci 14cb93a386Sopenharmony_cinamespace skottie { 15cb93a386Sopenharmony_cinamespace internal { 16cb93a386Sopenharmony_ci 17cb93a386Sopenharmony_cinamespace { 18cb93a386Sopenharmony_ci 19cb93a386Sopenharmony_ciSkM44 ComputeCameraMatrix(const SkV3& position, 20cb93a386Sopenharmony_ci const SkV3& poi, 21cb93a386Sopenharmony_ci const SkV3& rotation, 22cb93a386Sopenharmony_ci const SkSize& viewport_size, 23cb93a386Sopenharmony_ci float zoom) { 24cb93a386Sopenharmony_ci 25cb93a386Sopenharmony_ci // Initial camera vector. 26cb93a386Sopenharmony_ci const auto cam_t = SkM44::Rotate({0, 0, 1}, SkDegreesToRadians(-rotation.z)) 27cb93a386Sopenharmony_ci * SkM44::Rotate({0, 1, 0}, SkDegreesToRadians( rotation.y)) 28cb93a386Sopenharmony_ci * SkM44::Rotate({1, 0, 0}, SkDegreesToRadians( rotation.x)) 29cb93a386Sopenharmony_ci * SkM44::LookAt({ position.x, position.y, -position.z }, 30cb93a386Sopenharmony_ci { poi.x, poi.y, poi.z }, 31cb93a386Sopenharmony_ci { 0, 1, 0 }) 32cb93a386Sopenharmony_ci * SkM44::Scale(1, 1, -1); 33cb93a386Sopenharmony_ci 34cb93a386Sopenharmony_ci // View parameters: 35cb93a386Sopenharmony_ci // 36cb93a386Sopenharmony_ci // * size -> composition size (TODO: AE seems to base it on width only?) 37cb93a386Sopenharmony_ci // * distance -> "zoom" camera attribute 38cb93a386Sopenharmony_ci // 39cb93a386Sopenharmony_ci const auto view_size = std::max(viewport_size.width(), viewport_size.height()), 40cb93a386Sopenharmony_ci view_distance = zoom, 41cb93a386Sopenharmony_ci view_angle = std::atan(sk_ieee_float_divide(view_size * 0.5f, view_distance)); 42cb93a386Sopenharmony_ci 43cb93a386Sopenharmony_ci const auto persp_t = SkM44::Scale(view_size * 0.5f, view_size * 0.5f, 1) 44cb93a386Sopenharmony_ci * SkM44::Perspective(0, view_distance, 2 * view_angle); 45cb93a386Sopenharmony_ci 46cb93a386Sopenharmony_ci return SkM44::Translate(viewport_size.width() * 0.5f, 47cb93a386Sopenharmony_ci viewport_size.height() * 0.5f, 48cb93a386Sopenharmony_ci 0) 49cb93a386Sopenharmony_ci * persp_t * cam_t; 50cb93a386Sopenharmony_ci} 51cb93a386Sopenharmony_ci 52cb93a386Sopenharmony_ci} // namespace 53cb93a386Sopenharmony_ci 54cb93a386Sopenharmony_ciCameraAdaper::CameraAdaper(const skjson::ObjectValue& jlayer, 55cb93a386Sopenharmony_ci const skjson::ObjectValue& jtransform, 56cb93a386Sopenharmony_ci const AnimationBuilder& abuilder, 57cb93a386Sopenharmony_ci const SkSize& viewport_size) 58cb93a386Sopenharmony_ci : INHERITED(jtransform, abuilder) 59cb93a386Sopenharmony_ci , fViewportSize(viewport_size) 60cb93a386Sopenharmony_ci // The presence of an anchor point property ('a') differentiates 61cb93a386Sopenharmony_ci // one-node vs. two-node cameras. 62cb93a386Sopenharmony_ci , fType(jtransform["a"].is<skjson::NullValue>() ? CameraType::kOneNode 63cb93a386Sopenharmony_ci : CameraType::kTwoNode) { 64cb93a386Sopenharmony_ci // 'pe' (perspective?) corresponds to AE's "zoom" camera property. 65cb93a386Sopenharmony_ci this->bind(abuilder, jlayer["pe"], fZoom); 66cb93a386Sopenharmony_ci} 67cb93a386Sopenharmony_ci 68cb93a386Sopenharmony_ciCameraAdaper::~CameraAdaper() = default; 69cb93a386Sopenharmony_ci 70cb93a386Sopenharmony_ciSkM44 CameraAdaper::totalMatrix() const { 71cb93a386Sopenharmony_ci // Camera parameters: 72cb93a386Sopenharmony_ci // 73cb93a386Sopenharmony_ci // * location -> position attribute 74cb93a386Sopenharmony_ci // * point of interest -> anchor point attribute (two-node camera only) 75cb93a386Sopenharmony_ci // * orientation -> rotation attribute 76cb93a386Sopenharmony_ci // 77cb93a386Sopenharmony_ci const auto position = this->position(); 78cb93a386Sopenharmony_ci 79cb93a386Sopenharmony_ci return ComputeCameraMatrix(position, 80cb93a386Sopenharmony_ci this->poi(position), 81cb93a386Sopenharmony_ci this->rotation(), 82cb93a386Sopenharmony_ci fViewportSize, 83cb93a386Sopenharmony_ci fZoom); 84cb93a386Sopenharmony_ci} 85cb93a386Sopenharmony_ci 86cb93a386Sopenharmony_ciSkV3 CameraAdaper::poi(const SkV3& pos) const { 87cb93a386Sopenharmony_ci // AE supports two camera types: 88cb93a386Sopenharmony_ci // 89cb93a386Sopenharmony_ci // - one-node camera: does not auto-orient, and starts off perpendicular 90cb93a386Sopenharmony_ci // to the z = 0 plane, facing "forward" (decreasing z). 91cb93a386Sopenharmony_ci // 92cb93a386Sopenharmony_ci // - two-node camera: has a point of interest (encoded as the anchor point), 93cb93a386Sopenharmony_ci // and auto-orients to point in its direction. 94cb93a386Sopenharmony_ci 95cb93a386Sopenharmony_ci if (fType == CameraType::kOneNode) { 96cb93a386Sopenharmony_ci return { pos.x, pos.y, -pos.z - 1}; 97cb93a386Sopenharmony_ci } 98cb93a386Sopenharmony_ci 99cb93a386Sopenharmony_ci const auto ap = this->anchor_point(); 100cb93a386Sopenharmony_ci 101cb93a386Sopenharmony_ci return { ap.x, ap.y, -ap.z }; 102cb93a386Sopenharmony_ci} 103cb93a386Sopenharmony_ci 104cb93a386Sopenharmony_cisk_sp<sksg::Transform> CameraAdaper::DefaultCameraTransform(const SkSize& viewport_size) { 105cb93a386Sopenharmony_ci const auto center = SkVector::Make(viewport_size.width() * 0.5f, 106cb93a386Sopenharmony_ci viewport_size.height() * 0.5f); 107cb93a386Sopenharmony_ci 108cb93a386Sopenharmony_ci static constexpr float kDefaultAEZoom = 879.13f; 109cb93a386Sopenharmony_ci 110cb93a386Sopenharmony_ci const SkV3 pos = { center.fX, center.fY, -kDefaultAEZoom }, 111cb93a386Sopenharmony_ci poi = { pos.x, pos.y, -pos.z - 1 }, 112cb93a386Sopenharmony_ci rot = { 0, 0, 0 }; 113cb93a386Sopenharmony_ci 114cb93a386Sopenharmony_ci return sksg::Matrix<SkM44>::Make( 115cb93a386Sopenharmony_ci ComputeCameraMatrix(pos, poi, rot, viewport_size, kDefaultAEZoom)); 116cb93a386Sopenharmony_ci} 117cb93a386Sopenharmony_ci 118cb93a386Sopenharmony_cisk_sp<sksg::Transform> AnimationBuilder::attachCamera(const skjson::ObjectValue& jlayer, 119cb93a386Sopenharmony_ci const skjson::ObjectValue& jtransform, 120cb93a386Sopenharmony_ci sk_sp<sksg::Transform> parent, 121cb93a386Sopenharmony_ci const SkSize& viewport_size) const { 122cb93a386Sopenharmony_ci auto adapter = sk_make_sp<CameraAdaper>(jlayer, jtransform, *this, viewport_size); 123cb93a386Sopenharmony_ci 124cb93a386Sopenharmony_ci if (adapter->isStatic()) { 125cb93a386Sopenharmony_ci adapter->seek(0); 126cb93a386Sopenharmony_ci } else { 127cb93a386Sopenharmony_ci fCurrentAnimatorScope->push_back(adapter); 128cb93a386Sopenharmony_ci } 129cb93a386Sopenharmony_ci 130cb93a386Sopenharmony_ci return sksg::Transform::MakeConcat(adapter->node(), std::move(parent)); 131cb93a386Sopenharmony_ci} 132cb93a386Sopenharmony_ci 133cb93a386Sopenharmony_ci} // namespace internal 134cb93a386Sopenharmony_ci} // namespace skottie 135