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