1 module evael.system.window;
2 
3 import std.traits : EnumMembers;
4 import std.experimental.logger;
5 
6 public import bindbc.glfw;
7 
8 import evael.core.game_config : GraphicsSettings;
9 import evael.system.cursor;
10 
11 import evael.lib.memory : NoGCClass;
12 import evael.lib..string : Cstring;
13 
14 /**
15  * Window.
16  *
17  * High-level interface to GLFWWindow.
18  */
19 class Window : NoGCClass
20 {
21     /// GLFW window handle
22     private GLFWwindow* m_glfwWindow;
23 
24     /// GLFW cursors
25     private GLFWcursor*[Cursor] m_cursors;
26 
27     /// Current cursor
28     private Cursor m_currentCursor;
29 
30     mixin(GLFWCallback!("onWindowClose", "GLFWwindowclosefun"));
31     mixin(GLFWCallback!("onWindowSize", "GLFWwindowsizefun"));
32     mixin(GLFWCallback!("onCursorPos", "GLFWcursorposfun"));
33     mixin(GLFWCallback!("onMouseButton", "GLFWmousebuttonfun"));
34     mixin(GLFWCallback!("onScroll", "GLFWscrollfun"));
35     mixin(GLFWCallback!("onKey", "GLFWkeyfun"));
36     mixin(GLFWCallback!("onChar", "GLFWcharfun"));
37     
38     /**
39      * Window constructor.
40      * Params:
41      *		title : window title
42      *      settings : window settings
43      */
44     @nogc
45     public this(in string title, in ref GraphicsSettings graphicsSettings)
46     {
47         glfwWindowHint(GLFW_RESIZABLE, graphicsSettings.resizable);
48         
49         this.m_glfwWindow = glfwCreateWindow(graphicsSettings.width, graphicsSettings.height,
50             Cstring(title), graphicsSettings.fullscreen ? glfwGetPrimaryMonitor() : null, null);
51 
52         /*foreach(cursor; [EnumMembers!(Cursor)])
53         {
54             this.m_cursors[cursor] = glfwCreateStandardCursor(cursor);
55         }
56 
57         this.setCursor(Cursor.Arrow);*/
58     }
59 
60     /**
61      * Window destructor.
62      */
63     @nogc
64     public ~this()
65     {
66         foreach (cursor; this.m_cursors.byValue())
67         {
68             glfwDestroyCursor(cursor);            
69         }
70 
71         glfwDestroyWindow(this.m_glfwWindow);
72     }
73 
74     /**
75      * Polls window events.
76      */
77     @nogc
78     public void pollEvents() nothrow
79     {
80         glfwSwapBuffers(this.m_glfwWindow);
81         glfwPollEvents();
82     }
83     
84     /**
85      * Sets window cursor.
86      * Params:
87      *      cursor: cursor to set
88      */
89     @nogc
90     public void setCursor(in Cursor cursor) nothrow
91     {
92         if (this.m_currentCursor == cursor)
93         {
94             return;
95         }
96 
97         auto cursorPtr = cursor in this.m_cursors;
98 
99         if (cursorPtr !is null)
100         {
101             this.m_currentCursor = cursor;
102             glfwSetCursor(this.m_glfwWindow, *cursorPtr);
103         }
104     }
105 
106     /**
107      * Hides cursor.
108      */
109     @nogc
110     public void hideCursor() nothrow
111     {
112         glfwSetInputMode(this.m_glfwWindow, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);
113     }
114 
115     @nogc
116     @property nothrow
117     {
118         GLFWwindow* glfwWindow() 
119         {
120             return this.m_glfwWindow;
121         }
122     }
123 }
124 
125 template GLFWCallback(string name, string glfwCallback)
126 {
127     string GLFWCallbackImpl()
128     {
129         enum callbackName = name ~ "Callback";
130         return "@nogc @property public void " ~ name ~ "(" ~ glfwCallback ~ " cb) { glfwSet" ~ callbackName[2..$] ~ "(this.m_glfwWindow, cb); }";
131     }
132 
133     enum GLFWCallback = GLFWCallbackImpl;
134 }