#include <glut.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <stdio.h>
#include <math.h>
#include<iostream>
#define GL_BGR 0x80E0 // 扩展的BGR颜色格式
#define M_PI 3.14159265358979323846
// 纹理ID
GLuint skyTexture, roadTexture, wheelTexture, carTexture;
// 小车位置和车轮旋转角度
float carPosition = -1.0f;
float wheelRotation = 0.0f;
// 改进的BMP文件加载函数
GLuint loadBMP(const char* filename) {
FILE* file;
errno_t error = fopen_s(&file, filename, "rb"); // 使用二进制模式打开文件
if (error != 0 || file == nullptr) {
std::cerr << "无法打开文件: " << filename << std::endl;
return 0;
}
// 读取BMP文件头
unsigned char header[54];
if (fread(header, 1, 54, file) != 54) {
std::cerr << "无效的BMP文件头: " << filename << std::endl;
fclose(file);
return 0;
}
// 检查是否为BMP文件
if (header[0] != 'B' || header[1] != 'M') {
std::cerr << "不是BMP文件: " << filename << std::endl;
fclose(file);
return 0;
}
// 获取图像数据的偏移量
int dataPos = *(int*)&(header[0x0A]);
// 获取图像大小
int imageSize = *(int*)&(header[0x22]);
// 获取图像宽度和高度
int width = *(int*)&(header[0x12]);
int height = *(int*)&(header[0x16]);
// 如果BMP文件没有提供图像大小,则计算它
if (imageSize == 0)
imageSize = width * height * 3; // 3表示RGB
// 如果数据位置未指定,则使用默认值
if (dataPos == 0)
dataPos = 54; // BMP文件头的大小
// 为图像数据分配内存
unsigned char* data = new unsigned char[imageSize];
// 读取图像数据
fseek(file, dataPos, SEEK_SET);
fread(data, 1, imageSize, file);
fclose(file);
// 创建纹理ID
GLuint textureID;
glGenTextures(1, &textureID);
// 绑定纹理
glBindTexture(GL_TEXTURE_2D, textureID);
// 加载纹理数据到OpenGL
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_BGR, GL_UNSIGNED_BYTE, data);
delete[] data;
// 设置纹理过滤
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
return textureID;
}
// 绘制带纹理的矩形
void drawTexturedQuad(float x, float y, float width, float height) {
glBegin(GL_QUADS);
glTexCoord2f(0.0f, 0.0f); glVertex2f(x, y);
glTexCoord2f(1.0f, 0.0f); glVertex2f(x + width, y);
glTexCoord2f(1.0f, 1.0f); glVertex2f(x + width, y + height);
glTexCoord2f(0.0f, 1.0f); glVertex2f(x, y + height);
glEnd();
}
// 绘制带纹理的旋转车轮
void drawWheel(float cx, float cy, float radius) {
glPushMatrix();
// 移动到车轮中心并应用旋转
glTranslatef(cx, cy, 0.0f);
glRotatef(wheelRotation, 0.0f, 0.0f, 1.0f);
const int segments = 36;
glBegin(GL_TRIANGLE_FAN);
glTexCoord2f(0.5f, 0.5f); // 中心点
glVertex2f(0.0f, 0.0f);
for (int i = 0; i <= segments; i++) {
float angle = 2.0f * M_PI * i / segments;
float x = cos(angle) * radius;
float y = sin(angle) * radius;
// 计算纹理坐标
glTexCoord2f(0.5f + 0.5f * cos(angle), 0.5f + 0.5f * sin(angle));
glVertex2f(x, y);
}
glEnd();
glPopMatrix();
}
// 绘制小车
void drawCar() {
// 车身 (矩形)
glColor3f(1.0f, 1.0f, 1.0f); // 确保颜色为白色,不影响纹理颜色
glBindTexture(GL_TEXTURE_2D, carTexture);
drawTexturedQuad(carPosition - 0.2f, -0.5f, 0.4f, 0.2f);
// 车轮
glBindTexture(GL_TEXTURE_2D, wheelTexture);
drawWheel(carPosition - 0.15f, -0.55f, 0.07f); // 左轮
drawWheel(carPosition + 0.15f, -0.55f, 0.07f); // 右轮
}
// 场景渲染函数
void renderScene() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// 绘制天空
glBindTexture(GL_TEXTURE_2D, skyTexture);
drawTexturedQuad(-1.0f, -1.0f, 2.0f, 2.0f);
// 绘制道路
glBindTexture(GL_TEXTURE_2D, roadTexture);
drawTexturedQuad(-1.0f, -1.0f, 2.0f, 0.5f);
// 绘制小车
drawCar();
glutSwapBuffers();
}
// 动画更新函数
void update(int value) {
// 更新小车位置(水平移动)
carPosition += 0.01f;
if (carPosition > 1.2f) carPosition = -1.2f;
// 更新车轮旋转角度(顺时针旋转)
wheelRotation -= 5.0f;
if (wheelRotation > 360.0f) wheelRotation += 360.0f;
// 触发重绘
glutPostRedisplay();
glutTimerFunc(16, update, 0); // 约60FPS
}
// 初始化函数
void init() {
// 设置清除颜色为白色(背景色)
glClearColor(1.0, 1.0, 1.0, 0.0);
// 加载纹理
skyTexture = loadBMP("sky.bmp");
roadTexture = loadBMP("road.bmp");
wheelTexture = loadBMP("wheel.bmp");
carTexture = loadBMP("car.bmp");
// 检查纹理是否加载成功
if (!skyTexture || !roadTexture || !wheelTexture || !carTexture) {
std::cerr << "纹理加载失败!请确保所有BMP文件都在正确的位置。" << std::endl;
}
// 启用纹理和混合
glEnable(GL_TEXTURE_2D);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// 设置2D正交投影
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(-1.0, 1.0, -1.0, 1.0);
glMatrixMode(GL_MODELVIEW);
// 设置背景色
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
}
int main(int argc, char** argv) {
// 初始化GLUT
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
glutInitWindowSize(800, 600);
glutCreateWindow("OpenGL 2D动画 - 移动小车");
// 注册回调函数
init();
glutDisplayFunc(renderScene);
glutTimerFunc(0, update, 0); // 启动动画
// 进入主循环
glutMainLoop();
return 0;
}
开启光照计算,加入至少2个光源,并设置2种以上材质,使得场景中的对象呈现出不同的材质特征。