📄 dxsurfacemgr.h
字号:
#pragma once
const HDC NULL_HDC = 0;
#include <atlbase.h>
#include <memory>
#include <ddraw.h>
#pragma comment(lib,"ddraw.lib")
BOOL DXErrorString(HRESULT hResult, LPTSTR lpszErrorBuff, DWORD cchError);
struct XRect : tagRECT
{
XRect()
{ }
XRect(int l, int t, int r, int b)
{ left = l; top = t; right = r; bottom = b; }
XRect(const RECT& srcRect)
{ ::CopyRect(this, &srcRect); }
XRect(LPCRECT lpSrcRect)
{ ::CopyRect(this, lpSrcRect); }
XRect(POINT point, SIZE size)
{ right = (left = point.x) + size.cx; bottom = (top = point.y) + size.cy; }
XRect(POINT topLeft, POINT bottomRight)
{ left = topLeft.x; top = topLeft.y;right = bottomRight.x; bottom = bottomRight.y; }
int Width() const
{ return right - left; }
int Height() const
{ return bottom - top; }
operator LPRECT()
{ return this; }
operator LPCRECT() const
{ return this; }
BOOL IsRectEmpty() const
{ return ::IsRectEmpty(this); }
BOOL IsRectNull() const
{ return (left == 0 && right == 0 && top == 0 && bottom == 0); }
BOOL PtInRect(POINT point) const
{ return ::PtInRect(this, point); }
void operator=(const RECT& srcRect)
{ ::CopyRect(this, &srcRect); }
BOOL operator==(const RECT& rect) const
{ return ::EqualRect(this, &rect); }
BOOL operator!=(const RECT& rect) const
{ return !::EqualRect(this, &rect); }
};
// this builds a 16 bit color value in 5.5.5 format (1-bit alpha mode)
#define _RGB16BIT555(r,g,b) ((b%32) + ((g%32) << 5) + ((r%32) << 10))
// this builds a 16 bit color value in 5.6.5 format (green dominate mode)
#define _RGB16BIT565(r,g,b) ((b%32) + ((g%64) << 5) + ((r%32) << 11))
interface ClrConverter
{
virtual DWORD Convert(int r, int g, int b) = 0;
};
struct CRGB8BIT : ClrConverter
{
DWORD lastasked_,lastgot_;
CComPtr<IDirectDrawSurface> srfc_;
CRGB8BIT(IDirectDrawSurface* srfc)
:srfc_(srfc), lastasked_(-1)
{ }
DWORD Convert(int r, int g, int b)
{
COLORREF dwGDIColor = RGB(r,g,b);
if(lastasked_==dwGDIColor)
return lastgot_;
lastasked_ = dwGDIColor;
COLORREF rgbT;
// Use GDI SetPixel to color match for us
HDC hdc;
if( dwGDIColor != CLR_INVALID && srfc_->GetDC(&hdc) == DD_OK)
{
rgbT = GetPixel(hdc, 0, 0); // Save current pixel value
SetPixel(hdc, 0, 0, dwGDIColor); // Set our value
srfc_->ReleaseDC(hdc);
}
// Now lock the surface so we can read back the converted color
DWORD dw = CLR_INVALID;
DDSURFACEDESC ddsd;
ddsd.dwSize = sizeof(ddsd);
HRESULT hr = srfc_->Lock( NULL, &ddsd, DDLOCK_WAIT, NULL );
if(SUCCEEDED(hr))
{
dw = *(DWORD *) ddsd.lpSurface;
// if( ddsd.ddpfPixelFormat.dwRGBBitCount < 32 ) // Mask it to bpp
dw &= (1 << ddsd.ddpfPixelFormat.dwRGBBitCount) - 1;
srfc_->Unlock(NULL);
}
// Now put the color that was there back.
if(dwGDIColor != CLR_INVALID && srfc_->GetDC(&hdc) == DD_OK)
{
SetPixel( hdc, 0, 0, rgbT );
srfc_->ReleaseDC(hdc);
}
lastgot_ = dw;
return dw;
}
};
struct CRGB24BIT : ClrConverter
{
DWORD Convert(int r, int g, int b)
{
return ((b) + ((g) << 8) + ((r) << 16));
}
};
struct CRGB32BIT : ClrConverter
{
DWORD Convert(int r, int g, int b)
{
int a = 0;
return ((b) + ((g) << 8) + ((r) << 16) + ((a) << 24));
}
};
struct CRGBTo16BIT565 : ClrConverter
{
DWORD Convert(int r, int g, int b)
{
const int scale5 = 256/32;
const int scale6 = 256/64;
return _RGB16BIT565( r / scale5, g / scale6, b / scale5 );
}
};
struct CRGBTo16BIT555 : ClrConverter
{
DWORD Convert(int r, int g, int b)
{
const int scale5 = 256/32;
return _RGB16BIT565( r / scale5, g / scale5, b / scale5 );
}
};
struct CDDSURFACEDESC:DDSURFACEDESC
{
CDDSURFACEDESC(DWORD Flags, DWORD Caps, int Width = 0, int Height = 0)
{
memset(this, 0,sizeof(CDDSURFACEDESC));
this->dwSize = sizeof(DDSURFACEDESC);
this->dwFlags = Flags;
this->ddsCaps.dwCaps = Caps;
if(Width > 0 && Height > 0)
{
this->dwHeight = Height;
this->dwWidth = Width;
}
}
};
struct CDDPIXELFORMAT:DDPIXELFORMAT
{
DWORD bitformat_;
CDDPIXELFORMAT(IDirectDrawSurface* Surface)
:bitformat_(0)
{
memset(this, 0,sizeof(DDPIXELFORMAT));
this->dwSize = sizeof(DDPIXELFORMAT);
if(SUCCEEDED(Surface->GetPixelFormat(this)))
{
bitformat_ = this->dwRGBBitCount;
}
}
bool IsValid()
{
return bitformat_ != 0?true:false;
}
DWORD GetBitCount() const
{
return bitformat_;
}
bool InRGBMode() const
{
return ( (this->dwFlags & DDPF_RGB) && !(this->dwFlags & DDPF_PALETTEINDEXED8) ) ? true: false;
}
bool InPaletteMode() const
{
return ((this->dwFlags & DDPF_PALETTEINDEXED8) || (this->dwFlags & DDPF_PALETTEINDEXEDTO8))? true: false;
}
};
struct TDoBeginPaint
{
PAINTSTRUCT m_ps;
HDC BeginPaint(HWND h)
{
return ::BeginPaint(h, &m_ps);
}
BOOL EndPaint(HWND h)
{
return ::EndPaint(h, &m_ps);
}
};
struct TDontBeginPaint
{
PAINTSTRUCT m_ps;
HDC hdc_;
TDontBeginPaint()
:hdc_(0)
{ }
HDC BeginPaint(HWND h)
{ return hdc_; }
BOOL EndPaint(HWND h)
{ return false; }
};
template <class TBEGINPAINT = TDoBeginPaint>
class CDXSurfaceMgr : public TBEGINPAINT
{
CComPtr<IDirectDraw> directdraw_;
CComPtr<IDirectDrawSurface> primarysurface_, secondarysurface_;
CComPtr<IDirectDrawClipper> clipper_;
HWND window_;
std::auto_ptr<ClrConverter> rgbconverter_;
HDC current_hdc_;
XRect current_rect_;
IDirectDrawSurface* CreateSecondarySurface(const int Width, const int Height)
{
if(NULL!=primarysurface_.p)
{
IDirectDrawSurface* ss =NULL;
CDDSURFACEDESC dds(DDSD_CAPS|DDSD_HEIGHT|DDSD_WIDTH, DDSCAPS_OFFSCREENPLAIN, Width, Height);
HRESULT hr = directdraw_->CreateSurface(&dds,&ss, NULL);
if(SUCCEEDED(hr))
return ss;
}
return NULL;
}
void fillclr(IDirectDrawSurface* surface, COLORREF BackFillColor)
{
DDBLTFX bltfx; memset(&bltfx, 0,sizeof(DDBLTFX)); bltfx.dwSize = sizeof(DDBLTFX);
// convert the rgb given into what ever pixel format we may have
bltfx.dwFillColor = rgbconverter_->Convert(GetRValue(BackFillColor),
GetGValue(BackFillColor),
GetBValue(BackFillColor));
HRESULT hr = surface->Blt(NULL, NULL, NULL, DDBLT_COLORFILL|DDBLT_WAIT,&bltfx);
}
BOOL ClientToScreen(LPRECT lpRect) const
{
if(!::ClientToScreen(window_, (LPPOINT)lpRect))
return FALSE;
return ::ClientToScreen(window_, ((LPPOINT)lpRect)+1);
}
bool SetPixel(int x, int y, UCHAR* pb, DDSURFACEDESC& ddsd, int Clr)
{
*((USHORT *)(pb + x*2 + y*ddsd.lPitch)) = Clr;
return true;
}
IDirectDrawPalette* Build256Palette()
{
IDirectDrawPalette* ddp = 0;
PALETTEENTRY pal[256];
// setup static windows entries
for(int i =0; i<10 ;i++)
{
//the first 10
pal[i].peFlags = PC_EXPLICIT;
pal[i].peRed = i;
pal[i].peGreen = pal[i].peBlue = 0;
// the last ten
pal[i+246].peFlags = PC_EXPLICIT;
pal[i+246].peRed = i+246;
pal[i+246].peGreen = pal[i].peBlue = 0;
}
// default everything else
for(i=10; i<246 ;i++)
{
pal[i].peFlags = PC_NOCOLLAPSE;
pal[i].peRed = pal[i].peGreen = pal[i].peBlue = 27;
}
HRESULT hr =directdraw_->CreatePalette(DDPCAPS_8BIT, pal, &ddp, NULL);
return ddp;
}
public:
bool IsValid()
{
return (primarysurface_.p != NULL) ? true:false;
}
bool Initialise(HWND Window)
{
if(NULL==Window) return false;
window_ = Window;
// create DirectDrawObject
HRESULT hr = ::DirectDrawCreate(NULL, &directdraw_.p,NULL);
if (FAILED(hr)) return false;
hr = directdraw_->SetCooperativeLevel(window_,DDSCL_NORMAL);
if (FAILED(hr)) return false;
// create primary surface
CDDSURFACEDESC dds(DDSD_CAPS, DDSCAPS_PRIMARYSURFACE);
hr = directdraw_->CreateSurface(&dds,&primarysurface_.p, NULL);
if (FAILED(hr)) return false;
// attach clipper to window all blits will
// then be clipped to the primary surface
hr = directdraw_->CreateClipper(0, &clipper_.p, NULL);
if (FAILED(hr)) return false;
hr = clipper_->SetHWnd(0, window_);
if (FAILED(hr)) return false;
// attach clipper to primary surface
hr = primarysurface_->SetClipper(clipper_);
if (FAILED(hr)) return false;
// work out the pixel format for colour conversions
CDDPIXELFORMAT pf(primarysurface_.p);
if(pf.IsValid())
{
if(pf.InRGBMode())
{
DWORD tst = pf.GetBitCount();
if(15 == tst) // 16 bit 555
{
std::auto_ptr<ClrConverter> rgbconverter(new CRGBTo16BIT555);
rgbconverter_ = rgbconverter;
}
if(16 == tst) // 16 bit 565
{
std::auto_ptr<ClrConverter> rgbconverter(new CRGBTo16BIT565);
rgbconverter_ = rgbconverter;
}
if(24 == tst) // 24 bit
{
std::auto_ptr<ClrConverter> rgbconverter(new CRGB24BIT);
rgbconverter_ = rgbconverter;
}
if(32 == tst) // 32 bit
{
std::auto_ptr<ClrConverter> rgbconverter(new CRGB32BIT);
rgbconverter_ = rgbconverter;
}
}
else if(pf.InPaletteMode())
{
std::auto_ptr<ClrConverter> rgbconverter(new CRGB8BIT(primarysurface_));
rgbconverter_ = rgbconverter;
}
else
{
ATLTRACE("u r living on borrowed time - please retire now\n");
}
}
return true;
}
HDC& BeginPaint(COLORREF BackFillColor = 0)
{
current_hdc_ = NULL_HDC;
if(!IsValid()) return current_hdc_;
TBEGINPAINT::BeginPaint(window_);
XRect client; ::GetClientRect(window_, &client); ClientToScreen(&client);
// only create new secondary surface if the window has changed size
if(current_rect_!=client)
{
secondarysurface_ = CreateSecondarySurface(client.Width(), client.Height());
if(NULL==secondarysurface_.p) return current_hdc_;
current_rect_ = client;
}
// fill the secondary surface
fillclr(secondarysurface_, BackFillColor);
// GetDC will _lock_ the surface for us
secondarysurface_->GetDC(¤t_hdc_);
return current_hdc_;
}
bool EndPaint()
{
if(NULL_HDC!=current_hdc_)
{
// ReleaseDC will unlock the surface
secondarysurface_->ReleaseDC(current_hdc_);
// copy all of the secondary surface onto the primary
HRESULT hr = primarysurface_->Blt(¤t_rect_, // destination
secondarysurface_, NULL, // Source surface, Source rectangle NULL = entire surface
DDBLT_WAIT, NULL);
if(SUCCEEDED(hr))
{
TBEGINPAINT::EndPaint(window_);
return true;
}
}
return false;
}
};
typedef CDXSurfaceMgr<TDoBeginPaint> CDXSurfaceManager;
// use this one if you call your BeginPaint/EndPaint or use CDC
typedef CDXSurfaceMgr<TDontBeginPaint> CDXSurfaceManager_NBP;
static BOOL DXErrorString(HRESULT hResult, LPTSTR lpszErrorBuff, DWORD cchError)
{
DWORD cLen;
LPTSTR lpszError;
TCHAR szMsg[1024];
// Check parameters
if (!lpszErrorBuff || !cchError)
{
// Error, invalid parameters
return FALSE;
}
switch (hResult)
{
case DD_OK:
// The request completed successfully.
lpszError = TEXT("DD_OK");
break;
case DDERR_ALREADYINITIALIZED:
// The object has already been initialized.
lpszError = TEXT("DDERR_ALREADYINITIALIZED");
break;
case DDERR_BLTFASTCANTCLIP:
// A DirectDrawClipper object is attached to a source surface
// that has passed into a call to the IDirectDrawSurface2::BltFast method.
lpszError = TEXT("DDERR_BLTFASTCANTCLIP");
break;
case DDERR_CANNOTATTACHSURFACE:
// A surface cannot be attached to another requested surface.
lpszError = TEXT("DDERR_CANNOTATTACHSURFACE");
break;
case DDERR_CANNOTDETACHSURFACE:
// A surface cannot be detached from another requested surface.
lpszError = TEXT("DDERR_CANNOTDETACHSURFACE");
break;
case DDERR_CANTCREATEDC:
// Windows cannot create any more device contexts (DCs).
lpszError = TEXT("DDERR_CANTCREATEDC");
break;
case DDERR_CANTDUPLICATE:
// Primary and 3D surfaces, or surfaces that are
// implicitly created, cannot be duplicated.
lpszError = TEXT("DDERR_CANTDUPLICATE");
break;
case DDERR_CANTLOCKSURFACE:
// Access to this surface is refused because an
// attempt was made to lock the primary surface without DCI support.
lpszError = TEXT("DDERR_CANTLOCKSURFACE");
break;
case DDERR_CANTPAGELOCK:
// An attempt to page lock a surface failed.
// Page lock will not work on a display-memory
// surface or an emulated primary surface.
lpszError = TEXT("DDERR_CANTPAGELOCK");
break;
case DDERR_CANTPAGEUNLOCK:
// An attempt to page unlock a surface failed.
// Page unlock will not work on a display-memory
// surface or an emulated primary surface.
lpszError = TEXT("DDERR_CANTPAGEUNLOCK");
break;
case DDERR_CLIPPERISUSINGHWND:
// An attempt was made to set a clip list for a DirectDrawClipper
// object that is already monitoring a window handle.
lpszError = TEXT("DDERR_CLIPPERISUSINGHWND");
break;
case DDERR_COLORKEYNOTSET:
// No source color key is specified for this operation
lpszError = TEXT("DDERR_COLORKEYNOTSET");
break;
case DDERR_CURRENTLYNOTAVAIL:
// No support is currently available.
lpszError = TEXT("DDERR_CURRENTLYNOTAVAIL");
break;
case DDERR_DCALREADYCREATED:
// A device context (DC) has already been returned for this surface.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -