Direct2D bitmap RAM usage optimization - c++

Currently I wrote some code that loads original image with WIC, stores it in variable as ID2D1Bitmap* and then creates another resized one, via compatible render target and scale effect (I can provide example, if needed), so, for every basic image I have two bitmaps.
However, bitmaps use a lot of ram — loading just 10 2mb images costs more than 100mb of ram. I don’t understand why it uses ram at all, if it should be in GPU memory, as I understand.
So, I asking here the solution to reduce that ram usage.
I read about atlas method, but it seems to be hard to develop. Maybe there are another tricks?
Example of code
#include <Windows.h>
HDC hdcDevice = GetDC(NULL);
int xw = GetDeviceCaps(hdcDevice, HORZRES);
int yw = GetDeviceCaps(hdcDevice, VERTRES);
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp);
#include <d2d1_1.h>
#include <dwrite.h>
#include <wincodec.h>
#pragma comment(lib, "d2d1")
#pragma comment(lib, "dxguid.lib")
#pragma comment(lib, "dwrite.lib")
using namespace std;
template<class Interface>
inline void SafeRelease(
Interface** ppInterfaceToRelease)
{
if (*ppInterfaceToRelease != NULL)
{
(*ppInterfaceToRelease)->Release();
(*ppInterfaceToRelease) = NULL;
}
}
ID2D1Bitmap* bitmap;
ID2D1Factory* factory;
IWICImagingFactory* d2dWICFactory;
IWICFormatConverter* d2dConverter;
IDWriteFactory* writeFactory;
IWICFormatConverter* d2dConverter2 = nullptr;
ID2D1BitmapRenderTarget* back = nullptr;
ID2D1DeviceContext* tar = nullptr;
ID2D1DeviceContext* target = nullptr;
ID2D1Effect* scale = nullptr;
class UIElement
{
public:
ID2D1Bitmap* imgOrig;
ID2D1Bitmap* img;
D2D1_SIZE_F si;
ID2D1DeviceContext* tar;
float x;
float y;
float width;
float height;
UIElement(ID2D1DeviceContext *tar, float x, float y, float width, float height)
{
this->tar = tar;
this->x = x; this->y = y; this->width = width; this->height = height;
this->img = nullptr;
scale->SetValue(D2D1_SCALE_PROP_INTERPOLATION_MODE, D2D1_INTERPOLATION_MODE::D2D1_INTERPOLATION_MODE_HIGH_QUALITY_CUBIC);
}
void setBackgroundImage(const wchar_t* path)
{
IWICBitmapDecoder* d2dDecoder;
IWICBitmapFrameDecode* d2dBmpSrc;
IWICFormatConverter* d2dConverter2 = nullptr;
d2dWICFactory->CreateFormatConverter(&d2dConverter2);
d2dWICFactory->CreateDecoderFromFilename(path, NULL, GENERIC_READ,
WICDecodeMetadataCacheOnLoad, &d2dDecoder);
if (d2dDecoder)
{
d2dDecoder->GetFrame(0, &d2dBmpSrc);
if (d2dBmpSrc && d2dConverter2)
{
d2dConverter2->Initialize(d2dBmpSrc, GUID_WICPixelFormat32bppPBGRA,
WICBitmapDitherTypeNone, NULL, 0.f, WICBitmapPaletteTypeMedianCut);
tar->CreateBitmapFromWicBitmap(d2dConverter2, NULL, &imgOrig);
if (imgOrig)
{
si = imgOrig->GetSize();
RescaleImage();
}
}
}
SafeRelease(&d2dConverter2);
SafeRelease(&d2dDecoder);
SafeRelease(&d2dBmpSrc);
}
inline void RescaleImage(ID2D1Bitmap* cache = nullptr)
{
SafeRelease(&img);
tar->CreateBitmap(D2D1::SizeU(width, height), 0, 0, D2D1::BitmapProperties(
D2D1::PixelFormat(DXGI_FORMAT::DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE::D2D1_ALPHA_MODE_PREMULTIPLIED)
), &img);
if (cache != nullptr)
scale->SetInput(0, cache);
else if (this->imgOrig)
scale->SetInput(0, this->imgOrig);
scale->SetValue(D2D1_SCALE_PROP_SCALE, D2D1::Vector2F(this->width / si.width, this->height / si.height));
ID2D1BitmapRenderTarget* rnd = nullptr;
tar->CreateCompatibleRenderTarget(D2D1::SizeF(width, height), &rnd);
ID2D1DeviceContext* rndc = nullptr;
rnd->QueryInterface(&rndc);
rndc->BeginDraw();
rndc->DrawImage(scale);
rndc->EndDraw();
img->CopyFromRenderTarget(0, rndc, 0);
SafeRelease(&rndc);
SafeRelease(&rnd);
}
inline void Render()
{
D2D1_RECT_F rect = D2D1::RectF(this->x, this->y, this->x + this->width, this->y + this->height);
if(img)
this->tar->DrawBitmap(img, rect);
}
}*elements[100] = { NULL };
inline void Render()
{
tar->BeginDraw();
tar->Clear(D2D1::ColorF(1,1,1,1));
target->BeginDraw();
target->Clear(D2D1::ColorF(1,0,1,1));
for (int i = 0; i < 100 && elements[i]; i++)
elements[i]->Render();
auto hr = target->EndDraw();
tar->DrawImage(bitmap);
hr = tar->EndDraw();
}
int WINAPI WinMain(HINSTANCE hin, HINSTANCE, LPSTR, int)
{
ReleaseDC(NULL, hdcDevice);
WNDCLASS c = { NULL };
c.lpszClassName = L"asd";
c.lpfnWndProc = WndProc;
c.hInstance = hin;
c.style = CS_VREDRAW | CS_HREDRAW;
c.hCursor = LoadCursor(NULL, IDC_ARROW);
c.hbrBackground = CreateSolidBrush(RGB(255, 255, 255));
RegisterClass(&c);
int cx = 500, cy = 500;
int x = xw / 2 - cx / 2, y = yw / 2 - cy / 2;
HWND hwnd = CreateWindowEx(NULL, L"asd", L"asd", WS_POPUP | WS_VISIBLE, x, y, cx, cy, NULL, NULL, hin, 0);
HeapSetInformation(NULL, HeapEnableTerminationOnCorruption, NULL, 0);
CoInitialize(NULL);
D2D1CreateFactory(D2D1_FACTORY_TYPE::D2D1_FACTORY_TYPE_MULTI_THREADED, &factory);
CoCreateInstance(CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER,
__uuidof(IWICImagingFactory), (void**)(&d2dWICFactory));
d2dWICFactory->CreateFormatConverter(&d2dConverter);
DWriteCreateFactory(
DWRITE_FACTORY_TYPE_SHARED,
__uuidof(writeFactory),
reinterpret_cast<IUnknown**>(&writeFactory)
);
d2dWICFactory->CreateFormatConverter(&d2dConverter2);
D2D1_SIZE_U size = D2D1::SizeU(cx, cy);
ID2D1HwndRenderTarget* a = nullptr;
factory->CreateHwndRenderTarget(D2D1::RenderTargetProperties(D2D1_RENDER_TARGET_TYPE_DEFAULT, D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN, D2D1_ALPHA_MODE_PREMULTIPLIED)), D2D1::HwndRenderTargetProperties(hwnd, size), &a);//);
a->QueryInterface(&tar);
tar->CreateCompatibleRenderTarget(&back);
back->QueryInterface(&target);
back->GetBitmap(&bitmap);
target->CreateEffect(CLSID_D2D1Scale, &scale);
scale->SetValue(D2D1_SCALE_PROP_INTERPOLATION_MODE, D2D1_INTERPOLATION_MODE::D2D1_INTERPOLATION_MODE_HIGH_QUALITY_CUBIC);
MSG msg;
for (int i = 0; i < 10; i++)
{
elements[i] = new UIElement(target, 50*i, 10, 50, 50);
elements[i]->setBackgroundImage(L"bitmap.bmp");
}
while (GetMessage(&msg, NULL, 0, 0))
{
Render();
TranslateMessage(&msg);
DispatchMessage(&msg);
}
CoUninitialize();
return 0;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
{
switch (message)
{
case WM_LBUTTONDOWN:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, message, wp, lp);
}
return NULL;
}
*I want Windows 7 support.

As Simon Mourier pointed in comments, it seems that in my code WIC bitmap's memory, allocated at RAM is not being free, even despite on realizing all wic's com objects.
So, I tried to get bitmap from wic not to final direct2d bitmap I need but for temporary direct2d bitmap, then create empty final direct2d bitmap, copy there temp bitmap and release temp bitmap.
This worked, now with 10 2mb png images (with their resized duplicates) my program uses few megabytes of RAM, and earlier about 120mb.
// WIC loading stuff
ID2D1Bitmap *temp = nullptr;
ID2D1Bitmap *imgOrig = nullptr;
target->CreateBitmapFromWicBitmap(d2dConverter, NULL, &temp);
if (temp)
{
D2D1_SIZE_F size = temp->GetSize();
target->CreateBitmap(D2D1::SizeU(size.width, size.height), 0, 0, D2D1::BitmapProperties(
D2D1::PixelFormat(DXGI_FORMAT::DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE::D2D1_ALPHA_MODE_PREMULTIPLIED)
), &imgOrig);
imgOrig->CopyFromBitmap(0, temp, 0);
SafeRelease(&temp);
}
// Release WIC

Related

Why is D3Dcompiler_43.dll Loaded and Unloaded every frame (huge performance hit), but it only happens when I have two windows of different sizes open?

Why is D3Dcompiler_43.dll Loaded and Unloaded every frame?
Why does my two window direct-X 11 application drop from 2000 Hz to 12 Hz when I resize one of the windows?
In simplified sample I have attached code from, it starts with two identical sized windows at 2000 Hz, but if I change the size of either one, the frame rate of both goes to 12 Hz.
If I minimize either one, I get back to full speed, 4000Hz with one window.
When it is running at 12 Hz, I get the following Output Trace EVERY FRAME:
'Galaxies.exe' (Win32): Loaded 'C:\Windows\System32\D3Dcompiler_43.dll'
'Galaxies.exe' (Win32): Unloaded 'C:\Windows\System32\D3Dcompiler_43.dll'
This trace comes out when I call IDGXISwapChain->Present().
This trace does not come out when running 2000Hz.
I do not expect to need D3Dcompiler_43.dll at all, since I build my shaders at compile time, not run time. But if it did need it, then it should load it and keep it, not load each frame.
And if I make the window sizes match again, or minimize one, then the trace stops.
C++, Directx 11
My basic template is based on the Microsoft Sample "SimpleTexturePC".
Main changes from that template:
compile textures into program rather than reading at run time
compile shaders into program rather than reading at run time
extend DeviceResources to be able to support more than one window
by making arrays for all the resources, such as RenderTargetView
Extending Main.cpp to create more than one window, and have a WinProc for each.
Each of these unique WinProcs then calls a WinProcCommon with an "index" that identifies the window.
Adding a second camera for use on 2nd window
Adding a trace to the main application "Galaxies.cpp" so I could see the FPS.
(the rest of the main application behavior is not in simplified sample).
Main.cpp
//
// Main.cpp
//
#include ...
namespace
{
std::unique_ptr<Galaxies> g_game_p;
};
LPCWSTR g_szAppName0 = L"World1";
LPCWSTR g_szAppName1 = L"World2";
LPCWSTR g_szAppName2 = L"World3";
LRESULT CALLBACK WndProcWorld1(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK WndProcWorld2(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK WndProcWorld3(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK WndProcCommon(UINT, HWND, UINT, WPARAM, LPARAM);
// Entry point
int WINAPI wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
if (!XMVerifyCPUSupport())
return 1;
HRESULT hr = CoInitializeEx(nullptr, COINITBASE_MULTITHREADED);
if (FAILED(hr))
return 1;
g_game_p = std::make_unique<Galaxies>();
int border = getInvisableBorderWidth();
// Register / create window 1
{
// Register class
WNDCLASSEXW wcex = {};
wcex.cbSize = sizeof(WNDCLASSEXW);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProcWorld1;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIconW(hInstance, L"IDI_ICON1");
wcex.hCursor = LoadCursorW(nullptr, IDC_ARROW);
wcex.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_WINDOW + 1);
wcex.lpszClassName = L"WindowClass1";
wcex.hIconSm = LoadIconW(wcex.hInstance, L"IDI_ICON1");
if (!RegisterClassExW(&wcex)) // W implies unicode version.
return 1;
// Create window
int w, h;
g_game_p->GetDefaultWindowSize(w, h);
HWND hwnd = CreateWindowExW(0, wcex.lpszClassName, g_szAppName0, WS_OVERLAPPEDWINDOW,
50 - border, 50, w, h, nullptr, nullptr, hInstance, nullptr);
SetWindowLongPtr(hwnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(g_game_p.get()));
if (!hwnd)
return 1;
g_game_p->Initialize(kGameWindow1, hwnd, w, h); // this chooses non-fullscreen location, though we will go full screen in a sec...
ShowWindow(hwnd, SW_SHOWNORMAL);
}
// Register / create window 2
{
// Register class
WNDCLASSEXW wcex = {};
wcex.cbSize = sizeof(WNDCLASSEXW);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProcWorld2;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIconW(hInstance, L"IDI_ICON2");
wcex.hCursor = LoadCursorW(nullptr, IDC_ARROW);
wcex.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_WINDOW + 1);
wcex.lpszClassName = L"WindowClass2";
wcex.hIconSm = LoadIconW(wcex.hInstance, L"IDI_ICON2");
if (!RegisterClassExW(&wcex)) // W implies unicode version.
return 1;
// Create window
int w, h;
g_game_p->GetDefaultWindowSize(w, h);
HWND hwnd = CreateWindowExW(0, wcex.lpszClassName, g_szAppName1, WS_OVERLAPPEDWINDOW,
100 - border, 100, w + 00, h + 00, nullptr, nullptr, hInstance, nullptr);
SetWindowLongPtr(hwnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(g_game_p.get()));
if (!hwnd)
return 1;
g_game_p->Initialize(kGameWindow2, hwnd, w, h);
ShowWindow(hwnd, SW_SHOWNORMAL);
}
// Main message loop
MSG msg = {};
while (WM_QUIT != msg.message)
{
if (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
{
g_game_p->Tick();
}
}
g_game_p.reset();
CoUninitialize();
return static_cast<int>(msg.wParam);
}
// First parameter "index" used to differentiate the three windows.
LRESULT CALLBACK WndProcCommon(UINT index, HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
WindowStruct& winInfo = g_deviceResources_p->GetWindowStruct(index);
auto galaxies_p = reinterpret_cast<Galaxies*>(GetWindowLongPtr(hWnd, GWLP_USERDATA));
switch (message)
{
case WM_PAINT:
if (winInfo.in_sizemove && galaxies_p)
{
RECT rc;
GetWindowRect(hWnd, &rc);
galaxies_p->OnWindowSizeChanged(index, rc.right - rc.left, rc.bottom - rc.top);
galaxies_p->Tick();
}
else
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
EndPaint(hWnd, &ps);
}
break;
case WM_MOVE:
if (galaxies_p)
{
galaxies_p->OnWindowMoved(index);
}
break;
case WM_SIZE:
if (wParam == SIZE_MINIMIZED)
{
if (!winInfo.minimized)
{
winInfo.minimized = true;
if (!winInfo.in_suspend && galaxies_p)
galaxies_p->OnSuspending();
winInfo.in_suspend = true;
}
}
else if (winInfo.minimized)
{
winInfo.minimized = false;
if (winInfo.in_suspend && galaxies_p)
galaxies_p->OnResuming();
winInfo.in_suspend = false;
}
else if (!winInfo.in_sizemove && galaxies_p)
{
RECT rc;
GetWindowRect(hWnd, &rc);
galaxies_p->OnWindowSizeChanged(index, rc.right - rc.left, rc.bottom - rc.top);
}
break;
case WM_ENTERSIZEMOVE:
winInfo.in_sizemove = true;
break;
case WM_EXITSIZEMOVE:
winInfo.in_sizemove = false;
if (galaxies_p)
{
RECT rc;
GetWindowRect(hWnd, &rc);
galaxies_p->OnWindowSizeChanged(index, rc.right - rc.left, rc.bottom - rc.top);
}
break;
case WM_GETMINMAXINFO:
if (lParam)
{
auto info = reinterpret_cast<MINMAXINFO*>(lParam);
info->ptMinTrackSize.x = 320;
info->ptMinTrackSize.y = 200;
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
case ... mouse cases
Mouse::ProcessMessage(message, wParam, lParam);
break;
case WM_KEYDOWN:
case WM_KEYUP:
case WM_SYSKEYUP:
Keyboard::ProcessMessage(message, wParam, lParam);
break;
case WM_MENUCHAR:
return MAKELRESULT(0, MNC_CLOSE);
}
return DefWindowProc(hWnd, message, wParam, lParam);
}
// Windows procedure x3
LRESULT CALLBACK WndProcWorld1(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
return WndProcCommon(kGameWindow1, hWnd, message, wParam, lParam);
}
LRESULT CALLBACK WndProcWorld2(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
return WndProcCommon(kGameWindow2, hWnd, message, wParam, lParam);
}
LRESULT CALLBACK WndProcWorld3(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
return WndProcCommon(kGameWindow3, hWnd, message, wParam, lParam);
}
// Exit helper
void ExitGame() noexcept
{
PostQuitMessage(0);
}
Galaxies.cpp
//
// Galaxies.cpp
//
#include ...
// Global variables
std::unique_ptr<DX::StepTimer> g_timer_p;
std::unique_ptr<DX::DeviceResources> g_deviceResources_p;
std::unique_ptr<DirectX::CommonStates> g_states_p;
std::unique_ptr<padInput> g_input_p;
std::unique_ptr<Camera> g_camera_p[2];
std::unique_ptr<HudText> g_text_p;
Galaxies::Galaxies() noexcept(false)
{
g_deviceResources_p = std::make_unique<DX::DeviceResources>(DXGI_FORMAT_B8G8R8A8_UNORM_SRGB);
g_deviceResources_p->RegisterDeviceNotify(this);
}
void Galaxies::Initialize(UINT index, HWND window, int width, int height)
{
static int once = true;
if (once)
{
g_deviceResources_p->CreateDeviceResources();
once = false;
}
switch (index)
{
case kGameWindow1:
{
g_timer_p = std::make_unique<DX::StepTimer>();
g_input_p = std::make_unique<padInput>();
g_camera_p[0] = std::make_unique<Camera>();
g_camera_p[1] = std::make_unique<Camera>();
g_text_p = std::make_unique<HudText>();
// PER OBJECT INITIALIZE
g_camera_p[0]->Initialize(0);
g_camera_p[1]->Initialize(1);
g_input_p ->Initialize();
g_text_p ->Initialize();
g_deviceResources_p->SetWindow(index, window, width, height);
g_deviceResources_p->CreateWindowSizeDependentResources(index);
OnDeviceRestored();
break;
}
case kGameWindow2:
case kGameWindow3:
default:
{
g_deviceResources_p->SetWindow(index, window, width, height);
g_deviceResources_p->CreateWindowSizeDependentResources(index);
break;
}
}
}
void Galaxies::GetDefaultWindowSize(int& width, int& height) const noexcept
{
...
}
void Galaxies::OnDeviceLost()
{
g_states_p.reset();
m_spPerFrameConstantBuffer.Reset();
g_text_p->OnDeviceLost();
}
void Galaxies::OnDeviceRestored()
{
CreateDeviceDependentResources();
CreateWindowSizeDependentResources(0);
CreateWindowSizeDependentResources(1);
WindowSizeChangeConfirmed(0);
WindowSizeChangeConfirmed(1);
g_text_p->OnDeviceRestored();
}
void Galaxies::OnSuspending()
{
}
void Galaxies::OnResuming()
{
g_timer_p->ResetElapsedTime();
}
void Galaxies::OnWindowMoved(UINT index)
{
auto r = g_deviceResources_p->GetOutputSize(index);
g_deviceResources_p->WindowSizeChanged(index, r.width, r.height);
}
// Pass in CURRENT (Last known) window size (icluding frame), so we can compare that with current size
// as read in deviceResources.
void Galaxies::OnWindowSizeChanged(UINT index, int width, int height)
{
// returns false if size unchanged
if (g_deviceResources_p->WindowSizeChanged(index, width, height))
{
CreateWindowSizeDependentResources(0);
WindowSizeChangeConfirmed(index);
}
}
void Galaxies::Tick()
{
UpdateRenderGPUTextures();
g_timer_p->Tick([&]()
{
UpdateInput();
UpdateCameras();
UpdateWorld();
});
RenderWorld(0);
if (!g_deviceResources_p->isWindowMinimized(1))
{
RenderWorld(1);
}
}
void Galaxies::Clear(int index)
{
// Clear the views.
auto context = g_deviceResources_p->GetD3DDeviceContext();
auto renderTargetView = g_deviceResources_p->GetRenderTargetView(index);
auto depthStencilView = g_deviceResources_p->GetDepthStencilView(index);
context->ClearRenderTargetView(renderTargetView, Colors::Black);
context->ClearDepthStencilView(depthStencilView, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0);
}
void Galaxies::CreateDeviceDependentResources()
{
auto device = g_deviceResources_p->GetD3DDevice();
g_states_p = std::make_unique<CommonStates>(device);
// Create constant buffers.
D3D11_BUFFER_DESC bufferDesc = {};
bufferDesc.Usage = D3D11_USAGE_DYNAMIC;
bufferDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
bufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
bufferDesc.MiscFlags = 0;
bufferDesc.ByteWidth = sizeof(PerFrameConstantBuffer);
DX::ThrowIfFailed(device->CreateBuffer(&bufferDesc, nullptr, m_spPerFrameConstantBuffer.ReleaseAndGetAddressOf()));
}
// Allocate all memory resources that change on a window SizeChanged event.
void Galaxies::CreateWindowSizeDependentResources(UINT index)
{
// TODO: Initialize windows-size dependent objects here.
}
void Galaxies::UpdateRenderGPUTextures()
{
// Don't try to render anything before the first Update.
if (g_timer_p->GetFrameCount() == 0)
{
return;
}
}
void Galaxies::UpdateInput()
{
g_input_p->Update();
if (g_input_p->isKeyDownEdge(escape))
{
ExitGame();
}
}
void Galaxies::UpdateCameras()
{
g_camera_p[0]->Update();
// g_camera_p[1]->Update();
}
// Updates the world.
void Galaxies::UpdateWorld()
{
}
void Galaxies::RenderWorld(int index) // index 0, 1. not 2 (not edit window)
{
if (g_timer_p->GetFrameCount() == 0)
{
return;
}
Clear(index);
// Update Constants Buffer with per-frame variables.
// Though I now do this up to 3 times per frame - once per window.
auto context = g_deviceResources_p->GetD3DDeviceContext();
auto d3dBuffer = m_spPerFrameConstantBuffer.Get();
// Exclude 3rd window for now
if (index != 2)
{ // PRE-LOCK
MapGuard mappedResource(context, d3dBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0);
PerFrameConstantBuffer* data = reinterpret_cast<PerFrameConstantBuffer*>(mappedResource.get());
g_camera_p[index]->GetPerFrameData(data);
data->frameTime = g_timer_p->GetElapsedSeconds();
if (g_input_p->isButtonToggleSet(leftShoulder))
{
data->frameTime *= 5;
}
data->totalTime = g_timer_p->GetTotalSeconds();
int fps = (int)g_timer_p->GetFramesPerSecond();
char buffer[TEXT_NUM_OF_CHAR];
memset(buffer, 127, sizeof(buffer));
if (index == 0)
{
snprintf(&buffer[0 * TEXT_NUM_CHAR_PER_ROW], TEXT_NUM_CHAR_PER_ROW + 1, "Window 1 ");
}
else
{
snprintf(&buffer[0 * TEXT_NUM_CHAR_PER_ROW], TEXT_NUM_CHAR_PER_ROW + 1, "Window 2 ");
}
snprintf(&buffer[TEXT_NUM_CHAR_PER_ROW], TEXT_NUM_CHAR_PER_ROW + 1, "Galaxies V0.01 ");
snprintf(&buffer[2 * TEXT_NUM_CHAR_PER_ROW], TEXT_NUM_CHAR_PER_ROW + 1, " FPS = %d ", fps);
for (int i = 0; i < TEXT_NUM_OF_CHAR; i++)
{
data->alpha[4 * i] = buffer[i] - 0x20; // 0x20 is the first ascii char in our texture atlas. It is " "
}
} // UNLOCK (in mappedResource destructor)
context->VSSetConstantBuffers(CONSTANTS_PER_FRAME, 1, &d3dBuffer);
context->PSSetConstantBuffers(CONSTANTS_PER_FRAME, 1, &d3dBuffer);
auto renderTargetView = g_deviceResources_p->GetRenderTargetView(index);
auto depthStencilView = g_deviceResources_p->GetDepthStencilView(index);
context->OMSetRenderTargets(1, &renderTargetView, depthStencilView);
// Set the viewport.
auto viewport = g_deviceResources_p->GetScreenViewport(index);
context->RSSetViewports(1, &viewport);
if (index != 2)
{
g_text_p->Render();
}
g_deviceResources_p->Present(index);
}
void Galaxies::WindowSizeChangeConfirmed(UINT index)
{
auto size = g_deviceResources_p->GetOutputSize(index);
switch (index)
{
case (kGameWindow1):
g_camera_p[0]->OnWindowSizeChanged(size.width, size.height);
g_text_p ->OnWindowSizeChanged(size.width, size.height);
break;
case (kGameWindow2):
g_camera_p[1]->OnWindowSizeChanged(size.width, size.height);
break;
case (kGameWindow3):
break;
default:
break;
}
}
DeviceResources.cpp
//
// DeviceResources.cpp
//
#include ...
using namespace DirectX;
using namespace DX;
using Microsoft::WRL::ComPtr;
DeviceResources::DeviceResources(
DXGI_FORMAT backBufferFormat,
DXGI_FORMAT depthBufferFormat,
UINT backBufferCount,
D3D_FEATURE_LEVEL minFeatureLevel,
unsigned int flags) noexcept :
m_backBufferFormat{ backBufferFormat },
m_depthBufferFormat{ depthBufferFormat },
m_backBufferCount{backBufferCount},
m_d3dMinFeatureLevel(minFeatureLevel),
m_window(),
m_d3dFeatureLevel(D3D_FEATURE_LEVEL_9_1),
m_colorSpace(DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709),
m_options(flags | c_FlipPresent | c_AllowTearing),
m_deviceNotify(nullptr)
{
m_windowCount = 0;
for (int index = 0; index < c_MaxWindows; index++)
{
m_window[index] = nullptr;
m_WindowStruct[index] = WindowStruct();
m_screenViewport[index] = { 100, 100, 800, 600, 0, 1 };
}
}
void DeviceResources::CreateDeviceResources()
{
UINT creationFlags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;
CreateFactory();
...
// Determine feature levels
...
ComPtr<IDXGIAdapter1> adapter;
GetHardwareAdapter(adapter.GetAddressOf());
// Create the Direct3D 11 API device / context.
ComPtr<ID3D11Device> device;
ComPtr<ID3D11DeviceContext> context;
HRESULT hr = E_FAIL;
if (adapter)
{
hr = D3D11CreateDevice(
adapter.Get(),
D3D_DRIVER_TYPE_UNKNOWN,
nullptr,
creationFlags,
s_featureLevels,
featLevelCount,
D3D11_SDK_VERSION,
device.GetAddressOf(),
&m_d3dFeatureLevel,
context.GetAddressOf()
);
}
if (FAILED(hr))
{
// fall back to WARP device.
...
}
ThrowIfFailed(hr);
ThrowIfFailed(device.As(&m_d3dDevice));
ThrowIfFailed(context.As(&m_d3dContext));
}
// recreate every time the window size is changed.
void DeviceResources::CreateWindowSizeDependentResources(UINT index)
{
if (!m_window[index])
{
throw std::exception("need valid window handle");
}
// Clear the previous window size specific context.
ID3D11RenderTargetView* nullViews[] = { nullptr };
m_d3dContext->OMSetRenderTargets(_countof(nullViews), nullViews, nullptr);
m_d3dRenderTargetView[index].Reset();
m_d3dDepthStencilView[index].Reset();
m_renderTargetTexture[index].Reset();
m_depthStencilTexture[index].Reset();
m_d3dContext->Flush();
// Determine the render target size in pixels.
const UINT backBufferWidth = std::max<UINT>(static_cast<UINT>(m_WindowStruct[index].currentPos.width), 1u);
const UINT backBufferHeight = std::max<UINT>(static_cast<UINT>(m_WindowStruct[index].currentPos.height), 1u);
const DXGI_FORMAT backBufferFormat = (m_options & (c_FlipPresent | c_AllowTearing | c_EnableHDR)) ? NoSRGB(m_backBufferFormat) : m_backBufferFormat;
if (m_swapChain[index])
{
// If the swap chain already exists, resize it.
HRESULT hr = m_swapChain[index]->ResizeBuffers(
m_backBufferCount,
backBufferWidth,
backBufferHeight,
backBufferFormat,
(m_options & c_AllowTearing) ? DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING : 0u
);
if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET)
{
...
}
else
{
ThrowIfFailed(hr);
}
}
else
{
// Create a descriptor for the swap chain.
DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {};
swapChainDesc.Width = backBufferWidth;
swapChainDesc.Height = backBufferHeight;
swapChainDesc.Format = backBufferFormat;
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapChainDesc.BufferCount = m_backBufferCount;
swapChainDesc.SampleDesc.Count = 1;
swapChainDesc.SampleDesc.Quality = 0;
swapChainDesc.Scaling = DXGI_SCALING_STRETCH;
swapChainDesc.SwapEffect = (m_options & (c_FlipPresent | c_AllowTearing | c_EnableHDR)) ? DXGI_SWAP_EFFECT_FLIP_DISCARD : DXGI_SWAP_EFFECT_DISCARD;
swapChainDesc.AlphaMode = DXGI_ALPHA_MODE_IGNORE;
swapChainDesc.Flags = (m_options & c_AllowTearing) ? DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING : 0u;
DXGI_SWAP_CHAIN_FULLSCREEN_DESC fsSwapChainDesc = {};
fsSwapChainDesc.Windowed = TRUE;
// Create a SwapChain
ThrowIfFailed(m_dxgiFactory->CreateSwapChainForHwnd(
m_d3dDevice.Get(),
m_window[index],
&swapChainDesc,
&fsSwapChainDesc,
nullptr, m_swapChain[index].ReleaseAndGetAddressOf()
));
ThrowIfFailed(m_dxgiFactory->MakeWindowAssociation(m_window[index], DXGI_MWA_NO_ALT_ENTER));
}
// Create a render target view of the swap chain back buffer.
ThrowIfFailed(m_swapChain[index]->GetBuffer(0, IID_PPV_ARGS(m_renderTargetTexture[index].ReleaseAndGetAddressOf())));
CD3D11_RENDER_TARGET_VIEW_DESC renderTargetViewDesc(D3D11_RTV_DIMENSION_TEXTURE2D, m_backBufferFormat);
ThrowIfFailed(m_d3dDevice->CreateRenderTargetView(
m_renderTargetTexture[index].Get(),
&renderTargetViewDesc,
m_d3dRenderTargetView[index].ReleaseAndGetAddressOf()
));
if (m_depthBufferFormat != DXGI_FORMAT_UNKNOWN)
{
// Create a depth stencil view for use with 3D rendering if needed.
CD3D11_TEXTURE2D_DESC depthStencilDesc(
m_depthBufferFormat,
backBufferWidth,
backBufferHeight,
1,
1,
D3D11_BIND_DEPTH_STENCIL
);
ThrowIfFailed(m_d3dDevice->CreateTexture2D(
&depthStencilDesc,
nullptr,
m_depthStencilTexture[index].ReleaseAndGetAddressOf()
));
CD3D11_DEPTH_STENCIL_VIEW_DESC depthStencilViewDesc(D3D11_DSV_DIMENSION_TEXTURE2D);
ThrowIfFailed(m_d3dDevice->CreateDepthStencilView(
m_depthStencilTexture[index].Get(),
&depthStencilViewDesc,
m_d3dDepthStencilView[index].ReleaseAndGetAddressOf()
));
}
// Set the 3D rendering viewport
m_screenViewport[index] = CD3D11_VIEWPORT(
0.0f,
0.0f,
static_cast<float>(backBufferWidth),
static_cast<float>(backBufferHeight)
);
}
void DeviceResources::SetWindow(UINT index, HWND window, int width, int height) noexcept
{
m_window[index] = window;
int indent = 50 * (index + 1);
RECTxywh windowPos = { indent - getInvisableBorderWidth(), indent, width, height };
m_WindowStruct[index].setWindowedByWindowPos(windowPos, 0, true);
}
bool DeviceResources::WindowSizeChanged(UINT index, int width, int height)
{
RECTxywh newRc = { 0, 0, width, height };
RECTxywh oldRc = { 0, 0, m_WindowStruct[index].currentPos.width, m_WindowStruct[index].currentPos.height };
if (newRc == oldRc)
{
// i.e. size didnt actually change
return false;
}
m_WindowStruct[index].setWindowedByWindowPos(newRc, 0, false);
CreateWindowSizeDependentResources(index);
return true;
}
// Recreate all device resources
void DeviceResources::HandleDeviceLost(UINT index)
{
if (m_deviceNotify)
{
m_deviceNotify->OnDeviceLost();
}
m_d3dDepthStencilView[index].Reset();
m_d3dRenderTargetView[index].Reset();
m_renderTargetTexture[index].Reset();
m_depthStencilTexture[index].Reset();
m_swapChain[index].Reset();
m_d3dContext.Reset();
m_d3dDevice.Reset();
m_dxgiFactory.Reset();
CreateDeviceResources();
CreateWindowSizeDependentResources(index);
if (m_deviceNotify)
{
m_deviceNotify->OnDeviceRestored();
}
}
int DeviceResources::getNumberOfMonitors()
{
ComPtr<IDXGIAdapter1> adapter;
GetHardwareAdapter(adapter.GetAddressOf());
IDXGIOutput* output = NULL;
int count = 0;
for (int i = 0; DXGI_ERROR_NOT_FOUND != adapter->EnumOutputs(i, &output); ++i)
{
count++;
}
return count;
}
RECTxywh DeviceResources::getMonitorSize(int monitor)
{
RECT position = getMonitorPos(monitor);
RECTxywh size(0, 0, position.right - position.left, position.bottom - position.top);
return size;
}
// 1 based index into monitors
RECT DeviceResources::getMonitorPos(int monitor)
{
ComPtr<IDXGIAdapter1> adapter;
GetHardwareAdapter(adapter.GetAddressOf());
RECT pos = {};
IDXGIOutput* output = NULL;
int count = -1;
if ( DXGI_ERROR_NOT_FOUND != adapter->EnumOutputs(monitor, &output) )
{
DXGI_OUTPUT_DESC outputDesc;
HRESULT hr = output->GetDesc(&outputDesc);
pos = outputDesc.DesktopCoordinates;
}
return pos;
}
RECT DeviceResources::getWindowPos(int index)
{
RECT windowRect;
HWND window = m_window[index];
GetWindowRect(window, &windowRect);
return windowRect;
}
void DeviceResources::setWindowPosition(int index, RECTxywh pos)
{
HWND hWnd = m_window[index];
SetWindowPos(hWnd, HWND_TOP, pos.left, pos.top, pos.width, pos.height, SWP_FRAMECHANGED)
ShowWindow(hWnd, SW_SHOWNORMAL)
}
bool DeviceResources::isWindowMinimized(int index)
{
return IsIconic(m_window[index]);
}
// Present the contents of the swap chain to the screen.
void DeviceResources::Present(int index)
{
HRESULT hr = E_FAIL;
if (m_options & c_AllowTearing)
{
hr = m_swapChain[index]->Present(0, DXGI_PRESENT_ALLOW_TEARING);
Print(L"TRACE: Present Present %i \n", index);
}
else
{
hr = m_swapChain[index]->Present(1, 0);
}
m_d3dContext->DiscardView(m_d3dRenderTargetView[index].Get());
if (m_d3dDepthStencilView[index])
{
// Discard the contents of the depth stencil.
m_d3dContext->DiscardView(m_d3dDepthStencilView[index].Get());
}
if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET)
{
HandleDeviceLost(index);
}
else
{
ThrowIfFailed(hr);
if (!m_dxgiFactory->IsCurrent())
{
CreateFactory();
}
}
}
void DeviceResources::CreateFactory()
{
ThrowIfFailed(CreateDXGIFactory1(IID_PPV_ARGS(m_dxgiFactory.ReleaseAndGetAddressOf())));
}
void DeviceResources::GetHardwareAdapter(IDXGIAdapter1** ppAdapter)
{
...
}

Change the color of the title bar (caption) of a win32 application

I want to change the color of the title bar in my application as I have seen done in programs such as Skype Preview. I have found only one solution offered on the internet for this (WM_NCPAINT) which seems to require me to draw a completely custom title bar which is of course not ideal when all I want to do is change the background color. Is anyone aware of a better solution? Someone suggested hooking GetSysColor, but it is never called with an index of 2 (COLOR_ACTIVECAPTION) so the color is being retrieved from elsewhere.
Current title bar:
(source: pbrd.co)
End goal:
You can change window title bar color / behaviour with DWMAPI's DwmSetWindowAttribute function in Win32.
NOTE: Might require Windows SDK 10.0.22000.0 (aka first Windows 11 SDK) as DWMWA_USE_IMMERSIVE_DARK_MODE|DWMWA_BORDER_COLOR|DWMWA_CAPTION_COLOR were not documented in Windows SDK 10.0.19041.0 (latest Windows 10 SDK). People have got DWMWA_USE_IMMERSIVE_DARK_MODE working before the public documentation of the variable by simply using dwAttribute as 20 (or 19 if Windows was before Windows 10 20H1). Here is an example of Qt using it in their Windows platform integration by allowing application to use it by passing -platform windows:darkmode=1 flag when launching the application.
To enable immersive dark mode (available in Windows 10 / 11, but undocumented in Windows 10 SDK (can be used by setting value as dwAttribute as 20), value was 19 pre Windows 10 20H1 Update)
Immersive Dark Mode Enabled
Immersive Dark Mode Enabled Out of Focus
#include <dwmapi.h>
BOOL USE_DARK_MODE = true;
BOOL SET_IMMERSIVE_DARK_MODE_SUCCESS = SUCCEEDED(DwmSetWindowAttribute(
WINhWnd, DWMWINDOWATTRIBUTE::DWMWA_USE_IMMERSIVE_DARK_MODE,
&USE_DARK_MODE, sizeof(USE_DARK_MODE)));
To change border color (only in Windows 11 SDK)
Border Color set to 0x00FFFFFF
Border Color set to 0x00505050
#include <dwmapi.h>
COLORREF DARK_COLOR = 0x00505050;
BOOL SET_CAPTION_COLOR = SUCCEEDED(DwmSetWindowAttribute(
WINhWnd, DWMWINDOWATTRIBUTE::DWMWA_BORDER_COLOR,
&DARK_COLOR, sizeof(DARK_COLOR)));
To change caption color (only in Windows 11 SDK)
Caption Color set to 0x00FFFFFF
Caption Color set to 0x00505050
#include <dwmapi.h>
COLORREF DARK_COLOR = 0x00505050;
BOOL SET_CAPTION_COLOR = SUCCEEDED(DwmSetWindowAttribute(
WINhWnd, DWMWINDOWATTRIBUTE::DWMWA_CAPTION_COLOR,
&DARK_COLOR, sizeof(DARK_COLOR)));
The first thing I'm going to say is: You have been warned!
This is an awfully laborious task. It's a long way from easy and much time was spent reading the Wine sources (linux implementation of native win32 functionality)
Seeing this question brought back 'fond' (read: exasperating!) memories of my efforts to achieve the same result. The process is a somewhat convoluted one and foisters upon you a great many more responsibilities than simply painting the title-bar. (I've included about 500 lines of code)
Amongst other things, you need to handle window activation/inactivation, sizing, NC area buttons, application icon and title-text.
Using some (drawing) utility functions in other files I've not included, the following was achieved:
Both of which are modifications to this dialog:
With the assistance of these (color-keyed) images:
and some stretching/drawing (the image is divided into 9 pieces)
I note upon re-vising this code, that the borders are over-drawn by the client-area. I imagine, because I've not sized it correctly in response to the WM_NCCALCSIZE message. I also used another image which did indeed have borders of 8pixels wide, rather than the 14 that these two show. (You can see the commented-out code in response to the message I mentioned)
The idea is that first, we sub-class the standard dialog-box's WindowProc. In this subclassed handler, we tell the Desktop Window Manager to disable composition for our window, we setup a layered window (this is how the black one appears semi-transparent) and then finally, do the non-client drawing ourselves in response to a WM_NCPAINT message.
I'll also point out that for reasons that have long since escaped me, I wasn't especially satisfied with the functioning of the code.
With that said, here's some code to sink your teeth into:
#define _WIN32_WINNT 0x0501
#define UNICODE 1
#include <windows.h>
#include <commctrl.h>
#include <stdio.h>
#include "resource.h"
#include "../graphics/graphics.h"
#include <dwmapi.h>
using namespace Gdiplus;
HINSTANCE hInst;
LRESULT CALLBACK DlgSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData);
LRESULT onNcPaint(HWND hwnd, WPARAM wParam, LPARAM lParam);
HBITMAP frameImg, frameRedImg, frameOrigImg;
int frameIndex = 0;
//HRESULT DwmEnableComposition(UINT uCompositionAction);
typedef HRESULT (WINAPI *pFnDwmEnableComposition)(UINT uCompAction);
typedef HRESULT (WINAPI *pFnDwmSetWindowAttribute)(HWND hwnd, DWORD dwAttribute, LPCVOID pvAttribute, DWORD cbAttribute);
#define WM_DMWNCRENDERINGCHANGED 0x31F
// wParam = 1 (fRenderingEnabled = true)
// wParam = 0 (fRenderingEnabled = false)
HRESULT EnableNcDwm(HWND hwnd, bool enable)
{
HMODULE dwmMod = LoadLibrary(L"dwmapi.dll");
if (dwmMod)
{
pFnDwmSetWindowAttribute DwmSetWindowAttribute;
DwmSetWindowAttribute = (pFnDwmSetWindowAttribute)GetProcAddress(dwmMod, "DwmSetWindowAttribute");
HRESULT hr = S_OK;
DWMNCRENDERINGPOLICY ncrp;
if (enable)
ncrp = DWMNCRP_ENABLED;
else
ncrp = DWMNCRP_DISABLED;
// Disable non-client area rendering on the window.
hr = DwmSetWindowAttribute(hwnd, DWMWA_NCRENDERING_POLICY, &ncrp, sizeof(ncrp));
FreeLibrary(dwmMod);
if (SUCCEEDED(hr))
{
return hr;
}
}
return S_FALSE;
}
/*
#define DWM_EC_DISABLECOMPOSITION 0
#define DWM_EC_ENABLECOMPOSITION 1
HRESULT EnableDWM(HWND hwnd, bool enable)
{
HMODULE dwmMod = LoadLibrary(L"dwmapi.dll");
pFnDwmEnableComposition DwmEnableComposition;
DwmEnableComposition = (pFnDwmEnableComposition)GetProcAddress(dwmMod, "DwmEnableComposition");
HRESULT hr = S_OK;
// Disable DWM Composition
if (enable)
hr = DwmEnableComposition(DWM_EC_ENABLECOMPOSITION);
else
hr = DwmEnableComposition(DWM_EC_DISABLECOMPOSITION);
FreeLibrary(dwmMod);
return hr;
}
*/
BOOL CALLBACK DlgMain(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
static bool isSubclassed = false;
switch(uMsg)
{
case WM_DMWNCRENDERINGCHANGED:
{
long dwEx = GetWindowLong(hwndDlg, GWL_EXSTYLE);
dwEx &= ~(WS_EX_LAYERED);
SetWindowLong(hwndDlg, GWL_EXSTYLE, dwEx);
InvalidateRect(hwndDlg, NULL, true);
UpdateWindow(hwndDlg);
MoveAnchorsImmediatelly(hwndDlg);
}
return 0;
// case WM_ERASEBKGND:
// {
// RECT rc;
// GetClientRect(hwndDlg, &rc);
// FillRect((HDC)wParam, &rc, (HBRUSH) COLOR_BACKGROUND);
// return 1;
// }
case WM_INITDIALOG:
{
mSetAnchorMode(GetDlgItem(hwndDlg, IDC_BUTTON1), ANCHOR_CENTER);
}
return TRUE;
case WM_SIZE:
{
//MoveAnchorsImmediatelly(hwndDlg);
DeferAnchorsMove(hwndDlg);
}
return TRUE;
case WM_CLOSE:
{
EndDialog(hwndDlg, 0);
}
return TRUE;
case WM_COMMAND:
{
switch(LOWORD(wParam))
{
case IDC_BUTTON1:
if (isSubclassed == false)
{
SetWindowSubclass( hwndDlg, DlgSubclassProc, 1, NULL);
EnableNcDwm(hwndDlg, false);
frameIndex++;
frameIndex &= 1; // make sure it can only be in range [0..1]
}
else
{
RemoveWindowSubclass( hwndDlg, DlgSubclassProc, 1);
EnableNcDwm(hwndDlg, true);
}
isSubclassed = !isSubclassed;
// InvalidateRect(hwndDlg, NULL, true);
// UpdateWindow(hwndDlg);
// MoveAnchorsImmediatelly(hwndDlg);
break;
}
}
return TRUE;
}
return FALSE;
}
LRESULT CALLBACK DlgSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
{
static byte alpha = 255;
switch (uMsg)
{
case WM_ENTERSIZEMOVE:
printf("WM_ENTERSIZEMOVE\n");
return 0;
break;
case WM_EXITSIZEMOVE:
printf("WM_EXITSIZEMOVE\n");
return 0;
break;
case WM_MOUSEWHEEL:
if (((SHORT)(HIWORD(wParam))) > 0)
{
if (alpha > 30)
alpha -= 5;
}
else if (alpha < 255)
alpha += 5;
SetLayeredWindowAttributes(hwnd, RGB(255,0,255), alpha, LWA_COLORKEY|LWA_ALPHA);
UpdateWindow(hwnd);
return 0;
case WM_DMWNCRENDERINGCHANGED:
{
// printf("WM_DMWNCRENDERINGCHANGED\n");
long dwEx = GetWindowLong(hwnd, GWL_EXSTYLE);
dwEx |= WS_EX_LAYERED;
SetWindowLong(hwnd, GWL_EXSTYLE, dwEx);
SetLayeredWindowAttributes(hwnd, RGB(255,0,255), alpha, LWA_COLORKEY|LWA_ALPHA);
//MoveAnchorsImmediatelly(hwnd);
DeferAnchorsMove(hwnd);
InvalidateRect(hwnd, NULL, true);
UpdateWindow(hwnd);
// showWndRect(hwnd);
return 0;
}
break;
case WM_NCACTIVATE:
case WM_NCPAINT:
// printf("WM_NCPAINT -");
// printf("wParam: 0x%08d lParam 0x%08x\n", wParam, lParam);
onNcPaint(hwnd, wParam, lParam);
return 0;
case WM_NCCALCSIZE:
{
RECT *rc = (RECT*)lParam;
rc->left += 8; // frame image margin widths
rc->top += 30;
rc->right -= 8;
rc->bottom -= 8;
// rc->left += 14; // frame image margin widths
// rc->top += 39;
// rc->right -= 14;
// rc->bottom -= 14;
}
return (WVR_HREDRAW | WVR_VREDRAW);
case WM_NCHITTEST:
{
POINT mousePos, rawMousePos;
RECT clientRect, windowRect;
mousePos.x = LOWORD(lParam);
mousePos.y = HIWORD(lParam);
rawMousePos = mousePos;
GetClientRect(hwnd, &clientRect);
GetWindowRect(hwnd, &windowRect);
ScreenToClient(hwnd, &mousePos);
if ((mousePos.x < clientRect.left) && (rawMousePos.y < windowRect.top+8))
return HTTOPLEFT;
if ((mousePos.x > clientRect.right) && (rawMousePos.y < windowRect.top+8))
return HTTOPRIGHT;
if ( (mousePos.x < clientRect.left) && (mousePos.y > clientRect.bottom))
return HTBOTTOMLEFT;
if ( (mousePos.x > clientRect.right) && (mousePos.y > clientRect.bottom))
return HTBOTTOMRIGHT;
if (rawMousePos.x < windowRect.left+11)
return HTLEFT;
if (rawMousePos.x > windowRect.right-11)
return HTRIGHT;
if (mousePos.y > clientRect.bottom)
return HTBOTTOM;
RECT closeRect;
SetRect(&closeRect, windowRect.left + 15, windowRect.top+7, windowRect.left+15+16, windowRect.top+25);
if (PtInRect(&closeRect, rawMousePos))
{
// printf("over sys menu (appIcon) - %d,%d\n", mousePos.x, mousePos.y);
return HTSYSMENU;
}
if (rawMousePos.y < windowRect.top+8)
return HTTOP;
if (mousePos.y < 0)
return HTCAPTION;
else
return HTCLIENT;
}
}
return DefSubclassProc(hwnd, uMsg, wParam, lParam);
// return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
LRESULT onNcPaint(HWND hwnd, WPARAM wParam, LPARAM lParam)
{
// draw Frame
// HBRUSH mBrush = CreateSolidBrush( RGB(0,113,201) );
HDC hdc = GetWindowDC(hwnd);
// HDC hdc = GetDCEx(hwnd, (HRGN)wParam, DCX_WINDOW);//|DCX_INTERSECTRGN);
RECT mRect, wndRect;
GetWindowRect(hwnd, &mRect);
wndRect = mRect;
mRect.right -= mRect.left;
mRect.bottom -= mRect.top;
mRect.left = 0;
mRect.top = 0;
HDC memDC = CreateCompatibleDC(hdc);
HBITMAP old, memBmp;
old = (HBITMAP)GetCurrentObject(memDC, OBJ_BITMAP);
memBmp = CreateCompatibleBitmap(hdc, mRect.right, mRect.bottom);
//memBmp = zCreateDibSection(hdc, mRect.right, mRect.bottom, 24);
SelectObject(memDC, memBmp);
//StretchNineDraw(HDC destDC, RECT destRect, HBITMAP srcImage, RECT srcRect,
// int marginLeft, int marginTop, int marginRight, int marginBottom, int alpha);
if (frameIndex == 0)
// StretchNineDraw(memDC, mRect, frameImg, (RECT){0,0,33,58}, 16,41,16,16, 255);
StretchNineDrawNoAlpha(memDC, mRect, frameImg, (RECT){0,0,33,58}, 16,41,16,16);
else
StretchNineDraw(memDC, mRect, frameRedImg, (RECT){0,0,33,58}, 16,41,16,16, 255);
// StretchNineDrawNoAlpha(memDC, mRect, frameRedImg, (RECT){0,0,33,58}, 16,41,16,16);
// StretchNineDrawNoAlpha(memDC, mRect, frameOrigImg, (RECT){0,0,17,39}, 8,30,8,8);
//1111drawImgNineSquareStretching(memDC, mRect, frameImg, (RECT){0,0,33,58}, 16,41,16,16);
//void StretchNineDrawNoAlpha(HDC destDC, RECT destRect, HBITMAP srcImage, RECT srcRect,
// int marginLeft, int marginTop, int marginRight, int marginBottom)
// draw icon
HICON smallIcon = LoadIcon (NULL, IDI_APPLICATION);
DrawIconEx(memDC, 15, 9, smallIcon, 16, 16, 0,0, DI_NORMAL );
// draw window text
wchar_t wndText[100];
RECT textRect;
textRect.left = 9 + 16 + 9;
textRect.top = 0;
textRect.right = 1000;
textRect.bottom = 32;
GetWindowText(hwnd, wndText, 99);
//int oldMode = SetBkMode(hdc, TRANSPARENT);
//int oldMode = SetBkMode(memDC, TRANSPARENT);
SetBkMode(memDC, TRANSPARENT);
HFONT oldFont, hfont0 = CreateFont(-13, 0, 0, 0, 0, FALSE, FALSE, FALSE, 1, 0, 0, 0, 0, (L"Ms Shell Dlg"));
oldFont = (HFONT)SelectObject(memDC, hfont0);
DrawText(memDC, wndText, -1, &textRect, DT_VCENTER|DT_SINGLELINE|DT_LEFT);
SelectObject(memDC, oldFont);
DeleteObject(hfont0);
// top slice
BitBlt(hdc, 0,0, mRect.right,41, memDC, 0,0, SRCCOPY);
// left edge
BitBlt(hdc, 0, mRect.top + 41, 16, mRect.bottom - (41+16),
memDC, 0, mRect.top + 41, SRCCOPY);
// right edge
BitBlt(hdc, mRect.right-16, mRect.top + 41, 16, mRect.bottom - (41+16),
memDC, mRect.right-16, mRect.top + 41, SRCCOPY);
// bottom slice
BitBlt(hdc, 0,mRect.bottom-16, mRect.right,16, memDC, 0,mRect.bottom-16, SRCCOPY);
// BitBlt(hdc, 0,0, mRect.right,mRect.bottom, memDC, 0,0, SRCCOPY);
ReleaseDC(hwnd, hdc);
SelectObject(memDC, old);
DeleteDC(memDC);
DeleteObject(memBmp);
// ValidateRgn(hwnd, (HRGN)wParam);
return 0;
}
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
GdiplusStartupInput gdiplusStartupInput;
ULONG_PTR gdiplusToken;
GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
frameImg = mLoadImageFile(L"frame.png");
frameRedImg = mLoadImageFile(L"frameRed.png");
frameOrigImg = mLoadImageFile(L"frameOrig.png");
hInst=hInstance;
InitCommonControls();
int result = DialogBox(hInst, MAKEINTRESOURCE(DLG_MAIN), NULL, (DLGPROC)DlgMain);
GdiplusShutdown(gdiplusToken);
return result;
}
Find below the functions that:
- Load a png file (uses GDI+)
- stretch draw this image onto the borders
/* BMP, GIF, JPEG, PNG, TIFF, Exif, WMF, and EMF */
HBITMAP mLoadImageFile(wchar_t *filename)
{
HBITMAP result = NULL;
Bitmap bitmap(filename, false);
bitmap.GetHBITMAP(0, &result);
return result;
}
void GetRectSize(LPRECT tgt, int *width, int *height)
{
*width = (tgt->right - tgt->left) + 1;
*height = (tgt->bottom - tgt->top) + 1;
}
BOOL SetRectSizePos(LPRECT tgt, int xPos, int yPos, int width, int height)
{
return SetRect(tgt, xPos, yPos, xPos+(width-1), yPos+(height-1));
}
BOOL MoveRect(LPRECT tgt, int newX, int newY)
{
int width, height;
GetRectSize(tgt, &width, &height);
return SetRectSizePos(tgt, newX,newY, width,height);
}
// ****** marginLeft = 6
// ....|....|.... *
// ..tL.|.tM.|.tR.. *
// ---------------- * marginTop = 3
// ..mL.|.mM.|.mR..
// ---------------- * marginBottom = 3
// ..bL.|.bM.|.bR.. *
// ....|....|.... *
// ****** marginRight = 6
void CalcNineRects(LPRECT srcRect, RECT *dest, int marginLeft, int marginTop, int marginRight, int marginBottom)
{
int srcWidth, srcHeight;
int leftWidth, midWidth, rightWidth;
int topHeight, midHeight, botHeight;
int xOrig, yOrig;
GetRectSize(srcRect, &srcWidth, &srcHeight);
xOrig = srcRect->left;
yOrig = srcRect->top;
leftWidth = marginLeft;
midWidth = srcWidth - (marginLeft + marginRight) - 1;
rightWidth = marginRight;
topHeight = marginTop;
midHeight = srcHeight - (marginTop + marginBottom) - 1;
botHeight = marginBottom;
SetRectSizePos(&dest[0], xOrig, yOrig, leftWidth, topHeight);
SetRectSizePos(&dest[1], xOrig+(leftWidth), yOrig, midWidth, topHeight);
SetRectSizePos(&dest[2], xOrig+(leftWidth+midWidth), yOrig, rightWidth, topHeight);
SetRectSizePos(&dest[3], xOrig, yOrig+(topHeight), leftWidth, midHeight);
SetRectSizePos(&dest[4], xOrig+(leftWidth), yOrig+(topHeight), midWidth, midHeight);
SetRectSizePos(&dest[5], xOrig+(leftWidth+midWidth), yOrig+(topHeight), rightWidth, midHeight);
SetRectSizePos(&dest[6], xOrig,yOrig+(topHeight+midHeight), leftWidth, botHeight);
SetRectSizePos(&dest[7], xOrig+(leftWidth), yOrig+(topHeight+midHeight), midWidth, botHeight);
SetRectSizePos(&dest[8], xOrig+(leftWidth+midWidth), yOrig+(topHeight+midHeight), rightWidth, botHeight);
}
void StretchNineDraw(HDC destDC, RECT destRect, HBITMAP srcImage, RECT srcRect,
int marginLeft, int marginTop, int marginRight, int marginBottom,int alpha)
{
RECT destRectList[9], srcRectList[9];
int i;
int curSrcWidth, curSrcHeight, curDestWidth, curDestHeight;
HDC srcDC;
HBITMAP oldSrcBmp;
srcDC = CreateCompatibleDC(destDC);
// GetCurrentObject(srcDC, OBJ_BITMAP);
oldSrcBmp = (HBITMAP) SelectObject(srcDC, srcImage);
BLENDFUNCTION bf = {AC_SRC_OVER,0,alpha,AC_SRC_ALPHA};
int destHeight, destWidth;
GetRectSize(&destRect, &destWidth, &destHeight);
CalcNineRects(&srcRect, srcRectList, marginLeft, marginTop, marginRight, marginBottom);
CalcNineRects(&destRect, destRectList, marginLeft, marginTop, marginRight, marginBottom);
// printf("dst rect: %d,%d - %d,%d -- \n", destRect.left, destRect.top, destRect.right,destRect.bottom);
for (i=0; i<9; i++)
{
GetRectSize(&srcRectList[i], &curSrcWidth, &curSrcHeight);
GetRectSize(&destRectList[i], &curDestWidth, &curDestHeight);
AlphaBlend( destDC,
destRectList[i].left, destRectList[i].top,
curDestWidth, curDestHeight,
srcDC,
srcRectList[i].left, srcRectList[i].top,
curSrcWidth, curSrcHeight,
bf
);
}
SelectObject(srcDC, oldSrcBmp);
DeleteDC(srcDC);
}
Finally, the code for anchoring controls to the window (automatically recalculate their position when the window is re-sized)
typedef struct ANCHORPROPERTY
{
long anchorType;
RECT rc;
} *pANCHORPROPERTY;
#define ANCHOR_NONE 0
#define ANCHOR_WIDTH 1
#define ANCHOR_RIGHT 2
#define ANCHOR_CENTER_HORZ 3
#define ANCHOR_HEIGHT 4
#define ANCHOR_HEIGHT_WIDTH 5
#define ANCHOR_HEIGHT_RIGHT 6
#define ANCHOR_BOTTOM 7
#define ANCHOR_BOTTOM_WIDTH 8
#define ANCHOR_BOTTOM_RIGHT 9
#define ANCHOR_CENTER_HORZ_BOTTOM 10
#define ANCHOR_CENTER_VERT 11
#define ANCHOR_CENTER_VERT_RIGHT 12
#define ANCHOR_CENTER 13
pANCHORPROPERTY getWndAnchor(HWND hwnd);
bool removeAnchor(HWND hwnd);
bool mSetAnchorMode(HWND hwnd, long anchorMode);
BOOL CALLBACK AnchorEnum(HWND hwnd, LPARAM lParam);
void MoveAnchorsImmediatelly(HWND controlParent);
void DeferAnchorsMove(HWND controlParent);
long getChildCount(HWND controlParent);
pANCHORPROPERTY getWndAnchor(HWND hwnd)
{
return (pANCHORPROPERTY)GetProp(hwnd, L"anchor");
}
bool removeAnchor(HWND hwnd)
{
pANCHORPROPERTY pAnchor;
if (GetProp(hwnd, L"anchor") != NULL)
{
pAnchor = (pANCHORPROPERTY)RemoveProp(hwnd, L"anchor");
delete pAnchor;
}
return false;
}
bool mSetAnchorMode(HWND hwnd, long anchorMode)
{
bool result = false;
RECT rc, pr;
POINT p;
if (IsWindow(hwnd))
{
pANCHORPROPERTY pAnchor;
pAnchor = getWndAnchor(hwnd);
if (pAnchor == NULL)
{
pAnchor = new ANCHORPROPERTY;
SetProp(hwnd, L"anchor", pAnchor);
}
GetWindowRect(hwnd, &rc);
p.x = rc.left;
p.y = rc.top;
ScreenToClient( GetParent(hwnd), &p);
GetClientRect( GetParent(hwnd), &pr);
// printf("pos: %d,%d\n", p.x, p.y);
pAnchor->anchorType = mmin( mmax(anchorMode, ANCHOR_NONE), ANCHOR_CENTER);
pAnchor->rc.left = p.x;
pAnchor->rc.top = p.y;
pAnchor->rc.right = pr.right - (rc.right-rc.left + p.x);
pAnchor->rc.bottom = pr.bottom - (rc.bottom - rc.top + p.y);
result = true;
}
return result;
}
BOOL CALLBACK AnchorEnum(HWND hwnd, LPARAM lParam)
{
RECT pr, rc;
long x,y,xW,yH;
pANCHORPROPERTY pAnchor;
pAnchor = (pANCHORPROPERTY)GetProp(hwnd, L"anchor");
if (pAnchor != NULL)
{
if (pAnchor->anchorType != ANCHOR_NONE)
{
// printf("child enumerated - %d\n", pAnchor->anchorType);
RECT client, wnd;
GetClientRect(hwnd, &client);
GetWindowRect(hwnd, &wnd);
// printf("WndRect: %d x %d", (wnd.right-wnd.left) + 1, (wnd.bottom-wnd.top)+1);
// printf("client: %d x %d", client.right-client.left+1, client.bottom-client.top+1 );
int wW, wH, cW,cH;
wW = (wnd.right-wnd.left) + 1;
wH = (wnd.bottom-wnd.top) + 1;
cW = (client.right-client.left) + 1;
cH = (client.bottom-client.top) + 1;
GetClientRect(hwnd, &rc);
GetClientRect(GetParent(hwnd), &pr);
switch (pAnchor->anchorType)
{
case ANCHOR_WIDTH:
x = pAnchor->rc.left;
y = pAnchor->rc.top;
xW = mmax(pr.right - pAnchor->rc.left - pAnchor->rc.right, 0);
yH = rc.bottom;
break;
case ANCHOR_RIGHT: // = 2
x = (pr.right - rc.right - pAnchor->rc.right) - (wW-cW);
y = pAnchor->rc.top;
xW = rc.right + (wW-cW);
yH = rc.bottom + (wH-cH);
// printf("xPos, yPos: %d, %d - Size: %d x %d\n", x,y,xW,yH);
break;
case ANCHOR_CENTER_HORZ: // = 3
x = (pr.right - rc.right) / 2;
y = pAnchor->rc.top;
xW = rc.right;
yH = rc.bottom;
break;
case ANCHOR_HEIGHT: // = 4
x = pAnchor->rc.left;
y = pAnchor->rc.top;
xW = rc.right;
yH = mmax(pr.bottom - pAnchor->rc.top - pAnchor->rc.bottom, 0);
break;
case ANCHOR_HEIGHT_WIDTH: // = 5
x = pAnchor->rc.left;
y = pAnchor->rc.top;
xW = mmax(pr.right - pAnchor->rc.left - pAnchor->rc.right, 0);
yH = mmax(pr.bottom - pAnchor->rc.top - pAnchor->rc.bottom, 0);
break;
case ANCHOR_HEIGHT_RIGHT: // = 6
x = pr.right - rc.right - pAnchor->rc.right;
y = pAnchor->rc.top;
xW = rc.right;
yH = mmax(pr.bottom - pAnchor->rc.top - pAnchor->rc.bottom, 0);
break;
case ANCHOR_BOTTOM: // = 7
x = pAnchor->rc.left;
y = pr.bottom - pAnchor->rc.bottom - rc.bottom;
xW = rc.right;
yH = rc.bottom;
break;
case ANCHOR_BOTTOM_WIDTH: // = 8
x = pAnchor->rc.left;
y = pr.bottom - pAnchor->rc.bottom - rc.bottom;
xW = mmax(pr.right - pAnchor->rc.left - pAnchor->rc.right, 0);
yH = rc.bottom;
break;
case ANCHOR_BOTTOM_RIGHT: // = 9
x = pr.right - rc.right - pAnchor->rc.right;
y = pr.bottom - pAnchor->rc.bottom - rc.bottom;
xW = rc.right;
yH = rc.bottom;
break;
case ANCHOR_CENTER_HORZ_BOTTOM: // = 10
x = (pr.right - rc.right) / 2;
y = pr.bottom - pAnchor->rc.bottom - rc.bottom;
xW = rc.right;
yH = rc.bottom;
break;
case ANCHOR_CENTER_VERT: // = 11
x = pAnchor->rc.left;
y = (pr.bottom - rc.bottom) / 2;
xW = rc.right;
yH = rc.bottom;
break;
case ANCHOR_CENTER_VERT_RIGHT: // = 12
x = pr.right - rc.right - pAnchor->rc.right;
y = (pr.bottom - rc.bottom) / 2;
xW = rc.right;
yH = rc.bottom;
break;
case ANCHOR_CENTER: // = 13
x = (pr.right - rc.right) / 2;
y = (pr.bottom - rc.bottom) / 2;
xW = rc.right;
yH = rc.bottom;
break;
}
if (lParam == 0)
SetWindowPos(hwnd,0, x,y, xW,yH, SWP_NOZORDER|SWP_NOCOPYBITS);
else
DeferWindowPos((HDWP)lParam, hwnd, 0, x,y, xW,yH, SWP_NOZORDER|SWP_NOCOPYBITS);
}
}
return true;
}
void MoveAnchorsImmediatelly(HWND controlParent)
{
EnumChildWindows(controlParent, AnchorEnum, 0);
}
BOOL CALLBACK CountEnum(HWND hwnd, LPARAM lParam)
{
long *pCount = (long*)lParam;
++(*pCount);
return true;
}
long getChildCount(HWND controlParent)
{
long curCount = 0;
EnumChildWindows(controlParent, CountEnum, (LPARAM)&curCount);
// printf("Child count: %d\n", curCount);
return curCount;
}
void DeferAnchorsMove(HWND controlParent)
{
HDWP deferMoveHandle;
int childCount = getChildCount(controlParent);
deferMoveHandle = BeginDeferWindowPos(childCount);
EnumChildWindows(controlParent, AnchorEnum, (LPARAM)deferMoveHandle);
EndDeferWindowPos(deferMoveHandle);
}
You may try to create a window without a frame; i found reference here:
opening a window that has no title bar with win32
and then make your own title bar inside your application, in the color you like (located at the top of the window starting from the visible part).

How can I render the images on the monitor (or TV) connected to HDMI port of my computer

I am pretty new to DirectX 10 programming, and I have been trying to do the following with my limited skills..
I am trying to display an Image from one machine on to another output device(Another Monitor/TV) connected via HDMI. I researched on it and came to know that DXGI can be pretty useful for rendering purposes. Moreover while researching further I came across this link here. It does show how to display different images on multiple monitors connected to the main machine but it requires extended display for that.
My requirement is that when I run the code It should render the image on another output device without making it an extended display.
Approcah I am trying is that I am enumerating Video Adapters(which in my case is 1 ) and and then enumerating outputs available which should be two in numbers as I have an HDMI out connected to my PC. But if I do not set extended display it shows only one output available in my enumerated outputs array and if I extend the display it shows two of them.Once I am done with enumerating outputs I want to Render that image on desired output.
As far as i know every video adapter has a port for HDMI connected to it.
I wonder, if there is way I can access that port programatically and could render the image using that port??
Other than MSDN, documentation or explanation of those concepts are rather limited, so any help would be very welcome. Here is some code I have :
// include the basic windows header files and the Direct3D header files
#include <windows.h>
#include <windowsx.h>
#include <d3d11.h>
#include <d3dx11.h>
#include <d3dx10.h>
#include<vector>
#include<iostream>
#include <sstream>
#include<dxgi.h>
using namespace std;
// include the Direct3D Library file
#pragma comment (lib, "d3d11.lib")
#pragma comment (lib, "d3dx11.lib")
#pragma comment (lib, "d3dx10.lib")
#pragma comment(lib, "dxguid.lib")
#pragma comment(lib, "dxgi.lib")
std::vector<IDXGIAdapter*> EnumerateAdapters();
void PrintAdapterInfo(IDXGIAdapter* pAdapter);
std::vector<IDXGIOutput*> EnumerateOutputs(IDXGIAdapter* pAdapter);
void PrintOutputInfo(IDXGIOutput* output);
std::vector<DXGI_MODE_DESC*> GetDisplayModeList(IDXGIOutput* output);
void PrintDisplayModeInfo(DXGI_MODE_DESC* pModeDesc);
// global declarations
IDXGISwapChain *swapchain; // the pointer to the swap chain interface
ID3D11Device *dev; // the pointer to our Direct3D device interface
ID3D11DeviceContext *devcon; // the pointer to our Direct3D device context
ID3D11RenderTargetView *backbuffer; // the pointer to our back buffer
IDXGIAdapter *pAdapter;
IDXGIAdapter* adapter = NULL;
IDXGIFactory1* factory = NULL;
HINSTANCE hInstance;
HINSTANCE hPrevInstance;
LPSTR lpCmdLine;
HWND hWnd;
std::vector<IDXGIOutput*> outputArray;
int nCmdShow;
// function prototypes
void InitD3D(HWND hWnd); // sets up and initializes Direct3D
void RenderFrame(void); // renders a single frame
void CleanD3D(void); // closes Direct3D and releases memory
void CreateWindowsForOutputs();
void GetAdapter();
void MultiRender();
void CreateSwapChainsAndViews();
std::vector<IDXGIAdapter*> EnumerateAdapters();
// the WindowProc function prototype
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
struct WindowDataContainer
{
//Direct3D 10 stuff per window data
IDXGISwapChain* swapChain;
ID3D11RenderTargetView* renderTargetView;
ID3D11DepthStencilView* depthStencilView;
// window goodies
HWND hWnd;
int width;
int height;
};
std::vector<WindowDataContainer*> WindowsArray;
// the entry point for any Windows program
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
std::cout << "Hello \nworld!"; // Will show a popup
std::vector<IDXGIAdapter*> adapters = EnumerateAdapters();
for(std::vector<IDXGIAdapter*>::iterator itor = adapters.begin(); itor != adapters.end(); ++itor)
{
//PrintAdapterInfo(*itor);
// Get Output info
std::vector<IDXGIOutput*> outputArray = EnumerateOutputs(*itor);
for(std::vector<IDXGIOutput*>::iterator outputItor = outputArray.begin(); outputItor != outputArray.end(); ++outputItor)
{
// PrintOutputInfo(*outputItor);
// Get display mode list
std::vector<DXGI_MODE_DESC*> modeList = GetDisplayModeList(*outputItor);
for(std::vector<DXGI_MODE_DESC*>::iterator modeItor = modeList.begin(); modeItor != modeList.end(); ++modeItor)
{
// PrintDisplayModeInfo(*modeItor);
}
}
CreateWindowsForOutputs();
MSG msg;
while(TRUE)
{
if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
if(msg.message == WM_QUIT)
break;
}
MultiRender();
}
//std::getchar();
// return 0;
}
//std:getchar();
}
std::vector<IDXGIAdapter*> EnumerateAdapters()
{
// Create DXGI factory
IDXGIFactory1* pFactory = NULL;
HRESULT hr = CreateDXGIFactory1(__uuidof(IDXGIFactory1), (void**)(&pFactory));
if (FAILED(hr))
{
MessageBox(NULL, L"Create DXGI factory failed", L"Error", 0);
}
// Enumerate devices
IDXGIAdapter* pAdapter = NULL;
std::vector<IDXGIAdapter*> vAdapters;
for (UINT i = 0; pFactory->EnumAdapters(i, &pAdapter) != DXGI_ERROR_NOT_FOUND; ++i)
{
vAdapters.push_back(pAdapter);
}
if (pFactory)
{
pFactory->Release();
pFactory = NULL;
}
return vAdapters;
}
// this is the main message handler for the program
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch(message)
{
case WM_DESTROY:
{
PostQuitMessage(0);
return 0;
} break;
}
return DefWindowProc (hWnd, message, wParam, lParam);
}
// this function initializes and prepares Direct3D for use
void InitD3D(HWND hWnd)
{
// create a struct to hold information about the swap chain
DXGI_SWAP_CHAIN_DESC scd;
// clear out the struct for use
ZeroMemory(&scd, sizeof(DXGI_SWAP_CHAIN_DESC));
// fill the swap chain description struct
scd.BufferCount = 1; // one back buffer
scd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; // use 32-bit color
scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; // how swap chain is to be used
scd.OutputWindow = hWnd; // the window to be used
scd.SampleDesc.Count = 1; // how many multisamples
scd.SampleDesc.Quality = 0; // multisample quality level
scd.Windowed = TRUE; // windowed/full-screen mode
// create a device, device context and swap chain using the information in the scd struct
D3D11CreateDeviceAndSwapChain( NULL,
D3D_DRIVER_TYPE_HARDWARE,
NULL,
NULL,
NULL,
NULL,
D3D11_SDK_VERSION,
&scd,
&swapchain,
&dev,
NULL,
&devcon);
// get the address of the back buffer
ID3D11Texture2D *pBackBuffer;
swapchain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&pBackBuffer);
// use the back buffer address to create the render target
dev->CreateRenderTargetView(pBackBuffer, NULL, &backbuffer);
pBackBuffer->Release();
// set the render target as the back buffer
devcon->OMSetRenderTargets(1, &backbuffer, NULL);
// Set the viewport
D3D11_VIEWPORT viewport;
ZeroMemory(&viewport, sizeof(D3D11_VIEWPORT));
viewport.TopLeftX = 0;
viewport.TopLeftY = 0;
viewport.Width = 800;
viewport.Height = 600;
devcon->RSSetViewports(1, &viewport);
}
// this is the function used to render a single frame
void RenderFrame(void)
{
// clear the back buffer to a deep blue
devcon->ClearRenderTargetView(backbuffer, D3DXCOLOR(0.0f, 0.2f, 0.4f, 1.0f));
// do 3D rendering on the back buffer here
// switch the back buffer and the front buffer
swapchain->Present(0, 0);
}
// this is the function that cleans up Direct3D and COM
void CleanD3D(void)
{
// close and release all existing COM objects
swapchain->Release();
backbuffer->Release();
dev->Release();
devcon->Release();
}
//Acquiring the outputs on our adapter
std::vector<IDXGIOutput*> EnumerateOutputs(IDXGIAdapter* pAdapter)
{
//std::vector<IDXGIOutput*> outputs;
IDXGIOutput* pOutput = NULL;
for (UINT i = 0; pAdapter->EnumOutputs(i, &pOutput) != DXGI_ERROR_NOT_FOUND; ++i)
{
outputArray.push_back(pOutput);
}
return outputArray;
}
void CreateWindowsForOutputs()
{ // std::vector<IDXGIOutput*> outputArray;
for( int i = 0; i < outputArray.size(); ++i )
{
IDXGIOutput* output = outputArray.at(i);
DXGI_OUTPUT_DESC outputDesc;
output->GetDesc( &outputDesc );
int x = outputDesc.DesktopCoordinates.left;
int y = outputDesc.DesktopCoordinates.top;
int width = outputDesc.DesktopCoordinates.right - x;
int height = outputDesc.DesktopCoordinates.bottom - y;
WNDCLASSEX wc;
ZeroMemory(&wc, sizeof(WNDCLASSEX));
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WindowProc;
wc.hInstance = hInstance;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
wc.lpszClassName = L"WindowClass";
RegisterClassEx(&wc);
RECT wr = {0, 0, 800, 600};
AdjustWindowRect(&wr, WS_OVERLAPPEDWINDOW, FALSE);
// Don't forget to clean this up. And all D3D COM objects.
WindowDataContainer* window = new WindowDataContainer;
window->hWnd = CreateWindowEx(NULL,
L"WindowClass",
L"Our First Direct3D Program",
WS_OVERLAPPEDWINDOW,
300,
300,
wr.right - wr.left,
wr.bottom - wr.top,
NULL,
NULL,
hInstance,
NULL);
// show the window
ShowWindow( window->hWnd, SW_SHOWDEFAULT );
// InitD3D(hWnd);
CreateSwapChainsAndViews();
// set width and height
window->width = width;
window->height = height;
std::vector<WindowDataContainer*> windowsArray;
// shove it in the std::vector
windowsArray.push_back(window);
//if first window, associate it with DXGI so it can jump in
// when there is something of interest in the message queue
// think fullscreen mode switches etc. MSDN for more info.
// if(i == 0)
// factory->MakeWindowAssociation( window->hWnd, 0 );
}
}
std::vector<DXGI_MODE_DESC*> GetDisplayModeList(IDXGIOutput* output)
{
UINT num = 0;
DXGI_FORMAT format = DXGI_FORMAT_R32G32B32A32_TYPELESS;
UINT flags = DXGI_ENUM_MODES_INTERLACED | DXGI_ENUM_MODES_SCALING;
// Get number of display modes
output->GetDisplayModeList(format, flags, &num, 0);
// Get display mode list
DXGI_MODE_DESC * pDescs = new DXGI_MODE_DESC[num];
output->GetDisplayModeList(format, flags, &num, pDescs);
std::vector<DXGI_MODE_DESC*> displayList;
for(int i = 0; i < num; ++i)
{
displayList.push_back(&pDescs[i]);
}
return displayList;
}
void CreateSwapChainsAndViews()
{
std::vector<WindowDataContainer*> windowsArray;
for( int i = 0; i < windowsArray.size(); i++ )
{
WindowDataContainer* window = windowsArray.at(i);
// get the dxgi device
IDXGIDevice* DXGIDevice = NULL;
dev->QueryInterface( IID_IDXGIDevice, ( void** )&DXGIDevice ); // COM stuff, hopefully you are familiar
// create a swap chain
DXGI_SWAP_CHAIN_DESC swapChainDesc;
// fill it in
WindowDataContainer *p_Window = new WindowDataContainer;
HRESULT hr = factory->CreateSwapChain( DXGIDevice, &swapChainDesc, &p_Window->swapChain );
DXGIDevice->Release();
DXGIDevice = NULL;
// get the backbuffer
ID3D11Texture2D* backBuffer = NULL;
hr = window->swapChain->GetBuffer( 0, IID_ID3D11Texture2D, ( void** )&backBuffer );
// get the backbuffer desc
D3D11_TEXTURE2D_DESC backBufferDesc;
backBuffer->GetDesc( &backBufferDesc );
// create the render target view
D3D11_RENDER_TARGET_VIEW_DESC RTVDesc;
// fill it in
dev->CreateRenderTargetView( backBuffer, &RTVDesc, &window->renderTargetView );
backBuffer->Release();
backBuffer = NULL;
// Create depth stencil texture
ID3D11Texture2D* depthStencil = NULL;
D3D11_TEXTURE2D_DESC descDepth;
// fill it in
dev->CreateTexture2D( &descDepth, NULL, &depthStencil );
// Create the depth stencil view
D3D11_DEPTH_STENCIL_VIEW_DESC descDSV;
// fill it in
dev->CreateDepthStencilView( depthStencil, &descDSV, &window->depthStencilView );
}
}
void MultiRender( )
{
std::vector<WindowDataContainer*> windowsArray;
// Clear them all
for( int i = 0; i < windowsArray.size(); i++ )
{
WindowDataContainer* window = windowsArray.at(i);
// There is the answer to your second question:
devcon->OMSetRenderTargets( 1, &window->renderTargetView, NULL );
// Don't forget to adjust the viewport, in fullscreen it's not important...
D3D11_VIEWPORT Viewport;
Viewport.TopLeftX = 0;
Viewport.TopLeftY = 0;
Viewport.Width = window->width;
Viewport.Height = window->height;
Viewport.MinDepth = 0.0f;
Viewport.MaxDepth = 1.0f;
devcon->RSSetViewports( 1, &Viewport );
// TO DO: AMAZING STUFF PER WINDOW
}
}
//std::vector<IDXGIOutput*> outputArray; // contains outputs per adapter
void EnumOutputsOnAdapter()
{
IDXGIOutput* output = NULL;
for(int i = 0; DXGI_ERROR_NOT_FOUND != adapter->EnumOutputs(i, &output); ++i)
{
// get the description
DXGI_OUTPUT_DESC outputDesc;
HRESULT hr = output->GetDesc( &outputDesc );
outputArray.push_back( output );
}
}
// applicable for multiple ones with little effort
void GetAdapter()
{
// remember, we assume there's only one adapter (example purposes)
for( int i = 0; DXGI_ERROR_NOT_FOUND != factory->EnumAdapters( i, &adapter ); ++i );
{
// get the description of the adapter, assuming no failure
DXGI_ADAPTER_DESC adapterDesc;
HRESULT hr = adapter->GetDesc( &adapterDesc );
// Getting the outputs active on our adapter
EnumOutputsOnAdapter();
}
}

Ribbon button items with large images and checkboxes

I've got a menu attached to a split ribbon button like this (VS2008, Feature Pack):
std::auto_ptr<CMFCRibbonButton> apBtn3(new CMFCRibbonButton(ID_RIBBON_BTN_3, _T("Split Button"), 2, 2));
apBtn3->SetMenu(IDR_RIBBON_MENU_1, TRUE);
apBtn3->SetAlwaysLargeImage();
apBtn3->RemoveSubItem(0);
std::auto_ptr<CMFCRibbonButton> apSubButton(new CMFCRibbonButton(ID_RIBBON_MBTN_1, _T("Item 1"), 2, 2));
apSubButton->SetAlwaysLargeImage();
apBtn3->AddSubItem(apSubButton.release(), 0);
pPanel1->Add(apBtn3.release());
I want to put checkboxes in front of each menu item and have provided SetCheck() calls in the CN_UPDATE_COMMAND_UI handler but checkboxes will only show up, if I disable the large icons.
Is there any way to use checkboxes along with large icons in CMFCRibbonButton menus? If not, what would be the best possible workaround?
I found a usable workaround to check large icons by alpha-blending a green circle with a checkmark in it over the icon -- the same solution Windows uses to mark the default audio device or printer in the control panel:
This is my CMFCRibbonButtonEx class declaration:
class CMFCRibbonButtonEx : public CMFCRibbonButton
{
// Construction
public:
CMFCRibbonButtonEx();
CMFCRibbonButtonEx(UINT nID, LPCTSTR lpszText, int nSmallImageIndex = -1, int nLargeImageIndex = -1, BOOL bAlwaysShowDescription = FALSE);
CMFCRibbonButtonEx(UINT nID, LPCTSTR lpszText, HICON hIcon, BOOL bAlwaysShowDescription = FALSE, HICON hIconSmall = NULL, BOOL bAutoDestroyIcon = FALSE, BOOL bAlphaBlendIcon = FALSE);
// Overridden
void SetCheck(BOOL bCheck = TRUE);
void DrawImage(CDC* pDC, RibbonImageType type, CRect rectImage);
// Attributes
private:
BOOL m_bChecked;
// Helper
private:
void DrawCheckmark(CDC* pDC, int CheckmarkResourceBitmapID, RECT *r);
void PremultiplyBitmapAlpha(HDC hDC, HBITMAP hBmp);
};
Here are the class function definitions:
CMFCRibbonButtonEx::CMFCRibbonButtonEx() : CMFCRibbonButton() { }
CMFCRibbonButtonEx::CMFCRibbonButtonEx(UINT nID, LPCTSTR lpszText, int nSmallImageIndex, int nLargeImageIndex, BOOL bAlwaysShowDescription)
: CMFCRibbonButton(nID, lpszText, nSmallImageIndex, nLargeImageIndex, bAlwaysShowDescription) { }
CMFCRibbonButtonEx::CMFCRibbonButtonEx(UINT nID, LPCTSTR lpszText, HICON hIcon, BOOL bAlwaysShowDescription, HICON hIconSmall, BOOL bAutoDestroyIcon, BOOL bAlphaBlendIcon)
: CMFCRibbonButton(nID, lpszText, hIcon, bAlwaysShowDescription , hIconSmall, bAutoDestroyIcon, bAlphaBlendIcon) { }
void CMFCRibbonButtonEx::SetCheck(BOOL bCheck)
{
m_bChecked = bCheck;
}
void CMFCRibbonButtonEx::DrawImage(CDC* pDC, RibbonImageType type, CRect rectImage)
{
CMFCRibbonButton::DrawImage(pDC, type, rectImage);
if (type == RibbonImageLarge && m_bChecked)
DrawCheckmark(pDC, IDB_BIG_ICON_CHECKMARK, &rectImage);
}
void CMFCRibbonButtonEx::DrawCheckmark(CDC* pDC, int CheckmarkResourceBitmapID, RECT *r)
{
HDC hdc;
CDC *dc;
CDC dcMem;
CBitmap cbm;
VERIFY(hdc = pDC->m_hDC);
VERIFY(dc = pDC);
dcMem.CreateCompatibleDC(dc);
cbm.LoadBitmap(CheckmarkResourceBitmapID);
PremultiplyBitmapAlpha(dcMem.m_hDC, cbm);
SelectObject(dcMem.m_hDC, cbm.m_hObject);
BLENDFUNCTION bf;
bf.BlendOp = AC_SRC_OVER;
bf.BlendFlags = 0;
bf.SourceConstantAlpha = 255;
bf.AlphaFormat = AC_SRC_ALPHA;
::AlphaBlend(hdc, r->left, r->top, r->right-r->left, r->bottom-r->top, dcMem, 0, 0, 32, 32, bf);
VERIFY(dcMem.DeleteDC());
}
void CMFCRibbonButtonEx::PremultiplyBitmapAlpha(HDC hDC, HBITMAP hBmp)
{
BITMAP bm = { 0 };
GetObject(hBmp, sizeof(bm), &bm);
BITMAPINFO* bmi = (BITMAPINFO*) _alloca(sizeof(BITMAPINFOHEADER) + (256 * sizeof(RGBQUAD)));
::ZeroMemory(bmi, sizeof(BITMAPINFOHEADER) + (256 * sizeof(RGBQUAD)));
bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
BOOL bRes = ::GetDIBits(hDC, hBmp, 0, bm.bmHeight, NULL, bmi, DIB_RGB_COLORS);
if( !bRes || bmi->bmiHeader.biBitCount != 32 ) return;
LPBYTE pBitData = (LPBYTE) ::LocalAlloc(LPTR, bm.bmWidth * bm.bmHeight * sizeof(DWORD));
if( pBitData == NULL ) return;
LPBYTE pData = pBitData;
::GetDIBits(hDC, hBmp, 0, bm.bmHeight, pData, bmi, DIB_RGB_COLORS);
for( int y = 0; y < bm.bmHeight; y++ ) {
for( int x = 0; x < bm.bmWidth; x++ ) {
pData[0] = (BYTE)((DWORD)pData[0] * pData[3] / 255);
pData[1] = (BYTE)((DWORD)pData[1] * pData[3] / 255);
pData[2] = (BYTE)((DWORD)pData[2] * pData[3] / 255);
pData += 4;
}
}
::SetDIBits(hDC, hBmp, 0, bm.bmHeight, pBitData, bmi, DIB_RGB_COLORS);
::LocalFree(pBitData);
}
IDB_BIG_ICON_CHECKMARK is a 32bit bmp with alpha channel: Download here
Sadly, in OnCmdMsg only a fake CMFCRibbonButton created by the ribbon framework is being maintained, so SetCheck() doesn't have any effect on an IsChecked() call in DrawImage(). You just have to find the real CMFCRibbonButtonEx in the subitems of the menu like this:
BOOL CEasyCashView::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo)
{
...
else if (nID >= ID_MY_ITEMS_BASE && nID < ID_ITEMS_BASE+MAX_MY_ITEMS)
{
if (nCode == CN_COMMAND)
{
OnMyItemsCommand(nID);
}
else if (nCode == CN_UPDATE_COMMAND_UI)
{
((CCmdUI*)pExtra)->SetCheck(myItemsCheckedArray[nID-ID_MY_ITEMS_BASE] == TRUE);
// this won't have any effect, use code below
CMFCRibbonButton* pMyMainMenuButton;
if (pMyMainMenuButton = ((CMainFrame*)AfxGetMainWnd())->m_pMyMainMenuButton)
{
int i;
for (i = 0; i < pMyMainMenuButton->GetSubItems().GetCount(); i++)
if (pMyMainMenuButton->GetSubItems()[i]->GetID() == nID)
{
((CMFCRibbonButtonEx*)pMyMainMenuButton->GetSubItems()[i])->SetCheck(myItemsCheckedArray[nID-ID_MY_ITEMS_BASE] == TRUE);
break;
}
}
return TRUE;
}
}
Should anyone know how to connect the fake CMFCRibbonButton (or CMFCRibbonBaseElement) maintained by CCmdUI to the originally created CMFCRibbonButtonEx, please leave me a comment.
"checkboxes in front of each menu item"
Is the below picture what you're looking for? If yes, this can be achieved by editing the ribbon xml file.

Getting an stack overflow error if creating a terrain larger that 128*128 in size from file

when i try to load a heighmap.raw larger in size that 128*128 i get at stack overflow error
can anyone help me out?
#include<Windows.h>
#include<WindowsX.h>
#include<d3d9.h>
#include<d3dx9.h>
#define CUSTOMFVF (D3DFVF_XYZ|D3DFVF_DIFFUSE)
#define CENTERX 400
#define CENTERY 300
#define RADIUS 100
#include<fstream>
#define WIDTH 64
#define HEIGHT 64
float eyeX;
float eyeY;
float eyeZ;
#pragma comment(lib,"d3d9.lib")
#pragma comment(lib,"d3dx9.lib")
IDirect3D9 *pDirect3D = NULL;
IDirect3DDevice9 *pDevice = NULL;
IDirect3DVertexBuffer9 *pV_Buffer = NULL;
IDirect3DIndexBuffer9 *pV_Index = NULL;
D3DPRESENT_PARAMETERS pp = {0};
D3DVIEWPORT9 vp={0};
void InitDirectx(HWND hWnd);
bool render();
void Init_graphics(void);
void cleanD3D(void);
struct OURCUSTOMVERTEX
{
float x,y,z;
DWORD color;
};
D3DXMATRIX matView;
D3DXMATRIX matProjection;
D3DXMATRIX matWorld;
LRESULT CALLBACK WindowProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam);
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR cmdline,int nCmdShow)
{
WNDCLASSEX wcex = {0};
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.hInstance = hInstance;
wcex.lpszClassName = TEXT("DirectX Window");
wcex.lpfnWndProc = WindowProc;
ATOM result = RegisterClassEx (&wcex);
if(result == 0)
{
MessageBox(NULL, TEXT("Register class failed"), TEXT("Error"), MB_OK);
}
HWND hWnd = NULL;
hWnd = CreateWindowEx(0,wcex.lpszClassName,TEXT("DirectX Window"),WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,CW_USEDEFAULT,800, 600,NULL,NULL,hInstance,NULL);
if(hWnd == NULL)
{
MessageBox(NULL,TEXT("Window Creation Failed"),TEXT("ERROR"),MB_OK);
}
ShowWindow(hWnd,nCmdShow);
InitDirectx(hWnd);
MSG msg = {0};
while(true)
{
PeekMessage(&msg,NULL,0,0,PM_REMOVE);
if(msg.message == WM_QUIT)
break;
DispatchMessage(&msg);
render();
}
}
LRESULT CALLBACK WindowProc(HWND hwnd,UINT message,WPARAM wparam,LPARAM lparam)
{
switch(message)
{
case WM_KEYDOWN:
switch(wparam)
{
case VK_UP:
eyeZ = eyeZ - .05;
break;
case VK_DOWN:
eyeZ = eyeZ + .05;
break;
case VK_LEFT:
eyeX = eyeX - .05;
break;
case VK_RIGHT:
eyeX = eyeX + .05;
break;
}
break;
case WM_DESTROY:
{
PostQuitMessage(0);
break;
}
default :
return DefWindowProc(hwnd,message,wparam,lparam);
}
return 0;
}
void InitDirectx(HWND hWnd)
{
pDirect3D = Direct3DCreate9(D3D_SDK_VERSION);
pp.BackBufferFormat=D3DFMT_A8R8G8B8;
pp.BackBufferWidth = 800;
pp.BackBufferHeight = 600;
pp.hDeviceWindow=hWnd;
pp.SwapEffect=D3DSWAPEFFECT_DISCARD;
pp.Windowed =true;
pDirect3D->CreateDevice(D3DADAPTER_DEFAULT,D3DDEVTYPE_HAL,hWnd,D3DCREATE_SOFTWARE_VERTEXPROCESSING,&pp,&pDevice);
pDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
Init_graphics();
}
bool render()
{
pDevice->Clear(0,NULL,D3DCLEAR_TARGET,D3DCOLOR_XRGB(0,0,0),0.0,NULL);
pDevice->BeginScene();
{
/** create the view matrix **/
D3DXMatrixLookAtLH(&matView, &D3DXVECTOR3(eyeX, eyeY, eyeZ), &D3DXVECTOR3(0, 0, 1), &D3DXVECTOR3(0, 1, 0));
pDevice->SetFVF(CUSTOMFVF);
pDevice->SetTransform(D3DTS_WORLD, &matWorld);
pDevice->SetTransform(D3DTS_VIEW, &matView);
pDevice->SetTransform(D3DTS_PROJECTION, &matProjection);
pDevice->SetRenderState(D3DRS_LIGHTING, FALSE);
pDevice->SetStreamSource(0,pV_Buffer,0,sizeof(OURCUSTOMVERTEX));
// pDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 2);
pDevice->SetIndices(pV_Index);
pDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST,0, 0, WIDTH*HEIGHT, 0, (WIDTH-1)*(HEIGHT-1)*2);
}
pDevice->EndScene();
pDevice->Present(NULL,NULL,0,NULL);
return true;
}
void CleanD3D(void)
{
pV_Buffer->Release();
pDevice->Release();
pDirect3D->Release();
}
void Init_graphics(void)
{
OURCUSTOMVERTEX Vertices[WIDTH*HEIGHT];
float flt_HeightData[WIDTH][HEIGHT];
flt_HeightData[0][0]=0;
flt_HeightData[1][0]=0;
flt_HeightData[2][0]=0;
flt_HeightData[3][0]=0;
flt_HeightData[0][1]=1;
flt_HeightData[1][1]=0;
flt_HeightData[2][1]=2;
flt_HeightData[3][1]=2;
flt_HeightData[0][2]=2;
flt_HeightData[1][2]=2;
flt_HeightData[2][2]=4;
flt_HeightData[3][2]=2;
std::ifstream f_DataFile;
f_DataFile.open("heightdata.raw", std::ios::binary);
if (f_DataFile.is_open())
{
for (int x=0;x< WIDTH;x++) {
for (int y=0; y< HEIGHT;y++) {
Vertices[y*WIDTH + x].x = -x;
Vertices[y*WIDTH + x].y = y;
Vertices[y*WIDTH + x].z = f_DataFile.get()/50;
Vertices[y*WIDTH + x].color = 0xffffffff;
}
}
}
f_DataFile.close();
pDevice->CreateVertexBuffer(WIDTH*HEIGHT*sizeof(OURCUSTOMVERTEX),
0,
CUSTOMFVF,
D3DPOOL_DEFAULT,
&pV_Buffer,
NULL);
VOID *pVoid = NULL;
pV_Buffer->Lock(0, (WIDTH-1)*(HEIGHT-1)*6*sizeof(OURCUSTOMVERTEX),(void**)&pVoid,0);
memcpy(pVoid,Vertices,WIDTH*HEIGHT*sizeof(OURCUSTOMVERTEX));
pV_Buffer->Unlock();
short s_Indices[(WIDTH-1)*(HEIGHT-1)*6];
for (int x=0;x< WIDTH-1;x++) {
for (int y=0; y< HEIGHT-1;y++) {
s_Indices[(x+y*(WIDTH-1))*6+2] = x+y*WIDTH;
s_Indices[(x+y*(WIDTH-1))*6+1] = (x+1)+y*WIDTH;
s_Indices[(x+y*(WIDTH-1))*6] = (x+1)+(y+1)*WIDTH;
s_Indices[(x+y*(WIDTH-1))*6+3] = (x+1)+(y+1)*WIDTH;
s_Indices[(x+y*(WIDTH-1))*6+4] = x+y*WIDTH;
s_Indices[(x+y*(WIDTH-1))*6+5] = x+(y+1)*WIDTH;
}
}
pDevice->CreateIndexBuffer((WIDTH-1)*(HEIGHT-1)*6*sizeof(short),
0,
D3DFMT_INDEX16,
D3DPOOL_MANAGED,
&pV_Index,
NULL);
VOID *pVoid2= NULL;
pV_Index->Lock(0, (WIDTH-1)*(HEIGHT-1)*6*sizeof(short),(void**)&pVoid2,0);
memcpy(pVoid2, s_Indices,(WIDTH-1)*(HEIGHT-1)*6*sizeof(short));
pV_Index->Unlock();
pDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
pDevice->SetRenderState(D3DRS_LIGHTING,false);
pDevice->SetRenderState(D3DRS_FILLMODE,D3DFILL_WIREFRAME);
/** Reset the world matrix to identity **/
D3DXMatrixIdentity(&matWorld);
/** create the projection matrix **/
D3DXMatrixPerspectiveFovLH(&matProjection, 60, 1.6666F, 1, 1000);
vp.X= 0;
vp.Y = 0;
vp.Width = WIDTH;
vp.Height = HEIGHT;
//pDevice->SetViewport(&vp);
eyeX = 0;
eyeY = 0;
eyeZ = +5;
}
Increase the size of the stack or, preferably, allocate the arrays on the heap. The easiest way to do this in C++ is by using std::vector.
These
OURCUSTOMVERTEX Vertices[WIDTH*HEIGHT];
float flt_HeightData[WIDTH][HEIGHT];
are too big to go on the stack. You could use new to allocate them dynamically.
OURCUSTOMVERTEX* Vertices = new OURCUSTOMVERTEX[WIDTH*HEIGHT];
float* flt_HeightData = new float[WIDTH*HEIGHT];
This will mean you need to learn about dynamic heap allocation. In particular you are going to have problems with the 2d flt_HeightData array.
A better, simpler way is to use std::vector
std::vector<OURCUSTOMVERTEX> Vertices(WIDTH*HEIGHT);
std::vector<float> flt_HeightData(WIDTH*HEIGHT);
but again flt_HeightData is going to cause problems.
You have some reading to do I think, there's a lot of things to learn.
I suppose this is a culprit:
OURCUSTOMVERTEX Vertices[WIDTH*HEIGHT];
Allocate it on the heap, like:
OURCUSTOMVERTEX* Vertices = new OURCUSTOMVERTEX[WIDTH*HEIGHT];