码迷,mamicode.com
首页 > 其他好文 > 详细

[OpenGL] 简单二维粒子系统——烟花,喷水,落叶

时间:2016-07-20 21:32:44      阅读:407      评论:0      收藏:0      [点我收藏+]

标签:

        参考代码:http://download.csdn.net/detail/blue6333589/6785389

        在这个代码的基础上扩展了二维粒子系统的框架,该系统由一个发射器类和一个粒子类组成,作为编程练习而言,我们只实现了最基本的粒子系统功能,但是已经可以做出一些效果了。

        在这里,通过调节参数给出了在这个框架下烟花、喷水、落叶的代码,参考代码实现的是飘雪;只要在物理参数模拟和贴图选择上做得足够好,也可以实现火焰、爆炸等效果。


        发射器

        其中发射器类支持从点发射和从直线发射,暂时不支持曲线(编程实现困难)以及平面(二维不便于平面发射)的发射器,发射位置分布是随机而均匀的。

        同时,我们还可以指定发射速率(单位时间内发射的粒子数目),来控制粒子产生的快慢。

      粒子

        粒子包含位置、速度、加速度、颜色、贴图、角度、大小、生命等属性。这些都是通过编写init函数完成的,这个init函数是使用库的人自行编写,传入发射器类作为函数指针调用,在这个函数中设置粒子的属性,只要稍作改动,还能实现同一个发射器发射多种形状粒子的效果。    

      运行流程

      

初始化发射器
初始化粒子参数
发射粒子
粒子死亡,重新生成该粒子


  particle.h

#pragma once
#define GLUT_DISABLE_ATEXIT_HACK
#include <gl/glut.h>  


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<stdlib.h>
#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 <stdlib.h>     
#include<time.h>  
#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 <stdlib.h>     
#include<time.h>  
#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 <stdlib.h>     
#include<time.h>  
#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

______________________________________________________________________________________________________________________________________

以下纹理代码来自参考代码(可加载jpg图片),非原创,在这里给出以保证代码完整性:

texture.h

#pragma once
#include <gl/glut.h>              // OpenGL32库的头文件
#include<stdio.h>
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 <stdio.h>              // 标准输入输出头文件
#include <olectl.h>              // OLE控制库头文件
#include <math.h>              // 数学函数头文件

#include "texture.h"

bool BuildTexture(char *szPathName, GLuint &texid)      // 载入图片并转换为纹理
{
	HDC   hdcTemp;            // DC用来保存位图
	HBITMAP  hbmpTemp;            // 保存临时位图
	IPicture *pPicture;            // 定义IPicture Interface
	OLECHAR  wszPath[MAX_PATH + 1];         // 图片的完全路径
	char  szPath[MAX_PATH + 1];          // 图片的完全路径
	long  lWidth;             // 图像宽度
	long  lHeight;            // 图像高度
	long  lWidthPixels;           // 图像的宽带(以像素为单位)
	long  lHeightPixels;           // 图像的高带(以像素为单位)
	GLint  glMaxTexDim;           // 保存纹理的最大尺寸

	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]);       // 获取当前像素
		BYTE  temp = 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 文件到内存
{
	GLubyte  TGAheader[12] = { 0,0,2,0,0,0,0,0,0,0,0,0 };    // 没有压缩的TGA Header
	GLubyte  TGAcompare[12];           // 用来比较 TGA Header
	GLubyte  header[6];            // Header里,头六个有用字节
	GLuint  bytesPerPixel;           // 保存TGA文件里每个像素用到的字节数
	GLuint  imageSize;            // 用来保存随机产生的图像的大小
	GLuint  temp;             // 临时变量
	GLuint  type = 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 = (GLubyte *)malloc(imageSize);     // 开辟一个内存空间用来存储TGA数据

	if (texture->imageData == 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; i<int(imageSize); i += bytesPerPixel)    // 循环遍历图像数据
	{                 // 交换第一和第三字节(红 和 蓝)
		temp = texture->imageData[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;              // 纹理创建成功,返回正确
}



[OpenGL] 简单二维粒子系统——烟花,喷水,落叶

标签:

原文地址:http://blog.csdn.net/zju_fish1996/article/details/51968085

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!