1 /* 2 * BSD 3-Clause License 3 * 4 * Copyright (c) 2016, Mango-Engine Team 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions are met: 9 * 10 * * Redistributions of source code must retain the above copyright notice, this 11 * list of conditions and the following disclaimer. 12 * 13 * * Redistributions in binary form must reproduce the above copyright notice, 14 * this list of conditions and the following disclaimer in the documentation 15 * and/or other materials provided with the distribution. 16 * 17 * * Neither the name of the copyright holder nor the names of its 18 * contributors may be used to endorse or promote products derived from 19 * this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 module mango_engine.graphics.opengl.gl_window; 33 34 version(mango_GLBackend) { 35 import mango_engine.graphics.window; 36 import mango_engine.mango; 37 import mango_engine.game; 38 import mango_engine.input; 39 import mango_engine.event.core; 40 import mango_engine.event.graphics; 41 import mango_engine.graphics.renderer; 42 import mango_engine.graphics.opengl.gl_backend; 43 import mango_engine.graphics.opengl.gl_renderer; 44 45 import blocksound.util : toCString, toDString; // TODO: move to mango_stl 46 47 import derelict.glfw3.glfw3; 48 import derelict.opengl3.gl3 : glViewport, glGetString, GL_VERSION, GL_RENDERER, GL_VENDOR; 49 50 import std.container.dlist; 51 import std.conv; 52 53 private struct KeyEvent { 54 GLFWwindow* window; 55 int key; 56 int scancode; 57 int action; 58 int mods; 59 } 60 61 private __gshared GameManager gamePtr; 62 63 extern(C) private void glfw_windowSizeCallback(GLFWwindow* window, int width, int height) @system nothrow { 64 glViewport(0, 0, width, height); // Tell OpenGL the window was resized 65 } 66 67 extern(C) private void glfw_keyEventCallback(GLFWwindow* window, int key, int scancode, int action, int mods) @system nothrow { 68 //keyEventQueue.insertBack(KeyEvent(window, key, scancode, action, mods)); // Add the keyEvent to the queue 69 gamePtr.inputManager.sendInputEventMessage(INPUT_TYPE_KEY, new KeyInputData(key, action)); 70 } 71 72 class GLWindow : Window { 73 __gshared { 74 private GLFWwindow* window; 75 } 76 77 this(Renderer renderer, in string title, in uint width, in uint height, SyncType syncType) @trusted { 78 super(renderer, title, width, height, syncType); 79 80 renderer.submitOperation(&this.setupWindow); 81 } 82 83 private void setupWindow() @trusted 84 in { 85 assert((cast(GLRenderer) this.renderer) !is null, "renderer not instanceof GLRenderer!"); 86 } body { 87 glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_API); 88 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, MANGO_GL_VERSION_MAJOR); 89 glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, MANGO_GL_VERSION_MINOR); 90 91 this.window = glfwCreateWindow(this.width, this.height, toCString(this.title), null, null); 92 if(!window) { 93 throw new Exception("Failed to create window! Does the host machine support OpenGL " ~ MANGO_GL_VERSION ~ "?"); 94 } 95 96 glfwMakeContextCurrent(this.window); 97 98 glbackend_loadCoreMethods(); 99 100 glfwSetWindowSizeCallback(this.window, &glfw_windowSizeCallback); 101 glfwSetKeyCallback(this.window, &glfw_keyEventCallback); 102 103 string glVersion = toDString(glGetString(GL_VERSION)); 104 105 GLOBAL_LOGGER.logInfo("GL_VERSION: " ~ glVersion); 106 GLOBAL_LOGGER.logInfo("GL_RENDERER: " ~ toDString(glGetString(GL_RENDERER))); 107 GLOBAL_LOGGER.logInfo("GL_VENDOR: " ~ toDString(glGetString(GL_VENDOR))); 108 109 (cast(GLRenderer) this.renderer).registerWindowId(this.window); 110 } 111 112 GLFWwindow* getWindowPtr() @system nothrow { 113 return window; 114 } 115 116 override { 117 protected void setTitle_(in string title) @system { 118 this.renderer.submitOperation(() { 119 this.game.logger.logDebug("Window title changed to " ~ title); 120 glfwSetWindowTitle(this.window, toCString(title)); 121 }); 122 } 123 124 protected void setVisible_(in bool visible) @system { 125 this.renderer.submitOperation(() { 126 this.game.logger.logDebug("Window set visible: " ~ to!string(visible)); 127 if(visible) { 128 glfwShowWindow(this.window); 129 } else { 130 glfwHideWindow(this.window); 131 } 132 }); 133 } 134 135 protected void resize_(in uint width, in uint height) @system { 136 this.renderer.submitOperation(() { 137 this.game.logger.logDebug("Window manually resized to " ~ to!string(width) ~ "x" ~ to!string(height)); 138 glfwSetWindowSize(this.window, width, height); 139 }); 140 } 141 142 protected void onGamemanager_notify() @system { 143 gamePtr = this.game(); 144 145 this.game.eventManager.registerEventHook(TickEvent.classinfo.name, EventHook((Event e) { 146 debug { 147 import std.stdio; 148 //writeln("i've been called!"); 149 } 150 if(this.window is null) return; 151 152 if(glfwWindowShouldClose(this.window)) { 153 this.game.logger.logDebug("Window closing."); 154 this.game.stop(); 155 } 156 })); 157 } 158 } 159 } 160 }