1 module armos.app.glfwwindow; 2 3 import armos.app; 4 import armos.events; 5 import derelict.opengl3.gl; 6 import armos.app.window; 7 import armos.math; 8 import armos.graphics.renderer; 9 /++ 10 GLFWを利用したWindowです.armosではデフォルトでこのclassを元にWindowが生成されます. 11 +/ 12 class GLFWWindow : Window{ 13 import derelict.glfw3.glfw3; 14 import std.range:put; 15 mixin BaseWindow; 16 17 public{ 18 enum bool hasRenderer = true; 19 /++ 20 Params: 21 apprication = Windowとひも付けされるアプリケーションです. 22 +/ 23 this(WindowConfig config = new WindowConfig, GLFWwindow* sharedContext = null){ 24 DerelictGL.load(); 25 DerelictGLFW3.load(); 26 27 if( !glfwInit() ){} 28 29 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, config.glVersionMajor); 30 glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, config.glVersionMinor); 31 32 import armos.utils.semver; 33 if(config.glVersion >= SemVer("3.2.0")){ 34 glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); 35 glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); 36 } 37 38 _window = glfwCreateWindow(config.width, config.height, cast(char*)_name, null, sharedContext); 39 if(!_window){close;} 40 41 GLFWWindow.glfwWindowToArmosGLFWWindow[_window] = this; 42 43 glfwMakeContextCurrent(_window); 44 45 if(config.glVersion >= SemVer("3.2.0")){ 46 DerelictGL3.reload(); 47 }else{ 48 DerelictGL.reload(); 49 } 50 51 initGLFWEvents(); 52 _subjects = new CoreSubjects; 53 54 glfwSwapInterval(0); 55 glfwSwapBuffers(_window); 56 57 writeVersion; 58 59 60 _renderer = new Renderer; 61 } 62 63 ~this(){ 64 GLFWWindow.glfwWindowToArmosGLFWWindow.remove(_window); 65 } 66 67 void size(Vector2i size){ 68 glfwSetWindowSize(_window, size[0], size[1]); 69 } 70 71 /++ 72 Windowのサイズを返します. 73 +/ 74 Vector2i size()const{ 75 auto vec = Vector2i(); 76 glfwGetWindowSize(cast(GLFWwindow*)(_window), &vec[0], &vec[1]); 77 return vec; 78 } 79 80 /++ 81 Windowのframw bufferのサイズを返します. 82 +/ 83 Vector2i frameBufferSize()const{ 84 auto vec = Vector2i(); 85 glfwGetFramebufferSize(cast(GLFWwindow*)(_window), &vec[0], &vec[1]); 86 return vec; 87 } 88 89 /++ 90 イベントが発生している場合,登録されたイベントを実行します 91 +/ 92 void pollEvents(){ 93 glfwPollEvents(); 94 } 95 96 void setup(){ 97 _renderer.setup(); 98 put(_subjects.setup, SetupEvent()); 99 } 100 101 /++ 102 Windowを更新します. 103 +/ 104 void update(){ 105 put(_subjects.update, UpdateEvent()); 106 _shouldClose = cast(bool)glfwWindowShouldClose(_window); 107 } 108 109 void draw(){ 110 if(_renderer){ 111 _renderer.startRender(); 112 } 113 put(_subjects.draw, DrawEvent()); 114 if(_renderer){ 115 _renderer.finishRender(); 116 } 117 glfwSwapBuffers(_window); 118 } 119 120 /++ 121 Windowを閉じます. 122 +/ 123 void close(){ 124 put(_subjects.exit, ExitEvent()); 125 _shouldClose = true; 126 glfwDestroyWindow(_window); 127 } 128 129 void name(in string str){ 130 import std..string; 131 _name = str; 132 glfwSetWindowTitle(_window, str.toStringz); 133 } 134 135 void select(){ 136 glfwMakeContextCurrent(_window); 137 }; 138 139 /// VerticalSync 140 void verticalSync(in bool f){ 141 glfwSwapInterval(f); 142 }; 143 144 /// 145 float pixelScreenCoordScale()const{ 146 return frameBufferSize.x / size.x; 147 }; 148 149 void initEvents(Application app){ 150 assert(_subjects); 151 import rx; 152 _subjects.setup.doSubscribe!(event => app.setup(event)); 153 _subjects.update.doSubscribe!(event => app.update(event)); 154 _subjects.draw.doSubscribe!(event => app.draw(event)); 155 _subjects.exit.doSubscribe!(event => app.exit(event)); 156 _subjects.windowResize.doSubscribe!(event => app.windowResized(event)); 157 _subjects.keyPressed.doSubscribe!(event => app.keyPressed(event)); 158 _subjects.keyReleased.doSubscribe!(event => app.keyReleased(event)); 159 _subjects.unicodeInputted.doSubscribe!(event => app.unicodeInputted(event)); 160 _subjects.mouseMoved.doSubscribe!(event => app.mouseMoved(event)); 161 _subjects.mousePressed.doSubscribe!(event => app.mousePressed(event)); 162 _subjects.mouseDragged.doSubscribe!(event => app.mouseDragged(event)); 163 _subjects.mouseReleased.doSubscribe!(event => app.mouseReleased(event)); 164 _subjects.mouseScrolled.doSubscribe!(event => app.mouseScrolled(event)); 165 } 166 167 CoreObservables observables(){ 168 import std.conv:to; 169 return _subjects.to!CoreObservables; 170 } 171 172 Renderer renderer(){return _renderer;} 173 174 GLFWwindow* context(){ 175 return _window; 176 } 177 }//public 178 179 private{ 180 GLFWwindow* _window; 181 CoreSubjects _subjects; 182 Renderer _renderer; 183 184 static extern(C) void keyCallbackFunction(GLFWwindow* window, int key, int scancode, int action, int mods){ 185 auto currentGLFWWindow = GLFWWindow.glfwWindowToArmosGLFWWindow[window]; 186 mainLoop.select(currentGLFWWindow); 187 import std.conv; 188 import armos.utils.keytype; 189 if(action == GLFW_PRESS){ 190 put(currentGLFWWindow._subjects.keyPressed, KeyPressedEvent(key.to!KeyType)); 191 }else if(action == GLFW_RELEASE){ 192 put(currentGLFWWindow._subjects.keyReleased, KeyReleasedEvent(key.to!KeyType)); 193 } 194 } 195 196 static extern(C) void charCallbackFunction(GLFWwindow* window, uint key){ 197 auto currentGLFWWindow = GLFWWindow.glfwWindowToArmosGLFWWindow[window]; 198 mainLoop.select(currentGLFWWindow); 199 put(currentGLFWWindow._subjects.unicodeInputted, UnicodeInputtedEvent(key)); 200 } 201 202 static extern(C) void cursorPositionFunction(GLFWwindow* window, double xpos, double ypos){ 203 auto currentGLFWWindow = GLFWWindow.glfwWindowToArmosGLFWWindow[window]; 204 mainLoop.select(currentGLFWWindow); 205 put(currentGLFWWindow._subjects.mouseMoved, MouseMovedEvent(cast(int)xpos, cast(int)ypos, 0)); 206 } 207 208 static extern(C ) void mouseButtonFunction(GLFWwindow* window, int button, int action, int mods){ 209 auto currentGLFWWindow = GLFWWindow.glfwWindowToArmosGLFWWindow[window]; 210 mainLoop.select(currentGLFWWindow); 211 212 double xpos, ypos; 213 glfwGetCursorPos(window, &xpos, &ypos); 214 215 if(action == GLFW_PRESS){ 216 put(currentGLFWWindow._subjects.mousePressed, MousePressedEvent(cast(int)xpos, cast(int)ypos, button)); 217 }else if(action == GLFW_RELEASE){ 218 put(currentGLFWWindow._subjects.mouseReleased, MouseReleasedEvent(cast(int)xpos, cast(int)ypos, button)); 219 } 220 } 221 222 static extern(C ) void resizeWindowFunction(GLFWwindow* window, int width, int height){ 223 import armos.graphics; 224 auto currentGLFWWindow = GLFWWindow.glfwWindowToArmosGLFWWindow[window]; 225 mainLoop.select(currentGLFWWindow); 226 currentRenderer.resize(); 227 put(currentGLFWWindow._subjects.windowResize, WindowResizeEvent(cast(int)width, cast(int)height)); 228 } 229 230 static extern(C ) void mouseScrolledCallback(GLFWwindow* window, double xOffset, double yOffset){ 231 import armos.graphics; 232 auto currentGLFWWindow = GLFWWindow.glfwWindowToArmosGLFWWindow[window]; 233 mainLoop.select(currentGLFWWindow); 234 put(currentGLFWWindow._subjects.mouseScrolled, MouseScrolledEvent(cast(int)xOffset, cast(int)yOffset)); 235 } 236 237 void writeVersion(){ 238 import std.stdio, std.conv; 239 writefln("Vendor: %s", to!string(glGetString(GL_VENDOR))); 240 writefln("Renderer: %s", to!string(glGetString(GL_RENDERER))); 241 writefln("Version: %s", to!string(glGetString(GL_VERSION))); 242 writefln("GLSL: %s\n", to!string(glGetString(GL_SHADING_LANGUAGE_VERSION))); 243 }; 244 245 246 247 void initGLFWEvents(){ 248 // glfwSetKeyCallback(window, &keyCallbackFunction); 249 glfwSetKeyCallback(_window, cast(GLFWkeyfun)&keyCallbackFunction); 250 glfwSetCharCallback(_window, cast(GLFWcharfun)&charCallbackFunction); 251 glfwSetCursorPosCallback(_window, cast(GLFWcursorposfun)&cursorPositionFunction); 252 glfwSetMouseButtonCallback(_window, cast(GLFWmousebuttonfun)&mouseButtonFunction); 253 glfwSetWindowSizeCallback(_window, cast(GLFWwindowsizefun)&resizeWindowFunction); 254 glfwSetScrollCallback(_window, cast(GLFWscrollfun)&mouseScrolledCallback); 255 } 256 257 static GLFWWindow[GLFWwindow*] glfwWindowToArmosGLFWWindow; 258 }//private 259 } 260