- sprite additions: multiple locations, auto wrapping, scale mod
- remap colors on a texture - two pixel scaling algorithms: custom scale2x based on http://www.scale2x.it/algorithm.html and superxbr
This commit is contained in:
parent
3d439e56e0
commit
bc2a4a39ad
|
@ -0,0 +1,375 @@
|
|||
//// *** Super-xBR code begins here - MIT LICENSE *** ///
|
||||
|
||||
/*
|
||||
|
||||
******* Super XBR Scaler *******
|
||||
|
||||
Copyright (c) 2016 Hyllian - sergiogdb@gmail.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
typedef uint32_t u32;
|
||||
|
||||
#define R(_col) ((_col>> 0)&0xFF)
|
||||
#define G(_col) ((_col>> 8)&0xFF)
|
||||
#define B(_col) ((_col>>16)&0xFF)
|
||||
#define A(_col) ((_col>>24)&0xFF)
|
||||
|
||||
|
||||
#define wgt1 0.129633f
|
||||
#define wgt2 0.175068f
|
||||
#define w1 (-wgt1)
|
||||
#define w2 (wgt1+0.5f)
|
||||
#define w3 (-wgt2)
|
||||
#define w4 (wgt2+0.5f)
|
||||
|
||||
|
||||
|
||||
float df(float A, float B)
|
||||
{
|
||||
return abs(A - B);
|
||||
}
|
||||
|
||||
float min4(float a, float b, float c, float d)
|
||||
{
|
||||
return std::min(std::min(a,b),std::min(c, d));
|
||||
}
|
||||
|
||||
float max4(float a, float b, float c, float d)
|
||||
{
|
||||
return std::max(std::max(a, b), std::max(c, d));
|
||||
}
|
||||
|
||||
template<class T>
|
||||
T clamp(T x, T floor, T ceil)
|
||||
{
|
||||
return std::max(std::min(x, ceil), floor);
|
||||
}
|
||||
|
||||
/*
|
||||
P1
|
||||
|P0|B |C |P1| C F4 |a0|b1|c2|d3|
|
||||
|D |E |F |F4| B F I4 |b0|c1|d2|e3| |e1|i1|i2|e2|
|
||||
|G |H |I |I4| P0 E A I P3 |c0|d1|e2|f3| |e3|i3|i4|e4|
|
||||
|P2|H5|I5|P3| D H I5 |d0|e1|f2|g3|
|
||||
G H5
|
||||
P2
|
||||
|
||||
sx, sy
|
||||
-1 -1 | -2 0 (x+y) (x-y) -3 1 (x+y-1) (x-y+1)
|
||||
-1 0 | -1 -1 -2 0
|
||||
-1 1 | 0 -2 -1 -1
|
||||
-1 2 | 1 -3 0 -2
|
||||
|
||||
0 -1 | -1 1 (x+y) (x-y) ... ... ...
|
||||
0 0 | 0 0
|
||||
0 1 | 1 -1
|
||||
0 2 | 2 -2
|
||||
|
||||
1 -1 | 0 2 ...
|
||||
1 0 | 1 1
|
||||
1 1 | 2 0
|
||||
1 2 | 3 -1
|
||||
|
||||
2 -1 | 1 3 ...
|
||||
2 0 | 2 2
|
||||
2 1 | 3 1
|
||||
2 2 | 4 0
|
||||
|
||||
|
||||
*/
|
||||
|
||||
float diagonal_edge(float mat[][4], float *wp) {
|
||||
float dw1 = wp[0]*(df(mat[0][2], mat[1][1]) + df(mat[1][1], mat[2][0]) + df(mat[1][3], mat[2][2]) + df(mat[2][2], mat[3][1])) +\
|
||||
wp[1]*(df(mat[0][3], mat[1][2]) + df(mat[2][1], mat[3][0])) + \
|
||||
wp[2]*(df(mat[0][3], mat[2][1]) + df(mat[1][2], mat[3][0])) +\
|
||||
wp[3]*df(mat[1][2], mat[2][1]) +\
|
||||
wp[4]*(df(mat[0][2], mat[2][0]) + df(mat[1][3], mat[3][1])) +\
|
||||
wp[5]*(df(mat[0][1], mat[1][0]) + df(mat[2][3], mat[3][2]));
|
||||
|
||||
float dw2 = wp[0]*(df(mat[0][1], mat[1][2]) + df(mat[1][2], mat[2][3]) + df(mat[1][0], mat[2][1]) + df(mat[2][1], mat[3][2])) +\
|
||||
wp[1]*(df(mat[0][0], mat[1][1]) + df(mat[2][2], mat[3][3])) +\
|
||||
wp[2]*(df(mat[0][0], mat[2][2]) + df(mat[1][1], mat[3][3])) +\
|
||||
wp[3]*df(mat[1][1], mat[2][2]) +\
|
||||
wp[4]*(df(mat[1][0], mat[3][2]) + df(mat[0][1], mat[2][3])) +\
|
||||
wp[5]*(df(mat[0][2], mat[1][3]) + df(mat[2][0], mat[3][1]));
|
||||
|
||||
return (dw1 - dw2);
|
||||
}
|
||||
|
||||
// Not used yet...
|
||||
float cross_edge(float mat[][4], float *wp) {
|
||||
float hvw1 = wp[3] * (df(mat[1][1], mat[2][1]) + df(mat[1][2], mat[2][2])) + \
|
||||
wp[0] * (df(mat[0][1], mat[1][1]) + df(mat[2][1], mat[3][1]) + df(mat[0][2], mat[1][2]) + df(mat[2][2], mat[3][2])) + \
|
||||
wp[2] * (df(mat[0][1], mat[2][1]) + df(mat[1][1], mat[3][1]) + df(mat[0][2], mat[2][2]) + df(mat[1][2], mat[3][2]));
|
||||
|
||||
float hvw2 = wp[3] * (df(mat[1][1], mat[1][2]) + df(mat[2][1], mat[2][2])) + \
|
||||
wp[0] * (df(mat[1][0], mat[1][1]) + df(mat[2][0], mat[2][1]) + df(mat[1][2], mat[1][3]) + df(mat[2][2], mat[2][3])) + \
|
||||
wp[2] * (df(mat[1][0], mat[1][2]) + df(mat[1][1], mat[1][3]) + df(mat[2][0], mat[2][2]) + df(mat[2][1], mat[2][3]));
|
||||
|
||||
return (hvw1 - hvw2);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
///////////////////////// Super-xBR scaling
|
||||
// perform super-xbr (fast shader version) scaling by factor f=2 only.
|
||||
template<int f>
|
||||
void scaleSuperXBRT(u32* data, u32* out, int w, int h) {
|
||||
int outw = w*f, outh = h*f;
|
||||
|
||||
float wp[6] = { 2.0f, 1.0f, -1.0f, 4.0f, -1.0f, 1.0f };
|
||||
|
||||
// First Pass
|
||||
for (int y = 0; y < outh; ++y) {
|
||||
for (int x = 0; x < outw; ++x) {
|
||||
float r[4][4], g[4][4], b[4][4], a[4][4], Y[4][4];
|
||||
int cx = x / f, cy = y / f; // central pixels on original images
|
||||
// sample supporting pixels in original image
|
||||
for (int sx = -1; sx <= 2; ++sx) {
|
||||
for (int sy = -1; sy <= 2; ++sy) {
|
||||
// clamp pixel locations
|
||||
int csy = clamp(sy + cy, 0, h - 1);
|
||||
int csx = clamp(sx + cx, 0, w - 1);
|
||||
// sample & add weighted components
|
||||
u32 sample = data[csy*w + csx];
|
||||
r[sx + 1][sy + 1] = (float)R(sample);
|
||||
g[sx + 1][sy + 1] = (float)G(sample);
|
||||
b[sx + 1][sy + 1] = (float)B(sample);
|
||||
a[sx + 1][sy + 1] = (float)A(sample);
|
||||
Y[sx + 1][sy + 1] = (float)(0.2126*r[sx + 1][sy + 1] + 0.7152*g[sx + 1][sy + 1] + 0.0722*b[sx + 1][sy + 1]);
|
||||
}
|
||||
}
|
||||
float min_r_sample = min4(r[1][1], r[2][1], r[1][2], r[2][2]);
|
||||
float min_g_sample = min4(g[1][1], g[2][1], g[1][2], g[2][2]);
|
||||
float min_b_sample = min4(b[1][1], b[2][1], b[1][2], b[2][2]);
|
||||
float min_a_sample = min4(a[1][1], a[2][1], a[1][2], a[2][2]);
|
||||
float max_r_sample = max4(r[1][1], r[2][1], r[1][2], r[2][2]);
|
||||
float max_g_sample = max4(g[1][1], g[2][1], g[1][2], g[2][2]);
|
||||
float max_b_sample = max4(b[1][1], b[2][1], b[1][2], b[2][2]);
|
||||
float max_a_sample = max4(a[1][1], a[2][1], a[1][2], a[2][2]);
|
||||
float d_edge = diagonal_edge(Y, &wp[0]);
|
||||
float r1, g1, b1, a1, r2, g2, b2, a2, rf, gf, bf, af;
|
||||
r1 = (float)w1*(r[0][3] + r[3][0]) + (float)w2*(r[1][2] + r[2][1]);
|
||||
g1 = (float)w1*(g[0][3] + g[3][0]) + (float)w2*(g[1][2] + g[2][1]);
|
||||
b1 = (float)w1*(b[0][3] + b[3][0]) + (float)w2*(b[1][2] + b[2][1]);
|
||||
a1 = (float)w1*(a[0][3] + a[3][0]) + (float)w2*(a[1][2] + a[2][1]);
|
||||
r2 = (float)w1*(r[0][0] + r[3][3]) + (float)w2*(r[1][1] + r[2][2]);
|
||||
g2 = (float)w1*(g[0][0] + g[3][3]) + (float)w2*(g[1][1] + g[2][2]);
|
||||
b2 = (float)w1*(b[0][0] + b[3][3]) + (float)w2*(b[1][1] + b[2][2]);
|
||||
a2 = (float)w1*(a[0][0] + a[3][3]) + (float)w2*(a[1][1] + a[2][2]);
|
||||
// generate and write result
|
||||
if (d_edge <= 0.0f) { rf = r1; gf = g1; bf = b1; af = a1; }
|
||||
else { rf = r2; gf = g2; bf = b2; af = a2; }
|
||||
// anti-ringing, clamp.
|
||||
rf = clamp(rf, min_r_sample, max_r_sample);
|
||||
gf = clamp(gf, min_g_sample, max_g_sample);
|
||||
bf = clamp(bf, min_b_sample, max_b_sample);
|
||||
af = clamp(af, min_a_sample, max_a_sample);
|
||||
int ri = clamp(static_cast<int>(ceilf(rf)), 0, 255);
|
||||
int gi = clamp(static_cast<int>(ceilf(gf)), 0, 255);
|
||||
int bi = clamp(static_cast<int>(ceilf(bf)), 0, 255);
|
||||
int ai = clamp(static_cast<int>(ceilf(af)), 0, 255);
|
||||
out[y*outw + x] = out[y*outw + x + 1] = out[(y + 1)*outw + x] = data[cy*w + cx];
|
||||
out[(y+1)*outw + x+1] = (ai << 24) | (bi << 16) | (gi << 8) | ri;
|
||||
++x;
|
||||
}
|
||||
++y;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Second Pass
|
||||
wp[0] = 2.0f;
|
||||
wp[1] = 0.0f;
|
||||
wp[2] = 0.0f;
|
||||
wp[3] = 0.0f;
|
||||
wp[4] = 0.0f;
|
||||
wp[5] = 0.0f;
|
||||
|
||||
for (int y = 0; y < outh; ++y) {
|
||||
for (int x = 0; x < outw; ++x) {
|
||||
float r[4][4], g[4][4], b[4][4], a[4][4], Y[4][4];
|
||||
// sample supporting pixels in original image
|
||||
for (int sx = -1; sx <= 2; ++sx) {
|
||||
for (int sy = -1; sy <= 2; ++sy) {
|
||||
// clamp pixel locations
|
||||
int csy = clamp(sx - sy + y, 0, f*h - 1);
|
||||
int csx = clamp(sx + sy + x, 0, f*w - 1);
|
||||
// sample & add weighted components
|
||||
u32 sample = out[csy*outw + csx];
|
||||
r[sx + 1][sy + 1] = (float)R(sample);
|
||||
g[sx + 1][sy + 1] = (float)G(sample);
|
||||
b[sx + 1][sy + 1] = (float)B(sample);
|
||||
a[sx + 1][sy + 1] = (float)A(sample);
|
||||
Y[sx + 1][sy + 1] = (float)(0.2126*r[sx + 1][sy + 1] + 0.7152*g[sx + 1][sy + 1] + 0.0722*b[sx + 1][sy + 1]);
|
||||
}
|
||||
}
|
||||
float min_r_sample = min4(r[1][1], r[2][1], r[1][2], r[2][2]);
|
||||
float min_g_sample = min4(g[1][1], g[2][1], g[1][2], g[2][2]);
|
||||
float min_b_sample = min4(b[1][1], b[2][1], b[1][2], b[2][2]);
|
||||
float min_a_sample = min4(a[1][1], a[2][1], a[1][2], a[2][2]);
|
||||
float max_r_sample = max4(r[1][1], r[2][1], r[1][2], r[2][2]);
|
||||
float max_g_sample = max4(g[1][1], g[2][1], g[1][2], g[2][2]);
|
||||
float max_b_sample = max4(b[1][1], b[2][1], b[1][2], b[2][2]);
|
||||
float max_a_sample = max4(a[1][1], a[2][1], a[1][2], a[2][2]);
|
||||
float d_edge = diagonal_edge(Y, &wp[0]);
|
||||
float r1, g1, b1, a1, r2, g2, b2, a2, rf, gf, bf, af;
|
||||
r1 = (float)w3*(r[0][3] + r[3][0]) + (float)w4*(r[1][2] + r[2][1]);
|
||||
g1 = (float)w3*(g[0][3] + g[3][0]) + (float)w4*(g[1][2] + g[2][1]);
|
||||
b1 = (float)w3*(b[0][3] + b[3][0]) + (float)w4*(b[1][2] + b[2][1]);
|
||||
a1 = (float)w3*(a[0][3] + a[3][0]) + (float)w4*(a[1][2] + a[2][1]);
|
||||
r2 = (float)w3*(r[0][0] + r[3][3]) + (float)w4*(r[1][1] + r[2][2]);
|
||||
g2 = (float)w3*(g[0][0] + g[3][3]) + (float)w4*(g[1][1] + g[2][2]);
|
||||
b2 = (float)w3*(b[0][0] + b[3][3]) + (float)w4*(b[1][1] + b[2][2]);
|
||||
a2 = (float)w3*(a[0][0] + a[3][3]) + (float)w4*(a[1][1] + a[2][2]);
|
||||
// generate and write result
|
||||
if (d_edge <= 0.0f) { rf = r1; gf = g1; bf = b1; af = a1; }
|
||||
else { rf = r2; gf = g2; bf = b2; af = a2; }
|
||||
// anti-ringing, clamp.
|
||||
rf = clamp(rf, min_r_sample, max_r_sample);
|
||||
gf = clamp(gf, min_g_sample, max_g_sample);
|
||||
bf = clamp(bf, min_b_sample, max_b_sample);
|
||||
af = clamp(af, min_a_sample, max_a_sample);
|
||||
int ri = clamp(static_cast<int>(ceilf(rf)), 0, 255);
|
||||
int gi = clamp(static_cast<int>(ceilf(gf)), 0, 255);
|
||||
int bi = clamp(static_cast<int>(ceilf(bf)), 0, 255);
|
||||
int ai = clamp(static_cast<int>(ceilf(af)), 0, 255);
|
||||
out[y*outw + x + 1] = (ai << 24) | (bi << 16) | (gi << 8) | ri;
|
||||
|
||||
for (int sx = -1; sx <= 2; ++sx) {
|
||||
for (int sy = -1; sy <= 2; ++sy) {
|
||||
// clamp pixel locations
|
||||
int csy = clamp(sx - sy + 1 + y, 0, f*h - 1);
|
||||
int csx = clamp(sx + sy - 1 + x, 0, f*w - 1);
|
||||
// sample & add weighted components
|
||||
u32 sample = out[csy*outw + csx];
|
||||
r[sx + 1][sy + 1] = (float)R(sample);
|
||||
g[sx + 1][sy + 1] = (float)G(sample);
|
||||
b[sx + 1][sy + 1] = (float)B(sample);
|
||||
a[sx + 1][sy + 1] = (float)A(sample);
|
||||
Y[sx + 1][sy + 1] = (float)(0.2126*r[sx + 1][sy + 1] + 0.7152*g[sx + 1][sy + 1] + 0.0722*b[sx + 1][sy + 1]);
|
||||
}
|
||||
}
|
||||
d_edge = diagonal_edge(Y, &wp[0]);
|
||||
r1 = (float)w3*(r[0][3] + r[3][0]) + (float)w4*(r[1][2] + r[2][1]);
|
||||
g1 = (float)w3*(g[0][3] + g[3][0]) + (float)w4*(g[1][2] + g[2][1]);
|
||||
b1 = (float)w3*(b[0][3] + b[3][0]) + (float)w4*(b[1][2] + b[2][1]);
|
||||
a1 = (float)w3*(a[0][3] + a[3][0]) + (float)w4*(a[1][2] + a[2][1]);
|
||||
r2 = (float)w3*(r[0][0] + r[3][3]) + (float)w4*(r[1][1] + r[2][2]);
|
||||
g2 = (float)w3*(g[0][0] + g[3][3]) + (float)w4*(g[1][1] + g[2][2]);
|
||||
b2 = (float)w3*(b[0][0] + b[3][3]) + (float)w4*(b[1][1] + b[2][2]);
|
||||
a2 = (float)w3*(a[0][0] + a[3][3]) + (float)w4*(a[1][1] + a[2][2]);
|
||||
// generate and write result
|
||||
if (d_edge <= 0.0f) { rf = r1; gf = g1; bf = b1; af = a1; }
|
||||
else { rf = r2; gf = g2; bf = b2; af = a2; }
|
||||
// anti-ringing, clamp.
|
||||
rf = clamp(rf, min_r_sample, max_r_sample);
|
||||
gf = clamp(gf, min_g_sample, max_g_sample);
|
||||
bf = clamp(bf, min_b_sample, max_b_sample);
|
||||
af = clamp(af, min_a_sample, max_a_sample);
|
||||
ri = clamp(static_cast<int>(ceilf(rf)), 0, 255);
|
||||
gi = clamp(static_cast<int>(ceilf(gf)), 0, 255);
|
||||
bi = clamp(static_cast<int>(ceilf(bf)), 0, 255);
|
||||
ai = clamp(static_cast<int>(ceilf(af)), 0, 255);
|
||||
out[(y+1)*outw + x] = (ai << 24) | (bi << 16) | (gi << 8) | ri;
|
||||
++x;
|
||||
}
|
||||
++y;
|
||||
}
|
||||
|
||||
// Third Pass
|
||||
wp[0] = 2.0f;
|
||||
wp[1] = 1.0f;
|
||||
wp[2] = -1.0f;
|
||||
wp[3] = 4.0f;
|
||||
wp[4] = -1.0f;
|
||||
wp[5] = 1.0f;
|
||||
|
||||
for (int y = outh - 1; y >= 0; --y) {
|
||||
for (int x = outw - 1; x >= 0; --x) {
|
||||
float r[4][4], g[4][4], b[4][4], a[4][4], Y[4][4];
|
||||
for (int sx = -2; sx <= 1; ++sx) {
|
||||
for (int sy = -2; sy <= 1; ++sy) {
|
||||
// clamp pixel locations
|
||||
int csy = clamp(sy + y, 0, f*h - 1);
|
||||
int csx = clamp(sx + x, 0, f*w - 1);
|
||||
// sample & add weighted components
|
||||
u32 sample = out[csy*outw + csx];
|
||||
r[sx + 2][sy + 2] = (float)R(sample);
|
||||
g[sx + 2][sy + 2] = (float)G(sample);
|
||||
b[sx + 2][sy + 2] = (float)B(sample);
|
||||
a[sx + 2][sy + 2] = (float)A(sample);
|
||||
Y[sx + 2][sy + 2] = (float)(0.2126*r[sx + 2][sy + 2] + 0.7152*g[sx + 2][sy + 2] + 0.0722*b[sx + 2][sy + 2]);
|
||||
}
|
||||
}
|
||||
float min_r_sample = min4(r[1][1], r[2][1], r[1][2], r[2][2]);
|
||||
float min_g_sample = min4(g[1][1], g[2][1], g[1][2], g[2][2]);
|
||||
float min_b_sample = min4(b[1][1], b[2][1], b[1][2], b[2][2]);
|
||||
float min_a_sample = min4(a[1][1], a[2][1], a[1][2], a[2][2]);
|
||||
float max_r_sample = max4(r[1][1], r[2][1], r[1][2], r[2][2]);
|
||||
float max_g_sample = max4(g[1][1], g[2][1], g[1][2], g[2][2]);
|
||||
float max_b_sample = max4(b[1][1], b[2][1], b[1][2], b[2][2]);
|
||||
float max_a_sample = max4(a[1][1], a[2][1], a[1][2], a[2][2]);
|
||||
float d_edge = diagonal_edge(Y, &wp[0]);
|
||||
float r1, g1, b1, a1, r2, g2, b2, a2, rf, gf, bf, af;
|
||||
r1 = (float)w1*(r[0][3] + r[3][0]) + (float)w2*(r[1][2] + r[2][1]);
|
||||
g1 = (float)w1*(g[0][3] + g[3][0]) + (float)w2*(g[1][2] + g[2][1]);
|
||||
b1 = (float)w1*(b[0][3] + b[3][0]) + (float)w2*(b[1][2] + b[2][1]);
|
||||
a1 = (float)w1*(a[0][3] + a[3][0]) + (float)w2*(a[1][2] + a[2][1]);
|
||||
r2 = (float)w1*(r[0][0] + r[3][3]) + (float)w2*(r[1][1] + r[2][2]);
|
||||
g2 = (float)w1*(g[0][0] + g[3][3]) + (float)w2*(g[1][1] + g[2][2]);
|
||||
b2 = (float)w1*(b[0][0] + b[3][3]) + (float)w2*(b[1][1] + b[2][2]);
|
||||
a2 = (float)w1*(a[0][0] + a[3][3]) + (float)w2*(a[1][1] + a[2][2]);
|
||||
// generate and write result
|
||||
if (d_edge <= 0.0f) { rf = r1; gf = g1; bf = b1; af = a1; }
|
||||
else { rf = r2; gf = g2; bf = b2; af = a2; }
|
||||
// anti-ringing, clamp.
|
||||
rf = clamp(rf, min_r_sample, max_r_sample);
|
||||
gf = clamp(gf, min_g_sample, max_g_sample);
|
||||
bf = clamp(bf, min_b_sample, max_b_sample);
|
||||
af = clamp(af, min_a_sample, max_a_sample);
|
||||
int ri = clamp(static_cast<int>(ceilf(rf)), 0, 255);
|
||||
int gi = clamp(static_cast<int>(ceilf(gf)), 0, 255);
|
||||
int bi = clamp(static_cast<int>(ceilf(bf)), 0, 255);
|
||||
int ai = clamp(static_cast<int>(ceilf(af)), 0, 255);
|
||||
out[y*outw + x] = (ai << 24) | (bi << 16) | (gi << 8) | ri;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
//// *** Super-xBR code ends here - MIT LICENSE *** ///
|
||||
|
||||
|
||||
// void scaleSuperXBR(int factor, u32* data, u32* out, int w, int h) {
|
||||
/* Needs implementation.*/
|
||||
// switch (factor) {
|
||||
// case 2: scaleSuperXBRT<2>(data, out, w, h); break;
|
||||
// default: ERROR_LOG(VIDEO, "Super-xBR upsampling only implemented for factor 2");
|
||||
// }
|
||||
|
||||
// }
|
22
src/Box.cpp
22
src/Box.cpp
|
@ -1,10 +1,6 @@
|
|||
#include "Box.hpp"
|
||||
|
||||
Box::Box(glm::vec2 nw, glm::vec2 size)
|
||||
{
|
||||
set_nw(nw);
|
||||
set_size(size);
|
||||
}
|
||||
Box::Box(const glm::vec2& nw, const glm::vec2& size) : rect({nw.x, nw.y, size.x, size.y}) {}
|
||||
|
||||
float Box::get_x() const
|
||||
{
|
||||
|
@ -134,8 +130,7 @@ glm::vec2 Box::get_center() const
|
|||
|
||||
void Box::set_nw(const glm::vec2& nw)
|
||||
{
|
||||
set_x(nw.x);
|
||||
set_y(nw.y);
|
||||
move(nw - get_nw());
|
||||
}
|
||||
|
||||
void Box::set_north(const glm::vec2& n)
|
||||
|
@ -173,12 +168,23 @@ SDL_FRect* Box::get_rect()
|
|||
return ▭
|
||||
}
|
||||
|
||||
void Box::zero()
|
||||
SDL_Rect Box::get_int_rect()
|
||||
{
|
||||
return {static_cast<int>(rect.x), static_cast<int>(rect.y), static_cast<int>(rect.w), static_cast<int>(rect.h)};
|
||||
}
|
||||
|
||||
void Box::clear()
|
||||
{
|
||||
set_nw(glm::vec2(0, 0));
|
||||
set_size(glm::vec2(0, 0));
|
||||
}
|
||||
|
||||
void Box::scale(float amount)
|
||||
{
|
||||
set_w(get_w() * amount);
|
||||
set_h(get_h() * amount);
|
||||
}
|
||||
|
||||
void Box::move(const glm::vec2& delta)
|
||||
{
|
||||
set_x(get_x() + delta.x);
|
||||
|
|
|
@ -11,9 +11,9 @@
|
|||
|
||||
struct Box
|
||||
{
|
||||
SDL_FRect rect = {0, 0, 0, 0};
|
||||
SDL_FRect rect;
|
||||
|
||||
Box(glm::vec2 = {0, 0}, glm::vec2 = {0, 0});
|
||||
Box(const glm::vec2& = {0, 0}, const glm::vec2& = {0, 0});
|
||||
float get_x() const;
|
||||
float get_y() const;
|
||||
float get_w() const;
|
||||
|
@ -47,7 +47,9 @@ struct Box
|
|||
void set_west(const glm::vec2&);
|
||||
void set_center(const glm::vec2&);
|
||||
SDL_FRect* get_rect();
|
||||
void zero();
|
||||
SDL_Rect get_int_rect();
|
||||
void clear();
|
||||
void scale(float);
|
||||
void move(const glm::vec2&);
|
||||
std::string get_class_name() { return "Box"; }
|
||||
std::ostream& to_string (std::ostream&) const;
|
||||
|
|
|
@ -38,14 +38,16 @@ void Display::get_screen_pixels(unsigned char* pixels, int w, int h, int x, int
|
|||
}
|
||||
else
|
||||
{
|
||||
Uint32 format;
|
||||
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
|
||||
format = SDL_PIXELFORMAT_ARGB8888;
|
||||
#else
|
||||
format = SDL_PIXELFORMAT_ABGR8888;
|
||||
#endif
|
||||
// Uint32 format;
|
||||
// #if SDL_BYTEORDER == SDL_BIG_ENDIAN
|
||||
// format = SDL_PIXELFORMAT_ARGB8888;
|
||||
// #else
|
||||
// format = SDL_PIXELFORMAT_ABGR8888;
|
||||
// #endif
|
||||
SDL_SetRenderTarget(get_root()->renderer, NULL);
|
||||
SDL_RenderPresent(get_root()->renderer);
|
||||
SDL_RenderReadPixels(
|
||||
get_root()->renderer, NULL, format, pixels, bpp / 8 * w);
|
||||
get_root()->renderer, NULL, SDL_PIXELFORMAT_RGBA32, pixels, bpp / 8 * w);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
48
src/Game.cpp
48
src/Game.cpp
|
@ -40,7 +40,7 @@ void FramerateIndicator::refresh()
|
|||
SDL_Texture* texture = SDL_CreateTextureFromSurface(get_root()->get_renderer(), surface);
|
||||
add_frame(texture);
|
||||
SDL_FreeSurface(surface);
|
||||
box.set_ne(get_display().get_window_box().get_ne());
|
||||
set_ne(get_display().get_window_box().get_ne());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -136,14 +136,14 @@ Game::~Game()
|
|||
get_delegate().unsubscribe(this);
|
||||
}
|
||||
|
||||
void Game::print_error(std::string message)
|
||||
void Game::print_error(const std::string& message)
|
||||
{
|
||||
std::cerr << message << std::endl;
|
||||
sfw::print_error(message);
|
||||
}
|
||||
|
||||
void Game::print_sdl_error(std::string message)
|
||||
void Game::print_sdl_error(const std::string& message)
|
||||
{
|
||||
std::cerr << message << " " << SDL_GetError() << std::endl;
|
||||
sfw::print_sdl_error(message);
|
||||
}
|
||||
|
||||
void Game::print_gl_attributes()
|
||||
|
@ -177,7 +177,8 @@ void Game::load_sdl_context()
|
|||
SDL_GL_DeleteContext(glcontext);
|
||||
glcontext = NULL;
|
||||
}
|
||||
if ((renderer = SDL_CreateRenderer(window, -1, 0)) == NULL)
|
||||
if ((renderer = SDL_CreateRenderer(
|
||||
window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE)) == NULL)
|
||||
{
|
||||
print_sdl_error("Could not create renderer");
|
||||
flag_to_end();
|
||||
|
@ -463,10 +464,10 @@ void Game::run()
|
|||
emscripten_set_main_loop_arg(&loop, this, -1, true);
|
||||
#else
|
||||
SDL_Log("using standard main loop");
|
||||
while (not done)
|
||||
while (!done)
|
||||
{
|
||||
frame(SDL_GetTicks());
|
||||
SDL_Delay(8);
|
||||
SDL_Delay(0);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -476,6 +477,7 @@ void Game::frame(float ticks)
|
|||
// std::cout << "frame_length: " << frame_length << ", ticks: " << ticks << ", last_frame_timestamp: " << last_frame_timestamp <<
|
||||
// ", frame_time_overflow: " << frame_time_overflow;
|
||||
if (ticks - last_frame_timestamp + frame_time_overflow >= frame_length)
|
||||
// if (ticks - last_frame_timestamp >= frame_length)
|
||||
{
|
||||
last_frame_length = ticks - last_frame_timestamp;
|
||||
if (frame_length_history.size() == 5000)
|
||||
|
@ -486,20 +488,26 @@ void Game::frame(float ticks)
|
|||
frame_time_overflow = last_frame_length + frame_time_overflow - frame_length;
|
||||
last_frame_timestamp = ticks;
|
||||
// std::cout << ", last_frame_length: " << last_frame_length << " [rendering frame]";
|
||||
recorder.update();
|
||||
delegate.dispatch();
|
||||
get_root()->input.unsuppress_animation.update();
|
||||
update();
|
||||
framerate_indicator.update();
|
||||
if (!is_gl_context)
|
||||
if (last_frame_length < 1000)
|
||||
{
|
||||
SDL_RenderPresent(renderer);
|
||||
}
|
||||
if (frame_time_overflow > frame_length)
|
||||
{
|
||||
// SDL_Log("%i frame(s) dropped", ((int) (frame_time_overflow / frame_length)));
|
||||
frame_time_overflow = 0;
|
||||
if (!is_gl_context)
|
||||
{
|
||||
recorder.update();
|
||||
}
|
||||
delegate.dispatch();
|
||||
get_root()->input.unsuppress_animation.update();
|
||||
update();
|
||||
framerate_indicator.update();
|
||||
if (!is_gl_context)
|
||||
{
|
||||
SDL_RenderPresent(renderer);
|
||||
}
|
||||
}
|
||||
// if (frame_time_overflow > frame_length)
|
||||
// {
|
||||
// // SDL_Log("%i frame(s) dropped", ((int) (frame_time_overflow / frame_length)));
|
||||
// frame_time_overflow = 0;
|
||||
// }
|
||||
frame_count_this_second++;
|
||||
if (ticks - last_frame_count_timestamp >= 1000)
|
||||
{
|
||||
|
|
|
@ -67,8 +67,8 @@ struct Game : Node
|
|||
|
||||
Game();
|
||||
~Game();
|
||||
void print_error(std::string);
|
||||
void print_sdl_error(std::string);
|
||||
void print_error(const std::string&);
|
||||
void print_sdl_error(const std::string&);
|
||||
void print_gl_attributes();
|
||||
void print_frame_length_history();
|
||||
void load_sdl_context();
|
||||
|
@ -92,6 +92,7 @@ struct Game : Node
|
|||
template<typename T>
|
||||
float weight(T amount)
|
||||
{
|
||||
// std::cout << amount << " - " << last_frame_length << std::endl;
|
||||
return (last_frame_length / (1000.0 / 60)) * amount;
|
||||
}
|
||||
|
||||
|
|
194
src/Sprite.cpp
194
src/Sprite.cpp
|
@ -109,9 +109,41 @@ Frameset& Sprite::get_current_frameset()
|
|||
return framesets[current_frameset_name];
|
||||
}
|
||||
|
||||
Box& Sprite::get_box(int index)
|
||||
{
|
||||
return boxes[index];
|
||||
}
|
||||
|
||||
void Sprite::add_box(glm::vec2 position, bool absolute)
|
||||
{
|
||||
if (!absolute)
|
||||
{
|
||||
position += get_nw();
|
||||
}
|
||||
boxes.emplace_back(glm::vec2(position.x, position.y), glm::vec2(get_w(), get_h()));
|
||||
}
|
||||
|
||||
void Sprite::update_size()
|
||||
{
|
||||
box.set_size(get_current_frameset().get_size());
|
||||
for (Box& box : boxes)
|
||||
{
|
||||
box.set_size(get_current_frameset().get_size());
|
||||
}
|
||||
}
|
||||
|
||||
void Sprite::set_scale(float s)
|
||||
{
|
||||
scale = s;
|
||||
for (auto& member : framesets)
|
||||
{
|
||||
member.second.set_size(member.second.get_size() * s);
|
||||
}
|
||||
update_size();
|
||||
}
|
||||
|
||||
float Sprite::get_scale() const
|
||||
{
|
||||
return scale;
|
||||
}
|
||||
|
||||
bool Sprite::is_loaded() const
|
||||
|
@ -126,7 +158,10 @@ void Sprite::unload()
|
|||
SDL_DestroyTexture(frames.back());
|
||||
frames.pop_back();
|
||||
}
|
||||
box.zero();
|
||||
for (Box& box : boxes)
|
||||
{
|
||||
box.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void Sprite::advance_frame()
|
||||
|
@ -160,69 +195,156 @@ void Sprite::set_step(glm::vec2 s)
|
|||
step.y = s.y;
|
||||
}
|
||||
|
||||
float Sprite::get_w() const
|
||||
void Sprite::set_alpha_mod(Uint8 mod)
|
||||
{
|
||||
return box.get_w();
|
||||
alpha_mod = mod;
|
||||
}
|
||||
|
||||
float Sprite::get_h() const
|
||||
Uint8 Sprite::get_alpha_mod() const
|
||||
{
|
||||
return box.get_h();
|
||||
return alpha_mod;
|
||||
}
|
||||
|
||||
glm::vec2 Sprite::get_size() const
|
||||
float Sprite::get_w()
|
||||
{
|
||||
return box.get_size();
|
||||
return get_box().get_w();
|
||||
}
|
||||
|
||||
float Sprite::get_top() const
|
||||
float Sprite::get_h()
|
||||
{
|
||||
return box.get_top();
|
||||
return get_box().get_h();
|
||||
}
|
||||
|
||||
float Sprite::get_right() const
|
||||
glm::vec2 Sprite::get_size()
|
||||
{
|
||||
return box.get_right();
|
||||
return get_box().get_size();
|
||||
}
|
||||
|
||||
float Sprite::get_bottom() const
|
||||
float Sprite::get_top(int index)
|
||||
{
|
||||
return box.get_bottom();
|
||||
return get_box(index).get_top();
|
||||
}
|
||||
|
||||
float Sprite::get_left() const
|
||||
float Sprite::get_right(int index)
|
||||
{
|
||||
return box.get_left();
|
||||
return get_box(index).get_right();
|
||||
}
|
||||
|
||||
glm::vec2 Sprite::get_nw() const
|
||||
float Sprite::get_bottom(int index)
|
||||
{
|
||||
return box.get_nw();
|
||||
return get_box(index).get_bottom();
|
||||
}
|
||||
|
||||
glm::vec2 Sprite::get_north() const
|
||||
float Sprite::get_left(int index)
|
||||
{
|
||||
return box.get_north();
|
||||
return get_box(index).get_left();
|
||||
}
|
||||
|
||||
glm::vec2 Sprite::get_west() const
|
||||
glm::vec2 Sprite::get_nw(int index)
|
||||
{
|
||||
return box.get_west();
|
||||
return get_box(index).get_nw();
|
||||
}
|
||||
|
||||
glm::vec2 Sprite::get_north(int index)
|
||||
{
|
||||
return get_box(index).get_north();
|
||||
}
|
||||
|
||||
glm::vec2 Sprite::get_ne(int index)
|
||||
{
|
||||
return get_box(index).get_ne();
|
||||
}
|
||||
|
||||
glm::vec2 Sprite::get_east(int index)
|
||||
{
|
||||
return get_box(index).get_east();
|
||||
}
|
||||
|
||||
glm::vec2 Sprite::get_west(int index)
|
||||
{
|
||||
return get_box(index).get_west();
|
||||
}
|
||||
|
||||
glm::vec2 Sprite::get_center(int index)
|
||||
{
|
||||
return get_box(index).get_center();
|
||||
}
|
||||
|
||||
void Sprite::set_nw(const glm::vec2& nw)
|
||||
{
|
||||
box.set_nw(nw);
|
||||
move(nw - get_nw(), false);
|
||||
}
|
||||
|
||||
void Sprite::move(glm::vec2 delta, bool weighted)
|
||||
void Sprite::set_ne(const glm::vec2& ne)
|
||||
{
|
||||
move(ne - get_ne(), false);
|
||||
}
|
||||
|
||||
void Sprite::set_center(const glm::vec2& center)
|
||||
{
|
||||
move(center - get_center(), false);
|
||||
}
|
||||
|
||||
void Sprite::add_wrap(bool x, bool y)
|
||||
{
|
||||
add_wrap(x, y, get_display().get_window_box());
|
||||
}
|
||||
|
||||
void Sprite::add_wrap(bool x, bool y, Box frame)
|
||||
{
|
||||
wrap = {x, y};
|
||||
int original_box_count = boxes.size();
|
||||
for (int ii = 0; ii < original_box_count; ii++)
|
||||
{
|
||||
if (x)
|
||||
{
|
||||
add_box({frame.get_w(), 0});
|
||||
}
|
||||
if (y)
|
||||
{
|
||||
add_box({0, frame.get_h()});
|
||||
}
|
||||
if (x && y)
|
||||
{
|
||||
add_box({frame.get_w(), frame.get_h()});
|
||||
}
|
||||
}
|
||||
wrap_frame = frame;
|
||||
}
|
||||
|
||||
glm::vec2 Sprite::move(glm::vec2 delta, bool weighted)
|
||||
{
|
||||
Game *game = get_root();
|
||||
if (weighted)
|
||||
{
|
||||
delta = game->weight(delta);
|
||||
delta = get_root()->weight(delta);
|
||||
}
|
||||
box.move(delta);
|
||||
for (Box& box : boxes)
|
||||
{
|
||||
box.move(delta);
|
||||
}
|
||||
if (wrap.x)
|
||||
{
|
||||
if (get_right() > wrap_frame.get_right())
|
||||
{
|
||||
move({-wrap_frame.get_w(), 0}, false);
|
||||
}
|
||||
else if (get_right() < wrap_frame.get_left())
|
||||
{
|
||||
move({wrap_frame.get_w(), 0}, false);
|
||||
}
|
||||
}
|
||||
if (wrap.y)
|
||||
{
|
||||
if (get_bottom() > wrap_frame.get_bottom())
|
||||
{
|
||||
move({0, -wrap_frame.get_h()}, false);
|
||||
}
|
||||
else if (get_bottom() < wrap_frame.get_top())
|
||||
{
|
||||
move({0, wrap_frame.get_h()}, false);
|
||||
}
|
||||
}
|
||||
return delta;
|
||||
}
|
||||
|
||||
void Sprite::update()
|
||||
|
@ -239,7 +361,19 @@ void Sprite::update()
|
|||
SDL_Renderer* renderer = get_root()->renderer;
|
||||
SDL_SetTextureAlphaMod(texture, alpha_mod);
|
||||
SDL_SetRenderTarget(renderer, NULL);
|
||||
SDL_RenderCopyF(renderer, texture, NULL, box.get_rect());
|
||||
if (wrap.x || wrap.y)
|
||||
{
|
||||
SDL_Rect wrap_frame_rect = wrap_frame.get_int_rect();
|
||||
SDL_RenderSetClipRect(renderer, &wrap_frame_rect);
|
||||
}
|
||||
for (Box& box : boxes)
|
||||
{
|
||||
SDL_RenderCopyF(renderer, texture, NULL, box.get_rect());
|
||||
}
|
||||
if (wrap.x || wrap.y)
|
||||
{
|
||||
SDL_RenderSetClipRect(renderer, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -293,8 +427,8 @@ glm::vec2 Frameset::measure() const
|
|||
if (index < sprite->frames.size())
|
||||
{
|
||||
SDL_QueryTexture(sprite->frames[index], NULL, NULL, &w, &h);
|
||||
s.x = std::max(static_cast<float>(w), s.x);
|
||||
s.y = std::max(static_cast<float>(h), s.y);
|
||||
s.x = std::max(static_cast<float>(w * sprite->scale), s.x);
|
||||
s.y = std::max(static_cast<float>(h * sprite->scale), s.y);
|
||||
}
|
||||
}
|
||||
return s;
|
||||
|
|
|
@ -23,14 +23,17 @@ struct Sprite : Node
|
|||
|
||||
std::vector<SDL_Texture*> frames;
|
||||
std::vector<fs::path> frame_paths;
|
||||
Box box;
|
||||
std::vector<Box> boxes = {{{0, 0}, {0, 0}}};
|
||||
Animation frame_animation = Animation(&Sprite::advance_frame, this);
|
||||
Animation blink_animation = Animation(&Sprite::toggle_hidden, this, 500);
|
||||
bool hidden = false;
|
||||
glm::vec2 step = {0, 0};
|
||||
float scale = 1;
|
||||
Uint8 alpha_mod = 255;
|
||||
std::map<std::string, Frameset> framesets;
|
||||
std::string current_frameset_name;
|
||||
glm::bvec2 wrap = {false, false};
|
||||
Box wrap_frame;
|
||||
|
||||
Sprite();
|
||||
Sprite(Node*);
|
||||
|
@ -44,7 +47,11 @@ struct Sprite : Node
|
|||
Frameset& add_frameset(std::string);
|
||||
void set_frameset(std::string);
|
||||
Frameset& get_current_frameset();
|
||||
Box& get_box(int = 0);
|
||||
void add_box(glm::vec2, bool = false);
|
||||
void update_size();
|
||||
void set_scale(float);
|
||||
float get_scale() const;
|
||||
bool is_loaded() const;
|
||||
void unload();
|
||||
void advance_frame();
|
||||
|
@ -53,18 +60,27 @@ struct Sprite : Node
|
|||
void toggle_hidden();
|
||||
bool is_hidden() const;
|
||||
void set_step(glm::vec2);
|
||||
float get_w() const;
|
||||
float get_h() const;
|
||||
glm::vec2 get_size() const;
|
||||
float get_top() const;
|
||||
float get_right() const;
|
||||
float get_bottom() const;
|
||||
float get_left() const;
|
||||
glm::vec2 get_nw() const;
|
||||
glm::vec2 get_north() const;
|
||||
glm::vec2 get_west() const;
|
||||
void set_alpha_mod(Uint8);
|
||||
Uint8 get_alpha_mod() const;
|
||||
float get_w();
|
||||
float get_h();
|
||||
glm::vec2 get_size();
|
||||
float get_top(int = 0);
|
||||
float get_right(int = 0);
|
||||
float get_bottom(int = 0);
|
||||
float get_left(int = 0);
|
||||
glm::vec2 get_nw(int = 0);
|
||||
glm::vec2 get_north(int = 0);
|
||||
glm::vec2 get_ne(int = 0);
|
||||
glm::vec2 get_east(int = 0);
|
||||
glm::vec2 get_west(int = 0);
|
||||
glm::vec2 get_center(int = 0);
|
||||
void set_nw(const glm::vec2&);
|
||||
void move(glm::vec2, bool = true);
|
||||
void set_ne(const glm::vec2&);
|
||||
void set_center(const glm::vec2&);
|
||||
void add_wrap(bool, bool);
|
||||
void add_wrap(bool, bool, Box);
|
||||
glm::vec2 move(glm::vec2, bool = true);
|
||||
void update();
|
||||
std::string get_class_name() { return "Sprite"; }
|
||||
~Sprite() { unload(); }
|
||||
|
|
|
@ -40,16 +40,220 @@ void sfw::fill_texture(SDL_Renderer* renderer, SDL_Texture* texture, SDL_Texture
|
|||
}
|
||||
}
|
||||
|
||||
SDL_Texture* sfw::duplicate_texture(SDL_Renderer* renderer, SDL_Texture* texture)
|
||||
SDL_Texture* sfw::duplicate_texture(SDL_Renderer* renderer, SDL_Texture* base, Uint32 format)
|
||||
{
|
||||
Box box = get_texture_box(texture);
|
||||
SDL_Texture* duplicate = SDL_CreateTexture(
|
||||
renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, box.get_w(), box.get_h());
|
||||
SDL_SetRenderTarget(renderer, duplicate);
|
||||
SDL_RenderCopyF(renderer, texture, NULL, NULL);
|
||||
Box box = get_texture_box(base);
|
||||
SDL_Texture* duplicate = SDL_CreateTexture(renderer, format, SDL_TEXTUREACCESS_TARGET, box.get_w(), box.get_h());
|
||||
if (duplicate == NULL)
|
||||
{
|
||||
print_sdl_error("could not create texture from base");
|
||||
return NULL;
|
||||
}
|
||||
if ((SDL_SetRenderTarget(renderer, duplicate)) < 0)
|
||||
{
|
||||
print_sdl_error("could not set render target to duplicate");
|
||||
return NULL;
|
||||
}
|
||||
if ((SDL_RenderCopyF(renderer, base, NULL, NULL)) < 0)
|
||||
{
|
||||
print_sdl_error("could not render base onto duplicate");
|
||||
return NULL;
|
||||
}
|
||||
return duplicate;
|
||||
}
|
||||
|
||||
SDL_Texture* sfw::get_remapped_texture(
|
||||
SDL_Renderer* renderer, SDL_Texture* base, const std::map<SDL_Color, SDL_Color>& map, Uint32 format)
|
||||
{
|
||||
SDL_Texture* remapped = duplicate_texture(renderer, base, format);
|
||||
if (remapped == NULL)
|
||||
{
|
||||
print_sdl_error("could not duplicate base texture");
|
||||
return NULL;
|
||||
}
|
||||
if ((SDL_SetRenderTarget(renderer, remapped)) < 0)
|
||||
{
|
||||
print_sdl_error("could not set render target to remapped texture");
|
||||
return NULL;
|
||||
}
|
||||
Box box = get_texture_box(remapped);
|
||||
int bytes_per_pixel = SDL_BYTESPERPIXEL(format);
|
||||
int bytes_total = bytes_per_pixel * box.get_w() * box.get_h();
|
||||
unsigned char* pixels = new unsigned char[bytes_total];
|
||||
if ((SDL_RenderReadPixels(renderer, NULL, format, pixels, bytes_total / box.get_h())) < 0)
|
||||
{
|
||||
print_sdl_error("could not read pixels after setting remapped texture as target");
|
||||
return NULL;
|
||||
}
|
||||
SDL_Color color;
|
||||
for (int ii = 0; ii < bytes_total; ii += bytes_per_pixel)
|
||||
{
|
||||
color = {pixels[ii], pixels[ii + 1], pixels[ii + 2], 255};
|
||||
if (bytes_per_pixel == 4)
|
||||
{
|
||||
color.a = pixels[ii + 3];
|
||||
}
|
||||
for (auto& pair : map)
|
||||
{
|
||||
if (color.r == pair.first.r && color.g == pair.first.g && color.b == pair.first.b &&
|
||||
(bytes_per_pixel < 4 || color.a == pair.first.a))
|
||||
{
|
||||
pixels[ii] = pair.second.r;
|
||||
pixels[ii + 1] = pair.second.g;
|
||||
pixels[ii + 2] = pair.second.b;
|
||||
if (bytes_per_pixel == 4)
|
||||
{
|
||||
pixels[ii + 3] = pair.second.a;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (SDL_UpdateTexture(remapped, NULL, pixels, bytes_total / box.get_h()) < 0)
|
||||
{
|
||||
print_sdl_error("could not update remapped texture");
|
||||
}
|
||||
delete[] pixels;
|
||||
return remapped;
|
||||
}
|
||||
|
||||
SDL_Texture* sfw::get_remapped_texture(
|
||||
SDL_Renderer* renderer, const std::string& path, const std::map<SDL_Color, SDL_Color>& map, Uint32 format)
|
||||
{
|
||||
SDL_Texture* base = IMG_LoadTexture(renderer, path.c_str());
|
||||
if (base == NULL)
|
||||
{
|
||||
print_sdl_error("error loading file");
|
||||
return NULL;
|
||||
}
|
||||
SDL_Texture* remapped = get_remapped_texture(renderer, base, map, format);
|
||||
if (remapped == NULL)
|
||||
{
|
||||
print_error("could not remap texture");
|
||||
return NULL;
|
||||
}
|
||||
SDL_DestroyTexture(base);
|
||||
return remapped;
|
||||
}
|
||||
|
||||
#include "superxbr.cpp"
|
||||
#include "hq2x.c"
|
||||
|
||||
/*
|
||||
Base texture must be set to SDL_TEXTUREACCESS_TARGET
|
||||
|
||||
Scale2x implementation based on the explanation at http://www.scale2x.it/algorithm.html
|
||||
*/
|
||||
SDL_Texture* sfw::get_pixel_scaled_texture(SDL_Renderer* renderer, SDL_Texture* base, int count, int version)
|
||||
{
|
||||
if ((SDL_SetRenderTarget(renderer, base)) < 0)
|
||||
{
|
||||
print_sdl_error("could not set render target to remapped texture");
|
||||
return NULL;
|
||||
}
|
||||
glm::ivec2 size = get_texture_box(base).get_size();
|
||||
Uint32 format = SDL_PIXELFORMAT_RGBA32;
|
||||
int bytes_per_pixel, bytes_per_row, bytes_total;
|
||||
Uint32 *src, *dst, *src_begin, *dst_begin;
|
||||
for (int ii = 0; ii < count; ii++, size *= 2)
|
||||
{
|
||||
bytes_per_pixel = SDL_BYTESPERPIXEL(format);
|
||||
bytes_per_row = bytes_per_pixel * size.x;
|
||||
bytes_total = bytes_per_row * size.y;
|
||||
if (ii == 0)
|
||||
{
|
||||
src = new Uint32[size.x * size.y];
|
||||
src_begin = src;
|
||||
if ((SDL_RenderReadPixels(renderer, NULL, format, src, bytes_per_row)) < 0)
|
||||
{
|
||||
print_sdl_error("could not read pixels after setting remapped texture as target");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
src = dst_begin;
|
||||
src_begin = src;
|
||||
}
|
||||
dst = new Uint32[size.x * size.y * 4];
|
||||
dst_begin = dst;
|
||||
if (version == scaler::scale2x)
|
||||
{
|
||||
Uint32 A, B, C, D, E, F, G, H, I;
|
||||
for (int y = 0; y < size.y; y++)
|
||||
{
|
||||
for (int x = 0; x < size.x; x++)
|
||||
{
|
||||
E = *src;
|
||||
B = y == 0 ? E : *(src - size.x);
|
||||
D = x == 0 ? E : *(src - 1);
|
||||
F = x == size.x - 1 ? E : *(src + 1);
|
||||
H = y == size.y - 1 ? E : *(src + size.x);
|
||||
if (y != 0 && x != 0 && y != size.y - 1 && x != size.x - 1)
|
||||
{
|
||||
A = *(src - size.x - 1);
|
||||
C = *(src - size.x + 1);
|
||||
G = *(src + size.x - 1);
|
||||
I = *(src + size.x + 1);
|
||||
}
|
||||
if (x == 0)
|
||||
{
|
||||
A = B;
|
||||
G = H;
|
||||
}
|
||||
if (y == 0)
|
||||
{
|
||||
A = D;
|
||||
C = F;
|
||||
}
|
||||
if (x == size.x - 1)
|
||||
{
|
||||
C = B;
|
||||
I = H;
|
||||
}
|
||||
if (y == size.y - 1)
|
||||
{
|
||||
G = D;
|
||||
I = F;
|
||||
}
|
||||
if (B != H && D != F)
|
||||
{
|
||||
*dst = D == B ? D : E;
|
||||
*(dst + 1) = B == F ? F : E;
|
||||
*(dst + 2 * size.x) = D == H ? D : E;
|
||||
*(dst + 2 * size.x + 1) = H == F ? F : E;
|
||||
}
|
||||
else
|
||||
{
|
||||
*dst = E;
|
||||
*(dst + 1) = E;
|
||||
*(dst + 2 * size.x) = E;
|
||||
*(dst + 2 * size.x + 1) = E;
|
||||
}
|
||||
src++;
|
||||
dst += 2;
|
||||
}
|
||||
dst += 2 * size.x;
|
||||
}
|
||||
}
|
||||
else if (version == scaler::xbr)
|
||||
{
|
||||
scaleSuperXBRT<2>(src, dst, size.x, size.y);
|
||||
}
|
||||
delete[] src_begin;
|
||||
}
|
||||
SDL_Texture* scaled = SDL_CreateTexture(renderer, format, SDL_TEXTUREACCESS_TARGET, size.x, size.y);
|
||||
if (scaled == NULL)
|
||||
{
|
||||
print_sdl_error("could not create scaled texture");
|
||||
}
|
||||
if (SDL_UpdateTexture(scaled, NULL, dst_begin, bytes_per_row * 2) < 0)
|
||||
{
|
||||
print_sdl_error("could not copy pixels to scaled texture");
|
||||
}
|
||||
delete[] dst_begin;
|
||||
return scaled;
|
||||
}
|
||||
|
||||
std::vector<fs::path> sfw::glob(fs::path query)
|
||||
{
|
||||
fs::path basename = query.parent_path();
|
||||
|
@ -98,8 +302,34 @@ fs::path sfw::get_next_file_name(
|
|||
return path;
|
||||
}
|
||||
|
||||
void sfw::print_error(const std::string& message)
|
||||
{
|
||||
std::cerr << message << std::endl;
|
||||
}
|
||||
|
||||
void sfw::print_sdl_error(const std::string& message)
|
||||
{
|
||||
std::cerr << message << " " << SDL_GetError() << std::endl;
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& out, const glm::vec2& vector)
|
||||
{
|
||||
out << "{" << vector.x << ", " << vector.y << "}";
|
||||
return out;
|
||||
}
|
||||
|
||||
bool operator<(const SDL_Color& color_1, const SDL_Color& color_2)
|
||||
{
|
||||
return color_1.r < color_2.r || color_1.g < color_2.g || color_1.b < color_2.b || color_1.a < color_2.a;
|
||||
}
|
||||
|
||||
bool operator==(const SDL_Color& color_1, const SDL_Color& color_2)
|
||||
{
|
||||
return color_1.r == color_2.r && color_1.g == color_2.g && color_1.b == color_2.b && color_1.a == color_2.a;
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& out, const SDL_Color& color)
|
||||
{
|
||||
out << "{" << color.r << ", " << color.g << ", " << color.b << ", " << color.a << "}";
|
||||
return out;
|
||||
}
|
||||
|
|
|
@ -8,28 +8,41 @@
|
|||
#include <algorithm>
|
||||
#include <iomanip>
|
||||
#include <stdexcept>
|
||||
#include <map>
|
||||
|
||||
#include "SDL.h"
|
||||
#include "SDL_image.h"
|
||||
|
||||
#define GLM_ENABLE_EXPERIMENTAL
|
||||
#include "glm/trigonometric.hpp"
|
||||
#include "glm/vec2.hpp"
|
||||
#include "glm/gtx/vector_angle.hpp"
|
||||
|
||||
#include "SDL.h"
|
||||
|
||||
#include "Box.hpp"
|
||||
#include "Color.hpp"
|
||||
#include "filesystem.hpp"
|
||||
|
||||
namespace sfw
|
||||
{
|
||||
enum scaler {scale2x, xbr};
|
||||
|
||||
glm::vec2 get_step(glm::vec2, glm::vec2, float);
|
||||
void set_magnitude(glm::vec2&, float);
|
||||
Box get_texture_box(SDL_Texture*);
|
||||
void fill_texture(SDL_Renderer*, SDL_Texture*, int, int, int, int = 0xff);
|
||||
void fill_texture(SDL_Renderer*, SDL_Texture*, SDL_Texture*);
|
||||
SDL_Texture* duplicate_texture(SDL_Renderer*, SDL_Texture*);
|
||||
SDL_Texture* duplicate_texture(SDL_Renderer*, SDL_Texture*, Uint32 = SDL_PIXELFORMAT_RGBA32);
|
||||
SDL_Texture* get_remapped_texture(
|
||||
SDL_Renderer*, SDL_Texture*, const std::map<SDL_Color, SDL_Color>&, Uint32 = SDL_PIXELFORMAT_RGBA32);
|
||||
SDL_Texture* get_remapped_texture(
|
||||
SDL_Renderer*, const std::string&, const std::map<SDL_Color, SDL_Color>&,
|
||||
Uint32 = SDL_PIXELFORMAT_RGBA32);
|
||||
SDL_Texture* get_pixel_scaled_texture(SDL_Renderer*, SDL_Texture*, int = 1, int = scaler::scale2x);
|
||||
std::vector<fs::path> glob(fs::path);
|
||||
fs::path get_next_file_name(
|
||||
fs::path, int = 0, std::string = "", std::string = "");
|
||||
void print_error(const std::string&);
|
||||
void print_sdl_error(const std::string&);
|
||||
|
||||
template<typename T1, typename T2>
|
||||
bool is_in_container(T1& container, T2& member)
|
||||
|
@ -81,5 +94,8 @@ namespace sfw
|
|||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream&, const glm::vec2&);
|
||||
bool operator<(const SDL_Color& color_1, const SDL_Color& color_2);
|
||||
bool operator==(const SDL_Color& color_1, const SDL_Color& color_2);
|
||||
std::ostream& operator<<(std::ostream&, const SDL_Color&);
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue