火焰效果模拟程序
2012-1-21 ~ 2021-4-3
(0)
模拟火焰效果的程序。
执行效果抓图如下:
通过修改色系,本程序可以实现红色火焰、蓝色火焰、绿色火焰三种效果,在 InitFire() 函数中取消相应行注释可以实现不同色系的火焰效果。
完整的源代码如下:
///////////////////////////////////////////////////
// 程序名称:火焰模拟程序
// 编译环境:VC6.0 / VC2010,EasyX_20200727
// 作 者:yangw80 <yw80@qq.com>
// 最后修改:2012-1-21
// PS: 核心算法参考的微软范例,在此感谢。
//
#include <graphics.h>
#include <conio.h>
#include <time.h>
// 宏常量
#define WIDTH 640
#define HEIGHT 480
#define FIREWIDTH 320
#define FIREHEIGHT 180
// 全局变量
COLORREF g_Colors[193]; // 火焰色系中使用的全部颜色
BYTE g_Fire[FIREWIDTH]; // 火焰数据
BYTE g_Bits[FIREHEIGHT * FIREWIDTH]; // 火焰数据
// 火焰属性
int m_nDecay = 5; // 衰减度,范围 [1, 100],默认 5
int m_nFlammability = 385; // 易燃性,范围 [1, 399],默认 385
int m_nMaxHeat = 192; // 最高热度,范围 [0, 192],默认 192
int m_nSpreadRate = 20; // 传播速率,范围 [1, 100],默认 20
int m_nSize = 160; // 火源宽度,范围 [40, FIREWIDTH],默认 160
int m_nSmoothness = 1; // 平滑度,范围 [0, 5],默认 1
int m_nDistribution = 1; // 分布,范围 [0, 10],默认 1
int m_nChaos = 50; // 混沌,范围 [1, 100],默认 50
// 初始化火焰
void InitFire()
{
// 初始化颜色
int r, g, b;
// 默认红色火焰。根据注释选择不同的火焰效果
b = 256+256+255; g = 256+255; r = 255; // 红色火焰
// r = 256+256+255; g = 256+255; b = 255; // 蓝色火焰
// g = 256+256+255; b = 256+255; r = 255; // 绿色火焰
// 生成火焰色系
for(int i = 192; i >= 0; i--)
{
g_Colors[i] = RGB((r > 255) ? 255 : r, (g > 255) ? 255 : g, (b > 255) ? 255 : b);
r = (r > 3) ? (r - 4) : 0;
g = (g > 3) ? (g - 4) : 0;
b = (b > 3) ? (b - 4) : 0;
}
// 置空火焰数组
memset(g_Fire, 0, FIREWIDTH);
memset(g_Bits, 0, FIREWIDTH * FIREHEIGHT);
}
// 画色系
void DrawColorScheme()
{
POINT s[8] = { {0, 450}, {580, 450}, {580, 420}, {610, 420},
{610, 0}, {639, 0}, {639, 479}, {0, 479} };
HRGN rgn1 = CreatePolygonRgn(s, 8, WINDING);
HRGN rgn2 = CreateEllipticRgn(550, 390, 611, 451);
CombineRgn(rgn1, rgn1, rgn2, RGN_DIFF);
// 定义裁剪区域
setcliprgn(rgn1); // 设置区域 rgn 为裁剪区
DeleteObject(rgn1);
DeleteObject(rgn2);
// 画色系
int c, x, y;
for (int i = 0; i < 1120; i++)
{
c = int(i / 5.8);
x = (i <= 479 ? 639 : 639 - i + 479);
y = (i <= 479 ? i : 479);
setcolor(BGR(g_Colors[c]));
line(0, 0, x, y);
}
// 取消裁剪区域
setcliprgn(NULL);
}
// 计算火焰的每个点
inline void BurnPoint(BYTE* pRow, BYTE* pNextRow)
{
BYTE* pTarget;
int off = rand() % (m_nDistribution + 1);
int val = m_nDecay + 1;
val = rand() % val;
val = *pNextRow - val;
pTarget = (rand() & 1) ? pRow + off : pRow - off;
*pTarget = (val > 0) ? (BYTE)val : 0;
}
// 计算火焰
void RenderFlame()
{
int xStart, xEnd, x, y;
BYTE* pRow;
BYTE* pNextRow;
xStart = (FIREWIDTH - m_nSize) / 2;
xEnd = xStart + m_nSize + 1;
pRow = g_Bits;
for (x = 0; x < FIREWIDTH; x++)
{
if (x < (xStart + m_nDistribution) || x >= (xEnd - m_nDistribution))
g_Fire[x] = 0;
*pRow++ = g_Fire[x];
}
for (y = FIREHEIGHT - 1; y > 0; y--) // y = 0 火焰最大;y++ 火焰变小
{
pRow = (g_Bits + FIREWIDTH * y);
pNextRow = (g_Bits + FIREWIDTH * (y - 1));
if (rand() & 1)
{
for (x = 0; x < FIREWIDTH; x++)
{
BurnPoint(pRow, pNextRow);
pRow++;
pNextRow++;
}
}
else
{
pRow += FIREWIDTH - 1;
pNextRow += FIREWIDTH - 1;
for (x = 0; x < FIREWIDTH; x++)
{
BurnPoint(pRow, pNextRow);
pRow--;
pNextRow--;
}
}
}
if (rand() % (400 - m_nFlammability) == 0)
{
int off = m_nSize - 5;
off = rand() % off;
off += xStart;
for (x = off; x < off + 5; x++)
g_Fire[x] = 239;
}
for (x = xStart; x < xEnd; x++)
{
if (g_Fire[x] < m_nMaxHeat)
{
int val = rand() % m_nChaos + 1;
val -= m_nChaos / 2;
val += m_nSpreadRate;
val += g_Fire[x];
if ( val > m_nMaxHeat)
g_Fire[x] = m_nMaxHeat;
else if (val < 0)
g_Fire[x] = 0;
else
g_Fire[x] = val;
}
else
g_Fire[x] = m_nMaxHeat;
}
if (m_nSmoothness > 0)
{
xStart += m_nSmoothness;
xEnd -= m_nSmoothness;
for (x = xStart; x < xEnd; x++)
{
int val = 0;
for (y = x - m_nSmoothness; y < x + 1 + m_nSmoothness; y++)
val += g_Fire[y];
g_Fire[x] = val / (2 * m_nSmoothness + 1);
}
}
}
// 显示火焰
void PaintFlame(int offset_x, int offset_y)
{
DWORD* pDst = GetImageBuffer(); // 获取显示缓冲区指针
for(int y = 0; y < FIREHEIGHT; y++)
for(int x = 0; x < FIREWIDTH; x++)
{
COLORREF c = g_Colors[g_Bits[y * FIREWIDTH + x]];
pDst[(offset_y - y) * WIDTH + offset_x + x] = c;
}
}
// 主函数
int main()
{
initgraph(WIDTH, HEIGHT); // 创建绘图窗口
srand((unsigned)time(NULL)); // 设置随机种子
InitFire(); // 初始化火焰
DrawColorScheme(); // 绘制色系图
while(!_kbhit()) // 按任意键退出
{
RenderFlame(); // 渲染火焰
PaintFlame(145, 320); // 显示火焰
Sleep(33); // 延时
}
closegraph();
return 0;
}
添加评论
取消回复