Created
December 9, 2016 13:37
-
-
Save Shtille/b4ceac8a7a05d3b1f6838c82e7963082 to your computer and use it in GitHub Desktop.
Make POT bitmap from NPOT bitmap using bilinear interpolation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
template <typename T> | |
static T RoundToPowerOfTwo(T x) | |
{ | |
T n = 1; | |
while (n < x) | |
n <<= 1; | |
return n; | |
} | |
static int InterpolateColor(int c1, int c2, float alpha) | |
{ | |
int a1 = (c1 & 0xff000000) >> 24; | |
int b1 = (c1 & 0xff0000) >> 16; | |
int g1 = (c1 & 0x00ff00) >> 8; | |
int r1 = (c1 & 0x0000ff); | |
int a2 = (c2 & 0xff000000) >> 24; | |
int b2 = (c2 & 0xff0000) >> 16; | |
int g2 = (c2 & 0x00ff00) >> 8; | |
int r2 = (c2 & 0x0000ff); | |
int r = r1 + (int)((r2-r1)*alpha); | |
int g = g1 + (int)((g2-g1)*alpha); | |
int b = b1 + (int)((b2-b1)*alpha); | |
int a = a1 + (int)((a2-a1)*alpha); | |
return (a << 24) | (b << 16) | (g << 8) | r; | |
} | |
static void MakePotTextureFromNpot(int& width, int& height, std::vector<unsigned char>& vdata) | |
{ | |
if (((width & (width-1)) != 0) || ((height & (height-1)) != 0)) | |
{ | |
// Need to make POT | |
unsigned int * data = reinterpret_cast<unsigned int*>(&vdata[0]); | |
int w2 = RoundToPowerOfTwo(width); | |
int h2 = RoundToPowerOfTwo(height); | |
// Rescale image to power of 2 | |
int new_size = w2 * h2; | |
std::vector<unsigned char> new_vdata; | |
new_vdata.resize(new_size*4); | |
unsigned int * new_data = reinterpret_cast<unsigned int*>(&new_vdata[0]); | |
for (int dh2 = 0; dh2 < h2; ++dh2) | |
{ | |
float rh = (float)dh2 / (float)h2; | |
float y = rh * (float)height; | |
int dh = (int)y; | |
int dh1 = std::min<int>(dh+1, height-1); | |
float ry = y - (float)dh; // fract part of y | |
for (int dw2 = 0; dw2 < w2; ++dw2) | |
{ | |
float rw = (float)dw2 / (float)w2; | |
float x = rw * (float)width; | |
int dw = (int)x; | |
int dw1 = std::min<int>(dw+1, width-1); | |
float rx = x - (float)dw; // fract part of x | |
// We will use bilinear interpolation | |
int sample1 = (int) data[dw +width*dh ]; | |
int sample2 = (int) data[dw1+width*dh ]; | |
int sample3 = (int) data[dw +width*dh1]; | |
int sample4 = (int) data[dw1+width*dh1]; | |
int color1 = InterpolateColor(sample1, sample2, rx); | |
int color2 = InterpolateColor(sample3, sample4, rx);; | |
int color3 = InterpolateColor(color1, color2, ry); | |
new_data[dw2+w2*dh2] = (unsigned int)color3; | |
} | |
} | |
// Finally | |
width = w2; | |
height = h2; | |
vdata.swap(new_vdata); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment