cscg22-gearboy

CSCG 2022 Challenge 'Gearboy'
git clone https://git.sinitax.com/sinitax/cscg22-gearboy
Log | Files | Refs | sfeed.txt

SDL_winrtvideo.cpp (13213B)


      1/*
      2  Simple DirectMedia Layer
      3  Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org>
      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#if SDL_VIDEO_DRIVER_WINRT
     24
     25/* WinRT SDL video driver implementation
     26
     27   Initial work on this was done by David Ludwig (dludwig@pobox.com), and
     28   was based off of SDL's "dummy" video driver.
     29 */
     30
     31/* Windows includes */
     32#include <agile.h>
     33#include <wrl/client.h>
     34using namespace Windows::UI::Core;
     35
     36
     37/* SDL includes */
     38extern "C" {
     39#include "SDL_video.h"
     40#include "SDL_mouse.h"
     41#include "../SDL_sysvideo.h"
     42#include "../SDL_pixels_c.h"
     43#include "../../events/SDL_events_c.h"
     44#include "../../render/SDL_sysrender.h"
     45#include "SDL_syswm.h"
     46#include "SDL_winrtopengles.h"
     47}
     48
     49#include "../../core/winrt/SDL_winrtapp_direct3d.h"
     50#include "../../core/winrt/SDL_winrtapp_xaml.h"
     51#include "SDL_winrtvideo_cpp.h"
     52#include "SDL_winrtevents_c.h"
     53#include "SDL_winrtmouse_c.h"
     54#include "SDL_main.h"
     55#include "SDL_system.h"
     56//#include "SDL_log.h"
     57
     58
     59/* Initialization/Query functions */
     60static int WINRT_VideoInit(_THIS);
     61static int WINRT_InitModes(_THIS);
     62static int WINRT_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode);
     63static void WINRT_VideoQuit(_THIS);
     64
     65
     66/* Window functions */
     67static int WINRT_CreateWindow(_THIS, SDL_Window * window);
     68static void WINRT_DestroyWindow(_THIS, SDL_Window * window);
     69static SDL_bool WINRT_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info);
     70
     71
     72/* SDL-internal globals: */
     73SDL_Window * WINRT_GlobalSDLWindow = NULL;
     74
     75
     76/* WinRT driver bootstrap functions */
     77
     78static int
     79WINRT_Available(void)
     80{
     81    return (1);
     82}
     83
     84static void
     85WINRT_DeleteDevice(SDL_VideoDevice * device)
     86{
     87    if (device->driverdata) {
     88        SDL_VideoData * video_data = (SDL_VideoData *)device->driverdata;
     89        if (video_data->winrtEglWindow) {
     90            video_data->winrtEglWindow->Release();
     91        }
     92        SDL_free(video_data);
     93    }
     94
     95    SDL_free(device);
     96}
     97
     98static SDL_VideoDevice *
     99WINRT_CreateDevice(int devindex)
    100{
    101    SDL_VideoDevice *device;
    102    SDL_VideoData *data;
    103
    104    /* Initialize all variables that we clean on shutdown */
    105    device = (SDL_VideoDevice *) SDL_calloc(1, sizeof(SDL_VideoDevice));
    106    if (!device) {
    107        SDL_OutOfMemory();
    108        if (device) {
    109            SDL_free(device);
    110        }
    111        return (0);
    112    }
    113
    114    data = (SDL_VideoData *) SDL_calloc(1, sizeof(SDL_VideoData));
    115    if (!data) {
    116        SDL_OutOfMemory();
    117        return (0);
    118    }
    119    SDL_zerop(data);
    120    device->driverdata = data;
    121
    122    /* Set the function pointers */
    123    device->VideoInit = WINRT_VideoInit;
    124    device->VideoQuit = WINRT_VideoQuit;
    125    device->CreateWindow = WINRT_CreateWindow;
    126    device->DestroyWindow = WINRT_DestroyWindow;
    127    device->SetDisplayMode = WINRT_SetDisplayMode;
    128    device->PumpEvents = WINRT_PumpEvents;
    129    device->GetWindowWMInfo = WINRT_GetWindowWMInfo;
    130#ifdef SDL_VIDEO_OPENGL_EGL
    131    device->GL_LoadLibrary = WINRT_GLES_LoadLibrary;
    132    device->GL_GetProcAddress = WINRT_GLES_GetProcAddress;
    133    device->GL_UnloadLibrary = WINRT_GLES_UnloadLibrary;
    134    device->GL_CreateContext = WINRT_GLES_CreateContext;
    135    device->GL_MakeCurrent = WINRT_GLES_MakeCurrent;
    136    device->GL_SetSwapInterval = WINRT_GLES_SetSwapInterval;
    137    device->GL_GetSwapInterval = WINRT_GLES_GetSwapInterval;
    138    device->GL_SwapWindow = WINRT_GLES_SwapWindow;
    139    device->GL_DeleteContext = WINRT_GLES_DeleteContext;
    140#endif
    141    device->free = WINRT_DeleteDevice;
    142
    143    return device;
    144}
    145
    146#define WINRTVID_DRIVER_NAME "winrt"
    147VideoBootStrap WINRT_bootstrap = {
    148    WINRTVID_DRIVER_NAME, "SDL WinRT video driver",
    149    WINRT_Available, WINRT_CreateDevice
    150};
    151
    152int
    153WINRT_VideoInit(_THIS)
    154{
    155    if (WINRT_InitModes(_this) < 0) {
    156        return -1;
    157    }
    158    WINRT_InitMouse(_this);
    159    WINRT_InitTouch(_this);
    160
    161    return 0;
    162}
    163
    164int
    165WINRT_CalcDisplayModeUsingNativeWindow(SDL_DisplayMode * mode)
    166{
    167    SDL_DisplayModeData * driverdata;
    168
    169    using namespace Windows::Graphics::Display;
    170
    171    // Go no further if a native window cannot be accessed.  This can happen,
    172    // for example, if this function is called from certain threads, such as
    173    // the SDL/XAML thread.
    174    if (!CoreWindow::GetForCurrentThread()) {
    175        return SDL_SetError("SDL/WinRT display modes cannot be calculated outside of the main thread, such as in SDL's XAML thread");
    176    }
    177
    178    //SDL_Log("%s, size={%f,%f}, current orientation=%d, native orientation=%d, auto rot. pref=%d, DPI = %f\n",
    179    //    __FUNCTION__,
    180    //    CoreWindow::GetForCurrentThread()->Bounds.Width, CoreWindow::GetForCurrentThread()->Bounds.Height,
    181    //    WINRT_DISPLAY_PROPERTY(CurrentOrientation),
    182    //    WINRT_DISPLAY_PROPERTY(NativeOrientation),
    183    //    WINRT_DISPLAY_PROPERTY(AutoRotationPreferences),
    184    //    WINRT_DISPLAY_PROPERTY(LogicalDpi));
    185
    186    // Calculate the display size given the window size, taking into account
    187    // the current display's DPI:
    188    const float currentDPI = WINRT_DISPLAY_PROPERTY(LogicalDpi);
    189    const float dipsPerInch = 96.0f;
    190    const int w = (int) ((CoreWindow::GetForCurrentThread()->Bounds.Width * currentDPI) / dipsPerInch);
    191    const int h = (int) ((CoreWindow::GetForCurrentThread()->Bounds.Height * currentDPI) / dipsPerInch);
    192    if (w == 0 || w == h) {
    193        return SDL_SetError("Unable to calculate the WinRT window/display's size");
    194    }
    195
    196    // Create a driverdata field:
    197    driverdata = (SDL_DisplayModeData *) SDL_malloc(sizeof(*driverdata));
    198    if (!driverdata) {
    199        return SDL_OutOfMemory();
    200    }
    201    SDL_zerop(driverdata);
    202
    203    // Fill in most fields:
    204    SDL_zerop(mode);
    205    mode->format = SDL_PIXELFORMAT_RGB888;
    206    mode->refresh_rate = 0;  // TODO, WinRT: see if refresh rate data is available, or relevant (for WinRT apps)
    207    mode->w = w;
    208    mode->h = h;
    209    mode->driverdata = driverdata;
    210    driverdata->currentOrientation = WINRT_DISPLAY_PROPERTY(CurrentOrientation);
    211
    212#if (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) && (NTDDI_VERSION == NTDDI_WIN8)
    213    // On Windows Phone 8.0, the native window's size is always in portrait,
    214    // regardless of the device's orientation.  This is in contrast to
    215    // Windows 8.x/RT and Windows Phone 8.1, which will resize the native window as the device's
    216    // orientation changes.  In order to compensate for this behavior,
    217    // on Windows Phone, the mode's width and height will be swapped when
    218    // the device is in a landscape (non-portrait) mode.
    219    switch (driverdata->currentOrientation) {
    220        case DisplayOrientations::Landscape:
    221        case DisplayOrientations::LandscapeFlipped:
    222        {
    223            const int tmp = mode->h;
    224            mode->h = mode->w;
    225            mode->w = tmp;
    226            break;
    227        }
    228
    229        default:
    230            break;
    231    }
    232#endif
    233
    234    return 0;
    235}
    236
    237int
    238WINRT_DuplicateDisplayMode(SDL_DisplayMode * dest, const SDL_DisplayMode * src)
    239{
    240    SDL_DisplayModeData * driverdata;
    241    driverdata = (SDL_DisplayModeData *) SDL_malloc(sizeof(*driverdata));
    242    if (!driverdata) {
    243        return SDL_OutOfMemory();
    244    }
    245    SDL_memcpy(driverdata, src->driverdata, sizeof(SDL_DisplayModeData));
    246    SDL_memcpy(dest, src, sizeof(SDL_DisplayMode));
    247    dest->driverdata = driverdata;
    248    return 0;
    249}
    250
    251int
    252WINRT_InitModes(_THIS)
    253{
    254    // Retrieve the display mode:
    255    SDL_DisplayMode mode, desktop_mode;
    256    if (WINRT_CalcDisplayModeUsingNativeWindow(&mode) != 0) {
    257        return -1;	// If WINRT_CalcDisplayModeUsingNativeWindow fails, it'll already have set the SDL error
    258    }
    259
    260    if (WINRT_DuplicateDisplayMode(&desktop_mode, &mode) != 0) {
    261        return -1;
    262    }
    263    if (SDL_AddBasicVideoDisplay(&desktop_mode) < 0) {
    264        return -1;
    265    }
    266
    267    SDL_AddDisplayMode(&_this->displays[0], &mode);
    268    return 0;
    269}
    270
    271static int
    272WINRT_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode)
    273{
    274    return 0;
    275}
    276
    277void
    278WINRT_VideoQuit(_THIS)
    279{
    280    WINRT_QuitMouse(_this);
    281}
    282
    283int
    284WINRT_CreateWindow(_THIS, SDL_Window * window)
    285{
    286    // Make sure that only one window gets created, at least until multimonitor
    287    // support is added.
    288    if (WINRT_GlobalSDLWindow != NULL) {
    289        SDL_SetError("WinRT only supports one window");
    290        return -1;
    291    }
    292
    293    SDL_WindowData *data = new SDL_WindowData;
    294    if (!data) {
    295        SDL_OutOfMemory();
    296        return -1;
    297    }
    298    window->driverdata = data;
    299    data->sdlWindow = window;
    300
    301    /* To note, when XAML support is enabled, access to the CoreWindow will not
    302       be possible, at least not via the SDL/XAML thread.  Attempts to access it
    303       from there will throw exceptions.  As such, the SDL_WindowData's
    304       'coreWindow' field will only be set (to a non-null value) if XAML isn't
    305       enabled.
    306    */
    307    if (!WINRT_XAMLWasEnabled) {
    308        data->coreWindow = CoreWindow::GetForCurrentThread();
    309    }
    310
    311#if SDL_VIDEO_OPENGL_EGL
    312    /* Setup the EGL surface, but only if OpenGL ES 2 was requested. */
    313    if (!(window->flags & SDL_WINDOW_OPENGL)) {
    314        /* OpenGL ES 2 wasn't requested.  Don't set up an EGL surface. */
    315        data->egl_surface = EGL_NO_SURFACE;
    316    } else {
    317        /* OpenGL ES 2 was reuqested.  Set up an EGL surface. */
    318        SDL_VideoData * video_data = (SDL_VideoData *)_this->driverdata;
    319
    320        /* Call SDL_EGL_ChooseConfig and eglCreateWindowSurface directly,
    321         * rather than via SDL_EGL_CreateSurface, as ANGLE/WinRT requires
    322         * a C++ object, ComPtr<IUnknown>, to be passed into
    323         * eglCreateWindowSurface.
    324         */
    325        if (SDL_EGL_ChooseConfig(_this) != 0) {
    326            char buf[512];
    327            SDL_snprintf(buf, sizeof(buf), "SDL_EGL_ChooseConfig failed: %s", SDL_GetError());
    328            return SDL_SetError(buf);
    329        }
    330
    331        Microsoft::WRL::ComPtr<IUnknown> cpp_winrtEglWindow = video_data->winrtEglWindow;
    332        data->egl_surface = ((eglCreateWindowSurface_Function)_this->egl_data->eglCreateWindowSurface)(
    333            _this->egl_data->egl_display,
    334            _this->egl_data->egl_config,
    335            cpp_winrtEglWindow, NULL);
    336        if (data->egl_surface == NULL) {
    337            return SDL_SetError("eglCreateWindowSurface failed");
    338        }
    339    }
    340#endif
    341
    342    /* Make sure the window is considered to be positioned at {0,0},
    343       and is considered fullscreen, shown, and the like.
    344    */
    345    window->x = 0;
    346    window->y = 0;
    347    window->flags =
    348        SDL_WINDOW_FULLSCREEN |
    349        SDL_WINDOW_SHOWN |
    350        SDL_WINDOW_BORDERLESS |
    351        SDL_WINDOW_MAXIMIZED |
    352        SDL_WINDOW_INPUT_GRABBED;
    353
    354#if SDL_VIDEO_OPENGL_EGL
    355    if (data->egl_surface) {
    356        window->flags |= SDL_WINDOW_OPENGL;
    357    }
    358#endif
    359
    360    /* WinRT does not, as of this writing, appear to support app-adjustable
    361       window sizes.  Set the window size to whatever the native WinRT
    362       CoreWindow is set at.
    363
    364       TODO, WinRT: if and when non-fullscreen XAML control support is added to SDL, consider making those resizable via SDL_Window's interfaces.
    365    */
    366    window->w = _this->displays[0].current_mode.w;
    367    window->h = _this->displays[0].current_mode.h;
    368
    369    /* For now, treat WinRT apps as if they always have focus.
    370       TODO, WinRT: try tracking keyboard and mouse focus state with respect to snapped apps
    371     */
    372    SDL_SetMouseFocus(window);
    373    SDL_SetKeyboardFocus(window);
    374 
    375    /* Make sure the WinRT app's IFramworkView can post events on
    376       behalf of SDL:
    377    */
    378    WINRT_GlobalSDLWindow = window;
    379
    380    /* All done! */
    381    return 0;
    382}
    383
    384void
    385WINRT_DestroyWindow(_THIS, SDL_Window * window)
    386{
    387    SDL_WindowData * data = (SDL_WindowData *) window->driverdata;
    388
    389    if (WINRT_GlobalSDLWindow == window) {
    390        WINRT_GlobalSDLWindow = NULL;
    391    }
    392
    393    if (data) {
    394        // Delete the internal window data:
    395        delete data;
    396        data = NULL;
    397    }
    398}
    399
    400SDL_bool
    401WINRT_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info)
    402{
    403    SDL_WindowData * data = (SDL_WindowData *) window->driverdata;
    404
    405    if (info->version.major <= SDL_MAJOR_VERSION) {
    406        info->subsystem = SDL_SYSWM_WINRT;
    407        info->info.winrt.window = reinterpret_cast<IInspectable *>(data->coreWindow.Get());
    408        return SDL_TRUE;
    409    } else {
    410        SDL_SetError("Application not compiled with SDL %d.%d\n",
    411                     SDL_MAJOR_VERSION, SDL_MINOR_VERSION);
    412        return SDL_FALSE;
    413    }
    414    return SDL_FALSE;
    415}
    416
    417#endif /* SDL_VIDEO_DRIVER_WINRT */
    418
    419/* vi: set ts=4 sw=4 expandtab: */