/
TextureMatrix.cpp
123 lines (105 loc) · 3.38 KB
/
TextureMatrix.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
#include "TextureMatrix.h"
#include "texturelib.h"
#include "math/pi.h"
#include "math/Vector2.h"
#include "math/Matrix3.h"
TextureMatrix::TextureMatrix()
{
_coords[0][0] = 2.0f;
_coords[0][1] = 0.f;
_coords[0][2] = 0.f;
_coords[1][0] = 0.f;
_coords[1][1] = 2.0f;
_coords[1][2] = 0.f;
}
TextureMatrix::TextureMatrix(const Matrix3& transform)
{
_coords[0][0] = transform.xx();
_coords[0][1] = transform.yx();
_coords[0][2] = transform.zx();
_coords[1][0] = transform.xy();
_coords[1][1] = transform.yy();
_coords[1][2] = transform.zy();
}
TextureMatrix::TextureMatrix(const ShiftScaleRotation& ssr)
{
auto r = degrees_to_radians(-ssr.rotate);
auto c = cos(r);
auto s = sin(r);
auto x = 1.0 / ssr.scale[0];
auto y = 1.0 / ssr.scale[1];
_coords[0][0] = x * c;
_coords[1][0] = x * s;
_coords[0][1] = y * -s;
_coords[1][1] = y * c;
_coords[0][2] = -ssr.shift[0];
_coords[1][2] = ssr.shift[1];
}
void TextureMatrix::shift(double s, double t)
{
// x and y are geometric values, which we must compute as ST increments
// this depends on the texture size and the pixel/texel ratio
// as a ratio against texture size
// the scale of the texture is not relevant here (we work directly on a transformation from the base vectors)
_coords[0][2] -= s;
_coords[1][2] += t;
}
void TextureMatrix::addScale(std::size_t width, std::size_t height)
{
_coords[0][0] /= width;
_coords[0][1] /= width;
_coords[0][2] /= width;
_coords[1][0] /= height;
_coords[1][1] /= height;
_coords[1][2] /= height;
}
ShiftScaleRotation TextureMatrix::getShiftScaleRotation() const
{
ShiftScaleRotation ssr;
ssr.scale[0] = 1.0 / Vector2(_coords[0][0], _coords[1][0]).getLength();
ssr.scale[1] = 1.0 / Vector2(_coords[0][1], _coords[1][1]).getLength();
ssr.rotate = -radians_to_degrees(arctangent_yx(_coords[1][0], _coords[0][0]));
ssr.shift[0] = -_coords[0][2];
ssr.shift[1] = _coords[1][2];
// determine whether or not an axis is flipped using a 2d cross-product
auto cross = Vector2(_coords[0][0], _coords[0][1]).crossProduct(Vector2(_coords[1][0], _coords[1][1]));
if (cross < 0)
{
// This is a bit of a compromise when using BPs--since we don't know *which* axis was flipped,
// we pick one (rather arbitrarily) using the following convention: If the X-axis is between
// 0 and 180, we assume it's the Y-axis that flipped, otherwise we assume it's the X-axis and
// subtract out 180 degrees to compensate.
if (ssr.rotate >= 180.0)
{
ssr.rotate -= 180.0;
ssr.scale[0] = -ssr.scale[0];
}
else
{
ssr.scale[1] = -ssr.scale[1];
}
}
return ssr;
}
void TextureMatrix::normalise(float width, float height)
{
_coords[0][2] = float_mod(_coords[0][2], width);
_coords[1][2] = float_mod(_coords[1][2], height);
}
Matrix3 TextureMatrix::getMatrix3() const
{
return Matrix3::byRows(
_coords[0][0], _coords[0][1], _coords[0][2],
_coords[1][0], _coords[1][1], _coords[1][2],
0, 0, 1
);
}
bool TextureMatrix::isSane() const
{
return !std::isnan(_coords[0][0]) && !std::isinf(_coords[0][0]) &&
!std::isnan(_coords[0][1]) && !std::isinf(_coords[0][1]) &&
!std::isnan(_coords[0][2]) && !std::isinf(_coords[0][2]) &&
!std::isnan(_coords[1][0]) && !std::isinf(_coords[1][0]) &&
!std::isnan(_coords[1][1]) && !std::isinf(_coords[1][1]) &&
!std::isnan(_coords[1][2]) && !std::isinf(_coords[1][2]);
}