Quadrotor drone in glut?

I wanna know if is it possible and easy to implement a simple quadrotor in glut? I’m a beginner in glut however I don’t have problem with the mathematical model of the quadrotor and the dynamic equations of the system. Any books, tutorials about that??

Neither GLUT nor OpenGL has anything to do with simulating movement. It can draw a model. It can draw a model in a different place from last frame. It’s up to you to decide where to draw it so that it looks like it’s moving.

In short, all of the major work of this is outside of the bounds of OpenGL.

I have find a link that draw an dynamic helicopter at http://www.staroceans.net/helicopter-camera.htm

I think that is more logical to add first the “simple” handling of the dynamic equation of a single helicoptere with only the main big rotor in work in the air for beginning, add the handling of the tail rotor after … and extend this to a quadrator at the end

I have begin to add the handling of the vertival elevation of the helicopter using keys 8 and 2 :

The helicopter.h file


#include <GL/glut.h>

//the view changing parameter
const GLfloat ViewAngleOffset=0.01;
//const GLfloat ViewAngleLROffset=10*ViewAngleOffset;
//const GLfloat ZoomAngleOffset=0.5;
//const GLfloat ZoomRatioOffset=0.5;
const GLfloat ZoomRadiusOffset=0.05;

//the view init parameter
const GLfloat ViewStartRadius=5;
const GLfloat ViewStartTheta=60;
const GLfloat ViewStartPhi=20;

//const GLfloat ViewStartRatio=1;

//model start state parameter
const GLfloat StartAxisAnglex=0;
const GLfloat StartAxisAngley=0;
const GLfloat StartAxisAnglez=0;

//the view volume init parameter
const GLfloat SIZE= 1000;            // To deal with the view volume
const GLfloat NEAR_Z= 0.001;
const GLfloat FAR_Z= 100.0;

//color advance offset
const GLint MaximumColorNumber=10;
const GLint ColorAdvanceStep=10;
const GLint ColorStartIndex=3;
const GLfloat ColorAdvanceOffset=0.09;
const GLfloat DefaultAxisLength=10;

//constant PI
const GLfloat PI= 3.14159265;        // An excessively abused used constant !!

//cockpit relative size
const GLfloat CockpitWidth=1.5;
const GLfloat CockpitHeight=1.0;
const GLfloat Front_Rear_Ratio=0.15;


//skid relative size
const GLfloat SkidSupportHeight=0.5;
const GLfloat SkidSupportDistance=2;
const GLfloat SkidWidth=10;
const GLfloat SkidRadius=0.1;
const GLfloat SkidJointOffset=0.8;
const GLfloat BoomLength=10;
const GLfloat TailRotorSupportRadius=0.3;
/*const */ GLfloat TailRotorSupportOffset = TailRotorSupportRadius * 0.5;

//utility function for drawing models
void drawOval(GLfloat x, GLfloat y, GLfloat z);
void drawSphere(float fRadius, GLint slices, GLint rings);
void drawCylinder(float fTopR, float fBottomR, float fHeight);
void drawDisk(GLdouble innerRadius, GLdouble outerRadius, GLint slices, GLint rings,
    GLdouble startAngle, GLdouble sweepAngle);
void drawShearCylinder(GLfloat topRad, GLfloat bottomRad, GLfloat height, GLfloat angle);
void drawPatialTorus(GLfloat rCrossSection, GLfloat rAxial, GLfloat sweepAngle);

//small helper functions
GLfloat deg2rad(GLfloat degree);
void setColor();// a little fancy random color generator
void initColorArray();



//model helper functions for each module

void drawSkidSupport(const GLfloat SkidSupportDistance, const GLfloat SkidSupportHeight);


void divider_x(void(*pfunc)(), GLfloat start, GLfloat end, GLint num);
void divider_y(void(*pfunc)(), GLfloat down, GLfloat up, GLint num);
void drawRotor();
void drawHelicopter();

void drawScene();

//setup functions
void init (void);
void showMenu(void);
void showReferenceAxis(void);


//callback functions
void keyboardCallbackProc(unsigned char key, int x, int y);
void specialCallbackProc (int key, int x, int y);

The helicopter.cpp file :


/****************************************************************************************/
/* 
/* Assignment3 : Building a helicopter model.
/* Points to notice: 
/*        1.  Implemented helicopter forward/backward motion and both first-person,
            third-person camera are followed with the helicopter motion.
        2.  Yaw,pitch and roll operations are smoothed by using sin/cos functions.
        3.  Yaw,pitch and roll are limited in a limited angle so that no flipping view 
            occurs.
        4.  All other functions of previous assignment are preserved except that rotation
            around x/y/z axis are replaced by yaw/pitch/roll. Helicopter are located in 
            new position such that rotation axis is in pilot's position in cockpit.
        5.  To implement moving third-person view camera left/right about cockpit of 
            helicopter is a little bit tricky because if you don't bookkeep if last operation
            is same kind of operation, you have no way to make viewer convince that you are
            moving left/right. Therefore I used a buffer to store information of last 
            operation. If last operation is exactly this kind of operation, I will use
            the very first dat of both "theta and radius". Otherwise refresh these data.
        6.  There is little change in modeling helicopter from previous assignment.
        7.  The usage is exactly like menu in function "showmenu".
                printf("
 Use w/W to toggle between wireframe and shaded model.");
                printf("
 Use o/O to toggle between ortho and perspective views.");
                printf("
 Use a/A to show/hide the reference axis <x = RED, y = GREEN, z = BLUE>.");
                printf("
 Use the f/F,b/B keys to approach and leave model.");
                printf("
 Use arrow up/down keys for camera rotations up/down about origin.");
                printf("
 Use arrow left/right keys for camera rotations left/right about origin.");

                printf("
 Use s/S keys to start/stop spinning of rotor of helicopter");
                printf("
 Use 1 keys to toggle first-person camera view.");
                printf("
 Use 3 keys to toggle third-person camera view.");

                printf("
 Use p/P keys to pitch helicopter and first-person view camera.");
                
                printf("
 Use y/Y keys to yaw helicopter and first-person view camera.");
                printf("
 Use r/R keys to roll helicopter and first-person view camera.");
                
                printf("
 Use t/T keys to move helicopter backward/forward along x-axis \
                    and first-person and third-person view camera.");
                
                printf("
 Use h/H keys to move helicopter left/right along z-axis \
                    and first-person and third-person view camera.");

                printf("
 Use i/I key to move third-person view camera up/down about \
                    cockpit of helicopter
");
                
                printf("
 Use k/K key to rotate third-person view camera up/down about \
                    cockpit of helicopter
");

                printf("
 Use j/J key to move third-person view camera left/right about \
                    cockpit of helicopter
");

                printf("
 Use l/L key to rotate third-person view camera left/right about \
                    cockpit of helicopter
");

                printf("
 Use 2/8 key to handle vertical elevation (YLP) 
");

                printf("
 Use d/D to restore all default states.");
                printf("
 Use m/M to see the menu again.");
                
                printf("
 Use escape key to exit.
");

/* DATED 31th, oct, 2005        
    Qingzhe Huang 5037735    nickhuang99@hotmail.com
/* 
/****************************************************************************************/

#include <GL/glut.h>            // This is assuming that you have glut.h set in your include path.
#include <stdio.h>            // Other necessary program related includes.
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include "helicopter.h"

/*
GLdouble xy[4] = {0.0, 0.0, 1.0, 0.0};
GLdouble yz[4] = {1.0, 0.0, 0.0, 0.0};
GLdouble zx[4] = {0.0, 1.0, 0.0, 0.0};
*/
int curColorIndex = ColorStartIndex;
const GLfloat MaxRotatingAngle=30;
const GLfloat MovementSpeed=0.3;
GLfloat tailRotorRotatingAngle=0;
GLfloat mainRotorRotatingAngle=0;
GLfloat mainRotorSpinSpeed=0, tailRotorSpinSpeed=0;
bool bCamera=true;
GLfloat oldLeftTheta=0, oldLeftRadius=0, lastLeftTheta=0, lastLeftRadius=0, 
    totalLeftAngleOffset=0;
GLfloat oldRightTheta=0, oldRightRadius=0, lastRightTheta=0, lastRightRadius=0, 
    totalRightAngleOffset=0;

//float x_Angle = StartAxisAnglex;        // The rotation angles about x, y and z axis.
//float y_Angle = StartAxisAngley;
//float z_Angle = StartAxisAnglez;

GLfloat yaw=0, pitch=0, roll=0;
GLfloat viewPortw, viewPorth;
//GLfloat ratio=ViewStartRatio;

bool bAxis;            // To show or not to show the reference axis.

bool bWire;            // To wireframe/not.

GLfloat fovy = 90.0;        // For Perspective projections.
int H= SIZE, W= SIZE;
GLfloat fViewVol;            // For Orthographic projections.
enum {PERSPECTIVE, ORTHOGRAPHIC} ePrjn = PERSPECTIVE;

GLfloat move_x=0, move_z=0, move_y=0;

//the polar coordinate parameter
GLfloat radius=ViewStartRadius, theta=deg2rad(ViewStartTheta), phi=deg2rad(ViewStartPhi);

GLfloat colorArray[MaximumColorNumber][3];


GLfloat deg2rad(GLfloat degree)
{
    return degree/360.0*2*PI;
}
//this is just set color from color table initialized at beginning.
void setColor()
{
    curColorIndex++;
    curColorIndex%=MaximumColorNumber;
    glColor3f(colorArray[curColorIndex][0], colorArray[curColorIndex][1],
        colorArray[curColorIndex][2]);
}

/*
void setColor()
{
    GLfloat r,g,b;
    curColorIndex++;
    if (curColorIndex>ColorAdvanceStep)
    {
        r=1;
    }
    else
    {
        r=(curColorIndex%ColorAdvanceStep)*ColorAdvanceOffset;
    }
    if (curColorIndex>2*ColorAdvanceStep)
    {
        g=1;
    }
    else
    {
        g=curColorIndex%(2*ColorAdvanceStep)*ColorAdvanceOffset;
    }
    if (curColorIndex>3*ColorAdvanceStep)
    {
        b=1;
    }
    else
    {
        b=curColorIndex%(ColorAdvanceStep*3)*ColorAdvanceOffset;
    }

    glColor3f(r,g,b);
}
*/

void initColorArray()
{
    GLfloat base[3]={0.8,0.5,0.2};

    for (int i=0; i<MaximumColorNumber; i++)
    {
        for (int j=0; j<3; j++)
        {
            base[j]+=0.1;
            if (base[j]>1.0)
            {
                base[j]-=1.0;
            }
            colorArray[i][j]=base[j];
        }
    }
}




/****************************************************************************************/
void showMenu(void)
                // Self Explanatory.
{
    printf("



 COMP471 ASSIGNMENT3 HELICOPTER. ");
    printf("
---------------------------------------------------------------");
    printf("
 Operations: ");
    printf("
 Use w/W to toggle between wireframe and shaded model.");
    printf("
 Use o/O to toggle between ortho and perspective views.");
    printf("
 Use a/A to show/hide the reference axis <x = RED, y = GREEN, z = BLUE>.");
    printf("
 Use the f/F,b/B keys to approach and leave model.");
    printf("
 Use arrow up/down keys for camera rotations up/down about origin.");
    printf("
 Use arrow left/right keys for camera rotations left/right about origin.");

    printf("
 Use s/S keys to start/stop spinning of rotor of helicopter");
    printf("
 Use 1 keys to toggle first-person camera view.");
    printf("
 Use 3 keys to toggle third-person camera view.");

    printf("
 Use p/P keys to pitch helicopter and first-person view camera.");
    
    printf("
 Use y/Y keys to yaw helicopter and first-person view camera.");
    printf("
 Use r/R keys to roll helicopter and first-person view camera.");
    
    printf("
 Use t/T keys to move helicopter backward/forward along x-axis \
        and first-person and third-person view camera.");
    
    printf("
 Use h/H keys to move helicopter left/right along z-axis \
        and first-person and third-person view camera.");

    printf("
 Use i/I key to move third-person view camera up/down about \
        cockpit of helicopter
");
    
    printf("
 Use k/K key to rotate third-person view camera up/down about \
        cockpit of helicopter
");

    printf("
 Use j/J key to move third-person view camera left/right about \
        cockpit of helicopter
");

    printf("
 Use l/L key to rotate third-person view camera left/right about \
        cockpit of helicopter
");

    printf("
 Use 2/8 key to handle vertical elevation (YLP) 
");

    printf("
 Use d/D to restore all default states.");
    printf("
 Use m/M to see the menu again.");
    
    printf("
 Use escape key to exit.
");

}

/****************************************************************************************/
void init (void)
                        // Initializes the gl Graphics env and the program variables.
{
    glMatrixMode(GL_PROJECTION);
                            // Set the current openGL matrix to GL_PROJECTION ie projection matrix.
    glLoadIdentity();
                        // Load identitiy values in the above.
    if(ePrjn == PERSPECTIVE)
    {
        gluPerspective(fovy, (GLfloat)W/(GLfloat)H, NEAR_Z, FAR_Z);
                            // This sets the view volume to be a Perspective one.
    }
    else
    {
        fViewVol = 50.0;
        glOrtho(-fViewVol, fViewVol, -fViewVol, fViewVol, NEAR_Z, FAR_Z);
                            // This sets the view volume to be a Orthographic one.
    }


    glMatrixMode(GL_MODELVIEW);    
                            // Change the current matrix mode to Model-View matrix.
    glLoadIdentity();
                            

    glClearColor (0.5, 0.5, 0.5, 0.0);
                        // set the background color to black.

    glShadeModel(GL_SMOOTH);
    glEnable(GL_DEPTH_TEST);
    bAxis = true;
    
    bWire = false;
    glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
    showMenu();

    initColorArray();
}


/****************************************************************************************/
void keyboardCallbackProc(unsigned char key, int x, int y)
                        // This is the callback procedure for capturing OpenGL Keyboard events.
{
    GLfloat temp;
    
    
    switch(key)
    {
    case '1':
        bCamera=false;
        break;
    case '3':
        bCamera=true;
        break;
    case 'd':
    case 'D':
        pitch=yaw=roll=0;
        move_x=move_z=0;
        break;
    case 'a':                // Show axes.
    case 'A':
        bAxis=!bAxis;        
        break;
    
    case 'O':                //Change to orthographic projections
        ePrjn = ORTHOGRAPHIC;
        init();
        break;
    case 'o':
        ePrjn = PERSPECTIVE;        
        init();
        break;
    case 'C':
    case 'c' :                // Clear viewing parameters and return to initial view.
        init();
        break;

    case 'f':
    case 'F':
        if (ePrjn==    PERSPECTIVE)
        {
            if (radius>ZoomRadiusOffset)
            {
                radius-=ZoomRadiusOffset;
            }
        }
        break;
    case 'b':
    case 'B':
        if (ePrjn==    PERSPECTIVE)
        {
            radius+=ZoomRadiusOffset;
        }
        break;

    case 'M' :
    case 'm' :
        showMenu();
        break;
    case 'w':
    case 'W':
        if (bWire == false)            
        {
            bWire = true;    // Wireframe model.
            glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
        }
        else
        {
            bWire = false;    // Solid model.
            glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
        }
        break;
    case 'P':                //Change to perspective projections    
    case 'p':
        pitch+=2;
        break;
    case 'r':
    case 'R':
        roll+=1;
        break;
    case 'y':
    case 'Y':
        yaw+=2;
        break;
    case 't':
        move_x+=MovementSpeed;
        break;
    case 'T':
        move_x-=MovementSpeed;
        break;
    case 'h':
        move_z+=MovementSpeed;
        break;
    case 'H':
        move_z-=MovementSpeed;
        break;
    case 's':
        mainRotorSpinSpeed=15;
        tailRotorSpinSpeed=20;
        break;
    case 'S':
        mainRotorSpinSpeed=0;
        tailRotorSpinSpeed=0;
        break;
    case 'i':    
        temp=theta;
        theta-=ViewAngleOffset;
        if (theta<=0)
        {
            theta=temp;
        }
        else
        {
            radius=radius*sin(temp)/sin(theta);
        }
        break;
    case 'I':
        temp=theta;
        theta+=ViewAngleOffset;
        if (theta>=PI)
        {
            theta=temp;
        }
        else
        {
            radius=radius*sin(temp)/sin(theta);
        }
        break;
    case 'k':
        temp=theta;
        theta-=ViewAngleOffset;
        if (theta<=0)
        {
            theta=temp;
        }
        break;
    case 'K':
        temp=theta;
        theta+=ViewAngleOffset;
        if (theta>=PI)
        {
            theta=temp;
        }
        break;
    case 'j':
        //this is the first time or last operation is NOT this operation
        if (oldLeftTheta==0&&oldLeftRadius==0||lastLeftTheta!=theta||lastLeftRadius!=radius)
        {
            oldLeftTheta=theta;
            oldLeftRadius=radius;
            totalLeftAngleOffset=ViewAngleOffset;
        }
        else
        {
            totalLeftAngleOffset+=ViewAngleOffset;
        }

        //temp=radius;
        phi-=ViewAngleOffset;
        theta=atan(tan(oldLeftTheta)/cos(totalLeftAngleOffset));
        radius=oldLeftRadius*cos(oldLeftTheta)/cos(theta);
        lastLeftTheta=theta;
        lastLeftRadius=radius;        
        break;
    case 'J':
        //this is the first time or last operation is NOT this operation
        if (oldRightTheta==0&&oldRightRadius==0||lastRightTheta!=theta||lastRightRadius!=radius)
        {
            oldRightTheta=theta;
            oldRightRadius=radius;
            totalRightAngleOffset=ViewAngleOffset;
        }
        else
        {
            //if last time is same operation, we increment angle offset
            totalRightAngleOffset+=ViewAngleOffset;
        }
    
        phi+=ViewAngleOffset;
        theta=atan(tan(oldRightTheta)/cos(totalRightAngleOffset));
        radius=oldRightRadius*cos(oldRightTheta)/cos(theta);
        lastRightTheta=theta;
        lastRightRadius=radius;        
        break;
    case 'l':
        phi-=ViewAngleOffset;
        break;
    case 'L':
        phi+=ViewAngleOffset;

    case '8' : 
        move_y++;
        break;
    case '2' : 
        if( move_y > 0 ) 
            move_y--;
        break;

        
        break;
    case 27 :                //ESCAPE Code for exiting program.
        exit(1);
        break;
    }
    glutPostRedisplay();    // Direct the glut system to redisplay the screen.
}

/****************************************************************************************/
// This is the callback procedure for capturing special charater events.
void specialCallbackProc (int key, int x, int y)                        
{
    GLfloat temp;
    switch (key)        
    {
        case GLUT_KEY_LEFT:        // Rotate the model about the y-axis.
            phi -= ViewAngleOffset;
            break;

        case GLUT_KEY_RIGHT:    
            phi += ViewAngleOffset;
            break;

        case GLUT_KEY_UP :        // Rotate the model about the x-axis.
            temp=theta;
            theta -= ViewAngleOffset;
            if (theta<=0)
            {
                theta=temp;
            }
            break;

        case GLUT_KEY_DOWN :
            temp=theta;
            theta += ViewAngleOffset;
            if (theta>=PI)
            {
                theta=temp;
            }
            break;
    }
    glutPostRedisplay();
}


/****************************************************************************************/
void reShapeCallbackProc(int w, int h)
                        // This is the callback procedure for capturing reShape event for window resizing.
{
    glViewport(0, 0, w, h);
                        // Set the viewport to current window size.
    W = w;
    H = h;

    glMatrixMode(GL_PROJECTION); 
    glLoadIdentity();
    if(ePrjn == PERSPECTIVE)
    {
        gluPerspective(fovy, (GLfloat)W/(GLfloat)H, NEAR_Z, FAR_Z);
    }
    else
    {
        if (w > h)
        {
            W = (fViewVol * w) / h;
            H = fViewVol;
        }
        else
        {
            W = fViewVol;
            H = (fViewVol * h) / w;
        }
        glOrtho(-W, W, -H, H, NEAR_Z, FAR_Z);
    }                    // Change the view volume to maintain the aspect ratio wrt to viewport.

    glMatrixMode(GL_MODELVIEW);

    glutPostRedisplay();
}


/****************************************************************************************/
void drawSphere(float fRadius, GLint slices, GLint rings)
                            // Used to generate a Sphere shape.
{
    GLUquadricObj* pObj;
    pObj =  gluNewQuadric();
                            // Creates a new quadrics object and returns a pointer to it.

    gluQuadricDrawStyle(pObj, GLU_FILL);

    gluSphere(pObj, fRadius,slices, rings);
                            // Draw the sphere with a radius : fRadius.
    gluDeleteQuadric(pObj);
                            // Free the Quadric

}

/****************************************************************************************/
// Used to generate a cylinder shape.
void drawCylinder(float fTopR, float fBottomR, float fHeight)                        
{
    GLUquadricObj* pObj;
                            // To keep the original texture intact we need to set the current color to WHITE.

    pObj = gluNewQuadric();
                            // Creates a new quadrics object and returns a pointer to it.
    gluQuadricDrawStyle(pObj, GLU_FILL);

    gluCylinder(pObj, fTopR, fBottomR, fHeight, 20, 20);
                            // Draw the cylinder with a radius : fRadius.
    gluDeleteQuadric(pObj);
                            // Free the Quadric

}

/****************************************************************************************/

// Used to generate a cylinder shape.
void drawDisk(GLdouble innerRadius, GLdouble outerRadius, GLint slices, GLint rings,
GLdouble startAngle, GLdouble sweepAngle)
{
    GLUquadricObj* pObj;

    pObj = gluNewQuadric();
                            // Creates a new quadrics object and returns a pointer to it.
    gluQuadricDrawStyle(pObj, GLU_FILL);

    gluPartialDisk(pObj, innerRadius, outerRadius, slices, rings, startAngle, sweepAngle);
                        // Draw the cylinder with a radius : fRadius.
    gluDeleteQuadric(pObj);
                            // Free the Quadric
}

/****************************************************************************************/
void showReferenceAxis(void)
                        // Draw the reference axis
{
    if(bAxis)
    {
     glPushAttrib(GL_ALL_ATTRIB_BITS);
                        // Pushes attributes like current color to attribute stack.
     glBegin(GL_LINES);
                        // X axis red
      glColor3f(1, 0, 0);
      glVertex3f(0, 0, 0);
      glVertex3f(DefaultAxisLength, 0, 0);
                        // Y axis green
      glColor3f(0, 1, 0);
      glVertex3f(0, 0, 0);
      glVertex3f(0, DefaultAxisLength, 0);
                        // Z axis blue
      glColor3f(0, 0, 1);
      glVertex3f(0, 0, 0);
      glVertex3f(0, 0, DefaultAxisLength);
      glEnd();
      glPopAttrib();
                        // // Pops attributes like current color from the attribute stack and sets as current.
    }
}

/******************************************************************************/

void drawScene()
{
    int i;
    const GLfloat GroundHeight=-4;
    const GLfloat TrafficSignLength=1, TrafficSignWidth=0.5;
    const GLfloat Sign_Y_Offset=0;
    const GLfloat View_Size=100;
    const GLfloat BallonSize=0.5;

    glPushMatrix();

        // YLP 27/04/2013 : add vertical elevation
        glTranslatef(0, -move_y, 0);

        glColor4f(0.0, 0.8, 0.0,1);
        glLineWidth(2);
        for (i=0; i<100; i++)
        {    
            glBegin(GL_LINES);
            glVertex3f(-View_Size, GroundHeight,
                -View_Size+i*TrafficSignLength*2);
            glVertex3f(View_Size, GroundHeight, 
                -View_Size+i*TrafficSignLength*2);
            
            glVertex3f(-View_Size+i*TrafficSignLength*2, GroundHeight, -View_Size);
            glVertex3f(-View_Size+i*TrafficSignLength*2, GroundHeight, View_Size);
            glEnd();        
        }

        glColor4f(1,0,0.7,1);
        glPushMatrix();
            glTranslatef(-20, 2, 6);
            for (i=0; i<10; i++)
            {
                glTranslatef(TrafficSignLength*8, 0, 0);  
        
                glScalef(1, 1.3, 1);
                glColor4f(1,0.9-i*0.1,0.1+i*0.1,1);
                glutSolidSphere(BallonSize, 30, 30);
                glBegin(GL_LINES);
                    glVertex3f(0, -BallonSize/1.3,0);
                    glVertex3f(0, -BallonSize*2,0);
                glEnd();

            }
        glPopMatrix();
        glPushMatrix();
            glTranslatef(-20, 2, -6);
            for (i=0; i<10; i++)
            {
                glTranslatef(TrafficSignLength*8, 0, 0);  
                glScalef(1, 1.3, 1);
                glColor4f(1,0.1+i*0.1,0.9-i*0.1,1);
                glutSolidSphere(BallonSize, 30, 30);
                glBegin(GL_LINES);
                    glVertex3f(0, -BallonSize/1.3,0);
                    glVertex3f(0, -BallonSize*2,0);
                glEnd();
            }
        glPopMatrix();
            glTranslatef(-10, 2, 0);
            glColor4f(0.1, 0.6, 0.9, 0.9);
            glScalef(1, 1.3, 1);
            glutSolidSphere(BallonSize, 30, 30);
            glBegin(GL_LINES);
                glVertex3f(0, -BallonSize/1.3,0);
                glVertex3f(0, -BallonSize*2,0);
            glEnd();            

    glPopMatrix();

}

/******************************************************************************/


void drawHalfOval(GLfloat x, GLfloat y, GLfloat z)
{
    GLdouble xz_clip[4]={0, 1, 0, 0};
    glPushMatrix();
        glClipPlane (GL_CLIP_PLANE0, xz_clip);    
        glEnable (GL_CLIP_PLANE0);
        glScalef(x, y, z);
        glutSolidSphere(1.0, 20, 20);
        glDisable(GL_CLIP_PLANE0);
    glPopMatrix();
}

void divider_x(void(*pfunc)(), GLfloat start, GLfloat end, GLint num)
{
    GLdouble left_clip[4], right_clip[4];
    GLfloat step=(end-start)/num;

    glPushMatrix();
        left_clip[0]=1;
        left_clip[1]=left_clip[2]=right_clip[1]=right_clip[2]=0;
        left_clip[3]=-start;
        right_clip[0]=-1;
        right_clip[3]=start+step;

        glEnable(GL_CLIP_PLANE4);
        glEnable(GL_CLIP_PLANE5);
        do
        {
            setColor();
            glClipPlane(GL_CLIP_PLANE4, left_clip);
            glClipPlane(GL_CLIP_PLANE5, right_clip);
            pfunc();
            left_clip[3]+=step;
            right_clip[3]+=step;
        }
        while(right_clip[3]<end);
        glDisable(GL_CLIP_PLANE4);
        glDisable(GL_CLIP_PLANE5);
    glPopMatrix();
}

/******************************************************************************/
//this is a little funny function such that it divides an object into several
//partitions along y-axis. This is purely for fun

void divider_y(void(*pfunc)(), GLfloat down, GLfloat up, GLint num)
{
    GLdouble up_clip[4], down_clip[4];
    GLfloat step=(up-down)/num;

    glPushMatrix();
        down_clip[1]=1;
        down_clip[0]=down_clip[2]=up_clip[0]=up_clip[2]=0;
        down_clip[3]=-down;
        up_clip[1]=-1;
        up_clip[3]=down+step;

        glEnable(GL_CLIP_PLANE2);
        glEnable(GL_CLIP_PLANE3);
        do
        {
            setColor();
            glClipPlane(GL_CLIP_PLANE2, up_clip);
            glClipPlane(GL_CLIP_PLANE3, down_clip);
            pfunc();
            up_clip[3]+=step;
            down_clip[3]+=step;
        }
        while(up_clip[3]<up);
        glDisable(GL_CLIP_PLANE2);
        glDisable(GL_CLIP_PLANE3);
    glPopMatrix();
}

/******************************************************************************/


void drawWindow()
{
    GLdouble front_clip[4]={-1, 0, 0, CockpitWidth*Front_Rear_Ratio};
    
    glPushMatrix();
            
        //setColor();
        glColor4f(0.8,0.4,0.6,0.6);
        glClipPlane (GL_CLIP_PLANE1, front_clip);    
        glEnable (GL_CLIP_PLANE1);    
        glEnable (GL_BLEND);

        glDepthMask (GL_FALSE);

        glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);


        drawHalfOval(CockpitWidth, CockpitHeight, 1.0);
        glDepthMask (GL_TRUE);
        glDisable (GL_BLEND);
        glDisable(GL_CLIP_PLANE1);
    
    glPopMatrix();
}

//draw the cockpit of helicopter
void drawCockpit()
{
    void drawWindow();

    GLdouble rear_clip[4]={1, 0, 0, -CockpitWidth*Front_Rear_Ratio};

    glPushMatrix();
        glPushMatrix();
            //draw lower part of cockpit
            glRotatef(180, 0, 0, 1);
            setColor();
            drawHalfOval(CockpitWidth, 0.5*CockpitHeight, 1.0);
        glPopMatrix();
        glPushMatrix();
            //draw window part
    
            glClipPlane (GL_CLIP_PLANE1, rear_clip);    
            glEnable (GL_CLIP_PLANE1);    
            //draw upper-rear part of cockpit
            setColor();
            
            //front_clip[3]=CockpitWidth*0.8;
            drawHalfOval(CockpitWidth, CockpitHeight, 1.0);            
            glDisable(GL_CLIP_PLANE1);
            //divider_x(drawWindow, -CockpitWidth, CockpitWidth*Front_Rear_Ratio, 3);
            drawWindow();
    
        glPopMatrix();
        

    glPopMatrix();
}

void drawOval(GLfloat x, GLfloat y, GLfloat z)
{
    glPushMatrix();
    //setColor();
    glScalef(x, y, z);
    glutSolidSphere(1.0, 20, 20);
    glPopMatrix();
}

void drawBlade()
{
    const GLfloat BladeWidth=0.1;
    const GLfloat BladeHeight=0.08;
    const GLfloat BladeLength=1.0;//always 1.0
    glPushMatrix();
        //setColor();
        glTranslatef(0, 0, BladeLength);
        drawOval(BladeWidth, BladeHeight, BladeLength);
    glPopMatrix();
}

void drawMainRotor()
{
    const GLfloat MainRotorAxisHeight=0.4;
    const GLfloat MainRotorAxisRadius=0.05;

    glPushMatrix();
        setColor();
        glPushMatrix();
            //draw rotor axis
            glRotatef(-90, 1,0,0);
            drawCylinder(MainRotorAxisRadius, MainRotorAxisRadius, MainRotorAxisHeight);
        glPopMatrix();
            setColor();
            glTranslatef(0, MainRotorAxisHeight, 0);            
            drawRotor();
        
    glPopMatrix();
}

void drawShearCylinder(GLfloat topRad, GLfloat bottomRad, GLfloat height, GLfloat angle)
{
    //by default the angle is 45
    GLfloat matrix[16]=
    {
        1,0,0,0,
        1,1,0,0,
        0,0,1,0,
        0,0,0,1
    };
    //matrix[4]=cos(angle);
    //setColor();
    glPushMatrix();
        glMultMatrixf(matrix);
        glRotatef(-90, 1,0,0);
        glScalef(bottomRad, bottomRad, height);
        drawCylinder(topRad, bottomRad, height);

    glPopMatrix();
}

void drawSkidSupport(const GLfloat SkidSupportDistance, const GLfloat SkidSupportHeight)
{
    
    const GLfloat SkidSupportRadius=0.3;

    glPushMatrix();        
        
        glPushMatrix();            
            glTranslatef(-SkidSupportDistance/2.0, 0, SkidSupportDistance/2.0);
            //glRotatef(-90, 1,0,0);
            drawShearCylinder(SkidSupportRadius, SkidSupportRadius, SkidSupportHeight, 45);
        glPopMatrix();
        glPushMatrix();
            glTranslatef(SkidSupportDistance/2.0, 0, SkidSupportDistance/2.0);            
            drawShearCylinder(SkidSupportRadius, SkidSupportRadius, SkidSupportHeight, 45);
        glPopMatrix();
        glPushMatrix();
            glTranslatef(SkidSupportDistance/2.0, 0, -SkidSupportDistance/2.0);            
            drawShearCylinder(SkidSupportRadius, SkidSupportRadius, SkidSupportHeight, 45);
        glPopMatrix();
            glTranslatef(-SkidSupportDistance/2.0, 0, -SkidSupportDistance/2.0);            
            drawShearCylinder(SkidSupportRadius, SkidSupportRadius, SkidSupportHeight, 45);
    glPopMatrix();
}


void drawSkidBottom(const GLfloat SkidRadius, const GLfloat SkidJointOffset, 
                    const GLfloat SkidSupportDistance)
{
    const GLfloat ratio=1;
    GLfloat SkidLength=SkidSupportDistance+SkidJointOffset*2;

    glPushMatrix();
        setColor();
        glRotatef(90, 0, 1,0);
        glScalef(ratio*1.7, ratio, 1);
        drawCylinder(SkidRadius/ratio, SkidRadius/ratio, SkidLength);
    glPopMatrix();
}

void drawBoom()
{
    const GLfloat BoomJointRadius=BoomLength/3;
    const GLfloat BoomTopRadius=BoomLength/10;
    const GLfloat BoomBaseHeight=1;
    const GLfloat BoomBaseRadius=BoomLength/2;
    glPushMatrix();
        setColor();
        
        glPushMatrix();
            glRotatef(90, 0,1,0);
            drawCylinder(BoomJointRadius, BoomTopRadius, BoomLength);
        glPopMatrix();
            setColor();
            glTranslatef(-BoomBaseHeight, 0, 0);
            glRotatef(90, 0, 1, 0);
            drawCylinder(BoomBaseRadius, BoomJointRadius, BoomBaseHeight);
    glPopMatrix();
}

void drawTailRotor()
{
    const GLfloat ratio=0.3;
    glPushMatrix();
        //setColor();
        glScalef(ratio,ratio*5,ratio);
        glRotatef(tailRotorRotatingAngle, 0,1,0);
        drawMainRotor();

    glPopMatrix();
}
void drawTailBalancer()
{
    glPushMatrix();        
        glScalef(4, 4, 0.1);
        drawShearCylinder(TailRotorSupportRadius, TailRotorSupportRadius*0.5, 
            TailRotorSupportRadius, 45);
    glPopMatrix();
}

void drawTailBoom()
{
    //these helper functions will only be used by this function
    void drawBoom();
    void drawTailRotor();
    void drawTailBalancer();
    
    const GLfloat ratio=0.2;
    glPushMatrix();
        glPushMatrix();
            glScalef(ratio, ratio,ratio);
            divider_x(drawBoom, 0, BoomLength, 20);
            //drawBoom();
        glPopMatrix();
        glPushMatrix();
            //draw the tail 
            glTranslatef(BoomLength*ratio+TailRotorSupportOffset, 0, 0);
            setColor();
            glutSolidSphere(TailRotorSupportRadius, 20, 20);
        glPopMatrix();

        glPushMatrix();
            
            glTranslatef(BoomLength*ratio+TailRotorSupportOffset, 
                0, TailRotorSupportRadius);
            glScalef(0.8, 0.8, 0.8);
            glRotatef(90, 1, 0, 0);
            drawTailRotor();
        glPopMatrix();
        glPushMatrix();
            glTranslatef(BoomLength*ratio+TailRotorSupportOffset, 
                TailRotorSupportRadius-0.1, 0);
            drawTailBalancer();
            
        glPopMatrix();
            glTranslatef(BoomLength*ratio+TailRotorSupportOffset, 
                    -TailRotorSupportRadius+0.1, 0);
            glRotatef(180, 0, 1, 0);
            glRotatef(180, 0, 0, 1);
            drawTailBalancer();

    
    glPopMatrix();
}

void drawPatialTorus(GLfloat rCrossSection, GLfloat rAxial, GLfloat sweepAngle)
{
    GLdouble clipPlane0[4]={1,0,0,0};//y=0 plane
    GLdouble clipPlane1[4]={tan(sweepAngle), 1, 0, 0}; //y=x*tan(angle) plane

    glPushMatrix();
        //setColor();
        glRotatef(180, 0, 0,1);
        glTranslatef(0, -rAxial, 0);
        glClipPlane(GL_CLIP_PLANE0, clipPlane0);
        glClipPlane(GL_CLIP_PLANE1, clipPlane1);
        glEnable(GL_CLIP_PLANE0);
        glEnable(GL_CLIP_PLANE1);
        glutSolidTorus(rCrossSection, rAxial, 40, 40);
        glDisable(GL_CLIP_PLANE0);
        glDisable(GL_CLIP_PLANE1);
    glPopMatrix();
}
        
void drawSkid()
{
    //helper function only be called inside this
    void drawSkidBottom(const GLfloat SkidRadius, const GLfloat SkidJointOffset, 
                    const GLfloat SkidSupportDistance);

    glPushMatrix();
    
        drawSkidSupport(SkidSupportDistance, SkidSupportHeight);
        glPushMatrix();
            glTranslatef(-SkidSupportDistance/2.0-SkidJointOffset, 
                    -SkidRadius, SkidSupportDistance/2.0);
            drawSkidBottom(SkidRadius, SkidJointOffset, SkidSupportDistance);
        glPopMatrix();
        glPushMatrix();
            glTranslatef(-SkidSupportDistance/2.0-SkidJointOffset, 
                    -SkidRadius, -SkidSupportDistance/2.0);
            drawSkidBottom(SkidRadius, SkidJointOffset, SkidSupportDistance);
        glPopMatrix();
        glPushMatrix();
            glTranslatef(-SkidSupportDistance+0.2, -SkidRadius, -SkidSupportDistance/2.0);
            drawPatialTorus(SkidRadius+0.02, 2.3, 40);
        glPopMatrix();
            glTranslatef(-SkidSupportDistance+0.2, -SkidRadius, SkidSupportDistance/2.0);
            drawPatialTorus(SkidRadius+0.02, 2.3, 40);
    glPopMatrix();
    
}


void drawRotor()
{
    void drawBlade();

    glPushMatrix();    
        drawBlade();
        glRotatef(120, 0, 1, 0);
        drawBlade();
        glRotatef(120, 0, 1, 0);
        drawBlade();
    glPopMatrix();
}


//I don't want other application accidentally have a name conflict
//with my helper function, so I declare those function inside its calling
//function
void drawHelicopter()
{
    //the major module of helicopter
    void drawCockpit();
    void drawTailBoom();
    void drawMainRotor();
    void drawSkid();

    curColorIndex=ColorStartIndex;
    glPushMatrix();


        glPushMatrix();
            //glRotatef(180, 0, 1, 0);
            drawCockpit();
        glPopMatrix();
        
        glPushMatrix();
            glTranslatef(CockpitWidth-0.08, CockpitHeight/5, 0);
            //glRotatef(180, 0, 1, 0);
            glScalef(0.8, 0.4, 0.4);
            drawTailBoom();
        glPopMatrix();
        
        glPushMatrix();
            glTranslatef(0, CockpitHeight, 0 );
            glRotatef(mainRotorRotatingAngle, 0,1,0);
            drawMainRotor();
        glPopMatrix();
        glPushMatrix();
            glTranslatef(0, -SkidSupportHeight, 0);
            glScalef(0.6, 1, 0.5);
            drawSkid();
        glPopMatrix();    
        
    glPopMatrix();

}


/****************************************************************************************/
void displayCallbackProc (void)
                        // This is the callback procedure for capturing OpenGL Display events.
                        // All the 'happening' things happen here :)
{
    GLfloat eye_x, eye_y, eye_z;
    const GLfloat X_Offset=1.5;
    const GLfloat Y_Offset=-1;
    const GLfloat EyeSightLength=5;
    //GLfloat eye_x1, eye_y1, eye_z1;
    
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glColor3f(1.0, 1.0, 1.0);
    
    mainRotorRotatingAngle+=mainRotorSpinSpeed;
    tailRotorRotatingAngle+=tailRotorSpinSpeed;
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    //glTranslatef(0, 0, -20.0);    // Translate the object by 20 units in -ve z-direction.
    //glScalef(4, 4, 4);


/************************************************************
The view transformation        
*************************************************************/
    //theta_rad=deg2rad(theta);
    //phi_rad=deg2rad(phi);
    eye_x=radius*sin(theta)*sin(phi);
    eye_y=radius*cos(theta);
    eye_z=radius*sin(theta)*cos(phi);

    //glPushMatrix();
    
    if (bCamera)
    {
        gluLookAt(eye_x+move_x, eye_y, eye_z+move_z, move_x, 0, move_z, 0, 1, 0);
        glTranslatef(-eye_x, -eye_y, -eye_z);
        showReferenceAxis();
        drawScene();
        //translate helicopter a little back so that pilot is at rotation axis
        glTranslatef(X_Offset+move_x, Y_Offset,move_z);
        
        glScalef(2, 2, 2);

    //    glRotatef(x_Angle, 1.0, 0.0, 0.0);    // Rotate the object by x_Angle about x-axis
    //    glRotatef(y_Angle, 0.0, 1.0, 0.0);    // Rotate the object by y_Angle about y-axis
    //    glRotatef(z_Angle, 0.0, 0.0, 1.0);    // Rotate the object by z_Angle about z-axis

        glRotatef(sin(deg2rad(yaw))*MaxRotatingAngle, 0,1,0);
        glRotatef(sin(deg2rad(pitch))*MaxRotatingAngle/2, 0,0,1);
        glRotatef(sin(deg2rad(roll))*MaxRotatingAngle, 1,0,0);
        drawHelicopter();

        glTranslatef(eye_x, eye_y, eye_z);

    }
    else
    {
        gluLookAt(move_x,0,move_z, -1+move_x, -sin(deg2rad(pitch)), move_z -sin(deg2rad(yaw)), 
            sin(sin(deg2rad(pitch))*PI/6), cos(sin(deg2rad(pitch))*PI/6), 
            sin(sin(deg2rad(roll)))*PI/6);
        //glTranslatef(-move_x, -eye_y, -eye_z);
        showReferenceAxis();
        drawScene();
        glTranslatef(X_Offset+move_x, Y_Offset,move_z);
        
        glScalef(2, 2, 2);

    //    glRotatef(x_Angle, 1.0, 0.0, 0.0);    // Rotate the object by x_Angle about x-axis
    //    glRotatef(y_Angle, 0.0, 1.0, 0.0);    // Rotate the object by y_Angle about y-axis
    //    glRotatef(z_Angle, 0.0, 0.0, 1.0);    // Rotate the object by z_Angle about z-axis

        glRotatef(sin(deg2rad(yaw))*MaxRotatingAngle, 0,1,0);
        glRotatef(sin(deg2rad(pitch))*MaxRotatingAngle/2, 0,0,1);
        glRotatef(sin(deg2rad(roll))*MaxRotatingAngle, 1,0,0);
        drawHelicopter();
    }

    
    //the following sequence is HIGHLY important because
    //you want the object to rotate w.r.t. to original world 
    //origin and you need to transform it between world coordinate and
    //view-coordinate

    
            
    
    glutSwapBuffers();    // Use of double buffering to avoid flicker.
    glutPostRedisplay();
}

/****************************************************************************************/
int main (int argc, char *argv[])
                        // The main program.
{
        
    /* All customary glut env initializations. */
    glutInit(&argc, argv);    
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
    glutInitWindowSize(SIZE, SIZE);
    glutInitWindowPosition(10, 10);
    glutCreateWindow("A primitive model of a helicopter ! ~nick");

    /* glut env initializations done. */
                        

    init();                // Initialize the openGL env. variables and the application global variables.


    /* Callback registrations with the OpenGL env are done here */
    
    glutDisplayFunc(displayCallbackProc);
    glutKeyboardFunc(keyboardCallbackProc);
    glutSpecialFunc(specialCallbackProc);
    glutReshapeFunc(reShapeCallbackProc);

    /* Callback registrations done.*/

    glutMainLoop();
                        // Inside glutMainLoop(); all the mouse/KB events pertaining to the 
                        // application window are dispatched. This loop is never exited so the  
                        // statements after glutMainLoop(); are never executed !
    return 1;
}

This code compile fine with g++ :


g++ helicopter.cpp -lGL -lglut -lGLU -o helicopter

(only a warning about an “anonymous type with no linkage used to declare variable” but this don’t seem problematic)

Thank you all