4
\$\begingroup\$

I have been playing around with OpenGL and created a fairly basic 2D animation was just hoping someone could take a look and give me some pointers.

Main.cpp:

#include "glut.h"
#include <math.h>
#include <stdio.h>



int bc = 0.4; //building color
int frame=0;

class points{
public:
    float x, y;
};
points startLine[2] = {{300,800},{300,800}};

points endLine[2] = {{250,170},{250,170}};

points tweenLine[4];


int numpoints=2;


float proportion = 0.0; //helicopter scene

float lScale = 0.0; //line scale
float fScale = 0.5; 
float bScale = 0.5;
float bTrans = 0.0;
int flag = 0;

void tween(points source[10], points destination[10], double proportion, points tweenLine[10])
{

    for( int i = 0; i < numpoints; i++)
        {
                // get the source point
            double sourceX = source[i].x;
            double sourceY = source[i].y;

                // get the destination point
            double destinationX = destination[i].x;
            double destinationY = destination[i].y;

                // get the difference between source and destination
            double differenceX = (destinationX - sourceX);
            double differenceY = (destinationY - sourceY);

                // tween point is source position + proportion
             // of distance between source and destination
            double tweenX = sourceX + ( differenceX * proportion );
            double tweenY = sourceY + ( differenceY * proportion );

           // create point with tween co-ordinates in tween array
            tweenLine[i].x = tweenX;
            tweenLine[i].y = tweenY;
        }


}
void printText(float x, float y, int spacing, void *font, char *string) 
{
  char *c;
  int x1=x;

  for (c=string; *c != '\0'; c++) 
{
    glRasterPos2f(x1,y);
        glutBitmapCharacter(font, *c);

    x1 = x1 + glutBitmapWidth(font,*c) + spacing;
  }
}


void init(void)
{
    // Set display window color to as glClearColor(R,G,B,Alpha)
    glClearColor(0.2, 0.2, 0.4, 0.0);
    // Set projection parameters.
    glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
    // Set 2D Transformation as gluOrtho2D(Min Width, Max Width, Min Height, Max Height)
    gluOrtho2D(0.0, 800, 0.0, 600);
}
void background(){

glBegin(GL_QUADS);
//floor
glColor3f(0.0, 0.0, 0.0);
glVertex2f(-1.0,-1.0);
glVertex2f(1.0,-1.0);
//sky
glColor3f(0.2, 0.2, 0.4);
glVertex2f(1.0, 1.0);
glVertex2f(-1.0, 1.0);
glEnd();
}

//function to draw text 
void man()
{
    //body
    glColor3f(0.0, 0.0, 0.0);
    glBegin(GL_POLYGON);
    glVertex2i(332, 150);
    glVertex2i(340, 150);
    glVertex2i(340, 160);
    glVertex2i(332, 160);
    glEnd();
    //head
    glColor3f(0.9, 0.2, 0.2);
    glBegin(GL_POLYGON);
    glVertex2i(334, 160);
    glVertex2i(338, 160);
    glVertex2i(338, 163);
    glVertex2i(334, 163);
    glEnd();

}


void morphSpotlight()
{
    //morph to white
    glColor3f(1, 1, 1);
        tween(startLine, endLine, proportion, tweenLine);
    glBegin(GL_LINE_LOOP);
    for(int i=0; i<numpoints; i++)
    {
        glVertex2i(tweenLine[i].x,tweenLine[i].y);
    }
    proportion += 0.005;
    if(proportion >0.5) proportion +=0.01;
    if(proportion >0.8) proportion =0.8;
}

void window()
{ 
    glColor3f(0.9, 0.9, 0.0);
    glBegin(GL_POLYGON);
    glVertex2i(330, 170);
    glVertex2i(340, 170);
    glVertex2i(340, 150);
    glVertex2i(330, 150);
    glEnd();
}
void backdrop()
{
    // Back strip
    glColor3f(bc, bc, bc);
    glBegin(GL_POLYGON);
    glVertex2i(0, 35);
    glVertex2i(900, 35);
    glVertex2i(900, 0);
    glVertex2i(0, 0);
    glEnd();
    //
    glColor3f(bc, bc, bc);
    glBegin(GL_POLYGON);
    glVertex2i(0, 60);
    glVertex2i(40, 70);
    glVertex2i(40, 0);
    glVertex2i(0, 0);
    glEnd();

    //building 
    glColor3f(bc, bc, bc);
    glBegin(GL_POLYGON);
    glVertex2i(70, 90);
    glVertex2i(100, 90);
    glVertex2i(100, 0);
    glVertex2i(70, 0);
    glEnd();

    //building 1
    glColor3f(bc, bc, bc);
    glBegin(GL_POLYGON);
    glVertex2i(50, 110);
    glVertex2i(70, 110);
    glVertex2i(70, 0);
    glVertex2i(50, 0);
    glEnd();

    //building 3
    glColor3f(bc, bc, bc);
    glBegin(GL_POLYGON);
    glVertex2i(110, 160);
    glVertex2i(180, 160);
    glVertex2i(180, 0);
    glVertex2i(110, 0);
    glEnd();

    //building 3 roof
    glColor3f(bc, bc, bc);
    glBegin(GL_POLYGON);
    glVertex2i(110, 160);
    glVertex2i(180, 160);
    glVertex2i(145, 180);
    glEnd();


    //lip
    glColor3f(bc, bc, bc);
    glBegin(GL_POLYGON);
    glVertex2i(180, 80);
    glVertex2i(190, 80);
    glVertex2i(190, 0);
    glVertex2i(180, 0);
    glEnd();

    //angled building
    glColor3f(bc, bc, bc);
    glBegin(GL_POLYGON);
    glVertex2i(190, 120);
    glVertex2i(230, 105);
    glVertex2i(230, 0);
    glVertex2i(190, 0);
    glEnd();

    //reverse-angled building
    glColor3f(bc, bc, bc);
    glBegin(GL_POLYGON);
    glVertex2i(230, 50);
    glVertex2i(250, 60);
    glVertex2i(250, 0);
    glVertex2i(230, 0);
    glEnd();

    //rectangle building
    glColor3f(bc, bc, bc);
    glBegin(GL_POLYGON);
    glVertex2i(265, 100);
    glVertex2i(300, 100);
    glVertex2i(300, 0);
    glVertex2i(265, 0);
    glEnd();

    //lip
    glColor3f(bc, bc, bc);
    glBegin(GL_POLYGON);
    glVertex2i(300, 60);
    glVertex2i(310, 70);
    glVertex2i(310, 0);
    glVertex2i(300, 0);
    glEnd();

    //spire
    glColor3f(bc, bc, bc);
    glBegin(GL_POLYGON);
    glVertex2i(310, 200);
    glVertex2i(360, 200);
    glVertex2i(360, 0);
    glVertex2i(310, 0);
    glEnd();

    //spire top
    glColor3f(bc, bc, bc);
    glBegin(GL_POLYGON);
    glVertex2i(310, 200);
    glVertex2i(360, 200);
    glVertex2i(335, 270);
    glVertex2i(310, 0);
    glEnd();

    //
    glColor3f(bc, bc, bc);
    glBegin(GL_POLYGON);
    glVertex2i(370, 130);
    glVertex2i(400, 140);
    glVertex2i(400, 0);
    glVertex2i(370, 0);
    glEnd();

    //lip high
    glColor3f(bc, bc, bc);
    glBegin(GL_POLYGON);
    glVertex2i(400, 140);
    glVertex2i(405, 130);
    glVertex2i(405, 0);
    glVertex2i(400, 0);
    glEnd();

    //lip
    glColor3f(bc, bc, bc);
    glBegin(GL_POLYGON);
    glVertex2i(405, 50);
    glVertex2i(420, 60);
    glVertex2i(420, 0);
    glVertex2i(405, 0);
    glEnd();

    //small building
    glColor3f(bc, bc, bc);
    glBegin(GL_POLYGON);
    glVertex2i(420, 60);
    glVertex2i(440, 60);
    glVertex2i(440, 0);
    glVertex2i(420, 0);
    glEnd();

    //small adj building
    glColor3f(bc, bc, bc);
    glBegin(GL_POLYGON);
    glVertex2i(440, 140);
    glVertex2i(480, 135);
    glVertex2i(480, 0);
    glVertex2i(440, 0);
    glEnd();

    //mid size
    glColor3f(bc, bc, bc);
    glBegin(GL_POLYGON);
    glVertex2i(485, 160);
    glVertex2i(500, 170);
    glVertex2i(500, 0);
    glVertex2i(485, 0);
    glEnd();

    //lip
    glColor3f(bc, bc, bc);
    glBegin(GL_POLYGON);
    glVertex2i(500, 170);
    glVertex2i(530, 170);
    glVertex2i(530, 0);
    glVertex2i(500, 0);
    glEnd();

    //b
    glColor3f(bc, bc, bc);
    glBegin(GL_POLYGON);
    glVertex2i(500, 200);
    glVertex2i(550, 200);
    glVertex2i(550, 0);
    glVertex2i(500, 0);
    glEnd();
    //b
    glColor3f(bc, bc, bc);
    glBegin(GL_POLYGON);
    glVertex2i(550, 55);
    glVertex2i(560, 55);
    glVertex2i(560, 0);
    glVertex2i(500, 0);
    glEnd();
    //
    glColor3f(bc, bc, bc);
    glBegin(GL_POLYGON);
    glVertex2i(560, 70);
    glVertex2i(580, 73);
    glVertex2i(580, 0);
    glVertex2i(560, 0);
    glEnd();
    //
    glColor3f(bc, bc, bc);
    glBegin(GL_POLYGON);
    glVertex2i(580, 73);
    glVertex2i(595, 73);
    glVertex2i(595, 0);
    glVertex2i(580, 0);
    glEnd();
    //
    glColor3f(bc, bc, bc);
    glBegin(GL_POLYGON);
    glVertex2i(595, 73);
    glVertex2i(615, 70);
    glVertex2i(615, 0);
    glVertex2i(595, 0);
    glEnd();
    //
    glColor3f(bc, bc, bc);
    glBegin(GL_POLYGON);
    glVertex2i(620, 80);
    glVertex2i(650, 80);
    glVertex2i(650, 0);
    glVertex2i(620, 0);
    glEnd();
    //
    glColor3f(bc, bc, bc);
    glBegin(GL_POLYGON);
    glVertex2i(650, 190);
    glVertex2i(690, 195);
    glVertex2i(690, 0);
    glVertex2i(650, 0);
    glEnd();
    //
    glColor3f(bc, bc, bc);
    glBegin(GL_POLYGON);
    glVertex2i(650, 190);
    glVertex2i(690, 195);
    glVertex2i(690, 0);
    glVertex2i(650, 0);
    glEnd();
    //
    glColor3f(bc, bc, bc);
    glBegin(GL_POLYGON);
    glVertex2i(690, 195);
    glVertex2i(710, 195);
    glVertex2i(710, 0);
    glVertex2i(690, 0);
    glEnd();
    //
    glColor3f(bc, bc, bc);
    glBegin(GL_POLYGON);
    glVertex2i(720, 60);
    glVertex2i(760, 60);
    glVertex2i(760, 0);
    glVertex2i(720, 0);
    glEnd();
    //
    glColor3f(bc, bc, bc);
    glBegin(GL_POLYGON);
    glVertex2i(762, 90);
    glVertex2i(790, 95);
    glVertex2i(790, 0);
    glVertex2i(762, 0);
    glEnd();
    //
    //
    glColor3f(bc, bc, bc);
    glBegin(GL_POLYGON);
    glVertex2i(790, 60);
    glVertex2i(800, 60);
    glVertex2i(800, 0);
    glVertex2i(790, 0);
    glEnd();


}


void citySkyLine()
{
    //Roof
    //glClear(GL_COLOR_BUFFER_BIT);     // Clear display window
    // Set line segment color as glColor3f(R,G,B)

    // Building 1
    glColor3f(0.25, 0.25, 0.25);
    glBegin(GL_POLYGON);
    glVertex2i(80, 250);
    glVertex2i(170, 250);
    glVertex2i(170, 0);
    glVertex2i(80, 0);
    glEnd();

    //building 2
    glColor3f(0.25, 0.25, 0.25);
    glBegin(GL_POLYGON);
    glVertex2i(300, 230);
    glVertex2i(420, 280);
    glVertex2i(420, 0);
    glVertex2i(300, 0);
    glEnd();

    //building 3
    glColor3f(0.25, 0.25, 0.25);
    glBegin(GL_POLYGON);
    glVertex2i(500, 260);
    glVertex2i(620, 260);
    glVertex2i(620, 0);
    glVertex2i(500, 0);
    glEnd();

    //building 3 roof
    glColor3f(0.25, 0.25, 0.25);
    glBegin(GL_POLYGON);
    glVertex2i(500, 260);
    glVertex2i(620, 260);
    glVertex2i(560, 290);
    glEnd();

    //building 4
    glColor3f(0.25, 0.25, 0.25);
    glBegin(GL_POLYGON);
    glVertex2i(750, 460);
    glVertex2i(880, 460);
    glVertex2i(750, 0);
    glVertex2i(880, 0);
    glEnd();

    //building 4 lip
    glColor3f(0.25, 0.25, 0.25);
    glBegin(GL_POLYGON);
    glVertex2i(735, 470);
    glVertex2i(755, 470);
    glVertex2i(735, 0);
    glVertex2i(790, 0);
    glEnd();

}


void drawBitmapText(char *string,float x,float y,float z) 
{  
    char *c;
    glRasterPos3f(x, y, z);

    for (c=string; *c != '\0'; c++) 
    {
        glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_10, *c);
    }
}

void Timer( int value )
{
   if( value ) glutPostRedisplay();
   glutTimerFunc(40,Timer,value);
}

void visibility(int state)
{
 switch (state)
 {
   case GLUT_VISIBLE:
             Timer(1);
             break;
   case GLUT_NOT_VISIBLE:
             Timer(0);
             break;
   default:
             break;
 }
}

void display(void)
{
   fScale += 0.005f;
   int bSpeed=-frame/10;//background speed
   int sSpeed =0;
   glClear(GL_COLOR_BUFFER_BIT);
   frame++;
       if((frame>=0) && (frame<200))
       {
           background();
        glPushMatrix();
            glTranslatef(bSpeed,0,0);
            backdrop();
         glPopMatrix();
            citySkyLine();
            if ((frame>50))
            {
                 window();
            }
            if ((frame>100) && (frame <= 200))
            {

                glClear(GL_COLOR_BUFFER_BIT);
                glPushMatrix();
                glScalef(fScale, fScale,1);
                backdrop();
                citySkyLine();
                window();
                glPopMatrix();
            }
       }
        if ((frame>=200) && (frame <500))
        {
            glClear(GL_COLOR_BUFFER_BIT);
                glPushMatrix();
                glScalef(1.5, 1.5,1); //maintain zoom
                backdrop();
                citySkyLine();
                if ((frame>=330) && (frame <500))
                {
                morphSpotlight(); //morph window to create spotlight
                }
                window();
                man();
                glPopMatrix();
                glDisable(GL_LIGHTING); //change text color
                if ((frame>=210) && (frame <250))
                {
                    glColor3f(1,1,1);
                    printText(300,310,3,GLUT_BITMAP_HELVETICA_18,"Is that someone at the door?");
                }
                if ((frame>=260) && (frame <300))
                {
                    glColor3f(1,1,1);
                    printText(280,310,3,GLUT_BITMAP_TIMES_ROMAN_24,"KNOCK KNOCK!");
                    printText(250,290,3,GLUT_BITMAP_TIMES_ROMAN_24,"Open up its the police!");
                }
                if ((frame>=310) && (frame <360))
                {
                    glColor3f(1,1,1);
                    printText(300,310,3,GLUT_BITMAP_HELVETICA_18,"Oh no! I'm done for!");
                }

        }
   glFlush();


}

int main(int argc, char ** argv)
{
    // Initialize GLUT
    glutInit(&argc, argv);
    // Set display mode
    glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
    // Set top - left display window position.
    glutInitWindowPosition(100, 100);
    // Set display window width and height
    glutInitWindowSize(1200, 600);
    // Create display window with the given title
    glutCreateWindow("Animation in OpenGL ");
    // Execute initialization procedure
    init();
    // Send graphics to display window
    glutDisplayFunc(display);
        glutVisibilityFunc(visibility);
    // Display everything and wait.
    glutMainLoop();
}
\$\endgroup\$
4
\$\begingroup\$

Was just hoping someone could take a look and give me some pointers.

Sure, there you go:

0x7fff52ce196c
0x7fff52ce1960
0x7fff52ce195c
0x7fff52ce1950

:P


If you got past the lame joke, here are some suggestions that can improve your code:

Avoid global mutable data

It is tempting to just drop a few globals on such a small single-source-file program, but that's a weak escuse for doing so. Passing your data as function arguments is no trouble at all and has so many benefits over global variables.

Function parameters give you explicit dependencies, and that makes it so much easier reasoning about the code. Consider making those globals at the top level local to each function that uses them, passing as parameters where appropriate.

You can also group related data to make things simpler, for instance, you could have a Line structure:

struct Line {
    Point start;
    Point end;
};

Speaking of structures...

Use struct for "dumb" data aggregates

The usual convention in C++ (note that this is not a language requirement, just a convention for programmers) is to use class for "smart" types, things with methods and private data, while struct is used for simple data aggregates with public fields.

My suggestion is to make your point a simple struct for that reason. I'd also suggest using a capitalized first letter for Point, that's a very common naming convention for user-defined types, so you can for example declare Point point{};.

Don't Repeat Yourself!

This block of code is repeated dozens of times, only changing the parameters:

glColor3f(bc, bc, bc);
glBegin(GL_POLYGON);
glVertex2i(0, 35);
glVertex2i(900, 35);
glVertex2i(900, 0);
glVertex2i(0, 0);
glEnd();

Code duplication is one of your worst enemies, fight it by defining reusable functions:

struct Color {
    float r, g, b;
};

struct Rectangle {
    int x, y;
    int width, height;
};

void drawGLRectangle(const Color& color, const Rectangle& rect)
{
    glColor3f(color.r, color.g, color.b);
    glBegin(GL_QUADS);
    glVertex2i(rect.x, rect.y);
    glVertex2i(rect.x, rect.y + rect.height);
    glVertex2i(rect.x + rect.width, rect.y + rect.height);
    glVertex2i(rect.x + rect.width, rect.y);
    glEnd();
}

Also note how I use structures to group related variables. Passing a Rectangle and a Color conveys a lot more meaning than passing a bunch of floats and ints, plus it makes a lot harder to mismatch the parameters, since a Color doesn't convert to a Rectangle.

Side Note: I think you can use GL_QUADS for glBegin(), since you're drawing a simple rectangle.

Use more named constants

You have a bunch of magic numbers in your code, which I have no idea of the meaning. You will probably also forget yourself why a particular value was used here-and-there six months from now, so replace as many of them as you can with named constants that describe what that value is meant to represent and why it was chosen. Where you think a constant is not necessary, at least provide a comment.

Use const pointer where appropriate

When taking a read-only parameter by pointer or reference, always use const to clearly indicate that and disallow modification:

//                  V---- here
void drawBitmapText(const char* string, float x, float y, float z) 
{
    glRasterPos3f(x, y, z);

    //   V---- and here
    for (const char* c = string; *c != '\0'; c++) 
    {
        glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_10, *c);
    }
}

Fix your indentation

Your code is not very consistently indented and this hurts readability. Manually indenting code is a thing of the past, install a formatting tool like Clang-Format in your editor, it works wonders!

Classes can help you better organize your program

Lastly a suggestion: Take a look at classes and some concepts of Object Oriented Programming (OOP). It might help you better organize your code in the future. You can start from here.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.