// PixelBlock.h #ifndef PixelBlockh #define PixelBlockh #if _MSC_VER > 1000 #pragma once #endif // _MSC_VER > 1000 #include "Colors.h" // For IsGray /* To draw to the screen really fast you need an area of memory you can access directly and Blit to the screen. The following class encapsulates this using a simple call to SetDIBitsToDevice. The Pixel Block of RAM that you draw to, is an array of DWORDs each holding the colour in the format 0xRRGGBB where RR the Red, GG the Green and BB the Blue. The only other important data structure is a BITMAPINFO with its bmiHeader.biCompression set to BI_RGB. Code is included to initialise the Pixel Block by blitting from the Window to the PixelBlock. */ class CPixelBlock { BITMAPINFO BitmapInfo; protected: DWORD* Bits; WORD Width,Height; public: CPixelBlock() : Bits(0), Width(0), Height(0) {} CPixelBlock(WORD Width, WORD Height, DWORD Color=0) : Bits(new DWORD[Width*Height]), Width(Width), Height(Height) { Set(); Empty(Color); } virtual ~CPixelBlock() {try{delete[] Bits; Bits=0;}catch(...){ASSERT(0);}} void Set(WORD width, WORD height, DWORD Color=0) { if((Width==width+1)&&(Height==height+1)) return; Width=width+1; Height=height+1; Set(); delete[] Bits; Bits=new DWORD[Width*Height]; Empty(Color); } void Render(HDC hDC, int x=0, int y=0, CString Path="") { if(hDC) SetDIBitsToDevice(hDC, x,y, Width,Height, 0,0, 0,Height, Bits, &BitmapInfo, DIB_RGB_COLORS); if(!Path.IsEmpty()) Save(Path); } void Empty(DWORD Color) { if(CColors::IsGray(Color)) memset((void*)Bits, Color, Width*Height*sizeof(DWORD)); // Just uses the LSB of Color else{ // A colored background will be slower: DWORD* it=Bits; for(int i=Width*Height; i--; *it++=Color); } } bool Set(HDC hDC, WORD width, WORD height) {return Set(hDC, CRect(0,0,width,height));} // Uses whatever is currently drawn on the DC bool Set(HDC hDC, const CRect& Rect) { // Uses whatever is currently drawn on the DC Set(Rect.Width(), Rect.Height()); /* Yes, you can use GetPixel, but its _very_ slow... for(int y=Rect.top; yhDC, x,y); PixelBlock.SetPixel(x-Rect.left, y-Rect.top, c); } } */ bool OK=false; // Copy from the hDC to our Bits Array: HDC MemDC=CreateCompatibleDC(hDC); // Make a Compatible DC if(MemDC) { HBITMAP Bitmap=CreateCompatibleBitmap(hDC, Width, Height); // and a Compatible Bitmap if(Bitmap) { HGDIOBJ Old=SelectObject(MemDC, Bitmap); // Select the Compatible Bitmap into the Compatible DC if(Old) { if(BitBlt(MemDC, 0,0, Width,Height, hDC, Rect.left,Rect.top, SRCCOPY) // Blit from the DC to the Compatible DC && GetDIBits(hDC, Bitmap, 0, Height, (LPVOID)Bits, &BitmapInfo, DIB_RGB_COLORS)) OK=true; // Get the Bits from the Bitmap SelectObject(MemDC, Old); // Release the resources now the bits are in the Bitmap } DeleteObject(Bitmap); } DeleteDC(MemDC); } return OK; } WORD GetWidth () const {return Width ;} WORD GetHeight() const {return Height;} bool IsValid(WORD x, WORD y) const {return (x=Bits; ptr-=Width) File.Write(ptr, 4*Width); return true; } private: void Set() { BitmapInfo.bmiHeader.biSize =sizeof(BITMAPINFOHEADER); BitmapInfo.bmiHeader.biWidth = Width ; BitmapInfo.bmiHeader.biHeight =-Height; // Minus make the origin the same Windows BitmapInfo.bmiHeader.biPlanes =1; BitmapInfo.bmiHeader.biBitCount =32; BitmapInfo.bmiHeader.biCompression =BI_RGB; BitmapInfo.bmiHeader.biSizeImage =0; BitmapInfo.bmiHeader.biXPelsPerMeter=0; BitmapInfo.bmiHeader.biYPelsPerMeter=0; BitmapInfo.bmiHeader.biClrUsed =0; BitmapInfo.bmiHeader.biClrImportant =0; } }; #include "Colors.h" struct CPixelPainter : public CPixelBlock { CPixelPainter() {} virtual ~CPixelPainter() {} WORD GetWidth() const {return CPixelBlock::GetWidth();} void SetPixel (WORD x, WORD y, DWORD Colour) { if(IsValid(x,y)) Bits[Width*y+x] = Colour;} DWORD GetPixel (WORD x, WORD y, DWORD Colour=0) const {return IsValid(x,y) ? Bits[Width*y+x] : Colour;} DWORD* GetPointer(WORD x, WORD y) const {return IsValid(x,y) ? &Bits[Width*y+x] : 0;} void BlendPixel(WORD x, WORD y, DWORD Colour, BYTE Transparency) {SetPixel(x,y, CColors::AlphaBlend(GetPixel(x,y), Colour, Transparency));} }; #endif // ndef PixelBlockh