1 module rpui.platform_sdl;
2 
3 version(rpuiSdl2):
4 
5 import std.utf;
6 import std.conv;
7 import std.array;
8 import std..string;
9 
10 import derelict.sdl2.sdl;
11 import derelict.sdl2.ttf;
12 import derelict.sdl2.image;
13 
14 import gapi.opengl;
15 
16 import rpui.events;
17 import rpui.events_observer;
18 import rpui.input;
19 import rpui.platform;
20 
21 extern(C) void platformShowSystemCursor() {
22     SDL_ShowCursor(SDL_ENABLE);
23 }
24 
25 extern(C) void platformHideSystemCursor() {
26     SDL_ShowCursor(SDL_DISABLE);
27 }
28 
29 extern(C) void platformSetMousePosition(void* window, in int x, in int y) {
30     SDL_WarpMouseInWindow(cast(SDL_Window*) window, x, y);
31 }
32 
33 extern(C) float platformGetTicks() {
34     return SDL_GetTicks();
35 }
36 
37 extern(C) bool platformEventLoop(void* window, EventsObserver events) {
38     SDL_Event event;
39 
40     while (SDL_PollEvent(&event)) {
41         if (event.type == SDL_QUIT) {
42             return false;
43         }
44         else if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED) {
45             import std.stdio;
46             int w, h;
47             SDL_GL_GetDrawableSize(cast(SDL_Window*) window, &w, &h);
48             writeln(w, "x", h);
49             events.notify(WindowResizeEvent(event.window.data1, event.window.data2, w, h));
50         }
51         else if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_EXPOSED) {
52             events.notify(WindowExposedEvent());
53         }
54         else if (event.type == SDL_MOUSEMOTION) {
55             const button = createMouseButtonFromSdlState(event.motion.state);
56             events.notify(MouseMoveEvent(event.motion.x, event.motion.y, button));
57         }
58         else if (event.type == SDL_MOUSEBUTTONDOWN) {
59             const button = createMouseButtonFromButtonSdlEvent(event);
60             events.notify(MouseDownEvent(event.button.x, event.button.y, button));
61 
62             switch (event.button.clicks) {
63                 case 2:
64                     events.notify(DblClickEvent(event.button.x, event.button.y, button));
65                     break;
66 
67                 case 3:
68                     events.notify(TripleClickEvent(event.button.x, event.button.y, button));
69                     break;
70 
71                 default:
72                     // Ignore
73             }
74         }
75         else if (event.type == SDL_MOUSEBUTTONUP) {
76             const button = createMouseButtonFromButtonSdlEvent(event);
77             events.notify(MouseUpEvent(event.button.x, event.button.y, button));
78         }
79         else if (event.type == SDL_MOUSEWHEEL) {
80             events.notify(MouseWheelEvent(event.wheel.x, event.wheel.y));
81         }
82         else if (event.type == SDL_TEXTINPUT) {
83             events.notify(TextEnteredEvent(toUTF32(fromStringz(event.text.text.ptr))));
84         }
85         else if (event.type == SDL_KEYDOWN) {
86             try {
87                 const key = to!(KeyCode)(to!(int)(event.key.keysym.sym));
88                 setKeyPressed(key, true);
89                 events.notify(KeyPressedEvent(key));
90             } catch (Exception e) {
91             }
92         }
93         else if (event.type == SDL_KEYUP) {
94             try {
95                 const key = to!(KeyCode)(to!(int)(event.key.keysym.sym));
96                 events.notify(KeyReleasedEvent(key));
97                 setKeyPressed(key, false);
98             } catch (Exception e) {
99             }
100         }
101     }
102 
103     return true;
104 }
105 
106 extern(C) void platformSwapWindow(void* window) {
107     SDL_GL_SwapWindow(cast(SDL_Window*) window);
108 }
109 
110 extern(C) void platformGapiDeleteContext(void* context) {
111     SDL_GL_DeleteContext(context);
112 }
113 
114 extern(C) void platformDestroyWindow(void* window) {
115     SDL_DestroyWindow(cast(SDL_Window*) window);
116 }
117 
118 extern(C) void platformShutdown() {
119     SDL_Quit();
120     TTF_Quit();
121 }
122 
123 extern(C) void platformInit() {
124     // Load shared libraries
125     DerelictGL3.load();
126     DerelictSDL2.load();
127     DerelictSDL2Image.load();
128     DerelictSDL2TTF.load();
129 
130     // Init
131     if (SDL_Init(SDL_INIT_VIDEO) < 0)
132         throw new Error("Failed to init SDL");
133 
134     if (TTF_Init() < 0)
135         throw new Error("Failed to init SDL TTF");
136 
137     SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
138     SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1);
139     SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
140     SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
141     SDL_GL_SetSwapInterval(2);
142 }
143 
144 extern(C) Window platformCreateWindow(in string title, uint width, uint height) {
145     auto window = SDL_CreateWindow(
146         toStringz(title),
147         SDL_WINDOWPOS_CENTERED,
148         SDL_WINDOWPOS_CENTERED,
149         width,
150         height,
151         SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI
152     );
153 
154     if (window == null)
155         throw new Error("SDL Error: " ~ to!string(SDL_GetError()));
156 
157     auto glContext = SDL_GL_CreateContext(window);
158 
159     if (glContext == null)
160         throw new Error("SDL Error: " ~ to!string(SDL_GetError()));
161 
162     SDL_GL_SwapWindow(window);
163     DerelictGL3.reload();
164 
165     return Window(window, glContext);
166 }
167 
168 extern(C) void platformSetClipboardTextUtf8(in string text) {
169     SDL_SetClipboardText(toStringz(text));
170 }
171 
172 extern(C) void platformSetClipboardTextUtf32(in dstring text) {
173     // writeln("PLATFORM COPY: ", data.charString);
174 
175     SDL_SetClipboardText(toStringz(to!string(text)));
176 }
177 
178 extern(C) string platformGetClipboardTextUtf8() {
179     return to!string(fromStringz(SDL_GetClipboardText()));
180 }
181 
182 extern(C) dstring platformGetClipboardTextUtf32() {
183     return to!dstring(fromStringz(SDL_GetClipboardText()));
184 }
185 
186 extern(C) bool hasClipboardText() {
187     return cast(bool) SDL_HasClipboardText();
188 }