2009年11月01日

Fireエフェクト

どこかでゲットしたすごい古いコードを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 ------------------------------


タグ:Win32API
posted by S.F. at 14:40| 千葉 晴れ| Comment(0) | TrackBack(0) | etc | このブログの読者になる | 更新情報をチェックする
この記事へのコメント
コメントを書く
お名前: [必須入力]

メールアドレス:

ホームページアドレス:

コメント:

認証コード: [必須入力]


※画像の中の文字を半角で入力してください。
※ブログオーナーが承認したコメントのみ表示されます。
この記事へのトラックバックURL
http://blog.seesaa.jp/tb/131748343
※ブログオーナーが承認したトラックバックのみ表示されます。
※言及リンクのないトラックバックは受信されません。

この記事へのトラックバック