summaryrefslogtreecommitdiff
path: root/src/Bitmap.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/Bitmap.cpp')
-rw-r--r--src/Bitmap.cpp363
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;
+}