178b860769
When per-character 3D is enabled, text properties can be animated in 3 dimensions. - position and scale become 3-value vectors - in addition to existing "r" (really rz), rotation gains "rx" and "ry" - instead of specializing for 3D, expand the existing structures to handle both 3D and 2D modes - also ensure that sksg::Transform does not flatten to SkMatrix Change-Id: I426a7ee1ff38c1702deb85e9f1db80f6069f36d6 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/272648 Reviewed-by: Mike Reed <reed@google.com> Commit-Queue: Florin Malita <fmalita@chromium.org>
399 lines
13 KiB
C++
399 lines
13 KiB
C++
/*
|
|
* Copyright 2020 Google Inc.
|
|
*
|
|
* Use of this source code is governed by a BSD-style license that can be
|
|
* found in the LICENSE file.
|
|
*/
|
|
|
|
#ifndef SkM44_DEFINED
|
|
#define SkM44_DEFINED
|
|
|
|
#include "include/core/SkMatrix.h"
|
|
#include "include/core/SkScalar.h"
|
|
|
|
struct SkV2 {
|
|
float x, y;
|
|
|
|
bool operator==(const SkV2 v) const { return x == v.x && y == v.y; }
|
|
bool operator!=(const SkV2 v) const { return !(*this == v); }
|
|
|
|
static SkScalar Dot(SkV2 a, SkV2 b) { return a.x * b.x + a.y * b.y; }
|
|
static SkScalar Cross(SkV2 a, SkV2 b) { return a.x * b.y - a.y * b.x; }
|
|
static SkV2 Normalize(SkV2 v) { return v * (1.0f / v.length()); }
|
|
|
|
SkV2 operator-() const { return {-x, -y}; }
|
|
SkV2 operator+(SkV2 v) const { return {x+v.x, y+v.y}; }
|
|
SkV2 operator-(SkV2 v) const { return {x-v.x, y-v.y}; }
|
|
|
|
SkV2 operator*(SkV2 v) const { return {x*v.x, y*v.y}; }
|
|
friend SkV2 operator*(SkV2 v, SkScalar s) { return {v.x*s, v.y*s}; }
|
|
friend SkV2 operator*(SkScalar s, SkV2 v) { return {v.x*s, v.y*s}; }
|
|
|
|
void operator+=(SkV2 v) { *this = *this + v; }
|
|
void operator-=(SkV2 v) { *this = *this - v; }
|
|
void operator*=(SkV2 v) { *this = *this * v; }
|
|
void operator*=(SkScalar s) { *this = *this * s; }
|
|
|
|
SkScalar lengthSquared() const { return Dot(*this, *this); }
|
|
SkScalar length() const { return SkScalarSqrt(this->lengthSquared()); }
|
|
|
|
SkScalar dot(SkV2 v) const { return Dot(*this, v); }
|
|
SkScalar cross(SkV2 v) const { return Cross(*this, v); }
|
|
SkV2 normalize() const { return Normalize(*this); }
|
|
|
|
const float* ptr() const { return &x; }
|
|
float* ptr() { return &x; }
|
|
};
|
|
|
|
struct SkV3 {
|
|
float x, y, z;
|
|
|
|
bool operator==(const SkV3& v) const {
|
|
return x == v.x && y == v.y && z == v.z;
|
|
}
|
|
bool operator!=(const SkV3& v) const { return !(*this == v); }
|
|
|
|
static SkScalar Dot(const SkV3& a, const SkV3& b) { return a.x*b.x + a.y*b.y + a.z*b.z; }
|
|
static SkV3 Cross(const SkV3& a, const SkV3& b) {
|
|
return { a.y*b.z - a.z*b.y, a.z*b.x - a.x*b.z, a.x*b.y - a.y*b.x };
|
|
}
|
|
static SkV3 Normalize(const SkV3& v) { return v * (1.0f / v.length()); }
|
|
|
|
SkV3 operator-() const { return {-x, -y, -z}; }
|
|
SkV3 operator+(const SkV3& v) const { return { x + v.x, y + v.y, z + v.z }; }
|
|
SkV3 operator-(const SkV3& v) const { return { x - v.x, y - v.y, z - v.z }; }
|
|
|
|
SkV3 operator*(const SkV3& v) const {
|
|
return { x*v.x, y*v.y, z*v.z };
|
|
}
|
|
friend SkV3 operator*(const SkV3& v, SkScalar s) {
|
|
return { v.x*s, v.y*s, v.z*s };
|
|
}
|
|
friend SkV3 operator*(SkScalar s, const SkV3& v) { return v*s; }
|
|
|
|
void operator+=(SkV3 v) { *this = *this + v; }
|
|
void operator-=(SkV3 v) { *this = *this - v; }
|
|
void operator*=(SkV3 v) { *this = *this * v; }
|
|
void operator*=(SkScalar s) { *this = *this * s; }
|
|
|
|
SkScalar lengthSquared() const { return Dot(*this, *this); }
|
|
SkScalar length() const { return SkScalarSqrt(Dot(*this, *this)); }
|
|
|
|
SkScalar dot(const SkV3& v) const { return Dot(*this, v); }
|
|
SkV3 cross(const SkV3& v) const { return Cross(*this, v); }
|
|
SkV3 normalize() const { return Normalize(*this); }
|
|
|
|
const float* ptr() const { return &x; }
|
|
float* ptr() { return &x; }
|
|
};
|
|
|
|
struct SkV4 {
|
|
float x, y, z, w;
|
|
|
|
bool operator==(const SkV4& v) const {
|
|
return x == v.x && y == v.y && z == v.z && w == v.w;
|
|
}
|
|
bool operator!=(const SkV4& v) const { return !(*this == v); }
|
|
|
|
SkV4 operator-() const { return {-x, -y, -z, -w}; }
|
|
SkV4 operator+(const SkV4& v) const { return { x + v.x, y + v.y, z + v.z, w + v.w }; }
|
|
SkV4 operator-(const SkV4& v) const { return { x - v.x, y - v.y, z - v.z, w - v.w }; }
|
|
|
|
SkV4 operator*(const SkV4& v) const {
|
|
return { x*v.x, y*v.y, z*v.z, w*v.w };
|
|
}
|
|
friend SkV4 operator*(const SkV4& v, SkScalar s) {
|
|
return { v.x*s, v.y*s, v.z*s, v.w*s };
|
|
}
|
|
friend SkV4 operator*(SkScalar s, const SkV4& v) { return v*s; }
|
|
|
|
const float* ptr() const { return &x; }
|
|
float* ptr() { return &x; }
|
|
};
|
|
|
|
/**
|
|
* 4x4 matrix used by SkCanvas and other parts of Skia.
|
|
*
|
|
* Skia assumes a right-handed coordinate system:
|
|
* +X goes to the right
|
|
* +Y goes down
|
|
* +Z goes into the screen (away from the viewer)
|
|
*/
|
|
class SkM44 {
|
|
public:
|
|
SkM44(const SkM44& src) = default;
|
|
SkM44& operator=(const SkM44& src) = default;
|
|
|
|
constexpr SkM44()
|
|
: fMat{1, 0, 0, 0,
|
|
0, 1, 0, 0,
|
|
0, 0, 1, 0,
|
|
0, 0, 0, 1}
|
|
{}
|
|
|
|
SkM44(const SkM44& a, const SkM44& b) {
|
|
this->setConcat(a, b);
|
|
}
|
|
|
|
enum Uninitialized_Constructor {
|
|
kUninitialized_Constructor
|
|
};
|
|
SkM44(Uninitialized_Constructor) {}
|
|
|
|
enum NaN_Constructor {
|
|
kNaN_Constructor
|
|
};
|
|
SkM44(NaN_Constructor)
|
|
: fMat{SK_ScalarNaN, SK_ScalarNaN, SK_ScalarNaN, SK_ScalarNaN,
|
|
SK_ScalarNaN, SK_ScalarNaN, SK_ScalarNaN, SK_ScalarNaN,
|
|
SK_ScalarNaN, SK_ScalarNaN, SK_ScalarNaN, SK_ScalarNaN,
|
|
SK_ScalarNaN, SK_ScalarNaN, SK_ScalarNaN, SK_ScalarNaN}
|
|
{}
|
|
|
|
/**
|
|
* Parameters are treated as row-major.
|
|
*/
|
|
SkM44(SkScalar m0, SkScalar m4, SkScalar m8, SkScalar m12,
|
|
SkScalar m1, SkScalar m5, SkScalar m9, SkScalar m13,
|
|
SkScalar m2, SkScalar m6, SkScalar m10, SkScalar m14,
|
|
SkScalar m3, SkScalar m7, SkScalar m11, SkScalar m15)
|
|
{
|
|
this->set44(m0, m4, m8, m12,
|
|
m1, m5, m9, m13,
|
|
m2, m6, m10, m14,
|
|
m3, m7, m11, m15);
|
|
}
|
|
|
|
static SkM44 Rows(const SkV4& r0, const SkV4& r1, const SkV4& r2, const SkV4& r3) {
|
|
SkM44 m(kUninitialized_Constructor);
|
|
m.setRow(0, r0);
|
|
m.setRow(1, r1);
|
|
m.setRow(2, r2);
|
|
m.setRow(3, r3);
|
|
return m;
|
|
}
|
|
static SkM44 Cols(const SkV4& c0, const SkV4& c1, const SkV4& c2, const SkV4& c3) {
|
|
SkM44 m(kUninitialized_Constructor);
|
|
m.setCol(0, c0);
|
|
m.setCol(1, c1);
|
|
m.setCol(2, c2);
|
|
m.setCol(3, c3);
|
|
return m;
|
|
}
|
|
|
|
static SkM44 Translate(SkScalar x, SkScalar y, SkScalar z = 0) {
|
|
return SkM44(1, 0, 0, x,
|
|
0, 1, 0, y,
|
|
0, 0, 1, z,
|
|
0, 0, 0, 1);
|
|
}
|
|
|
|
static SkM44 Scale(SkScalar x, SkScalar y, SkScalar z = 1) {
|
|
return SkM44(x, 0, 0, 0,
|
|
0, y, 0, 0,
|
|
0, 0, z, 0,
|
|
0, 0, 0, 1);
|
|
}
|
|
|
|
static SkM44 Rotate(SkV3 axis, SkScalar radians) {
|
|
SkM44 m(kUninitialized_Constructor);
|
|
m.setRotate(axis, radians);
|
|
return m;
|
|
}
|
|
|
|
bool operator==(const SkM44& other) const;
|
|
bool operator!=(const SkM44& other) const {
|
|
return !(other == *this);
|
|
}
|
|
|
|
void getColMajor(SkScalar v[]) const {
|
|
memcpy(v, fMat, sizeof(fMat));
|
|
}
|
|
void getRowMajor(SkScalar v[]) const;
|
|
|
|
SkM44& setColMajor(const SkScalar v[]) {
|
|
memcpy(fMat, v, sizeof(fMat));
|
|
return *this;
|
|
}
|
|
SkM44& setRowMajor(const SkScalar v[]);
|
|
|
|
/* Parameters in same order as constructor.
|
|
*/
|
|
SkM44& set44(SkScalar m0, SkScalar m4, SkScalar m8, SkScalar m12,
|
|
SkScalar m1, SkScalar m5, SkScalar m9, SkScalar m13,
|
|
SkScalar m2, SkScalar m6, SkScalar m10, SkScalar m14,
|
|
SkScalar m3, SkScalar m7, SkScalar m11, SkScalar m15) {
|
|
fMat[0] = m0; fMat[4] = m4; fMat[8] = m8; fMat[12] = m12;
|
|
fMat[1] = m1; fMat[5] = m5; fMat[9] = m9; fMat[13] = m13;
|
|
fMat[2] = m2; fMat[6] = m6; fMat[10] = m10; fMat[14] = m14;
|
|
fMat[3] = m3; fMat[7] = m7; fMat[11] = m11; fMat[15] = m15;
|
|
return *this;
|
|
}
|
|
|
|
SkScalar rc(int r, int c) const {
|
|
SkASSERT(r >= 0 && r <= 3);
|
|
SkASSERT(c >= 0 && c <= 3);
|
|
return fMat[c*4 + r];
|
|
}
|
|
void setRC(int r, int c, SkScalar value) {
|
|
SkASSERT(r >= 0 && r <= 3);
|
|
SkASSERT(c >= 0 && c <= 3);
|
|
fMat[c*4 + r] = value;
|
|
}
|
|
|
|
SkV4 row(int i) const {
|
|
SkASSERT(i >= 0 && i <= 3);
|
|
return {fMat[i + 0], fMat[i + 4], fMat[i + 8], fMat[i + 12]};
|
|
}
|
|
SkV4 col(int i) const {
|
|
SkASSERT(i >= 0 && i <= 3);
|
|
return {fMat[i*4 + 0], fMat[i*4 + 1], fMat[i*4 + 2], fMat[i*4 + 3]};
|
|
}
|
|
|
|
void setRow(int i, const SkV4& v) {
|
|
SkASSERT(i >= 0 && i <= 3);
|
|
fMat[i + 0] = v.x;
|
|
fMat[i + 4] = v.y;
|
|
fMat[i + 8] = v.z;
|
|
fMat[i + 12] = v.w;
|
|
}
|
|
void setCol(int i, const SkV4& v) {
|
|
SkASSERT(i >= 0 && i <= 3);
|
|
memcpy(&fMat[i*4], v.ptr(), sizeof(v));
|
|
}
|
|
|
|
SkM44& setIdentity() {
|
|
return this->set44(1, 0, 0, 0,
|
|
0, 1, 0, 0,
|
|
0, 0, 1, 0,
|
|
0, 0, 0, 1);
|
|
}
|
|
|
|
SkM44& setTranslate(SkScalar x, SkScalar y, SkScalar z = 0) {
|
|
return this->set44(1, 0, 0, x,
|
|
0, 1, 0, y,
|
|
0, 0, 1, z,
|
|
0, 0, 0, 1);
|
|
}
|
|
|
|
SkM44& setScale(SkScalar x, SkScalar y, SkScalar z = 1) {
|
|
return this->set44(x, 0, 0, 0,
|
|
0, y, 0, 0,
|
|
0, 0, z, 0,
|
|
0, 0, 0, 1);
|
|
}
|
|
|
|
/**
|
|
* Set this matrix to rotate about the specified unit-length axis vector,
|
|
* by an angle specified by its sin() and cos().
|
|
*
|
|
* This does not attempt to verify that axis.length() == 1 or that the sin,cos values
|
|
* are correct.
|
|
*/
|
|
SkM44& setRotateUnitSinCos(SkV3 axis, SkScalar sinAngle, SkScalar cosAngle);
|
|
|
|
/**
|
|
* Set this matrix to rotate about the specified unit-length axis vector,
|
|
* by an angle specified in radians.
|
|
*
|
|
* This does not attempt to verify that axis.length() == 1.
|
|
*/
|
|
SkM44& setRotateUnit(SkV3 axis, SkScalar radians) {
|
|
return this->setRotateUnitSinCos(axis, SkScalarSin(radians), SkScalarCos(radians));
|
|
}
|
|
|
|
/**
|
|
* Set this matrix to rotate about the specified axis vector,
|
|
* by an angle specified in radians.
|
|
*
|
|
* Note: axis is not assumed to be unit-length, so it will be normalized internally.
|
|
* If axis is already unit-length, call setRotateAboutUnitRadians() instead.
|
|
*/
|
|
SkM44& setRotate(SkV3 axis, SkScalar radians);
|
|
|
|
SkM44& setConcat16(const SkM44& a, const SkScalar colMajor[16]);
|
|
|
|
SkM44& setConcat(const SkM44& a, const SkM44& b) {
|
|
return this->setConcat16(a, b.fMat);
|
|
}
|
|
|
|
friend SkM44 operator*(const SkM44& a, const SkM44& b) {
|
|
return SkM44(a, b);
|
|
}
|
|
|
|
SkM44& preConcat16(const SkScalar colMajor[16]) {
|
|
return this->setConcat16(*this, colMajor);
|
|
}
|
|
|
|
/** If this is invertible, return that in inverse and return true. If it is
|
|
* not invertible, return false and leave the inverse parameter unchanged.
|
|
*/
|
|
bool SK_WARN_UNUSED_RESULT invert(SkM44* inverse) const;
|
|
|
|
SkM44 transpose() const;
|
|
|
|
void dump() const;
|
|
|
|
////////////
|
|
|
|
SkV4 map(float x, float y, float z, float w) const;
|
|
SkV4 operator*(const SkV4& v) const {
|
|
return this->map(v.x, v.y, v.z, v.w);
|
|
}
|
|
SkV3 operator*(SkV3 v) const {
|
|
auto v4 = this->map(v.x, v.y, v.z, 0);
|
|
return {v4.x, v4.y, v4.z};
|
|
}
|
|
|
|
////////////////////// Converting to/from SkMatrix
|
|
|
|
/* When converting from SkM44 to SkMatrix, the third row and
|
|
* column is dropped. When converting from SkMatrix to SkM44
|
|
* the third row and column remain as identity:
|
|
* [ a b c ] [ a b 0 c ]
|
|
* [ d e f ] -> [ d e 0 f ]
|
|
* [ g h i ] [ 0 0 1 0 ]
|
|
* [ g h 0 i ]
|
|
*/
|
|
SkMatrix asM33() const {
|
|
return SkMatrix::MakeAll(fMat[0], fMat[4], fMat[12],
|
|
fMat[1], fMat[5], fMat[13],
|
|
fMat[3], fMat[7], fMat[15]);
|
|
}
|
|
|
|
SkM44(const SkMatrix& src)
|
|
: SkM44(src[SkMatrix::kMScaleX], src[SkMatrix::kMSkewX], 0, src[SkMatrix::kMTransX],
|
|
src[SkMatrix::kMSkewY], src[SkMatrix::kMScaleY], 0, src[SkMatrix::kMTransY],
|
|
0, 0, 1, 0,
|
|
src[SkMatrix::kMPersp0], src[SkMatrix::kMPersp1], 0, src[SkMatrix::kMPersp2])
|
|
{}
|
|
|
|
SkM44& operator=(const SkMatrix& src) {
|
|
*this = SkM44(src);
|
|
return *this;
|
|
}
|
|
|
|
SkM44& preTranslate(SkScalar x, SkScalar y);
|
|
SkM44& preScale(SkScalar x, SkScalar y);
|
|
SkM44& preConcat(const SkMatrix&);
|
|
|
|
private:
|
|
/* Stored in column-major.
|
|
* Indices
|
|
* 0 4 8 12 1 0 0 trans_x
|
|
* 1 5 9 13 e.g. 0 1 0 trans_y
|
|
* 2 6 10 14 0 0 1 trans_z
|
|
* 3 7 11 15 0 0 0 1
|
|
*/
|
|
SkScalar fMat[16];
|
|
|
|
double determinant() const;
|
|
|
|
friend class SkMatrixPriv;
|
|
};
|
|
|
|
SkM44 Sk3LookAt(const SkV3& eye, const SkV3& center, const SkV3& up);
|
|
SkM44 Sk3Perspective(float near, float far, float angle);
|
|
|
|
#endif
|