由于学校要求,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略有改动):文章来源:https://www.toymoban.com/news/detail-720106.html
opengl大作业2d&3d文章来源地址https://www.toymoban.com/news/detail-720106.html
到了这里,关于Opengl大作业2D&3D,基于freeglut库的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!