| |
| Broncode van vuur effect in C |
© 2010 Hein Pragt
Een heel leuk grafisch effect dat u vaak tegenkomt in demo's is gegenereerd vuur. Ik zal in het kort proberen uit te leggen hoe we vuur kunnen maken. Eerst hebben we een kleurenpalet nodig dat van donkerblauw naar donkerrood overloopt en dan van rood naar geel en daarna van geel naar wit. Dit zijn de kleuren waar het vuur uit gaat bestaan. We hebben 255 kleuren en 0 is het meest donker en 255 is het meest licht. We maken een scherm buffer en die vullen we eerst met alleen maar 0. We zetten onder in de laatste regel om de beurt 255 of 0 met een random functie. Daarna gaan we het scherm omhoog scrollen waarbij we van een punt het gemiddelde kleurwaarde nemen met de omliggende punten. Dit zetten we als kleurwaarde in het nieuw pixel en dit blijven we herhalen. De pixels op hogere lijnen zullen dus steeds meer gedempt gaan worden en aangezien ons kleurenpalet mooi de kleuren van vuur bevat zal het een redelijk realistisch beeld van vuur opleveren. Aangezien we met een loop de informatie punt voor punt op het scherm kopiėren blinkt deze routine niet uit in snelheid en is wel een redelijk zware machine nodig om een goed resultaat te zien.
Omdat het om vrij universele code gaat heb ik de Windows Win32 interface zo minimaal mogelijk gemaakt, dit is
trouwens altijd mijn voorkeur om programmas zo portable mogelijk te maken en niet te afhankelijk te zijn van
het besturingssysteem.
// ------------------------------------
// Win32 Demo Fire
// (c) 2010 Hein Pragt
// Standard GDI is realy too slow!
// ------------------------------------
#include <windows.h>
#include <windowsx.h>
#include <stdlib.h>
// Interface to windows
void PlotPixel(int x, int y, DWORD c);
// -------------------------------------------------------------
// This is our demo code
// -------------------------------------------------------------
#define SCREEN_WIDTH 240
#define SCREEN_HEIGHT 180
static COLORREF colors[256];
static unsigned char fire[SCREEN_WIDTH][SCREEN_HEIGHT];
int sWidth, sHeight;
DWORD nStartTime;
void Init(int WinWidth, int WinHeight);
void GameLoop(void);
void ProcFire(void);
// ---------------------------------------
// Call this before at init of the app
// ---------------------------------------
void Init(int WinWidth, int WinHeight)
{
int i;
sWidth = WinWidth;
sHeight = WinHeight;
/* create a suitable fire palette, this is crucial for a good effect */
/* black to blue, blue to red, red to yellow, yellow to white*/
for (i=0; i<32; i++) {
/* black to blue, 32 values*/
colors[i] = RGB(0,0,i << 1);
/* blue to red, 32 values*/
colors[i + 32] = RGB(i << 3,0,64 - (i << 1));
/*red to yellow, 32 values*/
colors[i + 64] = RGB(255,i << 3,0);
/* yellow to white, 162 */
colors[i + 96] = RGB(255,255,i << 2);
colors[i + 128] = RGB(255,255,64 + (i << 2));
colors[i + 160] = RGB(255,255,128 + (i << 2));
colors[i + 192] = RGB(255,255,192 + i);
colors[i + 224] = RGB(255,255,224 + i);
}
nStartTime = GetTickCount(); // Init timer
memset(fire,0,sHeight * sWidth);
}
// ---------------------------------------
// Call this to keep the engine running
// ---------------------------------------
void GameLoop()
{
if ((GetTickCount() - nStartTime) < 10) {
Sleep(1);
return; // Wait for next frame
}
nStartTime = GetTickCount();
ProcFire();
}
// ---------------------------------------
// Call this to keep the engine running
// ---------------------------------------
void ProcFire()
{
int x,y,v;
unsigned char *src;
for (y=sHeight - 140; y<sHeight; y++) {
for (x=1; x<sWidth-1; x++) {
fire[x][y-1] = (fire[x][y] + fire[x][y-1]-1 + fire[x][y+1]) / 3;
}
}
v = 255;
for (x=1; x<sWidth-1; x++) {
int random = rand() % 14;
if (random > 10)
if (v == 0) v = 255; else v = 0;
fire[x][sHeight-1] = v;
}
// Copy to screen
src = &fire[0];
for (x=0; x<sWidth; x++) {
for (y=0; y<sHeight; y++) {
PlotPixel(x,y, colors[*src++]);
}
}
}
// ---------------------------------------------
// The minimal Window interface code
// ---------------------------------------------
#define WIN_CLASS_NAME "MyGraphClass"
HDC hMainDC;
HINSTANCE hInstance;
HWND hWnd;
int WinWidth = SCREEN_WIDTH;
int WinHeight = SCREEN_HEIGHT;
LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
int WINAPI WinMain(HINSTANCE hinstance, HINSTANCE hprevinstance, LPSTR lpcmdline, int ncmdshow)
{
WNDCLASSEX winclass;
HWND hwnd;
MSG msg;
winclass.cbSize = sizeof(WNDCLASSEX);
winclass.style = CS_DBLCLKS | CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
winclass.lpfnWndProc = WindowProc;
winclass.cbClsExtra = 0;
winclass.cbWndExtra = 0;
winclass.hInstance = hinstance;
winclass.hIcon = LoadIcon(NULL, IDI_WINLOGO);
winclass.hCursor = LoadCursor(NULL, IDC_ARROW);
winclass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
winclass.lpszMenuName = NULL; // no menu
winclass.lpszClassName = (LPCWSTR) WIN_CLASS_NAME;
winclass.hIconSm = LoadIcon(NULL, IDI_WINLOGO);
if (!RegisterClassEx(&winclass))
return(0);
if (!(hwnd = CreateWindowEx(NULL,
WIN_CLASS_NAME, // class identifier
TEXT("Demo"), // window title
WS_OVERLAPPEDWINDOW | WS_VISIBLE, // parameters
CW_USEDEFAULT, CW_USEDEFAULT, // initial position
WinWidth, WinHeight, // Window size
NULL, // handle to parent
NULL, // handle to menu
hinstance, // app handle
NULL)))
return(0);
// Copy to globals
hWnd = hwnd;
hInstance = hinstance;
hMainDC = GetDC(hWnd);
Init(WinWidth, WinHeight);
while(TRUE) {
if (PeekMessage(&msg,0,0,0,PM_REMOVE)) {
if (msg.message == WM_QUIT) // exit loop on quit
break;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
GameLoop(); // keep animation running
}
ReleaseDC(hWnd, hMainDC);
return(msg.wParam);
}
// ---------------------------------------------
// The minimal Window message handler
// ---------------------------------------------
LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg,WPARAM wparam, LPARAM lparam)
{
switch(msg) {
case WM_DESTROY:
PostQuitMessage(0);
return(0);
break;
case WM_CLOSE:
break;
}
return(DefWindowProc(hwnd, msg, wparam, lparam));
}
// ---------------------------------------------
// The plot pixel function
// ---------------------------------------------
void PlotPixel(int x, int y, DWORD c)
{
SetPixel(hMainDC, x, y, c);
}
Last update: 09-04-2010
|
|