summaryrefslogtreecommitdiff
path: root/contrib/SDL-3.2.8/src/video/openvr/SDL_openvrvideo.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/SDL-3.2.8/src/video/openvr/SDL_openvrvideo.c')
-rw-r--r--contrib/SDL-3.2.8/src/video/openvr/SDL_openvrvideo.c1664
1 files changed, 1664 insertions, 0 deletions
diff --git a/contrib/SDL-3.2.8/src/video/openvr/SDL_openvrvideo.c b/contrib/SDL-3.2.8/src/video/openvr/SDL_openvrvideo.c
new file mode 100644
index 0000000..6387c37
--- /dev/null
+++ b/contrib/SDL-3.2.8/src/video/openvr/SDL_openvrvideo.c
@@ -0,0 +1,1664 @@
1/*
2 Simple DirectMedia Layer
3 Copyright (C) 2022 Charles Lohr <charlesl@valvesoftware.com>
4
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any damages
7 arising from the use of this software.
8
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it
11 freely, subject to the following restrictions:
12
13 1. The origin of this software must not be misrepresented; you must not
14 claim that you wrote the original software. If you use this software
15 in a product, an acknowledgment in the product documentation would be
16 appreciated but is not required.
17 2. Altered source versions must be plainly marked as such, and must not be
18 misrepresented as being the original software.
19 3. This notice may not be removed or altered from any source distribution.
20*/
21#include "SDL_internal.h"
22
23#ifdef SDL_VIDEO_DRIVER_OPENVR
24
25#define DEBUG_OPENVR
26
27#include "../../events/SDL_mouse_c.h"
28#include "../../events/SDL_keyboard_c.h"
29#include "../../events/SDL_events_c.h"
30#include "../SDL_sysvideo.h"
31#include "../SDL_pixels_c.h"
32#include "../SDL_egl_c.h"
33#include "SDL_openvrvideo.h"
34
35#include <SDL3/SDL_opengl.h>
36
37#ifdef SDL_VIDEO_DRIVER_WINDOWS
38#include "../windows/SDL_windowsopengles.h"
39#include "../windows/SDL_windowsopengl.h"
40#include "../windows/SDL_windowsvulkan.h"
41#define DEFAULT_OPENGL "OPENGL32.DLL"
42static bool OPENVR_GL_LoadLibrary(SDL_VideoDevice *_this, const char *path);
43static SDL_GLContext OPENVR_GL_CreateContext(SDL_VideoDevice *_this, SDL_Window *window);
44
45struct SDL_GLContextState
46{
47 HGLRC hglrc;
48};
49
50#else
51#include <SDL3/SDL_opengles2_gl2.h>
52#endif
53
54#define MARKER_ID 0
55#define MARKER_STR "vr-marker,frame_end,type,application"
56
57#undef EXTERN_C
58
59// For access to functions that don't get the video data context.
60SDL_VideoData * global_openvr_driver;
61
62static void InitializeMouseFunctions();
63
64struct SDL_CursorData
65{
66 unsigned texture_id_handle;
67 int hot_x, hot_y;
68 int w, h;
69};
70
71// GL Extensions for functions we will be using.
72static void (APIENTRY *ov_glGenFramebuffers)(GLsizei n, GLuint *framebuffers);
73static void (APIENTRY *ov_glGenRenderbuffers)(GLsizei n, GLuint *renderbuffers);
74static void (APIENTRY *ov_glBindFramebuffer)(GLenum target, GLuint framebuffer);
75static void (APIENTRY *ov_glBindRenderbuffer)(GLenum target, GLuint renderbuffer);
76static void (APIENTRY *ov_glRenderbufferStorage)(GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
77static void (APIENTRY *ov_glFramebufferRenderbuffer)(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
78static void (APIENTRY *ov_glFramebufferTexture2D)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
79static GLenum (APIENTRY *ov_glCheckNamedFramebufferStatus)(GLuint framebuffer, GLenum target);
80static GLenum (APIENTRY *ov_glGetError)();
81static void (APIENTRY *ov_glFlush)();
82static void (APIENTRY *ov_glFinish)();
83static void (APIENTRY *ov_glGenTextures)(GLsizei n, GLuint *textures);
84static void (APIENTRY *ov_glDeleteTextures)(GLsizei n, GLuint *textures);
85static void (APIENTRY *ov_glTexParameterf)(GLenum target, GLenum pname, GLfloat param);
86static void (APIENTRY *ov_glTexParameteri)(GLenum target, GLenum pname, GLenum param);
87static void (APIENTRY *ov_glTexImage2D)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *data);
88static void (APIENTRY *ov_glBindTexture)(GLenum target, GLuint texture);
89static void (APIENTRY *ov_glDrawBuffers)(GLsizei n, const GLenum *bufs);
90static void (APIENTRY *ov_glGetIntegerv)(GLenum pname, GLint * data);
91static const GLubyte *(APIENTRY *ov_glGetStringi)(GLenum name, GLuint index);
92static void (APIENTRY *ov_glClear)(GLbitfield mask);
93static void (APIENTRY *ov_glClearColor)(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
94static void (APIENTRY *ov_glColorMask)(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);
95static void (APIENTRY *ov_glDebugMessageInsert)(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const char *message);
96
97#ifdef SDL_VIDEO_DRIVER_WINDOWS
98static PROC (*ov_wglGetProcAddress)(LPCSTR);
99static HGLRC (*ov_wglCreateContext)(HDC);
100static BOOL (*ov_wglDeleteContext)(HGLRC);
101static BOOL (*ov_wglMakeCurrent)(HDC, HGLRC);
102//static HGLRC (*ov_wglGetCurrentContext)(void);
103#endif
104
105
106#define OPENVR_DEFAULT_WIDTH 1920
107#define OPENVR_DEFAULT_HEIGHT 1080
108
109#define OPENVR_SetupProc(proc) { proc = (void*)SDL_GL_GetProcAddress((#proc)+3); if (!proc) { failed_extension = (#proc)+3; } }
110
111static bool OPENVR_InitExtensions(SDL_VideoDevice *_this)
112{
113 if (!ov_glGetError) {
114 const char * failed_extension = 0;
115 OPENVR_SetupProc(ov_glGenFramebuffers);
116 OPENVR_SetupProc(ov_glGenRenderbuffers);
117 OPENVR_SetupProc(ov_glBindFramebuffer);
118 OPENVR_SetupProc(ov_glBindRenderbuffer);
119 OPENVR_SetupProc(ov_glRenderbufferStorage);
120 OPENVR_SetupProc(ov_glFramebufferRenderbuffer);
121 OPENVR_SetupProc(ov_glFramebufferTexture2D);
122 OPENVR_SetupProc(ov_glCheckNamedFramebufferStatus);
123 OPENVR_SetupProc(ov_glGetError);
124 OPENVR_SetupProc(ov_glFlush);
125 OPENVR_SetupProc(ov_glFinish);
126 OPENVR_SetupProc(ov_glGenTextures);
127 OPENVR_SetupProc(ov_glDeleteTextures);
128 OPENVR_SetupProc(ov_glTexParameterf);
129 OPENVR_SetupProc(ov_glTexParameteri);
130 OPENVR_SetupProc(ov_glTexImage2D);
131 OPENVR_SetupProc(ov_glBindTexture);
132 OPENVR_SetupProc(ov_glDrawBuffers);
133 OPENVR_SetupProc(ov_glClear);
134 OPENVR_SetupProc(ov_glClearColor);
135 OPENVR_SetupProc(ov_glColorMask);
136 OPENVR_SetupProc(ov_glGetStringi);
137 OPENVR_SetupProc(ov_glGetIntegerv);
138 OPENVR_SetupProc(ov_glDebugMessageInsert);
139 if (failed_extension) {
140 return SDL_SetError("Error loading GL extension for %s", failed_extension);
141 }
142 }
143 return true;
144}
145
146static bool OPENVR_SetOverlayError(EVROverlayError e)
147{
148 switch (e) {
149#define CASE(X) case EVROverlayError_VROverlayError_##X: return SDL_SetError("VROverlayError %s", #X)
150 CASE(UnknownOverlay);
151 CASE(InvalidHandle);
152 CASE(PermissionDenied);
153 CASE(OverlayLimitExceeded);
154 CASE(WrongVisibilityType);
155 CASE(KeyTooLong);
156 CASE(NameTooLong);
157 CASE(KeyInUse);
158 CASE(WrongTransformType);
159 CASE(InvalidTrackedDevice);
160 CASE(InvalidParameter);
161 CASE(ThumbnailCantBeDestroyed);
162 CASE(ArrayTooSmall);
163 CASE(RequestFailed);
164 CASE(InvalidTexture);
165 CASE(UnableToLoadFile);
166 CASE(KeyboardAlreadyInUse);
167 CASE(NoNeighbor);
168 CASE(TooManyMaskPrimitives);
169 CASE(BadMaskPrimitive);
170 CASE(TextureAlreadyLocked);
171 CASE(TextureLockCapacityReached);
172 CASE(TextureNotLocked);
173 CASE(TimedOut);
174#undef CASE
175 default:
176 return SDL_SetError("Unknown VROverlayError %d", e);
177 }
178}
179
180static bool OPENVR_InitializeOverlay(SDL_VideoDevice *_this, SDL_Window *window);
181
182static bool OPENVR_VideoInit(SDL_VideoDevice *_this)
183{
184 SDL_VideoData *data = (SDL_VideoData *)_this->internal;
185
186 const char * hintWidth = SDL_GetHint("SDL_DEFAULT_WIDTH");
187 const char * hintHeight = SDL_GetHint("SDL_DEFAULT_HEIGHT");
188 const char * hintFPS = SDL_GetHint("SDL_DEFAULT_FPS");
189 int width = hintWidth ? SDL_atoi(hintWidth) : 0;
190 int height = hintHeight ? SDL_atoi(hintHeight) : 0;
191 int fps = hintFPS ? SDL_atoi(hintFPS) : 0;
192
193 SDL_VideoDisplay display;
194 SDL_zero(display);
195 display.desktop_mode.format = SDL_PIXELFORMAT_RGBA32;
196 display.desktop_mode.w = OPENVR_DEFAULT_WIDTH;
197 display.desktop_mode.h = OPENVR_DEFAULT_HEIGHT;
198 display.natural_orientation = SDL_ORIENTATION_LANDSCAPE;
199 display.current_orientation = SDL_ORIENTATION_LANDSCAPE;
200 display.content_scale = 1.0f;
201 if (height > 0 && width > 0) {
202 display.desktop_mode.w = width;
203 display.desktop_mode.h = height;
204 }
205 if (fps) {
206 display.desktop_mode.refresh_rate = fps;
207 } else {
208 display.desktop_mode.refresh_rate = data->oSystem->GetFloatTrackedDeviceProperty(k_unTrackedDeviceIndex_Hmd, ETrackedDeviceProperty_Prop_DisplayFrequency_Float, 0);
209 }
210
211 display.internal = (SDL_DisplayData *)data;
212 display.name = (char*)"OpenVRDisplay";
213 SDL_AddVideoDisplay(&display, false);
214
215 return true;
216}
217
218static void OPENVR_VideoQuit(SDL_VideoDevice *_this)
219{
220 SDL_VideoData *videodata = (SDL_VideoData *)_this->internal;
221 if (videodata->bDidCreateOverlay && videodata->overlayID != 0) {
222 videodata->oOverlay->DestroyOverlay(videodata->overlayID);
223 }
224}
225
226static void OPENVR_Destroy(SDL_VideoDevice *device)
227{
228 SDL_VideoData *data = device->internal;
229
230#ifdef SDL_PLATFORM_WINDOWS
231 SDL_UnregisterApp();
232#endif
233
234 if (data) {
235 if (data->openVRLIB) {
236 SDL_UnloadObject(data->openVRLIB);
237 }
238 }
239 SDL_free(device->internal);
240 SDL_free(device);
241}
242
243static uint32_t *ImageSDLToOpenVRGL(SDL_Surface * surf, bool bFlipY)
244{
245 int w = surf->w;
246 int h = surf->h;
247 int pitch = surf->pitch;
248 int x, y;
249 uint32_t * pxd = SDL_malloc(4 * surf->w * surf->h);
250 for(y = 0; y < h; y++) {
251 uint32_t * iline = (uint32_t*)&(((uint8_t*)surf->pixels)[y*pitch]);
252 uint32_t * oline = &pxd[(bFlipY?(h-y-1):y)*w];
253 for(x = 0; x < w; x++)
254 {
255 uint32_t pr = iline[x];
256 oline[x] = (pr & 0xff00ff00) | ((pr & 0xff) << 16) | ((pr & 0xff0000)>>16);
257 }
258 }
259 return pxd;
260}
261
262static bool OPENVR_CheckRenderbuffer(SDL_VideoDevice *_this)
263{
264 SDL_VideoData *videodata = (SDL_VideoData *)_this->internal;
265
266 if (videodata->targw == 0 || videodata->targh == 0) {
267 videodata->targw = OPENVR_DEFAULT_WIDTH;
268 videodata->targh = OPENVR_DEFAULT_HEIGHT;
269 }
270
271 if (videodata->targh != videodata->last_targh
272 || videodata->targw != videodata->last_targw) {
273
274 struct HmdVector2_t ms;
275 int status;
276
277 if (videodata->fbo <= 0) {
278 ov_glGenFramebuffers(1, &videodata->fbo);
279 ov_glGenRenderbuffers(1, &videodata->rbo);
280 ov_glGenTextures(1, &videodata->overlaytexture);
281 }
282
283 // Generate the OpenGL Backing buffers/etc.
284 ov_glBindFramebuffer(GL_FRAMEBUFFER, videodata->fbo);
285 ov_glBindRenderbuffer(GL_RENDERBUFFER, videodata->rbo);
286 ov_glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, videodata->targw, videodata->targh);
287 ov_glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, videodata->rbo);
288 ov_glBindTexture(GL_TEXTURE_2D, videodata->overlaytexture);
289 ov_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
290 ov_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
291 ov_glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, videodata->targw, videodata->targh, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
292 ov_glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, videodata->overlaytexture, 0);
293 status = ov_glCheckNamedFramebufferStatus(videodata->fbo, GL_FRAMEBUFFER);
294 if (status != GL_FRAMEBUFFER_COMPLETE) {
295 return SDL_SetError("OPENVR: Can't generate overlay buffer");
296 }
297 ov_glBindFramebuffer(GL_FRAMEBUFFER, 0);
298
299 ms.v[0] = (float)videodata->targw;
300 ms.v[1] = (float)videodata->targh;
301 videodata->oOverlay->SetOverlayMouseScale(videodata->overlayID, &ms);
302
303 videodata->last_targh = videodata->targh;
304 videodata->last_targw = videodata->targw;
305 }
306 return true;
307}
308
309static bool OPENVR_VirtualControllerRumble(void *userdata, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
310{
311 // On XBOX Controllers Low/High maps to Left/Right
312 SDL_VideoData *videodata = (SDL_VideoData *)userdata;
313
314 const float k_flIntensity = 320.f; // Maximum frequency
315 float flLeftFrequency = (float)low_frequency_rumble * k_flIntensity / 65535.f;
316 float flRightFrequency = (float)high_frequency_rumble * k_flIntensity / 65535.f;
317 float flDurationSeconds = 2.f;
318 float flAmplitude = 1.f;
319
320 videodata->oInput->TriggerHapticVibrationAction(videodata->input_action_handles_haptics[0], 0, flDurationSeconds, flLeftFrequency, flAmplitude, 0);
321 videodata->oInput->TriggerHapticVibrationAction(videodata->input_action_handles_haptics[1], 0, flDurationSeconds, flRightFrequency, flAmplitude, 0);
322
323 return true;
324}
325
326static bool OPENVR_VirtualControllerRumbleTriggers(void *userdata, Uint16 left_rumble, Uint16 right_rumble)
327{
328 SDL_VideoData *videodata = (SDL_VideoData *)userdata;
329 videodata->oInput->TriggerHapticVibrationAction(videodata->input_action_handles_haptics[0], 0, 0.1f, left_rumble, 1.0, 0);
330 videodata->oInput->TriggerHapticVibrationAction(videodata->input_action_handles_haptics[1], 0, 0.1f, right_rumble, 1.0, 0);
331 return true;
332}
333
334static void OPENVR_VirtualControllerUpdate(void *userdata)
335{
336 SDL_VideoData *videodata = (SDL_VideoData *)userdata;
337 SDL_Joystick * joystick = videodata->virtual_joystick;
338 InputDigitalActionData_t digital_input_action;
339 InputAnalogActionData_t analog_input_action;
340 EVRInputError e;
341#ifdef DEBUG_OPENVR
342 //char cts[10240];
343 //char * ctsx = cts;
344#endif
345 VRActiveActionSet_t actionSet = { 0 };
346 actionSet.ulActionSet = videodata->input_action_set;
347 e = videodata->oInput->UpdateActionState(&actionSet, sizeof(actionSet), 1);
348 if (e)
349 {
350#ifdef DEBUG_OPENVR
351 SDL_Log("ERROR: Failed to update action state");
352#endif
353 return;
354 }
355
356 for (int d = 0; d < videodata->input_action_handles_buttons_count; d++)
357 {
358 if (videodata->input_action_handles_buttons[d] == k_ulInvalidActionHandle)
359 continue;
360 e = videodata->oInput->GetDigitalActionData(videodata->input_action_handles_buttons[d], &digital_input_action, sizeof(digital_input_action), k_ulInvalidInputValueHandle);
361 if (e)
362 {
363#ifdef DEBUG_OPENVR
364 SDL_Log("ERROR: Failed to get digital action data: %d", d);
365#endif
366 return;
367 }
368 SDL_SetJoystickVirtualButton(joystick, d, digital_input_action.bState);
369#ifdef DEBUG_OPENVR
370 //ctsx+=sprintf(ctsx,"%d", digital_input_action.bState);
371#endif
372 }
373
374 // Left Stick
375 e = videodata->oInput->GetAnalogActionData(videodata->input_action_handles_axes[0], &analog_input_action, sizeof(analog_input_action), k_ulInvalidInputValueHandle);
376 if (e)
377 {
378#ifdef DEBUG_OPENVR
379 SDL_Log("ERROR: Failed to get analog action data: left stick");
380#endif
381 return;
382 }
383 SDL_SetJoystickVirtualAxis(joystick, SDL_GAMEPAD_AXIS_LEFTX, (Sint16)(analog_input_action.x * SDL_JOYSTICK_AXIS_MAX));
384 SDL_SetJoystickVirtualAxis(joystick, SDL_GAMEPAD_AXIS_LEFTY, (Sint16)(-analog_input_action.y * SDL_JOYSTICK_AXIS_MAX));
385
386 // Right Stick
387 e = videodata->oInput->GetAnalogActionData(videodata->input_action_handles_axes[1], &analog_input_action, sizeof(analog_input_action), k_ulInvalidInputValueHandle);
388 if (e)
389 {
390#ifdef DEBUG_OPENVR
391 SDL_Log("ERROR: Failed to get analog action data: right stick");
392#endif
393 return;
394 }
395 SDL_SetJoystickVirtualAxis(joystick, SDL_GAMEPAD_AXIS_RIGHTX, (Sint16)(analog_input_action.x * SDL_JOYSTICK_AXIS_MAX));
396 SDL_SetJoystickVirtualAxis(joystick, SDL_GAMEPAD_AXIS_RIGHTY, (Sint16)(-analog_input_action.y * SDL_JOYSTICK_AXIS_MAX));
397
398 // Left Trigger
399 e = videodata->oInput->GetAnalogActionData(videodata->input_action_handles_axes[2], &analog_input_action, sizeof(analog_input_action), k_ulInvalidInputValueHandle);
400 if (e)
401 {
402#ifdef DEBUG_OPENVR
403 SDL_Log("ERROR: Failed to get analog action data: left trigger");
404#endif
405 return;
406 }
407 SDL_SetJoystickVirtualAxis(joystick, SDL_GAMEPAD_AXIS_LEFT_TRIGGER, (Sint16)((analog_input_action.x * 2.0f - 1.0f) * SDL_JOYSTICK_AXIS_MAX));
408
409 // Right Trigger
410 e = videodata->oInput->GetAnalogActionData(videodata->input_action_handles_axes[3], &analog_input_action, sizeof(analog_input_action), k_ulInvalidInputValueHandle);
411 if (e)
412 {
413#ifdef DEBUG_OPENVR
414 SDL_Log("ERROR: Failed to get analog action data: right trigger");
415#endif
416 return;
417 }
418 SDL_SetJoystickVirtualAxis(joystick, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER, (Sint16)((analog_input_action.x * 2.0f - 1.0f) * SDL_JOYSTICK_AXIS_MAX));
419
420#if 0
421 for (a = 0; a < videodata->input_action_handles_axes_count; a++)
422 {
423 float xval = 0.0f;
424 e = videodata->oInput->GetAnalogActionData(videodata->input_action_handles_axes[a], &analog_input_action, sizeof(analog_input_action), k_ulInvalidInputValueHandle);
425 if (e) goto updatefail;
426 xval = analog_input_action.x;
427 if (a == SDL_CONTROLLER_AXIS_LEFTY || a == SDL_CONTROLLER_AXIS_RIGHTY)
428 xval *= -1.0f;
429 if (a == SDL_GAMEPAD_AXIS_LEFT_TRIGGER || a == SDL_GAMEPAD_AXIS_RIGHT_TRIGGER)
430 xval = xval * 2.0f - 1.0f;
431 //SDL_SetJoystickVirtualAxis(joystick, a, analog_input_action.x*32767);
432 xval *= SDL_JOYSTICK_AXIS_MAX;
433 SDL_SetJoystickVirtualAxis(joystick, a, xval);
434#ifdef DEBUG_OPENVR
435 //ctsx+=sprintf(ctsx,"[%f]", analog_input_action.x);
436#endif
437 }
438#endif
439#ifdef DEBUG_OPENVR
440 //SDL_Log("Debug Input States: %s", cts);
441#endif
442 return;
443}
444
445static bool OPENVR_SetupJoystickBasedOnLoadedActionManifest(SDL_VideoData * videodata)
446{
447 SDL_VirtualJoystickDesc desc;
448 int virtual_index;
449
450 EVRInputError e = 0;
451
452 char * k_pchBooleanActionPaths[SDL_GAMEPAD_BUTTON_COUNT] = {
453 "/actions/virtualgamepad/in/a",
454 "/actions/virtualgamepad/in/b",
455 "/actions/virtualgamepad/in/x",
456 "/actions/virtualgamepad/in/y",
457 "/actions/virtualgamepad/in/back",
458 "/actions/virtualgamepad/in/guide",
459 "/actions/virtualgamepad/in/start",
460 "/actions/virtualgamepad/in/stick_click_left",
461 "/actions/virtualgamepad/in/stick_click_right",
462 "/actions/virtualgamepad/in/shoulder_left",
463 "/actions/virtualgamepad/in/shoulder_right",
464 "/actions/virtualgamepad/in/dpad_up",
465 "/actions/virtualgamepad/in/dpad_down",
466 "/actions/virtualgamepad/in/dpad_left",
467 "/actions/virtualgamepad/in/dpad_right",
468 "/actions/virtualgamepad/in/misc_1",
469 "/actions/virtualgamepad/in/paddle_1",
470 "/actions/virtualgamepad/in/paddle_2",
471 "/actions/virtualgamepad/in/paddle_3",
472 "/actions/virtualgamepad/in/paddle_4",
473 "/actions/virtualgamepad/in/touchpad_click",
474 "/actions/virtualgamepad/in/misc_2",
475 "/actions/virtualgamepad/in/misc_3",
476 "/actions/virtualgamepad/in/misc_4",
477 "/actions/virtualgamepad/in/misc_5",
478 "/actions/virtualgamepad/in/misc_6",
479 };
480 char * k_pchAnalogActionPaths[4] = {
481 "/actions/virtualgamepad/in/stick_left",
482 "/actions/virtualgamepad/in/stick_right",
483 "/actions/virtualgamepad/in/trigger_left",
484 "/actions/virtualgamepad/in/trigger_right",
485 };
486
487 if ((e = videodata->oInput->GetActionSetHandle("/actions/virtualgamepad", &videodata->input_action_set)) != EVRInputError_VRInputError_None)
488 {
489#ifdef DEBUG_OPENVR
490 SDL_Log("ERROR: Failed to get action set handle: %d", e);
491#endif
492 return SDL_SetError("Failed to get action set handle");
493 }
494
495 videodata->input_action_handles_buttons_count = sizeof(k_pchBooleanActionPaths) / sizeof(k_pchBooleanActionPaths[0]);
496 videodata->input_action_handles_buttons = SDL_malloc(videodata->input_action_handles_buttons_count * sizeof(VRActionHandle_t));
497
498 for (int i = 0; i < videodata->input_action_handles_buttons_count; i++)
499 {
500 e = videodata->oInput->GetActionHandle(k_pchBooleanActionPaths[i], &videodata->input_action_handles_buttons[i]);
501 if (e)
502 {
503 SDL_Log("ERROR: Failed to get button action %d ('%s')", i, k_pchBooleanActionPaths[i]);
504 return SDL_SetError("ERROR: Failed to get button action");
505 }
506 }
507
508 videodata->input_action_handles_axes_count = sizeof(k_pchAnalogActionPaths) / sizeof(k_pchAnalogActionPaths[0]);
509 videodata->input_action_handles_axes = SDL_malloc(videodata->input_action_handles_axes_count * sizeof(VRActionHandle_t));
510
511 for (int i = 0; i < videodata->input_action_handles_axes_count; i++)
512 {
513 e = videodata->oInput->GetActionHandle(k_pchAnalogActionPaths[i], &videodata->input_action_handles_axes[i]);
514 if (e)
515 {
516 SDL_Log("ERROR: Failed to get analog action %d ('%s')", i, k_pchAnalogActionPaths[i]);
517 return SDL_SetError("ERROR: Failed to get analog action");
518 }
519 }
520
521 e = videodata->oInput->GetActionHandle("/actions/virtualgamepad/out/haptic_left", &videodata->input_action_handles_haptics[0]);
522 e |= videodata->oInput->GetActionHandle("/actions/virtualgamepad/out/haptic_right", &videodata->input_action_handles_haptics[1]);
523 if (e)
524 {
525#ifdef DEBUG_OPENVR
526 SDL_Log("ERROR: Failed to get haptics action");
527#endif
528 return SDL_SetError("ERROR: Failed to get haptics action");
529 }
530
531 // Create a virtual joystick.
532 SDL_INIT_INTERFACE(&desc);
533 desc.type = SDL_JOYSTICK_TYPE_GAMEPAD;
534 desc.naxes = SDL_GAMEPAD_AXIS_COUNT;
535 desc.nbuttons = SDL_GAMEPAD_BUTTON_COUNT;
536 desc.Rumble = OPENVR_VirtualControllerRumble;
537 desc.RumbleTriggers = OPENVR_VirtualControllerRumbleTriggers;
538 desc.Update = OPENVR_VirtualControllerUpdate;
539 desc.userdata = videodata;
540 virtual_index = SDL_AttachVirtualJoystick(&desc);
541
542 if (virtual_index < 0) {
543 return SDL_SetError("OPENVR: Couldn't open virtual joystick device: %s", SDL_GetError());
544 } else {
545 videodata->virtual_joystick = SDL_OpenJoystick(virtual_index);
546 if (!videodata->virtual_joystick) {
547 return SDL_SetError("OPENVR: Couldn't open virtual joystick device: %s", SDL_GetError());
548 }
549 }
550
551#ifdef DEBUG_OPENVR
552 SDL_Log("Loaded virtual joystick with %d buttons and %d axes", videodata->input_action_handles_buttons_count, videodata->input_action_handles_axes_count);
553#endif
554
555 return false;
556}
557
558static bool OPENVR_InitializeOverlay(SDL_VideoDevice *_this,SDL_Window *window)
559{
560 SDL_VideoData *videodata = (SDL_VideoData *)_this->internal;
561
562 // Wait til here, to make sure we have our context setup correctly.
563 if (!OPENVR_InitExtensions(_this)) {
564 return false;
565 }
566
567 // Generate the overlay.
568 {
569 const char * hint = SDL_GetHint("SDL_OPENVR_OVERLAY_NAME");
570 char * cursorname = 0;
571 if (!hint) {
572 hint = "sdl";
573 }
574
575 SDL_asprintf(&videodata->sOverlayName, "%s-overlay",hint);
576 if (!videodata->sOverlayName) {
577 return false;
578 }
579 SDL_asprintf(&cursorname, "%s-cursor",hint);
580 if (!cursorname) {
581 return false;
582 }
583
584 EVROverlayError result = videodata->oOverlay->CreateDashboardOverlay(videodata->sOverlayName,
585 window->title, &videodata->overlayID, &videodata->thumbID);
586 if (result != EVROverlayError_VROverlayError_None) {
587 SDL_free(cursorname);
588 return SDL_SetError("Could not create dashboard overlay (%d)", result );
589 }
590 result = videodata->oOverlay->CreateOverlay(cursorname, window->title, &videodata->cursorID);
591 if (result != EVROverlayError_VROverlayError_None) {
592 SDL_free(cursorname);
593 return SDL_SetError("Could not create cursor overlay (%d)", result );
594 }
595 SDL_PropertiesID props = SDL_GetWindowProperties(window);
596 SDL_SetNumberProperty(props, SDL_PROP_WINDOW_OPENVR_OVERLAY_ID, videodata->overlayID);
597 SDL_free(cursorname);
598 videodata->bHasShownOverlay = false;
599 }
600 {
601 const char * hint = SDL_GetHint("SDL_OPENVR_OVERLAY_PANEL_WIDTH");
602 float fWidth = hint ? (float)SDL_atof(hint) : 1.0f;
603 videodata->oOverlay->SetOverlayWidthInMeters(videodata->overlayID, fWidth);
604 }
605 {
606 const char * hint = SDL_GetHint("SDL_OPENVR_CURSOR_WIDTH");
607 // Default is what SteamVR Does
608 float fCursorWidth = hint ? (float)SDL_atof(hint) : 0.06f;
609 videodata->oOverlay->SetOverlayWidthInMeters(videodata->cursorID, fCursorWidth * 0.5f);
610 }
611 {
612 const char * hint = SDL_GetHint("SDL_OPENVR_WINDOW_ICON_FILE");
613 videodata->bIconOverridden = false;
614 if (hint) {
615 char * tmpcopy = SDL_strdup(hint);
616 EVROverlayError err = videodata->oOverlay->SetOverlayFromFile(videodata->thumbID, tmpcopy);
617 SDL_free(tmpcopy);
618 if (err == EVROverlayError_VROverlayError_None) {
619 videodata->bIconOverridden = SDL_GetHintBoolean("SDL_OPENVR_WINDOW_ICON_OVERRIDE",false);
620 }
621 }
622 }
623 {
624 VRTextureBounds_t bounds;
625 bounds.uMin = 0;
626 bounds.uMax = 1;
627 bounds.vMin = 0;
628 bounds.vMax = 1;
629 videodata->oOverlay->SetOverlayTextureBounds(videodata->overlayID, &bounds);
630 }
631
632 if (!OPENVR_CheckRenderbuffer(_this)) {
633 return false;
634 }
635
636
637 global_openvr_driver = videodata;
638 InitializeMouseFunctions();
639
640 // Actually show the overlay.
641 videodata->oOverlay->SetOverlayFlag(videodata->overlayID, 1<<23, true); //vr::VROverlayFlags_EnableControlBar
642 videodata->oOverlay->SetOverlayFlag(videodata->overlayID, 1<<24, true); //vr::VROverlayFlags_EnableControlBarKeyboard
643 videodata->oOverlay->SetOverlayFlag(videodata->overlayID, 1<<25, true); //vr::VROverlayFlags_EnableControlBarClose
644 videodata->oOverlay->SetOverlayName(videodata->overlayID, window->title);
645
646 videodata->bDidCreateOverlay = true;
647 videodata->window = window;
648
649 return true;
650}
651
652
653static bool OPENVR_SetupFrame(SDL_VideoDevice *_this, SDL_Window *window)
654{
655 SDL_VideoData *videodata = (SDL_VideoData *)_this->internal;
656 static const GLenum buffers[8] = { GL_COLOR_ATTACHMENT0_EXT };
657
658 videodata->is_buffer_rendering = true;
659
660#ifdef DEBUG_OPENVR
661 {
662 int error = ov_glGetError();
663 if (error)
664 SDL_Log("Found GL Error before beginning frame: %d / (Framebuffer:%d)", error, ov_glCheckNamedFramebufferStatus(videodata->fbo, GL_FRAMEBUFFER));
665 }
666#endif
667
668 ov_glBindFramebuffer(GL_FRAMEBUFFER, videodata->fbo);
669 ov_glDrawBuffers(1, buffers);
670
671 // Set the alpha channel for non-transparent windows
672 if (!(window->flags & SDL_WINDOW_TRANSPARENT)) {
673 ov_glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
674 ov_glColorMask(false, false, false, true);
675 ov_glClear(GL_COLOR_BUFFER_BIT);
676 ov_glColorMask(true, true, true, true);
677 }
678
679 ov_glBindTexture( GL_TEXTURE_2D, videodata->saved_texture_state );
680
681 return true;
682}
683
684static bool OPENVR_ReleaseFrame(SDL_VideoDevice *_this)
685{
686 SDL_VideoData *videodata = (SDL_VideoData *)_this->internal;
687 ov_glGetIntegerv(GL_TEXTURE_BINDING_2D, &videodata->saved_texture_state);
688
689 if (!ov_glGetError) {
690 return true;
691 }
692
693 if (!videodata->is_buffer_rendering) {
694 return true;
695 }
696
697#ifdef DEBUG_OPENVR
698 {
699 int error = ov_glGetError();
700 if (error) {
701 SDL_Log("Found GL Error before release frame: %d / (Framebuffer:%d)", error, ov_glCheckNamedFramebufferStatus(videodata->fbo, GL_FRAMEBUFFER));
702 }
703 }
704#endif
705
706 videodata->is_buffer_rendering = false;
707
708 ov_glBindFramebuffer(GL_FRAMEBUFFER, 0);
709
710 if (videodata->overlaytexture != 0 &&
711 videodata->targh == videodata->last_targh &&
712 videodata->targw == videodata->last_targw) {
713 // Only submit frames to OpenVR if the textu re exists.
714 struct Texture_t tex;
715
716 // Setup a Texture_t object to send in the texture.
717 tex.eColorSpace = EColorSpace_ColorSpace_Auto;
718 tex.eType = ETextureType_TextureType_OpenGL;
719 tex.handle = (void *)(intptr_t)videodata->overlaytexture;
720
721 // Send texture into OpenVR as the overlay.
722 videodata->oOverlay->SetOverlayTexture(videodata->overlayID, &tex);
723 }
724
725 if (!videodata->bHasShownOverlay && videodata->bDidCreateOverlay) {
726 videodata->oOverlay->ShowDashboard(videodata->sOverlayName);
727 videodata->bHasShownOverlay = true;
728 }
729
730 if (videodata->renderdoc_debugmarker_frame_end) {
731 ov_glDebugMessageInsert(GL_DEBUG_SOURCE_APPLICATION,
732 GL_DEBUG_TYPE_MARKER, MARKER_ID, GL_DEBUG_SEVERITY_NOTIFICATION, -1,
733 MARKER_STR);
734 }
735
736 return OPENVR_CheckRenderbuffer(_this);
737}
738
739static void OPENVR_HandleResize(SDL_VideoDevice *_this, int w, int h)
740{
741 SDL_VideoData *data = (SDL_VideoData *)_this->internal;
742 data->targw = w;
743 data->targh = h;
744}
745
746static bool OPENVR_SetDisplayMode(SDL_VideoDevice *_this, SDL_VideoDisplay *display, SDL_DisplayMode *mode)
747{
748 return true;
749}
750
751
752#ifdef SDL_VIDEO_DRIVER_WINDOWS
753static LRESULT CALLBACK OpenVRVideoWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
754{
755 switch (msg) {
756 case WM_DESTROY:
757 return 0;
758 }
759 return DefWindowProc(hwnd, msg, wParam, lParam);
760}
761
762static bool OPENVR_GL_LoadLibrary(SDL_VideoDevice *_this, const char *path)
763{
764 if (path == NULL) {
765 path = SDL_GetHint(SDL_HINT_OPENGL_LIBRARY);
766 }
767
768 if (path == NULL) {
769 path = DEFAULT_OPENGL;
770 }
771 _this->gl_config.dll_handle = SDL_LoadObject(path);
772 if (!_this->gl_config.dll_handle) {
773 return false;
774 }
775 SDL_strlcpy(_this->gl_config.driver_path, path,
776 SDL_arraysize(_this->gl_config.driver_path));
777
778 // Allocate OpenGL memory
779 _this->gl_data = (struct SDL_GLDriverData *)SDL_calloc(1, sizeof(struct SDL_GLDriverData));
780 if (!_this->gl_data) {
781 return false;
782 }
783 _this->gl_config.driver_loaded = true;
784
785 return true;
786}
787
788static SDL_FunctionPointer OPENVR_GL_GetProcAddress(SDL_VideoDevice *_this, const char *proc)
789{
790 SDL_FunctionPointer result = NULL;
791 if (ov_wglGetProcAddress) {
792 result = (SDL_FunctionPointer)ov_wglGetProcAddress(proc);
793 if (result) {
794 return result;
795 }
796 }
797
798 return SDL_LoadFunction(_this->gl_config.dll_handle, proc);
799}
800
801static void OPENVR_GL_UnloadLibrary(SDL_VideoDevice *_this)
802{
803 SDL_GL_UnloadLibrary();
804}
805
806static SDL_GLContext OPENVR_GL_CreateContext(SDL_VideoDevice *_this, SDL_Window *window)
807{
808 GLint numExtensions;
809 int i;
810 SDL_VideoData *videodata = (SDL_VideoData *)_this->internal;
811 if (!videodata->hglrc) {
812 // Crate a surfaceless EGL Context
813 HWND hwnd;
814
815 WNDCLASSA wnd;
816 wnd.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
817 wnd.lpfnWndProc = OpenVRVideoWndProc;
818 wnd.cbClsExtra = 0;
819 wnd.cbWndExtra = 0;
820 wnd.hInstance = GetModuleHandle(NULL);
821 wnd.hIcon = LoadIcon(NULL, IDI_APPLICATION);
822 wnd.hCursor = LoadCursor(NULL, IDC_ARROW);
823 wnd.hbrBackground = (HBRUSH)(COLOR_BACKGROUND);
824 wnd.lpszMenuName = NULL;
825 wnd.lpszClassName = "SDL_openvrvideo_classname";
826 RegisterClassA(&wnd);
827 hwnd = CreateWindowA("SDL_openvrvideo_classname", "SDL_openvrvideo_windowname", (WS_OVERLAPPEDWINDOW), 0, 0,
828 100, 100, NULL, NULL, GetModuleHandle(NULL), NULL);
829
830 MSG msg;
831 while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
832 TranslateMessage(&msg);
833 DispatchMessage(&msg);
834 }
835
836 videodata->hdc = GetDC(hwnd);
837
838 static PIXELFORMATDESCRIPTOR pfd =
839 {
840 sizeof(PIXELFORMATDESCRIPTOR),
841 1,
842 PFD_DRAW_TO_WINDOW |
843 PFD_SUPPORT_OPENGL |
844 PFD_DOUBLEBUFFER,
845 PFD_TYPE_RGBA,
846 24,
847 8, 0, 8, 8, 8, 16,
848 8,
849 24,
850 32,
851 8, 8, 8, 8,
852 16,
853 0,
854 0,
855 PFD_MAIN_PLANE,
856 0,
857 0, 0, 0
858 };
859 GLuint PixelFormat = ChoosePixelFormat(videodata->hdc, &pfd);
860 if (!SetPixelFormat(videodata->hdc, PixelFormat, &pfd)) {
861 SDL_SetError( "Could not set pixel format" );
862 return NULL;
863 }
864 HMODULE opengl = GetModuleHandleA(DEFAULT_OPENGL);
865 if (!opengl) {
866 SDL_SetError("Could not open OpenGL Library %s", DEFAULT_OPENGL);
867 return NULL;
868 }
869
870 ov_wglMakeCurrent = (BOOL(*)(HDC, HGLRC))GetProcAddress(opengl, "wglMakeCurrent");
871 ov_wglCreateContext = (HGLRC(*)(HDC))GetProcAddress(opengl, "wglCreateContext");
872 ov_wglGetProcAddress = (PROC(*)(LPCSTR))GetProcAddress(opengl, "wglGetProcAddress");
873 ov_wglDeleteContext = (BOOL(*)(HGLRC))GetProcAddress(opengl, "wglDeleteContext");
874 if (!ov_wglMakeCurrent || !ov_wglCreateContext) {
875 SDL_SetError("Cannot get wgl context procs(%p, %p)", ov_wglMakeCurrent, ov_wglCreateContext);
876 return NULL;
877 }
878
879 videodata->hglrc = ov_wglCreateContext(videodata->hdc);
880 if (!videodata->hglrc || !ov_wglMakeCurrent(videodata->hdc, videodata->hglrc)) {
881 SDL_SetError("Could not make current OpenGL context.");
882 return NULL;
883 }
884 }
885
886 i = OPENVR_InitExtensions(_this);
887 if (i == 0) {
888 return NULL;
889 }
890
891 videodata->renderdoc_debugmarker_frame_end = false;
892
893 ov_glGetIntegerv(GL_NUM_EXTENSIONS, &numExtensions);
894 for (i = 0; i < numExtensions; i++) {
895 const char *ccc = (const char *)ov_glGetStringi(GL_EXTENSIONS, i);
896 if (SDL_strcmp(ccc, "GL_KHR_debug") == 0) {
897#ifdef DEBUG_OPENVR
898 SDL_Log("Found renderdoc debug extension.");
899#endif
900 videodata->renderdoc_debugmarker_frame_end = true;
901 }
902 }
903
904 if (!videodata->bDidCreateOverlay) {
905 if (!OPENVR_InitializeOverlay(_this, window)) {
906 return NULL;
907 }
908 }
909
910 OPENVR_CheckRenderbuffer(_this);
911
912 OPENVR_SetupFrame(_this, window);
913
914 SDL_GLContext result = SDL_malloc(sizeof(struct SDL_GLContextState));
915 if (!result) {
916 return NULL;
917 }
918 result->hglrc = videodata->hglrc;
919 return result;
920}
921
922static bool OPENVR_GL_MakeCurrent(SDL_VideoDevice *_this, SDL_Window *wnd, SDL_GLContext context)
923{
924 SDL_VideoData *videodata = (SDL_VideoData *)_this->internal;
925 ov_wglMakeCurrent(videodata->hdc, videodata->hglrc);
926 return true;
927}
928
929static bool OPENVR_GL_SetSwapInterval(SDL_VideoDevice *_this, int interval)
930{
931 SDL_VideoData *videodata = (SDL_VideoData *)_this->internal;
932 videodata->swap_interval = interval;
933 return true;
934}
935
936static bool OPENVR_GL_GetSwapInterval(SDL_VideoDevice *_this, int *swapInterval)
937{
938 SDL_VideoData *videodata = (SDL_VideoData *)_this->internal;
939 if (swapInterval)
940 *swapInterval = videodata->swap_interval;
941 else
942 return SDL_SetError("OPENVR: null passed in for GetSwapInterval");
943 return true;
944}
945
946static bool OPENVR_GL_DestroyContext(SDL_VideoDevice *_this, SDL_GLContext context)
947{
948 SDL_VideoData *videodata = (SDL_VideoData *)_this->internal;
949 ov_wglMakeCurrent(videodata->hdc, NULL);
950 ov_wglDeleteContext(videodata->hglrc);
951 return true;
952}
953
954
955#else
956
957static EGLint context_attribs[] = {
958 EGL_CONTEXT_CLIENT_VERSION, 2,
959 EGL_NONE
960};
961
962static bool SDL_EGL_InitInternal(SDL_VideoData * vd)
963{
964 // Crate a surfaceless EGL Context
965 EGLint major, minor;
966 EGLConfig eglCfg=NULL;
967 EGLBoolean b;
968
969 vd->eglDpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
970#ifdef DEBUG_OPENVR
971 SDL_Log("EGL Display: %p", vd->eglDpy);
972#endif
973
974 if (vd->eglDpy == 0) {
975 return SDL_SetError("No EGL Display");
976 }
977
978 b = eglInitialize(vd->eglDpy, &major, &minor);
979 if (!b) {
980 return SDL_SetError("eglInitialize failed");
981 }
982
983 eglBindAPI(EGL_OPENGL_API);
984#ifdef DEBUG_OPENVR
985 SDL_Log("EGL Major Minor: %d %d = %d", major, minor, b);
986#endif
987
988 vd->eglCtx = eglCreateContext(vd->eglDpy, eglCfg, EGL_NO_CONTEXT, context_attribs);
989
990#ifdef DEBUG_OPENVR
991 {
992 int err = eglGetError();
993 if (err != EGL_SUCCESS) {
994 return SDL_SetError("EGL Error after eglCreateContext %d", err);
995 }
996 }
997#endif
998
999 if (!vd->eglCtx) {
1000 return SDL_SetError("No EGL context available");
1001 }
1002
1003 eglMakeCurrent(vd->eglDpy, EGL_NO_SURFACE, EGL_NO_SURFACE, vd->eglCtx);
1004
1005 return true;
1006}
1007
1008// Linux, EGL, etc.
1009static bool OVR_EGL_LoadLibrary(SDL_VideoDevice *_this, const char *path)
1010{
1011 return SDL_EGL_LoadLibrary(_this, path, /*displaydata->native_display*/0, 0);
1012}
1013
1014static SDL_FunctionPointer OVR_EGL_GetProcAddress(SDL_VideoDevice *_this, const char *proc)
1015{
1016 return SDL_EGL_GetProcAddress(proc);
1017}
1018static void OVR_EGL_UnloadLibrary(SDL_VideoDevice *_this)
1019{
1020 return SDL_EGL_UnloadLibrary(_this);
1021}
1022static SDL_GLContext OVR_EGL_CreateContext(SDL_VideoDevice *_this, SDL_Window * window)
1023{
1024 GLint numExtensions;
1025 SDL_VideoData *videodata = (SDL_VideoData *)_this->internal;
1026 if (!videodata->eglCtx) {
1027 if (!SDL_EGL_InitInternal(videodata)) {
1028 return NULL;
1029 }
1030 }
1031
1032 if (!OPENVR_InitExtensions(_this)) {
1033 return NULL;
1034 }
1035
1036 videodata->renderdoc_debugmarker_frame_end = false;
1037
1038 ov_glGetIntegerv(GL_NUM_EXTENSIONS, &numExtensions);
1039 for(int i = 0; i < numExtensions; i++) {
1040 const char * ccc = (const char*)ov_glGetStringi(GL_EXTENSIONS, i);
1041 if (SDL_strcmp(ccc, "GL_KHR_debug") == 0) {
1042#ifdef DEBUG_OPENVR
1043 SDL_Log("Found renderdoc debug extension.");
1044#endif
1045 videodata->renderdoc_debugmarker_frame_end = true;
1046 }
1047 }
1048
1049 if (!videodata->bDidCreateOverlay) {
1050 if (!OPENVR_InitializeOverlay(_this, window)) {
1051 return NULL;
1052 }
1053 }
1054
1055 OPENVR_CheckRenderbuffer(_this);
1056
1057 OPENVR_SetupFrame(_this, window);
1058
1059 return videodata->eglCtx;
1060}
1061
1062static bool OVR_EGL_MakeCurrent(SDL_VideoDevice *_this, SDL_Window * wnd, SDL_GLContext context)
1063{
1064 SDL_VideoData *videodata = (SDL_VideoData *)_this->internal;
1065 eglMakeCurrent(videodata->eglDpy, EGL_NO_SURFACE, EGL_NO_SURFACE, videodata->eglCtx);
1066 return true;
1067}
1068
1069static bool OVR_EGL_SetSwapInterval(SDL_VideoDevice *_this, int interval)
1070{
1071 SDL_VideoData *videodata = (SDL_VideoData *)_this->internal;
1072 videodata->swap_interval = interval;
1073 return true;
1074}
1075
1076static bool OVR_EGL_GetSwapInterval(SDL_VideoDevice *_this, int * swapInterval)
1077{
1078 SDL_VideoData *videodata = (SDL_VideoData *)_this->internal;
1079 if (swapInterval)
1080 *swapInterval = videodata->swap_interval;
1081 else
1082 return SDL_SetError("OPENVR: null passed in for GetSwapInterval");
1083 return true;
1084}
1085
1086static bool OVR_EGL_DestroyContext(SDL_VideoDevice *_this, SDL_GLContext context)
1087{
1088 SDL_VideoData *videodata = (SDL_VideoData *)_this->internal;
1089 if (videodata->eglDpy) {
1090 eglTerminate(videodata->eglDpy);
1091 }
1092 return true;
1093}
1094
1095#endif
1096
1097static bool OPENVR_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID create_props)
1098{
1099 SDL_WindowData *data;
1100
1101 // Allocate window internal data
1102 data = (SDL_WindowData *)SDL_calloc(1, sizeof(SDL_WindowData));
1103 if (data == NULL) {
1104 return SDL_OutOfMemory();
1105 }
1106
1107 window->max_w = 4096;
1108 window->max_h = 4096;
1109 window->min_w = 1;
1110 window->min_h = 1;
1111
1112 // Setup driver data for this window
1113 window->internal = data;
1114 return true;
1115}
1116
1117
1118static void OPENVR_DestroyWindow(SDL_VideoDevice *_this, SDL_Window *window)
1119{
1120 SDL_WindowData *data;
1121
1122 data = window->internal;
1123 if (data) {
1124 SDL_free(data);
1125 }
1126 window->internal = NULL;
1127}
1128
1129static void OPENVR_SetWindowTitle(SDL_VideoDevice *_this, SDL_Window *window)
1130{
1131 SDL_VideoData * data = (SDL_VideoData *)_this->internal;
1132 if (data->bDidCreateOverlay) {
1133 data->oOverlay->SetOverlayName(data->overlayID, window->title);
1134 }
1135}
1136
1137static void OPENVR_SetWindowSize(SDL_VideoDevice *_this, SDL_Window *window)
1138{
1139 SDL_VideoData *data = (SDL_VideoData *)_this->internal;
1140
1141 if (window->pending.w != window->w) {
1142 window->w = window->pending.w;
1143 }
1144
1145 if (window->pending.h != window->h) {
1146 window->h = window->pending.h;
1147 }
1148
1149 if (data->targh != window->h || data->targw != window->w) {
1150 OPENVR_HandleResize(_this, window->w, window->h);
1151 }
1152
1153 SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_RESIZED, window->w, window->h);
1154}
1155
1156static void OPENVR_GetWindowSizeInPixels(SDL_VideoDevice *_this, SDL_Window *window, int *w, int *h)
1157{
1158 SDL_VideoData *data = (SDL_VideoData *)_this->internal;
1159 *w = data->targw;
1160 *h = data->targh;
1161}
1162
1163static void OPENVR_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window)
1164{
1165 SDL_VideoData *data = (SDL_VideoData *)_this->internal;
1166 if (data->targh != window->h || data->targw != window->w) {
1167 OPENVR_HandleResize(_this, window->w, window->h);
1168 }
1169
1170 data->oOverlay->ShowDashboard(data->sOverlayName);
1171
1172 window->flags |= (SDL_WINDOW_INPUT_FOCUS | SDL_WINDOW_MOUSE_FOCUS);
1173 SDL_SetKeyboardFocus(window);
1174}
1175
1176static void OPENVR_HideWindow(SDL_VideoDevice *_this, SDL_Window *window)
1177{
1178 return;
1179}
1180
1181static bool OPENVR_GL_SwapWindow(SDL_VideoDevice *_this, SDL_Window *window)
1182{
1183 SDL_VideoData *videodata = (SDL_VideoData *)_this->internal;
1184
1185 // This is a little weird. On Windows, we don't necessarily call the normal
1186 // context creation function, and we might get here without having our buffers
1187 // initialized.
1188 if (!videodata->bDidCreateOverlay) {
1189 if (!OPENVR_InitializeOverlay(_this, window)) {
1190 return false;
1191 }
1192 }
1193
1194 if (!OPENVR_ReleaseFrame(_this)) {
1195 return false;
1196 }
1197
1198 // If swap_interval is nonzero (i.e. -1 or 1) we want to wait for vsync on the compositor.
1199 if (videodata->swap_interval != 0) {
1200 videodata->oOverlay->WaitFrameSync(100);
1201 }
1202
1203 if (!OPENVR_SetupFrame(_this, window)) {
1204 return false;
1205 }
1206
1207 return true;
1208}
1209
1210static void OPENVR_HandleMouse(float x, float y, int btn, int evt)
1211{
1212 if (evt == 2) {
1213 SDL_SendMouseMotion(0, NULL, SDL_GLOBAL_MOUSE_ID, false, x, y);
1214 } else {
1215 const Uint8 button = SDL_BUTTON_LEFT + btn;
1216 const bool down = (evt != 0);
1217 SDL_SendMouseButton(0, NULL, SDL_GLOBAL_MOUSE_ID, button, down);
1218 }
1219}
1220
1221
1222static bool OPENVR_HasScreenKeyboardSupport(SDL_VideoDevice *_this)
1223{
1224 return true;
1225}
1226
1227static void OPENVR_ShowScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID props)
1228{
1229 SDL_VideoData *videodata = (SDL_VideoData *)_this->internal;
1230 if (!videodata ||
1231 videodata->oOverlay == 0 ||
1232 videodata->overlayID == 0) {
1233 return;
1234 }
1235 EGamepadTextInputMode input_mode;
1236 switch (SDL_GetTextInputType(props)) {
1237 case SDL_TEXTINPUT_TYPE_TEXT_PASSWORD_HIDDEN:
1238 case SDL_TEXTINPUT_TYPE_NUMBER_PASSWORD_HIDDEN:
1239 input_mode = EGamepadTextInputMode_k_EGamepadTextInputModePassword;
1240 break;
1241 default:
1242 input_mode = EGamepadTextInputMode_k_EGamepadTextInputModeNormal;
1243 break;
1244 }
1245 EGamepadTextInputLineMode line_mode;
1246 if (SDL_GetTextInputMultiline(props)) {
1247 line_mode = EGamepadTextInputLineMode_k_EGamepadTextInputLineModeMultipleLines;
1248 } else {
1249 line_mode = EGamepadTextInputLineMode_k_EGamepadTextInputLineModeSingleLine;
1250 }
1251 videodata->oOverlay->ShowKeyboardForOverlay(videodata->overlayID,
1252 input_mode, line_mode,
1253 EKeyboardFlags_KeyboardFlag_Minimal, "Virtual Keyboard", 128, "", 0);
1254 videodata->bKeyboardShown = true;
1255}
1256
1257static void OPENVR_HideScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window)
1258{
1259 SDL_VideoData *videodata = (SDL_VideoData *)_this->internal;
1260 videodata->oOverlay->HideKeyboard();
1261 videodata->bKeyboardShown = false;
1262}
1263
1264static bool OPENVR_IsScreenKeyboardShown(SDL_VideoDevice *_this, SDL_Window *window)
1265{
1266 SDL_VideoData *videodata = (SDL_VideoData *)_this->internal;
1267 return videodata->bKeyboardShown;
1268}
1269
1270static SDL_Cursor *OPENVR_CreateCursor(SDL_Surface * surface, int hot_x, int hot_y)
1271{
1272 SDL_Cursor *result = SDL_calloc(1, sizeof(SDL_Cursor));
1273 if (!result) {
1274 return NULL;
1275 }
1276
1277 uint32_t * pixels = ImageSDLToOpenVRGL(surface, false);
1278 SDL_CursorData *ovrc = (SDL_CursorData *)SDL_calloc(1, sizeof(*ovrc));
1279 if (!ovrc) {
1280 SDL_free(result);
1281 return NULL;
1282 }
1283 result->internal = ovrc;
1284
1285 ov_glGenTextures(1, &ovrc->texture_id_handle);
1286 ov_glBindTexture(GL_TEXTURE_2D, ovrc->texture_id_handle);
1287 ov_glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, surface->w, surface->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
1288 SDL_free(pixels);
1289 ov_glBindTexture(GL_TEXTURE_2D, 0);
1290
1291 ovrc->hot_x = hot_x;
1292 ovrc->hot_y = hot_y;
1293 ovrc->w = surface->w;
1294 ovrc->h = surface->h;
1295
1296 return result;
1297}
1298
1299static bool OPENVR_ShowCursor(SDL_Cursor * cursor)
1300{
1301 SDL_CursorData * ovrc;
1302 EVROverlayError e;
1303 Texture_t texture;
1304 HmdVector2_t hotspot;
1305 VRTextureBounds_t tb;
1306
1307 if (!cursor) {
1308 global_openvr_driver->oOverlay->SetOverlayFlag(global_openvr_driver->overlayID, VROverlayFlags_HideLaserIntersection, true);
1309 e = global_openvr_driver->oOverlay->SetOverlayCursor(global_openvr_driver->overlayID, k_ulOverlayHandleInvalid);
1310 if (e != EVROverlayError_VROverlayError_None) {
1311 return OPENVR_SetOverlayError(e);
1312 }
1313 return true;
1314 }
1315
1316 global_openvr_driver->oOverlay->SetOverlayFlag(global_openvr_driver->overlayID, VROverlayFlags_HideLaserIntersection, false);
1317
1318 ovrc = cursor->internal;
1319
1320 if (!ovrc) {
1321 // Sometimes at boot there is a race condition where this is not ready.
1322 return true;
1323 }
1324
1325 hotspot.v[0] = (float)ovrc->hot_x / (float)ovrc->w;
1326 hotspot.v[1] = (float)ovrc->hot_y / (float)ovrc->h;
1327
1328 texture.handle = (void*)(intptr_t)(ovrc->texture_id_handle);
1329 texture.eType = ETextureType_TextureType_OpenGL;
1330 texture.eColorSpace = EColorSpace_ColorSpace_Auto;
1331
1332 tb.uMin = 0;
1333 tb.uMax = 1;
1334 tb.vMin = 1;
1335 tb.vMax = 0;
1336
1337 e = global_openvr_driver->oOverlay->SetOverlayTextureBounds(global_openvr_driver->cursorID, &tb);
1338 if (e != EVROverlayError_VROverlayError_None) {
1339 return OPENVR_SetOverlayError(e);
1340 }
1341
1342 e = global_openvr_driver->oOverlay->SetOverlayTransformCursor(global_openvr_driver->cursorID, &hotspot);
1343 if (e != EVROverlayError_VROverlayError_None) {
1344 return OPENVR_SetOverlayError(e);
1345 }
1346
1347 e = global_openvr_driver->oOverlay->SetOverlayTexture(global_openvr_driver->cursorID, &texture);
1348 if (e != EVROverlayError_VROverlayError_None) {
1349 return OPENVR_SetOverlayError(e);
1350 }
1351
1352 e = global_openvr_driver->oOverlay->SetOverlayCursor(global_openvr_driver->overlayID, global_openvr_driver->cursorID);
1353 if (e != EVROverlayError_VROverlayError_None) {
1354 return OPENVR_SetOverlayError(e);
1355 }
1356
1357 return true;
1358}
1359
1360static void OPENVR_FreeCursor(SDL_Cursor * cursor)
1361{
1362 if (cursor) {
1363 SDL_CursorData *ovrc = cursor->internal;
1364 if (ovrc) {
1365 ov_glDeleteTextures(1, &ovrc->texture_id_handle);
1366 SDL_free(ovrc);
1367 }
1368 SDL_free(cursor);
1369 }
1370}
1371
1372
1373static bool OPENVR_SetWindowIcon(SDL_VideoDevice *_this, SDL_Window * window, SDL_Surface * icon)
1374{
1375 if (!global_openvr_driver) {
1376 return SDL_SetError("OpenVR Overlay not initialized");
1377 }
1378
1379 unsigned texture_id_handle;
1380 EVROverlayError e;
1381 Texture_t texture;
1382 uint32_t * pixels;
1383 SDL_VideoData *videodata = (SDL_VideoData *)_this->internal;
1384 if (videodata->bIconOverridden) {
1385 return SDL_SetError("OpenVR Icon is overridden.");
1386 }
1387
1388 pixels = ImageSDLToOpenVRGL(icon, true);
1389
1390 ov_glGenTextures(1, &texture_id_handle);
1391 ov_glBindTexture(GL_TEXTURE_2D, texture_id_handle);
1392 ov_glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, icon->w, icon->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
1393 SDL_free(pixels);
1394 ov_glBindTexture(GL_TEXTURE_2D, 0);
1395
1396 texture.handle = (void*)(intptr_t)(texture_id_handle);
1397 texture.eType = ETextureType_TextureType_OpenGL;
1398 texture.eColorSpace = EColorSpace_ColorSpace_Auto;
1399
1400 e = global_openvr_driver->oOverlay->SetOverlayTexture(videodata->thumbID, &texture);
1401 if (e != EVROverlayError_VROverlayError_None) {
1402 return OPENVR_SetOverlayError(e);
1403 }
1404 return true;
1405}
1406
1407static bool OPENVR_ShowMessageBox(SDL_VideoDevice *_this,const SDL_MessageBoxData *messageboxdata, int *buttonid)
1408{
1409 SDL_VideoData *videodata = (SDL_VideoData *)_this->internal;
1410 char empty = 0;
1411 char * message = SDL_strdup(messageboxdata->message?messageboxdata->message:"");
1412 char * title = SDL_strdup(messageboxdata->message?messageboxdata->message:"");
1413 char * ok = SDL_strdup("Ok");
1414 videodata->oOverlay->ShowMessageOverlay(message, title, ok, &empty, &empty, &empty);
1415 SDL_free(ok);
1416 SDL_free(title);
1417 SDL_free(message);
1418 return true;
1419}
1420
1421static void InitializeMouseFunctions()
1422{
1423 SDL_Mouse *mouse = SDL_GetMouse();
1424 mouse->CreateCursor = OPENVR_CreateCursor;
1425 mouse->ShowCursor = OPENVR_ShowCursor;
1426 mouse->FreeCursor = OPENVR_FreeCursor;
1427}
1428
1429static void OPENVR_PumpEvents(SDL_VideoDevice *_this)
1430{
1431 SDL_VideoData *videodata = (SDL_VideoData *)_this->internal;
1432 struct VREvent_t nEvent;
1433 if (videodata->overlayID) {
1434 while (videodata->oOverlay->PollNextOverlayEvent(videodata->overlayID, &nEvent, sizeof(nEvent))) {
1435 switch (nEvent.eventType) {
1436 case EVREventType_VREvent_ButtonPress:
1437 case EVREventType_VREvent_ButtonUnpress:
1438 break;
1439 case EVREventType_VREvent_MouseMove:
1440 OPENVR_HandleMouse(nEvent.data.mouse.x, videodata->targh - nEvent.data.mouse.y, nEvent.data.mouse.button, 2);
1441 break;
1442 case EVREventType_VREvent_MouseButtonDown:
1443 OPENVR_HandleMouse(nEvent.data.mouse.x, videodata->targh - nEvent.data.mouse.y, 0, 1);
1444 break;
1445 case EVREventType_VREvent_MouseButtonUp:
1446 OPENVR_HandleMouse(nEvent.data.mouse.x, videodata->targh - nEvent.data.mouse.y, 0, 0);
1447 break;
1448 case EVREventType_VREvent_KeyboardCharInput:
1449 SDL_SendKeyboardUnicodeKey(SDL_GetTicksNS(), nEvent.data.keyboard.cNewInput[0]);
1450 break;
1451 case EVREventType_VREvent_OverlayShown:
1452 SDL_SetKeyboardFocus(videodata->window);
1453 SDL_SendWindowEvent(videodata->window, SDL_EVENT_WINDOW_RESTORED, 0, 0);
1454 SDL_SendWindowEvent(videodata->window, SDL_EVENT_WINDOW_SHOWN, 0, 0);
1455 break;
1456 case EVREventType_VREvent_OverlayHidden:
1457 SDL_SendWindowEvent(videodata->window, SDL_EVENT_WINDOW_HIDDEN, 0, 0);
1458 SDL_SendWindowEvent(videodata->window, SDL_EVENT_WINDOW_MINIMIZED, 0, 0);
1459 SDL_SetKeyboardFocus(NULL);
1460 break;
1461 case EVREventType_VREvent_OverlayClosed:
1462 case EVREventType_VREvent_Quit:
1463 SDL_Quit();
1464 break;
1465 }
1466 }
1467 }
1468}
1469
1470
1471static SDL_VideoDevice *OPENVR_CreateDevice(void)
1472{
1473 SDL_VideoDevice *device;
1474 SDL_VideoData *data;
1475
1476#ifdef SDL_PLATFORM_WINDOWS
1477 SDL_RegisterApp(NULL, 0, NULL);
1478#endif
1479
1480 // Initialize all variables that we clean on shutdown
1481 device = (SDL_VideoDevice *)SDL_calloc(1, sizeof(SDL_VideoDevice));
1482 if (device) {
1483 data = (struct SDL_VideoData *)SDL_calloc(1, sizeof(SDL_VideoData));
1484 } else {
1485 data = NULL;
1486 }
1487 if (!data) {
1488#ifdef SDL_PLATFORM_WINDOWS
1489 SDL_UnregisterApp();
1490#endif
1491 SDL_free(device);
1492 return NULL;
1493 }
1494 device->internal = data;
1495
1496 {
1497 const char * hint = SDL_GetHint(SDL_HINT_OPENVR_LIBRARY);
1498 if (hint)
1499 data->openVRLIB = SDL_LoadObject(hint);
1500#ifdef SDL_PLATFORM_WINDOWS
1501 if (!data->openVRLIB)
1502 data->openVRLIB = SDL_LoadObject("openvr_api.dll");
1503#else
1504 if (!data->openVRLIB)
1505 data->openVRLIB = SDL_LoadObject("openvr_api.so");
1506#endif
1507 }
1508
1509 if (!data->openVRLIB) {
1510 SDL_SetError("Could not open OpenVR API Library");
1511 goto error;
1512 }
1513
1514 data->FN_VR_InitInternal = (intptr_t(*)(EVRInitError * peError, EVRApplicationType eType))SDL_LoadFunction(data->openVRLIB, "VR_InitInternal");
1515 data->FN_VR_GetVRInitErrorAsEnglishDescription = (const char *(*)(EVRInitError error))SDL_LoadFunction(data->openVRLIB, "VR_GetVRInitErrorAsEnglishDescription");
1516 data->FN_VR_GetGenericInterface = (intptr_t (*)(const char *pchInterfaceVersion, EVRInitError * peError))SDL_LoadFunction(data->openVRLIB, "VR_GetGenericInterface");
1517 if (!data->FN_VR_InitInternal || !data->FN_VR_GetVRInitErrorAsEnglishDescription || !data->FN_VR_GetGenericInterface) {
1518 goto error;
1519 }
1520
1521 char fnname[128];
1522 EVRInitError e;
1523 data->vrtoken = data->FN_VR_InitInternal(&e, EVRApplicationType_VRApplication_Overlay);
1524 if (!data->vrtoken) {
1525 const char *err = "Can't get english description";
1526 if (data->FN_VR_GetVRInitErrorAsEnglishDescription != NULL)
1527 err = data->FN_VR_GetVRInitErrorAsEnglishDescription(e);
1528 SDL_SetError("Could not generate OpenVR Context (%s)", err);
1529 goto error;
1530 }
1531
1532 SDL_snprintf(fnname, 127, "FnTable:%s", IVRSystem_Version);
1533 data->oSystem = (struct VR_IVRSystem_FnTable *)data->FN_VR_GetGenericInterface(fnname, &e);
1534 SDL_snprintf(fnname, 127, "FnTable:%s", IVROverlay_Version);
1535 data->oOverlay = (struct VR_IVROverlay_FnTable *)data->FN_VR_GetGenericInterface(fnname, &e);
1536 SDL_snprintf(fnname, 127, "FnTable:%s", IVRInput_Version);
1537 data->oInput = (struct VR_IVRInput_FnTable *)data->FN_VR_GetGenericInterface(fnname, &e);
1538
1539 if (!data->oOverlay || !data->oSystem || !data->oInput) {
1540 SDL_SetError("Could not get interfaces for the OpenVR System (%s), Overlay (%s) and Input (%s) versions", IVRSystem_Version, IVROverlay_Version, IVRInput_Version);
1541 }
1542
1543 const char *hint = SDL_GetHint("SDL_OPENVR_INPUT_PROFILE");
1544 char *loadpath = 0;
1545 EVRInputError err;
1546
1547 if (hint) {
1548 SDL_asprintf(&loadpath, "%s", hint);
1549 } else {
1550 const char *basepath = SDL_GetBasePath();
1551 SDL_asprintf(&loadpath, "%ssdloverlay_actions.json", basepath);
1552 }
1553 if (!loadpath) {
1554 goto error;
1555 }
1556
1557 err = data->oInput->SetActionManifestPath(loadpath);
1558#ifdef DEBUG_OPENVR
1559 SDL_Log("Loaded action manifest at %s (%d)", loadpath, err);
1560#endif
1561 SDL_free(loadpath);
1562 if (err != EVRInputError_VRInputError_None) {
1563 // I know we don't normally log, but this _really_ should be percolated
1564 // up as far as we can.
1565 SDL_Log("Could not load action manifest path");
1566 // If we didn't have a hint, this is a soft fail.
1567 // If we did have the hint, then it's a hard fail.
1568 if (hint) {
1569 goto error;
1570 }
1571 } else {
1572 if(!OPENVR_SetupJoystickBasedOnLoadedActionManifest(data)) {
1573 goto error;
1574 }
1575 }
1576
1577 // Setup amount of available displays
1578 device->num_displays = 0;
1579
1580 // Set device free function
1581 device->free = OPENVR_Destroy;
1582
1583 // Setup all functions which we can handle
1584 device->VideoInit = OPENVR_VideoInit;
1585 device->VideoQuit = OPENVR_VideoQuit;
1586 device->SetDisplayMode = OPENVR_SetDisplayMode;
1587 device->CreateSDLWindow = OPENVR_CreateWindow;
1588 device->SetWindowTitle = OPENVR_SetWindowTitle;
1589 device->SetWindowSize = OPENVR_SetWindowSize;
1590 device->GetWindowSizeInPixels = OPENVR_GetWindowSizeInPixels;
1591 device->ShowWindow = OPENVR_ShowWindow;
1592 device->HideWindow = OPENVR_HideWindow;
1593 device->DestroyWindow = OPENVR_DestroyWindow;
1594 device->ShowMessageBox = OPENVR_ShowMessageBox;
1595
1596#ifdef SDL_VIDEO_DRIVER_WINDOWS
1597#ifdef SDL_VIDEO_OPENGL_WGL
1598 device->GL_LoadLibrary = OPENVR_GL_LoadLibrary;
1599 device->GL_GetProcAddress = OPENVR_GL_GetProcAddress;
1600 device->GL_UnloadLibrary = OPENVR_GL_UnloadLibrary;
1601 device->GL_CreateContext = OPENVR_GL_CreateContext;
1602 device->GL_MakeCurrent = OPENVR_GL_MakeCurrent;
1603 device->GL_SetSwapInterval = OPENVR_GL_SetSwapInterval;
1604 device->GL_GetSwapInterval = OPENVR_GL_GetSwapInterval;
1605 device->GL_SwapWindow = OPENVR_GL_SwapWindow;
1606 device->GL_DestroyContext = OPENVR_GL_DestroyContext;
1607#elif SDL_VIDEO_OPENGL_EGL
1608 device->GL_LoadLibrary = WIN_GLES_LoadLibrary;
1609 device->GL_GetProcAddress = WIN_GLES_GetProcAddress;
1610 device->GL_UnloadLibrary = WIN_GLES_UnloadLibrary;
1611 device->GL_CreateContext = WIN_GLES_CreateContext;
1612 device->GL_MakeCurrent = WIN_GLES_MakeCurrent;
1613 device->GL_SetSwapInterval = WIN_GLES_SetSwapInterval;
1614 device->GL_GetSwapInterval = WIN_GLES_GetSwapInterval;
1615 device->GL_SwapWindow = WIN_GLES_SwapWindow;
1616 device->GL_DestroyContext = WIN_GLES_DestroyContext;
1617#endif
1618#else
1619 device->GL_LoadLibrary = OVR_EGL_LoadLibrary;
1620 device->GL_GetProcAddress = OVR_EGL_GetProcAddress;
1621 device->GL_UnloadLibrary = OVR_EGL_UnloadLibrary;
1622 device->GL_CreateContext = OVR_EGL_CreateContext;
1623 device->GL_MakeCurrent = OVR_EGL_MakeCurrent;
1624 device->GL_SetSwapInterval = OVR_EGL_SetSwapInterval;
1625 device->GL_GetSwapInterval = OVR_EGL_GetSwapInterval;
1626 device->GL_DestroyContext = OVR_EGL_DestroyContext;
1627 device->GL_SwapWindow = OPENVR_GL_SwapWindow;
1628#endif
1629
1630#if defined(SDL_VIDEO_VULKAN) && defined(SDL_VIDEO_DRIVER_WINDOWS)
1631 device->Vulkan_LoadLibrary = WIN_Vulkan_LoadLibrary;
1632 device->Vulkan_UnloadLibrary = WIN_Vulkan_UnloadLibrary;
1633 device->Vulkan_GetInstanceExtensions = WIN_Vulkan_GetInstanceExtensions;
1634 device->Vulkan_CreateSurface = WIN_Vulkan_CreateSurface;
1635#else
1636 device->Vulkan_LoadLibrary = 0;
1637 device->Vulkan_UnloadLibrary = 0;
1638 device->Vulkan_GetInstanceExtensions = 0;
1639 device->Vulkan_CreateSurface = 0;
1640#endif
1641
1642 device->PumpEvents = OPENVR_PumpEvents;
1643 device->VideoInit = OPENVR_VideoInit;
1644 device->VideoQuit = OPENVR_VideoQuit;
1645
1646 device->HasScreenKeyboardSupport = OPENVR_HasScreenKeyboardSupport;
1647 device->ShowScreenKeyboard = OPENVR_ShowScreenKeyboard;
1648 device->HideScreenKeyboard = OPENVR_HideScreenKeyboard;
1649 device->IsScreenKeyboardShown = OPENVR_IsScreenKeyboardShown;
1650 device->SetWindowIcon = OPENVR_SetWindowIcon;
1651
1652 return device;
1653
1654error:
1655 OPENVR_Destroy(device);
1656 return NULL;
1657}
1658
1659VideoBootStrap OPENVR_bootstrap = {
1660 "openvr", "SDL OpenVR video driver", OPENVR_CreateDevice, NULL, false
1661};
1662
1663#endif // SDL_VIDEO_DRIVER_WINDOWS
1664