Opengl大作业2D&3D,基于freeglut库

由于学校要求,opengl的一系列库中只允许使用freeglut,软件为vs2019。代码贴在下边:

2D作业:

// File ID: NewYearCard.cpp
// Title: Happy New Year!
// Author: L_Stock
#define FREEGLUT_STATIC
#define PI 3.14159265
#include <GL/freeglut.h>
#include <iostream>

GLint time_interval = 3;         																       // the time interval
GLfloat viewPortx = 0, viewPorty = 0, viewPWidth = 1280;					                           // the location and size of the viewport
GLfloat viewPxStep = 0, viewPyStep = 0, viewPWStep = 0;												   // steps of the viewport's location and size
GLfloat Color = 0, ColorStep = 0;																	   // the color of the words
GLfloat star = 292, starRotate = 0, starStep = 0, starRotateStep = 0.03;						       // location and step of the stars
GLfloat fwStart = -450, fwStartSize = 3, fwSStep = 0, fwSSStep = 0;								       // starting point, its size and step of the starting flame in a firework
GLfloat flameLength = -50, flameSize = -4, deFlameLength = 0, deFlameSize = 0;					       // length and size of the flame
GLfloat flameLStep = 0, flameSStep = 0, deFlameLStep = 0, deFlameSStep = 0;						       // steps of length and size above
																								  	   
void display(void);																				  	   
void GL_CIRCLE(float x, float y, float r, int n);													   // draw a circle
void GL_ELLIPSE(float x, float y, float longr, float shortr, int n);								   // draw a ellipse
void GL_STAR(float x, float y, float longr, float degree);											   // draw a star
void GL_LEAVES(float x, float y, float size, float light);										       // draw some leaves with snow
void GL_TREE(float x, float y, float size, float light);										       // draw a tree
void GL_FLAME(float startx, float starty, float endx, float endy, float size);					       // draw a piece of flame
void GL_FIREWORK(float x, float y);																       // draw a firework
void selectFont(int size, int charset, const char* face);										       // select the font
void keyboard_input(unsigned char key, int x, int y);											       // keyboard interaction
void mouse_input(int button, int state, int x, int y);											       // mouse interactions
void when_in_mainloop();																		       // idle callback function
void OnTimer(int value);

int main(int argc, char** argv)
 {
	// make sure the window is big enough and set its location in the screen
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_MULTISAMPLE);
	glutInitWindowPosition(glutGet(GLUT_SCREEN_WIDTH) / 2 - 640, glutGet(GLUT_SCREEN_HEIGHT) / 2 - 360);
	glutInitWindowSize(1280, 720);

	// create the window
	glutCreateWindow("Happy New Year!");
	glutDisplayFunc(display);
	glutIdleFunc(when_in_mainloop);
	glutTimerFunc(time_interval, OnTimer, 1);
	glutKeyboardFunc(keyboard_input);
	glutMouseFunc(mouse_input);
	glutMainLoop();
}

// to display the figures onto the screen
void display(void)
{
	// initialization
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluOrtho2D(0, 800, 0, 600);
	glClearColor(0, 0, 0, 0);
	glClear(GL_COLOR_BUFFER_BIT);

	// to draw a background with color transiting smoothly from dark blue to black
	glBegin(GL_QUADS);
		// one quad
		glColor3f(0, 0, 0.2);
		glVertex2f(0, 0);
		glVertex2f(800, 0);
		glColor3f(0, 0, 0.06);
		glVertex2f(800, 300);
		glVertex2f(0, 300);
		// the other quad
		glColor3f(0, 0, 0.06);
		glVertex2f(0, 300);
		glVertex2f(800, 300);
		glColor3f(0, 0, 0);
		glVertex2f(800, 600);
		glVertex2f(0, 600);
	glEnd();

	// the moon, it is made up of two circles, between which one is black and the other is white.
	glColor3f(1, 0.985, 0.88);
	GL_CIRCLE(100, 460, 70, 40);
	glColor3f(0, 0, 0.04);
	GL_CIRCLE(80, 480, 75, 40);

	// strings for greeting
	glColor3f(Color, Color, Color + 0.045);
	selectFont(256, ANSI_CHARSET, "Times New Roman");
	glRasterPos2f(207, 310);
	static int isFirstCall = 1;
	static GLuint lists;
	if (isFirstCall) {
		isFirstCall = 0;
		lists = glGenLists(256);
		wglUseFontBitmaps(wglGetCurrentDC(), 0, 256, lists);
	}
	const char* str = "2 0 2 3";
	for (; *str != '\0'; ++str) {
		glCallList(lists + *str);
	}
	glColor3f(Color, Color, Color + 0.08);
	glRasterPos2f(277, 265);
	for (const char* c = "GREETINGS FOR THE NEW YEAR !"; *c != '\0'; c++)
		glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_24, *c);

	// firework
	GL_FIREWORK(400, 400);
	GL_FIREWORK(150, 350);
	GL_FIREWORK(650, 350);

	// seven stars
	GL_STAR(350, 380 + star, 13, -30);
	GL_STAR(430, 455 + star, 13, 80);
	GL_STAR(500, 440 + star, 13, -30);
	GL_STAR(600, 435 + star, 13, 80);
	GL_STAR(640, 330 + star, 13, -30);
	GL_STAR(760, 350 + star, 13, 80);
	GL_STAR(765, 510 + star, 13, -30);

	// green trees on the snow land
	GL_TREE(50, 95, 65, 0.7);
	GL_TREE(110, 70, 55, 0.5);
	GL_TREE(150, 90, 70, 0.85);
	glColor3f(0.91, 0.91, 0.96);
	GL_ELLIPSE(260, -10, 170, 60, 50);
	glColor3f(0.95, 0.95, 1);
	GL_ELLIPSE(0, -20, 260, 110, 60);
	GL_TREE(80, 100, 80, 1);
	GL_TREE(300, 60, 70, 0.9);

	// do you want to build a snowman
	glColor3f(0.93, 0.93, 0.97);
	GL_ELLIPSE(705, 60, 65, 60, 40);
	glColor3f(0.95, 0.95, 1);
	GL_ELLIPSE(709, 160, 44, 40, 40);
	glColor3f(0, 0, 0);
	GL_ELLIPSE(720, 165, 4, 6, 20);
	GL_ELLIPSE(680, 165, 3, 4.5, 20);
	glRasterPos2f(694.5, 143);
	glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_24, 'v');
	glColor3f(0, 0.5, 0.8);
	for (float i = -2 * PI / 3; i <= -PI / 3; i += 0.05)
		GL_CIRCLE(709 + 83 * cos(i), 189 + 75 * sin(i), 8, 20);
	glBegin(GL_QUADS);
		glVertex2f(739, 130);
		glVertex2f(749, 130);
		glVertex2f(770, 102);
		glVertex2f(756, 90);
	glEnd();

	glutSwapBuffers();
}

// to draw a circle, the location of the center of which and the radius are required
// it is worth noticing that: when the polygon has enough sides, it is difficult to distinguish it from the circle
// so a positive integer n is given to set the number of sides.
void GL_CIRCLE(float x, float y, float r, int n)
{
	glBegin(GL_POLYGON);
		for (int i = 0; i < n; i++) glVertex2f(x + r * cos(2 * PI / n * i), y + r * 4 / 3 * sin(2 * PI / n * i));
	glEnd();
}

// draw a ellipse, the principle of which is similar to that of drawing a circle
void GL_ELLIPSE(float x, float y, float longr, float shortr, int n) 
{
	glBegin(GL_POLYGON);
		for (int i = 0; i < n; i++) glVertex2f(x + longr * cos(2 * PI / n * i), y + shortr * 4 / 3 * sin(2 * PI / n * i));
	glEnd();
}

// to draw a star, broken the star into 10 triangles and draw them one by one. 
// Rotation matrixs are utilized to set the deviation angle.
void GL_STAR(float x, float y, float longr, float degree)
{
	glPushMatrix();
	glTranslatef(x, y, 0);
	glScalef(1, 1.333, 0);
	glRotatef(degree + starRotate, 0, 0, 1);
	glScalef(1, 0.75, 0);
	glTranslatef(-x, -y, 0);
	glBegin(GL_TRIANGLES);
		for (int i = 0; i < 5; i++) {
			glColor3f(1, 0.93, 0.6);
			glVertex2f(x, y);
			glColor3f(0.72, 0.6, 0);
			glVertex2f(x + longr / 2 * cos(2 * PI / 5 * (i - 1.0) + PI / 5), y + longr / 2 * 4 / 3 * sin(2 * PI / 5 * (i - 1.0) + PI / 5));
			glColor3f(0.82, 0.7, 0);
			glVertex2f(x + longr * cos(2 * PI / 5 * i), y + longr * 4 / 3 * sin(2 * PI / 5 * i));
		}
		for (int i = 0; i < 5; i++) {
			glColor3f(1, 0.93, 0.6);
			glVertex2f(x, y);
			glColor3f(0.72, 0.6, 0);
			glVertex2f(x + longr / 2 * cos(2 * PI / 5 * i + PI / 5), y + longr / 2 * 4 / 3 * sin(2 * PI / 5 * i + PI / 5));
			glColor3f(0.82, 0.7, 0);
			glVertex2f(x + longr * cos(2 * PI / 5 * i), y + longr * 4 / 3 * sin(2 * PI / 5 * i));
		}
	glEnd();
	glPopMatrix();
}

// to draw some leaves with snow on them
void GL_LEAVES(float x, float y, float size, float light)
{
	// leaves
	glBegin(GL_POLYGON);
	glColor3f(0.35 * light, 0.54 * light, 0.23 * light);
	glVertex2f(x, y + size / 10);
	glColor3f(0.22 * light, 0.34 * light, 0.14 * light);
	glVertex2f(x, y - size);
	glVertex2f(x - size / 9, y - size * 13 / 9);
	glVertex2f(x - size / 5, y - size);
	glVertex2f(x - size * 2 / 3, y - size * 14 / 9);
	glVertex2f(x - size * 5 / 9, y - size);
	glVertex2f(x - size, y - size * 9 / 8);
	glEnd();

	// and snow on them. Snow has two layers, the upper one is white while the lower one is grey.
	float t = 0;
	glColor3f(0.5 * light, 0.5 * light, 0.5 * light);
	for (int i = 0; i < 8; i++) {
		GL_CIRCLE(x - size * 5 / 8 + i * size / 14,							                           // x
			y - size * 7 / 10 + i * size / 60 - pow(-1, i) * size / 25 + t,                            // y
			size / 10, 														                           // r
			(int)(size / 2));												                           // n
		if (i == 4) t = size / 16;
	}
	t = 0;
	glColor3f(0.95 * light, 0.95 * light, light);
	for (int i = 0; i < 8; i++) {
		GL_CIRCLE(x - size * 5 / 8 + i * size / 14,							                           // x
			y - size * 2 / 3 + i * size / 60 - pow(-1, i) * size / 25 + t,                             // y
			size / 10, 														                           // r
			(int)(size / 2));												                           // n
		if (i == 4) t = size / 16;
	}
}

// to draw a tree, a tree is made up of 6 pieces of leaves
void GL_TREE(float x, float y, float size, float light)
{
	// the brown trunk
	glColor3f(0.4 * light, 0.16 * light, 0);
	glBegin(GL_POLYGON);
		glVertex2f(x, y - size / 25);
		glColor3f(0.5 * light, 0.25 * light, 0);
		glVertex2f(x + size / 12, y);
		glVertex2f(x + size / 20, y + size * 4 / 5);
		glVertex2f(x - size / 20, y + size * 4 / 5);
		glVertex2f(x - size / 12, y);
	glEnd();
	float localsize = size / 9;

	// the white snow and the green leaves
	for (int i = 0; i < 3; i++) {
		GL_LEAVES(x,																	               // x
			y + size * 5 / 4 + i * size * 2 / 5 - pow(i / 2, 2) * size / 6,                            // y
			size * 2 / 3 - i * size / 6,												               // size
			light + light * i / 6);					   									               // light
		glPushMatrix();																                   
		glTranslatef(x, 0, 0);														                   
		glScalef(-1, 1, 0);															                   
		glTranslatef(-x, 0, 0);														                   
		GL_LEAVES(x,																	               // x
			y + size * 5 / 4 + i * size * 2 / 5 - pow(i / 2, 2) * size / 6,   			               // y
			size * 2 / 3 - i * size / 6,												               // size
			light + light * i / 6);					   									               // light
		glPopMatrix();
	}
}

// to draw a flame. It uses a triangle fan to imitate a circular cone.
void GL_FLAME(float startx, float starty, float endx, float endy, float size)
{
	glColor3f(1, 0, 0);
	size += flameSize - deFlameSize;
	glBegin(GL_TRIANGLE_FAN);
		glVertex2f(startx + deFlameLength, starty);
		glColor3f(1, 0.8, 0);
		for (int i = 0; i <= 20; i++) 
			glVertex2f(endx + size * cos(2 * PI / 15 * i) + flameLength, 				               // x
				endy + size * 4 / 3 * sin(2 * PI / 15 * i));							               // y
	glEnd();
}

// to draw a firework which is made up of 18 flames and 5 stars
void GL_FIREWORK(float x, float y)
{
	// the starting flame is also a triangle fan
	float size = 4;
	glColor3f(0.7, 0, 0);
	glBegin(GL_TRIANGLE_FAN);
	glVertex2f(x, y - 50 + fwStart);
	glColor3f(0.8, 0.5, 0);
	for (int i = 0; i <= 20; i++)
		glVertex2f(x + fwStartSize * cos(2 * PI / 15 * i),											   // x
			y + fwStart + fwStartSize * 4 / 3 * sin(2 * PI / 15 * i));								   // y
	glEnd();

	// the location of every flame is different, enabled by a periodic function.
	for (float i = 0; i < 18; i++) {
		glPushMatrix();
		glTranslatef(x, y, 0);
		glScalef(1, 1.333, 0);
		glRotatef(i * 20, 0, 0, 1);
		glScalef(1, 0.75, 0);
		glTranslatef(-x, -y, 0);
		GL_FLAME(x + 3 * size + 2 * size * sin(i * 2),												   // startx
			y,																						   // starty
			x + 20 * size + 2 * size * (sin(i * 3) + cos(i * 3)),									   // endx
			y,																						   // endy
			size);																					   // size
		glPopMatrix();
	}
	size += flameSize - deFlameSize;

	// five flame stars, showing up along with the firework
	for (float i = 0; i < 5; i++) {
		glPushMatrix();
		glTranslatef(x, y, 0);
		glScalef(1, 1.333, 0);
		glRotatef(i * 72, 0, 0, 1);
		glScalef(1, 0.75, 0);
		glTranslatef(-x, -y, 0);
		GL_STAR(x + 100 + flameLength,																	// x
			y,																							// y
			2 * size,																					// longr
			i * 20);																					// degree
		glPopMatrix();
		glEnd();
	}
}

// to select a font
void selectFont(int size, int charset, const char* face) {
	HFONT hFont = CreateFontA(size, 0, 0, 0, FW_MEDIUM, 0, 0, 0, charset, OUT_DEFAULT_PRECIS,
		CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_SWISS, face);
	HFONT hOldFont = (HFONT)SelectObject(wglGetCurrentDC(), hFont);
	DeleteObject(hOldFont);
}

void keyboard_input(unsigned char key, int x, int y)
{
	if (key == 'q' || key == 'Q') exit(0);
	else if (key == ' ' && fwStart == -450) {
		viewPxStep = 4;
		viewPWStep = 8;
	}
}

void mouse_input(int button, int state, int x, int y) 
{
	if (state == GLUT_DOWN && button == GLUT_LEFT_BUTTON) starStep = 0.8;
}

// force OpenGL to redraw the current window
void when_in_mainloop() {
	glViewport(viewPortx, viewPorty, viewPWidth, viewPWidth * 0.5625);
	glutPostRedisplay();
} 

void OnTimer(int value)
{
	viewPortx -= viewPxStep;
	viewPorty -= viewPyStep;
	viewPWidth += viewPWStep;
	star -= starStep;
	starRotate -= starRotateStep;
	fwStart += fwSStep;
	fwStartSize += fwSSStep;
	flameLength += flameLStep;
	flameSize += flameSStep;
   	deFlameLength += deFlameLStep;
	deFlameSize += deFlameSStep;
	Color += ColorStep;

	if (viewPortx <= -500) {
		viewPxStep = 0;
		viewPWStep = 0;
		fwSStep = 0.9;
		fwSSStep = -0.006;
		viewPyStep = fwSStep;
	}
	if (starRotate < -360) starRotate += 360;
	if (star <= 0) {
		starStep = 0;
		star = 0;
	}
	if (fwStart >= 0) {
		fwSStep = 0;
		fwSSStep = 0;
		flameLStep = 0.4;
		flameSStep = 0.032;
		viewPyStep = -3.6;
		viewPxStep = -4;
		viewPWStep = -8;
	}
	if (flameLength >= 0) {
		flameLStep = 0;
		flameSStep = 0;
		deFlameLStep = 0.1;
		deFlameSStep = 0.008;
		ColorStep = 0.004;
		viewPyStep = 0;
		viewPxStep = 0;
		viewPWStep = 0;
	}
	if (deFlameLength >= 50) {
		deFlameLStep = 0;
		deFlameSStep = 0;
		ColorStep = 0;
	}

	glutTimerFunc(time_interval, OnTimer, 1);
}

3D作业:

注意3D没有贴图文件会闪退,贴图文件打包在网盘里了,记得和.cpp放在同一个目录下。

链接:https://pan.baidu.com/s/11_j8PiyzTbrreNE6JrdfIg?pwd=2333 
提取码:2333

// File ID: TrainTrack.cpp
// Title: Live a Wonderful Life!
// Author: L_Stock
#define FREEGLUT_STATIC
#define GLUT_DISABLE_ATEXIT_HACK
#define PI 3.14159265
#include <GL/freeglut.h>
#include <math.h>
#include <stdlib.h> 
#include <stdio.h>
#include "vector"

using namespace std;

GLint cutoff = 0;
GLfloat lookat = 0, lookatStep = 0;
GLfloat camerax1 = 0, camerax2 = 0, cmrAccelerationx1 = 0, cmrAccelerationx2 = 0;
GLfloat cameray = 0, cmrAccelerationy = 0;
GLfloat cameraz1 = 0, cameraz2 = 0, cmrAccelerationz = 0;
GLfloat Rotate = 0, rttAcceleration = 0;
GLfloat tra = 0, traAcceleration = 0;
GLboolean start = false, stage2 = false, shake = false;
GLfloat shakeRange = 0, shakesita = 0, ssitaAcceleration = 2;
GLfloat light1_position[] = { 0, 293, 155.5, 1 };

// These are information of texture loaded.
GLint imagewidth0, imageheight0, pixellength0;
GLint imagewidth1, imageheight1, pixellength1;
GLint imagewidth2, imageheight2, pixellength2;
vector<GLubyte*>p; 
GLuint texture[3];

void GL_LIGHT(void);
void GL_READIMAGE(const char path[256], GLint& imagewidth, GLint& imageheight, GLint& pixellength);
void GL_LOADTEXTURE(void);
void ADJUST_CAMERA(void);
void GL_TRIPRISM(GLfloat length, GLfloat depth, GLfloat angle);
void GL_CUBOID(GLfloat x, GLfloat y, GLfloat z, GLfloat length, GLfloat height, GLfloat depth);
void GL_WOOD(GLfloat x, GLfloat y, GLfloat z, GLfloat length, GLfloat height, GLfloat depth);
void GL_RAIL(GLfloat track_x);
void GL_SCREW(GLfloat track_x);
void GL_RAILROAD(void);
void GL_1BYn_RING(GLfloat r, GLfloat h, GLint n);
void QUARTER_PILLAR(GLfloat r, GLfloat h);
void STEAM_POCKET(GLfloat sp_z);
void GL_WHEEL(GLfloat wheel_x, GLfloat wheel_z, GLfloat r, GLfloat offset);
void WALL_PIECE(GLfloat wall_x, GLfloat wall_y, GLfloat wall_z);
void GL_DOOR(GLfloat door_x, GLfloat door_y, GLfloat door_z);
void BENT_BRACKET(void);
void TRAIN_HEAD(void);
void GL_LOCK(GLfloat lock_z);
void GL_CARRIAGE(GLfloat carriage_z);
void TRAIN_BODY(void);
void GL_GLASS(void);
void GL_TRAIN(void);
void GL_PLATFORM(GLfloat r);
void BRIDGE_PIECE(void);
void GL_BRIDGE(void);
void GL_BACKGROUND(GLfloat angle);
void display(void);
void keyboard_input(unsigned char key, int x, int y);
void mouse_input(int button, int state, int x, int y);
void Animation(void);

int main(int argc, char** argv) {
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_MULTISAMPLE);
	glutInitWindowPosition(160, 70);
	glutInitWindowSize(1600, 900);
	glutCreateWindow("Live a Wonderful Life!");

	GL_LIGHT();
	GL_LOADTEXTURE();
	glutDisplayFunc(display);
	glDeleteTextures(3, &texture[0]);
	glutKeyboardFunc(keyboard_input);
	glutMouseFunc(mouse_input);
	glutIdleFunc(Animation);

	glutMainLoop();
}

// Display all the things.
void display(void)
{
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
	ADJUST_CAMERA();

	// set the light on the head of the train
	GLfloat light1_ambient_diffuse[] = { 0.8f, 0.8f, 0.8f, 1.0f };
	GLfloat light1_specular[] = { 1.0f, 1.0f, 1.0f, 1.0f };
	GLfloat spot1_position[] = { 0, -1, -2 };
	GLfloat attenuation1[] = { 0.03 };
	glLightfv(GL_LIGHT1, GL_AMBIENT, light1_ambient_diffuse);
	glLightfv(GL_LIGHT1, GL_DIFFUSE, light1_ambient_diffuse);
	glLightfv(GL_LIGHT1, GL_SPECULAR, light1_specular);
	glLightf(GL_LIGHT1, GL_SPOT_CUTOFF, cutoff);
	glLightfv(GL_LIGHT1, GL_SPOT_DIRECTION, spot1_position);
	glLightfv(GL_LIGHT1, GL_LINEAR_ATTENUATION, attenuation1);

	// The train, the railroad, and the bridge.
	glPushMatrix();
	glTranslatef(0, 0, -tra);
	glLightfv(GL_LIGHT1, GL_POSITION, light1_position);
	GL_TRAIN();
	glPopMatrix();
	GL_RAILROAD(); 
	GL_BRIDGE();

	// Disable the lighting for a while to better show the night sky.
	glDisable(GL_LIGHTING);
	for (int i = 0; i < 4; i++) GL_BACKGROUND(i * 90);
	glColor3f(0.9, 1, 0.9);
	glBegin(GL_QUAD_STRIP);
	for (int i = 0; i < 220; i++)
	{
		glVertex3f(-200 + 1000 * cos(2 * PI / 395 * (i - 140.0)), 1700 + 1000 * sin(2 * PI / 395 * (i - 140.0)), -5900);
		glVertex3f(-700 + 1000 * cos(2 * PI / 580 * (i - 170.0)), 2030 + 1000 * sin(2 * PI / 580 * (i - 170.0)), -5900);
	}
	glEnd();
	glEnable(GL_LIGHTING);

	// to imitate the inverted reflection in water, change the train light first.
	GLfloat light_ambient_diffuse[] = { 0.25f, 0.25f, 0.25f, 1.0f };
	glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient_diffuse);
	glLightfv(GL_LIGHT0, GL_DIFFUSE, light_ambient_diffuse);

	// Disable the light, draw the reflection and recover it.
	// As only the reflection of the bridge will be shown in the screen, only the bridge is needed.
	glDisable(GL_LIGHT1);
	glPushMatrix();
	glScalef(1, -0.6, 1);
	glTranslatef(0, -415, 0);
	GL_BRIDGE();
	glTranslatef(0, 0, -tra);
	glPopMatrix();
	glEnable(GL_LIGHT1);

	// recver the train light.
	GLfloat light_diffuse[] = { 0.4f, 0.4f, 0.4f, 1.0f };
	glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse);

	// The material of the water.
	GLfloat wat_ambient_diffuse[] = { 0, 0, 0, 0.3 };
	GLfloat wat_specular[] = { 0, 0, 0, 0.3 };
	GLfloat wat_shininess[] = { 0 };

	// set the material for the water and draw it.
	glMaterialfv(GL_FRONT, GL_AMBIENT, wat_ambient_diffuse);
	glMaterialfv(GL_FRONT, GL_DIFFUSE, wat_ambient_diffuse);
	glMaterialfv(GL_FRONT, GL_SPECULAR, wat_specular);
	glMaterialfv(GL_FRONT, GL_SHININESS, wat_shininess);

	// Use a piece of translucent cuboid to imitate the water.
	GL_CUBOID(0, 157, 0, 16000, 1, 16000);

	// Swap the buffers.
	glutSwapBuffers();
}

// Enable the light from the environment. This is a directional light.
void GL_LIGHT(void)
{
	glEnable(GL_LIGHTING);
	glEnable(GL_LIGHT0);
	glDepthFunc(GL_LEQUAL);
	glEnable(GL_DEPTH_TEST);
	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

	GLfloat light_ambient[] = { 0.25f, 0.25f, 0.25f, 1.0f };
	GLfloat light_diffuse[] = { 0.4f, 0.4f, 0.4f, 1.0f };
	GLfloat light_specular[] = { 0.7f, 0.7f, 0.7f, 1.0f };
	GLfloat light_position[] = { -1500, 800, 100, 0 }; // Directional light

	glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient);
	glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse);
	glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular);
	glLightfv(GL_LIGHT0, GL_POSITION, light_position);

	// clear the color
	glClearColor(0, 0, 0, 0);
}

// Read image from file. The form of image is limited to .bmp.
void GL_READIMAGE(const char path[256], GLint& imagewidth, GLint& imageheight, GLint& pixellength)
{
	GLubyte* pixeldata;
	FILE* pfile;
	fopen_s(&pfile, path, "rb");
	if (pfile == 0) exit(0);

	fseek(pfile, 0x0012, SEEK_SET);
	fread(&imagewidth, sizeof(imagewidth), 1, pfile);
	fread(&imageheight, sizeof(imageheight), 1, pfile);

	pixellength = imagewidth * 3;
	while (pixellength % 4 != 0)pixellength++;
	pixellength *= imageheight;

	pixeldata = (GLubyte*)malloc(pixellength);
	if (pixeldata == 0) exit(0);

	fseek(pfile, 54, SEEK_SET);
	fread(pixeldata, pixellength, 1, pfile);
	p.push_back(pixeldata);
	fclose(pfile);
}

// Load textures.
void GL_LOADTEXTURE(void)
{
	glEnable(GL_TEXTURE_2D);
	GL_READIMAGE("WD.bmp", imagewidth0, imageheight0, pixellength0);
	GL_READIMAGE("BG.bmp", imagewidth1, imageheight1, pixellength1);
	GL_READIMAGE("ST.bmp", imagewidth2, imageheight2, pixellength2);

	glPixelStorei(GL_UNPACK_ALIGNMENT, 1); // set pixel storage modes (in the memory)
	glGenTextures(3, &texture[0]); // number of texture names to be generated and an array of texture names
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_BLEND_SRC);
}

// Set the model-view-projection matrix
void ADJUST_CAMERA(void)
{
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluPerspective(60, 1.77777778, 1, 10000);

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	gluLookAt(-45.0 - camerax1, 275.0 + cameray, 80.0 - cameraz1, 0.0 - camerax2, lookat + 275.0 + cameray, 120.0 - cameraz2, 0, 1, 0);
}

// Generate a triangle prism at the original. It has so many limitations.
void GL_TRIPRISM(GLfloat length, GLfloat depth, GLfloat angle)
{
	// The side. This is made up of three quads.
	GLfloat height = length * tan(angle);
	glBegin(GL_QUADS);
	glNormal3f(0, -1, 0);
	glVertex3f(-0.5 * length, -0.5 * height, -0.5 * depth);
	glVertex3f( 0.5 * length, -0.5 * height, -0.5 * depth);
	glVertex3f( 0.5 * length, -0.5 * height,  0.5 * depth);
	glVertex3f(-0.5 * length, -0.5 * height,  0.5 * depth);
	glNormal3f(-1, 0, 0);
	glVertex3f(-0.5 * length, -0.5 * height, -0.5 * depth);
	glVertex3f(-0.5 * length, -0.5 * height,  0.5 * depth);
	glVertex3f(-0.5 * length,  0.5 * height,  0.5 * depth);
	glVertex3f(-0.5 * length,  0.5 * height, -0.5 * depth);
	glNormal3f(sin(angle), cos(angle), 0);
	glVertex3f(-0.5 * length,  0.5 * height, -0.5 * depth);
	glVertex3f(-0.5 * length,  0.5 * height,  0.5 * depth);
	glVertex3f( 0.5 * length, -0.5 * height,  0.5 * depth);
	glVertex3f( 0.5 * length, -0.5 * height, -0.5 * depth);
	glEnd();

	// The top and the bottom. These are two triangles.
	glBegin(GL_TRIANGLES);
	glNormal3f(0, 0, -1);
	glVertex3f( 0.5 * length, -0.5 * height, -0.5 * depth);
	glVertex3f(-0.5 * length, -0.5 * height, -0.5 * depth);
	glVertex3f(-0.5 * length,  0.5 * height, -0.5 * depth);
	glNormal3f(0, 0, 1);
	glVertex3f( 0.5 * length, -0.5 * height,  0.5 * depth);
	glVertex3f(-0.5 * length, -0.5 * height,  0.5 * depth);
	glVertex3f(-0.5 * length,  0.5 * height,  0.5 * depth);
	glEnd();
}

// Generate a cuboid which is made up of two triangle prism. Cooridinate can be set through this function.
void GL_CUBOID(GLfloat x, GLfloat y, GLfloat z, GLfloat length, GLfloat height, GLfloat depth)
{
	glPushMatrix();
	glTranslatef(x, y, z);
	GL_TRIPRISM(length, depth, atan(height / length));
	glRotatef(180, 0, 0, 1);
	GL_TRIPRISM(length, depth, atan(height / length));
	glPopMatrix();
}

// Generate one piece of wood sleeper. Use a for loop to generate others. Textures have been bound.
void GL_WOOD(GLfloat x, GLfloat y, GLfloat z, GLfloat length, GLfloat height, GLfloat depth)
{
	// Given that the bottom and the side face to negative half axis of X-axis are not required, they are omitted.
	// As a result. the wood is made up of only 4 quads, rather than 6.
	glEnable(GL_TEXTURE_2D);
	glTexImage2D(GL_TEXTURE_2D, 0, 3, imagewidth0, imageheight0, 0, GL_BGR_EXT, GL_UNSIGNED_BYTE, p[0]);
	glBegin(GL_QUADS);
	glNormal3f(0, 0, -1);
	glTexCoord2f(0.0, 0.0); glVertex3f(x - 0.5 * length, y - 0.5 * height, z - 0.5 * depth);
	glTexCoord2f(0.0, 0.5); glVertex3f(x + 0.5 * length, y - 0.5 * height, z - 0.5 * depth);
	glTexCoord2f(0.1, 0.5); glVertex3f(x + 0.5 * length, y + 0.5 * height, z - 0.5 * depth);
	glTexCoord2f(0.1, 0.0); glVertex3f(x - 0.5 * length, y + 0.5 * height, z - 0.5 * depth);
	glNormal3f(0, 1, 0);
	glTexCoord2f(0.0, 0.0); glVertex3f(x - 0.5 * length, y + 0.5 * height, z - 0.5 * depth);
	glTexCoord2f(0.0, 0.5); glVertex3f(x + 0.5 * length, y + 0.5 * height, z - 0.5 * depth);
	glTexCoord2f(0.1, 0.5); glVertex3f(x + 0.5 * length, y + 0.5 * height, z + 0.5 * depth);
	glTexCoord2f(0.1, 0.0); glVertex3f(x - 0.5 * length, y + 0.5 * height, z + 0.5 * depth);
	glNormal3f(0, 0, 1);
	glTexCoord2f(0.0, 0.0); glVertex3f(x - 0.5 * length, y + 0.5 * height, z + 0.5 * depth);
	glTexCoord2f(0.0, 0.5); glVertex3f(x + 0.5 * length, y + 0.5 * height, z + 0.5 * depth);
	glTexCoord2f(0.1, 0.5); glVertex3f(x + 0.5 * length, y - 0.5 * height, z + 0.5 * depth);
	glTexCoord2f(0.1, 0.0); glVertex3f(x - 0.5 * length, y - 0.5 * height, z + 0.5 * depth);
	glNormal3f(-1, 0, 0);
	glTexCoord2f(0.0, 0.0); glVertex3f(x - 0.5 * length, y - 0.5 * height, z - 0.5 * depth);
	glTexCoord2f(0.0, 0.1); glVertex3f(x - 0.5 * length, y + 0.5 * height, z - 0.5 * depth);
	glTexCoord2f(0.5, 0.1); glVertex3f(x - 0.5 * length, y + 0.5 * height, z + 0.5 * depth);
	glTexCoord2f(0.5, 0.0); glVertex3f(x - 0.5 * length, y - 0.5 * height, z + 0.5 * depth);
	glEnd();
	glDisable(GL_TEXTURE_2D);
}

// Generate one rail. It is made up of three cuboid and one cylinder.
// Because of the problem of light, draw a list of cylinders rather than just one.
void GL_RAIL(GLfloat track_x)
{
	GL_CUBOID(track_x, 240.85, 100, 1.4, 0.6, 1800);
	GL_CUBOID(track_x, 241.75, 100, 0.53, 1.2, 1800);
	GL_CUBOID(track_x, 242.7, 100, 0.98, 0.7, 1800);

	// A list of cylinders.
	for (int i = -800; i <= 1000; i += 2)
	{
		glPushMatrix();
		glTranslatef(track_x, 243.05, i);
		glScalef(1, 0.5, 1);
		glutSolidCylinder(0.49, 2, 20, 1);
		glPopMatrix();
	}
}

// Generate a line of screw. They works to connect the wood sleeper and the rail.
void GL_SCREW(GLfloat track_x)
{
	// For one piece of screw, it is made up of a flat cuboid and a little cylinder(to imitate screw).
	for (int i = -50; i <= 75; i++)
	{
		// The cuboids
		GL_CUBOID(track_x - 12.5, 240.3, i * 16, 4, 0.8, 3);
		GL_CUBOID(track_x + 12.5, 240.3, i * 16, 4, 0.8, 3);

		// And all the cylinders.
		glPushMatrix();
		glTranslatef(track_x - 13.75, 240, i * 16);
		glRotatef(-90, 1, 0, 0);
		glutSolidCylinder(0.3, 1.1, 10, 1);
		glTranslatef(2.5, 0, 0);
		glutSolidCylinder(0.3, 1.1, 10, 1);
		glTranslatef(22.5, 0, 0);
		glutSolidCylinder(0.3, 1.1, 10, 1);
		glTranslatef(2.5, 0, 0);
		glutSolidCylinder(0.3, 1.1, 10, 1);
		glPopMatrix();
	}
}

// Generate the whole railroad which is made up of three parts: rails, wood sleepers, and screws.
void GL_RAILROAD(void)
{
	// The material of the rail.
	GLfloat met_ambient[] = { 0.25, 0.25, 0.25, 1.00 };
	GLfloat met_diffuse[] = { 0.40, 0.40, 0.40, 1.00 };
	GLfloat met_specular[] = { 0.774597, 0.774597, 0.774597, 1.000000 };
	GLfloat met_shininess[] = { 76.800003 };

	// The base material of the wood sleeper. This will be blend with the texture.
	GLfloat wood_ambient_and_diffuse[] = { 0.610, 0.606, 0.610, 1.000 };
	GLfloat wood_specular[] = { 0.610, 0.606, 0.610, 1.000 };
	GLfloat wood_shininess[] = { 10 };

	// The material of the screw.
	GLfloat screw_ambient[] = { 0.252, 0.239, 0.227, 1.000 };
	GLfloat screw_diffuse[] = { 0.327, 0.314, 0.301, 1.000 };
	GLfloat screw_specular[] = { 0.407, 0.494, 0.481, 1.000 };
	GLfloat screw_shininess[] = { 43.400003 };

	// set the material for the rail and draw them. 
	glMaterialfv(GL_FRONT, GL_AMBIENT, met_ambient);
	glMaterialfv(GL_FRONT, GL_DIFFUSE, met_diffuse);
	glMaterialfv(GL_FRONT, GL_SPECULAR, met_specular);
	glMaterialfv(GL_FRONT, GL_SHININESS, met_shininess);
	GL_RAIL(12.5);
	GL_RAIL(-12.5);
	GL_RAIL(84.5);
	GL_RAIL(59.5);

	// set the material for the wood sleeper and draw them. 
	// Generate 2 lines of wood sleepers by a for loop.
	glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, wood_ambient_and_diffuse);
	glMaterialfv(GL_FRONT, GL_SPECULAR, wood_specular);
	glMaterialfv(GL_FRONT, GL_SHININESS, wood_shininess);
	for (int i = -50; i <= 75; i++) GL_WOOD( 0, 240, i * 16, 40, 1, 4);
	for (int i = -50; i <= 75; i++) GL_WOOD(72, 240, i * 16, 40, 1, 4);

	// set the material for the screw and draw them. 
	glMaterialfv(GL_FRONT, GL_AMBIENT, screw_ambient);
	glMaterialfv(GL_FRONT, GL_DIFFUSE, screw_diffuse);
	glMaterialfv(GL_FRONT, GL_SPECULAR, screw_specular);
	glMaterialfv(GL_FRONT, GL_SHININESS, screw_shininess);
	GL_SCREW(0);
	GL_SCREW(72);
}

// Generate a ring divide by n.
// This is implemented by the parametric equation: x = x0 + rcos(t), y = y0 + rsin(t).
// Generate two curves first and then connect them.
// For example, if n = 4, generate a quarter ring. While if n = 1, generate a ring.
void GL_1BYn_RING(GLfloat r, GLfloat h, GLint n)
{
	for (int i = 0; i < 160 / n; i++)
	{
		// The first cylindrical surface, radius = r.
		glBegin(GL_POLYGON);
		glNormal3f(0, -cos(2 * PI / 160 * i), sin(2 * PI / 160 * i));
		glVertex3f(-h / 2, -r * cos(2 * PI / 160 * i), r * sin(2 * PI / 160 * i));
		glVertex3f( h / 2, -r * cos(2 * PI / 160 * i), r * sin(2 * PI / 160 * i));
		glVertex3f( h / 2, -r * cos(2 * PI / 160 * (i + 1.0)), r * sin(2 * PI / 160 * (i + 1.0)));
		glVertex3f(-h / 2, -r * cos(2 * PI / 160 * (i + 1.0)), r * sin(2 * PI / 160 * (i + 1.0)));
		glEnd();
		
		// The second cylindrical surface, radius = 0.8 * r.
		glBegin(GL_POLYGON);
		glNormal3f(0, cos(2 * PI / 160 * i), -sin(2 * PI / 160 * i));
		glVertex3f(-h / 2, -r * 0.8 * cos(2 * PI / 160 * i), r * 0.8 * sin(2 * PI / 160 * i));
		glVertex3f( h / 2, -r * 0.8 * cos(2 * PI / 160 * i), r * 0.8 * sin(2 * PI / 160 * i));
		glVertex3f( h / 2, -r * 0.8 * cos(2 * PI / 160 * (i + 1.0)), r * 0.8 * sin(2 * PI / 160 * (i + 1.0)));
		glVertex3f(-h / 2, -r * 0.8 * cos(2 * PI / 160 * (i + 1.0)), r * 0.8 * sin(2 * PI / 160 * (i + 1.0)));
		glEnd();
	}

	// The bottom and the top
	glBegin(GL_QUADS);
	glNormal3f(0, 0, -1);
	glVertex3f( h / 2, -r * cos(2 * PI), r * sin(2 * PI));
	glVertex3f(-h / 2, -r * cos(2 * PI), r * sin(2 * PI));
	glVertex3f(-h / 2, -r * 0.8 * cos(2 * PI), r * 0.8 * sin(2 * PI));
	glVertex3f( h / 2, -r * 0.8 * cos(2 * PI), r * 0.8 * sin(2 * PI));
	glNormal3f(0, 1, 0);
	glVertex3f( h / 2, 0, r);
	glVertex3f(-h / 2, 0, r);
	glVertex3f(-h / 2, 0, r * 0.8);
	glVertex3f( h / 2, 0, r * 0.8);
	glEnd();

	// The two sides, connect the two curves to encapsulate the whole ring.
	glBegin(GL_QUAD_STRIP);
	glNormal3f(1, 0, 0);
	for (int i = 0; i <= 160 / n; i++) 
	{
		glVertex3f( h / 2, -r * cos(2 * PI / 160 * i), r * sin(2 * PI / 160 * i));
		glVertex3f( h / 2, -r * 0.8 * cos(2 * PI / 160 * i), r * 0.8 * sin(2 * PI / 160 * i));
	}
	glEnd();
	glBegin(GL_QUAD_STRIP);
	glNormal3f(-1, 0, 0);
	for (int i = 0; i <= 160 / n; i++)
	{
		glVertex3f(-h / 2, -r * cos(2 * PI / 160 * i), r * sin(2 * PI / 160 * i));
		glVertex3f(-h / 2, -r * 0.8 * cos(2 * PI / 160 * i), r * 0.8 * sin(2 * PI / 160 * i));
	}
	glEnd();
}

// Generate a pillar, which is made up of a quarter ring and two J-face.
void QUARTER_PILLAR(GLfloat r, GLfloat h)
{
	// The quarter ring.
	GL_1BYn_RING(r, h, 4);

	// The first J-face, which is based on the parametric equation:
	// x = x0 + r - rcos(t), y = y0 + r - rsin(t).
	// Change a little for adaptation.
	glPushMatrix();
	glTranslatef(-h / 2, -r, r);
	glBegin(GL_TRIANGLE_FAN);
	glNormal3f(-1, 0, 0);
	glVertex3f(0, 0, 0);
	for (int i = 0; i < 10; i++) glVertex3f(0, r - r * sin(2 * PI / 40 * i), r * cos(2 * PI / 40 * i) - r);
	glEnd();
	glPopMatrix();

	// The second one.
	glPushMatrix();
	glTranslatef(h / 2, -r, r);
	glBegin(GL_TRIANGLE_FAN);
	glNormal3f(1, 0, 0);
	glVertex3f(0, 0, 0);
	for (int i = 0; i < 10; i++) glVertex3f(0, r - r * sin(2 * PI / 40 * i), r * cos(2 * PI / 40 * i) - r);
	glEnd();
	glPopMatrix();
}

// The two hump on the top of the train head, consist of a cylinder and a sphere.
void STEAM_POCKET(GLfloat sp_z)
{
	glPushMatrix();
	glTranslatef(0, 295, sp_z);
	glRotatef(90, 1, 0, 0);
	glutSolidCylinder(5, 10, 100, 1);
	glScalef(1, 1, 0.5);
	glutSolidSphere(5, 50, 50);
	glPopMatrix();
}

// The wheel. This is made up of two rings and 4 axles.
// A GLfloat offset to let it rotate for some angles when created to show a sense of reality.
void GL_WHEEL(GLfloat wheel_x, GLfloat wheel_z, GLfloat r, GLfloat offset)
{
	// The first ring.
	glPushMatrix();
	if (wheel_x > 0) glTranslatef(wheel_x - 0.5, 243.45 + r, wheel_z);
	else glTranslatef(wheel_x + 0.65, 243.45 + r, wheel_z);
	GL_1BYn_RING(r * 1.12, 0.3, 1);
	glPopMatrix();

	// The second ring, which is smaller than the first one.
	glPushMatrix();
	glTranslatef(wheel_x + 0.15, 243.45 + r, wheel_z);
	GL_1BYn_RING(r, 1.3, 1);
	if (wheel_x > 0) glTranslatef(0.5, 0, 0);
	else glTranslatef(-0.5, 0, 0);
	glRotatef(90, 0, 1, 0);
	glutSolidCylinder(r / 4, 1, 20, 1);
	glPopMatrix();

	// The four axles, which are imitated by long cuboids.
	for (int i = 0; i < 4; i++)
	{
		glPushMatrix();
		glTranslatef(wheel_x, 243.45 + r, wheel_z);
		glRotatef(i * 45, 1, 0, 0);
		glRotatef(offset - Rotate, 1, 0, 0);
		GL_CUBOID(0, 0, 0, 0.8, 1, 1.98 * r);
		glPopMatrix();
	}
}

// Generate one piece of wall of carriages, use for loop to generate others.
void WALL_PIECE(GLfloat wall_x, GLfloat wall_y, GLfloat wall_z)
{
	GL_CUBOID(wall_x, wall_y - 8.25, wall_z, 1, 16.5, 12);
	GL_CUBOID(wall_x, wall_y + 5.25, wall_z - 5.25, 1, 10.5, 1.5);
	GL_CUBOID(wall_x, wall_y + 5.25, wall_z - 4.75, 2, 10.5, 0.5);
	GL_CUBOID(wall_x, wall_y + 5.25, wall_z + 5.25, 1, 10.5, 1.5);
	GL_CUBOID(wall_x, wall_y + 5.25, wall_z + 4.75, 2, 10.5, 0.5);
	GL_CUBOID(wall_x, wall_y - 0.25, wall_z, 2, 0.5, 10);
	GL_CUBOID(wall_x, wall_y + 10.75, wall_z, 2, 0.5, 10);
	GL_CUBOID(wall_x, wall_y + 13.5, wall_z, 1, 6, 12);
}

// Generate a door for carriages.
void GL_DOOR(GLfloat door_x, GLfloat door_y, GLfloat door_z)
{
	GL_CUBOID(door_x, door_y, door_z, 1, 33, 12);
	GL_CUBOID(door_x, door_y, door_z - 4.75, 2, 27, 0.5);
	GL_CUBOID(door_x, door_y, door_z + 4.75, 2, 27, 0.5);
	GL_CUBOID(door_x, door_y - 13.75, door_z, 2, 0.5, 10);
	GL_CUBOID(door_x, door_y + 13.75, door_z, 2, 0.5, 10);
}

// The bent bracket of the train head.
void BENT_BRACKET(void)
{
	// The main part is the quarter ring.
	glPushMatrix();
	glTranslatef(0, 264, 143);
	GL_1BYn_RING(8, 34, 4);
	glPopMatrix();

	// One part of its holder is made up of two J-shape board.
	glPushMatrix();
	glTranslatef(-11.49, 256, 151);
	glBegin(GL_TRIANGLE_FAN);
	glNormal3f(-1, 0, 0);
	glVertex3f(0, 0, 0);
	for (int i = 0; i < 10; i++) glVertex3f(0, 8 - 8 * sin(2 * PI / 40 * i), 8 * cos(2 * PI / 40 * i) - 8);
	glEnd();
	glPopMatrix();

	// Another part is made up of two cylinder
	glPushMatrix();
	glTranslatef(8, 257.6, 149.5);
	glRotatef(90, 0, 1, 0);
	glutSolidCylinder(6.4, 1.3, 100, 1);
	glPopMatrix();
	glPushMatrix();
	glTranslatef(-8, 257.6, 149.5);
	glRotatef(90, 0, 1, 0);
	glutSolidCylinder(6.4, 1.3, 100, 1);
	glPopMatrix();

	// The buffle is extended by a board made up of three cuboid and two triangle prisms.
	GL_CUBOID(0, 256.8, 142, 34, 1.6, 2);
	GL_CUBOID(0, 255.5, 141.6, 34, 1.4, 1.2);
	GL_CUBOID(0, 253.5, 141.6, 24, 3, 1.2);
	glPushMatrix();
	glTranslatef(-14.5, 253.5, 141.6);
	glRotatef(180, 0, 0, 1);
	GL_TRIPRISM(5, 1.2, PI / 6);
	glPopMatrix();
	glPushMatrix();
	glTranslatef(14.5, 253.5, 141.6);
	glScalef(1, -1, 1);
	GL_TRIPRISM(5, 1.2, PI / 6);
	glPopMatrix();
}

// The train head, which is made up of several parts.
void TRAIN_HEAD(void)
{
	// The board.
	GL_CUBOID(0, 255, 193.5, 23, 12, 88);
	GL_CUBOID(0, 246.5, 190, 18, 5, 90);
	GL_CUBOID(0, 261, 197, 34, 2, 94);
	GL_CUBOID(0, 263, 180, 34, 2, 60);
	GL_CUBOID(0, 265, 195, 34, 2, 30);
	glPushMatrix();
	glTranslatef(0, 266, 213.9);
	glRotatef(90, 1, 0, 0);
	QUARTER_PILLAR(4, 34);
	glPopMatrix();

	// And the boiler, imitate by cylinders.
	for (int i = 0; i < 3; i++) 
	{
		glPushMatrix();
		glTranslatef(0, 276, 174 + i * 8);
		glutSolidCylinder(12, 1.5, 80, 1);
		glPopMatrix();
	}
	glPushMatrix();
	glTranslatef(0, 276, 160);
	glutSolidCylinder(11.5, 50, 80, 1);
	glTranslatef(0, 0, -9);
	glutSolidCylinder(12, 16.5, 80, 1);
	glTranslatef(0, 0, -1);
	glutSolidCylinder(11, 1, 80, 1 );
	glPopMatrix();

	// And the bent bracket.
	BENT_BRACKET();

	// The steam machine, which is made up of four cylinders and two cuboids.
	// The 4 cylinders.
	glPushMatrix();
	glTranslatef(-15.5, 250, 158);
	glutSolidCylinder(4, 12, 40, 1);
	glTranslatef(0, 0, -0.5);
	glutSolidCylinder(3.7, 13, 40, 1);
	glTranslatef(-1, 6.9, 1);
	glutSolidCylinder(3, 11, 40, 1);
	glTranslatef(0, 0, -0.5);
	glutSolidCylinder(2.8, 12, 40, 1);
	glPopMatrix();
	// The 2 cuboids.
	glPushMatrix();
	glTranslatef(-17.99, 253.5, 164);
	glRotatef(0, 0, 0, 1);
	glTranslatef(18, -253, -164);
	GL_CUBOID(-18, 253, 164, 3, 6.9, 10);
	glTranslatef(-13.5, 254, 164);
	glRotatef(17, 0, 0, 1);
	glTranslatef(13.5, -254, -164);
	GL_CUBOID(-14, 254, 164, 3, 6.9, 10);
	glPopMatrix();

	// The holder for the boiler which is made up of two quarter pillar,
	// and the connection part between them(imitate by a cuboid).
	glPushMatrix();
	glTranslatef(-16.99, 271.2, 160);
	glRotatef(90, 0, 1, 0);
	QUARTER_PILLAR(9, 12);
	glPopMatrix();
	glPushMatrix();
	glTranslatef(16.99, 271.2, 160);
	glRotatef(-90, 0, 1, 0);
	QUARTER_PILLAR(9, 12);
	glPopMatrix();
	GL_CUBOID(0, 266, 160, 16, 4, 12);

	// holders for the wheels, implemented by 4 triangle prisms.
	for (int i = 0; i < 5; i++)
	{
		glPushMatrix();
		glTranslatef(-14, 258, 172 + 16 * i);
		glRotatef(180, 0, 0, 1);
		GL_TRIPRISM(5, 2, PI / 3);
		glPopMatrix();
	}

	// The steam pockets.
	STEAM_POCKET(200);
	STEAM_POCKET(183);

	// The chimney
	GLUquadric* A = gluNewQuadric();
	glPushMatrix();
	glTranslatef(0, 299, 165);
	glRotatef(90, 1, 0, 0);
	glutSolidCylinder(3.5, 15, 100, 1);
	gluCylinder(A, 4, 3.5, 3, 100, 40);
	glPopMatrix();

	// The lamp frame, imitate by a ring and a circle.
	// The ring
	glPushMatrix();
	glTranslatef(0, 291, 153.5);
	glRotatef(90, 0, 1, 0);
	GL_1BYn_RING(2.5, 4, 1);
	glPopMatrix();
	GL_CUBOID(0, 288, 153.5, 3, 2, 3.2);
	// And the circle, implemented by the parametric equation.
	glBegin(GL_POLYGON);
	glNormal3f(0, 0, -1);
	for (int i = 0; i < 20; i++) glVertex3f(2.5 * cos(2 * PI / 20 * i), 291 + 2.5 * sin(2 * PI / 20 * i), 155.5);
	glEnd();

	// The master's room, only two walls of which is required
	// as only they will be projected onto the screen
	WALL_PIECE(-14.5, 276.5, 218);
	WALL_PIECE(-14.5, 276.5, 230);
	GL_CUBOID(0, 276.5, 211, 30, 33, 2);
	GL_CUBOID(0, 276.5, 210.5, 32, 33, 1);
	GL_CUBOID(0, 276.5, 238, 30, 33, 4);
	GL_CUBOID(0, 276.5, 237.5, 32, 33, 1);
	GL_CUBOID(0, 293.5, 228, 32, 1, 36);
	GL_CUBOID(0, 291, 228, 30, 4, 36);
	glPushMatrix();
	glTranslatef(7.5, 295.5, 228);
	GL_TRIPRISM(16, 36, PI / 15);
	glTranslatef(-16, 0, 0);
	glScalef(-1, 1, 1);
	GL_TRIPRISM(16, 36, PI / 15);
	glPopMatrix();
}

// Generate the lock to connect the train head with the train body, and connect every carrige together.
void GL_LOCK(GLfloat lock_z)
{
	GL_CUBOID(0, 252, lock_z, 4, 4, 20);
	GL_CUBOID(0, 252, lock_z, 6, 6, 5);
}

// One carriage. It is made up of the ceiling, walls and doors.
void GL_CARRIAGE(GLfloat carriage_z)
{
	// The two doors and the wall face to the positive half axis of X-axis.
	GL_DOOR(-16.5, 270, carriage_z);
	for (int i = 1; i <= 6; i++) WALL_PIECE(-16.5, 270, carriage_z + 12 * i);
	GL_DOOR(-16.5, 270, carriage_z + 84);

	// The walls and the ceiling(imilate by a cylinder).
	GL_CUBOID(0, 270, carriage_z - 7, 35, 33, 2);
	GL_CUBOID(0, 270, carriage_z + 91, 35, 33, 2);
	glPushMatrix();
	glTranslatef(0, 286.5, carriage_z - 8);
	glScalef(1, 0.5, 1);
	glutSolidCylinder(17.5, 100, 150, 1);
	glPopMatrix();

	// The bottom of the carriage.
	GL_CUBOID(0, 255, carriage_z + 42, 23, 12, 98);
	GL_CUBOID(0, 246.5, carriage_z + 42, 18, 5, 94);
}

// The train body, which is made up of several parts.
void TRAIN_BODY(void)
{	
	// The box between the train head and the train body, consist of many cuboids and triangle prisms.
	// Main part
	GL_CUBOID(0, 247, 263, 18, 5, 24);
	GL_CUBOID(0, 255, 263, 23, 12, 28);
	GL_CUBOID(0, 271, 263, 34, 30, 28);
	GL_CUBOID(0, 261, 263, 34, 10, 30);
	GL_CUBOID(-17, 271, 248.5, 2, 30, 1);
	GL_CUBOID(-17, 271, 277.5, 2, 30, 1);
	GL_CUBOID(0, 288, 263, 34, 4, 20);
	GL_CUBOID(0, 290.5, 263, 36, 1, 20);

	// Part for decoration
	glPushMatrix();
	glTranslatef(-17, 288.25, 250.8);
	glRotatef(-45, 1, 0, 0);
	GL_CUBOID(0, 0, 0, 2, 1, 7);
	GL_CUBOID(34, 0, 0, 2, 1, 7);
	glPopMatrix();
	glPushMatrix();
	glTranslatef(-17, 288.25, 275.2);
	glRotatef(45, 1, 0, 0);
	GL_CUBOID(0, 0, 0, 2, 1, 7);
	GL_CUBOID(34, 0, 0, 2, 1, 7);
	glPopMatrix();
	GL_CUBOID(0, 280, 248.5, 34, 1, 1);
	GL_CUBOID(0, 285.5, 248.5, 34, 1, 1);
	GL_CUBOID(0, 280, 277.5, 34, 1, 1);
	GL_CUBOID(0, 285.5, 277.5, 34, 1, 1);
	glPushMatrix();
	glTranslatef(0, 288, 251);
	glRotatef(90, 0, 1, 0);
	GL_TRIPRISM(4, 34, PI / 4);
	glPopMatrix();
	glPushMatrix();
	glTranslatef(0, 288, 275);
	glRotatef(-90, 0, 1, 0);
	GL_TRIPRISM(4, 34, PI / 4);
	glPopMatrix();

	// The lock and all the carriages.
	GL_LOCK(243);
	for (int i = 0; i < 9; i++)	GL_CARRIAGE(290 + i * 105);
	for (int i = 0; i < 9; i++)	GL_LOCK(280 + i * 105);
}

// The glass for the window of the train.
void GL_GLASS(void)
{
	glPushMatrix();
	glTranslatef(0, 291, 151.5);
	glutSolidCylinder(2, 3.7, 40, 1);
	glPopMatrix();

	GL_CUBOID(-14.5, 281.75, 218, 1, 10.5, 9);
	GL_CUBOID(-14.5, 281.75, 230, 1, 10.5, 9);
	for (int i = 0; i < 9; i++)
		for (int j = 1; j <= 6; j++) GL_CUBOID(-16.5, 275.25, 290 + 105 * i + 12 * j, 1, 10.5, 9);
}

// The train, which is made up of train head, train body, glass and wheels. 
void GL_TRAIN(void)
{
	// The material of the train.
	GLfloat tra_ambient[] = { 0.05, 0.05, 0.05, 1.00 };
	GLfloat tra_diffuse[] = { 0.45, 0.45, 0.52, 1.00 };
	GLfloat tra_specular[] = { 0.774597, 0.774597, 0.774597, 1.000000 };
	GLfloat tra_shininess[] = { 76.800003 };

	// set the material for the train and draw it. 
	glMaterialfv(GL_FRONT, GL_AMBIENT, tra_ambient);
	glMaterialfv(GL_FRONT, GL_DIFFUSE, tra_diffuse);
	glMaterialfv(GL_FRONT, GL_SPECULAR, tra_specular);
	glMaterialfv(GL_FRONT, GL_SHININESS, tra_shininess);
	
	// The large wheels for the train head.
	for (int i = 0; i < 4; i++) { GL_WHEEL(-12.5, 180 + 16 * i, 6.75, i * 13); }
	
	// The small wheels for the train head.
	GL_WHEEL(-12.5, 150, 5, 0);
	GL_WHEEL( 12.2, 150, 5, 0);
	GL_WHEEL(-12.5, 269.5, 5, 7);
	GL_WHEEL(-12.5, 256.5, 5, 14);

	// Other wheels on the train.
	for (int i = 0; i < 9; i++)
		for (int j = 0; j < 8; j++) GL_WHEEL(-12.5, 290 + i * 105 + j * 12, 5, j * 11);
	for (int j = 0; j < 8; j++) GL_WHEEL(12.2 , 290 + 8 * 105 + j * 12, 5, j * 11);

	// Train head and train body.
	TRAIN_HEAD();
	TRAIN_BODY();

	// The material of the glass.
	GLfloat gla_ambient_diffuse[] = { 0.705882, 0.715882, 0.705882, 0.500000 };
	GLfloat gla_specular[] = { 0.933333, 0.943333, 0.933333, 0.500000 };
	GLfloat gla_shininess[] = { 59.846150 };

	// set the material for the train and draw it. 
	glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, gla_ambient_diffuse);
	glMaterialfv(GL_FRONT, GL_SPECULAR, gla_specular);
	glMaterialfv(GL_FRONT, GL_SHININESS, gla_shininess);
	GL_GLASS();
}

// The platform for the bridge, consist of two quads.
void GL_PLATFORM(GLfloat r)
{
	glBegin(GL_QUADS);
	glNormal3f(0, 1, 0);
	glTexCoord2f(0.6, 7.2); glVertex3f(0, 2.4 * r, -0.2 * r);
	glTexCoord2f(-6.6, 7.2); glVertex3f(0, 2.4 * r, 2.2 * r);
	glTexCoord2f(-6.6, 7.8); glVertex3f(20, 2.4 * r, 2.2 * r);
	glTexCoord2f(0.6, 7.8); glVertex3f(20, 2.4 * r, -0.2 * r);
	glNormal3f(1, 0, 0);
	glTexCoord2f(0.6, 7.8); glVertex3f(20, 2.4 * r, -0.2 * r);
	glTexCoord2f(-6.6, 7.8); glVertex3f(20, 2.4 * r, 2.2 * r);
	glTexCoord2f(-6.6, 7.7); glVertex3f(20, 2.4 * r - 4, 2.2 * r);
	glTexCoord2f(0.6, 7.7); glVertex3f(20, 2.4 * r - 4, -0.2 * r);
	glEnd();
}
 
// Generate one piece of bridge, generate the others by a for loop.
// The bridge piece is made up of two parts: bridge face, platform, brige floor and bridge hole.
// Both of them are based on the parametric equation similar to that of GL_1BYn_RING.
void BRIDGE_PIECE(void)
{
	glEnable(GL_TEXTURE_2D);
	glTexImage2D(GL_TEXTURE_2D, 0, 3, imagewidth1, imageheight1, 0, GL_BGR_EXT, GL_UNSIGNED_BYTE, p[1]);
	GLfloat r = 100;

	// The lower part 1 of bridge face.
	glBegin(GL_QUAD_STRIP);
	glNormal3f(-1, 0, 0);
	for (int i = 35; i <= 100; i++)
	{
		glTexCoord2f(0, 3 * sin(2 * PI / 400 * i) + 3);
		glVertex3f(0, r * sin(2 * PI / 400 * i) + r, 0);
		glTexCoord2f(3.6 - 3 * cos(2 * PI / 400 * i), 3 * sin(2 * PI / 400 * i) + 3);
		glVertex3f(0, r * sin(2 * PI / 400 * i) + r, 1.2 * r - r * cos(2 * PI / 400 * i));
	}

	// The upper part of bridge face.
	glTexCoord2f(0, 6);     glVertex3f(0, 2 * r, 0);
	glTexCoord2f(7.2, 6);   glVertex3f(0, 2 * r, 2.4 * r);
	glTexCoord2f(0, 7.2);   glVertex3f(0, 2.4 * r, 0);
	glTexCoord2f(7.2, 7.2); glVertex3f(0, 2.4 * r, 2.4 * r);
	glEnd();

	// The lower part 2 of bridge face.
	glBegin(GL_QUAD_STRIP);
	for (int i = 35; i <= 100; i++)
	{
		glTexCoord2f(7.2, 3 * sin(2 * PI / 400 * i) + 3);
		glVertex3f(0, r * sin(2 * PI / 400 * i) + r, 2.4 * r);
		glTexCoord2f(3.6 + 3 * cos(2 * PI / 400 * i), 3 * sin(2 * PI / 400 * i) + 3);
		glVertex3f(0, r * sin(2 * PI / 400 * i) + r, 1.2 * r + r * cos(2 * PI / 400 * i));
	}
	glEnd();

	// The platforms
	GL_PLATFORM(r);
	glPushMatrix();
	glTranslatef(160, 0, 0);
	glScalef(-1, 1, 1);
	GL_PLATFORM(r);
	glPopMatrix();
	
	// The bridge hole
	glBegin(GL_QUAD_STRIP);
	for (int i = 35; i <= 165; i++)
	{
		glNormal3f(0, -sin(2 * PI / 400 * i), -cos(2 * PI / 400 * i));
		glTexCoord2f(3.6 + 3 * cos(2 * PI / 400 * i), 3 * sin(2 * PI / 400 * i) + 3);
		glVertex3f(0, r * sin(2 * PI / 400 * i) + r, 1.2 * r + r * cos(2 * PI / 400 * i));
		glTexCoord2f(8.4 + 3 * cos(2 * PI / 400 * i), 3 * sin(2 * PI / 400 * i) + 3);
		glVertex3f(160, r * sin(2 * PI / 400 * i) + r, 1.2 * r + r * cos(2 * PI / 400 * i));
	}
	glEnd();

	// The bridge floor, use texture to imitate the little stones.
	glTexImage2D(GL_TEXTURE_2D, 0, 3, imagewidth2, imageheight2, 0, GL_BGR_EXT, GL_UNSIGNED_BYTE, p[2]);
	glBegin(GL_QUADS);
	glTexCoord2f( 0.6, 7.8);  glVertex3f(20,  2.4 * r - 4, -0.2 * r);
	glTexCoord2f(-6.6, 7.8);  glVertex3f(20,  2.4 * r - 4,  2.2 * r);
	glTexCoord2f(-6.6, 11.4); glVertex3f(140, 2.4 * r - 4,  2.2 * r);
	glTexCoord2f( 0.6, 11.4); glVertex3f(140, 2.4 * r - 4, -0.2 * r);
	glEnd();
	glDisable(GL_TEXTURE_2D);
}

// The bridge, use a for loop to generate a list of bridge pieces.
void GL_BRIDGE(void)
{
	// The material of the bridge.
	GLfloat bri_ambient_diffuse[] = { 0.4, 0.4, 0.4, 1.00 };
	GLfloat bri_specular[] = { 0.374597, 0.374597, 0.374597, 1.000000 };
	GLfloat bri_shininess[] = { 6.800003 };

	// set the material for the train and draw it.
	glMaterialfv(GL_FRONT, GL_AMBIENT, bri_ambient_diffuse);
	glMaterialfv(GL_FRONT, GL_DIFFUSE, bri_ambient_diffuse);
	glMaterialfv(GL_FRONT, GL_SPECULAR, bri_specular);
	glMaterialfv(GL_FRONT, GL_SHININESS, bri_shininess);
	glPushMatrix();
	glTranslatef(-44, 3.5, 0);
	for (int i = -3; i < 7; i++)
	{
		glPushMatrix();
		glTranslatef(0, 0, 240 * i);
		BRIDGE_PIECE();
		glPopMatrix();
	}
	glPopMatrix();
}

// The background. Use 4 planes to imitate the night sky.
void GL_BACKGROUND(GLfloat angle)
{
	glPushMatrix();
	glRotatef(angle, 0, 1, 0);
	glBegin(GL_QUAD_STRIP);
	glColor3f(0, 0, 0.2);
	glVertex3f(-10000, 0, 6000);
	glVertex3f( 10000, 0, 6000);
	glColor3f(0, 0, 0.1);
	glVertex3f(-10000, 1000, 6000);
	glVertex3f( 10000, 1000, 6000);
	glColor3f(0, 0, 0.0);
	glVertex3f(-10000, 3000, 6000);
	glVertex3f( 10000, 3000, 6000);
	glEnd();
	glPopMatrix();
}

void keyboard_input(unsigned char key, int x, int y)
{
	if (key == 'q' || key == 'Q') exit(0);
	if (key == ' ' && shake) {
		start = true;
	}
}

void mouse_input(int button, int state, int x, int y)
{
	if (state == GLUT_DOWN && button == GLUT_LEFT_BUTTON) 
	{
		cutoff = 45;
		shake = true;
	}
}

// The animation
void Animation(void) 
{
	glViewport(0, 0, 1600, 900);

	// In stage 1, move forward with speed increasing by time.
	if (start) 
	{
		tra += traAcceleration;
		lookat += lookatStep;
		Rotate += rttAcceleration;
		camerax1 += cmrAccelerationx1;
		camerax2 += cmrAccelerationx2;
		cameray += cmrAccelerationy;
		cameraz1 += cmrAccelerationz;
		cameraz2 += cmrAccelerationz;
	}
	if (Rotate >= 360) Rotate = 0;
	if (rttAcceleration <= 10 && !stage2 && start) 
	{
		rttAcceleration += 0.1;
		traAcceleration += 0.01;
		cmrAccelerationz += 0.005;
	}
	if (rttAcceleration >= 10 && rttAcceleration <= 18 && !stage2 && start) 
	{
		rttAcceleration += 0.2;
		traAcceleration += 0.04;
		cmrAccelerationz += 0.06;
		cmrAccelerationx1 += 0.02;
		cmrAccelerationx2 += 0.018;
	}
	if (rttAcceleration >= 18 && rttAcceleration <= 30 && !stage2 && start) 
	{
		rttAcceleration += 0.2;
		traAcceleration += 0.12;
		cmrAccelerationz += 0.18;
		cmrAccelerationx1 += 0.04;
		cmrAccelerationx2 += 0.037;
		cmrAccelerationy += 0.005;
	}

	// Look up for convenience of changing the lens.
	if (rttAcceleration >= 29 && !stage2 && start) lookatStep += 0.5;
	if (lookat >= 100 && !stage2)
	{
		camerax2 = lookatStep = 0;
		traAcceleration = cmrAccelerationx1 = cmrAccelerationx2 = cmrAccelerationy = cmrAccelerationz = 0;
		tra = 225;
		traAcceleration = 3;
		stage2 = true;
		camerax1 = -45;
		cameray = -25;
		cameraz1 = -920;
		lookat = 0;
	}

	// After changing the lens, move into stage2, where the train move forward in a stable speed.
	if (stage2 && lookat < 200) 
	{
		lookatStep = 4;
		lookatStep += 0.4;
	}
	if (stage2 && lookat >= 200) lookatStep -= 0.4;
	if (stage2 && lookatStep <= 0) lookatStep = 0;
	if (tra >= 2000) rttAcceleration = traAcceleration = 0;

	// In stage 1, shake the lens to imitate the shaking created by the train.
	shakeRange = 10 / pow((pow((-45.0 - camerax1), 2) + pow((80.0 - cameraz1 - tra), 2)), 0.5);
	if (!start) shakeRange *= 0.6;
	if (shake && !stage2) 
	{
		shakesita += ssitaAcceleration;
		lookat += shakeRange * sin(shakesita);
	}
	if (shakesita > 2 * PI) shakesita -= 2 * PI;
	glutPostRedisplay();
}

 效果如下(3D略有改动):

opengl大作业2d&3d

  • 9
    点赞
  • 62
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值