Glut Object

             A Preliminary OpenGL Object Model

A. Third Edition

How do you make bird fly? How do you make flower blossom?

Actually these are irrelevant question and I just don't know the answer. Neither do I know how I should proceed with this

project!

 

(Now I know how a bird can fly! Now I know how I can make a flower blossom! It all happens almost in one instant! And this

one single instant comes after a long, long period of half year!)

B.The problem

I run into big, big problem and my confidence corrupted.

 

(What is the problem is always the biggest question to ask yourself before even to think about how to solve! Now tell me

what is the problem!

The problem is not what I thought! The depth-test works, but works incorrectly. And I was always in an illusion that the

depth-test wasn't working. Indeed it works but the picture seems to be fragmented. So this is really the problem!

Now let's think about how to solve!

It is so simple and still I don't get it! I cannot set the near-plane to be 0 in parameter of glPerspective. As long as

it is not 0, it works fine! And why? I don't know and I don't care for the time being.)

 

C.The idea of program
 
I combined a little matrix calculation tool in this edition which solves my headache in computing rotation transformations.
 
{
Are you fed up with glPushMatrix, glPopMatrix? Are you fall in asleep when repeating set up relative scale between object model? Are you
feeling dizzy when you try to figure out the rotation and transferring order? Why don't you leave that to me and you just concentrate on your
creative art-working?
A simple, straight-forward, high-level object model design toy which eases you from tedious object model creating work.
It all starts from our observation of objects in this world. If an object is in our scene world, you need to setup its parameter like its 
size, color, orientation, position, posture and its movement etc. Then graphic programming really becomes a parameter setup job and even
people from fine arts can do the programming by writing simplest script file or code file!
1. All object is inheritated from GlutObject which has a pure virtual method "display" to be implemented by derived class.
2. All derived class only need to setup its parameters like following:
 "volume"  represents the bounding cube of object, 
"direction" represents the orientation of object
"position" represents the coordinate of object center
"color" of course represents the color
And in order to create complex object, I introduce "clip-ratio" etc which is not a good idea to be put here. Maybe it should be put in a 
derived class. Anyway this is not important details.
3. When a display-callback is called, it will do the transformation universally for all objects. In other words, you don't have to write any
line of code for transformation because they are always the same and have been done by library.
4. If you need create an object, simply inherit from GlutObject and implement the "display" method where you only need to tell how to draw
the object in origin. And I have created a series common objects for you like sphere, cube, torus and when I say "create" it means I only 
write one line of code in method "display".
5. What if you want to create a complex object? You simply create a GlutObjectList which contains a bunch of objects and you just implement
the "display" method of "GlutObjectList". (See example "Helicopter")
6. Can I move the complex object? Of course you can, simply write your move method in the "display". (see example in rotor moving in 
Helicopter)
7. Is there any flaw in your design? Yes, the performance of program is not my priority because it concentrates on how to increase 
programming productivity. And when I started writing the basic transformation matrix, I was not quite clear about rotation matrix, so there
is big flaw in "direction" design. Because at that time, I thought it would be faster if I did the matrix multiplication myself. And the 
thing is, you make things bad by using vector instead of angles in rotating. And later I found out that only one vector cannot represent
the "posture" of asymmetric object. You need either three angles or two vectors. I would fix this flaw later.
}
 
D.The major functions
Just in case you are not familiar with OpenGL and want a test-drive, you need to install an OpenGL programming environment in your VC++ by 
copying "glut.h" file in your "/include" directory and a compiling library "glut32.lib" must be copied in your "lib" directory. The run-time
"dll", "glut32.dll" must be copied to your "system" or "system32" director in your "windows" directory. Once created with a "win console" 
project in VC++, go to the "setting" of "project" and "linking" tab to add "glut32.lib". 
(This sounds trivial for programmers, but it is worthwhile for beginners.:) And of course I can use a VC++ key word: 
#pragma comment( lib, "glut32") to ask linker to search glut32.lib automatically, still those .h .lib and .dll file needs to be copied by 
programmer.

E.Further improvement
The next step?
F.File listing
1. glutObject.h
2. glutObject.cpp
3. glutObjects.h
4. glutObjects.cpp
5. utility.h
6. rotation.h
7. rotation.cpp
8. main.cpp
file name: glutObject.h
#ifndef  GLUTOBJECT_H
#define GLUTOBJECT_H

#include <GL/glut.h>
//#include "glutobjects.h"
#include <cstdlib>
#include "utility.h"
//#define NICKSPACE_BEGIN namespace NICKSPACE {
//#define NICKSPACE_END }

//NICKSPACE_BEGIN
//const GLfloat PI=3.14159;
const GLint MaximumObjectNumber=150;
const GLint MaximumListNumber=20;


//typedef GLfloat[3] GlutVector;

class GlutObjectList;

extern GlutObjectList* gObjectListPtr;
extern enum AdjustViewState;
//extern enum PerspetiveStyle;
const GLfloat DefaultPosition[3]={0,0,0};
const GLfloat DefaultDirection[3]={1,0,0};
const GLfloat DefaultColor[4]={1,0,0,1};
const GLfloat DefaultVolume[3]={1,1,1};
const GLfloat DefaultBackColor[3]={1,1,1};
const bool DefaultDrawingStyle=false;//this means solid instead of mesh
const GLfloat DefaultPerspectAngle=70;
const GLfloat DefaultViewVolume[3]={800, 600, 800};
const GLfloat DefaultNearPlane=0;
const GLfloat DefaultWindowWidth=800;
const GLfloat DefaultWindowHeight=600;
const GLint DefaultWindowPosition_x=0;
const GLint DefaultWindowPosition_y=0;
const GLfloat DefaultTheta=deg2rad(80);
const GLfloat DefaultPhi=deg2rad(20);
const GLfloat DefaultRadius=20;
const GLfloat DefaultXAngle=0;
const GLfloat DefaultYAngle=0;
const GLfloat DefaultZAngle=0;
const GLfloat ViewAngleOffset=0.01;
const GLfloat RotateAngleOffset=5;
const bool DefaultObjectInternalState=false;
//void display();



class GlutObject
{
	friend class GlutObjectList;
	friend 	void arrayCopy(GLfloat tgt[], const GLfloat src[]);
public:
	void setPosition(GLfloat x, GLfloat y, GLfloat z);
	void setPosition(GLfloat* array);
	void setDirection(GLfloat x, GLfloat y, GLfloat z);
	void setDirection(GLfloat* array);
	void setVolume(GLfloat w, GLfloat h, GLfloat l);
	void setColor(GLfloat r, GLfloat g, GLfloat b, GLfloat a=1);
	void doRotation();
	//void doTransform();
	//GlutObject(GlutObjectList*& lstPtr=gObjectListPtr);
	GlutObject();	
	//virtual void keyboardFunction(unsigned char key, GLint x,  GLint y);
	void draw();
	//virtual void lastDraw();
	virtual void display()=0;
	
	void setClipRatio(GLfloat ratio);
	void lastRotate(enum AXIS axis, GLfloat angle);
protected:
	GLfloat position[3];
	GLfloat direction[3];
	GLfloat color[4];
	GLfloat volume[3];
	GLdouble clipPlane[4];
	GLfloat clipRatio;
	GLfloat rotatingAngle;
	enum AXIS rotatingAxis;
	bool bDisableClip;
	bool bVisible;
	bool bInternal;
	void setClipPlane();
	void normalizeDirection();
};


class GlutObjectList
{
	friend class GlutObject;
	friend void arrayCopy(GLfloat tgt[], const GLfloat src[]);
public:
	GlutObjectList();
//	void keyboardFunction(unsigned char key, GLint x, GLint y);
	void drawAll(bool bDrawOpaque);
	virtual void display();//the way you want to do
	void addNewObject(GlutObject* ptr);
protected:
	GLint objectCount;
	//PerspetiveStyle ePerspective;
	GlutObject*  objectList[MaximumObjectNumber];
	
	//void draw3DAxis(GLfloat width, GLfloat height);
};
//NICKSPACE_END

class GlutSystem
{
	friend void displayCallback();
	friend void reshapeCallback(int w, int h);
	friend void keyboardCallback(unsigned char key, int x, int y);
	friend void specialCallback(int key, int x, int y);
	friend void run();
	friend void init();
public:
	void reshapeCallback(int w, int h);
	void specialCallback(int key, int x, int y);
	void displayCallback();
	void keyboardCallback(unsigned char key, int x, int y);
	void addNewList(GlutObjectList* lstPtr);
	GlutSystem();
	void init();
	void run();
protected:
	GlutObjectList* objectListArray[MaximumListNumber];
	GLint listCount;
	bool bDrawingMesh;
	GLfloat perspectAngle;
	bool bPerspective;
	bool bDrawAxis;
	GLfloat x_Angle, y_Angle, z_Angle;
	GLfloat theta;
	GLfloat phi;
	GLfloat radius;
	AdjustViewState eAdjustView;
	GLfloat viewVolume[3];
	GLfloat windowWidth, windowHeight;
	GLfloat viewPortWidth, viewPortHeight;
	int windowPos_x, windowPos_y;
	GLfloat nearPlane;
	GLfloat backColor[3];//?????
	GLfloat foreColor[3];
	void setDisplayMode();
	void adjustView();

	void drawAll();

};

#endif
 
file name: glutObject.cpp
#include <GL/glut.h>
#include <cstdlib>
#include <iostream>
#include <cmath>
#include "glutObject.h"
#include "glutobjects.h"
#include "rotation.h"

using namespace std;
extern GlutObject3DAxis axis;
//NICKSPACE_BEGIN
const GLint AdjustScale=2;
GlutObjectList* gObjectListPtr=NULL;
GlutSystem* gGlutSystemPtr=NULL;
//enum PerspetiveStyle{PERSPECTIVE, ORTHOGONAL};
enum AdjustViewState{ADV_KEEPSHAPE=0, ADV_ENLARGE=AdjustScale, ADV_REDUCE=-AdjustScale};

//bool flag=false;


GLdouble STDPlane[3][3]=
{
	{1,0,0},
	{0,1,0},
	{0,0,1}
};

const bool DefaultPerspectiveStyle=true;


void GlutObject::setColor(GLfloat r, GLfloat g, GLfloat b, GLfloat a)
{
	color[0]=r;
	color[1]=g;
	color[2]=b;
	color[3]=a;
}


void GlutObject::setPosition(GLfloat x, GLfloat y, GLfloat z)
{
	position[0]=x;
	position[1]=y;
	position[2]=z;
	//setClipPlane();
}

void GlutObject::setPosition(GLfloat* array)
{
	for(int i=0; i<3; i++)
	{
		position[i]=array[i];
	}
	//setClipPlane();
}

void GlutObject::setDirection(GLfloat x, GLfloat y, GLfloat z)
{
	direction[0]=x;
	direction[1]=y;
	direction[2]=z;
}

void GlutObject::setDirection(GLfloat* array)
{
	for (int i=0; i<3; i++)
	{
		direction[i]=array[i];
	}
}

void GlutObject::setVolume(GLfloat w, GLfloat h, GLfloat l)
{
	volume[0]=w;
	volume[1]=h;
	volume[2]=l;
}


//GlutObject::GlutObject(GlutObjectList*& lstPtr)
GlutObject::GlutObject()
{	
	/*
	if (lstPtr==NULL)
	{
		lstPtr=new GlutObjectList;
	}
	
	lstPtr->addNewObject(this);
	*/
	arrayCopy(direction, DefaultDirection);
	arrayCopy(volume, DefaultVolume);
	arrayCopy(color, DefaultColor);
	color[3]=DefaultColor[3];
	arrayCopy(position, DefaultPosition);	
	clipRatio=0.0;	
	setClipPlane();
	bDisableClip=true;
	bVisible=true;
	bInternal=false;
	rotatingAngle=0;
}

void arrayCopy(GLfloat tgt[], const GLfloat src[])
{
	for (int i=0; i<3; i++)
	{
		tgt[i]=src[i];
	}
}

void GlutObject::normalizeDirection()
{
	GLfloat temp;
	temp=sqrt(direction[0]*direction[0]+direction[1]*direction[1]+
		direction[2]*direction[2]);
	direction[0]/=temp;
	direction[1]/=temp;
	direction[2]/=temp;
}


void GlutObject::setClipRatio(GLfloat ratio)
{
	clipPlane[3]=-ratio/2;
}

void GlutObject::setClipPlane()
{
	//this is a naive clip plane setting, which is xz plane 
	//at position
	clipPlane[0]=clipPlane[2]=0;
	clipPlane[1]=1;
	clipPlane[3]=0;
}

void GlutObject::doRotation()
{
	GLfloat output[16];
	Matrix matrix;
	//Vector vertex(position);
	Vector axis(direction);
	matrix.rotateAxis(axis);

	//glPushMatrix();
	matrix.outputArray(output);
	//glPushMatrix();
	glMultMatrixf(output);
	//glPopMatrix();
}

void GlutObject::lastRotate(enum AXIS axis, GLfloat angle)
{
	rotatingAxis=axis;
	rotatingAngle=angle;
}

//no rotatations!!!
void GlutObject::draw()
{
	glPushMatrix();
	//glLoadIdentity();
	glColor4f(color[0], color[1], color[2], color[3]);
	glTranslatef(position[0], position[1], position[2]);

	//lastDraw();
	doRotation();
	if (rotatingAngle!=0)
	{
		switch (rotatingAxis)
		{
		case X_AXIS:
			glRotatef(rotatingAngle, 1,0,0);
			break;
		case Y_AXIS:
			glRotatef(rotatingAngle, 0,1,0);
			break;
		case Z_AXIS:
			glRotatef(rotatingAngle, 0,0,1);
			break;
		}
	}
	glScalef(volume[0], volume[1], volume[2]);
	
	//glColor3f(color[0], color[1], color[2]);
	display();
	//glTranslatef(position[0], position[1], position[2]);
	
	//glTranslatef(-position[0], -position[1], -position[2]);
	//doRotation();
	//glTranslatef(-position[0], -position[1], -position[2]);
/*
	if (!bDisableClip)
	{
		glClipPlane (GL_CLIP_PLANE0, clipPlane);	
		glEnable (GL_CLIP_PLANE0);
		display();
		glDisable(GL_CLIP_PLANE0);
	}
	else
	{
		display();
	}
	*/
	//glTranslatef(-position[0], -position[1], -position[2]);
	glPopMatrix();
}
					


//GlutObjectList

void reshapeCallback(int w, int h)
{
	gGlutSystemPtr->reshapeCallback(w, h);
}

void displayCallback()
{
	gGlutSystemPtr->displayCallback();
	glutPostRedisplay();
}

void specialCallback(int key, int x, int y)
{
	gGlutSystemPtr->specialCallback(key, x, y);
}

void keyboardCallback(unsigned char key, int x, int y)
{
	gGlutSystemPtr->keyboardCallback(key, x, y);
}

void init()
{
	gGlutSystemPtr->init();
}

void run()
{
	gGlutSystemPtr->run();
}

void GlutObjectList::addNewObject(GlutObject* ptr)
{
	objectList[objectCount++]=ptr;
}

GlutObjectList::GlutObjectList()
{
	if (gGlutSystemPtr==NULL)
	{
		gGlutSystemPtr=new GlutSystem;
		gGlutSystemPtr->init();
	}
	gGlutSystemPtr->addNewList(this);
	objectCount=0;

}

void GlutObjectList::display()
{
	//add your method here
}

void GlutObjectList::drawAll(bool bDrawOpaque)
{
	int i;
	//for testing

	//flag=!flag;


	glMatrixMode(GL_MODELVIEW);
	//glLoadIdentity();
	//glTranslatef(0, 0, -50);
	glPushMatrix();
	display();
	//glTranslatef(0, 0, 50);
	//first we draw all opaque object
	//glEnable(GL_DEPTH_TEST);
	if (bDrawOpaque)
	{	
		for (i=0; i<objectCount; i++)
		{
			if (objectList[i]->color[3]==1)
			{
				objectList[i]->draw();
			}
		}
		//glDepthMask (GL_FALSE);
	}
	else
	{
	//glFlush();
	//then let's draw all transparent object with blending enabled	
		glDepthMask (GL_FALSE);
		glEnable (GL_BLEND);
		//glEnable(GL_DEPTH_TEST);
		//glDisable(GL_DEPTH_TEST);
		//glDepthMask (GL_TRUE);
		
		glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

		for (i=0; i<objectCount; i++)
		{
			if (objectList[i]->color[3]<1)
			{
				objectList[i]->draw();
			}
		}
		//glDepthMask (GL_FALSE);
		glDisable (GL_BLEND);
		glDepthMask (GL_TRUE);
		
	}
	glPopMatrix();
	//glFlush();

}


void GlutSystem::addNewList(GlutObjectList* lstPtr)
{
	if (listCount>=MaximumListNumber)
	{
		cout<<"maximum list number reached!\n";
		exit(1);
	}
	objectListArray[listCount++]=lstPtr;
}

GlutSystem::GlutSystem()
{
	listCount=0;
	arrayCopy(backColor, DefaultBackColor);
	arrayCopy(viewVolume, DefaultViewVolume);
	nearPlane=DefaultNearPlane;
	perspectAngle=DefaultPerspectAngle;
	windowWidth=DefaultWindowWidth;
	windowHeight=DefaultWindowHeight;
	windowPos_x=DefaultWindowPosition_x;
	windowPos_y=DefaultWindowPosition_y;
	viewPortWidth=windowWidth;
	viewPortHeight=windowHeight;
	theta=DefaultTheta;
	phi=DefaultPhi;
	radius=DefaultRadius;
	//ePerspective=DefaultPerspectiveStyle;
	bPerspective=DefaultPerspectiveStyle;
	eAdjustView=ADV_KEEPSHAPE;
	x_Angle=DefaultXAngle;
	y_Angle=DefaultYAngle;
	z_Angle=DefaultZAngle;
	setDisplayMode();
	bDrawAxis=true;
	bDrawingMesh=DefaultDrawingStyle;
	//init();

}

void GlutSystem::init()
{
	glutInitWindowSize(windowWidth, windowHeight);
	glutInitWindowPosition(windowPos_x, windowPos_y);
	glutCreateWindow("A generic object system");

	glutDisplayFunc(::displayCallback);
	glutReshapeFunc(::reshapeCallback);
	glutKeyboardFunc(::keyboardCallback);
	glutSpecialFunc(::specialCallback);



	// Set the current openGL matrix to GL_PROJECTION ie projection matrix.
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	// Load identitiy values in the above.
	if(bPerspective)
	{
		gluPerspective(perspectAngle, (GLfloat)windowWidth/(GLfloat)windowHeight,
			nearPlane, nearPlane+viewVolume[2]);
							// This sets the view volume to be a Perspective one.
	}
	else
	{
		// This sets the view volume to be a Orthographic one.
		glOrtho(-viewVolume[0]/2, viewVolume[0]/2, -viewVolume[1]/2, viewVolume[1]/2, 
			nearPlane, nearPlane+viewVolume[2]);
							
	}
	glMatrixMode(GL_MODELVIEW);	
							// Change the current matrix mode to Model-View matrix.
	glLoadIdentity();
							
	// set the background color to black.
	glClearColor (0.5, 0.5, 0.5, 1.0);

	glShadeModel(GL_SMOOTH);
	
	glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
	
	glEnable(GL_DEPTH_TEST);
	//showMenu();

}

void GlutSystem::keyboardCallback(unsigned char key, int x, int y)
{
	switch(key)
	{
	case 'a':
	case 'A':
		bDrawAxis=!bDrawAxis;
		break;
	case 'p':
	case 'P':
		bPerspective=!bPerspective;
		//glClear(GL_COLOR_BUFFER_BIT);
		setDisplayMode();
		//glFlush();
		break;
	case 'w':
	case 'W':
		if (!bDrawingMesh)			
		{
			bDrawingMesh = true;	// Wireframe model.
			glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
		}
		else
		{
			bDrawingMesh = false;	// Solid model.
			glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
		}
		break;

	case 's':
		eAdjustView=ADV_REDUCE;
		adjustView();
		break;
	case 'S':
		eAdjustView=ADV_ENLARGE;
		adjustView();
		break;
		//THIS is only useful for debugging

	case 27:
		exit(0);
		break;
	case 'x':
		x_Angle += RotateAngleOffset;
		break;
	case 'X':
		x_Angle -= RotateAngleOffset;
		break;
	case 'y':
		y_Angle += RotateAngleOffset;
		break;
	case 'Y':
		y_Angle -= RotateAngleOffset;
		break;
	case 'z':
		z_Angle += RotateAngleOffset;
		break;
	case 'Z':
		z_Angle -= RotateAngleOffset;
		break;	
	default:
		break;
	}
	glutPostRedisplay();

}
void GlutSystem::specialCallback(int key, int x, int y)						
{
	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.
			theta -= ViewAngleOffset;
			break;

		case GLUT_KEY_DOWN :	
			theta += ViewAngleOffset;
			break;
	}
	glutPostRedisplay();
}



void GlutSystem::displayCallback()
{
	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		
*************************************************************/
	//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();
	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();
	drawAll();
	glTranslatef(eye_x, eye_y, eye_z);
	glutPostRedisplay();
	glutSwapBuffers();	// Use of double buffering to avoid flicker.
	//glClear(GL_COLOR_BUFFER_BIT);

	
	//glutPostRedisplay();
}

void GlutSystem::setDisplayMode()
{
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	if(bPerspective)
	{
		gluPerspective(perspectAngle, viewVolume[0]/viewVolume[1], nearPlane, 
			nearPlane+viewVolume[2]);
	}
	else
	{	
		glOrtho(-viewVolume[0]/2, viewVolume[0]/2, -viewVolume[1]/2, viewVolume[1]/2, 
			nearPlane, nearPlane+viewVolume[2]);
	}					// Change the view volume to maintain the aspect ratio wrt to viewport.

	glMatrixMode(GL_MODELVIEW);
}

void GlutSystem::adjustView()
{
	GLfloat ratio;
	ratio=viewVolume[0]/viewVolume[1];
	
	if (eAdjustView==ADV_KEEPSHAPE)
	{		
		if (windowWidth/windowHeight>ratio)
		{
			//too wider
			viewPortWidth= viewPortHeight*ratio;
		}
		else
		{
			//become thinner
			viewPortHeight=viewPortWidth/ratio;
		}
	}
	else
	{
		if (bPerspective)
		{
			perspectAngle-=eAdjustView;
			setDisplayMode();
		}
		else
		{
			viewVolume[0]+=eAdjustView;
			viewVolume[1]+=eAdjustView*ratio;
			viewVolume[2]+=eAdjustView;
			setDisplayMode();
			/*
			viewPortHeight+=eAdjustView;
			viewPortWidth+=eAdjustView*ratio;
			
			glViewport((windowWidth-viewPortWidth)/2, (windowHeight-viewPortHeight)/2,
				(windowWidth+viewPortWidth)/2, (windowHeight+viewPortHeight)/2);
			*/
			//glViewport(0, 0, viewPortWidth, viewPortHeight);
		}
		eAdjustView=ADV_KEEPSHAPE;
	}
}


void GlutSystem::reshapeCallback(int w, int h)
{
	windowWidth=w;
	windowHeight=h;
	//adjustView();

	//glViewport((windowWidth-viewPortWidth)/2, (windowHeight-viewPortHeight)/2,
	//			(windowWidth+viewPortWidth)/2, (windowHeight+viewPortHeight)/2);

	//glViewport(0, 0, viewPortWidth, viewPortHeight);

	//adjustView();
	setDisplayMode();

	glMatrixMode(GL_MODELVIEW);
	glutPostRedisplay();
}

void GlutSystem::drawAll()
{
	int i;
	glMatrixMode(GL_MODELVIEW);
	//glLoadIdentity();
	//glTranslatef(0, 0, -50);
	
	if (bDrawAxis)
	{
		axis.draw();		
	}
	
	//glTranslatef(0, 0, 50);
	//first we draw all opaque object
	//glDepthMask (GL_TRUE);
	for (i=0; i<listCount; i++)
	{
		objectListArray[i]->drawAll(true);		
	}

	for (i=0; i<listCount; i++)
	{
		objectListArray[i]->drawAll(false);		
	}

	glFlush();
}

	
void GlutSystem::run()
{
	glutMainLoop();
}

GLfloat deg2rad(GLfloat degree)
{
	return degree/360.0*2*PI;
}

//NICKSPACE_END
 

  
file name: glutObjects.h
#ifndef  GLUTOBJECTS_H
#define GLUTOBJECTS_H

#include "glutObject.h"

//NICKSPACE_BEGIN
const GLfloat DefaultTopDownRatio=0.5;

class GlutObjectSweepSphere: public GlutObject
{
public:
	virtual void display();
	GlutObjectSweepSphere(GLfloat ration=0.25);
protected:
	GLfloat sweepRatio;
};

class GlutObjectSphere : public GlutObject
{
public:
	virtual void display();
};


class GlutObjectCube: public GlutObject
{
public:
	virtual void display();
};
	

class GlutObjectHalfCone: public GlutObject
{
public:
	virtual void display();
};


class GlutObjectTorus: public GlutObject
{
protected:
	GLfloat sectionAxisRatio;
public:	
	GlutObjectTorus(GLfloat ratio=0.5);
	virtual void display();
};

class GlutObjectSweepTorus: public GlutObjectTorus
{
protected:
	GLfloat sweepRatio;
public:
	GlutObjectSweepTorus(GLfloat ratio=0.5, GLfloat theSweepRatio=0.25);
	virtual void display();
};

class GlutObjectHalfTorus: public GlutObjectTorus
{
public:
	GlutObjectHalfTorus(GLfloat ratio=0.5);
	virtual void display();
};

class GlutObjectHalfSphere: public GlutObject
{
public:
	GlutObjectHalfSphere();
	virtual void display();
protected:
	//GLdouble clipPlane[4];
};

class GlutObject3DAxis: public GlutObject
{
public:
	GlutObject3DAxis();
	virtual void display();
};


class GlutObjectCylinder: public GlutObject
{
public:
	GlutObjectCylinder();
	virtual void display();
	void setRatio(GLfloat theRatio){ratio=theRatio;}
protected:
	GLfloat ratio;
};

class GlutObjectCone: public GlutObject
{
public:
	GlutObjectCone();
	virtual void display();
protected:
	
};

class GlutObjectSliceCone: public GlutObject
{
protected:
public:
	void lastDraw();
	void display();
};



class GlutObjectFace: public GlutObject
{
protected:
	GlutObjectSphere head;
	GlutObjectHalfTorus hatBrim;
	GlutObjectHalfSphere hatTop;
	GlutObjectSphere leftEye, rightEye;
	GlutObjectHalfSphere mouth;
	GlutObjectSliceCone nose;

public:
	GlutObjectFace();
	void display();
};

//NICKSPACE_END

#endif

file name: glutObjects.cpp
#include "glutObjects.h"
#include <GL/glut.h>
#include <cmath>



const GLfloat DefaultAxisLength=DefaultWindowWidth/25;
const GLfloat ArrowLength=0.6;
const GLint DrawingLineNumber=20;
//const GLfloat DefaultXAxisColor[3]={1,0,0};
GlutObject3DAxis axis;

//NICKSPACE_BEGIN
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};


void GlutObjectCube::display()
{
	glutSolidCube(1);
}

void GlutObjectSphere::display()
{
	glutSolidSphere(1, DrawingLineNumber, DrawingLineNumber);

}

GlutObjectSweepSphere::GlutObjectSweepSphere(GLfloat ratio)
{
	sweepRatio=ratio;
}

void GlutObjectSweepSphere::display()
{
	if (sweepRatio!=0.25||sweepRatio!=-0.25)
	{
		clipPlane[0]=tan(2*PI*sweepRatio);
		clipPlane[1]=-1;	
	}
	else
	{
		clipPlane[0]=1;
		clipPlane[1]=0;
	}
	clipPlane[2]=clipPlane[3]=0;
	glClipPlane(GL_CLIP_PLANE0, zx);
	glClipPlane(GL_CLIP_PLANE1, clipPlane);
	glEnable(GL_CLIP_PLANE0);
	glEnable(GL_CLIP_PLANE1);
	glutSolidSphere(1, DrawingLineNumber, DrawingLineNumber);
	glDisable(GL_CLIP_PLANE0);
	glDisable(GL_CLIP_PLANE1);
}



GlutObjectHalfSphere::GlutObjectHalfSphere()
{
	bDisableClip=false;
}

GlutObjectSweepTorus::GlutObjectSweepTorus(GLfloat ratio, GLfloat theSweepRatio)
{
	sectionAxisRatio=ratio;
	sweepRatio=theSweepRatio;
}

void GlutObjectSweepTorus::display()
{
	double clipPlanePlus[4]={0};
	clipPlane[0]=0;
	clipPlane[1]=1;
	clipPlane[2]=0;
	clipPlane[3]=0;

	clipPlanePlus[2]=clipPlanePlus[3]=0;
	if (sweepRatio!=0.25)
	{
		clipPlanePlus[0]=tan(sweepRatio*2*PI);
		clipPlanePlus[1]=-1;
	}
	else
	{
		clipPlanePlus[0]=1;
		clipPlanePlus[1]=0;
	}
	
	glRotatef(90, 0, 1, 0);
	glClipPlane(GL_CLIP_PLANE0, clipPlane);
	glClipPlane(GL_CLIP_PLANE1, clipPlanePlus);
	
	glEnable (GL_CLIP_PLANE0);
	glEnable (GL_CLIP_PLANE1);
	//glTranslatef(position[0], position[1]-volume[1]/2.0, position[2]);
	glutSolidTorus(sectionAxisRatio, 1, DrawingLineNumber, DrawingLineNumber);
	glDisable(GL_CLIP_PLANE0);
	glDisable(GL_CLIP_PLANE1);
	
}
GlutObjectHalfTorus::GlutObjectHalfTorus(GLfloat ratio)
{
	sectionAxisRatio=ratio;
}

void GlutObjectHalfTorus::display()
{
	clipPlane[0]=0;
	clipPlane[1]=0;
	clipPlane[2]=1;
	clipPlane[3]=0;
	
	glRotatef(90, 0, 1, 0);
	glClipPlane (GL_CLIP_PLANE0, clipPlane);
	
	glEnable (GL_CLIP_PLANE0);
	//glTranslatef(position[0], position[1]-volume[1]/2.0, position[2]);
	glutSolidTorus(sectionAxisRatio, 1, DrawingLineNumber, DrawingLineNumber);

	glDisable(GL_CLIP_PLANE0);
}


void GlutObjectHalfSphere::display()
{
	//assume clipplane is xy parallel

	clipPlane[0]=clipPlane[2]=0;
	clipPlane[1]=1;
	clipPlane[3]=0;

	//glRotatef(90, 0, 0, 1);
	glClipPlane (GL_CLIP_PLANE0, clipPlane);	
	glEnable (GL_CLIP_PLANE0);
	//glTranslatef(position[0], position[1]-volume[1]/2.0, position[2]);
	glutSolidSphere(1, DrawingLineNumber, DrawingLineNumber);

	glDisable(GL_CLIP_PLANE0);
}

void GlutObjectHalfCone::display()
{
	clipPlane[0]=0;
	clipPlane[1]=0;
	clipPlane[2]=-1;
	clipPlane[3]=0.5;

	glRotatef(90, 0, 1, 0);
	glClipPlane (GL_CLIP_PLANE0, clipPlane);	
	glEnable (GL_CLIP_PLANE0);
	//glTranslatef(position[0], position[1]-volume[1]/2.0, position[2]);
	glutSolidCone(1, 1, DrawingLineNumber, DrawingLineNumber);

	glDisable(GL_CLIP_PLANE0);
}

GlutObjectTorus::GlutObjectTorus(GLfloat ratio)
{
	sectionAxisRatio=ratio;
}

void GlutObjectTorus::display()
{
	glRotatef(90, 0, 1, 0);
	glutSolidTorus(sectionAxisRatio, 1, DrawingLineNumber, DrawingLineNumber);
}

GlutObject3DAxis::GlutObject3DAxis()
{
	position[0]=position[1]=0;
	position[2]=0;
	color[0]=color[1]=0; 
	color[2]=1;
}

void GlutObject3DAxis::display()
{
	glPushMatrix();
	
	//glMatrixMode(GL_MODELVIEW);
	//glLoadIdentity();

	//glRotatef(30, 1,0, 0);
	//glRotatef(-45, 0,1, 0);
	//glRotatef(60, 0, 0, 1);
	
	glBegin(GL_LINES);
		glColor4f(1,0,0,1);
		//X axis
		glVertex3fv(position);
		glVertex3f(position[0]+DefaultAxisLength, position[1], position[2]);
		glColor4f(0,1,0, 1);
		//Y axis
		glVertex3fv(position);
		glVertex3f(position[0], position[1]+DefaultAxisLength, position[2]);
		glColor4f(0,0,1,1);
		//Z axis
		glVertex3fv(position);
		glVertex3f(position[0], position[1], position[2]+DefaultAxisLength);

	glEnd();

	//draw three solid cone as arrows of axis
	//glLoadIdentity();
	//save current TM matrix
	//draw cone for X axis
	glPushMatrix();
	glTranslatef(position[0]+DefaultAxisLength-ArrowLength, position[1], position[2]);
	glRotatef(90, 0, 1, 0);
	//glTranslatef(x/2-ArrowLength, 0.0, 0.0);
	//glTranslatef(100, 0.0, 0.0);
	glutSolidCone(ArrowLength, ArrowLength*4, 10, 10);
	//glTranslatef(x/2+ArrowLength, ArrowLength, 0);
	//glutBitmapCharacter(GLUT_BITMAP_9_BY_15, 'X');
	
	//glLoadIdentity();
	glPopMatrix();
	glPushMatrix();
	//glRotatef(-90, 0, 1, 0);
	//glTranslatef(-(x/2-ArrowLength), 0.0, 0.0);
	glTranslatef(position[0], position[1]+DefaultAxisLength-ArrowLength, position[2]);
	glRotatef(-90, 1, 0, 0);
	glutSolidCone(ArrowLength, ArrowLength*4, 10, 10);
	glPopMatrix();
	//glLoadIdentity();
	
	glTranslatef(position[0], position[1], position[2]+DefaultAxisLength-ArrowLength);
	//glRotatef(-90, 1, 0, 0);
	glutSolidCone(ArrowLength, ArrowLength*4, 10, 10);
	glPopMatrix();
}

GlutObjectCylinder::GlutObjectCylinder()
{
	ratio=DefaultTopDownRatio;
}

void GlutObjectCylinder::display()
{
	GLUquadricObj* pObj;
	pObj = gluNewQuadric();
	// Creates a new quadrics object and returns a pointer to it.
	//glTranslatef(position[0], position[1], -position[2]/2);
	gluQuadricDrawStyle(pObj, GLU_FILL);
	
	//gluCylinder(pObj, volume[0]*ratio, volume[0], volume[2], volume[2]/2, volume[0]/2);
	//gluCylinder(pObj, (GLdouble)volume[0], (GLdouble)volume[0], (GLdouble)volume[2], 
	//	(int)volume[2], (int)volume[0]);
	glRotatef(90, 0, 1, 0);
	gluCylinder(pObj, 0.8, 0.8, 0.5, DrawingLineNumber, DrawingLineNumber);
	//gluSphere(pObj, volume[0], volume[0]/2, volume[0]/2);
							// Draw the cylinder with a radius : fRadius.
	gluDeleteQuadric(pObj);
}

void GlutObjectSliceCone::lastDraw()
{
	glRotatef(-90, 0,1,0);
}

void GlutObjectSliceCone::display()
{
	clipPlane[0]=1;
	clipPlane[1]=clipPlane[2]=clipPlane[2]=0;
	
	glRotatef(90, 0, 1,0);
	glClipPlane(GL_CLIP_PLANE0, clipPlane);	
	glEnable (GL_CLIP_PLANE0);
	//glTranslatef(position[0], position[1]-volume[1]/2.0, position[2]);
	glutSolidCone(1, 1, DrawingLineNumber, DrawingLineNumber);

	glDisable(GL_CLIP_PLANE0);
}

	

GlutObjectCone::GlutObjectCone()
{
	
}

void GlutObjectCone::display()
{
	//GLUquadricObj* pObj;
	//pObj = gluNewQuadric();
	// Creates a new quadrics object and returns a pointer to it.
	//glTranslatef(position[0], position[1], -position[2]/2);
	
	//glPushMatrix();
		glRotatef(90, 0,1,0);
		glutSolidCone(1, 1, DrawingLineNumber, DrawingLineNumber);
	//glPopMatrix();
	/*
	if (bDrawingMesh)
	{
		//gluQuadricDrawStyle(pObj, GLU_LINE);
		glutWireCone(volume[0], volume[2], volume[0], volume[2]);
	}
	else
	{
		//gluQuadricDrawStyle(pObj, GLU_FILL);
		glutSolidCone(volume[0], volume[2], volume[0], volume[2]);
	}
	*/
	
	//gluCylinder(pObj, volume[0]*ratio, volume[0], volume[2], volume[2]/2, volume[0]/2);
	//gluCylinder(pObj, (GLdouble)volume[0], (GLdouble)volume[0], (GLdouble)volume[2], 
	//	(int)volume[2], (int)volume[0]);
	//gluCylinder(pObj, 0.8, 0.8, 0.5, 20, 20);
	//gluPartialDisk(pObj, volume[0]*ratio, volume[0], volume[0], volume[1], 0, 90);
	//gluSphere(pObj, volume[0], volume[0]/2, volume[0]/2);
							// Draw the cylinder with a radius : fRadius.
	//gluDeleteQuadric(pObj);
}


GlutObjectFace::GlutObjectFace()
{
	addNewObject(&head);
	addNewObject(&hatBrim);
	addNewObject(&hatTop);
	addNewObject(&leftEye);
	addNewObject(&rightEye);
	addNewObject(&mouth);
	addNewObject(&nose);
	
	head.setVolume(3, 5, 3);
	head.setDirection(0, 0,1);
	head.setPosition(0,0,0);
	head.setColor(0.5, 0.5, 0);
	hatBrim.setVolume(3, 1, 3);
	hatBrim.setColor(1, 1, 1);
	hatBrim.setDirection(0,1,0);
	hatBrim.setPosition(0, 3, 0);

	
	hatTop.setVolume(3, 3,3);
	hatTop.setDirection(0, -1,0);
	hatTop.setColor(1,0.6, 0.7);

	hatTop.setPosition(0, 3, 0);
	
	leftEye.setVolume(0.5, 0.5, 0.1);
	leftEye.setPosition(-1, -0.1, 2.5);
	rightEye.setPosition(1, -0.1,  2.5);

	leftEye.setDirection(0,0,1);
	rightEye.setVolume(0.5, 0.5, 0.1);
	rightEye.setDirection(0,0,1);
	leftEye.setColor(0,0,0);
	rightEye.setColor(0,0,0);

	mouth.setColor(1,0,0);
	mouth.setPosition(0, -3.2, 2.4);
	mouth.setVolume(1.0, 0.3, 0.3);
	mouth.setDirection(0,0,-1);

	nose.setColor(0,1,0);
	nose.setDirection(0,1,0);
	nose.setVolume(0.8, 1.8, 0.5);
	nose.setPosition(0, -1.8, 3);
		
}

void GlutObjectFace::display()
{
	glTranslatef(10, 0, 10);

}
//NICKSPACE_END
	
 
	
file name: utility.h
#ifndef UTILITY_H
#define UTILITY_H
#include <GL/glut.h>
const double PI=3.1415926535;

GLfloat deg2rad(GLfloat degree);

//double rad2deg(double rad);
GLfloat rad2deg(GLfloat rad);

enum AXIS {X_AXIS, Y_AXIS, Z_AXIS};








#endif
 
 
file name: rotation.h
#ifndef ROTATION_H
#define ROTATION_H
#include <GL/glut.h>
#include "utility.h"


class Matrix;

class Vertex
{
public:
	Vertex(GLfloat x, GLfloat y, GLfloat z);
	GLfloat array[3];
};

class Vector
{
	friend class Matrix;
	//friend Vector operator*(const Vector& vect, GLfloat scalor);
public:
	GLfloat operator*(const Vector& other)const;//dot product
	Vector();
	Vector(GLfloat* otherArray);
	//Vector operator -();
	Vector operator*(GLfloat scalor) const;
	Vector(GLfloat d0, GLfloat d1, GLfloat d2);
	void clear();
	void display();
	GLfloat array[4];
	void normalize();

protected:
};

class Matrix
{
public:
	Matrix operator*(const Matrix& other);
	Vector operator*(const Vector& other);
	const Vector colVector(int index) const;
	void loadIdentity();
	Matrix();
	void translate(const Vector& vect);
	void translate(GLfloat d0, GLfloat d1, GLfloat d2);
	void rotate(AXIS axis, GLfloat degree);
	void rotateAxis(const Vector& axis);
	void rotateAxis(const Vector& vertex, const Vector& axis);
	void rotate(const Vector& vect, GLfloat degree);
	void rotate(const Vector& vertex, const Vector& axis);
	void rotate(const Vector& vertex, const Vector& axis, GLfloat degree);
	void display();
	Matrix arrayMultiply(Matrix* matrixArray, int number);
	Matrix transpose();
	void outputArray(GLfloat* output);
protected:
	Vector rowVector[4];
};

#endif

	
 
 
file name: rotation.cpp
#include <iostream>
#include <cmath>
#include "rotation.h"
#include "utility.h"


using namespace std;

GLfloat rad2deg(GLfloat rad)
{
	return rad/2/PI*360;
}


Vertex::Vertex(GLfloat x, GLfloat y, GLfloat z)
{
	array[0]=x;
	array[1]=y;
	array[2]=z;
}

//for the last one is just a scalor and shouldn't be multiply
Vector Vector::operator *(GLfloat scalor)const
{
	Vector result=*this;
	for (int i=0; i<3; i++)
	{
		result.array[i]=array[i]*scalor;
	}
	return result;
}
/*
Vector operator*(const Vector& vect, GLfloat scalor)
{
	Vector result=vect;
	return result.operator *(scalor);
}
*/

//to do:
void Vector::normalize()
{
	GLfloat temp=0;
	int i;
	for (i=0; i<3; i++)
	{
		temp+=array[i]*array[i];
	}
	temp=sqrt(temp);
	if (temp!=0)
	{
		for (i=0; i<4; i++)
		{
		}
	}
}

GLfloat Vector::operator *(const Vector& other)const
{
	GLfloat result=0;
	for (int i=0; i<4; i++)
	{
		result+=array[i]*other.array[i];
	}
	return result;
}

Vector::Vector()
{
	clear();
	array[3]=1;
}

Vector::Vector(GLfloat d0, GLfloat d1, GLfloat d2)
{
	array[0]=d0;
	array[1]=d1;
	array[2]=d2;
	array[3]=1;
}

Vector::Vector(GLfloat* otherArray)
{
	for (int i=0; i<3; i++)
	{
		array[i]=otherArray[i];
	}
	array[3]=1;
}

void Vector::clear()
{
	for (int i=0; i<4; i++)
	{
		array[i]=0;
	}
}

const Vector Matrix::colVector(int index) const
{
	Vector result;
	for (int i=0; i<4; i++)
	{
		result.array[i]=rowVector[i].array[index];
	}
	return result;
}

/*
Vector Vector::operator -()
{
	Vector result=*this;
	for (int i=0; i<3; i++)
	{
		result.array[i]=-result.array[i];
	}
	return result;
}
*/

void Vector::display()
{
	cout<<"\n\t(";
	for (int i=0; i<4; i++)
	{
		cout<<array[i];
		if (i!=3)
		{
			cout<<", ";
		}
	}
	cout<<")\n";
}

Matrix::Matrix()
{
	loadIdentity();
}

void Matrix::display()
{
	for(int i=0; i<4; i++)
	{
		rowVector[i].display();
	}
}

void Matrix::loadIdentity()
{
	for(int i=0; i<4; i++)
	{
		rowVector[i].clear();
		rowVector[i].array[i]=1;
	}
}


Matrix Matrix::operator *(const Matrix& other)
{
	Matrix result;
	for (int i=0; i<4; i++)
	{
		for (int j=0; j<4; j++)
		{
			result.rowVector[i].array[j]=rowVector[i]*other.colVector(j);
		}
	}
	return result;
}



void Matrix::translate(const Vector& vect)
{
	loadIdentity();
	for (int i=0; i<3; i++)
	{
		rowVector[i].array[3]=vect.array[i];
	}
}

void Matrix::translate(GLfloat d0, GLfloat d1, GLfloat d2)
{
	Vector vect(d0, d1, d2);
	translate(vect);	
}


void Matrix::rotate(enum AXIS axis, GLfloat degree)
{
	loadIdentity();
	GLfloat rad=deg2rad(degree);
	switch(axis)
	{
	case X_AXIS:
		rowVector[1].array[1]=cos(rad);
		rowVector[2].array[2]=cos(rad);
		rowVector[1].array[2]=-sin(rad);
		rowVector[2].array[1]=sin(rad);
		break;
	case Y_AXIS:
		rowVector[0].array[0]=cos(rad);
		rowVector[2].array[2]=cos(rad);
		rowVector[0].array[2]=sin(rad);
		rowVector[2].array[0]=-sin(rad);
		break;
	case Z_AXIS:
		rowVector[0].array[0]=cos(rad);
		rowVector[1].array[1]=cos(rad);
		rowVector[0].array[1]=-sin(rad);
		rowVector[1].array[0]=sin(rad);
		break;
	}
}

void Matrix::outputArray(GLfloat* output)
{
	for (int r=0; r<4; r++)
	{
		for (int c=0; c<4; c++)
		{
			output[r*4+c]=colVector(r).array[c];
		}
	}
}

Matrix Matrix::transpose()
{
	Matrix result;
	for (int r=0; r<4; r++)
	{
		result.rowVector[r]=colVector(r);
	}
	return result;
}


Matrix Matrix::arrayMultiply(Matrix* matrixArray, int number)
{
	Matrix result;
	for (int i=0; i<number; i++)
	{
		result=result*matrixArray[i];
	}
	return result;
}


void Matrix::rotateAxis(const Vector& vertex, const Vector& axis)
{
	Matrix matrixArray[2];
	matrixArray[0].translate(vertex);
	matrixArray[1].rotateAxis(axis);
	//matrixArray[2].translate(vertex*(-1));
	*this=arrayMultiply(matrixArray, 2);	
}

void Matrix::rotateAxis(const Vector& axis)
{
	GLfloat a,b,c,norm, d;
	Matrix matrixArray[2];
	a=axis.array[0];
	b=axis.array[1];
	c=axis.array[2];
	norm=sqrt(a*a+b*b+c*c);
	if (norm!=0)
	{
		a/=norm;
		b/=norm;
		c/=norm;
	}
	else
	{
		printf("zero vector detected!\n");
		exit(1);
	}

	d=sqrt(c*c+b*b);
	//if it is not coincide with x_axis
	//matrixArray[0].rotate(Y_AXIS, -rad2deg(acos(a/sqrt(1-b*b))));

	if (b==1)
	{
		matrixArray[0].rotate(Y_AXIS, 90);
	}
	else
	{
		if (b==-1)
		{
			matrixArray[0].rotate(Y_AXIS, -90);
		}
		else
		{
			if (c<0)
			{
				matrixArray[0].rotate(Y_AXIS, -(180-rad2deg(acos(a/sqrt(1-b*b)))));
			}
			else
			{
				matrixArray[0].rotate(Y_AXIS, -rad2deg(acos(a/sqrt(1-b*b))));
			}
		}

	}
	matrixArray[1].rotate(Z_AXIS, rad2deg(asin(b)));
	/*
	if (a<0)
	{
		matrixArray[1].rotate(Z_AXIS, -(180-rad2deg(asin(b))));
	}
	else
	{
		matrixArray[1].rotate(Z_AXIS, rad2deg(asin(b)));
	}
	*/
	/*
	if (b==1||b==-1)
	{
		matrixArray[0].rotate(Y_AXIS, -90);
	}
	else
	{
		matrixArray[0].rotate(Y_AXIS, -rad2deg(acos(a/sqrt(1-b*b))));
	}
	*/
/*
	if (b<0)
	{
		matrixArray[1].rotate(Z_AXIS, 180+rad2deg(asin(b)));
	}
	else
	{
		matrixArray[1].rotate(Z_AXIS, rad2deg(asin(b)));
	}

*/
	
	

	//(matrixArray[0]*matrixArray[1]).display();
	//cout<<"\n";
	*this=matrixArray[0]*matrixArray[1];

}

void Matrix::rotate(const Vector& vertex, const Vector& axis, GLfloat degree)
{
	Matrix matrixArray[3];
	Vector newVertex;
	newVertex=vertex*(-1.0);
	matrixArray[0].translate(vertex);
	matrixArray[1].rotate(axis, degree);
	matrixArray[2].translate(newVertex);
	/*
	for (int i=0; i<3; i++)
	{
		matrixArray[i].display();
	}
	*/
	*this=matrixArray[0]*matrixArray[1]*matrixArray[2];
}


void Matrix::rotate(const Vector& vect, GLfloat degree)
{
	GLfloat a,b,c,norm, d;
	Matrix matrixArray[5];
	a=vect.array[0];
	b=vect.array[1];
	c=vect.array[2];
	norm=sqrt(a*a+b*b+c*c);
	if (norm!=0)
	{
		a/=norm;
		b/=norm;
		c/=norm;
	}
	d=sqrt(b*b+c*c);
	//if it is not coincide with x_axis
	if (d!=0)
	{	
		matrixArray[0].rotate(X_AXIS, rad2deg(acos(c/d)));
	}
	matrixArray[1].rotate(Y_AXIS, rad2deg(acos(d)));
	matrixArray[2].rotate(Z_AXIS, degree);
	matrixArray[3].rotate(Y_AXIS, -rad2deg(acos(d)));
	if (d!=0)
	{
		matrixArray[4].rotate(X_AXIS, -rad2deg(acos(c/d)));
	}
	for (int i=0; i<3; i++)
	{
		matrixArray[i].display();
	}
	//(matrixArray[0]*matrixArray[1]).display();
	//cout<<"\n";
	*this=matrixArray[0]*matrixArray[1]*matrixArray[2]*matrixArray[3]
		*matrixArray[4];
}


/*
int main()
{
	Matrix translate;
	Matrix rotate;
	Vector vertex(4,5,6), axis(3,2,5);

	rotate.rotate(vertex, axis, 45);
	rotate.display();
	//translate.display();


	return 0;
}
*/
 
 
file name: helicopter.h
#ifndef HELICOPTER_H
#define HELICOPTER_H

#include "glutobject.h"
#include "glutobjects.h"

const GLfloat MainRotorLength=5;
const GLfloat TailRotorLength=1.5;

class Helicopter: public GlutObjectList
{
public:	
	virtual void display();
	Helicopter();
protected:
	//static GlutObjectList helicopter;
	GlutObjectSweepSphere cockpitBottomFront;
	GlutObjectSweepSphere cockpitBottomRear;
	GlutObjectSweepSphere cockpitWindow;
	GlutObjectSweepSphere cockpitRear;
	//boom
	GlutObjectHalfCone boomConnecter;
	GlutObjectHalfCone mainBoom;
	GlutObjectSphere tailSupport;
	//main rotor
	GlutObjectSphere mainRotor1;
	GlutObjectSphere mainRotor2;
	GlutObjectSphere mainRotor3;

	GlutObjectCylinder mainRotorAxis;

	
	//tail rotor 
	GlutObjectCylinder tailRotorAxis;
	GlutObjectSphere tailRotor1;
	GlutObjectSphere tailRotor2;
	GlutObjectSphere tailRotor3;
	
	//skid
	GlutObjectHalfCone skidSupport1;
	GlutObjectHalfCone skidSupport2;
	GlutObjectHalfCone skidSupport3;
	GlutObjectHalfCone skidSupport4;

	GlutObjectCylinder skid1;
	GlutObjectCylinder skid2;

	GlutObjectSweepTorus skidFront1;
	GlutObjectSweepTorus skidFront2;


	GLfloat tailRollingAngle;

	GLfloat rollingAngle;
	void drawCockpit();
	void drawMainRotor();
	void drawBoom();
	void drawTailRotor();
	void rotating();
	void drawSkid();
	//void init();



};

#endif
 
file name: helicopter.cpp
#include "glutobjects.h"
#include "glutObject.h"
#include "helicopter.h"
#include "utility.h"
#include <cmath>

//using namespace std;


//Helicopter::helicopter=new GlutObjectList;


const GLfloat X_Offset=3;
const GLfloat Z_Offset=2;
const GLfloat CockpitHeight=5;
const GLfloat BoomLength=25;
const GLfloat SkidHeight=5;
const GLfloat SkidDistance=3;

void Helicopter::display()
{
	rollingAngle+=8;
	tailRollingAngle+=3;


	drawMainRotor();
	drawTailRotor();
	/*
	mainRotor1.setDirection(cos(deg2rad(rollingAngle)), 0, sin(deg2rad(rollingAngle)));
	mainRotor2.setDirection(cos(deg2rad(rollingAngle+120)), 0,
		sin(deg2rad(rollingAngle+120)));
	mainRotor3.setDirection(cos(deg2rad(rollingAngle-60)), 0,
		sin(deg2rad(rollingAngle-60)));
*/
//	glPushMatrix();
//		glTranslatef(10, 0,0);
//	glPopMatrix();
}

void Helicopter::rotating()
{
	tailRotor1.setDirection(cos(deg2rad(tailRollingAngle)), sin(deg2rad(tailRollingAngle)), 0);
	tailRotor2.setDirection(cos(deg2rad(tailRollingAngle+120)), 
		sin(deg2rad(tailRollingAngle+120)), 0);

	tailRotor3.setDirection(cos(deg2rad(tailRollingAngle-120)), 
		sin(deg2rad(tailRollingAngle-120)), 0);

	mainRotor1.setDirection(cos(deg2rad(rollingAngle)), 0, sin(deg2rad(rollingAngle)));
	mainRotor2.setDirection(cos(deg2rad(rollingAngle+120)), 0,
		sin(deg2rad(rollingAngle+120)));
	mainRotor3.setDirection(cos(deg2rad(rollingAngle-120)), 0,
		sin(deg2rad(rollingAngle-120)));
}

Helicopter::Helicopter()
{

	addNewObject(&cockpitBottomFront);
	addNewObject(&cockpitBottomRear);
	addNewObject(&cockpitWindow);
	addNewObject(&cockpitRear);
	addNewObject(&boomConnecter);
	addNewObject(&mainBoom);
	
	addNewObject(&mainRotor1);
	addNewObject(&mainRotor2);
	addNewObject(&mainRotor3);
	addNewObject(&mainRotorAxis);
	addNewObject(&tailSupport);

	addNewObject(&tailRotorAxis);

	addNewObject(&tailRotor1);
	addNewObject(&tailRotor2);
	addNewObject(&tailRotor3);

	addNewObject(&skidSupport1);
	
	addNewObject(&skidSupport2);
	/*
	addNewObject(&skidSupport3);
	addNewObject(&skidSupport4);

	addNewObject(&skid1);
	addNewObject(&skid2);

	addNewObject(&skidFront1);
	addNewObject(&skidFront2);
	*/

	tailRollingAngle=0;

	rollingAngle=0;
	drawCockpit();
	drawBoom();
	drawMainRotor();
	drawTailRotor();
	drawSkid();
}


void Helicopter::drawSkid()
{
	skidSupport1.setColor(1, 0.4, 0.2, 1);
	skidSupport1.setPosition(X_Offset+SkidDistance, -CockpitHeight/2, SkidDistance);
	skidSupport1.setDirection(0, -1,0.8);
	skidSupport1.setVolume(SkidHeight, 0.5, 0.5);


	skidSupport2.setColor(1, 0.4, 0.2, 1);
	skidSupport2.setPosition(X_Offset+SkidDistance, -CockpitHeight/2, -SkidDistance);
	skidSupport2.setDirection(0, 1,-0.8);
	skidSupport2.setVolume(SkidHeight, 0.5, 0.5);

	skidSupport1.setColor(1, 0.4, 0.2, 1);
	skidSupport1.setPosition(X_Offset+SkidDistance, -CockpitHeight/2, SkidDistance);
	skidSupport1.setDirection(0, -1,0.8);
	skidSupport1.setVolume(SkidHeight, 0.5, 0.5);


	skidSupport1.setColor(1, 0.4, 0.2, 1);
	skidSupport1.setPosition(X_Offset+SkidDistance, -CockpitHeight/2, SkidDistance);
	skidSupport1.setDirection(0, -1,0.8);
	skidSupport1.setVolume(SkidHeight, 0.5, 0.5);


}


void Helicopter::drawBoom()
{
	boomConnecter.setColor(0.25, 1, 0.1, 1);
	//boomConnecter.setDirection(1,0,0);
	//boomConnecter.lastRotate(Z_AXIS, -90);
	boomConnecter.setVolume(3,2,2);
	boomConnecter.setPosition(8.65+X_Offset,0,0);

	//boom
	mainBoom.setColor(0, 0.8, 0.2,1);
	mainBoom.setPosition(9.5+X_Offset, 0, 0);
	mainBoom.setDirection(1, 0,0);
	mainBoom.setVolume(BoomLength, 1.5, 1.5);

	tailSupport.setColor(0.1, 0.7, 0.3,1);
	tailSupport.setVolume(1,1,1);
	tailSupport.setPosition(9.5+X_Offset+BoomLength/2, 0, 0);
}

void Helicopter::drawCockpit()
{
	cockpitBottomFront.setColor(1, 0,0,1);
	cockpitBottomFront.setVolume(5, CockpitHeight, 5);
	cockpitBottomFront.setDirection(-1, 0, 0);
	cockpitBottomFront.lastRotate(X_AXIS, 180);
	cockpitBottomFront.setPosition(-5+X_Offset,0,0);


	
	cockpitWindow.setColor(0, 0.5, 0.5, 0.5);
	cockpitWindow.setVolume(5, CockpitHeight, 5);
	cockpitWindow.setDirection(-1,0,0);
	cockpitWindow.setPosition(-5+X_Offset,0,0);


	cockpitBottomRear.setColor(1, 0,0,1);
	cockpitBottomRear.setVolume(15, CockpitHeight, 5);
	cockpitBottomRear.setDirection(1,0,0);
	cockpitBottomRear.lastRotate(X_AXIS, 180);
	cockpitBottomRear.setPosition(-5+X_Offset,0,0);

	cockpitRear.setColor(0,0.8, 0.3, 1);
	cockpitRear.setVolume(15, CockpitHeight, 5);
	cockpitRear.setDirection(1,0,0);
	cockpitRear.setPosition(-5+X_Offset,0,0);
	//cockpitRear.lastDraw()
}

void Helicopter::drawMainRotor()
{
	mainRotor1.setPosition(MainRotorLength*cos(deg2rad(rollingAngle)), 7, 
		MainRotorLength*sin(deg2rad(rollingAngle)));
	mainRotor1.setColor(0.3, 0.5, 0.7, 1);
	mainRotor1.setDirection(cos(deg2rad(rollingAngle)), 0, sin(deg2rad(rollingAngle)));
	mainRotor1.setVolume(MainRotorLength, 0.2, 0.3);

	mainRotor2.setPosition(MainRotorLength*cos(deg2rad(rollingAngle+120)), 7, 
		MainRotorLength*sin(deg2rad(rollingAngle+120)));
	mainRotor2.setColor(0.3, 0.5, 0.7, 1);
	mainRotor2.setDirection(cos(deg2rad(rollingAngle+120)), 0,
		sin(deg2rad(rollingAngle+120)));
	mainRotor2.setVolume(MainRotorLength, 0.2, 0.3);



	mainRotor3.setPosition(MainRotorLength*cos(deg2rad(rollingAngle-120)), 7, 
		MainRotorLength*sin(deg2rad(rollingAngle-120)));
	mainRotor3.setColor(0.3, 0.5, 0.7, 1);

	mainRotor3.setDirection(cos(deg2rad(rollingAngle-120)), 0,
		sin(deg2rad(rollingAngle-120)));
	mainRotor3.setVolume(MainRotorLength, 0.2, 0.3);

	mainRotorAxis.setPosition(0, CockpitHeight-0.5, 0);
	mainRotorAxis.setDirection(0,1,0);
	mainRotorAxis.setVolume(5, 0.3, 0.3);
	mainRotorAxis.setColor(0.1,0.8,0.3,1);
}


void Helicopter::drawTailRotor()
{
	tailRotorAxis.setPosition(9.5+BoomLength/2+X_Offset, 0, Z_Offset/2);
	tailRotorAxis.setVolume(Z_Offset, 0.1, 0.1);
	tailRotorAxis.setColor(0.8, 0.3,0.3,1);
	tailRotorAxis.setDirection(0,0,1);



	tailRotor1.setPosition(9.5+BoomLength/2+X_Offset+TailRotorLength*cos(deg2rad(tailRollingAngle)), 
		TailRotorLength*sin(deg2rad(tailRollingAngle)), Z_Offset);
	tailRotor1.setDirection(cos(deg2rad(tailRollingAngle)), sin(deg2rad(tailRollingAngle)), 0);
	tailRotor1.setColor(0.5, 0.4, 0.2,1);
	tailRotor1.setVolume(TailRotorLength, 0.1, 0.2);
	
	tailRotor2.setPosition(9.5+BoomLength/2+X_Offset+TailRotorLength*cos(deg2rad(tailRollingAngle+120)), 
		TailRotorLength*sin(deg2rad(tailRollingAngle+120)), Z_Offset);
	tailRotor2.setDirection(cos(deg2rad(tailRollingAngle+120)), 
		sin(deg2rad(tailRollingAngle+120)), 0);
	tailRotor2.setColor(0.5, 0.4, 0.2,1);
	tailRotor2.setVolume(TailRotorLength, 0.1, 0.2);


	tailRotor3.setPosition(9.5+BoomLength/2+X_Offset+TailRotorLength*cos(deg2rad(tailRollingAngle-120)), 
		TailRotorLength*sin(deg2rad(tailRollingAngle-120)), Z_Offset);
	tailRotor3.setDirection(cos(deg2rad(tailRollingAngle-120)), 
		sin(deg2rad(tailRollingAngle-120)), 0);
	tailRotor3.setColor(0.5, 0.4, 0.2,1);
	tailRotor3.setVolume(TailRotorLength, 0.1, 0.2);
}	
 
file name: main.cpp
#include <GL/glut.h>
#include "glutObject.h"
#include "glutobjects.h"
#include "helicopter.h"
#include <stdio.h>
#include <iostream>
#include <cmath>

using namespace std;

//#include "glutObject.h"

//using namespace NICKSPACE;
//extern void displayCallback();

int main(int argc, char** argv)
{
	glutInit(&argc, argv);	
	//glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
	//GlutObjectSphere sphere;
	//GlutObjectCube cube;
	/*
	GlutObjectCone cone;
	cone.setColor(0, 1, 0);
	cone.setPosition(10, 0, 10);
	cone.setVolume(8, 2, 2);
	cone.setDirection(1, 1, 1);
	
	GlutObjectCylinder cylinder;
	cylinder.setDirection(0, 1, 1);
	cylinder.setPosition(10, 10, 0);
	cylinder.setVolume(4, 2, 1);
	cylinder.setColor(0, 1, 0.5);

	GlutObjectHalfCone halfCone;
	halfCone.setVolume(10, 5, 5);
	halfCone.setDirection(0, 0, 1);
	halfCone.setColor(1,1,0);
	halfCone.setPosition(5, 5, 0);
	GlutObjectSweepTorus o(0.13, 0.125);
	o.setDirection(1, 0, 0);
	o.setPosition(0, 0, 0);
	o.setColor(1, 1, 0);
	o.setVolume(4, 4, 4);
	//cout<<cos(3.1415/2.0)<<endl;
	//sphere.setPosition(0, 0, 0);
	//sphere.setVolume(2, 2, 2);

	
	//cube.setPosition(10, 0, 0);
	//cube.setColor(0,1,0);
	//cube.setVolume(2, 2, 2);
	//cube.setDirection(5, 5,0);
/*
	GlutObject3DAxis axis;

	GlutObjectHalfSphere halfSphere;
	halfSphere.setPosition(0, 2, 2);
	halfSphere.setVolume(1, 1, 1);
	halfSphere.setDirection(0,0,30);
	halfSphere.setClipRatio(0.7);
/*
	GlutObjectCylinder cylinder;
	cylinder.setColor(0.5, 0.5, 0.0);
	//cylinder.setDirection(0, 60, 0);
	cylinder.setVolume(9, 9, 14);
	cylinder.setPosition(0, 0, -60);

	GlutObjectCone cone;
	cone.setColor(0, 1, 0);
	cone.setPosition(0, 1, -2);
	cone.setVolume(2, 2, 1);
	*/
	//GlutObjectFace face;
/*
	GlutObjectSweepSphere cone, cone1;

	cone1.setColor(0.3, 1, 0.3, 0.6);
	cone1.setPosition(10, 0, 0.5);
	cone1.setVolume(3, 3, 3);
	cone1.setDirection(-1, 0,0);

	cone.setColor(1, 0.3, 0, 1);
	cone.setPosition(10, 0, 0);
	cone.setVolume(2, 2, 2);
	cone.setDirection(-1, 0,0);
*/
	Helicopter heli;
	GlutObjectFace face;
	run();


	return 0;
}
 
 
 
 

				 back.gif (341 bytes)       up.gif (335 bytes)         next.gif (337 bytes)