helicopter

Helicopter-Camera and Movement

    A.Second Edition

    This is the comp471 assignment 3 which requires to add more camera function and movement to previous helicopter model.

    B.The problem

    Problem Statement:
    This assignment aims at incorporating some simple animation and enhanced camera
    movements in the program that you have built so far. Extend your assignment # 2 to include the
    following functionalities:
    R1) Helicopter Animation:
    ¡¤  Helicopter movement: The helicopter motion in accordance to Euler angles (qx, qy, qz), also
    known as YPR (Yaw, Pitch and Roll). For example look at the diagrams below.
    The motion will be defined as follows. For the Yaw motion, you will rotate the helicopter about
    an axis of rotation passing through a ¡°center¡± of the cockpit. For the Pitch motion, you will
    rotation the entire helicopter about an axis of rotation passing through the same ¡°center¡± of the
    cockpit. The Roll motion should rotation the entire helicopter about the axis of rotation passing
    through the same ¡°center¡± of the cockpit. Of course, all these axes of rotation are perpendicular
    to each other and line up with the symmetries of the helicopter.
    Helicopter movement continued: The helicopter should be able to fly in the forward in the
    negative n vector direction (for the right-handed uvn viewing-coordinate reference frame) of
    the first-person camera sitting at the position of the pilot in the cockpit.
    Make sure all motions are realistic, e.g., the pitch and roll motion or the forward motion should
    not let the helicopter pass though the plane of the ¡°ground¡±, etc.
    ¡¤  Rotor motion: When toggled on, have the main rotors and the tail rotors spin at constant rates
    (the rear rotors should spin faster than the main rotors). While the rotors are spinning, the
    helicopter may still remain stationary with respect to its environment.
    R2) Camera Motion
    ¡¤  Implement two cameras - first and third person. Give controls to toggle between both. The third
    person camera is already in place from assignment #2. A first person camera would be one
    where the camera is placed roughly at the position of pilot of helicopter (at an appropriate
    location within the cockpit) and facing forward, i.e., the world is seen from the pilot¡¯s
    perspective. This is just like a Quake or Doom game where the camera is placed in the eyes of
    the role player. This means that the Yaw, Pitch and Roll motions and forward motion for the
    helicopter applies for the first person camera as well.
    R3) Flooring and environment
    ¡¤  Create ¡°ground¡± (a finite sized plane) and place the helicopter at a small distance over it. Also
    place some simple objects in the scene (like ¨C cones, cubes, cylinders, etc) at significant
    distances. This would give a feel for an environment when the user changes the views. The
    objects need not be complex (like ¨C trees, houses, etc.) [Note: The program should show these
    additional objects in both wire frame and shaded forms.]
    ¡¤  Make the structures representing the windows of the cockpit transparent so that the first
    person camera can see out.
    Comp 471/Fall 2005 Page 3 of 3 Assignment #3
    Suggested keyboard commands to control the view:
    ¡¤  Toggle using 1/3 for first and third person camera.
    ¡¤  Toggle using s/S to start or stop the rotor spinning motions.
    ¡¤  Use the y/Y, p/P and r/R keys for the YPR motion of the helicopter (and also the first person
    camera). Use the t/T keys for the forward motion of the helicopter.
    ¡¤  For the third person camera ¨C
    o Use the i/I and k/K keys to move/rotate the center of projection up/down about a point (say
    centre of gravity) centrally located on the helicopter.
    o Use the j/J and l/L keys to move/rotate the center of projection left/right about the point (as
    mentioned above) centrally located on the helicopter.
    o Use the f/b keys to move forward and backwards respectively on the line joining the point
    (as mentioned above) centrally located on the helicopter and the center of projection.
    [Note ¨C The above commands are in addition to the ones given in assignment #2. Make suitable assumptions
    wherever needed.]

    ¡¡

C.The idea of program
¡¡

The programming part of openGL is sometimes straight forward if someone shows you the correct path. However, it can become

very tricky at some points. I happened to be the case. I spent almost two days to re-structure my glutobject library before

I completely give up because there seems to have too many traps. Sometimes it is very painful for you to discover a single

bug and probably this bug is not caused by your slackness. For example, one hard bug I found in my glutobject is that the

range values of "asin()" and "acos()" function caused my rotor not to rotating properly. This is quite unthinkable. I mean,

I only expect I made some stupid mistakes in calculating matrix transformations and it turns out to be not my fault.

Actually I feel quite comfortable after I give up my library. It is quite an easy job to implement a few camera function

within two hours. And one more small functionality of movement causes me less than half hour including writing some

comments and updating menu contents. I mean it is nothing more than parameter setup. Can this be called programming?

    D.The major functions

    There is a couple of things which I want to mention. First, I defined a little fancy function which takes a drawing function

    as parameter then divides the object either horizontally or vertically into several parts by repeatedly using clipping. It

    is called "divider_x" and "divider_y". The other one is that the sequence of rotating model and gluLookAt function is highly

    important. I realized this only after almost 45 minutes later when I always found helicopter is not rotating around origin

    but rather w.r.t eye position! Therefore the following program segment explains everything:

    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;

    	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    	glColor3f(1.0, 1.0, 1.0);

    	glMatrixMode(GL_MODELVIEW);
    	glLoadIdentity();

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

    	gluLookAt(eye_x, eye_y, eye_z, 0, 0, 0, 0, 1, 0);

    	//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
    	glTranslatef(-eye_x, -eye_y, -eye_z);
    	showReferenceAxis();
    	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

    	drawHelicopter();

    	glTranslatef(eye_x, eye_y, eye_z);

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

    You need to place your drawHelicopter function between two "glTranslatef" and gluLookAt function must be called first.

    ¡¡

    One funny aspect of implementation is about moving third-person view camera left/right. Originally I thought it is as

    trivial as moving up/down. But it is not! Because this operation actually changes all three parameter: theta, phi, radius.

    So, it is the most complicated operation among all! And to achieve realistic for viewer, you have to maintain consistency

    of these kind of operation. i.e. if you want to move left/right in a series of operation, you need to record the very

    first theta, radius, phi. Otherwise it won't give viewer feeling of left/right. It is hard to explain until you try by

    yourself.

    E.Further improvement

    Honestly speaking, my helicopter is not nice at all. One big reason is that I am not the kind of "art" guy who can draw

    picture very well. And I am not that kind of "engineering" guy who can draw the assembly plan very well. And I am now more

    interested in "framework" which is half-finished project previously. If you have any difficulty in compiling the file, pls

    refer to here.

    F.File listing

    1. helicopter.h

    2. helicopter.cpp

    file name: helicopter.h

    #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);

    file name: helicopter.cpp

    ¡¡

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

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

    				printf("\n Use p/P keys to pitch helicopter and first-person view camera.");

    				printf("\n Use y/Y keys to yaw helicopter and first-person view camera.");
    				printf("\n Use r/R keys to roll helicopter and first-person view camera.");

    				printf("\n Use t/T keys to move helicopter backward/forward along x-axis \
    					and first-person and third-person view camera.");

    				printf("\n Use h/H keys to move helicopter left/right along z-axis \
    					and first-person and third-person view camera.");

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

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

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

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

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

    				printf("\n Use escape key to exit.\n");

    /* 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 "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;

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

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

    	printf("\n Use p/P keys to pitch helicopter and first-person view camera.");

    	printf("\n Use y/Y keys to yaw helicopter and first-person view camera.");
    	printf("\n Use r/R keys to roll helicopter and first-person view camera.");

    	printf("\n Use t/T keys to move helicopter backward/forward along x-axis \
    		and first-person and third-person view camera.");

    	printf("\n Use h/H keys to move helicopter left/right along z-axis \
    		and first-person and third-person view camera.");

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

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

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

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

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

    	printf("\n Use escape key to exit.\n");

    }

    /****************************************************************************************/
    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;
    		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();
    		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;
    }

    /*************************** END OF PROGRAM ************************************************/

    ¡¡

    ¡¡

    ¡¡