I select displays in multiple display environments and produce captured programs.
And try to draw a cursor by selecting dc among multiple displays.
I draw cursors with bitblt bitmap images and it works well.
HDC HDCC = CreateDC((L"Display"), NULL, NULL, NULL);
But When I select from createDC multuple display value,
DISPLAY_DEVICEW info = { 0 };
info.cb = sizeof(DISPLAY_DEVICEW);
EnumDisplayDevicesW(NULL, 0, &info, EDD_GET_DEVICE_INTERFACE_NAME);
HDCC = CreateDC(info.DeviceName, NULL, NULL, NULL);
I am working hard to get other display images. But there is no drawing cursor. (Other forms of cursor are not drawn, only text cursor is drawn)
This is my code.
const int d_count = GetSystemMetrics(SM_CMONITORS); //I have 3 display and count is 3.
HDC hCaptureDC;
HDC HDCC;
HBITMAP hBitmap;
HGDIOBJ hOld;
BYTE *src;
bool GetMouse() {
CURSORINFO cursor = { sizeof(cursor) };
::GetCursorInfo(&cursor);
ICONINFOEXW info = { sizeof(info) };
::GetIconInfoExW(cursor.hCursor, &info);
BITMAP bmpCursor = { 0 };
GetObject(info.hbmColor, sizeof(bmpCursor), &bmpCursor);
POINT point;
GetCursorPos(&point);
bool res = DrawIconEx(hCaptureDC, point.x, point.y, cursor.hCursor, bmpCursor.bmWidth, bmpCursor.bmHeight, 0, NULL, DI_NORMAL);
return res;
}
void screencap(){
BITMAPINFO MyBMInfo;
BITMAPINFOHEADER bmpInfoHeader;
HWND m_hWndCopy= GetDesktopWindow();
GetClientRect(m_hWndCopy, &ImageRect);
const int nWidth = ImageRect.right - ImageRect.left;
const int nHeight = ImageRect.bottom - ImageRect.top;
MyBMInfo = { 0 };
MyBMInfo.bmiHeader.biSize = sizeof(MyBMInfo.bmiHeader);
bmpInfoHeader = { sizeof(BITMAPINFOHEADER) };
bmpInfoHeader.biWidth = nWidth;
bmpInfoHeader.biHeight = nHeight;
bmpInfoHeader.biPlanes = 1;
bmpInfoHeader.biBitCount = 32;
b_size = ((nWidth * bmpInfoHeader.biBitCount + 31) / 32) * 4 * nHeight;
//HDCC = CreateDC((L"Display"), NULL, NULL, NULL); //It's good.
DISPLAY_DEVICEW info = { 0 };
info.cb = sizeof(DISPLAY_DEVICEW);
EnumDisplayDevicesW(NULL, 0, &info, EDD_GET_DEVICE_INTERFACE_NAME);
HDCC = CreateDC(info.DeviceName, NULL, NULL, NULL); // It draws only text cursor.
hCaptureDC = CreateCompatibleDC(HDCC);
hBitmap = CreateCompatibleBitmap(HDCC, nWidth, nHeight);
hOld = SelectObject(hCaptureDC, hBitmap);
BitBlt(hCaptureDC, 0, 0, nWidth, nHeight, HDCC, 0, 0, SRCCOPY);
GetMouse();
SelectObject(hCaptureDC, hOld);
src = (BYTE*)malloc(b_size);
if (GetDIBits(hCaptureDC, hBitmap, 0, nHeight, src, (BITMAPINFO*)&bmpInfoHeader, DIB_RGB_COLORS)) {
if (RGBSaveBMP(src) == true)
free(src);
}
}
I'm using windows 10.
How can I solved?
Any links, idea, Thanks.
ADD
It does not draw cursor....(except text cursor.)
HDCC = CreateDC(TEXT("\\\\.\\Display1"), NULL, NULL, NULL);
It draws cursor..
HDCC = CreateDC(TEXT("Display"), NULL, NULL, NULL);
SOLVED:
Now, I changed my algorithm.
CreateDC(L"Display", NULL, NULL, NULL) create DC for all monitors, so what is your problem? – user2120666 Apr 22 at 15:37
This comment is very helpful but It was not kind. (Or I was stupid.) :(
HDC HDCC = CreateDC((L"Display"), NULL, NULL, NULL);
HDCC has "All Virtual Screens" DC.
When I selected the monitor I needed, and accordingly selected and used the area to capture on the virtual screen.
HDC hCaptureDC = CreateCompatibleDC(HDCC);
HBITMAP hBitmap = CreateCompatibleBitmap(HDCC, nWidth, nHeight);
HDC HDCC = CreateDC((L"Display"), NULL, NULL, NULL);
DEVMODE dev;
std::string str = "\\\\.\\Display" + std::to_string(select);
std::wstring temp;
temp.assign(str.begin(), str.end());
EnumDisplaySettingsW(temp.c_str(), ENUM_CURRENT_SETTINGS, &dev);
printf("Display%d : (%d * %d) (%d, %d)\n", select, dev.dmPelsWidth, dev.dmPelsHeight, dev.dmPosition.x, dev.dmPosition.y);
nWidth = dev.dmPelsWidth;
nHeight = dev.dmPelsHeight;
nposx = dev.dmPosition.x;
nposy = dev.dmPosition.y;
hOld = SelectObject(hCaptureDC, hBitmap);
BitBlt(hCaptureDC, 0, 0, nWidth, nHeight, HDCC, nposx, nposy, SRCCOPY);
int colorcheck = GetSystemMetrics(SM_SAMEDISPLAYFORMAT);
CURSORINFO cursor = { sizeof(cursor) };
bool check = ::GetCursorInfo(&cursor);
bool check2 = ::GetCursorInfo(&cursor);
int count = ShowCursor(TRUE);
info = { sizeof(info) };
::GetIconInfoExW(cursor.hCursor, &info);
GetCursorPos(&point);
if (point.x > nWidth) {
point.x = point.x - nWidth;
}
else if (point.x < 0) {
point.x = nWidth + point.x;
}
if (point.y > nHeight) {
point.y = point.y - nHeight;
}
else if (point.y < 0) {
point.y = nHeight + point.y;
}
cursor.ptScreenPos.x = point.x;
cursor.ptScreenPos.y = point.y;
bool res = ::DrawIconEx(hCaptureDC, point.x, point.y, cursor.hCursor, 0, 0, 0, NULL, DI_NORMAL);
BYTE* src = (BYTE*)malloc(b_size);
GetDIBits(hCaptureDC, hBitmap, 0, nHeight, src, (BITMAPINFO*)&bmpInfoHeader, DIB_RGB_COLORS)
Thanks for the comment!
Your call GetClientRect(m_hWndCopy, &ImageRect); is wrong.
From documentation:
The rectangle of the desktop window returned by GetWindowRect or
GetClientRect is always equal to the rectangle of the primary monitor,
for compatibility with existing applications.
So you are capturing only primary display.
Following MSDN to get EnumDisplayMonitor may solve your problem.
Use EnumDisplayMonitors to get the device name and pass it to
CreateDC.
Related
This one is a c++/MFC project.
I need to display a position of the cursor. So I must redraw tooltip everytime when a mouse is moving.
I can draw a tooltip but a tooltip was drawn isn't cleared.
The OnShowTooltip() function will be called if mouse is moving.
void OnShowToolTip(const CPoint& ptMousePosition,CString strText)
{
UpdateData(true);
if (bToolTip)
{
unsigned int uid = 0; // for ti initialization
// CREATE A TOOLTIP WINDOW
hwndTT = CreateWindowEx(WS_EX_TOPMOST,
TOOLTIPS_CLASS,
NULL,
TTS_NOPREFIX ,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
NULL,
NULL
);
// INITIALIZE MEMBERS OF THE TOOLINFO STRUCTURE
//ti.cbSize = sizeof(TOOLINFO);
ti.cbSize = TTTOOLINFO_V1_SIZE;
ti.uFlags = TTF_TRACK;
ti.hwnd = NULL;
ti.hinst = NULL;
ti.uId = uid;
ti.lpszText = (LPSTR)(LPCSTR) strText;
// ToolTip control will cover the whole window
ti.rect.left = 0;
ti.rect.top = 0;
ti.rect.right = 0;
ti.rect.bottom = 0;
// SEND AN ADDTOOL MESSAGE TO THE TOOLTIP CONTROL WINDOW
::SendMessage(hwndTT, TTM_ADDTOOL, 0, (LPARAM) (LPTOOLINFO) &ti);
::SendMessage(hwndTT, TTM_TRACKPOSITION, 0, (LPARAM)(DWORD) MAKELONG(ptMousePosition.x, ptMousePosition.y));
::SendMessage(hwndTT, TTM_TRACKACTIVATE, true, (LPARAM)(LPTOOLINFO) &ti);
bToolTip=false;
}else{
::SendMessage(hwndTT, TTM_TRACKACTIVATE, false, (LPARAM)(LPTOOLINFO) &ti);
bToolTip=true;
}
}
I have a function for handling mouse events like below
BOOL DoDragPoint2D(CPoint point,CString strPositions)
{
switch (msg.message)
{
case WM_MOUSEMOVE:
bToolTip = TRUE;
OnShowToolTip(point,strPositions);
break;
case WM_LBUTTONUP:
bToolTip = FALSE;
OnShowToolTip(point,strPositions);
}
}
Although I set bTooltip to be FALSE. But It cannot to remove tooltip.
Moreover I try to call Invalidate() function but a tooltip still display until a dubbuging is stopped.
Each time the mouse moves, a new tooltip is created.
You only need to create the tooltip once in WM_CREATE event.
Then send TTM_SETTOOLINFO message to update ti.lpszText.
ep.
case WM_CREATE:
{
unsigned int uid = 0; // for ti initialization
hwndTT = CreateWindowEx(WS_EX_TOPMOST,
TOOLTIPS_CLASS,
NULL,
TTS_NOPREFIX,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
NULL,
NULL
);
// INITIALIZE MEMBERS OF THE TOOLINFO STRUCTURE
//ti.cbSize = sizeof(TOOLINFO);
ti.cbSize = TTTOOLINFO_V1_SIZE;
ti.uFlags = TTF_TRACK;
ti.hwnd = NULL;
ti.hinst = NULL;
ti.uId = uid;
ti.lpszText = const_cast <wchar_t*>(L"");
// ToolTip control will cover the whole window
ti.rect.left = 0;
ti.rect.top = 0;
ti.rect.right = 0;
ti.rect.bottom = 0;
::SendMessage(hwndTT, TTM_ADDTOOL, 0, (LPARAM)(LPTOOLINFO)&ti);
}
break;
case WM_MOUSEMOVE:
...
ti.lpszText = (LPSTR)(LPCSTR) strText;
::SendMessage(hwndTT, TTM_SETTOOLINFO, 0, (LPARAM)&ti);
::SendMessage(hwndTT, TTM_TRACKPOSITION, 0, (LPARAM)(DWORD) MAKELONG(ptMousePosition.x, ptMousePosition.y));
::SendMessage(hwndTT, TTM_TRACKACTIVATE, true, (LPARAM)(LPTOOLINFO) &ti);
...
I want to render one triangle to texture and then that render to texture need to be displayed in a smaller size at top-left corner of screen with the original triangle at center of the screen.
I have developed one application but not succeeded. Please help me on this.
My code is as follows -
#include <windows.h>
#include <d3d11_1.h>
#include <d3dcompiler.h>
#include <directxmath.h>
#include <directxcolors.h>
#include "resource.h"
using namespace DirectX;
//--------------------------------------------------------------------------------------
// Structures
//--------------------------------------------------------------------------------------
struct SimpleVertex
{
XMFLOAT3 Pos;
};
//--------------------------------------------------------------------------------------
// Global Variables
//--------------------------------------------------------------------------------------
HINSTANCE g_hInst = nullptr;
HWND g_hWnd = nullptr;
D3D_DRIVER_TYPE g_driverType = D3D_DRIVER_TYPE_NULL;
D3D_FEATURE_LEVEL g_featureLevel = D3D_FEATURE_LEVEL_11_0;
ID3D11Device* g_pd3dDevice = nullptr;
ID3D11Device1* g_pd3dDevice1 = nullptr;
ID3D11DeviceContext* g_pImmediateContext = nullptr;
ID3D11DeviceContext1* g_pImmediateContext1 = nullptr;
IDXGISwapChain* g_pSwapChain = nullptr;
IDXGISwapChain1* g_pSwapChain1 = nullptr;
ID3D11RenderTargetView* g_pRenderTargetView = nullptr;
ID3D11VertexShader* g_pVertexShader = nullptr;
ID3D11PixelShader* g_pPixelShader = nullptr;
ID3D11InputLayout* g_pVertexLayout = nullptr;
ID3D11Buffer* g_pVertexBuffer = nullptr;
ID3D11Texture2D* m_renderTargetTexture=nullptr;
ID3D11RenderTargetView* m_renderTargetView=nullptr;
ID3D11ShaderResourceView* m_shaderResourceView=nullptr;
ID3D11DepthStencilView* m_depthStencilView;
ID3D11Texture2D* m_depthStencilBuffer;
ID3D11DepthStencilState* m_depthStencilState;
//--------------------------------------------------------------------------------------
// Forward declarations
//--------------------------------------------------------------------------------------
HRESULT InitWindow( HINSTANCE hInstance, int nCmdShow );
HRESULT InitDevice();
void CleanupDevice();
LRESULT CALLBACK WndProc( HWND, UINT, WPARAM, LPARAM );
void Render();
void RenderOnTexture();
//--------------------------------------------------------------------------------------
// Entry point to the program. Initializes everything and goes into a message processing
// loop. Idle time is used to render the scene.
//--------------------------------------------------------------------------------------
int WINAPI wWinMain( _In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow )
{
UNREFERENCED_PARAMETER( hPrevInstance );
UNREFERENCED_PARAMETER( lpCmdLine );
if( FAILED( InitWindow( hInstance, nCmdShow ) ) )
return 0;
if( FAILED( InitDevice() ) )
{
CleanupDevice();
return 0;
}
// Main message loop
MSG msg = {0};
while( WM_QUIT != msg.message )
{
if( PeekMessage( &msg, nullptr, 0, 0, PM_REMOVE ) )
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
else
{
Render();
}
}
CleanupDevice();
return ( int )msg.wParam;
}
//--------------------------------------------------------------------------------------
// Register class and create window
//--------------------------------------------------------------------------------------
HRESULT InitWindow( HINSTANCE hInstance, int nCmdShow )
{
// Register class
WNDCLASSEX wcex;
wcex.cbSize = sizeof( WNDCLASSEX );
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon( hInstance, ( LPCTSTR )IDI_TUTORIAL1 );
wcex.hCursor = LoadCursor( nullptr, IDC_ARROW );
wcex.hbrBackground = ( HBRUSH )( COLOR_WINDOW + 1 );
wcex.lpszMenuName = nullptr;
wcex.lpszClassName = L"TutorialWindowClass";
wcex.hIconSm = LoadIcon( wcex.hInstance, ( LPCTSTR )IDI_TUTORIAL1 );
if( !RegisterClassEx( &wcex ) )
return E_FAIL;
// Create window
g_hInst = hInstance;
RECT rc = { 0, 0, 800, 600 };
AdjustWindowRect( &rc, WS_OVERLAPPEDWINDOW, FALSE );
g_hWnd = CreateWindow( L"TutorialWindowClass", L"Direct3D 11 Tutorial 2: Rendering a Triangle",
WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX,
CW_USEDEFAULT, CW_USEDEFAULT, rc.right - rc.left, rc.bottom - rc.top, nullptr, nullptr, hInstance,
nullptr );
if( !g_hWnd )
return E_FAIL;
ShowWindow( g_hWnd, nCmdShow );
return S_OK;
}
//--------------------------------------------------------------------------------------
// Helper for compiling shaders with D3DCompile
//
// With VS 11, we could load up prebuilt .cso files instead...
//--------------------------------------------------------------------------------------
HRESULT CompileShaderFromFile( WCHAR* szFileName, LPCSTR szEntryPoint, LPCSTR szShaderModel, ID3DBlob** ppBlobOut )
{
HRESULT hr = S_OK;
DWORD dwShaderFlags = D3DCOMPILE_ENABLE_STRICTNESS;
#ifdef _DEBUG
// Set the D3DCOMPILE_DEBUG flag to embed debug information in the shaders.
// Setting this flag improves the shader debugging experience, but still allows
// the shaders to be optimized and to run exactly the way they will run in
// the release configuration of this program.
dwShaderFlags |= D3DCOMPILE_DEBUG;
// Disable optimizations to further improve shader debugging
dwShaderFlags |= D3DCOMPILE_SKIP_OPTIMIZATION;
#endif
ID3DBlob* pErrorBlob = nullptr;
hr = D3DCompileFromFile( szFileName, nullptr, nullptr, szEntryPoint, szShaderModel,
dwShaderFlags, 0, ppBlobOut, &pErrorBlob );
if( FAILED(hr) )
{
if( pErrorBlob )
{
OutputDebugStringA( reinterpret_cast<const char*>( pErrorBlob->GetBufferPointer() ) );
pErrorBlob->Release();
}
return hr;
}
if( pErrorBlob ) pErrorBlob->Release();
return S_OK;
}
//--------------------------------------------------------------------------------------
// Create Direct3D device and swap chain
//--------------------------------------------------------------------------------------
HRESULT InitDevice()
{
HRESULT hr = S_OK;
RECT rc;
GetClientRect( g_hWnd, &rc );
UINT width = rc.right - rc.left;
UINT height = rc.bottom - rc.top;
UINT createDeviceFlags = 0;
#ifdef _DEBUG
createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG;
#endif
D3D_DRIVER_TYPE driverTypes[] =
{
D3D_DRIVER_TYPE_HARDWARE,
D3D_DRIVER_TYPE_WARP,
D3D_DRIVER_TYPE_REFERENCE,
};
UINT numDriverTypes = ARRAYSIZE( driverTypes );
D3D_FEATURE_LEVEL featureLevels[] =
{
D3D_FEATURE_LEVEL_11_1,
D3D_FEATURE_LEVEL_11_0,
D3D_FEATURE_LEVEL_10_1,
D3D_FEATURE_LEVEL_10_0,
};
UINT numFeatureLevels = ARRAYSIZE( featureLevels );
for( UINT driverTypeIndex = 0; driverTypeIndex < numDriverTypes; driverTypeIndex++ )
{
g_driverType = driverTypes[driverTypeIndex];
hr = D3D11CreateDevice( nullptr, g_driverType, nullptr, createDeviceFlags, featureLevels, numFeatureLevels,
D3D11_SDK_VERSION, &g_pd3dDevice, &g_featureLevel, &g_pImmediateContext );
if ( hr == E_INVALIDARG )
{
// DirectX 11.0 platforms will not recognize D3D_FEATURE_LEVEL_11_1 so we need to retry without it
hr = D3D11CreateDevice( nullptr, g_driverType, nullptr, createDeviceFlags, &featureLevels[1], numFeatureLevels - 1,
D3D11_SDK_VERSION, &g_pd3dDevice, &g_featureLevel, &g_pImmediateContext );
}
if( SUCCEEDED( hr ) )
break;
}
if( FAILED( hr ) )
return hr;
// Obtain DXGI factory from device (since we used nullptr for pAdapter above)
IDXGIFactory1* dxgiFactory = nullptr;
{
IDXGIDevice* dxgiDevice = nullptr;
hr = g_pd3dDevice->QueryInterface( __uuidof(IDXGIDevice), reinterpret_cast<void**>(&dxgiDevice) );
if (SUCCEEDED(hr))
{
IDXGIAdapter* adapter = nullptr;
hr = dxgiDevice->GetAdapter(&adapter);
if (SUCCEEDED(hr))
{
hr = adapter->GetParent( __uuidof(IDXGIFactory1), reinterpret_cast<void**>(&dxgiFactory) );
adapter->Release();
}
dxgiDevice->Release();
}
}
if (FAILED(hr))
return hr;
// Create swap chain
IDXGIFactory2* dxgiFactory2 = nullptr;
hr = dxgiFactory->QueryInterface( __uuidof(IDXGIFactory2), reinterpret_cast<void**>(&dxgiFactory2) );
if ( dxgiFactory2 )
{
// DirectX 11.1 or later
hr = g_pd3dDevice->QueryInterface( __uuidof(ID3D11Device1), reinterpret_cast<void**>(&g_pd3dDevice1) );
if (SUCCEEDED(hr))
{
(void) g_pImmediateContext->QueryInterface( __uuidof(ID3D11DeviceContext1), reinterpret_cast<void**>(&g_pImmediateContext1) );
}
DXGI_SWAP_CHAIN_DESC1 sd;
ZeroMemory(&sd, sizeof(sd));
sd.Width = width;
sd.Height = height;
sd.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
sd.SampleDesc.Count = 1;
sd.SampleDesc.Quality = 0;
sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
sd.BufferCount = 1;
hr = dxgiFactory2->CreateSwapChainForHwnd( g_pd3dDevice, g_hWnd, &sd, nullptr, nullptr, &g_pSwapChain1 );
if (SUCCEEDED(hr))
{
hr = g_pSwapChain1->QueryInterface( __uuidof(IDXGISwapChain), reinterpret_cast<void**>(&g_pSwapChain) );
}
dxgiFactory2->Release();
}
else
{
// DirectX 11.0 systems
DXGI_SWAP_CHAIN_DESC sd;
ZeroMemory(&sd, sizeof(sd));
sd.BufferCount = 1;
sd.BufferDesc.Width = width;
sd.BufferDesc.Height = height;
sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
sd.BufferDesc.RefreshRate.Numerator = 60;
sd.BufferDesc.RefreshRate.Denominator = 1;
sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
sd.OutputWindow = g_hWnd;
sd.SampleDesc.Count = 1;
sd.SampleDesc.Quality = 0;
sd.Windowed = TRUE;
hr = dxgiFactory->CreateSwapChain( g_pd3dDevice, &sd, &g_pSwapChain );
}
// Note this tutorial doesn't handle full-screen swapchains so we block the ALT+ENTER shortcut
dxgiFactory->MakeWindowAssociation( g_hWnd, DXGI_MWA_NO_ALT_ENTER );
dxgiFactory->Release();
if (FAILED(hr))
return hr;
// Create a render target view
ID3D11Texture2D* pBackBuffer = nullptr;
hr = g_pSwapChain->GetBuffer( 0, __uuidof( ID3D11Texture2D ), reinterpret_cast<void**>( &pBackBuffer ) );
if( FAILED( hr ) )
return hr;
hr = g_pd3dDevice->CreateRenderTargetView( pBackBuffer, nullptr, &g_pRenderTargetView );
pBackBuffer->Release();
if( FAILED( hr ) )
return hr;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
D3D11_TEXTURE2D_DESC textureDesc;
HRESULT result;
D3D11_RENDER_TARGET_VIEW_DESC renderTargetViewDesc;
D3D11_SHADER_RESOURCE_VIEW_DESC shaderResourceViewDesc;
// Initialize the render target texture description.
ZeroMemory(&textureDesc, sizeof(textureDesc));
// Setup the render target texture description.
textureDesc.Width = 400/*textureWidth*/;
textureDesc.Height = 400/*textureHeight*/;
textureDesc.MipLevels = 1;
textureDesc.ArraySize = 1;
textureDesc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT;
textureDesc.SampleDesc.Count = 1;
textureDesc.Usage = D3D11_USAGE_DEFAULT;
textureDesc.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE;
textureDesc.CPUAccessFlags = 0;
textureDesc.MiscFlags = 0;
// Create the render target texture.
result = g_pd3dDevice->CreateTexture2D(&textureDesc, NULL, &m_renderTargetTexture);
if (FAILED(result))
{
return false;
}
// Setup the description of the render target view.
renderTargetViewDesc.Format = textureDesc.Format;
renderTargetViewDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
renderTargetViewDesc.Texture2D.MipSlice = 0;
// Create the render target view.
result = g_pd3dDevice->CreateRenderTargetView(m_renderTargetTexture, &renderTargetViewDesc, &m_renderTargetView);
if (FAILED(result))
{
return false;
}
// Setup the description of the shader resource view.
shaderResourceViewDesc.Format = textureDesc.Format;
shaderResourceViewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
shaderResourceViewDesc.Texture2D.MostDetailedMip = 0;
shaderResourceViewDesc.Texture2D.MipLevels = 1;
// Create the shader resource view.
result = g_pd3dDevice->CreateShaderResourceView(m_renderTargetTexture, &shaderResourceViewDesc, &m_shaderResourceView);
//D3D11_TEXTURE2D_DESC depthBufferDesc;
//D3D11_DEPTH_STENCIL_DESC depthStencilDesc;
//D3D11_DEPTH_STENCIL_VIEW_DESC depthStencilViewDesc;
//// Initialize the description of the depth buffer.
//ZeroMemory(&depthBufferDesc, sizeof(depthBufferDesc));
//// Set up the description of the depth buffer.
//depthBufferDesc.Width = 400;
//depthBufferDesc.Height = 400;
//depthBufferDesc.MipLevels = 1;
//depthBufferDesc.ArraySize = 1;
//depthBufferDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
//depthBufferDesc.SampleDesc.Count = 1;
//depthBufferDesc.SampleDesc.Quality = 0;
//depthBufferDesc.Usage = D3D11_USAGE_DEFAULT;
//depthBufferDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
//depthBufferDesc.CPUAccessFlags = 0;
//depthBufferDesc.MiscFlags = 0;
//// Create the texture for the depth buffer using the filled out description.
//result = g_pd3dDevice->CreateTexture2D(&depthBufferDesc, NULL, &m_depthStencilBuffer);
//if (FAILED(result))
//{
// return false;
//}
//// Initialize the description of the stencil state.
//ZeroMemory(&depthStencilDesc, sizeof(depthStencilDesc));
//// Set up the description of the stencil state.
//depthStencilDesc.DepthEnable = true;
//depthStencilDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
//depthStencilDesc.DepthFunc = D3D11_COMPARISON_LESS;
//depthStencilDesc.StencilEnable = true;
//depthStencilDesc.StencilReadMask = 0xFF;
//depthStencilDesc.StencilWriteMask = 0xFF;
//// Stencil operations if pixel is front-facing.
//depthStencilDesc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
//depthStencilDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_INCR;
//depthStencilDesc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
//depthStencilDesc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
//// Stencil operations if pixel is back-facing.
//depthStencilDesc.BackFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
//depthStencilDesc.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_DECR;
//depthStencilDesc.BackFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
//depthStencilDesc.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
//// Create the depth stencil state.
//result = g_pd3dDevice->CreateDepthStencilState(&depthStencilDesc, &m_depthStencilState);
//if (FAILED(result))
//{
// return false;
//}
//// Set the depth stencil state.
//g_pImmediateContext->OMSetDepthStencilState(m_depthStencilState, 1);
//// Initialize the depth stencil view.
//ZeroMemory(&depthStencilViewDesc, sizeof(depthStencilViewDesc));
//// Set up the depth stencil view description.
//depthStencilViewDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
//depthStencilViewDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
//depthStencilViewDesc.Texture2D.MipSlice = 0;
//// Create the depth stencil view.
//result = g_pd3dDevice->CreateDepthStencilView(m_depthStencilBuffer, &depthStencilViewDesc, &m_depthStencilView);
//if (FAILED(result))
//{
// return false;
//}
// Bind the render target view and depth stencil buffer to the output render pipeline.
g_pImmediateContext->OMSetRenderTargets(1, &m_renderTargetView, /*m_depthStencilView*/nullptr);
// Clear the back buffer.
g_pImmediateContext->ClearRenderTargetView(m_renderTargetView, Colors::Red);
// Clear the depth buffer.
//g_pImmediateContext->ClearDepthStencilView(depthStencilView, D3D11_CLEAR_DEPTH, 1.0f, 0);
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Setup the viewport
D3D11_VIEWPORT vp;
vp.Width = (FLOAT)width;
vp.Height = (FLOAT)height;
vp.MinDepth = 0.0f;
vp.MaxDepth = 1.0f;
vp.TopLeftX = 0;
vp.TopLeftY = 0;
g_pImmediateContext->RSSetViewports( 1, &vp );
// Compile the vertex shader
ID3DBlob* pVSBlob = nullptr;
hr = CompileShaderFromFile( L"Tutorial02.fx", "VS", "vs_4_0", &pVSBlob );
if( FAILED( hr ) )
{
MessageBox( nullptr,
L"The FX file cannot be compiled. Please run this executable from the directory that contains the FX file.", L"Error", MB_OK );
return hr;
}
// Create the vertex shader
hr = g_pd3dDevice->CreateVertexShader( pVSBlob->GetBufferPointer(), pVSBlob->GetBufferSize(), nullptr, &g_pVertexShader );
if( FAILED( hr ) )
{
pVSBlob->Release();
return hr;
}
// Define the input layout
D3D11_INPUT_ELEMENT_DESC layout[] =
{
{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
};
UINT numElements = ARRAYSIZE( layout );
// Create the input layout
hr = g_pd3dDevice->CreateInputLayout( layout, numElements, pVSBlob->GetBufferPointer(),
pVSBlob->GetBufferSize(), &g_pVertexLayout );
pVSBlob->Release();
if( FAILED( hr ) )
return hr;
// Set the input layout
g_pImmediateContext->IASetInputLayout( g_pVertexLayout );
// Compile the pixel shader
ID3DBlob* pPSBlob = nullptr;
hr = CompileShaderFromFile( L"Tutorial02.fx", "PS", "ps_4_0", &pPSBlob );
if( FAILED( hr ) )
{
MessageBox( nullptr,
L"The FX file cannot be compiled. Please run this executable from the directory that contains the FX file.", L"Error", MB_OK );
return hr;
}
// Create the pixel shader
hr = g_pd3dDevice->CreatePixelShader( pPSBlob->GetBufferPointer(), pPSBlob->GetBufferSize(), nullptr, &g_pPixelShader );
pPSBlob->Release();
if( FAILED( hr ) )
return hr;
// Create vertex buffer
SimpleVertex vertices[] =
{
XMFLOAT3( 0.0f, 0.5f, 0.5f ),
XMFLOAT3( 0.5f, -0.5f, 0.5f ),
XMFLOAT3( -0.5f, -0.5f, 0.5f ),
};
D3D11_BUFFER_DESC bd;
ZeroMemory( &bd, sizeof(bd) );
bd.Usage = D3D11_USAGE_DEFAULT;
bd.ByteWidth = sizeof( SimpleVertex ) * 3;
bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
bd.CPUAccessFlags = 0;
D3D11_SUBRESOURCE_DATA InitData;
ZeroMemory( &InitData, sizeof(InitData) );
InitData.pSysMem = vertices;
hr = g_pd3dDevice->CreateBuffer( &bd, &InitData, &g_pVertexBuffer );
if( FAILED( hr ) )
return hr;
// Set vertex buffer
UINT stride = sizeof( SimpleVertex );
UINT offset = 0;
g_pImmediateContext->IASetVertexBuffers( 0, 1, &g_pVertexBuffer, &stride, &offset );
// Set primitive topology
g_pImmediateContext->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST );
RenderOnTexture();
return S_OK;
}
//--------------------------------------------------------------------------------------
// Clean up the objects we've created
//--------------------------------------------------------------------------------------
void CleanupDevice()
{
if( g_pImmediateContext ) g_pImmediateContext->ClearState();
if( g_pVertexBuffer ) g_pVertexBuffer->Release();
if( g_pVertexLayout ) g_pVertexLayout->Release();
if( g_pVertexShader ) g_pVertexShader->Release();
if( g_pPixelShader ) g_pPixelShader->Release();
if( g_pRenderTargetView ) g_pRenderTargetView->Release();
if( g_pSwapChain1 ) g_pSwapChain1->Release();
if( g_pSwapChain ) g_pSwapChain->Release();
if( g_pImmediateContext1 ) g_pImmediateContext1->Release();
if( g_pImmediateContext ) g_pImmediateContext->Release();
if( g_pd3dDevice1 ) g_pd3dDevice1->Release();
if( g_pd3dDevice ) g_pd3dDevice->Release();
}
//--------------------------------------------------------------------------------------
// Called every time the application receives a message
//--------------------------------------------------------------------------------------
LRESULT CALLBACK WndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
{
PAINTSTRUCT ps;
HDC hdc;
switch( message )
{
case WM_PAINT:
hdc = BeginPaint( hWnd, &ps );
EndPaint( hWnd, &ps );
break;
case WM_DESTROY:
PostQuitMessage( 0 );
break;
// Note that this tutorial does not handle resizing (WM_SIZE) requests,
// so we created the window without the resize border.
default:
return DefWindowProc( hWnd, message, wParam, lParam );
}
return 0;
}
//--------------------------------------------------------------------------------------
// Render a frame
//--------------------------------------------------------------------------------------
void Render()
{
// Clear the back buffer
g_pImmediateContext->ClearRenderTargetView( g_pRenderTargetView, Colors::MidnightBlue );
// Render a triangle
/*g_pImmediateContext->VSSetShader( g_pVertexShader, nullptr, 0 );
g_pImmediateContext->PSSetShader( g_pPixelShader, nullptr, 0 );
g_pImmediateContext->Draw( 3, 0 );*/
g_pImmediateContext->PSSetShaderResources(0, 1, &m_shaderResourceView);
// Present the information rendered to the back buffer to the front buffer (the screen)
g_pSwapChain->Present( 0, 0 );
}
void RenderOnTexture()
{
g_pImmediateContext->VSSetShader(g_pVertexShader, nullptr, 0);
g_pImmediateContext->PSSetShader(g_pPixelShader, nullptr, 0);
g_pImmediateContext->Draw(3, 0);
g_pImmediateContext->OMSetRenderTargets(1, &g_pRenderTargetView, nullptr);
}
Your Render() function has no draw calls in it.
I can't stop the flickering. I got the advice to add dubbel-buffering. How do I do that?
#include <iostream>
#include <windows.h>
#include <string>
#include <fstream>
#include <vector>
using namespace std;
namespace {
const int ID_NEW = 1;
const int ID_QUIT = 2;
const int ID_ABOUT = 3;
const int NORTH_BUTTON_ID = 4;
const int SOUTH_BUTTON_ID = 5;
const int WEST_BUTTON_ID = 6;
const int EAST_BUTTON_ID = 7;
const int ID_FINISHED_GAME = 8;
int x = 0;
int y = 0;
int xStart = 0;
int yStart = 0;
int windowHeight = 400;
int windowWidth = 500;
char level1[20][21];
int noOfMoves = 0;
}
void readLevel(string fileName, char level[20][21]) {
char character{};
ifstream file(fileName);
int i = 0;
int j = 0;
if (file.is_open()) {
while (file >> character) {
level[j][i] = character;
if (level[j][i] == 's') {
y = yStart = j;
x = xStart = i;
}
if (++i % 20 == 0) {
i = 0;
j++;
}
}
file.close();
}
}
void restart(){
x = xStart;
y = yStart;
noOfMoves = 0;
}
LRESULT CALLBACK WinProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
HDC hdc{ 0 };
PAINTSTRUCT ps{ 0 };
switch (msg) {
case WM_CLOSE:
PostQuitMessage(0);
return 0;
case WM_COMMAND:
switch (LOWORD(wParam)){
case ID_ABOUT:
MessageBox(hwnd, L"About this program!", L"About", MB_OK);
return 0;
case ID_NEW:
restart();
return 0;
case ID_QUIT:
if (MessageBox(0, L"Do you really want to quit?", L"Are you sure?", MB_YESNO) == IDYES) {
PostQuitMessage(0);
return 0;
}
case NORTH_BUTTON_ID:
if (level1[y - 1][x] != '1') {
y -= 1;
noOfMoves++;
}
break;
case SOUTH_BUTTON_ID:
if (level1[y + 1][x] != '1'){
y += 1;
noOfMoves++;
}
break;
case WEST_BUTTON_ID:
if (level1[y][x - 1] != '1'){
x -= 1;
noOfMoves++;
}
break;
case EAST_BUTTON_ID:
if (level1[y][x + 1] != '1') {
x += 1;
noOfMoves++;
}
break;
}
if (level1[y][x] == 'e') {
wstring moves = L"Congratulations, you finished the game with " + to_wstring(noOfMoves);
MessageBox(hwnd, moves.c_str(), L"Finished game", MB_OK);
}
case WM_PAINT: {
char wall[2] = { "W" };
char floor[2] = { 'W' };
char current[2] = { "X" };
char goal[2] = { "G" };
wstring position = L"Position = [" + to_wstring(x) + L", " + to_wstring(y) + L"]";
wstring moves = L"Move = " + to_wstring(noOfMoves);
hdc = BeginPaint(hwnd, &ps);
TextOut(hdc, 20, 200, position.c_str(), position.size());
TextOut(hdc, 20, 220, moves.c_str(), moves.size());
for (int i = 0; i < 20; i++) {
for (int j = 0; j < 20; j++) {
if (level1[j][i] == '1') {
SetTextColor(hdc, RGB(0, 0, 0));
SetBkColor(hdc, RGB(0, 0, 0));
TextOut(hdc, 14 * i + 190, 14 * j + 20, LPCTSTR(wall), strlen(wall));
}
SetBkColor(hdc, RGB(255, 255, 255));
if (level1[j][i] == '0') {
SetTextColor(hdc, RGB(255, 255, 255));
TextOut(hdc, 14 * i + 190, 14 * j + 20, LPCTSTR(floor), strlen(floor));
}
SetTextColor(hdc, RGB(0, 0, 0));
if (i == x && j == y)
TextOut(hdc, 14 * i + 190, 14 * j + 20, LPCTSTR(current), strlen(current));
if (level1[j][i] == 'e')
TextOut(hdc, 14 * i + 190, 14 * j + 20, LPCTSTR(goal), strlen(goal));
}
}
EndPaint(hwnd, &ps);
break;
}
case WM_ERASEBKGND:
return true;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
HMENU CreateMainMenu() {
HMENU main = CreateMenu();
HMENU file = CreateMenu();
AppendMenu(file, MF_STRING, ID_NEW, L"&New");
AppendMenu(file, MF_SEPARATOR, 0, 0);
AppendMenu(file, MF_STRING, ID_QUIT, L"&Quit");
AppendMenu(main, MF_POPUP, (UINT_PTR)file, L"&File");
HMENU help = CreateMenu();
AppendMenu(help, MF_STRING, ID_ABOUT, L"&About");
AppendMenu(main, MF_POPUP, (UINT_PTR)help, L"&Help");
return main;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow) {
readLevel("level1.txt", level1);
WNDCLASS wc = { 0 };
wc.hbrBackground = NULL;
wc.lpfnWndProc = WinProc;
wc.hInstance = hInstance;
wc.lpszClassName = L"MyWindowClass";
RegisterClass(&wc);
HWND hwnd = CreateWindow(L"MyWindowClass", L"The Maze",
WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
windowWidth, windowHeight, 0, CreateMainMenu(), hInstance, 0);
HWND buttonNorth = CreateWindow(L"BUTTON", L"NORTH", WS_CHILD | WS_VISIBLE,
10, 20, 150, 40, hwnd, (HMENU)NORTH_BUTTON_ID, hInstance, 0);
HWND buttonSouth = CreateWindow(L"BUTTON", L"SOUTH", WS_CHILD | WS_VISIBLE,
10, 60, 150, 40, hwnd, (HMENU)SOUTH_BUTTON_ID, hInstance, 0);
HWND buttonEast = CreateWindow(L"BUTTON", L"EAST", WS_CHILD | WS_VISIBLE,
10, 140, 150, 40, hwnd, (HMENU)EAST_BUTTON_ID, hInstance, 0);
HWND buttonWest = CreateWindow(L"BUTTON", L"WEST", WS_CHILD | WS_VISIBLE,
10, 100, 150, 40, hwnd, (HMENU)WEST_BUTTON_ID, hInstance, 0);
UpdateWindow(hwnd);
ShowWindow(hwnd, nCmdShow);
MSG msg = { 0 };
BOOL isRunning = true;
while (isRunning) {
while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {
if (msg.message == WM_QUIT)
isRunning = false;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
wc.hbrBackground = NULL;
InvalidateRect(hwnd, NULL, FALSE);
Sleep(10);
}
return 0;
}
As member Retired Ninja said, you make compatible device context with the original one ( hdc in your case ), and create a bitmap compatible with your original device context ( bitmap size is equal to the size of your rectangle where you paint your stuff ).
Then select this newly created bitmap into compatible device context you just created and draw everything on it.
Then you just BitBlt(...) the compatible device context into original one.
Do not forget to perform proper cleanup in order to avoid GDI leaks.
Your code should look like this:
case WM_PAINT:
{
// skipped the initialization part to preserve space
// just copy those, they are irrelevant for your problem
hdc = BeginPaint(hwnd, &ps);
// create memory DC and memory bitmap where we shall do our drawing
HDC memDC = CreateCompatibleDC( hdc );
// get window's client rectangle. We need this for bitmap creation.
RECT rcClientRectangle;
GetClientRect( hwnd, &rcClientRect );
// now we can create bitmap where we shall do our drawing
HBITMAP bmp = CreateCompatibleBitmap( hdc,
rcClientRect.right - rcClientRect.left,
rcClientRect.bottom - rcClientRect.top );
// we need to save original bitmap, and select it back when we are done,
// in order to avoid GDI leaks!
HBITMAP oldBmp = (HBITMAP)SelectObject( memDC, bmp );
// now you draw your stuff in memory dc;
// just substitute hdc with memDC in your drawing code,
// like I did below:
TextOut( memDC, //...
TextOut( memDC, //...
for (int i = 0; i < 20; i++)
{
for (int j = 0; j < 20; j++)
{
if (level1[j][i] == '1')
{
SetTextColor( memDC, //...
SetBkColor( memDC, //...
TextOut( memDC, //...
}
SetBkColor( memDC, //...
if (level1[j][i] == '0')
{
SetTextColor( memDC, //...
TextOut( memDC, //...
}
SetTextColor( memDC, //...
if (i == x && j == y)
TextOut( memDC, //...
if (level1[j][i] == 'e')
TextOut( memDC, //...
}
}
// OK, everything is drawn into memory DC,
// now is the time to draw that final result into our target DC
BitBlt( hdc, 0, 0, rcClientRect.right - rcClientRect.left,
rcClientRect.bottom - rcClientRect.top, memDC, 0, 0, SRCCOPY );
// all done, now we need to cleanup
SelectObject( memDC, oldBmp ); // select back original bitmap
DeleteObject( bmp ); // delete bitmap since it is no longer required
DeleteDC( memDC ); // delete memory DC since it is no longer required
EndPaint(hwnd, &ps);
break;
}
this is an example code of msdn to create toolbar, but this example use the standard images of the system.
What do I need to change in this code to use my images from resource file, for example: IDB_COPY BITMAP "copy.bmp", and IDB_CUT BITMAP "cut.bmp", and IDB_PASTE BITMAP "paste.bmp".
HIMAGELIST g_hImageList = NULL;
HWND CreateSimpleToolbar(HWND hWndParent)
{
// Declare and initialize local constants.
const int ImageListID = 0;
const int numButtons = 3;
const int bitmapSize = 16;
const DWORD buttonStyles = BTNS_AUTOSIZE;
// Create the toolbar.
HWND hWndToolbar = CreateWindowEx(0, TOOLBARCLASSNAME, NULL,
WS_CHILD | TBSTYLE_WRAPABLE, 0, 0, 0, 0,
hWndParent, NULL, g_hInst, NULL);
if (hWndToolbar == NULL)
return NULL;
// Create the image list.
g_hImageList = ImageList_Create(bitmapSize, bitmapSize, // Dimensions of individual bitmaps.
ILC_COLOR16 | ILC_MASK, // Ensures transparent background.
numButtons, 0);
// Set the image list.
SendMessage(hWndToolbar, TB_SETIMAGELIST,
(WPARAM)ImageListID,
(LPARAM)g_hImageList);
// Load the button images.
SendMessage(hWndToolbar, TB_LOADIMAGES,
(WPARAM)IDB_STD_SMALL_COLOR,
(LPARAM)HINST_COMMCTRL);
// Initialize button info.
// IDM_NEW, IDM_OPEN, and IDM_SAVE are application-defined command constants.
TBBUTTON tbButtons[numButtons] =
{
{ MAKELONG(STD_FILENEW, ImageListID), IDM_NEW, TBSTATE_ENABLED, buttonStyles, {0}, 0, (INT_PTR)L"New" },
{ MAKELONG(STD_FILEOPEN, ImageListID), IDM_OPEN, TBSTATE_ENABLED, buttonStyles, {0}, 0, (INT_PTR)L"Open"},
{ MAKELONG(STD_FILESAVE, ImageListID), IDM_SAVE, 0, buttonStyles, {0}, 0, (INT_PTR)L"Save"}
};
// Add buttons.
SendMessage(hWndToolbar, TB_BUTTONSTRUCTSIZE, (WPARAM)sizeof(TBBUTTON), 0);
SendMessage(hWndToolbar, TB_ADDBUTTONS, (WPARAM)numButtons, (LPARAM)&tbButtons);
// Resize the toolbar, and then show it.
SendMessage(hWndToolbar, TB_AUTOSIZE, 0, 0);
ShowWindow(hWndToolbar, TRUE);
return hWndToolbar;
}
I found this solution:
const int ID_TB_STANDARD = 0;
const int ID_IL_STANDARD = 0;
HWND hWndToolbar = CreateWindowEx(0, TOOLBARCLASSNAME, NULL,
WS_CHILD | TBSTYLE_TOOLTIPS, 0, 0, 0, 0, hWnd, (HMENU)ID_TB_STANDARD, hInstance, NULL);
HIMAGELIST hImageList = ImageList_LoadBitmap(hInstance, MAKEINTRESOURCEW(IDB_CUT), 16, 0, RGB(255, 0, 255));
ImageList_Add(hImageList, LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_COPY)), NULL);
ImageList_Add(hImageList, LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_PASTE)), NULL);
SendMessage(hWndToolbar, TB_SETIMAGELIST, (WPARAM)ID_IL_STANDARD, (LPARAM)hImageList);
SendMessage(hWndToolbar, (UINT) TB_SETHOTIMAGELIST, 0, (LPARAM)hHotImageList);
SendMessage(hWndToolbar, TB_BUTTONSTRUCTSIZE, (WPARAM)sizeof(TBBUTTON), 0);
TBBUTTON tbb[3] =
{
{0,ID_CUT,TBSTATE_ENABLED,TBSTYLE_BUTTON},
{1,ID_COPY,TBSTATE_ENABLED,TBSTYLE_BUTTON},
{2,ID_PASTE,TBSTATE_ENABLED,TBSTYLE_BUTTON},
};
SendMessage(hWndToolbar, (UINT) TB_ADDBUTTONS, 3, (LPARAM)&tbb);
SendMessage(hWndToolbar, TB_AUTOSIZE, 0, 0);
ShowWindow(hWndToolbar , SW_SHOW);
I am writing a WIN32 DirectX 9 program in which I load a few textures (a person and a background) and display them on the screen. However, they become warped (stretched), not being a one-to-one representation of what I drew in Paint. I tried different window sizes and different screen resolutions, but it still doesn't work.
I can force a very close imitation of the original thing by calling D3DXMatrixTransformation2D before drawing the sprite. However, that doesn't fix the problem. My program relies on me knowing exactly where the person is in relevence to the background (in reality, the background moves and the person stays in the middle of the screen).
Is there something simple I am missing or is it that I just can't do that for some reason? I can give code if it more than a simple fix, but I hope not. For the record, I recieve no errors or warnings; it's just a visual and movement-tracking issue. Thank you.
EDIT: Here's some code:
//start of program
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
//Define and register the Windows Class ***Function
createWindowClass(hInstance);
//Create the window (still not shown)
HWND hWnd = CreateWindow("Sample Window Class", "Person With Ship", WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 800, 600, NULL, NULL, hInstance, NULL);
//Define and create the DirectX9 object ***Function
HRESULT hr = createDirectX(hWnd);
D3DXCreateSprite(d3dDevice, &sprite);
D3DXCreateTextureFromFile(d3dDevice, "landingPad2.png", &texture);
D3DXCreateTextureFromFile(d3dDevice, "person.png", &person);
//D3DXCreateTextureFromFile(d3dDevice, "secondRoom.png", &secondRoom);
//Set up text
LPD3DXFONT mFont;
D3DXCreateFont(d3dDevice, 20, 0, FW_BOLD, 0, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,
DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, TEXT("Arial"), &mFont );
//Finally show window
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
//setup keyboard
RAWINPUTDEVICE Rid[1]; // array of structs for input devices
Rid[0].usUsagePage = 1; // use 1 for most inputs
Rid[0].usUsage = 6; //2-mouse, 4-joystick, 6-keyboard
Rid[0].dwFlags = 0; //use 0
Rid[0].hwndTarget=NULL; //use NULL
RegisterRawInputDevices(Rid,1,sizeof(RAWINPUTDEVICE)); // registers all of the input devices
//MAIN LOOP!!
MSG msg;
ZeroMemory(&msg, sizeof(msg));
while (msg.message!=WM_QUIT)
{
while(PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
updateGraphics(hr, mFont);
updatePosition();
}
mFont->Release();
texture->Release();
return msg.wParam;
}
void createWindowClass(HINSTANCE hInstance)
{
const LPCSTR CLASS_NAME = "Sample Window Class";
//create windows object
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style= CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc= (WNDPROC)WndProc;
wcex.cbClsExtra= 0;
wcex.cbWndExtra= 0;
wcex.hInstance= hInstance;
wcex.hIcon= 0;
wcex.hCursor= LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground= (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName= 0;
wcex.lpszClassName= CLASS_NAME;
wcex.hIconSm= 0;
//register windows class
RegisterClassEx(&wcex);
}
HRESULT createDirectX(HWND hWnd)
{
//create directx object
d3dObject = Direct3DCreate9(D3D_SDK_VERSION);
if (d3dObject==NULL)
{
exit(1);
}
//Present Parameters struct
D3DPRESENT_PARAMETERS presParams;
//Sets everything to 0
ZeroMemory(&presParams, sizeof(presParams));
presParams.Windowed = TRUE;
presParams.SwapEffect = D3DSWAPEFFECT_DISCARD;
presParams.BackBufferFormat = D3DFMT_UNKNOWN;
presParams.PresentationInterval = D3DPRESENT_INTERVAL_ONE;
//DIRECT3D Stuff (not used currently)
//presParams.EnableAutoDepthStencil = TRUE;
//presParams.AutoDepthStencilFormat = D3DFMT_D16;
//d3dDevice->SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE);
//D3DXMatrixIdentity( &worldMatrix );
HRESULT hr = d3dObject->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL,hWnd, D3DCREATE_HARDWARE_VERTEXPROCESSING, &presParams, &d3dDevice);
return hr;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_INPUT:
{
UINT bufferSize;
GetRawInputData((HRAWINPUT)lParam, RID_INPUT, NULL, &bufferSize, sizeof (RAWINPUTHEADER));
// Create a buffer of the correct size
BYTE *buffer=new BYTE[bufferSize];
// Call the function again, this time with the buffer to get the data
GetRawInputData((HRAWINPUT)lParam, RID_INPUT, (LPVOID)buffer, &bufferSize, sizeof (RAWINPUTHEADER));
PRAWINPUT raw = (RAWINPUT*) buffer;
getInput(raw);
break;
}
case WM_COMMAND:
{
int wmId = LOWORD(wParam);
int wmEvent = HIWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case IDM_EXIT:
DestroyWindow(hWnd);
break;
}
break;
}
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
void getInput(PRAWINPUT raw)
{
if (raw->header.dwType== RIM_TYPEKEYBOARD)
{
USHORT keyCode = raw->data.keyboard.VKey;
switch(keyCode)
{
case VK_LEFT:
keyUp=raw->data.keyboard.Flags & RI_KEY_BREAK;
if (keyUp == false)
counterTrue = true;
else
counterTrue = false;
break;
case VK_RIGHT:
keyUp=raw->data.keyboard.Flags & RI_KEY_BREAK;
if (keyUp == false)
clockwiseTrue = true;
else
clockwiseTrue = false;
break;
case VK_UP:
keyUp=raw->data.keyboard.Flags & RI_KEY_BREAK;
if (keyUp == false)
upTrue = true;
else
upTrue = false;
break;
case VK_DOWN:
keyUp=raw->data.keyboard.Flags & RI_KEY_BREAK;
if (keyUp == false)
downTrue = true;
else
downTrue = false;
break;
default:
break;
}
if (keyCode == 'A')
{
keyUp=raw->data.keyboard.Flags & RI_KEY_BREAK;
if (keyUp == false)
leftTrue = true;
else
leftTrue = false;
}
if (keyCode == 'D')
{
keyUp=raw->data.keyboard.Flags & RI_KEY_BREAK;
if (keyUp == false)
rightTrue = true;
else
rightTrue = false;
}
if (keyCode == 'W')
{
keyUp=raw->data.keyboard.Flags & RI_KEY_BREAK;
if (keyUp == false)
upTrue = true;
else
upTrue = false;
}
if (keyCode == 'S')
{
keyUp=raw->data.keyboard.Flags & RI_KEY_BREAK;
if (keyUp == false)
downTrue = true;
else
downTrue = false;
}
}
}
void updateGraphics(HRESULT hr, LPD3DXFONT mFont)
{
hr = d3dDevice->Clear(0, NULL, D3DCLEAR_TARGET| D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0,0,0), 1.0f, 0);
hr = d3dDevice->BeginScene();
sprite->Begin(D3DXSPRITE_ALPHABLEND);
// Texture being used is 64 by 64:
D3DXVECTOR2 spriteCentre=D3DXVECTOR2(rotationCenter.x, rotationCenter.y);
// Screen position of the sprite
D3DXVECTOR2 trans=D3DXVECTOR2(pos.x, pos.y);
// Build our matrix to rotate, scale and position our sprite
D3DXMATRIX mat;
D3DXVECTOR2 scaling(0.5798f, 0.784f);
// out, scaling centre, scaling rotation, scaling, rotation centre, rotation, translation
D3DXMatrixTransformation2D(&mat,NULL, NULL, &scaling,&spriteCentre,rotation,NULL/*&trans*/);
// Tell the sprite about the matrix
sprite->SetTransform(&mat);
sprite->Draw(texture, NULL, &rotationCenter, &pos, 0xFFFFFFFF);
scaling.x = 0.53;
scaling.y = 0.57f;
D3DXMatrixTransformation2D(&mat,NULL,0.0, &scaling,&spriteCentre, 0,NULL/*&trans*/);
sprite->SetTransform(&mat);
sprite->Draw(person, NULL, NULL, &personPos, 0xFFFFFFFF);
sprite->End();
DisplaySomeText(mFont);
d3dDevice->EndScene();
d3dDevice->Present(NULL, NULL, NULL, NULL);
}
void updatePosition()
{
if (clockwiseTrue == true)
{
rotation -= (float)0.03;
}
else if (counterTrue == true)
{
rotation += (float)0.03;
}
if (rotation >(PI))
{
rotation -= (float)(2*PI);
}
if (rotation <= -(PI))
{
rotation += (float)(2*PI);
}
if (upTrue == true)
{
pos.y += (3*cos(rotation));
pos.x += (3*sin(rotation));
}
else if (downTrue == true)
{
pos.y -= (3*cos(rotation));
pos.x -= (3*sin(rotation));
}
if (leftTrue == true)
{
pos.x += (3*cos(rotation));
pos.y -= (3*sin(rotation));
}
else if (rightTrue == true)
{
pos.x -= (3*cos(rotation));
pos.y += (3*sin(rotation));
}
//collision detection
if (rotation >=0 && rotation < (PI/2))
{
if (pos.y - (30*cos(rotation)) - (30*sin(rotation)) < -138 && pos.x < 350 && pos.x > -550)
{
pos.y = -142 + (30*cos(rotation)) + (30*sin(rotation));
}
}
if (rotation < 0 && rotation > -(PI/2))
{
if (pos.y - (51*cos(rotation)) + (14*sin(rotation)) < -142 && pos.x < 350 && pos.x > -550)
{
pos.y = -142 + (51*cos(rotation)) - (14*sin(rotation));
}
}
if (rotation < -(PI/2) && rotation > -(PI))
{
if (pos.y + (51*cos(rotation)) + (14*sin(rotation)) < -142 && pos.x < 350 && pos.x > -550)
{
pos.y = -142 - (51*cos(rotation)) - (14*sin(rotation));
}
}
if (rotation > (PI/2) && rotation <= (PI))
{
if (pos.y + (51*cos(rotation)) - (14*sin(rotation)) < -142 && pos.x < 350 && pos.x > -550)
{
pos.y = -142 - (51*cos(rotation)) + (14*sin(rotation));
}
}
}
void DisplaySomeText(LPD3DXFONT mFont)
{
// Create a colour for the text - in this case blue
D3DCOLOR fontColor = D3DCOLOR_ARGB(255,0,0,255);
// Create a rectangle to indicate where on the screen it should be drawn
RECT rct;
rct.left=200;
rct.right=780;
rct.top=10;
rct.bottom=rct.top+20;
TCHAR cX[30] = "x";
TCHAR cY[30] = "y";
TCHAR cR[30] = "r";
TCHAR cQ[30] = "q";
size_t cchDest = 30;
LPCTSTR pszFormat = TEXT("%f");
HRESULT har = StringCchPrintf(cX, cchDest, pszFormat, pos.x);
HRESULT her = StringCchPrintf(cY, cchDest, pszFormat, pos.y);
HRESULT hir = StringCchPrintf(cR, cchDest, pszFormat, rotation);
HRESULT hur = StringCchPrintf(cQ, cchDest, pszFormat, (pos.y - (43*cos(rotation))));
mFont->DrawText(NULL, cX, -1, &rct, 0, fontColor);
rct.left += 100;
mFont->DrawText(NULL, cY, -1, &rct, 0, fontColor);
rct.left += 100;
mFont->DrawText(NULL, cR, -1, &rct, 0, fontColor);
rct.left += 100;
mFont->DrawText(NULL, cQ, -1, &rct, 0, fontColor);
}
So, finally: the issue was due to the texture dimensions not being powers of two :) This behaviour is quite usual, but it is still hardware-dependent: in theory there may exist some videocards which handle arbitrary texture sizes the same way as power-of-two-sized ones. To know that they do we'd have to check their capabilities via IDirect3DDevice9::GetDeviceCaps.