Search code examples
c++openglgraphicscoordinate-transformation

Flipping Opengl drawing without scale by negative numbers


I am trying to draw two 2D diamonds facing each other. So I drew the first diamond then I drew the second diamond after using:

glTranslated(0, -150, 0);

so it can appear exactly under my first diamond . However, I ran into a problem that I couldn't flip the second diamond so it could look like a mirror.

Here is what i am trying to do:

What i am trying to do

I searched online for solutions and they all mentioned that I should use

glScalef(1.0f,-1.0f,1.0f); 

but each time I use it the drawing disappears.

The function

glRotatef(angle,x,y,z); 

caught my attention but i couldn't use it properly resulting in wrong direction.

Here is how my image looks like right now without glRotate():

Without glRotate()

So I think I need the proper technique to use any of these functions.

Note: I am using many line loops and vertices to draw.

  #include <windows.h>  // For MS Windows
  #include <GL/glut.h>   // (or others, depending on the system in use)
  void init(void)
  {
     glClearColor(1.0, 1.0, 1.0, 0.0);  // Set display-window color to 
      white.
    glMatrixMode(GL_PROJECTION);       // Set projection parameters.
    gluOrtho2D(0.0, 400.0, 0.0, 400.0);
  }
  void drawDiamond()
     {
  glBegin(GL_LINE_LOOP);
  glVertex2f(125, 350);
  glVertex2f(245, 350);
  glVertex2f(290, 300);
  glVertex2f(182, 200);
  glVertex2f(75, 300);
  glEnd();


 glBegin(GL_LINE_LOOP);
 glVertex2f(109, 333);
 glVertex2f(138, 350);
 glVertex2f(159, 337);
 glVertex2f(123, 300);
glEnd();

glBegin(GL_LINE_LOOP);
glVertex2f(109, 333);
glVertex2f(123, 300);
glVertex2f(154, 225);
glVertex2f(92, 300);
glEnd();

glBegin(GL_LINE_LOOP);
glVertex2f(290, 300);
glVertex2f(75, 300);
glEnd();

glBegin(GL_LINE_LOOP);
glVertex2f(123, 300);
glVertex2f(159, 337);
glVertex2f(154, 300);
glVertex2f(171, 225);
glEnd();

glBegin(GL_LINE_LOOP);
glVertex2f(181, 300);
glVertex2f(159, 337);
glVertex2f(181, 350);
glVertex2f(209, 337);
glVertex2f(181, 300);
glVertex2f(171, 225);
glEnd();

glBegin(GL_LINE_LOOP);
glVertex2f(181, 300);
glVertex2f(209, 337);
glVertex2f(219, 300);
glVertex2f(195, 225);
glVertex2f(181, 300);
glEnd();
glBegin(GL_LINE_LOOP);
glVertex2f(209, 337);
glVertex2f(243, 300);
glVertex2f(195, 225);
glVertex2f(219, 300);
glEnd();

glBegin(GL_LINE_LOOP);
glVertex2f(209, 337);
glVertex2f(229, 350);
glVertex2f(260, 333);
glVertex2f(243, 300);
glVertex2f(209, 337);
glEnd();

glBegin(GL_LINE_LOOP);
glVertex2f(260, 333);
glVertex2f(278, 300);
glVertex2f(210, 225);
glVertex2f(243, 300);
glEnd();

glBegin(GL_LINE_LOOP);
glVertex2f(195, 225);
glVertex2f(182, 200);
glEnd();

glBegin(GL_LINE_LOOP);
glVertex2f(171, 225);
glVertex2f(182, 200);
glEnd();

}

void display()
{
glClear(GL_COLOR_BUFFER_BIT);  // Clear display window.
glColor3f(0.0, 0.0, 0.0);      // Set line segment color to blue.

                               // your code goes here
drawDiamond();
glTranslatef(0.0f, -150, 0.0f);
drawDiamond();
glFlush();     // Process all OpenGL routines as quickly as possible.

}
void main(int argc, char** argv)
{
glutInit(&argc, argv);                         // Initialize GLUT.
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);   // Set display mode.
glutInitWindowPosition(50, 100);   // Set top-left display-window 
position.
glutInitWindowSize(400, 400);      // Set display-window width and 
height. 
glutCreateWindow("Diamond Project"); // Create display window. 

init();                            // Execute initialization procedure. 
glutDisplayFunc(display);       // Send graphics to display window. 


glutMainLoop();                    // Display everything and wait.      

}


Solution

  • What you want to do is to mirror (flip) the object around an axis, which is parallel to the X-axis, and goes through the bottom bounding of the object (diamond).

    To do so, the bottom Y coordinate (bottomY) has to be found and the object has to be translated in the opposite direction. Note the bottom of the model coordinates (vertices) and not the bottom of final coordinates on the viewport:

    float bottomY = 200.0f;
    glTranslatef( 0.0f, -bottomY , 0.0f );
    

    At next the object has to be flipped. This can either be done by

    glRotatef(180.0f, 1.0f, 0.0f, 0.0f);
    

    or by

    glScalef(1.0f, -1.0f, 0.0f)
    

    Note, both operations result in the same transformation matrix, because cos(90°) = cos(-90°), sin(90°) = -sin(90°).

    Then the bottomY translation has to be reversed:

    glTranslatef( 0.0f, bottomY, 0.0f );
    

    But note that the OpenGL fixed function pipeline stack operates in the the reverse order, because the current matrix is multiplied by the matrix which is specified by the new operation.

    Translation: See the documentation of glTranslate:

    glTranslate produces a translation by x y z . The current matrix (see glMatrixMode) is multiplied by this translation matrix, with the product replacing the current matrix.

    Rotation: See the documentation of glRotate:

    glRotate produces a rotation of angle degrees around the vector x y z . The current matrix (see glMatrixMode) is multiplied by a rotation matrix with the product replacing the current matrix.

    Scaling: See the documentation of glScale:

    glScaleproduces a nonuniform scaling along the x, y, and z axes. The three parameters indicate the desired scale factor along each of the three axes. The current matrix (see glMatrixMode) is multiplied by this scale matrix.


    This means the the following should do what you want:

    float bottomY = 200.0f;
    
    glMatrixMode( GL_MODELVIEW );
    glLoadIdentity();
    
    drawDiamond();
    
    glTranslatef( 0.0f, bottomY , 0.0f );
    glRotatef( 180.0f, 1.0f, 0.0f, 0.0f );
    glTranslatef( 0.0f, -bottomY , 0.0f );
    
    drawDiamond();
    

    and is the same as:

    glTranslatef( 0.0f, bottomY , 0.0f );
    glScalef( 1.0f, -1.0f, 1.0f );
    glTranslatef( 0.0f, -bottomY , 0.0f );