#define DONT_INCLUDE_AFXTEMPL #include "Bitmap.h" static int getColoursUsed(BITMAPINFO *bmp); Bitmap::Bitmap() { mBitmap = NULL; mPixels = NULL; Allocate(640, 480); } Bitmap::~Bitmap() { Free(); } void Bitmap::Free() { if (mBitmap) { GlobalUnlock(GlobalHandle(mBitmap)); GlobalFree(GlobalHandle(mBitmap)); } if (mPixels) { GlobalUnlock(GlobalHandle(mPixels)); GlobalFree(GlobalHandle(mPixels)); } } BOOL Bitmap::AllocateHeader() { int size = GetBitmapHeaderSize(); if (mBitmap) { GlobalUnlock(GlobalHandle(mBitmap)); GlobalFree(GlobalHandle(mBitmap)); } mBitmap = (BITMAPINFO *) GlobalLock(GlobalAlloc(GMEM_MOVEABLE, size)); if (!mBitmap) { SetErrorCode(8); return false; } memset(mBitmap, 0, size); return true; } void Bitmap::SetErrorCode(int code) { mErrorCode = code; } BOOL Bitmap::SetHeader(const Bitmap *other) { int size = GetBitmapHeaderSize(); AllocateHeader(); memcpy(mBitmap, other->mBitmap, size); return true; } BOOL Bitmap::LoadFile(const char *path) { #pragma var_order(fileHeader, infoHeader, fd, colorsSize, ofstruct, startOffset, colorsUsed, bufferSize) OFSTRUCT ofstruct; int fd = OpenFile(path, &ofstruct, 0); if (fd == -1) { SetErrorCode(1); return false; } BITMAPFILEHEADER fileHeader; int startOffset = _llseek(fd, 0, FILE_BEGIN); if (_lread(fd, &fileHeader, sizeof(fileHeader)) != sizeof(fileHeader)) { SetErrorCode(3); _lclose(fd); return false; } if (fileHeader.bfType != 'MB') { SetErrorCode(4); _lclose(fd); return false; } BITMAPINFOHEADER infoHeader; if (_lread(fd, &infoHeader, sizeof(infoHeader)) != sizeof(infoHeader)) { SetErrorCode(5); _lclose(fd); return false; } AllocateHeader(); if (!mBitmap) { _lclose(fd); return false; } memcpy(&mBitmap->bmiHeader, &infoHeader, sizeof(infoHeader)); int colorsUsed = getColoursUsed((BITMAPINFO *) &infoHeader); int colorsSize = colorsUsed * sizeof(RGBQUAD); if (_lread(fd, mBitmap->bmiColors, colorsSize) != colorsSize) { SetErrorCode(6); _lclose(fd); return false; } mColors = GetColors(); if (mPixels) { GlobalUnlock(GlobalHandle(mPixels)); GlobalFree(GlobalHandle(mPixels)); } int bufferSize = fileHeader.bfSize - fileHeader.bfOffBits; mPixels = (BYTE *) GlobalLock(GlobalAlloc(GMEM_MOVEABLE, bufferSize)); if (!mPixels) { SetErrorCode(11); _lclose(fd); return false; } _llseek(fd, startOffset + fileHeader.bfOffBits, FILE_BEGIN); if (_lread(fd, mPixels, bufferSize) != bufferSize) { SetErrorCode(12); _lclose(fd); return false; } _lclose(fd); return true; } static int getColoursUsed(BITMAPINFO *bmp) { BITMAPINFOHEADER *header = &bmp->bmiHeader; int bitCount = header->biBitCount; int colors; switch (bitCount) { case 1: colors = 2; break; case 4: colors = 16; break; case 8: colors = 256; break; default: colors = 0; } if (header->biClrUsed != 0) colors = header->biClrUsed; return colors; } BOOL Bitmap::InitHeader(int width, int height) { if (!mBitmap) return false; BITMAPINFOHEADER *header = &mBitmap->bmiHeader; header->biSize = sizeof(BITMAPINFOHEADER); header->biWidth = width; header->biHeight = height; header->biPlanes = 1; header->biBitCount = 8; header->biCompression = 0; header->biSizeImage = 0; header->biXPelsPerMeter = 0; header->biYPelsPerMeter = 0; header->biClrUsed = 0; header->biClrImportant = 0; return true; } BOOL Bitmap::InitGreyscalePalette() { mColors = GetColors(); for (int i = 0; i < 256; i++) { mColors->rgbRed = i; mColors->rgbGreen = i; mColors->rgbBlue = i; mColors->rgbReserved = 0; mColors++; } return true; } BOOL Bitmap::Allocate(int width, int height) { Free(); unsigned int bmiSize = sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * 256; mBitmap = (BITMAPINFO *) GlobalLock(GlobalAlloc(GMEM_MOVEABLE, bmiSize)); if (!mBitmap) return false; InitHeader(width, height); SetDefaultRect(); InitGreyscalePalette(); unsigned int bufferSize = ((width + 3) & ~3) * height; mPixels = (BYTE *) GlobalLock(GlobalAlloc(GMEM_MOVEABLE, bufferSize)); if (!mPixels) { Free(); return false; } for (unsigned int i = 0; i < bufferSize; i++) mPixels[i] = 0; return true; } void Bitmap::Draw(HDC dc, int x, int y) { StretchDIBits(dc, x, y, mBitmap->bmiHeader.biWidth, mBitmap->bmiHeader.biHeight, 0, 0, mBitmap->bmiHeader.biWidth, mBitmap->bmiHeader.biHeight, mPixels, mBitmap, DIB_RGB_COLORS, SRCCOPY); } void Bitmap::Draw(HDC dc, const RECT &rect) { int theWidth = rect.right - rect.left; int theHeight = rect.bottom - rect.top; StretchDIBits(dc, rect.left, rect.right, theWidth, theHeight, 0, 0, theWidth, theHeight, mPixels, mBitmap, DIB_RGB_COLORS, SRCCOPY); } // surely this can't be what they did??? struct LOGPALETTE256 { WORD palVersion; WORD palNumEntries; PALETTEENTRY palPalEntry[256]; }; HPALETTE Bitmap::CreatePalette() { unsigned int count = getColoursUsed(mBitmap); LOGPALETTE256 logPalette = {0x300, 256}; for (unsigned int i = 0; i < count; i++) { logPalette.palPalEntry[i].peRed = mColors[i].rgbRed; logPalette.palPalEntry[i].peGreen = mColors[i].rgbGreen; logPalette.palPalEntry[i].peBlue = mColors[i].rgbBlue; logPalette.palPalEntry[i].peFlags = 0; } HPALETTE palette = ::CreatePalette((LOGPALETTE *) &logPalette); return palette; } BOOL Bitmap::DrawBitmap(const Bitmap *bmp, RECT srcRect, RECT destRect) { #pragma var_order(x, rectWidth, y, srcHeight, rectHeight, srcBitmap, destStride, destBuffer, srcStride, srcBuffer) int rectHeight = srcRect.bottom - srcRect.top; int rectWidth = srcRect.right - srcRect.left; int srcStride = bmp->mRect.right - bmp->mRect.left; int destStride = mRect.right - mRect.left; const BYTE *srcBuffer = bmp->mPixels; BYTE *destBuffer = mPixels; const BITMAPINFO *srcBitmap = bmp->mBitmap; int srcHeight = srcBitmap->bmiHeader.biHeight; for (int x = 0, y = 0; y < rectHeight; y++) { for (x = 0; x < rectWidth; x++) { destBuffer[x + (destStride * (GetHeight() - y - 1 - destRect.top)) + destRect.left] = srcBuffer[x + (srcStride * (srcHeight - y - 1 - srcRect.top)) + srcRect.left]; } } return true; } BOOL Bitmap::DrawBitmap(const Bitmap *bmp, RECT srcRect, RECT destRect, BYTE transparentCol) { #pragma var_order(x, rectWidth, y, srcHeight, rectHeight, unk1C, srcAddress, unk24, srcBitmap, destStride, destAddress, destBuffer, srcStride, srcBuffer) int rectHeight = srcRect.bottom - srcRect.top; int rectWidth = srcRect.right - srcRect.left; int srcStride = bmp->mRect.right - bmp->mRect.left; int destStride = mRect.right - mRect.left; const BYTE *srcBuffer = bmp->mPixels; BYTE *destBuffer = mPixels; const BITMAPINFO *srcBitmap = bmp->mBitmap; int srcHeight = srcBitmap->bmiHeader.biHeight; int unk24 = 0; BYTE unk1C = transparentCol; int srcAddress, destAddress; for (int x = 0, y = 0; y < rectHeight; y++) { for (x = 0; x < rectWidth; x++) { srcAddress = x + (srcStride * (srcHeight - y - 1 - srcRect.top)) + srcRect.left; destAddress = x + (destStride * (GetHeight() - y - 1 - destRect.top)) + destRect.left; if (srcBuffer[srcAddress] != transparentCol) destBuffer[destAddress] = srcBuffer[srcAddress]; } } return true; } BOOL Bitmap::SetPalette(const Bitmap *other) { unsigned int count = getColoursUsed(other->mBitmap); for (unsigned int i = 0; i < count; i++) { mColors[i].rgbRed = other->mColors[i].rgbRed; mColors[i].rgbGreen = other->mColors[i].rgbGreen; mColors[i].rgbBlue = other->mColors[i].rgbBlue; } return true; } BYTE Bitmap::GetPixel(int x, int y) const { const BYTE *buffer = mPixels; int stride = mRect.right - mRect.left; int address = x + stride * (GetHeight() - y - 1); return mPixels[address]; } int Bitmap::GetPixel(POINT pt) const { const BYTE *buffer = mPixels; int stride = mRect.right - mRect.left; int address = pt.x + stride * (GetHeight() - pt.y - 1); return mPixels[address]; } void Bitmap::SetRect(int left, int top, int right, int bottom) { mRect.left = left; mRect.top = top; mRect.right = right; mRect.bottom = bottom; } void Bitmap::SetDefaultRect() { if (mBitmap) { BITMAPINFOHEADER *theBitmap = &mBitmap->bmiHeader; mRect.left = 0; mRect.top = 0; mRect.right = theBitmap->biWidth; mRect.bottom = theBitmap->biHeight; } else { mRect.bottom = 0; mRect.right = 0; mRect.top = 0; mRect.left = 0; } } int Bitmap::GetHeight() const { if (mBitmap) { BITMAPINFO *bmp = mBitmap; return bmp->bmiHeader.biHeight; } return 0; } int Bitmap::GetWidth() const { if (mBitmap) { BITMAPINFO *bmp = mBitmap; return bmp->bmiHeader.biWidth; } return 0; }