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

Author Topic: [Solved] Change viewport to keep aspect ratio of scene  (Read 14656 times)

0 Members and 1 Guest are viewing this topic.

JoshuaBehrens

  • Newbie
  • *
  • Posts: 35
    • View Profile
[Solved] Change viewport to keep aspect ratio of scene
« on: July 14, 2014, 02:16:22 pm »
Hey guys,

I am stuck with certain problem: I manage stuff inside of sth you can call a scene and I want to keep the aspect ratio of the scene when the window is resized. I want to do this by changing the viewport. I am used to the fact that the viewport is given in pixels as sf::View seems to use percentage values of the window size I scale my calculated viewport down with these lines:

// down scale to % units ; windoww/h are from the resize event
viewport.width  = viewport.width  / windoww;
viewport.height = viewport.height / windowh;
// center
viewport.left = ( 1.0 - viewport.width  ) * 0.5;
viewport.top  = ( 1.0 - viewport.height ) * 0.5;

But it seems that my calculations are always wrong :/ and I guess I am stuck in my head so I can't see the problem. I tried this way to get the right upscaled/cropped size:
 // in = ( scenew, sceneh ); clip = ( windoww, windowh )
sf::Vector2f scaleToFit( const sf::Vector2f& in, const sf::Vector2f& clip )
{
        sf::Vector2f ret( in );
        if ( ( clip.y * in.x ) / in.y >= clip.x )
        {
                ret.y = ( clip.x * in.y ) / in.x;
                ret.x = clip.x;
        }
        else if ( ( clip.x * in.y ) / in.x >= clip.y )
        {
                ret.x = ( clip.y * in.x ) / in.y;
                ret.y = clip.y;
        }
        else
                ret = clip;
        return ret;
}
 
All I get is strange resizing. The scene keeps in the center but if I extend the width of the window (there should be black panels on the left and right) the black panels get very big so the scene does not keep its ratio and I don't know why. I hope I can get some help here.

Just for your information: This is what all happens on the resize event but I don't expect an error there:
sf::View v( sf::FloatRect( 0, 0, scenew, sceneh ) );
sf::FloatRect viewport( sf::Vector2f( 0, 0 ), scaleToFit( sf::Vector2f( screenw, screenh ), sf::Vector2f( windoww, windowh ) ) );
viewport.width  = viewport.width  / basicSettings.windoww;
viewport.height = viewport.height / basicSettings.windowh;
viewport.left = ( 1.0 - viewport.width  ) * 0.5;
viewport.top  = ( 1.0 - viewport.height ) * 0.5;
v.setViewport( viewport );
window.setView( v );
 
« Last Edit: August 02, 2014, 01:19:46 am by JoshuaBehrens »

Hapax

  • Hero Member
  • *****
  • Posts: 3043
  • My number of posts is shown in hexadecimal.
    • View Profile
Re: Change viewport to keep aspect ratio of scene
« Reply #1 on: July 14, 2014, 08:26:52 pm »
You aim seems to be keeping the view constantly letterboxed. Does the view really have to be resized with the window? Can't you just adjust the aspect of it and keep one of the sides always matching the original view?

Anyway, it looks like
sf::FloatRect viewport( sf::Vector2f( 0, 0 ), scaleToFit( sf::Vector2f( screenw, screenh ), sf::Vector2f( windoww, windowh ) ) );
should be
sf::FloatRect viewport( sf::Vector2f( 0, 0 ), scaleToFit( sf::Vector2f( scenew, sceneh ), sf::Vector2f( windoww, windowh ) ) );
(scenew & sceneh instead of screenw & screenh)
Selba Ward - SFML drawables
Kairos - Timing Library
Rectangular Boundary Collision - Rectangular SAT Collision

@Hapaxiation - Hapaxia on Twitter

JoshuaBehrens

  • Newbie
  • *
  • Posts: 35
    • View Profile
Re: Change viewport to keep aspect ratio of scene
« Reply #2 on: July 15, 2014, 06:11:20 pm »
Yeah that is just a typo. As I compared it to a scene I renamed the variables in the code (except these two). So this is not a real "error".
Letterboxed ... that was the word ... Well at the right window ratio there are no letterboxes(obvious) but yes I want the letterboxes.

Hapax

  • Hero Member
  • *****
  • Posts: 3043
  • My number of posts is shown in hexadecimal.
    • View Profile
Re: Change viewport to keep aspect ratio of scene
« Reply #3 on: July 15, 2014, 10:34:31 pm »
In this line:
viewport.width  = viewport.width  / windoww;
you are dividing the current ratio by the size of the window in pixels and then assigning that as the new ratio.

I think it should rather be:
viewport.width = currentViewportWidthInPixels / windoww;

Obviously, the same sort of thing would also apply to the height line.
Selba Ward - SFML drawables
Kairos - Timing Library
Rectangular Boundary Collision - Rectangular SAT Collision

@Hapaxiation - Hapaxia on Twitter

JoshuaBehrens

  • Newbie
  • *
  • Posts: 35
    • View Profile
Re: Change viewport to keep aspect ratio of scene
« Reply #4 on: July 16, 2014, 12:30:51 am »
As scenew, sceneh, windoww and windowh contain values in pixel unit scaleToFit returns unit pixel. So viewport.width/.height contain pixel values.

Hapax

  • Hero Member
  • *****
  • Posts: 3043
  • My number of posts is shown in hexadecimal.
    • View Profile
Re: Change viewport to keep aspect ratio of scene
« Reply #5 on: July 16, 2014, 12:56:30 am »
Ah, I see; that makes sense.
However, the .setViewPort requires ratios, not pixels.
Also, your viewport.left and viewport.top are based on viewport.width and viewport.height being ratios.
Selba Ward - SFML drawables
Kairos - Timing Library
Rectangular Boundary Collision - Rectangular SAT Collision

@Hapaxiation - Hapaxia on Twitter

JoshuaBehrens

  • Newbie
  • *
  • Posts: 35
    • View Profile
Re: Change viewport to keep aspect ratio of scene
« Reply #6 on: July 16, 2014, 05:42:20 am »
That is why I scale the size values by dividing by their maximum pixel units (window size). The position is just position in the center.

Hapax

  • Hero Member
  • *****
  • Posts: 3043
  • My number of posts is shown in hexadecimal.
    • View Profile
Re: Change viewport to keep aspect ratio of scene
« Reply #7 on: July 18, 2014, 03:28:06 pm »
My point is that you're scaling using one ratio and one pixel length to get a ratio. They should be both ratios or both pixel lengths.

e.g.
viewport.width = 0.5
windoww = 600

then
viewport.width = 0.5 / 600 = 0.000833
0.000833 is probably not the width you wanted.
Selba Ward - SFML drawables
Kairos - Timing Library
Rectangular Boundary Collision - Rectangular SAT Collision

@Hapaxiation - Hapaxia on Twitter

JoshuaBehrens

  • Newbie
  • *
  • Posts: 35
    • View Profile
Re: Change viewport to keep aspect ratio of scene
« Reply #8 on: July 30, 2014, 04:49:46 pm »
I got your point, but the units are fine(and they were the right units all the time). I was testing an other way, but here is the same issue that it is scaling weird. I looks like this generates no panels when the window is like a square and scales wrong if it is rectangular.
        // not edited
        sf::View v( sf::FloatRect( sf::Vector2f( basicSettings.screenx, basicSettings.screeny ), \
                                                           sf::Vector2f( basicSettings.screenw, basicSettings.screenh ) ) );

        sf::Vector2f S( basicSettings.screenw, basicSettings.screenh );
        sf::Vector2f W( basicSettings.windoww, basicSettings.windowh );

        float scalor( std::min( W.x / S.x, W.y / S.y ) ); // squared window preference?!
        sf::Vector2f scaled( S );
        scaled *= scalor;
        printf( "scaled: %f %f\n", scaled.x, scaled.y );

        sf::FloatRect viewport( sf::Vector2f( 0, 0 ), scaled );
        viewport.width  = viewport.width  / W.x;
        viewport.height = viewport.height / W.y;
        viewport.left = ( 1.0 - viewport.width  ) * 0.5;
        viewport.top  = ( 1.0 - viewport.height ) * 0.5;
        v.setViewport( viewport ); // in the end still not the same ratio as the scene
        basicSettings.window.setView( v );

Why did anyone chose to set the viewport in percent units? Why not in pixels as the glViewport does? It was easier with pixel values to check the problem :/ as you always had to deal with pixels when changing the viewport.

Hapax

  • Hero Member
  • *****
  • Posts: 3043
  • My number of posts is shown in hexadecimal.
    • View Profile
Re: Change viewport to keep aspect ratio of scene
« Reply #9 on: July 30, 2014, 07:32:03 pm »
Why did anyone chose to set the viewport in percent units? Why not in pixels as the glViewport does? It was easier with pixel values to check the problem :/ as you always had to deal with pixels when changing the viewport.
There are no percentages; they're ratios. This question is answered in the tutorial:
Quote
the viewport is not defined in pixels, but rather as a ratio of the window size. This is much more convenient: this way you don't have to track resize events to update the size of the viewport. It is also more intuitive: you will most likely need to define your viewport as a fraction of your window, not as a fixed-size rectangle.

I got your point, but the units are fine(and they were the right units all the time).
I can't see a possible way that the units could have been fine. Either you were using a ratio where a pixel size should have been used or you were using a pixel size where a ratio should have been used.

I must admit that I had a tiny bit of trouble with keeping aspect ratio of view constant when window's aspect ratio changed, but it turned out to be not that difficult (I'm slow :P); keep at it!  ;)
Selba Ward - SFML drawables
Kairos - Timing Library
Rectangular Boundary Collision - Rectangular SAT Collision

@Hapaxiation - Hapaxia on Twitter

JoshuaBehrens

  • Newbie
  • *
  • Posts: 35
    • View Profile
Re: Change viewport to keep aspect ratio of scene
« Reply #10 on: July 31, 2014, 08:16:39 am »
Well percentages and ratios both are usually used with values between 0..1 and as I am not a native English speaker I might tend to use wrong words.

Ok, I got the reason why ratios are used. Why do you stick to the thought that the units were/are wrong and not the values? Check the code, I convert from pixel to ratio with this:
    viewport.width  = viewport.width  / W.x;
    viewport.height = viewport.height / W.y;
And all before this is pixel and all after this is in ratio units.

Can't you write something more helpful? If you already had the same problem why can't you give a hint, where I should rethink my code or give (pseudo-)code.

maly

  • Newbie
  • *
  • Posts: 14
    • View Profile
Re: Change viewport to keep aspect ratio of scene
« Reply #11 on: July 31, 2014, 12:30:02 pm »
Something like this?
float screenwidth = windowsize.x / static_cast<float>(gamesize.x);
float screenheight = windowsize.y / static_cast<float>(gamesize.y);

sf::FloatRect viewport;
viewport.width = 1.f;
viewport.height = 1.f;

if(screenwidth > screenheight)
{
        viewport.width = screenheight / screenwidth;
        viewport.left = (1.f - viewport.width) / 2.f;
}
else if(screenwidth < screenheight)
{
        viewport.height = screenwidth / screenheight;
        viewport.top = (1.f - viewport.height) / 2.f;
}

sf::View v( sf::FloatRect( 0, 0, gamesize.x , gamesize.y ) );
v.setViewport(viewport);

JoshuaBehrens

  • Newbie
  • *
  • Posts: 35
    • View Profile
Re: Change viewport to keep aspect ratio of scene
« Reply #12 on: July 31, 2014, 07:55:22 pm »
I tried yours maly and it ends up the same as my implementation.
        float screenwidth =  static_cast<float>(basicSettings.windoww) / static_cast<float>(basicSettings.screenw);
        float screenheight = static_cast<float>(basicSettings.windowh) / static_cast<float>(basicSettings.screenh);

        sf::FloatRect viewport;
        viewport.width = 1.f;
        viewport.height = 1.f;

        if( screenwidth > screenheight )
        {
                viewport.width = screenheight / screenwidth;
                viewport.left = (1.f - viewport.width) / 2.f;
        }
        else if(screenwidth < screenheight)
        {
                viewport.height = screenwidth / screenheight;
                viewport.top = (1.f - viewport.height) / 2.f;
        }

        sf::View v( sf::FloatRect( sf::Vector2f( basicSettings.screenx, basicSettings.screeny ), \
                                                           sf::Vector2f( basicSettings.screenw, basicSettings.screenh ) ) );
        v.setViewport(viewport);

        basicSettings.window.setView( v );
I guess I make some screenshots:
(click to show/hide)
« Last Edit: August 01, 2014, 05:27:59 am by JoshuaBehrens »

Gobbles

  • Full Member
  • ***
  • Posts: 132
    • View Profile
    • Email
Re: Change viewport to keep aspect ratio of scene
« Reply #13 on: August 01, 2014, 02:15:41 am »
just put something together rather quick, wonder if it's the same kind of thing your trying to do.
void Game::MaintainAspectRatio()
{
        //first we check our new aspect width to see if it changed
        float newAspectWidth = window.getSize().x;
        float newAspectHeight = window.getSize().y;
        if(newAspectWidth != currentAspectWidth)
        {
                //width changed, maintain the aspect ratio and adjust the height
                currentAspectWidth = newAspectWidth;
                currentAspectHeight = currentAspectWidth / aspectRatio;
        }
        else if(newAspectHeight != currentAspectHeight)
        {
                //height changed, maintain aspect ratio and change the width
                currentAspectHeight = newAspectHeight;
                currentAspectWidth = currentAspectHeight * aspectRatio;
        }
        std::cout << "width: " << currentAspectWidth << " height: " << currentAspectHeight;
        window.setSize(sf::Vector2u(currentAspectWidth, currentAspectHeight));
}

Where aspectRatio is always 4:3.

Edit: I should also mention that this gets called whenever theres a Resize Event.

JoshuaBehrens

  • Newbie
  • *
  • Posts: 35
    • View Profile
Re: Change viewport to keep aspect ratio of scene
« Reply #14 on: August 01, 2014, 05:26:28 am »
I get your dirty trick behind it as you limit the window size. I don't really like it as I cannot freely do with the window what I want (as a player).
I tried your code with currentAspectWidth and currentAspectHeight as floats. After resizing once the window shrunk:
(click to show/hide)
I also tried to change the floats to ints(just currentAspect***) and the same phenomenom:
(click to show/hide)