module window; import derelict.sdl2.sdl; import glad.gl.all; /** * Converts an integer representing a colour, for example 0x428bca into a 4 element * int array for passing to OpenGL. */ GLfloat[4] to(T : GLfloat[4])(int color, ubyte alpha = 255) nothrow @nogc pure { GLfloat[4] gl_color = [ //mask out r, g, b components from int cast(float)cast(ubyte)(color>>16)/255, cast(float)cast(ubyte)(color>>8)/255, cast(float)cast(ubyte)(color)/255, cast(float)cast(ubyte)(alpha)/255 ]; return gl_color; } // to!GLfloat[4] struct Window { import core.stdc.stdio; import core.stdc.stdlib; SDL_Window* window; SDL_GLContext context; extern(Windows) nothrow @nogc static void openGLCallbackFunction( GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const (GLchar)* message, void* userParam) { printf("Message: %s \nSource: %s \nType: %s \nID: %d \nSeverity: %s\n\n", message, to!(char*)(source), to!(char*)(type), id, to!(char*)(severity)); if (severity == GL_DEBUG_SEVERITY_HIGH) { printf("Aborting...\n"); import core.stdc.stdlib : exit; exit(-1); } } // openGLCallbackFunction void createWindow(int w, int h, const char* title = "Chipd8 Emu") { assert(w > 0, "window width must be > 0"); assert(h > 0, "window height must be > 0"); // minimum OpenGL 3.3 SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3); SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 32); // DEBUGGERING! SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG); SDL_Window* new_win = SDL_CreateWindow(title, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, w, h, SDL_WINDOW_OPENGL); if (new_win == null) { printf("SDL2 - Window could not be created: %s\n", SDL_GetError()); return; } SDL_GLContext new_con = SDL_GL_CreateContext(new_win); if (new_con == null) { printf("SDL2 - failed creating OpenGL 3.3 context: %s\n", SDL_GetError()); return; } import glad.gl.loader; import std.functional; // Check OpenGL properties printf("OpenGL loaded\n"); gladLoadGL((const (char)* a) => SDL_GL_GetProcAddress(a)); printf("Vendor: %s\n", glGetString(GL_VENDOR)); printf("Renderer: %s\n", glGetString(GL_RENDERER)); printf("Version: %s\n", glGetString(GL_VERSION)); // enable debuggering glEnable(GL_DEBUG_OUTPUT); glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); glDebugMessageCallback(&openGLCallbackFunction, null); //enable all glDebugMessageControl( GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, null, true ); //disable notification messages glDebugMessageControl( GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_NOTIFICATION, 0, null, false ); // assign em yes window = new_win; context = new_con; atexit(SDL_Quit); } // createWindow void handleEvent(ref SDL_Event ev) { } // handleEvent void renderClear(int colour) { auto col = to!(float[4])(colour, 255); glClearColor(col[0], col[1], col[2], col[3]); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } // renderClear void renderPresent() { SDL_GL_SwapWindow(window); } // renderPresent void mousePos(ref int x, ref int y) { SDL_GetMouseState(&x, &y); } void windowSize(ref int w, ref int h) { SDL_GetWindowSize(window, &w, &h); } void framebufferSize(ref int w, ref int h) { SDL_GL_GetDrawableSize(window, &w, &h); } } // Window /** * Converts a GLenum representation of a value to a c string representation, * for use with debug printing of OpenGL info, from debug callbacks for example. */ const (char*) to(T : char*)(GLenum value) { import glad.gl.all; switch (value) { // sources case GL_DEBUG_SOURCE_API: return "API"; case GL_DEBUG_SOURCE_WINDOW_SYSTEM: return "Window System"; case GL_DEBUG_SOURCE_SHADER_COMPILER: return "Shader Compiler"; case GL_DEBUG_SOURCE_THIRD_PARTY: return "Third Party"; case GL_DEBUG_SOURCE_APPLICATION: return "Application"; case GL_DEBUG_SOURCE_OTHER: return "Other"; // error types case GL_DEBUG_TYPE_ERROR: return "Error"; case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR: return "Deprecated Behaviour"; case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR: return "Undefined Behaviour"; case GL_DEBUG_TYPE_PORTABILITY: return "Portability"; case GL_DEBUG_TYPE_PERFORMANCE: return "Performance"; case GL_DEBUG_TYPE_MARKER: return "Marker"; case GL_DEBUG_TYPE_PUSH_GROUP: return "Push Group"; case GL_DEBUG_TYPE_POP_GROUP: return "Pop Group"; case GL_DEBUG_TYPE_OTHER: return "Other"; // severity markers case GL_DEBUG_SEVERITY_HIGH: return "High"; case GL_DEBUG_SEVERITY_MEDIUM: return "Medium"; case GL_DEBUG_SEVERITY_LOW: return "Low"; case GL_DEBUG_SEVERITY_NOTIFICATION: return "Notification"; default: return "(undefined)"; } } // to!string(GLenum)