diff --git a/Makefile b/Makefile index fdf76ed..dd31f3e 100644 --- a/Makefile +++ b/Makefile @@ -1,13 +1,29 @@ -FLAGS=-fPIC --shared -LIBS=-lX11 -lGL -FILES=src/openwindow.c deps/lib/glad.a +FLAGS=-fPIC --shared -libopenwindow.so: glad.a - gcc ${FLAGS} -o libopenwindow.so ${FILES} +LINUX_FILES=src/openwindow.c deps/lib/glad_linux.a + +WINDOWS_LIBS=-lopengl32 -lgdi32 +WINDOWS_FILES=src/openwindow.c deps/lib/glad_windows.a + +OUTPUT=lib/ + +all: libopenwindow.so libopenwindow.dll + +libopenwindow.so: glad_linux.a + mkdir -p ${OUTPUT} + gcc ${FLAGS} -o ${OUTPUT}libopenwindow.so ${LINUX_FILES} + +libopenwindow.dll: glad_windows.a + mkdir -p ${OUTPUT} + x86_64-w64-mingw32-gcc ${FLAGS} -o ${OUTPUT}libopenwindow.dll ${WINDOWS_FILES} ${WINDOWS_LIBS} GLAD_FLAGS=-fPIC -c GLAD_FILES=deps/src/glad.c -glad.a: deps/src/glad.o - gcc ${GLAD_FLAGS} -o deps/src/glad.o ${GLAD_FILES} - ar rcs deps/lib/glad.a deps/src/glad.o +glad_linux.a: deps/src/glad.c + gcc ${GLAD_FLAGS} -o deps/src/glad_linux.o ${GLAD_FILES} + ar rcs deps/lib/glad_linux.a deps/src/glad_linux.o + +glad_windows.a: deps/src/glad.c + x86_64-w64-mingw32-gcc ${GLAD_FLAGS} -o deps/src/glad_windows.o ${GLAD_FILES} + ar rcs deps/lib/glad_windows.a deps/src/glad_windows.o diff --git a/main.c b/main.c index b76cade..bf06544 100644 --- a/main.c +++ b/main.c @@ -1,6 +1,9 @@ #include #include +#include "deps/include/glad/glad.h" +#include "src/openwindow.h" + #ifndef _WIN32 #include @@ -9,8 +12,6 @@ #include #undef Window -#include "src/openwindow.h" - void xevent(Window * w, XEvent xev) { switch (xev.type) { @@ -37,6 +38,10 @@ void xevent(Window * w, XEvent xev) { } } +#else + +#include + #endif // _WIN32 const char * fss = @@ -52,22 +57,25 @@ int main(void) { Window w = openWindow("Window", 800, 600); + // TODO: do this +#ifndef _WIN32 windowSetEventHandler(&w, xevent); +#endif // _WIN32 - while (!w.close) { + while (!w.close) + { windowHandleEvents(&w); - glClearColor(1, 1, 1, 1); + glClearColor(0.1f, 0.2f, 0.3f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); + glViewport(0, 0, 800, 600); + + glColor3f(1.0, 0, 0); glBegin(GL_TRIANGLES); - glColor3f(1.0f, 0.0f, 0.0f); glVertex2f(-0.5, -0.5); - glColor3f(0.0f, 1.0f, 0.0f); glVertex2f(0.5, -0.5); - glColor3f(0.0f, 0.0f, 1.0f); glVertex2f(0.0, 0.5); glEnd(); - glFlush(); windowDraw(w); } diff --git a/other/deltatime.c b/other/deltatime.c new file mode 100644 index 0000000..0f2548f --- /dev/null +++ b/other/deltatime.c @@ -0,0 +1,13 @@ +#include "deltatime.h" + +struct timespec deltaTimeX1, deltaTimeX2; + +#include + +double getDeltaTime() { + clock_gettime(CLOCK_MONOTONIC, &deltaTimeX2); + double dt = (deltaTimeX2.tv_sec - deltaTimeX1.tv_sec) + (deltaTimeX2.tv_nsec - deltaTimeX1.tv_nsec) / 1e9; + deltaTimeX1 = deltaTimeX2; + + return dt; +} diff --git a/other/deltatime.h b/other/deltatime.h new file mode 100644 index 0000000..eac8bc7 --- /dev/null +++ b/other/deltatime.h @@ -0,0 +1,8 @@ +#ifndef DELTA_TIME_H_ +#define DELTA_TIME_H_ + +extern struct timespec deltaTimeX1, deltaTimeX2; + +double getDeltaTime(); + +#endif // DELTA_TIME_H_ diff --git a/other/graphics.c b/other/graphics.c new file mode 100644 index 0000000..9a29f9a --- /dev/null +++ b/other/graphics.c @@ -0,0 +1,87 @@ +#include +#include + +#include "graphics.h" + +#include "../deps/include/glad/glad.h" + +const char * defaultVertexShader = +"#version 330 core\n" +"precision mediump float;" +"void main()\n" +"{\n" +"}"; + +const char * defaultFragmentShader = +"#version 330 core\n" +"precision mediump float;" +"out vec4 FragColor;\n" +"void main()\n" +"{\n" +" FragColor = vec4(1.0f, 1.0f, 1.0f, 1.0f);\n" +"}"; + +void compileShader(GLuint program, const char * source, GLenum type) { + GLint status = 0; + + GLuint shader = glCreateShader(type); + + glShaderSource(shader, 1, &source, NULL); + glCompileShader(shader); + glGetShaderiv(shader, GL_COMPILE_STATUS, &status); + + if (status != GL_TRUE) { + fprintf(stderr, "Failed to compile %s shader!\n", type == GL_VERTEX_SHADER ? "vertex" : "fragment"); + + GLint len; + glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &len); + char * infolog = (char*) malloc(len * sizeof(char)); + glGetShaderInfoLog(shader, len, NULL, infolog); + fprintf(stderr, "Shader compilation error: %s\n", infolog); + free(infolog); + + exit(1); + } + + glAttachShader(program, shader); +} + +void linkProgram(GLuint program) { + int status = 0; + + glLinkProgram(program); + + glGetProgramiv(program, GL_LINK_STATUS, &status); + if (status != GL_TRUE) { + fprintf(stderr, "Failed to link program!\n"); + + GLint len; + glGetProgramiv(program, GL_INFO_LOG_LENGTH, &len); + char * infolog = (char*) malloc(len * sizeof(char)); + glGetProgramInfoLog(program, len, NULL, infolog); + fprintf(stderr, "Program linking error: %s", infolog); + free(infolog); + + exit(1); + } +} + +Graphics createGraphics(const char * vss, const char * fss) { + GLuint program = glCreateProgram(); + + if (vss == NULL) vss = defaultVertexShader; + if (fss == NULL) fss = defaultFragmentShader; + + compileShader(program, vss, GL_VERTEX_SHADER); + compileShader(program, fss, GL_FRAGMENT_SHADER); + + linkProgram(program); + + GLuint vao; + glGenVertexArrays(1, &vao); + + return (Graphics) { + .program = program, + .vao = vao, + }; +} diff --git a/other/graphics.h b/other/graphics.h new file mode 100644 index 0000000..db10109 --- /dev/null +++ b/other/graphics.h @@ -0,0 +1,15 @@ +#ifndef GRAPHICS_H_ +#define GRAPHICS_H_ + +#include "../deps/include/glad/glad.h" + +extern const char * defaultVertexShader, * defaultFragmentShader; + +typedef struct { + GLuint program; + GLuint vao; +} Graphics; + +Graphics createGraphics(const char * vss, const char * fss); + +#endif // GRAPHICS_H_ diff --git a/sample/lis.c b/sample/lis.c new file mode 100644 index 0000000..553005b --- /dev/null +++ b/sample/lis.c @@ -0,0 +1,82 @@ +#include +#include "../deps/include/glad/glad.h" +#include + +LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); + +HGLRC CreateOpenGLContext(HWND hwnd, HDC hdc) { + PIXELFORMATDESCRIPTOR pfd = { + sizeof(PIXELFORMATDESCRIPTOR), + 1, + PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER, + PFD_TYPE_RGBA, + 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 8, 0, + PFD_MAIN_PLANE, 0, 0, 0, 0 + }; + + int pf = ChoosePixelFormat(hdc, &pfd); + SetPixelFormat(hdc, pf, &pfd); + return wglCreateContext(hdc); +} + +int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { + const char CLASS_NAME[] = "WGLSampleWindow"; + + WNDCLASS wc = {0}; + wc.lpfnWndProc = WindowProc; + wc.hInstance = hInstance; + wc.lpszClassName = CLASS_NAME; + RegisterClass(&wc); + + HWND hwnd = CreateWindowEx(0, CLASS_NAME, "OpenGL with WGL and GLAD", WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT, CW_USEDEFAULT, 800, 600, NULL, NULL, hInstance, NULL); + + if (!hwnd) return -1; + + HDC hdc = GetDC(hwnd); + HGLRC hglrc = CreateOpenGLContext(hwnd, hdc); + wglMakeCurrent(hdc, hglrc); + + // Load OpenGL functions using GLAD + if (!gladLoadGL()) { + MessageBoxA(NULL, "Failed to initialize GLAD", "Error", MB_OK | MB_ICONERROR); + return -1; + } + + ShowWindow(hwnd, nCmdShow); + + // Main loop + MSG msg; + while (1) { + while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { + if (msg.message == WM_QUIT) goto cleanup; + TranslateMessage(&msg); + DispatchMessage(&msg); + } + + // OpenGL rendering + glClearColor(0.1f, 0.2f, 0.3f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT); + + SwapBuffers(hdc); + } + +cleanup: + wglMakeCurrent(NULL, NULL); + wglDeleteContext(hglrc); + ReleaseDC(hwnd, hdc); + DestroyWindow(hwnd); + return 0; +} + +LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { + switch (uMsg) { + case WM_CLOSE: + PostQuitMessage(0); + return 0; + case WM_DESTROY: + return 0; + default: + return DefWindowProc(hwnd, uMsg, wParam, lParam); + } +} diff --git a/sample/lis.exe b/sample/lis.exe new file mode 100755 index 0000000..4457215 Binary files /dev/null and b/sample/lis.exe differ diff --git a/sample/test.c b/sample/test.c new file mode 100644 index 0000000..776f48c --- /dev/null +++ b/sample/test.c @@ -0,0 +1,106 @@ +#include +#include "../deps/include/glad/glad.h" + +LRESULT CALLBACK wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { + switch (msg) { + case WM_CLOSE: + PostQuitMessage(0); + break; + default: + return DefWindowProc(hwnd, msg, wParam, lParam); + } + return 0; +} + +int main() { + WNDCLASSEX wcex = {0}; + wcex.cbSize = sizeof(WNDCLASSEX); + wcex.style = CS_CLASSDC; + wcex.lpfnWndProc = wndProc; + wcex.cbClsExtra = 0; + wcex.cbWndExtra = 0; + wcex.hInstance = GetModuleHandle(NULL); + wcex.hIcon = NULL; + wcex.hCursor = LoadCursor(NULL, IDC_ARROW); + wcex.hbrBackground = 0; + wcex.lpszMenuName = NULL; + wcex.lpszClassName = "OpenGL"; + wcex.hIconSm = NULL; + + if (!RegisterClassEx(&wcex)) { + MessageBox(NULL, "Failed to register window class", "Error", MB_ICONERROR); + return -1; + } + + HWND hwnd = CreateWindow("OpenGL", "OpenGL", WS_OVERLAPPEDWINDOW | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 800, 600, NULL, NULL, GetModuleHandle(NULL), NULL); + + if (hwnd == NULL) { + MessageBox(NULL, "Failed to create window", "Error", MB_ICONERROR); + return -1; + } + + HDC hdc = GetDC(hwnd); + if (hdc == NULL) { + MessageBox(NULL, "Failed to get device context", "Error", MB_ICONERROR); + return -1; + } + + PIXELFORMATDESCRIPTOR pfd = {0}; + pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR); + pfd.nVersion = 1; + pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; + pfd.iPixelType = PFD_TYPE_RGBA; + pfd.cColorBits = 32; + pfd.cDepthBits = 24; + pfd.cStencilBits = 8; + + int format = ChoosePixelFormat(hdc, &pfd); + if (format == 0) { + MessageBox(NULL, "Failed to choose pixel format", "Error", MB_ICONERROR); + return -1; + } + + if (!SetPixelFormat(hdc, format, &pfd)) { + MessageBox(NULL, "Failed to set pixel format", "Error", MB_ICONERROR); + return -1; + } + + HGLRC hrc = wglCreateContext(hdc); + if (hrc == NULL) { + MessageBox(NULL, "Failed to create OpenGL context", "Error", MB_ICONERROR); + return -1; + } + + if (!wglMakeCurrent(hdc, hrc)) { + MessageBox(NULL, "Failed to make OpenGL context current", "Error", MB_ICONERROR); + return -1; + } + + if (!gladLoadGLLoader((GLADloadproc)wglGetProcAddress)) { + MessageBox(NULL, "Failed to load OpenGL functions", "Error", MB_ICONERROR); + return -1; + } + + MSG msg; + while (1) { + if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + if (msg.message == WM_QUIT) { + break; + } + } else { + glClear(GL_COLOR_BUFFER_BIT); + glClearColor(1.0f, 0.0f, 0.0f, 1.0f); + SwapBuffers(hdc); + } + } + + wglDeleteContext(hrc); + ReleaseDC(hwnd, hdc); + DestroyWindow(hwnd); + UnregisterClass("OpenGL", GetModuleHandle(NULL)); + + return 0; +} + diff --git a/sample/test.exe b/sample/test.exe new file mode 100755 index 0000000..aaed9e7 Binary files /dev/null and b/sample/test.exe differ diff --git a/sample/w.c b/sample/w.c new file mode 100644 index 0000000..4c4e22a --- /dev/null +++ b/sample/w.c @@ -0,0 +1,107 @@ +#include +#include +#include "../deps/include/glad/glad.h" + +LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch (message) + { + case WM_CLOSE: + PostQuitMessage(0); + break; + case WM_LBUTTONDOWN: + printf("AAA\n"); + break; + default: + return DefWindowProc(hWnd, message, wParam, lParam); + } + return 0; +} + +int main() +{ + // Register the window class + WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, WndProc, 0L, 0L, GetModuleHandle(NULL), NULL, NULL, NULL, NULL, "GLSample", NULL }; + RegisterClassEx(&wc); + + // Create the window + HWND hWnd = CreateWindowEx( + 0, + "GLSample", + "OpenGL Sample", + WS_OVERLAPPEDWINDOW | WS_VISIBLE, + CW_USEDEFAULT, + CW_USEDEFAULT, + 256, + 256, + NULL, + NULL, + GetModuleHandle(NULL), + NULL + ); + + // Enable OpenGL + HDC hDC = GetDC(hWnd); + PIXELFORMATDESCRIPTOR pfd = { + sizeof(PIXELFORMATDESCRIPTOR), + 1, + PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER, + PFD_TYPE_RGBA, + 32, + 0, 0, 0, 0, 0, 0, + 0, + 0, + 0, + 0, 0, 0, 0, + 16, + 0, + 0, + PFD_MAIN_PLANE, + 0, + 0, 0, 0 + }; + + int iFormat = ChoosePixelFormat(hDC, &pfd); + SetPixelFormat(hDC, iFormat, &pfd); + + // Create the OpenGL context + HGLRC hRC = wglCreateContext(hDC); + wglMakeCurrent(hDC, hRC); + + gladLoadGLLoader((GLADloadproc)wglGetProcAddress); + + // Main loop + MSG msg; + while (GetMessage(&msg, NULL, 0, 0)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + + // Clear the screen + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT); + + // Draw a triangle + glBegin(GL_TRIANGLES); + glColor3f(1.0f, 0.0f, 0.0f); + glVertex2f(-0.5f, -0.5f); + glColor3f(0.0f, 1.0f, 0.0f); + glVertex2f(0.5f, -0.5f); + glColor3f(0.0f, 0.0f, 1.0f); + glVertex2f(0.0f, 0.5f); + glEnd(); + + // Swap buffers + SwapBuffers(hDC); + } + + // Disable OpenGL + wglMakeCurrent(NULL, NULL); + wglDeleteContext(hRC); + ReleaseDC(hWnd, hDC); + + // Clean up + UnregisterClass("GLSample", GetModuleHandle(NULL)); + return msg.wParam; +} + diff --git a/sample/w.exe b/sample/w.exe new file mode 100755 index 0000000..0c9fd78 Binary files /dev/null and b/sample/w.exe differ diff --git a/sample/win.c b/sample/win.c new file mode 100644 index 0000000..a026a49 --- /dev/null +++ b/sample/win.c @@ -0,0 +1,152 @@ +#include +#include + +// Global variables +HINSTANCE hInstance; +HWND hWnd; +HDC hDC; +HGLRC hRC; + +// Forward declarations +LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); +void EnableOpenGL(HWND, HDC*, HGLRC*); +void DisableOpenGL(HWND, HDC, HGLRC); + +int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) +{ + // Register the window class + WNDCLASSEX wc = { + sizeof(WNDCLASSEX), + CS_CLASSDC, + WndProc, + 0L, + 0L, + hInst, + NULL, + NULL, + NULL, + NULL, + "GLSample", + NULL + }; + RegisterClassEx(&wc); + + // Create the window + hWnd = CreateWindowEx( + 0, + "GLSample", + "OpenGL Sample", + WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT, + CW_USEDEFAULT, + 256, + 256, + NULL, + NULL, + hInst, + NULL + ); + + // Enable OpenGL + EnableOpenGL(hWnd, &hDC, &hRC); + + // Show the window + ShowWindow(hWnd, nCmdShow); + UpdateWindow(hWnd); + + // Main loop + MSG msg; + while (GetMessage(&msg, NULL, 0, 0)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + + // Disable OpenGL + DisableOpenGL(hWnd, hDC, hRC); + + // Clean up + UnregisterClass("GLSample", hInstance); + return msg.wParam; +} + +LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch (message) + { + case WM_CLOSE: + PostQuitMessage(0); + break; + case WM_SIZE: + glViewport(0, 0, LOWORD(lParam), HIWORD(lParam)); + break; + case WM_PAINT: + { + PAINTSTRUCT ps; + BeginPaint(hWnd, &ps); + + // Clear the screen + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT); + + // Draw a triangle + glBegin(GL_TRIANGLES); + glColor3f(1.0f, 0.0f, 0.0f); + glVertex2f(-0.5f, -0.5f); + glColor3f(0.0f, 1.0f, 0.0f); + glVertex2f(0.5f, -0.5f); + glColor3f(0.0f, 0.0f, 1.0f); + glVertex2f(0.0f, 0.5f); + glEnd(); + + // Swap buffers + SwapBuffers(hDC); + + EndPaint(hWnd, &ps); + } + break; + default: + return DefWindowProc(hWnd, message, wParam, lParam); + } + return 0; +} + +void EnableOpenGL(HWND hWnd, HDC* hDC, HGLRC* hRC) +{ + *hDC = GetDC(hWnd); + + // Set the pixel format + PIXELFORMATDESCRIPTOR pfd = { + sizeof(PIXELFORMATDESCRIPTOR), + 1, + PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER, + PFD_TYPE_RGBA, + 32, + 0, 0, 0, 0, 0, 0, + 0, + 0, + 0, + 0, 0, 0, 0, + 16, + 0, + 0, + PFD_MAIN_PLANE, + 0, + 0, 0, 0 + }; + + int iFormat = ChoosePixelFormat(*hDC, &pfd); + SetPixelFormat(*hDC, iFormat, &pfd); + + // Create the OpenGL context + *hRC = wglCreateContext(*hDC); + wglMakeCurrent(*hDC, *hRC); +} + +void DisableOpenGL(HWND hWnd, HDC hDC, HGLRC hRC) +{ + wglMakeCurrent(NULL, NULL); + wglDeleteContext(hRC); + ReleaseDC(hWnd, hDC); +} + diff --git a/sample/win.exe b/sample/win.exe new file mode 100755 index 0000000..14e9174 Binary files /dev/null and b/sample/win.exe differ diff --git a/sample/x11 b/sample/x11 new file mode 100755 index 0000000..26d84d8 Binary files /dev/null and b/sample/x11 differ diff --git a/sample/x11.c b/sample/x11.c new file mode 100644 index 0000000..dbb794a --- /dev/null +++ b/sample/x11.c @@ -0,0 +1,256 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091 +#define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092 +typedef GLXContext (*glXCreateContextAttribsARBProc)(Display*, GLXFBConfig, GLXContext, Bool, const int*); + +// Helper to check for extension string presence. Adapted from: +// http://www.opengl.org/resources/features/OGLextensions/ +static bool isExtensionSupported(const char *extList, const char *extension) +{ + const char *start; + const char *where, *terminator; + + /* Extension names should not have spaces. */ + where = strchr(extension, ' '); + if (where || *extension == '\0') + return false; + + /* It takes a bit of care to be fool-proof about parsing the + OpenGL extensions string. Don't be fooled by sub-strings, + etc. */ + for (start=extList;;) { + where = strstr(start, extension); + + if (!where) + break; + + terminator = where + strlen(extension); + + if ( where == start || *(where - 1) == ' ' ) + if ( *terminator == ' ' || *terminator == '\0' ) + return true; + + start = terminator; + } + + return false; +} + +int main(int argc, char* argv[]) +{ + Display *display = XOpenDisplay(NULL); + + if (!display) + { + printf("Failed to open X display\n"); + exit(1); + } + + // Get a matching FB config + static int visual_attribs[] = + { + GLX_X_RENDERABLE , True, + GLX_DRAWABLE_TYPE , GLX_WINDOW_BIT, + GLX_RENDER_TYPE , GLX_RGBA_BIT, + GLX_X_VISUAL_TYPE , GLX_TRUE_COLOR, + GLX_RED_SIZE , 8, + GLX_GREEN_SIZE , 8, + GLX_BLUE_SIZE , 8, + GLX_ALPHA_SIZE , 8, + GLX_DEPTH_SIZE , 24, + GLX_STENCIL_SIZE , 8, + GLX_DOUBLEBUFFER , True, + //GLX_SAMPLE_BUFFERS , 1, + //GLX_SAMPLES , 4, + None + }; + + int glx_major, glx_minor; + + // FBConfigs were added in GLX version 1.3. + if ( !glXQueryVersion( display, &glx_major, &glx_minor ) || + ( ( glx_major == 1 ) && ( glx_minor < 3 ) ) || ( glx_major < 1 ) ) + { + printf("Invalid GLX version"); + exit(1); + } + + printf( "Getting matching framebuffer configs\n" ); + int fbcount; + GLXFBConfig* fbc = glXChooseFBConfig(display, DefaultScreen(display), visual_attribs, &fbcount); + if (!fbc) + { + printf( "Failed to retrieve a framebuffer config\n" ); + exit(1); + } + printf( "Found %d matching FB configs.\n", fbcount ); + + // Pick the FB config/visual with the most samples per pixel + printf( "Getting XVisualInfos\n" ); + int best_fbc = -1, worst_fbc = -1, best_num_samp = -1, worst_num_samp = 999; + + int i; + for (i=0; i visualid, samp_buf, samples ); + + if ( best_fbc < 0 || samp_buf && samples > best_num_samp ) + best_fbc = i, best_num_samp = samples; + if ( worst_fbc < 0 || !samp_buf || samples < worst_num_samp ) + worst_fbc = i, worst_num_samp = samples; + } + XFree( vi ); + } + + GLXFBConfig bestFbc = fbc[ best_fbc ]; + + // Be sure to free the FBConfig list allocated by glXChooseFBConfig() + XFree( fbc ); + + // Get a visual + XVisualInfo *vi = glXGetVisualFromFBConfig( display, bestFbc ); + printf( "Chosen visual ID = 0x%x\n", vi->visualid ); + + printf( "Creating colormap\n" ); + XSetWindowAttributes swa; + Colormap cmap; + swa.colormap = cmap = XCreateColormap( display, + RootWindow( display, vi->screen ), + vi->visual, AllocNone ); + swa.background_pixmap = None ; + swa.border_pixel = 0; + swa.event_mask = StructureNotifyMask; + + printf( "Creating window\n" ); + Window win = XCreateWindow( display, RootWindow( display, vi->screen ), + 0, 0, 100, 100, 0, vi->depth, InputOutput, + vi->visual, + CWBorderPixel|CWColormap|CWEventMask, &swa ); + if ( !win ) + { + printf( "Failed to create window.\n" ); + exit(1); + } + + // Done with the visual info data + XFree( vi ); + + XStoreName( display, win, "GL 3.0 Window" ); + + printf( "Mapping window\n" ); + XMapWindow( display, win ); + + // Get the default screen's GLX extension list + //const char *glxExts = glXQueryExtensionsString( display, + // DefaultScreen( display ) ); + + // NOTE: It is not necessary to create or make current to a context before + // calling glXGetProcAddressARB + glXCreateContextAttribsARBProc glXCreateContextAttribsARB = 0; + glXCreateContextAttribsARB = (glXCreateContextAttribsARBProc) + glXGetProcAddressARB( (const GLubyte *) "glXCreateContextAttribsARB" ); + + GLXContext ctx = 0; + + // Install an X error handler so the application won't exit if GL 3.0 + // context allocation fails. + // + // Note this error handler is global. All display connections in all threads + // of a process use the same error handler, so be sure to guard against other + // threads issuing X commands while this code is running. + //ctxErrorOccurred = false; + //int (*oldHandler)(Display*, XErrorEvent*) = + // XSetErrorHandler(&ctxErrorHandler); + + // Check for the GLX_ARB_create_context extension string and the function. + // If either is not present, use GLX 1.3 context creation method. + //if ( !isExtensionSupported( glxExts, "GLX_ARB_create_context" ) || + // !glXCreateContextAttribsARB ) + //{ + // printf( "glXCreateContextAttribsARB() not found" + // " ... using old-style GLX context\n" ); + // ctx = glXCreateNewContext( display, bestFbc, GLX_RGBA_TYPE, 0, True ); + //} else + //{ + int context_attribs[] = + { + GLX_CONTEXT_MAJOR_VERSION_ARB, 3, + GLX_CONTEXT_MINOR_VERSION_ARB, 0, + //GLX_CONTEXT_FLAGS_ARB , GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB, + None + }; + + printf( "Creating context\n" ); + ctx = glXCreateContextAttribsARB( display, bestFbc, 0, + True, context_attribs ); + + // Sync to ensure any errors generated are processed. + //XSync( display, False ); + //if (ctxErrorOccurred && !ctx) + //{ + // context_attribs[1] = 1; + // context_attribs[3] = 0; + + // ctxErrorOccurred = false; + + // printf( "Failed to create GL 3.0 context" + // " ... using old-style GLX context\n" ); + // ctx = glXCreateContextAttribsARB( display, bestFbc, 0, + // True, context_attribs ); + //} + //} + + //XSync( display, False ); + //XSetErrorHandler( oldHandler ); + + //if ( ctxErrorOccurred || !ctx ) + //{ + // printf( "Failed to create an OpenGL context\n" ); + // exit(1); + //} + + printf( "Making context current\n" ); + glXMakeCurrent( display, win, ctx ); + + const GLubyte * v = glGetString(GL_VERSION); + printf("%s\n", v); + + glClearColor( 0, 0.5, 1, 1 ); + glClear( GL_COLOR_BUFFER_BIT ); + glXSwapBuffers ( display, win ); + + sleep( 1 ); + + glClearColor ( 1, 0.5, 0, 1 ); + glClear ( GL_COLOR_BUFFER_BIT ); + glXSwapBuffers ( display, win ); + + sleep( 1 ); + + glXMakeCurrent( display, 0, 0 ); + glXDestroyContext( display, ctx ); + + XDestroyWindow( display, win ); + XFreeColormap( display, cmap ); + XCloseDisplay( display ); + + return 0; +} diff --git a/src/openwindow.c b/src/openwindow.c index f648c97..270fab0 100644 --- a/src/openwindow.c +++ b/src/openwindow.c @@ -12,8 +12,6 @@ int initOpenGL() { #ifndef _WIN32 -#define GLLOADER glXGetProcAddress - typedef GLXContext (*glXCreateContextAttribsARBProc)(Display*, GLXFBConfig, GLXContext, Bool, const int*); bool checkGLXVersion(Window window) { @@ -87,9 +85,9 @@ int initGLX(Window * window) glXGetProcAddressARB( (const GLubyte *) "glXCreateContextAttribsARB" ); int context_attribs[] = { - GLX_CONTEXT_MAJOR_VERSION_ARB, 3, - GLX_CONTEXT_MINOR_VERSION_ARB, 0, - //GLX_CONTEXT_FLAGS_ARB , GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB, + GLX_CONTEXT_MAJOR_VERSION_ARB, 4, + GLX_CONTEXT_MINOR_VERSION_ARB, 6, + GLX_CONTEXT_FLAGS_ARB , GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB, None }; window->glx.context = glXCreateContextAttribsARB(window->x.display, window->glx.config, 0, True, context_attribs); @@ -206,51 +204,122 @@ void closeWindow(Window window) { #else #include +#include -#define GLLOADER wglGetProcAddress +#define WND_CLASS_NAME "OpenWindowWndClass" LRESULT CALLBACK wndProc(HWND hwnd, unsigned int msg, WPARAM wParam, LPARAM lParam) { - Window * window = (Window *)GetWindowLong(hwnd, GWLP_USERDATA); + Window * window = (Window *)(LONG_PTR)GetWindowLong(hwnd, GWLP_USERDATA); switch (msg) { - case WM_CLOSE: { - window->close = true; - return 0; - } + case WM_KEYDOWN: + { + if (wParam == VK_ESCAPE) window->close = true; + break; + } } return (DefWindowProc(hwnd, msg, wParam, lParam)); } -int initWGL(Window * window, const char * title, size_t width, size_t height) { - HINSTANCE hInstance = GetModuleHandle(NULL); +int init(Window * window, const char * title, size_t width, size_t height) { + window->wgl.instance = GetModuleHandle(NULL); WNDCLASSEX wcex; wcex.cbSize = sizeof(WNDCLASSEX); - wcex.style = CS_OWNDC; - wcex.lpfnWndProc = &DefWindowProc; + wcex.style = CS_CLASSDC; + wcex.lpfnWndProc = wndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; - wcex.hInstance = hInstance; + wcex.hInstance = window->wgl.instance; wcex.hIcon = NULL; wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = 0; wcex.lpszMenuName = NULL; - wcex.lpszClassName = title; + wcex.lpszClassName = WND_CLASS_NAME; wcex.hIconSm = NULL; - wcex.lpfnWndProc = wndProc; RegisterClassEx(&wcex); - RECT rect = { 0, 0, width, height }; - int style = WS_BORDER | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME; - AdjustWindowRect(&rect, style, FALSE); - window->w.window = CreateWindow(title, "example", style, CW_USEDEFAULT, CW_USEDEFAULT, rect.right - rect.left, rect.bottom - rect.top, NULL, NULL, GetModuleHandle(NULL), window); - ShowWindow(window->w.window, SW_SHOW); + window->wgl.window = CreateWindow( + WND_CLASS_NAME, + title, + WS_OVERLAPPEDWINDOW | WS_VISIBLE, + CW_USEDEFAULT, + CW_USEDEFAULT, + width, + height, + NULL, + NULL, + window->wgl.instance, + window + ); - SetWindowLong(window->w.window, GWLP_USERDATA, (LONG)window); + if (window->wgl.window == NULL) return -1; + + ShowWindow(window->wgl.window, SW_SHOW); + + SetWindowLong(window->wgl.window, GWLP_USERDATA, (LONG_PTR)window); + + window->wgl.display = GetDC(window->wgl.window); + PIXELFORMATDESCRIPTOR pfd = {0}; + pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR); + pfd.nVersion = 1; + pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; + pfd.iPixelType = PFD_TYPE_RGBA; + pfd.cColorBits = 32; + pfd.cRedBits = 0; + pfd.cRedShift = 0; + pfd.cGreenBits = 0; + pfd.cGreenShift = 0; + pfd.cBlueBits = 0; + pfd.cBlueShift = 0; + pfd.cAlphaBits = 0; + pfd.cAlphaShift = 0; + pfd.cAccumBits = 0; + pfd.cAccumRedBits = 0; + pfd.cAccumGreenBits = 0; + pfd.cAccumBlueBits = 0; + pfd.cAccumAlphaBits = 0; + pfd.cDepthBits = 24; + pfd.cStencilBits = 8; + pfd.cAuxBuffers = 0; + pfd.iLayerType = PFD_MAIN_PLANE; + pfd.bReserved = 0; + pfd.dwLayerMask = 0; + pfd.dwVisibleMask = 0; + pfd.dwDamageMask = 0; + + int format = ChoosePixelFormat(window->wgl.display, &pfd); + SetPixelFormat(window->wgl.display, format, &pfd); + + HGLRC tempContext = wglCreateContext(window->wgl.display); + if (tempContext == NULL) return -1; + + if (!wglMakeCurrent(window->wgl.display, tempContext)) return -1; + + PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC)wglGetProcAddress("wglCreateContextAttribsARB"); + if (wglCreateContextAttribsARB == NULL) return -1; + + int attribs[] = { + WGL_CONTEXT_MAJOR_VERSION_ARB, 4, + WGL_CONTEXT_MINOR_VERSION_ARB, 6, + WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB, + 0 + }; + + window->wgl.context = wglCreateContextAttribsARB(window->wgl.display, 0, attribs); + if (window->wgl.context == NULL) { + fprintf(stderr, "Failed to create wgl context!\n"); + return -1; + } + + wglMakeCurrent(window->wgl.display, NULL); + wglDeleteContext(tempContext); + + wglMakeCurrent(window->wgl.display, window->wgl.context); return 0; } @@ -258,24 +327,41 @@ int initWGL(Window * window, const char * title, size_t width, size_t height) { Window openWindow(const char * name, size_t width, size_t height) { Window w = {0}; - if (initWGL(&w, name, width, height) < 0) { - fprintf(stderr, "Failed to initialize egl!\n"); + if (init(&w, name, width, height) < 0) { + fprintf(stderr, "Failed to initialize wgl!\n"); exit(1); } - initOpenGL(); - - eglMakeCurrent(w.egl.display, w.egl.surface, w.egl.surface, w.egl.context); + if (initOpenGL() < 0) { + fprintf(stderr, "Failed to initialize window: GLAD/OPENGL error!\n"); + exit(1); + } return w; } +void windowDraw(Window window) { + SwapBuffers(window.wgl.display); +} + +void windowHandleEvents(Window * window) { + MSG msg; + GetMessage(&msg, NULL, 0, 0); + TranslateMessage(&msg); + DispatchMessage(&msg); +} + void closeWindow(Window window) { - DestroyWindow(window.w.window); + wglMakeCurrent(NULL, NULL); + wglDeleteContext(window.wgl.context); + ReleaseDC(window.wgl.window, window.wgl.display); + + DestroyWindow(window.wgl.window); + UnregisterClass(WND_CLASS_NAME, window.wgl.instance); } #endif // _WIN32 int getOpenGLProcs(void) { - return gladLoadGLLoader((GLADloadproc)GLLOADER); + return gladLoadGL(); } diff --git a/src/openwindow.h b/src/openwindow.h index b53d5ce..ace7d37 100644 --- a/src/openwindow.h +++ b/src/openwindow.h @@ -38,36 +38,41 @@ typedef struct Window { bool close; } Window; -#else - -typedef struct { -} WGL; - -typedef struct { - HDC display; - HWND window; -} Windows; - -typedef struct Window Window; - -typedef struct Window { - WGL wgl; - Windows x; - WindowEventHandler eventHandler; - bool close; -} Window; - -#endif // _WIN32 - -// depends on glad -int getOpenGLProcs(void); - Window openWindow(const char * name, size_t width, size_t height); void windowDraw(Window window); void windowSetEventHandler(Window * window, WindowEventHandler handler); void windowHandleEvents(Window * window); void closeWindow(Window w); +#else + +#include + +typedef struct { + HINSTANCE instance; + HDC display; + HWND window; + HGLRC context; +} WGL; + +typedef struct Window Window; + +typedef struct Window { + WGL wgl; + //WindowEventHandler eventHandler; + bool close; +} Window; + +Window openWindow(const char * name, size_t width, size_t height); +void windowDraw(Window window); +void windowHandleEvents(Window * window); +void closeWindow(Window w); + +#endif // _WIN32 + +// depends on glad +int getOpenGLProcs(void); + #endif // _OPEN_WINDOW_H_ // TODO: Add all the error handling to the glx