Skip to content

Instantly share code, notes, and snippets.

@Eleobert
Last active August 1, 2024 14:52
Show Gist options
  • Save Eleobert/d4bbf044db7cb5a587666cff5a6f1174 to your computer and use it in GitHub Desktop.
Save Eleobert/d4bbf044db7cb5a587666cff5a6f1174 to your computer and use it in GitHub Desktop.
OpenGL context creation on win32 (without any extensions)
#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);
}
@hidegi
Copy link

hidegi commented Mar 7, 2022

epic, finally someone who shows the skeleton of ogl-context creation..

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment