How to get this DIB code to work with an 8bpp Bitmap?

Started by
2 comments, last by Airbatz 3 years ago

Before I begin, I should mention that this code was not written by me, but it does what I need. I've only read a little about DIB's and was experimenting with some different examples, but most of them tend to use 24bpp bitmaps. I want to use an 8bpp compressed bitmap to reduce its size in my executable. The program compiles but doesn't display it. What is missing here? The code will work fine with a 24bpp bitmap.

#include <windows.h>
#include "resource.h"

struct BACKBUFFER {
	HWND    hwnd;
	HDC     hdc;
	HBITMAP hbmp;
	HBITMAP hbmpPrev;
	HBRUSH  hbr;
	int     cx;
	int     cy;
};
typedef struct BACKBUFFER BACKBUFFER;

struct OBJECT {
	HDC     hdc;
	HBITMAP hbmp;
	HBITMAP hbmpPrev;
	BOOL    bUp;
	int     nBright;
	int     x;
	int     y;
	int     cx;
	int     cy;
};
typedef struct OBJECT OBJECT;

BOOL       g_bPause = FALSE;
BOOL       g_bLostFocus = FALSE;
BACKBUFFER g_backBuffer = {0};
OBJECT     g_object = {0};

int  Run(void);
BOOL CreateBackbuffer(HWND hwnd);
void DestroyBackbuffer();

BOOL CreateObject(HWND hwnd);
void DestroyObject();

void Move(void);
void Render(void);
void Show(void);

BYTE ArrangeBright(BYTE color, BYTE bright);
void CopyBits(HBITMAP hbmpDest, int xStart, int yStart, int cx, int cy, HBITMAP hbmpSrc, BYTE bright);
LPBYTE GetBits(HBITMAP hbmp, int x, int y);
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

int WINAPI WinMain(HINSTANCE hinst, HINSTANCE hinstPrev, LPSTR lpszCmdLine, int nCmdShow)
{
	TCHAR      szAppName[] = TEXT("RGB Fade");
	HWND       hwnd;
	WNDCLASSEX wc;
	RECT       rc;
	DWORD      dwStyle;

	wc.cbSize        = sizeof(WNDCLASSEX);
	wc.style         = 0;
	wc.lpfnWndProc   = WindowProc;
	wc.cbClsExtra    = 0;
	wc.cbWndExtra    = 0;
	wc.hInstance     = hinst;
	wc.hIcon         = (HICON)LoadImage(NULL, IDI_APPLICATION, IMAGE_ICON, 0, 0, LR_SHARED);
	wc.hCursor       = (HCURSOR)LoadImage(NULL, IDC_ARROW, IMAGE_CURSOR, 0, 0, LR_SHARED);
	wc.hbrBackground = (HBRUSH)GetStockObject(NULL_BRUSH);
	wc.lpszMenuName  = NULL;
	wc.lpszClassName = szAppName;
	wc.hIconSm       = (HICON)LoadImage(NULL, IDI_APPLICATION, IMAGE_ICON, 0, 0, LR_SHARED);

	if (RegisterClassEx(&wc) == 0)
		return 0;

	dwStyle = WS_OVERLAPPEDWINDOW & ~WS_THICKFRAME & ~WS_MAXIMIZEBOX;
	SetRect(&rc, 0, 0, 320, 175);
	AdjustWindowRect(&rc, dwStyle, FALSE);

	hwnd = CreateWindowEx(0, szAppName, szAppName, dwStyle, CW_USEDEFAULT, CW_USEDEFAULT, rc.right - rc.left, rc.bottom - rc.top, NULL, NULL, hinst, NULL);
	if (hwnd == NULL)
		return 0;

	ShowWindow(hwnd, nCmdShow);
	UpdateWindow(hwnd);

	return Run();
}

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	switch (uMsg) {

	case WM_CREATE:
		if (!CreateBackbuffer(hwnd))
			return -1;
		if (!CreateObject(hwnd))
			return -1;
		return 0;

	case WM_KEYDOWN:
		if (wParam == VK_PAUSE) {
			g_bPause = !g_bPause;
			if (g_bPause)
				Show();
		}
		return 0;

	case WM_PAINT:
		Show();
		break;

	case WM_NCLBUTTONDOWN:
		Show();
		break;

	case WM_ERASEBKGND:
		return 0;

	case WM_SETFOCUS:
		g_bLostFocus = FALSE;
		return 0;

	case WM_KILLFOCUS:
		g_bLostFocus = TRUE;
		return 0;

	case WM_DESTROY:
		DestroyBackbuffer();
		DestroyObject();
		PostQuitMessage(0);
		return 0;

	default:
		break;

	}

	return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

int Run(void)
{
	MSG   msg;
	BOOL  bMove;
	DWORD dwInterval = 40;
	DWORD dwCurTime, dwNextTime;

	bMove      = TRUE;
	dwNextTime = timeGetTime();

	for (;;) {
		if (g_bPause || g_bLostFocus || PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) {
			if (GetMessage(&msg, NULL, 0, 0) > 0)
				DispatchMessage(&msg);
			else
				break;
		}
		else {
			if (bMove) {
				Move();
				Render();

				bMove = FALSE;
			}

			dwCurTime = timeGetTime();

			if (dwCurTime > dwNextTime) {
				Show();

				dwNextTime += dwInterval;

				if (dwNextTime < dwCurTime)
					dwNextTime = dwCurTime + dwInterval;

				bMove = TRUE;
			}
			else
				Sleep(dwNextTime - dwCurTime);
		}
	}

	return (int)msg.wParam;
}

BOOL CreateBackbuffer(HWND hwnd)
{
	HDC              hdc;
	LPVOID           lp;
	BITMAPINFO       bmi;
	BITMAPINFOHEADER bmiHeader;

	ZeroMemory(&bmiHeader, sizeof(BITMAPINFOHEADER));
	bmiHeader.biSize      = sizeof(BITMAPINFOHEADER);
	bmiHeader.biWidth     = 320;
	bmiHeader.biHeight    = 175;
	bmiHeader.biPlanes    = 1;
	bmiHeader.biBitCount  = 24;

	bmi.bmiHeader = bmiHeader;

	g_backBuffer.hbmp = CreateDIBSection(NULL, (LPBITMAPINFO)&bmi, DIB_RGB_COLORS, &lp, NULL, 0);
	if (g_backBuffer.hbmp == NULL)
		return FALSE;

	hdc = GetDC(hwnd);

	g_backBuffer.hdc = CreateCompatibleDC(hdc);
	g_backBuffer.hbmpPrev = (HBITMAP)SelectObject(g_backBuffer.hdc, g_backBuffer.hbmp);

	ReleaseDC(hwnd, hdc);

	g_backBuffer.hwnd = hwnd;
	g_backBuffer.hbr  = (HBRUSH)GetStockObject(BLACK_BRUSH);
	g_backBuffer.cx   = 320;
	g_backBuffer.cy   = 175;

	return TRUE;
}

void DestroyBackbuffer()
{
	if (g_backBuffer.hdc != NULL) {
		if (g_backBuffer.hbmp != NULL) {
			SelectObject(g_backBuffer.hdc, g_backBuffer.hbmpPrev);
			DeleteObject(g_backBuffer.hbmp);
		}
		DeleteDC(g_backBuffer.hdc);
	}
}

BOOL CreateObject(HWND hwnd)
{
	HDC    hdc;
	BITMAP bm;

	hdc = GetDC(hwnd);

	g_object.hdc = CreateCompatibleDC(hdc);
	g_object.hbmp = (HBITMAP)LoadImage(GetModuleHandle(NULL), MAKEINTRESOURCE(IDB_PIC), IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION);
	if (g_object.hbmp == NULL) {
		ReleaseDC(hwnd, hdc);
		return FALSE;
	}

	g_object.hbmpPrev = (HBITMAP)SelectObject(g_object.hdc, g_object.hbmp);

	g_object.bUp = FALSE;
	g_object.nBright = 0;

	GetObject(g_object.hbmp, sizeof(BITMAP), &bm);
	g_object.x  = 0;
	g_object.y  = 0;
	g_object.cx = bm.bmWidth;
	g_object.cy = bm.bmHeight;

	ReleaseDC(hwnd, hdc);

	return TRUE;
}

void DestroyObject()
{
	if (g_object.hdc != NULL) {
		if (g_object.hbmp != NULL) {
			SelectObject(g_object.hdc, g_object.hbmpPrev);
			DeleteObject(g_object.hbmp);
		}
		DeleteDC(g_object.hdc);
	}
}

void Move(void)
{
	int nSpeed = 1;

	if (GetAsyncKeyState(VK_SPACE) < 0)
		nSpeed = 3;

	if (g_object.bUp) {
		g_object.nBright += 2 * nSpeed;
		if (g_object.nBright >= 255) {
			g_object.bUp = FALSE;
			g_object.nBright = 255;
		}
	}
	else {
		g_object.nBright -= 2 * nSpeed;
		if (g_object.nBright <= 0) {
			g_object.bUp = TRUE;
			g_object.nBright = 0;
		}
	}
}

void Render(void)
{
	RECT rc;

	SetRect(&rc, 0, 0, g_backBuffer.cx, g_backBuffer.cy);
	FillRect(g_backBuffer.hdc, &rc, g_backBuffer.hbr);

	CopyBits(g_backBuffer.hbmp, g_object.x, g_object.y, g_object.cx, g_object.cy, g_object.hbmp, (BYTE)g_object.nBright);
}

void Show(void)
{
	HDC hdc;

	hdc = GetDC(g_backBuffer.hwnd);

	BitBlt(hdc, 0, 0, g_backBuffer.cx, g_backBuffer.cy, g_backBuffer.hdc, 0, 0, SRCCOPY);

	ReleaseDC(g_backBuffer.hwnd, hdc);
}

BYTE ArrangeBright(BYTE color, BYTE bright)
{
	if (bright > 128)
		color += ((255 - color) * (bright - 127)) / 128;
	else
		color = color * bright / 128;

	return color;
}

void CopyBits(HBITMAP hbmpDest, int xStart, int yStart, int cx, int cy, HBITMAP hbmpSrc, BYTE bright)
{
	int    x, y;
	LPBYTE lpSrc, lpDest;

	for (y = 0; y < cy; y++) {
		lpSrc  = GetBits(hbmpSrc, 0, y);
		lpDest = GetBits(hbmpDest, xStart, yStart + y);
		for (x = 0; x < cx; x++) {
			lpDest[0] = ArrangeBright(lpSrc[0], bright);
			lpDest[1] = ArrangeBright(lpSrc[1], bright);
			lpDest[2] = ArrangeBright(lpSrc[2], bright);

			lpSrc  += 3;
			lpDest += 3;
		}
	}
}

LPBYTE GetBits(HBITMAP hbmp, int x, int y)
{
	BITMAP bm;
	LPBYTE lp;

	GetObject(hbmp, sizeof(BITMAP), &bm);

	lp = (LPBYTE)bm.bmBits;
	lp += (bm.bmHeight - y - 1) * ((3 * bm.bmWidth + 3) / 4) * 4;
	lp += 3 * x;

	return lp;
}

None

Advertisement

Where is the Show() defined, and have you checked whether it is ever hit?

It is defined at the bottom of the code, and is called from WM_PAINT. This function blits the double buffer to the screen. The program fades a bitmap in and out using a loop. I'm reading a little more and found that 256 color bitmaps require an RGBQUAD struct to be initialized with a palette.

None

This topic is closed to new replies.

Advertisement