SFML community forums

Help => Window => Topic started by: lucifercartwright on November 01, 2017, 06:44:16 am

Title: Get rid of letterboxing
Post by: lucifercartwright on November 01, 2017, 06:44:16 am
So currently I've got code that is able to pick a correct logical width given a fixed logical height (180px) for the game resolution. It calculates the logical width based on the screen resolution you're on and adjusts the fixed logical height.

For example..

Say I want my logical height of the game to be at 180px. The ideal logical width would be: 320px  and the ideal logical height would stay at 180px since my display resolution is set to 1920 x 1080 and it's a perfect division.

If the display resolution is 1600 x 1024, the ideal logical size would be: 266.667 x 170.667 (integer truncation to 266 x 170).

I'm just not sure how to implement it correctly. So far it works on 1920 x 1080, but if I change the display to 1600 x 1024 and go fullscreen (borderless), the screen starts flickering. I can also see (past the flickering) that there is also still letterboxing. I believe that has to do with the posX and sizeX and posY and sizeY variables, but I'm not sure how to modify those correctly (code below).

My logical width and height calculation code:
sf::Vector2<int> GameWindow::getIdealSize() {

    sf::VideoMode desktop = sf::VideoMode::getDesktopMode();

    double display_width = desktop.width;//modes[0].width;
    double display_height = desktop.height;//modes[0].height;

    double ideal_width = 0; //we need to calculate this, we won't be using this fixed value anymore
    double ideal_height = 180; //fixed height value

    double aspect_ratio = display_width / display_height;

    ideal_width = round(ideal_height * aspect_ratio);

    //Portrait (comment this out as we're using landscape mode for this game, we have a fixed ideal_height set
    //ideal_height = round(ideal_width / aspect_ratio);

    //Perfect Pixel Scaling
    if((int)display_width % (int)ideal_width != 0){
        double d = round(display_width / ideal_width);
        ideal_width = display_width / d;
    }

    if((int)display_height % (int)ideal_height != 0){
        double d = round(display_height / ideal_height);
        ideal_height = display_height / d;
    }

    //ideal_width and ideal_height must be even numbers
    if((int)ideal_width & 1){
        ideal_width+=1;
    }
    if((int)ideal_height & 1){
        ideal_height++;
    }

    cout << "display_width: " << display_width << " display_height: " << display_height << " aspect_ratio: " << aspect_ratio << " ideal_width: " << ideal_width << " ideal_height: " << ideal_height << endl;

    sf::Vector2<int> v(ideal_width, ideal_height);

    return v;
}
 

So currently to implement scaling the view I'm using the letterboxing code provided by Hapax:
https://github.com/SFML/SFML/wiki/Source%3A-Letterbox-effect-using-a-view

I'm honestly just not sure how to apply it here though. I don't know what to set sizeX and sizeY to (I'm pretty sure posX and posY would be 0). And I'm not sure why the screen flickers when I go on a lower resolution (1600x1024).

Current adjusted letterbox removal code:
sf::View GameWindow::getNoLetterboxView(sf::View view, int windowWidth, int windowHeight) {

    // Compares the aspect ratio of the window to the aspect ratio of the view,
    // and sets the view's viewport accordingly in order to archieve a letterbox effect.
    // A new view (with a new viewport set) is returned.

    float windowRatio = windowWidth / (float) windowHeight;
    float viewRatio = view.getSize().x / (float) view.getSize().y;
    float sizeX = 1;
    float sizeY = 1;
    float posX = 0;
    float posY = 0;

    bool horizontalSpacing = true;
    if (windowRatio < viewRatio)
        horizontalSpacing = false;

    // If horizontalSpacing is true, the black bars will appear on the left and right side.
    // Otherwise, the black bars will appear on the top and bottom.

    if (horizontalSpacing) {
        sizeX = viewRatio / windowRatio; //not sure what to set this to
        posX = 0;
    }

    else {
        sizeY = windowRatio / viewRatio; //not sure what to set this to
        posY = 0;
    }

    view.setViewport( sf::FloatRect(posX, posY, sizeX, sizeY) );

    return view;
}
 

And here is where I create the window and apply the view to the window:

//Multiply the logical size of the window by 3 so its not so tiny
int window_w = GameWindow::getIdealSize().x * 3;
int window_h = GameWindow::getIdealSize().y * 3;
//Create the window
window = GameWindow::createWindow(window_w, window_h);

sf::View view;
sf::Vector2<int> logicalSize = GameWindow::getIdealSize();
view.setSize( logicalSize.x, logicalSize.y );
view.setCenter( view.getSize().x / 2, view.getSize().y / 2 );
view = GameWindow::getNoLetterboxView( view, logicalSize.x, logicalSize.y );

while(running) {
    //Handle events here (toggle fullscreen by pressing F key)
    handleEvents();

    //Update logic code here
   //...

   //Rendering and applying view to window here
    window->clear();
    window->setView(view);
    window->draw(bg);
    window->draw(spr);
    window->display();
}

 

The game window looks fine. But when I go to fullscreen (borderless):

I've got the correct logical size (unless I shouldn't be truncating it, should I be flooring/ceiling it?). What can I do to fix both the flickering and letterboxing still showing up?
Title: Re: Get rid of letterboxing
Post by: eXpl0it3r on November 01, 2017, 09:58:36 am
I feel like you're mixing multiple things here.

If you want to adjust the view depending on the window size, simply follow the official tutorial: https://www.sfml-dev.org/tutorials/2.4/graphics-view.php#showing-more-when-the-window-is-resized

If you get flickering, then this either a driver/display issue or your doing multiple window.display() calls.
Title: Re: Get rid of letterboxing
Post by: lucifercartwright on November 01, 2017, 05:09:52 pm
I feel like you're mixing multiple things here.

If you want to adjust the view depending on the window size, simply follow the official tutorial: https://www.sfml-dev.org/tutorials/2.4/graphics-view.php#showing-more-when-the-window-is-resized

If you get flickering, then this either a driver/display issue or your doing multiple window.display() calls.

Well I posted my window->display() code, I'm only calling it once.

Also I see what the tutorial is saying but if I do that, I get a lot of black space:
(https://i.imgur.com/tW9PuvV.png)

My code:
            sf::FloatRect visibleArea(0, 0, window->getSize().x, window->getSize().y);
            sf::View v(visibleArea);
            window->setView(v);
            window->draw(bg);
            window->display();
 

Window size is 960x540. This is how it's technically supposed to look: (resized in photoshop manually)
(https://i.imgur.com/SEhlecz.png)

I'm assuming I have to use sf::View::zoom()? Because I'm honestly confused how zoom works. Not sure what to set the factor to. Setting it to 2 makes the view smaller (no idea), setting it below 1 makes it larger. I set the factor to 0.333 (320/960) and it seems right (can barely tell), but the view is now not located at position(0, 0), so I don't know what it's doing:

(https://i.imgur.com/OgfY6Of.png)

Code I used for setting zoom:
    sf::FloatRect visibleArea(0, 0, window->getSize().x, window->getSize().y);
    sf::View v(visibleArea);
    v.zoom( 360.0 / 960.0 );
    window->setView(v);
    window->draw(bg);
    window->display();
 
Title: Re: Get rid of letterboxing
Post by: achpile on November 01, 2017, 05:23:58 pm
try to set View rect (0, 0, 320, 180)