#ifndef APP_TYPES_H
#define APP_TYPES_H
#ifndef APP_S16
    #define APP_S16 short
#endif
#ifndef APP_U32
    #define APP_U32 unsigned int
#endif
#ifndef APP_U64
    #define APP_U64 unsigned long long
#endif
#include "app_opengl.h"

typedef struct app_t app_t;
typedef enum app_log_level_t {
  APP_LOG_LEVEL_INFO,
  APP_LOG_LEVEL_WARNING,
  APP_LOG_LEVEL_ERROR,
} app_log_level_t;



typedef enum app_screenmode_t {
  APP_SCREENMODE_WINDOW,
  APP_SCREENMODE_FULLSCREEN,
} app_screenmode_t;

typedef struct app_display_t {
  char id[64];
  int x;
  int y;
  int width;
  int height;
} app_display_t;

typedef struct app_displays_t {
  app_display_t *displays;
  int count;
} app_displays_t;

typedef enum app_key_t {
  APP_KEY_INVALID,
  APP_KEY_LBUTTON,
  APP_KEY_RBUTTON,
  APP_KEY_CANCEL,
  APP_KEY_MBUTTON,
  APP_KEY_XBUTTON1,
  APP_KEY_XBUTTON2,
  APP_KEY_BACK,
  APP_KEY_TAB,
  APP_KEY_CLEAR,
  APP_KEY_RETURN,
  APP_KEY_SHIFT,
  APP_KEY_CONTROL,
  APP_KEY_MENU,
  APP_KEY_PAUSE,
  APP_KEY_CAPITAL,
  APP_KEY_KANA,
  APP_KEY_HANGUL = APP_KEY_KANA,
  APP_KEY_JUNJA,
  APP_KEY_FINAL,
  APP_KEY_HANJA,
  APP_KEY_KANJI = APP_KEY_HANJA,
  APP_KEY_ESCAPE,
  APP_KEY_CONVERT,
  APP_KEY_NONCONVERT,
  APP_KEY_ACCEPT,
  APP_KEY_MODECHANGE,
  APP_KEY_SPACE,
  APP_KEY_PRIOR,
  APP_KEY_NEXT,
  APP_KEY_END,
  APP_KEY_HOME,
  APP_KEY_LEFT,
  APP_KEY_UP,
  APP_KEY_RIGHT,
  APP_KEY_DOWN,
  APP_KEY_SELECT,
  APP_KEY_PRINT,
  APP_KEY_EXEC,
  APP_KEY_SNAPSHOT,
  APP_KEY_INSERT,
  APP_KEY_DELETE,
  APP_KEY_HELP,
  APP_KEY_0,
  APP_KEY_1,
  APP_KEY_2,
  APP_KEY_3,
  APP_KEY_4,
  APP_KEY_5,
  APP_KEY_6,
  APP_KEY_7,
  APP_KEY_8,
  APP_KEY_9,
  APP_KEY_A,
  APP_KEY_B,
  APP_KEY_C,
  APP_KEY_D,
  APP_KEY_E,
  APP_KEY_F,
  APP_KEY_G,
  APP_KEY_H,
  APP_KEY_I,
  APP_KEY_J,
  APP_KEY_K,
  APP_KEY_L,
  APP_KEY_M,
  APP_KEY_N,
  APP_KEY_O,
  APP_KEY_P,
  APP_KEY_Q,
  APP_KEY_R,
  APP_KEY_S,
  APP_KEY_T,
  APP_KEY_U,
  APP_KEY_V,
  APP_KEY_W,
  APP_KEY_X,
  APP_KEY_Y,
  APP_KEY_Z,
  APP_KEY_LWIN,
  APP_KEY_RWIN,
  APP_KEY_APPS,
  APP_KEY_SLEEP,
  APP_KEY_NUMPAD0,
  APP_KEY_NUMPAD1,
  APP_KEY_NUMPAD2,
  APP_KEY_NUMPAD3,
  APP_KEY_NUMPAD4,
  APP_KEY_NUMPAD5,
  APP_KEY_NUMPAD6,
  APP_KEY_NUMPAD7,
  APP_KEY_NUMPAD8,
  APP_KEY_NUMPAD9,
  APP_KEY_MULTIPLY,
  APP_KEY_ADD,
  APP_KEY_SEPARATOR,
  APP_KEY_SUBTRACT,
  APP_KEY_DECIMAL,
  APP_KEY_DIVIDE,
  APP_KEY_F1,
  APP_KEY_F2,
  APP_KEY_F3,
  APP_KEY_F4,
  APP_KEY_F5,
  APP_KEY_F6,
  APP_KEY_F7,
  APP_KEY_F8,
  APP_KEY_F9,
  APP_KEY_F10,
  APP_KEY_F11,
  APP_KEY_F12,
  APP_KEY_F13,
  APP_KEY_F14,
  APP_KEY_F15,
  APP_KEY_F16,
  APP_KEY_F17,
  APP_KEY_F18,
  APP_KEY_F19,
  APP_KEY_F20,
  APP_KEY_F21,
  APP_KEY_F22,
  APP_KEY_F23,
  APP_KEY_F24,
  APP_KEY_NUMLOCK,
  APP_KEY_SCROLL,
  APP_KEY_LSHIFT,
  APP_KEY_RSHIFT,
  APP_KEY_LCONTROL,
  APP_KEY_RCONTROL,
  APP_KEY_LMENU,
  APP_KEY_RMENU,
  APP_KEY_BROWSER_BACK,
  APP_KEY_BROWSER_FORWARD,
  APP_KEY_BROWSER_REFRESH,
  APP_KEY_BROWSER_STOP,
  APP_KEY_BROWSER_SEARCH,
  APP_KEY_BROWSER_FAVORITES,
  APP_KEY_BROWSER_HOME,
  APP_KEY_VOLUME_MUTE,
  APP_KEY_VOLUME_DOWN,
  APP_KEY_VOLUME_UP,
  APP_KEY_MEDIA_NEXT_TRACK,
  APP_KEY_MEDIA_PREV_TRACK,
  APP_KEY_MEDIA_STOP,
  APP_KEY_MEDIA_PLAY_PAUSE,
  APP_KEY_LAUNCH_MAIL,
  APP_KEY_LAUNCH_MEDIA_SELECT,
  APP_KEY_LAUNCH_APP1,
  APP_KEY_LAUNCH_APP2,
  APP_KEY_OEM_1,
  APP_KEY_OEM_PLUS,
  APP_KEY_OEM_COMMA,
  APP_KEY_OEM_MINUS,
  APP_KEY_OEM_PERIOD,
  APP_KEY_OEM_2,
  APP_KEY_OEM_3,
  APP_KEY_OEM_4,
  APP_KEY_OEM_5,
  APP_KEY_OEM_6,
  APP_KEY_OEM_7,
  APP_KEY_OEM_8,
  APP_KEY_OEM_102,
  APP_KEY_PROCESSKEY,
  APP_KEY_ATTN,
  APP_KEY_CRSEL,
  APP_KEY_EXSEL,
  APP_KEY_EREOF,
  APP_KEY_PLAY,
  APP_KEY_ZOOM,
  APP_KEY_NONAME,
  APP_KEY_PA1,
  APP_KEY_OEM_CLEAR,
  APP_KEYCOUNT
} app_key_t;

typedef enum app_input_type_t {
  APP_INPUT_KEY_DOWN,
  APP_INPUT_KEY_UP,
  APP_INPUT_DOUBLE_CLICK,
  APP_INPUT_CHAR,
  APP_INPUT_MOUSE_MOVE,
  APP_INPUT_MOUSE_DELTA,
  APP_INPUT_SCROLL_WHEEL,
  APP_INPUT_TABLET
} app_input_type_t;

typedef enum app_pressed_t {
  APP_NOT_PRESSED,
  APP_PRESSED,
} app_pressed_t;

typedef struct app_input_event_t {
  app_input_type_t type;
  union data_t {
    app_key_t key;
    char char_code;
    struct {
      int x;
      int y;
    } mouse_pos;
    struct {
      float x;
      float y;
    } mouse_delta;
    float wheel_delta;
    struct {
      int x;
      int y;
      float pressure;
      app_pressed_t tip;
      app_pressed_t lower;
      app_pressed_t upper;
    } tablet;
  } data;
} app_input_event_t;

typedef struct app_input_t {
  app_input_event_t *events;
  int count;
} app_input_t;

#if defined(APP_NULL)
struct app_t {
  void *dummy;
};
#elif defined(APP_WINDOWS)
#define _CRT_NONSTDC_NO_DEPRECATE
#ifndef _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#endif

#if !defined( _WIN32_WINNT ) || _WIN32_WINNT < 0x0601
#undef _WIN32_WINNT
    #define _WIN32_WINNT 0x0601// requires Windows 7 minimum
#endif
// 0x0400=Windows NT 4.0, 0x0500=Windows 2000, 0x0501=Windows XP, 0x0502=Windows Server 2003, 0x0600=Windows Vista,
// 0x0601=Windows 7, 0x0602=Windows 8, 0x0603=Windows 8.1, 0x0A00=Windows 10,
#define _WINSOCKAPI_
#pragma warning( push )
#pragma warning( disable: 4619 ) // #pragma warning: there is no warning number 'nnnn'
#pragma warning( disable: 4668 ) // 'symbol' is not defined as a preprocessor macro, replacing with '0' for 'directives'
#pragma warning( disable: 4768 ) // __declspec attributes before linkage specification are ignored
#pragma warning( disable: 4255 ) // 'function' : no function prototype given: converting '()' to '(void)'
#pragma warning( disable: 4917 ) // 'declarator' : a GUID can only be associated with a class, interface or namespace
#define _NTDDSCM_H_ /* Fixes the error of mismatched pragma warning push/pop in Windows SDK 10.0.17763.0 */
#include <windows.h>
//#include <shlobj.h>
#pragma warning( pop )
#ifndef __TINYC__
#pragma comment( lib, "user32.lib" )
#pragma comment( lib, "gdi32.lib" )
#pragma comment( lib, "winmm.lib" )
#pragma comment( lib, "shell32.lib" )
#else
#pragma comment( lib, "user32")
#pragma comment( lib, "gdi32")
#endif

#include <time.h>
#include <stdio.h>

#pragma warning( push )
#pragma warning( disable: 4668 ) // 'symbol' is not defined as a preprocessor macro, replacing with '0' for 'directives'
#include <math.h>
#pragma warning( pop )
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
typedef struct _DSOUND_WAVEFORMATEX {
  WORD wFormatTag;
  WORD nChannels;
  DWORD nSamplesPerSec;
  DWORD nAvgBytesPerSec;
  WORD nBlockAlign;
  WORD wBitsPerSample;
  WORD cbSize;
} DSOUND_WAVEFORMATEX;

typedef struct _DSBUFFERDESC {
  DWORD dwSize;
  DWORD dwFlags;
  DWORD dwBufferBytes;
  DWORD dwReserved;
  DSOUND_WAVEFORMATEX *lpwfxFormat;
} DSBUFFERDESC;

typedef struct _DSBPOSITIONNOTIFY {
  DWORD dwOffset;
  HANDLE hEventNotify;
} DSBPOSITIONNOTIFY;

typedef struct _DSCAPS DSCAPS;
typedef struct _DSBCAPS DSBCAPS;
typedef struct _DSEFFECTDESC DSEFFECTDESC;
struct IDirectSound8;

typedef struct IDirectSoundBuffer8 {
  struct IDirectSoundBuffer8Vtbl *lpVtbl;
} IDirectSoundBuffer8;
typedef struct IDirectSoundBuffer8Vtbl IDirectSoundBuffer8Vtbl;

struct IDirectSoundBuffer8Vtbl {
  // IUnknown methods
  HRESULT(STDMETHODCALLTYPE *QueryInterface)(IDirectSoundBuffer8 *, REFIID,
                                             LPVOID *);
  ULONG(STDMETHODCALLTYPE *AddRef)(IDirectSoundBuffer8 *);
  ULONG(STDMETHODCALLTYPE *Release)(IDirectSoundBuffer8 *);

  // IDirectSoundBuffer methods
  HRESULT(STDMETHODCALLTYPE *GetCaps)(IDirectSoundBuffer8 *,
                                      DSBCAPS *pDSBufferCaps);
  HRESULT(STDMETHODCALLTYPE *GetCurrentPosition)(IDirectSoundBuffer8 *,
                                                 LPDWORD pdwCurrentPlayCursor,
                                                 LPDWORD pdwCurrentWriteCursor);
  HRESULT(STDMETHODCALLTYPE *GetFormat)(IDirectSoundBuffer8 *,
                                        DSOUND_WAVEFORMATEX *pwfxFormat,
                                        DWORD dwSizeAllocated,
                                        LPDWORD pdwSizeWritten);
  HRESULT(STDMETHODCALLTYPE *GetVolume)(IDirectSoundBuffer8 *, LPLONG plVolume);
  HRESULT(STDMETHODCALLTYPE *GetPan)(IDirectSoundBuffer8 *, LPLONG plPan);
  HRESULT(STDMETHODCALLTYPE *GetFrequency)(IDirectSoundBuffer8 *,
                                           LPDWORD pdwFrequency);
  HRESULT(STDMETHODCALLTYPE *GetStatus)(IDirectSoundBuffer8 *,
                                        LPDWORD pdwStatus);
  HRESULT(STDMETHODCALLTYPE *Initialize)(IDirectSoundBuffer8 *,
                                         struct IDirectSound8 *pDirectSound,
                                         DSBUFFERDESC *pcDSBufferDesc);
  HRESULT(STDMETHODCALLTYPE *Lock)(IDirectSoundBuffer8 *, DWORD dwOffset,
                                   DWORD dwBytes, LPVOID *ppvAudioPtr1,
                                   LPDWORD pdwAudioBytes1, LPVOID *ppvAudioPtr2,
                                   LPDWORD pdwAudioBytes2, DWORD dwFlags);
  HRESULT(STDMETHODCALLTYPE *Play)(IDirectSoundBuffer8 *, DWORD dwReserved1,
                                   DWORD dwPriority, DWORD dwFlags);
  HRESULT(STDMETHODCALLTYPE *SetCurrentPosition)(IDirectSoundBuffer8 *,
                                                 DWORD dwNewPosition);
  HRESULT(STDMETHODCALLTYPE *SetFormat)(IDirectSoundBuffer8 *,
                                        DSOUND_WAVEFORMATEX *pcfxFormat);
  HRESULT(STDMETHODCALLTYPE *SetVolume)(IDirectSoundBuffer8 *, LONG lVolume);
  HRESULT(STDMETHODCALLTYPE *SetPan)(IDirectSoundBuffer8 *, LONG lPan);
  HRESULT(STDMETHODCALLTYPE *SetFrequency)(IDirectSoundBuffer8 *,
                                           DWORD dwFrequency);
  HRESULT(STDMETHODCALLTYPE *Stop)(IDirectSoundBuffer8 *);
  HRESULT(STDMETHODCALLTYPE *Unlock)(IDirectSoundBuffer8 *, LPVOID pvAudioPtr1,
                                     DWORD dwAudioBytes1, LPVOID pvAudioPtr2,
                                     DWORD dwAudioBytes2);
  HRESULT(STDMETHODCALLTYPE *Restore)(IDirectSoundBuffer8 *);

  // IDirectSoundBuffer8 methods
  HRESULT(STDMETHODCALLTYPE *SetFX)(IDirectSoundBuffer8 *, DWORD dwEffectsCount,
                                    DSEFFECTDESC *pDSFXDesc,
                                    LPDWORD pdwResultCodes);
  HRESULT(STDMETHODCALLTYPE *AcquireResources)(IDirectSoundBuffer8 *,
                                               DWORD dwFlags,
                                               DWORD dwEffectsCount,
                                               LPDWORD pdwResultCodes);
  HRESULT(STDMETHODCALLTYPE *GetObjectInPath)(IDirectSoundBuffer8 *,
                                              REFGUID rguidObject,
                                              DWORD dwIndex,
                                              REFGUID rguidInterface,
                                              LPVOID *ppObject);
};

#define IDirectSoundBuffer8_QueryInterface(p, a, b)                            \
  (p)->lpVtbl->QueryInterface(p, a, b)
#define IDirectSoundBuffer8_Lock(p, a, b, c, d, e, f, g)                       \
  (p)->lpVtbl->Lock(p, a, b, c, d, e, f, g)
#define IDirectSoundBuffer8_Unlock(p, a, b, c, d)                              \
  (p)->lpVtbl->Unlock(p, a, b, c, d)
#define IDirectSoundBuffer8_Restore(p) (p)->lpVtbl->Restore(p)
#define IDirectSoundBuffer8_GetCurrentPosition(p, a, b)                        \
  (p)->lpVtbl->GetCurrentPosition(p, a, b)
#define IDirectSoundBuffer8_Play(p, a, b, c) (p)->lpVtbl->Play(p, a, b, c)
#define IDirectSoundBuffer8_SetVolume(p, a) (p)->lpVtbl->SetVolume(p, a)
#define IDirectSoundBuffer8_Release(p) (p)->lpVtbl->Release(p)

typedef struct IDirectSound8 {
  struct IDirectSound8Vtbl *lpVtbl;
} IDirectSound8;
typedef struct IDirectSound8Vtbl IDirectSound8Vtbl;

struct IDirectSound8Vtbl {
  // IUnknown methods
  HRESULT(STDMETHODCALLTYPE *QueryInterface)(IDirectSound8 *, REFIID, LPVOID *);
  ULONG(STDMETHODCALLTYPE *AddRef)(IDirectSound8 *);
  ULONG(STDMETHODCALLTYPE *Release)(IDirectSound8 *);

  // IDirectSound methods
  HRESULT(STDMETHODCALLTYPE *CreateSoundBuffer)(
      IDirectSound8 *, DSBUFFERDESC *pcDSBufferDesc,
      struct IDirectSoundBuffer8 **ppDSBuffer, void *pUnkOuter);
  HRESULT(STDMETHODCALLTYPE *GetCaps)(IDirectSound8 *, DSCAPS *pDSCaps);
  HRESULT(STDMETHODCALLTYPE *DuplicateSoundBuffer)(
      IDirectSound8 *, struct IDirectSoundBuffer8 *pDSBufferOriginal,
      struct IDirectSoundBuffer8 **ppDSBufferDuplicate);
  HRESULT(STDMETHODCALLTYPE *SetCooperativeLevel)(IDirectSound8 *, HWND hwnd,
                                                  DWORD dwLevel);
  HRESULT(STDMETHODCALLTYPE *Compact)(IDirectSound8 *);
  HRESULT(STDMETHODCALLTYPE *GetSpeakerConfig)(IDirectSound8 *,
                                               LPDWORD pdwSpeakerConfig);
  HRESULT(STDMETHODCALLTYPE *SetSpeakerConfig)(IDirectSound8 *,
                                               DWORD dwSpeakerConfig);
  HRESULT(STDMETHODCALLTYPE *Initialize)(IDirectSound8 *, LPCGUID pcGuidDevice);

  // IDirectSound8 methods
  HRESULT(STDMETHODCALLTYPE *VerifyCertification)(IDirectSound8 *,
                                                  LPDWORD pdwCertified);
};

#define IDirectSound8_Release(p) (p)->lpVtbl->Release(p)
#define IDirectSound8_CreateSoundBuffer(p, a, b, c)                            \
  (p)->lpVtbl->CreateSoundBuffer(p, a, b, c)
#define IDirectSound8_SetCooperativeLevel(p, a, b)                             \
  (p)->lpVtbl->SetCooperativeLevel(p, a, b)

typedef struct IDirectSoundNotify {
  struct IDirectSoundNotifyVtbl *lpVtbl;
} IDirectSoundNotify;
typedef struct IDirectSoundNotifyVtbl IDirectSoundNotifyVtbl;

struct IDirectSoundNotifyVtbl {
  HRESULT(STDMETHODCALLTYPE *QueryInterface)(IDirectSoundNotify *, REFIID,
                                             LPVOID *);
  ULONG(STDMETHODCALLTYPE *AddRef)(IDirectSoundNotify *);
  ULONG(STDMETHODCALLTYPE *Release)(IDirectSoundNotify *);
  HRESULT(STDMETHODCALLTYPE *SetNotificationPositions)(
      IDirectSoundNotify *, DWORD dwPositionNotifies,
      DSBPOSITIONNOTIFY *pcPositionNotifies);
};

#define IDirectSoundNotify_Release(p) (p)->lpVtbl->Release(p)
#define IDirectSoundNotify_SetNotificationPositions(p, a, b)                   \
  (p)->lpVtbl->SetNotificationPositions(p, a, b)

#define DS_OK S_OK
#define DSERR_BUFFERLOST MAKE_HRESULT(1, 0x878, 150)

#define DSSCL_NORMAL 0x00000001
#define DSBCAPS_CTRLVOLUME 0x00000080
#define DSBCAPS_CTRLPOSITIONNOTIFY 0x00000100
#define DSBCAPS_GLOBALFOCUS 0x00008000
#define DSBCAPS_GETCURRENTPOSITION2 0x00010000
#define DSBPLAY_LOOPING 0x00000001
#define DSBVOLUME_MIN -10000

#ifdef __cplusplus
};
#endif // __cplusplus
typedef struct APP_LOGCONTEXTA
    {
    char lcName[ 40 ]; UINT lcOptions; UINT lcStatus; UINT lcLocks; UINT lcMsgBase; UINT lcDevice; UINT lcPktRate;
    DWORD lcPktData; DWORD lcPktMode; DWORD lcMoveMask; DWORD lcBtnDnMask; DWORD lcBtnUpMask; LONG lcInOrgX;
    LONG lcInOrgY; LONG lcInOrgZ; LONG lcInExtX; LONG lcInExtY; LONG lcInExtZ; LONG lcOutOrgX; LONG lcOutOrgY;
    LONG lcOutOrgZ; LONG lcOutExtX; LONG lcOutExtY; LONG lcOutExtZ; DWORD lcSensX; DWORD lcSensY; DWORD lcSensZ;
    BOOL lcSysMode; int lcSysOrgX; int lcSysOrgY; int lcSysExtX; int lcSysExtY; DWORD lcSysSensX; DWORD lcSysSensY;
    } APP_LOGCONTEXTA;
typedef struct APP_AXIS { LONG axMin; LONG axMax; UINT axUnits; DWORD axResolution; } APP_AXIS;
typedef struct APP_PACKET { DWORD pkButtons; LONG pkX; LONG pkY; UINT pkNormalPressure; } APP_PACKET;
DECLARE_HANDLE( APP_HMGR );
DECLARE_HANDLE( APP_HCTX );
#define APP_WTI_DEVICES 100
#define APP_WTI_DDCTXS 400 /* 1.1 */
#define APP_CXO_MESSAGES 0x0004
#define APP_DVC_NPRESSURE 15
#define APP_PK_BUTTONS 0x0040 // button information
#define APP_PK_X 0x0080 // x axis
#define APP_PK_Y 0x0100 // y axis
#define APP_PK_NORMAL_PRESSURE 0x0400 // normal or tip pressure
#define APP_PACKETDATA APP_PK_X | APP_PK_Y | APP_PK_BUTTONS | APP_PK_NORMAL_PRESSURE
#define APP_PACKETMODE 0
#define APP_WT_PACKET 0x7FF0
///// END DSOUND DEFINITIONS //////

struct app_t {
  void *memctx;
  void *logctx;
  void *fatalctx;
  app_interpolation_t interpolation;
  app_screenmode_t screenmode;

  BOOL initialized;
  BOOL closed;

  char exe_path[260];
  char userdata_path[260];
  char appdata_path[260];
  char const *cmdline;

  HINSTANCE hinstance;
  HWND hwnd;
  LRESULT(CALLBACK *user_wndproc)(app_t *, HWND, UINT, WPARAM, LPARAM);

  HDC hdc;
  HICON icon;
  BOOL has_focus;
  BOOL is_minimized;

  struct app_internal_opengl_t gl;
  HMODULE gl_dll;
  HGLRC gl_context;
  PROC(APP_GLCALLTYPE *wglGetProcAddress)(LPCSTR);
  HGLRC(APP_GLCALLTYPE *wglCreateContext)(HDC);
  BOOL(APP_GLCALLTYPE *wglDeleteContext)(HGLRC);
  BOOL(APP_GLCALLTYPE *wglMakeCurrent)(HDC, HGLRC);
  BOOL(APP_GLCALLTYPE *wglSwapIntervalEXT)(int);

  UINT(WINAPI *GetRawInputDataPtr)(HRAWINPUT, UINT, LPVOID, PUINT, UINT);

  HANDLE sound_notifications[2];
  HMODULE dsound_dll;
  struct IDirectSound8 *dsound;
  struct IDirectSoundBuffer8 *dsoundbuf;
  HANDLE sound_thread_handle;
  volatile LONG exit_sound_thread;
  int sample_pairs_count;
  int sound_level;
  void (*sound_callback)(APP_S16 *sample_pairs, int sample_pairs_count,
                         void *user_data);
  void *sound_user_data;

  HCURSOR current_pointer;

  BOOL clip_cursor;
  RECT clip_rect;

  app_input_event_t input_events[1024];
  int input_count;

  int windowed_x;
  int windowed_y;
  int windowed_h;
  int windowed_w;
  int fullscreen_width;
  int fullscreen_height;

  int display_count;
  app_display_t displays[16];
  HMONITOR displays_hmonitor[16];

  struct {
    HMODULE wintab_dll;
    APP_HCTX context;
    int max_pressure;

    UINT(WINAPI *WTInfo)(UINT, UINT, LPVOID);
    APP_HCTX(WINAPI *WTOpen)(HWND, APP_LOGCONTEXTA *, BOOL);
    BOOL(WINAPI *WTClose)(APP_HCTX);
    BOOL(WINAPI *WTEnable)(APP_HCTX, BOOL);
    BOOL(WINAPI *WTPacket)(APP_HCTX, UINT, LPVOID);
  } tablet;
};
#elif defined(APP_SDL)
#include <stdio.h>
#include <string.h>


#include "SDL.h"
struct app_t {
  void *memctx;
  void *logctx;
  void *fatalctx;
  struct app_internal_opengl_t gl;
  int initialized;
  int exit_requested;
  int has_focus;
  app_interpolation_t interpolation;
  app_screenmode_t screenmode;

  SDL_Window *window;
  SDL_Cursor *cursor;

  SDL_AudioDeviceID sound_device;
  void (*sound_callback)(APP_S16 *sample_pairs, int sample_pairs_count,
                         void *user_data);
  void *sound_user_data;
  int volume;

  app_input_event_t input_events[1024];
  int input_count;

  int display_count;
  app_display_t displays[16];
};

#elif defined(APP_WASM)
struct app_t {
  void *memctx;
  void *logctx;
  void *fatalctx;
  struct app_internal_opengl_t gl;
  int has_focus;
  app_interpolation_t interpolation;

  void (*sound_callback)(APP_S16 *sample_pairs, int sample_pairs_count,
                         void *user_data);
  void *sound_user_data;
  int sound_buffer_size;
  APP_S16 *sound_buffer;
  int volume;

  app_input_event_t input_events[1024];
  int input_count;
  int pointer_x;
  int pointer_y;
};
#endif

#endif