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