我开始研究一个免费项目,在OpenGL中创建自己的渲染引擎 我已经在DirectX中创建了一个并且想要探索新的东西。 我的DirectX引擎在这里有一些缺陷所以我想在我的OpenGl引擎中纠正它们。
目前我正在尝试创建一个新窗口来渲染我的几何体。我希望我的窗口类可以重新使用,所以我创建了一个模板类:
#ifndef _IWINDOW_H
#define _IWINDOW_H
#ifndef _WINDOWS_
#include <windows.h>
#endif
#ifndef _STRING_H
#include "string.h"
#endif
template<class T>
class IWindow
{
public:
IWindow();
virtual ~IWindow();
static LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
virtual LRESULT handleEvent(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) = 0;
virtual BYTE getWindowBitsPerPixel() const = 0;
virtual long getWindowWidth() const = 0;
virtual long getWindowHeight() const = 0;
virtual const std::tstring getWindowTitle() const = 0;
virtual const std::tstring getWindowClassName() const = 0;
HWND getWindowHandle();
HINSTANCE getWindowInstance();
protected:
bool createWindow();
bool destroyWindow();
void setExtendedStyle(DWORD extendedStyle);
void setStyle(DWORD style);
DWORD getExtentedStyle() const;
DWORD getStyle() const;
RECT getWindowRect() const;
private:
bool setupWindow();
bool errorHandling();
WNDCLASS createWindowClass();
RECT createWindowRect();
PIXELFORMATDESCRIPTOR createWindowPixelFormatDescription();
HGLRC handle_resourcecontext;
HDC handle_devicecontext;
HWND handle_window;
HINSTANCE handle_instance;
RECT window_rect;
DWORD extended_style;
DWORD style;
unsigned int pixel_format;
};
template<class T>
IWindow<T>::IWindow()
: handle_resourcecontext(0)
, handle_devicecontext(0)
, handle_window(0)
, handle_instance(GetModuleHandle(NULL))
, window_rect()
, extended_style(0)
, style(0)
, pixel_format(0)
{}
template<class T>
IWindow<T>::~IWindow()
{}
template<class T>
LRESULT CALLBACK IWindow<T>::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
if (uMsg == WM_CREATE)
{
// if the message is WM_CREATE, the lParam contains a pointer to a CREATESTRUCT
// the CREATESTRUCT contains the "this" pointer from the CreateWindow method
// the "this" pointer of our app is stored in the createstruct pcs->lpCreateParams
CREATESTRUCT *pCS = (CREATESTRUCT*)lParam;
SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG)pCS->lpCreateParams);
}
else
{
//retrieve the stored "this" pointer
LONG value = GetWindowLongPtr(hWnd, GWLP_USERDATA);
T* window = (T*)(GetWindowLongPtr(hWnd, GWLP_USERDATA));
if (window != nullptr)
return window->handleEvent(hWnd, uMsg, wParam, lParam);
}
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
template<class T>
bool IWindow<T>::createWindow()
{
this->window_rect = createWindowRect();
if (!RegisterClass(&createWindowClass()))
{
MessageBox(NULL, _T("Failed To Register The Window Class."), _T("ERROR"), MB_OK | MB_ICONEXCLAMATION);
return FALSE;
}
if (!setupWindow())
return FALSE;
if (!errorHandling())
return FALSE;
ShowWindow(this->handle_window, SW_SHOW);
SetForegroundWindow(this->handle_window);
SetFocus(this->handle_window);
return TRUE;
}
template<class T>
bool IWindow<T>::destroyWindow()
{
LPCTSTR window_classname = getWindowClassName().c_str();
if (this->handle_resourcecontext)
{
if (!wglMakeCurrent(NULL, NULL)) MessageBox(NULL, _T("Release Of DC And RC Failed."), _T("SHUTDOWN ERROR"), MB_OK | MB_ICONINFORMATION);
if (!wglDeleteContext(this->handle_resourcecontext)) MessageBox(NULL, _T("Release Rendering Context Failed."), _T("SHUTDOWN ERROR"), MB_OK | MB_ICONINFORMATION);
this->handle_resourcecontext = NULL;
}
if (this->handle_devicecontext && !ReleaseDC(this->handle_window, this->handle_devicecontext))
{
MessageBox(NULL, _T("Release Device Context Failed."), _T("SHUTDOWN ERROR"), MB_OK | MB_ICONINFORMATION);
this->handle_devicecontext = NULL;
}
if (this->handle_window && !DestroyWindow(this->handle_window))
{
MessageBox(NULL, _T("Could Not Release hWnd."), _T("SHUTDOWN ERROR"), MB_OK | MB_ICONINFORMATION);
this->handle_window = NULL;
}
if (!UnregisterClass(_T("classname"), this->handle_instance))
{
MessageBox(NULL, _T("Could Not Unregister Class."), _T("SHUTDOWN ERROR"), MB_OK | MB_ICONINFORMATION);
this->handle_instance = NULL;
}
return TRUE;
}
template<class T>
void IWindow<T>::setExtendedStyle(DWORD extendedStyle)
{
this->extended_style = extendedStyle;
}
template<class T>
void IWindow<T>::setStyle(DWORD style)
{
this->style = style;
}
template<class T>
DWORD IWindow<T>::getExtentedStyle() const
{
return this->extended_style;
}
template<class T>
DWORD IWindow<T>::getStyle() const
{
return this->style;
}
template<class T>
RECT IWindow<T>::getWindowRect() const
{
return this->window_rect;
}
template<class T>
bool IWindow<T>::setupWindow()
{
LPCTSTR window_classname = getWindowClassName().c_str();
LPCTSTR window_title = getWindowTitle().c_str();
this->handle_window = CreateWindowEx(this->extended_style,
_T("classname"),
window_title,
this->style |
WS_CLIPSIBLINGS |
WS_CLIPCHILDREN,
0, 0,
this->window_rect.right - this->window_rect.left,
this->window_rect.bottom - this->window_rect.top,
NULL,
NULL,
this->handle_instance,
this);
int error = GetLastError();
if (!this->handle_window)
{
MessageBox(NULL, _T("Window Creation Error."), _T("ERROR"), MB_OK | MB_ICONEXCLAMATION);
return FALSE;
}
return TRUE;
}
template<class T>
bool IWindow<T>::errorHandling()
{
//Check if we have a device context
if (!(this->handle_devicecontext = GetDC(this->handle_window)))
{
MessageBox(NULL, _T("Can't Create A GL Device Context."), _T("ERROR"), MB_OK | MB_ICONEXCLAMATION);
return FALSE;
}
//Check the pixel format
PIXELFORMATDESCRIPTOR pfd = createWindowPixelFormatDescription();
this->pixel_format = ChoosePixelFormat(this->handle_devicecontext, &pfd);
if (!this->pixel_format)
{
MessageBox(NULL, _T("Can't Find A Suitable PixelFormat."), _T("ERROR"), MB_OK | MB_ICONEXCLAMATION);
return FALSE;
}
if (!SetPixelFormat(this->handle_devicecontext, this->pixel_format, &pfd))
{
MessageBox(NULL, _T("Can't Set The PixelFormat."), _T("ERROR"), MB_OK | MB_ICONEXCLAMATION);
return FALSE;
}
//Check if the open gl context is succesfully created
this->handle_resourcecontext = wglCreateContext(this->handle_devicecontext);
if (!this->handle_resourcecontext)
{
MessageBox(NULL, _T("Can't Create A GL Rendering Context."), _T("ERROR"), MB_OK | MB_ICONEXCLAMATION);
return FALSE;
}
if (!wglMakeCurrent(this->handle_devicecontext, this->handle_resourcecontext))
{
MessageBox(NULL, _T("Can't Activate The GL Rendering Context."), _T("ERROR"), MB_OK | MB_ICONEXCLAMATION);
return FALSE;
}
return TRUE;
}
template<class T>
WNDCLASS IWindow<T>::createWindowClass()
{
LPCTSTR window_classname = getWindowClassName().c_str();
WNDCLASS wc;
wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
wc.lpfnWndProc = (WNDPROC)WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = sizeof(LONG_PTR);
wc.hInstance = this->handle_instance;
//TODO: load the cursor and application icon!
wc.hIcon = LoadIcon(NULL, IDI_WINLOGO);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = NULL;
wc.lpszMenuName = NULL;
wc.lpszClassName = _T("classname");
return wc;
}
template<class T>
RECT IWindow<T>::createWindowRect()
{
return RECT
{
(long)0,
(long)0,
(long)getWindowWidth(),
(long)getWindowHeight()
};
}
template<class T>
PIXELFORMATDESCRIPTOR IWindow<T>::createWindowPixelFormatDescription()
{
return PIXELFORMATDESCRIPTOR
{
sizeof(PIXELFORMATDESCRIPTOR),
1,
PFD_DRAW_TO_WINDOW |
PFD_SUPPORT_OPENGL |
PFD_DOUBLEBUFFER,
PFD_TYPE_RGBA,
getWindowBitsPerPixel(),
0, 0, 0, 0, 0, 0,
0,
0,
0,
0, 0, 0, 0,
16,
0,
0,
PFD_MAIN_PLANE,
0,
0, 0, 0
};
}
template<class T>
HWND IWindow<T>::getWindowHandle()
{
return this->handle_window;
}
template<class T>
HINSTANCE IWindow<T>::getWindowInstance()
{
return this->handle_instance;
}
#endif //_IWINDOW_H
如果我创建这个类的实例,它将看起来像这样:
#ifndef _WINDOW_H
#define _WINDOW_H
#include "System.h"
#include "IWindow.h"
class MainWindow : public System, public IWindow<MainWindow>
{
public:
MainWindow();
virtual ~MainWindow();
virtual bool initialize();
virtual void update();
virtual bool shutDown();
bool setFullscreen(bool fullscreen);
bool getFullscreen() const;
virtual LRESULT handleEvent(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
virtual BYTE getWindowBitsPerPixel() const;
virtual long getWindowWidth() const;
virtual long getWindowHeight() const;
virtual const std::tstring getWindowTitle() const;
virtual const std::tstring getWindowClassName() const;
private:
};
#endif //_WINDOW_H
使用相应的源文件:
#include "MainWindow.h"
#include <gl\gl.h>
#include <gl\glu.h>
#ifndef _STRING_H
#include "string.h"
#endif
#include "WorldSettings.h"
#include "ApplicationSettings.h"
#include "SystemType.h"
#include "Singleton.h"
MainWindow::MainWindow()
:System(SystemType::WINDOW_SYSTEM)
{
}
MainWindow::~MainWindow()
{
}
bool MainWindow::initialize()
{
if (!createWindow())
{
shutDown();
return FALSE;
}
return true;
}
void MainWindow::update()
{
}
bool MainWindow::shutDown()
{
ApplicationSettings settings = Singleton<WorldSettings>::getInstance().getApplicationSettings();
if (settings.getFullscreen())
{
ChangeDisplaySettings(NULL, 0);
ShowCursor(TRUE);
}
destroyWindow();
return TRUE;
}
bool MainWindow::setFullscreen(bool fullscreen)
{
ApplicationSettings settings = Singleton<WorldSettings>::getInstance().getApplicationSettings();
if (settings.getFullscreen() == fullscreen)
return true;
if (fullscreen)
{
DEVMODE dmScreenSettings;
memset(&dmScreenSettings, 0, sizeof(dmScreenSettings));
dmScreenSettings.dmSize = sizeof(dmScreenSettings);
dmScreenSettings.dmPelsWidth = settings.getWindowWidth();
dmScreenSettings.dmPelsHeight = settings.getWindowHeight();
dmScreenSettings.dmBitsPerPel = settings.getBitsPerPixel();
dmScreenSettings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
if (ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL)
{
if (MessageBox(NULL, _T("The Requested Fullscreen Mode Is Not Supported By\nYour Video Card. Use Windowed Mode Instead?"), _T("NeHe GL"), MB_YESNO | MB_ICONEXCLAMATION) == IDYES)
{
settings.setFullscreen(FALSE);
}
else
{
MessageBox(NULL, _T("Program Will Now Close."), _T("ERROR"), MB_OK | MB_ICONSTOP);
return FALSE;
}
}
}
if (settings.getFullscreen())
{
setExtendedStyle(WS_EX_APPWINDOW);
setStyle(WS_POPUP);
ShowCursor(FALSE);
}
else
{
setExtendedStyle(WS_EX_APPWINDOW | WS_EX_WINDOWEDGE);
setStyle(WS_OVERLAPPEDWINDOW);
ShowCursor(TRUE);
}
AdjustWindowRectEx(&getWindowRect(), getStyle(), FALSE, getExtentedStyle());
//If the settings have been changed apply them to the worldsettings
Singleton<WorldSettings>::getInstance().setApplicationSettings(settings);
return TRUE;
}
bool MainWindow::getFullscreen() const
{
return Singleton<WorldSettings>::getInstance().getApplicationSettings().getFullscreen();
}
LRESULT MainWindow::handleEvent(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_ACTIVATE:
{
if (!HIWORD(wParam))
{
activate();
}
else
{
deactivate();
}
return 0;
}
case WM_SYSCOMMAND:
{
switch (wParam)
{
case SC_SCREENSAVE:
case SC_MONITORPOWER:
return 0;
}
break;
}
case WM_CLOSE:
{
PostQuitMessage(0);
return 0;
}
//case WM_SIZE:
//{
// ReSizeGLScene(LOWORD(lParam), HIWORD(lParam));
// return 0;
//}
}
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
BYTE MainWindow::getWindowBitsPerPixel() const
{
return Singleton<WorldSettings>::getInstance().getApplicationSettings().getBitsPerPixel();
}
long MainWindow::getWindowWidth() const
{
return Singleton<WorldSettings>::getInstance().getApplicationSettings().getWindowWidth();
}
long MainWindow::getWindowHeight() const
{
return Singleton<WorldSettings>::getInstance().getApplicationSettings().getWindowHeight();
}
const std::tstring MainWindow::getWindowTitle() const
{
return Singleton<WorldSettings>::getInstance().getApplicationSettings().getWindowTitle();
}
const std::tstring MainWindow::getWindowClassName() const
{
return Singleton<WorldSettings>::getInstance().getApplicationSettings().getWindowTitle();
}
问题在于每当我使用CreateWindowEx(...)创建主窗口时,WndProc函数内的强制转换始终会失败。 我已经将“this”指针作为CreateWindowEx(...)函数的最后一个参数,从WndProc函数内的GetWindowLongPtr(...)方法中检索它。这样我就可以调用类本身的自定义事件处理方法,以使用更“面向对象”的设计。
如果有人能看到我在这里做错了什么,我很乐意听到。 提前感谢您阅读这篇长篇文章。
亲切的问候。 Dyronix。
答案 0 :(得分:0)
我找到了解决问题的方法。 我可以将void指针强制转换为基类的类型,而不是转换为基类的类型,因为每个类都会继承它,无论如何都会调用正确的方法
LRESULT CALLBACK IWindow<T>::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
if (uMsg == WM_CREATE)
{
// if the message is WM_CREATE, the lParam contains a pointer to a CREATESTRUCT
// the CREATESTRUCT contains the "this" pointer from the CreateWindow method
// the "this" pointer of our app is stored in the createstruct pcs->lpCreateParams
CREATESTRUCT *pCS = (CREATESTRUCT*)lParam;
SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG)pCS->lpCreateParams);
}
else
{
//retrieve the stored "this" pointer
LONG value = GetWindowLongPtr(hWnd, GWLP_USERDATA);
IWindow* window = (IWindow*)(GetWindowLongPtr(hWnd, GWLP_USERDATA));
if (window != nullptr)
return window->handleEvent(hWnd, uMsg, wParam, lParam);
}
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
所以实际上我并不是100%确定,但模板类不需要,可以删除。我首先想到我需要为每个新类创建一个不同的实例才能使WndProc工作,但我认为你只需要一个WndProc / Application并且它将捕获来自所有活动窗口的所有窗口消息。 / p>
在任何情况下,如果是这种情况,你可以删除模板类,如果不是我可以保留它。该解决方案适用于这两种方法。