OpenGL on a custom made win32 window, using cygwin compiler, doesn't work - c++

I wrote a bit of code, based on NeHe's first tutorial, which creates a window and initializes gl context. this worked exactly as it should in vc++. Then I've tried to replicate the same code in eclipse c++ environment using cygwin compiler and the problems began.
The window compiles without any errors (A number of warnings but no errors), the exe opens a win32 window as it should, all of the functionality that I've coded into the window works too (e.g. full screen mode, change resolution) the only problem is that instead of refreshing the background of the window with red colour as it should I'm getting a black square and that's it.
To me this looks like an opengl initialization problem. Been trying to solve this problem for two days but I can't find any solution I hope somebody can see what I'm doing wrong.
Below are the code extracts.
Initial method
#include <iostream>
#include <windows.h>
#include <gl/glew.h>
#include <string>
#define GLEW_STATIC
using namespace std;
#include <glWindow.h>
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
MSG msg;
GLboolean Exit = FALSE;
glWindow screen("Dark Light", 640, 480, 16);
while(!Exit){
if (screen.LastError() == errNone && screen.WndState() != glExit){
// Is There A Message Waiting?
if (PeekMessage(&msg, screen.Handles().Window(), 0, 0, PM_REMOVE)){
// Have We Received A Quit Message?
if (msg.message == WM_QUIT){
screen.WndState() = glExit;
}
// If Not, Deal With Window Messages
else{
TranslateMessage(&msg); // Translate The Message
DispatchMessage(&msg); // Dispatch The Message
}
}
// If There Are No Messages
else{
if (screen.WndState() == glActive){
if (screen.KeysState(VK_ESCAPE)){
screen.WndState() = glExit;
}
else{
// Draw The Scene
screen.Draw();
}
}
if (screen.KeysState(VK_F1)){
screen.KeysState(VK_F1) = FALSE;
screen.ToggleFullscreen();
}
if (screen.KeysState(VK_SPACE)){
screen.KeysState(VK_SPACE) = FALSE;
screen.SetResolution(800, 600);
}
}
}
else{
Exit = true;
}
}
// Shutdown
return 0;
}
glWindow.h
#ifndef GLWINDOW_H
#define GLWINDOW_H
#include <string>
using namespace std;
enum glWndState
{
glActive = 0, glPaused = 1, glExit = 2
};
enum glWndErrors
{
errNone = 0, errCreateWC = 1, errCreateWnd = 2, errCreateDC = 3, errMatchPixelFormat = 4,
errSetPixelFormat = 5, errCreateRC = 6, errActivateRC = 7, errInitGL = 8, errChangeRC = 9,
errReleaseRC = 10, errReleaseDC = 11, errDestroyWnd = 12, errDestroyWC = 13, errGoToFullscreen = 14,
errGoToWindowed = 15, errGetInstance = 16
};
class glWndSettings
{
private:
GLsizei _width;
GLsizei _height;
GLboolean _fullscreen;
GLint _bits;
PIXELFORMATDESCRIPTOR _pfd;
DEVMODE _screenSettings;
public:
glWndSettings(GLsizei width, GLsizei height, GLint bits);
glWndErrors glSetStyle(HWND hWnd);
glWndErrors glSetStyle(HWND hWnd, GLboolean fullscreen, GLboolean save = TRUE);
glWndErrors glSetResolution(HWND hWnd, GLsizei width, GLsizei height);
GLsizei& Width();
GLsizei& Height();
GLboolean& Fullscreen();
GLint& Bits();
PIXELFORMATDESCRIPTOR& PixelFormatDescription();
};
class glWndHandles
{
private:
string _className;
HINSTANCE _hInstance;
WNDCLASS _wc;
HWND _hWnd;
HDC _hDC;
HGLRC _hRC;
GLuint _pixelFormat;
public:
glWndHandles(HICON icon, string title, WNDPROC wndProc);
~glWndHandles();
glWndErrors glDefWindow(PIXELFORMATDESCRIPTOR pfd);
HINSTANCE& Instance();
WNDCLASS& WinClass();
HWND& Window();
HDC& DeviceContext();
HGLRC& RenderContext();
};
class glWndFPS
{
GLint _framesCounter;
GLint _fps;
public:
glWndFPS();
GLvoid NewFrame();
GLvoid ResetFrames();
GLint FPS();
};
class glWindow
{
glWndHandles _handles;
glWndSettings _settings;
glWndFPS _fps;
glWndErrors _error;
glWndState _state;
bool _keys[256];
string _title;
static LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
public:
glWindow(string title, int width, int height, int bits);
~glWindow();
int InitGL();
GLvoid Draw();
GLvoid DisplayFPS();
GLvoid SetTitle(string title);
GLvoid SetResolution(GLsizei width, GLsizei height);
GLvoid SetFullscreen(GLboolean fullscreen);
GLvoid ToggleFullscreen();
glWndHandles& Handles();
glWndSettings& Settings();
glWndFPS& fpsInfo();
glWndErrors& LastError();
glWndState& WndState();
bool& KeysState(int key);
GLvoid ReSizeGLScene(GLsizei width, GLsizei height);
};
#endif /* GLWINDOW_H_ */
glWindow.cpp
#include <stdio.h>
#include <windows.h>
#include <GL/glew.h>
#include <glm/gtc/matrix_transform.hpp>
using namespace std;
#include "glWindow.h"
glWndSettings::glWndSettings(GLsizei width, GLsizei height, GLint bits){
_fullscreen = FALSE;
_width = width;
_height = height;
_bits = bits;
_pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR); // Size Of This Pixel Format Descriptor
_pfd.nVersion = 1; // Version Number
_pfd.dwFlags = PFD_DRAW_TO_WINDOW | // Format Must Support Window
PFD_SUPPORT_OPENGL | // Format Must Support OpenGL
PFD_DOUBLEBUFFER; // Must Support Double Buffering
_pfd.iPixelType = PFD_TYPE_RGBA; // Request An RGBA Format
_pfd.cColorBits = bits; // Select Our Color Depth
_pfd.cRedBits = 0; _pfd.cRedShift = 0;
_pfd.cGreenBits = 0; _pfd.cGreenShift = 0;
_pfd.cBlueBits = 0; _pfd.cBlueShift = 0; // Color Bits Ignored
_pfd.cAlphaBits = 0; _pfd.cAlphaShift = 0; // No Alpha Buffer
_pfd.cAccumBits = 0;
_pfd.cAccumRedBits = 0;
_pfd.cAccumGreenBits = 0;
_pfd.cAccumBlueBits = 0;
_pfd.cAccumAlphaBits = 0;
_pfd.cDepthBits = 16; // 16Bit Z-Buffer (Depth Buffer)
_pfd.cStencilBits = 0; // No Stencil Buffer
_pfd.cAuxBuffers = 0; // No Auxiliary Buffer
_pfd.iLayerType = PFD_MAIN_PLANE; // Main Drawing Layer
_pfd.bReserved = 0; // Reserved
_pfd.dwLayerMask = 0;
_pfd.dwVisibleMask = 0;
_pfd.dwDamageMask = 0; // Layer Masks Ignored
}
glWndErrors glWndSettings::glSetStyle(HWND hWnd){
GLboolean fullscreen = !_fullscreen;
return glSetStyle(hWnd, fullscreen);
}
glWndErrors glWndSettings::glSetStyle(HWND hWnd, GLboolean fullscreen, GLboolean save){
DWORD dwExStyle = 0;
DWORD dwStyle = 0;
if (save)
_fullscreen = fullscreen;
if (fullscreen){
dwExStyle = WS_EX_APPWINDOW;
dwStyle = WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
memset(&_screenSettings, 0, sizeof(_screenSettings)); // Makes Sure Memory's Cleared
_screenSettings.dmSize = sizeof(_screenSettings); // Size Of The Devmode Structure
_screenSettings.dmPelsWidth = _width; // Selected Screen Width
_screenSettings.dmPelsHeight = _height; // Selected Screen Height
_screenSettings.dmBitsPerPel = _bits; // Selected Bits Per Pixel
_screenSettings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
// Try To Set Selected Mode And Get Results. NOTE: CDS_FULLSCREEN Gets Rid Of Start Bar.
if (ChangeDisplaySettings(&_screenSettings, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL){
return errGoToFullscreen;
}
while(ShowCursor(FALSE) >= 0);
}
else{
dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
dwStyle = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX;
if (ChangeDisplaySettings(NULL, 0) != DISP_CHANGE_SUCCESSFUL){
return errGoToWindowed;
}
while(ShowCursor(TRUE) < 0);
}
RECT windowRect;
windowRect.left=(long)0; // Set Left Value To 0
windowRect.right=(long)_width; // Set Right Value To Requested Width
windowRect.top=(long)0; // Set Top Value To 0
windowRect.bottom=(long)_height; // Set Bottom Value To Requested Height
AdjustWindowRectEx(&windowRect, dwStyle, FALSE, dwExStyle); // Adjust Window To True Requested Size
ShowWindow(hWnd, SW_HIDE);
DWORD oldExStyle = SetWindowLongPtr(hWnd, GWL_EXSTYLE, dwExStyle);
DWORD oldStyle = SetWindowLongPtr(hWnd, GWL_STYLE, dwStyle);
SetWindowPos(hWnd, HWND_TOP, 0, 0, windowRect.right, windowRect.bottom, SWP_NOZORDER);
ShowWindow(hWnd, SW_SHOW);
return errNone;
}
glWndErrors glWndSettings::glSetResolution(HWND hWnd, GLsizei width, GLsizei height){
_width = width; _height = height;
glSetStyle(hWnd, _fullscreen);
return errNone;
}
GLsizei& glWndSettings::Width(){
return _width;
}
GLsizei& glWndSettings::Height(){
return _height;
}
GLboolean& glWndSettings::Fullscreen(){
return _fullscreen;
}
GLint& glWndSettings::Bits(){
return _bits;
}
PIXELFORMATDESCRIPTOR& glWndSettings::PixelFormatDescription(){
return _pfd;
}
glWndHandles::glWndHandles(HICON icon, string title, WNDPROC wndProc){
_hInstance = NULL;
_hWnd = NULL;
_hDC = NULL;
_hRC = NULL;
_pixelFormat = NULL;
_className = title;
_wc.style = CS_HREDRAW | CS_VREDRAW | // Redraw On Size
CS_OWNDC; // Own DC For Window.
_wc.lpfnWndProc = wndProc; // WndProc Handles Messages
_wc.cbClsExtra = NULL; // No Extra Window Data
_wc.cbWndExtra = NULL; // No Extra Window Data
_wc.hInstance = NULL; // Set The Instance
_wc.hIcon = icon; // Load The Default Icon
_wc.hCursor = LoadCursor(NULL, IDC_ARROW); // Load The Arrow Pointer
_wc.hbrBackground = NULL; // No Background Required For GL
_wc.lpszMenuName = NULL; // We Don't Want A Menu
_wc.lpszClassName = _className.c_str(); // Set The Class Name
}
glWndHandles::~glWndHandles(){
// Are We Able To Release The DC And RC Contexts?
if (_hRC){
if (!wglMakeCurrent(NULL, NULL))
MessageBox(NULL, "Release Of DC And RC Failed.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);
// Are We Able To Delete The RC?
if (!wglDeleteContext(_hRC))
MessageBox(NULL, "Release Rendering Context Failed.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);
}
// Are We Able To Release The DC
if (_hDC && !ReleaseDC(_hWnd, _hDC))
MessageBox(NULL, "Release Device Context Failed.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);
// Are We Able To Destroy The Window?
if (_hWnd && !DestroyWindow(_hWnd))
MessageBox(NULL, "Could Not Release hWnd.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);
// Are We Able To Unregister Class
if (!UnregisterClass(_className.c_str(), _hInstance))
MessageBox(NULL, "Could Not Unregister Class.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);
}
glWndErrors glWndHandles::glDefWindow(PIXELFORMATDESCRIPTOR pfd){
if ((_hInstance = GetModuleHandle(NULL))){
_wc.hInstance = _hInstance;
}
else{
MessageBox(NULL, "Failed To Get Window's Instance.", "ERROR", MB_OK|MB_ICONEXCLAMATION);
return errGetInstance;
}
if (!RegisterClass(&_wc)){
MessageBox(NULL, "Failed To Register The Window Class.", "ERROR", MB_OK|MB_ICONEXCLAMATION);
return errCreateWC;
}
if (!(_hWnd=CreateWindowEx( NULL, // Extended Style For The Window
_wc.lpszClassName, // Class Name
_className.c_str(), // Window Title
NULL, // Style For The Window
0, 0, 300, 300, // Window's Position and Size
NULL, // No Parent Window
NULL, // No Menu
_hInstance, // Instance
NULL))){
MessageBox(NULL, "Window Creation Error.", "ERROR",MB_OK|MB_ICONEXCLAMATION);
return errCreateWnd;
}
//Get Window's Device Context
if (!(_hDC = GetDC(_hWnd))){
MessageBox(NULL, "Can't Create A GL Device Context.", "ERROR",MB_OK|MB_ICONEXCLAMATION);
return errCreateDC;
}
// Did Windows Find A Matching Pixel Format?
if (!(_pixelFormat = ChoosePixelFormat(_hDC, &pfd))){
MessageBox(NULL, "Can't Find A Suitable PixelFormat.", "ERROR",MB_OK|MB_ICONEXCLAMATION);
return errMatchPixelFormat;
}
// Are We Able To Set The Pixel Format?
if(!SetPixelFormat(_hDC, _pixelFormat, &pfd)){
MessageBox(NULL, "Can't Set The PixelFormat.", "ERROR",MB_OK|MB_ICONEXCLAMATION);
return errSetPixelFormat;
}
if (!(_hRC=wglCreateContext(_hDC))){
MessageBox(NULL, "Can't Create A GL Rendering Context.", "ERROR",MB_OK|MB_ICONEXCLAMATION);
return errCreateRC;
}
if(!wglMakeCurrent(_hDC,_hRC)){
MessageBox(NULL, "Can't Activate The GL Rendering Context.", "ERROR",MB_OK|MB_ICONEXCLAMATION);
return errActivateRC;
}
// GLenum err = glewInit();
//
// if (err != GLEW_OK){
// MessageBox(NULL, (char*)glewGetErrorString(err), "ERROR", MB_OK|MB_ICONEXCLAMATION);
// return errInitGL;
// }
return errNone;
}
HINSTANCE& glWndHandles::Instance(){
return _hInstance;
}
WNDCLASS& glWndHandles::WinClass(){
return _wc;
}
HDC& glWndHandles::DeviceContext(){
return _hDC;
}
HGLRC& glWndHandles::RenderContext(){
return _hRC;
}
HWND& glWndHandles::Window(){
return _hWnd;
}
glWndFPS::glWndFPS(){
_framesCounter = 0; _fps = 0;
}
GLvoid glWndFPS::NewFrame(){
_framesCounter++;
}
GLvoid glWndFPS::ResetFrames(){
_fps = _framesCounter; _framesCounter = 0;
}
GLint glWndFPS::FPS(){
return _fps;
}
glWindow* owner;
LRESULT CALLBACK glWindow::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam){
// Check For Windows Messages
switch (uMsg){
// Watch For Window Activate Message
case WM_ACTIVATE:{
// Check Minimization State
if (!HIWORD(wParam)){
// Program Is Active
owner->_state = glActive;
}
else{
// Program Is No Longer Active
owner->_state = glPaused;
}
// Return To The Message Loop
return 0;
}
// Intercept System Commands
case WM_SYSCOMMAND:{
// Check System Calls
switch (wParam){
// Screensaver Trying To Start?
case SC_SCREENSAVE:
// Monitor Trying To Enter Powersave?
case SC_MONITORPOWER:
// Prevent From Happening
return 0;
}
break;
}
// Did We Receive A Close Message?
case WM_CLOSE:{
// Send A Quit Message
PostQuitMessage(0);
return 0;
}
// Is A Key Being Held Down?
case WM_KEYDOWN:{
// If So, Mark It As TRUE
owner->_keys[wParam] = TRUE;
return 0;
}
// Has A Key Been Released?
case WM_KEYUP:{
// If So, Mark It As FALSE
owner->_keys[wParam] = FALSE;
return 0;
}
// Resize The OpenGL Window
case WM_SIZE:{
if (owner->Settings().Fullscreen() && IsWindowVisible(hWnd)){
if (wParam == SIZE_MINIMIZED)
owner->Settings().glSetStyle(hWnd, FALSE, FALSE);
else if (wParam == SIZE_RESTORED)
owner->Settings().glSetStyle(hWnd, TRUE, FALSE);
}
// LoWord=Width, HiWord=Height
owner->ReSizeGLScene(LOWORD(lParam), HIWORD(lParam));
return 0;
}
case WM_KILLFOCUS:{
if (IsWindowVisible(hWnd) && owner->Settings().Fullscreen())
ShowWindow(hWnd, SW_MINIMIZE);
return 0;
}
case WM_TIMER:{
if (wParam == 1)
owner->DisplayFPS();
return 0;
}
}
// Pass All Unhandled Messages To DefWindowProc
return DefWindowProc(hWnd,uMsg,wParam,lParam);
}
glWindow::glWindow(string title, int width, int height, int bits)
:_settings(width, height, bits), _handles(LoadIcon(NULL, IDI_WINLOGO), title, (WNDPROC)WndProc)
{
for (int i = 0; i < 256; i++){
_keys[i] = false;
}
_error = errNone; _state = glActive; owner = this;
_title = title;
if ((_error = _handles.glDefWindow(_settings.PixelFormatDescription())) != errNone){
return;
}
_settings.glSetStyle(_handles.Window(), false);
SetForegroundWindow(_handles.Window()); // Slightly Higher Priority
SetFocus(_handles.Window()); // Sets Keyboard Focus To The Window
// Initialize Our Newly Created GL Window
if (!InitGL()){
MessageBox(NULL, "Initialization Failed.", "ERROR", MB_OK|MB_ICONEXCLAMATION);
_error = errInitGL;
return;
}
SetTimer(_handles.Window(), 1, 1000, NULL);
}
glWindow::~glWindow(void){
if (_settings.Fullscreen()){
ChangeDisplaySettings(NULL,0); // If So Switch Back To The Desktop
ShowCursor(TRUE); // Show Mouse Pointer
}
}
int glWindow::InitGL(){
glShadeModel(GL_SMOOTH);
glClearColor(1.0f, 0.0f, 0.0f, 0.0f);
glClearDepth(1.0f); // Depth Buffer Setup
glEnable(GL_DEPTH_TEST); // Enables Depth Testing
glDepthFunc(GL_LEQUAL); // The Type Of Depth Test To Do
// Really Nice Perspective Calculations
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
return TRUE; // Initialization Went OK
}
GLvoid glWindow::Draw(){
//Clear The Screen And The Depth Buffer
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity(); // Reset The Current Modelview Matrix
SwapBuffers(_handles.DeviceContext());
fpsInfo().NewFrame();
}
glWndErrors& glWindow::LastError(){
return _error;
}
glWndState& glWindow::WndState(){
return _state;
}
glWndHandles& glWindow::Handles(){
return _handles;
}
glWndSettings& glWindow::Settings(){
return _settings;
}
glWndFPS& glWindow::fpsInfo(){
return _fps;
}
bool& glWindow::KeysState(int key){
return _keys[key];
}
GLvoid glWindow::DisplayFPS(){
fpsInfo().ResetFrames();
char fps[100];
sprintf(fps, "%d", fpsInfo().FPS());
SetTitle(_title + " : ");
SetTimer(_handles.Window(), 1, 1000, NULL);
}
GLvoid glWindow::SetTitle(string title){
SetWindowText(_handles.Window(), title.c_str());
}
GLvoid glWindow::SetResolution(GLsizei width, GLsizei height){
_settings.glSetResolution(_handles.Window(), width, height);
}
GLvoid glWindow::SetFullscreen(GLboolean fullscreen){
_settings.glSetStyle(_handles.Window(), fullscreen);
}
GLvoid glWindow::ToggleFullscreen(){
_settings.glSetStyle(_handles.Window());
}
GLvoid glWindow::ReSizeGLScene(GLsizei width, GLsizei height){
if (height == 0 && width == 0){
return;
}
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION); // Select The Projection Matrix
glLoadIdentity(); // Reset The Projection Matrix
// Calculate The Aspect Ratio Of The Window
glm::perspective(45.0f, (GLfloat)width/(GLfloat)height, 0.1f, 100.0f);
glMatrixMode(GL_MODELVIEW); // Select The Modelview Matrix
glLoadIdentity(); // Reset The Modelview Matrix
}
Compiler output
g++ -ID:/DarkLight/hello/header -ID:/DarkLight/externals/include -O0 -g3 -Wall -c -fmessage-length=0 -o "src\\glWindow.o" "..\\src\\glWindow.cpp"
g++ -ID:/DarkLight/hello/header -ID:/DarkLight/externals/include -O0 -g3 -Wall -c -fmessage-length=0 -o "src\\hello.o" "..\\src\\hello.cpp"
g++ -mwindows -o hello.exe "src\\hello.o" "src\\glWindow.o" -lgl -lglew32 -lglu32 -lopengl32 -lgdi32

How did you compile the Cygwin build? Specifically which libraries did you link?
Cygwin can be compiled for the native GUI system (Win32) or to make use of X11. But OpenGL goes through two very different stacks between the two cases. In case of Win32 it goes through WGL and in case of X11 it goes through GLX. Now if you accidently linked the GLX based OpenGL API (-lGL) then all the OpenGL symbols are there, so things seem to work superficially, but there's no output. You have to link against opengl32.lib, i.e. -lopengl32 so that the WGL based bindings are used.

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)
{
...
}

Capture screenshot of minimized window [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 2 years ago.
Improve this question
I tried to follow the example found:
Capturing an image from a minimized window
My code:
#include <iostream>
#include <string>
#include <windows.h>
#include <gdiplus.h>
#pragma comment(lib, "gdiplus.lib")
#pragma warning(disable : 4996)
using namespace std;
using namespace Gdiplus;
int GetEncoderClsid(LPCWSTR format, CLSID* pClsid)
{
unsigned int num = 0, size = 0;
GetImageEncodersSize(&num, &size);
if (size == 0) return -1;
ImageCodecInfo* pImageCodecInfo = (ImageCodecInfo*)(malloc(size));
if (pImageCodecInfo == NULL) return -1;
GetImageEncoders(num, size, pImageCodecInfo);
for (unsigned int j = 0; j < num; ++j) {
if (wcscmp(pImageCodecInfo[j].MimeType, format) == 0) {
*pClsid = pImageCodecInfo[j].Clsid;
free(pImageCodecInfo);
return j;
}
}
free(pImageCodecInfo);
return -1;
}
int SaveScreenshot(string filename, ULONG uQuality, HWND hwnd) // by Napalm
{
ULONG_PTR gdiplusToken;
GdiplusStartupInput gdiplusStartupInput;
GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
HWND hMyWnd = hwnd;
//HWND hMyWnd = GetDesktopWindow();
RECT r;
int w, h;
HDC dc, hdcCapture;
int nBPP, nCapture, iRes;
LPBYTE lpCapture;
CLSID imageCLSID;
Bitmap* pScreenShot;
// get the area of my application's window
GetWindowRect(hMyWnd, &r);
dc = GetWindowDC(hMyWnd); // GetDC(hMyWnd) ;
w = r.right - r.left;
h = r.bottom - r.top;
nBPP = GetDeviceCaps(dc, BITSPIXEL);
hdcCapture = CreateCompatibleDC(dc);
// create the buffer for the screenshot
BITMAPINFO bmiCapture = { sizeof(BITMAPINFOHEADER), w, -h, 1, nBPP, BI_RGB, 0, 0, 0, 0, 0, };
// create a container and take the screenshot
HBITMAP hbmCapture = CreateDIBSection(dc, &bmiCapture, DIB_PAL_COLORS, (LPVOID*)&lpCapture, NULL, 0);
// failed to take it
if (!hbmCapture) {
DeleteDC(hdcCapture);
DeleteDC(dc);
GdiplusShutdown(gdiplusToken);
printf("failed to take the screenshot. err: %d\n", GetLastError());
return 0;
}
// copy the screenshot buffer
nCapture = SaveDC(hdcCapture);
SelectObject(hdcCapture, hbmCapture);
BitBlt(hdcCapture, 0, 0, w, h, dc, 0, 0, SRCCOPY);
RestoreDC(hdcCapture, nCapture);
DeleteDC(hdcCapture);
DeleteDC(dc);
// save the buffer to a file
pScreenShot = new Bitmap(hbmCapture, (HPALETTE)NULL);
EncoderParameters encoderParams;
encoderParams.Count = 1;
encoderParams.Parameter[0].NumberOfValues = 1;
encoderParams.Parameter[0].Guid = EncoderQuality;
encoderParams.Parameter[0].Type = EncoderParameterValueTypeLong;
encoderParams.Parameter[0].Value = &uQuality;
GetEncoderClsid(L"image/jpeg", &imageCLSID);
wchar_t* lpszFilename = new wchar_t[filename.length() + 1];
mbstowcs(lpszFilename, filename.c_str(), filename.length() + 1);
iRes = (pScreenShot->Save(lpszFilename, &imageCLSID, &encoderParams) == Ok);
delete pScreenShot;
DeleteObject(hbmCapture);
GdiplusShutdown(gdiplusToken);
return iRes;
}
int main() {
HWND hWnd;
hWnd = FindWindowA(NULL, "txt.txt - Bloco de Notas");
WINDOWPLACEMENT wp = { 0 };
wp.length = sizeof(WINDOWPLACEMENT);
GetWindowPlacement(hWnd, &wp);
ANIMATIONINFO ai = { 0 };
bool restoreAnimated = false;
if (wp.showCmd == SW_SHOWMINIMIZED)
{
ai.cbSize = sizeof(ANIMATIONINFO);
SystemParametersInfo(SPI_GETANIMATION, sizeof(ANIMATIONINFO), &ai, 0);
if (ai.iMinAnimate != 0)
{
ai.iMinAnimate = 0;
SystemParametersInfo(SPI_SETANIMATION, sizeof(ANIMATIONINFO), &ai, 0);
restoreAnimated = true;
}
// optionally move the window off-screen, or
// apply alpha using SetLayeredWindowAttributes()...
ShowWindow(hWnd, SW_SHOWNOACTIVATE);
}
// capture as needed ...
string path = "C:\\Users\\CAIO\\Desktop\\screenshot.jpg";
ULONG quality = 100;
SaveScreenshot(path, quality, hWnd);
if (wp.showCmd == SW_SHOWMINIMIZED)
{
SetWindowPlacement(hWnd, &wp);
// optionally remove alpha using SetLayeredWindowAttributes()...
if (restoreAnimated)
{
ai.iMinAnimate = 1;
SystemParametersInfo(SPI_SETANIMATION, sizeof(ANIMATIONINFO), &ai, 0);
}
}
return 0;
}
In her code there's restoreAnimation = true; and if (restoreAnimation) did he mean restoreAnimated?
With the code above it still shown the window for a sec, also the captured image is all black (maybe captured while minimized) or is not captured properly.
https://youtu.be/8b1wXxtaXsY?t=9
Sec 8 and 9 from the video you can see the window is being shown on the screen.
Suggestions?
did he mean restoreAnimated?
I think yes.
This code from #Remy only disables the animation effects when minimizing and restoring, the window will still be displayed for a short time when restoring. As the answer pointed out, you can use SetLayeredWindowAttributes to make the window nearly completely transparent(It should be noted that using SetLayeredWindowAttributes needs to ensure that hwnd has WS_EX_LAYERED style.) and then you will not see the window, but the operating system will.
In addition, the problem of incomplete window capture is because the window is not drawn completely, call UpdateWindow after ShowWindow works for me, it will send a WM_PAINT message to the window.
bool restoreAnimated = false;
BYTE Alph = 0;
LONG_PTR exstyle = 0;
if (wp.showCmd == SW_SHOWMINIMIZED)
{
ai.cbSize = sizeof(ANIMATIONINFO);
SystemParametersInfo(SPI_GETANIMATION, sizeof(ANIMATIONINFO), &ai, 0);
if (ai.iMinAnimate != 0)
{
ai.iMinAnimate = 0;
SystemParametersInfo(SPI_SETANIMATION, sizeof(ANIMATIONINFO), &ai, 0);
restoreAnimated = true;
}
// optionally move the window off-screen, or
// apply alpha using SetLayeredWindowAttributes()...
exstyle = GetWindowLongPtr(hWnd, GWL_EXSTYLE);
SetWindowLongPtr(hWnd, GWL_EXSTYLE, exstyle | WS_EX_LAYERED);
DWORD flag;
BOOL ret = GetLayeredWindowAttributes(hWnd, 0, &Alph, 0);
SetLayeredWindowAttributes(hWnd, 0, 1, LWA_ALPHA);
ShowWindow(hWnd, SW_SHOWNOACTIVATE);
UpdateWindow(hWnd);
}
// capture as needed ...
string path = "C:\\Users\\name\\Desktop\\screenshot.jpg";
ULONG quality = 100;
SaveScreenshot(path, quality, hWnd);
if (wp.showCmd == SW_SHOWMINIMIZED)
{
SetWindowPlacement(hWnd, &wp);
// optionally remove alpha using SetLayeredWindowAttributes()...
SetLayeredWindowAttributes(hWnd, 0, Alph, LWA_ALPHA);
SetWindowLongPtr(hWnd, GWL_EXSTYLE, exstyle);
if (restoreAnimated)
{
ai.iMinAnimate = 1;
SystemParametersInfo(SPI_SETANIMATION, sizeof(ANIMATIONINFO), &ai, 0);
}
}

Initializing OpenGL without libraries

Every tutorial I find Online uses SDL or GLAD or other libraries to initialize OpenGL. Is there a way of initializing OpenGL with no extra libraries (like DirectX)?
The reason for that, Is that I am building a Game Engine and I want to minimize the external libraries as possible and to be able to handle more error messages.
Initializing OpenGL differs from one operating system to another, that's why people made these libraries to ease other developers work.
Some tutorials that will help you.
For Windows (WGL)
https://www.khronos.org/opengl/wiki/Creating_an_OpenGL_Context
http://www.rastertek.com/gl40tut03.html
For Linux (GLX)
https://www.khronos.org/opengl/wiki/Tutorial:_OpenGL_3.0_Context_Creation_(GLX)
There isn't much quality information about doing this. I found a great piece of code called windows_modern_opengl_context.c on github by the user nickrolfe. I thought I'd share it here to make it easier for others to find. If you link -lopengl32 and make sure you have -mwindows flag up it should compile fine with a modern c compiler. I'm using gcc -std=c11. If you want to use C++ you may have to edit the code to not use designated initializers when initializing the structs. I'm not sure.
EDIT:
This code creates an empty window using the win32 api with a modern opengl context (Version 3.3). You will still need to load the appropriate gl extensions in order to call functions such as glCreateShader(...); I recommend using glad to do this. If you use glad like I said you should use gladLoadGL() instead of gladLoadGLLoader() to load the extensions.
// Sample code showing how to create a modern OpenGL window and rendering context on Win32.
#include <windows.h>
#include <gl/gl.h>
#include <stdbool.h>
typedef HGLRC WINAPI wglCreateContextAttribsARB_type(HDC hdc, HGLRC hShareContext, const int *attribList);
wglCreateContextAttribsARB_type *wglCreateContextAttribsARB;
// See https://www.opengl.org/registry/specs/ARB/wgl_create_context.txt for all values
#define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091
#define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092
#define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126
#define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001
typedef BOOL WINAPI wglChoosePixelFormatARB_type(HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats);
wglChoosePixelFormatARB_type *wglChoosePixelFormatARB;
// See https://www.opengl.org/registry/specs/ARB/wgl_pixel_format.txt for all values
#define WGL_DRAW_TO_WINDOW_ARB 0x2001
#define WGL_ACCELERATION_ARB 0x2003
#define WGL_SUPPORT_OPENGL_ARB 0x2010
#define WGL_DOUBLE_BUFFER_ARB 0x2011
#define WGL_PIXEL_TYPE_ARB 0x2013
#define WGL_COLOR_BITS_ARB 0x2014
#define WGL_DEPTH_BITS_ARB 0x2022
#define WGL_STENCIL_BITS_ARB 0x2023
#define WGL_FULL_ACCELERATION_ARB 0x2027
#define WGL_TYPE_RGBA_ARB 0x202B
static void
fatal_error(char *msg)
{
MessageBoxA(NULL, msg, "Error", MB_OK | MB_ICONEXCLAMATION);
exit(EXIT_FAILURE);
}
static void
init_opengl_extensions(void)
{
// Before we can load extensions, we need a dummy OpenGL context, created using a dummy window.
// We use a dummy window because you can only set the pixel format for a window once. For the
// real window, we want to use wglChoosePixelFormatARB (so we can potentially specify options
// that aren't available in PIXELFORMATDESCRIPTOR), but we can't load and use that before we
// have a context.
WNDCLASSA window_class = {
.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC,
.lpfnWndProc = DefWindowProcA,
.hInstance = GetModuleHandle(0),
.lpszClassName = "Dummy_WGL_djuasiodwa",
};
if (!RegisterClassA(&window_class)) {
fatal_error("Failed to register dummy OpenGL window.");
}
HWND dummy_window = CreateWindowExA(
0,
window_class.lpszClassName,
"Dummy OpenGL Window",
0,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
0,
0,
window_class.hInstance,
0);
if (!dummy_window) {
fatal_error("Failed to create dummy OpenGL window.");
}
HDC dummy_dc = GetDC(dummy_window);
PIXELFORMATDESCRIPTOR pfd = {
.nSize = sizeof(pfd),
.nVersion = 1,
.iPixelType = PFD_TYPE_RGBA,
.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,
.cColorBits = 32,
.cAlphaBits = 8,
.iLayerType = PFD_MAIN_PLANE,
.cDepthBits = 24,
.cStencilBits = 8,
};
int pixel_format = ChoosePixelFormat(dummy_dc, &pfd);
if (!pixel_format) {
fatal_error("Failed to find a suitable pixel format.");
}
if (!SetPixelFormat(dummy_dc, pixel_format, &pfd)) {
fatal_error("Failed to set the pixel format.");
}
HGLRC dummy_context = wglCreateContext(dummy_dc);
if (!dummy_context) {
fatal_error("Failed to create a dummy OpenGL rendering context.");
}
if (!wglMakeCurrent(dummy_dc, dummy_context)) {
fatal_error("Failed to activate dummy OpenGL rendering context.");
}
wglCreateContextAttribsARB = (wglCreateContextAttribsARB_type*)wglGetProcAddress("wglCreateContextAttribsARB");
wglChoosePixelFormatARB = (wglChoosePixelFormatARB_type*)wglGetProcAddress("wglChoosePixelFormatARB");
wglMakeCurrent(dummy_dc, 0);
wglDeleteContext(dummy_context);
ReleaseDC(dummy_window, dummy_dc);
DestroyWindow(dummy_window);
}
static HGLRC
init_opengl(HDC real_dc)
{
init_opengl_extensions();
// Now we can choose a pixel format the modern way, using wglChoosePixelFormatARB.
int pixel_format_attribs[] = {
WGL_DRAW_TO_WINDOW_ARB, GL_TRUE,
WGL_SUPPORT_OPENGL_ARB, GL_TRUE,
WGL_DOUBLE_BUFFER_ARB, GL_TRUE,
WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB,
WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB,
WGL_COLOR_BITS_ARB, 32,
WGL_DEPTH_BITS_ARB, 24,
WGL_STENCIL_BITS_ARB, 8,
0
};
int pixel_format;
UINT num_formats;
wglChoosePixelFormatARB(real_dc, pixel_format_attribs, 0, 1, &pixel_format, &num_formats);
if (!num_formats) {
fatal_error("Failed to set the OpenGL 3.3 pixel format.");
}
PIXELFORMATDESCRIPTOR pfd;
DescribePixelFormat(real_dc, pixel_format, sizeof(pfd), &pfd);
if (!SetPixelFormat(real_dc, pixel_format, &pfd)) {
fatal_error("Failed to set the OpenGL 3.3 pixel format.");
}
// Specify that we want to create an OpenGL 3.3 core profile context
int gl33_attribs[] = {
WGL_CONTEXT_MAJOR_VERSION_ARB, 3,
WGL_CONTEXT_MINOR_VERSION_ARB, 3,
WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
0,
};
HGLRC gl33_context = wglCreateContextAttribsARB(real_dc, 0, gl33_attribs);
if (!gl33_context) {
fatal_error("Failed to create OpenGL 3.3 context.");
}
if (!wglMakeCurrent(real_dc, gl33_context)) {
fatal_error("Failed to activate OpenGL 3.3 rendering context.");
}
return gl33_context;
}
static LRESULT CALLBACK
window_callback(HWND window, UINT msg, WPARAM wparam, LPARAM lparam)
{
LRESULT result = 0;
switch (msg) {
case WM_CLOSE:
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
result = DefWindowProcA(window, msg, wparam, lparam);
break;
}
return result;
}
static HWND
create_window(HINSTANCE inst)
{
WNDCLASSA window_class = {
.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC,
.lpfnWndProc = window_callback,
.hInstance = inst,
.hCursor = LoadCursor(0, IDC_ARROW),
.hbrBackground = 0,
.lpszClassName = "WGL_fdjhsklf",
};
if (!RegisterClassA(&window_class)) {
fatal_error("Failed to register window.");
}
// Specify a desired width and height, then adjust the rect so the window's client area will be
// that size.
RECT rect = {
.right = 1024,
.bottom = 576,
};
DWORD window_style = WS_OVERLAPPEDWINDOW;
AdjustWindowRect(&rect, window_style, false);
HWND window = CreateWindowExA(
0,
window_class.lpszClassName,
"OpenGL",
window_style,
CW_USEDEFAULT,
CW_USEDEFAULT,
rect.right - rect.left,
rect.bottom - rect.top,
0,
0,
inst,
0);
if (!window) {
fatal_error("Failed to create window.");
}
return window;
}
int WINAPI
WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmd_line, int show)
{
HWND window = create_window(inst);
HDC gldc = GetDC(window);
HGLRC glrc = init_opengl(gldc);
ShowWindow(window, show);
UpdateWindow(window);
bool running = true;
while (running) {
MSG msg;
while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) {
if (msg.message == WM_QUIT) {
running = false;
} else {
TranslateMessage(&msg);
DispatchMessageA(&msg);
}
}
glClearColor(1.0f, 0.5f, 0.5f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Do OpenGL rendering here
SwapBuffers(gldc);
}
return 0;
}

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();
}
}

OpenGL context creation never chooses pixel format

I'm trying to create an OpenGL context inside a Win32 window for a library I'm writing. I've boiled it down to a small example which will compile to help debug it. For some reason, it never chooses a pixel format properly. Here's the code:
#include <iostream>
#include <windows.h>
#include <GL/glew.h>
#include <GL/gl.h>
#include <GL/wglew.h>
HWND handle;
HDC deviceContext;
HGLRC context;
int resolutionX = 1280;
int resolutionY = 720;
std::string title = "Test Window";
LRESULT CALLBACK eventCallback(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
int main()
{
// Register the window class
WNDCLASSA windowClass;
windowClass.style = 0;
windowClass.lpfnWndProc = &eventCallback;
windowClass.cbClsExtra = 0;
windowClass.cbWndExtra = 0;
windowClass.hInstance = GetModuleHandle(nullptr);
windowClass.hIcon = nullptr;
windowClass.hCursor = nullptr;
windowClass.hbrBackground = nullptr;
windowClass.lpszMenuName = nullptr;
windowClass.lpszClassName = "Test_Window";
RegisterClassA(&windowClass);
// Compute position and size
HDC screenDC = GetDC(nullptr);
int left = (GetDeviceCaps(screenDC, HORZRES) - static_cast<int>(resolutionX)) / 2;
int top = (GetDeviceCaps(screenDC, VERTRES) - static_cast<int>(resolutionY)) / 2;
int width = resolutionX;
int height = resolutionY;
ReleaseDC(nullptr, screenDC);
// Set window style
DWORD win32Style = WS_VISIBLE | WS_CAPTION | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_THICKFRAME | WS_SYSMENU;
// In windowed mode, adjust width and height so that window will have the requested client area
RECT rectangle = {0, 0, width, height};
AdjustWindowRect(&rectangle, win32Style, false);
width = rectangle.right - rectangle.left;
height = rectangle.bottom - rectangle.top;
// Create the window
handle = CreateWindowA("Test_Window", title.c_str(), win32Style, left, top, width, height, NULL, NULL, GetModuleHandle(nullptr), nullptr);
if(handle == NULL)
{
std::cout << "Failed to create window" << std::endl;
return 1;
}
// Setup a pixel format descriptor from the rendering settings
PIXELFORMATDESCRIPTOR descriptor;
ZeroMemory(&descriptor, sizeof(descriptor));
descriptor.nSize = sizeof(descriptor);
descriptor.nVersion = 1;
descriptor.iLayerType = PFD_MAIN_PLANE;
descriptor.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
descriptor.iPixelType = PFD_TYPE_RGBA;
descriptor.cColorBits = static_cast<BYTE>(32);
descriptor.cDepthBits = static_cast<BYTE>(24);
descriptor.cStencilBits = static_cast<BYTE>(8);
descriptor.cAlphaBits = 8;
// Get the pixel format that best matches our requirements
int bestFormat = ChoosePixelFormat(deviceContext, &descriptor);
if(bestFormat == 0)
{
std::cout << "Failed to find a suitable pixel format for device context -- cannot create OpenGL context" << std::endl;
return 1;
}
// Extract the depth and stencil bits from the chosen format
PIXELFORMATDESCRIPTOR actualFormat;
actualFormat.nSize = sizeof(actualFormat);
actualFormat.nVersion = 1;
DescribePixelFormat(deviceContext, bestFormat, sizeof(actualFormat), &actualFormat);
// Set the chosen pixel format
if(!SetPixelFormat(deviceContext, bestFormat, &actualFormat))
{
std::cout << "Failed to set pixel format for device context -- cannot create OpenGL context" << std::endl;
return 1;
}
PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB = reinterpret_cast<PFNWGLCREATECONTEXTATTRIBSARBPROC>(wglGetProcAddress("wglCreateContextAttribsARB"));
if(wglCreateContextAttribsARB)
{
int attributes[] =
{
WGL_CONTEXT_MAJOR_VERSION_ARB, static_cast<int>(3),
WGL_CONTEXT_MINOR_VERSION_ARB, static_cast<int>(0),
WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB,
0, 0
};
context = wglCreateContextAttribsARB(deviceContext, nullptr, attributes);
}
if(!context)
{
context = wglCreateContext(deviceContext);
if(!context)
{
std::cout << "Failed to create the OpenGL context" << std::endl;
return 1;
}
}
// Destroy the OpenGL context
wglMakeCurrent(nullptr, nullptr);
wglDeleteContext(context);
// Destroy the device context
ReleaseDC(handle, deviceContext);
// Destroy the window handle
DestroyWindow(handle);
// Unregister the window
UnregisterClassA("Test_Window", GetModuleHandle(nullptr));
std::cout << "Window created" << std::endl;
return 0;
}
LRESULT CALLBACK eventCallback(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
// Associate handle and Window instance when the creation message is received
if(message == WM_CREATE)
{
LONG_PTR window = (LONG_PTR)reinterpret_cast<CREATESTRUCT*>(lParam)->lpCreateParams;
// Set as the "user data" parameter of the window
SetWindowLongPtr(hwnd, GWLP_USERDATA, window);
}
return DefWindowProcA(hwnd, message, wParam, lParam);
}
You never initialize deviceContext, which means that it will have a garbage value. If you call GetLastError after trying ChoosePixelFormat, I imagine that you'll find that it's telling you that you have an invalid handle.
wglGetProcAddress needs a valid OpenGL context being created and bound to yield a sensible result. Which means that in order to use wglCreateContextAttribsARB you first have to create an intermediary helper OpenGL context that gives you access to that function.
Update
As it happens I recently wrote some small helper to deal with this. Available under the terms of the MIT license at https://github.com/datenwolf/wglarb
Try to add this on the initialization of pixel format descriptor:
descriptor.cRedBits = 8;
descriptor.cGreenBits = 8;
descriptor.cBlueBits = 8;