296 lines
6.1 KiB
C++
296 lines
6.1 KiB
C++
|
#include "bltcanvas.h"
|
||
|
#include <tataki/bitmap/bitmap.h>
|
||
|
|
||
|
BltCanvas::~BltCanvas()
|
||
|
{
|
||
|
if (hdc == NULL) return ;
|
||
|
|
||
|
// kill the bitmap and its DC
|
||
|
SelectObject(hdc, prevbmp);
|
||
|
if (ourbmp)
|
||
|
{
|
||
|
//GdiFlush();
|
||
|
DeleteObject(hbmp);
|
||
|
}
|
||
|
DeleteDC(hdc);
|
||
|
hdc = NULL;
|
||
|
|
||
|
if (skinbmps)
|
||
|
{
|
||
|
for (int i=0;i<skinbmps->getNumItems();i++)
|
||
|
skinbmps->enumItem(i)->Release();
|
||
|
|
||
|
delete skinbmps;
|
||
|
}
|
||
|
if (envelope)
|
||
|
envelope->Release();
|
||
|
}
|
||
|
|
||
|
BltCanvas::BltCanvas(HBITMAP bmp)
|
||
|
{
|
||
|
prevbmp = NULL;
|
||
|
bits = NULL;
|
||
|
fcoord = TRUE;
|
||
|
ourbmp = FALSE;
|
||
|
skinbmps = NULL;
|
||
|
envelope = NULL;
|
||
|
|
||
|
hbmp = bmp;
|
||
|
ASSERT(hbmp != NULL);
|
||
|
|
||
|
// create tha DC
|
||
|
hdc = CreateCompatibleDC(NULL);
|
||
|
prevbmp = (HBITMAP)SelectObject(hdc, hbmp);
|
||
|
}
|
||
|
|
||
|
BltCanvas::BltCanvas()
|
||
|
{
|
||
|
hbmp = NULL;
|
||
|
prevbmp = NULL;
|
||
|
bits = NULL;
|
||
|
fcoord = TRUE;
|
||
|
ourbmp = FALSE;
|
||
|
bpp = 32; // TODO: benski> pass as parameter?
|
||
|
skinbmps = NULL;
|
||
|
envelope = NULL;
|
||
|
hdc = CreateCompatibleDC(NULL);
|
||
|
}
|
||
|
|
||
|
BltCanvas::BltCanvas(int w, int h, HWND wnd, int nb_bpp/*, unsigned char *pal, int palsize*/)
|
||
|
{
|
||
|
hbmp = NULL;
|
||
|
prevbmp = NULL;
|
||
|
bits = NULL;
|
||
|
fcoord = TRUE;
|
||
|
ourbmp = FALSE;
|
||
|
bpp = nb_bpp;
|
||
|
skinbmps = NULL;
|
||
|
envelope = NULL;
|
||
|
hdc = CreateCompatibleDC(NULL);
|
||
|
AllocBitmap(w,h,nb_bpp);
|
||
|
|
||
|
if (hbmp)
|
||
|
{
|
||
|
// create tha DC
|
||
|
|
||
|
if (!hdc) {
|
||
|
// int x = GetLastError();
|
||
|
}
|
||
|
prevbmp = (HBITMAP)SelectObject(hdc, hbmp);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void BltCanvas::AllocBitmap(int w, int h, int nb_bpp)
|
||
|
{
|
||
|
ASSERT(!hbmp);
|
||
|
ASSERT(w != 0 && h != 0);
|
||
|
if (w == 0) w = 1;
|
||
|
if (h == 0) h = 1;
|
||
|
|
||
|
BITMAPINFO bmi;
|
||
|
MEMZERO(&bmi, sizeof(BITMAPINFO));
|
||
|
//bmi.bmiHeader.biClrUsed = 0; // we memzero above, no need
|
||
|
//bmi.bmiHeader.biClrImportant = 0; // we memzero above, no need
|
||
|
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
|
||
|
bmi.bmiHeader.biWidth = ABS(w);
|
||
|
bmi.bmiHeader.biHeight = -ABS(h);
|
||
|
bmi.bmiHeader.biPlanes = 1;
|
||
|
bmi.bmiHeader.biBitCount = nb_bpp;
|
||
|
bmi.bmiHeader.biCompression = BI_RGB;
|
||
|
//bmi.bmiHeader.biSizeImage = 0; // we memzero above, no need
|
||
|
//bmi.bmiHeader.biXPelsPerMeter = 0; // we memzero above, no need
|
||
|
//bmi.bmiHeader.biYPelsPerMeter = 0; // we memzero above, no need
|
||
|
//GdiFlush();
|
||
|
hbmp = CreateDIBSection(hdc, &bmi, DIB_RGB_COLORS, &bits, NULL, 0);
|
||
|
|
||
|
if (hbmp == NULL)
|
||
|
{
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
ourbmp=TRUE;
|
||
|
GetObject(hbmp, sizeof(BITMAP), &bm);
|
||
|
width = bm.bmWidth;
|
||
|
height = ABS(bm.bmHeight);
|
||
|
pitch = bm.bmWidthBytes;
|
||
|
}
|
||
|
|
||
|
void *BltCanvas::getBits()
|
||
|
{
|
||
|
return bits;
|
||
|
}
|
||
|
|
||
|
HBITMAP BltCanvas::getBitmap()
|
||
|
{
|
||
|
return hbmp;
|
||
|
}
|
||
|
|
||
|
SkinBitmap *BltCanvas::getSkinBitmap()
|
||
|
{
|
||
|
// make a SkinBitmap envelope
|
||
|
if (!envelope)
|
||
|
envelope = new SkinBitmap(getBitmap(), getHDC(), 1, getBits());
|
||
|
|
||
|
// do not delete envelope, it's deleted in destructor
|
||
|
return envelope;
|
||
|
}
|
||
|
|
||
|
SkinBitmap *BltCanvas::makeSkinBitmap()
|
||
|
{
|
||
|
// make a clone of the bitmap - JF> what was that crap about envelopes?
|
||
|
SkinBitmap *clone = new SkinBitmap(getBitmap(), getHDC(), 1);
|
||
|
|
||
|
if (!skinbmps)
|
||
|
skinbmps = new PtrList<SkinBitmap>;
|
||
|
skinbmps->addItem(clone);
|
||
|
|
||
|
return clone;
|
||
|
}
|
||
|
|
||
|
void BltCanvas::disposeSkinBitmap(SkinBitmap *b)
|
||
|
{
|
||
|
if (skinbmps->haveItem(b))
|
||
|
{
|
||
|
skinbmps->removeItem(b);
|
||
|
b->Release();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
DebugString("disposeSkinBitmap called on unknown pointer, you should call it from the object used to makeSkinBitmap()\n");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void BltCanvas::fillBits(COLORREF color)
|
||
|
{
|
||
|
if (bpp == 32)
|
||
|
{ // clear out the bits
|
||
|
DWORD *dwbits = (DWORD *)bits;
|
||
|
MEMFILL<DWORD>(dwbits, color, bm.bmWidth * bm.bmHeight);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void BltCanvas::vflip(int vert_cells)
|
||
|
{
|
||
|
ASSERT(bits != NULL);
|
||
|
// BITMAP bm;
|
||
|
// int r = GetObject(hbmp, sizeof(BITMAP), &bm);
|
||
|
// if (r == 0) return;
|
||
|
int w = bm.bmWidth, h = bm.bmHeight;
|
||
|
int bytes = 4 * w;
|
||
|
__int8 *tmpbuf = (__int8 *)MALLOC(bytes);
|
||
|
if (tmpbuf)
|
||
|
{
|
||
|
int cell_h = h / vert_cells;
|
||
|
for (int j = 0; j < vert_cells; j++)
|
||
|
for (int i = 0; i < cell_h / 2; i++)
|
||
|
{
|
||
|
char *p1, *p2;
|
||
|
p1 = (__int8 *)bits + bytes * i + (j * cell_h * bytes);
|
||
|
p2 = (__int8 *)bits + bytes * ((cell_h - 1) - i) + (j * cell_h * bytes);
|
||
|
if (p1 == p2) continue;
|
||
|
MEMCPY(tmpbuf, p1, bytes);
|
||
|
MEMCPY(p1, p2, bytes);
|
||
|
MEMCPY(p2, tmpbuf, bytes);
|
||
|
}
|
||
|
FREE(tmpbuf);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void BltCanvas::hflip(int hor_cells)
|
||
|
{
|
||
|
ASSERT(bits != NULL);
|
||
|
// todo: optimize
|
||
|
int w = bm.bmWidth, h = bm.bmHeight;
|
||
|
for (int i = 0;i < hor_cells;i++)
|
||
|
for (int x = 0;x < w / 2 / hor_cells;x++)
|
||
|
for (int y = 0;y < h;y++)
|
||
|
{
|
||
|
int *p = ((int *)bits) + x + y * w + (i * w / hor_cells);
|
||
|
int *d = ((int *)bits) + ((w / hor_cells) - x) + y * w + (i * w / hor_cells) - 1;
|
||
|
int t = *p;
|
||
|
*p = *d;
|
||
|
*d = t;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void BltCanvas::maskColor(COLORREF from, COLORREF to)
|
||
|
{
|
||
|
int n = bm.bmWidth * bm.bmHeight;
|
||
|
//GdiFlush();
|
||
|
DWORD *b = (DWORD *)getBits();
|
||
|
from &= 0xffffff;
|
||
|
while (n--)
|
||
|
{
|
||
|
if ((*b & 0xffffff) == from)
|
||
|
{
|
||
|
*b = to;
|
||
|
}
|
||
|
else *b |= 0xff000000; // force all other pixels non masked
|
||
|
b++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void BltCanvas::makeAlpha(int newalpha)
|
||
|
{
|
||
|
int w, h;
|
||
|
getDim(&w, &h, NULL);
|
||
|
premultiply((ARGB32 *)getBits(), w*h, newalpha);
|
||
|
}
|
||
|
|
||
|
#if 0
|
||
|
void BltCanvas::premultiply(ARGB32 *m_pBits, int nwords, int newalpha)
|
||
|
{
|
||
|
if (newalpha == -1)
|
||
|
{
|
||
|
for (; nwords > 0; nwords--, m_pBits++)
|
||
|
{
|
||
|
unsigned char *pixel = (unsigned char *)m_pBits;
|
||
|
unsigned int alpha = pixel[3];
|
||
|
if (alpha == 255) continue;
|
||
|
pixel[0] = (pixel[0] * alpha) >> 8; // blue
|
||
|
pixel[1] = (pixel[1] * alpha) >> 8; // green
|
||
|
pixel[2] = (pixel[2] * alpha) >> 8; // red
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
for (; nwords > 0; nwords--, m_pBits++)
|
||
|
{
|
||
|
unsigned char *pixel = (unsigned char *)m_pBits;
|
||
|
pixel[0] = (pixel[0] * newalpha) >> 8; // blue
|
||
|
pixel[1] = (pixel[1] * newalpha) >> 8; // green
|
||
|
pixel[2] = (pixel[2] * newalpha) >> 8; // red
|
||
|
pixel[3] = (pixel[3] * newalpha) >> 8; // alpha
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
// benski> this may not be completely safe. it's meant for skinbitmap::blittorect
|
||
|
// it doesn't take into account skin bitmaps, enveloped bitmaps, or any other things like that
|
||
|
void BltCanvas::DestructiveResize(int w, int h, int nb_bpp)
|
||
|
{
|
||
|
if (hdc != NULL)
|
||
|
{
|
||
|
SelectObject(hdc, prevbmp);
|
||
|
prevbmp=0;
|
||
|
}
|
||
|
|
||
|
if (ourbmp && hbmp)
|
||
|
{
|
||
|
DeleteObject(hbmp);
|
||
|
hbmp=NULL;
|
||
|
ourbmp=FALSE;
|
||
|
}
|
||
|
|
||
|
// create tha DC
|
||
|
if (hdc == NULL)
|
||
|
hdc = CreateCompatibleDC(NULL);
|
||
|
|
||
|
AllocBitmap(w,h,nb_bpp);
|
||
|
|
||
|
prevbmp = (HBITMAP)SelectObject(hdc, hbmp);
|
||
|
if (envelope) envelope->Release();
|
||
|
envelope=0;
|
||
|
}
|