Hello, i'm a new programmer. I've been trying to implement bi-linear interpolation for image scaling. For starters this is what it looks like with nearest neighbour:
(I haven't spent much time in getting the colours right).
So I scaled a 32x32 pixels by 2 to 64x64 like so:
This prints every perlin noise value for every even x,y coordinate pixel and just a black one for anything else. It uses sf::RectangleShape to draw the pixels. I'm trying to replace the black ones using bilinear interpolation.
For bi-linear I had a read of the wikipedia page
https://en.wikipedia.org/wiki/Bilinear_interpolation:
And implemented this using float values:
void getSquarePoints(sf::Vector2i& bLPos, sf::Vector2i& bRPos, sf::Vector2i& tLPos, sf::Vector2i& tRPos, int x, int y)
{
bLPos.x, tLPos.x = (x * (PIXEL_WIDTH / 2));
bRPos.x, tRPos.x = tLPos.x + (PIXEL_WIDTH / 2);
tLPos.y, tRPos.y = (x * (PIXEL_HEIGHT / 2));
bLPos.y, bRPos.y = tLPos.y + (PIXEL_HEIGHT / 2);
}
void bilinearInterpolate(sf::RectangleShape& cell, float tL, float tR, float bL, float bR, int x, int y, sf::Texture& texture, sf::RenderWindow& window)
{
sf::Image image{};
sf::Vector2i tLPos{}, tRPos{}, bLPos{}, bRPos{}; // Position for each corner. tL = top Left
// bR = bottom Right
getSquarePoints(bLPos, bRPos, tLPos, tRPos, x, y);
int totalDistanceX{ TERRAIN_SIZE / 2 }; // Size of rectangleShape in X direction
int totalDistanceY{ TERRAIN_SIZE / 2 }; // Size of rectangleShape in Y direction
image.create(totalDistanceX, totalDistanceY, sf::Color(0, 0, 0));
int differenceToLeft{}; // distance to left hand side
int differenceToRight{}; // distance to right hand side
float currentPixel{};
for (int pixelY{ tLPos.y }; pixelY < bLPos.y; ++pixelY)
{
for (int pixelX{ tLPos.x }; pixelX < tRPos.x; ++pixelX)
{
differenceToLeft = pixelX - tLPos.x;
differenceToRight = tRPos.x - pixelX;
//vertical
int differenceToTop{ tLPos.y - pixelY };
int differenceToBottom{ pixelY - bLPos.y };
float rTop = (float)(tL * differenceToRight + (tR * differenceToLeft)) / totalDistanceX;
float rBot = (float)(bL * differenceToRight + (bR * differenceToLeft)) / totalDistanceX;
currentPixel = (float)(rBot * differenceToTop + rTop * differenceToBottom) / totalDistanceY;
image.setPixel(pixelX, pixelY, FloatToTerrainColor(currentPixel));
}
}
texture.update(image);
cell.setTexture(&texture);
}
void drawNoise2d(float noise[], sf::RenderWindow& window, sf::Texture& texture)
{
sf::Color color{};
sf::RectangleShape cell{ sf::Vector2f(TERRAIN_SIZE / 2, TERRAIN_SIZE / 2) };
float pixel_w{ 0 };
for (int y{ 0 }; y < TERRAIN_SIZE * 2; ++y)
{
for (int x{ 0 }; x < TERRAIN_SIZE * 2; ++x)
{
//Even x,y coords(already colored)
if (x % 2 == 0 && y % 2 == 0)
{
pixel_w = noise[(y * TERRAIN_SIZE + x) / 32];
color = FloatToTerrainColor(pixel_w);
cell.setFillColor(color);
}
// These in between the even x,y coords
else if (x % 2 == 1 && y % 2 == 0)
{
float left{noise[(y * TERRAIN_SIZE + x - 1) / 2] };
float right{ (noise[(y * TERRAIN_SIZE + x + 1) / 2]) };
bilinearInterpolate(cell, left, right, left, right, x, y, texture, window);
}
//These are in between top and bottom of even , y coords
else if (x % 2 == 0 && y % 2 == 1)
{
float top{ noise[(y * TERRAIN_SIZE + x - TERRAIN_SIZE) / 2] };
float bot{ noise[(y * TERRAIN_SIZE + x + TERRAIN_SIZE) / 2] };
bilinearInterpolate(cell, top, top, bot, bot, x, y, texture, window);
}
// These are inbetween to the sides of even,y coords
else if (x % 2 == 1 && y % 2 == 1)
{
float topLeft{ noise[(y * TERRAIN_SIZE + x - TERRAIN_SIZE - 1) / 2] };
float topRight{ noise[(y * TERRAIN_SIZE + x - TERRAIN_SIZE + 1) / 2] };
float bottomLeft{ noise[(y * TERRAIN_SIZE + x + TERRAIN_SIZE - 1) / 2] };
float bottomRight{ noise[(y * TERRAIN_SIZE + x + TERRAIN_SIZE + 1) / 2] };
bilinearInterpolate(cell, topLeft, topRight, bottomLeft, bottomRight, x, y, texture, window);
}
cell.setPosition(x * (PIXEL_WIDTH / 2), y * (PIXEL_HEIGHT / 2));
window.draw(cell);
}
}
}
// CONSTANTS
constexpr int TERRAIN_SIZE{ 32 };
constexpr int SCREEN_WIDTH{ 1040 };
constexpr int SCREEN_HEIGHT{ 1040 };
constexpr int PIXEL_WIDTH{ SCREEN_WIDTH / TERRAIN_SIZE };
constexpr int PIXEL_HEIGHT{ SCREEN_HEIGHT / TERRAIN_SIZE };
// in int main()
float *noise = new float[TERRAIN_SIZE * TERRAIN_SIZE]{};
generateNoise2d(nOctaves, noise, terrain, scalingBias); // method to generate noise values
sf::Texture texture{};
texture.create(TERRAIN_SIZE / 2, TERRAIN_SIZE / 2);
I've done the same bilinear function using the RGB values of the noise values unlike the one above which only uses the noise values. Both have led to the screen crashing and I have been trying to debug and fix it for some hours now and at this point, I've given up. I've also tried using sf::Image which led to no success either. Any suggestions?