Last active
August 1, 2024 14:52
-
-
Save Eleobert/d4bbf044db7cb5a587666cff5a6f1174 to your computer and use it in GitHub Desktop.
OpenGL context creation on win32 (without any extensions)
This file contains 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 <Windows.h> | |
#include <GL\GL.h> | |
#include <glext.h> | |
#include <wglext.h> | |
#include <iostream> | |
#pragma comment(lib, "opengl32.lib") | |
#define LOAD_GL_FUNC(x, p) x = reinterpret_cast<p>(wglGetProcAddress(#x)); \ | |
if (x == nullptr) { MessageBox(NULL, #x, "Error Loading OpenGL function", MB_OK); return 0;} | |
const char *vertexShaderSource = "#version 330 core\n" | |
"layout (location = 0) in vec3 pos;\n" | |
"void main()\n" | |
"{\n" | |
" gl_Position = vec4(pos.x, pos.y, pos.z, 1.0);\n" | |
"}\0"; | |
const char *fragmentShaderSource = "#version 330 core\n" | |
"out vec4 FragColor;\n" | |
"void main()\n" | |
"{\n" | |
" FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n" | |
"}\n\0"; | |
int vertexShader, fragmentShader; | |
int shaderProgram; | |
unsigned int VBO, VAO; | |
float vertices[] = { | |
-0.5f, -0.5f, 0.0f, // left | |
0.5f, -0.5f, 0.0f, // right | |
0.0f, 0.5f, 0.0f // top | |
}; | |
PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB; | |
PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB; | |
PFNGLCREATEPROGRAMPROC glCreateProgram; | |
PFNGLDELETEPROGRAMPROC glDeleteProgram; | |
PFNGLUSEPROGRAMPROC glUseProgram; | |
PFNGLATTACHSHADERPROC glAttachShader; | |
PFNGLDETACHSHADERPROC glDetachShader; | |
PFNGLLINKPROGRAMPROC glLinkProgram; | |
PFNGLENABLEVERTEXATTRIBARRAYPROC glEnableVertexAttribArray; | |
PFNGLCREATESHADERPROC glCreateShader; | |
PFNGLDELETESHADERPROC glDeleteShader; | |
PFNGLSHADERSOURCEPROC glShaderSource; | |
PFNGLCOMPILESHADERPROC glCompileShader; | |
PFNGLGENBUFFERSPROC glGenBuffers; | |
PFNGLBINDBUFFERPROC glBindBuffer; | |
PFNGLBUFFERDATAPROC glBufferData; | |
PFNGLVERTEXATTRIBPOINTERPROC glVertexAttribPointer; | |
PFNGLDELETEBUFFERSPROC glDeleteBuffers; | |
PFNGLGENVERTEXARRAYSPROC glGenVertexArrays; | |
PFNGLBINDVERTEXARRAYPROC glBindVertexArray; | |
PFNGLDELETEVERTEXARRAYSPROC glDeleteVertexArrays; | |
LRESULT CALLBACK WindowProcedure(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); | |
HWND createWindow(HINSTANCE hInstance, HWND& WND, HDC& DC, HGLRC& RC); | |
int loadOpenGLFunctions(); | |
void createShadersAndBuffers(); | |
int main() | |
{ | |
HDC DC = NULL; | |
HGLRC RC = NULL; | |
HWND hWnd = NULL; | |
createWindow(0, hWnd, DC, RC); | |
if (hWnd == nullptr) | |
exit(-1); | |
SetWindowText(hWnd, (LPCSTR)glGetString(GL_VERSION)); | |
ShowWindow(hWnd, 1); | |
createShadersAndBuffers(); | |
MSG msg; | |
bool active = true; | |
while (active) { | |
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { | |
if (msg.message == WM_QUIT) { | |
active = false; | |
} | |
TranslateMessage(&msg); | |
DispatchMessage(&msg); | |
} | |
glClearColor(0.129f, 0.586f, 0.949f, 1.0f); | |
glClear(GL_COLOR_BUFFER_BIT); | |
glUseProgram(shaderProgram); | |
glBindVertexArray(VAO); | |
glDrawArrays(GL_TRIANGLES, 0, 3); | |
SwapBuffers(DC); | |
} | |
wglMakeCurrent(NULL, NULL); | |
wglDeleteContext(RC); | |
ReleaseDC(hWnd, DC); | |
DestroyWindow(hWnd); | |
} | |
HWND createWindow(HINSTANCE hInstance, HWND& WND, HDC& DC, HGLRC& RC) { | |
//-----register window class | |
WNDCLASSEX wcex; | |
ZeroMemory(&wcex, sizeof(wcex)); | |
wcex.cbSize = sizeof(wcex); | |
wcex.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; | |
wcex.lpfnWndProc = WindowProcedure; | |
wcex.hInstance = hInstance; | |
wcex.hCursor = LoadCursor(NULL, IDC_ARROW); | |
wcex.lpszClassName = "window"; | |
if (!RegisterClassEx(&wcex)) { | |
MessageBox(NULL, "Cannot register window class.", "Error", MB_OK); | |
return nullptr; | |
} | |
//-----create fake window | |
HWND fakeWND = CreateWindow("window", "Fake Window", | |
WS_CLIPSIBLINGS | WS_CLIPCHILDREN, | |
0, 0, 1, 1, NULL, NULL, hInstance, NULL); | |
if (fakeWND == NULL) { | |
MessageBox(NULL, "Error creating the fake window.", | |
"Error", MB_OK); | |
return nullptr; | |
} | |
//---create fake contex | |
HDC fakeDC = GetDC(fakeWND); | |
PIXELFORMATDESCRIPTOR fakePFD; | |
ZeroMemory(&fakePFD, sizeof(fakePFD)); | |
fakePFD.nSize = sizeof(fakePFD); | |
fakePFD.nVersion = 1; | |
fakePFD.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; | |
fakePFD.iPixelType = PFD_TYPE_RGBA; | |
fakePFD.cColorBits = 32; | |
fakePFD.cAlphaBits = 8; | |
fakePFD.cDepthBits = 24; | |
int fakePFDID = ChoosePixelFormat(fakeDC, &fakePFD); | |
if (fakePFDID == 0) { | |
MessageBox(NULL, "Could not choose pixel format.", | |
"Error", MB_OK); | |
return nullptr; | |
} | |
if (SetPixelFormat(fakeDC, fakePFDID, &fakePFD) == false) { | |
MessageBox(NULL, "Could not set pixel format.", | |
"Error", MB_OK); | |
return nullptr; | |
} | |
HGLRC fakeRC = wglCreateContext(fakeDC); // Rendering Contex | |
if (fakeRC == 0) { | |
MessageBox(NULL, "Could not create fake context.", | |
"Error", MB_OK); | |
return nullptr; | |
} | |
if (wglMakeCurrent(fakeDC, fakeRC) == false) { | |
MessageBox(NULL, "Could not make fake context current.", | |
"Error", MB_OK); | |
return nullptr; | |
} | |
//---create real context | |
loadOpenGLFunctions(); | |
WND = CreateWindow( | |
"window", "OpenGL Window", | |
WS_CAPTION | WS_SYSMENU | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, | |
100, 100, | |
800, 600, | |
NULL, NULL, | |
hInstance, NULL); | |
DC = GetDC(WND); | |
const int pixelAttribs[] = { | |
WGL_DRAW_TO_WINDOW_ARB, GL_TRUE, | |
WGL_SUPPORT_OPENGL_ARB, GL_TRUE, | |
WGL_DOUBLE_BUFFER_ARB, GL_TRUE, | |
WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB, | |
WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB, | |
WGL_COLOR_BITS_ARB, 32, | |
WGL_ALPHA_BITS_ARB, 8, | |
WGL_DEPTH_BITS_ARB, 24, | |
WGL_STENCIL_BITS_ARB, 8, | |
WGL_SAMPLE_BUFFERS_ARB, GL_TRUE, | |
WGL_SAMPLES_ARB, 4, | |
0 | |
}; | |
int pixelFormatID; UINT numFormats; | |
bool status = wglChoosePixelFormatARB(DC, pixelAttribs, NULL, 1, &pixelFormatID, &numFormats); | |
if (status == false || numFormats == 0) { | |
MessageBox(NULL, "Could not choose pixel format.", | |
"Error", MB_OK); | |
return 0; | |
} | |
PIXELFORMATDESCRIPTOR PFD; | |
DescribePixelFormat(DC, pixelFormatID, sizeof(PFD), &PFD); | |
SetPixelFormat(DC, pixelFormatID, &PFD); | |
int contextAttribs[] = { | |
WGL_CONTEXT_MAJOR_VERSION_ARB, 3, | |
WGL_CONTEXT_MINOR_VERSION_ARB, 3, | |
WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB, | |
0 | |
}; | |
RC = wglCreateContextAttribsARB(DC, 0, contextAttribs); | |
if (RC == NULL) { | |
MessageBox(NULL, "Could not create opengl context.", | |
"Error", MB_OK); | |
return nullptr; | |
} | |
wglMakeCurrent(NULL, NULL); | |
wglDeleteContext(fakeRC); | |
ReleaseDC(fakeWND, fakeDC); | |
DestroyWindow(fakeWND); | |
if (!wglMakeCurrent(DC, RC)) { | |
MessageBox(NULL, "Could not make opengl context current.", | |
"Error", MB_OK); | |
return nullptr; | |
} | |
return WND; | |
} | |
LRESULT CALLBACK WindowProcedure(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { | |
switch (message) { | |
case WM_KEYDOWN: | |
if (wParam == VK_ESCAPE) { | |
PostQuitMessage(0); | |
} | |
break; | |
case WM_CLOSE: | |
PostQuitMessage(0); | |
break; | |
default: | |
return DefWindowProc(hWnd, message, wParam, lParam); | |
} | |
return 0; | |
} | |
int loadOpenGLFunctions() { | |
LOAD_GL_FUNC(wglChoosePixelFormatARB, PFNWGLCHOOSEPIXELFORMATARBPROC); | |
LOAD_GL_FUNC(wglCreateContextAttribsARB,PFNWGLCREATECONTEXTATTRIBSARBPROC); | |
LOAD_GL_FUNC(glCreateProgram, PFNGLCREATEPROGRAMPROC); | |
LOAD_GL_FUNC(glDeleteProgram, PFNGLDELETEPROGRAMPROC); | |
LOAD_GL_FUNC(glUseProgram, PFNGLUSEPROGRAMPROC); | |
LOAD_GL_FUNC(glAttachShader, PFNGLATTACHSHADERPROC); | |
LOAD_GL_FUNC(glLinkProgram, PFNGLLINKPROGRAMPROC); | |
LOAD_GL_FUNC(glEnableVertexAttribArray, PFNGLENABLEVERTEXATTRIBARRAYPROC); | |
LOAD_GL_FUNC(glCreateShader, PFNGLCREATESHADERPROC); | |
LOAD_GL_FUNC(glDeleteShader, PFNGLDELETESHADERPROC); | |
LOAD_GL_FUNC(glShaderSource, PFNGLSHADERSOURCEPROC); | |
LOAD_GL_FUNC(glCompileShader, PFNGLCOMPILESHADERPROC); | |
LOAD_GL_FUNC(glGenBuffers, PFNGLGENBUFFERSPROC); | |
LOAD_GL_FUNC(glBindBuffer, PFNGLBINDBUFFERPROC); | |
LOAD_GL_FUNC(glBufferData, PFNGLBUFFERDATAPROC); | |
LOAD_GL_FUNC(glVertexAttribPointer, PFNGLVERTEXATTRIBPOINTERPROC); | |
LOAD_GL_FUNC(glDeleteBuffers, PFNGLDELETEBUFFERSPROC); | |
LOAD_GL_FUNC(glGenVertexArrays, PFNGLGENVERTEXARRAYSPROC); | |
LOAD_GL_FUNC(glBindVertexArray, PFNGLBINDVERTEXARRAYPROC); | |
LOAD_GL_FUNC(glDeleteVertexArrays, PFNGLDELETEVERTEXARRAYSPROC); | |
return 1; | |
} | |
void createShadersAndBuffers() { | |
//vertext shader | |
vertexShader = glCreateShader(GL_VERTEX_SHADER); | |
glShaderSource(vertexShader, 1, &vertexShaderSource, NULL); | |
glCompileShader(vertexShader); | |
// fragment shader | |
fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); | |
glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL); | |
glCompileShader(fragmentShader); | |
//link shaders | |
shaderProgram = glCreateProgram(); | |
glAttachShader(shaderProgram, vertexShader); | |
glAttachShader(shaderProgram, fragmentShader); | |
glLinkProgram(shaderProgram); | |
glDeleteShader(vertexShader); | |
glDeleteShader(fragmentShader); | |
//-------------------------------------------------- | |
glGenVertexArrays(1, &VAO); | |
glGenBuffers(1, &VBO); | |
glBindVertexArray(VAO); | |
glBindBuffer(GL_ARRAY_BUFFER, VBO); | |
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); | |
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0); | |
glEnableVertexAttribArray(0); | |
glBindBuffer(GL_ARRAY_BUFFER, 0); | |
glBindVertexArray(0); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
epic, finally someone who shows the skeleton of ogl-context creation..