3

I have a Windows (XP) application which needs to display a two-dimensional rectangle within a window. The rectangle must not be clipped (i.e. must always lie completely within the viewport), and must preserve its aspect ratio on resize. Currently, the method which handles layout distorts the aspect ratio of the rectangle to match the window. I want the rectangle to scale to the window and be centered in the window (again, without clipping). The method as it stands is below. lWinDist and lMaxDepth are the width and height of the rectangle to be displayed (in 48ths of an inch, if it matters):

void CRoRRecView::RedoLayout( long lWinDist, long lMaxDepth )
{
    CDC* pDC = GetDC() ;

    if ( pDC != NULL )
    {
        m_lWinDist = lWinDist;
        GetClientRect( m_rectClient ) ;
        int nClientWidth = m_rectClient.Width();
        int nClientHeight = m_rectClient.Height();
        glViewport( 0, 0, nClientWidth, nClientHeight );

        glMatrixMode( GL_PROJECTION);
        glLoadIdentity();

        m_fWinXDist = (float) lWinDist ;
        m_fWinYDist = lMaxDepth ;
        m_fAspectRatio = m_fWinXDist / m_fWinYDist;

        glOrtho(0.0, m_fWinXDist, 0.0, m_fWinYDist, -1, 1 ) ;

        glRotatef(180.0, 0,1,0); 
        glTranslatef( (float)(-1 * lWinDist),0,0 ); // Translate across the x axis

        glMatrixMode( GL_MODELVIEW );
        glLoadIdentity();

        ReleaseDC( pDC ) ;
    }
}
genpfault
  • 51,148
  • 11
  • 85
  • 139
PSU
  • 43
  • 1
  • 1
  • 4

4 Answers4

4

Try this reshape function. It will preserve your aspect ratio, resize the object, and make the viewport to be centralize.

// initial window screen size
int WIDTH = 400;
int HEIGHT = 300;

// reshape function, call with glutReshapeFunc(reshape) in yout main function
void reshape(int width, int height) {
    const float ar_origin = (float) WIDTH / (float) HEIGHT;
    const float ar_new = (float) width / (float) height;

    float scale_w = (float) width / (float) WIDTH;
    float scale_h = (float) height / (float) HEIGHT;
    if (ar_new > ar_origin) {
        scale_w = scale_h;
    } else {
        scale_h = scale_w;
    }

    float margin_x = (width - WIDTH * scale_w) / 2;
    float margin_y = (height - HEIGHT * scale_h) / 2;

    glViewport(margin_x, margin_y, WIDTH * scale_w, HEIGHT * scale_h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(0, WIDTH / ar_origin, 0, HEIGHT / ar_origin, 0, 1.0);

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity() ;
}
Ifan Iqbal
  • 3,053
  • 5
  • 28
  • 31
4

This one should scale as expected:

// g++ main.cpp -lglut -lGL
#include <GL/glut.h>

void display()
{
    glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

    glMatrixMode( GL_PROJECTION );
    glLoadIdentity();
    double w = glutGet( GLUT_WINDOW_WIDTH );
    double h = glutGet( GLUT_WINDOW_HEIGHT );
    double ar = w / h;
    glOrtho( -2 * ar, 2 * ar, -2, 2, -1, 1);

    glMatrixMode( GL_MODELVIEW );
    glLoadIdentity();

    glColor3ub( 255, 0, 0 );
    glBegin( GL_QUADS );
    glVertex2i( -1, -1 );
    glVertex2i(  1, -1 );
    glVertex2i(  1,  1 );
    glVertex2i( -1,  1 );
    glEnd();

    glutSwapBuffers();
}

int main( int argc, char **argv )
{
    glutInit( &argc, argv );
    glutInitDisplayMode( GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE );
    glutInitWindowSize( 640, 480 );
    glutCreateWindow( "Aspect Ratio" );
    glutDisplayFunc( display );
    glutMainLoop();
    return 0;
}
genpfault
  • 51,148
  • 11
  • 85
  • 139
  • Thanks. Yes, that scales nicely. Unfortunately, the entire issue has become moot on my end; the powers that be have declared that the aspect ratio shall be fixed. I'll keep this in my back pocket anyway. – PSU Dec 07 '10 at 16:57
0

I think you should look at this to get the right numbers:

self.hOffset = (self.wOffset / (16.0 / 9.0));
self.xOffset = ((int)ceil((_backingWidth  / 2.0) - ((_backingWidth  + self.wOffset) / 2.0)));
self.yOffset = ((int)ceil((_backingHeight / 2.0) - ((_backingHeight + self.hOffset) / 2.0)));

glViewport(self.xOffset, self.yOffset, _backingWidth + self.wOffset, _backingHeight + self.hOffset );

In the above code, wOffset, which is the width of the image, give or take its value changed via a slider. The first line increases the height as the width is increased at the correct ratio, which happens to be 16:9 (it doesn't work well to divide the width by the height to get the ratio; specifying it explicitly does best). The next two lines adjust the x,y coordinates of the image, so that as it is increased or decreased in size, it always stays centered.

This is by far a simpler, easier approach—and lighter on the GPU. If there are reasons why the mega-coding approach I'm seeing here is better, I can't figure it out. Good luck.

James Bush
  • 1,485
  • 14
  • 19
0

Try this:

#include <GL/glut.h>

size_t win_w = 0;
size_t win_h = 0;

void display(void)
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(0, win_w, 0, win_h, -1, 1);

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    glColor3ub(255,0,0);
    glPushMatrix();
        glTranslatef(win_w/2,win_h/2,0);
        glScalef(50,50,50);
        glBegin(GL_QUADS);
            glVertex2f(-1,-1);
            glVertex2f(1,-1);
            glVertex2f(1,1);
            glVertex2f(-1,1);
        glEnd();
    glPopMatrix();

    glFlush();
    glutSwapBuffers();
}

void reshape(int w, int h)
{
    win_w = w;
    win_h = h;
    glViewport(0, 0, w, h);
}

int main(int argc, char **argv)
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE);

    glutInitWindowSize(800,600);
    glutCreateWindow("Aspect Ratio");

    glutDisplayFunc(display);
    glutReshapeFunc(reshape);
    glutMainLoop();
    return 0;
}
genpfault
  • 51,148
  • 11
  • 85
  • 139
  • 1
    Thanks. However, while the aspect ratio and centering of the object is maintained, it is not resizing as the window is resized. That is to say, if the object begins by occupying, say, 3/4 of the height of the window, it will always occupy 3/4 of the height of the window after resizing. – PSU Dec 03 '10 at 22:21
  • @PSU: Yep, you're right. I had a slightly different version that did the correct thing, I'll see if I can pull it up. – genpfault Dec 04 '10 at 00:26