openGL模拟烟雾特效

前言

          使用openGL模拟烟雾特效,基于Bulr算法,通常,图像处理软件会提供"模糊"(blur)滤镜,使图片产生模糊的效果,"模糊"的算法有很多种,其中有一种叫做"高斯模糊"(Gaussian Blur)。它将正态分布(又名"高斯分布")用于图像处理。

       

"模糊"的算法有很多种,其中有一种叫做"高斯模糊"(Gaussian Blur)。它将正态分布(又名"高斯分布")用于图像处理。

讲解高斯分布文章,大家可以参考下

原理

一下内容参考网上大牛:

作者: 阮一峰

日期: 2012年11月14日

photoShop上面有 Blur选项

本文介绍"高斯模糊"的算法,你会看到这是一个非常简单易懂的算法。本质上,它是一种数据平滑技术(data smoothing),适用于多个场合,图像处理恰好提供了一个直观的应用实例。

一、高斯模糊的原理

所谓"模糊",可以理解成每一个像素都取周边像素的平均值。

上图中,2是中间点,周边点都是1。

"中间点"取"周围点"的平均值,就会变成1。在数值上,这是一种"平滑化"。在图形上,就相当于产生"模糊"效果,"中间点"失去细节。

显然,计算平均值时,取值范围越大,"模糊效果"越强烈。

上面分别是原图、模糊半径3像素、模糊半径10像素的效果。模糊半径越大,图像就越模糊。从数值角度看,就是数值越平滑。

接下来的问题就是,既然每个点都要取周边像素的平均值,那么应该如何分配权重呢?

如果使用简单平均,显然不是很合理,因为图像都是连续的,越靠近的点关系越密切,越远离的点关系越疏远。因此,加权平均更合理,距离越近的点权重越大,距离越远的点权重越小。

二、正态分布的权重

正态分布显然是一种可取的权重分配模式。

在图形上,正态分布是一种钟形曲线,越接近中心,取值越大,越远离中心,取值越小。

计算平均值的时候,我们只需要将"中心点"作为原点,其他点按照其在正态曲线上的位置,分配权重,就可以得到一个加权平均值。

三、高斯函数

上面的正态分布是一维的,图像都是二维的,所以我们需要二维的正态分布。

正态分布的密度函数叫做"高斯函数"(Gaussian function)。它的一维形式是:

其中,μ是x的均值,σ是x的方差。因为计算平均值的时候,中心点就是原点,所以μ等于0。

根据一维高斯函数,可以推导得到二维高斯函数:

有了这个函数 ,就可以计算每个点的权重了。

四、权重矩阵

假定中心点的坐标是(0,0),那么距离它最近的8个点的坐标如下:

更远的点以此类推。

为了计算权重矩阵,需要设定σ的值。假定σ=1.5,则模糊半径为1的权重矩阵如下:

这9个点的权重总和等于0.4787147,如果只计算这9个点的加权平均,还必须让它们的权重之和等于1,因此上面9个值还要分别除以0.4787147,得到最终的权重矩阵。

五、计算高斯模糊

有了权重矩阵,就可以计算高斯模糊的值了。

假设现有9个像素点,灰度值(0-255)如下:

每个点乘以自己的权重值:

得到

将这9个值加起来,就是中心点的高斯模糊的值。

对所有点重复这个过程,就得到了高斯模糊后的图像。如果原图是彩色图片,可以对RGB三个通道分别做高斯模糊。

六、边界点的处理

如果一个点处于边界,周边没有足够的点,怎么办?

一个变通方法,就是把已有的点拷贝到另一面的对应位置,模拟出完整的矩阵。

七、参考文献

How to program a Gaussian Blur without using 3rd party libraries

实践

          好了,上面介绍完了Blur理论知识,现在开始从代码方面讨论在openGL中实现基于Blur的烟雾特效。

先看下运行效果:烟雾是动态的哦

tools.h   这个头文件是个工具类,主要实现openGL基本的操作,矩阵操作、点乘、叉乘、坐标变换

#include <cmath>
#include "gl/glut.h"

using namespace std;

struct GPoint3d {
	double mX, mY, mZ;
	double x() { return mX; }
	double y() { return mY; }
	double z() { return mZ; }
	void setX(double x) { mX = x; }
	void setY(double y) { mY = y; }
	void setZ(double z) { mZ = z; }
	void set(double x, double y, double z) { mX = x; mY = y; mZ = z; }
};

class TrackBall
{
	int OldX;
	int OldY;
	double mMatrix[16];
public:
	TrackBall() {}
	// 向量的点积
	double dotMult(GPoint3d v1, GPoint3d v2);
	// 向量的叉积
	GPoint3d crossMult(GPoint3d v1, GPoint3d v2);
	// 将鼠标二维点映射为球面向量(用于鼠标追踪球) 
	GPoint3d gMousePtToSphereVec(int x, int y, int w, int h);
	void makeRolate();

	void MouseMove(int x, int y);
	void resize()
	{
		glGetDoublev(GL_MODELVIEW_MATRIX, mMatrix);  // 返回当前模型矩阵
	}
	void setXY(int x, int y) { OldX = x; OldY = y; }
	void setP(double *v)//{x1,y1,z1,  x2,y2,z2,  x3,y3,z3}
	{
		GPoint3d v1, v2, v3;
		v1.setX(v[3] - v[0]);
		v1.setY(v[4] - v[1]);
		v1.setZ(v[5] - v[2]);

		v2.setX(v[6] - v[0]);
		v2.setY(v[7] - v[1]);
		v2.setZ(v[8] - v[2]);

		v3 = crossMult(v1, v2);

		glNormal3f(v3.x(), v3.y(), v3.z());
	}
};

 tools.cpp


#include "tools.h"


double TrackBall::dotMult(GPoint3d v1, GPoint3d v2)
{
	double angle;
	angle = v1.x()*v2.x() + v1.y()*v2.y() + v1.z()*v2.z();
	return angle;
}
GPoint3d TrackBall::crossMult(GPoint3d v1, GPoint3d v2)
{
	GPoint3d v;
	v.setX(v1.y()*v2.z() - v1.z()*v2.y());
	v.setY(v1.z()*v2.x() - v1.x()*v2.z());
	v.setZ(v1.x()*v2.y() - v1.y()*v2.x());
	return v;
}

// 将鼠标二维点映射为球面向量(用于鼠标追踪球) 
GPoint3d TrackBall::gMousePtToSphereVec(int x, int y, int w, int h)
{
	double x1, y1, z1, r, len;
	GPoint3d vec;
	x1 = (2.0*x - w) / w;
	y1 = (h - 2.0*y) / h;
	r = x1*x1 + y1*y1;
	if (r > 1) r = 1;
	z1 = sqrt(1 - r);
	len = sqrt(x1*x1 + y1*y1 + z1*z1);
	vec.setX(x1 / len);
	vec.setY(y1 / len);
	vec.setZ(z1 / len);
	return vec;
}
void TrackBall::makeRolate()
{
	glMultMatrixd(mMatrix);
}
void TrackBall::MouseMove(int x, int y)
{
	if (x != OldX || y != OldY)
	{
		int wWidth, wHeight;
		wWidth = glutGet(GLUT_WINDOW_WIDTH);
		wHeight = glutGet(GLUT_WINDOW_HEIGHT);
		GPoint3d lastVec = gMousePtToSphereVec(OldX, OldY, wWidth, wHeight);
		GPoint3d currentVec = gMousePtToSphereVec(x, y, wWidth, wHeight);
		OldX = x;        OldY = y;
		// 求旋转角度
		double rotAngle = acos(dotMult(lastVec, currentVec))*57.29577958;
		// 求旋转向量轴
		GPoint3d axis = crossMult(lastVec, currentVec);
		glMatrixMode(GL_MODELVIEW);
		glPushMatrix();
		glLoadIdentity();
		glRotated(rotAngle, axis.x(), axis.y(), axis.z()); // 旋转

		glMultMatrixd(mMatrix);
		glGetDoublev(GL_MODELVIEW_MATRIX, mMatrix);  // 返回当前模型矩阵

		glPopMatrix();
	}
}

Grids.h  绘制网格用的,可以暂时不管他

#include <iostream>

#include <cmath>

using namespace std;

class Grids
{
	int row;
	int col;
	double **mat;
public:
	Grids();
	Grids(int r, int c);
	Grids(int r, int c, double **m);
	~Grids();
	void Mul_Mat(Grids* m1, Grids* m2, Grids* m3);
	void Inv_Mat(Grids* m1, Grids* m2);
	double** Surface_Fitting(Grids* m1, Grids* m2);
};

Grids.cpp


#include "Grids.h"

Grids::Grids()
{
	row = 0;
	col = 0;
	mat = 0;
}

Grids::Grids(int r, int c)
{
	row = r;
	col = c;
	mat = 0;
}

Grids::Grids(int r, int c, double **m)
{
	row = r;
	col = c;
	mat = m;
}

Grids::~Grids()
{
	mat = 0;
	row = 0;
	col = 0;
}

void Grids::Mul_Mat(Grids* m1, Grids* m2, Grids* m3)
{
	int i = 0, j = 0, p = 0;
	double sum = 0;
	if (m1->col != m2->row) {
		cout << "\n行、列数不匹配!";
		exit(0);
	}
	m3->row = m1->row;
	m3->col = m2->col;
	m3->mat = new double*[m1->row];
	if (NULL == m3->mat) {
		cout << "ERROR!\n";
		exit(0);
	}
	for (i = 0; i < m3->row; i++) {
		m3->mat[i] = new double[m3->col];
		for (j = 0; j < m3->col; j++) {
			for (m3->mat[i][j] = 0, p = 0; p < m1->col; p++) {
				m3->mat[i][j] += m1->mat[i][p] * m2->mat[p][j];
			}
		}
	}
}

void Grids::Inv_Mat(Grids* m1, Grids* m2)
{
	int i, j, n, *is, *js, k;
	double d, p;
	if (m1->row != m1->col) {
		cout << "ERROR! 必须是方阵才能求逆!\n";
		exit(1);
	}
	m2->mat = new double*[m1->row];//申请行指针数组
	if (NULL == m2->mat) {
		cout << "ERROR! 申请内存出错!\n";
		exit(1);
	}
	for (i = 0; i < m1->row; i++) {
		m2->mat[i] = new double[m1->col];//申请行
		for (j = 0; j < m1->col; j++)
			m2->mat[i][j] = m1->mat[i][j];
	}
	n = m1->row;
	m2->row = m1->row;
	m2->col = m1->col;
	is = new int[n];
	js = new int[n];
	if (NULL == is || NULL == js) {
		cout << "ERROR! 申请内存出错!\n";
		exit(1);
	}
	for (k = 0; k <= n - 1; k++) { //全选主元
		d = 0.000;
		for (i = k; i <= n - 1; i++) {
			for (j = k; j <= n - 1; j++) {
				p = fabs(m2->mat[i][j]);
				if (p > d) {
					d = p;
					is[k] = i;
					js[k] = j;
				}
			}
		}
		if (1.0 == d + 1.0) {
			delete[]is;
			delete[]js;
			cout << "ERROR ! 矩阵求逆出错!\n";
			exit(1);
		}
		if (is[k] != k) { /*行交换*/
			for (j = 0; j <= n - 1; j++) {
				p = m2->mat[k][j];
				m2->mat[k][j] = m2->mat[is[k]][j];
				m2->mat[is[k]][j] = p;
			}
		}
		if (js[k] != k) { /*列交换*/
			for (i = 0; i <= n - 1; i++) {
				p = m2->mat[i][k];
				m2->mat[i][k] = m2->mat[i][js[k]];
				m2->mat[i][js[k]] = p;
			}
		}
		m2->mat[k][k] = 1 / m2->mat[k][k];
		for (j = 0; j <= n - 1; j++) {
			if (j != k) {
				m2->mat[k][j] = m2->mat[k][j] * m2->mat[k][k];
			}
		}
		for (i = 0; i <= n - 1; i++) {
			if (i != k) {
				for (j = 0; j <= n - 1; j++) {
					if (j != k) {
						m2->mat[i][j] = m2->mat[i][j] - m2->mat[i][k] * m2->mat[k][j];
					}
				}
			}
		}
		for (i = 0; i <= n - 1; i++) {
			if (i != k) {
				m2->mat[i][k] = -m2->mat[i][k] * m2->mat[k][k];
			}
		}
	}
	for (k = n - 1; k >= 0; k--) {
		if (js[k] != k) {
			for (j = 0; j <= n - 1; j++) {
				p = m2->mat[k][j];
				m2->mat[k][j] = m2->mat[js[k]][j];
				m2->mat[js[k]][j] = p;
			}
		}
		if (is[k] != k) {
			for (i = 0; i <= n - 1; i++) {
				p = m2->mat[i][k];
				m2->mat[i][k] = m2->mat[i][is[k]];
				m2->mat[i][is[k]] = p;
			}
		}
	}
	delete[]is;
	delete[]js;
}

double** Grids::Surface_Fitting(Grids* m1, Grids* m2)
{  // m1为已知数组R,m2为自变量数组
	int i, j;
	double ipso = 0.05;
	Grids *R = new Grids(m1->col + 3, m1->col + 3);
	R->mat = new double*[R->row];
	for (i = 0; i < R->row; i++)
		R->mat[i] = new double[R->col];
	for (i = 0; i < R->row; i++) {
		for (j = 0; j < R->col; j++) {
			if (i < m1->col&&j < m1->col) {
				if (i == j)
					R->mat[i][j] = ipso;
				else
					R->mat[i][j] = sqrt(pow(m1->mat[0][i] - m1->mat[0][j], 2) + pow(m1->mat[1][i] - m1->mat[1][j], 2));
			}
			if (i >= m1->col&&j < m1->col) {
				if (i == m1->col)
					R->mat[i][j] = 1;
				else
					R->mat[i][j] = m1->mat[i - m1->col - 1][j];
			}
			if (i < m1->col&&j >= m1->col) {
				if (j == m1->col)
					R->mat[i][j] = 1;
				else
					R->mat[i][j] = m1->mat[j - (m1->col) - 1][i];
			}
			if (i >= m1->col&&j >= m1->col) {
				R->mat[i][j] = 0;
			}
		}
	}

	Grids *z1 = new Grids(m1->col + 3, 1);
	Grids *invm1 = new Grids();
	Grids *F = new Grids();
	z1->mat = new double*[z1->row];
	for (i = 0; i < z1->row; i++) {
		z1->mat[i] = new double[z1->col];
		for (j = 0; j < z1->col; j++) {
			if (i < m1->col)
				z1->mat[i][j] = m1->mat[2][i];
			else
				z1->mat[i][j] = 0;
		}
	}
	Inv_Mat(R, invm1);

	Mul_Mat(invm1, z1, F);

	Grids *z = new Grids();
	Grids *r = new Grids(m2->col, F->row);
	r->mat = new double*[r->row];
	for (i = 0; i < r->row; i++)
		r->mat[i] = new double[r->col];
	for (i = 0; i < r->row; i++) {
		for (j = 0; j < m1->col + 3; j++) {
			if (j < m1->col) {
				double temp = sqrt(pow(m2->mat[0][i] - m1->mat[0][j], 2) + pow(m2->mat[1][i] - m1->mat[1][j], 2));
				r->mat[i][j] = temp*log(temp + ipso);
			}
			else {
				if (j == m1->col)
					r->mat[i][j] = 1;
				else
					r->mat[i][j] = m2->mat[j - m1->col - 1][i];
			}
		}
	}
	/*    FF->mat=new double*[FF->row];
	for(i=0;i<FF->row;i++)
	FF->mat[i]=new double[FF->col];
	for(i=0;i<FF->row;i++){
	for(j=0;j<FF->col;j++){
	if(i<m2->col)
	FF->mat[i][j]=F->mat[i/4][j/4];
	else
	FF->mat[i][j]=F->mat[i-m2->col+m1->col][j];
	}
	}*/
	Mul_Mat(r, F, z);

	Grids *xyz = new Grids(m2->row + 1, m2->col);
	xyz->mat = new double*[xyz->row];
	for (i = 0; i < xyz->row; i++)
		xyz->mat[i] = new double[xyz->col];
	for (i = 0; i < xyz->row; i++) {
		for (j = 0; j < xyz->col; j++) {
			if (i < m2->row)
				xyz->mat[i][j] = m2->mat[i][j];
			else
				xyz->mat[i][j] = z->mat[j][0];
		}
	}
	for (i = 0; i < R->row; i++)
		delete[] R->mat[i];
	delete[] R->mat;
	for (i = 0; i < z1->row; i++)
		delete[] z1->mat[i];
	delete[] z1->mat;
	for (i = 0; i < invm1->row; i++)
		delete[] invm1->mat[i];
	delete[] invm1->mat;
	for (i = 0; i < F->row; i++)
		delete[] F->mat[i];
	delete[] F->mat;
	for (i = 0; i < z->row; i++)
		delete[] z->mat[i];
	delete[] z->mat;
	for (i = 0; i < r->row; i++)
		delete[] r->mat[i];
	delete[] r->mat;
	return xyz->mat;
}

3dmap.h  主要是模拟点的,与烟雾无关,也可以不用管它

class _3dMap
{
	double **data;
	int M, N;
	int dip;
	double scale;
	bool showBaseLine;
	double max, min;
	bool LineMode;
public:
	_3dMap();
	~_3dMap();

	void initMap();
	void drawBaseLine();
	void showColorStrip();
	void drawMap();
	//void _3dMap::setLineOrFill();
	void setLineOrFill();
	double getAver(double * arr);
	void setColor(double z1, double z2, double z3);
};



3dmap.cpp


#include "3dmap.h"
#include "Grids.h"
#include "GL/glut.h"

_3dMap::_3dMap()
{
	M = 320;
	N = 220;
	showBaseLine = true;
	LineMode = false;
	scale = 20.0;
	dip = 1;
	max = -1000;
	min = 10000;
}

_3dMap::~_3dMap() 
{

}



void _3dMap::setLineOrFill()
{
	LineMode = !LineMode;
}

double _3dMap::getAver(double * arr)
{
	double num = 0;
	int n = 3;//(int)(sizeof(arr)/sizeof(double))/3;
	for (int i = 0; i < n; i++)
		num += arr[3 * i + 2];
	return num / n;
}

void _3dMap::setColor(double z1, double z2, double z3)
{
	float r, g, b;
	double temp = (max + min) / 2;
	double aver = (z1 + z2 + z3) / 3;
	/*printf("%lf  ",aver);*/
	if (aver > temp)
	{
		r = (aver - temp) / (temp - min);
		b = 0;
	}
	else {
		r = 0;
		b = (temp - aver) / (temp - min);
	}
	g = 1 - ((abs(temp - aver)) / (temp - min));
	glColor3f(r, g, b);
}


void _3dMap::initMap()
{

	int temp[] = {
		229,219,199,216,235,255,266,285,272,241,246,281,284,275,261,273,
		221,214,195,216,234,258,273,289,281,249,259,278,287,272,275,277,
		213,203,196,206,221,232,259,293,294,277,258,285,287,283,288,286,
		204,195,200,201,209,218,231,259,288,306,286,291,301,311,319,298,
		196,207,201,211,239,234,241,259,294,315,317,321,325,322,325,341,
		208,218,204,214,235,260,239,268,298,291,331,313,281,280,280,280,
		216,231,218,196,220,255,271,253,264,303,322,312,276,243,238,239,
		236,242,218,198,200,215,224,238,261,294,324,312,280,255,220,200,
		255,241,219,211,206,225,252,275,284,285,305,316,271,237,208,191,
		245,218,207,198,214,241,261,256,273,276,291,298,281,238,197,175,
		225,215,205,195,208,221,235,252,262,271,301,275,245,212,181,171
	};
	int len = 11 * 16;
	int i, j;
	double** src = new double*[3];
	for (i = 0; i < 3; i++)
		src[i] = new double[len];
	for (i = 0; i < 11; i++)
	{//y
		for (j = 0; j < 16; j++)
		{//x
			src[0][i * 16 + j] = j * 10;
			src[1][i * 16 + j] = i * 10;
			src[2][i * 16 + j] = temp[i * 16 + j];
		}
	}
	Grids g1(3, len, src);
	double** des = new double*[2];
	for (i = 0; i < 2; i++)
		des[i] = new double[N*M];
	for (i = 0; i < N; i++)
	{//y
		for (j = 0; j < M; j++)
		{//x
			des[0][i*M + j] = j / 2;
			des[1][i*M + j] = i / 2;
		}
	}
	Grids g2(2, N*M, des);
	data = g1.Surface_Fitting(&g1, &g2);

	for (i = 0; i < N; i++)
	{//height
		for (int j = 0; j < M; j++)
		{//width
			data[0][i*M + j] *= 2;
			data[1][i*M + j] *= 2;
			data[2][i*M + j] /= 5;

			if (max < data[2][i*M + j])
				max = data[2][i*M + j];
			if (min > data[2][i*M + j])
				min = data[2][i*M + j];
		}
	}
	printf("max=%lf,min=%lf\n", max, min);
}
void _3dMap::drawBaseLine()
{
	glColor3f(0.0f, 0.0f, 1.0f);//指定线的颜色,蓝色

	glLineWidth(4);
	glBegin(GL_LINES);
	{
		// x-axis

		glVertex3f(0.0f, 0.0f, 0.0f);
		glVertex3f(410.0f, 0.0f, 0.0f);

		// x-axis arrow

		glVertex3f(410.0f, 0.0f, 0.0f);
		glVertex3f(400.0f, 6.0f, 0.0f);
		glVertex3f(410.0f, 0.0f, 0.0f);
		glVertex3f(400.0f, -6.0f, 0.0f);
	}
	glEnd();

	glColor3f(0.0f, 1.0f, 0.0f);//指定线的颜色,绿色

	glBegin(GL_LINES);
	{
		// y-axis

		glVertex3f(0.0f, 0.0f, 0.0f);
		glVertex3f(0.0f, 410.0f, 0.0f);

		glVertex3f(0.0f, 410.0f, 0.0f);
		glVertex3f(6.0f, 400.0f, 0.0f);
		glVertex3f(0.0f, 410.0f, 0.0f);
		glVertex3f(-6.0f, 400.0f, 0.0f);
	}
	glEnd();


	glColor3f(1.0f, 0.0f, 0.0f);//指定线的颜色,红色

	glBegin(GL_LINES);
	{
		// z-axis

		glVertex3f(0.0f, 0.0f, 0.0f);
		glVertex3f(0.0f, 0.0f, 410.0f);
		glVertex3f(0.0f, 0.0f, 410.0f);
		glVertex3f(0.0f, 6.0f, 400.0f);
		glVertex3f(0.0f, 0.0f, 410.0f);
		glVertex3f(0.0f, -6.0f, 400.0f);
	}
	glEnd();


	//绘制y-z平面表格
	glColor3f((GLfloat)216.0f / 255.0f, (GLfloat)191.0f / 255.0f, (GLfloat)216.0f / 255.0f);//指定线的颜色,蓝色
	//glColor3f(0.0f, 0.0f, 0.13f);
	glLineWidth(2);
	glBegin(GL_LINES);
	{
		for (int i = 1; i <= 400; i += 40)
		{
			glVertex3f(0.0f, 370.0f, i*1.0f);  //纵向
			glVertex3f(0.0f, 0.0f, i*1.0f);

			glVertex3f(0.0f, i*1.0f, 370.0f);  //横向
			glVertex3f(0.0f, i*1.0f, 0.0f);
		}
	}
	glEnd();

	//x-y平面表格
	glBegin(GL_LINES);
	{
		for (int i = 1; i <= 400; i += 40)
		{
			glVertex3f(i*1.0f, 370.0f, 0.0f);  //纵向
			glVertex3f(i*1.0f, 0.0f, 0.0f);

			glVertex3f(0.0f, i*1.0f, 0.0f);  //横向
			glVertex3f(370.0f, i*1.0f, 0.0f);
		}
	}
	glEnd();


	//x-z平面表格
	glBegin(GL_LINES);
	{
		for (int i = 1; i <= 400; i += 40)
		{
			glVertex3f(370.0f, 0.0f, i*1.0f);
			glVertex3f(0.0f, 0.0f, i*1.0f);

			glVertex3f(i*1.0f, 0.0f, 0.0f);  //横向
			glVertex3f(i*1.0f, 0.0f, 370.0f);
		}
	}
	glEnd();
}

void _3dMap::showColorStrip()
{
	GLint width = 200;
	GLint height = 10;

	GLsizei dw;
	int n, i;
	dw = 2;
	n = (width - 1) / dw;
	//cout << "n=" << n << endl;
	//glClear(GL_COLOR_BUFFER_BIT);
	GLsizei r, g, b;
	for (i = 0; i < n; i++)
	{
		//绘制应力云图的关键就是下面的这五种不同的颜色对应关系
		//根据自己需要可以设置不同的等级,四种也是可以的
		if (i >= 0 && i <= n / 5)
		{
			r = 255;
			g = i * 255 / (n / 5);
			b = 0;
		}
		else if (i > n / 5 && i <= 2 * n / 5)
		{
			r = 255 - (i - n / 5) * 255 / (n / 5);
			g = 255;
			b = 0;
		}
		else if (i > 2 * n / 5 && i <= 3 * n / 5)
		{
			r = 0;
			g = 255;
			b = (i - 2 * n / 5) * 255 / (n / 5);
		}
		else if (i > 3 * n / 5 && i <= 4 * n / 5)
		{
			r = 0;
			g = 255 - (i - 3 * n / 5) * 255 / (n / 5);
			b = 255;
		}
		else
		{
			r = (i - 4 * n / 5) * 255 / (n / 5);
			g = 0;
			b = 255;
		}
		glColor3f(r / 255.0f, g / 255.0f, b / 255.0f);
		glRectf(1.0*i*dw, 0.0, 1.0*(i + 1)*dw, height);
	}

	
	glFlush();
}
void _3dMap::drawMap()
{

	if (showBaseLine)
		drawBaseLine();

	if (LineMode)
		glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
	else
		glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);

	glLineWidth(0.4f);
	for (int i = 0; i < N - 1; i++)
	{//height22

		for (int j = 0; j < M - 1; j++)
		{//width32
			glBegin(GL_TRIANGLE_FAN);
			int t = i*M + j;
			setColor(data[2][t], data[2][t + 1], data[2][t + 1 + M]);

			glVertex3f(data[0][t], data[1][t], data[2][t]);
			glVertex3f(data[0][t + 1], data[1][t + 1], data[2][t + 1]);
			glVertex3f(data[0][t + 1 + M], data[1][t + 1 + M], data[2][t + 1 + M]);
			setColor(data[2][t + M], data[2][t + 1], data[2][t + 1 + M]);
			glVertex3f(data[0][t + M], data[1][t + M], data[2][t + M]);
			glEnd();
		}
	}
}

xFreeTypeLib.h   这时渲染三维字体用的,也可以不用管它

#ifndef _X_FREE_TYPE_LIB_H_
#define _X_FREE_TYPE_LIB_H_
#endif  //_X_FREE_TYPE_LIB_H_


#include <Windows.h>  
#include <iostream>  
#include "Gl\GL.h" 
#include "Gl\glut.h"    
#include "ft2build.h"  
#include "freetype/freetype.h"  
#include "freetype/ftglyph.h" 
#include "freetype/ftoutln.h"  
#include "freetype/fttrigon.h"  

#define MAX_NO_TEXTURES 1  

#define CUBE_TEXTURE 0  

//GLuint texture_id[MAX_NO_TEXTURES];

typedef struct xCharTexture
{
	GLuint  m_texID;
	wchar_t m_chaID;
	int     m_Width;
	int     m_Height;

	int     m_adv_x;
	int     m_adv_y;
	int     m_delta_x;
	int     m_delta_y;
public:
	xCharTexture()
	{
		m_texID = 0;
		m_chaID = 0;
		m_Width = 0;
		m_Height = 0;
	}
}stuxCharTexture;
/*g_TexID[65536];*/

class xFreeTypeLib
{
	FT_Library m_FT2Lib;
	FT_Face    m_FT_Face;

public:
	int   m_w;
	int   m_h;
	void load(const char* font_file, int _w, int _h);
	GLuint loadChar(wchar_t ch);
};

xFreeTypeLib.cpp


#include "xFreeTypeLib.h"

stuxCharTexture g_TexID[65536];

void xFreeTypeLib::load(const char* font_file, int _w, int _h)
{
	FT_Library library;
	if (FT_Init_FreeType(&library))
		exit(0);
	//加载一个字体,取默认的Face,一般为Regualer  
	if (FT_New_Face(library, font_file, 0, &m_FT_Face))
		exit(0);
	//选择字符表  
	FT_Select_Charmap(m_FT_Face, FT_ENCODING_UNICODE);
	m_w = _w; m_h = _h;
	m_FT_Face->num_fixed_sizes;
	//大小要乘64.这是规定。照做就可以了。  
	//FT_Set_Char_Size( m_FT_Face , 0 , m_w << 6, 96, 96);  
	//用来存放指定字符宽度和高度的特定数据  
	FT_Set_Pixel_Sizes(m_FT_Face, m_w, m_h);
}

GLuint xFreeTypeLib::loadChar(wchar_t ch)
{
	if (g_TexID[ch].m_texID)
		return g_TexID[ch].m_texID;
	/* 装载字形图像到字形槽(将会抹掉先前的字形图像) */
	if (FT_Load_Char(m_FT_Face, ch, /*FT_LOAD_RENDER|*/FT_LOAD_FORCE_AUTOHINT |
		(TRUE ? FT_LOAD_TARGET_NORMAL : FT_LOAD_MONOCHROME | FT_LOAD_TARGET_MONO)))
	{
		return 0;
	}

	/*if(FT_Load_Glyph( m_FT_Face, FT_Get_Char_Index( m_FT_Face, ch ), FT_LOAD_FORCE_AUTOHINT ))
	throw std::runtime_error("FT_Load_Glyph failed");*/

	xCharTexture& charTex = g_TexID[ch];

	//得到字模  
	FT_Glyph glyph;
	//把字形图像从字形槽复制到新的FT_Glyph对象glyph中。这个函数返回一个错误码并且设置glyph。   
	if (FT_Get_Glyph(m_FT_Face->glyph, &glyph))
		return 0;

	//转化成位图  
	FT_Render_Glyph(m_FT_Face->glyph, FT_RENDER_MODE_LCD);//FT_RENDER_MODE_NORMAL  );   
	FT_Glyph_To_Bitmap(&glyph, ft_render_mode_normal, 0, 1);
	FT_BitmapGlyph bitmap_glyph = (FT_BitmapGlyph)glyph;

	//取道位图数据  
	FT_Bitmap& bitmap = bitmap_glyph->bitmap;

	//把位图数据拷贝自己定义的数据区里.这样旧可以画到需要的东西上面了。  
	int width = bitmap.width;
	int height = bitmap.rows;

	m_FT_Face->size->metrics.y_ppem;      //伸缩距离到设备空间  
	m_FT_Face->glyph->metrics.horiAdvance;  //水平文本排列  


	charTex.m_Width = width;
	charTex.m_Height = height;
	charTex.m_adv_x = m_FT_Face->glyph->advance.x / 64.0f;  //步进宽度  
	charTex.m_adv_y = m_FT_Face->size->metrics.y_ppem;        //m_FT_Face->glyph->metrics.horiBearingY / 64.0f;  
	charTex.m_delta_x = (float)bitmap_glyph->left;           //left:字形原点(0,0)到字形位图最左边象素的水平距离.它以整数象素的形式表示。   
	charTex.m_delta_y = (float)bitmap_glyph->top - height;   //Top: 类似于字形槽的bitmap_top字段。  
	glGenTextures(1, &charTex.m_texID);
	glBindTexture(GL_TEXTURE_2D, charTex.m_texID);
	char* pBuf = new char[width * height * 4];
	for (int j = 0; j < height; j++)
	{
		for (int i = 0; i < width; i++)
		{
			unsigned char _vl = (i >= bitmap.width || j >= bitmap.rows) ? 0 : bitmap.buffer[i + bitmap.width*j];
			pBuf[(4 * i + (height - j - 1) * width * 4)] = 0xFF;
			pBuf[(4 * i + (height - j - 1) * width * 4) + 1] = 0xFF;
			pBuf[(4 * i + (height - j - 1) * width * 4) + 2] = 0xFF;
			pBuf[(4 * i + (height - j - 1) * width * 4) + 3] = _vl;
		}
	}

	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pBuf);  //指定一个二维的纹理图片  
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);                            //glTexParameteri():纹理过滤  
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
	glTexEnvi(GL_TEXTURE_2D, GL_TEXTURE_ENV_MODE, GL_REPLACE);                                //纹理进行混合  

	/*gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pBuf);
	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S, GL_CLAMP);
	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T, GL_CLAMP);
	glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
	glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
	glTexEnvi(GL_TEXTURE_2D,GL_TEXTURE_ENV_MODE,GL_REPLACE);*/
	delete[] pBuf;
	return charTex.m_chaID;
}

main.cpp

// SmokeSimulate.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
// 包含有关OpenGL函数的头文件
//#include "GL/GL.H"
//#include "GL/GLU.h"
//#include "GL/GLAUX.H"
//#include "GL/glut.h"
//#include <iostream>

//#include <iostream>
//#include <Windows.h>  
#include "tools.h"
#include "Grids.h"
#include "3dmap.h"
#include "xFreeTypeLib.h"
#include "glm/glm.hpp"
#include "glm/gtc/matrix_transform.hpp"
#include "glm/gtc/type_ptr.hpp"

#define SMOKEX 32
#define SMOKEY 32

typedef struct {
	float r;
	float g;
	float b;
} COL;

/
bool RenderScene();
int InitGL(GLvoid);
void Fuoco(void);
void ShowSmoke(float x, float y, float z, float dim);
COL Colore(float k);

bool    freeze;
int     frame;
GLuint	Texture[1];
unsigned char Bsmoke[SMOKEX][SMOKEY];

int xFar = 0.0f, yFar = 0.0f, zFar = 0.0f;
int wWidth = 1366, wHeight = 768;
int oldX, oldY;
bool gIsStartTrackBall = false;
bool gIsMoveMap = false;
TrackBall trackball;
_3dMap map;

xFreeTypeLib g_FreeTypeLib;
float ratio;
//wchar_t g_UnicodeString[]=L"aaabb/x4E2D/x6587/x0031/x0032/x0033";    
const char g_UnicodeString[] = "0     1      2      3     4      5     6  时间(天)\" ";
const char g_UnicodeStringScript[] = "-10   0     10      20      30     40      50  \" ";
const char g_UnicodeStringScriptHz[] = "0       1000        2000         3000       4000        5000  频率(MHz)\" ";
const char g_UnicodeStringScriptLevel[] = "0    1000    2000    3000   4000   5000  能量电平(Db)\" ";


extern stuxCharTexture g_TexID[65536];


LPWSTR AnsiToUnicode(LPCSTR lpcstr);
void drawText(wchar_t* _strText, int x, int y, int maxW, int h);

void displayEvent()
{
	//glClearColor(0.0f, 0.0f, 0.1f, 0.5f);
	//glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	//glMatrixMode(GL_MODELVIEW);
	//glLoadIdentity();

	//glPushMatrix();
	//glTranslatef(-200.0f, 50.0f, -400.0f);
	//glRotatef(-45.0f, 0.0f, 1.0f, 0.0f);
	//glTranslatef(xFar, yFar, zFar);
	//trackball.makeRolate();
	//map.drawMap();

	时间
	//glTranslatef(0.0f, 0.0f, 390.0f);
	//glRotatef(90.0f, 1.0f, 0.0f, 0.0f);
	//wchar_t *wstr = AnsiToUnicode(g_UnicodeString);
	//drawText(wstr, 0, -10, 900, 25);  //什么变成透明模式

	频率
	//glTranslatef(320.0f, 0.0f, 0.0f);
	//glRotatef(-90.0f, 0.0f, 0.0f, 1.0f);
	//wchar_t *wstrScriptHz = AnsiToUnicode(g_UnicodeStringScriptHz);
	//drawText(wstrScriptHz, 10, 90, 900, 25);  //什么变成透明模式

	能量电平
	频率
	//glTranslatef(0.0f, -420.0f, 30.0f);
	//glRotatef(90.0f, 0.0f, 1.0f, 0.0f);
	glRotatef(90.0f, 0.0f, 1.0f, 1.0f);
	//wchar_t *wstrScriptLevel = AnsiToUnicode(g_UnicodeStringScriptLevel);
	//drawText(wstrScriptLevel, 10, 90, 900, 25);  //什么变成透明模式

	//glPopMatrix();
	//glEnable(GL_TEXTURE_2D);
	glDisable(GL_TEXTURE_2D);   //关闭字形纹理

	//map.showColorStrip();

	//glPushMatrix();
	//glTranslatef(0.0f, 80.0f, 0.0f);
	//glRotatef(-150.0f, 1.0f, 0.0f, 0.0f);
	//wchar_t *wstrScript = AnsiToUnicode(g_UnicodeStringScript);
	//drawText(wstrScript, 10, 90, 900, 25);  //什么变成透明模式



	//glPopMatrix();


	//烟雾相关
	RenderScene();


	//glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	//glLoadIdentity();
	//frame++;
	//frame = frame % 2;
	//if (frame == 0)
	//{
	//	if (freeze == false)
	//		Fuoco();	// 生成烟雾
	//}
	//glTranslatef(0.1f, 0.0f, -2.7f);
	//ShowSmoke(0, 0, 0, (float)0.2);		// 显示烟雾


	glFlush();
	glutSwapBuffers();  // 交换缓存 
}

void mouseMoveEvent(int x, int y)
{
	if (gIsStartTrackBall)
	{
		trackball.MouseMove(x, y);
		//glutPostRedisplay();
	}
	if (gIsMoveMap)
	{
		xFar -= oldX - x;
		yFar += oldY - y;
		oldX = x;
		oldY = y;
		//glutPostRedisplay();
	}
}
// 鼠标事件函数 
void mouseEvent(int button, int state, int x, int y)
{
	if (state == GLUT_UP && button == GLUT_WHEEL_UP)  //鼠标滚轮
	{
		zFar -= 80;
		glutPostRedisplay();
	}
	if (state == GLUT_UP && button == GLUT_WHEEL_DOWN)
	{
		zFar += 80;
		glutPostRedisplay();
	}


	if (button == GLUT_LEFT_BUTTON)
	{
		if (state == GLUT_DOWN)
		{
			oldX = x;
			oldY = y;
			trackball.setXY(x, y);
			gIsStartTrackBall = true;
		}
		else if (state == GLUT_UP)
		{
			oldX = x;
			oldY = y;
			gIsStartTrackBall = false;
		}
		glutPostRedisplay();
	}
	else if (button == GLUT_RIGHT_BUTTON)
	{
		if (state == GLUT_DOWN)
		{
			oldX = x;
			oldY = y;
			gIsMoveMap = true;
		}
		else if (state == GLUT_UP)
		{
			oldX = x;
			oldY = y;
			gIsMoveMap = false;
		}
	}
}
// 窗体尺寸变化事件 
void resizeEvent(int w, int h)
{
	//wWidth = w;
	//wHeight = h;
	//zFar = 0.0f;
	//xFar = 0.0f;
	//yFar = 0.0f;
	//glViewport(0, 0, w, h);
	//glMatrixMode(GL_PROJECTION);
	//glLoadIdentity();
	//h = h > 0 ? h : 1;
	//float aspect = (float)w / (float)h;
	//gluPerspective(45, aspect, 0.001, 15000.0);
	//glTranslatef(200, -190, -550.0f);
	glRotatef(-90.0f, 0.0f, 0.0f, 1.0f);
	//trackball.resize();



	/
//添加窗口缩放时的图形变换函数
	glViewport(0, 0, w, h);
	/
	glMatrixMode(GL_PROJECTION);	// 选择投影矩阵
	glLoadIdentity();				// 设置投影矩阵
	// 根据窗口的比例设置变换
	gluPerspective(45.0f, (GLfloat)w / (GLfloat)h, 0.1f, 100.0f);
	glMatrixMode(GL_MODELVIEW);		// 选择模型矩阵
	glLoadIdentity();				// 设置模型矩阵

	glutPostRedisplay();

}
void processSpecialKeys(int key, int x, int y) {
	if (key == 101)
	{
		zFar += 4;
		glutPostRedisplay();
	}
	if (key == 103)
	{//
		zFar -= 4;
		glutPostRedisplay();
	}
	printf("key:%d\n", key);
}

void MenuFunc(int data)
{
	switch (data)
	{
	case 1:
		map.setLineOrFill(); break;
	default:break;
	}
	glutPostRedisplay();
}
void glInit()
{
	glShadeModel(GL_FLAT);//SMOOTH//GL_FLAT
	glClearColor(1.0f, 1.0f, 1.0f, 0.5f);
	glClearDepth(1.0f);

	glEnable(GL_NORMALIZE);

	glEnable(GL_DEPTH_TEST);
	glAlphaFunc(GL_GREATER, 0);
	glDepthFunc(GL_LEQUAL);
	glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);

	/*glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);*/

	glEnable(GL_POINT_SMOOTH);
	glEnable(GL_LINE_SMOOTH);
	glEnable(GL_POLYGON_SMOOTH);

	glHint(GL_POINT_SMOOTH_HINT, GL_NICEST); // Make round points, not square points
	glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);  // Antialias the lines
	glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);


	//glClearColor(1.0f,1.0f,1.0f,0.5f);  //窗口背景设置为白色
	glMatrixMode(GL_MODELVIEW); //设置投影参数

	glEnable(GL_COLOR_MATERIAL);
	glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);

	//g_FreeTypeLib.load("simhei.ttf",14,14);  
	// g_FreeTypeLib.load("c://windows//fonts//simhei.ttf",14,14);  
	g_FreeTypeLib.load("c://windows//fonts//simhei.ttf", 12, 12);

	//烟雾
	InitGL();

	//glDisable(GL_CULL_FACE);

	//glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);  

}

xCharTexture* getTextChar(wchar_t ch)
{
	g_FreeTypeLib.loadChar(ch);
	return &g_TexID[ch];
}

LPWSTR AnsiToUnicode(LPCSTR lpcstr)   //参数lpcstr类型也可是char*  
{
	LPWSTR Pwstr;
	int  i;
	i = MultiByteToWideChar(CP_ACP, 0, lpcstr, -1, NULL, 0);
	Pwstr = new WCHAR[i];
	MultiByteToWideChar(CP_ACP, 0, lpcstr, -1, Pwstr, i);

	return (Pwstr);
}




void drawText(wchar_t* _strText, int x, int y, int maxW, int h)
{
	int sx = x;
	int sy = y;
	int maxH = h;
	size_t nLen = wcslen(_strText);

	for (int i = 0; i < nLen; i++)
	{
		if (_strText[i] == '/n')
		{
			sx = x; sy += maxH + 12;
			continue;
		}
		xCharTexture* pCharTex = getTextChar(_strText[i]);
		glBindTexture(GL_TEXTURE_2D, pCharTex->m_texID);                          //绑定到目标纹理  
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_LINEAR);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_LINEAR);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
		glEnable(GL_BLEND);
		glDepthMask(GL_TRUE);//打开或关闭OpenGL的特殊功能  
		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);  //特殊的像素算法  
		//glBlendFunc(GL_ONE, GL_ZERO);
		glEnable(GL_TEXTURE_2D);    //去透明
		int w = pCharTex->m_Width;
		int h = pCharTex->m_Height;

		int ch_x = sx + pCharTex->m_delta_x;
		int ch_y = sy - h - pCharTex->m_delta_y;

		if (maxH < h) maxH = h;
		glBegin(GL_QUADS);                                                    // 定义一个或一组原始的顶点  
		{
			glTexCoord2f(0.0f, 1.0f); glVertex3f(ch_x, ch_y, 1.0f);
			glTexCoord2f(1.0f, 1.0f); glVertex3f(ch_x + w, ch_y, 1.0f);
			glTexCoord2f(1.0f, 0.0f); glVertex3f(ch_x + w, ch_y + h, 1.0f);
			glTexCoord2f(0.0f, 0.0f); glVertex3f(ch_x, ch_y + h, 1.0f);
		}
		glEnd();
		sx += pCharTex->m_adv_x;
		if (sx > x + maxW)
		{
			sx = x; sy += maxH + 12;
		}
	}
}


//
//						场景绘制与渲染
//
bool RenderScene()
{
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glLoadIdentity();
	frame++;
	frame = frame % 2;
	if (frame == 0)
	{
		if (freeze == false)
			Fuoco();	// 生成烟雾
	}
	glTranslatef(0.1f, 0.0f, -2.7f);
	ShowSmoke(0, 0, 0, (float)0.2);		// 显示烟雾

	//::SwapBuffers(m_pDC->GetSafeHdc());		// 交互缓冲区
	//glFlush();
	//glutSwapBuffers();  // 交换缓存 

	glutPostRedisplay();
	return true;
}


COL Colore(float k)
{
	COL c;
	//	if( k<64 )
	//	{
	//		c.r=k/64;
	//		c.g=k/64;
	//		c.b=k/64;
	//	}
	//	else
	//	{
	if (k < 128)
	{
		c.r = k / 128;
		c.g = k / 128;
		c.b = k / 128;
	}
	else
	{
		if (k < 192)
		{
			c.r = k / 256;
			c.g = k / 256;
			c.b = k / 256;
		}
		else
		{
			c.r = 1;
			c.g = 1;
			c.b = 1;
		}
	}
	//	}
	return(c);
}

void ShowSmoke(float x, float y, float z, float dim)
{
	float xi, yi;
	float ka, kb, kc, kd;
	COL col;
	int xd, yd;

	yi = y + dim * SMOKEY / 2;

	for (yd = 0; yd < SMOKEY - 1; yd++)
	{
		xi = x - dim * SMOKEX / 2;
		for (xd = 1; xd < SMOKEX - 1; xd++)
		{
			ka = (float)Bsmoke[xd][yd];
			kb = (float)Bsmoke[xd + 1][yd];
			kc = (float)Bsmoke[xd + 1][yd + 1];
			kd = (float)Bsmoke[xd][yd + 1];

			glBegin(GL_QUADS);		// 绘制四边形
			col = Colore(kd);
			glColor3f(col.r, col.g, col.b);
			glVertex3f(xi, yi, z);
			col = Colore(kc);
			glColor3f(col.r, col.g, col.b);
			glVertex3f(xi + dim, yi, z);
			col = Colore(kb);
			glColor3f(col.r, col.g, col.b);
			glVertex3f(xi + dim, yi + dim, z);
			col = Colore(ka);
			glColor3f(col.r, col.g, col.b);
			glVertex3f(xi, yi + dim, z);
			glEnd();
			xi += dim;
		}
		yi -= dim;
	}
}

void Fuoco(void)
{
	int x, y;
	int k;

	for (x = 8; x < SMOKEX - 8; x++)
		Bsmoke[x][SMOKEY - 1] = rand() % 192;

	for (x = 0; x < 5; x++)
		Bsmoke[rand() % SMOKEX][SMOKEY - 1] = 0;

	for (y = 0; y < SMOKEY - 1; y++)
	{
		for (x = 1; x < SMOKEX - 1; x++)
		{
			k = Bsmoke[x][y] + Bsmoke[x - 1][y + 1] + Bsmoke[x + 1][y + 1] + Bsmoke[x][y + 1];
			k = k / 4 - 2;
			if (k < 0)
				k = 0;
			Bsmoke[x][y] = (unsigned char)k;
		}
	}
}

int InitGL(GLvoid)
{
	glShadeModel(GL_SMOOTH);
	glClearColor(0.0f, 0.0f, 0.0f, 0.5f);
	glClearDepth(1.0f);
	glEnable(GL_DEPTH_TEST);
	glDepthFunc(GL_LEQUAL);
	glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);

	for (int y = 0; y < SMOKEY; y++)
	{
		for (int x = 0; x < SMOKEX; x++)
			Bsmoke[x][y] = 0;
	}

	freeze = false;
	frame = 0;
	return TRUE;
}


int main(int argc, char* argv[])
{
	//ANSI字符串,内容长度7字节     
	char sz[20] = "中文123";

	//UNICODE字符串,内容长度5个wchar_t(10字节)     
	wchar_t   wsz[100] = L"/x4E2D/x6587/x0031/x0032/x0033";
	//运行时设定当前ANSI编码,VC格式     
	setlocale(LC_ALL, ".936");

	//GCC中格式     
	setlocale(LC_ALL, "zh_CN.GBK");

	//VisualC++中使用小写%s,按照setlocale指定编码输出到文件     
	//GCC中使用大写%S     


	//把UNICODE字符串按照setlocale指定的编码转换成字节     
	wcstombs(sz, wsz, 20);
	//把字节串按照setlocale指定的编码转换成UNICODE字符串     
	mbstowcs(wsz, sz, 20);

	map.initMap();

	glutInit(&argc, argv);                                             //初始化GLUT
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH | GLUT_MULTISAMPLE);  //设置显示模式
	glutInitWindowPosition(0, 0);  //设置显示窗口的左上角位置
	glutInitWindowSize(wWidth, wHeight);         //设置窗口的长和高
	glutCreateWindow("3DMap");     //创造显示窗口

	glInit();                                       //开始初始化过程

	int main_version, sub_version, release_version;
	const char* version = (const char*)glGetString(GL_VERSION);
	sscanf(version, "%d.%d.%d", &main_version, &sub_version, &release_version);
	printf("OpenGL 版本:%s\n", version);
	printf("主版本号:%d\n", main_version);
	printf("次版本号:%d\n", sub_version);
	printf("发行版本号:%d\n", release_version);


	glutReshapeFunc(resizeEvent);
	glutDisplayFunc(displayEvent);
	glutMouseFunc(mouseEvent);
	glutSpecialFunc(processSpecialKeys);
	glutMotionFunc(mouseMoveEvent);
	glutCreateMenu(MenuFunc);
	glutAddMenuEntry("填充/网格", 1);
	glutAttachMenu(GLUT_MIDDLE_BUTTON);

	glutMainLoop();    //显示所有并等候

	getchar();
	return 0;
}

工程源码下载地址

  • 1
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值