#define WIN32_LEAN_AND_MEAN #include static int winWidth; static int winHeight; static int screenWidth; static int screenHeight; static int depth; static HBITMAP offscreen; static HDC offscreenDC; static HDC blitDC; static bool readyToRender = false; static HBITMAP blob; int blobw, blobh; PALETTEENTRY *palette = NULL; void blit8(HBITMAP src, int srcx, int srcy, int w, int h, HBITMAP dst, int dstx, int dsty, float a, bool t) { if(a == 0.0) return; // completely transparent ... can't even see it! BITMAP bm; GetObject(src, sizeof(bm), (void *)&bm); int srcpitch = ((bm.bmWidthBytes + 3) / 4) * 4; int srcadd = srcpitch - w; unsigned char *srcbits = (unsigned char*)bm.bmBits; unsigned long tcolor; if(t) tcolor = *srcbits; srcbits += (srcy * srcpitch) + srcx; GetObject(dst, sizeof(bm), (void *)&bm); int dstpitch = ((bm.bmWidthBytes + 3) / 4) * 4; int dstadd = dstpitch - w; unsigned char *dstbits = (unsigned char *)bm.bmBits; dstbits += (dsty * dstpitch) + dstx; int x; int y = 0; float ainv = 1.0f - a; while(y < h) { x = 0; while(x < w) { if(a >= 0.5f) { if(!t || (*srcbits != tcolor)) { *dstbits = *srcbits; *dstbits = (char)(x + y); } srcbits++; dstbits++; } x++; } srcbits += srcadd; dstbits += dstadd; y++; } } void blit16(HBITMAP src, int srcx, int srcy, int w, int h, HBITMAP dst, int dstx, int dsty, float a, bool t) { if(a == 0.0) return; // completely transparent ... can't even see it! BITMAP bm; GetObject(src, sizeof(bm), (void *)&bm); int srcpitch = ((bm.bmWidthBytes + 3) / 4) * 4; srcpitch /= 2; int srcadd = srcpitch - w; unsigned short *srcbits = (unsigned short*)bm.bmBits; unsigned short tcolor; if(t) tcolor = *srcbits; srcbits += (srcy * srcpitch) + srcx; GetObject(dst, sizeof(bm), (void *)&bm); int dstpitch = ((bm.bmWidthBytes + 3) / 4) * 4; dstpitch /= 2; int dstadd = dstpitch - w; unsigned short *dstbits = (unsigned short *)bm.bmBits; dstbits += (dsty * dstpitch) + dstx; int x; int y = 0; if(a == 1.0) { if(!t) { // transparency: no // alpha : no while(y < h) { x = 0; while(x < w) { *dstbits++ = *srcbits++; x++; } srcbits += srcadd; dstbits += dstadd; y++; } } else { // transparency: yes // alpha : no unsigned short sb; while(y < h) { x = 0; while(x < w) { sb = *srcbits++; if(!t || (sb != tcolor)) *dstbits++ = sb; else dstbits++; x++; } srcbits += srcadd; dstbits += dstadd; y++; } } } else { unsigned long sb; unsigned long db; float ainv = 1.0f - a; if(!t) { // transparency: no // alpha : yes while(y < h) { x = 0; while(x < w) { sb = *srcbits++; db = *dstbits; *dstbits++ = (((unsigned short)((sb & 0xf800) * a) + (unsigned short)((db & 0xf800) * ainv)) & 0xf800) | (((unsigned short)((sb & 0x07e0) * a) + (unsigned short)((db & 0x07e0) * ainv)) & 0x07e0) | (((unsigned short)((sb & 0x001f) * a) + (unsigned short)((db & 0x001f) * ainv)) & 0x001f) ; x++; } srcbits += srcadd; dstbits += dstadd; y++; } } else { // transparency: yes // alpha : yes while(y < h) { x = 0; while(x < w) { sb = *srcbits++; db = *dstbits; if(!t || (sb != tcolor)) { *dstbits++ = (((unsigned short)((sb & 0xf800) * a) + (unsigned short)((db & 0xf800) * ainv)) & 0xf800) | (((unsigned short)((sb & 0x07e0) * a) + (unsigned short)((db & 0x07e0) * ainv)) & 0x07e0) | (((unsigned short)((sb & 0x001f) * a) + (unsigned short)((db & 0x001f) * ainv)) & 0x001f) ; } else { dstbits++; } x++; } srcbits += srcadd; dstbits += dstadd; y++; } } } } void blit24(HBITMAP src, int srcx, int srcy, int w, int h, HBITMAP dst, int dstx, int dsty, float a, bool t) { if(a == 0.0) return; // completely transparent ... can't even see it! BITMAP bm; GetObject(src, sizeof(bm), (void *)&bm); int srcpitch = ((bm.bmWidthBytes + 3) / 4) * 4; int srcadd = srcpitch - (w * 3); unsigned char *srcbits = (unsigned char*)bm.bmBits; unsigned long tcolor; if(t) tcolor = (*((unsigned long *)(srcbits)) & 0xffffff); srcbits += (srcy * srcpitch) + (srcx * 3); GetObject(dst, sizeof(bm), (void *)&bm); int dstpitch = ((bm.bmWidthBytes + 3) / 4) * 4; int dstadd = dstpitch - (w * 3); unsigned char *dstbits = (unsigned char *)bm.bmBits; dstbits += (dsty * dstpitch) + (dstx * 3); int x; int y = 0; unsigned char sb; unsigned char db; float ainv = 1.0f - a; while(y < h) { x = 0; while(x < w) { if(!t || ((*((unsigned long *)(srcbits)) & 0xffffff) != tcolor)) { sb = *srcbits++; db = *dstbits; *dstbits++ = (unsigned char)((sb * a) + (db * ainv)); sb = *srcbits++; db = *dstbits; *dstbits++ = (unsigned char)((sb * a) + (db * ainv)); sb = *srcbits++; db = *dstbits; *dstbits++ = (unsigned char)((sb * a) + (db * ainv)); } else { srcbits += 3; dstbits += 3; } x++; } srcbits += srcadd; dstbits += dstadd; y++; } } void (*blit)(HBITMAP src, int srcx, int srcy, int w, int h, HBITMAP dst, int dstx, int dsty, float a, bool t); #include static int fps = 0; static int frame = 0; static unsigned long then = 0; void Render(HWND hWnd, HDC hdc) { if(!readyToRender) return; SelectObject(offscreenDC, GetStockObject(GRAY_BRUSH)); Rectangle(offscreenDC, 0, 0, winWidth, winHeight); unsigned long now = GetTickCount() / 1000; if(now != then) { then = now; fps = frame; frame = 0; } else { frame++; } char s[20]; sprintf(s, "Depth=%d FPS=%d", depth, fps); TextOut(offscreenDC, 20, 20, s, strlen(s)); blit(blob, 0, 0, blobw, blobh, offscreen, 20, 100, 1.0f, false); blit(blob, 0, 0, blobw, blobh, offscreen, 40, 100, 0.8f, false); blit(blob, 0, 0, blobw, blobh, offscreen, 60, 100, 0.6f, false); blit(blob, 0, 0, blobw, blobh, offscreen, 80, 100, 0.4f, false); blit(blob, 0, 0, blobw, blobh, offscreen, 100, 100, 0.2f, false); blit(blob, 0, 0, blobw, blobh, offscreen, 20, 80, 1.0f, true); blit(blob, 0, 0, blobw, blobh, offscreen, 40, 80, 0.8f, true); blit(blob, 0, 0, blobw, blobh, offscreen, 60, 80, 0.6f, true); blit(blob, 0, 0, blobw, blobh, offscreen, 80, 80, 0.4f, true); blit(blob, 0, 0, blobw, blobh, offscreen, 100, 80, 0.2f, true); // Blast back buffer to screen BitBlt(hdc, 0, 0, winWidth, winHeight, offscreenDC, 0, 0, SRCCOPY); } LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { PAINTSTRUCT ps; HDC hdc; switch (message) { case WM_TIMER: { // tick InvalidateRect(hWnd, NULL, TRUE); } break; case WM_PAINT: hdc = BeginPaint(hWnd, &ps); Render(hWnd, hdc); EndPaint(hWnd, &ps); break; case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } return 0; } void GetOptimalDIBFormat(HDC hdc, BITMAPINFOHEADER *pbi) { HBITMAP hbm; hbm = CreateCompatibleBitmap(hdc, 1, 1); ZeroMemory(pbi, sizeof(BITMAPINFOHEADER)); pbi->biSize = sizeof(BITMAPINFOHEADER); pbi->biBitCount = 0; GetDIBits(hdc, hbm, 0, 1, NULL, (BITMAPINFO*)pbi, DIB_RGB_COLORS); DeleteObject(hbm); } HBITMAP CreateCompatibleDIBSection(HDC hdc, int w, int h) { struct { BITMAPINFOHEADER bmiHeader; DWORD rmask; DWORD gmask; DWORD bmask; } bbb; HBITMAP hbm = CreateCompatibleBitmap(hdc, w, h); ZeroMemory(&bbb.bmiHeader, sizeof(BITMAPINFOHEADER)); bbb.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); bbb.bmiHeader.biBitCount = 0; GetDIBits(hdc, hbm, 0, 1, NULL, (BITMAPINFO*)&bbb.bmiHeader, DIB_RGB_COLORS); DeleteObject(hbm); bbb.bmiHeader.biHeight = bbb.bmiHeader.biHeight * -1; bbb.rmask = 0xf800; bbb.gmask = 0x07e0; bbb.bmask = 0x001f; return CreateDIBSection(hdc, (BITMAPINFO *)&bbb, DIB_RGB_COLORS, NULL, NULL, 0); } /* Try to load a bitmap by name from disk. If found, load it and return handle to it. If not found, pull bitmap with same name from compiled in resources. If not found there either, return null. If non-null pointers are supplied for skw and skh, they will be filled in with the bitmaps width and height. */ static HBITMAP getBitmap(const char *bmname, int *skw, int *skh) { HINSTANCE inst = GetModuleHandle(NULL); HBITMAP bm = (HBITMAP)LoadImage( inst, bmname, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_DEFAULTSIZE); if(bm == NULL) bm = (HBITMAP)LoadImage(inst, bmname, IMAGE_BITMAP, 0, 0, 0); if(bm != NULL) { BITMAP b; GetObject(bm, sizeof(b), (void *)&b); if(skw) *skw = b.bmWidth; if(skh) *skh = b.bmHeight; } return bm; } HBITMAP getBitmap(const char *name, HINSTANCE hInstance, HWND hWnd) { int w, h; HBITMAP hbm = getBitmap(name, &w, &h); if(hbm == NULL) return NULL; blobw = w; blobh = h; HDC hdc = GetDC(hWnd); HDC hdc1 = CreateCompatibleDC(hdc); HDC hdc2 = CreateCompatibleDC(hdc); HBITMAP cbm = CreateCompatibleDIBSection(hdc, w, h); SelectObject(hdc1, hbm); SelectObject(hdc2, cbm); BitBlt(hdc2, 0, 0, w, h, hdc1, 0, 0, SRCCOPY); DeleteDC(hdc2); DeleteDC(hdc1); ReleaseDC(hWnd, hdc); DeleteObject(hbm); return cbm; } int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { MSG msg; // Register class WNDCLASSEX wcex; wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = (WNDPROC)WndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = hInstance; wcex.hIcon = LoadIcon(hInstance, (LPCTSTR)"APP_ICON"); wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = NULL; wcex.lpszMenuName = 0; wcex.lpszClassName = "BigLoudWhip"; wcex.hIconSm = LoadIcon(hInstance, (LPCTSTR)"APP_ICON"); RegisterClassEx(&wcex); // Open window HWND hWnd = CreateWindow("BigLoudWhip", "Whoopa", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 450, 450, NULL, NULL, hInstance, NULL); if (!hWnd) return FALSE; ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); SetTimer(hWnd, 1, 50, NULL); // Grab out some info about the screen and window. RECT rc; GetClientRect(hWnd, &rc); winWidth = rc.right - rc.left + 1; winHeight = rc.bottom - rc.top + 1; HDC hdc = GetDC(hWnd); screenWidth = GetDeviceCaps(hdc, HORZRES); screenHeight = GetDeviceCaps(hdc, VERTRES); depth = GetDeviceCaps(hdc, BITSPIXEL) * GetDeviceCaps(hdc, PLANES); // Set up blit routine based on depth of display if(depth == 8) blit = blit8; else if(depth == 16) blit = blit16; else if(depth == 24) blit = blit24; else return FALSE; // Create offscreen bitmap and dc offscreen = CreateCompatibleDIBSection( hdc, winWidth, winHeight); offscreenDC = CreateCompatibleDC(hdc); SelectObject(offscreenDC, offscreen); // Create a dc for blitting. blitDC = CreateCompatibleDC(hdc); GdiSetBatchLimit(1); UINT numColors = GetSystemPaletteEntries(hdc, 0, 0, 0); if(numColors > 0) { palette = new PALETTEENTRY[numColors]; GetSystemPaletteEntries(hdc, 0, numColors, palette); } ReleaseDC(hWnd, hdc); blob = getBitmap("something.bmp", hInstance, hWnd); if(!blob) return 0; readyToRender = true; // Main message loop: while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; }