diff options
Diffstat (limited to 'src/Bitmap.cpp')
-rw-r--r-- | src/Bitmap.cpp | 363 |
1 files changed, 363 insertions, 0 deletions
diff --git a/src/Bitmap.cpp b/src/Bitmap.cpp new file mode 100644 index 0000000..44674d6 --- /dev/null +++ b/src/Bitmap.cpp @@ -0,0 +1,363 @@ +#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; +} |