Fireエフェクト

公開:2009-11-02 14:40
更新:2020-02-15 04:36
カテゴリ:windows,その他api

どこかでゲットしたすごい古いコードをVistaで動かしてみた。
もともとはWin3.1用であったが、WinGの部分をDIBに置き換えたらあっさり動いた。
(たぶん作者はhttp://www.terra.es/personal3/jare70/)
20091031Fire.png


// ------------------------ WINFIRE.CPP ------------------------------
// Win32 port By S.F. 2009.11.1.
// もとネタは下記コメントを参照。WinGで組まれていたのをDIBに置き換えた。
// ---------------
// Coded bye Jare of Iguana near Xmas of 1994
// Comments to a880104@zipi.fi.upm.es
// My original ASM routine was 200 lines of plain ASM, this Windows
// version goes up to near 500 lines!!
// You can use this for anything you like, but you must credit me.
#include <windows.h>
#include <windowsx.h>
#include <stdlib.h>
#include <string.h>
// Fire array size.
#define FIREW 128
#define FIREH  96
// Nice size for the window. Frame will take some bits apart, however.
#define WINDOWW FIREW*4
#define WINDOWH FIREH*4
// Handy msg structure.
typedef struct {
HWND    hwnd;
UINT    msg;
WPARAM  wParam;
LPARAM  lParam;
} tMSG, *pMSG;
// Low Level data types.
typedef unsigned char  byte;
typedef unsigned short word;
typedef unsigned long  dword;
typedef byte  * Pbyte;
typedef word  * Pword;
typedef dword * Pdword;
typedef byte  FAR * LPbyte;
typedef word  FAR * LPword;
typedef dword FAR * LPdword;
// ===============================================================
// WinG DC handling functions.
struct dc {
dc(HWND h): h_(h) {dc_ = GetDC(h);}
~dc(){ReleaseDC(h_,dc_);}
operator HDC() {return dc_;}
private:
HDC dc_;
HWND h_;
};
// The stock default bitmap of a WinGDC.
static HBITMAP hBitmapMonochrome = 0;
// Creates a top-down WinGDC with the specified rgb palette.
// Returns the HDC and stores the bitmap pointer in ppSurfaceBits,
// if not passed a NULL parameter.
HDC MakeWinGDC(HWND hwnd,RGBQUAD rgb[256], LPbyte *ppSurfaceBits) {
HBITMAP hBitmapNew;
int     i;
static BITMAPINFO info;
// Force top-down 8-bit bitmap of size FIREW*FIREH.
info.bmiHeader.biSize         = sizeof(info.bmiHeader);
info.bmiHeader.biPlanes       = 1;
info.bmiHeader.biBitCount     = 8;
info.bmiHeader.biCompression  = BI_RGB;
info.bmiHeader.biSizeImage    = 0;
info.bmiHeader.biClrUsed      = 0;
info.bmiHeader.biClrImportant = 0;
info.bmiHeader.biWidth        = FIREW;
info.bmiHeader.biHeight       = -FIREH;    // Minus for top-down.
for (i = 0; i < 256; i++)
info.bmiColors[i] = rgb[i];
// Create a WinGDC and Bitmap, then select away DC's default
// monochrome bitmap.
dc hdc(hwnd);
hBitmapNew = ::CreateDIBSection(hdc,&info,DIB_RGB_COLORS,(void**)ppSurfaceBits,NULL,NULL);
HDC dcBitmap = ::CreateCompatibleDC(hdc);
hBitmapMonochrome = (HBITMAP)SelectObject(dcBitmap,hBitmapNew);
return dcBitmap;
}
// Finishes the WinGDC. Pretty straightforward.
static void EndWinGDC(HDC hWinGDC) {
HBITMAP hBitmapOld;
if (hWinGDC && hBitmapMonochrome) {
// Select the stock 1x1 monochrome bitmap back in
hBitmapOld = (HBITMAP)SelectObject(hWinGDC,
hBitmapMonochrome);
hBitmapMonochrome = 0;
DeleteObject(hBitmapOld);
DeleteDC(hWinGDC);
}
}
// Creates a palette from the specified colors, but requires
// using the system colors. Updates 'rgb' to enable the use of an
// identity palette i.e. on exit, rgb contains the effective
// palette, that can in turn be used for creating the WinGDC.
static HPALETTE CreateIdentityPalette(RGBQUAD aRGB[256], int nColors)
{
int i;
static struct {
WORD         Version;
WORD         NumberOfEntries;
PALETTEENTRY aEntries[256];
} pal = {
0x300,
256
};
// For SYSPAL_STATIC, get the twenty static colors into
// the array, then fill in the empty spaces with the
// given color table
{
dc sysdc(NULL);
// Get the static colors
GetSystemPaletteEntries(sysdc, 0,   10, pal.aEntries);
GetSystemPaletteEntries(sysdc, 246, 10, pal.aEntries + 246);
// Set the peFlags of the lower static colors to zero.
// And copy the static colors to the user palette so
// the caller knows exactly which palette we created.
for (i = 0; i < 10; i++) {
aRGB[i].rgbRed   = pal.aEntries[i].peRed;
aRGB[i].rgbGreen = pal.aEntries[i].peGreen;
aRGB[i].rgbBlue  = pal.aEntries[i].peBlue;
pal.aEntries[i].peFlags = 0;
}
// Fill in the entries from the given color table
for (; i < nColors+10; i++) {
pal.aEntries[i].peRed   = aRGB[i].rgbRed;
pal.aEntries[i].peGreen = aRGB[i].rgbGreen;
pal.aEntries[i].peBlue  = aRGB[i].rgbBlue;
pal.aEntries[i].peFlags = PC_RESERVED;
}
// Mark any empty entries as PC_RESERVED
for (; i < 246; i++) {
aRGB[i].rgbRed   = pal.aEntries[i].peRed;
aRGB[i].rgbGreen = pal.aEntries[i].peGreen;
aRGB[i].rgbBlue  = pal.aEntries[i].peBlue;
pal.aEntries[i].peFlags = PC_RESERVED;
}
// Set the peFlags of the upper static colors to zero, and
// copy static colors.
for (; i < 256; i++) {
aRGB[i].rgbRed   = pal.aEntries[i].peRed;
aRGB[i].rgbGreen = pal.aEntries[i].peGreen;
aRGB[i].rgbBlue  = pal.aEntries[i].peBlue;
pal.aEntries[i].peFlags = 0;
}
}
// Create the palette
return CreatePalette((LOGPALETTE *)&pal);
}
// ===============================================================
// Fire algorithm. Pure C, ASM will do it much faster.
static void DoFire(Pbyte to, Pbyte from) {
int i, j;
from += FIREW;
to   += 0;
// All lines but the first and last. The first will disappear,
// and the last must be taken with care for the limits of the
// array.
for (i = 1; i < FIREH-1; i++) {
// Leftmost pixel.
*to++ = (byte)((  (word)from[-1]          + (word)from[1]
+ (word)from[-(int)FIREW] + (word)from[FIREW]) >> 2);
from++;
// Middle pixels.
for (j = 1; j < FIREW-1; j++) {
*to++ = (byte)((  (word)from[-1]            + (word)from[1]
+ (word)from[-(int)FIREW-1] + (word)from[-(int)FIREW+1]
+ (word)from[+(int)FIREW-1] + (word)from[+(int)FIREW+1]
+ (word)from[-(int)FIREW]   + (word)from[FIREW]
) >> 3);
from++;
}
// Rightmost pixel.
*to++ = (byte)((  (word)from[-1]          + (word)from[1]
+ (word)from[-(int)FIREW] + (word)from[FIREW]) >> 2);
from++;
}
// Bottom line.
for (j = 0; j < FIREW-1; j++) {
*to++ = (byte)((  (word)from[-1]          + (word)from[1]
+ (word)from[-(int)FIREW] + (word)from[0]) >> 2);
from++;
}
// Rightmost pixel of bottom line.
*to = (byte)(((word)from[-1] + (word)from[-(int)FIREW]) >> 1);
}
// ===============================================================
// Fire Window message handlers.
// Global vars.
static HINSTANCE AppInstance;       // ditto.
static HDC      ScreenHDC;          // WinGDC created.
static LPbyte   Screen;             // Pointer to the surface bitmap.
static UINT     Timer;              // Timer identifier.
static RGBQUAD  rgb[256];           // Palette used.
static HPALETTE Palette;            // Handle to it.
static int      WindowState;        // Minimized, maximized or normal?
static HICON    FireIcon;           // Handle to icon for QueryDragIcon.
// Fire buffers. FAR so the are in their own data segment.
static byte FireBuf1[FIREW*FIREH], FireBuf2[FIREW*FIREH];
static Pbyte Buf1 = FireBuf1, Buf2 = FireBuf2;
// ---------- Message handlers.
static LRESULT wmCreate(pMSG msg) {
int     i;
FireIcon = LoadIcon(AppInstance, "FIREICON");
// Create a smooth palette.
memset(rgb, 0, sizeof(rgb));
for (i = 10; i < 10+16; i++)
rgb[i].rgbRed   = (BYTE)((i-10)*16);
for (; i < 10+48; i++) {
rgb[i].rgbRed   = 255;
rgb[i].rgbGreen = (BYTE)((i-10-16)*8);
}
for (; i < 10+80; i++) {
rgb[i].rgbRed   = 255;
rgb[i].rgbGreen = 255;
rgb[i].rgbBlue  = (BYTE)((i-10-48)*8);
}
for (; i < 10+236; i++) {
rgb[i].rgbRed   = 255;
rgb[i].rgbGreen = 255;
rgb[i].rgbBlue  = 255;
}
// Clean up buffers.
memset(FireBuf1, 0, sizeof(FireBuf1));
memset(FireBuf2, 0, sizeof(FireBuf2));
// Create stuff.
Palette   = CreateIdentityPalette(rgb, 236);
ScreenHDC = MakeWinGDC(msg->hwnd,rgb, &Screen);
WindowState = SC_RESTORE;
Timer     = SetTimer(msg->hwnd, 1, 1, NULL);
return DefWindowProc(msg->hwnd, msg->msg, msg->wParam, msg->lParam);
}
static LRESULT wmDestroy(pMSG msg) {
KillTimer(msg->hwnd, Timer);
EndWinGDC(ScreenHDC);
if (Palette != 0)
DeleteObject(Palette);
DestroyIcon(FireIcon);
return DefWindowProc(msg->hwnd, msg->msg, msg->wParam, msg->lParam);
}
static LRESULT wmTimer(pMSG msg) {
HDC     hdc;
int     i;
LPdword p;
Pdword  q;
Pbyte   s;
RECT    r;
// Clean bottom line.
memset(Buf2 + FIREW*(FIREH-1), 0, FIREW);
// Set random hot spots and animate.
for (i = 0; i < 20; i++) {
int k = rand() % (FIREW-2);
Buf2[FIREW*FIREH - k] = 235;
}
DoFire(Buf1, Buf2);
// Copy buffer to the WinGDC bitmap, adding 10 for the colors.
p = (LPdword)Screen;
q = (Pdword)Buf1;
for (i = 0; i < FIREH*FIREW/4; i++)
*p++ = *q++ + 0x0a0a0a0a;
// Swap buffers.
s = Buf1;
Buf1 = Buf2;
Buf2 = s;
// Dump bitmap.
GetClientRect(msg->hwnd, &r);
hdc = GetDC(msg->hwnd);
SelectPalette(hdc, Palette, FALSE);
RealizePalette(hdc);
// If window is not minimized or maximized, do optimal stretch
// by multiplying by 2^2, else stretch to whatever the size.
// Vertical stretch can be anything, as it doesn't slow down
// if it's not stretched by a power of two.
if (WindowState == SC_MINIMIZE || WindowState == SC_MAXIMIZE)
{
StretchBlt(hdc, 0, 0, r.right-r.left, r.bottom-r.top,
ScreenHDC, 0, 0, FIREW, FIREH,SRCCOPY);
} else {
StretchBlt(hdc, 0, 0, WINDOWW, r.bottom-r.top,
ScreenHDC, 0, 0, FIREW, FIREH,SRCCOPY);
}
ReleaseDC(msg->hwnd, hdc);
return DefWindowProc(msg->hwnd, msg->msg, msg->wParam, msg->lParam);
}
static LRESULT wmQueryNewPalette(pMSG msg) {
HDC hdc;
LRESULT f;
hdc = GetDC(msg->hwnd);
if (Palette)
SelectPalette(hdc, Palette, FALSE);
f = RealizePalette(hdc);
ReleaseDC(msg->hwnd, hdc);
return f;
}
static LRESULT wmSysCommand(pMSG msg) {
if (msg->wParam == SC_MINIMIZE ||
msg->wParam == SC_MAXIMIZE ||
msg->wParam == SC_RESTORE)
WindowState = msg->wParam;
return DefWindowProc(msg->hwnd, msg->msg, msg->wParam, msg->lParam);
}
static LRESULT wmWindowPosChanging(pMSG msg) {
LPWINDOWPOS lpwp;
RECT rw, rc;
int  x, w;
// If window is not maximized or minimized, align its client
// area to a four-pixel boundary for optimal performance.
if (WindowState == SC_RESTORE) {
lpwp = (LPWINDOWPOS)msg->lParam;
GetWindowRect(msg->hwnd, &rw);
GetClientRect(msg->hwnd, &rc);
w = rw.right - rw.left - (rc.right - rc.left); // Width of frame.
x = lpwp->x + w;
lpwp->x = (x & ~3) - w;   // Align it.
if (lpwp->cx - w > WINDOWW)
lpwp->cx = w + WINDOWW;
}
return DefWindowProc(msg->hwnd, msg->msg, msg->wParam, msg->lParam);
}
// Window procedure.
LRESULT CALLBACK FireWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
tMSG m;
m.hwnd   = hwnd;
m.msg    = msg;
m.wParam = wParam;
m.lParam = lParam;
switch (msg) {
case WM_CREATE:        return wmCreate(&m);
case WM_DESTROY:       return wmDestroy(&m);
case WM_QUERYDRAGICON:
if (FireIcon != (HICON)NULL)
return (LRESULT)FireIcon;
break;
case WM_TIMER: return wmTimer(&m);
case WM_PALETTECHANGED:
if ((HWND)wParam != hwnd)   // If we changed the palette.
return wmQueryNewPalette(&m);
break;
case WM_QUERYNEWPALETTE: return wmQueryNewPalette(&m);
case WM_WINDOWPOSCHANGING: return wmWindowPosChanging(&m);
case WM_SYSCOMMAND:        return wmSysCommand(&m);
case WM_CLOSE:
PostQuitMessage(0);
break;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
// ===============================================================
// Main entry point.
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int sw) {
static char ClassName[] = "WinFire";
static char AppName[]   = "WinFire";
int w, h;
MSG msg;
HWND hwnd;
if (hPrev == 0) {
WNDCLASS c;
c.hCursor       = LoadCursor(NULL, IDC_WAIT);
c.hIcon         = NULL;
c.lpszMenuName  = NULL;
c.lpszClassName = "WinFire";
c.hbrBackground = NULL;
c.hInstance     = hInst;
c.style         = CS_BYTEALIGNCLIENT | CS_VREDRAW | CS_HREDRAW;
c.lpfnWndProc   = (WNDPROC)FireWndProc;
c.cbWndExtra    = 0;
c.cbClsExtra    = 0;
if (!RegisterClass(&c))
return 1;
}
AppInstance = hInst;
w = GetSystemMetrics(SM_CXSCREEN);
h = GetSystemMetrics(SM_CYSCREEN);
hwnd = CreateWindow (ClassName,                // Class name
AppName,                  // Caption
WS_OVERLAPPEDWINDOW,      // Style bits
(w-WINDOWW)/2, (h-WINDOWH)/2, // Position
WINDOWW, WINDOWH,             // Size
(HWND)NULL,               // Parent window (no parent)
(HMENU)NULL,              // no menu
hInst,                    // handle to window instance
(LPSTR)NULL               // no params to pass on
);
if (hwnd == (HWND)NULL)
return 1;
ShowWindow(hwnd, sw);
while (GetMessage(&msg, (HWND)NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
// ------------------------ WINFIRE.CPP ------------------------------