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

2D作业:

// File ID: NewYearCard.cpp

// Title: Happy New Year!

// Author: L_Stock

#define FREEGLUT_STATIC

#define PI 3.14159265

#include

#include

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

#include

#include

#include

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

vectorp;

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

精彩链接

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: