/
TextureMatrix.cpp
136 lines (116 loc) · 4.25 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
124
125
126
127
128
129
130
131
132
133
134
135
136
#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(std::size_t width, std::size_t height) const
{
ShiftScaleRotation ssr;
// These values are going to show up in the Surface Inspector, which takes the image
// dimensions into account. We stretch UV space using the image dimensions.
// Surface Inspector wants to display values such that scale == 1.0 means:
// a 512-unit wide face can display the full 512px of the editor image.
// The corresponding texture matrix transform features a scale value like 1/512
// to scale the 512 XYZ coord down to 1.0 in UV space.
ssr.scale[0] = 1.0 / Vector2(_coords[0][0] * width, _coords[1][0] * height).getLength();
ssr.scale[1] = 1.0 / Vector2(_coords[0][1] * width, _coords[1][1] * height).getLength();
ssr.rotate = -radians_to_degrees(arctangent_yx(_coords[1][0] * height, _coords[0][0] * width));
// We want the shift values appear in pixels of the editor image,
// so scale up the UV values by the editor image dimensions
ssr.shift[0] = -_coords[0][2] * width;
ssr.shift[1] = _coords[1][2] * height;
// We only need to display shift values in the range of the texture dimensions
ssr.shift[0] = float_mod(ssr.shift[0], width);
ssr.shift[1] = float_mod(ssr.shift[1], height);
// 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]);
}