Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Drawing image pixels to texture then into a rectangle for bilinear interpolation  (Read 1588 times)

0 Members and 1 Guest are viewing this topic.

JohnSnow007

  • Newbie
  • *
  • Posts: 15
    • View Profile
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?
« Last Edit: October 27, 2020, 08:53:34 am by JohnSnow007 »

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Quote
Both have led to the screen crashing and I have been trying to debug and fix it for some hours
So, after some hours, you should know at least where it is crashing, and possibly have more details about the problem? Can you share that with us?
Laurent Gomila - SFML developer

JohnSnow007

  • Newbie
  • *
  • Posts: 15
    • View Profile
Quote
Both have led to the screen crashing and I have been trying to debug and fix it for some hours
So, after some hours, you should know at least where it is crashing, and possibly have more details about the problem? Can you share that with us?

Its running fine actually, however the screen is completely black. I can adjust the frequency, octaves and the scaling period but it still remains completely black. If I only use this if statements:

                        if (x % 2 == 0 && y % 2 == 0)
                        {
                                pixel_w = noise[(y * TERRAIN_SIZE + x) / 2];
                               
                        }
                        color = FloatToTerrainColor(pixel_w);
                        cell.setFillColor(color);
                        cell.setPosition(x * (PIXEL_WIDTH / 2), y * (PIXEL_HEIGHT / 2));
                        window.draw(cell);
 

It will be able to draw the squares with half the filled with color and the rest black like the image like I showed on the top.

However the other else if statements involve creating a rectangleShape, that takes a texture from an sf::Image, which has every pixel set to a color, to fill in the black squares.

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11032
    • View Profile
    • development blog
    • Email
Are you calling display() on the window?
Can you provide a complete and minimal example?
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/