3

I'm trying to develop a program in which every time a click is performed on the window, a random-size circle appears on the window centered on where the click happened. After that, I need to use glOrtho() or gluOrtho2D() so that the viewing volume would be set up in such a way that when the window is resized, the circles do not change their sizes or get distorted on the screen.

I tried to write the reshape function in different ways but I can't get the right result.

int winWidth = 800;             
int winHeight = 600; 

int main( int argc, char** argv )
{
    glutInit( &argc, argv );
    glutInitDisplayMode( GLUT_RGB | GLUT_SINGLE );  
    glutInitWindowSize( winWidth, winHeight );
    glutCreateWindow( "main" );

    MyInit();

    glutDisplayFunc( MyDisplay );
    glutReshapeFunc( MyReshape );
    glutMouseFunc( MyMouse );

    glutMainLoop();
    return 0;
}

void MyReshape( int w, int h )
{
    winWidth = w;
    winHeight = h;

    glViewport( 0, 0, w, h );

    glMatrixMode( GL_PROJECTION );
    glLoadIdentity();
    if (w <= h)
        glOrtho(-2.0, 2.0, -2.0 * (GLfloat) h / (GLfloat) w,
            2.0 * (GLfloat) h / (GLfloat) w, -20.0, 20.0);
    else
        glOrtho(-2.0 * (GLfloat) w / (GLfloat) h,
            2.0 * (GLfloat) w / (GLfloat) h, -2.0, 2.0, -20.0, 20.0);

    glMatrixMode( GL_MODELVIEW );

}

void MyMouse( int btn, int state, int x, int y )
{
    if ( btn == GLUT_LEFT_BUTTON && state == GLUT_DOWN )
    {
        disc[numDiscs].pos[0] = x;
        disc[numDiscs].pos[1] = y;
        disc[numDiscs].speed[0] = ((rand() % 2) * 2 - 1) * (MIN_X_SPEED + rand() / (RAND_MAX / (MAX_X_SPEED - MIN_X_SPEED)));
        disc[numDiscs].speed[1] = ((rand() % 2) * 2 - 1) * (MIN_Y_SPEED + rand() / (RAND_MAX / (MAX_Y_SPEED - MIN_Y_SPEED)));
        disc[numDiscs].radius = (MIN_RADIUS + rand() / (RAND_MAX / (MAX_RADIUS - MIN_RADIUS)))/10;
        disc[numDiscs].color[0] = (char)rand() % 256;
        disc[numDiscs].color[1] = (char)rand() % 256;
        disc[numDiscs].color[2] = (char)rand() % 256;

        numDiscs++;
        glutPostRedisplay();
    }
}

void MyDisplay( void )
{
    glClear( GL_COLOR_BUFFER_BIT );
    glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );

    for ( int i = 0; i < numDiscs; i++ ) DrawDisc( &disc[i] );

    glFlush();  
}

void MyInit( void )
{
    glClearColor( 0.0, 0.0, 0.0, 1.0 ); 
    glShadeModel( GL_FLAT );
}
Rabbid76
  • 202,892
  • 27
  • 131
  • 174
  • 1
    You could simply set `glOrtho(0, w, 0, h, -1, 1)` and draw the circles with sizes in pixels. If you want to keep origin in view center, `glOrtho(-w / 2, w / 2, -h / 2, h / 2, -1, 1)` would do. Or, do you want a constant relative size of cirlces regarding to view? – Scheff's Cat Sep 05 '19 at 05:45
  • Thank you! It seems that they work when the window is resized. The only problem is that with the first solution the circles are drawn mirrored horizontally wrt where I click, while with the second solution they are drawn mirrored vertically. Any idea why? –  Sep 05 '19 at 06:47
  • Mouse coordinates are measured from top-left corner of window while in the OpenGL view (with the mentioned `glOrtho(0, w, 0, h, -1, 1)`) the origin is in the bottom left corner. You may try `glOrtho(0, w, h, 0, -1, 1);` which makes view coordinates identical to pixel coordinates. Alternatively, you could convert the mouse coordinates into view space (e.g. by `y = h - y;`). – Scheff's Cat Sep 05 '19 at 06:52
  • This really helped me a lot! Thank you very much! –  Sep 05 '19 at 06:56
  • The difference between `glOrtho(0, w, 0, h, -1, 1)` and `glOrtho(0, w, h, 0, -1, 1)` is that the first makes a left handed coordinate system in "screen space" where the latter a right handed. It's probably tolerable for 2d (and no back-face culling) but might become an issue in 3d. I once fiddled with this in [SO: Ortho and Persp are reversing Z depth sign?](https://stackoverflow.com/a/52887566/7478597). ;-) – Scheff's Cat Sep 05 '19 at 06:59

1 Answers1

4

[...] in such a way that when the window is resized, the circles do not change their sizes or get distorted [...]

If the circles should keep there size in pixel units, then you've to define a orthographic projection, which is based on the relation of the current size of the window to initial size of the window.
Since the size of you window is (800, 600) you've to scale the projection dependent on the height of the window by w/600.0 respectively h/600.0, because the height is less than the width and the aspect is applied to the longer side:

void MyReshape( int w, int h )
{
    winWidth = w;
    winHeight = h;

    glViewport( 0, 0, w, h );

    glMatrixMode( GL_PROJECTION );
    glLoadIdentity();
    if (w <= h)
    {
        GLdouble  aspect = (GLdouble)h / w;
        GLdouble  scale  = w / 600.0;

        scale *= 2.0;
        project = glm::ortho(-scale, scale, -scale * aspect, scale * aspect, -20.0, 20.0);
    }
    else
    {
        GLdouble  aspect = (GLdouble)w / h;
        GLdouble  scale  = h / 600.0;

        scale *= 2.0;
        project = glm::ortho(-scale * aspect, scale * aspect, -scale, scale, -20.0, 20.0);
    }
    glMatrixMode( GL_MODELVIEW );
}
Rabbid76
  • 202,892
  • 27
  • 131
  • 174