Created
May 5, 2018 07:56
-
-
Save davepkennedy/8979254ef8fc8b86965dcb38e60e3ce2 to your computer and use it in GitHub Desktop.
Basic code for GL4 on Window
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include <Windows.h> | |
#define DECLARE_APP(WinType) \ | |
int CALLBACK wWinMain( \ | |
HINSTANCE hInst, \ | |
HINSTANCE hPrevInst, \ | |
LPWSTR lpCmdLine, \ | |
int nCmdShow \ | |
) { \ | |
Application<WinType> app; \ | |
return app.Run(); \ | |
} | |
template <typename WINDOW> | |
class Application { | |
private: | |
WINDOW* window; | |
void Setup() | |
{ | |
WINDOW dummy; | |
dummy.Register(); | |
dummy.Create(); | |
if (dummy.CanUpgrade()) { | |
window = new WINDOW(&dummy); | |
} | |
else { | |
window = new WINDOW; | |
} | |
window->Register(); | |
window->Create(); | |
window->ShowWindow(SW_SHOW); | |
window->Update(); | |
} | |
void Loop() | |
{ | |
MSG msg; | |
ZeroMemory(&msg, sizeof(MSG)); | |
while (true) { | |
if (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE)) { | |
if (msg.message == WM_QUIT) { | |
break; | |
} | |
TranslateMessage(&msg); | |
DispatchMessage(&msg); | |
} | |
if (window->MakeCurrent()) { | |
window->Tick(); | |
window->Render(); | |
window->SwapBuffers(); | |
} | |
} | |
} | |
void Teardown() | |
{ | |
window->Shutdown(); | |
delete window; | |
} | |
public: | |
int Run() | |
{ | |
Setup(); | |
Loop(); | |
Teardown(); | |
return 0; | |
} | |
}; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "GLWindow.h" | |
#pragma comment (lib, "opengl32") | |
GLWindow::GLWindow() | |
: _lastTick(GetTickCount64()) | |
, _createdVersion(1) | |
{ | |
observe(WM_CREATE, [this](WPARAM, LPARAM) { | |
_deviceContext = GetDC(this->Handle()); | |
this->SetupContext(_deviceContext); | |
_glContext = wglCreateContext(_deviceContext); | |
MakeCurrent(); | |
LoadPrototypes(); | |
Init(); | |
}); | |
SetupCommon(); | |
} | |
int GLWindow::ChoosePixelFormat(const HDC hdc, const int multisamples, const bool stereo3D) { | |
FLOAT fAttributes[] = { 0, 0 }; | |
int iAttributes[] = { | |
WGL_SAMPLE_BUFFERS_ARB, ((multisamples > 1) ? 1 : 0), | |
WGL_SAMPLES_ARB, multisamples, | |
WGL_DOUBLE_BUFFER_ARB, TRUE, | |
WGL_STENCIL_BITS_ARB, 8, | |
WGL_DEPTH_BITS_ARB, 24, | |
WGL_RED_BITS_ARB, 8, | |
WGL_BLUE_BITS_ARB, 8, | |
WGL_GREEN_BITS_ARB, 8, | |
WGL_ALPHA_BITS_ARB, 8, | |
WGL_STEREO_ARB, (stereo3D ? TRUE : FALSE), | |
0, 0 | |
}; | |
int pixelFormat; | |
UINT numFormats; | |
if (!wglChoosePixelFormatARB(hdc, iAttributes, fAttributes, 1, &pixelFormat, &numFormats)) { | |
return -1; | |
} | |
return pixelFormat; | |
} | |
GLWindow::GLWindow(const GLWindow* window) | |
: _lastTick(GetTickCount64()) | |
, _createdVersion(window->Version()) | |
{ | |
observe(WM_CREATE, [this, window](WPARAM, LPARAM) { | |
LoadPrototypes(); | |
_deviceContext = GetDC(this->Handle()); | |
int pixelFormat = this->ChoosePixelFormat(_deviceContext, 0, false); | |
PIXELFORMATDESCRIPTOR pfd; | |
ZeroMemory(&pfd, sizeof(PIXELFORMATDESCRIPTOR)); | |
DescribePixelFormat(_deviceContext, pixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &pfd); | |
if (!SetPixelFormat(_deviceContext, pixelFormat, &pfd)) { | |
ShowLastError(); | |
} | |
const int attribs[] = | |
{ | |
//WGL_CONTEXT_MAJOR_VERSION_ARB, 3, | |
//WGL_CONTEXT_MINOR_VERSION_ARB, 0, | |
WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_DEBUG_BIT_ARB, | |
WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB, | |
0, 0 | |
}; | |
_glContext = wglCreateContextAttribsARB(_deviceContext, nullptr, attribs); | |
MakeCurrent(); | |
Init(); | |
}); | |
SetupCommon(); | |
} | |
void GLWindow::Destroy() | |
{ | |
wglDeleteContext(_glContext); | |
ReleaseDC(Handle(), _deviceContext); | |
} | |
void GLWindow::SetupCommon() | |
{ | |
observe(WM_CLOSE, [](WPARAM, LPARAM) {PostQuitMessage(0); }); | |
observe(WM_SIZE, [this](WPARAM wParam, LPARAM lParam) { | |
int width = LOWORD(lParam); | |
int height = HIWORD(lParam); | |
Resized(width, height); | |
}); | |
} | |
GLWindow::~GLWindow() | |
{ | |
wglDeleteContext(_glContext); | |
} | |
int GLWindow::Version() const | |
{ | |
const char* version = (char*)glGetString(GL_VERSION); | |
int version_max, version_min; | |
sscanf_s(version, "%d.%d", &version_max, &version_min); | |
return version_max; | |
} | |
void GLWindow::SetupContext(HDC hDC) { | |
PIXELFORMATDESCRIPTOR pfd; | |
ZeroMemory(&pfd, sizeof(PIXELFORMATDESCRIPTOR)); | |
pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR); | |
pfd.nSize = 1; | |
pfd.dwFlags = PFD_DRAW_TO_WINDOW | | |
PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; | |
pfd.iPixelType = PFD_TYPE_RGBA; | |
pfd.cColorBits = 32; | |
pfd.cDepthBits = 16; | |
pfd.iLayerType = PFD_MAIN_PLANE; | |
int format = ::ChoosePixelFormat(hDC, &pfd); | |
SetPixelFormat(hDC, format, &pfd); | |
} | |
BOOL GLWindow::MakeCurrent() | |
{ | |
return ::wglMakeCurrent(_deviceContext, _glContext); | |
} | |
void GLWindow::Resized(int width, int height) | |
{ | |
MakeCurrent(); | |
glViewport(0, 0, width, height); | |
} | |
void GLWindow::SwapBuffers() | |
{ | |
::SwapBuffers(_deviceContext); | |
} | |
void GLWindow::Init() | |
{ | |
} | |
void GLWindow::Shutdown() | |
{ | |
} | |
void GLWindow::Render() | |
{ | |
} | |
void GLWindow::Tick() | |
{ | |
ULONGLONG thisTick = GetTickCount64(); | |
TimeElapsed(thisTick - _lastTick); | |
_lastTick = thisTick; | |
} | |
void GLWindow::LoadDll() { | |
_gldll = LoadLibrary(TEXT("opengl32.dll")); | |
} | |
void GLWindow::UnloadDll() { | |
FreeLibrary(_gldll); | |
} | |
LPVOID GLWindow::LoadFunction(const char* name) { | |
LPVOID ret = wglGetProcAddress(name); | |
if (!ret) { | |
ret = GetProcAddress(_gldll, name); | |
} | |
return ret; | |
} | |
void GLWindow::LoadPrototypes() { | |
LoadDll(); | |
wglChoosePixelFormatARB = (PFNWGLCHOOSEPIXELFORMATARBPROC)LoadFunction("wglChoosePixelFormatARB"); | |
wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC)LoadFunction("wglCreateContextAttribsARB"); | |
glGetString = (PFNGLGETSTRINGPROC)LoadFunction("glGetString"); | |
glViewport = (PFNGLVIEWPORTPROC)LoadFunction("glViewport"); | |
glClearBufferfv = (PFNGLCLEARBUFFERFVPROC)LoadFunction("glClearBufferfv"); | |
glEnable = (PFNGLENABLEPROC)LoadFunction("glEnable"); | |
glDepthFunc = (PFNGLDEPTHFUNCPROC)LoadFunction("glDepthFunc"); | |
glGenBuffers = (PFNGLGENBUFFERSPROC)LoadFunction("glGenBuffers"); | |
glBindBuffer = (PFNGLBINDBUFFERPROC)LoadFunction("glBindBuffer"); | |
glBufferData = (PFNGLBUFFERDATAPROC)LoadFunction("glBufferData"); | |
glGenVertexArrays = (PFNGLGENVERTEXARRAYSPROC)LoadFunction("glGenVertexArrays"); | |
glBindVertexArray = (PFNGLBINDVERTEXARRAYPROC)LoadFunction("glBindVertexArray"); | |
glEnableVertexAttribArray = (PFNGLENABLEVERTEXATTRIBARRAYPROC)LoadFunction("glEnableVertexAttribArray"); | |
glVertexAttribPointer = (PFNGLVERTEXATTRIBPOINTERPROC)LoadFunction("glVertexAttribPointer"); | |
glCreateShader = (PFNGLCREATESHADERPROC)LoadFunction("glCreateShader"); | |
glShaderSource = (PFNGLSHADERSOURCEPROC)LoadFunction("glShaderSource"); | |
glCompileShader = (PFNGLCOMPILESHADERPROC)LoadFunction("glCompileShader"); | |
glCreateProgram = (PFNGLCREATEPROGRAMPROC)LoadFunction("glCreateProgram"); | |
glAttachShader = (PFNGLATTACHSHADERPROC)LoadFunction("glAttachShader"); | |
glLinkProgram = (PFNGLLINKPROGRAMPROC)LoadFunction("glLinkProgram"); | |
glClear = (PFNGLCLEARPROC)LoadFunction("glClear"); | |
glUseProgram = (PFNGLUSEPROGRAMPROC)LoadFunction("glUseProgram"); | |
glDrawArrays = (PFNGLDRAWARRAYSPROC)LoadFunction("glDrawArrays"); | |
UnloadDll(); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include "Window.h" | |
#include "GL\glcorearb.h" | |
#include "GL\glext.h" | |
#include "GL\wglext.h" | |
class GLWindow : | |
public Window | |
{ | |
private: | |
int _createdVersion; | |
HDC _deviceContext; | |
HGLRC _glContext; | |
ULONGLONG _lastTick; | |
HMODULE _gldll; | |
private: | |
void LoadDll(); | |
void UnloadDll(); | |
LPVOID LoadFunction(const char* name); | |
void SetupCommon(); | |
protected: | |
void SetupContext(HDC hDC); | |
int ChoosePixelFormat(const HDC hdc, const int multisamples, const bool stereo3D); | |
void LoadPrototypes(); | |
virtual void TimeElapsed(ULONGLONG elapsedTime) {} | |
void PrintShaderLog(GLuint shader) const; | |
void PrintShaderInfoLog(GLuint shader) const; | |
public: | |
GLWindow(); | |
GLWindow(const GLWindow* window); | |
virtual ~GLWindow(); | |
void Destroy(); | |
BOOL MakeCurrent(); | |
void Resized(int width, int height); | |
void Tick(); | |
virtual void Init(); | |
virtual void Shutdown(); | |
virtual void Render(); | |
void SwapBuffers(); | |
inline BOOL CanUpgrade() const { | |
return (Version() > _createdVersion); | |
} | |
UINT ClassStyle() { return Window::ClassStyle() | CS_OWNDC; } | |
LPCTSTR ClassName() { return TEXT("GLWindow"); } | |
int Version() const; | |
protected: | |
PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB; | |
PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB; | |
PFNGLGETSTRINGPROC glGetString; | |
PFNGLVIEWPORTPROC glViewport; | |
PFNGLCLEARBUFFERFVPROC glClearBufferfv; | |
PFNGLENABLEPROC glEnable; | |
PFNGLDEPTHFUNCPROC glDepthFunc; | |
PFNGLGENBUFFERSPROC glGenBuffers; | |
PFNGLBINDBUFFERPROC glBindBuffer; | |
PFNGLBUFFERDATAPROC glBufferData; | |
PFNGLGENVERTEXARRAYSPROC glGenVertexArrays; | |
PFNGLBINDVERTEXARRAYPROC glBindVertexArray; | |
PFNGLENABLEVERTEXATTRIBARRAYPROC glEnableVertexAttribArray; | |
PFNGLVERTEXATTRIBPOINTERPROC glVertexAttribPointer; | |
PFNGLCREATESHADERPROC glCreateShader; | |
PFNGLSHADERSOURCEPROC glShaderSource; | |
PFNGLCOMPILESHADERPROC glCompileShader; | |
PFNGLCREATEPROGRAMPROC glCreateProgram; | |
PFNGLATTACHSHADERPROC glAttachShader; | |
PFNGLLINKPROGRAMPROC glLinkProgram; | |
PFNGLCLEARPROC glClear; | |
PFNGLUSEPROGRAMPROC glUseProgram; | |
PFNGLDRAWARRAYSPROC glDrawArrays; | |
}; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include <map> | |
#include <functional> | |
template <typename MSG, typename ... ARGS> | |
class Observable { | |
private: | |
std::map<MSG, std::function<void(ARGS...)>> callbacks; | |
public: | |
void observe(MSG msg, std::function<void(ARGS...)> callback) { | |
callbacks[msg] = callback; | |
} | |
void invoke(MSG msg, ARGS... args) { | |
if (callbacks.find(msg) != callbacks.end()) { | |
callbacks[msg](std::forward<ARGS>(args)...); | |
} | |
} | |
}; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "Window.h" | |
LRESULT CALLBACK Window::WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) | |
{ | |
Window* window = nullptr; | |
if (msg == WM_CREATE) { | |
LPCREATESTRUCT lpCreateStruct = (LPCREATESTRUCT)lParam; | |
window = (Window*)lpCreateStruct->lpCreateParams; | |
window->_window = hWnd; | |
SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG)window); | |
} | |
else { | |
window = (Window*)GetWindowLongPtr(hWnd, GWLP_USERDATA); | |
} | |
if (window) { | |
window->invoke(msg, wParam, lParam); | |
} | |
return DefWindowProc(hWnd, msg, wParam, lParam); | |
} | |
Window::Window() | |
: _window(nullptr) | |
{ | |
} | |
Window::~Window() | |
{ | |
Close(); | |
Destroy(); | |
} | |
ATOM Window::Register() | |
{ | |
WNDCLASSEX wcx; | |
::ZeroMemory(&wcx, sizeof(WNDCLASSEX)); | |
wcx.cbSize = sizeof(WNDCLASSEX); | |
wcx.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); | |
wcx.hCursor = LoadCursor(nullptr, IDC_ARROW); | |
wcx.hIcon = LoadIcon(nullptr, IDI_APPLICATION); | |
wcx.hIconSm = wcx.hIcon; | |
wcx.hInstance = GetModuleHandle(nullptr); | |
wcx.lpfnWndProc = WndProc; | |
wcx.lpszClassName = ClassName(); | |
wcx.lpszMenuName = nullptr; | |
wcx.style = ClassStyle(); | |
return RegisterClassEx(&wcx); | |
} | |
void Window::Create() | |
{ | |
CreateWindow(ClassName(), WindowName(), WindowStyle(), | |
CW_USEDEFAULT, CW_USEDEFAULT, | |
CW_USEDEFAULT, CW_USEDEFAULT, | |
nullptr, nullptr, GetModuleHandle(nullptr), this); | |
observe(WM_CLOSE, [](WPARAM, LPARAM) {PostQuitMessage(0); }); | |
} | |
void Window::Update() | |
{ | |
UpdateWindow(_window); | |
} | |
void Window::ShowWindow(int nCmdShow) | |
{ | |
::ShowWindow(_window, nCmdShow); | |
} | |
void Window::Close() | |
{ | |
if (_window) { | |
CloseWindow(_window); | |
} | |
} | |
void Window::Destroy() | |
{ | |
if (_window) { | |
DestroyWindow(_window); | |
_window = nullptr; | |
} | |
} | |
SIZE Window::Size() const | |
{ | |
RECT rect; | |
SIZE size = { 0, 0 }; | |
if (GetWindowRect(_window, &rect)) { | |
size.cx = rect.right - rect.left; | |
size.cy = rect.bottom - rect.top; | |
} | |
return size; | |
} | |
void Window::ShowLastError() const | |
{ | |
DWORD err = GetLastError(); | |
// Translate ErrorCode to String. | |
LPTSTR error = nullptr; | |
if (::FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, | |
nullptr, | |
err, | |
0, (LPTSTR)&error, | |
0, | |
nullptr) == 0) | |
{ | |
// Failed in translating. | |
} | |
// Display message. | |
MessageBox(nullptr, error, TEXT("Error"), MB_OK | MB_ICONWARNING); | |
// Free the buffer. | |
if (error) | |
{ | |
::LocalFree(error); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include <Windows.h> | |
#include "Observable.h" | |
class Window : | |
public Observable <UINT, WPARAM, LPARAM> | |
{ | |
private: | |
HWND _window; | |
private: | |
static LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); | |
protected: | |
inline HWND Handle() const { return _window; } | |
void ShowLastError() const; | |
public: | |
Window(); | |
virtual ~Window(); | |
ATOM Register(); | |
void Create(); | |
void Update(); | |
void ShowWindow(int nCmdShow); | |
void Close(); | |
virtual void Destroy(); | |
SIZE Size() const; | |
virtual LPCTSTR ClassName() { return TEXT("BasicWindow"); } | |
virtual LPCTSTR WindowName() { return ClassName(); } | |
virtual UINT ClassStyle() { return CS_HREDRAW | CS_VREDRAW; } | |
virtual UINT WindowStyle() { return WS_OVERLAPPEDWINDOW; } | |
}; | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment