2016-01-27 00:37:58 chip
Page 1539
📢 PUBLIC
Jan 26 2016
MyD2D.cpp:
/*************************************************************************/
/** MyD2D.cpp: Wrapper around Direct2D, SwapChain method. **/
/** (C)2013 nlited systems, Chip Doran **/
/*************************************************************************/
#include <Windows.h>
#include <wrl.h>
#include <d2d1.h>
#include <d2d1_1.h>
#include <d3d11.h>
#include <d3d11_1.h>
#include <dwrite.h>
#include <wincodec.h>
#include <dxgidebug.h>
#include "Util.h"
#include "MyD2D.h"
using namespace Microsoft::WRL; //ComPtr<>
using namespace D2D1; //Direct2D version 1
class MyD2D {
public:
static MyD2D *Ptr(HD2D hD2D);
static int Create(HD2D *phD2D, HINSTANCE hModule);
int Destroy(void);
int CreateResourcesWnd(HWND hWnd);
int ReleaseResources(HWND hWnd);
int Resize(const RECT *pR);
int Begin(ID2D1DeviceContext **ppDC);
ID2D1DeviceContext *GetDC(void);
int End(HRESULT *pWinErr);
IDWriteTextFormat *GetTextFormatter(void);
int BitmapCreate(struct Bitmap_s *pBitmap);
//Data
UINT32 Signature;
private:
MyD2D(void);
~MyD2D(void);
int Create2(HINSTANCE hModule);
int CreateSwapChain(void);
int CreateSwapBitmap();
int BitmapCreateBMP(struct Bitmap_s *pBitmap);
int BitmapCreateOther(struct Bitmap_s *pBitmap);
//Data
HINSTANCE hInst;
HWND hWnd;
bool IsDrawing;
ID2D1Factory1 *pD2DFactory;
IDWriteFactory *pDWriteFactory;
IWICImagingFactory *pWICFactory;
ID2D1DeviceContext *pD2DC;
ComPtr<IDXGISwapChain1> pSwapChain;
IDWriteTextFormat *pTextFmt;
D2D1_PIXEL_FORMAT PxlFmt;
UINT64 PaintTime;
};
/*************************************************************************/
/** Public interface **/
/*************************************************************************/
int MyD2DCreate(HD2D *phD2D, HINSTANCE hModule) {
if(IsBadPtr(phD2D,sizeof(*phD2D),BADPTR_WRITE))
return(ERR_BADPTR);
return(MyD2D::Create(phD2D,hModule));
}
int MyD2DDestroy(HD2D hD2D) {
MyD2D *pD2D= MyD2D::Ptr(hD2D);
if(!pD2D)
return(ERR_BADHANDLE);
return(pD2D->Destroy());
}
int MyD2DCreateResourcesWnd(HD2D hD2D, HWND hWnd) {
MyD2D *pD2D= MyD2D::Ptr(hD2D);
if(!pD2D)
return(ERR_BADHANDLE);
return(pD2D->CreateResourcesWnd(hWnd));
}
int MyD2DReleaseResources(HD2D hD2D, HWND hWnd) {
MyD2D *pD2D= MyD2D::Ptr(hD2D);
if(!pD2D)
return(ERR_BADHANDLE);
return(pD2D->ReleaseResources(hWnd));
}
int MyD2DResize(HD2D hD2D,const RECT *pR) {
MyD2D *pD2D= MyD2D::Ptr(hD2D);
if(!pD2D)
return(ERR_BADHANDLE);
return(pD2D->Resize(pR));
}
int MyD2DBegin(HD2D hD2D, ID2D1DeviceContext **ppDC) {
MyD2D *pD2D= MyD2D::Ptr(hD2D);
if(!pD2D)
return(ERR_BADHANDLE);
return(pD2D->Begin(ppDC));
}
ID2D1DeviceContext *MyD2DGetDC(HD2D hD2D) {
MyD2D *pD2D= MyD2D::Ptr(hD2D);
if(!pD2D)
return(0);
return(pD2D->GetDC());
}
int MyD2DEnd(HD2D hD2D, HRESULT *pWinErr) {
MyD2D *pD2D= MyD2D::Ptr(hD2D);
if(!pD2D)
return(ERR_BADHANDLE);
return(pD2D->End(pWinErr));
}
IDWriteTextFormat *MyD2DTextFormat(HD2D hD2D) {
MyD2D *pD2D= MyD2D::Ptr(hD2D);
if(!pD2D)
return(0);
return(pD2D->GetTextFormatter());
}
int MyD2DBitmapCreate(HD2D hD2D, struct Bitmap_s *pBitmap) {
MyD2D *pD2D= MyD2D::Ptr(hD2D);
if(!pD2D)
return(ERR_BADHANDLE);
if(IsBadPtr(pBitmap,sizeof(*pBitmap),BADPTR_RW))
return(ERR_BADPTR);
return(pD2D->BitmapCreate(pBitmap));
}
/*************************************************************************/
/** Public internals **/
/*************************************************************************/
MyD2D *MyD2D::Ptr(HD2D hD2D) {
MyD2D *pD2D= (MyD2D*)hD2D;
if(!hD2D || IsBadPtr(pD2D,sizeof(*pD2D),BADPTR_RW) || pD2D->Signature!=SIGNATURE_MYD2D)
pD2D= 0;
return(pD2D);
}
int MyD2D::Create(HD2D *phD2D, HINSTANCE hModule) {
int Err= ERR_OK;
MyD2D *pD= new MyD2D;
if(!pD) {
Err= Error(ERR_NOMEM,__FUNCTION__": Unable to alloc %d",sizeof(*pD));
} else if(IsErr(Err= pD->Create2(hModule))) {
delete pD;
} else {
*phD2D= (HD2D)pD;
}
return(Err);
}
static void Report(void) {
#if 0
typedef HRESULT (__stdcall *fPtr)(const IID&, void **);
HMODULE hDLL= GetModuleHandleW(L"dxgidebug.dll");
fPtr DXIGetDebugInterface= (fPtr)GetProcAddress(hDLL,"DXGIGetDebugInterface");
DXGIGetDebugInterface(__uuidof(IDXGIDebug),(void**)&pDXGIDebug);
DXGIGetDebugInterface(__uuidof(IDXGIInfoQueue),(void**)&pIDXGIInfoQueue);
const char Name[]= "pFactory";
pFactory->SetPrivateData(WKPDID_D3DDebugObjectName,sizeof(Name)-1,Name);
IDXGIDebug *pDebug;
if(SUCCEEDED(DXGIGetDebugInterface(__uuidof(IDXGIDebug),(void**)&pDebug))) {
pDebug->ReportLiveObjects(DXGI_DEBUG_ALL,DXGI_DEBUG_RLO_ALL);
}
#endif
}
int MyD2D::Destroy(void) {
int Err= ERR_OK;
delete this;
Report();
return(Err);
}
int MyD2D::CreateResourcesWnd(HWND hWnd) {
int Err= ERR_OK;
HRESULT WinErr;
RECT rWnd;
this->hWnd= hWnd;
PxlFmt= PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM,D2D1_ALPHA_MODE_PREMULTIPLIED);
GetClientRect(hWnd,&rWnd);
//First we need a Direct2D Factory...
D2D1_FACTORY_OPTIONS options;
options.debugLevel= D2D1_DEBUG_LEVEL_INFORMATION;
if(!pD2DFactory && !SUCCEEDED(WinErr= D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED,options,&pD2DFactory)))
return(Error(ERR_SYSCREATE,__FUNCTION__": Unable to create Direct2D factory [%d]",WinErr));
if(IsErr(Err= CreateSwapChain()))
return(Error(Err,__FUNCTION__": Unable to create swap chain."));
//Then we need a text Writer Factory...
if(!pDWriteFactory) {
WinErr= DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED,__uuidof(IDWriteFactory),reinterpret_cast<IUnknown**>(&pDWriteFactory));
if(!SUCCEEDED(WinErr))
return(Error(ERR_SYSCREATE,__FUNCTION__": Unable to create WriteFactory. [%d]",WinErr));
}
//Then we need a Text Writer Formatter...
if(!pTextFmt) {
WinErr= pDWriteFactory->CreateTextFormat(L"Bitstream Vera Sans Mono",0,DWRITE_FONT_WEIGHT_NORMAL,DWRITE_FONT_STYLE_NORMAL,DWRITE_FONT_STRETCH_NORMAL,(FLOAT)12,L"en-us",&pTextFmt);
if(!SUCCEEDED(WinErr))
return(Error(ERR_SYSCREATE,__FUNCTION__": Unable to create TextFormat. [%d]",WinErr));
}
//Create WIC Factory...
if(!pWICFactory) {
//Be sure to define _WIN32_WINNT_=0x0601 in the project settings for Win7 compatibility!
if(!SUCCEEDED(WinErr= CoCreateInstance(CLSID_WICImagingFactory,0,CLSCTX_INPROC_SERVER,IID_PPV_ARGS(&pWICFactory)))) {
return(Error(ERR_SYSCREATE,__FUNCTION__": Unable to create WIC Factory. [%d]",WinErr));
}
}
return(ERR_OK);
}
int MyD2D::ReleaseResources(HWND hWnd) {
int Err= ERR_OK;
SafeRelease(pTextFmt);
SafeRelease(pDWriteFactory);
SafeRelease(pD2DC);
SafeRelease(pD2DFactory);
SafeRelease(pWICFactory);
return(Err);
}
int MyD2D::Resize(const RECT *pR) {
int Err= ERR_OK;
HRESULT WinErr;
pD2DC->SetTarget(0);
if(!SUCCEEDED(WinErr= pSwapChain->ResizeBuffers(0,0,0,DXGI_FORMAT_UNKNOWN,0))) {
Err= Error(ERR_FAILED,"MyD2D:Resize: Unable to resize swap chain buffers. [%X]",WinErr);
} else if(IsErr(Err= CreateSwapBitmap())) {
Err= Error(Err,"MyD2D:Resize: Unable to create SwapBitmap.");
}
return(Err);
}
int MyD2D::Begin(ID2D1DeviceContext **ppDC) {
int Err= ERR_OK;
LARGE_INTEGER Start,End;
if(!pD2DC)
return(ERR_NOINIT);
if(!pSwapChain.Get())
return(ERR_NOINIT);
if(IsDrawing)
return(ERR_BUSY);
IsDrawing= true;
QueryPerformanceCounter(&Start);
pD2DC->BeginDraw();
QueryPerformanceCounter(&End);
PaintTime= End.QuadPart - Start.QuadPart;
*ppDC= pD2DC;
return(Err);
}
ID2D1DeviceContext *MyD2D::GetDC(void) {
return(pD2DC);
}
int MyD2D::End(HRESULT *pWinErr) {
int Err= ERR_OK;
HRESULT WinErr= 0;
D2D1_TAG Tag1,Tag2;
LARGE_INTEGER Start,End;
if(!IsDrawing) {
Err= ERR_NOT_READY;
} else {
IsDrawing= false;
QueryPerformanceCounter(&Start);
WinErr= pD2DC->EndDraw(&Tag1,&Tag2);
if(!SUCCEEDED(WinErr)) {
Err= Error(ERR_FAILED,"MyD2D:End: DrawEnd failed: (%X:%d,%d)",WinErr,Tag1,Tag2);
} else if(!SUCCEEDED(WinErr= pSwapChain->Present(1,0))) {
Err= Error(ERR_FAILED,"MyD2D:End: Present failed: (%X)",WinErr);
}
QueryPerformanceCounter(&End);
PaintTime+= (End.QuadPart-Start.QuadPart);
if(!IsErr(Err))
Err= (int)PaintTime;
}
if(pWinErr)
*pWinErr= WinErr;
return(Err);
}
IDWriteTextFormat *MyD2D::GetTextFormatter(void) {
return(pTextFmt);
}
int MyD2D::BitmapCreate(struct Bitmap_s *pBitmap) {
int Err= ERR_OK;
if(IsErr(Err= BitmapCreateBMP(pBitmap))) {
if(IsErr(Err= BitmapCreateOther(pBitmap))) {
Err= Error(Err,__FUNCTION__": Unable to load bitmap '%S'",pBitmap->Name);
}
}
return(Err);
}
/*************************************************************************/
/** Private internals **/
/*************************************************************************/
MyD2D::MyD2D(void) {
memset(this,0,sizeof(*this));
Signature= SIGNATURE_MYD2D;
}
MyD2D::~MyD2D(void) {
Signature|= SIGNATURE_INVALID;
ReleaseResources(0);
}
int MyD2D::Create2(HINSTANCE hModule) {
int Err= ERR_OK;
hInst= hModule;
return(Err);
}
int MyD2D::CreateSwapChain(void) {
int Err= ERR_OK;
HRESULT WinErr;
ComPtr<IDXGIFactory2> pDxFactory;
ComPtr<ID3D11Device> pD3Device; //Used to draw to the back buffer
ComPtr<IDXGIDevice> pDxDevice;
ComPtr<ID2D1Device> pD2Device;
ComPtr<IDXGIAdapter> pAdapter;
DXGI_SWAP_CHAIN_DESC1 SwapProp;
//Create a D3D device
if(!SUCCEEDED(WinErr= D3D11CreateDevice(0,D3D_DRIVER_TYPE_HARDWARE,0,D3D11_CREATE_DEVICE_BGRA_SUPPORT,0,0,D3D11_SDK_VERSION,pD3Device.GetAddressOf(),0,0))) {
if(WinErr==DXGI_ERROR_UNSUPPORTED) {
Warn(ERR_NOT_SUPPORTED,__FUNCTION__": D3D hardware driver not available.");
WinErr= D3D11CreateDevice(0,D3D_DRIVER_TYPE_WARP,0,D3D11_CREATE_DEVICE_BGRA_SUPPORT,0,0,D3D11_SDK_VERSION,&pD3Device,0,0);
}
if(!SUCCEEDED(WinErr))
return(Error(ERR_SYSCREATE,__FUNCTION__": Unable to create D3D devicee. [%X]",WinErr));
}
pD3Device.As(&pDxDevice);
if(!SUCCEEDED(WinErr= pD2DFactory->CreateDevice(pDxDevice.Get(),pD2Device.GetAddressOf())))
return(Error(ERR_SYSCREATE,__FUNCTION__": Unable to create D2DDevice. [%X]",WinErr));
if(!SUCCEEDED(WinErr= pD2Device->CreateDeviceContext(D2D1_DEVICE_CONTEXT_OPTIONS_NONE,&pD2DC)))
return(Error(ERR_SYSCREATE,__FUNCTION__": Unable to create Direct2D DeviceContext. [%X]",WinErr));
if(!SUCCEEDED(WinErr= pDxDevice->GetAdapter(&pAdapter)))
return(Error(ERR_SYSCREATE,__FUNCTION__": Unable to create DxAdapter. [%X]",WinErr));
if(!SUCCEEDED(WinErr= pAdapter->GetParent(__uuidof(pDxFactory),reinterpret_cast<void**>(pDxFactory.GetAddressOf()))))
//if(!SUCCEEDED(WinErr= pAdapter->GetParent(__uuidof(IDXGIFactory2),reinterpret_cast<void**>(pDxFactory.GetAddressOf()))))
return(Error(ERR_SYSCREATE,__FUNCTION__": Unable to obtain DxFactory. [%X]",WinErr));
memset(&SwapProp,0,sizeof(SwapProp));
SwapProp.Format= DXGI_FORMAT_B8G8R8A8_UNORM;
SwapProp.SampleDesc.Count= 1;
SwapProp.BufferUsage= DXGI_USAGE_RENDER_TARGET_OUTPUT;
SwapProp.BufferCount= 2;
if(!SUCCEEDED(WinErr= pDxFactory->CreateSwapChainForHwnd(pDxDevice.Get(),hWnd,&SwapProp,0,0,pSwapChain.GetAddressOf())))
return(Error(ERR_SYSCREATE,__FUNCTION__": Unable to create swap chain. [%X]",WinErr));
if(IsErr(Err= CreateSwapBitmap()))
return(Error(Err,__FUNCTION__": Unable to create SwapBitmap."));
return(Err);
}
int MyD2D::CreateSwapBitmap() {
int Err= ERR_OK;
HRESULT WinErr;
ComPtr<IDXGISurface> pSurface;
D2D1_BITMAP_PROPERTIES1 BmpProp;
ComPtr<ID2D1Bitmap1> pBitmap;
float dpiX,dpiY;
//Create a surface on the back buffer...
if(!SUCCEEDED(WinErr= pSwapChain->GetBuffer(0,__uuidof(pSurface),reinterpret_cast<void**>(pSurface.GetAddressOf()))))
return(Error(ERR_SYSCREATE,__FUNCTION__": Unable to create DX surface. [%X]",WinErr));
//Create a bitmap on the surface...
BmpProp= BitmapProperties1(D2D1_BITMAP_OPTIONS_TARGET | D2D1_BITMAP_OPTIONS_CANNOT_DRAW,PxlFmt);
if(!SUCCEEDED(WinErr= pD2DC->CreateBitmapFromDxgiSurface(pSurface.Get(),BmpProp,pBitmap.GetAddressOf())))
return(Error(ERR_SYSCREATE,__FUNCTION__": Unable to create D2D Bitmap. [%X]",WinErr));
pD2DC->SetTarget(pBitmap.Get());
pD2DFactory->GetDesktopDpi(&dpiX,&dpiY);
pD2DC->SetDpi(dpiX,dpiY);
return(Err);
}
int MyD2D::BitmapCreateBMP(struct Bitmap_s *pBitmap) {
int Err= ERR_OK;
HRESULT WinErr;
HBITMAP hBitmap= 0;
IWICBitmap *pWICBitmap= 0;
IWICFormatConverter *pConverter= 0;
if(!pD2DC) {
Err= Error(ERR_NOINIT,__FUNCTION__": No D2DC yet, unable to load '%S'",pBitmap->Name);
} else if(!(hBitmap= LoadBitmap(hInst,pBitmap->Name))) {
//Step 1: Load and create GDI bitmap from resource (Steps 1-4 of MSDN example)
Err= Warn(ERR_NOTFOUND,__FUNCTION__": Unable to LoadBitmap(%S)!",pBitmap->Name);
} else if(!SUCCEEDED(WinErr= pWICFactory->CreateBitmapFromHBITMAP(hBitmap,0,WICBitmapIgnoreAlpha,&pWICBitmap))) {
//Step 2: Convert HBITMAP to WICBitmap
//This upscales to 32bit+Alpha
//NOTE: Ignore alpha if source doesn't have it, otherwise alpha will be zero and the bitmap will be invisible!
Err= Error(ERR_SYSCREATE,__FUNCTION__": Unable to create WIC bitmap for %S. [%d]",pBitmap->Name,WinErr);
} else if(!SUCCEEDED(WinErr= pWICFactory->CreateFormatConverter(&pConverter))) {
//Step 3: Create a WIC convert to transform bitmap to RenderTgt's native format
Err= Error(ERR_SYSCREATE,__FUNCTION__": Unable to create WIC Converter. [%d]",WinErr);
} else if(!SUCCEEDED(WinErr= pConverter->Initialize(pWICBitmap,GUID_WICPixelFormat32bppPBGRA,WICBitmapDitherTypeNone,0,0,WICBitmapPaletteTypeMedianCut))) {
//Step 4: Initialize converter to take 32bit PBGRA
Err= Error(ERR_SYSCREATE,__FUNCTION__": Unable to initialize format converter. [%d]",WinErr);
} else if(!SUCCEEDED(WinErr= pD2DC->CreateBitmapFromWicBitmap(pConverter,&pBitmap->pBitmap))) {
//Step 5: Convert WIC bitmap to RenderTgt's native format
Err= Error(ERR_SYSCREATE,__FUNCTION__": Unable to create RenderTarget bitmap. [%d]",WinErr);
} else {
pBitmap->SizeDPI= pBitmap->pBitmap->GetSize();
Debug(DBG_BITMAP,__FUNCTION__": BitmapBMP(%S) loaded as %X.",pBitmap->Name,pBitmap->pBitmap);
}
SafeRelease(pConverter);
SafeRelease(pWICBitmap);
if(hBitmap)
DeleteObject(hBitmap);
return(Err);
}
int MyD2D::BitmapCreateOther(struct Bitmap_s *pBitmap) {
int Err= ERR_OK;
HRESULT WinErr;
HRSRC hResource= 0;
HGLOBAL hData;
void *pData;
DWORD DataSz;
IWICStream *pStream= 0;
IWICBitmapDecoder *pDecoder= 0;
IWICBitmapFrameDecode *pSource= 0;
IWICFormatConverter *pConverter= 0;
if(!pD2DC) {
Err= Error(ERR_NOINIT,__FUNCTION__": No D2DC yet, unable to load '%S'",pBitmap->Name);
} else if(!(hResource= FindResource(hInst,pBitmap->Name,pBitmap->Type))) {
//Step 1: Find the resource
//NOTE: This fails for Bitmap resources (for unknown reason)
Err= Error(ERR_NOTFOUND,__FUNCTION__": Bitmap '%S' not found.",pBitmap->Name);
} else if(!(hData= LoadResource(hInst,hResource))) {
//Step 2: Load the resource into memory
Err= Error(ERR_SYSCREATE,__FUNCTION__": Unable to load resource '%S'",pBitmap->Name);
} else if(!(pData= LockResource(hData))) {
//Step 3: Lock the resource to process memory.
Err= Error(ERR_SYSCREATE,__FUNCTION__": Unable to lock resource '%S'",pBitmap->Name);
} else if(!(DataSz= SizeofResource(hInst,hResource))) {
//Step 4: Determine the size of the resource in bytes (it's still memory!)
Err= Error(ERR_SYSCREATE,__FUNCTION__": Unable to determine size of '%S'",pBitmap->Name);
} else if(!SUCCEEDED(WinErr= pWICFactory->CreateStream(&pStream))) {
//Step 5: Create the WIC stream to read the resource
Err= Error(ERR_SYSCREATE,__FUNCTION__": Unable to create WIC stream for '%S'",pBitmap->Name);
} else if(!SUCCEEDED(WinErr= pStream->InitializeFromMemory(reinterpret_cast<BYTE*>(pData),DataSz))) {
//Step 6: Initialize the stream
Err= Error(ERR_SYSCREATE,__FUNCTION__": Unable to parse bitmap '%S' stream. [%d]",pBitmap->Name,WinErr);
} else if(!SUCCEEDED(WinErr= pWICFactory->CreateDecoderFromStream(pStream,0,WICDecodeMetadataCacheOnLoad,&pDecoder))) {
//Step 7: Create a stream decoder
Err= Error(ERR_SYSCREATE,__FUNCTION__": Unable to decode '%S' [%d]",pBitmap->Name,WinErr);
} else if(!SUCCEEDED(WinErr= pDecoder->GetFrame(0,&pSource))) {
//Step 8: Read the first frame
Err= Error(ERR_SYSCREATE,__FUNCTION__": Unable to extract frame from '%S' [%d]",pBitmap->Name,WinErr);
} else if(!SUCCEEDED(WinErr= pWICFactory->CreateFormatConverter(&pConverter))) {
//Step 9: Create a format converter
Err= Error(ERR_SYSCREATE,__FUNCTION__": Unable to create format converter for '%S' [%d]",pBitmap->Name,WinErr);
} else if(!SUCCEEDED(WinErr= pConverter->Initialize(pSource,GUID_WICPixelFormat32bppPBGRA,WICBitmapDitherTypeNone,0,0,WICBitmapPaletteTypeMedianCut))) {
//Step 10: Initialize the converter
Err= Error(ERR_SYSCREATE,__FUNCTION__": Unable to convert '%S' [%d]",pBitmap->Name,WinErr);
} else if(!SUCCEEDED(WinErr= pD2DC->CreateBitmapFromWicBitmap(pConverter,0,&pBitmap->pBitmap))) {
//Step 11: Convert the bitmap from device-independent WIC to device-specific RenderTgt
Err= Error(ERR_SYSCREATE,__FUNCTION__": Unable to create RenderTgt bitmap for '%S' [%d]",pBitmap->Name,WinErr);
} else {
//Done! Retrieve the original size of the image.
pBitmap->SizeDPI= pBitmap->pBitmap->GetSize();
Debug(DBG_BITMAP,__FUNCTION__": BitmapOther(%S) loaded as %X.",pBitmap->Name,pBitmap->pBitmap);
}
SafeRelease(pConverter);
SafeRelease(pSource);
SafeRelease(pDecoder);
SafeRelease(pStream);
UnlockResource(hData);
return(ERR_OK);
}
WebV7 (C)2018 nlited | Rendered by tikope in 33.622ms | 3.16.50.1