Hi, there !
I´ve tried the Bitmap Opacity Masking Example.
Get it from here:
http://msdn.microsoft.com/en-us/library/dd372307(VS.85).aspx
The >Bitmap-Opacity-Mask< is always opaque and not transparent, I see no checkerboard thru.
e.g. tried loading 8bit,32bit,straight,premueltiplied,tif,bmp for it.
Maybe you know how to fix this, it´s nearly the original sample.
Do I have to specially load any exotic-prepared bitmaps ? Or are any exotic parameters wrong ?
I couldn´t understand why this sample mustn´t work.
My Opacity Mask Sample I´ve changed this little bit:
Changed BitmaploadfromResource into BitmaploadfromFile (beneath identical).
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// Copyright (c) Microsoft Corporation. All rights reserved
//+-----------------------------------------------------------------------------
//
//
// $Description:
// Sample DirectWrite Application
//
// $ENDTAG
//
//------------------------------------------------------------------------------
#include "stdafx.h"
/******************************************************************
* *
* WinMain *
* *
* Application entrypoint *
* *
******************************************************************/
int WINAPI WinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
HRESULT hr;
if (SUCCEEDED(CoInitialize(NULL)))
{
{
DemoApp app;
if (SUCCEEDED(hr = app.Initialize()))
{
app.RunMessageLoop();
}
}
CoUninitialize();
}
return SUCCEEDED(hr) ? EXIT_SUCCESS : EXIT_FAILURE;
}
/******************************************************************
* *
* DemoApp::DemoApp constructor *
* *
* Initialize member data *
* *
******************************************************************/
DemoApp::DemoApp() :
m_hwnd(NULL)
{
}
/******************************************************************
* *
* DemoApp::~DemoApp destructor *
* *
* Tear down resources *
* *
******************************************************************/
DemoApp::~DemoApp()
{
}
/******************************************************************
* *
* DemoApp::Initialize *
* *
* Create application window and device-independent resources *
* *
******************************************************************/
HRESULT DemoApp::Initialize()
{
WNDCLASSEX wcex;
HRESULT hr;
ATOM atom;
IFR(CreateDeviceIndependentResources());
// Register window class
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = DemoApp::WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = sizeof(LONG_PTR);
wcex.hInstance = HINST_THISCOMPONENT;
wcex.hbrBackground = NULL;
wcex.lpszMenuName = NULL;
wcex.hIcon = LoadIcon(
NULL,
IDI_APPLICATION
);
wcex.hCursor = LoadCursor(
NULL,
IDC_ARROW
);
wcex.lpszClassName = TEXT("D2DDemoApp");
wcex.hIconSm = LoadIcon(
NULL,
IDI_APPLICATION
);
atom = RegisterClassEx(
&wcex
);
IFR(atom ? S_OK : E_FAIL);
//
// Create Window takes its size in Pixels, so, to have a consistent DIP size, you
// obtain the DPI and use it to scale the window size.
FLOAT dpiX, dpiY;
//
// The factory returns the current system DPI. This is also the value it will use
// to create its own windows.
//
m_spD2DFactory->GetDesktopDpi(&dpiX, &dpiY);
// Create window
m_hwnd = CreateWindow(
TEXT("D2DDemoApp"),
TEXT("Direct2D Demo App"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
static_cast<UINT>(dpiX * 800.f / 96.f),
static_cast<UINT>(dpiY * 800.f / 96.f),
NULL,
NULL,
HINST_THISCOMPONENT,
this
);
IFR(m_hwnd ? S_OK : E_FAIL);
ShowWindow(m_hwnd, SW_SHOWNORMAL);
UpdateWindow(m_hwnd);
return hr;
}
/******************************************************************
* *
* DemoApp::CreateDeviceIndependentResources *
* *
* This method is used to create resources which are not bound *
* to any device. Their lifetime effectively extends for the *
* duration of the app. *
* *
******************************************************************/
HRESULT DemoApp::CreateDeviceIndependentResources()
{
HRESULT hr = S_OK;
// Create WIC factory
IFR(CoCreateInstance(
CLSID_WICImagingFactory,
NULL,
CLSCTX_INPROC_SERVER,
IID_IWICImagingFactory,
reinterpret_cast<void **>(&m_spWICFactory)
));
// Create Direct2D factory
IFR(D2D1CreateFactory(
D2D1_FACTORY_TYPE_SINGLE_THREADED,
&m_spD2DFactory
));
// Create a shared DirectWrite factory
IFR(DWriteCreateFactory(
DWRITE_FACTORY_TYPE_SHARED,
__uuidof(IDWriteFactory),
reinterpret_cast<IUnknown**>(&m_spDWriteFactory)
));
m_spD2DFactory->CreateRectangleGeometry(D2D1::RectF(0,5,200,195),&m_spRectGeo);
m_wszOriginalBitmapText=L"Original Bitmap";
m_wszBitmapBrushOpacityMaskText=L"Bitmap Opacity Mask";
m_wszLinearGradientOpacityMaskText=L"Linear Gradient Opacity Mask";
m_wszRadialGradientOpacityMaskText=L"Radial Gradient Opacity Mask";
m_wszWithBitmapBrushOpacityMaskText=L"Bitmap With Bitmap Opacity Mask Applied";
m_wszWithLinearGradientOpacityMaskText=L"Bitmap With Linear Gradient Opacity Mask Applied";
m_wszWithRadialGradientOpacityMaskText=L"Bitmap With Radial Gradient Opacity Mask Applied";
// Create a text format.
IFR(m_spDWriteFactory->CreateTextFormat(
L"Verdana", //font family name
NULL, //font collection (NULL sets it to use the system font collection)
DWRITE_FONT_WEIGHT_REGULAR,
DWRITE_FONT_STYLE_NORMAL,
DWRITE_FONT_STRETCH_NORMAL,
12.0f,
L"en-us",
&m_spTextFormat
));
return hr;
}
/******************************************************************
* *
* DemoApp::CreateDeviceResources *
* *
* This method creates resources which are bound to a particular *
* D3D device. It's all centralized here, in case the resources *
* need to be recreated in case of D3D device loss (eg. display *
* change, remoting, removal of video card, etc). *
* *
******************************************************************/
HRESULT DemoApp::CreateDeviceResources()
{
HRESULT hr = S_OK;
if (!m_spRT)
{
RECT rc;
GetClientRect(m_hwnd, &rc);
D2D1_SIZE_U size = D2D1::SizeU(
rc.right - rc.left,
rc.bottom - rc.top
);
// Create a Direct2D render target
IFR(m_spD2DFactory->CreateHwndRenderTarget(
D2D1::RenderTargetProperties(),
D2D1::HwndRenderTargetProperties(
m_hwnd,
size
),
&m_spRT
));
IFR(m_spRT->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::Black),&m_spBlackBrush));
//Create the bitmap to be used by the bitmap brush
// Instead of loadingFromResource this is the only part I changed in this sample
// But unlikely the official text-samples haven´t got the images with it
LoadBitmapFromFile(m_spRT,
m_spWICFactory,
L"V:\\GRAPHIK space 4D\\Masking Test.bmp",
0,
0,
&m_spBitmap
);
LoadBitmapFromFile(m_spRT,
m_spWICFactory,
L"V:\\GRAPHIK space 4D\\Masking Test2.bmp",
0,
0,
&m_spBitmapMask
);
D2D1_BITMAP_BRUSH_PROPERTIES propertiesXClampYClamp = { D2D1_EXTEND_MODE_CLAMP, D2D1_EXTEND_MODE_CLAMP,
D2D1_BITMAP_INTERPOLATION_MODE_NEAREST_NEIGHBOR };
IFR(m_spRT->CreateBitmapBrush(
m_spBitmap,
propertiesXClampYClamp,
&m_spOriginalBitmapBrush));
IFR(m_spRT->CreateBitmapBrush(
m_spBitmapMask,
propertiesXClampYClamp,
&m_spBitmapMaskBrush));
//Create an array of gradient stops to put in the gradient stop collection which will be used in the linear
gradient brush
D2D1_GRADIENT_STOP gradientStops[2];
gradientStops[0].color = D2D1::ColorF(D2D1::ColorF::Black,1.0f);
gradientStops[0].position = 0.0f;
gradientStops[1].color = D2D1::ColorF(D2D1::ColorF::White,0.0f);
gradientStops[1].position = 1.0f;
//Create the ID2D1GradientStopCollection from a previously declared array of D2D1_GRADIENT_STOP structs
IFR(m_spRT->CreateGradientStopCollection(gradientStops,
2,
D2D1_GAMMA_2_2,
D2D1_EXTEND_MODE_CLAMP,
&m_spGradientStopCollection));
//The line that determines the direction of the gradient starts at the top left corner of the box to the
bottom right corner
IFR(m_spRT->CreateLinearGradientBrush(D2D1::LinearGradientBrushProperties(D2D1::Point2F(0,0),D2D1::Point2F
(200,200)),
m_spGradientStopCollection,
&m_spLinearGradientBrush));
//The center of the gradient is in the center of the box. The gradient origin offset was set to zero(0,0) or
center in this case.
IFR(m_spRT->CreateRadialGradientBrush(D2D1::RadialGradientBrushProperties(D2D1::Point2F(100,100),
D2D1::Point2F(0,0), 100,100),
m_spGradientStopCollection,
&m_spRadialGradientBrush));
// Create the compatible render target
ID2D1BitmapRenderTargetPtr spCompatibleRenderTarget;
IFR(m_spRT->CreateCompatibleRenderTarget(D2D1::SizeF(20.0f, 20.0f),
&spCompatibleRenderTarget));
// Create the pattern
ID2D1SolidColorBrushPtr spWhiteBrush;
IFR(spCompatibleRenderTarget->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::White),
&spWhiteBrush));
ID2D1SolidColorBrushPtr spGrayBrush;
IFR(spCompatibleRenderTarget->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::LightGray),
&spGrayBrush));
//Draw filled rectangles onto the render target
spCompatibleRenderTarget->BeginDraw();
spCompatibleRenderTarget->FillRectangle(D2D1::RectF(0.0f, 0.0f, 10.0f, 10.0f), spGrayBrush);
spCompatibleRenderTarget->FillRectangle(D2D1::RectF(10.0f, 0.0f, 20.0f, 10.0f), spWhiteBrush);
spCompatibleRenderTarget->FillRectangle(D2D1::RectF(10.0f, 10.0f, 20.0f, 20.0f), spGrayBrush);
spCompatibleRenderTarget->FillRectangle(D2D1::RectF(0.0f, 10.0f, 10.0f, 20.0f), spWhiteBrush);
spCompatibleRenderTarget->EndDraw();
//Get the bitmap from the render target.
IFR(spCompatibleRenderTarget->GetBitmap(&m_spCheckeredBitmap));
//Choose the tiling mode for the bitmap brush
D2D1_BITMAP_BRUSH_PROPERTIES brushProperties = D2D1::BitmapBrushProperties(D2D1_EXTEND_MODE_WRAP,
D2D1_EXTEND_MODE_WRAP);
//Create the bitmap brush
IFR(m_spRT->CreateBitmapBrush(m_spCheckeredBitmap, brushProperties, &m_spCheckerPatternBitmapBrush));
}
return hr;
}
/******************************************************************
* *
* DemoApp::DiscardDeviceResources *
* *
* Discard device-specific resources which need to be recreated *
* when a D3D device is lost *
* *
******************************************************************/
void DemoApp::DiscardDeviceResources()
{
m_spRT = NULL;
m_spBlackBrush = NULL;
m_spLinearGradientBrush = NULL;
m_spRadialGradientBrush = NULL;
m_spOriginalBitmapBrush = NULL;
m_spGradientStopCollection = NULL;
m_spCheckerPatternBitmapBrush = NULL;
}
/******************************************************************
* *
* DemoApp::RunMessageLoop *
* *
* Main window message loop *
* *
******************************************************************/
void DemoApp::RunMessageLoop()
{
MSG msg;
while (GetMessage(&msg, NULL, 0, 0)>0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
/******************************************************************
* *
* DemoApp::OnRender *
* *
* Called whenever the application needs to display the client *
* window. *
* *
* Note that this function will not render anything if the window *
* is occluded (eg. obscured by other windows or off monitor). *
* Also, this function will automatically discard device-specific *
* resources if the D3D device disappears during execution, and *
* will recreate the resources the next time it's invoked. *
* *
******************************************************************/
HRESULT DemoApp::OnRender(const PAINTSTRUCT &ps)
{
HRESULT hr;
IFR(DrawD2DContent(ps));
return hr;
}
/******************************************************************
* *
* DemoApp::DrawD2DContent *
* *
* This method draws blocks demonstrating different opacity *
* masks. *
* *
* *
* Note that this function will not render anything if the window *
* is occluded (eg. obscured by other windows or off monitor). *
* Also, this function will automatically discard device-specific *
* resources if the D3D device disappears during execution, and *
* will recreate the resources the next time it's invoked. *
* *
******************************************************************/
HRESULT DemoApp::DrawD2DContent(const PAINTSTRUCT &ps)
{
HRESULT hr = S_OK;
CreateDeviceResources();
if (!(m_spRT->CheckWindowState() & D2D1_WINDOW_STATE_OCCLUDED))
{
m_spRT->BeginDraw();
m_spRT->SetTransform(
D2D1::Matrix3x2F::Identity()
);
//Rectangle that holds the shape of rectangles to be filled with brushes
D2D1_RECT_F rcBrushRect = D2D1::RectF(0,5, 200, 195);
//Rectangle that holds the shape of rectangles where captions are drawn with DrawText
D2D1_RECT_F rcTextRect = D2D1::RectF(5,205,200,300);
//Starting with a white background
m_spRT->Clear(D2D1::ColorF(D2D1::ColorF::Blue));
////Original Bitmap
m_spRT->SetTransform(D2D1::Matrix3x2F::Translation(D2D1::SizeF(5, 5)));
m_spRT->FillRectangle(&rcBrushRect,m_spOriginalBitmapBrush);
m_spRT->DrawRectangle(&rcBrushRect,m_spBlackBrush,1,NULL);
//
// m_spRT->DrawBitmap(m_spOpacityMask);
//
//Caption using a DirectWrite format from m_spDWriteFactory->CreateTextFormat
m_spRT->DrawText(m_wszOriginalBitmapText,
wcslen(m_wszOriginalBitmapText),
m_spTextFormat,
&rcTextRect,
m_spBlackBrush);
//Linear Gradient Opacity Mask
m_spRT->SetTransform(D2D1::Matrix3x2F::Translation(D2D1::SizeF(255, 5)));
m_spRT->FillRectangle(&rcBrushRect,m_spCheckerPatternBitmapBrush);
m_spRT->FillRectangle(&rcBrushRect,m_spLinearGradientBrush);
m_spRT->DrawRectangle(&rcBrushRect,m_spBlackBrush,1,NULL);
//Caption using a DirectWrite format from m_spDWriteFactory->CreateTextFormat
m_spRT->DrawText(m_wszLinearGradientOpacityMaskText,
wcslen(m_wszLinearGradientOpacityMaskText),
m_spTextFormat,
&rcTextRect,
m_spBlackBrush);
//Radial Gradient Opacity Mask
m_spRT->SetTransform(D2D1::Matrix3x2F::Translation(D2D1::SizeF(255, 255)));
m_spRT->FillRectangle(&rcBrushRect,m_spCheckerPatternBitmapBrush);
m_spRT->FillRectangle(&rcBrushRect,m_spRadialGradientBrush);
m_spRT->DrawRectangle(&rcBrushRect,m_spBlackBrush,1,NULL);
//Caption using a DirectWrite format from m_spDWriteFactory->CreateTextFormat
m_spRT->DrawText(m_wszRadialGradientOpacityMaskText,
wcslen(m_wszRadialGradientOpacityMaskText),
m_spTextFormat,
&rcTextRect,
m_spBlackBrush);
//Bitmap Opacity Mask
m_spRT->SetTransform(D2D1::Matrix3x2F::Translation(D2D1::SizeF(255, 505)));
m_spRT->FillRectangle(&rcBrushRect,m_spCheckerPatternBitmapBrush);
m_spRT->FillRectangle(&rcBrushRect,m_spBitmapMaskBrush);
m_spRT->DrawRectangle(&rcBrushRect,m_spBlackBrush,1,NULL);
//Caption using a DirectWrite format from m_spDWriteFactory->CreateTextFormat
m_spRT->DrawText(m_wszBitmapBrushOpacityMaskText,
wcslen(m_wszBitmapBrushOpacityMaskText),
m_spTextFormat,
&rcTextRect,
m_spBlackBrush);
//Bitmap with Linear Gradient Opacity Brush
m_spRT->SetTransform(D2D1::Matrix3x2F::Translation(D2D1::SizeF(505, 5)));
m_spRT->FillGeometry(m_spRectGeo,m_spOriginalBitmapBrush,m_spLinearGradientBrush);
m_spRT->DrawRectangle(&rcBrushRect,m_spBlackBrush,1,NULL);
//Caption using a DirectWrite format from m_spDWriteFactory->CreateTextFormat
m_spRT->DrawText(m_wszWithLinearGradientOpacityMaskText,
wcslen(m_wszWithLinearGradientOpacityMaskText),
m_spTextFormat,
&rcTextRect,
m_spBlackBrush);
//Bitmap with Radial Gradient Opacity Brush
m_spRT->SetTransform(D2D1::Matrix3x2F::Translation(D2D1::SizeF(505, 255)));
m_spRT->FillGeometry(m_spRectGeo,m_spOriginalBitmapBrush,m_spRadialGradientBrush);
m_spRT->DrawRectangle(&rcBrushRect,m_spBlackBrush,1,NULL);
//Caption using a DirectWrite format from m_spDWriteFactory->CreateTextFormat
m_spRT->DrawText(m_wszWithRadialGradientOpacityMaskText,
wcslen(m_wszWithRadialGradientOpacityMaskText),
m_spTextFormat,
&rcTextRect,
m_spBlackBrush);
//Bitmap with Bitmap Opacity Brush
m_spRT->SetTransform(D2D1::Matrix3x2F::Translation(D2D1::SizeF(505, 505)));
//D2D1_ANTIALIAS_MODE_ALIASED must be set for FillOpacityMask to function properly
m_spRT->SetAntialiasMode(D2D1_ANTIALIAS_MODE_ALIASED);
m_spRT->FillOpacityMask(
m_spBitmap,
m_spBitmapMaskBrush,
D2D1_OPACITY_MASK_CONTENT_GRAPHICS,
0,
0);
m_spRT->DrawRectangle(&rcBrushRect,m_spBlackBrush,1,NULL);
//Caption using a DirectWrite format from m_spDWriteFactory->CreateTextFormat
m_spRT->DrawText(m_wszWithBitmapBrushOpacityMaskText,
wcslen(m_wszWithBitmapBrushOpacityMaskText),
m_spTextFormat,
&rcTextRect,
m_spBlackBrush);
hr = m_spRT->EndDraw();
}
if (hr == D2DERR_RECREATE_TARGET)
{
DiscardDeviceResources();
}
return S_OK;
}
/******************************************************************
* *
* DemoApp::OnResize *
* *
* If the application receives a WM_SIZE message, this method *
* resize the render target appropriately. *
* *
******************************************************************/
void DemoApp::OnResize(UINT width, UINT height)
{
if (m_spRT)
{
D2D1_SIZE_U size;
size.width = width;
size.height = height;
HRESULT hr = m_spRT->Resize(size);
// If we couldn't resize, release it and we'll recreate it
// during the next render pass.
if (FAILED(hr))
{
DiscardDeviceResources();
InvalidateRect(m_hwnd, NULL, FALSE);
}
}
}
/******************************************************************
* *
* DemoApp::WndProc *
* *
* Window message handler *
* *
******************************************************************/
LRESULT CALLBACK DemoApp::WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
if (message == WM_CREATE)
{
LPCREATESTRUCT pcs = (LPCREATESTRUCT)lParam;
DemoApp *pDemoApp = (DemoApp *)pcs->lpCreateParams;
::SetWindowLongPtrW(
hwnd,
GWLP_USERDATA,
PtrToUlong(pDemoApp));
return 1;
}
DemoApp *pDemoApp = reinterpret_cast<DemoApp *>(static_cast<LONG_PTR>(
::GetWindowLongPtrW(hwnd, GWLP_USERDATA)));
if (pDemoApp)
{
switch(message)
{
case WM_SIZE:
{
UINT width = LOWORD(lParam);
UINT height = HIWORD(lParam);
pDemoApp->OnResize(width, height);
//InvalidateRect(hwnd, NULL, true);
}
return 0;
case WM_PAINT:
case WM_DISPLAYCHANGE:
{
Sleep(200);
PAINTSTRUCT ps;
BeginPaint(hwnd, &ps);
pDemoApp->OnRender(ps);
EndPaint(hwnd, &ps);
}
return 0;
case WM_DESTROY:
{
PostQuitMessage(0);
}
return 1;
}
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
//
//
//
// Creates a Direct2D bitmap from the specified
// file name.
//
//
//
HRESULT DemoApp::LoadBitmapFromFile(
ID2D1RenderTarget *pRenderTarget,
IWICImagingFactory *pIWICFactory,
PCWSTR uri,
UINT destinationWidth,
UINT destinationHeight,
__deref_out ID2D1Bitmap **ppBitmap
)
{
HRESULT hr = S_OK;
IWICBitmapDecoderPtr spDecoder;
IWICBitmapFrameDecodePtr spSource;
IWICStreamPtr spStream;
IWICFormatConverterPtr spConverter;
IWICBitmapScalerPtr spScaler;
IFR(pIWICFactory->CreateDecoderFromFilename(
uri, NULL, GENERIC_READ, WICDecodeMetadataCacheOnLoad, &spDecoder
));
// Create the initial frame.
IFR(spDecoder->GetFrame(0, &spSource));
// Convert the image format to 32bppPBGRA -- which Direct2D expects.
IFR(pIWICFactory->CreateFormatConverter(&spConverter));
// If a new width or height was specified, create an
// IWICBitmapScaler and use it to resize the image.
if (destinationWidth != 0 || destinationHeight != 0){
UINT originalWidth, originalHeight;
spSource->GetSize(&originalWidth, &originalHeight);
if (destinationWidth == 0){
FLOAT scalar = static_cast<FLOAT>(destinationHeight) / static_cast<FLOAT>(originalHeight);
destinationWidth = static_cast<UINT>(scalar * static_cast<FLOAT>(originalWidth));
}
else if (destinationHeight == 0) {
FLOAT scalar = static_cast<FLOAT>(destinationWidth) / static_cast<FLOAT>(originalWidth);
destinationHeight = static_cast<UINT>(scalar * static_cast<FLOAT>(originalHeight));
}
IFR(pIWICFactory->CreateBitmapScaler(&spScaler));
IFR(spScaler->Initialize(
spSource,
destinationWidth,
destinationHeight,
WICBitmapInterpolationModeCubic
));
IFR(spConverter->Initialize(
spScaler,
GUID_WICPixelFormat32bppPBGRA,
WICBitmapDitherTypeNone,
NULL,
0.f,
WICBitmapPaletteTypeMedianCut
));
}
else // Don't scale the image.
{
IFR(spConverter->Initialize(
spSource,
GUID_WICPixelFormat32bppPBGRA,
WICBitmapDitherTypeNone,
NULL,
0.f,
WICBitmapPaletteTypeMedianCut
));
}
// Create a Direct2D bitmap from the WIC bitmap.
IFR(pRenderTarget->CreateBitmapFromWicBitmap(
spConverter,
NULL,
ppBitmap
));
return hr;
}