Coverage Report

Created: 2021-08-22 09:07

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