- gf25152 的博客
OpenGL
- @ 2026-3-29 19:24:06
-lopengl32 -lglu32 -lglut32 -lpng
#include <iostream>
#include <GL/glut.h>
#include <png.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
using namespace std;
// 摄像机视角控制
float camX = 0.0f, camY = 8.0f, camZ = 20.0f;
float rotX = 0.0f, rotY = 0.0f;
int lastMouseX, lastMouseY;
bool mouseDown = false;
// 纹理ID
GLuint tex_grass_on, tex_grass_side, tex_dirt, tex_stone;
// 平台尺寸(方块数量)
#define PLAT_SIZE 10
// 平台总层数
#define LAYERS 6
// ------------------------------
// PNG图片加载函数(C++98兼容)
// ------------------------------
GLuint loadPNG(const char* filename) {
FILE* fp = fopen(filename, "rb");
if (!fp) {
cout << "找不到贴图: " << filename << endl;
return 0;
}
unsigned char sig[8];
fread(sig, 1, 8, fp);
if (!png_check_sig(sig, 8)) {
fclose(fp);
return 0;
}
png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
png_infop info_ptr = png_create_info_struct(png_ptr);
setjmp(png_jmpbuf(png_ptr));
png_init_io(png_ptr, fp);
png_set_sig_bytes(png_ptr, 8);
png_read_info(png_ptr, info_ptr);
int width = png_get_image_width(png_ptr, info_ptr);
int height = png_get_image_height(png_ptr, info_ptr);
int channels = png_get_channels(png_ptr, info_ptr);
png_bytep* row_pointers = new png_bytep[height];
unsigned char* data = new unsigned char[width * height * channels];
for (int i = 0; i < height; i++) {
row_pointers[height - 1 - i] = data + i * width * channels;
}
png_read_image(png_ptr, row_pointers);
GLuint tex;
glGenTextures(1, &tex);
glBindTexture(GL_TEXTURE_2D, tex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
if (channels == 3) {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
} else {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
}
delete[] row_pointers;
delete[] data;
fclose(fp);
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
return tex;
}
// ------------------------------
// 渲染单个立方体(带6面纹理)
// ------------------------------
void drawCube(float x, float y, float z, GLuint top, GLuint side, GLuint bottom) {
glPushMatrix();
glTranslatef(x, y, z);
// 上面
glBindTexture(GL_TEXTURE_2D, top);
glBegin(GL_QUADS);
glTexCoord2f(0,0); glVertex3f(-1,1,-1);
glTexCoord2f(1,0); glVertex3f(1,1,-1);
glTexCoord2f(1,1); glVertex3f(1,1,1);
glTexCoord2f(0,1); glVertex3f(-1,1,1);
glEnd();
// 下面
glBindTexture(GL_TEXTURE_2D, bottom);
glBegin(GL_QUADS);
glTexCoord2f(0,0); glVertex3f(-1,-1,-1);
glTexCoord2f(1,0); glVertex3f(1,-1,-1);
glTexCoord2f(1,1); glVertex3f(1,-1,1);
glTexCoord2f(0,1); glVertex3f(-1,-1,1);
glEnd();
// 四周
glBindTexture(GL_TEXTURE_2D, side);
// 前
glBegin(GL_QUADS);
glTexCoord2f(0,0); glVertex3f(-1,-1,1);
glTexCoord2f(1,0); glVertex3f(1,-1,1);
glTexCoord2f(1,1); glVertex3f(1,1,1);
glTexCoord2f(0,1); glVertex3f(-1,1,1);
glEnd();
// 后
glBegin(GL_QUADS);
glTexCoord2f(0,0); glVertex3f(-1,-1,-1);
glTexCoord2f(1,0); glVertex3f(1,-1,-1);
glTexCoord2f(1,1); glVertex3f(1,1,-1);
glTexCoord2f(0,1); glVertex3f(-1,1,-1);
glEnd();
// 左
glBegin(GL_QUADS);
glTexCoord2f(0,0); glVertex3f(-1,-1,-1);
glTexCoord2f(1,0); glVertex3f(-1,-1,1);
glTexCoord2f(1,1); glVertex3f(-1,1,1);
glTexCoord2f(0,1); glVertex3f(-1,1,-1);
glEnd();
// 右
glBegin(GL_QUADS);
glTexCoord2f(0,0); glVertex3f(1,-1,-1);
glTexCoord2f(1,0); glVertex3f(1,-1,1);
glTexCoord2f(1,1); glVertex3f(1,1,1);
glTexCoord2f(0,1); glVertex3f(1,1,-1);
glEnd();
glPopMatrix();
}
// ------------------------------
// 生成6层平台
// ------------------------------
void drawWorld() {
for (int layer = 1; layer <= LAYERS; ++layer) {
GLuint t, s, b;
if (layer == 6) { // 顶层:草方块
t = tex_grass_on;
s = tex_grass_side;
b = tex_dirt;
}
else if (layer == 5 || layer == 4) { // 泥土
t = s = b = tex_dirt;
}
else { // 石头(1、2、3层)
t = s = b = tex_stone;
}
float y = layer * 2.0f - 6.0f;
for (int x = -PLAT_SIZE; x < PLAT_SIZE; ++x) {
for (int z = -PLAT_SIZE; z < PLAT_SIZE; ++z) {
drawCube(x*2, y, z*2, t, s, b);
}
}
}
}
// ------------------------------
// OpenGL主渲染
// ------------------------------
void display() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
// 3D视角
glRotatef(rotX, 1,0,0);
glRotatef(rotY, 0,1,0);
glTranslatef(-camX, -camY, -camZ);
drawWorld();
glutSwapBuffers();
}
// ------------------------------
// 鼠标控制视角
// ------------------------------
void mouse(int button, int state, int x, int y) {
if (button == GLUT_LEFT_BUTTON) {
mouseDown = (state == GLUT_DOWN);
lastMouseX = x;
lastMouseY = y;
}
}
void motion(int x, int y) {
if (mouseDown) {
rotY += (x - lastMouseX) * 0.3f;
rotX += (y - lastMouseY) * 0.3f;
lastMouseX = x;
lastMouseY = y;
glutPostRedisplay();
}
}
// ------------------------------
// 键盘移动
// ------------------------------
void keyboard(int key, int x, int y) {
float speed = 1.0f;
if (key == GLUT_KEY_UP) camZ -= speed;
if (key == GLUT_KEY_DOWN) camZ += speed;
if (key == GLUT_KEY_LEFT) camX -= speed;
if (key == GLUT_KEY_RIGHT) camX += speed;
glutPostRedisplay();
}
// ------------------------------
// 初始化
// ------------------------------
void init() {
glEnable(GL_TEXTURE_2D);
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
glClearColor(0.5f, 0.7f, 1.0f, 1.0f);
// 加载贴图(同exe文件夹)
tex_grass_on = loadPNG("grass_block_on.png");
tex_grass_side = loadPNG("grass_block_side.png");
tex_dirt = loadPNG("dirt.png");
tex_stone = loadPNG("stone.png");
// 透视投影
glMatrixMode(GL_PROJECTION);
gluPerspective(60, 1.0, 0.1, 100);
glMatrixMode(GL_MODELVIEW);
}
// ------------------------------
// 主函数
// ------------------------------
int main(int argc, char** argv) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize(800, 600);
glutCreateWindow("Minecraft 3D Platform - C++98 OpenGL");
init();
glutDisplayFunc(display);
glutMouseFunc(mouse);
glutMotionFunc(motion);
glutSpecialFunc(keyboard);
glutMainLoop();
return 0;
}