flightsim.c
来自「飞机飞行界面」· C语言 代码 · 共 1,162 行 · 第 1/3 页
C
1,162 行
/*
* Flight simulator example from Chapter 16.
*
* Written by Michael Sweet
*/
#include <GL/glut.h>
#include <stdio.h>
#include <math.h>
#ifndef WIN32
# include <sys/time.h>
#endif /* !WIN32 */
#ifndef M_PI
# define M_PI (double)3.14159265358979323846
#endif /* !M_PI */
#include "texture.h"
#include "font.h"
/*
* Constants:
*/
#define TERRAIN_COUNT 41 /* Number of postings (must be odd) */
#define TERRAIN_SIZE 4000.0 /* Size of terrain database */
#define TERRAIN_VIEW 1000.0 /* Viewable distance in terrain database */
#define TERRAIN_SPACING 100.0 /* Spacing between postings */
/*
* Terrain posting structure...
*/
typedef struct
{
GLfloat v[3]; /* Position */
GLfloat n[3]; /* Lighting normal */
} TP;
/*
* Globals...
*/
int RedrawAll; /* 1 = redraw everything, 0 = just terrain */
int RedrawAirspeed; /* 1 = redraw the airspeed indicator */
int RedrawAltimeter; /* 1 = redraw the altimeter */
int RedrawCompass; /* 1 = redraw the compass */
int RedrawHorizon; /* 1 = redraw the artificial horizon */
int Width; /* Width of window */
int Height; /* Height of window */
double LastTime; /* Last update time */
int MouseStartX; /* Initial mouse X position */
int MouseStartY; /* Initial mouse Y position */
int MouseX; /* Mouse X position */
int MouseY; /* Mouse Y position */
int ViewAngle = 0; /* Viewing angle */
GLenum PolyMode = GL_FILL; /* Polygon drawing mode */
int UseTexturing = 1; /* Use texturing? */
int ShowLighting = 1; /* Show lighting? */
int ShowSky = 1; /* Show sky? */
int ShowTerrain = 1; /* Show 3D terrain? */
int ShowWater = 1; /* Show water? */
GLfloat Velocity = 10.0; /* Flying speed */
GLfloat Position[3] = /* Position of viewer */
{
0.0, 10.0, 0.0
};
GLfloat Orientation[3] = /* Orientation of viewer */
{
0.0, 0.0, 0.0
};
TP Terrain[TERRAIN_COUNT][TERRAIN_COUNT];
/* Terrain postings */
GLuint LandTexture; /* Land texture object */
GLuint SkyTexture; /* Sky texture object */
GLFONT *TextFont; /* Font to use for text */
int FPS = 0, /* Frames per second value */
FPSCount = 0; /* Frames per second count */
double FPSTime = 0.0; /* Frames per second time */
GLfloat Airspeed = 10.0; /* Airspeed indicator */
GLfloat Altimeter = 0.0; /* Altimeter reading */
GLfloat Horizon[2] = /* Artificial horizon position */
{
0.0, 0.0
};
GLfloat Compass = 0.0; /* Compass position */
int UseSwapHint; /* Use swap hint extension? */
PROC glAddSwapHintRectWIN; /* Swap hint extension function */
/*
* Functions...
*/
void BuildTerrain(void);
void DivideTerrain(int left, int right, int bottom, int top);
double GetClock(void);
void Idle(void);
void Joystick(unsigned state, int x, int y, int z);
void Keyboard(unsigned char key, int x, int y);
void Motion(int x, int y);
void Mouse(int button, int state, int x, int y);
void Redraw(void);
void Resize(int width, int height);
void Special(int key, int x, int y);
/*
* 'main()' - Open a window and display a sphere and cube.
*/
int /* O - Exit status */
main(int argc, /* I - Number of command-line arguments */
char *argv[]) /* I - Command-line arguments */
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
glutInitWindowSize(792, 573);
glutCreateWindow("Flight Simulator");
glutDisplayFunc(Redraw);
if (glutDeviceGet(GLUT_HAS_JOYSTICK))
glutJoystickFunc(Joystick, 200);
glutKeyboardFunc(Keyboard);
glutMotionFunc(Motion);
glutMouseFunc(Mouse);
glutReshapeFunc(Resize);
glutSpecialFunc(Special);
TextFont = FontCreate(wglGetCurrentDC(), "Arial", 16, 0, 0);
LandTexture = TextureLoad("land.bmp", GL_FALSE, GL_LINEAR_MIPMAP_LINEAR,
GL_LINEAR, GL_REPEAT);
SkyTexture = TextureLoad("sky.bmp", GL_FALSE, GL_LINEAR, GL_LINEAR,
GL_CLAMP);
BuildTerrain();
puts("QUICK HELP:");
puts("");
puts("ESC - Quit");
puts("',' - Slow down, '<' - Slowest");
puts("'.' - Speed up, '>' - Fastest");
puts("'3' - Toggle terrain");
puts("'l' - Toggle lighting");
puts("'s' - Toggle sky/clouds");
puts("'t' - Toggle texturing");
puts("'w' - Toggle water");
puts("'W' - Toggle wireframe");
printf("GL_EXTENSIONS = %s\n", glGetString(GL_EXTENSIONS));
if (strstr(glGetString(GL_EXTENSIONS), "WIN_swap_hint") != NULL)
{
UseSwapHint = 1;
glAddSwapHintRectWIN = wglGetProcAddress("glAddSwapHintRectWIN");
}
else
UseSwapHint = 0;
RedrawAll = 1;
glutMainLoop();
return (0);
}
/*
* 'BuildTerrain()' - Build a fractal landscape...
*/
void
BuildTerrain(void)
{
int i, j; /* Looping vars */
TP *tp; /* Terrain posting */
GLfloat nx, ny, nz, nw; /* Normal components */
for (i = 0, tp = Terrain[0]; i < TERRAIN_COUNT; i ++)
for (j = 0; j < TERRAIN_COUNT; j ++, tp ++)
{
tp->v[0] = TERRAIN_SPACING * i - 0.5 * TERRAIN_SIZE;
tp->v[1] = 2.0;
tp->v[2] = 0.5 * TERRAIN_SIZE - TERRAIN_SPACING * j;
}
DivideTerrain(0, TERRAIN_COUNT - 1, 0, TERRAIN_COUNT - 1);
/*
* Loop through the terrain arrays and regenerate the
* lighting normals based on the terrain height.
*/
for (i = 0, tp = Terrain[0]; i < (TERRAIN_COUNT - 1); i ++, tp ++)
for (j = 0; j < (TERRAIN_COUNT - 1); j ++, tp ++)
{
/*
* Compute the cross product of the vectors above and to
* the right (simplified for this special case).
*/
nx = tp[0].v[1] - tp[1].v[1];
ny = -1.0;
nz = tp[0].v[1] - tp[TERRAIN_COUNT].v[1];
nw = -1.0 / sqrt(nx * nx + ny * ny + nz * nz);
/* Normalize the normal vector and store it... */
tp->n[0] = nx * nw;
tp->n[1] = ny * nw;
tp->n[2] = nz * nw;
}
/*
* Set the top and right normals to be the same as the
* second-to-last normals.
*/
for (i = 0, tp = Terrain[TERRAIN_COUNT - 2];
i < TERRAIN_COUNT;
i ++, tp ++)
{
tp[TERRAIN_COUNT].n[0] = tp[0].n[0];
tp[TERRAIN_COUNT].n[1] = tp[0].n[1];
tp[TERRAIN_COUNT].n[2] = tp[0].n[2];
}
for (i = 0, tp = Terrain[0] + TERRAIN_COUNT - 2;
i < (TERRAIN_COUNT - 1);
i ++, tp += TERRAIN_COUNT)
{
tp[1].n[0] = tp[0].n[0];
tp[1].n[1] = tp[0].n[1];
tp[1].n[2] = tp[0].n[2];
}
/* Position the viewer just above the terrain */
Position[1] = Terrain[TERRAIN_COUNT / 2][TERRAIN_COUNT / 2].v[1] + 10.0;
}
/*
* 'DivideTerrain()' - Subdivide terrain until all of the landscape is done.
*/
void
DivideTerrain(int left, /* I - Left posting */
int right, /* I - Right posting */
int bottom, /* I - Bottom posting */
int top) /* I - Top posting */
{
int x, y; /* Middle column and row */
int halfel, maxel; /* Maximum amount of change for middle */
x = (left + right) / 2;
y = (bottom + top) / 2;
halfel = (rand() % 50) + 50;
maxel = 2 * halfel + 1;
Terrain[x][bottom].v[1] = 0.5 * (Terrain[left][bottom].v[1] +
Terrain[right][bottom].v[1]) +
((rand() % maxel) - halfel) * 0.2;
Terrain[x][top].v[1] = 0.5 * (Terrain[left][top].v[1] +
Terrain[right][top].v[1]) +
((rand() % maxel) - halfel) * 0.2;
Terrain[left][y].v[1] = 0.5 * (Terrain[left][bottom].v[1] +
Terrain[left][top].v[1]) +
((rand() % maxel) - halfel) * 0.2;
Terrain[right][y].v[1] = 0.5 * (Terrain[right][bottom].v[1] +
Terrain[right][top].v[1]) +
((rand() % maxel) - halfel) * 0.2;
if (x == (TERRAIN_COUNT / 2) && y == (TERRAIN_COUNT / 2))
Terrain[x][y].v[1] = 0.25 * (Terrain[left][bottom].v[1] +
Terrain[right][bottom].v[1] +
Terrain[left][top].v[1] +
Terrain[right][top].v[1]) +
((rand() % maxel) - halfel) * 0.5;
else
Terrain[x][y].v[1] = 0.25 * (Terrain[left][bottom].v[1] +
Terrain[right][bottom].v[1] +
Terrain[left][top].v[1] +
Terrain[right][top].v[1]) +
((rand() % maxel) - halfel) * 0.2;
if ((x - left) > 1)
{
DivideTerrain(left, x, bottom, y);
DivideTerrain(left, x, y, top);
DivideTerrain(x, right, bottom, y);
DivideTerrain(x, right, y, top);
}
}
/*
* 'GetClock()' - Return an increasing clock time in seconds...
*/
double /* O - Time in seconds */
GetClock(void)
{
#ifdef WIN32
SYSTEMTIME t; /* Current time of day */
GetSystemTime(&t);
return (((t.wHour * 60.0) + t.wMinute) * 60 + t.wSecond +
t.wMilliseconds * 0.001);
#else /* UNIX */
struct timeval t; /* Current time of day */
gettimeofday(&t, NULL);
return ((double)t.tv_sec + 0.000001 * (double)t.tv_usec);
#endif /* WIN32 */
}
/*
* 'Idle()' - Move the viewer and redraw...
*/
void
Idle(void)
{
int i, j; /* Column and row in terrain */
GLfloat movex, movey; /* Scaled mouse movement */
double curtime; /* Current time in milliseconds */
GLfloat distance; /* Distance to move */
GLfloat cheading; /* Cosine of heading */
GLfloat sheading; /* Sine of heading */
GLfloat cpitch; /* Cosine of pitch */
GLfloat spitch; /* Sine of pitch */
/* Get the current system time to figure out how far to move. */
curtime = GetClock();
distance = curtime - LastTime;
LastTime = curtime;
/*
* See how far the mouse pointer is from the 'center' (click)
* position.
*/
movex = 0.01 * sqrt(Velocity) * (MouseX - MouseStartX);
movey = 0.01 * sqrt(Velocity) * (MouseY - MouseStartY);
/*
* Adjust roll, pitch, and heading according to the current
* mouse inputs and orientation.
*/
Orientation[0] += distance * movey * cos(Orientation[2] * M_PI / 180.0);
Orientation[1] += distance * movey * sin(Orientation[2] * M_PI / 180.0);
Orientation[2] += distance * movex;
/* Move based upon the current orientation... */
cheading = cos(Orientation[1] * M_PI / 180.0);
sheading = sin(Orientation[1] * M_PI / 180.0);
cpitch = cos(Orientation[0] * M_PI / 180.0);
spitch = sin(Orientation[0] * M_PI / 180.0);
Position[0] += Velocity * distance * sheading * cpitch;
Position[1] += Velocity * distance * spitch;
Position[2] -= Velocity * distance * cheading * cpitch;
/* Limit the viewer to the terrain... */
if (Position[0] < (-0.45 * TERRAIN_SIZE))
{
Position[0] = -0.45 * TERRAIN_SIZE;
Orientation[1] += 10.0 * distance;
}
if (Position[0] > (0.45 * TERRAIN_SIZE))
{
Position[0] = 0.45 * TERRAIN_SIZE;
Orientation[1] += 10.0 * distance;
}
if (Position[2] < (-0.45 * TERRAIN_SIZE))
{
Position[2] = -0.45 * TERRAIN_SIZE;
Orientation[1] += 10.0 * distance;
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?