-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathBitmapShader.cpp
More file actions
110 lines (98 loc) · 3.65 KB
/
Copy pathBitmapShader.cpp
File metadata and controls
110 lines (98 loc) · 3.65 KB
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
#ifndef Shader_DEFINED
#define Shader_DEFINED
#include "./include/GShader.h"
#include "./include/GMatrix.h"
#include "./include/GBitmap.h"
#include "./include/GPoint.h"
/// @brief A bitmap shader.
class BitmapShader : public GShader {
public:
BitmapShader(const GBitmap& ShaderBM, const GMatrix& localInverse, GShader::TileMode tileMode) :
ShaderBM(ShaderBM),
localInverse(localInverse),
mode(tileMode) { }
bool isOpaque() { return ShaderBM.isOpaque(); }
bool setContext(const GMatrix& ctm) override {
GMatrix inv_ctm;
if (!ctm.invert(&inv_ctm)) return false;
m = GMatrix::Concat(localInverse, inv_ctm);
return true;
}
void shadeRow(int x, int y, int count, GPixel row[]) {
GPoint tmp = m * GPoint{x + 0.5f, y + 0.5f};
float localX = tmp.fX;
float localY = tmp.fY;
float dx = m[0];
float dy = m[3];
for (int j = 0; j < count; j ++) {
float ix = localX + dx * j;
float iy = localY + dy * j;
// Clamp
switch(mode) {
case GShader::kClamp: {
if (ix >= ShaderBM.width()) {
ix = ShaderBM.width() - 1;
} else if (ix < 0) ix = 0;
if (iy >= ShaderBM.height()) {
iy = ShaderBM.height() - 1;
} else if (iy < 0) iy = 0;
break;
}
case GShader::kRepeat: {
ix = ix / ShaderBM.width();
iy = iy / ShaderBM.height();
ix = ix - floor(ix);
iy = iy - floor(iy);
ix = ix * ShaderBM.width();
iy = iy * ShaderBM.height();
if (ix > ShaderBM.width() - 1) {
ix = ShaderBM.width() - 1;
}
if (iy > ShaderBM.height() - 1) {
iy = ShaderBM.height() - 1;
}
assert(ix < ShaderBM.width());
assert(iy < ShaderBM.height());
break;
}
case GShader::kMirror: {
ix = ix / (2 * ShaderBM.width());
iy = iy / (2 * ShaderBM.height());
ix = ix - floor(ix);
iy = iy - floor(iy);
if (ix <= 0.5) ix = ix * 2 * ShaderBM.width();
else {
float diff = ix - 0.5;
ix = (0.5 - diff) * 2 * ShaderBM.width();
}
if (iy <= 0.5) iy = iy * 2 * ShaderBM.height();
else {
float diff = iy - 0.5;
iy = (0.5 - diff) * 2 * ShaderBM.height();
}
if (ix > ShaderBM.width() - 1) {
ix = ShaderBM.width() - 1;
}
if (iy > ShaderBM.height() - 1) {
iy = ShaderBM.height() - 1;
}
assert(ix < ShaderBM.width());
assert(iy < ShaderBM.height());
break;
}
}
row[j] = *ShaderBM.getAddr(ix, iy);
}
}
private:
GMatrix m;
GMatrix localInverse;
GBitmap ShaderBM;
GShader::TileMode mode;
};
std::unique_ptr<GShader> GCreateBitmapShader(const GBitmap& ShaderBM,
const GMatrix& localInverse,
GShader::TileMode tileMode) {
return std::unique_ptr<GShader>(new BitmapShader(ShaderBM, localInverse, tileMode));
}
#endif