[OpenGL] 简单二维粒子系统——烟花,喷水,落叶
参考代码:http://download.csdn.net/detail/blue6333589/6785389
在这个代码的基础上扩展了二维粒子系统的框架,该系统由一个发射器类和一个粒子类组成,作为编程练习而言,我们只实现了最基本的粒子系统功能,但是已经可以做出一些效果了。
在这里,通过调节参数给出了在这个框架下烟花、喷水、落叶的代码,参考代码实现的是飘雪;只要在物理参数模拟和贴图选择上做得足够好,也可以实现火焰、爆炸等效果。
发射器 其中发射器类支持从点发射和从直线发射,暂时不支持曲线(编程实现困难)以及平面(二维不便于平面发射)的发射器,发射位置分布是随机而均匀的。
同时,我们还可以指定发射速率(单位时间内发射的粒子数目),来控制粒子产生的快慢。
粒子
粒子包含位置、速度、加速度、颜色、贴图、角度、大小、生命等属性。这些都是通过编写init函数完成的,这个init函数是使用库的人自行编写,传入发射器类作为函数指针调用,在这个函数中设置粒子的属性,只要稍作改动,还能实现同一个发射器发射多种形状粒子的效果。
运行流程
初始化发射器 初始化粒子参数 发射粒子 粒子死亡,重新生成该粒子 |
particle.h
#pragma once
#define GLUT_DISABLE_ATEXIT_HACK
#include class particle {
bool is_forever;
//永生
bool has_tex;
//纹理或颜色
float x, y;
//位置
float size_x;
//大小
float size_y;
unsigned int texture;
//纹理
float speed_x;
//速度
float speed_y;
float acc_x;
//加速度
float acc_y;
float life;
//生命
float angle;
//角度
unsigned char color[3];
//颜色
friend class emitter;
void draw(GLuint texture);
//绘制粒子(纹理)
void draw();
//绘制粒子(颜色)
void show();
public:
particle();
particle(float _size_x, float _size_y,
float _speed_x, float _speed_y,
float _acc_x, float _acc_y,
float _life, float _angle, unsigned int _texture, bool _is_forever);
particle(float _size_x, float _size_y,
float _speed_x, float _speed_y,
float _acc_x, float _acc_y,
float _life, float _angle, unsigned char* _color, bool _is_forever);
};
class emitter {
float x1, y1, x2, y2;
//发射器位置
int speed;
//发射速率
particle **p;
//发射粒子
particle* (*f)();
//初始化粒子的函数指针
public:
void emit(particle* (init)());
void update();
emitter(int _speed, float _x1,
float _x2, float _y1, float _y2);
};
particle.cpp
#include
#include"particle.h"void particle::draw(GLuint texture)
{
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, texture);
//选择纹理texture[status]
const GLfloat x1 = -0.5, x2 = 0.5;
const GLfloat y1 = -0.5, y2 = 0.5;
const GLfloat point[4][2] = { { x1,y1 },{ x2,y1 },{ x2,y2 },{ x1,y2 } };
int dir[4][2] = { { 0,0 },{ 1,0 },{ 1,1 },{ 0,1 } };
glBegin(GL_QUADS);
for (int i = 0;
i < 4;
i++) {
glTexCoord2iv(dir[i]);
glVertex2fv(point[i]);
}
glEnd();
glDisable(GL_TEXTURE_2D);
}void particle::draw()
{
const GLfloat x1 = -0.5, x2 = 0.5;
const GLfloat y1 = -0.5, y2 = 0.5;
const GLfloat point[4][2] = { { x1,y1 },{ x2,y1 },{ x2,y2 },{ x1,y2 } };
glBegin(GL_QUADS);
for (int i = 0;
i < 4;
i++) {
glVertex2fv(point[i]);
}
glEnd();
}void particle::show() { if (life > 0 || is_forever) {
if (has_tex) {
glDepthMask(GL_FALSE);
glPushMatrix();
glTranslatef(x, y, 0);
glRotatef(angle, 0, 0, 1);
glScalef(size_x, size_y, 0);
draw(texture);
glPopMatrix();
y += speed_y;
x += speed_x;
speed_y += acc_y;
speed_x += acc_x;
if (!is_forever)life -= 0.2f;
glDepthMask(GL_TRUE);
}
else {
glPushMatrix();
glColor3f(color[0], color[1], color[2]);
glTranslatef(x, y, 0);
glRotatef(angle, 0, 0, 1);
glScalef(size_x, size_y, 0);
draw();
glPopMatrix();
y += speed_y;
x += speed_x;
speed_y += acc_y;
speed_x += acc_x;
if (!is_forever)life -= 0.2f;
glColor3f(0, 0, 0);
}
}
}
particle::particle() {}
particle::particle(float _size_x, float _size_y,
float _speed_x, float _speed_y,
float _acc_x, float _acc_y,
float _life, float _angle, unsigned int _texture, bool _is_forever) {
size_x = _size_x;
size_y = _size_y;
speed_x = _speed_x;
speed_y = _speed_y;
acc_x = _acc_x;
acc_y = _acc_y;
life = _life;
texture = _texture;
angle = _angle;
has_tex = true;
is_forever = _is_forever;
}
particle::particle(float _size_x, float _size_y,
float _speed_x, float _speed_y,
float _acc_x, float _acc_y,
float _life, float _angle, unsigned char* _color, bool _is_forever) {
size_x = _size_x;
size_y = _size_y;
speed_x = _speed_x;
speed_y = _speed_y;
acc_x = _acc_x;
acc_y = _acc_y;
life = _life;
if (_is_forever)_life = 1;
color[0] = *_color;
color[1] = *(_color + 1);
color[2] = *(_color + 2);
angle = _angle;
has_tex = false;
is_forever = _is_forever;
}void emitter::emit(particle* (init)()) {
for (int i = 0;
i < speed;
i++) {
f = init;
p[i] = init();
int place = rand() % speed;
p[i]->x = 1.0f*place / speed*(x2 - x1) + x1;
p[i]->y = 1.0f*place / speed*(y2 - y1) + y1;
}
}void emitter::update() {
for (int i = 0;
i < speed;
i++) {
p[i]->show();
if (p[i]->life < 0) {
delete p[i];
p[i] = f();
int place = rand() % speed;
p[i]->x = 1.0f*place / speed*(x2 - x1) + x1;
p[i]->y = 1.0f*place / speed*(y2 - y1) + y1;
}
}
}emitter::emitter(int _speed, float _x1,
float _x2, float _y1, float _y2) {
speed = _speed;
x1 = _x1;
x2 = _x2;
y1 = _y1;
y2 = _y2;
p = new particle*[speed];
}
我们通过修改main.cpp,在这个粒子系统框架下,可以实现不同的效果:
落叶:
文章图片
main.cpp
#define _CRT_SECURE_NO_WARNINGS#include
#include
#include"particle.h"
#include"texture.h"
emitter *e1;
GLuint texture[1];
//视区
float whRatio;
int wHeight = 0;
int wWidth = 0;
//视点
float center[] = { 0, 0, 0 };
float eye[] = { 0, 0, 5 };
particle* init_particle()
{
float size = rand() % 100 * 0.02f;
unsigned char color[] = { 1.0f,0.0f,0.0f };
particle* p = new particle(size, size, float(rand() % 10 - 4) / 80, float(rand() % 10 - 4) / 40,
1.0 / 10000, -4.9 / 40000, rand() % 200, rand() % 360,texture[0],false);
return p;
}void drawScene()
{
e1->update();
}void updateView(int height, int width)
{
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
//设置矩阵模式为投影
glLoadIdentity();
//初始化矩阵为单位矩阵
whRatio = (GLfloat)width / (GLfloat)height;
//设置显示比例
glOrtho(-30, 30, -30, 30, -100, 100);
//正投影
glMatrixMode(GL_MODELVIEW);
//设置矩阵模式为模型
}void reshape(int width, int height)
{
if (height == 0){ //如果高度为0
height = 1;
//让高度为1(避免出现分母为0的现象)
}
wHeight = height;
wWidth = width;
updateView(wHeight, wWidth);
//更新视角
}void idle()
{
glutPostRedisplay();
}void init(void)
{
srand(unsigned(time(nullptr)));
glClearColor(1.0, 0.0, 0.0, 0.0);
glShadeModel(GL_SMOOTH);
glEnable(GL_DEPTH_TEST);
glColor4f(1.0, 1.0, 1.0, 1.0f);
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
glEnable(GL_BLEND);
BuildTexture("11.jpg", texture[0]);
e1 = new emitter(500, -30,30, 30, 30);
e1->emit(init_particle);
}void redraw()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//清除颜色和深度缓存
glClearColor(0, 0, 0, 1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
//初始化矩阵为单位矩阵
gluLookAt(eye[0], eye[1], eye[2], center[0], center[1], center[2], 0, 1, 0);
drawScene();
//绘制场景
glutSwapBuffers();
//交换缓冲区
}int main(int argc, char *argv[])
{
glutInit(&argc, argv);
//对glut的初始化
glutInitDisplayMode(GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE);
//初始化显示模式:RGB颜色模型,深度测试,双缓冲
glutInitWindowSize(800, 600);
//设置窗口大小
int windowHandle = glutCreateWindow("Simple GLUT App");
//设置窗口标题
glutDisplayFunc(redraw);
//注册绘制回调函数
glutReshapeFunc(reshape);
//注册重绘回调函数
glutIdleFunc(idle);
//注册全局回调函数:空闲时调用
init();
glutMainLoop();
// glut事件处理循环
return 0;
}
文章图片
11.jpg
烟花:
文章图片
main.cpp
#define _CRT_SECURE_NO_WARNINGS#include
#include
#include"particle.h"
#include"texture.h"
emitter *e1;
emitter *e2;
emitter *e3;
//视区
float whRatio;
int wHeight = 0;
int wWidth = 0;
//视点
float center[] = { 0, 0, 0 };
float eye[] = { 0, 0, 5 };
particle* init_particle1()
{
float size = rand() % 15 * 0.02f;
unsigned char color[] = { 1.0f,0.0f,0.0f };
particle* p = new particle(size, size, float(rand() % 10 - 4) / 80, float(rand() % 10 - 4) / 80,
0, -4.9 / 40000, rand() % 80, 0, color, false);
return p;
}particle* init_particle2()
{
float size = rand() % 15 * 0.02f;
unsigned char color[] = { 0.0f,1.0f,0.0f };
particle* p = new particle(size, size, float(rand() % 10 - 4) / 80, float(rand() % 10 - 4) / 80,
0, -4.9 / 40000, rand() % 50, 0, color, false);
return p;
}
particle* init_particle3()
{
float size = rand() % 15 * 0.02f;
unsigned char color[] = { 0.0f,0.0f,1.0f };
particle* p = new particle(size, size, float(rand() % 10 - 4) / 80, float(rand() % 10 - 4) / 80,
0, -4.9 / 40000, rand() % 40, 0, color,false);
return p;
}void drawScene()
{
e1->update();
e2->update();
e3->update();
}void updateView(int height, int width)
{
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
//设置矩阵模式为投影
glLoadIdentity();
//初始化矩阵为单位矩阵
whRatio = (GLfloat)width / (GLfloat)height;
//设置显示比例
glOrtho(-30, 30, -30, 30, -100, 100);
//正投影
glMatrixMode(GL_MODELVIEW);
//设置矩阵模式为模型
}void reshape(int width, int height)
{
if (height == 0){ //如果高度为0
height = 1;
//让高度为1(避免出现分母为0的现象)
}
wHeight = height;
wWidth = width;
updateView(wHeight, wWidth);
//更新视角
}void idle()
{
glutPostRedisplay();
}void init(void)
{
srand(unsigned(time(nullptr)));
glClearColor(1.0, 0.0, 0.0, 0.0);
glShadeModel(GL_SMOOTH);
glEnable(GL_DEPTH_TEST);
glColor4f(1.0, 1.0, 1.0, 1.0f);
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
glEnable(GL_BLEND);
e1 = new emitter(1000, 0, 0, 0, 0);
e1->emit(init_particle1);
e2 = new emitter(1000, 10, 10, 10, 10);
e2->emit(init_particle2);
e3 = new emitter(1000, -20, -20, 13, 13);
e3->emit(init_particle3);
}void redraw()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//清除颜色和深度缓存
glClearColor(0, 0, 0, 1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
//初始化矩阵为单位矩阵
gluLookAt(eye[0], eye[1], eye[2], center[0], center[1], center[2], 0, 1, 0);
drawScene();
//绘制场景
glutSwapBuffers();
//交换缓冲区
}int main(int argc, char *argv[])
{
glutInit(&argc, argv);
//对glut的初始化
glutInitDisplayMode(GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE);
//初始化显示模式:RGB颜色模型,深度测试,双缓冲
glutInitWindowSize(800, 600);
//设置窗口大小
int windowHandle = glutCreateWindow("Simple GLUT App");
//设置窗口标题
glutDisplayFunc(redraw);
//注册绘制回调函数
glutReshapeFunc(reshape);
//注册重绘回调函数
glutIdleFunc(idle);
//注册全局回调函数:空闲时调用
init();
glutMainLoop();
// glut事件处理循环
return 0;
}
喷水:
文章图片
main.cpp
#define _CRT_SECURE_NO_WARNINGS#include
#include
#include"particle.h"
#include"texture.h"
emitter *e1;
GLuint texture[1];
//视区
float whRatio;
int wHeight = 0;
int wWidth = 0;
//视点
float center[] = { 0, 0, 0 };
float eye[] = { 0, 0, 5 };
particle* init_particle()
{
static int count = 0;
float size = rand() % 50 * 0.02f;
particle* p;
p = new particle(size, size, float(rand() % 10-4) / 50, float(rand() % 100) / 200+0.5,
0, -4.9 / 1000, rand() % 60, 0, texture[0],false);
return p;
}
void drawScene()
{
e1->update();
}void updateView(int height, int width)
{
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
//设置矩阵模式为投影
glLoadIdentity();
//初始化矩阵为单位矩阵
whRatio = (GLfloat)width / (GLfloat)height;
//设置显示比例
glOrtho(-30, 30, -30, 30, -100, 100);
//正投影
glMatrixMode(GL_MODELVIEW);
//设置矩阵模式为模型
}void reshape(int width, int height)
{
if (height == 0){ //如果高度为0
height = 1;
//让高度为1(避免出现分母为0的现象)
}
wHeight = height;
wWidth = width;
updateView(wHeight, wWidth);
//更新视角
}void idle()
{
glutPostRedisplay();
}void init(void)
{
srand(unsigned(time(nullptr)));
glClearColor(1.0, 0.0, 0.0, 0.0);
glShadeModel(GL_SMOOTH);
glEnable(GL_DEPTH_TEST);
glColor4f(1.0, 1.0, 1.0, 1.0f);
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
glEnable(GL_BLEND);
BuildTexture("12.jpg", texture[0]);
e1 = new emitter(5000, 0,0, -30, -30);
e1->emit(init_particle);
}void redraw()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//清除颜色和深度缓存
glClearColor(0, 0, 0, 1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
//初始化矩阵为单位矩阵
gluLookAt(eye[0], eye[1], eye[2], center[0], center[1], center[2], 0, 1, 0);
drawScene();
//绘制场景
glutSwapBuffers();
//交换缓冲区
}int main(int argc, char *argv[])
{
glutInit(&argc, argv);
//对glut的初始化
glutInitDisplayMode(GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE);
//初始化显示模式:RGB颜色模型,深度测试,双缓冲
glutInitWindowSize(800, 600);
//设置窗口大小
int windowHandle = glutCreateWindow("Simple GLUT App");
//设置窗口标题
glutDisplayFunc(redraw);
//注册绘制回调函数
glutReshapeFunc(reshape);
//注册重绘回调函数
glutIdleFunc(idle);
//注册全局回调函数:空闲时调用
init();
glutMainLoop();
// glut事件处理循环
return 0;
}
文章图片
12.jpg
______________________________________________________________________________________________________________________________________
【[OpenGL] 简单二维粒子系统——烟花,喷水,落叶】以下纹理代码来自参考代码(可加载jpg图片),非原创,在这里给出以保证代码完整性:
texture.h
#pragma once
#include // OpenGL32库的头文件
#include
struct TextureTga// 建立一个结构体
{
GLubyte *imageData;
// 图像数据 (最高32bit)
GLuint bpp;
// 每一象素的图像颜色深度
GLuint width;
// 图像宽度
GLuint height;
// 图像高度
GLuint texID;
// 纹理ID
};
// 载入BMP,JPG,GIF等文件
bool BuildTexture(char *szPathName, GLuint &texid);
// 载入TGA文件
bool BuildTexture(char *filename, TextureTga *texture);
texture.cpp
#define _CRT_SECURE_NO_WARNINGS
#include// 标准输入输出头文件
#include // OLE控制库头文件
#include // 数学函数头文件#include "texture.h"bool BuildTexture(char *szPathName, GLuint &texid)// 载入图片并转换为纹理
{
HDChdcTemp;
// DC用来保存位图
HBITMAPhbmpTemp;
// 保存临时位图
IPicture *pPicture;
// 定义IPicture Interface
OLECHARwszPath[MAX_PATH + 1];
// 图片的完全路径
charszPath[MAX_PATH + 1];
// 图片的完全路径
longlWidth;
// 图像宽度
longlHeight;
// 图像高度
longlWidthPixels;
// 图像的宽带(以像素为单位)
longlHeightPixels;
// 图像的高带(以像素为单位)
GLintglMaxTexDim;
// 保存纹理的最大尺寸 if (strstr(szPathName, "http://"))// 如果路径包含 http:// 则...
{
strcpy(szPath, szPathName);
// 把路径拷贝到 szPath
}
else// 否则从文件导入图片
{
GetCurrentDirectory(MAX_PATH, szPath);
// 取得当前路径
strcat(szPath, "\\");
// 添加字符"\"
strcat(szPath, szPathName);
// 添加图片的相对路径
} MultiByteToWideChar(CP_ACP, 0, szPath, -1, wszPath, MAX_PATH);
// 把ASCII码转化为Unicode标准码
HRESULT hr = OleLoadPicturePath(wszPath, 0, 0, 0, IID_IPicture, (void**)&pPicture);
if (FAILED(hr))// 如果导入失败
{
// 图片载入失败出错信息
MessageBox(HWND_DESKTOP, "图片导入失败!\n(TextureLoad Failed!)", "Error", MB_OK | MB_ICONEXCLAMATION);
return FALSE;
// 返回 FALSE
} hdcTemp = CreateCompatibleDC(GetDC(0));
// 建立窗口设备描述表
if (!hdcTemp)// 建立失败?
{
pPicture->Release();
// 释放IPicture
// 图片载入失败出错信息
MessageBox(HWND_DESKTOP, "图片导入失败!\n(TextureLoad Failed!)", "Error", MB_OK | MB_ICONEXCLAMATION);
return FALSE;
// 返回 FALSE
} glGetIntegerv(GL_MAX_TEXTURE_SIZE, &glMaxTexDim);
// 取得支持的纹理最大尺寸 pPicture->get_Width(&lWidth);
// 取得IPicture 宽度 (转换为Pixels格式)
lWidthPixels = MulDiv(lWidth, GetDeviceCaps(hdcTemp, LOGPIXELSX), 2540);
pPicture->get_Height(&lHeight);
// 取得IPicture 高度 (转换为Pixels格式)
lHeightPixels = MulDiv(lHeight, GetDeviceCaps(hdcTemp, LOGPIXELSY), 2540);
// 调整图片到最好的效果
if (lWidthPixels <= glMaxTexDim)// 图片宽度是否超过显卡最大支持尺寸
lWidthPixels = 1 << (int)floor((log((double)lWidthPixels) / log(2.0f)) + 0.5f);
else// 否则,将图片宽度设为显卡最大支持尺寸
lWidthPixels = glMaxTexDim;
if (lHeightPixels <= glMaxTexDim)// 图片高度是否超过显卡最大支持尺寸
lHeightPixels = 1 << (int)floor((log((double)lHeightPixels) / log(2.0f)) + 0.5f);
else// 否则,将图片高度设为显卡最大支持尺寸
lHeightPixels = glMaxTexDim;
// 建立一个临时位图
BITMAPINFO bi = { 0 };
// 位图的类型
DWORD*pBits = 0;
// 指向位图Bits的指针 bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
// 设置结构大小
bi.bmiHeader.biBitCount = 32;
// 32 位
bi.bmiHeader.biWidth = lWidthPixels;
// 宽度像素值
bi.bmiHeader.biHeight = lHeightPixels;
// 高度像素值
bi.bmiHeader.biCompression = BI_RGB;
// RGB 格式
bi.bmiHeader.biPlanes = 1;
// 一个位平面// 建立一个位图这样我们可以指定颜色和深度 并访问每位的值
hbmpTemp = CreateDIBSection(hdcTemp, &bi, DIB_RGB_COLORS, (void**)&pBits, 0, 0);
if (!hbmpTemp)// 建立失败?
{
DeleteDC(hdcTemp);
// 删除设备描述表
pPicture->Release();
// 释放IPicture
// 图片载入失败出错信息
MessageBox(HWND_DESKTOP, "图片导入失败!\n(TextureLoad Failed!)", "Error", MB_OK | MB_ICONEXCLAMATION);
return FALSE;
// 返回 FALSE
} SelectObject(hdcTemp, hbmpTemp);
// 选择临时DC句柄和临时位图对象// 在位图上绘制IPicture
pPicture->Render(hdcTemp, 0, 0, lWidthPixels, lHeightPixels, 0, lHeight, lWidth, -lHeight, 0);
// 将BGR转换为RGB 将ALPHA值设为255
for (long i = 0;
i < lWidthPixels * lHeightPixels;
i++)// 循环遍历所有的像素
{
BYTE* pPixel = (BYTE*)(&pBits[i]);
// 获取当前像素
BYTEtemp = pPixel[0];
// 临时存储第一个颜色像素(蓝色)
pPixel[0] = pPixel[2];
// 将红色值存到第一位
pPixel[2] = temp;
// 将蓝色值存到第三位
pPixel[3] = 255;
// ALPHA值设为255
} glGenTextures(1, &texid);
// 创建纹理// 使用来自位图数据生成 的典型纹理
glBindTexture(GL_TEXTURE_2D, texid);
// 绑定纹理
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
// 线形滤波
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// 线形滤波// 生成纹理
glTexImage2D(GL_TEXTURE_2D, 0, 3, lWidthPixels, lHeightPixels, 0, GL_RGBA, GL_UNSIGNED_BYTE, pBits);
DeleteObject(hbmpTemp);
// 删除对象
DeleteDC(hdcTemp);
// 删除设备描述表 pPicture->Release();
// 释放 IPicture return true;
// 返回 TRUE
}bool BuildTexture(char *filename, TextureTga *texture)// 载入一个.TGA 文件到内存
{
GLubyteTGAheader[12] = { 0,0,2,0,0,0,0,0,0,0,0,0 };
// 没有压缩的TGA Header
GLubyteTGAcompare[12];
// 用来比较 TGA Header
GLubyteheader[6];
// Header里,头六个有用字节
GLuintbytesPerPixel;
// 保存TGA文件里每个像素用到的字节数
GLuintimageSize;
// 用来保存随机产生的图像的大小
GLuinttemp;
// 临时变量
GLuinttype = GL_RGBA;
// 将默认的GL模式设置为RBGA (32 BPP) FILE *file = fopen(filename, "rb");
// 打开 TGA 文件 if (file == NULL)// 文件是否已存在?
{
// 图片载入失败出错信息
MessageBox(HWND_DESKTOP, "图片导入失败!\n(TextureLoad Failed!)", "Error", MB_OK | MB_ICONEXCLAMATION);
return FALSE;
// 返回FALSE
} if (fread(TGAcompare, 1, sizeof(TGAcompare), file) != sizeof(TGAcompare)// 是否有十二个字节可读?
|| memcmp(TGAheader, TGAcompare, sizeof(TGAheader)) != 0// header和我们想要的是否相符?
|| fread(header, 1, sizeof(header), file) != sizeof(header))// 如果是读下六个字节
{
fclose(file);
// 如果失败,关闭文件
// 图片载入失败出错信息
MessageBox(HWND_DESKTOP, "图片导入失败!\n(TextureLoad Failed!)", "Error", MB_OK | MB_ICONEXCLAMATION);
return FALSE;
// 返回FALSE
} texture->width = header[1] * 256 + header[0];
// 确定的TGA 宽度 (高字节*256+低字节)
texture->height = header[3] * 256 + header[2];
// 确定的TGA 高度 (高字节*256+低字节) if (texture->width <= 0// 宽度是否小于等于0
|| texture->height <= 0// 高度是否小于等于0
|| (header[4] != 24 && header[4] != 32))// TGA 是24位或32位?
{
fclose(file);
// 任何一个不成立, 则关闭文件
// 图片载入失败出错信息
MessageBox(HWND_DESKTOP, "图片导入失败!\n(TextureLoad Failed!)", "Error", MB_OK | MB_ICONEXCLAMATION);
return FALSE;
// 返回FALSE
} texture->bpp = header[4];
// 获取TGA每个像素的位(24 or 32)
bytesPerPixel = texture->bpp / 8;
// 除以8以取得 每个像素的字节
imageSize = texture->width*texture->height*bytesPerPixel;
// 计算TAG数据所需要的内存 texture->imageData = https://www.it610.com/article/(GLubyte *)malloc(imageSize);
// 开辟一个内存空间用来存储TGA数据 if (texture->imageData =https://www.it610.com/article/= NULL// 用来存储的内存是否存在?
|| fread(texture->imageData, 1, imageSize, file) != imageSize) // 图像大小是否和内存空间大小相符?
{
if (texture->imageData != NULL)// 图像数据是否载入
{
free(texture->imageData);
// 如果是 释放图像数据
}
fclose(file);
// 关闭文件
MessageBox(HWND_DESKTOP, "图片导入失败!\n(TextureLoad Failed!)", "Error", MB_OK | MB_ICONEXCLAMATION);
return FALSE;
// 返回FALSE
} for (GLuint i = 0;
iimageData[i];
// 将图像数据‘i’的值存在临时变量中
texture->imageData[i] = texture->imageData[i + 2];
// 将第三个字节的值存到第一个字节里
texture->imageData[i + 2] = temp;
// 将临时变量的值存入第三字节(第一字节的值)
} fclose(file);
// 关闭文件//创建一种纹理
glGenTextures(1, &texture->texID);
// 产生OpenGL纹理ID glBindTexture(GL_TEXTURE_2D, texture->texID);
// 绑定纹理
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
// 线性滤波
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// 线性滤波 if (texture->bpp == 24)// TGA图片是不是 24 位的
{
type = GL_RGB;
// 如果是将'type'设置为 GL_RGB
} glTexImage2D(GL_TEXTURE_2D, 0, type, texture->width, texture->height, 0, type, GL_UNSIGNED_BYTE, texture->imageData);
return true;
// 纹理创建成功,返回正确
}
推荐阅读
- 科学养胃,别被忽悠,其实真的很简单
- opencv|opencv C++模板匹配的简单实现
- 松软可口易消化,无需烤箱超简单,新手麻麻也能轻松成功~
- 简单心理2019春A期+32+张荣
- 《算法》-图[有向图]
- android防止连续点击的简单实现(kotlin)
- 机器学习一些简单笔记
- 分享!如何分分钟实现微信扫二维码调用外部浏览器打开指定页面的功能
- Android超简单实现沉浸式状态栏
- 20180531去二维火学习完给股东的分享