1 /*
2     Copyright © 2020, Luna Nielsen
3     Distributed under the 2-Clause BSD License, see LICENSE file.
4     
5     Authors: Luna Nielsen
6 */
7 module engine.core.window;
8 import bindbc.glfw;
9 import bindbc.opengl;
10 import engine.render : kmViewport;
11 
12 /**
13     Static instance of the game window
14 */
15 static Window GameWindow;
16 
17 /**
18     A Window
19 */
20 class Window {
21 private:
22     GLFWwindow* window;
23     string title_;
24     int width_;
25     int height_;
26 
27     int fbWidth;
28     int fbHeight;
29 
30 public:
31 
32     /**
33         Destructor
34     */
35     ~this() {
36         glfwDestroyWindow(window);
37     }
38 
39     /**
40         Constructor
41     */
42     this(string title = "My Game", int width = 640, int height = 480) {
43         this.title_ = title;
44         this.width_ = width;
45         this.height_ = height;
46         this.fbWidth = width;
47         this.fbHeight = height;
48 
49         glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
50         glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
51         glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE); // To make macOS happy
52         glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_COMPAT_PROFILE);
53         window = glfwCreateWindow(640, 480, this.title_.ptr, null, null);
54         
55     }
56 
57     /**
58         Hides the window
59     */
60     void hide() {
61         glfwHideWindow(window);
62     }
63 
64     /**
65         Show window
66     */
67     void show() {
68         glfwShowWindow(window);
69     }
70 
71     /**
72         Gets the title of the window
73     */
74     @property string title() {
75         return this.title_;
76     }
77 
78     /**
79         Sets the title of the window
80     */
81     @property void title(string value) {
82         this.title_ = value;
83         glfwSetWindowTitle(window, this.title_.ptr);
84     }
85 
86     /**
87         Gets the width of the window's framebuffer
88     */
89     @property int width() {
90         return this.fbWidth;
91     }
92 
93     /**
94         Gets the height of the window's framebuffer
95     */
96     @property int height() {
97         return this.fbHeight;
98     }
99 
100     /**
101         Resizes the window
102     */
103     void resize(int width, int height) {
104         this.width_ = width;
105         this.height_ = height;
106         glfwSetWindowSize(window, width, height);
107     }
108 
109     /**
110         Gets whether the window is fullscreen
111     */
112     bool fullscreen() {
113         return glfwGetWindowMonitor(window) !is null;
114     }
115 
116     /**
117         Sets the window's fullscreen state
118     */
119     void fullscreen(bool value) {
120         if (this.fullscreen == value) return;
121 
122         // TODO: change state
123         // HACK: currently we're just setting the window as borderless
124         if (value) {
125             const(GLFWvidmode)* mode = glfwGetVideoMode(glfwGetPrimaryMonitor());
126             this.resize(mode.width, mode.height);
127             glfwSetWindowAttrib(window, GLFW_DECORATED, GLFW_FALSE);
128         } else {
129             glfwSetWindowAttrib(window, GLFW_DECORATED, GLFW_TRUE);
130         }
131     }
132 
133     /**
134         poll for new window events
135     */
136     void update() {
137         glfwPollEvents();
138         glfwGetFramebufferSize(window, &fbWidth, &fbHeight);
139     }
140 
141     /**
142         Set the close request flag
143     */
144     void close() {
145         glfwSetWindowShouldClose(window, 1);
146     }
147 
148     /**
149         Gets whether the window has requested to close (aka the game is requested to exit)
150     */
151     bool isExitRequested() {
152         return cast(bool)glfwWindowShouldClose(window);
153     }
154 
155     /**
156         Makes the OpenGL context of the window current
157     */
158     void makeCurrent() {
159         glfwMakeContextCurrent(window);
160     }
161 
162     /**
163         Swaps the OpenGL buffers for the window
164     */
165     void swapBuffers() {
166         glfwSwapBuffers(window);
167     }
168 
169     /**
170         Sets the swap interval, by default vsync
171     */
172     void setSwapInterval(SwapInterval interval = SwapInterval.VSync) {
173         glfwSwapInterval(cast(int)interval);
174     }
175 
176     /**
177         Resets the OpenGL viewport to fit the window
178     */
179     void resetViewport() {
180         kmViewport(0, 0, width, height);
181     }
182 
183     /**
184         Gets the glfw window pointer
185     */
186     GLFWwindow* winPtr() {
187         return window;
188     }
189 }
190 
191 /**
192     A swap interval
193 */
194 enum SwapInterval : int {
195     Unlimited = 0,
196     VSync = 1
197 }